From 7a6610139a1e1d9297dd1c5d178022eac36839cb Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 2 Nov 2010 08:05:51 +0100 Subject: intel-iommu: Fix use after release during device attach Obtain the new pgd pointer before releasing the page containing this value. Cc: stable@kernel.org Signed-off-by: Jan Kiszka Reviewed-by: Sheng Yang Signed-off-by: David Woodhouse --- drivers/pci/intel-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4789f8e8bf7a..35463ddf10a1 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3627,9 +3627,9 @@ static int intel_iommu_attach_device(struct iommu_domain *domain, pte = dmar_domain->pgd; if (dma_pte_present(pte)) { - free_pgtable_page(dmar_domain->pgd); dmar_domain->pgd = (struct dma_pte *) phys_to_virt(dma_pte_addr(pte)); + free_pgtable_page(pte); } dmar_domain->agaw--; } -- cgit v1.2.2 From fccdd7c4aeb7ed639b51126941545bc5b3824dab Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 22:47:47 -0800 Subject: Input: ad7877 - convert to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitate updates to the PM core. Do this move for the ad7879 SPI driver. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7877.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index a1952fcc083e..714d4e0f9f95 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -826,39 +827,37 @@ static int __devexit ad7877_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int ad7877_suspend(struct spi_device *spi, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int ad7877_suspend(struct device *dev) { - struct ad7877 *ts = dev_get_drvdata(&spi->dev); + struct ad7877 *ts = dev_get_drvdata(dev); ad7877_disable(ts); return 0; } -static int ad7877_resume(struct spi_device *spi) +static int ad7877_resume(struct device *dev) { - struct ad7877 *ts = dev_get_drvdata(&spi->dev); + struct ad7877 *ts = dev_get_drvdata(dev); ad7877_enable(ts); return 0; } -#else -#define ad7877_suspend NULL -#define ad7877_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume); + static struct spi_driver ad7877_driver = { .driver = { .name = "ad7877", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &ad7877_pm, }, .probe = ad7877_probe, .remove = __devexit_p(ad7877_remove), - .suspend = ad7877_suspend, - .resume = ad7877_resume, }; static int __init ad7877_init(void) -- cgit v1.2.2 From c7848c8e1a26ca6075d6cb538657f5381afcadc4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 22:48:44 -0800 Subject: Input: ad7879 - convert SPI to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitate updates to the PM core. Do this move for the ad7879 SPI driver. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-spi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 59c6e68c4325..ddf732f3cafc 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -7,6 +7,7 @@ */ #include /* BUS_SPI */ +#include #include #include "ad7879.h" @@ -20,9 +21,10 @@ #define AD7879_WRITECMD(reg) (AD7879_CMD(reg)) #define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ) -#ifdef CONFIG_PM -static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int ad7879_spi_suspend(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct ad7879 *ts = spi_get_drvdata(spi); ad7879_suspend(ts); @@ -30,19 +32,19 @@ static int ad7879_spi_suspend(struct spi_device *spi, pm_message_t message) return 0; } -static int ad7879_spi_resume(struct spi_device *spi) +static int ad7879_spi_resume(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct ad7879 *ts = spi_get_drvdata(spi); ad7879_resume(ts); return 0; } -#else -# define ad7879_spi_suspend NULL -# define ad7879_spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad7879_spi_pm, ad7879_spi_suspend, ad7879_spi_resume); + /* * ad7879_read/write are only used for initial setup and for sysfs controls. * The main traffic is done in ad7879_collect(). @@ -173,11 +175,10 @@ static struct spi_driver ad7879_spi_driver = { .name = "ad7879", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &ad7879_spi_pm, }, .probe = ad7879_spi_probe, .remove = __devexit_p(ad7879_spi_remove), - .suspend = ad7879_spi_suspend, - .resume = ad7879_spi_resume, }; static int __init ad7879_spi_init(void) -- cgit v1.2.2 From 3c36e719033ddc09aded770472cbdb477fcb4479 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 22:51:26 -0800 Subject: Input: ads7846 - convert to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitate updates to the PM core. Do this move for the ads7846 driver. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 14ea54b78e46..b31e90f0d44b 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -892,9 +893,10 @@ static irqreturn_t ads7846_irq(int irq, void *handle) return IRQ_HANDLED; } -static int ads7846_suspend(struct spi_device *spi, pm_message_t message) +#ifdef CONFIG_PM_SLEEP +static int ads7846_suspend(struct device *dev) { - struct ads7846 *ts = dev_get_drvdata(&spi->dev); + struct ads7846 *ts = dev_get_drvdata(dev); mutex_lock(&ts->lock); @@ -914,9 +916,9 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message) return 0; } -static int ads7846_resume(struct spi_device *spi) +static int ads7846_resume(struct device *dev) { - struct ads7846 *ts = dev_get_drvdata(&spi->dev); + struct ads7846 *ts = dev_get_drvdata(dev); mutex_lock(&ts->lock); @@ -935,6 +937,9 @@ static int ads7846_resume(struct spi_device *spi) return 0; } +#endif + +static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts) { @@ -1402,11 +1407,10 @@ static struct spi_driver ads7846_driver = { .name = "ads7846", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &ads7846_pm, }, .probe = ads7846_probe, .remove = __devexit_p(ads7846_remove), - .suspend = ads7846_suspend, - .resume = ads7846_resume, }; static int __init ads7846_init(void) -- cgit v1.2.2 From f117a3e3004381ccadadc5156178c283815ca393 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 17:21:35 +0100 Subject: firewire: ohci: log dead DMA contexts When a DMA context goes into the dead state (and the controller thus stops working correctly), logging this error and the controller's error code might be helpful for debugging. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 59 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index bd3c61b6dd8d..c7394361afcb 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -208,9 +208,11 @@ struct fw_ohci { struct context at_request_ctx; struct context at_response_ctx; + u32 it_context_support; u32 it_context_mask; /* unoccupied IT contexts */ struct iso_context *it_context_list; u64 ir_context_channels; /* unoccupied channels */ + u32 ir_context_support; u32 ir_context_mask; /* unoccupied IR contexts */ struct iso_context *ir_context_list; u64 mc_channels; /* channels in use by the multichannel IR context */ @@ -338,7 +340,7 @@ static void log_irqs(u32 evt) !(evt & OHCI1394_busReset)) return; - fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, + fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, evt & OHCI1394_selfIDComplete ? " selfID" : "", evt & OHCI1394_RQPkt ? " AR_req" : "", evt & OHCI1394_RSPkt ? " AR_resp" : "", @@ -351,6 +353,7 @@ static void log_irqs(u32 evt) evt & OHCI1394_cycle64Seconds ? " cycle64Seconds" : "", evt & OHCI1394_cycleInconsistent ? " cycleInconsistent" : "", evt & OHCI1394_regAccessFail ? " regAccessFail" : "", + evt & OHCI1394_unrecoverableError ? " unrecoverableError" : "", evt & OHCI1394_busReset ? " busReset" : "", evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | OHCI1394_RSPkt | OHCI1394_reqTxComplete | @@ -1590,6 +1593,47 @@ static void at_context_transmit(struct context *ctx, struct fw_packet *packet) } +static void detect_dead_context(struct fw_ohci *ohci, + const char *name, unsigned int regs) +{ + u32 ctl; + + ctl = reg_read(ohci, CONTROL_SET(regs)); + if (ctl & CONTEXT_DEAD) { +#ifdef CONFIG_FIREWIRE_OHCI_DEBUG + fw_error("DMA context %s has stopped, error code: %s\n", + name, evts[ctl & 0x1f]); +#else + fw_error("DMA context %s has stopped, error code: %#x\n", + name, ctl & 0x1f); +#endif + } +} + +static void handle_dead_contexts(struct fw_ohci *ohci) +{ + unsigned int i; + char name[8]; + + detect_dead_context(ohci, "ATReq", OHCI1394_AsReqTrContextBase); + detect_dead_context(ohci, "ATRsp", OHCI1394_AsRspTrContextBase); + detect_dead_context(ohci, "ARReq", OHCI1394_AsReqRcvContextBase); + detect_dead_context(ohci, "ARRsp", OHCI1394_AsRspRcvContextBase); + for (i = 0; i < 32; ++i) { + if (!(ohci->it_context_support & (1 << i))) + continue; + sprintf(name, "IT%u", i); + detect_dead_context(ohci, name, OHCI1394_IsoXmitContextBase(i)); + } + for (i = 0; i < 32; ++i) { + if (!(ohci->ir_context_support & (1 << i))) + continue; + sprintf(name, "IR%u", i); + detect_dead_context(ohci, name, OHCI1394_IsoRcvContextBase(i)); + } + /* TODO: maybe try to flush and restart the dead contexts */ +} + static u32 cycle_timer_ticks(u32 cycle_timer) { u32 ticks; @@ -1904,6 +1948,9 @@ static irqreturn_t irq_handler(int irq, void *data) fw_notify("isochronous cycle inconsistent\n"); } + if (unlikely(event & OHCI1394_unrecoverableError)) + handle_dead_contexts(ohci); + if (event & OHCI1394_cycle64Seconds) { spin_lock(&ohci->lock); update_bus_time(ohci); @@ -2141,7 +2188,9 @@ static int ohci_enable(struct fw_card *card, OHCI1394_selfIDComplete | OHCI1394_regAccessFail | OHCI1394_cycle64Seconds | - OHCI1394_cycleInconsistent | OHCI1394_cycleTooLong | + OHCI1394_cycleInconsistent | + OHCI1394_unrecoverableError | + OHCI1394_cycleTooLong | OHCI1394_masterIntEnable; if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) irqs |= OHCI1394_busReset; @@ -3207,15 +3256,17 @@ static int __devinit pci_probe(struct pci_dev *dev, reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0); ohci->ir_context_channels = ~0ULL; - ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); + ohci->ir_context_support = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet); reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0); + ohci->ir_context_mask = ohci->ir_context_support; ohci->n_ir = hweight32(ohci->ir_context_mask); size = sizeof(struct iso_context) * ohci->n_ir; ohci->ir_context_list = kzalloc(size, GFP_KERNEL); reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0); - ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); + ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet); reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0); + ohci->it_context_mask = ohci->it_context_support; ohci->n_it = hweight32(ohci->it_context_mask); size = sizeof(struct iso_context) * ohci->n_it; ohci->it_context_list = kzalloc(size, GFP_KERNEL); -- cgit v1.2.2 From 3e204dfcaff0e7f6c4d9873fb8c9d948ec5ab2da Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 17:28:27 +0100 Subject: firewire: cdev: remove unneeded idr_find() from complete_transaction() Outbound transactions are never aborted with release_client_resource(), so it is not necessary for complete_transaction() to check whether the resource is still registered. Only shutdown_resource() can abort such an transaction, and this is already handled with the in_shutdown check. Signed-off-by: Clemens Ladisch Signed-off-by: "Stefan Richter" --- drivers/firewire/core-cdev.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 48ae712e2101..4434f7ca11d5 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -544,14 +544,8 @@ static void complete_transaction(struct fw_card *card, int rcode, * 1. If called while in shutdown, the idr tree must be left untouched. * The idr handle will be removed and the client reference will be * dropped later. - * 2. If the call chain was release_client_resource -> - * release_transaction -> complete_transaction (instead of a normal - * conclusion of the transaction), i.e. if this resource was already - * unregistered from the idr, the client reference will be dropped - * by release_client_resource and we must not drop it here. */ - if (!client->in_shutdown && - idr_find(&client->resource_idr, e->r.resource.handle)) { + if (!client->in_shutdown) { idr_remove(&client->resource_idr, e->r.resource.handle); /* Drop the idr's reference */ client_put(client); -- cgit v1.2.2 From 5a5e62da9be255439e8ce59f96828775b7b33374 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 17:28:39 +0100 Subject: firewire: cdev: always wait for outbound transactions to complete We must not use fw_cancel_transaction() because it cannot correctly abort still-active transactions. The only place in core-cdev where this matters is when the file is released. Instead of trying to abort the transactions, we wait for them to complete normally, i.e., until all outbound transaction resources have been removed from the IDR tree. Signed-off-by: Clemens Ladisch Signed-off-by: "Stefan Richter" --- drivers/firewire/core-cdev.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 4434f7ca11d5..5485c0877b81 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -64,6 +64,7 @@ struct client { struct idr resource_idr; struct list_head event_list; wait_queue_head_t wait; + wait_queue_head_t tx_flush_wait; u64 bus_reset_closure; struct fw_iso_context *iso_context; @@ -251,6 +252,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file) idr_init(&client->resource_idr); INIT_LIST_HEAD(&client->event_list); init_waitqueue_head(&client->wait); + init_waitqueue_head(&client->tx_flush_wait); INIT_LIST_HEAD(&client->phy_receiver_link); kref_init(&client->kref); @@ -520,10 +522,6 @@ static int release_client_resource(struct client *client, u32 handle, static void release_transaction(struct client *client, struct client_resource *resource) { - struct outbound_transaction_resource *r = container_of(resource, - struct outbound_transaction_resource, resource); - - fw_cancel_transaction(client->device->card, &r->transaction); } static void complete_transaction(struct fw_card *card, int rcode, @@ -540,16 +538,9 @@ static void complete_transaction(struct fw_card *card, int rcode, memcpy(rsp->data, payload, rsp->length); spin_lock_irqsave(&client->lock, flags); - /* - * 1. If called while in shutdown, the idr tree must be left untouched. - * The idr handle will be removed and the client reference will be - * dropped later. - */ - if (!client->in_shutdown) { - idr_remove(&client->resource_idr, e->r.resource.handle); - /* Drop the idr's reference */ - client_put(client); - } + idr_remove(&client->resource_idr, e->r.resource.handle); + if (client->in_shutdown) + wake_up(&client->tx_flush_wait); spin_unlock_irqrestore(&client->lock, flags); rsp->type = FW_CDEV_EVENT_RESPONSE; @@ -569,6 +560,8 @@ static void complete_transaction(struct fw_card *card, int rcode, queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length, NULL, 0); + /* Drop the idr's reference */ + client_put(client); /* Drop the transaction callback's reference */ client_put(client); } @@ -1672,6 +1665,25 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma) return ret; } +static int is_outbound_transaction_resource(int id, void *p, void *data) +{ + struct client_resource *resource = p; + + return resource->release == release_transaction; +} + +static int has_outbound_transactions(struct client *client) +{ + int ret; + + spin_lock_irq(&client->lock); + ret = idr_for_each(&client->resource_idr, + is_outbound_transaction_resource, NULL); + spin_unlock_irq(&client->lock); + + return ret; +} + static int shutdown_resource(int id, void *p, void *data) { struct client_resource *resource = p; @@ -1707,6 +1719,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file) client->in_shutdown = true; spin_unlock_irq(&client->lock); + wait_event(client->tx_flush_wait, !has_outbound_transactions(client)); + idr_for_each(&client->resource_idr, shutdown_resource, client); idr_remove_all(&client->resource_idr); idr_destroy(&client->resource_idr); -- cgit v1.2.2 From dbc9880fa731fe2482a706bbabb4165269233063 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 10 Jan 2011 17:29:03 +0100 Subject: firewire: cdev: remove unneeded reference For outbound transactions, the IDR's and the callback's references now have exactly the same lifetime, so we do not need both of them. Signed-off-by: Clemens Ladisch Signed-off-by: "Stefan Richter" --- drivers/firewire/core-cdev.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 5485c0877b81..e0c13fb3ae22 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -562,8 +562,6 @@ static void complete_transaction(struct fw_card *card, int rcode, /* Drop the idr's reference */ client_put(client); - /* Drop the transaction callback's reference */ - client_put(client); } static int init_request(struct client *client, @@ -601,9 +599,6 @@ static int init_request(struct client *client, if (ret < 0) goto failed; - /* Get a reference for the transaction callback */ - client_get(client); - fw_send_request(client->device->card, &e->r.transaction, request->tcode, destination_id, request->generation, speed, request->offset, e->response.data, -- cgit v1.2.2 From e71084af58cf15e6043338500eeaf6281d0a62af Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sat, 22 Jan 2011 15:05:03 +0100 Subject: firewire: core: fix card->reset_jiffies overflow On a 32-bit machine with, e.g., HZ=1000, jiffies will overflow after about 50 days, so if there are between 25 and 50 days between bus resets, the card->reset_jiffies comparisons can get wrong results. To fix this, ensure that this timestamp always uses 64 bits. Signed-off-by: Clemens Ladisch Signed-off-by: "Stefan Richter" --- drivers/firewire/core-card.c | 5 +++-- drivers/firewire/core-cdev.c | 3 ++- drivers/firewire/core-device.c | 3 ++- drivers/firewire/core-topology.c | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 24ff35511e2b..3241dc4e1fc9 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -233,7 +233,7 @@ static void br_work(struct work_struct *work) /* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */ if (card->reset_jiffies != 0 && - time_is_after_jiffies(card->reset_jiffies + 2 * HZ)) { + time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) { if (!schedule_delayed_work(&card->br_work, 2 * HZ)) fw_card_put(card); return; @@ -316,7 +316,8 @@ static void bm_work(struct work_struct *work) irm_id = card->irm_node->node_id; local_id = card->local_node->node_id; - grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 8)); + grace = time_after64(get_jiffies_64(), + card->reset_jiffies + DIV_ROUND_UP(HZ, 8)); if ((is_next_generation(generation, card->bm_generation) && !card->bm_abdicate) || diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index e0c13fb3ae22..62ac111af243 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -1205,7 +1205,8 @@ static void iso_resource_work(struct work_struct *work) todo = r->todo; /* Allow 1000ms grace period for other reallocations. */ if (todo == ISO_RES_ALLOC && - time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) { + time_before64(get_jiffies_64(), + client->device->card->reset_jiffies + HZ)) { schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3)); skip = true; } else { diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 6113b896e790..57461923bacf 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -747,7 +747,8 @@ static void fw_device_shutdown(struct work_struct *work) container_of(work, struct fw_device, work.work); int minor = MINOR(device->device.devt); - if (time_is_after_jiffies(device->card->reset_jiffies + SHUTDOWN_DELAY) + if (time_before64(get_jiffies_64(), + device->card->reset_jiffies + SHUTDOWN_DELAY) && !list_empty(&device->card->link)) { schedule_delayed_work(&device->work, SHUTDOWN_DELAY); return; diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 09be1a635505..193ed9233144 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -545,7 +545,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, */ smp_wmb(); card->generation = generation; - card->reset_jiffies = jiffies; + card->reset_jiffies = get_jiffies_64(); card->bm_node_id = 0xffff; card->bm_abdicate = bm_abdicate; fw_schedule_bm_work(card, 0); -- cgit v1.2.2 From 335d7c58fcc1b71387a2c38b610b08bb9d3a6fcc Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 26 Jan 2011 11:45:49 -0800 Subject: i2c/busses: Add support for Diolan U2C-12 USB-I2C adapter This patch adds support for the Diolan U2C-12 USB-I2C adapter. It also updates MAINTAINERS to list the author as maintainer. Signed-off-by: Guenter Roeck Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-diolan-u2c.c | 535 ++++++++++++++++++++++++++++++++++++ 3 files changed, 546 insertions(+) create mode 100644 drivers/i2c/busses/i2c-diolan-u2c.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 113505a6434e..30f8dbd7e03d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -648,6 +648,16 @@ config I2C_EG20T comment "External I2C/SMBus adapter drivers" +config I2C_DIOLAN_U2C + tristate "Diolan U2C-12 USB adapter" + depends on USB + help + If you say yes to this option, support will be included for Diolan + U2C-12, a USB to I2C interface. + + This driver can also be built as a module. If so, the module + will be called i2c-diolan-u2c. + config I2C_PARPORT tristate "Parallel port adapter" depends on PARPORT diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 9d2d0ec7fb23..3c630b7c5663 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o # External I2C/SMBus adapter drivers +obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c new file mode 100644 index 000000000000..76366716a854 --- /dev/null +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -0,0 +1,535 @@ +/* + * Driver for the Diolan u2c-12 USB-I2C adapter + * + * Copyright (c) 2010-2011 Ericsson AB + * + * Derived from: + * i2c-tiny-usb.c + * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "i2c-diolan-u2c" + +#define USB_VENDOR_ID_DIOLAN 0x0abf +#define USB_DEVICE_ID_DIOLAN_U2C 0x3370 + +#define DIOLAN_OUT_EP 0x02 +#define DIOLAN_IN_EP 0x84 + +/* commands via USB, must match command ids in the firmware */ +#define CMD_I2C_READ 0x01 +#define CMD_I2C_WRITE 0x02 +#define CMD_I2C_SCAN 0x03 /* Returns list of detected devices */ +#define CMD_I2C_RELEASE_SDA 0x04 +#define CMD_I2C_RELEASE_SCL 0x05 +#define CMD_I2C_DROP_SDA 0x06 +#define CMD_I2C_DROP_SCL 0x07 +#define CMD_I2C_READ_SDA 0x08 +#define CMD_I2C_READ_SCL 0x09 +#define CMD_GET_FW_VERSION 0x0a +#define CMD_GET_SERIAL 0x0b +#define CMD_I2C_START 0x0c +#define CMD_I2C_STOP 0x0d +#define CMD_I2C_REPEATED_START 0x0e +#define CMD_I2C_PUT_BYTE 0x0f +#define CMD_I2C_GET_BYTE 0x10 +#define CMD_I2C_PUT_ACK 0x11 +#define CMD_I2C_GET_ACK 0x12 +#define CMD_I2C_PUT_BYTE_ACK 0x13 +#define CMD_I2C_GET_BYTE_ACK 0x14 +#define CMD_I2C_SET_SPEED 0x1b +#define CMD_I2C_GET_SPEED 0x1c +#define CMD_I2C_SET_CLK_SYNC 0x24 +#define CMD_I2C_GET_CLK_SYNC 0x25 +#define CMD_I2C_SET_CLK_SYNC_TO 0x26 +#define CMD_I2C_GET_CLK_SYNC_TO 0x27 + +#define RESP_OK 0x00 +#define RESP_FAILED 0x01 +#define RESP_BAD_MEMADDR 0x04 +#define RESP_DATA_ERR 0x05 +#define RESP_NOT_IMPLEMENTED 0x06 +#define RESP_NACK 0x07 +#define RESP_TIMEOUT 0x09 + +#define U2C_I2C_SPEED_FAST 0 /* 400 kHz */ +#define U2C_I2C_SPEED_STD 1 /* 100 kHz */ +#define U2C_I2C_SPEED_2KHZ 242 /* 2 kHz, minimum speed */ +#define U2C_I2C_SPEED(f) ((DIV_ROUND_UP(1000000, (f)) - 10) / 2 + 1) + +#define U2C_I2C_FREQ_FAST 400000 +#define U2C_I2C_FREQ_STD 100000 +#define U2C_I2C_FREQ(s) (1000000 / (2 * (s - 1) + 10)) + +#define DIOLAN_USB_TIMEOUT 100 /* in ms */ +#define DIOLAN_SYNC_TIMEOUT 20 /* in ms */ + +#define DIOLAN_OUTBUF_LEN 128 +#define DIOLAN_FLUSH_LEN (DIOLAN_OUTBUF_LEN - 4) +#define DIOLAN_INBUF_LEN 256 /* Maximum supported receive length */ + +/* Structure to hold all of our device specific stuff */ +struct i2c_diolan_u2c { + u8 obuffer[DIOLAN_OUTBUF_LEN]; /* output buffer */ + u8 ibuffer[DIOLAN_INBUF_LEN]; /* input buffer */ + struct usb_device *usb_dev; /* the usb device for this device */ + struct usb_interface *interface;/* the interface for this device */ + struct i2c_adapter adapter; /* i2c related things */ + int olen; /* Output buffer length */ + int ocount; /* Number of enqueued messages */ +}; + +static uint frequency = U2C_I2C_FREQ_STD; /* I2C clock frequency in Hz */ + +module_param(frequency, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(frequency, "I2C clock frequency in hertz"); + +/* usb layer */ + +/* Send command to device, and get response. */ +static int diolan_usb_transfer(struct i2c_diolan_u2c *dev) +{ + int ret = 0; + int actual; + int i; + + if (!dev->olen || !dev->ocount) + return -EINVAL; + + ret = usb_bulk_msg(dev->usb_dev, + usb_sndbulkpipe(dev->usb_dev, DIOLAN_OUT_EP), + dev->obuffer, dev->olen, &actual, + DIOLAN_USB_TIMEOUT); + if (!ret) { + for (i = 0; i < dev->ocount; i++) { + int tmpret; + + tmpret = usb_bulk_msg(dev->usb_dev, + usb_rcvbulkpipe(dev->usb_dev, + DIOLAN_IN_EP), + dev->ibuffer, + sizeof(dev->ibuffer), &actual, + DIOLAN_USB_TIMEOUT); + /* + * Stop command processing if a previous command + * returned an error. + * Note that we still need to retrieve all messages. + */ + if (ret < 0) + continue; + ret = tmpret; + if (ret == 0 && actual > 0) { + switch (dev->ibuffer[actual - 1]) { + case RESP_NACK: + /* + * Return ENXIO if NACK was received as + * response to the address phase, + * EIO otherwise + */ + ret = i == 1 ? -ENXIO : -EIO; + break; + case RESP_TIMEOUT: + ret = -ETIMEDOUT; + break; + case RESP_OK: + /* strip off return code */ + ret = actual - 1; + break; + default: + ret = -EIO; + break; + } + } + } + } + dev->olen = 0; + dev->ocount = 0; + return ret; +} + +static int diolan_write_cmd(struct i2c_diolan_u2c *dev, bool flush) +{ + if (flush || dev->olen >= DIOLAN_FLUSH_LEN) + return diolan_usb_transfer(dev); + return 0; +} + +/* Send command (no data) */ +static int diolan_usb_cmd(struct i2c_diolan_u2c *dev, u8 command, bool flush) +{ + dev->obuffer[dev->olen++] = command; + dev->ocount++; + return diolan_write_cmd(dev, flush); +} + +/* Send command with one byte of data */ +static int diolan_usb_cmd_data(struct i2c_diolan_u2c *dev, u8 command, u8 data, + bool flush) +{ + dev->obuffer[dev->olen++] = command; + dev->obuffer[dev->olen++] = data; + dev->ocount++; + return diolan_write_cmd(dev, flush); +} + +/* Send command with two bytes of data */ +static int diolan_usb_cmd_data2(struct i2c_diolan_u2c *dev, u8 command, u8 d1, + u8 d2, bool flush) +{ + dev->obuffer[dev->olen++] = command; + dev->obuffer[dev->olen++] = d1; + dev->obuffer[dev->olen++] = d2; + dev->ocount++; + return diolan_write_cmd(dev, flush); +} + +/* + * Flush input queue. + * If we don't do this at startup and the controller has queued up + * messages which were not retrieved, it will stop responding + * at some point. + */ +static void diolan_flush_input(struct i2c_diolan_u2c *dev) +{ + int i; + + for (i = 0; i < 10; i++) { + int actual = 0; + int ret; + + ret = usb_bulk_msg(dev->usb_dev, + usb_rcvbulkpipe(dev->usb_dev, DIOLAN_IN_EP), + dev->ibuffer, sizeof(dev->ibuffer), &actual, + DIOLAN_USB_TIMEOUT); + if (ret < 0 || actual == 0) + break; + } + if (i == 10) + dev_err(&dev->interface->dev, "Failed to flush input buffer\n"); +} + +static int diolan_i2c_start(struct i2c_diolan_u2c *dev) +{ + return diolan_usb_cmd(dev, CMD_I2C_START, false); +} + +static int diolan_i2c_repeated_start(struct i2c_diolan_u2c *dev) +{ + return diolan_usb_cmd(dev, CMD_I2C_REPEATED_START, false); +} + +static int diolan_i2c_stop(struct i2c_diolan_u2c *dev) +{ + return diolan_usb_cmd(dev, CMD_I2C_STOP, true); +} + +static int diolan_i2c_get_byte_ack(struct i2c_diolan_u2c *dev, bool ack, + u8 *byte) +{ + int ret; + + ret = diolan_usb_cmd_data(dev, CMD_I2C_GET_BYTE_ACK, ack, true); + if (ret > 0) + *byte = dev->ibuffer[0]; + else if (ret == 0) + ret = -EIO; + + return ret; +} + +static int diolan_i2c_put_byte_ack(struct i2c_diolan_u2c *dev, u8 byte) +{ + return diolan_usb_cmd_data(dev, CMD_I2C_PUT_BYTE_ACK, byte, false); +} + +static int diolan_set_speed(struct i2c_diolan_u2c *dev, u8 speed) +{ + return diolan_usb_cmd_data(dev, CMD_I2C_SET_SPEED, speed, true); +} + +/* Enable or disable clock synchronization (stretching) */ +static int diolan_set_clock_synch(struct i2c_diolan_u2c *dev, bool enable) +{ + return diolan_usb_cmd_data(dev, CMD_I2C_SET_CLK_SYNC, enable, true); +} + +/* Set clock synchronization timeout in ms */ +static int diolan_set_clock_synch_timeout(struct i2c_diolan_u2c *dev, int ms) +{ + int to_val = ms * 10; + + return diolan_usb_cmd_data2(dev, CMD_I2C_SET_CLK_SYNC_TO, + to_val & 0xff, (to_val >> 8) & 0xff, true); +} + +static void diolan_fw_version(struct i2c_diolan_u2c *dev) +{ + int ret; + + ret = diolan_usb_cmd(dev, CMD_GET_FW_VERSION, true); + if (ret >= 2) + dev_info(&dev->interface->dev, + "Diolan U2C firmware version %u.%u\n", + (unsigned int)dev->ibuffer[0], + (unsigned int)dev->ibuffer[1]); +} + +static void diolan_get_serial(struct i2c_diolan_u2c *dev) +{ + int ret; + u32 serial; + + ret = diolan_usb_cmd(dev, CMD_GET_SERIAL, true); + if (ret >= 4) { + serial = le32_to_cpu(*(u32 *)dev->ibuffer); + dev_info(&dev->interface->dev, + "Diolan U2C serial number %u\n", serial); + } +} + +static int diolan_init(struct i2c_diolan_u2c *dev) +{ + int speed, ret; + + if (frequency >= 200000) { + speed = U2C_I2C_SPEED_FAST; + frequency = U2C_I2C_FREQ_FAST; + } else if (frequency >= 100000 || frequency == 0) { + speed = U2C_I2C_SPEED_STD; + frequency = U2C_I2C_FREQ_STD; + } else { + speed = U2C_I2C_SPEED(frequency); + if (speed > U2C_I2C_SPEED_2KHZ) + speed = U2C_I2C_SPEED_2KHZ; + frequency = U2C_I2C_FREQ(speed); + } + + dev_info(&dev->interface->dev, + "Diolan U2C at USB bus %03d address %03d speed %d Hz\n", + dev->usb_dev->bus->busnum, dev->usb_dev->devnum, frequency); + + diolan_flush_input(dev); + diolan_fw_version(dev); + diolan_get_serial(dev); + + /* Set I2C speed */ + ret = diolan_set_speed(dev, speed); + if (ret < 0) + return ret; + + /* Configure I2C clock synchronization */ + ret = diolan_set_clock_synch(dev, speed != U2C_I2C_SPEED_FAST); + if (ret < 0) + return ret; + + if (speed != U2C_I2C_SPEED_FAST) + ret = diolan_set_clock_synch_timeout(dev, DIOLAN_SYNC_TIMEOUT); + + return ret; +} + +/* i2c layer */ + +static int diolan_usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + int num) +{ + struct i2c_diolan_u2c *dev = i2c_get_adapdata(adapter); + struct i2c_msg *pmsg; + int i, j; + int ret, sret; + + ret = diolan_i2c_start(dev); + if (ret < 0) + return ret; + + for (i = 0; i < num; i++) { + pmsg = &msgs[i]; + if (i) { + ret = diolan_i2c_repeated_start(dev); + if (ret < 0) + goto abort; + } + if (pmsg->flags & I2C_M_RD) { + ret = + diolan_i2c_put_byte_ack(dev, (pmsg->addr << 1) | 1); + if (ret < 0) + goto abort; + for (j = 0; j < pmsg->len; j++) { + u8 byte; + bool ack = j < pmsg->len - 1; + + /* + * Don't send NACK if this is the first byte + * of a SMBUS_BLOCK message. + */ + if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN)) + ack = true; + + ret = diolan_i2c_get_byte_ack(dev, ack, &byte); + if (ret < 0) + goto abort; + /* + * Adjust count if first received byte is length + */ + if (j == 0 && (pmsg->flags & I2C_M_RECV_LEN)) { + if (byte == 0 + || byte > I2C_SMBUS_BLOCK_MAX) { + ret = -EPROTO; + goto abort; + } + pmsg->len += byte; + } + pmsg->buf[j] = byte; + } + } else { + ret = diolan_i2c_put_byte_ack(dev, pmsg->addr << 1); + if (ret < 0) + goto abort; + for (j = 0; j < pmsg->len; j++) { + ret = diolan_i2c_put_byte_ack(dev, + pmsg->buf[j]); + if (ret < 0) + goto abort; + } + } + } +abort: + sret = diolan_i2c_stop(dev); + if (sret < 0 && ret >= 0) + ret = sret; + return ret; +} + +/* + * Return list of supported functionality. + */ +static u32 diolan_usb_func(struct i2c_adapter *a) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL; +} + +static const struct i2c_algorithm diolan_usb_algorithm = { + .master_xfer = diolan_usb_xfer, + .functionality = diolan_usb_func, +}; + +/* device layer */ + +static const struct usb_device_id diolan_u2c_table[] = { + { USB_DEVICE(USB_VENDOR_ID_DIOLAN, USB_DEVICE_ID_DIOLAN_U2C) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, diolan_u2c_table); + +static void diolan_u2c_free(struct i2c_diolan_u2c *dev) +{ + usb_put_dev(dev->usb_dev); + kfree(dev); +} + +static int diolan_u2c_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct i2c_diolan_u2c *dev; + int ret; + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&interface->dev, "no memory for device state\n"); + ret = -ENOMEM; + goto error; + } + + dev->usb_dev = usb_get_dev(interface_to_usbdev(interface)); + dev->interface = interface; + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + /* setup i2c adapter description */ + dev->adapter.owner = THIS_MODULE; + dev->adapter.class = I2C_CLASS_HWMON; + dev->adapter.algo = &diolan_usb_algorithm; + i2c_set_adapdata(&dev->adapter, dev); + snprintf(dev->adapter.name, sizeof(dev->adapter.name), + DRIVER_NAME " at bus %03d device %03d", + dev->usb_dev->bus->busnum, dev->usb_dev->devnum); + + dev->adapter.dev.parent = &dev->interface->dev; + + /* initialize diolan i2c interface */ + ret = diolan_init(dev); + if (ret < 0) { + dev_err(&interface->dev, "failed to initialize adapter\n"); + goto error_free; + } + + /* and finally attach to i2c layer */ + ret = i2c_add_adapter(&dev->adapter); + if (ret < 0) { + dev_err(&interface->dev, "failed to add I2C adapter\n"); + goto error_free; + } + + dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n"); + + return 0; + +error_free: + usb_set_intfdata(interface, NULL); + diolan_u2c_free(dev); +error: + return ret; +} + +static void diolan_u2c_disconnect(struct usb_interface *interface) +{ + struct i2c_diolan_u2c *dev = usb_get_intfdata(interface); + + i2c_del_adapter(&dev->adapter); + usb_set_intfdata(interface, NULL); + diolan_u2c_free(dev); + + dev_dbg(&interface->dev, "disconnected\n"); +} + +static struct usb_driver diolan_u2c_driver = { + .name = DRIVER_NAME, + .probe = diolan_u2c_probe, + .disconnect = diolan_u2c_disconnect, + .id_table = diolan_u2c_table, +}; + +static int __init diolan_u2c_init(void) +{ + /* register this driver with the USB subsystem */ + return usb_register(&diolan_u2c_driver); +} + +static void __exit diolan_u2c_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&diolan_u2c_driver); +} + +module_init(diolan_u2c_init); +module_exit(diolan_u2c_exit); + +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION(DRIVER_NAME " driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 087809fce28f50098d9c3ef1a6865c722f23afd2 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Fri, 21 Jan 2011 14:11:52 +0000 Subject: dmaengine/dw_dmac: don't scan descriptors if no xfers in progress Some hardware (picoChip picoXCell in particular) sometimes has the block transfer complete bit being set for a channel after the whole transfer has completed. If we don't have any transfers in the active list then don't bother to scan the descriptors. This often happens in normal operation and doesn't require the channel to be reset. v2: cleanup whitespace Signed-off-by: Jamie Iles Signed-off-by: Dan Williams --- drivers/dma/dw_dmac.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index a3991ab0d67e..db22754be35d 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -291,6 +291,9 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) return; } + if (list_empty(&dwc->active_list)) + return; + dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp); list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { -- cgit v1.2.2 From f301c062dcdd113bc977ae1ebc8c12232f8531a9 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Fri, 21 Jan 2011 14:11:53 +0000 Subject: dmaengine/dw_dmac: allow src/dst masters to be configured at runtime Some platforms have flexible mastering capabilities and this needs to be selected at runtime. If the platform has specified private data in the form of the dw_dma_slave then fetch the source and destination masters from here. If this isn't present, default to the previous of 0 and 1. v2: cleanup whitespace Acked-by: Hans-Christian Egtvedt Signed-off-by: Jamie Iles Signed-off-by: Dan Williams --- drivers/dma/dw_dmac.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index db22754be35d..a4cf2614085a 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -32,15 +32,18 @@ * which does not support descriptor writeback. */ -/* NOTE: DMS+SMS is system-specific. We should get this information - * from the platform code somehow. - */ -#define DWC_DEFAULT_CTLLO (DWC_CTLL_DST_MSIZE(0) \ - | DWC_CTLL_SRC_MSIZE(0) \ - | DWC_CTLL_DMS(0) \ - | DWC_CTLL_SMS(1) \ - | DWC_CTLL_LLP_D_EN \ - | DWC_CTLL_LLP_S_EN) +#define DWC_DEFAULT_CTLLO(private) ({ \ + struct dw_dma_slave *__slave = (private); \ + int dms = __slave ? __slave->dst_master : 0; \ + int sms = __slave ? __slave->src_master : 1; \ + \ + (DWC_CTLL_DST_MSIZE(0) \ + | DWC_CTLL_SRC_MSIZE(0) \ + | DWC_CTLL_LLP_D_EN \ + | DWC_CTLL_LLP_S_EN \ + | DWC_CTLL_DMS(dms) \ + | DWC_CTLL_SMS(sms)); \ + }) /* * This is configuration-dependent and usually a funny size like 4095. @@ -591,7 +594,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, else src_width = dst_width = 0; - ctllo = DWC_DEFAULT_CTLLO + ctllo = DWC_DEFAULT_CTLLO(chan->private) | DWC_CTLL_DST_WIDTH(dst_width) | DWC_CTLL_SRC_WIDTH(src_width) | DWC_CTLL_DST_INC @@ -672,7 +675,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, switch (direction) { case DMA_TO_DEVICE: - ctllo = (DWC_DEFAULT_CTLLO + ctllo = (DWC_DEFAULT_CTLLO(chan->private) | DWC_CTLL_DST_WIDTH(reg_width) | DWC_CTLL_DST_FIX | DWC_CTLL_SRC_INC @@ -717,7 +720,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, } break; case DMA_FROM_DEVICE: - ctllo = (DWC_DEFAULT_CTLLO + ctllo = (DWC_DEFAULT_CTLLO(chan->private) | DWC_CTLL_SRC_WIDTH(reg_width) | DWC_CTLL_DST_INC | DWC_CTLL_SRC_FIX @@ -1129,7 +1132,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, case DMA_TO_DEVICE: desc->lli.dar = dws->tx_reg; desc->lli.sar = buf_addr + (period_len * i); - desc->lli.ctllo = (DWC_DEFAULT_CTLLO + desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private) | DWC_CTLL_DST_WIDTH(reg_width) | DWC_CTLL_SRC_WIDTH(reg_width) | DWC_CTLL_DST_FIX @@ -1140,7 +1143,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, case DMA_FROM_DEVICE: desc->lli.dar = buf_addr + (period_len * i); desc->lli.sar = dws->rx_reg; - desc->lli.ctllo = (DWC_DEFAULT_CTLLO + desc->lli.ctllo = (DWC_DEFAULT_CTLLO(chan->private) | DWC_CTLL_SRC_WIDTH(reg_width) | DWC_CTLL_DST_WIDTH(reg_width) | DWC_CTLL_DST_INC -- cgit v1.2.2 From 95ea759e9e116dade3e7386be2a3db76c90f4675 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Fri, 21 Jan 2011 14:11:54 +0000 Subject: dmaengine/dw_dmac: provide a mechanism to indicate private devices Some platforms (e.g. Picochip PC3XX) have multiple DMA controllers where some may be used for slave transfers and others for general purpose memcpy type transfers. Add a .is_private boolean to the platform data structure so that controllers can be marked as private so that the DMA_PRIVATE capability will be set for that controller. Signed-off-by: Jamie Iles Signed-off-by: Dan Williams --- drivers/dma/dw_dmac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index a4cf2614085a..08dab3badad2 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1341,6 +1341,8 @@ static int __init dw_probe(struct platform_device *pdev) dma_cap_set(DMA_MEMCPY, dw->dma.cap_mask); dma_cap_set(DMA_SLAVE, dw->dma.cap_mask); + if (pdata->is_private) + dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask); dw->dma.dev = &pdev->dev; dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources; dw->dma.device_free_chan_resources = dwc_free_chan_resources; -- cgit v1.2.2 From 00cfa730db0d8378685148e6365b9cec7384b275 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 30 Jan 2011 12:31:30 -0800 Subject: Input: wm831x - add driver for Wolfson WM831x PMIC touchscreen controllers Some of the WM831x series of PMICs from Wolfson Microelectronics include a resistive touchscreen controller. Implement support for these controllers within the input API. Platform data is supported to allow configuration of system parameters such as selection between four and five wire touchscreens and for specification of optional direct to CPU IRQs for sample availability and for pen down. Use of this feature for at least the data IRQ is strongly recommended. Thanks to Julien Boibessot for extensive testing and detailed feedback. Signed-off-by: Mark Brown Tested-by: Julien Boibessot Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/wm831x-ts.c | 355 ++++++++++++++++++++++++++++++++++ 3 files changed, 366 insertions(+) create mode 100644 drivers/input/touchscreen/wm831x-ts.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 07ac77d393a4..ec5ee98fa6f6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -423,6 +423,16 @@ config TOUCHSCREEN_UCB1400 To compile this driver as a module, choose M here: the module will be called ucb1400_ts. +config TOUCHSCREEN_WM831X + tristate "Support for WM831x touchscreen controllers" + depends on MFD_WM831X + help + This enables support for the touchscreen controller on the WM831x + series of PMICs. + + To compile this driver as a module, choose M here: the + module will be called wm831x-ts. + config TOUCHSCREEN_WM97XX tristate "Support for WM97xx AC97 touchscreen controllers" depends on AC97_BUS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 718bcc814952..e8dcfab7c2dc 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o +obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c new file mode 100644 index 000000000000..a6121bdb635d --- /dev/null +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -0,0 +1,355 @@ +/* + * Touchscreen driver for WM831x PMICs + * + * Copyright 2011 Wolfson Microelectronics plc. + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * R16424 (0x4028) - Touch Control 1 + */ +#define WM831X_TCH_ENA 0x8000 /* TCH_ENA */ +#define WM831X_TCH_CVT_ENA 0x4000 /* TCH_CVT_ENA */ +#define WM831X_TCH_SLPENA 0x1000 /* TCH_SLPENA */ +#define WM831X_TCH_Z_ENA 0x0400 /* TCH_Z_ENA */ +#define WM831X_TCH_Y_ENA 0x0200 /* TCH_Y_ENA */ +#define WM831X_TCH_X_ENA 0x0100 /* TCH_X_ENA */ +#define WM831X_TCH_DELAY_MASK 0x00E0 /* TCH_DELAY - [7:5] */ +#define WM831X_TCH_DELAY_SHIFT 5 /* TCH_DELAY - [7:5] */ +#define WM831X_TCH_DELAY_WIDTH 3 /* TCH_DELAY - [7:5] */ +#define WM831X_TCH_RATE_MASK 0x001F /* TCH_RATE - [4:0] */ +#define WM831X_TCH_RATE_SHIFT 0 /* TCH_RATE - [4:0] */ +#define WM831X_TCH_RATE_WIDTH 5 /* TCH_RATE - [4:0] */ + +/* + * R16425 (0x4029) - Touch Control 2 + */ +#define WM831X_TCH_PD_WK 0x2000 /* TCH_PD_WK */ +#define WM831X_TCH_5WIRE 0x1000 /* TCH_5WIRE */ +#define WM831X_TCH_PDONLY 0x0800 /* TCH_PDONLY */ +#define WM831X_TCH_ISEL 0x0100 /* TCH_ISEL */ +#define WM831X_TCH_RPU_MASK 0x000F /* TCH_RPU - [3:0] */ +#define WM831X_TCH_RPU_SHIFT 0 /* TCH_RPU - [3:0] */ +#define WM831X_TCH_RPU_WIDTH 4 /* TCH_RPU - [3:0] */ + +/* + * R16426-8 (0x402A-C) - Touch Data X/Y/X + */ +#define WM831X_TCH_PD 0x8000 /* TCH_PD1 */ +#define WM831X_TCH_DATA_MASK 0x0FFF /* TCH_DATA - [11:0] */ +#define WM831X_TCH_DATA_SHIFT 0 /* TCH_DATA - [11:0] */ +#define WM831X_TCH_DATA_WIDTH 12 /* TCH_DATA - [11:0] */ + +struct wm831x_ts { + struct input_dev *input_dev; + struct wm831x *wm831x; + unsigned int data_irq; + unsigned int pd_irq; + bool pressure; + bool pen_down; +}; + +static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) +{ + struct wm831x_ts *wm831x_ts = irq_data; + struct wm831x *wm831x = wm831x_ts->wm831x; + static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE }; + u16 data[3]; + int count = wm831x_ts->pressure ? 3 : 2; + int i, ret; + + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, + WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); + + ret = wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, + data); + if (ret != 0) { + dev_err(wm831x->dev, "Failed to read touch data: %d\n", + ret); + return IRQ_NONE; + } + + /* + * We get a pen down reading on every reading, report pen up if any + * individual reading does so. + */ + wm831x_ts->pen_down = true; + for (i = 0; i < count; i++) { + if (!(data[i] & WM831X_TCH_PD)) { + wm831x_ts->pen_down = false; + continue; + } + input_report_abs(wm831x_ts->input_dev, data_types[i], + data[i] & WM831X_TCH_DATA_MASK); + } + + if (!wm831x_ts->pen_down) { + disable_irq_nosync(wm831x_ts->data_irq); + + /* Don't need data any more */ + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | + WM831X_TCH_Z_ENA, 0); + + /* Flush any final samples that arrived while reading */ + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, + WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); + + wm831x_bulk_read(wm831x, WM831X_TOUCH_DATA_X, count, data); + + if (wm831x_ts->pressure) + input_report_abs(wm831x_ts->input_dev, + ABS_PRESSURE, 0); + + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); + } + + input_sync(wm831x_ts->input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) +{ + struct wm831x_ts *wm831x_ts = irq_data; + struct wm831x *wm831x = wm831x_ts->wm831x; + int ena; + + /* Start collecting data */ + ena = wm831x_ts->pressure ? WM831X_TCH_Z_ENA : 0; + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); + + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); + input_sync(wm831x_ts->input_dev); + + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, + WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); + + wm831x_ts->pen_down = true; + enable_irq(wm831x_ts->data_irq); + + return IRQ_HANDLED; +} + +static int wm831x_ts_input_open(struct input_dev *idev) +{ + struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); + struct wm831x *wm831x = wm831x_ts->wm831x; + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_ENA, WM831X_TCH_ENA); + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA); + + return 0; +} + +static void wm831x_ts_input_close(struct input_dev *idev) +{ + struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); + struct wm831x *wm831x = wm831x_ts->wm831x; + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | + WM831X_TCH_Z_ENA, 0); + + if (wm831x_ts->pen_down) + disable_irq(wm831x_ts->data_irq); +} + +static __devinit int wm831x_ts_probe(struct platform_device *pdev) +{ + struct wm831x_ts *wm831x_ts; + struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); + struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); + struct wm831x_touch_pdata *pdata = + core_pdata ? core_pdata->touch : NULL; + struct input_dev *input_dev; + int error; + + wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!wm831x_ts || !input_dev) { + error = -ENOMEM; + goto err_alloc; + } + + wm831x_ts->wm831x = wm831x; + wm831x_ts->input_dev = input_dev; + + /* + * If we have a direct IRQ use it, otherwise use the interrupt + * from the WM831x IRQ controller. + */ + if (pdata && pdata->data_irq) + wm831x_ts->data_irq = pdata->data_irq; + else + wm831x_ts->data_irq = platform_get_irq_byname(pdev, "TCHDATA"); + + if (pdata && pdata->pd_irq) + wm831x_ts->pd_irq = pdata->pd_irq; + else + wm831x_ts->pd_irq = platform_get_irq_byname(pdev, "TCHPD"); + + wm831x_ts->pressure = pdata && pdata->pressure; + + /* Five wire touchscreens can't report pressure */ + if (pdata && pdata->fivewire) { + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_5WIRE, WM831X_TCH_5WIRE); + + /* Pressure measurements are not possible for five wire mode */ + WARN_ON(pdata->pressure && pdata->fivewire); + wm831x_ts->pressure = false; + } else { + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_5WIRE, 0); + } + + if (pdata) { + switch (pdata->isel) { + default: + dev_err(&pdev->dev, "Unsupported ISEL setting: %d\n", + pdata->isel); + /* Fall through */ + case 200: + case 0: + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_ISEL, 0); + break; + case 400: + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_ISEL, WM831X_TCH_ISEL); + break; + } + } + + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_2, + WM831X_TCH_PDONLY, 0); + + /* Default to 96 samples/sec */ + wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, + WM831X_TCH_RATE_MASK, 6); + + error = request_threaded_irq(wm831x_ts->data_irq, + NULL, wm831x_ts_data_irq, + IRQF_ONESHOT, + "Touchscreen data", wm831x_ts); + if (error) { + dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", + wm831x_ts->data_irq, error); + goto err_alloc; + } + disable_irq(wm831x_ts->data_irq); + + error = request_threaded_irq(wm831x_ts->pd_irq, + NULL, wm831x_ts_pen_down_irq, + IRQF_ONESHOT, + "Touchscreen pen down", wm831x_ts); + if (error) { + dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", + wm831x_ts->pd_irq, error); + goto err_data_irq; + } + + /* set up touch configuration */ + input_dev->name = "WM831x touchscreen"; + input_dev->phys = "wm831x"; + input_dev->open = wm831x_ts_input_open; + input_dev->close = wm831x_ts_input_close; + + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + + input_set_abs_params(input_dev, ABS_X, 0, 4095, 5, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 4095, 5, 0); + if (wm831x_ts->pressure) + input_set_abs_params(input_dev, ABS_PRESSURE, 0, 4095, 5, 0); + + input_set_drvdata(input_dev, wm831x_ts); + input_dev->dev.parent = &pdev->dev; + + error = input_register_device(input_dev); + if (error) + goto err_pd_irq; + + platform_set_drvdata(pdev, wm831x_ts); + return 0; + +err_pd_irq: + free_irq(wm831x_ts->pd_irq, wm831x_ts); +err_data_irq: + free_irq(wm831x_ts->data_irq, wm831x_ts); +err_alloc: + input_free_device(input_dev); + kfree(wm831x_ts); + + return error; +} + +static __devexit int wm831x_ts_remove(struct platform_device *pdev) +{ + struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev); + + free_irq(wm831x_ts->pd_irq, wm831x_ts); + free_irq(wm831x_ts->data_irq, wm831x_ts); + input_unregister_device(wm831x_ts->input_dev); + kfree(wm831x_ts); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver wm831x_ts_driver = { + .driver = { + .name = "wm831x-touch", + .owner = THIS_MODULE, + }, + .probe = wm831x_ts_probe, + .remove = __devexit_p(wm831x_ts_remove), +}; + +static int __init wm831x_ts_init(void) +{ + return platform_driver_register(&wm831x_ts_driver); +} +module_init(wm831x_ts_init); + +static void __exit wm831x_ts_exit(void) +{ + platform_driver_unregister(&wm831x_ts_driver); +} +module_exit(wm831x_ts_exit); + +/* Module information */ +MODULE_AUTHOR("Mark Brown "); +MODULE_DESCRIPTION("WM831x PMIC touchscreen driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm831x-touch"); -- cgit v1.2.2 From cb9ab2d8e4661c811d5e9a8e687b6f736690c90e Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:04 +0100 Subject: dma40: make init function static Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 6e1d46a65d0e..52013ed4b442 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -3060,7 +3060,7 @@ static struct platform_driver d40_driver = { }, }; -int __init stedma40_init(void) +static int __init stedma40_init(void) { return platform_driver_probe(&d40_driver, d40_probe); } -- cgit v1.2.2 From 262d2915d4f11e5e78e432ab68f0ee034ef3f75f Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:05 +0100 Subject: dma40: ensure event lines get enabled The controller sometimes fails to register the enable of the event line when both src and dst event lines are used on the same logical channel. Implement the recommended software workaround, which is to retry the write until it works. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 63 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 52013ed4b442..42c88fc28815 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -303,6 +303,11 @@ struct d40_reg_val { unsigned int val; }; +static struct device *chan2dev(struct d40_chan *d40c) +{ + return &d40c->chan.dev->device; +} + static int d40_pool_lli_alloc(struct d40_desc *d40d, int lli_len, bool is_log) { @@ -701,17 +706,46 @@ static void d40_term_all(struct d40_chan *d40c) d40c->busy = false; } +static void __d40_config_set_event(struct d40_chan *d40c, bool enable, + u32 event, int reg) +{ + void __iomem *addr = d40c->base->virtbase + D40_DREG_PCBASE + + d40c->phy_chan->num * D40_DREG_PCDELTA + reg; + int tries; + + if (!enable) { + writel((D40_DEACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event)) + | ~D40_EVENTLINE_MASK(event), addr); + return; + } + + /* + * The hardware sometimes doesn't register the enable when src and dst + * event lines are active on the same logical channel. Retry to ensure + * it does. Usually only one retry is sufficient. + */ + tries = 100; + while (--tries) { + writel((D40_ACTIVATE_EVENTLINE << D40_EVENTLINE_POS(event)) + | ~D40_EVENTLINE_MASK(event), addr); + + if (readl(addr) & D40_EVENTLINE_MASK(event)) + break; + } + + if (tries != 99) + dev_dbg(chan2dev(d40c), + "[%s] workaround enable S%cLNK (%d tries)\n", + __func__, reg == D40_CHAN_REG_SSLNK ? 'S' : 'D', + 100 - tries); + + WARN_ON(!tries); +} + static void d40_config_set_event(struct d40_chan *d40c, bool do_enable) { - u32 val; unsigned long flags; - /* Notice, that disable requires the physical channel to be stopped */ - if (do_enable) - val = D40_ACTIVATE_EVENTLINE; - else - val = D40_DEACTIVATE_EVENTLINE; - spin_lock_irqsave(&d40c->phy_chan->lock, flags); /* Enable event line connected to device (or memcpy) */ @@ -719,20 +753,15 @@ static void d40_config_set_event(struct d40_chan *d40c, bool do_enable) (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH)) { u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type); - writel((val << D40_EVENTLINE_POS(event)) | - ~D40_EVENTLINE_MASK(event), - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSLNK); + __d40_config_set_event(d40c, do_enable, event, + D40_CHAN_REG_SSLNK); } + if (d40c->dma_cfg.dir != STEDMA40_PERIPH_TO_MEM) { u32 event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type); - writel((val << D40_EVENTLINE_POS(event)) | - ~D40_EVENTLINE_MASK(event), - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDLNK); + __d40_config_set_event(d40c, do_enable, event, + D40_CHAN_REG_SDLNK); } spin_unlock_irqrestore(&d40c->phy_chan->lock, flags); -- cgit v1.2.2 From 7d83a854a1a44a8f6a699503441403a36c42f66c Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:06 +0100 Subject: dma40: remove "hardware link with previous jobs" code This link in hardware with previous jobs code is: - unused, no clients using or requiring this feature - incomplete, being implemented only for physical channels - broken, only working to perform one link Remove it. This also allows us to get rid of the channel pause in the submit_tx() routine. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 113 +++--------------------------------------------- 1 file changed, 6 insertions(+), 107 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 42c88fc28815..ed2a3ebcd86c 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -94,7 +94,6 @@ struct d40_lli_pool { * during a transfer. * @node: List entry. * @is_in_client_list: true if the client owns this descriptor. - * @is_hw_linked: true if this job will automatically be continued for * the previous one. * * This descriptor is used for both logical and physical transfers. @@ -114,7 +113,6 @@ struct d40_desc { struct list_head node; bool is_in_client_list; - bool is_hw_linked; }; /** @@ -548,18 +546,6 @@ static struct d40_desc *d40_first_queued(struct d40_chan *d40c) return d; } -static struct d40_desc *d40_last_queued(struct d40_chan *d40c) -{ - struct d40_desc *d; - - if (list_empty(&d40c->queue)) - return NULL; - list_for_each_entry(d, &d40c->queue, node) - if (list_is_last(&d->node, &d40c->queue)) - break; - return d; -} - static int d40_psize_2_burst_size(bool is_log, int psize) { if (is_log) { @@ -940,77 +926,6 @@ no_suspend: return res; } -static void d40_tx_submit_log(struct d40_chan *d40c, struct d40_desc *d40d) -{ - /* TODO: Write */ -} - -static void d40_tx_submit_phy(struct d40_chan *d40c, struct d40_desc *d40d) -{ - struct d40_desc *d40d_prev = NULL; - int i; - u32 val; - - if (!list_empty(&d40c->queue)) - d40d_prev = d40_last_queued(d40c); - else if (!list_empty(&d40c->active)) - d40d_prev = d40_first_active_get(d40c); - - if (!d40d_prev) - return; - - /* Here we try to join this job with previous jobs */ - val = readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSLNK); - - /* Figure out which link we're currently transmitting */ - for (i = 0; i < d40d_prev->lli_len; i++) - if (val == d40d_prev->lli_phy.src[i].reg_lnk) - break; - - val = readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSELT) >> D40_SREG_ELEM_LOG_ECNT_POS; - - if (i == (d40d_prev->lli_len - 1) && val > 0) { - /* Change the current one */ - writel(virt_to_phys(d40d->lli_phy.src), - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSLNK); - writel(virt_to_phys(d40d->lli_phy.dst), - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDLNK); - - d40d->is_hw_linked = true; - - } else if (i < d40d_prev->lli_len) { - (void) dma_unmap_single(d40c->base->dev, - virt_to_phys(d40d_prev->lli_phy.src), - d40d_prev->lli_pool.size, - DMA_TO_DEVICE); - - /* Keep the settings */ - val = d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk & - ~D40_SREG_LNK_PHYS_LNK_MASK; - d40d_prev->lli_phy.src[d40d_prev->lli_len - 1].reg_lnk = - val | virt_to_phys(d40d->lli_phy.src); - - val = d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk & - ~D40_SREG_LNK_PHYS_LNK_MASK; - d40d_prev->lli_phy.dst[d40d_prev->lli_len - 1].reg_lnk = - val | virt_to_phys(d40d->lli_phy.dst); - - (void) dma_map_single(d40c->base->dev, - d40d_prev->lli_phy.src, - d40d_prev->lli_pool.size, - DMA_TO_DEVICE); - d40d->is_hw_linked = true; - } -} - static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) { struct d40_chan *d40c = container_of(tx->chan, @@ -1019,8 +934,6 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) struct d40_desc *d40d = container_of(tx, struct d40_desc, txd); unsigned long flags; - (void) d40_pause(&d40c->chan); - spin_lock_irqsave(&d40c->lock, flags); d40c->chan.cookie++; @@ -1030,17 +943,10 @@ static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) d40d->txd.cookie = d40c->chan.cookie; - if (d40c->log_num == D40_PHY_CHAN) - d40_tx_submit_phy(d40c, d40d); - else - d40_tx_submit_log(d40c, d40d); - d40_desc_queue(d40c, d40d); spin_unlock_irqrestore(&d40c->lock, flags); - (void) d40_resume(&d40c->chan); - return tx->cookie; } @@ -1080,21 +986,14 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c) /* Add to active queue */ d40_desc_submit(d40c, d40d); - /* - * If this job is already linked in hw, - * do not submit it. - */ - - if (!d40d->is_hw_linked) { - /* Initiate DMA job */ - d40_desc_load(d40c, d40d); + /* Initiate DMA job */ + d40_desc_load(d40c, d40d); - /* Start dma job */ - err = d40_start(d40c); + /* Start dma job */ + err = d40_start(d40c); - if (err) - return NULL; - } + if (err) + return NULL; } return d40d; -- cgit v1.2.2 From 8ca84687b91322b9eafeaf4da43a21684cd0316e Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:07 +0100 Subject: dma40: use helper for channel registers base The register offset computation for accessing channel registers is copy/pasted in several places. Create a helper function to do it. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 74 ++++++++++++++++++++----------------------------- 1 file changed, 30 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index ed2a3ebcd86c..3d4cea3cff35 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -306,6 +306,12 @@ static struct device *chan2dev(struct d40_chan *d40c) return &d40c->chan.dev->device; } +static void __iomem *chan_base(struct d40_chan *chan) +{ + return chan->base->virtbase + D40_DREG_PCBASE + + chan->phy_chan->num * D40_DREG_PCDELTA; +} + static int d40_pool_lli_alloc(struct d40_desc *d40d, int lli_len, bool is_log) { @@ -695,8 +701,7 @@ static void d40_term_all(struct d40_chan *d40c) static void __d40_config_set_event(struct d40_chan *d40c, bool enable, u32 event, int reg) { - void __iomem *addr = d40c->base->virtbase + D40_DREG_PCBASE - + d40c->phy_chan->num * D40_DREG_PCDELTA + reg; + void __iomem *addr = chan_base(d40c) + reg; int tries; if (!enable) { @@ -755,15 +760,12 @@ static void d40_config_set_event(struct d40_chan *d40c, bool do_enable) static u32 d40_chan_has_events(struct d40_chan *d40c) { + void __iomem *chanbase = chan_base(d40c); u32 val; - val = readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSLNK); + val = readl(chanbase + D40_CHAN_REG_SSLNK); + val |= readl(chanbase + D40_CHAN_REG_SDLNK); - val |= readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDLNK); return val; } @@ -810,29 +812,17 @@ static void d40_config_write(struct d40_chan *d40c) writel(var, d40c->base->virtbase + D40_DREG_PRMOE + addr_base); if (d40c->log_num != D40_PHY_CHAN) { + int lidx = (d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) + & D40_SREG_ELEM_LOG_LIDX_MASK; + void __iomem *chanbase = chan_base(d40c); + /* Set default config for CFG reg */ - writel(d40c->src_def_cfg, - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSCFG); - writel(d40c->dst_def_cfg, - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDCFG); + writel(d40c->src_def_cfg, chanbase + D40_CHAN_REG_SSCFG); + writel(d40c->dst_def_cfg, chanbase + D40_CHAN_REG_SDCFG); /* Set LIDX for lcla */ - writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) & - D40_SREG_ELEM_LOG_LIDX_MASK, - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDELT); - - writel((d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) & - D40_SREG_ELEM_LOG_LIDX_MASK, - d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSELT); - + writel(lidx, chanbase + D40_CHAN_REG_SSELT); + writel(lidx, chanbase + D40_CHAN_REG_SDELT); } } @@ -843,12 +833,12 @@ static u32 d40_residue(struct d40_chan *d40c) if (d40c->log_num != D40_PHY_CHAN) num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK) >> D40_MEM_LCSP2_ECNT_POS; - else - num_elt = (readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDELT) & - D40_SREG_ELEM_PHY_ECNT_MASK) >> - D40_SREG_ELEM_PHY_ECNT_POS; + else { + u32 val = readl(chan_base(d40c) + D40_CHAN_REG_SDELT); + num_elt = (val & D40_SREG_ELEM_PHY_ECNT_MASK) + >> D40_SREG_ELEM_PHY_ECNT_POS; + } + return num_elt * (1 << d40c->dma_cfg.dst_info.data_width); } @@ -859,10 +849,9 @@ static bool d40_tx_is_linked(struct d40_chan *d40c) if (d40c->log_num != D40_PHY_CHAN) is_link = readl(&d40c->lcpa->lcsp3) & D40_MEM_LCSP3_DLOS_MASK; else - is_link = readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDLNK) & - D40_SREG_LNK_PHYS_LNK_MASK; + is_link = readl(chan_base(d40c) + D40_CHAN_REG_SDLNK) + & D40_SREG_LNK_PHYS_LNK_MASK; + return is_link; } @@ -1550,6 +1539,7 @@ static int d40_free_dma(struct d40_chan *d40c) static bool d40_is_paused(struct d40_chan *d40c) { + void __iomem *chanbase = chan_base(d40c); bool is_paused = false; unsigned long flags; void __iomem *active_reg; @@ -1576,14 +1566,10 @@ static bool d40_is_paused(struct d40_chan *d40c) if (d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH || d40c->dma_cfg.dir == STEDMA40_MEM_TO_MEM) { event = D40_TYPE_TO_EVENT(d40c->dma_cfg.dst_dev_type); - status = readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SDLNK); + status = readl(chanbase + D40_CHAN_REG_SDLNK); } else if (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) { event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type); - status = readl(d40c->base->virtbase + D40_DREG_PCBASE + - d40c->phy_chan->num * D40_DREG_PCDELTA + - D40_CHAN_REG_SSLNK); + status = readl(chanbase + D40_CHAN_REG_SSLNK); } else { dev_err(&d40c->chan.dev->device, "[%s] Unknown direction\n", __func__); -- cgit v1.2.2 From 724a8577d80c6f8e9ac680be1cf419eddbd6f2a1 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:08 +0100 Subject: dma40: use helpers for channel type check The somewhat confusing check d40c->log_num == D40_PHY_CHAN and its variants are used in several places to check if a channel is logical or physical. Use appropriately named helpers to do this to make the code more readable. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 54 +++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 3d4cea3cff35..0073988cdaf6 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -306,6 +306,16 @@ static struct device *chan2dev(struct d40_chan *d40c) return &d40c->chan.dev->device; } +static bool chan_is_physical(struct d40_chan *chan) +{ + return chan->log_num == D40_PHY_CHAN; +} + +static bool chan_is_logical(struct d40_chan *chan) +{ + return !chan_is_physical(chan); +} + static void __iomem *chan_base(struct d40_chan *chan) { return chan->base->virtbase + D40_DREG_PCBASE + @@ -400,7 +410,7 @@ static int d40_lcla_free_all(struct d40_chan *d40c, int i; int ret = -EINVAL; - if (d40c->log_num == D40_PHY_CHAN) + if (chan_is_physical(d40c)) return 0; spin_lock_irqsave(&d40c->base->lcla_pool.lock, flags); @@ -472,7 +482,7 @@ static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d) { int curr_lcla = -EINVAL, next_lcla; - if (d40c->log_num == D40_PHY_CHAN) { + if (chan_is_physical(d40c)) { d40_phy_lli_write(d40c->base->virtbase, d40c->phy_chan->num, d40d->lli_phy.dst, @@ -788,7 +798,7 @@ static u32 d40_get_prmo(struct d40_chan *d40c) = D40_DREG_PRMO_LCHAN_SRC_LOG_DST_LOG, }; - if (d40c->log_num == D40_PHY_CHAN) + if (chan_is_physical(d40c)) return phy_map[d40c->dma_cfg.mode_opt]; else return log_map[d40c->dma_cfg.mode_opt]; @@ -802,7 +812,7 @@ static void d40_config_write(struct d40_chan *d40c) /* Odd addresses are even addresses + 4 */ addr_base = (d40c->phy_chan->num % 2) * 4; /* Setup channel mode to logical or physical */ - var = ((u32)(d40c->log_num != D40_PHY_CHAN) + 1) << + var = ((u32)(chan_is_logical(d40c)) + 1) << D40_CHAN_POS(d40c->phy_chan->num); writel(var, d40c->base->virtbase + D40_DREG_PRMSE + addr_base); @@ -811,7 +821,7 @@ static void d40_config_write(struct d40_chan *d40c) writel(var, d40c->base->virtbase + D40_DREG_PRMOE + addr_base); - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { int lidx = (d40c->phy_chan->num << D40_SREG_ELEM_LOG_LIDX_POS) & D40_SREG_ELEM_LOG_LIDX_MASK; void __iomem *chanbase = chan_base(d40c); @@ -830,7 +840,7 @@ static u32 d40_residue(struct d40_chan *d40c) { u32 num_elt; - if (d40c->log_num != D40_PHY_CHAN) + if (chan_is_logical(d40c)) num_elt = (readl(&d40c->lcpa->lcsp2) & D40_MEM_LCSP2_ECNT_MASK) >> D40_MEM_LCSP2_ECNT_POS; else { @@ -846,7 +856,7 @@ static bool d40_tx_is_linked(struct d40_chan *d40c) { bool is_link; - if (d40c->log_num != D40_PHY_CHAN) + if (chan_is_logical(d40c)) is_link = readl(&d40c->lcpa->lcsp3) & D40_MEM_LCSP3_DLOS_MASK; else is_link = readl(chan_base(d40c) + D40_CHAN_REG_SDLNK) @@ -869,7 +879,7 @@ static int d40_pause(struct dma_chan *chan) res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); if (res == 0) { - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { d40_config_set_event(d40c, false); /* Resume the other logical channels if any */ if (d40_chan_has_events(d40c)) @@ -895,7 +905,7 @@ static int d40_resume(struct dma_chan *chan) spin_lock_irqsave(&d40c->lock, flags); if (d40c->base->rev == 0) - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); goto no_suspend; @@ -904,7 +914,7 @@ static int d40_resume(struct dma_chan *chan) /* If bytes left to transfer or linked tx resume job */ if (d40_residue(d40c) || d40_tx_is_linked(d40c)) { - if (d40c->log_num != D40_PHY_CHAN) + if (chan_is_logical(d40c)) d40_config_set_event(d40c, true); res = d40_channel_execute_command(d40c, D40_DMA_RUN); @@ -944,7 +954,7 @@ static int d40_start(struct d40_chan *d40c) if (d40c->base->rev == 0) { int err; - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { err = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); if (err) @@ -952,7 +962,7 @@ static int d40_start(struct d40_chan *d40c) } } - if (d40c->log_num != D40_PHY_CHAN) + if (chan_is_logical(d40c)) d40_config_set_event(d40c, true); return d40_channel_execute_command(d40c, D40_DMA_RUN); @@ -1495,7 +1505,7 @@ static int d40_free_dma(struct d40_chan *d40c) return res; } - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { /* Release logical channel, deactivate the event line */ d40_config_set_event(d40c, false); @@ -1548,7 +1558,7 @@ static bool d40_is_paused(struct d40_chan *d40c) spin_lock_irqsave(&d40c->lock, flags); - if (d40c->log_num == D40_PHY_CHAN) { + if (chan_is_physical(d40c)) { if (d40c->phy_chan->num % 2 == 0) active_reg = d40c->base->virtbase + D40_DREG_ACTIVE; else @@ -1638,7 +1648,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, d40d->lli_current = 0; d40d->txd.flags = dma_flags; - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { dev_err(&d40c->chan.dev->device, @@ -1765,9 +1775,9 @@ static int d40_alloc_chan_resources(struct dma_chan *chan) /* Fill in basic CFG register values */ d40_phy_cfg(&d40c->dma_cfg, &d40c->src_def_cfg, - &d40c->dst_def_cfg, d40c->log_num != D40_PHY_CHAN); + &d40c->dst_def_cfg, chan_is_logical(d40c)); - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { d40_log_cfg(&d40c->dma_cfg, &d40c->log_def.lcsp1, &d40c->log_def.lcsp3); @@ -1857,7 +1867,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, d40d->txd.tx_submit = d40_tx_submit; - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { dev_err(&d40c->chan.dev->device, @@ -2093,7 +2103,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, if (d40d == NULL) goto err; - if (d40c->log_num != D40_PHY_CHAN) + if (chan_is_logical(d40c)) err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len, direction, dma_flags); else @@ -2103,7 +2113,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, dev_err(&d40c->chan.dev->device, "[%s] Failed to prepare %s slave sg job: %d\n", __func__, - d40c->log_num != D40_PHY_CHAN ? "log" : "phy", err); + chan_is_logical(d40c) ? "log" : "phy", err); goto err; } @@ -2253,7 +2263,7 @@ static void d40_set_runtime_config(struct dma_chan *chan, return; } - if (d40c->log_num != D40_PHY_CHAN) { + if (chan_is_logical(d40c)) { if (config_maxburst >= 16) psize = STEDMA40_PSIZE_LOG_16; else if (config_maxburst >= 8) @@ -2286,7 +2296,7 @@ static void d40_set_runtime_config(struct dma_chan *chan, cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; /* Fill in register values */ - if (d40c->log_num != D40_PHY_CHAN) + if (chan_is_logical(d40c)) d40_log_cfg(cfg, &d40c->log_def.lcsp1, &d40c->log_def.lcsp3); else d40_phy_cfg(cfg, &d40c->src_def_cfg, -- cgit v1.2.2 From 6db5a8ba11bf23d1618e392518f1684cbf2fe031 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:09 +0100 Subject: dma40: use helpers for error functions Almost every use of dev_err in this driver prints the function name. Abstract out wrappers to help with this and reduce code duplication. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 201 ++++++++++++++++++------------------------------ 1 file changed, 74 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 0073988cdaf6..ab3ca6af7dbd 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -322,6 +322,12 @@ static void __iomem *chan_base(struct d40_chan *chan) chan->phy_chan->num * D40_DREG_PCDELTA; } +#define d40_err(dev, format, arg...) \ + dev_err(dev, "[%s] " format, __func__, ## arg) + +#define chan_err(d40c, format, arg...) \ + d40_err(chan2dev(d40c), format, ## arg) + static int d40_pool_lli_alloc(struct d40_desc *d40d, int lli_len, bool is_log) { @@ -673,9 +679,9 @@ static int d40_channel_execute_command(struct d40_chan *d40c, } if (i == D40_SUSPEND_MAX_IT) { - dev_err(&d40c->chan.dev->device, - "[%s]: unable to suspend the chl %d (log: %d) status %x\n", - __func__, d40c->phy_chan->num, d40c->log_num, + chan_err(d40c, + "unable to suspend the chl %d (log: %d) status %x\n", + d40c->phy_chan->num, d40c->log_num, status); dump_stack(); ret = -EBUSY; @@ -1143,9 +1149,8 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data) if (!il[row].is_error) dma_tc_handle(d40c); else - dev_err(base->dev, - "[%s] IRQ chan: %ld offset %d idx %d\n", - __func__, chan, il[row].offset, idx); + d40_err(base->dev, "IRQ chan: %ld offset %d idx %d\n", + chan, il[row].offset, idx); spin_unlock(&d40c->lock); } @@ -1164,8 +1169,7 @@ static int d40_validate_conf(struct d40_chan *d40c, bool is_log = conf->mode == STEDMA40_MODE_LOGICAL; if (!conf->dir) { - dev_err(&d40c->chan.dev->device, "[%s] Invalid direction.\n", - __func__); + chan_err(d40c, "Invalid direction.\n"); res = -EINVAL; } @@ -1173,46 +1177,40 @@ static int d40_validate_conf(struct d40_chan *d40c, d40c->base->plat_data->dev_tx[conf->dst_dev_type] == 0 && d40c->runtime_addr == 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Invalid TX channel address (%d)\n", - __func__, conf->dst_dev_type); + chan_err(d40c, "Invalid TX channel address (%d)\n", + conf->dst_dev_type); res = -EINVAL; } if (conf->src_dev_type != STEDMA40_DEV_SRC_MEMORY && d40c->base->plat_data->dev_rx[conf->src_dev_type] == 0 && d40c->runtime_addr == 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Invalid RX channel address (%d)\n", - __func__, conf->src_dev_type); + chan_err(d40c, "Invalid RX channel address (%d)\n", + conf->src_dev_type); res = -EINVAL; } if (conf->dir == STEDMA40_MEM_TO_PERIPH && dst_event_group == STEDMA40_DEV_DST_MEMORY) { - dev_err(&d40c->chan.dev->device, "[%s] Invalid dst\n", - __func__); + chan_err(d40c, "Invalid dst\n"); res = -EINVAL; } if (conf->dir == STEDMA40_PERIPH_TO_MEM && src_event_group == STEDMA40_DEV_SRC_MEMORY) { - dev_err(&d40c->chan.dev->device, "[%s] Invalid src\n", - __func__); + chan_err(d40c, "Invalid src\n"); res = -EINVAL; } if (src_event_group == STEDMA40_DEV_SRC_MEMORY && dst_event_group == STEDMA40_DEV_DST_MEMORY && is_log) { - dev_err(&d40c->chan.dev->device, - "[%s] No event line\n", __func__); + chan_err(d40c, "No event line\n"); res = -EINVAL; } if (conf->dir == STEDMA40_PERIPH_TO_PERIPH && (src_event_group != dst_event_group)) { - dev_err(&d40c->chan.dev->device, - "[%s] Invalid event group\n", __func__); + chan_err(d40c, "Invalid event group\n"); res = -EINVAL; } @@ -1221,9 +1219,7 @@ static int d40_validate_conf(struct d40_chan *d40c, * DMAC HW supports it. Will be added to this driver, * in case any dma client requires it. */ - dev_err(&d40c->chan.dev->device, - "[%s] periph to periph not supported\n", - __func__); + chan_err(d40c, "periph to periph not supported\n"); res = -EINVAL; } @@ -1236,9 +1232,7 @@ static int d40_validate_conf(struct d40_chan *d40c, * src (burst x width) == dst (burst x width) */ - dev_err(&d40c->chan.dev->device, - "[%s] src (burst x width) != dst (burst x width)\n", - __func__); + chan_err(d40c, "src (burst x width) != dst (burst x width)\n"); res = -EINVAL; } @@ -1441,8 +1435,7 @@ static int d40_config_memcpy(struct d40_chan *d40c) dma_has_cap(DMA_SLAVE, cap)) { d40c->dma_cfg = *d40c->base->plat_data->memcpy_conf_phy; } else { - dev_err(&d40c->chan.dev->device, "[%s] No memcpy\n", - __func__); + chan_err(d40c, "No memcpy\n"); return -EINVAL; } @@ -1473,15 +1466,13 @@ static int d40_free_dma(struct d40_chan *d40c) } if (phy == NULL) { - dev_err(&d40c->chan.dev->device, "[%s] phy == null\n", - __func__); + chan_err(d40c, "phy == null\n"); return -EINVAL; } if (phy->allocated_src == D40_ALLOC_FREE && phy->allocated_dst == D40_ALLOC_FREE) { - dev_err(&d40c->chan.dev->device, "[%s] channel already free\n", - __func__); + chan_err(d40c, "channel already free\n"); return -EINVAL; } @@ -1493,15 +1484,13 @@ static int d40_free_dma(struct d40_chan *d40c) event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type); is_src = true; } else { - dev_err(&d40c->chan.dev->device, - "[%s] Unknown direction\n", __func__); + chan_err(d40c, "Unknown direction\n"); return -EINVAL; } res = d40_channel_execute_command(d40c, D40_DMA_SUSPEND_REQ); if (res) { - dev_err(&d40c->chan.dev->device, "[%s] suspend failed\n", - __func__); + chan_err(d40c, "suspend failed\n"); return res; } @@ -1521,9 +1510,8 @@ static int d40_free_dma(struct d40_chan *d40c) res = d40_channel_execute_command(d40c, D40_DMA_RUN); if (res) { - dev_err(&d40c->chan.dev->device, - "[%s] Executing RUN command\n", - __func__); + chan_err(d40c, + "Executing RUN command\n"); return res; } } @@ -1536,8 +1524,7 @@ static int d40_free_dma(struct d40_chan *d40c) /* Release physical channel */ res = d40_channel_execute_command(d40c, D40_DMA_STOP); if (res) { - dev_err(&d40c->chan.dev->device, - "[%s] Failed to stop channel\n", __func__); + chan_err(d40c, "Failed to stop channel\n"); return res; } d40c->phy_chan = NULL; @@ -1581,8 +1568,7 @@ static bool d40_is_paused(struct d40_chan *d40c) event = D40_TYPE_TO_EVENT(d40c->dma_cfg.src_dev_type); status = readl(chanbase + D40_CHAN_REG_SSLNK); } else { - dev_err(&d40c->chan.dev->device, - "[%s] Unknown direction\n", __func__); + chan_err(d40c, "Unknown direction\n"); goto _exit; } @@ -1625,8 +1611,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, unsigned long flags; if (d40c->phy_chan == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Unallocated channel.\n", __func__); + chan_err(d40c, "Unallocated channel.\n"); return ERR_PTR(-EINVAL); } @@ -1640,8 +1625,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.data_width); if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); + chan_err(d40c, "Unaligned size\n"); goto err; } @@ -1651,8 +1635,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, if (chan_is_logical(d40c)) { if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Out of memory\n", __func__); + chan_err(d40c, "Out of memory\n"); goto err; } @@ -1671,8 +1654,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, d40c->dma_cfg.src_info.data_width); } else { if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Out of memory\n", __func__); + chan_err(d40c, "Out of memory\n"); goto err; } @@ -1758,9 +1740,7 @@ static int d40_alloc_chan_resources(struct dma_chan *chan) if (!d40c->configured) { err = d40_config_memcpy(d40c); if (err) { - dev_err(&d40c->chan.dev->device, - "[%s] Failed to configure memcpy channel\n", - __func__); + chan_err(d40c, "Failed to configure memcpy channel\n"); goto fail; } } @@ -1768,8 +1748,7 @@ static int d40_alloc_chan_resources(struct dma_chan *chan) err = d40_allocate_channel(d40c); if (err) { - dev_err(&d40c->chan.dev->device, - "[%s] Failed to allocate channel\n", __func__); + chan_err(d40c, "Failed to allocate channel\n"); goto fail; } @@ -1810,8 +1789,7 @@ static void d40_free_chan_resources(struct dma_chan *chan) unsigned long flags; if (d40c->phy_chan == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Cannot free unallocated channel\n", __func__); + chan_err(d40c, "Cannot free unallocated channel\n"); return; } @@ -1821,8 +1799,7 @@ static void d40_free_chan_resources(struct dma_chan *chan) err = d40_free_dma(d40c); if (err) - dev_err(&d40c->chan.dev->device, - "[%s] Failed to free channel\n", __func__); + chan_err(d40c, "Failed to free channel\n"); spin_unlock_irqrestore(&d40c->lock, flags); } @@ -1838,8 +1815,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, unsigned long flags; if (d40c->phy_chan == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Channel is not allocated.\n", __func__); + chan_err(d40c, "Channel is not allocated.\n"); return ERR_PTR(-EINVAL); } @@ -1847,8 +1823,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, d40d = d40_desc_get(d40c); if (d40d == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Descriptor is NULL\n", __func__); + chan_err(d40c, "Descriptor is NULL\n"); goto err; } @@ -1857,8 +1832,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.data_width); if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); + chan_err(d40c, "Unaligned size\n"); goto err; } @@ -1870,8 +1844,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, if (chan_is_logical(d40c)) { if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Out of memory\n", __func__); + chan_err(d40c, "Out of memory\n"); goto err; } d40d->lli_current = 0; @@ -1897,8 +1870,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, } else { if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Out of memory\n", __func__); + chan_err(d40c, "Out of memory\n"); goto err; } @@ -1966,14 +1938,12 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.data_width); if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); + chan_err(d40c, "Unaligned size\n"); return -EINVAL; } if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Out of memory\n", __func__); + chan_err(d40c, "Out of memory\n"); return -ENOMEM; } @@ -2022,14 +1992,12 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, d40c->dma_cfg.src_info.data_width, d40c->dma_cfg.dst_info.data_width); if (d40d->lli_len < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Unaligned size\n", __func__); + chan_err(d40c, "Unaligned size\n"); return -EINVAL; } if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { - dev_err(&d40c->chan.dev->device, - "[%s] Out of memory\n", __func__); + chan_err(d40c, "Out of memory\n"); return -ENOMEM; } @@ -2092,8 +2060,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, int err; if (d40c->phy_chan == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Cannot prepare unallocated channel\n", __func__); + chan_err(d40c, "Cannot prepare unallocated channel\n"); return ERR_PTR(-EINVAL); } @@ -2110,9 +2077,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, err = d40_prep_slave_sg_phy(d40d, d40c, sgl, sg_len, direction, dma_flags); if (err) { - dev_err(&d40c->chan.dev->device, - "[%s] Failed to prepare %s slave sg job: %d\n", - __func__, + chan_err(d40c, "Failed to prepare %s slave sg job: %d\n", chan_is_logical(d40c) ? "log" : "phy", err); goto err; } @@ -2143,9 +2108,7 @@ static enum dma_status d40_tx_status(struct dma_chan *chan, int ret; if (d40c->phy_chan == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Cannot read status of unallocated channel\n", - __func__); + chan_err(d40c, "Cannot read status of unallocated channel\n"); return -EINVAL; } @@ -2169,8 +2132,7 @@ static void d40_issue_pending(struct dma_chan *chan) unsigned long flags; if (d40c->phy_chan == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Channel is not allocated!\n", __func__); + chan_err(d40c, "Channel is not allocated!\n"); return; } @@ -2321,8 +2283,7 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); if (d40c->phy_chan == NULL) { - dev_err(&d40c->chan.dev->device, - "[%s] Channel is not allocated!\n", __func__); + chan_err(d40c, "Channel is not allocated!\n"); return -EINVAL; } @@ -2404,9 +2365,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, err = dma_async_device_register(&base->dma_slave); if (err) { - dev_err(base->dev, - "[%s] Failed to register slave channels\n", - __func__); + d40_err(base->dev, "Failed to register slave channels\n"); goto failure1; } @@ -2435,9 +2394,8 @@ static int __init d40_dmaengine_init(struct d40_base *base, err = dma_async_device_register(&base->dma_memcpy); if (err) { - dev_err(base->dev, - "[%s] Failed to regsiter memcpy only channels\n", - __func__); + d40_err(base->dev, + "Failed to regsiter memcpy only channels\n"); goto failure2; } @@ -2462,9 +2420,8 @@ static int __init d40_dmaengine_init(struct d40_base *base, err = dma_async_device_register(&base->dma_both); if (err) { - dev_err(base->dev, - "[%s] Failed to register logical and physical capable channels\n", - __func__); + d40_err(base->dev, + "Failed to register logical and physical capable channels\n"); goto failure3; } return 0; @@ -2566,8 +2523,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { - dev_err(&pdev->dev, "[%s] No matching clock found\n", - __func__); + d40_err(&pdev->dev, "No matching clock found\n"); goto failure; } @@ -2590,9 +2546,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(dma_id_regs); i++) { if (dma_id_regs[i].val != readl(virtbase + dma_id_regs[i].reg)) { - dev_err(&pdev->dev, - "[%s] Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n", - __func__, + d40_err(&pdev->dev, + "Unknown hardware! Expected 0x%x at 0x%x but got 0x%x\n", dma_id_regs[i].val, dma_id_regs[i].reg, readl(virtbase + dma_id_regs[i].reg)); @@ -2605,9 +2560,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) if ((val & D40_DREG_PERIPHID2_DESIGNER_MASK) != D40_HW_DESIGNER) { - dev_err(&pdev->dev, - "[%s] Unknown designer! Got %x wanted %x\n", - __func__, val & D40_DREG_PERIPHID2_DESIGNER_MASK, + d40_err(&pdev->dev, "Unknown designer! Got %x wanted %x\n", + val & D40_DREG_PERIPHID2_DESIGNER_MASK, D40_HW_DESIGNER); goto failure; } @@ -2637,7 +2591,7 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) sizeof(struct d40_chan), GFP_KERNEL); if (base == NULL) { - dev_err(&pdev->dev, "[%s] Out of memory\n", __func__); + d40_err(&pdev->dev, "Out of memory\n"); goto failure; } @@ -2809,9 +2763,8 @@ static int __init d40_lcla_allocate(struct d40_base *base) base->lcla_pool.pages); if (!page_list[i]) { - dev_err(base->dev, - "[%s] Failed to allocate %d pages.\n", - __func__, base->lcla_pool.pages); + d40_err(base->dev, "Failed to allocate %d pages.\n", + base->lcla_pool.pages); for (j = 0; j < i; j++) free_pages(page_list[j], base->lcla_pool.pages); @@ -2881,9 +2834,7 @@ static int __init d40_probe(struct platform_device *pdev) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lcpa"); if (!res) { ret = -ENOENT; - dev_err(&pdev->dev, - "[%s] No \"lcpa\" memory resource\n", - __func__); + d40_err(&pdev->dev, "No \"lcpa\" memory resource\n"); goto failure; } base->lcpa_size = resource_size(res); @@ -2892,9 +2843,9 @@ static int __init d40_probe(struct platform_device *pdev) if (request_mem_region(res->start, resource_size(res), D40_NAME " I/O lcpa") == NULL) { ret = -EBUSY; - dev_err(&pdev->dev, - "[%s] Failed to request LCPA region 0x%x-0x%x\n", - __func__, res->start, res->end); + d40_err(&pdev->dev, + "Failed to request LCPA region 0x%x-0x%x\n", + res->start, res->end); goto failure; } @@ -2910,16 +2861,13 @@ static int __init d40_probe(struct platform_device *pdev) base->lcpa_base = ioremap(res->start, resource_size(res)); if (!base->lcpa_base) { ret = -ENOMEM; - dev_err(&pdev->dev, - "[%s] Failed to ioremap LCPA region\n", - __func__); + d40_err(&pdev->dev, "Failed to ioremap LCPA region\n"); goto failure; } ret = d40_lcla_allocate(base); if (ret) { - dev_err(&pdev->dev, "[%s] Failed to allocate LCLA area\n", - __func__); + d40_err(&pdev->dev, "Failed to allocate LCLA area\n"); goto failure; } @@ -2928,9 +2876,8 @@ static int __init d40_probe(struct platform_device *pdev) base->irq = platform_get_irq(pdev, 0); ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base); - if (ret) { - dev_err(&pdev->dev, "[%s] No IRQ defined\n", __func__); + d40_err(&pdev->dev, "No IRQ defined\n"); goto failure; } @@ -2973,7 +2920,7 @@ failure: kfree(base); } - dev_err(&pdev->dev, "[%s] probe failed\n", __func__); + d40_err(&pdev->dev, "probe failed\n"); return ret; } -- cgit v1.2.2 From 4d5949009e585b2bcf09dc4de625351f987a1e6d Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:10 +0100 Subject: dma40: fix comment to refer to SOCs rather than boards And add DB8500v2 information. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index ab3ca6af7dbd..0faae662ad15 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2497,9 +2497,10 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev) { .reg = D40_DREG_PERIPHID1, .val = 0x0000}, /* * D40_DREG_PERIPHID2 Depends on HW revision: - * MOP500/HREF ED has 0x0008, + * DB8500ed has 0x0008, * ? has 0x0018, - * HREF V1 has 0x0028 + * DB8500v1 has 0x0028 + * DB8500v2 has 0x0038 */ { .reg = D40_DREG_PERIPHID3, .val = 0x0000}, -- cgit v1.2.2 From ac2c0a387194f45c759572b3462d1bf92ec92f00 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:11 +0100 Subject: dma40: allow realtime and priority for event lines DB8500v2's DMA40 (revision 3) allows setting event lines as high priority and real time. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 34 ++++++++++++++++++++++++++++++++++ drivers/dma/ste_dma40_ll.h | 16 ++++++++++++++++ 2 files changed, 50 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 0faae662ad15..ce5516221581 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1724,6 +1724,38 @@ bool stedma40_filter(struct dma_chan *chan, void *data) } EXPORT_SYMBOL(stedma40_filter); +static void __d40_set_prio_rt(struct d40_chan *d40c, int dev_type, bool src) +{ + bool realtime = d40c->dma_cfg.realtime; + bool highprio = d40c->dma_cfg.high_priority; + u32 prioreg = highprio ? D40_DREG_PSEG1 : D40_DREG_PCEG1; + u32 rtreg = realtime ? D40_DREG_RSEG1 : D40_DREG_RCEG1; + u32 event = D40_TYPE_TO_EVENT(dev_type); + u32 group = D40_TYPE_TO_GROUP(dev_type); + u32 bit = 1 << event; + + /* Destination event lines are stored in the upper halfword */ + if (!src) + bit <<= 16; + + writel(bit, d40c->base->virtbase + prioreg + group * 4); + writel(bit, d40c->base->virtbase + rtreg + group * 4); +} + +static void d40_set_prio_realtime(struct d40_chan *d40c) +{ + if (d40c->base->rev < 3) + return; + + if ((d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_MEM) || + (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH)) + __d40_set_prio_rt(d40c, d40c->dma_cfg.src_dev_type, true); + + if ((d40c->dma_cfg.dir == STEDMA40_MEM_TO_PERIPH) || + (d40c->dma_cfg.dir == STEDMA40_PERIPH_TO_PERIPH)) + __d40_set_prio_rt(d40c, d40c->dma_cfg.dst_dev_type, false); +} + /* DMA ENGINE functions */ static int d40_alloc_chan_resources(struct dma_chan *chan) { @@ -1756,6 +1788,8 @@ static int d40_alloc_chan_resources(struct dma_chan *chan) d40_phy_cfg(&d40c->dma_cfg, &d40c->src_def_cfg, &d40c->dst_def_cfg, chan_is_logical(d40c)); + d40_set_prio_realtime(d40c); + if (chan_is_logical(d40c)) { d40_log_cfg(&d40c->dma_cfg, &d40c->log_def.lcsp1, &d40c->log_def.lcsp3); diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 9cc43495bea2..e93f394187a3 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -163,6 +163,22 @@ #define D40_DREG_LCEIS1 0x0B4 #define D40_DREG_LCEIS2 0x0B8 #define D40_DREG_LCEIS3 0x0BC +#define D40_DREG_PSEG1 0x110 +#define D40_DREG_PSEG2 0x114 +#define D40_DREG_PSEG3 0x118 +#define D40_DREG_PSEG4 0x11C +#define D40_DREG_PCEG1 0x120 +#define D40_DREG_PCEG2 0x124 +#define D40_DREG_PCEG3 0x128 +#define D40_DREG_PCEG4 0x12C +#define D40_DREG_RSEG1 0x130 +#define D40_DREG_RSEG2 0x134 +#define D40_DREG_RSEG3 0x138 +#define D40_DREG_RSEG4 0x13C +#define D40_DREG_RCEG1 0x140 +#define D40_DREG_RCEG2 0x144 +#define D40_DREG_RCEG3 0x148 +#define D40_DREG_RCEG4 0x14C #define D40_DREG_STFU 0xFC8 #define D40_DREG_ICFG 0xFCC #define D40_DREG_PERIPHID0 0xFE0 -- cgit v1.2.2 From 594ece4dc0e8ac222945ef2048430600ad3c7644 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:12 +0100 Subject: dma40: remove unnecessary ALIGN()s ALIGN(x * y, y) == x * y ALIGN(aligned + x * y, y) == aligned + x * y Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index ce5516221581..d32a9ac86084 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -344,7 +344,7 @@ static int d40_pool_lli_alloc(struct d40_desc *d40d, d40d->lli_pool.size = sizeof(d40d->lli_pool.pre_alloc_lli); d40d->lli_pool.base = NULL; } else { - d40d->lli_pool.size = ALIGN(lli_len * 2 * align, align); + d40d->lli_pool.size = lli_len * 2 * align; base = kmalloc(d40d->lli_pool.size + align, GFP_NOWAIT); d40d->lli_pool.base = base; @@ -356,13 +356,11 @@ static int d40_pool_lli_alloc(struct d40_desc *d40d, if (is_log) { d40d->lli_log.src = PTR_ALIGN((struct d40_log_lli *) base, align); - d40d->lli_log.dst = PTR_ALIGN(d40d->lli_log.src + lli_len, - align); + d40d->lli_log.dst = d40d->lli_log.src + lli_len; } else { d40d->lli_phy.src = PTR_ALIGN((struct d40_phy_lli *)base, align); - d40d->lli_phy.dst = PTR_ALIGN(d40d->lli_phy.src + lli_len, - align); + d40d->lli_phy.dst = d40d->lli_phy.src + lli_len; } return 0; -- cgit v1.2.2 From 7fe8be5a74eb058b0b48970caef83e0215f55944 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:13 +0100 Subject: dma40: use sg_dma_address() instead of sg_phys() The address to use for DMA should be taken from sg_dma_address() and not sg_phys(). Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40_ll.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 0b096a38322d..6f03f580c492 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -272,7 +272,7 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, if (target) dst = target; else - dst = sg_phys(current_sg); + dst = sg_dma_address(current_sg); l_phys = ALIGN(lli_phys + (lli - lli_sg) * sizeof(struct d40_phy_lli), D40_LLI_ALIGN); @@ -416,7 +416,7 @@ int d40_log_sg_to_dev(struct scatterlist *sg, if (direction == DMA_TO_DEVICE) { lli_src = d40_log_buf_to_lli(lli_src, - sg_phys(current_sg), + sg_dma_address(current_sg), sg_dma_len(current_sg), lcsp->lcsp1, src_data_width, dst_data_width, @@ -431,7 +431,7 @@ int d40_log_sg_to_dev(struct scatterlist *sg, } else { lli_dst = d40_log_buf_to_lli(lli_dst, - sg_phys(current_sg), + sg_dma_address(current_sg), sg_dma_len(current_sg), lcsp->lcsp3, dst_data_width, src_data_width, @@ -491,7 +491,7 @@ int d40_log_sg_to_lli(struct scatterlist *sg, for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); lli = d40_log_buf_to_lli(lli, - sg_phys(current_sg), + sg_dma_address(current_sg), sg_dma_len(current_sg), lcsp13, data_width1, data_width2, true); -- cgit v1.2.2 From 026cbc424a162e495ad29e91d354fb8fc2da2657 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:14 +0100 Subject: dma40: fix DMA API usage for LCLA Map the buffer once and use dma_sync*() appropriately instead of mapping the buffer over and over without unmapping it. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index d32a9ac86084..f08e5c49c5d2 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -128,6 +128,7 @@ struct d40_desc { */ struct d40_lcla_pool { void *base; + dma_addr_t dma_addr; void *base_unaligned; int pages; spinlock_t lock; @@ -504,25 +505,25 @@ static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d) d40d->lli_current++; for (; d40d->lli_current < d40d->lli_len; d40d->lli_current++) { - struct d40_log_lli *lcla; + unsigned int lcla_offset = d40c->phy_chan->num * 1024 + + 8 * curr_lcla * 2; + struct d40_lcla_pool *pool = &d40c->base->lcla_pool; + struct d40_log_lli *lcla = pool->base + lcla_offset; if (d40d->lli_current + 1 < d40d->lli_len) next_lcla = d40_lcla_alloc_one(d40c, d40d); else next_lcla = -EINVAL; - lcla = d40c->base->lcla_pool.base + - d40c->phy_chan->num * 1024 + - 8 * curr_lcla * 2; - d40_log_lli_lcla_write(lcla, &d40d->lli_log.dst[d40d->lli_current], &d40d->lli_log.src[d40d->lli_current], next_lcla); - (void) dma_map_single(d40c->base->dev, lcla, - 2 * sizeof(struct d40_log_lli), - DMA_TO_DEVICE); + dma_sync_single_range_for_device(d40c->base->dev, + pool->dma_addr, lcla_offset, + 2 * sizeof(struct d40_log_lli), + DMA_TO_DEVICE); curr_lcla = next_lcla; @@ -2771,6 +2772,7 @@ static void __init d40_hw_init(struct d40_base *base) static int __init d40_lcla_allocate(struct d40_base *base) { + struct d40_lcla_pool *pool = &base->lcla_pool; unsigned long *page_list; int i, j; int ret = 0; @@ -2835,6 +2837,15 @@ static int __init d40_lcla_allocate(struct d40_base *base) LCLA_ALIGNMENT); } + pool->dma_addr = dma_map_single(base->dev, pool->base, + SZ_1K * base->num_phy_chans, + DMA_TO_DEVICE); + if (dma_mapping_error(base->dev, pool->dma_addr)) { + pool->dma_addr = 0; + ret = -ENOMEM; + goto failure; + } + writel(virt_to_phys(base->lcla_pool.base), base->virtbase + D40_DREG_LCLA); failure: @@ -2929,6 +2940,12 @@ failure: kmem_cache_destroy(base->desc_slab); if (base->virtbase) iounmap(base->virtbase); + + if (base->lcla_pool.dma_addr) + dma_unmap_single(base->dev, base->lcla_pool.dma_addr, + SZ_1K * base->num_phy_chans, + DMA_TO_DEVICE); + if (!base->lcla_pool.base_unaligned && base->lcla_pool.base) free_pages((unsigned long)base->lcla_pool.base, base->lcla_pool.pages); -- cgit v1.2.2 From b00f938c8cf5ba8e7a692519548a256aa3ea1203 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:15 +0100 Subject: dma40: fix DMA API usage for LLIs Map and unmap the LLIs and use dma_sync_single_for_device() appropriately instead of mapping and never unmapping them. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 58 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index f08e5c49c5d2..b5856864d48d 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -68,6 +68,7 @@ enum d40_command { * @base: Pointer to memory area when the pre_alloc_lli's are not large * enough, IE bigger than the most common case, 1 dst and 1 src. NULL if * pre_alloc_lli is used. + * @dma_addr: DMA address, if mapped * @size: The size in bytes of the memory at base or the size of pre_alloc_lli. * @pre_alloc_lli: Pre allocated area for the most common case of transfers, * one buffer to one buffer. @@ -75,6 +76,7 @@ enum d40_command { struct d40_lli_pool { void *base; int size; + dma_addr_t dma_addr; /* Space for dst and src, plus an extra for padding */ u8 pre_alloc_lli[3 * sizeof(struct d40_phy_lli)]; }; @@ -329,7 +331,7 @@ static void __iomem *chan_base(struct d40_chan *chan) #define chan_err(d40c, format, arg...) \ d40_err(chan2dev(d40c), format, ## arg) -static int d40_pool_lli_alloc(struct d40_desc *d40d, +static int d40_pool_lli_alloc(struct d40_chan *d40c, struct d40_desc *d40d, int lli_len, bool is_log) { u32 align; @@ -358,17 +360,36 @@ static int d40_pool_lli_alloc(struct d40_desc *d40d, d40d->lli_log.src = PTR_ALIGN((struct d40_log_lli *) base, align); d40d->lli_log.dst = d40d->lli_log.src + lli_len; + + d40d->lli_pool.dma_addr = 0; } else { d40d->lli_phy.src = PTR_ALIGN((struct d40_phy_lli *)base, align); d40d->lli_phy.dst = d40d->lli_phy.src + lli_len; + + d40d->lli_pool.dma_addr = dma_map_single(d40c->base->dev, + d40d->lli_phy.src, + d40d->lli_pool.size, + DMA_TO_DEVICE); + + if (dma_mapping_error(d40c->base->dev, + d40d->lli_pool.dma_addr)) { + kfree(d40d->lli_pool.base); + d40d->lli_pool.base = NULL; + d40d->lli_pool.dma_addr = 0; + return -ENOMEM; + } } return 0; } -static void d40_pool_lli_free(struct d40_desc *d40d) +static void d40_pool_lli_free(struct d40_chan *d40c, struct d40_desc *d40d) { + if (d40d->lli_pool.dma_addr) + dma_unmap_single(d40c->base->dev, d40d->lli_pool.dma_addr, + d40d->lli_pool.size, DMA_TO_DEVICE); + kfree(d40d->lli_pool.base); d40d->lli_pool.base = NULL; d40d->lli_pool.size = 0; @@ -454,7 +475,7 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c) list_for_each_entry_safe(d, _d, &d40c->client, node) if (async_tx_test_ack(&d->txd)) { - d40_pool_lli_free(d); + d40_pool_lli_free(d40c, d); d40_desc_remove(d); desc = d; memset(desc, 0, sizeof(*desc)); @@ -474,6 +495,7 @@ static struct d40_desc *d40_desc_get(struct d40_chan *d40c) static void d40_desc_free(struct d40_chan *d40c, struct d40_desc *d40d) { + d40_pool_lli_free(d40c, d40d); d40_lcla_free_all(d40c, d40d); kmem_cache_free(d40c->base->desc_slab, d40d); } @@ -1063,7 +1085,7 @@ static void dma_tasklet(unsigned long data) callback_param = d40d->txd.callback_param; if (async_tx_test_ack(&d40d->txd)) { - d40_pool_lli_free(d40d); + d40_pool_lli_free(d40c, d40d); d40_desc_remove(d40d); d40_desc_free(d40c, d40d); } else { @@ -1459,7 +1481,7 @@ static int d40_free_dma(struct d40_chan *d40c) /* Release client owned descriptors */ if (!list_empty(&d40c->client)) list_for_each_entry_safe(d, _d, &d40c->client, node) { - d40_pool_lli_free(d); + d40_pool_lli_free(d40c, d); d40_desc_remove(d); d40_desc_free(d40c, d); } @@ -1633,7 +1655,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, if (chan_is_logical(d40c)) { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { + if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, true) < 0) { chan_err(d40c, "Out of memory\n"); goto err; } @@ -1652,7 +1674,7 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, d40c->dma_cfg.dst_info.data_width, d40c->dma_cfg.src_info.data_width); } else { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { + if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, false) < 0) { chan_err(d40c, "Out of memory\n"); goto err; } @@ -1683,8 +1705,9 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, if (res < 0) goto err; - (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src, - d40d->lli_pool.size, DMA_TO_DEVICE); + dma_sync_single_for_device(d40c->base->dev, + d40d->lli_pool.dma_addr, + d40d->lli_pool.size, DMA_TO_DEVICE); } dma_async_tx_descriptor_init(&d40d->txd, chan); @@ -1876,7 +1899,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, if (chan_is_logical(d40c)) { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { + if (d40_pool_lli_alloc(d40c,d40d, d40d->lli_len, true) < 0) { chan_err(d40c, "Out of memory\n"); goto err; } @@ -1902,7 +1925,7 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, } else { - if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { + if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, false) < 0) { chan_err(d40c, "Out of memory\n"); goto err; } @@ -1931,8 +1954,9 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, false) == NULL) goto err; - (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src, - d40d->lli_pool.size, DMA_TO_DEVICE); + dma_sync_single_for_device(d40c->base->dev, + d40d->lli_pool.dma_addr, + d40d->lli_pool.size, DMA_TO_DEVICE); } spin_unlock_irqrestore(&d40c->lock, flags); @@ -1975,7 +1999,7 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, return -EINVAL; } - if (d40_pool_lli_alloc(d40d, d40d->lli_len, true) < 0) { + if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, true) < 0) { chan_err(d40c, "Out of memory\n"); return -ENOMEM; } @@ -2029,7 +2053,7 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, return -EINVAL; } - if (d40_pool_lli_alloc(d40d, d40d->lli_len, false) < 0) { + if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, false) < 0) { chan_err(d40c, "Out of memory\n"); return -ENOMEM; } @@ -2075,8 +2099,8 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, if (res < 0) return res; - (void) dma_map_single(d40c->base->dev, d40d->lli_phy.src, - d40d->lli_pool.size, DMA_TO_DEVICE); + dma_sync_single_for_device(d40c->base->dev, d40d->lli_pool.dma_addr, + d40d->lli_pool.size, DMA_TO_DEVICE); return 0; } -- cgit v1.2.2 From d924abad7fa9a78d70b20552bf27fe4f7a19a2fb Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:16 +0100 Subject: dma40: remove unnecessary casts Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index b5856864d48d..bd72269dac08 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -357,14 +357,12 @@ static int d40_pool_lli_alloc(struct d40_chan *d40c, struct d40_desc *d40d, } if (is_log) { - d40d->lli_log.src = PTR_ALIGN((struct d40_log_lli *) base, - align); + d40d->lli_log.src = PTR_ALIGN(base, align); d40d->lli_log.dst = d40d->lli_log.src + lli_len; d40d->lli_pool.dma_addr = 0; } else { - d40d->lli_phy.src = PTR_ALIGN((struct d40_phy_lli *)base, - align); + d40d->lli_phy.src = PTR_ALIGN(base, align); d40d->lli_phy.dst = d40d->lli_phy.src + lli_len; d40d->lli_pool.dma_addr = dma_map_single(d40c->base->dev, -- cgit v1.2.2 From 95944c6ef5b5214508273992416adb836b63c73f Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:17 +0100 Subject: dma40: implement prep_memcpy as a wrapper around memcpy_sg To simplify the code. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 107 ++++----------------------------------------- drivers/dma/ste_dma40_ll.c | 2 +- drivers/dma/ste_dma40_ll.h | 11 ----- 3 files changed, 10 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index bd72269dac08..0a20179349b0 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1863,108 +1863,19 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, size_t size, unsigned long dma_flags) { - struct d40_desc *d40d; - struct d40_chan *d40c = container_of(chan, struct d40_chan, - chan); - unsigned long flags; - - if (d40c->phy_chan == NULL) { - chan_err(d40c, "Channel is not allocated.\n"); - return ERR_PTR(-EINVAL); - } - - spin_lock_irqsave(&d40c->lock, flags); - d40d = d40_desc_get(d40c); - - if (d40d == NULL) { - chan_err(d40c, "Descriptor is NULL\n"); - goto err; - } - - d40d->txd.flags = dma_flags; - d40d->lli_len = d40_size_2_dmalen(size, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - chan_err(d40c, "Unaligned size\n"); - goto err; - } - - - dma_async_tx_descriptor_init(&d40d->txd, chan); - - d40d->txd.tx_submit = d40_tx_submit; - - if (chan_is_logical(d40c)) { - - if (d40_pool_lli_alloc(d40c,d40d, d40d->lli_len, true) < 0) { - chan_err(d40c, "Out of memory\n"); - goto err; - } - d40d->lli_current = 0; - - if (d40_log_buf_to_lli(d40d->lli_log.src, - src, - size, - d40c->log_def.lcsp1, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, - true) == NULL) - goto err; - - if (d40_log_buf_to_lli(d40d->lli_log.dst, - dst, - size, - d40c->log_def.lcsp3, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, - true) == NULL) - goto err; - - } else { - - if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, false) < 0) { - chan_err(d40c, "Out of memory\n"); - goto err; - } - - if (d40_phy_buf_to_lli(d40d->lli_phy.src, - src, - size, - d40c->dma_cfg.src_info.psize, - 0, - d40c->src_def_cfg, - true, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, - false) == NULL) - goto err; + struct scatterlist dst_sg; + struct scatterlist src_sg; - if (d40_phy_buf_to_lli(d40d->lli_phy.dst, - dst, - size, - d40c->dma_cfg.dst_info.psize, - 0, - d40c->dst_def_cfg, - true, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, - false) == NULL) - goto err; + sg_init_table(&dst_sg, 1); + sg_init_table(&src_sg, 1); - dma_sync_single_for_device(d40c->base->dev, - d40d->lli_pool.dma_addr, - d40d->lli_pool.size, DMA_TO_DEVICE); - } + sg_dma_address(&dst_sg) = dst; + sg_dma_address(&src_sg) = src; - spin_unlock_irqrestore(&d40c->lock, flags); - return &d40d->txd; + sg_dma_len(&dst_sg) = size; + sg_dma_len(&src_sg) = size; -err: - if (d40d) - d40_desc_free(d40c, d40d); - spin_unlock_irqrestore(&d40c->lock, flags); - return NULL; + return stedma40_memcpy_sg(chan, &dst_sg, &src_sg, 1, dma_flags); } static struct dma_async_tx_descriptor * diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 6f03f580c492..552c5972c75e 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -198,7 +198,7 @@ static int d40_seg_size(int size, int data_width1, int data_width2) return seg_max; } -struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, +static struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, int psize, diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index e93f394187a3..a5d71714ebf7 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -312,17 +312,6 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, u32 data_width2, int psize); -struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, - dma_addr_t data, - u32 data_size, - int psize, - dma_addr_t next_lli, - u32 reg_cfg, - bool term_int, - u32 data_width1, - u32 data_width2, - bool is_device); - void d40_phy_lli_write(void __iomem *virtbase, u32 phy_chan_num, struct d40_phy_lli *lli_dst, -- cgit v1.2.2 From 5f81158f90db4bc8a79e91736aa3afce8e590e46 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:18 +0100 Subject: dma40: combine desc init functions The desc init code can be shared between the mem and slave prep routines. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 76 +++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 0a20179349b0..5259a9832435 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1617,6 +1617,35 @@ static u32 stedma40_residue(struct dma_chan *chan) return bytes_left; } +static struct d40_desc * +d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg, + unsigned int sg_len, unsigned long dma_flags) +{ + struct stedma40_chan_cfg *cfg = &chan->dma_cfg; + struct d40_desc *desc; + + desc = d40_desc_get(chan); + if (!desc) + return NULL; + + desc->lli_len = d40_sg_2_dmalen(sg, sg_len, cfg->src_info.data_width, + cfg->dst_info.data_width); + if (desc->lli_len < 0) { + chan_err(chan, "Unaligned size\n"); + d40_desc_free(chan, desc); + + return NULL; + } + + desc->lli_current = 0; + desc->txd.flags = dma_flags; + desc->txd.tx_submit = d40_tx_submit; + + dma_async_tx_descriptor_init(&desc->txd, &chan->chan); + + return desc; +} + struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, struct scatterlist *sgl_dst, struct scatterlist *sgl_src, @@ -1635,22 +1664,11 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, } spin_lock_irqsave(&d40c->lock, flags); - d40d = d40_desc_get(d40c); - if (d40d == NULL) + d40d = d40_prep_desc(d40c, sgl_dst, sgl_len, dma_flags); + if (!d40d) goto err; - d40d->lli_len = d40_sg_2_dmalen(sgl_dst, sgl_len, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - chan_err(d40c, "Unaligned size\n"); - goto err; - } - - d40d->lli_current = 0; - d40d->txd.flags = dma_flags; - if (chan_is_logical(d40c)) { if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, true) < 0) { @@ -1708,10 +1726,6 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, d40d->lli_pool.size, DMA_TO_DEVICE); } - dma_async_tx_descriptor_init(&d40d->txd, chan); - - d40d->txd.tx_submit = d40_tx_submit; - spin_unlock_irqrestore(&d40c->lock, flags); return &d40d->txd; @@ -1900,21 +1914,11 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, dma_addr_t dev_addr = 0; int total_size; - d40d->lli_len = d40_sg_2_dmalen(sgl, sg_len, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - chan_err(d40c, "Unaligned size\n"); - return -EINVAL; - } - if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, true) < 0) { chan_err(d40c, "Out of memory\n"); return -ENOMEM; } - d40d->lli_current = 0; - if (direction == DMA_FROM_DEVICE) if (d40c->runtime_addr) dev_addr = d40c->runtime_addr; @@ -1954,21 +1958,11 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, dma_addr_t dst_dev_addr; int res; - d40d->lli_len = d40_sg_2_dmalen(sgl, sgl_len, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - if (d40d->lli_len < 0) { - chan_err(d40c, "Unaligned size\n"); - return -EINVAL; - } - if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, false) < 0) { chan_err(d40c, "Out of memory\n"); return -ENOMEM; } - d40d->lli_current = 0; - if (direction == DMA_FROM_DEVICE) { dst_dev_addr = 0; if (d40c->runtime_addr) @@ -2031,8 +2025,8 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, } spin_lock_irqsave(&d40c->lock, flags); - d40d = d40_desc_get(d40c); + d40d = d40_prep_desc(d40c, sgl, sg_len, dma_flags); if (d40d == NULL) goto err; @@ -2048,12 +2042,6 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, goto err; } - d40d->txd.flags = dma_flags; - - dma_async_tx_descriptor_init(&d40d->txd, chan); - - d40d->txd.tx_submit = d40_tx_submit; - spin_unlock_irqrestore(&d40c->lock, flags); return &d40d->txd; -- cgit v1.2.2 From dbd887880320b6a56811bb38ff4ad888728c3a91 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:19 +0100 Subject: dma40: combine duplicated d40_pool_lli_alloc() calls Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 5259a9832435..495f9eb0a4b6 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -332,8 +332,9 @@ static void __iomem *chan_base(struct d40_chan *chan) d40_err(chan2dev(d40c), format, ## arg) static int d40_pool_lli_alloc(struct d40_chan *d40c, struct d40_desc *d40d, - int lli_len, bool is_log) + int lli_len) { + bool is_log = chan_is_logical(d40c); u32 align; void *base; @@ -1623,6 +1624,7 @@ d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg, { struct stedma40_chan_cfg *cfg = &chan->dma_cfg; struct d40_desc *desc; + int ret; desc = d40_desc_get(chan); if (!desc) @@ -1632,11 +1634,16 @@ d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg, cfg->dst_info.data_width); if (desc->lli_len < 0) { chan_err(chan, "Unaligned size\n"); - d40_desc_free(chan, desc); + goto err; + } - return NULL; + ret = d40_pool_lli_alloc(chan, desc, desc->lli_len); + if (ret < 0) { + chan_err(chan, "Could not allocate lli\n"); + goto err; } + desc->lli_current = 0; desc->txd.flags = dma_flags; desc->txd.tx_submit = d40_tx_submit; @@ -1644,6 +1651,10 @@ d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg, dma_async_tx_descriptor_init(&desc->txd, &chan->chan); return desc; + +err: + d40_desc_free(chan, desc); + return NULL; } struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, @@ -1670,12 +1681,6 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, goto err; if (chan_is_logical(d40c)) { - - if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, true) < 0) { - chan_err(d40c, "Out of memory\n"); - goto err; - } - (void) d40_log_sg_to_lli(sgl_src, sgl_len, d40d->lli_log.src, @@ -1690,11 +1695,6 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, d40c->dma_cfg.dst_info.data_width, d40c->dma_cfg.src_info.data_width); } else { - if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, false) < 0) { - chan_err(d40c, "Out of memory\n"); - goto err; - } - res = d40_phy_sg_to_lli(sgl_src, sgl_len, 0, @@ -1914,11 +1914,6 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, dma_addr_t dev_addr = 0; int total_size; - if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, true) < 0) { - chan_err(d40c, "Out of memory\n"); - return -ENOMEM; - } - if (direction == DMA_FROM_DEVICE) if (d40c->runtime_addr) dev_addr = d40c->runtime_addr; @@ -1958,11 +1953,6 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, dma_addr_t dst_dev_addr; int res; - if (d40_pool_lli_alloc(d40c, d40d, d40d->lli_len, false) < 0) { - chan_err(d40c, "Out of memory\n"); - return -ENOMEM; - } - if (direction == DMA_FROM_DEVICE) { dst_dev_addr = 0; if (d40c->runtime_addr) -- cgit v1.2.2 From 00ac0341486ffe212f45ff1fe0780d12a36fffde Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:20 +0100 Subject: dma40: remove duplicated dev addr code Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 66 ++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 495f9eb0a4b6..65b5aad1fc4c 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1909,25 +1909,10 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d, struct scatterlist *sgl, unsigned int sg_len, enum dma_data_direction direction, - unsigned long dma_flags) + dma_addr_t dev_addr) { - dma_addr_t dev_addr = 0; int total_size; - if (direction == DMA_FROM_DEVICE) - if (d40c->runtime_addr) - dev_addr = d40c->runtime_addr; - else - dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; - else if (direction == DMA_TO_DEVICE) - if (d40c->runtime_addr) - dev_addr = d40c->runtime_addr; - else - dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; - - else - return -EINVAL; - total_size = d40_log_sg_to_dev(sgl, sg_len, &d40d->lli_log, &d40c->log_def, @@ -1947,27 +1932,12 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, struct scatterlist *sgl, unsigned int sgl_len, enum dma_data_direction direction, - unsigned long dma_flags) + dma_addr_t dev_addr) { - dma_addr_t src_dev_addr; - dma_addr_t dst_dev_addr; + dma_addr_t src_dev_addr = direction == DMA_FROM_DEVICE ? dev_addr : 0; + dma_addr_t dst_dev_addr = direction == DMA_TO_DEVICE ? dev_addr : 0; int res; - if (direction == DMA_FROM_DEVICE) { - dst_dev_addr = 0; - if (d40c->runtime_addr) - src_dev_addr = d40c->runtime_addr; - else - src_dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; - } else if (direction == DMA_TO_DEVICE) { - if (d40c->runtime_addr) - dst_dev_addr = d40c->runtime_addr; - else - dst_dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; - src_dev_addr = 0; - } else - return -EINVAL; - res = d40_phy_sg_to_lli(sgl, sgl_len, src_dev_addr, @@ -1997,6 +1967,24 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d, return 0; } +static dma_addr_t +d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction) +{ + struct stedma40_platform_data *plat = chan->base->plat_data; + struct stedma40_chan_cfg *cfg = &chan->dma_cfg; + dma_addr_t addr; + + if (chan->runtime_addr) + return chan->runtime_addr; + + if (direction == DMA_FROM_DEVICE) + addr = plat->dev_rx[cfg->src_dev_type]; + else if (direction == DMA_TO_DEVICE) + addr = plat->dev_tx[cfg->dst_dev_type]; + + return addr; +} + static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, @@ -2006,6 +1994,7 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, struct d40_desc *d40d; struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); + dma_addr_t dev_addr; unsigned long flags; int err; @@ -2014,18 +2003,23 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, return ERR_PTR(-EINVAL); } + if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE) + return NULL; + spin_lock_irqsave(&d40c->lock, flags); d40d = d40_prep_desc(d40c, sgl, sg_len, dma_flags); if (d40d == NULL) goto err; + dev_addr = d40_get_dev_addr(d40c, direction); + if (chan_is_logical(d40c)) err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len, - direction, dma_flags); + direction, dev_addr); else err = d40_prep_slave_sg_phy(d40d, d40c, sgl, sg_len, - direction, dma_flags); + direction, dev_addr); if (err) { chan_err(d40c, "Failed to prepare %s slave sg job: %d\n", chan_is_logical(d40c) ? "log" : "phy", err); -- cgit v1.2.2 From 3e3a0763e78b520dac5fde569c42664863336d94 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:21 +0100 Subject: dma40: combine mem and slave sg-to-lli functions Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 194 +++++++++++++++++++++--------------------------- 1 file changed, 84 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 65b5aad1fc4c..8c6abc23db80 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1618,6 +1618,81 @@ static u32 stedma40_residue(struct dma_chan *chan) return bytes_left; } +static int +d40_prep_sg_log(struct d40_chan *chan, struct d40_desc *desc, + struct scatterlist *sg_src, struct scatterlist *sg_dst, + unsigned int sg_len, enum dma_data_direction direction, + dma_addr_t dev_addr) +{ + struct stedma40_chan_cfg *cfg = &chan->dma_cfg; + struct stedma40_half_channel_info *src_info = &cfg->src_info; + struct stedma40_half_channel_info *dst_info = &cfg->dst_info; + + if (direction == DMA_NONE) { + /* memcpy */ + (void) d40_log_sg_to_lli(sg_src, sg_len, + desc->lli_log.src, + chan->log_def.lcsp1, + src_info->data_width, + dst_info->data_width); + + (void) d40_log_sg_to_lli(sg_dst, sg_len, + desc->lli_log.dst, + chan->log_def.lcsp3, + dst_info->data_width, + src_info->data_width); + } else { + unsigned int total_size; + + total_size = d40_log_sg_to_dev(sg_src, sg_len, + &desc->lli_log, + &chan->log_def, + src_info->data_width, + dst_info->data_width, + direction, dev_addr); + if (total_size < 0) + return -EINVAL; + } + + return 0; +} + +static int +d40_prep_sg_phy(struct d40_chan *chan, struct d40_desc *desc, + struct scatterlist *sg_src, struct scatterlist *sg_dst, + unsigned int sg_len, enum dma_data_direction direction, + dma_addr_t dev_addr) +{ + dma_addr_t src_dev_addr = direction == DMA_FROM_DEVICE ? dev_addr : 0; + dma_addr_t dst_dev_addr = direction == DMA_TO_DEVICE ? dev_addr : 0; + struct stedma40_chan_cfg *cfg = &chan->dma_cfg; + struct stedma40_half_channel_info *src_info = &cfg->src_info; + struct stedma40_half_channel_info *dst_info = &cfg->dst_info; + int ret; + + ret = d40_phy_sg_to_lli(sg_src, sg_len, src_dev_addr, + desc->lli_phy.src, + virt_to_phys(desc->lli_phy.src), + chan->src_def_cfg, + src_info->data_width, + dst_info->data_width, + src_info->psize); + + ret = d40_phy_sg_to_lli(sg_dst, sg_len, dst_dev_addr, + desc->lli_phy.dst, + virt_to_phys(desc->lli_phy.dst), + chan->dst_def_cfg, + dst_info->data_width, + src_info->data_width, + dst_info->psize); + + dma_sync_single_for_device(chan->base->dev, desc->lli_pool.dma_addr, + desc->lli_pool.size, DMA_TO_DEVICE); + + return ret < 0 ? ret : 0; +} + + static struct d40_desc * d40_prep_desc(struct d40_chan *chan, struct scatterlist *sg, unsigned int sg_len, unsigned long dma_flags) @@ -1663,7 +1738,6 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, unsigned int sgl_len, unsigned long dma_flags) { - int res; struct d40_desc *d40d; struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); @@ -1681,49 +1755,11 @@ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, goto err; if (chan_is_logical(d40c)) { - (void) d40_log_sg_to_lli(sgl_src, - sgl_len, - d40d->lli_log.src, - d40c->log_def.lcsp1, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width); - - (void) d40_log_sg_to_lli(sgl_dst, - sgl_len, - d40d->lli_log.dst, - d40c->log_def.lcsp3, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width); + d40_prep_sg_log(d40c, d40d, sgl_src, sgl_dst, + sgl_len, DMA_NONE, 0); } else { - res = d40_phy_sg_to_lli(sgl_src, - sgl_len, - 0, - d40d->lli_phy.src, - virt_to_phys(d40d->lli_phy.src), - d40c->src_def_cfg, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.psize); - - if (res < 0) - goto err; - - res = d40_phy_sg_to_lli(sgl_dst, - sgl_len, - 0, - d40d->lli_phy.dst, - virt_to_phys(d40d->lli_phy.dst), - d40c->dst_def_cfg, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.psize); - - if (res < 0) - goto err; - - dma_sync_single_for_device(d40c->base->dev, - d40d->lli_pool.dma_addr, - d40d->lli_pool.size, DMA_TO_DEVICE); + d40_prep_sg_phy(d40c, d40d, sgl_src, sgl_dst, + sgl_len, DMA_NONE, 0); } spin_unlock_irqrestore(&d40c->lock, flags); @@ -1904,69 +1940,6 @@ d40_prep_sg(struct dma_chan *chan, return stedma40_memcpy_sg(chan, dst_sg, src_sg, dst_nents, dma_flags); } -static int d40_prep_slave_sg_log(struct d40_desc *d40d, - struct d40_chan *d40c, - struct scatterlist *sgl, - unsigned int sg_len, - enum dma_data_direction direction, - dma_addr_t dev_addr) -{ - int total_size; - - total_size = d40_log_sg_to_dev(sgl, sg_len, - &d40d->lli_log, - &d40c->log_def, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, - direction, - dev_addr); - - if (total_size < 0) - return -EINVAL; - - return 0; -} - -static int d40_prep_slave_sg_phy(struct d40_desc *d40d, - struct d40_chan *d40c, - struct scatterlist *sgl, - unsigned int sgl_len, - enum dma_data_direction direction, - dma_addr_t dev_addr) -{ - dma_addr_t src_dev_addr = direction == DMA_FROM_DEVICE ? dev_addr : 0; - dma_addr_t dst_dev_addr = direction == DMA_TO_DEVICE ? dev_addr : 0; - int res; - - res = d40_phy_sg_to_lli(sgl, - sgl_len, - src_dev_addr, - d40d->lli_phy.src, - virt_to_phys(d40d->lli_phy.src), - d40c->src_def_cfg, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.psize); - if (res < 0) - return res; - - res = d40_phy_sg_to_lli(sgl, - sgl_len, - dst_dev_addr, - d40d->lli_phy.dst, - virt_to_phys(d40d->lli_phy.dst), - d40c->dst_def_cfg, - d40c->dma_cfg.dst_info.data_width, - d40c->dma_cfg.src_info.data_width, - d40c->dma_cfg.dst_info.psize); - if (res < 0) - return res; - - dma_sync_single_for_device(d40c->base->dev, d40d->lli_pool.dma_addr, - d40d->lli_pool.size, DMA_TO_DEVICE); - return 0; -} - static dma_addr_t d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction) { @@ -2015,11 +1988,12 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, dev_addr = d40_get_dev_addr(d40c, direction); if (chan_is_logical(d40c)) - err = d40_prep_slave_sg_log(d40d, d40c, sgl, sg_len, - direction, dev_addr); + err = d40_prep_sg_log(d40c, d40d, sgl, NULL, + sg_len, direction, dev_addr); else - err = d40_prep_slave_sg_phy(d40d, d40c, sgl, sg_len, - direction, dev_addr); + err = d40_prep_sg_phy(d40c, d40d, sgl, NULL, + sg_len, direction, dev_addr); + if (err) { chan_err(d40c, "Failed to prepare %s slave sg job: %d\n", chan_is_logical(d40c) ? "log" : "phy", err); -- cgit v1.2.2 From 10a946b3a4e1ad665a81981cbe33c3d3903cd7da Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:22 +0100 Subject: dma40: remove export of stedma40_memcpy_sg The dmaengine framework has the API for this now. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 8c6abc23db80..0f5d61720ab8 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1733,6 +1733,7 @@ err: } struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, +static struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, struct scatterlist *sgl_dst, struct scatterlist *sgl_src, unsigned int sgl_len, @@ -1771,7 +1772,6 @@ err: spin_unlock_irqrestore(&d40c->lock, flags); return NULL; } -EXPORT_SYMBOL(stedma40_memcpy_sg); bool stedma40_filter(struct dma_chan *chan, void *data) { -- cgit v1.2.2 From cade1d30b2e071a687011c2a38c03ed7187ec501 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:23 +0100 Subject: dma40: combine mem and slave prep_sg functions Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 156 +++++++++++++++++++----------------------------- 1 file changed, 62 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 0f5d61720ab8..4e9d6c5a7134 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1732,44 +1732,70 @@ err: return NULL; } -struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, -static struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, - struct scatterlist *sgl_dst, - struct scatterlist *sgl_src, - unsigned int sgl_len, - unsigned long dma_flags) +static dma_addr_t +d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction) { - struct d40_desc *d40d; - struct d40_chan *d40c = container_of(chan, struct d40_chan, - chan); + struct stedma40_platform_data *plat = chan->base->plat_data; + struct stedma40_chan_cfg *cfg = &chan->dma_cfg; + dma_addr_t addr; + + if (chan->runtime_addr) + return chan->runtime_addr; + + if (direction == DMA_FROM_DEVICE) + addr = plat->dev_rx[cfg->src_dev_type]; + else if (direction == DMA_TO_DEVICE) + addr = plat->dev_tx[cfg->dst_dev_type]; + + return addr; +} + +static struct dma_async_tx_descriptor * +d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, + struct scatterlist *sg_dst, unsigned int sg_len, + enum dma_data_direction direction, unsigned long dma_flags) +{ + struct d40_chan *chan = container_of(dchan, struct d40_chan, chan); + dma_addr_t dev_addr = 0; + struct d40_desc *desc; unsigned long flags; + int ret; - if (d40c->phy_chan == NULL) { - chan_err(d40c, "Unallocated channel.\n"); - return ERR_PTR(-EINVAL); + if (!chan->phy_chan) { + chan_err(chan, "Cannot prepare unallocated channel\n"); + return NULL; } - spin_lock_irqsave(&d40c->lock, flags); + spin_lock_irqsave(&chan->lock, flags); - d40d = d40_prep_desc(d40c, sgl_dst, sgl_len, dma_flags); - if (!d40d) + desc = d40_prep_desc(chan, sg_src, sg_len, dma_flags); + if (desc == NULL) goto err; - if (chan_is_logical(d40c)) { - d40_prep_sg_log(d40c, d40d, sgl_src, sgl_dst, - sgl_len, DMA_NONE, 0); - } else { - d40_prep_sg_phy(d40c, d40d, sgl_src, sgl_dst, - sgl_len, DMA_NONE, 0); + if (direction != DMA_NONE) + dev_addr = d40_get_dev_addr(chan, direction); + + if (chan_is_logical(chan)) + ret = d40_prep_sg_log(chan, desc, sg_src, sg_dst, + sg_len, direction, dev_addr); + else + ret = d40_prep_sg_phy(chan, desc, sg_src, sg_dst, + sg_len, direction, dev_addr); + + if (ret) { + chan_err(chan, "Failed to prepare %s sg job: %d\n", + chan_is_logical(chan) ? "log" : "phy", ret); + goto err; } - spin_unlock_irqrestore(&d40c->lock, flags); + spin_unlock_irqrestore(&chan->lock, flags); + + return &desc->txd; - return &d40d->txd; err: - if (d40d) - d40_desc_free(d40c, d40d); - spin_unlock_irqrestore(&d40c->lock, flags); + if (desc) + d40_desc_free(chan, desc); + spin_unlock_irqrestore(&chan->lock, flags); return NULL; } @@ -1925,37 +1951,19 @@ static struct dma_async_tx_descriptor *d40_prep_memcpy(struct dma_chan *chan, sg_dma_len(&dst_sg) = size; sg_dma_len(&src_sg) = size; - return stedma40_memcpy_sg(chan, &dst_sg, &src_sg, 1, dma_flags); + return d40_prep_sg(chan, &src_sg, &dst_sg, 1, DMA_NONE, dma_flags); } static struct dma_async_tx_descriptor * -d40_prep_sg(struct dma_chan *chan, - struct scatterlist *dst_sg, unsigned int dst_nents, - struct scatterlist *src_sg, unsigned int src_nents, - unsigned long dma_flags) +d40_prep_memcpy_sg(struct dma_chan *chan, + struct scatterlist *dst_sg, unsigned int dst_nents, + struct scatterlist *src_sg, unsigned int src_nents, + unsigned long dma_flags) { if (dst_nents != src_nents) return NULL; - return stedma40_memcpy_sg(chan, dst_sg, src_sg, dst_nents, dma_flags); -} - -static dma_addr_t -d40_get_dev_addr(struct d40_chan *chan, enum dma_data_direction direction) -{ - struct stedma40_platform_data *plat = chan->base->plat_data; - struct stedma40_chan_cfg *cfg = &chan->dma_cfg; - dma_addr_t addr; - - if (chan->runtime_addr) - return chan->runtime_addr; - - if (direction == DMA_FROM_DEVICE) - addr = plat->dev_rx[cfg->src_dev_type]; - else if (direction == DMA_TO_DEVICE) - addr = plat->dev_tx[cfg->dst_dev_type]; - - return addr; + return d40_prep_sg(chan, src_sg, dst_sg, src_nents, DMA_NONE, dma_flags); } static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, @@ -1964,50 +1972,10 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, enum dma_data_direction direction, unsigned long dma_flags) { - struct d40_desc *d40d; - struct d40_chan *d40c = container_of(chan, struct d40_chan, - chan); - dma_addr_t dev_addr; - unsigned long flags; - int err; - - if (d40c->phy_chan == NULL) { - chan_err(d40c, "Cannot prepare unallocated channel\n"); - return ERR_PTR(-EINVAL); - } - if (direction != DMA_FROM_DEVICE && direction != DMA_TO_DEVICE) return NULL; - spin_lock_irqsave(&d40c->lock, flags); - - d40d = d40_prep_desc(d40c, sgl, sg_len, dma_flags); - if (d40d == NULL) - goto err; - - dev_addr = d40_get_dev_addr(d40c, direction); - - if (chan_is_logical(d40c)) - err = d40_prep_sg_log(d40c, d40d, sgl, NULL, - sg_len, direction, dev_addr); - else - err = d40_prep_sg_phy(d40c, d40d, sgl, NULL, - sg_len, direction, dev_addr); - - if (err) { - chan_err(d40c, "Failed to prepare %s slave sg job: %d\n", - chan_is_logical(d40c) ? "log" : "phy", err); - goto err; - } - - spin_unlock_irqrestore(&d40c->lock, flags); - return &d40d->txd; - -err: - if (d40d) - d40_desc_free(d40c, d40d); - spin_unlock_irqrestore(&d40c->lock, flags); - return NULL; + return d40_prep_sg(chan, sgl, sgl, sg_len, direction, dma_flags); } static enum dma_status d40_tx_status(struct dma_chan *chan, @@ -2267,7 +2235,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, base->dma_slave.device_alloc_chan_resources = d40_alloc_chan_resources; base->dma_slave.device_free_chan_resources = d40_free_chan_resources; base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy; - base->dma_slave.device_prep_dma_sg = d40_prep_sg; + base->dma_slave.device_prep_dma_sg = d40_prep_memcpy_sg; base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg; base->dma_slave.device_tx_status = d40_tx_status; base->dma_slave.device_issue_pending = d40_issue_pending; @@ -2291,7 +2259,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, base->dma_memcpy.device_alloc_chan_resources = d40_alloc_chan_resources; base->dma_memcpy.device_free_chan_resources = d40_free_chan_resources; base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy; - base->dma_slave.device_prep_dma_sg = d40_prep_sg; + base->dma_slave.device_prep_dma_sg = d40_prep_memcpy_sg; base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg; base->dma_memcpy.device_tx_status = d40_tx_status; base->dma_memcpy.device_issue_pending = d40_issue_pending; @@ -2322,7 +2290,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, base->dma_both.device_alloc_chan_resources = d40_alloc_chan_resources; base->dma_both.device_free_chan_resources = d40_free_chan_resources; base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy; - base->dma_slave.device_prep_dma_sg = d40_prep_sg; + base->dma_slave.device_prep_dma_sg = d40_prep_memcpy_sg; base->dma_both.device_prep_slave_sg = d40_prep_slave_sg; base->dma_both.device_tx_status = d40_tx_status; base->dma_both.device_issue_pending = d40_issue_pending; -- cgit v1.2.2 From 1c4b0927feab41346b0be971e0287aaf46eba8e0 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:24 +0100 Subject: dma40: move lli_load to main source file These register writes are better placed in the main source file rather than ll.c. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 22 ++++++++++++++++++---- drivers/dma/ste_dma40_ll.c | 26 -------------------------- drivers/dma/ste_dma40_ll.h | 5 ----- 3 files changed, 18 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 4e9d6c5a7134..6a7a00d5d682 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -504,15 +504,29 @@ static void d40_desc_submit(struct d40_chan *d40c, struct d40_desc *desc) list_add_tail(&desc->node, &d40c->active); } +static void d40_phy_lli_load(struct d40_chan *chan, struct d40_desc *desc) +{ + struct d40_phy_lli *lli_dst = desc->lli_phy.dst; + struct d40_phy_lli *lli_src = desc->lli_phy.src; + void __iomem *base = chan_base(chan); + + writel(lli_src->reg_cfg, base + D40_CHAN_REG_SSCFG); + writel(lli_src->reg_elt, base + D40_CHAN_REG_SSELT); + writel(lli_src->reg_ptr, base + D40_CHAN_REG_SSPTR); + writel(lli_src->reg_lnk, base + D40_CHAN_REG_SSLNK); + + writel(lli_dst->reg_cfg, base + D40_CHAN_REG_SDCFG); + writel(lli_dst->reg_elt, base + D40_CHAN_REG_SDELT); + writel(lli_dst->reg_ptr, base + D40_CHAN_REG_SDPTR); + writel(lli_dst->reg_lnk, base + D40_CHAN_REG_SDLNK); +} + static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d) { int curr_lcla = -EINVAL, next_lcla; if (chan_is_physical(d40c)) { - d40_phy_lli_write(d40c->base->virtbase, - d40c->phy_chan->num, - d40d->lli_phy.dst, - d40d->lli_phy.src); + d40_phy_lli_load(d40c, d40d); d40d->lli_current = d40d->lli_len; } else { diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 552c5972c75e..fd7525162596 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -295,32 +295,6 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, } -void d40_phy_lli_write(void __iomem *virtbase, - u32 phy_chan_num, - struct d40_phy_lli *lli_dst, - struct d40_phy_lli *lli_src) -{ - - writel(lli_src->reg_cfg, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSCFG); - writel(lli_src->reg_elt, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT); - writel(lli_src->reg_ptr, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSPTR); - writel(lli_src->reg_lnk, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSLNK); - - writel(lli_dst->reg_cfg, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDCFG); - writel(lli_dst->reg_elt, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT); - writel(lli_dst->reg_ptr, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDPTR); - writel(lli_dst->reg_lnk, virtbase + D40_DREG_PCBASE + - phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDLNK); - -} - /* DMA logical lli operations */ static void d40_log_lli_link(struct d40_log_lli *lli_dst, diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index a5d71714ebf7..46578a661b28 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -312,11 +312,6 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, u32 data_width2, int psize); -void d40_phy_lli_write(void __iomem *virtbase, - u32 phy_chan_num, - struct d40_phy_lli *lli_dst, - struct d40_phy_lli *lli_src); - /* Logical channels */ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, -- cgit v1.2.2 From e24b36bdf873b4a64545fd66da13877214d235cf Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:25 +0100 Subject: dma40: combine duplicated code in log_sg_to_dev Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40_ll.c | 52 ++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index fd7525162596..fa6c3ab93fae 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -385,40 +385,34 @@ int d40_log_sg_to_dev(struct scatterlist *sg, struct d40_log_lli *lli_dst = lli->dst; for_each_sg(sg, current_sg, sg_len, i) { - total_size += sg_dma_len(current_sg); + dma_addr_t sg_addr = sg_dma_address(current_sg); + unsigned int len = sg_dma_len(current_sg); + dma_addr_t src; + dma_addr_t dst; + + total_size += len; if (direction == DMA_TO_DEVICE) { - lli_src = - d40_log_buf_to_lli(lli_src, - sg_dma_address(current_sg), - sg_dma_len(current_sg), - lcsp->lcsp1, src_data_width, - dst_data_width, - true); - lli_dst = - d40_log_buf_to_lli(lli_dst, - dev_addr, - sg_dma_len(current_sg), - lcsp->lcsp3, dst_data_width, - src_data_width, - false); + src = sg_addr; + dst = dev_addr; } else { - lli_dst = - d40_log_buf_to_lli(lli_dst, - sg_dma_address(current_sg), - sg_dma_len(current_sg), - lcsp->lcsp3, dst_data_width, - src_data_width, - true); - lli_src = - d40_log_buf_to_lli(lli_src, - dev_addr, - sg_dma_len(current_sg), - lcsp->lcsp1, src_data_width, - dst_data_width, - false); + src = dev_addr; + dst = sg_addr; } + + lli_src = d40_log_buf_to_lli(lli_src, src, len, + lcsp->lcsp1, + src_data_width, + dst_data_width, + src == sg_addr); + + lli_dst = d40_log_buf_to_lli(lli_dst, dst, len, + lcsp->lcsp3, + dst_data_width, + src_data_width, + dst == sg_addr); } + return total_size; } -- cgit v1.2.2 From 5ed04b8575cb22920b1333aeb55121339449048f Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:26 +0100 Subject: dma40: unify d40_log_sg_to_lli funcs for mem and slave Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 41 ++++++++++++------------------ drivers/dma/ste_dma40_ll.c | 63 +++++++++------------------------------------- drivers/dma/ste_dma40_ll.h | 10 +------- 3 files changed, 29 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 6a7a00d5d682..c597dba713b0 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1638,37 +1638,28 @@ d40_prep_sg_log(struct d40_chan *chan, struct d40_desc *desc, unsigned int sg_len, enum dma_data_direction direction, dma_addr_t dev_addr) { + dma_addr_t src_dev_addr = direction == DMA_FROM_DEVICE ? dev_addr : 0; + dma_addr_t dst_dev_addr = direction == DMA_TO_DEVICE ? dev_addr : 0; struct stedma40_chan_cfg *cfg = &chan->dma_cfg; struct stedma40_half_channel_info *src_info = &cfg->src_info; struct stedma40_half_channel_info *dst_info = &cfg->dst_info; + int ret; - if (direction == DMA_NONE) { - /* memcpy */ - (void) d40_log_sg_to_lli(sg_src, sg_len, - desc->lli_log.src, - chan->log_def.lcsp1, - src_info->data_width, - dst_info->data_width); - - (void) d40_log_sg_to_lli(sg_dst, sg_len, - desc->lli_log.dst, - chan->log_def.lcsp3, - dst_info->data_width, - src_info->data_width); - } else { - unsigned int total_size; + ret = d40_log_sg_to_lli(sg_src, sg_len, + src_dev_addr, + desc->lli_log.src, + chan->log_def.lcsp1, + src_info->data_width, + dst_info->data_width); - total_size = d40_log_sg_to_dev(sg_src, sg_len, - &desc->lli_log, - &chan->log_def, - src_info->data_width, - dst_info->data_width, - direction, dev_addr); - if (total_size < 0) - return -EINVAL; - } + ret = d40_log_sg_to_lli(sg_dst, sg_len, + dst_dev_addr, + desc->lli_log.dst, + chan->log_def.lcsp3, + dst_info->data_width, + src_info->data_width); - return 0; + return ret < 0 ? ret : 0; } static int diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index fa6c3ab93fae..9935c6dbcfe0 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -369,53 +369,6 @@ static void d40_log_fill_lli(struct d40_log_lli *lli, } -int d40_log_sg_to_dev(struct scatterlist *sg, - int sg_len, - struct d40_log_lli_bidir *lli, - struct d40_def_lcsp *lcsp, - u32 src_data_width, - u32 dst_data_width, - enum dma_data_direction direction, - dma_addr_t dev_addr) -{ - int total_size = 0; - struct scatterlist *current_sg = sg; - int i; - struct d40_log_lli *lli_src = lli->src; - struct d40_log_lli *lli_dst = lli->dst; - - for_each_sg(sg, current_sg, sg_len, i) { - dma_addr_t sg_addr = sg_dma_address(current_sg); - unsigned int len = sg_dma_len(current_sg); - dma_addr_t src; - dma_addr_t dst; - - total_size += len; - - if (direction == DMA_TO_DEVICE) { - src = sg_addr; - dst = dev_addr; - } else { - src = dev_addr; - dst = sg_addr; - } - - lli_src = d40_log_buf_to_lli(lli_src, src, len, - lcsp->lcsp1, - src_data_width, - dst_data_width, - src == sg_addr); - - lli_dst = d40_log_buf_to_lli(lli_dst, dst, len, - lcsp->lcsp3, - dst_data_width, - src_data_width, - dst == sg_addr); - } - - return total_size; -} - struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, dma_addr_t addr, int size, @@ -447,6 +400,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, + dma_addr_t dev_addr, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2) @@ -455,14 +409,21 @@ int d40_log_sg_to_lli(struct scatterlist *sg, struct scatterlist *current_sg = sg; int i; struct d40_log_lli *lli = lli_sg; + bool autoinc = !dev_addr; for_each_sg(sg, current_sg, sg_len, i) { + dma_addr_t sg_addr = sg_dma_address(current_sg); + unsigned int len = sg_dma_len(current_sg); + dma_addr_t addr = dev_addr ?: sg_addr; + total_size += sg_dma_len(current_sg); - lli = d40_log_buf_to_lli(lli, - sg_dma_address(current_sg), - sg_dma_len(current_sg), + + lli = d40_log_buf_to_lli(lli, addr, len, lcsp13, - data_width1, data_width2, true); + data_width1, + data_width2, + autoinc); } + return total_size; } diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 46578a661b28..867f23f6e098 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -321,17 +321,9 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, u32 data_width1, u32 data_width2, bool addr_inc); -int d40_log_sg_to_dev(struct scatterlist *sg, - int sg_len, - struct d40_log_lli_bidir *lli, - struct d40_def_lcsp *lcsp, - u32 src_data_width, - u32 dst_data_width, - enum dma_data_direction direction, - dma_addr_t dev_addr); - int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, + dma_addr_t dev_addr, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2); -- cgit v1.2.2 From cc31b6f7949efd46c5f13d0758cf7b0bcb71fae2 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:27 +0100 Subject: dma40: pass the info pointer all the way to reduce argument count Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 8 ++------ drivers/dma/ste_dma40_ll.c | 42 ++++++++++++++++++------------------------ drivers/dma/ste_dma40_ll.h | 5 ++--- 3 files changed, 22 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index c597dba713b0..3c61c582303d 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1679,17 +1679,13 @@ d40_prep_sg_phy(struct d40_chan *chan, struct d40_desc *desc, desc->lli_phy.src, virt_to_phys(desc->lli_phy.src), chan->src_def_cfg, - src_info->data_width, - dst_info->data_width, - src_info->psize); + src_info, dst_info); ret = d40_phy_sg_to_lli(sg_dst, sg_len, dst_dev_addr, desc->lli_phy.dst, virt_to_phys(desc->lli_phy.dst), chan->dst_def_cfg, - dst_info->data_width, - src_info->data_width, - dst_info->psize); + dst_info, src_info); dma_sync_single_for_device(chan->base->dev, desc->lli_pool.dma_addr, desc->lli_pool.size, DMA_TO_DEVICE); diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 9935c6dbcfe0..509a13049d7e 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -125,13 +125,14 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg, static int d40_phy_fill_lli(struct d40_phy_lli *lli, dma_addr_t data, u32 data_size, - int psize, dma_addr_t next_lli, u32 reg_cfg, bool term_int, - u32 data_width, - bool is_device) + bool is_device, + struct stedma40_half_channel_info *info) { + unsigned int data_width = info->data_width; + int psize = info->psize; int num_elems; if (psize == STEDMA40_PSIZE_PHY_1) @@ -198,16 +199,11 @@ static int d40_seg_size(int size, int data_width1, int data_width2) return seg_max; } -static struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, - dma_addr_t addr, - u32 size, - int psize, - dma_addr_t lli_phys, - u32 reg_cfg, - bool term_int, - u32 data_width1, - u32 data_width2, - bool is_device) +static struct d40_phy_lli * +d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, + dma_addr_t lli_phys, u32 reg_cfg, bool term_int, + bool is_device, struct stedma40_half_channel_info *info, + struct stedma40_half_channel_info *otherinfo) { int err; dma_addr_t next = lli_phys; @@ -215,7 +211,8 @@ static struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, int size_seg = 0; do { - size_seg = d40_seg_size(size_rest, data_width1, data_width2); + size_seg = d40_seg_size(size_rest, info->data_width, + otherinfo->data_width); size_rest -= size_seg; if (term_int && size_rest == 0) @@ -227,12 +224,11 @@ static struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, err = d40_phy_fill_lli(lli, addr, size_seg, - psize, next, reg_cfg, !next, - data_width1, - is_device); + is_device, + info); if (err) goto err; @@ -254,9 +250,8 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli_sg, dma_addr_t lli_phys, u32 reg_cfg, - u32 data_width1, - u32 data_width2, - int psize) + struct stedma40_half_channel_info *info, + struct stedma40_half_channel_info *otherinfo) { int total_size = 0; int i; @@ -280,13 +275,12 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, lli = d40_phy_buf_to_lli(lli, dst, sg_dma_len(current_sg), - psize, l_phys, reg_cfg, sg_len - 1 == i, - data_width1, - data_width2, - target == dst); + target == dst, + info, + otherinfo); if (lli == NULL) return -EINVAL; } diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 867f23f6e098..cd94afd9c2f2 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -308,9 +308,8 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli, dma_addr_t lli_phys, u32 reg_cfg, - u32 data_width1, - u32 data_width2, - int psize); + struct stedma40_half_channel_info *info, + struct stedma40_half_channel_info *otherinfo); /* Logical channels */ -- cgit v1.2.2 From 822c567639971628ceba2c53531670d595e3164d Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:28 +0100 Subject: dma40: unify src/dst addr check Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 3c61c582303d..d9dfda2c65b5 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1635,11 +1635,9 @@ static u32 stedma40_residue(struct dma_chan *chan) static int d40_prep_sg_log(struct d40_chan *chan, struct d40_desc *desc, struct scatterlist *sg_src, struct scatterlist *sg_dst, - unsigned int sg_len, enum dma_data_direction direction, - dma_addr_t dev_addr) + unsigned int sg_len, dma_addr_t src_dev_addr, + dma_addr_t dst_dev_addr) { - dma_addr_t src_dev_addr = direction == DMA_FROM_DEVICE ? dev_addr : 0; - dma_addr_t dst_dev_addr = direction == DMA_TO_DEVICE ? dev_addr : 0; struct stedma40_chan_cfg *cfg = &chan->dma_cfg; struct stedma40_half_channel_info *src_info = &cfg->src_info; struct stedma40_half_channel_info *dst_info = &cfg->dst_info; @@ -1665,11 +1663,9 @@ d40_prep_sg_log(struct d40_chan *chan, struct d40_desc *desc, static int d40_prep_sg_phy(struct d40_chan *chan, struct d40_desc *desc, struct scatterlist *sg_src, struct scatterlist *sg_dst, - unsigned int sg_len, enum dma_data_direction direction, - dma_addr_t dev_addr) + unsigned int sg_len, dma_addr_t src_dev_addr, + dma_addr_t dst_dev_addr) { - dma_addr_t src_dev_addr = direction == DMA_FROM_DEVICE ? dev_addr : 0; - dma_addr_t dst_dev_addr = direction == DMA_TO_DEVICE ? dev_addr : 0; struct stedma40_chan_cfg *cfg = &chan->dma_cfg; struct stedma40_half_channel_info *src_info = &cfg->src_info; struct stedma40_half_channel_info *dst_info = &cfg->dst_info; @@ -1757,7 +1753,8 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, enum dma_data_direction direction, unsigned long dma_flags) { struct d40_chan *chan = container_of(dchan, struct d40_chan, chan); - dma_addr_t dev_addr = 0; + dma_addr_t src_dev_addr = 0; + dma_addr_t dst_dev_addr = 0; struct d40_desc *desc; unsigned long flags; int ret; @@ -1773,15 +1770,21 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, if (desc == NULL) goto err; - if (direction != DMA_NONE) - dev_addr = d40_get_dev_addr(chan, direction); + if (direction != DMA_NONE) { + dma_addr_t dev_addr = d40_get_dev_addr(chan, direction); + + if (direction == DMA_FROM_DEVICE) + src_dev_addr = dev_addr; + else if (direction == DMA_TO_DEVICE) + dst_dev_addr = dev_addr; + } if (chan_is_logical(chan)) ret = d40_prep_sg_log(chan, desc, sg_src, sg_dst, - sg_len, direction, dev_addr); + sg_len, src_dev_addr, dst_dev_addr); else ret = d40_prep_sg_phy(chan, desc, sg_src, sg_dst, - sg_len, direction, dev_addr); + sg_len, src_dev_addr, dst_dev_addr); if (ret) { chan_err(chan, "Failed to prepare %s sg job: %d\n", -- cgit v1.2.2 From 1f7622ca55b1f5875e32140b4781759f800aded3 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:29 +0100 Subject: dma40: make d40_log_buf_to_lli static Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40_ll.c | 2 +- drivers/dma/ste_dma40_ll.h | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 509a13049d7e..876aad2c838a 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -363,7 +363,7 @@ static void d40_log_fill_lli(struct d40_log_lli *lli, } -struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, +static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, dma_addr_t addr, int size, u32 lcsp13, /* src or dst*/ diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index cd94afd9c2f2..4626c8874374 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -313,13 +313,6 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, /* Logical channels */ -struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, - dma_addr_t addr, - int size, - u32 lcsp13, /* src or dst*/ - u32 data_width1, u32 data_width2, - bool addr_inc); - int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, dma_addr_t dev_addr, -- cgit v1.2.2 From 7f933bed96e9872131014ea2bdd5b012e43fc316 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:30 +0100 Subject: dma40: use flags to reduce parameter count Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40_ll.c | 84 ++++++++++++++++++++++++++-------------------- drivers/dma/ste_dma40_ll.h | 5 +++ 2 files changed, 52 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 876aad2c838a..88b9e371be2f 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -127,10 +127,11 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli, u32 data_size, dma_addr_t next_lli, u32 reg_cfg, - bool term_int, - bool is_device, - struct stedma40_half_channel_info *info) + struct stedma40_half_channel_info *info, + unsigned int flags) { + bool addr_inc = flags & LLI_ADDR_INC; + bool term_int = flags & LLI_TERM_INT; unsigned int data_width = info->data_width; int psize = info->psize; int num_elems; @@ -155,7 +156,7 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli, * Distance to next element sized entry. * Usually the size of the element unless you want gaps. */ - if (!is_device) + if (addr_inc) lli->reg_elt |= (0x1 << data_width) << D40_SREG_ELEM_PHY_EIDX_POS; @@ -201,40 +202,45 @@ static int d40_seg_size(int size, int data_width1, int data_width2) static struct d40_phy_lli * d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, - dma_addr_t lli_phys, u32 reg_cfg, bool term_int, - bool is_device, struct stedma40_half_channel_info *info, - struct stedma40_half_channel_info *otherinfo) + dma_addr_t lli_phys, u32 reg_cfg, + struct stedma40_half_channel_info *info, + struct stedma40_half_channel_info *otherinfo, + unsigned long flags) { + bool addr_inc = flags & LLI_ADDR_INC; + bool term_int = flags & LLI_TERM_INT; int err; dma_addr_t next = lli_phys; int size_rest = size; int size_seg = 0; + /* + * This piece may be split up based on d40_seg_size(); we only want the + * term int on the last part. + */ + if (term_int) + flags &= ~LLI_TERM_INT; + do { size_seg = d40_seg_size(size_rest, info->data_width, otherinfo->data_width); size_rest -= size_seg; - if (term_int && size_rest == 0) + if (term_int && size_rest == 0) { next = 0; - else + flags |= LLI_TERM_INT; + } else next = ALIGN(next + sizeof(struct d40_phy_lli), D40_LLI_ALIGN); - err = d40_phy_fill_lli(lli, - addr, - size_seg, - next, - reg_cfg, - !next, - is_device, - info); + err = d40_phy_fill_lli(lli, addr, size_seg, next, + reg_cfg, info, flags); if (err) goto err; lli++; - if (!is_device) + if (addr_inc) addr += size_seg; } while (size_rest); @@ -256,31 +262,29 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, int total_size = 0; int i; struct scatterlist *current_sg = sg; - dma_addr_t dst; struct d40_phy_lli *lli = lli_sg; dma_addr_t l_phys = lli_phys; + unsigned long flags = 0; + + if (!target) + flags |= LLI_ADDR_INC; for_each_sg(sg, current_sg, sg_len, i) { + dma_addr_t sg_addr = sg_dma_address(current_sg); + unsigned int len = sg_dma_len(current_sg); + dma_addr_t dst = target ?: sg_addr; total_size += sg_dma_len(current_sg); - if (target) - dst = target; - else - dst = sg_dma_address(current_sg); + if (i == sg_len - 1) + flags |= LLI_TERM_INT; l_phys = ALIGN(lli_phys + (lli - lli_sg) * sizeof(struct d40_phy_lli), D40_LLI_ALIGN); - lli = d40_phy_buf_to_lli(lli, - dst, - sg_dma_len(current_sg), - l_phys, - reg_cfg, - sg_len - 1 == i, - target == dst, - info, - otherinfo); + lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, + reg_cfg, info, otherinfo, flags); + if (lli == NULL) return -EINVAL; } @@ -343,8 +347,10 @@ static void d40_log_fill_lli(struct d40_log_lli *lli, dma_addr_t data, u32 data_size, u32 reg_cfg, u32 data_width, - bool addr_inc) + unsigned int flags) { + bool addr_inc = flags & LLI_ADDR_INC; + lli->lcsp13 = reg_cfg; /* The number of elements to transfer */ @@ -369,8 +375,9 @@ static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2, - bool addr_inc) + unsigned int flags) { + bool addr_inc = flags & LLI_ADDR_INC; struct d40_log_lli *lli = lli_sg; int size_rest = size; int size_seg = 0; @@ -383,7 +390,7 @@ static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, addr, size_seg, lcsp13, data_width1, - addr_inc); + flags); if (addr_inc) addr += size_seg; lli++; @@ -403,7 +410,10 @@ int d40_log_sg_to_lli(struct scatterlist *sg, struct scatterlist *current_sg = sg; int i; struct d40_log_lli *lli = lli_sg; - bool autoinc = !dev_addr; + unsigned long flags = 0; + + if (!dev_addr) + flags |= LLI_ADDR_INC; for_each_sg(sg, current_sg, sg_len, i) { dma_addr_t sg_addr = sg_dma_address(current_sg); @@ -416,7 +426,7 @@ int d40_log_sg_to_lli(struct scatterlist *sg, lcsp13, data_width1, data_width2, - autoinc); + flags); } return total_size; diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 4626c8874374..59e72f0cc901 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -293,6 +293,11 @@ struct d40_def_lcsp { /* Physical channels */ +enum d40_lli_flags { + LLI_ADDR_INC = 1 << 0, + LLI_TERM_INT = 1 << 1, +}; + void d40_phy_cfg(struct stedma40_chan_cfg *cfg, u32 *src_cfg, u32 *dst_cfg, -- cgit v1.2.2 From e65889c75ccb5b64dfb60f32e2d9448446cabcc7 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:31 +0100 Subject: dma40: extract lcla code into separate function Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 92 +++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index d9dfda2c65b5..4ec96ac1e41a 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -521,54 +521,62 @@ static void d40_phy_lli_load(struct d40_chan *chan, struct d40_desc *desc) writel(lli_dst->reg_lnk, base + D40_CHAN_REG_SDLNK); } -static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d) -{ - int curr_lcla = -EINVAL, next_lcla; - - if (chan_is_physical(d40c)) { - d40_phy_lli_load(d40c, d40d); - d40d->lli_current = d40d->lli_len; - } else { - - if ((d40d->lli_len - d40d->lli_current) > 1) - curr_lcla = d40_lcla_alloc_one(d40c, d40d); - - d40_log_lli_lcpa_write(d40c->lcpa, - &d40d->lli_log.dst[d40d->lli_current], - &d40d->lli_log.src[d40d->lli_current], - curr_lcla); - - d40d->lli_current++; - for (; d40d->lli_current < d40d->lli_len; d40d->lli_current++) { - unsigned int lcla_offset = d40c->phy_chan->num * 1024 + - 8 * curr_lcla * 2; - struct d40_lcla_pool *pool = &d40c->base->lcla_pool; - struct d40_log_lli *lcla = pool->base + lcla_offset; - - if (d40d->lli_current + 1 < d40d->lli_len) - next_lcla = d40_lcla_alloc_one(d40c, d40d); - else - next_lcla = -EINVAL; - - d40_log_lli_lcla_write(lcla, - &d40d->lli_log.dst[d40d->lli_current], - &d40d->lli_log.src[d40d->lli_current], - next_lcla); +static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) +{ + struct d40_lcla_pool *pool = &chan->base->lcla_pool; + struct d40_log_lli_bidir *lli = &desc->lli_log; + int lli_current = desc->lli_current; + int lli_len = desc->lli_len; + int curr_lcla = -EINVAL; + + if (lli_len - lli_current > 1) + curr_lcla = d40_lcla_alloc_one(chan, desc); + + d40_log_lli_lcpa_write(chan->lcpa, + &lli->dst[lli_current], + &lli->src[lli_current], + curr_lcla); + + lli_current++; + for (; lli_current < lli_len; lli_current++) { + unsigned int lcla_offset = chan->phy_chan->num * 1024 + + 8 * curr_lcla * 2; + struct d40_log_lli *lcla = pool->base + lcla_offset; + int next_lcla; + + if (lli_current + 1 < lli_len) + next_lcla = d40_lcla_alloc_one(chan, desc); + else + next_lcla = -EINVAL; - dma_sync_single_range_for_device(d40c->base->dev, - pool->dma_addr, lcla_offset, - 2 * sizeof(struct d40_log_lli), - DMA_TO_DEVICE); + d40_log_lli_lcla_write(lcla, + &lli->dst[lli_current], + &lli->src[lli_current], + next_lcla); - curr_lcla = next_lcla; + dma_sync_single_range_for_device(chan->base->dev, + pool->dma_addr, lcla_offset, + 2 * sizeof(struct d40_log_lli), + DMA_TO_DEVICE); - if (curr_lcla == -EINVAL) { - d40d->lli_current++; - break; - } + curr_lcla = next_lcla; + if (curr_lcla == -EINVAL) { + lli_current++; + break; } } + + desc->lli_current = lli_current; +} + +static void d40_desc_load(struct d40_chan *d40c, struct d40_desc *d40d) +{ + if (chan_is_physical(d40c)) { + d40_phy_lli_load(d40c, d40d); + d40d->lli_current = d40d->lli_len; + } else + d40_log_lli_to_lcxa(d40c, d40d); } static struct d40_desc *d40_first_active_get(struct d40_chan *d40c) -- cgit v1.2.2 From 6045f0bb2818393a44e835454db96709cb5b3d80 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:32 +0100 Subject: dma40: handle failure to allocate first LCLA Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 4ec96ac1e41a..b8cce85a9558 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -538,6 +538,10 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) curr_lcla); lli_current++; + + if (curr_lcla < 0) + goto out; + for (; lli_current < lli_len; lli_current++) { unsigned int lcla_offset = chan->phy_chan->num * 1024 + 8 * curr_lcla * 2; @@ -567,6 +571,7 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) } } +out: desc->lli_current = lli_current; } -- cgit v1.2.2 From 7ad74a7cf6f6355fd3f4c15afe63460fc4ec3f57 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:33 +0100 Subject: dma40: fix DMA_SG capability and channels The DMA_SG cap is enabled on the wrong channel, and the pointers are repeatedly set incorrectly. Fix it and combine the ops settings to a common function. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 71 +++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index b8cce85a9558..929fd8f45a2d 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2238,6 +2238,32 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma, } } +static void d40_ops_init(struct d40_base *base, struct dma_device *dev) +{ + if (dma_has_cap(DMA_SLAVE, dev->cap_mask)) + dev->device_prep_slave_sg = d40_prep_slave_sg; + + if (dma_has_cap(DMA_MEMCPY, dev->cap_mask)) { + dev->device_prep_dma_memcpy = d40_prep_memcpy; + + /* + * This controller can only access address at even + * 32bit boundaries, i.e. 2^2 + */ + dev->copy_align = 2; + } + + if (dma_has_cap(DMA_SG, dev->cap_mask)) + dev->device_prep_dma_sg = d40_prep_memcpy_sg; + + dev->device_alloc_chan_resources = d40_alloc_chan_resources; + dev->device_free_chan_resources = d40_free_chan_resources; + dev->device_issue_pending = d40_issue_pending; + dev->device_tx_status = d40_tx_status; + dev->device_control = d40_control; + dev->dev = base->dev; +} + static int __init d40_dmaengine_init(struct d40_base *base, int num_reserved_chans) { @@ -2249,15 +2275,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, dma_cap_zero(base->dma_slave.cap_mask); dma_cap_set(DMA_SLAVE, base->dma_slave.cap_mask); - base->dma_slave.device_alloc_chan_resources = d40_alloc_chan_resources; - base->dma_slave.device_free_chan_resources = d40_free_chan_resources; - base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy; - base->dma_slave.device_prep_dma_sg = d40_prep_memcpy_sg; - base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg; - base->dma_slave.device_tx_status = d40_tx_status; - base->dma_slave.device_issue_pending = d40_issue_pending; - base->dma_slave.device_control = d40_control; - base->dma_slave.dev = base->dev; + d40_ops_init(base, &base->dma_slave); err = dma_async_device_register(&base->dma_slave); @@ -2271,22 +2289,9 @@ static int __init d40_dmaengine_init(struct d40_base *base, dma_cap_zero(base->dma_memcpy.cap_mask); dma_cap_set(DMA_MEMCPY, base->dma_memcpy.cap_mask); - dma_cap_set(DMA_SG, base->dma_slave.cap_mask); - - base->dma_memcpy.device_alloc_chan_resources = d40_alloc_chan_resources; - base->dma_memcpy.device_free_chan_resources = d40_free_chan_resources; - base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy; - base->dma_slave.device_prep_dma_sg = d40_prep_memcpy_sg; - base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg; - base->dma_memcpy.device_tx_status = d40_tx_status; - base->dma_memcpy.device_issue_pending = d40_issue_pending; - base->dma_memcpy.device_control = d40_control; - base->dma_memcpy.dev = base->dev; - /* - * This controller can only access address at even - * 32bit boundaries, i.e. 2^2 - */ - base->dma_memcpy.copy_align = 2; + dma_cap_set(DMA_SG, base->dma_memcpy.cap_mask); + + d40_ops_init(base, &base->dma_memcpy); err = dma_async_device_register(&base->dma_memcpy); @@ -2302,18 +2307,10 @@ static int __init d40_dmaengine_init(struct d40_base *base, dma_cap_zero(base->dma_both.cap_mask); dma_cap_set(DMA_SLAVE, base->dma_both.cap_mask); dma_cap_set(DMA_MEMCPY, base->dma_both.cap_mask); - dma_cap_set(DMA_SG, base->dma_slave.cap_mask); - - base->dma_both.device_alloc_chan_resources = d40_alloc_chan_resources; - base->dma_both.device_free_chan_resources = d40_free_chan_resources; - base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy; - base->dma_slave.device_prep_dma_sg = d40_prep_memcpy_sg; - base->dma_both.device_prep_slave_sg = d40_prep_slave_sg; - base->dma_both.device_tx_status = d40_tx_status; - base->dma_both.device_issue_pending = d40_issue_pending; - base->dma_both.device_control = d40_control; - base->dma_both.dev = base->dev; - base->dma_both.copy_align = 2; + dma_cap_set(DMA_SG, base->dma_both.cap_mask); + + d40_ops_init(base, &base->dma_both); + err = dma_async_device_register(&base->dma_both); if (err) { -- cgit v1.2.2 From 86eb5fb61125e4646c9447a1f2ce130817dab34e Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:34 +0100 Subject: dma40: stop ongoing transfers in DMA_TERMINATE_ALL The current implementation of DMA_TERMINATE_ALL leaves ongoing transfers running. Fix it. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 929fd8f45a2d..8fd0bb94e777 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -918,10 +918,8 @@ static bool d40_tx_is_linked(struct d40_chan *d40c) return is_link; } -static int d40_pause(struct dma_chan *chan) +static int d40_pause(struct d40_chan *d40c) { - struct d40_chan *d40c = - container_of(chan, struct d40_chan, chan); int res = 0; unsigned long flags; @@ -945,10 +943,8 @@ static int d40_pause(struct dma_chan *chan) return res; } -static int d40_resume(struct dma_chan *chan) +static int d40_resume(struct d40_chan *d40c) { - struct d40_chan *d40c = - container_of(chan, struct d40_chan, chan); int res = 0; unsigned long flags; @@ -978,6 +974,22 @@ no_suspend: return res; } +static int d40_terminate_all(struct d40_chan *chan) +{ + unsigned long flags; + int ret = 0; + + ret = d40_pause(chan); + if (!ret && chan_is_physical(chan)) + ret = d40_channel_execute_command(chan, D40_DMA_STOP); + + spin_lock_irqsave(&chan->lock, flags); + d40_term_all(chan); + spin_unlock_irqrestore(&chan->lock, flags); + + return ret; +} + static dma_cookie_t d40_tx_submit(struct dma_async_tx_descriptor *tx) { struct d40_chan *d40c = container_of(tx->chan, @@ -2176,7 +2188,6 @@ static void d40_set_runtime_config(struct dma_chan *chan, static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { - unsigned long flags; struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); if (d40c->phy_chan == NULL) { @@ -2186,14 +2197,11 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, switch (cmd) { case DMA_TERMINATE_ALL: - spin_lock_irqsave(&d40c->lock, flags); - d40_term_all(d40c); - spin_unlock_irqrestore(&d40c->lock, flags); - return 0; + return d40_terminate_all(d40c); case DMA_PAUSE: - return d40_pause(chan); + return d40_pause(d40c); case DMA_RESUME: - return d40_resume(chan); + return d40_resume(d40c); case DMA_SLAVE_CONFIG: d40_set_runtime_config(chan, (struct dma_slave_config *) arg); -- cgit v1.2.2 From 0c842b551063c5f7382ac9b457992f3b34972801 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 25 Jan 2011 11:18:35 +0100 Subject: dma40: cyclic xfer support Support cyclic transfers, which are useful for ALSA drivers. Acked-by: Per Forlin Acked-by: Jonas Aaberg Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Dan Williams --- drivers/dma/ste_dma40.c | 172 ++++++++++++++++++++++++++++++++++++--------- drivers/dma/ste_dma40_ll.c | 35 +++++---- drivers/dma/ste_dma40_ll.h | 9 ++- 3 files changed, 167 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 8fd0bb94e777..af955de035f4 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -115,6 +115,7 @@ struct d40_desc { struct list_head node; bool is_in_client_list; + bool cyclic; }; /** @@ -527,17 +528,45 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) struct d40_log_lli_bidir *lli = &desc->lli_log; int lli_current = desc->lli_current; int lli_len = desc->lli_len; + bool cyclic = desc->cyclic; int curr_lcla = -EINVAL; + int first_lcla = 0; + bool linkback; - if (lli_len - lli_current > 1) + /* + * We may have partially running cyclic transfers, in case we did't get + * enough LCLA entries. + */ + linkback = cyclic && lli_current == 0; + + /* + * For linkback, we need one LCLA even with only one link, because we + * can't link back to the one in LCPA space + */ + if (linkback || (lli_len - lli_current > 1)) { curr_lcla = d40_lcla_alloc_one(chan, desc); + first_lcla = curr_lcla; + } + + /* + * For linkback, we normally load the LCPA in the loop since we need to + * link it to the second LCLA and not the first. However, if we + * couldn't even get a first LCLA, then we have to run in LCPA and + * reload manually. + */ + if (!linkback || curr_lcla == -EINVAL) { + unsigned int flags = 0; - d40_log_lli_lcpa_write(chan->lcpa, - &lli->dst[lli_current], - &lli->src[lli_current], - curr_lcla); + if (curr_lcla == -EINVAL) + flags |= LLI_TERM_INT; - lli_current++; + d40_log_lli_lcpa_write(chan->lcpa, + &lli->dst[lli_current], + &lli->src[lli_current], + curr_lcla, + flags); + lli_current++; + } if (curr_lcla < 0) goto out; @@ -546,17 +575,33 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) unsigned int lcla_offset = chan->phy_chan->num * 1024 + 8 * curr_lcla * 2; struct d40_log_lli *lcla = pool->base + lcla_offset; + unsigned int flags = 0; int next_lcla; if (lli_current + 1 < lli_len) next_lcla = d40_lcla_alloc_one(chan, desc); else - next_lcla = -EINVAL; + next_lcla = linkback ? first_lcla : -EINVAL; + + if (cyclic || next_lcla == -EINVAL) + flags |= LLI_TERM_INT; + if (linkback && curr_lcla == first_lcla) { + /* First link goes in both LCPA and LCLA */ + d40_log_lli_lcpa_write(chan->lcpa, + &lli->dst[lli_current], + &lli->src[lli_current], + next_lcla, flags); + } + + /* + * One unused LCLA in the cyclic case if the very first + * next_lcla fails... + */ d40_log_lli_lcla_write(lcla, &lli->dst[lli_current], &lli->src[lli_current], - next_lcla); + next_lcla, flags); dma_sync_single_range_for_device(chan->base->dev, pool->dma_addr, lcla_offset, @@ -565,7 +610,7 @@ static void d40_log_lli_to_lcxa(struct d40_chan *chan, struct d40_desc *desc) curr_lcla = next_lcla; - if (curr_lcla == -EINVAL) { + if (curr_lcla == -EINVAL || curr_lcla == first_lcla) { lli_current++; break; } @@ -1074,17 +1119,36 @@ static void dma_tc_handle(struct d40_chan *d40c) if (d40d == NULL) return; - d40_lcla_free_all(d40c, d40d); + if (d40d->cyclic) { + /* + * If this was a paritially loaded list, we need to reloaded + * it, and only when the list is completed. We need to check + * for done because the interrupt will hit for every link, and + * not just the last one. + */ + if (d40d->lli_current < d40d->lli_len + && !d40_tx_is_linked(d40c) + && !d40_residue(d40c)) { + d40_lcla_free_all(d40c, d40d); + d40_desc_load(d40c, d40d); + (void) d40_start(d40c); - if (d40d->lli_current < d40d->lli_len) { - d40_desc_load(d40c, d40d); - /* Start dma job */ - (void) d40_start(d40c); - return; - } + if (d40d->lli_current == d40d->lli_len) + d40d->lli_current = 0; + } + } else { + d40_lcla_free_all(d40c, d40d); - if (d40_queue_start(d40c) == NULL) - d40c->busy = false; + if (d40d->lli_current < d40d->lli_len) { + d40_desc_load(d40c, d40d); + /* Start dma job */ + (void) d40_start(d40c); + return; + } + + if (d40_queue_start(d40c) == NULL) + d40c->busy = false; + } d40c->pending_tx++; tasklet_schedule(&d40c->tasklet); @@ -1103,11 +1167,11 @@ static void dma_tasklet(unsigned long data) /* Get first active entry from list */ d40d = d40_first_active_get(d40c); - if (d40d == NULL) goto err; - d40c->completed = d40d->txd.cookie; + if (!d40d->cyclic) + d40c->completed = d40d->txd.cookie; /* * If terminating a channel pending_tx is set to zero. @@ -1122,16 +1186,18 @@ static void dma_tasklet(unsigned long data) callback = d40d->txd.callback; callback_param = d40d->txd.callback_param; - if (async_tx_test_ack(&d40d->txd)) { - d40_pool_lli_free(d40c, d40d); - d40_desc_remove(d40d); - d40_desc_free(d40c, d40d); - } else { - if (!d40d->is_in_client_list) { + if (!d40d->cyclic) { + if (async_tx_test_ack(&d40d->txd)) { + d40_pool_lli_free(d40c, d40d); d40_desc_remove(d40d); - d40_lcla_free_all(d40c, d40d); - list_add_tail(&d40d->node, &d40c->client); - d40d->is_in_client_list = true; + d40_desc_free(d40c, d40d); + } else { + if (!d40d->is_in_client_list) { + d40_desc_remove(d40d); + d40_lcla_free_all(d40c, d40d); + list_add_tail(&d40d->node, &d40c->client); + d40d->is_in_client_list = true; + } } } @@ -1694,19 +1760,23 @@ d40_prep_sg_phy(struct d40_chan *chan, struct d40_desc *desc, struct stedma40_chan_cfg *cfg = &chan->dma_cfg; struct stedma40_half_channel_info *src_info = &cfg->src_info; struct stedma40_half_channel_info *dst_info = &cfg->dst_info; + unsigned long flags = 0; int ret; + if (desc->cyclic) + flags |= LLI_CYCLIC | LLI_TERM_INT; + ret = d40_phy_sg_to_lli(sg_src, sg_len, src_dev_addr, desc->lli_phy.src, virt_to_phys(desc->lli_phy.src), chan->src_def_cfg, - src_info, dst_info); + src_info, dst_info, flags); ret = d40_phy_sg_to_lli(sg_dst, sg_len, dst_dev_addr, desc->lli_phy.dst, virt_to_phys(desc->lli_phy.dst), chan->dst_def_cfg, - dst_info, src_info); + dst_info, src_info, flags); dma_sync_single_for_device(chan->base->dev, desc->lli_pool.dma_addr, desc->lli_pool.size, DMA_TO_DEVICE); @@ -1789,12 +1859,16 @@ d40_prep_sg(struct dma_chan *dchan, struct scatterlist *sg_src, return NULL; } + spin_lock_irqsave(&chan->lock, flags); desc = d40_prep_desc(chan, sg_src, sg_len, dma_flags); if (desc == NULL) goto err; + if (sg_next(&sg_src[sg_len - 1]) == sg_src) + desc->cyclic = true; + if (direction != DMA_NONE) { dma_addr_t dev_addr = d40_get_dev_addr(chan, direction); @@ -2007,6 +2081,36 @@ static struct dma_async_tx_descriptor *d40_prep_slave_sg(struct dma_chan *chan, return d40_prep_sg(chan, sgl, sgl, sg_len, direction, dma_flags); } +static struct dma_async_tx_descriptor * +dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr, + size_t buf_len, size_t period_len, + enum dma_data_direction direction) +{ + unsigned int periods = buf_len / period_len; + struct dma_async_tx_descriptor *txd; + struct scatterlist *sg; + int i; + + sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_KERNEL); + for (i = 0; i < periods; i++) { + sg_dma_address(&sg[i]) = dma_addr; + sg_dma_len(&sg[i]) = period_len; + dma_addr += period_len; + } + + sg[periods].offset = 0; + sg[periods].length = 0; + sg[periods].page_link = + ((unsigned long)sg | 0x01) & ~0x02; + + txd = d40_prep_sg(chan, sg, sg, periods, direction, + DMA_PREP_INTERRUPT); + + kfree(sg); + + return txd; +} + static enum dma_status d40_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) @@ -2264,6 +2368,9 @@ static void d40_ops_init(struct d40_base *base, struct dma_device *dev) if (dma_has_cap(DMA_SG, dev->cap_mask)) dev->device_prep_dma_sg = d40_prep_memcpy_sg; + if (dma_has_cap(DMA_CYCLIC, dev->cap_mask)) + dev->device_prep_dma_cyclic = dma40_prep_dma_cyclic; + dev->device_alloc_chan_resources = d40_alloc_chan_resources; dev->device_free_chan_resources = d40_free_chan_resources; dev->device_issue_pending = d40_issue_pending; @@ -2282,6 +2389,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, dma_cap_zero(base->dma_slave.cap_mask); dma_cap_set(DMA_SLAVE, base->dma_slave.cap_mask); + dma_cap_set(DMA_CYCLIC, base->dma_slave.cap_mask); d40_ops_init(base, &base->dma_slave); @@ -2316,9 +2424,9 @@ static int __init d40_dmaengine_init(struct d40_base *base, dma_cap_set(DMA_SLAVE, base->dma_both.cap_mask); dma_cap_set(DMA_MEMCPY, base->dma_both.cap_mask); dma_cap_set(DMA_SG, base->dma_both.cap_mask); + dma_cap_set(DMA_CYCLIC, base->dma_slave.cap_mask); d40_ops_init(base, &base->dma_both); - err = dma_async_device_register(&base->dma_both); if (err) { diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 88b9e371be2f..cad9e1daedff 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c @@ -202,13 +202,15 @@ static int d40_seg_size(int size, int data_width1, int data_width2) static struct d40_phy_lli * d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, - dma_addr_t lli_phys, u32 reg_cfg, + dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg, struct stedma40_half_channel_info *info, struct stedma40_half_channel_info *otherinfo, unsigned long flags) { + bool lastlink = flags & LLI_LAST_LINK; bool addr_inc = flags & LLI_ADDR_INC; bool term_int = flags & LLI_TERM_INT; + bool cyclic = flags & LLI_CYCLIC; int err; dma_addr_t next = lli_phys; int size_rest = size; @@ -226,10 +228,12 @@ d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, otherinfo->data_width); size_rest -= size_seg; - if (term_int && size_rest == 0) { - next = 0; + if (size_rest == 0 && term_int) flags |= LLI_TERM_INT; - } else + + if (size_rest == 0 && lastlink) + next = cyclic ? first_phys : 0; + else next = ALIGN(next + sizeof(struct d40_phy_lli), D40_LLI_ALIGN); @@ -257,14 +261,14 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, dma_addr_t lli_phys, u32 reg_cfg, struct stedma40_half_channel_info *info, - struct stedma40_half_channel_info *otherinfo) + struct stedma40_half_channel_info *otherinfo, + unsigned long flags) { int total_size = 0; int i; struct scatterlist *current_sg = sg; struct d40_phy_lli *lli = lli_sg; dma_addr_t l_phys = lli_phys; - unsigned long flags = 0; if (!target) flags |= LLI_ADDR_INC; @@ -277,12 +281,12 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, total_size += sg_dma_len(current_sg); if (i == sg_len - 1) - flags |= LLI_TERM_INT; + flags |= LLI_TERM_INT | LLI_LAST_LINK; l_phys = ALIGN(lli_phys + (lli - lli_sg) * sizeof(struct d40_phy_lli), D40_LLI_ALIGN); - lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, + lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys, reg_cfg, info, otherinfo, flags); if (lli == NULL) @@ -297,15 +301,18 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, static void d40_log_lli_link(struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, - int next) + int next, unsigned int flags) { + bool interrupt = flags & LLI_TERM_INT; u32 slos = 0; u32 dlos = 0; if (next != -EINVAL) { slos = next * 2; dlos = next * 2 + 1; - } else { + } + + if (interrupt) { lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; } @@ -320,9 +327,9 @@ static void d40_log_lli_link(struct d40_log_lli *lli_dst, void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, - int next) + int next, unsigned int flags) { - d40_log_lli_link(lli_dst, lli_src, next); + d40_log_lli_link(lli_dst, lli_src, next, flags); writel(lli_src->lcsp02, &lcpa[0].lcsp0); writel(lli_src->lcsp13, &lcpa[0].lcsp1); @@ -333,9 +340,9 @@ void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, void d40_log_lli_lcla_write(struct d40_log_lli *lcla, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, - int next) + int next, unsigned int flags) { - d40_log_lli_link(lli_dst, lli_src, next); + d40_log_lli_link(lli_dst, lli_src, next, flags); writel(lli_src->lcsp02, &lcla[0].lcsp02); writel(lli_src->lcsp13, &lcla[0].lcsp13); diff --git a/drivers/dma/ste_dma40_ll.h b/drivers/dma/ste_dma40_ll.h index 59e72f0cc901..195ee65ee7f3 100644 --- a/drivers/dma/ste_dma40_ll.h +++ b/drivers/dma/ste_dma40_ll.h @@ -296,6 +296,8 @@ struct d40_def_lcsp { enum d40_lli_flags { LLI_ADDR_INC = 1 << 0, LLI_TERM_INT = 1 << 1, + LLI_CYCLIC = 1 << 2, + LLI_LAST_LINK = 1 << 3, }; void d40_phy_cfg(struct stedma40_chan_cfg *cfg, @@ -314,7 +316,8 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, dma_addr_t lli_phys, u32 reg_cfg, struct stedma40_half_channel_info *info, - struct stedma40_half_channel_info *otherinfo); + struct stedma40_half_channel_info *otherinfo, + unsigned long flags); /* Logical channels */ @@ -328,11 +331,11 @@ int d40_log_sg_to_lli(struct scatterlist *sg, void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, - int next); + int next, unsigned int flags); void d40_log_lli_lcla_write(struct d40_log_lli *lcla, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, - int next); + int next, unsigned int flags); #endif /* STE_DMA40_LLI_H */ -- cgit v1.2.2 From 51d07566045787b99219d809639c8724506fc78a Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Tue, 25 Jan 2011 11:10:06 -0800 Subject: bq20z75: Add support for charge properties Adding support for charge properties for gas gauge. Also ensuring that battery mode is correct now for energy as well as charge properties by setting it on the fly. I also added 2 functions to power_supply.h to help identify the units for specific properties more easily by power supplies. Signed-off-by: Rhyland Klein Signed-off-by: Anton Vorontsov --- drivers/power/bq20z75.c | 98 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index 492da27e1a47..4141775e5ff6 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c @@ -38,11 +38,22 @@ enum { REG_CYCLE_COUNT, REG_SERIAL_NUMBER, REG_REMAINING_CAPACITY, + REG_REMAINING_CAPACITY_CHARGE, REG_FULL_CHARGE_CAPACITY, + REG_FULL_CHARGE_CAPACITY_CHARGE, REG_DESIGN_CAPACITY, + REG_DESIGN_CAPACITY_CHARGE, REG_DESIGN_VOLTAGE, }; +/* Battery Mode defines */ +#define BATTERY_MODE_OFFSET 0x03 +#define BATTERY_MODE_MASK 0x8000 +enum bq20z75_battery_mode { + BATTERY_MODE_AMPS, + BATTERY_MODE_WATTS +}; + /* manufacturer access defines */ #define MANUFACTURER_ACCESS_STATUS 0x0006 #define MANUFACTURER_ACCESS_SLEEP 0x0011 @@ -78,8 +89,12 @@ static const struct bq20z75_device_data { BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY, 0x0E, 0, 100), [REG_REMAINING_CAPACITY] = BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_NOW, 0x0F, 0, 65535), + [REG_REMAINING_CAPACITY_CHARGE] = + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_NOW, 0x0F, 0, 65535), [REG_FULL_CHARGE_CAPACITY] = BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), + [REG_FULL_CHARGE_CAPACITY_CHARGE] = + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), [REG_TIME_TO_EMPTY] = BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 65535), @@ -93,6 +108,9 @@ static const struct bq20z75_device_data { [REG_DESIGN_CAPACITY] = BQ20Z75_DATA(POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, 0x18, 0, 65535), + [REG_DESIGN_CAPACITY_CHARGE] = + BQ20Z75_DATA(POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 0x18, 0, + 65535), [REG_DESIGN_VOLTAGE] = BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 0x19, 0, 65535), @@ -117,6 +135,9 @@ static enum power_supply_property bq20z75_properties[] = { POWER_SUPPLY_PROP_ENERGY_NOW, POWER_SUPPLY_PROP_ENERGY_FULL, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, }; struct bq20z75_info { @@ -260,6 +281,9 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: val->intval *= BASE_UNIT_CONVERSION; break; @@ -281,11 +305,44 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, } } +static enum bq20z75_battery_mode +bq20z75_set_battery_mode(struct i2c_client *client, + enum bq20z75_battery_mode mode) +{ + int ret, original_val; + + original_val = bq20z75_read_word_data(client, BATTERY_MODE_OFFSET); + if (original_val < 0) + return original_val; + + if ((original_val & BATTERY_MODE_MASK) == mode) + return mode; + + if (mode == BATTERY_MODE_AMPS) + ret = original_val & ~BATTERY_MODE_MASK; + else + ret = original_val | BATTERY_MODE_MASK; + + ret = bq20z75_write_word_data(client, BATTERY_MODE_OFFSET, ret); + if (ret < 0) + return ret; + + return original_val & BATTERY_MODE_MASK; +} + static int bq20z75_get_battery_capacity(struct i2c_client *client, int reg_offset, enum power_supply_property psp, union power_supply_propval *val) { s32 ret; + enum bq20z75_battery_mode mode = BATTERY_MODE_WATTS; + + if (power_supply_is_amp_property(psp)) + mode = BATTERY_MODE_AMPS; + + mode = bq20z75_set_battery_mode(client, mode); + if (mode < 0) + return mode; ret = bq20z75_read_word_data(client, bq20z75_data[reg_offset].addr); if (ret < 0) @@ -298,6 +355,10 @@ static int bq20z75_get_battery_capacity(struct i2c_client *client, } else val->intval = ret; + ret = bq20z75_set_battery_mode(client, mode); + if (ret < 0) + return ret; + return 0; } @@ -318,11 +379,25 @@ static int bq20z75_get_battery_serial_number(struct i2c_client *client, return 0; } +static int bq20z75_get_property_index(struct i2c_client *client, + enum power_supply_property psp) +{ + int count; + for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) + if (psp == bq20z75_data[count].psp) + return count; + + dev_warn(&client->dev, + "%s: Invalid Property - %d\n", __func__, psp); + + return -EINVAL; +} + static int bq20z75_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - int count; + int ps_index; int ret; struct bq20z75_info *bq20z75_device = container_of(psy, struct bq20z75_info, power_supply); @@ -343,13 +418,15 @@ static int bq20z75_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_ENERGY_NOW: case POWER_SUPPLY_PROP_ENERGY_FULL: case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_CHARGE_FULL: + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: case POWER_SUPPLY_PROP_CAPACITY: - for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { - if (psp == bq20z75_data[count].psp) - break; - } + ps_index = bq20z75_get_property_index(client, psp); + if (ps_index < 0) + return ps_index; - ret = bq20z75_get_battery_capacity(client, count, psp, val); + ret = bq20z75_get_battery_capacity(client, ps_index, psp, val); if (ret) return ret; @@ -369,12 +446,11 @@ static int bq20z75_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - for (count = 0; count < ARRAY_SIZE(bq20z75_data); count++) { - if (psp == bq20z75_data[count].psp) - break; - } + ps_index = bq20z75_get_property_index(client, psp); + if (ps_index < 0) + return ps_index; - ret = bq20z75_get_battery_property(client, count, psp, val); + ret = bq20z75_get_battery_property(client, ps_index, psp, val); if (ret) return ret; -- cgit v1.2.2 From 0b9536c957095eb1497828aa51b34ac695f67eae Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Fri, 7 Jan 2011 16:28:16 +0000 Subject: leds: Add ability to blink via simple trigger As blink API is now available, it's possible to add ability to blink via simple trigger. Signed-off-by: Vasily Khoruzhick Signed-off-by: Anton Vorontsov --- drivers/leds/led-triggers.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index c41eb6180c9c..4bebae733349 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -231,6 +231,26 @@ void led_trigger_event(struct led_trigger *trigger, } EXPORT_SYMBOL_GPL(led_trigger_event); +void led_trigger_blink(struct led_trigger *trigger, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct list_head *entry; + + if (!trigger) + return; + + read_lock(&trigger->leddev_list_lock); + list_for_each(entry, &trigger->led_cdevs) { + struct led_classdev *led_cdev; + + led_cdev = list_entry(entry, struct led_classdev, trig_list); + led_blink_set(led_cdev, delay_on, delay_off); + } + read_unlock(&trigger->leddev_list_lock); +} +EXPORT_SYMBOL_GPL(led_trigger_blink); + void led_trigger_register_simple(const char *name, struct led_trigger **tp) { struct led_trigger *trigger; -- cgit v1.2.2 From 6501f728c56f831626d52b236023e556bca37f51 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Fri, 7 Jan 2011 18:28:17 +0200 Subject: power_supply: Add new LED trigger charging-blink-solid-full Add new trigger to power_supply LEDs. It will blink when battery is charging, and stay solid when battery is charged. It's usefull to indicate battery state when there's only one LED available. Signed-off-by: Vasily Khoruzhick Signed-off-by: Anton Vorontsov --- drivers/power/power_supply_leds.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index 031a554837f7..da25eb94e5c6 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c @@ -21,6 +21,8 @@ static void power_supply_update_bat_leds(struct power_supply *psy) { union power_supply_propval status; + unsigned long delay_on = 0; + unsigned long delay_off = 0; if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) return; @@ -32,16 +34,22 @@ static void power_supply_update_bat_leds(struct power_supply *psy) led_trigger_event(psy->charging_full_trig, LED_FULL); led_trigger_event(psy->charging_trig, LED_OFF); led_trigger_event(psy->full_trig, LED_FULL); + led_trigger_event(psy->charging_blink_full_solid_trig, + LED_FULL); break; case POWER_SUPPLY_STATUS_CHARGING: led_trigger_event(psy->charging_full_trig, LED_FULL); led_trigger_event(psy->charging_trig, LED_FULL); led_trigger_event(psy->full_trig, LED_OFF); + led_trigger_blink(psy->charging_blink_full_solid_trig, + &delay_on, &delay_off); break; default: led_trigger_event(psy->charging_full_trig, LED_OFF); led_trigger_event(psy->charging_trig, LED_OFF); led_trigger_event(psy->full_trig, LED_OFF); + led_trigger_event(psy->charging_blink_full_solid_trig, + LED_OFF); break; } } @@ -64,15 +72,24 @@ static int power_supply_create_bat_triggers(struct power_supply *psy) if (!psy->full_trig_name) goto full_failed; + psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL, + "%s-charging-blink-full-solid", psy->name); + if (!psy->charging_blink_full_solid_trig_name) + goto charging_blink_full_solid_failed; + led_trigger_register_simple(psy->charging_full_trig_name, &psy->charging_full_trig); led_trigger_register_simple(psy->charging_trig_name, &psy->charging_trig); led_trigger_register_simple(psy->full_trig_name, &psy->full_trig); + led_trigger_register_simple(psy->charging_blink_full_solid_trig_name, + &psy->charging_blink_full_solid_trig); goto success; +charging_blink_full_solid_failed: + kfree(psy->full_trig_name); full_failed: kfree(psy->charging_trig_name); charging_failed: @@ -88,6 +105,8 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy) led_trigger_unregister_simple(psy->charging_full_trig); led_trigger_unregister_simple(psy->charging_trig); led_trigger_unregister_simple(psy->full_trig); + led_trigger_unregister_simple(psy->charging_blink_full_solid_trig); + kfree(psy->charging_blink_full_solid_trig_name); kfree(psy->full_trig_name); kfree(psy->charging_trig_name); kfree(psy->charging_full_trig_name); -- cgit v1.2.2 From 723d928417bffff6467da155d8ebbbe016464012 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 31 Jan 2011 21:09:25 -0800 Subject: Input: wm831x-ts - remove use of ternary operator While being applied the driver was modified to add use of the ternary operator. Write the conditionals out longhand as I find it terribly unhelpful for legibility. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index a6121bdb635d..1022f715d3c2 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -76,9 +76,14 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) struct wm831x *wm831x = wm831x_ts->wm831x; static int data_types[] = { ABS_X, ABS_Y, ABS_PRESSURE }; u16 data[3]; - int count = wm831x_ts->pressure ? 3 : 2; + int count; int i, ret; + if (wm831x_ts->pressure) + count = 3; + else + count = 2; + wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_TCHDATA_EINT, WM831X_TCHDATA_EINT); @@ -134,10 +139,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) { struct wm831x_ts *wm831x_ts = irq_data; struct wm831x *wm831x = wm831x_ts->wm831x; - int ena; + int ena = 0; /* Start collecting data */ - ena = wm831x_ts->pressure ? WM831X_TCH_Z_ENA : 0; + if (wm831x_ts->pressure) + ena |= WM831X_TCH_Z_ENA; wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, @@ -188,11 +194,13 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) struct wm831x_ts *wm831x_ts; struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); - struct wm831x_touch_pdata *pdata = - core_pdata ? core_pdata->touch : NULL; + struct wm831x_touch_pdata *pdata = NULL; struct input_dev *input_dev; int error; + if (core_pdata) + pdata = core_pdata->touch; + wm831x_ts = kzalloc(sizeof(struct wm831x_ts), GFP_KERNEL); input_dev = input_allocate_device(); if (!wm831x_ts || !input_dev) { -- cgit v1.2.2 From f06e6a52ca3dbe927f58653b1e90cbb53f5ceb55 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 31 Jan 2011 21:06:39 -0800 Subject: Input: dvb-usb-remote - convert to new style of get/setkeycode Acked-by: Mauro Carvalho Chehab Signed-off-by: Dmitry Torokhov --- drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 113 ++++++++++++++++++----------- 1 file changed, 70 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 23005b3cf30b..347fbd4e2d56 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -8,60 +8,71 @@ #include "dvb-usb-common.h" #include +static unsigned int +legacy_dvb_usb_get_keymap_index(const struct input_keymap_entry *ke, + struct rc_map_table *keymap, + unsigned int keymap_size) +{ + unsigned int index; + unsigned int scancode; + + if (ke->flags & INPUT_KEYMAP_BY_INDEX) { + index = ke->index; + } else { + if (input_scancode_to_scalar(ke, &scancode)) + return keymap_size; + + /* See if we can match the raw key code. */ + for (index = 0; index < keymap_size; index++) + if (keymap[index].scancode == scancode) + break; + + /* See if there is an unused hole in the map */ + if (index >= keymap_size) { + for (index = 0; index < keymap_size; index++) { + if (keymap[index].keycode == KEY_RESERVED || + keymap[index].keycode == KEY_UNKNOWN) { + break; + } + } + } + } + + return index; +} + static int legacy_dvb_usb_getkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int *keycode) + struct input_keymap_entry *ke) { struct dvb_usb_device *d = input_get_drvdata(dev); - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - int i; + unsigned int keymap_size = d->props.rc.legacy.rc_map_size; + unsigned int index; - /* See if we can match the raw key code. */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].scancode == scancode) { - *keycode = keymap[i].keycode; - return 0; - } + index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); + if (index >= keymap_size) + return -EINVAL; - /* - * If is there extra space, returns KEY_RESERVED, - * otherwise, input core won't let legacy_dvb_usb_setkeycode - * to work - */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].keycode == KEY_RESERVED || - keymap[i].keycode == KEY_UNKNOWN) { - *keycode = KEY_RESERVED; - return 0; - } + ke->keycode = keymap[index].keycode; + if (ke->keycode == KEY_UNKNOWN) + ke->keycode = KEY_RESERVED; + ke->len = sizeof(keymap[index].scancode); + memcpy(&ke->scancode, &keymap[index].scancode, ke->len); + ke->index = index; - return -EINVAL; + return 0; } static int legacy_dvb_usb_setkeycode(struct input_dev *dev, - unsigned int scancode, unsigned int keycode) + const struct input_keymap_entry *ke, + unsigned int *old_keycode) { struct dvb_usb_device *d = input_get_drvdata(dev); - struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table; - int i; - - /* Search if it is replacing an existing keycode */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].scancode == scancode) { - keymap[i].keycode = keycode; - return 0; - } - - /* Search if is there a clean entry. If so, use it */ - for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) - if (keymap[i].keycode == KEY_RESERVED || - keymap[i].keycode == KEY_UNKNOWN) { - keymap[i].scancode = scancode; - keymap[i].keycode = keycode; - return 0; - } + unsigned int keymap_size = d->props.rc.legacy.rc_map_size; + unsigned int index; + index = legacy_dvb_usb_get_keymap_index(ke, keymap, keymap_size); /* * FIXME: Currently, it is not possible to increase the size of * scancode table. For it to happen, one possibility @@ -69,8 +80,24 @@ static int legacy_dvb_usb_setkeycode(struct input_dev *dev, * copying data, appending the new key on it, and freeing * the old one - or maybe just allocating some spare space */ + if (index >= keymap_size) + return -EINVAL; + + *old_keycode = keymap[index].keycode; + keymap->keycode = ke->keycode; + __set_bit(ke->keycode, dev->keybit); + + if (*old_keycode != KEY_RESERVED) { + __clear_bit(*old_keycode, dev->keybit); + for (index = 0; index < keymap_size; index++) { + if (keymap[index].keycode == *old_keycode) { + __set_bit(*old_keycode, dev->keybit); + break; + } + } + } - return -EINVAL; + return 0; } /* Remote-control poll function - called every dib->rc_query_interval ms to see @@ -171,8 +198,8 @@ static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) d->input_dev = input_dev; d->rc_dev = NULL; - input_dev->getkeycode = legacy_dvb_usb_getkeycode; - input_dev->setkeycode = legacy_dvb_usb_setkeycode; + input_dev->getkeycode_new = legacy_dvb_usb_getkeycode; + input_dev->setkeycode_new = legacy_dvb_usb_setkeycode; /* set the bits for the keys */ deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); -- cgit v1.2.2 From aebd636bd60e2dda0ebc907dd5f7f4a45174411c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 31 Jan 2011 21:06:39 -0800 Subject: Input: switch completely over to the new versions of get/setkeycode All users of old style get/setkeycode methids have been converted so it is time to retire them. Acked-by: Mauro Carvalho Chehab Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-input.c | 4 +-- drivers/input/input.c | 55 ++++-------------------------- drivers/input/misc/ati_remote2.c | 4 +-- drivers/input/sparse-keymap.c | 4 +-- drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 4 +-- drivers/media/rc/rc-main.c | 4 +-- 6 files changed, 17 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 7f552bfad32c..ba2aeea2cbf9 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -888,8 +888,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) hid->ll_driver->hidinput_input_event; input_dev->open = hidinput_open; input_dev->close = hidinput_close; - input_dev->setkeycode_new = hidinput_setkeycode; - input_dev->getkeycode_new = hidinput_getkeycode; + input_dev->setkeycode = hidinput_setkeycode; + input_dev->getkeycode = hidinput_getkeycode; input_dev->name = hid->name; input_dev->phys = hid->phys; diff --git a/drivers/input/input.c b/drivers/input/input.c index 7985114beac7..ee2959bd322c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -806,22 +806,9 @@ int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke) int retval; spin_lock_irqsave(&dev->event_lock, flags); - - if (dev->getkeycode) { - /* - * Support for legacy drivers, that don't implement the new - * ioctls - */ - u32 scancode = ke->index; - - memcpy(ke->scancode, &scancode, sizeof(scancode)); - ke->len = sizeof(scancode); - retval = dev->getkeycode(dev, scancode, &ke->keycode); - } else { - retval = dev->getkeycode_new(dev, ke); - } - + retval = dev->getkeycode(dev, ke); spin_unlock_irqrestore(&dev->event_lock, flags); + return retval; } EXPORT_SYMBOL(input_get_keycode); @@ -846,35 +833,7 @@ int input_set_keycode(struct input_dev *dev, spin_lock_irqsave(&dev->event_lock, flags); - if (dev->setkeycode) { - /* - * Support for legacy drivers, that don't implement the new - * ioctls - */ - unsigned int scancode; - - retval = input_scancode_to_scalar(ke, &scancode); - if (retval) - goto out; - - /* - * We need to know the old scancode, in order to generate a - * keyup effect, if the set operation happens successfully - */ - if (!dev->getkeycode) { - retval = -EINVAL; - goto out; - } - - retval = dev->getkeycode(dev, scancode, &old_keycode); - if (retval) - goto out; - - retval = dev->setkeycode(dev, scancode, ke->keycode); - } else { - retval = dev->setkeycode_new(dev, ke, &old_keycode); - } - + retval = dev->setkeycode(dev, ke, &old_keycode); if (retval) goto out; @@ -1861,11 +1820,11 @@ int input_register_device(struct input_dev *dev) dev->rep[REP_PERIOD] = 33; } - if (!dev->getkeycode && !dev->getkeycode_new) - dev->getkeycode_new = input_default_getkeycode; + if (!dev->getkeycode) + dev->getkeycode = input_default_getkeycode; - if (!dev->setkeycode && !dev->setkeycode_new) - dev->setkeycode_new = input_default_setkeycode; + if (!dev->setkeycode) + dev->setkeycode = input_default_setkeycode; dev_set_name(&dev->dev, "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 0b0e9be63542..9ccdb82d869a 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -612,8 +612,8 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) idev->open = ati_remote2_open; idev->close = ati_remote2_close; - idev->getkeycode_new = ati_remote2_getkeycode; - idev->setkeycode_new = ati_remote2_setkeycode; + idev->getkeycode = ati_remote2_getkeycode; + idev->setkeycode = ati_remote2_setkeycode; idev->name = ar2->name; idev->phys = ar2->phys; diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 7729e547ba65..337bf51bc984 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -210,8 +210,8 @@ int sparse_keymap_setup(struct input_dev *dev, dev->keycode = map; dev->keycodemax = map_size; - dev->getkeycode_new = sparse_keymap_getkeycode; - dev->setkeycode_new = sparse_keymap_setkeycode; + dev->getkeycode = sparse_keymap_getkeycode; + dev->setkeycode = sparse_keymap_setkeycode; return 0; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 347fbd4e2d56..b2b9415d874d 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -198,8 +198,8 @@ static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d) d->input_dev = input_dev; d->rc_dev = NULL; - input_dev->getkeycode_new = legacy_dvb_usb_getkeycode; - input_dev->setkeycode_new = legacy_dvb_usb_setkeycode; + input_dev->getkeycode = legacy_dvb_usb_getkeycode; + input_dev->setkeycode = legacy_dvb_usb_setkeycode; /* set the bits for the keys */ deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 512a2f4ada0e..c3769283936f 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -966,8 +966,8 @@ struct rc_dev *rc_allocate_device(void) return NULL; } - dev->input_dev->getkeycode_new = ir_getkeycode; - dev->input_dev->setkeycode_new = ir_setkeycode; + dev->input_dev->getkeycode = ir_getkeycode; + dev->input_dev->setkeycode = ir_setkeycode; input_set_drvdata(dev->input_dev, dev); spin_lock_init(&dev->rc_map.lock); -- cgit v1.2.2 From 2546bcc2d64c3bd0e7cb802cb8fc6cf757c6be0b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 31 Jan 2011 21:06:34 -0800 Subject: Input: input-polldev - fix a couple of typos Signed-off-by: Dmitry Torokhov --- drivers/input/input-polldev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index 0559e309bac9..3037842a60d8 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c @@ -192,7 +192,7 @@ static struct attribute_group input_polldev_attribute_group = { }; /** - * input_allocate_polled_device - allocated memory polled device + * input_allocate_polled_device - allocate memory for polled device * * The function allocates memory for a polled device and also * for an input device associated with this polled device. @@ -239,7 +239,7 @@ EXPORT_SYMBOL(input_free_polled_device); * with input layer. The device should be allocated with call to * input_allocate_polled_device(). Callers should also set up poll() * method and set up capabilities (id, name, phys, bits) of the - * corresponing input_dev structure. + * corresponding input_dev structure. */ int input_register_polled_device(struct input_polled_dev *dev) { -- cgit v1.2.2 From 4c4231ea2f794d73bbb50b8d84e00c66a012a607 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 6 Feb 2011 20:45:52 +0000 Subject: [PARISC] Convert to new irq_chip functions Convert all the parisc driver interrupt handlers (dino, eisa, gsc, iosapic and superio) as well as the cpu interrupts. Prepare show_interrupts for GENERIC_HARDIRQS_NO_DEPRECATED and finally selects that Kconfig option [jejb: compile and testing fixes] Signed-off-by: Thomas Gleixner Signed-off-by: James Bottomley --- drivers/parisc/dino.c | 22 +++++++++++----------- drivers/parisc/eisa.c | 12 +++++++----- drivers/parisc/gsc.c | 22 +++++++++++----------- drivers/parisc/iosapic.c | 40 ++++++++++++++++++++-------------------- drivers/parisc/superio.c | 12 +++++++----- 5 files changed, 56 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 9383063d2b16..bcd5d54b7d4d 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -296,25 +296,25 @@ static struct pci_port_ops dino_port_ops = { .outl = dino_out32 }; -static void dino_mask_irq(unsigned int irq) +static void dino_mask_irq(struct irq_data *d) { - struct dino_device *dino_dev = get_irq_chip_data(irq); - int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS); + struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); + int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS); - DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq); /* Clear the matching bit in the IMR register */ dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq)); __raw_writel(dino_dev->imr, dino_dev->hba.base_addr+DINO_IMR); } -static void dino_unmask_irq(unsigned int irq) +static void dino_unmask_irq(struct irq_data *d) { - struct dino_device *dino_dev = get_irq_chip_data(irq); - int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS); + struct dino_device *dino_dev = irq_data_get_irq_chip_data(d); + int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS); u32 tmp; - DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, irq); + DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq); /* ** clear pending IRQ bits @@ -346,9 +346,9 @@ static void dino_unmask_irq(unsigned int irq) } static struct irq_chip dino_interrupt_type = { - .name = "GSC-PCI", - .unmask = dino_unmask_irq, - .mask = dino_mask_irq, + .name = "GSC-PCI", + .irq_unmask = dino_unmask_irq, + .irq_mask = dino_mask_irq, }; diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index e860038b0b84..deeec32a5803 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -144,8 +144,9 @@ static unsigned int eisa_irq_level __read_mostly; /* default to edge triggered * /* called by free irq */ -static void eisa_mask_irq(unsigned int irq) +static void eisa_mask_irq(struct irq_data *d) { + unsigned int irq = d->irq; unsigned long flags; EISA_DBG("disable irq %d\n", irq); @@ -164,8 +165,9 @@ static void eisa_mask_irq(unsigned int irq) } /* called by request irq */ -static void eisa_unmask_irq(unsigned int irq) +static void eisa_unmask_irq(struct irq_data *d) { + unsigned int irq = d->irq; unsigned long flags; EISA_DBG("enable irq %d\n", irq); @@ -183,9 +185,9 @@ static void eisa_unmask_irq(unsigned int irq) } static struct irq_chip eisa_interrupt_type = { - .name = "EISA", - .unmask = eisa_unmask_irq, - .mask = eisa_mask_irq, + .name = "EISA", + .irq_unmask = eisa_unmask_irq, + .irq_mask = eisa_mask_irq, }; static irqreturn_t eisa_irq(int wax_irq, void *intr_dev) diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index 772b1939ac21..ef31080cf591 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -105,13 +105,13 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit) return NO_IRQ; } -static void gsc_asic_mask_irq(unsigned int irq) +static void gsc_asic_mask_irq(struct irq_data *d) { - struct gsc_asic *irq_dev = get_irq_chip_data(irq); - int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32); + struct gsc_asic *irq_dev = irq_data_get_irq_chip_data(d); + int local_irq = gsc_find_local_irq(d->irq, irq_dev->global_irq, 32); u32 imr; - DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq, + DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, d->irq, irq_dev->name, imr); /* Disable the IRQ line by clearing the bit in the IMR */ @@ -120,13 +120,13 @@ static void gsc_asic_mask_irq(unsigned int irq) gsc_writel(imr, irq_dev->hpa + OFFSET_IMR); } -static void gsc_asic_unmask_irq(unsigned int irq) +static void gsc_asic_unmask_irq(struct irq_data *d) { - struct gsc_asic *irq_dev = get_irq_chip_data(irq); - int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32); + struct gsc_asic *irq_dev = irq_data_get_irq_chip_data(d); + int local_irq = gsc_find_local_irq(d->irq, irq_dev->global_irq, 32); u32 imr; - DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, irq, + DEBPRINTK(KERN_DEBUG "%s(%d) %s: IMR 0x%x\n", __func__, d->irq, irq_dev->name, imr); /* Enable the IRQ line by setting the bit in the IMR */ @@ -140,9 +140,9 @@ static void gsc_asic_unmask_irq(unsigned int irq) } static struct irq_chip gsc_asic_interrupt_type = { - .name = "GSC-ASIC", - .unmask = gsc_asic_unmask_irq, - .mask = gsc_asic_mask_irq, + .name = "GSC-ASIC", + .irq_unmask = gsc_asic_unmask_irq, + .irq_mask = gsc_asic_mask_irq, }; int gsc_assign_irq(struct irq_chip *type, void *data) diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 0327894bf235..95930d016235 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -615,10 +615,10 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1) } -static void iosapic_mask_irq(unsigned int irq) +static void iosapic_mask_irq(struct irq_data *d) { unsigned long flags; - struct vector_info *vi = get_irq_chip_data(irq); + struct vector_info *vi = irq_data_get_irq_chip_data(d); u32 d0, d1; spin_lock_irqsave(&iosapic_lock, flags); @@ -628,9 +628,9 @@ static void iosapic_mask_irq(unsigned int irq) spin_unlock_irqrestore(&iosapic_lock, flags); } -static void iosapic_unmask_irq(unsigned int irq) +static void iosapic_unmask_irq(struct irq_data *d) { - struct vector_info *vi = get_irq_chip_data(irq); + struct vector_info *vi = irq_data_get_irq_chip_data(d); u32 d0, d1; /* data is initialized by fixup_irq */ @@ -666,34 +666,34 @@ printk("\n"); * enables their IRQ. It can lead to "interesting" race conditions * in the driver initialization sequence. */ - DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", irq, + DBG(KERN_DEBUG "enable_irq(%d): eoi(%p, 0x%x)\n", d->irq, vi->eoi_addr, vi->eoi_data); iosapic_eoi(vi->eoi_addr, vi->eoi_data); } -static void iosapic_eoi_irq(unsigned int irq) +static void iosapic_eoi_irq(struct irq_data *d) { - struct vector_info *vi = get_irq_chip_data(irq); + struct vector_info *vi = irq_data_get_irq_chip_data(d); iosapic_eoi(vi->eoi_addr, vi->eoi_data); - cpu_eoi_irq(irq); + cpu_eoi_irq(d); } #ifdef CONFIG_SMP -static int iosapic_set_affinity_irq(unsigned int irq, - const struct cpumask *dest) +static int iosapic_set_affinity_irq(struct irq_data *d, + const struct cpumask *dest, bool force) { - struct vector_info *vi = get_irq_chip_data(irq); + struct vector_info *vi = irq_data_get_irq_chip_data(d); u32 d0, d1, dummy_d0; unsigned long flags; int dest_cpu; - dest_cpu = cpu_check_affinity(irq, dest); + dest_cpu = cpu_check_affinity(d, dest); if (dest_cpu < 0) return -1; - cpumask_copy(irq_desc[irq].affinity, cpumask_of(dest_cpu)); - vi->txn_addr = txn_affinity_addr(irq, dest_cpu); + cpumask_copy(d->affinity, cpumask_of(dest_cpu)); + vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu); spin_lock_irqsave(&iosapic_lock, flags); /* d1 contains the destination CPU, so only want to set that @@ -708,13 +708,13 @@ static int iosapic_set_affinity_irq(unsigned int irq, #endif static struct irq_chip iosapic_interrupt_type = { - .name = "IO-SAPIC-level", - .unmask = iosapic_unmask_irq, - .mask = iosapic_mask_irq, - .ack = cpu_ack_irq, - .eoi = iosapic_eoi_irq, + .name = "IO-SAPIC-level", + .irq_unmask = iosapic_unmask_irq, + .irq_mask = iosapic_mask_irq, + .irq_ack = cpu_ack_irq, + .irq_eoi = iosapic_eoi_irq, #ifdef CONFIG_SMP - .set_affinity = iosapic_set_affinity_irq, + .irq_set_affinity = iosapic_set_affinity_irq, #endif }; diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 28241532c0fd..a4d8ff66a639 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -286,8 +286,9 @@ superio_init(struct pci_dev *pcidev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init); -static void superio_mask_irq(unsigned int irq) +static void superio_mask_irq(struct irq_data *d) { + unsigned int irq = d->irq; u8 r8; if ((irq < 1) || (irq == 2) || (irq > 7)) { @@ -303,8 +304,9 @@ static void superio_mask_irq(unsigned int irq) outb (r8,IC_PIC1+1); } -static void superio_unmask_irq(unsigned int irq) +static void superio_unmask_irq(struct irq_data *d) { + unsigned int irq = d->irq; u8 r8; if ((irq < 1) || (irq == 2) || (irq > 7)) { @@ -320,9 +322,9 @@ static void superio_unmask_irq(unsigned int irq) } static struct irq_chip superio_interrupt_type = { - .name = SUPERIO, - .unmask = superio_unmask_irq, - .mask = superio_mask_irq, + .name = SUPERIO, + .irq_unmask = superio_unmask_irq, + .irq_mask = superio_mask_irq, }; #ifdef DEBUG_SUPERIO_INIT -- cgit v1.2.2 From ff6433225b08d74f77f6eb4c5bf5ca434a371492 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 19 Jan 2011 21:10:24 +0000 Subject: ARM: clcd: clean up CLCD announcement printks Make the CLCD announcement printk say which primecell part number has been found. Display the revision as an unsigned decimal, and display only the first 8 hex digits of the base address unless it's larger. Acked-by: Catalin Marinas Signed-off-by: Russell King --- drivers/video/amba-clcd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 1c2c68356ea7..aedbb345f8a9 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -443,8 +443,8 @@ static int clcdfb_register(struct clcd_fb *fb) fb_set_var(&fb->fb, &fb->fb.var); - printk(KERN_INFO "CLCD: %s hardware, %s display\n", - fb->board->name, fb->panel->mode.name); + dev_info(&fb->dev->dev, "%s hardware, %s display\n", + fb->board->name, fb->panel->mode.name); ret = register_framebuffer(&fb->fb); if (ret == 0) @@ -486,6 +486,10 @@ static int clcdfb_probe(struct amba_device *dev, struct amba_id *id) fb->dev = dev; fb->board = board; + dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n", + amba_part(dev), amba_rev(dev), + (unsigned long long)dev->res.start); + ret = fb->board->setup(fb); if (ret) goto free_fb; -- cgit v1.2.2 From 7b4e9ced69a120e7e7446e3303d2307aa29d891c Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 21 Jan 2011 14:03:28 +0000 Subject: ARM: clcd: add method for describing display capabilities The ARM CLCD PL110 controller in TFT mode provides two output formats based on whether the controller is in 24bpp mode or not - either 5551 or 888. PL111 augments this with a 444 and 565 modes. Some implementations provide an external MUX on the PL110 output to reassign the bits to achieve 565 mode. Provide a system of capability flags to allow the CLCD driver to work out what is supported by each panel and board, and therefore which display formats are permitted. Acked-by: Catalin Marinas Signed-off-by: Russell King --- drivers/video/amba-clcd.c | 95 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index aedbb345f8a9..8bd370697533 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -120,8 +120,23 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) static int clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) { + u32 caps; int ret = 0; + if (fb->panel->caps && fb->board->caps) + caps = fb->panel->caps & fb->board->caps; + else { + /* Old way of specifying what can be used */ + caps = fb->panel->cntl & CNTL_BGR ? + CLCD_CAP_BGR : CLCD_CAP_RGB; + /* But mask out 444 modes as they weren't supported */ + caps &= ~CLCD_CAP_444; + } + + /* Only TFT panels can do RGB888/BGR888 */ + if (!(fb->panel->cntl & CNTL_LCDTFT)) + caps &= ~CLCD_CAP_888; + memset(&var->transp, 0, sizeof(var->transp)); var->red.msb_right = 0; @@ -133,6 +148,13 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) case 2: case 4: case 8: + /* If we can't do 5551, reject */ + caps &= CLCD_CAP_5551; + if (!caps) { + ret = -EINVAL; + break; + } + var->red.length = var->bits_per_pixel; var->red.offset = 0; var->green.length = var->bits_per_pixel; @@ -140,23 +162,61 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) var->blue.length = var->bits_per_pixel; var->blue.offset = 0; break; + case 16: - var->red.length = 5; - var->blue.length = 5; + /* If we can't do 444, 5551 or 565, reject */ + if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) { + ret = -EINVAL; + break; + } + /* - * Green length can be 5 or 6 depending whether - * we're operating in RGB555 or RGB565 mode. + * Green length can be 4, 5 or 6 depending whether + * we're operating in 444, 5551 or 565 mode. */ - if (var->green.length != 5 && var->green.length != 6) - var->green.length = 6; + if (var->green.length == 4 && caps & CLCD_CAP_444) + caps &= CLCD_CAP_444; + if (var->green.length == 5 && caps & CLCD_CAP_5551) + caps &= CLCD_CAP_5551; + else if (var->green.length == 6 && caps & CLCD_CAP_565) + caps &= CLCD_CAP_565; + else { + /* + * PL110 officially only supports RGB555, + * but may be wired up to allow RGB565. + */ + if (caps & CLCD_CAP_565) { + var->green.length = 6; + caps &= CLCD_CAP_565; + } else if (caps & CLCD_CAP_5551) { + var->green.length = 5; + caps &= CLCD_CAP_5551; + } else { + var->green.length = 4; + caps &= CLCD_CAP_444; + } + } + + if (var->green.length >= 5) { + var->red.length = 5; + var->blue.length = 5; + } else { + var->red.length = 4; + var->blue.length = 4; + } break; case 32: - if (fb->panel->cntl & CNTL_LCDTFT) { - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; + /* If we can't do 888, reject */ + caps &= CLCD_CAP_888; + if (!caps) { + ret = -EINVAL; break; } + + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + break; default: ret = -EINVAL; break; @@ -168,7 +228,20 @@ clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) * the bitfield length defined above. */ if (ret == 0 && var->bits_per_pixel >= 16) { - if (fb->panel->cntl & CNTL_BGR) { + bool bgr, rgb; + + bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0; + rgb = caps & CLCD_CAP_RGB && var->red.offset == 0; + + if (!bgr && !rgb) + /* + * The requested format was not possible, try just + * our capabilities. One of BGR or RGB must be + * supported. + */ + bgr = caps & CLCD_CAP_BGR; + + if (bgr) { var->blue.offset = 0; var->green.offset = var->blue.offset + var->blue.length; var->red.offset = var->green.offset + var->green.length; -- cgit v1.2.2 From 964de52147c2842092642512e6f654fc2ab51408 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 2 Feb 2011 23:21:58 -0800 Subject: Input: qt602240_ts - rename to atmel_mxt_ts Since the driver will be supporting whole range of Atmels mXT touchscreen controllers we better rename it to atmel_mxt_ts. Acked-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 24 +- drivers/input/touchscreen/Makefile | 2 +- drivers/input/touchscreen/atmel_mxt_ts.c | 1406 ++++++++++++++++++++++++++++++ drivers/input/touchscreen/qt602240_ts.c | 1406 ------------------------------ 4 files changed, 1419 insertions(+), 1419 deletions(-) create mode 100644 drivers/input/touchscreen/atmel_mxt_ts.c delete mode 100644 drivers/input/touchscreen/qt602240_ts.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 258e43e98ec3..2fbd3d39b7eb 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -86,6 +86,18 @@ config TOUCHSCREEN_AD7879_SPI To compile this driver as a module, choose M here: the module will be called ad7879-spi. +config TOUCHSCREEN_ATMEL_MXT + tristate "Atmel mXT I2C Touchscreen" + depends on I2C + help + Say Y here if you have Atmel mXT series I2C touchscreen, + such as AT42QT602240/ATMXT224, connected to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called atmel_mxt_ts. + config TOUCHSCREEN_BITSY tristate "Compaq iPAQ H3600 (Bitsy) touchscreen" depends on SA1100_BITSY @@ -339,18 +351,6 @@ config TOUCHSCREEN_PENMOUNT To compile this driver as a module, choose M here: the module will be called penmount. -config TOUCHSCREEN_QT602240 - tristate "QT602240 I2C Touchscreen" - depends on I2C - help - Say Y here if you have the AT42QT602240/ATMXT224 I2C touchscreen - connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called qt602240_ts. - config TOUCHSCREEN_MIGOR tristate "Renesas MIGO-R touchscreen" depends on SH_MIGOR && I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index e8dcfab7c2dc..756156409b83 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o +obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o @@ -37,7 +38,6 @@ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o -obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c new file mode 100644 index 000000000000..47067789b747 --- /dev/null +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -0,0 +1,1406 @@ +/* + * AT42QT602240/ATMXT224 Touchscreen driver + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Version */ +#define QT602240_VER_20 20 +#define QT602240_VER_21 21 +#define QT602240_VER_22 22 + +/* Slave addresses */ +#define QT602240_APP_LOW 0x4a +#define QT602240_APP_HIGH 0x4b +#define QT602240_BOOT_LOW 0x24 +#define QT602240_BOOT_HIGH 0x25 + +/* Firmware */ +#define QT602240_FW_NAME "qt602240.fw" + +/* Registers */ +#define QT602240_FAMILY_ID 0x00 +#define QT602240_VARIANT_ID 0x01 +#define QT602240_VERSION 0x02 +#define QT602240_BUILD 0x03 +#define QT602240_MATRIX_X_SIZE 0x04 +#define QT602240_MATRIX_Y_SIZE 0x05 +#define QT602240_OBJECT_NUM 0x06 +#define QT602240_OBJECT_START 0x07 + +#define QT602240_OBJECT_SIZE 6 + +/* Object types */ +#define QT602240_DEBUG_DIAGNOSTIC 37 +#define QT602240_GEN_MESSAGE 5 +#define QT602240_GEN_COMMAND 6 +#define QT602240_GEN_POWER 7 +#define QT602240_GEN_ACQUIRE 8 +#define QT602240_TOUCH_MULTI 9 +#define QT602240_TOUCH_KEYARRAY 15 +#define QT602240_TOUCH_PROXIMITY 23 +#define QT602240_PROCI_GRIPFACE 20 +#define QT602240_PROCG_NOISE 22 +#define QT602240_PROCI_ONETOUCH 24 +#define QT602240_PROCI_TWOTOUCH 27 +#define QT602240_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ +#define QT602240_SPT_GPIOPWM 19 +#define QT602240_SPT_SELFTEST 25 +#define QT602240_SPT_CTECONFIG 28 +#define QT602240_SPT_USERDATA 38 /* firmware ver 21 over */ + +/* QT602240_GEN_COMMAND field */ +#define QT602240_COMMAND_RESET 0 +#define QT602240_COMMAND_BACKUPNV 1 +#define QT602240_COMMAND_CALIBRATE 2 +#define QT602240_COMMAND_REPORTALL 3 +#define QT602240_COMMAND_DIAGNOSTIC 5 + +/* QT602240_GEN_POWER field */ +#define QT602240_POWER_IDLEACQINT 0 +#define QT602240_POWER_ACTVACQINT 1 +#define QT602240_POWER_ACTV2IDLETO 2 + +/* QT602240_GEN_ACQUIRE field */ +#define QT602240_ACQUIRE_CHRGTIME 0 +#define QT602240_ACQUIRE_TCHDRIFT 2 +#define QT602240_ACQUIRE_DRIFTST 3 +#define QT602240_ACQUIRE_TCHAUTOCAL 4 +#define QT602240_ACQUIRE_SYNC 5 +#define QT602240_ACQUIRE_ATCHCALST 6 +#define QT602240_ACQUIRE_ATCHCALSTHR 7 + +/* QT602240_TOUCH_MULTI field */ +#define QT602240_TOUCH_CTRL 0 +#define QT602240_TOUCH_XORIGIN 1 +#define QT602240_TOUCH_YORIGIN 2 +#define QT602240_TOUCH_XSIZE 3 +#define QT602240_TOUCH_YSIZE 4 +#define QT602240_TOUCH_BLEN 6 +#define QT602240_TOUCH_TCHTHR 7 +#define QT602240_TOUCH_TCHDI 8 +#define QT602240_TOUCH_ORIENT 9 +#define QT602240_TOUCH_MOVHYSTI 11 +#define QT602240_TOUCH_MOVHYSTN 12 +#define QT602240_TOUCH_NUMTOUCH 14 +#define QT602240_TOUCH_MRGHYST 15 +#define QT602240_TOUCH_MRGTHR 16 +#define QT602240_TOUCH_AMPHYST 17 +#define QT602240_TOUCH_XRANGE_LSB 18 +#define QT602240_TOUCH_XRANGE_MSB 19 +#define QT602240_TOUCH_YRANGE_LSB 20 +#define QT602240_TOUCH_YRANGE_MSB 21 +#define QT602240_TOUCH_XLOCLIP 22 +#define QT602240_TOUCH_XHICLIP 23 +#define QT602240_TOUCH_YLOCLIP 24 +#define QT602240_TOUCH_YHICLIP 25 +#define QT602240_TOUCH_XEDGECTRL 26 +#define QT602240_TOUCH_XEDGEDIST 27 +#define QT602240_TOUCH_YEDGECTRL 28 +#define QT602240_TOUCH_YEDGEDIST 29 +#define QT602240_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ + +/* QT602240_PROCI_GRIPFACE field */ +#define QT602240_GRIPFACE_CTRL 0 +#define QT602240_GRIPFACE_XLOGRIP 1 +#define QT602240_GRIPFACE_XHIGRIP 2 +#define QT602240_GRIPFACE_YLOGRIP 3 +#define QT602240_GRIPFACE_YHIGRIP 4 +#define QT602240_GRIPFACE_MAXTCHS 5 +#define QT602240_GRIPFACE_SZTHR1 7 +#define QT602240_GRIPFACE_SZTHR2 8 +#define QT602240_GRIPFACE_SHPTHR1 9 +#define QT602240_GRIPFACE_SHPTHR2 10 +#define QT602240_GRIPFACE_SUPEXTTO 11 + +/* QT602240_PROCI_NOISE field */ +#define QT602240_NOISE_CTRL 0 +#define QT602240_NOISE_OUTFLEN 1 +#define QT602240_NOISE_GCAFUL_LSB 3 +#define QT602240_NOISE_GCAFUL_MSB 4 +#define QT602240_NOISE_GCAFLL_LSB 5 +#define QT602240_NOISE_GCAFLL_MSB 6 +#define QT602240_NOISE_ACTVGCAFVALID 7 +#define QT602240_NOISE_NOISETHR 8 +#define QT602240_NOISE_FREQHOPSCALE 10 +#define QT602240_NOISE_FREQ0 11 +#define QT602240_NOISE_FREQ1 12 +#define QT602240_NOISE_FREQ2 13 +#define QT602240_NOISE_FREQ3 14 +#define QT602240_NOISE_FREQ4 15 +#define QT602240_NOISE_IDLEGCAFVALID 16 + +/* QT602240_SPT_COMMSCONFIG */ +#define QT602240_COMMS_CTRL 0 +#define QT602240_COMMS_CMD 1 + +/* QT602240_SPT_CTECONFIG field */ +#define QT602240_CTE_CTRL 0 +#define QT602240_CTE_CMD 1 +#define QT602240_CTE_MODE 2 +#define QT602240_CTE_IDLEGCAFDEPTH 3 +#define QT602240_CTE_ACTVGCAFDEPTH 4 +#define QT602240_CTE_VOLTAGE 5 /* firmware ver 21 over */ + +#define QT602240_VOLTAGE_DEFAULT 2700000 +#define QT602240_VOLTAGE_STEP 10000 + +/* Define for QT602240_GEN_COMMAND */ +#define QT602240_BOOT_VALUE 0xa5 +#define QT602240_BACKUP_VALUE 0x55 +#define QT602240_BACKUP_TIME 25 /* msec */ +#define QT602240_RESET_TIME 65 /* msec */ + +#define QT602240_FWRESET_TIME 175 /* msec */ + +/* Command to unlock bootloader */ +#define QT602240_UNLOCK_CMD_MSB 0xaa +#define QT602240_UNLOCK_CMD_LSB 0xdc + +/* Bootloader mode status */ +#define QT602240_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ +#define QT602240_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ +#define QT602240_FRAME_CRC_CHECK 0x02 +#define QT602240_FRAME_CRC_FAIL 0x03 +#define QT602240_FRAME_CRC_PASS 0x04 +#define QT602240_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ +#define QT602240_BOOT_STATUS_MASK 0x3f + +/* Touch status */ +#define QT602240_SUPPRESS (1 << 1) +#define QT602240_AMP (1 << 2) +#define QT602240_VECTOR (1 << 3) +#define QT602240_MOVE (1 << 4) +#define QT602240_RELEASE (1 << 5) +#define QT602240_PRESS (1 << 6) +#define QT602240_DETECT (1 << 7) + +/* Touchscreen absolute values */ +#define QT602240_MAX_XC 0x3ff +#define QT602240_MAX_YC 0x3ff +#define QT602240_MAX_AREA 0xff + +#define QT602240_MAX_FINGER 10 + +/* Initial register values recommended from chip vendor */ +static const u8 init_vals_ver_20[] = { + /* QT602240_GEN_COMMAND(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_GEN_POWER(7) */ + 0x20, 0xff, 0x32, + /* QT602240_GEN_ACQUIRE(8) */ + 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, + /* QT602240_TOUCH_MULTI(9) */ + 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, + /* QT602240_TOUCH_KEYARRAY(15) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_SPT_GPIOPWM(19) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + /* QT602240_PROCI_GRIPFACE(20) */ + 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, + 0x1e, 0x00, + /* QT602240_PROCG_NOISE(22) */ + 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, + 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, + /* QT602240_TOUCH_PROXIMITY(23) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* QT602240_PROCI_ONETOUCH(24) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_SELFTEST(25) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_TWOTOUCH(27) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_CTECONFIG(28) */ + 0x00, 0x00, 0x00, 0x04, 0x08, +}; + +static const u8 init_vals_ver_21[] = { + /* QT602240_GEN_COMMAND(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_GEN_POWER(7) */ + 0x20, 0xff, 0x32, + /* QT602240_GEN_ACQUIRE(8) */ + 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, + /* QT602240_TOUCH_MULTI(9) */ + 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_TOUCH_KEYARRAY(15) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_SPT_GPIOPWM(19) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_GRIPFACE(20) */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, + 0x0f, 0x0a, + /* QT602240_PROCG_NOISE(22) */ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, + 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, + /* QT602240_TOUCH_PROXIMITY(23) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + /* QT602240_PROCI_ONETOUCH(24) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_SELFTEST(25) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_TWOTOUCH(27) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_CTECONFIG(28) */ + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, +}; + +static const u8 init_vals_ver_22[] = { + /* QT602240_GEN_COMMAND(6) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_GEN_POWER(7) */ + 0x20, 0xff, 0x32, + /* QT602240_GEN_ACQUIRE(8) */ + 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, + /* QT602240_TOUCH_MULTI(9) */ + 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_TOUCH_KEYARRAY(15) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + /* QT602240_SPT_GPIOPWM(19) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_GRIPFACE(20) */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, + 0x0f, 0x0a, + /* QT602240_PROCG_NOISE(22) */ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, + 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, + /* QT602240_TOUCH_PROXIMITY(23) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_ONETOUCH(24) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_SELFTEST(25) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + /* QT602240_PROCI_TWOTOUCH(27) */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* QT602240_SPT_CTECONFIG(28) */ + 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, +}; + +struct qt602240_info { + u8 family_id; + u8 variant_id; + u8 version; + u8 build; + u8 matrix_xsize; + u8 matrix_ysize; + u8 object_num; +}; + +struct qt602240_object { + u8 type; + u16 start_address; + u8 size; + u8 instances; + u8 num_report_ids; + + /* to map object and message */ + u8 max_reportid; +}; + +struct qt602240_message { + u8 reportid; + u8 message[7]; + u8 checksum; +}; + +struct qt602240_finger { + int status; + int x; + int y; + int area; +}; + +/* Each client has this additional data */ +struct qt602240_data { + struct i2c_client *client; + struct input_dev *input_dev; + const struct qt602240_platform_data *pdata; + struct qt602240_object *object_table; + struct qt602240_info info; + struct qt602240_finger finger[QT602240_MAX_FINGER]; + unsigned int irq; +}; + +static bool qt602240_object_readable(unsigned int type) +{ + switch (type) { + case QT602240_GEN_MESSAGE: + case QT602240_GEN_COMMAND: + case QT602240_GEN_POWER: + case QT602240_GEN_ACQUIRE: + case QT602240_TOUCH_MULTI: + case QT602240_TOUCH_KEYARRAY: + case QT602240_TOUCH_PROXIMITY: + case QT602240_PROCI_GRIPFACE: + case QT602240_PROCG_NOISE: + case QT602240_PROCI_ONETOUCH: + case QT602240_PROCI_TWOTOUCH: + case QT602240_SPT_COMMSCONFIG: + case QT602240_SPT_GPIOPWM: + case QT602240_SPT_SELFTEST: + case QT602240_SPT_CTECONFIG: + case QT602240_SPT_USERDATA: + return true; + default: + return false; + } +} + +static bool qt602240_object_writable(unsigned int type) +{ + switch (type) { + case QT602240_GEN_COMMAND: + case QT602240_GEN_POWER: + case QT602240_GEN_ACQUIRE: + case QT602240_TOUCH_MULTI: + case QT602240_TOUCH_KEYARRAY: + case QT602240_TOUCH_PROXIMITY: + case QT602240_PROCI_GRIPFACE: + case QT602240_PROCG_NOISE: + case QT602240_PROCI_ONETOUCH: + case QT602240_PROCI_TWOTOUCH: + case QT602240_SPT_GPIOPWM: + case QT602240_SPT_SELFTEST: + case QT602240_SPT_CTECONFIG: + return true; + default: + return false; + } +} + +static void qt602240_dump_message(struct device *dev, + struct qt602240_message *message) +{ + dev_dbg(dev, "reportid:\t0x%x\n", message->reportid); + dev_dbg(dev, "message1:\t0x%x\n", message->message[0]); + dev_dbg(dev, "message2:\t0x%x\n", message->message[1]); + dev_dbg(dev, "message3:\t0x%x\n", message->message[2]); + dev_dbg(dev, "message4:\t0x%x\n", message->message[3]); + dev_dbg(dev, "message5:\t0x%x\n", message->message[4]); + dev_dbg(dev, "message6:\t0x%x\n", message->message[5]); + dev_dbg(dev, "message7:\t0x%x\n", message->message[6]); + dev_dbg(dev, "checksum:\t0x%x\n", message->checksum); +} + +static int qt602240_check_bootloader(struct i2c_client *client, + unsigned int state) +{ + u8 val; + +recheck: + if (i2c_master_recv(client, &val, 1) != 1) { + dev_err(&client->dev, "%s: i2c recv failed\n", __func__); + return -EIO; + } + + switch (state) { + case QT602240_WAITING_BOOTLOAD_CMD: + case QT602240_WAITING_FRAME_DATA: + val &= ~QT602240_BOOT_STATUS_MASK; + break; + case QT602240_FRAME_CRC_PASS: + if (val == QT602240_FRAME_CRC_CHECK) + goto recheck; + break; + default: + return -EINVAL; + } + + if (val != state) { + dev_err(&client->dev, "Unvalid bootloader mode state\n"); + return -EINVAL; + } + + return 0; +} + +static int qt602240_unlock_bootloader(struct i2c_client *client) +{ + u8 buf[2]; + + buf[0] = QT602240_UNLOCK_CMD_LSB; + buf[1] = QT602240_UNLOCK_CMD_MSB; + + if (i2c_master_send(client, buf, 2) != 2) { + dev_err(&client->dev, "%s: i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int qt602240_fw_write(struct i2c_client *client, + const u8 *data, unsigned int frame_size) +{ + if (i2c_master_send(client, data, frame_size) != frame_size) { + dev_err(&client->dev, "%s: i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int __qt602240_read_reg(struct i2c_client *client, + u16 reg, u16 len, void *val) +{ + struct i2c_msg xfer[2]; + u8 buf[2]; + + buf[0] = reg & 0xff; + buf[1] = (reg >> 8) & 0xff; + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 2; + xfer[0].buf = buf; + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = len; + xfer[1].buf = val; + + if (i2c_transfer(client->adapter, xfer, 2) != 2) { + dev_err(&client->dev, "%s: i2c transfer failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val) +{ + return __qt602240_read_reg(client, reg, 1, val); +} + +static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) +{ + u8 buf[3]; + + buf[0] = reg & 0xff; + buf[1] = (reg >> 8) & 0xff; + buf[2] = val; + + if (i2c_master_send(client, buf, 3) != 3) { + dev_err(&client->dev, "%s: i2c send failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int qt602240_read_object_table(struct i2c_client *client, + u16 reg, u8 *object_buf) +{ + return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE, + object_buf); +} + +static struct qt602240_object * +qt602240_get_object(struct qt602240_data *data, u8 type) +{ + struct qt602240_object *object; + int i; + + for (i = 0; i < data->info.object_num; i++) { + object = data->object_table + i; + if (object->type == type) + return object; + } + + dev_err(&data->client->dev, "Invalid object type\n"); + return NULL; +} + +static int qt602240_read_message(struct qt602240_data *data, + struct qt602240_message *message) +{ + struct qt602240_object *object; + u16 reg; + + object = qt602240_get_object(data, QT602240_GEN_MESSAGE); + if (!object) + return -EINVAL; + + reg = object->start_address; + return __qt602240_read_reg(data->client, reg, + sizeof(struct qt602240_message), message); +} + +static int qt602240_read_object(struct qt602240_data *data, + u8 type, u8 offset, u8 *val) +{ + struct qt602240_object *object; + u16 reg; + + object = qt602240_get_object(data, type); + if (!object) + return -EINVAL; + + reg = object->start_address; + return __qt602240_read_reg(data->client, reg + offset, 1, val); +} + +static int qt602240_write_object(struct qt602240_data *data, + u8 type, u8 offset, u8 val) +{ + struct qt602240_object *object; + u16 reg; + + object = qt602240_get_object(data, type); + if (!object) + return -EINVAL; + + reg = object->start_address; + return qt602240_write_reg(data->client, reg + offset, val); +} + +static void qt602240_input_report(struct qt602240_data *data, int single_id) +{ + struct qt602240_finger *finger = data->finger; + struct input_dev *input_dev = data->input_dev; + int status = finger[single_id].status; + int finger_num = 0; + int id; + + for (id = 0; id < QT602240_MAX_FINGER; id++) { + if (!finger[id].status) + continue; + + input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, + finger[id].status != QT602240_RELEASE ? + finger[id].area : 0); + input_report_abs(input_dev, ABS_MT_POSITION_X, + finger[id].x); + input_report_abs(input_dev, ABS_MT_POSITION_Y, + finger[id].y); + input_mt_sync(input_dev); + + if (finger[id].status == QT602240_RELEASE) + finger[id].status = 0; + else + finger_num++; + } + + input_report_key(input_dev, BTN_TOUCH, finger_num > 0); + + if (status != QT602240_RELEASE) { + input_report_abs(input_dev, ABS_X, finger[single_id].x); + input_report_abs(input_dev, ABS_Y, finger[single_id].y); + } + + input_sync(input_dev); +} + +static void qt602240_input_touchevent(struct qt602240_data *data, + struct qt602240_message *message, int id) +{ + struct qt602240_finger *finger = data->finger; + struct device *dev = &data->client->dev; + u8 status = message->message[0]; + int x; + int y; + int area; + + /* Check the touch is present on the screen */ + if (!(status & QT602240_DETECT)) { + if (status & QT602240_RELEASE) { + dev_dbg(dev, "[%d] released\n", id); + + finger[id].status = QT602240_RELEASE; + qt602240_input_report(data, id); + } + return; + } + + /* Check only AMP detection */ + if (!(status & (QT602240_PRESS | QT602240_MOVE))) + return; + + x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6); + y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2); + area = message->message[4]; + + dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, + status & QT602240_MOVE ? "moved" : "pressed", + x, y, area); + + finger[id].status = status & QT602240_MOVE ? + QT602240_MOVE : QT602240_PRESS; + finger[id].x = x; + finger[id].y = y; + finger[id].area = area; + + qt602240_input_report(data, id); +} + +static irqreturn_t qt602240_interrupt(int irq, void *dev_id) +{ + struct qt602240_data *data = dev_id; + struct qt602240_message message; + struct qt602240_object *object; + struct device *dev = &data->client->dev; + int id; + u8 reportid; + u8 max_reportid; + u8 min_reportid; + + do { + if (qt602240_read_message(data, &message)) { + dev_err(dev, "Failed to read message\n"); + goto end; + } + + reportid = message.reportid; + + /* whether reportid is thing of QT602240_TOUCH_MULTI */ + object = qt602240_get_object(data, QT602240_TOUCH_MULTI); + if (!object) + goto end; + + max_reportid = object->max_reportid; + min_reportid = max_reportid - object->num_report_ids + 1; + id = reportid - min_reportid; + + if (reportid >= min_reportid && reportid <= max_reportid) + qt602240_input_touchevent(data, &message, id); + else + qt602240_dump_message(dev, &message); + } while (reportid != 0xff); + +end: + return IRQ_HANDLED; +} + +static int qt602240_check_reg_init(struct qt602240_data *data) +{ + struct qt602240_object *object; + struct device *dev = &data->client->dev; + int index = 0; + int i, j; + u8 version = data->info.version; + u8 *init_vals; + + switch (version) { + case QT602240_VER_20: + init_vals = (u8 *)init_vals_ver_20; + break; + case QT602240_VER_21: + init_vals = (u8 *)init_vals_ver_21; + break; + case QT602240_VER_22: + init_vals = (u8 *)init_vals_ver_22; + break; + default: + dev_err(dev, "Firmware version %d doesn't support\n", version); + return -EINVAL; + } + + for (i = 0; i < data->info.object_num; i++) { + object = data->object_table + i; + + if (!qt602240_object_writable(object->type)) + continue; + + for (j = 0; j < object->size + 1; j++) + qt602240_write_object(data, object->type, j, + init_vals[index + j]); + + index += object->size + 1; + } + + return 0; +} + +static int qt602240_check_matrix_size(struct qt602240_data *data) +{ + const struct qt602240_platform_data *pdata = data->pdata; + struct device *dev = &data->client->dev; + int mode = -1; + int error; + u8 val; + + dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line); + dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line); + + switch (pdata->x_line) { + case 0 ... 15: + if (pdata->y_line <= 14) + mode = 0; + break; + case 16: + if (pdata->y_line <= 12) + mode = 1; + if (pdata->y_line == 13 || pdata->y_line == 14) + mode = 0; + break; + case 17: + if (pdata->y_line <= 11) + mode = 2; + if (pdata->y_line == 12 || pdata->y_line == 13) + mode = 1; + break; + case 18: + if (pdata->y_line <= 10) + mode = 3; + if (pdata->y_line == 11 || pdata->y_line == 12) + mode = 2; + break; + case 19: + if (pdata->y_line <= 9) + mode = 4; + if (pdata->y_line == 10 || pdata->y_line == 11) + mode = 3; + break; + case 20: + mode = 4; + } + + if (mode < 0) { + dev_err(dev, "Invalid X/Y lines\n"); + return -EINVAL; + } + + error = qt602240_read_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_MODE, &val); + if (error) + return error; + + if (mode == val) + return 0; + + /* Change the CTE configuration */ + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_CTRL, 1); + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_MODE, mode); + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_CTRL, 0); + + return 0; +} + +static int qt602240_make_highchg(struct qt602240_data *data) +{ + struct device *dev = &data->client->dev; + int count = 10; + int error; + u8 val; + + /* Read dummy message to make high CHG pin */ + do { + error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val); + if (error) + return error; + } while ((val != 0xff) && --count); + + if (!count) { + dev_err(dev, "CHG pin isn't cleared\n"); + return -EBUSY; + } + + return 0; +} + +static void qt602240_handle_pdata(struct qt602240_data *data) +{ + const struct qt602240_platform_data *pdata = data->pdata; + u8 voltage; + + /* Set touchscreen lines */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE, + pdata->x_line); + qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE, + pdata->y_line); + + /* Set touchscreen orient */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT, + pdata->orient); + + /* Set touchscreen burst length */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_BLEN, pdata->blen); + + /* Set touchscreen threshold */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_TCHTHR, pdata->threshold); + + /* Set touchscreen resolution */ + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); + qt602240_write_object(data, QT602240_TOUCH_MULTI, + QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); + + /* Set touchscreen voltage */ + if (data->info.version >= QT602240_VER_21 && pdata->voltage) { + if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) { + voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) / + QT602240_VOLTAGE_STEP; + voltage = 0xff - voltage + 1; + } else + voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) / + QT602240_VOLTAGE_STEP; + + qt602240_write_object(data, QT602240_SPT_CTECONFIG, + QT602240_CTE_VOLTAGE, voltage); + } +} + +static int qt602240_get_info(struct qt602240_data *data) +{ + struct i2c_client *client = data->client; + struct qt602240_info *info = &data->info; + int error; + u8 val; + + error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val); + if (error) + return error; + info->family_id = val; + + error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val); + if (error) + return error; + info->variant_id = val; + + error = qt602240_read_reg(client, QT602240_VERSION, &val); + if (error) + return error; + info->version = val; + + error = qt602240_read_reg(client, QT602240_BUILD, &val); + if (error) + return error; + info->build = val; + + error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val); + if (error) + return error; + info->object_num = val; + + return 0; +} + +static int qt602240_get_object_table(struct qt602240_data *data) +{ + int error; + int i; + u16 reg; + u8 reportid = 0; + u8 buf[QT602240_OBJECT_SIZE]; + + for (i = 0; i < data->info.object_num; i++) { + struct qt602240_object *object = data->object_table + i; + + reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i; + error = qt602240_read_object_table(data->client, reg, buf); + if (error) + return error; + + object->type = buf[0]; + object->start_address = (buf[2] << 8) | buf[1]; + object->size = buf[3]; + object->instances = buf[4]; + object->num_report_ids = buf[5]; + + if (object->num_report_ids) { + reportid += object->num_report_ids * + (object->instances + 1); + object->max_reportid = reportid; + } + } + + return 0; +} + +static int qt602240_initialize(struct qt602240_data *data) +{ + struct i2c_client *client = data->client; + struct qt602240_info *info = &data->info; + int error; + u8 val; + + error = qt602240_get_info(data); + if (error) + return error; + + data->object_table = kcalloc(info->object_num, + sizeof(struct qt602240_object), + GFP_KERNEL); + if (!data->object_table) { + dev_err(&client->dev, "Failed to allocate memory\n"); + return -ENOMEM; + } + + /* Get object table information */ + error = qt602240_get_object_table(data); + if (error) + return error; + + /* Check register init values */ + error = qt602240_check_reg_init(data); + if (error) + return error; + + /* Check X/Y matrix size */ + error = qt602240_check_matrix_size(data); + if (error) + return error; + + error = qt602240_make_highchg(data); + if (error) + return error; + + qt602240_handle_pdata(data); + + /* Backup to memory */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_BACKUPNV, + QT602240_BACKUP_VALUE); + msleep(QT602240_BACKUP_TIME); + + /* Soft reset */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_RESET, 1); + msleep(QT602240_RESET_TIME); + + /* Update matrix size at info struct */ + error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val); + if (error) + return error; + info->matrix_xsize = val; + + error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val); + if (error) + return error; + info->matrix_ysize = val; + + dev_info(&client->dev, + "Family ID: %d Variant ID: %d Version: %d Build: %d\n", + info->family_id, info->variant_id, info->version, + info->build); + + dev_info(&client->dev, + "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n", + info->matrix_xsize, info->matrix_ysize, + info->object_num); + + return 0; +} + +static ssize_t qt602240_object_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qt602240_data *data = dev_get_drvdata(dev); + struct qt602240_object *object; + int count = 0; + int i, j; + int error; + u8 val; + + for (i = 0; i < data->info.object_num; i++) { + object = data->object_table + i; + + count += sprintf(buf + count, + "Object Table Element %d(Type %d)\n", + i + 1, object->type); + + if (!qt602240_object_readable(object->type)) { + count += sprintf(buf + count, "\n"); + continue; + } + + for (j = 0; j < object->size + 1; j++) { + error = qt602240_read_object(data, + object->type, j, &val); + if (error) + return error; + + count += sprintf(buf + count, + " Byte %d: 0x%x (%d)\n", j, val, val); + } + + count += sprintf(buf + count, "\n"); + } + + return count; +} + +static int qt602240_load_fw(struct device *dev, const char *fn) +{ + struct qt602240_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + const struct firmware *fw = NULL; + unsigned int frame_size; + unsigned int pos = 0; + int ret; + + ret = request_firmware(&fw, fn, dev); + if (ret) { + dev_err(dev, "Unable to open firmware %s\n", fn); + return ret; + } + + /* Change to the bootloader mode */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_RESET, QT602240_BOOT_VALUE); + msleep(QT602240_RESET_TIME); + + /* Change to slave address of bootloader */ + if (client->addr == QT602240_APP_LOW) + client->addr = QT602240_BOOT_LOW; + else + client->addr = QT602240_BOOT_HIGH; + + ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD); + if (ret) + goto out; + + /* Unlock bootloader */ + qt602240_unlock_bootloader(client); + + while (pos < fw->size) { + ret = qt602240_check_bootloader(client, + QT602240_WAITING_FRAME_DATA); + if (ret) + goto out; + + frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); + + /* We should add 2 at frame size as the the firmware data is not + * included the CRC bytes. + */ + frame_size += 2; + + /* Write one frame to device */ + qt602240_fw_write(client, fw->data + pos, frame_size); + + ret = qt602240_check_bootloader(client, + QT602240_FRAME_CRC_PASS); + if (ret) + goto out; + + pos += frame_size; + + dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size); + } + +out: + release_firmware(fw); + + /* Change to slave address of application */ + if (client->addr == QT602240_BOOT_LOW) + client->addr = QT602240_APP_LOW; + else + client->addr = QT602240_APP_HIGH; + + return ret; +} + +static ssize_t qt602240_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qt602240_data *data = dev_get_drvdata(dev); + unsigned int version; + int error; + + if (sscanf(buf, "%u", &version) != 1) { + dev_err(dev, "Invalid values\n"); + return -EINVAL; + } + + if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) { + dev_err(dev, "FW update supported starting with version 21\n"); + return -EINVAL; + } + + disable_irq(data->irq); + + error = qt602240_load_fw(dev, QT602240_FW_NAME); + if (error) { + dev_err(dev, "The firmware update failed(%d)\n", error); + count = error; + } else { + dev_dbg(dev, "The firmware update succeeded\n"); + + /* Wait for reset */ + msleep(QT602240_FWRESET_TIME); + + kfree(data->object_table); + data->object_table = NULL; + + qt602240_initialize(data); + } + + enable_irq(data->irq); + + return count; +} + +static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL); +static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store); + +static struct attribute *qt602240_attrs[] = { + &dev_attr_object.attr, + &dev_attr_update_fw.attr, + NULL +}; + +static const struct attribute_group qt602240_attr_group = { + .attrs = qt602240_attrs, +}; + +static void qt602240_start(struct qt602240_data *data) +{ + /* Touch enable */ + qt602240_write_object(data, + QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83); +} + +static void qt602240_stop(struct qt602240_data *data) +{ + /* Touch disable */ + qt602240_write_object(data, + QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0); +} + +static int qt602240_input_open(struct input_dev *dev) +{ + struct qt602240_data *data = input_get_drvdata(dev); + + qt602240_start(data); + + return 0; +} + +static void qt602240_input_close(struct input_dev *dev) +{ + struct qt602240_data *data = input_get_drvdata(dev); + + qt602240_stop(data); +} + +static int __devinit qt602240_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct qt602240_data *data; + struct input_dev *input_dev; + int error; + + if (!client->dev.platform_data) + return -EINVAL; + + data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!data || !input_dev) { + dev_err(&client->dev, "Failed to allocate memory\n"); + error = -ENOMEM; + goto err_free_mem; + } + + input_dev->name = "AT42QT602240/ATMXT224 Touchscreen"; + input_dev->id.bustype = BUS_I2C; + input_dev->dev.parent = &client->dev; + input_dev->open = qt602240_input_open; + input_dev->close = qt602240_input_close; + + __set_bit(EV_ABS, input_dev->evbit); + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOUCH, input_dev->keybit); + + /* For single touch */ + input_set_abs_params(input_dev, ABS_X, + 0, QT602240_MAX_XC, 0, 0); + input_set_abs_params(input_dev, ABS_Y, + 0, QT602240_MAX_YC, 0, 0); + + /* For multi touch */ + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, + 0, QT602240_MAX_AREA, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, QT602240_MAX_XC, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, QT602240_MAX_YC, 0, 0); + + input_set_drvdata(input_dev, data); + + data->client = client; + data->input_dev = input_dev; + data->pdata = client->dev.platform_data; + data->irq = client->irq; + + i2c_set_clientdata(client, data); + + error = qt602240_initialize(data); + if (error) + goto err_free_object; + + error = request_threaded_irq(client->irq, NULL, qt602240_interrupt, + IRQF_TRIGGER_FALLING, client->dev.driver->name, data); + if (error) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_free_object; + } + + error = input_register_device(input_dev); + if (error) + goto err_free_irq; + + error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group); + if (error) + goto err_unregister_device; + + return 0; + +err_unregister_device: + input_unregister_device(input_dev); + input_dev = NULL; +err_free_irq: + free_irq(client->irq, data); +err_free_object: + kfree(data->object_table); +err_free_mem: + input_free_device(input_dev); + kfree(data); + return error; +} + +static int __devexit qt602240_remove(struct i2c_client *client) +{ + struct qt602240_data *data = i2c_get_clientdata(client); + + sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group); + free_irq(data->irq, data); + input_unregister_device(data->input_dev); + kfree(data->object_table); + kfree(data); + + return 0; +} + +#ifdef CONFIG_PM +static int qt602240_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qt602240_data *data = i2c_get_clientdata(client); + struct input_dev *input_dev = data->input_dev; + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + qt602240_stop(data); + + mutex_unlock(&input_dev->mutex); + + return 0; +} + +static int qt602240_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qt602240_data *data = i2c_get_clientdata(client); + struct input_dev *input_dev = data->input_dev; + + /* Soft reset */ + qt602240_write_object(data, QT602240_GEN_COMMAND, + QT602240_COMMAND_RESET, 1); + + msleep(QT602240_RESET_TIME); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + qt602240_start(data); + + mutex_unlock(&input_dev->mutex); + + return 0; +} + +static const struct dev_pm_ops qt602240_pm_ops = { + .suspend = qt602240_suspend, + .resume = qt602240_resume, +}; +#endif + +static const struct i2c_device_id qt602240_id[] = { + { "qt602240_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, qt602240_id); + +static struct i2c_driver qt602240_driver = { + .driver = { + .name = "qt602240_ts", + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &qt602240_pm_ops, +#endif + }, + .probe = qt602240_probe, + .remove = __devexit_p(qt602240_remove), + .id_table = qt602240_id, +}; + +static int __init qt602240_init(void) +{ + return i2c_add_driver(&qt602240_driver); +} + +static void __exit qt602240_exit(void) +{ + i2c_del_driver(&qt602240_driver); +} + +module_init(qt602240_init); +module_exit(qt602240_exit); + +/* Module information */ +MODULE_AUTHOR("Joonyoung Shim "); +MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/qt602240_ts.c b/drivers/input/touchscreen/qt602240_ts.c deleted file mode 100644 index 4dcb0e872f6a..000000000000 --- a/drivers/input/touchscreen/qt602240_ts.c +++ /dev/null @@ -1,1406 +0,0 @@ -/* - * AT42QT602240/ATMXT224 Touchscreen driver - * - * Copyright (C) 2010 Samsung Electronics Co.Ltd - * Author: Joonyoung Shim - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Version */ -#define QT602240_VER_20 20 -#define QT602240_VER_21 21 -#define QT602240_VER_22 22 - -/* Slave addresses */ -#define QT602240_APP_LOW 0x4a -#define QT602240_APP_HIGH 0x4b -#define QT602240_BOOT_LOW 0x24 -#define QT602240_BOOT_HIGH 0x25 - -/* Firmware */ -#define QT602240_FW_NAME "qt602240.fw" - -/* Registers */ -#define QT602240_FAMILY_ID 0x00 -#define QT602240_VARIANT_ID 0x01 -#define QT602240_VERSION 0x02 -#define QT602240_BUILD 0x03 -#define QT602240_MATRIX_X_SIZE 0x04 -#define QT602240_MATRIX_Y_SIZE 0x05 -#define QT602240_OBJECT_NUM 0x06 -#define QT602240_OBJECT_START 0x07 - -#define QT602240_OBJECT_SIZE 6 - -/* Object types */ -#define QT602240_DEBUG_DIAGNOSTIC 37 -#define QT602240_GEN_MESSAGE 5 -#define QT602240_GEN_COMMAND 6 -#define QT602240_GEN_POWER 7 -#define QT602240_GEN_ACQUIRE 8 -#define QT602240_TOUCH_MULTI 9 -#define QT602240_TOUCH_KEYARRAY 15 -#define QT602240_TOUCH_PROXIMITY 23 -#define QT602240_PROCI_GRIPFACE 20 -#define QT602240_PROCG_NOISE 22 -#define QT602240_PROCI_ONETOUCH 24 -#define QT602240_PROCI_TWOTOUCH 27 -#define QT602240_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ -#define QT602240_SPT_GPIOPWM 19 -#define QT602240_SPT_SELFTEST 25 -#define QT602240_SPT_CTECONFIG 28 -#define QT602240_SPT_USERDATA 38 /* firmware ver 21 over */ - -/* QT602240_GEN_COMMAND field */ -#define QT602240_COMMAND_RESET 0 -#define QT602240_COMMAND_BACKUPNV 1 -#define QT602240_COMMAND_CALIBRATE 2 -#define QT602240_COMMAND_REPORTALL 3 -#define QT602240_COMMAND_DIAGNOSTIC 5 - -/* QT602240_GEN_POWER field */ -#define QT602240_POWER_IDLEACQINT 0 -#define QT602240_POWER_ACTVACQINT 1 -#define QT602240_POWER_ACTV2IDLETO 2 - -/* QT602240_GEN_ACQUIRE field */ -#define QT602240_ACQUIRE_CHRGTIME 0 -#define QT602240_ACQUIRE_TCHDRIFT 2 -#define QT602240_ACQUIRE_DRIFTST 3 -#define QT602240_ACQUIRE_TCHAUTOCAL 4 -#define QT602240_ACQUIRE_SYNC 5 -#define QT602240_ACQUIRE_ATCHCALST 6 -#define QT602240_ACQUIRE_ATCHCALSTHR 7 - -/* QT602240_TOUCH_MULTI field */ -#define QT602240_TOUCH_CTRL 0 -#define QT602240_TOUCH_XORIGIN 1 -#define QT602240_TOUCH_YORIGIN 2 -#define QT602240_TOUCH_XSIZE 3 -#define QT602240_TOUCH_YSIZE 4 -#define QT602240_TOUCH_BLEN 6 -#define QT602240_TOUCH_TCHTHR 7 -#define QT602240_TOUCH_TCHDI 8 -#define QT602240_TOUCH_ORIENT 9 -#define QT602240_TOUCH_MOVHYSTI 11 -#define QT602240_TOUCH_MOVHYSTN 12 -#define QT602240_TOUCH_NUMTOUCH 14 -#define QT602240_TOUCH_MRGHYST 15 -#define QT602240_TOUCH_MRGTHR 16 -#define QT602240_TOUCH_AMPHYST 17 -#define QT602240_TOUCH_XRANGE_LSB 18 -#define QT602240_TOUCH_XRANGE_MSB 19 -#define QT602240_TOUCH_YRANGE_LSB 20 -#define QT602240_TOUCH_YRANGE_MSB 21 -#define QT602240_TOUCH_XLOCLIP 22 -#define QT602240_TOUCH_XHICLIP 23 -#define QT602240_TOUCH_YLOCLIP 24 -#define QT602240_TOUCH_YHICLIP 25 -#define QT602240_TOUCH_XEDGECTRL 26 -#define QT602240_TOUCH_XEDGEDIST 27 -#define QT602240_TOUCH_YEDGECTRL 28 -#define QT602240_TOUCH_YEDGEDIST 29 -#define QT602240_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ - -/* QT602240_PROCI_GRIPFACE field */ -#define QT602240_GRIPFACE_CTRL 0 -#define QT602240_GRIPFACE_XLOGRIP 1 -#define QT602240_GRIPFACE_XHIGRIP 2 -#define QT602240_GRIPFACE_YLOGRIP 3 -#define QT602240_GRIPFACE_YHIGRIP 4 -#define QT602240_GRIPFACE_MAXTCHS 5 -#define QT602240_GRIPFACE_SZTHR1 7 -#define QT602240_GRIPFACE_SZTHR2 8 -#define QT602240_GRIPFACE_SHPTHR1 9 -#define QT602240_GRIPFACE_SHPTHR2 10 -#define QT602240_GRIPFACE_SUPEXTTO 11 - -/* QT602240_PROCI_NOISE field */ -#define QT602240_NOISE_CTRL 0 -#define QT602240_NOISE_OUTFLEN 1 -#define QT602240_NOISE_GCAFUL_LSB 3 -#define QT602240_NOISE_GCAFUL_MSB 4 -#define QT602240_NOISE_GCAFLL_LSB 5 -#define QT602240_NOISE_GCAFLL_MSB 6 -#define QT602240_NOISE_ACTVGCAFVALID 7 -#define QT602240_NOISE_NOISETHR 8 -#define QT602240_NOISE_FREQHOPSCALE 10 -#define QT602240_NOISE_FREQ0 11 -#define QT602240_NOISE_FREQ1 12 -#define QT602240_NOISE_FREQ2 13 -#define QT602240_NOISE_FREQ3 14 -#define QT602240_NOISE_FREQ4 15 -#define QT602240_NOISE_IDLEGCAFVALID 16 - -/* QT602240_SPT_COMMSCONFIG */ -#define QT602240_COMMS_CTRL 0 -#define QT602240_COMMS_CMD 1 - -/* QT602240_SPT_CTECONFIG field */ -#define QT602240_CTE_CTRL 0 -#define QT602240_CTE_CMD 1 -#define QT602240_CTE_MODE 2 -#define QT602240_CTE_IDLEGCAFDEPTH 3 -#define QT602240_CTE_ACTVGCAFDEPTH 4 -#define QT602240_CTE_VOLTAGE 5 /* firmware ver 21 over */ - -#define QT602240_VOLTAGE_DEFAULT 2700000 -#define QT602240_VOLTAGE_STEP 10000 - -/* Define for QT602240_GEN_COMMAND */ -#define QT602240_BOOT_VALUE 0xa5 -#define QT602240_BACKUP_VALUE 0x55 -#define QT602240_BACKUP_TIME 25 /* msec */ -#define QT602240_RESET_TIME 65 /* msec */ - -#define QT602240_FWRESET_TIME 175 /* msec */ - -/* Command to unlock bootloader */ -#define QT602240_UNLOCK_CMD_MSB 0xaa -#define QT602240_UNLOCK_CMD_LSB 0xdc - -/* Bootloader mode status */ -#define QT602240_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ -#define QT602240_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ -#define QT602240_FRAME_CRC_CHECK 0x02 -#define QT602240_FRAME_CRC_FAIL 0x03 -#define QT602240_FRAME_CRC_PASS 0x04 -#define QT602240_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ -#define QT602240_BOOT_STATUS_MASK 0x3f - -/* Touch status */ -#define QT602240_SUPPRESS (1 << 1) -#define QT602240_AMP (1 << 2) -#define QT602240_VECTOR (1 << 3) -#define QT602240_MOVE (1 << 4) -#define QT602240_RELEASE (1 << 5) -#define QT602240_PRESS (1 << 6) -#define QT602240_DETECT (1 << 7) - -/* Touchscreen absolute values */ -#define QT602240_MAX_XC 0x3ff -#define QT602240_MAX_YC 0x3ff -#define QT602240_MAX_AREA 0xff - -#define QT602240_MAX_FINGER 10 - -/* Initial register values recommended from chip vendor */ -static const u8 init_vals_ver_20[] = { - /* QT602240_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ - 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, - /* QT602240_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, - /* QT602240_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ - 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, - 0x1e, 0x00, - /* QT602240_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, - 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, - /* QT602240_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x04, 0x08, -}; - -static const u8 init_vals_ver_21[] = { - /* QT602240_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - -static const u8 init_vals_ver_22[] = { - /* QT602240_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* QT602240_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - -struct qt602240_info { - u8 family_id; - u8 variant_id; - u8 version; - u8 build; - u8 matrix_xsize; - u8 matrix_ysize; - u8 object_num; -}; - -struct qt602240_object { - u8 type; - u16 start_address; - u8 size; - u8 instances; - u8 num_report_ids; - - /* to map object and message */ - u8 max_reportid; -}; - -struct qt602240_message { - u8 reportid; - u8 message[7]; - u8 checksum; -}; - -struct qt602240_finger { - int status; - int x; - int y; - int area; -}; - -/* Each client has this additional data */ -struct qt602240_data { - struct i2c_client *client; - struct input_dev *input_dev; - const struct qt602240_platform_data *pdata; - struct qt602240_object *object_table; - struct qt602240_info info; - struct qt602240_finger finger[QT602240_MAX_FINGER]; - unsigned int irq; -}; - -static bool qt602240_object_readable(unsigned int type) -{ - switch (type) { - case QT602240_GEN_MESSAGE: - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_COMMSCONFIG: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: - case QT602240_SPT_USERDATA: - return true; - default: - return false; - } -} - -static bool qt602240_object_writable(unsigned int type) -{ - switch (type) { - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: - return true; - default: - return false; - } -} - -static void qt602240_dump_message(struct device *dev, - struct qt602240_message *message) -{ - dev_dbg(dev, "reportid:\t0x%x\n", message->reportid); - dev_dbg(dev, "message1:\t0x%x\n", message->message[0]); - dev_dbg(dev, "message2:\t0x%x\n", message->message[1]); - dev_dbg(dev, "message3:\t0x%x\n", message->message[2]); - dev_dbg(dev, "message4:\t0x%x\n", message->message[3]); - dev_dbg(dev, "message5:\t0x%x\n", message->message[4]); - dev_dbg(dev, "message6:\t0x%x\n", message->message[5]); - dev_dbg(dev, "message7:\t0x%x\n", message->message[6]); - dev_dbg(dev, "checksum:\t0x%x\n", message->checksum); -} - -static int qt602240_check_bootloader(struct i2c_client *client, - unsigned int state) -{ - u8 val; - -recheck: - if (i2c_master_recv(client, &val, 1) != 1) { - dev_err(&client->dev, "%s: i2c recv failed\n", __func__); - return -EIO; - } - - switch (state) { - case QT602240_WAITING_BOOTLOAD_CMD: - case QT602240_WAITING_FRAME_DATA: - val &= ~QT602240_BOOT_STATUS_MASK; - break; - case QT602240_FRAME_CRC_PASS: - if (val == QT602240_FRAME_CRC_CHECK) - goto recheck; - break; - default: - return -EINVAL; - } - - if (val != state) { - dev_err(&client->dev, "Unvalid bootloader mode state\n"); - return -EINVAL; - } - - return 0; -} - -static int qt602240_unlock_bootloader(struct i2c_client *client) -{ - u8 buf[2]; - - buf[0] = QT602240_UNLOCK_CMD_LSB; - buf[1] = QT602240_UNLOCK_CMD_MSB; - - if (i2c_master_send(client, buf, 2) != 2) { - dev_err(&client->dev, "%s: i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int qt602240_fw_write(struct i2c_client *client, - const u8 *data, unsigned int frame_size) -{ - if (i2c_master_send(client, data, frame_size) != frame_size) { - dev_err(&client->dev, "%s: i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int __qt602240_read_reg(struct i2c_client *client, - u16 reg, u16 len, void *val) -{ - struct i2c_msg xfer[2]; - u8 buf[2]; - - buf[0] = reg & 0xff; - buf[1] = (reg >> 8) & 0xff; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 2; - xfer[0].buf = buf; - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = len; - xfer[1].buf = val; - - if (i2c_transfer(client->adapter, xfer, 2) != 2) { - dev_err(&client->dev, "%s: i2c transfer failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val) -{ - return __qt602240_read_reg(client, reg, 1, val); -} - -static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) -{ - u8 buf[3]; - - buf[0] = reg & 0xff; - buf[1] = (reg >> 8) & 0xff; - buf[2] = val; - - if (i2c_master_send(client, buf, 3) != 3) { - dev_err(&client->dev, "%s: i2c send failed\n", __func__); - return -EIO; - } - - return 0; -} - -static int qt602240_read_object_table(struct i2c_client *client, - u16 reg, u8 *object_buf) -{ - return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE, - object_buf); -} - -static struct qt602240_object * -qt602240_get_object(struct qt602240_data *data, u8 type) -{ - struct qt602240_object *object; - int i; - - for (i = 0; i < data->info.object_num; i++) { - object = data->object_table + i; - if (object->type == type) - return object; - } - - dev_err(&data->client->dev, "Invalid object type\n"); - return NULL; -} - -static int qt602240_read_message(struct qt602240_data *data, - struct qt602240_message *message) -{ - struct qt602240_object *object; - u16 reg; - - object = qt602240_get_object(data, QT602240_GEN_MESSAGE); - if (!object) - return -EINVAL; - - reg = object->start_address; - return __qt602240_read_reg(data->client, reg, - sizeof(struct qt602240_message), message); -} - -static int qt602240_read_object(struct qt602240_data *data, - u8 type, u8 offset, u8 *val) -{ - struct qt602240_object *object; - u16 reg; - - object = qt602240_get_object(data, type); - if (!object) - return -EINVAL; - - reg = object->start_address; - return __qt602240_read_reg(data->client, reg + offset, 1, val); -} - -static int qt602240_write_object(struct qt602240_data *data, - u8 type, u8 offset, u8 val) -{ - struct qt602240_object *object; - u16 reg; - - object = qt602240_get_object(data, type); - if (!object) - return -EINVAL; - - reg = object->start_address; - return qt602240_write_reg(data->client, reg + offset, val); -} - -static void qt602240_input_report(struct qt602240_data *data, int single_id) -{ - struct qt602240_finger *finger = data->finger; - struct input_dev *input_dev = data->input_dev; - int status = finger[single_id].status; - int finger_num = 0; - int id; - - for (id = 0; id < QT602240_MAX_FINGER; id++) { - if (!finger[id].status) - continue; - - input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - finger[id].status != QT602240_RELEASE ? - finger[id].area : 0); - input_report_abs(input_dev, ABS_MT_POSITION_X, - finger[id].x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, - finger[id].y); - input_mt_sync(input_dev); - - if (finger[id].status == QT602240_RELEASE) - finger[id].status = 0; - else - finger_num++; - } - - input_report_key(input_dev, BTN_TOUCH, finger_num > 0); - - if (status != QT602240_RELEASE) { - input_report_abs(input_dev, ABS_X, finger[single_id].x); - input_report_abs(input_dev, ABS_Y, finger[single_id].y); - } - - input_sync(input_dev); -} - -static void qt602240_input_touchevent(struct qt602240_data *data, - struct qt602240_message *message, int id) -{ - struct qt602240_finger *finger = data->finger; - struct device *dev = &data->client->dev; - u8 status = message->message[0]; - int x; - int y; - int area; - - /* Check the touch is present on the screen */ - if (!(status & QT602240_DETECT)) { - if (status & QT602240_RELEASE) { - dev_dbg(dev, "[%d] released\n", id); - - finger[id].status = QT602240_RELEASE; - qt602240_input_report(data, id); - } - return; - } - - /* Check only AMP detection */ - if (!(status & (QT602240_PRESS | QT602240_MOVE))) - return; - - x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6); - y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2); - area = message->message[4]; - - dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, - status & QT602240_MOVE ? "moved" : "pressed", - x, y, area); - - finger[id].status = status & QT602240_MOVE ? - QT602240_MOVE : QT602240_PRESS; - finger[id].x = x; - finger[id].y = y; - finger[id].area = area; - - qt602240_input_report(data, id); -} - -static irqreturn_t qt602240_interrupt(int irq, void *dev_id) -{ - struct qt602240_data *data = dev_id; - struct qt602240_message message; - struct qt602240_object *object; - struct device *dev = &data->client->dev; - int id; - u8 reportid; - u8 max_reportid; - u8 min_reportid; - - do { - if (qt602240_read_message(data, &message)) { - dev_err(dev, "Failed to read message\n"); - goto end; - } - - reportid = message.reportid; - - /* whether reportid is thing of QT602240_TOUCH_MULTI */ - object = qt602240_get_object(data, QT602240_TOUCH_MULTI); - if (!object) - goto end; - - max_reportid = object->max_reportid; - min_reportid = max_reportid - object->num_report_ids + 1; - id = reportid - min_reportid; - - if (reportid >= min_reportid && reportid <= max_reportid) - qt602240_input_touchevent(data, &message, id); - else - qt602240_dump_message(dev, &message); - } while (reportid != 0xff); - -end: - return IRQ_HANDLED; -} - -static int qt602240_check_reg_init(struct qt602240_data *data) -{ - struct qt602240_object *object; - struct device *dev = &data->client->dev; - int index = 0; - int i, j; - u8 version = data->info.version; - u8 *init_vals; - - switch (version) { - case QT602240_VER_20: - init_vals = (u8 *)init_vals_ver_20; - break; - case QT602240_VER_21: - init_vals = (u8 *)init_vals_ver_21; - break; - case QT602240_VER_22: - init_vals = (u8 *)init_vals_ver_22; - break; - default: - dev_err(dev, "Firmware version %d doesn't support\n", version); - return -EINVAL; - } - - for (i = 0; i < data->info.object_num; i++) { - object = data->object_table + i; - - if (!qt602240_object_writable(object->type)) - continue; - - for (j = 0; j < object->size + 1; j++) - qt602240_write_object(data, object->type, j, - init_vals[index + j]); - - index += object->size + 1; - } - - return 0; -} - -static int qt602240_check_matrix_size(struct qt602240_data *data) -{ - const struct qt602240_platform_data *pdata = data->pdata; - struct device *dev = &data->client->dev; - int mode = -1; - int error; - u8 val; - - dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line); - dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line); - - switch (pdata->x_line) { - case 0 ... 15: - if (pdata->y_line <= 14) - mode = 0; - break; - case 16: - if (pdata->y_line <= 12) - mode = 1; - if (pdata->y_line == 13 || pdata->y_line == 14) - mode = 0; - break; - case 17: - if (pdata->y_line <= 11) - mode = 2; - if (pdata->y_line == 12 || pdata->y_line == 13) - mode = 1; - break; - case 18: - if (pdata->y_line <= 10) - mode = 3; - if (pdata->y_line == 11 || pdata->y_line == 12) - mode = 2; - break; - case 19: - if (pdata->y_line <= 9) - mode = 4; - if (pdata->y_line == 10 || pdata->y_line == 11) - mode = 3; - break; - case 20: - mode = 4; - } - - if (mode < 0) { - dev_err(dev, "Invalid X/Y lines\n"); - return -EINVAL; - } - - error = qt602240_read_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, &val); - if (error) - return error; - - if (mode == val) - return 0; - - /* Change the CTE configuration */ - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 1); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, mode); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 0); - - return 0; -} - -static int qt602240_make_highchg(struct qt602240_data *data) -{ - struct device *dev = &data->client->dev; - int count = 10; - int error; - u8 val; - - /* Read dummy message to make high CHG pin */ - do { - error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val); - if (error) - return error; - } while ((val != 0xff) && --count); - - if (!count) { - dev_err(dev, "CHG pin isn't cleared\n"); - return -EBUSY; - } - - return 0; -} - -static void qt602240_handle_pdata(struct qt602240_data *data) -{ - const struct qt602240_platform_data *pdata = data->pdata; - u8 voltage; - - /* Set touchscreen lines */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE, - pdata->x_line); - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE, - pdata->y_line); - - /* Set touchscreen orient */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT, - pdata->orient); - - /* Set touchscreen burst length */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_BLEN, pdata->blen); - - /* Set touchscreen threshold */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_TCHTHR, pdata->threshold); - - /* Set touchscreen resolution */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); - - /* Set touchscreen voltage */ - if (data->info.version >= QT602240_VER_21 && pdata->voltage) { - if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) { - voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) / - QT602240_VOLTAGE_STEP; - voltage = 0xff - voltage + 1; - } else - voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) / - QT602240_VOLTAGE_STEP; - - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_VOLTAGE, voltage); - } -} - -static int qt602240_get_info(struct qt602240_data *data) -{ - struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; - int error; - u8 val; - - error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val); - if (error) - return error; - info->family_id = val; - - error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val); - if (error) - return error; - info->variant_id = val; - - error = qt602240_read_reg(client, QT602240_VERSION, &val); - if (error) - return error; - info->version = val; - - error = qt602240_read_reg(client, QT602240_BUILD, &val); - if (error) - return error; - info->build = val; - - error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val); - if (error) - return error; - info->object_num = val; - - return 0; -} - -static int qt602240_get_object_table(struct qt602240_data *data) -{ - int error; - int i; - u16 reg; - u8 reportid = 0; - u8 buf[QT602240_OBJECT_SIZE]; - - for (i = 0; i < data->info.object_num; i++) { - struct qt602240_object *object = data->object_table + i; - - reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i; - error = qt602240_read_object_table(data->client, reg, buf); - if (error) - return error; - - object->type = buf[0]; - object->start_address = (buf[2] << 8) | buf[1]; - object->size = buf[3]; - object->instances = buf[4]; - object->num_report_ids = buf[5]; - - if (object->num_report_ids) { - reportid += object->num_report_ids * - (object->instances + 1); - object->max_reportid = reportid; - } - } - - return 0; -} - -static int qt602240_initialize(struct qt602240_data *data) -{ - struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; - int error; - u8 val; - - error = qt602240_get_info(data); - if (error) - return error; - - data->object_table = kcalloc(info->object_num, - sizeof(struct qt602240_object), - GFP_KERNEL); - if (!data->object_table) { - dev_err(&client->dev, "Failed to allocate memory\n"); - return -ENOMEM; - } - - /* Get object table information */ - error = qt602240_get_object_table(data); - if (error) - return error; - - /* Check register init values */ - error = qt602240_check_reg_init(data); - if (error) - return error; - - /* Check X/Y matrix size */ - error = qt602240_check_matrix_size(data); - if (error) - return error; - - error = qt602240_make_highchg(data); - if (error) - return error; - - qt602240_handle_pdata(data); - - /* Backup to memory */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_BACKUPNV, - QT602240_BACKUP_VALUE); - msleep(QT602240_BACKUP_TIME); - - /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); - msleep(QT602240_RESET_TIME); - - /* Update matrix size at info struct */ - error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val); - if (error) - return error; - info->matrix_xsize = val; - - error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val); - if (error) - return error; - info->matrix_ysize = val; - - dev_info(&client->dev, - "Family ID: %d Variant ID: %d Version: %d Build: %d\n", - info->family_id, info->variant_id, info->version, - info->build); - - dev_info(&client->dev, - "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n", - info->matrix_xsize, info->matrix_ysize, - info->object_num); - - return 0; -} - -static ssize_t qt602240_object_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct qt602240_data *data = dev_get_drvdata(dev); - struct qt602240_object *object; - int count = 0; - int i, j; - int error; - u8 val; - - for (i = 0; i < data->info.object_num; i++) { - object = data->object_table + i; - - count += sprintf(buf + count, - "Object Table Element %d(Type %d)\n", - i + 1, object->type); - - if (!qt602240_object_readable(object->type)) { - count += sprintf(buf + count, "\n"); - continue; - } - - for (j = 0; j < object->size + 1; j++) { - error = qt602240_read_object(data, - object->type, j, &val); - if (error) - return error; - - count += sprintf(buf + count, - " Byte %d: 0x%x (%d)\n", j, val, val); - } - - count += sprintf(buf + count, "\n"); - } - - return count; -} - -static int qt602240_load_fw(struct device *dev, const char *fn) -{ - struct qt602240_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; - const struct firmware *fw = NULL; - unsigned int frame_size; - unsigned int pos = 0; - int ret; - - ret = request_firmware(&fw, fn, dev); - if (ret) { - dev_err(dev, "Unable to open firmware %s\n", fn); - return ret; - } - - /* Change to the bootloader mode */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, QT602240_BOOT_VALUE); - msleep(QT602240_RESET_TIME); - - /* Change to slave address of bootloader */ - if (client->addr == QT602240_APP_LOW) - client->addr = QT602240_BOOT_LOW; - else - client->addr = QT602240_BOOT_HIGH; - - ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD); - if (ret) - goto out; - - /* Unlock bootloader */ - qt602240_unlock_bootloader(client); - - while (pos < fw->size) { - ret = qt602240_check_bootloader(client, - QT602240_WAITING_FRAME_DATA); - if (ret) - goto out; - - frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); - - /* We should add 2 at frame size as the the firmware data is not - * included the CRC bytes. - */ - frame_size += 2; - - /* Write one frame to device */ - qt602240_fw_write(client, fw->data + pos, frame_size); - - ret = qt602240_check_bootloader(client, - QT602240_FRAME_CRC_PASS); - if (ret) - goto out; - - pos += frame_size; - - dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size); - } - -out: - release_firmware(fw); - - /* Change to slave address of application */ - if (client->addr == QT602240_BOOT_LOW) - client->addr = QT602240_APP_LOW; - else - client->addr = QT602240_APP_HIGH; - - return ret; -} - -static ssize_t qt602240_update_fw_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct qt602240_data *data = dev_get_drvdata(dev); - unsigned int version; - int error; - - if (sscanf(buf, "%u", &version) != 1) { - dev_err(dev, "Invalid values\n"); - return -EINVAL; - } - - if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) { - dev_err(dev, "FW update supported starting with version 21\n"); - return -EINVAL; - } - - disable_irq(data->irq); - - error = qt602240_load_fw(dev, QT602240_FW_NAME); - if (error) { - dev_err(dev, "The firmware update failed(%d)\n", error); - count = error; - } else { - dev_dbg(dev, "The firmware update succeeded\n"); - - /* Wait for reset */ - msleep(QT602240_FWRESET_TIME); - - kfree(data->object_table); - data->object_table = NULL; - - qt602240_initialize(data); - } - - enable_irq(data->irq); - - return count; -} - -static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL); -static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store); - -static struct attribute *qt602240_attrs[] = { - &dev_attr_object.attr, - &dev_attr_update_fw.attr, - NULL -}; - -static const struct attribute_group qt602240_attr_group = { - .attrs = qt602240_attrs, -}; - -static void qt602240_start(struct qt602240_data *data) -{ - /* Touch enable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83); -} - -static void qt602240_stop(struct qt602240_data *data) -{ - /* Touch disable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0); -} - -static int qt602240_input_open(struct input_dev *dev) -{ - struct qt602240_data *data = input_get_drvdata(dev); - - qt602240_start(data); - - return 0; -} - -static void qt602240_input_close(struct input_dev *dev) -{ - struct qt602240_data *data = input_get_drvdata(dev); - - qt602240_stop(data); -} - -static int __devinit qt602240_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct qt602240_data *data; - struct input_dev *input_dev; - int error; - - if (!client->dev.platform_data) - return -EINVAL; - - data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!data || !input_dev) { - dev_err(&client->dev, "Failed to allocate memory\n"); - error = -ENOMEM; - goto err_free_mem; - } - - input_dev->name = "AT42QT602240/ATMXT224 Touchscreen"; - input_dev->id.bustype = BUS_I2C; - input_dev->dev.parent = &client->dev; - input_dev->open = qt602240_input_open; - input_dev->close = qt602240_input_close; - - __set_bit(EV_ABS, input_dev->evbit); - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(BTN_TOUCH, input_dev->keybit); - - /* For single touch */ - input_set_abs_params(input_dev, ABS_X, - 0, QT602240_MAX_XC, 0, 0); - input_set_abs_params(input_dev, ABS_Y, - 0, QT602240_MAX_YC, 0, 0); - - /* For multi touch */ - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, - 0, QT602240_MAX_AREA, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, QT602240_MAX_XC, 0, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, QT602240_MAX_YC, 0, 0); - - input_set_drvdata(input_dev, data); - - data->client = client; - data->input_dev = input_dev; - data->pdata = client->dev.platform_data; - data->irq = client->irq; - - i2c_set_clientdata(client, data); - - error = qt602240_initialize(data); - if (error) - goto err_free_object; - - error = request_threaded_irq(client->irq, NULL, qt602240_interrupt, - IRQF_TRIGGER_FALLING, client->dev.driver->name, data); - if (error) { - dev_err(&client->dev, "Failed to register interrupt\n"); - goto err_free_object; - } - - error = input_register_device(input_dev); - if (error) - goto err_free_irq; - - error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group); - if (error) - goto err_unregister_device; - - return 0; - -err_unregister_device: - input_unregister_device(input_dev); - input_dev = NULL; -err_free_irq: - free_irq(client->irq, data); -err_free_object: - kfree(data->object_table); -err_free_mem: - input_free_device(input_dev); - kfree(data); - return error; -} - -static int __devexit qt602240_remove(struct i2c_client *client) -{ - struct qt602240_data *data = i2c_get_clientdata(client); - - sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group); - free_irq(data->irq, data); - input_unregister_device(data->input_dev); - kfree(data->object_table); - kfree(data); - - return 0; -} - -#ifdef CONFIG_PM -static int qt602240_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); - struct input_dev *input_dev = data->input_dev; - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) - qt602240_stop(data); - - mutex_unlock(&input_dev->mutex); - - return 0; -} - -static int qt602240_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); - struct input_dev *input_dev = data->input_dev; - - /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); - - msleep(QT602240_RESET_TIME); - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) - qt602240_start(data); - - mutex_unlock(&input_dev->mutex); - - return 0; -} - -static const struct dev_pm_ops qt602240_pm_ops = { - .suspend = qt602240_suspend, - .resume = qt602240_resume, -}; -#endif - -static const struct i2c_device_id qt602240_id[] = { - { "qt602240_ts", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, qt602240_id); - -static struct i2c_driver qt602240_driver = { - .driver = { - .name = "qt602240_ts", - .owner = THIS_MODULE, -#ifdef CONFIG_PM - .pm = &qt602240_pm_ops, -#endif - }, - .probe = qt602240_probe, - .remove = __devexit_p(qt602240_remove), - .id_table = qt602240_id, -}; - -static int __init qt602240_init(void) -{ - return i2c_add_driver(&qt602240_driver); -} - -static void __exit qt602240_exit(void) -{ - i2c_del_driver(&qt602240_driver); -} - -module_init(qt602240_init); -module_exit(qt602240_exit); - -/* Module information */ -MODULE_AUTHOR("Joonyoung Shim "); -MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 7686b108d8ef5c32f429d5228798636f3a1caf5a Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Wed, 2 Feb 2011 23:21:58 -0800 Subject: Input: atmel_mxt_ts - get rid of qt602240 prefixes in names Change prefixes from qt602240 to mxt to reflect that the driver supports whole line of mXT touchscreens. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 929 ++++++++++++++++--------------- 1 file changed, 465 insertions(+), 464 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 47067789b747..5dca78a00c94 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1,5 +1,5 @@ /* - * AT42QT602240/ATMXT224 Touchscreen driver + * Atmel maXTouch Touchscreen driver * * Copyright (C) 2010 Samsung Electronics Co.Ltd * Author: Joonyoung Shim @@ -22,300 +22,300 @@ #include /* Version */ -#define QT602240_VER_20 20 -#define QT602240_VER_21 21 -#define QT602240_VER_22 22 +#define MXT_VER_20 20 +#define MXT_VER_21 21 +#define MXT_VER_22 22 /* Slave addresses */ -#define QT602240_APP_LOW 0x4a -#define QT602240_APP_HIGH 0x4b -#define QT602240_BOOT_LOW 0x24 -#define QT602240_BOOT_HIGH 0x25 +#define MXT_APP_LOW 0x4a +#define MXT_APP_HIGH 0x4b +#define MXT_BOOT_LOW 0x24 +#define MXT_BOOT_HIGH 0x25 /* Firmware */ -#define QT602240_FW_NAME "qt602240.fw" +#define MXT_FW_NAME "maxtouch.fw" /* Registers */ -#define QT602240_FAMILY_ID 0x00 -#define QT602240_VARIANT_ID 0x01 -#define QT602240_VERSION 0x02 -#define QT602240_BUILD 0x03 -#define QT602240_MATRIX_X_SIZE 0x04 -#define QT602240_MATRIX_Y_SIZE 0x05 -#define QT602240_OBJECT_NUM 0x06 -#define QT602240_OBJECT_START 0x07 +#define MXT_FAMILY_ID 0x00 +#define MXT_VARIANT_ID 0x01 +#define MXT_VERSION 0x02 +#define MXT_BUILD 0x03 +#define MXT_MATRIX_X_SIZE 0x04 +#define MXT_MATRIX_Y_SIZE 0x05 +#define MXT_OBJECT_NUM 0x06 +#define MXT_OBJECT_START 0x07 -#define QT602240_OBJECT_SIZE 6 +#define MXT_OBJECT_SIZE 6 /* Object types */ -#define QT602240_DEBUG_DIAGNOSTIC 37 -#define QT602240_GEN_MESSAGE 5 -#define QT602240_GEN_COMMAND 6 -#define QT602240_GEN_POWER 7 -#define QT602240_GEN_ACQUIRE 8 -#define QT602240_TOUCH_MULTI 9 -#define QT602240_TOUCH_KEYARRAY 15 -#define QT602240_TOUCH_PROXIMITY 23 -#define QT602240_PROCI_GRIPFACE 20 -#define QT602240_PROCG_NOISE 22 -#define QT602240_PROCI_ONETOUCH 24 -#define QT602240_PROCI_TWOTOUCH 27 -#define QT602240_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ -#define QT602240_SPT_GPIOPWM 19 -#define QT602240_SPT_SELFTEST 25 -#define QT602240_SPT_CTECONFIG 28 -#define QT602240_SPT_USERDATA 38 /* firmware ver 21 over */ - -/* QT602240_GEN_COMMAND field */ -#define QT602240_COMMAND_RESET 0 -#define QT602240_COMMAND_BACKUPNV 1 -#define QT602240_COMMAND_CALIBRATE 2 -#define QT602240_COMMAND_REPORTALL 3 -#define QT602240_COMMAND_DIAGNOSTIC 5 - -/* QT602240_GEN_POWER field */ -#define QT602240_POWER_IDLEACQINT 0 -#define QT602240_POWER_ACTVACQINT 1 -#define QT602240_POWER_ACTV2IDLETO 2 - -/* QT602240_GEN_ACQUIRE field */ -#define QT602240_ACQUIRE_CHRGTIME 0 -#define QT602240_ACQUIRE_TCHDRIFT 2 -#define QT602240_ACQUIRE_DRIFTST 3 -#define QT602240_ACQUIRE_TCHAUTOCAL 4 -#define QT602240_ACQUIRE_SYNC 5 -#define QT602240_ACQUIRE_ATCHCALST 6 -#define QT602240_ACQUIRE_ATCHCALSTHR 7 - -/* QT602240_TOUCH_MULTI field */ -#define QT602240_TOUCH_CTRL 0 -#define QT602240_TOUCH_XORIGIN 1 -#define QT602240_TOUCH_YORIGIN 2 -#define QT602240_TOUCH_XSIZE 3 -#define QT602240_TOUCH_YSIZE 4 -#define QT602240_TOUCH_BLEN 6 -#define QT602240_TOUCH_TCHTHR 7 -#define QT602240_TOUCH_TCHDI 8 -#define QT602240_TOUCH_ORIENT 9 -#define QT602240_TOUCH_MOVHYSTI 11 -#define QT602240_TOUCH_MOVHYSTN 12 -#define QT602240_TOUCH_NUMTOUCH 14 -#define QT602240_TOUCH_MRGHYST 15 -#define QT602240_TOUCH_MRGTHR 16 -#define QT602240_TOUCH_AMPHYST 17 -#define QT602240_TOUCH_XRANGE_LSB 18 -#define QT602240_TOUCH_XRANGE_MSB 19 -#define QT602240_TOUCH_YRANGE_LSB 20 -#define QT602240_TOUCH_YRANGE_MSB 21 -#define QT602240_TOUCH_XLOCLIP 22 -#define QT602240_TOUCH_XHICLIP 23 -#define QT602240_TOUCH_YLOCLIP 24 -#define QT602240_TOUCH_YHICLIP 25 -#define QT602240_TOUCH_XEDGECTRL 26 -#define QT602240_TOUCH_XEDGEDIST 27 -#define QT602240_TOUCH_YEDGECTRL 28 -#define QT602240_TOUCH_YEDGEDIST 29 -#define QT602240_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ - -/* QT602240_PROCI_GRIPFACE field */ -#define QT602240_GRIPFACE_CTRL 0 -#define QT602240_GRIPFACE_XLOGRIP 1 -#define QT602240_GRIPFACE_XHIGRIP 2 -#define QT602240_GRIPFACE_YLOGRIP 3 -#define QT602240_GRIPFACE_YHIGRIP 4 -#define QT602240_GRIPFACE_MAXTCHS 5 -#define QT602240_GRIPFACE_SZTHR1 7 -#define QT602240_GRIPFACE_SZTHR2 8 -#define QT602240_GRIPFACE_SHPTHR1 9 -#define QT602240_GRIPFACE_SHPTHR2 10 -#define QT602240_GRIPFACE_SUPEXTTO 11 - -/* QT602240_PROCI_NOISE field */ -#define QT602240_NOISE_CTRL 0 -#define QT602240_NOISE_OUTFLEN 1 -#define QT602240_NOISE_GCAFUL_LSB 3 -#define QT602240_NOISE_GCAFUL_MSB 4 -#define QT602240_NOISE_GCAFLL_LSB 5 -#define QT602240_NOISE_GCAFLL_MSB 6 -#define QT602240_NOISE_ACTVGCAFVALID 7 -#define QT602240_NOISE_NOISETHR 8 -#define QT602240_NOISE_FREQHOPSCALE 10 -#define QT602240_NOISE_FREQ0 11 -#define QT602240_NOISE_FREQ1 12 -#define QT602240_NOISE_FREQ2 13 -#define QT602240_NOISE_FREQ3 14 -#define QT602240_NOISE_FREQ4 15 -#define QT602240_NOISE_IDLEGCAFVALID 16 - -/* QT602240_SPT_COMMSCONFIG */ -#define QT602240_COMMS_CTRL 0 -#define QT602240_COMMS_CMD 1 - -/* QT602240_SPT_CTECONFIG field */ -#define QT602240_CTE_CTRL 0 -#define QT602240_CTE_CMD 1 -#define QT602240_CTE_MODE 2 -#define QT602240_CTE_IDLEGCAFDEPTH 3 -#define QT602240_CTE_ACTVGCAFDEPTH 4 -#define QT602240_CTE_VOLTAGE 5 /* firmware ver 21 over */ - -#define QT602240_VOLTAGE_DEFAULT 2700000 -#define QT602240_VOLTAGE_STEP 10000 - -/* Define for QT602240_GEN_COMMAND */ -#define QT602240_BOOT_VALUE 0xa5 -#define QT602240_BACKUP_VALUE 0x55 -#define QT602240_BACKUP_TIME 25 /* msec */ -#define QT602240_RESET_TIME 65 /* msec */ - -#define QT602240_FWRESET_TIME 175 /* msec */ +#define MXT_DEBUG_DIAGNOSTIC 37 +#define MXT_GEN_MESSAGE 5 +#define MXT_GEN_COMMAND 6 +#define MXT_GEN_POWER 7 +#define MXT_GEN_ACQUIRE 8 +#define MXT_TOUCH_MULTI 9 +#define MXT_TOUCH_KEYARRAY 15 +#define MXT_TOUCH_PROXIMITY 23 +#define MXT_PROCI_GRIPFACE 20 +#define MXT_PROCG_NOISE 22 +#define MXT_PROCI_ONETOUCH 24 +#define MXT_PROCI_TWOTOUCH 27 +#define MXT_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ +#define MXT_SPT_GPIOPWM 19 +#define MXT_SPT_SELFTEST 25 +#define MXT_SPT_CTECONFIG 28 +#define MXT_SPT_USERDATA 38 /* firmware ver 21 over */ + +/* MXT_GEN_COMMAND field */ +#define MXT_COMMAND_RESET 0 +#define MXT_COMMAND_BACKUPNV 1 +#define MXT_COMMAND_CALIBRATE 2 +#define MXT_COMMAND_REPORTALL 3 +#define MXT_COMMAND_DIAGNOSTIC 5 + +/* MXT_GEN_POWER field */ +#define MXT_POWER_IDLEACQINT 0 +#define MXT_POWER_ACTVACQINT 1 +#define MXT_POWER_ACTV2IDLETO 2 + +/* MXT_GEN_ACQUIRE field */ +#define MXT_ACQUIRE_CHRGTIME 0 +#define MXT_ACQUIRE_TCHDRIFT 2 +#define MXT_ACQUIRE_DRIFTST 3 +#define MXT_ACQUIRE_TCHAUTOCAL 4 +#define MXT_ACQUIRE_SYNC 5 +#define MXT_ACQUIRE_ATCHCALST 6 +#define MXT_ACQUIRE_ATCHCALSTHR 7 + +/* MXT_TOUCH_MULTI field */ +#define MXT_TOUCH_CTRL 0 +#define MXT_TOUCH_XORIGIN 1 +#define MXT_TOUCH_YORIGIN 2 +#define MXT_TOUCH_XSIZE 3 +#define MXT_TOUCH_YSIZE 4 +#define MXT_TOUCH_BLEN 6 +#define MXT_TOUCH_TCHTHR 7 +#define MXT_TOUCH_TCHDI 8 +#define MXT_TOUCH_ORIENT 9 +#define MXT_TOUCH_MOVHYSTI 11 +#define MXT_TOUCH_MOVHYSTN 12 +#define MXT_TOUCH_NUMTOUCH 14 +#define MXT_TOUCH_MRGHYST 15 +#define MXT_TOUCH_MRGTHR 16 +#define MXT_TOUCH_AMPHYST 17 +#define MXT_TOUCH_XRANGE_LSB 18 +#define MXT_TOUCH_XRANGE_MSB 19 +#define MXT_TOUCH_YRANGE_LSB 20 +#define MXT_TOUCH_YRANGE_MSB 21 +#define MXT_TOUCH_XLOCLIP 22 +#define MXT_TOUCH_XHICLIP 23 +#define MXT_TOUCH_YLOCLIP 24 +#define MXT_TOUCH_YHICLIP 25 +#define MXT_TOUCH_XEDGECTRL 26 +#define MXT_TOUCH_XEDGEDIST 27 +#define MXT_TOUCH_YEDGECTRL 28 +#define MXT_TOUCH_YEDGEDIST 29 +#define MXT_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ + +/* MXT_PROCI_GRIPFACE field */ +#define MXT_GRIPFACE_CTRL 0 +#define MXT_GRIPFACE_XLOGRIP 1 +#define MXT_GRIPFACE_XHIGRIP 2 +#define MXT_GRIPFACE_YLOGRIP 3 +#define MXT_GRIPFACE_YHIGRIP 4 +#define MXT_GRIPFACE_MAXTCHS 5 +#define MXT_GRIPFACE_SZTHR1 7 +#define MXT_GRIPFACE_SZTHR2 8 +#define MXT_GRIPFACE_SHPTHR1 9 +#define MXT_GRIPFACE_SHPTHR2 10 +#define MXT_GRIPFACE_SUPEXTTO 11 + +/* MXT_PROCI_NOISE field */ +#define MXT_NOISE_CTRL 0 +#define MXT_NOISE_OUTFLEN 1 +#define MXT_NOISE_GCAFUL_LSB 3 +#define MXT_NOISE_GCAFUL_MSB 4 +#define MXT_NOISE_GCAFLL_LSB 5 +#define MXT_NOISE_GCAFLL_MSB 6 +#define MXT_NOISE_ACTVGCAFVALID 7 +#define MXT_NOISE_NOISETHR 8 +#define MXT_NOISE_FREQHOPSCALE 10 +#define MXT_NOISE_FREQ0 11 +#define MXT_NOISE_FREQ1 12 +#define MXT_NOISE_FREQ2 13 +#define MXT_NOISE_FREQ3 14 +#define MXT_NOISE_FREQ4 15 +#define MXT_NOISE_IDLEGCAFVALID 16 + +/* MXT_SPT_COMMSCONFIG */ +#define MXT_COMMS_CTRL 0 +#define MXT_COMMS_CMD 1 + +/* MXT_SPT_CTECONFIG field */ +#define MXT_CTE_CTRL 0 +#define MXT_CTE_CMD 1 +#define MXT_CTE_MODE 2 +#define MXT_CTE_IDLEGCAFDEPTH 3 +#define MXT_CTE_ACTVGCAFDEPTH 4 +#define MXT_CTE_VOLTAGE 5 /* firmware ver 21 over */ + +#define MXT_VOLTAGE_DEFAULT 2700000 +#define MXT_VOLTAGE_STEP 10000 + +/* Define for MXT_GEN_COMMAND */ +#define MXT_BOOT_VALUE 0xa5 +#define MXT_BACKUP_VALUE 0x55 +#define MXT_BACKUP_TIME 25 /* msec */ +#define MXT_RESET_TIME 65 /* msec */ + +#define MXT_FWRESET_TIME 175 /* msec */ /* Command to unlock bootloader */ -#define QT602240_UNLOCK_CMD_MSB 0xaa -#define QT602240_UNLOCK_CMD_LSB 0xdc +#define MXT_UNLOCK_CMD_MSB 0xaa +#define MXT_UNLOCK_CMD_LSB 0xdc /* Bootloader mode status */ -#define QT602240_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ -#define QT602240_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ -#define QT602240_FRAME_CRC_CHECK 0x02 -#define QT602240_FRAME_CRC_FAIL 0x03 -#define QT602240_FRAME_CRC_PASS 0x04 -#define QT602240_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ -#define QT602240_BOOT_STATUS_MASK 0x3f +#define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */ +#define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */ +#define MXT_FRAME_CRC_CHECK 0x02 +#define MXT_FRAME_CRC_FAIL 0x03 +#define MXT_FRAME_CRC_PASS 0x04 +#define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */ +#define MXT_BOOT_STATUS_MASK 0x3f /* Touch status */ -#define QT602240_SUPPRESS (1 << 1) -#define QT602240_AMP (1 << 2) -#define QT602240_VECTOR (1 << 3) -#define QT602240_MOVE (1 << 4) -#define QT602240_RELEASE (1 << 5) -#define QT602240_PRESS (1 << 6) -#define QT602240_DETECT (1 << 7) +#define MXT_SUPPRESS (1 << 1) +#define MXT_AMP (1 << 2) +#define MXT_VECTOR (1 << 3) +#define MXT_MOVE (1 << 4) +#define MXT_RELEASE (1 << 5) +#define MXT_PRESS (1 << 6) +#define MXT_DETECT (1 << 7) /* Touchscreen absolute values */ -#define QT602240_MAX_XC 0x3ff -#define QT602240_MAX_YC 0x3ff -#define QT602240_MAX_AREA 0xff +#define MXT_MAX_XC 0x3ff +#define MXT_MAX_YC 0x3ff +#define MXT_MAX_AREA 0xff -#define QT602240_MAX_FINGER 10 +#define MXT_MAX_FINGER 10 /* Initial register values recommended from chip vendor */ static const u8 init_vals_ver_20[] = { - /* QT602240_GEN_COMMAND(6) */ + /* MXT_GEN_COMMAND(6) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ + /* MXT_GEN_POWER(7) */ 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ + /* MXT_GEN_ACQUIRE(8) */ 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, - /* QT602240_TOUCH_MULTI(9) */ + /* MXT_TOUCH_MULTI(9) */ 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, - /* QT602240_TOUCH_KEYARRAY(15) */ + /* MXT_TOUCH_KEYARRAY(15) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_GPIOPWM(19) */ + /* MXT_SPT_GPIOPWM(19) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ + /* MXT_PROCI_GRIPFACE(20) */ 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, 0x1e, 0x00, - /* QT602240_PROCG_NOISE(22) */ + /* MXT_PROCG_NOISE(22) */ 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, - /* QT602240_TOUCH_PROXIMITY(23) */ + /* MXT_TOUCH_PROXIMITY(23) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ + /* MXT_PROCI_ONETOUCH(24) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ + /* MXT_SPT_SELFTEST(25) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ + /* MXT_PROCI_TWOTOUCH(27) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ + /* MXT_SPT_CTECONFIG(28) */ 0x00, 0x00, 0x00, 0x04, 0x08, }; static const u8 init_vals_ver_21[] = { - /* QT602240_GEN_COMMAND(6) */ + /* MXT_GEN_COMMAND(6) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ + /* MXT_GEN_POWER(7) */ 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ + /* MXT_GEN_ACQUIRE(8) */ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ + /* MXT_TOUCH_MULTI(9) */ 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ + /* MXT_TOUCH_KEYARRAY(15) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_GPIOPWM(19) */ + /* MXT_SPT_GPIOPWM(19) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ + /* MXT_PROCI_GRIPFACE(20) */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ + /* MXT_PROCG_NOISE(22) */ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ + /* MXT_TOUCH_PROXIMITY(23) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ + /* MXT_PROCI_ONETOUCH(24) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ + /* MXT_SPT_SELFTEST(25) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ + /* MXT_PROCI_TWOTOUCH(27) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ + /* MXT_SPT_CTECONFIG(28) */ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, }; static const u8 init_vals_ver_22[] = { - /* QT602240_GEN_COMMAND(6) */ + /* MXT_GEN_COMMAND(6) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_GEN_POWER(7) */ + /* MXT_GEN_POWER(7) */ 0x20, 0xff, 0x32, - /* QT602240_GEN_ACQUIRE(8) */ + /* MXT_GEN_ACQUIRE(8) */ 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* QT602240_TOUCH_MULTI(9) */ + /* MXT_TOUCH_MULTI(9) */ 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_TOUCH_KEYARRAY(15) */ + /* MXT_TOUCH_KEYARRAY(15) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_GPIOPWM(19) */ + /* MXT_SPT_GPIOPWM(19) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_GRIPFACE(20) */ + /* MXT_PROCI_GRIPFACE(20) */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, 0x0f, 0x0a, - /* QT602240_PROCG_NOISE(22) */ + /* MXT_PROCG_NOISE(22) */ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* QT602240_TOUCH_PROXIMITY(23) */ + /* MXT_TOUCH_PROXIMITY(23) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_ONETOUCH(24) */ + /* MXT_PROCI_ONETOUCH(24) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_SELFTEST(25) */ + /* MXT_SPT_SELFTEST(25) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_PROCI_TWOTOUCH(27) */ + /* MXT_PROCI_TWOTOUCH(27) */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* QT602240_SPT_CTECONFIG(28) */ + /* MXT_SPT_CTECONFIG(28) */ 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, }; -struct qt602240_info { +struct mxt_info { u8 family_id; u8 variant_id; u8 version; @@ -325,7 +325,7 @@ struct qt602240_info { u8 object_num; }; -struct qt602240_object { +struct mxt_object { u8 type; u16 start_address; u8 size; @@ -336,13 +336,13 @@ struct qt602240_object { u8 max_reportid; }; -struct qt602240_message { +struct mxt_message { u8 reportid; u8 message[7]; u8 checksum; }; -struct qt602240_finger { +struct mxt_finger { int status; int x; int y; @@ -350,65 +350,65 @@ struct qt602240_finger { }; /* Each client has this additional data */ -struct qt602240_data { +struct mxt_data { struct i2c_client *client; struct input_dev *input_dev; - const struct qt602240_platform_data *pdata; - struct qt602240_object *object_table; - struct qt602240_info info; - struct qt602240_finger finger[QT602240_MAX_FINGER]; + const struct mxt_platform_data *pdata; + struct mxt_object *object_table; + struct mxt_info info; + struct mxt_finger finger[MXT_MAX_FINGER]; unsigned int irq; }; -static bool qt602240_object_readable(unsigned int type) +static bool mxt_object_readable(unsigned int type) { switch (type) { - case QT602240_GEN_MESSAGE: - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_COMMSCONFIG: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: - case QT602240_SPT_USERDATA: + case MXT_GEN_MESSAGE: + case MXT_GEN_COMMAND: + case MXT_GEN_POWER: + case MXT_GEN_ACQUIRE: + case MXT_TOUCH_MULTI: + case MXT_TOUCH_KEYARRAY: + case MXT_TOUCH_PROXIMITY: + case MXT_PROCI_GRIPFACE: + case MXT_PROCG_NOISE: + case MXT_PROCI_ONETOUCH: + case MXT_PROCI_TWOTOUCH: + case MXT_SPT_COMMSCONFIG: + case MXT_SPT_GPIOPWM: + case MXT_SPT_SELFTEST: + case MXT_SPT_CTECONFIG: + case MXT_SPT_USERDATA: return true; default: return false; } } -static bool qt602240_object_writable(unsigned int type) +static bool mxt_object_writable(unsigned int type) { switch (type) { - case QT602240_GEN_COMMAND: - case QT602240_GEN_POWER: - case QT602240_GEN_ACQUIRE: - case QT602240_TOUCH_MULTI: - case QT602240_TOUCH_KEYARRAY: - case QT602240_TOUCH_PROXIMITY: - case QT602240_PROCI_GRIPFACE: - case QT602240_PROCG_NOISE: - case QT602240_PROCI_ONETOUCH: - case QT602240_PROCI_TWOTOUCH: - case QT602240_SPT_GPIOPWM: - case QT602240_SPT_SELFTEST: - case QT602240_SPT_CTECONFIG: + case MXT_GEN_COMMAND: + case MXT_GEN_POWER: + case MXT_GEN_ACQUIRE: + case MXT_TOUCH_MULTI: + case MXT_TOUCH_KEYARRAY: + case MXT_TOUCH_PROXIMITY: + case MXT_PROCI_GRIPFACE: + case MXT_PROCG_NOISE: + case MXT_PROCI_ONETOUCH: + case MXT_PROCI_TWOTOUCH: + case MXT_SPT_GPIOPWM: + case MXT_SPT_SELFTEST: + case MXT_SPT_CTECONFIG: return true; default: return false; } } -static void qt602240_dump_message(struct device *dev, - struct qt602240_message *message) +static void mxt_dump_message(struct device *dev, + struct mxt_message *message) { dev_dbg(dev, "reportid:\t0x%x\n", message->reportid); dev_dbg(dev, "message1:\t0x%x\n", message->message[0]); @@ -421,7 +421,7 @@ static void qt602240_dump_message(struct device *dev, dev_dbg(dev, "checksum:\t0x%x\n", message->checksum); } -static int qt602240_check_bootloader(struct i2c_client *client, +static int mxt_check_bootloader(struct i2c_client *client, unsigned int state) { u8 val; @@ -433,12 +433,12 @@ recheck: } switch (state) { - case QT602240_WAITING_BOOTLOAD_CMD: - case QT602240_WAITING_FRAME_DATA: - val &= ~QT602240_BOOT_STATUS_MASK; + case MXT_WAITING_BOOTLOAD_CMD: + case MXT_WAITING_FRAME_DATA: + val &= ~MXT_BOOT_STATUS_MASK; break; - case QT602240_FRAME_CRC_PASS: - if (val == QT602240_FRAME_CRC_CHECK) + case MXT_FRAME_CRC_PASS: + if (val == MXT_FRAME_CRC_CHECK) goto recheck; break; default: @@ -453,12 +453,12 @@ recheck: return 0; } -static int qt602240_unlock_bootloader(struct i2c_client *client) +static int mxt_unlock_bootloader(struct i2c_client *client) { u8 buf[2]; - buf[0] = QT602240_UNLOCK_CMD_LSB; - buf[1] = QT602240_UNLOCK_CMD_MSB; + buf[0] = MXT_UNLOCK_CMD_LSB; + buf[1] = MXT_UNLOCK_CMD_MSB; if (i2c_master_send(client, buf, 2) != 2) { dev_err(&client->dev, "%s: i2c send failed\n", __func__); @@ -468,7 +468,7 @@ static int qt602240_unlock_bootloader(struct i2c_client *client) return 0; } -static int qt602240_fw_write(struct i2c_client *client, +static int mxt_fw_write(struct i2c_client *client, const u8 *data, unsigned int frame_size) { if (i2c_master_send(client, data, frame_size) != frame_size) { @@ -479,7 +479,7 @@ static int qt602240_fw_write(struct i2c_client *client, return 0; } -static int __qt602240_read_reg(struct i2c_client *client, +static int __mxt_read_reg(struct i2c_client *client, u16 reg, u16 len, void *val) { struct i2c_msg xfer[2]; @@ -508,12 +508,12 @@ static int __qt602240_read_reg(struct i2c_client *client, return 0; } -static int qt602240_read_reg(struct i2c_client *client, u16 reg, u8 *val) +static int mxt_read_reg(struct i2c_client *client, u16 reg, u8 *val) { - return __qt602240_read_reg(client, reg, 1, val); + return __mxt_read_reg(client, reg, 1, val); } -static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) +static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) { u8 buf[3]; @@ -529,17 +529,17 @@ static int qt602240_write_reg(struct i2c_client *client, u16 reg, u8 val) return 0; } -static int qt602240_read_object_table(struct i2c_client *client, +static int mxt_read_object_table(struct i2c_client *client, u16 reg, u8 *object_buf) { - return __qt602240_read_reg(client, reg, QT602240_OBJECT_SIZE, + return __mxt_read_reg(client, reg, MXT_OBJECT_SIZE, object_buf); } -static struct qt602240_object * -qt602240_get_object(struct qt602240_data *data, u8 type) +static struct mxt_object * +mxt_get_object(struct mxt_data *data, u8 type) { - struct qt602240_object *object; + struct mxt_object *object; int i; for (i = 0; i < data->info.object_num; i++) { @@ -552,63 +552,63 @@ qt602240_get_object(struct qt602240_data *data, u8 type) return NULL; } -static int qt602240_read_message(struct qt602240_data *data, - struct qt602240_message *message) +static int mxt_read_message(struct mxt_data *data, + struct mxt_message *message) { - struct qt602240_object *object; + struct mxt_object *object; u16 reg; - object = qt602240_get_object(data, QT602240_GEN_MESSAGE); + object = mxt_get_object(data, MXT_GEN_MESSAGE); if (!object) return -EINVAL; reg = object->start_address; - return __qt602240_read_reg(data->client, reg, - sizeof(struct qt602240_message), message); + return __mxt_read_reg(data->client, reg, + sizeof(struct mxt_message), message); } -static int qt602240_read_object(struct qt602240_data *data, +static int mxt_read_object(struct mxt_data *data, u8 type, u8 offset, u8 *val) { - struct qt602240_object *object; + struct mxt_object *object; u16 reg; - object = qt602240_get_object(data, type); + object = mxt_get_object(data, type); if (!object) return -EINVAL; reg = object->start_address; - return __qt602240_read_reg(data->client, reg + offset, 1, val); + return __mxt_read_reg(data->client, reg + offset, 1, val); } -static int qt602240_write_object(struct qt602240_data *data, +static int mxt_write_object(struct mxt_data *data, u8 type, u8 offset, u8 val) { - struct qt602240_object *object; + struct mxt_object *object; u16 reg; - object = qt602240_get_object(data, type); + object = mxt_get_object(data, type); if (!object) return -EINVAL; reg = object->start_address; - return qt602240_write_reg(data->client, reg + offset, val); + return mxt_write_reg(data->client, reg + offset, val); } -static void qt602240_input_report(struct qt602240_data *data, int single_id) +static void mxt_input_report(struct mxt_data *data, int single_id) { - struct qt602240_finger *finger = data->finger; + struct mxt_finger *finger = data->finger; struct input_dev *input_dev = data->input_dev; int status = finger[single_id].status; int finger_num = 0; int id; - for (id = 0; id < QT602240_MAX_FINGER; id++) { + for (id = 0; id < MXT_MAX_FINGER; id++) { if (!finger[id].status) continue; input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, - finger[id].status != QT602240_RELEASE ? + finger[id].status != MXT_RELEASE ? finger[id].area : 0); input_report_abs(input_dev, ABS_MT_POSITION_X, finger[id].x); @@ -616,7 +616,7 @@ static void qt602240_input_report(struct qt602240_data *data, int single_id) finger[id].y); input_mt_sync(input_dev); - if (finger[id].status == QT602240_RELEASE) + if (finger[id].status == MXT_RELEASE) finger[id].status = 0; else finger_num++; @@ -624,7 +624,7 @@ static void qt602240_input_report(struct qt602240_data *data, int single_id) input_report_key(input_dev, BTN_TOUCH, finger_num > 0); - if (status != QT602240_RELEASE) { + if (status != MXT_RELEASE) { input_report_abs(input_dev, ABS_X, finger[single_id].x); input_report_abs(input_dev, ABS_Y, finger[single_id].y); } @@ -632,10 +632,10 @@ static void qt602240_input_report(struct qt602240_data *data, int single_id) input_sync(input_dev); } -static void qt602240_input_touchevent(struct qt602240_data *data, - struct qt602240_message *message, int id) +static void mxt_input_touchevent(struct mxt_data *data, + struct mxt_message *message, int id) { - struct qt602240_finger *finger = data->finger; + struct mxt_finger *finger = data->finger; struct device *dev = &data->client->dev; u8 status = message->message[0]; int x; @@ -643,18 +643,18 @@ static void qt602240_input_touchevent(struct qt602240_data *data, int area; /* Check the touch is present on the screen */ - if (!(status & QT602240_DETECT)) { - if (status & QT602240_RELEASE) { + if (!(status & MXT_DETECT)) { + if (status & MXT_RELEASE) { dev_dbg(dev, "[%d] released\n", id); - finger[id].status = QT602240_RELEASE; - qt602240_input_report(data, id); + finger[id].status = MXT_RELEASE; + mxt_input_report(data, id); } return; } /* Check only AMP detection */ - if (!(status & (QT602240_PRESS | QT602240_MOVE))) + if (!(status & (MXT_PRESS | MXT_MOVE))) return; x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6); @@ -662,23 +662,23 @@ static void qt602240_input_touchevent(struct qt602240_data *data, area = message->message[4]; dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id, - status & QT602240_MOVE ? "moved" : "pressed", + status & MXT_MOVE ? "moved" : "pressed", x, y, area); - finger[id].status = status & QT602240_MOVE ? - QT602240_MOVE : QT602240_PRESS; + finger[id].status = status & MXT_MOVE ? + MXT_MOVE : MXT_PRESS; finger[id].x = x; finger[id].y = y; finger[id].area = area; - qt602240_input_report(data, id); + mxt_input_report(data, id); } -static irqreturn_t qt602240_interrupt(int irq, void *dev_id) +static irqreturn_t mxt_interrupt(int irq, void *dev_id) { - struct qt602240_data *data = dev_id; - struct qt602240_message message; - struct qt602240_object *object; + struct mxt_data *data = dev_id; + struct mxt_message message; + struct mxt_object *object; struct device *dev = &data->client->dev; int id; u8 reportid; @@ -686,15 +686,15 @@ static irqreturn_t qt602240_interrupt(int irq, void *dev_id) u8 min_reportid; do { - if (qt602240_read_message(data, &message)) { + if (mxt_read_message(data, &message)) { dev_err(dev, "Failed to read message\n"); goto end; } reportid = message.reportid; - /* whether reportid is thing of QT602240_TOUCH_MULTI */ - object = qt602240_get_object(data, QT602240_TOUCH_MULTI); + /* whether reportid is thing of MXT_TOUCH_MULTI */ + object = mxt_get_object(data, MXT_TOUCH_MULTI); if (!object) goto end; @@ -703,18 +703,18 @@ static irqreturn_t qt602240_interrupt(int irq, void *dev_id) id = reportid - min_reportid; if (reportid >= min_reportid && reportid <= max_reportid) - qt602240_input_touchevent(data, &message, id); + mxt_input_touchevent(data, &message, id); else - qt602240_dump_message(dev, &message); + mxt_dump_message(dev, &message); } while (reportid != 0xff); end: return IRQ_HANDLED; } -static int qt602240_check_reg_init(struct qt602240_data *data) +static int mxt_check_reg_init(struct mxt_data *data) { - struct qt602240_object *object; + struct mxt_object *object; struct device *dev = &data->client->dev; int index = 0; int i, j; @@ -722,13 +722,13 @@ static int qt602240_check_reg_init(struct qt602240_data *data) u8 *init_vals; switch (version) { - case QT602240_VER_20: + case MXT_VER_20: init_vals = (u8 *)init_vals_ver_20; break; - case QT602240_VER_21: + case MXT_VER_21: init_vals = (u8 *)init_vals_ver_21; break; - case QT602240_VER_22: + case MXT_VER_22: init_vals = (u8 *)init_vals_ver_22; break; default: @@ -739,11 +739,11 @@ static int qt602240_check_reg_init(struct qt602240_data *data) for (i = 0; i < data->info.object_num; i++) { object = data->object_table + i; - if (!qt602240_object_writable(object->type)) + if (!mxt_object_writable(object->type)) continue; for (j = 0; j < object->size + 1; j++) - qt602240_write_object(data, object->type, j, + mxt_write_object(data, object->type, j, init_vals[index + j]); index += object->size + 1; @@ -752,9 +752,9 @@ static int qt602240_check_reg_init(struct qt602240_data *data) return 0; } -static int qt602240_check_matrix_size(struct qt602240_data *data) +static int mxt_check_matrix_size(struct mxt_data *data) { - const struct qt602240_platform_data *pdata = data->pdata; + const struct mxt_platform_data *pdata = data->pdata; struct device *dev = &data->client->dev; int mode = -1; int error; @@ -801,8 +801,8 @@ static int qt602240_check_matrix_size(struct qt602240_data *data) return -EINVAL; } - error = qt602240_read_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, &val); + error = mxt_read_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_MODE, &val); if (error) return error; @@ -810,17 +810,17 @@ static int qt602240_check_matrix_size(struct qt602240_data *data) return 0; /* Change the CTE configuration */ - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 1); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_MODE, mode); - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_CTRL, 0); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_CTRL, 1); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_MODE, mode); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_CTRL, 0); return 0; } -static int qt602240_make_highchg(struct qt602240_data *data) +static int mxt_make_highchg(struct mxt_data *data) { struct device *dev = &data->client->dev; int count = 10; @@ -829,7 +829,7 @@ static int qt602240_make_highchg(struct qt602240_data *data) /* Read dummy message to make high CHG pin */ do { - error = qt602240_read_object(data, QT602240_GEN_MESSAGE, 0, &val); + error = mxt_read_object(data, MXT_GEN_MESSAGE, 0, &val); if (error) return error; } while ((val != 0xff) && --count); @@ -842,82 +842,82 @@ static int qt602240_make_highchg(struct qt602240_data *data) return 0; } -static void qt602240_handle_pdata(struct qt602240_data *data) +static void mxt_handle_pdata(struct mxt_data *data) { - const struct qt602240_platform_data *pdata = data->pdata; + const struct mxt_platform_data *pdata = data->pdata; u8 voltage; /* Set touchscreen lines */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_XSIZE, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XSIZE, pdata->x_line); - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_YSIZE, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YSIZE, pdata->y_line); /* Set touchscreen orient */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, QT602240_TOUCH_ORIENT, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_ORIENT, pdata->orient); /* Set touchscreen burst length */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_BLEN, pdata->blen); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_BLEN, pdata->blen); /* Set touchscreen threshold */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_TCHTHR, pdata->threshold); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_TCHTHR, pdata->threshold); /* Set touchscreen resolution */ - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); - qt602240_write_object(data, QT602240_TOUCH_MULTI, - QT602240_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); + mxt_write_object(data, MXT_TOUCH_MULTI, + MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); /* Set touchscreen voltage */ - if (data->info.version >= QT602240_VER_21 && pdata->voltage) { - if (pdata->voltage < QT602240_VOLTAGE_DEFAULT) { - voltage = (QT602240_VOLTAGE_DEFAULT - pdata->voltage) / - QT602240_VOLTAGE_STEP; + if (data->info.version >= MXT_VER_21 && pdata->voltage) { + if (pdata->voltage < MXT_VOLTAGE_DEFAULT) { + voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) / + MXT_VOLTAGE_STEP; voltage = 0xff - voltage + 1; } else - voltage = (pdata->voltage - QT602240_VOLTAGE_DEFAULT) / - QT602240_VOLTAGE_STEP; + voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) / + MXT_VOLTAGE_STEP; - qt602240_write_object(data, QT602240_SPT_CTECONFIG, - QT602240_CTE_VOLTAGE, voltage); + mxt_write_object(data, MXT_SPT_CTECONFIG, + MXT_CTE_VOLTAGE, voltage); } } -static int qt602240_get_info(struct qt602240_data *data) +static int mxt_get_info(struct mxt_data *data) { struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; + struct mxt_info *info = &data->info; int error; u8 val; - error = qt602240_read_reg(client, QT602240_FAMILY_ID, &val); + error = mxt_read_reg(client, MXT_FAMILY_ID, &val); if (error) return error; info->family_id = val; - error = qt602240_read_reg(client, QT602240_VARIANT_ID, &val); + error = mxt_read_reg(client, MXT_VARIANT_ID, &val); if (error) return error; info->variant_id = val; - error = qt602240_read_reg(client, QT602240_VERSION, &val); + error = mxt_read_reg(client, MXT_VERSION, &val); if (error) return error; info->version = val; - error = qt602240_read_reg(client, QT602240_BUILD, &val); + error = mxt_read_reg(client, MXT_BUILD, &val); if (error) return error; info->build = val; - error = qt602240_read_reg(client, QT602240_OBJECT_NUM, &val); + error = mxt_read_reg(client, MXT_OBJECT_NUM, &val); if (error) return error; info->object_num = val; @@ -925,19 +925,19 @@ static int qt602240_get_info(struct qt602240_data *data) return 0; } -static int qt602240_get_object_table(struct qt602240_data *data) +static int mxt_get_object_table(struct mxt_data *data) { int error; int i; u16 reg; u8 reportid = 0; - u8 buf[QT602240_OBJECT_SIZE]; + u8 buf[MXT_OBJECT_SIZE]; for (i = 0; i < data->info.object_num; i++) { - struct qt602240_object *object = data->object_table + i; + struct mxt_object *object = data->object_table + i; - reg = QT602240_OBJECT_START + QT602240_OBJECT_SIZE * i; - error = qt602240_read_object_table(data->client, reg, buf); + reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i; + error = mxt_read_object_table(data->client, reg, buf); if (error) return error; @@ -957,19 +957,19 @@ static int qt602240_get_object_table(struct qt602240_data *data) return 0; } -static int qt602240_initialize(struct qt602240_data *data) +static int mxt_initialize(struct mxt_data *data) { struct i2c_client *client = data->client; - struct qt602240_info *info = &data->info; + struct mxt_info *info = &data->info; int error; u8 val; - error = qt602240_get_info(data); + error = mxt_get_info(data); if (error) return error; data->object_table = kcalloc(info->object_num, - sizeof(struct qt602240_object), + sizeof(struct mxt_object), GFP_KERNEL); if (!data->object_table) { dev_err(&client->dev, "Failed to allocate memory\n"); @@ -977,44 +977,44 @@ static int qt602240_initialize(struct qt602240_data *data) } /* Get object table information */ - error = qt602240_get_object_table(data); + error = mxt_get_object_table(data); if (error) return error; /* Check register init values */ - error = qt602240_check_reg_init(data); + error = mxt_check_reg_init(data); if (error) return error; /* Check X/Y matrix size */ - error = qt602240_check_matrix_size(data); + error = mxt_check_matrix_size(data); if (error) return error; - error = qt602240_make_highchg(data); + error = mxt_make_highchg(data); if (error) return error; - qt602240_handle_pdata(data); + mxt_handle_pdata(data); /* Backup to memory */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_BACKUPNV, - QT602240_BACKUP_VALUE); - msleep(QT602240_BACKUP_TIME); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_BACKUPNV, + MXT_BACKUP_VALUE); + msleep(MXT_BACKUP_TIME); /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); - msleep(QT602240_RESET_TIME); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_RESET, 1); + msleep(MXT_RESET_TIME); /* Update matrix size at info struct */ - error = qt602240_read_reg(client, QT602240_MATRIX_X_SIZE, &val); + error = mxt_read_reg(client, MXT_MATRIX_X_SIZE, &val); if (error) return error; info->matrix_xsize = val; - error = qt602240_read_reg(client, QT602240_MATRIX_Y_SIZE, &val); + error = mxt_read_reg(client, MXT_MATRIX_Y_SIZE, &val); if (error) return error; info->matrix_ysize = val; @@ -1032,11 +1032,11 @@ static int qt602240_initialize(struct qt602240_data *data) return 0; } -static ssize_t qt602240_object_show(struct device *dev, +static ssize_t mxt_object_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct qt602240_data *data = dev_get_drvdata(dev); - struct qt602240_object *object; + struct mxt_data *data = dev_get_drvdata(dev); + struct mxt_object *object; int count = 0; int i, j; int error; @@ -1049,13 +1049,13 @@ static ssize_t qt602240_object_show(struct device *dev, "Object Table Element %d(Type %d)\n", i + 1, object->type); - if (!qt602240_object_readable(object->type)) { + if (!mxt_object_readable(object->type)) { count += sprintf(buf + count, "\n"); continue; } for (j = 0; j < object->size + 1; j++) { - error = qt602240_read_object(data, + error = mxt_read_object(data, object->type, j, &val); if (error) return error; @@ -1070,9 +1070,9 @@ static ssize_t qt602240_object_show(struct device *dev, return count; } -static int qt602240_load_fw(struct device *dev, const char *fn) +static int mxt_load_fw(struct device *dev, const char *fn) { - struct qt602240_data *data = dev_get_drvdata(dev); + struct mxt_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; const struct firmware *fw = NULL; unsigned int frame_size; @@ -1086,26 +1086,26 @@ static int qt602240_load_fw(struct device *dev, const char *fn) } /* Change to the bootloader mode */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, QT602240_BOOT_VALUE); - msleep(QT602240_RESET_TIME); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_RESET, MXT_BOOT_VALUE); + msleep(MXT_RESET_TIME); /* Change to slave address of bootloader */ - if (client->addr == QT602240_APP_LOW) - client->addr = QT602240_BOOT_LOW; + if (client->addr == MXT_APP_LOW) + client->addr = MXT_BOOT_LOW; else - client->addr = QT602240_BOOT_HIGH; + client->addr = MXT_BOOT_HIGH; - ret = qt602240_check_bootloader(client, QT602240_WAITING_BOOTLOAD_CMD); + ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD); if (ret) goto out; /* Unlock bootloader */ - qt602240_unlock_bootloader(client); + mxt_unlock_bootloader(client); while (pos < fw->size) { - ret = qt602240_check_bootloader(client, - QT602240_WAITING_FRAME_DATA); + ret = mxt_check_bootloader(client, + MXT_WAITING_FRAME_DATA); if (ret) goto out; @@ -1117,10 +1117,10 @@ static int qt602240_load_fw(struct device *dev, const char *fn) frame_size += 2; /* Write one frame to device */ - qt602240_fw_write(client, fw->data + pos, frame_size); + mxt_fw_write(client, fw->data + pos, frame_size); - ret = qt602240_check_bootloader(client, - QT602240_FRAME_CRC_PASS); + ret = mxt_check_bootloader(client, + MXT_FRAME_CRC_PASS); if (ret) goto out; @@ -1133,19 +1133,19 @@ out: release_firmware(fw); /* Change to slave address of application */ - if (client->addr == QT602240_BOOT_LOW) - client->addr = QT602240_APP_LOW; + if (client->addr == MXT_BOOT_LOW) + client->addr = MXT_APP_LOW; else - client->addr = QT602240_APP_HIGH; + client->addr = MXT_APP_HIGH; return ret; } -static ssize_t qt602240_update_fw_store(struct device *dev, +static ssize_t mxt_update_fw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct qt602240_data *data = dev_get_drvdata(dev); + struct mxt_data *data = dev_get_drvdata(dev); unsigned int version; int error; @@ -1154,14 +1154,14 @@ static ssize_t qt602240_update_fw_store(struct device *dev, return -EINVAL; } - if (data->info.version < QT602240_VER_21 || version < QT602240_VER_21) { + if (data->info.version < MXT_VER_21 || version < MXT_VER_21) { dev_err(dev, "FW update supported starting with version 21\n"); return -EINVAL; } disable_irq(data->irq); - error = qt602240_load_fw(dev, QT602240_FW_NAME); + error = mxt_load_fw(dev, MXT_FW_NAME); if (error) { dev_err(dev, "The firmware update failed(%d)\n", error); count = error; @@ -1169,12 +1169,12 @@ static ssize_t qt602240_update_fw_store(struct device *dev, dev_dbg(dev, "The firmware update succeeded\n"); /* Wait for reset */ - msleep(QT602240_FWRESET_TIME); + msleep(MXT_FWRESET_TIME); kfree(data->object_table); data->object_table = NULL; - qt602240_initialize(data); + mxt_initialize(data); } enable_irq(data->irq); @@ -1182,60 +1182,60 @@ static ssize_t qt602240_update_fw_store(struct device *dev, return count; } -static DEVICE_ATTR(object, 0444, qt602240_object_show, NULL); -static DEVICE_ATTR(update_fw, 0664, NULL, qt602240_update_fw_store); +static DEVICE_ATTR(object, 0444, mxt_object_show, NULL); +static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store); -static struct attribute *qt602240_attrs[] = { +static struct attribute *mxt_attrs[] = { &dev_attr_object.attr, &dev_attr_update_fw.attr, NULL }; -static const struct attribute_group qt602240_attr_group = { - .attrs = qt602240_attrs, +static const struct attribute_group mxt_attr_group = { + .attrs = mxt_attrs, }; -static void qt602240_start(struct qt602240_data *data) +static void mxt_start(struct mxt_data *data) { /* Touch enable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0x83); + mxt_write_object(data, + MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0x83); } -static void qt602240_stop(struct qt602240_data *data) +static void mxt_stop(struct mxt_data *data) { /* Touch disable */ - qt602240_write_object(data, - QT602240_TOUCH_MULTI, QT602240_TOUCH_CTRL, 0); + mxt_write_object(data, + MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0); } -static int qt602240_input_open(struct input_dev *dev) +static int mxt_input_open(struct input_dev *dev) { - struct qt602240_data *data = input_get_drvdata(dev); + struct mxt_data *data = input_get_drvdata(dev); - qt602240_start(data); + mxt_start(data); return 0; } -static void qt602240_input_close(struct input_dev *dev) +static void mxt_input_close(struct input_dev *dev) { - struct qt602240_data *data = input_get_drvdata(dev); + struct mxt_data *data = input_get_drvdata(dev); - qt602240_stop(data); + mxt_stop(data); } -static int __devinit qt602240_probe(struct i2c_client *client, +static int __devinit mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct qt602240_data *data; + struct mxt_data *data; struct input_dev *input_dev; int error; if (!client->dev.platform_data) return -EINVAL; - data = kzalloc(sizeof(struct qt602240_data), GFP_KERNEL); + data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); input_dev = input_allocate_device(); if (!data || !input_dev) { dev_err(&client->dev, "Failed to allocate memory\n"); @@ -1243,11 +1243,11 @@ static int __devinit qt602240_probe(struct i2c_client *client, goto err_free_mem; } - input_dev->name = "AT42QT602240/ATMXT224 Touchscreen"; + input_dev->name = "Atmel maXTouch Touchscreen"; input_dev->id.bustype = BUS_I2C; input_dev->dev.parent = &client->dev; - input_dev->open = qt602240_input_open; - input_dev->close = qt602240_input_close; + input_dev->open = mxt_input_open; + input_dev->close = mxt_input_close; __set_bit(EV_ABS, input_dev->evbit); __set_bit(EV_KEY, input_dev->evbit); @@ -1255,17 +1255,17 @@ static int __devinit qt602240_probe(struct i2c_client *client, /* For single touch */ input_set_abs_params(input_dev, ABS_X, - 0, QT602240_MAX_XC, 0, 0); + 0, MXT_MAX_XC, 0, 0); input_set_abs_params(input_dev, ABS_Y, - 0, QT602240_MAX_YC, 0, 0); + 0, MXT_MAX_YC, 0, 0); /* For multi touch */ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, - 0, QT602240_MAX_AREA, 0, 0); + 0, MXT_MAX_AREA, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, QT602240_MAX_XC, 0, 0); + 0, MXT_MAX_XC, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, QT602240_MAX_YC, 0, 0); + 0, MXT_MAX_YC, 0, 0); input_set_drvdata(input_dev, data); @@ -1276,11 +1276,11 @@ static int __devinit qt602240_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - error = qt602240_initialize(data); + error = mxt_initialize(data); if (error) goto err_free_object; - error = request_threaded_irq(client->irq, NULL, qt602240_interrupt, + error = request_threaded_irq(client->irq, NULL, mxt_interrupt, IRQF_TRIGGER_FALLING, client->dev.driver->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); @@ -1291,7 +1291,7 @@ static int __devinit qt602240_probe(struct i2c_client *client, if (error) goto err_free_irq; - error = sysfs_create_group(&client->dev.kobj, &qt602240_attr_group); + error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); if (error) goto err_unregister_device; @@ -1310,11 +1310,11 @@ err_free_mem: return error; } -static int __devexit qt602240_remove(struct i2c_client *client) +static int __devexit mxt_remove(struct i2c_client *client) { - struct qt602240_data *data = i2c_get_clientdata(client); + struct mxt_data *data = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &qt602240_attr_group); + sysfs_remove_group(&client->dev.kobj, &mxt_attr_group); free_irq(data->irq, data); input_unregister_device(data->input_dev); kfree(data->object_table); @@ -1324,83 +1324,84 @@ static int __devexit qt602240_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int qt602240_suspend(struct device *dev) +static int mxt_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); + struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; mutex_lock(&input_dev->mutex); if (input_dev->users) - qt602240_stop(data); + mxt_stop(data); mutex_unlock(&input_dev->mutex); return 0; } -static int qt602240_resume(struct device *dev) +static int mxt_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct qt602240_data *data = i2c_get_clientdata(client); + struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; /* Soft reset */ - qt602240_write_object(data, QT602240_GEN_COMMAND, - QT602240_COMMAND_RESET, 1); + mxt_write_object(data, MXT_GEN_COMMAND, + MXT_COMMAND_RESET, 1); - msleep(QT602240_RESET_TIME); + msleep(MXT_RESET_TIME); mutex_lock(&input_dev->mutex); if (input_dev->users) - qt602240_start(data); + mxt_start(data); mutex_unlock(&input_dev->mutex); return 0; } -static const struct dev_pm_ops qt602240_pm_ops = { - .suspend = qt602240_suspend, - .resume = qt602240_resume, +static const struct dev_pm_ops mxt_pm_ops = { + .suspend = mxt_suspend, + .resume = mxt_resume, }; #endif -static const struct i2c_device_id qt602240_id[] = { +static const struct i2c_device_id mxt_id[] = { { "qt602240_ts", 0 }, + { "atmel_mxt_ts", 0 }, { } }; -MODULE_DEVICE_TABLE(i2c, qt602240_id); +MODULE_DEVICE_TABLE(i2c, mxt_id); -static struct i2c_driver qt602240_driver = { +static struct i2c_driver mxt_driver = { .driver = { - .name = "qt602240_ts", + .name = "atmel_mxt_ts", .owner = THIS_MODULE, #ifdef CONFIG_PM - .pm = &qt602240_pm_ops, + .pm = &mxt_pm_ops, #endif }, - .probe = qt602240_probe, - .remove = __devexit_p(qt602240_remove), - .id_table = qt602240_id, + .probe = mxt_probe, + .remove = __devexit_p(mxt_remove), + .id_table = mxt_id, }; -static int __init qt602240_init(void) +static int __init mxt_init(void) { - return i2c_add_driver(&qt602240_driver); + return i2c_add_driver(&mxt_driver); } -static void __exit qt602240_exit(void) +static void __exit mxt_exit(void) { - i2c_del_driver(&qt602240_driver); + i2c_del_driver(&mxt_driver); } -module_init(qt602240_init); -module_exit(qt602240_exit); +module_init(mxt_init); +module_exit(mxt_exit); /* Module information */ MODULE_AUTHOR("Joonyoung Shim "); -MODULE_DESCRIPTION("AT42QT602240/ATMXT224 Touchscreen driver"); +MODULE_DESCRIPTION("Atmel maXTouch Touchscreen driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 26cdb1ae76f842e895ef4d09796a9101a7f8746b Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Fri, 4 Feb 2011 00:51:05 -0800 Subject: Input: atmel_mxt_ts - read whole message to make CHG low Read the whole message, as reading just the first byte isn't always guaranteed to clear the message. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 5dca78a00c94..162a3bf019e4 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -823,16 +823,16 @@ static int mxt_check_matrix_size(struct mxt_data *data) static int mxt_make_highchg(struct mxt_data *data) { struct device *dev = &data->client->dev; + struct mxt_message message; int count = 10; int error; - u8 val; /* Read dummy message to make high CHG pin */ do { - error = mxt_read_object(data, MXT_GEN_MESSAGE, 0, &val); + error = mxt_read_message(data, &message); if (error) return error; - } while ((val != 0xff) && --count); + } while (message.reportid != 0xff && --count); if (!count) { dev_err(dev, "CHG pin isn't cleared\n"); -- cgit v1.2.2 From 5d9d6e91b835796c21fbd7ce479880e5181be112 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Fri, 11 Feb 2011 01:10:44 -0800 Subject: Input: uinput - fix setting up device name The check for non-empty device name was botched since we tried to account for extra space for the terminating zero at the same time. Convert to kstrndup() to avoid this problem. Signed-off-by: David Herrmann Acked-by: Aristeu Rozanski Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 82542a1c1098..c0888e3d2fb4 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -347,8 +347,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu { struct uinput_user_dev *user_dev; struct input_dev *dev; - char *name; - int i, size; + int i; int retval; if (count != sizeof(struct uinput_user_dev)) @@ -373,19 +372,19 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu udev->ff_effects_max = user_dev->ff_effects_max; - size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1; - if (!size) { + /* Ensure name is filled in */ + if (!user_dev->name[0]) { retval = -EINVAL; goto exit; } kfree(dev->name); - dev->name = name = kmalloc(size, GFP_KERNEL); - if (!name) { + dev->name = kstrndup(user_dev->name, UINPUT_MAX_NAME_SIZE, + GFP_KERNEL); + if (!dev->name) { retval = -ENOMEM; goto exit; } - strlcpy(name, user_dev->name, size); dev->id.bustype = user_dev->id.bustype; dev->id.vendor = user_dev->id.vendor; -- cgit v1.2.2 From 4dfcc271d587465f0d181c7636453ba4d0ec8acc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 11 Feb 2011 01:10:45 -0800 Subject: Input: uinput - use memdup_user() and friends Instead of open-coding copying of data structures from userspace use memdup_user() and strndup_user(). Note that this introduces change in behavior because driver used to truncate 'phys' longer than 1024 bytes, but now it will refuse to set 'phys' that long. Arguably trying to set such 'phys' is suspect anyways. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index c0888e3d2fb4..7f8331f45bad 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -361,14 +361,9 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu dev = udev->dev; - user_dev = kmalloc(sizeof(struct uinput_user_dev), GFP_KERNEL); - if (!user_dev) - return -ENOMEM; - - if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) { - retval = -EFAULT; - goto exit; - } + user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev)); + if (!IS_ERR(user_dev)) + return PTR_ERR(user_dev); udev->ff_effects_max = user_dev->ff_effects_max; @@ -621,7 +616,6 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, struct uinput_ff_upload ff_up; struct uinput_ff_erase ff_erase; struct uinput_request *req; - int length; char *phys; retval = mutex_lock_interruptible(&udev->mutex); @@ -688,24 +682,15 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd, retval = -EINVAL; goto out; } - length = strnlen_user(p, 1024); - if (length <= 0) { - retval = -EFAULT; - break; + + phys = strndup_user(p, 1024); + if (IS_ERR(phys)) { + retval = PTR_ERR(phys); + goto out; } + kfree(udev->dev->phys); - udev->dev->phys = phys = kmalloc(length, GFP_KERNEL); - if (!phys) { - retval = -ENOMEM; - break; - } - if (copy_from_user(phys, p, length)) { - udev->dev->phys = NULL; - kfree(phys); - retval = -EFAULT; - break; - } - phys[length - 1] = '\0'; + udev->dev->phys = phys; break; case UI_BEGIN_FF_UPLOAD: -- cgit v1.2.2 From 6b7cfd193a00ba72efb19a05c486f96ae9297d0b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:49:05 -0800 Subject: Input: ad714x-i2c - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific PM operations in order to facilitate core work. Do this conversion for ad714x-i2c. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ad714x-i2c.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index 2bef8fa56c94..e21deb1baa8a 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -10,23 +10,23 @@ #include #include #include +#include #include "ad714x.h" #ifdef CONFIG_PM -static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message) +static int ad714x_i2c_suspend(struct device *dev) { - return ad714x_disable(i2c_get_clientdata(client)); + return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev))); } -static int ad714x_i2c_resume(struct i2c_client *client) +static int ad714x_i2c_resume(struct device *dev) { - return ad714x_enable(i2c_get_clientdata(client)); + return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev))); } -#else -# define ad714x_i2c_suspend NULL -# define ad714x_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume); + static int ad714x_i2c_write(struct device *dev, unsigned short reg, unsigned short data) { @@ -114,11 +114,10 @@ MODULE_DEVICE_TABLE(i2c, ad714x_id); static struct i2c_driver ad714x_i2c_driver = { .driver = { .name = "ad714x_captouch", + .pm = &ad714x_i2c_pm, }, .probe = ad714x_i2c_probe, .remove = __devexit_p(ad714x_i2c_remove), - .suspend = ad714x_i2c_suspend, - .resume = ad714x_i2c_resume, .id_table = ad714x_id, }; -- cgit v1.2.2 From a257090cd4e26b96667a15262f322e51f6582507 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:49:37 -0800 Subject: Input: ad714x-spi - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific PM operations in order to facilitate core work. Do this conversion for ad714x-spi. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ad714x-spi.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c index 7f8dedfd1bfe..4120dd549305 100644 --- a/drivers/input/misc/ad714x-spi.c +++ b/drivers/input/misc/ad714x-spi.c @@ -9,6 +9,7 @@ #include /* BUS_I2C */ #include #include +#include #include #include "ad714x.h" @@ -16,20 +17,19 @@ #define AD714x_SPI_READ BIT(10) #ifdef CONFIG_PM -static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message) +static int ad714x_spi_suspend(struct device *dev) { - return ad714x_disable(spi_get_drvdata(spi)); + return ad714x_disable(spi_get_drvdata(to_spi_device(dev))); } -static int ad714x_spi_resume(struct spi_device *spi) +static int ad714x_spi_resume(struct device *dev) { - return ad714x_enable(spi_get_drvdata(spi)); + return ad714x_enable(spi_get_drvdata(to_spi_device(dev))); } -#else -# define ad714x_spi_suspend NULL -# define ad714x_spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume); + static int ad714x_spi_read(struct device *dev, unsigned short reg, unsigned short *data) { @@ -79,11 +79,10 @@ static struct spi_driver ad714x_spi_driver = { .driver = { .name = "ad714x_captouch", .owner = THIS_MODULE, + .pm = &ad714x_spi_pm, }, .probe = ad714x_spi_probe, .remove = __devexit_p(ad714x_spi_remove), - .suspend = ad714x_spi_suspend, - .resume = ad714x_spi_resume, }; static __init int ad714x_spi_init(void) -- cgit v1.2.2 From 65b0c03852d75e4d7d0bc282344b1500fe471725 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:50:37 -0800 Subject: Input: lm8323 - convert to dev_pm_ops There is a general move away from bus specific PM operations to using dev_pm_ops in order to facilicate core improvements. Update lm8323 to the new model. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lm8323.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index f7c2a166576b..b732870ecc89 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -802,8 +803,9 @@ static int __devexit lm8323_remove(struct i2c_client *client) * We don't need to explicitly suspend the chip, as it already switches off * when there's no activity. */ -static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg) +static int lm8323_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct lm8323_chip *lm = i2c_get_clientdata(client); int i; @@ -821,8 +823,9 @@ static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int lm8323_resume(struct i2c_client *client) +static int lm8323_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct lm8323_chip *lm = i2c_get_clientdata(client); int i; @@ -839,11 +842,10 @@ static int lm8323_resume(struct i2c_client *client) return 0; } -#else -#define lm8323_suspend NULL -#define lm8323_resume NULL #endif +static SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume); + static const struct i2c_device_id lm8323_id[] = { { "lm8323", 0 }, { } @@ -852,11 +854,10 @@ static const struct i2c_device_id lm8323_id[] = { static struct i2c_driver lm8323_i2c_driver = { .driver = { .name = "lm8323", + .pm = &lm8323_pm_ops, }, .probe = lm8323_probe, .remove = __devexit_p(lm8323_remove), - .suspend = lm8323_suspend, - .resume = lm8323_resume, .id_table = lm8323_id, }; MODULE_DEVICE_TABLE(i2c, lm8323_id); -- cgit v1.2.2 From 76e2c68f3214c3a641b9e489cdaea035bfbc8060 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:51:13 -0800 Subject: Input: max7359 - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific ops to facilitate core work. Do this conversion for max7359. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/max7359_keypad.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index 9091ff5ea808..5afe35ad24d3 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -271,8 +272,10 @@ static int __devexit max7359_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int max7359_suspend(struct i2c_client *client, pm_message_t mesg) +static int max7359_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + max7359_fall_deepsleep(client); if (device_may_wakeup(&client->dev)) @@ -281,8 +284,10 @@ static int max7359_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int max7359_resume(struct i2c_client *client) +static int max7359_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + if (device_may_wakeup(&client->dev)) disable_irq_wake(client->irq); @@ -291,11 +296,10 @@ static int max7359_resume(struct i2c_client *client) return 0; } -#else -#define max7359_suspend NULL -#define max7359_resume NULL #endif +static SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume); + static const struct i2c_device_id max7359_ids[] = { { "max7359", 0 }, { } @@ -305,11 +309,10 @@ MODULE_DEVICE_TABLE(i2c, max7359_ids); static struct i2c_driver max7359_i2c_driver = { .driver = { .name = "max7359", + .pm = &max7359_pm, }, .probe = max7359_probe, .remove = __devexit_p(max7359_remove), - .suspend = max7359_suspend, - .resume = max7359_resume, .id_table = max7359_ids, }; -- cgit v1.2.2 From fbb899356d4a6b6080ab3d9656914938db49449e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:51:52 -0800 Subject: Input: adxl34x-i2c - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific ones in order to facilitate core development. Do this conversion for adxl34x-i2c. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x-i2c.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index 0779724af7e7..ccacf2bb06a4 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "adxl34x.h" static int adxl34x_smbus_read(struct device *dev, unsigned char reg) @@ -105,8 +106,9 @@ static int __devexit adxl34x_i2c_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message) +static int adxl34x_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct adxl34x *ac = i2c_get_clientdata(client); adxl34x_suspend(ac); @@ -114,19 +116,20 @@ static int adxl34x_i2c_suspend(struct i2c_client *client, pm_message_t message) return 0; } -static int adxl34x_i2c_resume(struct i2c_client *client) +static int adxl34x_i2c_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct adxl34x *ac = i2c_get_clientdata(client); adxl34x_resume(ac); return 0; } -#else -# define adxl34x_i2c_suspend NULL -# define adxl34x_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend, + adxl34x_i2c_resume); + static const struct i2c_device_id adxl34x_id[] = { { "adxl34x", 0 }, { } @@ -138,11 +141,10 @@ static struct i2c_driver adxl34x_driver = { .driver = { .name = "adxl34x", .owner = THIS_MODULE, + .pm = &adxl34x_i2c_pm, }, .probe = adxl34x_i2c_probe, .remove = __devexit_p(adxl34x_i2c_remove), - .suspend = adxl34x_i2c_suspend, - .resume = adxl34x_i2c_resume, .id_table = adxl34x_id, }; -- cgit v1.2.2 From 4d1ac94e2e3cd15f06ffc74efa42d6572fdf7689 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 09:22:40 -0800 Subject: Input: adxl34x-spi - convert to dev_pm_ops There is a general move to convert drivers to use dev_pm_ops rather than bus specific ones in order to facilitate core development. Do this conversion for adxl34x-spi. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x-spi.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 782de9e89828..5231add66a65 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -10,6 +10,7 @@ #include /* BUS_SPI */ #include #include +#include #include #include "adxl34x.h" @@ -94,8 +95,9 @@ static int __devexit adxl34x_spi_remove(struct spi_device *spi) } #ifdef CONFIG_PM -static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message) +static int adxl34x_spi_suspend(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct adxl34x *ac = dev_get_drvdata(&spi->dev); adxl34x_suspend(ac); @@ -103,29 +105,29 @@ static int adxl34x_spi_suspend(struct spi_device *spi, pm_message_t message) return 0; } -static int adxl34x_spi_resume(struct spi_device *spi) +static int adxl34x_spi_resume(struct device *dev) { + struct spi_device *spi = to_spi_device(dev); struct adxl34x *ac = dev_get_drvdata(&spi->dev); adxl34x_resume(ac); return 0; } -#else -# define adxl34x_spi_suspend NULL -# define adxl34x_spi_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend, + adxl34x_spi_resume); + static struct spi_driver adxl34x_driver = { .driver = { .name = "adxl34x", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &adxl34x_spi_pm, }, .probe = adxl34x_spi_probe, .remove = __devexit_p(adxl34x_spi_remove), - .suspend = adxl34x_spi_suspend, - .resume = adxl34x_spi_resume, }; static int __init adxl34x_spi_init(void) -- cgit v1.2.2 From 3dcab3bdd9cbf45433fc4e1514f3144638652e2b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:53:04 -0800 Subject: Input: adxl34x - fix references to adx134x The adxl34x SPI driver has what appears to be a typo referring to the device as adx134x with the numeral 1 rather than letter l. This appears to be an error so convert. Signed-off-by: Mark Brown Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c index 5231add66a65..f29de22fdda0 100644 --- a/drivers/input/misc/adxl34x-spi.c +++ b/drivers/input/misc/adxl34x-spi.c @@ -58,7 +58,7 @@ static int adxl34x_spi_read_block(struct device *dev, return (status < 0) ? status : 0; } -static const struct adxl34x_bus_ops adx134x_spi_bops = { +static const struct adxl34x_bus_ops adxl34x_spi_bops = { .bustype = BUS_SPI, .write = adxl34x_spi_write, .read = adxl34x_spi_read, @@ -77,7 +77,7 @@ static int __devinit adxl34x_spi_probe(struct spi_device *spi) ac = adxl34x_probe(&spi->dev, spi->irq, spi->max_speed_hz > MAX_FREQ_NO_FIFODELAY, - &adx134x_spi_bops); + &adxl34x_spi_bops); if (IS_ERR(ac)) return PTR_ERR(ac); -- cgit v1.2.2 From 87b2c7df329e547c1905e0b7e13bfce09cfa5cfe Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 11 Feb 2011 08:53:33 -0800 Subject: Input: synaptics_i2c - convert to dev_pm_ops There is a general move to convert drivers to dev_pm_ops rather than bus specific PM ops in order to facilitate core development. Do this converison for synaptics-i2c. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 0ae62f0bcb32..f6aa26d305ed 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -18,6 +18,7 @@ #include #include #include +#include #define DRIVER_NAME "synaptics_i2c" /* maximum product id is 15 characters */ @@ -619,8 +620,9 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +static int synaptics_i2c_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct synaptics_i2c *touch = i2c_get_clientdata(client); cancel_delayed_work_sync(&touch->dwork); @@ -631,9 +633,10 @@ static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int synaptics_i2c_resume(struct i2c_client *client) +static int synaptics_i2c_resume(struct device *dev) { int ret; + struct i2c_client *client = to_i2c_client(dev); struct synaptics_i2c *touch = i2c_get_clientdata(client); ret = synaptics_i2c_reset_config(client); @@ -645,11 +648,11 @@ static int synaptics_i2c_resume(struct i2c_client *client) return 0; } -#else -#define synaptics_i2c_suspend NULL -#define synaptics_i2c_resume NULL #endif +static SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend, + synaptics_i2c_resume); + static const struct i2c_device_id synaptics_i2c_id_table[] = { { "synaptics_i2c", 0 }, { }, @@ -660,13 +663,12 @@ static struct i2c_driver synaptics_i2c_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, + .pm = &synaptics_i2c_pm, }, .probe = synaptics_i2c_probe, .remove = __devexit_p(synaptics_i2c_remove), - .suspend = synaptics_i2c_suspend, - .resume = synaptics_i2c_resume, .id_table = synaptics_i2c_id_table, }; -- cgit v1.2.2 From 46ee2a05a466ca7e34d65fe3feba195d62109362 Mon Sep 17 00:00:00 2001 From: Chris Leech Date: Tue, 15 Feb 2011 13:36:52 -0800 Subject: Input: atmel_mxt_ts - add mXT224 identifier to id_table "mXT224" is used in the Intel mid firmware in SFI tables to identify the presence of this I2C device. Signed-off-by: Chris Leech Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 162a3bf019e4..fe8902e1f010 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1371,6 +1371,7 @@ static const struct dev_pm_ops mxt_pm_ops = { static const struct i2c_device_id mxt_id[] = { { "qt602240_ts", 0 }, { "atmel_mxt_ts", 0 }, + { "mXT224", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, mxt_id); -- cgit v1.2.2 From 71749f5c66e797a39600dae9de58aab3858dc488 Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Tue, 15 Feb 2011 13:36:52 -0800 Subject: Input: atmel_mxt_ts - allow board code to suppliy controller config As there is no common configuration settings that would work in every situation, remove the fixed config data from driver code and add config data to platform data. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 148 +++---------------------------- 1 file changed, 13 insertions(+), 135 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index fe8902e1f010..52032ef3d3ab 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -199,122 +199,6 @@ #define MXT_MAX_FINGER 10 -/* Initial register values recommended from chip vendor */ -static const u8 init_vals_ver_20[] = { - /* MXT_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* MXT_GEN_ACQUIRE(8) */ - 0x08, 0x05, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, - /* MXT_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x64, - /* MXT_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, - /* MXT_PROCI_GRIPFACE(20) */ - 0x00, 0x64, 0x64, 0x64, 0x64, 0x00, 0x00, 0x1e, 0x14, 0x04, - 0x1e, 0x00, - /* MXT_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x19, 0x00, 0xe7, 0xff, 0x04, 0x32, 0x00, - 0x01, 0x0a, 0x0f, 0x14, 0x00, 0x00, 0xe8, - /* MXT_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* MXT_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x04, 0x08, -}; - -static const u8 init_vals_ver_21[] = { - /* MXT_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* MXT_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* MXT_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* MXT_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* MXT_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - /* MXT_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - -static const u8 init_vals_ver_22[] = { - /* MXT_GEN_COMMAND(6) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_GEN_POWER(7) */ - 0x20, 0xff, 0x32, - /* MXT_GEN_ACQUIRE(8) */ - 0x0a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x09, 0x23, - /* MXT_TOUCH_MULTI(9) */ - 0x00, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x01, 0x01, 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_TOUCH_KEYARRAY(15) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, - /* MXT_SPT_GPIOPWM(19) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_GRIPFACE(20) */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x28, 0x04, - 0x0f, 0x0a, - /* MXT_PROCG_NOISE(22) */ - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x23, 0x00, - 0x00, 0x05, 0x0f, 0x19, 0x23, 0x2d, 0x03, - /* MXT_TOUCH_PROXIMITY(23) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_ONETOUCH(24) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_SELFTEST(25) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - /* MXT_PROCI_TWOTOUCH(27) */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* MXT_SPT_CTECONFIG(28) */ - 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, -}; - struct mxt_info { u8 family_id; u8 variant_id; @@ -714,26 +598,15 @@ end: static int mxt_check_reg_init(struct mxt_data *data) { + const struct mxt_platform_data *pdata = data->pdata; struct mxt_object *object; struct device *dev = &data->client->dev; int index = 0; - int i, j; - u8 version = data->info.version; - u8 *init_vals; + int i, j, config_offset; - switch (version) { - case MXT_VER_20: - init_vals = (u8 *)init_vals_ver_20; - break; - case MXT_VER_21: - init_vals = (u8 *)init_vals_ver_21; - break; - case MXT_VER_22: - init_vals = (u8 *)init_vals_ver_22; - break; - default: - dev_err(dev, "Firmware version %d doesn't support\n", version); - return -EINVAL; + if (!pdata->config) { + dev_dbg(dev, "No cfg data defined, skipping reg init\n"); + return 0; } for (i = 0; i < data->info.object_num; i++) { @@ -742,10 +615,15 @@ static int mxt_check_reg_init(struct mxt_data *data) if (!mxt_object_writable(object->type)) continue; - for (j = 0; j < object->size + 1; j++) + for (j = 0; j < object->size + 1; j++) { + config_offset = index + j; + if (config_offset > pdata->config_length) { + dev_err(dev, "Not enough config data!\n"); + return -EINVAL; + } mxt_write_object(data, object->type, j, - init_vals[index + j]); - + pdata->config[config_offset]); + } index += object->size + 1; } -- cgit v1.2.2 From 919ed895f0b4227da26ea1b0a1347db5010f105e Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Tue, 15 Feb 2011 13:36:52 -0800 Subject: Input: atmel_mxt_ts - allow board code to specify IRQ flags Different board have different requirements/setups so let's be more flexible. Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 52032ef3d3ab..d2e5864ca096 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1106,11 +1106,12 @@ static void mxt_input_close(struct input_dev *dev) static int __devinit mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct mxt_platform_data *pdata = client->dev.platform_data; struct mxt_data *data; struct input_dev *input_dev; int error; - if (!client->dev.platform_data) + if (!pdata) return -EINVAL; data = kzalloc(sizeof(struct mxt_data), GFP_KERNEL); @@ -1149,7 +1150,7 @@ static int __devinit mxt_probe(struct i2c_client *client, data->client = client; data->input_dev = input_dev; - data->pdata = client->dev.platform_data; + data->pdata = pdata; data->irq = client->irq; i2c_set_clientdata(client, data); @@ -1159,7 +1160,7 @@ static int __devinit mxt_probe(struct i2c_client *client, goto err_free_object; error = request_threaded_irq(client->irq, NULL, mxt_interrupt, - IRQF_TRIGGER_FALLING, client->dev.driver->name, data); + pdata->irqflags, client->dev.driver->name, data); if (error) { dev_err(&client->dev, "Failed to register interrupt\n"); goto err_free_object; -- cgit v1.2.2 From 163d27706bb91a648cc292151fc072e1e8cd4b4d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 18 Feb 2011 08:30:52 -0800 Subject: Input: uinput - reversed test in uinput_setup_device() The test here is reversed. It should be if (IS_ERR()) instead of if (!IS_ERR()). Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 7f8331f45bad..364bdf43a381 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -362,7 +362,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu dev = udev->dev; user_dev = memdup_user(buffer, sizeof(struct uinput_user_dev)); - if (!IS_ERR(user_dev)) + if (IS_ERR(user_dev)) return PTR_ERR(user_dev); udev->ff_effects_max = user_dev->ff_effects_max; -- cgit v1.2.2 From f722e17fdb2c97bbec2563636dd88489cdb1428b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 8 Jan 2011 19:12:26 +0100 Subject: power_supply: Ignore -ENODATA errors when generating uevents Sometimes a driver can not report a meaningful value for a certain property and returns -ENODATA. Currently when generating a uevent and a property return -ENODATA it is treated as an error an no uevent is generated at all. This is not an desirable behavior. This patch adds a special case for -ENODATA and ignores properties which return this error code when generating the uevent. Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/power_supply_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index cd1f90754a3a..605514afc29f 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -270,7 +270,7 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) attr = &power_supply_attrs[psy->properties[j]]; ret = power_supply_show_property(dev, attr, prop_buf); - if (ret == -ENODEV) { + if (ret == -ENODEV || ret == -ENODATA) { /* When a battery is absent, we expect -ENODEV. Don't abort; send the uevent with at least the the PRESENT=0 property */ ret = 0; -- cgit v1.2.2 From 97774672573ac4355bd12cf84b202555c1131b69 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 21 Feb 2011 15:34:19 +0100 Subject: power_supply: Initialize changed_work before calling device_add Calling device_add causes an inital uevent for that device to be generated. The power_supply uevent function calls the drivers get_property function, which might causes the driver to update its state, which again might causes the driver to call power_supply_changed(). Since the power_supplys changed_work has not been initialized at this point the behavior is undefined and can result in an OOPS. This patch fixes the issue by initializing the power_supplys changed_work prior to adding the power_supplys device to the device tree. Reported-by: Grazvydas Ignotas Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/power_supply_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 970f7335d3a7..329b46b2327d 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -171,6 +171,8 @@ int power_supply_register(struct device *parent, struct power_supply *psy) dev_set_drvdata(dev, psy); psy->dev = dev; + INIT_WORK(&psy->changed_work, power_supply_changed_work); + rc = kobject_set_name(&dev->kobj, "%s", psy->name); if (rc) goto kobject_set_name_failed; @@ -179,8 +181,6 @@ int power_supply_register(struct device *parent, struct power_supply *psy) if (rc) goto device_add_failed; - INIT_WORK(&psy->changed_work, power_supply_changed_work); - rc = power_supply_create_triggers(psy); if (rc) goto create_triggers_failed; -- cgit v1.2.2 From 5661f334e8a53848552c8763f3bd63d0672b2e7b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 24 May 2010 20:36:52 +0200 Subject: bq27x00: Add type property This patch adds the type property to the bq27x00 battery driver. All bq27x00 are lithium ion batteries. Signed-off-by: Lars-Peter Clausen Acked-by: Rodolfo Giometti Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index eff0273d4030..bb043f93cead 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -78,6 +78,7 @@ static enum power_supply_property bq27x00_battery_props[] = { POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, }; /* @@ -277,6 +278,9 @@ static int bq27x00_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val); break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; default: return -EINVAL; } -- cgit v1.2.2 From 0e9f30497e88600ba52013665270f543bb94f0d8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 24 May 2010 20:20:57 +0200 Subject: bq27x00: Improve temperature property precession This patch improves the precession of the temperature property of the bq27x00 driver. By dividing before multiplying the current code effectively cuts of the last decimal digit. This patch fixes it by multiplying before dividing. Signed-off-by: Lars-Peter Clausen Acked-by: Rodolfo Giometti Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index bb043f93cead..4f7465999c86 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -109,7 +109,7 @@ static int bq27x00_battery_temperature(struct bq27x00_device_info *di) if (di->chip == BQ27500) return temp - 2731; else - return ((temp >> 2) - 273) * 10; + return ((temp * 5) - 5463) / 2; } /* -- cgit v1.2.2 From a2e5118c370e78c3841606e7edc7677c986325fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Mon, 24 May 2010 20:52:13 +0200 Subject: bq27x00: Fix CURRENT_NOW property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the bq27000 datasheet the current should be calculated by the following formula: current = AI * 3570 / 20 This patch adjust the drivers code accordingly. Signed-off-by: Pali Rohár Signed-off-by: Lars-Peter Clausen Acked-by: Rodolfo Giometti Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 4f7465999c86..1b06134e0ae8 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -44,6 +44,8 @@ #define BQ27500_FLAG_DSC BIT(0) #define BQ27500_FLAG_FC BIT(9) +#define BQ27000_RS 20 /* Resistor sense */ + /* If the system has several batteries we need a different name for each * of them... */ @@ -149,7 +151,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di) if (di->chip == BQ27500) { /* bq27500 returns signed value */ - curr = (int)(s16)curr; + curr = (int)((s16)curr) * 1000; } else { ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); if (ret < 0) { @@ -160,9 +162,10 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di) dev_dbg(di->dev, "negative current!\n"); curr = -curr; } + curr = curr * 3570 / BQ27000_RS; } - return curr * 1000; + return curr; } /* -- cgit v1.2.2 From 3413b4ea250ff0b4142a154a2764e33979957e8b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 24 May 2010 21:57:33 +0200 Subject: bq27x00: Return -ENODEV for properties if the battery is not present This patch changes get_property callback of the bq27x00 battery to return -ENODEV for properties other then the PROP_PRESENT if the battery is not present. The power subsystem core expects a driver to behave that way. Signed-off-by: Lars-Peter Clausen Acked-by: Rodolfo Giometti Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 1b06134e0ae8..9f16666dc466 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -252,16 +252,21 @@ static int bq27x00_battery_get_property(struct power_supply *psy, { int ret = 0; struct bq27x00_device_info *di = to_bq27x00_device_info(psy); + int voltage = bq27x00_battery_voltage(di); + + if (psp != POWER_SUPPLY_PROP_PRESENT && voltage <= 0) + return -ENODEV; switch (psp) { case POWER_SUPPLY_PROP_STATUS: ret = bq27x00_battery_status(di, val); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = voltage; + break; case POWER_SUPPLY_PROP_PRESENT: - val->intval = bq27x00_battery_voltage(di); if (psp == POWER_SUPPLY_PROP_PRESENT) - val->intval = val->intval <= 0 ? 0 : 1; + val->intval = voltage <= 0 ? 0 : 1; break; case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = bq27x00_battery_current(di); -- cgit v1.2.2 From a40402ef0bf3b6e53a7dfd396e9487eb2f613e19 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 24 May 2010 19:37:58 +0200 Subject: bq27x00: Prepare code for addition of bq27000 platform driver This patch simplifies the drivers data structure and moves code to be shared by the bq27000 and bq27200/bq27500 init functions into a common function. This patch has no functional changes, it only moves code around. Signed-off-by: Lars-Peter Clausen Acked-by: Rodolfo Giometti Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 86 +++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 9f16666dc466..def951d8fc2b 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -54,8 +54,8 @@ static DEFINE_MUTEX(battery_mutex); struct bq27x00_device_info; struct bq27x00_access_methods { - int (*read)(u8 reg, int *rt_value, int b_single, - struct bq27x00_device_info *di); + int (*read)(struct bq27x00_device_info *, u8 reg, int *rt_value, + bool single); }; enum bq27x00_chip { BQ27000, BQ27500 }; @@ -63,11 +63,11 @@ enum bq27x00_chip { BQ27000, BQ27500 }; struct bq27x00_device_info { struct device *dev; int id; - struct bq27x00_access_methods *bus; - struct power_supply bat; enum bq27x00_chip chip; - struct i2c_client *client; + struct power_supply bat; + + struct bq27x00_access_methods bus; }; static enum power_supply_property bq27x00_battery_props[] = { @@ -87,10 +87,10 @@ static enum power_supply_property bq27x00_battery_props[] = { * Common code for BQ27x00 devices */ -static int bq27x00_read(u8 reg, int *rt_value, int b_single, - struct bq27x00_device_info *di) +static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, + int *rt_value, bool single) { - return di->bus->read(reg, rt_value, b_single, di); + return di->bus.read(di, reg, rt_value, single); } /* @@ -102,7 +102,7 @@ static int bq27x00_battery_temperature(struct bq27x00_device_info *di) int ret; int temp = 0; - ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di); + ret = bq27x00_read(di, BQ27x00_REG_TEMP, &temp, false); if (ret) { dev_err(di->dev, "error reading temperature\n"); return ret; @@ -123,7 +123,7 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di) int ret; int volt = 0; - ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di); + ret = bq27x00_read(di, BQ27x00_REG_VOLT, &volt, false); if (ret) { dev_err(di->dev, "error reading voltage\n"); return ret; @@ -143,7 +143,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di) int curr = 0; int flags = 0; - ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di); + ret = bq27x00_read(di, BQ27x00_REG_AI, &curr, false); if (ret) { dev_err(di->dev, "error reading current\n"); return 0; @@ -153,7 +153,7 @@ static int bq27x00_battery_current(struct bq27x00_device_info *di) /* bq27500 returns signed value */ curr = (int)((s16)curr) * 1000; } else { - ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); + ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return 0; @@ -178,9 +178,9 @@ static int bq27x00_battery_rsoc(struct bq27x00_device_info *di) int rsoc = 0; if (di->chip == BQ27500) - ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di); + ret = bq27x00_read(di, BQ27500_REG_SOC, &rsoc, false); else - ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di); + ret = bq27x00_read(di, BQ27000_REG_RSOC, &rsoc, true); if (ret) { dev_err(di->dev, "error reading relative State-of-Charge\n"); return ret; @@ -196,7 +196,7 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, int status; int ret; - ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di); + ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false); if (ret < 0) { dev_err(di->dev, "error reading flags\n"); return ret; @@ -230,7 +230,7 @@ static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg, int tval = 0; int ret; - ret = bq27x00_read(reg, &tval, 0, di); + ret = bq27x00_read(di, reg, &tval, false); if (ret) { dev_err(di->dev, "error reading register %02x\n", reg); return ret; @@ -296,23 +296,35 @@ static int bq27x00_battery_get_property(struct power_supply *psy, return ret; } -static void bq27x00_powersupply_init(struct bq27x00_device_info *di) +static int bq27x00_powersupply_init(struct bq27x00_device_info *di) { + int ret; + di->bat.type = POWER_SUPPLY_TYPE_BATTERY; di->bat.properties = bq27x00_battery_props; di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); di->bat.get_property = bq27x00_battery_get_property; di->bat.external_power_changed = NULL; + + ret = power_supply_register(di->dev, &di->bat); + if (ret) { + dev_err(di->dev, "failed to register battery: %d\n", ret); + return ret; + } + + dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); + + return 0; } /* * i2c specific code */ -static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single, - struct bq27x00_device_info *di) +static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, + int *rt_value, bool single) { - struct i2c_client *client = di->client; + struct i2c_client *client = to_i2c_client(di->dev); struct i2c_msg msg[1]; unsigned char data[2]; int err; @@ -329,7 +341,7 @@ static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single, err = i2c_transfer(client->adapter, msg, 1); if (err >= 0) { - if (!b_single) + if (!single) msg->len = 2; else msg->len = 1; @@ -337,7 +349,7 @@ static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single, msg->flags = I2C_M_RD; err = i2c_transfer(client->adapter, msg, 1); if (err >= 0) { - if (!b_single) + if (!single) *rt_value = get_unaligned_le16(data); else *rt_value = data[0]; @@ -353,7 +365,6 @@ static int bq27x00_battery_probe(struct i2c_client *client, { char *name; struct bq27x00_device_info *di; - struct bq27x00_access_methods *bus; int num; int retval = 0; @@ -380,38 +391,20 @@ static int bq27x00_battery_probe(struct i2c_client *client, retval = -ENOMEM; goto batt_failed_2; } + di->id = num; + di->dev = &client->dev; di->chip = id->driver_data; + di->bat.name = name; + di->bus.read = &bq27x00_read_i2c; - bus = kzalloc(sizeof(*bus), GFP_KERNEL); - if (!bus) { - dev_err(&client->dev, "failed to allocate access method " - "data\n"); - retval = -ENOMEM; + if (bq27x00_powersupply_init(di)) goto batt_failed_3; - } i2c_set_clientdata(client, di); - di->dev = &client->dev; - di->bat.name = name; - bus->read = &bq27x00_read_i2c; - di->bus = bus; - di->client = client; - - bq27x00_powersupply_init(di); - - retval = power_supply_register(&client->dev, &di->bat); - if (retval) { - dev_err(&client->dev, "failed to register battery\n"); - goto batt_failed_4; - } - - dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION); return 0; -batt_failed_4: - kfree(bus); batt_failed_3: kfree(di); batt_failed_2: @@ -430,7 +423,6 @@ static int bq27x00_battery_remove(struct i2c_client *client) power_supply_unregister(&di->bat); - kfree(di->bus); kfree(di->bat.name); mutex_lock(&battery_mutex); -- cgit v1.2.2 From 7fb7ba588c0f276609609565b21fcc853284a9a0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 24 May 2010 19:55:27 +0200 Subject: bq27x00: Add bq27000 support This patch adds support for the bq27000 battery to the bq27x00 driver. The bq27000 is similar to the bq27200 except that it uses the HDQ bus instead of I2C to communicate with the host system. The driver is implemented as a platform driver. The driver expects to be provided with a read callback function through its platform data. The read function is assumed to do the lowlevel HDQ handling and read out the value of a certain register. Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/Kconfig | 14 +++ drivers/power/bq27x00_battery.c | 184 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 183 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 61bf5d724139..52a462fc6b84 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -117,10 +117,24 @@ config BATTERY_BQ20Z75 config BATTERY_BQ27x00 tristate "BQ27x00 battery driver" + help + Say Y here to enable support for batteries with BQ27x00 (I2C/HDQ) chips. + +config BATTERY_BQ27X00_I2C + bool "BQ27200/BQ27500 support" + depends on BATTERY_BQ27x00 depends on I2C + default y help Say Y here to enable support for batteries with BQ27x00 (I2C) chips. +config BATTERY_BQ27X00_PLATFORM + bool "BQ27000 support" + depends on BATTERY_BQ27x00 + default y + help + Say Y here to enable support for batteries with BQ27000 (HDQ) chips. + config BATTERY_DA9030 tristate "DA9030 battery driver" depends on PMIC_DA903X diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index def951d8fc2b..44bc76be0780 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -3,6 +3,7 @@ * * Copyright (C) 2008 Rodolfo Giometti * Copyright (C) 2008 Eurotech S.p.A. + * Copyright (C) 2010-2011 Lars-Peter Clausen * * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. * @@ -27,6 +28,8 @@ #include #include +#include + #define DRIVER_VERSION "1.1.0" #define BQ27x00_REG_TEMP 0x06 @@ -46,12 +49,6 @@ #define BQ27000_RS 20 /* Resistor sense */ -/* If the system has several batteries we need a different name for each - * of them... - */ -static DEFINE_IDR(battery_id); -static DEFINE_MUTEX(battery_mutex); - struct bq27x00_device_info; struct bq27x00_access_methods { int (*read)(struct bq27x00_device_info *, u8 reg, int *rt_value, @@ -317,9 +314,15 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) return 0; } -/* - * i2c specific code + +/* i2c specific code */ +#ifdef CONFIG_BATTERY_BQ27X00_I2C + +/* If the system has several batteries we need a different name for each + * of them... */ +static DEFINE_IDR(battery_id); +static DEFINE_MUTEX(battery_mutex); static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, int *rt_value, bool single) @@ -434,10 +437,6 @@ static int bq27x00_battery_remove(struct i2c_client *client) return 0; } -/* - * Module stuff - */ - static const struct i2c_device_id bq27x00_id[] = { { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */ { "bq27500", BQ27500 }, @@ -453,13 +452,167 @@ static struct i2c_driver bq27x00_battery_driver = { .id_table = bq27x00_id, }; +static inline int bq27x00_battery_i2c_init(void) +{ + int ret = i2c_add_driver(&bq27x00_battery_driver); + if (ret) + printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n"); + + return ret; +} + +static inline void bq27x00_battery_i2c_exit(void) +{ + i2c_del_driver(&bq27x00_battery_driver); +} + +#else + +static inline int bq27x00_battery_i2c_init(void) { return 0; } +static inline void bq27x00_battery_i2c_exit(void) {}; + +#endif + +/* platform specific code */ +#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM + +static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, + int *rt_value, bool single) +{ + struct device *dev = di->dev; + struct bq27000_platform_data *pdata = dev->platform_data; + unsigned int timeout = 3; + int upper, lower; + int temp; + + if (!single) { + /* Make sure the value has not changed in between reading the + * lower and the upper part */ + upper = pdata->read(dev, reg + 1); + do { + temp = upper; + if (upper < 0) + return upper; + + lower = pdata->read(dev, reg); + if (lower < 0) + return lower; + + upper = pdata->read(dev, reg + 1); + } while (temp != upper && --timeout); + + if (timeout == 0) + return -EIO; + + *rt_value = (upper << 8) | lower; + } else { + lower = pdata->read(dev, reg); + if (lower < 0) + return lower; + *rt_value = lower; + } + return 0; +} + +static int __devinit bq27000_battery_probe(struct platform_device *pdev) +{ + struct bq27x00_device_info *di; + struct bq27000_platform_data *pdata = pdev->dev.platform_data; + int ret; + + if (!pdata) { + dev_err(&pdev->dev, "no platform_data supplied\n"); + return -EINVAL; + } + + if (!pdata->read) { + dev_err(&pdev->dev, "no hdq read callback supplied\n"); + return -EINVAL; + } + + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) { + dev_err(&pdev->dev, "failed to allocate device info data\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, di); + + di->dev = &pdev->dev; + di->chip = BQ27000; + + di->bat.name = pdata->name ?: dev_name(&pdev->dev); + di->bus.read = &bq27000_read_platform; + + ret = bq27x00_powersupply_init(di); + if (ret) + goto err_free; + + return 0; + +err_free: + platform_set_drvdata(pdev, NULL); + kfree(di); + + return ret; +} + +static int __devexit bq27000_battery_remove(struct platform_device *pdev) +{ + struct bq27x00_device_info *di = platform_get_drvdata(pdev); + + power_supply_unregister(&di->bat); + platform_set_drvdata(pdev, NULL); + kfree(di); + + return 0; +} + +static struct platform_driver bq27000_battery_driver = { + .probe = bq27000_battery_probe, + .remove = __devexit_p(bq27000_battery_remove), + .driver = { + .name = "bq27000-battery", + .owner = THIS_MODULE, + }, +}; + +static inline int bq27x00_battery_platform_init(void) +{ + int ret = platform_driver_register(&bq27000_battery_driver); + if (ret) + printk(KERN_ERR "Unable to register BQ27000 platform driver\n"); + + return ret; +} + +static inline void bq27x00_battery_platform_exit(void) +{ + platform_driver_unregister(&bq27000_battery_driver); +} + +#else + +static inline int bq27x00_battery_platform_init(void) { return 0; } +static inline void bq27x00_battery_platform_exit(void) {}; + +#endif + +/* + * Module stuff + */ + static int __init bq27x00_battery_init(void) { int ret; - ret = i2c_add_driver(&bq27x00_battery_driver); + ret = bq27x00_battery_i2c_init(); + if (ret) + return ret; + + ret = bq27x00_battery_platform_init(); if (ret) - printk(KERN_ERR "Unable to register BQ27x00 driver\n"); + bq27x00_battery_i2c_exit(); return ret; } @@ -467,7 +620,8 @@ module_init(bq27x00_battery_init); static void __exit bq27x00_battery_exit(void) { - i2c_del_driver(&bq27x00_battery_driver); + bq27x00_battery_platform_exit(); + bq27x00_battery_i2c_exit(); } module_exit(bq27x00_battery_exit); -- cgit v1.2.2 From 297a533b3e621be520d44d8baf3bb72ce15c4110 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Jan 2011 20:12:47 +0100 Subject: bq27x00: Cache battery registers This patch adds a register cache to the bq27x00 battery driver. Usually multiple, if not all, power_supply properties are queried at once, for example when an uevent is generated. Since some registers are used by multiple properties caching the registers should reduce the number of reads. The cache is valid for 5 seconds this roughly matches the internal update interval of the current register for the bq27000/bq27200. Fast changing properties(*_NOW) which can be obtained by reading a single register are not cached. It will also be used in the follow up patch to check if the battery status has been changed since the last update to emit power_supply_changed events. Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 271 ++++++++++++++++++++++------------------ 1 file changed, 150 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 44bc76be0780..dbe3fcb3b0ba 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -51,17 +51,30 @@ struct bq27x00_device_info; struct bq27x00_access_methods { - int (*read)(struct bq27x00_device_info *, u8 reg, int *rt_value, - bool single); + int (*read)(struct bq27x00_device_info *di, u8 reg, bool single); }; enum bq27x00_chip { BQ27000, BQ27500 }; +struct bq27x00_reg_cache { + int temperature; + int time_to_empty; + int time_to_empty_avg; + int time_to_full; + int capacity; + int flags; + + int current_now; +}; + struct bq27x00_device_info { struct device *dev; int id; enum bq27x00_chip chip; + struct bq27x00_reg_cache cache; + unsigned long last_update; + struct power_supply bat; struct bq27x00_access_methods bus; @@ -85,48 +98,93 @@ static enum power_supply_property bq27x00_battery_props[] = { */ static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg, - int *rt_value, bool single) + bool single) { - return di->bus.read(di, reg, rt_value, single); + return di->bus.read(di, reg, single); } /* - * Return the battery temperature in tenths of degree Celsius + * Return the battery Relative State-of-Charge * Or < 0 if something fails. */ -static int bq27x00_battery_temperature(struct bq27x00_device_info *di) +static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) { - int ret; - int temp = 0; - - ret = bq27x00_read(di, BQ27x00_REG_TEMP, &temp, false); - if (ret) { - dev_err(di->dev, "error reading temperature\n"); - return ret; - } + int rsoc; if (di->chip == BQ27500) - return temp - 2731; + rsoc = bq27x00_read(di, BQ27500_REG_SOC, false); else - return ((temp * 5) - 5463) / 2; + rsoc = bq27x00_read(di, BQ27000_REG_RSOC, true); + + if (rsoc < 0) + dev_err(di->dev, "error reading relative State-of-Charge\n"); + + return rsoc; } /* - * Return the battery Voltage in milivolts - * Or < 0 if something fails. + * Read a time register. + * Return < 0 if something fails. */ -static int bq27x00_battery_voltage(struct bq27x00_device_info *di) +static int bq27x00_battery_read_time(struct bq27x00_device_info *di, u8 reg) { - int ret; - int volt = 0; + int tval; - ret = bq27x00_read(di, BQ27x00_REG_VOLT, &volt, false); - if (ret) { - dev_err(di->dev, "error reading voltage\n"); - return ret; + tval = bq27x00_read(di, reg, false); + if (tval < 0) { + dev_err(di->dev, "error reading register %02x: %d\n", reg, tval); + return tval; } - return volt * 1000; + if (tval == 65535) + return -ENODATA; + + return tval * 60; +} + +static void bq27x00_update(struct bq27x00_device_info *di) +{ + struct bq27x00_reg_cache cache = {0, }; + bool is_bq27500 = di->chip == BQ27500; + + cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, is_bq27500); + if (cache.flags >= 0) { + cache.capacity = bq27x00_battery_read_rsoc(di); + cache.temperature = bq27x00_read(di, BQ27x00_REG_TEMP, false); + cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); + cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); + cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); + + if (!is_bq27500) + cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); + } + + /* Ignore current_now which is a snapshot of the current battery state + * and is likely to be different even between two consecutive reads */ + if (memcmp(&di->cache, &cache, sizeof(cache) - sizeof(int)) != 0) { + di->cache = cache; + power_supply_changed(&di->bat); + } + + di->last_update = jiffies; +} + +/* + * Return the battery temperature in tenths of degree Celsius + * Or < 0 if something fails. + */ +static int bq27x00_battery_temperature(struct bq27x00_device_info *di, + union power_supply_propval *val) +{ + if (di->cache.temperature < 0) + return di->cache.temperature; + + if (di->chip == BQ27500) + val->intval = di->cache.temperature - 2731; + else + val->intval = ((di->cache.temperature * 5) - 5463) / 2; + + return 0; } /* @@ -134,109 +192,84 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di) * Note that current can be negative signed as well * Or 0 if something fails. */ -static int bq27x00_battery_current(struct bq27x00_device_info *di) +static int bq27x00_battery_current(struct bq27x00_device_info *di, + union power_supply_propval *val) { - int ret; - int curr = 0; - int flags = 0; + int curr; - ret = bq27x00_read(di, BQ27x00_REG_AI, &curr, false); - if (ret) { - dev_err(di->dev, "error reading current\n"); - return 0; - } + if (di->chip == BQ27500) + curr = bq27x00_read(di, BQ27x00_REG_AI, false); + else + curr = di->cache.current_now; + + if (curr < 0) + return curr; if (di->chip == BQ27500) { /* bq27500 returns signed value */ - curr = (int)((s16)curr) * 1000; + val->intval = (int)((s16)curr) * 1000; } else { - ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false); - if (ret < 0) { - dev_err(di->dev, "error reading flags\n"); - return 0; - } - if (flags & BQ27000_FLAG_CHGS) { + if (di->cache.flags & BQ27000_FLAG_CHGS) { dev_dbg(di->dev, "negative current!\n"); curr = -curr; } - curr = curr * 3570 / BQ27000_RS; - } - - return curr; -} - -/* - * Return the battery Relative State-of-Charge - * Or < 0 if something fails. - */ -static int bq27x00_battery_rsoc(struct bq27x00_device_info *di) -{ - int ret; - int rsoc = 0; - if (di->chip == BQ27500) - ret = bq27x00_read(di, BQ27500_REG_SOC, &rsoc, false); - else - ret = bq27x00_read(di, BQ27000_REG_RSOC, &rsoc, true); - if (ret) { - dev_err(di->dev, "error reading relative State-of-Charge\n"); - return ret; + val->intval = curr * 3570 / BQ27000_RS; } - return rsoc; + return 0; } static int bq27x00_battery_status(struct bq27x00_device_info *di, - union power_supply_propval *val) + union power_supply_propval *val) { - int flags = 0; int status; - int ret; - - ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false); - if (ret < 0) { - dev_err(di->dev, "error reading flags\n"); - return ret; - } if (di->chip == BQ27500) { - if (flags & BQ27500_FLAG_FC) + if (di->cache.flags & BQ27500_FLAG_FC) status = POWER_SUPPLY_STATUS_FULL; - else if (flags & BQ27500_FLAG_DSC) + else if (di->cache.flags & BQ27500_FLAG_DSC) status = POWER_SUPPLY_STATUS_DISCHARGING; else status = POWER_SUPPLY_STATUS_CHARGING; } else { - if (flags & BQ27000_FLAG_CHGS) + if (di->cache.flags & BQ27000_FLAG_CHGS) status = POWER_SUPPLY_STATUS_CHARGING; else status = POWER_SUPPLY_STATUS_DISCHARGING; } val->intval = status; + return 0; } /* - * Read a time register. - * Return < 0 if something fails. + * Return the battery Voltage in milivolts + * Or < 0 if something fails. */ -static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg, - union power_supply_propval *val) +static int bq27x00_battery_voltage(struct bq27x00_device_info *di, + union power_supply_propval *val) { - int tval = 0; - int ret; + int volt; - ret = bq27x00_read(di, reg, &tval, false); - if (ret) { - dev_err(di->dev, "error reading register %02x\n", reg); - return ret; - } + volt = bq27x00_read(di, BQ27x00_REG_VOLT, false); + if (volt < 0) + return volt; - if (tval == 65535) - return -ENODATA; + val->intval = volt * 1000; + + return 0; +} + +static int bq27x00_simple_value(int value, + union power_supply_propval *val) +{ + if (value < 0) + return value; + + val->intval = value; - val->intval = tval * 60; return 0; } @@ -249,9 +282,11 @@ static int bq27x00_battery_get_property(struct power_supply *psy, { int ret = 0; struct bq27x00_device_info *di = to_bq27x00_device_info(psy); - int voltage = bq27x00_battery_voltage(di); - if (psp != POWER_SUPPLY_PROP_PRESENT && voltage <= 0) + if (time_is_before_jiffies(di->last_update + 5 * HZ)) + bq27x00_update(di); + + if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) return -ENODEV; switch (psp) { @@ -259,29 +294,28 @@ static int bq27x00_battery_get_property(struct power_supply *psy, ret = bq27x00_battery_status(di, val); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - val->intval = voltage; + ret = bq27x00_battery_voltage(di, val); break; case POWER_SUPPLY_PROP_PRESENT: - if (psp == POWER_SUPPLY_PROP_PRESENT) - val->intval = voltage <= 0 ? 0 : 1; + val->intval = di->cache.flags < 0 ? 0 : 1; break; case POWER_SUPPLY_PROP_CURRENT_NOW: - val->intval = bq27x00_battery_current(di); + ret = bq27x00_battery_current(di, val); break; case POWER_SUPPLY_PROP_CAPACITY: - val->intval = bq27x00_battery_rsoc(di); + ret = bq27x00_simple_value(di->cache.capacity, val); break; case POWER_SUPPLY_PROP_TEMP: - val->intval = bq27x00_battery_temperature(di); + ret = bq27x00_battery_temperature(di, val); break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: - ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val); + ret = bq27x00_simple_value(di->cache.time_to_empty, val); break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: - ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val); + ret = bq27x00_simple_value(di->cache.time_to_empty_avg, val); break; case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: - ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val); + ret = bq27x00_simple_value(di->cache.time_to_full, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -311,6 +345,8 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION); + bq27x00_update(di); + return 0; } @@ -324,13 +360,12 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) static DEFINE_IDR(battery_id); static DEFINE_MUTEX(battery_mutex); -static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, - int *rt_value, bool single) +static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single) { struct i2c_client *client = to_i2c_client(di->dev); struct i2c_msg msg[1]; unsigned char data[2]; - int err; + int ret; if (!client->adapter) return -ENODEV; @@ -341,26 +376,24 @@ static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, msg->buf = data; data[0] = reg; - err = i2c_transfer(client->adapter, msg, 1); + ret = i2c_transfer(client->adapter, msg, 1); - if (err >= 0) { + if (ret >= 0) { if (!single) msg->len = 2; else msg->len = 1; msg->flags = I2C_M_RD; - err = i2c_transfer(client->adapter, msg, 1); - if (err >= 0) { + ret = i2c_transfer(client->adapter, msg, 1); + if (ret >= 0) { if (!single) - *rt_value = get_unaligned_le16(data); + ret = get_unaligned_le16(data); else - *rt_value = data[0]; - - return 0; + ret = data[0]; } } - return err; + return ret; } static int bq27x00_battery_probe(struct i2c_client *client, @@ -477,7 +510,7 @@ static inline void bq27x00_battery_i2c_exit(void) {}; #ifdef CONFIG_BATTERY_BQ27X00_PLATFORM static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, - int *rt_value, bool single) + bool single) { struct device *dev = di->dev; struct bq27000_platform_data *pdata = dev->platform_data; @@ -504,14 +537,10 @@ static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, if (timeout == 0) return -EIO; - *rt_value = (upper << 8) | lower; - } else { - lower = pdata->read(dev, reg); - if (lower < 0) - return lower; - *rt_value = lower; + return (upper << 8) | lower; } - return 0; + + return pdata->read(dev, reg); } static int __devinit bq27000_battery_probe(struct platform_device *pdev) -- cgit v1.2.2 From 740b755a3b3433f5ee5f9ef54de5d1b4c08223cc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 7 Jan 2011 20:14:53 +0100 Subject: bq27x00: Poll battery state This patch adds support for polling the battery state and generating a power_supply_changed() event if it has changed. Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 58 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index dbe3fcb3b0ba..25350fcbadb3 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -74,10 +74,13 @@ struct bq27x00_device_info { struct bq27x00_reg_cache cache; unsigned long last_update; + struct delayed_work work; struct power_supply bat; struct bq27x00_access_methods bus; + + struct mutex lock; }; static enum power_supply_property bq27x00_battery_props[] = { @@ -93,6 +96,11 @@ static enum power_supply_property bq27x00_battery_props[] = { POWER_SUPPLY_PROP_TECHNOLOGY, }; +static unsigned int poll_interval = 360; +module_param(poll_interval, uint, 0644); +MODULE_PARM_DESC(poll_interval, "battery poll interval in seconds - " \ + "0 disables polling"); + /* * Common code for BQ27x00 devices */ @@ -169,6 +177,21 @@ static void bq27x00_update(struct bq27x00_device_info *di) di->last_update = jiffies; } +static void bq27x00_battery_poll(struct work_struct *work) +{ + struct bq27x00_device_info *di = + container_of(work, struct bq27x00_device_info, work.work); + + bq27x00_update(di); + + if (poll_interval > 0) { + /* The timer does not have to be accurate. */ + set_timer_slack(&di->work.timer, poll_interval * HZ / 4); + schedule_delayed_work(&di->work, poll_interval * HZ); + } +} + + /* * Return the battery temperature in tenths of degree Celsius * Or < 0 if something fails. @@ -283,8 +306,12 @@ static int bq27x00_battery_get_property(struct power_supply *psy, int ret = 0; struct bq27x00_device_info *di = to_bq27x00_device_info(psy); - if (time_is_before_jiffies(di->last_update + 5 * HZ)) - bq27x00_update(di); + mutex_lock(&di->lock); + if (time_is_before_jiffies(di->last_update + 5 * HZ)) { + cancel_delayed_work_sync(&di->work); + bq27x00_battery_poll(&di->work.work); + } + mutex_unlock(&di->lock); if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) return -ENODEV; @@ -327,6 +354,14 @@ static int bq27x00_battery_get_property(struct power_supply *psy, return ret; } +static void bq27x00_external_power_changed(struct power_supply *psy) +{ + struct bq27x00_device_info *di = to_bq27x00_device_info(psy); + + cancel_delayed_work_sync(&di->work); + schedule_delayed_work(&di->work, 0); +} + static int bq27x00_powersupply_init(struct bq27x00_device_info *di) { int ret; @@ -335,7 +370,10 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) di->bat.properties = bq27x00_battery_props; di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props); di->bat.get_property = bq27x00_battery_get_property; - di->bat.external_power_changed = NULL; + di->bat.external_power_changed = bq27x00_external_power_changed; + + INIT_DELAYED_WORK(&di->work, bq27x00_battery_poll); + mutex_init(&di->lock); ret = power_supply_register(di->dev, &di->bat); if (ret) { @@ -350,6 +388,15 @@ static int bq27x00_powersupply_init(struct bq27x00_device_info *di) return 0; } +static void bq27x00_powersupply_unregister(struct bq27x00_device_info *di) +{ + cancel_delayed_work_sync(&di->work); + + power_supply_unregister(&di->bat); + + mutex_destroy(&di->lock); +} + /* i2c specific code */ #ifdef CONFIG_BATTERY_BQ27X00_I2C @@ -457,7 +504,7 @@ static int bq27x00_battery_remove(struct i2c_client *client) { struct bq27x00_device_info *di = i2c_get_clientdata(client); - power_supply_unregister(&di->bat); + bq27x00_powersupply_unregister(di); kfree(di->bat.name); @@ -590,7 +637,8 @@ static int __devexit bq27000_battery_remove(struct platform_device *pdev) { struct bq27x00_device_info *di = platform_get_drvdata(pdev); - power_supply_unregister(&di->bat); + bq27x00_powersupply_unregister(di); + platform_set_drvdata(pdev, NULL); kfree(di); -- cgit v1.2.2 From 631c17ee5daf0ca73688cb5e5216fc0e3e340483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 1 Feb 2011 00:08:02 +0100 Subject: bq27x00: Add new properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch add support for reporting properties POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_ENERGY_NOW in module bq27x00_battery. Signed-off-by: Pali Rohár Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 152 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 25350fcbadb3..a1bd1ff753b3 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -16,6 +16,13 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * */ + +/* + * Datasheets: + * http://focus.ti.com/docs/prod/folders/print/bq27000.html + * http://focus.ti.com/docs/prod/folders/print/bq27500.html + */ + #include #include #include @@ -30,7 +37,7 @@ #include -#define DRIVER_VERSION "1.1.0" +#define DRIVER_VERSION "1.2.0" #define BQ27x00_REG_TEMP 0x06 #define BQ27x00_REG_VOLT 0x08 @@ -39,11 +46,17 @@ #define BQ27x00_REG_TTE 0x16 #define BQ27x00_REG_TTF 0x18 #define BQ27x00_REG_TTECP 0x26 +#define BQ27x00_REG_NAC 0x0C /* Nominal available capaciy */ +#define BQ27x00_REG_LMD 0x12 /* Last measured discharge */ +#define BQ27x00_REG_CYCT 0x2A /* Cycle count total */ +#define BQ27x00_REG_AE 0x22 /* Available enery */ #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ +#define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ #define BQ27000_FLAG_CHGS BIT(7) #define BQ27500_REG_SOC 0x2c +#define BQ27500_REG_DCAP 0x3C /* Design capacity */ #define BQ27500_FLAG_DSC BIT(0) #define BQ27500_FLAG_FC BIT(9) @@ -61,6 +74,8 @@ struct bq27x00_reg_cache { int time_to_empty; int time_to_empty_avg; int time_to_full; + int charge_full; + int charge_counter; int capacity; int flags; @@ -73,6 +88,8 @@ struct bq27x00_device_info { enum bq27x00_chip chip; struct bq27x00_reg_cache cache; + int charge_design_full; + unsigned long last_update; struct delayed_work work; @@ -94,6 +111,11 @@ static enum power_supply_property bq27x00_battery_props[] = { POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_ENERGY_NOW, }; static unsigned int poll_interval = 360; @@ -130,6 +152,87 @@ static int bq27x00_battery_read_rsoc(struct bq27x00_device_info *di) return rsoc; } +/* + * Return a battery charge value in µAh + * Or < 0 if something fails. + */ +static int bq27x00_battery_read_charge(struct bq27x00_device_info *di, u8 reg) +{ + int charge; + + charge = bq27x00_read(di, reg, false); + if (charge < 0) { + dev_err(di->dev, "error reading nominal available capacity\n"); + return charge; + } + + if (di->chip == BQ27500) + charge *= 1000; + else + charge = charge * 3570 / BQ27000_RS; + + return charge; +} + +/* + * Return the battery Nominal available capaciy in µAh + * Or < 0 if something fails. + */ +static inline int bq27x00_battery_read_nac(struct bq27x00_device_info *di) +{ + return bq27x00_battery_read_charge(di, BQ27x00_REG_NAC); +} + +/* + * Return the battery Last measured discharge in µAh + * Or < 0 if something fails. + */ +static inline int bq27x00_battery_read_lmd(struct bq27x00_device_info *di) +{ + return bq27x00_battery_read_charge(di, BQ27x00_REG_LMD); +} + +/* + * Return the battery Initial last measured discharge in µAh + * Or < 0 if something fails. + */ +static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di) +{ + int ilmd; + + if (di->chip == BQ27500) + ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false); + else + ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true); + + if (ilmd < 0) { + dev_err(di->dev, "error reading initial last measured discharge\n"); + return ilmd; + } + + if (di->chip == BQ27500) + ilmd *= 1000; + else + ilmd = ilmd * 256 * 3570 / BQ27000_RS; + + return ilmd; +} + +/* + * Return the battery Cycle count total + * Or < 0 if something fails. + */ +static int bq27x00_battery_read_cyct(struct bq27x00_device_info *di) +{ + int cyct; + + cyct = bq27x00_read(di, BQ27x00_REG_CYCT, false); + if (cyct < 0) + dev_err(di->dev, "error reading cycle count total\n"); + + return cyct; +} + /* * Read a time register. * Return < 0 if something fails. @@ -162,9 +265,15 @@ static void bq27x00_update(struct bq27x00_device_info *di) cache.time_to_empty = bq27x00_battery_read_time(di, BQ27x00_REG_TTE); cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP); cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF); + cache.charge_full = bq27x00_battery_read_lmd(di); + cache.charge_counter = bq27x00_battery_read_cyct(di); if (!is_bq27500) cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false); + + /* We only have to read charge design full once */ + if (di->charge_design_full <= 0) + di->charge_design_full = bq27x00_battery_read_ilmd(di); } /* Ignore current_now which is a snapshot of the current battery state @@ -285,6 +394,32 @@ static int bq27x00_battery_voltage(struct bq27x00_device_info *di, return 0; } +/* + * Return the battery Available energy in µWh + * Or < 0 if something fails. + */ +static int bq27x00_battery_energy(struct bq27x00_device_info *di, + union power_supply_propval *val) +{ + int ae; + + ae = bq27x00_read(di, BQ27x00_REG_AE, false); + if (ae < 0) { + dev_err(di->dev, "error reading available energy\n"); + return ae; + } + + if (di->chip == BQ27500) + ae *= 1000; + else + ae = ae * 29200 / BQ27000_RS; + + val->intval = ae; + + return 0; +} + + static int bq27x00_simple_value(int value, union power_supply_propval *val) { @@ -347,6 +482,21 @@ static int bq27x00_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + ret = bq27x00_simple_value(bq27x00_battery_read_nac(di), val); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + ret = bq27x00_simple_value(di->cache.charge_full, val); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + ret = bq27x00_simple_value(di->charge_design_full, val); + break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + ret = bq27x00_simple_value(di->cache.charge_counter, val); + break; + case POWER_SUPPLY_PROP_ENERGY_NOW: + ret = bq27x00_battery_energy(di, val); + break; default: return -EINVAL; } -- cgit v1.2.2 From fd9b958c5525024204e7e2c48fe5eae560d171bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 1 Feb 2011 00:10:41 +0100 Subject: bq27x00: Add MODULE_DEVICE_TABLE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds MODULE_DEVICE_TABLE for module bq27x00_battery. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Signed-off-by: Lars-Peter Clausen Acked-by: Rodolfo Giometti Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index a1bd1ff753b3..0e99d02dea33 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -672,6 +672,7 @@ static const struct i2c_device_id bq27x00_id[] = { { "bq27500", BQ27500 }, {}, }; +MODULE_DEVICE_TABLE(i2c, bq27x00_id); static struct i2c_driver bq27x00_battery_driver = { .driver = { -- cgit v1.2.2 From c1b9ab67e7c7021be9d0db6345d6ccc5d70248f1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 18 Sep 2010 17:31:16 +0200 Subject: bq27x00: Give more specific reports on battery status The current code only reports whether the battery is charging or discharging. But the battery also reports whether it is fully charged, furthermore by look at if the battery is supplied we can tell whether it is discharging or not charging. Signed-off-by: Lars-Peter Clausen Acked-by: Rodolfo Giometti Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 0e99d02dea33..003be5f1c785 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -54,6 +54,7 @@ #define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */ #define BQ27000_REG_ILMD 0x76 /* Initial last measured discharge */ #define BQ27000_FLAG_CHGS BIT(7) +#define BQ27000_FLAG_FC BIT(5) #define BQ27500_REG_SOC 0x2c #define BQ27500_REG_DCAP 0x3C /* Design capacity */ @@ -365,8 +366,12 @@ static int bq27x00_battery_status(struct bq27x00_device_info *di, else status = POWER_SUPPLY_STATUS_CHARGING; } else { - if (di->cache.flags & BQ27000_FLAG_CHGS) + if (di->cache.flags & BQ27000_FLAG_FC) + status = POWER_SUPPLY_STATUS_FULL; + else if (di->cache.flags & BQ27000_FLAG_CHGS) status = POWER_SUPPLY_STATUS_CHARGING; + else if (power_supply_am_i_supplied(&di->bat)) + status = POWER_SUPPLY_STATUS_NOT_CHARGING; else status = POWER_SUPPLY_STATUS_DISCHARGING; } -- cgit v1.2.2 From bf7d4140450f6dbc019a8831223e08d778f90dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Tue, 1 Feb 2011 00:23:13 +0100 Subject: bq27x00: Minor cleanups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Consistently use uppercase for hexadecimal values. * Clarify/fix the unit of functions return value in its comment. Signed-off-by: Pali Rohár Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 003be5f1c785..b44555f1b633 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -56,7 +56,7 @@ #define BQ27000_FLAG_CHGS BIT(7) #define BQ27000_FLAG_FC BIT(5) -#define BQ27500_REG_SOC 0x2c +#define BQ27500_REG_SOC 0x2C #define BQ27500_REG_DCAP 0x3C /* Design capacity */ #define BQ27500_FLAG_DSC BIT(0) #define BQ27500_FLAG_FC BIT(9) @@ -321,7 +321,7 @@ static int bq27x00_battery_temperature(struct bq27x00_device_info *di, } /* - * Return the battery average current + * Return the battery average current in µA * Note that current can be negative signed as well * Or 0 if something fails. */ -- cgit v1.2.2 From 2ec523a8238a117b082ca6b0cef3b9ae812364f9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 2 Feb 2011 19:35:07 +0100 Subject: bq27x00: Cleanup bq27x00_i2c_read Some minor stylistic cleanups. Signed-off-by: Lars-Peter Clausen Tested-by: Grazvydas Ignotas --- drivers/power/bq27x00_battery.c | 45 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index b44555f1b633..740a0ac29dd1 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -565,36 +565,39 @@ static DEFINE_MUTEX(battery_mutex); static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single) { struct i2c_client *client = to_i2c_client(di->dev); - struct i2c_msg msg[1]; + struct i2c_msg msg; unsigned char data[2]; int ret; if (!client->adapter) return -ENODEV; - msg->addr = client->addr; - msg->flags = 0; - msg->len = 1; - msg->buf = data; + msg.addr = client->addr; + msg.flags = 0; + msg.len = 1; + msg.buf = data; data[0] = reg; - ret = i2c_transfer(client->adapter, msg, 1); + ret = i2c_transfer(client->adapter, &msg, 1); + + if (ret < 0) + return ret; + + if (single) + msg.len = 1; + else + msg.len = 2; + + msg.flags = I2C_M_RD; + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) + return ret; + + if (!single) + ret = get_unaligned_le16(data); + else + ret = data[0]; - if (ret >= 0) { - if (!single) - msg->len = 2; - else - msg->len = 1; - - msg->flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, msg, 1); - if (ret >= 0) { - if (!single) - ret = get_unaligned_le16(data); - else - ret = data[0]; - } - } return ret; } -- cgit v1.2.2 From 9e912f452931b3da9d13d716a381ba0d5fb74ced Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Tue, 15 Feb 2011 23:27:35 +0200 Subject: bq27x00: Use single i2c_transfer call for property read Doing this by using 2 calls sometimes results in unexpected values being returned on OMAP3 i2c controller. Signed-off-by: Grazvydas Ignotas Signed-off-by: Lars-Peter Clausen --- drivers/power/bq27x00_battery.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 740a0ac29dd1..59e68dbd028b 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -565,31 +565,26 @@ static DEFINE_MUTEX(battery_mutex); static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg, bool single) { struct i2c_client *client = to_i2c_client(di->dev); - struct i2c_msg msg; + struct i2c_msg msg[2]; unsigned char data[2]; int ret; if (!client->adapter) return -ENODEV; - msg.addr = client->addr; - msg.flags = 0; - msg.len = 1; - msg.buf = data; - - data[0] = reg; - ret = i2c_transfer(client->adapter, &msg, 1); - - if (ret < 0) - return ret; - + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].buf = ® + msg[0].len = sizeof(reg); + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; if (single) - msg.len = 1; + msg[1].len = 1; else - msg.len = 2; + msg[1].len = 2; - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); if (ret < 0) return ret; -- cgit v1.2.2 From 5ad567ffbaf208bd35bff4341906346c1a1d4574 Mon Sep 17 00:00:00 2001 From: Abraham Arce Date: Tue, 22 Feb 2011 22:25:59 -0800 Subject: Input: omap4-keypad - wire up runtime PM handling Enable Runtime PM functionality in OMAP4 driver based on the following assumptions: - keyboard controller in wakeup domain so it is always on and power impact is minimal; - in OMAP4 the device control is at module/device level and ick/fclk level control is difficult so cutting of clocks will prevent interrupts. Signed-off-by: Abraham Arce Signed-off-by: Shubhrajyoti D Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap4-keypad.c | 74 ++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 45bd0977d006..c51a3c4a7feb 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -80,20 +81,6 @@ struct omap4_keypad { unsigned short keymap[]; }; -static void __devinit omap4_keypad_config(struct omap4_keypad *keypad_data) -{ - __raw_writel(OMAP4_VAL_FUNCTIONALCFG, - keypad_data->base + OMAP4_KBD_CTRL); - __raw_writel(OMAP4_VAL_DEBOUNCINGTIME, - keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME); - __raw_writel(OMAP4_VAL_IRQDISABLE, - keypad_data->base + OMAP4_KBD_IRQSTATUS); - __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, - keypad_data->base + OMAP4_KBD_IRQENABLE); - __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA, - keypad_data->base + OMAP4_KBD_WAKEUPENABLE); -} - /* Interrupt handler */ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) { @@ -144,6 +131,49 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static int omap4_keypad_open(struct input_dev *input) +{ + struct omap4_keypad *keypad_data = input_get_drvdata(input); + + pm_runtime_get_sync(input->dev.parent); + + disable_irq(keypad_data->irq); + + __raw_writel(OMAP4_VAL_FUNCTIONALCFG, + keypad_data->base + OMAP4_KBD_CTRL); + __raw_writel(OMAP4_VAL_DEBOUNCINGTIME, + keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME); + __raw_writel(OMAP4_VAL_IRQDISABLE, + keypad_data->base + OMAP4_KBD_IRQSTATUS); + __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY, + keypad_data->base + OMAP4_KBD_IRQENABLE); + __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA, + keypad_data->base + OMAP4_KBD_WAKEUPENABLE); + + enable_irq(keypad_data->irq); + + return 0; +} + +static void omap4_keypad_close(struct input_dev *input) +{ + struct omap4_keypad *keypad_data = input_get_drvdata(input); + + disable_irq(keypad_data->irq); + + /* Disable interrupts */ + __raw_writel(OMAP4_VAL_IRQDISABLE, + keypad_data->base + OMAP4_KBD_IRQENABLE); + + /* clear pending interrupts */ + __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS), + keypad_data->base + OMAP4_KBD_IRQSTATUS); + + enable_irq(keypad_data->irq); + + pm_runtime_put_sync(input->dev.parent); +} + static int __devinit omap4_keypad_probe(struct platform_device *pdev) { const struct omap4_keypad_platform_data *pdata; @@ -225,6 +255,9 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) input_dev->id.product = 0x0001; input_dev->id.version = 0x0001; + input_dev->open = omap4_keypad_open; + input_dev->close = omap4_keypad_close; + input_dev->keycode = keypad_data->keymap; input_dev->keycodesize = sizeof(keypad_data->keymap[0]); input_dev->keycodemax = max_keys; @@ -239,8 +272,6 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) matrix_keypad_build_keymap(pdata->keymap_data, row_shift, input_dev->keycode, input_dev->keybit); - omap4_keypad_config(keypad_data); - error = request_irq(keypad_data->irq, omap4_keypad_interrupt, IRQF_TRIGGER_RISING, "omap4-keypad", keypad_data); @@ -249,17 +280,19 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev) goto err_free_input; } + pm_runtime_enable(&pdev->dev); + error = input_register_device(keypad_data->input); if (error < 0) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err_free_irq; + goto err_pm_disable; } - platform_set_drvdata(pdev, keypad_data); return 0; -err_free_irq: +err_pm_disable: + pm_runtime_disable(&pdev->dev); free_irq(keypad_data->irq, keypad_data); err_free_input: input_free_device(input_dev); @@ -278,6 +311,9 @@ static int __devexit omap4_keypad_remove(struct platform_device *pdev) struct resource *res; free_irq(keypad_data->irq, keypad_data); + + pm_runtime_disable(&pdev->dev); + input_unregister_device(keypad_data->input); iounmap(keypad_data->base); -- cgit v1.2.2 From adf779c1ee1d5556ebd83e39a7189022d4ebce3a Mon Sep 17 00:00:00 2001 From: Heungjun Kim Date: Wed, 23 Feb 2011 21:40:11 -0800 Subject: Input: mcs_touchkey - add support for suspend/resume This adds support for system-level suspend/resume to the driver. Signed-off-by: Heungjun Kim Signed-off-by: Kyungmin Park Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 48 ++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 63b849d7e90b..03fa59a0b220 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -1,5 +1,5 @@ /* - * mcs_touchkey.c - Touchkey driver for MELFAS MCS5000/5080 controller + * Touchkey driver for MELFAS MCS5000/5080 controller * * Copyright (C) 2010 Samsung Electronics Co.Ltd * Author: HeungJun Kim @@ -19,6 +19,7 @@ #include #include #include +#include /* MCS5000 Touchkey */ #define MCS5000_TOUCHKEY_STATUS 0x04 @@ -45,6 +46,8 @@ struct mcs_touchkey_chip { }; struct mcs_touchkey_data { + void (*poweron)(bool); + struct i2c_client *client; struct input_dev *input_dev; struct mcs_touchkey_chip chip; @@ -169,6 +172,11 @@ static int __devinit mcs_touchkey_probe(struct i2c_client *client, if (pdata->cfg_pin) pdata->cfg_pin(); + if (pdata->poweron) { + data->poweron = pdata->poweron; + data->poweron(true); + } + error = request_threaded_irq(client->irq, NULL, mcs_touchkey_interrupt, IRQF_TRIGGER_FALLING, client->dev.driver->name, data); if (error) { @@ -196,12 +204,49 @@ static int __devexit mcs_touchkey_remove(struct i2c_client *client) struct mcs_touchkey_data *data = i2c_get_clientdata(client); free_irq(client->irq, data); + if (data->poweron) + data->poweron(false); input_unregister_device(data->input_dev); kfree(data); return 0; } +#ifdef CONFIG_PM_SLEEP +static int mcs_touchkey_suspend(struct device *dev) +{ + struct mcs_touchkey_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + /* Disable the work */ + disable_irq(client->irq); + + /* Finally turn off the power */ + if (data->poweron) + data->poweron(false); + + return 0; +} + +static int mcs_touchkey_resume(struct device *dev) +{ + struct mcs_touchkey_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + /* Enable the device first */ + if (data->poweron) + data->poweron(true); + + /* Enable irq again */ + enable_irq(client->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(mcs_touchkey_pm_ops, + mcs_touchkey_suspend, mcs_touchkey_resume); + static const struct i2c_device_id mcs_touchkey_id[] = { { "mcs5000_touchkey", MCS5000_TOUCHKEY }, { "mcs5080_touchkey", MCS5080_TOUCHKEY }, @@ -213,6 +258,7 @@ static struct i2c_driver mcs_touchkey_driver = { .driver = { .name = "mcs_touchkey", .owner = THIS_MODULE, + .pm = &mcs_touchkey_pm_ops, }, .probe = mcs_touchkey_probe, .remove = __devexit_p(mcs_touchkey_remove), -- cgit v1.2.2 From 5f62615ef5e50b0ad6c125fe1e38f2ac675012e2 Mon Sep 17 00:00:00 2001 From: HeungJun Kim Date: Wed, 23 Feb 2011 21:42:49 -0800 Subject: Input: mcs_touchkey - add shutdown handler The MCS50XX series has a HW bug that requires explicit chip power down. If chip is not powered down before shutting the system down the control pins (powerup, interrupt) are pulled up and residue current continues flowing into the chips making them continue consuming power. Signed-off-by: Heungjun Kim Signed-off-by: Kyungmin Park Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/mcs_touchkey.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 03fa59a0b220..af1aab324a4c 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -212,6 +212,14 @@ static int __devexit mcs_touchkey_remove(struct i2c_client *client) return 0; } +static void mcs_touchkey_shutdown(struct i2c_client *client) +{ + struct mcs_touchkey_data *data = i2c_get_clientdata(client); + + if (data->poweron) + data->poweron(false); +} + #ifdef CONFIG_PM_SLEEP static int mcs_touchkey_suspend(struct device *dev) { @@ -262,6 +270,7 @@ static struct i2c_driver mcs_touchkey_driver = { }, .probe = mcs_touchkey_probe, .remove = __devexit_p(mcs_touchkey_remove), + .shutdown = mcs_touchkey_shutdown, .id_table = mcs_touchkey_id, }; -- cgit v1.2.2 From 073b4964b3b75fd9e19bf3933b26d9c23591c9db Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:37:31 +0100 Subject: ACPI: Do not export functions that are only used in osl.c The functions acpi_os_map_generic_address() and acpi_os_unmap_generic_address() are only used in drivers/acpi/osl.c, so make them static and remove the extern definitions of them from include/linux/acpi_io.h. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c90c76aa7f8b..ff2189d3fa06 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -397,7 +397,7 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) __acpi_unmap_table(virt, size); } -int acpi_os_map_generic_address(struct acpi_generic_address *addr) +static int acpi_os_map_generic_address(struct acpi_generic_address *addr) { void __iomem *virt; @@ -413,9 +413,8 @@ int acpi_os_map_generic_address(struct acpi_generic_address *addr) return 0; } -EXPORT_SYMBOL_GPL(acpi_os_map_generic_address); -void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) +static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) { void __iomem *virt; unsigned long flags; @@ -433,7 +432,6 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) acpi_os_unmap_memory(virt, size); } -EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address); #ifdef ACPI_FUTURE_USAGE acpi_status -- cgit v1.2.2 From 7bbb890358b96cb6f77adc6815f2072bdf813d5d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:37:42 +0100 Subject: ACPI: Change acpi_ioremap_lock into a mutex There's no reason why acpi_ioremap_lock has to be a spinlock, because all of the functions it is used in may sleep anyway and there's no reason why it should be locked with interrupts off. Use a mutex instead (that's going to allow us to put some more operations under the lock later). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index ff2189d3fa06..97061928249a 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -109,7 +109,7 @@ struct acpi_ioremap { }; static LIST_HEAD(acpi_ioremaps); -static DEFINE_SPINLOCK(acpi_ioremap_lock); +static DEFINE_MUTEX(acpi_ioremap_lock); static void __init acpi_osi_setup_late(void); @@ -303,7 +303,6 @@ void __iomem *__init_refok acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { struct acpi_ioremap *map, *tmp_map; - unsigned long flags; void __iomem *virt; acpi_physical_address pg_off; acpi_size pg_sz; @@ -334,18 +333,18 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) map->size = pg_sz; kref_init(&map->ref); - spin_lock_irqsave(&acpi_ioremap_lock, flags); + mutex_lock(&acpi_ioremap_lock); /* Check if page has already been mapped. */ tmp_map = acpi_map_lookup(phys, size); if (tmp_map) { kref_get(&tmp_map->ref); - spin_unlock_irqrestore(&acpi_ioremap_lock, flags); + mutex_unlock(&acpi_ioremap_lock); iounmap(map->virt); kfree(map); return tmp_map->virt + (phys - tmp_map->phys); } list_add_tail_rcu(&map->list, &acpi_ioremaps); - spin_unlock_irqrestore(&acpi_ioremap_lock, flags); + mutex_unlock(&acpi_ioremap_lock); return map->virt + (phys - map->phys); } @@ -362,7 +361,6 @@ static void acpi_kref_del_iomap(struct kref *ref) void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; - unsigned long flags; int del; if (!acpi_gbl_permanent_mmap) { @@ -370,17 +368,17 @@ void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) return; } - spin_lock_irqsave(&acpi_ioremap_lock, flags); + mutex_lock(&acpi_ioremap_lock); map = acpi_map_lookup_virt(virt, size); if (!map) { - spin_unlock_irqrestore(&acpi_ioremap_lock, flags); + mutex_unlock(&acpi_ioremap_lock); printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt); dump_stack(); return; } del = kref_put(&map->ref, acpi_kref_del_iomap); - spin_unlock_irqrestore(&acpi_ioremap_lock, flags); + mutex_unlock(&acpi_ioremap_lock); if (!del) return; @@ -417,7 +415,6 @@ static int acpi_os_map_generic_address(struct acpi_generic_address *addr) static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) { void __iomem *virt; - unsigned long flags; acpi_size size = addr->bit_width / 8; if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) @@ -426,9 +423,9 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) if (!addr->address || !addr->bit_width) return; - spin_lock_irqsave(&acpi_ioremap_lock, flags); + mutex_lock(&acpi_ioremap_lock); virt = acpi_map_vaddr_lookup(addr->address, size); - spin_unlock_irqrestore(&acpi_ioremap_lock, flags); + mutex_unlock(&acpi_ioremap_lock); acpi_os_unmap_memory(virt, size); } -- cgit v1.2.2 From 7fe135dc058faea0ce319a03e3b6f98c5049955c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:37:53 +0100 Subject: ACPI: Avoid walking the list of memory mappings in osl.c twice in a row Make acpi_os_unmap_generic_address() use acpi_map_lookup() to find the desired iomap and drop the reference to it directly (and eventually remove it if necessary) instead of calling acpi_os_unmap_memory(), which requires us to walk the list of ACPI iomaps twice in a row (first, to get the virtual address associated with the iomap and second, to get the iomap itself). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 97061928249a..f6785bced215 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -358,6 +358,13 @@ static void acpi_kref_del_iomap(struct kref *ref) list_del_rcu(&map->list); } +static void acpi_os_remove_map(struct acpi_ioremap *map) +{ + synchronize_rcu(); + iounmap(map->virt); + kfree(map); +} + void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; @@ -372,20 +379,14 @@ void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) map = acpi_map_lookup_virt(virt, size); if (!map) { mutex_unlock(&acpi_ioremap_lock); - printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt); - dump_stack(); + WARN(true, PREFIX "%s: bad address %p\n", __func__, virt); return; } - del = kref_put(&map->ref, acpi_kref_del_iomap); mutex_unlock(&acpi_ioremap_lock); - if (!del) - return; - - synchronize_rcu(); - iounmap(map->virt); - kfree(map); + if (del) + acpi_os_remove_map(map); } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); @@ -414,8 +415,8 @@ static int acpi_os_map_generic_address(struct acpi_generic_address *addr) static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) { - void __iomem *virt; - acpi_size size = addr->bit_width / 8; + struct acpi_ioremap *map; + int del; if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return; @@ -424,10 +425,16 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) return; mutex_lock(&acpi_ioremap_lock); - virt = acpi_map_vaddr_lookup(addr->address, size); + map = acpi_map_lookup(addr->address, addr->bit_width / 8); + if (!map) { + mutex_unlock(&acpi_ioremap_lock); + return; + } + del = kref_put(&map->ref, acpi_kref_del_iomap); mutex_unlock(&acpi_ioremap_lock); - acpi_os_unmap_memory(virt, size); + if (del) + acpi_os_remove_map(map); } #ifdef ACPI_FUTURE_USAGE -- cgit v1.2.2 From 7ffd0443f2502478545e23e194b7eb8e16376072 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:38:05 +0100 Subject: ACPI: Make acpi_os_map_memory() avoid creating unnecessary mappings Modify acpi_os_map_memory() so that it doesn't call acpi_os_ioremap() unconditionally every time it is executed (except when acpi_gbl_permanent_mmap is unset), which pretty much defeats the purpose of maintaining the list of ACPI iomaps in osl.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index f6785bced215..445f205752a2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -302,7 +302,7 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size) void __iomem *__init_refok acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { - struct acpi_ioremap *map, *tmp_map; + struct acpi_ioremap *map; void __iomem *virt; acpi_physical_address pg_off; acpi_size pg_sz; @@ -315,14 +315,25 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) if (!acpi_gbl_permanent_mmap) return __acpi_map_table((unsigned long)phys, size); + mutex_lock(&acpi_ioremap_lock); + /* Check if there's a suitable mapping already. */ + map = acpi_map_lookup(phys, size); + if (map) { + kref_get(&map->ref); + goto out; + } + map = kzalloc(sizeof(*map), GFP_KERNEL); - if (!map) + if (!map) { + mutex_unlock(&acpi_ioremap_lock); return NULL; + } pg_off = round_down(phys, PAGE_SIZE); pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; virt = acpi_os_ioremap(pg_off, pg_sz); if (!virt) { + mutex_unlock(&acpi_ioremap_lock); kfree(map); return NULL; } @@ -333,19 +344,10 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) map->size = pg_sz; kref_init(&map->ref); - mutex_lock(&acpi_ioremap_lock); - /* Check if page has already been mapped. */ - tmp_map = acpi_map_lookup(phys, size); - if (tmp_map) { - kref_get(&tmp_map->ref); - mutex_unlock(&acpi_ioremap_lock); - iounmap(map->virt); - kfree(map); - return tmp_map->virt + (phys - tmp_map->phys); - } list_add_tail_rcu(&map->list, &acpi_ioremaps); - mutex_unlock(&acpi_ioremap_lock); + out: + mutex_unlock(&acpi_ioremap_lock); return map->virt + (phys - map->phys); } EXPORT_SYMBOL_GPL(acpi_os_map_memory); -- cgit v1.2.2 From b7c1fadd6c2eead56d0664a3a921980120de0c11 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:38:15 +0100 Subject: ACPI: Do not use krefs under a mutex in osl.c The reference counting of ACPI iomaps is carried out entirely under acpi_ioremap_lock, so it is sufficient to use simple counters instead of krefs for this purpose. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 445f205752a2..5389f9f2e2ff 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -105,7 +105,7 @@ struct acpi_ioremap { void __iomem *virt; acpi_physical_address phys; acpi_size size; - struct kref ref; + unsigned long refcount; }; static LIST_HEAD(acpi_ioremaps); @@ -319,7 +319,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) /* Check if there's a suitable mapping already. */ map = acpi_map_lookup(phys, size); if (map) { - kref_get(&map->ref); + map->refcount++; goto out; } @@ -342,7 +342,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) map->virt = virt; map->phys = pg_off; map->size = pg_sz; - kref_init(&map->ref); + map->refcount = 1; list_add_tail_rcu(&map->list, &acpi_ioremaps); @@ -352,25 +352,24 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size) } EXPORT_SYMBOL_GPL(acpi_os_map_memory); -static void acpi_kref_del_iomap(struct kref *ref) +static void acpi_os_drop_map_ref(struct acpi_ioremap *map) { - struct acpi_ioremap *map; - - map = container_of(ref, struct acpi_ioremap, ref); - list_del_rcu(&map->list); + if (!--map->refcount) + list_del_rcu(&map->list); } -static void acpi_os_remove_map(struct acpi_ioremap *map) +static void acpi_os_map_cleanup(struct acpi_ioremap *map) { - synchronize_rcu(); - iounmap(map->virt); - kfree(map); + if (!map->refcount) { + synchronize_rcu(); + iounmap(map->virt); + kfree(map); + } } void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; - int del; if (!acpi_gbl_permanent_mmap) { __acpi_unmap_table(virt, size); @@ -384,11 +383,10 @@ void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) WARN(true, PREFIX "%s: bad address %p\n", __func__, virt); return; } - del = kref_put(&map->ref, acpi_kref_del_iomap); + acpi_os_drop_map_ref(map); mutex_unlock(&acpi_ioremap_lock); - if (del) - acpi_os_remove_map(map); + acpi_os_map_cleanup(map); } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); @@ -418,7 +416,6 @@ static int acpi_os_map_generic_address(struct acpi_generic_address *addr) static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) { struct acpi_ioremap *map; - int del; if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return; @@ -432,11 +429,10 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) mutex_unlock(&acpi_ioremap_lock); return; } - del = kref_put(&map->ref, acpi_kref_del_iomap); + acpi_os_drop_map_ref(map); mutex_unlock(&acpi_ioremap_lock); - if (del) - acpi_os_remove_map(map); + acpi_os_map_cleanup(map); } #ifdef ACPI_FUTURE_USAGE -- cgit v1.2.2 From 13606a2de1996f8d83a9ce296f74022bdbadf712 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:38:25 +0100 Subject: ACPI: Introduce acpi_os_get_iomem() Introduce function acpi_os_get_iomem() that may be used by its callers to get a reference to an ACPI iomap. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 5389f9f2e2ff..52ca8721bc9c 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -285,6 +285,22 @@ acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size) return NULL; } +void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size) +{ + struct acpi_ioremap *map; + void __iomem *virt = NULL; + + mutex_lock(&acpi_ioremap_lock); + map = acpi_map_lookup(phys, size); + if (map) { + virt = map->virt + (phys - map->phys); + map->refcount++; + } + mutex_unlock(&acpi_ioremap_lock); + return virt; +} +EXPORT_SYMBOL_GPL(acpi_os_get_iomem); + /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ static struct acpi_ioremap * acpi_map_lookup_virt(void __iomem *virt, acpi_size size) -- cgit v1.2.2 From bb45e394e21eb2abc710ad43d98ebac1069bf355 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:38:38 +0100 Subject: ACPI / PM: Use existing ACPI iomaps for NVS save/restore (v2) Modify the NVS save/restore code to use acpi_os_get_iomem() and acpi_os_unmap_memory() to acquire and release references to ACPI iomaps, respectively. If there's no ACPI iomap corresponding to the given NVS page, acpi_os_ioremap() is used to map that page and iounmap() is used to unmap it during resume. [If the page is not present in the ACPI iomaps already, it doesn't make sense to add its mapping to the list of ACPI iomaps, because it's going to be thrown away during the subsequent resume anyway.] Testing on my HP nx6325 shows that approx. 90% of the NVS pages have already been mapped by ACPI before suspend and are present in the ACPI iomaps, so this change appears to be the right thing to do in general. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/nvs.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index fa5a1df42b79..096787b43c96 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -26,6 +26,7 @@ struct nvs_page { unsigned int size; void *kaddr; void *data; + bool unmap; struct list_head node; }; @@ -44,6 +45,9 @@ int suspend_nvs_register(unsigned long start, unsigned long size) { struct nvs_page *entry, *next; + pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n", + start, size); + while (size > 0) { unsigned int nr_bytes; @@ -81,7 +85,13 @@ void suspend_nvs_free(void) free_page((unsigned long)entry->data); entry->data = NULL; if (entry->kaddr) { - iounmap(entry->kaddr); + if (entry->unmap) { + iounmap(entry->kaddr); + entry->unmap = false; + } else { + acpi_os_unmap_memory(entry->kaddr, + entry->size); + } entry->kaddr = NULL; } } @@ -115,8 +125,14 @@ int suspend_nvs_save(void) list_for_each_entry(entry, &nvs_list, node) if (entry->data) { - entry->kaddr = acpi_os_ioremap(entry->phys_start, - entry->size); + unsigned long phys = entry->phys_start; + unsigned int size = entry->size; + + entry->kaddr = acpi_os_get_iomem(phys, size); + if (!entry->kaddr) { + entry->kaddr = acpi_os_ioremap(phys, size); + entry->unmap = !!entry->kaddr; + } if (!entry->kaddr) { suspend_nvs_free(); return -ENOMEM; -- cgit v1.2.2 From 5190726765b40774c069e187a958e10ccd970e65 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:40:37 +0100 Subject: ACPI: Remove the wakeup.run_wake_count device field The wakeup.run_wake_count ACPI device field is only used by the PCI runtime PM code to "protect" devices from being prepared for generating wakeup signals more than once in a row. However, it really doesn't provide any protection, because (1) all of the functions it is supposed to protect use their own reference counters effectively ensuring that the device will be set up for generating wakeup signals just once and (2) the PCI runtime PM code uses wakeup.run_wake_count in a racy way, since nothing prevents acpi_dev_run_wake() from being called concurrently from two different threads for the same device. Remove the wakeup.run_wake_count ACPI device field which is unnecessary, confusing and used in a wrong way. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 2 -- drivers/acpi/scan.c | 1 - drivers/pci/pci-acpi.c | 16 ++++------------ 3 files changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 76bbb78a5ad9..e643a0936dc4 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -430,7 +430,6 @@ static int acpi_button_add(struct acpi_device *device) /* Button's GPE is run-wake GPE */ acpi_enable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); - device->wakeup.run_wake_count++; device_set_wakeup_enable(&device->dev, true); } @@ -453,7 +452,6 @@ static int acpi_button_remove(struct acpi_device *device, int type) if (device->wakeup.flags.valid) { acpi_disable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); - device->wakeup.run_wake_count--; device_set_wakeup_enable(&device->dev, false); } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b99e62494607..b136c9c1e531 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -797,7 +797,6 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) acpi_status status; acpi_event_status event_status; - device->wakeup.run_wake_count = 0; device->wakeup.flags.notifier_present = 0; /* Power button, Lid switch always enable wakeup */ diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 6fe0772e0e7d..7c3b18e78cee 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -293,19 +293,11 @@ static int acpi_dev_run_wake(struct device *phys_dev, bool enable) } if (enable) { - if (!dev->wakeup.run_wake_count++) { - acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); - acpi_enable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); - } - } else if (dev->wakeup.run_wake_count > 0) { - if (!--dev->wakeup.run_wake_count) { - acpi_disable_gpe(dev->wakeup.gpe_device, - dev->wakeup.gpe_number); - acpi_disable_wakeup_device_power(dev); - } + acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); + acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); } else { - error = -EALREADY; + acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); + acpi_disable_wakeup_device_power(dev); } return error; -- cgit v1.2.2 From c19f9a84ec807da57fd75bbd9a3f2b8269611f79 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:41:13 +0100 Subject: ACPI / Button: Avoid disabling wakeup unnecessarily on remove If a button device had already been enabled to wake up the system from sleep states before the button driver saw it, the driver shouldn't disable the device's wakeup capability when being detached from the device. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index e643a0936dc4..12c28f4adb67 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -98,6 +98,7 @@ struct acpi_button { struct input_dev *input; char phys[32]; /* for input device */ unsigned long pushed; + bool wakeup_enabled; }; static const struct file_operations acpi_button_info_fops = { @@ -430,7 +431,10 @@ static int acpi_button_add(struct acpi_device *device) /* Button's GPE is run-wake GPE */ acpi_enable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); - device_set_wakeup_enable(&device->dev, true); + if (!device_may_wakeup(&device->dev)) { + device_set_wakeup_enable(&device->dev, true); + button->wakeup_enabled = true; + } } printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); @@ -452,7 +456,8 @@ static int acpi_button_remove(struct acpi_device *device, int type) if (device->wakeup.flags.valid) { acpi_disable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); - device_set_wakeup_enable(&device->dev, false); + if (button->wakeup_enabled) + device_set_wakeup_enable(&device->dev, false); } acpi_button_remove_fs(device); -- cgit v1.2.2 From c41b93fb8551148a93d3bba870365e8489317f02 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:41:35 +0100 Subject: ACPI / PM: Drop acpi_restore_state_mem() The function acpi_restore_state_mem() has never been and most likely never will be used, so remove it. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index d6a8cd14de2e..67dcd3886563 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -293,10 +293,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); - /* restore processor state */ - if (acpi_state == ACPI_STATE_S3) - acpi_restore_state_mem(); - suspend_nvs_restore(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; -- cgit v1.2.2 From 82911fe1988fadfc9c01673202cbc411aa803244 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:41:47 +0100 Subject: ACPI / PM: acpi_suspend_enter() need not switch interrupts off The function acpi_suspend_enter() is always called with interrupts off, so it doesn't need to switch them off and on. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 67dcd3886563..3b549379801a 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -243,7 +243,6 @@ static int acpi_suspend_begin(suspend_state_t pm_state) static int acpi_suspend_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; - unsigned long flags = 0; u32 acpi_state = acpi_target_sleep_state; ACPI_FLUSH_CPU_CACHE(); @@ -256,7 +255,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) return error; } - local_irq_save(flags); switch (acpi_state) { case ACPI_STATE_S1: barrier(); @@ -290,7 +288,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) /* Allow EC transactions to happen. */ acpi_ec_unblock_transactions_early(); - local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); suspend_nvs_restore(); -- cgit v1.2.2 From 7a63f08b2b904d25e966dd0e15c9af4a13c80b90 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:41:57 +0100 Subject: ACPI / PM: Modify the "low-level resume finished" message Move the low-level resume completion message to the point where control goes back to acpi_suspend_enter() during resume and change it so that it's more informative. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 3b549379801a..6bea2fe8434b 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -263,6 +263,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) case ACPI_STATE_S3: do_suspend_lowlevel(); + pr_info(PREFIX "Low-level resume complete\n"); break; } @@ -288,8 +289,6 @@ static int acpi_suspend_enter(suspend_state_t pm_state) /* Allow EC transactions to happen. */ acpi_ec_unblock_transactions_early(); - printk(KERN_DEBUG "Back to C!\n"); - suspend_nvs_restore(); return ACPI_SUCCESS(status) ? 0 : -EFAULT; -- cgit v1.2.2 From 979f11b060c0b35b03b86ae854d6f21a710305d0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:42:09 +0100 Subject: ACPI / PM: Call acpi_save_state_mem() right before low-level suspend Since acpi_save_state_mem() is only called by acpi_suspend_enter() if the target sleep state is S3, it's better to call it under the switch (acpi_state), right before do_suspend_lowlevel(). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 6bea2fe8434b..2307604064b3 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -244,17 +244,10 @@ static int acpi_suspend_enter(suspend_state_t pm_state) { acpi_status status = AE_OK; u32 acpi_state = acpi_target_sleep_state; + int error; ACPI_FLUSH_CPU_CACHE(); - /* Do arch specific saving of state. */ - if (acpi_state == ACPI_STATE_S3) { - int error = acpi_save_state_mem(); - - if (error) - return error; - } - switch (acpi_state) { case ACPI_STATE_S1: barrier(); @@ -262,6 +255,9 @@ static int acpi_suspend_enter(suspend_state_t pm_state) break; case ACPI_STATE_S3: + error = acpi_save_state_mem(); + if (error) + return error; do_suspend_lowlevel(); pr_info(PREFIX "Low-level resume complete\n"); break; -- cgit v1.2.2 From f1a2003e22f6b50ea21f7f4b38b38c5ebc9c8017 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:42:22 +0100 Subject: ACPI / PM: Merge do_suspend_lowlevel() into acpi_save_state_mem() The function do_suspend_lowlevel() is specific to x86 and defined in assembly code, so it should be called from the x86 low-level suspend code rather than from acpi_suspend_enter(). Merge do_suspend_lowlevel() into the x86's acpi_save_state_mem() and change the name of the latter to acpi_suspend_lowlevel(), so that the function's purpose is better reflected by its name. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 2307604064b3..0a81bf11f473 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -199,8 +199,6 @@ static void acpi_pm_end(void) #endif /* CONFIG_ACPI_SLEEP */ #ifdef CONFIG_SUSPEND -extern void do_suspend_lowlevel(void); - static u32 acpi_suspend_states[] = { [PM_SUSPEND_ON] = ACPI_STATE_S0, [PM_SUSPEND_STANDBY] = ACPI_STATE_S1, @@ -255,10 +253,9 @@ static int acpi_suspend_enter(suspend_state_t pm_state) break; case ACPI_STATE_S3: - error = acpi_save_state_mem(); + error = acpi_suspend_lowlevel(); if (error) return error; - do_suspend_lowlevel(); pr_info(PREFIX "Low-level resume complete\n"); break; } -- cgit v1.2.2 From aad83b143008e1d406248803550bfbfc600b6398 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:42:35 +0100 Subject: ACPI / PM: acpi_hibernation_enter() need not switch interrupts off The function acpi_hibernation_enter() is always called with interrupts off, so it doesn't need to switch them off and on. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 0a81bf11f473..84f57143ad7c 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -457,16 +457,13 @@ static int acpi_hibernation_begin(void) static int acpi_hibernation_enter(void) { acpi_status status = AE_OK; - unsigned long flags = 0; ACPI_FLUSH_CPU_CACHE(); - local_irq_save(flags); /* This shouldn't return. If it returns, we have a problem */ status = acpi_enter_sleep_state(ACPI_STATE_S4); /* Reprogram control registers and execute _BFS */ acpi_leave_sleep_state_prep(ACPI_STATE_S4); - local_irq_restore(flags); return ACPI_SUCCESS(status) ? 0 : -EFAULT; } -- cgit v1.2.2 From 23fe36306ea489eef7dd88506bdcefdc8da39c91 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 8 Feb 2011 23:48:16 +0100 Subject: ACPI: Avoid calling request_irq() many times for the same interrupt In principle acpi_os_install_interrupt_handler() may be called multiple times for different interrupts, either from acpi_ev_get_gpe_xrupt_block(), or from acpi_ev_install_sci_handler(). However, it always attempts to request the same interrupt, acpi_gbl_FADT.sci_interrupt and it doesn't check whether or not this interrupt has already been requested. Modify this function so that it refuses to request interrupts other than acpi_gbl_FADT.sci_interrupt and change acpi_os_remove_interrupt_handler() so that it refuses to free such interrupts. Use the observation that the only supported ACPI interrupt must be equal to acpi_gbl_FADT.sci_interrupt and drop an unnecessary variable acpi_irq_irq. This change has been tested on Toshiba Portege R500 and HP nx6325 without introducing any visible problems. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c90c76aa7f8b..187dff96356b 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -76,7 +76,6 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER */ -static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; @@ -516,11 +515,15 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_stats_init(); /* - * Ignore the GSI from the core, and use the value in our copy of the - * FADT. It may not be the same if an interrupt source override exists - * for the SCI. + * ACPI interrupts different from the SCI in our copy of the FADT are + * not supported. */ - gsi = acpi_gbl_FADT.sci_interrupt; + if (gsi != acpi_gbl_FADT.sci_interrupt) + return AE_BAD_PARAMETER; + + if (acpi_irq_handler) + return AE_ALREADY_ACQUIRED; + if (acpi_gsi_to_irq(gsi, &irq) < 0) { printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", gsi); @@ -531,20 +534,20 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_context = context; if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); + acpi_irq_handler = NULL; return AE_NOT_ACQUIRED; } - acpi_irq_irq = irq; return AE_OK; } acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler) { - if (irq) { - free_irq(irq, acpi_irq); - acpi_irq_handler = NULL; - acpi_irq_irq = 0; - } + if (irq != acpi_gbl_FADT.sci_interrupt) + return AE_BAD_PARAMETER; + + free_irq(irq, acpi_irq); + acpi_irq_handler = NULL; return AE_OK; } @@ -1603,7 +1606,7 @@ acpi_status __init acpi_os_initialize1(void) acpi_status acpi_os_terminate(void) { if (acpi_irq_handler) { - acpi_os_remove_interrupt_handler(acpi_irq_irq, + acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt, acpi_irq_handler); } -- cgit v1.2.2 From 0d3c07378bb7d423302d7cb0dcd3fa5a26c40220 Mon Sep 17 00:00:00 2001 From: Iiro Valkonen Date: Wed, 23 Feb 2011 21:07:20 -0800 Subject: Input: atmel_mxt_ts - remove matrix size check The mxt_check_matrix_size() is currently setting the CTE mode to match xline/yline information that is in the platform data, but it does not take into account for example the fact that we could have a key array in use too (key array would use some x/y lines as well). It would be better to simply rely on the configuration data, and make sure that the CTE mode set in there matches the touch object (touchscreen, key array, proximity) configuration (which are set in the config data too). Signed-off-by: Iiro Valkonen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 73 -------------------------------- 1 file changed, 73 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index d2e5864ca096..6264ba80c38c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -630,74 +630,6 @@ static int mxt_check_reg_init(struct mxt_data *data) return 0; } -static int mxt_check_matrix_size(struct mxt_data *data) -{ - const struct mxt_platform_data *pdata = data->pdata; - struct device *dev = &data->client->dev; - int mode = -1; - int error; - u8 val; - - dev_dbg(dev, "Number of X lines: %d\n", pdata->x_line); - dev_dbg(dev, "Number of Y lines: %d\n", pdata->y_line); - - switch (pdata->x_line) { - case 0 ... 15: - if (pdata->y_line <= 14) - mode = 0; - break; - case 16: - if (pdata->y_line <= 12) - mode = 1; - if (pdata->y_line == 13 || pdata->y_line == 14) - mode = 0; - break; - case 17: - if (pdata->y_line <= 11) - mode = 2; - if (pdata->y_line == 12 || pdata->y_line == 13) - mode = 1; - break; - case 18: - if (pdata->y_line <= 10) - mode = 3; - if (pdata->y_line == 11 || pdata->y_line == 12) - mode = 2; - break; - case 19: - if (pdata->y_line <= 9) - mode = 4; - if (pdata->y_line == 10 || pdata->y_line == 11) - mode = 3; - break; - case 20: - mode = 4; - } - - if (mode < 0) { - dev_err(dev, "Invalid X/Y lines\n"); - return -EINVAL; - } - - error = mxt_read_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_MODE, &val); - if (error) - return error; - - if (mode == val) - return 0; - - /* Change the CTE configuration */ - mxt_write_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_CTRL, 1); - mxt_write_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_MODE, mode); - mxt_write_object(data, MXT_SPT_CTECONFIG, - MXT_CTE_CTRL, 0); - - return 0; -} - static int mxt_make_highchg(struct mxt_data *data) { struct device *dev = &data->client->dev; @@ -864,11 +796,6 @@ static int mxt_initialize(struct mxt_data *data) if (error) return error; - /* Check X/Y matrix size */ - error = mxt_check_matrix_size(data); - if (error) - return error; - error = mxt_make_highchg(data); if (error) return error; -- cgit v1.2.2 From 8fd2af11d2fe1d50621e958747744f1c93e5b758 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 23 Jan 2011 12:26:51 +0100 Subject: firewire: nosy: should work on Power Mac G4 PCI too The first board generation of Power Mac G4 ("Yikes!", those with PCI graphics) still had a PCILynx controller like their G3 predecessors, but not the later AGP models. (Jonathan Woithe recalls to have heard of it, and some web sources reinforce it.) Signed-off-by: Stefan Richter --- drivers/firewire/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 68f942cb30f2..49009b489f37 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -77,7 +77,8 @@ config FIREWIRE_NOSY The following cards are known to be based on PCILynx or PCILynx-2: IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2 (PCI card), Newer Technology FireWire 2 Go (CardBus card), - Apple Power Mac G3 blue & white (onboard controller). + Apple Power Mac G3 blue & white and G4 with PCI graphics + (onboard controller). To compile this driver as a module, say M here: The module will be called nosy. Source code of a userspace interface to nosy, called -- cgit v1.2.2 From 5aaffc65a27dd9db65455c2c9ab3ede57238d2f5 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 31 Jan 2011 11:58:58 +0100 Subject: firewire: core: rename some variables In manage_channel(), rename the variables "c" and "i" to the more expressive "bit" and "channel". Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/core-iso.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c index c003fa4e2db1..95bc01a02a88 100644 --- a/drivers/firewire/core-iso.c +++ b/drivers/firewire/core-iso.c @@ -235,45 +235,45 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation, static int manage_channel(struct fw_card *card, int irm_id, int generation, u32 channels_mask, u64 offset, bool allocate, __be32 data[2]) { - __be32 c, all, old; - int i, ret = -EIO, retry = 5; + __be32 bit, all, old; + int channel, ret = -EIO, retry = 5; old = all = allocate ? cpu_to_be32(~0) : 0; - for (i = 0; i < 32; i++) { - if (!(channels_mask & 1 << i)) + for (channel = 0; channel < 32; channel++) { + if (!(channels_mask & 1 << channel)) continue; ret = -EBUSY; - c = cpu_to_be32(1 << (31 - i)); - if ((old & c) != (all & c)) + bit = cpu_to_be32(1 << (31 - channel)); + if ((old & bit) != (all & bit)) continue; data[0] = old; - data[1] = old ^ c; + data[1] = old ^ bit; switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP, irm_id, generation, SCODE_100, offset, data, 8)) { case RCODE_GENERATION: /* A generation change frees all channels. */ - return allocate ? -EAGAIN : i; + return allocate ? -EAGAIN : channel; case RCODE_COMPLETE: if (data[0] == old) - return i; + return channel; old = data[0]; /* Is the IRM 1394a-2000 compliant? */ - if ((data[0] & c) == (data[1] & c)) + if ((data[0] & bit) == (data[1] & bit)) continue; /* 1394-1995 IRM, fall through to retry. */ default: if (retry) { retry--; - i--; + channel--; } else { ret = -EIO; } -- cgit v1.2.2 From e81cbebdfc384f9c2ae91225f16ef994118e5e2c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 16 Feb 2011 10:32:11 +0100 Subject: firewire: ohci: prevent iso completion callbacks after context stop To prevent the iso packet callback from being called after fw_iso_context_stop() has returned, make sure that the context's tasklet has finished executing before that. This fixes access-after-free bugs that have so far been observed only in the upcoming snd-firewire-speakers driver, but can theoretically also happen in the firedtv driver. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c7394361afcb..f1497b1fcf2e 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2764,6 +2764,7 @@ static int ohci_stop_iso(struct fw_iso_context *base) } flush_writes(ohci); context_stop(&ctx->context); + tasklet_kill(&ctx->context.tasklet); return 0; } -- cgit v1.2.2 From 44b74d909dc943fd9384930a141450cb17133511 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 23 Feb 2011 09:27:40 +0100 Subject: firewire: ohci: prevent starting of iso contexts with empty queue If a misguided program tried to start an isochronous context before it has queued any packets, the call would appear to succeed, but the context would not actually go into the running state, and the OHCI controller would then raise an unrecoverableError interrupt because the first Z value is zero and thus invalid. The driver logs such errors, but there is no mechanism to report this back to the program. Add an explicit check so that this error can be returned synchronously. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f1497b1fcf2e..c0572283b93e 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2706,6 +2706,10 @@ static int ohci_start_iso(struct fw_iso_context *base, u32 control = IR_CONTEXT_ISOCH_HEADER, match; int index; + /* the controller cannot start without any queued packets */ + if (ctx->context.last->branch_address == 0) + return -ENODATA; + switch (ctx->base.type) { case FW_ISO_CONTEXT_TRANSMIT: index = ctx - ohci->it_context_list; -- cgit v1.2.2 From c5a9f9d0895b2c16908979244d3d678fd6db0545 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 18 Feb 2011 10:01:20 +0530 Subject: pch_dma: fix kernel error issue fix the following kernel error ------------[ cut here ]------------ WARNING: at kernel/softirq.c:159 _local_bh_enable_ip.clone.5+0x35/0x71() Hardware name: To be filled by O.E.M. Modules linked in: pch_uart pch_dma fuse mga drm cpufreq_ondemand acpi_cpufreq mperf ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 ip6table_filter ip6_tables ipv6 uinput snd_hda_codec_realtek snd_hda_intel snd_hda_codec matroxfb_base snd_hwdep 8250_pnp snd_seq snd_seq_device matroxfb_DAC1064 snd_pcm joydev 8250 matroxfb_accel snd_timer matroxfb_Ti3026 ppdev pegasus parport_pc snd parport matroxfb_g450 g450_pll serial_core video output matroxfb_misc soundcore snd_page_alloc serio_raw pcspkr ext4 jbd2 crc16 sdhci_pci sdhci mmc_core floppy [last unloaded: scsi_wait_scan] Pid: 0, comm: swapper Not tainted 2.6.37.upstream_check+ #8 Call Trace: [] warn_slowpath_common+0x65/0x7a [] ? _local_bh_enable_ip.clone.5+0x35/0x71 [] warn_slowpath_null+0xf/0x13 [] _local_bh_enable_ip.clone.5+0x35/0x71 [] local_bh_enable_ip+0x8/0xa [] _raw_spin_unlock_bh+0x10/0x12 [] pd_prep_slave_sg+0xba/0x200 [pch_dma] [] pch_uart_interrupt+0x44d/0x6aa [pch_uart] [] handle_IRQ_event+0x1d/0x9e [] handle_fasteoi_irq+0x90/0xc7 [] ? handle_fasteoi_irq+0x0/0xc7 [] ? do_IRQ+0x3e/0x89 [] ? common_interrupt+0x29/0x30 [] ? sys_getpriority+0x12d/0x1a2 [] ? arch_local_irq_enable+0x5/0xb [] ? acpi_idle_enter_bm+0x22a/0x261 [] ? cpuidle_idle_call+0x70/0xa1 [] ? cpu_idle+0x49/0x6a [] ? rest_init+0x58/0x5a [] ? start_kernel+0x2d0/0x2d5 [] ? i386_start_kernel+0xce/0xd5 Signed-off-by: Tomoya MORINAGA Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index 1c38418ae61f..bf2ddd601dc2 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -366,7 +366,7 @@ static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd) struct pch_dma_chan *pd_chan = to_pd_chan(txd->chan); dma_cookie_t cookie; - spin_lock_bh(&pd_chan->lock); + spin_lock(&pd_chan->lock); cookie = pdc_assign_cookie(pd_chan, desc); if (list_empty(&pd_chan->active_list)) { @@ -376,7 +376,7 @@ static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd) list_add_tail(&desc->desc_node, &pd_chan->queue); } - spin_unlock_bh(&pd_chan->lock); + spin_unlock(&pd_chan->lock); return 0; } @@ -386,7 +386,7 @@ static struct pch_dma_desc *pdc_alloc_desc(struct dma_chan *chan, gfp_t flags) struct pch_dma *pd = to_pd(chan->device); dma_addr_t addr; - desc = pci_pool_alloc(pd->pool, GFP_KERNEL, &addr); + desc = pci_pool_alloc(pd->pool, flags, &addr); if (desc) { memset(desc, 0, sizeof(struct pch_dma_desc)); INIT_LIST_HEAD(&desc->tx_list); @@ -405,7 +405,7 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan) struct pch_dma_desc *ret = NULL; int i; - spin_lock_bh(&pd_chan->lock); + spin_lock(&pd_chan->lock); list_for_each_entry_safe(desc, _d, &pd_chan->free_list, desc_node) { i++; if (async_tx_test_ack(&desc->txd)) { @@ -415,15 +415,15 @@ static struct pch_dma_desc *pdc_desc_get(struct pch_dma_chan *pd_chan) } dev_dbg(chan2dev(&pd_chan->chan), "desc %p not ACKed\n", desc); } - spin_unlock_bh(&pd_chan->lock); + spin_unlock(&pd_chan->lock); dev_dbg(chan2dev(&pd_chan->chan), "scanned %d descriptors\n", i); if (!ret) { ret = pdc_alloc_desc(&pd_chan->chan, GFP_NOIO); if (ret) { - spin_lock_bh(&pd_chan->lock); + spin_lock(&pd_chan->lock); pd_chan->descs_allocated++; - spin_unlock_bh(&pd_chan->lock); + spin_unlock(&pd_chan->lock); } else { dev_err(chan2dev(&pd_chan->chan), "failed to alloc desc\n"); @@ -437,10 +437,10 @@ static void pdc_desc_put(struct pch_dma_chan *pd_chan, struct pch_dma_desc *desc) { if (desc) { - spin_lock_bh(&pd_chan->lock); + spin_lock(&pd_chan->lock); list_splice_init(&desc->tx_list, &pd_chan->free_list); list_add(&desc->desc_node, &pd_chan->free_list); - spin_unlock_bh(&pd_chan->lock); + spin_unlock(&pd_chan->lock); } } @@ -530,9 +530,9 @@ static void pd_issue_pending(struct dma_chan *chan) struct pch_dma_chan *pd_chan = to_pd_chan(chan); if (pdc_is_idle(pd_chan)) { - spin_lock_bh(&pd_chan->lock); + spin_lock(&pd_chan->lock); pdc_advance_work(pd_chan); - spin_unlock_bh(&pd_chan->lock); + spin_unlock(&pd_chan->lock); } } @@ -592,7 +592,6 @@ static struct dma_async_tx_descriptor *pd_prep_slave_sg(struct dma_chan *chan, goto err_desc_get; } - if (!first) { first = desc; } else { @@ -641,13 +640,13 @@ static int pd_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, spin_unlock_bh(&pd_chan->lock); - return 0; } static void pdc_tasklet(unsigned long data) { struct pch_dma_chan *pd_chan = (struct pch_dma_chan *)data; + unsigned long flags; if (!pdc_is_idle(pd_chan)) { dev_err(chan2dev(&pd_chan->chan), @@ -655,12 +654,12 @@ static void pdc_tasklet(unsigned long data) return; } - spin_lock_bh(&pd_chan->lock); + spin_lock_irqsave(&pd_chan->lock, flags); if (test_and_clear_bit(0, &pd_chan->err_status)) pdc_handle_error(pd_chan); else pdc_advance_work(pd_chan); - spin_unlock_bh(&pd_chan->lock); + spin_unlock_irqrestore(&pd_chan->lock, flags); } static irqreturn_t pd_irq(int irq, void *devid) -- cgit v1.2.2 From 26d890f0d09fd58f7194aad651e86283cb9e6574 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 18 Feb 2011 10:01:21 +0530 Subject: pch_dma: set the number of array correctly set the number of array correctly. Signed-off-by: Tomoya MORINAGA Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index bf2ddd601dc2..b1dfba7e37b4 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -82,7 +82,7 @@ struct pch_dma_regs { u32 dma_sts1; u32 reserved2; u32 reserved3; - struct pch_dma_desc_regs desc[0]; + struct pch_dma_desc_regs desc[MAX_CHAN_NR]; }; struct pch_dma_desc { @@ -124,7 +124,7 @@ struct pch_dma { struct pci_pool *pool; struct pch_dma_regs regs; struct pch_dma_desc_regs ch_regs[MAX_CHAN_NR]; - struct pch_dma_chan channels[0]; + struct pch_dma_chan channels[MAX_CHAN_NR]; }; #define PCH_DMA_CTL0 0x00 -- cgit v1.2.2 From 5063511539bbb436ae8e4f75409561ef547f8516 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Fri, 25 Feb 2011 09:33:13 -0800 Subject: Input: bcm5974 - Report button also for zero fingers With the current code, pressing the integrated button with an isolating tool does not result in any button report. Fixed with this this patch. Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/bcm5974.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index b95231763911..d24837210f04 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -390,10 +390,6 @@ static int report_tp_state(struct bcm5974 *dev, int size) ptest = int2bound(&c->p, raw_p); origin = raw2int(f->origin); - /* set the integrated button if applicable */ - if (c->tp_type == TYPE2) - ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); - /* while tracking finger still valid, count all fingers */ if (ptest > PRESSURE_LOW && origin) { abs_p = ptest; @@ -412,6 +408,10 @@ static int report_tp_state(struct bcm5974 *dev, int size) } } + /* set the integrated button if applicable */ + if (c->tp_type == TYPE2) + ibt = raw2int(dev->tp_data[BUTTON_TYPE2]); + if (dev->fingers < nmin) dev->fingers = nmin; if (dev->fingers > nmax) -- cgit v1.2.2 From 439581ec07fa9cf3f519dd461a2cf41cfd3adcb4 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Fri, 25 Feb 2011 09:30:46 -0800 Subject: Input: evdev - fix evdev_write return value on partial writes As was recently brought up on the busybox list (http://lists.busybox.net/pipermail/busybox/2011-January/074565.html), evdev_write doesn't properly check the count argument, which will lead to a return value > count on partial writes if the remaining bytes are accessible - causing userspace confusion. Fix it by only handling each full input_event structure and return -EINVAL if less than 1 struct was written, similar to how it is done in evdev_read. Reported-by: Baruch Siach Signed-off-by: Peter Korsgaard Acked-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index c8471a2552e7..7f42d3a454d2 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -321,6 +321,9 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, struct input_event event; int retval; + if (count < input_event_size()) + return -EINVAL; + retval = mutex_lock_interruptible(&evdev->mutex); if (retval) return retval; @@ -330,17 +333,16 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer, goto out; } - while (retval < count) { - + do { if (input_event_from_user(buffer + retval, &event)) { retval = -EFAULT; goto out; } + retval += input_event_size(); input_inject_event(&evdev->handle, event.type, event.code, event.value); - retval += input_event_size(); - } + } while (retval + input_event_size() <= count); out: mutex_unlock(&evdev->mutex); -- cgit v1.2.2 From d6ccc442b12102414c1343f0adacaa8a1aaa516c Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 25 Feb 2011 13:56:36 +0200 Subject: twl4030_charger: Make the driver atomic notifier safe This queues work from the otg notification where the i2c operations can be safely made. Needed for atomic otg notifiers. Signed-off-by: Heikki Krogerus Tested-by: Grazvydas Ignotas Signed-off-by: Anton Vorontsov --- drivers/power/twl4030_charger.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index ff1f42398a2e..92c16e1677bd 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c @@ -71,8 +71,11 @@ struct twl4030_bci { struct power_supply usb; struct otg_transceiver *transceiver; struct notifier_block otg_nb; + struct work_struct work; int irq_chg; int irq_bci; + + unsigned long event; }; /* @@ -258,14 +261,11 @@ static irqreturn_t twl4030_bci_interrupt(int irq, void *arg) return IRQ_HANDLED; } -static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, - void *priv) +static void twl4030_bci_usb_work(struct work_struct *data) { - struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); + struct twl4030_bci *bci = container_of(data, struct twl4030_bci, work); - dev_dbg(bci->dev, "OTG notify %lu\n", val); - - switch (val) { + switch (bci->event) { case USB_EVENT_VBUS: case USB_EVENT_CHARGER: twl4030_charger_enable_usb(bci, true); @@ -274,6 +274,17 @@ static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, twl4030_charger_enable_usb(bci, false); break; } +} + +static int twl4030_bci_usb_ncb(struct notifier_block *nb, unsigned long val, + void *priv) +{ + struct twl4030_bci *bci = container_of(nb, struct twl4030_bci, otg_nb); + + dev_dbg(bci->dev, "OTG notify %lu\n", val); + + bci->event = val; + schedule_work(&bci->work); return NOTIFY_OK; } @@ -466,6 +477,8 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) goto fail_bci_irq; } + INIT_WORK(&bci->work, twl4030_bci_usb_work); + bci->transceiver = otg_get_transceiver(); if (bci->transceiver != NULL) { bci->otg_nb.notifier_call = twl4030_bci_usb_ncb; -- cgit v1.2.2 From 15e123e5d7e8ee9ba3717e743d8eb5fd0fe57712 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Sun, 27 Feb 2011 22:36:43 +0100 Subject: intel_idle: Rename cpuidle states Userspace apps might have to cut off parts off the idle state name for display reasons. Switch NHM-C1 to C1-NHM (and others) so that a cut off name is unique and makes sense to the user. Signed-off-by: Thomas Renninger CC: lenb@kernel.org Signed-off-by: Len Brown --- drivers/idle/intel_idle.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 4a5c4a44ffb1..a46dddf61078 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -107,7 +107,7 @@ static unsigned long long auto_demotion_disable_flags; static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C0 */ }, { /* MWAIT C1 */ - .name = "NHM-C1", + .name = "C1-NHM", .desc = "MWAIT 0x00", .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -115,7 +115,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 6, .enter = &intel_idle }, { /* MWAIT C2 */ - .name = "NHM-C3", + .name = "C3-NHM", .desc = "MWAIT 0x10", .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -123,7 +123,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 80, .enter = &intel_idle }, { /* MWAIT C3 */ - .name = "NHM-C6", + .name = "C6-NHM", .desc = "MWAIT 0x20", .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -135,7 +135,7 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C0 */ }, { /* MWAIT C1 */ - .name = "SNB-C1", + .name = "C1-SNB", .desc = "MWAIT 0x00", .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -143,7 +143,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 1, .enter = &intel_idle }, { /* MWAIT C2 */ - .name = "SNB-C3", + .name = "C3-SNB", .desc = "MWAIT 0x10", .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -151,7 +151,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 211, .enter = &intel_idle }, { /* MWAIT C3 */ - .name = "SNB-C6", + .name = "C6-SNB", .desc = "MWAIT 0x20", .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -159,7 +159,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 345, .enter = &intel_idle }, { /* MWAIT C4 */ - .name = "SNB-C7", + .name = "C7-SNB", .desc = "MWAIT 0x30", .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -171,7 +171,7 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C0 */ }, { /* MWAIT C1 */ - .name = "ATM-C1", + .name = "C1-ATM", .desc = "MWAIT 0x00", .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -179,7 +179,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { .target_residency = 4, .enter = &intel_idle }, { /* MWAIT C2 */ - .name = "ATM-C2", + .name = "C2-ATM", .desc = "MWAIT 0x10", .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID, @@ -188,7 +188,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { .enter = &intel_idle }, { /* MWAIT C3 */ }, { /* MWAIT C4 */ - .name = "ATM-C4", + .name = "C4-ATM", .desc = "MWAIT 0x30", .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, @@ -197,7 +197,7 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { .enter = &intel_idle }, { /* MWAIT C5 */ }, { /* MWAIT C6 */ - .name = "ATM-C6", + .name = "C6-ATM", .desc = "MWAIT 0x52", .driver_data = (void *) 0x52, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, -- cgit v1.2.2 From bb879101606dd7235d8f4ecd0f707b63281d0838 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Mon, 28 Feb 2011 16:55:28 -0800 Subject: bq20z75: Add optional battery detect gpio Adding support for an optional gpio for battery detection. This is passed in through the i2c platform data. It also accepts another field, battery_detect_present to signify the gpio state which means the battery is present, either 0 (low) or 1 (high). Signed-off-by: Rhyland Klein Signed-off-by: Anton Vorontsov --- drivers/power/bq20z75.c | 160 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 129 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index 4141775e5ff6..a51e98d74d34 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c @@ -25,6 +25,10 @@ #include #include #include +#include +#include + +#include enum { REG_MANUFACTURER_DATA, @@ -141,8 +145,13 @@ static enum power_supply_property bq20z75_properties[] = { }; struct bq20z75_info { - struct i2c_client *client; - struct power_supply power_supply; + struct i2c_client *client; + struct power_supply power_supply; + struct bq20z75_platform_data *pdata; + bool is_present; + bool gpio_detect; + bool enable_detection; + int irq; }; static int bq20z75_read_word_data(struct i2c_client *client, u8 address) @@ -179,6 +188,18 @@ static int bq20z75_get_battery_presence_and_health( union power_supply_propval *val) { s32 ret; + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); + + if (psp == POWER_SUPPLY_PROP_PRESENT && + bq20z75_device->gpio_detect) { + ret = gpio_get_value( + bq20z75_device->pdata->battery_detect); + if (ret == bq20z75_device->pdata->battery_detect_present) + val->intval = 1; + else + val->intval = 0; + return ret; + } /* Write to ManufacturerAccess with * ManufacturerAccess command and then @@ -192,8 +213,11 @@ static int bq20z75_get_battery_presence_and_health( ret = bq20z75_read_word_data(client, bq20z75_data[REG_MANUFACTURER_DATA].addr); - if (ret < 0) + if (ret < 0) { + if (psp == POWER_SUPPLY_PROP_PRESENT) + val->intval = 0; /* battery removed */ return ret; + } if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value || ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) { @@ -397,8 +421,7 @@ static int bq20z75_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - int ps_index; - int ret; + int ret = 0; struct bq20z75_info *bq20z75_device = container_of(psy, struct bq20z75_info, power_supply); struct i2c_client *client = bq20z75_device->client; @@ -407,8 +430,6 @@ static int bq20z75_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_HEALTH: ret = bq20z75_get_battery_presence_and_health(client, psp, val); - if (ret) - return ret; break; case POWER_SUPPLY_PROP_TECHNOLOGY: @@ -422,20 +443,15 @@ static int bq20z75_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: case POWER_SUPPLY_PROP_CAPACITY: - ps_index = bq20z75_get_property_index(client, psp); - if (ps_index < 0) - return ps_index; - - ret = bq20z75_get_battery_capacity(client, ps_index, psp, val); - if (ret) - return ret; + ret = bq20z75_get_property_index(client, psp); + if (ret < 0) + break; + ret = bq20z75_get_battery_capacity(client, ret, psp, val); break; case POWER_SUPPLY_PROP_SERIAL_NUMBER: ret = bq20z75_get_battery_serial_number(client, val); - if (ret) - return ret; break; case POWER_SUPPLY_PROP_STATUS: @@ -446,14 +462,11 @@ static int bq20z75_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - ps_index = bq20z75_get_property_index(client, psp); - if (ps_index < 0) - return ps_index; - - ret = bq20z75_get_battery_property(client, ps_index, psp, val); - if (ret) - return ret; + ret = bq20z75_get_property_index(client, psp); + if (ret < 0) + break; + ret = bq20z75_get_battery_property(client, ret, psp, val); break; default: @@ -462,26 +475,51 @@ static int bq20z75_get_property(struct power_supply *psy, return -EINVAL; } - /* Convert units to match requirements for power supply class */ - bq20z75_unit_adjustment(client, psp, val); + if (!bq20z75_device->enable_detection) + goto done; + + if (!bq20z75_device->gpio_detect && + bq20z75_device->is_present != (ret >= 0)) { + bq20z75_device->is_present = (ret >= 0); + power_supply_changed(&bq20z75_device->power_supply); + } + +done: + if (!ret) { + /* Convert units to match requirements for power supply class */ + bq20z75_unit_adjustment(client, psp, val); + } dev_dbg(&client->dev, "%s: property = %d, value = %d\n", __func__, psp, val->intval); - return 0; + return ret; } -static int bq20z75_probe(struct i2c_client *client, +static irqreturn_t bq20z75_irq(int irq, void *devid) +{ + struct power_supply *battery = devid; + + power_supply_changed(battery); + + return IRQ_HANDLED; +} + +static int __devinit bq20z75_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bq20z75_info *bq20z75_device; + struct bq20z75_platform_data *pdata = client->dev.platform_data; int rc; + int irq; bq20z75_device = kzalloc(sizeof(struct bq20z75_info), GFP_KERNEL); if (!bq20z75_device) return -ENOMEM; bq20z75_device->client = client; + bq20z75_device->enable_detection = false; + bq20z75_device->gpio_detect = false; bq20z75_device->power_supply.name = "battery"; bq20z75_device->power_supply.type = POWER_SUPPLY_TYPE_BATTERY; bq20z75_device->power_supply.properties = bq20z75_properties; @@ -489,26 +527,86 @@ static int bq20z75_probe(struct i2c_client *client, ARRAY_SIZE(bq20z75_properties); bq20z75_device->power_supply.get_property = bq20z75_get_property; + if (pdata) { + bq20z75_device->gpio_detect = + gpio_is_valid(pdata->battery_detect); + bq20z75_device->pdata = pdata; + } + i2c_set_clientdata(client, bq20z75_device); + if (!bq20z75_device->gpio_detect) + goto skip_gpio; + + rc = gpio_request(pdata->battery_detect, dev_name(&client->dev)); + if (rc) { + dev_warn(&client->dev, "Failed to request gpio: %d\n", rc); + bq20z75_device->gpio_detect = false; + goto skip_gpio; + } + + rc = gpio_direction_input(pdata->battery_detect); + if (rc) { + dev_warn(&client->dev, "Failed to get gpio as input: %d\n", rc); + gpio_free(pdata->battery_detect); + bq20z75_device->gpio_detect = false; + goto skip_gpio; + } + + irq = gpio_to_irq(pdata->battery_detect); + if (irq <= 0) { + dev_warn(&client->dev, "Failed to get gpio as irq: %d\n", irq); + gpio_free(pdata->battery_detect); + bq20z75_device->gpio_detect = false; + goto skip_gpio; + } + + rc = request_irq(irq, bq20z75_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + dev_name(&client->dev), &bq20z75_device->power_supply); + if (rc) { + dev_warn(&client->dev, "Failed to request irq: %d\n", rc); + gpio_free(pdata->battery_detect); + bq20z75_device->gpio_detect = false; + goto skip_gpio; + } + + bq20z75_device->irq = irq; + +skip_gpio: + rc = power_supply_register(&client->dev, &bq20z75_device->power_supply); if (rc) { dev_err(&client->dev, "%s: Failed to register power supply\n", __func__); - kfree(bq20z75_device); - return rc; + goto exit_psupply; } dev_info(&client->dev, "%s: battery gas gauge device registered\n", client->name); return 0; + +exit_psupply: + if (bq20z75_device->irq) + free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); + if (bq20z75_device->gpio_detect) + gpio_free(pdata->battery_detect); + + kfree(bq20z75_device); + + return rc; } -static int bq20z75_remove(struct i2c_client *client) +static int __devexit bq20z75_remove(struct i2c_client *client) { struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); + if (bq20z75_device->irq) + free_irq(bq20z75_device->irq, &bq20z75_device->power_supply); + if (bq20z75_device->gpio_detect) + gpio_free(bq20z75_device->pdata->battery_detect); + power_supply_unregister(&bq20z75_device->power_supply); kfree(bq20z75_device); bq20z75_device = NULL; @@ -544,7 +642,7 @@ static const struct i2c_device_id bq20z75_id[] = { static struct i2c_driver bq20z75_battery_driver = { .probe = bq20z75_probe, - .remove = bq20z75_remove, + .remove = __devexit_p(bq20z75_remove), .suspend = bq20z75_suspend, .resume = bq20z75_resume, .id_table = bq20z75_id, -- cgit v1.2.2 From ff28fcef1bedcfbdf49500fee1573dc2f3eedb22 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Mon, 28 Feb 2011 16:55:29 -0800 Subject: bq20z75: Add i2c retry mechanism With the support of platform data, now adding support for option i2c retries on read/write failures. Ths is specified through the optional platform data. Signed-off-by: Rhyland Klein Signed-off-by: Anton Vorontsov --- drivers/power/bq20z75.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index a51e98d74d34..e82d10e25e8c 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c @@ -156,30 +156,55 @@ struct bq20z75_info { static int bq20z75_read_word_data(struct i2c_client *client, u8 address) { - s32 ret; + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); + s32 ret = 0; + int retries = 1; + + if (bq20z75_device->pdata) + retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); + + while (retries > 0) { + ret = i2c_smbus_read_word_data(client, address); + if (ret >= 0) + break; + retries--; + } - ret = i2c_smbus_read_word_data(client, address); if (ret < 0) { - dev_err(&client->dev, + dev_warn(&client->dev, "%s: i2c read at address 0x%x failed\n", __func__, address); return ret; } + return le16_to_cpu(ret); } static int bq20z75_write_word_data(struct i2c_client *client, u8 address, u16 value) { - s32 ret; + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); + s32 ret = 0; + int retries = 1; + + if (bq20z75_device->pdata) + retries = max(bq20z75_device->pdata->i2c_retry_count + 1, 1); + + while (retries > 0) { + ret = i2c_smbus_write_word_data(client, address, + le16_to_cpu(value)); + if (ret >= 0) + break; + retries--; + } - ret = i2c_smbus_write_word_data(client, address, le16_to_cpu(value)); if (ret < 0) { - dev_err(&client->dev, + dev_warn(&client->dev, "%s: i2c write to address 0x%x failed\n", __func__, address); return ret; } + return 0; } -- cgit v1.2.2 From f3da0dee31689130a06f12f06575c7a5b62421ad Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 1 Mar 2011 17:22:33 +0800 Subject: bq20z75: Add MODULE_DEVICE_TABLE The device table is required to load modules based on modaliases. After adding the MODULE_DEVICE_TABLE, below entry will be added to modules.alias: alias i2c:bq20z75 bq20z75 Signed-off-by: Axel Lin Signed-off-by: Anton Vorontsov --- drivers/power/bq20z75.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index e82d10e25e8c..8018e8cc7a74 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c @@ -664,6 +664,7 @@ static const struct i2c_device_id bq20z75_id[] = { { "bq20z75", 0 }, {} }; +MODULE_DEVICE_TABLE(i2c, bq20z75_id); static struct i2c_driver bq20z75_battery_driver = { .probe = bq20z75_probe, -- cgit v1.2.2 From 84ab16f54bbde67c8c2aabc36b034c91044935cb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 1 Mar 2011 17:23:34 +0800 Subject: ds2782_battery: Add MODULE_DEVICE_TABLE The device table is required to load modules based on modaliases. After adding the MODULE_DEVICE_TABLE, below entries will be added to modules.alias: alias i2c:ds2786 ds2782_battery alias i2c:ds2782 ds2782_battery Signed-off-by: Axel Lin Signed-off-by: Anton Vorontsov --- drivers/power/ds2782_battery.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c index 6957e8af6449..4d2dc4fa2888 100644 --- a/drivers/power/ds2782_battery.c +++ b/drivers/power/ds2782_battery.c @@ -393,6 +393,7 @@ static const struct i2c_device_id ds278x_id[] = { {"ds2786", DS2786}, {}, }; +MODULE_DEVICE_TABLE(i2c, ds278x_id); static struct i2c_driver ds278x_battery_driver = { .driver = { -- cgit v1.2.2 From dcbc9169ed3ce7cd12328fec8b9eb9f7b91ce130 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 1 Mar 2011 17:24:34 +0800 Subject: z2_battery: Add MODULE_DEVICE_TABLE The device table is required to load modules based on modaliases. After adding the MODULE_DEVICE_TABLE, below entry will be added to modules.alias: alias i2c:aer915 z2_battery Signed-off-by: Axel Lin Signed-off-by: Anton Vorontsov --- drivers/power/z2_battery.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index e5ed52d71937..81304c0bb9d3 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c @@ -293,6 +293,7 @@ static const struct i2c_device_id z2_batt_id[] = { { "aer915", 0 }, { } }; +MODULE_DEVICE_TABLE(i2c, z2_batt_id); static struct i2c_driver z2_batt_driver = { .driver = { -- cgit v1.2.2 From 173442f2787c88e1ed1bb62aaeb6fd9127720559 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 1 Mar 2011 14:16:23 +0900 Subject: i2c-eg20t: support new device OKI SEMICONDUCTOR ML7213 IOH Support new device OKI SEMICONDUCTOR ML7213 IOH. The ML7213 which is for IVI(In-Vehicle Infotainment) is a companion chip for the Atom E6xx series and compatible with the Intel EG20T PCH. Signed-off-by: Tomoya MORINAGA Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 15 ++-- drivers/i2c/busses/i2c-eg20t.c | 161 +++++++++++++++++++++++++---------------- 2 files changed, 108 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 113505a6434e..5b592dfcbd78 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -639,12 +639,15 @@ config I2C_XILINX will be called xilinx_i2c. config I2C_EG20T - tristate "PCH I2C of Intel EG20T" - depends on PCI - help - This driver is for PCH(Platform controller Hub) I2C of EG20T which - is an IOH(Input/Output Hub) for x86 embedded processor. - This driver can access PCH I2C bus device. + tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH" + depends on PCI + help + This driver is for PCH(Platform controller Hub) I2C of EG20T which + is an IOH(Input/Output Hub) for x86 embedded processor. + This driver can access PCH I2C bus device. + + This driver also supports the ML7213, a companion chip for the + Atom E6xx series and compatible with the Intel EG20T PCH. comment "External I2C/SMBus adapter drivers" diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 2e067dd2ee51..c57c83734692 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -131,6 +131,13 @@ #define pch_pci_dbg(pdev, fmt, arg...) \ dev_dbg(&pdev->dev, "%s :" fmt, __func__, ##arg) +/* +Set the number of I2C instance max +Intel EG20T PCH : 1ch +OKI SEMICONDUCTOR ML7213 IOH : 2ch +*/ +#define PCH_I2C_MAX_DEV 2 + /** * struct i2c_algo_pch_data - for I2C driver functionalities * @pch_adapter: stores the reference to i2c_adapter structure @@ -155,12 +162,14 @@ struct i2c_algo_pch_data { * @pch_data: stores a list of i2c_algo_pch_data * @pch_i2c_suspended: specifies whether the system is suspended or not * perhaps with more lines and words. + * @ch_num: specifies the number of i2c instance * * pch_data has as many elements as maximum I2C channels */ struct adapter_info { - struct i2c_algo_pch_data pch_data; + struct i2c_algo_pch_data pch_data[PCH_I2C_MAX_DEV]; bool pch_i2c_suspended; + int ch_num; }; @@ -169,8 +178,13 @@ static int pch_clk = 50000; /* specifies I2C clock speed in KHz */ static wait_queue_head_t pch_event; static DEFINE_MUTEX(pch_mutex); +/* Definition for ML7213 by OKI SEMICONDUCTOR */ +#define PCI_VENDOR_ID_ROHM 0x10DB +#define PCI_DEVICE_ID_ML7213_I2C 0x802D + static struct pci_device_id __devinitdata pch_pcidev_id[] = { - {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH_I2C)}, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, }, {0,} }; @@ -211,8 +225,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap) /* Initialize I2C registers */ iowrite32(0x21, p + PCH_I2CNF); - pch_setbit(adap->pch_base_address, PCH_I2CCTL, - PCH_I2CCTL_I2CMEN); + pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_I2CCTL_I2CMEN); if (pch_i2c_speed != 400) pch_i2c_speed = 100; @@ -254,7 +267,7 @@ static inline bool ktime_lt(const ktime_t cmp1, const ktime_t cmp2) * @timeout: waiting time counter (us). */ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, - s32 timeout) + s32 timeout) { void __iomem *p = adap->pch_base_address; @@ -474,8 +487,8 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap) * @last: specifies whether last message or not. * @first: specifies whether first message or not. */ -s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, - u32 last, u32 first) +static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, + u32 last, u32 first) { struct i2c_algo_pch_data *adap = i2c_adap->algo_data; @@ -568,10 +581,10 @@ s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, } /** - * pch_i2c_cb_ch0() - Interrupt handler Call back function + * pch_i2c_cb() - Interrupt handler Call back function * @adap: Pointer to struct i2c_algo_pch_data. */ -static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap) +static void pch_i2c_cb(struct i2c_algo_pch_data *adap) { u32 sts; void __iomem *p = adap->pch_base_address; @@ -599,24 +612,30 @@ static void pch_i2c_cb_ch0(struct i2c_algo_pch_data *adap) */ static irqreturn_t pch_i2c_handler(int irq, void *pData) { - s32 reg_val; - - struct i2c_algo_pch_data *adap_data = (struct i2c_algo_pch_data *)pData; - void __iomem *p = adap_data->pch_base_address; - u32 mode = ioread32(p + PCH_I2CMOD) & (BUFFER_MODE | EEPROM_SR_MODE); - - if (mode != NORMAL_MODE) { - pch_err(adap_data, "I2C mode is not supported\n"); - return IRQ_NONE; + u32 reg_val; + int flag; + int i; + struct adapter_info *adap_info = pData; + void __iomem *p; + u32 mode; + + for (i = 0, flag = 0; i < adap_info->ch_num; i++) { + p = adap_info->pch_data[i].pch_base_address; + mode = ioread32(p + PCH_I2CMOD); + mode &= BUFFER_MODE | EEPROM_SR_MODE; + if (mode != NORMAL_MODE) { + pch_err(adap_info->pch_data, + "I2C-%d mode(%d) is not supported\n", mode, i); + continue; + } + reg_val = ioread32(p + PCH_I2CSR); + if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) { + pch_i2c_cb(&adap_info->pch_data[i]); + flag = 1; + } } - reg_val = ioread32(p + PCH_I2CSR); - if (reg_val & (I2CMAL_BIT | I2CMCF_BIT | I2CMIF_BIT)) - pch_i2c_cb_ch0(adap_data); - else - return IRQ_NONE; - - return IRQ_HANDLED; + return flag ? IRQ_HANDLED : IRQ_NONE; } /** @@ -626,7 +645,7 @@ static irqreturn_t pch_i2c_handler(int irq, void *pData) * @num: number of messages. */ static s32 pch_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, s32 num) + struct i2c_msg *msgs, s32 num) { struct i2c_msg *pmsg; u32 i = 0; @@ -709,11 +728,13 @@ static void pch_i2c_disbl_int(struct i2c_algo_pch_data *adap) } static int __devinit pch_i2c_probe(struct pci_dev *pdev, - const struct pci_device_id *id) + const struct pci_device_id *id) { void __iomem *base_addr; - s32 ret; + int ret; + int i, j; struct adapter_info *adap_info; + struct i2c_adapter *pch_adap; pch_pci_dbg(pdev, "Entered.\n"); @@ -743,44 +764,48 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, goto err_pci_iomap; } - adap_info->pch_i2c_suspended = false; + /* Set the number of I2C channel instance */ + adap_info->ch_num = id->driver_data; - adap_info->pch_data.p_adapter_info = adap_info; + for (i = 0; i < adap_info->ch_num; i++) { + pch_adap = &adap_info->pch_data[i].pch_adapter; + adap_info->pch_i2c_suspended = false; - adap_info->pch_data.pch_adapter.owner = THIS_MODULE; - adap_info->pch_data.pch_adapter.class = I2C_CLASS_HWMON; - strcpy(adap_info->pch_data.pch_adapter.name, KBUILD_MODNAME); - adap_info->pch_data.pch_adapter.algo = &pch_algorithm; - adap_info->pch_data.pch_adapter.algo_data = - &adap_info->pch_data; + adap_info->pch_data[i].p_adapter_info = adap_info; - /* (i * 0x80) + base_addr; */ - adap_info->pch_data.pch_base_address = base_addr; + pch_adap->owner = THIS_MODULE; + pch_adap->class = I2C_CLASS_HWMON; + strcpy(pch_adap->name, KBUILD_MODNAME); + pch_adap->algo = &pch_algorithm; + pch_adap->algo_data = &adap_info->pch_data[i]; - adap_info->pch_data.pch_adapter.dev.parent = &pdev->dev; + /* base_addr + offset; */ + adap_info->pch_data[i].pch_base_address = base_addr + 0x100 * i; - ret = i2c_add_adapter(&(adap_info->pch_data.pch_adapter)); + pch_adap->dev.parent = &pdev->dev; - if (ret) { - pch_pci_err(pdev, "i2c_add_adapter FAILED\n"); - goto err_i2c_add_adapter; - } + ret = i2c_add_adapter(pch_adap); + if (ret) { + pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i); + goto err_i2c_add_adapter; + } - pch_i2c_init(&adap_info->pch_data); + pch_i2c_init(&adap_info->pch_data[i]); + } ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, - KBUILD_MODNAME, &adap_info->pch_data); + KBUILD_MODNAME, adap_info); if (ret) { pch_pci_err(pdev, "request_irq FAILED\n"); - goto err_request_irq; + goto err_i2c_add_adapter; } pci_set_drvdata(pdev, adap_info); pch_pci_dbg(pdev, "returns %d.\n", ret); return 0; -err_request_irq: - i2c_del_adapter(&(adap_info->pch_data.pch_adapter)); err_i2c_add_adapter: + for (j = 0; j < i; j++) + i2c_del_adapter(&adap_info->pch_data[j].pch_adapter); pci_iounmap(pdev, base_addr); err_pci_iomap: pci_release_regions(pdev); @@ -793,17 +818,22 @@ err_pci_enable: static void __devexit pch_i2c_remove(struct pci_dev *pdev) { + int i; struct adapter_info *adap_info = pci_get_drvdata(pdev); - pch_i2c_disbl_int(&adap_info->pch_data); - free_irq(pdev->irq, &adap_info->pch_data); - i2c_del_adapter(&(adap_info->pch_data.pch_adapter)); + free_irq(pdev->irq, adap_info); - if (adap_info->pch_data.pch_base_address) { - pci_iounmap(pdev, adap_info->pch_data.pch_base_address); - adap_info->pch_data.pch_base_address = 0; + for (i = 0; i < adap_info->ch_num; i++) { + pch_i2c_disbl_int(&adap_info->pch_data[i]); + i2c_del_adapter(&adap_info->pch_data[i].pch_adapter); } + if (adap_info->pch_data[0].pch_base_address) + pci_iounmap(pdev, adap_info->pch_data[0].pch_base_address); + + for (i = 0; i < adap_info->ch_num; i++) + adap_info->pch_data[i].pch_base_address = 0; + pci_set_drvdata(pdev, NULL); pci_release_regions(pdev); @@ -816,17 +846,22 @@ static void __devexit pch_i2c_remove(struct pci_dev *pdev) static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state) { int ret; + int i; struct adapter_info *adap_info = pci_get_drvdata(pdev); - void __iomem *p = adap_info->pch_data.pch_base_address; + void __iomem *p = adap_info->pch_data[0].pch_base_address; adap_info->pch_i2c_suspended = true; - while ((adap_info->pch_data.pch_i2c_xfer_in_progress)) { - /* Wait until all channel transfers are completed */ - msleep(20); + for (i = 0; i < adap_info->ch_num; i++) { + while ((adap_info->pch_data[i].pch_i2c_xfer_in_progress)) { + /* Wait until all channel transfers are completed */ + msleep(20); + } } + /* Disable the i2c interrupts */ - pch_i2c_disbl_int(&adap_info->pch_data); + for (i = 0; i < adap_info->ch_num; i++) + pch_i2c_disbl_int(&adap_info->pch_data[i]); pch_pci_dbg(pdev, "I2CSR = %x I2CBUFSTA = %x I2CESRSTA = %x " "invoked function pch_i2c_disbl_int successfully\n", @@ -849,6 +884,7 @@ static int pch_i2c_suspend(struct pci_dev *pdev, pm_message_t state) static int pch_i2c_resume(struct pci_dev *pdev) { + int i; struct adapter_info *adap_info = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); @@ -861,7 +897,8 @@ static int pch_i2c_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D3hot, 0); - pch_i2c_init(&adap_info->pch_data); + for (i = 0; i < adap_info->ch_num; i++) + pch_i2c_init(&adap_info->pch_data[i]); adap_info->pch_i2c_suspended = false; @@ -893,7 +930,7 @@ static void __exit pch_pci_exit(void) } module_exit(pch_pci_exit); -MODULE_DESCRIPTION("PCH I2C PCI Driver"); +MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH I2C Driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tomoya MORINAGA. "); module_param(pch_i2c_speed, int, (S_IRUSR | S_IWUSR)); -- cgit v1.2.2 From a580b8c5429a624d120cd603e1498bf676e2b4da Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Sun, 27 Feb 2011 00:47:42 +0800 Subject: dmaengine: mxs-dma: add dma support for i.MX23/28 This patch adds dma support for Freescale MXS-based SoC i.MX23/28, including apbh-dma and apbx-dma. * apbh-dma and apbx-dma are supported in the driver as two mxs-dma instances. * apbh-dma is different between mx23 and mx28, hardware version register is used to differentiate. * mxs-dma supports pio function besides data transfer. The driver uses dma_data_direction DMA_NONE to identify the pio mode, and steals sgl and sg_len to get pio words and numbers from clients. * mxs dmaengine has some very specific features, like sense function and the special NAND support (nand_lock, nand_wait4ready). These are too specific to implemented in generic dmaengine driver. * The driver refers to imx-sdma and only a single descriptor is statically assigned to each channel. Signed-off-by: Shawn Guo Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 8 + drivers/dma/Makefile | 1 + drivers/dma/mxs-dma.c | 724 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 733 insertions(+) create mode 100644 drivers/dma/mxs-dma.c (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 1c28816152fa..76f6472ba315 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -227,6 +227,14 @@ config IMX_DMA Support the i.MX DMA engine. This engine is integrated into Freescale i.MX1/21/27 chips. +config MXS_DMA + bool "MXS DMA support" + depends on SOC_IMX23 || SOC_IMX28 + select DMA_ENGINE + help + Support the MXS DMA engine. This engine including APBH-DMA + and APBX-DMA is integrated into Freescale i.MX23/28 chips. + config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 64b21f5cd740..802b55795f8b 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/ obj-$(CONFIG_IMX_SDMA) += imx-sdma.o obj-$(CONFIG_IMX_DMA) += imx-dma.o +obj-$(CONFIG_MXS_DMA) += mxs-dma.o obj-$(CONFIG_TIMB_DMA) += timb_dma.o obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o obj-$(CONFIG_PL330_DMA) += pl330.o diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c new file mode 100644 index 000000000000..88aad4f54002 --- /dev/null +++ b/drivers/dma/mxs-dma.c @@ -0,0 +1,724 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Refer to drivers/dma/imx-sdma.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * NOTE: The term "PIO" throughout the mxs-dma implementation means + * PIO mode of mxs apbh-dma and apbx-dma. With this working mode, + * dma can program the controller registers of peripheral devices. + */ + +#define MXS_DMA_APBH 0 +#define MXS_DMA_APBX 1 +#define dma_is_apbh() (mxs_dma->dev_id == MXS_DMA_APBH) + +#define APBH_VERSION_LATEST 3 +#define apbh_is_old() (mxs_dma->version < APBH_VERSION_LATEST) + +#define HW_APBHX_CTRL0 0x000 +#define BM_APBH_CTRL0_APB_BURST8_EN (1 << 29) +#define BM_APBH_CTRL0_APB_BURST_EN (1 << 28) +#define BP_APBH_CTRL0_CLKGATE_CHANNEL 8 +#define BP_APBH_CTRL0_RESET_CHANNEL 16 +#define HW_APBHX_CTRL1 0x010 +#define HW_APBHX_CTRL2 0x020 +#define HW_APBHX_CHANNEL_CTRL 0x030 +#define BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL 16 +#define HW_APBH_VERSION (cpu_is_mx23() ? 0x3f0 : 0x800) +#define HW_APBX_VERSION 0x800 +#define BP_APBHX_VERSION_MAJOR 24 +#define HW_APBHX_CHn_NXTCMDAR(n) \ + (((dma_is_apbh() && apbh_is_old()) ? 0x050 : 0x110) + (n) * 0x70) +#define HW_APBHX_CHn_SEMA(n) \ + (((dma_is_apbh() && apbh_is_old()) ? 0x080 : 0x140) + (n) * 0x70) + +/* + * ccw bits definitions + * + * COMMAND: 0..1 (2) + * CHAIN: 2 (1) + * IRQ: 3 (1) + * NAND_LOCK: 4 (1) - not implemented + * NAND_WAIT4READY: 5 (1) - not implemented + * DEC_SEM: 6 (1) + * WAIT4END: 7 (1) + * HALT_ON_TERMINATE: 8 (1) + * TERMINATE_FLUSH: 9 (1) + * RESERVED: 10..11 (2) + * PIO_NUM: 12..15 (4) + */ +#define BP_CCW_COMMAND 0 +#define BM_CCW_COMMAND (3 << 0) +#define CCW_CHAIN (1 << 2) +#define CCW_IRQ (1 << 3) +#define CCW_DEC_SEM (1 << 6) +#define CCW_WAIT4END (1 << 7) +#define CCW_HALT_ON_TERM (1 << 8) +#define CCW_TERM_FLUSH (1 << 9) +#define BP_CCW_PIO_NUM 12 +#define BM_CCW_PIO_NUM (0xf << 12) + +#define BF_CCW(value, field) (((value) << BP_CCW_##field) & BM_CCW_##field) + +#define MXS_DMA_CMD_NO_XFER 0 +#define MXS_DMA_CMD_WRITE 1 +#define MXS_DMA_CMD_READ 2 +#define MXS_DMA_CMD_DMA_SENSE 3 /* not implemented */ + +struct mxs_dma_ccw { + u32 next; + u16 bits; + u16 xfer_bytes; +#define MAX_XFER_BYTES 0xff00 + u32 bufaddr; +#define MXS_PIO_WORDS 16 + u32 pio_words[MXS_PIO_WORDS]; +}; + +#define NUM_CCW (int)(PAGE_SIZE / sizeof(struct mxs_dma_ccw)) + +struct mxs_dma_chan { + struct mxs_dma_engine *mxs_dma; + struct dma_chan chan; + struct dma_async_tx_descriptor desc; + struct tasklet_struct tasklet; + int chan_irq; + struct mxs_dma_ccw *ccw; + dma_addr_t ccw_phys; + dma_cookie_t last_completed; + enum dma_status status; + unsigned int flags; +#define MXS_DMA_SG_LOOP (1 << 0) +}; + +#define MXS_DMA_CHANNELS 16 +#define MXS_DMA_CHANNELS_MASK 0xffff + +struct mxs_dma_engine { + int dev_id; + unsigned int version; + void __iomem *base; + struct clk *clk; + struct dma_device dma_device; + struct device_dma_parameters dma_parms; + struct mxs_dma_chan mxs_chans[MXS_DMA_CHANNELS]; +}; + +static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan) +{ + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int chan_id = mxs_chan->chan.chan_id; + + if (dma_is_apbh() && apbh_is_old()) + writel(1 << (chan_id + BP_APBH_CTRL0_RESET_CHANNEL), + mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); + else + writel(1 << (chan_id + BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL), + mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR); +} + +static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan) +{ + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int chan_id = mxs_chan->chan.chan_id; + + /* set cmd_addr up */ + writel(mxs_chan->ccw_phys, + mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id)); + + /* enable apbh channel clock */ + if (dma_is_apbh()) { + if (apbh_is_old()) + writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), + mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); + else + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); + } + + /* write 1 to SEMA to kick off the channel */ + writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id)); +} + +static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan) +{ + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int chan_id = mxs_chan->chan.chan_id; + + /* disable apbh channel clock */ + if (dma_is_apbh()) { + if (apbh_is_old()) + writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL), + mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); + else + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); + } + + mxs_chan->status = DMA_SUCCESS; +} + +static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan) +{ + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int chan_id = mxs_chan->chan.chan_id; + + /* freeze the channel */ + if (dma_is_apbh() && apbh_is_old()) + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); + else + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR); + + mxs_chan->status = DMA_PAUSED; +} + +static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan) +{ + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int chan_id = mxs_chan->chan.chan_id; + + /* unfreeze the channel */ + if (dma_is_apbh() && apbh_is_old()) + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR); + else + writel(1 << chan_id, + mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_CLR_ADDR); + + mxs_chan->status = DMA_IN_PROGRESS; +} + +static dma_cookie_t mxs_dma_assign_cookie(struct mxs_dma_chan *mxs_chan) +{ + dma_cookie_t cookie = mxs_chan->chan.cookie; + + if (++cookie < 0) + cookie = 1; + + mxs_chan->chan.cookie = cookie; + mxs_chan->desc.cookie = cookie; + + return cookie; +} + +static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct mxs_dma_chan, chan); +} + +static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx) +{ + struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(tx->chan); + + mxs_dma_enable_chan(mxs_chan); + + return mxs_dma_assign_cookie(mxs_chan); +} + +static void mxs_dma_tasklet(unsigned long data) +{ + struct mxs_dma_chan *mxs_chan = (struct mxs_dma_chan *) data; + + if (mxs_chan->desc.callback) + mxs_chan->desc.callback(mxs_chan->desc.callback_param); +} + +static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id) +{ + struct mxs_dma_engine *mxs_dma = dev_id; + u32 stat1, stat2; + + /* completion status */ + stat1 = readl(mxs_dma->base + HW_APBHX_CTRL1); + stat1 &= MXS_DMA_CHANNELS_MASK; + writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + MXS_CLR_ADDR); + + /* error status */ + stat2 = readl(mxs_dma->base + HW_APBHX_CTRL2); + writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + MXS_CLR_ADDR); + + /* + * When both completion and error of termination bits set at the + * same time, we do not take it as an error. IOW, it only becomes + * an error we need to handler here in case of ether it's (1) an bus + * error or (2) a termination error with no completion. + */ + stat2 = ((stat2 >> MXS_DMA_CHANNELS) & stat2) | /* (1) */ + (~(stat2 >> MXS_DMA_CHANNELS) & stat2 & ~stat1); /* (2) */ + + /* combine error and completion status for checking */ + stat1 = (stat2 << MXS_DMA_CHANNELS) | stat1; + while (stat1) { + int channel = fls(stat1) - 1; + struct mxs_dma_chan *mxs_chan = + &mxs_dma->mxs_chans[channel % MXS_DMA_CHANNELS]; + + if (channel >= MXS_DMA_CHANNELS) { + dev_dbg(mxs_dma->dma_device.dev, + "%s: error in channel %d\n", __func__, + channel - MXS_DMA_CHANNELS); + mxs_chan->status = DMA_ERROR; + mxs_dma_reset_chan(mxs_chan); + } else { + if (mxs_chan->flags & MXS_DMA_SG_LOOP) + mxs_chan->status = DMA_IN_PROGRESS; + else + mxs_chan->status = DMA_SUCCESS; + } + + stat1 &= ~(1 << channel); + + if (mxs_chan->status == DMA_SUCCESS) + mxs_chan->last_completed = mxs_chan->desc.cookie; + + /* schedule tasklet on this channel */ + tasklet_schedule(&mxs_chan->tasklet); + } + + return IRQ_HANDLED; +} + +static int mxs_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); + struct mxs_dma_data *data = chan->private; + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int ret; + + if (!data) + return -EINVAL; + + mxs_chan->chan_irq = data->chan_irq; + + mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev, PAGE_SIZE, + &mxs_chan->ccw_phys, GFP_KERNEL); + if (!mxs_chan->ccw) { + ret = -ENOMEM; + goto err_alloc; + } + + memset(mxs_chan->ccw, 0, PAGE_SIZE); + + ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler, + 0, "mxs-dma", mxs_dma); + if (ret) + goto err_irq; + + ret = clk_enable(mxs_dma->clk); + if (ret) + goto err_clk; + + mxs_dma_reset_chan(mxs_chan); + + dma_async_tx_descriptor_init(&mxs_chan->desc, chan); + mxs_chan->desc.tx_submit = mxs_dma_tx_submit; + + /* the descriptor is ready */ + async_tx_ack(&mxs_chan->desc); + + return 0; + +err_clk: + free_irq(mxs_chan->chan_irq, mxs_dma); +err_irq: + dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE, + mxs_chan->ccw, mxs_chan->ccw_phys); +err_alloc: + return ret; +} + +static void mxs_dma_free_chan_resources(struct dma_chan *chan) +{ + struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + + mxs_dma_disable_chan(mxs_chan); + + free_irq(mxs_chan->chan_irq, mxs_dma); + + dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE, + mxs_chan->ccw, mxs_chan->ccw_phys); + + clk_disable(mxs_dma->clk); +} + +static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_data_direction direction, + unsigned long append) +{ + struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + struct mxs_dma_ccw *ccw; + struct scatterlist *sg; + int i, j; + u32 *pio; + static int idx; + + if (mxs_chan->status == DMA_IN_PROGRESS && !append) + return NULL; + + if (sg_len + (append ? idx : 0) > NUM_CCW) { + dev_err(mxs_dma->dma_device.dev, + "maximum number of sg exceeded: %d > %d\n", + sg_len, NUM_CCW); + goto err_out; + } + + mxs_chan->status = DMA_IN_PROGRESS; + mxs_chan->flags = 0; + + /* + * If the sg is prepared with append flag set, the sg + * will be appended to the last prepared sg. + */ + if (append) { + BUG_ON(idx < 1); + ccw = &mxs_chan->ccw[idx - 1]; + ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx; + ccw->bits |= CCW_CHAIN; + ccw->bits &= ~CCW_IRQ; + ccw->bits &= ~CCW_DEC_SEM; + ccw->bits &= ~CCW_WAIT4END; + } else { + idx = 0; + } + + if (direction == DMA_NONE) { + ccw = &mxs_chan->ccw[idx++]; + pio = (u32 *) sgl; + + for (j = 0; j < sg_len;) + ccw->pio_words[j++] = *pio++; + + ccw->bits = 0; + ccw->bits |= CCW_IRQ; + ccw->bits |= CCW_DEC_SEM; + ccw->bits |= CCW_WAIT4END; + ccw->bits |= CCW_HALT_ON_TERM; + ccw->bits |= CCW_TERM_FLUSH; + ccw->bits |= BF_CCW(sg_len, PIO_NUM); + ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND); + } else { + for_each_sg(sgl, sg, sg_len, i) { + if (sg->length > MAX_XFER_BYTES) { + dev_err(mxs_dma->dma_device.dev, "maximum bytes for sg entry exceeded: %d > %d\n", + sg->length, MAX_XFER_BYTES); + goto err_out; + } + + ccw = &mxs_chan->ccw[idx++]; + + ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx; + ccw->bufaddr = sg->dma_address; + ccw->xfer_bytes = sg->length; + + ccw->bits = 0; + ccw->bits |= CCW_CHAIN; + ccw->bits |= CCW_HALT_ON_TERM; + ccw->bits |= CCW_TERM_FLUSH; + ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ? + MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, + COMMAND); + + if (i + 1 == sg_len) { + ccw->bits &= ~CCW_CHAIN; + ccw->bits |= CCW_IRQ; + ccw->bits |= CCW_DEC_SEM; + ccw->bits |= CCW_WAIT4END; + } + } + } + + return &mxs_chan->desc; + +err_out: + mxs_chan->status = DMA_ERROR; + return NULL; +} + +static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len, + size_t period_len, enum dma_data_direction direction) +{ + struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); + struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; + int num_periods = buf_len / period_len; + int i = 0, buf = 0; + + if (mxs_chan->status == DMA_IN_PROGRESS) + return NULL; + + mxs_chan->status = DMA_IN_PROGRESS; + mxs_chan->flags |= MXS_DMA_SG_LOOP; + + if (num_periods > NUM_CCW) { + dev_err(mxs_dma->dma_device.dev, + "maximum number of sg exceeded: %d > %d\n", + num_periods, NUM_CCW); + goto err_out; + } + + if (period_len > MAX_XFER_BYTES) { + dev_err(mxs_dma->dma_device.dev, + "maximum period size exceeded: %d > %d\n", + period_len, MAX_XFER_BYTES); + goto err_out; + } + + while (buf < buf_len) { + struct mxs_dma_ccw *ccw = &mxs_chan->ccw[i]; + + if (i + 1 == num_periods) + ccw->next = mxs_chan->ccw_phys; + else + ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * (i + 1); + + ccw->bufaddr = dma_addr; + ccw->xfer_bytes = period_len; + + ccw->bits = 0; + ccw->bits |= CCW_CHAIN; + ccw->bits |= CCW_IRQ; + ccw->bits |= CCW_HALT_ON_TERM; + ccw->bits |= CCW_TERM_FLUSH; + ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ? + MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, COMMAND); + + dma_addr += period_len; + buf += period_len; + + i++; + } + + return &mxs_chan->desc; + +err_out: + mxs_chan->status = DMA_ERROR; + return NULL; +} + +static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, + unsigned long arg) +{ + struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); + int ret = 0; + + switch (cmd) { + case DMA_TERMINATE_ALL: + mxs_dma_disable_chan(mxs_chan); + break; + case DMA_PAUSE: + mxs_dma_pause_chan(mxs_chan); + break; + case DMA_RESUME: + mxs_dma_resume_chan(mxs_chan); + break; + default: + ret = -ENOSYS; + } + + return ret; +} + +static enum dma_status mxs_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *txstate) +{ + struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan); + dma_cookie_t last_used; + + last_used = chan->cookie; + dma_set_tx_state(txstate, mxs_chan->last_completed, last_used, 0); + + return mxs_chan->status; +} + +static void mxs_dma_issue_pending(struct dma_chan *chan) +{ + /* + * Nothing to do. We only have a single descriptor. + */ +} + +static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma) +{ + int ret; + + ret = clk_enable(mxs_dma->clk); + if (ret) + goto err_out; + + ret = mxs_reset_block(mxs_dma->base); + if (ret) + goto err_out; + + /* only major version matters */ + mxs_dma->version = readl(mxs_dma->base + + ((mxs_dma->dev_id == MXS_DMA_APBX) ? + HW_APBX_VERSION : HW_APBH_VERSION)) >> + BP_APBHX_VERSION_MAJOR; + + /* enable apbh burst */ + if (dma_is_apbh()) { + writel(BM_APBH_CTRL0_APB_BURST_EN, + mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); + writel(BM_APBH_CTRL0_APB_BURST8_EN, + mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR); + } + + /* enable irq for all the channels */ + writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS, + mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR); + + clk_disable(mxs_dma->clk); + + return 0; + +err_out: + return ret; +} + +static int __init mxs_dma_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id_entry = + platform_get_device_id(pdev); + struct mxs_dma_engine *mxs_dma; + struct resource *iores; + int ret, i; + + mxs_dma = kzalloc(sizeof(*mxs_dma), GFP_KERNEL); + if (!mxs_dma) + return -ENOMEM; + + mxs_dma->dev_id = id_entry->driver_data; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!request_mem_region(iores->start, resource_size(iores), + pdev->name)) { + ret = -EBUSY; + goto err_request_region; + } + + mxs_dma->base = ioremap(iores->start, resource_size(iores)); + if (!mxs_dma->base) { + ret = -ENOMEM; + goto err_ioremap; + } + + mxs_dma->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(mxs_dma->clk)) { + ret = PTR_ERR(mxs_dma->clk); + goto err_clk; + } + + dma_cap_set(DMA_SLAVE, mxs_dma->dma_device.cap_mask); + dma_cap_set(DMA_CYCLIC, mxs_dma->dma_device.cap_mask); + + INIT_LIST_HEAD(&mxs_dma->dma_device.channels); + + /* Initialize channel parameters */ + for (i = 0; i < MXS_DMA_CHANNELS; i++) { + struct mxs_dma_chan *mxs_chan = &mxs_dma->mxs_chans[i]; + + mxs_chan->mxs_dma = mxs_dma; + mxs_chan->chan.device = &mxs_dma->dma_device; + + tasklet_init(&mxs_chan->tasklet, mxs_dma_tasklet, + (unsigned long) mxs_chan); + + + /* Add the channel to mxs_chan list */ + list_add_tail(&mxs_chan->chan.device_node, + &mxs_dma->dma_device.channels); + } + + ret = mxs_dma_init(mxs_dma); + if (ret) + goto err_init; + + mxs_dma->dma_device.dev = &pdev->dev; + + /* mxs_dma gets 65535 bytes maximum sg size */ + mxs_dma->dma_device.dev->dma_parms = &mxs_dma->dma_parms; + dma_set_max_seg_size(mxs_dma->dma_device.dev, MAX_XFER_BYTES); + + mxs_dma->dma_device.device_alloc_chan_resources = mxs_dma_alloc_chan_resources; + mxs_dma->dma_device.device_free_chan_resources = mxs_dma_free_chan_resources; + mxs_dma->dma_device.device_tx_status = mxs_dma_tx_status; + mxs_dma->dma_device.device_prep_slave_sg = mxs_dma_prep_slave_sg; + mxs_dma->dma_device.device_prep_dma_cyclic = mxs_dma_prep_dma_cyclic; + mxs_dma->dma_device.device_control = mxs_dma_control; + mxs_dma->dma_device.device_issue_pending = mxs_dma_issue_pending; + + ret = dma_async_device_register(&mxs_dma->dma_device); + if (ret) { + dev_err(mxs_dma->dma_device.dev, "unable to register\n"); + goto err_init; + } + + dev_info(mxs_dma->dma_device.dev, "initialized\n"); + + return 0; + +err_init: + clk_put(mxs_dma->clk); +err_clk: + iounmap(mxs_dma->base); +err_ioremap: + release_mem_region(iores->start, resource_size(iores)); +err_request_region: + kfree(mxs_dma); + return ret; +} + +static struct platform_device_id mxs_dma_type[] = { + { + .name = "mxs-dma-apbh", + .driver_data = MXS_DMA_APBH, + }, { + .name = "mxs-dma-apbx", + .driver_data = MXS_DMA_APBX, + } +}; + +static struct platform_driver mxs_dma_driver = { + .driver = { + .name = "mxs-dma", + }, + .id_table = mxs_dma_type, +}; + +static int __init mxs_dma_module_init(void) +{ + return platform_driver_probe(&mxs_dma_driver, mxs_dma_probe); +} +subsys_initcall(mxs_dma_module_init); -- cgit v1.2.2 From cd25f54961273c2e4cbd47441e04832468382a5e Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 2 Mar 2011 19:04:50 -0500 Subject: loop: No need to initialize ->queue_lock explicitly before calling blk_cleanup_queue() Now we initialize ->queue_lock at queue allocation time so driver does not have to worry about initializing it before calling blk_cleanup_queue(). Signed-off-by: Jens Axboe --- drivers/block/loop.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 49e6a545eb63..44e18c073c44 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1641,9 +1641,6 @@ out: static void loop_free(struct loop_device *lo) { - if (!lo->lo_queue->queue_lock) - lo->lo_queue->queue_lock = &lo->lo_queue->__queue_lock; - blk_cleanup_queue(lo->lo_queue); put_disk(lo->lo_disk); list_del(&lo->lo_list); -- cgit v1.2.2 From 6dfad339645247c9deb553e4d68e21211ddc61bd Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Mon, 14 Feb 2011 15:29:34 +0800 Subject: ACPICA: GPE detect optimization - ignore unused GPE registers This optimization will simply ignore GPE registers that contain no enabled GPEs - there is no need to read the register. ACPICA bugzilla 884. http://www.acpica.org/bugzilla/show_bug.cgi?id=884 Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/acpica/evgpe.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 14988a86066f..67d44ef2fbc1 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -373,6 +373,15 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) gpe_register_info = &gpe_block->register_info[i]; + /* + * Optimization: If there are no GPEs enabled within this + * register, we can safely ignore the entire register. + */ + if (!(gpe_register_info->enable_for_run | + gpe_register_info->enable_for_wake)) { + continue; + } + /* Read the Status Register */ status = -- cgit v1.2.2 From 64b3db22c04586997ab4be46dd5a5b99f8a2d390 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Feb 2011 15:50:42 +0800 Subject: ACPICA: Remove use of unreliable FADT revision field The revision number in the FADT has been found to be completely unreliable and cannot be trusted. Only the table length can be used to infer the actual version. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/tbfadt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 428d44e2d162..6f5588e62c0a 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -384,8 +384,11 @@ static void acpi_tb_convert_fadt(void) * * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at * offset 45, 55, 95, and the word located at offset 109, 110. + * + * Note: The FADT revision value is unreliable. Only the length can be + * trusted. */ - if (acpi_gbl_FADT.header.revision < FADT2_REVISION_ID) { + if (acpi_gbl_FADT.header.length <= ACPI_FADT_V2_SIZE) { acpi_gbl_FADT.preferred_profile = 0; acpi_gbl_FADT.pstate_control = 0; acpi_gbl_FADT.cst_control = 0; -- cgit v1.2.2 From 1b74dfb2f735454031584dc8162f8f27aa5265bf Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Feb 2011 15:52:56 +0800 Subject: ACPICA: Clarify a couple of error messages Clarify region error messages with ID= prefix for space id. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/exfldio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 6c79c29f082d..f915a7f3f921 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -280,13 +280,13 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, if (ACPI_FAILURE(status)) { if (status == AE_NOT_IMPLEMENTED) { ACPI_ERROR((AE_INFO, - "Region %s(0x%X) not implemented", + "Region %s (ID=%u) not implemented", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id)); } else if (status == AE_NOT_EXIST) { ACPI_ERROR((AE_INFO, - "Region %s(0x%X) has no handler", + "Region %s (ID=%u) has no handler", acpi_ut_get_region_name(rgn_desc->region. space_id), rgn_desc->region.space_id)); -- cgit v1.2.2 From a257e07527890a7f95982b9c330efd8d2de3707a Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Feb 2011 16:00:21 +0800 Subject: ACPICA: Split large utglobal into utdecode.c. utglobal.c contained a lot of code not related to global variables. These utility decode functions are moved to utdecode.c Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/Makefile | 2 +- drivers/acpi/acpica/aclocal.h | 19 -- drivers/acpi/acpica/utdecode.c | 546 +++++++++++++++++++++++++++++++++++++++++ drivers/acpi/acpica/utglobal.c | 483 ------------------------------------ 4 files changed, 547 insertions(+), 503 deletions(-) create mode 100644 drivers/acpi/acpica/utdecode.c (limited to 'drivers') diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index eec2eadd2431..b1706aacbe98 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -45,4 +45,4 @@ acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o acpi-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ utstate.o utmutex.o utobject.o utresrc.o utlock.o utids.o \ - utosi.o utxferror.o + utosi.o utxferror.o utdecode.o diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 54784bb42cec..01bcab1c5cc4 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -89,25 +89,6 @@ union acpi_parse_object; #define ACPI_MAX_MUTEX 7 #define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1 -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -#ifdef DEFINE_ACPI_GLOBALS - -/* Debug names for the mutexes above */ - -static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { - "ACPI_MTX_Interpreter", - "ACPI_MTX_Namespace", - "ACPI_MTX_Tables", - "ACPI_MTX_Events", - "ACPI_MTX_Caches", - "ACPI_MTX_Memory", - "ACPI_MTX_CommandComplete", - "ACPI_MTX_CommandReady" -}; - -#endif -#endif - /* Lock structure for reader/writer interfaces */ struct acpi_rw_lock { diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c new file mode 100644 index 000000000000..ce91e59c449f --- /dev/null +++ b/drivers/acpi/acpica/utdecode.c @@ -0,0 +1,546 @@ +/****************************************************************************** + * + * Module Name: utdecode - Utility decoding routines (value-to-string) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2011, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utdecode") + +/******************************************************************************* + * + * FUNCTION: acpi_format_exception + * + * PARAMETERS: Status - The acpi_status code to be formatted + * + * RETURN: A string containing the exception text. A valid pointer is + * always returned. + * + * DESCRIPTION: This function translates an ACPI exception into an ASCII string + * It is here instead of utxface.c so it is always present. + * + ******************************************************************************/ +const char *acpi_format_exception(acpi_status status) +{ + const char *exception = NULL; + + ACPI_FUNCTION_ENTRY(); + + exception = acpi_ut_validate_exception(status); + if (!exception) { + + /* Exception code was not recognized */ + + ACPI_ERROR((AE_INFO, + "Unknown exception code: 0x%8.8X", status)); + + exception = "UNKNOWN_STATUS_CODE"; + } + + return (ACPI_CAST_PTR(const char, exception)); +} + +ACPI_EXPORT_SYMBOL(acpi_format_exception) + +/* + * Properties of the ACPI Object Types, both internal and external. + * The table is indexed by values of acpi_object_type + */ +const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES] = { + ACPI_NS_NORMAL, /* 00 Any */ + ACPI_NS_NORMAL, /* 01 Number */ + ACPI_NS_NORMAL, /* 02 String */ + ACPI_NS_NORMAL, /* 03 Buffer */ + ACPI_NS_NORMAL, /* 04 Package */ + ACPI_NS_NORMAL, /* 05 field_unit */ + ACPI_NS_NEWSCOPE, /* 06 Device */ + ACPI_NS_NORMAL, /* 07 Event */ + ACPI_NS_NEWSCOPE, /* 08 Method */ + ACPI_NS_NORMAL, /* 09 Mutex */ + ACPI_NS_NORMAL, /* 10 Region */ + ACPI_NS_NEWSCOPE, /* 11 Power */ + ACPI_NS_NEWSCOPE, /* 12 Processor */ + ACPI_NS_NEWSCOPE, /* 13 Thermal */ + ACPI_NS_NORMAL, /* 14 buffer_field */ + ACPI_NS_NORMAL, /* 15 ddb_handle */ + ACPI_NS_NORMAL, /* 16 Debug Object */ + ACPI_NS_NORMAL, /* 17 def_field */ + ACPI_NS_NORMAL, /* 18 bank_field */ + ACPI_NS_NORMAL, /* 19 index_field */ + ACPI_NS_NORMAL, /* 20 Reference */ + ACPI_NS_NORMAL, /* 21 Alias */ + ACPI_NS_NORMAL, /* 22 method_alias */ + ACPI_NS_NORMAL, /* 23 Notify */ + ACPI_NS_NORMAL, /* 24 Address Handler */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */ + ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */ + ACPI_NS_NEWSCOPE, /* 27 Scope */ + ACPI_NS_NORMAL, /* 28 Extra */ + ACPI_NS_NORMAL, /* 29 Data */ + ACPI_NS_NORMAL /* 30 Invalid */ +}; + +/******************************************************************************* + * + * FUNCTION: acpi_ut_hex_to_ascii_char + * + * PARAMETERS: Integer - Contains the hex digit + * Position - bit position of the digit within the + * integer (multiple of 4) + * + * RETURN: The converted Ascii character + * + * DESCRIPTION: Convert a hex digit to an Ascii character + * + ******************************************************************************/ + +/* Hex to ASCII conversion table */ + +static const char acpi_gbl_hex_to_ascii[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +char acpi_ut_hex_to_ascii_char(u64 integer, u32 position) +{ + + return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_region_name + * + * PARAMETERS: Space ID - ID for the region + * + * RETURN: Decoded region space_id name + * + * DESCRIPTION: Translate a Space ID into a name string (Debug only) + * + ******************************************************************************/ + +/* Region type decoding */ + +const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { + "SystemMemory", + "SystemIO", + "PCI_Config", + "EmbeddedControl", + "SMBus", + "SystemCMOS", + "PCIBARTarget", + "IPMI", + "DataTable" +}; + +char *acpi_ut_get_region_name(u8 space_id) +{ + + if (space_id >= ACPI_USER_REGION_BEGIN) { + return ("UserDefinedRegion"); + } else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) { + return ("InvalidSpaceId"); + } + + return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id])); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_event_name + * + * PARAMETERS: event_id - Fixed event ID + * + * RETURN: Decoded event ID name + * + * DESCRIPTION: Translate a Event ID into a name string (Debug only) + * + ******************************************************************************/ + +/* Event type decoding */ + +static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = { + "PM_Timer", + "GlobalLock", + "PowerButton", + "SleepButton", + "RealTimeClock", +}; + +char *acpi_ut_get_event_name(u32 event_id) +{ + + if (event_id > ACPI_EVENT_MAX) { + return ("InvalidEventID"); + } + + return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id])); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_type_name + * + * PARAMETERS: Type - An ACPI object type + * + * RETURN: Decoded ACPI object type name + * + * DESCRIPTION: Translate a Type ID into a name string (Debug only) + * + ******************************************************************************/ + +/* + * Elements of acpi_gbl_ns_type_names below must match + * one-to-one with values of acpi_object_type + * + * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; + * when stored in a table it really means that we have thus far seen no + * evidence to indicate what type is actually going to be stored for this entry. + */ +static const char acpi_gbl_bad_type[] = "UNDEFINED"; + +/* Printable names of the ACPI object types */ + +static const char *acpi_gbl_ns_type_names[] = { + /* 00 */ "Untyped", + /* 01 */ "Integer", + /* 02 */ "String", + /* 03 */ "Buffer", + /* 04 */ "Package", + /* 05 */ "FieldUnit", + /* 06 */ "Device", + /* 07 */ "Event", + /* 08 */ "Method", + /* 09 */ "Mutex", + /* 10 */ "Region", + /* 11 */ "Power", + /* 12 */ "Processor", + /* 13 */ "Thermal", + /* 14 */ "BufferField", + /* 15 */ "DdbHandle", + /* 16 */ "DebugObject", + /* 17 */ "RegionField", + /* 18 */ "BankField", + /* 19 */ "IndexField", + /* 20 */ "Reference", + /* 21 */ "Alias", + /* 22 */ "MethodAlias", + /* 23 */ "Notify", + /* 24 */ "AddrHandler", + /* 25 */ "ResourceDesc", + /* 26 */ "ResourceFld", + /* 27 */ "Scope", + /* 28 */ "Extra", + /* 29 */ "Data", + /* 30 */ "Invalid" +}; + +char *acpi_ut_get_type_name(acpi_object_type type) +{ + + if (type > ACPI_TYPE_INVALID) { + return (ACPI_CAST_PTR(char, acpi_gbl_bad_type)); + } + + return (ACPI_CAST_PTR(char, acpi_gbl_ns_type_names[type])); +} + +char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) +{ + + if (!obj_desc) { + return ("[NULL Object Descriptor]"); + } + + return (acpi_ut_get_type_name(obj_desc->common.type)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_node_name + * + * PARAMETERS: Object - A namespace node + * + * RETURN: ASCII name of the node + * + * DESCRIPTION: Validate the node and return the node's ACPI name. + * + ******************************************************************************/ + +char *acpi_ut_get_node_name(void *object) +{ + struct acpi_namespace_node *node = (struct acpi_namespace_node *)object; + + /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ + + if (!object) { + return ("NULL"); + } + + /* Check for Root node */ + + if ((object == ACPI_ROOT_OBJECT) || (object == acpi_gbl_root_node)) { + return ("\"\\\" "); + } + + /* Descriptor must be a namespace node */ + + if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { + return ("####"); + } + + /* + * Ensure name is valid. The name was validated/repaired when the node + * was created, but make sure it has not been corrupted. + */ + acpi_ut_repair_name(node->name.ascii); + + /* Return the name */ + + return (node->name.ascii); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_descriptor_name + * + * PARAMETERS: Object - An ACPI object + * + * RETURN: Decoded name of the descriptor type + * + * DESCRIPTION: Validate object and return the descriptor type + * + ******************************************************************************/ + +/* Printable names of object descriptor types */ + +static const char *acpi_gbl_desc_type_names[] = { + /* 00 */ "Not a Descriptor", + /* 01 */ "Cached", + /* 02 */ "State-Generic", + /* 03 */ "State-Update", + /* 04 */ "State-Package", + /* 05 */ "State-Control", + /* 06 */ "State-RootParseScope", + /* 07 */ "State-ParseScope", + /* 08 */ "State-WalkScope", + /* 09 */ "State-Result", + /* 10 */ "State-Notify", + /* 11 */ "State-Thread", + /* 12 */ "Walk", + /* 13 */ "Parser", + /* 14 */ "Operand", + /* 15 */ "Node" +}; + +char *acpi_ut_get_descriptor_name(void *object) +{ + + if (!object) { + return ("NULL OBJECT"); + } + + if (ACPI_GET_DESCRIPTOR_TYPE(object) > ACPI_DESC_TYPE_MAX) { + return ("Not a Descriptor"); + } + + return (ACPI_CAST_PTR(char, + acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE + (object)])); + +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_reference_name + * + * PARAMETERS: Object - An ACPI reference object + * + * RETURN: Decoded name of the type of reference + * + * DESCRIPTION: Decode a reference object sub-type to a string. + * + ******************************************************************************/ + +/* Printable names of reference object sub-types */ + +static const char *acpi_gbl_ref_class_names[] = { + /* 00 */ "Local", + /* 01 */ "Argument", + /* 02 */ "RefOf", + /* 03 */ "Index", + /* 04 */ "DdbHandle", + /* 05 */ "Named Object", + /* 06 */ "Debug" +}; + +const char *acpi_ut_get_reference_name(union acpi_operand_object *object) +{ + + if (!object) { + return ("NULL Object"); + } + + if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) { + return ("Not an Operand object"); + } + + if (object->common.type != ACPI_TYPE_LOCAL_REFERENCE) { + return ("Not a Reference object"); + } + + if (object->reference.class > ACPI_REFCLASS_MAX) { + return ("Unknown Reference class"); + } + + return (acpi_gbl_ref_class_names[object->reference.class]); +} + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* + * Strings and procedures used for debug only + */ + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_mutex_name + * + * PARAMETERS: mutex_id - The predefined ID for this mutex. + * + * RETURN: Decoded name of the internal mutex + * + * DESCRIPTION: Translate a mutex ID into a name string (Debug only) + * + ******************************************************************************/ + +/* Names for internal mutex objects, used for debug output */ + +static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { + "ACPI_MTX_Interpreter", + "ACPI_MTX_Namespace", + "ACPI_MTX_Tables", + "ACPI_MTX_Events", + "ACPI_MTX_Caches", + "ACPI_MTX_Memory", + "ACPI_MTX_CommandComplete", + "ACPI_MTX_CommandReady" +}; + +char *acpi_ut_get_mutex_name(u32 mutex_id) +{ + + if (mutex_id > ACPI_MAX_MUTEX) { + return ("Invalid Mutex ID"); + } + + return (acpi_gbl_mutex_names[mutex_id]); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_notify_name + * + * PARAMETERS: notify_value - Value from the Notify() request + * + * RETURN: Decoded name for the notify value + * + * DESCRIPTION: Translate a Notify Value to a notify namestring. + * + ******************************************************************************/ + +/* Names for Notify() values, used for debug output */ + +static const char *acpi_gbl_notify_value_names[] = { + "Bus Check", + "Device Check", + "Device Wake", + "Eject Request", + "Device Check Light", + "Frequency Mismatch", + "Bus Mode Mismatch", + "Power Fault", + "Capabilities Check", + "Device PLD Check", + "Reserved", + "System Locality Update" +}; + +const char *acpi_ut_get_notify_name(u32 notify_value) +{ + + if (notify_value <= ACPI_NOTIFY_MAX) { + return (acpi_gbl_notify_value_names[notify_value]); + } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) { + return ("Reserved"); + } else { /* Greater or equal to 0x80 */ + + return ("**Device Specific**"); + } +} +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ut_valid_object_type + * + * PARAMETERS: Type - Object type to be validated + * + * RETURN: TRUE if valid object type, FALSE otherwise + * + * DESCRIPTION: Validate an object type + * + ******************************************************************************/ + +u8 acpi_ut_valid_object_type(acpi_object_type type) +{ + + if (type > ACPI_TYPE_LOCAL_MAX) { + + /* Note: Assumes all TYPEs are contiguous (external/local) */ + + return (FALSE); + } + + return (TRUE); +} diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index 97dd9bbf055a..fc9097821516 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -45,7 +45,6 @@ #include #include "accommon.h" -#include "acnamesp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utglobal") @@ -105,43 +104,6 @@ const char *acpi_gbl_highest_dstate_names[ACPI_NUM_sx_d_METHODS] = { "_S4D" }; -/******************************************************************************* - * - * FUNCTION: acpi_format_exception - * - * PARAMETERS: Status - The acpi_status code to be formatted - * - * RETURN: A string containing the exception text. A valid pointer is - * always returned. - * - * DESCRIPTION: This function translates an ACPI exception into an ASCII string - * It is here instead of utxface.c so it is always present. - * - ******************************************************************************/ - -const char *acpi_format_exception(acpi_status status) -{ - const char *exception = NULL; - - ACPI_FUNCTION_ENTRY(); - - exception = acpi_ut_validate_exception(status); - if (!exception) { - - /* Exception code was not recognized */ - - ACPI_ERROR((AE_INFO, - "Unknown exception code: 0x%8.8X", status)); - - exception = "UNKNOWN_STATUS_CODE"; - dump_stack(); - } - - return (ACPI_CAST_PTR(const char, exception)); -} - -ACPI_EXPORT_SYMBOL(acpi_format_exception) - /******************************************************************************* * * Namespace globals @@ -177,71 +139,6 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = { {NULL, ACPI_TYPE_ANY, NULL} }; -/* - * Properties of the ACPI Object Types, both internal and external. - * The table is indexed by values of acpi_object_type - */ -const u8 acpi_gbl_ns_properties[] = { - ACPI_NS_NORMAL, /* 00 Any */ - ACPI_NS_NORMAL, /* 01 Number */ - ACPI_NS_NORMAL, /* 02 String */ - ACPI_NS_NORMAL, /* 03 Buffer */ - ACPI_NS_NORMAL, /* 04 Package */ - ACPI_NS_NORMAL, /* 05 field_unit */ - ACPI_NS_NEWSCOPE, /* 06 Device */ - ACPI_NS_NORMAL, /* 07 Event */ - ACPI_NS_NEWSCOPE, /* 08 Method */ - ACPI_NS_NORMAL, /* 09 Mutex */ - ACPI_NS_NORMAL, /* 10 Region */ - ACPI_NS_NEWSCOPE, /* 11 Power */ - ACPI_NS_NEWSCOPE, /* 12 Processor */ - ACPI_NS_NEWSCOPE, /* 13 Thermal */ - ACPI_NS_NORMAL, /* 14 buffer_field */ - ACPI_NS_NORMAL, /* 15 ddb_handle */ - ACPI_NS_NORMAL, /* 16 Debug Object */ - ACPI_NS_NORMAL, /* 17 def_field */ - ACPI_NS_NORMAL, /* 18 bank_field */ - ACPI_NS_NORMAL, /* 19 index_field */ - ACPI_NS_NORMAL, /* 20 Reference */ - ACPI_NS_NORMAL, /* 21 Alias */ - ACPI_NS_NORMAL, /* 22 method_alias */ - ACPI_NS_NORMAL, /* 23 Notify */ - ACPI_NS_NORMAL, /* 24 Address Handler */ - ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */ - ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */ - ACPI_NS_NEWSCOPE, /* 27 Scope */ - ACPI_NS_NORMAL, /* 28 Extra */ - ACPI_NS_NORMAL, /* 29 Data */ - ACPI_NS_NORMAL /* 30 Invalid */ -}; - -/* Hex to ASCII conversion table */ - -static const char acpi_gbl_hex_to_ascii[] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' -}; - -/******************************************************************************* - * - * FUNCTION: acpi_ut_hex_to_ascii_char - * - * PARAMETERS: Integer - Contains the hex digit - * Position - bit position of the digit within the - * integer (multiple of 4) - * - * RETURN: The converted Ascii character - * - * DESCRIPTION: Convert a hex digit to an Ascii character - * - ******************************************************************************/ - -char acpi_ut_hex_to_ascii_char(u64 integer, u32 position) -{ - - return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]); -} - /****************************************************************************** * * Event and Hardware globals @@ -339,386 +236,6 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] = ACPI_BITMASK_RT_CLOCK_ENABLE}, }; -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_region_name - * - * PARAMETERS: None. - * - * RETURN: Status - * - * DESCRIPTION: Translate a Space ID into a name string (Debug only) - * - ******************************************************************************/ - -/* Region type decoding */ - -const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { - "SystemMemory", - "SystemIO", - "PCI_Config", - "EmbeddedControl", - "SMBus", - "SystemCMOS", - "PCIBARTarget", - "IPMI", - "DataTable" -}; - -char *acpi_ut_get_region_name(u8 space_id) -{ - - if (space_id >= ACPI_USER_REGION_BEGIN) { - return ("UserDefinedRegion"); - } else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) { - return ("InvalidSpaceId"); - } - - return (ACPI_CAST_PTR(char, acpi_gbl_region_types[space_id])); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_event_name - * - * PARAMETERS: None. - * - * RETURN: Status - * - * DESCRIPTION: Translate a Event ID into a name string (Debug only) - * - ******************************************************************************/ - -/* Event type decoding */ - -static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] = { - "PM_Timer", - "GlobalLock", - "PowerButton", - "SleepButton", - "RealTimeClock", -}; - -char *acpi_ut_get_event_name(u32 event_id) -{ - - if (event_id > ACPI_EVENT_MAX) { - return ("InvalidEventID"); - } - - return (ACPI_CAST_PTR(char, acpi_gbl_event_types[event_id])); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_type_name - * - * PARAMETERS: None. - * - * RETURN: Status - * - * DESCRIPTION: Translate a Type ID into a name string (Debug only) - * - ******************************************************************************/ - -/* - * Elements of acpi_gbl_ns_type_names below must match - * one-to-one with values of acpi_object_type - * - * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; - * when stored in a table it really means that we have thus far seen no - * evidence to indicate what type is actually going to be stored for this entry. - */ -static const char acpi_gbl_bad_type[] = "UNDEFINED"; - -/* Printable names of the ACPI object types */ - -static const char *acpi_gbl_ns_type_names[] = { - /* 00 */ "Untyped", - /* 01 */ "Integer", - /* 02 */ "String", - /* 03 */ "Buffer", - /* 04 */ "Package", - /* 05 */ "FieldUnit", - /* 06 */ "Device", - /* 07 */ "Event", - /* 08 */ "Method", - /* 09 */ "Mutex", - /* 10 */ "Region", - /* 11 */ "Power", - /* 12 */ "Processor", - /* 13 */ "Thermal", - /* 14 */ "BufferField", - /* 15 */ "DdbHandle", - /* 16 */ "DebugObject", - /* 17 */ "RegionField", - /* 18 */ "BankField", - /* 19 */ "IndexField", - /* 20 */ "Reference", - /* 21 */ "Alias", - /* 22 */ "MethodAlias", - /* 23 */ "Notify", - /* 24 */ "AddrHandler", - /* 25 */ "ResourceDesc", - /* 26 */ "ResourceFld", - /* 27 */ "Scope", - /* 28 */ "Extra", - /* 29 */ "Data", - /* 30 */ "Invalid" -}; - -char *acpi_ut_get_type_name(acpi_object_type type) -{ - - if (type > ACPI_TYPE_INVALID) { - return (ACPI_CAST_PTR(char, acpi_gbl_bad_type)); - } - - return (ACPI_CAST_PTR(char, acpi_gbl_ns_type_names[type])); -} - -char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) -{ - - if (!obj_desc) { - return ("[NULL Object Descriptor]"); - } - - return (acpi_ut_get_type_name(obj_desc->common.type)); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_node_name - * - * PARAMETERS: Object - A namespace node - * - * RETURN: Pointer to a string - * - * DESCRIPTION: Validate the node and return the node's ACPI name. - * - ******************************************************************************/ - -char *acpi_ut_get_node_name(void *object) -{ - struct acpi_namespace_node *node = (struct acpi_namespace_node *)object; - - /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */ - - if (!object) { - return ("NULL"); - } - - /* Check for Root node */ - - if ((object == ACPI_ROOT_OBJECT) || (object == acpi_gbl_root_node)) { - return ("\"\\\" "); - } - - /* Descriptor must be a namespace node */ - - if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) { - return ("####"); - } - - /* Name must be a valid ACPI name */ - - if (!acpi_ut_valid_acpi_name(node->name.integer)) { - node->name.integer = acpi_ut_repair_name(node->name.ascii); - } - - /* Return the name */ - - return (node->name.ascii); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_descriptor_name - * - * PARAMETERS: Object - An ACPI object - * - * RETURN: Pointer to a string - * - * DESCRIPTION: Validate object and return the descriptor type - * - ******************************************************************************/ - -/* Printable names of object descriptor types */ - -static const char *acpi_gbl_desc_type_names[] = { - /* 00 */ "Invalid", - /* 01 */ "Cached", - /* 02 */ "State-Generic", - /* 03 */ "State-Update", - /* 04 */ "State-Package", - /* 05 */ "State-Control", - /* 06 */ "State-RootParseScope", - /* 07 */ "State-ParseScope", - /* 08 */ "State-WalkScope", - /* 09 */ "State-Result", - /* 10 */ "State-Notify", - /* 11 */ "State-Thread", - /* 12 */ "Walk", - /* 13 */ "Parser", - /* 14 */ "Operand", - /* 15 */ "Node" -}; - -char *acpi_ut_get_descriptor_name(void *object) -{ - - if (!object) { - return ("NULL OBJECT"); - } - - if (ACPI_GET_DESCRIPTOR_TYPE(object) > ACPI_DESC_TYPE_MAX) { - return (ACPI_CAST_PTR(char, acpi_gbl_bad_type)); - } - - return (ACPI_CAST_PTR(char, - acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE - (object)])); - -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_reference_name - * - * PARAMETERS: Object - An ACPI reference object - * - * RETURN: Pointer to a string - * - * DESCRIPTION: Decode a reference object sub-type to a string. - * - ******************************************************************************/ - -/* Printable names of reference object sub-types */ - -static const char *acpi_gbl_ref_class_names[] = { - /* 00 */ "Local", - /* 01 */ "Argument", - /* 02 */ "RefOf", - /* 03 */ "Index", - /* 04 */ "DdbHandle", - /* 05 */ "Named Object", - /* 06 */ "Debug" -}; - -const char *acpi_ut_get_reference_name(union acpi_operand_object *object) -{ - if (!object) - return "NULL Object"; - - if (ACPI_GET_DESCRIPTOR_TYPE(object) != ACPI_DESC_TYPE_OPERAND) - return "Not an Operand object"; - - if (object->common.type != ACPI_TYPE_LOCAL_REFERENCE) - return "Not a Reference object"; - - if (object->reference.class > ACPI_REFCLASS_MAX) - return "Unknown Reference class"; - - return acpi_gbl_ref_class_names[object->reference.class]; -} - -#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -/* - * Strings and procedures used for debug only - */ - -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_mutex_name - * - * PARAMETERS: mutex_id - The predefined ID for this mutex. - * - * RETURN: String containing the name of the mutex. Always returns a valid - * pointer. - * - * DESCRIPTION: Translate a mutex ID into a name string (Debug only) - * - ******************************************************************************/ - -char *acpi_ut_get_mutex_name(u32 mutex_id) -{ - - if (mutex_id > ACPI_MAX_MUTEX) { - return ("Invalid Mutex ID"); - } - - return (acpi_gbl_mutex_names[mutex_id]); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_get_notify_name - * - * PARAMETERS: notify_value - Value from the Notify() request - * - * RETURN: String corresponding to the Notify Value. - * - * DESCRIPTION: Translate a Notify Value to a notify namestring. - * - ******************************************************************************/ - -/* Names for Notify() values, used for debug output */ - -static const char *acpi_gbl_notify_value_names[] = { - "Bus Check", - "Device Check", - "Device Wake", - "Eject Request", - "Device Check Light", - "Frequency Mismatch", - "Bus Mode Mismatch", - "Power Fault", - "Capabilities Check", - "Device PLD Check", - "Reserved", - "System Locality Update" -}; - -const char *acpi_ut_get_notify_name(u32 notify_value) -{ - - if (notify_value <= ACPI_NOTIFY_MAX) { - return (acpi_gbl_notify_value_names[notify_value]); - } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) { - return ("Reserved"); - } else { /* Greater or equal to 0x80 */ - - return ("**Device Specific**"); - } -} -#endif - -/******************************************************************************* - * - * FUNCTION: acpi_ut_valid_object_type - * - * PARAMETERS: Type - Object type to be validated - * - * RETURN: TRUE if valid object type, FALSE otherwise - * - * DESCRIPTION: Validate an object type - * - ******************************************************************************/ - -u8 acpi_ut_valid_object_type(acpi_object_type type) -{ - - if (type > ACPI_TYPE_LOCAL_MAX) { - - /* Note: Assumes all TYPEs are contiguous (external/local) */ - - return (FALSE); - } - - return (TRUE); -} - /******************************************************************************* * * FUNCTION: acpi_ut_init_globals -- cgit v1.2.2 From 9ad19ac456a5f097f7cbbfef820b95297d6a934f Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Feb 2011 16:09:40 +0800 Subject: ACPICA: Split large dsopcode and dsload.c files. Split dsopcode.c into dsargs.c and dscontrol.c. Split dsload.c into dsload2.c. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/Makefile | 2 +- drivers/acpi/acpica/acdispat.h | 38 ++- drivers/acpi/acpica/dsargs.c | 391 ++++++++++++++++++++++ drivers/acpi/acpica/dscontrol.c | 410 +++++++++++++++++++++++ drivers/acpi/acpica/dsopcode.c | 725 +--------------------------------------- drivers/acpi/acpica/dswload.c | 670 +------------------------------------ drivers/acpi/acpica/dswload2.c | 720 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 1549 insertions(+), 1407 deletions(-) create mode 100644 drivers/acpi/acpica/dsargs.c create mode 100644 drivers/acpi/acpica/dscontrol.c create mode 100644 drivers/acpi/acpica/dswload2.c (limited to 'drivers') diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index b1706aacbe98..a1224712fd0c 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -10,7 +10,7 @@ obj-y += acpi.o acpi-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ - dsinit.o + dsinit.o dsargs.o dscontrol.o dswload2.o acpi-y += evevent.o evregion.o evsci.o evxfevnt.o \ evmisc.o evrgnini.o evxface.o evxfregn.o \ diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 666271b65418..2d1b7ffa377a 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -48,7 +48,7 @@ #define NAMEOF_ARG_NTE "__A0" /* - * dsopcode - support for late evaluation + * dsargs - execution of dynamic arguments for static objects */ acpi_status acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc); @@ -62,6 +62,20 @@ acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc); acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc); +/* + * dscontrol - support for execution control opcodes + */ +acpi_status +acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status +acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +/* + * dsopcode - support for late operand evaluation + */ acpi_status acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, union acpi_parse_object *op); @@ -85,17 +99,6 @@ acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, acpi_status acpi_ds_initialize_region(acpi_handle obj_handle); -/* - * dsctrl - Parser/Interpreter interface, control stack routines - */ -acpi_status -acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, - union acpi_parse_object *op); - -acpi_status -acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state, - union acpi_parse_object *op); - /* * dsexec - Parser/Interpreter interface, method execution callbacks */ @@ -136,23 +139,26 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, struct acpi_walk_state *walk_state); /* - * dsload - Parser/Interpreter interface, namespace load callbacks + * dsload - Parser/Interpreter interface, pass 1 namespace load callbacks */ +acpi_status +acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number); + acpi_status acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, union acpi_parse_object **out_op); acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state); +/* + * dsload - Parser/Interpreter interface, pass 2 namespace load callbacks + */ acpi_status acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, union acpi_parse_object **out_op); acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state); -acpi_status -acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number); - /* * dsmthdat - method data (locals/args) */ diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c new file mode 100644 index 000000000000..8c7b99728aa2 --- /dev/null +++ b/drivers/acpi/acpica/dsargs.c @@ -0,0 +1,391 @@ +/****************************************************************************** + * + * Module Name: dsargs - Support for execution of dynamic arguments for static + * objects (regions, fields, buffer fields, etc.) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2011, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acnamesp.h" + +#define _COMPONENT ACPI_DISPATCHER +ACPI_MODULE_NAME("dsargs") + +/* Local prototypes */ +static acpi_status +acpi_ds_execute_arguments(struct acpi_namespace_node *node, + struct acpi_namespace_node *scope_node, + u32 aml_length, u8 *aml_start); + +/******************************************************************************* + * + * FUNCTION: acpi_ds_execute_arguments + * + * PARAMETERS: Node - Object NS node + * scope_node - Parent NS node + * aml_length - Length of executable AML + * aml_start - Pointer to the AML + * + * RETURN: Status. + * + * DESCRIPTION: Late (deferred) execution of region or field arguments + * + ******************************************************************************/ + +static acpi_status +acpi_ds_execute_arguments(struct acpi_namespace_node *node, + struct acpi_namespace_node *scope_node, + u32 aml_length, u8 *aml_start) +{ + acpi_status status; + union acpi_parse_object *op; + struct acpi_walk_state *walk_state; + + ACPI_FUNCTION_TRACE(ds_execute_arguments); + + /* Allocate a new parser op to be the root of the parsed tree */ + + op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); + if (!op) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Save the Node for use in acpi_ps_parse_aml */ + + op->common.node = scope_node; + + /* Create and initialize a new parser state */ + + walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL); + if (!walk_state) { + status = AE_NO_MEMORY; + goto cleanup; + } + + status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, + aml_length, NULL, ACPI_IMODE_LOAD_PASS1); + if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } + + /* Mark this parse as a deferred opcode */ + + walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP; + walk_state->deferred_node = node; + + /* Pass1: Parse the entire declaration */ + + status = acpi_ps_parse_aml(walk_state); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + + /* Get and init the Op created above */ + + op->common.node = node; + acpi_ps_delete_parse_tree(op); + + /* Evaluate the deferred arguments */ + + op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); + if (!op) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + op->common.node = scope_node; + + /* Create and initialize a new parser state */ + + walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL); + if (!walk_state) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Execute the opcode and arguments */ + + status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, + aml_length, NULL, ACPI_IMODE_EXECUTE); + if (ACPI_FAILURE(status)) { + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } + + /* Mark this execution as a deferred opcode */ + + walk_state->deferred_node = node; + status = acpi_ps_parse_aml(walk_state); + + cleanup: + acpi_ps_delete_parse_tree(op); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_get_buffer_field_arguments + * + * PARAMETERS: obj_desc - A valid buffer_field object + * + * RETURN: Status. + * + * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late + * evaluation of these field attributes. + * + ******************************************************************************/ + +acpi_status +acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) +{ + union acpi_operand_object *extra_desc; + struct acpi_namespace_node *node; + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc); + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS(AE_OK); + } + + /* Get the AML pointer (method object) and buffer_field node */ + + extra_desc = acpi_ns_get_secondary_object(obj_desc); + node = obj_desc->buffer_field.node; + + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname(ACPI_TYPE_BUFFER_FIELD, + node, NULL)); + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n", + acpi_ut_get_node_name(node))); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments(node, node->parent, + extra_desc->extra.aml_length, + extra_desc->extra.aml_start); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_get_bank_field_arguments + * + * PARAMETERS: obj_desc - A valid bank_field object + * + * RETURN: Status. + * + * DESCRIPTION: Get bank_field bank_value. This implements the late + * evaluation of these field attributes. + * + ******************************************************************************/ + +acpi_status +acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc) +{ + union acpi_operand_object *extra_desc; + struct acpi_namespace_node *node; + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc); + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS(AE_OK); + } + + /* Get the AML pointer (method object) and bank_field node */ + + extra_desc = acpi_ns_get_secondary_object(obj_desc); + node = obj_desc->bank_field.node; + + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname + (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL)); + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n", + acpi_ut_get_node_name(node))); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments(node, node->parent, + extra_desc->extra.aml_length, + extra_desc->extra.aml_start); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_get_buffer_arguments + * + * PARAMETERS: obj_desc - A valid Buffer object + * + * RETURN: Status. + * + * DESCRIPTION: Get Buffer length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ******************************************************************************/ + +acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc) +{ + struct acpi_namespace_node *node; + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc); + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS(AE_OK); + } + + /* Get the Buffer node */ + + node = obj_desc->buffer.node; + if (!node) { + ACPI_ERROR((AE_INFO, + "No pointer back to namespace node in buffer object %p", + obj_desc)); + return_ACPI_STATUS(AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Buffer Arg Init\n")); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments(node, node, + obj_desc->buffer.aml_length, + obj_desc->buffer.aml_start); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_get_package_arguments + * + * PARAMETERS: obj_desc - A valid Package object + * + * RETURN: Status. + * + * DESCRIPTION: Get Package length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ******************************************************************************/ + +acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc) +{ + struct acpi_namespace_node *node; + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc); + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS(AE_OK); + } + + /* Get the Package node */ + + node = obj_desc->package.node; + if (!node) { + ACPI_ERROR((AE_INFO, + "No pointer back to namespace node in package %p", + obj_desc)); + return_ACPI_STATUS(AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n")); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments(node, node, + obj_desc->package.aml_length, + obj_desc->package.aml_start); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_get_region_arguments + * + * PARAMETERS: obj_desc - A valid region object + * + * RETURN: Status. + * + * DESCRIPTION: Get region address and length. This implements the late + * evaluation of these region attributes. + * + ******************************************************************************/ + +acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) +{ + struct acpi_namespace_node *node; + acpi_status status; + union acpi_operand_object *extra_desc; + + ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc); + + if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS(AE_OK); + } + + extra_desc = acpi_ns_get_secondary_object(obj_desc); + if (!extra_desc) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + + /* Get the Region node */ + + node = obj_desc->region.node; + + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname + (ACPI_TYPE_REGION, node, NULL)); + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n", + acpi_ut_get_node_name(node), + extra_desc->extra.aml_start)); + + /* Execute the argument AML */ + + status = acpi_ds_execute_arguments(node, node->parent, + extra_desc->extra.aml_length, + extra_desc->extra.aml_start); + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c new file mode 100644 index 000000000000..26c49fff58da --- /dev/null +++ b/drivers/acpi/acpica/dscontrol.c @@ -0,0 +1,410 @@ +/****************************************************************************** + * + * Module Name: dscontrol - Support for execution control opcodes - + * if/else/while/return + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2011, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" + +#define _COMPONENT ACPI_DISPATCHER +ACPI_MODULE_NAME("dscontrol") + +/******************************************************************************* + * + * FUNCTION: acpi_ds_exec_begin_control_op + * + * PARAMETERS: walk_list - The list that owns the walk stack + * Op - The control Op + * + * RETURN: Status + * + * DESCRIPTION: Handles all control ops encountered during control method + * execution. + * + ******************************************************************************/ +acpi_status +acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + acpi_status status = AE_OK; + union acpi_generic_state *control_state; + + ACPI_FUNCTION_NAME(ds_exec_begin_control_op); + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", + op, op->common.aml_opcode, walk_state)); + + switch (op->common.aml_opcode) { + case AML_WHILE_OP: + + /* + * If this is an additional iteration of a while loop, continue. + * There is no need to allocate a new control state. + */ + if (walk_state->control_state) { + if (walk_state->control_state->control. + aml_predicate_start == + (walk_state->parser_state.aml - 1)) { + + /* Reset the state to start-of-loop */ + + walk_state->control_state->common.state = + ACPI_CONTROL_CONDITIONAL_EXECUTING; + break; + } + } + + /*lint -fallthrough */ + + case AML_IF_OP: + + /* + * IF/WHILE: Create a new control state to manage these + * constructs. We need to manage these as a stack, in order + * to handle nesting. + */ + control_state = acpi_ut_create_control_state(); + if (!control_state) { + status = AE_NO_MEMORY; + break; + } + /* + * Save a pointer to the predicate for multiple executions + * of a loop + */ + control_state->control.aml_predicate_start = + walk_state->parser_state.aml - 1; + control_state->control.package_end = + walk_state->parser_state.pkg_end; + control_state->control.opcode = op->common.aml_opcode; + + /* Push the control state on this walk's control stack */ + + acpi_ut_push_generic_state(&walk_state->control_state, + control_state); + break; + + case AML_ELSE_OP: + + /* Predicate is in the state object */ + /* If predicate is true, the IF was executed, ignore ELSE part */ + + if (walk_state->last_predicate) { + status = AE_CTRL_TRUE; + } + + break; + + case AML_RETURN_OP: + + break; + + default: + break; + } + + return (status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_exec_end_control_op + * + * PARAMETERS: walk_list - The list that owns the walk stack + * Op - The control Op + * + * RETURN: Status + * + * DESCRIPTION: Handles all control ops encountered during control method + * execution. + * + ******************************************************************************/ + +acpi_status +acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, + union acpi_parse_object * op) +{ + acpi_status status = AE_OK; + union acpi_generic_state *control_state; + + ACPI_FUNCTION_NAME(ds_exec_end_control_op); + + switch (op->common.aml_opcode) { + case AML_IF_OP: + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op)); + + /* + * Save the result of the predicate in case there is an + * ELSE to come + */ + walk_state->last_predicate = + (u8)walk_state->control_state->common.value; + + /* + * Pop the control state that was created at the start + * of the IF and free it + */ + control_state = + acpi_ut_pop_generic_state(&walk_state->control_state); + acpi_ut_delete_generic_state(control_state); + break; + + case AML_ELSE_OP: + + break; + + case AML_WHILE_OP: + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); + + control_state = walk_state->control_state; + if (control_state->common.value) { + + /* Predicate was true, the body of the loop was just executed */ + + /* + * This loop counter mechanism allows the interpreter to escape + * possibly infinite loops. This can occur in poorly written AML + * when the hardware does not respond within a while loop and the + * loop does not implement a timeout. + */ + control_state->control.loop_count++; + if (control_state->control.loop_count > + ACPI_MAX_LOOP_ITERATIONS) { + status = AE_AML_INFINITE_LOOP; + break; + } + + /* + * Go back and evaluate the predicate and maybe execute the loop + * another time + */ + status = AE_CTRL_PENDING; + walk_state->aml_last_while = + control_state->control.aml_predicate_start; + break; + } + + /* Predicate was false, terminate this while loop */ + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "[WHILE_OP] termination! Op=%p\n", op)); + + /* Pop this control state and free it */ + + control_state = + acpi_ut_pop_generic_state(&walk_state->control_state); + acpi_ut_delete_generic_state(control_state); + break; + + case AML_RETURN_OP: + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "[RETURN_OP] Op=%p Arg=%p\n", op, + op->common.value.arg)); + + /* + * One optional operand -- the return value + * It can be either an immediate operand or a result that + * has been bubbled up the tree + */ + if (op->common.value.arg) { + + /* Since we have a real Return(), delete any implicit return */ + + acpi_ds_clear_implicit_return(walk_state); + + /* Return statement has an immediate operand */ + + status = + acpi_ds_create_operands(walk_state, + op->common.value.arg); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + */ + status = + acpi_ex_resolve_to_value(&walk_state->operands[0], + walk_state); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* + * Get the return value and save as the last result + * value. This is the only place where walk_state->return_desc + * is set to anything other than zero! + */ + walk_state->return_desc = walk_state->operands[0]; + } else if (walk_state->result_count) { + + /* Since we have a real Return(), delete any implicit return */ + + acpi_ds_clear_implicit_return(walk_state); + + /* + * The return value has come from a previous calculation. + * + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + * + * Allow references created by the Index operator to return + * unchanged. + */ + if ((ACPI_GET_DESCRIPTOR_TYPE + (walk_state->results->results.obj_desc[0]) == + ACPI_DESC_TYPE_OPERAND) + && ((walk_state->results->results.obj_desc[0])-> + common.type == ACPI_TYPE_LOCAL_REFERENCE) + && ((walk_state->results->results.obj_desc[0])-> + reference.class != ACPI_REFCLASS_INDEX)) { + status = + acpi_ex_resolve_to_value(&walk_state-> + results->results. + obj_desc[0], + walk_state); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + walk_state->return_desc = + walk_state->results->results.obj_desc[0]; + } else { + /* No return operand */ + + if (walk_state->num_operands) { + acpi_ut_remove_reference(walk_state-> + operands[0]); + } + + walk_state->operands[0] = NULL; + walk_state->num_operands = 0; + walk_state->return_desc = NULL; + } + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "Completed RETURN_OP State=%p, RetVal=%p\n", + walk_state, walk_state->return_desc)); + + /* End the control method execution right now */ + + status = AE_CTRL_TERMINATE; + break; + + case AML_NOOP_OP: + + /* Just do nothing! */ + break; + + case AML_BREAK_POINT_OP: + + /* + * Set the single-step flag. This will cause the debugger (if present) + * to break to the console within the AML debugger at the start of the + * next AML instruction. + */ + ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); + ACPI_DEBUGGER_EXEC(acpi_os_printf + ("**break** Executed AML BreakPoint opcode\n")); + + /* Call to the OSL in case OS wants a piece of the action */ + + status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, + "Executed AML Breakpoint opcode"); + break; + + case AML_BREAK_OP: + case AML_CONTINUE_OP: /* ACPI 2.0 */ + + /* Pop and delete control states until we find a while */ + + while (walk_state->control_state && + (walk_state->control_state->control.opcode != + AML_WHILE_OP)) { + control_state = + acpi_ut_pop_generic_state(&walk_state-> + control_state); + acpi_ut_delete_generic_state(control_state); + } + + /* No while found? */ + + if (!walk_state->control_state) { + return (AE_AML_NO_WHILE); + } + + /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */ + + walk_state->aml_last_while = + walk_state->control_state->control.package_end; + + /* Return status depending on opcode */ + + if (op->common.aml_opcode == AML_BREAK_OP) { + status = AE_CTRL_BREAK; + } else { + status = AE_CTRL_CONTINUE; + } + break; + + default: + + ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p", + op->common.aml_opcode, op)); + + status = AE_AML_BAD_OPCODE; + break; + } + + return (status); +} diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index bbecf293aeeb..c627a288e027 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -1,7 +1,6 @@ /****************************************************************************** * - * Module Name: dsopcode - Dispatcher Op Region support and handling of - * "control" opcodes + * Module Name: dsopcode - Dispatcher suport for regions and fields * *****************************************************************************/ @@ -56,11 +55,6 @@ ACPI_MODULE_NAME("dsopcode") /* Local prototypes */ -static acpi_status -acpi_ds_execute_arguments(struct acpi_namespace_node *node, - struct acpi_namespace_node *scope_node, - u32 aml_length, u8 * aml_start); - static acpi_status acpi_ds_init_buffer_field(u16 aml_opcode, union acpi_operand_object *obj_desc, @@ -69,361 +63,6 @@ acpi_ds_init_buffer_field(u16 aml_opcode, union acpi_operand_object *length_desc, union acpi_operand_object *result_desc); -/******************************************************************************* - * - * FUNCTION: acpi_ds_execute_arguments - * - * PARAMETERS: Node - Object NS node - * scope_node - Parent NS node - * aml_length - Length of executable AML - * aml_start - Pointer to the AML - * - * RETURN: Status. - * - * DESCRIPTION: Late (deferred) execution of region or field arguments - * - ******************************************************************************/ - -static acpi_status -acpi_ds_execute_arguments(struct acpi_namespace_node *node, - struct acpi_namespace_node *scope_node, - u32 aml_length, u8 * aml_start) -{ - acpi_status status; - union acpi_parse_object *op; - struct acpi_walk_state *walk_state; - - ACPI_FUNCTION_TRACE(ds_execute_arguments); - - /* - * Allocate a new parser op to be the root of the parsed tree - */ - op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); - if (!op) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Save the Node for use in acpi_ps_parse_aml */ - - op->common.node = scope_node; - - /* Create and initialize a new parser state */ - - walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL); - if (!walk_state) { - status = AE_NO_MEMORY; - goto cleanup; - } - - status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, - aml_length, NULL, ACPI_IMODE_LOAD_PASS1); - if (ACPI_FAILURE(status)) { - acpi_ds_delete_walk_state(walk_state); - goto cleanup; - } - - /* Mark this parse as a deferred opcode */ - - walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP; - walk_state->deferred_node = node; - - /* Pass1: Parse the entire declaration */ - - status = acpi_ps_parse_aml(walk_state); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - /* Get and init the Op created above */ - - op->common.node = node; - acpi_ps_delete_parse_tree(op); - - /* Evaluate the deferred arguments */ - - op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); - if (!op) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - op->common.node = scope_node; - - /* Create and initialize a new parser state */ - - walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL); - if (!walk_state) { - status = AE_NO_MEMORY; - goto cleanup; - } - - /* Execute the opcode and arguments */ - - status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start, - aml_length, NULL, ACPI_IMODE_EXECUTE); - if (ACPI_FAILURE(status)) { - acpi_ds_delete_walk_state(walk_state); - goto cleanup; - } - - /* Mark this execution as a deferred opcode */ - - walk_state->deferred_node = node; - status = acpi_ps_parse_aml(walk_state); - - cleanup: - acpi_ps_delete_parse_tree(op); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_get_buffer_field_arguments - * - * PARAMETERS: obj_desc - A valid buffer_field object - * - * RETURN: Status. - * - * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late - * evaluation of these field attributes. - * - ******************************************************************************/ - -acpi_status -acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc) -{ - union acpi_operand_object *extra_desc; - struct acpi_namespace_node *node; - acpi_status status; - - ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc); - - if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { - return_ACPI_STATUS(AE_OK); - } - - /* Get the AML pointer (method object) and buffer_field node */ - - extra_desc = acpi_ns_get_secondary_object(obj_desc); - node = obj_desc->buffer_field.node; - - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname - (ACPI_TYPE_BUFFER_FIELD, node, NULL)); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n", - acpi_ut_get_node_name(node))); - - /* Execute the AML code for the term_arg arguments */ - - status = acpi_ds_execute_arguments(node, node->parent, - extra_desc->extra.aml_length, - extra_desc->extra.aml_start); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_get_bank_field_arguments - * - * PARAMETERS: obj_desc - A valid bank_field object - * - * RETURN: Status. - * - * DESCRIPTION: Get bank_field bank_value. This implements the late - * evaluation of these field attributes. - * - ******************************************************************************/ - -acpi_status -acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc) -{ - union acpi_operand_object *extra_desc; - struct acpi_namespace_node *node; - acpi_status status; - - ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc); - - if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { - return_ACPI_STATUS(AE_OK); - } - - /* Get the AML pointer (method object) and bank_field node */ - - extra_desc = acpi_ns_get_secondary_object(obj_desc); - node = obj_desc->bank_field.node; - - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname - (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL)); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n", - acpi_ut_get_node_name(node))); - - /* Execute the AML code for the term_arg arguments */ - - status = acpi_ds_execute_arguments(node, node->parent, - extra_desc->extra.aml_length, - extra_desc->extra.aml_start); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_get_buffer_arguments - * - * PARAMETERS: obj_desc - A valid Buffer object - * - * RETURN: Status. - * - * DESCRIPTION: Get Buffer length and initializer byte list. This implements - * the late evaluation of these attributes. - * - ******************************************************************************/ - -acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc) -{ - struct acpi_namespace_node *node; - acpi_status status; - - ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc); - - if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { - return_ACPI_STATUS(AE_OK); - } - - /* Get the Buffer node */ - - node = obj_desc->buffer.node; - if (!node) { - ACPI_ERROR((AE_INFO, - "No pointer back to namespace node in buffer object %p", - obj_desc)); - return_ACPI_STATUS(AE_AML_INTERNAL); - } - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Buffer Arg Init\n")); - - /* Execute the AML code for the term_arg arguments */ - - status = acpi_ds_execute_arguments(node, node, - obj_desc->buffer.aml_length, - obj_desc->buffer.aml_start); - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_get_package_arguments - * - * PARAMETERS: obj_desc - A valid Package object - * - * RETURN: Status. - * - * DESCRIPTION: Get Package length and initializer byte list. This implements - * the late evaluation of these attributes. - * - ******************************************************************************/ - -acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc) -{ - struct acpi_namespace_node *node; - acpi_status status; - - ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc); - - if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { - return_ACPI_STATUS(AE_OK); - } - - /* Get the Package node */ - - node = obj_desc->package.node; - if (!node) { - ACPI_ERROR((AE_INFO, - "No pointer back to namespace node in package %p", - obj_desc)); - return_ACPI_STATUS(AE_AML_INTERNAL); - } - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n")); - - /* Execute the AML code for the term_arg arguments */ - - status = acpi_ds_execute_arguments(node, node, - obj_desc->package.aml_length, - obj_desc->package.aml_start); - return_ACPI_STATUS(status); -} - -/***************************************************************************** - * - * FUNCTION: acpi_ds_get_region_arguments - * - * PARAMETERS: obj_desc - A valid region object - * - * RETURN: Status. - * - * DESCRIPTION: Get region address and length. This implements the late - * evaluation of these region attributes. - * - ****************************************************************************/ - -acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) -{ - struct acpi_namespace_node *node; - acpi_status status; - union acpi_operand_object *extra_desc; - - ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc); - - if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { - return_ACPI_STATUS(AE_OK); - } - - extra_desc = acpi_ns_get_secondary_object(obj_desc); - if (!extra_desc) { - return_ACPI_STATUS(AE_NOT_EXIST); - } - - /* Get the Region node */ - - node = obj_desc->region.node; - - ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname - (ACPI_TYPE_REGION, node, NULL)); - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n", - acpi_ut_get_node_name(node), - extra_desc->extra.aml_start)); - - /* Execute the argument AML */ - - status = acpi_ds_execute_arguments(node, node->parent, - extra_desc->extra.aml_length, - extra_desc->extra.aml_start); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - - /* Validate the region address/length via the host OS */ - - status = acpi_os_validate_address(obj_desc->region.space_id, - obj_desc->region.address, - (acpi_size) obj_desc->region.length, - acpi_ut_get_node_name(node)); - - if (ACPI_FAILURE(status)) { - /* - * Invalid address/length. We will emit an error message and mark - * the region as invalid, so that it will cause an additional error if - * it is ever used. Then return AE_OK. - */ - ACPI_EXCEPTION((AE_INFO, status, - "During address validation of OpRegion [%4.4s]", - node->name.ascii)); - obj_desc->common.flags |= AOPOBJ_INVALID; - status = AE_OK; - } - - return_ACPI_STATUS(status); -} - /******************************************************************************* * * FUNCTION: acpi_ds_initialize_region @@ -826,8 +465,9 @@ acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, * * RETURN: Status * - * DESCRIPTION: Get region address and length - * Called from acpi_ds_exec_end_op during data_table_region parse tree walk + * DESCRIPTION: Get region address and length. + * Called from acpi_ds_exec_end_op during data_table_region parse + * tree walk. * ******************************************************************************/ @@ -1114,360 +754,3 @@ acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, acpi_ut_remove_reference(operand_desc); return_ACPI_STATUS(status); } - -/******************************************************************************* - * - * FUNCTION: acpi_ds_exec_begin_control_op - * - * PARAMETERS: walk_list - The list that owns the walk stack - * Op - The control Op - * - * RETURN: Status - * - * DESCRIPTION: Handles all control ops encountered during control method - * execution. - * - ******************************************************************************/ - -acpi_status -acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, - union acpi_parse_object *op) -{ - acpi_status status = AE_OK; - union acpi_generic_state *control_state; - - ACPI_FUNCTION_NAME(ds_exec_begin_control_op); - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op, - op->common.aml_opcode, walk_state)); - - switch (op->common.aml_opcode) { - case AML_WHILE_OP: - - /* - * If this is an additional iteration of a while loop, continue. - * There is no need to allocate a new control state. - */ - if (walk_state->control_state) { - if (walk_state->control_state->control.aml_predicate_start - == (walk_state->parser_state.aml - 1)) { - - /* Reset the state to start-of-loop */ - - walk_state->control_state->common.state = - ACPI_CONTROL_CONDITIONAL_EXECUTING; - break; - } - } - - /*lint -fallthrough */ - - case AML_IF_OP: - - /* - * IF/WHILE: Create a new control state to manage these - * constructs. We need to manage these as a stack, in order - * to handle nesting. - */ - control_state = acpi_ut_create_control_state(); - if (!control_state) { - status = AE_NO_MEMORY; - break; - } - /* - * Save a pointer to the predicate for multiple executions - * of a loop - */ - control_state->control.aml_predicate_start = - walk_state->parser_state.aml - 1; - control_state->control.package_end = - walk_state->parser_state.pkg_end; - control_state->control.opcode = op->common.aml_opcode; - - /* Push the control state on this walk's control stack */ - - acpi_ut_push_generic_state(&walk_state->control_state, - control_state); - break; - - case AML_ELSE_OP: - - /* Predicate is in the state object */ - /* If predicate is true, the IF was executed, ignore ELSE part */ - - if (walk_state->last_predicate) { - status = AE_CTRL_TRUE; - } - - break; - - case AML_RETURN_OP: - - break; - - default: - break; - } - - return (status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_exec_end_control_op - * - * PARAMETERS: walk_list - The list that owns the walk stack - * Op - The control Op - * - * RETURN: Status - * - * DESCRIPTION: Handles all control ops encountered during control method - * execution. - * - ******************************************************************************/ - -acpi_status -acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, - union acpi_parse_object * op) -{ - acpi_status status = AE_OK; - union acpi_generic_state *control_state; - - ACPI_FUNCTION_NAME(ds_exec_end_control_op); - - switch (op->common.aml_opcode) { - case AML_IF_OP: - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op)); - - /* - * Save the result of the predicate in case there is an - * ELSE to come - */ - walk_state->last_predicate = - (u8) walk_state->control_state->common.value; - - /* - * Pop the control state that was created at the start - * of the IF and free it - */ - control_state = - acpi_ut_pop_generic_state(&walk_state->control_state); - acpi_ut_delete_generic_state(control_state); - break; - - case AML_ELSE_OP: - - break; - - case AML_WHILE_OP: - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); - - control_state = walk_state->control_state; - if (control_state->common.value) { - - /* Predicate was true, the body of the loop was just executed */ - - /* - * This loop counter mechanism allows the interpreter to escape - * possibly infinite loops. This can occur in poorly written AML - * when the hardware does not respond within a while loop and the - * loop does not implement a timeout. - */ - control_state->control.loop_count++; - if (control_state->control.loop_count > - ACPI_MAX_LOOP_ITERATIONS) { - status = AE_AML_INFINITE_LOOP; - break; - } - - /* - * Go back and evaluate the predicate and maybe execute the loop - * another time - */ - status = AE_CTRL_PENDING; - walk_state->aml_last_while = - control_state->control.aml_predicate_start; - break; - } - - /* Predicate was false, terminate this while loop */ - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "[WHILE_OP] termination! Op=%p\n", op)); - - /* Pop this control state and free it */ - - control_state = - acpi_ut_pop_generic_state(&walk_state->control_state); - acpi_ut_delete_generic_state(control_state); - break; - - case AML_RETURN_OP: - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "[RETURN_OP] Op=%p Arg=%p\n", op, - op->common.value.arg)); - - /* - * One optional operand -- the return value - * It can be either an immediate operand or a result that - * has been bubbled up the tree - */ - if (op->common.value.arg) { - - /* Since we have a real Return(), delete any implicit return */ - - acpi_ds_clear_implicit_return(walk_state); - - /* Return statement has an immediate operand */ - - status = - acpi_ds_create_operands(walk_state, - op->common.value.arg); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* - * If value being returned is a Reference (such as - * an arg or local), resolve it now because it may - * cease to exist at the end of the method. - */ - status = - acpi_ex_resolve_to_value(&walk_state->operands[0], - walk_state); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* - * Get the return value and save as the last result - * value. This is the only place where walk_state->return_desc - * is set to anything other than zero! - */ - walk_state->return_desc = walk_state->operands[0]; - } else if (walk_state->result_count) { - - /* Since we have a real Return(), delete any implicit return */ - - acpi_ds_clear_implicit_return(walk_state); - - /* - * The return value has come from a previous calculation. - * - * If value being returned is a Reference (such as - * an arg or local), resolve it now because it may - * cease to exist at the end of the method. - * - * Allow references created by the Index operator to return unchanged. - */ - if ((ACPI_GET_DESCRIPTOR_TYPE - (walk_state->results->results.obj_desc[0]) == - ACPI_DESC_TYPE_OPERAND) - && ((walk_state->results->results.obj_desc[0])-> - common.type == ACPI_TYPE_LOCAL_REFERENCE) - && ((walk_state->results->results.obj_desc[0])-> - reference.class != ACPI_REFCLASS_INDEX)) { - status = - acpi_ex_resolve_to_value(&walk_state-> - results->results. - obj_desc[0], - walk_state); - if (ACPI_FAILURE(status)) { - return (status); - } - } - - walk_state->return_desc = - walk_state->results->results.obj_desc[0]; - } else { - /* No return operand */ - - if (walk_state->num_operands) { - acpi_ut_remove_reference(walk_state-> - operands[0]); - } - - walk_state->operands[0] = NULL; - walk_state->num_operands = 0; - walk_state->return_desc = NULL; - } - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Completed RETURN_OP State=%p, RetVal=%p\n", - walk_state, walk_state->return_desc)); - - /* End the control method execution right now */ - - status = AE_CTRL_TERMINATE; - break; - - case AML_NOOP_OP: - - /* Just do nothing! */ - break; - - case AML_BREAK_POINT_OP: - - /* - * Set the single-step flag. This will cause the debugger (if present) - * to break to the console within the AML debugger at the start of the - * next AML instruction. - */ - ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); - ACPI_DEBUGGER_EXEC(acpi_os_printf - ("**break** Executed AML BreakPoint opcode\n")); - - /* Call to the OSL in case OS wants a piece of the action */ - - status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, - "Executed AML Breakpoint opcode"); - break; - - case AML_BREAK_OP: - case AML_CONTINUE_OP: /* ACPI 2.0 */ - - /* Pop and delete control states until we find a while */ - - while (walk_state->control_state && - (walk_state->control_state->control.opcode != - AML_WHILE_OP)) { - control_state = - acpi_ut_pop_generic_state(&walk_state-> - control_state); - acpi_ut_delete_generic_state(control_state); - } - - /* No while found? */ - - if (!walk_state->control_state) { - return (AE_AML_NO_WHILE); - } - - /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */ - - walk_state->aml_last_while = - walk_state->control_state->control.package_end; - - /* Return status depending on opcode */ - - if (op->common.aml_opcode == AML_BREAK_OP) { - status = AE_CTRL_BREAK; - } else { - status = AE_CTRL_CONTINUE; - } - break; - - default: - - ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p", - op->common.aml_opcode, op)); - - status = AE_AML_BAD_OPCODE; - break; - } - - return (status); -} diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 52566ff5e903..23a3b1ab20c1 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Module Name: dswload - Dispatcher namespace load callbacks + * Module Name: dswload - Dispatcher first pass namespace load callbacks * *****************************************************************************/ @@ -48,7 +48,6 @@ #include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" -#include "acevents.h" #ifdef ACPI_ASL_COMPILER #include @@ -537,670 +536,3 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state) return_ACPI_STATUS(status); } - -/******************************************************************************* - * - * FUNCTION: acpi_ds_load2_begin_op - * - * PARAMETERS: walk_state - Current state of the parse tree walk - * out_op - Wher to return op if a new one is created - * - * RETURN: Status - * - * DESCRIPTION: Descending callback used during the loading of ACPI tables. - * - ******************************************************************************/ - -acpi_status -acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, - union acpi_parse_object **out_op) -{ - union acpi_parse_object *op; - struct acpi_namespace_node *node; - acpi_status status; - acpi_object_type object_type; - char *buffer_ptr; - u32 flags; - - ACPI_FUNCTION_TRACE(ds_load2_begin_op); - - op = walk_state->op; - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, - walk_state)); - - if (op) { - if ((walk_state->control_state) && - (walk_state->control_state->common.state == - ACPI_CONTROL_CONDITIONAL_EXECUTING)) { - - /* We are executing a while loop outside of a method */ - - status = acpi_ds_exec_begin_op(walk_state, out_op); - return_ACPI_STATUS(status); - } - - /* We only care about Namespace opcodes here */ - - if ((!(walk_state->op_info->flags & AML_NSOPCODE) && - (walk_state->opcode != AML_INT_NAMEPATH_OP)) || - (!(walk_state->op_info->flags & AML_NAMED))) { - return_ACPI_STATUS(AE_OK); - } - - /* Get the name we are going to enter or lookup in the namespace */ - - if (walk_state->opcode == AML_INT_NAMEPATH_OP) { - - /* For Namepath op, get the path string */ - - buffer_ptr = op->common.value.string; - if (!buffer_ptr) { - - /* No name, just exit */ - - return_ACPI_STATUS(AE_OK); - } - } else { - /* Get name from the op */ - - buffer_ptr = ACPI_CAST_PTR(char, &op->named.name); - } - } else { - /* Get the namestring from the raw AML */ - - buffer_ptr = - acpi_ps_get_next_namestring(&walk_state->parser_state); - } - - /* Map the opcode into an internal object type */ - - object_type = walk_state->op_info->object_type; - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "State=%p Op=%p Type=%X\n", walk_state, op, - object_type)); - - switch (walk_state->opcode) { - case AML_FIELD_OP: - case AML_BANK_FIELD_OP: - case AML_INDEX_FIELD_OP: - - node = NULL; - status = AE_OK; - break; - - case AML_INT_NAMEPATH_OP: - /* - * The name_path is an object reference to an existing object. - * Don't enter the name into the namespace, but look it up - * for use later. - */ - status = - acpi_ns_lookup(walk_state->scope_info, buffer_ptr, - object_type, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT, walk_state, &(node)); - break; - - case AML_SCOPE_OP: - - /* Special case for Scope(\) -> refers to the Root node */ - - if (op && (op->named.node == acpi_gbl_root_node)) { - node = op->named.node; - - status = - acpi_ds_scope_stack_push(node, object_type, - walk_state); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } else { - /* - * The Path is an object reference to an existing object. - * Don't enter the name into the namespace, but look it up - * for use later. - */ - status = - acpi_ns_lookup(walk_state->scope_info, buffer_ptr, - object_type, ACPI_IMODE_EXECUTE, - ACPI_NS_SEARCH_PARENT, walk_state, - &(node)); - if (ACPI_FAILURE(status)) { -#ifdef ACPI_ASL_COMPILER - if (status == AE_NOT_FOUND) { - status = AE_OK; - } else { - ACPI_ERROR_NAMESPACE(buffer_ptr, - status); - } -#else - ACPI_ERROR_NAMESPACE(buffer_ptr, status); -#endif - return_ACPI_STATUS(status); - } - } - - /* - * We must check to make sure that the target is - * one of the opcodes that actually opens a scope - */ - switch (node->type) { - case ACPI_TYPE_ANY: - case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ - case ACPI_TYPE_DEVICE: - case ACPI_TYPE_POWER: - case ACPI_TYPE_PROCESSOR: - case ACPI_TYPE_THERMAL: - - /* These are acceptable types */ - break; - - case ACPI_TYPE_INTEGER: - case ACPI_TYPE_STRING: - case ACPI_TYPE_BUFFER: - - /* - * These types we will allow, but we will change the type. - * This enables some existing code of the form: - * - * Name (DEB, 0) - * Scope (DEB) { ... } - */ - ACPI_WARNING((AE_INFO, - "Type override - [%4.4s] had invalid type (%s) " - "for Scope operator, changed to type ANY\n", - acpi_ut_get_node_name(node), - acpi_ut_get_type_name(node->type))); - - node->type = ACPI_TYPE_ANY; - walk_state->scope_info->common.value = ACPI_TYPE_ANY; - break; - - default: - - /* All other types are an error */ - - ACPI_ERROR((AE_INFO, - "Invalid type (%s) for target of " - "Scope operator [%4.4s] (Cannot override)", - acpi_ut_get_type_name(node->type), - acpi_ut_get_node_name(node))); - - return (AE_AML_OPERAND_TYPE); - } - break; - - default: - - /* All other opcodes */ - - if (op && op->common.node) { - - /* This op/node was previously entered into the namespace */ - - node = op->common.node; - - if (acpi_ns_opens_scope(object_type)) { - status = - acpi_ds_scope_stack_push(node, object_type, - walk_state); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - - return_ACPI_STATUS(AE_OK); - } - - /* - * Enter the named type into the internal namespace. We enter the name - * as we go downward in the parse tree. Any necessary subobjects that - * involve arguments to the opcode must be created as we go back up the - * parse tree later. - * - * Note: Name may already exist if we are executing a deferred opcode. - */ - if (walk_state->deferred_node) { - - /* This name is already in the namespace, get the node */ - - node = walk_state->deferred_node; - status = AE_OK; - break; - } - - flags = ACPI_NS_NO_UPSEARCH; - if (walk_state->pass_number == ACPI_IMODE_EXECUTE) { - - /* Execution mode, node cannot already exist, node is temporary */ - - flags |= ACPI_NS_ERROR_IF_FOUND; - - if (! - (walk_state-> - parse_flags & ACPI_PARSE_MODULE_LEVEL)) { - flags |= ACPI_NS_TEMPORARY; - } - } - - /* Add new entry or lookup existing entry */ - - status = - acpi_ns_lookup(walk_state->scope_info, buffer_ptr, - object_type, ACPI_IMODE_LOAD_PASS2, flags, - walk_state, &node); - - if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) { - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "***New Node [%4.4s] %p is temporary\n", - acpi_ut_get_node_name(node), node)); - } - break; - } - - if (ACPI_FAILURE(status)) { - ACPI_ERROR_NAMESPACE(buffer_ptr, status); - return_ACPI_STATUS(status); - } - - if (!op) { - - /* Create a new op */ - - op = acpi_ps_alloc_op(walk_state->opcode); - if (!op) { - return_ACPI_STATUS(AE_NO_MEMORY); - } - - /* Initialize the new op */ - - if (node) { - op->named.name = node->name.integer; - } - *out_op = op; - } - - /* - * Put the Node in the "op" object that the parser uses, so we - * can get it again quickly when this scope is closed - */ - op->common.node = node; - return_ACPI_STATUS(status); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ds_load2_end_op - * - * PARAMETERS: walk_state - Current state of the parse tree walk - * - * RETURN: Status - * - * DESCRIPTION: Ascending callback used during the loading of the namespace, - * both control methods and everything else. - * - ******************************************************************************/ - -acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) -{ - union acpi_parse_object *op; - acpi_status status = AE_OK; - acpi_object_type object_type; - struct acpi_namespace_node *node; - union acpi_parse_object *arg; - struct acpi_namespace_node *new_node; -#ifndef ACPI_NO_METHOD_EXECUTION - u32 i; - u8 region_space; -#endif - - ACPI_FUNCTION_TRACE(ds_load2_end_op); - - op = walk_state->op; - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", - walk_state->op_info->name, op, walk_state)); - - /* Check if opcode had an associated namespace object */ - - if (!(walk_state->op_info->flags & AML_NSOBJECT)) { - return_ACPI_STATUS(AE_OK); - } - - if (op->common.aml_opcode == AML_SCOPE_OP) { - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Ending scope Op=%p State=%p\n", op, - walk_state)); - } - - object_type = walk_state->op_info->object_type; - - /* - * Get the Node/name from the earlier lookup - * (It was saved in the *op structure) - */ - node = op->common.node; - - /* - * Put the Node on the object stack (Contains the ACPI Name of - * this object) - */ - walk_state->operands[0] = (void *)node; - walk_state->num_operands = 1; - - /* Pop the scope stack */ - - if (acpi_ns_opens_scope(object_type) && - (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "(%s) Popping scope for Op %p\n", - acpi_ut_get_type_name(object_type), op)); - - status = acpi_ds_scope_stack_pop(walk_state); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - } - - /* - * Named operations are as follows: - * - * AML_ALIAS - * AML_BANKFIELD - * AML_CREATEBITFIELD - * AML_CREATEBYTEFIELD - * AML_CREATEDWORDFIELD - * AML_CREATEFIELD - * AML_CREATEQWORDFIELD - * AML_CREATEWORDFIELD - * AML_DATA_REGION - * AML_DEVICE - * AML_EVENT - * AML_FIELD - * AML_INDEXFIELD - * AML_METHOD - * AML_METHODCALL - * AML_MUTEX - * AML_NAME - * AML_NAMEDFIELD - * AML_OPREGION - * AML_POWERRES - * AML_PROCESSOR - * AML_SCOPE - * AML_THERMALZONE - */ - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "Create-Load [%s] State=%p Op=%p NamedObj=%p\n", - acpi_ps_get_opcode_name(op->common.aml_opcode), - walk_state, op, node)); - - /* Decode the opcode */ - - arg = op->common.value.arg; - - switch (walk_state->op_info->type) { -#ifndef ACPI_NO_METHOD_EXECUTION - - case AML_TYPE_CREATE_FIELD: - /* - * Create the field object, but the field buffer and index must - * be evaluated later during the execution phase - */ - status = acpi_ds_create_buffer_field(op, walk_state); - break; - - case AML_TYPE_NAMED_FIELD: - /* - * If we are executing a method, initialize the field - */ - if (walk_state->method_node) { - status = acpi_ds_init_field_objects(op, walk_state); - } - - switch (op->common.aml_opcode) { - case AML_INDEX_FIELD_OP: - - status = - acpi_ds_create_index_field(op, - (acpi_handle) arg-> - common.node, walk_state); - break; - - case AML_BANK_FIELD_OP: - - status = - acpi_ds_create_bank_field(op, arg->common.node, - walk_state); - break; - - case AML_FIELD_OP: - - status = - acpi_ds_create_field(op, arg->common.node, - walk_state); - break; - - default: - /* All NAMED_FIELD opcodes must be handled above */ - break; - } - break; - - case AML_TYPE_NAMED_SIMPLE: - - status = acpi_ds_create_operands(walk_state, arg); - if (ACPI_FAILURE(status)) { - goto cleanup; - } - - switch (op->common.aml_opcode) { - case AML_PROCESSOR_OP: - - status = acpi_ex_create_processor(walk_state); - break; - - case AML_POWER_RES_OP: - - status = acpi_ex_create_power_resource(walk_state); - break; - - case AML_MUTEX_OP: - - status = acpi_ex_create_mutex(walk_state); - break; - - case AML_EVENT_OP: - - status = acpi_ex_create_event(walk_state); - break; - - case AML_ALIAS_OP: - - status = acpi_ex_create_alias(walk_state); - break; - - default: - /* Unknown opcode */ - - status = AE_OK; - goto cleanup; - } - - /* Delete operands */ - - for (i = 1; i < walk_state->num_operands; i++) { - acpi_ut_remove_reference(walk_state->operands[i]); - walk_state->operands[i] = NULL; - } - - break; -#endif /* ACPI_NO_METHOD_EXECUTION */ - - case AML_TYPE_NAMED_COMPLEX: - - switch (op->common.aml_opcode) { -#ifndef ACPI_NO_METHOD_EXECUTION - case AML_REGION_OP: - case AML_DATA_REGION_OP: - - if (op->common.aml_opcode == AML_REGION_OP) { - region_space = (acpi_adr_space_type) - ((op->common.value.arg)->common.value. - integer); - } else { - region_space = REGION_DATA_TABLE; - } - - /* - * The op_region is not fully parsed at this time. The only valid - * argument is the space_id. (We must save the address of the - * AML of the address and length operands) - * - * If we have a valid region, initialize it. The namespace is - * unlocked at this point. - * - * Need to unlock interpreter if it is locked (if we are running - * a control method), in order to allow _REG methods to be run - * during acpi_ev_initialize_region. - */ - if (walk_state->method_node) { - /* - * Executing a method: initialize the region and unlock - * the interpreter - */ - status = - acpi_ex_create_region(op->named.data, - op->named.length, - region_space, - walk_state); - if (ACPI_FAILURE(status)) { - return (status); - } - - acpi_ex_exit_interpreter(); - } - - status = - acpi_ev_initialize_region - (acpi_ns_get_attached_object(node), FALSE); - if (walk_state->method_node) { - acpi_ex_enter_interpreter(); - } - - if (ACPI_FAILURE(status)) { - /* - * If AE_NOT_EXIST is returned, it is not fatal - * because many regions get created before a handler - * is installed for said region. - */ - if (AE_NOT_EXIST == status) { - status = AE_OK; - } - } - break; - - case AML_NAME_OP: - - status = acpi_ds_create_node(walk_state, node, op); - break; - - case AML_METHOD_OP: - /* - * method_op pkg_length name_string method_flags term_list - * - * Note: We must create the method node/object pair as soon as we - * see the method declaration. This allows later pass1 parsing - * of invocations of the method (need to know the number of - * arguments.) - */ - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "LOADING-Method: State=%p Op=%p NamedObj=%p\n", - walk_state, op, op->named.node)); - - if (!acpi_ns_get_attached_object(op->named.node)) { - walk_state->operands[0] = - ACPI_CAST_PTR(void, op->named.node); - walk_state->num_operands = 1; - - status = - acpi_ds_create_operands(walk_state, - op->common.value. - arg); - if (ACPI_SUCCESS(status)) { - status = - acpi_ex_create_method(op->named. - data, - op->named. - length, - walk_state); - } - walk_state->operands[0] = NULL; - walk_state->num_operands = 0; - - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } - } - break; - -#endif /* ACPI_NO_METHOD_EXECUTION */ - - default: - /* All NAMED_COMPLEX opcodes must be handled above */ - break; - } - break; - - case AML_CLASS_INTERNAL: - - /* case AML_INT_NAMEPATH_OP: */ - break; - - case AML_CLASS_METHOD_CALL: - - ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, - "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n", - walk_state, op, node)); - - /* - * Lookup the method name and save the Node - */ - status = - acpi_ns_lookup(walk_state->scope_info, - arg->common.value.string, ACPI_TYPE_ANY, - ACPI_IMODE_LOAD_PASS2, - ACPI_NS_SEARCH_PARENT | - ACPI_NS_DONT_OPEN_SCOPE, walk_state, - &(new_node)); - if (ACPI_SUCCESS(status)) { - /* - * Make sure that what we found is indeed a method - * We didn't search for a method on purpose, to see if the name - * would resolve - */ - if (new_node->type != ACPI_TYPE_METHOD) { - status = AE_AML_OPERAND_TYPE; - } - - /* We could put the returned object (Node) on the object stack for - * later, but for now, we will put it in the "op" object that the - * parser uses, so we can get it again at the end of this scope - */ - op->common.node = new_node; - } else { - ACPI_ERROR_NAMESPACE(arg->common.value.string, status); - } - break; - - default: - break; - } - - cleanup: - - /* Remove the Node pushed at the very beginning */ - - walk_state->operands[0] = NULL; - walk_state->num_operands = 0; - return_ACPI_STATUS(status); -} diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c new file mode 100644 index 000000000000..4be4e921dfe1 --- /dev/null +++ b/drivers/acpi/acpica/dswload2.c @@ -0,0 +1,720 @@ +/****************************************************************************** + * + * Module Name: dswload2 - Dispatcher second pass namespace load callbacks + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2011, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" + +#define _COMPONENT ACPI_DISPATCHER +ACPI_MODULE_NAME("dswload2") + +/******************************************************************************* + * + * FUNCTION: acpi_ds_load2_begin_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * out_op - Wher to return op if a new one is created + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * + ******************************************************************************/ +acpi_status +acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op) +{ + union acpi_parse_object *op; + struct acpi_namespace_node *node; + acpi_status status; + acpi_object_type object_type; + char *buffer_ptr; + u32 flags; + + ACPI_FUNCTION_TRACE(ds_load2_begin_op); + + op = walk_state->op; + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, + walk_state)); + + if (op) { + if ((walk_state->control_state) && + (walk_state->control_state->common.state == + ACPI_CONTROL_CONDITIONAL_EXECUTING)) { + + /* We are executing a while loop outside of a method */ + + status = acpi_ds_exec_begin_op(walk_state, out_op); + return_ACPI_STATUS(status); + } + + /* We only care about Namespace opcodes here */ + + if ((!(walk_state->op_info->flags & AML_NSOPCODE) && + (walk_state->opcode != AML_INT_NAMEPATH_OP)) || + (!(walk_state->op_info->flags & AML_NAMED))) { + return_ACPI_STATUS(AE_OK); + } + + /* Get the name we are going to enter or lookup in the namespace */ + + if (walk_state->opcode == AML_INT_NAMEPATH_OP) { + + /* For Namepath op, get the path string */ + + buffer_ptr = op->common.value.string; + if (!buffer_ptr) { + + /* No name, just exit */ + + return_ACPI_STATUS(AE_OK); + } + } else { + /* Get name from the op */ + + buffer_ptr = ACPI_CAST_PTR(char, &op->named.name); + } + } else { + /* Get the namestring from the raw AML */ + + buffer_ptr = + acpi_ps_get_next_namestring(&walk_state->parser_state); + } + + /* Map the opcode into an internal object type */ + + object_type = walk_state->op_info->object_type; + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "State=%p Op=%p Type=%X\n", walk_state, op, + object_type)); + + switch (walk_state->opcode) { + case AML_FIELD_OP: + case AML_BANK_FIELD_OP: + case AML_INDEX_FIELD_OP: + + node = NULL; + status = AE_OK; + break; + + case AML_INT_NAMEPATH_OP: + /* + * The name_path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. + */ + status = + acpi_ns_lookup(walk_state->scope_info, buffer_ptr, + object_type, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + break; + + case AML_SCOPE_OP: + + /* Special case for Scope(\) -> refers to the Root node */ + + if (op && (op->named.node == acpi_gbl_root_node)) { + node = op->named.node; + + status = + acpi_ds_scope_stack_push(node, object_type, + walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } else { + /* + * The Path is an object reference to an existing object. + * Don't enter the name into the namespace, but look it up + * for use later. + */ + status = + acpi_ns_lookup(walk_state->scope_info, buffer_ptr, + object_type, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, + &(node)); + if (ACPI_FAILURE(status)) { +#ifdef ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + status = AE_OK; + } else { + ACPI_ERROR_NAMESPACE(buffer_ptr, + status); + } +#else + ACPI_ERROR_NAMESPACE(buffer_ptr, status); +#endif + return_ACPI_STATUS(status); + } + } + + /* + * We must check to make sure that the target is + * one of the opcodes that actually opens a scope + */ + switch (node->type) { + case ACPI_TYPE_ANY: + case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types */ + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * These types we will allow, but we will change the type. + * This enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + */ + ACPI_WARNING((AE_INFO, + "Type override - [%4.4s] had invalid type (%s) " + "for Scope operator, changed to type ANY\n", + acpi_ut_get_node_name(node), + acpi_ut_get_type_name(node->type))); + + node->type = ACPI_TYPE_ANY; + walk_state->scope_info->common.value = ACPI_TYPE_ANY; + break; + + default: + + /* All other types are an error */ + + ACPI_ERROR((AE_INFO, + "Invalid type (%s) for target of " + "Scope operator [%4.4s] (Cannot override)", + acpi_ut_get_type_name(node->type), + acpi_ut_get_node_name(node))); + + return (AE_AML_OPERAND_TYPE); + } + break; + + default: + + /* All other opcodes */ + + if (op && op->common.node) { + + /* This op/node was previously entered into the namespace */ + + node = op->common.node; + + if (acpi_ns_opens_scope(object_type)) { + status = + acpi_ds_scope_stack_push(node, object_type, + walk_state); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } + + return_ACPI_STATUS(AE_OK); + } + + /* + * Enter the named type into the internal namespace. We enter the name + * as we go downward in the parse tree. Any necessary subobjects that + * involve arguments to the opcode must be created as we go back up the + * parse tree later. + * + * Note: Name may already exist if we are executing a deferred opcode. + */ + if (walk_state->deferred_node) { + + /* This name is already in the namespace, get the node */ + + node = walk_state->deferred_node; + status = AE_OK; + break; + } + + flags = ACPI_NS_NO_UPSEARCH; + if (walk_state->pass_number == ACPI_IMODE_EXECUTE) { + + /* Execution mode, node cannot already exist, node is temporary */ + + flags |= ACPI_NS_ERROR_IF_FOUND; + + if (! + (walk_state-> + parse_flags & ACPI_PARSE_MODULE_LEVEL)) { + flags |= ACPI_NS_TEMPORARY; + } + } + + /* Add new entry or lookup existing entry */ + + status = + acpi_ns_lookup(walk_state->scope_info, buffer_ptr, + object_type, ACPI_IMODE_LOAD_PASS2, flags, + walk_state, &node); + + if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "***New Node [%4.4s] %p is temporary\n", + acpi_ut_get_node_name(node), node)); + } + break; + } + + if (ACPI_FAILURE(status)) { + ACPI_ERROR_NAMESPACE(buffer_ptr, status); + return_ACPI_STATUS(status); + } + + if (!op) { + + /* Create a new op */ + + op = acpi_ps_alloc_op(walk_state->opcode); + if (!op) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + /* Initialize the new op */ + + if (node) { + op->named.name = node->name.integer; + } + *out_op = op; + } + + /* + * Put the Node in the "op" object that the parser uses, so we + * can get it again quickly when this scope is closed + */ + op->common.node = node; + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_load2_end_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * both control methods and everything else. + * + ******************************************************************************/ + +acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) +{ + union acpi_parse_object *op; + acpi_status status = AE_OK; + acpi_object_type object_type; + struct acpi_namespace_node *node; + union acpi_parse_object *arg; + struct acpi_namespace_node *new_node; +#ifndef ACPI_NO_METHOD_EXECUTION + u32 i; + u8 region_space; +#endif + + ACPI_FUNCTION_TRACE(ds_load2_end_op); + + op = walk_state->op; + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", + walk_state->op_info->name, op, walk_state)); + + /* Check if opcode had an associated namespace object */ + + if (!(walk_state->op_info->flags & AML_NSOBJECT)) { + return_ACPI_STATUS(AE_OK); + } + + if (op->common.aml_opcode == AML_SCOPE_OP) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "Ending scope Op=%p State=%p\n", op, + walk_state)); + } + + object_type = walk_state->op_info->object_type; + + /* + * Get the Node/name from the earlier lookup + * (It was saved in the *op structure) + */ + node = op->common.node; + + /* + * Put the Node on the object stack (Contains the ACPI Name of + * this object) + */ + walk_state->operands[0] = (void *)node; + walk_state->num_operands = 1; + + /* Pop the scope stack */ + + if (acpi_ns_opens_scope(object_type) && + (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "(%s) Popping scope for Op %p\n", + acpi_ut_get_type_name(object_type), op)); + + status = acpi_ds_scope_stack_pop(walk_state); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + } + + /* + * Named operations are as follows: + * + * AML_ALIAS + * AML_BANKFIELD + * AML_CREATEBITFIELD + * AML_CREATEBYTEFIELD + * AML_CREATEDWORDFIELD + * AML_CREATEFIELD + * AML_CREATEQWORDFIELD + * AML_CREATEWORDFIELD + * AML_DATA_REGION + * AML_DEVICE + * AML_EVENT + * AML_FIELD + * AML_INDEXFIELD + * AML_METHOD + * AML_METHODCALL + * AML_MUTEX + * AML_NAME + * AML_NAMEDFIELD + * AML_OPREGION + * AML_POWERRES + * AML_PROCESSOR + * AML_SCOPE + * AML_THERMALZONE + */ + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "Create-Load [%s] State=%p Op=%p NamedObj=%p\n", + acpi_ps_get_opcode_name(op->common.aml_opcode), + walk_state, op, node)); + + /* Decode the opcode */ + + arg = op->common.value.arg; + + switch (walk_state->op_info->type) { +#ifndef ACPI_NO_METHOD_EXECUTION + + case AML_TYPE_CREATE_FIELD: + /* + * Create the field object, but the field buffer and index must + * be evaluated later during the execution phase + */ + status = acpi_ds_create_buffer_field(op, walk_state); + break; + + case AML_TYPE_NAMED_FIELD: + /* + * If we are executing a method, initialize the field + */ + if (walk_state->method_node) { + status = acpi_ds_init_field_objects(op, walk_state); + } + + switch (op->common.aml_opcode) { + case AML_INDEX_FIELD_OP: + + status = + acpi_ds_create_index_field(op, + (acpi_handle) arg-> + common.node, walk_state); + break; + + case AML_BANK_FIELD_OP: + + status = + acpi_ds_create_bank_field(op, arg->common.node, + walk_state); + break; + + case AML_FIELD_OP: + + status = + acpi_ds_create_field(op, arg->common.node, + walk_state); + break; + + default: + /* All NAMED_FIELD opcodes must be handled above */ + break; + } + break; + + case AML_TYPE_NAMED_SIMPLE: + + status = acpi_ds_create_operands(walk_state, arg); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + + switch (op->common.aml_opcode) { + case AML_PROCESSOR_OP: + + status = acpi_ex_create_processor(walk_state); + break; + + case AML_POWER_RES_OP: + + status = acpi_ex_create_power_resource(walk_state); + break; + + case AML_MUTEX_OP: + + status = acpi_ex_create_mutex(walk_state); + break; + + case AML_EVENT_OP: + + status = acpi_ex_create_event(walk_state); + break; + + case AML_ALIAS_OP: + + status = acpi_ex_create_alias(walk_state); + break; + + default: + /* Unknown opcode */ + + status = AE_OK; + goto cleanup; + } + + /* Delete operands */ + + for (i = 1; i < walk_state->num_operands; i++) { + acpi_ut_remove_reference(walk_state->operands[i]); + walk_state->operands[i] = NULL; + } + + break; +#endif /* ACPI_NO_METHOD_EXECUTION */ + + case AML_TYPE_NAMED_COMPLEX: + + switch (op->common.aml_opcode) { +#ifndef ACPI_NO_METHOD_EXECUTION + case AML_REGION_OP: + case AML_DATA_REGION_OP: + + if (op->common.aml_opcode == AML_REGION_OP) { + region_space = (acpi_adr_space_type) + ((op->common.value.arg)->common.value. + integer); + } else { + region_space = REGION_DATA_TABLE; + } + + /* + * The op_region is not fully parsed at this time. The only valid + * argument is the space_id. (We must save the address of the + * AML of the address and length operands) + * + * If we have a valid region, initialize it. The namespace is + * unlocked at this point. + * + * Need to unlock interpreter if it is locked (if we are running + * a control method), in order to allow _REG methods to be run + * during acpi_ev_initialize_region. + */ + if (walk_state->method_node) { + /* + * Executing a method: initialize the region and unlock + * the interpreter + */ + status = + acpi_ex_create_region(op->named.data, + op->named.length, + region_space, + walk_state); + if (ACPI_FAILURE(status)) { + return (status); + } + + acpi_ex_exit_interpreter(); + } + + status = + acpi_ev_initialize_region + (acpi_ns_get_attached_object(node), FALSE); + if (walk_state->method_node) { + acpi_ex_enter_interpreter(); + } + + if (ACPI_FAILURE(status)) { + /* + * If AE_NOT_EXIST is returned, it is not fatal + * because many regions get created before a handler + * is installed for said region. + */ + if (AE_NOT_EXIST == status) { + status = AE_OK; + } + } + break; + + case AML_NAME_OP: + + status = acpi_ds_create_node(walk_state, node, op); + break; + + case AML_METHOD_OP: + /* + * method_op pkg_length name_string method_flags term_list + * + * Note: We must create the method node/object pair as soon as we + * see the method declaration. This allows later pass1 parsing + * of invocations of the method (need to know the number of + * arguments.) + */ + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "LOADING-Method: State=%p Op=%p NamedObj=%p\n", + walk_state, op, op->named.node)); + + if (!acpi_ns_get_attached_object(op->named.node)) { + walk_state->operands[0] = + ACPI_CAST_PTR(void, op->named.node); + walk_state->num_operands = 1; + + status = + acpi_ds_create_operands(walk_state, + op->common.value. + arg); + if (ACPI_SUCCESS(status)) { + status = + acpi_ex_create_method(op->named. + data, + op->named. + length, + walk_state); + } + walk_state->operands[0] = NULL; + walk_state->num_operands = 0; + + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } + break; + +#endif /* ACPI_NO_METHOD_EXECUTION */ + + default: + /* All NAMED_COMPLEX opcodes must be handled above */ + break; + } + break; + + case AML_CLASS_INTERNAL: + + /* case AML_INT_NAMEPATH_OP: */ + break; + + case AML_CLASS_METHOD_CALL: + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n", + walk_state, op, node)); + + /* + * Lookup the method name and save the Node + */ + status = + acpi_ns_lookup(walk_state->scope_info, + arg->common.value.string, ACPI_TYPE_ANY, + ACPI_IMODE_LOAD_PASS2, + ACPI_NS_SEARCH_PARENT | + ACPI_NS_DONT_OPEN_SCOPE, walk_state, + &(new_node)); + if (ACPI_SUCCESS(status)) { + /* + * Make sure that what we found is indeed a method + * We didn't search for a method on purpose, to see if the name + * would resolve + */ + if (new_node->type != ACPI_TYPE_METHOD) { + status = AE_AML_OPERAND_TYPE; + } + + /* We could put the returned object (Node) on the object stack for + * later, but for now, we will put it in the "op" object that the + * parser uses, so we can get it again at the end of this scope + */ + op->common.node = new_node; + } else { + ACPI_ERROR_NAMESPACE(arg->common.value.string, status); + } + break; + + default: + break; + } + + cleanup: + + /* Remove the Node pushed at the very beginning */ + + walk_state->operands[0] = NULL; + walk_state->num_operands = 0; + return_ACPI_STATUS(status); +} -- cgit v1.2.2 From 47863b9cbec29f137b3a7718ec851be879b41137 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Feb 2011 16:11:43 +0800 Subject: ACPICA: Add support for FunctionalFixedHW in acpi_ut_get_region_name Was missing this region type. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/utdecode.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index ce91e59c449f..136a814cec69 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -179,6 +179,8 @@ char *acpi_ut_get_region_name(u8 space_id) if (space_id >= ACPI_USER_REGION_BEGIN) { return ("UserDefinedRegion"); + } else if (space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { + return ("FunctionalFixedHW"); } else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS) { return ("InvalidSpaceId"); } -- cgit v1.2.2 From ef09c4f578147464524041cbe3205bb25f900598 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 14 Feb 2011 16:13:25 +0800 Subject: ACPICA: Add mechanism to defer _REG methods for some installed handlers The memory/io/pci/dataTable regions must always be available. For any user installed handlers for these spaces, defer execution of _REG methods until acpi_enable_subsystem. This prevents any chicken/egg problems and ensures that no methods are executed until all of these regions are ready and available. Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/acpica/acglobal.h | 4 ++++ drivers/acpi/acpica/evregion.c | 2 ++ drivers/acpi/acpica/evxfregn.c | 34 ++++++++++++++++++++++++++++++++-- drivers/acpi/acpica/utglobal.c | 1 + 4 files changed, 39 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 82a1bd283db8..d69750b83b36 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -273,6 +273,10 @@ ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS]; ACPI_EXTERN u8 acpi_gbl_last_owner_id_index; ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset; +/* Initialization sequencing */ + +ACPI_EXTERN u8 acpi_gbl_reg_methods_executed; + /* Misc */ ACPI_EXTERN u32 acpi_gbl_original_mode; diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 785a5ee64585..bea7223d7a71 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -231,6 +231,8 @@ acpi_status acpi_ev_initialize_op_regions(void) } } + acpi_gbl_reg_methods_executed = TRUE; + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index eb7386763712..c85c8c45599d 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -110,9 +110,39 @@ acpi_install_address_space_handler(acpi_handle device, goto unlock_and_exit; } - /* Run all _REG methods for this address space */ + /* + * For the default space_iDs, (the IDs for which there are default region handlers + * installed) Only execute the _REG methods if the global initialization _REG + * methods have already been run (via acpi_initialize_objects). In other words, + * we will defer the execution of the _REG methods for these space_iDs until + * execution of acpi_initialize_objects. This is done because we need the handlers + * for the default spaces (mem/io/pci/table) to be installed before we can run + * any control methods (or _REG methods). There is known BIOS code that depends + * on this. + * + * For all other space_iDs, we can safely execute the _REG methods immediately. + * This means that for IDs like embedded_controller, this function should be called + * only after acpi_enable_subsystem has been called. + */ + switch (space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + case ACPI_ADR_SPACE_SYSTEM_IO: + case ACPI_ADR_SPACE_PCI_CONFIG: + case ACPI_ADR_SPACE_DATA_TABLE: + + if (acpi_gbl_reg_methods_executed) { + + /* Run all _REG methods for this address space */ + + status = acpi_ev_execute_reg_methods(node, space_id); + } + break; + + default: - status = acpi_ev_execute_reg_methods(node, space_id); + status = acpi_ev_execute_reg_methods(node, space_id); + break; + } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index fc9097821516..833a38a9c905 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -323,6 +323,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT; acpi_gbl_osi_data = 0; acpi_gbl_osi_mutex = NULL; + acpi_gbl_reg_methods_executed = FALSE; /* Hardware oriented */ -- cgit v1.2.2 From 4fdfbe8506fa236f3c4cc915b24e70f84a6f768a Mon Sep 17 00:00:00 2001 From: Durgadoss R Date: Thu, 20 Jan 2011 02:40:56 +0530 Subject: Thermal_Framework-Fix_crash_during_hwmon_unregister This patch fixes the following bug: The thermal framework creates a temp*_crit interface, only when the get_crit_temp pointer is defined. But during the _unregister_ path, without checking for the function definition, it is trying to remove the temp*_crit interface. Signed-off-by: Durgadoss R Signed-off-by: Len Brown --- drivers/thermal/thermal_sys.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 713b7ea4a607..fc6f2a5bde01 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -560,7 +560,8 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) tz->hwmon = NULL; device_remove_file(hwmon->device, &tz->temp_input.attr); - device_remove_file(hwmon->device, &tz->temp_crit.attr); + if (tz->ops->get_crit_temp) + device_remove_file(hwmon->device, &tz->temp_crit.attr); mutex_lock(&thermal_list_lock); list_del(&tz->hwmon_node); -- cgit v1.2.2 From 6430c9c12a7dbb8f60f0d8294b73b3c0bb03f64f Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 17 Feb 2011 16:33:53 +0000 Subject: ACPI: use __init where possible in processor driver Use __init for several functions, remove an unnecessary export and a stray use of __ref. Signed-off-by: Jan Beulich Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 9 ++++----- drivers/acpi/processor_driver.c | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 3c1a2fec8cda..ac77dde39199 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -19,7 +19,7 @@ #define _COMPONENT ACPI_PROCESSOR_COMPONENT ACPI_MODULE_NAME("processor_core"); -static int set_no_mwait(const struct dmi_system_id *id) +static int __init set_no_mwait(const struct dmi_system_id *id) { printk(KERN_NOTICE PREFIX "%s detected - " "disabling mwait for CPU C-states\n", id->ident); @@ -27,7 +27,7 @@ static int set_no_mwait(const struct dmi_system_id *id) return 0; } -static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = { +static struct dmi_system_id __initdata processor_idle_dmi_table[] = { { set_no_mwait, "Extensa 5220", { DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), @@ -183,7 +183,7 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) EXPORT_SYMBOL_GPL(acpi_get_cpuid); #endif -static bool processor_physically_present(acpi_handle handle) +static bool __init processor_physically_present(acpi_handle handle) { int cpuid, type; u32 acpi_id; @@ -323,9 +323,8 @@ void acpi_processor_set_pdc(acpi_handle handle) kfree(obj_list->pointer); kfree(obj_list); } -EXPORT_SYMBOL_GPL(acpi_processor_set_pdc); -static acpi_status +static acpi_status __init early_init_pdc(acpi_handle handle, u32 lvl, void *context, void **rv) { if (processor_physically_present(handle) == false) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 360a74e6add0..a4e0f1ba6040 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -635,8 +635,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) return 0; } -static void __ref acpi_processor_hotplug_notify(acpi_handle handle, - u32 event, void *data) +static void acpi_processor_hotplug_notify(acpi_handle handle, + u32 event, void *data) { struct acpi_processor *pr; struct acpi_device *device = NULL; -- cgit v1.2.2 From af10f941ab7807d8b0bb3c66e679d8a6bbbe7485 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 17 Feb 2011 16:36:24 +0000 Subject: ACPI: use __cpuinit for the acpi_processor_set_pdc() call tree Once acpi_map_lsapic() in ia64 follows how x86 treats it wrt section placement, the whole tree from acpi_processor_set_pdc() can become __cpuinit. Signed-off-by: Jan Beulich Acked-by: Tony Luck Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index ac77dde39199..25bf17da69fd 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -223,7 +223,7 @@ static bool __init processor_physically_present(acpi_handle handle) return true; } -static void acpi_set_pdc_bits(u32 *buf) +static void __cpuinit acpi_set_pdc_bits(u32 *buf) { buf[0] = ACPI_PDC_REVISION_ID; buf[1] = 1; @@ -235,7 +235,7 @@ static void acpi_set_pdc_bits(u32 *buf) arch_acpi_set_pdc_bits(buf); } -static struct acpi_object_list *acpi_processor_alloc_pdc(void) +static struct acpi_object_list *__cpuinit acpi_processor_alloc_pdc(void) { struct acpi_object_list *obj_list; union acpi_object *obj; @@ -278,7 +278,7 @@ static struct acpi_object_list *acpi_processor_alloc_pdc(void) * _PDC is required for a BIOS-OS handshake for most of the newer * ACPI processor features. */ -static int +static int __cpuinit acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) { acpi_status status = AE_OK; @@ -306,7 +306,7 @@ acpi_processor_eval_pdc(acpi_handle handle, struct acpi_object_list *pdc_in) return status; } -void acpi_processor_set_pdc(acpi_handle handle) +void __cpuinit acpi_processor_set_pdc(acpi_handle handle) { struct acpi_object_list *obj_list; -- cgit v1.2.2 From f44ad7e91dd12bed0959b3e715f4f3ab84951a59 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:14 +0530 Subject: dw_dmac: Remove compilation dependency from AVR32 and put on HAVE_CLK This driver will now be used in atleast two platforms AVR32 & ARM. And there is no actual hardware dependency of this driver over AVR32 or ARM. So this dependency can be removed altogether. Also dw_dmac driver uses clk framework and must have compilation dependency on HAVE_CLK Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 76f6472ba315..d700895cb40f 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -82,7 +82,7 @@ config INTEL_IOP_ADMA config DW_DMAC tristate "Synopsys DesignWare AHB DMA support" - depends on AVR32 + depends on HAVE_CLK select DMA_ENGINE default y if CPU_AT32AP7000 help -- cgit v1.2.2 From cb689a706d17ef19a61735670ded60466dd015fa Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:15 +0530 Subject: dw_dmac: Replace module_init() with subsys_initcall() In some cases users of dw_dmac are initialized before dw_dmac, and if they try to use dw_dmac, they simply fail. So its better we register init() routine of driver using subsys_initcall() instead of module_init(), so that dma driver is available at the earliest possible. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 08dab3badad2..064a1830a76b 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1455,7 +1455,7 @@ static int __init dw_init(void) { return platform_driver_probe(&dw_driver, dw_probe); } -module_init(dw_init); +subsys_initcall(dw_init); static void __exit dw_exit(void) { -- cgit v1.2.2 From f336e42f73d93b74fd21bf9176ee6c7ab8b195c5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:16 +0530 Subject: dw_dmac: Move single descriptor from dwc->queue to dwc->active_list in dwc_complete_all dwc_complete_all and other routines was removing all descriptors from dwc->queue and pushing them to dwc->active_list. Only one was required to be removed. Also we are calling dwc_dostart, once list is fixed. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 064a1830a76b..942b50f57f21 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -87,11 +87,6 @@ static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc) return list_entry(dwc->active_list.next, struct dw_desc, desc_node); } -static struct dw_desc *dwc_first_queued(struct dw_dma_chan *dwc) -{ - return list_entry(dwc->queue.next, struct dw_desc, desc_node); -} - static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc) { struct dw_desc *desc, *_desc; @@ -262,10 +257,11 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc) * Submit queued descriptors ASAP, i.e. before we go through * the completed ones. */ - if (!list_empty(&dwc->queue)) - dwc_dostart(dwc, dwc_first_queued(dwc)); list_splice_init(&dwc->active_list, &list); - list_splice_init(&dwc->queue, &dwc->active_list); + if (!list_empty(&dwc->queue)) { + list_move(dwc->queue.next, &dwc->active_list); + dwc_dostart(dwc, dwc_first_active(dwc)); + } list_for_each_entry_safe(desc, _desc, &list, desc_node) dwc_descriptor_complete(dwc, desc); @@ -325,8 +321,8 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) cpu_relax(); if (!list_empty(&dwc->queue)) { - dwc_dostart(dwc, dwc_first_queued(dwc)); - list_splice_init(&dwc->queue, &dwc->active_list); + list_move(dwc->queue.next, &dwc->active_list); + dwc_dostart(dwc, dwc_first_active(dwc)); } } @@ -352,7 +348,7 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc) */ bad_desc = dwc_first_active(dwc); list_del_init(&bad_desc->desc_node); - list_splice_init(&dwc->queue, dwc->active_list.prev); + list_move(dwc->queue.next, dwc->active_list.prev); /* Clear the error flag and try to restart the controller */ dma_writel(dw, CLEAR.ERROR, dwc->mask); @@ -547,8 +543,8 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx) if (list_empty(&dwc->active_list)) { dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n", desc->txd.cookie); - dwc_dostart(dwc, desc); list_add_tail(&desc->desc_node, &dwc->active_list); + dwc_dostart(dwc, dwc_first_active(dwc)); } else { dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n", desc->txd.cookie); -- cgit v1.2.2 From 569432efa7975f5795efb8142134f5a098942381 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:17 +0530 Subject: dw_dmac: Calling dwc_scan_descriptors from dwc_tx_status() after taking lock Lock must be taken before calling dwc_scan_descriptors, as this may access/modify shared data and queues. dwc_tx_status wasn't taking lock before calling this routine. This patch add code that takes lock before calling dwc_scan_descriptors. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 942b50f57f21..2b0d5e99ae71 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -836,7 +836,9 @@ dwc_tx_status(struct dma_chan *chan, ret = dma_async_is_complete(cookie, last_complete, last_used); if (ret != DMA_SUCCESS) { + spin_lock_bh(&dwc->lock); dwc_scan_descriptors(to_dw_dma(chan->device), dwc); + spin_unlock_bh(&dwc->lock); last_complete = dwc->completed; last_used = chan->cookie; -- cgit v1.2.2 From a02274564dd78f7edde3c9ff197ed44f2f8a5a81 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:18 +0530 Subject: dw_dmac: Adding support for 64 bit access width for memcpy xfers Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 2b0d5e99ae71..e5d97bf9264a 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -583,7 +583,9 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, * We can be a lot more clever here, but this should take care * of the most common optimization. */ - if (!((src | dest | len) & 3)) + if (!((src | dest | len) & 7)) + src_width = dst_width = 3; + else if (!((src | dest | len) & 3)) src_width = dst_width = 2; else if (!((src | dest | len) & 1)) src_width = dst_width = 1; -- cgit v1.2.2 From 418e74070662e1ae7d9bb5202f773d35c9a7f05e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 4 Mar 2011 15:42:50 +0530 Subject: dw_dmac: Change value of DWC_MAX_COUNT to 4095. Every descriptor can transfer a maximum count of 4095 (12 bits, in control reg), So we must have DWC_MAX_COUNT as 4095 instead of 2048. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index e5d97bf9264a..711ebe954f5b 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -47,14 +47,13 @@ /* * This is configuration-dependent and usually a funny size like 4095. - * Let's round it down to the nearest power of two. * * Note that this is a transfer count, i.e. if we transfer 32-bit - * words, we can do 8192 bytes per descriptor. + * words, we can do 16380 bytes per descriptor. * * This parameter is also system-specific. */ -#define DWC_MAX_COUNT 2048U +#define DWC_MAX_COUNT 4095U /* * Number of descriptors to allocate for each channel. This should be -- cgit v1.2.2 From e518076ef8cb56adb558ff56ad5bfa0cd9f3abd9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:20 +0530 Subject: dw_dmac: Mark all tx_descriptors with DMA_CRTL_ACK after xfer finish dwc_desc_get checks all descriptors for DMA_CTRL_ACK before allocating them for transfers. And descriptors are not marked with DMA_CRTL_ACK after transfer finishes. Thus descriptor once used is not usable again. This patch marks descriptors with DMA_CRTL_ACK after dma xfer finishes Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 711ebe954f5b..6ab440e532bf 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -198,6 +198,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc) dma_async_tx_callback callback; void *param; struct dma_async_tx_descriptor *txd = &desc->txd; + struct dw_desc *child; dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie); @@ -206,6 +207,12 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc) param = txd->callback_param; dwc_sync_desc_for_cpu(dwc, desc); + + /* async_tx_ack */ + list_for_each_entry(child, &desc->tx_list, desc_node) + async_tx_ack(&child->txd); + async_tx_ack(&desc->txd); + list_splice_init(&desc->tx_list, &dwc->free_list); list_move(&desc->desc_node, &dwc->free_list); -- cgit v1.2.2 From b0c3130d69bda5cd91aa3b3f08e7878df49fde69 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:21 +0530 Subject: dw_dmac: Pass Channel Allocation Order from platform_data In SPEAr Platform channels 4-7 have more Fifo depth. So we must get better channel first. This patch introduces concept of channel allocation order in dw_dmac. If user doesn't pass anything or 0, than normal (ascending) channel allocation will follow, else channels will be allocated in descending order. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 6ab440e532bf..f413e123405a 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1319,7 +1319,11 @@ static int __init dw_probe(struct platform_device *pdev) dwc->chan.device = &dw->dma; dwc->chan.cookie = dwc->completed = 1; dwc->chan.chan_id = i; - list_add_tail(&dwc->chan.device_node, &dw->dma.channels); + if (pdata->chan_allocation_order == CHAN_ALLOCATION_ASCENDING) + list_add_tail(&dwc->chan.device_node, + &dw->dma.channels); + else + list_add(&dwc->chan.device_node, &dw->dma.channels); dwc->ch_regs = &__dw_regs(dw)->CHAN[i]; spin_lock_init(&dwc->lock); -- cgit v1.2.2 From 93317e8e35b77633d589fe0e132291195757d785 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:22 +0530 Subject: dw_dmac: Pass Channel Priority from platform_data In Synopsys designware, channel priority is programmable. This patch adds support for passing channel priority through platform data. By default Ascending channel priority will be followed, i.e. channel 0 will get highest priority and channel 7 will get lowest. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 11 ++++++++++- drivers/dma/dw_dmac_regs.h | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index f413e123405a..318a342fc7ec 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -901,8 +901,11 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan) BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); cfghi = dws->cfg_hi; - cfglo = dws->cfg_lo; + cfglo = dws->cfg_lo & ~DWC_CFGL_CH_PRIOR_MASK; } + + cfglo |= DWC_CFGL_CH_PRIOR(dwc->priority); + channel_writel(dwc, CFG_LO, cfglo); channel_writel(dwc, CFG_HI, cfghi); @@ -1325,6 +1328,12 @@ static int __init dw_probe(struct platform_device *pdev) else list_add(&dwc->chan.device_node, &dw->dma.channels); + /* 7 is highest priority & 0 is lowest. */ + if (pdata->chan_priority == CHAN_PRIORITY_ASCENDING) + dwc->priority = 7 - i; + else + dwc->priority = i; + dwc->ch_regs = &__dw_regs(dw)->CHAN[i]; spin_lock_init(&dwc->lock); dwc->mask = 1 << i; diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index d9a939f67f46..6a8e6d35f359 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -101,6 +101,8 @@ struct dw_dma_regs { #define DWC_CTLH_BLOCK_TS_MASK 0x00000fff /* Bitfields in CFG_LO. Platform-configurable bits are in */ +#define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */ +#define DWC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */ #define DWC_CFGL_CH_SUSP (1 << 8) /* pause xfer */ #define DWC_CFGL_FIFO_EMPTY (1 << 9) /* pause xfer */ #define DWC_CFGL_HS_DST (1 << 10) /* handshake w/dst */ @@ -134,6 +136,7 @@ struct dw_dma_chan { struct dma_chan chan; void __iomem *ch_regs; u8 mask; + u8 priority; spinlock_t lock; -- cgit v1.2.2 From ee66509d7f354eecb45ac99f21ea6aa8650dea7e Mon Sep 17 00:00:00 2001 From: Viresh KUMAR Date: Fri, 4 Mar 2011 15:42:51 +0530 Subject: dw_dmac: Allow src/dst msize & flow controller to be configured at runtime Msize or Burst Size is peripheral dependent in case of prep_slave_sg and cyclic_prep transfers, and in case of memcpy transfers it is platform dependent. So msize configuration must come from platform data. Also some peripherals (ex: JPEG), need to be flow controller for dma transfers, so this information in case of slave_sg & cyclic_prep transfers must come from platform data. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 14 ++++++++------ drivers/dma/dw_dmac_regs.h | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 318a342fc7ec..90ea08a53d62 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -36,9 +36,11 @@ struct dw_dma_slave *__slave = (private); \ int dms = __slave ? __slave->dst_master : 0; \ int sms = __slave ? __slave->src_master : 1; \ + u8 smsize = __slave ? __slave->src_msize : 0; \ + u8 dmsize = __slave ? __slave->dst_msize : 0; \ \ - (DWC_CTLL_DST_MSIZE(0) \ - | DWC_CTLL_SRC_MSIZE(0) \ + (DWC_CTLL_DST_MSIZE(dmsize) \ + | DWC_CTLL_SRC_MSIZE(smsize) \ | DWC_CTLL_LLP_D_EN \ | DWC_CTLL_LLP_S_EN \ | DWC_CTLL_DMS(dms) \ @@ -683,7 +685,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | DWC_CTLL_DST_WIDTH(reg_width) | DWC_CTLL_DST_FIX | DWC_CTLL_SRC_INC - | DWC_CTLL_FC_M2P); + | DWC_CTLL_FC(dws->fc)); reg = dws->tx_reg; for_each_sg(sgl, sg, sg_len, i) { struct dw_desc *desc; @@ -728,7 +730,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | DWC_CTLL_SRC_WIDTH(reg_width) | DWC_CTLL_DST_INC | DWC_CTLL_SRC_FIX - | DWC_CTLL_FC_P2M); + | DWC_CTLL_FC(dws->fc)); reg = dws->rx_reg; for_each_sg(sgl, sg, sg_len, i) { @@ -1146,7 +1148,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, | DWC_CTLL_SRC_WIDTH(reg_width) | DWC_CTLL_DST_FIX | DWC_CTLL_SRC_INC - | DWC_CTLL_FC_M2P + | DWC_CTLL_FC(dws->fc) | DWC_CTLL_INT_EN); break; case DMA_FROM_DEVICE: @@ -1157,7 +1159,7 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan, | DWC_CTLL_DST_WIDTH(reg_width) | DWC_CTLL_DST_INC | DWC_CTLL_SRC_FIX - | DWC_CTLL_FC_P2M + | DWC_CTLL_FC(dws->fc) | DWC_CTLL_INT_EN); break; default: diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index 6a8e6d35f359..9a32964bf795 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -86,6 +86,7 @@ struct dw_dma_regs { #define DWC_CTLL_SRC_MSIZE(n) ((n)<<14) #define DWC_CTLL_S_GATH_EN (1 << 17) /* src gather, !FIX */ #define DWC_CTLL_D_SCAT_EN (1 << 18) /* dst scatter, !FIX */ +#define DWC_CTLL_FC(n) ((n) << 20) #define DWC_CTLL_FC_M2M (0 << 20) /* mem-to-mem */ #define DWC_CTLL_FC_M2P (1 << 20) /* mem-to-periph */ #define DWC_CTLL_FC_P2M (2 << 20) /* periph-to-mem */ -- cgit v1.2.2 From e51dc53b8c7fa2d9ac4ef8f317f5dfe07a79e65a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Mar 2011 15:47:25 +0530 Subject: dw_dmac: Setting Default Burst length for transfers as 16. This patch sets default Burst length for all transfer to 16. This will enhance performance when user doesn't have any chan->private data. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 90ea08a53d62..9c25c7d099e4 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -36,8 +36,8 @@ struct dw_dma_slave *__slave = (private); \ int dms = __slave ? __slave->dst_master : 0; \ int sms = __slave ? __slave->src_master : 1; \ - u8 smsize = __slave ? __slave->src_msize : 0; \ - u8 dmsize = __slave ? __slave->dst_msize : 0; \ + u8 smsize = __slave ? __slave->src_msize : DW_DMA_MSIZE_16; \ + u8 dmsize = __slave ? __slave->dst_msize : DW_DMA_MSIZE_16; \ \ (DWC_CTLL_DST_MSIZE(dmsize) \ | DWC_CTLL_SRC_MSIZE(smsize) \ -- cgit v1.2.2 From 29782da5f0206335e2325508ba4fee0d624ddab6 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 4 Mar 2011 14:58:32 +0530 Subject: dmaengine/dw_dmac fix: use readl & writel instead of __raw_readl & __raw_writel On ARMv7 cores, device memory mapped as Normal Non-cacheable, may not guarantee ordered access causing failures in device drivers that do not use the mandatory memory barriers. readl & writel versions contain necessary memory barriers for this. commit 79f64dbf68c8a9779a7e9a25e0a9f0217a25b57a: "ARM: 6273/1: Add barriers to the I/O accessors if ARM_DMA_MEM_BUFFERABLE" can be referred for more information on this. Signed-off-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw_dmac_regs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw_dmac_regs.h index 9a32964bf795..720f821527f8 100644 --- a/drivers/dma/dw_dmac_regs.h +++ b/drivers/dma/dw_dmac_regs.h @@ -159,9 +159,9 @@ __dwc_regs(struct dw_dma_chan *dwc) } #define channel_readl(dwc, name) \ - __raw_readl(&(__dwc_regs(dwc)->name)) + readl(&(__dwc_regs(dwc)->name)) #define channel_writel(dwc, name, val) \ - __raw_writel((val), &(__dwc_regs(dwc)->name)) + writel((val), &(__dwc_regs(dwc)->name)) static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan) { @@ -185,9 +185,9 @@ static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw) } #define dma_readl(dw, name) \ - __raw_readl(&(__dw_regs(dw)->name)) + readl(&(__dw_regs(dw)->name)) #define dma_writel(dw, name, val) \ - __raw_writel((val), &(__dw_regs(dw)->name)) + writel((val), &(__dw_regs(dw)->name)) #define channel_set_bit(dw, reg, mask) \ dma_writel(dw, reg, ((mask) << 8) | (mask)) -- cgit v1.2.2 From 0b863b333f529c7ddd8bee58e6696a7254417a05 Mon Sep 17 00:00:00 2001 From: Rakib Mullick Date: Sun, 6 Mar 2011 17:26:10 +0600 Subject: drivers, pch_dma: Fix warning when CONFIG_PM=n. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_PM=n, we get the following warning: drivers/dma/pch_dma.c:741: warning: ‘pch_dma_suspend’ defined but not used drivers/dma/pch_dma.c:755: warning: ‘pch_dma_resume’ defined but not used To fix it, wrap pch_dma_{suspend,resume} and pch_dma_{save,restore}_regs functions with CONFIG_PM. Signed-off-by: Rakib Mullick Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index b1dfba7e37b4..8d8fef1480a9 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -693,6 +693,7 @@ static irqreturn_t pd_irq(int irq, void *devid) return ret; } +#ifdef CONFIG_PM static void pch_dma_save_regs(struct pch_dma *pd) { struct pch_dma_chan *pd_chan; @@ -770,6 +771,7 @@ static int pch_dma_resume(struct pci_dev *pdev) return 0; } +#endif static int __devinit pch_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) -- cgit v1.2.2 From d47effe1be0c4fc983306a9c704632e3a087eed8 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Tue, 1 Mar 2011 17:06:37 +0530 Subject: vhost: Cleanup vhost.c and net.c Minor cleanup of vhost.c and net.c to match coding style. Signed-off-by: Krishna Kumar Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 19 +++++++++++------- drivers/vhost/vhost.c | 53 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index f616cefc95ba..59dad9fe52dd 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -60,6 +60,7 @@ static int move_iovec_hdr(struct iovec *from, struct iovec *to, { int seg = 0; size_t size; + while (len && seg < iov_count) { size = min(from->iov_len, len); to->iov_base = from->iov_base; @@ -79,6 +80,7 @@ static void copy_iovec_hdr(const struct iovec *from, struct iovec *to, { int seg = 0; size_t size; + while (len && seg < iovcount) { size = min(from->iov_len, len); to->iov_base = from->iov_base; @@ -296,17 +298,16 @@ static void handle_rx_big(struct vhost_net *net) .msg_iov = vq->iov, .msg_flags = MSG_DONTWAIT, }; - struct virtio_net_hdr hdr = { .flags = 0, .gso_type = VIRTIO_NET_HDR_GSO_NONE }; - size_t len, total_len = 0; int err; size_t hdr_size; /* TODO: check that we are running from vhost_worker? */ struct socket *sock = rcu_dereference_check(vq->private_data, 1); + if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) return; @@ -405,18 +406,17 @@ static void handle_rx_mergeable(struct vhost_net *net) .msg_iov = vq->iov, .msg_flags = MSG_DONTWAIT, }; - struct virtio_net_hdr_mrg_rxbuf hdr = { .hdr.flags = 0, .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE }; - size_t total_len = 0; int err, headcount; size_t vhost_hlen, sock_hlen; size_t vhost_len, sock_len; /* TODO: check that we are running from vhost_worker? */ struct socket *sock = rcu_dereference_check(vq->private_data, 1); + if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) return; @@ -654,6 +654,7 @@ static struct socket *get_raw_socket(int fd) } uaddr; int uaddr_len = sizeof uaddr, r; struct socket *sock = sockfd_lookup(fd, &r); + if (!sock) return ERR_PTR(-ENOTSOCK); @@ -682,6 +683,7 @@ static struct socket *get_tap_socket(int fd) { struct file *file = fget(fd); struct socket *sock; + if (!file) return ERR_PTR(-EBADF); sock = tun_get_socket(file); @@ -696,6 +698,7 @@ static struct socket *get_tap_socket(int fd) static struct socket *get_socket(int fd) { struct socket *sock; + /* special case to disable backend */ if (fd == -1) return NULL; @@ -741,9 +744,9 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd) oldsock = rcu_dereference_protected(vq->private_data, lockdep_is_held(&vq->mutex)); if (sock != oldsock) { - vhost_net_disable_vq(n, vq); - rcu_assign_pointer(vq->private_data, sock); - vhost_net_enable_vq(n, vq); + vhost_net_disable_vq(n, vq); + rcu_assign_pointer(vq->private_data, sock); + vhost_net_enable_vq(n, vq); } mutex_unlock(&vq->mutex); @@ -768,6 +771,7 @@ static long vhost_net_reset_owner(struct vhost_net *n) struct socket *tx_sock = NULL; struct socket *rx_sock = NULL; long err; + mutex_lock(&n->dev.mutex); err = vhost_dev_check_owner(&n->dev); if (err) @@ -829,6 +833,7 @@ static long vhost_net_ioctl(struct file *f, unsigned int ioctl, struct vhost_vring_file backend; u64 features; int r; + switch (ioctl) { case VHOST_NET_SET_BACKEND: if (copy_from_user(&backend, argp, sizeof backend)) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index ade0568c07a4..b0cc7f8ca4de 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -41,8 +41,8 @@ static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, poll_table *pt) { struct vhost_poll *poll; - poll = container_of(pt, struct vhost_poll, table); + poll = container_of(pt, struct vhost_poll, table); poll->wqh = wqh; add_wait_queue(wqh, &poll->wait); } @@ -85,6 +85,7 @@ void vhost_poll_init(struct vhost_poll *poll, vhost_work_fn_t fn, void vhost_poll_start(struct vhost_poll *poll, struct file *file) { unsigned long mask; + mask = file->f_op->poll(file, &poll->table); if (mask) vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask); @@ -101,6 +102,7 @@ static bool vhost_work_seq_done(struct vhost_dev *dev, struct vhost_work *work, unsigned seq) { int left; + spin_lock_irq(&dev->work_lock); left = seq - work->done_seq; spin_unlock_irq(&dev->work_lock); @@ -222,6 +224,7 @@ static int vhost_worker(void *data) static long vhost_dev_alloc_iovecs(struct vhost_dev *dev) { int i; + for (i = 0; i < dev->nvqs; ++i) { dev->vqs[i].indirect = kmalloc(sizeof *dev->vqs[i].indirect * UIO_MAXIOV, GFP_KERNEL); @@ -235,6 +238,7 @@ static long vhost_dev_alloc_iovecs(struct vhost_dev *dev) goto err_nomem; } return 0; + err_nomem: for (; i >= 0; --i) { kfree(dev->vqs[i].indirect); @@ -247,6 +251,7 @@ err_nomem: static void vhost_dev_free_iovecs(struct vhost_dev *dev) { int i; + for (i = 0; i < dev->nvqs; ++i) { kfree(dev->vqs[i].indirect); dev->vqs[i].indirect = NULL; @@ -296,26 +301,28 @@ long vhost_dev_check_owner(struct vhost_dev *dev) } struct vhost_attach_cgroups_struct { - struct vhost_work work; - struct task_struct *owner; - int ret; + struct vhost_work work; + struct task_struct *owner; + int ret; }; static void vhost_attach_cgroups_work(struct vhost_work *work) { - struct vhost_attach_cgroups_struct *s; - s = container_of(work, struct vhost_attach_cgroups_struct, work); - s->ret = cgroup_attach_task_all(s->owner, current); + struct vhost_attach_cgroups_struct *s; + + s = container_of(work, struct vhost_attach_cgroups_struct, work); + s->ret = cgroup_attach_task_all(s->owner, current); } static int vhost_attach_cgroups(struct vhost_dev *dev) { - struct vhost_attach_cgroups_struct attach; - attach.owner = current; - vhost_work_init(&attach.work, vhost_attach_cgroups_work); - vhost_work_queue(dev, &attach.work); - vhost_work_flush(dev, &attach.work); - return attach.ret; + struct vhost_attach_cgroups_struct attach; + + attach.owner = current; + vhost_work_init(&attach.work, vhost_attach_cgroups_work); + vhost_work_queue(dev, &attach.work); + vhost_work_flush(dev, &attach.work); + return attach.ret; } /* Caller should have device mutex */ @@ -323,11 +330,13 @@ static long vhost_dev_set_owner(struct vhost_dev *dev) { struct task_struct *worker; int err; + /* Is there an owner already? */ if (dev->mm) { err = -EBUSY; goto err_mm; } + /* No owner, become one */ dev->mm = get_task_mm(current); worker = kthread_create(vhost_worker, dev, "vhost-%d", current->pid); @@ -380,6 +389,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev) void vhost_dev_cleanup(struct vhost_dev *dev) { int i; + for (i = 0; i < dev->nvqs; ++i) { if (dev->vqs[i].kick && dev->vqs[i].handle_kick) { vhost_poll_stop(&dev->vqs[i].poll); @@ -421,6 +431,7 @@ void vhost_dev_cleanup(struct vhost_dev *dev) static int log_access_ok(void __user *log_base, u64 addr, unsigned long sz) { u64 a = addr / VHOST_PAGE_SIZE / 8; + /* Make sure 64 bit math will not overflow. */ if (a > ULONG_MAX - (unsigned long)log_base || a + (unsigned long)log_base > ULONG_MAX) @@ -461,6 +472,7 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem, int log_all) { int i; + for (i = 0; i < d->nvqs; ++i) { int ok; mutex_lock(&d->vqs[i].mutex); @@ -527,6 +539,7 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) { struct vhost_memory mem, *newmem, *oldmem; unsigned long size = offsetof(struct vhost_memory, regions); + if (copy_from_user(&mem, m, size)) return -EFAULT; if (mem.padding) @@ -544,7 +557,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m) return -EFAULT; } - if (!memory_access_ok(d, newmem, vhost_has_feature(d, VHOST_F_LOG_ALL))) { + if (!memory_access_ok(d, newmem, + vhost_has_feature(d, VHOST_F_LOG_ALL))) { kfree(newmem); return -EFAULT; } @@ -560,6 +574,7 @@ static int init_used(struct vhost_virtqueue *vq, struct vring_used __user *used) { int r = put_user(vq->used_flags, &used->flags); + if (r) return r; return get_user(vq->last_used_idx, &used->idx); @@ -849,6 +864,7 @@ static const struct vhost_memory_region *find_region(struct vhost_memory *mem, { struct vhost_memory_region *reg; int i; + /* linear search is not brilliant, but we really have on the order of 6 * regions in practice */ for (i = 0; i < mem->nregions; ++i) { @@ -871,6 +887,7 @@ static int set_bit_to_user(int nr, void __user *addr) void *base; int bit = nr + (log % PAGE_SIZE) * 8; int r; + r = get_user_pages_fast(log, 1, 1, &page); if (r < 0) return r; @@ -888,6 +905,7 @@ static int log_write(void __user *log_base, { u64 write_page = write_address / VHOST_PAGE_SIZE; int r; + if (!write_length) return 0; write_length += write_address % VHOST_PAGE_SIZE; @@ -1037,8 +1055,8 @@ static int get_indirect(struct vhost_dev *dev, struct vhost_virtqueue *vq, i, count); return -EINVAL; } - if (unlikely(memcpy_fromiovec((unsigned char *)&desc, vq->indirect, - sizeof desc))) { + if (unlikely(memcpy_fromiovec((unsigned char *)&desc, + vq->indirect, sizeof desc))) { vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n", i, (size_t)indirect->addr + i * sizeof desc); return -EINVAL; @@ -1317,6 +1335,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads, void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq) { __u16 flags; + /* Flush out used index updates. This is paired * with the barrier that the Guest executes when enabling * interrupts. */ @@ -1361,6 +1380,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq) { u16 avail_idx; int r; + if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY)) return false; vq->used_flags &= ~VRING_USED_F_NO_NOTIFY; @@ -1387,6 +1407,7 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq) void vhost_disable_notify(struct vhost_virtqueue *vq) { int r; + if (vq->used_flags & VRING_USED_F_NO_NOTIFY) return; vq->used_flags |= VRING_USED_F_NO_NOTIFY; -- cgit v1.2.2 From fcc042a2806064ffcaed7a0c5cb710eca0e99108 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 6 Mar 2011 13:33:49 +0200 Subject: vhost: copy_from_user -> __copy_from_user copy_from_user is pretty high on perf top profile, replacing it with __copy_from_user helps. It's also safe because we do access_ok checks during setup. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index b0cc7f8ca4de..2ab291241635 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1171,7 +1171,7 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq, i, vq->num, head); return -EINVAL; } - ret = copy_from_user(&desc, vq->desc + i, sizeof desc); + ret = __copy_from_user(&desc, vq->desc + i, sizeof desc); if (unlikely(ret)) { vq_err(vq, "Failed to get descriptor: idx %d addr %p\n", i, vq->desc + i); -- cgit v1.2.2 From 5b03a1b140e13a28ff6be1526892a9dc538ddef6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:27 +0100 Subject: ide: Convert to bdops->check_events() Convert ->media_changed() to the new ->check_events() method. The conversion is mostly mechanical. The only notable change is that cdrom now doesn't generate any event if @slot_nr isn't CDSL_CURRENT. It used to return -EINVAL which would be treated as media changed. As media changer isn't supported anyway, this doesn't make any difference. This makes ide emit the standard disk events and allows kernel event polling. Currently, only MEDIA_CHANGE event is implemented. Adding support for EJECT_REQUEST shouldn't be difficult; however, given that ide driver is already deprecated, it probably is best to leave it alone. Signed-off-by: Tejun Heo Acked-by: Jens Axboe Cc: Kay Sievers Cc: "David S. Miller" Cc: linux-ide@vger.kernel.org --- drivers/ide/ide-cd.c | 10 ++++++---- drivers/ide/ide-cd.h | 3 ++- drivers/ide/ide-cd_ioctl.c | 8 ++++---- drivers/ide/ide-gd.c | 14 ++++++++------ 4 files changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 0c73fe39a236..a2e29099ee0c 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1177,7 +1177,7 @@ static struct cdrom_device_ops ide_cdrom_dops = { .open = ide_cdrom_open_real, .release = ide_cdrom_release_real, .drive_status = ide_cdrom_drive_status, - .media_changed = ide_cdrom_check_media_change_real, + .check_events = ide_cdrom_check_events_real, .tray_move = ide_cdrom_tray_move, .lock_door = ide_cdrom_lock_door, .select_speed = ide_cdrom_select_speed, @@ -1702,10 +1702,11 @@ static int idecd_ioctl(struct block_device *bdev, fmode_t mode, } -static int idecd_media_changed(struct gendisk *disk) +static unsigned int idecd_check_events(struct gendisk *disk, + unsigned int clearing) { struct cdrom_info *info = ide_drv_g(disk, cdrom_info); - return cdrom_media_changed(&info->devinfo); + return cdrom_check_events(&info->devinfo, clearing); } static int idecd_revalidate_disk(struct gendisk *disk) @@ -1723,7 +1724,7 @@ static const struct block_device_operations idecd_ops = { .open = idecd_open, .release = idecd_release, .ioctl = idecd_ioctl, - .media_changed = idecd_media_changed, + .check_events = idecd_check_events, .revalidate_disk = idecd_revalidate_disk }; @@ -1790,6 +1791,7 @@ static int ide_cd_probe(ide_drive_t *drive) ide_cd_read_toc(drive, &sense); g->fops = &idecd_ops; g->flags |= GENHD_FL_REMOVABLE; + g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h index 93a3cf1b0f3f..1efc936f5b66 100644 --- a/drivers/ide/ide-cd.h +++ b/drivers/ide/ide-cd.h @@ -111,7 +111,8 @@ int cdrom_check_status(ide_drive_t *, struct request_sense *); int ide_cdrom_open_real(struct cdrom_device_info *, int); void ide_cdrom_release_real(struct cdrom_device_info *); int ide_cdrom_drive_status(struct cdrom_device_info *, int); -int ide_cdrom_check_media_change_real(struct cdrom_device_info *, int); +unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *, + unsigned int clearing, int slot_nr); int ide_cdrom_tray_move(struct cdrom_device_info *, int); int ide_cdrom_lock_door(struct cdrom_device_info *, int); int ide_cdrom_select_speed(struct cdrom_device_info *, int); diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c index 766b3deeb23c..2a6bc50e8a41 100644 --- a/drivers/ide/ide-cd_ioctl.c +++ b/drivers/ide/ide-cd_ioctl.c @@ -79,8 +79,8 @@ int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr) return CDS_DRIVE_NOT_READY; } -int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi, - int slot_nr) +unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi, + unsigned int clearing, int slot_nr) { ide_drive_t *drive = cdi->handle; int retval; @@ -89,9 +89,9 @@ int ide_cdrom_check_media_change_real(struct cdrom_device_info *cdi, (void) cdrom_check_status(drive, NULL); retval = (drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED) ? 1 : 0; drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; - return retval; + return retval ? DISK_EVENT_MEDIA_CHANGE : 0; } else { - return -EINVAL; + return 0; } } diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index 35c4b43585e3..c4ffd4888939 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -285,11 +285,12 @@ static int ide_gd_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } -static int ide_gd_media_changed(struct gendisk *disk) +static unsigned int ide_gd_check_events(struct gendisk *disk, + unsigned int clearing) { struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); ide_drive_t *drive = idkp->drive; - int ret; + bool ret; /* do not scan partitions twice if this is a removable device */ if (drive->dev_flags & IDE_DFLAG_ATTACH) { @@ -297,10 +298,10 @@ static int ide_gd_media_changed(struct gendisk *disk) return 0; } - ret = !!(drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED); + ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED; drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; - return ret; + return ret ? DISK_EVENT_MEDIA_CHANGE : 0; } static void ide_gd_unlock_native_capacity(struct gendisk *disk) @@ -318,7 +319,7 @@ static int ide_gd_revalidate_disk(struct gendisk *disk) struct ide_disk_obj *idkp = ide_drv_g(disk, ide_disk_obj); ide_drive_t *drive = idkp->drive; - if (ide_gd_media_changed(disk)) + if (ide_gd_check_events(disk, 0)) drive->disk_ops->get_capacity(drive); set_capacity(disk, ide_gd_capacity(drive)); @@ -340,7 +341,7 @@ static const struct block_device_operations ide_gd_ops = { .release = ide_gd_release, .ioctl = ide_gd_ioctl, .getgeo = ide_gd_getgeo, - .media_changed = ide_gd_media_changed, + .check_events = ide_gd_check_events, .unlock_native_capacity = ide_gd_unlock_native_capacity, .revalidate_disk = ide_gd_revalidate_disk }; @@ -412,6 +413,7 @@ static int ide_gd_probe(ide_drive_t *drive) if (drive->dev_flags & IDE_DFLAG_REMOVABLE) g->flags = GENHD_FL_REMOVABLE; g->fops = &ide_gd_ops; + g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; -- cgit v1.2.2 From 1a8a74f03fcde1725ff26520220f3d21dbd8faa1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:27 +0100 Subject: floppy,{ami|ata}flop: Convert to bdops->check_events() Convert the floppy drivers from ->media_changed() to ->check_events(). Both floppy and ataflop buffer media changed state bit and clear them on revalidation and will behave correctly with kernel event polling. I can't tell how amiflop clears its event and it's possible that it may generate spurious events when polled. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers --- drivers/block/amiflop.c | 9 +++++---- drivers/block/ataflop.c | 14 ++++++++------ drivers/block/floppy.c | 10 ++++++---- 3 files changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 7888501ad9ee..5e7d3fe2c13b 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1658,12 +1658,12 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) } /* - * floppy-change is never called from an interrupt, so we can relax a bit + * check_events is never called from an interrupt, so we can relax a bit * here, sleep etc. Note that floppy-on tries to set current_DOR to point * to the desired drive, but it will probably not survive the sleep if * several floppies are used at the same time: thus the loop. */ -static int amiga_floppy_change(struct gendisk *disk) +static unsigned amiga_check_events(struct gendisk *disk, unsigned int clearing) { struct amiga_floppy_struct *p = disk->private_data; int drive = p - unit; @@ -1686,7 +1686,7 @@ static int amiga_floppy_change(struct gendisk *disk) p->dirty = 0; writepending = 0; /* if this was true before, too bad! */ writefromint = 0; - return 1; + return DISK_EVENT_MEDIA_CHANGE; } return 0; } @@ -1697,7 +1697,7 @@ static const struct block_device_operations floppy_fops = { .release = floppy_release, .ioctl = fd_ioctl, .getgeo = fd_getgeo, - .media_changed = amiga_floppy_change, + .check_events = amiga_check_events, }; static int __init fd_probe_drives(void) @@ -1736,6 +1736,7 @@ static int __init fd_probe_drives(void) disk->major = FLOPPY_MAJOR; disk->first_minor = drive; disk->fops = &floppy_fops; + disk->events = DISK_EVENT_MEDIA_CHANGE; sprintf(disk->disk_name, "fd%d", drive); disk->private_data = &unit[drive]; set_capacity(disk, 880*2); diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 605a67e40bbf..c871eae14120 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1324,23 +1324,24 @@ static void finish_fdc_done( int dummy ) * due to unrecognised disk changes. */ -static int check_floppy_change(struct gendisk *disk) +static unsigned int floppy_check_events(struct gendisk *disk, + unsigned int clearing) { struct atari_floppy_struct *p = disk->private_data; unsigned int drive = p - unit; if (test_bit (drive, &fake_change)) { /* simulated change (e.g. after formatting) */ - return 1; + return DISK_EVENT_MEDIA_CHANGE; } if (test_bit (drive, &changed_floppies)) { /* surely changed (the WP signal changed at least once) */ - return 1; + return DISK_EVENT_MEDIA_CHANGE; } if (UD.wpstat) { /* WP is on -> could be changed: to be sure, buffers should be * invalidated... */ - return 1; + return DISK_EVENT_MEDIA_CHANGE; } return 0; @@ -1570,7 +1571,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, * or the next access will revalidate - and clear UDT :-( */ - if (check_floppy_change(disk)) + if (floppy_check_events(disk, 0)) floppy_revalidate(disk); if (UD.flags & FTD_MSG) @@ -1904,7 +1905,7 @@ static const struct block_device_operations floppy_fops = { .open = floppy_unlocked_open, .release = floppy_release, .ioctl = fd_ioctl, - .media_changed = check_floppy_change, + .check_events = floppy_check_events, .revalidate_disk= floppy_revalidate, }; @@ -1963,6 +1964,7 @@ static int __init atari_floppy_init (void) unit[i].disk->first_minor = i; sprintf(unit[i].disk->disk_name, "fd%d", i); unit[i].disk->fops = &floppy_fops; + unit[i].disk->events = DISK_EVENT_MEDIA_CHANGE; unit[i].disk->private_data = &unit[i]; unit[i].disk->queue = blk_init_queue(do_fd_request, &ataflop_lock); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 77fc76f8aea9..3851dbc03e05 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3770,13 +3770,14 @@ out2: /* * Check if the disk has been changed or if a change has been faked. */ -static int check_floppy_change(struct gendisk *disk) +static unsigned int floppy_check_events(struct gendisk *disk, + unsigned int clearing) { int drive = (long)disk->private_data; if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags) || test_bit(FD_VERIFY_BIT, &UDRS->flags)) - return 1; + return DISK_EVENT_MEDIA_CHANGE; if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) { lock_fdc(drive, false); @@ -3788,7 +3789,7 @@ static int check_floppy_change(struct gendisk *disk) test_bit(FD_VERIFY_BIT, &UDRS->flags) || test_bit(drive, &fake_change) || drive_no_geom(drive)) - return 1; + return DISK_EVENT_MEDIA_CHANGE; return 0; } @@ -3898,7 +3899,7 @@ static const struct block_device_operations floppy_fops = { .release = floppy_release, .ioctl = fd_ioctl, .getgeo = fd_getgeo, - .media_changed = check_floppy_change, + .check_events = floppy_check_events, .revalidate_disk = floppy_revalidate, }; @@ -4205,6 +4206,7 @@ static int __init floppy_init(void) disks[dr]->major = FLOPPY_MAJOR; disks[dr]->first_minor = TOMINOR(dr); disks[dr]->fops = &floppy_fops; + disks[dr]->events = DISK_EVENT_MEDIA_CHANGE; sprintf(disks[dr]->disk_name, "fd%d", dr); init_timer(&motor_off_timer[dr]); -- cgit v1.2.2 From 1c27030bd21e7e2c68ef5be9f28c63778cf4b27f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: gdrom,viocd: Convert to bdops->check_events() Convert gdrom and viocd from ->media_changed() to ->check_events(). It's unclear how the conditions are cleared and it's possible that it may generate spurious events when polled. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers --- drivers/cdrom/gdrom.c | 16 ++++++++++------ drivers/cdrom/viocd.c | 17 ++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 64a21461c408..b2b034fea34e 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -395,10 +395,12 @@ static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore) return CDS_NO_INFO; } -static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore) +static unsigned int gdrom_check_events(struct cdrom_device_info *cd_info, + unsigned int clearing, int ignore) { /* check the sense key */ - return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60; + return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60 ? + DISK_EVENT_MEDIA_CHANGE : 0; } /* reset the G1 bus */ @@ -483,7 +485,7 @@ static struct cdrom_device_ops gdrom_ops = { .open = gdrom_open, .release = gdrom_release, .drive_status = gdrom_drivestatus, - .media_changed = gdrom_mediachanged, + .check_events = gdrom_check_events, .get_last_session = gdrom_get_last_session, .reset = gdrom_hardreset, .audio_ioctl = gdrom_audio_ioctl, @@ -509,9 +511,10 @@ static int gdrom_bdops_release(struct gendisk *disk, fmode_t mode) return 0; } -static int gdrom_bdops_mediachanged(struct gendisk *disk) +static unsigned int gdrom_bdops_check_events(struct gendisk *disk, + unsigned int clearing) { - return cdrom_media_changed(gd.cd_info); + return cdrom_check_events(gd.cd_info, clearing); } static int gdrom_bdops_ioctl(struct block_device *bdev, fmode_t mode, @@ -530,7 +533,7 @@ static const struct block_device_operations gdrom_bdops = { .owner = THIS_MODULE, .open = gdrom_bdops_open, .release = gdrom_bdops_release, - .media_changed = gdrom_bdops_mediachanged, + .check_events = gdrom_bdops_check_events, .ioctl = gdrom_bdops_ioctl, }; @@ -800,6 +803,7 @@ static int __devinit probe_gdrom(struct platform_device *devptr) goto probe_fail_cdrom_register; } gd.disk->fops = &gdrom_bdops; + gd.disk->events = DISK_EVENT_MEDIA_CHANGE; /* latch on to the interrupt */ err = gdrom_set_interrupt_handlers(); if (err) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index be73a9b493a6..4e874c5fa605 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -186,10 +186,11 @@ static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode, return ret; } -static int viocd_blk_media_changed(struct gendisk *disk) +static unsigned int viocd_blk_check_events(struct gendisk *disk, + unsigned int clearing) { struct disk_info *di = disk->private_data; - return cdrom_media_changed(&di->viocd_info); + return cdrom_check_events(&di->viocd_info, clearing); } static const struct block_device_operations viocd_fops = { @@ -197,7 +198,7 @@ static const struct block_device_operations viocd_fops = { .open = viocd_blk_open, .release = viocd_blk_release, .ioctl = viocd_blk_ioctl, - .media_changed = viocd_blk_media_changed, + .check_events = viocd_blk_check_events, }; static int viocd_open(struct cdrom_device_info *cdi, int purpose) @@ -320,7 +321,8 @@ static void do_viocd_request(struct request_queue *q) } } -static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr) +static unsigned int viocd_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int disc_nr) { struct viocd_waitevent we; HvLpEvent_Rc hvrc; @@ -340,7 +342,7 @@ static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr) if (hvrc != 0) { pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", (int)hvrc); - return -EIO; + return 0; } wait_for_completion(&we.com); @@ -354,7 +356,7 @@ static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr) return 0; } - return we.changed; + return we.changed ? DISK_EVENT_MEDIA_CHANGE : 0; } static int viocd_lock_door(struct cdrom_device_info *cdi, int locking) @@ -550,7 +552,7 @@ static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, static struct cdrom_device_ops viocd_dops = { .open = viocd_open, .release = viocd_release, - .media_changed = viocd_media_changed, + .check_events = viocd_check_events, .lock_door = viocd_lock_door, .generic_packet = viocd_packet, .audio_ioctl = viocd_audio_ioctl, @@ -624,6 +626,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) gendisk->queue = q; gendisk->fops = &viocd_fops; gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE; + gendisk->events = DISK_EVENT_MEDIA_CHANGE; set_capacity(gendisk, 0); gendisk->private_data = d; d->viocd_disk = gendisk; -- cgit v1.2.2 From b1b56b93f331bd61492fdb99e7986f7a528ca730 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: paride: Convert to bdops->check_events() Convert paride drivers from ->media_changed() to ->check_events(). pcd and pd buffer and clear events after reporting; however, pf unconditionally reports MEDIA_CHANGE and will generate spurious events when polled. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers Cc: Tim Waugh --- drivers/block/paride/pcd.c | 18 +++++++++++------- drivers/block/paride/pd.c | 7 ++++--- drivers/block/paride/pf.c | 10 ++++++---- 3 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 62cec6afd7ad..2f2ccf686251 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -172,7 +172,8 @@ module_param_array(drive3, int, NULL, 0); static int pcd_open(struct cdrom_device_info *cdi, int purpose); static void pcd_release(struct cdrom_device_info *cdi); static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr); -static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr); +static unsigned int pcd_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int slot_nr); static int pcd_tray_move(struct cdrom_device_info *cdi, int position); static int pcd_lock_door(struct cdrom_device_info *cdi, int lock); static int pcd_drive_reset(struct cdrom_device_info *cdi); @@ -257,10 +258,11 @@ static int pcd_block_ioctl(struct block_device *bdev, fmode_t mode, return ret; } -static int pcd_block_media_changed(struct gendisk *disk) +static unsigned int pcd_block_check_events(struct gendisk *disk, + unsigned int clearing) { struct pcd_unit *cd = disk->private_data; - return cdrom_media_changed(&cd->info); + return cdrom_check_events(&cd->info, clearing); } static const struct block_device_operations pcd_bdops = { @@ -268,14 +270,14 @@ static const struct block_device_operations pcd_bdops = { .open = pcd_block_open, .release = pcd_block_release, .ioctl = pcd_block_ioctl, - .media_changed = pcd_block_media_changed, + .check_events = pcd_block_check_events, }; static struct cdrom_device_ops pcd_dops = { .open = pcd_open, .release = pcd_release, .drive_status = pcd_drive_status, - .media_changed = pcd_media_changed, + .check_events = pcd_check_events, .tray_move = pcd_tray_move, .lock_door = pcd_lock_door, .get_mcn = pcd_get_mcn, @@ -318,6 +320,7 @@ static void pcd_init_units(void) disk->first_minor = unit; strcpy(disk->disk_name, cd->name); /* umm... */ disk->fops = &pcd_bdops; + disk->events = DISK_EVENT_MEDIA_CHANGE; } } @@ -502,13 +505,14 @@ static int pcd_packet(struct cdrom_device_info *cdi, struct packet_command *cgc) #define DBMSG(msg) ((verbose>1)?(msg):NULL) -static int pcd_media_changed(struct cdrom_device_info *cdi, int slot_nr) +static unsigned int pcd_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int slot_nr) { struct pcd_unit *cd = cdi->handle; int res = cd->changed; if (res) cd->changed = 0; - return res; + return res ? DISK_EVENT_MEDIA_CHANGE : 0; } static int pcd_lock_door(struct cdrom_device_info *cdi, int lock) diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index c0ee1558b9bb..21dfdb776869 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -794,7 +794,7 @@ static int pd_release(struct gendisk *p, fmode_t mode) return 0; } -static int pd_check_media(struct gendisk *p) +static unsigned int pd_check_events(struct gendisk *p, unsigned int clearing) { struct pd_unit *disk = p->private_data; int r; @@ -803,7 +803,7 @@ static int pd_check_media(struct gendisk *p) pd_special_command(disk, pd_media_check); r = disk->changed; disk->changed = 0; - return r; + return r ? DISK_EVENT_MEDIA_CHANGE : 0; } static int pd_revalidate(struct gendisk *p) @@ -822,7 +822,7 @@ static const struct block_device_operations pd_fops = { .release = pd_release, .ioctl = pd_ioctl, .getgeo = pd_getgeo, - .media_changed = pd_check_media, + .check_events = pd_check_events, .revalidate_disk= pd_revalidate }; @@ -837,6 +837,7 @@ static void pd_probe_drive(struct pd_unit *disk) p->fops = &pd_fops; p->major = major; p->first_minor = (disk - pd) << PD_BITS; + p->events = DISK_EVENT_MEDIA_CHANGE; disk->gd = p; p->private_data = disk; p->queue = pd_queue; diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 635f25dd9e10..7adeb1edbf43 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -243,7 +243,8 @@ static struct pf_unit units[PF_UNITS]; static int pf_identify(struct pf_unit *pf); static void pf_lock(struct pf_unit *pf, int func); static void pf_eject(struct pf_unit *pf); -static int pf_check_media(struct gendisk *disk); +static unsigned int pf_check_events(struct gendisk *disk, + unsigned int clearing); static char pf_scratch[512]; /* scratch block buffer */ @@ -270,7 +271,7 @@ static const struct block_device_operations pf_fops = { .release = pf_release, .ioctl = pf_ioctl, .getgeo = pf_getgeo, - .media_changed = pf_check_media, + .check_events = pf_check_events, }; static void __init pf_init_units(void) @@ -293,6 +294,7 @@ static void __init pf_init_units(void) disk->first_minor = unit; strcpy(disk->disk_name, pf->name); disk->fops = &pf_fops; + disk->events = DISK_EVENT_MEDIA_CHANGE; if (!(*drives[unit])[D_PRT]) pf_drive_count++; } @@ -377,9 +379,9 @@ static int pf_release(struct gendisk *disk, fmode_t mode) } -static int pf_check_media(struct gendisk *disk) +static unsigned int pf_check_events(struct gendisk *disk, unsigned int clearing) { - return 1; + return DISK_EVENT_MEDIA_CHANGE; } static inline int status_reg(struct pf_unit *pf) -- cgit v1.2.2 From 507daea2276677785ba8096d90b9e8049632fc46 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: dac960: Convert to bdops->check_events() Convert from ->media_changed() to ->check_events(). DAC960 media change notification seems to be one way (once set, never cleared) and will generate spurious events when polled once the condition triggers. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers --- drivers/block/DAC960.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 1f286ab461d3..79882104e431 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -140,13 +140,14 @@ static int DAC960_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } -static int DAC960_media_changed(struct gendisk *disk) +static unsigned int DAC960_check_events(struct gendisk *disk, + unsigned int clearing) { DAC960_Controller_T *p = disk->queue->queuedata; int drive_nr = (long)disk->private_data; if (!p->LogicalDriveInitiallyAccessible[drive_nr]) - return 1; + return DISK_EVENT_MEDIA_CHANGE; return 0; } @@ -163,7 +164,7 @@ static const struct block_device_operations DAC960_BlockDeviceOperations = { .owner = THIS_MODULE, .open = DAC960_open, .getgeo = DAC960_getgeo, - .media_changed = DAC960_media_changed, + .check_events = DAC960_check_events, .revalidate_disk = DAC960_revalidate_disk, }; @@ -2546,6 +2547,7 @@ static bool DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller) disk->major = MajorNumber; disk->first_minor = n << DAC960_MaxPartitionsBits; disk->fops = &DAC960_BlockDeviceOperations; + disk->events = DISK_EVENT_MEDIA_CHANGE; } /* Indicate the Block Device Registration completed successfully, -- cgit v1.2.2 From 4bbde77787270e17418dd32c7eb32e42ad16cfc7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: swim[3]: Convert to bdops->check_events() Convert from ->media_changed() to ->check_events(). Both swim and swim3 buffer media changed state and clear it on revalidation. They will behave correctly with kernel event polling. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers Cc: Laurent Vivier Cc: Benjamin Herrenschmidt --- drivers/block/swim.c | 8 +++++--- drivers/block/swim3.c | 11 +++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/swim.c b/drivers/block/swim.c index 75333d0a3327..24a482f2fbd6 100644 --- a/drivers/block/swim.c +++ b/drivers/block/swim.c @@ -741,11 +741,12 @@ static int floppy_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } -static int floppy_check_change(struct gendisk *disk) +static unsigned int floppy_check_events(struct gendisk *disk, + unsigned int clearing) { struct floppy_state *fs = disk->private_data; - return fs->ejected; + return fs->ejected ? DISK_EVENT_MEDIA_CHANGE : 0; } static int floppy_revalidate(struct gendisk *disk) @@ -772,7 +773,7 @@ static const struct block_device_operations floppy_fops = { .release = floppy_release, .ioctl = floppy_ioctl, .getgeo = floppy_getgeo, - .media_changed = floppy_check_change, + .check_events = floppy_check_events, .revalidate_disk = floppy_revalidate, }; @@ -857,6 +858,7 @@ static int __devinit swim_floppy_init(struct swim_priv *swd) swd->unit[drive].disk->first_minor = drive; sprintf(swd->unit[drive].disk->disk_name, "fd%d", drive); swd->unit[drive].disk->fops = &floppy_fops; + swd->unit[drive].disk->events = DISK_EVENT_MEDIA_CHANGE; swd->unit[drive].disk->private_data = &swd->unit[drive]; swd->unit[drive].disk->queue = swd->queue; set_capacity(swd->unit[drive].disk, 2880); diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index bf3a5b859299..4c10f56facbf 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -250,7 +250,8 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long param); static int floppy_open(struct block_device *bdev, fmode_t mode); static int floppy_release(struct gendisk *disk, fmode_t mode); -static int floppy_check_change(struct gendisk *disk); +static unsigned int floppy_check_events(struct gendisk *disk, + unsigned int clearing); static int floppy_revalidate(struct gendisk *disk); static bool swim3_end_request(int err, unsigned int nr_bytes) @@ -975,10 +976,11 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) return 0; } -static int floppy_check_change(struct gendisk *disk) +static unsigned int floppy_check_events(struct gendisk *disk, + unsigned int clearing) { struct floppy_state *fs = disk->private_data; - return fs->ejected; + return fs->ejected ? DISK_EVENT_MEDIA_CHANGE : 0; } static int floppy_revalidate(struct gendisk *disk) @@ -1025,7 +1027,7 @@ static const struct block_device_operations floppy_fops = { .open = floppy_unlocked_open, .release = floppy_release, .ioctl = floppy_ioctl, - .media_changed = floppy_check_change, + .check_events = floppy_check_events, .revalidate_disk= floppy_revalidate, }; @@ -1161,6 +1163,7 @@ static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device disk->major = FLOPPY_MAJOR; disk->first_minor = i; disk->fops = &floppy_fops; + disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = &floppy_states[i]; disk->queue = swim3_queue; disk->flags |= GENHD_FL_REMOVABLE; -- cgit v1.2.2 From aaa7c01546d3dc944f5758f671284177131ccce3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: ub: Convert to bdops->check_events() Convert from ->media_changed() to ->check_events(). ub buffers media changed state and clears it on revalidation. It will behave correctly with kernel event polling. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers Cc: Pete Zaitcev --- drivers/block/ub.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 9ae3bb713286..68b9430c7cfe 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1788,7 +1788,8 @@ static int ub_bd_revalidate(struct gendisk *disk) * * The return code is bool! */ -static int ub_bd_media_changed(struct gendisk *disk) +static unsigned int ub_bd_check_events(struct gendisk *disk, + unsigned int clearing) { struct ub_lun *lun = disk->private_data; @@ -1806,10 +1807,10 @@ static int ub_bd_media_changed(struct gendisk *disk) */ if (ub_sync_tur(lun->udev, lun) != 0) { lun->changed = 1; - return 1; + return DISK_EVENT_MEDIA_CHANGE; } - return lun->changed; + return lun->changed ? DISK_EVENT_MEDIA_CHANGE : 0; } static const struct block_device_operations ub_bd_fops = { @@ -1817,7 +1818,7 @@ static const struct block_device_operations ub_bd_fops = { .open = ub_bd_unlocked_open, .release = ub_bd_release, .ioctl = ub_bd_ioctl, - .media_changed = ub_bd_media_changed, + .check_events = ub_bd_check_events, .revalidate_disk = ub_bd_revalidate, }; @@ -2333,6 +2334,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) disk->major = UB_MAJOR; disk->first_minor = lun->id * UB_PARTS_PER_LUN; disk->fops = &ub_bd_fops; + disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = lun; disk->driverfs_dev = &sc->intf->dev; -- cgit v1.2.2 From 3a200911ada2d5b955c2c6daa22364c6de83c52c Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: xsysace: Convert to bdops->check_events() Convert from ->media_changed() to ->check_events(). xsysace buffers media changed state and clears it on revalidation. It will behave correctly with kernel event polling. Signed-off-by: Tejun Heo Acked-by: Grant Likely Cc: Jens Axboe Cc: Kay Sievers --- drivers/block/xsysace.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 829161edae53..16a2fa96b810 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -867,12 +867,12 @@ static void ace_request(struct request_queue * q) } } -static int ace_media_changed(struct gendisk *gd) +static unsigned int ace_check_events(struct gendisk *gd, unsigned int clearing) { struct ace_device *ace = gd->private_data; - dev_dbg(ace->dev, "ace_media_changed(): %i\n", ace->media_change); + dev_dbg(ace->dev, "ace_check_events(): %i\n", ace->media_change); - return ace->media_change; + return ace->media_change ? DISK_EVENT_MEDIA_CHANGE : 0; } static int ace_revalidate_disk(struct gendisk *gd) @@ -953,7 +953,7 @@ static const struct block_device_operations ace_fops = { .owner = THIS_MODULE, .open = ace_open, .release = ace_release, - .media_changed = ace_media_changed, + .check_events = ace_check_events, .revalidate_disk = ace_revalidate_disk, .getgeo = ace_getgeo, }; @@ -1005,6 +1005,7 @@ static int __devinit ace_setup(struct ace_device *ace) ace->gd->major = ace_major; ace->gd->first_minor = ace->id * ACE_NUM_MINORS; ace->gd->fops = &ace_fops; + ace->gd->events = DISK_EVENT_MEDIA_CHANGE; ace->gd->queue = ace->queue; ace->gd->private_data = ace; snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a'); -- cgit v1.2.2 From f47350fdecb7ce9fe715e2df4431c4b51c4ef46b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: i2o_block: Convert to bdops->check_events() Convert from ->media_changed() to ->check_events(). i2o_block buffers media changed state and clears it after reporting. It will behave correctly with kernel event polling. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers Cc: Markus Lidel --- drivers/message/i2o/i2o_block.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index ae7cad185898..f81c25d4a125 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -695,20 +695,22 @@ static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode, }; /** - * i2o_block_media_changed - Have we seen a media change? + * i2o_block_check_events - Have we seen a media change? * @disk: gendisk which should be verified + * @clearing: events being cleared * * Verifies if the media has changed. * * Returns 1 if the media was changed or 0 otherwise. */ -static int i2o_block_media_changed(struct gendisk *disk) +static unsigned int i2o_block_check_events(struct gendisk *disk, + unsigned int clearing) { struct i2o_block_device *p = disk->private_data; if (p->media_change_flag) { p->media_change_flag = 0; - return 1; + return DISK_EVENT_MEDIA_CHANGE; } return 0; } @@ -950,7 +952,7 @@ static const struct block_device_operations i2o_block_fops = { .ioctl = i2o_block_ioctl, .compat_ioctl = i2o_block_ioctl, .getgeo = i2o_block_getgeo, - .media_changed = i2o_block_media_changed + .check_events = i2o_block_check_events, }; /** @@ -1002,6 +1004,7 @@ static struct i2o_block_device *i2o_block_device_alloc(void) gd->major = I2O_MAJOR; gd->queue = queue; gd->fops = &i2o_block_fops; + gd->events = DISK_EVENT_MEDIA_CHANGE; gd->private_data = dev; dev->gd = gd; -- cgit v1.2.2 From ffe80cea354519d846767b8165598c2903706c2a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: s390/tape_block: Convert to bdops->check_events() Convert from ->media_changed() to ->check_events(). s390/tape_block buffers media changed state and clears it on revalidation. It will behave correctly with kernel event polling. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers Cc: Martin Schwidefsky Cc: Heiko Carstens --- drivers/s390/char/tape_block.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 55d2d0f4eabc..ad8431636012 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -48,14 +48,14 @@ static DEFINE_MUTEX(tape_block_mutex); static int tapeblock_open(struct block_device *, fmode_t); static int tapeblock_release(struct gendisk *, fmode_t); -static int tapeblock_medium_changed(struct gendisk *); +static unsigned int tapeblock_check_events(struct gendisk *, unsigned int); static int tapeblock_revalidate_disk(struct gendisk *); static const struct block_device_operations tapeblock_fops = { .owner = THIS_MODULE, .open = tapeblock_open, .release = tapeblock_release, - .media_changed = tapeblock_medium_changed, + .check_events = tapeblock_check_events, .revalidate_disk = tapeblock_revalidate_disk, }; @@ -237,6 +237,7 @@ tapeblock_setup_device(struct tape_device * device) disk->major = tapeblock_major; disk->first_minor = device->first_minor; disk->fops = &tapeblock_fops; + disk->events = DISK_EVENT_MEDIA_CHANGE; disk->private_data = tape_get_device(device); disk->queue = blkdat->request_queue; set_capacity(disk, 0); @@ -340,8 +341,8 @@ tapeblock_revalidate_disk(struct gendisk *disk) return 0; } -static int -tapeblock_medium_changed(struct gendisk *disk) +static unsigned int +tapeblock_check_events(struct gendisk *disk, unsigned int clearing) { struct tape_device *device; @@ -349,7 +350,7 @@ tapeblock_medium_changed(struct gendisk *disk) DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n", device, device->blk_data.medium_changed); - return device->blk_data.medium_changed; + return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0; } /* -- cgit v1.2.2 From 6fac80e3aa9e5bfc6cadb9ea8d0584c557c4b198 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: umem: Drop dummy ->media_changed() umem doesn't implement media changed detection and there's no need to implement dummy callback anymore. Remove it. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers --- drivers/block/umem.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 8be57151f5d6..9b102abe209c 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -779,20 +779,10 @@ static int mm_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } -/* - * Future support for removable devices - */ -static int mm_check_change(struct gendisk *disk) -{ -/* struct cardinfo *dev = disk->private_data; */ - return 0; -} - static const struct block_device_operations mm_fops = { .owner = THIS_MODULE, .getgeo = mm_getgeo, .revalidate_disk = mm_revalidate, - .media_changed = mm_check_change, }; static int __devinit mm_pci_probe(struct pci_dev *dev, -- cgit v1.2.2 From 3c0d206092f50be82523dba2b0e0a02de9e6aad3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:28 +0100 Subject: pktcdvd: Convert to bdops->check_events() Convert from ->media_changed() to ->check_events(). pktcdvd needs to forward all event related operations to the underlying device. Forward ->check_events() instead of ->media_changed() and inherit disk->[async_]events. Signed-off-by: Tejun Heo Cc: Jens Axboe Cc: Kay Sievers Cc: Peter Osterlund --- drivers/block/pktcdvd.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 77d70eebb6b2..a077db27b7c9 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2796,7 +2796,8 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, return ret; } -static int pkt_media_changed(struct gendisk *disk) +static unsigned int pkt_check_events(struct gendisk *disk, + unsigned int clearing) { struct pktcdvd_device *pd = disk->private_data; struct gendisk *attached_disk; @@ -2806,9 +2807,9 @@ static int pkt_media_changed(struct gendisk *disk) if (!pd->bdev) return 0; attached_disk = pd->bdev->bd_disk; - if (!attached_disk) + if (!attached_disk || !attached_disk->fops->check_events) return 0; - return attached_disk->fops->media_changed(attached_disk); + return attached_disk->fops->check_events(attached_disk, clearing); } static const struct block_device_operations pktcdvd_ops = { @@ -2816,7 +2817,7 @@ static const struct block_device_operations pktcdvd_ops = { .open = pkt_open, .release = pkt_close, .ioctl = pkt_ioctl, - .media_changed = pkt_media_changed, + .check_events = pkt_check_events, }; static char *pktcdvd_devnode(struct gendisk *gd, mode_t *mode) @@ -2889,6 +2890,10 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev) if (ret) goto out_new_dev; + /* inherit events of the host device */ + disk->events = pd->bdev->bd_disk->events; + disk->async_events = pd->bdev->bd_disk->async_events; + add_disk(disk); pkt_sysfs_dev_new(pd); -- cgit v1.2.2 From cafb0bfca1a73efd6d8a4a6a6a716e6134b96c24 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 9 Mar 2011 19:54:29 +0100 Subject: staging: Convert to bdops->check_events() Convert two staging drivers - blkvsc_drv and cyasblkdev_block - from ->media_changed() to ->check_events(). The former always indicated media changed while the latter always indicated media not changed. Not sure what the drivers are trying to achieve but keep the original behavior. Signed-off-by: Tejun Heo Acked-by: Greg Kroah-Hartman Cc: Jens Axboe Cc: Kay Sievers --- drivers/staging/hv/blkvsc_drv.c | 11 +++++++---- drivers/staging/westbridge/astoria/block/cyasblkdev_block.c | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c index 4fb809485d9e..1ecd7e17f571 100644 --- a/drivers/staging/hv/blkvsc_drv.c +++ b/drivers/staging/hv/blkvsc_drv.c @@ -131,7 +131,8 @@ static void blkvsc_shutdown(struct device *device); static int blkvsc_open(struct block_device *bdev, fmode_t mode); static int blkvsc_release(struct gendisk *disk, fmode_t mode); -static int blkvsc_media_changed(struct gendisk *gd); +static unsigned int blkvsc_check_events(struct gendisk *gd, + unsigned int clearing); static int blkvsc_revalidate_disk(struct gendisk *gd); static int blkvsc_getgeo(struct block_device *bd, struct hd_geometry *hg); static int blkvsc_ioctl(struct block_device *bd, fmode_t mode, @@ -162,7 +163,7 @@ static const struct block_device_operations block_ops = { .owner = THIS_MODULE, .open = blkvsc_open, .release = blkvsc_release, - .media_changed = blkvsc_media_changed, + .check_events = blkvsc_check_events, .revalidate_disk = blkvsc_revalidate_disk, .getgeo = blkvsc_getgeo, .ioctl = blkvsc_ioctl, @@ -367,6 +368,7 @@ static int blkvsc_probe(struct device *device) else blkdev->gd->first_minor = 0; blkdev->gd->fops = &block_ops; + blkdev->gd->events = DISK_EVENT_MEDIA_CHANGE; blkdev->gd->private_data = blkdev; blkdev->gd->driverfs_dev = &(blkdev->device_ctx->device); sprintf(blkdev->gd->disk_name, "hd%c", 'a' + devnum); @@ -1352,10 +1354,11 @@ static int blkvsc_release(struct gendisk *disk, fmode_t mode) return 0; } -static int blkvsc_media_changed(struct gendisk *gd) +static unsigned int blkvsc_check_events(struct gendisk *gd, + unsigned int clearing) { DPRINT_DBG(BLKVSC_DRV, "- enter\n"); - return 1; + return DISK_EVENT_MEDIA_CHANGE; } static int blkvsc_revalidate_disk(struct gendisk *gd) diff --git a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c index e1851f00be56..842cd9214a5e 100644 --- a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c +++ b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c @@ -381,10 +381,10 @@ static int cyasblkdev_blk_ioctl( return -ENOTTY; } -/* Media_changed block_device opp +/* check_events block_device opp * this one is called by kernel to confirm if the media really changed * as we indicated by issuing check_disk_change() call */ -int cyasblkdev_media_changed(struct gendisk *gd) +unsigned int cyasblkdev_check_events(struct gendisk *gd, unsigned int clearing) { struct cyasblkdev_blk_data *bd; @@ -402,7 +402,7 @@ int cyasblkdev_media_changed(struct gendisk *gd) #endif } - /* return media change state "1" yes, 0 no */ + /* return media change state - DISK_EVENT_MEDIA_CHANGE yes, 0 no */ return 0; } @@ -432,7 +432,7 @@ static struct block_device_operations cyasblkdev_bdops = { .ioctl = cyasblkdev_blk_ioctl, /* .getgeo = cyasblkdev_blk_getgeo, */ /* added to support media removal( real and simulated) media */ - .media_changed = cyasblkdev_media_changed, + .check_events = cyasblkdev_check_events, /* added to support media removal( real and simulated) media */ .revalidate_disk = cyasblkdev_revalidate_disk, .owner = THIS_MODULE, @@ -1090,6 +1090,7 @@ static int cyasblkdev_add_disks(int bus_num, bd->user_disk_0->first_minor = devidx << CYASBLKDEV_SHIFT; bd->user_disk_0->minors = 8; bd->user_disk_0->fops = &cyasblkdev_bdops; + bd->user_disk_0->events = DISK_EVENT_MEDIA_CHANGE; bd->user_disk_0->private_data = bd; bd->user_disk_0->queue = bd->queue.queue; bd->dbgprn_flags = DBGPRN_RD_RQ; @@ -1190,6 +1191,7 @@ static int cyasblkdev_add_disks(int bus_num, bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT; bd->user_disk_1->minors = 8; bd->user_disk_1->fops = &cyasblkdev_bdops; + bd->user_disk_0->events = DISK_EVENT_MEDIA_CHANGE; bd->user_disk_1->private_data = bd; bd->user_disk_1->queue = bd->queue.queue; bd->dbgprn_flags = DBGPRN_RD_RQ; @@ -1278,6 +1280,7 @@ static int cyasblkdev_add_disks(int bus_num, (devidx + 2) << CYASBLKDEV_SHIFT; bd->system_disk->minors = 8; bd->system_disk->fops = &cyasblkdev_bdops; + bd->system_disk->events = DISK_EVENT_MEDIA_CHANGE; bd->system_disk->private_data = bd; bd->system_disk->queue = bd->queue.queue; /* don't search for vfat -- cgit v1.2.2 From 0a41e90bb7c931fd53d73ea770f5b251af6c91ce Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 16 Apr 2010 21:11:21 +0200 Subject: ide-cd: convert to blk_delay_queue() for a short pause It was always abuse to reuse the plugging infrastructure for this, convert it to the (new) real API for delaying queueing a bit. Signed-off-by: Jens Axboe Acked-by: David S. Miller --- drivers/ide/ide-cd.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 0c73fe39a236..7ce9caf4521b 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -258,17 +258,10 @@ static int ide_cd_breathe(ide_drive_t *drive, struct request *rq) if (time_after(jiffies, info->write_timeout)) return 0; else { - struct request_queue *q = drive->queue; - unsigned long flags; - /* - * take a breather relying on the unplug timer to kick us again + * take a breather */ - - spin_lock_irqsave(q->queue_lock, flags); - blk_plug_device(q); - spin_unlock_irqrestore(q->queue_lock, flags); - + blk_delay_queue(drive->queue, 1); return 1; } } @@ -1514,8 +1507,6 @@ static int ide_cdrom_setup(ide_drive_t *drive) blk_queue_dma_alignment(q, 31); blk_queue_update_dma_pad(q, 15); - q->unplug_delay = max((1 * HZ) / 1000, 1); - drive->dev_flags |= IDE_DFLAG_MEDIA_CHANGED; drive->atapi_flags = IDE_AFLAG_NO_EJECT | ide_cd_flags(id); -- cgit v1.2.2 From a488e74976bf0a9bccecdd094378394942dacef1 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 16 Apr 2010 21:13:15 +0200 Subject: scsi: convert to blk_delay_queue() It was always abuse to reuse the plugging infrastructure for this, convert it to the (new) real API for delaying queueing a bit. A default delay of 3 msec is defined, to match the previous behaviour. Signed-off-by: Jens Axboe --- drivers/scsi/scsi_lib.c | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9045c52abd25..5a0ae7a944ce 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -67,6 +67,13 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = { struct kmem_cache *scsi_sdb_cache; +/* + * When to reinvoke queueing after a resource shortage. It's 3 msecs to + * not change behaviour from the previous unplug mechanism, experimentation + * may prove this needs changing. + */ +#define SCSI_QUEUE_DELAY 3 + static void scsi_run_queue(struct request_queue *q); /* @@ -149,14 +156,7 @@ static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) /* * Requeue this command. It will go before all other commands * that are already in the queue. - * - * NOTE: there is magic here about the way the queue is plugged if - * we have no outstanding commands. - * - * Although we *don't* plug the queue, we call the request - * function. The SCSI request function detects the blocked condition - * and plugs the queue appropriately. - */ + */ spin_lock_irqsave(q->queue_lock, flags); blk_requeue_request(q, cmd->request); spin_unlock_irqrestore(q->queue_lock, flags); @@ -1194,11 +1194,11 @@ int scsi_prep_return(struct request_queue *q, struct request *req, int ret) case BLKPREP_DEFER: /* * If we defer, the blk_peek_request() returns NULL, but the - * queue must be restarted, so we plug here if no returning - * command will automatically do that. + * queue must be restarted, so we schedule a callback to happen + * shortly. */ if (sdev->device_busy == 0) - blk_plug_device(q); + blk_delay_queue(q, SCSI_QUEUE_DELAY); break; default: req->cmd_flags |= REQ_DONTPREP; @@ -1237,7 +1237,7 @@ static inline int scsi_dev_queue_ready(struct request_queue *q, sdev_printk(KERN_INFO, sdev, "unblocking device at zero depth\n")); } else { - blk_plug_device(q); + blk_delay_queue(q, SCSI_QUEUE_DELAY); return 0; } } @@ -1467,7 +1467,7 @@ static void scsi_request_fn(struct request_queue *q) * the host is no longer able to accept any more requests. */ shost = sdev->host; - while (!blk_queue_plugged(q)) { + for (;;) { int rtn; /* * get next queueable request. We do this early to make sure @@ -1546,15 +1546,8 @@ static void scsi_request_fn(struct request_queue *q) */ rtn = scsi_dispatch_cmd(cmd); spin_lock_irq(q->queue_lock); - if(rtn) { - /* we're refusing the command; because of - * the way locks get dropped, we need to - * check here if plugging is required */ - if(sdev->device_busy == 0) - blk_plug_device(q); - - break; - } + if (rtn) + goto out_delay; } goto out; @@ -1573,9 +1566,10 @@ static void scsi_request_fn(struct request_queue *q) spin_lock_irq(q->queue_lock); blk_requeue_request(q, req); sdev->device_busy--; - if(sdev->device_busy == 0) - blk_plug_device(q); - out: +out_delay: + if (sdev->device_busy == 0) + blk_delay_queue(q, SCSI_QUEUE_DELAY); +out: /* must be careful here...if we trigger the ->remove() function * we cannot be holding the q lock */ spin_unlock_irq(q->queue_lock); -- cgit v1.2.2 From 7eaceaccab5f40bbfda044629a6298616aeaed50 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 10 Mar 2011 08:52:07 +0100 Subject: block: remove per-queue plugging Code has been converted over to the new explicit on-stack plugging, and delay users have been converted to use the new API for that. So lets kill off the old plugging along with aops->sync_page(). Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 6 --- drivers/block/cpqarray.c | 3 -- drivers/block/drbd/drbd_actlog.c | 2 - drivers/block/drbd/drbd_bitmap.c | 1 - drivers/block/drbd/drbd_int.h | 14 ------ drivers/block/drbd/drbd_main.c | 33 +------------- drivers/block/drbd/drbd_receiver.c | 20 +-------- drivers/block/drbd/drbd_req.c | 4 -- drivers/block/drbd/drbd_worker.c | 1 - drivers/block/drbd/drbd_wrappers.h | 18 -------- drivers/block/floppy.c | 1 - drivers/block/loop.c | 13 ------ drivers/block/pktcdvd.c | 2 - drivers/block/umem.c | 16 +------ drivers/ide/ide-atapi.c | 3 +- drivers/ide/ide-io.c | 4 -- drivers/ide/ide-park.c | 2 +- drivers/md/bitmap.c | 3 +- drivers/md/dm-crypt.c | 9 +--- drivers/md/dm-kcopyd.c | 52 +++------------------- drivers/md/dm-raid.c | 2 +- drivers/md/dm-raid1.c | 2 - drivers/md/dm-table.c | 24 ---------- drivers/md/dm.c | 33 +++----------- drivers/md/linear.c | 17 -------- drivers/md/md.c | 7 --- drivers/md/multipath.c | 31 ------------- drivers/md/raid0.c | 16 ------- drivers/md/raid1.c | 83 ++++++++--------------------------- drivers/md/raid10.c | 87 ++++++++----------------------------- drivers/md/raid5.c | 62 ++++---------------------- drivers/md/raid5.h | 2 +- drivers/message/i2o/i2o_block.c | 6 +-- drivers/mmc/card/queue.c | 3 +- drivers/s390/block/dasd.c | 2 +- drivers/s390/char/tape_block.c | 1 - drivers/scsi/scsi_transport_fc.c | 2 +- drivers/scsi/scsi_transport_sas.c | 6 +-- drivers/target/target_core_iblock.c | 7 ++- 39 files changed, 71 insertions(+), 529 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 9279272b3732..35658f445fca 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3170,12 +3170,6 @@ static void do_cciss_request(struct request_queue *q) int sg_index = 0; int chained = 0; - /* We call start_io here in case there is a command waiting on the - * queue that has not been sent. - */ - if (blk_queue_plugged(q)) - goto startio; - queue: creq = blk_peek_request(q); if (!creq) diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 946dad4caef3..b2fceb53e809 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -911,9 +911,6 @@ static void do_ida_request(struct request_queue *q) struct scatterlist tmp_sg[SG_MAX]; int i, dir, seg; - if (blk_queue_plugged(q)) - goto startio; - queue_next: creq = blk_peek_request(q); if (!creq) diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index ba95cba192be..2096628d6e65 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -689,8 +689,6 @@ void drbd_al_to_on_disk_bm(struct drbd_conf *mdev) } } - drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev)); - /* always (try to) flush bitmap to stable storage */ drbd_md_flush(mdev); diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index fd42832f785b..0645ca829a94 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -840,7 +840,6 @@ static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) for (i = 0; i < num_pages; i++) bm_page_io_async(mdev, b, i, rw); - drbd_blk_run_queue(bdev_get_queue(mdev->ldev->md_bdev)); wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0); if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) { diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 3803a0348937..0b5718e19586 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2382,20 +2382,6 @@ static inline int drbd_queue_order_type(struct drbd_conf *mdev) return QUEUE_ORDERED_NONE; } -static inline void drbd_blk_run_queue(struct request_queue *q) -{ - if (q && q->unplug_fn) - q->unplug_fn(q); -} - -static inline void drbd_kick_lo(struct drbd_conf *mdev) -{ - if (get_ldev(mdev)) { - drbd_blk_run_queue(bdev_get_queue(mdev->ldev->backing_bdev)); - put_ldev(mdev); - } -} - static inline void drbd_md_flush(struct drbd_conf *mdev) { int r; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 29cd0dc9fe4f..6049cb85310d 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2719,35 +2719,6 @@ static int drbd_release(struct gendisk *gd, fmode_t mode) return 0; } -static void drbd_unplug_fn(struct request_queue *q) -{ - struct drbd_conf *mdev = q->queuedata; - - /* unplug FIRST */ - spin_lock_irq(q->queue_lock); - blk_remove_plug(q); - spin_unlock_irq(q->queue_lock); - - /* only if connected */ - spin_lock_irq(&mdev->req_lock); - if (mdev->state.pdsk >= D_INCONSISTENT && mdev->state.conn >= C_CONNECTED) { - D_ASSERT(mdev->state.role == R_PRIMARY); - if (test_and_clear_bit(UNPLUG_REMOTE, &mdev->flags)) { - /* add to the data.work queue, - * unless already queued. - * XXX this might be a good addition to drbd_queue_work - * anyways, to detect "double queuing" ... */ - if (list_empty(&mdev->unplug_work.list)) - drbd_queue_work(&mdev->data.work, - &mdev->unplug_work); - } - } - spin_unlock_irq(&mdev->req_lock); - - if (mdev->state.disk >= D_INCONSISTENT) - drbd_kick_lo(mdev); -} - static void drbd_set_defaults(struct drbd_conf *mdev) { /* This way we get a compile error when sync_conf grows, @@ -3222,9 +3193,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); blk_queue_merge_bvec(q, drbd_merge_bvec); - q->queue_lock = &mdev->req_lock; /* needed since we use */ - /* plugging on a queue, that actually has no requests! */ - q->unplug_fn = drbd_unplug_fn; + q->queue_lock = &mdev->req_lock; mdev->md_io_page = alloc_page(GFP_KERNEL); if (!mdev->md_io_page) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 24487d4fb202..84132f8bf8a4 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -187,15 +187,6 @@ static struct page *drbd_pp_first_pages_or_try_alloc(struct drbd_conf *mdev, int return NULL; } -/* kick lower level device, if we have more than (arbitrary number) - * reference counts on it, which typically are locally submitted io - * requests. don't use unacked_cnt, so we speed up proto A and B, too. */ -static void maybe_kick_lo(struct drbd_conf *mdev) -{ - if (atomic_read(&mdev->local_cnt) >= mdev->net_conf->unplug_watermark) - drbd_kick_lo(mdev); -} - static void reclaim_net_ee(struct drbd_conf *mdev, struct list_head *to_be_freed) { struct drbd_epoch_entry *e; @@ -219,7 +210,6 @@ static void drbd_kick_lo_and_reclaim_net(struct drbd_conf *mdev) LIST_HEAD(reclaimed); struct drbd_epoch_entry *e, *t; - maybe_kick_lo(mdev); spin_lock_irq(&mdev->req_lock); reclaim_net_ee(mdev, &reclaimed); spin_unlock_irq(&mdev->req_lock); @@ -436,8 +426,7 @@ void _drbd_wait_ee_list_empty(struct drbd_conf *mdev, struct list_head *head) while (!list_empty(head)) { prepare_to_wait(&mdev->ee_wait, &wait, TASK_UNINTERRUPTIBLE); spin_unlock_irq(&mdev->req_lock); - drbd_kick_lo(mdev); - schedule(); + io_schedule(); finish_wait(&mdev->ee_wait, &wait); spin_lock_irq(&mdev->req_lock); } @@ -1147,7 +1136,6 @@ next_bio: drbd_generic_make_request(mdev, fault_type, bio); } while (bios); - maybe_kick_lo(mdev); return 0; fail: @@ -1167,9 +1155,6 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign inc_unacked(mdev); - if (mdev->net_conf->wire_protocol != DRBD_PROT_C) - drbd_kick_lo(mdev); - mdev->current_epoch->barrier_nr = p->barrier; rv = drbd_may_finish_epoch(mdev, mdev->current_epoch, EV_GOT_BARRIER_NR); @@ -3556,9 +3541,6 @@ static int receive_skip(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) { - if (mdev->state.disk >= D_INCONSISTENT) - drbd_kick_lo(mdev); - /* Make sure we've acked all the TCP data associated * with the data requests being unplugged */ drbd_tcp_quickack(mdev->data.socket); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 11a75d32a2e2..ad3fc6228f27 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -960,10 +960,6 @@ allocate_barrier: bio_endio(req->private_bio, -EIO); } - /* we need to plug ALWAYS since we possibly need to kick lo_dev. - * we plug after submit, so we won't miss an unplug event */ - drbd_plug_device(mdev); - return 0; fail_conflicting: diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 34f224b018b3..e027446590d3 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -792,7 +792,6 @@ int drbd_resync_finished(struct drbd_conf *mdev) * queue (or even the read operations for those packets * is not finished by now). Retry in 100ms. */ - drbd_kick_lo(mdev); __set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC); diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h index defdb5013ea3..53586fa5ae1b 100644 --- a/drivers/block/drbd/drbd_wrappers.h +++ b/drivers/block/drbd/drbd_wrappers.h @@ -45,24 +45,6 @@ static inline void drbd_generic_make_request(struct drbd_conf *mdev, generic_make_request(bio); } -static inline void drbd_plug_device(struct drbd_conf *mdev) -{ - struct request_queue *q; - q = bdev_get_queue(mdev->this_bdev); - - spin_lock_irq(q->queue_lock); - -/* XXX the check on !blk_queue_plugged is redundant, - * implicitly checked in blk_plug_device */ - - if (!blk_queue_plugged(q)) { - blk_plug_device(q); - del_timer(&q->unplug_timer); - /* unplugging should not happen automatically... */ - } - spin_unlock_irq(q->queue_lock); -} - static inline int drbd_crypto_is_hash(struct crypto_tfm *tfm) { return (crypto_tfm_alg_type(tfm) & CRYPTO_ALG_TYPE_HASH_MASK) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index b9ba04fc2b34..271142b9e2cd 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3837,7 +3837,6 @@ static int __floppy_read_block_0(struct block_device *bdev) bio.bi_end_io = floppy_rb0_complete; submit_bio(READ, &bio); - generic_unplug_device(bdev_get_queue(bdev)); process_fd_request(); wait_for_completion(&complete); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 49e6a545eb63..01b8e4a87c9f 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -541,17 +541,6 @@ out: return 0; } -/* - * kick off io on the underlying address space - */ -static void loop_unplug(struct request_queue *q) -{ - struct loop_device *lo = q->queuedata; - - queue_flag_clear_unlocked(QUEUE_FLAG_PLUGGED, q); - blk_run_address_space(lo->lo_backing_file->f_mapping); -} - struct switch_request { struct file *file; struct completion wait; @@ -918,7 +907,6 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode, */ blk_queue_make_request(lo->lo_queue, loop_make_request); lo->lo_queue->queuedata = lo; - lo->lo_queue->unplug_fn = loop_unplug; if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync) blk_queue_flush(lo->lo_queue, REQ_FLUSH); @@ -1020,7 +1008,6 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev) kthread_stop(lo->lo_thread); - lo->lo_queue->unplug_fn = NULL; lo->lo_backing_file = NULL; loop_release_xfer(lo); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 77d70eebb6b2..d20e13f80001 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1606,8 +1606,6 @@ static int kcdrwd(void *foobar) min_sleep_time = pkt->sleep_time; } - generic_unplug_device(bdev_get_queue(pd->bdev)); - VPRINTK("kcdrwd: sleeping\n"); residue = schedule_timeout(min_sleep_time); VPRINTK("kcdrwd: wake up\n"); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 8be57151f5d6..653439faa729 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -241,8 +241,7 @@ static void dump_dmastat(struct cardinfo *card, unsigned int dmastat) * * Whenever IO on the active page completes, the Ready page is activated * and the ex-Active page is clean out and made Ready. - * Otherwise the Ready page is only activated when it becomes full, or - * when mm_unplug_device is called via the unplug_io_fn. + * Otherwise the Ready page is only activated when it becomes full. * * If a request arrives while both pages a full, it is queued, and b_rdev is * overloaded to record whether it was a read or a write. @@ -333,17 +332,6 @@ static inline void reset_page(struct mm_page *page) page->biotail = &page->bio; } -static void mm_unplug_device(struct request_queue *q) -{ - struct cardinfo *card = q->queuedata; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - if (blk_remove_plug(q)) - activate(card); - spin_unlock_irqrestore(&card->lock, flags); -} - /* * If there is room on Ready page, take * one bh off list and add it. @@ -535,7 +523,6 @@ static int mm_make_request(struct request_queue *q, struct bio *bio) *card->biotail = bio; bio->bi_next = NULL; card->biotail = &bio->bi_next; - blk_plug_device(q); spin_unlock_irq(&card->lock); return 0; @@ -907,7 +894,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, blk_queue_make_request(card->queue, mm_make_request); card->queue->queue_lock = &card->lock; card->queue->queuedata = card; - card->queue->unplug_fn = mm_unplug_device; tasklet_init(&card->tasklet, process_page, (unsigned long)card); diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index e88a2cf17711..6f218e014e99 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -233,8 +233,7 @@ int ide_queue_sense_rq(ide_drive_t *drive, void *special) drive->hwif->rq = NULL; - elv_add_request(drive->queue, &drive->sense_rq, - ELEVATOR_INSERT_FRONT, 0); + elv_add_request(drive->queue, &drive->sense_rq, ELEVATOR_INSERT_FRONT); return 0; } EXPORT_SYMBOL_GPL(ide_queue_sense_rq); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 999dac054bcc..f4077840d3ab 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -549,8 +549,6 @@ plug_device_2: if (rq) blk_requeue_request(q, rq); - if (!elv_queue_empty(q)) - blk_plug_device(q); } void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) @@ -562,8 +560,6 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) if (rq) blk_requeue_request(q, rq); - if (!elv_queue_empty(q)) - blk_plug_device(q); spin_unlock_irqrestore(q->queue_lock, flags); } diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c index 88a380c5a470..6ab9ab2a5081 100644 --- a/drivers/ide/ide-park.c +++ b/drivers/ide/ide-park.c @@ -52,7 +52,7 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) rq->cmd[0] = REQ_UNPARK_HEADS; rq->cmd_len = 1; rq->cmd_type = REQ_TYPE_SPECIAL; - elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1); + elv_add_request(q, rq, ELEVATOR_INSERT_FRONT); out: return; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 9a35320fb59f..54bfc274b39a 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1339,8 +1339,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect prepare_to_wait(&bitmap->overflow_wait, &__wait, TASK_UNINTERRUPTIBLE); spin_unlock_irq(&bitmap->lock); - md_unplug(bitmap->mddev); - schedule(); + io_schedule(); finish_wait(&bitmap->overflow_wait, &__wait); continue; } diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 4e054bd91664..2c62c1169f78 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -991,11 +991,6 @@ static void clone_init(struct dm_crypt_io *io, struct bio *clone) clone->bi_destructor = dm_crypt_bio_destructor; } -static void kcryptd_unplug(struct crypt_config *cc) -{ - blk_unplug(bdev_get_queue(cc->dev->bdev)); -} - static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp) { struct crypt_config *cc = io->target->private; @@ -1008,10 +1003,8 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp) * one in order to decrypt the whole bio data *afterwards*. */ clone = bio_alloc_bioset(gfp, bio_segments(base_bio), cc->bs); - if (!clone) { - kcryptd_unplug(cc); + if (!clone) return 1; - } crypt_inc_pending(io); diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 924f5f0084c2..400cf35094a4 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -37,13 +37,6 @@ struct dm_kcopyd_client { unsigned int nr_pages; unsigned int nr_free_pages; - /* - * Block devices to unplug. - * Non-NULL pointer means that a block device has some pending requests - * and needs to be unplugged. - */ - struct block_device *unplug[2]; - struct dm_io_client *io_client; wait_queue_head_t destroyq; @@ -315,31 +308,6 @@ static int run_complete_job(struct kcopyd_job *job) return 0; } -/* - * Unplug the block device at the specified index. - */ -static void unplug(struct dm_kcopyd_client *kc, int rw) -{ - if (kc->unplug[rw] != NULL) { - blk_unplug(bdev_get_queue(kc->unplug[rw])); - kc->unplug[rw] = NULL; - } -} - -/* - * Prepare block device unplug. If there's another device - * to be unplugged at the same array index, we unplug that - * device first. - */ -static void prepare_unplug(struct dm_kcopyd_client *kc, int rw, - struct block_device *bdev) -{ - if (likely(kc->unplug[rw] == bdev)) - return; - unplug(kc, rw); - kc->unplug[rw] = bdev; -} - static void complete_io(unsigned long error, void *context) { struct kcopyd_job *job = (struct kcopyd_job *) context; @@ -386,15 +354,12 @@ static int run_io_job(struct kcopyd_job *job) .client = job->kc->io_client, }; - if (job->rw == READ) { + if (job->rw == READ) r = dm_io(&io_req, 1, &job->source, NULL); - prepare_unplug(job->kc, READ, job->source.bdev); - } else { + else { if (job->num_dests > 1) io_req.bi_rw |= REQ_UNPLUG; r = dm_io(&io_req, job->num_dests, job->dests, NULL); - if (!(io_req.bi_rw & REQ_UNPLUG)) - prepare_unplug(job->kc, WRITE, job->dests[0].bdev); } return r; @@ -466,6 +431,7 @@ static void do_work(struct work_struct *work) { struct dm_kcopyd_client *kc = container_of(work, struct dm_kcopyd_client, kcopyd_work); + struct blk_plug plug; /* * The order that these are called is *very* important. @@ -473,18 +439,12 @@ static void do_work(struct work_struct *work) * Pages jobs when successful will jump onto the io jobs * list. io jobs call wake when they complete and it all * starts again. - * - * Note that io_jobs add block devices to the unplug array, - * this array is cleared with "unplug" calls. It is thus - * forbidden to run complete_jobs after io_jobs and before - * unplug because the block device could be destroyed in - * job completion callback. */ + blk_start_plug(&plug); process_jobs(&kc->complete_jobs, kc, run_complete_job); process_jobs(&kc->pages_jobs, kc, run_pages_job); process_jobs(&kc->io_jobs, kc, run_io_job); - unplug(kc, READ); - unplug(kc, WRITE); + blk_finish_plug(&plug); } /* @@ -665,8 +625,6 @@ int dm_kcopyd_client_create(unsigned int nr_pages, INIT_LIST_HEAD(&kc->io_jobs); INIT_LIST_HEAD(&kc->pages_jobs); - memset(kc->unplug, 0, sizeof(kc->unplug)); - kc->job_pool = mempool_create_slab_pool(MIN_JOBS, _job_cache); if (!kc->job_pool) goto bad_slab; diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index b9e1e15ef11c..5ef136cdba91 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -394,7 +394,7 @@ static void raid_unplug(struct dm_target_callbacks *cb) { struct raid_set *rs = container_of(cb, struct raid_set, callbacks); - md_raid5_unplug_device(rs->md.private); + md_raid5_kick_device(rs->md.private); } /* diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index dee326775c60..976ad4688afc 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -842,8 +842,6 @@ static void do_mirror(struct work_struct *work) do_reads(ms, &reads); do_writes(ms, &writes); do_failures(ms, &failures); - - dm_table_unplug_all(ms->ti->table); } /*----------------------------------------------------------------- diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 38e4eb1bb965..f50a7b952257 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1275,29 +1275,6 @@ int dm_table_any_busy_target(struct dm_table *t) return 0; } -void dm_table_unplug_all(struct dm_table *t) -{ - struct dm_dev_internal *dd; - struct list_head *devices = dm_table_get_devices(t); - struct dm_target_callbacks *cb; - - list_for_each_entry(dd, devices, list) { - struct request_queue *q = bdev_get_queue(dd->dm_dev.bdev); - char b[BDEVNAME_SIZE]; - - if (likely(q)) - blk_unplug(q); - else - DMWARN_LIMIT("%s: Cannot unplug nonexistent device %s", - dm_device_name(t->md), - bdevname(dd->dm_dev.bdev, b)); - } - - list_for_each_entry(cb, &t->target_callbacks, list) - if (cb->unplug_fn) - cb->unplug_fn(cb); -} - struct mapped_device *dm_table_get_md(struct dm_table *t) { return t->md; @@ -1345,4 +1322,3 @@ EXPORT_SYMBOL(dm_table_get_mode); EXPORT_SYMBOL(dm_table_get_md); EXPORT_SYMBOL(dm_table_put); EXPORT_SYMBOL(dm_table_get); -EXPORT_SYMBOL(dm_table_unplug_all); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index eaa3af0e0632..d22b9905c168 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -807,8 +807,6 @@ void dm_requeue_unmapped_request(struct request *clone) dm_unprep_request(rq); spin_lock_irqsave(q->queue_lock, flags); - if (elv_queue_empty(q)) - blk_plug_device(q); blk_requeue_request(q, rq); spin_unlock_irqrestore(q->queue_lock, flags); @@ -1613,10 +1611,10 @@ static void dm_request_fn(struct request_queue *q) * number of in-flight I/Os after the queue is stopped in * dm_suspend(). */ - while (!blk_queue_plugged(q) && !blk_queue_stopped(q)) { + while (!blk_queue_stopped(q)) { rq = blk_peek_request(q); if (!rq) - goto plug_and_out; + goto delay_and_out; /* always use block 0 to find the target for flushes for now */ pos = 0; @@ -1627,7 +1625,7 @@ static void dm_request_fn(struct request_queue *q) BUG_ON(!dm_target_is_valid(ti)); if (ti->type->busy && ti->type->busy(ti)) - goto plug_and_out; + goto delay_and_out; blk_start_request(rq); clone = rq->special; @@ -1647,11 +1645,8 @@ requeued: BUG_ON(!irqs_disabled()); spin_lock(q->queue_lock); -plug_and_out: - if (!elv_queue_empty(q)) - /* Some requests still remain, retry later */ - blk_plug_device(q); - +delay_and_out: + blk_delay_queue(q, HZ / 10); out: dm_table_put(map); @@ -1680,20 +1675,6 @@ static int dm_lld_busy(struct request_queue *q) return r; } -static void dm_unplug_all(struct request_queue *q) -{ - struct mapped_device *md = q->queuedata; - struct dm_table *map = dm_get_live_table(md); - - if (map) { - if (dm_request_based(md)) - generic_unplug_device(q); - - dm_table_unplug_all(map); - dm_table_put(map); - } -} - static int dm_any_congested(void *congested_data, int bdi_bits) { int r = bdi_bits; @@ -1817,7 +1798,6 @@ static void dm_init_md_queue(struct mapped_device *md) md->queue->backing_dev_info.congested_data = md; blk_queue_make_request(md->queue, dm_request); blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); - md->queue->unplug_fn = dm_unplug_all; blk_queue_merge_bvec(md->queue, dm_merge_bvec); blk_queue_flush(md->queue, REQ_FLUSH | REQ_FUA); } @@ -2263,8 +2243,6 @@ static int dm_wait_for_completion(struct mapped_device *md, int interruptible) int r = 0; DECLARE_WAITQUEUE(wait, current); - dm_unplug_all(md->queue); - add_wait_queue(&md->wait, &wait); while (1) { @@ -2539,7 +2517,6 @@ int dm_resume(struct mapped_device *md) clear_bit(DMF_SUSPENDED, &md->flags); - dm_table_unplug_all(map); r = 0; out: dm_table_put(map); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 8a2f767f26d8..38861b5b9d90 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -87,22 +87,6 @@ static int linear_mergeable_bvec(struct request_queue *q, return maxsectors << 9; } -static void linear_unplug(struct request_queue *q) -{ - mddev_t *mddev = q->queuedata; - linear_conf_t *conf; - int i; - - rcu_read_lock(); - conf = rcu_dereference(mddev->private); - - for (i=0; i < mddev->raid_disks; i++) { - struct request_queue *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev); - blk_unplug(r_queue); - } - rcu_read_unlock(); -} - static int linear_congested(void *data, int bits) { mddev_t *mddev = data; @@ -225,7 +209,6 @@ static int linear_run (mddev_t *mddev) md_set_array_sectors(mddev, linear_size(mddev, 0, 0)); blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); - mddev->queue->unplug_fn = linear_unplug; mddev->queue->backing_dev_info.congested_fn = linear_congested; mddev->queue->backing_dev_info.congested_data = mddev; md_integrity_register(mddev); diff --git a/drivers/md/md.c b/drivers/md/md.c index 0cc30ecda4c1..ca0d79c264b9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4812,7 +4812,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) __md_stop_writes(mddev); md_stop(mddev); mddev->queue->merge_bvec_fn = NULL; - mddev->queue->unplug_fn = NULL; mddev->queue->backing_dev_info.congested_fn = NULL; /* tell userspace to handle 'inactive' */ @@ -6669,8 +6668,6 @@ EXPORT_SYMBOL_GPL(md_allow_write); void md_unplug(mddev_t *mddev) { - if (mddev->queue) - blk_unplug(mddev->queue); if (mddev->plug) mddev->plug->unplug_fn(mddev->plug); } @@ -6853,7 +6850,6 @@ void md_do_sync(mddev_t *mddev) >= mddev->resync_max - mddev->curr_resync_completed )) { /* time to update curr_resync_completed */ - md_unplug(mddev); wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active) == 0); mddev->curr_resync_completed = j; @@ -6929,7 +6925,6 @@ void md_do_sync(mddev_t *mddev) * about not overloading the IO subsystem. (things like an * e2fsck being done on the RAID array should execute fast) */ - md_unplug(mddev); cond_resched(); currspeed = ((unsigned long)(io_sectors-mddev->resync_mark_cnt))/2 @@ -6948,8 +6943,6 @@ void md_do_sync(mddev_t *mddev) * this also signals 'finished resyncing' to md_stop */ out: - md_unplug(mddev); - wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active)); /* tell personality that we are finished */ diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 6d7ddf32ef2e..1cc8ed44e4ad 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -106,36 +106,6 @@ static void multipath_end_request(struct bio *bio, int error) rdev_dec_pending(rdev, conf->mddev); } -static void unplug_slaves(mddev_t *mddev) -{ - multipath_conf_t *conf = mddev->private; - int i; - - rcu_read_lock(); - for (i=0; iraid_disks; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags) - && atomic_read(&rdev->nr_pending)) { - struct request_queue *r_queue = bdev_get_queue(rdev->bdev); - - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - - blk_unplug(r_queue); - - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - rcu_read_unlock(); -} - -static void multipath_unplug(struct request_queue *q) -{ - unplug_slaves(q->queuedata); -} - - static int multipath_make_request(mddev_t *mddev, struct bio * bio) { multipath_conf_t *conf = mddev->private; @@ -518,7 +488,6 @@ static int multipath_run (mddev_t *mddev) */ md_set_array_sectors(mddev, multipath_size(mddev, 0, 0)); - mddev->queue->unplug_fn = multipath_unplug; mddev->queue->backing_dev_info.congested_fn = multipath_congested; mddev->queue->backing_dev_info.congested_data = mddev; md_integrity_register(mddev); diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 637a96855edb..6338c0fe6208 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -25,21 +25,6 @@ #include "raid0.h" #include "raid5.h" -static void raid0_unplug(struct request_queue *q) -{ - mddev_t *mddev = q->queuedata; - raid0_conf_t *conf = mddev->private; - mdk_rdev_t **devlist = conf->devlist; - int raid_disks = conf->strip_zone[0].nb_dev; - int i; - - for (i=0; i < raid_disks; i++) { - struct request_queue *r_queue = bdev_get_queue(devlist[i]->bdev); - - blk_unplug(r_queue); - } -} - static int raid0_congested(void *data, int bits) { mddev_t *mddev = data; @@ -272,7 +257,6 @@ static int create_strip_zones(mddev_t *mddev, raid0_conf_t **private_conf) mdname(mddev), (unsigned long long)smallest->sectors); } - mddev->queue->unplug_fn = raid0_unplug; mddev->queue->backing_dev_info.congested_fn = raid0_congested; mddev->queue->backing_dev_info.congested_data = mddev; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a23ffa397ba9..b67d822d57ae 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -52,23 +52,16 @@ #define NR_RAID1_BIOS 256 -static void unplug_slaves(mddev_t *mddev); - static void allow_barrier(conf_t *conf); static void lower_barrier(conf_t *conf); static void * r1bio_pool_alloc(gfp_t gfp_flags, void *data) { struct pool_info *pi = data; - r1bio_t *r1_bio; int size = offsetof(r1bio_t, bios[pi->raid_disks]); /* allocate a r1bio with room for raid_disks entries in the bios array */ - r1_bio = kzalloc(size, gfp_flags); - if (!r1_bio && pi->mddev) - unplug_slaves(pi->mddev); - - return r1_bio; + return kzalloc(size, gfp_flags); } static void r1bio_pool_free(void *r1_bio, void *data) @@ -91,10 +84,8 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data) int i, j; r1_bio = r1bio_pool_alloc(gfp_flags, pi); - if (!r1_bio) { - unplug_slaves(pi->mddev); + if (!r1_bio) return NULL; - } /* * Allocate bios : 1 for reading, n-1 for writing @@ -520,37 +511,6 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) return new_disk; } -static void unplug_slaves(mddev_t *mddev) -{ - conf_t *conf = mddev->private; - int i; - - rcu_read_lock(); - for (i=0; iraid_disks; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) { - struct request_queue *r_queue = bdev_get_queue(rdev->bdev); - - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - - blk_unplug(r_queue); - - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - rcu_read_unlock(); -} - -static void raid1_unplug(struct request_queue *q) -{ - mddev_t *mddev = q->queuedata; - - unplug_slaves(mddev); - md_wakeup_thread(mddev->thread); -} - static int raid1_congested(void *data, int bits) { mddev_t *mddev = data; @@ -580,20 +540,16 @@ static int raid1_congested(void *data, int bits) } -static int flush_pending_writes(conf_t *conf) +static void flush_pending_writes(conf_t *conf) { /* Any writes that have been queued but are awaiting * bitmap updates get flushed here. - * We return 1 if any requests were actually submitted. */ - int rv = 0; - spin_lock_irq(&conf->device_lock); if (conf->pending_bio_list.head) { struct bio *bio; bio = bio_list_get(&conf->pending_bio_list); - blk_remove_plug(conf->mddev->queue); spin_unlock_irq(&conf->device_lock); /* flush any pending bitmap writes to * disk before proceeding w/ I/O */ @@ -605,10 +561,14 @@ static int flush_pending_writes(conf_t *conf) generic_make_request(bio); bio = next; } - rv = 1; } else spin_unlock_irq(&conf->device_lock); - return rv; +} + +static void md_kick_device(mddev_t *mddev) +{ + blk_flush_plug(current); + md_wakeup_thread(mddev->thread); } /* Barriers.... @@ -640,8 +600,7 @@ static void raise_barrier(conf_t *conf) /* Wait until no block IO is waiting */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_waiting, - conf->resync_lock, - raid1_unplug(conf->mddev->queue)); + conf->resync_lock, md_kick_device(conf->mddev)); /* block any new IO from starting */ conf->barrier++; @@ -649,8 +608,7 @@ static void raise_barrier(conf_t *conf) /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, - raid1_unplug(conf->mddev->queue)); + conf->resync_lock, md_kick_device(conf->mddev)); spin_unlock_irq(&conf->resync_lock); } @@ -672,7 +630,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - raid1_unplug(conf->mddev->queue)); + md_kick_device(conf->mddev)); conf->nr_waiting--; } conf->nr_pending++; @@ -709,7 +667,7 @@ static void freeze_array(conf_t *conf) conf->nr_pending == conf->nr_queued+1, conf->resync_lock, ({ flush_pending_writes(conf); - raid1_unplug(conf->mddev->queue); })); + md_kick_device(conf->mddev); })); spin_unlock_irq(&conf->resync_lock); } static void unfreeze_array(conf_t *conf) @@ -959,7 +917,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) atomic_inc(&r1_bio->remaining); spin_lock_irqsave(&conf->device_lock, flags); bio_list_add(&conf->pending_bio_list, mbio); - blk_plug_device(mddev->queue); spin_unlock_irqrestore(&conf->device_lock, flags); } r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL); @@ -968,7 +925,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid1d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync) + if (do_sync || !bitmap) md_wakeup_thread(mddev->thread); return 0; @@ -1558,7 +1515,6 @@ static void raid1d(mddev_t *mddev) unsigned long flags; conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; - int unplug=0; mdk_rdev_t *rdev; md_check_recovery(mddev); @@ -1566,7 +1522,7 @@ static void raid1d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; - unplug += flush_pending_writes(conf); + flush_pending_writes(conf); spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) { @@ -1580,10 +1536,9 @@ static void raid1d(mddev_t *mddev) mddev = r1_bio->mddev; conf = mddev->private; - if (test_bit(R1BIO_IsSync, &r1_bio->state)) { + if (test_bit(R1BIO_IsSync, &r1_bio->state)) sync_request_write(mddev, r1_bio); - unplug = 1; - } else { + else { int disk; /* we got a read error. Maybe the drive is bad. Maybe just @@ -1633,14 +1588,11 @@ static void raid1d(mddev_t *mddev) bio->bi_end_io = raid1_end_read_request; bio->bi_rw = READ | do_sync; bio->bi_private = r1_bio; - unplug = 1; generic_make_request(bio); } } cond_resched(); } - if (unplug) - unplug_slaves(mddev); } @@ -2064,7 +2016,6 @@ static int run(mddev_t *mddev) md_set_array_sectors(mddev, raid1_size(mddev, 0, 0)); - mddev->queue->unplug_fn = raid1_unplug; mddev->queue->backing_dev_info.congested_fn = raid1_congested; mddev->queue->backing_dev_info.congested_data = mddev; md_integrity_register(mddev); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 3b607b28741b..e79f1c5bf71b 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -57,23 +57,16 @@ */ #define NR_RAID10_BIOS 256 -static void unplug_slaves(mddev_t *mddev); - static void allow_barrier(conf_t *conf); static void lower_barrier(conf_t *conf); static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data) { conf_t *conf = data; - r10bio_t *r10_bio; int size = offsetof(struct r10bio_s, devs[conf->copies]); /* allocate a r10bio with room for raid_disks entries in the bios array */ - r10_bio = kzalloc(size, gfp_flags); - if (!r10_bio && conf->mddev) - unplug_slaves(conf->mddev); - - return r10_bio; + return kzalloc(size, gfp_flags); } static void r10bio_pool_free(void *r10_bio, void *data) @@ -106,10 +99,8 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data) int nalloc; r10_bio = r10bio_pool_alloc(gfp_flags, conf); - if (!r10_bio) { - unplug_slaves(conf->mddev); + if (!r10_bio) return NULL; - } if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery)) nalloc = conf->copies; /* resync */ @@ -597,37 +588,6 @@ rb_out: return disk; } -static void unplug_slaves(mddev_t *mddev) -{ - conf_t *conf = mddev->private; - int i; - - rcu_read_lock(); - for (i=0; i < conf->raid_disks; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) { - struct request_queue *r_queue = bdev_get_queue(rdev->bdev); - - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - - blk_unplug(r_queue); - - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - rcu_read_unlock(); -} - -static void raid10_unplug(struct request_queue *q) -{ - mddev_t *mddev = q->queuedata; - - unplug_slaves(q->queuedata); - md_wakeup_thread(mddev->thread); -} - static int raid10_congested(void *data, int bits) { mddev_t *mddev = data; @@ -649,20 +609,16 @@ static int raid10_congested(void *data, int bits) return ret; } -static int flush_pending_writes(conf_t *conf) +static void flush_pending_writes(conf_t *conf) { /* Any writes that have been queued but are awaiting * bitmap updates get flushed here. - * We return 1 if any requests were actually submitted. */ - int rv = 0; - spin_lock_irq(&conf->device_lock); if (conf->pending_bio_list.head) { struct bio *bio; bio = bio_list_get(&conf->pending_bio_list); - blk_remove_plug(conf->mddev->queue); spin_unlock_irq(&conf->device_lock); /* flush any pending bitmap writes to disk * before proceeding w/ I/O */ @@ -674,11 +630,16 @@ static int flush_pending_writes(conf_t *conf) generic_make_request(bio); bio = next; } - rv = 1; } else spin_unlock_irq(&conf->device_lock); - return rv; } + +static void md_kick_device(mddev_t *mddev) +{ + blk_flush_plug(current); + md_wakeup_thread(mddev->thread); +} + /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -708,8 +669,7 @@ static void raise_barrier(conf_t *conf, int force) /* Wait until no block IO is waiting (unless 'force') */ wait_event_lock_irq(conf->wait_barrier, force || !conf->nr_waiting, - conf->resync_lock, - raid10_unplug(conf->mddev->queue)); + conf->resync_lock, md_kick_device(conf->mddev)); /* block any new IO from starting */ conf->barrier++; @@ -717,8 +677,7 @@ static void raise_barrier(conf_t *conf, int force) /* No wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, - raid10_unplug(conf->mddev->queue)); + conf->resync_lock, md_kick_device(conf->mddev)); spin_unlock_irq(&conf->resync_lock); } @@ -739,7 +698,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - raid10_unplug(conf->mddev->queue)); + md_kick_device(conf->mddev)); conf->nr_waiting--; } conf->nr_pending++; @@ -776,7 +735,7 @@ static void freeze_array(conf_t *conf) conf->nr_pending == conf->nr_queued+1, conf->resync_lock, ({ flush_pending_writes(conf); - raid10_unplug(conf->mddev->queue); })); + md_kick_device(conf->mddev); })); spin_unlock_irq(&conf->resync_lock); } @@ -971,7 +930,6 @@ static int make_request(mddev_t *mddev, struct bio * bio) atomic_inc(&r10_bio->remaining); spin_lock_irqsave(&conf->device_lock, flags); bio_list_add(&conf->pending_bio_list, mbio); - blk_plug_device(mddev->queue); spin_unlock_irqrestore(&conf->device_lock, flags); } @@ -988,7 +946,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid10d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync) + if (do_sync || !mddev->bitmap) md_wakeup_thread(mddev->thread); return 0; @@ -1681,7 +1639,6 @@ static void raid10d(mddev_t *mddev) unsigned long flags; conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; - int unplug=0; mdk_rdev_t *rdev; md_check_recovery(mddev); @@ -1689,7 +1646,7 @@ static void raid10d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; - unplug += flush_pending_writes(conf); + flush_pending_writes(conf); spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) { @@ -1703,13 +1660,11 @@ static void raid10d(mddev_t *mddev) mddev = r10_bio->mddev; conf = mddev->private; - if (test_bit(R10BIO_IsSync, &r10_bio->state)) { + if (test_bit(R10BIO_IsSync, &r10_bio->state)) sync_request_write(mddev, r10_bio); - unplug = 1; - } else if (test_bit(R10BIO_IsRecover, &r10_bio->state)) { + else if (test_bit(R10BIO_IsRecover, &r10_bio->state)) recovery_request_write(mddev, r10_bio); - unplug = 1; - } else { + else { int mirror; /* we got a read error. Maybe the drive is bad. Maybe just * the block and we can fix it. @@ -1756,14 +1711,11 @@ static void raid10d(mddev_t *mddev) bio->bi_rw = READ | do_sync; bio->bi_private = r10_bio; bio->bi_end_io = raid10_end_read_request; - unplug = 1; generic_make_request(bio); } } cond_resched(); } - if (unplug) - unplug_slaves(mddev); } @@ -2376,7 +2328,6 @@ static int run(mddev_t *mddev) md_set_array_sectors(mddev, size); mddev->resync_max_sectors = size; - mddev->queue->unplug_fn = raid10_unplug; mddev->queue->backing_dev_info.congested_fn = raid10_congested; mddev->queue->backing_dev_info.congested_data = mddev; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 702812824195..e867ee42b152 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -433,8 +433,6 @@ static int has_failed(raid5_conf_t *conf) return 0; } -static void unplug_slaves(mddev_t *mddev); - static struct stripe_head * get_active_stripe(raid5_conf_t *conf, sector_t sector, int previous, int noblock, int noquiesce) @@ -463,8 +461,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector, < (conf->max_nr_stripes *3/4) || !conf->inactive_blocked), conf->device_lock, - md_raid5_unplug_device(conf) - ); + md_raid5_kick_device(conf)); conf->inactive_blocked = 0; } else init_stripe(sh, sector, previous); @@ -1473,8 +1470,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) wait_event_lock_irq(conf->wait_for_stripe, !list_empty(&conf->inactive_list), conf->device_lock, - unplug_slaves(conf->mddev) - ); + blk_flush_plug(current)); osh = get_free_stripe(conf); spin_unlock_irq(&conf->device_lock); atomic_set(&nsh->count, 1); @@ -3645,58 +3641,19 @@ static void activate_bit_delay(raid5_conf_t *conf) } } -static void unplug_slaves(mddev_t *mddev) +void md_raid5_kick_device(raid5_conf_t *conf) { - raid5_conf_t *conf = mddev->private; - int i; - int devs = max(conf->raid_disks, conf->previous_raid_disks); - - rcu_read_lock(); - for (i = 0; i < devs; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev); - if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) { - struct request_queue *r_queue = bdev_get_queue(rdev->bdev); - - atomic_inc(&rdev->nr_pending); - rcu_read_unlock(); - - blk_unplug(r_queue); - - rdev_dec_pending(rdev, mddev); - rcu_read_lock(); - } - } - rcu_read_unlock(); -} - -void md_raid5_unplug_device(raid5_conf_t *conf) -{ - unsigned long flags; - - spin_lock_irqsave(&conf->device_lock, flags); - - if (plugger_remove_plug(&conf->plug)) { - conf->seq_flush++; - raid5_activate_delayed(conf); - } + blk_flush_plug(current); + raid5_activate_delayed(conf); md_wakeup_thread(conf->mddev->thread); - - spin_unlock_irqrestore(&conf->device_lock, flags); - - unplug_slaves(conf->mddev); } -EXPORT_SYMBOL_GPL(md_raid5_unplug_device); +EXPORT_SYMBOL_GPL(md_raid5_kick_device); static void raid5_unplug(struct plug_handle *plug) { raid5_conf_t *conf = container_of(plug, raid5_conf_t, plug); - md_raid5_unplug_device(conf); -} -static void raid5_unplug_queue(struct request_queue *q) -{ - mddev_t *mddev = q->queuedata; - md_raid5_unplug_device(mddev->private); + md_raid5_kick_device(conf); } int md_raid5_congested(mddev_t *mddev, int bits) @@ -4100,7 +4057,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) * add failed due to overlap. Flush everything * and wait a while */ - md_raid5_unplug_device(conf); + md_raid5_kick_device(conf); release_stripe(sh); schedule(); goto retry; @@ -4365,7 +4322,6 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski if (sector_nr >= max_sector) { /* just being told to finish up .. nothing much to do */ - unplug_slaves(mddev); if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) { end_reshape(conf); @@ -4569,7 +4525,6 @@ static void raid5d(mddev_t *mddev) spin_unlock_irq(&conf->device_lock); async_tx_issue_pending_all(); - unplug_slaves(mddev); pr_debug("--- raid5d inactive\n"); } @@ -5205,7 +5160,6 @@ static int run(mddev_t *mddev) mddev->queue->backing_dev_info.congested_data = mddev; mddev->queue->backing_dev_info.congested_fn = raid5_congested; mddev->queue->queue_lock = &conf->device_lock; - mddev->queue->unplug_fn = raid5_unplug_queue; chunk_size = mddev->chunk_sectors << 9; blk_queue_io_min(mddev->queue, chunk_size); diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 2ace0582b409..8d563a4f022a 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -503,6 +503,6 @@ static inline int algorithm_is_DDF(int layout) } extern int md_raid5_congested(mddev_t *mddev, int bits); -extern void md_raid5_unplug_device(raid5_conf_t *conf); +extern void md_raid5_kick_device(raid5_conf_t *conf); extern int raid5_set_cache_size(mddev_t *mddev, int size); #endif diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index ae7cad185898..b29eb4eaa86e 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -895,11 +895,7 @@ static void i2o_block_request_fn(struct request_queue *q) { struct request *req; - while (!blk_queue_plugged(q)) { - req = blk_peek_request(q); - if (!req) - break; - + while ((req = blk_peek_request(q)) != NULL) { if (req->cmd_type == REQ_TYPE_FS) { struct i2o_block_delayed_request *dreq; struct i2o_block_request *ireq = req->special; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 4e42d030e097..2ae727568df9 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -55,8 +55,7 @@ static int mmc_queue_thread(void *d) spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); - if (!blk_queue_plugged(q)) - req = blk_fetch_request(q); + req = blk_fetch_request(q); mq->req = req; spin_unlock_irq(q->queue_lock); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 794bfd962266..4d2df2f76ea0 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1917,7 +1917,7 @@ static void __dasd_process_request_queue(struct dasd_block *block) return; } /* Now we try to fetch requests from the request queue */ - while (!blk_queue_plugged(queue) && (req = blk_peek_request(queue))) { + while ((req = blk_peek_request(queue))) { if (basedev->features & DASD_FEATURE_READONLY && rq_data_dir(req) == WRITE) { DBF_DEV_EVENT(DBF_ERR, basedev, diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index 55d2d0f4eabc..f061b2527b44 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -161,7 +161,6 @@ tapeblock_requeue(struct work_struct *work) { spin_lock_irq(&device->blk_data.request_queue_lock); while ( - !blk_queue_plugged(queue) && blk_peek_request(queue) && nr_queued < TAPEBLOCK_MIN_REQUEUE ) { diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 998c01be3234..2cefabd5bdb5 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3913,7 +3913,7 @@ fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, if (!get_device(dev)) return; - while (!blk_queue_plugged(q)) { + while (1) { if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED) && !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) break; diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 927e99cb7225..c6fcf76cade5 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -173,11 +173,7 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, int ret; int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *); - while (!blk_queue_plugged(q)) { - req = blk_fetch_request(q); - if (!req) - break; - + while ((req = blk_fetch_request(q)) != NULL) { spin_unlock_irq(q->queue_lock); handler = to_sas_internal(shost->transportt)->f->smp_handler; diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 67f0c09983c8..c1b539d7b0d3 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -392,9 +392,8 @@ static int iblock_do_task(struct se_task *task) { struct se_device *dev = task->task_se_cmd->se_dev; struct iblock_req *req = IBLOCK_REQ(task); - struct iblock_dev *ibd = (struct iblock_dev *)req->ib_dev; - struct request_queue *q = bdev_get_queue(ibd->ibd_bd); struct bio *bio = req->ib_bio, *nbio = NULL; + struct blk_plug plug; int rw; if (task->task_data_direction == DMA_TO_DEVICE) { @@ -412,6 +411,7 @@ static int iblock_do_task(struct se_task *task) rw = READ; } + blk_start_plug(&plug); while (bio) { nbio = bio->bi_next; bio->bi_next = NULL; @@ -421,9 +421,8 @@ static int iblock_do_task(struct se_task *task) submit_bio(rw, bio); bio = nbio; } + blk_finish_plug(&plug); - if (q->unplug_fn) - q->unplug_fn(q); return PYX_TRANSPORT_SENT_TO_TRANSPORT; } -- cgit v1.2.2 From 721a9602e6607417c6bc15b18e97a2f35266c690 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 9 Mar 2011 11:56:30 +0100 Subject: block: kill off REQ_UNPLUG With the plugging now being explicitly controlled by the submitter, callers need not pass down unplugging hints to the block layer. If they want to unplug, it's because they manually plugged on their own - in which case, they should just unplug at will. Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 3 +-- drivers/block/drbd/drbd_receiver.c | 9 +-------- drivers/md/bitmap.c | 2 +- drivers/md/dm-io.c | 2 +- drivers/md/dm-kcopyd.c | 5 +---- drivers/md/md.c | 5 ++--- 8 files changed, 9 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 2096628d6e65..aca302492ff2 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -80,7 +80,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, if ((rw & WRITE) && !test_bit(MD_NO_FUA, &mdev->flags)) rw |= REQ_FUA; - rw |= REQ_UNPLUG | REQ_SYNC; + rw |= REQ_SYNC; bio = bio_alloc(GFP_NOIO, 1); bio->bi_bdev = bdev->md_bdev; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 0b5718e19586..b0bd27dfc1e8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -377,7 +377,7 @@ union p_header { #define DP_HARDBARRIER 1 /* depricated */ #define DP_RW_SYNC 2 /* equals REQ_SYNC */ #define DP_MAY_SET_IN_SYNC 4 -#define DP_UNPLUG 8 /* equals REQ_UNPLUG */ +#define DP_UNPLUG 8 /* not used anymore */ #define DP_FUA 16 /* equals REQ_FUA */ #define DP_FLUSH 32 /* equals REQ_FLUSH */ #define DP_DISCARD 64 /* equals REQ_DISCARD */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 6049cb85310d..8a43ce0edeed 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2477,12 +2477,11 @@ static u32 bio_flags_to_wire(struct drbd_conf *mdev, unsigned long bi_rw) { if (mdev->agreed_pro_version >= 95) return (bi_rw & REQ_SYNC ? DP_RW_SYNC : 0) | - (bi_rw & REQ_UNPLUG ? DP_UNPLUG : 0) | (bi_rw & REQ_FUA ? DP_FUA : 0) | (bi_rw & REQ_FLUSH ? DP_FLUSH : 0) | (bi_rw & REQ_DISCARD ? DP_DISCARD : 0); else - return bi_rw & (REQ_SYNC | REQ_UNPLUG) ? DP_RW_SYNC : 0; + return bi_rw & REQ_SYNC ? DP_RW_SYNC : 0; } /* Used to send write requests diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 84132f8bf8a4..8e68be939deb 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1100,8 +1100,6 @@ next_bio: /* > e->sector, unless this is the first bio */ bio->bi_sector = sector; bio->bi_bdev = mdev->ldev->backing_bdev; - /* we special case some flags in the multi-bio case, see below - * (REQ_UNPLUG) */ bio->bi_rw = rw; bio->bi_private = e; bio->bi_end_io = drbd_endio_sec; @@ -1130,10 +1128,6 @@ next_bio: bios = bios->bi_next; bio->bi_next = NULL; - /* strip off REQ_UNPLUG unless it is the last bio */ - if (bios) - bio->bi_rw &= ~REQ_UNPLUG; - drbd_generic_make_request(mdev, fault_type, bio); } while (bios); return 0; @@ -1621,12 +1615,11 @@ static unsigned long write_flags_to_bio(struct drbd_conf *mdev, u32 dpf) { if (mdev->agreed_pro_version >= 95) return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) | - (dpf & DP_UNPLUG ? REQ_UNPLUG : 0) | (dpf & DP_FUA ? REQ_FUA : 0) | (dpf & DP_FLUSH ? REQ_FUA : 0) | (dpf & DP_DISCARD ? REQ_DISCARD : 0); else - return dpf & DP_RW_SYNC ? (REQ_SYNC | REQ_UNPLUG) : 0; + return dpf & DP_RW_SYNC ? REQ_SYNC : 0; } /* mirrored write */ diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 54bfc274b39a..ca203cb23f3c 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -347,7 +347,7 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait) atomic_inc(&bitmap->pending_writes); set_buffer_locked(bh); set_buffer_mapped(bh); - submit_bh(WRITE | REQ_UNPLUG | REQ_SYNC, bh); + submit_bh(WRITE | REQ_SYNC, bh); bh = bh->b_this_page; } diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 136d4f71a116..76a5af00a26b 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -352,7 +352,7 @@ static void dispatch_io(int rw, unsigned int num_regions, BUG_ON(num_regions > DM_IO_MAX_REGIONS); if (sync) - rw |= REQ_SYNC | REQ_UNPLUG; + rw |= REQ_SYNC; /* * For multiple regions we need to be careful to rewind diff --git a/drivers/md/dm-kcopyd.c b/drivers/md/dm-kcopyd.c index 400cf35094a4..1bb73a13ca40 100644 --- a/drivers/md/dm-kcopyd.c +++ b/drivers/md/dm-kcopyd.c @@ -356,11 +356,8 @@ static int run_io_job(struct kcopyd_job *job) if (job->rw == READ) r = dm_io(&io_req, 1, &job->source, NULL); - else { - if (job->num_dests > 1) - io_req.bi_rw |= REQ_UNPLUG; + else r = dm_io(&io_req, job->num_dests, job->dests, NULL); - } return r; } diff --git a/drivers/md/md.c b/drivers/md/md.c index ca0d79c264b9..28f9c1ee4e3a 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -777,8 +777,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev, bio->bi_end_io = super_written; atomic_inc(&mddev->pending_writes); - submit_bio(REQ_WRITE | REQ_SYNC | REQ_UNPLUG | REQ_FLUSH | REQ_FUA, - bio); + submit_bio(REQ_WRITE | REQ_SYNC | REQ_FLUSH | REQ_FUA, bio); } void md_super_wait(mddev_t *mddev) @@ -806,7 +805,7 @@ int sync_page_io(mdk_rdev_t *rdev, sector_t sector, int size, struct completion event; int ret; - rw |= REQ_SYNC | REQ_UNPLUG; + rw |= REQ_SYNC; bio->bi_bdev = (metadata_op && rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; -- cgit v1.2.2 From 26525618863afcc4aab8b2a83451d37c6f513460 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 09:56:33 +0100 Subject: drbd: only reset online-verify start sector if verify completed For network hickups during online-verify, on the next verify triggered, we by default want to resume where it left off. After any replication link interruption, there will be a (possibly empty) resync. Do not reset online-verify start sector if some resync completed, that would defeats the purpose. Only reset the start sector once a verify run is completed. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index e027446590d3..6cfc5417da8e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -782,6 +782,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) union drbd_state os, ns; struct drbd_work *w; char *khelper_cmd = NULL; + int verify_done = 0; /* Remove all elements from the resync LRU. Since future actions * might set bits in the (main) bitmap, then the entries in the @@ -818,6 +819,8 @@ int drbd_resync_finished(struct drbd_conf *mdev) spin_lock_irq(&mdev->req_lock); os = mdev->state; + verify_done = (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T); + /* This protects us against multiple calls (that can happen in the presence of application IO), and against connectivity loss just before we arrive here. */ if (os.conn <= C_CONNECTED) @@ -827,8 +830,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) ns.conn = C_CONNECTED; dev_info(DEV, "%s done (total %lu sec; paused %lu sec; %lu K/sec)\n", - (os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) ? - "Online verify " : "Resync", + verify_done ? "Online verify " : "Resync", dt + mdev->rs_paused, mdev->rs_paused, dbdt); n_oos = drbd_bm_total_weight(mdev); @@ -905,7 +907,8 @@ out: mdev->rs_total = 0; mdev->rs_failed = 0; mdev->rs_paused = 0; - mdev->ov_start_sector = 0; + if (verify_done) + mdev->ov_start_sector = 0; drbd_md_sync(mdev); -- cgit v1.2.2 From 30b743a2d532af39c9ed13c85d5473f6f620f6c8 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 09:39:06 +0100 Subject: drbd: improve online-verify progress tracking For a partial (resumed) online-verify, initialize rs_total not to total bits, but to number of bits to check in this run, to match the meaning rs_total has for actual resync. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 23 ++++++++++++----------- drivers/block/drbd/drbd_proc.c | 11 ++++++----- drivers/block/drbd/drbd_receiver.c | 3 ++- 3 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8a43ce0edeed..a1a2cb1eadf1 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -961,6 +961,10 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state /* helper for __drbd_set_state */ static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) { + if (mdev->agreed_pro_version < 90) + mdev->ov_start_sector = 0; + mdev->rs_total = drbd_bm_bits(mdev); + mdev->ov_position = 0; if (cs == C_VERIFY_T) { /* starting online verify from an arbitrary position * does not fit well into the existing protocol. @@ -970,11 +974,15 @@ static void set_ov_position(struct drbd_conf *mdev, enum drbd_conns cs) mdev->ov_start_sector = ~(sector_t)0; } else { unsigned long bit = BM_SECT_TO_BIT(mdev->ov_start_sector); - if (bit >= mdev->rs_total) + if (bit >= mdev->rs_total) { mdev->ov_start_sector = BM_BIT_TO_SECT(mdev->rs_total - 1); + mdev->rs_total = 1; + } else + mdev->rs_total -= bit; mdev->ov_position = mdev->ov_start_sector; } + mdev->ov_left = mdev->rs_total; } static void drbd_resume_al(struct drbd_conf *mdev) @@ -1081,7 +1089,7 @@ int __drbd_set_state(struct drbd_conf *mdev, if ((os.conn == C_VERIFY_S || os.conn == C_VERIFY_T) && ns.conn < C_CONNECTED) { mdev->ov_start_sector = - BM_BIT_TO_SECT(mdev->rs_total - mdev->ov_left); + BM_BIT_TO_SECT(drbd_bm_bits(mdev) - mdev->ov_left); dev_info(DEV, "Online Verify reached sector %llu\n", (unsigned long long)mdev->ov_start_sector); } @@ -1106,14 +1114,7 @@ int __drbd_set_state(struct drbd_conf *mdev, unsigned long now = jiffies; int i; - mdev->ov_position = 0; - mdev->rs_total = drbd_bm_bits(mdev); - if (mdev->agreed_pro_version >= 90) - set_ov_position(mdev, ns.conn); - else - mdev->ov_start_sector = 0; - mdev->ov_left = mdev->rs_total - - BM_SECT_TO_BIT(mdev->ov_position); + set_ov_position(mdev, ns.conn); mdev->rs_start = now; mdev->rs_last_events = 0; mdev->rs_last_sect_ev = 0; @@ -1121,7 +1122,7 @@ int __drbd_set_state(struct drbd_conf *mdev, mdev->ov_last_oos_start = 0; for (i = 0; i < DRBD_SYNC_MARKS; i++) { - mdev->rs_mark_left[i] = mdev->rs_total; + mdev->rs_mark_left[i] = mdev->ov_left; mdev->rs_mark_time[i] = now; } diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 7e6ac307e2de..0b20aa837022 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -239,12 +239,13 @@ static int drbd_seq_show(struct seq_file *seq, void *v) mdev->state.conn == C_SYNC_TARGET) drbd_syncer_progress(mdev, seq); - if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) + if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) { + unsigned long bm_bits = drbd_bm_bits(mdev); seq_printf(seq, "\t%3d%% %lu/%lu\n", - (int)((mdev->rs_total-mdev->ov_left) / - (mdev->rs_total/100+1)), - mdev->rs_total - mdev->ov_left, - mdev->rs_total); + (int)((bm_bits-mdev->ov_left) / + (bm_bits/100+1)), + bm_bits - mdev->ov_left, bm_bits); + } if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) { lc_seq_printf_stats(seq, mdev->resync); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8e68be939deb..88856a7f42a0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2005,7 +2005,8 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un mdev->agreed_pro_version >= 90) { mdev->ov_start_sector = sector; mdev->ov_position = sector; - mdev->ov_left = mdev->rs_total - BM_SECT_TO_BIT(sector); + mdev->ov_left = drbd_bm_bits(mdev) - BM_SECT_TO_BIT(sector); + mdev->rs_total = mdev->ov_left; dev_info(DEV, "Online Verify start sector: %llu\n", (unsigned long long)sector); } -- cgit v1.2.2 From de228bba676e1f76e5e5f9444e51bb2db003cefb Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 09:43:15 +0100 Subject: drbd: initialize online-verify progress tracking on verify target For partial (resumed) online verify, initialize the resync step marks once we know what the online verify start sector is. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 88856a7f42a0..3b95eef07546 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2003,10 +2003,16 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un case P_OV_REQUEST: if (mdev->ov_start_sector == ~(sector_t)0 && mdev->agreed_pro_version >= 90) { + unsigned long now = jiffies; + int i; mdev->ov_start_sector = sector; mdev->ov_position = sector; mdev->ov_left = drbd_bm_bits(mdev) - BM_SECT_TO_BIT(sector); mdev->rs_total = mdev->ov_left; + for (i = 0; i < DRBD_SYNC_MARKS; i++) { + mdev->rs_mark_left[i] = mdev->ov_left; + mdev->rs_mark_time[i] = now; + } dev_info(DEV, "Online Verify start sector: %llu\n", (unsigned long long)sector); } -- cgit v1.2.2 From c6ea14dfa391da58e309d0d5041564b3d9dbb82f Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 09:23:37 +0100 Subject: drbd: factor out advancement of resync marks for progress reporting This is in preparation to unify progress reporting of online-verify and resync requests. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index aca302492ff2..b3f18545b469 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -919,6 +919,22 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, } } +void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go) +{ + unsigned long now = jiffies; + unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark]; + int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS; + if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) { + if (mdev->rs_mark_left[mdev->rs_last_mark] != still_to_go && + mdev->state.conn != C_PAUSED_SYNC_T && + mdev->state.conn != C_PAUSED_SYNC_S) { + mdev->rs_mark_time[next] = now; + mdev->rs_mark_left[next] = still_to_go; + mdev->rs_last_mark = next; + } + } +} + /* clear the bit corresponding to the piece of storage in question: * size byte of data starting from sector. Only clear a bits of the affected * one ore more _aligned_ BM_BLOCK_SIZE blocks. @@ -969,19 +985,7 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, */ count = drbd_bm_clear_bits(mdev, sbnr, ebnr); if (count && get_ldev(mdev)) { - unsigned long now = jiffies; - unsigned long last = mdev->rs_mark_time[mdev->rs_last_mark]; - int next = (mdev->rs_last_mark + 1) % DRBD_SYNC_MARKS; - if (time_after_eq(now, last + DRBD_SYNC_MARK_STEP)) { - unsigned long tw = drbd_bm_total_weight(mdev); - if (mdev->rs_mark_left[mdev->rs_last_mark] != tw && - mdev->state.conn != C_PAUSED_SYNC_T && - mdev->state.conn != C_PAUSED_SYNC_S) { - mdev->rs_mark_time[next] = now; - mdev->rs_mark_left[next] = tw; - mdev->rs_last_mark = next; - } - } + drbd_advance_rs_marks(mdev, drbd_bm_total_weight(mdev)); spin_lock_irqsave(&mdev->al_lock, flags); drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE); spin_unlock_irqrestore(&mdev->al_lock, flags); -- cgit v1.2.2 From ea5442aff68c559c951373739201721185191748 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 09:48:01 +0100 Subject: drbd: advance progress step marks for online-verify Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_receiver.c | 8 +++++++- drivers/block/drbd/drbd_worker.c | 8 +++++++- 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index b0bd27dfc1e8..6cba131011d5 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1619,6 +1619,7 @@ extern int drbd_rs_del_all(struct drbd_conf *mdev); extern void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size); extern int drbd_al_read_log(struct drbd_conf *mdev, struct drbd_backing_dev *); +extern void drbd_advance_rs_marks(struct drbd_conf *mdev, unsigned long still_to_go); extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, const char *file, const unsigned int line); #define drbd_set_in_sync(mdev, sector, size) \ diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 3b95eef07546..10db70a23376 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4340,7 +4340,13 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) drbd_rs_complete_io(mdev, sector); dec_rs_pending(mdev); - if (--mdev->ov_left == 0) { + --mdev->ov_left; + + /* let's advance progress step marks only for every other megabyte */ + if ((mdev->ov_left & 0x200) == 0x200) + drbd_advance_rs_marks(mdev, mdev->ov_left); + + if (mdev->ov_left == 0) { w = kmalloc(sizeof(*w), GFP_NOIO); if (w) { w->cb = w_ov_finished; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 6cfc5417da8e..a050eb0d93ba 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1185,7 +1185,13 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) drbd_free_ee(mdev, e); - if (--mdev->ov_left == 0) { + --mdev->ov_left; + + /* let's advance progress step marks only for every other megabyte */ + if ((mdev->ov_left & 0x200) == 0x200) + drbd_advance_rs_marks(mdev, mdev->ov_left); + + if (mdev->ov_left == 0) { ov_oos_print(mdev); drbd_resync_finished(mdev); } -- cgit v1.2.2 From 439d595379f87ec95249da21122eb085866f8ba9 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 09:52:46 +0100 Subject: drbd: show progress bar and ETA for online-verify Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 5 +++- drivers/block/drbd/drbd_proc.c | 52 ++++++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 6cba131011d5..7131bf2af6ae 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2157,7 +2157,10 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, * units of BM_BLOCK_SIZE. * for the percentage, we don't care. */ - *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; + if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) + *bits_left = mdev->ov_left; + else + *bits_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; /* >> 10 to prevent overflow, * +1 to prevent division by zero */ if (*bits_left > mdev->rs_total) { diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 0b20aa837022..0ec6f4b6a4a8 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -45,6 +45,19 @@ const struct file_operations drbd_proc_fops = { .release = single_release, }; +void seq_printf_with_thousands_grouping(struct seq_file *seq, long v) +{ + /* v is in kB/sec. We don't expect TiByte/sec yet. */ + if (unlikely(v >= 1000000)) { + /* cool: > GiByte/s */ + seq_printf(seq, "%ld,", v / 1000000); + v /= 1000000; + seq_printf(seq, "%03ld,%03ld", v/1000, v % 1000); + } else if (likely(v >= 1000)) + seq_printf(seq, "%ld,%03ld", v/1000, v % 1000); + else + seq_printf(seq, "%ld", v); +} /*lge * progress bars shamelessly adapted from driver/md/md.c @@ -94,6 +107,7 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) /* Rolling marks. last_mark+1 may just now be modified. last_mark+2 is * at least (DRBD_SYNC_MARKS-2)*DRBD_SYNC_MARK_STEP old, and has at * least DRBD_SYNC_MARK_STEP time before it will be modified. */ + /* ------------------------ ~18s average ------------------------ */ i = (mdev->rs_last_mark + 2) % DRBD_SYNC_MARKS; dt = (jiffies - mdev->rs_mark_time[i]) / HZ; if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) @@ -107,14 +121,29 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) seq_printf(seq, "finish: %lu:%02lu:%02lu", rt / 3600, (rt % 3600) / 60, rt % 60); - /* current speed average over (SYNC_MARKS * SYNC_MARK_STEP) jiffies */ dbdt = Bit2KB(db/dt); - if (dbdt > 1000) - seq_printf(seq, " speed: %ld,%03ld", - dbdt/1000, dbdt % 1000); - else - seq_printf(seq, " speed: %ld", dbdt); + seq_printf(seq, " speed: "); + seq_printf_with_thousands_grouping(seq, dbdt); + seq_printf(seq, " ("); + /* ------------------------- ~3s average ------------------------ */ + if (proc_details >= 1) { + /* this is what drbd_rs_should_slow_down() uses */ + i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; + dt = (jiffies - mdev->rs_mark_time[i]) / HZ; + if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) + stalled = 1; + + if (!dt) + dt++; + db = mdev->rs_mark_left[i] - rs_left; + rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */ + + dbdt = Bit2KB(db/dt); + seq_printf_with_thousands_grouping(seq, dbdt); + seq_printf(seq, " -- "); + } + /* --------------------- long term average ---------------------- */ /* mean speed since syncer started * we do account for PausedSync periods */ dt = (jiffies - mdev->rs_start - mdev->rs_paused) / HZ; @@ -122,11 +151,8 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) dt = 1; db = mdev->rs_total - rs_left; dbdt = Bit2KB(db/dt); - if (dbdt > 1000) - seq_printf(seq, " (%ld,%03ld)", - dbdt/1000, dbdt % 1000); - else - seq_printf(seq, " (%ld)", dbdt); + seq_printf_with_thousands_grouping(seq, dbdt); + seq_printf(seq, ")"); if (mdev->state.conn == C_SYNC_TARGET) { if (mdev->c_sync_rate > 1000) @@ -236,7 +262,9 @@ static int drbd_seq_show(struct seq_file *seq, void *v) Bit2KB(drbd_bm_total_weight(mdev))); } if (mdev->state.conn == C_SYNC_SOURCE || - mdev->state.conn == C_SYNC_TARGET) + mdev->state.conn == C_SYNC_TARGET || + mdev->state.conn == C_VERIFY_S || + mdev->state.conn == C_VERIFY_T) drbd_syncer_progress(mdev, seq); if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) { -- cgit v1.2.2 From 9bd28d3c90c80c7ec46085de281b38f67331da41 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 09:55:18 +0100 Subject: drbd: factor out drbd_rs_controller_reset Preparation patch to be able to use the auto-throttling resync controller for online-verify requests as well. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_worker.c | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 7131bf2af6ae..85207b275e41 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1499,6 +1499,7 @@ extern int drbd_resync_finished(struct drbd_conf *mdev); extern int drbd_md_sync_page_io(struct drbd_conf *mdev, struct drbd_backing_dev *bdev, sector_t sector, int rw); extern void drbd_ov_oos_found(struct drbd_conf*, sector_t, int); +extern void drbd_rs_controller_reset(struct drbd_conf *mdev); static inline void ov_oos_print(struct drbd_conf *mdev) { diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index a050eb0d93ba..971e9b3b13ba 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1439,6 +1439,17 @@ int drbd_alter_sa(struct drbd_conf *mdev, int na) return retcode; } +void drbd_rs_controller_reset(struct drbd_conf *mdev) +{ + atomic_set(&mdev->rs_sect_in, 0); + atomic_set(&mdev->rs_sect_ev, 0); + mdev->rs_in_flight = 0; + mdev->rs_planed = 0; + spin_lock(&mdev->peer_seq_lock); + fifo_set(&mdev->rs_plan_s, 0); + spin_unlock(&mdev->peer_seq_lock); +} + /** * drbd_start_resync() - Start the resync process * @mdev: DRBD device. @@ -1556,13 +1567,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) drbd_resync_finished(mdev); } - atomic_set(&mdev->rs_sect_in, 0); - atomic_set(&mdev->rs_sect_ev, 0); - mdev->rs_in_flight = 0; - mdev->rs_planed = 0; - spin_lock(&mdev->peer_seq_lock); - fifo_set(&mdev->rs_plan_s, 0); - spin_unlock(&mdev->peer_seq_lock); + drbd_rs_controller_reset(mdev); /* ns.conn may already be != mdev->state.conn, * we may have been paused in between, or become paused until * the timer triggers. -- cgit v1.2.2 From e65f440d474d7d6a6fd8a2c844e851d8c96ed9c5 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 10:04:07 +0100 Subject: drbd: factor out drbd_rs_number_requests Preparation patch to be able to use the auto-throttling resync controller for online-verify requests as well. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 61 +++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 971e9b3b13ba..6d111c8515f7 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -492,6 +492,32 @@ int drbd_rs_controller(struct drbd_conf *mdev) return req_sect; } +int drbd_rs_number_requests(struct drbd_conf *mdev) +{ + int number; + if (mdev->rs_plan_s.size) { /* mdev->sync_conf.c_plan_ahead */ + number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9); + mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME; + } else { + mdev->c_sync_rate = mdev->sync_conf.rate; + number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ); + } + + /* Throttle resync on lower level disk activity, which may also be + * caused by application IO on Primary/SyncTarget. + * Keep this after the call to drbd_rs_controller, as that assumes + * to be called as precisely as possible every SLEEP_TIME, + * and would be confused otherwise. */ + if (number && drbd_rs_should_slow_down(mdev)) { + mdev->c_sync_rate = 1; + number = 0; + } + + /* ignore the amount of pending requests, the resync controller should + * throttle down to incoming reply rate soon enough anyways. */ + return number; +} + int w_make_resync_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { @@ -499,7 +525,7 @@ int w_make_resync_request(struct drbd_conf *mdev, sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); int max_segment_size; - int number, rollback_i, size, pe, mx; + int number, rollback_i, size; int align, queued, sndbuf; int i = 0; @@ -537,39 +563,10 @@ int w_make_resync_request(struct drbd_conf *mdev, mdev->agreed_pro_version < 94 ? queue_max_segment_size(mdev->rq_queue) : mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_SEGMENT_SIZE; - if (mdev->rs_plan_s.size) { /* mdev->sync_conf.c_plan_ahead */ - number = drbd_rs_controller(mdev) >> (BM_BLOCK_SHIFT - 9); - mdev->c_sync_rate = number * HZ * (BM_BLOCK_SIZE / 1024) / SLEEP_TIME; - } else { - mdev->c_sync_rate = mdev->sync_conf.rate; - number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ); - } - - /* Throttle resync on lower level disk activity, which may also be - * caused by application IO on Primary/SyncTarget. - * Keep this after the call to drbd_rs_controller, as that assumes - * to be called as precisely as possible every SLEEP_TIME, - * and would be confused otherwise. */ - if (drbd_rs_should_slow_down(mdev)) + number = drbd_rs_number_requests(mdev); + if (number == 0) goto requeue; - mutex_lock(&mdev->data.mutex); - if (mdev->data.socket) - mx = mdev->data.socket->sk->sk_rcvbuf / sizeof(struct p_block_req); - else - mx = 1; - mutex_unlock(&mdev->data.mutex); - - /* For resync rates >160MB/sec, allow more pending RS requests */ - if (number > mx) - mx = number; - - /* Limit the number of pending RS requests to no more than the peer's receive buffer */ - pe = atomic_read(&mdev->rs_pending_cnt); - if ((pe + number) > mx) { - number = mx - pe; - } - for (i = 0; i < number; i++) { /* Stop generating RS requests, when half of the send buffer is filled */ mutex_lock(&mdev->data.mutex); -- cgit v1.2.2 From 2649f0809f55e4df98c333a2b85c6fc8fee04804 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 5 Nov 2010 10:05:47 +0100 Subject: drbd: use the resync controller for online-verify requests as well Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 ++ drivers/block/drbd/drbd_proc.c | 3 ++- drivers/block/drbd/drbd_receiver.c | 10 ++++++++-- drivers/block/drbd/drbd_worker.c | 8 ++------ 4 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index a1a2cb1eadf1..6afb81f807bd 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1126,6 +1126,8 @@ int __drbd_set_state(struct drbd_conf *mdev, mdev->rs_mark_time[i] = now; } + drbd_rs_controller_reset(mdev); + if (ns.conn == C_VERIFY_S) { dev_info(DEV, "Starting Online Verify from sector %llu\n", (unsigned long long)mdev->ov_position); diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 0ec6f4b6a4a8..fab3fde3477b 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -154,7 +154,8 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) seq_printf_with_thousands_grouping(seq, dbdt); seq_printf(seq, ")"); - if (mdev->state.conn == C_SYNC_TARGET) { + if (mdev->state.conn == C_SYNC_TARGET || + mdev->state.conn == C_VERIFY_S) { if (mdev->c_sync_rate > 1000) seq_printf(seq, " want: %d,%03d", mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 10db70a23376..1c56af03c38b 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1883,8 +1883,12 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev) /* sync speed average over the last 2*DRBD_SYNC_MARK_STEP, * approx. */ - i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-2) % DRBD_SYNC_MARKS; - rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; + i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; + + if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) + rs_left = mdev->ov_left; + else + rs_left = drbd_bm_total_weight(mdev) - mdev->rs_failed; dt = ((long)jiffies - (long)mdev->rs_mark_time[i]) / HZ; if (!dt) @@ -1992,6 +1996,8 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un D_ASSERT(mdev->agreed_pro_version >= 89); e->w.cb = w_e_end_csum_rs_req; } else if (cmd == P_OV_REPLY) { + /* track progress, we may need to throttle */ + atomic_add(size >> 9, &mdev->rs_sect_in); e->w.cb = w_e_end_ov_reply; dec_rs_pending(mdev); /* drbd_rs_begin_io done when we sent this request, diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 6d111c8515f7..af805efc94d7 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -708,11 +708,7 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca return 0; } - number = SLEEP_TIME*mdev->sync_conf.rate / ((BM_BLOCK_SIZE/1024)*HZ); - if (atomic_read(&mdev->rs_pending_cnt) > number) - goto requeue; - - number -= atomic_read(&mdev->rs_pending_cnt); + number = drbd_rs_number_requests(mdev); sector = mdev->ov_position; for (i = 0; i < number; i++) { @@ -741,11 +737,11 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca mdev->ov_position = sector; requeue: + mdev->rs_in_flight += (i << (BM_BLOCK_SHIFT - 9)); mod_timer(&mdev->resync_timer, jiffies + SLEEP_TIME); return 1; } - int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { kfree(w); -- cgit v1.2.2 From 18edc0b9d7dac2f74117a0bdb98f2e705eb74d82 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 9 Nov 2010 14:12:10 +0100 Subject: drbd: fix potential wrap of 32bit oos:%lu display in /proc/drbd When converting bits (4k resolution, still) to kB, we shift left. If it was a large number of bits on a 32bit box (>= 4 TiB storage), we may wrap the 32bit unsigned long base type, resulting in incorrect display. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_proc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index fab3fde3477b..07368b75392a 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -259,8 +259,9 @@ static int drbd_seq_show(struct seq_file *seq, void *v) mdev->epochs, write_ordering_chars[mdev->write_ordering] ); - seq_printf(seq, " oos:%lu\n", - Bit2KB(drbd_bm_total_weight(mdev))); + seq_printf(seq, " oos:%llu\n", + Bit2KB((unsigned long long) + drbd_bm_total_weight(mdev))); } if (mdev->state.conn == C_SYNC_SOURCE || mdev->state.conn == C_SYNC_TARGET || -- cgit v1.2.2 From 5f9915bbb8e0975ce99f893c29b8e89100b33399 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 9 Nov 2010 14:15:24 +0100 Subject: drbd: further converge progress display of resync and online-verify Show progressbar and ETA always, with proc_details >= 1 also show the current sector position for both resync and online-verify on both nodes. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_proc.c | 46 ++++++++++++++++++++++---------------- drivers/block/drbd/drbd_receiver.c | 4 ++++ 2 files changed, 31 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 07368b75392a..329b66a91e44 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -84,7 +84,12 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) seq_printf(seq, "."); seq_printf(seq, "] "); - seq_printf(seq, "sync'ed:%3u.%u%% ", res / 10, res % 10); + if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) + seq_printf(seq, "verified:"); + else + seq_printf(seq, "sync'ed:"); + seq_printf(seq, "%3u.%u%% ", res / 10, res % 10); + /* if more than 1 GB display in MB */ if (mdev->rs_total > 0x100000L) seq_printf(seq, "(%lu/%lu)M\n\t", @@ -130,14 +135,9 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) /* this is what drbd_rs_should_slow_down() uses */ i = (mdev->rs_last_mark + DRBD_SYNC_MARKS-1) % DRBD_SYNC_MARKS; dt = (jiffies - mdev->rs_mark_time[i]) / HZ; - if (dt > (DRBD_SYNC_MARK_STEP * DRBD_SYNC_MARKS)) - stalled = 1; - if (!dt) dt++; db = mdev->rs_mark_left[i] - rs_left; - rt = (dt * (rs_left / (db/100+1)))/100; /* seconds */ - dbdt = Bit2KB(db/dt); seq_printf_with_thousands_grouping(seq, dbdt); seq_printf(seq, " -- "); @@ -156,13 +156,29 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) if (mdev->state.conn == C_SYNC_TARGET || mdev->state.conn == C_VERIFY_S) { - if (mdev->c_sync_rate > 1000) - seq_printf(seq, " want: %d,%03d", - mdev->c_sync_rate / 1000, mdev->c_sync_rate % 1000); - else - seq_printf(seq, " want: %d", mdev->c_sync_rate); + seq_printf(seq, " want: "); + seq_printf_with_thousands_grouping(seq, mdev->c_sync_rate); } seq_printf(seq, " K/sec%s\n", stalled ? " (stalled)" : ""); + + if (proc_details >= 1) { + /* 64 bit: + * we convert to sectors in the display below. */ + u64 bm_bits = drbd_bm_bits(mdev); + u64 bit_pos; + if (mdev->state.conn == C_VERIFY_S || + mdev->state.conn == C_VERIFY_T) + bit_pos = bm_bits - mdev->ov_left; + else + bit_pos = mdev->bm_resync_fo; + /* Total sectors may be slightly off for oddly + * sized devices. So what. */ + seq_printf(seq, + "\t%3d%% sector pos: %llu/%llu\n", + (int)(bit_pos / (bm_bits/100+1)), + (unsigned long long) BM_BIT_TO_SECT(bit_pos), + (unsigned long long) BM_BIT_TO_SECT(bm_bits)); + } } static void resync_dump_detail(struct seq_file *seq, struct lc_element *e) @@ -269,14 +285,6 @@ static int drbd_seq_show(struct seq_file *seq, void *v) mdev->state.conn == C_VERIFY_T) drbd_syncer_progress(mdev, seq); - if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) { - unsigned long bm_bits = drbd_bm_bits(mdev); - seq_printf(seq, "\t%3d%% %lu/%lu\n", - (int)((bm_bits-mdev->ov_left) / - (bm_bits/100+1)), - bm_bits - mdev->ov_left, bm_bits); - } - if (proc_details >= 1 && get_ldev_if_state(mdev, D_FAILED)) { lc_seq_printf_stats(seq, mdev->resync); lc_seq_printf_stats(seq, mdev->act_log); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 1c56af03c38b..d0e19a242af4 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1974,6 +1974,8 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un case P_RS_DATA_REQUEST: e->w.cb = w_e_end_rsdata_req; fault_type = DRBD_FAULT_RS_RD; + /* used in the sector offset progress display */ + mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); break; case P_OV_REPLY: @@ -1995,6 +1997,8 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un if (cmd == P_CSUM_RS_REQUEST) { D_ASSERT(mdev->agreed_pro_version >= 89); e->w.cb = w_e_end_csum_rs_req; + /* used in the sector offset progress display */ + mdev->bm_resync_fo = BM_SECT_TO_BIT(sector); } else if (cmd == P_OV_REPLY) { /* track progress, we may need to throttle */ atomic_add(size >> 9, &mdev->rs_sect_in); -- cgit v1.2.2 From 470be44ab1841f3261a4d758450a42e6b79e9551 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 10 Nov 2010 10:36:52 +0100 Subject: drbd: detect modification of in-flight buffers With data-integrity digest enabled, double-check on the sending side for modifications by upper layers of buffers under write back, so we can tell it appart from corruption on the "wire". Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 28 +++++++++++++++++++++++++++- drivers/block/drbd/drbd_receiver.c | 3 ++- 2 files changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 6afb81f807bd..451fc36a85cb 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2537,10 +2537,36 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); } if (ok) { - if (mdev->net_conf->wire_protocol == DRBD_PROT_A) + /* For protocol A, we have to memcpy the payload into + * socket buffers, as we may complete right away + * as soon as we handed it over to tcp, at which point the data + * pages may become invalid. + * + * For data-integrity enabled, we copy it as well, so we can be + * sure that even if the bio pages may still be modified, it + * won't change the data on the wire, thus if the digest checks + * out ok after sending on this side, but does not fit on the + * receiving side, we sure have detected corruption elsewhere. + */ + if (mdev->net_conf->wire_protocol == DRBD_PROT_A || dgs) ok = _drbd_send_bio(mdev, req->master_bio); else ok = _drbd_send_zc_bio(mdev, req->master_bio); + + /* double check digest, sometimes buffers have been modified in flight. */ + if (dgs > 0 && dgs <= 64) { + /* 64 byte, 512 bit, is the larges digest size + * currently supported in kernel crypto. */ + unsigned char digest[64]; + drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, digest); + if (memcmp(mdev->int_dig_out, digest, dgs)) { + dev_warn(DEV, + "Digest mismatch, buffer modified by upper layers during write: %llus +%u\n", + (unsigned long long)req->sector, req->size); + } + } /* else if (dgs > 64) { + ... Be noisy about digest too large ... + } */ } drbd_put_data_sock(mdev); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index d0e19a242af4..ca213c6e5f9d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1281,7 +1281,8 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ if (dgs) { drbd_csum_ee(mdev, mdev->integrity_r_tfm, e, dig_vv); if (memcmp(dig_in, dig_vv, dgs)) { - dev_err(DEV, "Digest integrity check FAILED.\n"); + dev_err(DEV, "Digest integrity check FAILED: %llus +%u\n", + (unsigned long long)sector, data_size); drbd_bcast_ee(mdev, "digest failed", dgs, dig_in, dig_vv, e); drbd_free_ee(mdev, e); -- cgit v1.2.2 From 3129b1b9aed15bbebde1b2a5719434273feb295d Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 11 Nov 2010 10:47:05 +0100 Subject: drbd: debug: limit nelink-broadcast of request on digest mismatch to 32k We used to be limited to 32k requests, but have increased that limit to 128k now. This part of the code can only deal with 32k, it would scramble arbitrary pages for larger requests. As it is used for debugging only anyways, it is ok to simply truncate the dumped data here. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 8cbfaa687d72..dad559810ed6 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2398,10 +2398,11 @@ void drbd_bcast_ee(struct drbd_conf *mdev, tl = tl_add_int(tl, T_ee_sector, &e->sector); tl = tl_add_int(tl, T_ee_block_id, &e->block_id); + /* dump the first 32k */ + len = min_t(unsigned, e->size, 32 << 10); put_unaligned(T_ee_data, tl++); - put_unaligned(e->size, tl++); + put_unaligned(len, tl++); - len = e->size; page = e->pages; page_chain_for_each(page) { void *d = kmap_atomic(page, KM_USER0); @@ -2410,6 +2411,8 @@ void drbd_bcast_ee(struct drbd_conf *mdev, kunmap_atomic(d, KM_USER0); tl = (unsigned short*)((char*)tl + l); len -= l; + if (len == 0) + break; } put_unaligned(TT_END, tl++); /* Close the tag list */ -- cgit v1.2.2 From 1816a2b47afae838e53a177d5d166cc7be97d6b5 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 11 Nov 2010 15:19:07 +0100 Subject: drbd: properly use max_hw_sectors to limit the our bio size To ease tracking of bios in some hash tables, we want it to not cross certain boundaries (128k, used to be 32k). We limit the maximum bio size using queue parameters. Historically some defines and variables we use there have been named max_segment_size, which was misguided. Rename them to max_bio_size, and use [blk_]queue_max_hw_sectors where appropriate. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 8 ++++---- drivers/block/drbd/drbd_int.h | 4 ++-- drivers/block/drbd/drbd_main.c | 6 +++--- drivers/block/drbd/drbd_nl.c | 27 +++++++++++++-------------- drivers/block/drbd/drbd_receiver.c | 18 +++++++++--------- drivers/block/drbd/drbd_req.c | 8 ++++---- drivers/block/drbd/drbd_worker.c | 12 ++++++------ 7 files changed, 41 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index b3f18545b469..b4adb58c7472 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -952,7 +952,7 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, int wake_up = 0; unsigned long flags; - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "drbd_set_in_sync: sector=%llus size=%d nonsense!\n", (unsigned long long)sector, size); return; @@ -1002,7 +1002,7 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, /* * this is intended to set one request worth of data out of sync. * affects at least 1 bit, - * and at most 1+DRBD_MAX_SEGMENT_SIZE/BM_BLOCK_SIZE bits. + * and at most 1+DRBD_MAX_BIO_SIZE/BM_BLOCK_SIZE bits. * * called by tl_clear and drbd_send_dblock (==drbd_make_request). * so this can be _any_ process. @@ -1015,7 +1015,7 @@ void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, unsigned int enr, count; struct lc_element *e; - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "sector: %llus, size: %d\n", (unsigned long long)sector, size); return; @@ -1387,7 +1387,7 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size) sector_t esector, nr_sectors; int wake_up = 0; - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "drbd_rs_failed_io: sector=%llus size=%d nonsense!\n", (unsigned long long)sector, size); return; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 85207b275e41..bcba2742cfba 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -512,7 +512,7 @@ struct p_sizes { u64 d_size; /* size of disk */ u64 u_size; /* user requested size */ u64 c_size; /* current exported size */ - u32 max_segment_size; /* Maximal size of a BIO */ + u32 max_bio_size; /* Maximal size of a BIO */ u16 queue_order_type; /* not yet implemented in DRBD*/ u16 dds_flags; /* use enum dds_flags here. */ } __packed; @@ -1398,7 +1398,7 @@ struct bm_extent { * With a value of 8 all IO in one 128K block make it to the same slot of the * hash table. */ #define HT_SHIFT 8 -#define DRBD_MAX_SEGMENT_SIZE (1U<<(9+HT_SHIFT)) +#define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT)) #define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 451fc36a85cb..9d9c2ed31e9a 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1924,7 +1924,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl p.d_size = cpu_to_be64(d_size); p.u_size = cpu_to_be64(u_size); p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev)); - p.max_segment_size = cpu_to_be32(queue_max_segment_size(mdev->rq_queue)); + p.max_bio_size = cpu_to_be32(queue_max_hw_sectors(mdev->rq_queue) << 9); p.queue_order_type = cpu_to_be16(q_order_type); p.dds_flags = cpu_to_be16(flags); @@ -2952,7 +2952,7 @@ static void drbd_destroy_mempools(void) static int drbd_create_mempools(void) { struct page *page; - const int number = (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE) * minor_count; + const int number = (DRBD_MAX_BIO_SIZE/PAGE_SIZE) * minor_count; int i; /* prepare our caches and mempools */ @@ -3218,7 +3218,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) q->backing_dev_info.congested_data = mdev; blk_queue_make_request(q, drbd_make_request_26); - blk_queue_max_segment_size(q, DRBD_MAX_SEGMENT_SIZE); + blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE >> 9); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); blk_queue_merge_bvec(q, drbd_merge_bvec); q->queue_lock = &mdev->req_lock; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index dad559810ed6..9e27d82a9a19 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -765,22 +765,21 @@ static int drbd_check_al_size(struct drbd_conf *mdev) return 0; } -void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_seg_s) __must_hold(local) +void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size) __must_hold(local) { struct request_queue * const q = mdev->rq_queue; struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue; int max_segments = mdev->ldev->dc.max_bio_bvecs; + int max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9); - max_seg_s = min(queue_max_sectors(b) * queue_logical_block_size(b), max_seg_s); - - blk_queue_max_hw_sectors(q, max_seg_s >> 9); - blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS); - blk_queue_max_segment_size(q, max_seg_s); blk_queue_logical_block_size(q, 512); - blk_queue_segment_boundary(q, PAGE_SIZE-1); - blk_stack_limits(&q->limits, &b->limits, 0); + blk_queue_max_hw_sectors(q, max_hw_sectors); + /* This is the workaround for "bio would need to, but cannot, be split" */ + blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS); + blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1); + blk_queue_stack_limits(q, b); - dev_info(DEV, "max_segment_size ( = BIO size ) = %u\n", queue_max_segment_size(q)); + dev_info(DEV, "max BIO size = %u\n", queue_max_hw_sectors(q) << 9); if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) { dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n", @@ -858,7 +857,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp struct block_device *bdev; struct lru_cache *resync_lru = NULL; union drbd_state ns, os; - unsigned int max_seg_s; + unsigned int max_bio_size; int rv; int cp_discovered = 0; int logical_block_size; @@ -1109,20 +1108,20 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp mdev->read_cnt = 0; mdev->writ_cnt = 0; - max_seg_s = DRBD_MAX_SEGMENT_SIZE; + max_bio_size = DRBD_MAX_BIO_SIZE; if (mdev->state.conn == C_CONNECTED) { /* We are Primary, Connected, and now attach a new local * backing store. We must not increase the user visible maximum * bio size on this device to something the peer may not be * able to handle. */ if (mdev->agreed_pro_version < 94) - max_seg_s = queue_max_segment_size(mdev->rq_queue); + max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9; else if (mdev->agreed_pro_version == 94) - max_seg_s = DRBD_MAX_SIZE_H80_PACKET; + max_bio_size = DRBD_MAX_SIZE_H80_PACKET; /* else: drbd 8.3.9 and later, stay with default */ } - drbd_setup_queue_param(mdev, max_seg_s); + drbd_setup_queue_param(mdev, max_bio_size); /* If I am currently not R_PRIMARY, * but meta data primary indicator is set, diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index ca213c6e5f9d..79e7b57006b1 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -277,7 +277,7 @@ static void drbd_pp_free(struct drbd_conf *mdev, struct page *page, int is_net) atomic_t *a = is_net ? &mdev->pp_in_use_by_net : &mdev->pp_in_use; int i; - if (drbd_pp_vacant > (DRBD_MAX_SEGMENT_SIZE/PAGE_SIZE)*minor_count) + if (drbd_pp_vacant > (DRBD_MAX_BIO_SIZE/PAGE_SIZE)*minor_count) i = page_chain_free(page); else { struct page *tmp; @@ -1240,7 +1240,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ data_size -= dgs; ERR_IF(data_size & 0x1ff) return NULL; - ERR_IF(data_size > DRBD_MAX_SEGMENT_SIZE) return NULL; + ERR_IF(data_size > DRBD_MAX_BIO_SIZE) return NULL; /* even though we trust out peer, * we sometimes have to double check. */ @@ -1917,7 +1917,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un sector = be64_to_cpu(p->sector); size = be32_to_cpu(p->blksize); - if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_SEGMENT_SIZE) { + if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, (unsigned long long)sector, size); return FALSE; @@ -2897,7 +2897,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned { struct p_sizes *p = &mdev->data.rbuf.sizes; enum determine_dev_size dd = unchanged; - unsigned int max_seg_s; + unsigned int max_bio_size; sector_t p_size, p_usize, my_usize; int ldsc = 0; /* local disk size changed */ enum dds_flags ddsf; @@ -2970,14 +2970,14 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } if (mdev->agreed_pro_version < 94) - max_seg_s = be32_to_cpu(p->max_segment_size); + max_bio_size = be32_to_cpu(p->max_bio_size); else if (mdev->agreed_pro_version == 94) - max_seg_s = DRBD_MAX_SIZE_H80_PACKET; + max_bio_size = DRBD_MAX_SIZE_H80_PACKET; else /* drbd 8.3.8 onwards */ - max_seg_s = DRBD_MAX_SEGMENT_SIZE; + max_bio_size = DRBD_MAX_BIO_SIZE; - if (max_seg_s != queue_max_segment_size(mdev->rq_queue)) - drbd_setup_queue_param(mdev, max_seg_s); + if (max_bio_size != queue_max_hw_sectors(mdev->rq_queue) << 9) + drbd_setup_queue_param(mdev, max_bio_size); drbd_setup_order_type(mdev, be16_to_cpu(p->queue_order_type)); put_ldev(mdev); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index ad3fc6228f27..08f53ce9b88f 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1047,7 +1047,7 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) /* can this bio be split generically? * Maybe add our own split-arbitrary-bios function. */ - if (bio->bi_vcnt != 1 || bio->bi_idx != 0 || bio->bi_size > DRBD_MAX_SEGMENT_SIZE) { + if (bio->bi_vcnt != 1 || bio->bi_idx != 0 || bio->bi_size > DRBD_MAX_BIO_SIZE) { /* rather error out here than BUG in bio_split */ dev_err(DEV, "bio would need to, but cannot, be split: " "(vcnt=%u,idx=%u,size=%u,sector=%llu)\n", @@ -1098,7 +1098,7 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) } /* This is called by bio_add_page(). With this function we reduce - * the number of BIOs that span over multiple DRBD_MAX_SEGMENT_SIZEs + * the number of BIOs that span over multiple DRBD_MAX_BIO_SIZEs * units (was AL_EXTENTs). * * we do the calculation within the lower 32bit of the byte offsets, @@ -1118,8 +1118,8 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct unsigned int bio_size = bvm->bi_size; int limit, backing_limit; - limit = DRBD_MAX_SEGMENT_SIZE - - ((bio_offset & (DRBD_MAX_SEGMENT_SIZE-1)) + bio_size); + limit = DRBD_MAX_BIO_SIZE + - ((bio_offset & (DRBD_MAX_BIO_SIZE-1)) + bio_size); if (limit < 0) limit = 0; if (bio_size == 0) { diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index af805efc94d7..782d87237cb4 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -524,7 +524,7 @@ int w_make_resync_request(struct drbd_conf *mdev, unsigned long bit; sector_t sector; const sector_t capacity = drbd_get_capacity(mdev->this_bdev); - int max_segment_size; + int max_bio_size; int number, rollback_i, size; int align, queued, sndbuf; int i = 0; @@ -559,9 +559,9 @@ int w_make_resync_request(struct drbd_conf *mdev, /* starting with drbd 8.3.8, we can handle multi-bio EEs, * if it should be necessary */ - max_segment_size = - mdev->agreed_pro_version < 94 ? queue_max_segment_size(mdev->rq_queue) : - mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_SEGMENT_SIZE; + max_bio_size = + mdev->agreed_pro_version < 94 ? queue_max_hw_sectors(mdev->rq_queue) << 9 : + mdev->agreed_pro_version < 95 ? DRBD_MAX_SIZE_H80_PACKET : DRBD_MAX_BIO_SIZE; number = drbd_rs_number_requests(mdev); if (number == 0) @@ -605,7 +605,7 @@ next_sector: goto next_sector; } -#if DRBD_MAX_SEGMENT_SIZE > BM_BLOCK_SIZE +#if DRBD_MAX_BIO_SIZE > BM_BLOCK_SIZE /* try to find some adjacent bits. * we stop if we have already the maximum req size. * @@ -615,7 +615,7 @@ next_sector: align = 1; rollback_i = i; for (;;) { - if (size + BM_BLOCK_SIZE > max_segment_size) + if (size + BM_BLOCK_SIZE > max_bio_size) break; /* Be always aligned */ -- cgit v1.2.2 From 4896e8c1b8fb7e46a65a6676e271fc047a260a3e Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 11 Nov 2010 22:41:04 +0100 Subject: drbd: restore compatibility with 32bit kernels With commit drbd: further converge progress display of resync and online-verify accidentally an u64/u64 div was introduced, causing an unresolvable symbol __udivdi3 to be reference. Actually for that division, 32bit are still suficient for now, so we can revert to unsigned long instead. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_proc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 329b66a91e44..49d817cfe865 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -164,8 +164,8 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) if (proc_details >= 1) { /* 64 bit: * we convert to sectors in the display below. */ - u64 bm_bits = drbd_bm_bits(mdev); - u64 bit_pos; + unsigned long bm_bits = drbd_bm_bits(mdev); + unsigned long bit_pos; if (mdev->state.conn == C_VERIFY_S || mdev->state.conn == C_VERIFY_T) bit_pos = bm_bits - mdev->ov_left; @@ -176,8 +176,8 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) seq_printf(seq, "\t%3d%% sector pos: %llu/%llu\n", (int)(bit_pos / (bm_bits/100+1)), - (unsigned long long) BM_BIT_TO_SECT(bit_pos), - (unsigned long long) BM_BIT_TO_SECT(bm_bits)); + (unsigned long long)bit_pos * BM_SECT_PER_BIT, + (unsigned long long)bm_bits * BM_SECT_PER_BIT); } } -- cgit v1.2.2 From 688593c5a82068aea64df0b836793dfbbaa646d7 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 17 Nov 2010 22:25:03 +0100 Subject: drbd: Renamed write_flags_to_bio() to wire_flags_to_bio() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 79e7b57006b1..f3052d871d31 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1612,15 +1612,15 @@ static int drbd_wait_peer_seq(struct drbd_conf *mdev, const u32 packet_seq) return ret; } -static unsigned long write_flags_to_bio(struct drbd_conf *mdev, u32 dpf) +/* see also bio_flags_to_wire() + * DRBD_REQ_*, because we need to semantically map the flags to data packet + * flags and back. We may replicate to other kernel versions. */ +static unsigned long wire_flags_to_bio(struct drbd_conf *mdev, u32 dpf) { - if (mdev->agreed_pro_version >= 95) - return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) | - (dpf & DP_FUA ? REQ_FUA : 0) | - (dpf & DP_FLUSH ? REQ_FUA : 0) | - (dpf & DP_DISCARD ? REQ_DISCARD : 0); - else - return dpf & DP_RW_SYNC ? REQ_SYNC : 0; + return (dpf & DP_RW_SYNC ? REQ_SYNC : 0) | + (dpf & DP_FUA ? REQ_FUA : 0) | + (dpf & DP_FLUSH ? REQ_FLUSH : 0) | + (dpf & DP_DISCARD ? REQ_DISCARD : 0); } /* mirrored write */ @@ -1660,18 +1660,18 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned e->w.cb = e_end_block; + dp_flags = be32_to_cpu(p->dp_flags); + rw |= wire_flags_to_bio(mdev, dp_flags); + + if (dp_flags & DP_MAY_SET_IN_SYNC) + e->flags |= EE_MAY_SET_IN_SYNC; + spin_lock(&mdev->epoch_lock); e->epoch = mdev->current_epoch; atomic_inc(&e->epoch->epoch_size); atomic_inc(&e->epoch->active); spin_unlock(&mdev->epoch_lock); - dp_flags = be32_to_cpu(p->dp_flags); - rw |= write_flags_to_bio(mdev, dp_flags); - - if (dp_flags & DP_MAY_SET_IN_SYNC) - e->flags |= EE_MAY_SET_IN_SYNC; - /* I'm the receiver, I do hold a net_cnt reference. */ if (!mdev->net_conf->two_primaries) { spin_lock_irq(&mdev->req_lock); -- cgit v1.2.2 From 759fbdfba66e620aceb3e73167e6003d1b8b0b0b Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 26 Oct 2010 16:02:27 +0200 Subject: drbd: Track the numbers of sectors in flight Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_main.c | 1 + drivers/block/drbd/drbd_req.c | 13 ++++++++++++- drivers/block/drbd/drbd_req.h | 12 +++++++----- 4 files changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index bcba2742cfba..c804e44b9455 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1102,6 +1102,7 @@ struct drbd_conf { struct fifo_buffer rs_plan_s; /* correction values of resync planer */ int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */ int rs_planed; /* resync sectors already planed */ + atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */ }; static inline struct drbd_conf *minor_to_mdev(unsigned int minor) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9d9c2ed31e9a..e81d009dd061 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2799,6 +2799,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) atomic_set(&mdev->pp_in_use_by_net, 0); atomic_set(&mdev->rs_sect_in, 0); atomic_set(&mdev->rs_sect_ev, 0); + atomic_set(&mdev->ap_in_flight, 0); mutex_init(&mdev->md_io_mutex); mutex_init(&mdev->data.mutex); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 08f53ce9b88f..5c60d77d447c 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -558,6 +558,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, case handed_over_to_network: /* assert something? */ + if (bio_data_dir(req->master_bio) == WRITE) + atomic_add(req->size>>9, &mdev->ap_in_flight); + if (bio_data_dir(req->master_bio) == WRITE && mdev->net_conf->wire_protocol == DRBD_PROT_A) { /* this is what is dangerous about protocol A: @@ -591,6 +594,9 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, dec_ap_pending(mdev); req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); req->rq_state |= RQ_NET_DONE; + if (req->rq_state & RQ_NET_SENT && req->rq_state & RQ_WRITE) + atomic_sub(req->size>>9, &mdev->ap_in_flight); + /* if it is still queued, we may not complete it here. * it will be canceled soon. */ if (!(req->rq_state & RQ_NET_QUEUED)) @@ -628,14 +634,17 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_NET_OK; D_ASSERT(req->rq_state & RQ_NET_PENDING); dec_ap_pending(mdev); + atomic_sub(req->size>>9, &mdev->ap_in_flight); req->rq_state &= ~RQ_NET_PENDING; _req_may_be_done_not_susp(req, m); break; case neg_acked: /* assert something? */ - if (req->rq_state & RQ_NET_PENDING) + if (req->rq_state & RQ_NET_PENDING) { dec_ap_pending(mdev); + atomic_sub(req->size>>9, &mdev->ap_in_flight); + } req->rq_state &= ~(RQ_NET_OK|RQ_NET_PENDING); req->rq_state |= RQ_NET_DONE; @@ -692,6 +701,8 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, } D_ASSERT(req->rq_state & RQ_NET_SENT); req->rq_state |= RQ_NET_DONE; + if (mdev->net_conf->wire_protocol == DRBD_PROT_A) + atomic_sub(req->size>>9, &mdev->ap_in_flight); _req_may_be_done(req, m); /* Allowed while state.susp */ break; diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index ab2bd09d54b4..69d350fe7c1e 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -338,19 +338,21 @@ static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what) return rv; } -/* completion of master bio is outside of spinlock. - * If you need it irqsave, do it your self! - * Which means: don't use from bio endio callback. */ +/* completion of master bio is outside of our spinlock. + * We still may or may not be inside some irqs disabled section + * of the lower level driver completion callback, so we need to + * spin_lock_irqsave here. */ static inline int req_mod(struct drbd_request *req, enum drbd_req_event what) { + unsigned long flags; struct drbd_conf *mdev = req->mdev; struct bio_and_error m; int rv; - spin_lock_irq(&mdev->req_lock); + spin_lock_irqsave(&mdev->req_lock, flags); rv = __req_mod(req, what, &m); - spin_unlock_irq(&mdev->req_lock); + spin_unlock_irqrestore(&mdev->req_lock, flags); if (m.bio) complete_master_bio(mdev, &m); -- cgit v1.2.2 From 422028b1ca4c07995af82a18abced022ff4c296c Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 27 Oct 2010 11:12:07 +0200 Subject: drbd: New configuration parameters for dealing with network congestion net { on_congestion {block|pull-ahead|disconnect}; congestion-fill {sectors}; congestion-extents {al-extents}; } Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 9e27d82a9a19..f969d8717e23 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1323,6 +1323,8 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, new_conf->wire_protocol = DRBD_PROT_C; new_conf->ping_timeo = DRBD_PING_TIMEO_DEF; new_conf->rr_conflict = DRBD_RR_CONFLICT_DEF; + new_conf->on_congestion = DRBD_ON_CONGESTION_DEF; + new_conf->cong_extents = DRBD_CONG_EXTENTS_DEF; if (!net_conf_from_tags(mdev, nlp->tag_list, new_conf)) { retcode = ERR_MANDATORY_TAG; @@ -1344,6 +1346,11 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, } } + if (new_conf->on_congestion != OC_BLOCK && new_conf->wire_protocol != DRBD_PROT_A) { + retcode = ERR_CONG_NOT_PROTO_A; + goto fail; + } + if (mdev->state.role == R_PRIMARY && new_conf->want_lose) { retcode = ERR_DISCARD; goto fail; -- cgit v1.2.2 From 67531718d8f1259f01ab84c2aa25f7b03c7afd46 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 27 Oct 2010 12:21:30 +0200 Subject: drbd: Implemented two new connection states Ahead/Behind In this connection mode, the ahead node no longer replicates application IO. The behind's disk becomes out dated. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 ++ drivers/block/drbd/drbd_main.c | 12 ++++++++++-- drivers/block/drbd/drbd_receiver.c | 3 +++ drivers/block/drbd/drbd_req.c | 23 +++++++++++++++++++++++ drivers/block/drbd/drbd_strings.c | 4 +++- 5 files changed, 41 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c804e44b9455..21b7439438cd 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2217,6 +2217,8 @@ static inline int drbd_state_is_stable(union drbd_state s) case C_VERIFY_T: case C_PAUSED_SYNC_S: case C_PAUSED_SYNC_T: + case C_AHEAD: + case C_BEHIND: /* maybe stable, look at the disk state */ break; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index e81d009dd061..46f27d6c0b21 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -871,16 +871,19 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state if (ns.conn >= C_CONNECTED && ((ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) || - (ns.disk == D_NEGOTIATING && ns.conn == C_WF_BITMAP_T))) { + (ns.disk == D_NEGOTIATING && ns.conn == C_WF_BITMAP_T) || + ns.conn >= C_AHEAD)) { switch (ns.conn) { case C_WF_BITMAP_T: case C_PAUSED_SYNC_T: + case C_BEHIND: ns.disk = D_OUTDATED; break; case C_CONNECTED: case C_WF_BITMAP_S: case C_SYNC_SOURCE: case C_PAUSED_SYNC_S: + case C_AHEAD: ns.disk = D_UP_TO_DATE; break; case C_SYNC_TARGET: @@ -893,16 +896,18 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state } if (ns.conn >= C_CONNECTED && - (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED)) { + (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED || ns.conn >= C_AHEAD)) { switch (ns.conn) { case C_CONNECTED: case C_WF_BITMAP_T: case C_PAUSED_SYNC_T: case C_SYNC_TARGET: + case C_BEHIND: ns.pdsk = D_UP_TO_DATE; break; case C_WF_BITMAP_S: case C_PAUSED_SYNC_S: + case C_AHEAD: /* remap any consistent state to D_OUTDATED, * but disallow "upgrade" of not even consistent states. */ @@ -1374,6 +1379,9 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (os.conn == C_WF_REPORT_PARAMS && ns.conn >= C_CONNECTED) drbd_send_state(mdev); + if (os.conn != C_AHEAD && ns.conn == C_AHEAD) + drbd_send_state(mdev); + /* We are in the progress to start a full sync... */ if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f3052d871d31..b19e8b2c4ce5 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3179,6 +3179,9 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (ns.conn == C_WF_REPORT_PARAMS) ns.conn = C_CONNECTED; + if (peer_state.conn == C_AHEAD) + ns.conn = C_BEHIND; + if (mdev->p_uuid && peer_state.disk >= D_NEGOTIATING && get_ldev_if_state(mdev, D_NEGOTIATING)) { int cr; /* consider resync */ diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 5c60d77d447c..60288fb3c4d7 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -948,6 +948,29 @@ allocate_barrier: ? queue_for_net_write : queue_for_net_read); } + + if (remote && mdev->net_conf->on_congestion != OC_BLOCK) { + int congested = 0; + + if (mdev->net_conf->cong_fill && + atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) { + dev_info(DEV, "Congestion-fill threshold reached\n"); + congested = 1; + } + + if (mdev->act_log->used >= mdev->net_conf->cong_extents) { + dev_info(DEV, "Congestion-extents threshold reached\n"); + congested = 1; + } + + if (congested) { + if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) + _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL); + else /*mdev->net_conf->on_congestion == OC_DISCONNECT */ + _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL); + } + } + spin_unlock_irq(&mdev->req_lock); kfree(b); /* if someone else has beaten us to it... */ diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c index 85179e1fb50a..5b970adc3b6f 100644 --- a/drivers/block/drbd/drbd_strings.c +++ b/drivers/block/drbd/drbd_strings.c @@ -48,6 +48,8 @@ static const char *drbd_conn_s_names[] = { [C_PAUSED_SYNC_T] = "PausedSyncT", [C_VERIFY_S] = "VerifyS", [C_VERIFY_T] = "VerifyT", + [C_AHEAD] = "Ahead", + [C_BEHIND] = "Behind", }; static const char *drbd_role_s_names[] = { @@ -92,7 +94,7 @@ static const char *drbd_state_sw_errors[] = { const char *drbd_conn_str(enum drbd_conns s) { /* enums are unsigned... */ - return s > C_PAUSED_SYNC_T ? "TOO_LARGE" : drbd_conn_s_names[s]; + return s > C_BEHIND ? "TOO_LARGE" : drbd_conn_s_names[s]; } const char *drbd_role_str(enum drbd_role s) -- cgit v1.2.2 From 73a01a18b9c28a0fab1131ece5b0a9bc00a879b8 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 27 Oct 2010 14:33:00 +0200 Subject: drbd: New packet for Ahead/Behind mode: P_OUT_OF_SYNC Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 10 +++++---- drivers/block/drbd/drbd_int.h | 14 +++++++++++- drivers/block/drbd/drbd_main.c | 10 +++++++++ drivers/block/drbd/drbd_receiver.c | 10 +++++++++ drivers/block/drbd/drbd_req.c | 44 +++++++++++++++++++++++++++----------- drivers/block/drbd/drbd_req.h | 4 +++- drivers/block/drbd/drbd_worker.c | 16 ++++++++++++++ 7 files changed, 90 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index b4adb58c7472..33f6cc537d08 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -1007,22 +1007,22 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, * called by tl_clear and drbd_send_dblock (==drbd_make_request). * so this can be _any_ process. */ -void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, +int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, const char *file, const unsigned int line) { unsigned long sbnr, ebnr, lbnr, flags; sector_t esector, nr_sectors; - unsigned int enr, count; + unsigned int enr, count = 0; struct lc_element *e; if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "sector: %llus, size: %d\n", (unsigned long long)sector, size); - return; + return 0; } if (!get_ldev(mdev)) - return; /* no disk, no metadata, no bitmap to set bits in */ + return 0; /* no disk, no metadata, no bitmap to set bits in */ nr_sectors = drbd_get_capacity(mdev->this_bdev); esector = sector + (size >> 9) - 1; @@ -1052,6 +1052,8 @@ void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, out: put_ldev(mdev); + + return count; } static diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 21b7439438cd..471331236826 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -212,6 +212,7 @@ enum drbd_packets { /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */ /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */ P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */ + P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */ P_MAX_CMD = 0x28, P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ @@ -269,6 +270,7 @@ static inline const char *cmdname(enum drbd_packets cmd) [P_RS_IS_IN_SYNC] = "CsumRSIsInSync", [P_COMPRESSED_BITMAP] = "CBitmap", [P_DELAY_PROBE] = "DelayProbe", + [P_OUT_OF_SYNC] = "OutOfSync", [P_MAX_CMD] = NULL, }; @@ -550,6 +552,13 @@ struct p_discard { u32 pad; } __packed; +struct p_block_desc { + struct p_header80 head; + u64 sector; + u32 blksize; + u32 pad; /* to multiple of 8 Byte */ +} __packed; + /* Valid values for the encoding field. * Bump proto version when changing this. */ enum drbd_bitmap_code { @@ -647,6 +656,7 @@ union p_polymorph { struct p_block_req block_req; struct p_delay_probe93 delay_probe93; struct p_rs_uuid rs_uuid; + struct p_block_desc block_desc; } __packed; /**********************************************************************/ @@ -1221,6 +1231,7 @@ extern int drbd_send_ack_dp(struct drbd_conf *mdev, enum drbd_packets cmd, struct p_data *dp, int data_size); extern int drbd_send_ack_ex(struct drbd_conf *mdev, enum drbd_packets cmd, sector_t sector, int blksize, u64 block_id); +extern int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, struct drbd_epoch_entry *e); extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); @@ -1534,6 +1545,7 @@ extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int); +extern int w_send_oos(struct drbd_conf *, struct drbd_work *, int); extern void resync_timer_fn(unsigned long data); @@ -1626,7 +1638,7 @@ extern void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, const char *file, const unsigned int line); #define drbd_set_in_sync(mdev, sector, size) \ __drbd_set_in_sync(mdev, sector, size, __FILE__, __LINE__) -extern void __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, +extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, int size, const char *file, const unsigned int line); #define drbd_set_out_of_sync(mdev, sector, size) \ __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 46f27d6c0b21..0dc93f43a476 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2634,6 +2634,16 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, return ok; } +int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req) +{ + struct p_block_desc p; + + p.sector = cpu_to_be64(req->sector); + p.blksize = cpu_to_be32(req->size); + + return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_OUT_OF_SYNC, &p.head, sizeof(p)); +} + /* drbd_send distinguishes two cases: diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b19e8b2c4ce5..04a08e7541cc 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3562,6 +3562,15 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, u return TRUE; } +static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) +{ + struct p_block_desc *p = &mdev->data.rbuf.block_desc; + + drbd_set_out_of_sync(mdev, be64_to_cpu(p->sector), be32_to_cpu(p->blksize)); + + return TRUE; +} + typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive); struct data_cmd { @@ -3592,6 +3601,7 @@ static struct data_cmd drbd_cmd_handler[] = { [P_OV_REPLY] = { 1, sizeof(struct p_block_req), receive_DataRequest }, [P_CSUM_RS_REQUEST] = { 1, sizeof(struct p_block_req), receive_DataRequest }, [P_DELAY_PROBE] = { 0, sizeof(struct p_delay_probe93), receive_skip }, + [P_OUT_OF_SYNC] = { 0, sizeof(struct p_block_desc), receive_out_of_sync }, /* anything missing from this table is in * the asender_tbl, see get_asender_cmd */ [P_MAX_CMD] = { 0, 0, NULL }, diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 60288fb3c4d7..a8d1ff2bda27 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -142,7 +142,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, /* before we can signal completion to the upper layers, * we may need to close the current epoch */ - if (mdev->state.conn >= C_CONNECTED && + if (mdev->state.conn >= C_CONNECTED && mdev->state.conn < C_AHEAD && req->epoch == mdev->newest_tle->br_number) queue_barrier(mdev); @@ -545,6 +545,14 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, break; + case queue_for_send_oos: + req->rq_state |= RQ_NET_QUEUED; + req->w.cb = w_send_oos; + drbd_queue_work(&mdev->data.work, &req->w); + break; + + case oos_handed_to_network: + /* actually the same */ case send_canceled: /* treat it the same */ case send_failed: @@ -756,7 +764,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) const sector_t sector = bio->bi_sector; struct drbd_tl_epoch *b = NULL; struct drbd_request *req; - int local, remote; + int local, remote, send_oos = 0; int err = -EIO; int ret = 0; @@ -820,8 +828,11 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) } remote = remote && (mdev->state.pdsk == D_UP_TO_DATE || - (mdev->state.pdsk == D_INCONSISTENT && - mdev->state.conn >= C_CONNECTED)); + (mdev->state.pdsk >= D_INCONSISTENT && + mdev->state.conn >= C_CONNECTED && + mdev->state.conn < C_AHEAD)); + send_oos = (rw == WRITE && mdev->state.conn == C_AHEAD && + mdev->state.pdsk >= D_INCONSISTENT); if (!(local || remote) && !is_susp(mdev->state)) { if (__ratelimit(&drbd_ratelimit_state)) @@ -835,7 +846,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) * but there is a race between testing the bit and pointer outside the * spinlock, and grabbing the spinlock. * if we lost that race, we retry. */ - if (rw == WRITE && remote && + if (rw == WRITE && (remote || send_oos) && mdev->unused_spare_tle == NULL && test_bit(CREATE_BARRIER, &mdev->flags)) { allocate_barrier: @@ -860,11 +871,15 @@ allocate_barrier: goto fail_free_complete; } - if (remote) { + if (remote || send_oos) { remote = (mdev->state.pdsk == D_UP_TO_DATE || - (mdev->state.pdsk == D_INCONSISTENT && - mdev->state.conn >= C_CONNECTED)); - if (!remote) + (mdev->state.pdsk >= D_INCONSISTENT && + mdev->state.conn >= C_CONNECTED && + mdev->state.conn < C_AHEAD)); + send_oos = (rw == WRITE && mdev->state.conn == C_AHEAD && + mdev->state.pdsk >= D_INCONSISTENT); + + if (!(remote || send_oos)) dev_warn(DEV, "lost connection while grabbing the req_lock!\n"); if (!(local || remote)) { dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); @@ -877,7 +892,7 @@ allocate_barrier: mdev->unused_spare_tle = b; b = NULL; } - if (rw == WRITE && remote && + if (rw == WRITE && (remote || send_oos) && mdev->unused_spare_tle == NULL && test_bit(CREATE_BARRIER, &mdev->flags)) { /* someone closed the current epoch @@ -900,7 +915,7 @@ allocate_barrier: * barrier packet. To get the write ordering right, we only have to * make sure that, if this is a write request and it triggered a * barrier packet, this request is queued within the same spinlock. */ - if (remote && mdev->unused_spare_tle && + if ((remote || send_oos) && mdev->unused_spare_tle && test_and_clear_bit(CREATE_BARRIER, &mdev->flags)) { _tl_add_barrier(mdev, mdev->unused_spare_tle); mdev->unused_spare_tle = NULL; @@ -948,8 +963,11 @@ allocate_barrier: ? queue_for_net_write : queue_for_net_read); } + if (send_oos && drbd_set_out_of_sync(mdev, sector, size)) + _req_mod(req, queue_for_send_oos); - if (remote && mdev->net_conf->on_congestion != OC_BLOCK) { + if (remote && + mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { int congested = 0; if (mdev->net_conf->cong_fill && @@ -964,6 +982,8 @@ allocate_barrier: } if (congested) { + queue_barrier(mdev); + if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL); else /*mdev->net_conf->on_congestion == OC_DISCONNECT */ diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 69d350fe7c1e..40d3dcd8fc81 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -82,14 +82,16 @@ enum drbd_req_event { to_be_submitted, /* XXX yes, now I am inconsistent... - * these two are not "events" but "actions" + * these are not "events" but "actions" * oh, well... */ queue_for_net_write, queue_for_net_read, + queue_for_send_oos, send_canceled, send_failed, handed_over_to_network, + oos_handed_to_network, connection_lost_while_pending, read_retry_remote_canceled, recv_acked_by_peer, diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 782d87237cb4..67499077c482 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1237,6 +1237,22 @@ int w_send_write_hint(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return drbd_send_short_cmd(mdev, P_UNPLUG_REMOTE); } +int w_send_oos(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + struct drbd_request *req = container_of(w, struct drbd_request, w); + int ok; + + if (unlikely(cancel)) { + req_mod(req, send_canceled); + return 1; + } + + ok = drbd_send_oos(mdev, req); + req_mod(req, oos_handed_to_network); + + return ok; +} + /** * w_send_dblock() - Worker callback to send a P_DATA packet in order to mirror a write request * @mdev: DRBD device. -- cgit v1.2.2 From c4752ef1284519c3baa1c3b19df34a80b4905245 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 27 Oct 2010 17:32:36 +0200 Subject: drbd: When proxy's buffer drained off go into regular resync mode Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 4 +++- drivers/block/drbd/drbd_main.c | 1 + drivers/block/drbd/drbd_receiver.c | 9 +++++++++ drivers/block/drbd/drbd_worker.c | 10 +++++++++- 4 files changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 471331236826..da02cce374c9 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -973,7 +973,8 @@ struct drbd_conf { struct drbd_work resync_work, unplug_work, go_diskless, - md_sync_work; + md_sync_work, + start_resync_work; struct timer_list resync_timer; struct timer_list md_sync_timer; #ifdef DRBD_DEBUG_MD_SYNC @@ -1546,6 +1547,7 @@ extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int); extern int w_send_oos(struct drbd_conf *, struct drbd_work *, int); +extern int w_start_resync(struct drbd_conf *, struct drbd_work *, int); extern void resync_timer_fn(unsigned long data); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 0dc93f43a476..f49505cf8d0f 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2846,6 +2846,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) INIT_LIST_HEAD(&mdev->unplug_work.list); INIT_LIST_HEAD(&mdev->go_diskless.list); INIT_LIST_HEAD(&mdev->md_sync_work.list); + INIT_LIST_HEAD(&mdev->start_resync_work.list); INIT_LIST_HEAD(&mdev->bm_io_work.w.list); mdev->resync_work.cb = w_resync_inactive; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 04a08e7541cc..ee9238e59327 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3279,6 +3279,7 @@ static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsi wait_event(mdev->misc_wait, mdev->state.conn == C_WF_SYNC_UUID || + mdev->state.conn == C_BEHIND || mdev->state.conn < C_CONNECTED || mdev->state.disk < D_NEGOTIATING); @@ -4338,6 +4339,14 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) tl_release(mdev, p->barrier, be32_to_cpu(p->set_size)); + if (mdev->state.conn == C_AHEAD && + atomic_read(&mdev->ap_in_flight) == 0 && + list_empty(&mdev->start_resync_work.list)) { + struct drbd_work *w = &mdev->start_resync_work; + w->cb = w_start_resync; + drbd_queue_work_front(&mdev->data.work, w); + } + return TRUE; } diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 67499077c482..c9e7cb7c788a 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -742,6 +742,14 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca return 1; } + +int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) +{ + drbd_start_resync(mdev, C_SYNC_SOURCE); + + return 1; +} + int w_ov_finished(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { kfree(w); @@ -1472,7 +1480,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) union drbd_state ns; int r; - if (mdev->state.conn >= C_SYNC_SOURCE) { + if (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn < C_AHEAD) { dev_err(DEV, "Resync already running!\n"); return; } -- cgit v1.2.2 From 59817f4fab6a165ba83ce399464ba38432db8233 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 29 Oct 2010 12:44:20 +0200 Subject: drbd: Do not cleanup resync LRU for the Ahead/Behind SyncSource/SyncTarget transitions This one should be replaced with moving this cleanup to the 'right' position. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index c9e7cb7c788a..982d68432a0f 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1485,8 +1485,13 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) return; } - /* In case a previous resync run was aborted by an IO error/detach on the peer. */ - drbd_rs_cancel_all(mdev); + if (mdev->state.conn < C_AHEAD) { + /* In case a previous resync run was aborted by an IO error/detach on the peer. */ + drbd_rs_cancel_all(mdev); + /* This should be done when we abort the resync. We definitely do not + want to have this for connections going back and forth between + Ahead/Behind and SyncSource/SyncTarget */ + } if (side == C_SYNC_TARGET) { /* Since application IO was locked out during C_WF_BITMAP_T and -- cgit v1.2.2 From e3555d8545976703938d1b59e2db509426dbe02c Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Sun, 7 Nov 2010 15:56:29 +0100 Subject: drbd: Implemented priority inheritance for resync requests We only issue resync requests if there is no significant application IO going on. = Application IO has higher priority than resnyc IO. If application IO can not be started because the resync process locked an resync_lru entry, start the IO operations necessary to release the lock ASAP. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 4 ++-- drivers/block/drbd/drbd_int.h | 3 ++- drivers/block/drbd/drbd_receiver.c | 22 ++++++++++++++++++---- drivers/block/drbd/drbd_worker.c | 18 +++++------------- 4 files changed, 27 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 33f6cc537d08..28f85d950781 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -182,6 +182,7 @@ static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr) if (unlikely(tmp != NULL)) { struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce); if (test_bit(BME_NO_WRITES, &bm_ext->flags)) { + set_bit(BME_PRIORITY, &bm_ext->flags); spin_unlock_irq(&mdev->al_lock); return NULL; } @@ -1297,8 +1298,7 @@ void drbd_rs_complete_io(struct drbd_conf *mdev, sector_t sector) } if (lc_put(mdev->resync, &bm_ext->lce) == 0) { - clear_bit(BME_LOCKED, &bm_ext->flags); - clear_bit(BME_NO_WRITES, &bm_ext->flags); + bm_ext->flags = 0; /* clear BME_LOCKED, BME_NO_WRITES and BME_PRIORITY */ mdev->resync_locked--; wake_up(&mdev->al_wait); } diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index da02cce374c9..366873d661b8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1326,6 +1326,7 @@ struct bm_extent { #define BME_NO_WRITES 0 /* bm_extent.flags: no more requests on this one! */ #define BME_LOCKED 1 /* bm_extent.flags: syncer active on this one. */ +#define BME_PRIORITY 2 /* finish resync IO on this extent ASAP! App IO waiting! */ /* drbd_bitmap.c */ /* @@ -1552,7 +1553,7 @@ extern int w_start_resync(struct drbd_conf *, struct drbd_work *, int); extern void resync_timer_fn(unsigned long data); /* drbd_receiver.c */ -extern int drbd_rs_should_slow_down(struct drbd_conf *mdev); +extern int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector); extern int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, const unsigned rw, const int fault_type); extern int drbd_release_ee(struct drbd_conf *mdev, struct list_head *list); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index ee9238e59327..0630a2e122d3 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1862,10 +1862,11 @@ out_interrupted: * The current sync rate used here uses only the most recent two step marks, * to have a short time average so we can react faster. */ -int drbd_rs_should_slow_down(struct drbd_conf *mdev) +int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector) { struct gendisk *disk = mdev->ldev->backing_bdev->bd_contains->bd_disk; unsigned long db, dt, dbdt; + struct lc_element *tmp; int curr_events; int throttle = 0; @@ -1873,9 +1874,22 @@ int drbd_rs_should_slow_down(struct drbd_conf *mdev) if (mdev->sync_conf.c_min_rate == 0) return 0; + spin_lock_irq(&mdev->al_lock); + tmp = lc_find(mdev->resync, BM_SECT_TO_EXT(sector)); + if (tmp) { + struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce); + if (test_bit(BME_PRIORITY, &bm_ext->flags)) { + spin_unlock_irq(&mdev->al_lock); + return 0; + } + /* Do not slow down if app IO is already waiting for this extent */ + } + spin_unlock_irq(&mdev->al_lock); + curr_events = (int)part_stat_read(&disk->part0, sectors[0]) + (int)part_stat_read(&disk->part0, sectors[1]) - atomic_read(&mdev->rs_sect_ev); + if (!mdev->rs_last_events || curr_events - mdev->rs_last_events > 64) { unsigned long rs_left; int i; @@ -2060,9 +2074,9 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un * we would also throttle its application reads. * In that case, throttling is done on the SyncTarget only. */ - if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev)) - msleep(100); - if (drbd_rs_begin_io(mdev, e->sector)) + if (mdev->state.peer != R_PRIMARY && drbd_rs_should_slow_down(mdev, sector)) + schedule_timeout_uninterruptible(HZ/10); + if (drbd_rs_begin_io(mdev, sector)) goto out_free_e; submit_for_resync: diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 982d68432a0f..4008130f2b2c 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -355,7 +355,7 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) if (!get_ldev(mdev)) return -EIO; - if (drbd_rs_should_slow_down(mdev)) + if (drbd_rs_should_slow_down(mdev, sector)) goto defer; /* GFP_TRY, because if there is no memory available right now, this may @@ -503,16 +503,6 @@ int drbd_rs_number_requests(struct drbd_conf *mdev) number = SLEEP_TIME * mdev->c_sync_rate / ((BM_BLOCK_SIZE / 1024) * HZ); } - /* Throttle resync on lower level disk activity, which may also be - * caused by application IO on Primary/SyncTarget. - * Keep this after the call to drbd_rs_controller, as that assumes - * to be called as precisely as possible every SLEEP_TIME, - * and would be confused otherwise. */ - if (number && drbd_rs_should_slow_down(mdev)) { - mdev->c_sync_rate = 1; - number = 0; - } - /* ignore the amount of pending requests, the resync controller should * throttle down to incoming reply rate soon enough anyways. */ return number; @@ -594,7 +584,8 @@ next_sector: sector = BM_BIT_TO_SECT(bit); - if (drbd_try_rs_begin_io(mdev, sector)) { + if (drbd_rs_should_slow_down(mdev, sector) || + drbd_try_rs_begin_io(mdev, sector)) { mdev->bm_resync_fo = bit; goto requeue; } @@ -719,7 +710,8 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca size = BM_BLOCK_SIZE; - if (drbd_try_rs_begin_io(mdev, sector)) { + if (drbd_rs_should_slow_down(mdev, sector) || + drbd_try_rs_begin_io(mdev, sector)) { mdev->ov_position = sector; goto requeue; } -- cgit v1.2.2 From 9d77a5fee9d2a1ea4cd9a841d27b107df5913b33 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Sun, 7 Nov 2010 18:02:56 +0100 Subject: drbd: Make some functions static Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 - drivers/block/drbd/drbd_worker.c | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 366873d661b8..77ac6765fd57 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1540,7 +1540,6 @@ extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int); extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); -extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int); extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int); extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 4008130f2b2c..ab5cff502f5b 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -39,6 +39,8 @@ #include "drbd_req.h" static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int cancel); +static int w_make_resync_request(struct drbd_conf *mdev, + struct drbd_work *w, int cancel); @@ -438,7 +440,7 @@ static void fifo_add_val(struct fifo_buffer *fb, int value) fb->values[i] += value; } -int drbd_rs_controller(struct drbd_conf *mdev) +static int drbd_rs_controller(struct drbd_conf *mdev) { unsigned int sect_in; /* Number of sectors that came in since the last turn */ unsigned int want; /* The number of sectors we want in the proxy */ @@ -492,7 +494,7 @@ int drbd_rs_controller(struct drbd_conf *mdev) return req_sect; } -int drbd_rs_number_requests(struct drbd_conf *mdev) +static int drbd_rs_number_requests(struct drbd_conf *mdev) { int number; if (mdev->rs_plan_s.size) { /* mdev->sync_conf.c_plan_ahead */ @@ -508,8 +510,8 @@ int drbd_rs_number_requests(struct drbd_conf *mdev) return number; } -int w_make_resync_request(struct drbd_conf *mdev, - struct drbd_work *w, int cancel) +static int w_make_resync_request(struct drbd_conf *mdev, + struct drbd_work *w, int cancel) { unsigned long bit; sector_t sector; -- cgit v1.2.2 From f91ab6282df251d28aa4ad1bd85194ebe0a0115b Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 9 Nov 2010 13:59:41 +0100 Subject: drbd: Implemented side-stepping in drbd_res_begin_io() Before: drbd_rs_begin_io() locked app-IO out of an RS extent, and waited then until all previous app-IO in that area finished. (But not only until the disk-IO was finished but until the barrier/epoch ack came in for that == round trip time latency ++) After: As soon as a new app-IO waits wants to start new IO on that RS extent, drbd_rs_begin_io() steps aside (clearing the BME_NO_WRITES flag again). It retries after 100ms. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 28f85d950781..5570d9bdc863 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -176,14 +176,17 @@ static struct lc_element *_al_get(struct drbd_conf *mdev, unsigned int enr) struct lc_element *al_ext; struct lc_element *tmp; unsigned long al_flags = 0; + int wake; spin_lock_irq(&mdev->al_lock); tmp = lc_find(mdev->resync, enr/AL_EXT_PER_BM_SECT); if (unlikely(tmp != NULL)) { struct bm_extent *bm_ext = lc_entry(tmp, struct bm_extent, lce); if (test_bit(BME_NO_WRITES, &bm_ext->flags)) { - set_bit(BME_PRIORITY, &bm_ext->flags); + wake = !test_and_set_bit(BME_PRIORITY, &bm_ext->flags); spin_unlock_irq(&mdev->al_lock); + if (wake) + wake_up(&mdev->al_wait); return NULL; } } @@ -1135,7 +1138,10 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) unsigned int enr = BM_SECT_TO_EXT(sector); struct bm_extent *bm_ext; int i, sig; + int sa = 200; /* Step aside 200 times, then grab the extent and let app-IO wait. + 200 times -> 20 seconds. */ +retry: sig = wait_event_interruptible(mdev->al_wait, (bm_ext = _bme_get(mdev, enr))); if (sig) @@ -1146,16 +1152,24 @@ int drbd_rs_begin_io(struct drbd_conf *mdev, sector_t sector) for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { sig = wait_event_interruptible(mdev->al_wait, - !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i)); - if (sig) { + !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i) || + (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)); + + if (sig || (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)) { spin_lock_irq(&mdev->al_lock); if (lc_put(mdev->resync, &bm_ext->lce) == 0) { - clear_bit(BME_NO_WRITES, &bm_ext->flags); + bm_ext->flags = 0; /* clears BME_NO_WRITES and eventually BME_PRIORITY */ mdev->resync_locked--; wake_up(&mdev->al_wait); } spin_unlock_irq(&mdev->al_lock); - return -EINTR; + if (sig) + return -EINTR; + if (schedule_timeout_interruptible(HZ/10)) + return -EINTR; + if (--sa == 0) + dev_warn(DEV,"drbd_rs_begin_io() no longer stepping aside.\n"); + goto retry; } } set_bit(BME_LOCKED, &bm_ext->flags); -- cgit v1.2.2 From aeda1cd6a58009ef21b6d9c09b1a3ded726c2d10 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 9 Nov 2010 17:45:06 +0100 Subject: drbd: Begin to account BIO processing time before inc_ap_bio() Since inc_ap_bio() might sleep already Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 12 ++++++++---- drivers/block/drbd/drbd_req.h | 1 - 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index a8d1ff2bda27..eff0fbf69dd4 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -757,7 +757,7 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); } -static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) +static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) { const int rw = bio_rw(bio); const int size = bio->bi_size; @@ -778,6 +778,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) bio_endio(bio, -ENOMEM); return 0; } + req->start_time = start_time; local = get_ldev(mdev); if (!local) { @@ -1076,12 +1077,15 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) { unsigned int s_enr, e_enr; struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; + unsigned long start_time; if (drbd_fail_request_early(mdev, bio_data_dir(bio) & WRITE)) { bio_endio(bio, -EPERM); return 0; } + start_time = jiffies; + /* * what we "blindly" assume: */ @@ -1096,7 +1100,7 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) if (likely(s_enr == e_enr)) { inc_ap_bio(mdev, 1); - return drbd_make_request_common(mdev, bio); + return drbd_make_request_common(mdev, bio, start_time); } /* can this bio be split generically? @@ -1138,10 +1142,10 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) D_ASSERT(e_enr == s_enr + 1); - while (drbd_make_request_common(mdev, &bp->bio1)) + while (drbd_make_request_common(mdev, &bp->bio1, start_time)) inc_ap_bio(mdev, 1); - while (drbd_make_request_common(mdev, &bp->bio2)) + while (drbd_make_request_common(mdev, &bp->bio2, start_time)) inc_ap_bio(mdev, 1); dec_ap_bio(mdev); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 40d3dcd8fc81..077c47b1e9d7 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -291,7 +291,6 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->epoch = 0; req->sector = bio_src->bi_sector; req->size = bio_src->bi_size; - req->start_time = jiffies; INIT_HLIST_NODE(&req->colision); INIT_LIST_HEAD(&req->tl_requests); INIT_LIST_HEAD(&req->w.list); -- cgit v1.2.2 From 127b317844e7cc0458743b604998bece95eab030 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 16 Nov 2010 10:07:53 +0100 Subject: drbd: use test_and_set_bit() to decide if bm_io_work should be queued Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f49505cf8d0f..843b90966920 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3772,6 +3772,7 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) drbd_bm_unlock(mdev); clear_bit(BITMAP_IO, &mdev->flags); + smp_mb__after_clear_bit(); wake_up(&mdev->misc_wait); if (work->done) @@ -3850,11 +3851,8 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, set_bit(BITMAP_IO, &mdev->flags); if (atomic_read(&mdev->ap_bio_cnt) == 0) { - if (list_empty(&mdev->bm_io_work.w.list)) { - set_bit(BITMAP_IO_QUEUED, &mdev->flags); + if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags)) drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); - } else - dev_err(DEV, "FIXME avoided double queuing bm_io_work\n"); } } -- cgit v1.2.2 From 8869d683b7491467fd39fcbe79756fce3e6f35e7 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 17 Nov 2010 18:24:19 +0100 Subject: drbd: Fixed inc_ap_bio() The condition must be checked after perpare_to_wait(). The old implementaion could loose wakeup events. Never observed in real life. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 77ac6765fd57..9a944604939f 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2309,15 +2309,21 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) return 1; } -/* I'd like to use wait_event_lock_irq, - * but I'm not sure when it got introduced, - * and not sure when it has 3 or 4 arguments */ -static inline void inc_ap_bio(struct drbd_conf *mdev, int count) +static inline int _inc_ap_bio_cond(struct drbd_conf *mdev, int count) { - /* compare with after_state_ch, - * os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S */ - DEFINE_WAIT(wait); + int rv = 0; + + spin_lock_irq(&mdev->req_lock); + rv = __inc_ap_bio_cond(mdev); + if (rv) + atomic_add(count, &mdev->ap_bio_cnt); + spin_unlock_irq(&mdev->req_lock); + + return rv; +} +static inline void inc_ap_bio(struct drbd_conf *mdev, int count) +{ /* we wait here * as long as the device is suspended * until the bitmap is no longer on the fly during connection @@ -2326,16 +2332,7 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int count) * to avoid races with the reconnect code, * we need to atomic_inc within the spinlock. */ - spin_lock_irq(&mdev->req_lock); - while (!__inc_ap_bio_cond(mdev)) { - prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&mdev->req_lock); - schedule(); - finish_wait(&mdev->misc_wait, &wait); - spin_lock_irq(&mdev->req_lock); - } - atomic_add(count, &mdev->ap_bio_cnt); - spin_unlock_irq(&mdev->req_lock); + wait_event(mdev->misc_wait, _inc_ap_bio_cond(mdev, count)); } static inline void dec_ap_bio(struct drbd_conf *mdev) -- cgit v1.2.2 From 22afd7ee94c1c5857323b677267ba8bace09bcef Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 16 Nov 2010 15:30:44 +0100 Subject: drbd: Fixed race condition in drbd_queue_bitmap_io May only test for ap_bio_cnt == 0 under req_lock. It can increase only under req_lock. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 843b90966920..975dc5a66549 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3849,11 +3849,13 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, mdev->bm_io_work.done = done; mdev->bm_io_work.why = why; + spin_lock_irq(&mdev->req_lock); set_bit(BITMAP_IO, &mdev->flags); if (atomic_read(&mdev->ap_bio_cnt) == 0) { if (!test_and_set_bit(BITMAP_IO_QUEUED, &mdev->flags)) drbd_queue_work(&mdev->data.work, &mdev->bm_io_work.w); } + spin_unlock_irq(&mdev->req_lock); } /** -- cgit v1.2.2 From ab17b68f4579b460753a416b0afc4446381d876f Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 17 Nov 2010 16:54:36 +0100 Subject: drbd: Improvements in sanitize_state() The relevant change is that the state change to C_FW_BITMAP_S should implicitly change pdsk to C_CONSISTENT. (Think of it as C_OUTDATED, only without the guarantee that the peer has the outdated written to its meta data) At that opportunity I restructured the switch statement so that it gets evaluated every time. (Has declarative character) Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 144 +++++++++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 975dc5a66549..74a6d55259af 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -817,6 +817,7 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state union drbd_state ns, const char **warn_sync_abort) { enum drbd_fencing_p fp; + enum drbd_disk_state disk_min, disk_max, pdsk_min, pdsk_max; fp = FP_DONT_CARE; if (get_ldev(mdev)) { @@ -869,61 +870,6 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state ns.conn = C_CONNECTED; } - if (ns.conn >= C_CONNECTED && - ((ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) || - (ns.disk == D_NEGOTIATING && ns.conn == C_WF_BITMAP_T) || - ns.conn >= C_AHEAD)) { - switch (ns.conn) { - case C_WF_BITMAP_T: - case C_PAUSED_SYNC_T: - case C_BEHIND: - ns.disk = D_OUTDATED; - break; - case C_CONNECTED: - case C_WF_BITMAP_S: - case C_SYNC_SOURCE: - case C_PAUSED_SYNC_S: - case C_AHEAD: - ns.disk = D_UP_TO_DATE; - break; - case C_SYNC_TARGET: - ns.disk = D_INCONSISTENT; - dev_warn(DEV, "Implicitly set disk state Inconsistent!\n"); - break; - } - if (os.disk == D_OUTDATED && ns.disk == D_UP_TO_DATE) - dev_warn(DEV, "Implicitly set disk from Outdated to UpToDate\n"); - } - - if (ns.conn >= C_CONNECTED && - (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED || ns.conn >= C_AHEAD)) { - switch (ns.conn) { - case C_CONNECTED: - case C_WF_BITMAP_T: - case C_PAUSED_SYNC_T: - case C_SYNC_TARGET: - case C_BEHIND: - ns.pdsk = D_UP_TO_DATE; - break; - case C_WF_BITMAP_S: - case C_PAUSED_SYNC_S: - case C_AHEAD: - /* remap any consistent state to D_OUTDATED, - * but disallow "upgrade" of not even consistent states. - */ - ns.pdsk = - (D_DISKLESS < os.pdsk && os.pdsk < D_OUTDATED) - ? os.pdsk : D_OUTDATED; - break; - case C_SYNC_SOURCE: - ns.pdsk = D_INCONSISTENT; - dev_warn(DEV, "Implicitly set pdsk Inconsistent!\n"); - break; - } - if (os.pdsk == D_OUTDATED && ns.pdsk == D_UP_TO_DATE) - dev_warn(DEV, "Implicitly set pdsk from Outdated to UpToDate\n"); - } - /* Connection breaks down before we finished "Negotiating" */ if (ns.conn < C_CONNECTED && ns.disk == D_NEGOTIATING && get_ldev_if_state(mdev, D_NEGOTIATING)) { @@ -938,6 +884,94 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state put_ldev(mdev); } + /* D_CONSISTENT and D_OUTDATED vanish when we get connected */ + if (ns.conn >= C_CONNECTED && ns.conn < C_AHEAD) { + if (ns.disk == D_CONSISTENT || ns.disk == D_OUTDATED) + ns.disk = D_UP_TO_DATE; + if (ns.pdsk == D_CONSISTENT || ns.pdsk == D_OUTDATED) + ns.pdsk = D_UP_TO_DATE; + } + + /* Implications of the connection stat on the disk states */ + disk_min = D_DISKLESS; + disk_max = D_UP_TO_DATE; + pdsk_min = D_INCONSISTENT; + pdsk_max = D_UNKNOWN; + switch ((enum drbd_conns)ns.conn) { + case C_WF_BITMAP_T: + case C_PAUSED_SYNC_T: + case C_STARTING_SYNC_T: + case C_WF_SYNC_UUID: + case C_BEHIND: + disk_min = D_INCONSISTENT; + disk_max = D_OUTDATED; + pdsk_min = D_UP_TO_DATE; + pdsk_max = D_UP_TO_DATE; + break; + case C_VERIFY_S: + case C_VERIFY_T: + disk_min = D_UP_TO_DATE; + disk_max = D_UP_TO_DATE; + pdsk_min = D_UP_TO_DATE; + pdsk_max = D_UP_TO_DATE; + break; + case C_CONNECTED: + disk_min = D_DISKLESS; + disk_max = D_UP_TO_DATE; + pdsk_min = D_DISKLESS; + pdsk_max = D_UP_TO_DATE; + break; + case C_WF_BITMAP_S: + case C_PAUSED_SYNC_S: + case C_STARTING_SYNC_S: + case C_AHEAD: + disk_min = D_UP_TO_DATE; + disk_max = D_UP_TO_DATE; + pdsk_min = D_INCONSISTENT; + pdsk_max = D_CONSISTENT; /* D_OUTDATED would be nice. But explicit outdate necessary*/ + break; + case C_SYNC_TARGET: + disk_min = D_INCONSISTENT; + disk_max = D_INCONSISTENT; + pdsk_min = D_UP_TO_DATE; + pdsk_max = D_UP_TO_DATE; + break; + case C_SYNC_SOURCE: + disk_min = D_UP_TO_DATE; + disk_max = D_UP_TO_DATE; + pdsk_min = D_INCONSISTENT; + pdsk_max = D_INCONSISTENT; + break; + case C_STANDALONE: + case C_DISCONNECTING: + case C_UNCONNECTED: + case C_TIMEOUT: + case C_BROKEN_PIPE: + case C_NETWORK_FAILURE: + case C_PROTOCOL_ERROR: + case C_TEAR_DOWN: + case C_WF_CONNECTION: + case C_WF_REPORT_PARAMS: + case C_MASK: + break; + } + if (ns.disk > disk_max) + ns.disk = disk_max; + + if (ns.disk < disk_min) { + dev_warn(DEV, "Implicitly set disk from %s to %s\n", + drbd_disk_str(ns.disk), drbd_disk_str(disk_min)); + ns.disk = disk_min; + } + if (ns.pdsk > pdsk_max) + ns.pdsk = pdsk_max; + + if (ns.pdsk < pdsk_min) { + dev_warn(DEV, "Implicitly set pdsk from %s to %s\n", + drbd_disk_str(ns.pdsk), drbd_disk_str(pdsk_min)); + ns.pdsk = pdsk_min; + } + if (fp == FP_STONITH && (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) -- cgit v1.2.2 From 3719094ec2dec411b3151f10048316d787e086f9 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 10 Nov 2010 12:08:37 +0100 Subject: drbd: Starting with protocol 96 we can allow app-IO while receiving the bitmap * C_STARTING_SYNC_S, C_STARTING_SYNC_T In these states the bitmap gets written to disk. Locking out of app-IO is done by using the drbd_queue_bitmap_io() and drbd_bitmap_io() functions these days. It is no longer necessary to lock out app-IO based on the connection state. App-IO that may come in after the BITMAP_IO flag got cleared before the state transition to C_SYNC_(SOURCE|TARGET) does not get mirrored, sets a bit in the local bitmap, that is already set, therefore changes nothing. * C_WF_BITMAP_S In this state we send updates (P_OUT_OF_SYNC packets). With that we make sure they have the same number of bits when going into the C_SYNC_(SOURCE|TARGET) connection state. * C_UNCONNECTED: The receiver starts, no need to lock out IO. * C_DISCONNECTING: in drbd_disconnect() we had a wait_event() to wait until ap_bio_cnt reaches 0. Removed that. * C_TIMEOUT, C_BROKEN_PIPE, C_NETWORK_FAILURE C_PROTOCOL_ERROR, C_TEAR_DOWN: Same as C_DISCONNECTING * C_WF_REPORT_PARAMS: IO still possible since that is still like C_WF_CONNECTION. And we do not need to send barriers in C_WF_BITMAP_S connection state. Allow concurrent accesses to the bitmap when receiving the bitmap. Everything gets ORed anyways. A drbd_free_tl_hash() is in after_state_chg_work(). At that point all the work items of the last connections must have been processed. Introduced a call to drbd_free_tl_hash() into drbd_free_mdev() for paranoia reasons. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 19 ++++++++++++------- drivers/block/drbd/drbd_main.c | 1 + drivers/block/drbd/drbd_receiver.c | 13 ++----------- drivers/block/drbd/drbd_req.c | 37 ++++++++++++++++++++++++------------- 4 files changed, 39 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 9a944604939f..38bbaba8bd89 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2213,8 +2213,9 @@ static inline int drbd_get_max_buffers(struct drbd_conf *mdev) return mxb; } -static inline int drbd_state_is_stable(union drbd_state s) +static inline int drbd_state_is_stable(struct drbd_conf *mdev) { + union drbd_state s = mdev->state; /* DO NOT add a default clause, we want the compiler to warn us * for any newly introduced state we may have forgotten to add here */ @@ -2233,11 +2234,7 @@ static inline int drbd_state_is_stable(union drbd_state s) case C_PAUSED_SYNC_T: case C_AHEAD: case C_BEHIND: - /* maybe stable, look at the disk state */ - break; - - /* no new io accepted during tansitional states - * like handshake or teardown */ + /* transitional states, IO allowed */ case C_DISCONNECTING: case C_UNCONNECTED: case C_TIMEOUT: @@ -2248,7 +2245,15 @@ static inline int drbd_state_is_stable(union drbd_state s) case C_WF_REPORT_PARAMS: case C_STARTING_SYNC_S: case C_STARTING_SYNC_T: + break; + + /* Allow IO in BM exchange states with new protocols */ case C_WF_BITMAP_S: + if (mdev->agreed_pro_version < 96) + return 0; + break; + + /* no new io accepted in these states */ case C_WF_BITMAP_T: case C_WF_SYNC_UUID: case C_MASK: @@ -2297,7 +2302,7 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) * to start during "stable" states. */ /* no new io accepted when attaching or detaching the disk */ - if (!drbd_state_is_stable(mdev->state)) + if (!drbd_state_is_stable(mdev)) return 0; /* since some older kernels don't have atomic_add_unless, diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 74a6d55259af..14afbd4e53a5 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3334,6 +3334,7 @@ void drbd_free_mdev(struct drbd_conf *mdev) put_disk(mdev->vdisk); blk_cleanup_queue(mdev->rq_queue); free_cpumask_var(mdev->cpu_mask); + drbd_free_tl_hash(mdev); kfree(mdev); } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 0630a2e122d3..f4aba9f894ba 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3468,9 +3468,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne int ok = FALSE; struct p_header80 *h = &mdev->data.rbuf.header.h80; - wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); - - drbd_bm_lock(mdev, "receive bitmap"); + /* drbd_bm_lock(mdev, "receive bitmap"); By intention no bm_lock */ /* maybe we should use some per thread scratch page, * and allocate that during initial device creation? */ @@ -3542,7 +3540,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne ok = TRUE; out: - drbd_bm_unlock(mdev); + /* drbd_bm_unlock(mdev); by intention no lock */ if (ok && mdev->state.conn == C_WF_BITMAP_S) drbd_start_resync(mdev, C_SYNC_SOURCE); free_page((unsigned long) buffer); @@ -3804,13 +3802,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) if (os.conn == C_DISCONNECTING) { wait_event(mdev->net_cnt_wait, atomic_read(&mdev->net_cnt) == 0); - if (!is_susp(mdev->state)) { - /* we must not free the tl_hash - * while application io is still on the fly */ - wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); - drbd_free_tl_hash(mdev); - } - crypto_free_hash(mdev->cram_hmac_tfm); mdev->cram_hmac_tfm = NULL; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index eff0fbf69dd4..4cb8247d83c9 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -142,7 +142,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, /* before we can signal completion to the upper layers, * we may need to close the current epoch */ - if (mdev->state.conn >= C_CONNECTED && mdev->state.conn < C_AHEAD && + if (mdev->state.conn >= C_WF_BITMAP_T && mdev->state.conn < C_AHEAD && req->epoch == mdev->newest_tle->br_number) queue_barrier(mdev); @@ -757,6 +757,23 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); } +static int drbd_should_do_remote(struct drbd_conf *mdev) +{ + union drbd_state s = mdev->state; + + return s.pdsk == D_UP_TO_DATE || + (s.pdsk >= D_INCONSISTENT && + s.conn >= C_WF_BITMAP_T && + s.conn < C_AHEAD); +} +static int drbd_should_send_oos(struct drbd_conf *mdev) +{ + union drbd_state s = mdev->state; + + return s.pdsk >= D_INCONSISTENT && + (s.conn == C_AHEAD || s.conn == C_WF_BITMAP_S); +} + static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) { const int rw = bio_rw(bio); @@ -828,12 +845,9 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns drbd_al_begin_io(mdev, sector); } - remote = remote && (mdev->state.pdsk == D_UP_TO_DATE || - (mdev->state.pdsk >= D_INCONSISTENT && - mdev->state.conn >= C_CONNECTED && - mdev->state.conn < C_AHEAD)); - send_oos = (rw == WRITE && mdev->state.conn == C_AHEAD && - mdev->state.pdsk >= D_INCONSISTENT); + remote = remote && drbd_should_do_remote(mdev); + send_oos = rw == WRITE && drbd_should_send_oos(mdev); + D_ASSERT(!(remote && send_oos)); if (!(local || remote) && !is_susp(mdev->state)) { if (__ratelimit(&drbd_ratelimit_state)) @@ -873,12 +887,9 @@ allocate_barrier: } if (remote || send_oos) { - remote = (mdev->state.pdsk == D_UP_TO_DATE || - (mdev->state.pdsk >= D_INCONSISTENT && - mdev->state.conn >= C_CONNECTED && - mdev->state.conn < C_AHEAD)); - send_oos = (rw == WRITE && mdev->state.conn == C_AHEAD && - mdev->state.pdsk >= D_INCONSISTENT); + remote = drbd_should_do_remote(mdev); + send_oos = rw == WRITE && drbd_should_send_oos(mdev); + D_ASSERT(!(remote && send_oos)); if (!(remote || send_oos)) dev_warn(DEV, "lost connection while grabbing the req_lock!\n"); -- cgit v1.2.2 From 1fc80cf37810d6b00cac27a219b8ecab2010adac Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 22 Nov 2010 14:18:47 +0100 Subject: drbd: Becoming sync target may not happen out of < C_WF_REPORT_PARAMS This patch is acutally a necessary addendum to the patch "fix for spurious full sync (becoming sync target looked like invalidate)" Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 14afbd4e53a5..8b8a38dc6492 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -800,6 +800,10 @@ static int is_valid_state_transition(struct drbd_conf *mdev, os.conn < C_CONNECTED) rv = SS_NEED_CONNECTION; + if ((ns.conn == C_SYNC_TARGET || ns.conn == C_SYNC_SOURCE) + && os.conn < C_WF_REPORT_PARAMS) + rv = SS_NEED_CONNECTION; /* No NetworkFailure -> SyncTarget etc... */ + return rv; } -- cgit v1.2.2 From c507f46f26661d4d0dc95a1b1271df5855ab4602 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 22 Nov 2010 15:49:17 +0100 Subject: drbd: Removed 20 seconds upper bound for side-stepping Given low-enough network bandwidth combined with a IO pattern that hammers onto a single RS-extent, side-stepping might be necessary for much longer times. Changed the code to print a single informal message after 20 seconds, but it keeps on stepping aside forever. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 5570d9bdc863..4a1b199f4ae7 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -1153,7 +1153,7 @@ retry: for (i = 0; i < AL_EXT_PER_BM_SECT; i++) { sig = wait_event_interruptible(mdev->al_wait, !_is_in_al(mdev, enr * AL_EXT_PER_BM_SECT + i) || - (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)); + test_bit(BME_PRIORITY, &bm_ext->flags)); if (sig || (test_bit(BME_PRIORITY, &bm_ext->flags) && sa)) { spin_lock_irq(&mdev->al_lock); @@ -1167,8 +1167,9 @@ retry: return -EINTR; if (schedule_timeout_interruptible(HZ/10)) return -EINTR; - if (--sa == 0) - dev_warn(DEV,"drbd_rs_begin_io() no longer stepping aside.\n"); + if (sa && --sa == 0) + dev_warn(DEV,"drbd_rs_begin_io() stepped aside for 20sec." + "Resync stalled?\n"); goto retry; } } -- cgit v1.2.2 From 3da127fa887e5187ede702b835770634d705f8b2 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 24 Nov 2010 10:33:02 +0100 Subject: drbd: increase module count on /proc/drbd access If someone holds /proc/drbd open, previously rmmod would "succeed" in starting the unload, but then block on remove_proc_entry, leading to a situation where the lsmod does not show drbd anymore, but /proc/drbd being still there (but no longer accessible). I'd rather have rmmod fail up front in this case. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_proc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index 49d817cfe865..efba62cd2e58 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -34,6 +34,7 @@ #include "drbd_int.h" static int drbd_proc_open(struct inode *inode, struct file *file); +static int drbd_proc_release(struct inode *inode, struct file *file); struct proc_dir_entry *drbd_proc; @@ -42,7 +43,7 @@ const struct file_operations drbd_proc_fops = { .open = drbd_proc_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = drbd_proc_release, }; void seq_printf_with_thousands_grouping(struct seq_file *seq, long v) @@ -304,7 +305,15 @@ static int drbd_seq_show(struct seq_file *seq, void *v) static int drbd_proc_open(struct inode *inode, struct file *file) { - return single_open(file, drbd_seq_show, PDE(inode)->data); + if (try_module_get(THIS_MODULE)) + return single_open(file, drbd_seq_show, PDE(inode)->data); + return -ENODEV; +} + +static int drbd_proc_release(struct inode *inode, struct file *file) +{ + module_put(THIS_MODULE); + return single_release(inode, file); } /* PROC FS stuff end */ -- cgit v1.2.2 From 17a93f3007c13003c739a19d0814cb5c2d21daba Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 24 Nov 2010 10:37:35 +0100 Subject: drbd: remove /proc/drbd before unregistering from netlink There still exists a (theoretical) race on module unload, where /proc/drbd may still exist, but the netlink callback has been unregistered already, allowing drbdsetup to shout without listeners, and get no reply. Reorder remove_proc_entry and unregister of netlink callback. drbdsetup first checks for existence of the proc entry, and if that is missing, won't even try to contact the module. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8b8a38dc6492..150ed16d26ef 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3174,11 +3174,20 @@ static void drbd_cleanup(void) unregister_reboot_notifier(&drbd_notifier); + /* first remove proc, + * drbdsetup uses it's presence to detect + * whether DRBD is loaded. + * If we would get stuck in proc removal, + * but have netlink already deregistered, + * some drbdsetup commands may wait forever + * for an answer. + */ + if (drbd_proc) + remove_proc_entry("drbd", NULL); + drbd_nl_cleanup(); if (minor_table) { - if (drbd_proc) - remove_proc_entry("drbd", NULL); i = minor_count; while (i--) drbd_delete_device(i); -- cgit v1.2.2 From 3e3a7766c2e6995ac98e7855017abc3544d54e08 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 24 Nov 2010 10:41:45 +0100 Subject: drbd: use kzalloc and memset(,0,) to start with clean buffers in drbd_nl Make sure we start with clean buffers to not accidentally send garbage back to userspace. Note: has not been observed; but just in case. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index f969d8717e23..80a389d24cdd 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2211,7 +2211,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms reply_size += cm->reply_body_size; /* allocation not in the IO path, cqueue thread context */ - cn_reply = kmalloc(reply_size, GFP_KERNEL); + cn_reply = kzalloc(reply_size, GFP_KERNEL); if (!cn_reply) { retcode = ERR_NOMEM; goto fail; @@ -2382,7 +2382,7 @@ void drbd_bcast_ee(struct drbd_conf *mdev, /* receiver thread context, which is not in the writeout path (of this node), * but may be in the writeout path of the _other_ node. * GFP_NOIO to avoid potential "distributed deadlock". */ - cn_reply = kmalloc( + cn_reply = kzalloc( sizeof(struct cn_msg)+ sizeof(struct drbd_nl_cfg_reply)+ sizeof(struct dump_ee_tag_len_struct)+ @@ -2517,6 +2517,7 @@ void drbd_nl_send_reply(struct cn_msg *req, int ret_code) (struct drbd_nl_cfg_reply *)cn_reply->data; int rr; + memset(buffer, 0, sizeof(buffer)); cn_reply->id = req->id; cn_reply->seq = req->seq; -- cgit v1.2.2 From 42ff269d1022a86be4f526cf674998c47b7ab856 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 24 Nov 2010 10:11:14 +0100 Subject: drbd: add packet_type 27 (return_code_only) to netlink api In case we ever should add an other packet type, we must not reuse 27, as that currently used for "empty" return code only replies. Document it as such. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 80a389d24cdd..6a6dde6c51c6 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2195,7 +2195,8 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms goto fail; } - if (nlp->packet_type >= P_nl_after_last_packet) { + if (nlp->packet_type >= P_nl_after_last_packet || + nlp->packet_type == P_return_code_only) { retcode = ERR_PACKET_NR; goto fail; } @@ -2219,7 +2220,7 @@ static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms reply = (struct drbd_nl_cfg_reply *) cn_reply->data; reply->packet_type = - cm->reply_body_size ? nlp->packet_type : P_nl_after_last_packet; + cm->reply_body_size ? nlp->packet_type : P_return_code_only; reply->minor = nlp->drbd_minor; reply->ret_code = NO_ERROR; /* Might by modified by cm->function. */ /* reply->tag_list; might be modified by cm->function. */ @@ -2525,6 +2526,7 @@ void drbd_nl_send_reply(struct cn_msg *req, int ret_code) cn_reply->len = sizeof(struct drbd_nl_cfg_reply); cn_reply->flags = 0; + reply->packet_type = P_return_code_only; reply->minor = ((struct drbd_nl_cfg_req *)req->data)->drbd_minor; reply->ret_code = ret_code; -- cgit v1.2.2 From 2561b9c1f1d63077c41903fc6ad58dc9ec47248b Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 3 Dec 2010 15:22:48 +0100 Subject: drbd: --force option for disconnect As the network connection can be lost at any time, a --force option for disconnect is just a matter of completeness. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 6a6dde6c51c6..cd0459f0403f 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1531,6 +1531,21 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl struct drbd_nl_cfg_reply *reply) { int retcode; + struct disconnect dc; + + memset(&dc, 0, sizeof(struct disconnect)); + if (!disconnect_from_tags(mdev, nlp->tag_list, &dc)) { + retcode = ERR_MANDATORY_TAG; + goto fail; + } + + if (dc.force) { + spin_lock_irq(&mdev->req_lock); + if (mdev->state.conn >= C_WF_CONNECTION) + _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), CS_HARD, NULL); + spin_unlock_irq(&mdev->req_lock); + goto done; + } retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED); -- cgit v1.2.2 From 09b9e7979378fe070784de20e50bb1d42aa643ab Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 3 Dec 2010 16:04:24 +0100 Subject: drbd: Implemented the before-resync-source handler Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index ab5cff502f5b..e201f6f82c0e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1499,6 +1499,20 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); return; } + } else /* C_SYNC_SOURCE */ { + r = drbd_khelper(mdev, "before-resync-source"); + r = (r >> 8) & 0xff; + if (r > 0) { + if (r == 3) { + dev_info(DEV, "before-resync-source handler returned %d, " + "ignoring. Old userland tools?", r); + } else { + dev_info(DEV, "before-resync-source handler returned %d, " + "dropping connection.\n", r); + drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); + return; + } + } } drbd_state_lock(mdev); -- cgit v1.2.2 From 8a3c104438be4986a77f332009b695fcac48f620 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Sun, 5 Dec 2010 14:11:14 +0100 Subject: drbd: fix regression, we need to close drbd epochs during normal operation commit e2041475e6ddb081734d161f6421977323f5a9b9 drbd: Starting with protocol 96 we can allow app-IO while receiving the bitmap Contained a bad chunk that tried to optimize away drbd barriers during bitmap exchange, but accidentally dropped them for normal mode as well. Impact: depending on activity log size and access pattern, activity log extents may not be recycled in time, causeing IO to block indefinetely. Fix: skip drbd barriers only if there is no connection to send them on, or the request being completed has not been on the network at all. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 4cb8247d83c9..de5fe70f2b42 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -140,9 +140,14 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev, struct hlist_node *n; struct hlist_head *slot; - /* before we can signal completion to the upper layers, - * we may need to close the current epoch */ - if (mdev->state.conn >= C_WF_BITMAP_T && mdev->state.conn < C_AHEAD && + /* Before we can signal completion to the upper layers, + * we may need to close the current epoch. + * We can skip this, if this request has not even been sent, because we + * did not have a fully established connection yet/anymore, during + * bitmap exchange, or while we are C_AHEAD due to congestion policy. + */ + if (mdev->state.conn >= C_CONNECTED && + (s & RQ_NET_SENT) != 0 && req->epoch == mdev->newest_tle->br_number) queue_barrier(mdev); -- cgit v1.2.2 From 7e458c32da946bd4f6aea476b61b79575578f834 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 8 Dec 2010 19:02:09 +0100 Subject: drbd: Removed an unnecessary #undef Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f4aba9f894ba..f8cd3f230d84 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2963,7 +2963,6 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } put_ldev(mdev); } -#undef min_not_zero ddsf = be16_to_cpu(p->dds_flags); if (get_ldev(mdev)) { -- cgit v1.2.2 From 220df4d006ed561b8fd4fbd8c01c6c28d6143653 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 9 Dec 2010 15:21:02 +0100 Subject: drbd: fix incomplete error message Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f8cd3f230d84..55fee1a6c647 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2499,7 +2499,7 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol return C_MASK; } if (hg == -1001) { - dev_alert(DEV, "To resolve this both sides have to support at least protocol\n"); + dev_alert(DEV, "To resolve this both sides have to support at least protocol 91\n"); return C_MASK; } -- cgit v1.2.2 From cab2f74b45127a78b9a2980f54ca16cc9f45ddac Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 9 Dec 2010 16:08:46 +0100 Subject: drbd: Make sure that drbd_send() has sent the right number of bytes Reviewed-by: Lars Ellenberg Signed-off-by: Philipp Reisner --- drivers/block/drbd/drbd_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 150ed16d26ef..50b6841d135b 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2580,7 +2580,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req) if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb); - ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); + ok = dgs == drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); } if (ok) { /* For protocol A, we have to memcpy the payload into @@ -2662,7 +2662,7 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, if (ok && dgs) { dgb = mdev->int_dig_out; drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb); - ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); + ok = dgs == drbd_send(mdev, mdev->data.socket, dgb, dgs, 0); } if (ok) ok = _drbd_send_zc_ee(mdev, e); -- cgit v1.2.2 From 96756784a6250c7d9878671ef3386b93b0c576d4 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 9 Dec 2010 16:23:43 +0100 Subject: drbd: Remove left-over prototype Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 38bbaba8bd89..3268d201025b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1236,8 +1236,6 @@ extern int drbd_send_oos(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd, struct drbd_epoch_entry *e); extern int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req); -extern int _drbd_send_barrier(struct drbd_conf *mdev, - struct drbd_tl_epoch *barrier); extern int drbd_send_drequest(struct drbd_conf *mdev, int cmd, sector_t sector, int size, u64 block_id); extern int drbd_send_drequest_csum(struct drbd_conf *mdev, -- cgit v1.2.2 From 2f58dcfc85b6800efd938f755e6c5f9979f4aa5c Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 13 Dec 2010 17:48:19 +0100 Subject: drbd: Rename drbd_make_request_26 to drbd_make_request Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_req.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 3268d201025b..7514cf7a958c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1479,7 +1479,7 @@ extern void drbd_free_mdev(struct drbd_conf *mdev); extern int proc_details; /* drbd_req */ -extern int drbd_make_request_26(struct request_queue *q, struct bio *bio); +extern int drbd_make_request(struct request_queue *q, struct bio *bio); extern int drbd_read_remote(struct drbd_conf *mdev, struct drbd_request *req); extern int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec); extern int is_valid_ar_handle(struct drbd_request *, sector_t); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 50b6841d135b..7d60527c3b5a 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3284,7 +3284,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) q->backing_dev_info.congested_fn = drbd_congested; q->backing_dev_info.congested_data = mdev; - blk_queue_make_request(q, drbd_make_request_26); + blk_queue_make_request(q, drbd_make_request); blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE >> 9); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); blk_queue_merge_bvec(q, drbd_merge_bvec); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index de5fe70f2b42..079213d93490 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -884,7 +884,7 @@ allocate_barrier: if (is_susp(mdev->state)) { /* If we got suspended, use the retry mechanism of generic_make_request() to restart processing of this - bio. In the next call to drbd_make_request_26 + bio. In the next call to drbd_make_request we sleep in inc_ap_bio() */ ret = 1; spin_unlock_irq(&mdev->req_lock); @@ -1089,7 +1089,7 @@ static int drbd_fail_request_early(struct drbd_conf *mdev, int is_write) return 0; } -int drbd_make_request_26(struct request_queue *q, struct bio *bio) +int drbd_make_request(struct request_queue *q, struct bio *bio) { unsigned int s_enr, e_enr; struct drbd_conf *mdev = (struct drbd_conf *) q->queuedata; @@ -1182,7 +1182,7 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) * As long as the BIO is empty we have to allow at least one bvec, * regardless of size and offset. so the resulting bio may still * cross extent boundaries. those are dealt with (bio_split) in - * drbd_make_request_26. + * drbd_make_request. */ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct bio_vec *bvec) { -- cgit v1.2.2 From 662d91a23a8e8451ca47c08d5cff710fd080fd3a Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 7 Dec 2010 03:01:41 +0100 Subject: drbd: Get rid of unnecessary macros (1) This macro doesn't save much code, but makes things a lot harder to read. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 71 ++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7d60527c3b5a..f43e2aa354a6 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -674,21 +674,6 @@ void print_st_err(struct drbd_conf *mdev, } -#define drbd_peer_str drbd_role_str -#define drbd_pdsk_str drbd_disk_str - -#define drbd_susp_str(A) ((A) ? "1" : "0") -#define drbd_aftr_isp_str(A) ((A) ? "1" : "0") -#define drbd_peer_isp_str(A) ((A) ? "1" : "0") -#define drbd_user_isp_str(A) ((A) ? "1" : "0") - -#define PSC(A) \ - ({ if (ns.A != os.A) { \ - pbp += sprintf(pbp, #A "( %s -> %s ) ", \ - drbd_##A##_str(os.A), \ - drbd_##A##_str(ns.A)); \ - } }) - /** * is_valid_state() - Returns an SS_ error code if ns is not valid * @mdev: DRBD device. @@ -1084,22 +1069,46 @@ int __drbd_set_state(struct drbd_conf *mdev, dev_warn(DEV, "%s aborted.\n", warn_sync_abort); { - char *pbp, pb[300]; - pbp = pb; - *pbp = 0; - PSC(role); - PSC(peer); - PSC(conn); - PSC(disk); - PSC(pdsk); - if (is_susp(ns) != is_susp(os)) - pbp += sprintf(pbp, "susp( %s -> %s ) ", - drbd_susp_str(is_susp(os)), - drbd_susp_str(is_susp(ns))); - PSC(aftr_isp); - PSC(peer_isp); - PSC(user_isp); - dev_info(DEV, "%s\n", pb); + char *pbp, pb[300]; + pbp = pb; + *pbp = 0; + if (ns.role != os.role) + pbp += sprintf(pbp, "role( %s -> %s ) ", + drbd_role_str(os.role), + drbd_role_str(ns.role)); + if (ns.peer != os.peer) + pbp += sprintf(pbp, "peer( %s -> %s ) ", + drbd_role_str(os.peer), + drbd_role_str(ns.peer)); + if (ns.conn != os.conn) + pbp += sprintf(pbp, "conn( %s -> %s ) ", + drbd_conn_str(os.conn), + drbd_conn_str(ns.conn)); + if (ns.disk != os.disk) + pbp += sprintf(pbp, "disk( %s -> %s ) ", + drbd_disk_str(os.disk), + drbd_disk_str(ns.disk)); + if (ns.pdsk != os.pdsk) + pbp += sprintf(pbp, "pdsk( %s -> %s ) ", + drbd_disk_str(os.pdsk), + drbd_disk_str(ns.pdsk)); + if (is_susp(ns) != is_susp(os)) + pbp += sprintf(pbp, "susp( %d -> %d ) ", + is_susp(os), + is_susp(ns)); + if (ns.aftr_isp != os.aftr_isp) + pbp += sprintf(pbp, "aftr_isp( %d -> %d ) ", + os.aftr_isp, + ns.aftr_isp); + if (ns.peer_isp != os.peer_isp) + pbp += sprintf(pbp, "peer_isp( %d -> %d ) ", + os.peer_isp, + ns.peer_isp); + if (ns.user_isp != os.user_isp) + pbp += sprintf(pbp, "user_isp( %d -> %d ) ", + os.user_isp, + ns.user_isp); + dev_info(DEV, "%s\n", pb); } /* solve the race between becoming unconfigured, -- cgit v1.2.2 From 0cf9d27e38447efe5e5edce155a66a782a5aac4a Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 7 Dec 2010 10:43:29 +0100 Subject: drbd: Get rid of unnecessary macros (2) The FAULT_ACTIVE macro just wraps the drbd_insert_fault macro for no apparent reason. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 4 ++-- drivers/block/drbd/drbd_bitmap.c | 4 ++-- drivers/block/drbd/drbd_int.h | 9 ++++----- drivers/block/drbd/drbd_receiver.c | 4 ++-- drivers/block/drbd/drbd_req.c | 6 +++--- drivers/block/drbd/drbd_wrappers.h | 2 +- 6 files changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 4a1b199f4ae7..2e8a95ce79b1 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -92,7 +92,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, bio->bi_end_io = drbd_md_io_complete; bio->bi_rw = rw; - if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) + if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) bio_endio(bio, -EIO); else submit_bio(rw, bio); @@ -685,7 +685,7 @@ void drbd_al_to_on_disk_bm(struct drbd_conf *mdev) for (i = 0; i < nr_elements; i++) { if (bios[i] == NULL) break; - if (FAULT_ACTIVE(mdev, DRBD_FAULT_MD_WR)) { + if (drbd_insert_fault(mdev, DRBD_FAULT_MD_WR)) { bios[i]->bi_rw = WRITE; bio_endio(bios[i], -EIO); } else { diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 0645ca829a94..5dafbabe9617 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -502,7 +502,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) D_ASSERT(b->bm_pages != NULL); npages = b->bm_pages; } else { - if (FAULT_ACTIVE(mdev, DRBD_FAULT_BM_ALLOC)) + if (drbd_insert_fault(mdev, DRBD_FAULT_BM_ALLOC)) npages = NULL; else npages = bm_realloc_pages(b, want); @@ -768,7 +768,7 @@ static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int bio->bi_private = b; bio->bi_end_io = bm_async_io_complete; - if (FAULT_ACTIVE(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { + if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { bio->bi_rw |= rw; bio_endio(bio, -EIO); } else { diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 7514cf7a958c..c81710a42111 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -137,20 +137,19 @@ enum { DRBD_FAULT_MAX, }; -#ifdef CONFIG_DRBD_FAULT_INJECTION extern unsigned int _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type); + static inline int drbd_insert_fault(struct drbd_conf *mdev, unsigned int type) { +#ifdef CONFIG_DRBD_FAULT_INJECTION return fault_rate && (enable_faults & (1<> PAGE_SHIFT; - if (FAULT_ACTIVE(mdev, DRBD_FAULT_AL_EE)) + if (drbd_insert_fault(mdev, DRBD_FAULT_AL_EE)) return NULL; e = mempool_alloc(drbd_ee_mempool, gfp_mask & ~__GFP_HIGHMEM); @@ -1264,7 +1264,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ unsigned len = min_t(int, ds, PAGE_SIZE); data = kmap(page); rr = drbd_recv(mdev, data, len); - if (FAULT_ACTIVE(mdev, DRBD_FAULT_RECEIVE)) { + if (drbd_insert_fault(mdev, DRBD_FAULT_RECEIVE)) { dev_err(DEV, "Fault injection: Corrupting data on receive\n"); data[0] = data[0] ^ (unsigned long)-1; } diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 079213d93490..53e7cc506456 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1020,9 +1020,9 @@ allocate_barrier: * stable storage, and this is a WRITE, we may not even submit * this bio. */ if (get_ldev(mdev)) { - if (FAULT_ACTIVE(mdev, rw == WRITE ? DRBD_FAULT_DT_WR - : rw == READ ? DRBD_FAULT_DT_RD - : DRBD_FAULT_DT_RA)) + if (drbd_insert_fault(mdev, rw == WRITE ? DRBD_FAULT_DT_WR + : rw == READ ? DRBD_FAULT_DT_RD + : DRBD_FAULT_DT_RA)) bio_endio(req->private_bio, -EIO); else generic_make_request(req->private_bio); diff --git a/drivers/block/drbd/drbd_wrappers.h b/drivers/block/drbd/drbd_wrappers.h index 53586fa5ae1b..151f1a37478f 100644 --- a/drivers/block/drbd/drbd_wrappers.h +++ b/drivers/block/drbd/drbd_wrappers.h @@ -39,7 +39,7 @@ static inline void drbd_generic_make_request(struct drbd_conf *mdev, return; } - if (FAULT_ACTIVE(mdev, fault_type)) + if (drbd_insert_fault(mdev, fault_type)) bio_endio(bio, -EIO); else generic_make_request(bio); -- cgit v1.2.2 From 116676ca621a862a8124969772f4dd61c8b40eee Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 8 Dec 2010 13:33:11 +0100 Subject: drbd: Rename enum drbd_ret_codes to enum drbd_ret_code Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_nl.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f43e2aa354a6..8d69e3a1b3c2 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3570,7 +3570,7 @@ void drbd_md_sync(struct drbd_conf *mdev) * @mdev: DRBD device. * @bdev: Device from which the meta data should be read in. * - * Return 0 (NO_ERROR) on success, and an enum drbd_ret_codes in case + * Return 0 (NO_ERROR) on success, and an enum drbd_ret_code in case * something goes wrong. Currently only: ERR_IO_MD_DISK, ERR_MD_INVALID. */ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index cd0459f0403f..fe336592e538 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -849,7 +849,7 @@ static void drbd_suspend_al(struct drbd_conf *mdev) static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { - enum drbd_ret_codes retcode; + enum drbd_ret_code retcode; enum determine_dev_size dd; sector_t max_possible_sectors; sector_t min_md_device_sectors; @@ -1278,7 +1278,7 @@ static int drbd_nl_net_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply) { int i, ns; - enum drbd_ret_codes retcode; + enum drbd_ret_code retcode; struct net_conf *new_conf = NULL; struct crypto_hash *tfm = NULL; struct crypto_hash *integrity_w_tfm = NULL; -- cgit v1.2.2 From c8b325632f0e5ffdaeca3d1f3be77c9399316a40 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 8 Dec 2010 01:06:16 +0100 Subject: drbd: Rename enum drbd_state_ret_codes to enum drbd_state_rv Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 5 +++-- drivers/block/drbd/drbd_strings.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8d69e3a1b3c2..cddf311b7429 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -510,8 +510,9 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state int drbd_send_state_req(struct drbd_conf *, union drbd_state, union drbd_state); -static enum drbd_state_ret_codes _req_st_cond(struct drbd_conf *mdev, - union drbd_state mask, union drbd_state val) +static enum drbd_state_rv +_req_st_cond(struct drbd_conf *mdev, union drbd_state mask, + union drbd_state val) { union drbd_state os, ns; unsigned long flags; diff --git a/drivers/block/drbd/drbd_strings.c b/drivers/block/drbd/drbd_strings.c index 5b970adc3b6f..c44a2a602772 100644 --- a/drivers/block/drbd/drbd_strings.c +++ b/drivers/block/drbd/drbd_strings.c @@ -107,7 +107,7 @@ const char *drbd_disk_str(enum drbd_disk_state s) return s > D_UP_TO_DATE ? "TOO_LARGE" : drbd_disk_s_names[s]; } -const char *drbd_set_st_err_str(enum drbd_state_ret_codes err) +const char *drbd_set_st_err_str(enum drbd_state_rv err) { return err <= SS_AFTER_LAST_ERROR ? "TOO_SMALL" : err > SS_TWO_PRIMARIES ? "TOO_LARGE" -- cgit v1.2.2 From bf885f8a6772fb48409dd505a09d974a5e621f22 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Wed, 8 Dec 2010 00:39:32 +0100 Subject: drbd: Be more explicit about functions that return an enum drbd_state_rv Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 32 ++++++++++++--------- drivers/block/drbd/drbd_main.c | 59 +++++++++++++++++++++----------------- drivers/block/drbd/drbd_nl.c | 29 ++++++++++--------- drivers/block/drbd/drbd_receiver.c | 2 +- 4 files changed, 67 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index c81710a42111..749607a494e6 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1174,14 +1174,19 @@ enum dds_flags { }; extern void drbd_init_set_defaults(struct drbd_conf *mdev); -extern int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, - union drbd_state mask, union drbd_state val); +extern enum drbd_state_rv drbd_change_state(struct drbd_conf *mdev, + enum chg_state_flags f, + union drbd_state mask, + union drbd_state val); extern void drbd_force_state(struct drbd_conf *, union drbd_state, union drbd_state); -extern int _drbd_request_state(struct drbd_conf *, union drbd_state, - union drbd_state, enum chg_state_flags); -extern int __drbd_set_state(struct drbd_conf *, union drbd_state, - enum chg_state_flags, struct completion *done); +extern enum drbd_state_rv _drbd_request_state(struct drbd_conf *, + union drbd_state, + union drbd_state, + enum chg_state_flags); +extern enum drbd_state_rv __drbd_set_state(struct drbd_conf *, union drbd_state, + enum chg_state_flags, + struct completion *done); extern void print_st_err(struct drbd_conf *, union drbd_state, union drbd_state, int); extern int drbd_thread_start(struct drbd_thread *thi); @@ -1245,7 +1250,7 @@ extern int drbd_send_ov_request(struct drbd_conf *mdev,sector_t sector,int size) extern int drbd_send_bitmap(struct drbd_conf *mdev); extern int _drbd_send_bitmap(struct drbd_conf *mdev); -extern int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode); +extern int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode); extern void drbd_free_bc(struct drbd_backing_dev *ldev); extern void drbd_mdev_cleanup(struct drbd_conf *mdev); @@ -1493,8 +1498,9 @@ enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local); extern void resync_after_online_grow(struct drbd_conf *); extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local); -extern int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, - int force); +extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev, + enum drbd_role new_role, + int force); extern enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); extern void drbd_try_outdate_peer_async(struct drbd_conf *mdev); extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); @@ -1761,11 +1767,11 @@ static inline void drbd_state_unlock(struct drbd_conf *mdev) wake_up(&mdev->misc_wait); } -static inline int _drbd_set_state(struct drbd_conf *mdev, - union drbd_state ns, enum chg_state_flags flags, - struct completion *done) +static inline enum drbd_state_rv +_drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, + enum chg_state_flags flags, struct completion *done) { - int rv; + enum drbd_state_rv rv; read_lock(&global_state_lock); rv = __drbd_set_state(mdev, ns, flags, done); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index cddf311b7429..a101dceb2d49 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -473,12 +473,13 @@ static int cl_wide_st_chg(struct drbd_conf *mdev, (os.conn == C_CONNECTED && ns.conn == C_VERIFY_S); } -int drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, - union drbd_state mask, union drbd_state val) +enum drbd_state_rv +drbd_change_state(struct drbd_conf *mdev, enum chg_state_flags f, + union drbd_state mask, union drbd_state val) { unsigned long flags; union drbd_state os, ns; - int rv; + enum drbd_state_rv rv; spin_lock_irqsave(&mdev->req_lock, flags); os = mdev->state; @@ -502,9 +503,10 @@ void drbd_force_state(struct drbd_conf *mdev, drbd_change_state(mdev, CS_HARD, mask, val); } -static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns); -static int is_valid_state_transition(struct drbd_conf *, - union drbd_state, union drbd_state); +static enum drbd_state_rv is_valid_state(struct drbd_conf *, union drbd_state); +static enum drbd_state_rv is_valid_state_transition(struct drbd_conf *, + union drbd_state, + union drbd_state); static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state os, union drbd_state ns, const char **warn_sync_abort); int drbd_send_state_req(struct drbd_conf *, @@ -516,7 +518,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, { union drbd_state os, ns; unsigned long flags; - int rv; + enum drbd_state_rv rv; if (test_and_clear_bit(CL_ST_CHG_SUCCESS, &mdev->flags)) return SS_CW_SUCCESS; @@ -537,7 +539,7 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, if (rv == SS_SUCCESS) { rv = is_valid_state_transition(mdev, ns, os); if (rv == SS_SUCCESS) - rv = 0; /* cont waiting, otherwise fail. */ + rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ } } spin_unlock_irqrestore(&mdev->req_lock, flags); @@ -555,14 +557,14 @@ _req_st_cond(struct drbd_conf *mdev, union drbd_state mask, * Should not be called directly, use drbd_request_state() or * _drbd_request_state(). */ -static int drbd_req_state(struct drbd_conf *mdev, - union drbd_state mask, union drbd_state val, - enum chg_state_flags f) +static enum drbd_state_rv +drbd_req_state(struct drbd_conf *mdev, union drbd_state mask, + union drbd_state val, enum chg_state_flags f) { struct completion done; unsigned long flags; union drbd_state os, ns; - int rv; + enum drbd_state_rv rv; init_completion(&done); @@ -637,10 +639,11 @@ abort: * Cousin of drbd_request_state(), useful with the CS_WAIT_COMPLETE * flag, or when logging of failed state change requests is not desired. */ -int _drbd_request_state(struct drbd_conf *mdev, union drbd_state mask, - union drbd_state val, enum chg_state_flags f) +enum drbd_state_rv +_drbd_request_state(struct drbd_conf *mdev, union drbd_state mask, + union drbd_state val, enum chg_state_flags f) { - int rv; + enum drbd_state_rv rv; wait_event(mdev->state_wait, (rv = drbd_req_state(mdev, mask, val, f)) != SS_IN_TRANSIENT_STATE); @@ -664,8 +667,8 @@ static void print_st(struct drbd_conf *mdev, char *name, union drbd_state ns) ); } -void print_st_err(struct drbd_conf *mdev, - union drbd_state os, union drbd_state ns, int err) +void print_st_err(struct drbd_conf *mdev, union drbd_state os, + union drbd_state ns, enum drbd_state_rv err) { if (err == SS_IN_TRANSIENT_STATE) return; @@ -680,12 +683,13 @@ void print_st_err(struct drbd_conf *mdev, * @mdev: DRBD device. * @ns: State to consider. */ -static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) +static enum drbd_state_rv +is_valid_state(struct drbd_conf *mdev, union drbd_state ns) { /* See drbd_state_sw_errors in drbd_strings.c */ enum drbd_fencing_p fp; - int rv = SS_SUCCESS; + enum drbd_state_rv rv = SS_SUCCESS; fp = FP_DONT_CARE; if (get_ldev(mdev)) { @@ -748,10 +752,11 @@ static int is_valid_state(struct drbd_conf *mdev, union drbd_state ns) * @ns: new state. * @os: old state. */ -static int is_valid_state_transition(struct drbd_conf *mdev, - union drbd_state ns, union drbd_state os) +static enum drbd_state_rv +is_valid_state_transition(struct drbd_conf *mdev, union drbd_state ns, + union drbd_state os) { - int rv = SS_SUCCESS; + enum drbd_state_rv rv = SS_SUCCESS; if ((ns.conn == C_STARTING_SYNC_T || ns.conn == C_STARTING_SYNC_S) && os.conn > C_CONNECTED) @@ -1029,12 +1034,12 @@ static void drbd_resume_al(struct drbd_conf *mdev) * * Caller needs to hold req_lock, and global_state_lock. Do not call directly. */ -int __drbd_set_state(struct drbd_conf *mdev, - union drbd_state ns, enum chg_state_flags flags, - struct completion *done) +enum drbd_state_rv +__drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, + enum chg_state_flags flags, struct completion *done) { union drbd_state os; - int rv = SS_SUCCESS; + enum drbd_state_rv rv = SS_SUCCESS; const char *warn_sync_abort = NULL; struct after_state_chg_work *ascw; @@ -2031,7 +2036,7 @@ int drbd_send_state_req(struct drbd_conf *mdev, (struct p_header80 *)&p, sizeof(p)); } -int drbd_send_sr_reply(struct drbd_conf *mdev, int retcode) +int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode) { struct p_req_state_reply p; diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index fe336592e538..7a2faf6d48e2 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -288,10 +288,11 @@ void drbd_try_outdate_peer_async(struct drbd_conf *mdev) dev_err(DEV, "out of mem, failed to invoke fence-peer helper\n"); } -int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) +enum drbd_state_rv +drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) { const int max_tries = 4; - int r = 0; + enum drbd_state_rv rv = SS_UNKNOWN_ERROR; int try = 0; int forced = 0; union drbd_state mask, val; @@ -306,17 +307,17 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) val.i = 0; val.role = new_role; while (try++ < max_tries) { - r = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE); + rv = _drbd_request_state(mdev, mask, val, CS_WAIT_COMPLETE); /* in case we first succeeded to outdate, * but now suddenly could establish a connection */ - if (r == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) { + if (rv == SS_CW_FAILED_BY_PEER && mask.pdsk != 0) { val.pdsk = 0; mask.pdsk = 0; continue; } - if (r == SS_NO_UP_TO_DATE_DISK && force && + if (rv == SS_NO_UP_TO_DATE_DISK && force && (mdev->state.disk < D_UP_TO_DATE && mdev->state.disk >= D_INCONSISTENT)) { mask.disk = D_MASK; @@ -325,7 +326,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) continue; } - if (r == SS_NO_UP_TO_DATE_DISK && + if (rv == SS_NO_UP_TO_DATE_DISK && mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) { D_ASSERT(mdev->state.pdsk == D_UNKNOWN); nps = drbd_try_outdate_peer(mdev); @@ -341,9 +342,9 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) continue; } - if (r == SS_NOTHING_TO_DO) + if (rv == SS_NOTHING_TO_DO) goto fail; - if (r == SS_PRIMARY_NOP && mask.pdsk == 0) { + if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) { nps = drbd_try_outdate_peer(mdev); if (force && nps > D_OUTDATED) { @@ -356,7 +357,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) continue; } - if (r == SS_TWO_PRIMARIES) { + if (rv == SS_TWO_PRIMARIES) { /* Maybe the peer is detected as dead very soon... retry at most once more in this case. */ __set_current_state(TASK_INTERRUPTIBLE); @@ -365,16 +366,16 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) try = max_tries - 1; continue; } - if (r < SS_SUCCESS) { - r = _drbd_request_state(mdev, mask, val, + if (rv < SS_SUCCESS) { + rv = _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_WAIT_COMPLETE); - if (r < SS_SUCCESS) + if (rv < SS_SUCCESS) goto fail; } break; } - if (r < SS_SUCCESS) + if (rv < SS_SUCCESS) goto fail; if (forced) @@ -423,7 +424,7 @@ int drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) kobject_uevent(&disk_to_dev(mdev->vdisk)->kobj, KOBJ_CHANGE); fail: mutex_unlock(&mdev->state_mutex); - return r; + return rv; } static struct drbd_conf *ensure_mdev(int minor, int create) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index d34d093278c7..c116cbdc9dca 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3112,7 +3112,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi { struct p_req_state *p = &mdev->data.rbuf.req_state; union drbd_state mask, val; - int rv; + enum drbd_state_rv rv; mask.i = be32_to_cpu(p->mask); val.i = be32_to_cpu(p->val); -- cgit v1.2.2 From bb4379464efeb4624757e2cc0bf9207a309c1075 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 9 Dec 2010 14:02:35 +0100 Subject: drbd: Another small enum drbd_state_rv cleanup Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index c116cbdc9dca..8088744d0ec1 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2209,12 +2209,14 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) case ASB_CALL_HELPER: hg = drbd_asb_recover_0p(mdev); if (hg == -1 && mdev->state.role == R_PRIMARY) { - self = drbd_set_role(mdev, R_SECONDARY, 0); + enum drbd_state_rv rv2; + + drbd_set_role(mdev, R_SECONDARY, 0); /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, * we might be here in C_WF_REPORT_PARAMS which is transient. * we do not need to wait for the after state change work either. */ - self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); - if (self != SS_SUCCESS) { + rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); + if (rv2 != SS_SUCCESS) { drbd_khelper(mdev, "pri-lost-after-sb"); } else { dev_warn(DEV, "Successfully gave up primary role.\n"); @@ -2252,11 +2254,13 @@ static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) case ASB_CALL_HELPER: hg = drbd_asb_recover_0p(mdev); if (hg == -1) { + enum drbd_state_rv rv2; + /* drbd_change_state() does not sleep while in SS_IN_TRANSIENT_STATE, * we might be here in C_WF_REPORT_PARAMS which is transient. * we do not need to wait for the after state change work either. */ - self = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); - if (self != SS_SUCCESS) { + rv2 = drbd_change_state(mdev, CS_VERBOSE, NS(role, R_SECONDARY)); + if (rv2 != SS_SUCCESS) { drbd_khelper(mdev, "pri-lost-after-sb"); } else { dev_warn(DEV, "Successfully gave up primary role.\n"); -- cgit v1.2.2 From 6184ea2145609b4ad63b141bf1f8124135ff4949 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 9 Dec 2010 14:23:27 +0100 Subject: drbd: This code is dead now Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 8088744d0ec1..00dcb1172ca8 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2179,10 +2179,7 @@ static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) { - int self, peer, hg, rv = -100; - - self = mdev->ldev->md.uuid[UI_BITMAP] & 1; - peer = mdev->p_uuid[UI_BITMAP] & 1; + int hg, rv = -100; switch (mdev->net_conf->after_sb_1p) { case ASB_DISCARD_YOUNGER_PRI: @@ -2231,10 +2228,7 @@ static int drbd_asb_recover_1p(struct drbd_conf *mdev) __must_hold(local) static int drbd_asb_recover_2p(struct drbd_conf *mdev) __must_hold(local) { - int self, peer, hg, rv = -100; - - self = mdev->ldev->md.uuid[UI_BITMAP] & 1; - peer = mdev->p_uuid[UI_BITMAP] & 1; + int hg, rv = -100; switch (mdev->net_conf->after_sb_2p) { case ASB_DISCARD_YOUNGER_PRI: -- cgit v1.2.2 From 81e84650c200de0695372461964dd960365696db Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 9 Dec 2010 15:03:57 +0100 Subject: drbd: Use the standard bool, true, and false keywords Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 8 +-- drivers/block/drbd/drbd_bitmap.c | 4 +- drivers/block/drbd/drbd_int.h | 13 +--- drivers/block/drbd/drbd_main.c | 30 ++++----- drivers/block/drbd/drbd_nl.c | 4 +- drivers/block/drbd/drbd_receiver.c | 128 ++++++++++++++++++------------------- drivers/block/drbd/drbd_req.c | 4 +- drivers/block/drbd/drbd_worker.c | 4 +- 8 files changed, 94 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 2e8a95ce79b1..e3f0f4d31d75 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -338,7 +338,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) + mdev->ldev->md.al_offset + mdev->al_tr_pos; if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) - drbd_chk_io_error(mdev, 1, TRUE); + drbd_chk_io_error(mdev, 1, true); if (++mdev->al_tr_pos > div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) @@ -528,7 +528,7 @@ static void atodb_endio(struct bio *bio, int error) if (!error && !uptodate) error = -EIO; - drbd_chk_io_error(mdev, error, TRUE); + drbd_chk_io_error(mdev, error, true); if (error && wc->error == 0) wc->error = error; @@ -991,7 +991,7 @@ void __drbd_set_in_sync(struct drbd_conf *mdev, sector_t sector, int size, if (count && get_ldev(mdev)) { drbd_advance_rs_marks(mdev, drbd_bm_total_weight(mdev)); spin_lock_irqsave(&mdev->al_lock, flags); - drbd_try_clear_on_disk_bm(mdev, sector, count, TRUE); + drbd_try_clear_on_disk_bm(mdev, sector, count, true); spin_unlock_irqrestore(&mdev->al_lock, flags); /* just wake_up unconditional now, various lc_chaged(), @@ -1441,7 +1441,7 @@ void drbd_rs_failed_io(struct drbd_conf *mdev, sector_t sector, int size) mdev->rs_failed += count; if (get_ldev(mdev)) { - drbd_try_clear_on_disk_bm(mdev, sector, count, FALSE); + drbd_try_clear_on_disk_bm(mdev, sector, count, false); put_ldev(mdev); } diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 5dafbabe9617..9390e9526786 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -844,7 +844,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) { dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); - drbd_chk_io_error(mdev, 1, TRUE); + drbd_chk_io_error(mdev, 1, true); err = -EIO; } @@ -916,7 +916,7 @@ int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(lo dev_err(DEV, "IO ERROR writing bitmap sector %lu " "(meta-disk sector %llus)\n", enr, (unsigned long long)on_disk_sector); - drbd_chk_io_error(mdev, 1, TRUE); + drbd_chk_io_error(mdev, 1, true); for (i = 0; i < AL_EXT_PER_BM_SECT; i++) drbd_bm_ALe_set_all(mdev, enr*AL_EXT_PER_BM_SECT+i); } diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 749607a494e6..0855934e19d0 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -72,13 +72,6 @@ extern int fault_devs; extern char usermode_helper[]; -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - /* I don't remember why XCPU ... * This is used to wake the asender, * and to interrupt sending the sending task @@ -2002,17 +1995,17 @@ static inline int drbd_send_ping_ack(struct drbd_conf *mdev) static inline void drbd_thread_stop(struct drbd_thread *thi) { - _drbd_thread_stop(thi, FALSE, TRUE); + _drbd_thread_stop(thi, false, true); } static inline void drbd_thread_stop_nowait(struct drbd_thread *thi) { - _drbd_thread_stop(thi, FALSE, FALSE); + _drbd_thread_stop(thi, false, false); } static inline void drbd_thread_restart_nowait(struct drbd_thread *thi) { - _drbd_thread_stop(thi, TRUE, FALSE); + _drbd_thread_stop(thi, true, false); } /* counts how many answer packets packets we expect from our peer, diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index a101dceb2d49..7eb447d20cce 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -456,7 +456,7 @@ void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what) } /** - * cl_wide_st_chg() - TRUE if the state change is a cluster wide one + * cl_wide_st_chg() - true if the state change is a cluster wide one * @mdev: DRBD device. * @os: old (current) state. * @ns: new (wanted) state. @@ -1623,7 +1623,7 @@ int drbd_thread_start(struct drbd_thread *thi) if (!try_module_get(THIS_MODULE)) { dev_err(DEV, "Failed to get module reference in drbd_thread_start\n"); spin_unlock_irqrestore(&thi->t_lock, flags); - return FALSE; + return false; } init_completion(&thi->stop); @@ -1640,7 +1640,7 @@ int drbd_thread_start(struct drbd_thread *thi) dev_err(DEV, "Couldn't start thread\n"); module_put(THIS_MODULE); - return FALSE; + return false; } spin_lock_irqsave(&thi->t_lock, flags); thi->task = nt; @@ -1660,7 +1660,7 @@ int drbd_thread_start(struct drbd_thread *thi) break; } - return TRUE; + return true; } @@ -1758,8 +1758,8 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, { int sent, ok; - ERR_IF(!h) return FALSE; - ERR_IF(!size) return FALSE; + ERR_IF(!h) return false; + ERR_IF(!size) return false; h->magic = BE_DRBD_MAGIC; h->command = cpu_to_be16(cmd); @@ -2196,14 +2196,14 @@ int _drbd_send_bitmap(struct drbd_conf *mdev) struct p_header80 *p; int ret; - ERR_IF(!mdev->bitmap) return FALSE; + ERR_IF(!mdev->bitmap) return false; /* maybe we should use some per thread scratch page, * and allocate that during initial device creation? */ p = (struct p_header80 *) __get_free_page(GFP_NOIO); if (!p) { dev_err(DEV, "failed to allocate one page buffer in %s\n", __func__); - return FALSE; + return false; } if (get_ldev(mdev)) { @@ -2256,7 +2256,7 @@ int drbd_send_b_ack(struct drbd_conf *mdev, u32 barrier_nr, u32 set_size) p.set_size = cpu_to_be32(set_size); if (mdev->state.conn < C_CONNECTED) - return FALSE; + return false; ok = drbd_send_cmd(mdev, USE_META_SOCKET, P_BARRIER_ACK, (struct p_header80 *)&p, sizeof(p)); return ok; @@ -2284,7 +2284,7 @@ static int _drbd_send_ack(struct drbd_conf *mdev, enum drbd_packets cmd, p.seq_num = cpu_to_be32(atomic_add_return(1, &mdev->packet_seq)); if (!mdev->meta.socket || mdev->state.conn < C_CONNECTED) - return FALSE; + return false; ok = drbd_send_cmd(mdev, USE_META_SOCKET, cmd, (struct p_header80 *)&p, sizeof(p)); return ok; @@ -2390,8 +2390,8 @@ int drbd_send_ov_request(struct drbd_conf *mdev, sector_t sector, int size) } /* called on sndtimeo - * returns FALSE if we should retry, - * TRUE if we think connection is dead + * returns false if we should retry, + * true if we think connection is dead */ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *sock) { @@ -2404,7 +2404,7 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket * || mdev->state.conn < C_CONNECTED; if (drop_it) - return TRUE; + return true; drop_it = !--mdev->ko_count; if (!drop_it) { @@ -3283,7 +3283,7 @@ struct drbd_conf *drbd_new_device(unsigned int minor) goto out_no_disk; mdev->vdisk = disk; - set_disk_ro(disk, TRUE); + set_disk_ro(disk, true); disk->queue = q; disk->major = DRBD_MAJOR; @@ -3560,7 +3560,7 @@ void drbd_md_sync(struct drbd_conf *mdev) if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { /* this was a try anyways ... */ dev_err(DEV, "meta data update failed!\n"); - drbd_chk_io_error(mdev, 1, TRUE); + drbd_chk_io_error(mdev, 1, true); } /* Update mdev->ldev->md.la_size_sect, diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 7a2faf6d48e2..9e94c348c42c 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -385,7 +385,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) wait_event(mdev->misc_wait, atomic_read(&mdev->ap_pending_cnt) == 0); if (new_role == R_SECONDARY) { - set_disk_ro(mdev->vdisk, TRUE); + set_disk_ro(mdev->vdisk, true); if (get_ldev(mdev)) { mdev->ldev->md.uuid[UI_CURRENT] &= ~(u64)1; put_ldev(mdev); @@ -395,7 +395,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) mdev->net_conf->want_lose = 0; put_net_conf(mdev); } - set_disk_ro(mdev->vdisk, FALSE); + set_disk_ro(mdev->vdisk, false); if (get_ldev(mdev)) { if (((mdev->state.conn < C_CONNECTED || mdev->state.pdsk <= D_FAILED) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 00dcb1172ca8..732aacb46a32 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -725,16 +725,16 @@ static int drbd_socket_okay(struct drbd_conf *mdev, struct socket **sock) char tb[4]; if (!*sock) - return FALSE; + return false; rr = drbd_recv_short(mdev, *sock, tb, 4, MSG_DONTWAIT | MSG_PEEK); if (rr > 0 || rr == -EAGAIN) { - return TRUE; + return true; } else { sock_release(*sock); *sock = NULL; - return FALSE; + return false; } } @@ -933,7 +933,7 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi r = drbd_recv(mdev, h, sizeof(*h)); if (unlikely(r != sizeof(*h))) { dev_err(DEV, "short read expecting header on sock: r=%d\n", r); - return FALSE; + return false; } if (likely(h->h80.magic == BE_DRBD_MAGIC)) { @@ -947,11 +947,11 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi be32_to_cpu(h->h80.magic), be16_to_cpu(h->h80.command), be16_to_cpu(h->h80.length)); - return FALSE; + return false; } mdev->last_received = jiffies; - return TRUE; + return true; } static void drbd_flush(struct drbd_conf *mdev) @@ -1160,7 +1160,7 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign switch (mdev->write_ordering) { case WO_none: if (rv == FE_RECYCLED) - return TRUE; + return true; /* receiver context, in the writeout path of the other node. * avoid potential distributed deadlock */ @@ -1188,10 +1188,10 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign D_ASSERT(atomic_read(&epoch->active) == 0); D_ASSERT(epoch->flags == 0); - return TRUE; + return true; default: dev_err(DEV, "Strangeness in mdev->write_ordering %d\n", mdev->write_ordering); - return FALSE; + return false; } epoch->flags = 0; @@ -1209,7 +1209,7 @@ static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsign } spin_unlock(&mdev->epoch_lock); - return TRUE; + return true; } /* used from receive_RSDataReply (recv_resync_read) @@ -1303,7 +1303,7 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) void *data; if (!data_size) - return TRUE; + return true; page = drbd_pp_alloc(mdev, 1, 1); @@ -1426,7 +1426,7 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si atomic_add(data_size >> 9, &mdev->rs_sect_ev); if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0) - return TRUE; + return true; /* drbd_submit_ee currently fails for one reason only: * not being able to allocate enough bios. @@ -1438,7 +1438,7 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si drbd_free_ee(mdev, e); fail: put_ldev(mdev); - return FALSE; + return false; } static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) @@ -1455,7 +1455,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi spin_unlock_irq(&mdev->req_lock); if (unlikely(!req)) { dev_err(DEV, "Got a corrupt block_id/sector pair(1).\n"); - return FALSE; + return false; } /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid @@ -1655,7 +1655,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned e = read_in_block(mdev, p->block_id, sector, data_size); if (!e) { put_ldev(mdev); - return FALSE; + return false; } e->w.cb = e_end_block; @@ -1774,7 +1774,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned put_ldev(mdev); wake_asender(mdev); finish_wait(&mdev->misc_wait, &wait); - return TRUE; + return true; } if (signal_pending(current)) { @@ -1830,7 +1830,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0) - return TRUE; + return true; /* drbd_submit_ee currently fails for one reason only: * not being able to allocate enough bios. @@ -1848,7 +1848,7 @@ out_interrupted: * receive a barrier... atomic_inc(&mdev->epoch_size); */ put_ldev(mdev); drbd_free_ee(mdev, e); - return FALSE; + return false; } /* We may throttle resync, if the lower device seems to be busy, @@ -1934,12 +1934,12 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un if (size <= 0 || (size & 0x1ff) != 0 || size > DRBD_MAX_BIO_SIZE) { dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, (unsigned long long)sector, size); - return FALSE; + return false; } if (sector + (size>>9) > capacity) { dev_err(DEV, "%s:%d: sector: %llus, size: %u\n", __FILE__, __LINE__, (unsigned long long)sector, size); - return FALSE; + return false; } if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) { @@ -1976,7 +1976,7 @@ static int receive_DataRequest(struct drbd_conf *mdev, enum drbd_packets cmd, un e = drbd_alloc_ee(mdev, p->block_id, sector, size, GFP_NOIO); if (!e) { put_ldev(mdev); - return FALSE; + return false; } switch (cmd) { @@ -2089,7 +2089,7 @@ submit: spin_unlock_irq(&mdev->req_lock); if (drbd_submit_ee(mdev, e, READ, fault_type) == 0) - return TRUE; + return true; /* drbd_submit_ee currently fails for one reason only: * not being able to allocate enough bios. @@ -2102,7 +2102,7 @@ submit: out_free_e: put_ldev(mdev); drbd_free_ee(mdev, e); - return FALSE; + return false; } static int drbd_asb_recover_0p(struct drbd_conf *mdev) __must_hold(local) @@ -2690,7 +2690,7 @@ static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsig unsigned char *my_alg = mdev->net_conf->integrity_alg; if (drbd_recv(mdev, p_integrity_alg, data_size) != data_size) - return FALSE; + return false; p_integrity_alg[SHARED_SECRET_MAX-1] = 0; if (strcmp(p_integrity_alg, my_alg)) { @@ -2701,11 +2701,11 @@ static int receive_protocol(struct drbd_conf *mdev, enum drbd_packets cmd, unsig my_alg[0] ? my_alg : (unsigned char *)""); } - return TRUE; + return true; disconnect: drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - return FALSE; + return false; } /* helper function @@ -2737,7 +2737,7 @@ struct crypto_hash *drbd_crypto_alloc_digest_safe(const struct drbd_conf *mdev, static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int packet_size) { - int ok = TRUE; + int ok = true; struct p_rs_param_95 *p = &mdev->data.rbuf.rs_param_95; unsigned int header_size, data_size, exp_max_sz; struct crypto_hash *verify_tfm = NULL; @@ -2755,7 +2755,7 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi if (packet_size > exp_max_sz) { dev_err(DEV, "SyncParam packet too long: received %u, expected <= %u bytes\n", packet_size, exp_max_sz); - return FALSE; + return false; } if (apv <= 88) { @@ -2775,7 +2775,7 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); if (drbd_recv(mdev, &p->head.payload, header_size) != header_size) - return FALSE; + return false; mdev->sync_conf.rate = be32_to_cpu(p->rate); @@ -2785,11 +2785,11 @@ static int receive_SyncParam(struct drbd_conf *mdev, enum drbd_packets cmd, unsi dev_err(DEV, "verify-alg too long, " "peer wants %u, accepting only %u byte\n", data_size, SHARED_SECRET_MAX); - return FALSE; + return false; } if (drbd_recv(mdev, p->verify_alg, data_size) != data_size) - return FALSE; + return false; /* we expect NUL terminated string */ /* but just in case someone tries to be evil */ @@ -2883,7 +2883,7 @@ disconnect: /* but free the verify_tfm again, if csums_tfm did not work out */ crypto_free_hash(verify_tfm); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - return FALSE; + return false; } static void drbd_setup_order_type(struct drbd_conf *mdev, int peer) @@ -2920,7 +2920,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (p_size == 0 && mdev->state.disk == D_DISKLESS) { dev_err(DEV, "some backing storage is needed\n"); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - return FALSE; + return false; } /* just store the peer's disk size for now. @@ -2957,7 +2957,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); mdev->ldev->dc.disk_size = my_usize; put_ldev(mdev); - return FALSE; + return false; } put_ldev(mdev); } @@ -2967,7 +2967,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned dd = drbd_determin_dev_size(mdev, ddsf); put_ldev(mdev); if (dd == dev_size_error) - return FALSE; + return false; drbd_md_sync(mdev); } else { /* I am diskless, need to accept the peer's size. */ @@ -3014,7 +3014,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned } } - return TRUE; + return true; } static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) @@ -3038,7 +3038,7 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned dev_err(DEV, "Can only connect to data with current UUID=%016llX\n", (unsigned long long)mdev->ed_uuid); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - return FALSE; + return false; } if (get_ldev(mdev)) { @@ -3073,7 +3073,7 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT) drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); - return TRUE; + return true; } /** @@ -3118,7 +3118,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi if (test_bit(DISCARD_CONCURRENT, &mdev->flags) && test_bit(CLUSTER_ST_CHANGE, &mdev->flags)) { drbd_send_sr_reply(mdev, SS_CONCURRENT_ST_CHG); - return TRUE; + return true; } mask = convert_state(mask); @@ -3129,7 +3129,7 @@ static int receive_req_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsi drbd_send_sr_reply(mdev, rv); drbd_md_sync(mdev); - return TRUE; + return true; } static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) @@ -3174,7 +3174,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned peer_state.conn == C_CONNECTED) { if (drbd_bm_total_weight(mdev) <= mdev->rs_failed) drbd_resync_finished(mdev); - return TRUE; + return true; } } @@ -3227,10 +3227,10 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned real_peer_disk = D_DISKLESS; } else { if (test_and_clear_bit(CONN_DRY_RUN, &mdev->flags)) - return FALSE; + return false; D_ASSERT(os.conn == C_WF_REPORT_PARAMS); drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - return FALSE; + return false; } } } @@ -3255,7 +3255,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned drbd_uuid_new_current(mdev); clear_bit(NEW_CUR_UUID, &mdev->flags); drbd_force_state(mdev, NS2(conn, C_PROTOCOL_ERROR, susp, 0)); - return FALSE; + return false; } rv = _drbd_set_state(mdev, ns, cs_flags, NULL); ns = mdev->state; @@ -3263,7 +3263,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (rv < SS_SUCCESS) { drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); - return FALSE; + return false; } if (os.conn > C_WF_REPORT_PARAMS) { @@ -3281,7 +3281,7 @@ static int receive_state(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned drbd_md_sync(mdev); /* update connected indicator, la_size, ... */ - return TRUE; + return true; } static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) @@ -3308,7 +3308,7 @@ static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsi } else dev_err(DEV, "Ignoring SyncUUID packet!\n"); - return TRUE; + return true; } enum receive_bitmap_ret { OK, DONE, FAILED }; @@ -3462,7 +3462,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne struct bm_xfer_ctx c; void *buffer; enum receive_bitmap_ret ret; - int ok = FALSE; + int ok = false; struct p_header80 *h = &mdev->data.rbuf.header.h80; /* drbd_bm_lock(mdev, "receive bitmap"); By intention no bm_lock */ @@ -3535,7 +3535,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne drbd_conn_str(mdev->state.conn)); } - ok = TRUE; + ok = true; out: /* drbd_bm_unlock(mdev); by intention no lock */ if (ok && mdev->state.conn == C_WF_BITMAP_S) @@ -3569,7 +3569,7 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, enum drbd_packets cmd, u * with the data requests being unplugged */ drbd_tcp_quickack(mdev->data.socket); - return TRUE; + return true; } static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) @@ -3578,7 +3578,7 @@ static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, un drbd_set_out_of_sync(mdev, be64_to_cpu(p->sector), be32_to_cpu(p->blksize)); - return TRUE; + return true; } typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, enum drbd_packets cmd, unsigned int to_receive); @@ -4147,7 +4147,7 @@ static int got_RqSReply(struct drbd_conf *mdev, struct p_header80 *h) } wake_up(&mdev->state_wait); - return TRUE; + return true; } static int got_Ping(struct drbd_conf *mdev, struct p_header80 *h) @@ -4163,7 +4163,7 @@ static int got_PingAck(struct drbd_conf *mdev, struct p_header80 *h) if (!test_and_set_bit(GOT_PING_ACK, &mdev->flags)) wake_up(&mdev->misc_wait); - return TRUE; + return true; } static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) @@ -4186,7 +4186,7 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) dec_rs_pending(mdev); atomic_add(blksize >> 9, &mdev->rs_sect_in); - return TRUE; + return true; } /* when we receive the ACK for a write request, @@ -4230,14 +4230,14 @@ static int validate_req_change_req_state(struct drbd_conf *mdev, if (unlikely(!req)) { spin_unlock_irq(&mdev->req_lock); dev_err(DEV, "%s: got a corrupt block_id/sector pair\n", func); - return FALSE; + return false; } __req_mod(req, what, &m); spin_unlock_irq(&mdev->req_lock); if (m.bio) complete_master_bio(mdev, &m); - return TRUE; + return true; } static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) @@ -4252,7 +4252,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) if (is_syncer_block_id(p->block_id)) { drbd_set_in_sync(mdev, sector, blksize); dec_rs_pending(mdev); - return TRUE; + return true; } switch (be16_to_cpu(h->command)) { case P_RS_WRITE_ACK: @@ -4273,7 +4273,7 @@ static int got_BlockAck(struct drbd_conf *mdev, struct p_header80 *h) break; default: D_ASSERT(0); - return FALSE; + return false; } return validate_req_change_req_state(mdev, p->block_id, sector, @@ -4294,7 +4294,7 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) int size = be32_to_cpu(p->blksize); dec_rs_pending(mdev); drbd_rs_failed_io(mdev, sector, size); - return TRUE; + return true; } return validate_req_change_req_state(mdev, p->block_id, sector, _ack_id_to_req, __func__ , neg_acked); @@ -4332,7 +4332,7 @@ static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) put_ldev(mdev); } - return TRUE; + return true; } static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) @@ -4349,7 +4349,7 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) drbd_queue_work_front(&mdev->data.work, w); } - return TRUE; + return true; } static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) @@ -4370,7 +4370,7 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) ov_oos_print(mdev); if (!get_ldev(mdev)) - return TRUE; + return true; drbd_rs_complete_io(mdev, sector); dec_rs_pending(mdev); @@ -4393,12 +4393,12 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) } } put_ldev(mdev); - return TRUE; + return true; } static int got_skip(struct drbd_conf *mdev, struct p_header80 *h) { - return TRUE; + return true; } struct asender_cmd { diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 53e7cc506456..528909090df7 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -445,7 +445,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, req->rq_state |= RQ_LOCAL_COMPLETED; req->rq_state &= ~RQ_LOCAL_PENDING; - __drbd_chk_io_error(mdev, FALSE); + __drbd_chk_io_error(mdev, false); _req_may_be_done_not_susp(req, m); put_ldev(mdev); break; @@ -466,7 +466,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, D_ASSERT(!(req->rq_state & RQ_NET_MASK)); - __drbd_chk_io_error(mdev, FALSE); + __drbd_chk_io_error(mdev, false); put_ldev(mdev); /* no point in retrying if there is no good remote data, diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index e201f6f82c0e..9fe3e890da0f 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -96,7 +96,7 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local) if (list_empty(&mdev->read_ee)) wake_up(&mdev->ee_wait); if (test_bit(__EE_WAS_ERROR, &e->flags)) - __drbd_chk_io_error(mdev, FALSE); + __drbd_chk_io_error(mdev, false); spin_unlock_irqrestore(&mdev->req_lock, flags); drbd_queue_work(&mdev->data.work, &e->w); @@ -139,7 +139,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo : list_empty(&mdev->active_ee); if (test_bit(__EE_WAS_ERROR, &e->flags)) - __drbd_chk_io_error(mdev, FALSE); + __drbd_chk_io_error(mdev, false); spin_unlock_irqrestore(&mdev->req_lock, flags); if (is_syncer_req) -- cgit v1.2.2 From f2024e7ce29f4287395ce879364cd68c7ac226f2 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 10 Dec 2010 13:44:05 +0100 Subject: drbd: drbd_nl_disk_conf: Avoid a compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Warning: comparison between ‘enum drbd_ret_code’ and ‘enum drbd_state_rv’ Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 9e94c348c42c..ada5483f7e56 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -859,7 +859,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp struct lru_cache *resync_lru = NULL; union drbd_state ns, os; unsigned int max_bio_size; - int rv; + enum drbd_state_rv rv; int cp_discovered = 0; int logical_block_size; @@ -1005,9 +1005,10 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp /* and for any other previously queued work */ drbd_flush_workqueue(mdev); - retcode = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE); + rv = _drbd_request_state(mdev, NS(disk, D_ATTACHING), CS_VERBOSE); + retcode = rv; /* FIXME: Type mismatch. */ drbd_resume_io(mdev); - if (retcode < SS_SUCCESS) + if (rv < SS_SUCCESS) goto fail; if (!get_ldev_if_state(mdev, D_ATTACHING)) -- cgit v1.2.2 From 4114be815f9811da42a21dc2f7ff552833660595 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 10 Dec 2010 17:09:10 +0100 Subject: drbd: receive_bitmap: Fix the wrong return value Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 732aacb46a32..44b102d41b4a 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3499,7 +3499,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne goto out; if (data_size <= (sizeof(*p) - sizeof(p->head))) { dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); - return FAILED; + return false; } ret = decode_bitmap_c(mdev, p, &c); } else { -- cgit v1.2.2 From de1f8e4a0af3c2d0dff9f6341fead4b509941282 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 10 Dec 2010 21:04:00 +0100 Subject: drbd: receive_bitmap: Avoid casting enum drbd_state_rv to int Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 44b102d41b4a..2a604e7b7a01 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3522,12 +3522,14 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne INFO_bm_xfer_stats(mdev, "receive", &c); if (mdev->state.conn == C_WF_BITMAP_T) { + enum drbd_state_rv rv; + ok = !drbd_send_bitmap(mdev); if (!ok) goto out; /* Omit CS_ORDERED with this state transition to avoid deadlocks. */ - ok = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); - D_ASSERT(ok == SS_SUCCESS); + rv = _drbd_request_state(mdev, NS(conn, C_WF_SYNC_UUID), CS_VERBOSE); + D_ASSERT(rv == SS_SUCCESS); } else if (mdev->state.conn != C_WF_BITMAP_S) { /* admin may have requested C_DISCONNECTING, * other threads may have noticed network errors */ -- cgit v1.2.2 From 78fcbdae224469cb48767fa29ca41f1d5890e57c Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Fri, 10 Dec 2010 22:18:27 +0100 Subject: drbd: receive_bitmap: Missing free_page() on error path Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2a604e7b7a01..f217d351d77c 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3499,7 +3499,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne goto out; if (data_size <= (sizeof(*p) - sizeof(p->head))) { dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); - return false; + goto out; } ret = decode_bitmap_c(mdev, p, &c); } else { -- cgit v1.2.2 From f70af118e3f3638698ac08959a41b9f9fe7237c8 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Sat, 11 Dec 2010 18:51:50 +0100 Subject: drbd: send_bitmap_rle_or_plain: Get rid of ugly and useless enum Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7eb447d20cce..7c72595b7ff0 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2140,9 +2140,15 @@ int fill_bitmap_rle_bits(struct drbd_conf *mdev, return len; } -enum { OK, FAILED, DONE } +/** + * send_bitmap_rle_or_plain + * + * Return 0 when done, 1 when another iteration is needed, and a negative error + * code upon failure. + */ +static int send_bitmap_rle_or_plain(struct drbd_conf *mdev, - struct p_header80 *h, struct bm_xfer_ctx *c) + struct p_header80 *h, struct bm_xfer_ctx *c) { struct p_compressed_bm *p = (void*)h; unsigned long num_words; @@ -2152,7 +2158,7 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, len = fill_bitmap_rle_bits(mdev, p, c); if (len < 0) - return FAILED; + return -EIO; if (len) { DCBP_set_code(p, RLE_VLI_Bits); @@ -2182,11 +2188,14 @@ send_bitmap_rle_or_plain(struct drbd_conf *mdev, if (c->bit_offset > c->bm_bits) c->bit_offset = c->bm_bits; } - ok = ok ? ((len == 0) ? DONE : OK) : FAILED; - - if (ok == DONE) - INFO_bm_xfer_stats(mdev, "send", c); - return ok; + if (ok) { + if (len == 0) { + INFO_bm_xfer_stats(mdev, "send", c); + return 0; + } else + return 1; + } + return -EIO; } /* See the comment at receive_bitmap() */ @@ -2194,7 +2203,7 @@ int _drbd_send_bitmap(struct drbd_conf *mdev) { struct bm_xfer_ctx c; struct p_header80 *p; - int ret; + int err; ERR_IF(!mdev->bitmap) return false; @@ -2229,11 +2238,11 @@ int _drbd_send_bitmap(struct drbd_conf *mdev) }; do { - ret = send_bitmap_rle_or_plain(mdev, p, &c); - } while (ret == OK); + err = send_bitmap_rle_or_plain(mdev, p, &c); + } while (err > 0); free_page((unsigned long) p); - return (ret == DONE); + return err == 0; } int drbd_send_bitmap(struct drbd_conf *mdev) -- cgit v1.2.2 From 2c46407d241f4b0e5b87959aae8f50f41fdd2a3a Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Sat, 11 Dec 2010 21:53:12 +0100 Subject: drbd: receive_bitmap_plain: Get rid of ugly and useless enum Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 73 ++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f217d351d77c..be7fc67eeeca 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3311,23 +3311,32 @@ static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsi return true; } -enum receive_bitmap_ret { OK, DONE, FAILED }; - -static enum receive_bitmap_ret +/** + * receive_bitmap_plain + * + * Return 0 when done, 1 when another iteration is needed, and a negative error + * code upon failure. + */ +static int receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, unsigned long *buffer, struct bm_xfer_ctx *c) { unsigned num_words = min_t(size_t, BM_PACKET_WORDS, c->bm_words - c->word_offset); unsigned want = num_words * sizeof(long); + int err; if (want != data_size) { dev_err(DEV, "%s:want (%u) != data_size (%u)\n", __func__, want, data_size); - return FAILED; + return -EIO; } if (want == 0) - return DONE; - if (drbd_recv(mdev, buffer, want) != want) - return FAILED; + return 0; + err = drbd_recv(mdev, buffer, want); + if (err != want) { + if (err >= 0) + err = -EIO; + return err; + } drbd_bm_merge_lel(mdev, c->word_offset, num_words, buffer); @@ -3336,10 +3345,16 @@ receive_bitmap_plain(struct drbd_conf *mdev, unsigned int data_size, if (c->bit_offset > c->bm_bits) c->bit_offset = c->bm_bits; - return OK; + return 1; } -static enum receive_bitmap_ret +/** + * recv_bm_rle_bits + * + * Return 0 when done, 1 when another iteration is needed, and a negative error + * code upon failure. + */ +static int recv_bm_rle_bits(struct drbd_conf *mdev, struct p_compressed_bm *p, struct bm_xfer_ctx *c) @@ -3359,18 +3374,18 @@ recv_bm_rle_bits(struct drbd_conf *mdev, bits = bitstream_get_bits(&bs, &look_ahead, 64); if (bits < 0) - return FAILED; + return -EIO; for (have = bits; have > 0; s += rl, toggle = !toggle) { bits = vli_decode_bits(&rl, look_ahead); if (bits <= 0) - return FAILED; + return -EIO; if (toggle) { e = s + rl -1; if (e >= c->bm_bits) { dev_err(DEV, "bitmap overflow (e:%lu) while decoding bm RLE packet\n", e); - return FAILED; + return -EIO; } _drbd_bm_set_bits(mdev, s, e); } @@ -3380,14 +3395,14 @@ recv_bm_rle_bits(struct drbd_conf *mdev, have, bits, look_ahead, (unsigned int)(bs.cur.b - p->code), (unsigned int)bs.buf_len); - return FAILED; + return -EIO; } look_ahead >>= bits; have -= bits; bits = bitstream_get_bits(&bs, &tmp, 64 - have); if (bits < 0) - return FAILED; + return -EIO; look_ahead |= tmp << have; have += bits; } @@ -3395,10 +3410,16 @@ recv_bm_rle_bits(struct drbd_conf *mdev, c->bit_offset = s; bm_xfer_ctx_bit_to_word_offset(c); - return (s == c->bm_bits) ? DONE : OK; + return (s != c->bm_bits); } -static enum receive_bitmap_ret +/** + * decode_bitmap_c + * + * Return 0 when done, 1 when another iteration is needed, and a negative error + * code upon failure. + */ +static int decode_bitmap_c(struct drbd_conf *mdev, struct p_compressed_bm *p, struct bm_xfer_ctx *c) @@ -3412,7 +3433,7 @@ decode_bitmap_c(struct drbd_conf *mdev, dev_err(DEV, "receive_bitmap_c: unknown encoding %u\n", p->encoding); drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); - return FAILED; + return -EIO; } void INFO_bm_xfer_stats(struct drbd_conf *mdev, @@ -3461,7 +3482,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne { struct bm_xfer_ctx c; void *buffer; - enum receive_bitmap_ret ret; + int err; int ok = false; struct p_header80 *h = &mdev->data.rbuf.header.h80; @@ -3480,9 +3501,9 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne .bm_words = drbd_bm_words(mdev), }; - do { + for(;;) { if (cmd == P_BITMAP) { - ret = receive_bitmap_plain(mdev, data_size, buffer, &c); + err = receive_bitmap_plain(mdev, data_size, buffer, &c); } else if (cmd == P_COMPRESSED_BITMAP) { /* MAYBE: sanity check that we speak proto >= 90, * and the feature is enabled! */ @@ -3501,7 +3522,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne dev_err(DEV, "ReportCBitmap packet too small (l:%u)\n", data_size); goto out; } - ret = decode_bitmap_c(mdev, p, &c); + err = decode_bitmap_c(mdev, p, &c); } else { dev_warn(DEV, "receive_bitmap: cmd neither ReportBitMap nor ReportCBitMap (is 0x%x)", cmd); goto out; @@ -3510,14 +3531,14 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne c.packets[cmd == P_BITMAP]++; c.bytes[cmd == P_BITMAP] += sizeof(struct p_header80) + data_size; - if (ret != OK) + if (err <= 0) { + if (err < 0) + goto out; break; - + } if (!drbd_recv_header(mdev, &cmd, &data_size)) goto out; - } while (ret == OK); - if (ret == FAILED) - goto out; + } INFO_bm_xfer_stats(mdev, "receive", &c); -- cgit v1.2.2 From 24dccabb390412d04435e11cfb535df51def7b2d Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Sun, 12 Dec 2010 17:45:41 +0100 Subject: drbd: Fix: drbd_bitmap_io does not return an enum determine_dev_size I guess bitmap I/O errors are supposed to cause drbd_determin_dev_size to return dev_size_error. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index ada5483f7e56..2f0724982143 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -643,11 +643,17 @@ enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, enum dds_ || prev_size != mdev->ldev->md.md_size_sect; if (la_size_changed || md_moved) { + int err; + drbd_al_shrink(mdev); /* All extents inactive. */ dev_info(DEV, "Writing the whole bitmap, %s\n", la_size_changed && md_moved ? "size changed and md moved" : la_size_changed ? "size changed" : "md moved"); - rv = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */ + err = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */ + if (err) { + rv = dev_size_error; + goto out; + } drbd_md_mark_dirty(mdev); } -- cgit v1.2.2 From 1b881ef77537f1077482f9946a6a99b4e2dd54b2 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 13 Dec 2010 18:03:38 +0100 Subject: drbd: Rename __inc_ap_bio_cond to may_inc_ap_bio The old name is confusing: the function does not increment anything. Also rename _inc_ap_bio_cond to inc_ap_bio_cond: there is no need for an underscore. Finally, make it clear that these functions return boolean values. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 22 +++++++++++----------- drivers/block/drbd/drbd_main.c | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 0855934e19d0..f6da48bb8c70 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2284,14 +2284,14 @@ static inline int is_susp(union drbd_state s) return s.susp || s.susp_nod || s.susp_fen; } -static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) +static inline bool may_inc_ap_bio(struct drbd_conf *mdev) { int mxb = drbd_get_max_buffers(mdev); if (is_susp(mdev->state)) - return 0; + return false; if (test_bit(SUSPEND_IO, &mdev->flags)) - return 0; + return false; /* to avoid potential deadlock or bitmap corruption, * in various places, we only allow new application io @@ -2299,23 +2299,23 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) /* no new io accepted when attaching or detaching the disk */ if (!drbd_state_is_stable(mdev)) - return 0; + return false; /* since some older kernels don't have atomic_add_unless, * and we are within the spinlock anyways, we have this workaround. */ if (atomic_read(&mdev->ap_bio_cnt) > mxb) - return 0; + return false; if (test_bit(BITMAP_IO, &mdev->flags)) - return 0; - return 1; + return false; + return true; } -static inline int _inc_ap_bio_cond(struct drbd_conf *mdev, int count) +static inline bool inc_ap_bio_cond(struct drbd_conf *mdev, int count) { - int rv = 0; + bool rv = false; spin_lock_irq(&mdev->req_lock); - rv = __inc_ap_bio_cond(mdev); + rv = may_inc_ap_bio(mdev); if (rv) atomic_add(count, &mdev->ap_bio_cnt); spin_unlock_irq(&mdev->req_lock); @@ -2333,7 +2333,7 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int count) * to avoid races with the reconnect code, * we need to atomic_inc within the spinlock. */ - wait_event(mdev->misc_wait, _inc_ap_bio_cond(mdev, count)); + wait_event(mdev->misc_wait, inc_ap_bio_cond(mdev, count)); } static inline void dec_ap_bio(struct drbd_conf *mdev) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7c72595b7ff0..67fffad213ec 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3239,7 +3239,7 @@ static int drbd_congested(void *congested_data, int bdi_bits) char reason = '-'; int r = 0; - if (!__inc_ap_bio_cond(mdev)) { + if (!may_inc_ap_bio(mdev)) { /* DRBD has frozen IO */ r = bdi_bits; reason = 'd'; -- cgit v1.2.2 From 7777a8ba1fc980e5edfe492ebf5a1676497b8db2 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 15 Dec 2010 23:21:39 +0100 Subject: drbd: bitmap: don't count unused bits (fix non-terminating resync) We trusted the on-disk bitmap to have unused bits cleared. In case that is not true for whatever reason, and we take a code path where the unused bits don't get cleared elsewhere (bm_clear_surplus is not called), we may miscount the bits, and get confused during resync, waiting for bits to get cleared that we don't even use: the resync process would not terminate. Fix this by masking out unused bits in __bm_count_bits. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 9390e9526786..c5361487cf47 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -376,9 +376,16 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia unsigned long *p_addr, *bm, offset = 0; unsigned long bits = 0; unsigned long i, do_now; + unsigned long words; - while (offset < b->bm_words) { - i = do_now = min_t(size_t, b->bm_words-offset, LWPP); + /* due to 64bit alignment, the last long on a 32bit arch + * may be not used at all. The last used long will likely + * be only partially used, always. Don't count those bits, + * but mask them out. */ + words = (b->bm_bits + BITS_PER_LONG - 1) >> LN2_BPL; + + while (offset < words) { + i = do_now = min_t(size_t, words-offset, LWPP); p_addr = __bm_map_paddr(b, offset, KM_USER0); bm = p_addr + MLPP(offset); while (i--) { @@ -388,8 +395,20 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia #endif bits += hweight_long(*bm++); } - __bm_unmap(p_addr, KM_USER0); offset += do_now; + if (offset == words) { + /* last word may only be partially used, + * see also bm_clear_surplus. */ + i = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1; + if (i) { + bits -= hweight_long(p_addr[do_now-1] & ~i); + p_addr[do_now-1] &= i; + } + /* 32bit arch, may have an unused padding long */ + if (words != b->bm_words) + p_addr[do_now] = 0; + } + __bm_unmap(p_addr, KM_USER0); cond_resched(); } -- cgit v1.2.2 From 95a0f10cddbf93ce89c175ac1c53dad2d20ad309 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 15 Dec 2010 08:59:09 +0100 Subject: drbd: store in-core bitmap little endian, regardless of architecture Our on-disk bitmap is a little endian bitstream. Up to now, we have stored the in-core copy of that in native endian, applying byte order conversion when necessary. Instead, keep the bitmap pages little endian, as they are read from disk, and use the generic_*_le_bit family of functions. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 166 ++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index c5361487cf47..8d959ed6c2cc 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -30,6 +30,7 @@ #include #include "drbd_int.h" + /* OPAQUE outside this file! * interface defined in drbd_int.h @@ -154,6 +155,14 @@ void drbd_bm_unlock(struct drbd_conf *mdev) mutex_unlock(&b->bm_change); } +static unsigned int bm_bit_to_page_idx(struct drbd_bitmap *b, u64 bitnr) +{ + /* page_nr = (bitnr/8) >> PAGE_SHIFT; */ + unsigned int page_nr = bitnr >> (PAGE_SHIFT + 3); + BUG_ON(page_nr >= b->bm_number_of_pages); + return page_nr; +} + /* word offset to long pointer */ static unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset, const enum km_type km) { @@ -168,6 +177,17 @@ static unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset return (unsigned long *) kmap_atomic(page, km); } +static unsigned long *__bm_map_pidx(struct drbd_bitmap *b, unsigned int idx, const enum km_type km) +{ + struct page *page = b->bm_pages[idx]; + return (unsigned long *) kmap_atomic(page, km); +} + +static unsigned long *bm_map_pidx(struct drbd_bitmap *b, unsigned int idx) +{ + return __bm_map_pidx(b, idx, KM_IRQ1); +} + static unsigned long * bm_map_paddr(struct drbd_bitmap *b, unsigned long offset) { return __bm_map_paddr(b, offset, KM_IRQ1); @@ -329,22 +349,42 @@ void drbd_bm_cleanup(struct drbd_conf *mdev) * this masks out the remaining bits. * Returns the number of bits cleared. */ +#define BITS_PER_PAGE (1UL << (PAGE_SHIFT + 3)) +#define BITS_PER_PAGE_MASK (BITS_PER_PAGE - 1) +#define BITS_PER_LONG_MASK (BITS_PER_LONG - 1) static int bm_clear_surplus(struct drbd_bitmap *b) { - const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1; - size_t w = b->bm_bits >> LN2_BPL; - int cleared = 0; + unsigned long mask; unsigned long *p_addr, *bm; + int tmp; + int cleared = 0; - p_addr = bm_map_paddr(b, w); - bm = p_addr + MLPP(w); - if (w < b->bm_words) { + /* number of bits modulo bits per page */ + tmp = (b->bm_bits & BITS_PER_PAGE_MASK); + /* mask the used bits of the word containing the last bit */ + mask = (1UL << (tmp & BITS_PER_LONG_MASK)) -1; + /* bitmap is always stored little endian, + * on disk and in core memory alike */ + mask = cpu_to_lel(mask); + + /* because of the "extra long to catch oob access" we allocate in + * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page + * containing the last _relevant_ bitmap word */ + p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, b->bm_bits - 1)); + bm = p_addr + (tmp/BITS_PER_LONG); + if (mask) { + /* If mask != 0, we are not exactly aligned, so bm now points + * to the long containing the last bit. + * If mask == 0, bm already points to the word immediately + * after the last (long word aligned) bit. */ cleared = hweight_long(*bm & ~mask); *bm &= mask; - w++; bm++; + bm++; } - if (w < b->bm_words) { + if (BITS_PER_LONG == 32 && ((bm - p_addr) & 1) == 1) { + /* on a 32bit arch, we may need to zero out + * a padding long to align with a 64bit remote */ cleared += hweight_long(*bm); *bm = 0; } @@ -354,24 +394,41 @@ static int bm_clear_surplus(struct drbd_bitmap *b) static void bm_set_surplus(struct drbd_bitmap *b) { - const unsigned long mask = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) - 1; - size_t w = b->bm_bits >> LN2_BPL; + unsigned long mask; unsigned long *p_addr, *bm; - - p_addr = bm_map_paddr(b, w); - bm = p_addr + MLPP(w); - if (w < b->bm_words) { + int tmp; + + /* number of bits modulo bits per page */ + tmp = (b->bm_bits & BITS_PER_PAGE_MASK); + /* mask the used bits of the word containing the last bit */ + mask = (1UL << (tmp & BITS_PER_LONG_MASK)) -1; + /* bitmap is always stored little endian, + * on disk and in core memory alike */ + mask = cpu_to_lel(mask); + + /* because of the "extra long to catch oob access" we allocate in + * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page + * containing the last _relevant_ bitmap word */ + p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, b->bm_bits - 1)); + bm = p_addr + (tmp/BITS_PER_LONG); + if (mask) { + /* If mask != 0, we are not exactly aligned, so bm now points + * to the long containing the last bit. + * If mask == 0, bm already points to the word immediately + * after the last (long word aligned) bit. */ *bm |= ~mask; - bm++; w++; + bm++; } - if (w < b->bm_words) { - *bm = ~(0UL); + if (BITS_PER_LONG == 32 && ((bm - p_addr) & 1) == 1) { + /* on a 32bit arch, we may need to zero out + * a padding long to align with a 64bit remote */ + *bm = ~0UL; } bm_unmap(p_addr); } -static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endian) +static unsigned long bm_count_bits(struct drbd_bitmap *b) { unsigned long *p_addr, *bm, offset = 0; unsigned long bits = 0; @@ -389,10 +446,6 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia p_addr = __bm_map_paddr(b, offset, KM_USER0); bm = p_addr + MLPP(offset); while (i--) { -#ifndef __LITTLE_ENDIAN - if (swap_endian) - *bm = lel_to_cpu(*bm); -#endif bits += hweight_long(*bm++); } offset += do_now; @@ -415,16 +468,6 @@ static unsigned long __bm_count_bits(struct drbd_bitmap *b, const int swap_endia return bits; } -static unsigned long bm_count_bits(struct drbd_bitmap *b) -{ - return __bm_count_bits(b, 0); -} - -static unsigned long bm_count_bits_swap_endian(struct drbd_bitmap *b) -{ - return __bm_count_bits(b, 1); -} - /* offset and len in long words.*/ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) { @@ -662,7 +705,7 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, offset += do_now; while (do_now--) { bits = hweight_long(*bm); - word = *bm | lel_to_cpu(*buffer++); + word = *bm | *buffer++; *bm++ = word; b->bm_set += hweight_long(word) - bits; } @@ -709,7 +752,7 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, bm = p_addr + MLPP(offset); offset += do_now; while (do_now--) - *buffer++ = cpu_to_lel(*bm++); + *buffer++ = *bm++; bm_unmap(p_addr); } } @@ -795,39 +838,6 @@ static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int } } -# if defined(__LITTLE_ENDIAN) - /* nothing to do, on disk == in memory */ -# define bm_cpu_to_lel(x) ((void)0) -# else -static void bm_cpu_to_lel(struct drbd_bitmap *b) -{ - /* need to cpu_to_lel all the pages ... - * this may be optimized by using - * cpu_to_lel(-1) == -1 and cpu_to_lel(0) == 0; - * the following is still not optimal, but better than nothing */ - unsigned int i; - unsigned long *p_addr, *bm; - if (b->bm_set == 0) { - /* no page at all; avoid swap if all is 0 */ - i = b->bm_number_of_pages; - } else if (b->bm_set == b->bm_bits) { - /* only the last page */ - i = b->bm_number_of_pages - 1; - } else { - /* all pages */ - i = 0; - } - for (; i < b->bm_number_of_pages; i++) { - p_addr = kmap_atomic(b->bm_pages[i], KM_USER0); - for (bm = p_addr; bm < p_addr + PAGE_SIZE/sizeof(long); bm++) - *bm = cpu_to_lel(*bm); - kunmap_atomic(p_addr, KM_USER0); - } -} -# endif -/* lel_to_cpu == cpu_to_lel */ -# define bm_lel_to_cpu(x) bm_cpu_to_lel(x) - /* * bm_rw: read/write the whole bitmap from/to its on disk location. */ @@ -847,10 +857,6 @@ static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) bm_words = drbd_bm_words(mdev); num_pages = (bm_words*sizeof(long) + PAGE_SIZE-1) >> PAGE_SHIFT; - /* on disk bitmap is little endian */ - if (rw == WRITE) - bm_cpu_to_lel(b); - now = jiffies; atomic_set(&b->bm_async_io, num_pages); __clear_bit(BM_MD_IO_ERROR, &b->bm_flags); @@ -869,13 +875,9 @@ static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) now = jiffies; if (rw == WRITE) { - /* swap back endianness */ - bm_lel_to_cpu(b); - /* flush bitmap to stable storage */ drbd_md_flush(mdev); } else /* rw == READ */ { - /* just read, if necessary adjust endianness */ - b->bm_set = bm_count_bits_swap_endian(b); + b->bm_set = bm_count_bits(b); dev_info(DEV, "recounting of set bits took additional %lu jiffies\n", jiffies - now); } @@ -969,9 +971,9 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, p_addr = __bm_map_paddr(b, offset, km); if (find_zero_bit) - i = find_next_zero_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); + i = generic_find_next_zero_le_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); else - i = find_next_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); + i = generic_find_next_le_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); __bm_unmap(p_addr, km); if (i < PAGE_SIZE*8) { @@ -1064,9 +1066,9 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, last_page_nr = page_nr; } if (val) - c += (0 == __test_and_set_bit(bitnr & BPP_MASK, p_addr)); + c += (0 == generic___test_and_set_le_bit(bitnr & BPP_MASK, p_addr)); else - c -= (0 != __test_and_clear_bit(bitnr & BPP_MASK, p_addr)); + c -= (0 != generic___test_and_clear_le_bit(bitnr & BPP_MASK, p_addr)); } if (p_addr) __bm_unmap(p_addr, km); @@ -1211,7 +1213,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) if (bitnr < b->bm_bits) { unsigned long offset = bitnr>>LN2_BPL; p_addr = bm_map_paddr(b, offset); - i = test_bit(bitnr & BPP_MASK, p_addr) ? 1 : 0; + i = generic_test_le_bit(bitnr & BPP_MASK, p_addr) ? 1 : 0; bm_unmap(p_addr); } else if (bitnr == b->bm_bits) { i = -1; @@ -1255,7 +1257,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi ERR_IF (bitnr >= b->bm_bits) { dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); } else { - c += (0 != test_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); + c += (0 != generic_test_le_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); } } if (p_addr) -- cgit v1.2.2 From 19f843aa08e2d8f87a09b4c2edc43b00638423a8 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 15 Dec 2010 08:59:11 +0100 Subject: drbd: bitmap keep track of changes vs on-disk bitmap When we set or clear bits in a bitmap page, also set a flag in the page->private pointer. This allows us to skip writes of unchanged pages. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 132 +++---------- drivers/block/drbd/drbd_bitmap.c | 409 +++++++++++++++++++++++++++++---------- drivers/block/drbd/drbd_int.h | 7 +- drivers/block/drbd/drbd_main.c | 27 ++- drivers/block/drbd/drbd_nl.c | 11 +- drivers/block/drbd/drbd_worker.c | 7 +- 6 files changed, 373 insertions(+), 220 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index e3f0f4d31d75..090fc2ce0df4 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -262,6 +262,33 @@ void drbd_al_complete_io(struct drbd_conf *mdev, sector_t sector) spin_unlock_irqrestore(&mdev->al_lock, flags); } +#if (PAGE_SHIFT + 3) < (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT) +/* Currently BM_BLOCK_SHIFT, BM_EXT_SHIFT and AL_EXTENT_SHIFT + * are still coupled, or assume too much about their relation. + * Code below will not work if this is violated. + * Will be cleaned up with some followup patch. + */ +# error FIXME +#endif + +static unsigned int al_extent_to_bm_page(unsigned int al_enr) +{ + return al_enr >> + /* bit to page */ + ((PAGE_SHIFT + 3) - + /* al extent number to bit */ + (AL_EXTENT_SHIFT - BM_BLOCK_SHIFT)); +} + +static unsigned int rs_extent_to_bm_page(unsigned int rs_enr) +{ + return rs_enr >> + /* bit to page */ + ((PAGE_SHIFT + 3) - + /* al extent number to bit */ + (BM_EXT_SHIFT - BM_BLOCK_SHIFT)); +} + int w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) { @@ -289,7 +316,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused) * For now, we must not write the transaction, * if we cannot write out the bitmap of the evicted extent. */ if (mdev->state.conn < C_CONNECTED && evicted != LC_FREE) - drbd_bm_write_sect(mdev, evicted/AL_EXT_PER_BM_SECT); + drbd_bm_write_page(mdev, al_extent_to_bm_page(evicted)); /* The bitmap write may have failed, causing a state change. */ if (mdev->state.disk < D_INCONSISTENT) { @@ -635,105 +662,6 @@ out_bio_put: return err; } -/** - * drbd_al_to_on_disk_bm() - * Writes bitmap parts covered by active AL extents - * @mdev: DRBD device. - * - * Called when we detach (unconfigure) local storage, - * or when we go from R_PRIMARY to R_SECONDARY role. - */ -void drbd_al_to_on_disk_bm(struct drbd_conf *mdev) -{ - int i, nr_elements; - unsigned int enr; - struct bio **bios; - struct drbd_atodb_wait wc; - - ERR_IF (!get_ldev_if_state(mdev, D_ATTACHING)) - return; /* sorry, I don't have any act_log etc... */ - - wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); - - nr_elements = mdev->act_log->nr_elements; - - /* GFP_KERNEL, we are not in anyone's write-out path */ - bios = kzalloc(sizeof(struct bio *) * nr_elements, GFP_KERNEL); - if (!bios) - goto submit_one_by_one; - - atomic_set(&wc.count, 0); - init_completion(&wc.io_done); - wc.mdev = mdev; - wc.error = 0; - - for (i = 0; i < nr_elements; i++) { - enr = lc_element_by_index(mdev->act_log, i)->lc_number; - if (enr == LC_FREE) - continue; - /* next statement also does atomic_inc wc.count and local_cnt */ - if (atodb_prepare_unless_covered(mdev, bios, - enr/AL_EXT_PER_BM_SECT, - &wc)) - goto free_bios_submit_one_by_one; - } - - /* unnecessary optimization? */ - lc_unlock(mdev->act_log); - wake_up(&mdev->al_wait); - - /* all prepared, submit them */ - for (i = 0; i < nr_elements; i++) { - if (bios[i] == NULL) - break; - if (drbd_insert_fault(mdev, DRBD_FAULT_MD_WR)) { - bios[i]->bi_rw = WRITE; - bio_endio(bios[i], -EIO); - } else { - submit_bio(WRITE, bios[i]); - } - } - - /* always (try to) flush bitmap to stable storage */ - drbd_md_flush(mdev); - - /* In case we did not submit a single IO do not wait for - * them to complete. ( Because we would wait forever here. ) - * - * In case we had IOs and they are already complete, there - * is not point in waiting anyways. - * Therefore this if () ... */ - if (atomic_read(&wc.count)) - wait_for_completion(&wc.io_done); - - put_ldev(mdev); - - kfree(bios); - return; - - free_bios_submit_one_by_one: - /* free everything by calling the endio callback directly. */ - for (i = 0; i < nr_elements && bios[i]; i++) - bio_endio(bios[i], 0); - - kfree(bios); - - submit_one_by_one: - dev_warn(DEV, "Using the slow drbd_al_to_on_disk_bm()\n"); - - for (i = 0; i < mdev->act_log->nr_elements; i++) { - enr = lc_element_by_index(mdev->act_log, i)->lc_number; - if (enr == LC_FREE) - continue; - /* Really slow: if we have al-extents 16..19 active, - * sector 4 will be written four times! Synchronous! */ - drbd_bm_write_sect(mdev, enr/AL_EXT_PER_BM_SECT); - } - - lc_unlock(mdev->act_log); - wake_up(&mdev->al_wait); - put_ldev(mdev); -} - /** * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents * @mdev: DRBD device. @@ -813,7 +741,7 @@ static int w_update_odbm(struct drbd_conf *mdev, struct drbd_work *w, int unused return 1; } - drbd_bm_write_sect(mdev, udw->enr); + drbd_bm_write_page(mdev, rs_extent_to_bm_page(udw->enr)); put_ldev(mdev); kfree(udw); @@ -893,7 +821,6 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, dev_warn(DEV, "Kicking resync_lru element enr=%u " "out with rs_failed=%d\n", ext->lce.lc_number, ext->rs_failed); - set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); } ext->rs_left = rs_left; ext->rs_failed = success ? 0 : count; @@ -912,7 +839,6 @@ static void drbd_try_clear_on_disk_bm(struct drbd_conf *mdev, sector_t sector, drbd_queue_work_front(&mdev->data.work, &udw->w); } else { dev_warn(DEV, "Could not kmalloc an udw\n"); - set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); } } } else { diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 8d959ed6c2cc..72cd41a96ef9 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -70,8 +70,7 @@ struct drbd_bitmap { sector_t bm_dev_capacity; struct mutex bm_change; /* serializes resize operations */ - atomic_t bm_async_io; - wait_queue_head_t bm_io_wait; + wait_queue_head_t bm_io_wait; /* used to serialize IO of single pages */ unsigned long bm_flags; @@ -82,7 +81,7 @@ struct drbd_bitmap { /* definition of bits in bm_flags */ #define BM_LOCKED 0 -#define BM_MD_IO_ERROR 1 +// #define BM_MD_IO_ERROR 1 unused now. #define BM_P_VMALLOCED 2 static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, @@ -155,26 +154,117 @@ void drbd_bm_unlock(struct drbd_conf *mdev) mutex_unlock(&b->bm_change); } -static unsigned int bm_bit_to_page_idx(struct drbd_bitmap *b, u64 bitnr) +/* we store some "meta" info about our pages in page->private */ +/* at a granularity of 4k storage per bitmap bit: + * one peta byte storage: 1<<50 byte, 1<<38 * 4k storage blocks + * 1<<38 bits, + * 1<<23 4k bitmap pages. + * Use 24 bits as page index, covers 2 peta byte storage + * at a granularity of 4k per bit. + * Used to report the failed page idx on io error from the endio handlers. + */ +#define BM_PAGE_IDX_MASK ((1UL<<24)-1) +/* this page is currently read in, or written back */ +#define BM_PAGE_IO_LOCK 31 +/* if there has been an IO error for this page */ +#define BM_PAGE_IO_ERROR 30 +/* this is to be able to intelligently skip disk IO, + * set if bits have been set since last IO. */ +#define BM_PAGE_NEED_WRITEOUT 29 +/* to mark for lazy writeout once syncer cleared all clearable bits, + * we if bits have been cleared since last IO. */ +#define BM_PAGE_LAZY_WRITEOUT 28 + +/* store_page_idx uses non-atomic assingment. It is only used directly after + * allocating the page. All other bm_set_page_* and bm_clear_page_* need to + * use atomic bit manipulation, as set_out_of_sync (and therefore bitmap + * changes) may happen from various contexts, and wait_on_bit/wake_up_bit + * requires it all to be atomic as well. */ +static void bm_store_page_idx(struct page *page, unsigned long idx) { - /* page_nr = (bitnr/8) >> PAGE_SHIFT; */ - unsigned int page_nr = bitnr >> (PAGE_SHIFT + 3); - BUG_ON(page_nr >= b->bm_number_of_pages); - return page_nr; + BUG_ON(0 != (idx & ~BM_PAGE_IDX_MASK)); + page_private(page) |= idx; } -/* word offset to long pointer */ -static unsigned long *__bm_map_paddr(struct drbd_bitmap *b, unsigned long offset, const enum km_type km) +static unsigned long bm_page_to_idx(struct page *page) { - struct page *page; - unsigned long page_nr; + return page_private(page) & BM_PAGE_IDX_MASK; +} + +/* As is very unlikely that the same page is under IO from more than one + * context, we can get away with a bit per page and one wait queue per bitmap. + */ +static void bm_page_lock_io(struct drbd_conf *mdev, int page_nr) +{ + struct drbd_bitmap *b = mdev->bitmap; + void *addr = &page_private(b->bm_pages[page_nr]); + wait_event(b->bm_io_wait, !test_and_set_bit(BM_PAGE_IO_LOCK, addr)); +} + +static void bm_page_unlock_io(struct drbd_conf *mdev, int page_nr) +{ + struct drbd_bitmap *b = mdev->bitmap; + void *addr = &page_private(b->bm_pages[page_nr]); + clear_bit(BM_PAGE_IO_LOCK, addr); + smp_mb__after_clear_bit(); + wake_up(&mdev->bitmap->bm_io_wait); +} + +/* set _before_ submit_io, so it may be reset due to being changed + * while this page is in flight... will get submitted later again */ +static void bm_set_page_unchanged(struct page *page) +{ + /* use cmpxchg? */ + clear_bit(BM_PAGE_NEED_WRITEOUT, &page_private(page)); + clear_bit(BM_PAGE_LAZY_WRITEOUT, &page_private(page)); +} + +static void bm_set_page_need_writeout(struct page *page) +{ + set_bit(BM_PAGE_NEED_WRITEOUT, &page_private(page)); +} + +static int bm_test_page_unchanged(struct page *page) +{ + volatile const unsigned long *addr = &page_private(page); + return (*addr & ((1UL<> PAGE_SHIFT; */ - page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3); + unsigned int page_nr = long_nr >> (PAGE_SHIFT - LN2_BPL + 3); BUG_ON(page_nr >= b->bm_number_of_pages); - page = b->bm_pages[page_nr]; + return page_nr; +} - return (unsigned long *) kmap_atomic(page, km); +static unsigned int bm_bit_to_page_idx(struct drbd_bitmap *b, u64 bitnr) +{ + /* page_nr = (bitnr/8) >> PAGE_SHIFT; */ + unsigned int page_nr = bitnr >> (PAGE_SHIFT + 3); + BUG_ON(page_nr >= b->bm_number_of_pages); + return page_nr; } static unsigned long *__bm_map_pidx(struct drbd_bitmap *b, unsigned int idx, const enum km_type km) @@ -188,11 +278,6 @@ static unsigned long *bm_map_pidx(struct drbd_bitmap *b, unsigned int idx) return __bm_map_pidx(b, idx, KM_IRQ1); } -static unsigned long * bm_map_paddr(struct drbd_bitmap *b, unsigned long offset) -{ - return __bm_map_paddr(b, offset, KM_IRQ1); -} - static void __bm_unmap(unsigned long *p_addr, const enum km_type km) { kunmap_atomic(p_addr, km); @@ -222,6 +307,7 @@ static void bm_unmap(unsigned long *p_addr) * to be able to report device specific. */ + static void bm_free_pages(struct page **pages, unsigned long number) { unsigned long i; @@ -289,6 +375,9 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) bm_vk_free(new_pages, vmalloced); return NULL; } + /* we want to know which page it is + * from the endio handlers */ + bm_store_page_idx(page, i); new_pages[i] = page; } } else { @@ -443,7 +532,7 @@ static unsigned long bm_count_bits(struct drbd_bitmap *b) while (offset < words) { i = do_now = min_t(size_t, words-offset, LWPP); - p_addr = __bm_map_paddr(b, offset, KM_USER0); + p_addr = __bm_map_pidx(b, bm_word_to_page_idx(b, offset), KM_USER0); bm = p_addr + MLPP(offset); while (i--) { bits += hweight_long(*bm++); @@ -472,6 +561,7 @@ static unsigned long bm_count_bits(struct drbd_bitmap *b) static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) { unsigned long *p_addr, *bm; + unsigned int idx; size_t do_now, end; #define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512) @@ -485,7 +575,8 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) while (offset < end) { do_now = min_t(size_t, ALIGN(offset + 1, LWPP), end) - offset; - p_addr = bm_map_paddr(b, offset); + idx = bm_word_to_page_idx(b, offset); + p_addr = bm_map_pidx(b, idx); bm = p_addr + MLPP(offset); if (bm+do_now > p_addr + LWPP) { printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n", @@ -494,6 +585,7 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) } memset(bm, c, do_now * sizeof(long)); bm_unmap(p_addr); + bm_set_page_need_writeout(b->bm_pages[idx]); offset += do_now; } } @@ -604,7 +696,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) bm_free_pages(opages + want, have - want); } - p_addr = bm_map_paddr(b, words); + p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, words)); bm = p_addr + MLPP(words); *bm = DRBD_MAGIC; bm_unmap(p_addr); @@ -616,7 +708,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) bm_vk_free(opages, opages_vmalloced); if (!growing) b->bm_set = bm_count_bits(b); - dev_info(DEV, "resync bitmap: bits=%lu words=%lu\n", bits, words); + dev_info(DEV, "resync bitmap: bits=%lu words=%lu pages=%lu\n", bits, words, want); out: drbd_bm_unlock(mdev); @@ -686,6 +778,7 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, struct drbd_bitmap *b = mdev->bitmap; unsigned long *p_addr, *bm; unsigned long word, bits; + unsigned int idx; size_t end, do_now; end = offset + number; @@ -700,7 +793,8 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, spin_lock_irq(&b->bm_lock); while (offset < end) { do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset; - p_addr = bm_map_paddr(b, offset); + idx = bm_word_to_page_idx(b, offset); + p_addr = bm_map_pidx(b, idx); bm = p_addr + MLPP(offset); offset += do_now; while (do_now--) { @@ -710,6 +804,7 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, b->bm_set += hweight_long(word) - bits; } bm_unmap(p_addr); + bm_set_page_need_writeout(b->bm_pages[idx]); } /* with 32bit <-> 64bit cross-platform connect * this is only correct for current usage, @@ -748,7 +843,7 @@ void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, else { while (offset < end) { do_now = min_t(size_t, ALIGN(offset+1, LWPP), end) - offset; - p_addr = bm_map_paddr(b, offset); + p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, offset)); bm = p_addr + MLPP(offset); offset += do_now; while (do_now--) @@ -786,9 +881,22 @@ void drbd_bm_clear_all(struct drbd_conf *mdev) spin_unlock_irq(&b->bm_lock); } +struct bm_aio_ctx { + struct drbd_conf *mdev; + atomic_t in_flight; + wait_queue_head_t io_wait; + unsigned flags; +#define BM_AIO_COPY_PAGES 1 + int error; +}; + +/* bv_page may be a copy, or may be the original */ static void bm_async_io_complete(struct bio *bio, int error) { - struct drbd_bitmap *b = bio->bi_private; + struct bm_aio_ctx *ctx = bio->bi_private; + struct drbd_conf *mdev = ctx->mdev; + struct drbd_bitmap *b = mdev->bitmap; + unsigned int idx = bm_page_to_idx(bio->bi_io_vec[0].bv_page); int uptodate = bio_flagged(bio, BIO_UPTODATE); @@ -799,35 +907,79 @@ static void bm_async_io_complete(struct bio *bio, int error) if (!error && !uptodate) error = -EIO; + if (!bm_test_page_unchanged(b->bm_pages[idx])) + dev_info(DEV, "bitmap page idx %u changed during IO!\n", idx); + if (error) { - /* doh. what now? - * for now, set all bits, and flag MD_IO_ERROR */ - __set_bit(BM_MD_IO_ERROR, &b->bm_flags); + /* ctx error will hold the completed-last non-zero error code, + * in case error codes differ. */ + ctx->error = error; + bm_set_page_io_err(b->bm_pages[idx]); + /* Not identical to on disk version of it. + * Is BM_PAGE_IO_ERROR enough? */ + if (__ratelimit(&drbd_ratelimit_state)) + dev_err(DEV, "IO ERROR %d on bitmap page idx %u\n", + error, idx); + } else { + bm_clear_page_io_err(b->bm_pages[idx]); + dynamic_dev_dbg(DEV, "bitmap page idx %u completed\n", idx); } - if (atomic_dec_and_test(&b->bm_async_io)) - wake_up(&b->bm_io_wait); + + bm_page_unlock_io(mdev, idx); + + /* FIXME give back to page pool */ + if (ctx->flags & BM_AIO_COPY_PAGES) + put_page(bio->bi_io_vec[0].bv_page); bio_put(bio); + + if (atomic_dec_and_test(&ctx->in_flight)) + wake_up(&ctx->io_wait); } -static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int page_nr, int rw) __must_hold(local) +static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local) { /* we are process context. we always get a bio */ struct bio *bio = bio_alloc(GFP_KERNEL, 1); + struct drbd_conf *mdev = ctx->mdev; + struct drbd_bitmap *b = mdev->bitmap; + struct page *page; unsigned int len; + sector_t on_disk_sector = mdev->ldev->md.md_offset + mdev->ldev->md.bm_offset; on_disk_sector += ((sector_t)page_nr) << (PAGE_SHIFT-9); /* this might happen with very small - * flexible external meta data device */ + * flexible external meta data device, + * or with PAGE_SIZE > 4k */ len = min_t(unsigned int, PAGE_SIZE, (drbd_md_last_sector(mdev->ldev) - on_disk_sector + 1)<<9); + /* serialize IO on this page */ + bm_page_lock_io(mdev, page_nr); + /* before memcpy and submit, + * so it can be redirtied any time */ + bm_set_page_unchanged(b->bm_pages[page_nr]); + + if (ctx->flags & BM_AIO_COPY_PAGES) { + /* FIXME alloc_page is good enough for now, but actually needs + * to use pre-allocated page pool */ + void *src, *dest; + page = alloc_page(__GFP_HIGHMEM|__GFP_WAIT); + dest = kmap_atomic(page, KM_USER0); + src = kmap_atomic(b->bm_pages[page_nr], KM_USER1); + memcpy(dest, src, PAGE_SIZE); + kunmap_atomic(src, KM_USER1); + kunmap_atomic(dest, KM_USER0); + bm_store_page_idx(page, page_nr); + } else + page = b->bm_pages[page_nr]; + bio->bi_bdev = mdev->ldev->md_bdev; bio->bi_sector = on_disk_sector; - bio_add_page(bio, b->bm_pages[page_nr], len, 0); - bio->bi_private = b; + bio_add_page(bio, page, len, 0); + bio->bi_private = ctx; bio->bi_end_io = bm_async_io_complete; if (drbd_insert_fault(mdev, (rw & WRITE) ? DRBD_FAULT_MD_WR : DRBD_FAULT_MD_RD)) { @@ -841,36 +993,72 @@ static void bm_page_io_async(struct drbd_conf *mdev, struct drbd_bitmap *b, int /* * bm_rw: read/write the whole bitmap from/to its on disk location. */ -static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) +static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_idx) __must_hold(local) { + struct bm_aio_ctx ctx = + { .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0 }; struct drbd_bitmap *b = mdev->bitmap; - /* sector_t sector; */ - int bm_words, num_pages, i; + int last_page, i, count = 0; unsigned long now; char ppb[10]; int err = 0; - WARN_ON(!bm_is_locked(b)); - - /* no spinlock here, the drbd_bm_lock should be enough! */ + /* + * We are protected against bitmap disappearing/resizing by holding an + * ldev reference (caller must have called get_ldev()). + * For read/write, we are protected against changes to the bitmap by + * the bitmap lock (see drbd_bitmap_io). + * For lazy writeout, we don't care for ongoing changes to the bitmap, + * as we submit copies of pages anyways. + */ + if (!ctx.flags) + WARN_ON(!bm_is_locked(b)); - bm_words = drbd_bm_words(mdev); - num_pages = (bm_words*sizeof(long) + PAGE_SIZE-1) >> PAGE_SHIFT; + /* because of the "extra long to catch oob access" we allocate in + * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page + * containing the last _relevant_ bitmap word */ + last_page = bm_word_to_page_idx(b, b->bm_words - 1); now = jiffies; - atomic_set(&b->bm_async_io, num_pages); - __clear_bit(BM_MD_IO_ERROR, &b->bm_flags); + ctx.mdev = mdev; + atomic_set(&ctx.in_flight, 1); /* one extra ref */ + init_waitqueue_head(&ctx.io_wait); + ctx.error = 0; /* let the layers below us try to merge these bios... */ - for (i = 0; i < num_pages; i++) - bm_page_io_async(mdev, b, i, rw); + for (i = 0; i <= last_page; i++) { + /* ignore completely unchanged pages */ + if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx) + break; + if (rw & WRITE) { + if (bm_test_page_unchanged(b->bm_pages[i])) { + dynamic_dev_dbg(DEV, "skipped bm write for idx %u\n", i); + continue; + } + /* during lazy writeout, + * ignore those pages not marked for lazy writeout. */ + if (lazy_writeout_upper_idx && + !bm_test_page_lazy_writeout(b->bm_pages[i])) { + dynamic_dev_dbg(DEV, "skipped bm lazy write for idx %u\n", i); + continue; + } + } + atomic_inc(&ctx.in_flight); + bm_page_io_async(&ctx, i, rw); + ++count; + cond_resched(); + } - wait_event(b->bm_io_wait, atomic_read(&b->bm_async_io) == 0); + atomic_dec(&ctx.in_flight); /* drop the extra ref */ + wait_event(ctx.io_wait, atomic_read(&ctx.in_flight) == 0); + dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", + rw == WRITE ? "WRITE" : "READ", + count, jiffies - now); - if (test_bit(BM_MD_IO_ERROR, &b->bm_flags)) { + if (ctx.error) { dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); drbd_chk_io_error(mdev, 1, true); - err = -EIO; + err = -EIO; /* ctx.error ? */ } now = jiffies; @@ -895,55 +1083,63 @@ static int bm_rw(struct drbd_conf *mdev, int rw) __must_hold(local) */ int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local) { - return bm_rw(mdev, READ); + return bm_rw(mdev, READ, 0); } /** * drbd_bm_write() - Write the whole bitmap to its on disk location. * @mdev: DRBD device. + * + * Will only write pages that have changed since last IO. */ int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local) { - return bm_rw(mdev, WRITE); + return bm_rw(mdev, WRITE, 0); } /** - * drbd_bm_write_sect: Writes a 512 (MD_SECTOR_SIZE) byte piece of the bitmap + * drbd_bm_lazy_write_out() - Write bitmap pages 0 to @upper_idx-1, if they have changed. * @mdev: DRBD device. - * @enr: Extent number in the resync lru (happens to be sector offset) + * @upper_idx: 0: write all changed pages; +ve: page index to stop scanning for changed pages + */ +int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(local) +{ + return bm_rw(mdev, WRITE, upper_idx); +} + + +/** + * drbd_bm_write_page: Writes a PAGE_SIZE aligned piece of bitmap + * @mdev: DRBD device. + * @idx: bitmap page index * - * The BM_EXT_SIZE is on purpose exactly the amount of the bitmap covered - * by a single sector write. Therefore enr == sector offset from the - * start of the bitmap. + * We don't want to special case on logical_block_size of the underlaying + * device, so we submit PAGE_SIZE aligned pieces containing the requested enr. + * Note that on "most" systems, PAGE_SIZE is 4k. */ -int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local) +int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) { - sector_t on_disk_sector = enr + mdev->ldev->md.md_offset - + mdev->ldev->md.bm_offset; - int bm_words, num_words, offset; - int err = 0; + struct bm_aio_ctx ctx = { .flags = BM_AIO_COPY_PAGES, }; - mutex_lock(&mdev->md_io_mutex); - bm_words = drbd_bm_words(mdev); - offset = S2W(enr); /* word offset into bitmap */ - num_words = min(S2W(1), bm_words - offset); - if (num_words < S2W(1)) - memset(page_address(mdev->md_io_page), 0, MD_SECTOR_SIZE); - drbd_bm_get_lel(mdev, offset, num_words, - page_address(mdev->md_io_page)); - if (!drbd_md_sync_page_io(mdev, mdev->ldev, on_disk_sector, WRITE)) { - int i; - err = -EIO; - dev_err(DEV, "IO ERROR writing bitmap sector %lu " - "(meta-disk sector %llus)\n", - enr, (unsigned long long)on_disk_sector); - drbd_chk_io_error(mdev, 1, true); - for (i = 0; i < AL_EXT_PER_BM_SECT; i++) - drbd_bm_ALe_set_all(mdev, enr*AL_EXT_PER_BM_SECT+i); + if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { + dev_info(DEV, "skipped bm page write for idx %u\n", idx); + return 0; } + + ctx.mdev = mdev; + atomic_set(&ctx.in_flight, 1); + init_waitqueue_head(&ctx.io_wait); + + bm_page_io_async(&ctx, idx, WRITE_SYNC); + wait_event(ctx.io_wait, atomic_read(&ctx.in_flight) == 0); + + if (ctx.error) + drbd_chk_io_error(mdev, 1, true); + /* that should force detach, so the in memory bitmap will be + * gone in a moment as well. */ + mdev->bm_writ_cnt++; - mutex_unlock(&mdev->md_io_mutex); - return err; + return ctx.error; } /* NOTE @@ -965,10 +1161,9 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits); } else { while (bm_fo < b->bm_bits) { - unsigned long offset; - bit_offset = bm_fo & ~BPP_MASK; /* bit offset of the page */ - offset = bit_offset >> LN2_BPL; /* word offset of the page */ - p_addr = __bm_map_paddr(b, offset, km); + /* bit offset of the first bit in the page */ + bit_offset = bm_fo & ~BPP_MASK; + p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo), km); if (find_zero_bit) i = generic_find_next_zero_le_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); @@ -1048,8 +1243,9 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, struct drbd_bitmap *b = mdev->bitmap; unsigned long *p_addr = NULL; unsigned long bitnr; - unsigned long last_page_nr = -1UL; + unsigned int last_page_nr = -1U; int c = 0; + int changed_total = 0; if (e >= b->bm_bits) { dev_err(DEV, "ASSERT FAILED: bit_s=%lu bit_e=%lu bm_bits=%lu\n", @@ -1057,12 +1253,17 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, e = b->bm_bits ? b->bm_bits -1 : 0; } for (bitnr = s; bitnr <= e; bitnr++) { - unsigned long offset = bitnr>>LN2_BPL; - unsigned long page_nr = offset >> (PAGE_SHIFT - LN2_BPL + 3); + unsigned int page_nr = bm_bit_to_page_idx(b, bitnr); if (page_nr != last_page_nr) { if (p_addr) __bm_unmap(p_addr, km); - p_addr = __bm_map_paddr(b, offset, km); + if (c < 0) + bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); + else if (c > 0) + bm_set_page_need_writeout(b->bm_pages[last_page_nr]); + changed_total += c; + c = 0; + p_addr = __bm_map_pidx(b, page_nr, km); last_page_nr = page_nr; } if (val) @@ -1072,8 +1273,13 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, } if (p_addr) __bm_unmap(p_addr, km); - b->bm_set += c; - return c; + if (c < 0) + bm_set_page_lazy_writeout(b->bm_pages[last_page_nr]); + else if (c > 0) + bm_set_page_need_writeout(b->bm_pages[last_page_nr]); + changed_total += c; + b->bm_set += changed_total; + return changed_total; } /* returns number of bits actually changed. @@ -1211,8 +1417,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) if (bm_is_locked(b)) bm_print_lock_info(mdev); if (bitnr < b->bm_bits) { - unsigned long offset = bitnr>>LN2_BPL; - p_addr = bm_map_paddr(b, offset); + p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr)); i = generic_test_le_bit(bitnr & BPP_MASK, p_addr) ? 1 : 0; bm_unmap(p_addr); } else if (bitnr == b->bm_bits) { @@ -1231,10 +1436,10 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi { unsigned long flags; struct drbd_bitmap *b = mdev->bitmap; - unsigned long *p_addr = NULL, page_nr = -1; + unsigned long *p_addr = NULL; unsigned long bitnr; + unsigned int page_nr = -1U; int c = 0; - size_t w; /* If this is called without a bitmap, that is a bug. But just to be * robust in case we screwed up elsewhere, in that case pretend there @@ -1247,12 +1452,12 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi if (bm_is_locked(b)) bm_print_lock_info(mdev); for (bitnr = s; bitnr <= e; bitnr++) { - w = bitnr >> LN2_BPL; - if (page_nr != w >> (PAGE_SHIFT - LN2_BPL + 3)) { - page_nr = w >> (PAGE_SHIFT - LN2_BPL + 3); + unsigned int idx = bm_bit_to_page_idx(b, bitnr); + if (page_nr != idx) { + page_nr = idx; if (p_addr) bm_unmap(p_addr); - p_addr = bm_map_paddr(b, w); + p_addr = bm_map_pidx(b, idx); } ERR_IF (bitnr >= b->bm_bits) { dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); @@ -1300,7 +1505,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) count = 0; if (s < b->bm_words) { int n = e-s; - p_addr = bm_map_paddr(b, s); + p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, s)); bm = p_addr + MLPP(s); while (n--) count += hweight_long(*bm++); @@ -1335,7 +1540,7 @@ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) count = 0; if (s < b->bm_words) { i = do_now = e-s; - p_addr = bm_map_paddr(b, s); + p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, s)); bm = p_addr + MLPP(s); while (i--) { count += hweight_long(*bm); diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index f6da48bb8c70..74cc50a21822 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -833,7 +833,7 @@ enum { CRASHED_PRIMARY, /* This node was a crashed primary. * Gets cleared when the state.conn * goes into C_CONNECTED state. */ - WRITE_BM_AFTER_RESYNC, /* A kmalloc() during resync failed */ + NO_BARRIER_SUPP, /* underlying block device doesn't implement barriers */ CONSIDER_RESYNC, MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */ @@ -1428,7 +1428,7 @@ extern void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e); extern int drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr); extern int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr); -extern int drbd_bm_write_sect(struct drbd_conf *mdev, unsigned long enr) __must_hold(local); +extern int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local); extern int drbd_bm_read(struct drbd_conf *mdev) __must_hold(local); extern int drbd_bm_write(struct drbd_conf *mdev) __must_hold(local); extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, @@ -1446,7 +1446,7 @@ extern int drbd_bm_rs_done(struct drbd_conf *mdev); /* for receive_bitmap */ extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, unsigned long *buffer); -/* for _drbd_send_bitmap and drbd_bm_write_sect */ +/* for _drbd_send_bitmap */ extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, unsigned long *buffer); @@ -1641,7 +1641,6 @@ extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, #define drbd_set_out_of_sync(mdev, sector, size) \ __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__) extern void drbd_al_apply_to_bm(struct drbd_conf *mdev); -extern void drbd_al_to_on_disk_bm(struct drbd_conf *mdev); extern void drbd_al_shrink(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 67fffad213ec..57ed7181742d 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1289,6 +1289,26 @@ static void abw_start_sync(struct drbd_conf *mdev, int rv) } } +int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why) +{ + int rv; + + D_ASSERT(current == mdev->worker.task); + + /* open coded non-blocking drbd_suspend_io(mdev); */ + set_bit(SUSPEND_IO, &mdev->flags); + if (!is_susp(mdev->state)) + D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0); + + drbd_bm_lock(mdev, why); + rv = io_fn(mdev); + drbd_bm_unlock(mdev); + + drbd_resume_io(mdev); + + return rv; +} + /** * after_state_ch() - Perform after state change actions that may sleep * @mdev: DRBD device. @@ -1404,7 +1424,12 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* D_DISKLESS Peer becomes secondary */ if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) - drbd_al_to_on_disk_bm(mdev); + drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, "demote diskless peer"); + put_ldev(mdev); + } + + if (os.role == R_PRIMARY && ns.role == R_SECONDARY && get_ldev(mdev)) { + drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, "demote"); put_ldev(mdev); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 2f0724982143..77dc022eaf6b 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -407,10 +407,8 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) } } - if ((new_role == R_SECONDARY) && get_ldev(mdev)) { - drbd_al_to_on_disk_bm(mdev); - put_ldev(mdev); - } + /* writeout of activity log covered areas of the bitmap + * to stable storage done in after state change already */ if (mdev->state.conn >= C_WF_REPORT_PARAMS) { /* if this was forced, we should consider sync */ @@ -1174,7 +1172,10 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (cp_discovered) { drbd_al_apply_to_bm(mdev); - drbd_al_to_on_disk_bm(mdev); + if (drbd_bitmap_io(mdev, &drbd_bm_write, "crashed primary apply AL")) { + retcode = ERR_IO_MD_DISK; + goto force_diskless_dec; + } } if (_drbd_bm_total_weight(mdev) == drbd_bm_bits(mdev)) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 9fe3e890da0f..d17f2ed777ce 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -907,10 +907,8 @@ out: drbd_md_sync(mdev); - if (test_and_clear_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags)) { - dev_info(DEV, "Writing the whole bitmap\n"); - drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); - } + dev_info(DEV, "Writing changed bitmap pages\n"); + drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); if (khelper_cmd) drbd_khelper(mdev, khelper_cmd); @@ -1127,7 +1125,6 @@ void drbd_ov_oos_found(struct drbd_conf *mdev, sector_t sector, int size) mdev->ov_last_oos_size = size>>9; } drbd_set_out_of_sync(mdev, sector, size); - set_bit(WRITE_BM_AFTER_RESYNC, &mdev->flags); } int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) -- cgit v1.2.2 From 4b0715f09655e76ca24c35a9e25e7c464c2f7346 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 14 Dec 2010 15:13:04 +0100 Subject: drbd: allow petabyte storage on 64bit arch Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 170 ++++++++++++++++++++++++--------------- drivers/block/drbd/drbd_int.h | 41 ++++++---- drivers/block/drbd/drbd_nl.c | 8 +- drivers/block/drbd/drbd_proc.c | 6 +- drivers/block/drbd/drbd_worker.c | 2 +- 5 files changed, 142 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 72cd41a96ef9..0e31e573af72 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -37,10 +37,46 @@ * convention: * function name drbd_bm_... => used elsewhere, "public". * function name bm_... => internal to implementation, "private". + */ + - * Note that since find_first_bit returns int, at the current granularity of - * the bitmap (4KB per byte), this implementation "only" supports up to - * 1<<(32+12) == 16 TB... +/* + * LIMITATIONS: + * We want to support >= peta byte of backend storage, while for now still using + * a granularity of one bit per 4KiB of storage. + * 1 << 50 bytes backend storage (1 PiB) + * 1 << (50 - 12) bits needed + * 38 --> we need u64 to index and count bits + * 1 << (38 - 3) bitmap bytes needed + * 35 --> we still need u64 to index and count bytes + * (that's 32 GiB of bitmap for 1 PiB storage) + * 1 << (35 - 2) 32bit longs needed + * 33 --> we'd even need u64 to index and count 32bit long words. + * 1 << (35 - 3) 64bit longs needed + * 32 --> we could get away with a 32bit unsigned int to index and count + * 64bit long words, but I rather stay with unsigned long for now. + * We probably should neither count nor point to bytes or long words + * directly, but either by bitnumber, or by page index and offset. + * 1 << (35 - 12) + * 22 --> we need that much 4KiB pages of bitmap. + * 1 << (22 + 3) --> on a 64bit arch, + * we need 32 MiB to store the array of page pointers. + * + * Because I'm lazy, and because the resulting patch was too large, too ugly + * and still incomplete, on 32bit we still "only" support 16 TiB (minus some), + * (1 << 32) bits * 4k storage. + * + + * bitmap storage and IO: + * Bitmap is stored little endian on disk, and is kept little endian in + * core memory. Currently we still hold the full bitmap in core as long + * as we are "attached" to a local disk, which at 32 GiB for 1PiB storage + * seems excessive. + * + * We plan to reduce the amount of in-core bitmap pages by pageing them in + * and out against their on-disk location as necessary, but need to make + * sure we don't cause too much meta data IO, and must not deadlock in + * tight memory situations. This needs some more work. */ /* @@ -56,13 +92,9 @@ struct drbd_bitmap { struct page **bm_pages; spinlock_t bm_lock; - /* WARNING unsigned long bm_*: - * 32bit number of bit offset is just enough for 512 MB bitmap. - * it will blow up if we make the bitmap bigger... - * not that it makes much sense to have a bitmap that large, - * rather change the granularity to 16k or 64k or something. - * (that implies other problems, however...) - */ + + /* see LIMITATIONS: above */ + unsigned long bm_set; /* nr of set bits; THINK maybe atomic_t? */ unsigned long bm_bits; size_t bm_words; @@ -517,43 +549,39 @@ static void bm_set_surplus(struct drbd_bitmap *b) bm_unmap(p_addr); } +/* you better not modify the bitmap while this is running, + * or its results will be stale */ static unsigned long bm_count_bits(struct drbd_bitmap *b) { - unsigned long *p_addr, *bm, offset = 0; + unsigned long *p_addr; unsigned long bits = 0; - unsigned long i, do_now; - unsigned long words; - - /* due to 64bit alignment, the last long on a 32bit arch - * may be not used at all. The last used long will likely - * be only partially used, always. Don't count those bits, - * but mask them out. */ - words = (b->bm_bits + BITS_PER_LONG - 1) >> LN2_BPL; - - while (offset < words) { - i = do_now = min_t(size_t, words-offset, LWPP); - p_addr = __bm_map_pidx(b, bm_word_to_page_idx(b, offset), KM_USER0); - bm = p_addr + MLPP(offset); - while (i--) { - bits += hweight_long(*bm++); - } - offset += do_now; - if (offset == words) { - /* last word may only be partially used, - * see also bm_clear_surplus. */ - i = (1UL << (b->bm_bits & (BITS_PER_LONG-1))) -1; - if (i) { - bits -= hweight_long(p_addr[do_now-1] & ~i); - p_addr[do_now-1] &= i; - } - /* 32bit arch, may have an unused padding long */ - if (words != b->bm_words) - p_addr[do_now] = 0; - } + unsigned long mask = (1UL << (b->bm_bits & BITS_PER_LONG_MASK)) -1; + int idx, last_page, i, last_word; + + /* because of the "extra long to catch oob access" we allocate in + * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page + * containing the last _relevant_ bitmap word */ + last_page = bm_bit_to_page_idx(b, b->bm_bits-1); + + /* all but last page */ + for (idx = 0; idx < last_page; idx++) { + p_addr = __bm_map_pidx(b, idx, KM_USER0); + for (i = 0; i < LWPP; i++) + bits += hweight_long(p_addr[i]); __bm_unmap(p_addr, KM_USER0); cond_resched(); } - + /* last (or only) page */ + last_word = ((b->bm_bits - 1) & BITS_PER_PAGE_MASK) >> LN2_BPL; + p_addr = __bm_map_pidx(b, idx, KM_USER0); + for (i = 0; i < last_word; i++) + bits += hweight_long(p_addr[i]); + p_addr[last_word] &= cpu_to_lel(mask); + bits += hweight_long(p_addr[last_word]); + /* 32bit arch, may have an unused padding long */ + if (BITS_PER_LONG == 32 && (last_word & 1) == 0) + p_addr[last_word+1] = 0; + __bm_unmap(p_addr, KM_USER0); return bits; } @@ -564,8 +592,6 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) unsigned int idx; size_t do_now, end; -#define BM_SECTORS_PER_BIT (BM_BLOCK_SIZE/512) - end = offset + len; if (end > b->bm_words) { @@ -645,8 +671,14 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) words = ALIGN(bits, 64) >> LN2_BPL; if (get_ldev(mdev)) { - D_ASSERT((u64)bits <= (((u64)mdev->ldev->md.md_size_sect-MD_BM_OFFSET) << 12)); + u64 bits_on_disk = ((u64)mdev->ldev->md.md_size_sect-MD_BM_OFFSET) << 12; put_ldev(mdev); + if (bits > bits_on_disk) { + dev_info(DEV, "bits = %lu\n", bits); + dev_info(DEV, "bits_on_disk = %llu\n", bits_on_disk); + err = -ENOSPC; + goto out; + } } /* one extra long to catch off by one errors */ @@ -1113,9 +1145,12 @@ int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(l * @mdev: DRBD device. * @idx: bitmap page index * - * We don't want to special case on logical_block_size of the underlaying - * device, so we submit PAGE_SIZE aligned pieces containing the requested enr. + * We don't want to special case on logical_block_size of the backend device, + * so we submit PAGE_SIZE aligned pieces. * Note that on "most" systems, PAGE_SIZE is 4k. + * + * In case this becomes an issue on systems with larger PAGE_SIZE, + * we may want to change this again to write 4k aligned 4k pieces. */ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) { @@ -1144,52 +1179,57 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc /* NOTE * find_first_bit returns int, we return unsigned long. - * should not make much difference anyways, but ... + * For this to work on 32bit arch with bitnumbers > (1<<32), + * we'd need to return u64, and get a whole lot of other places + * fixed where we still use unsigned long. * * this returns a bit number, NOT a sector! */ -#define BPP_MASK ((1UL << (PAGE_SHIFT+3)) - 1) static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, const int find_zero_bit, const enum km_type km) { struct drbd_bitmap *b = mdev->bitmap; - unsigned long i = -1UL; unsigned long *p_addr; - unsigned long bit_offset; /* bit offset of the mapped page. */ + unsigned long bit_offset; + unsigned i; + if (bm_fo > b->bm_bits) { dev_err(DEV, "bm_fo=%lu bm_bits=%lu\n", bm_fo, b->bm_bits); + bm_fo = DRBD_END_OF_BITMAP; } else { while (bm_fo < b->bm_bits) { /* bit offset of the first bit in the page */ - bit_offset = bm_fo & ~BPP_MASK; + bit_offset = bm_fo & ~BITS_PER_PAGE_MASK; p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo), km); if (find_zero_bit) - i = generic_find_next_zero_le_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); + i = generic_find_next_zero_le_bit(p_addr, + PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); else - i = generic_find_next_le_bit(p_addr, PAGE_SIZE*8, bm_fo & BPP_MASK); + i = generic_find_next_le_bit(p_addr, + PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); __bm_unmap(p_addr, km); if (i < PAGE_SIZE*8) { - i = bit_offset + i; - if (i >= b->bm_bits) + bm_fo = bit_offset + i; + if (bm_fo >= b->bm_bits) break; goto found; } bm_fo = bit_offset + PAGE_SIZE*8; } - i = -1UL; + bm_fo = DRBD_END_OF_BITMAP; } found: - return i; + return bm_fo; } static unsigned long bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, const int find_zero_bit) { struct drbd_bitmap *b = mdev->bitmap; - unsigned long i = -1UL; + unsigned long i = DRBD_END_OF_BITMAP; ERR_IF(!b) return i; ERR_IF(!b->bm_pages) return i; @@ -1267,9 +1307,9 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, last_page_nr = page_nr; } if (val) - c += (0 == generic___test_and_set_le_bit(bitnr & BPP_MASK, p_addr)); + c += (0 == generic___test_and_set_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); else - c -= (0 != generic___test_and_clear_le_bit(bitnr & BPP_MASK, p_addr)); + c -= (0 != generic___test_and_clear_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); } if (p_addr) __bm_unmap(p_addr, km); @@ -1418,7 +1458,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) bm_print_lock_info(mdev); if (bitnr < b->bm_bits) { p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr)); - i = generic_test_le_bit(bitnr & BPP_MASK, p_addr) ? 1 : 0; + i = generic_test_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0; bm_unmap(p_addr); } else if (bitnr == b->bm_bits) { i = -1; @@ -1517,13 +1557,15 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) return count; } -/* set all bits covered by the AL-extent al_enr */ +/* Set all bits covered by the AL-extent al_enr. + * Returns number of bits changed. */ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) { struct drbd_bitmap *b = mdev->bitmap; unsigned long *p_addr, *bm; unsigned long weight; - int count, s, e, i, do_now; + unsigned long s, e; + int count, i, do_now; ERR_IF(!b) return 0; ERR_IF(!b->bm_pages) return 0; @@ -1552,7 +1594,7 @@ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) if (e == b->bm_words) b->bm_set -= bm_clear_surplus(b); } else { - dev_err(DEV, "start offset (%d) too large in drbd_bm_ALe_set_all\n", s); + dev_err(DEV, "start offset (%lu) too large in drbd_bm_ALe_set_all\n", s); } weight = b->bm_set - weight; spin_unlock_irq(&b->bm_lock); diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 74cc50a21822..5a2d0ec72b34 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1003,9 +1003,9 @@ struct drbd_conf { struct hlist_head *tl_hash; unsigned int tl_hash_s; - /* blocks to sync in this run [unit BM_BLOCK_SIZE] */ + /* blocks to resync in this run [unit BM_BLOCK_SIZE] */ unsigned long rs_total; - /* number of sync IOs that failed in this run */ + /* number of resync blocks that failed in this run */ unsigned long rs_failed; /* Syncer's start time [unit jiffies] */ unsigned long rs_start; @@ -1399,7 +1399,9 @@ struct bm_extent { * you should use 64bit OS for that much storage, anyways. */ #define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0xffff7fff) #else -#define DRBD_MAX_SECTORS_FLEX BM_BIT_TO_SECT(0x1LU << 32) +/* we allow up to 1 PiB now on 64bit architecture with "flexible" meta data */ +#define DRBD_MAX_SECTORS_FLEX (1UL << 51) +/* corresponds to (1UL << 38) bits right now. */ #endif #endif @@ -1419,11 +1421,15 @@ extern int drbd_bm_resize(struct drbd_conf *mdev, sector_t sectors, int set_new extern void drbd_bm_cleanup(struct drbd_conf *mdev); extern void drbd_bm_set_all(struct drbd_conf *mdev); extern void drbd_bm_clear_all(struct drbd_conf *mdev); +/* set/clear/test only a few bits at a time */ extern int drbd_bm_set_bits( struct drbd_conf *mdev, unsigned long s, unsigned long e); extern int drbd_bm_clear_bits( struct drbd_conf *mdev, unsigned long s, unsigned long e); -/* bm_set_bits variant for use while holding drbd_bm_lock */ +extern int drbd_bm_count_bits( + struct drbd_conf *mdev, const unsigned long s, const unsigned long e); +/* bm_set_bits variant for use while holding drbd_bm_lock, + * may process the whole bitmap in one go */ extern void _drbd_bm_set_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e); extern int drbd_bm_test_bit(struct drbd_conf *mdev, unsigned long bitnr); @@ -1436,6 +1442,8 @@ extern unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, extern size_t drbd_bm_words(struct drbd_conf *mdev); extern unsigned long drbd_bm_bits(struct drbd_conf *mdev); extern sector_t drbd_bm_capacity(struct drbd_conf *mdev); + +#define DRBD_END_OF_BITMAP (~(unsigned long)0) extern unsigned long drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo); /* bm_find_next variants for use while you hold drbd_bm_lock() */ extern unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo); @@ -1452,8 +1460,6 @@ extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, extern void drbd_bm_lock(struct drbd_conf *mdev, char *why); extern void drbd_bm_unlock(struct drbd_conf *mdev); - -extern int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsigned long e); /* drbd_main.c */ extern struct kmem_cache *drbd_request_cache; @@ -2158,10 +2164,8 @@ extern int _get_ldev_if_state(struct drbd_conf *mdev, enum drbd_disk_state mins) static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, unsigned long *bits_left, unsigned int *per_mil_done) { - /* - * this is to break it at compile time when we change that - * (we may feel 4TB maximum storage per drbd is not enough) - */ + /* this is to break it at compile time when we change that, in case we + * want to support more than (1<<32) bits on a 32bit arch. */ typecheck(unsigned long, mdev->rs_total); /* note: both rs_total and rs_left are in bits, i.e. in @@ -2186,10 +2190,19 @@ static inline void drbd_get_syncer_progress(struct drbd_conf *mdev, *bits_left, mdev->rs_total, mdev->rs_failed); *per_mil_done = 0; } else { - /* make sure the calculation happens in long context */ - unsigned long tmp = 1000UL - - (*bits_left >> 10)*1000UL - / ((mdev->rs_total >> 10) + 1UL); + /* Make sure the division happens in long context. + * We allow up to one petabyte storage right now, + * at a granularity of 4k per bit that is 2**38 bits. + * After shift right and multiplication by 1000, + * this should still fit easily into a 32bit long, + * so we don't need a 64bit division on 32bit arch. + * Note: currently we don't support such large bitmaps on 32bit + * arch anyways, but no harm done to be prepared for it here. + */ + unsigned int shift = mdev->rs_total >= (1ULL << 32) ? 16 : 10; + unsigned long left = *bits_left >> shift; + unsigned long total = 1UL + (mdev->rs_total >> shift); + unsigned long tmp = 1000UL - left * 1000UL/total; *per_mil_done = tmp; } } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 77dc022eaf6b..a46bc0287e21 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -527,17 +527,19 @@ static void drbd_md_set_sector_offsets(struct drbd_conf *mdev, } } +/* input size is expected to be in KB */ char *ppsize(char *buf, unsigned long long size) { - /* Needs 9 bytes at max. */ + /* Needs 9 bytes at max including trailing NUL: + * -1ULL ==> "16384 EB" */ static char units[] = { 'K', 'M', 'G', 'T', 'P', 'E' }; int base = 0; - while (size >= 10000) { + while (size >= 10000 && base < sizeof(units)-1) { /* shift + round */ size = (size >> 10) + !!(size & (1<<9)); base++; } - sprintf(buf, "%lu %cB", (long)size, units[base]); + sprintf(buf, "%u %cB", (unsigned)size, units[base]); return buf; } diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index efba62cd2e58..2959cdfb77f5 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -91,9 +91,9 @@ static void drbd_syncer_progress(struct drbd_conf *mdev, struct seq_file *seq) seq_printf(seq, "sync'ed:"); seq_printf(seq, "%3u.%u%% ", res / 10, res % 10); - /* if more than 1 GB display in MB */ - if (mdev->rs_total > 0x100000L) - seq_printf(seq, "(%lu/%lu)M\n\t", + /* if more than a few GB, display in MB */ + if (mdev->rs_total > (4UL << (30 - BM_BLOCK_SHIFT))) + seq_printf(seq, "(%lu/%lu)M", (unsigned long) Bit2KB(rs_left >> 10), (unsigned long) Bit2KB(mdev->rs_total >> 10)); else diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index d17f2ed777ce..be46084c254e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -577,7 +577,7 @@ next_sector: size = BM_BLOCK_SIZE; bit = drbd_bm_find_next(mdev, mdev->bm_resync_fo); - if (bit == -1UL) { + if (bit == DRBD_END_OF_BITMAP) { mdev->bm_resync_fo = drbd_bm_bits(mdev); mdev->resync_work.cb = w_resync_inactive; put_ldev(mdev); -- cgit v1.2.2 From 6850c4421481139dc2cf982358e79c833a50d73c Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 16 Dec 2010 00:32:38 +0100 Subject: drbd: get rid of unused debug code Long time ago, we had paranoia code in the bitmap that allocated one extra word, assigned a magic value, and checked on every occasion that the magic value was still unchanged. That debug code is unused, the extra long word complicates code a bit. Get rid of it. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 0e31e573af72..09d208b858e7 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -488,10 +488,7 @@ static int bm_clear_surplus(struct drbd_bitmap *b) * on disk and in core memory alike */ mask = cpu_to_lel(mask); - /* because of the "extra long to catch oob access" we allocate in - * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page - * containing the last _relevant_ bitmap word */ - p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, b->bm_bits - 1)); + p_addr = bm_map_pidx(b, b->bm_number_of_pages - 1); bm = p_addr + (tmp/BITS_PER_LONG); if (mask) { /* If mask != 0, we are not exactly aligned, so bm now points @@ -527,10 +524,7 @@ static void bm_set_surplus(struct drbd_bitmap *b) * on disk and in core memory alike */ mask = cpu_to_lel(mask); - /* because of the "extra long to catch oob access" we allocate in - * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page - * containing the last _relevant_ bitmap word */ - p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, b->bm_bits - 1)); + p_addr = bm_map_pidx(b, b->bm_number_of_pages - 1); bm = p_addr + (tmp/BITS_PER_LONG); if (mask) { /* If mask != 0, we are not exactly aligned, so bm now points @@ -556,15 +550,10 @@ static unsigned long bm_count_bits(struct drbd_bitmap *b) unsigned long *p_addr; unsigned long bits = 0; unsigned long mask = (1UL << (b->bm_bits & BITS_PER_LONG_MASK)) -1; - int idx, last_page, i, last_word; - - /* because of the "extra long to catch oob access" we allocate in - * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page - * containing the last _relevant_ bitmap word */ - last_page = bm_bit_to_page_idx(b, b->bm_bits-1); + int idx, i, last_word; /* all but last page */ - for (idx = 0; idx < last_page; idx++) { + for (idx = 0; idx < b->bm_number_of_pages - 1; idx++) { p_addr = __bm_map_pidx(b, idx, KM_USER0); for (i = 0; i < LWPP; i++) bits += hweight_long(p_addr[i]); @@ -627,7 +616,7 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) { struct drbd_bitmap *b = mdev->bitmap; - unsigned long bits, words, owords, obits, *p_addr, *bm; + unsigned long bits, words, owords, obits; unsigned long want, have, onpages; /* number of pages */ struct page **npages, **opages = NULL; int err = 0, growing; @@ -681,8 +670,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) } } - /* one extra long to catch off by one errors */ - want = ALIGN((words+1)*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT; + want = ALIGN(words*sizeof(long), PAGE_SIZE) >> PAGE_SHIFT; have = b->bm_number_of_pages; if (want == have) { D_ASSERT(b->bm_pages != NULL); @@ -728,11 +716,6 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) bm_free_pages(opages + want, have - want); } - p_addr = bm_map_pidx(b, bm_word_to_page_idx(b, words)); - bm = p_addr + MLPP(words); - *bm = DRBD_MAGIC; - bm_unmap(p_addr); - (void)bm_clear_surplus(b); spin_unlock_irq(&b->bm_lock); @@ -845,7 +828,6 @@ void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, size_t number, */ if (end == b->bm_words) b->bm_set -= bm_clear_surplus(b); - spin_unlock_irq(&b->bm_lock); } @@ -1030,7 +1012,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id struct bm_aio_ctx ctx = { .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0 }; struct drbd_bitmap *b = mdev->bitmap; - int last_page, i, count = 0; + int num_pages, i, count = 0; unsigned long now; char ppb[10]; int err = 0; @@ -1046,10 +1028,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id if (!ctx.flags) WARN_ON(!bm_is_locked(b)); - /* because of the "extra long to catch oob access" we allocate in - * drbd_bm_resize, bm_number_of_pages -1 is not necessarily the page - * containing the last _relevant_ bitmap word */ - last_page = bm_word_to_page_idx(b, b->bm_words - 1); + num_pages = b->bm_number_of_pages; now = jiffies; ctx.mdev = mdev; @@ -1058,7 +1037,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id ctx.error = 0; /* let the layers below us try to merge these bios... */ - for (i = 0; i <= last_page; i++) { + for (i = 0; i < num_pages; i++) { /* ignore completely unchanged pages */ if (lazy_writeout_upper_idx && i == lazy_writeout_upper_idx) break; -- cgit v1.2.2 From 84e7c0f7d123d64d97e1f789ad2f23a72fe8981f Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 16 Dec 2010 00:37:57 +0100 Subject: drbd: Removed a reference to debug macros removed long time ago Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 09d208b858e7..423dede45844 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -596,9 +596,8 @@ static void bm_memset(struct drbd_bitmap *b, size_t offset, int c, size_t len) if (bm+do_now > p_addr + LWPP) { printk(KERN_ALERT "drbd: BUG BUG BUG! p_addr:%p bm:%p do_now:%d\n", p_addr, bm, (int)do_now); - break; /* breaks to after catch_oob_access_end() only! */ - } - memset(bm, c, do_now * sizeof(long)); + } else + memset(bm, c, do_now * sizeof(long)); bm_unmap(p_addr); bm_set_page_need_writeout(b->bm_pages[idx]); offset += do_now; -- cgit v1.2.2 From 02851e9f00d78dbc8ded0aacbf9bf3b631d627b3 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 16 Dec 2010 14:47:39 +0100 Subject: drbd: move bitmap write from resync_finished to after_state_change We must not call it directly from resync_finished, as we may be in either receiver or worker context there. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 14 ++++++++++---- drivers/block/drbd/drbd_worker.c | 3 --- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 57ed7181742d..c6c7e3e6dc23 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1548,6 +1548,9 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) drbd_send_state(mdev); + if (os.conn > C_CONNECTED && ns.conn == C_CONNECTED) + drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); + /* free tl_hash if we Got thawed and are C_STANDALONE */ if (ns.conn == C_STANDALONE && !is_susp(ns) && mdev->tl_hash) drbd_free_tl_hash(mdev); @@ -3860,13 +3863,16 @@ int drbd_bmio_clear_n_write(struct drbd_conf *mdev) static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) { struct bm_io_work *work = container_of(w, struct bm_io_work, w); - int rv; + int rv = -EIO; D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0); - drbd_bm_lock(mdev, work->why); - rv = work->io_fn(mdev); - drbd_bm_unlock(mdev); + if (get_ldev(mdev)) { + drbd_bm_lock(mdev, work->why); + rv = work->io_fn(mdev); + drbd_bm_unlock(mdev); + put_ldev(mdev); + } clear_bit(BITMAP_IO, &mdev->flags); smp_mb__after_clear_bit(); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index be46084c254e..2374454cdf17 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -907,9 +907,6 @@ out: drbd_md_sync(mdev); - dev_info(DEV, "Writing changed bitmap pages\n"); - drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); - if (khelper_cmd) drbd_khelper(mdev, khelper_cmd); -- cgit v1.2.2 From 2265b473aecc1a6fe1f84a0ee272ba39806c2a8a Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 16 Dec 2010 15:41:26 +0100 Subject: drbd: fix potential dereference of NULL pointer If drbd used to have crypto digest algorithms configured, then is being unconfigured (but not unloaded), it frees the algorithms, but does not reset the config. If it then is reconfigured to use the very same algorithm, it "forgot" to re-allocate the algorithms, thinking that the config has not changed in that aspect. It will then Oops on the first attempt to actually use those algorithms. Fix this by resetting the config to defaults after cleanup. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index c6c7e3e6dc23..4da6f11cc82e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3020,6 +3020,8 @@ void drbd_mdev_cleanup(struct drbd_conf *mdev) D_ASSERT(list_empty(&mdev->resync_work.list)); D_ASSERT(list_empty(&mdev->unplug_work.list)); D_ASSERT(list_empty(&mdev->go_diskless.list)); + + drbd_set_defaults(mdev); } -- cgit v1.2.2 From c88d65e2231dbae4b7cd0ad7b2a919857a1be171 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 20 Dec 2010 15:29:28 +0100 Subject: drbd: Documenting drbd_should_do_remote() and drbd_should_send_oos() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 528909090df7..889175110c91 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -762,7 +762,7 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); } -static int drbd_should_do_remote(struct drbd_conf *mdev) +static bool drbd_should_do_remote(struct drbd_conf *mdev) { union drbd_state s = mdev->state; @@ -770,13 +770,17 @@ static int drbd_should_do_remote(struct drbd_conf *mdev) (s.pdsk >= D_INCONSISTENT && s.conn >= C_WF_BITMAP_T && s.conn < C_AHEAD); + /* Before proto 96 that was >= CONNECTED instead of >= C_WF_BITMAP_T. + That is equivalent since before 96 IO was frozen in the C_WF_BITMAP* + states. */ } -static int drbd_should_send_oos(struct drbd_conf *mdev) +static bool drbd_should_send_oos(struct drbd_conf *mdev) { union drbd_state s = mdev->state; - return s.pdsk >= D_INCONSISTENT && - (s.conn == C_AHEAD || s.conn == C_WF_BITMAP_S); + return s.conn == C_AHEAD || s.conn == C_WF_BITMAP_S; + /* pdsk = D_INCONSISTENT as a consequence. Protocol 96 check not necessary + since we enter state C_AHEAD only if proto >= 96 */ } static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) -- cgit v1.2.2 From f735e3635430c6d1c319664d82b34376e3f9aa17 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 17 Dec 2010 21:06:18 +0100 Subject: drbd: add debugging assert to make sure the protocol is clean We expect to only receive the recently introduced "set out of sync" packets in specific states. If we receive them in different states, that may confuse the resync process to the point where it won't terminate, or think it made negative progress. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index be7fc67eeeca..f0a0f66fbe68 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3599,6 +3599,16 @@ static int receive_out_of_sync(struct drbd_conf *mdev, enum drbd_packets cmd, un { struct p_block_desc *p = &mdev->data.rbuf.block_desc; + switch (mdev->state.conn) { + case C_WF_SYNC_UUID: + case C_WF_BITMAP_T: + case C_BEHIND: + break; + default: + dev_err(DEV, "ASSERT FAILED cstate = %s, expected: WFSyncUUID|WFBitMapT|Behind\n", + drbd_conn_str(mdev->state.conn)); + } + drbd_set_out_of_sync(mdev, be64_to_cpu(p->sector), be32_to_cpu(p->blksize)); return true; -- cgit v1.2.2 From 5a22db8968a69bec835d1ed9a96ab3381719e0c0 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 17 Dec 2010 21:14:23 +0100 Subject: drbd: serialize sending of resync uuid with pending w_send_oos To improve the latency of IO requests during bitmap exchange, we recently allowed writes while waiting for the bitmap, sending "set out-of-sync" information packets for any newly dirtied bits. We have to make sure that the new resync-uuid does not overtake these "set oos" packets. Once the resync-uuid is received, the sync target starts the resync process, and expects the bitmap to only be cleared, not re-set. If we use this protocol extension, we queue the generation and sending of the resync-uuid on the worker, which naturally serializes with all previously queued packets. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 22 +++++++++++++++++++--- drivers/block/drbd/drbd_worker.c | 27 ++++++++++++++------------- 3 files changed, 34 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 5a2d0ec72b34..ec06e744be42 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1204,7 +1204,7 @@ extern int drbd_send(struct drbd_conf *mdev, struct socket *sock, extern int drbd_send_protocol(struct drbd_conf *mdev); extern int drbd_send_uuids(struct drbd_conf *mdev); extern int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev); -extern int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val); +extern int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev); extern int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags flags); extern int _drbd_send_state(struct drbd_conf *mdev); extern int drbd_send_state(struct drbd_conf *mdev); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 4da6f11cc82e..2190064d59bd 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1387,6 +1387,17 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, spin_unlock_irq(&mdev->req_lock); } + /* Became sync source. With protocol >= 96, we still need to send out + * the sync uuid now. Need to do that before any drbd_send_state, or + * the other side may go "paused sync" before receiving the sync uuids, + * which is unexpected. */ + if ((os.conn != C_SYNC_SOURCE && os.conn != C_PAUSED_SYNC_S) && + (ns.conn == C_SYNC_SOURCE || ns.conn == C_PAUSED_SYNC_S) && + mdev->agreed_pro_version >= 96 && get_ldev(mdev)) { + drbd_gen_and_send_sync_uuid(mdev); + put_ldev(mdev); + } + /* Do not change the order of the if above and the two below... */ if (os.pdsk == D_DISKLESS && ns.pdsk > D_DISKLESS) { /* attach on the peer */ drbd_send_uuids(mdev); @@ -1980,12 +1991,17 @@ int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev) return _drbd_send_uuids(mdev, 8); } - -int drbd_send_sync_uuid(struct drbd_conf *mdev, u64 val) +int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev) { struct p_rs_uuid p; + u64 uuid; + + D_ASSERT(mdev->state.disk == D_UP_TO_DATE); - p.uuid = cpu_to_be64(val); + get_random_bytes(&uuid, sizeof(u64)); + drbd_uuid_set(mdev, UI_BITMAP, uuid); + drbd_md_sync(mdev); + p.uuid = cpu_to_be64(uuid); return drbd_send_cmd(mdev, USE_DATA_SOCKET, P_SYNC_UUID, (struct p_header80 *)&p, sizeof(p)); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 2374454cdf17..3df37e65c118 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1516,18 +1516,6 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) return; } - if (side == C_SYNC_TARGET) { - mdev->bm_resync_fo = 0; - } else /* side == C_SYNC_SOURCE */ { - u64 uuid; - - get_random_bytes(&uuid, sizeof(u64)); - drbd_uuid_set(mdev, UI_BITMAP, uuid); - drbd_send_sync_uuid(mdev, uuid); - - D_ASSERT(mdev->state.disk == D_UP_TO_DATE); - } - write_lock_irq(&global_state_lock); ns = mdev->state; @@ -1565,7 +1553,19 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) _drbd_pause_after(mdev); } write_unlock_irq(&global_state_lock); - put_ldev(mdev); + + if (side == C_SYNC_TARGET) + mdev->bm_resync_fo = 0; + + /* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid + * with w_send_oos, or the sync target will get confused as to + * how much bits to resync. We cannot do that always, because for an + * empty resync and protocol < 95, we need to do it here, as we call + * drbd_resync_finished from here in that case. + * We drbd_gen_and_send_sync_uuid here for protocol < 96, + * and from after_state_ch otherwise. */ + if (side == C_SYNC_SOURCE && mdev->agreed_pro_version < 96) + drbd_gen_and_send_sync_uuid(mdev); if (r == SS_SUCCESS) { dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n", @@ -1601,6 +1601,7 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) drbd_md_sync(mdev); } + put_ldev(mdev); drbd_state_unlock(mdev); } -- cgit v1.2.2 From 7648cdfe52daf0ca4fa9489879dea9e089b0dfe1 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 17 Dec 2010 23:58:41 +0100 Subject: drbd: be less noisy with some log messages We expect changes to a bitmap page in drbd_bm_write_page, that's why we submit a copy page. If a page changes during global writeout, that would be unexpected, and reason to warn, though. Also, often page writeout can be skipped (on activity log transactions during normal operation, for example), no need to log that everytime. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 423dede45844..314a3632303b 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -920,8 +920,9 @@ static void bm_async_io_complete(struct bio *bio, int error) if (!error && !uptodate) error = -EIO; - if (!bm_test_page_unchanged(b->bm_pages[idx])) - dev_info(DEV, "bitmap page idx %u changed during IO!\n", idx); + if ((ctx->flags & BM_AIO_COPY_PAGES) == 0 && + !bm_test_page_unchanged(b->bm_pages[idx])) + dev_warn(DEV, "bitmap page idx %u changed during IO!\n", idx); if (error) { /* ctx error will hold the completed-last non-zero error code, @@ -1135,7 +1136,7 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc struct bm_aio_ctx ctx = { .flags = BM_AIO_COPY_PAGES, }; if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { - dev_info(DEV, "skipped bm page write for idx %u\n", idx); + dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx); return 0; } -- cgit v1.2.2 From 418e0a927d520f9c8e875ea75abee35d93a0f1b3 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Sat, 18 Dec 2010 13:36:54 +0100 Subject: drbd: spelling fix in log message Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 2190064d59bd..f529c25e1ad5 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1351,7 +1351,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (ns.conn == C_CONNECTED) what = resend, nsm.susp_nod = 0; else /* ns.conn > C_CONNECTED */ - dev_err(DEV, "Unexpected Resynd going on!\n"); + dev_err(DEV, "Unexpected Resync going on!\n"); } if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) -- cgit v1.2.2 From 06d33e968d2c58143a7aaafa8963cf6a58099467 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Sat, 18 Dec 2010 17:00:59 +0100 Subject: drbd: improve on bitmap write out timing Even though we now track the need for bitmap writeout per bitmap page, there is no need to trigger the writeout while a resync is going on. Once the resync is finished (or aborted), we trigger bitmap writeout anyways. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f529c25e1ad5..755297a15633 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1439,7 +1439,11 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, put_ldev(mdev); } - if (os.role == R_PRIMARY && ns.role == R_SECONDARY && get_ldev(mdev)) { + /* Write out all changed bits on demote. + * Though, no need to da that just yet + * if there is a resync going on still */ + if (os.role == R_PRIMARY && ns.role == R_SECONDARY && + mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) { drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, "demote"); put_ldev(mdev); } @@ -1559,7 +1563,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) drbd_send_state(mdev); - if (os.conn > C_CONNECTED && ns.conn == C_CONNECTED) + if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); /* free tl_hash if we Got thawed and are C_STANDALONE */ -- cgit v1.2.2 From 725a97e43ee945cc813fffd9e628e50d703b973b Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Sun, 19 Dec 2010 11:29:55 +0100 Subject: drbd: fix potential access of on-stack wait_queue_head_t after return I run into something declaring itself as "spinlock deadlock", BUG: spinlock lockup on CPU#1, kjournald/27816, ffff88000ad6bca0 Pid: 27816, comm: kjournald Tainted: G W 2.6.34.6 #2 Call Trace: [] do_raw_spin_lock+0x11e/0x14d [] _raw_spin_lock_irqsave+0x6a/0x81 [] ? __wake_up+0x22/0x50 [] __wake_up+0x22/0x50 [] bm_async_io_complete+0x258/0x299 [drbd] but the call traces do not fit at all, all other cpus are cpu_idle. I think it may be this race: drbd_bm_write_page wait_queue_head_t io_wait; atomic_t in_flight; bm_async_io submit_bio bm_async_io_complete if (atomic_dec_and_test(in_flight)) wait_event(io_wait, atomic_read(in_flight) == 0) return wake_up(io_wait) The wake_up now accesses the wait_queue_head_t spinlock, which is no longer valid, since the stack frame of drbd_bm_write_page has been clobbered now. Fix this by using struct completion, which does both the condition test as well as the wake_up inside its spinlock, so this race cannot happen. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 314a3632303b..25428bc28476 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -897,7 +897,7 @@ void drbd_bm_clear_all(struct drbd_conf *mdev) struct bm_aio_ctx { struct drbd_conf *mdev; atomic_t in_flight; - wait_queue_head_t io_wait; + struct completion done; unsigned flags; #define BM_AIO_COPY_PAGES 1 int error; @@ -948,7 +948,7 @@ static void bm_async_io_complete(struct bio *bio, int error) bio_put(bio); if (atomic_dec_and_test(&ctx->in_flight)) - wake_up(&ctx->io_wait); + complete(&ctx->done); } static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local) @@ -1009,8 +1009,12 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must */ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_idx) __must_hold(local) { - struct bm_aio_ctx ctx = - { .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0 }; + struct bm_aio_ctx ctx = { + .mdev = mdev, + .in_flight = ATOMIC_INIT(1), + .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), + .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0, + }; struct drbd_bitmap *b = mdev->bitmap; int num_pages, i, count = 0; unsigned long now; @@ -1031,10 +1035,6 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id num_pages = b->bm_number_of_pages; now = jiffies; - ctx.mdev = mdev; - atomic_set(&ctx.in_flight, 1); /* one extra ref */ - init_waitqueue_head(&ctx.io_wait); - ctx.error = 0; /* let the layers below us try to merge these bios... */ for (i = 0; i < num_pages; i++) { @@ -1060,8 +1060,13 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id cond_resched(); } - atomic_dec(&ctx.in_flight); /* drop the extra ref */ - wait_event(ctx.io_wait, atomic_read(&ctx.in_flight) == 0); + /* + * We initialize ctx.in_flight to one to make sure bm_async_io_complete + * will not complete() early, and decrement / test it here. If there + * are still some bios in flight, we need to wait for them here. + */ + if (!atomic_dec_and_test(&ctx.in_flight)) + wait_for_completion(&ctx.done); dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", rw == WRITE ? "WRITE" : "READ", count, jiffies - now); @@ -1133,19 +1138,20 @@ int drbd_bm_write_lazy(struct drbd_conf *mdev, unsigned upper_idx) __must_hold(l */ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) { - struct bm_aio_ctx ctx = { .flags = BM_AIO_COPY_PAGES, }; + struct bm_aio_ctx ctx = { + .mdev = mdev, + .in_flight = ATOMIC_INIT(1), + .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), + .flags = BM_AIO_COPY_PAGES, + }; if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx); return 0; } - ctx.mdev = mdev; - atomic_set(&ctx.in_flight, 1); - init_waitqueue_head(&ctx.io_wait); - bm_page_io_async(&ctx, idx, WRITE_SYNC); - wait_event(ctx.io_wait, atomic_read(&ctx.in_flight) == 0); + wait_for_completion(&ctx.done); if (ctx.error) drbd_chk_io_error(mdev, 1, true); -- cgit v1.2.2 From 3f98688afc2ce0138fc88e272bdd128e1e0b0976 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 20 Dec 2010 14:48:20 +0100 Subject: drbd: There might be a resync after unfreezing IO due to no disk [Bugz 332] When on-no-data-accessible is set to suspend-io, also consider that a Primary, SyncTarget node losses its connection. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 755297a15633..9bd53cf2cdb2 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1347,16 +1347,14 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, nsm.i = -1; if (ns.susp_nod) { - if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { - if (ns.conn == C_CONNECTED) - what = resend, nsm.susp_nod = 0; - else /* ns.conn > C_CONNECTED */ - dev_err(DEV, "Unexpected Resync going on!\n"); - } + if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) + what = resend; if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) - what = restart_frozen_disk_io, nsm.susp_nod = 0; + what = restart_frozen_disk_io; + if (what != nothing) + nsm.susp_nod = 0; } if (ns.susp_fen) { -- cgit v1.2.2 From 071942727824bab03b1a3f6b6eeb5b269697b333 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 20 Dec 2010 15:38:07 +0100 Subject: drbd: ratelimit io error messages Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 3df37e65c118..7bfeb79e7105 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -165,14 +165,15 @@ void drbd_endio_sec(struct bio *bio, int error) int uptodate = bio_flagged(bio, BIO_UPTODATE); int is_write = bio_data_dir(bio) == WRITE; - if (error) + if (error && __ratelimit(&drbd_ratelimit_state)) dev_warn(DEV, "%s: error=%d s=%llus\n", is_write ? "write" : "read", error, (unsigned long long)e->sector); if (!error && !uptodate) { - dev_warn(DEV, "%s: setting error to -EIO s=%llus\n", - is_write ? "write" : "read", - (unsigned long long)e->sector); + if (__ratelimit(&drbd_ratelimit_state)) + dev_warn(DEV, "%s: setting error to -EIO s=%llus\n", + is_write ? "write" : "read", + (unsigned long long)e->sector); /* strange behavior of some lower level drivers... * fail the request by clearing the uptodate flag, * but do not return any error?! */ -- cgit v1.2.2 From 617049aa7d753e8c821ac77126ab90e9f1b66d6d Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 22 Dec 2010 12:48:31 +0100 Subject: drbd: Fixed an issue with AHEAD -> SYNC_SOURCE transitions Create a new barrier when leaving the AHEAD mode. Otherwise we trigger the assertion in req_mod(, barrier_acked) D_ASSERT(req->rq_state & RQ_NET_SENT); The new barrier is created by recycling the newest existing one. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9bd53cf2cdb2..90050ab7adf3 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -335,6 +335,24 @@ bail: drbd_force_state(mdev, NS(conn, C_PROTOCOL_ERROR)); } + +/* In C_AHEAD mode only out_of_sync packets are sent for requests. Detach + * those requests from the newsest barrier when changing to an other cstate. + * + * That headless list vanishes when the last request finished its write or + * send out_of_sync packet. */ +static void tl_forget(struct drbd_conf *mdev) +{ + struct drbd_tl_epoch *b; + + if (test_bit(CREATE_BARRIER, &mdev->flags)) + return; + + b = mdev->newest_tle; + list_del(&b->requests); + _tl_add_barrier(mdev, b); +} + /** * _tl_restart() - Walks the transfer log, and applies an action to all requests * @mdev: DRBD device. @@ -1242,6 +1260,9 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) drbd_resume_al(mdev); + if (os.conn == C_AHEAD && ns.conn != C_AHEAD) + tl_forget(mdev); + ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); if (ascw) { ascw->os = os; -- cgit v1.2.2 From d612d309e4c8401ad94c531678b59c4a8b7c41ce Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 27 Dec 2010 10:53:28 +0100 Subject: drbd: No longer answer P_RS_DATA_REQUEST packets when in C_AHEAD mode When the sync source node replies to a P_RS_DATA_REQUEST packet when it is already in ahead mode. I.e. those two packets crossed each other on the wire, that may lead to diverging bitmaps. This never happens in a well-tuned-system. In a well-tuned- system the resync controller has reduced the resync speed to zero long before we got into ahead-mode. But we have to be prepared for the not-well-tuned-system of course as well. Because -> diverging bitmaps = non terminating resync. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 ++- drivers/block/drbd/drbd_receiver.c | 12 +++++++++++- drivers/block/drbd/drbd_worker.c | 4 +++- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index ec06e744be42..a529285b0cd3 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -205,8 +205,9 @@ enum drbd_packets { /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */ P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */ P_OUT_OF_SYNC = 0x28, /* Mark as out of sync (Outrunning), data socket */ + P_RS_CANCEL = 0x29, /* meta: Used to cancel RS_DATA_REQUEST packet by SyncSource */ - P_MAX_CMD = 0x28, + P_MAX_CMD = 0x2A, P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ P_MAX_OPT_CMD = 0x101, diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index f0a0f66fbe68..bf865bd83414 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4361,7 +4361,16 @@ static int got_NegRSDReply(struct drbd_conf *mdev, struct p_header80 *h) if (get_ldev_if_state(mdev, D_FAILED)) { drbd_rs_complete_io(mdev, sector); - drbd_rs_failed_io(mdev, sector, size); + switch (be16_to_cpu(h->command)) { + case P_NEG_RS_DREPLY: + drbd_rs_failed_io(mdev, sector, size); + case P_RS_CANCEL: + break; + default: + D_ASSERT(0); + put_ldev(mdev); + return false; + } put_ldev(mdev); } @@ -4459,6 +4468,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, [P_DELAY_PROBE] = { sizeof(struct p_delay_probe93), got_skip }, + [P_RS_CANCEL] = { sizeof(struct p_block_ack), got_NegRSDReply}, [P_MAX_CMD] = { 0, NULL }, }; if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 7bfeb79e7105..1d7510ebaa43 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -988,7 +988,9 @@ int w_e_end_rsdata_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) put_ldev(mdev); } - if (likely((e->flags & EE_WAS_ERROR) == 0)) { + if (mdev->state.conn == C_AHEAD) { + ok = drbd_send_ack(mdev, P_RS_CANCEL, e); + } else if (likely((e->flags & EE_WAS_ERROR) == 0)) { if (likely(mdev->state.pdsk >= D_INCONSISTENT)) { inc_rs_pending(mdev); ok = drbd_send_block(mdev, P_RS_DATA_REPLY, e); -- cgit v1.2.2 From da0a78161d2b2da4819a1f05a38bb1dcbe02d951 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 23 Dec 2010 14:24:33 +0100 Subject: drbd: Be more careful with SyncSource -> Ahead transitions We may not get from SyncSource to Ahead if we have sent some P_RS_DATA_REPLY packets to the peer and are waiting for P_WRITE_ACK. Again, this is not relevant for proper tuned systems, but makes sure that the not-tuned system does not get diverging bitmaps. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 3 ++- drivers/block/drbd/drbd_req.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index bf865bd83414..fd0957f9c230 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4385,10 +4385,11 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) if (mdev->state.conn == C_AHEAD && atomic_read(&mdev->ap_in_flight) == 0 && + atomic_read(&mdev->rs_pending_cnt) == 0 && list_empty(&mdev->start_resync_work.list)) { struct drbd_work *w = &mdev->start_resync_work; w->cb = w_start_resync; - drbd_queue_work_front(&mdev->data.work, w); + drbd_queue_work(&mdev->data.work, w); } return true; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 889175110c91..a3f6b04ebaba 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1002,7 +1002,13 @@ allocate_barrier: congested = 1; } - if (congested) { + if (congested && atomic_read(&mdev->rs_pending_cnt) == 0) { + /* rs_pending_cnt must be zero, otherwise the two peers + might get different bitmaps. With sane configurations + the resync stalls long before we might want to go into + AHEAD mode. + We could force the resync into PAUSE mode here if + rs_pending_cnt is > 0 ... */ queue_barrier(mdev); if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) -- cgit v1.2.2 From 794abb753e29e85949b3719dbc2ab6a98711a47e Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 27 Dec 2010 11:51:23 +0100 Subject: drbd: Cleaned up the resync timer logic Besides removed a few lines of code, this moves the inspection of the state from before the queuing process to after the queuing. I.e. more closely to the actual invocation of the work. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 2 +- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_worker.c | 48 +++++++++------------------------------- 3 files changed, 13 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index a529285b0cd3..dc11b7070ba9 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1540,7 +1540,7 @@ extern int w_e_end_csum_rs_req(struct drbd_conf *, struct drbd_work *, int); extern int w_e_end_ov_reply(struct drbd_conf *, struct drbd_work *, int); extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int); extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int); -extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int); +extern int w_resync_timer(struct drbd_conf *, struct drbd_work *, int); extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int); extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int); extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 90050ab7adf3..4074d6699307 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2978,7 +2978,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) INIT_LIST_HEAD(&mdev->start_resync_work.list); INIT_LIST_HEAD(&mdev->bm_io_work.w.list); - mdev->resync_work.cb = w_resync_inactive; + mdev->resync_work.cb = w_resync_timer; mdev->unplug_work.cb = w_send_write_hint; mdev->go_diskless.cb = w_go_diskless; mdev->md_sync_work.cb = w_md_sync; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 1d7510ebaa43..147f76b26810 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -253,13 +253,6 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel) return w_send_read_req(mdev, w, 0); } -int w_resync_inactive(struct drbd_conf *mdev, struct drbd_work *w, int cancel) -{ - ERR_IF(cancel) return 1; - dev_err(DEV, "resync inactive, but callback triggered??\n"); - return 1; /* Simply ignore this! */ -} - void drbd_csum_ee(struct drbd_conf *mdev, struct crypto_hash *tfm, struct drbd_epoch_entry *e, void *digest) { struct hash_desc desc; @@ -389,26 +382,25 @@ defer: return -EAGAIN; } -void resync_timer_fn(unsigned long data) +int w_resync_timer(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - struct drbd_conf *mdev = (struct drbd_conf *) data; - int queue; - - queue = 1; switch (mdev->state.conn) { case C_VERIFY_S: - mdev->resync_work.cb = w_make_ov_request; + w_make_ov_request(mdev, w, cancel); break; case C_SYNC_TARGET: - mdev->resync_work.cb = w_make_resync_request; + w_make_resync_request(mdev, w, cancel); break; - default: - queue = 0; - mdev->resync_work.cb = w_resync_inactive; } - /* harmless race: list_empty outside data.work.q_lock */ - if (list_empty(&mdev->resync_work.list) && queue) + return 1; +} + +void resync_timer_fn(unsigned long data) +{ + struct drbd_conf *mdev = (struct drbd_conf *) data; + + if (list_empty(&mdev->resync_work.list)) drbd_queue_work(&mdev->data.work, &mdev->resync_work); } @@ -525,15 +517,6 @@ static int w_make_resync_request(struct drbd_conf *mdev, if (unlikely(cancel)) return 1; - if (unlikely(mdev->state.conn < C_CONNECTED)) { - dev_err(DEV, "Confused in w_make_resync_request()! cstate < Connected"); - return 0; - } - - if (mdev->state.conn != C_SYNC_TARGET) - dev_err(DEV, "%s in w_make_resync_request\n", - drbd_conn_str(mdev->state.conn)); - if (mdev->rs_total == 0) { /* empty resync? */ drbd_resync_finished(mdev); @@ -546,7 +529,6 @@ static int w_make_resync_request(struct drbd_conf *mdev, to continue resync with a broken disk makes no sense at all */ dev_err(DEV, "Disk broke down during resync!\n"); - mdev->resync_work.cb = w_resync_inactive; return 1; } @@ -580,7 +562,6 @@ next_sector: if (bit == DRBD_END_OF_BITMAP) { mdev->bm_resync_fo = drbd_bm_bits(mdev); - mdev->resync_work.cb = w_resync_inactive; put_ldev(mdev); return 1; } @@ -676,7 +657,6 @@ next_sector: * resync data block, and the last bit is cleared. * until then resync "work" is "inactive" ... */ - mdev->resync_work.cb = w_resync_inactive; put_ldev(mdev); return 1; } @@ -697,17 +677,11 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca if (unlikely(cancel)) return 1; - if (unlikely(mdev->state.conn < C_CONNECTED)) { - dev_err(DEV, "Confused in w_make_ov_request()! cstate < Connected"); - return 0; - } - number = drbd_rs_number_requests(mdev); sector = mdev->ov_position; for (i = 0; i < number; i++) { if (sector >= capacity) { - mdev->resync_work.cb = w_resync_inactive; return 1; } -- cgit v1.2.2 From 110a204a354a5a69f99ed0bc8e6d779e6a94d410 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Mon, 3 Jan 2011 15:47:08 +0100 Subject: drbd: Remove useless / wrong comments Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index dc11b7070ba9..84b4575fdf43 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -680,13 +680,6 @@ static inline enum drbd_thread_state get_t_state(struct drbd_thread *thi) return thi->t_state; } - -/* - * Having this as the first member of a struct provides sort of "inheritance". - * "derived" structs can be "drbd_queue_work()"ed. - * The callback should know and cast back to the descendant struct. - * drbd_request and drbd_epoch_entry are descendants of drbd_work. - */ struct drbd_work; typedef int (*drbd_work_cb)(struct drbd_conf *, struct drbd_work *, int cancel); struct drbd_work { @@ -715,9 +708,6 @@ struct drbd_request { * starting a new epoch... */ - /* up to here, the struct layout is identical to drbd_epoch_entry; - * we might be able to use that to our advantage... */ - struct list_head tl_requests; /* ring list in the transfer log */ struct bio *master_bio; /* master bio pointer */ unsigned long rq_state; /* see comments above _req_mod() */ -- cgit v1.2.2 From 2b8a90b55533c66258a1ff0fb27b8cffa95665c4 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 10 Jan 2011 11:15:17 +0100 Subject: drbd: Corrected off-by-one error in DRBD_MINOR_COUNT_MAX Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 4074d6699307..da98bff7c333 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -85,7 +85,8 @@ MODULE_AUTHOR("Philipp Reisner , " MODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION); MODULE_VERSION(REL_VERSION); MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (1-255)"); +MODULE_PARM_DESC(minor_count, "Maximum number of drbd devices (" + __stringify(DRBD_MINOR_COUNT_MIN) "-" __stringify(DRBD_MINOR_COUNT_MAX) ")"); MODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR); #include @@ -115,7 +116,7 @@ module_param(fault_devs, int, 0644); #endif /* module parameter, defined */ -unsigned int minor_count = 32; +unsigned int minor_count = DRBD_MINOR_COUNT_DEF; int disable_sendpage; int allow_oos; unsigned int cn_idx = CN_IDX_DRBD; @@ -3456,7 +3457,7 @@ int __init drbd_init(void) return -EINVAL; } - if (1 > minor_count || minor_count > 255) { + if (minor_count < DRBD_MINOR_COUNT_MIN || minor_count > DRBD_MINOR_COUNT_MAX) { printk(KERN_ERR "drbd: invalid minor_count (%d)\n", minor_count); #ifdef MODULE -- cgit v1.2.2 From 4a23f2649698272abcd9e0c9a992d65739f32792 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 11 Jan 2011 17:42:17 +0100 Subject: drbd: Do not full sync if a P_SYNC_UUID packet gets lost See also commit from 2009-08-15 "drbd_uuid_compare(): Do not full sync in case a P_SYNC_UUID packet gets lost." We saw cases where the History UUIDs where not as expected. So the detection of the special case did not trigger. With the sync UUID no longer being a random number, but deducible from the previous bitmap UUID, the detection of this special case becomes more reliable. The SyncUUID now is the previous bitmap UUID + 0x1000000000000. Rule 5a: Cs = H1p & H1p + Offset = Bp Connection was lost before SyncUUID Packet came through. Corrent (peer) UUIDs: Bp = H1p H1p = H2p H2p = 0 Become Sync target. Rule 7a: Cp = H1s & H1s + Offset = Bs Connection was lost before SyncUUID Packet came through. Correct (own) UUIDs: Bs = H1s H1s = H2s H2s = 0 Become Sync source. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_receiver.c | 35 +++++++++++++++++++++-------------- 3 files changed, 23 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 84b4575fdf43..3c8eecd9666d 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -97,6 +97,7 @@ extern char usermode_helper[]; #define ID_SYNCER (-1ULL) #define ID_VACANT 0 #define is_syncer_block_id(id) ((id) == ID_SYNCER) +#define UUID_NEW_BM_OFFSET ((u64)0x0001000000000000ULL) struct drbd_conf; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index da98bff7c333..b3b6d3190f65 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2022,7 +2022,7 @@ int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev) D_ASSERT(mdev->state.disk == D_UP_TO_DATE); - get_random_bytes(&uuid, sizeof(u64)); + uuid = mdev->ldev->md.uuid[UI_BITMAP] + UUID_NEW_BM_OFFSET; drbd_uuid_set(mdev, UI_BITMAP, uuid); drbd_md_sync(mdev); p.uuid = cpu_to_be64(uuid); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index fd0957f9c230..7991183749e3 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2293,6 +2293,8 @@ static void drbd_uuid_dump(struct drbd_conf *mdev, char *text, u64 *uuid, -2 C_SYNC_TARGET set BitMap -100 after split brain, disconnect -1000 unrelated data +-1091 requires proto 91 +-1096 requires proto 96 */ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(local) { @@ -2322,7 +2324,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l if (mdev->p_uuid[UI_BITMAP] == (u64)0 && mdev->ldev->md.uuid[UI_BITMAP] != (u64)0) { if (mdev->agreed_pro_version < 91) - return -1001; + return -1091; if ((mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) && (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1))) { @@ -2343,7 +2345,7 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l if (mdev->ldev->md.uuid[UI_BITMAP] == (u64)0 && mdev->p_uuid[UI_BITMAP] != (u64)0) { if (mdev->agreed_pro_version < 91) - return -1001; + return -1091; if ((mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == (mdev->p_uuid[UI_BITMAP] & ~((u64)1)) && (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1))) { @@ -2388,17 +2390,22 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l *rule_nr = 51; peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1); if (self == peer) { - self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1); - peer = mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1); - if (self == peer) { + if (mdev->agreed_pro_version < 96 ? + (mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1)) == + (mdev->p_uuid[UI_HISTORY_START + 1] & ~((u64)1)) : + peer + UUID_NEW_BM_OFFSET == (mdev->p_uuid[UI_BITMAP] & ~((u64)1))) { /* The last P_SYNC_UUID did not get though. Undo the last start of resync as sync source modifications of the peer's UUIDs. */ if (mdev->agreed_pro_version < 91) - return -1001; + return -1091; mdev->p_uuid[UI_BITMAP] = mdev->p_uuid[UI_HISTORY_START]; mdev->p_uuid[UI_HISTORY_START] = mdev->p_uuid[UI_HISTORY_START + 1]; + + dev_info(DEV, "Did not got last syncUUID packet, corrected:\n"); + drbd_uuid_dump(mdev, "peer", mdev->p_uuid, mdev->p_uuid[UI_SIZE], mdev->p_uuid[UI_FLAGS]); + return -1; } } @@ -2420,20 +2427,20 @@ static int drbd_uuid_compare(struct drbd_conf *mdev, int *rule_nr) __must_hold(l *rule_nr = 71; self = mdev->ldev->md.uuid[UI_HISTORY_START] & ~((u64)1); if (self == peer) { - self = mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1); - peer = mdev->p_uuid[UI_HISTORY_START] & ~((u64)1); - if (self == peer) { + if (mdev->agreed_pro_version < 96 ? + (mdev->ldev->md.uuid[UI_HISTORY_START + 1] & ~((u64)1)) == + (mdev->p_uuid[UI_HISTORY_START] & ~((u64)1)) : + self + UUID_NEW_BM_OFFSET == (mdev->ldev->md.uuid[UI_BITMAP] & ~((u64)1))) { /* The last P_SYNC_UUID did not get though. Undo the last start of resync as sync source modifications of our UUIDs. */ if (mdev->agreed_pro_version < 91) - return -1001; + return -1091; _drbd_uuid_set(mdev, UI_BITMAP, mdev->ldev->md.uuid[UI_HISTORY_START]); _drbd_uuid_set(mdev, UI_HISTORY_START, mdev->ldev->md.uuid[UI_HISTORY_START + 1]); - dev_info(DEV, "Undid last start of resync:\n"); - + dev_info(DEV, "Last syncUUID did not get through, corrected:\n"); drbd_uuid_dump(mdev, "self", mdev->ldev->md.uuid, mdev->state.disk >= D_NEGOTIATING ? drbd_bm_total_weight(mdev) : 0, 0); @@ -2496,8 +2503,8 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol dev_alert(DEV, "Unrelated data, aborting!\n"); return C_MASK; } - if (hg == -1001) { - dev_alert(DEV, "To resolve this both sides have to support at least protocol 91\n"); + if (hg < -1000) { + dev_alert(DEV, "To resolve this both sides have to support at least protocol %d\n", -hg - 1000); return C_MASK; } -- cgit v1.2.2 From 71c78cfba232de8f61a4b1bbb6e876424d133407 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 14 Jan 2011 19:20:34 +0100 Subject: drbd: Nothing should stop SyncSource -> Ahead transitions Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index a3f6b04ebaba..6f9d1bfcca58 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1002,7 +1002,7 @@ allocate_barrier: congested = 1; } - if (congested && atomic_read(&mdev->rs_pending_cnt) == 0) { + if (congested) { /* rs_pending_cnt must be zero, otherwise the two peers might get different bitmaps. With sane configurations the resync stalls long before we might want to go into -- cgit v1.2.2 From 370a43e7982dd497822097e0ae6022947ac2e7d4 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 14 Jan 2011 16:03:11 +0100 Subject: drbd: Work on the Ahead -> SyncSource transition The test if rs_pending_cnt == 0 was too weak. Using Test for unacked_cnt == 0 instead. Moved that into the worker. Since unacked_cnt gets already increased when an P_RS_DATA_REQ comes in. Also using a timer to make Ahead -> SyncSource -> Ahead cycles slower... Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 3 +++ drivers/block/drbd/drbd_main.c | 4 ++++ drivers/block/drbd/drbd_receiver.c | 8 +++----- drivers/block/drbd/drbd_worker.c | 16 +++++++++++++++- 4 files changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 3c8eecd9666d..cfe7fff459e3 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -850,6 +850,7 @@ enum { GOT_PING_ACK, /* set when we receive a ping_ack packet, misc wait gets woken */ NEW_CUR_UUID, /* Create new current UUID when thawing IO */ AL_SUSPENDED, /* Activity logging is currently suspended. */ + AHEAD_TO_SYNC_SOURCE, /* Ahead -> SyncSource queued */ }; struct drbd_bitmap; /* opaque for drbd_conf */ @@ -961,6 +962,7 @@ struct drbd_conf { start_resync_work; struct timer_list resync_timer; struct timer_list md_sync_timer; + struct timer_list start_resync_timer; #ifdef DRBD_DEBUG_MD_SYNC struct { unsigned int line; @@ -1544,6 +1546,7 @@ extern int w_send_oos(struct drbd_conf *, struct drbd_work *, int); extern int w_start_resync(struct drbd_conf *, struct drbd_work *, int); extern void resync_timer_fn(unsigned long data); +extern void start_resync_timer_fn(unsigned long data); /* drbd_receiver.c */ extern int drbd_rs_should_slow_down(struct drbd_conf *mdev, sector_t sector); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b3b6d3190f65..8ec7c65988be 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2984,12 +2984,16 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) mdev->go_diskless.cb = w_go_diskless; mdev->md_sync_work.cb = w_md_sync; mdev->bm_io_work.w.cb = w_bitmap_io; + mdev->start_resync_work.cb = w_start_resync; init_timer(&mdev->resync_timer); init_timer(&mdev->md_sync_timer); + init_timer(&mdev->start_resync_timer); mdev->resync_timer.function = resync_timer_fn; mdev->resync_timer.data = (unsigned long) mdev; mdev->md_sync_timer.function = md_sync_timer_fn; mdev->md_sync_timer.data = (unsigned long) mdev; + mdev->start_resync_timer.function = start_resync_timer_fn; + mdev->start_resync_timer.data = (unsigned long) mdev; init_waitqueue_head(&mdev->misc_wait); init_waitqueue_head(&mdev->state_wait); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 7991183749e3..18cb8b609fe4 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4392,11 +4392,9 @@ static int got_BarrierAck(struct drbd_conf *mdev, struct p_header80 *h) if (mdev->state.conn == C_AHEAD && atomic_read(&mdev->ap_in_flight) == 0 && - atomic_read(&mdev->rs_pending_cnt) == 0 && - list_empty(&mdev->start_resync_work.list)) { - struct drbd_work *w = &mdev->start_resync_work; - w->cb = w_start_resync; - drbd_queue_work(&mdev->data.work, w); + !test_and_set_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags)) { + mdev->start_resync_timer.expires = jiffies + HZ; + add_timer(&mdev->start_resync_timer); } return true; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 147f76b26810..3a95b701b5d0 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -712,10 +712,24 @@ static int w_make_ov_request(struct drbd_conf *mdev, struct drbd_work *w, int ca } +void start_resync_timer_fn(unsigned long data) +{ + struct drbd_conf *mdev = (struct drbd_conf *) data; + + drbd_queue_work(&mdev->data.work, &mdev->start_resync_work); +} + int w_start_resync(struct drbd_conf *mdev, struct drbd_work *w, int cancel) { - drbd_start_resync(mdev, C_SYNC_SOURCE); + if (atomic_read(&mdev->unacked_cnt) || atomic_read(&mdev->rs_pending_cnt)) { + dev_warn(DEV, "w_start_resync later...\n"); + mdev->start_resync_timer.expires = jiffies + HZ/10; + add_timer(&mdev->start_resync_timer); + return 1; + } + drbd_start_resync(mdev, C_SYNC_SOURCE); + clear_bit(AHEAD_TO_SYNC_SOURCE, &mdev->current_epoch->flags); return 1; } -- cgit v1.2.2 From 148efa165e9464927887b03c83a52c33b80b4431 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Sat, 15 Jan 2011 00:21:15 +0100 Subject: drbd: Do not drop net config if sending in drbd_send_protocol() fails Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 2 +- drivers/block/drbd/drbd_receiver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 8ec7c65988be..1061b9fff2b0 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1967,7 +1967,7 @@ int drbd_send_protocol(struct drbd_conf *mdev) else { dev_err(DEV, "--dry-run is not supported by peer"); kfree(p); - return 0; + return -1; } } p->conn_flags = cpu_to_be32(cf); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 18cb8b609fe4..fb8e86153fd0 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -906,7 +906,7 @@ retry: put_ldev(mdev); } - if (!drbd_send_protocol(mdev)) + if (drbd_send_protocol(mdev) == -1) return -1; drbd_send_sync_param(mdev, &mdev->sync_conf); drbd_send_sizes(mdev, 0, 0); -- cgit v1.2.2 From 94f2b05f03fbc605f83ae501682c85ff4535bb6d Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 17 Jan 2011 15:14:26 +0100 Subject: drbd: Killed an assert that is no longer valid The point is that drbd_disconnect() can be called with a cstate of WFConnection. That happens if the user issues "drbdsetup disconnect" while the drbd_connect() function executes. Then drbdd_init() will call drbdd(), which in turn will return without receiving any packets. Then drbdd_init() will end up calling drbd_disconnect() with a cstate of WFConnection. Bottom line: This assertion is wrong as it is, and we do not see value in fixing it. => Removing it. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index fb8e86153fd0..2207d2886f84 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3763,9 +3763,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) if (mdev->state.conn == C_STANDALONE) return; - if (mdev->state.conn >= C_WF_CONNECTION) - dev_err(DEV, "ASSERT FAILED cstate = %s, expected < WFConnection\n", - drbd_conn_str(mdev->state.conn)); /* asender does not clean up anything. it must not interfere, either */ drbd_thread_stop(&mdev->asender); -- cgit v1.2.2 From 2deb8336d04106f215c21ad1b029e78d12033d02 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 17 Jan 2011 18:39:18 +0100 Subject: drbd: Fixed P_NEG_ACK processing for protocol A and B Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. The master bio might already be completed, therefore the request is no longer in the collision hash. => Do not try to validate block_id as request In Protocol B we might already have got a P_RECV_ACK but then get a P_NEG_ACK after wards. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 45 ++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2207d2886f84..a7f5b6d134e3 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1633,9 +1633,6 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned u32 dp_flags; if (!get_ldev(mdev)) { - if (__ratelimit(&drbd_ratelimit_state)) - dev_err(DEV, "Can not write mirrored data block " - "to local disk.\n"); spin_lock(&mdev->peer_seq_lock); if (mdev->peer_seq+1 == be32_to_cpu(p->seq_num)) mdev->peer_seq++; @@ -4247,8 +4244,6 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev, return req; } } - dev_err(DEV, "_ack_id_to_req: failed to find req %p, sector %llus in list\n", - (void *)(unsigned long)id, (unsigned long long)sector); return NULL; } @@ -4266,7 +4261,9 @@ static int validate_req_change_req_state(struct drbd_conf *mdev, req = validator(mdev, id, sector); if (unlikely(!req)) { spin_unlock_irq(&mdev->req_lock); - dev_err(DEV, "%s: got a corrupt block_id/sector pair\n", func); + + dev_err(DEV, "%s: failed to find req %p, sector %llus\n", func, + (void *)(unsigned long)id, (unsigned long long)sector); return false; } __req_mod(req, what, &m); @@ -4321,20 +4318,44 @@ static int got_NegAck(struct drbd_conf *mdev, struct p_header80 *h) { struct p_block_ack *p = (struct p_block_ack *)h; sector_t sector = be64_to_cpu(p->sector); - - if (__ratelimit(&drbd_ratelimit_state)) - dev_warn(DEV, "Got NegAck packet. Peer is in troubles?\n"); + int size = be32_to_cpu(p->blksize); + struct drbd_request *req; + struct bio_and_error m; update_peer_seq(mdev, be32_to_cpu(p->seq_num)); if (is_syncer_block_id(p->block_id)) { - int size = be32_to_cpu(p->blksize); dec_rs_pending(mdev); drbd_rs_failed_io(mdev, sector, size); return true; } - return validate_req_change_req_state(mdev, p->block_id, sector, - _ack_id_to_req, __func__ , neg_acked); + + spin_lock_irq(&mdev->req_lock); + req = _ack_id_to_req(mdev, p->block_id, sector); + if (!req) { + spin_unlock_irq(&mdev->req_lock); + if (mdev->net_conf->wire_protocol == DRBD_PROT_A || + mdev->net_conf->wire_protocol == DRBD_PROT_B) { + /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. + The master bio might already be completed, therefore the + request is no longer in the collision hash. + => Do not try to validate block_id as request. */ + /* In Protocol B we might already have got a P_RECV_ACK + but then get a P_NEG_ACK after wards. */ + drbd_set_out_of_sync(mdev, sector, size); + return true; + } else { + dev_err(DEV, "%s: failed to find req %p, sector %llus\n", __func__, + (void *)(unsigned long)p->block_id, (unsigned long long)sector); + return false; + } + } + __req_mod(req, neg_acked, &m); + spin_unlock_irq(&mdev->req_lock); + + if (m.bio) + complete_master_bio(mdev, &m); + return true; } static int got_NegDReply(struct drbd_conf *mdev, struct p_header80 *h) -- cgit v1.2.2 From 6a35c45f890dc18c5527ac501b308058118f20e7 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Mon, 17 Jan 2011 20:27:30 +0100 Subject: drbd: Ensure that an epoch contains only requests of one kind The assert in drbd_req.c:755 forces us to have only requests of one kind in an epoch. The two kinds we distinguish here are: local-only or mirrored. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 7 ++++++- drivers/block/drbd/drbd_req.c | 29 ++++------------------------- drivers/block/drbd/drbd_req.h | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 1061b9fff2b0..34ee8e44a751 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1261,9 +1261,14 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) drbd_resume_al(mdev); - if (os.conn == C_AHEAD && ns.conn != C_AHEAD) + /* Start a new epoch in case we start to mirror write requests */ + if (!drbd_should_do_remote(os) && drbd_should_do_remote(ns)) tl_forget(mdev); + /* Do not add local-only requests to an epoch with mirrored requests */ + if (drbd_should_do_remote(os) && !drbd_should_do_remote(ns)) + set_bit(CREATE_BARRIER, &mdev->flags); + ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); if (ascw) { ascw->os = os; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 6f9d1bfcca58..336937a14d3f 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -762,27 +762,6 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); } -static bool drbd_should_do_remote(struct drbd_conf *mdev) -{ - union drbd_state s = mdev->state; - - return s.pdsk == D_UP_TO_DATE || - (s.pdsk >= D_INCONSISTENT && - s.conn >= C_WF_BITMAP_T && - s.conn < C_AHEAD); - /* Before proto 96 that was >= CONNECTED instead of >= C_WF_BITMAP_T. - That is equivalent since before 96 IO was frozen in the C_WF_BITMAP* - states. */ -} -static bool drbd_should_send_oos(struct drbd_conf *mdev) -{ - union drbd_state s = mdev->state; - - return s.conn == C_AHEAD || s.conn == C_WF_BITMAP_S; - /* pdsk = D_INCONSISTENT as a consequence. Protocol 96 check not necessary - since we enter state C_AHEAD only if proto >= 96 */ -} - static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) { const int rw = bio_rw(bio); @@ -854,8 +833,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, uns drbd_al_begin_io(mdev, sector); } - remote = remote && drbd_should_do_remote(mdev); - send_oos = rw == WRITE && drbd_should_send_oos(mdev); + remote = remote && drbd_should_do_remote(mdev->state); + send_oos = rw == WRITE && drbd_should_send_oos(mdev->state); D_ASSERT(!(remote && send_oos)); if (!(local || remote) && !is_susp(mdev->state)) { @@ -896,8 +875,8 @@ allocate_barrier: } if (remote || send_oos) { - remote = drbd_should_do_remote(mdev); - send_oos = rw == WRITE && drbd_should_send_oos(mdev); + remote = drbd_should_do_remote(mdev->state); + send_oos = rw == WRITE && drbd_should_send_oos(mdev->state); D_ASSERT(!(remote && send_oos)); if (!(remote || send_oos)) diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 077c47b1e9d7..32c1f2a31266 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -360,4 +360,22 @@ static inline int req_mod(struct drbd_request *req, return rv; } + +static inline bool drbd_should_do_remote(union drbd_state s) +{ + return s.pdsk == D_UP_TO_DATE || + (s.pdsk >= D_INCONSISTENT && + s.conn >= C_WF_BITMAP_T && + s.conn < C_AHEAD); + /* Before proto 96 that was >= CONNECTED instead of >= C_WF_BITMAP_T. + That is equivalent since before 96 IO was frozen in the C_WF_BITMAP* + states. */ +} +static inline bool drbd_should_send_oos(union drbd_state s) +{ + return s.conn == C_AHEAD || s.conn == C_WF_BITMAP_S; + /* pdsk = D_INCONSISTENT as a consequence. Protocol 96 check not necessary + since we enter state C_AHEAD only if proto >= 96 */ +} + #endif -- cgit v1.2.2 From 20ee639024e3d33111df0e343050b218c656bf16 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 18 Jan 2011 15:28:59 +0100 Subject: drbd: cleaned up __set_current_state() followed by schedule_timeout() calls Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 3 +-- drivers/block/drbd/drbd_receiver.c | 9 +++------ drivers/block/drbd/drbd_worker.c | 3 +-- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index a46bc0287e21..42e16e4edfa3 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -360,8 +360,7 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) if (rv == SS_TWO_PRIMARIES) { /* Maybe the peer is detected as dead very soon... retry at most once more in this case. */ - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout((mdev->net_conf->ping_timeo+1)*HZ/10); + schedule_timeout_interruptible((mdev->net_conf->ping_timeo+1)*HZ/10); if (try < max_tries) try = max_tries - 1; continue; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index a7f5b6d134e3..3ccc6c33a330 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -768,8 +768,7 @@ static int drbd_connect(struct drbd_conf *mdev) if (s || ++try >= 3) break; /* give the other side time to call bind() & listen() */ - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + schedule_timeout_interruptible(HZ / 10); } if (s) { @@ -788,8 +787,7 @@ static int drbd_connect(struct drbd_conf *mdev) } if (sock && msock) { - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + schedule_timeout_interruptible(HZ / 10); ok = drbd_socket_okay(mdev, &sock); ok = drbd_socket_okay(mdev, &msock) && ok; if (ok) @@ -4142,8 +4140,7 @@ int drbdd_init(struct drbd_thread *thi) h = drbd_connect(mdev); if (h == 0) { drbd_disconnect(mdev); - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); + schedule_timeout_interruptible(HZ); } if (h == -1) { dev_warn(DEV, "Discarding network configuration.\n"); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 3a95b701b5d0..7b3d4dc4af84 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -777,8 +777,7 @@ int drbd_resync_finished(struct drbd_conf *mdev) * queue (or even the read operations for those packets * is not finished by now). Retry in 100ms. */ - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); + schedule_timeout_interruptible(HZ / 10); w = kmalloc(sizeof(struct drbd_work), GFP_ATOMIC); if (w) { w->cb = w_resync_finished; -- cgit v1.2.2 From 6c922ed543bee1bc6685ade07be59f3fa49a7288 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Wed, 12 Jan 2011 11:51:13 +0100 Subject: drbd: only generate and send a new sync uuid after a successful state change Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 7b3d4dc4af84..ec42e04bb517 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1544,24 +1544,23 @@ void drbd_start_resync(struct drbd_conf *mdev, enum drbd_conns side) } write_unlock_irq(&global_state_lock); - if (side == C_SYNC_TARGET) - mdev->bm_resync_fo = 0; - - /* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid - * with w_send_oos, or the sync target will get confused as to - * how much bits to resync. We cannot do that always, because for an - * empty resync and protocol < 95, we need to do it here, as we call - * drbd_resync_finished from here in that case. - * We drbd_gen_and_send_sync_uuid here for protocol < 96, - * and from after_state_ch otherwise. */ - if (side == C_SYNC_SOURCE && mdev->agreed_pro_version < 96) - drbd_gen_and_send_sync_uuid(mdev); - if (r == SS_SUCCESS) { dev_info(DEV, "Began resync as %s (will sync %lu KB [%lu bits set]).\n", drbd_conn_str(ns.conn), (unsigned long) mdev->rs_total << (BM_BLOCK_SHIFT-10), (unsigned long) mdev->rs_total); + if (side == C_SYNC_TARGET) + mdev->bm_resync_fo = 0; + + /* Since protocol 96, we must serialize drbd_gen_and_send_sync_uuid + * with w_send_oos, or the sync target will get confused as to + * how much bits to resync. We cannot do that always, because for an + * empty resync and protocol < 95, we need to do it here, as we call + * drbd_resync_finished from here in that case. + * We drbd_gen_and_send_sync_uuid here for protocol < 96, + * and from after_state_ch otherwise. */ + if (side == C_SYNC_SOURCE && mdev->agreed_pro_version < 96) + drbd_gen_and_send_sync_uuid(mdev); if (mdev->agreed_pro_version < 95 && mdev->rs_total == 0) { /* This still has a race (about when exactly the peers -- cgit v1.2.2 From 194bfb32dba8345a7e0f83e9b1ee965e14d4b679 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Tue, 18 Jan 2011 10:38:01 +0100 Subject: drbd: serialize admin requests for new resync with pending bitmap io Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 42e16e4edfa3..434b621f76a9 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1873,6 +1873,10 @@ static int drbd_nl_invalidate(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl { int retcode; + /* If there is still bitmap IO pending, probably because of a previous + * resync just being finished, wait for it before requesting a new resync. */ + wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); + retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_T), CS_ORDERED); if (retcode < SS_SUCCESS && retcode != SS_NEED_CONNECTION) @@ -1908,6 +1912,10 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re { int retcode; + /* If there is still bitmap IO pending, probably because of a previous + * resync just being finished, wait for it before requesting a new resync. */ + wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); + retcode = _drbd_request_state(mdev, NS(conn, C_STARTING_SYNC_S), CS_ORDERED); if (retcode < SS_SUCCESS) { @@ -1916,7 +1924,6 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re into a full resync. */ retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT)); if (retcode >= SS_SUCCESS) { - /* open coded drbd_bitmap_io() */ if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al, "set_n_write from invalidate_peer")) retcode = ERR_IO_MD_DISK; -- cgit v1.2.2 From 54b956abef2c1ab339fd01792e69e4a921a5e487 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 20 Jan 2011 10:47:53 +0100 Subject: drbd: don't pointlessly queue bitmap send, if we lost connection This is a minor optimization and cleanup, and also considerably reduces some harmless (but noisy) race with the connection cleanup code. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 34ee8e44a751..1caced08a73e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1428,8 +1428,13 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, drbd_send_uuids(mdev); drbd_send_state(mdev); } - if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S) - drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, "send_bitmap (WFBitMapS)"); + /* No point in queuing send_bitmap if we don't have a connection + * anymore, so check also the _current_ state, not only the new state + * at the time this work was queued. */ + if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S && + mdev->state.conn == C_WF_BITMAP_S) + drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, + "send_bitmap (WFBitMapS)"); /* Lost contact to peer's copy of the data */ if ((os.pdsk >= D_INCONSISTENT && -- cgit v1.2.2 From 79a30d2d71f7be862de93228fe9b919ef664af52 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 20 Jan 2011 10:32:05 +0100 Subject: drbd: queue bitmap writeout more intelligently The "lazy writeout" of cleared bitmap pages happens during resync, and should happen again once the resync finishes cleanly, or is aborted. If resync finished cleanly, or was aborted because of peer disk failure, we trigger the writeout from worker context in the after state change work. If resync was aborted because of connection failure, we should not immediately trigger bitmap writeout, but rather postpone the writeout to after the connection cleanup happened. We now do it in the receiver context from drbd_disconnect(). If resync was aborted because of local disk failure, well, there is nothing to write to anymore. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 12 +++++++++++- drivers/block/drbd/drbd_receiver.c | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 1caced08a73e..e0be4077d564 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1593,8 +1593,18 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (os.disk < D_UP_TO_DATE && os.conn >= C_SYNC_SOURCE && ns.conn == C_CONNECTED) drbd_send_state(mdev); - if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED) + /* This triggers bitmap writeout of potentially still unwritten pages + * if the resync finished cleanly, or aborted because of peer disk + * failure. Resync aborted because of connection failure does bitmap + * writeout from drbd_disconnect. + * For resync aborted because of local disk failure, we cannot do + * any bitmap writeout anymore. + */ + if (os.conn > C_CONNECTED && ns.conn == C_CONNECTED && + mdev->state.conn == C_CONNECTED && get_ldev(mdev)) { drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); + put_ldev(mdev); + } /* free tl_hash if we Got thawed and are C_STANDALONE */ if (ns.conn == C_STANDALONE && !is_susp(ns) && mdev->tl_hash) diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 3ccc6c33a330..432fe8f6b5d2 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3811,6 +3811,7 @@ static void drbd_disconnect(struct drbd_conf *mdev) fp = FP_DONT_CARE; if (get_ldev(mdev)) { + drbd_bitmap_io(mdev, &drbd_bm_write, "write from disconnect"); fp = mdev->ldev->dc.fencing; put_ldev(mdev); } -- cgit v1.2.2 From cd88d030d41a9b0100fd5fee872024e6ebc8b276 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 20 Jan 2011 11:46:41 +0100 Subject: drbd: Provide hints with the error message when clearing the sync pause flag When the user clears the sync-pause flag, and sync stays in pause state, give hints to the user, why it still is in pause state. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 434b621f76a9..ffe3a97fef9b 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1952,9 +1952,17 @@ static int drbd_nl_resume_sync(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n struct drbd_nl_cfg_reply *reply) { int retcode = NO_ERROR; + union drbd_state s; - if (drbd_request_state(mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO) - retcode = ERR_PAUSE_IS_CLEAR; + if (drbd_request_state(mdev, NS(user_isp, 0)) == SS_NOTHING_TO_DO) { + s = mdev->state; + if (s.conn == C_PAUSED_SYNC_S || s.conn == C_PAUSED_SYNC_T) { + retcode = s.aftr_isp ? ERR_PIC_AFTER_DEP : + s.peer_isp ? ERR_PIC_PEER_DEP : ERR_PAUSE_IS_CLEAR; + } else { + retcode = ERR_PAUSE_IS_CLEAR; + } + } reply->ret_code = retcode; return 0; -- cgit v1.2.2 From d07c9c10e5620c632aae9cac2b609033398f6139 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Thu, 20 Jan 2011 16:49:33 +0100 Subject: drbd: We can not process BIOs with a size of 0 Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 432fe8f6b5d2..e9354931eace 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1237,6 +1237,7 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ data_size -= dgs; + ERR_IF(data_size == 0) return NULL; ERR_IF(data_size & 0x1ff) return NULL; ERR_IF(data_size > DRBD_MAX_BIO_SIZE) return NULL; -- cgit v1.2.2 From 62b0da3a244ac33d25a77861ef1cc0080103f2ff Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Thu, 20 Jan 2011 13:25:21 +0100 Subject: drbd: log UUIDs whenever they change All decisions about sync, sync direction, and wether or not to allow a connect or attach are based on our set of UUIDs to tag a data generation. Log changes to the UUIDs whenever they occur, logging "new current UUID P:Q:R:S" is more useful than "Creating new current UUID". Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 6 ++-- drivers/block/drbd/drbd_main.c | 71 ++++++++++++++++++-------------------- drivers/block/drbd/drbd_nl.c | 1 + drivers/block/drbd/drbd_receiver.c | 11 ++++-- drivers/block/drbd/drbd_worker.c | 20 ++++++----- 5 files changed, 58 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index cfe7fff459e3..0a9059eb94db 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -1240,11 +1240,11 @@ extern int _drbd_send_bitmap(struct drbd_conf *mdev); extern int drbd_send_sr_reply(struct drbd_conf *mdev, enum drbd_state_rv retcode); extern void drbd_free_bc(struct drbd_backing_dev *ldev); extern void drbd_mdev_cleanup(struct drbd_conf *mdev); +void drbd_print_uuids(struct drbd_conf *mdev, const char *text); /* drbd_meta-data.c (still in drbd_main.c) */ extern void drbd_md_sync(struct drbd_conf *mdev); extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); -/* maybe define them below as inline? */ extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); extern void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); extern void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local); @@ -2360,9 +2360,11 @@ static inline void dec_ap_bio(struct drbd_conf *mdev) } } -static inline void drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val) +static inline int drbd_set_ed_uuid(struct drbd_conf *mdev, u64 val) { + int changed = mdev->ed_uuid != val; mdev->ed_uuid = val; + return changed; } static inline int seq_cmp(u32 a, u32 b) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index e0be4077d564..b68332a0e73e 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1159,6 +1159,10 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, atomic_inc(&mdev->local_cnt); mdev->state = ns; + + if (os.disk == D_ATTACHING && ns.disk >= D_NEGOTIATING) + drbd_print_uuids(mdev, "attached to UUIDs"); + wake_up(&mdev->misc_wait); wake_up(&mdev->state_wait); @@ -2035,6 +2039,24 @@ int drbd_send_uuids_skip_initial_sync(struct drbd_conf *mdev) return _drbd_send_uuids(mdev, 8); } +void drbd_print_uuids(struct drbd_conf *mdev, const char *text) +{ + if (get_ldev_if_state(mdev, D_NEGOTIATING)) { + u64 *uuid = mdev->ldev->md.uuid; + dev_info(DEV, "%s %016llX:%016llX:%016llX:%016llX\n", + text, + (unsigned long long)uuid[UI_CURRENT], + (unsigned long long)uuid[UI_BITMAP], + (unsigned long long)uuid[UI_HISTORY_START], + (unsigned long long)uuid[UI_HISTORY_END]); + put_ldev(mdev); + } else { + dev_info(DEV, "%s effective data uuid: %016llX\n", + text, + (unsigned long long)mdev->ed_uuid); + } +} + int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev) { struct p_rs_uuid p; @@ -2044,6 +2066,7 @@ int drbd_gen_and_send_sync_uuid(struct drbd_conf *mdev) uuid = mdev->ldev->md.uuid[UI_BITMAP] + UUID_NEW_BM_OFFSET; drbd_uuid_set(mdev, UI_BITMAP, uuid); + drbd_print_uuids(mdev, "updated sync UUID"); drbd_md_sync(mdev); p.uuid = cpu_to_be64(uuid); @@ -3749,28 +3772,6 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) return rv; } -static void debug_drbd_uuid(struct drbd_conf *mdev, enum drbd_uuid_index index) -{ - static char *uuid_str[UI_EXTENDED_SIZE] = { - [UI_CURRENT] = "CURRENT", - [UI_BITMAP] = "BITMAP", - [UI_HISTORY_START] = "HISTORY_START", - [UI_HISTORY_END] = "HISTORY_END", - [UI_SIZE] = "SIZE", - [UI_FLAGS] = "FLAGS", - }; - - if (index >= UI_EXTENDED_SIZE) { - dev_warn(DEV, " uuid_index >= EXTENDED_SIZE\n"); - return; - } - - dynamic_dev_dbg(DEV, " uuid[%s] now %016llX\n", - uuid_str[index], - (unsigned long long)mdev->ldev->md.uuid[index]); -} - - /** * drbd_md_mark_dirty() - Mark meta data super block as dirty * @mdev: DRBD device. @@ -3800,10 +3801,8 @@ static void drbd_uuid_move_history(struct drbd_conf *mdev) __must_hold(local) { int i; - for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) { + for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) mdev->ldev->md.uuid[i+1] = mdev->ldev->md.uuid[i]; - debug_drbd_uuid(mdev, i+1); - } } void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) @@ -3818,7 +3817,6 @@ void _drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) } mdev->ldev->md.uuid[idx] = val; - debug_drbd_uuid(mdev, idx); drbd_md_mark_dirty(mdev); } @@ -3828,7 +3826,6 @@ void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) if (mdev->ldev->md.uuid[idx]) { drbd_uuid_move_history(mdev); mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[idx]; - debug_drbd_uuid(mdev, UI_HISTORY_START); } _drbd_uuid_set(mdev, idx, val); } @@ -3843,14 +3840,16 @@ void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local) void drbd_uuid_new_current(struct drbd_conf *mdev) __must_hold(local) { u64 val; + unsigned long long bm_uuid = mdev->ldev->md.uuid[UI_BITMAP]; + + if (bm_uuid) + dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid); - dev_info(DEV, "Creating new current UUID\n"); - D_ASSERT(mdev->ldev->md.uuid[UI_BITMAP] == 0); mdev->ldev->md.uuid[UI_BITMAP] = mdev->ldev->md.uuid[UI_CURRENT]; - debug_drbd_uuid(mdev, UI_BITMAP); get_random_bytes(&val, sizeof(u64)); _drbd_uuid_set(mdev, UI_CURRENT, val); + drbd_print_uuids(mdev, "new current UUID"); /* get it to stable storage _now_ */ drbd_md_sync(mdev); } @@ -3864,16 +3863,12 @@ void drbd_uuid_set_bm(struct drbd_conf *mdev, u64 val) __must_hold(local) drbd_uuid_move_history(mdev); mdev->ldev->md.uuid[UI_HISTORY_START] = mdev->ldev->md.uuid[UI_BITMAP]; mdev->ldev->md.uuid[UI_BITMAP] = 0; - debug_drbd_uuid(mdev, UI_HISTORY_START); - debug_drbd_uuid(mdev, UI_BITMAP); } else { - if (mdev->ldev->md.uuid[UI_BITMAP]) - dev_warn(DEV, "bm UUID already set"); - - mdev->ldev->md.uuid[UI_BITMAP] = val; - mdev->ldev->md.uuid[UI_BITMAP] &= ~((u64)1); + unsigned long long bm_uuid = mdev->ldev->md.uuid[UI_BITMAP]; + if (bm_uuid) + dev_warn(DEV, "bm UUID was already set: %llX\n", bm_uuid); - debug_drbd_uuid(mdev, UI_BITMAP); + mdev->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1); } drbd_md_mark_dirty(mdev); } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index ffe3a97fef9b..ce6f2fe80852 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2151,6 +2151,7 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl if (skip_initial_sync) { drbd_send_uuids_skip_initial_sync(mdev); _drbd_uuid_set(mdev, UI_BITMAP, 0); + drbd_print_uuids(mdev, "cleared bitmap UUID"); spin_lock_irq(&mdev->req_lock); _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), CS_VERBOSE, NULL); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e9354931eace..e5686a81f42c 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -3024,7 +3024,7 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned { struct p_uuids *p = &mdev->data.rbuf.uuids; u64 *p_uuid; - int i; + int i, updated_uuids = 0; p_uuid = kmalloc(sizeof(u64)*UI_EXTENDED_SIZE, GFP_NOIO); @@ -3059,13 +3059,14 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), CS_VERBOSE, NULL); drbd_md_sync(mdev); + updated_uuids = 1; } put_ldev(mdev); } else if (mdev->state.disk < D_INCONSISTENT && mdev->state.role == R_PRIMARY) { /* I am a diskless primary, the peer just created a new current UUID for me. */ - drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); + updated_uuids = drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); } /* Before we test for the disk state, we should wait until an eventually @@ -3074,7 +3075,10 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned new disk state... */ wait_event(mdev->misc_wait, !test_bit(CLUSTER_ST_CHANGE, &mdev->flags)); if (mdev->state.conn >= C_CONNECTED && mdev->state.disk < D_INCONSISTENT) - drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); + updated_uuids |= drbd_set_ed_uuid(mdev, p_uuid[UI_CURRENT]); + + if (updated_uuids) + drbd_print_uuids(mdev, "receiver updated UUIDs to"); return true; } @@ -3305,6 +3309,7 @@ static int receive_sync_uuid(struct drbd_conf *mdev, enum drbd_packets cmd, unsi _drbd_uuid_set(mdev, UI_CURRENT, be64_to_cpu(p->uuid)); _drbd_uuid_set(mdev, UI_BITMAP, 0UL); + drbd_print_uuids(mdev, "updated sync uuid"); drbd_start_resync(mdev, C_SYNC_TARGET); put_ldev(mdev); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index ec42e04bb517..ff0eb308ee4a 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -871,14 +871,18 @@ int drbd_resync_finished(struct drbd_conf *mdev) } } - drbd_uuid_set_bm(mdev, 0UL); - - if (mdev->p_uuid) { - /* Now the two UUID sets are equal, update what we - * know of the peer. */ - int i; - for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++) - mdev->p_uuid[i] = mdev->ldev->md.uuid[i]; + if (!(os.conn == C_VERIFY_S || os.conn == C_VERIFY_T)) { + /* for verify runs, we don't update uuids here, + * so there would be nothing to report. */ + drbd_uuid_set_bm(mdev, 0UL); + drbd_print_uuids(mdev, "updated UUIDs"); + if (mdev->p_uuid) { + /* Now the two UUID sets are equal, update what we + * know of the peer. */ + int i; + for (i = UI_CURRENT ; i <= UI_HISTORY_END ; i++) + mdev->p_uuid[i] = mdev->ldev->md.uuid[i]; + } } } -- cgit v1.2.2 From 20ceb2b22edaf51e59e76087efdc71a16a2858de Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 21 Jan 2011 10:56:44 +0100 Subject: drbd: describe bitmap locking for bulk operation in finer detail Now that we do no longer in-place endian-swap the bitmap, we allow selected bitmap operations (testing bits, sometimes even settting bits) during some bulk operations. This caused us to hit a lot of FIXME asserts similar to FIXME asender in drbd_bm_count_bits, bitmap locked for 'write from resync_finished' by worker Which now is nonsense: looking at the bitmap is perfectly legal as long as it is not being resized. This cosmetic patch defines some flags to describe expectations in finer detail, so the asserts in e.g. bm_change_bits_to() can be skipped if appropriate. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_bitmap.c | 48 +++++++++++++------------------ drivers/block/drbd/drbd_int.h | 36 ++++++++++++++++++++--- drivers/block/drbd/drbd_main.c | 58 +++++++++++++++++++++++++------------- drivers/block/drbd/drbd_nl.c | 19 +++++++++---- drivers/block/drbd/drbd_receiver.c | 17 +++++++---- 5 files changed, 115 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 25428bc28476..b62dd5f26c5d 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -104,26 +104,16 @@ struct drbd_bitmap { wait_queue_head_t bm_io_wait; /* used to serialize IO of single pages */ - unsigned long bm_flags; + enum bm_flag bm_flags; /* debugging aid, in case we are still racy somewhere */ char *bm_why; struct task_struct *bm_task; }; -/* definition of bits in bm_flags */ -#define BM_LOCKED 0 -// #define BM_MD_IO_ERROR 1 unused now. -#define BM_P_VMALLOCED 2 - static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, unsigned long e, int val, const enum km_type km); -static int bm_is_locked(struct drbd_bitmap *b) -{ - return test_bit(BM_LOCKED, &b->bm_flags); -} - #define bm_print_lock_info(m) __bm_print_lock_info(m, __func__) static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) { @@ -140,7 +130,7 @@ static void __bm_print_lock_info(struct drbd_conf *mdev, const char *func) b->bm_task == mdev->worker.task ? "worker" : "?"); } -void drbd_bm_lock(struct drbd_conf *mdev, char *why) +void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags) { struct drbd_bitmap *b = mdev->bitmap; int trylock_failed; @@ -163,8 +153,9 @@ void drbd_bm_lock(struct drbd_conf *mdev, char *why) b->bm_task == mdev->worker.task ? "worker" : "?"); mutex_lock(&b->bm_change); } - if (__test_and_set_bit(BM_LOCKED, &b->bm_flags)) + if (BM_LOCKED_MASK & b->bm_flags) dev_err(DEV, "FIXME bitmap already locked in bm_lock\n"); + b->bm_flags |= flags & BM_LOCKED_MASK; b->bm_why = why; b->bm_task = current; @@ -178,9 +169,10 @@ void drbd_bm_unlock(struct drbd_conf *mdev) return; } - if (!__test_and_clear_bit(BM_LOCKED, &mdev->bitmap->bm_flags)) + if (!(BM_LOCKED_MASK & mdev->bitmap->bm_flags)) dev_err(DEV, "FIXME bitmap not locked in bm_unlock\n"); + b->bm_flags &= ~BM_LOCKED_MASK; b->bm_why = NULL; b->bm_task = NULL; mutex_unlock(&b->bm_change); @@ -421,9 +413,9 @@ static struct page **bm_realloc_pages(struct drbd_bitmap *b, unsigned long want) } if (vmalloced) - set_bit(BM_P_VMALLOCED, &b->bm_flags); + b->bm_flags |= BM_P_VMALLOCED; else - clear_bit(BM_P_VMALLOCED, &b->bm_flags); + b->bm_flags &= ~BM_P_VMALLOCED; return new_pages; } @@ -460,7 +452,7 @@ void drbd_bm_cleanup(struct drbd_conf *mdev) { ERR_IF (!mdev->bitmap) return; bm_free_pages(mdev->bitmap->bm_pages, mdev->bitmap->bm_number_of_pages); - bm_vk_free(mdev->bitmap->bm_pages, test_bit(BM_P_VMALLOCED, &mdev->bitmap->bm_flags)); + bm_vk_free(mdev->bitmap->bm_pages, (BM_P_VMALLOCED & mdev->bitmap->bm_flags)); kfree(mdev->bitmap); mdev->bitmap = NULL; } @@ -623,7 +615,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) ERR_IF(!b) return -ENOMEM; - drbd_bm_lock(mdev, "resize"); + drbd_bm_lock(mdev, "resize", BM_LOCKED_MASK); dev_info(DEV, "drbd_bm_resize called with capacity == %llu\n", (unsigned long long)capacity); @@ -631,7 +623,7 @@ int drbd_bm_resize(struct drbd_conf *mdev, sector_t capacity, int set_new_bits) if (capacity == b->bm_dev_capacity) goto out; - opages_vmalloced = test_bit(BM_P_VMALLOCED, &b->bm_flags); + opages_vmalloced = (BM_P_VMALLOCED & b->bm_flags); if (capacity == 0) { spin_lock_irq(&b->bm_lock); @@ -1030,7 +1022,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id * as we submit copies of pages anyways. */ if (!ctx.flags) - WARN_ON(!bm_is_locked(b)); + WARN_ON(!(BM_LOCKED_MASK & b->bm_flags)); num_pages = b->bm_number_of_pages; @@ -1220,7 +1212,7 @@ static unsigned long bm_find_next(struct drbd_conf *mdev, ERR_IF(!b->bm_pages) return i; spin_lock_irq(&b->bm_lock); - if (bm_is_locked(b)) + if (BM_DONT_TEST & b->bm_flags) bm_print_lock_info(mdev); i = __bm_find_next(mdev, bm_fo, find_zero_bit, KM_IRQ1); @@ -1246,13 +1238,13 @@ unsigned long drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo * you must take drbd_bm_lock() first */ unsigned long _drbd_bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo) { - /* WARN_ON(!bm_is_locked(mdev)); */ + /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */ return __bm_find_next(mdev, bm_fo, 0, KM_USER1); } unsigned long _drbd_bm_find_next_zero(struct drbd_conf *mdev, unsigned long bm_fo) { - /* WARN_ON(!bm_is_locked(mdev)); */ + /* WARN_ON(!(BM_DONT_SET & mdev->b->bm_flags)); */ return __bm_find_next(mdev, bm_fo, 1, KM_USER1); } @@ -1322,7 +1314,7 @@ static int bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, ERR_IF(!b->bm_pages) return 0; spin_lock_irqsave(&b->bm_lock, flags); - if (bm_is_locked(b)) + if ((val ? BM_DONT_SET : BM_DONT_CLEAR) & b->bm_flags) bm_print_lock_info(mdev); c = __bm_change_bits_to(mdev, s, e, val, KM_IRQ1); @@ -1439,7 +1431,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) ERR_IF(!b->bm_pages) return 0; spin_lock_irqsave(&b->bm_lock, flags); - if (bm_is_locked(b)) + if (BM_DONT_TEST & b->bm_flags) bm_print_lock_info(mdev); if (bitnr < b->bm_bits) { p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr)); @@ -1474,7 +1466,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi ERR_IF(!b->bm_pages) return 1; spin_lock_irqsave(&b->bm_lock, flags); - if (bm_is_locked(b)) + if (BM_DONT_TEST & b->bm_flags) bm_print_lock_info(mdev); for (bitnr = s; bitnr <= e; bitnr++) { unsigned int idx = bm_bit_to_page_idx(b, bitnr); @@ -1522,7 +1514,7 @@ int drbd_bm_e_weight(struct drbd_conf *mdev, unsigned long enr) ERR_IF(!b->bm_pages) return 0; spin_lock_irqsave(&b->bm_lock, flags); - if (bm_is_locked(b)) + if (BM_DONT_TEST & b->bm_flags) bm_print_lock_info(mdev); s = S2W(enr); @@ -1555,7 +1547,7 @@ unsigned long drbd_bm_ALe_set_all(struct drbd_conf *mdev, unsigned long al_enr) ERR_IF(!b->bm_pages) return 0; spin_lock_irq(&b->bm_lock); - if (bm_is_locked(b)) + if (BM_DONT_SET & b->bm_flags) bm_print_lock_info(mdev); weight = b->bm_set; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 0a9059eb94db..267d9897ca8c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -855,6 +855,32 @@ enum { struct drbd_bitmap; /* opaque for drbd_conf */ +/* definition of bits in bm_flags to be used in drbd_bm_lock + * and drbd_bitmap_io and friends. */ +enum bm_flag { + /* do we need to kfree, or vfree bm_pages? */ + BM_P_VMALLOCED = 0x10000, /* internal use only, will be masked out */ + + /* currently locked for bulk operation */ + BM_LOCKED_MASK = 0x7, + + /* in detail, that is: */ + BM_DONT_CLEAR = 0x1, + BM_DONT_SET = 0x2, + BM_DONT_TEST = 0x4, + + /* (test bit, count bit) allowed (common case) */ + BM_LOCKED_TEST_ALLOWED = 0x3, + + /* testing bits, as well as setting new bits allowed, but clearing bits + * would be unexpected. Used during bitmap receive. Setting new bits + * requires sending of "out-of-sync" information, though. */ + BM_LOCKED_SET_ALLOWED = 0x1, + + /* clear is not expected while bitmap is locked for bulk operation */ +}; + + /* TODO sort members for performance * MAYBE group them further */ @@ -920,6 +946,7 @@ struct drbd_md_io { struct bm_io_work { struct drbd_work w; char *why; + enum bm_flag flags; int (*io_fn)(struct drbd_conf *mdev); void (*done)(struct drbd_conf *mdev, int rv); }; @@ -1242,7 +1269,6 @@ extern void drbd_free_bc(struct drbd_backing_dev *ldev); extern void drbd_mdev_cleanup(struct drbd_conf *mdev); void drbd_print_uuids(struct drbd_conf *mdev, const char *text); -/* drbd_meta-data.c (still in drbd_main.c) */ extern void drbd_md_sync(struct drbd_conf *mdev); extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); @@ -1263,10 +1289,12 @@ extern void drbd_md_mark_dirty_(struct drbd_conf *mdev, extern void drbd_queue_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), void (*done)(struct drbd_conf *, int), - char *why); + char *why, enum bm_flag flags); +extern int drbd_bitmap_io(struct drbd_conf *mdev, + int (*io_fn)(struct drbd_conf *), + char *why, enum bm_flag flags); extern int drbd_bmio_set_n_write(struct drbd_conf *mdev); extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev); -extern int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why); extern void drbd_go_diskless(struct drbd_conf *mdev); extern void drbd_ldev_destroy(struct drbd_conf *mdev); @@ -1452,7 +1480,7 @@ extern void drbd_bm_merge_lel(struct drbd_conf *mdev, size_t offset, extern void drbd_bm_get_lel(struct drbd_conf *mdev, size_t offset, size_t number, unsigned long *buffer); -extern void drbd_bm_lock(struct drbd_conf *mdev, char *why); +extern void drbd_bm_lock(struct drbd_conf *mdev, char *why, enum bm_flag flags); extern void drbd_bm_unlock(struct drbd_conf *mdev); /* drbd_main.c */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index b68332a0e73e..a9e9b496e73b 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1320,7 +1320,9 @@ static void abw_start_sync(struct drbd_conf *mdev, int rv) } } -int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why) +int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, + int (*io_fn)(struct drbd_conf *), + char *why, enum bm_flag flags) { int rv; @@ -1328,10 +1330,8 @@ int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, int (*io_fn)(struct drbd_ /* open coded non-blocking drbd_suspend_io(mdev); */ set_bit(SUSPEND_IO, &mdev->flags); - if (!is_susp(mdev->state)) - D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0); - drbd_bm_lock(mdev, why); + drbd_bm_lock(mdev, why, flags); rv = io_fn(mdev); drbd_bm_unlock(mdev); @@ -1438,7 +1438,8 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S && mdev->state.conn == C_WF_BITMAP_S) drbd_queue_bitmap_io(mdev, &drbd_send_bitmap, NULL, - "send_bitmap (WFBitMapS)"); + "send_bitmap (WFBitMapS)", + BM_LOCKED_TEST_ALLOWED); /* Lost contact to peer's copy of the data */ if ((os.pdsk >= D_INCONSISTENT && @@ -1469,7 +1470,11 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* D_DISKLESS Peer becomes secondary */ if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY) - drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, "demote diskless peer"); + /* We may still be Primary ourselves. + * No harm done if the bitmap still changes, + * redirtied pages will follow later. */ + drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, + "demote diskless peer", BM_LOCKED_SET_ALLOWED); put_ldev(mdev); } @@ -1478,7 +1483,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, * if there is a resync going on still */ if (os.role == R_PRIMARY && ns.role == R_SECONDARY && mdev->state.conn <= C_CONNECTED && get_ldev(mdev)) { - drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, "demote"); + /* No changes to the bitmap expected this time, so assert that, + * even though no harm was done if it did change. */ + drbd_bitmap_io_from_worker(mdev, &drbd_bm_write, + "demote", BM_LOCKED_TEST_ALLOWED); put_ldev(mdev); } @@ -1512,12 +1520,17 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* We are in the progress to start a full sync... */ if ((os.conn != C_STARTING_SYNC_T && ns.conn == C_STARTING_SYNC_T) || (os.conn != C_STARTING_SYNC_S && ns.conn == C_STARTING_SYNC_S)) - drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, &abw_start_sync, "set_n_write from StartingSync"); + /* no other bitmap changes expected during this phase */ + drbd_queue_bitmap_io(mdev, + &drbd_bmio_set_n_write, &abw_start_sync, + "set_n_write from StartingSync", BM_LOCKED_TEST_ALLOWED); /* We are invalidating our self... */ if (os.conn < C_CONNECTED && ns.conn < C_CONNECTED && os.disk > D_INCONSISTENT && ns.disk == D_INCONSISTENT) - drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, "set_n_write from invalidate"); + /* other bitmap operation expected during this phase */ + drbd_queue_bitmap_io(mdev, &drbd_bmio_set_n_write, NULL, + "set_n_write from invalidate", BM_LOCKED_MASK); /* first half of local IO error, failure to attach, * or administrative detach */ @@ -1599,14 +1612,14 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, /* This triggers bitmap writeout of potentially still unwritten pages * if the resync finished cleanly, or aborted because of peer disk - * failure. Resync aborted because of connection failure does bitmap - * writeout from drbd_disconnect. + * failure, or because of connection loss. * For resync aborted because of local disk failure, we cannot do * any bitmap writeout anymore. + * No harm done if some bits change during this phase. */ - if (os.conn > C_CONNECTED && ns.conn == C_CONNECTED && - mdev->state.conn == C_CONNECTED && get_ldev(mdev)) { - drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, "write from resync_finished"); + if (os.conn > C_CONNECTED && ns.conn <= C_CONNECTED && get_ldev(mdev)) { + drbd_queue_bitmap_io(mdev, &drbd_bm_write, NULL, + "write from resync_finished", BM_LOCKED_SET_ALLOWED); put_ldev(mdev); } @@ -3929,7 +3942,7 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) D_ASSERT(atomic_read(&mdev->ap_bio_cnt) == 0); if (get_ldev(mdev)) { - drbd_bm_lock(mdev, work->why); + drbd_bm_lock(mdev, work->why, work->flags); rv = work->io_fn(mdev); drbd_bm_unlock(mdev); put_ldev(mdev); @@ -3944,6 +3957,7 @@ static int w_bitmap_io(struct drbd_conf *mdev, struct drbd_work *w, int unused) clear_bit(BITMAP_IO_QUEUED, &mdev->flags); work->why = NULL; + work->flags = 0; return 1; } @@ -3998,7 +4012,7 @@ void drbd_go_diskless(struct drbd_conf *mdev) void drbd_queue_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), void (*done)(struct drbd_conf *, int), - char *why) + char *why, enum bm_flag flags) { D_ASSERT(current == mdev->worker.task); @@ -4012,6 +4026,7 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, mdev->bm_io_work.io_fn = io_fn; mdev->bm_io_work.done = done; mdev->bm_io_work.why = why; + mdev->bm_io_work.flags = flags; spin_lock_irq(&mdev->req_lock); set_bit(BITMAP_IO, &mdev->flags); @@ -4031,19 +4046,22 @@ void drbd_queue_bitmap_io(struct drbd_conf *mdev, * freezes application IO while that the actual IO operations runs. This * functions MAY NOT be called from worker context. */ -int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), char *why) +int drbd_bitmap_io(struct drbd_conf *mdev, int (*io_fn)(struct drbd_conf *), + char *why, enum bm_flag flags) { int rv; D_ASSERT(current != mdev->worker.task); - drbd_suspend_io(mdev); + if ((flags & BM_LOCKED_SET_ALLOWED) == 0) + drbd_suspend_io(mdev); - drbd_bm_lock(mdev, why); + drbd_bm_lock(mdev, why, flags); rv = io_fn(mdev); drbd_bm_unlock(mdev); - drbd_resume_io(mdev); + if ((flags & BM_LOCKED_SET_ALLOWED) == 0) + drbd_resume_io(mdev); return rv; } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index ce6f2fe80852..bc0bcb964603 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -648,7 +648,9 @@ enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, enum dds_ dev_info(DEV, "Writing the whole bitmap, %s\n", la_size_changed && md_moved ? "size changed and md moved" : la_size_changed ? "size changed" : "md moved"); - err = drbd_bitmap_io(mdev, &drbd_bm_write, "size changed"); /* does drbd_resume_io() ! */ + /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */ + err = drbd_bitmap_io(mdev, &drbd_bm_write, + "size changed", BM_LOCKED_MASK); if (err) { rv = dev_size_error; goto out; @@ -1160,12 +1162,14 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (drbd_md_test_flag(mdev->ldev, MDF_FULL_SYNC)) { dev_info(DEV, "Assuming that all blocks are out of sync " "(aka FullSync)\n"); - if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from attaching")) { + if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, + "set_n_write from attaching", BM_LOCKED_MASK)) { retcode = ERR_IO_MD_DISK; goto force_diskless_dec; } } else { - if (drbd_bitmap_io(mdev, &drbd_bm_read, "read from attaching") < 0) { + if (drbd_bitmap_io(mdev, &drbd_bm_read, + "read from attaching", BM_LOCKED_MASK) < 0) { retcode = ERR_IO_MD_DISK; goto force_diskless_dec; } @@ -1173,7 +1177,8 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp if (cp_discovered) { drbd_al_apply_to_bm(mdev); - if (drbd_bitmap_io(mdev, &drbd_bm_write, "crashed primary apply AL")) { + if (drbd_bitmap_io(mdev, &drbd_bm_write, + "crashed primary apply AL", BM_LOCKED_MASK)) { retcode = ERR_IO_MD_DISK; goto force_diskless_dec; } @@ -1925,7 +1930,8 @@ static int drbd_nl_invalidate_peer(struct drbd_conf *mdev, struct drbd_nl_cfg_re retcode = drbd_request_state(mdev, NS(pdsk, D_INCONSISTENT)); if (retcode >= SS_SUCCESS) { if (drbd_bitmap_io(mdev, &drbd_bmio_set_susp_al, - "set_n_write from invalidate_peer")) + "set_n_write from invalidate_peer", + BM_LOCKED_SET_ALLOWED)) retcode = ERR_IO_MD_DISK; } } else @@ -2143,7 +2149,8 @@ static int drbd_nl_new_c_uuid(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl drbd_uuid_new_current(mdev); /* New current, previous to UI_BITMAP */ if (args.clear_bm) { - err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, "clear_n_write from new_c_uuid"); + err = drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, + "clear_n_write from new_c_uuid", BM_LOCKED_MASK); if (err) { dev_err(DEV, "Writing bitmap failed with %d\n",err); retcode = ERR_IO_MD_DISK; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e5686a81f42c..e13134f83fae 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -2599,7 +2599,8 @@ static enum drbd_conns drbd_sync_handshake(struct drbd_conf *mdev, enum drbd_rol if (abs(hg) >= 2) { dev_info(DEV, "Writing the whole bitmap, full sync required after drbd_sync_handshake.\n"); - if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake")) + if (drbd_bitmap_io(mdev, &drbd_bmio_set_n_write, "set_n_write from sync_handshake", + BM_LOCKED_SET_ALLOWED)) return C_MASK; } @@ -3053,7 +3054,8 @@ static int receive_uuids(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (skip_initial_sync) { dev_info(DEV, "Accepted new current UUID, preparing to skip initial sync\n"); drbd_bitmap_io(mdev, &drbd_bmio_clear_n_write, - "clear_n_write from receive_uuids"); + "clear_n_write from receive_uuids", + BM_LOCKED_TEST_ALLOWED); _drbd_uuid_set(mdev, UI_CURRENT, p_uuid[UI_CURRENT]); _drbd_uuid_set(mdev, UI_BITMAP, 0); _drbd_set_state(_NS2(mdev, disk, D_UP_TO_DATE, pdsk, D_UP_TO_DATE), @@ -3494,7 +3496,9 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne int ok = false; struct p_header80 *h = &mdev->data.rbuf.header.h80; - /* drbd_bm_lock(mdev, "receive bitmap"); By intention no bm_lock */ + drbd_bm_lock(mdev, "receive bitmap", BM_LOCKED_SET_ALLOWED); + /* you are supposed to send additional out-of-sync information + * if you actually set bits during this phase */ /* maybe we should use some per thread scratch page, * and allocate that during initial device creation? */ @@ -3568,7 +3572,7 @@ static int receive_bitmap(struct drbd_conf *mdev, enum drbd_packets cmd, unsigne ok = true; out: - /* drbd_bm_unlock(mdev); by intention no lock */ + drbd_bm_unlock(mdev); if (ok && mdev->state.conn == C_WF_BITMAP_S) drbd_start_resync(mdev, C_SYNC_SOURCE); free_page((unsigned long) buffer); @@ -3817,7 +3821,6 @@ static void drbd_disconnect(struct drbd_conf *mdev) fp = FP_DONT_CARE; if (get_ldev(mdev)) { - drbd_bitmap_io(mdev, &drbd_bm_write, "write from disconnect"); fp = mdev->ldev->dc.fencing; put_ldev(mdev); } @@ -3846,6 +3849,10 @@ static void drbd_disconnect(struct drbd_conf *mdev) drbd_request_state(mdev, NS(conn, C_STANDALONE)); } + /* serialize with bitmap writeout triggered by the state change, + * if any. */ + wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); + /* tcp_close and release of sendpage pages can be deferred. I don't * want to use SO_LINGER, because apparently it can be deferred for * more than 20 seconds (longest time I checked). -- cgit v1.2.2 From 0ddc5549f88dfc4a4c919693e9a86095e89e080b Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 21 Jan 2011 12:35:15 +0100 Subject: drbd: silence some noisy log messages during disconnect If we fail to send the information that we lost our disk, we have no connection, and no disk: no access to data anymore. That is either expected (deconfiguration), or there will be so much noise in the logs that "Sending state failed" is not useful at all. Drop it. If the reason for a shorter than expected receive was a signal, which we sent because we already decided to disconnect, these additional log messages are confusing and useless. This patch follows this pattern: - dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); + if (!signal_pending(current)) + dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); Also make them all dev_warn for consistency. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 6 ++--- drivers/block/drbd/drbd_receiver.c | 45 ++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index a9e9b496e73b..c3760f33d52c 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1585,8 +1585,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (drbd_send_state(mdev)) dev_warn(DEV, "Notified peer that I'm now diskless.\n"); - else - dev_err(DEV, "Sending state for being diskless failed\n"); /* corresponding get_ldev in __drbd_set_state * this may finaly trigger drbd_ldev_destroy. */ put_ldev(mdev); @@ -1868,8 +1866,8 @@ int _drbd_send_cmd(struct drbd_conf *mdev, struct socket *sock, sent = drbd_send(mdev, sock, h, size, msg_flags); ok = (sent == size); - if (!ok) - dev_err(DEV, "short sent %s size=%d sent=%d\n", + if (!ok && !signal_pending(current)) + dev_warn(DEV, "short sent %s size=%d sent=%d\n", cmdname(cmd), (int)size, sent); return ok; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index e13134f83fae..a56b107e01eb 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -930,7 +930,8 @@ static int drbd_recv_header(struct drbd_conf *mdev, enum drbd_packets *cmd, unsi r = drbd_recv(mdev, h, sizeof(*h)); if (unlikely(r != sizeof(*h))) { - dev_err(DEV, "short read expecting header on sock: r=%d\n", r); + if (!signal_pending(current)) + dev_warn(DEV, "short read expecting header on sock: r=%d\n", r); return false; } @@ -1229,8 +1230,10 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ if (dgs) { rr = drbd_recv(mdev, dig_in, dgs); if (rr != dgs) { - dev_warn(DEV, "short read receiving data digest: read %d expected %d\n", - rr, dgs); + if (!signal_pending(current)) + dev_warn(DEV, + "short read receiving data digest: read %d expected %d\n", + rr, dgs); return NULL; } } @@ -1270,8 +1273,9 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ kunmap(page); if (rr != len) { drbd_free_ee(mdev, e); - dev_warn(DEV, "short read receiving data: read %d expected %d\n", - rr, len); + if (!signal_pending(current)) + dev_warn(DEV, "short read receiving data: read %d expected %d\n", + rr, len); return NULL; } ds -= rr; @@ -1311,8 +1315,10 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) rr = drbd_recv(mdev, data, min_t(int, data_size, PAGE_SIZE)); if (rr != min_t(int, data_size, PAGE_SIZE)) { rv = 0; - dev_warn(DEV, "short read receiving data: read %d expected %d\n", - rr, min_t(int, data_size, PAGE_SIZE)); + if (!signal_pending(current)) + dev_warn(DEV, + "short read receiving data: read %d expected %d\n", + rr, min_t(int, data_size, PAGE_SIZE)); break; } data_size -= rr; @@ -1337,8 +1343,10 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, if (dgs) { rr = drbd_recv(mdev, dig_in, dgs); if (rr != dgs) { - dev_warn(DEV, "short read receiving data reply digest: read %d expected %d\n", - rr, dgs); + if (!signal_pending(current)) + dev_warn(DEV, + "short read receiving data reply digest: read %d expected %d\n", + rr, dgs); return 0; } } @@ -1359,9 +1367,10 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, expect); kunmap(bvec->bv_page); if (rr != expect) { - dev_warn(DEV, "short read receiving data reply: " - "read %d expected %d\n", - rr, expect); + if (!signal_pending(current)) + dev_warn(DEV, "short read receiving data reply: " + "read %d expected %d\n", + rr, expect); return 0; } data_size -= rr; @@ -3696,7 +3705,8 @@ static void drbdd(struct drbd_conf *mdev) 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); + if (!signal_pending(current)) + dev_warn(DEV, "short read while reading sub header: rv=%d\n", rv); goto err_out; } } @@ -3953,7 +3963,8 @@ static int drbd_do_handshake(struct drbd_conf *mdev) rv = drbd_recv(mdev, &p->head.payload, expect); if (rv != expect) { - dev_err(DEV, "short read receiving handshake packet: l=%u\n", rv); + if (!signal_pending(current)) + dev_warn(DEV, "short read receiving handshake packet: l=%u\n", rv); return 0; } @@ -4055,7 +4066,8 @@ static int drbd_do_auth(struct drbd_conf *mdev) rv = drbd_recv(mdev, peers_ch, length); if (rv != length) { - dev_err(DEV, "short read AuthChallenge: l=%u\n", rv); + if (!signal_pending(current)) + dev_warn(DEV, "short read AuthChallenge: l=%u\n", rv); rv = 0; goto fail; } @@ -4102,7 +4114,8 @@ static int drbd_do_auth(struct drbd_conf *mdev) rv = drbd_recv(mdev, response , resp_size); if (rv != resp_size) { - dev_err(DEV, "short read receiving AuthResponse: l=%u\n", rv); + if (!signal_pending(current)) + dev_warn(DEV, "short read receiving AuthResponse: l=%u\n", rv); rv = 0; goto fail; } -- cgit v1.2.2 From e636db5b956950b8b9bfbeb766a637f84bae1e3b Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 21 Jan 2011 17:10:37 +0100 Subject: drbd: fix potential imbalance of ap_in_flight When we receive a barrier ack, we walk the ring list of drbd requests in the transfer log of the respective epoch, do some housekeeping, and free those objects. We tried to keep epochs of mirrored and unmirrored drbd requests separate, and assert that no local-only requests are present in a barrier_acked epoch. It turns out that this has quite a number of corner cases and would add bloated code without functional benefit. We now revert the (insufficient) commits drbd: Fixed an issue with AHEAD -> SYNC_SOURCE transitions drbd: Ensure that an epoch contains only requests of one kind and instead fix the processing of barrier acks to cope with a mix of local-only and mirrored requests. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_main.c | 25 ------------------------- drivers/block/drbd/drbd_req.c | 9 +++++---- 2 files changed, 5 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index c3760f33d52c..9043772de400 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -337,23 +337,6 @@ bail: } -/* In C_AHEAD mode only out_of_sync packets are sent for requests. Detach - * those requests from the newsest barrier when changing to an other cstate. - * - * That headless list vanishes when the last request finished its write or - * send out_of_sync packet. */ -static void tl_forget(struct drbd_conf *mdev) -{ - struct drbd_tl_epoch *b; - - if (test_bit(CREATE_BARRIER, &mdev->flags)) - return; - - b = mdev->newest_tle; - list_del(&b->requests); - _tl_add_barrier(mdev, b); -} - /** * _tl_restart() - Walks the transfer log, and applies an action to all requests * @mdev: DRBD device. @@ -1265,14 +1248,6 @@ __drbd_set_state(struct drbd_conf *mdev, union drbd_state ns, if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) drbd_resume_al(mdev); - /* Start a new epoch in case we start to mirror write requests */ - if (!drbd_should_do_remote(os) && drbd_should_do_remote(ns)) - tl_forget(mdev); - - /* Do not add local-only requests to an epoch with mirrored requests */ - if (drbd_should_do_remote(os) && !drbd_should_do_remote(ns)) - set_bit(CREATE_BARRIER, &mdev->flags); - ascw = kmalloc(sizeof(*ascw), GFP_ATOMIC); if (ascw) { ascw->os = os; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 336937a14d3f..c28be4e5e57c 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -712,10 +712,11 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, dev_err(DEV, "FIXME (barrier_acked but pending)\n"); list_move(&req->tl_requests, &mdev->out_of_sequence_requests); } - D_ASSERT(req->rq_state & RQ_NET_SENT); - req->rq_state |= RQ_NET_DONE; - if (mdev->net_conf->wire_protocol == DRBD_PROT_A) - atomic_sub(req->size>>9, &mdev->ap_in_flight); + if ((req->rq_state & RQ_NET_MASK) != 0) { + req->rq_state |= RQ_NET_DONE; + if (mdev->net_conf->wire_protocol == DRBD_PROT_A) + atomic_sub(req->size>>9, &mdev->ap_in_flight); + } _req_may_be_done(req, m); /* Allowed while state.susp */ break; -- cgit v1.2.2 From 873b0d5f98ab70e4df7a62b2ef0305373f88f330 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Fri, 21 Jan 2011 22:53:48 +0100 Subject: drbd: serialize admin requests for new verify run with pending bitmap io This is an addendum to drbd: serialize admin requests for new resync with pending bitmap io It avoids a race that could trigger "FIXME" assert log messages. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_nl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index bc0bcb964603..87aaa7fc4d27 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -2106,6 +2106,11 @@ static int drbd_nl_start_ov(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, reply->ret_code = ERR_MANDATORY_TAG; return 0; } + + /* If there is still bitmap IO pending, e.g. previous resync or verify + * just being finished, wait for it before requesting a new resync. */ + wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); + /* w_make_ov_request expects position to be aligned */ mdev->ov_start_sector = args.start_sector & ~BM_SECT_PER_BIT; reply->ret_code = drbd_request_state(mdev,NS(conn,C_VERIFY_S)); -- cgit v1.2.2 From 039312b6481e2928f3be19fee94c83327d93e4c7 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Fri, 21 Jan 2011 14:13:22 +0100 Subject: drbd: Removed left over, now wrong comments Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index c28be4e5e57c..94fd5a2be559 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -983,13 +983,7 @@ allocate_barrier: } if (congested) { - /* rs_pending_cnt must be zero, otherwise the two peers - might get different bitmaps. With sane configurations - the resync stalls long before we might want to go into - AHEAD mode. - We could force the resync into PAUSE mode here if - rs_pending_cnt is > 0 ... */ - queue_barrier(mdev); + queue_barrier(mdev); /* last barrier, after mirrored writes */ if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL); -- cgit v1.2.2 From 10f6d9926cd17afff9dc03c967706419798b4929 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 24 Jan 2011 14:47:09 +0100 Subject: drbd: don't BUG_ON, if bio_add_page of a single page to an empty bio fails Just deal with it more gracefully, if we fail to add even a single page to an empty bio. We used to BUG_ON() there, but it has been observed in some Xen deployment, so we need to handle that case more robustly now. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 45 +++++++++++++++++++++++++------------- drivers/block/drbd/drbd_worker.c | 7 +++--- 2 files changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index a56b107e01eb..9e9fc3413137 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1073,6 +1073,16 @@ void drbd_bump_write_ordering(struct drbd_conf *mdev, enum write_ordering_e wo) * @mdev: DRBD device. * @e: epoch entry * @rw: flag field, see bio->bi_rw + * + * May spread the pages to multiple bios, + * depending on bio_add_page restrictions. + * + * Returns 0 if all bios have been submitted, + * -ENOMEM if we could not allocate enough bios, + * -ENOSPC (any better suggestion?) if we have not been able to bio_add_page a + * single page to an empty bio (which should never happen and likely indicates + * that the lower level IO stack is in some way broken). This has been observed + * on certain Xen deployments. */ /* TODO allocate from our own bio_set. */ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, @@ -1085,6 +1095,7 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, unsigned ds = e->size; unsigned n_bios = 0; unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT; + int err = -ENOMEM; /* In most cases, we will only need one bio. But in case the lower * level restrictions happen to be different at this offset on this @@ -1110,8 +1121,17 @@ next_bio: page_chain_for_each(page) { unsigned len = min_t(unsigned, ds, PAGE_SIZE); if (!bio_add_page(bio, page, len, 0)) { - /* a single page must always be possible! */ - BUG_ON(bio->bi_vcnt == 0); + /* A single page must always be possible! + * But in case it fails anyways, + * we deal with it, and complain (below). */ + if (bio->bi_vcnt == 0) { + dev_err(DEV, + "bio_add_page failed for len=%u, " + "bi_vcnt=0 (bi_sector=%llu)\n", + len, (unsigned long long)bio->bi_sector); + err = -ENOSPC; + goto fail; + } goto next_bio; } ds -= len; @@ -1137,7 +1157,7 @@ fail: bios = bios->bi_next; bio_put(bio); } - return -ENOMEM; + return err; } static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned int data_size) @@ -1436,9 +1456,8 @@ static int recv_resync_read(struct drbd_conf *mdev, sector_t sector, int data_si if (drbd_submit_ee(mdev, e, WRITE, DRBD_FAULT_RS_WR) == 0) return true; - /* drbd_submit_ee currently fails for one reason only: - * not being able to allocate enough bios. - * Is dropping the connection going to help? */ + /* don't care for the reason here */ + dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->req_lock); list_del(&e->w.list); spin_unlock_irq(&mdev->req_lock); @@ -1837,9 +1856,8 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned if (drbd_submit_ee(mdev, e, rw, DRBD_FAULT_DT_WR) == 0) return true; - /* drbd_submit_ee currently fails for one reason only: - * not being able to allocate enough bios. - * Is dropping the connection going to help? */ + /* don't care for the reason here */ + dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->req_lock); list_del(&e->w.list); hlist_del_init(&e->colision); @@ -1848,9 +1866,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned drbd_al_complete_io(mdev, e->sector); out_interrupted: - /* yes, the epoch_size now is imbalanced. - * but we drop the connection anyways, so we don't have a chance to - * receive a barrier... atomic_inc(&mdev->epoch_size); */ + drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + EV_CLEANUP); put_ldev(mdev); drbd_free_ee(mdev, e); return false; @@ -2096,9 +2112,8 @@ submit: if (drbd_submit_ee(mdev, e, READ, fault_type) == 0) return true; - /* drbd_submit_ee currently fails for one reason only: - * not being able to allocate enough bios. - * Is dropping the connection going to help? */ + /* don't care for the reason here */ + dev_err(DEV, "submit failed, triggering re-connect\n"); spin_lock_irq(&mdev->req_lock); list_del(&e->w.list); spin_unlock_irq(&mdev->req_lock); diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index ff0eb308ee4a..cfd324b9f95b 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -369,9 +369,10 @@ static int read_for_csum(struct drbd_conf *mdev, sector_t sector, int size) if (drbd_submit_ee(mdev, e, READ, DRBD_FAULT_RS_RD) == 0) return 0; - /* drbd_submit_ee currently fails for one reason only: - * not being able to allocate enough bios. - * Is dropping the connection going to help? */ + /* If it failed because of ENOMEM, retry should help. If it failed + * because bio_add_page failed (probably broken lower level driver), + * retry may or may not help. + * If it does not, you may need to force disconnect. */ spin_lock_irq(&mdev->req_lock); list_del(&e->w.list); spin_unlock_irq(&mdev->req_lock); -- cgit v1.2.2 From e99dc367b3aafb1ce2d5d92e94834d07b299e1d7 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 24 Jan 2011 14:58:39 +0100 Subject: drbd: kill dead code This code became obsolete and unused last December with drbd: bitmap keep track of changes vs on-disk bitmap Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 93 ---------------------------------------- 1 file changed, 93 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 090fc2ce0df4..a6050791401b 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -569,99 +569,6 @@ static void atodb_endio(struct bio *bio, int error) put_ldev(mdev); } -/* sector to word */ -#define S2W(s) ((s)<<(BM_EXT_SHIFT-BM_BLOCK_SHIFT-LN2_BPL)) - -/* activity log to on disk bitmap -- prepare bio unless that sector - * is already covered by previously prepared bios */ -static int atodb_prepare_unless_covered(struct drbd_conf *mdev, - struct bio **bios, - unsigned int enr, - struct drbd_atodb_wait *wc) __must_hold(local) -{ - struct bio *bio; - struct page *page; - sector_t on_disk_sector; - unsigned int page_offset = PAGE_SIZE; - int offset; - int i = 0; - int err = -ENOMEM; - - /* We always write aligned, full 4k blocks, - * so we can ignore the logical_block_size (for now) */ - enr &= ~7U; - on_disk_sector = enr + mdev->ldev->md.md_offset - + mdev->ldev->md.bm_offset; - - D_ASSERT(!(on_disk_sector & 7U)); - - /* Check if that enr is already covered by an already created bio. - * Caution, bios[] is not NULL terminated, - * but only initialized to all NULL. - * For completely scattered activity log, - * the last invocation iterates over all bios, - * and finds the last NULL entry. - */ - while ((bio = bios[i])) { - if (bio->bi_sector == on_disk_sector) - return 0; - i++; - } - /* bios[i] == NULL, the next not yet used slot */ - - /* GFP_KERNEL, we are not in the write-out path */ - bio = bio_alloc(GFP_KERNEL, 1); - if (bio == NULL) - return -ENOMEM; - - if (i > 0) { - const struct bio_vec *prev_bv = bios[i-1]->bi_io_vec; - page_offset = prev_bv->bv_offset + prev_bv->bv_len; - page = prev_bv->bv_page; - } - if (page_offset == PAGE_SIZE) { - page = alloc_page(__GFP_HIGHMEM); - if (page == NULL) - goto out_bio_put; - page_offset = 0; - } else { - get_page(page); - } - - offset = S2W(enr); - drbd_bm_get_lel(mdev, offset, - min_t(size_t, S2W(8), drbd_bm_words(mdev) - offset), - kmap(page) + page_offset); - kunmap(page); - - bio->bi_private = wc; - bio->bi_end_io = atodb_endio; - bio->bi_bdev = mdev->ldev->md_bdev; - bio->bi_sector = on_disk_sector; - - if (bio_add_page(bio, page, 4096, page_offset) != 4096) - goto out_put_page; - - atomic_inc(&wc->count); - /* we already know that we may do this... - * get_ldev_if_state(mdev,D_ATTACHING); - * just get the extra reference, so that the local_cnt reflects - * the number of pending IO requests DRBD at its backing device. - */ - atomic_inc(&mdev->local_cnt); - - bios[i] = bio; - - return 0; - -out_put_page: - err = -EINVAL; - put_page(page); -out_bio_put: - bio_put(bio); - return err; -} - /** * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents * @mdev: DRBD device. -- cgit v1.2.2 From fdda6544ad4d3284246e717b7108f7f497b45295 Mon Sep 17 00:00:00 2001 From: Lars Ellenberg Date: Mon, 24 Jan 2011 15:11:01 +0100 Subject: drbd: improve log message if received sector offset exceeds local capacity Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_receiver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 9e9fc3413137..3d62ac7cdc4a 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1267,7 +1267,8 @@ read_in_block(struct drbd_conf *mdev, u64 id, sector_t sector, int data_size) __ /* even though we trust out peer, * we sometimes have to double check. */ if (sector + (data_size>>9) > capacity) { - dev_err(DEV, "capacity: %llus < sector: %llus + size: %u\n", + dev_err(DEV, "request from peer beyond end of local disk: " + "capacity: %llus < sector: %llus + size: %u\n", (unsigned long long)capacity, (unsigned long long)sector, data_size); return NULL; -- cgit v1.2.2 From c5a91619793d444e5103ec5841045bf878718398 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Tue, 25 Jan 2011 17:33:38 +0100 Subject: drbd: Remove unused function atodb_endio() Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_actlog.c | 27 --------------------------- drivers/block/drbd/drbd_worker.c | 15 ++++++--------- 2 files changed, 6 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index a6050791401b..2a1642bc451d 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -542,33 +542,6 @@ cancel: return 1; } -static void atodb_endio(struct bio *bio, int error) -{ - struct drbd_atodb_wait *wc = bio->bi_private; - struct drbd_conf *mdev = wc->mdev; - struct page *page; - int uptodate = bio_flagged(bio, BIO_UPTODATE); - - /* strange behavior of some lower level drivers... - * fail the request by clearing the uptodate flag, - * but do not return any error?! */ - if (!error && !uptodate) - error = -EIO; - - drbd_chk_io_error(mdev, error, true); - if (error && wc->error == 0) - wc->error = error; - - if (atomic_dec_and_test(&wc->count)) - complete(&wc->io_done); - - page = bio->bi_io_vec[0].bv_page; - put_page(page); - bio_put(bio); - mdev->bm_writ_cnt++; - put_ldev(mdev); -} - /** * drbd_al_apply_to_bm() - Sets the bitmap to diry(1) where covered ba active AL extents * @mdev: DRBD device. diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index cfd324b9f95b..3d70d8d015d9 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -44,15 +44,12 @@ static int w_make_resync_request(struct drbd_conf *mdev, -/* defined here: - drbd_md_io_complete - drbd_endio_sec - drbd_endio_pri - - * more endio handlers: - atodb_endio in drbd_actlog.c - drbd_bm_async_io_complete in drbd_bitmap.c - +/* endio handlers: + * drbd_md_io_complete (defined here) + * drbd_endio_pri (defined here) + * drbd_endio_sec (defined here) + * bm_async_io_complete (defined in drbd_bitmap.c) + * * For all these callbacks, note the following: * The callbacks will be called in irq context by the IDE drivers, * and in Softirqs/Tasklets/BH context by the SCSI drivers. -- cgit v1.2.2 From 7fde2be93080c028c20078a2d6abec8a95891192 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 1 Mar 2011 11:08:28 +0100 Subject: drbd: Implemented real timeout checking for request processing time Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_int.h | 1 + drivers/block/drbd/drbd_main.c | 3 +++ drivers/block/drbd/drbd_receiver.c | 3 +++ drivers/block/drbd/drbd_req.c | 39 ++++++++++++++++++++++++++++++++++++++ drivers/block/drbd/drbd_req.h | 1 + 5 files changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 267d9897ca8c..81030d8d654b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -990,6 +990,7 @@ struct drbd_conf { struct timer_list resync_timer; struct timer_list md_sync_timer; struct timer_list start_resync_timer; + struct timer_list request_timer; #ifdef DRBD_DEBUG_MD_SYNC struct { unsigned int line; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9043772de400..dfc85f32d317 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -3017,12 +3017,15 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) init_timer(&mdev->resync_timer); init_timer(&mdev->md_sync_timer); init_timer(&mdev->start_resync_timer); + init_timer(&mdev->request_timer); mdev->resync_timer.function = resync_timer_fn; mdev->resync_timer.data = (unsigned long) mdev; mdev->md_sync_timer.function = md_sync_timer_fn; mdev->md_sync_timer.data = (unsigned long) mdev; mdev->start_resync_timer.function = start_resync_timer_fn; mdev->start_resync_timer.data = (unsigned long) mdev; + mdev->request_timer.function = request_timer_fn; + mdev->request_timer.data = (unsigned long) mdev; init_waitqueue_head(&mdev->misc_wait); init_waitqueue_head(&mdev->state_wait); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 3d62ac7cdc4a..fe1564c7d8b6 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -912,6 +912,7 @@ retry: drbd_send_state(mdev); clear_bit(USE_DEGR_WFC_T, &mdev->flags); clear_bit(RESIZE_PENDING, &mdev->flags); + mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */ return 1; @@ -3822,6 +3823,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) atomic_set(&mdev->rs_pending_cnt, 0); wake_up(&mdev->misc_wait); + del_timer(&mdev->request_timer); + /* make sure syncer is stopped and w_resume_next_sg queued */ del_timer_sync(&mdev->resync_timer); resync_timer_fn((unsigned long)mdev); diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 94fd5a2be559..c2cc28a55907 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1194,3 +1194,42 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct } return limit; } + +void request_timer_fn(unsigned long data) +{ + struct drbd_conf *mdev = (struct drbd_conf *) data; + struct drbd_request *req; /* oldest request */ + struct list_head *le; + unsigned long et = 0; /* effective timeout = ko_count * timeout */ + + if (get_net_conf(mdev)) { + et = mdev->net_conf->timeout*HZ/10 * mdev->net_conf->ko_count; + put_net_conf(mdev); + } + if (!et || mdev->state.conn < C_WF_REPORT_PARAMS) + return; /* Recurring timer stopped */ + + spin_lock_irq(&mdev->req_lock); + le = &mdev->oldest_tle->requests; + if (list_empty(le)) { + spin_unlock_irq(&mdev->req_lock); + mod_timer(&mdev->request_timer, jiffies + et); + return; + } + + le = le->prev; + req = list_entry(le, struct drbd_request, tl_requests); + if (time_is_before_eq_jiffies(req->start_time + et)) { + if (req->rq_state & RQ_NET_PENDING) { + dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n"); + _drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE, NULL); + } else { + dev_warn(DEV, "Local backing block device frozen?\n"); + mod_timer(&mdev->request_timer, jiffies + et); + } + } else { + mod_timer(&mdev->request_timer, req->start_time + et); + } + + spin_unlock_irq(&mdev->req_lock); +} diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 32c1f2a31266..32e2c3e6a813 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -322,6 +322,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what, struct bio_and_error *m); extern void complete_master_bio(struct drbd_conf *mdev, struct bio_and_error *m); +extern void request_timer_fn(unsigned long data); /* use this if you don't want to deal with calling complete_master_bio() * outside the spinlock, e.g. when walking some list on cleanup. */ -- cgit v1.2.2 From 8f21420ebd5ca5a751e2f606b49b0acd2a2af314 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Tue, 1 Mar 2011 15:52:35 +0100 Subject: drbd: Fixed handling of read errors on a 'VerifyT' node Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 3d70d8d015d9..7db29080f363 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1081,25 +1081,27 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) if (unlikely(cancel)) goto out; - if (unlikely((e->flags & EE_WAS_ERROR) != 0)) - goto out; - digest_size = crypto_hash_digestsize(mdev->verify_tfm); - /* FIXME if this allocation fails, online verify will not terminate! */ digest = kmalloc(digest_size, GFP_NOIO); - if (digest) { - drbd_csum_ee(mdev, mdev->verify_tfm, e, digest); - inc_rs_pending(mdev); - ok = drbd_send_drequest_csum(mdev, e->sector, e->size, - digest, digest_size, P_OV_REPLY); - if (!ok) - dec_rs_pending(mdev); - kfree(digest); + if (!digest) { + ok = 0; /* terminate the connection in case the allocation failed */ + goto out; } + if (likely(!(e->flags & EE_WAS_ERROR))) + drbd_csum_ee(mdev, mdev->verify_tfm, e, digest); + else + memset(digest, 0, digest_size); + + inc_rs_pending(mdev); + ok = drbd_send_drequest_csum(mdev, e->sector, e->size, + digest, digest_size, P_OV_REPLY); + if (!ok) + dec_rs_pending(mdev); + kfree(digest); + out: drbd_free_ee(mdev, e); - dec_unacked(mdev); return ok; -- cgit v1.2.2 From 7961243b7bdd62d72b47eb2c0bee776c51a8a8e2 Mon Sep 17 00:00:00 2001 From: Philipp Reisner Date: Wed, 2 Mar 2011 23:14:44 +0100 Subject: drbd: Fixed handling of read errors on a 'VerifyS' node Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_worker.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 7db29080f363..f7e6c92f8d03 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -1151,10 +1151,6 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) eq = !memcmp(digest, di->digest, digest_size); kfree(digest); } - } else { - ok = drbd_send_ack(mdev, P_NEG_RS_DREPLY, e); - if (__ratelimit(&drbd_ratelimit_state)) - dev_err(DEV, "Sending NegDReply. I guess it gets messy.\n"); } dec_unacked(mdev); -- cgit v1.2.2 From 03567812d81dd87a810b2bd1e804f4001de03da5 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Thu, 13 Jan 2011 10:43:40 +0100 Subject: drbd: drop code present under #ifdef which is relevant to 2.6.28 and below Signed-off-by: Or Gerlitz Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- drivers/block/drbd/drbd_req.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index c2cc28a55907..5c0c8be1bb0a 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -1127,11 +1127,7 @@ int drbd_make_request(struct request_queue *q, struct bio *bio) const int sps = 1 << HT_SHIFT; /* sectors per slot */ const int mask = sps - 1; const sector_t first_sectors = sps - (sect & mask); - bp = bio_split(bio, -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - bio_split_pool, -#endif - first_sectors); + bp = bio_split(bio, first_sectors); /* we need to get a "reference count" (ap_bio_cnt) * to avoid races with the disconnect/reconnect/suspend code. -- cgit v1.2.2 From 8ba775ca0d375ab42404ffd7a1a38326a7b21321 Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Mon, 24 Jan 2011 06:21:48 +0000 Subject: OMAP2, 3: DSS2: remove forced clk-disable from omap_dss_remove As part of omap hwmod changes, DSS will not be the only controller of its clocks. hwmod initialization also enables the interface clocks, and manages them. So, when DSS is built as a module, omap_dss_remove doesn't try to disable all clocks that have a higher usecount. Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 46 +++++++----------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 8e89f6049280..ee56859c52ce 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -623,7 +623,6 @@ static int omap_dss_remove(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; int i; - int c; dss_uninitialize_debugfs(); @@ -638,44 +637,13 @@ static int omap_dss_remove(struct platform_device *pdev) dss_exit(); - /* these should be removed at some point */ - c = core.dss_ick->usecount; - if (c > 0) { - DSSERR("warning: dss_ick usecount %d, disabling\n", c); - while (c-- > 0) - clk_disable(core.dss_ick); - } - - c = core.dss1_fck->usecount; - if (c > 0) { - DSSERR("warning: dss1_fck usecount %d, disabling\n", c); - while (c-- > 0) - clk_disable(core.dss1_fck); - } - - c = core.dss2_fck->usecount; - if (c > 0) { - DSSERR("warning: dss2_fck usecount %d, disabling\n", c); - while (c-- > 0) - clk_disable(core.dss2_fck); - } - - c = core.dss_54m_fck->usecount; - if (c > 0) { - DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c); - while (c-- > 0) - clk_disable(core.dss_54m_fck); - } - - if (core.dss_96m_fck) { - c = core.dss_96m_fck->usecount; - if (c > 0) { - DSSERR("warning: dss_96m_fck usecount %d, disabling\n", - c); - while (c-- > 0) - clk_disable(core.dss_96m_fck); - } - } + /* + * As part of hwmod changes, DSS is not the only controller of dss + * clocks; hwmod framework itself will also enable clocks during hwmod + * init for dss, and autoidle is set in h/w for DSS. Hence, there's no + * need to disable clocks if their usecounts > 1. + */ + WARN_ON(core.num_clks_enabled > 0); dss_put_clocks(); -- cgit v1.2.2 From 96c401bcb83a182a4f332f2f64ee6530ba35511a Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Mon, 24 Jan 2011 06:21:57 +0000 Subject: OMAP2, 3: DSS2: DSS: create platform_driver, move init, exit to driver Hwmod adaptation design requires each of the DSS HW IP to be a platform driver. So a platform_driver of DSS is created and init exit methods are moved from core.c to its driver probe,remove. pdev member has to be maintained by its own drivers. DSS platform driver is registered from inside omap_dss_probe, in the order desired. Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 19 +++++++-------- drivers/video/omap2/dss/dss.c | 55 ++++++++++++++++++++++++++++++++++++++++-- drivers/video/omap2/dss/dss.h | 4 +-- 3 files changed, 64 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index ee56859c52ce..e399ca22e514 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -517,15 +517,9 @@ static int omap_dss_probe(struct platform_device *pdev) core.ctx_id = dss_get_ctx_id(); DSSDBG("initial ctx id %u\n", core.ctx_id); -#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT - /* DISPC_CONTROL */ - if (omap_readl(0x48050440) & 1) /* LCD enabled? */ - skip_init = 1; -#endif - - r = dss_init(skip_init); + r = dss_init_platform_driver(); if (r) { - DSSERR("Failed to initialize DSS\n"); + DSSERR("Failed to initialize DSS platform driver\n"); goto err_dss; } @@ -553,6 +547,11 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_venc; } +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + /* DISPC_CONTROL */ + if (omap_readl(0x48050440) & 1) /* LCD enabled? */ + skip_init = 1; +#endif if (cpu_is_omap34xx()) { r = sdi_init(skip_init); if (r) { @@ -610,7 +609,7 @@ err_dispc: err_dpi: rfbi_exit(); err_rfbi: - dss_exit(); + dss_uninit_platform_driver(); err_dss: dss_clk_disable_all_no_ctx(); dss_put_clocks(); @@ -635,7 +634,7 @@ static int omap_dss_remove(struct platform_device *pdev) sdi_exit(); } - dss_exit(); + dss_uninit_platform_driver(); /* * As part of hwmod changes, DSS is not the only controller of dss diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 77c3621c9171..01406f48f438 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -59,6 +59,7 @@ struct dss_reg { dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) static struct { + struct platform_device *pdev; void __iomem *base; struct clk *dpll4_m4_ck; @@ -549,7 +550,7 @@ void dss_set_dac_pwrdn_bgz(bool enable) REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } -int dss_init(bool skip_init) +static int dss_init(bool skip_init) { int r; u32 rev; @@ -629,7 +630,7 @@ fail0: return r; } -void dss_exit(void) +static void dss_exit(void) { if (cpu_is_omap34xx()) clk_put(dss.dpll4_m4_ck); @@ -639,3 +640,53 @@ void dss_exit(void) iounmap(dss.base); } +/* DSS HW IP initialisation */ +static int omap_dsshw_probe(struct platform_device *pdev) +{ + int r; + int skip_init = 0; + + dss.pdev = pdev; + +#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT + /* DISPC_CONTROL */ + if (omap_readl(0x48050440) & 1) /* LCD enabled? */ + skip_init = 1; +#endif + + r = dss_init(skip_init); + if (r) { + DSSERR("Failed to initialize DSS\n"); + goto err_dss; + } + +err_dss: + + return r; +} + +static int omap_dsshw_remove(struct platform_device *pdev) +{ + dss_exit(); + + return 0; +} + +static struct platform_driver omap_dsshw_driver = { + .probe = omap_dsshw_probe, + .remove = omap_dsshw_remove, + .driver = { + .name = "omapdss_dss", + .owner = THIS_MODULE, + }, +}; + +int dss_init_platform_driver(void) +{ + return platform_driver_register(&omap_dsshw_driver); +} + +void dss_uninit_platform_driver(void) +{ + return platform_driver_unregister(&omap_dsshw_driver); +} diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index b394951120ac..37c4544e8907 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -214,8 +214,8 @@ void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr); void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); /* DSS */ -int dss_init(bool skip_init); -void dss_exit(void); +int dss_init_platform_driver(void); +void dss_uninit_platform_driver(void); void dss_save_context(void); void dss_restore_context(void); -- cgit v1.2.2 From 8b9cb3a8f39d0864c925c5cd5c2c54cfd85ad551 Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Mon, 24 Jan 2011 06:21:58 +0000 Subject: OMAP2, 3: DSS2: Move clocks from core driver to dss driver All clock management is moved to dss platform driver. clk_get/put APIs use dss device instead of core platform device. Hwmod adaptation design requires each of the DSS HW IP to be a platform driver. So the device name is changed from omapdss to omapdss_dss in 2420, 2430, 3xxx clock database files. Now the core driver "omapdss" only takes care of panel registration with the custom bus. core driver also uses the clk_enable() / clk_disable() APIs exposed by DSS for clock management. DSS driver would do clock management of clocks needed by DISPC, RFBI, DSI, VENC TODO: The clock content would be adapted to omap_hwmod in a seperate series. Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 343 +---------------------------------------- drivers/video/omap2/dss/dss.c | 334 ++++++++++++++++++++++++++++++++++++++- drivers/video/omap2/dss/dss.h | 13 +- 3 files changed, 345 insertions(+), 345 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index e399ca22e514..255935541d0d 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -34,32 +34,18 @@ #include #include -#include #include "dss.h" #include "dss_features.h" static struct { struct platform_device *pdev; - int ctx_id; - - struct clk *dss_ick; - struct clk *dss1_fck; - struct clk *dss2_fck; - struct clk *dss_54m_fck; - struct clk *dss_96m_fck; - unsigned num_clks_enabled; struct regulator *vdds_dsi_reg; struct regulator *vdds_sdi_reg; struct regulator *vdda_dac_reg; } core; -static void dss_clk_enable_all_no_ctx(void); -static void dss_clk_disable_all_no_ctx(void); -static void dss_clk_enable_no_ctx(enum dss_clock clks); -static void dss_clk_disable_no_ctx(enum dss_clock clks); - static char *def_disp_name; module_param_named(def_disp, def_disp_name, charp, 0); MODULE_PARM_DESC(def_disp_name, "default display name"); @@ -69,297 +55,6 @@ unsigned int dss_debug; module_param_named(debug, dss_debug, bool, 0644); #endif -/* CONTEXT */ -static int dss_get_ctx_id(void) -{ - struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; - int r; - - if (!pdata->get_last_off_on_transaction_id) - return 0; - r = pdata->get_last_off_on_transaction_id(&core.pdev->dev); - if (r < 0) { - dev_err(&core.pdev->dev, "getting transaction ID failed, " - "will force context restore\n"); - r = -1; - } - return r; -} - -int dss_need_ctx_restore(void) -{ - int id = dss_get_ctx_id(); - - if (id < 0 || id != core.ctx_id) { - DSSDBG("ctx id %d -> id %d\n", - core.ctx_id, id); - core.ctx_id = id; - return 1; - } else { - return 0; - } -} - -static void save_all_ctx(void) -{ - DSSDBG("save context\n"); - - dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1); - - dss_save_context(); - dispc_save_context(); -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_save_context(); -#endif - - dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1); -} - -static void restore_all_ctx(void) -{ - DSSDBG("restore context\n"); - - dss_clk_enable_all_no_ctx(); - - dss_restore_context(); - dispc_restore_context(); -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_restore_context(); -#endif - - dss_clk_disable_all_no_ctx(); -} - -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) -/* CLOCKS */ -static void core_dump_clocks(struct seq_file *s) -{ - int i; - struct clk *clocks[5] = { - core.dss_ick, - core.dss1_fck, - core.dss2_fck, - core.dss_54m_fck, - core.dss_96m_fck - }; - - seq_printf(s, "- CORE -\n"); - - seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled); - - for (i = 0; i < 5; i++) { - if (!clocks[i]) - continue; - seq_printf(s, "%-15s\t%lu\t%d\n", - clocks[i]->name, - clk_get_rate(clocks[i]), - clocks[i]->usecount); - } -} -#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */ - -static int dss_get_clock(struct clk **clock, const char *clk_name) -{ - struct clk *clk; - - clk = clk_get(&core.pdev->dev, clk_name); - - if (IS_ERR(clk)) { - DSSERR("can't get clock %s", clk_name); - return PTR_ERR(clk); - } - - *clock = clk; - - DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk)); - - return 0; -} - -static int dss_get_clocks(void) -{ - int r; - - core.dss_ick = NULL; - core.dss1_fck = NULL; - core.dss2_fck = NULL; - core.dss_54m_fck = NULL; - core.dss_96m_fck = NULL; - - r = dss_get_clock(&core.dss_ick, "ick"); - if (r) - goto err; - - r = dss_get_clock(&core.dss1_fck, "dss1_fck"); - if (r) - goto err; - - r = dss_get_clock(&core.dss2_fck, "dss2_fck"); - if (r) - goto err; - - r = dss_get_clock(&core.dss_54m_fck, "tv_fck"); - if (r) - goto err; - - r = dss_get_clock(&core.dss_96m_fck, "video_fck"); - if (r) - goto err; - - return 0; - -err: - if (core.dss_ick) - clk_put(core.dss_ick); - if (core.dss1_fck) - clk_put(core.dss1_fck); - if (core.dss2_fck) - clk_put(core.dss2_fck); - if (core.dss_54m_fck) - clk_put(core.dss_54m_fck); - if (core.dss_96m_fck) - clk_put(core.dss_96m_fck); - - return r; -} - -static void dss_put_clocks(void) -{ - if (core.dss_96m_fck) - clk_put(core.dss_96m_fck); - clk_put(core.dss_54m_fck); - clk_put(core.dss1_fck); - clk_put(core.dss2_fck); - clk_put(core.dss_ick); -} - -unsigned long dss_clk_get_rate(enum dss_clock clk) -{ - switch (clk) { - case DSS_CLK_ICK: - return clk_get_rate(core.dss_ick); - case DSS_CLK_FCK1: - return clk_get_rate(core.dss1_fck); - case DSS_CLK_FCK2: - return clk_get_rate(core.dss2_fck); - case DSS_CLK_54M: - return clk_get_rate(core.dss_54m_fck); - case DSS_CLK_96M: - return clk_get_rate(core.dss_96m_fck); - } - - BUG(); - return 0; -} - -static unsigned count_clk_bits(enum dss_clock clks) -{ - unsigned num_clks = 0; - - if (clks & DSS_CLK_ICK) - ++num_clks; - if (clks & DSS_CLK_FCK1) - ++num_clks; - if (clks & DSS_CLK_FCK2) - ++num_clks; - if (clks & DSS_CLK_54M) - ++num_clks; - if (clks & DSS_CLK_96M) - ++num_clks; - - return num_clks; -} - -static void dss_clk_enable_no_ctx(enum dss_clock clks) -{ - unsigned num_clks = count_clk_bits(clks); - - if (clks & DSS_CLK_ICK) - clk_enable(core.dss_ick); - if (clks & DSS_CLK_FCK1) - clk_enable(core.dss1_fck); - if (clks & DSS_CLK_FCK2) - clk_enable(core.dss2_fck); - if (clks & DSS_CLK_54M) - clk_enable(core.dss_54m_fck); - if (clks & DSS_CLK_96M) - clk_enable(core.dss_96m_fck); - - core.num_clks_enabled += num_clks; -} - -void dss_clk_enable(enum dss_clock clks) -{ - bool check_ctx = core.num_clks_enabled == 0; - - dss_clk_enable_no_ctx(clks); - - if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) - restore_all_ctx(); -} - -static void dss_clk_disable_no_ctx(enum dss_clock clks) -{ - unsigned num_clks = count_clk_bits(clks); - - if (clks & DSS_CLK_ICK) - clk_disable(core.dss_ick); - if (clks & DSS_CLK_FCK1) - clk_disable(core.dss1_fck); - if (clks & DSS_CLK_FCK2) - clk_disable(core.dss2_fck); - if (clks & DSS_CLK_54M) - clk_disable(core.dss_54m_fck); - if (clks & DSS_CLK_96M) - clk_disable(core.dss_96m_fck); - - core.num_clks_enabled -= num_clks; -} - -void dss_clk_disable(enum dss_clock clks) -{ - if (cpu_is_omap34xx()) { - unsigned num_clks = count_clk_bits(clks); - - BUG_ON(core.num_clks_enabled < num_clks); - - if (core.num_clks_enabled == num_clks) - save_all_ctx(); - } - - dss_clk_disable_no_ctx(clks); -} - -static void dss_clk_enable_all_no_ctx(void) -{ - enum dss_clock clks; - - clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M; - if (cpu_is_omap34xx()) - clks |= DSS_CLK_96M; - dss_clk_enable_no_ctx(clks); -} - -static void dss_clk_disable_all_no_ctx(void) -{ - enum dss_clock clks; - - clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M; - if (cpu_is_omap34xx()) - clks |= DSS_CLK_96M; - dss_clk_disable_no_ctx(clks); -} - -static void dss_clk_disable_all(void) -{ - enum dss_clock clks; - - clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M; - if (cpu_is_omap34xx()) - clks |= DSS_CLK_96M; - dss_clk_disable(clks); -} - /* REGULATORS */ struct regulator *dss_get_vdds_dsi(void) @@ -404,18 +99,7 @@ struct regulator *dss_get_vdda_dac(void) return reg; } -/* DEBUGFS */ #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) -static void dss_debug_dump_clocks(struct seq_file *s) -{ - core_dump_clocks(s); - dss_dump_clocks(s); - dispc_dump_clocks(s); -#ifdef CONFIG_OMAP2_DSS_DSI - dsi_dump_clocks(s); -#endif -} - static int dss_debug_show(struct seq_file *s, void *unused) { void (*func)(struct seq_file *) = s->private; @@ -508,21 +192,15 @@ static int omap_dss_probe(struct platform_device *pdev) dss_init_overlay_managers(pdev); dss_init_overlays(pdev); - r = dss_get_clocks(); - if (r) - goto err_clocks; - - dss_clk_enable_all_no_ctx(); - - core.ctx_id = dss_get_ctx_id(); - DSSDBG("initial ctx id %u\n", core.ctx_id); - r = dss_init_platform_driver(); if (r) { DSSERR("Failed to initialize DSS platform driver\n"); goto err_dss; } + /* keep clocks enabled to prevent context saves/restores during init */ + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + r = rfbi_init(); if (r) { DSSERR("Failed to initialize rfbi\n"); @@ -588,7 +266,7 @@ static int omap_dss_probe(struct platform_device *pdev) pdata->default_device = dssdev; } - dss_clk_disable_all(); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); return 0; @@ -611,9 +289,6 @@ err_dpi: err_rfbi: dss_uninit_platform_driver(); err_dss: - dss_clk_disable_all_no_ctx(); - dss_put_clocks(); -err_clocks: return r; } @@ -636,16 +311,6 @@ static int omap_dss_remove(struct platform_device *pdev) dss_uninit_platform_driver(); - /* - * As part of hwmod changes, DSS is not the only controller of dss - * clocks; hwmod framework itself will also enable clocks during hwmod - * init for dss, and autoidle is set in h/w for DSS. Hence, there's no - * need to disable clocks if their usecounts > 1. - */ - WARN_ON(core.num_clks_enabled > 0); - - dss_put_clocks(); - dss_uninit_overlays(pdev); dss_uninit_overlay_managers(pdev); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 01406f48f438..72b395d69aae 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -31,6 +31,7 @@ #include #include +#include #include "dss.h" #define DSS_BASE 0x48050000 @@ -61,8 +62,15 @@ struct dss_reg { static struct { struct platform_device *pdev; void __iomem *base; + int ctx_id; struct clk *dpll4_m4_ck; + struct clk *dss_ick; + struct clk *dss1_fck; + struct clk *dss2_fck; + struct clk *dss_54m_fck; + struct clk *dss_96m_fck; + unsigned num_clks_enabled; unsigned long cache_req_pck; unsigned long cache_prate; @@ -75,6 +83,11 @@ static struct { u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; +static void dss_clk_enable_all_no_ctx(void); +static void dss_clk_disable_all_no_ctx(void); +static void dss_clk_enable_no_ctx(enum dss_clock clks); +static void dss_clk_disable_no_ctx(enum dss_clock clks); + static int _omap_dss_wait_reset(void); static inline void dss_write_reg(const struct dss_reg idx, u32 val) @@ -640,6 +653,301 @@ static void dss_exit(void) iounmap(dss.base); } +/* CONTEXT */ +static int dss_get_ctx_id(void) +{ + struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; + int r; + + if (!pdata->board_data->get_last_off_on_transaction_id) + return 0; + r = pdata->board_data->get_last_off_on_transaction_id(&dss.pdev->dev); + if (r < 0) { + dev_err(&dss.pdev->dev, "getting transaction ID failed, " + "will force context restore\n"); + r = -1; + } + return r; +} + +int dss_need_ctx_restore(void) +{ + int id = dss_get_ctx_id(); + + if (id < 0 || id != dss.ctx_id) { + DSSDBG("ctx id %d -> id %d\n", + dss.ctx_id, id); + dss.ctx_id = id; + return 1; + } else { + return 0; + } +} + +static void save_all_ctx(void) +{ + DSSDBG("save context\n"); + + dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1); + + dss_save_context(); + dispc_save_context(); +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_save_context(); +#endif + + dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1); +} + +static void restore_all_ctx(void) +{ + DSSDBG("restore context\n"); + + dss_clk_enable_all_no_ctx(); + + dss_restore_context(); + dispc_restore_context(); +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_restore_context(); +#endif + + dss_clk_disable_all_no_ctx(); +} + +static int dss_get_clock(struct clk **clock, const char *clk_name) +{ + struct clk *clk; + + clk = clk_get(&dss.pdev->dev, clk_name); + + if (IS_ERR(clk)) { + DSSERR("can't get clock %s", clk_name); + return PTR_ERR(clk); + } + + *clock = clk; + + DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk)); + + return 0; +} + +static int dss_get_clocks(void) +{ + int r; + + dss.dss_ick = NULL; + dss.dss1_fck = NULL; + dss.dss2_fck = NULL; + dss.dss_54m_fck = NULL; + dss.dss_96m_fck = NULL; + + r = dss_get_clock(&dss.dss_ick, "ick"); + if (r) + goto err; + + r = dss_get_clock(&dss.dss1_fck, "dss1_fck"); + if (r) + goto err; + + r = dss_get_clock(&dss.dss2_fck, "dss2_fck"); + if (r) + goto err; + + r = dss_get_clock(&dss.dss_54m_fck, "tv_fck"); + if (r) + goto err; + + r = dss_get_clock(&dss.dss_96m_fck, "video_fck"); + if (r) + goto err; + + return 0; + +err: + if (dss.dss_ick) + clk_put(dss.dss_ick); + if (dss.dss1_fck) + clk_put(dss.dss1_fck); + if (dss.dss2_fck) + clk_put(dss.dss2_fck); + if (dss.dss_54m_fck) + clk_put(dss.dss_54m_fck); + if (dss.dss_96m_fck) + clk_put(dss.dss_96m_fck); + + return r; +} + +static void dss_put_clocks(void) +{ + if (dss.dss_96m_fck) + clk_put(dss.dss_96m_fck); + clk_put(dss.dss_54m_fck); + clk_put(dss.dss1_fck); + clk_put(dss.dss2_fck); + clk_put(dss.dss_ick); +} + +unsigned long dss_clk_get_rate(enum dss_clock clk) +{ + switch (clk) { + case DSS_CLK_ICK: + return clk_get_rate(dss.dss_ick); + case DSS_CLK_FCK1: + return clk_get_rate(dss.dss1_fck); + case DSS_CLK_FCK2: + return clk_get_rate(dss.dss2_fck); + case DSS_CLK_54M: + return clk_get_rate(dss.dss_54m_fck); + case DSS_CLK_96M: + return clk_get_rate(dss.dss_96m_fck); + } + + BUG(); + return 0; +} + +static unsigned count_clk_bits(enum dss_clock clks) +{ + unsigned num_clks = 0; + + if (clks & DSS_CLK_ICK) + ++num_clks; + if (clks & DSS_CLK_FCK1) + ++num_clks; + if (clks & DSS_CLK_FCK2) + ++num_clks; + if (clks & DSS_CLK_54M) + ++num_clks; + if (clks & DSS_CLK_96M) + ++num_clks; + + return num_clks; +} + +static void dss_clk_enable_no_ctx(enum dss_clock clks) +{ + unsigned num_clks = count_clk_bits(clks); + + if (clks & DSS_CLK_ICK) + clk_enable(dss.dss_ick); + if (clks & DSS_CLK_FCK1) + clk_enable(dss.dss1_fck); + if (clks & DSS_CLK_FCK2) + clk_enable(dss.dss2_fck); + if (clks & DSS_CLK_54M) + clk_enable(dss.dss_54m_fck); + if (clks & DSS_CLK_96M) + clk_enable(dss.dss_96m_fck); + + dss.num_clks_enabled += num_clks; +} + +void dss_clk_enable(enum dss_clock clks) +{ + bool check_ctx = dss.num_clks_enabled == 0; + + dss_clk_enable_no_ctx(clks); + + if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) + restore_all_ctx(); +} + +static void dss_clk_disable_no_ctx(enum dss_clock clks) +{ + unsigned num_clks = count_clk_bits(clks); + + if (clks & DSS_CLK_ICK) + clk_disable(dss.dss_ick); + if (clks & DSS_CLK_FCK1) + clk_disable(dss.dss1_fck); + if (clks & DSS_CLK_FCK2) + clk_disable(dss.dss2_fck); + if (clks & DSS_CLK_54M) + clk_disable(dss.dss_54m_fck); + if (clks & DSS_CLK_96M) + clk_disable(dss.dss_96m_fck); + + dss.num_clks_enabled -= num_clks; +} + +void dss_clk_disable(enum dss_clock clks) +{ + if (cpu_is_omap34xx()) { + unsigned num_clks = count_clk_bits(clks); + + BUG_ON(dss.num_clks_enabled < num_clks); + + if (dss.num_clks_enabled == num_clks) + save_all_ctx(); + } + + dss_clk_disable_no_ctx(clks); +} + +static void dss_clk_enable_all_no_ctx(void) +{ + enum dss_clock clks; + + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M; + if (cpu_is_omap34xx()) + clks |= DSS_CLK_96M; + dss_clk_enable_no_ctx(clks); +} + +static void dss_clk_disable_all_no_ctx(void) +{ + enum dss_clock clks; + + clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M; + if (cpu_is_omap34xx()) + clks |= DSS_CLK_96M; + dss_clk_disable_no_ctx(clks); +} + +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +/* CLOCKS */ +static void core_dump_clocks(struct seq_file *s) +{ + int i; + struct clk *clocks[5] = { + dss.dss_ick, + dss.dss1_fck, + dss.dss2_fck, + dss.dss_54m_fck, + dss.dss_96m_fck + }; + + seq_printf(s, "- CORE -\n"); + + seq_printf(s, "internal clk count\t\t%u\n", dss.num_clks_enabled); + + for (i = 0; i < 5; i++) { + if (!clocks[i]) + continue; + seq_printf(s, "%-15s\t%lu\t%d\n", + clocks[i]->name, + clk_get_rate(clocks[i]), + clocks[i]->usecount); + } +} +#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */ + +/* DEBUGFS */ +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +void dss_debug_dump_clocks(struct seq_file *s) +{ + core_dump_clocks(s); + dss_dump_clocks(s); + dispc_dump_clocks(s); +#ifdef CONFIG_OMAP2_DSS_DSI + dsi_dump_clocks(s); +#endif +} +#endif + + /* DSS HW IP initialisation */ static int omap_dsshw_probe(struct platform_device *pdev) { @@ -648,6 +956,15 @@ static int omap_dsshw_probe(struct platform_device *pdev) dss.pdev = pdev; + r = dss_get_clocks(); + if (r) + goto err_clocks; + + dss_clk_enable_all_no_ctx(); + + dss.ctx_id = dss_get_ctx_id(); + DSSDBG("initial ctx id %u\n", dss.ctx_id); + #ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT /* DISPC_CONTROL */ if (omap_readl(0x48050440) & 1) /* LCD enabled? */ @@ -660,15 +977,30 @@ static int omap_dsshw_probe(struct platform_device *pdev) goto err_dss; } -err_dss: + dss_clk_disable_all_no_ctx(); + return 0; +err_dss: + dss_clk_disable_all_no_ctx(); + dss_put_clocks(); +err_clocks: return r; } static int omap_dsshw_remove(struct platform_device *pdev) { + dss_exit(); + /* + * As part of hwmod changes, DSS is not the only controller of dss + * clocks; hwmod framework itself will also enable clocks during hwmod + * init for dss, and autoidle is set in h/w for DSS. Hence, there's no + * need to disable clocks if their usecounts > 1. + */ + WARN_ON(dss.num_clks_enabled > 0); + + dss_put_clocks(); return 0; } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 37c4544e8907..c535ee1db3ee 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -169,11 +169,6 @@ struct seq_file; struct platform_device; /* core */ -void dss_clk_enable(enum dss_clock clks); -void dss_clk_disable(enum dss_clock clks); -unsigned long dss_clk_get_rate(enum dss_clock clk); -int dss_need_ctx_restore(void); -void dss_dump_clocks(struct seq_file *s); struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); @@ -219,8 +214,16 @@ void dss_uninit_platform_driver(void); void dss_save_context(void); void dss_restore_context(void); +void dss_clk_enable(enum dss_clock clks); +void dss_clk_disable(enum dss_clock clks); +unsigned long dss_clk_get_rate(enum dss_clock clk); +int dss_need_ctx_restore(void); +void dss_dump_clocks(struct seq_file *s); void dss_dump_regs(struct seq_file *s); +#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) +void dss_debug_dump_clocks(struct seq_file *s); +#endif void dss_sdi_init(u8 datapairs); int dss_sdi_enable(void); -- cgit v1.2.2 From 3448d500f7002a5ee374ec92d954b1667cbf72a4 Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Mon, 24 Jan 2011 06:21:59 +0000 Subject: OMAP2, 3: DSS2: RFBI: create platform_driver, move init, exit to driver Hwmod adaptation design requires each of the DSS HW IP to be a platform driver. So a platform_driver for RFBI is created and init exit methods are moved from core.c to its driver probe,remove. pdev member has to be maintained by its own drivers. RFBI platform driver is registered from inside omap_dss_probe, in the order desired. Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 8 +-- drivers/video/omap2/dss/dss.h | 8 +-- drivers/video/omap2/dss/rfbi.c | 110 ++++++++++++++++++++++++----------------- 3 files changed, 74 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 255935541d0d..8eef616fee03 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -201,9 +201,9 @@ static int omap_dss_probe(struct platform_device *pdev) /* keep clocks enabled to prevent context saves/restores during init */ dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); - r = rfbi_init(); + r = rfbi_init_platform_driver(); if (r) { - DSSERR("Failed to initialize rfbi\n"); + DSSERR("Failed to initialize rfbi platform driver\n"); goto err_rfbi; } @@ -285,7 +285,7 @@ err_venc: err_dispc: dpi_exit(); err_dpi: - rfbi_exit(); + rfbi_uninit_platform_driver(); err_rfbi: dss_uninit_platform_driver(); err_dss: @@ -303,7 +303,7 @@ static int omap_dss_remove(struct platform_device *pdev) venc_exit(); dispc_exit(); dpi_exit(); - rfbi_exit(); + rfbi_uninit_platform_driver(); if (cpu_is_omap34xx()) { dsi_exit(); sdi_exit(); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index c535ee1db3ee..0ba4bdbd6b01 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -428,8 +428,8 @@ static inline void venc_exit(void) /* RFBI */ #ifdef CONFIG_OMAP2_DSS_RFBI -int rfbi_init(void); -void rfbi_exit(void); +int rfbi_init_platform_driver(void); +void rfbi_uninit_platform_driver(void); void rfbi_dump_regs(struct seq_file *s); int rfbi_configure(int rfbi_module, int bpp, int lines); @@ -440,11 +440,11 @@ void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t); unsigned long rfbi_get_max_tx_rate(void); int rfbi_init_display(struct omap_dss_device *display); #else -static inline int rfbi_init(void) +static inline int rfbi_init_platform_driver(void) { return 0; } -static inline void rfbi_exit(void) +static inline void rfbi_uninit_platform_driver(void) { } #endif diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 10a2ffe02882..153f963e8e89 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -100,6 +100,7 @@ static int rfbi_convert_timings(struct rfbi_timings *t); static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div); static struct { + struct platform_device *pdev; void __iomem *base; unsigned long l4_khz; @@ -957,50 +958,6 @@ void rfbi_dump_regs(struct seq_file *s) #undef DUMPREG } -int rfbi_init(void) -{ - u32 rev; - u32 l; - - spin_lock_init(&rfbi.cmd_lock); - - init_completion(&rfbi.cmd_done); - atomic_set(&rfbi.cmd_fifo_full, 0); - atomic_set(&rfbi.cmd_pending, 0); - - rfbi.base = ioremap(RFBI_BASE, SZ_256); - if (!rfbi.base) { - DSSERR("can't ioremap RFBI\n"); - return -ENOMEM; - } - - rfbi_enable_clocks(1); - - msleep(10); - - rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000; - - /* Enable autoidle and smart-idle */ - l = rfbi_read_reg(RFBI_SYSCONFIG); - l |= (1 << 0) | (2 << 3); - rfbi_write_reg(RFBI_SYSCONFIG, l); - - rev = rfbi_read_reg(RFBI_REVISION); - printk(KERN_INFO "OMAP RFBI rev %d.%d\n", - FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - - rfbi_enable_clocks(0); - - return 0; -} - -void rfbi_exit(void) -{ - DSSDBG("rfbi_exit\n"); - - iounmap(rfbi.base); -} - int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) { int r; @@ -1056,3 +1013,68 @@ int rfbi_init_display(struct omap_dss_device *dssdev) dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; return 0; } + +/* RFBI HW IP initialisation */ +static int omap_rfbihw_probe(struct platform_device *pdev) +{ + u32 rev; + u32 l; + + rfbi.pdev = pdev; + + spin_lock_init(&rfbi.cmd_lock); + + init_completion(&rfbi.cmd_done); + atomic_set(&rfbi.cmd_fifo_full, 0); + atomic_set(&rfbi.cmd_pending, 0); + + rfbi.base = ioremap(RFBI_BASE, SZ_256); + if (!rfbi.base) { + DSSERR("can't ioremap RFBI\n"); + return -ENOMEM; + } + + rfbi_enable_clocks(1); + + msleep(10); + + rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000; + + /* Enable autoidle and smart-idle */ + l = rfbi_read_reg(RFBI_SYSCONFIG); + l |= (1 << 0) | (2 << 3); + rfbi_write_reg(RFBI_SYSCONFIG, l); + + rev = rfbi_read_reg(RFBI_REVISION); + printk(KERN_INFO "OMAP RFBI rev %d.%d\n", + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + + rfbi_enable_clocks(0); + + return 0; +} + +static int omap_rfbihw_remove(struct platform_device *pdev) +{ + iounmap(rfbi.base); + return 0; +} + +static struct platform_driver omap_rfbihw_driver = { + .probe = omap_rfbihw_probe, + .remove = omap_rfbihw_remove, + .driver = { + .name = "omapdss_rfbi", + .owner = THIS_MODULE, + }, +}; + +int rfbi_init_platform_driver(void) +{ + return platform_driver_register(&omap_rfbihw_driver); +} + +void rfbi_uninit_platform_driver(void) +{ + return platform_driver_unregister(&omap_rfbihw_driver); +} -- cgit v1.2.2 From 060b6d9cbab03f1379dbe00393ab26d6eb371ce2 Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Mon, 24 Jan 2011 06:22:00 +0000 Subject: OMAP2, 3: DSS2: DISPC: create platform_driver, move init, exit to driver Hwmod adaptation design requires each of the DSS HW IP to be a platform driver. So a platform_driver for DISPC is created and init exit methods are moved from core.c to its driver probe,remove. pdev member has to be maintained by its own drivers. DISPC platform driver is registered from inside omap_dss_probe, in the order desired. Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 8 +-- drivers/video/omap2/dss/dispc.c | 105 ++++++++++++++++++++++++---------------- drivers/video/omap2/dss/dss.h | 4 +- 3 files changed, 70 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 8eef616fee03..8b7eab83e412 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -213,9 +213,9 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_dpi; } - r = dispc_init(); + r = dispc_init_platform_driver(); if (r) { - DSSERR("Failed to initialize dispc\n"); + DSSERR("Failed to initialize dispc platform driver\n"); goto err_dispc; } @@ -281,7 +281,7 @@ err_dsi: err_sdi: venc_exit(); err_venc: - dispc_exit(); + dispc_uninit_platform_driver(); err_dispc: dpi_exit(); err_dpi: @@ -301,7 +301,7 @@ static int omap_dss_remove(struct platform_device *pdev) dss_uninitialize_debugfs(); venc_exit(); - dispc_exit(); + dispc_uninit_platform_driver(); dpi_exit(); rfbi_uninit_platform_driver(); if (cpu_is_omap34xx()) { diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 9f8c69f16e61..28ad68b6be48 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -178,6 +178,7 @@ struct dispc_irq_stats { }; static struct { + struct platform_device *pdev; void __iomem *base; u32 fifo_size[3]; @@ -3269,47 +3270,6 @@ static void _omap_dispc_initial_config(void) dispc_read_plane_fifo_sizes(); } -int dispc_init(void) -{ - u32 rev; - - spin_lock_init(&dispc.irq_lock); - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS - spin_lock_init(&dispc.irq_stats_lock); - dispc.irq_stats.last_reset = jiffies; -#endif - - INIT_WORK(&dispc.error_work, dispc_error_worker); - - dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS); - if (!dispc.base) { - DSSERR("can't ioremap DISPC\n"); - return -ENOMEM; - } - - enable_clocks(1); - - _omap_dispc_initial_config(); - - _omap_dispc_initialize_irq(); - - dispc_save_context(); - - rev = dispc_read_reg(DISPC_REVISION); - printk(KERN_INFO "OMAP DISPC rev %d.%d\n", - FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); - - enable_clocks(0); - - return 0; -} - -void dispc_exit(void) -{ - iounmap(dispc.base); -} - int dispc_enable_plane(enum omap_plane plane, bool enable) { DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); @@ -3359,3 +3319,66 @@ int dispc_setup_plane(enum omap_plane plane, return r; } + +/* DISPC HW IP initialisation */ +static int omap_dispchw_probe(struct platform_device *pdev) +{ + u32 rev; + dispc.pdev = pdev; + + spin_lock_init(&dispc.irq_lock); + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + spin_lock_init(&dispc.irq_stats_lock); + dispc.irq_stats.last_reset = jiffies; +#endif + + INIT_WORK(&dispc.error_work, dispc_error_worker); + + dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS); + if (!dispc.base) { + DSSERR("can't ioremap DISPC\n"); + return -ENOMEM; + } + + enable_clocks(1); + + _omap_dispc_initial_config(); + + _omap_dispc_initialize_irq(); + + dispc_save_context(); + + rev = dispc_read_reg(DISPC_REVISION); + printk(KERN_INFO "OMAP DISPC rev %d.%d\n", + FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); + + enable_clocks(0); + + return 0; +} + +static int omap_dispchw_remove(struct platform_device *pdev) +{ + iounmap(dispc.base); + return 0; +} + +static struct platform_driver omap_dispchw_driver = { + .probe = omap_dispchw_probe, + .remove = omap_dispchw_remove, + .driver = { + .name = "omapdss_dispc", + .owner = THIS_MODULE, + }, +}; + +int dispc_init_platform_driver(void) +{ + return platform_driver_register(&omap_dispchw_driver); +} + +void dispc_uninit_platform_driver(void) +{ + return platform_driver_unregister(&omap_dispchw_driver); +} diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 0ba4bdbd6b01..f4835c85db90 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -319,8 +319,8 @@ static inline void dpi_exit(void) #endif /* DISPC */ -int dispc_init(void); -void dispc_exit(void); +int dispc_init_platform_driver(void); +void dispc_uninit_platform_driver(void); void dispc_dump_clocks(struct seq_file *s); void dispc_dump_irqs(struct seq_file *s); void dispc_dump_regs(struct seq_file *s); -- cgit v1.2.2 From 30ea50c9f5166a375b4dc0109d18a5d21bab5711 Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Mon, 24 Jan 2011 06:22:01 +0000 Subject: OMAP2, 3: DSS2: VENC: create platform_driver, move init, exit to driver Hwmod adaptation design requires each of the DSS HW IP to be a platform driver. So a platform_driver for VENC is created and init exit methods are moved from core.c to its driver probe,remove. pdev member has to be maintained by its own drivers. Also, venc_vdda_dac reading is moved to venc.c. VENC platform driver is registered from inside omap_dss_probe, in the order desired. Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 28 ++-------- drivers/video/omap2/dss/dss.h | 9 ++-- drivers/video/omap2/dss/venc.c | 116 +++++++++++++++++++++++++++-------------- 3 files changed, 84 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 8b7eab83e412..57c6303cb1cd 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -43,7 +43,6 @@ static struct { struct regulator *vdds_dsi_reg; struct regulator *vdds_sdi_reg; - struct regulator *vdda_dac_reg; } core; static char *def_disp_name; @@ -85,20 +84,6 @@ struct regulator *dss_get_vdds_sdi(void) return reg; } -struct regulator *dss_get_vdda_dac(void) -{ - struct regulator *reg; - - if (core.vdda_dac_reg != NULL) - return core.vdda_dac_reg; - - reg = regulator_get(&core.pdev->dev, "vdda_dac"); - if (!IS_ERR(reg)) - core.vdda_dac_reg = reg; - - return reg; -} - #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) static int dss_debug_show(struct seq_file *s, void *unused) { @@ -219,9 +204,9 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_dispc; } - r = venc_init(pdev); + r = venc_init_platform_driver(); if (r) { - DSSERR("Failed to initialize venc\n"); + DSSERR("Failed to initialize venc platform driver\n"); goto err_venc; } @@ -279,7 +264,7 @@ err_dsi: if (cpu_is_omap34xx()) sdi_exit(); err_sdi: - venc_exit(); + venc_uninit_platform_driver(); err_venc: dispc_uninit_platform_driver(); err_dispc: @@ -300,7 +285,7 @@ static int omap_dss_remove(struct platform_device *pdev) dss_uninitialize_debugfs(); - venc_exit(); + venc_uninit_platform_driver(); dispc_uninit_platform_driver(); dpi_exit(); rfbi_uninit_platform_driver(); @@ -597,11 +582,6 @@ static void __exit omap_dss_exit(void) core.vdds_sdi_reg = NULL; } - if (core.vdda_dac_reg != NULL) { - regulator_put(core.vdda_dac_reg); - core.vdda_dac_reg = NULL; - } - platform_driver_unregister(&omap_dss_driver); omap_dss_bus_unregister(); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index f4835c85db90..931385185dc6 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -172,7 +172,6 @@ struct platform_device; struct bus_type *dss_get_bus(void); struct regulator *dss_get_vdds_dsi(void); struct regulator *dss_get_vdds_sdi(void); -struct regulator *dss_get_vdda_dac(void); /* display */ int dss_suspend_all_devices(void); @@ -412,16 +411,16 @@ int dispc_get_clock_div(enum omap_channel channel, /* VENC */ #ifdef CONFIG_OMAP2_DSS_VENC -int venc_init(struct platform_device *pdev); -void venc_exit(void); +int venc_init_platform_driver(void); +void venc_uninit_platform_driver(void); void venc_dump_regs(struct seq_file *s); int venc_init_display(struct omap_dss_device *display); #else -static inline int venc_init(struct platform_device *pdev) +static inline int venc_init_platform_driver(void) { return 0; } -static inline void venc_exit(void) +static inline void venc_uninit_platform_driver(void) { } #endif diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index eff35050e28a..765a4ac44ecd 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -289,6 +289,7 @@ const struct omap_video_timings omap_dss_ntsc_timings = { EXPORT_SYMBOL(omap_dss_ntsc_timings); static struct { + struct platform_device *pdev; void __iomem *base; struct mutex venc_lock; u32 wss_data; @@ -306,6 +307,17 @@ static inline u32 venc_read_reg(int idx) return l; } +static struct regulator *venc_get_vdda_dac(void) +{ + struct regulator *reg; + + reg = regulator_get(&venc.pdev->dev, "vdda_dac"); + if (!IS_ERR(reg)) + venc.vdda_dac_reg = reg; + + return reg; +} + static void venc_write_config(const struct venc_config *config) { DSSDBG("write venc conf\n"); @@ -641,46 +653,6 @@ static struct omap_dss_driver venc_driver = { }; /* driver end */ - - -int venc_init(struct platform_device *pdev) -{ - u8 rev_id; - - mutex_init(&venc.venc_lock); - - venc.wss_data = 0; - - venc.base = ioremap(VENC_BASE, SZ_1K); - if (!venc.base) { - DSSERR("can't ioremap VENC\n"); - return -ENOMEM; - } - - venc.vdda_dac_reg = dss_get_vdda_dac(); - if (IS_ERR(venc.vdda_dac_reg)) { - iounmap(venc.base); - DSSERR("can't get VDDA_DAC regulator\n"); - return PTR_ERR(venc.vdda_dac_reg); - } - - venc_enable_clocks(1); - - rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); - printk(KERN_INFO "OMAP VENC rev %d\n", rev_id); - - venc_enable_clocks(0); - - return omap_dss_register_driver(&venc_driver); -} - -void venc_exit(void) -{ - omap_dss_unregister_driver(&venc_driver); - - iounmap(venc.base); -} - int venc_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); @@ -740,3 +712,67 @@ void venc_dump_regs(struct seq_file *s) #undef DUMPREG } + +/* VENC HW IP initialisation */ +static int omap_venchw_probe(struct platform_device *pdev) +{ + u8 rev_id; + venc.pdev = pdev; + + mutex_init(&venc.venc_lock); + + venc.wss_data = 0; + + venc.base = ioremap(VENC_BASE, SZ_1K); + if (!venc.base) { + DSSERR("can't ioremap VENC\n"); + return -ENOMEM; + } + + venc.vdda_dac_reg = venc_get_vdda_dac(); + if (IS_ERR(venc.vdda_dac_reg)) { + iounmap(venc.base); + DSSERR("can't get VDDA_DAC regulator\n"); + return PTR_ERR(venc.vdda_dac_reg); + } + + venc_enable_clocks(1); + + rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); + printk(KERN_INFO "OMAP VENC rev %d\n", rev_id); + + venc_enable_clocks(0); + + return omap_dss_register_driver(&venc_driver); +} + +static int omap_venchw_remove(struct platform_device *pdev) +{ + if (venc.vdda_dac_reg != NULL) { + regulator_put(venc.vdda_dac_reg); + venc.vdda_dac_reg = NULL; + } + omap_dss_unregister_driver(&venc_driver); + + iounmap(venc.base); + return 0; +} + +static struct platform_driver omap_venchw_driver = { + .probe = omap_venchw_probe, + .remove = omap_venchw_remove, + .driver = { + .name = "omapdss_venc", + .owner = THIS_MODULE, + }, +}; + +int venc_init_platform_driver(void) +{ + return platform_driver_register(&omap_venchw_driver); +} + +void venc_uninit_platform_driver(void) +{ + return platform_driver_unregister(&omap_venchw_driver); +} -- cgit v1.2.2 From c8aac01b7bd1109795586db11ea7f12ab1e2d163 Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Mon, 24 Jan 2011 06:22:02 +0000 Subject: OMAP2, 3: DSS2: DSI: create platform_driver, move init, exit to driver Hwmod adaptation design requires each of the DSS HW IP to be a platform driver. So a platform_driver for DSI is created and init exit methods are moved from core.c to its driver probe,remove. pdev member has to be maintained by its own drivers. Also, vdds_dsi regulator handling is copied to dsi.c, since vdds_dsi regulator is needed by dpi_init() too. Board files are updated accordingly to add 2 instances of vdds_dsi regulator. DSI platform driver is registered from inside omap_dss_probe, in the order desired. Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 8 +++--- drivers/video/omap2/dss/dsi.c | 64 ++++++++++++++++++++++++++++++++++++++++-- drivers/video/omap2/dss/dss.h | 8 +++--- 3 files changed, 69 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 57c6303cb1cd..3f7a5fcd1142 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -222,9 +222,9 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_sdi; } - r = dsi_init(pdev); + r = dsi_init_platform_driver(); if (r) { - DSSERR("Failed to initialize DSI\n"); + DSSERR("Failed to initialize DSI platform driver\n"); goto err_dsi; } } @@ -259,7 +259,7 @@ err_register: dss_uninitialize_debugfs(); err_debugfs: if (cpu_is_omap34xx()) - dsi_exit(); + dsi_uninit_platform_driver(); err_dsi: if (cpu_is_omap34xx()) sdi_exit(); @@ -290,7 +290,7 @@ static int omap_dss_remove(struct platform_device *pdev) dpi_exit(); rfbi_uninit_platform_driver(); if (cpu_is_omap34xx()) { - dsi_exit(); + dsi_uninit_platform_driver(); sdi_exit(); } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index ddf3a0560822..fa85f1adba2a 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -222,6 +222,7 @@ struct dsi_irq_stats { static struct { + struct platform_device *pdev; void __iomem *base; struct dsi_clock_info current_cinfo; @@ -292,6 +293,20 @@ static inline u32 dsi_read_reg(const struct dsi_reg idx) return __raw_readl(dsi.base + idx.idx); } +static struct regulator *dsi_get_vdds_dsi(void) +{ + struct regulator *reg; + + if (dsi.vdds_dsi_reg != NULL) + return dsi.vdds_dsi_reg; + + reg = regulator_get(&dsi.pdev->dev, "vdds_dsi"); + if (!IS_ERR(reg)) + dsi.vdds_dsi_reg = reg; + + return reg; +} + void dsi_save_context(void) { @@ -3238,7 +3253,7 @@ void dsi_wait_dsi2_pll_active(void) DSSERR("DSI2 PLL clock not active\n"); } -int dsi_init(struct platform_device *pdev) +static int dsi_init(struct platform_device *pdev) { u32 rev; int r; @@ -3275,7 +3290,7 @@ int dsi_init(struct platform_device *pdev) goto err1; } - dsi.vdds_dsi_reg = dss_get_vdds_dsi(); + dsi.vdds_dsi_reg = dsi_get_vdds_dsi(); if (IS_ERR(dsi.vdds_dsi_reg)) { DSSERR("can't get VDDS_DSI regulator\n"); r = PTR_ERR(dsi.vdds_dsi_reg); @@ -3298,8 +3313,13 @@ err1: return r; } -void dsi_exit(void) +static void dsi_exit(void) { + if (dsi.vdds_dsi_reg != NULL) { + regulator_put(dsi.vdds_dsi_reg); + dsi.vdds_dsi_reg = NULL; + } + iounmap(dsi.base); destroy_workqueue(dsi.workqueue); @@ -3307,3 +3327,41 @@ void dsi_exit(void) DSSDBG("omap_dsi_exit\n"); } +/* DSI1 HW IP initialisation */ +static int omap_dsi1hw_probe(struct platform_device *pdev) +{ + int r; + dsi.pdev = pdev; + r = dsi_init(pdev); + if (r) { + DSSERR("Failed to initialize DSI\n"); + goto err_dsi; + } +err_dsi: + return r; +} + +static int omap_dsi1hw_remove(struct platform_device *pdev) +{ + dsi_exit(); + return 0; +} + +static struct platform_driver omap_dsi1hw_driver = { + .probe = omap_dsi1hw_probe, + .remove = omap_dsi1hw_remove, + .driver = { + .name = "omapdss_dsi1", + .owner = THIS_MODULE, + }, +}; + +int dsi_init_platform_driver(void) +{ + return platform_driver_register(&omap_dsi1hw_driver); +} + +void dsi_uninit_platform_driver(void) +{ + return platform_driver_unregister(&omap_dsi1hw_driver); +} diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 931385185dc6..981d247c30f2 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -261,8 +261,8 @@ static inline void sdi_exit(void) /* DSI */ #ifdef CONFIG_OMAP2_DSS_DSI -int dsi_init(struct platform_device *pdev); -void dsi_exit(void); +int dsi_init_platform_driver(void); +void dsi_uninit_platform_driver(void); void dsi_dump_clocks(struct seq_file *s); void dsi_dump_irqs(struct seq_file *s); @@ -287,11 +287,11 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, void dsi_wait_dsi1_pll_active(void); void dsi_wait_dsi2_pll_active(void); #else -static inline int dsi_init(struct platform_device *pdev) +static inline int dsi_init_platform_driver(void) { return 0; } -static inline void dsi_exit(void) +static inline void dsi_uninit_platform_driver(void) { } static inline void dsi_wait_dsi1_pll_active(void) -- cgit v1.2.2 From a06b62f8004bd95c132fa312e8593c9a10f466ec Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Mon, 24 Jan 2011 06:22:03 +0000 Subject: OMAP2,3: DSS2: replace printk with dev_dbg in init This patch replaces printk's in the init/probe functions to dev_dbg for boot time optimization. Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 2 +- drivers/video/omap2/dss/dsi.c | 2 +- drivers/video/omap2/dss/rfbi.c | 2 +- drivers/video/omap2/dss/venc.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 28ad68b6be48..032e5dd19e09 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -3350,7 +3350,7 @@ static int omap_dispchw_probe(struct platform_device *pdev) dispc_save_context(); rev = dispc_read_reg(DISPC_REVISION); - printk(KERN_INFO "OMAP DISPC rev %d.%d\n", + dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); enable_clocks(0); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index fa85f1adba2a..df246033b940 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3300,7 +3300,7 @@ static int dsi_init(struct platform_device *pdev) enable_clocks(1); rev = dsi_read_reg(DSI_REVISION); - printk(KERN_INFO "OMAP DSI rev %d.%d\n", + dev_dbg(&pdev->dev, "OMAP DSI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); enable_clocks(0); diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 153f963e8e89..5f186484984f 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -1046,7 +1046,7 @@ static int omap_rfbihw_probe(struct platform_device *pdev) rfbi_write_reg(RFBI_SYSCONFIG, l); rev = rfbi_read_reg(RFBI_REVISION); - printk(KERN_INFO "OMAP RFBI rev %d.%d\n", + dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); rfbi_enable_clocks(0); diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 765a4ac44ecd..4a02f8eeb0d8 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -739,7 +739,7 @@ static int omap_venchw_probe(struct platform_device *pdev) venc_enable_clocks(1); rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); - printk(KERN_INFO "OMAP VENC rev %d\n", rev_id); + dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); venc_enable_clocks(0); -- cgit v1.2.2 From ea9da36a304eed585fc5ef89c0f1c460eca61b48 Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Mon, 24 Jan 2011 06:22:04 +0000 Subject: OMAP2,3: DSS2: Use platform device to get baseaddr DSS, DISPC, DSI, RFBI, VENC baseaddr can be obtained from platform_get_resource(). This API in turn picks the right silicon baseaddr from the hwmod database. So hardcoding of base addr could be removed. Reviewed-by: Paul Walmsley Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Sumit Semwal Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 11 ++++++++--- drivers/video/omap2/dss/dsi.c | 11 ++++++++--- drivers/video/omap2/dss/dss.c | 11 ++++++++--- drivers/video/omap2/dss/rfbi.c | 10 +++++++--- drivers/video/omap2/dss/venc.c | 11 ++++++++--- 5 files changed, 39 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 032e5dd19e09..96e37f8e75dc 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -42,8 +42,6 @@ #include "dss_features.h" /* DISPC */ -#define DISPC_BASE 0x48050400 - #define DISPC_SZ_REGS SZ_4K struct dispc_reg { u16 idx; }; @@ -3324,6 +3322,8 @@ int dispc_setup_plane(enum omap_plane plane, static int omap_dispchw_probe(struct platform_device *pdev) { u32 rev; + struct resource *dispc_mem; + dispc.pdev = pdev; spin_lock_init(&dispc.irq_lock); @@ -3335,7 +3335,12 @@ static int omap_dispchw_probe(struct platform_device *pdev) INIT_WORK(&dispc.error_work, dispc_error_worker); - dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS); + dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); + if (!dispc_mem) { + DSSERR("can't get IORESOURCE_MEM DISPC\n"); + return -EINVAL; + } + dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); if (!dispc.base) { DSSERR("can't ioremap DISPC\n"); return -ENOMEM; diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index df246033b940..c42acae10af0 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -42,8 +42,6 @@ /*#define VERBOSE_IRQ*/ #define DSI_CATCH_MISSING_TE -#define DSI_BASE 0x4804FC00 - struct dsi_reg { u16 idx; }; #define DSI_REG(idx) ((const struct dsi_reg) { idx }) @@ -3257,6 +3255,7 @@ static int dsi_init(struct platform_device *pdev) { u32 rev; int r; + struct resource *dsi_mem; spin_lock_init(&dsi.errors_lock); dsi.errors = 0; @@ -3283,7 +3282,13 @@ static int dsi_init(struct platform_device *pdev) dsi.te_timer.function = dsi_te_timeout; dsi.te_timer.data = 0; #endif - dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS); + dsi_mem = platform_get_resource(dsi.pdev, IORESOURCE_MEM, 0); + if (!dsi_mem) { + DSSERR("can't get IORESOURCE_MEM DSI\n"); + r = -EINVAL; + goto err1; + } + dsi.base = ioremap(dsi_mem->start, resource_size(dsi_mem)); if (!dsi.base) { DSSERR("can't ioremap DSI\n"); r = -ENOMEM; diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 72b395d69aae..ee9ce4af58b5 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -34,8 +34,6 @@ #include #include "dss.h" -#define DSS_BASE 0x48050000 - #define DSS_SZ_REGS SZ_512 struct dss_reg { @@ -567,8 +565,15 @@ static int dss_init(bool skip_init) { int r; u32 rev; + struct resource *dss_mem; - dss.base = ioremap(DSS_BASE, DSS_SZ_REGS); + dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); + if (!dss_mem) { + DSSERR("can't get IORESOURCE_MEM DSS\n"); + r = -EINVAL; + goto fail0; + } + dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); if (!dss.base) { DSSERR("can't ioremap DSS\n"); r = -ENOMEM; diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 5f186484984f..6dbb95d557f8 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -36,8 +36,6 @@ #include #include "dss.h" -#define RFBI_BASE 0x48050800 - struct rfbi_reg { u16 idx; }; #define RFBI_REG(idx) ((const struct rfbi_reg) { idx }) @@ -1019,6 +1017,7 @@ static int omap_rfbihw_probe(struct platform_device *pdev) { u32 rev; u32 l; + struct resource *rfbi_mem; rfbi.pdev = pdev; @@ -1028,7 +1027,12 @@ static int omap_rfbihw_probe(struct platform_device *pdev) atomic_set(&rfbi.cmd_fifo_full, 0); atomic_set(&rfbi.cmd_pending, 0); - rfbi.base = ioremap(RFBI_BASE, SZ_256); + rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); + if (!rfbi_mem) { + DSSERR("can't get IORESOURCE_MEM RFBI\n"); + return -EINVAL; + } + rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem)); if (!rfbi.base) { DSSERR("can't ioremap RFBI\n"); return -ENOMEM; diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 4a02f8eeb0d8..ef36811f6ac8 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -39,8 +39,6 @@ #include "dss.h" -#define VENC_BASE 0x48050C00 - /* Venc registers */ #define VENC_REV_ID 0x00 #define VENC_STATUS 0x04 @@ -717,13 +715,20 @@ void venc_dump_regs(struct seq_file *s) static int omap_venchw_probe(struct platform_device *pdev) { u8 rev_id; + struct resource *venc_mem; + venc.pdev = pdev; mutex_init(&venc.venc_lock); venc.wss_data = 0; - venc.base = ioremap(VENC_BASE, SZ_1K); + venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); + if (!venc_mem) { + DSSERR("can't get IORESOURCE_MEM VENC\n"); + return -EINVAL; + } + venc.base = ioremap(venc_mem->start, resource_size(venc_mem)); if (!venc.base) { DSSERR("can't ioremap VENC\n"); return -ENOMEM; -- cgit v1.2.2 From ef631f82500390b3dfc20b16214e53c443d675a4 Mon Sep 17 00:00:00 2001 From: Senthilvadivu Guruswamy Date: Tue, 15 Feb 2011 23:14:00 -0600 Subject: OMAP2,3: DSS2: Get DSS IRQ from platform device DSS IRQ number can be obtained from platform_get_irq(). This API in turn picks the right IRQ number belonging to HW IP from the hwmod database. So hardcoding of IRQ number could be removed. This IRQ is stored in dss_irq as part of dss structure, and freed it in dss_exit(). Reviewed-by: Paul Walmsley Reviewed-by: Kevin Hilman Tested-by: Kevin Hilman Signed-off-by: Senthilvadivu Guruswamy Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index ee9ce4af58b5..a00733d6436a 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -79,6 +79,7 @@ static struct { enum dss_clk_source dispc_clk_source; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; + int dss_irq; } dss; static void dss_clk_enable_all_no_ctx(void); @@ -609,11 +610,18 @@ static int dss_init(bool skip_init) REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ #endif - r = request_irq(INT_24XX_DSS_IRQ, - cpu_is_omap24xx() - ? dss_irq_handler_omap2 - : dss_irq_handler_omap3, - 0, "OMAP DSS", NULL); + dss.dss_irq = platform_get_irq(dss.pdev, 0); + if (dss.dss_irq < 0) { + DSSERR("omap2 dss: platform_get_irq failed\n"); + r = -ENODEV; + goto fail1; + } + + r = request_irq(dss.dss_irq, + cpu_is_omap24xx() + ? dss_irq_handler_omap2 + : dss_irq_handler_omap3, + 0, "OMAP DSS", NULL); if (r < 0) { DSSERR("omap2 dss: request_irq failed\n"); @@ -641,7 +649,7 @@ static int dss_init(bool skip_init) return 0; fail2: - free_irq(INT_24XX_DSS_IRQ, NULL); + free_irq(dss.dss_irq, NULL); fail1: iounmap(dss.base); fail0: @@ -653,7 +661,7 @@ static void dss_exit(void) if (cpu_is_omap34xx()) clk_put(dss.dpll4_m4_ck); - free_irq(INT_24XX_DSS_IRQ, NULL); + free_irq(dss.dss_irq, NULL); iounmap(dss.base); } -- cgit v1.2.2 From 872462cdfc74e7b93c09870128d9bb436d4e9804 Mon Sep 17 00:00:00 2001 From: Sumit Semwal Date: Mon, 31 Jan 2011 16:27:43 +0000 Subject: OMAP2PLUS: clocks: Align DSS clock names and roles Currently, clock database has tuples for DSS2. Because of this, the clock names are different across different OMAP platforms. This patch aligns the DSS2 clock names and roles across OMAP 2420, 2430, 3xxx, 44xx platforms in the clock databases, hwmod databases for opt-clocks, and DSS clock handling. This ensures that clk_get/put/enable/disable APIs in DSS can use uniform role names. Signed-off-by: Sumit Semwal Acked-by: Paul Walmsley Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index a00733d6436a..56d37bfefd4d 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -759,19 +759,19 @@ static int dss_get_clocks(void) if (r) goto err; - r = dss_get_clock(&dss.dss1_fck, "dss1_fck"); + r = dss_get_clock(&dss.dss1_fck, "fck"); if (r) goto err; - r = dss_get_clock(&dss.dss2_fck, "dss2_fck"); + r = dss_get_clock(&dss.dss2_fck, "sys_clk"); if (r) goto err; - r = dss_get_clock(&dss.dss_54m_fck, "tv_fck"); + r = dss_get_clock(&dss.dss_54m_fck, "tv_clk"); if (r) goto err; - r = dss_get_clock(&dss.dss_96m_fck, "video_fck"); + r = dss_get_clock(&dss.dss_96m_fck, "video_clk"); if (r) goto err; -- cgit v1.2.2 From 6af9cd1431db952a7f9f8931497c9989a48b07df Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 31 Jan 2011 16:27:44 +0000 Subject: OMAP2PLUS: DSS2: Generalize naming of PRCM related clock enums in DSS driver enum dss_clock structure is replaced with generic names that could be used across OMAP2420, 2430, 3xxx, 44xx platforms. Signed-off-by: Sumit Semwal Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 4 +-- drivers/video/omap2/dss/dispc.c | 10 +++---- drivers/video/omap2/dss/dpi.c | 16 +++++----- drivers/video/omap2/dss/dsi.c | 18 ++++++------ drivers/video/omap2/dss/dss.c | 62 +++++++++++++++++++-------------------- drivers/video/omap2/dss/dss.h | 10 +++---- drivers/video/omap2/dss/manager.c | 4 +-- drivers/video/omap2/dss/overlay.c | 4 +-- drivers/video/omap2/dss/rfbi.c | 10 +++---- drivers/video/omap2/dss/sdi.c | 8 ++--- drivers/video/omap2/dss/venc.c | 8 ++--- 11 files changed, 77 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 3f7a5fcd1142..f56ee64f5b58 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -184,7 +184,7 @@ static int omap_dss_probe(struct platform_device *pdev) } /* keep clocks enabled to prevent context saves/restores during init */ - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); r = rfbi_init_platform_driver(); if (r) { @@ -251,7 +251,7 @@ static int omap_dss_probe(struct platform_device *pdev) pdata->default_device = dssdev; } - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); return 0; diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 96e37f8e75dc..dc4518c4b0e4 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -551,9 +551,9 @@ void dispc_restore_context(void) static inline void enable_clocks(bool enable) { if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } bool dispc_go_busy(enum omap_channel channel) @@ -2311,7 +2311,7 @@ unsigned long dispc_fclk_rate(void) unsigned long r = 0; if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) - r = dss_clk_get_rate(DSS_CLK_FCK1); + r = dss_clk_get_rate(DSS_CLK_FCK); else #ifdef CONFIG_OMAP2_DSS_DSI r = dsi_get_dsi1_pll_rate(); @@ -2439,7 +2439,7 @@ void dispc_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); DUMPREG(DISPC_REVISION); DUMPREG(DISPC_SYSCONFIG); @@ -2596,7 +2596,7 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_VID_PRELOAD(0)); DUMPREG(DISPC_VID_PRELOAD(1)); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 75fb0a515430..746f1b6dd897 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -107,7 +107,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) bool is_tft; int r = 0; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, dssdev->panel.acbi, dssdev->panel.acb); @@ -137,7 +137,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) dispc_set_lcd_timings(dssdev->manager->id, t); err0: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); return r; } @@ -173,14 +173,14 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) goto err1; } - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); r = dpi_basic_init(dssdev); if (r) goto err2; #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL - dss_clk_enable(DSS_CLK_FCK2); + dss_clk_enable(DSS_CLK_SYSCK); r = dsi_pll_init(dssdev, 0, 1); if (r) goto err3; @@ -199,10 +199,10 @@ err4: #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL dsi_pll_uninit(); err3: - dss_clk_disable(DSS_CLK_FCK2); + dss_clk_disable(DSS_CLK_SYSCK); #endif err2: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); err1: @@ -219,10 +219,10 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_pll_uninit(); - dss_clk_disable(DSS_CLK_FCK2); + dss_clk_disable(DSS_CLK_SYSCK); #endif - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); if (cpu_is_omap34xx()) regulator_disable(dpi.vdds_dsi_reg); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index c42acae10af0..c7b5382e1a6b 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -654,18 +654,18 @@ static void dsi_vc_disable_bta_irq(int channel) static inline void enable_clocks(bool enable) { if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } /* source clock for DSI PLL. this could also be PCLKFREE */ static inline void dsi_enable_pll_clock(bool enable) { if (enable) - dss_clk_enable(DSS_CLK_FCK2); + dss_clk_enable(DSS_CLK_SYSCK); else - dss_clk_disable(DSS_CLK_FCK2); + dss_clk_disable(DSS_CLK_SYSCK); if (enable && dsi.pll_locked) { if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) @@ -741,7 +741,7 @@ static unsigned long dsi_fclk_rate(void) if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) { /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */ - r = dss_clk_get_rate(DSS_CLK_FCK1); + r = dss_clk_get_rate(DSS_CLK_FCK); } else { /* DSI FCLK source is DSI2_PLL_FCLK */ r = dsi_get_dsi2_pll_rate(); @@ -821,7 +821,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, return -EINVAL; if (cinfo->use_dss2_fck) { - cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2); + cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK); /* XXX it is unclear if highfreq should be used * with DSS2_FCK source also */ cinfo->highfreq = 0; @@ -867,7 +867,7 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck, int match = 0; unsigned long dss_clk_fck2; - dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2); + dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_SYSCK); if (req_pck == dsi.cache_req_pck && dsi.cache_cinfo.clkin == dss_clk_fck2) { @@ -1319,7 +1319,7 @@ void dsi_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); DUMPREG(DSI_REVISION); DUMPREG(DSI_SYSCONFIG); @@ -1391,7 +1391,7 @@ void dsi_dump_regs(struct seq_file *s) DUMPREG(DSI_PLL_CONFIGURATION1); DUMPREG(DSI_PLL_CONFIGURATION2); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 56d37bfefd4d..0372befbb692 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -227,7 +227,7 @@ void dss_dump_clocks(struct seq_file *s) unsigned long dpll4_ck_rate; unsigned long dpll4_m4_ck_rate; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); @@ -240,21 +240,21 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n", dpll4_ck_rate, dpll4_ck_rate / dpll4_m4_ck_rate, - dss_clk_get_rate(DSS_CLK_FCK1)); + dss_clk_get_rate(DSS_CLK_FCK)); else seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n", dpll4_ck_rate, dpll4_ck_rate / dpll4_m4_ck_rate, - dss_clk_get_rate(DSS_CLK_FCK1)); + dss_clk_get_rate(DSS_CLK_FCK)); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } void dss_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); DUMPREG(DSS_REVISION); DUMPREG(DSS_SYSCONFIG); @@ -265,7 +265,7 @@ void dss_dump_regs(struct seq_file *s) DUMPREG(DSS_PLL_CONTROL); DUMPREG(DSS_SDI_STATUS); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } @@ -350,7 +350,7 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) int dss_get_clock_div(struct dss_clock_info *cinfo) { - cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1); + cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); if (cpu_is_omap34xx()) { unsigned long prate; @@ -391,7 +391,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, prate = dss_get_dpll4_rate(); - fck = dss_clk_get_rate(DSS_CLK_FCK1); + fck = dss_clk_get_rate(DSS_CLK_FCK); if (req_pck == dss.cache_req_pck && ((cpu_is_omap34xx() && prate == dss.cache_prate) || dss.cache_dss_cinfo.fck == fck)) { @@ -418,7 +418,7 @@ retry: if (cpu_is_omap24xx()) { struct dispc_clock_info cur_dispc; /* XXX can we change the clock on omap2? */ - fck = dss_clk_get_rate(DSS_CLK_FCK1); + fck = dss_clk_get_rate(DSS_CLK_FCK); fck_div = 1; dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); @@ -701,7 +701,7 @@ static void save_all_ctx(void) { DSSDBG("save context\n"); - dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); dss_save_context(); dispc_save_context(); @@ -709,7 +709,7 @@ static void save_all_ctx(void) dsi_save_context(); #endif - dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK); } static void restore_all_ctx(void) @@ -807,13 +807,13 @@ unsigned long dss_clk_get_rate(enum dss_clock clk) switch (clk) { case DSS_CLK_ICK: return clk_get_rate(dss.dss_ick); - case DSS_CLK_FCK1: + case DSS_CLK_FCK: return clk_get_rate(dss.dss1_fck); - case DSS_CLK_FCK2: + case DSS_CLK_SYSCK: return clk_get_rate(dss.dss2_fck); - case DSS_CLK_54M: + case DSS_CLK_TVFCK: return clk_get_rate(dss.dss_54m_fck); - case DSS_CLK_96M: + case DSS_CLK_VIDFCK: return clk_get_rate(dss.dss_96m_fck); } @@ -827,13 +827,13 @@ static unsigned count_clk_bits(enum dss_clock clks) if (clks & DSS_CLK_ICK) ++num_clks; - if (clks & DSS_CLK_FCK1) + if (clks & DSS_CLK_FCK) ++num_clks; - if (clks & DSS_CLK_FCK2) + if (clks & DSS_CLK_SYSCK) ++num_clks; - if (clks & DSS_CLK_54M) + if (clks & DSS_CLK_TVFCK) ++num_clks; - if (clks & DSS_CLK_96M) + if (clks & DSS_CLK_VIDFCK) ++num_clks; return num_clks; @@ -845,13 +845,13 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks) if (clks & DSS_CLK_ICK) clk_enable(dss.dss_ick); - if (clks & DSS_CLK_FCK1) + if (clks & DSS_CLK_FCK) clk_enable(dss.dss1_fck); - if (clks & DSS_CLK_FCK2) + if (clks & DSS_CLK_SYSCK) clk_enable(dss.dss2_fck); - if (clks & DSS_CLK_54M) + if (clks & DSS_CLK_TVFCK) clk_enable(dss.dss_54m_fck); - if (clks & DSS_CLK_96M) + if (clks & DSS_CLK_VIDFCK) clk_enable(dss.dss_96m_fck); dss.num_clks_enabled += num_clks; @@ -873,13 +873,13 @@ static void dss_clk_disable_no_ctx(enum dss_clock clks) if (clks & DSS_CLK_ICK) clk_disable(dss.dss_ick); - if (clks & DSS_CLK_FCK1) + if (clks & DSS_CLK_FCK) clk_disable(dss.dss1_fck); - if (clks & DSS_CLK_FCK2) + if (clks & DSS_CLK_SYSCK) clk_disable(dss.dss2_fck); - if (clks & DSS_CLK_54M) + if (clks & DSS_CLK_TVFCK) clk_disable(dss.dss_54m_fck); - if (clks & DSS_CLK_96M) + if (clks & DSS_CLK_VIDFCK) clk_disable(dss.dss_96m_fck); dss.num_clks_enabled -= num_clks; @@ -903,9 +903,9 @@ static void dss_clk_enable_all_no_ctx(void) { enum dss_clock clks; - clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M; + clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; if (cpu_is_omap34xx()) - clks |= DSS_CLK_96M; + clks |= DSS_CLK_VIDFCK; dss_clk_enable_no_ctx(clks); } @@ -913,9 +913,9 @@ static void dss_clk_disable_all_no_ctx(void) { enum dss_clock clks; - clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M; + clks = DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_SYSCK | DSS_CLK_TVFCK; if (cpu_is_omap34xx()) - clks |= DSS_CLK_96M; + clks |= DSS_CLK_VIDFCK; dss_clk_disable_no_ctx(clks); } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 981d247c30f2..4b02e079f20e 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -112,11 +112,11 @@ enum omap_parallel_interface_mode { }; enum dss_clock { - DSS_CLK_ICK = 1 << 0, - DSS_CLK_FCK1 = 1 << 1, - DSS_CLK_FCK2 = 1 << 2, - DSS_CLK_54M = 1 << 3, - DSS_CLK_96M = 1 << 4, + DSS_CLK_ICK = 1 << 0, /* DSS_L3_ICLK and DSS_L4_ICLK */ + DSS_CLK_FCK = 1 << 1, /* DSS1_ALWON_FCLK */ + DSS_CLK_SYSCK = 1 << 2, /* DSS2_ALWON_FCLK */ + DSS_CLK_TVFCK = 1 << 3, /* DSS_TV_FCLK */ + DSS_CLK_VIDFCK = 1 << 4, /* DSS_96M_FCLK*/ }; enum dss_clk_source { diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 172d4e697309..1f53bf20b6cb 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -1394,7 +1394,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) } r = 0; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); if (!dss_cache.irq_enabled) { u32 mask; @@ -1407,7 +1407,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) dss_cache.irq_enabled = true; } configure_dispc(); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); spin_unlock_irqrestore(&dss_cache.lock, flags); diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 456efef03c20..996e9a4f6771 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -490,7 +490,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, ovl->manager = mgr; - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); /* XXX: on manual update display, in auto update mode, a bug happens * here. When an overlay is first enabled on LCD, then it's disabled, * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT @@ -499,7 +499,7 @@ static int omap_dss_set_manager(struct omap_overlay *ovl, * but I don't understand how or why. */ msleep(40); dispc_set_channel_out(ovl->id, mgr->id); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); return 0; } diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 6dbb95d557f8..5ea17f49c611 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -141,9 +141,9 @@ static inline u32 rfbi_read_reg(const struct rfbi_reg idx) static void rfbi_enable_clocks(bool enable) { if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } void omap_rfbi_write_command(const void *buf, u32 len) @@ -496,7 +496,7 @@ unsigned long rfbi_get_max_tx_rate(void) }; l4_rate = rfbi.l4_khz / 1000; - dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000; + dss1_rate = dss_clk_get_rate(DSS_CLK_FCK) / 1000000; for (i = 0; i < ARRAY_SIZE(ftab); i++) { /* Use a window instead of an exact match, to account @@ -921,7 +921,7 @@ void rfbi_dump_regs(struct seq_file *s) { #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); DUMPREG(RFBI_REVISION); DUMPREG(RFBI_SYSCONFIG); @@ -952,7 +952,7 @@ void rfbi_dump_regs(struct seq_file *s) DUMPREG(RFBI_VSYNC_WIDTH); DUMPREG(RFBI_HSYNC_WIDTH); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index b64adf7dfc88..8272fc1f3279 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -70,7 +70,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) /* In case of skip_init sdi_init has already enabled the clocks */ if (!sdi.skip_init) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); sdi_basic_init(dssdev); @@ -130,7 +130,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) return 0; err2: - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); regulator_disable(sdi.vdds_sdi_reg); err1: omap_dss_stop_device(dssdev); @@ -145,7 +145,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) dss_sdi_disable(); - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); regulator_disable(sdi.vdds_sdi_reg); @@ -175,7 +175,7 @@ int sdi_init(bool skip_init) * of them until sdi_display_enable is called. */ if (skip_init) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); return 0; } diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index ef36811f6ac8..1aadceb76e1d 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -391,11 +391,11 @@ static void venc_reset(void) static void venc_enable_clocks(int enable) { if (enable) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M | - DSS_CLK_96M); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | + DSS_CLK_VIDFCK); else - dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M | - DSS_CLK_96M); + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | DSS_CLK_TVFCK | + DSS_CLK_VIDFCK); } static const struct venc_config *venc_timings_to_config( -- cgit v1.2.2 From c7642f67e5bd71f91d165620f601f00c7c9802c9 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 31 Jan 2011 16:27:45 +0000 Subject: OMAP2PLUS: DSS2: Generalize external clock names in struct dss of dss.c The dss struct in dss.c has omap2/3 specific clock names. Making them generic, to increase readability and extendability. Signed-off-by: Sumit Semwal Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 82 +++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 0372befbb692..ab82f7937675 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -64,10 +64,10 @@ static struct { struct clk *dpll4_m4_ck; struct clk *dss_ick; - struct clk *dss1_fck; - struct clk *dss2_fck; - struct clk *dss_54m_fck; - struct clk *dss_96m_fck; + struct clk *dss_fck; + struct clk *dss_sys_clk; + struct clk *dss_tv_fck; + struct clk *dss_video_fck; unsigned num_clks_enabled; unsigned long cache_req_pck; @@ -750,28 +750,28 @@ static int dss_get_clocks(void) int r; dss.dss_ick = NULL; - dss.dss1_fck = NULL; - dss.dss2_fck = NULL; - dss.dss_54m_fck = NULL; - dss.dss_96m_fck = NULL; + dss.dss_fck = NULL; + dss.dss_sys_clk = NULL; + dss.dss_tv_fck = NULL; + dss.dss_video_fck = NULL; r = dss_get_clock(&dss.dss_ick, "ick"); if (r) goto err; - r = dss_get_clock(&dss.dss1_fck, "fck"); + r = dss_get_clock(&dss.dss_fck, "fck"); if (r) goto err; - r = dss_get_clock(&dss.dss2_fck, "sys_clk"); + r = dss_get_clock(&dss.dss_sys_clk, "sys_clk"); if (r) goto err; - r = dss_get_clock(&dss.dss_54m_fck, "tv_clk"); + r = dss_get_clock(&dss.dss_tv_fck, "tv_clk"); if (r) goto err; - r = dss_get_clock(&dss.dss_96m_fck, "video_clk"); + r = dss_get_clock(&dss.dss_video_fck, "video_clk"); if (r) goto err; @@ -780,25 +780,25 @@ static int dss_get_clocks(void) err: if (dss.dss_ick) clk_put(dss.dss_ick); - if (dss.dss1_fck) - clk_put(dss.dss1_fck); - if (dss.dss2_fck) - clk_put(dss.dss2_fck); - if (dss.dss_54m_fck) - clk_put(dss.dss_54m_fck); - if (dss.dss_96m_fck) - clk_put(dss.dss_96m_fck); + if (dss.dss_fck) + clk_put(dss.dss_fck); + if (dss.dss_sys_clk) + clk_put(dss.dss_sys_clk); + if (dss.dss_tv_fck) + clk_put(dss.dss_tv_fck); + if (dss.dss_video_fck) + clk_put(dss.dss_video_fck); return r; } static void dss_put_clocks(void) { - if (dss.dss_96m_fck) - clk_put(dss.dss_96m_fck); - clk_put(dss.dss_54m_fck); - clk_put(dss.dss1_fck); - clk_put(dss.dss2_fck); + if (dss.dss_video_fck) + clk_put(dss.dss_video_fck); + clk_put(dss.dss_tv_fck); + clk_put(dss.dss_fck); + clk_put(dss.dss_sys_clk); clk_put(dss.dss_ick); } @@ -808,13 +808,13 @@ unsigned long dss_clk_get_rate(enum dss_clock clk) case DSS_CLK_ICK: return clk_get_rate(dss.dss_ick); case DSS_CLK_FCK: - return clk_get_rate(dss.dss1_fck); + return clk_get_rate(dss.dss_fck); case DSS_CLK_SYSCK: - return clk_get_rate(dss.dss2_fck); + return clk_get_rate(dss.dss_sys_clk); case DSS_CLK_TVFCK: - return clk_get_rate(dss.dss_54m_fck); + return clk_get_rate(dss.dss_tv_fck); case DSS_CLK_VIDFCK: - return clk_get_rate(dss.dss_96m_fck); + return clk_get_rate(dss.dss_video_fck); } BUG(); @@ -846,13 +846,13 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks) if (clks & DSS_CLK_ICK) clk_enable(dss.dss_ick); if (clks & DSS_CLK_FCK) - clk_enable(dss.dss1_fck); + clk_enable(dss.dss_fck); if (clks & DSS_CLK_SYSCK) - clk_enable(dss.dss2_fck); + clk_enable(dss.dss_sys_clk); if (clks & DSS_CLK_TVFCK) - clk_enable(dss.dss_54m_fck); + clk_enable(dss.dss_tv_fck); if (clks & DSS_CLK_VIDFCK) - clk_enable(dss.dss_96m_fck); + clk_enable(dss.dss_video_fck); dss.num_clks_enabled += num_clks; } @@ -874,13 +874,13 @@ static void dss_clk_disable_no_ctx(enum dss_clock clks) if (clks & DSS_CLK_ICK) clk_disable(dss.dss_ick); if (clks & DSS_CLK_FCK) - clk_disable(dss.dss1_fck); + clk_disable(dss.dss_fck); if (clks & DSS_CLK_SYSCK) - clk_disable(dss.dss2_fck); + clk_disable(dss.dss_sys_clk); if (clks & DSS_CLK_TVFCK) - clk_disable(dss.dss_54m_fck); + clk_disable(dss.dss_tv_fck); if (clks & DSS_CLK_VIDFCK) - clk_disable(dss.dss_96m_fck); + clk_disable(dss.dss_video_fck); dss.num_clks_enabled -= num_clks; } @@ -926,10 +926,10 @@ static void core_dump_clocks(struct seq_file *s) int i; struct clk *clocks[5] = { dss.dss_ick, - dss.dss1_fck, - dss.dss2_fck, - dss.dss_54m_fck, - dss.dss_96m_fck + dss.dss_fck, + dss.dss_sys_clk, + dss.dss_tv_fck, + dss.dss_video_fck }; seq_printf(s, "- CORE -\n"); -- cgit v1.2.2 From 3f3aa06c46796cd2dc0f71d7d2f41bb75f7e97ff Mon Sep 17 00:00:00 2001 From: Mayuresh Janorkar Date: Tue, 15 Feb 2011 22:54:29 -0600 Subject: OMAP2PLUS: DSS2: Add OMAP4 Kconfig support Enable DSS2 and OMAPFB for OMAP4 in Kconfig Signed-off-by: Mayuresh Janorkar Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/Kconfig | 6 +++--- drivers/video/omap2/omapfb/Kconfig | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 43b64403eaa4..db01473c3307 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -1,8 +1,8 @@ menuconfig OMAP2_DSS - tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)" - depends on ARCH_OMAP2 || ARCH_OMAP3 + tristate "OMAP2+ Display Subsystem support (EXPERIMENTAL)" + depends on ARCH_OMAP2PLUS help - OMAP2/3 Display Subsystem support. + OMAP2+ Display Subsystem support. if OMAP2_DSS diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index 65149b22cf37..aa33386c81ff 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig @@ -1,5 +1,5 @@ menuconfig FB_OMAP2 - tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)" + tristate "OMAP2+ frame buffer support (EXPERIMENTAL)" depends on FB && OMAP2_DSS select OMAP2_VRAM @@ -8,10 +8,10 @@ menuconfig FB_OMAP2 select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT help - Frame buffer driver for OMAP2/3 based boards. + Frame buffer driver for OMAP2+ based boards. config FB_OMAP2_DEBUG_SUPPORT - bool "Debug support for OMAP2/3 FB" + bool "Debug support for OMAP2+ FB" default y depends on FB_OMAP2 help -- cgit v1.2.2 From ac425ed5fb0b6564d4eeee9fb13ef0c1f6da8e8f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 16 Feb 2011 04:53:44 -0600 Subject: OMAP: DSS2: Fix def_disp module param description MODULE_PARM_DESC() takes the name of the actual module parameter, not the name of the variable, as input. Fix the module parameter description for def_disp. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index f56ee64f5b58..bcf69a462b5f 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -47,7 +47,7 @@ static struct { static char *def_disp_name; module_param_named(def_disp, def_disp_name, charp, 0); -MODULE_PARM_DESC(def_disp_name, "default display name"); +MODULE_PARM_DESC(def_disp, "default display name"); #ifdef DEBUG unsigned int dss_debug; -- cgit v1.2.2 From 5f42f2ce63f5ecbd9bc744b9c25d9786e9a8e3b4 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 22 Feb 2011 15:53:46 +0200 Subject: OMAP: DSS2: Delay regulator_get() calls DSS submodules DPI/SDI/DSI/VENC require a regulator to function. However, if the board doesn't use, say, SDI, the board shouldn't need to configure vdds_sdi regulator required by the SDI module. Currently the regulators are acquired when the DSS driver is loaded. This means that if the kernel is configured with SDI, vdds_sdi regulator is needed for all boards. This patch changes the DSS driver to acquire the regulators only when a display of particular type is initialized. For example, vdds_sdi is acquired when sdi_init_display() is called. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dpi.c | 21 +++++++++++++-------- drivers/video/omap2/dss/dsi.c | 36 +++++++++++++----------------------- drivers/video/omap2/dss/sdi.c | 18 +++++++++++++----- drivers/video/omap2/dss/venc.c | 31 +++++++++++++------------------ 4 files changed, 52 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 746f1b6dd897..026702b921e5 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -303,22 +303,27 @@ int dpi_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); - return 0; -} + if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) { + struct regulator *vdds_dsi; -int dpi_init(struct platform_device *pdev) -{ - if (cpu_is_omap34xx()) { - dpi.vdds_dsi_reg = dss_get_vdds_dsi(); - if (IS_ERR(dpi.vdds_dsi_reg)) { + vdds_dsi = dss_get_vdds_dsi(); + + if (IS_ERR(vdds_dsi)) { DSSERR("can't get VDDS_DSI regulator\n"); - return PTR_ERR(dpi.vdds_dsi_reg); + return PTR_ERR(vdds_dsi); } + + dpi.vdds_dsi_reg = vdds_dsi; } return 0; } +int dpi_init(struct platform_device *pdev) +{ + return 0; +} + void dpi_exit(void) { } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index c7b5382e1a6b..2928cddeb3fc 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -291,20 +291,6 @@ static inline u32 dsi_read_reg(const struct dsi_reg idx) return __raw_readl(dsi.base + idx.idx); } -static struct regulator *dsi_get_vdds_dsi(void) -{ - struct regulator *reg; - - if (dsi.vdds_dsi_reg != NULL) - return dsi.vdds_dsi_reg; - - reg = regulator_get(&dsi.pdev->dev, "vdds_dsi"); - if (!IS_ERR(reg)) - dsi.vdds_dsi_reg = reg; - - return reg; -} - void dsi_save_context(void) { @@ -3236,6 +3222,19 @@ int dsi_init_display(struct omap_dss_device *dssdev) dsi.vc[0].dssdev = dssdev; dsi.vc[1].dssdev = dssdev; + if (dsi.vdds_dsi_reg == NULL) { + struct regulator *vdds_dsi; + + vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi"); + + if (IS_ERR(vdds_dsi)) { + DSSERR("can't get VDDS_DSI regulator\n"); + return PTR_ERR(vdds_dsi); + } + + dsi.vdds_dsi_reg = vdds_dsi; + } + return 0; } @@ -3295,13 +3294,6 @@ static int dsi_init(struct platform_device *pdev) goto err1; } - dsi.vdds_dsi_reg = dsi_get_vdds_dsi(); - if (IS_ERR(dsi.vdds_dsi_reg)) { - DSSERR("can't get VDDS_DSI regulator\n"); - r = PTR_ERR(dsi.vdds_dsi_reg); - goto err2; - } - enable_clocks(1); rev = dsi_read_reg(DSI_REVISION); @@ -3311,8 +3303,6 @@ static int dsi_init(struct platform_device *pdev) enable_clocks(0); return 0; -err2: - iounmap(dsi.base); err1: destroy_workqueue(dsi.workqueue); return r; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 8272fc1f3279..9f10a0d9e760 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -157,6 +157,19 @@ int sdi_init_display(struct omap_dss_device *dssdev) { DSSDBG("SDI init\n"); + if (sdi.vdds_sdi_reg == NULL) { + struct regulator *vdds_sdi; + + vdds_sdi = dss_get_vdds_sdi(); + + if (IS_ERR(vdds_sdi)) { + DSSERR("can't get VDDS_SDI regulator\n"); + return PTR_ERR(vdds_sdi); + } + + sdi.vdds_sdi_reg = vdds_sdi; + } + return 0; } @@ -165,11 +178,6 @@ int sdi_init(bool skip_init) /* we store this for first display enable, then clear it */ sdi.skip_init = skip_init; - sdi.vdds_sdi_reg = dss_get_vdds_sdi(); - if (IS_ERR(sdi.vdds_sdi_reg)) { - DSSERR("can't get VDDS_SDI regulator\n"); - return PTR_ERR(sdi.vdds_sdi_reg); - } /* * Enable clocks already here, otherwise there would be a toggle * of them until sdi_display_enable is called. diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 1aadceb76e1d..43009e57cd3e 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -305,17 +305,6 @@ static inline u32 venc_read_reg(int idx) return l; } -static struct regulator *venc_get_vdda_dac(void) -{ - struct regulator *reg; - - reg = regulator_get(&venc.pdev->dev, "vdda_dac"); - if (!IS_ERR(reg)) - venc.vdda_dac_reg = reg; - - return reg; -} - static void venc_write_config(const struct venc_config *config) { DSSDBG("write venc conf\n"); @@ -655,6 +644,19 @@ int venc_init_display(struct omap_dss_device *dssdev) { DSSDBG("init_display\n"); + if (venc.vdda_dac_reg == NULL) { + struct regulator *vdda_dac; + + vdda_dac = regulator_get(&venc.pdev->dev, "vdda_dac"); + + if (IS_ERR(vdda_dac)) { + DSSERR("can't get VDDA_DAC regulator\n"); + return PTR_ERR(vdda_dac); + } + + venc.vdda_dac_reg = vdda_dac; + } + return 0; } @@ -734,13 +736,6 @@ static int omap_venchw_probe(struct platform_device *pdev) return -ENOMEM; } - venc.vdda_dac_reg = venc_get_vdda_dac(); - if (IS_ERR(venc.vdda_dac_reg)) { - iounmap(venc.base); - DSSERR("can't get VDDA_DAC regulator\n"); - return PTR_ERR(venc.vdda_dac_reg); - } - venc_enable_clocks(1); rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); -- cgit v1.2.2 From 09dc89cb3123d102e1615fab9e3d65a70402d061 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 22 Feb 2011 16:39:47 +0200 Subject: OMAP: DSS2: Support for Samsung LTE430WQ-F0C Add support for Samsung LTE430WQ-F0C to panel-generic-dpi. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-generic-dpi.c | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 07eb30ee59c8..4a9b9ff59467 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c @@ -156,6 +156,31 @@ static struct panel_config generic_dpi_panels[] = { .power_off_delay = 0, .name = "toppoly_tdo35s", }, + + /* Samsung LTE430WQ-F0C */ + { + { + .x_res = 480, + .y_res = 272, + + .pixel_clock = 9200, + + .hfp = 8, + .hsw = 41, + .hbp = 45 - 41, + + .vfp = 4, + .vsw = 10, + .vbp = 12 - 10, + }, + .acbi = 0x0, + .acb = 0x0, + .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS, + .power_on_delay = 0, + .power_off_delay = 0, + .name = "samsung_lte430wq_f0c", + }, }; struct panel_drv_data { -- cgit v1.2.2 From 371e2081447ce2bc6a25c20b513b9ba33cf5769e Mon Sep 17 00:00:00 2001 From: "Janorkar, Mayuresh" Date: Tue, 22 Feb 2011 07:35:13 -0600 Subject: OMAPFB: Adding a check for timings in set_def_mode When omapfb.mode is passed through bootargs, when omapfb is setting mode, it would check if timings passed are fine for panel attached to it. It makes use of check_timing API provided by the panel. In current code if check_timing API is not available for attached panel, OMAPFB would return -EINVAL and BPP sent via bootargs will not have any effect. In case of panels like TAAL panel, omapfb or any other driver should not be allowed to change the timings. So bpps sent via bootargs will not have an effect. In such case we can check only the x_res and y_res with the panels resolution and if they match go ahead and set the bpps. The bpp value sent via bootarg would have an effect. Signed-off-by: Mayuresh Janorkar Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 4fdab8e9c496..505ec6672049 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2090,7 +2090,7 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, { int r; u8 bpp; - struct omap_video_timings timings; + struct omap_video_timings timings, temp_timings; r = omapfb_mode_to_timings(mode_str, &timings, &bpp); if (r) @@ -2100,14 +2100,23 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, fbdev->bpp_overrides[fbdev->num_bpp_overrides].bpp = bpp; ++fbdev->num_bpp_overrides; - if (!display->driver->check_timings || !display->driver->set_timings) - return -EINVAL; + if (display->driver->check_timings) { + r = display->driver->check_timings(display, &timings); + if (r) + return r; + } else { + /* If check_timings is not present compare xres and yres */ + if (display->driver->get_timings) { + display->driver->get_timings(display, &temp_timings); - r = display->driver->check_timings(display, &timings); - if (r) - return r; + if (temp_timings.x_res != timings.x_res || + temp_timings.y_res != timings.y_res) + return -EINVAL; + } + } - display->driver->set_timings(display, &timings); + if (display->driver->set_timings) + display->driver->set_timings(display, &timings); return 0; } -- cgit v1.2.2 From affe360d13e54b415cde2f11cee02369b4ed54bd Mon Sep 17 00:00:00 2001 From: archit taneja Date: Wed, 23 Feb 2011 08:41:03 +0000 Subject: OMAP: DSS2: Have separate irq handlers for DISPC and DSI Currently, the core DSS platform device requests for an irq line for OMAP2 and OMAP3. Make DISPC and DSI platform devices request for a shared IRQ line. On OMAP3, the logical OR of DSI and DISPC interrupt lines goes to the MPU. There is a register DSS_IRQSTATUS which tells if the interrupt came from DISPC or DSI. On OMAP2, there is no DSI, only DISPC interrupts goto the MPU. There is no DSS_IRQSTATUS register. Hence, it makes more sense to have separate irq handlers corresponding to the DSS sub modules instead of having a common handler. Since on OMAP3 the logical OR of the lines goes to MPU, the irq line is shared among the IRQ handlers. The hwmod irq info has been removed for DSS to DISPC and DSI for OMAP2 and OMAP3 hwmod databases. The Probes of DISPC and DSI now request for irq handlers. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 40 ++++++++++++++++++++++++++++---- drivers/video/omap2/dss/dsi.c | 25 ++++++++++++++++++-- drivers/video/omap2/dss/dss.c | 51 +---------------------------------------- 3 files changed, 60 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index dc4518c4b0e4..43f7091c71cb 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -178,6 +179,7 @@ struct dispc_irq_stats { static struct { struct platform_device *pdev; void __iomem *base; + int irq; u32 fifo_size[3]; @@ -2865,10 +2867,10 @@ static void print_irq_status(u32 status) * but we presume they are on because we got an IRQ. However, * an irq handler may turn the clocks off, so we may not have * clock later in the function. */ -void dispc_irq_handler(void) +static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) { int i; - u32 irqstatus; + u32 irqstatus, irqenable; u32 handledirqs = 0; u32 unhandled_errors; struct omap_dispc_isr_data *isr_data; @@ -2877,6 +2879,13 @@ void dispc_irq_handler(void) spin_lock(&dispc.irq_lock); irqstatus = dispc_read_reg(DISPC_IRQSTATUS); + irqenable = dispc_read_reg(DISPC_IRQENABLE); + + /* IRQ is not for us */ + if (!(irqstatus & irqenable)) { + spin_unlock(&dispc.irq_lock); + return IRQ_NONE; + } #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spin_lock(&dispc.irq_stats_lock); @@ -2928,6 +2937,8 @@ void dispc_irq_handler(void) } spin_unlock(&dispc.irq_lock); + + return IRQ_HANDLED; } static void dispc_error_worker(struct work_struct *work) @@ -3322,6 +3333,7 @@ int dispc_setup_plane(enum omap_plane plane, static int omap_dispchw_probe(struct platform_device *pdev) { u32 rev; + int r = 0; struct resource *dispc_mem; dispc.pdev = pdev; @@ -3338,12 +3350,27 @@ static int omap_dispchw_probe(struct platform_device *pdev) dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); if (!dispc_mem) { DSSERR("can't get IORESOURCE_MEM DISPC\n"); - return -EINVAL; + r = -EINVAL; + goto fail0; } dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); if (!dispc.base) { DSSERR("can't ioremap DISPC\n"); - return -ENOMEM; + r = -ENOMEM; + goto fail0; + } + dispc.irq = platform_get_irq(dispc.pdev, 0); + if (dispc.irq < 0) { + DSSERR("platform_get_irq failed\n"); + r = -ENODEV; + goto fail1; + } + + r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, + "OMAP DISPC", dispc.pdev); + if (r < 0) { + DSSERR("request_irq failed\n"); + goto fail1; } enable_clocks(1); @@ -3361,10 +3388,15 @@ static int omap_dispchw_probe(struct platform_device *pdev) enable_clocks(0); return 0; +fail1: + iounmap(dispc.base); +fail0: + return r; } static int omap_dispchw_remove(struct platform_device *pdev) { + free_irq(dispc.irq, dispc.pdev); iounmap(dispc.base); return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 2928cddeb3fc..2f7d9491cd02 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -222,6 +222,7 @@ static struct { struct platform_device *pdev; void __iomem *base; + int irq; struct dsi_clock_info current_cinfo; @@ -480,13 +481,17 @@ static void print_irq_status_cio(u32 status) static int debug_irq; /* called from dss */ -void dsi_irq_handler(void) +static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) { u32 irqstatus, vcstatus, ciostatus; int i; irqstatus = dsi_read_reg(DSI_IRQSTATUS); + /* IRQ is not for us */ + if (!irqstatus) + return IRQ_NONE; + #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spin_lock(&dsi.irq_stats_lock); dsi.irq_stats.irq_count++; @@ -564,9 +569,9 @@ void dsi_irq_handler(void) #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spin_unlock(&dsi.irq_stats_lock); #endif + return IRQ_HANDLED; } - static void _dsi_initialize_irq(void) { u32 l; @@ -3293,6 +3298,19 @@ static int dsi_init(struct platform_device *pdev) r = -ENOMEM; goto err1; } + dsi.irq = platform_get_irq(dsi.pdev, 0); + if (dsi.irq < 0) { + DSSERR("platform_get_irq failed\n"); + r = -ENODEV; + goto err2; + } + + r = request_irq(dsi.irq, omap_dsi_irq_handler, IRQF_SHARED, + "OMAP DSI1", dsi.pdev); + if (r < 0) { + DSSERR("request_irq failed\n"); + goto err2; + } enable_clocks(1); @@ -3303,6 +3321,8 @@ static int dsi_init(struct platform_device *pdev) enable_clocks(0); return 0; +err2: + iounmap(dsi.base); err1: destroy_workqueue(dsi.workqueue); return r; @@ -3315,6 +3335,7 @@ static void dsi_exit(void) dsi.vdds_dsi_reg = NULL; } + free_irq(dsi.irq, dsi.pdev); iounmap(dsi.base); destroy_workqueue(dsi.workqueue); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index ab82f7937675..dc57100cc43d 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -79,7 +78,6 @@ static struct { enum dss_clk_source dispc_clk_source; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; - int dss_irq; } dss; static void dss_clk_enable_all_no_ctx(void); @@ -495,31 +493,6 @@ found: return 0; } - - -static irqreturn_t dss_irq_handler_omap2(int irq, void *arg) -{ - dispc_irq_handler(); - - return IRQ_HANDLED; -} - -static irqreturn_t dss_irq_handler_omap3(int irq, void *arg) -{ - u32 irqstatus; - - irqstatus = dss_read_reg(DSS_IRQSTATUS); - - if (irqstatus & (1<<0)) /* DISPC_IRQ */ - dispc_irq_handler(); -#ifdef CONFIG_OMAP2_DSS_DSI - if (irqstatus & (1<<1)) /* DSI_IRQ */ - dsi_irq_handler(); -#endif - - return IRQ_HANDLED; -} - static int _omap_dss_wait_reset(void) { int t = 0; @@ -610,30 +583,12 @@ static int dss_init(bool skip_init) REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ #endif - dss.dss_irq = platform_get_irq(dss.pdev, 0); - if (dss.dss_irq < 0) { - DSSERR("omap2 dss: platform_get_irq failed\n"); - r = -ENODEV; - goto fail1; - } - - r = request_irq(dss.dss_irq, - cpu_is_omap24xx() - ? dss_irq_handler_omap2 - : dss_irq_handler_omap3, - 0, "OMAP DSS", NULL); - - if (r < 0) { - DSSERR("omap2 dss: request_irq failed\n"); - goto fail1; - } - if (cpu_is_omap34xx()) { dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); if (IS_ERR(dss.dpll4_m4_ck)) { DSSERR("Failed to get dpll4_m4_ck\n"); r = PTR_ERR(dss.dpll4_m4_ck); - goto fail2; + goto fail1; } } @@ -648,8 +603,6 @@ static int dss_init(bool skip_init) return 0; -fail2: - free_irq(dss.dss_irq, NULL); fail1: iounmap(dss.base); fail0: @@ -661,8 +614,6 @@ static void dss_exit(void) if (cpu_is_omap34xx()) clk_put(dss.dpll4_m4_ck); - free_irq(dss.dss_irq, NULL); - iounmap(dss.base); } -- cgit v1.2.2 From e528e3a8b4e005e6e2c9e50fdee1ab7e84cf1e27 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 24 Feb 2011 13:59:13 +0200 Subject: OMAP: DSS2: Clean up a switch-case Support for the display interface was checked in a separate switch-case. There's no reason for that, and this patch handles the fail code path in the same switch-case where the display initialization is done. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/display.c | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 22dd7a474f79..3f4fa0b08460 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -393,29 +393,6 @@ void dss_init_device(struct platform_device *pdev, int i; int r; - switch (dssdev->type) { -#ifdef CONFIG_OMAP2_DSS_DPI - case OMAP_DISPLAY_TYPE_DPI: -#endif -#ifdef CONFIG_OMAP2_DSS_RFBI - case OMAP_DISPLAY_TYPE_DBI: -#endif -#ifdef CONFIG_OMAP2_DSS_SDI - case OMAP_DISPLAY_TYPE_SDI: -#endif -#ifdef CONFIG_OMAP2_DSS_DSI - case OMAP_DISPLAY_TYPE_DSI: -#endif -#ifdef CONFIG_OMAP2_DSS_VENC - case OMAP_DISPLAY_TYPE_VENC: -#endif - break; - default: - DSSERR("Support for display '%s' not compiled in.\n", - dssdev->name); - return; - } - switch (dssdev->type) { #ifdef CONFIG_OMAP2_DSS_DPI case OMAP_DISPLAY_TYPE_DPI: @@ -443,7 +420,9 @@ void dss_init_device(struct platform_device *pdev, break; #endif default: - BUG(); + DSSERR("Support for display '%s' not compiled in.\n", + dssdev->name); + return; } if (r) { -- cgit v1.2.2 From 4e777dd765b7c10eb66532330cf3fe6ae0b477b0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 24 Feb 2011 14:20:31 +0200 Subject: OMAP: DSS2: FEATURES: Remove SDI from 3630 displays OMAP 3630 does not support SDI. Split omap3_dss_supported_displays into 3430 and 3630 entries, and remove the SDI from 3630 entry. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss_features.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index cf3ef696e141..f4367f6564a2 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -73,7 +73,7 @@ static const enum omap_display_type omap2_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_VENC, }; -static const enum omap_display_type omap3_dss_supported_displays[] = { +static const enum omap_display_type omap3430_dss_supported_displays[] = { /* OMAP_DSS_CHANNEL_LCD */ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI, @@ -82,6 +82,15 @@ static const enum omap_display_type omap3_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_VENC, }; +static const enum omap_display_type omap3630_dss_supported_displays[] = { + /* OMAP_DSS_CHANNEL_LCD */ + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | + OMAP_DISPLAY_TYPE_DSI, + + /* OMAP_DSS_CHANNEL_DIGIT */ + OMAP_DISPLAY_TYPE_VENC, +}; + static const enum omap_display_type omap4_dss_supported_displays[] = { /* OMAP_DSS_CHANNEL_LCD */ OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, @@ -161,7 +170,7 @@ static struct omap_dss_features omap3430_dss_features = { .num_mgrs = 2, .num_ovls = 3, - .supported_displays = omap3_dss_supported_displays, + .supported_displays = omap3430_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, }; @@ -176,7 +185,7 @@ static struct omap_dss_features omap3630_dss_features = { .num_mgrs = 2, .num_ovls = 3, - .supported_displays = omap3_dss_supported_displays, + .supported_displays = omap3630_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, }; -- cgit v1.2.2 From f8df01f1a47ea6e503f5ba8d782fc6fb53bb40e8 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 24 Feb 2011 14:21:25 +0200 Subject: OMAP: DSS2: FEATURES: Remove DSI & SDI from OMAP2 OMAP2 doesn't support SDI or DSI. Remove them from omap2_dss_supported_displays. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss_features.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index f4367f6564a2..fe22d11068bd 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -66,8 +66,7 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = { static const enum omap_display_type omap2_dss_supported_displays[] = { /* OMAP_DSS_CHANNEL_LCD */ - OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | - OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI, + OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, /* OMAP_DSS_CHANNEL_DIGIT */ OMAP_DISPLAY_TYPE_VENC, -- cgit v1.2.2 From 6ec549e50b192105ede7bb289a31da6f6e1a61e9 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 24 Feb 2011 14:18:50 +0200 Subject: OMAP: DSS2: Check for SDI HW before accessing SDI registers Only OMAP 3430 hardware has SDI support. The availability of SDI HW can be found out by checking if the LCD channel supports SDI displays. This patch checks for SDI HW support before accessing SDI registers, which fixes a crash on OMAP4 when SDI SW support is compiled in. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index dc57100cc43d..50c18677684d 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -32,6 +32,7 @@ #include #include #include "dss.h" +#include "dss_features.h" #define DSS_SZ_REGS SZ_512 @@ -110,10 +111,11 @@ void dss_save_context(void) SR(SYSCONFIG); SR(CONTROL); -#ifdef CONFIG_OMAP2_DSS_SDI - SR(SDI_CONTROL); - SR(PLL_CONTROL); -#endif + if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & + OMAP_DISPLAY_TYPE_SDI) { + SR(SDI_CONTROL); + SR(PLL_CONTROL); + } } void dss_restore_context(void) @@ -124,10 +126,11 @@ void dss_restore_context(void) RR(SYSCONFIG); RR(CONTROL); -#ifdef CONFIG_OMAP2_DSS_SDI - RR(SDI_CONTROL); - RR(PLL_CONTROL); -#endif + if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & + OMAP_DISPLAY_TYPE_SDI) { + RR(SDI_CONTROL); + RR(PLL_CONTROL); + } } #undef SR @@ -259,9 +262,13 @@ void dss_dump_regs(struct seq_file *s) DUMPREG(DSS_SYSSTATUS); DUMPREG(DSS_IRQSTATUS); DUMPREG(DSS_CONTROL); - DUMPREG(DSS_SDI_CONTROL); - DUMPREG(DSS_PLL_CONTROL); - DUMPREG(DSS_SDI_STATUS); + + if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & + OMAP_DISPLAY_TYPE_SDI) { + DUMPREG(DSS_SDI_CONTROL); + DUMPREG(DSS_PLL_CONTROL); + DUMPREG(DSS_SDI_STATUS); + } dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); #undef DUMPREG -- cgit v1.2.2 From 0897cc21036c4da0337d8ebcbe7d4b7bb81cf2ca Mon Sep 17 00:00:00 2001 From: "Janorkar, Mayuresh" Date: Thu, 24 Feb 2011 03:39:17 -0600 Subject: OMAP: OMAPFB: Adding help for FB_OMAP_LCD_VGA option CONFIG_FB_OMAP_LCD_VGA option is present in drivers/video/omap There is no explaination about what this flag does. Lets add information about it. FB_OMAP_LCD_VGA flag sets resolution of display to VGA (640 X 480). The default resolution of 3430 LDP is 320 X 240. Signed-off-by: Mayuresh Janorkar Signed-off-by: Tomi Valkeinen --- drivers/video/omap/Kconfig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index 083c8fe53e24..ff7049b2cc8f 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig @@ -11,7 +11,11 @@ config FB_OMAP config FB_OMAP_LCD_VGA bool "Use LCD in VGA mode" depends on MACH_OMAP_3430SDP || MACH_OMAP_LDP - + help + Set LCD resolution as VGA (640 X 480). + Default resolution without this option is QVGA(320 X 240). + Please take a look at drivers/video/omap/lcd_ldp.c file + for lcd driver code. choice depends on FB_OMAP && MACH_OVERO prompt "Screen resolution" -- cgit v1.2.2 From 4a0ab8df3e35da4d12df0631b2daae683dafe46c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 28 Oct 2010 15:29:33 +0300 Subject: OMAP: DSS2: Remove unused list There was an unused list defined in display.c. Remove it. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/display.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 3f4fa0b08460..7d96b724c992 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -25,14 +25,11 @@ #include #include #include -#include #include #include #include "dss.h" -static LIST_HEAD(display_list); - static ssize_t display_enabled_show(struct device *dev, struct device_attribute *attr, char *buf) { -- cgit v1.2.2 From 4b6b7fa2d3677d1d86780c73fe2284147713e3b1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Jun 2010 15:09:37 +0300 Subject: OMAP: DSS2: DSI: remove unused function dsi_reset_tx_fifo() was not used. Furthermore, OMAP errata states that TX FIFO flush is not functional, so the function wouldn't even have worked. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 2f7d9491cd02..c3019d95618d 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1626,20 +1626,6 @@ static int _dsi_reset(void) return _dsi_wait_reset(); } -static void dsi_reset_tx_fifo(int channel) -{ - u32 mask; - u32 l; - - /* set fifosize of the channel to 0, then return the old size */ - l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE); - - mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4); - dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask); - - dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l); -} - static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2, enum fifo_size size3, enum fifo_size size4) { -- cgit v1.2.2 From a1a0dccaea9e036200dc0b1070af1bfae06690fb Mon Sep 17 00:00:00 2001 From: "Semwal, Sumit" Date: Tue, 1 Mar 2011 02:42:14 -0600 Subject: OMAP2PLUS:DSS2: Use opt_clock_available from pdata hwmod databases provide information about which optional clocks are available for a given platform. This is available via a function pointer opt_clock_enable in pdata. Use this information during get/enable/disable/put of clocks. Signed-off-by: Sumit Semwal Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 46 ++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 50c18677684d..0cf5f8bd1c8a 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -706,6 +706,7 @@ static int dss_get_clock(struct clk **clock, const char *clk_name) static int dss_get_clocks(void) { int r; + struct omap_display_platform_data *pdata = dss.pdev->dev.platform_data; dss.dss_ick = NULL; dss.dss_fck = NULL; @@ -721,17 +722,28 @@ static int dss_get_clocks(void) if (r) goto err; - r = dss_get_clock(&dss.dss_sys_clk, "sys_clk"); - if (r) + if (!pdata->opt_clock_available) { + r = -ENODEV; goto err; + } - r = dss_get_clock(&dss.dss_tv_fck, "tv_clk"); - if (r) - goto err; + if (pdata->opt_clock_available("sys_clk")) { + r = dss_get_clock(&dss.dss_sys_clk, "sys_clk"); + if (r) + goto err; + } - r = dss_get_clock(&dss.dss_video_fck, "video_clk"); - if (r) - goto err; + if (pdata->opt_clock_available("tv_clk")) { + r = dss_get_clock(&dss.dss_tv_fck, "tv_clk"); + if (r) + goto err; + } + + if (pdata->opt_clock_available("video_clk")) { + r = dss_get_clock(&dss.dss_video_fck, "video_clk"); + if (r) + goto err; + } return 0; @@ -754,9 +766,11 @@ static void dss_put_clocks(void) { if (dss.dss_video_fck) clk_put(dss.dss_video_fck); - clk_put(dss.dss_tv_fck); + if (dss.dss_tv_fck) + clk_put(dss.dss_tv_fck); + if (dss.dss_sys_clk) + clk_put(dss.dss_sys_clk); clk_put(dss.dss_fck); - clk_put(dss.dss_sys_clk); clk_put(dss.dss_ick); } @@ -805,11 +819,11 @@ static void dss_clk_enable_no_ctx(enum dss_clock clks) clk_enable(dss.dss_ick); if (clks & DSS_CLK_FCK) clk_enable(dss.dss_fck); - if (clks & DSS_CLK_SYSCK) + if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) clk_enable(dss.dss_sys_clk); - if (clks & DSS_CLK_TVFCK) + if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) clk_enable(dss.dss_tv_fck); - if (clks & DSS_CLK_VIDFCK) + if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) clk_enable(dss.dss_video_fck); dss.num_clks_enabled += num_clks; @@ -833,11 +847,11 @@ static void dss_clk_disable_no_ctx(enum dss_clock clks) clk_disable(dss.dss_ick); if (clks & DSS_CLK_FCK) clk_disable(dss.dss_fck); - if (clks & DSS_CLK_SYSCK) + if ((clks & DSS_CLK_SYSCK) && dss.dss_sys_clk) clk_disable(dss.dss_sys_clk); - if (clks & DSS_CLK_TVFCK) + if ((clks & DSS_CLK_TVFCK) && dss.dss_tv_fck) clk_disable(dss.dss_tv_fck); - if (clks & DSS_CLK_VIDFCK) + if ((clks & DSS_CLK_VIDFCK) && dss.dss_video_fck) clk_disable(dss.dss_video_fck); dss.num_clks_enabled -= num_clks; -- cgit v1.2.2 From 08a0a657949e723f0cbb6a33b1c706134d5a6d78 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Tue, 1 Mar 2011 02:40:37 -0600 Subject: omapfb: Fix linker error in drivers/video/omap/lcd_2430sdp.c There is a linker error from lcd_2430sdp.c if CONFIG_TWL4030_CORE is not set. This can be triggered on OMAP2 builds when OMAP3 or OMAP4 are not set. drivers/built-in.o: In function `sdp2430_panel_disable': drivers/video/omap/lcd_2430sdp.c:123: undefined reference to `twl_i2c_write_u8' drivers/video/omap/lcd_2430sdp.c:124: undefined reference to `twl_i2c_write_u8' drivers/built-in.o: In function `sdp2430_panel_enable': drivers/video/omap/lcd_2430sdp.c:110: undefined reference to `twl_i2c_write_u8' drivers/video/omap/lcd_2430sdp.c:112: undefined reference to `twl_i2c_write_u8' Fix this by selecting the TWL4030_CORE for MACH_OMAP_2430SDP when building with CONFIG_FB_OMAP as there is no own Kconfig entry for lcd_2430 and it is compiled always when both MACH_OMAP_2430SDP and FB_OMAP are set. Signed-off-by: Jarkko Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index ff7049b2cc8f..15e7f1912af9 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig @@ -5,6 +5,7 @@ config FB_OMAP select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select TWL4030_CORE if MACH_OMAP_2430SDP help Frame buffer driver for OMAP based boards. -- cgit v1.2.2 From 87a7484b6a9ceaa9e7a9a238154b02ed4495f26a Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 2 Mar 2011 11:19:50 +0530 Subject: OMAP2PLUS: DSS2: FEATURES: DISPC overlay code cleanup Add dss_features and register fields to incorporate changes in DISPC pipelines between OMAP3 and OMAP4. Register fields added: FEAT_REG_HORIZONTALACCU, FEAT_REG_VERTICALACCU DSS Features added: FEAT_LINEBUFFERSPLIT, FEAT_ROWREPEATENABLE, FEAT_RESIZECONF _dispc_set_scaling() and _dispc_set_rotation_attrs() have been cleaned up. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 52 ++++++++++++++++++++++++---------- drivers/video/omap2/dss/dss_features.c | 30 ++++++++++++++++---- drivers/video/omap2/dss/dss_features.h | 5 ++++ 3 files changed, 66 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 43f7091c71cb..aa6479712d4c 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1130,10 +1130,16 @@ static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) u32 val; const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0), DISPC_VID_ACCU0(1) }; + u8 hor_start, hor_end, vert_start, vert_end; BUG_ON(plane == OMAP_DSS_GFX); - val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0); + dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); + dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); + + val = FLD_VAL(vaccu, vert_start, vert_end) | + FLD_VAL(haccu, hor_start, hor_end); + dispc_write_reg(ac0_reg[plane-1], val); } @@ -1142,10 +1148,16 @@ static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) u32 val; const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0), DISPC_VID_ACCU1(1) }; + u8 hor_start, hor_end, vert_start, vert_end; BUG_ON(plane == OMAP_DSS_GFX); - val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0); + dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end); + dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end); + + val = FLD_VAL(vaccu, vert_start, vert_end) | + FLD_VAL(haccu, hor_start, hor_end); + dispc_write_reg(ac1_reg[plane-1], val); } @@ -1183,16 +1195,25 @@ static void _dispc_set_scaling(enum omap_plane plane, _dispc_set_fir(plane, fir_hinc, fir_vinc); l = dispc_read_reg(dispc_reg_att[plane]); - l &= ~((0x0f << 5) | (0x3 << 21)); + /* RESIZEENABLE and VERTICALTAPS */ + l &= ~((0x3 << 5) | (0x1 << 21)); l |= fir_hinc ? (1 << 5) : 0; l |= fir_vinc ? (1 << 6) : 0; + l |= five_taps ? (1 << 21) : 0; - l |= hscaleup ? 0 : (1 << 7); - l |= vscaleup ? 0 : (1 << 8); + /* VRESIZECONF and HRESIZECONF */ + if (dss_has_feature(FEAT_RESIZECONF)) { + l &= ~(0x3 << 7); + l |= hscaleup ? 0 : (1 << 7); + l |= vscaleup ? 0 : (1 << 8); + } - l |= five_taps ? (1 << 21) : 0; - l |= five_taps ? (1 << 22) : 0; + /* LINEBUFFERSPLIT */ + if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) { + l &= ~(0x1 << 22); + l |= five_taps ? (1 << 22) : 0; + } dispc_write_reg(dispc_reg_att[plane], l); @@ -1216,9 +1237,11 @@ static void _dispc_set_scaling(enum omap_plane plane, static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, bool mirroring, enum omap_color_mode color_mode) { + bool row_repeat = false; + int vidrot = 0; + if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY) { - int vidrot = 0; if (mirroring) { switch (rotation) { @@ -1252,16 +1275,15 @@ static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, } } - REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12); - if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270) - REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18); + row_repeat = true; else - REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18); - } else { - REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12); - REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18); + row_repeat = false; } + + REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12); + if (dss_has_feature(FEAT_ROWREPEATENABLE)) + REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18); } static int color_mode_to_bpp(enum omap_color_mode color_mode) diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index fe22d11068bd..679be14b73a8 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -54,6 +54,8 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = { { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 }, { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 }, { FEAT_REG_FIFOSIZE, 8, 0 }, + { FEAT_REG_HORIZONTALACCU, 9, 0 }, + { FEAT_REG_VERTICALACCU, 25, 16 }, }; static const struct dss_reg_field omap3_dss_reg_fields[] = { @@ -62,6 +64,18 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = { { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 }, { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 }, { FEAT_REG_FIFOSIZE, 10, 0 }, + { FEAT_REG_HORIZONTALACCU, 9, 0 }, + { FEAT_REG_VERTICALACCU, 25, 16 }, +}; + +static const struct dss_reg_field omap4_dss_reg_fields[] = { + { FEAT_REG_FIRHINC, 12, 0 }, + { FEAT_REG_FIRVINC, 28, 16 }, + { FEAT_REG_FIFOLOWTHRESHOLD, 15, 0 }, + { FEAT_REG_FIFOHIGHTHRESHOLD, 31, 16 }, + { FEAT_REG_FIFOSIZE, 15, 0 }, + { FEAT_REG_HORIZONTALACCU, 10, 0 }, + { FEAT_REG_VERTICALACCU, 26, 16 }, }; static const enum omap_display_type omap2_dss_supported_displays[] = { @@ -149,7 +163,8 @@ static struct omap_dss_features omap2_dss_features = { .has_feature = FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | - FEAT_PCKFREEENABLE | FEAT_FUNCGATED, + FEAT_PCKFREEENABLE | FEAT_FUNCGATED | + FEAT_ROWREPEATENABLE | FEAT_RESIZECONF, .num_mgrs = 2, .num_ovls = 3, @@ -165,7 +180,8 @@ static struct omap_dss_features omap3430_dss_features = { .has_feature = FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | - FEAT_FUNCGATED, + FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | + FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF, .num_mgrs = 2, .num_ovls = 3, @@ -180,7 +196,9 @@ static struct omap_dss_features omap3630_dss_features = { .has_feature = FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | - FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED, + FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED | + FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | + FEAT_RESIZECONF, .num_mgrs = 2, .num_ovls = 3, @@ -190,12 +208,12 @@ static struct omap_dss_features omap3630_dss_features = { /* OMAP4 DSS Features */ static struct omap_dss_features omap4_dss_features = { - .reg_fields = omap3_dss_reg_fields, - .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), + .reg_fields = omap4_dss_reg_fields, + .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), .has_feature = FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | - FEAT_MGR_LCD2, + FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1, .num_mgrs = 3, .num_ovls = 3, diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index b9c70be92588..b3f81415507c 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -33,6 +33,9 @@ enum dss_feat_id { FEAT_PCKFREEENABLE = 1 << 5, FEAT_FUNCGATED = 1 << 6, FEAT_MGR_LCD2 = 1 << 7, + FEAT_LINEBUFFERSPLIT = 1 << 8, + FEAT_ROWREPEATENABLE = 1 << 9, + FEAT_RESIZECONF = 1 << 10, }; /* DSS register field id */ @@ -42,6 +45,8 @@ enum dss_feat_reg_field { FEAT_REG_FIFOHIGHTHRESHOLD, FEAT_REG_FIFOLOWTHRESHOLD, FEAT_REG_FIFOSIZE, + FEAT_REG_HORIZONTALACCU, + FEAT_REG_VERTICALACCU, }; /* DSS Feature Functions */ -- cgit v1.2.2 From 819d807c59af10cce1dcbb13539c2fb100953fcd Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 1 Mar 2011 11:54:00 +0530 Subject: OMAP2PLUS: DSS2: FEATURES: Function to Provide the max fck supported The maximum supported frequency for DSS has increased from 173 to 186 Mhz on OMAP4. Introduce a dss feature function to get the max_fck to replace DISPC_MAX_FCK macro. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 9 ++++++--- drivers/video/omap2/dss/dss.c | 8 +++++--- drivers/video/omap2/dss/dss.h | 2 -- drivers/video/omap2/dss/dss_features.c | 11 +++++++++++ drivers/video/omap2/dss/dss_features.h | 1 + 5 files changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index c3019d95618d..705599ad3166 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -38,6 +38,7 @@ #include #include "dss.h" +#include "dss_features.h" /*#define VERBOSE_IRQ*/ #define DSI_CATCH_MISSING_TE @@ -856,10 +857,12 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck, struct dispc_clock_info best_dispc; int min_fck_per_pck; int match = 0; - unsigned long dss_clk_fck2; + unsigned long dss_clk_fck2, max_dss_fck; dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_SYSCK); + max_dss_fck = dss_feat_get_max_dss_fck(); + if (req_pck == dsi.cache_req_pck && dsi.cache_cinfo.clkin == dss_clk_fck2) { DSSDBG("DSI clock info found from cache\n"); @@ -872,7 +875,7 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck, min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; if (min_fck_per_pck && - req_pck * min_fck_per_pck > DISPC_MAX_FCK) { + req_pck * min_fck_per_pck > max_dss_fck) { DSSERR("Requested pixel clock not possible with the current " "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " "the constraint off.\n"); @@ -925,7 +928,7 @@ retry: if (cur.dsi1_pll_fclk < req_pck) break; - if (cur.dsi1_pll_fclk > DISPC_MAX_FCK) + if (cur.dsi1_pll_fclk > max_dss_fck) continue; if (min_fck_per_pck && diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 0cf5f8bd1c8a..01be82a4f42f 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -387,7 +387,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, struct dss_clock_info best_dss; struct dispc_clock_info best_dispc; - unsigned long fck; + unsigned long fck, max_dss_fck; u16 fck_div; @@ -396,6 +396,8 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, prate = dss_get_dpll4_rate(); + max_dss_fck = dss_feat_get_max_dss_fck(); + fck = dss_clk_get_rate(DSS_CLK_FCK); if (req_pck == dss.cache_req_pck && ((cpu_is_omap34xx() && prate == dss.cache_prate) || @@ -409,7 +411,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; if (min_fck_per_pck && - req_pck * min_fck_per_pck > DISPC_MAX_FCK) { + req_pck * min_fck_per_pck > max_dss_fck) { DSSERR("Requested pixel clock not possible with the current " "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " "the constraint off.\n"); @@ -445,7 +447,7 @@ retry: else fck = prate / fck_div * 2; - if (fck > DISPC_MAX_FCK) + if (fck > max_dss_fck) continue; if (min_fck_per_pck && diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 4b02e079f20e..7fe32d1647f9 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -97,8 +97,6 @@ extern unsigned int dss_debug; #define FLD_MOD(orig, val, start, end) \ (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) -#define DISPC_MAX_FCK 173000000 - enum omap_burst_size { OMAP_DSS_BURST_4x32 = 0, OMAP_DSS_BURST_8x32 = 1, diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 679be14b73a8..3ebe0d91afd2 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -41,6 +41,7 @@ struct omap_dss_features { const int num_mgrs; const int num_ovls; + const unsigned long max_dss_fck; const enum omap_display_type *supported_displays; const enum omap_color_mode *supported_color_modes; }; @@ -168,6 +169,7 @@ static struct omap_dss_features omap2_dss_features = { .num_mgrs = 2, .num_ovls = 3, + .max_dss_fck = 173000000, .supported_displays = omap2_dss_supported_displays, .supported_color_modes = omap2_dss_supported_color_modes, }; @@ -185,6 +187,7 @@ static struct omap_dss_features omap3430_dss_features = { .num_mgrs = 2, .num_ovls = 3, + .max_dss_fck = 173000000, .supported_displays = omap3430_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, }; @@ -202,6 +205,7 @@ static struct omap_dss_features omap3630_dss_features = { .num_mgrs = 2, .num_ovls = 3, + .max_dss_fck = 173000000, .supported_displays = omap3630_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, }; @@ -217,6 +221,7 @@ static struct omap_dss_features omap4_dss_features = { .num_mgrs = 3, .num_ovls = 3, + .max_dss_fck = 186000000, .supported_displays = omap4_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, }; @@ -232,6 +237,12 @@ int dss_feat_get_num_ovls(void) return omap_current_dss_features->num_ovls; } +/* Max supported DSS FCK in Hz */ +unsigned long dss_feat_get_max_dss_fck(void) +{ + return omap_current_dss_features->max_dss_fck; +} + enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel) { return omap_current_dss_features->supported_displays[channel]; diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index b3f81415507c..18ab19515817 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -52,6 +52,7 @@ enum dss_feat_reg_field { /* DSS Feature Functions */ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); +unsigned long dss_feat_get_max_dss_fck(void); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, -- cgit v1.2.2 From 88134fa138b90518819b750891ffecc13f5f4886 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 6 Jan 2011 10:44:10 +0530 Subject: OMAP2PLUS: DSS2: Make members of dss_clk_source generic The enum members of 'dss_clk_source' have clock source names specific to OMAP2/3. Change the names to more generic terms such that they now describe where the clocks come from and what they are used for. Also, change the enum member names to have "DSS_CLK_SRC" instead of "DSS_SRC" for more clarity. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 4 ++-- drivers/video/omap2/dss/dpi.c | 4 ++-- drivers/video/omap2/dss/dsi.c | 20 ++++++++++---------- drivers/video/omap2/dss/dss.c | 20 ++++++++++---------- drivers/video/omap2/dss/dss.h | 6 +++--- 5 files changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index aa6479712d4c..a06b2ea41e98 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2334,7 +2334,7 @@ unsigned long dispc_fclk_rate(void) { unsigned long r = 0; - if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) + if (dss_get_dispc_clk_source() == DSS_CLK_SRC_FCK) r = dss_clk_get_rate(DSS_CLK_FCK); else #ifdef CONFIG_OMAP2_DSS_DSI @@ -2385,7 +2385,7 @@ void dispc_dump_clocks(struct seq_file *s) seq_printf(s, "- DISPC -\n"); seq_printf(s, "dispc fclk source = %s\n", - dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? + dss_get_dispc_clk_source() == DSS_CLK_SRC_FCK ? "dss1_alwon_fclk" : "dsi1_pll_fclk"); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 026702b921e5..1b2867dfeeb9 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -57,7 +57,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, if (r) return r; - dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); + dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC); r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); if (r) @@ -217,7 +217,7 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) dssdev->manager->disable(dssdev->manager); #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL - dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); dsi_pll_uninit(); dss_clk_disable(DSS_CLK_SYSCK); #endif diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 705599ad3166..df35aed828da 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -731,7 +731,7 @@ static unsigned long dsi_fclk_rate(void) { unsigned long r; - if (dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK) { + if (dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */ r = dss_clk_get_rate(DSS_CLK_FCK); } else { @@ -1188,19 +1188,19 @@ void dsi_dump_clocks(struct seq_file *s) seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n", cinfo->dsi1_pll_fclk, cinfo->regm3, - dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? + dss_get_dispc_clk_source() == DSS_CLK_SRC_FCK ? "off" : "on"); seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n", cinfo->dsi2_pll_fclk, cinfo->regm4, - dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? + dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK ? "off" : "on"); seq_printf(s, "- DSI -\n"); seq_printf(s, "dsi fclk source = %s\n", - dss_get_dsi_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ? + dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK ? "dss1_alwon_fclk" : "dsi2_pll_fclk"); seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate()); @@ -3038,8 +3038,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) if (r) goto err1; - dss_select_dispc_clk_source(DSS_SRC_DSI1_PLL_FCLK); - dss_select_dsi_clk_source(DSS_SRC_DSI2_PLL_FCLK); + dss_select_dispc_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC); + dss_select_dsi_clk_source(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI); DSSDBG("PLL OK\n"); @@ -3075,8 +3075,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) err3: dsi_complexio_uninit(); err2: - dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); - dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(DSS_CLK_SRC_FCK); err1: dsi_pll_uninit(); err0: @@ -3092,8 +3092,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) dsi_vc_enable(2, 0); dsi_vc_enable(3, 0); - dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); - dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(DSS_CLK_SRC_FCK); dsi_complexio_uninit(); dsi_pll_uninit(); } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 01be82a4f42f..998c188c8823 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -278,12 +278,12 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) { int b; - BUG_ON(clk_src != DSS_SRC_DSI1_PLL_FCLK && - clk_src != DSS_SRC_DSS1_ALWON_FCLK); + BUG_ON(clk_src != DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC && + clk_src != DSS_CLK_SRC_FCK); - b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + b = clk_src == DSS_CLK_SRC_FCK ? 0 : 1; - if (clk_src == DSS_SRC_DSI1_PLL_FCLK) + if (clk_src == DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC) dsi_wait_dsi1_pll_active(); REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ @@ -295,12 +295,12 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) { int b; - BUG_ON(clk_src != DSS_SRC_DSI2_PLL_FCLK && - clk_src != DSS_SRC_DSS1_ALWON_FCLK); + BUG_ON(clk_src != DSS_CLK_SRC_DSI_PLL_HSDIV_DSI && + clk_src != DSS_CLK_SRC_FCK); - b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + b = clk_src == DSS_CLK_SRC_FCK ? 0 : 1; - if (clk_src == DSS_SRC_DSI2_PLL_FCLK) + if (clk_src == DSS_CLK_SRC_DSI_PLL_HSDIV_DSI) dsi_wait_dsi2_pll_active(); REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ @@ -601,8 +601,8 @@ static int dss_init(bool skip_init) } } - dss.dsi_clk_source = DSS_SRC_DSS1_ALWON_FCLK; - dss.dispc_clk_source = DSS_SRC_DSS1_ALWON_FCLK; + dss.dsi_clk_source = DSS_CLK_SRC_FCK; + dss.dispc_clk_source = DSS_CLK_SRC_FCK; dss_save_context(); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 7fe32d1647f9..a166ff36ec90 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -118,9 +118,9 @@ enum dss_clock { }; enum dss_clk_source { - DSS_SRC_DSI1_PLL_FCLK, - DSS_SRC_DSI2_PLL_FCLK, - DSS_SRC_DSS1_ALWON_FCLK, + DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, /* DSI1_PLL_FCLK */ + DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, /* DSI2_PLL_FCLK */ + DSS_CLK_SRC_FCK, /* DSS1_ALWON_FCLK */ }; struct dss_clock_info { -- cgit v1.2.2 From 067a57e48e302863eb2d5ac0900ae9ae65dbc8c3 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 2 Mar 2011 11:57:25 +0530 Subject: OMAP2PLUS: DSS2: Use dss features to get clock source names of current OMAP Clock source names vary across OMAP2/3 and OMAP4, the clock source enum names have been made generic in the driver, but for purposes of debugging and dumping clock sources, it is better to preserve the actual TRM name of the clock. Introduce a dss feature function 'dss_feat_get_clk_source_name()' which returns a string with the TRM clock name for the current OMAP in use. The OMAP specific name is printed along the generic name within brackets. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 7 +++--- drivers/video/omap2/dss/dsi.c | 42 +++++++++++++++++++++++----------- drivers/video/omap2/dss/dss.c | 19 +++++++++++++-- drivers/video/omap2/dss/dss.h | 7 ++++++ drivers/video/omap2/dss/dss_features.c | 23 +++++++++++++++++++ drivers/video/omap2/dss/dss_features.h | 1 + 6 files changed, 81 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index a06b2ea41e98..2c82d9a3df4b 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2379,14 +2379,15 @@ unsigned long dispc_pclk_rate(enum omap_channel channel) void dispc_dump_clocks(struct seq_file *s) { int lcd, pcd; + enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); enable_clocks(1); seq_printf(s, "- DISPC -\n"); - seq_printf(s, "dispc fclk source = %s\n", - dss_get_dispc_clk_source() == DSS_CLK_SRC_FCK ? - "dss1_alwon_fclk" : "dsi1_pll_fclk"); + seq_printf(s, "dispc fclk source = %s (%s)\n", + dss_get_generic_clk_source_name(dispc_clk_src), + dss_feat_get_clk_source_name(dispc_clk_src)); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index df35aed828da..3ef94227bbe7 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1022,10 +1022,14 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4); - DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n", - cinfo->regm3, cinfo->dsi1_pll_fclk); - DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n", - cinfo->regm4, cinfo->dsi2_pll_fclk); + DSSDBG("regm3 = %d, %s (%s) = %lu\n", cinfo->regm3, + dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), + dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), + cinfo->dsi1_pll_fclk); + DSSDBG("regm4 = %d, %s (%s) = %lu\n", cinfo->regm4, + dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), + dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), + cinfo->dsi2_pll_fclk); REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */ @@ -1169,6 +1173,10 @@ void dsi_dump_clocks(struct seq_file *s) { int clksel; struct dsi_clock_info *cinfo = &dsi.current_cinfo; + enum dss_clk_source dispc_clk_src, dsi_clk_src; + + dispc_clk_src = dss_get_dispc_clk_source(); + dsi_clk_src = dss_get_dsi_clk_source(); enable_clocks(1); @@ -1185,23 +1193,27 @@ void dsi_dump_clocks(struct seq_file *s) seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", cinfo->clkin4ddr, cinfo->regm); - seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n", + seq_printf(s, "%s (%s)\t%-16luregm3 %u\t(%s)\n", + dss_get_generic_clk_source_name(dispc_clk_src), + dss_feat_get_clk_source_name(dispc_clk_src), cinfo->dsi1_pll_fclk, cinfo->regm3, - dss_get_dispc_clk_source() == DSS_CLK_SRC_FCK ? + dispc_clk_src == DSS_CLK_SRC_FCK ? "off" : "on"); - seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n", + seq_printf(s, "%s (%s)\t%-16luregm4 %u\t(%s)\n", + dss_get_generic_clk_source_name(dsi_clk_src), + dss_feat_get_clk_source_name(dsi_clk_src), cinfo->dsi2_pll_fclk, cinfo->regm4, - dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK ? + dsi_clk_src == DSS_CLK_SRC_FCK ? "off" : "on"); seq_printf(s, "- DSI -\n"); - seq_printf(s, "dsi fclk source = %s\n", - dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK ? - "dss1_alwon_fclk" : "dsi2_pll_fclk"); + seq_printf(s, "dsi fclk source = %s (%s)\n", + dss_get_generic_clk_source_name(dsi_clk_src), + dss_feat_get_clk_source_name(dsi_clk_src)); seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate()); @@ -3235,13 +3247,17 @@ int dsi_init_display(struct omap_dss_device *dssdev) void dsi_wait_dsi1_pll_active(void) { if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1) - DSSERR("DSI1 PLL clock not active\n"); + DSSERR("%s (%s) not active\n", + dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), + dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC)); } void dsi_wait_dsi2_pll_active(void) { if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1) - DSSERR("DSI2 PLL clock not active\n"); + DSSERR("%s (%s) not active\n", + dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), + dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI)); } static int dsi_init(struct platform_device *pdev) diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 998c188c8823..d049598bb412 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -81,6 +81,12 @@ static struct { u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; +static const struct dss_clk_source_name dss_generic_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI_PLL_HSDIV_DISPC" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI_PLL_HSDIV_DSI" }, + { DSS_CLK_SRC_FCK, "DSS_FCK" }, +}; + static void dss_clk_enable_all_no_ctx(void); static void dss_clk_disable_all_no_ctx(void); static void dss_clk_enable_no_ctx(enum dss_clock clks); @@ -223,6 +229,11 @@ void dss_sdi_disable(void) REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ } +const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src) +{ + return dss_generic_clk_source_names[clk_src].clksrc_name; +} + void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; @@ -238,12 +249,16 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); if (cpu_is_omap3630()) - seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n", + seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", + dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK), + dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK), dpll4_ck_rate, dpll4_ck_rate / dpll4_m4_ck_rate, dss_clk_get_rate(DSS_CLK_FCK)); else - seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n", + seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", + dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK), + dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK), dpll4_ck_rate, dpll4_ck_rate / dpll4_m4_ck_rate, dss_clk_get_rate(DSS_CLK_FCK)); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index a166ff36ec90..42ca70f2bfd5 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -123,6 +123,12 @@ enum dss_clk_source { DSS_CLK_SRC_FCK, /* DSS1_ALWON_FCLK */ }; +/* Correlates clock source name and dss_clk_source member */ +struct dss_clk_source_name { + enum dss_clk_source clksrc; + const char *clksrc_name; +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -215,6 +221,7 @@ void dss_clk_enable(enum dss_clock clks); void dss_clk_disable(enum dss_clock clks); unsigned long dss_clk_get_rate(enum dss_clock clk); int dss_need_ctx_restore(void); +const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); void dss_dump_regs(struct seq_file *s); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 3ebe0d91afd2..ccae57b34f5c 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -25,6 +25,7 @@ #include #include +#include "dss.h" #include "dss_features.h" /* Defines a generic omap register field */ @@ -44,6 +45,7 @@ struct omap_dss_features { const unsigned long max_dss_fck; const enum omap_display_type *supported_displays; const enum omap_color_mode *supported_color_modes; + const struct dss_clk_source_name *clksrc_names; }; /* This struct is assigned to one of the below during initialization */ @@ -157,6 +159,18 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = { OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32, }; +static const struct dss_clk_source_name omap2_dss_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "N/A" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "N/A" }, + { DSS_CLK_SRC_FCK, "DSS_FCLK1" }, +}; + +static const struct dss_clk_source_name omap3_dss_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI1_PLL_FCLK" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI2_PLL_FCLK" }, + { DSS_CLK_SRC_FCK, "DSS1_ALWON_FCLK" }, +}; + /* OMAP2 DSS Features */ static struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, @@ -172,6 +186,7 @@ static struct omap_dss_features omap2_dss_features = { .max_dss_fck = 173000000, .supported_displays = omap2_dss_supported_displays, .supported_color_modes = omap2_dss_supported_color_modes, + .clksrc_names = omap2_dss_clk_source_names, }; /* OMAP3 DSS Features */ @@ -190,6 +205,7 @@ static struct omap_dss_features omap3430_dss_features = { .max_dss_fck = 173000000, .supported_displays = omap3430_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, + .clksrc_names = omap3_dss_clk_source_names, }; static struct omap_dss_features omap3630_dss_features = { @@ -208,6 +224,7 @@ static struct omap_dss_features omap3630_dss_features = { .max_dss_fck = 173000000, .supported_displays = omap3630_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, + .clksrc_names = omap3_dss_clk_source_names, }; /* OMAP4 DSS Features */ @@ -224,6 +241,7 @@ static struct omap_dss_features omap4_dss_features = { .max_dss_fck = 186000000, .supported_displays = omap4_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, + .clksrc_names = omap3_dss_clk_source_names, }; /* Functions returning values related to a DSS feature */ @@ -260,6 +278,11 @@ bool dss_feat_color_mode_supported(enum omap_plane plane, color_mode; } +const char *dss_feat_get_clk_source_name(enum dss_clk_source id) +{ + return omap_current_dss_features->clksrc_names[id].clksrc_name; +} + /* DSS has_feature check */ bool dss_has_feature(enum dss_feat_id id) { diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 18ab19515817..65d6de7e0feb 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -57,6 +57,7 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, enum omap_color_mode color_mode); +const char *dss_feat_get_clk_source_name(enum dss_clk_source id); bool dss_has_feature(enum dss_feat_id id); void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); -- cgit v1.2.2 From 1bb478350670fadf708d3cbd6137c32dfbe3fd5f Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Thu, 24 Feb 2011 14:17:30 +0530 Subject: OMAP2PLUS: DSS2: DSI: Generalize DSI PLL Clock Naming DSI PLL output clock names have been made more generic. The clock name describes what the source of the clock and what clock is used for. Some of DSI PLL parameters like dividers and DSI PLL source have also been made more generic. dsi1_pll_fclk and dsi2_pll_fclk have been changed as dsi_pll_hsdiv_dispc_clk and dsi_pll_hsdiv_dsi_clk respectively. Also, the hsdividers are now named regm_dispc and regm_dsi instead of regm3 and regm4. Functions and macros named on the basis of these clock names have also been made generic. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 2 +- drivers/video/omap2/dss/dpi.c | 4 +- drivers/video/omap2/dss/dsi.c | 134 +++++++++++++++++++++------------------- drivers/video/omap2/dss/dss.c | 4 +- drivers/video/omap2/dss/dss.h | 20 +++--- 5 files changed, 85 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 2c82d9a3df4b..9fb11c17623f 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2338,7 +2338,7 @@ unsigned long dispc_fclk_rate(void) r = dss_clk_get_rate(DSS_CLK_FCK); else #ifdef CONFIG_OMAP2_DSS_DSI - r = dsi_get_dsi1_pll_rate(); + r = dsi_get_pll_hsdiv_dispc_rate(); #else BUG(); #endif diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 1b2867dfeeb9..08fed3080c0a 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -63,7 +63,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, if (r) return r; - *fck = dsi_cinfo.dsi1_pll_fclk; + *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; *lck_div = dispc_cinfo.lck_div; *pck_div = dispc_cinfo.pck_div; @@ -271,7 +271,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev, if (r) return r; - fck = dsi_cinfo.dsi1_pll_fclk; + fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; lck_div = dispc_cinfo.lck_div; pck_div = dispc_cinfo.pck_div; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 3ef94227bbe7..37ffbb6ecf69 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -189,8 +189,8 @@ struct dsi_reg { u16 idx; }; #define FINT_MIN 750000 #define REGN_MAX (1 << 7) #define REGM_MAX ((1 << 11) - 1) -#define REGM3_MAX (1 << 4) -#define REGM4_MAX (1 << 4) +#define REGM_DISPC_MAX (1 << 4) +#define REGM_DSI_MAX (1 << 4) #define LP_DIV_MAX ((1 << 13) - 1) enum fifo_size { @@ -642,7 +642,7 @@ static void dsi_vc_disable_bta_irq(int channel) dsi_write_reg(DSI_VC_IRQENABLE(channel), l); } -/* DSI func clock. this could also be DSI2_PLL_FCLK */ +/* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ static inline void enable_clocks(bool enable) { if (enable) @@ -712,14 +712,14 @@ static inline int dsi_if_enable(bool enable) return 0; } -unsigned long dsi_get_dsi1_pll_rate(void) +unsigned long dsi_get_pll_hsdiv_dispc_rate(void) { - return dsi.current_cinfo.dsi1_pll_fclk; + return dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk; } -static unsigned long dsi_get_dsi2_pll_rate(void) +static unsigned long dsi_get_pll_hsdiv_dsi_rate(void) { - return dsi.current_cinfo.dsi2_pll_fclk; + return dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk; } static unsigned long dsi_get_txbyteclkhs(void) @@ -732,11 +732,11 @@ static unsigned long dsi_fclk_rate(void) unsigned long r; if (dss_get_dsi_clk_source() == DSS_CLK_SRC_FCK) { - /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */ + /* DSI FCLK source is DSS_CLK_FCK */ r = dss_clk_get_rate(DSS_CLK_FCK); } else { - /* DSI FCLK source is DSI2_PLL_FCLK */ - r = dsi_get_dsi2_pll_rate(); + /* DSI FCLK source is dsi_pll_hsdiv_dsi_clk */ + r = dsi_get_pll_hsdiv_dsi_rate(); } return r; @@ -806,16 +806,16 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, if (cinfo->regm == 0 || cinfo->regm > REGM_MAX) return -EINVAL; - if (cinfo->regm3 > REGM3_MAX) + if (cinfo->regm_dispc > REGM_DISPC_MAX) return -EINVAL; - if (cinfo->regm4 > REGM4_MAX) + if (cinfo->regm_dsi > REGM_DSI_MAX) return -EINVAL; - if (cinfo->use_dss2_fck) { + if (cinfo->use_sys_clk) { cinfo->clkin = dss_clk_get_rate(DSS_CLK_SYSCK); /* XXX it is unclear if highfreq should be used - * with DSS2_FCK source also */ + * with DSS_SYS_CLK source also */ cinfo->highfreq = 0; } else { cinfo->clkin = dispc_pclk_rate(dssdev->manager->id); @@ -836,15 +836,17 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, if (cinfo->clkin4ddr > 1800 * 1000 * 1000) return -EINVAL; - if (cinfo->regm3 > 0) - cinfo->dsi1_pll_fclk = cinfo->clkin4ddr / cinfo->regm3; + if (cinfo->regm_dispc > 0) + cinfo->dsi_pll_hsdiv_dispc_clk = + cinfo->clkin4ddr / cinfo->regm_dispc; else - cinfo->dsi1_pll_fclk = 0; + cinfo->dsi_pll_hsdiv_dispc_clk = 0; - if (cinfo->regm4 > 0) - cinfo->dsi2_pll_fclk = cinfo->clkin4ddr / cinfo->regm4; + if (cinfo->regm_dsi > 0) + cinfo->dsi_pll_hsdiv_dsi_clk = + cinfo->clkin4ddr / cinfo->regm_dsi; else - cinfo->dsi2_pll_fclk = 0; + cinfo->dsi_pll_hsdiv_dsi_clk = 0; return 0; } @@ -857,18 +859,18 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck, struct dispc_clock_info best_dispc; int min_fck_per_pck; int match = 0; - unsigned long dss_clk_fck2, max_dss_fck; + unsigned long dss_sys_clk, max_dss_fck; - dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_SYSCK); + dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK); max_dss_fck = dss_feat_get_max_dss_fck(); if (req_pck == dsi.cache_req_pck && - dsi.cache_cinfo.clkin == dss_clk_fck2) { + dsi.cache_cinfo.clkin == dss_sys_clk) { DSSDBG("DSI clock info found from cache\n"); *dsi_cinfo = dsi.cache_cinfo; - dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk, - dispc_cinfo); + dispc_find_clk_divs(is_tft, req_pck, + dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo); return 0; } @@ -889,8 +891,8 @@ retry: memset(&best_dispc, 0, sizeof(best_dispc)); memset(&cur, 0, sizeof(cur)); - cur.clkin = dss_clk_fck2; - cur.use_dss2_fck = 1; + cur.clkin = dss_sys_clk; + cur.use_sys_clk = 1; cur.highfreq = 0; /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ @@ -916,30 +918,32 @@ retry: if (cur.clkin4ddr > 1800 * 1000 * 1000) break; - /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */ - for (cur.regm3 = 1; cur.regm3 < REGM3_MAX; - ++cur.regm3) { + /* dsi_pll_hsdiv_dispc_clk(MHz) = + * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */ + for (cur.regm_dispc = 1; cur.regm_dispc < REGM_DISPC_MAX; + ++cur.regm_dispc) { struct dispc_clock_info cur_dispc; - cur.dsi1_pll_fclk = cur.clkin4ddr / cur.regm3; + cur.dsi_pll_hsdiv_dispc_clk = + cur.clkin4ddr / cur.regm_dispc; /* this will narrow down the search a bit, * but still give pixclocks below what was * requested */ - if (cur.dsi1_pll_fclk < req_pck) + if (cur.dsi_pll_hsdiv_dispc_clk < req_pck) break; - if (cur.dsi1_pll_fclk > max_dss_fck) + if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck) continue; if (min_fck_per_pck && - cur.dsi1_pll_fclk < + cur.dsi_pll_hsdiv_dispc_clk < req_pck * min_fck_per_pck) continue; match = 1; dispc_find_clk_divs(is_tft, req_pck, - cur.dsi1_pll_fclk, + cur.dsi_pll_hsdiv_dispc_clk, &cur_dispc); if (abs(cur_dispc.pck - req_pck) < @@ -968,9 +972,9 @@ found: return -EINVAL; } - /* DSI2_PLL_FCLK (regm4) is not used */ - best.regm4 = 0; - best.dsi2_pll_fclk = 0; + /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */ + best.regm_dsi = 0; + best.dsi_pll_hsdiv_dsi_clk = 0; if (dsi_cinfo) *dsi_cinfo = best; @@ -994,18 +998,20 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) dsi.current_cinfo.fint = cinfo->fint; dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr; - dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk; - dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk; + dsi.current_cinfo.dsi_pll_hsdiv_dispc_clk = + cinfo->dsi_pll_hsdiv_dispc_clk; + dsi.current_cinfo.dsi_pll_hsdiv_dsi_clk = + cinfo->dsi_pll_hsdiv_dsi_clk; dsi.current_cinfo.regn = cinfo->regn; dsi.current_cinfo.regm = cinfo->regm; - dsi.current_cinfo.regm3 = cinfo->regm3; - dsi.current_cinfo.regm4 = cinfo->regm4; + dsi.current_cinfo.regm_dispc = cinfo->regm_dispc; + dsi.current_cinfo.regm_dsi = cinfo->regm_dsi; DSSDBG("DSI Fint %ld\n", cinfo->fint); DSSDBG("clkin (%s) rate %ld, highfreq %d\n", - cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree", + cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree", cinfo->clkin, cinfo->highfreq); @@ -1022,14 +1028,14 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4); - DSSDBG("regm3 = %d, %s (%s) = %lu\n", cinfo->regm3, + DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc, dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), - cinfo->dsi1_pll_fclk); - DSSDBG("regm4 = %d, %s (%s) = %lu\n", cinfo->regm4, + cinfo->dsi_pll_hsdiv_dispc_clk); + DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi, dss_get_generic_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), - cinfo->dsi2_pll_fclk); + cinfo->dsi_pll_hsdiv_dsi_clk); REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */ @@ -1037,9 +1043,9 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */ l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */ l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */ - l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0, + l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0, 22, 19); /* DSI_CLOCK_DIV */ - l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0, + l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0, 26, 23); /* DSIPROTO_CLOCK_DIV */ dsi_write_reg(DSI_PLL_CONFIGURATION1, l); @@ -1057,7 +1063,7 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) l = dsi_read_reg(DSI_PLL_CONFIGURATION2); l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ - l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1, + l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1, 11, 11); /* DSI_PLL_CLKSEL */ l = FLD_MOD(l, cinfo->highfreq, 12, 12); /* DSI_PLL_HIGHFREQ */ @@ -1186,26 +1192,26 @@ void dsi_dump_clocks(struct seq_file *s) seq_printf(s, "dsi pll source = %s\n", clksel == 0 ? - "dss2_alwon_fclk" : "pclkfree"); + "dss_sys_clk" : "pclkfree"); seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", cinfo->clkin4ddr, cinfo->regm); - seq_printf(s, "%s (%s)\t%-16luregm3 %u\t(%s)\n", + seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n", dss_get_generic_clk_source_name(dispc_clk_src), dss_feat_get_clk_source_name(dispc_clk_src), - cinfo->dsi1_pll_fclk, - cinfo->regm3, + cinfo->dsi_pll_hsdiv_dispc_clk, + cinfo->regm_dispc, dispc_clk_src == DSS_CLK_SRC_FCK ? "off" : "on"); - seq_printf(s, "%s (%s)\t%-16luregm4 %u\t(%s)\n", + seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n", dss_get_generic_clk_source_name(dsi_clk_src), dss_feat_get_clk_source_name(dsi_clk_src), - cinfo->dsi2_pll_fclk, - cinfo->regm4, + cinfo->dsi_pll_hsdiv_dsi_clk, + cinfo->regm_dsi, dsi_clk_src == DSS_CLK_SRC_FCK ? "off" : "on"); @@ -2989,12 +2995,12 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) struct dsi_clock_info cinfo; int r; - /* we always use DSS2_FCK as input clock */ - cinfo.use_dss2_fck = true; + /* we always use DSS_CLK_SYSCK as input clock */ + cinfo.use_sys_clk = true; cinfo.regn = dssdev->phy.dsi.div.regn; cinfo.regm = dssdev->phy.dsi.div.regm; - cinfo.regm3 = dssdev->phy.dsi.div.regm3; - cinfo.regm4 = dssdev->phy.dsi.div.regm4; + cinfo.regm_dispc = dssdev->phy.dsi.div.regm_dispc; + cinfo.regm_dsi = dssdev->phy.dsi.div.regm_dsi; r = dsi_calc_clock_rates(dssdev, &cinfo); if (r) { DSSERR("Failed to calc dsi clocks\n"); @@ -3016,7 +3022,7 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) int r; unsigned long long fck; - fck = dsi_get_dsi1_pll_rate(); + fck = dsi_get_pll_hsdiv_dispc_rate(); dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div; dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div; @@ -3244,7 +3250,7 @@ int dsi_init_display(struct omap_dss_device *dssdev) return 0; } -void dsi_wait_dsi1_pll_active(void) +void dsi_wait_pll_hsdiv_dispc_active(void) { if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1) DSSERR("%s (%s) not active\n", @@ -3252,7 +3258,7 @@ void dsi_wait_dsi1_pll_active(void) dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC)); } -void dsi_wait_dsi2_pll_active(void) +void dsi_wait_pll_hsdiv_dsi_active(void) { if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1) DSSERR("%s (%s) not active\n", diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index d049598bb412..5c6805b3362d 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -299,7 +299,7 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_CLK_SRC_FCK ? 0 : 1; if (clk_src == DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC) - dsi_wait_dsi1_pll_active(); + dsi_wait_pll_hsdiv_dispc_active(); REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ @@ -316,7 +316,7 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_CLK_SRC_FCK ? 0 : 1; if (clk_src == DSS_CLK_SRC_DSI_PLL_HSDIV_DSI) - dsi_wait_dsi2_pll_active(); + dsi_wait_pll_hsdiv_dsi_active(); REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 42ca70f2bfd5..20590fb53c91 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -152,21 +152,21 @@ struct dsi_clock_info { unsigned long fint; unsigned long clkin4ddr; unsigned long clkin; - unsigned long dsi1_pll_fclk; - unsigned long dsi2_pll_fclk; + unsigned long dsi_pll_hsdiv_dispc_clk; /* DSI1_PLL_CLK */ + unsigned long dsi_pll_hsdiv_dsi_clk; /* DSI2_PLL_CLK */ unsigned long lp_clk; /* dividers */ u16 regn; u16 regm; - u16 regm3; - u16 regm4; + u16 regm_dispc; /* REGM3 */ + u16 regm_dsi; /* REGM4 */ u16 lp_clk_div; u8 highfreq; - bool use_dss2_fck; + bool use_sys_clk; }; struct seq_file; @@ -278,7 +278,7 @@ void dsi_restore_context(void); int dsi_init_display(struct omap_dss_device *display); void dsi_irq_handler(void); -unsigned long dsi_get_dsi1_pll_rate(void); +unsigned long dsi_get_pll_hsdiv_dispc_rate(void); int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo); int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck, struct dsi_clock_info *cinfo, @@ -289,8 +289,8 @@ void dsi_pll_uninit(void); void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 fifo_size, enum omap_burst_size *burst_size, u32 *fifo_low, u32 *fifo_high); -void dsi_wait_dsi1_pll_active(void); -void dsi_wait_dsi2_pll_active(void); +void dsi_wait_pll_hsdiv_dispc_active(void); +void dsi_wait_pll_hsdiv_dsi_active(void); #else static inline int dsi_init_platform_driver(void) { @@ -299,10 +299,10 @@ static inline int dsi_init_platform_driver(void) static inline void dsi_uninit_platform_driver(void) { } -static inline void dsi_wait_dsi1_pll_active(void) +static inline void dsi_wait_pll_hsdiv_dispc_active(void) { } -static inline void dsi_wait_dsi2_pll_active(void) +static inline void dsi_wait_pll_hsdiv_dsi_active(void) { } #endif -- cgit v1.2.2 From 42c9dee82129d965bc8ca02170150817317c0135 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 12:29:27 +0200 Subject: OMAP: DSS2: Remove FB_OMAP_BOOTLOADER_INIT support FB_OMAP_BOOTLOADER_INIT does not work, and it was only partially implemented for SDI. This patch removes support for FB_OMAP_BOOTLOADER_INIT to clean up the code and to remove any assumptions that FB_OMAP_BOOTLOADER_INIT would work. Proper implementation is much more complex, requiring early boot time register and clock handling to keep the DSS running. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 8 +------- drivers/video/omap2/dss/dss.c | 41 ++++++++++++++++------------------------- drivers/video/omap2/dss/dss.h | 4 ++-- drivers/video/omap2/dss/sdi.c | 40 +++++++++------------------------------- 4 files changed, 28 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index bcf69a462b5f..02db5f1269ee 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -166,7 +166,6 @@ static inline void dss_uninitialize_debugfs(void) static int omap_dss_probe(struct platform_device *pdev) { struct omap_dss_board_info *pdata = pdev->dev.platform_data; - int skip_init = 0; int r; int i; @@ -210,13 +209,8 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_venc; } -#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT - /* DISPC_CONTROL */ - if (omap_readl(0x48050440) & 1) /* LCD enabled? */ - skip_init = 1; -#endif if (cpu_is_omap34xx()) { - r = sdi_init(skip_init); + r = sdi_init(); if (r) { DSSERR("Failed to initialize SDI\n"); goto err_sdi; diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 5c6805b3362d..4025a14c5bc1 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -559,7 +559,7 @@ void dss_set_dac_pwrdn_bgz(bool enable) REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } -static int dss_init(bool skip_init) +static int dss_init(void) { int r; u32 rev; @@ -578,22 +578,20 @@ static int dss_init(bool skip_init) goto fail0; } - if (!skip_init) { - /* disable LCD and DIGIT output. This seems to fix the synclost - * problem that we get, if the bootloader starts the DSS and - * the kernel resets it */ - omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440); - - /* We need to wait here a bit, otherwise we sometimes start to - * get synclost errors, and after that only power cycle will - * restore DSS functionality. I have no idea why this happens. - * And we have to wait _before_ resetting the DSS, but after - * enabling clocks. - */ - msleep(50); - - _omap_dss_reset(); - } + /* disable LCD and DIGIT output. This seems to fix the synclost + * problem that we get, if the bootloader starts the DSS and + * the kernel resets it */ + omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440); + + /* We need to wait here a bit, otherwise we sometimes start to + * get synclost errors, and after that only power cycle will + * restore DSS functionality. I have no idea why this happens. + * And we have to wait _before_ resetting the DSS, but after + * enabling clocks. + */ + msleep(50); + + _omap_dss_reset(); /* autoidle */ REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0); @@ -954,7 +952,6 @@ void dss_debug_dump_clocks(struct seq_file *s) static int omap_dsshw_probe(struct platform_device *pdev) { int r; - int skip_init = 0; dss.pdev = pdev; @@ -967,13 +964,7 @@ static int omap_dsshw_probe(struct platform_device *pdev) dss.ctx_id = dss_get_ctx_id(); DSSDBG("initial ctx id %u\n", dss.ctx_id); -#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT - /* DISPC_CONTROL */ - if (omap_readl(0x48050440) & 1) /* LCD enabled? */ - skip_init = 1; -#endif - - r = dss_init(skip_init); + r = dss_init(); if (r) { DSSERR("Failed to initialize DSS\n"); goto err_dss; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 20590fb53c91..069fcc72331c 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -251,11 +251,11 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, /* SDI */ #ifdef CONFIG_OMAP2_DSS_SDI -int sdi_init(bool skip_init); +int sdi_init(void); void sdi_exit(void); int sdi_init_display(struct omap_dss_device *display); #else -static inline int sdi_init(bool skip_init) +static inline int sdi_init(void) { return 0; } diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 9f10a0d9e760..54a53e648180 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -30,7 +30,6 @@ #include "dss.h" static struct { - bool skip_init; bool update_enabled; struct regulator *vdds_sdi_reg; } sdi; @@ -68,9 +67,7 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) if (r) goto err1; - /* In case of skip_init sdi_init has already enabled the clocks */ - if (!sdi.skip_init) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); sdi_basic_init(dssdev); @@ -80,14 +77,8 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, dssdev->panel.acbi, dssdev->panel.acb); - if (!sdi.skip_init) { - r = dss_calc_clock_div(1, t->pixel_clock * 1000, - &dss_cinfo, &dispc_cinfo); - } else { - r = dss_get_clock_div(&dss_cinfo); - r = dispc_get_clock_div(dssdev->manager->id, &dispc_cinfo); - } - + r = dss_calc_clock_div(1, t->pixel_clock * 1000, + &dss_cinfo, &dispc_cinfo); if (r) goto err2; @@ -116,18 +107,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) if (r) goto err2; - if (!sdi.skip_init) { - dss_sdi_init(dssdev->phy.sdi.datapairs); - r = dss_sdi_enable(); - if (r) - goto err1; - mdelay(2); - } + dss_sdi_init(dssdev->phy.sdi.datapairs); + r = dss_sdi_enable(); + if (r) + goto err1; + mdelay(2); dssdev->manager->enable(dssdev->manager); - sdi.skip_init = 0; - return 0; err2: dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); @@ -173,17 +160,8 @@ int sdi_init_display(struct omap_dss_device *dssdev) return 0; } -int sdi_init(bool skip_init) +int sdi_init(void) { - /* we store this for first display enable, then clear it */ - sdi.skip_init = skip_init; - - /* - * Enable clocks already here, otherwise there would be a toggle - * of them until sdi_display_enable is called. - */ - if (skip_init) - dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); return 0; } -- cgit v1.2.2 From 277b2881c3c0d97e214487fbd677b0590fb4acf3 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 12:32:48 +0200 Subject: OMAP: DSS2: Remove pdev argument from dpi_init dpi_init() does not use the pdev argument for anything. Remove it. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 2 +- drivers/video/omap2/dss/dpi.c | 2 +- drivers/video/omap2/dss/dss.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 02db5f1269ee..acefe50209fc 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -191,7 +191,7 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_rfbi; } - r = dpi_init(pdev); + r = dpi_init(); if (r) { DSSERR("Failed to initialize dpi\n"); goto err_dpi; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 08fed3080c0a..2d3ca4ca4a05 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -319,7 +319,7 @@ int dpi_init_display(struct omap_dss_device *dssdev) return 0; } -int dpi_init(struct platform_device *pdev) +int dpi_init(void) { return 0; } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 069fcc72331c..85d4141689c1 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -309,11 +309,11 @@ static inline void dsi_wait_pll_hsdiv_dsi_active(void) /* DPI */ #ifdef CONFIG_OMAP2_DSS_DPI -int dpi_init(struct platform_device *pdev); +int dpi_init(void); void dpi_exit(void); int dpi_init_display(struct omap_dss_device *dssdev); #else -static inline int dpi_init(struct platform_device *pdev) +static inline int dpi_init(void) { return 0; } -- cgit v1.2.2 From 587b5e8269fab583e4e9d2d6bbdc77b289ac78a7 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 12:47:54 +0200 Subject: OMAP: DSS2: Move DPI & SDI init into DSS plat driver DPI and SDI are different from the other interfaces as they are not hwmods and there is not platform driver for them. They could be said to be a part of DSS or DISPC modules, although it's not a clear definition. This patch moves DPI and SDI initialization into DSS platform driver, making the code more consistent: omap_dss_probe() only initializes platform drivers now. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 19 ------------------- drivers/video/omap2/dss/dss.c | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index acefe50209fc..8cfedae98211 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -191,12 +191,6 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_rfbi; } - r = dpi_init(); - if (r) { - DSSERR("Failed to initialize dpi\n"); - goto err_dpi; - } - r = dispc_init_platform_driver(); if (r) { DSSERR("Failed to initialize dispc platform driver\n"); @@ -210,12 +204,6 @@ static int omap_dss_probe(struct platform_device *pdev) } if (cpu_is_omap34xx()) { - r = sdi_init(); - if (r) { - DSSERR("Failed to initialize SDI\n"); - goto err_sdi; - } - r = dsi_init_platform_driver(); if (r) { DSSERR("Failed to initialize DSI platform driver\n"); @@ -255,15 +243,10 @@ err_debugfs: if (cpu_is_omap34xx()) dsi_uninit_platform_driver(); err_dsi: - if (cpu_is_omap34xx()) - sdi_exit(); -err_sdi: venc_uninit_platform_driver(); err_venc: dispc_uninit_platform_driver(); err_dispc: - dpi_exit(); -err_dpi: rfbi_uninit_platform_driver(); err_rfbi: dss_uninit_platform_driver(); @@ -281,11 +264,9 @@ static int omap_dss_remove(struct platform_device *pdev) venc_uninit_platform_driver(); dispc_uninit_platform_driver(); - dpi_exit(); rfbi_uninit_platform_driver(); if (cpu_is_omap34xx()) { dsi_uninit_platform_driver(); - sdi_exit(); } dss_uninit_platform_driver(); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 4025a14c5bc1..e5da050bcf85 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -970,9 +970,24 @@ static int omap_dsshw_probe(struct platform_device *pdev) goto err_dss; } + r = dpi_init(); + if (r) { + DSSERR("Failed to initialize DPI\n"); + goto err_dpi; + } + + r = sdi_init(); + if (r) { + DSSERR("Failed to initialize SDI\n"); + goto err_sdi; + } + dss_clk_disable_all_no_ctx(); return 0; - +err_sdi: + dpi_exit(); +err_dpi: + dss_exit(); err_dss: dss_clk_disable_all_no_ctx(); dss_put_clocks(); -- cgit v1.2.2 From 0a5835185420160f4fe8a6e1d1e42cd7efa07dc7 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 12:48:35 +0200 Subject: OMAP: DSS2: Remove unneeded cpu_is_xxx checks cpu_is_omapxxx() was used previously to select the supported interfaces. Now that the interfaces are platform devices, we no longer need to do the check when registering the driver. Thus we can just remove the checks. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index 8cfedae98211..c2f930bf2844 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -203,12 +203,10 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_venc; } - if (cpu_is_omap34xx()) { - r = dsi_init_platform_driver(); - if (r) { - DSSERR("Failed to initialize DSI platform driver\n"); - goto err_dsi; - } + r = dsi_init_platform_driver(); + if (r) { + DSSERR("Failed to initialize DSI platform driver\n"); + goto err_dsi; } r = dss_initialize_debugfs(); @@ -240,8 +238,7 @@ static int omap_dss_probe(struct platform_device *pdev) err_register: dss_uninitialize_debugfs(); err_debugfs: - if (cpu_is_omap34xx()) - dsi_uninit_platform_driver(); + dsi_uninit_platform_driver(); err_dsi: venc_uninit_platform_driver(); err_venc: @@ -265,10 +262,7 @@ static int omap_dss_remove(struct platform_device *pdev) venc_uninit_platform_driver(); dispc_uninit_platform_driver(); rfbi_uninit_platform_driver(); - if (cpu_is_omap34xx()) { - dsi_uninit_platform_driver(); - } - + dsi_uninit_platform_driver(); dss_uninit_platform_driver(); dss_uninit_overlays(pdev); -- cgit v1.2.2 From 5ee3c1445dd89342ca8498c14afef82d0f76c794 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 2 Mar 2011 12:35:53 +0530 Subject: OMAP: DSS2: Functions to request/release DSI VCs Introduce functions which request and release VC's. This will be used in panel drivers in their probes. omap_dsi_request_vc() takes in the pointer to the omap_dss_device, the VC_ID parameter which goes into the header of the DSI packets, and returns a Virtual channel number (or virtual channel register set) which it can use. omap_dsi_set_vc_id() takes the omap_dss_device pointer, the Virtual Channel number and the VC_ID that needs to be set for the specifed Virtual Channel. omap_dsi_release_vc() takes the omap_dss_device pointer and the Virtual Channel number that needs to be made free. Initialisation of VC parameters is done in dsi_init(). Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 67 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 37ffbb6ecf69..fe3578bbff7d 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -233,6 +233,7 @@ static struct enum dsi_vc_mode mode; struct omap_dss_device *dssdev; enum fifo_size fifo_size; + int vc_id; } vc[4]; struct mutex lock; @@ -1764,8 +1765,6 @@ static void dsi_vc_initial_config(int channel) r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */ dsi_write_reg(DSI_VC_CTRL(channel), r); - - dsi.vc[channel].mode = DSI_VC_MODE_L4; } static int dsi_vc_config_l4(int channel) @@ -1972,7 +1971,7 @@ static inline void dsi_vc_write_long_header(int channel, u8 data_type, WARN_ON(!dsi_bus_is_locked()); - data_id = data_type | channel << 6; + data_id = data_type | dsi.vc[channel].vc_id << 6; val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) | FLD_VAL(ecc, 31, 24); @@ -2075,7 +2074,7 @@ static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc) return -EINVAL; } - data_id = data_type | channel << 6; + data_id = data_type | dsi.vc[channel].vc_id << 6; r = (data_id << 0) | (data << 8) | (ecc << 24); @@ -3250,6 +3249,57 @@ int dsi_init_display(struct omap_dss_device *dssdev) return 0; } +int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) { + if (!dsi.vc[i].dssdev) { + dsi.vc[i].dssdev = dssdev; + *channel = i; + return 0; + } + } + + DSSERR("cannot get VC for display %s", dssdev->name); + return -ENOSPC; +} +EXPORT_SYMBOL(omap_dsi_request_vc); + +int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id) +{ + if (vc_id < 0 || vc_id > 3) { + DSSERR("VC ID out of range\n"); + return -EINVAL; + } + + if (channel < 0 || channel > 3) { + DSSERR("Virtual Channel out of range\n"); + return -EINVAL; + } + + if (dsi.vc[channel].dssdev != dssdev) { + DSSERR("Virtual Channel not allocated to display %s\n", + dssdev->name); + return -EINVAL; + } + + dsi.vc[channel].vc_id = vc_id; + + return 0; +} +EXPORT_SYMBOL(omap_dsi_set_vc_id); + +void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel) +{ + if ((channel >= 0 && channel <= 3) && + dsi.vc[channel].dssdev == dssdev) { + dsi.vc[channel].dssdev = NULL; + dsi.vc[channel].vc_id = 0; + } +} +EXPORT_SYMBOL(omap_dsi_release_vc); + void dsi_wait_pll_hsdiv_dispc_active(void) { if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1) @@ -3269,7 +3319,7 @@ void dsi_wait_pll_hsdiv_dsi_active(void) static int dsi_init(struct platform_device *pdev) { u32 rev; - int r; + int r, i; struct resource *dsi_mem; spin_lock_init(&dsi.errors_lock); @@ -3323,6 +3373,13 @@ static int dsi_init(struct platform_device *pdev) goto err2; } + /* DSI VCs initialization */ + for (i = 0; i < ARRAY_SIZE(dsi.vc); i++) { + dsi.vc[i].mode = DSI_VC_MODE_L4; + dsi.vc[i].dssdev = NULL; + dsi.vc[i].vc_id = 0; + } + enable_clocks(1); rev = dsi_read_reg(DSI_REVISION); -- cgit v1.2.2 From bc6d4b1d3d9b7568fe88f5bb80d0266a7ef624cc Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 1 Mar 2011 13:59:46 +0530 Subject: OMAP: DSS2: Use request / release calls in Taal for DSI Virtual Channels. Taal driver used to take a hard coded Macro for Virtual Channel and the VC_ID. The Taal panel driver now requests for a Virtual channel through the omap_dsi_request_vc() call in taal_probe(). The channel number returned by the request_vc() call is used for sending command and data to the Panel. The DSI driver automatically configures the Virtual Channel's source to either Video Port or L4 Slave port based on what the panel driver is using it for. The driver uses omap_dsi_release_vc() to free the VC specified by the panel. taal_remove() or when a request_vc() call fails. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 123 +++++++++++++++++------------- drivers/video/omap2/dss/dsi.c | 3 - 2 files changed, 71 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 61026f96ad20..abdfdd81001f 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -218,6 +218,8 @@ struct taal_data { u16 w; u16 h; } update_region; + int channel; + struct delayed_work te_timeout_work; bool use_dsi_bl; @@ -257,12 +259,12 @@ static void hw_guard_wait(struct taal_data *td) } } -static int taal_dcs_read_1(u8 dcs_cmd, u8 *data) +static int taal_dcs_read_1(struct taal_data *td, u8 dcs_cmd, u8 *data) { int r; u8 buf[1]; - r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1); + r = dsi_vc_dcs_read(td->channel, dcs_cmd, buf, 1); if (r < 0) return r; @@ -272,17 +274,17 @@ static int taal_dcs_read_1(u8 dcs_cmd, u8 *data) return 0; } -static int taal_dcs_write_0(u8 dcs_cmd) +static int taal_dcs_write_0(struct taal_data *td, u8 dcs_cmd) { - return dsi_vc_dcs_write(TCH, &dcs_cmd, 1); + return dsi_vc_dcs_write(td->channel, &dcs_cmd, 1); } -static int taal_dcs_write_1(u8 dcs_cmd, u8 param) +static int taal_dcs_write_1(struct taal_data *td, u8 dcs_cmd, u8 param) { u8 buf[2]; buf[0] = dcs_cmd; buf[1] = param; - return dsi_vc_dcs_write(TCH, buf, 2); + return dsi_vc_dcs_write(td->channel, buf, 2); } static int taal_sleep_in(struct taal_data *td) @@ -294,7 +296,7 @@ static int taal_sleep_in(struct taal_data *td) hw_guard_wait(td); cmd = DCS_SLEEP_IN; - r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1); + r = dsi_vc_dcs_write_nosync(td->channel, &cmd, 1); if (r) return r; @@ -312,7 +314,7 @@ static int taal_sleep_out(struct taal_data *td) hw_guard_wait(td); - r = taal_dcs_write_0(DCS_SLEEP_OUT); + r = taal_dcs_write_0(td, DCS_SLEEP_OUT); if (r) return r; @@ -324,30 +326,30 @@ static int taal_sleep_out(struct taal_data *td) return 0; } -static int taal_get_id(u8 *id1, u8 *id2, u8 *id3) +static int taal_get_id(struct taal_data *td, u8 *id1, u8 *id2, u8 *id3) { int r; - r = taal_dcs_read_1(DCS_GET_ID1, id1); + r = taal_dcs_read_1(td, DCS_GET_ID1, id1); if (r) return r; - r = taal_dcs_read_1(DCS_GET_ID2, id2); + r = taal_dcs_read_1(td, DCS_GET_ID2, id2); if (r) return r; - r = taal_dcs_read_1(DCS_GET_ID3, id3); + r = taal_dcs_read_1(td, DCS_GET_ID3, id3); if (r) return r; return 0; } -static int taal_set_addr_mode(u8 rotate, bool mirror) +static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror) { int r; u8 mode; int b5, b6, b7; - r = taal_dcs_read_1(DCS_READ_MADCTL, &mode); + r = taal_dcs_read_1(td, DCS_READ_MADCTL, &mode); if (r) return r; @@ -381,10 +383,11 @@ static int taal_set_addr_mode(u8 rotate, bool mirror) mode &= ~((1<<7) | (1<<6) | (1<<5)); mode |= (b7 << 7) | (b6 << 6) | (b5 << 5); - return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode); + return taal_dcs_write_1(td, DCS_MEM_ACC_CTRL, mode); } -static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h) +static int taal_set_update_window(struct taal_data *td, + u16 x, u16 y, u16 w, u16 h) { int r; u16 x1 = x; @@ -399,7 +402,7 @@ static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h) buf[3] = (x2 >> 8) & 0xff; buf[4] = (x2 >> 0) & 0xff; - r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf)); + r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf)); if (r) return r; @@ -409,11 +412,11 @@ static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h) buf[3] = (y2 >> 8) & 0xff; buf[4] = (y2 >> 0) & 0xff; - r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf)); + r = dsi_vc_dcs_write_nosync(td->channel, buf, sizeof(buf)); if (r) return r; - dsi_vc_send_bta_sync(TCH); + dsi_vc_send_bta_sync(td->channel); return r; } @@ -439,7 +442,7 @@ static int taal_bl_update_status(struct backlight_device *dev) if (td->use_dsi_bl) { if (td->enabled) { dsi_bus_lock(); - r = taal_dcs_write_1(DCS_BRIGHTNESS, level); + r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level); dsi_bus_unlock(); } else { r = 0; @@ -502,7 +505,7 @@ static ssize_t taal_num_errors_show(struct device *dev, if (td->enabled) { dsi_bus_lock(); - r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); + r = taal_dcs_read_1(td, DCS_READ_NUM_ERRORS, &errors); dsi_bus_unlock(); } else { r = -ENODEV; @@ -528,7 +531,7 @@ static ssize_t taal_hw_revision_show(struct device *dev, if (td->enabled) { dsi_bus_lock(); - r = taal_get_id(&id1, &id2, &id3); + r = taal_get_id(td, &id1, &id2, &id3); dsi_bus_unlock(); } else { r = -ENODEV; @@ -590,7 +593,7 @@ static ssize_t store_cabc_mode(struct device *dev, if (td->enabled) { dsi_bus_lock(); if (!td->cabc_broken) - taal_dcs_write_1(DCS_WRITE_CABC, i); + taal_dcs_write_1(td, DCS_WRITE_CABC, i); dsi_bus_unlock(); } @@ -774,14 +777,29 @@ static int taal_probe(struct omap_dss_device *dssdev) dev_dbg(&dssdev->dev, "Using GPIO TE\n"); } + r = omap_dsi_request_vc(dssdev, &td->channel); + if (r) { + dev_err(&dssdev->dev, "failed to get virtual channel\n"); + goto err_req_vc; + } + + r = omap_dsi_set_vc_id(dssdev, td->channel, TCH); + if (r) { + dev_err(&dssdev->dev, "failed to set VC_ID\n"); + goto err_vc_id; + } + r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); if (r) { dev_err(&dssdev->dev, "failed to create sysfs files\n"); - goto err_sysfs; + goto err_vc_id; } return 0; -err_sysfs: + +err_vc_id: + omap_dsi_release_vc(dssdev, td->channel); +err_req_vc: if (panel_data->use_ext_te) free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); err_irq: @@ -808,6 +826,7 @@ static void taal_remove(struct omap_dss_device *dssdev) dev_dbg(&dssdev->dev, "remove\n"); sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); + omap_dsi_release_vc(dssdev, td->channel); if (panel_data->use_ext_te) { int gpio = panel_data->ext_te_gpio; @@ -846,13 +865,13 @@ static int taal_power_on(struct omap_dss_device *dssdev) taal_hw_reset(dssdev); - omapdss_dsi_vc_enable_hs(TCH, false); + omapdss_dsi_vc_enable_hs(td->channel, false); r = taal_sleep_out(td); if (r) goto err; - r = taal_get_id(&id1, &id2, &id3); + r = taal_get_id(td, &id1, &id2, &id3); if (r) goto err; @@ -861,30 +880,30 @@ static int taal_power_on(struct omap_dss_device *dssdev) (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) td->cabc_broken = true; - r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); + r = taal_dcs_write_1(td, DCS_BRIGHTNESS, 0xff); if (r) goto err; - r = taal_dcs_write_1(DCS_CTRL_DISPLAY, + r = taal_dcs_write_1(td, DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */ if (r) goto err; - r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ + r = taal_dcs_write_1(td, DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ if (r) goto err; - r = taal_set_addr_mode(td->rotate, td->mirror); + r = taal_set_addr_mode(td, td->rotate, td->mirror); if (r) goto err; if (!td->cabc_broken) { - r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); + r = taal_dcs_write_1(td, DCS_WRITE_CABC, td->cabc_mode); if (r) goto err; } - r = taal_dcs_write_0(DCS_DISPLAY_ON); + r = taal_dcs_write_0(td, DCS_DISPLAY_ON); if (r) goto err; @@ -903,7 +922,7 @@ static int taal_power_on(struct omap_dss_device *dssdev) td->intro_printed = true; } - omapdss_dsi_vc_enable_hs(TCH, true); + omapdss_dsi_vc_enable_hs(td->channel, true); return 0; err: @@ -921,7 +940,7 @@ static void taal_power_off(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; - r = taal_dcs_write_0(DCS_DISPLAY_OFF); + r = taal_dcs_write_0(td, DCS_DISPLAY_OFF); if (!r) { r = taal_sleep_in(td); /* HACK: wait a bit so that the message goes through */ @@ -1089,7 +1108,7 @@ static irqreturn_t taal_te_isr(int irq, void *data) if (old) { cancel_delayed_work(&td->te_timeout_work); - r = omap_dsi_update(dssdev, TCH, + r = omap_dsi_update(dssdev, td->channel, td->update_region.x, td->update_region.y, td->update_region.w, @@ -1139,7 +1158,7 @@ static int taal_update(struct omap_dss_device *dssdev, if (r) goto err; - r = taal_set_update_window(x, y, w, h); + r = taal_set_update_window(td, x, y, w, h); if (r) goto err; @@ -1153,7 +1172,7 @@ static int taal_update(struct omap_dss_device *dssdev, msecs_to_jiffies(250)); atomic_set(&td->do_update, 1); } else { - r = omap_dsi_update(dssdev, TCH, x, y, w, h, + r = omap_dsi_update(dssdev, td->channel, x, y, w, h, taal_framedone_cb, dssdev); if (r) goto err; @@ -1191,9 +1210,9 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) int r; if (enable) - r = taal_dcs_write_1(DCS_TEAR_ON, 0); + r = taal_dcs_write_1(td, DCS_TEAR_ON, 0); else - r = taal_dcs_write_0(DCS_TEAR_OFF); + r = taal_dcs_write_0(td, DCS_TEAR_OFF); if (!panel_data->use_ext_te) omapdss_dsi_enable_te(dssdev, enable); @@ -1263,7 +1282,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) dsi_bus_lock(); if (td->enabled) { - r = taal_set_addr_mode(rotate, td->mirror); + r = taal_set_addr_mode(td, rotate, td->mirror); if (r) goto err; } @@ -1306,7 +1325,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) dsi_bus_lock(); if (td->enabled) { - r = taal_set_addr_mode(td->rotate, enable); + r = taal_set_addr_mode(td, td->rotate, enable); if (r) goto err; } @@ -1350,13 +1369,13 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num) dsi_bus_lock(); - r = taal_dcs_read_1(DCS_GET_ID1, &id1); + r = taal_dcs_read_1(td, DCS_GET_ID1, &id1); if (r) goto err2; - r = taal_dcs_read_1(DCS_GET_ID2, &id2); + r = taal_dcs_read_1(td, DCS_GET_ID2, &id2); if (r) goto err2; - r = taal_dcs_read_1(DCS_GET_ID3, &id3); + r = taal_dcs_read_1(td, DCS_GET_ID3, &id3); if (r) goto err2; @@ -1404,9 +1423,9 @@ static int taal_memory_read(struct omap_dss_device *dssdev, else plen = 2; - taal_set_update_window(x, y, w, h); + taal_set_update_window(td, x, y, w, h); - r = dsi_vc_set_max_rx_packet_size(TCH, plen); + r = dsi_vc_set_max_rx_packet_size(td->channel, plen); if (r) goto err2; @@ -1414,7 +1433,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev, u8 dcs_cmd = first ? 0x2e : 0x3e; first = 0; - r = dsi_vc_dcs_read(TCH, dcs_cmd, + r = dsi_vc_dcs_read(td->channel, dcs_cmd, buf + buf_used, size - buf_used); if (r < 0) { @@ -1440,7 +1459,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev, r = buf_used; err3: - dsi_vc_set_max_rx_packet_size(TCH, 1); + dsi_vc_set_max_rx_packet_size(td->channel, 1); err2: dsi_bus_unlock(); err1: @@ -1466,7 +1485,7 @@ static void taal_esd_work(struct work_struct *work) dsi_bus_lock(); - r = taal_dcs_read_1(DCS_RDDSDR, &state1); + r = taal_dcs_read_1(td, DCS_RDDSDR, &state1); if (r) { dev_err(&dssdev->dev, "failed to read Taal status\n"); goto err; @@ -1479,7 +1498,7 @@ static void taal_esd_work(struct work_struct *work) goto err; } - r = taal_dcs_read_1(DCS_RDDSDR, &state2); + r = taal_dcs_read_1(td, DCS_RDDSDR, &state2); if (r) { dev_err(&dssdev->dev, "failed to read Taal status\n"); goto err; @@ -1495,7 +1514,7 @@ static void taal_esd_work(struct work_struct *work) /* Self-diagnostics result is also shown on TE GPIO line. We need * to re-enable TE after self diagnostics */ if (td->te_enabled && panel_data->use_ext_te) { - r = taal_dcs_write_1(DCS_TEAR_ON, 0); + r = taal_dcs_write_1(td, DCS_TEAR_ON, 0); if (r) goto err; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index fe3578bbff7d..44b667b55ab8 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3230,9 +3230,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; - dsi.vc[0].dssdev = dssdev; - dsi.vc[1].dssdev = dssdev; - if (dsi.vdds_dsi_reg == NULL) { struct regulator *vdds_dsi; -- cgit v1.2.2 From f2988ab9f4a2bf5e24f37d20eab1aad6862953d3 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 10:06:48 +0200 Subject: HACK: OMAP: DSS2: Fix OMAP2_DSS_USE_DSI_PLL When using OMAP2_DSS_USE_DSI_PLL, which selects DSI PLL as source clock for DISPC, the DSI needs the vdds_dsi regulator. Latest regulator changes broke this, causing the the code to not acquire the regulator when using OMAP2_DSS_USE_DSI_PLL. This patch acquires the vdds_dsi regulator in dsi_pll_init(), fixing the issue. This is is just a quick hack to get the OMAP2_DSS_USE_DSI_PLL option working. There shouldn't be any other downside in this solution than some extra lines of code. OMAP2_DSS_USE_DSI_PLL is itself a big hack, and should be removed, and the feature itself should be implemented in a more sane way. However, the solution is not trivial, and people are using DSI PLL to get more exact pixel clocks, so this hack is an acceptable temporary solution for the time being. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 44b667b55ab8..be7694ff7ca7 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1119,6 +1119,26 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk, DSSDBG("PLL init\n"); +#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL + /* + * HACK: this is just a quick hack to get the USE_DSI_PLL + * option working. USE_DSI_PLL is itself a big hack, and + * should be removed. + */ + if (dsi.vdds_dsi_reg == NULL) { + struct regulator *vdds_dsi; + + vdds_dsi = regulator_get(&dsi.pdev->dev, "vdds_dsi"); + + if (IS_ERR(vdds_dsi)) { + DSSERR("can't get VDDS_DSI regulator\n"); + return PTR_ERR(vdds_dsi); + } + + dsi.vdds_dsi_reg = vdds_dsi; + } +#endif + enable_clocks(1); dsi_enable_pll_clock(1); -- cgit v1.2.2 From 85604b0a247615157cedfec46b9cbfde2884f80f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Mar 2011 13:16:23 +0200 Subject: HACK: OMAP: DSS2: add delay after enabling clocks On omap4 the registers may not be accessible right after enabling the clocks. At some point this will be handled by pm_runtime, but, for the time begin, adding a small delay after clk_enable() should make things work. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index e5da050bcf85..2be4d03ece43 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -850,6 +850,14 @@ void dss_clk_enable(enum dss_clock clks) dss_clk_enable_no_ctx(clks); + /* + * HACK: On omap4 the registers may not be accessible right after + * enabling the clocks. At some point this will be handled by + * pm_runtime, but for the time begin this should make things work. + */ + if (cpu_is_omap44xx() && check_ctx) + udelay(10); + if (check_ctx && cpu_is_omap34xx() && dss_need_ctx_restore()) restore_all_ctx(); } -- cgit v1.2.2 From 5c6366e14d9d4466ae34a1ccbc08dd8738909c1f Mon Sep 17 00:00:00 2001 From: "Murthy, Raghuveer" Date: Thu, 3 Mar 2011 09:27:58 -0600 Subject: OMAP: DSS2: Adding dss_features for independent core clk divider In OMAP3xxx DISPC_DIVISOR register has a logical clock divisor (lcd_div) field. The lcd_div is common, for deciding the DISPC core functional clock frequency, and the final pixel clock frequency for LCD display. In OMAP4, there are 2 LCD channels, hence two divisor registers, DISPC_DIVISOR1 and DISPC_DIVISOR2. Also, there is a third register DISPC_DIVISOR. The DISPC_DIVISOR in OMAP4 is used to configure lcd_div exclusively for core functional clock configuration. For pixel clock configuration of primary and secondary LCDs, lcd_div of DISPC_DIVISOR1 and DISPC_DIVISOR2 are used respectively Signed-off-by: Archit Taneja Signed-off-by: Raghuveer Murthy Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss_features.c | 3 ++- drivers/video/omap2/dss/dss_features.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index ccae57b34f5c..dc170ad079f2 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -234,7 +234,8 @@ static struct omap_dss_features omap4_dss_features = { .has_feature = FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | - FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1, + FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | + FEAT_CORE_CLK_DIV, .num_mgrs = 3, .num_ovls = 3, diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 65d6de7e0feb..569d1b295edd 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -36,6 +36,8 @@ enum dss_feat_id { FEAT_LINEBUFFERSPLIT = 1 << 8, FEAT_ROWREPEATENABLE = 1 << 9, FEAT_RESIZECONF = 1 << 10, + /* Independent core clk divider */ + FEAT_CORE_CLK_DIV = 1 << 11, }; /* DSS register field id */ -- cgit v1.2.2 From ce7fa5eb1e815e79e4dd5db42d0d1f8c9d96925b Mon Sep 17 00:00:00 2001 From: "Murthy, Raghuveer" Date: Thu, 3 Mar 2011 09:27:59 -0600 Subject: OMAP: DSS2: Renaming register macro DISPC_DIVISOR(ch) The OMAP4 DISPC_DIVISOR1 is backward compatible to OMAP3xxx DISPC_DIVISOR. However DISPC_DIVISOR is also provided in OMAP4, to control DISPC_CORE_CLK independent of Primary and Secondary display clocks. Renamed DISPC_DIVISOR(ch) to DISPC_DIVISORo(ch), to facilitate introduction of DISPC_DIVISOR register, which is specific for OMAP4. OMAP4 has 3 registers DISPC_DIVISOR, DISPC_DIVISOR1 and DISPC_DIVISOR2. Also updated, all the usages of DISPC_DIVISOR(ch) to DISPC_DIVISORo(ch). Use DISPC_DIVISORo(ch) when DISPC_DIVISOR1 or DISPC_DIVISOR2 has to be configured OMAP4 TRM uses DISPC_DIVISORo generically to refer to DISPC_DIVISOR1 and DISPC_DIVISOR2 Signed-off-by: Raghuveer Murthy Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 9fb11c17623f..a3dff5ffdcbb 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -73,7 +73,7 @@ struct dispc_reg { u16 idx; }; #define DISPC_TIMING_H(ch) DISPC_REG(ch != 2 ? 0x0064 : 0x0400) #define DISPC_TIMING_V(ch) DISPC_REG(ch != 2 ? 0x0068 : 0x0404) #define DISPC_POL_FREQ(ch) DISPC_REG(ch != 2 ? 0x006C : 0x0408) -#define DISPC_DIVISOR(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C) +#define DISPC_DIVISORo(ch) DISPC_REG(ch != 2 ? 0x0070 : 0x040C) #define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074) #define DISPC_SIZE_DIG DISPC_REG(0x0078) #define DISPC_SIZE_LCD(ch) DISPC_REG(ch != 2 ? 0x007C : 0x03CC) @@ -128,6 +128,7 @@ struct dispc_reg { u16 idx; }; #define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04) +#define DISPC_DIVISOR DISPC_REG(0x0804) #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ DISPC_IRQ_OCP_ERR | \ @@ -231,7 +232,7 @@ void dispc_save_context(void) SR(TIMING_H(0)); SR(TIMING_V(0)); SR(POL_FREQ(0)); - SR(DIVISOR(0)); + SR(DIVISORo(0)); SR(GLOBAL_ALPHA); SR(SIZE_DIG); SR(SIZE_LCD(0)); @@ -243,7 +244,7 @@ void dispc_save_context(void) SR(TIMING_H(2)); SR(TIMING_V(2)); SR(POL_FREQ(2)); - SR(DIVISOR(2)); + SR(DIVISORo(2)); SR(CONFIG2); } @@ -390,7 +391,7 @@ void dispc_restore_context(void) RR(TIMING_H(0)); RR(TIMING_V(0)); RR(POL_FREQ(0)); - RR(DIVISOR(0)); + RR(DIVISORo(0)); RR(GLOBAL_ALPHA); RR(SIZE_DIG); RR(SIZE_LCD(0)); @@ -401,7 +402,7 @@ void dispc_restore_context(void) RR(TIMING_H(2)); RR(TIMING_V(2)); RR(POL_FREQ(2)); - RR(DIVISOR(2)); + RR(DIVISORo(2)); RR(CONFIG2); } @@ -2316,7 +2317,7 @@ static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, BUG_ON(pck_div < 2); enable_clocks(1); - dispc_write_reg(DISPC_DIVISOR(channel), + dispc_write_reg(DISPC_DIVISORo(channel), FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); enable_clocks(0); } @@ -2325,7 +2326,7 @@ static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, int *pck_div) { u32 l; - l = dispc_read_reg(DISPC_DIVISOR(channel)); + l = dispc_read_reg(DISPC_DIVISORo(channel)); *lck_div = FLD_GET(l, 23, 16); *pck_div = FLD_GET(l, 7, 0); } @@ -2351,7 +2352,7 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR(channel)); + l = dispc_read_reg(DISPC_DIVISORo(channel)); lcd = FLD_GET(l, 23, 16); @@ -2366,7 +2367,7 @@ unsigned long dispc_pclk_rate(enum omap_channel channel) unsigned long r; u32 l; - l = dispc_read_reg(DISPC_DIVISOR(channel)); + l = dispc_read_reg(DISPC_DIVISORo(channel)); lcd = FLD_GET(l, 23, 16); pcd = FLD_GET(l, 7, 0); @@ -2483,7 +2484,7 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_TIMING_H(0)); DUMPREG(DISPC_TIMING_V(0)); DUMPREG(DISPC_POL_FREQ(0)); - DUMPREG(DISPC_DIVISOR(0)); + DUMPREG(DISPC_DIVISORo(0)); DUMPREG(DISPC_GLOBAL_ALPHA); DUMPREG(DISPC_SIZE_DIG); DUMPREG(DISPC_SIZE_LCD(0)); @@ -2495,7 +2496,7 @@ void dispc_dump_regs(struct seq_file *s) DUMPREG(DISPC_TIMING_H(2)); DUMPREG(DISPC_TIMING_V(2)); DUMPREG(DISPC_POL_FREQ(2)); - DUMPREG(DISPC_DIVISOR(2)); + DUMPREG(DISPC_DIVISORo(2)); DUMPREG(DISPC_SIZE_LCD(2)); } @@ -2737,8 +2738,8 @@ int dispc_get_clock_div(enum omap_channel channel, fck = dispc_fclk_rate(); - cinfo->lck_div = REG_GET(DISPC_DIVISOR(channel), 23, 16); - cinfo->pck_div = REG_GET(DISPC_DIVISOR(channel), 7, 0); + cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16); + cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0); cinfo->lck = fck / cinfo->lck_div; cinfo->pck = cinfo->lck / cinfo->pck_div; -- cgit v1.2.2 From 0cf35df353e8c36d4be0da2d7483896de599f397 Mon Sep 17 00:00:00 2001 From: "Murthy, Raghuveer" Date: Thu, 3 Mar 2011 09:28:00 -0600 Subject: OMAP4: DSS2: Using dss_features to set independent core clock divider Using dss_features to select independent core clock divider and setting it. Added the register used, to DISPC context save and restore group ----------------------------------------------------------------------- In OMAP4, the minimum DISPC_CORE_CLK required can be expressed as: DISPC_CORE_CLK >= max(PCLK1*HSCALE1, PCLK2*HSCALE2, ...) Where PCLKi is the pixel clock generated by MANAGERi and HSCALEi is the maximum horizontal downscaling done through MANAGERi Based on the usecase, core clk can be increased or decreased at runtime to save power. Such mechanism are not yet implemented. Hence, we set the core clock divisor to 1, to support maximum range of resolutions ------------------------------------------------------------------------ Signed-off-by: Raghuveer Murthy Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index a3dff5ffdcbb..dae9686fb437 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -375,6 +375,9 @@ void dispc_save_context(void) SR(VID_FIR_COEF_V(1, 7)); SR(VID_PRELOAD(1)); + + if (dss_has_feature(FEAT_CORE_CLK_DIV)) + SR(DIVISOR); } void dispc_restore_context(void) @@ -534,6 +537,9 @@ void dispc_restore_context(void) RR(VID_PRELOAD(1)); + if (dss_has_feature(FEAT_CORE_CLK_DIV)) + RR(DIVISOR); + /* enable last, because LCD & DIGIT enable are here */ RR(CONTROL); if (dss_has_feature(FEAT_MGR_LCD2)) @@ -2380,6 +2386,7 @@ unsigned long dispc_pclk_rate(enum omap_channel channel) void dispc_dump_clocks(struct seq_file *s) { int lcd, pcd; + u32 l; enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); enable_clocks(1); @@ -2392,6 +2399,14 @@ void dispc_dump_clocks(struct seq_file *s) seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); + if (dss_has_feature(FEAT_CORE_CLK_DIV)) { + seq_printf(s, "- DISPC-CORE-CLK -\n"); + l = dispc_read_reg(DISPC_DIVISOR); + lcd = FLD_GET(l, 23, 16); + + seq_printf(s, "lck\t\t%-16lulck div\t%u\n", + (dispc_fclk_rate()/lcd), lcd); + } seq_printf(s, "- LCD1 -\n"); dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); @@ -3287,6 +3302,15 @@ static void _omap_dispc_initial_config(void) l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */ dispc_write_reg(DISPC_SYSCONFIG, l); + /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ + if (dss_has_feature(FEAT_CORE_CLK_DIV)) { + l = dispc_read_reg(DISPC_DIVISOR); + /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ + l = FLD_MOD(l, 1, 0, 0); + l = FLD_MOD(l, 1, 23, 16); + dispc_write_reg(DISPC_DIVISOR, l); + } + /* FUNCGATED */ if (dss_has_feature(FEAT_FUNCGATED)) REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); -- cgit v1.2.2 From b9cb0984a6e6a09a4bcdc11ebc9f0eb71e5b6c85 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 4 Mar 2011 18:19:54 +0200 Subject: OMAP: DSS2: fix omap_dispc_register_isr() fail path Fix handling of error in omap_dispc_register_isr() in case there are no free isr slots available. Reported-by: Ben Tucker Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index dae9686fb437..4a368c47700e 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2831,6 +2831,9 @@ int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) break; } + if (ret) + goto err; + _omap_dispc_set_irqs(); spin_unlock_irqrestore(&dispc.irq_lock, flags); -- cgit v1.2.2 From 7654b4d3f4d2e2bc5b60990fc121891b95b33be5 Mon Sep 17 00:00:00 2001 From: Steve Sakoman Date: Sat, 5 Mar 2011 07:58:38 -0600 Subject: OMAP: DSS2: Add support for LG Philips LB035Q02 panel This patch adds support for the Gumstix Palo35 expansion board which utilizes the 320 x 240 pixel LG.Philips LB035Q02 LCD Panel Signed-off-by: Steve Sakoman Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/Kconfig | 6 + drivers/video/omap2/displays/Makefile | 1 + .../omap2/displays/panel-lgphilips-lb035q02.c | 279 +++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 drivers/video/omap2/displays/panel-lgphilips-lb035q02.c (limited to 'drivers') diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 940cab394c2e..d18ad6b2372a 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig @@ -9,6 +9,12 @@ config PANEL_GENERIC_DPI Supports LCD Panel used in TI SDP3430 and EVM boards, OMAP3517 EVM boards and CM-T35. +config PANEL_LGPHILIPS_LB035Q02 + tristate "LG.Philips LB035Q02 LCD Panel" + depends on OMAP2_DSS && SPI + help + LCD Panel used on the Gumstix Overo Palo35 + config PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" depends on OMAP2_DSS diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index 861f0255ec6b..0f601ab3abf4 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o +obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c new file mode 100644 index 000000000000..271324db2436 --- /dev/null +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c @@ -0,0 +1,279 @@ +/* + * LCD panel driver for LG.Philips LB035Q02 + * + * Author: Steve Sakoman + * + * 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include + +#include + +struct lb035q02_data { + struct mutex lock; +}; + +static struct omap_video_timings lb035q02_timings = { + .x_res = 320, + .y_res = 240, + + .pixel_clock = 6500, + + .hsw = 2, + .hfp = 20, + .hbp = 68, + + .vsw = 2, + .vfp = 4, + .vbp = 18, +}; + +static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) +{ + int r; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + return 0; + + r = omapdss_dpi_display_enable(dssdev); + if (r) + goto err0; + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) + goto err1; + } + + return 0; +err1: + omapdss_dpi_display_disable(dssdev); +err0: + return r; +} + +static void lb035q02_panel_power_off(struct omap_dss_device *dssdev) +{ + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return; + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + + omapdss_dpi_display_disable(dssdev); +} + +static int lb035q02_panel_probe(struct omap_dss_device *dssdev) +{ + struct lb035q02_data *ld; + int r; + + dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS; + dssdev->panel.timings = lb035q02_timings; + + ld = kzalloc(sizeof(*ld), GFP_KERNEL); + if (!ld) { + r = -ENOMEM; + goto err; + } + mutex_init(&ld->lock); + dev_set_drvdata(&dssdev->dev, ld); + return 0; +err: + return r; +} + +static void lb035q02_panel_remove(struct omap_dss_device *dssdev) +{ + struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); + + kfree(ld); +} + +static int lb035q02_panel_enable(struct omap_dss_device *dssdev) +{ + struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&ld->lock); + + r = lb035q02_panel_power_on(dssdev); + if (r) + goto err; + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&ld->lock); + return 0; +err: + mutex_unlock(&ld->lock); + return r; +} + +static void lb035q02_panel_disable(struct omap_dss_device *dssdev) +{ + struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&ld->lock); + + lb035q02_panel_power_off(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&ld->lock); +} + +static int lb035q02_panel_suspend(struct omap_dss_device *dssdev) +{ + struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); + + mutex_lock(&ld->lock); + + lb035q02_panel_power_off(dssdev); + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + + mutex_unlock(&ld->lock); + return 0; +} + +static int lb035q02_panel_resume(struct omap_dss_device *dssdev) +{ + struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); + int r; + + mutex_lock(&ld->lock); + + r = lb035q02_panel_power_on(dssdev); + if (r) + goto err; + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + + mutex_unlock(&ld->lock); + return 0; +err: + mutex_unlock(&ld->lock); + return r; +} + +static struct omap_dss_driver lb035q02_driver = { + .probe = lb035q02_panel_probe, + .remove = lb035q02_panel_remove, + + .enable = lb035q02_panel_enable, + .disable = lb035q02_panel_disable, + .suspend = lb035q02_panel_suspend, + .resume = lb035q02_panel_resume, + + .driver = { + .name = "lgphilips_lb035q02_panel", + .owner = THIS_MODULE, + }, +}; + +static int lb035q02_write_reg(struct spi_device *spi, u8 reg, u16 val) +{ + struct spi_message msg; + struct spi_transfer index_xfer = { + .len = 3, + .cs_change = 1, + }; + struct spi_transfer value_xfer = { + .len = 3, + }; + u8 buffer[16]; + + spi_message_init(&msg); + + /* register index */ + buffer[0] = 0x70; + buffer[1] = 0x00; + buffer[2] = reg & 0x7f; + index_xfer.tx_buf = buffer; + spi_message_add_tail(&index_xfer, &msg); + + /* register value */ + buffer[4] = 0x72; + buffer[5] = val >> 8; + buffer[6] = val; + value_xfer.tx_buf = buffer + 4; + spi_message_add_tail(&value_xfer, &msg); + + return spi_sync(spi, &msg); +} + +static void init_lb035q02_panel(struct spi_device *spi) +{ + /* Init sequence from page 28 of the lb035q02 spec */ + lb035q02_write_reg(spi, 0x01, 0x6300); + lb035q02_write_reg(spi, 0x02, 0x0200); + lb035q02_write_reg(spi, 0x03, 0x0177); + lb035q02_write_reg(spi, 0x04, 0x04c7); + lb035q02_write_reg(spi, 0x05, 0xffc0); + lb035q02_write_reg(spi, 0x06, 0xe806); + lb035q02_write_reg(spi, 0x0a, 0x4008); + lb035q02_write_reg(spi, 0x0b, 0x0000); + lb035q02_write_reg(spi, 0x0d, 0x0030); + lb035q02_write_reg(spi, 0x0e, 0x2800); + lb035q02_write_reg(spi, 0x0f, 0x0000); + lb035q02_write_reg(spi, 0x16, 0x9f80); + lb035q02_write_reg(spi, 0x17, 0x0a0f); + lb035q02_write_reg(spi, 0x1e, 0x00c1); + lb035q02_write_reg(spi, 0x30, 0x0300); + lb035q02_write_reg(spi, 0x31, 0x0007); + lb035q02_write_reg(spi, 0x32, 0x0000); + lb035q02_write_reg(spi, 0x33, 0x0000); + lb035q02_write_reg(spi, 0x34, 0x0707); + lb035q02_write_reg(spi, 0x35, 0x0004); + lb035q02_write_reg(spi, 0x36, 0x0302); + lb035q02_write_reg(spi, 0x37, 0x0202); + lb035q02_write_reg(spi, 0x3a, 0x0a0d); + lb035q02_write_reg(spi, 0x3b, 0x0806); +} + +static int __devinit lb035q02_panel_spi_probe(struct spi_device *spi) +{ + init_lb035q02_panel(spi); + return omap_dss_register_driver(&lb035q02_driver); +} + +static int __devexit lb035q02_panel_spi_remove(struct spi_device *spi) +{ + omap_dss_unregister_driver(&lb035q02_driver); + return 0; +} + +static struct spi_driver lb035q02_spi_driver = { + .driver = { + .name = "lgphilips_lb035q02_panel-spi", + .owner = THIS_MODULE, + }, + .probe = lb035q02_panel_spi_probe, + .remove = __devexit_p(lb035q02_panel_spi_remove), +}; + +static int __init lb035q02_panel_drv_init(void) +{ + return spi_register_driver(&lb035q02_spi_driver); +} + +static void __exit lb035q02_panel_drv_exit(void) +{ + spi_unregister_driver(&lb035q02_spi_driver); +} + +module_init(lb035q02_panel_drv_init); +module_exit(lb035q02_panel_drv_exit); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 66534e8e936a0b926863df90054dc59826d70528 Mon Sep 17 00:00:00 2001 From: "Taneja, Archit" Date: Tue, 8 Mar 2011 05:50:34 -0600 Subject: OMAP2PLUS: DSS2: Cleanup clock source related code Clean up some of the DSS functions which select/get clock sources, use switch to select the clock source members since more clock sources will be introduced later on. Remove the use of macro CONFIG_OMAP2_DSS_DSI in dispc_fclk_rate, use a dummy inline for function for dsi_get_pll_hsdiv_dispc_rate() instead for code clarity. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 15 +++++++++------ drivers/video/omap2/dss/dss.c | 32 ++++++++++++++++++++------------ drivers/video/omap2/dss/dss.h | 5 +++++ 3 files changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 4a368c47700e..28b690f2447f 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2341,14 +2341,17 @@ unsigned long dispc_fclk_rate(void) { unsigned long r = 0; - if (dss_get_dispc_clk_source() == DSS_CLK_SRC_FCK) + switch (dss_get_dispc_clk_source()) { + case DSS_CLK_SRC_FCK: r = dss_clk_get_rate(DSS_CLK_FCK); - else -#ifdef CONFIG_OMAP2_DSS_DSI + break; + case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: r = dsi_get_pll_hsdiv_dispc_rate(); -#else - BUG(); -#endif + break; + default: + BUG(); + } + return r; } diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 2be4d03ece43..93813fd626be 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -293,13 +293,17 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) { int b; - BUG_ON(clk_src != DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC && - clk_src != DSS_CLK_SRC_FCK); - - b = clk_src == DSS_CLK_SRC_FCK ? 0 : 1; - - if (clk_src == DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC) + switch (clk_src) { + case DSS_CLK_SRC_FCK: + b = 0; + break; + case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: + b = 1; dsi_wait_pll_hsdiv_dispc_active(); + break; + default: + BUG(); + } REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ @@ -310,13 +314,17 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) { int b; - BUG_ON(clk_src != DSS_CLK_SRC_DSI_PLL_HSDIV_DSI && - clk_src != DSS_CLK_SRC_FCK); - - b = clk_src == DSS_CLK_SRC_FCK ? 0 : 1; - - if (clk_src == DSS_CLK_SRC_DSI_PLL_HSDIV_DSI) + switch (clk_src) { + case DSS_CLK_SRC_FCK: + b = 0; + break; + case DSS_CLK_SRC_DSI_PLL_HSDIV_DSI: + b = 1; dsi_wait_pll_hsdiv_dsi_active(); + break; + default: + BUG(); + } REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 85d4141689c1..fc41b3f0c27e 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -299,6 +299,11 @@ static inline int dsi_init_platform_driver(void) static inline void dsi_uninit_platform_driver(void) { } +static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(void) +{ + WARN("%s: DSI not compiled in, returning rate as 0\n", __func__); + return 0; +} static inline void dsi_wait_pll_hsdiv_dispc_active(void) { } -- cgit v1.2.2 From ea75159ee6f00bd809f57a58e5505dc362382cc8 Mon Sep 17 00:00:00 2001 From: "Taneja, Archit" Date: Tue, 8 Mar 2011 05:50:35 -0600 Subject: OMAP4: DSS2: Clock source changes for OMAP4 On OMAP3, the pixel clock for the LCD manager was derived through DISPC_FCLK as: Lcd Pixel clock = DISPC_FCLK / lcd / pcd Where lcd and pcd are divisors in the DISPC_DIVISOR register. On OMAP4, the pixel clocks for LCD1 and LCD2 managers are derived from 2 new clocks named LCD1_CLK and LCD2_CLK. The pixel clocks are calculated as: Lcd_o Pixel clock = LCDo_CLK / lcdo /pcdo, o = 1, 2 Where lcdo and pcdo registers are divisors in DISPC_DIVISORo registers. LCD1_CLK and LCD2_CLK can have DSS_FCLK, and the M4 divider clocks of DSI1 PLL and DSI2 PLL as clock sources respectively. Introduce functions to select and get the clock source for these new clocks. Modify DISPC functions get the correct lck and pck rates based on the clock source of these clocks. Since OMAP2/3 don't have these clocks, force OMAP2/3 to always have the LCD_CLK source as DSS_CLK_SRC_FCK by introducing a dss feature. Introduce clock source names for OMAP4 and some register field changes in DSS_CTRL on OMAP4. Currently, LCD2_CLK can only have DSS_FCLK as its clock source as DSI2 PLL functionality hasn't been introduced yet. BUG for now if DSI2 PLL is selected as clock. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 31 +++++++++++++++++++++---- drivers/video/omap2/dss/dss.c | 42 +++++++++++++++++++++++++++++++++- drivers/video/omap2/dss/dss.h | 26 +++++++++++++-------- drivers/video/omap2/dss/dss_features.c | 13 +++++++++-- drivers/video/omap2/dss/dss_features.h | 3 +++ 5 files changed, 98 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 28b690f2447f..b8c576a0bc02 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2365,25 +2365,33 @@ unsigned long dispc_lclk_rate(enum omap_channel channel) lcd = FLD_GET(l, 23, 16); - r = dispc_fclk_rate(); + switch (dss_get_lcd_clk_source(channel)) { + case DSS_CLK_SRC_FCK: + r = dss_clk_get_rate(DSS_CLK_FCK); + break; + case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: + r = dsi_get_pll_hsdiv_dispc_rate(); + break; + default: + BUG(); + } return r / lcd; } unsigned long dispc_pclk_rate(enum omap_channel channel) { - int lcd, pcd; + int pcd; unsigned long r; u32 l; l = dispc_read_reg(DISPC_DIVISORo(channel)); - lcd = FLD_GET(l, 23, 16); pcd = FLD_GET(l, 7, 0); - r = dispc_fclk_rate(); + r = dispc_lclk_rate(channel); - return r / lcd / pcd; + return r / pcd; } void dispc_dump_clocks(struct seq_file *s) @@ -2391,6 +2399,7 @@ void dispc_dump_clocks(struct seq_file *s) int lcd, pcd; u32 l; enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); + enum dss_clk_source lcd_clk_src; enable_clocks(1); @@ -2412,6 +2421,12 @@ void dispc_dump_clocks(struct seq_file *s) } seq_printf(s, "- LCD1 -\n"); + lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD); + + seq_printf(s, "lcd1_clk source = %s (%s)\n", + dss_get_generic_clk_source_name(lcd_clk_src), + dss_feat_get_clk_source_name(lcd_clk_src)); + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); seq_printf(s, "lck\t\t%-16lulck div\t%u\n", @@ -2421,6 +2436,12 @@ void dispc_dump_clocks(struct seq_file *s) if (dss_has_feature(FEAT_MGR_LCD2)) { seq_printf(s, "- LCD2 -\n"); + lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2); + + seq_printf(s, "lcd2_clk source = %s (%s)\n", + dss_get_generic_clk_source_name(lcd_clk_src), + dss_feat_get_clk_source_name(lcd_clk_src)); + dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); seq_printf(s, "lck\t\t%-16lulck div\t%u\n", diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 93813fd626be..aed9345e8ada 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -77,6 +77,7 @@ static struct { enum dss_clk_source dsi_clk_source; enum dss_clk_source dispc_clk_source; + enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; @@ -292,6 +293,7 @@ void dss_dump_regs(struct seq_file *s) void dss_select_dispc_clk_source(enum dss_clk_source clk_src) { int b; + u8 start, end; switch (clk_src) { case DSS_CLK_SRC_FCK: @@ -305,7 +307,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) BUG(); } - REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ + dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); + + REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */ dss.dispc_clk_source = clk_src; } @@ -331,6 +335,34 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) dss.dsi_clk_source = clk_src; } +void dss_select_lcd_clk_source(enum omap_channel channel, + enum dss_clk_source clk_src) +{ + int b, ix, pos; + + if (!dss_has_feature(FEAT_LCD_CLK_SRC)) + return; + + switch (clk_src) { + case DSS_CLK_SRC_FCK: + b = 0; + break; + case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: + BUG_ON(channel != OMAP_DSS_CHANNEL_LCD); + b = 1; + dsi_wait_pll_hsdiv_dispc_active(); + break; + default: + BUG(); + } + + pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12; + REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */ + + ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; + dss.lcd_clk_source[ix] = clk_src; +} + enum dss_clk_source dss_get_dispc_clk_source(void) { return dss.dispc_clk_source; @@ -341,6 +373,12 @@ enum dss_clk_source dss_get_dsi_clk_source(void) return dss.dsi_clk_source; } +enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) +{ + int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; + return dss.lcd_clk_source[ix]; +} + /* calculate clock rates using dividers in cinfo */ int dss_calc_clock_rates(struct dss_clock_info *cinfo) { @@ -624,6 +662,8 @@ static int dss_init(void) dss.dsi_clk_source = DSS_CLK_SRC_FCK; dss.dispc_clk_source = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; dss_save_context(); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index fc41b3f0c27e..b845468d9706 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -118,9 +118,12 @@ enum dss_clock { }; enum dss_clk_source { - DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, /* DSI1_PLL_FCLK */ - DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, /* DSI2_PLL_FCLK */ - DSS_CLK_SRC_FCK, /* DSS1_ALWON_FCLK */ + DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, /* OMAP3: DSI1_PLL_FCLK + * OMAP4: PLL1_CLK1 */ + DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, /* OMAP3: DSI2_PLL_FCLK + * OMAP4: PLL1_CLK2 */ + DSS_CLK_SRC_FCK, /* OMAP2/3: DSS1_ALWON_FCLK + * OMAP4: DSS_FCLK */ }; /* Correlates clock source name and dss_clk_source member */ @@ -152,17 +155,19 @@ struct dsi_clock_info { unsigned long fint; unsigned long clkin4ddr; unsigned long clkin; - unsigned long dsi_pll_hsdiv_dispc_clk; /* DSI1_PLL_CLK */ - unsigned long dsi_pll_hsdiv_dsi_clk; /* DSI2_PLL_CLK */ - + unsigned long dsi_pll_hsdiv_dispc_clk; /* OMAP3: DSI1_PLL_CLK + * OMAP4: PLLx_CLK1 */ + unsigned long dsi_pll_hsdiv_dsi_clk; /* OMAP3: DSI2_PLL_CLK + * OMAP4: PLLx_CLK2 */ unsigned long lp_clk; /* dividers */ u16 regn; u16 regm; - u16 regm_dispc; /* REGM3 */ - u16 regm_dsi; /* REGM4 */ - + u16 regm_dispc; /* OMAP3: REGM3 + * OMAP4: REGM4 */ + u16 regm_dsi; /* OMAP3: REGM4 + * OMAP4: REGM5 */ u16 lp_clk_div; u8 highfreq; @@ -235,8 +240,11 @@ void dss_sdi_disable(void); void dss_select_dispc_clk_source(enum dss_clk_source clk_src); void dss_select_dsi_clk_source(enum dss_clk_source clk_src); +void dss_select_lcd_clk_source(enum omap_channel channel, + enum dss_clk_source clk_src); enum dss_clk_source dss_get_dispc_clk_source(void); enum dss_clk_source dss_get_dsi_clk_source(void); +enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel); void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index dc170ad079f2..6eb6ec62a000 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -59,6 +59,7 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = { { FEAT_REG_FIFOSIZE, 8, 0 }, { FEAT_REG_HORIZONTALACCU, 9, 0 }, { FEAT_REG_VERTICALACCU, 25, 16 }, + { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 }, }; static const struct dss_reg_field omap3_dss_reg_fields[] = { @@ -69,6 +70,7 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = { { FEAT_REG_FIFOSIZE, 10, 0 }, { FEAT_REG_HORIZONTALACCU, 9, 0 }, { FEAT_REG_VERTICALACCU, 25, 16 }, + { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 }, }; static const struct dss_reg_field omap4_dss_reg_fields[] = { @@ -79,6 +81,7 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { { FEAT_REG_FIFOSIZE, 15, 0 }, { FEAT_REG_HORIZONTALACCU, 10, 0 }, { FEAT_REG_VERTICALACCU, 26, 16 }, + { FEAT_REG_DISPC_CLK_SWITCH, 9, 8 }, }; static const enum omap_display_type omap2_dss_supported_displays[] = { @@ -171,6 +174,12 @@ static const struct dss_clk_source_name omap3_dss_clk_source_names[] = { { DSS_CLK_SRC_FCK, "DSS1_ALWON_FCLK" }, }; +static const struct dss_clk_source_name omap4_dss_clk_source_names[] = { + { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "PLL1_CLK1" }, + { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "PLL1_CLK2" }, + { DSS_CLK_SRC_FCK, "DSS_FCLK" }, +}; + /* OMAP2 DSS Features */ static struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, @@ -235,14 +244,14 @@ static struct omap_dss_features omap4_dss_features = { .has_feature = FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | - FEAT_CORE_CLK_DIV, + FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC, .num_mgrs = 3, .num_ovls = 3, .max_dss_fck = 186000000, .supported_displays = omap4_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, - .clksrc_names = omap3_dss_clk_source_names, + .clksrc_names = omap4_dss_clk_source_names, }; /* Functions returning values related to a DSS feature */ diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 569d1b295edd..729b5f19fa2e 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -22,6 +22,7 @@ #define MAX_DSS_MANAGERS 3 #define MAX_DSS_OVERLAYS 3 +#define MAX_DSS_LCD_MANAGERS 2 /* DSS has feature id */ enum dss_feat_id { @@ -38,6 +39,7 @@ enum dss_feat_id { FEAT_RESIZECONF = 1 << 10, /* Independent core clk divider */ FEAT_CORE_CLK_DIV = 1 << 11, + FEAT_LCD_CLK_SRC = 1 << 12, }; /* DSS register field id */ @@ -49,6 +51,7 @@ enum dss_feat_reg_field { FEAT_REG_FIFOSIZE, FEAT_REG_HORIZONTALACCU, FEAT_REG_VERTICALACCU, + FEAT_REG_DISPC_CLK_SWITCH, }; /* DSS Feature Functions */ -- cgit v1.2.2 From 4d42942cff0785d8a153bafcd62b6870726cd5f1 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 11 Jan 2011 14:33:35 +0300 Subject: mtd: make MTD_CONCAT support mandatory Move mtdconcat to be an integral part of the mtd core. It's a tiny bit of code, which bears 'say Y if you don't know what to do' note in the Kconfig. OTOH there are several ugly ifdefs depending on the MTD_CONCAT. So, making MTD_CONCAT support mandatory will allow us to clean up code a lot. Kconfig entry is changed to be a bool defaulting to Y, so all code pieces depending on it, will have MTD_CONCAT Kconfig symbol and CONFIG_MTD_CONCAT define. This will be removed in one of next patches. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Stefan Roese Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/Kconfig | 3 ++- drivers/mtd/Makefile | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 77414702cb00..c800247c04fb 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -34,7 +34,8 @@ config MTD_TESTS various checks and verifications when loaded. config MTD_CONCAT - tristate "MTD concatenating support" + bool + default y help Support for concatenating several MTD devices into a single (virtual) one. This allows you to have -for example- a JFFS(2) diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index d4e7f25b1ebb..eff3dd53cc05 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -4,11 +4,10 @@ # Core functionality. obj-$(CONFIG_MTD) += mtd.o -mtd-y := mtdcore.o mtdsuper.o +mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o -obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o -- cgit v1.2.2 From e1d6ee722285278b427007fc3fa4421a0c1b3b3c Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 11 Jan 2011 14:33:36 +0300 Subject: mtd: drop MTD_CONCAT dependencies from Kconfig As MTD_CONCAT is becoming a part of mtd core, it's no longer necessary to depend on it in Kconfig scripts. Drop such references. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Stefan Roese Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 5d37d315fa98..803072a71ed7 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -114,7 +114,7 @@ config MTD_SUN_UFLASH config MTD_SC520CDP tristate "CFI Flash device mapped on AMD SC520 CDP" - depends on X86 && MTD_CFI && MTD_CONCAT + depends on X86 && MTD_CFI help The SC520 CDP board has two banks of CFI-compliant chips and one Dual-in-line JEDEC chip. This 'mapping' driver supports that @@ -262,7 +262,7 @@ config MTD_BCM963XX config MTD_DILNETPC tristate "CFI Flash device mapped on DIL/Net PC" - depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN + depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN help MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP". For details, see -- cgit v1.2.2 From a8adc3f01b9a757a0d290b2987af6b998697399f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 11 Jan 2011 14:33:37 +0300 Subject: mtd: drop CONFIG_MTD_CONCAT ifdefs As MTD_CONCAT is becoming a part of mtd core, it's now meaningless to to check for it in ifdefs. Drop such references from MTD code. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Stefan Roese Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/ceiva.c | 6 ------ drivers/mtd/maps/integrator-flash.c | 10 ---------- drivers/mtd/maps/physmap.c | 8 -------- drivers/mtd/maps/physmap_of.c | 8 -------- drivers/mtd/maps/sa1100-flash.c | 8 -------- 5 files changed, 40 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index c09f4f57093e..e5f645b775ad 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -194,16 +194,10 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info * We detected multiple devices. Concatenate * them together. */ -#ifdef CONFIG_MTD_CONCAT *rmtd = mtd_concat_create(subdev, found, "clps flash"); if (*rmtd == NULL) ret = -ENXIO; -#else - printk(KERN_ERR "clps flash: multiple devices " - "found but MTD concat support disabled.\n"); - ret = -ENXIO; -#endif } } diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c index 2aac41bde8b3..e22ff5adbbf4 100644 --- a/drivers/mtd/maps/integrator-flash.c +++ b/drivers/mtd/maps/integrator-flash.c @@ -202,7 +202,6 @@ static int armflash_probe(struct platform_device *dev) if (info->nr_subdev == 1) info->mtd = info->subdev[0].mtd; else if (info->nr_subdev > 1) { -#ifdef CONFIG_MTD_CONCAT struct mtd_info *cdev[info->nr_subdev]; /* @@ -215,11 +214,6 @@ static int armflash_probe(struct platform_device *dev) dev_name(&dev->dev)); if (info->mtd == NULL) err = -ENXIO; -#else - printk(KERN_ERR "armflash: multiple devices found but " - "MTD concat support disabled.\n"); - err = -ENXIO; -#endif } if (err < 0) @@ -244,10 +238,8 @@ static int armflash_probe(struct platform_device *dev) cleanup: if (info->mtd) { del_mtd_partitions(info->mtd); -#ifdef CONFIG_MTD_CONCAT if (info->mtd != info->subdev[0].mtd) mtd_concat_destroy(info->mtd); -#endif } kfree(info->parts); subdev_err: @@ -272,10 +264,8 @@ static int armflash_remove(struct platform_device *dev) if (info) { if (info->mtd) { del_mtd_partitions(info->mtd); -#ifdef CONFIG_MTD_CONCAT if (info->mtd != info->subdev[0].mtd) mtd_concat_destroy(info->mtd); -#endif } kfree(info->parts); diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 4c18b98a3110..7522df4f71f1 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -59,10 +59,8 @@ static int physmap_flash_remove(struct platform_device *dev) #else del_mtd_device(info->cmtd); #endif -#ifdef CONFIG_MTD_CONCAT if (info->cmtd != info->mtd[0]) mtd_concat_destroy(info->cmtd); -#endif } for (i = 0; i < MAX_RESOURCES; i++) { @@ -159,15 +157,9 @@ static int physmap_flash_probe(struct platform_device *dev) /* * We detected multiple devices. Concatenate them together. */ -#ifdef CONFIG_MTD_CONCAT info->cmtd = mtd_concat_create(info->mtd, devices_found, dev_name(&dev->dev)); if (info->cmtd == NULL) err = -ENXIO; -#else - printk(KERN_ERR "physmap-flash: multiple devices " - "found but MTD concat support disabled.\n"); - err = -ENXIO; -#endif } if (err) goto err_out; diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 8506578e6a35..c85be8312488 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -104,12 +104,10 @@ static int of_flash_remove(struct platform_device *dev) return 0; dev_set_drvdata(&dev->dev, NULL); -#ifdef CONFIG_MTD_CONCAT if (info->cmtd != info->list[0].mtd) { del_mtd_device(info->cmtd); mtd_concat_destroy(info->cmtd); } -#endif if (info->cmtd) { if (OF_FLASH_PARTS(info)) { @@ -334,16 +332,10 @@ static int __devinit of_flash_probe(struct platform_device *dev, /* * We detected multiple devices. Concatenate them together. */ -#ifdef CONFIG_MTD_CONCAT info->cmtd = mtd_concat_create(mtd_list, info->list_size, dev_name(&dev->dev)); if (info->cmtd == NULL) err = -ENXIO; -#else - printk(KERN_ERR "physmap_of: multiple devices " - "found but MTD concat support disabled.\n"); - err = -ENXIO; -#endif } if (err) goto err_out; diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index f3af87e08ecd..da875908ea8e 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -232,10 +232,8 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla else del_mtd_partitions(info->mtd); #endif -#ifdef CONFIG_MTD_CONCAT if (info->mtd != info->subdev[0].mtd) mtd_concat_destroy(info->mtd); -#endif } kfree(info->parts); @@ -321,7 +319,6 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) info->mtd = info->subdev[0].mtd; ret = 0; } else if (info->num_subdev > 1) { -#ifdef CONFIG_MTD_CONCAT struct mtd_info *cdev[nr]; /* * We detected multiple devices. Concatenate them together. @@ -333,11 +330,6 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat) plat->name); if (info->mtd == NULL) ret = -ENXIO; -#else - printk(KERN_ERR "SA1100 flash: multiple devices " - "found but MTD concat support disabled.\n"); - ret = -ENXIO; -#endif } if (ret == 0) -- cgit v1.2.2 From f53fdebcc3e1e5d15ffd0b1204d5944b4ceb8a07 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Tue, 11 Jan 2011 14:33:39 +0300 Subject: mtd: drop MTD_CONCAT from Kconfig entirely As there are no more dependencies on MTD_CONCAT or CONFIG_MTD_CONCAT, drop this entry from Kconfig entirely. Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Stefan Roese Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/Kconfig | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index c800247c04fb..23088b3372d0 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -33,15 +33,6 @@ config MTD_TESTS should normally be compiled as kernel modules. The modules perform various checks and verifications when loaded. -config MTD_CONCAT - bool - default y - help - Support for concatenating several MTD devices into a single - (virtual) one. This allows you to have -for example- a JFFS(2) - file system spanning multiple physical flash chips. If unsure, - say 'Y'. - config MTD_PARTITIONS bool "MTD partitioning support" help -- cgit v1.2.2 From 83025c824fce44b6d007b9bbc506c4189fb89da1 Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Tue, 11 Jan 2011 12:43:49 +0000 Subject: mtd: mpc5121_nfc: don't treat NULL clk as an error clk_get() returns a struct clk cookie to the driver and some platforms may return NULL if they only support a single clock. clk_get() has only failed if it returns a ERR_PTR() encoded pointer. Signed-off-by: Jamie Iles Reviewed-by: Wolfram Sang Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/mpc5121_nfc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 469e649c911c..ddaf0011aa88 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -758,9 +759,9 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op, /* Enable NFC clock */ prv->clk = clk_get(dev, "nfc_clk"); - if (!prv->clk) { + if (IS_ERR(prv->clk)) { dev_err(dev, "Unable to acquire NFC clock!\n"); - retval = -ENODEV; + retval = PTR_ERR(prv->clk); goto error; } -- cgit v1.2.2 From ca91facf6babe548b5386993bb2820b7dc9b743d Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 11 Jan 2011 18:37:25 -0600 Subject: mtd: local symbols should be static The three backing_dev_info symbols are only used in this file and should be static. Signed-off-by: H Hartley Sweeten Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdcore.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 527cebf58da4..da69bc8a5a7d 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -43,7 +43,7 @@ * backing device capabilities for non-mappable devices (such as NAND flash) * - permits private mappings, copies are taken of the data */ -struct backing_dev_info mtd_bdi_unmappable = { +static struct backing_dev_info mtd_bdi_unmappable = { .capabilities = BDI_CAP_MAP_COPY, }; @@ -52,7 +52,7 @@ struct backing_dev_info mtd_bdi_unmappable = { * - permits private mappings, copies are taken of the data * - permits non-writable shared mappings */ -struct backing_dev_info mtd_bdi_ro_mappable = { +static struct backing_dev_info mtd_bdi_ro_mappable = { .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP), }; @@ -62,7 +62,7 @@ struct backing_dev_info mtd_bdi_ro_mappable = { * - permits private mappings, copies are taken of the data * - permits non-writable shared mappings */ -struct backing_dev_info mtd_bdi_rw_mappable = { +static struct backing_dev_info mtd_bdi_rw_mappable = { .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT | BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP), -- cgit v1.2.2 From 7f53f12f02b0b60af373a07fcac62b578381308e Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 11 Jan 2011 18:46:10 -0600 Subject: mtd: mtd_blkdevs: local symbols should be static The function blktrans_dev_release and blktrans_dev_put are only used locally in this file and should be static. Signed-off-by: H Hartley Sweeten Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtd_blkdevs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index e0a2373bf0e2..344ac1037ee7 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -40,7 +40,7 @@ static LIST_HEAD(blktrans_majors); static DEFINE_MUTEX(blktrans_ref_mutex); -void blktrans_dev_release(struct kref *kref) +static void blktrans_dev_release(struct kref *kref) { struct mtd_blktrans_dev *dev = container_of(kref, struct mtd_blktrans_dev, ref); @@ -67,7 +67,7 @@ unlock: return dev; } -void blktrans_dev_put(struct mtd_blktrans_dev *dev) +static void blktrans_dev_put(struct mtd_blktrans_dev *dev) { mutex_lock(&blktrans_ref_mutex); kref_put(&dev->ref, blktrans_dev_release); -- cgit v1.2.2 From cbc6c5e73dfa598b1fa5e67cef28096186e2a7cd Mon Sep 17 00:00:00 2001 From: Hong Xu Date: Tue, 18 Jan 2011 14:36:05 +0800 Subject: mtd: atmel_nand: Add DMA support to access Nandflash Some SAM9 chips have the ability to perform DMA between CPU and SMC controller. This patch adds DMA support for SAM9RL, SAM9G45, SSAM9G46,AM9M10, SAM9M11. Signed-off-by: Hong Xu Tested-by: Ryan Mallon Acked-by: Ryan Mallon Signed-off-by: David Woodhouse --- drivers/mtd/nand/atmel_nand.c | 166 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 157 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index ccce0f03b5dc..6fae04b3fc6d 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -48,6 +48,9 @@ #define no_ecc 0 #endif +static int use_dma = 1; +module_param(use_dma, int, 0); + static int on_flash_bbt = 0; module_param(on_flash_bbt, int, 0); @@ -89,11 +92,20 @@ struct atmel_nand_host { struct nand_chip nand_chip; struct mtd_info mtd; void __iomem *io_base; + dma_addr_t io_phys; struct atmel_nand_data *board; struct device *dev; void __iomem *ecc; + + struct completion comp; + struct dma_chan *dma_chan; }; +static int cpu_has_dma(void) +{ + return cpu_is_at91sam9rl() || cpu_is_at91sam9g45(); +} + /* * Enable NAND. */ @@ -150,7 +162,7 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) /* * Minimal-overhead PIO for data access. */ -static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) +static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) { struct nand_chip *nand_chip = mtd->priv; @@ -164,7 +176,7 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); } -static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) { struct nand_chip *nand_chip = mtd->priv; @@ -178,6 +190,121 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); } +static void dma_complete_func(void *completion) +{ + complete(completion); +} + +static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, + int is_read) +{ + struct dma_device *dma_dev; + enum dma_ctrl_flags flags; + dma_addr_t dma_src_addr, dma_dst_addr, phys_addr; + struct dma_async_tx_descriptor *tx = NULL; + dma_cookie_t cookie; + struct nand_chip *chip = mtd->priv; + struct atmel_nand_host *host = chip->priv; + void *p = buf; + int err = -EIO; + enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + if (buf >= high_memory) { + struct page *pg; + + if (((size_t)buf & PAGE_MASK) != + ((size_t)(buf + len - 1) & PAGE_MASK)) { + dev_warn(host->dev, "Buffer not fit in one page\n"); + goto err_buf; + } + + pg = vmalloc_to_page(buf); + if (pg == 0) { + dev_err(host->dev, "Failed to vmalloc_to_page\n"); + goto err_buf; + } + p = page_address(pg) + ((size_t)buf & ~PAGE_MASK); + } + + dma_dev = host->dma_chan->device; + + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP | + DMA_COMPL_SKIP_DEST_UNMAP; + + phys_addr = dma_map_single(dma_dev->dev, p, len, dir); + if (dma_mapping_error(dma_dev->dev, phys_addr)) { + dev_err(host->dev, "Failed to dma_map_single\n"); + goto err_buf; + } + + if (is_read) { + dma_src_addr = host->io_phys; + dma_dst_addr = phys_addr; + } else { + dma_src_addr = phys_addr; + dma_dst_addr = host->io_phys; + } + + tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr, + dma_src_addr, len, flags); + if (!tx) { + dev_err(host->dev, "Failed to prepare DMA memcpy\n"); + goto err_dma; + } + + init_completion(&host->comp); + tx->callback = dma_complete_func; + tx->callback_param = &host->comp; + + cookie = tx->tx_submit(tx); + if (dma_submit_error(cookie)) { + dev_err(host->dev, "Failed to do DMA tx_submit\n"); + goto err_dma; + } + + dma_async_issue_pending(host->dma_chan); + wait_for_completion(&host->comp); + + err = 0; + +err_dma: + dma_unmap_single(dma_dev->dev, phys_addr, len, dir); +err_buf: + if (err != 0) + dev_warn(host->dev, "Fall back to CPU I/O\n"); + return err; +} + +static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct atmel_nand_host *host = chip->priv; + + if (use_dma && len >= mtd->oobsize) + if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) + return; + + if (host->board->bus_width_16) + atmel_read_buf16(mtd, buf, len); + else + atmel_read_buf8(mtd, buf, len); +} + +static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct atmel_nand_host *host = chip->priv; + + if (use_dma && len >= mtd->oobsize) + if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) + return; + + if (host->board->bus_width_16) + atmel_write_buf16(mtd, buf, len); + else + atmel_write_buf8(mtd, buf, len); +} + /* * Calculate HW ECC * @@ -398,6 +525,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev) return -ENOMEM; } + host->io_phys = (dma_addr_t)mem->start; + host->io_base = ioremap(mem->start, mem->end - mem->start + 1); if (host->io_base == NULL) { printk(KERN_ERR "atmel_nand: ioremap failed\n"); @@ -448,14 +577,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->chip_delay = 20; /* 20us command delay time */ - if (host->board->bus_width_16) { /* 16-bit bus width */ + if (host->board->bus_width_16) /* 16-bit bus width */ nand_chip->options |= NAND_BUSWIDTH_16; - nand_chip->read_buf = atmel_read_buf16; - nand_chip->write_buf = atmel_write_buf16; - } else { - nand_chip->read_buf = atmel_read_buf; - nand_chip->write_buf = atmel_write_buf; - } + + nand_chip->read_buf = atmel_read_buf; + nand_chip->write_buf = atmel_write_buf; platform_set_drvdata(pdev, host); atmel_nand_enable(host); @@ -473,6 +599,22 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->options |= NAND_USE_FLASH_BBT; } + if (cpu_has_dma() && use_dma) { + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + host->dma_chan = dma_request_channel(mask, 0, NULL); + if (!host->dma_chan) { + dev_err(host->dev, "Failed to request DMA channel\n"); + use_dma = 0; + } + } + if (use_dma) + dev_info(host->dev, "Using DMA for NAND access.\n"); + else + dev_info(host->dev, "No DMA support for NAND access.\n"); + /* first scan to find the device and get the page size */ if (nand_scan_ident(mtd, 1, NULL)) { res = -ENXIO; @@ -555,6 +697,8 @@ err_scan_ident: err_no_card: atmel_nand_disable(host); platform_set_drvdata(pdev, NULL); + if (host->dma_chan) + dma_release_channel(host->dma_chan); if (host->ecc) iounmap(host->ecc); err_ecc_ioremap: @@ -578,6 +722,10 @@ static int __exit atmel_nand_remove(struct platform_device *pdev) if (host->ecc) iounmap(host->ecc); + + if (host->dma_chan) + dma_release_channel(host->dma_chan); + iounmap(host->io_base); kfree(host); -- cgit v1.2.2 From 771df61949cf2d6ae9ff07e209c80693cdbc9302 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Mon, 24 Jan 2011 17:45:42 +0100 Subject: mtd: adapt writebufsize calculation for concat If different chips with different writebufsize are concatenated, the writebufsize from the concat device has to be taken from the device with the largest writebuffer. This writebufsize is used later on in the UBI layer for the min I/O size. Signed-off-by: Holger Brunck Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtdconcat.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 5f5777bd3f75..5060e608ea5d 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -750,6 +750,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c struct mtd_concat *concat; uint32_t max_erasesize, curr_erasesize; int num_erase_region; + int max_writebufsize = 0; printk(KERN_NOTICE "Concatenating MTD devices:\n"); for (i = 0; i < num_devs; i++) @@ -776,7 +777,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.size = subdev[0]->size; concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; - concat->mtd.writebufsize = subdev[0]->writebufsize; + + for (i = 0; i < num_devs; i++) + if (max_writebufsize < subdev[i]->writebufsize) + max_writebufsize = subdev[i]->writebufsize; + concat->mtd.writebufsize = max_writebufsize; + concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; -- cgit v1.2.2 From 37a23c20181aaddb8019f0a57bcda334412b89f8 Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Tue, 25 Jan 2011 11:20:26 +0100 Subject: mtd: m25p80: add support for the EON EN25F32 chip Signed-off-by: Gabor Juhos Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index e4eba6cc1b2e..8d83a8b31670 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -655,7 +655,8 @@ static const struct spi_device_id m25p_ids[] = { { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) }, { "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, - /* EON -- en25pxx */ + /* EON -- en25xxx */ + { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, -- cgit v1.2.2 From 07be303d22ac7e067b8a7172a4043ebe32b74b33 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 2 Feb 2011 08:53:55 +0200 Subject: mtd: mtdram: initialize writebufsize field Set the 'mtd->writebufsize' field to 64 to mimic modern CFI flashes. Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/mtdram.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index 26a6e809013d..1483e18971ce 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -121,6 +121,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, mtd->flags = MTD_CAP_RAM; mtd->size = size; mtd->writesize = 1; + mtd->writebufsize = 64; /* Mimic CFI NOR flashes */ mtd->erasesize = MTDRAM_ERASE_SIZE; mtd->priv = mapped_address; -- cgit v1.2.2 From f17f12ce9dd6ec0a8e1f415ecdbaebfce0207464 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 30 Jan 2011 10:31:48 +0100 Subject: mtd: phram: fix memory leak Commit 4f678a58 (mtd: fix memory leaks in phram_setup) missed two cases where the memory allocated for name would be leaked. This commit frees the memory when register_device() fails and on unregister_devices(). Signed-off-by: Mathias Krause Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/devices/phram.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 52393282eaf1..8d28fa02a5a2 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -117,6 +117,7 @@ static void unregister_devices(void) list_for_each_entry_safe(this, safe, &phram_list, list) { del_mtd_device(&this->mtd); iounmap(this->mtd.priv); + kfree(this->mtd.name); kfree(this); } } @@ -275,6 +276,8 @@ static int phram_setup(const char *val, struct kernel_param *kp) ret = register_device(name, start, len); if (!ret) pr_info("%s device: %#x at %#x\n", name, len, start); + else + kfree(name); return ret; } -- cgit v1.2.2 From 3ee7451a023dd197fcfc1ba46dcce6d8ec5e1b78 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 2 Feb 2011 18:13:36 +0100 Subject: mtd: ts5500_flash: avoid calling map_destroy on NULL map_destroy dereferences its argument. The call is furthermore only reachable when this argument is NULL. Thus the call is dropped. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression *x; @@ *if (x == NULL) { ... * map_destroy(x); ... return ...; } // Signed-off-by: Julia Lawall Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/ts5500_flash.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index e2147bf11c88..e02dfa9d4ddd 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c @@ -94,7 +94,6 @@ static int __init init_ts5500_map(void) return 0; err1: - map_destroy(mymtd); iounmap(ts5500_map.virt); err2: return rc; -- cgit v1.2.2 From 7b7e905ec2ec511e06279181ca95a892db21e292 Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Thu, 3 Feb 2011 13:45:56 +0200 Subject: mtd: tests: print correct values The ebcnt and pgcnt variable initialization is moved before printk which uses them. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/tests/mtd_subpagetest.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 11204e8aab5f..334eae53a3db 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -394,6 +394,11 @@ static int __init mtd_subpagetest_init(void) } subpgsize = mtd->writesize >> mtd->subpage_sft; + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " "page size %u, subpage size %u, count of eraseblocks %u, " "pages per eraseblock %u, OOB size %u\n", @@ -413,11 +418,6 @@ static int __init mtd_subpagetest_init(void) goto out; } - tmp = mtd->size; - do_div(tmp, mtd->erasesize); - ebcnt = tmp; - pgcnt = mtd->erasesize / mtd->writesize; - err = scan_for_bad_eraseblocks(); if (err) goto out; -- cgit v1.2.2 From 7912a5e7f37512d8d105785046137435b70347ce Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 7 Feb 2011 23:48:25 +0300 Subject: mtd: nand: fix pointer NULL pointer dereferencing In 'verify_bbt_descr()', first check the "bd" pointer, then dereference it. Comments amended by Artem. Signed-off-by: Stanislav Fomichev Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_bbt.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 6ebd869993aa..a1e8b30078d9 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -1101,12 +1101,16 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; - u32 pattern_len = bd->len; - u32 bits = bd->options & NAND_BBT_NRBITS_MSK; + u32 pattern_len; + u32 bits; u32 table_size; if (!bd) return; + + pattern_len = bd->len; + bits = bd->options & NAND_BBT_NRBITS_MSK; + BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && !(this->options & NAND_USE_FLASH_BBT)); BUG_ON(!bits); -- cgit v1.2.2 From b085058fe556328443f982d892c9657b3aff9d4a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Feb 2011 12:02:38 +0200 Subject: mtd: OneNAND: return read error for 4KiB page read When reading using the 4KiB page read function, I/O errors could be ignored if more than 1 page was read at a time. Signed-off-by: Adrian Hunter Acked-by: Kyungmin Park Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index bac41caa8df7..38e6d76bcc0e 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1132,6 +1132,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, onenand_update_bufferram(mtd, from, !ret); if (ret == -EBADMSG) ret = 0; + if (ret) + break; } this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen); -- cgit v1.2.2 From e6da85685b2dec1e69e58366c22d1f883d6da575 Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Tue, 8 Feb 2011 12:02:42 +0200 Subject: mtd: onenand_base: onenand_verify bugfix for writepage non-aligned address In onenand_verify function the address can be writepage non-aligned. When a page is read for comparing the right offset should be used for "this->verify_buf" to get the right matching with compared "buf" buffer. Signed-off-by: Roman Tereshonkov Signed-off-by: Adrian Hunter Acked-by: Kyungmin Park Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 38e6d76bcc0e..4205b9423b89 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1648,11 +1648,10 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, int ret = 0; int thislen, column; + column = addr & (this->writesize - 1); + while (len != 0) { - thislen = min_t(int, this->writesize, len); - column = addr & (this->writesize - 1); - if (column + thislen > this->writesize) - thislen = this->writesize - column; + thislen = min_t(int, this->writesize - column, len); this->command(mtd, ONENAND_CMD_READ, addr, this->writesize); @@ -1666,12 +1665,13 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize); - if (memcmp(buf, this->verify_buf, thislen)) + if (memcmp(buf, this->verify_buf + column, thislen)) return -EBADMSG; len -= thislen; buf += thislen; addr += thislen; + column = 0; } return 0; -- cgit v1.2.2 From fc7fe7691c6bbd5f8f51a87e759770975c648410 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Feb 2011 12:02:39 +0200 Subject: mtd: tests: add count parameter to mtd_speedtest By default mtd_speedtest uses all the eraseblocks of the MTD partition being tested. For large partitions a smaller number is sufficient and makes running the test quicker. For that reason, add a parameter 'count' to specify the maximum number of eraseblocks to use for testing. Signed-off-by: Adrian Hunter Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/tests/mtd_speedtest.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 161feeb7b8b9..9bd986ef3b53 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -16,7 +16,7 @@ * * Test read and write speed of a MTD device. * - * Author: Adrian Hunter + * Author: Adrian Hunter */ #include @@ -33,6 +33,11 @@ static int dev; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); +static int count; +module_param(count, int, S_IRUGO); +MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use " + "(0 means use all)"); + static struct mtd_info *mtd; static unsigned char *iobuf; static unsigned char *bbt; @@ -326,7 +331,10 @@ static int __init mtd_speedtest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); - printk(PRINT_PREF "MTD device: %d\n", dev); + if (count) + printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); + else + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); if (IS_ERR(mtd)) { @@ -353,6 +361,9 @@ static int __init mtd_speedtest_init(void) (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); + if (count > 0 && count < ebcnt) + ebcnt = count; + err = -ENOMEM; iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); if (!iobuf) { -- cgit v1.2.2 From 4085bcc682e1276ab4ac2da9866daadf944d7167 Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Tue, 8 Feb 2011 12:02:40 +0200 Subject: mtd: tests: add multiblock erase test to the mtd_speedtest New multiblock erase speed test is added to mtd_speedtest. It consists of 2-, 4-, 8-, 16-, 32- and 64-blocks at once multiblock erase tests. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/tests/mtd_speedtest.c | 59 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 9bd986ef3b53..3ce6fce75e07 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -94,6 +94,33 @@ static int erase_eraseblock(int ebnum) return 0; } +static int multiblock_erase(int ebnum, int blocks) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize * blocks; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n", + err, ebnum, blocks); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d," + "blocks %d\n", ebnum, blocks); + return -EIO; + } + + return 0; +} + static int erase_whole_device(void) { int err; @@ -292,7 +319,10 @@ static long calc_speed(void) ms = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000; k = goodebcnt * mtd->erasesize / 1024; - speed = (k * 1000) / ms; + if (ms) + speed = (k * 1000) / ms; + else + speed = 0; return speed; } @@ -325,7 +355,7 @@ out: static int __init mtd_speedtest_init(void) { - int err, i; + int err, i, blocks, j, k; long speed; uint64_t tmp; @@ -495,6 +525,31 @@ static int __init mtd_speedtest_init(void) speed = calc_speed(); printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); + /* Multi-block erase all eraseblocks */ + for (k = 1; k < 7; k++) { + blocks = 1 << k; + printk(PRINT_PREF "Testing %dx multi-block erase speed\n", + blocks); + start_timing(); + for (i = 0; i < ebcnt; ) { + for (j = 0; j < blocks && (i + j) < ebcnt; j++) + if (bbt[i + j]) + break; + if (j < 1) { + i++; + continue; + } + err = multiblock_erase(i, j); + if (err) + goto out; + cond_resched(); + i += j; + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n", + blocks, speed); + } printk(PRINT_PREF "finished\n"); out: kfree(iobuf); -- cgit v1.2.2 From d8f90b2c9d521500bcd4a1ecdcdb283bfdd2186f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 9 Feb 2011 17:00:33 +0900 Subject: mtd: m25p80: add support for M25PX64 Signed-off-by: Yoshihiro Shimoda Signed-off-by: David Woodhouse --- drivers/mtd/devices/m25p80.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 8d83a8b31670..3fb981d4bb51 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -729,6 +729,8 @@ static const struct spi_device_id m25p_ids[] = { { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, + { "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) }, + /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, -- cgit v1.2.2 From 13ce77f46c79a3839e4c2ff9722c9416c165f498 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 10 Feb 2011 16:01:46 +0100 Subject: mtd: cfi: fix writebufsize initialization When initializing mtd->writebufsize, we must take into account possible flash chip interleaving. Wrong writebufsize initialization caused UBIFS recovery issues resulting in unmountable UBIFS file system on NOR flash partitions. Signed-off-by: Anatolij Gustschin Acked-by: Guillaume LECERF Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0001.c | 2 +- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- drivers/mtd/chips/cfi_cmdset_0020.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 4aaa88f8ab5f..092aef11120c 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -455,7 +455,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; mtd->writesize = 1; - mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; + mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index f072fcfde04e..7e9c4e9c274a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -440,7 +440,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; mtd->writesize = 1; - mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; + mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", __func__, mtd->writebufsize); diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index c04b7658abe9..ed56ad3884fb 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -238,7 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->resume = cfi_staa_resume; mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE; mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ - mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize; + mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; map->fldrv = &cfi_staa_chipdrv; __module_get(THIS_MODULE); mtd->name = map->name; -- cgit v1.2.2 From c7519dbf6f4b4408229d279d799c938ffdd06f21 Mon Sep 17 00:00:00 2001 From: Jarkko Lavinen Date: Mon, 14 Feb 2011 16:16:09 +0200 Subject: mtd_blkdevs: Add background processing support Add a new background method into mtd_blktrans_ops, add background support into mtd_blktrans_thread(), and add mtd_blktrans_cease_background(). If the mtd blktrans dev has the background support, the thread will call background function when the request queue becomes empty. The background operation may run as long as needs to until mtd_blktrans_cease_background() tells to stop. Signed-off-by: Jarkko Lavinen Tested-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtd_blkdevs.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 344ac1037ee7..e0b5f6442171 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -119,11 +119,22 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, } } +int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev) +{ + if (kthread_should_stop()) + return 1; + + return !elv_queue_empty(dev->rq); +} +EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background); + static int mtd_blktrans_thread(void *arg) { struct mtd_blktrans_dev *dev = arg; + struct mtd_blktrans_ops *tr = dev->tr; struct request_queue *rq = dev->rq; struct request *req = NULL; + int background_done = 0; spin_lock_irq(rq->queue_lock); @@ -131,6 +142,19 @@ static int mtd_blktrans_thread(void *arg) int res; if (!req && !(req = blk_fetch_request(rq))) { + if (tr->background && !background_done) { + spin_unlock_irq(rq->queue_lock); + mutex_lock(&dev->lock); + tr->background(dev); + mutex_unlock(&dev->lock); + spin_lock_irq(rq->queue_lock); + /* + * Do background processing just once per idle + * period. + */ + background_done = 1; + continue; + } set_current_state(TASK_INTERRUPTIBLE); if (kthread_should_stop()) @@ -152,6 +176,8 @@ static int mtd_blktrans_thread(void *arg) if (!__blk_end_request_cur(req, res)) req = NULL; + + background_done = 0; } if (req) -- cgit v1.2.2 From 115ee88c15b55859a8b59c5dccb3882bbd47e542 Mon Sep 17 00:00:00 2001 From: Jarkko Lavinen Date: Mon, 14 Feb 2011 16:16:10 +0200 Subject: mtd_blkdevs: Set the maximum discards size Set max_discard_sectors to UINT_MAX. Signed-off-by: Jarkko Lavinen Tested-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/mtd_blkdevs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index e0b5f6442171..650511304030 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -405,9 +405,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) new->rq->queuedata = new; blk_queue_logical_block_size(new->rq, tr->blksize); - if (tr->discard) - queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, - new->rq); + if (tr->discard) { + queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq); + new->rq->limits.max_discard_sectors = UINT_MAX; + } gd->queue = new->rq; -- cgit v1.2.2 From a321590246202f2598aca2f4ef63b992e8fc97ef Mon Sep 17 00:00:00 2001 From: Jarkko Lavinen Date: Mon, 14 Feb 2011 16:16:11 +0200 Subject: mtd: Add mtdswap block driver Add a driver for allowing an mtd device to be used as a block device for swapping. The block device is volatile, and the mapping of swapped pages is not stored on flash. Signed-off-by: Jarkko Lavinen Tested-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/Kconfig | 18 + drivers/mtd/Makefile | 1 + drivers/mtd/mtdswap.c | 1593 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1612 insertions(+) create mode 100644 drivers/mtd/mtdswap.c (limited to 'drivers') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 23088b3372d0..5fe01d556657 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -325,6 +325,24 @@ config MTD_OOPS To use, add console=ttyMTDx to the kernel command line, where x is the MTD device number to use. +config MTD_SWAP + tristate "Swap on MTD device support" + depends on MTD && SWAP + select MTD_BLKDEVS + help + Provides volatile block device driver on top of mtd partition + suitable for swapping. The mapping of written blocks is not saved. + The driver provides wear leveling by storing erase counter into the + OOB. + +config MTD_SWAP_STRICT + bool "Strict erase error handling" + depends on MTD_SWAP + help + Enables strict tolerance on failed erasures, marking erase blocks bad + right after the first failed operation. With non-strict mode the + erase operation is retried. + source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index eff3dd53cc05..d578095fb255 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_RFD_FTL) += rfd_ftl.o obj-$(CONFIG_SSFDC) += ssfdc.o obj-$(CONFIG_SM_FTL) += sm_ftl.o obj-$(CONFIG_MTD_OOPS) += mtdoops.o +obj-$(CONFIG_MTD_SWAP) += mtdswap.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c new file mode 100644 index 000000000000..57e6cc30bc42 --- /dev/null +++ b/drivers/mtd/mtdswap.c @@ -0,0 +1,1593 @@ +/* + * Swap block device support for MTDs + * Turns an MTD device into a swap device with block wear leveling + * + * Copyright © 2007,2011 Nokia Corporation. All rights reserved. + * + * Authors: Jarkko Lavinen + * + * Based on Richard Purdie's earlier implementation in 2007. Background + * support and lock-less operation written by Adrian Hunter. + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MTDSWAP_PREFIX "mtdswap" + +/* + * The number of free eraseblocks when GC should stop + */ +#define CLEAN_BLOCK_THRESHOLD 20 + +/* + * Number of free eraseblocks below which GC can also collect low frag + * blocks. + */ +#define LOW_FRAG_GC_TRESHOLD 5 + +/* + * Wear level cost amortization. We want to do wear leveling on the background + * without disturbing gc too much. This is made by defining max GC frequency. + * Frequency value 6 means 1/6 of the GC passes will pick an erase block based + * on the biggest wear difference rather than the biggest dirtiness. + * + * The lower freq2 should be chosen so that it makes sure the maximum erase + * difference will decrease even if a malicious application is deliberately + * trying to make erase differences large. + */ +#define MAX_ERASE_DIFF 4000 +#define COLLECT_NONDIRTY_BASE MAX_ERASE_DIFF +#define COLLECT_NONDIRTY_FREQ1 6 +#define COLLECT_NONDIRTY_FREQ2 4 + +#define PAGE_UNDEF UINT_MAX +#define BLOCK_UNDEF UINT_MAX +#define BLOCK_ERROR (UINT_MAX - 1) +#define BLOCK_MAX (UINT_MAX - 2) + +#define EBLOCK_BAD (1 << 0) +#define EBLOCK_NOMAGIC (1 << 1) +#define EBLOCK_BITFLIP (1 << 2) +#define EBLOCK_FAILED (1 << 3) +#define EBLOCK_READERR (1 << 4) +#define EBLOCK_IDX_SHIFT 5 + +struct swap_eb { + struct rb_node rb; + struct rb_root *root; + + unsigned int flags; + unsigned int active_count; + unsigned int erase_count; + unsigned int pad; /* speeds up pointer decremtnt */ +}; + +#define MTDSWAP_ECNT_MIN(rbroot) (rb_entry(rb_first(rbroot), struct swap_eb, \ + rb)->erase_count) +#define MTDSWAP_ECNT_MAX(rbroot) (rb_entry(rb_last(rbroot), struct swap_eb, \ + rb)->erase_count) + +struct mtdswap_tree { + struct rb_root root; + unsigned int count; +}; + +enum { + MTDSWAP_CLEAN, + MTDSWAP_USED, + MTDSWAP_LOWFRAG, + MTDSWAP_HIFRAG, + MTDSWAP_DIRTY, + MTDSWAP_BITFLIP, + MTDSWAP_FAILING, + MTDSWAP_TREE_CNT, +}; + +struct mtdswap_dev { + struct mtd_blktrans_dev *mbd_dev; + struct mtd_info *mtd; + struct device *dev; + + unsigned int *page_data; + unsigned int *revmap; + + unsigned int eblks; + unsigned int spare_eblks; + unsigned int pages_per_eblk; + unsigned int max_erase_count; + struct swap_eb *eb_data; + + struct mtdswap_tree trees[MTDSWAP_TREE_CNT]; + + unsigned long long sect_read_count; + unsigned long long sect_write_count; + unsigned long long mtd_write_count; + unsigned long long mtd_read_count; + unsigned long long discard_count; + unsigned long long discard_page_count; + + unsigned int curr_write_pos; + struct swap_eb *curr_write; + + char *page_buf; + char *oob_buf; + + struct dentry *debugfs_root; +}; + +struct mtdswap_oobdata { + __le16 magic; + __le32 count; +} __attribute__((packed)); + +#define MTDSWAP_MAGIC_CLEAN 0x2095 +#define MTDSWAP_MAGIC_DIRTY (MTDSWAP_MAGIC_CLEAN + 1) +#define MTDSWAP_TYPE_CLEAN 0 +#define MTDSWAP_TYPE_DIRTY 1 +#define MTDSWAP_OOBSIZE sizeof(struct mtdswap_oobdata) + +#define MTDSWAP_ERASE_RETRIES 3 /* Before marking erase block bad */ +#define MTDSWAP_IO_RETRIES 3 + +#ifdef CONFIG_MTD_SWAP_STRICT +#define MTDSWAP_STRICT 1 +#else +#define MTDSWAP_STRICT 0 +#endif + +enum { + MTDSWAP_SCANNED_CLEAN, + MTDSWAP_SCANNED_DIRTY, + MTDSWAP_SCANNED_BITFLIP, + MTDSWAP_SCANNED_BAD, +}; + +/* + * In the worst case mtdswap_writesect() has allocated the last clean + * page from the current block and is then pre-empted by the GC + * thread. The thread can consume a full erase block when moving a + * block. + */ +#define MIN_SPARE_EBLOCKS 2 +#define MIN_ERASE_BLOCKS (MIN_SPARE_EBLOCKS + 1) + +#define TREE_ROOT(d, name) (&d->trees[MTDSWAP_ ## name].root) +#define TREE_EMPTY(d, name) (TREE_ROOT(d, name)->rb_node == NULL) +#define TREE_NONEMPTY(d, name) (!TREE_EMPTY(d, name)) +#define TREE_COUNT(d, name) (d->trees[MTDSWAP_ ## name].count) + +#define MTDSWAP_MBD_TO_MTDSWAP(dev) ((struct mtdswap_dev *)dev->priv) + +static char partitions[128] = ""; +module_param_string(partitions, partitions, sizeof(partitions), 0444); +MODULE_PARM_DESC(partitions, "MTD partition numbers to use as swap " + "partitions=\"1,3,5\""); + +static unsigned int spare_eblocks = 10; +module_param(spare_eblocks, uint, 0444); +MODULE_PARM_DESC(spare_eblocks, "Percentage of spare erase blocks for " + "garbage collection (default 10%)"); + +static bool header; /* false */ +module_param(header, bool, 0444); +MODULE_PARM_DESC(header, + "Include builtin swap header (default 0, without header)"); + +static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background); + +static loff_t mtdswap_eb_offset(struct mtdswap_dev *d, struct swap_eb *eb) +{ + return (loff_t)(eb - d->eb_data) * d->mtd->erasesize; +} + +static void mtdswap_eb_detach(struct mtdswap_dev *d, struct swap_eb *eb) +{ + unsigned int oldidx; + struct mtdswap_tree *tp; + + if (eb->root) { + tp = container_of(eb->root, struct mtdswap_tree, root); + oldidx = tp - &d->trees[0]; + + d->trees[oldidx].count--; + rb_erase(&eb->rb, eb->root); + } +} + +static void __mtdswap_rb_add(struct rb_root *root, struct swap_eb *eb) +{ + struct rb_node **p, *parent = NULL; + struct swap_eb *cur; + + p = &root->rb_node; + while (*p) { + parent = *p; + cur = rb_entry(parent, struct swap_eb, rb); + if (eb->erase_count > cur->erase_count) + p = &(*p)->rb_right; + else + p = &(*p)->rb_left; + } + + rb_link_node(&eb->rb, parent, p); + rb_insert_color(&eb->rb, root); +} + +static void mtdswap_rb_add(struct mtdswap_dev *d, struct swap_eb *eb, int idx) +{ + struct rb_root *root; + + if (eb->root == &d->trees[idx].root) + return; + + mtdswap_eb_detach(d, eb); + root = &d->trees[idx].root; + __mtdswap_rb_add(root, eb); + eb->root = root; + d->trees[idx].count++; +} + +static struct rb_node *mtdswap_rb_index(struct rb_root *root, unsigned int idx) +{ + struct rb_node *p; + unsigned int i; + + p = rb_first(root); + i = 0; + while (i < idx && p) { + p = rb_next(p); + i++; + } + + return p; +} + +static int mtdswap_handle_badblock(struct mtdswap_dev *d, struct swap_eb *eb) +{ + int ret; + loff_t offset; + + d->spare_eblks--; + eb->flags |= EBLOCK_BAD; + mtdswap_eb_detach(d, eb); + eb->root = NULL; + + /* badblocks not supported */ + if (!d->mtd->block_markbad) + return 1; + + offset = mtdswap_eb_offset(d, eb); + dev_warn(d->dev, "Marking bad block at %08llx\n", offset); + ret = d->mtd->block_markbad(d->mtd, offset); + + if (ret) { + dev_warn(d->dev, "Mark block bad failed for block at %08llx " + "error %d\n", offset, ret); + return ret; + } + + return 1; + +} + +static int mtdswap_handle_write_error(struct mtdswap_dev *d, struct swap_eb *eb) +{ + unsigned int marked = eb->flags & EBLOCK_FAILED; + struct swap_eb *curr_write = d->curr_write; + + eb->flags |= EBLOCK_FAILED; + if (curr_write == eb) { + d->curr_write = NULL; + + if (!marked && d->curr_write_pos != 0) { + mtdswap_rb_add(d, eb, MTDSWAP_FAILING); + return 0; + } + } + + return mtdswap_handle_badblock(d, eb); +} + +static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from, + struct mtd_oob_ops *ops) +{ + int ret = d->mtd->read_oob(d->mtd, from, ops); + + if (ret == -EUCLEAN) + return ret; + + if (ret) { + dev_warn(d->dev, "Read OOB failed %d for block at %08llx\n", + ret, from); + return ret; + } + + if (ops->oobretlen < ops->ooblen) { + dev_warn(d->dev, "Read OOB return short read (%zd bytes not " + "%d) for block at %08llx\n", + ops->oobretlen, ops->ooblen, from); + return -EIO; + } + + return 0; +} + +static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) +{ + struct mtdswap_oobdata *data, *data2; + int ret; + loff_t offset; + struct mtd_oob_ops ops; + + offset = mtdswap_eb_offset(d, eb); + + /* Check first if the block is bad. */ + if (d->mtd->block_isbad && d->mtd->block_isbad(d->mtd, offset)) + return MTDSWAP_SCANNED_BAD; + + ops.ooblen = 2 * d->mtd->ecclayout->oobavail; + ops.oobbuf = d->oob_buf; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OOB_AUTO; + + ret = mtdswap_read_oob(d, offset, &ops); + + if (ret && ret != -EUCLEAN) + return ret; + + data = (struct mtdswap_oobdata *)d->oob_buf; + data2 = (struct mtdswap_oobdata *) + (d->oob_buf + d->mtd->ecclayout->oobavail); + + if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) { + eb->erase_count = le32_to_cpu(data->count); + if (ret == -EUCLEAN) + ret = MTDSWAP_SCANNED_BITFLIP; + else { + if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY) + ret = MTDSWAP_SCANNED_DIRTY; + else + ret = MTDSWAP_SCANNED_CLEAN; + } + } else { + eb->flags |= EBLOCK_NOMAGIC; + ret = MTDSWAP_SCANNED_DIRTY; + } + + return ret; +} + +static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, + u16 marker) +{ + struct mtdswap_oobdata n; + int ret; + loff_t offset; + struct mtd_oob_ops ops; + + ops.ooboffs = 0; + ops.oobbuf = (uint8_t *)&n; + ops.mode = MTD_OOB_AUTO; + ops.datbuf = NULL; + + if (marker == MTDSWAP_TYPE_CLEAN) { + n.magic = cpu_to_le16(MTDSWAP_MAGIC_CLEAN); + n.count = cpu_to_le32(eb->erase_count); + ops.ooblen = MTDSWAP_OOBSIZE; + offset = mtdswap_eb_offset(d, eb); + } else { + n.magic = cpu_to_le16(MTDSWAP_MAGIC_DIRTY); + ops.ooblen = sizeof(n.magic); + offset = mtdswap_eb_offset(d, eb) + d->mtd->writesize; + } + + ret = d->mtd->write_oob(d->mtd, offset , &ops); + + if (ret) { + dev_warn(d->dev, "Write OOB failed for block at %08llx " + "error %d\n", offset, ret); + if (ret == -EIO || ret == -EBADMSG) + mtdswap_handle_write_error(d, eb); + return ret; + } + + if (ops.oobretlen != ops.ooblen) { + dev_warn(d->dev, "Short OOB write for block at %08llx: " + "%zd not %d\n", + offset, ops.oobretlen, ops.ooblen); + return ret; + } + + return 0; +} + +/* + * Are there any erase blocks without MAGIC_CLEAN header, presumably + * because power was cut off after erase but before header write? We + * need to guestimate the erase count. + */ +static void mtdswap_check_counts(struct mtdswap_dev *d) +{ + struct rb_root hist_root = RB_ROOT; + struct rb_node *medrb; + struct swap_eb *eb; + unsigned int i, cnt, median; + + cnt = 0; + for (i = 0; i < d->eblks; i++) { + eb = d->eb_data + i; + + if (eb->flags & (EBLOCK_NOMAGIC | EBLOCK_BAD | EBLOCK_READERR)) + continue; + + __mtdswap_rb_add(&hist_root, eb); + cnt++; + } + + if (cnt == 0) + return; + + medrb = mtdswap_rb_index(&hist_root, cnt / 2); + median = rb_entry(medrb, struct swap_eb, rb)->erase_count; + + d->max_erase_count = MTDSWAP_ECNT_MAX(&hist_root); + + for (i = 0; i < d->eblks; i++) { + eb = d->eb_data + i; + + if (eb->flags & (EBLOCK_NOMAGIC | EBLOCK_READERR)) + eb->erase_count = median; + + if (eb->flags & (EBLOCK_NOMAGIC | EBLOCK_BAD | EBLOCK_READERR)) + continue; + + rb_erase(&eb->rb, &hist_root); + } +} + +static void mtdswap_scan_eblks(struct mtdswap_dev *d) +{ + int status; + unsigned int i, idx; + struct swap_eb *eb; + + for (i = 0; i < d->eblks; i++) { + eb = d->eb_data + i; + + status = mtdswap_read_markers(d, eb); + if (status < 0) + eb->flags |= EBLOCK_READERR; + else if (status == MTDSWAP_SCANNED_BAD) { + eb->flags |= EBLOCK_BAD; + continue; + } + + switch (status) { + case MTDSWAP_SCANNED_CLEAN: + idx = MTDSWAP_CLEAN; + break; + case MTDSWAP_SCANNED_DIRTY: + case MTDSWAP_SCANNED_BITFLIP: + idx = MTDSWAP_DIRTY; + break; + default: + idx = MTDSWAP_FAILING; + } + + eb->flags |= (idx << EBLOCK_IDX_SHIFT); + } + + mtdswap_check_counts(d); + + for (i = 0; i < d->eblks; i++) { + eb = d->eb_data + i; + + if (eb->flags & EBLOCK_BAD) + continue; + + idx = eb->flags >> EBLOCK_IDX_SHIFT; + mtdswap_rb_add(d, eb, idx); + } +} + +/* + * Place eblk into a tree corresponding to its number of active blocks + * it contains. + */ +static void mtdswap_store_eb(struct mtdswap_dev *d, struct swap_eb *eb) +{ + unsigned int weight = eb->active_count; + unsigned int maxweight = d->pages_per_eblk; + + if (eb == d->curr_write) + return; + + if (eb->flags & EBLOCK_BITFLIP) + mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP); + else if (eb->flags & (EBLOCK_READERR | EBLOCK_FAILED)) + mtdswap_rb_add(d, eb, MTDSWAP_FAILING); + if (weight == maxweight) + mtdswap_rb_add(d, eb, MTDSWAP_USED); + else if (weight == 0) + mtdswap_rb_add(d, eb, MTDSWAP_DIRTY); + else if (weight > (maxweight/2)) + mtdswap_rb_add(d, eb, MTDSWAP_LOWFRAG); + else + mtdswap_rb_add(d, eb, MTDSWAP_HIFRAG); +} + + +static void mtdswap_erase_callback(struct erase_info *done) +{ + wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; + wake_up(wait_q); +} + +static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb) +{ + struct mtd_info *mtd = d->mtd; + struct erase_info erase; + wait_queue_head_t wq; + unsigned int retries = 0; + int ret; + + eb->erase_count++; + if (eb->erase_count > d->max_erase_count) + d->max_erase_count = eb->erase_count; + +retry: + init_waitqueue_head(&wq); + memset(&erase, 0, sizeof(struct erase_info)); + + erase.mtd = mtd; + erase.callback = mtdswap_erase_callback; + erase.addr = mtdswap_eb_offset(d, eb); + erase.len = mtd->erasesize; + erase.priv = (u_long)&wq; + + ret = mtd->erase(mtd, &erase); + if (ret) { + if (retries++ < MTDSWAP_ERASE_RETRIES && !MTDSWAP_STRICT) { + dev_warn(d->dev, + "erase of erase block %#llx on %s failed", + erase.addr, mtd->name); + yield(); + goto retry; + } + + dev_err(d->dev, "Cannot erase erase block %#llx on %s\n", + erase.addr, mtd->name); + + mtdswap_handle_badblock(d, eb); + return -EIO; + } + + ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE || + erase.state == MTD_ERASE_FAILED); + if (ret) { + dev_err(d->dev, "Interrupted erase block %#llx erassure on %s", + erase.addr, mtd->name); + return -EINTR; + } + + if (erase.state == MTD_ERASE_FAILED) { + if (retries++ < MTDSWAP_ERASE_RETRIES) { + dev_warn(d->dev, + "erase of erase block %#llx on %s failed", + erase.addr, mtd->name); + yield(); + goto retry; + } + + mtdswap_handle_badblock(d, eb); + return -EIO; + } + + return 0; +} + +static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page, + unsigned int *block) +{ + int ret; + struct swap_eb *old_eb = d->curr_write; + struct rb_root *clean_root; + struct swap_eb *eb; + + if (old_eb == NULL || d->curr_write_pos >= d->pages_per_eblk) { + do { + if (TREE_EMPTY(d, CLEAN)) + return -ENOSPC; + + clean_root = TREE_ROOT(d, CLEAN); + eb = rb_entry(rb_first(clean_root), struct swap_eb, rb); + rb_erase(&eb->rb, clean_root); + eb->root = NULL; + TREE_COUNT(d, CLEAN)--; + + ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY); + } while (ret == -EIO || ret == -EBADMSG); + + if (ret) + return ret; + + d->curr_write_pos = 0; + d->curr_write = eb; + if (old_eb) + mtdswap_store_eb(d, old_eb); + } + + *block = (d->curr_write - d->eb_data) * d->pages_per_eblk + + d->curr_write_pos; + + d->curr_write->active_count++; + d->revmap[*block] = page; + d->curr_write_pos++; + + return 0; +} + +static unsigned int mtdswap_free_page_cnt(struct mtdswap_dev *d) +{ + return TREE_COUNT(d, CLEAN) * d->pages_per_eblk + + d->pages_per_eblk - d->curr_write_pos; +} + +static unsigned int mtdswap_enough_free_pages(struct mtdswap_dev *d) +{ + return mtdswap_free_page_cnt(d) > d->pages_per_eblk; +} + +static int mtdswap_write_block(struct mtdswap_dev *d, char *buf, + unsigned int page, unsigned int *bp, int gc_context) +{ + struct mtd_info *mtd = d->mtd; + struct swap_eb *eb; + size_t retlen; + loff_t writepos; + int ret; + +retry: + if (!gc_context) + while (!mtdswap_enough_free_pages(d)) + if (mtdswap_gc(d, 0) > 0) + return -ENOSPC; + + ret = mtdswap_map_free_block(d, page, bp); + eb = d->eb_data + (*bp / d->pages_per_eblk); + + if (ret == -EIO || ret == -EBADMSG) { + d->curr_write = NULL; + eb->active_count--; + d->revmap[*bp] = PAGE_UNDEF; + goto retry; + } + + if (ret < 0) + return ret; + + writepos = (loff_t)*bp << PAGE_SHIFT; + ret = mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf); + if (ret == -EIO || ret == -EBADMSG) { + d->curr_write_pos--; + eb->active_count--; + d->revmap[*bp] = PAGE_UNDEF; + mtdswap_handle_write_error(d, eb); + goto retry; + } + + if (ret < 0) { + dev_err(d->dev, "Write to MTD device failed: %d (%d written)", + ret, retlen); + goto err; + } + + if (retlen != PAGE_SIZE) { + dev_err(d->dev, "Short write to MTD device: %d written", + retlen); + ret = -EIO; + goto err; + } + + return ret; + +err: + d->curr_write_pos--; + eb->active_count--; + d->revmap[*bp] = PAGE_UNDEF; + + return ret; +} + +static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock, + unsigned int *newblock) +{ + struct mtd_info *mtd = d->mtd; + struct swap_eb *eb, *oldeb; + int ret; + size_t retlen; + unsigned int page, retries; + loff_t readpos; + + page = d->revmap[oldblock]; + readpos = (loff_t) oldblock << PAGE_SHIFT; + retries = 0; + +retry: + ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf); + + if (ret < 0 && ret != -EUCLEAN) { + oldeb = d->eb_data + oldblock / d->pages_per_eblk; + oldeb->flags |= EBLOCK_READERR; + + dev_err(d->dev, "Read Error: %d (block %u)\n", ret, + oldblock); + retries++; + if (retries < MTDSWAP_IO_RETRIES) + goto retry; + + goto read_error; + } + + if (retlen != PAGE_SIZE) { + dev_err(d->dev, "Short read: %d (block %u)\n", retlen, + oldblock); + ret = -EIO; + goto read_error; + } + + ret = mtdswap_write_block(d, d->page_buf, page, newblock, 1); + if (ret < 0) { + d->page_data[page] = BLOCK_ERROR; + dev_err(d->dev, "Write error: %d\n", ret); + return ret; + } + + eb = d->eb_data + *newblock / d->pages_per_eblk; + d->page_data[page] = *newblock; + d->revmap[oldblock] = PAGE_UNDEF; + eb = d->eb_data + oldblock / d->pages_per_eblk; + eb->active_count--; + + return 0; + +read_error: + d->page_data[page] = BLOCK_ERROR; + d->revmap[oldblock] = PAGE_UNDEF; + return ret; +} + +static int mtdswap_gc_eblock(struct mtdswap_dev *d, struct swap_eb *eb) +{ + unsigned int i, block, eblk_base, newblock; + int ret, errcode; + + errcode = 0; + eblk_base = (eb - d->eb_data) * d->pages_per_eblk; + + for (i = 0; i < d->pages_per_eblk; i++) { + if (d->spare_eblks < MIN_SPARE_EBLOCKS) + return -ENOSPC; + + block = eblk_base + i; + if (d->revmap[block] == PAGE_UNDEF) + continue; + + ret = mtdswap_move_block(d, block, &newblock); + if (ret < 0 && !errcode) + errcode = ret; + } + + return errcode; +} + +static int __mtdswap_choose_gc_tree(struct mtdswap_dev *d) +{ + int idx, stopat; + + if (TREE_COUNT(d, CLEAN) < LOW_FRAG_GC_TRESHOLD) + stopat = MTDSWAP_LOWFRAG; + else + stopat = MTDSWAP_HIFRAG; + + for (idx = MTDSWAP_BITFLIP; idx >= stopat; idx--) + if (d->trees[idx].root.rb_node != NULL) + return idx; + + return -1; +} + +static int mtdswap_wlfreq(unsigned int maxdiff) +{ + unsigned int h, x, y, dist, base; + + /* + * Calculate linear ramp down from f1 to f2 when maxdiff goes from + * MAX_ERASE_DIFF to MAX_ERASE_DIFF + COLLECT_NONDIRTY_BASE. Similar + * to triangle with height f1 - f1 and width COLLECT_NONDIRTY_BASE. + */ + + dist = maxdiff - MAX_ERASE_DIFF; + if (dist > COLLECT_NONDIRTY_BASE) + dist = COLLECT_NONDIRTY_BASE; + + /* + * Modelling the slop as right angular triangle with base + * COLLECT_NONDIRTY_BASE and height freq1 - freq2. The ratio y/x is + * equal to the ratio h/base. + */ + h = COLLECT_NONDIRTY_FREQ1 - COLLECT_NONDIRTY_FREQ2; + base = COLLECT_NONDIRTY_BASE; + + x = dist - base; + y = (x * h + base / 2) / base; + + return COLLECT_NONDIRTY_FREQ2 + y; +} + +static int mtdswap_choose_wl_tree(struct mtdswap_dev *d) +{ + static unsigned int pick_cnt; + unsigned int i, idx, wear, max; + struct rb_root *root; + + max = 0; + for (i = 0; i <= MTDSWAP_DIRTY; i++) { + root = &d->trees[i].root; + if (root->rb_node == NULL) + continue; + + wear = d->max_erase_count - MTDSWAP_ECNT_MIN(root); + if (wear > max) { + max = wear; + idx = i; + } + } + + if (max > MAX_ERASE_DIFF && pick_cnt >= mtdswap_wlfreq(max) - 1) { + pick_cnt = 0; + return idx; + } + + pick_cnt++; + return -1; +} + +static int mtdswap_choose_gc_tree(struct mtdswap_dev *d, + unsigned int background) +{ + int idx; + + if (TREE_NONEMPTY(d, FAILING) && + (background || (TREE_EMPTY(d, CLEAN) && TREE_EMPTY(d, DIRTY)))) + return MTDSWAP_FAILING; + + idx = mtdswap_choose_wl_tree(d); + if (idx >= MTDSWAP_CLEAN) + return idx; + + return __mtdswap_choose_gc_tree(d); +} + +static struct swap_eb *mtdswap_pick_gc_eblk(struct mtdswap_dev *d, + unsigned int background) +{ + struct rb_root *rp = NULL; + struct swap_eb *eb = NULL; + int idx; + + if (background && TREE_COUNT(d, CLEAN) > CLEAN_BLOCK_THRESHOLD && + TREE_EMPTY(d, DIRTY) && TREE_EMPTY(d, FAILING)) + return NULL; + + idx = mtdswap_choose_gc_tree(d, background); + if (idx < 0) + return NULL; + + rp = &d->trees[idx].root; + eb = rb_entry(rb_first(rp), struct swap_eb, rb); + + rb_erase(&eb->rb, rp); + eb->root = NULL; + d->trees[idx].count--; + return eb; +} + +static unsigned int mtdswap_test_patt(unsigned int i) +{ + return i % 2 ? 0x55555555 : 0xAAAAAAAA; +} + +static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, + struct swap_eb *eb) +{ + struct mtd_info *mtd = d->mtd; + unsigned int test, i, j, patt, mtd_pages; + loff_t base, pos; + unsigned int *p1 = (unsigned int *)d->page_buf; + unsigned char *p2 = (unsigned char *)d->oob_buf; + struct mtd_oob_ops ops; + int ret; + + ops.mode = MTD_OOB_AUTO; + ops.len = mtd->writesize; + ops.ooblen = mtd->ecclayout->oobavail; + ops.ooboffs = 0; + ops.datbuf = d->page_buf; + ops.oobbuf = d->oob_buf; + base = mtdswap_eb_offset(d, eb); + mtd_pages = d->pages_per_eblk * PAGE_SIZE / mtd->writesize; + + for (test = 0; test < 2; test++) { + pos = base; + for (i = 0; i < mtd_pages; i++) { + patt = mtdswap_test_patt(test + i); + memset(d->page_buf, patt, mtd->writesize); + memset(d->oob_buf, patt, mtd->ecclayout->oobavail); + ret = mtd->write_oob(mtd, pos, &ops); + if (ret) + goto error; + + pos += mtd->writesize; + } + + pos = base; + for (i = 0; i < mtd_pages; i++) { + ret = mtd->read_oob(mtd, pos, &ops); + if (ret) + goto error; + + patt = mtdswap_test_patt(test + i); + for (j = 0; j < mtd->writesize/sizeof(int); j++) + if (p1[j] != patt) + goto error; + + for (j = 0; j < mtd->ecclayout->oobavail; j++) + if (p2[j] != (unsigned char)patt) + goto error; + + pos += mtd->writesize; + } + + ret = mtdswap_erase_block(d, eb); + if (ret) + goto error; + } + + eb->flags &= ~EBLOCK_READERR; + return 1; + +error: + mtdswap_handle_badblock(d, eb); + return 0; +} + +static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background) +{ + struct swap_eb *eb; + int ret; + + if (d->spare_eblks < MIN_SPARE_EBLOCKS) + return 1; + + eb = mtdswap_pick_gc_eblk(d, background); + if (!eb) + return 1; + + ret = mtdswap_gc_eblock(d, eb); + if (ret == -ENOSPC) + return 1; + + if (eb->flags & EBLOCK_FAILED) { + mtdswap_handle_badblock(d, eb); + return 0; + } + + eb->flags &= ~EBLOCK_BITFLIP; + ret = mtdswap_erase_block(d, eb); + if ((eb->flags & EBLOCK_READERR) && + (ret || !mtdswap_eblk_passes(d, eb))) + return 0; + + if (ret == 0) + ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_CLEAN); + + if (ret == 0) + mtdswap_rb_add(d, eb, MTDSWAP_CLEAN); + else if (ret != -EIO && ret != -EBADMSG) + mtdswap_rb_add(d, eb, MTDSWAP_DIRTY); + + return 0; +} + +static void mtdswap_background(struct mtd_blktrans_dev *dev) +{ + struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); + int ret; + + while (1) { + ret = mtdswap_gc(d, 1); + if (ret || mtd_blktrans_cease_background(dev)) + return; + } +} + +static void mtdswap_cleanup(struct mtdswap_dev *d) +{ + vfree(d->eb_data); + vfree(d->revmap); + vfree(d->page_data); + kfree(d->oob_buf); + kfree(d->page_buf); +} + +static int mtdswap_flush(struct mtd_blktrans_dev *dev) +{ + struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); + + if (d->mtd->sync) + d->mtd->sync(d->mtd); + return 0; +} + +static unsigned int mtdswap_badblocks(struct mtd_info *mtd, uint64_t size) +{ + loff_t offset; + unsigned int badcnt; + + badcnt = 0; + + if (mtd->block_isbad) + for (offset = 0; offset < size; offset += mtd->erasesize) + if (mtd->block_isbad(mtd, offset)) + badcnt++; + + return badcnt; +} + +static int mtdswap_writesect(struct mtd_blktrans_dev *dev, + unsigned long page, char *buf) +{ + struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); + unsigned int newblock, mapped; + struct swap_eb *eb; + int ret; + + d->sect_write_count++; + + if (d->spare_eblks < MIN_SPARE_EBLOCKS) + return -ENOSPC; + + if (header) { + /* Ignore writes to the header page */ + if (unlikely(page == 0)) + return 0; + + page--; + } + + mapped = d->page_data[page]; + if (mapped <= BLOCK_MAX) { + eb = d->eb_data + (mapped / d->pages_per_eblk); + eb->active_count--; + mtdswap_store_eb(d, eb); + d->page_data[page] = BLOCK_UNDEF; + d->revmap[mapped] = PAGE_UNDEF; + } + + ret = mtdswap_write_block(d, buf, page, &newblock, 0); + d->mtd_write_count++; + + if (ret < 0) + return ret; + + eb = d->eb_data + (newblock / d->pages_per_eblk); + d->page_data[page] = newblock; + + return 0; +} + +/* Provide a dummy swap header for the kernel */ +static int mtdswap_auto_header(struct mtdswap_dev *d, char *buf) +{ + union swap_header *hd = (union swap_header *)(buf); + + memset(buf, 0, PAGE_SIZE - 10); + + hd->info.version = 1; + hd->info.last_page = d->mbd_dev->size - 1; + hd->info.nr_badpages = 0; + + memcpy(buf + PAGE_SIZE - 10, "SWAPSPACE2", 10); + + return 0; +} + +static int mtdswap_readsect(struct mtd_blktrans_dev *dev, + unsigned long page, char *buf) +{ + struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); + struct mtd_info *mtd = d->mtd; + unsigned int realblock, retries; + loff_t readpos; + struct swap_eb *eb; + size_t retlen; + int ret; + + d->sect_read_count++; + + if (header) { + if (unlikely(page == 0)) + return mtdswap_auto_header(d, buf); + + page--; + } + + realblock = d->page_data[page]; + if (realblock > BLOCK_MAX) { + memset(buf, 0x0, PAGE_SIZE); + if (realblock == BLOCK_UNDEF) + return 0; + else + return -EIO; + } + + eb = d->eb_data + (realblock / d->pages_per_eblk); + BUG_ON(d->revmap[realblock] == PAGE_UNDEF); + + readpos = (loff_t)realblock << PAGE_SHIFT; + retries = 0; + +retry: + ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf); + + d->mtd_read_count++; + if (ret == -EUCLEAN) { + eb->flags |= EBLOCK_BITFLIP; + mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP); + ret = 0; + } + + if (ret < 0) { + dev_err(d->dev, "Read error %d\n", ret); + eb->flags |= EBLOCK_READERR; + mtdswap_rb_add(d, eb, MTDSWAP_FAILING); + retries++; + if (retries < MTDSWAP_IO_RETRIES) + goto retry; + + return ret; + } + + if (retlen != PAGE_SIZE) { + dev_err(d->dev, "Short read %d\n", retlen); + return -EIO; + } + + return 0; +} + +static int mtdswap_discard(struct mtd_blktrans_dev *dev, unsigned long first, + unsigned nr_pages) +{ + struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); + unsigned long page; + struct swap_eb *eb; + unsigned int mapped; + + d->discard_count++; + + for (page = first; page < first + nr_pages; page++) { + mapped = d->page_data[page]; + if (mapped <= BLOCK_MAX) { + eb = d->eb_data + (mapped / d->pages_per_eblk); + eb->active_count--; + mtdswap_store_eb(d, eb); + d->page_data[page] = BLOCK_UNDEF; + d->revmap[mapped] = PAGE_UNDEF; + d->discard_page_count++; + } else if (mapped == BLOCK_ERROR) { + d->page_data[page] = BLOCK_UNDEF; + d->discard_page_count++; + } + } + + return 0; +} + +static int mtdswap_show(struct seq_file *s, void *data) +{ + struct mtdswap_dev *d = (struct mtdswap_dev *) s->private; + unsigned long sum; + unsigned int count[MTDSWAP_TREE_CNT]; + unsigned int min[MTDSWAP_TREE_CNT]; + unsigned int max[MTDSWAP_TREE_CNT]; + unsigned int i, cw = 0, cwp = 0, cwecount = 0, bb_cnt, mapped, pages; + uint64_t use_size; + char *name[] = {"clean", "used", "low", "high", "dirty", "bitflip", + "failing"}; + + mutex_lock(&d->mbd_dev->lock); + + for (i = 0; i < MTDSWAP_TREE_CNT; i++) { + struct rb_root *root = &d->trees[i].root; + + if (root->rb_node) { + count[i] = d->trees[i].count; + min[i] = rb_entry(rb_first(root), struct swap_eb, + rb)->erase_count; + max[i] = rb_entry(rb_last(root), struct swap_eb, + rb)->erase_count; + } else + count[i] = 0; + } + + if (d->curr_write) { + cw = 1; + cwp = d->curr_write_pos; + cwecount = d->curr_write->erase_count; + } + + sum = 0; + for (i = 0; i < d->eblks; i++) + sum += d->eb_data[i].erase_count; + + use_size = (uint64_t)d->eblks * d->mtd->erasesize; + bb_cnt = mtdswap_badblocks(d->mtd, use_size); + + mapped = 0; + pages = d->mbd_dev->size; + for (i = 0; i < pages; i++) + if (d->page_data[i] != BLOCK_UNDEF) + mapped++; + + mutex_unlock(&d->mbd_dev->lock); + + for (i = 0; i < MTDSWAP_TREE_CNT; i++) { + if (!count[i]) + continue; + + if (min[i] != max[i]) + seq_printf(s, "%s:\t%5d erase blocks, erased min %d, " + "max %d times\n", + name[i], count[i], min[i], max[i]); + else + seq_printf(s, "%s:\t%5d erase blocks, all erased %d " + "times\n", name[i], count[i], min[i]); + } + + if (bb_cnt) + seq_printf(s, "bad:\t%5u erase blocks\n", bb_cnt); + + if (cw) + seq_printf(s, "current erase block: %u pages used, %u free, " + "erased %u times\n", + cwp, d->pages_per_eblk - cwp, cwecount); + + seq_printf(s, "total erasures: %lu\n", sum); + + seq_printf(s, "\n"); + + seq_printf(s, "mtdswap_readsect count: %llu\n", d->sect_read_count); + seq_printf(s, "mtdswap_writesect count: %llu\n", d->sect_write_count); + seq_printf(s, "mtdswap_discard count: %llu\n", d->discard_count); + seq_printf(s, "mtd read count: %llu\n", d->mtd_read_count); + seq_printf(s, "mtd write count: %llu\n", d->mtd_write_count); + seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count); + + seq_printf(s, "\n"); + seq_printf(s, "total pages: %lu\n", pages); + seq_printf(s, "pages mapped: %u\n", mapped); + + return 0; +} + +static int mtdswap_open(struct inode *inode, struct file *file) +{ + return single_open(file, mtdswap_show, inode->i_private); +} + +static const struct file_operations mtdswap_fops = { + .open = mtdswap_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int mtdswap_add_debugfs(struct mtdswap_dev *d) +{ + struct gendisk *gd = d->mbd_dev->disk; + struct device *dev = disk_to_dev(gd); + + struct dentry *root; + struct dentry *dent; + + root = debugfs_create_dir(gd->disk_name, NULL); + if (IS_ERR(root)) + return 0; + + if (!root) { + dev_err(dev, "failed to initialize debugfs\n"); + return -1; + } + + d->debugfs_root = root; + + dent = debugfs_create_file("stats", S_IRUSR, root, d, + &mtdswap_fops); + if (!dent) { + dev_err(d->dev, "debugfs_create_file failed\n"); + debugfs_remove_recursive(root); + d->debugfs_root = NULL; + return -1; + } + + return 0; +} + +static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, + unsigned int spare_cnt) +{ + struct mtd_info *mtd = d->mbd_dev->mtd; + unsigned int i, eblk_bytes, pages, blocks; + int ret = -ENOMEM; + + d->mtd = mtd; + d->eblks = eblocks; + d->spare_eblks = spare_cnt; + d->pages_per_eblk = mtd->erasesize >> PAGE_SHIFT; + + pages = d->mbd_dev->size; + blocks = eblocks * d->pages_per_eblk; + + for (i = 0; i < MTDSWAP_TREE_CNT; i++) + d->trees[i].root = RB_ROOT; + + d->page_data = vmalloc(sizeof(int)*pages); + if (!d->page_data) + goto page_data_fail; + + d->revmap = vmalloc(sizeof(int)*blocks); + if (!d->revmap) + goto revmap_fail; + + eblk_bytes = sizeof(struct swap_eb)*d->eblks; + d->eb_data = vmalloc(eblk_bytes); + if (!d->eb_data) + goto eb_data_fail; + + memset(d->eb_data, 0, eblk_bytes); + for (i = 0; i < pages; i++) + d->page_data[i] = BLOCK_UNDEF; + + for (i = 0; i < blocks; i++) + d->revmap[i] = PAGE_UNDEF; + + d->page_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!d->page_buf) + goto page_buf_fail; + + d->oob_buf = kmalloc(2 * mtd->ecclayout->oobavail, GFP_KERNEL); + if (!d->oob_buf) + goto oob_buf_fail; + + mtdswap_scan_eblks(d); + + return 0; + +oob_buf_fail: + kfree(d->page_buf); +page_buf_fail: + vfree(d->eb_data); +eb_data_fail: + vfree(d->revmap); +revmap_fail: + vfree(d->page_data); +page_data_fail: + printk(KERN_ERR "%s: init failed (%d)\n", MTDSWAP_PREFIX, ret); + return ret; +} + +static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) +{ + struct mtdswap_dev *d; + struct mtd_blktrans_dev *mbd_dev; + char *parts; + char *this_opt; + unsigned long part; + unsigned int eblocks, eavailable, bad_blocks, spare_cnt; + uint64_t swap_size, use_size, size_limit; + struct nand_ecclayout *oinfo; + int ret; + + parts = &partitions[0]; + if (!*parts) + return; + + while ((this_opt = strsep(&parts, ",")) != NULL) { + if (strict_strtoul(this_opt, 0, &part) < 0) + return; + + if (mtd->index == part) + break; + } + + if (mtd->index != part) + return; + + if (mtd->erasesize < PAGE_SIZE || mtd->erasesize % PAGE_SIZE) { + printk(KERN_ERR "%s: Erase size %u not multiple of PAGE_SIZE " + "%lu\n", MTDSWAP_PREFIX, mtd->erasesize, PAGE_SIZE); + return; + } + + if (PAGE_SIZE % mtd->writesize || mtd->writesize > PAGE_SIZE) { + printk(KERN_ERR "%s: PAGE_SIZE %lu not multiple of write size" + " %u\n", MTDSWAP_PREFIX, PAGE_SIZE, mtd->writesize); + return; + } + + oinfo = mtd->ecclayout; + if (!mtd->oobsize || !oinfo || oinfo->oobavail < MTDSWAP_OOBSIZE) { + printk(KERN_ERR "%s: Not enough free bytes in OOB, " + "%d available, %u needed.\n", + MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE); + return; + } + + if (spare_eblocks > 100) + spare_eblocks = 100; + + use_size = mtd->size; + size_limit = (uint64_t) BLOCK_MAX * PAGE_SIZE; + + if (mtd->size > size_limit) { + printk(KERN_WARNING "%s: Device too large. Limiting size to " + "%llu bytes\n", MTDSWAP_PREFIX, size_limit); + use_size = size_limit; + } + + eblocks = mtd_div_by_eb(use_size, mtd); + use_size = eblocks * mtd->erasesize; + bad_blocks = mtdswap_badblocks(mtd, use_size); + eavailable = eblocks - bad_blocks; + + if (eavailable < MIN_ERASE_BLOCKS) { + printk(KERN_ERR "%s: Not enough erase blocks. %u available, " + "%d needed\n", MTDSWAP_PREFIX, eavailable, + MIN_ERASE_BLOCKS); + return; + } + + spare_cnt = div_u64((uint64_t)eavailable * spare_eblocks, 100); + + if (spare_cnt < MIN_SPARE_EBLOCKS) + spare_cnt = MIN_SPARE_EBLOCKS; + + if (spare_cnt > eavailable - 1) + spare_cnt = eavailable - 1; + + swap_size = (uint64_t)(eavailable - spare_cnt) * mtd->erasesize + + (header ? PAGE_SIZE : 0); + + printk(KERN_INFO "%s: Enabling MTD swap on device %lu, size %llu KB, " + "%u spare, %u bad blocks\n", + MTDSWAP_PREFIX, part, swap_size / 1024, spare_cnt, bad_blocks); + + d = kzalloc(sizeof(struct mtdswap_dev), GFP_KERNEL); + if (!d) + return; + + mbd_dev = kzalloc(sizeof(struct mtd_blktrans_dev), GFP_KERNEL); + if (!mbd_dev) { + kfree(d); + return; + } + + d->mbd_dev = mbd_dev; + mbd_dev->priv = d; + + mbd_dev->mtd = mtd; + mbd_dev->devnum = mtd->index; + mbd_dev->size = swap_size >> PAGE_SHIFT; + mbd_dev->tr = tr; + + if (!(mtd->flags & MTD_WRITEABLE)) + mbd_dev->readonly = 1; + + if (mtdswap_init(d, eblocks, spare_cnt) < 0) + goto init_failed; + + if (add_mtd_blktrans_dev(mbd_dev) < 0) + goto cleanup; + + d->dev = disk_to_dev(mbd_dev->disk); + + ret = mtdswap_add_debugfs(d); + if (ret < 0) + goto debugfs_failed; + + return; + +debugfs_failed: + del_mtd_blktrans_dev(mbd_dev); + +cleanup: + mtdswap_cleanup(d); + +init_failed: + kfree(mbd_dev); + kfree(d); +} + +static void mtdswap_remove_dev(struct mtd_blktrans_dev *dev) +{ + struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev); + + debugfs_remove_recursive(d->debugfs_root); + del_mtd_blktrans_dev(dev); + mtdswap_cleanup(d); + kfree(d); +} + +static struct mtd_blktrans_ops mtdswap_ops = { + .name = "mtdswap", + .major = 0, + .part_bits = 0, + .blksize = PAGE_SIZE, + .flush = mtdswap_flush, + .readsect = mtdswap_readsect, + .writesect = mtdswap_writesect, + .discard = mtdswap_discard, + .background = mtdswap_background, + .add_mtd = mtdswap_add_mtd, + .remove_dev = mtdswap_remove_dev, + .owner = THIS_MODULE, +}; + +static int __init mtdswap_modinit(void) +{ + return register_mtd_blktrans(&mtdswap_ops); +} + +static void __exit mtdswap_modexit(void) +{ + deregister_mtd_blktrans(&mtdswap_ops); +} + +module_init(mtdswap_modinit); +module_exit(mtdswap_modexit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jarkko Lavinen "); +MODULE_DESCRIPTION("Block device access to an MTD suitable for using as " + "swap space"); -- cgit v1.2.2 From dcfb81d61da1367e52f7f7e3ceff0d0044c3c7ee Mon Sep 17 00:00:00 2001 From: David Griego Date: Tue, 30 Nov 2010 15:32:05 +0530 Subject: mtd: NOR flash driver for OMAP-L137/AM17x OMAP-L137/AM17x has limited number of dedicated EMIFA address pins, enough to interface directly to an SDRAM. If a device such as an asynchronous flash needs to be attached to the EMIFA, then either GPIO pins or a chip select may be used to control the flash device's upper address lines. This patch adds support for the NOR flash on the OMAP-L137/ AM17x user interface daughter board using the latch-addr-flash MTD mapping driver which allows flashes to be partially physically addressed. The upper address lines are set by a board specific code which is a separate patch. Signed-off-by: David Griego Signed-off-by: Aleksey Makarov Signed-off-by: Sergei Shtylyov Signed-off-by: Savinay Dharmappa Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/maps/Kconfig | 9 ++ drivers/mtd/maps/Makefile | 1 + drivers/mtd/maps/latch-addr-flash.c | 272 ++++++++++++++++++++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 drivers/mtd/maps/latch-addr-flash.c (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 803072a71ed7..44b1f46458ca 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -552,4 +552,13 @@ config MTD_PISMO When built as a module, it will be called pismo.ko +config MTD_LATCH_ADDR + tristate "Latch-assisted Flash Chip Support" + depends on MTD_COMPLEX_MAPPINGS + help + Map driver which allows flashes to be partially physically addressed + and have the upper address lines set by a board specific code. + + If compiled as a module, it will be called latch-addr-flash. + endmenu diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index c7869c7a6b18..08533bd5cba7 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o obj-$(CONFIG_MTD_VMU) += vmu-flash.o obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o +obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c new file mode 100644 index 000000000000..ee2548085334 --- /dev/null +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -0,0 +1,272 @@ +/* + * Interface for NOR flash driver whose high address lines are latched + * + * Copyright © 2000 Nicolas Pitre + * Copyright © 2005-2008 Analog Devices Inc. + * Copyright © 2008 MontaVista Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "latch-addr-flash" + +struct latch_addr_flash_info { + struct mtd_info *mtd; + struct map_info map; + struct resource *res; + + void (*set_window)(unsigned long offset, void *data); + void *data; + + /* cache; could be found out of res */ + unsigned long win_mask; + + int nr_parts; + struct mtd_partition *parts; + + spinlock_t lock; +}; + +static map_word lf_read(struct map_info *map, unsigned long ofs) +{ + struct latch_addr_flash_info *info; + map_word datum; + + info = (struct latch_addr_flash_info *)map->map_priv_1; + + spin_lock(&info->lock); + + info->set_window(ofs, info->data); + datum = inline_map_read(map, info->win_mask & ofs); + + spin_unlock(&info->lock); + + return datum; +} + +static void lf_write(struct map_info *map, map_word datum, unsigned long ofs) +{ + struct latch_addr_flash_info *info; + + info = (struct latch_addr_flash_info *)map->map_priv_1; + + spin_lock(&info->lock); + + info->set_window(ofs, info->data); + inline_map_write(map, datum, info->win_mask & ofs); + + spin_unlock(&info->lock); +} + +static void lf_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + struct latch_addr_flash_info *info = + (struct latch_addr_flash_info *) map->map_priv_1; + unsigned n; + + while (len > 0) { + n = info->win_mask + 1 - (from & info->win_mask); + if (n > len) + n = len; + + spin_lock(&info->lock); + + info->set_window(from, info->data); + memcpy_fromio(to, map->virt + (from & info->win_mask), n); + + spin_unlock(&info->lock); + + to += n; + from += n; + len -= n; + } +} + +static char *rom_probe_types[] = { "cfi_probe", NULL }; + +static char *part_probe_types[] = { "cmdlinepart", NULL }; + +static int latch_addr_flash_remove(struct platform_device *dev) +{ + struct latch_addr_flash_info *info; + struct latch_addr_flash_data *latch_addr_data; + + info = platform_get_drvdata(dev); + if (info == NULL) + return 0; + platform_set_drvdata(dev, NULL); + + latch_addr_data = dev->dev.platform_data; + + if (info->mtd != NULL) { + if (mtd_has_partitions()) { + if (info->nr_parts) { + del_mtd_partitions(info->mtd); + kfree(info->parts); + } else if (latch_addr_data->nr_parts) { + del_mtd_partitions(info->mtd); + } else { + del_mtd_device(info->mtd); + } + } else { + del_mtd_device(info->mtd); + } + map_destroy(info->mtd); + } + + if (info->map.virt != NULL) + iounmap(info->map.virt); + + if (info->res != NULL) + release_mem_region(info->res->start, resource_size(info->res)); + + kfree(info); + + if (latch_addr_data->done) + latch_addr_data->done(latch_addr_data->data); + + return 0; +} + +static int __devinit latch_addr_flash_probe(struct platform_device *dev) +{ + struct latch_addr_flash_data *latch_addr_data; + struct latch_addr_flash_info *info; + resource_size_t win_base = dev->resource->start; + resource_size_t win_size = resource_size(dev->resource); + char **probe_type; + int chipsel; + int err; + + latch_addr_data = dev->dev.platform_data; + if (latch_addr_data == NULL) + return -ENODEV; + + pr_notice("latch-addr platform flash device: %#llx byte " + "window at %#.8llx\n", + (unsigned long long)win_size, (unsigned long long)win_base); + + chipsel = dev->id; + + if (latch_addr_data->init) { + err = latch_addr_data->init(latch_addr_data->data, chipsel); + if (err != 0) + return err; + } + + info = kzalloc(sizeof(struct latch_addr_flash_info), GFP_KERNEL); + if (info == NULL) { + err = -ENOMEM; + goto done; + } + + platform_set_drvdata(dev, info); + + info->res = request_mem_region(win_base, win_size, DRIVER_NAME); + if (info->res == NULL) { + dev_err(&dev->dev, "Could not reserve memory region\n"); + err = -EBUSY; + goto free_info; + } + + info->map.name = DRIVER_NAME; + info->map.size = latch_addr_data->size; + info->map.bankwidth = latch_addr_data->width; + + info->map.phys = NO_XIP; + info->map.virt = ioremap(win_base, win_size); + if (!info->map.virt) { + err = -ENOMEM; + goto free_res; + } + + info->map.map_priv_1 = (unsigned long)info; + + info->map.read = lf_read; + info->map.copy_from = lf_copy_from; + info->map.write = lf_write; + info->set_window = latch_addr_data->set_window; + info->data = latch_addr_data->data; + info->win_mask = win_size - 1; + + spin_lock_init(&info->lock); + + for (probe_type = rom_probe_types; !info->mtd && *probe_type; + probe_type++) + info->mtd = do_map_probe(*probe_type, &info->map); + + if (info->mtd == NULL) { + dev_err(&dev->dev, "map_probe failed\n"); + err = -ENODEV; + goto iounmap; + } + info->mtd->owner = THIS_MODULE; + + if (mtd_has_partitions()) { + + err = parse_mtd_partitions(info->mtd, + (const char **)part_probe_types, + &info->parts, 0); + if (err > 0) { + add_mtd_partitions(info->mtd, info->parts, err); + return 0; + } + if (latch_addr_data->nr_parts) { + pr_notice("Using latch-addr-flash partition information\n"); + add_mtd_partitions(info->mtd, latch_addr_data->parts, + latch_addr_data->nr_parts); + return 0; + } + } + add_mtd_device(info->mtd); + return 0; + +iounmap: + iounmap(info->map.virt); +free_res: + release_mem_region(info->res->start, resource_size(info->res)); +free_info: + kfree(info); +done: + if (latch_addr_data->done) + latch_addr_data->done(latch_addr_data->data); + return err; +} + +static struct platform_driver latch_addr_flash_driver = { + .probe = latch_addr_flash_probe, + .remove = __devexit_p(latch_addr_flash_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init latch_addr_flash_init(void) +{ + return platform_driver_register(&latch_addr_flash_driver); +} +module_init(latch_addr_flash_init); + +static void __exit latch_addr_flash_exit(void) +{ + platform_driver_unregister(&latch_addr_flash_driver); +} +module_exit(latch_addr_flash_exit); + +MODULE_AUTHOR("David Griego "); +MODULE_DESCRIPTION("MTD map driver for flashes addressed physically with upper " + "address lines being set board specifically"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From b3dcfd35244e1cb8dc8dfa5c05013b133dbb437a Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Thu, 17 Feb 2011 13:44:41 +0200 Subject: mtd: onenand: add new option to control initial onenand unlocking A new option ONENAND_SKIP_INITIAL_UNLOCKING is added. This allows to disable initial onenand unlocking when the driver is initialized. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/onenand_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 4205b9423b89..56a8b2005bda 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -4085,7 +4085,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) mtd->writebufsize = mtd->writesize; /* Unlock whole block */ - this->unlock_all(mtd); + if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING)) + this->unlock_all(mtd); ret = this->scan_bbt(mtd); if ((!FLEXONENAND(this)) || ret) -- cgit v1.2.2 From c93ff6bf16523d33e991a1fadde1b8d63eb7cd2c Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Thu, 17 Feb 2011 13:44:42 +0200 Subject: mtd: omap: add new variable to platform data to control onenand unlocking New variable skip_initial_unlocking is added to the omap_onenand_platform_data. This is used to inform the onenand driver to skip onenand unlocking when it is initialized. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/onenand/omap2.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index c849cacf4b2f..ea32c2fc4622 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -631,6 +631,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) { struct omap_onenand_platform_data *pdata; struct omap2_onenand *c; + struct onenand_chip *this; int r; pdata = pdev->dev.platform_data; @@ -728,9 +729,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->mtd.dev.parent = &pdev->dev; + this = &c->onenand; if (c->dma_channel >= 0) { - struct onenand_chip *this = &c->onenand; - this->wait = omap2_onenand_wait; if (cpu_is_omap34xx()) { this->read_bufferram = omap3_onenand_read_bufferram; @@ -751,6 +751,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->onenand.disable = omap2_onenand_disable; } + if (pdata->skip_initial_unlocking) + this->options |= ONENAND_SKIP_INITIAL_UNLOCKING; + if ((r = onenand_scan(&c->mtd, 1)) < 0) goto err_release_regulator; -- cgit v1.2.2 From 775adc3d44c8076d3e475fabebb61c08421c4421 Mon Sep 17 00:00:00 2001 From: Jason Liu Date: Fri, 25 Feb 2011 13:06:18 +0800 Subject: mtd: nand: fix a typo in a commentary Signed-off-by: Jason Liu Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a9c6ce745767..da7604050347 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2377,7 +2377,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, return -EINVAL; } - /* Do not allow reads past end of device */ + /* Do not allow write past end of device */ if (unlikely(to >= mtd->size || ops->ooboffs + ops->ooblen > ((mtd->size >> chip->page_shift) - -- cgit v1.2.2 From 74f1b7244e502c5a98906a5dcc5ec389aacd25e6 Mon Sep 17 00:00:00 2001 From: John Ogness Date: Mon, 28 Feb 2011 13:12:46 +0100 Subject: mtd: omap3: nand: report corrected ecc errors The number of corrected ECC errors should be reported since other MTD systems make use of this information (such as UBI data scrubbing). Signed-off-by: John Ogness Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/omap2.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 28af71c61834..d7a4e2550b13 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -517,6 +517,8 @@ static void gen_true_ecc(u8 *ecc_buf) * * This function compares two ECC's and indicates if there is an error. * If the error can be corrected it will be corrected to the buffer. + * If there is no error, %0 is returned. If there is an error but it + * was corrected, %1 is returned. Otherwise, %-1 is returned. */ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ u8 *ecc_data2, /* read from register */ @@ -622,7 +624,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ page_data[find_byte] ^= (1 << find_bit); - return 0; + return 1; default: if (isEccFF) { if (ecc_data2[0] == 0 && @@ -643,8 +645,11 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ * @calc_ecc: ecc read from HW ECC registers * * Compares the ecc read from nand spare area with ECC registers values - * and if ECC's mismached, it will call 'omap_compare_ecc' for error detection - * and correction. + * and if ECC's mismatched, it will call 'omap_compare_ecc' for error + * detection and correction. If there are no errors, %0 is returned. If + * there were errors and all of the errors were corrected, the number of + * corrected errors is returned. If uncorrectable errors exist, %-1 is + * returned. */ static int omap_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) @@ -652,6 +657,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat, struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, mtd); int blockCnt = 0, i = 0, ret = 0; + int stat = 0; /* Ex NAND_ECC_HW12_2048 */ if ((info->nand.ecc.mode == NAND_ECC_HW) && @@ -665,12 +671,14 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat, ret = omap_compare_ecc(read_ecc, calc_ecc, dat); if (ret < 0) return ret; + /* keep track of the number of corrected errors */ + stat += ret; } read_ecc += 3; calc_ecc += 3; dat += 512; } - return 0; + return stat; } /** -- cgit v1.2.2 From 5d9d9936209e589569a97985285b3282310cf2db Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 2 Mar 2011 16:47:55 +0200 Subject: mtd: mxc_nand: fix read past buffer end Signed-off-by: Baruch Siach Acked-by: Sascha hauer Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ef932ba55a0b..6cd78ed439a7 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -641,9 +641,9 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) n = min(n, len); - memcpy(buf, host->data_buf + col, len); + memcpy(buf, host->data_buf + col, n); - host->buf_start += len; + host->buf_start += n; } /* Used by the upper layer to verify the data in NAND Flash -- cgit v1.2.2 From e70727e442eb61581f836a9a0ca0c3b70d8a3ff2 Mon Sep 17 00:00:00 2001 From: David Lambert Date: Mon, 7 Mar 2011 12:00:46 +0200 Subject: mtd: speedtest: fix integer overflow 32-bit integers used in 'calc_speed()' may overflow and lead to incorrect results. Use 64-bit integers instead. Signed-off-by: David Lambert Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/tests/mtd_speedtest.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 3ce6fce75e07..627d4e2466a3 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -314,16 +314,16 @@ static inline void stop_timing(void) static long calc_speed(void) { - long ms, k, speed; + uint64_t k; + long ms; ms = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000; - k = goodebcnt * mtd->erasesize / 1024; - if (ms) - speed = (k * 1000) / ms; - else - speed = 0; - return speed; + if (ms == 0) + return 0; + k = goodebcnt * (mtd->erasesize / 1024) * 1000; + do_div(k, ms); + return k; } static int scan_for_bad_eraseblocks(void) -- cgit v1.2.2 From e353a20afaee1e3e67fc4fa663a76c68a4c1fb74 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 3 Mar 2011 11:08:30 +0800 Subject: mtd: pxa3xx_nand: make scan procedure more clear The previous probe function is some kind of big part. This patch seperate the resource allocation to keep the probe process more clear than before. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 99 +++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ea2c288df3f6..f44044381360 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -126,6 +126,7 @@ struct pxa3xx_nand_info { unsigned int buf_start; unsigned int buf_count; + struct mtd_info *mtd; /* DMA information */ int drcmr_dat; int drcmr_cmd; @@ -1044,34 +1045,27 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, this->chip_delay = 25; } -static int pxa3xx_nand_probe(struct platform_device *pdev) +static +struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) { - struct pxa3xx_nand_platform_data *pdata; + struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; struct pxa3xx_nand_info *info; - struct nand_chip *this; struct mtd_info *mtd; struct resource *r; - int ret = 0, irq; - - pdata = pdev->dev.platform_data; - - if (!pdata) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -ENODEV; - } + int ret, irq; mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), GFP_KERNEL); if (!mtd) { dev_err(&pdev->dev, "failed to allocate memory\n"); - return -ENOMEM; + return NULL; } info = (struct pxa3xx_nand_info *)(&mtd[1]); info->pdev = pdev; - this = &info->nand_chip; mtd->priv = info; + info->mtd = mtd; mtd->owner = THIS_MODULE; info->clk = clk_get(&pdev->dev, NULL); @@ -1149,31 +1143,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } pxa3xx_nand_init_mtd(mtd, info); + platform_set_drvdata(pdev, info); - platform_set_drvdata(pdev, mtd); - - if (nand_scan(mtd, 1)) { - dev_err(&pdev->dev, "failed to scan nand\n"); - ret = -ENXIO; - goto fail_free_irq; - } - -#ifdef CONFIG_MTD_PARTITIONS - if (mtd_has_cmdlinepart()) { - static const char *probes[] = { "cmdlinepart", NULL }; - struct mtd_partition *parts; - int nr_parts; - - nr_parts = parse_mtd_partitions(mtd, probes, &parts, 0); - - if (nr_parts) - return add_mtd_partitions(mtd, parts, nr_parts); - } - - return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); -#else - return 0; -#endif + return info; fail_free_irq: free_irq(irq, info); @@ -1193,13 +1165,13 @@ fail_put_clk: clk_put(info->clk); fail_free_mtd: kfree(mtd); - return ret; + return NULL; } static int pxa3xx_nand_remove(struct platform_device *pdev) { - struct mtd_info *mtd = platform_get_drvdata(pdev); - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); + struct mtd_info *mtd = info->mtd; struct resource *r; int irq; @@ -1230,11 +1202,50 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) return 0; } +static int pxa3xx_nand_probe(struct platform_device *pdev) +{ + struct pxa3xx_nand_platform_data *pdata; + struct pxa3xx_nand_info *info; + + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "no platform data defined\n"); + return -ENODEV; + } + + info = alloc_nand_resource(pdev); + if (info == NULL) + return -ENOMEM; + + if (nand_scan(info->mtd, 1)) { + dev_err(&pdev->dev, "failed to scan nand\n"); + pxa3xx_nand_remove(pdev); + return -ENODEV; + } + +#ifdef CONFIG_MTD_PARTITIONS + if (mtd_has_cmdlinepart()) { + const char *probes[] = { "cmdlinepart", NULL }; + struct mtd_partition *parts; + int nr_parts; + + nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); + + if (nr_parts) + return add_mtd_partitions(mtd, parts, nr_parts); + } + + return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); +#else + return 0; +#endif +} + #ifdef CONFIG_PM static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) { - struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); + struct mtd_info *mtd = info->mtd; if (info->state != STATE_READY) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); @@ -1246,8 +1257,8 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) static int pxa3xx_nand_resume(struct platform_device *pdev) { - struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(pdev); - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); + struct mtd_info *mtd = info->mtd; nand_writel(info, NDTR0CS0, info->ndtr0cs0); nand_writel(info, NDTR1CS0, info->ndtr1cs0); -- cgit v1.2.2 From f8155a404db95656f1519b28fdb96cb68f8b2364 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Mon, 28 Feb 2011 10:32:11 +0800 Subject: mtd: pxa3xx_nand: rework irq logic Enable all irq when we start the nand controller, and put all the transaction logic in the pxa3xx_nand_irq. By doing this way, we could dramatically increase the performance by avoid unnecessary delay. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 399 +++++++++++++++++++---------------------- 1 file changed, 187 insertions(+), 212 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index f44044381360..3264b1d5a638 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -27,6 +27,7 @@ #include #define CHIP_DELAY_TIMEOUT (2 * HZ/10) +#define NAND_STOP_DELAY (2 * HZ/50) /* registers and bit definitions */ #define NDCR (0x00) /* Control register */ @@ -52,16 +53,18 @@ #define NDCR_ND_MODE (0x3 << 21) #define NDCR_NAND_MODE (0x0) #define NDCR_CLR_PG_CNT (0x1 << 20) -#define NDCR_CLR_ECC (0x1 << 19) +#define NDCR_STOP_ON_UNCOR (0x1 << 19) #define NDCR_RD_ID_CNT_MASK (0x7 << 16) #define NDCR_RD_ID_CNT(x) (((x) << 16) & NDCR_RD_ID_CNT_MASK) #define NDCR_RA_START (0x1 << 15) #define NDCR_PG_PER_BLK (0x1 << 14) #define NDCR_ND_ARB_EN (0x1 << 12) +#define NDCR_INT_MASK (0xFFF) #define NDSR_MASK (0xfff) -#define NDSR_RDY (0x1 << 11) +#define NDSR_RDY (0x1 << 12) +#define NDSR_FLASH_RDY (0x1 << 11) #define NDSR_CS0_PAGED (0x1 << 10) #define NDSR_CS1_PAGED (0x1 << 9) #define NDSR_CS0_CMDD (0x1 << 8) @@ -104,13 +107,15 @@ enum { }; enum { - STATE_READY = 0, + STATE_IDLE = 0, STATE_CMD_HANDLE, STATE_DMA_READING, STATE_DMA_WRITING, STATE_DMA_DONE, STATE_PIO_READING, STATE_PIO_WRITING, + STATE_CMD_DONE, + STATE_READY, }; struct pxa3xx_nand_info { @@ -292,7 +297,48 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) } } -static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, +/** + * NOTE: it is a must to set ND_RUN firstly, then write + * command buffer, otherwise, it does not work. + * We enable all the interrupt at the same time, and + * let pxa3xx_nand_irq to handle all logic. + */ +static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) +{ + uint32_t ndcr; + + ndcr = info->reg_ndcr; + ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; + ndcr |= info->use_dma ? NDCR_DMA_EN : 0; + ndcr |= NDCR_ND_RUN; + + /* clear status bits and run */ + nand_writel(info, NDCR, 0); + nand_writel(info, NDSR, NDSR_MASK); + nand_writel(info, NDCR, ndcr); +} + +static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info) +{ + uint32_t ndcr; + int timeout = NAND_STOP_DELAY; + + /* wait RUN bit in NDCR become 0 */ + ndcr = nand_readl(info, NDCR); + while ((ndcr & NDCR_ND_RUN) && (timeout-- > 0)) { + ndcr = nand_readl(info, NDCR); + udelay(1); + } + + if (timeout <= 0) { + ndcr &= ~NDCR_ND_RUN; + nand_writel(info, NDCR, ndcr); + } + /* clear status bits */ + nand_writel(info, NDSR, NDSR_MASK); +} + +static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info, uint16_t cmd, int column, int page_addr) { const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; @@ -319,21 +365,18 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, if (cmd == cmdset->program) info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; - - return 0; } -static int prepare_erase_cmd(struct pxa3xx_nand_info *info, +static void prepare_erase_cmd(struct pxa3xx_nand_info *info, uint16_t cmd, int page_addr) { info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3); info->ndcb1 = page_addr; info->ndcb2 = 0; - return 0; } -static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) +static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) { const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; @@ -343,7 +386,7 @@ static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) info->oob_size = 0; if (cmd == cmdset->read_id) { - info->ndcb0 |= NDCB0_CMD_TYPE(3); + info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1); info->data_size = 8; } else if (cmd == cmdset->read_status) { info->ndcb0 |= NDCB0_CMD_TYPE(4); @@ -352,9 +395,7 @@ static int prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) cmd == cmdset->unlock) { info->ndcb0 |= NDCB0_CMD_TYPE(5); } else - return -EINVAL; - - return 0; + BUG(); } static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) @@ -402,10 +443,8 @@ static int write_cmd(struct pxa3xx_nand_info *info) return 0; } -static int handle_data_pio(struct pxa3xx_nand_info *info) +static void handle_data_pio(struct pxa3xx_nand_info *info) { - int ret, timeout = CHIP_DELAY_TIMEOUT; - switch (info->state) { case STATE_PIO_WRITING: __raw_writesl(info->mmio_base + NDDB, info->data_buff, @@ -413,14 +452,6 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) if (info->oob_size > 0) __raw_writesl(info->mmio_base + NDDB, info->oob_buff, DIV_ROUND_UP(info->oob_size, 4)); - - enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); - - ret = wait_for_completion_timeout(&info->cmd_complete, timeout); - if (!ret) { - printk(KERN_ERR "program command time out\n"); - return -1; - } break; case STATE_PIO_READING: __raw_readsl(info->mmio_base + NDDB, info->data_buff, @@ -432,14 +463,11 @@ static int handle_data_pio(struct pxa3xx_nand_info *info) default: printk(KERN_ERR "%s: invalid state %d\n", __func__, info->state); - return -EINVAL; + BUG(); } - - info->state = STATE_READY; - return 0; } -static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) +static void start_data_dma(struct pxa3xx_nand_info *info) { struct pxa_dma_desc *desc = info->data_desc; int dma_len = ALIGN(info->data_size + info->oob_size, 32); @@ -447,14 +475,21 @@ static void start_data_dma(struct pxa3xx_nand_info *info, int dir_out) desc->ddadr = DDADR_STOP; desc->dcmd = DCMD_ENDIRQEN | DCMD_WIDTH4 | DCMD_BURST32 | dma_len; - if (dir_out) { + switch (info->state) { + case STATE_DMA_WRITING: desc->dsadr = info->data_buff_phys; desc->dtadr = info->mmio_phys + NDDB; desc->dcmd |= DCMD_INCSRCADDR | DCMD_FLOWTRG; - } else { + break; + case STATE_DMA_READING: desc->dtadr = info->data_buff_phys; desc->dsadr = info->mmio_phys + NDDB; desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; + break; + default: + printk(KERN_ERR "%s: invalid state %d\n", __func__, + info->state); + BUG(); } DRCMR(info->drcmr_dat) = DRCMR_MAPVLD | info->data_dma_ch; @@ -472,93 +507,60 @@ static void pxa3xx_nand_data_dma_irq(int channel, void *data) if (dcsr & DCSR_BUSERR) { info->retcode = ERR_DMABUSERR; - complete(&info->cmd_complete); } - if (info->state == STATE_DMA_WRITING) { - info->state = STATE_DMA_DONE; - enable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); - } else { - info->state = STATE_READY; - complete(&info->cmd_complete); - } + info->state = STATE_DMA_DONE; + enable_int(info, NDCR_INT_MASK); + nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); } static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; - unsigned int status; + unsigned int status, is_completed = 0; status = nand_readl(info, NDSR); - if (status & (NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR)) { - if (status & NDSR_DBERR) - info->retcode = ERR_DBERR; - else if (status & NDSR_SBERR) - info->retcode = ERR_SBERR; - - disable_int(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); - - if (info->use_dma) { - info->state = STATE_DMA_READING; - start_data_dma(info, 0); - } else { - info->state = STATE_PIO_READING; - complete(&info->cmd_complete); - } - } else if (status & NDSR_WRDREQ) { - disable_int(info, NDSR_WRDREQ); + if (status & NDSR_DBERR) + info->retcode = ERR_DBERR; + if (status & NDSR_SBERR) + info->retcode = ERR_SBERR; + if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) { + /* whether use dma to transfer data */ if (info->use_dma) { - info->state = STATE_DMA_WRITING; - start_data_dma(info, 1); + disable_int(info, NDCR_INT_MASK); + info->state = (status & NDSR_RDDREQ) ? + STATE_DMA_READING : STATE_DMA_WRITING; + start_data_dma(info); + goto NORMAL_IRQ_EXIT; } else { - info->state = STATE_PIO_WRITING; - complete(&info->cmd_complete); + info->state = (status & NDSR_RDDREQ) ? + STATE_PIO_READING : STATE_PIO_WRITING; + handle_data_pio(info); } - } else if (status & (NDSR_CS0_BBD | NDSR_CS0_CMDD)) { - if (status & NDSR_CS0_BBD) - info->retcode = ERR_BBERR; - - disable_int(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); - info->state = STATE_READY; - complete(&info->cmd_complete); } - nand_writel(info, NDSR, status); - return IRQ_HANDLED; -} - -static int pxa3xx_nand_do_cmd(struct pxa3xx_nand_info *info, uint32_t event) -{ - uint32_t ndcr; - int ret, timeout = CHIP_DELAY_TIMEOUT; - - if (write_cmd(info)) { - info->retcode = ERR_SENDCMD; - goto fail_stop; + if (status & NDSR_CS0_CMDD) { + info->state = STATE_CMD_DONE; + is_completed = 1; } + if (status & NDSR_FLASH_RDY) + info->state = STATE_READY; - info->state = STATE_CMD_HANDLE; - - enable_int(info, event); - - ret = wait_for_completion_timeout(&info->cmd_complete, timeout); - if (!ret) { - printk(KERN_ERR "command execution timed out\n"); - info->retcode = ERR_SENDCMD; - goto fail_stop; + if (status & NDSR_WRCMDREQ) { + nand_writel(info, NDSR, NDSR_WRCMDREQ); + status &= ~NDSR_WRCMDREQ; + info->state = STATE_CMD_HANDLE; + nand_writel(info, NDCB0, info->ndcb0); + nand_writel(info, NDCB0, info->ndcb1); + nand_writel(info, NDCB0, info->ndcb2); } - if (info->use_dma == 0 && info->data_size > 0) - if (handle_data_pio(info)) - goto fail_stop; - - return 0; - -fail_stop: - ndcr = nand_readl(info, NDCR); - nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); - udelay(10); - return -ETIMEDOUT; + /* clear NDSR to let the controller exit the IRQ */ + nand_writel(info, NDSR, status); + if (is_completed) + complete(&info->cmd_complete); +NORMAL_IRQ_EXIT: + return IRQ_HANDLED; } static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) @@ -580,14 +582,13 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, { struct pxa3xx_nand_info *info = mtd->priv; const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; - int ret; + int ret, exec_cmd = 0; info->use_dma = (use_dma) ? 1 : 0; info->use_ecc = 0; info->data_size = 0; - info->state = STATE_READY; - - init_completion(&info->cmd_complete); + info->state = 0; + info->retcode = ERR_NONE; switch (command) { case NAND_CMD_READOOB: @@ -596,36 +597,18 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->buf_start = mtd->writesize + column; memset(info->data_buff, 0xFF, info->buf_count); - if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) - break; - - pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); - - /* We only are OOB, so if the data has error, does not matter */ - if (info->retcode == ERR_DBERR) - info->retcode = ERR_NONE; + prepare_read_prog_cmd(info, cmdset->read1, column, page_addr); + exec_cmd = 1; break; case NAND_CMD_READ0: info->use_ecc = 1; - info->retcode = ERR_NONE; info->buf_start = column; info->buf_count = mtd->writesize + mtd->oobsize; memset(info->data_buff, 0xFF, info->buf_count); - if (prepare_read_prog_cmd(info, cmdset->read1, column, page_addr)) - break; - - pxa3xx_nand_do_cmd(info, NDSR_RDDREQ | NDSR_DBERR | NDSR_SBERR); - - if (info->retcode == ERR_DBERR) { - /* for blank page (all 0xff), HW will calculate its ECC as - * 0, which is different from the ECC information within - * OOB, ignore such double bit errors - */ - if (is_buf_blank(info->data_buff, mtd->writesize)) - info->retcode = ERR_NONE; - } + prepare_read_prog_cmd(info, cmdset->read1, column, page_addr); + exec_cmd = 1; break; case NAND_CMD_SEQIN: info->buf_start = column; @@ -639,17 +622,13 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, case NAND_CMD_PAGEPROG: info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1; - if (prepare_read_prog_cmd(info, cmdset->program, - info->seqin_column, info->seqin_page_addr)) - break; - - pxa3xx_nand_do_cmd(info, NDSR_WRDREQ); + prepare_read_prog_cmd(info, cmdset->program, + info->seqin_column, info->seqin_page_addr); + exec_cmd = 1; break; case NAND_CMD_ERASE1: - if (prepare_erase_cmd(info, cmdset->erase, page_addr)) - break; - - pxa3xx_nand_do_cmd(info, NDSR_CS0_BBD | NDSR_CS0_CMDD); + prepare_erase_cmd(info, cmdset->erase, page_addr); + exec_cmd = 1; break; case NAND_CMD_ERASE2: break; @@ -660,40 +639,69 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->buf_count = (command == NAND_CMD_READID) ? info->read_id_bytes : 1; - if (prepare_other_cmd(info, (command == NAND_CMD_READID) ? - cmdset->read_id : cmdset->read_status)) - break; - - pxa3xx_nand_do_cmd(info, NDSR_RDDREQ); + prepare_other_cmd(info, (command == NAND_CMD_READID) ? + cmdset->read_id : cmdset->read_status); + exec_cmd = 1; break; case NAND_CMD_RESET: - if (prepare_other_cmd(info, cmdset->reset)) - break; - - ret = pxa3xx_nand_do_cmd(info, NDSR_CS0_CMDD); - if (ret == 0) { - int timeout = 2; - uint32_t ndcr; - - while (timeout--) { - if (nand_readl(info, NDSR) & NDSR_RDY) - break; - msleep(10); - } - - ndcr = nand_readl(info, NDCR); - nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); - } + prepare_other_cmd(info, cmdset->reset); + exec_cmd = 1; break; default: printk(KERN_ERR "non-supported command.\n"); break; } - if (info->retcode == ERR_DBERR) { - printk(KERN_ERR "double bit error @ page %08x\n", page_addr); - info->retcode = ERR_NONE; + if (exec_cmd) { + init_completion(&info->cmd_complete); + pxa3xx_nand_start(info); + + ret = wait_for_completion_timeout(&info->cmd_complete, + CHIP_DELAY_TIMEOUT); + if (!ret) { + printk(KERN_ERR "Wait time out!!!\n"); + /* Stop State Machine for next command cycle */ + pxa3xx_nand_stop(info); + } + info->state = STATE_IDLE; + } +} + +static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + chip->write_buf(mtd, buf, mtd->writesize); + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +} + +static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf, int page) +{ + struct pxa3xx_nand_info *info = mtd->priv; + + chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + if (info->retcode == ERR_SBERR) { + switch (info->use_ecc) { + case 1: + mtd->ecc_stats.corrected++; + break; + case 0: + default: + break; + } + } else if (info->retcode == ERR_DBERR) { + /* + * for blank page (all 0xff), HW will calculate its ECC as + * 0, which is different from the ECC information within + * OOB, ignore such double bit errors + */ + if (is_buf_blank(buf, mtd->writesize)) + mtd->ecc_stats.failed++; } + + return 0; } static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) @@ -770,47 +778,13 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) return 0; } -static void pxa3xx_nand_ecc_hwctl(struct mtd_info *mtd, int mode) -{ - return; -} - -static int pxa3xx_nand_ecc_calculate(struct mtd_info *mtd, - const uint8_t *dat, uint8_t *ecc_code) -{ - return 0; -} - -static int pxa3xx_nand_ecc_correct(struct mtd_info *mtd, - uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) -{ - struct pxa3xx_nand_info *info = mtd->priv; - /* - * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we - * consider it as a ecc error which will tell the caller the - * read fail We have distinguish all the errors, but the - * nand_read_ecc only check this function return value - * - * Corrected (single-bit) errors must also be noted. - */ - if (info->retcode == ERR_SBERR) - return 1; - else if (info->retcode != ERR_NONE) - return -1; - - return 0; -} - static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) { const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; uint32_t ndcr; uint8_t id_buff[8]; - if (prepare_other_cmd(info, cmdset->read_id)) { - printk(KERN_ERR "failed to prepare command\n"); - return -EINVAL; - } + prepare_other_cmd(info, cmdset->read_id); /* Send command */ if (write_cmd(info)) @@ -836,7 +810,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, { struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; - uint32_t ndcr = 0x00000FFF; /* disable all interrupts */ + uint32_t ndcr = 0x0; /* enable all interrupts */ if (f->page_size != 2048 && f->page_size != 512) return -EINVAL; @@ -888,11 +862,12 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) info->reg_ndcr = ndcr; info->cmdset = &default_cmdset; - if (__readid(info, &id)) + pxa3xx_nand_cmdfunc(info->mtd, NAND_CMD_READID, 0, 0); + id = *((uint16_t *)(info->data_buff)); + if (id == 0) return -ENODEV; /* Lookup the flash id */ - id = (id >> 8) & 0xff; /* device id is byte 2 */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (id == nand_flash_ids[i].id) { type = &nand_flash_ids[i]; @@ -935,8 +910,8 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, /* we use default timing to detect id */ f = DEFAULT_FLASH_TYPE; pxa3xx_nand_config_flash(info, f); - if (__readid(info, &id)) - goto fail_detect; + pxa3xx_nand_cmdfunc(info->mtd, NAND_CMD_READID, 0, 0); + id = *((uint16_t *)(info->data_buff)); for (i=0; inum_flash - 1; i++) { /* we first choose the flash definition from platfrom */ @@ -954,7 +929,6 @@ static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, dev_warn(&info->pdev->dev, "failed to detect configured nand flash; found %04x instead of\n", id); -fail_detect: return -ENODEV; } @@ -1025,6 +999,8 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, this->select_chip = pxa3xx_nand_select_chip; this->dev_ready = pxa3xx_nand_dev_ready; this->cmdfunc = pxa3xx_nand_cmdfunc; + this->ecc.read_page = pxa3xx_nand_read_page_hwecc; + this->ecc.write_page = pxa3xx_nand_write_page_hwecc; this->read_word = pxa3xx_nand_read_word; this->read_byte = pxa3xx_nand_read_byte; this->read_buf = pxa3xx_nand_read_buf; @@ -1032,9 +1008,6 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, this->verify_buf = pxa3xx_nand_verify_buf; this->ecc.mode = NAND_ECC_HW; - this->ecc.hwctl = pxa3xx_nand_ecc_hwctl; - this->ecc.calculate = pxa3xx_nand_ecc_calculate; - this->ecc.correct = pxa3xx_nand_ecc_correct; this->ecc.size = info->page_size; if (info->page_size == 2048) @@ -1177,10 +1150,6 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - del_mtd_device(mtd); -#ifdef CONFIG_MTD_PARTITIONS - del_mtd_partitions(mtd); -#endif irq = platform_get_irq(pdev, 0); if (irq >= 0) free_irq(irq, info); @@ -1198,7 +1167,13 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) clk_disable(info->clk); clk_put(info->clk); - kfree(mtd); + if (mtd) { + del_mtd_device(mtd); +#ifdef CONFIG_MTD_PARTITIONS + del_mtd_partitions(mtd); +#endif + kfree(mtd); + } return 0; } @@ -1232,10 +1207,10 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); if (nr_parts) - return add_mtd_partitions(mtd, parts, nr_parts); + return add_mtd_partitions(info->mtd, parts, nr_parts); } - return add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts); + return add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts); #else return 0; #endif @@ -1247,7 +1222,7 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); struct mtd_info *mtd = info->mtd; - if (info->state != STATE_READY) { + if (info->state) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); return -EAGAIN; } -- cgit v1.2.2 From 38caf7f68e6b4ad84094095887a490e3fa2ec501 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Mon, 28 Feb 2011 10:32:12 +0800 Subject: mtd: pxa3xx_nand: discard wait_for_event,write_cmd,__readid function Since we have rework the irq process, we don't need additional delay in wait_for_event. Also write_cmd and __readid is also discarded for the same reason. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang Acked-by: Eric Miao Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 77 +----------------------------------------- 1 file changed, 1 insertion(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 3264b1d5a638..be0aa44ada42 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -258,25 +258,6 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, nand_writel(info, NDTR1CS0, ndtr1); } -#define WAIT_EVENT_TIMEOUT 10 - -static int wait_for_event(struct pxa3xx_nand_info *info, uint32_t event) -{ - int timeout = WAIT_EVENT_TIMEOUT; - uint32_t ndsr; - - while (timeout--) { - ndsr = nand_readl(info, NDSR) & NDSR_MASK; - if (ndsr & event) { - nand_writel(info, NDSR, ndsr); - return 0; - } - udelay(10); - } - - return -ETIMEDOUT; -} - static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; @@ -414,35 +395,6 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) nand_writel(info, NDCR, ndcr | int_mask); } -/* NOTE: it is a must to set ND_RUN firstly, then write command buffer - * otherwise, it does not work - */ -static int write_cmd(struct pxa3xx_nand_info *info) -{ - uint32_t ndcr; - - /* clear status bits and run */ - nand_writel(info, NDSR, NDSR_MASK); - - ndcr = info->reg_ndcr; - - ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; - ndcr |= info->use_dma ? NDCR_DMA_EN : 0; - ndcr |= NDCR_ND_RUN; - - nand_writel(info, NDCR, ndcr); - - if (wait_for_event(info, NDSR_WRCMDREQ)) { - printk(KERN_ERR "timed out writing command\n"); - return -ETIMEDOUT; - } - - nand_writel(info, NDCB0, info->ndcb0); - nand_writel(info, NDCB0, info->ndcb1); - nand_writel(info, NDCB0, info->ndcb2); - return 0; -} - static void handle_data_pio(struct pxa3xx_nand_info *info) { switch (info->state) { @@ -778,33 +730,6 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) return 0; } -static int __readid(struct pxa3xx_nand_info *info, uint32_t *id) -{ - const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; - uint32_t ndcr; - uint8_t id_buff[8]; - - prepare_other_cmd(info, cmdset->read_id); - - /* Send command */ - if (write_cmd(info)) - goto fail_timeout; - - /* Wait for CMDDM(command done successfully) */ - if (wait_for_event(info, NDSR_RDDREQ)) - goto fail_timeout; - - __raw_readsl(info->mmio_base + NDDB, id_buff, 2); - *id = id_buff[0] | (id_buff[1] << 8); - return 0; - -fail_timeout: - ndcr = nand_readl(info, NDCR); - nand_writel(info, NDCR, ndcr & ~NDCR_ND_RUN); - udelay(10); - return -ETIMEDOUT; -} - static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, const struct pxa3xx_nand_flash *f) { @@ -857,7 +782,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - /* set info fields needed to __readid */ + /* set info fields needed to read id */ info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; info->reg_ndcr = ndcr; info->cmdset = &default_cmdset; -- cgit v1.2.2 From 4eb2da8994042d68e84e31138788429a102da2ea Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Mon, 28 Feb 2011 10:32:13 +0800 Subject: mtd: pxa3xx_nand: unify prepare command Make the interface simpler which could make both debug and enhancement easier. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 249 +++++++++++++++++++++++------------------ 1 file changed, 139 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index be0aa44ada42..de0a2a25eb01 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -28,6 +28,7 @@ #define CHIP_DELAY_TIMEOUT (2 * HZ/10) #define NAND_STOP_DELAY (2 * HZ/50) +#define PAGE_CHUNK_SIZE (2048) /* registers and bit definitions */ #define NDCR (0x00) /* Control register */ @@ -77,6 +78,7 @@ #define NDSR_RDDREQ (0x1 << 1) #define NDSR_WRCMDREQ (0x1) +#define NDCB0_ST_ROW_EN (0x1 << 26) #define NDCB0_AUTO_RS (0x1 << 25) #define NDCB0_CSEL (0x1 << 24) #define NDCB0_CMD_TYPE_MASK (0x7 << 21) @@ -319,66 +321,6 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info) nand_writel(info, NDSR, NDSR_MASK); } -static void prepare_read_prog_cmd(struct pxa3xx_nand_info *info, - uint16_t cmd, int column, int page_addr) -{ - const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; - pxa3xx_set_datasize(info); - - /* generate values for NDCBx registers */ - info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); - info->ndcb1 = 0; - info->ndcb2 = 0; - info->ndcb0 |= NDCB0_ADDR_CYC(info->row_addr_cycles + info->col_addr_cycles); - - if (info->col_addr_cycles == 2) { - /* large block, 2 cycles for column address - * row address starts from 3rd cycle - */ - info->ndcb1 |= page_addr << 16; - if (info->row_addr_cycles == 3) - info->ndcb2 = (page_addr >> 16) & 0xff; - } else - /* small block, 1 cycles for column address - * row address starts from 2nd cycle - */ - info->ndcb1 = page_addr << 8; - - if (cmd == cmdset->program) - info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; -} - -static void prepare_erase_cmd(struct pxa3xx_nand_info *info, - uint16_t cmd, int page_addr) -{ - info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); - info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3); - info->ndcb1 = page_addr; - info->ndcb2 = 0; -} - -static void prepare_other_cmd(struct pxa3xx_nand_info *info, uint16_t cmd) -{ - const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; - - info->ndcb0 = cmd | ((cmd & 0xff00) ? NDCB0_DBC : 0); - info->ndcb1 = 0; - info->ndcb2 = 0; - - info->oob_size = 0; - if (cmd == cmdset->read_id) { - info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1); - info->data_size = 8; - } else if (cmd == cmdset->read_status) { - info->ndcb0 |= NDCB0_CMD_TYPE(4); - info->data_size = 8; - } else if (cmd == cmdset->reset || cmd == cmdset->lock || - cmd == cmdset->unlock) { - info->ndcb0 |= NDCB0_CMD_TYPE(5); - } else - BUG(); -} - static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask) { uint32_t ndcr; @@ -529,81 +471,167 @@ static inline int is_buf_blank(uint8_t *buf, size_t len) return 1; } -static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, - int column, int page_addr) +static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, + uint16_t column, int page_addr) { - struct pxa3xx_nand_info *info = mtd->priv; - const struct pxa3xx_nand_cmdset *cmdset = info->cmdset; - int ret, exec_cmd = 0; + uint16_t cmd; + int addr_cycle, exec_cmd, ndcb0; + struct mtd_info *mtd = info->mtd; + + ndcb0 = 0; + addr_cycle = 0; + exec_cmd = 1; - info->use_dma = (use_dma) ? 1 : 0; - info->use_ecc = 0; - info->data_size = 0; - info->state = 0; - info->retcode = ERR_NONE; + /* reset data and oob column point to handle data */ + info->buf_start = 0; + info->buf_count = 0; + info->oob_size = 0; + info->use_ecc = 0; + info->retcode = ERR_NONE; switch (command) { + case NAND_CMD_READ0: + case NAND_CMD_PAGEPROG: + info->use_ecc = 1; case NAND_CMD_READOOB: - /* disable HW ECC to get all the OOB data */ - info->buf_count = mtd->writesize + mtd->oobsize; - info->buf_start = mtd->writesize + column; - memset(info->data_buff, 0xFF, info->buf_count); - - prepare_read_prog_cmd(info, cmdset->read1, column, page_addr); - exec_cmd = 1; + pxa3xx_set_datasize(info); + break; + case NAND_CMD_SEQIN: + exec_cmd = 0; + break; + default: + info->ndcb1 = 0; + info->ndcb2 = 0; break; + } + + info->ndcb0 = ndcb0; + addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles + + info->col_addr_cycles); + switch (command) { + case NAND_CMD_READOOB: case NAND_CMD_READ0: - info->use_ecc = 1; - info->buf_start = column; - info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xFF, info->buf_count); + cmd = info->cmdset->read1; + if (command == NAND_CMD_READOOB) + info->buf_start = mtd->writesize + column; + else + info->buf_start = column; + + if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | addr_cycle + | (cmd & NDCB0_CMD1_MASK); + else + info->ndcb0 |= NDCB0_CMD_TYPE(0) + | NDCB0_DBC + | addr_cycle + | cmd; - prepare_read_prog_cmd(info, cmdset->read1, column, page_addr); - exec_cmd = 1; - break; case NAND_CMD_SEQIN: - info->buf_start = column; + /* small page addr setting */ + if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { + info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) + | (column & 0xFF); + + info->ndcb2 = 0; + } else { + info->ndcb1 = ((page_addr & 0xFFFF) << 16) + | (column & 0xFFFF); + + if (page_addr & 0xFF0000) + info->ndcb2 = (page_addr & 0xFF0000) >> 16; + else + info->ndcb2 = 0; + } + info->buf_count = mtd->writesize + mtd->oobsize; - memset(info->data_buff, 0xff, info->buf_count); + memset(info->data_buff, 0xFF, info->buf_count); - /* save column/page_addr for next CMD_PAGEPROG */ - info->seqin_column = column; - info->seqin_page_addr = page_addr; break; + case NAND_CMD_PAGEPROG: - info->use_ecc = (info->seqin_column >= mtd->writesize) ? 0 : 1; + if (is_buf_blank(info->data_buff, + (mtd->writesize + mtd->oobsize))) { + exec_cmd = 0; + break; + } - prepare_read_prog_cmd(info, cmdset->program, - info->seqin_column, info->seqin_page_addr); - exec_cmd = 1; - break; - case NAND_CMD_ERASE1: - prepare_erase_cmd(info, cmdset->erase, page_addr); - exec_cmd = 1; - break; - case NAND_CMD_ERASE2: + cmd = info->cmdset->program; + info->ndcb0 |= NDCB0_CMD_TYPE(0x1) + | NDCB0_AUTO_RS + | NDCB0_ST_ROW_EN + | NDCB0_DBC + | cmd + | addr_cycle; break; + case NAND_CMD_READID: + cmd = info->cmdset->read_id; + info->buf_count = info->read_id_bytes; + info->ndcb0 |= NDCB0_CMD_TYPE(3) + | NDCB0_ADDR_CYC(1) + | cmd; + + info->data_size = 8; + break; case NAND_CMD_STATUS: - info->use_dma = 0; /* force PIO read */ - info->buf_start = 0; - info->buf_count = (command == NAND_CMD_READID) ? - info->read_id_bytes : 1; - - prepare_other_cmd(info, (command == NAND_CMD_READID) ? - cmdset->read_id : cmdset->read_status); - exec_cmd = 1; + cmd = info->cmdset->read_status; + info->buf_count = 1; + info->ndcb0 |= NDCB0_CMD_TYPE(4) + | NDCB0_ADDR_CYC(1) + | cmd; + + info->data_size = 8; + break; + + case NAND_CMD_ERASE1: + cmd = info->cmdset->erase; + info->ndcb0 |= NDCB0_CMD_TYPE(2) + | NDCB0_AUTO_RS + | NDCB0_ADDR_CYC(3) + | NDCB0_DBC + | cmd; + info->ndcb1 = page_addr; + info->ndcb2 = 0; + break; case NAND_CMD_RESET: - prepare_other_cmd(info, cmdset->reset); - exec_cmd = 1; + cmd = info->cmdset->reset; + info->ndcb0 |= NDCB0_CMD_TYPE(5) + | cmd; + + break; + + case NAND_CMD_ERASE2: + exec_cmd = 0; break; + default: - printk(KERN_ERR "non-supported command.\n"); + exec_cmd = 0; + printk(KERN_ERR "pxa3xx-nand: non-supported" + " command %x\n", command); break; } + return exec_cmd; +} + +static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + struct pxa3xx_nand_info *info = mtd->priv; + int ret, exec_cmd; + + /* + * if this is a x16 device ,then convert the input + * "byte" address into a "word" address appropriate + * for indexing a word-oriented device + */ + if (info->reg_ndcr & NDCR_DWIDTH_M) + column /= 2; + + exec_cmd = prepare_command_pool(info, command, column, page_addr); if (exec_cmd) { init_completion(&info->cmd_complete); pxa3xx_nand_start(info); @@ -919,6 +947,7 @@ static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, struct nand_chip *this = &info->nand_chip; this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0; + this->options |= NAND_NO_AUTOINCR; this->waitfunc = pxa3xx_nand_waitfunc; this->select_chip = pxa3xx_nand_select_chip; -- cgit v1.2.2 From 401e67e225f350757e11e39392dcc6a0fddcea63 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Mon, 28 Feb 2011 10:32:14 +0800 Subject: mtd: pxa3xx_nand: mtd scan id process could be defined by driver itself Different NAND driver may require its unique detection. For pxa3xx_nand, it use its self id database to get the necessary info. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 216 +++++++++++++++++++++++------------------ 1 file changed, 123 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index de0a2a25eb01..bb50cf2b11c4 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -123,6 +123,7 @@ enum { struct pxa3xx_nand_info { struct nand_chip nand_chip; + struct nand_hw_control controller; struct platform_device *pdev; struct pxa3xx_nand_cmdset *cmdset; @@ -157,6 +158,7 @@ struct pxa3xx_nand_info { int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ + int is_ready; unsigned int page_size; /* page size of attached chip */ unsigned int data_size; /* data size in FIFO */ @@ -223,6 +225,8 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) +const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; + #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) #define NDTR0_tWH(c) (min((c), 7) << 11) @@ -437,8 +441,10 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) info->state = STATE_CMD_DONE; is_completed = 1; } - if (status & NDSR_FLASH_RDY) + if (status & NDSR_FLASH_RDY) { + info->is_ready = 1; info->state = STATE_READY; + } if (status & NDSR_WRCMDREQ) { nand_writel(info, NDSR, NDSR_WRCMDREQ); @@ -483,10 +489,11 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, exec_cmd = 1; /* reset data and oob column point to handle data */ - info->buf_start = 0; - info->buf_count = 0; + info->buf_start = 0; + info->buf_count = 0; info->oob_size = 0; info->use_ecc = 0; + info->is_ready = 0; info->retcode = ERR_NONE; switch (command) { @@ -849,42 +856,6 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) return 0; } -static int pxa3xx_nand_detect_flash(struct pxa3xx_nand_info *info, - const struct pxa3xx_nand_platform_data *pdata) -{ - const struct pxa3xx_nand_flash *f; - uint32_t id = -1; - int i; - - if (pdata->keep_config) - if (pxa3xx_nand_detect_config(info) == 0) - return 0; - - /* we use default timing to detect id */ - f = DEFAULT_FLASH_TYPE; - pxa3xx_nand_config_flash(info, f); - pxa3xx_nand_cmdfunc(info->mtd, NAND_CMD_READID, 0, 0); - id = *((uint16_t *)(info->data_buff)); - - for (i=0; inum_flash - 1; i++) { - /* we first choose the flash definition from platfrom */ - if (i < pdata->num_flash) - f = pdata->flash + i; - else - f = &builtin_flash_types[i - pdata->num_flash + 1]; - if (f->chip_id == id) { - dev_info(&info->pdev->dev, "detect chip id: 0x%x\n", id); - pxa3xx_nand_config_flash(info, f); - return 0; - } - } - - dev_warn(&info->pdev->dev, - "failed to detect configured nand flash; found %04x instead of\n", - id); - return -ENODEV; -} - /* the maximum possible buffer size for large page with OOB data * is: 2048 + 64 = 2112 bytes, allocate a page here for both the * data buffer and the DMA descriptor @@ -926,57 +897,110 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) return 0; } -static struct nand_ecclayout hw_smallpage_ecclayout = { - .eccbytes = 6, - .eccpos = {8, 9, 10, 11, 12, 13 }, - .oobfree = { {2, 6} } -}; +static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) +{ + struct mtd_info *mtd = info->mtd; + struct nand_chip *chip = mtd->priv; -static struct nand_ecclayout hw_largepage_ecclayout = { - .eccbytes = 24, - .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { {2, 38} } -}; + /* use the common timing to make a try */ + pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); + chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); + if (info->is_ready) + return 1; + else + return 0; +} -static void pxa3xx_nand_init_mtd(struct mtd_info *mtd, - struct pxa3xx_nand_info *info) +static int pxa3xx_nand_scan(struct mtd_info *mtd) { - struct nand_chip *this = &info->nand_chip; - - this->options = (info->reg_ndcr & NDCR_DWIDTH_C) ? NAND_BUSWIDTH_16: 0; - this->options |= NAND_NO_AUTOINCR; - - this->waitfunc = pxa3xx_nand_waitfunc; - this->select_chip = pxa3xx_nand_select_chip; - this->dev_ready = pxa3xx_nand_dev_ready; - this->cmdfunc = pxa3xx_nand_cmdfunc; - this->ecc.read_page = pxa3xx_nand_read_page_hwecc; - this->ecc.write_page = pxa3xx_nand_write_page_hwecc; - this->read_word = pxa3xx_nand_read_word; - this->read_byte = pxa3xx_nand_read_byte; - this->read_buf = pxa3xx_nand_read_buf; - this->write_buf = pxa3xx_nand_write_buf; - this->verify_buf = pxa3xx_nand_verify_buf; - - this->ecc.mode = NAND_ECC_HW; - this->ecc.size = info->page_size; - - if (info->page_size == 2048) - this->ecc.layout = &hw_largepage_ecclayout; - else - this->ecc.layout = &hw_smallpage_ecclayout; + struct pxa3xx_nand_info *info = mtd->priv; + struct platform_device *pdev = info->pdev; + struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; + const struct pxa3xx_nand_flash *f = NULL; + struct nand_chip *chip = mtd->priv; + uint32_t id = -1; + int i, ret, num; + + if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) + return 0; + + ret = pxa3xx_nand_sensing(info); + if (!ret) { + kfree(mtd); + info->mtd = NULL; + printk(KERN_INFO "There is no nand chip on cs 0!\n"); + + return -EINVAL; + } + + chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); + id = *((uint16_t *)(info->data_buff)); + if (id != 0) + printk(KERN_INFO "Detect a flash id %x\n", id); + else { + kfree(mtd); + info->mtd = NULL; + printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); + + return -EINVAL; + } + + num = ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1; + for (i = 0; i < num; i++) { + if (i < pdata->num_flash) + f = pdata->flash + i; + else + f = &builtin_flash_types[i - pdata->num_flash + 1]; + + /* find the chip in default list */ + if (f->chip_id == id) { + pxa3xx_nand_config_flash(info, f); + mtd->writesize = f->page_size; + mtd->writesize_shift = ffs(mtd->writesize) - 1; + mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; + mtd->oobsize = mtd->writesize / 32; + mtd->erasesize = f->page_size * f->page_per_block; + mtd->erasesize_shift = ffs(mtd->erasesize) - 1; + mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; + + mtd->name = mtd_names[0]; + break; + } + } + + if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash)) { + kfree(mtd); + info->mtd = NULL; + printk(KERN_ERR "ERROR!! flash not defined!!!\n"); + + return -EINVAL; + } + + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = f->page_size; + chip->chipsize = (uint64_t)f->num_blocks * f->page_per_block + * f->page_size; + mtd->size = chip->chipsize; + + /* Calculate the address shift from the page size */ + chip->page_shift = ffs(mtd->writesize) - 1; + chip->pagemask = mtd_div_by_ws(chip->chipsize, mtd) - 1; + chip->numchips = 1; + chip->phys_erase_shift = ffs(mtd->erasesize) - 1; + chip->bbt_erase_shift = chip->phys_erase_shift; + + chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; + chip->options |= NAND_NO_AUTOINCR; + chip->options |= NAND_NO_READRDY; - this->chip_delay = 25; + return nand_scan_tail(mtd); } static struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) { - struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; struct pxa3xx_nand_info *info; + struct nand_chip *chip; struct mtd_info *mtd; struct resource *r; int ret, irq; @@ -989,12 +1013,27 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) } info = (struct pxa3xx_nand_info *)(&mtd[1]); + chip = (struct nand_chip *)(&mtd[1]); info->pdev = pdev; - - mtd->priv = info; info->mtd = mtd; + mtd->priv = info; mtd->owner = THIS_MODULE; + chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; + chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; + chip->controller = &info->controller; + chip->waitfunc = pxa3xx_nand_waitfunc; + chip->select_chip = pxa3xx_nand_select_chip; + chip->dev_ready = pxa3xx_nand_dev_ready; + chip->cmdfunc = pxa3xx_nand_cmdfunc; + chip->read_word = pxa3xx_nand_read_word; + chip->read_byte = pxa3xx_nand_read_byte; + chip->read_buf = pxa3xx_nand_read_buf; + chip->write_buf = pxa3xx_nand_write_buf; + chip->verify_buf = pxa3xx_nand_verify_buf; + + spin_lock_init(&chip->controller->lock); + init_waitqueue_head(&chip->controller->wq); info->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed to get nand clock\n"); @@ -1062,21 +1101,12 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) goto fail_free_buf; } - ret = pxa3xx_nand_detect_flash(info, pdata); - if (ret) { - dev_err(&pdev->dev, "failed to detect flash\n"); - ret = -ENODEV; - goto fail_free_irq; - } - - pxa3xx_nand_init_mtd(mtd, info); platform_set_drvdata(pdev, info); return info; -fail_free_irq: - free_irq(irq, info); fail_free_buf: + free_irq(irq, info); if (use_dma) { pxa_free_dma(info->data_dma_ch); dma_free_coherent(&pdev->dev, info->data_buff_size, @@ -1146,7 +1176,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) if (info == NULL) return -ENOMEM; - if (nand_scan(info->mtd, 1)) { + if (pxa3xx_nand_scan(info->mtd)) { dev_err(&pdev->dev, "failed to scan nand\n"); pxa3xx_nand_remove(pdev); return -ENODEV; -- cgit v1.2.2 From 4332c116869ceca58638beabd9e9a5d7db4cef83 Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Thu, 3 Mar 2011 11:27:01 +0800 Subject: mtd: pxa3xx_nand: clean the keep configure code Use nand_scan_ident to unify the need of mtd member initilization for both normal detection and keep configuration method. Signed-off-by: Lei Wen Signed-off-by: Haojian Zhuang Signed-off-by: David Woodhouse --- drivers/mtd/nand/pxa3xx_nand.c | 103 ++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index bb50cf2b11c4..ab7f4c33ced6 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -211,15 +211,15 @@ static struct pxa3xx_nand_timing timing[] = { }; static struct pxa3xx_nand_flash builtin_flash_types[] = { - { 0, 0, 2048, 8, 8, 0, &default_cmdset, &timing[0] }, - { 0x46ec, 32, 512, 16, 16, 4096, &default_cmdset, &timing[1] }, - { 0xdaec, 64, 2048, 8, 8, 2048, &default_cmdset, &timing[1] }, - { 0xd7ec, 128, 4096, 8, 8, 8192, &default_cmdset, &timing[1] }, - { 0xa12c, 64, 2048, 8, 8, 1024, &default_cmdset, &timing[2] }, - { 0xb12c, 64, 2048, 16, 16, 1024, &default_cmdset, &timing[2] }, - { 0xdc2c, 64, 2048, 8, 8, 4096, &default_cmdset, &timing[2] }, - { 0xcc2c, 64, 2048, 16, 16, 4096, &default_cmdset, &timing[2] }, - { 0xba20, 64, 2048, 16, 16, 2048, &default_cmdset, &timing[3] }, +{ "DEFAULT FLASH", 0, 0, 2048, 8, 8, 0, &timing[0] }, +{ "64MiB 16-bit", 0x46ec, 32, 512, 16, 16, 4096, &timing[1] }, +{ "256MiB 8-bit", 0xdaec, 64, 2048, 8, 8, 2048, &timing[1] }, +{ "4GiB 8-bit", 0xd7ec, 128, 4096, 8, 8, 8192, &timing[1] }, +{ "128MiB 8-bit", 0xa12c, 64, 2048, 8, 8, 1024, &timing[2] }, +{ "128MiB 16-bit", 0xb12c, 64, 2048, 16, 16, 1024, &timing[2] }, +{ "512MiB 8-bit", 0xdc2c, 64, 2048, 8, 8, 4096, &timing[2] }, +{ "512MiB 16-bit", 0xcc2c, 64, 2048, 16, 16, 4096, &timing[2] }, +{ "256MiB 16-bit", 0xba20, 64, 2048, 16, 16, 2048, &timing[3] }, }; /* Define a default flash type setting serve as flash detecting only */ @@ -779,9 +779,8 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, return -EINVAL; /* calculate flash information */ - info->cmdset = f->cmdset; + info->cmdset = &default_cmdset; info->page_size = f->page_size; - info->oob_buff = info->data_buff + f->page_size; info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ @@ -811,45 +810,12 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { uint32_t ndcr = nand_readl(info, NDCR); - struct nand_flash_dev *type = NULL; - uint32_t id = -1, page_per_block, num_blocks; - int i; - - page_per_block = ndcr & NDCR_PG_PER_BLK ? 64 : 32; info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; /* set info fields needed to read id */ info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; info->reg_ndcr = ndcr; info->cmdset = &default_cmdset; - pxa3xx_nand_cmdfunc(info->mtd, NAND_CMD_READID, 0, 0); - id = *((uint16_t *)(info->data_buff)); - if (id == 0) - return -ENODEV; - - /* Lookup the flash id */ - for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (id == nand_flash_ids[i].id) { - type = &nand_flash_ids[i]; - break; - } - } - - if (!type) - return -ENODEV; - - /* fill the missing flash information */ - i = __ffs(page_per_block * info->page_size); - num_blocks = type->chipsize << (20 - i); - - /* calculate addressing information */ - info->col_addr_cycles = (info->page_size == 2048) ? 2 : 1; - - if (num_blocks * page_per_block > 65536) - info->row_addr_cycles = 3; - else - info->row_addr_cycles = 2; - info->ndtr0cs0 = nand_readl(info, NDTR0CS0); info->ndtr1cs0 = nand_readl(info, NDTR1CS0); @@ -916,13 +882,15 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) struct pxa3xx_nand_info *info = mtd->priv; struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; + struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} }; const struct pxa3xx_nand_flash *f = NULL; struct nand_chip *chip = mtd->priv; uint32_t id = -1; + uint64_t chipsize; int i, ret, num; if (pdata->keep_config && !pxa3xx_nand_detect_config(info)) - return 0; + goto KEEP_CONFIG; ret = pxa3xx_nand_sensing(info); if (!ret) { @@ -953,22 +921,11 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) f = &builtin_flash_types[i - pdata->num_flash + 1]; /* find the chip in default list */ - if (f->chip_id == id) { - pxa3xx_nand_config_flash(info, f); - mtd->writesize = f->page_size; - mtd->writesize_shift = ffs(mtd->writesize) - 1; - mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; - mtd->oobsize = mtd->writesize / 32; - mtd->erasesize = f->page_size * f->page_per_block; - mtd->erasesize_shift = ffs(mtd->erasesize) - 1; - mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; - - mtd->name = mtd_names[0]; + if (f->chip_id == id) break; - } } - if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash)) { + if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { kfree(mtd); info->mtd = NULL; printk(KERN_ERR "ERROR!! flash not defined!!!\n"); @@ -976,18 +933,28 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) return -EINVAL; } + pxa3xx_nand_config_flash(info, f); + pxa3xx_flash_ids[0].name = f->name; + pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; + pxa3xx_flash_ids[0].pagesize = f->page_size; + chipsize = (uint64_t)f->num_blocks * f->page_per_block * f->page_size; + pxa3xx_flash_ids[0].chipsize = chipsize >> 20; + pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block; + if (f->flash_width == 16) + pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; +KEEP_CONFIG: + if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids)) + return -ENODEV; + /* calculate addressing information */ + info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; + info->oob_buff = info->data_buff + mtd->writesize; + if ((mtd->size >> chip->page_shift) > 65536) + info->row_addr_cycles = 3; + else + info->row_addr_cycles = 2; + mtd->name = mtd_names[0]; chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = f->page_size; - chip->chipsize = (uint64_t)f->num_blocks * f->page_per_block - * f->page_size; - mtd->size = chip->chipsize; - - /* Calculate the address shift from the page size */ - chip->page_shift = ffs(mtd->writesize) - 1; - chip->pagemask = mtd_div_by_ws(chip->chipsize, mtd) - 1; - chip->numchips = 1; - chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - chip->bbt_erase_shift = chip->phys_erase_shift; chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; chip->options |= NAND_NO_AUTOINCR; -- cgit v1.2.2 From f43272c482661bc88347bba237976eecfc1dbf5b Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Mon, 7 Mar 2011 13:50:44 -0500 Subject: mtd: DaVinci: Removed header file that is not required The DaVinci NAND driver was including the mach-types.h header file. This prevented the DaVinci NAND driver from getting used in a DSP only device. The linux port on c6x devices can make use of the same driver and does not define a corresponding header file. This header file was required in the driver because earlier there was code dependent on a machine_* check. This piece of code has now been factored out and is in arch/arm/mach-davinci/aemif.c Thus removing the header file is harmless Signed-off-by: Sandeep Paulraj Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/nand/davinci_nand.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index a90fde3ede28..aff3468867ac 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -37,9 +37,6 @@ #include #include -#include - - /* * This is a device driver for the NAND flash controller found on the * various DaVinci family chips. It handles up to four SoC chipselects, -- cgit v1.2.2 From 2c1c5f199482356c00f70b6f2f368c3455d1230c Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 9 Mar 2011 16:12:20 +0200 Subject: mtd: mxc_nand: fix OOB corruption when page size > 2KiB When page size is 4KiB, ecc.total is set to 8*9, and this causes nand_write_page_hwecc() to read past the initialized part of the eccpos array, which corrupts chip->oob_poi with bogus values from ecc_calc. Fix this by creating a proper nand_ecclayout for 4KiB flashes. Signed-off-by: Baruch Siach Acked-by: Sascha Hauer Signed-off-by: David Woodhouse --- drivers/mtd/nand/mxc_nand.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 6cd78ed439a7..b7d5a5b9a543 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -211,6 +211,31 @@ static struct nand_ecclayout nandv2_hw_eccoob_largepage = { } }; +/* OOB description for 4096 byte pages with 128 byte OOB */ +static struct nand_ecclayout nandv2_hw_eccoob_4k = { + .eccbytes = 8 * 9, + .eccpos = { + 7, 8, 9, 10, 11, 12, 13, 14, 15, + 23, 24, 25, 26, 27, 28, 29, 30, 31, + 39, 40, 41, 42, 43, 44, 45, 46, 47, + 55, 56, 57, 58, 59, 60, 61, 62, 63, + 71, 72, 73, 74, 75, 76, 77, 78, 79, + 87, 88, 89, 90, 91, 92, 93, 94, 95, + 103, 104, 105, 106, 107, 108, 109, 110, 111, + 119, 120, 121, 122, 123, 124, 125, 126, 127, + }, + .oobfree = { + {.offset = 2, .length = 4}, + {.offset = 16, .length = 7}, + {.offset = 32, .length = 7}, + {.offset = 48, .length = 7}, + {.offset = 64, .length = 7}, + {.offset = 80, .length = 7}, + {.offset = 96, .length = 7}, + {.offset = 112, .length = 7}, + } +}; + #ifdef CONFIG_MTD_PARTITIONS static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif @@ -1186,6 +1211,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) if (mtd->writesize == 2048) this->ecc.layout = oob_largepage; + if (nfc_is_v21() && mtd->writesize == 4096) + this->ecc.layout = &nandv2_hw_eccoob_4k; /* second phase scan */ if (nand_scan_tail(mtd)) { -- cgit v1.2.2 From 1065cda8a1a57d0d3bfccdce1a655a84439d24e0 Mon Sep 17 00:00:00 2001 From: Steffen Sledz Date: Thu, 10 Mar 2011 09:05:12 +0100 Subject: mtd: cfi: add support for AMIC flashes (e.g. A29L160AT) Signed-off-by: Steffen Sledz Signed-off-by: David Woodhouse --- drivers/mtd/chips/cfi_cmdset_0002.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 7e9c4e9c274a..f9a5331e9445 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -349,6 +349,7 @@ static struct cfi_fixup cfi_fixup_table[] = { { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri }, #ifdef AMD_BOOTLOC_BUG { CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock }, + { CFI_MFR_AMIC, CFI_ID_ANY, fixup_amd_bootblock }, { CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock }, #endif { CFI_MFR_AMD, 0x0050, fixup_use_secsi }, -- cgit v1.2.2 From 629286b9561982e90a6d49893a1c641e71b6a2a3 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Thu, 10 Mar 2011 22:31:39 +0800 Subject: mtd: sm_rtl: check kmalloc return value Because malloc/kzalloc may fail, we should check kmalloc/kzalloc return value in sm_create_sysfs_attributes(), mtd/sm_rtl.c and do error handling. Meanwhile, we should check sm_create_sysfs_attributes return value. Signed-off-by: Xiaochen Wang Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- drivers/mtd/sm_ftl.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 67822cf6c025..6405a95dc5bd 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -64,12 +64,16 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET); char *vendor = kmalloc(vendor_len, GFP_KERNEL); + if (!vendor) + goto error1; memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len); vendor[vendor_len] = 0; /* Initialize sysfs attributes */ vendor_attribute = kzalloc(sizeof(struct sm_sysfs_attribute), GFP_KERNEL); + if (!vendor_attribute) + goto error2; sysfs_attr_init(&vendor_attribute->dev_attr.attr); @@ -83,12 +87,24 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl) /* Create array of pointers to the attributes */ attributes = kzalloc(sizeof(struct attribute *) * (NUM_ATTRIBUTES + 1), GFP_KERNEL); + if (!attributes) + goto error3; attributes[0] = &vendor_attribute->dev_attr.attr; /* Finally create the attribute group */ attr_group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL); + if (!attr_group) + goto error4; attr_group->attrs = attributes; return attr_group; +error4: + kfree(attributes); +error3: + kfree(vendor_attribute); +error2: + kfree(vendor); +error1: + return NULL; } void sm_delete_sysfs_attributes(struct sm_ftl *ftl) @@ -1178,6 +1194,8 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) } ftl->disk_attributes = sm_create_sysfs_attributes(ftl); + if (!ftl->disk_attributes) + goto error6; trans->disk_attributes = ftl->disk_attributes; sm_printk("Found %d MiB xD/SmartMedia FTL on mtd%d", -- cgit v1.2.2 From 89d8d32060de17c23f761df74799c7c07b79dd01 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 11 Mar 2011 15:17:41 +0000 Subject: mtd: fix printf format warnings, mostly lack of %zd for size_t, in mtdswap Signed-off-by: David Woodhouse --- drivers/mtd/mtdswap.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 57e6cc30bc42..a65594fee4a3 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -331,7 +331,7 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from, if (ops->oobretlen < ops->ooblen) { dev_warn(d->dev, "Read OOB return short read (%zd bytes not " - "%d) for block at %08llx\n", + "%zd) for block at %08llx\n", ops->oobretlen, ops->ooblen, from); return -EIO; } @@ -421,7 +421,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, if (ops.oobretlen != ops.ooblen) { dev_warn(d->dev, "Short OOB write for block at %08llx: " - "%zd not %d\n", + "%zd not %zd\n", offset, ops.oobretlen, ops.ooblen); return ret; } @@ -705,13 +705,13 @@ retry: } if (ret < 0) { - dev_err(d->dev, "Write to MTD device failed: %d (%d written)", + dev_err(d->dev, "Write to MTD device failed: %d (%zd written)", ret, retlen); goto err; } if (retlen != PAGE_SIZE) { - dev_err(d->dev, "Short write to MTD device: %d written", + dev_err(d->dev, "Short write to MTD device: %zd written", retlen); ret = -EIO; goto err; @@ -758,7 +758,7 @@ retry: } if (retlen != PAGE_SIZE) { - dev_err(d->dev, "Short read: %d (block %u)\n", retlen, + dev_err(d->dev, "Short read: %zd (block %u)\n", retlen, oldblock); ret = -EIO; goto read_error; @@ -1188,7 +1188,7 @@ retry: } if (retlen != PAGE_SIZE) { - dev_err(d->dev, "Short read %d\n", retlen); + dev_err(d->dev, "Short read %zd\n", retlen); return -EIO; } @@ -1304,7 +1304,7 @@ static int mtdswap_show(struct seq_file *s, void *data) seq_printf(s, "discarded pages count: %llu\n", d->discard_page_count); seq_printf(s, "\n"); - seq_printf(s, "total pages: %lu\n", pages); + seq_printf(s, "total pages: %u\n", pages); seq_printf(s, "pages mapped: %u\n", mapped); return 0; @@ -1458,7 +1458,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) oinfo = mtd->ecclayout; if (!mtd->oobsize || !oinfo || oinfo->oobavail < MTDSWAP_OOBSIZE) { printk(KERN_ERR "%s: Not enough free bytes in OOB, " - "%d available, %u needed.\n", + "%d available, %lu needed.\n", MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE); return; } -- cgit v1.2.2 From 193bd40026443835e1b96c79d5efe559d01509ae Mon Sep 17 00:00:00 2001 From: Ivan Djelic Date: Fri, 11 Mar 2011 11:05:33 +0100 Subject: mtd: nand: add software BCH ECC support This patch adds software BCH ECC support to mtd, in order to handle recent NAND device ecc requirements (4 bits or more). It does so by adding a new ecc mode (NAND_ECC_SOFT_BCH) for use by board drivers, and a new Kconfig option to enable BCH support. It relies on the generic BCH library introduced in a previous patch. When a board driver uses mode NAND_ECC_SOFT_BCH, it should also set fields chip->ecc.size and chip->ecc.bytes to select BCH ecc data size and required error correction capability. See nand_bch_init() documentation for details. It has been tested on the following platforms using mtd-utils, UBI and UBIFS: x86 (with nandsim), arm926ejs. Signed-off-by: Ivan Djelic Signed-off-by: David Woodhouse --- drivers/mtd/nand/Kconfig | 15 +++ drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/nand_base.c | 40 ++++++- drivers/mtd/nand/nand_bch.c | 243 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/nand/nand_bch.c (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index c89592239bc7..78205ac2b10f 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -31,6 +31,21 @@ config MTD_NAND_VERIFY_WRITE device thinks the write was successful, a bit could have been flipped accidentally due to device wear or something else. +config MTD_NAND_BCH + tristate + select BCH + depends on MTD_NAND_ECC_BCH + default MTD_NAND + +config MTD_NAND_ECC_BCH + bool "Support software BCH ECC" + default n + help + This enables support for software BCH error correction. Binary BCH + codes are more powerful and cpu intensive than traditional Hamming + ECC codes. They are used with NAND devices requiring more than 1 bit + of error correction. + config MTD_SM_COMMON tristate default n diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 8ad6faec72cb..5745d831168e 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_MTD_NAND) += nand.o obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o +obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index da7604050347..85cfc061d41c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -3248,7 +3249,7 @@ int nand_scan_tail(struct mtd_info *mtd) /* * If no default placement scheme is given, select an appropriate one */ - if (!chip->ecc.layout) { + if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { switch (mtd->oobsize) { case 8: chip->ecc.layout = &nand_oob_8; @@ -3351,6 +3352,40 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.bytes = 3; break; + case NAND_ECC_SOFT_BCH: + if (!mtd_nand_has_bch()) { + printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); + BUG(); + } + chip->ecc.calculate = nand_bch_calculate_ecc; + chip->ecc.correct = nand_bch_correct_data; + chip->ecc.read_page = nand_read_page_swecc; + chip->ecc.read_subpage = nand_read_subpage; + chip->ecc.write_page = nand_write_page_swecc; + chip->ecc.read_page_raw = nand_read_page_raw; + chip->ecc.write_page_raw = nand_write_page_raw; + chip->ecc.read_oob = nand_read_oob_std; + chip->ecc.write_oob = nand_write_oob_std; + /* + * Board driver should supply ecc.size and ecc.bytes values to + * select how many bits are correctable; see nand_bch_init() + * for details. + * Otherwise, default to 4 bits for large page devices + */ + if (!chip->ecc.size && (mtd->oobsize >= 64)) { + chip->ecc.size = 512; + chip->ecc.bytes = 7; + } + chip->ecc.priv = nand_bch_init(mtd, + chip->ecc.size, + chip->ecc.bytes, + &chip->ecc.layout); + if (!chip->ecc.priv) { + printk(KERN_WARNING "BCH ECC initialization failed!\n"); + BUG(); + } + break; + case NAND_ECC_NONE: printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " "This is not recommended !!\n"); @@ -3501,6 +3536,9 @@ void nand_release(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; + if (chip->ecc.mode == NAND_ECC_SOFT_BCH) + nand_bch_free((struct nand_bch_control *)chip->ecc.priv); + #ifdef CONFIG_MTD_PARTITIONS /* Deregister partitions */ del_mtd_partitions(mtd); diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c new file mode 100644 index 000000000000..0f931e757116 --- /dev/null +++ b/drivers/mtd/nand/nand_bch.c @@ -0,0 +1,243 @@ +/* + * This file provides ECC correction for more than 1 bit per block of data, + * using binary BCH codes. It relies on the generic BCH library lib/bch.c. + * + * Copyright © 2011 Ivan Djelic + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 or (at your option) any + * later version. + * + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this file; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct nand_bch_control - private NAND BCH control structure + * @bch: BCH control structure + * @ecclayout: private ecc layout for this BCH configuration + * @errloc: error location array + * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid + */ +struct nand_bch_control { + struct bch_control *bch; + struct nand_ecclayout ecclayout; + unsigned int *errloc; + unsigned char *eccmask; +}; + +/** + * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block + * @mtd: MTD block structure + * @buf: input buffer with raw data + * @code: output buffer with ECC + */ +int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, + unsigned char *code) +{ + const struct nand_chip *chip = mtd->priv; + struct nand_bch_control *nbc = chip->ecc.priv; + unsigned int i; + + memset(code, 0, chip->ecc.bytes); + encode_bch(nbc->bch, buf, chip->ecc.size, code); + + /* apply mask so that an erased page is a valid codeword */ + for (i = 0; i < chip->ecc.bytes; i++) + code[i] ^= nbc->eccmask[i]; + + return 0; +} +EXPORT_SYMBOL(nand_bch_calculate_ecc); + +/** + * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) + * @mtd: MTD block structure + * @buf: raw data read from the chip + * @read_ecc: ECC from the chip + * @calc_ecc: the ECC calculated from raw data + * + * Detect and correct bit errors for a data byte block + */ +int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, + unsigned char *read_ecc, unsigned char *calc_ecc) +{ + const struct nand_chip *chip = mtd->priv; + struct nand_bch_control *nbc = chip->ecc.priv; + unsigned int *errloc = nbc->errloc; + int i, count; + + count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, + NULL, errloc); + if (count > 0) { + for (i = 0; i < count; i++) { + if (errloc[i] < (chip->ecc.size*8)) + /* error is located in data, correct it */ + buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); + /* else error in ecc, no action needed */ + + DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", + __func__, errloc[i]); + } + } else if (count < 0) { + printk(KERN_ERR "ecc unrecoverable error\n"); + count = -1; + } + return count; +} +EXPORT_SYMBOL(nand_bch_correct_data); + +/** + * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction + * @mtd: MTD block structure + * @eccsize: ecc block size in bytes + * @eccbytes: ecc length in bytes + * @ecclayout: output default layout + * + * Returns: + * a pointer to a new NAND BCH control structure, or NULL upon failure + * + * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes + * are used to compute BCH parameters m (Galois field order) and t (error + * correction capability). @eccbytes should be equal to the number of bytes + * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. + * + * Example: to configure 4 bit correction per 512 bytes, you should pass + * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) + * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) + */ +struct nand_bch_control * +nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, + struct nand_ecclayout **ecclayout) +{ + unsigned int m, t, eccsteps, i; + struct nand_ecclayout *layout; + struct nand_bch_control *nbc = NULL; + unsigned char *erased_page; + + if (!eccsize || !eccbytes) { + printk(KERN_WARNING "ecc parameters not supplied\n"); + goto fail; + } + + m = fls(1+8*eccsize); + t = (eccbytes*8)/m; + + nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); + if (!nbc) + goto fail; + + nbc->bch = init_bch(m, t, 0); + if (!nbc->bch) + goto fail; + + /* verify that eccbytes has the expected value */ + if (nbc->bch->ecc_bytes != eccbytes) { + printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", + eccbytes, nbc->bch->ecc_bytes); + goto fail; + } + + eccsteps = mtd->writesize/eccsize; + + /* if no ecc placement scheme was provided, build one */ + if (!*ecclayout) { + + /* handle large page devices only */ + if (mtd->oobsize < 64) { + printk(KERN_WARNING "must provide an oob scheme for " + "oobsize %d\n", mtd->oobsize); + goto fail; + } + + layout = &nbc->ecclayout; + layout->eccbytes = eccsteps*eccbytes; + + /* reserve 2 bytes for bad block marker */ + if (layout->eccbytes+2 > mtd->oobsize) { + printk(KERN_WARNING "no suitable oob scheme available " + "for oobsize %d eccbytes %u\n", mtd->oobsize, + eccbytes); + goto fail; + } + /* put ecc bytes at oob tail */ + for (i = 0; i < layout->eccbytes; i++) + layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; + + layout->oobfree[0].offset = 2; + layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; + + *ecclayout = layout; + } + + /* sanity checks */ + if (8*(eccsize+eccbytes) >= (1 << m)) { + printk(KERN_WARNING "eccsize %u is too large\n", eccsize); + goto fail; + } + if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) { + printk(KERN_WARNING "invalid ecc layout\n"); + goto fail; + } + + nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); + nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); + if (!nbc->eccmask || !nbc->errloc) + goto fail; + /* + * compute and store the inverted ecc of an erased ecc block + */ + erased_page = kmalloc(eccsize, GFP_KERNEL); + if (!erased_page) + goto fail; + + memset(erased_page, 0xff, eccsize); + memset(nbc->eccmask, 0, eccbytes); + encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); + kfree(erased_page); + + for (i = 0; i < eccbytes; i++) + nbc->eccmask[i] ^= 0xff; + + return nbc; +fail: + nand_bch_free(nbc); + return NULL; +} +EXPORT_SYMBOL(nand_bch_init); + +/** + * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources + * @nbc: NAND BCH control structure + */ +void nand_bch_free(struct nand_bch_control *nbc) +{ + if (nbc) { + free_bch(nbc->bch); + kfree(nbc->errloc); + kfree(nbc->eccmask); + kfree(nbc); + } +} +EXPORT_SYMBOL(nand_bch_free); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ivan Djelic "); +MODULE_DESCRIPTION("NAND software BCH ECC support"); -- cgit v1.2.2 From fc2ff592b5b41f3f32e790dd124eeb3bc80706c8 Mon Sep 17 00:00:00 2001 From: Ivan Djelic Date: Fri, 11 Mar 2011 11:05:34 +0100 Subject: mtd: nand: enable software BCH ECC in nand simulator This patch adds option 'bch' to nandsim, which can be used to enable software BCH ECC (introduced in previous patches) and select BCH error correction capability. Signed-off-by: Ivan Djelic Signed-off-by: David Woodhouse --- drivers/mtd/nand/nandsim.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index a5aa99f014ba..213181be0d9a 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,7 @@ static unsigned int rptwear = 0; static unsigned int overridesize = 0; static char *cache_file = NULL; static unsigned int bbt; +static unsigned int bch; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -132,6 +134,7 @@ module_param(rptwear, uint, 0400); module_param(overridesize, uint, 0400); module_param(cache_file, charp, 0400); module_param(bbt, uint, 0400); +module_param(bch, uint, 0400); MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); @@ -165,6 +168,8 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I " e.g. 5 means a size of 32 erase blocks"); MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area"); +MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should " + "be correctable in 512-byte blocks"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 4096 @@ -2309,7 +2314,43 @@ static int __init ns_init_module(void) if ((retval = parse_gravepages()) != 0) goto error; - if ((retval = nand_scan(nsmtd, 1)) != 0) { + retval = nand_scan_ident(nsmtd, 1, NULL); + if (retval) { + NS_ERR("cannot scan NAND Simulator device\n"); + if (retval > 0) + retval = -ENXIO; + goto error; + } + + if (bch) { + unsigned int eccsteps, eccbytes; + if (!mtd_nand_has_bch()) { + NS_ERR("BCH ECC support is disabled\n"); + retval = -EINVAL; + goto error; + } + /* use 512-byte ecc blocks */ + eccsteps = nsmtd->writesize/512; + eccbytes = (bch*13+7)/8; + /* do not bother supporting small page devices */ + if ((nsmtd->oobsize < 64) || !eccsteps) { + NS_ERR("bch not available on small page devices\n"); + retval = -EINVAL; + goto error; + } + if ((eccbytes*eccsteps+2) > nsmtd->oobsize) { + NS_ERR("invalid bch value %u\n", bch); + retval = -EINVAL; + goto error; + } + chip->ecc.mode = NAND_ECC_SOFT_BCH; + chip->ecc.size = 512; + chip->ecc.bytes = eccbytes; + NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size); + } + + retval = nand_scan_tail(nsmtd); + if (retval) { NS_ERR("can't register NAND Simulator\n"); if (retval > 0) retval = -ENXIO; -- cgit v1.2.2 From 957c2ec558caff09a3bdf333871fc617830f063d Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Fri, 11 Mar 2011 20:06:09 +0100 Subject: cciss: export resettable host attribute This attribute, requested by Redhat, allows kexec-tools to know whether the controller can honor the reset_devices kernel parameter and actually reset the controller. For kdump to work properly it is necessary that the reset_devices parameter be honored. This attribute enables kexec-tools to warn the user if they attempt to designate a non-resettable controller as the dump device. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 35658f445fca..eeed7aeb0b83 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -556,6 +556,44 @@ static void __devinit cciss_procinit(ctlr_info_t *h) #define to_hba(n) container_of(n, struct ctlr_info, dev) #define to_drv(n) container_of(n, drive_info_struct, dev) +/* List of controllers which cannot be reset on kexec with reset_devices */ +static u32 unresettable_controller[] = { + 0x324a103C, /* Smart Array P712m */ + 0x324b103C, /* SmartArray P711m */ + 0x3223103C, /* Smart Array P800 */ + 0x3234103C, /* Smart Array P400 */ + 0x3235103C, /* Smart Array P400i */ + 0x3211103C, /* Smart Array E200i */ + 0x3212103C, /* Smart Array E200 */ + 0x3213103C, /* Smart Array E200i */ + 0x3214103C, /* Smart Array E200i */ + 0x3215103C, /* Smart Array E200i */ + 0x3237103C, /* Smart Array E500 */ + 0x323D103C, /* Smart Array P700m */ + 0x409C0E11, /* Smart Array 6400 */ + 0x409D0E11, /* Smart Array 6400 EM */ +}; + +static int ctlr_is_resettable(struct ctlr_info *h) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++) + if (unresettable_controller[i] == h->board_id) + return 0; + return 1; +} + +static ssize_t host_show_resettable(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ctlr_info *h = to_hba(dev); + + return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h)); +} +static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL); + static ssize_t host_store_rescan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -741,6 +779,7 @@ static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL); static struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr, + &dev_attr_resettable.attr, NULL }; -- cgit v1.2.2 From 978eb516a4e1a1b47163518d6f5d5e81ab27a583 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Fri, 11 Mar 2011 20:07:38 +0100 Subject: cciss: Add missing allocation in scsi_cmd_stack_setup and corresponding deallocation This bit got lost somewhere along the way. Without this, panic. Signed-off-by: Stephen M. Cameron Cc: stable@kernel.org Signed-off-by: Jens Axboe --- drivers/block/cciss_scsi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 727d0225b7d0..3bfbde8b4013 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -226,6 +226,13 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa) return -ENOMEM; } + stk->elem = kmalloc(sizeof(stk->elem[0]) * stk->nelems, GFP_KERNEL); + if (!stk->elem) { + pci_free_consistent(h->pdev, size, stk->pool, + stk->cmd_pool_handle); + return -1; + } + for (i=0; ielem[i] = &stk->pool[i]; stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + @@ -255,6 +262,8 @@ scsi_cmd_stack_free(ctlr_info_t *h) pci_free_consistent(h->pdev, size, stk->pool, stk->cmd_pool_handle); stk->pool = NULL; cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE); + kfree(stk->elem); + stk->elem = NULL; } #if 0 -- cgit v1.2.2 From b203bd3f6b9c3db3b1979c2ff79bb2b9be8f03a3 Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:54:53 +0000 Subject: dmatest: fix automatic buffer unmap type The dmatest code relies on the DMAEngine API to automatically call dma_unmap_single() on src buffers. The flags it passes are incorrect, fix them. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 5589358b684d..7e1b0aa0ca50 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -285,7 +285,12 @@ static int dmatest_func(void *data) set_user_nice(current, 10); - flags = DMA_CTRL_ACK | DMA_COMPL_SKIP_DEST_UNMAP | DMA_PREP_INTERRUPT; + /* + * src buffers are freed by the DMAEngine code with dma_unmap_single() + * dst buffers are freed by ourselves below + */ + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT + | DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SRC_UNMAP_SINGLE; while (!kthread_should_stop() && !(iterations && total_tests >= iterations)) { -- cgit v1.2.2 From e8bd84df27c5921a9ac866aef06e044590ac118f Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:54:54 +0000 Subject: fsldma: move related helper functions near each other This is a purely cosmetic cleanup. It is nice to have related functions right next to each other in the code. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 116 ++++++++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 4de947a450fc..2e1af4555b0f 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -39,33 +39,9 @@ static const char msg_ld_oom[] = "No free memory for link descriptor\n"; -static void dma_init(struct fsldma_chan *chan) -{ - /* Reset the channel */ - DMA_OUT(chan, &chan->regs->mr, 0, 32); - - switch (chan->feature & FSL_DMA_IP_MASK) { - case FSL_DMA_IP_85XX: - /* Set the channel to below modes: - * EIE - Error interrupt enable - * EOSIE - End of segments interrupt enable (basic mode) - * EOLNIE - End of links interrupt enable - * BWC - Bandwidth sharing among channels - */ - DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC - | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE - | FSL_DMA_MR_EOSIE, 32); - break; - case FSL_DMA_IP_83XX: - /* Set the channel to below modes: - * EOTIE - End-of-transfer interrupt enable - * PRC_RM - PCI read multiple - */ - DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE - | FSL_DMA_MR_PRC_RM, 32); - break; - } -} +/* + * Register Helpers + */ static void set_sr(struct fsldma_chan *chan, u32 val) { @@ -77,6 +53,30 @@ static u32 get_sr(struct fsldma_chan *chan) return DMA_IN(chan, &chan->regs->sr, 32); } +static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr) +{ + DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64); +} + +static dma_addr_t get_cdar(struct fsldma_chan *chan) +{ + return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; +} + +static dma_addr_t get_ndar(struct fsldma_chan *chan) +{ + return DMA_IN(chan, &chan->regs->ndar, 64); +} + +static u32 get_bcr(struct fsldma_chan *chan) +{ + return DMA_IN(chan, &chan->regs->bcr, 32); +} + +/* + * Descriptor Helpers + */ + static void set_desc_cnt(struct fsldma_chan *chan, struct fsl_dma_ld_hw *hw, u32 count) { @@ -113,24 +113,49 @@ static void set_desc_next(struct fsldma_chan *chan, hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64); } -static void set_cdar(struct fsldma_chan *chan, dma_addr_t addr) +static void set_ld_eol(struct fsldma_chan *chan, + struct fsl_desc_sw *desc) { - DMA_OUT(chan, &chan->regs->cdar, addr | FSL_DMA_SNEN, 64); -} + u64 snoop_bits; -static dma_addr_t get_cdar(struct fsldma_chan *chan) -{ - return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; -} + snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX) + ? FSL_DMA_SNEN : 0; -static dma_addr_t get_ndar(struct fsldma_chan *chan) -{ - return DMA_IN(chan, &chan->regs->ndar, 64); + desc->hw.next_ln_addr = CPU_TO_DMA(chan, + DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL + | snoop_bits, 64); } -static u32 get_bcr(struct fsldma_chan *chan) +/* + * DMA Engine Hardware Control Helpers + */ + +static void dma_init(struct fsldma_chan *chan) { - return DMA_IN(chan, &chan->regs->bcr, 32); + /* Reset the channel */ + DMA_OUT(chan, &chan->regs->mr, 0, 32); + + switch (chan->feature & FSL_DMA_IP_MASK) { + case FSL_DMA_IP_85XX: + /* Set the channel to below modes: + * EIE - Error interrupt enable + * EOSIE - End of segments interrupt enable (basic mode) + * EOLNIE - End of links interrupt enable + * BWC - Bandwidth sharing among channels + */ + DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC + | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE + | FSL_DMA_MR_EOSIE, 32); + break; + case FSL_DMA_IP_83XX: + /* Set the channel to below modes: + * EOTIE - End-of-transfer interrupt enable + * PRC_RM - PCI read multiple + */ + DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_EOTIE + | FSL_DMA_MR_PRC_RM, 32); + break; + } } static int dma_is_idle(struct fsldma_chan *chan) @@ -185,19 +210,6 @@ static void dma_halt(struct fsldma_chan *chan) dev_err(chan->dev, "DMA halt timeout!\n"); } -static void set_ld_eol(struct fsldma_chan *chan, - struct fsl_desc_sw *desc) -{ - u64 snoop_bits; - - snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX) - ? FSL_DMA_SNEN : 0; - - desc->hw.next_ln_addr = CPU_TO_DMA(chan, - DMA_TO_CPU(chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL - | snoop_bits, 64); -} - /** * fsl_chan_set_src_loop_size - Set source address hold transfer size * @chan : Freescale DMA channel -- cgit v1.2.2 From b158471ef63bf399165db96e945a828096502d9d Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:54:55 +0000 Subject: fsldma: use channel name in printk output This makes debugging the driver much easier when multiple channels are running concurrently. In addition, you can see how much descriptor memory each channel has allocated via the dmapool API in sysfs. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 69 ++++++++++++++++++++++++++-------------------------- drivers/dma/fsldma.h | 1 + 2 files changed, 36 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 2e1af4555b0f..e535cd13f7cc 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -37,7 +37,12 @@ #include "fsldma.h" -static const char msg_ld_oom[] = "No free memory for link descriptor\n"; +#define chan_dbg(chan, fmt, arg...) \ + dev_dbg(chan->dev, "%s: " fmt, chan->name, ##arg) +#define chan_err(chan, fmt, arg...) \ + dev_err(chan->dev, "%s: " fmt, chan->name, ##arg) + +static const char msg_ld_oom[] = "No free memory for link descriptor"; /* * Register Helpers @@ -207,7 +212,7 @@ static void dma_halt(struct fsldma_chan *chan) } if (!dma_is_idle(chan)) - dev_err(chan->dev, "DMA halt timeout!\n"); + chan_err(chan, "DMA halt timeout!\n"); } /** @@ -405,7 +410,7 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor( desc = dma_pool_alloc(chan->desc_pool, GFP_ATOMIC, &pdesc); if (!desc) { - dev_dbg(chan->dev, "out of memory for link desc\n"); + chan_dbg(chan, "out of memory for link descriptor\n"); return NULL; } @@ -439,13 +444,11 @@ static int fsl_dma_alloc_chan_resources(struct dma_chan *dchan) * We need the descriptor to be aligned to 32bytes * for meeting FSL DMA specification requirement. */ - chan->desc_pool = dma_pool_create("fsl_dma_engine_desc_pool", - chan->dev, + chan->desc_pool = dma_pool_create(chan->name, chan->dev, sizeof(struct fsl_desc_sw), __alignof__(struct fsl_desc_sw), 0); if (!chan->desc_pool) { - dev_err(chan->dev, "unable to allocate channel %d " - "descriptor pool\n", chan->id); + chan_err(chan, "unable to allocate descriptor pool\n"); return -ENOMEM; } @@ -491,7 +494,7 @@ static void fsl_dma_free_chan_resources(struct dma_chan *dchan) struct fsldma_chan *chan = to_fsl_chan(dchan); unsigned long flags; - dev_dbg(chan->dev, "Free all channel resources.\n"); + chan_dbg(chan, "free all channel resources\n"); spin_lock_irqsave(&chan->desc_lock, flags); fsldma_free_desc_list(chan, &chan->ld_pending); fsldma_free_desc_list(chan, &chan->ld_running); @@ -514,7 +517,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags) new = fsl_dma_alloc_descriptor(chan); if (!new) { - dev_err(chan->dev, msg_ld_oom); + chan_err(chan, "%s\n", msg_ld_oom); return NULL; } @@ -551,11 +554,11 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( /* Allocate the link descriptor from DMA pool */ new = fsl_dma_alloc_descriptor(chan); if (!new) { - dev_err(chan->dev, msg_ld_oom); + chan_err(chan, "%s\n", msg_ld_oom); goto fail; } #ifdef FSL_DMA_LD_DEBUG - dev_dbg(chan->dev, "new link desc alloc %p\n", new); + chan_dbg(chan, "new link desc alloc %p\n", new); #endif copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT); @@ -639,11 +642,11 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan, /* allocate and populate the descriptor */ new = fsl_dma_alloc_descriptor(chan); if (!new) { - dev_err(chan->dev, msg_ld_oom); + chan_err(chan, "%s\n", msg_ld_oom); goto fail; } #ifdef FSL_DMA_LD_DEBUG - dev_dbg(chan->dev, "new link desc alloc %p\n", new); + chan_dbg(chan, "new link desc alloc %p\n", new); #endif set_desc_cnt(chan, &new->hw, len); @@ -815,7 +818,7 @@ static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan) spin_lock_irqsave(&chan->desc_lock, flags); if (list_empty(&chan->ld_running)) { - dev_dbg(chan->dev, "no running descriptors\n"); + chan_dbg(chan, "no running descriptors\n"); goto out_unlock; } @@ -863,7 +866,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) spin_lock_irqsave(&chan->desc_lock, flags); - dev_dbg(chan->dev, "chan completed_cookie = %d\n", chan->completed_cookie); + chan_dbg(chan, "chan completed_cookie = %d\n", chan->completed_cookie); list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) { dma_async_tx_callback callback; void *callback_param; @@ -879,7 +882,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) callback_param = desc->async_tx.callback_param; if (callback) { spin_unlock_irqrestore(&chan->desc_lock, flags); - dev_dbg(chan->dev, "LD %p callback\n", desc); + chan_dbg(chan, "LD %p callback\n", desc); callback(callback_param); spin_lock_irqsave(&chan->desc_lock, flags); } @@ -913,7 +916,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) * don't need to do any work at all */ if (list_empty(&chan->ld_pending)) { - dev_dbg(chan->dev, "no pending LDs\n"); + chan_dbg(chan, "no pending LDs\n"); goto out_unlock; } @@ -923,7 +926,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) * at the end of the current transaction */ if (!dma_is_idle(chan)) { - dev_dbg(chan->dev, "DMA controller still busy\n"); + chan_dbg(chan, "DMA controller still busy\n"); goto out_unlock; } @@ -1003,14 +1006,14 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) /* save and clear the status register */ stat = get_sr(chan); set_sr(chan, stat); - dev_dbg(chan->dev, "irq: channel %d, stat = 0x%x\n", chan->id, stat); + chan_dbg(chan, "irq: stat = 0x%x\n", stat); stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH); if (!stat) return IRQ_NONE; if (stat & FSL_DMA_SR_TE) - dev_err(chan->dev, "Transfer Error!\n"); + chan_err(chan, "Transfer Error!\n"); /* * Programming Error @@ -1018,7 +1021,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) * triger a PE interrupt. */ if (stat & FSL_DMA_SR_PE) { - dev_dbg(chan->dev, "irq: Programming Error INT\n"); + chan_dbg(chan, "irq: Programming Error INT\n"); if (get_bcr(chan) == 0) { /* BCR register is 0, this is a DMA_INTERRUPT async_tx. * Now, update the completed cookie, and continue the @@ -1035,8 +1038,8 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) * we will recycle the used descriptor. */ if (stat & FSL_DMA_SR_EOSI) { - dev_dbg(chan->dev, "irq: End-of-segments INT\n"); - dev_dbg(chan->dev, "irq: clndar 0x%llx, nlndar 0x%llx\n", + chan_dbg(chan, "irq: End-of-segments INT\n"); + chan_dbg(chan, "irq: clndar 0x%llx, nlndar 0x%llx\n", (unsigned long long)get_cdar(chan), (unsigned long long)get_ndar(chan)); stat &= ~FSL_DMA_SR_EOSI; @@ -1048,7 +1051,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) * and start the next transfer if it exist. */ if (stat & FSL_DMA_SR_EOCDI) { - dev_dbg(chan->dev, "irq: End-of-Chain link INT\n"); + chan_dbg(chan, "irq: End-of-Chain link INT\n"); stat &= ~FSL_DMA_SR_EOCDI; update_cookie = 1; xfer_ld_q = 1; @@ -1060,7 +1063,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) * prepare next transfer. */ if (stat & FSL_DMA_SR_EOLNI) { - dev_dbg(chan->dev, "irq: End-of-link INT\n"); + chan_dbg(chan, "irq: End-of-link INT\n"); stat &= ~FSL_DMA_SR_EOLNI; xfer_ld_q = 1; } @@ -1070,9 +1073,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) if (xfer_ld_q) fsl_chan_xfer_ld_queue(chan); if (stat) - dev_dbg(chan->dev, "irq: unhandled sr 0x%02x\n", stat); + chan_dbg(chan, "irq: unhandled sr 0x%08x\n", stat); - dev_dbg(chan->dev, "irq: Exit\n"); + chan_dbg(chan, "irq: Exit\n"); tasklet_schedule(&chan->tasklet); return IRQ_HANDLED; } @@ -1128,7 +1131,7 @@ static void fsldma_free_irqs(struct fsldma_device *fdev) for (i = 0; i < FSL_DMA_MAX_CHANS_PER_DEVICE; i++) { chan = fdev->chan[i]; if (chan && chan->irq != NO_IRQ) { - dev_dbg(fdev->dev, "free channel %d IRQ\n", chan->id); + chan_dbg(chan, "free per-channel IRQ\n"); free_irq(chan->irq, chan); } } @@ -1155,19 +1158,16 @@ static int fsldma_request_irqs(struct fsldma_device *fdev) continue; if (chan->irq == NO_IRQ) { - dev_err(fdev->dev, "no interrupts property defined for " - "DMA channel %d. Please fix your " - "device tree\n", chan->id); + chan_err(chan, "interrupts property missing in device tree\n"); ret = -ENODEV; goto out_unwind; } - dev_dbg(fdev->dev, "request channel %d IRQ\n", chan->id); + chan_dbg(chan, "request per-channel IRQ\n"); ret = request_irq(chan->irq, fsldma_chan_irq, IRQF_SHARED, "fsldma-chan", chan); if (ret) { - dev_err(fdev->dev, "unable to request IRQ for DMA " - "channel %d\n", chan->id); + chan_err(chan, "unable to request per-channel IRQ\n"); goto out_unwind; } } @@ -1242,6 +1242,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev, fdev->chan[chan->id] = chan; tasklet_init(&chan->tasklet, dma_do_tasklet, (unsigned long)chan); + snprintf(chan->name, sizeof(chan->name), "chan%d", chan->id); /* Initialize the channel */ dma_init(chan); diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index ba9f403c0fbe..113e7134010b 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -135,6 +135,7 @@ struct fsldma_device { #define FSL_DMA_CHAN_START_EXT 0x00002000 struct fsldma_chan { + char name[8]; /* Channel name */ struct fsldma_chan_regs __iomem *regs; dma_cookie_t completed_cookie; /* The maximum cookie completed */ spinlock_t desc_lock; /* Descriptor operation lock */ -- cgit v1.2.2 From 0ab09c36818ca88f65c88f4d8c6d067fbf10578d Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:54:56 +0000 Subject: fsldma: improve link descriptor debugging This adds better tracking to link descriptor allocations, callbacks, and frees. This makes it much easier to track errors with link descriptors. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index e535cd13f7cc..82b8e9f9c7bf 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -420,6 +420,10 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor( desc->async_tx.tx_submit = fsl_dma_tx_submit; desc->async_tx.phys = pdesc; +#ifdef FSL_DMA_LD_DEBUG + chan_dbg(chan, "LD %p allocated\n", desc); +#endif + return desc; } @@ -470,6 +474,9 @@ static void fsldma_free_desc_list(struct fsldma_chan *chan, list_for_each_entry_safe(desc, _desc, list, node) { list_del(&desc->node); +#ifdef FSL_DMA_LD_DEBUG + chan_dbg(chan, "LD %p free\n", desc); +#endif dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); } } @@ -481,6 +488,9 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan, list_for_each_entry_safe_reverse(desc, _desc, list, node) { list_del(&desc->node); +#ifdef FSL_DMA_LD_DEBUG + chan_dbg(chan, "LD %p free\n", desc); +#endif dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); } } @@ -557,9 +567,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( chan_err(chan, "%s\n", msg_ld_oom); goto fail; } -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "new link desc alloc %p\n", new); -#endif copy = min(len, (size_t)FSL_DMA_BCR_MAX_CNT); @@ -645,9 +652,6 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan, chan_err(chan, "%s\n", msg_ld_oom); goto fail; } -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "new link desc alloc %p\n", new); -#endif set_desc_cnt(chan, &new->hw, len); set_desc_src(chan, &new->hw, src); @@ -882,13 +886,18 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) callback_param = desc->async_tx.callback_param; if (callback) { spin_unlock_irqrestore(&chan->desc_lock, flags); +#ifdef FSL_DMA_LD_DEBUG chan_dbg(chan, "LD %p callback\n", desc); +#endif callback(callback_param); spin_lock_irqsave(&chan->desc_lock, flags); } /* Run any dependencies, then free the descriptor */ dma_run_dependencies(&desc->async_tx); +#ifdef FSL_DMA_LD_DEBUG + chan_dbg(chan, "LD %p free\n", desc); +#endif dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); } -- cgit v1.2.2 From 31f4306c83a2daa3e348056b720de511bffe5a9b Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:54:57 +0000 Subject: fsldma: minor codingstyle and consistency fixes This fixes some minor violations of the coding style. It also changes the style of the device_prep_dma_*() function definitions so they are identical. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 29 +++++++++++++---------------- drivers/dma/fsldma.h | 4 ++-- 2 files changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 82b8e9f9c7bf..5da1a4a817e3 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -89,7 +89,7 @@ static void set_desc_cnt(struct fsldma_chan *chan, } static void set_desc_src(struct fsldma_chan *chan, - struct fsl_dma_ld_hw *hw, dma_addr_t src) + struct fsl_dma_ld_hw *hw, dma_addr_t src) { u64 snoop_bits; @@ -99,7 +99,7 @@ static void set_desc_src(struct fsldma_chan *chan, } static void set_desc_dst(struct fsldma_chan *chan, - struct fsl_dma_ld_hw *hw, dma_addr_t dst) + struct fsl_dma_ld_hw *hw, dma_addr_t dst) { u64 snoop_bits; @@ -109,7 +109,7 @@ static void set_desc_dst(struct fsldma_chan *chan, } static void set_desc_next(struct fsldma_chan *chan, - struct fsl_dma_ld_hw *hw, dma_addr_t next) + struct fsl_dma_ld_hw *hw, dma_addr_t next) { u64 snoop_bits; @@ -118,8 +118,7 @@ static void set_desc_next(struct fsldma_chan *chan, hw->next_ln_addr = CPU_TO_DMA(chan, snoop_bits | next, 64); } -static void set_ld_eol(struct fsldma_chan *chan, - struct fsl_desc_sw *desc) +static void set_ld_eol(struct fsldma_chan *chan, struct fsl_desc_sw *desc) { u64 snoop_bits; @@ -338,8 +337,7 @@ static void fsl_chan_toggle_ext_start(struct fsldma_chan *chan, int enable) chan->feature &= ~FSL_DMA_CHAN_START_EXT; } -static void append_ld_queue(struct fsldma_chan *chan, - struct fsl_desc_sw *desc) +static void append_ld_queue(struct fsldma_chan *chan, struct fsl_desc_sw *desc) { struct fsl_desc_sw *tail = to_fsl_desc(chan->ld_pending.prev); @@ -380,8 +378,8 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) cookie = chan->common.cookie; list_for_each_entry(child, &desc->tx_list, node) { cookie++; - if (cookie < 0) - cookie = 1; + if (cookie < DMA_MIN_COOKIE) + cookie = DMA_MIN_COOKIE; child->async_tx.cookie = cookie; } @@ -402,8 +400,7 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx) * * Return - The descriptor allocated. NULL for failed. */ -static struct fsl_desc_sw *fsl_dma_alloc_descriptor( - struct fsldma_chan *chan) +static struct fsl_desc_sw *fsl_dma_alloc_descriptor(struct fsldma_chan *chan) { struct fsl_desc_sw *desc; dma_addr_t pdesc; @@ -427,7 +424,6 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor( return desc; } - /** * fsl_dma_alloc_chan_resources - Allocate resources for DMA channel. * @chan : Freescale DMA channel @@ -537,14 +533,15 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags) /* Insert the link descriptor to the LD ring */ list_add_tail(&new->node, &new->tx_list); - /* Set End-of-link to the last link descriptor of new list*/ + /* Set End-of-link to the last link descriptor of new list */ set_ld_eol(chan, new); return &new->async_tx; } -static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( - struct dma_chan *dchan, dma_addr_t dma_dst, dma_addr_t dma_src, +static struct dma_async_tx_descriptor * +fsl_dma_prep_memcpy(struct dma_chan *dchan, + dma_addr_t dma_dst, dma_addr_t dma_src, size_t len, unsigned long flags) { struct fsldma_chan *chan; @@ -594,7 +591,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy( new->async_tx.flags = flags; /* client is in control of this ack */ new->async_tx.cookie = -EBUSY; - /* Set End-of-link to the last link descriptor of new list*/ + /* Set End-of-link to the last link descriptor of new list */ set_ld_eol(chan, new); return &first->async_tx; diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index 113e7134010b..49189dacd5f4 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -102,8 +102,8 @@ struct fsl_desc_sw { } __attribute__((aligned(32))); struct fsldma_chan_regs { - u32 mr; /* 0x00 - Mode Register */ - u32 sr; /* 0x04 - Status Register */ + u32 mr; /* 0x00 - Mode Register */ + u32 sr; /* 0x04 - Status Register */ u64 cdar; /* 0x08 - Current descriptor address register */ u64 sar; /* 0x10 - Source Address Register */ u64 dar; /* 0x18 - Destination Address Register */ -- cgit v1.2.2 From f04cd40701deace2efb9edd7120e59366bda2118 Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:54:58 +0000 Subject: fsldma: fix controller lockups Enabling poisoning in the dmapool API quickly showed that the DMA controller was fetching descriptors that should not have been in use. This has caused intermittent controller lockups during testing. I have been unable to figure out the exact set of conditions which cause this to happen. However, I believe it is related to the driver using the hardware registers to track whether the controller is busy or not. The code can incorrectly decide that the hardware is idle due to lag between register writes and the hardware actually becoming busy. To fix this, the driver has been reworked to explicitly track the state of the hardware, rather than try to guess what it is doing based on the register values. This has passed dmatest with 10 threads per channel, 100000 iterations per thread several times without error. Previously, this would fail within a few seconds. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 220 +++++++++++++++++++++++---------------------------- drivers/dma/fsldma.h | 1 + 2 files changed, 99 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 5da1a4a817e3..6e9ad6edc4af 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -68,11 +68,6 @@ static dma_addr_t get_cdar(struct fsldma_chan *chan) return DMA_IN(chan, &chan->regs->cdar, 64) & ~FSL_DMA_SNEN; } -static dma_addr_t get_ndar(struct fsldma_chan *chan) -{ - return DMA_IN(chan, &chan->regs->ndar, 64); -} - static u32 get_bcr(struct fsldma_chan *chan) { return DMA_IN(chan, &chan->regs->bcr, 32); @@ -143,13 +138,11 @@ static void dma_init(struct fsldma_chan *chan) case FSL_DMA_IP_85XX: /* Set the channel to below modes: * EIE - Error interrupt enable - * EOSIE - End of segments interrupt enable (basic mode) * EOLNIE - End of links interrupt enable * BWC - Bandwidth sharing among channels */ DMA_OUT(chan, &chan->regs->mr, FSL_DMA_MR_BWC - | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE - | FSL_DMA_MR_EOSIE, 32); + | FSL_DMA_MR_EIE | FSL_DMA_MR_EOLNIE, 32); break; case FSL_DMA_IP_83XX: /* Set the channel to below modes: @@ -168,25 +161,32 @@ static int dma_is_idle(struct fsldma_chan *chan) return (!(sr & FSL_DMA_SR_CB)) || (sr & FSL_DMA_SR_CH); } +/* + * Start the DMA controller + * + * Preconditions: + * - the CDAR register must point to the start descriptor + * - the MRn[CS] bit must be cleared + */ static void dma_start(struct fsldma_chan *chan) { u32 mode; mode = DMA_IN(chan, &chan->regs->mr, 32); - if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { - if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { - DMA_OUT(chan, &chan->regs->bcr, 0, 32); - mode |= FSL_DMA_MR_EMP_EN; - } else { - mode &= ~FSL_DMA_MR_EMP_EN; - } + if (chan->feature & FSL_DMA_CHAN_PAUSE_EXT) { + DMA_OUT(chan, &chan->regs->bcr, 0, 32); + mode |= FSL_DMA_MR_EMP_EN; + } else { + mode &= ~FSL_DMA_MR_EMP_EN; } - if (chan->feature & FSL_DMA_CHAN_START_EXT) + if (chan->feature & FSL_DMA_CHAN_START_EXT) { mode |= FSL_DMA_MR_EMS_EN; - else + } else { + mode &= ~FSL_DMA_MR_EMS_EN; mode |= FSL_DMA_MR_CS; + } DMA_OUT(chan, &chan->regs->mr, mode, 32); } @@ -760,14 +760,15 @@ static int fsl_dma_device_control(struct dma_chan *dchan, switch (cmd) { case DMA_TERMINATE_ALL: + spin_lock_irqsave(&chan->desc_lock, flags); + /* Halt the DMA engine */ dma_halt(chan); - spin_lock_irqsave(&chan->desc_lock, flags); - /* Remove and free all of the descriptors in the LD queue */ fsldma_free_desc_list(chan, &chan->ld_pending); fsldma_free_desc_list(chan, &chan->ld_running); + chan->idle = true; spin_unlock_irqrestore(&chan->desc_lock, flags); return 0; @@ -805,76 +806,43 @@ static int fsl_dma_device_control(struct dma_chan *dchan, } /** - * fsl_dma_update_completed_cookie - Update the completed cookie. + * fsl_chan_ld_cleanup - Clean up link descriptors * @chan : Freescale DMA channel * - * CONTEXT: hardirq + * This function is run after the queue of running descriptors has been + * executed by the DMA engine. It will run any callbacks, and then free + * the descriptors. + * + * HARDWARE STATE: idle */ -static void fsl_dma_update_completed_cookie(struct fsldma_chan *chan) +static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) { - struct fsl_desc_sw *desc; + struct fsl_desc_sw *desc, *_desc; unsigned long flags; - dma_cookie_t cookie; spin_lock_irqsave(&chan->desc_lock, flags); + /* if the ld_running list is empty, there is nothing to do */ if (list_empty(&chan->ld_running)) { - chan_dbg(chan, "no running descriptors\n"); + chan_dbg(chan, "no descriptors to cleanup\n"); goto out_unlock; } - /* Get the last descriptor, update the cookie to that */ + /* + * Get the last descriptor, update the cookie to it + * + * This is done before callbacks run so that clients can check the + * status of their DMA transfer inside the callback. + */ desc = to_fsl_desc(chan->ld_running.prev); - if (dma_is_idle(chan)) - cookie = desc->async_tx.cookie; - else { - cookie = desc->async_tx.cookie - 1; - if (unlikely(cookie < DMA_MIN_COOKIE)) - cookie = DMA_MAX_COOKIE; - } - - chan->completed_cookie = cookie; - -out_unlock: - spin_unlock_irqrestore(&chan->desc_lock, flags); -} - -/** - * fsldma_desc_status - Check the status of a descriptor - * @chan: Freescale DMA channel - * @desc: DMA SW descriptor - * - * This function will return the status of the given descriptor - */ -static enum dma_status fsldma_desc_status(struct fsldma_chan *chan, - struct fsl_desc_sw *desc) -{ - return dma_async_is_complete(desc->async_tx.cookie, - chan->completed_cookie, - chan->common.cookie); -} - -/** - * fsl_chan_ld_cleanup - Clean up link descriptors - * @chan : Freescale DMA channel - * - * This function clean up the ld_queue of DMA channel. - */ -static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) -{ - struct fsl_desc_sw *desc, *_desc; - unsigned long flags; - - spin_lock_irqsave(&chan->desc_lock, flags); + chan->completed_cookie = desc->async_tx.cookie; + chan_dbg(chan, "completed_cookie = %d\n", chan->completed_cookie); - chan_dbg(chan, "chan completed_cookie = %d\n", chan->completed_cookie); + /* Run the callback for each descriptor, in order */ list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) { dma_async_tx_callback callback; void *callback_param; - if (fsldma_desc_status(chan, desc) == DMA_IN_PROGRESS) - break; - /* Remove from the list of running transactions */ list_del(&desc->node); @@ -898,6 +866,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); } +out_unlock: spin_unlock_irqrestore(&chan->desc_lock, flags); } @@ -905,10 +874,7 @@ static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) * fsl_chan_xfer_ld_queue - transfer any pending transactions * @chan : Freescale DMA channel * - * This will make sure that any pending transactions will be run. - * If the DMA controller is idle, it will be started. Otherwise, - * the DMA controller's interrupt handler will start any pending - * transactions when it becomes idle. + * HARDWARE STATE: idle */ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) { @@ -927,22 +893,15 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) } /* - * The DMA controller is not idle, which means the interrupt - * handler will start any queued transactions when it runs - * at the end of the current transaction + * The DMA controller is not idle, which means that the interrupt + * handler will start any queued transactions when it runs after + * this transaction finishes */ - if (!dma_is_idle(chan)) { + if (!chan->idle) { chan_dbg(chan, "DMA controller still busy\n"); goto out_unlock; } - /* - * TODO: - * make sure the dma_halt() function really un-wedges the - * controller as much as possible - */ - dma_halt(chan); - /* * If there are some link descriptors which have not been * transferred, we need to start the controller @@ -952,15 +911,32 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) * Move all elements from the queue of pending transactions * onto the list of running transactions */ + chan_dbg(chan, "idle, starting controller\n"); desc = list_first_entry(&chan->ld_pending, struct fsl_desc_sw, node); list_splice_tail_init(&chan->ld_pending, &chan->ld_running); + /* + * The 85xx DMA controller doesn't clear the channel start bit + * automatically at the end of a transfer. Therefore we must clear + * it in software before starting the transfer. + */ + if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { + u32 mode; + + mode = DMA_IN(chan, &chan->regs->mr, 32); + mode &= ~FSL_DMA_MR_CS; + DMA_OUT(chan, &chan->regs->mr, mode, 32); + } + /* * Program the descriptor's address into the DMA controller, * then start the DMA transaction */ set_cdar(chan, desc->async_tx.phys); + get_cdar(chan); + dma_start(chan); + chan->idle = false; out_unlock: spin_unlock_irqrestore(&chan->desc_lock, flags); @@ -985,16 +961,18 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan, struct dma_tx_state *txstate) { struct fsldma_chan *chan = to_fsl_chan(dchan); - dma_cookie_t last_used; dma_cookie_t last_complete; + dma_cookie_t last_used; + unsigned long flags; - fsl_chan_ld_cleanup(chan); + spin_lock_irqsave(&chan->desc_lock, flags); - last_used = dchan->cookie; last_complete = chan->completed_cookie; + last_used = dchan->cookie; - dma_set_tx_state(txstate, last_complete, last_used, 0); + spin_unlock_irqrestore(&chan->desc_lock, flags); + dma_set_tx_state(txstate, last_complete, last_used, 0); return dma_async_is_complete(cookie, last_complete, last_used); } @@ -1005,8 +983,6 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan, static irqreturn_t fsldma_chan_irq(int irq, void *data) { struct fsldma_chan *chan = data; - int update_cookie = 0; - int xfer_ld_q = 0; u32 stat; /* save and clear the status register */ @@ -1014,6 +990,7 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) set_sr(chan, stat); chan_dbg(chan, "irq: stat = 0x%x\n", stat); + /* check that this was really our device */ stat &= ~(FSL_DMA_SR_CB | FSL_DMA_SR_CH); if (!stat) return IRQ_NONE; @@ -1028,28 +1005,9 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) */ if (stat & FSL_DMA_SR_PE) { chan_dbg(chan, "irq: Programming Error INT\n"); - if (get_bcr(chan) == 0) { - /* BCR register is 0, this is a DMA_INTERRUPT async_tx. - * Now, update the completed cookie, and continue the - * next uncompleted transfer. - */ - update_cookie = 1; - xfer_ld_q = 1; - } stat &= ~FSL_DMA_SR_PE; - } - - /* - * If the link descriptor segment transfer finishes, - * we will recycle the used descriptor. - */ - if (stat & FSL_DMA_SR_EOSI) { - chan_dbg(chan, "irq: End-of-segments INT\n"); - chan_dbg(chan, "irq: clndar 0x%llx, nlndar 0x%llx\n", - (unsigned long long)get_cdar(chan), - (unsigned long long)get_ndar(chan)); - stat &= ~FSL_DMA_SR_EOSI; - update_cookie = 1; + if (get_bcr(chan) != 0) + chan_err(chan, "Programming Error!\n"); } /* @@ -1059,8 +1017,6 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) if (stat & FSL_DMA_SR_EOCDI) { chan_dbg(chan, "irq: End-of-Chain link INT\n"); stat &= ~FSL_DMA_SR_EOCDI; - update_cookie = 1; - xfer_ld_q = 1; } /* @@ -1071,25 +1027,44 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) if (stat & FSL_DMA_SR_EOLNI) { chan_dbg(chan, "irq: End-of-link INT\n"); stat &= ~FSL_DMA_SR_EOLNI; - xfer_ld_q = 1; } - if (update_cookie) - fsl_dma_update_completed_cookie(chan); - if (xfer_ld_q) - fsl_chan_xfer_ld_queue(chan); + /* check that the DMA controller is really idle */ + if (!dma_is_idle(chan)) + chan_err(chan, "irq: controller not idle!\n"); + + /* check that we handled all of the bits */ if (stat) - chan_dbg(chan, "irq: unhandled sr 0x%08x\n", stat); + chan_err(chan, "irq: unhandled sr 0x%08x\n", stat); - chan_dbg(chan, "irq: Exit\n"); + /* + * Schedule the tasklet to handle all cleanup of the current + * transaction. It will start a new transaction if there is + * one pending. + */ tasklet_schedule(&chan->tasklet); + chan_dbg(chan, "irq: Exit\n"); return IRQ_HANDLED; } static void dma_do_tasklet(unsigned long data) { struct fsldma_chan *chan = (struct fsldma_chan *)data; + unsigned long flags; + + chan_dbg(chan, "tasklet entry\n"); + + /* run all callbacks, free all used descriptors */ fsl_chan_ld_cleanup(chan); + + /* the channel is now idle */ + spin_lock_irqsave(&chan->desc_lock, flags); + chan->idle = true; + spin_unlock_irqrestore(&chan->desc_lock, flags); + + /* start any pending transactions automatically */ + fsl_chan_xfer_ld_queue(chan); + chan_dbg(chan, "tasklet exit\n"); } static irqreturn_t fsldma_ctrl_irq(int irq, void *data) @@ -1269,6 +1244,7 @@ static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev, spin_lock_init(&chan->desc_lock); INIT_LIST_HEAD(&chan->ld_pending); INIT_LIST_HEAD(&chan->ld_running); + chan->idle = true; chan->common.device = &fdev->common; diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h index 49189dacd5f4..9cb5aa57c677 100644 --- a/drivers/dma/fsldma.h +++ b/drivers/dma/fsldma.h @@ -148,6 +148,7 @@ struct fsldma_chan { int id; /* Raw id of this channel */ struct tasklet_struct tasklet; u32 feature; + bool idle; /* DMA controller is idle */ void (*toggle_ext_pause)(struct fsldma_chan *fsl_chan, int enable); void (*toggle_ext_start)(struct fsldma_chan *fsl_chan, int enable); -- cgit v1.2.2 From 9c4d1e7bdeb1ed4dc0c3341d40662a6fbc5f2dc2 Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:54:59 +0000 Subject: fsldma: support async_tx dependencies and automatic unmapping Previous to this patch, the dma_run_dependencies() function has been called while holding desc_lock. This function can call tx_submit() for other descriptors, which may try to re-grab the lock. Avoid this by moving the descriptors to be cleaned up to a temporary list, and dropping the lock before cleanup. At the same time, add support for automatic unmapping of src and dst buffers, as offered by the DMAEngine API. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 131 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 6e9ad6edc4af..526579df6033 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -83,6 +83,11 @@ static void set_desc_cnt(struct fsldma_chan *chan, hw->count = CPU_TO_DMA(chan, count, 32); } +static u32 get_desc_cnt(struct fsldma_chan *chan, struct fsl_desc_sw *desc) +{ + return DMA_TO_CPU(chan, desc->hw.count, 32); +} + static void set_desc_src(struct fsldma_chan *chan, struct fsl_dma_ld_hw *hw, dma_addr_t src) { @@ -93,6 +98,16 @@ static void set_desc_src(struct fsldma_chan *chan, hw->src_addr = CPU_TO_DMA(chan, snoop_bits | src, 64); } +static dma_addr_t get_desc_src(struct fsldma_chan *chan, + struct fsl_desc_sw *desc) +{ + u64 snoop_bits; + + snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) + ? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0; + return DMA_TO_CPU(chan, desc->hw.src_addr, 64) & ~snoop_bits; +} + static void set_desc_dst(struct fsldma_chan *chan, struct fsl_dma_ld_hw *hw, dma_addr_t dst) { @@ -103,6 +118,16 @@ static void set_desc_dst(struct fsldma_chan *chan, hw->dst_addr = CPU_TO_DMA(chan, snoop_bits | dst, 64); } +static dma_addr_t get_desc_dst(struct fsldma_chan *chan, + struct fsl_desc_sw *desc) +{ + u64 snoop_bits; + + snoop_bits = ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) + ? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0; + return DMA_TO_CPU(chan, desc->hw.dst_addr, 64) & ~snoop_bits; +} + static void set_desc_next(struct fsldma_chan *chan, struct fsl_dma_ld_hw *hw, dma_addr_t next) { @@ -805,6 +830,57 @@ static int fsl_dma_device_control(struct dma_chan *dchan, return 0; } +/** + * fsldma_cleanup_descriptor - cleanup and free a single link descriptor + * @chan: Freescale DMA channel + * @desc: descriptor to cleanup and free + * + * This function is used on a descriptor which has been executed by the DMA + * controller. It will run any callbacks, submit any dependencies, and then + * free the descriptor. + */ +static void fsldma_cleanup_descriptor(struct fsldma_chan *chan, + struct fsl_desc_sw *desc) +{ + struct dma_async_tx_descriptor *txd = &desc->async_tx; + struct device *dev = chan->common.device->dev; + dma_addr_t src = get_desc_src(chan, desc); + dma_addr_t dst = get_desc_dst(chan, desc); + u32 len = get_desc_cnt(chan, desc); + + /* Run the link descriptor callback function */ + if (txd->callback) { +#ifdef FSL_DMA_LD_DEBUG + chan_dbg(chan, "LD %p callback\n", desc); +#endif + txd->callback(txd->callback_param); + } + + /* Run any dependencies */ + dma_run_dependencies(txd); + + /* Unmap the dst buffer, if requested */ + if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) { + if (txd->flags & DMA_COMPL_DEST_UNMAP_SINGLE) + dma_unmap_single(dev, dst, len, DMA_FROM_DEVICE); + else + dma_unmap_page(dev, dst, len, DMA_FROM_DEVICE); + } + + /* Unmap the src buffer, if requested */ + if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) { + if (txd->flags & DMA_COMPL_SRC_UNMAP_SINGLE) + dma_unmap_single(dev, src, len, DMA_TO_DEVICE); + else + dma_unmap_page(dev, src, len, DMA_TO_DEVICE); + } + +#ifdef FSL_DMA_LD_DEBUG + chan_dbg(chan, "LD %p free\n", desc); +#endif + dma_pool_free(chan->desc_pool, desc, txd->phys); +} + /** * fsl_chan_ld_cleanup - Clean up link descriptors * @chan : Freescale DMA channel @@ -818,56 +894,39 @@ static int fsl_dma_device_control(struct dma_chan *dchan, static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) { struct fsl_desc_sw *desc, *_desc; + LIST_HEAD(ld_cleanup); unsigned long flags; spin_lock_irqsave(&chan->desc_lock, flags); - /* if the ld_running list is empty, there is nothing to do */ - if (list_empty(&chan->ld_running)) { - chan_dbg(chan, "no descriptors to cleanup\n"); - goto out_unlock; + /* update the cookie if we have some descriptors to cleanup */ + if (!list_empty(&chan->ld_running)) { + dma_cookie_t cookie; + + desc = to_fsl_desc(chan->ld_running.prev); + cookie = desc->async_tx.cookie; + + chan->completed_cookie = cookie; + chan_dbg(chan, "completed cookie=%d\n", cookie); } /* - * Get the last descriptor, update the cookie to it - * - * This is done before callbacks run so that clients can check the - * status of their DMA transfer inside the callback. + * move the descriptors to a temporary list so we can drop the lock + * during the entire cleanup operation */ - desc = to_fsl_desc(chan->ld_running.prev); - chan->completed_cookie = desc->async_tx.cookie; - chan_dbg(chan, "completed_cookie = %d\n", chan->completed_cookie); + list_splice_tail_init(&chan->ld_running, &ld_cleanup); + + spin_unlock_irqrestore(&chan->desc_lock, flags); /* Run the callback for each descriptor, in order */ - list_for_each_entry_safe(desc, _desc, &chan->ld_running, node) { - dma_async_tx_callback callback; - void *callback_param; + list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) { - /* Remove from the list of running transactions */ + /* Remove from the list of transactions */ list_del(&desc->node); - /* Run the link descriptor callback function */ - callback = desc->async_tx.callback; - callback_param = desc->async_tx.callback_param; - if (callback) { - spin_unlock_irqrestore(&chan->desc_lock, flags); -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "LD %p callback\n", desc); -#endif - callback(callback_param); - spin_lock_irqsave(&chan->desc_lock, flags); - } - - /* Run any dependencies, then free the descriptor */ - dma_run_dependencies(&desc->async_tx); -#ifdef FSL_DMA_LD_DEBUG - chan_dbg(chan, "LD %p free\n", desc); -#endif - dma_pool_free(chan->desc_pool, desc, desc->async_tx.phys); + /* Run all cleanup for this descriptor */ + fsldma_cleanup_descriptor(chan, desc); } - -out_unlock: - spin_unlock_irqrestore(&chan->desc_lock, flags); } /** -- cgit v1.2.2 From dc8d4091575ba81e886ebcdfd1e559c981f82f86 Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:55:00 +0000 Subject: fsldma: reduce locking during descriptor cleanup This merges the fsl_chan_ld_cleanup() function into the dma_do_tasklet() function to reduce locking overhead. In the best case, we will be able to keep the DMA controller busy while we are freeing used descriptors. In all cases, the spinlock is grabbed two times fewer than before on each transaction. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 108 ++++++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 526579df6033..d300de456c90 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -881,66 +881,16 @@ static void fsldma_cleanup_descriptor(struct fsldma_chan *chan, dma_pool_free(chan->desc_pool, desc, txd->phys); } -/** - * fsl_chan_ld_cleanup - Clean up link descriptors - * @chan : Freescale DMA channel - * - * This function is run after the queue of running descriptors has been - * executed by the DMA engine. It will run any callbacks, and then free - * the descriptors. - * - * HARDWARE STATE: idle - */ -static void fsl_chan_ld_cleanup(struct fsldma_chan *chan) -{ - struct fsl_desc_sw *desc, *_desc; - LIST_HEAD(ld_cleanup); - unsigned long flags; - - spin_lock_irqsave(&chan->desc_lock, flags); - - /* update the cookie if we have some descriptors to cleanup */ - if (!list_empty(&chan->ld_running)) { - dma_cookie_t cookie; - - desc = to_fsl_desc(chan->ld_running.prev); - cookie = desc->async_tx.cookie; - - chan->completed_cookie = cookie; - chan_dbg(chan, "completed cookie=%d\n", cookie); - } - - /* - * move the descriptors to a temporary list so we can drop the lock - * during the entire cleanup operation - */ - list_splice_tail_init(&chan->ld_running, &ld_cleanup); - - spin_unlock_irqrestore(&chan->desc_lock, flags); - - /* Run the callback for each descriptor, in order */ - list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) { - - /* Remove from the list of transactions */ - list_del(&desc->node); - - /* Run all cleanup for this descriptor */ - fsldma_cleanup_descriptor(chan, desc); - } -} - /** * fsl_chan_xfer_ld_queue - transfer any pending transactions * @chan : Freescale DMA channel * * HARDWARE STATE: idle + * LOCKING: must hold chan->desc_lock */ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) { struct fsl_desc_sw *desc; - unsigned long flags; - - spin_lock_irqsave(&chan->desc_lock, flags); /* * If the list of pending descriptors is empty, then we @@ -948,7 +898,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) */ if (list_empty(&chan->ld_pending)) { chan_dbg(chan, "no pending LDs\n"); - goto out_unlock; + return; } /* @@ -958,7 +908,7 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) */ if (!chan->idle) { chan_dbg(chan, "DMA controller still busy\n"); - goto out_unlock; + return; } /* @@ -996,9 +946,6 @@ static void fsl_chan_xfer_ld_queue(struct fsldma_chan *chan) dma_start(chan); chan->idle = false; - -out_unlock: - spin_unlock_irqrestore(&chan->desc_lock, flags); } /** @@ -1008,7 +955,11 @@ out_unlock: static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan) { struct fsldma_chan *chan = to_fsl_chan(dchan); + unsigned long flags; + + spin_lock_irqsave(&chan->desc_lock, flags); fsl_chan_xfer_ld_queue(chan); + spin_unlock_irqrestore(&chan->desc_lock, flags); } /** @@ -1109,20 +1060,53 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data) static void dma_do_tasklet(unsigned long data) { struct fsldma_chan *chan = (struct fsldma_chan *)data; + struct fsl_desc_sw *desc, *_desc; + LIST_HEAD(ld_cleanup); unsigned long flags; chan_dbg(chan, "tasklet entry\n"); - /* run all callbacks, free all used descriptors */ - fsl_chan_ld_cleanup(chan); - - /* the channel is now idle */ spin_lock_irqsave(&chan->desc_lock, flags); + + /* update the cookie if we have some descriptors to cleanup */ + if (!list_empty(&chan->ld_running)) { + dma_cookie_t cookie; + + desc = to_fsl_desc(chan->ld_running.prev); + cookie = desc->async_tx.cookie; + + chan->completed_cookie = cookie; + chan_dbg(chan, "completed_cookie=%d\n", cookie); + } + + /* + * move the descriptors to a temporary list so we can drop the lock + * during the entire cleanup operation + */ + list_splice_tail_init(&chan->ld_running, &ld_cleanup); + + /* the hardware is now idle and ready for more */ chan->idle = true; - spin_unlock_irqrestore(&chan->desc_lock, flags); - /* start any pending transactions automatically */ + /* + * Start any pending transactions automatically + * + * In the ideal case, we keep the DMA controller busy while we go + * ahead and free the descriptors below. + */ fsl_chan_xfer_ld_queue(chan); + spin_unlock_irqrestore(&chan->desc_lock, flags); + + /* Run the callback for each descriptor, in order */ + list_for_each_entry_safe(desc, _desc, &ld_cleanup, node) { + + /* Remove from the list of transactions */ + list_del(&desc->node); + + /* Run all cleanup for this descriptor */ + fsldma_cleanup_descriptor(chan, desc); + } + chan_dbg(chan, "tasklet exit\n"); } -- cgit v1.2.2 From a00ae34ac8bc8a5897d9b6b9b685c39b955b14b9 Mon Sep 17 00:00:00 2001 From: Ira Snyder Date: Thu, 3 Mar 2011 07:55:01 +0000 Subject: fsldma: make halt behave nicely on all supported controllers The original dma_halt() function set the CA (channel abort) bit on both the 83xx and 85xx controllers. This is incorrect on the 83xx, where this bit means TEM (transfer error mask) instead. The 83xx doesn't support channel abort, so we only do this operation on 85xx. Signed-off-by: Ira W. Snyder Signed-off-by: Dan Williams --- drivers/dma/fsldma.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index d300de456c90..8670a5012122 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -221,13 +221,26 @@ static void dma_halt(struct fsldma_chan *chan) u32 mode; int i; + /* read the mode register */ mode = DMA_IN(chan, &chan->regs->mr, 32); - mode |= FSL_DMA_MR_CA; - DMA_OUT(chan, &chan->regs->mr, mode, 32); - mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA); + /* + * The 85xx controller supports channel abort, which will stop + * the current transfer. On 83xx, this bit is the transfer error + * mask bit, which should not be changed. + */ + if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) { + mode |= FSL_DMA_MR_CA; + DMA_OUT(chan, &chan->regs->mr, mode, 32); + + mode &= ~FSL_DMA_MR_CA; + } + + /* stop the DMA controller */ + mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN); DMA_OUT(chan, &chan->regs->mr, mode, 32); + /* wait for the DMA controller to become idle */ for (i = 0; i < 100; i++) { if (dma_is_idle(chan)) return; -- cgit v1.2.2 From 4a765046553a88e4ec80ad84d2131b9e69ab4ab0 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Sat, 12 Mar 2011 10:02:11 +0100 Subject: cciss: hoist tag masking out of loop In process_nonindexed_cmd, hoist figuring of masked tag out of loop since it is the same throughout. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index eeed7aeb0b83..0a296c1eff4f 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -3433,14 +3433,12 @@ static inline u32 process_indexed_cmd(ctlr_info_t *h, u32 raw_tag) /* process completion of a non-indexed command */ static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag) { - u32 tag; CommandList_struct *c = NULL; __u32 busaddr_masked, tag_masked; - tag = cciss_tag_discard_error_bits(raw_tag); + tag_masked = cciss_tag_discard_error_bits(raw_tag); list_for_each_entry(c, &h->cmpQ, list) { busaddr_masked = cciss_tag_discard_error_bits(c->busaddr); - tag_masked = cciss_tag_discard_error_bits(tag); if (busaddr_masked == tag_masked) { finish_cmd(h, c, raw_tag); return next_command(h); -- cgit v1.2.2 From 0498cc2a9e81de97674adde8ced8a1462a397013 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Sat, 12 Mar 2011 10:02:16 +0100 Subject: cciss: Inform controller we are using 32-bit tags. Controller will DMA only 32-bits of the tag per command on completion if it knows we are only using 32-bit tags. Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 25 +++++++++++++++---------- drivers/block/cciss_cmd.h | 1 + 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 0a296c1eff4f..27b04a32b0c5 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -231,7 +231,7 @@ static const struct block_device_operations cciss_fops = { */ static void set_performant_mode(ctlr_info_t *h, CommandList_struct *c) { - if (likely(h->transMethod == CFGTBL_Trans_Performant)) + if (likely(h->transMethod & CFGTBL_Trans_Performant)) c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); } @@ -3175,10 +3175,13 @@ static inline u32 cciss_tag_to_index(u32 tag) return tag >> DIRECT_LOOKUP_SHIFT; } -static inline u32 cciss_tag_discard_error_bits(u32 tag) +static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag) { -#define CCISS_ERROR_BITS 0x03 - return tag & ~CCISS_ERROR_BITS; +#define CCISS_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1) +#define CCISS_SIMPLE_ERROR_BITS 0x03 + if (likely(h->transMethod & CFGTBL_Trans_Performant)) + return tag & ~CCISS_PERF_ERROR_BITS; + return tag & ~CCISS_SIMPLE_ERROR_BITS; } static inline void cciss_mark_tag_indexed(u32 *tag) @@ -3398,7 +3401,7 @@ static inline u32 next_command(ctlr_info_t *h) { u32 a; - if (unlikely(h->transMethod != CFGTBL_Trans_Performant)) + if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) return h->access.command_completed(h); if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { @@ -3436,9 +3439,9 @@ static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag) CommandList_struct *c = NULL; __u32 busaddr_masked, tag_masked; - tag_masked = cciss_tag_discard_error_bits(raw_tag); + tag_masked = cciss_tag_discard_error_bits(h, raw_tag); list_for_each_entry(c, &h->cmpQ, list) { - busaddr_masked = cciss_tag_discard_error_bits(c->busaddr); + busaddr_masked = cciss_tag_discard_error_bits(h, c->busaddr); if (busaddr_masked == tag_masked) { finish_cmd(h, c, raw_tag); return next_command(h); @@ -3790,7 +3793,8 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h) } } -static __devinit void cciss_enter_performant_mode(ctlr_info_t *h) +static __devinit void cciss_enter_performant_mode(ctlr_info_t *h, + u32 use_short_tags) { /* This is a bit complicated. There are 8 registers on * the controller which we write to to tell it 8 different @@ -3845,7 +3849,7 @@ static __devinit void cciss_enter_performant_mode(ctlr_info_t *h) writel(0, &h->transtable->RepQCtrAddrHigh32); writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32); writel(0, &h->transtable->RepQAddr0High32); - writel(CFGTBL_Trans_Performant, + writel(CFGTBL_Trans_Performant | use_short_tags, &(h->cfgtable->HostWrite.TransportRequest)); writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); @@ -3892,7 +3896,8 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) if ((h->reply_pool == NULL) || (h->blockFetchTable == NULL)) goto clean_up; - cciss_enter_performant_mode(h); + cciss_enter_performant_mode(h, + trans_support & CFGTBL_Trans_use_short_tags); /* Change the access methods to the performant access methods */ h->access = SA5_performant_access; diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index 35463d2f0ee7..cd441bef031f 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -56,6 +56,7 @@ #define CFGTBL_Trans_Simple 0x00000002l #define CFGTBL_Trans_Performant 0x00000004l +#define CFGTBL_Trans_use_short_tags 0x20000000l #define CFGTBL_BusType_Ultra2 0x00000001l #define CFGTBL_BusType_Ultra3 0x00000002l -- cgit v1.2.2 From 16011131ced8bdb317e1bf03324ca78a27fa0a1c Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Sat, 12 Mar 2011 10:02:21 +0100 Subject: cciss: Mask off error bits of c->busaddr in cmd_special_free when calling pci_free_consistent Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 27b04a32b0c5..f21116cb8b82 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -193,7 +193,7 @@ static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev, u64 *cfg_offset); static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev, unsigned long *memory_bar); - +static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag); /* performant mode helper functions */ static void calc_bucket_map(int *bucket, int num_buckets, int nsgs, @@ -1012,8 +1012,8 @@ static void cmd_special_free(ctlr_info_t *h, CommandList_struct *c) temp64.val32.upper = c->ErrDesc.Addr.upper; pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct), c->err_info, (dma_addr_t) temp64.val); - pci_free_consistent(h->pdev, sizeof(CommandList_struct), - c, (dma_addr_t) c->busaddr); + pci_free_consistent(h->pdev, sizeof(CommandList_struct), c, + (dma_addr_t) cciss_tag_discard_error_bits(h, (u32) c->busaddr)); } static inline ctlr_info_t *get_host(struct gendisk *disk) -- cgit v1.2.2 From fcab1c112ade881d884cd7b8161f7543194d12e1 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Sat, 12 Mar 2011 10:02:24 +0100 Subject: cciss: remove unnecessary casts Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index f21116cb8b82..25267e92ce31 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1529,8 +1529,7 @@ static int cciss_bigpassthru(ctlr_info_t *h, void __user *argp) return -EINVAL; if (!capable(CAP_SYS_RAWIO)) return -EPERM; - ioc = (BIG_IOCTL_Command_struct *) - kmalloc(sizeof(*ioc), GFP_KERNEL); + ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); if (!ioc) { status = -ENOMEM; goto cleanup1; -- cgit v1.2.2 From 6d9a4f9e21486fa83526a9a9fdf88b9b2cdfd299 Mon Sep 17 00:00:00 2001 From: "Stephen M. Cameron" Date: Sat, 12 Mar 2011 10:02:30 +0100 Subject: cciss: fix missed command status value CMD_UNABORTABLE and fix a nearby typo, "do" that should have been "due" Signed-off-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 11 +++++++++++ drivers/block/cciss_scsi.c | 13 +++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 25267e92ce31..9bf13988f1a2 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2691,6 +2691,10 @@ static int process_sendcmd_error(ctlr_info_t *h, CommandList_struct *c) c->Request.CDB[0]); return_status = IO_NEEDS_RETRY; break; + case CMD_UNABORTABLE: + dev_warn(&h->pdev->dev, "cmd unabortable\n"); + return_status = IO_ERROR; + break; default: dev_warn(&h->pdev->dev, "cmd 0x%02x returned " "unknown status %x\n", c->Request.CDB[0], @@ -3141,6 +3145,13 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? DID_PASSTHROUGH : DID_ERROR); break; + case CMD_UNABORTABLE: + dev_warn(&h->pdev->dev, "cmd %p unabortable\n", cmd); + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC ? + DID_PASSTHROUGH : DID_ERROR); + break; default: dev_warn(&h->pdev->dev, "cmd %p returned " "unknown status %x\n", cmd, diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 3bfbde8b4013..8fa2a2e90b9f 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -833,13 +833,18 @@ static void complete_scsi_command(CommandList_struct *c, int timeout, break; case CMD_UNSOLICITED_ABORT: cmd->result = DID_ABORT << 16; - dev_warn(&h->pdev->dev, "%p aborted do to an " + dev_warn(&h->pdev->dev, "%p aborted due to an " "unsolicited abort\n", c); break; case CMD_TIMEOUT: cmd->result = DID_TIME_OUT << 16; dev_warn(&h->pdev->dev, "%p timedout\n", c); break; + case CMD_UNABORTABLE: + cmd->result = DID_ERROR << 16; + dev_warn(&h->pdev->dev, "c %p command " + "unabortable\n", c); + break; default: cmd->result = DID_ERROR << 16; dev_warn(&h->pdev->dev, @@ -1016,11 +1021,15 @@ cciss_scsi_interpret_error(ctlr_info_t *h, CommandList_struct *c) break; case CMD_UNSOLICITED_ABORT: dev_warn(&h->pdev->dev, - "%p aborted do to an unsolicited abort\n", c); + "%p aborted due to an unsolicited abort\n", c); break; case CMD_TIMEOUT: dev_warn(&h->pdev->dev, "%p timedout\n", c); break; + case CMD_UNABORTABLE: + dev_warn(&h->pdev->dev, + "%p unabortable\n", c); + break; default: dev_warn(&h->pdev->dev, "%p returned unknown status %x\n", -- cgit v1.2.2 From b66538014f7eae121afa99ca18488fd67536a1bf Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 12 Mar 2011 13:47:51 +0100 Subject: Revert "cciss: Add missing allocation in scsi_cmd_stack_setup and corresponding deallocation" This reverts commit 978eb516a4e1a1b47163518d6f5d5e81ab27a583. The commit was broken, relying on other changes that have not been committed yet. Signed-off-by: Jens Axboe --- drivers/block/cciss_scsi.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 8fa2a2e90b9f..df793803f5ae 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -226,13 +226,6 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa) return -ENOMEM; } - stk->elem = kmalloc(sizeof(stk->elem[0]) * stk->nelems, GFP_KERNEL); - if (!stk->elem) { - pci_free_consistent(h->pdev, size, stk->pool, - stk->cmd_pool_handle); - return -1; - } - for (i=0; ielem[i] = &stk->pool[i]; stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle + @@ -262,8 +255,6 @@ scsi_cmd_stack_free(ctlr_info_t *h) pci_free_consistent(h->pdev, size, stk->pool, stk->cmd_pool_handle); stk->pool = NULL; cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE); - kfree(stk->elem); - stk->elem = NULL; } #if 0 -- cgit v1.2.2 From a97590e56d0d58e1dd262353f7cbd84e81d8e600 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 4 Mar 2011 14:52:16 -0700 Subject: intel-iommu: Unlink domain from iommu When we remove a device, we unlink the iommu from the domain, but we never do the reverse unlinking of the domain from the iommu. This means that we never clear iommu->domain_ids, eventually leading to resource exhaustion if we repeatedly bind and unbind a device to a driver. Also free empty domains to avoid a resource leak. Signed-off-by: Alex Williamson Acked-by: Donald Dutile Signed-off-by: David Woodhouse Cc: stable@kernel.org --- drivers/pci/intel-iommu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 35463ddf10a1..292f2233295e 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3260,9 +3260,15 @@ static int device_notifier(struct notifier_block *nb, if (!domain) return 0; - if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) + if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) { domain_remove_one_dev_info(domain, pdev); + if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) && + !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) && + list_empty(&domain->devices)) + domain_exit(domain); + } + return 0; } @@ -3411,6 +3417,11 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain, domain->iommu_count--; domain_update_iommu_cap(domain); spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags); + + spin_lock_irqsave(&iommu->lock, tmp_flags); + clear_bit(domain->id, iommu->domain_ids); + iommu->domains[domain->id] = NULL; + spin_unlock_irqrestore(&iommu->lock, tmp_flags); } spin_unlock_irqrestore(&device_domain_lock, flags); -- cgit v1.2.2 From 2fe9723df8e45fd247782adea244a5e653c30bf4 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 4 Mar 2011 14:52:30 -0700 Subject: intel-iommu: Fix get_domain_for_dev() error path If we run out of domain_ids and fail iommu_attach_domain(), we fall into domain_exit() without having setup enough of the domain structure for this to do anything useful. In fact, it typically runs off into the weeds walking the bogus domain->devices list. Just free the domain. Signed-off-by: Alex Williamson Acked-by: Donald Dutile Signed-off-by: David Woodhouse Cc: stable@kernel.org --- drivers/pci/intel-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 292f2233295e..5dc5d3e3508e 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1835,7 +1835,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) ret = iommu_attach_domain(domain, iommu); if (ret) { - domain_exit(domain); + free_domain_mem(domain); goto error; } -- cgit v1.2.2 From 4fc193814b3a269c1ea89aefdb56d4f957680d44 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:33:33 -0800 Subject: Input: wacom - do not send 2FGT Tablet PC events in TAP format 2FGT Tablet PC touch events were processed in _TAP_ format. Remove them so we can change to _MT_ format. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 84 ++++------------------------------------ drivers/input/tablet/wacom_wac.h | 5 +-- 2 files changed, 10 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 367fa82a607e..5488c6172621 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -675,40 +675,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 1; } - -static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx) -{ - struct input_dev *input = wacom->input; - int finger = idx + 1; - int x = le16_to_cpup((__le16 *)&data[finger * 2]) & 0x7fff; - int y = le16_to_cpup((__le16 *)&data[4 + finger * 2]) & 0x7fff; - - /* - * Work around input core suppressing "duplicate" events since - * we are abusing ABS_X/ABS_Y to transmit multi-finger data. - * This should go away once we switch to true multitouch - * protocol. - */ - if (wacom->last_finger != finger) { - if (x == input_abs_get_val(input, ABS_X)) - x++; - - if (y == input_abs_get_val(input, ABS_Y)) - y++; - } - - input_report_abs(input, ABS_X, x); - input_report_abs(input, ABS_Y, y); - input_report_abs(input, ABS_MISC, wacom->id[0]); - input_report_key(input, wacom->tool[finger], 1); - if (!idx) - input_report_key(input, BTN_TOUCH, 1); - input_event(input, EV_MSC, MSC_SERIAL, finger); - input_sync(input); - - wacom->last_finger = finger; -} - static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx) { struct input_dev *input = wacom->input; @@ -731,7 +697,6 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) wacom->tool[1] = BTN_TOOL_DOUBLETAP; wacom->id[0] = TOUCH_DEVICE_ID; - wacom->tool[2] = BTN_TOOL_TRIPLETAP; if (len != WACOM_PKGLEN_TPC1FG) { @@ -746,18 +711,6 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) input_report_key(input, wacom->tool[1], 1); input_sync(input); break; - - case WACOM_REPORT_TPC2FG: - if (data[1] & 0x01) - wacom_tpc_finger_in(wacom, data, 0); - else if (wacom->id[1] & 0x01) - wacom_tpc_touch_out(wacom, 0); - - if (data[1] & 0x02) - wacom_tpc_finger_in(wacom, data, 1); - else if (wacom->id[1] & 0x02) - wacom_tpc_touch_out(wacom, 1); - break; } } else { input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); @@ -779,47 +732,26 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) dbg("wacom_tpc_irq: received report #%d", data[0]); - if (len == WACOM_PKGLEN_TPC1FG || /* single touch */ - data[0] == WACOM_REPORT_TPC1FG || /* single touch */ - data[0] == WACOM_REPORT_TPC2FG) { /* 2FG touch */ + if (len == WACOM_PKGLEN_TPC1FG || + data[0] == WACOM_REPORT_TPC1FG) { /* single touch */ if (wacom->shared->stylus_in_proximity) { if (wacom->id[1] & 0x01) wacom_tpc_touch_out(wacom, 0); - if (wacom->id[1] & 0x02) - wacom_tpc_touch_out(wacom, 1); - wacom->id[1] = 0; return 0; } - if (len == WACOM_PKGLEN_TPC1FG) { /* with touch */ + if (len == WACOM_PKGLEN_TPC1FG) prox = data[0] & 0x01; - } else { /* with capacity */ - if (data[0] == WACOM_REPORT_TPC1FG) - /* single touch */ - prox = data[1] & 0x01; - else - /* 2FG touch data */ - prox = data[1] & 0x03; - } + else /* with capacity */ + prox = data[1] & 0x01; - if (prox) { - if (!wacom->id[1]) - wacom->last_finger = 1; + if (prox) wacom_tpc_touch_in(wacom, len); - } else { - if (data[0] == WACOM_REPORT_TPC2FG) { - /* 2FGT out-prox */ - if (wacom->id[1] & 0x01) - wacom_tpc_touch_out(wacom, 0); - - if (wacom->id[1] & 0x02) - wacom_tpc_touch_out(wacom, 1); - } else - /* one finger touch */ - wacom_tpc_touch_out(wacom, 0); + else { + wacom_tpc_touch_out(wacom, 0); wacom->id[0] = 0; } diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index b1310ec9720c..8f747dd1214e 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -93,10 +93,9 @@ struct wacom_shared { struct wacom_wac { char name[64]; unsigned char *data; - int tool[3]; - int id[3]; + int tool[2]; + int id[2]; __u32 serial[2]; - int last_finger; struct wacom_features features; struct wacom_shared *shared; struct input_dev *input; -- cgit v1.2.2 From 8aa9a9ac89baa0e423da0211e0883d28165697e0 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:34:11 -0800 Subject: Input: wacom - process pen data in its own routine So it would be easier for patch reviewers to follow the data path. Reviewed-by: Henrik Rydberg Reviewed-by: Chris Bagwell Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 73 ++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 5488c6172621..15bab99a4c7e 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -722,13 +722,47 @@ static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) } } -static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) +static int wacom_tpc_pen(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; char *data = wacom->data; struct input_dev *input = wacom->input; - int prox = 0, pressure; - int retval = 0; + int prox, pressure; + + prox = data[1] & 0x20; + + if (!wacom->shared->stylus_in_proximity) { /* first in prox */ + /* Going into proximity select tool */ + wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; + if (wacom->tool[0] == BTN_TOOL_PEN) + wacom->id[0] = STYLUS_DEVICE_ID; + else + wacom->id[0] = ERASER_DEVICE_ID; + + wacom->shared->stylus_in_proximity = true; + } + input_report_key(input, BTN_STYLUS, data[1] & 0x02); + input_report_key(input, BTN_STYLUS2, data[1] & 0x10); + input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); + input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); + pressure = ((data[7] & 0x01) << 8) | data[6]; + if (pressure < 0) + pressure = features->pressure_max + pressure + 1; + input_report_abs(input, ABS_PRESSURE, pressure); + input_report_key(input, BTN_TOUCH, data[1] & 0x05); + if (!prox) { /* out-prox */ + wacom->id[0] = 0; + wacom->shared->stylus_in_proximity = false; + } + input_report_key(input, wacom->tool[0], prox); + + return 1; +} + +static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) +{ + char *data = wacom->data; + int prox = 0; dbg("wacom_tpc_irq: received report #%d", data[0]); @@ -757,37 +791,10 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) } /* keep prox bit to send proper out-prox event */ wacom->id[1] = prox; - } else if (data[0] == WACOM_REPORT_PENABLED) { /* Penabled */ - prox = data[1] & 0x20; - - if (!wacom->shared->stylus_in_proximity) { /* first in prox */ - /* Going into proximity select tool */ - wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - if (wacom->tool[0] == BTN_TOOL_PEN) - wacom->id[0] = STYLUS_DEVICE_ID; - else - wacom->id[0] = ERASER_DEVICE_ID; + } else if (data[0] == WACOM_REPORT_PENABLED) + return wacom_tpc_pen(wacom); - wacom->shared->stylus_in_proximity = true; - } - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x10); - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - pressure = ((data[7] & 0x01) << 8) | data[6]; - if (pressure < 0) - pressure = features->pressure_max + pressure + 1; - input_report_abs(input, ABS_PRESSURE, pressure); - input_report_key(input, BTN_TOUCH, data[1] & 0x05); - if (!prox) { /* out-prox */ - wacom->id[0] = 0; - wacom->shared->stylus_in_proximity = false; - } - input_report_key(input, wacom->tool[0], prox); - input_report_abs(input, ABS_MISC, wacom->id[0]); - retval = 1; - } - return retval; + return 0; } static int wacom_bpt_touch(struct wacom_wac *wacom) -- cgit v1.2.2 From a43c7c53835ba1ff4e488806d0f8b98e9dce9b0e Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:34:42 -0800 Subject: Input: wacom - support one finger touch the touchscreen way There are two types of 1FGT devices supported in wacom_wac.c. Changing them to follow the existing touchscreen format, i.e., only report BTN_TOUCH as a valid tool type. Touch data will be ignored if pen is in proximity. This requires a touch up event sent if touch was down when pen comes in. The touch up event should be sent before any pen events are emitted. Otherwise, two pointers would race for the cursor. However, we can not send a touch up inside wacom_tpc_pen since pen and touch are on different logical port. That is why we have to check if touch is up before sending pen events. Reviewed-by: Henrik Rydberg Reviewed-by: Chris Bagwell Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 139 ++++++++++++++------------------------- drivers/input/tablet/wacom_wac.h | 1 + 2 files changed, 50 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 15bab99a4c7e..adf8946e8f0d 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -675,51 +675,37 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 1; } -static void wacom_tpc_touch_out(struct wacom_wac *wacom, int idx) -{ - struct input_dev *input = wacom->input; - int finger = idx + 1; - - input_report_abs(input, ABS_X, 0); - input_report_abs(input, ABS_Y, 0); - input_report_abs(input, ABS_MISC, 0); - input_report_key(input, wacom->tool[finger], 0); - if (!idx) - input_report_key(input, BTN_TOUCH, 0); - input_event(input, EV_MSC, MSC_SERIAL, finger); - input_sync(input); -} - -static void wacom_tpc_touch_in(struct wacom_wac *wacom, size_t len) +static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) { char *data = wacom->data; struct input_dev *input = wacom->input; + bool prox; + int x = 0, y = 0; - wacom->tool[1] = BTN_TOOL_DOUBLETAP; - wacom->id[0] = TOUCH_DEVICE_ID; + if (!wacom->shared->stylus_in_proximity) { + if (len == WACOM_PKGLEN_TPC1FG) { + prox = data[0] & 0x01; + x = get_unaligned_le16(&data[1]); + y = get_unaligned_le16(&data[3]); + } else { /* with capacity */ + prox = data[1] & 0x01; + x = le16_to_cpup((__le16 *)&data[2]); + y = le16_to_cpup((__le16 *)&data[4]); + } + } else + /* force touch out when pen is in prox */ + prox = 0; - if (len != WACOM_PKGLEN_TPC1FG) { + if (prox) { + input_report_abs(input, ABS_X, x); + input_report_abs(input, ABS_Y, y); + } + input_report_key(input, BTN_TOUCH, prox); - switch (data[0]) { + /* keep touch state for pen events */ + wacom->shared->touch_down = prox; - case WACOM_REPORT_TPC1FG: - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - input_report_abs(input, ABS_PRESSURE, le16_to_cpup((__le16 *)&data[6])); - input_report_key(input, BTN_TOUCH, le16_to_cpup((__le16 *)&data[6])); - input_report_abs(input, ABS_MISC, wacom->id[0]); - input_report_key(input, wacom->tool[1], 1); - input_sync(input); - break; - } - } else { - input_report_abs(input, ABS_X, get_unaligned_le16(&data[1])); - input_report_abs(input, ABS_Y, get_unaligned_le16(&data[3])); - input_report_key(input, BTN_TOUCH, 1); - input_report_abs(input, ABS_MISC, wacom->id[1]); - input_report_key(input, wacom->tool[1], 1); - input_sync(input); - } + return 1; } static int wacom_tpc_pen(struct wacom_wac *wacom) @@ -727,71 +713,43 @@ static int wacom_tpc_pen(struct wacom_wac *wacom) struct wacom_features *features = &wacom->features; char *data = wacom->data; struct input_dev *input = wacom->input; - int prox, pressure; - - prox = data[1] & 0x20; + int pressure; + bool prox = data[1] & 0x20; - if (!wacom->shared->stylus_in_proximity) { /* first in prox */ + if (!wacom->shared->stylus_in_proximity) /* first in prox */ /* Going into proximity select tool */ wacom->tool[0] = (data[1] & 0x0c) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; - if (wacom->tool[0] == BTN_TOOL_PEN) - wacom->id[0] = STYLUS_DEVICE_ID; - else - wacom->id[0] = ERASER_DEVICE_ID; - wacom->shared->stylus_in_proximity = true; - } - input_report_key(input, BTN_STYLUS, data[1] & 0x02); - input_report_key(input, BTN_STYLUS2, data[1] & 0x10); - input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); - input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); - pressure = ((data[7] & 0x01) << 8) | data[6]; - if (pressure < 0) - pressure = features->pressure_max + pressure + 1; - input_report_abs(input, ABS_PRESSURE, pressure); - input_report_key(input, BTN_TOUCH, data[1] & 0x05); - if (!prox) { /* out-prox */ - wacom->id[0] = 0; - wacom->shared->stylus_in_proximity = false; + /* keep pen state for touch events */ + wacom->shared->stylus_in_proximity = prox; + + /* send pen events only when touch is up or forced out */ + if (!wacom->shared->touch_down) { + input_report_key(input, BTN_STYLUS, data[1] & 0x02); + input_report_key(input, BTN_STYLUS2, data[1] & 0x10); + input_report_abs(input, ABS_X, le16_to_cpup((__le16 *)&data[2])); + input_report_abs(input, ABS_Y, le16_to_cpup((__le16 *)&data[4])); + pressure = ((data[7] & 0x01) << 8) | data[6]; + if (pressure < 0) + pressure = features->pressure_max + pressure + 1; + input_report_abs(input, ABS_PRESSURE, pressure); + input_report_key(input, BTN_TOUCH, data[1] & 0x05); + input_report_key(input, wacom->tool[0], prox); + return 1; } - input_report_key(input, wacom->tool[0], prox); - return 1; + return 0; } static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) { char *data = wacom->data; - int prox = 0; dbg("wacom_tpc_irq: received report #%d", data[0]); - if (len == WACOM_PKGLEN_TPC1FG || - data[0] == WACOM_REPORT_TPC1FG) { /* single touch */ - - if (wacom->shared->stylus_in_proximity) { - if (wacom->id[1] & 0x01) - wacom_tpc_touch_out(wacom, 0); - - wacom->id[1] = 0; - return 0; - } - - if (len == WACOM_PKGLEN_TPC1FG) - prox = data[0] & 0x01; - else /* with capacity */ - prox = data[1] & 0x01; - - if (prox) - wacom_tpc_touch_in(wacom, len); - else { - wacom_tpc_touch_out(wacom, 0); - - wacom->id[0] = 0; - } - /* keep prox bit to send proper out-prox event */ - wacom->id[1] = prox; - } else if (data[0] == WACOM_REPORT_PENABLED) + if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG) + return wacom_tpc_single_touch(wacom, len); + else if (data[0] == WACOM_REPORT_PENABLED) return wacom_tpc_pen(wacom); return 0; @@ -1172,6 +1130,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, /* fall through */ case TABLETPC: + __clear_bit(ABS_MISC, input_dev->absbit); + if (features->device_type == BTN_TOOL_DOUBLETAP || features->device_type == BTN_TOOL_TRIPLETAP) { input_abs_set_res(input_dev, ABS_X, @@ -1180,7 +1140,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_abs_set_res(input_dev, ABS_Y, wacom_calculate_touch_res(features->y_max, features->y_phy)); - __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); } if (features->device_type != BTN_TOOL_PEN) diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 8f747dd1214e..835f756b150c 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -88,6 +88,7 @@ struct wacom_features { struct wacom_shared { bool stylus_in_proximity; + bool touch_down; }; struct wacom_wac { -- cgit v1.2.2 From 84eb5aa6ccb2a62c40722b8c5fb1338ea12155a3 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 12 Mar 2011 20:35:18 -0800 Subject: Input: wacom - support 2FGT in MT format Reviewed-by: Henrik Rydberg Reviewed-by: Chris Bagwell Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_sys.c | 12 ++++---- drivers/input/tablet/wacom_wac.c | 59 ++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index fc381498b798..b97665f9765e 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -193,16 +193,16 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi case HID_USAGE_X: if (usage == WCM_DESKTOP) { if (finger) { - features->device_type = BTN_TOOL_DOUBLETAP; + features->device_type = BTN_TOOL_FINGER; if (features->type == TABLETPC2FG) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_TPC2FG; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; } if (features->type == BAMBOO_PT) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_BBTOUCH; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; features->x_phy = get_unaligned_le16(&report[i + 5]); features->x_max = @@ -241,11 +241,11 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi case HID_USAGE_Y: if (usage == WCM_DESKTOP) { if (finger) { - features->device_type = BTN_TOOL_DOUBLETAP; + features->device_type = BTN_TOOL_FINGER; if (features->type == TABLETPC2FG) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_TPC2FG; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; features->y_max = get_unaligned_le16(&report[i + 3]); features->y_phy = @@ -254,7 +254,7 @@ static int wacom_parse_hid(struct usb_interface *intf, struct hid_descriptor *hi } else if (features->type == BAMBOO_PT) { /* need to reset back */ features->pktlen = WACOM_PKGLEN_BBTOUCH; - features->device_type = BTN_TOOL_TRIPLETAP; + features->device_type = BTN_TOOL_DOUBLETAP; features->y_phy = get_unaligned_le16(&report[i + 3]); features->y_max = diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index adf8946e8f0d..5597637cfd41 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -675,6 +675,37 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) return 1; } +static int wacom_tpc_mt_touch(struct wacom_wac *wacom) +{ + struct input_dev *input = wacom->input; + unsigned char *data = wacom->data; + int contact_with_no_pen_down_count = 0; + int i; + + for (i = 0; i < 2; i++) { + int p = data[1] & (1 << i); + bool touch = p && !wacom->shared->stylus_in_proximity; + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); + if (touch) { + int x = le16_to_cpup((__le16 *)&data[i * 2 + 2]) & 0x7fff; + int y = le16_to_cpup((__le16 *)&data[i * 2 + 6]) & 0x7fff; + + input_report_abs(input, ABS_MT_POSITION_X, x); + input_report_abs(input, ABS_MT_POSITION_Y, y); + contact_with_no_pen_down_count++; + } + } + + /* keep touch state for pen event */ + wacom->shared->touch_down = (contact_with_no_pen_down_count > 0); + + input_mt_report_pointer_emulation(input, true); + + return 1; +} + static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) { char *data = wacom->data; @@ -749,6 +780,8 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG) return wacom_tpc_single_touch(wacom, len); + else if (data[0] == WACOM_REPORT_TPC2FG) + return wacom_tpc_mt_touch(wacom); else if (data[0] == WACOM_REPORT_PENABLED) return wacom_tpc_pen(wacom); @@ -975,7 +1008,7 @@ void wacom_setup_device_quirks(struct wacom_features *features) { /* touch device found but size is not defined. use default */ - if (features->device_type == BTN_TOOL_DOUBLETAP && !features->x_max) { + if (features->device_type == BTN_TOOL_FINGER && !features->x_max) { features->x_max = 1023; features->y_max = 1023; } @@ -987,7 +1020,7 @@ void wacom_setup_device_quirks(struct wacom_features *features) /* quirks for bamboo touch */ if (features->type == BAMBOO_PT && - features->device_type == BTN_TOOL_TRIPLETAP) { + features->device_type == BTN_TOOL_DOUBLETAP) { features->x_max <<= 5; features->y_max <<= 5; features->x_fuzz <<= 5; @@ -1123,28 +1156,30 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, break; case TABLETPC2FG: - if (features->device_type == BTN_TOOL_TRIPLETAP) { - __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); - input_set_capability(input_dev, EV_MSC, MSC_SERIAL); + if (features->device_type == BTN_TOOL_DOUBLETAP) { + + input_mt_init_slots(input_dev, 2); + input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, features->y_max, 0, 0); } /* fall through */ case TABLETPC: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type == BTN_TOOL_DOUBLETAP || - features->device_type == BTN_TOOL_TRIPLETAP) { + if (features->device_type != BTN_TOOL_PEN) { input_abs_set_res(input_dev, ABS_X, wacom_calculate_touch_res(features->x_max, features->x_phy)); input_abs_set_res(input_dev, ABS_Y, wacom_calculate_touch_res(features->y_max, features->y_phy)); - } - - if (features->device_type != BTN_TOOL_PEN) break; /* no need to process stylus stuff */ - + } /* fall through */ case PL: @@ -1162,7 +1197,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type == BTN_TOOL_TRIPLETAP) { + if (features->device_type == BTN_TOOL_DOUBLETAP) { __set_bit(BTN_LEFT, input_dev->keybit); __set_bit(BTN_FORWARD, input_dev->keybit); __set_bit(BTN_BACK, input_dev->keybit); -- cgit v1.2.2 From 47340bd9fefb571888836da942b5aee0e85e959c Mon Sep 17 00:00:00 2001 From: Andy Botting Date: Sat, 12 Mar 2011 20:27:22 -0800 Subject: Input: bcm5974 - add support for MacBookPro8 This patch add multitouch support for the MacBookPro8,1 and MacBookPro8,2 models. Cc: stable@kernel.org Signed-off-by: Andy Botting Signed-off-by: Henrik Rydberg Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-apple.c | 6 ++++++ drivers/hid/hid-core.c | 6 ++++++ drivers/hid/hid-ids.h | 3 +++ drivers/input/mouse/bcm5974.c | 20 ++++++++++++++++++++ 4 files changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 61aa71233392..b85744fe8464 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -481,6 +481,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index d678cf3d33d5..48a0a2f3e072 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1302,6 +1302,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, @@ -1801,6 +1804,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 92a0d61a7379..ca32ecbdce06 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -103,6 +103,9 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 +#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 +#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 +#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index ee82851afe3e..318531424848 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -63,6 +63,10 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 #define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 +/* Macbook8 (unibody, March 2011) */ +#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 +#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 +#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 #define BCM5974_DEVICE(prod) { \ .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ @@ -96,6 +100,10 @@ static const struct usb_device_id bcm5974_table[] = { BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO), BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS), + /* MacbookPro8 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), /* Terminating entry */ {} }; @@ -274,6 +282,18 @@ static const struct bcm5974_config bcm5974_config_table[] = { { DIM_X, DIM_X / SN_COORD, -4616, 5112 }, { DIM_Y, DIM_Y / SN_COORD, -142, 5234 } }, + { + USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING5_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING5_JIS, + HAS_INTEGRATED_BUTTON, + 0x84, sizeof(struct bt_data), + 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4415, 5050 }, + { DIM_Y, DIM_Y / SN_COORD, -55, 6680 } + }, {} }; -- cgit v1.2.2 From 23c483d29fcbc35591131019660b2630cc6629ae Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 12 Mar 2011 20:48:34 -0800 Subject: Input: wm831x-ts - default pressure measurements on tslib expects pressure measurements so enable them by default for better compatibility. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 1022f715d3c2..3db0c29f3b05 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -225,7 +225,10 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) else wm831x_ts->pd_irq = platform_get_irq_byname(pdev, "TCHPD"); - wm831x_ts->pressure = pdata && pdata->pressure; + if (pdata) + wm831x_ts->pressure = pdata->pressure; + else + wm831x_ts->pressure = true; /* Five wire touchscreens can't report pressure */ if (pdata && pdata->fivewire) { -- cgit v1.2.2 From cfbdab951369f15de890597530076bf0119361be Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 17 Jan 2011 16:10:59 +0800 Subject: vhost-net: check the support of mergeable buffer outside the receive loop No need to check the support of mergeable buffer inside the recevie loop as the whole handle_rx()_xx is in the read critical region. So this patch move it ahead of the receiving loop. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 59dad9fe52dd..9f57cd45fe8f 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -411,7 +411,7 @@ static void handle_rx_mergeable(struct vhost_net *net) .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE }; size_t total_len = 0; - int err, headcount; + int err, headcount, mergeable; size_t vhost_hlen, sock_hlen; size_t vhost_len, sock_len; /* TODO: check that we are running from vhost_worker? */ @@ -427,6 +427,7 @@ static void handle_rx_mergeable(struct vhost_net *net) vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ? vq->log : NULL; + mergeable = vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF); while ((sock_len = peek_head_len(sock->sk))) { sock_len += sock_hlen; @@ -476,7 +477,7 @@ static void handle_rx_mergeable(struct vhost_net *net) break; } /* TODO: Should check and handle checksum. */ - if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF) && + if (likely(mergeable) && memcpy_toiovecend(vq->hdr, (unsigned char *)&headcount, offsetof(typeof(hdr), num_buffers), sizeof hdr.num_buffers)) { -- cgit v1.2.2 From 94249369e9930276e30087da205349a55478cbb5 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 17 Jan 2011 16:11:08 +0800 Subject: vhost-net: Unify the code of mergeable and big buffer handling Codes duplication were found between the handling of mergeable and big buffers, so this patch tries to unify them. This could be easily done by adding a quota to the get_rx_bufs() which is used to limit the number of buffers it returns (for mergeable buffer, the quota is simply UIO_MAXIOV, for big buffers, the quota is just 1), and then the previous handle_rx_mergeable() could be resued also for big buffers. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 128 +++------------------------------------------------- 1 file changed, 7 insertions(+), 121 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9f57cd45fe8f..0329c411bbf1 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -229,6 +229,7 @@ static int peek_head_len(struct sock *sk) * @iovcount - returned count of io vectors we fill * @log - vhost log * @log_num - log offset + * @quota - headcount quota, 1 for big buffer * returns number of buffer heads allocated, negative on error */ static int get_rx_bufs(struct vhost_virtqueue *vq, @@ -236,7 +237,8 @@ static int get_rx_bufs(struct vhost_virtqueue *vq, int datalen, unsigned *iovcount, struct vhost_log *log, - unsigned *log_num) + unsigned *log_num, + unsigned int quota) { unsigned int out, in; int seg = 0; @@ -244,7 +246,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq, unsigned d; int r, nlogs = 0; - while (datalen > 0) { + while (datalen > 0 && headcount < quota) { if (unlikely(seg >= UIO_MAXIOV)) { r = -ENOBUFS; goto err; @@ -284,116 +286,7 @@ err: /* Expects to be always run from workqueue - which acts as * read-size critical section for our kind of RCU. */ -static void handle_rx_big(struct vhost_net *net) -{ - struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; - unsigned out, in, log, s; - int head; - struct vhost_log *vq_log; - struct msghdr msg = { - .msg_name = NULL, - .msg_namelen = 0, - .msg_control = NULL, /* FIXME: get and handle RX aux data. */ - .msg_controllen = 0, - .msg_iov = vq->iov, - .msg_flags = MSG_DONTWAIT, - }; - struct virtio_net_hdr hdr = { - .flags = 0, - .gso_type = VIRTIO_NET_HDR_GSO_NONE - }; - size_t len, total_len = 0; - int err; - size_t hdr_size; - /* TODO: check that we are running from vhost_worker? */ - struct socket *sock = rcu_dereference_check(vq->private_data, 1); - - if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) - return; - - mutex_lock(&vq->mutex); - vhost_disable_notify(vq); - hdr_size = vq->vhost_hlen; - - vq_log = unlikely(vhost_has_feature(&net->dev, VHOST_F_LOG_ALL)) ? - vq->log : NULL; - - for (;;) { - head = vhost_get_vq_desc(&net->dev, vq, vq->iov, - ARRAY_SIZE(vq->iov), - &out, &in, - vq_log, &log); - /* On error, stop handling until the next kick. */ - if (unlikely(head < 0)) - break; - /* OK, now we need to know about added descriptors. */ - if (head == vq->num) { - if (unlikely(vhost_enable_notify(vq))) { - /* They have slipped one in as we were - * doing that: check again. */ - vhost_disable_notify(vq); - continue; - } - /* Nothing new? Wait for eventfd to tell us - * they refilled. */ - break; - } - /* We don't need to be notified again. */ - if (out) { - vq_err(vq, "Unexpected descriptor format for RX: " - "out %d, int %d\n", - out, in); - break; - } - /* Skip header. TODO: support TSO/mergeable rx buffers. */ - s = move_iovec_hdr(vq->iov, vq->hdr, hdr_size, in); - msg.msg_iovlen = in; - len = iov_length(vq->iov, in); - /* Sanity check */ - if (!len) { - vq_err(vq, "Unexpected header len for RX: " - "%zd expected %zd\n", - iov_length(vq->hdr, s), hdr_size); - break; - } - err = sock->ops->recvmsg(NULL, sock, &msg, - len, MSG_DONTWAIT | MSG_TRUNC); - /* TODO: Check specific error and bomb out unless EAGAIN? */ - if (err < 0) { - vhost_discard_vq_desc(vq, 1); - break; - } - /* TODO: Should check and handle checksum. */ - if (err > len) { - pr_debug("Discarded truncated rx packet: " - " len %d > %zd\n", err, len); - vhost_discard_vq_desc(vq, 1); - continue; - } - len = err; - err = memcpy_toiovec(vq->hdr, (unsigned char *)&hdr, hdr_size); - if (err) { - vq_err(vq, "Unable to write vnet_hdr at addr %p: %d\n", - vq->iov->iov_base, err); - break; - } - len += hdr_size; - vhost_add_used_and_signal(&net->dev, vq, head, len); - if (unlikely(vq_log)) - vhost_log_write(vq, vq_log, log, len); - total_len += len; - if (unlikely(total_len >= VHOST_NET_WEIGHT)) { - vhost_poll_queue(&vq->poll); - break; - } - } - - mutex_unlock(&vq->mutex); -} - -/* Expects to be always run from workqueue - which acts as - * read-size critical section for our kind of RCU. */ -static void handle_rx_mergeable(struct vhost_net *net) +static void handle_rx(struct vhost_net *net) { struct vhost_virtqueue *vq = &net->dev.vqs[VHOST_NET_VQ_RX]; unsigned uninitialized_var(in), log; @@ -433,7 +326,8 @@ static void handle_rx_mergeable(struct vhost_net *net) sock_len += sock_hlen; vhost_len = sock_len + vhost_hlen; headcount = get_rx_bufs(vq, vq->heads, vhost_len, - &in, vq_log, &log); + &in, vq_log, &log, + likely(mergeable) ? UIO_MAXIOV : 1); /* On error, stop handling until the next kick. */ if (unlikely(headcount < 0)) break; @@ -499,14 +393,6 @@ static void handle_rx_mergeable(struct vhost_net *net) mutex_unlock(&vq->mutex); } -static void handle_rx(struct vhost_net *net) -{ - if (vhost_has_feature(&net->dev, VIRTIO_NET_F_MRG_RXBUF)) - handle_rx_mergeable(net); - else - handle_rx_big(net); -} - static void handle_tx_kick(struct vhost_work *work) { struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue, -- cgit v1.2.2 From 783e3988544b94ff3918666b9f36866ac547fba1 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 17 Jan 2011 16:11:17 +0800 Subject: vhost: lock receive queue, not the socket vhost takes a sock lock to try and prevent the skb from being pulled from the receive queue after skb_peek. However this is not the right lock to use for that, sk_receive_queue.lock is. Fix that up. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 0329c411bbf1..57203014c457 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -213,12 +213,13 @@ static int peek_head_len(struct sock *sk) { struct sk_buff *head; int len = 0; + unsigned long flags; - lock_sock(sk); + spin_lock_irqsave(&sk->sk_receive_queue.lock, flags); head = skb_peek(&sk->sk_receive_queue); - if (head) + if (likely(head)) len = head->len; - release_sock(sk); + spin_unlock_irqrestore(&sk->sk_receive_queue.lock, flags); return len; } -- cgit v1.2.2 From de4d768a428d9de943dd6dc82bcd61742955cb6e Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 13 Mar 2011 23:00:52 +0200 Subject: vhost-net: remove unlocked use of receive_queue Use of skb_queue_empty(&sock->sk->sk_receive_queue) without taking the sk_receive_queue.lock is unsafe or useless. Take it out. Reported-by: Eric Dumazet Signed-off-by: Michael S. Tsirkin --- drivers/vhost/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 57203014c457..2f7c76a85e53 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -311,7 +311,7 @@ static void handle_rx(struct vhost_net *net) /* TODO: check that we are running from vhost_worker? */ struct socket *sock = rcu_dereference_check(vq->private_data, 1); - if (!sock || skb_queue_empty(&sock->sk->sk_receive_queue)) + if (!sock) return; mutex_lock(&vq->mutex); -- cgit v1.2.2 From bd7e4e85f3b8e5c7ea2f09d0b3350b264e339a14 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Sun, 13 Mar 2011 23:34:59 -0700 Subject: Input: add Atmel AT42QT1070 keypad driver The AT42QT1070 QTouch sensor supports up to 7 keys. The driver has been tested on Atmel AT91SAM9M10-G45-EK board, and it should work fine on other platforms. Signed-off-by: Bo Shen Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/Kconfig | 10 ++ drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/qt1070.c | 276 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/input/keyboard/qt1070.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c7a92028f450..b16bed038f72 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -112,6 +112,16 @@ config KEYBOARD_ATKBD_RDI_KEYCODES right-hand column will be interpreted as the key shown in the left-hand column. +config KEYBOARD_QT1070 + tristate "Atmel AT42QT1070 Touch Sensor Chip" + depends on I2C + help + Say Y here if you want to use Atmel AT42QT1070 QTouch + Sensor chip as input device. + + To compile this driver as a module, choose M here: + the module will be called qt1070 + config KEYBOARD_QT2160 tristate "Atmel AT42QT2160 Touch Sensor Chip" depends on I2C && EXPERIMENTAL diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 468c627a2844..878e6c20deb0 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o +obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c new file mode 100644 index 000000000000..fba8404c7297 --- /dev/null +++ b/drivers/input/keyboard/qt1070.c @@ -0,0 +1,276 @@ +/* + * Atmel AT42QT1070 QTouch Sensor Controller + * + * Copyright (C) 2011 Atmel + * + * Authors: Bo Shen + * + * Base on AT42QT2160 driver by: + * Raphael Derosso Pereira + * Copyright (C) 2009 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Address for each register */ +#define CHIP_ID 0x00 +#define QT1070_CHIP_ID 0x2E + +#define FW_VERSION 0x01 +#define QT1070_FW_VERSION 0x15 + +#define DET_STATUS 0x02 + +#define KEY_STATUS 0x03 + +/* Calibrate */ +#define CALIBRATE_CMD 0x38 +#define QT1070_CAL_TIME 200 + +/* Reset */ +#define RESET 0x39 +#define QT1070_RESET_TIME 255 + +/* AT42QT1070 support up to 7 keys */ +static const unsigned short qt1070_key2code[] = { + KEY_0, KEY_1, KEY_2, KEY_3, + KEY_4, KEY_5, KEY_6, +}; + +struct qt1070_data { + struct i2c_client *client; + struct input_dev *input; + unsigned int irq; + unsigned short keycodes[ARRAY_SIZE(qt1070_key2code)]; + u8 last_keys; +}; + +static int qt1070_read(struct i2c_client *client, u8 reg) +{ + int ret; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + dev_err(&client->dev, + "can not read register, returned %d\n", ret); + + return ret; +} + +static int qt1070_write(struct i2c_client *client, u8 reg, u8 data) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + dev_err(&client->dev, + "can not write register, returned %d\n", ret); + + return ret; +} + +static bool __devinit qt1070_identify(struct i2c_client *client) +{ + int id, ver; + + /* Read Chip ID */ + id = qt1070_read(client, CHIP_ID); + if (id != QT1070_CHIP_ID) { + dev_err(&client->dev, "ID %d not supported\n", id); + return false; + } + + /* Read firmware version */ + ver = qt1070_read(client, FW_VERSION); + if (ver < 0) { + dev_err(&client->dev, "could not read the firmware version\n"); + return false; + } + + dev_info(&client->dev, "AT42QT1070 firmware version %x\n", ver); + + return true; +} + +static irqreturn_t qt1070_interrupt(int irq, void *dev_id) +{ + struct qt1070_data *data = dev_id; + struct i2c_client *client = data->client; + struct input_dev *input = data->input; + int i; + u8 new_keys, keyval, mask = 0x01; + + /* Read the detected status register, thus clearing interrupt */ + qt1070_read(client, DET_STATUS); + + /* Read which key changed */ + new_keys = qt1070_read(client, KEY_STATUS); + + for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) { + keyval = new_keys & mask; + if ((data->last_keys & mask) != keyval) + input_report_key(input, data->keycodes[i], keyval); + mask <<= 1; + } + input_sync(input); + + data->last_keys = new_keys; + return IRQ_HANDLED; +} + +static int __devinit qt1070_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct qt1070_data *data; + struct input_dev *input; + int i; + int err; + + err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); + if (!err) { + dev_err(&client->dev, "%s adapter not supported\n", + dev_driver_string(&client->adapter->dev)); + return -ENODEV; + } + + if (!client->irq) { + dev_err(&client->dev, "please assign the irq to this device\n"); + return -EINVAL; + } + + /* Identify the qt1070 chip */ + if (!qt1070_identify(client)) + return -ENODEV; + + data = kzalloc(sizeof(struct qt1070_data), GFP_KERNEL); + input = input_allocate_device(); + if (!data || !input) { + dev_err(&client->dev, "insufficient memory\n"); + err = -ENOMEM; + goto err_free_mem; + } + + data->client = client; + data->input = input; + data->irq = client->irq; + + input->name = "AT42QT1070 QTouch Sensor"; + input->dev.parent = &client->dev; + input->id.bustype = BUS_I2C; + + /* Add the keycode */ + input->keycode = data->keycodes; + input->keycodesize = sizeof(data->keycodes[0]); + input->keycodemax = ARRAY_SIZE(qt1070_key2code); + + __set_bit(EV_KEY, input->evbit); + + for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) { + data->keycodes[i] = qt1070_key2code[i]; + __set_bit(qt1070_key2code[i], input->keybit); + } + + /* Calibrate device */ + qt1070_write(client, CALIBRATE_CMD, 1); + msleep(QT1070_CAL_TIME); + + /* Soft reset */ + qt1070_write(client, RESET, 1); + msleep(QT1070_RESET_TIME); + + err = request_threaded_irq(client->irq, NULL, qt1070_interrupt, + IRQF_TRIGGER_NONE, client->dev.driver->name, data); + if (err) { + dev_err(&client->dev, "fail to request irq\n"); + goto err_free_mem; + } + + /* Register the input device */ + err = input_register_device(data->input); + if (err) { + dev_err(&client->dev, "Failed to register input device\n"); + goto err_free_irq; + } + + i2c_set_clientdata(client, data); + + /* Read to clear the chang line */ + qt1070_read(client, DET_STATUS); + + return 0; + +err_free_irq: + free_irq(client->irq, data); +err_free_mem: + input_free_device(input); + kfree(data); + return err; +} + +static int __devexit qt1070_remove(struct i2c_client *client) +{ + struct qt1070_data *data = i2c_get_clientdata(client); + + /* Release IRQ */ + free_irq(client->irq, data); + + input_unregister_device(data->input); + kfree(data); + + i2c_set_clientdata(client, NULL); + + return 0; +} + +static const struct i2c_device_id qt1070_id[] = { + { "qt1070", 0 }, + { }, +}; + +static struct i2c_driver qt1070_driver = { + .driver = { + .name = "qt1070", + .owner = THIS_MODULE, + }, + .id_table = qt1070_id, + .probe = qt1070_probe, + .remove = __devexit_p(qt1070_remove), +}; + +static int __init qt1070_init(void) +{ + return i2c_add_driver(&qt1070_driver); +} +module_init(qt1070_init); + +static void __exit qt1070_exit(void) +{ + i2c_del_driver(&qt1070_driver); +} +module_exit(qt1070_exit); + +MODULE_AUTHOR("Bo Shen "); +MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From ba02fa37de80bea10d706f39f076dd848348320a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 11 Mar 2011 09:28:06 +0200 Subject: HACK: OMAP: DSS2: VENC: disable VENC on OMAP4 to prevent crash Something seems to be wrong with OMAP4 & VENC, and register access fails in omap_venchw_probe(). This patch skips venc driver registration on OMAP4, thus circumventing the problem for now. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/venc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 43009e57cd3e..8e35a5bae429 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -769,10 +769,16 @@ static struct platform_driver omap_venchw_driver = { int venc_init_platform_driver(void) { + if (cpu_is_omap44xx()) + return 0; + return platform_driver_register(&omap_venchw_driver); } void venc_uninit_platform_driver(void) { + if (cpu_is_omap44xx()) + return; + return platform_driver_unregister(&omap_venchw_driver); } -- cgit v1.2.2 From b6258fc1feabda868694ad5fdc7ca8edf3ef30ec Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sat, 26 Feb 2011 15:08:35 +0100 Subject: firewire: ohci: omit IntEvent.busReset check rom AT queueing Since commit 82b662dc4102 "flush AT contexts after bus reset for OHCI 1.2", the driver takes care of any AT packets that were enqueued during a bus reset phase. The check from commit 76f73ca1b291 is therefore no longer necessary and the MMIO read can be avoided. Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index c0572283b93e..8f1e3ce930d6 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1329,21 +1329,8 @@ static int at_context_queue_packet(struct context *ctx, DESCRIPTOR_IRQ_ALWAYS | DESCRIPTOR_BRANCH_ALWAYS); - /* - * If the controller and packet generations don't match, we need to - * bail out and try again. If IntEvent.busReset is set, the AT context - * is halted, so appending to the context and trying to run it is - * futile. Most controllers do the right thing and just flush the AT - * queue (per section 7.2.3.2 of the OHCI 1.1 specification), but - * some controllers (like a JMicron JMB381 PCI-e) misbehave and wind - * up stalling out. So we just bail out in software and try again - * later, and everyone is happy. - * FIXME: Test of IntEvent.busReset may no longer be necessary since we - * flush AT queues in bus_reset_tasklet. - * FIXME: Document how the locking works. - */ - if (ohci->generation != packet->generation || - reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { + /* FIXME: Document how the locking works. */ + if (ohci->generation != packet->generation) { if (packet->payload_mapped) dma_unmap_single(ohci->card.device, payload_bus, packet->payload_length, DMA_TO_DEVICE); -- cgit v1.2.2 From d838d2c09af0820e306e3e9e31f97e873823b0b4 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Fri, 11 Mar 2011 04:17:27 +0300 Subject: firewire: ohci: Misleading kfree in ohci.c::pci_probe/remove It seems drivers/firewire/ohci.c is making some optimistic assumptions about struct fw_ohci and that member "card" will always remain the first member of the struct. Plus it's probably going to confuse a lot of static code analyzers too. So I wonder if there is a good reason not to free the ohci struct just like it was allocated instead of the tricky &ohci->card way? Signed-off-by: Oleg Drokin It is perhaps just a rudiment from before mainline submission of the driver. Signed-off-by: Stefan Richter --- drivers/firewire/ohci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 8f1e3ce930d6..f903d7b6f34a 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3309,7 +3309,7 @@ static int __devinit pci_probe(struct pci_dev *dev, fail_disable: pci_disable_device(dev); fail_free: - kfree(&ohci->card); + kfree(ohci); pmac_ohci_off(dev); fail: if (err == -ENOMEM) @@ -3353,7 +3353,7 @@ static void pci_remove(struct pci_dev *dev) pci_iounmap(dev, ohci->registers); pci_release_region(dev, 0); pci_disable_device(dev); - kfree(&ohci->card); + kfree(ohci); pmac_ohci_off(dev); fw_notify("Removed fw-ohci device.\n"); -- cgit v1.2.2 From e7cbb90ad244b9d3ba5c6d57aec05d6c73df0a98 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 14 Mar 2011 21:39:09 -0700 Subject: Input: wm831x-ts - ensure the controller is in a known state on open Explicitly set all the enable bits when opening the device just in case something left the device in an unexpected state. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 3db0c29f3b05..6ae054f8e0aa 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -167,7 +167,9 @@ static int wm831x_ts_input_open(struct input_dev *idev) struct wm831x *wm831x = wm831x_ts->wm831x; wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, - WM831X_TCH_ENA, WM831X_TCH_ENA); + WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | + WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | + WM831X_TCH_Z_ENA, WM831X_TCH_ENA); wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_CVT_ENA, WM831X_TCH_CVT_ENA); -- cgit v1.2.2 From 979a72dad9c6649486e35a84324af8e81936af03 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 14 Mar 2011 21:41:34 -0700 Subject: Input: atmel_mxt_ts - remove firmware version check Atmel touchscreen chips have different firmware version with each chip, so we cannot distinguish attribute of chip by firmware version. Signed-off-by: Joonyoung Shim Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 6264ba80c38c..0986fa46e9df 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -60,11 +60,11 @@ #define MXT_PROCG_NOISE 22 #define MXT_PROCI_ONETOUCH 24 #define MXT_PROCI_TWOTOUCH 27 -#define MXT_SPT_COMMSCONFIG 18 /* firmware ver 21 over */ +#define MXT_SPT_COMMSCONFIG 18 #define MXT_SPT_GPIOPWM 19 #define MXT_SPT_SELFTEST 25 #define MXT_SPT_CTECONFIG 28 -#define MXT_SPT_USERDATA 38 /* firmware ver 21 over */ +#define MXT_SPT_USERDATA 38 /* MXT_GEN_COMMAND field */ #define MXT_COMMAND_RESET 0 @@ -115,7 +115,7 @@ #define MXT_TOUCH_XEDGEDIST 27 #define MXT_TOUCH_YEDGECTRL 28 #define MXT_TOUCH_YEDGEDIST 29 -#define MXT_TOUCH_JUMPLIMIT 30 /* firmware ver 22 over */ +#define MXT_TOUCH_JUMPLIMIT 30 /* MXT_PROCI_GRIPFACE field */ #define MXT_GRIPFACE_CTRL 0 @@ -157,7 +157,7 @@ #define MXT_CTE_MODE 2 #define MXT_CTE_IDLEGCAFDEPTH 3 #define MXT_CTE_ACTVGCAFDEPTH 4 -#define MXT_CTE_VOLTAGE 5 /* firmware ver 21 over */ +#define MXT_CTE_VOLTAGE 5 #define MXT_VOLTAGE_DEFAULT 2700000 #define MXT_VOLTAGE_STEP 10000 @@ -686,7 +686,7 @@ static void mxt_handle_pdata(struct mxt_data *data) MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); /* Set touchscreen voltage */ - if (data->info.version >= MXT_VER_21 && pdata->voltage) { + if (pdata->voltage) { if (pdata->voltage < MXT_VOLTAGE_DEFAULT) { voltage = (MXT_VOLTAGE_DEFAULT - pdata->voltage) / MXT_VOLTAGE_STEP; @@ -951,19 +951,8 @@ static ssize_t mxt_update_fw_store(struct device *dev, const char *buf, size_t count) { struct mxt_data *data = dev_get_drvdata(dev); - unsigned int version; int error; - if (sscanf(buf, "%u", &version) != 1) { - dev_err(dev, "Invalid values\n"); - return -EINVAL; - } - - if (data->info.version < MXT_VER_21 || version < MXT_VER_21) { - dev_err(dev, "FW update supported starting with version 21\n"); - return -EINVAL; - } - disable_irq(data->irq); error = mxt_load_fw(dev, MXT_FW_NAME); -- cgit v1.2.2 From 4c75de32eb9fcaa14925e2e444748f8b71e4f6fc Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 14 Mar 2011 21:41:40 -0700 Subject: Input: atmel_mxt_ts - add objects of mXT1386 chip Atmel mXT1386 chip is operated by atmel_mxt_ts driver and it has some different objects. Signed-off-by: Joonyoung Shim Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 0986fa46e9df..4012436633b1 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -60,11 +60,15 @@ #define MXT_PROCG_NOISE 22 #define MXT_PROCI_ONETOUCH 24 #define MXT_PROCI_TWOTOUCH 27 +#define MXT_PROCI_GRIP 40 +#define MXT_PROCI_PALM 41 #define MXT_SPT_COMMSCONFIG 18 #define MXT_SPT_GPIOPWM 19 #define MXT_SPT_SELFTEST 25 #define MXT_SPT_CTECONFIG 28 #define MXT_SPT_USERDATA 38 +#define MXT_SPT_DIGITIZER 43 +#define MXT_SPT_MESSAGECOUNT 44 /* MXT_GEN_COMMAND field */ #define MXT_COMMAND_RESET 0 @@ -258,6 +262,8 @@ static bool mxt_object_readable(unsigned int type) case MXT_PROCG_NOISE: case MXT_PROCI_ONETOUCH: case MXT_PROCI_TWOTOUCH: + case MXT_PROCI_GRIP: + case MXT_PROCI_PALM: case MXT_SPT_COMMSCONFIG: case MXT_SPT_GPIOPWM: case MXT_SPT_SELFTEST: @@ -282,6 +288,8 @@ static bool mxt_object_writable(unsigned int type) case MXT_PROCG_NOISE: case MXT_PROCI_ONETOUCH: case MXT_PROCI_TWOTOUCH: + case MXT_PROCI_GRIP: + case MXT_PROCI_PALM: case MXT_SPT_GPIOPWM: case MXT_SPT_SELFTEST: case MXT_SPT_CTECONFIG: -- cgit v1.2.2 From 235e7dba0264d4c6e56ee217fc7ef6d80da5eb67 Mon Sep 17 00:00:00 2001 From: "Taneja, Archit" Date: Mon, 14 Mar 2011 23:28:21 -0500 Subject: OMAP2PLUS: DSS2: FEATURES: Fix usage of dss_reg_field and dss_clk_source_name The structures dss_reg_field and dss_clk_source_name have enum members which specify the register field and the clock source respectively. These members are not used to choose the correct result in the corresponding feature functions. Remove these members and change the features array declaration to incorporate these enums. The structure dss_clk_source_name without the enum member is just a pointer to an string. Remove the structure and use a character pointer directly. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 10 ++--- drivers/video/omap2/dss/dss.h | 6 --- drivers/video/omap2/dss/dss_features.c | 77 +++++++++++++++++----------------- 3 files changed, 43 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index aed9345e8ada..06ad31290853 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -82,10 +82,10 @@ static struct { u32 ctx[DSS_SZ_REGS / sizeof(u32)]; } dss; -static const struct dss_clk_source_name dss_generic_clk_source_names[] = { - { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI_PLL_HSDIV_DISPC" }, - { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI_PLL_HSDIV_DSI" }, - { DSS_CLK_SRC_FCK, "DSS_FCK" }, +static const char * const dss_generic_clk_source_names[] = { + [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", + [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", + [DSS_CLK_SRC_FCK] = "DSS_FCK", }; static void dss_clk_enable_all_no_ctx(void); @@ -232,7 +232,7 @@ void dss_sdi_disable(void) const char *dss_get_generic_clk_source_name(enum dss_clk_source clk_src) { - return dss_generic_clk_source_names[clk_src].clksrc_name; + return dss_generic_clk_source_names[clk_src]; } void dss_dump_clocks(struct seq_file *s) diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index b845468d9706..26a43c93e489 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -126,12 +126,6 @@ enum dss_clk_source { * OMAP4: DSS_FCLK */ }; -/* Correlates clock source name and dss_clk_source member */ -struct dss_clk_source_name { - enum dss_clk_source clksrc; - const char *clksrc_name; -}; - struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 6eb6ec62a000..8de3344842d7 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -30,7 +30,6 @@ /* Defines a generic omap register field */ struct dss_reg_field { - enum dss_feat_reg_field id; u8 start, end; }; @@ -45,43 +44,43 @@ struct omap_dss_features { const unsigned long max_dss_fck; const enum omap_display_type *supported_displays; const enum omap_color_mode *supported_color_modes; - const struct dss_clk_source_name *clksrc_names; + const char * const *clksrc_names; }; /* This struct is assigned to one of the below during initialization */ static struct omap_dss_features *omap_current_dss_features; static const struct dss_reg_field omap2_dss_reg_fields[] = { - { FEAT_REG_FIRHINC, 11, 0 }, - { FEAT_REG_FIRVINC, 27, 16 }, - { FEAT_REG_FIFOLOWTHRESHOLD, 8, 0 }, - { FEAT_REG_FIFOHIGHTHRESHOLD, 24, 16 }, - { FEAT_REG_FIFOSIZE, 8, 0 }, - { FEAT_REG_HORIZONTALACCU, 9, 0 }, - { FEAT_REG_VERTICALACCU, 25, 16 }, - { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 }, + [FEAT_REG_FIRHINC] = { 11, 0 }, + [FEAT_REG_FIRVINC] = { 27, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 }, + [FEAT_REG_FIFOSIZE] = { 8, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, + [FEAT_REG_VERTICALACCU] = { 25, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, }; static const struct dss_reg_field omap3_dss_reg_fields[] = { - { FEAT_REG_FIRHINC, 12, 0 }, - { FEAT_REG_FIRVINC, 28, 16 }, - { FEAT_REG_FIFOLOWTHRESHOLD, 11, 0 }, - { FEAT_REG_FIFOHIGHTHRESHOLD, 27, 16 }, - { FEAT_REG_FIFOSIZE, 10, 0 }, - { FEAT_REG_HORIZONTALACCU, 9, 0 }, - { FEAT_REG_VERTICALACCU, 25, 16 }, - { FEAT_REG_DISPC_CLK_SWITCH, 0, 0 }, + [FEAT_REG_FIRHINC] = { 12, 0 }, + [FEAT_REG_FIRVINC] = { 28, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 }, + [FEAT_REG_FIFOSIZE] = { 10, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, + [FEAT_REG_VERTICALACCU] = { 25, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, }; static const struct dss_reg_field omap4_dss_reg_fields[] = { - { FEAT_REG_FIRHINC, 12, 0 }, - { FEAT_REG_FIRVINC, 28, 16 }, - { FEAT_REG_FIFOLOWTHRESHOLD, 15, 0 }, - { FEAT_REG_FIFOHIGHTHRESHOLD, 31, 16 }, - { FEAT_REG_FIFOSIZE, 15, 0 }, - { FEAT_REG_HORIZONTALACCU, 10, 0 }, - { FEAT_REG_VERTICALACCU, 26, 16 }, - { FEAT_REG_DISPC_CLK_SWITCH, 9, 8 }, + [FEAT_REG_FIRHINC] = { 12, 0 }, + [FEAT_REG_FIRVINC] = { 28, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, + [FEAT_REG_FIFOSIZE] = { 15, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, + [FEAT_REG_VERTICALACCU] = { 26, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 }, }; static const enum omap_display_type omap2_dss_supported_displays[] = { @@ -162,22 +161,22 @@ static const enum omap_color_mode omap3_dss_supported_color_modes[] = { OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32, }; -static const struct dss_clk_source_name omap2_dss_clk_source_names[] = { - { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "N/A" }, - { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "N/A" }, - { DSS_CLK_SRC_FCK, "DSS_FCLK1" }, +static const char * const omap2_dss_clk_source_names[] = { + [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A", + [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A", + [DSS_CLK_SRC_FCK] = "DSS_FCLK1", }; -static const struct dss_clk_source_name omap3_dss_clk_source_names[] = { - { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "DSI1_PLL_FCLK" }, - { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "DSI2_PLL_FCLK" }, - { DSS_CLK_SRC_FCK, "DSS1_ALWON_FCLK" }, +static const char * const omap3_dss_clk_source_names[] = { + [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK", + [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK", + [DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK", }; -static const struct dss_clk_source_name omap4_dss_clk_source_names[] = { - { DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, "PLL1_CLK1" }, - { DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, "PLL1_CLK2" }, - { DSS_CLK_SRC_FCK, "DSS_FCLK" }, +static const char * const omap4_dss_clk_source_names[] = { + [DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1", + [DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2", + [DSS_CLK_SRC_FCK] = "DSS_FCLK", }; /* OMAP2 DSS Features */ @@ -290,7 +289,7 @@ bool dss_feat_color_mode_supported(enum omap_plane plane, const char *dss_feat_get_clk_source_name(enum dss_clk_source id) { - return omap_current_dss_features->clksrc_names[id].clksrc_name; + return omap_current_dss_features->clksrc_names[id]; } /* DSS has_feature check */ -- cgit v1.2.2 From 31ef82377f1e0f1bc7d308ae4312e6cc5a431885 Mon Sep 17 00:00:00 2001 From: "Taneja, Archit" Date: Mon, 14 Mar 2011 23:28:22 -0500 Subject: OMAP: DSS2: FEATURES: Functions to return min and max values of parameters Create 2 functions dss_feat_get_param_min() and dss_feat_get_param_max() which return the minimum and maximum value of a parameter. Introduce a enum in dss_features called dss_range_param which contains parameters whose ranges we are interested in. Replace this with dss_feat_get_max_dss_fck() which is specific to the parameter DSS_FCK. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 2 +- drivers/video/omap2/dss/dss.c | 2 +- drivers/video/omap2/dss/dss_features.c | 36 ++++++++++++++++++++++++++-------- drivers/video/omap2/dss/dss_features.h | 7 ++++++- 4 files changed, 36 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index be7694ff7ca7..6e7f46828148 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -864,7 +864,7 @@ int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck, dss_sys_clk = dss_clk_get_rate(DSS_CLK_SYSCK); - max_dss_fck = dss_feat_get_max_dss_fck(); + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); if (req_pck == dsi.cache_req_pck && dsi.cache_cinfo.clkin == dss_sys_clk) { diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 06ad31290853..562d8d28d4f2 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -457,7 +457,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, prate = dss_get_dpll4_rate(); - max_dss_fck = dss_feat_get_max_dss_fck(); + max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); fck = dss_clk_get_rate(DSS_CLK_FCK); if (req_pck == dss.cache_req_pck && diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 8de3344842d7..4c8b32af496c 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -33,6 +33,10 @@ struct dss_reg_field { u8 start, end; }; +struct dss_param_range { + int min, max; +}; + struct omap_dss_features { const struct dss_reg_field *reg_fields; const int num_reg_fields; @@ -41,10 +45,10 @@ struct omap_dss_features { const int num_mgrs; const int num_ovls; - const unsigned long max_dss_fck; const enum omap_display_type *supported_displays; const enum omap_color_mode *supported_color_modes; const char * const *clksrc_names; + const struct dss_param_range *dss_params; }; /* This struct is assigned to one of the below during initialization */ @@ -179,6 +183,18 @@ static const char * const omap4_dss_clk_source_names[] = { [DSS_CLK_SRC_FCK] = "DSS_FCLK", }; +static const struct dss_param_range omap2_dss_param_range[] = { + [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, +}; + +static const struct dss_param_range omap3_dss_param_range[] = { + [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, +}; + +static const struct dss_param_range omap4_dss_param_range[] = { + [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, +}; + /* OMAP2 DSS Features */ static struct omap_dss_features omap2_dss_features = { .reg_fields = omap2_dss_reg_fields, @@ -191,10 +207,10 @@ static struct omap_dss_features omap2_dss_features = { .num_mgrs = 2, .num_ovls = 3, - .max_dss_fck = 173000000, .supported_displays = omap2_dss_supported_displays, .supported_color_modes = omap2_dss_supported_color_modes, .clksrc_names = omap2_dss_clk_source_names, + .dss_params = omap2_dss_param_range, }; /* OMAP3 DSS Features */ @@ -210,10 +226,10 @@ static struct omap_dss_features omap3430_dss_features = { .num_mgrs = 2, .num_ovls = 3, - .max_dss_fck = 173000000, .supported_displays = omap3430_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, .clksrc_names = omap3_dss_clk_source_names, + .dss_params = omap3_dss_param_range, }; static struct omap_dss_features omap3630_dss_features = { @@ -229,10 +245,10 @@ static struct omap_dss_features omap3630_dss_features = { .num_mgrs = 2, .num_ovls = 3, - .max_dss_fck = 173000000, .supported_displays = omap3630_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, .clksrc_names = omap3_dss_clk_source_names, + .dss_params = omap3_dss_param_range, }; /* OMAP4 DSS Features */ @@ -247,10 +263,10 @@ static struct omap_dss_features omap4_dss_features = { .num_mgrs = 3, .num_ovls = 3, - .max_dss_fck = 186000000, .supported_displays = omap4_dss_supported_displays, .supported_color_modes = omap3_dss_supported_color_modes, .clksrc_names = omap4_dss_clk_source_names, + .dss_params = omap4_dss_param_range, }; /* Functions returning values related to a DSS feature */ @@ -264,10 +280,14 @@ int dss_feat_get_num_ovls(void) return omap_current_dss_features->num_ovls; } -/* Max supported DSS FCK in Hz */ -unsigned long dss_feat_get_max_dss_fck(void) +unsigned long dss_feat_get_param_min(enum dss_range_param param) +{ + return omap_current_dss_features->dss_params[param].min; +} + +unsigned long dss_feat_get_param_max(enum dss_range_param param) { - return omap_current_dss_features->max_dss_fck; + return omap_current_dss_features->dss_params[param].max; } enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel) diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 729b5f19fa2e..da63bbf38e90 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -54,10 +54,15 @@ enum dss_feat_reg_field { FEAT_REG_DISPC_CLK_SWITCH, }; +enum dss_range_param { + FEAT_PARAM_DSS_FCK, +}; + /* DSS Feature Functions */ int dss_feat_get_num_mgrs(void); int dss_feat_get_num_ovls(void); -unsigned long dss_feat_get_max_dss_fck(void); +unsigned long dss_feat_get_param_min(enum dss_range_param param); +unsigned long dss_feat_get_param_max(enum dss_range_param param); enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, -- cgit v1.2.2 From 49641116392ad7522fa0efad53f7ed63f811bd88 Mon Sep 17 00:00:00 2001 From: "Taneja, Archit" Date: Mon, 14 Mar 2011 23:28:23 -0500 Subject: OMAP: DSS2: FEATURES: DSI PLL parameter cleanup The DSI PLL parameters (regm, regn, regm_dispc, regm_dsi, fint) have different fields and also different Max values on OMAP3 and OMAP4. Use dss features to calculate the register fields and min/max values based on current OMAP revision. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 69 ++++++++++++++++++---------- drivers/video/omap2/dss/dss_features.c | 84 +++++++++++++++++++++++----------- drivers/video/omap2/dss/dss_features.h | 10 ++++ 3 files changed, 113 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 6e7f46828148..7a4b4404a976 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -185,14 +185,6 @@ struct dsi_reg { u16 idx; }; #define DSI_DT_RX_SHORT_READ_1 0x21 #define DSI_DT_RX_SHORT_READ_2 0x22 -#define FINT_MAX 2100000 -#define FINT_MIN 750000 -#define REGN_MAX (1 << 7) -#define REGM_MAX ((1 << 11) - 1) -#define REGM_DISPC_MAX (1 << 4) -#define REGM_DSI_MAX (1 << 4) -#define LP_DIV_MAX ((1 << 13) - 1) - enum fifo_size { DSI_FIFO_SIZE_0 = 0, DSI_FIFO_SIZE_32 = 1, @@ -277,6 +269,11 @@ static struct spinlock_t irq_stats_lock; struct dsi_irq_stats irq_stats; #endif + /* DSI PLL Parameter Ranges */ + unsigned long regm_max, regn_max; + unsigned long regm_dispc_max, regm_dsi_max; + unsigned long fint_min, fint_max; + unsigned long lpdiv_max; } dsi; #ifdef DEBUG @@ -751,7 +748,7 @@ static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev) lp_clk_div = dssdev->phy.dsi.div.lp_clk_div; - if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX) + if (lp_clk_div == 0 || lp_clk_div > dsi.lpdiv_max) return -EINVAL; dsi_fclk = dsi_fclk_rate(); @@ -801,16 +798,16 @@ static int dsi_pll_power(enum dsi_pll_power_state state) static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, struct dsi_clock_info *cinfo) { - if (cinfo->regn == 0 || cinfo->regn > REGN_MAX) + if (cinfo->regn == 0 || cinfo->regn > dsi.regn_max) return -EINVAL; - if (cinfo->regm == 0 || cinfo->regm > REGM_MAX) + if (cinfo->regm == 0 || cinfo->regm > dsi.regm_max) return -EINVAL; - if (cinfo->regm_dispc > REGM_DISPC_MAX) + if (cinfo->regm_dispc > dsi.regm_dispc_max) return -EINVAL; - if (cinfo->regm_dsi > REGM_DSI_MAX) + if (cinfo->regm_dsi > dsi.regm_dsi_max) return -EINVAL; if (cinfo->use_sys_clk) { @@ -829,7 +826,7 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1)); - if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN) + if (cinfo->fint > dsi.fint_max || cinfo->fint < dsi.fint_min) return -EINVAL; cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint; @@ -899,17 +896,17 @@ retry: /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */ /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ - for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) { + for (cur.regn = 1; cur.regn < dsi.regn_max; ++cur.regn) { if (cur.highfreq == 0) cur.fint = cur.clkin / cur.regn; else cur.fint = cur.clkin / (2 * cur.regn); - if (cur.fint > FINT_MAX || cur.fint < FINT_MIN) + if (cur.fint > dsi.fint_max || cur.fint < dsi.fint_min) continue; /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */ - for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) { + for (cur.regm = 1; cur.regm < dsi.regm_max; ++cur.regm) { unsigned long a, b; a = 2 * cur.regm * (cur.clkin/1000); @@ -921,7 +918,7 @@ retry: /* dsi_pll_hsdiv_dispc_clk(MHz) = * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */ - for (cur.regm_dispc = 1; cur.regm_dispc < REGM_DISPC_MAX; + for (cur.regm_dispc = 1; cur.regm_dispc < dsi.regm_dispc_max; ++cur.regm_dispc) { struct dispc_clock_info cur_dispc; cur.dsi_pll_hsdiv_dispc_clk = @@ -994,6 +991,8 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) int r = 0; u32 l; int f; + u8 regn_start, regn_end, regm_start, regm_end; + u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; DSSDBGF(); @@ -1038,19 +1037,30 @@ int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo) dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), cinfo->dsi_pll_hsdiv_dsi_clk); + dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, ®n_start, ®n_end); + dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, ®m_start, ®m_end); + dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, ®m_dispc_start, + ®m_dispc_end); + dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, ®m_dsi_start, + ®m_dsi_end); + REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */ l = dsi_read_reg(DSI_PLL_CONFIGURATION1); l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */ - l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */ - l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */ + /* DSI_PLL_REGN */ + l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end); + /* DSI_PLL_REGM */ + l = FLD_MOD(l, cinfo->regm, regm_start, regm_end); + /* DSI_CLOCK_DIV */ l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0, - 22, 19); /* DSI_CLOCK_DIV */ + regm_dispc_start, regm_dispc_end); + /* DSIPROTO_CLOCK_DIV */ l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0, - 26, 23); /* DSIPROTO_CLOCK_DIV */ + regm_dsi_start, regm_dsi_end); dsi_write_reg(DSI_PLL_CONFIGURATION1, l); - BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000); + BUG_ON(cinfo->fint < dsi.fint_min || cinfo->fint > dsi.fint_max); if (cinfo->fint < 1000000) f = 0x3; else if (cinfo->fint < 1250000) @@ -3333,6 +3343,17 @@ void dsi_wait_pll_hsdiv_dsi_active(void) dss_feat_get_clk_source_name(DSS_CLK_SRC_DSI_PLL_HSDIV_DSI)); } +static void dsi_calc_clock_param_ranges(void) +{ + dsi.regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN); + dsi.regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM); + dsi.regm_dispc_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC); + dsi.regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI); + dsi.fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT); + dsi.fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT); + dsi.lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); +} + static int dsi_init(struct platform_device *pdev) { u32 rev; @@ -3397,6 +3418,8 @@ static int dsi_init(struct platform_device *pdev) dsi.vc[i].vc_id = 0; } + dsi_calc_clock_param_ranges(); + enable_clocks(1); rev = dsi_read_reg(DSI_REVISION); diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 4c8b32af496c..06b18f73449b 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -55,36 +55,48 @@ struct omap_dss_features { static struct omap_dss_features *omap_current_dss_features; static const struct dss_reg_field omap2_dss_reg_fields[] = { - [FEAT_REG_FIRHINC] = { 11, 0 }, - [FEAT_REG_FIRVINC] = { 27, 16 }, - [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 }, - [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 }, - [FEAT_REG_FIFOSIZE] = { 8, 0 }, - [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, - [FEAT_REG_VERTICALACCU] = { 25, 16 }, - [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, + [FEAT_REG_FIRHINC] = { 11, 0 }, + [FEAT_REG_FIRVINC] = { 27, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 }, + [FEAT_REG_FIFOSIZE] = { 8, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, + [FEAT_REG_VERTICALACCU] = { 25, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, + [FEAT_REG_DSIPLL_REGN] = { 0, 0 }, + [FEAT_REG_DSIPLL_REGM] = { 0, 0 }, + [FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 }, + [FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 }, }; static const struct dss_reg_field omap3_dss_reg_fields[] = { - [FEAT_REG_FIRHINC] = { 12, 0 }, - [FEAT_REG_FIRVINC] = { 28, 16 }, - [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 }, - [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 }, - [FEAT_REG_FIFOSIZE] = { 10, 0 }, - [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, - [FEAT_REG_VERTICALACCU] = { 25, 16 }, - [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, + [FEAT_REG_FIRHINC] = { 12, 0 }, + [FEAT_REG_FIRVINC] = { 28, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 }, + [FEAT_REG_FIFOSIZE] = { 10, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, + [FEAT_REG_VERTICALACCU] = { 25, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, + [FEAT_REG_DSIPLL_REGN] = { 7, 1 }, + [FEAT_REG_DSIPLL_REGM] = { 18, 8 }, + [FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 }, + [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 }, }; static const struct dss_reg_field omap4_dss_reg_fields[] = { - [FEAT_REG_FIRHINC] = { 12, 0 }, - [FEAT_REG_FIRVINC] = { 28, 16 }, - [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, - [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, - [FEAT_REG_FIFOSIZE] = { 15, 0 }, - [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, - [FEAT_REG_VERTICALACCU] = { 26, 16 }, - [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 }, + [FEAT_REG_FIRHINC] = { 12, 0 }, + [FEAT_REG_FIRVINC] = { 28, 16 }, + [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, + [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, + [FEAT_REG_FIFOSIZE] = { 15, 0 }, + [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, + [FEAT_REG_VERTICALACCU] = { 26, 16 }, + [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 }, + [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, + [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, + [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, + [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, }; static const enum omap_display_type omap2_dss_supported_displays[] = { @@ -184,15 +196,33 @@ static const char * const omap4_dss_clk_source_names[] = { }; static const struct dss_param_range omap2_dss_param_range[] = { - [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, + [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, + [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, + [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, + [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 }, + [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 }, + [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, + [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, }; static const struct dss_param_range omap3_dss_param_range[] = { - [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, + [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, + [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 }, + [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, + [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, + [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, }; static const struct dss_param_range omap4_dss_param_range[] = { - [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, + [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, + [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, + [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, + [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, + [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, }; /* OMAP2 DSS Features */ diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index da63bbf38e90..12e9c4ef0dec 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h @@ -52,10 +52,20 @@ enum dss_feat_reg_field { FEAT_REG_HORIZONTALACCU, FEAT_REG_VERTICALACCU, FEAT_REG_DISPC_CLK_SWITCH, + FEAT_REG_DSIPLL_REGN, + FEAT_REG_DSIPLL_REGM, + FEAT_REG_DSIPLL_REGM_DISPC, + FEAT_REG_DSIPLL_REGM_DSI, }; enum dss_range_param { FEAT_PARAM_DSS_FCK, + FEAT_PARAM_DSIPLL_REGN, + FEAT_PARAM_DSIPLL_REGM, + FEAT_PARAM_DSIPLL_REGM_DISPC, + FEAT_PARAM_DSIPLL_REGM_DSI, + FEAT_PARAM_DSIPLL_FINT, + FEAT_PARAM_DSIPLL_LPDIV, }; /* DSS Feature Functions */ -- cgit v1.2.2 From 69b281a61442f97e8df14babc9bb6a28624886b1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 14:44:27 +0200 Subject: OMAP: DSS2: DSI: Restructure IRQ handler Clean up the IRQ handler a bit by separating collection of IRQ stats and handling of IRQ errors to separate functions. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 123 +++++++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 7a4b4404a976..b6c08a6f2da1 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -477,26 +477,33 @@ static void print_irq_status_cio(u32 status) printk("\n"); } -static int debug_irq; - -/* called from dss */ -static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS +static void dsi_collect_irq_stats(u32 irqstatus, u32 *vcstatus, u32 ciostatus) { - u32 irqstatus, vcstatus, ciostatus; int i; - irqstatus = dsi_read_reg(DSI_IRQSTATUS); - - /* IRQ is not for us */ - if (!irqstatus) - return IRQ_NONE; - -#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spin_lock(&dsi.irq_stats_lock); + dsi.irq_stats.irq_count++; dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs); + + for (i = 0; i < 4; ++i) + dss_collect_irq_stats(vcstatus[i], dsi.irq_stats.vc_irqs[i]); + + dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs); + + spin_unlock(&dsi.irq_stats_lock); +} +#else +#define dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus) #endif +static int debug_irq; + +static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus) +{ + int i; + if (irqstatus & DSI_IRQ_ERROR_MASK) { DSSERR("DSI error, irqstatus %x\n", irqstatus); print_irq_status(irqstatus); @@ -507,37 +514,48 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) print_irq_status(irqstatus); } -#ifdef DSI_CATCH_MISSING_TE - if (irqstatus & DSI_IRQ_TE_TRIGGER) - del_timer(&dsi.te_timer); -#endif - for (i = 0; i < 4; ++i) { - if ((irqstatus & (1< Date: Wed, 2 Mar 2011 14:47:04 +0200 Subject: OMAP: DSS2: DSI: Add ISR support Add generic ISR support for DSI interrupts. ISRs can be used instead of custom hooks in the interrupt handler. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 329 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 304 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b6c08a6f2da1..8613ec489410 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -185,6 +185,16 @@ struct dsi_reg { u16 idx; }; #define DSI_DT_RX_SHORT_READ_1 0x21 #define DSI_DT_RX_SHORT_READ_2 0x22 +typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); + +#define DSI_MAX_NR_ISRS 2 + +struct dsi_isr_data { + omap_dsi_isr_t isr; + void *arg; + u32 mask; +}; + enum fifo_size { DSI_FIFO_SIZE_0 = 0, DSI_FIFO_SIZE_32 = 1, @@ -211,6 +221,12 @@ struct dsi_irq_stats { unsigned cio_irqs[32]; }; +struct dsi_isr_tables { + struct dsi_isr_data isr_table[DSI_MAX_NR_ISRS]; + struct dsi_isr_data isr_table_vc[4][DSI_MAX_NR_ISRS]; + struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS]; +}; + static struct { struct platform_device *pdev; @@ -236,6 +252,11 @@ static struct struct completion bta_completion; void (*bta_callback)(void); + spinlock_t irq_lock; + struct dsi_isr_tables isr_tables; + /* space for a copy used by the interrupt handler */ + struct dsi_isr_tables isr_tables_copy; + int update_channel; struct dsi_update_region update_region; @@ -532,16 +553,56 @@ static void dsi_handle_irq_errors(u32 irqstatus, u32 *vcstatus, u32 ciostatus) } } +static void dsi_call_isrs(struct dsi_isr_data *isr_array, + unsigned isr_array_size, u32 irqstatus) +{ + struct dsi_isr_data *isr_data; + int i; + + for (i = 0; i < isr_array_size; i++) { + isr_data = &isr_array[i]; + if (isr_data->isr && isr_data->mask & irqstatus) + isr_data->isr(isr_data->arg, irqstatus); + } +} + +static void dsi_handle_isrs(struct dsi_isr_tables *isr_tables, + u32 irqstatus, u32 *vcstatus, u32 ciostatus) +{ + int i; + + dsi_call_isrs(isr_tables->isr_table, + ARRAY_SIZE(isr_tables->isr_table), + irqstatus); + + for (i = 0; i < 4; ++i) { + if (vcstatus[i] == 0) + continue; + dsi_call_isrs(isr_tables->isr_table_vc[i], + ARRAY_SIZE(isr_tables->isr_table_vc[i]), + vcstatus[i]); + } + + if (ciostatus != 0) + dsi_call_isrs(isr_tables->isr_table_cio, + ARRAY_SIZE(isr_tables->isr_table_cio), + ciostatus); +} + static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) { u32 irqstatus, vcstatus[4], ciostatus; int i; + spin_lock(&dsi.irq_lock); + irqstatus = dsi_read_reg(DSI_IRQSTATUS); /* IRQ is not for us */ - if (!irqstatus) + if (!irqstatus) { + spin_unlock(&dsi.irq_lock); return IRQ_NONE; + } dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); /* flush posted write */ @@ -587,6 +648,14 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) } } + /* make a copy and unlock, so that isrs can unregister + * themselves */ + memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables)); + + spin_unlock(&dsi.irq_lock); + + dsi_handle_isrs(&dsi.isr_tables_copy, irqstatus, vcstatus, ciostatus); + dsi_handle_irq_errors(irqstatus, vcstatus, ciostatus); dsi_collect_irq_stats(irqstatus, vcstatus, ciostatus); @@ -594,42 +663,251 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) return IRQ_HANDLED; } -static void _dsi_initialize_irq(void) +/* dsi.irq_lock has to be locked by the caller */ +static void _omap_dsi_configure_irqs(struct dsi_isr_data *isr_array, + unsigned isr_array_size, u32 default_mask, + const struct dsi_reg enable_reg, + const struct dsi_reg status_reg) { - u32 l; + struct dsi_isr_data *isr_data; + u32 mask; + u32 old_mask; int i; - /* disable all interrupts */ - dsi_write_reg(DSI_IRQENABLE, 0); - for (i = 0; i < 4; ++i) - dsi_write_reg(DSI_VC_IRQENABLE(i), 0); - dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0); + mask = default_mask; - /* clear interrupt status */ - l = dsi_read_reg(DSI_IRQSTATUS); - dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK); + for (i = 0; i < isr_array_size; i++) { + isr_data = &isr_array[i]; - for (i = 0; i < 4; ++i) { - l = dsi_read_reg(DSI_VC_IRQSTATUS(i)); - dsi_write_reg(DSI_VC_IRQSTATUS(i), l); + if (isr_data->isr == NULL) + continue; + + mask |= isr_data->mask; } - l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); - dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l); + old_mask = dsi_read_reg(enable_reg); + /* clear the irqstatus for newly enabled irqs */ + dsi_write_reg(status_reg, (mask ^ old_mask) & mask); + dsi_write_reg(enable_reg, mask); + + /* flush posted writes */ + dsi_read_reg(enable_reg); + dsi_read_reg(status_reg); +} - /* enable error irqs */ - l = DSI_IRQ_ERROR_MASK; +/* dsi.irq_lock has to be locked by the caller */ +static void _omap_dsi_set_irqs(void) +{ + u32 mask = DSI_IRQ_ERROR_MASK; #ifdef DSI_CATCH_MISSING_TE - l |= DSI_IRQ_TE_TRIGGER; + mask |= DSI_IRQ_TE_TRIGGER; #endif - dsi_write_reg(DSI_IRQENABLE, l); + _omap_dsi_configure_irqs(dsi.isr_tables.isr_table, + ARRAY_SIZE(dsi.isr_tables.isr_table), mask, + DSI_IRQENABLE, DSI_IRQSTATUS); +} - l = DSI_VC_IRQ_ERROR_MASK; - for (i = 0; i < 4; ++i) - dsi_write_reg(DSI_VC_IRQENABLE(i), l); +/* dsi.irq_lock has to be locked by the caller */ +static void _omap_dsi_set_irqs_vc(int vc) +{ + _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_vc[vc], + ARRAY_SIZE(dsi.isr_tables.isr_table_vc[vc]), + DSI_VC_IRQ_ERROR_MASK, + DSI_VC_IRQENABLE(vc), DSI_VC_IRQSTATUS(vc)); +} + +/* dsi.irq_lock has to be locked by the caller */ +static void _omap_dsi_set_irqs_cio(void) +{ + _omap_dsi_configure_irqs(dsi.isr_tables.isr_table_cio, + ARRAY_SIZE(dsi.isr_tables.isr_table_cio), + DSI_CIO_IRQ_ERROR_MASK, + DSI_COMPLEXIO_IRQ_ENABLE, DSI_COMPLEXIO_IRQ_STATUS); +} + +static void _dsi_initialize_irq(void) +{ + unsigned long flags; + int vc; + + spin_lock_irqsave(&dsi.irq_lock, flags); + + memset(&dsi.isr_tables, 0, sizeof(dsi.isr_tables)); + + _omap_dsi_set_irqs(); + for (vc = 0; vc < 4; ++vc) + _omap_dsi_set_irqs_vc(vc); + _omap_dsi_set_irqs_cio(); + + spin_unlock_irqrestore(&dsi.irq_lock, flags); +} - l = DSI_CIO_IRQ_ERROR_MASK; - dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l); +static int _dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask, + struct dsi_isr_data *isr_array, unsigned isr_array_size) +{ + struct dsi_isr_data *isr_data; + int free_idx; + int i; + + BUG_ON(isr == NULL); + + /* check for duplicate entry and find a free slot */ + free_idx = -1; + for (i = 0; i < isr_array_size; i++) { + isr_data = &isr_array[i]; + + if (isr_data->isr == isr && isr_data->arg == arg && + isr_data->mask == mask) { + return -EINVAL; + } + + if (isr_data->isr == NULL && free_idx == -1) + free_idx = i; + } + + if (free_idx == -1) + return -EBUSY; + + isr_data = &isr_array[free_idx]; + isr_data->isr = isr; + isr_data->arg = arg; + isr_data->mask = mask; + + return 0; +} + +static int _dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask, + struct dsi_isr_data *isr_array, unsigned isr_array_size) +{ + struct dsi_isr_data *isr_data; + int i; + + for (i = 0; i < isr_array_size; i++) { + isr_data = &isr_array[i]; + if (isr_data->isr != isr || isr_data->arg != arg || + isr_data->mask != mask) + continue; + + isr_data->isr = NULL; + isr_data->arg = NULL; + isr_data->mask = 0; + + return 0; + } + + return -EINVAL; +} + +static int dsi_register_isr(omap_dsi_isr_t isr, void *arg, u32 mask) +{ + unsigned long flags; + int r; + + spin_lock_irqsave(&dsi.irq_lock, flags); + + r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table, + ARRAY_SIZE(dsi.isr_tables.isr_table)); + + if (r == 0) + _omap_dsi_set_irqs(); + + spin_unlock_irqrestore(&dsi.irq_lock, flags); + + return r; +} + +static int dsi_unregister_isr(omap_dsi_isr_t isr, void *arg, u32 mask) +{ + unsigned long flags; + int r; + + spin_lock_irqsave(&dsi.irq_lock, flags); + + r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table, + ARRAY_SIZE(dsi.isr_tables.isr_table)); + + if (r == 0) + _omap_dsi_set_irqs(); + + spin_unlock_irqrestore(&dsi.irq_lock, flags); + + return r; +} + +static int dsi_register_isr_vc(int channel, omap_dsi_isr_t isr, void *arg, + u32 mask) +{ + unsigned long flags; + int r; + + spin_lock_irqsave(&dsi.irq_lock, flags); + + r = _dsi_register_isr(isr, arg, mask, + dsi.isr_tables.isr_table_vc[channel], + ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel])); + + if (r == 0) + _omap_dsi_set_irqs_vc(channel); + + spin_unlock_irqrestore(&dsi.irq_lock, flags); + + return r; +} + +static int dsi_unregister_isr_vc(int channel, omap_dsi_isr_t isr, void *arg, + u32 mask) +{ + unsigned long flags; + int r; + + spin_lock_irqsave(&dsi.irq_lock, flags); + + r = _dsi_unregister_isr(isr, arg, mask, + dsi.isr_tables.isr_table_vc[channel], + ARRAY_SIZE(dsi.isr_tables.isr_table_vc[channel])); + + if (r == 0) + _omap_dsi_set_irqs_vc(channel); + + spin_unlock_irqrestore(&dsi.irq_lock, flags); + + return r; +} + +static int dsi_register_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask) +{ + unsigned long flags; + int r; + + spin_lock_irqsave(&dsi.irq_lock, flags); + + r = _dsi_register_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio, + ARRAY_SIZE(dsi.isr_tables.isr_table_cio)); + + if (r == 0) + _omap_dsi_set_irqs_cio(); + + spin_unlock_irqrestore(&dsi.irq_lock, flags); + + return r; +} + +static int dsi_unregister_isr_cio(omap_dsi_isr_t isr, void *arg, u32 mask) +{ + unsigned long flags; + int r; + + spin_lock_irqsave(&dsi.irq_lock, flags); + + r = _dsi_unregister_isr(isr, arg, mask, dsi.isr_tables.isr_table_cio, + ARRAY_SIZE(dsi.isr_tables.isr_table_cio)); + + if (r == 0) + _omap_dsi_set_irqs_cio(); + + spin_unlock_irqrestore(&dsi.irq_lock, flags); + + return r; } static u32 dsi_get_errors(void) @@ -3383,6 +3661,7 @@ static int dsi_init(struct platform_device *pdev) int r, i; struct resource *dsi_mem; + spin_lock_init(&dsi.irq_lock); spin_lock_init(&dsi.errors_lock); dsi.errors = 0; -- cgit v1.2.2 From f36a06e702ef804a99ce3a286514d84610a74db5 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 14:48:41 +0200 Subject: OMAP: DSS2: DSI: use ISR in send_bta_sync Remove bta_completion handling from the interrupt handler, and use ISR support instead. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 8613ec489410..18b72521ee7e 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -249,7 +249,6 @@ static struct unsigned pll_locked; - struct completion bta_completion; void (*bta_callback)(void); spinlock_t irq_lock; @@ -338,6 +337,11 @@ static bool dsi_bus_is_locked(void) return dsi.bus_lock.count == 0; } +static void dsi_completion_handler(void *data, u32 mask) +{ + complete((struct completion *)data); +} + static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum, int value) { @@ -641,8 +645,6 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) continue; if (vcstatus[i] & DSI_VC_IRQ_BTA) { - complete(&dsi.bta_completion); - if (dsi.bta_callback) dsi.bta_callback(); } @@ -2263,33 +2265,37 @@ static int dsi_vc_send_bta(int channel) int dsi_vc_send_bta_sync(int channel) { + DECLARE_COMPLETION_ONSTACK(completion); int r = 0; u32 err; - INIT_COMPLETION(dsi.bta_completion); - - dsi_vc_enable_bta_irq(channel); + r = dsi_register_isr_vc(channel, dsi_completion_handler, + &completion, DSI_VC_IRQ_BTA); + if (r) + goto err0; r = dsi_vc_send_bta(channel); if (r) - goto err; + goto err1; - if (wait_for_completion_timeout(&dsi.bta_completion, + if (wait_for_completion_timeout(&completion, msecs_to_jiffies(500)) == 0) { DSSERR("Failed to receive BTA\n"); r = -EIO; - goto err; + goto err1; } err = dsi_get_errors(); if (err) { DSSERR("Error while sending BTA: %x\n", err); r = -EIO; - goto err; + goto err1; } -err: - dsi_vc_disable_bta_irq(channel); +err1: + dsi_unregister_isr_vc(channel, dsi_completion_handler, + &completion, DSI_VC_IRQ_BTA); +err0: return r; } EXPORT_SYMBOL(dsi_vc_send_bta_sync); @@ -3670,8 +3676,6 @@ static int dsi_init(struct platform_device *pdev) dsi.irq_stats.last_reset = jiffies; #endif - init_completion(&dsi.bta_completion); - mutex_init(&dsi.lock); sema_init(&dsi.bus_lock, 1); -- cgit v1.2.2 From f34bd465cae57bcce11fb7f953cfcbb18222b99e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 14:52:48 +0200 Subject: OMAP: DSS2: DSI: use ISR for BTA in framedone Remove bta_callback from the interrupt handler, and use ISR support instead. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 57 ++++++++++++------------------------------- 1 file changed, 15 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 18b72521ee7e..cd872e9d7989 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -249,8 +249,6 @@ static struct unsigned pll_locked; - void (*bta_callback)(void); - spinlock_t irq_lock; struct dsi_isr_tables isr_tables; /* space for a copy used by the interrupt handler */ @@ -640,16 +638,6 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) del_timer(&dsi.te_timer); #endif - for (i = 0; i < 4; ++i) { - if (vcstatus[i] == 0) - continue; - - if (vcstatus[i] & DSI_VC_IRQ_BTA) { - if (dsi.bta_callback) - dsi.bta_callback(); - } - } - /* make a copy and unlock, so that isrs can unregister * themselves */ memcpy(&dsi.isr_tables_copy, &dsi.isr_tables, sizeof(dsi.isr_tables)); @@ -923,26 +911,6 @@ static u32 dsi_get_errors(void) return e; } -static void dsi_vc_enable_bta_irq(int channel) -{ - u32 l; - - dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA); - - l = dsi_read_reg(DSI_VC_IRQENABLE(channel)); - l |= DSI_VC_IRQ_BTA; - dsi_write_reg(DSI_VC_IRQENABLE(channel), l); -} - -static void dsi_vc_disable_bta_irq(int channel) -{ - u32 l; - - l = dsi_read_reg(DSI_VC_IRQENABLE(channel)); - l &= ~DSI_VC_IRQ_BTA; - dsi_write_reg(DSI_VC_IRQENABLE(channel), l); -} - /* DSI func clock. this could also be dsi_pll_hsdiv_dsi_clk */ static inline void enable_clocks(bool enable) { @@ -3109,19 +3077,20 @@ static void dsi_te_timeout(unsigned long arg) } #endif +static void dsi_framedone_bta_callback(void *data, u32 mask); + static void dsi_handle_framedone(int error) { const int channel = dsi.update_channel; - cancel_delayed_work(&dsi.framedone_timeout_work); + dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback, + NULL, DSI_VC_IRQ_BTA); - dsi_vc_disable_bta_irq(channel); + cancel_delayed_work(&dsi.framedone_timeout_work); /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); - dsi.bta_callback = NULL; - if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ @@ -3155,7 +3124,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) dsi_handle_framedone(-ETIMEDOUT); } -static void dsi_framedone_bta_callback(void) +static void dsi_framedone_bta_callback(void *data, u32 mask) { dsi_handle_framedone(0); @@ -3195,15 +3164,19 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) * asynchronously. * */ - dsi.bta_callback = dsi_framedone_bta_callback; - - barrier(); - - dsi_vc_enable_bta_irq(channel); + r = dsi_register_isr_vc(channel, dsi_framedone_bta_callback, + NULL, DSI_VC_IRQ_BTA); + if (r) { + DSSERR("Failed to register BTA ISR\n"); + dsi_handle_framedone(-EIO); + return; + } r = dsi_vc_send_bta(channel); if (r) { DSSERR("BTA after framedone failed\n"); + dsi_unregister_isr_vc(channel, dsi_framedone_bta_callback, + NULL, DSI_VC_IRQ_BTA); dsi_handle_framedone(-EIO); } } -- cgit v1.2.2 From 773b30b22f8c5ac4ccc52775c17809cc5826cb86 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 8 Oct 2010 16:15:25 +0300 Subject: OMAP: DSS2: DSI: catch DSI errors in send_bta_sync dsi_vc_send_bta_sync() waits for BTA interrupt with a 500ms timeout. If a DSI error happens, no BTA is received and the timeout triggers. This could be handled much faster by listening to DSI errors also. This patch uses the ISR support to notice DSI errors while waiting for the BTA, thus speeding up the fail-path considerably. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index cd872e9d7989..37226628bc0f 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2242,24 +2242,31 @@ int dsi_vc_send_bta_sync(int channel) if (r) goto err0; - r = dsi_vc_send_bta(channel); + r = dsi_register_isr(dsi_completion_handler, &completion, + DSI_IRQ_ERROR_MASK); if (r) goto err1; + r = dsi_vc_send_bta(channel); + if (r) + goto err2; + if (wait_for_completion_timeout(&completion, msecs_to_jiffies(500)) == 0) { DSSERR("Failed to receive BTA\n"); r = -EIO; - goto err1; + goto err2; } err = dsi_get_errors(); if (err) { DSSERR("Error while sending BTA: %x\n", err); r = -EIO; - goto err1; + goto err2; } - +err2: + dsi_unregister_isr(dsi_completion_handler, &completion, + DSI_IRQ_ERROR_MASK); err1: dsi_unregister_isr_vc(channel, dsi_completion_handler, &completion, DSI_VC_IRQ_BTA); -- cgit v1.2.2 From d80d499ed926e70b429d309360f5910d5ad54788 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Mar 2011 15:53:07 +0200 Subject: OMAP: DSS2: DSI: fix IRQ debug prints print_irq_status functions can be called with empty irq status when full irq debugging is enabled. This patch makes print_irq_status functions return immediately when given an empty irq status to lessen the debug spam slightly. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 37226628bc0f..0a7f1a47f8e3 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -409,6 +409,9 @@ static void dsi_perf_show(const char *name) static void print_irq_status(u32 status) { + if (status == 0) + return; + #ifndef VERBOSE_IRQ if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0) return; @@ -444,6 +447,9 @@ static void print_irq_status(u32 status) static void print_irq_status_vc(int channel, u32 status) { + if (status == 0) + return; + #ifndef VERBOSE_IRQ if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0) return; @@ -470,6 +476,9 @@ static void print_irq_status_vc(int channel, u32 status) static void print_irq_status_cio(u32 status) { + if (status == 0) + return; + printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status); #define PIS(x) \ -- cgit v1.2.2 From 709de99df0ecf3102e7728fbd876a3591859f423 Mon Sep 17 00:00:00 2001 From: Chuanxiao Dong Date: Sat, 22 Jan 2011 04:09:41 +0800 Subject: mmc: export eMMC4.4 enhanced area details to sysfs Enhanced area feature is a new feature defined in eMMC4.4 standard. This user data area provides higher performance/reliability, at the expense of using twice the effective media space due to the area using SLC. The MMC driver now reads out the enhanced area offset and size and adds them to the device attributes in sysfs. Enabling the enhanced area can only be done once, and should be done in manufacturing. To use this feature, bit ERASE_GRP_DEF should also be set. Documentation/ABI/testing/sysfs-devices-mmc describes the two new attributes. Signed-off-by: Chuanxiao Dong Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 16006ef153fe..6396c5d98e85 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -302,6 +302,44 @@ static int mmc_read_ext_csd(struct mmc_card *card) } if (card->ext_csd.rev >= 4) { + /* + * Enhanced area feature support -- check whether the eMMC + * card has the Enhanced area enabled. If so, export enhanced + * area offset and size to user by adding sysfs interface. + */ + if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && + (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { + u8 hc_erase_grp_sz = + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; + u8 hc_wp_grp_sz = + ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + + card->ext_csd.enhanced_area_en = 1; + /* + * calculate the enhanced data area offset, in bytes + */ + card->ext_csd.enhanced_area_offset = + (ext_csd[139] << 24) + (ext_csd[138] << 16) + + (ext_csd[137] << 8) + ext_csd[136]; + if (mmc_card_blockaddr(card)) + card->ext_csd.enhanced_area_offset <<= 9; + /* + * calculate the enhanced data area size, in kilobytes + */ + card->ext_csd.enhanced_area_size = + (ext_csd[142] << 16) + (ext_csd[141] << 8) + + ext_csd[140]; + card->ext_csd.enhanced_area_size *= + (size_t)(hc_erase_grp_sz * hc_wp_grp_sz); + card->ext_csd.enhanced_area_size <<= 9; + } else { + /* + * If the enhanced area is not enabled, disable these + * device attributes. + */ + card->ext_csd.enhanced_area_offset = -EINVAL; + card->ext_csd.enhanced_area_size = -EINVAL; + } card->ext_csd.sec_trim_mult = ext_csd[EXT_CSD_SEC_TRIM_MULT]; card->ext_csd.sec_erase_mult = @@ -336,6 +374,9 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); +MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", + card->ext_csd.enhanced_area_offset); +MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, @@ -349,6 +390,8 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_name.attr, &dev_attr_oemid.attr, &dev_attr_serial.attr, + &dev_attr_enhanced_area_offset.attr, + &dev_attr_enhanced_area_size.attr, NULL, }; @@ -483,6 +526,37 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_set_erase_size(card); } + /* + * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF + * bit. This bit will be lost everytime after a reset or power off. + */ + if (card->ext_csd.enhanced_area_en) { + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_ERASE_GROUP_DEF, 1); + + if (err && err != -EBADMSG) + goto free_card; + + if (err) { + err = 0; + /* + * Just disable enhanced area off & sz + * will try to enable ERASE_GROUP_DEF + * during next time reinit + */ + card->ext_csd.enhanced_area_offset = -EINVAL; + card->ext_csd.enhanced_area_size = -EINVAL; + } else { + card->ext_csd.erase_group_def = 1; + /* + * enable ERASE_GRP_DEF successfully. + * This will affect the erase size, so + * here need to reset erase size + */ + mmc_set_erase_size(card); + } + } + /* * Activate high speed (if supported) */ -- cgit v1.2.2 From 3362177fe1b7c23ee8497ee720ab4d6f6ba0b840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20H=C3=A9bert?= Date: Mon, 31 Jan 2011 12:31:24 -0500 Subject: mmc: Fix the block device read only flag While the MMC handled the card's read only flag correctly on open, it did not setup the flag in the allocated disk structure. The consequence being that probing the /sys/class/block/mmcblkX/ro attribute always reported 0. Signed-off-by: Marc-Andre Hebert Reviewed-by: Chris Ball Tested-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/card/block.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index bfc8a8ae55df..61d233a7c118 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -621,6 +621,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) md->disk->private_data = md; md->disk->queue = md->queue.queue; md->disk->driverfs_dev = &card->dev; + set_disk_ro(md->disk, md->read_only); /* * As discussed on lkml, GENHD_FL_REMOVABLE should: -- cgit v1.2.2 From 732f0e31db03c84005578927ed9d4e996c3c0020 Mon Sep 17 00:00:00 2001 From: Kyungmin Park Date: Sat, 30 Oct 2010 12:58:56 +0900 Subject: mmc: sdhci-s3c: Auto CMD12 support Samsung SDHCI host controller supports the Auto CMD12. Signed-off-by: Kyungmin Park Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-s3c.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 5309ab95aada..69e3ee321eb5 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -499,6 +499,9 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) * SDHCI block, or a missing configuration that needs to be set. */ host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ; + /* This host supports the Auto CMD12 */ + host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; + if (pdata->cd_type == S3C_SDHCI_CD_NONE || pdata->cd_type == S3C_SDHCI_CD_PERMANENT) host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; -- cgit v1.2.2 From 54d6b44a5f0da708e8a9e496df304e05e8748ef9 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Sun, 6 Feb 2011 15:06:24 -0500 Subject: mmc: mmc_test: Only warn about not waiting for busy if it's supported If the MMC host controller does not support waiting for card signaling busy state (MMC_CAP_WAIT_WHILE_BUSY cap), there is no point in prining the relevant warning message. Signed-off-by: Pawel Moll Reviewed-by: Matt Fleming Signed-off-by: Chris Ball --- drivers/mmc/card/mmc_test.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 21adc27f4132..0131c6c0d8f6 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -226,9 +226,10 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) if (!busy && mmc_test_busy(&cmd)) { busy = 1; - printk(KERN_INFO "%s: Warning: Host did not " - "wait for busy state to end.\n", - mmc_hostname(test->card->host)); + if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) + printk(KERN_INFO "%s: Warning: Host did not " + "wait for busy state to end.\n", + mmc_hostname(test->card->host)); } } while (mmc_test_busy(&cmd)); -- cgit v1.2.2 From 66c036e0142fed2484d58a2d3c7a4d21ba32b6a6 Mon Sep 17 00:00:00 2001 From: Pierre Tardy Date: Sun, 6 Feb 2011 19:02:48 +0100 Subject: mmc: put the led blinking code after clock ungating Since mmc clock gating can also be used as a power gating tip, it's better to put the led blinking after having ungated the clock. Signed-off-by: Pierre Tardy Acked-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 150b5f3cd401..2af2ee1a2265 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -167,8 +167,6 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) WARN_ON(!host->claimed); - led_trigger_event(host->led, LED_FULL); - mrq->cmd->error = 0; mrq->cmd->mrq = mrq; if (mrq->data) { @@ -194,6 +192,7 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) } } mmc_host_clk_ungate(host); + led_trigger_event(host->led, LED_FULL); host->ops->request(host, mrq); } -- cgit v1.2.2 From 57f0adc7eaaf4315d568e72069dbe48aa7e20995 Mon Sep 17 00:00:00 2001 From: Pierre Tardy Date: Sun, 6 Feb 2011 19:03:46 +0100 Subject: mmc: add per device quirk placeholder Some cards have quirks valid for every platforms using current platform quirk hooks leads to a lot of code and debug duplication. So we inspire a bit from what exists in PCI subsystem and do our own per vendorid/deviceid quirk. We still drop the complexity of the pci quirk system (with special section tables, and so on). That can be added later if needed. Signed-off-by: Pierre Tardy Acked-by: Linus Walleij Acked-by: Ohad Ben-Cohen Signed-off-by: Chris Ball --- drivers/mmc/core/Makefile | 3 ++- drivers/mmc/core/core.h | 2 ++ drivers/mmc/core/quirks.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/sdio.c | 1 + 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 drivers/mmc/core/quirks.c (limited to 'drivers') diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 86b479119332..639501970b41 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_MMC) += mmc_core.o mmc_core-y := core.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ - sdio_cis.o sdio_io.o sdio_irq.o + sdio_cis.o sdio_io.o sdio_irq.o \ + quirks.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index ca1fdde29df6..20b1c0831eac 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -61,6 +61,8 @@ int mmc_attach_mmc(struct mmc_host *host); int mmc_attach_sd(struct mmc_host *host); int mmc_attach_sdio(struct mmc_host *host); +void mmc_fixup_device(struct mmc_card *card); + /* Module parameters */ extern int use_spi_crc; diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c new file mode 100644 index 000000000000..e18cb49c12b1 --- /dev/null +++ b/drivers/mmc/core/quirks.c @@ -0,0 +1,61 @@ +/* + * This file contains work-arounds for many known sdio hardware + * bugs. + * + * Copyright (c) 2011 Pierre Tardy + * Inspired from pci fixup code: + * Copyright (c) 1999 Martin Mares + * + */ + +#include +#include +#include +#include + +/* + * The world is not perfect and supplies us with broken mmc/sdio devices. + * For at least a part of these bugs we need a work-around + */ + +struct mmc_fixup { + u16 vendor, device; /* You can use SDIO_ANY_ID here of course */ + void (*vendor_fixup)(struct mmc_card *card, int data); + int data; +}; + +/* + * This hook just adds a quirk unconditionnally + */ +static void __maybe_unused add_quirk(struct mmc_card *card, int data) +{ + card->quirks |= data; +} + +/* + * This hook just removes a quirk unconditionnally + */ +static void __maybe_unused remove_quirk(struct mmc_card *card, int data) +{ + card->quirks &= ~data; +} + +static const struct mmc_fixup mmc_fixup_methods[] = { + { 0 } +}; + +void mmc_fixup_device(struct mmc_card *card) +{ + const struct mmc_fixup *f; + + for (f = mmc_fixup_methods; f->vendor_fixup; f++) { + if ((f->vendor == card->cis.vendor + || f->vendor == (u16) SDIO_ANY_ID) && + (f->device == card->cis.device + || f->device == (u16) SDIO_ANY_ID)) { + dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup); + f->vendor_fixup(card, f->data); + } + } +} +EXPORT_SYMBOL(mmc_fixup_device); diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ebc62ad4cc56..c9fbb777440d 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -458,6 +458,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, card = oldcard; } + mmc_fixup_device(card); if (card->type == MMC_TYPE_SD_COMBO) { err = mmc_sd_setup_card(host, card, oldcard != NULL); -- cgit v1.2.2 From db9935000d95ae3f9702b7ff6ac0eef2319d8772 Mon Sep 17 00:00:00 2001 From: Pierre Tardy Date: Sun, 6 Feb 2011 19:03:47 +0100 Subject: mmc: add MMC_QUIRK_BROKEN_CLK_GATING Some sdio card are not following sdio standard, and do not work when the sdio bus's clock is gated. To keep functionnality for all legacy driver, we turn this quirk on for every sdio card. Drivers needs to disable the quirk manually when someone verifies that their supported card works with clock gating. Signed-off-by: Pierre Tardy Acked-by: Ohad Ben-Cohen Signed-off-by: Chris Ball --- drivers/mmc/core/host.c | 5 +---- drivers/mmc/core/quirks.c | 13 +++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index b3ac6c5bc5c6..461e6a17fb90 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -160,10 +160,7 @@ static bool mmc_host_may_gate_card(struct mmc_card *card) * gate the clock, because there is somebody out there that may still * be using it. */ - if (mmc_card_sdio(card)) - return false; - - return true; + return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING); } /** diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index e18cb49c12b1..890843129e3b 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -40,7 +40,20 @@ static void __maybe_unused remove_quirk(struct mmc_card *card, int data) card->quirks &= ~data; } +/* + * This hook just adds a quirk for all sdio devices + */ +static void add_quirk_for_sdio_devices(struct mmc_card *card, int data) +{ + if (mmc_card_sdio(card)) + card->quirks |= data; +} + static const struct mmc_fixup mmc_fixup_methods[] = { + /* by default sdio devices are considered CLK_GATING broken */ + /* good cards will be whitelisted as they are tested */ + { SDIO_ANY_ID, SDIO_ANY_ID, + add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING } { 0 } }; -- cgit v1.2.2 From 12f8ef8fb21f3b410b28eb57fc79bfe71232512a Mon Sep 17 00:00:00 2001 From: Pierre Tardy Date: Sun, 6 Feb 2011 19:04:17 +0100 Subject: mmc: remove BROKEN_CLK_GATING quirk for wl1271 This sdio card supports having its sdio clock shutdown. It is also not using the SDIO IRQ, but rather uses a side gpio irq. Signed-off-by: Pierre Tardy Signed-off-by: Chris Ball --- drivers/mmc/core/quirks.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index 890843129e3b..11118b74eb20 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -49,11 +49,21 @@ static void add_quirk_for_sdio_devices(struct mmc_card *card, int data) card->quirks |= data; } +#ifndef SDIO_VENDOR_ID_TI +#define SDIO_VENDOR_ID_TI 0x0097 +#endif + +#ifndef SDIO_DEVICE_ID_TI_WL1271 +#define SDIO_DEVICE_ID_TI_WL1271 0x4076 +#endif + static const struct mmc_fixup mmc_fixup_methods[] = { /* by default sdio devices are considered CLK_GATING broken */ /* good cards will be whitelisted as they are tested */ { SDIO_ANY_ID, SDIO_ANY_ID, - add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING } + add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING }, + { SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, + remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING }, { 0 } }; -- cgit v1.2.2 From 0532ff6358ae00615cfba7212f5075356b437c66 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Feb 2011 13:41:01 +0200 Subject: mmc: mmc_test: make performance test area size about 4MiB The test area size was set to the preferred erase size but for comparison purposes it is better if it is the same size for different devices. Make it a multiple of preferred erase size that is greater than or equal to 4MiB. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/card/mmc_test.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 0131c6c0d8f6..ec6060c06ce8 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -1426,28 +1426,29 @@ static int mmc_test_area_cleanup(struct mmc_test_card *test) } /* - * Initialize an area for testing large transfers. The size of the area is the - * preferred erase size which is a good size for optimal transfer speed. Note - * that is typically 4MiB for modern cards. The test area is set to the middle - * of the card because cards may have different charateristics at the front - * (for FAT file system optimization). Optionally, the area is erased (if the - * card supports it) which may improve write performance. Optionally, the area - * is filled with data for subsequent read tests. + * Initialize an area for testing large transfers. The test area is set to the + * middle of the card because cards may have different charateristics at the + * front (for FAT file system optimization). Optionally, the area is erased + * (if the card supports it) which may improve write performance. Optionally, + * the area is filled with data for subsequent read tests. */ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill) { struct mmc_test_area *t = &test->area; - unsigned long min_sz = 64 * 1024; + unsigned long min_sz = 64 * 1024, sz; int ret; ret = mmc_test_set_blksize(test, 512); if (ret) return ret; - if (test->card->pref_erase > TEST_AREA_MAX_SIZE >> 9) - t->max_sz = TEST_AREA_MAX_SIZE; - else - t->max_sz = (unsigned long)test->card->pref_erase << 9; + /* Make the test area size about 4MiB */ + sz = (unsigned long)test->card->pref_erase << 9; + t->max_sz = sz; + while (t->max_sz < 4 * 1024 * 1024) + t->max_sz += sz; + while (t->max_sz > TEST_AREA_MAX_SIZE && t->max_sz > sz) + t->max_sz -= sz; t->max_segs = test->card->host->max_segs; t->max_seg_sz = test->card->host->max_seg_size; -- cgit v1.2.2 From b6056d12342f936256cbf64c86459af06f11cd5e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Feb 2011 13:41:02 +0200 Subject: mmc: mmc_test: add tests to measure random I/O operations per second Existing performance tests measure single or sequential I/O speed. Add two random I/O tests: 33. Random read performance by transfer size 34. Random write performance by transfer size Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/card/mmc_test.c | 139 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 128 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index ec6060c06ce8..d1aa57a4d058 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -88,6 +88,7 @@ struct mmc_test_area { * @sectors: amount of sectors to check in one group * @ts: time values of transfer * @rate: calculated transfer rate + * @iops: I/O operations per second (times 100) */ struct mmc_test_transfer_result { struct list_head link; @@ -95,6 +96,7 @@ struct mmc_test_transfer_result { unsigned int sectors; struct timespec ts; unsigned int rate; + unsigned int iops; }; /** @@ -495,7 +497,7 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts) */ static void mmc_test_save_transfer_result(struct mmc_test_card *test, unsigned int count, unsigned int sectors, struct timespec ts, - unsigned int rate) + unsigned int rate, unsigned int iops) { struct mmc_test_transfer_result *tr; @@ -510,6 +512,7 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test, tr->sectors = sectors; tr->ts = ts; tr->rate = rate; + tr->iops = iops; list_add_tail(&tr->link, &test->gr->tr_lst); } @@ -520,20 +523,22 @@ static void mmc_test_save_transfer_result(struct mmc_test_card *test, static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, struct timespec *ts1, struct timespec *ts2) { - unsigned int rate, sectors = bytes >> 9; + unsigned int rate, iops, sectors = bytes >> 9; struct timespec ts; ts = timespec_sub(*ts2, *ts1); rate = mmc_test_rate(bytes, &ts); + iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */ printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " - "seconds (%u kB/s, %u KiB/s)\n", + "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n", mmc_hostname(test->card->host), sectors, sectors >> 1, (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, - (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024); + (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024, + iops / 100, iops % 100); - mmc_test_save_transfer_result(test, 1, sectors, ts, rate); + mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops); } /* @@ -543,22 +548,24 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, unsigned int count, struct timespec *ts1, struct timespec *ts2) { - unsigned int rate, sectors = bytes >> 9; + unsigned int rate, iops, sectors = bytes >> 9; uint64_t tot = bytes * count; struct timespec ts; ts = timespec_sub(*ts2, *ts1); rate = mmc_test_rate(tot, &ts); + iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */ printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " - "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n", + "%lu.%09lu seconds (%u kB/s, %u KiB/s, " + "%u.%02u IOPS)\n", mmc_hostname(test->card->host), count, sectors, count, sectors >> 1, (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec, - rate / 1000, rate / 1024); + rate / 1000, rate / 1024, iops / 100, iops % 100); - mmc_test_save_transfer_result(test, count, sectors, ts, rate); + mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops); } /* @@ -1768,6 +1775,102 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test) return 0; } +static unsigned int rnd_next = 1; + +static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt) +{ + uint64_t r; + + rnd_next = rnd_next * 1103515245 + 12345; + r = (rnd_next >> 16) & 0x7fff; + return (r * rnd_cnt) >> 15; +} + +static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print, + unsigned long sz) +{ + unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea; + unsigned int ssz; + struct timespec ts1, ts2, ts; + int ret; + + ssz = sz >> 9; + + rnd_addr = mmc_test_capacity(test->card) / 4; + range1 = rnd_addr / test->card->pref_erase; + range2 = range1 / ssz; + + getnstimeofday(&ts1); + for (cnt = 0; cnt < UINT_MAX; cnt++) { + getnstimeofday(&ts2); + ts = timespec_sub(ts2, ts1); + if (ts.tv_sec >= 10) + break; + ea = mmc_test_rnd_num(range1); + if (ea == last_ea) + ea -= 1; + last_ea = ea; + dev_addr = rnd_addr + test->card->pref_erase * ea + + ssz * mmc_test_rnd_num(range2); + ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0); + if (ret) + return ret; + } + if (print) + mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); + return 0; +} + +static int mmc_test_random_perf(struct mmc_test_card *test, int write) +{ + unsigned int next; + unsigned long sz; + int ret; + + for (sz = 512; sz < test->area.max_tfr; sz <<= 1) { + /* + * When writing, try to get more consistent results by running + * the test twice with exactly the same I/O but outputting the + * results only for the 2nd run. + */ + if (write) { + next = rnd_next; + ret = mmc_test_rnd_perf(test, write, 0, sz); + if (ret) + return ret; + rnd_next = next; + } + ret = mmc_test_rnd_perf(test, write, 1, sz); + if (ret) + return ret; + } + sz = test->area.max_tfr; + if (write) { + next = rnd_next; + ret = mmc_test_rnd_perf(test, write, 0, sz); + if (ret) + return ret; + rnd_next = next; + } + return mmc_test_rnd_perf(test, write, 1, sz); +} + +/* + * Random read performance by transfer size. + */ +static int mmc_test_random_read_perf(struct mmc_test_card *test) +{ + return mmc_test_random_perf(test, 0); +} + +/* + * Random write performance by transfer size. + */ +static int mmc_test_random_write_perf(struct mmc_test_card *test) +{ + return mmc_test_random_perf(test, 1); +} + static const struct mmc_test_case mmc_test_cases[] = { { .name = "Basic write (no data verification)", @@ -2007,6 +2110,20 @@ static const struct mmc_test_case mmc_test_cases[] = { .cleanup = mmc_test_area_cleanup, }, + { + .name = "Random read performance by transfer size", + .prepare = mmc_test_area_prepare, + .run = mmc_test_random_read_perf, + .cleanup = mmc_test_area_cleanup, + }, + + { + .name = "Random write performance by transfer size", + .prepare = mmc_test_area_prepare, + .run = mmc_test_random_write_perf, + .cleanup = mmc_test_area_cleanup, + }, + }; static DEFINE_MUTEX(mmc_test_lock); @@ -2150,11 +2267,11 @@ static int mtf_test_show(struct seq_file *sf, void *data) seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result); list_for_each_entry(tr, &gr->tr_lst, link) { - seq_printf(sf, "%u %d %lu.%09lu %u\n", + seq_printf(sf, "%u %d %lu.%09lu %u %u.%02u\n", tr->count, tr->sectors, (unsigned long)tr->ts.tv_sec, (unsigned long)tr->ts.tv_nsec, - tr->rate); + tr->rate, tr->iops / 100, tr->iops % 100); } } -- cgit v1.2.2 From a803d551d92079beb599cc37fa407c059c82c821 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 8 Feb 2011 13:41:03 +0200 Subject: mmc: mmc_test: add tests to measure large sequential I/O performance Add two large sequential I/O performance tests: 35. Large sequential read into scattered pages 36. Large sequential write from scattered pages The tests measure transfer times for 10MiB, 100MiB, 1000MiB. Signed-off-by: Adrian Hunter Signed-off-by: Chris Ball --- drivers/mmc/card/mmc_test.c | 100 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index d1aa57a4d058..5ec8eddfcf6e 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -1871,6 +1871,92 @@ static int mmc_test_random_write_perf(struct mmc_test_card *test) return mmc_test_random_perf(test, 1); } +static int mmc_test_seq_perf(struct mmc_test_card *test, int write, + unsigned int tot_sz, int max_scatter) +{ + unsigned int dev_addr, i, cnt, sz, ssz; + struct timespec ts1, ts2, ts; + int ret; + + sz = test->area.max_tfr; + /* + * In the case of a maximally scattered transfer, the maximum transfer + * size is further limited by using PAGE_SIZE segments. + */ + if (max_scatter) { + struct mmc_test_area *t = &test->area; + unsigned long max_tfr; + + if (t->max_seg_sz >= PAGE_SIZE) + max_tfr = t->max_segs * PAGE_SIZE; + else + max_tfr = t->max_segs * t->max_seg_sz; + if (sz > max_tfr) + sz = max_tfr; + } + + ssz = sz >> 9; + dev_addr = mmc_test_capacity(test->card) / 4; + if (tot_sz > dev_addr << 9) + tot_sz = dev_addr << 9; + cnt = tot_sz / sz; + dev_addr &= 0xffff0000; /* Round to 64MiB boundary */ + + getnstimeofday(&ts1); + for (i = 0; i < cnt; i++) { + ret = mmc_test_area_io(test, sz, dev_addr, write, + max_scatter, 0); + if (ret) + return ret; + dev_addr += ssz; + } + getnstimeofday(&ts2); + + ts = timespec_sub(ts2, ts1); + mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); + + return 0; +} + +static int mmc_test_large_seq_perf(struct mmc_test_card *test, int write) +{ + int ret, i; + + for (i = 0; i < 10; i++) { + ret = mmc_test_seq_perf(test, write, 10 * 1024 * 1024, 1); + if (ret) + return ret; + } + for (i = 0; i < 5; i++) { + ret = mmc_test_seq_perf(test, write, 100 * 1024 * 1024, 1); + if (ret) + return ret; + } + for (i = 0; i < 3; i++) { + ret = mmc_test_seq_perf(test, write, 1000 * 1024 * 1024, 1); + if (ret) + return ret; + } + + return ret; +} + +/* + * Large sequential read performance. + */ +static int mmc_test_large_seq_read_perf(struct mmc_test_card *test) +{ + return mmc_test_large_seq_perf(test, 0); +} + +/* + * Large sequential write performance. + */ +static int mmc_test_large_seq_write_perf(struct mmc_test_card *test) +{ + return mmc_test_large_seq_perf(test, 1); +} + static const struct mmc_test_case mmc_test_cases[] = { { .name = "Basic write (no data verification)", @@ -2124,6 +2210,20 @@ static const struct mmc_test_case mmc_test_cases[] = { .cleanup = mmc_test_area_cleanup, }, + { + .name = "Large sequential read into scattered pages", + .prepare = mmc_test_area_prepare, + .run = mmc_test_large_seq_read_perf, + .cleanup = mmc_test_area_cleanup, + }, + + { + .name = "Large sequential write from scattered pages", + .prepare = mmc_test_area_prepare, + .run = mmc_test_large_seq_write_perf, + .cleanup = mmc_test_area_cleanup, + }, + }; static DEFINE_MUTEX(mmc_test_lock); -- cgit v1.2.2 From a803d7fbc1ae64244eb8738aa0e4ac491b45d26c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 9 Feb 2011 07:25:22 +0900 Subject: mmc: tmio_mmc: Improve readability of the output of pr_debug_status() Reviewed-by: Guennadi Liakhovetski Signed-off-by: Simon Horman Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 50 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e3c6ef208391..a33f71841dec 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -228,36 +228,40 @@ static void tmio_mmc_kunmap_atomic(void *virt, unsigned long *flags) #ifdef CONFIG_MMC_DEBUG -#define STATUS_TO_TEXT(a) \ +#define STATUS_TO_TEXT(a, status, i) \ do { \ - if (status & TMIO_STAT_##a) \ + if (status & TMIO_STAT_##a) { \ + if (i++) \ + printk(" | "); \ printk(#a); \ + } \ } while (0) void pr_debug_status(u32 status) { + int i = 0; printk(KERN_DEBUG "status: %08x = ", status); - STATUS_TO_TEXT(CARD_REMOVE); - STATUS_TO_TEXT(CARD_INSERT); - STATUS_TO_TEXT(SIGSTATE); - STATUS_TO_TEXT(WRPROTECT); - STATUS_TO_TEXT(CARD_REMOVE_A); - STATUS_TO_TEXT(CARD_INSERT_A); - STATUS_TO_TEXT(SIGSTATE_A); - STATUS_TO_TEXT(CMD_IDX_ERR); - STATUS_TO_TEXT(STOPBIT_ERR); - STATUS_TO_TEXT(ILL_FUNC); - STATUS_TO_TEXT(CMD_BUSY); - STATUS_TO_TEXT(CMDRESPEND); - STATUS_TO_TEXT(DATAEND); - STATUS_TO_TEXT(CRCFAIL); - STATUS_TO_TEXT(DATATIMEOUT); - STATUS_TO_TEXT(CMDTIMEOUT); - STATUS_TO_TEXT(RXOVERFLOW); - STATUS_TO_TEXT(TXUNDERRUN); - STATUS_TO_TEXT(RXRDY); - STATUS_TO_TEXT(TXRQ); - STATUS_TO_TEXT(ILL_ACCESS); + STATUS_TO_TEXT(CARD_REMOVE, status, i); + STATUS_TO_TEXT(CARD_INSERT, status, i); + STATUS_TO_TEXT(SIGSTATE, status, i); + STATUS_TO_TEXT(WRPROTECT, status, i); + STATUS_TO_TEXT(CARD_REMOVE_A, status, i); + STATUS_TO_TEXT(CARD_INSERT_A, status, i); + STATUS_TO_TEXT(SIGSTATE_A, status, i); + STATUS_TO_TEXT(CMD_IDX_ERR, status, i); + STATUS_TO_TEXT(STOPBIT_ERR, status, i); + STATUS_TO_TEXT(ILL_FUNC, status, i); + STATUS_TO_TEXT(CMD_BUSY, status, i); + STATUS_TO_TEXT(CMDRESPEND, status, i); + STATUS_TO_TEXT(DATAEND, status, i); + STATUS_TO_TEXT(CRCFAIL, status, i); + STATUS_TO_TEXT(DATATIMEOUT, status, i); + STATUS_TO_TEXT(CMDTIMEOUT, status, i); + STATUS_TO_TEXT(RXOVERFLOW, status, i); + STATUS_TO_TEXT(TXUNDERRUN, status, i); + STATUS_TO_TEXT(RXRDY, status, i); + STATUS_TO_TEXT(TXRQ, status, i); + STATUS_TO_TEXT(ILL_ACCESS, status, i); printk("\n"); } -- cgit v1.2.2 From 170cba8cad5d9350f2c76bbd22013cc31ae26b0f Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 20 Jan 2011 15:02:59 -0200 Subject: mmc: mmc_mxc: Allow selection only for the correct platforms Currently MMC_MXC driver can be selected by all i.MX devices. Restrict its use only for the appropriate processors. Signed-off-by: Fabio Estevam Acked-by: Sascha Hauer Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index afe8c6fa166a..54b7bd54a52a 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -311,7 +311,7 @@ config MMC_MSM config MMC_MXC tristate "Freescale i.MX2/3 Multimedia Card Interface support" - depends on ARCH_MXC + depends on MACH_MX21 || MACH_MX27 || ARCH_MX31 help This selects the Freescale i.MX2/3 Multimedia card Interface. If you have a i.MX platform with a Multimedia Card slot, -- cgit v1.2.2 From dd6c4b9807581b37bf68ba3cd160c6859f070d39 Mon Sep 17 00:00:00 2001 From: Will Newton Date: Thu, 10 Feb 2011 14:37:03 -0500 Subject: mmc: dw_mmc: Run card detect tasklet during slot initialisation. We need to run the card detect tasklet at the end of slot initialisation as it is possible that a card has been inserted prior to boot, so we don't see an insertion interrupt and now the card is sitting there inserted but with no power to it. Signed-off-by: Neil Jones Signed-off-by: Will Newton Reviewed-by: Matt Fleming Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 2fcc82577c1b..c01cb8642fb5 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1441,6 +1441,12 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) /* Card initially undetected */ slot->last_detect_state = 0; + /* + * Card may have been plugged in prior to boot so we + * need to run the detect tasklet + */ + tasklet_schedule(&host->card_tasklet); + return 0; } -- cgit v1.2.2 From aadb9f4110096876c6f03073415439f76f0c61ca Mon Sep 17 00:00:00 2001 From: Will Newton Date: Thu, 10 Feb 2011 10:40:57 +0000 Subject: mmc: dw_mmc: Enable low-power mode for the card clock. Setting this bit in the clock enable register will stop the clock when the card is in the IDLE state. Signed-off-by: Will Newton Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c01cb8642fb5..cd6d8212dacc 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -562,7 +562,8 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot) SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0); /* enable clock */ - mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE); + mci_writel(host, CLKENA, SDMMC_CLKEN_ENABLE | + SDMMC_CLKEN_LOW_PWR); /* inform CIU */ mci_send_cmd(slot, -- cgit v1.2.2 From 50cec37c1ac24e9a02b845242a4712e2fb092b5c Mon Sep 17 00:00:00 2001 From: Will Newton Date: Thu, 10 Feb 2011 10:41:02 +0000 Subject: mmc: Improve MMC_TEST config text. The test file is created under debugfs, not sysfs. Also remove the unnecessary default n. Signed-off-by: Will Newton Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/card/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig index 2a876c4099cd..3b1f783bf924 100644 --- a/drivers/mmc/card/Kconfig +++ b/drivers/mmc/card/Kconfig @@ -58,12 +58,11 @@ config SDIO_UART config MMC_TEST tristate "MMC host test driver" - default n help Development driver that performs a series of reads and writes to a memory card in order to expose certain well known bugs in host controllers. The tests are executed by writing to the - "test" file in sysfs under each card. Note that whatever is + "test" file in debugfs under each card. Note that whatever is on your card will be overwritten by these tests. This driver is only of interest to those developing or -- cgit v1.2.2 From ce1014965ae2538e7447b19879bd0e8109690b79 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 10 Feb 2011 10:58:37 +0000 Subject: mmc: Ensure prototypes for SD API are visible in sd.c So we know the implementation and prototypes agree with each other. Signed-off-by: Mark Brown Reviewed-by: Chris Ball Signed-off-by: Chris Ball --- drivers/mmc/core/sd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d18c32bca99b..6dac89fe0535 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -21,6 +21,7 @@ #include "core.h" #include "bus.h" #include "mmc_ops.h" +#include "sd.h" #include "sd_ops.h" static const unsigned int tran_exp[] = { -- cgit v1.2.2 From 5fd11c0754fa069b6aba64b65734aa2fb193552d Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Fri, 11 Feb 2011 16:25:31 -0600 Subject: mmc: sdhci: Add Ricoh e823 PCI ID Signed-off-by: Manoj Iyer Cc: Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 0dc905b20eee..f7e622c539ba 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -546,6 +546,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, }, + { + .vendor = PCI_VENDOR_ID_RICOH, + .device = 0xe823, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc, + }, + { .vendor = PCI_VENDOR_ID_ENE, .device = PCI_DEVICE_ID_ENE_CB712_SD, -- cgit v1.2.2 From 266ac3f297adb72fb6c34949a38337c6fad4c7a6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:08:06 +0100 Subject: mmc: atmel-mci: map DMA sglist on the DMA engine As established for the MMCI, it is proper to map the DMA buffers on the DMA engine which is the one actually performing the DMA. Signed-off-by: Linus Walleij Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index ad2a7a032cdf..045bdbbe3720 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -578,7 +578,8 @@ static void atmci_dma_cleanup(struct atmel_mci *host) struct mmc_data *data = host->data; if (data) - dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len, + dma_unmap_sg(host->dma.chan->device->dev, + data->sg, data->sg_len, ((data->flags & MMC_DATA_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); } @@ -684,7 +685,8 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) else direction = DMA_TO_DEVICE; - sglen = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, direction); + sglen = dma_map_sg(chan->device->dev, data->sg, + data->sg_len, direction); if (sglen != data->sg_len) goto unmap_exit; desc = chan->device->device_prep_slave_sg(chan, @@ -699,7 +701,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) return 0; unmap_exit: - dma_unmap_sg(&host->pdev->dev, data->sg, sglen, direction); + dma_unmap_sg(chan->device->dev, data->sg, sglen, direction); return -ENOMEM; } -- cgit v1.2.2 From 88ce4db313bca1e4e6ef3b448471f85d3e14a854 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:08:16 +0100 Subject: mmc: atmel-mci: conform to DMA-API Fixes the following: - It is perfectly legal for the dma_map_sg() to return fewer entries than were passed in. - Supply the returned numer of (possibly coalesced) entries to the device_pre_slave_sg() function. - Use the proper original sg_len when unmapping the sglist in the error path. Signed-off-by: Linus Walleij Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 045bdbbe3720..df5a13542370 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -687,10 +687,9 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) sglen = dma_map_sg(chan->device->dev, data->sg, data->sg_len, direction); - if (sglen != data->sg_len) - goto unmap_exit; + desc = chan->device->device_prep_slave_sg(chan, - data->sg, data->sg_len, direction, + data->sg, sglen, direction, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) goto unmap_exit; @@ -701,7 +700,7 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) return 0; unmap_exit: - dma_unmap_sg(chan->device->dev, data->sg, sglen, direction); + dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction); return -ENOMEM; } -- cgit v1.2.2 From 5328906aa2e54a7a5e99e1ba8ee52b387e8be44b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:08:26 +0100 Subject: mmc: atmel-mci: use dmaengine helper functions Use the new dmaengine helpers to make the code more readable. Signed-off-by: Linus Walleij Signed-off-by: Nicolas Ferre Signed-off-by: Chris Ball --- drivers/mmc/host/atmel-mci.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index df5a13542370..80bc9a5c25cc 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -589,7 +589,7 @@ static void atmci_stop_dma(struct atmel_mci *host) struct dma_chan *chan = host->data_chan; if (chan) { - chan->device->device_control(chan, DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(chan); atmci_dma_cleanup(host); } else { /* Data transfer was stopped by the interrupt handler */ @@ -710,8 +710,8 @@ static void atmci_submit_data(struct atmel_mci *host) struct dma_async_tx_descriptor *desc = host->dma.data_desc; if (chan) { - desc->tx_submit(desc); - chan->device->device_issue_pending(chan); + dmaengine_submit(desc); + dma_async_issue_pending(chan); } } -- cgit v1.2.2 From 1ed828dbb4a90f273b2a3cc70c9c28306427ea7c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:09:29 +0100 Subject: mmc: sh_mmcif: map DMA buffers on the DMA engine device As established for the MMCI, it is proper to map the DMA buffers on the DMA engine which is the one actually performing the DMA. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 12884c270171..8e4aba90d6a4 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -194,10 +194,12 @@ static void mmcif_dma_complete(void *arg) return; if (host->data->flags & MMC_DATA_READ) - dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen, + dma_unmap_sg(host->chan_rx->device->dev, + host->data->sg, host->dma_sglen, DMA_FROM_DEVICE); else - dma_unmap_sg(&host->pd->dev, host->data->sg, host->dma_sglen, + dma_unmap_sg(host->chan_tx->device->dev, + host->data->sg, host->dma_sglen, DMA_TO_DEVICE); complete(&host->dma_complete); @@ -211,7 +213,8 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_FROM_DEVICE); + ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, + DMA_FROM_DEVICE); if (ret > 0) { host->dma_sglen = ret; desc = chan->device->device_prep_slave_sg(chan, sg, ret, @@ -263,7 +266,8 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) dma_cookie_t cookie = -EINVAL; int ret; - ret = dma_map_sg(&host->pd->dev, sg, host->data->sg_len, DMA_TO_DEVICE); + ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, + DMA_TO_DEVICE); if (ret > 0) { host->dma_sglen = ret; desc = chan->device->device_prep_slave_sg(chan, sg, ret, -- cgit v1.2.2 From 9dc3fb5e4584630c50f7a5405efe9835d321ad44 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:09:40 +0100 Subject: mmc: sh_mmcif: unmap with the proper sglen According to the DMA-API you shall unmap the sglists with the same sglist length as passed into the mapping function, not the returned value from the mapping function. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 8e4aba90d6a4..61ad19ecfbf8 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -195,11 +195,11 @@ static void mmcif_dma_complete(void *arg) if (host->data->flags & MMC_DATA_READ) dma_unmap_sg(host->chan_rx->device->dev, - host->data->sg, host->dma_sglen, + host->data->sg, host->data->sg_len, DMA_FROM_DEVICE); else dma_unmap_sg(host->chan_tx->device->dev, - host->data->sg, host->dma_sglen, + host->data->sg, host->data->sg_len, DMA_TO_DEVICE); complete(&host->dma_complete); -- cgit v1.2.2 From f38f94c6b226f7c6888bedbcadf0ed2ddca7d029 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:09:50 +0100 Subject: mmc: sh_mmcif: rename and retype activity variable The host_sglen is now actually used to keep track of whether DMA is active or not, so rename and retype it to bool. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 61ad19ecfbf8..e247031f91f7 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -169,7 +169,7 @@ struct sh_mmcif_host { struct dma_chan *chan_rx; struct dma_chan *chan_tx; struct completion dma_complete; - unsigned int dma_sglen; + bool dma_active; }; static inline void sh_mmcif_bitset(struct sh_mmcif_host *host, @@ -216,7 +216,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, DMA_FROM_DEVICE); if (ret > 0) { - host->dma_sglen = ret; + host->dma_active = true; desc = chan->device->device_prep_slave_sg(chan, sg, ret, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } @@ -241,7 +241,7 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) if (ret >= 0) ret = -EIO; host->chan_rx = NULL; - host->dma_sglen = 0; + host->dma_active = false; dma_release_channel(chan); /* Free the Tx channel too */ chan = host->chan_tx; @@ -269,7 +269,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) ret = dma_map_sg(chan->device->dev, sg, host->data->sg_len, DMA_TO_DEVICE); if (ret > 0) { - host->dma_sglen = ret; + host->dma_active = true; desc = chan->device->device_prep_slave_sg(chan, sg, ret, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); } @@ -294,7 +294,7 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) if (ret >= 0) ret = -EIO; host->chan_tx = NULL; - host->dma_sglen = 0; + host->dma_active = false; dma_release_channel(chan); /* Free the Rx channel too */ chan = host->chan_rx; @@ -321,7 +321,7 @@ static bool sh_mmcif_filter(struct dma_chan *chan, void *arg) static void sh_mmcif_request_dma(struct sh_mmcif_host *host, struct sh_mmcif_plat_data *pdata) { - host->dma_sglen = 0; + host->dma_active = false; /* We can only either use DMA for both Tx and Rx or not use it at all */ if (pdata->dma) { @@ -368,7 +368,7 @@ static void sh_mmcif_release_dma(struct sh_mmcif_host *host) dma_release_channel(chan); } - host->dma_sglen = 0; + host->dma_active = false; } static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) @@ -757,7 +757,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, } sh_mmcif_get_response(host, cmd); if (host->data) { - if (!host->dma_sglen) { + if (!host->dma_active) { ret = sh_mmcif_data_trans(host, mrq, cmd->opcode); } else { long time = @@ -769,7 +769,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, ret = time; sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); - host->dma_sglen = 0; + host->dma_active = false; } if (ret < 0) mrq->data->bytes_xfered = 0; -- cgit v1.2.2 From a5ece7d29d09714a690f83f6f0ce395f4374021e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:10:00 +0100 Subject: mmc: sh_mmcif: use dmaengine helpers, drop submit check Use the new dmaengine helper functions, and drop the error check on the returned cookier from the dmaengine - we recently established that this is really not allowed to fail. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index e247031f91f7..aea86262ed66 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -224,14 +224,9 @@ static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) if (desc) { desc->callback = mmcif_dma_complete; desc->callback_param = host; - cookie = desc->tx_submit(desc); - if (cookie < 0) { - desc = NULL; - ret = cookie; - } else { - sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN); - chan->device->device_issue_pending(chan); - } + cookie = dmaengine_submit(desc); + sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN); + dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", __func__, host->data->sg_len, ret, cookie); @@ -277,14 +272,9 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) if (desc) { desc->callback = mmcif_dma_complete; desc->callback_param = host; - cookie = desc->tx_submit(desc); - if (cookie < 0) { - desc = NULL; - ret = cookie; - } else { - sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN); - chan->device->device_issue_pending(chan); - } + cookie = dmaengine_submit(desc); + sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN); + dma_async_issue_pending(chan); } dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n", __func__, host->data->sg_len, ret, cookie); -- cgit v1.2.2 From 2dc7ddc1e7e68ee7793dda0ca0d659367d035e3d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:10:37 +0100 Subject: mmc: tmio_mmc: map DMA buffers on the DMA engine device As established for the MMCI, it is proper to map the DMA buffers on the DMA engine which is the one actually performing the DMA. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index a33f71841dec..0d36fa9c629e 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -829,7 +829,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) sg = host->sg_ptr; } - ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_FROM_DEVICE); + ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); if (ret > 0) { host->dma_sglen = ret; desc = chan->device->device_prep_slave_sg(chan, sg, ret, @@ -910,7 +910,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) sg = host->sg_ptr; } - ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, DMA_TO_DEVICE); + ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); if (ret > 0) { host->dma_sglen = ret; desc = chan->device->device_prep_slave_sg(chan, sg, ret, @@ -982,10 +982,12 @@ static void tmio_tasklet_fn(unsigned long arg) goto out; if (host->data->flags & MMC_DATA_READ) - dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen, + dma_unmap_sg(host->chan_rx->device->dev, + host->sg_ptr, host->dma_sglen, DMA_FROM_DEVICE); else - dma_unmap_sg(&host->pdev->dev, host->sg_ptr, host->dma_sglen, + dma_unmap_sg(host->chan_tx->device->dev, + host->sg_ptr, host->dma_sglen, DMA_TO_DEVICE); tmio_mmc_do_data_irq(host); -- cgit v1.2.2 From d7554caa2c3410c07a1889a08c66288edbdc216a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:10:47 +0100 Subject: mmc: tmio_mmc: unmap with the proper sglen According to the DMA-API you shall unmap the sglists with the same sglist length as passed into the mapping function, not the returned value from the mapping function. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 0d36fa9c629e..1b9fa21c2bdc 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -983,11 +983,11 @@ static void tmio_tasklet_fn(unsigned long arg) if (host->data->flags & MMC_DATA_READ) dma_unmap_sg(host->chan_rx->device->dev, - host->sg_ptr, host->dma_sglen, + host->sg_ptr, host->sg_len, DMA_FROM_DEVICE); else dma_unmap_sg(host->chan_tx->device->dev, - host->sg_ptr, host->dma_sglen, + host->sg_ptr, host->sg_len, DMA_TO_DEVICE); tmio_mmc_do_data_irq(host); -- cgit v1.2.2 From 3383433ce70613514593c940a2ae4e6ab19f2b28 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:10:56 +0100 Subject: mmc: tmio_mmc: drop dma_sglen state variable This variable doesn't seem to be used for anything after the other patches so just drop it. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 1b9fa21c2bdc..699b6ab209b2 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -152,7 +152,6 @@ struct tmio_mmc_host { struct tasklet_struct dma_complete; struct tasklet_struct dma_issue; #ifdef CONFIG_TMIO_MMC_DMA - unsigned int dma_sglen; u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN))); struct scatterlist bounce_sg; #endif @@ -830,11 +829,9 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) } ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); - if (ret > 0) { - host->dma_sglen = ret; + if (ret > 0) desc = chan->device->device_prep_slave_sg(chan, sg, ret, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - } if (desc) { desc->callback = tmio_dma_complete; @@ -911,11 +908,9 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) } ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); - if (ret > 0) { - host->dma_sglen = ret; + if (ret > 0) desc = chan->device->device_prep_slave_sg(chan, sg, ret, DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - } if (desc) { desc->callback = tmio_dma_complete; -- cgit v1.2.2 From 449bdc2d9d62794246351d10dd4534a239bf06b6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 10 Feb 2011 16:11:07 +0100 Subject: mmc: tmio_mmc: use dmaengine helpers, drop submit check Use the new dmaengine helper functions, and drop the error check on the returned cookier from the dmaengine - we recently established that this is really not allowed to fail. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 699b6ab209b2..0e4998fa6fc5 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -836,13 +836,8 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) if (desc) { desc->callback = tmio_dma_complete; desc->callback_param = host; - cookie = desc->tx_submit(desc); - if (cookie < 0) { - desc = NULL; - ret = cookie; - } else { - chan->device->device_issue_pending(chan); - } + cookie = dmaengine_submit(desc); + dma_async_issue_pending(chan); } dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", __func__, host->sg_len, ret, cookie, host->mrq); @@ -915,11 +910,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) if (desc) { desc->callback = tmio_dma_complete; desc->callback_param = host; - cookie = desc->tx_submit(desc); - if (cookie < 0) { - desc = NULL; - ret = cookie; - } + cookie = dmaengine_submit(desc); } dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", __func__, host->sg_len, ret, cookie, host->mrq); @@ -963,7 +954,7 @@ static void tmio_issue_tasklet_fn(unsigned long priv) struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; struct dma_chan *chan = host->chan_tx; - chan->device->device_issue_pending(chan); + dma_async_issue_pending(chan); } static void tmio_tasklet_fn(unsigned long arg) -- cgit v1.2.2 From c9b2a06fb0efda37241861915a8639c27bddaa85 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Feb 2011 16:12:38 +0900 Subject: mmc: dw_mmc: support 8-bit buswidth This patch adds support for 8-bit buswidth. dw_mmc can use 8-bit buswidth and set to CTYPE_8BIT in card-type register. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Acked-by: Will Newton Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index cd6d8212dacc..62c8440ff04b 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -673,6 +673,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_BUS_WIDTH_4: slot->ctype = SDMMC_CTYPE_4BIT; break; + case MMC_BUS_WIDTH_8: + slot->ctype = SDMMC_CTYPE_8BIT; + break; } if (ios->clock) { -- cgit v1.2.2 From f53fbde48ef0a5ce7733fbc84da18014d0a11cf0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 18 Feb 2011 10:21:09 +0100 Subject: mmc: mxcmmc: use dmaengine API This switches the mxcmmc driver to use the dmaengine API. Unlike the old one this one is always present in the tree, even if no DMA is implemented, hence we can remove all the #ifdefs in from the driver. The driver automatically switches to PIO mode if no DMA support or no suitable channel is available. Signed-off-by: Sascha Hauer Acked-by: Arnd Bergmann Signed-off-by: Chris Ball --- drivers/mmc/host/mxcmmc.c | 181 ++++++++++++++++++++++++++-------------------- 1 file changed, 104 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 4428594261c5..cc20e0259325 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -32,16 +32,14 @@ #include #include #include +#include #include #include #include #include -#ifdef CONFIG_ARCH_MX2 -#include -#define HAS_DMA -#endif +#include #define DRIVER_NAME "mxc-mmc" @@ -118,7 +116,8 @@ struct mxcmci_host { void __iomem *base; int irq; int detect_irq; - int dma; + struct dma_chan *dma; + struct dma_async_tx_descriptor *desc; int do_dma; int default_irq_mask; int use_sdio; @@ -129,7 +128,6 @@ struct mxcmci_host { struct mmc_command *cmd; struct mmc_data *data; - unsigned int dma_nents; unsigned int datasize; unsigned int dma_dir; @@ -144,6 +142,11 @@ struct mxcmci_host { spinlock_t lock; struct regulator *vcc; + + int burstlen; + int dmareq; + struct dma_slave_config dma_slave_config; + struct imx_dma_data dma_data; }; static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); @@ -206,17 +209,16 @@ static void mxcmci_softreset(struct mxcmci_host *host) writew(0xff, host->base + MMC_REG_RES_TO); } +static int mxcmci_setup_dma(struct mmc_host *mmc); static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) { unsigned int nob = data->blocks; unsigned int blksz = data->blksz; unsigned int datasize = nob * blksz; -#ifdef HAS_DMA struct scatterlist *sg; - int i; - int ret; -#endif + int i, nents; + if (data->flags & MMC_DATA_STREAM) nob = 0xffff; @@ -227,7 +229,9 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) writew(blksz, host->base + MMC_REG_BLK_LEN); host->datasize = datasize; -#ifdef HAS_DMA + if (!mxcmci_use_dma(host)) + return 0; + for_each_sg(data->sg, sg, data->sg_len, i) { if (sg->offset & 3 || sg->length & 3) { host->do_dma = 0; @@ -235,34 +239,30 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) } } - if (data->flags & MMC_DATA_READ) { + if (data->flags & MMC_DATA_READ) host->dma_dir = DMA_FROM_DEVICE; - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - - ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, - datasize, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_READ); - } else { + else host->dma_dir = DMA_TO_DEVICE; - host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, host->dma_dir); - ret = imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, - datasize, - host->res->start + MMC_REG_BUFFER_ACCESS, - DMA_MODE_WRITE); - } + nents = dma_map_sg(host->dma->device->dev, data->sg, + data->sg_len, host->dma_dir); + if (nents != data->sg_len) + return -EINVAL; + + host->desc = host->dma->device->device_prep_slave_sg(host->dma, + data->sg, data->sg_len, host->dma_dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (ret) { - dev_err(mmc_dev(host->mmc), "failed to setup DMA : %d\n", ret); - return ret; + if (!host->desc) { + dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, + host->dma_dir); + host->do_dma = 0; + return 0; /* Fall back to PIO */ } wmb(); - imx_dma_enable(host->dma); -#endif /* HAS_DMA */ + dmaengine_submit(host->desc); + return 0; } @@ -337,13 +337,11 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) struct mmc_data *data = host->data; int data_error; -#ifdef HAS_DMA if (mxcmci_use_dma(host)) { - imx_dma_disable(host->dma); - dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents, + dmaengine_terminate_all(host->dma); + dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len, host->dma_dir); } -#endif if (stat & STATUS_ERR_MASK) { dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", @@ -545,7 +543,6 @@ static void mxcmci_datawork(struct work_struct *work) } } -#ifdef HAS_DMA static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat) { struct mmc_data *data = host->data; @@ -568,7 +565,6 @@ static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat) mxcmci_finish_request(host, host->req); } } -#endif /* HAS_DMA */ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) { @@ -606,12 +602,10 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; spin_unlock_irqrestore(&host->lock, flags); -#ifdef HAS_DMA if (mxcmci_use_dma(host) && (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, host->base + MMC_REG_STATUS); -#endif if (sdio_irq) { writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); @@ -621,14 +615,14 @@ static irqreturn_t mxcmci_irq(int irq, void *devid) if (stat & STATUS_END_CMD_RESP) mxcmci_cmd_done(host, stat); -#ifdef HAS_DMA if (mxcmci_use_dma(host) && (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) mxcmci_data_done(host, stat); -#endif + if (host->default_irq_mask && (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL))) mmc_detect_change(host->mmc, msecs_to_jiffies(200)); + return IRQ_HANDLED; } @@ -642,9 +636,10 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) host->req = req; host->cmdat &= ~CMD_DAT_CONT_INIT; -#ifdef HAS_DMA - host->do_dma = 1; -#endif + + if (host->dma) + host->do_dma = 1; + if (req->data) { error = mxcmci_setup_data(host, req->data); if (error) { @@ -660,6 +655,7 @@ static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req) } error = mxcmci_start_cmd(host, req->cmd, cmdat); + out: if (error) mxcmci_finish_request(host, req); @@ -698,22 +694,46 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios) prescaler, divider, clk_in, clk_ios); } +static int mxcmci_setup_dma(struct mmc_host *mmc) +{ + struct mxcmci_host *host = mmc_priv(mmc); + struct dma_slave_config *config = &host->dma_slave_config; + + config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS; + config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS; + config->dst_addr_width = 4; + config->src_addr_width = 4; + config->dst_maxburst = host->burstlen; + config->src_maxburst = host->burstlen; + + return dmaengine_slave_config(host->dma, config); +} + static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mxcmci_host *host = mmc_priv(mmc); -#ifdef HAS_DMA - unsigned int blen; + int burstlen, ret; + /* * use burstlen of 64 in 4 bit mode (--> reg value 0) * use burstlen of 16 in 1 bit mode (--> reg value 16) */ if (ios->bus_width == MMC_BUS_WIDTH_4) - blen = 0; + burstlen = 64; else - blen = 16; + burstlen = 16; + + if (mxcmci_use_dma(host) && burstlen != host->burstlen) { + host->burstlen = burstlen; + ret = mxcmci_setup_dma(mmc); + if (ret) { + dev_err(mmc_dev(host->mmc), + "failed to config DMA channel. Falling back to PIO\n"); + dma_release_channel(host->dma); + host->do_dma = 0; + } + } - imx_dma_config_burstlen(host->dma, blen); -#endif if (ios->bus_width == MMC_BUS_WIDTH_4) host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4; else @@ -794,6 +814,18 @@ static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) host->caps |= MMC_CAP_4_BIT_DATA; } +static bool filter(struct dma_chan *chan, void *param) +{ + struct mxcmci_host *host = param; + + if (!imx_dma_is_general_purpose(chan)) + return false; + + chan->private = &host->dma_data; + + return true; +} + static const struct mmc_host_ops mxcmci_ops = { .request = mxcmci_request, .set_ios = mxcmci_set_ios, @@ -808,6 +840,7 @@ static int mxcmci_probe(struct platform_device *pdev) struct mxcmci_host *host = NULL; struct resource *iores, *r; int ret = 0, irq; + dma_cap_mask_t mask; printk(KERN_INFO "i.MX SDHC driver\n"); @@ -883,29 +916,23 @@ static int mxcmci_probe(struct platform_device *pdev) writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR); -#ifdef HAS_DMA - host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW); - if (host->dma < 0) { - dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n"); - ret = -EBUSY; - goto out_clk_put; - } - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!r) { - ret = -EINVAL; - goto out_free_dma; + if (r) { + host->dmareq = r->start; + host->dma_data.peripheral_type = IMX_DMATYPE_SDHC; + host->dma_data.priority = DMA_PRIO_LOW; + host->dma_data.dma_request = host->dmareq; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma = dma_request_channel(mask, filter, host); + if (host->dma) + mmc->max_seg_size = dma_get_max_seg_size( + host->dma->device->dev); } - ret = imx_dma_config_channel(host->dma, - IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO, - IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR, - r->start, 0); - if (ret) { - dev_err(mmc_dev(host->mmc), "failed to config DMA channel\n"); - goto out_free_dma; - } -#endif + if (!host->dma) + dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n"); + INIT_WORK(&host->datawork, mxcmci_datawork); ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host); @@ -928,9 +955,8 @@ static int mxcmci_probe(struct platform_device *pdev) out_free_irq: free_irq(host->irq, host); out_free_dma: -#ifdef HAS_DMA - imx_dma_free(host->dma); -#endif + if (host->dma) + dma_release_channel(host->dma); out_clk_put: clk_disable(host->clk); clk_put(host->clk); @@ -960,9 +986,10 @@ static int mxcmci_remove(struct platform_device *pdev) free_irq(host->irq, host); iounmap(host->base); -#ifdef HAS_DMA - imx_dma_free(host->dma); -#endif + + if (host->dma) + dma_release_channel(host->dma); + clk_disable(host->clk); clk_put(host->clk); -- cgit v1.2.2 From 8154b5756d3cb850f846ff38cf35cbbb7c2b45fe Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 10 Feb 2011 18:07:30 +0100 Subject: mmc: sdhci-tegra: free irq on error and remove Signed-off-by: Wolfram Sang Acked-by: Olof Johansson Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-tegra.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 4823ee94a63f..f7e1f964395f 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -169,7 +169,7 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host, if (rc) { dev_err(mmc_dev(host->mmc), "failed to allocate wp gpio\n"); - goto out_cd; + goto out_irq; } tegra_gpio_enable(plat->wp_gpio); gpio_direction_input(plat->wp_gpio); @@ -195,6 +195,9 @@ out_wp: gpio_free(plat->wp_gpio); } +out_irq: + if (gpio_is_valid(plat->cd_gpio)) + free_irq(gpio_to_irq(plat->cd_gpio), host); out_cd: if (gpio_is_valid(plat->cd_gpio)) { tegra_gpio_disable(plat->cd_gpio); @@ -225,6 +228,7 @@ static void tegra_sdhci_pltfm_exit(struct sdhci_host *host) } if (gpio_is_valid(plat->cd_gpio)) { + free_irq(gpio_to_irq(plat->cd_gpio), host); tegra_gpio_disable(plat->cd_gpio); gpio_free(plat->cd_gpio); } -- cgit v1.2.2 From e4243f13d10e5fbe2b84e211dcac3bc6e0792167 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 21 Feb 2011 18:35:28 +0800 Subject: mmc: mxs-mmc: add mmc host driver for i.MX23/28 This adds the mmc host driver for Freescale MXS-based SoC i.MX23/28. The driver calls into mxs-dma via generic dmaengine api for both pio and data transfer. Thanks Chris Ball for the indentation patch. Signed-off-by: Shawn Guo Reviewed-by: Arnd Bergmann Tested-by: Wolfram Sang Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 9 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/mxs-mmc.c | 874 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 884 insertions(+) create mode 100644 drivers/mmc/host/mxs-mmc.c (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 54b7bd54a52a..398d7d54c52a 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -319,6 +319,15 @@ config MMC_MXC If unsure, say N. +config MMC_MXS + tristate "Freescale MXS Multimedia Card Interface support" + depends on ARCH_MXS && MXS_DMA + help + This selects the Freescale SSP MMC controller found on MXS based + platforms like mx23/28. + + If unsure, say N. + config MMC_TIFM_SD tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)" depends on EXPERIMENTAL && PCI diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index e834fb223e9a..30aa6867745f 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o +obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_SDHCI_PXA) += sdhci-pxa.o diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c new file mode 100644 index 000000000000..99d39a6a1032 --- /dev/null +++ b/drivers/mmc/host/mxs-mmc.c @@ -0,0 +1,874 @@ +/* + * Portions copyright (C) 2003 Russell King, PXA MMCI Driver + * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver + * + * Copyright 2008 Embedded Alley Solutions, Inc. + * Copyright 2009-2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define DRIVER_NAME "mxs-mmc" + +/* card detect polling timeout */ +#define MXS_MMC_DETECT_TIMEOUT (HZ/2) + +#define SSP_VERSION_LATEST 4 +#define ssp_is_old() (host->version < SSP_VERSION_LATEST) + +/* SSP registers */ +#define HW_SSP_CTRL0 0x000 +#define BM_SSP_CTRL0_RUN (1 << 29) +#define BM_SSP_CTRL0_SDIO_IRQ_CHECK (1 << 28) +#define BM_SSP_CTRL0_IGNORE_CRC (1 << 26) +#define BM_SSP_CTRL0_READ (1 << 25) +#define BM_SSP_CTRL0_DATA_XFER (1 << 24) +#define BP_SSP_CTRL0_BUS_WIDTH (22) +#define BM_SSP_CTRL0_BUS_WIDTH (0x3 << 22) +#define BM_SSP_CTRL0_WAIT_FOR_IRQ (1 << 21) +#define BM_SSP_CTRL0_LONG_RESP (1 << 19) +#define BM_SSP_CTRL0_GET_RESP (1 << 17) +#define BM_SSP_CTRL0_ENABLE (1 << 16) +#define BP_SSP_CTRL0_XFER_COUNT (0) +#define BM_SSP_CTRL0_XFER_COUNT (0xffff) +#define HW_SSP_CMD0 0x010 +#define BM_SSP_CMD0_DBL_DATA_RATE_EN (1 << 25) +#define BM_SSP_CMD0_SLOW_CLKING_EN (1 << 22) +#define BM_SSP_CMD0_CONT_CLKING_EN (1 << 21) +#define BM_SSP_CMD0_APPEND_8CYC (1 << 20) +#define BP_SSP_CMD0_BLOCK_SIZE (16) +#define BM_SSP_CMD0_BLOCK_SIZE (0xf << 16) +#define BP_SSP_CMD0_BLOCK_COUNT (8) +#define BM_SSP_CMD0_BLOCK_COUNT (0xff << 8) +#define BP_SSP_CMD0_CMD (0) +#define BM_SSP_CMD0_CMD (0xff) +#define HW_SSP_CMD1 0x020 +#define HW_SSP_XFER_SIZE 0x030 +#define HW_SSP_BLOCK_SIZE 0x040 +#define BP_SSP_BLOCK_SIZE_BLOCK_COUNT (4) +#define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4) +#define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0) +#define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf) +#define HW_SSP_TIMING (ssp_is_old() ? 0x050 : 0x070) +#define BP_SSP_TIMING_TIMEOUT (16) +#define BM_SSP_TIMING_TIMEOUT (0xffff << 16) +#define BP_SSP_TIMING_CLOCK_DIVIDE (8) +#define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8) +#define BP_SSP_TIMING_CLOCK_RATE (0) +#define BM_SSP_TIMING_CLOCK_RATE (0xff) +#define HW_SSP_CTRL1 (ssp_is_old() ? 0x060 : 0x080) +#define BM_SSP_CTRL1_SDIO_IRQ (1 << 31) +#define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30) +#define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29) +#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN (1 << 28) +#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ (1 << 27) +#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN (1 << 26) +#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ (1 << 25) +#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN (1 << 24) +#define BM_SSP_CTRL1_DATA_CRC_IRQ (1 << 23) +#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN (1 << 22) +#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ (1 << 21) +#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN (1 << 20) +#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ (1 << 17) +#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN (1 << 16) +#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ (1 << 15) +#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN (1 << 14) +#define BM_SSP_CTRL1_DMA_ENABLE (1 << 13) +#define BM_SSP_CTRL1_POLARITY (1 << 9) +#define BP_SSP_CTRL1_WORD_LENGTH (4) +#define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4) +#define BP_SSP_CTRL1_SSP_MODE (0) +#define BM_SSP_CTRL1_SSP_MODE (0xf) +#define HW_SSP_SDRESP0 (ssp_is_old() ? 0x080 : 0x0a0) +#define HW_SSP_SDRESP1 (ssp_is_old() ? 0x090 : 0x0b0) +#define HW_SSP_SDRESP2 (ssp_is_old() ? 0x0a0 : 0x0c0) +#define HW_SSP_SDRESP3 (ssp_is_old() ? 0x0b0 : 0x0d0) +#define HW_SSP_STATUS (ssp_is_old() ? 0x0c0 : 0x100) +#define BM_SSP_STATUS_CARD_DETECT (1 << 28) +#define BM_SSP_STATUS_SDIO_IRQ (1 << 17) +#define HW_SSP_VERSION (cpu_is_mx23() ? 0x110 : 0x130) +#define BP_SSP_VERSION_MAJOR (24) + +#define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field) + +#define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \ + BM_SSP_CTRL1_RESP_ERR_IRQ | \ + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_DATA_CRC_IRQ | \ + BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \ + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \ + BM_SSP_CTRL1_FIFO_OVERRUN_IRQ) + +#define SSP_PIO_NUM 3 + +struct mxs_mmc_host { + struct mmc_host *mmc; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + + void __iomem *base; + int irq; + struct resource *res; + struct resource *dma_res; + struct clk *clk; + unsigned int clk_rate; + + struct dma_chan *dmach; + struct mxs_dma_data dma_data; + unsigned int dma_dir; + u32 ssp_pio_words[SSP_PIO_NUM]; + + unsigned int version; + unsigned char bus_width; + spinlock_t lock; + int sdio_irq_en; +}; + +static int mxs_mmc_get_ro(struct mmc_host *mmc) +{ + struct mxs_mmc_host *host = mmc_priv(mmc); + struct mxs_mmc_platform_data *pdata = + mmc_dev(host->mmc)->platform_data; + + if (!pdata) + return -EFAULT; + + if (!gpio_is_valid(pdata->wp_gpio)) + return -EINVAL; + + return gpio_get_value(pdata->wp_gpio); +} + +static int mxs_mmc_get_cd(struct mmc_host *mmc) +{ + struct mxs_mmc_host *host = mmc_priv(mmc); + + return !(readl(host->base + HW_SSP_STATUS) & + BM_SSP_STATUS_CARD_DETECT); +} + +static void mxs_mmc_reset(struct mxs_mmc_host *host) +{ + u32 ctrl0, ctrl1; + + mxs_reset_block(host->base); + + ctrl0 = BM_SSP_CTRL0_IGNORE_CRC; + ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) | + BF_SSP(0x7, CTRL1_WORD_LENGTH) | + BM_SSP_CTRL1_DMA_ENABLE | + BM_SSP_CTRL1_POLARITY | + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_DATA_CRC_IRQ_EN | + BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN | + BM_SSP_CTRL1_RESP_ERR_IRQ_EN; + + writel(BF_SSP(0xffff, TIMING_TIMEOUT) | + BF_SSP(2, TIMING_CLOCK_DIVIDE) | + BF_SSP(0, TIMING_CLOCK_RATE), + host->base + HW_SSP_TIMING); + + if (host->sdio_irq_en) { + ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; + ctrl1 |= BM_SSP_CTRL1_SDIO_IRQ_EN; + } + + writel(ctrl0, host->base + HW_SSP_CTRL0); + writel(ctrl1, host->base + HW_SSP_CTRL1); +} + +static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, + struct mmc_command *cmd); + +static void mxs_mmc_request_done(struct mxs_mmc_host *host) +{ + struct mmc_command *cmd = host->cmd; + struct mmc_data *data = host->data; + struct mmc_request *mrq = host->mrq; + + if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) { + if (mmc_resp_type(cmd) & MMC_RSP_136) { + cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0); + cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1); + cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2); + cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3); + } else { + cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0); + } + } + + if (data) { + dma_unmap_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma_dir); + /* + * If there was an error on any block, we mark all + * data blocks as being in error. + */ + if (!data->error) + data->bytes_xfered = data->blocks * data->blksz; + else + data->bytes_xfered = 0; + + host->data = NULL; + if (mrq->stop) { + mxs_mmc_start_cmd(host, mrq->stop); + return; + } + } + + host->mrq = NULL; + mmc_request_done(host->mmc, mrq); +} + +static void mxs_mmc_dma_irq_callback(void *param) +{ + struct mxs_mmc_host *host = param; + + mxs_mmc_request_done(host); +} + +static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id) +{ + struct mxs_mmc_host *host = dev_id; + struct mmc_command *cmd = host->cmd; + struct mmc_data *data = host->data; + u32 stat; + + spin_lock(&host->lock); + + stat = readl(host->base + HW_SSP_CTRL1); + writel(stat & MXS_MMC_IRQ_BITS, + host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); + + if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN)) + mmc_signal_sdio_irq(host->mmc); + + spin_unlock(&host->lock); + + if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ) + cmd->error = -ETIMEDOUT; + else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ) + cmd->error = -EIO; + + if (data) { + if (stat & (BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | + BM_SSP_CTRL1_RECV_TIMEOUT_IRQ)) + data->error = -ETIMEDOUT; + else if (stat & BM_SSP_CTRL1_DATA_CRC_IRQ) + data->error = -EILSEQ; + else if (stat & (BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | + BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)) + data->error = -EIO; + } + + return IRQ_HANDLED; +} + +static struct dma_async_tx_descriptor *mxs_mmc_prep_dma( + struct mxs_mmc_host *host, unsigned int append) +{ + struct dma_async_tx_descriptor *desc; + struct mmc_data *data = host->data; + struct scatterlist * sgl; + unsigned int sg_len; + + if (data) { + /* data */ + dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma_dir); + sgl = data->sg; + sg_len = data->sg_len; + } else { + /* pio */ + sgl = (struct scatterlist *) host->ssp_pio_words; + sg_len = SSP_PIO_NUM; + } + + desc = host->dmach->device->device_prep_slave_sg(host->dmach, + sgl, sg_len, host->dma_dir, append); + if (desc) { + desc->callback = mxs_mmc_dma_irq_callback; + desc->callback_param = host; + } else { + if (data) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma_dir); + } + + return desc; +} + +static void mxs_mmc_bc(struct mxs_mmc_host *host) +{ + struct mmc_command *cmd = host->cmd; + struct dma_async_tx_descriptor *desc; + u32 ctrl0, cmd0, cmd1; + + ctrl0 = BM_SSP_CTRL0_ENABLE | BM_SSP_CTRL0_IGNORE_CRC; + cmd0 = BF_SSP(cmd->opcode, CMD0_CMD) | BM_SSP_CMD0_APPEND_8CYC; + cmd1 = cmd->arg; + + if (host->sdio_irq_en) { + ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; + cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; + } + + host->ssp_pio_words[0] = ctrl0; + host->ssp_pio_words[1] = cmd0; + host->ssp_pio_words[2] = cmd1; + host->dma_dir = DMA_NONE; + desc = mxs_mmc_prep_dma(host, 0); + if (!desc) + goto out; + + dmaengine_submit(desc); + return; + +out: + dev_warn(mmc_dev(host->mmc), + "%s: failed to prep dma\n", __func__); +} + +static void mxs_mmc_ac(struct mxs_mmc_host *host) +{ + struct mmc_command *cmd = host->cmd; + struct dma_async_tx_descriptor *desc; + u32 ignore_crc, get_resp, long_resp; + u32 ctrl0, cmd0, cmd1; + + ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? + 0 : BM_SSP_CTRL0_IGNORE_CRC; + get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? + BM_SSP_CTRL0_GET_RESP : 0; + long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? + BM_SSP_CTRL0_LONG_RESP : 0; + + ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | get_resp | long_resp; + cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); + cmd1 = cmd->arg; + + if (host->sdio_irq_en) { + ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; + cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; + } + + host->ssp_pio_words[0] = ctrl0; + host->ssp_pio_words[1] = cmd0; + host->ssp_pio_words[2] = cmd1; + host->dma_dir = DMA_NONE; + desc = mxs_mmc_prep_dma(host, 0); + if (!desc) + goto out; + + dmaengine_submit(desc); + return; + +out: + dev_warn(mmc_dev(host->mmc), + "%s: failed to prep dma\n", __func__); +} + +static unsigned short mxs_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns) +{ + const unsigned int ssp_timeout_mul = 4096; + /* + * Calculate ticks in ms since ns are large numbers + * and might overflow + */ + const unsigned int clock_per_ms = clock_rate / 1000; + const unsigned int ms = ns / 1000; + const unsigned int ticks = ms * clock_per_ms; + const unsigned int ssp_ticks = ticks / ssp_timeout_mul; + + WARN_ON(ssp_ticks == 0); + return ssp_ticks; +} + +static void mxs_mmc_adtc(struct mxs_mmc_host *host) +{ + struct mmc_command *cmd = host->cmd; + struct mmc_data *data = cmd->data; + struct dma_async_tx_descriptor *desc; + struct scatterlist *sgl = data->sg, *sg; + unsigned int sg_len = data->sg_len; + int i; + + unsigned short dma_data_dir, timeout; + unsigned int data_size = 0, log2_blksz; + unsigned int blocks = data->blocks; + + u32 ignore_crc, get_resp, long_resp, read; + u32 ctrl0, cmd0, cmd1, val; + + ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ? + 0 : BM_SSP_CTRL0_IGNORE_CRC; + get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ? + BM_SSP_CTRL0_GET_RESP : 0; + long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ? + BM_SSP_CTRL0_LONG_RESP : 0; + + if (data->flags & MMC_DATA_WRITE) { + dma_data_dir = DMA_TO_DEVICE; + read = 0; + } else { + dma_data_dir = DMA_FROM_DEVICE; + read = BM_SSP_CTRL0_READ; + } + + ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) | + ignore_crc | get_resp | long_resp | + BM_SSP_CTRL0_DATA_XFER | read | + BM_SSP_CTRL0_WAIT_FOR_IRQ | + BM_SSP_CTRL0_ENABLE; + + cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); + + /* get logarithm to base 2 of block size for setting register */ + log2_blksz = ilog2(data->blksz); + + /* + * take special care of the case that data size from data->sg + * is not equal to blocks x blksz + */ + for_each_sg(sgl, sg, sg_len, i) + data_size += sg->length; + + if (data_size != data->blocks * data->blksz) + blocks = 1; + + /* xfer count, block size and count need to be set differently */ + if (ssp_is_old()) { + ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT); + cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) | + BF_SSP(blocks - 1, CMD0_BLOCK_COUNT); + } else { + writel(data_size, host->base + HW_SSP_XFER_SIZE); + writel(BF_SSP(log2_blksz, BLOCK_SIZE_BLOCK_SIZE) | + BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT), + host->base + HW_SSP_BLOCK_SIZE); + } + + if ((cmd->opcode == MMC_STOP_TRANSMISSION) || + (cmd->opcode == SD_IO_RW_EXTENDED)) + cmd0 |= BM_SSP_CMD0_APPEND_8CYC; + + cmd1 = cmd->arg; + + if (host->sdio_irq_en) { + ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; + cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; + } + + /* set the timeout count */ + timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns); + val = readl(host->base + HW_SSP_TIMING); + val &= ~(BM_SSP_TIMING_TIMEOUT); + val |= BF_SSP(timeout, TIMING_TIMEOUT); + writel(val, host->base + HW_SSP_TIMING); + + /* pio */ + host->ssp_pio_words[0] = ctrl0; + host->ssp_pio_words[1] = cmd0; + host->ssp_pio_words[2] = cmd1; + host->dma_dir = DMA_NONE; + desc = mxs_mmc_prep_dma(host, 0); + if (!desc) + goto out; + + /* append data sg */ + WARN_ON(host->data != NULL); + host->data = data; + host->dma_dir = dma_data_dir; + desc = mxs_mmc_prep_dma(host, 1); + if (!desc) + goto out; + + dmaengine_submit(desc); + return; +out: + dev_warn(mmc_dev(host->mmc), + "%s: failed to prep dma\n", __func__); +} + +static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, + struct mmc_command *cmd) +{ + host->cmd = cmd; + + switch (mmc_cmd_type(cmd)) { + case MMC_CMD_BC: + mxs_mmc_bc(host); + break; + case MMC_CMD_BCR: + mxs_mmc_ac(host); + break; + case MMC_CMD_AC: + mxs_mmc_ac(host); + break; + case MMC_CMD_ADTC: + mxs_mmc_adtc(host); + break; + default: + dev_warn(mmc_dev(host->mmc), + "%s: unknown MMC command\n", __func__); + break; + } +} + +static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct mxs_mmc_host *host = mmc_priv(mmc); + + WARN_ON(host->mrq != NULL); + host->mrq = mrq; + mxs_mmc_start_cmd(host, mrq->cmd); +} + +static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate) +{ + unsigned int ssp_rate, bit_rate; + u32 div1, div2; + u32 val; + + ssp_rate = clk_get_rate(host->clk); + + for (div1 = 2; div1 < 254; div1 += 2) { + div2 = ssp_rate / rate / div1; + if (div2 < 0x100) + break; + } + + if (div1 >= 254) { + dev_err(mmc_dev(host->mmc), + "%s: cannot set clock to %d\n", __func__, rate); + return; + } + + if (div2 == 0) + bit_rate = ssp_rate / div1; + else + bit_rate = ssp_rate / div1 / div2; + + val = readl(host->base + HW_SSP_TIMING); + val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); + val |= BF_SSP(div1, TIMING_CLOCK_DIVIDE); + val |= BF_SSP(div2 - 1, TIMING_CLOCK_RATE); + writel(val, host->base + HW_SSP_TIMING); + + host->clk_rate = bit_rate; + + dev_dbg(mmc_dev(host->mmc), + "%s: div1 %d, div2 %d, ssp %d, bit %d, rate %d\n", + __func__, div1, div2, ssp_rate, bit_rate, rate); +} + +static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct mxs_mmc_host *host = mmc_priv(mmc); + + if (ios->bus_width == MMC_BUS_WIDTH_8) + host->bus_width = 2; + else if (ios->bus_width == MMC_BUS_WIDTH_4) + host->bus_width = 1; + else + host->bus_width = 0; + + if (ios->clock) + mxs_mmc_set_clk_rate(host, ios->clock); +} + +static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct mxs_mmc_host *host = mmc_priv(mmc); + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + host->sdio_irq_en = enable; + + if (enable) { + writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, + host->base + HW_SSP_CTRL0 + MXS_SET_ADDR); + writel(BM_SSP_CTRL1_SDIO_IRQ_EN, + host->base + HW_SSP_CTRL1 + MXS_SET_ADDR); + + if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ) + mmc_signal_sdio_irq(host->mmc); + + } else { + writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK, + host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR); + writel(BM_SSP_CTRL1_SDIO_IRQ_EN, + host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR); + } + + spin_unlock_irqrestore(&host->lock, flags); +} + +static const struct mmc_host_ops mxs_mmc_ops = { + .request = mxs_mmc_request, + .get_ro = mxs_mmc_get_ro, + .get_cd = mxs_mmc_get_cd, + .set_ios = mxs_mmc_set_ios, + .enable_sdio_irq = mxs_mmc_enable_sdio_irq, +}; + +static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param) +{ + struct mxs_mmc_host *host = param; + + if (!mxs_dma_is_apbh(chan)) + return false; + + if (chan->chan_id != host->dma_res->start) + return false; + + chan->private = &host->dma_data; + + return true; +} + +static int mxs_mmc_probe(struct platform_device *pdev) +{ + struct mxs_mmc_host *host; + struct mmc_host *mmc; + struct resource *iores, *dmares, *r; + struct mxs_mmc_platform_data *pdata; + int ret = 0, irq_err, irq_dma; + dma_cap_mask_t mask; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); + irq_err = platform_get_irq(pdev, 0); + irq_dma = platform_get_irq(pdev, 1); + if (!iores || !dmares || irq_err < 0 || irq_dma < 0) + return -EINVAL; + + r = request_mem_region(iores->start, resource_size(iores), pdev->name); + if (!r) + return -EBUSY; + + mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); + if (!mmc) { + ret = -ENOMEM; + goto out_release_mem; + } + + host = mmc_priv(mmc); + host->base = ioremap(r->start, resource_size(r)); + if (!host->base) { + ret = -ENOMEM; + goto out_mmc_free; + } + + /* only major verion does matter */ + host->version = readl(host->base + HW_SSP_VERSION) >> + BP_SSP_VERSION_MAJOR; + + host->mmc = mmc; + host->res = r; + host->dma_res = dmares; + host->irq = irq_err; + host->sdio_irq_en = 0; + + host->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + goto out_iounmap; + } + clk_enable(host->clk); + + mxs_mmc_reset(host); + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma_data.chan_irq = irq_dma; + host->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host); + if (!host->dmach) { + dev_err(mmc_dev(host->mmc), + "%s: failed to request dma\n", __func__); + goto out_clk_put; + } + + /* set mmc core parameters */ + mmc->ops = &mxs_mmc_ops; + mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; + + pdata = mmc_dev(host->mmc)->platform_data; + if (pdata) { + if (pdata->flags & SLOTF_8_BIT_CAPABLE) + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + if (pdata->flags & SLOTF_4_BIT_CAPABLE) + mmc->caps |= MMC_CAP_4_BIT_DATA; + } + + mmc->f_min = 400000; + mmc->f_max = 288000000; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + mmc->max_segs = 52; + mmc->max_blk_size = 1 << 0xf; + mmc->max_blk_count = (ssp_is_old()) ? 0xff : 0xffffff; + mmc->max_req_size = (ssp_is_old()) ? 0xffff : 0xffffffff; + mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev); + + platform_set_drvdata(pdev, mmc); + + ret = request_irq(host->irq, mxs_mmc_irq_handler, 0, DRIVER_NAME, host); + if (ret) + goto out_free_dma; + + spin_lock_init(&host->lock); + + ret = mmc_add_host(mmc); + if (ret) + goto out_free_irq; + + dev_info(mmc_dev(host->mmc), "initialized\n"); + + return 0; + +out_free_irq: + free_irq(host->irq, host); +out_free_dma: + if (host->dmach) + dma_release_channel(host->dmach); +out_clk_put: + clk_disable(host->clk); + clk_put(host->clk); +out_iounmap: + iounmap(host->base); +out_mmc_free: + mmc_free_host(mmc); +out_release_mem: + release_mem_region(iores->start, resource_size(iores)); + return ret; +} + +static int mxs_mmc_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct mxs_mmc_host *host = mmc_priv(mmc); + struct resource *res = host->res; + + mmc_remove_host(mmc); + + free_irq(host->irq, host); + + platform_set_drvdata(pdev, NULL); + + if (host->dmach) + dma_release_channel(host->dmach); + + clk_disable(host->clk); + clk_put(host->clk); + + iounmap(host->base); + + mmc_free_host(mmc); + + release_mem_region(res->start, resource_size(res)); + + return 0; +} + +#ifdef CONFIG_PM +static int mxs_mmc_suspend(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + struct mxs_mmc_host *host = mmc_priv(mmc); + int ret = 0; + + ret = mmc_suspend_host(mmc); + + clk_disable(host->clk); + + return ret; +} + +static int mxs_mmc_resume(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + struct mxs_mmc_host *host = mmc_priv(mmc); + int ret = 0; + + clk_enable(host->clk); + + ret = mmc_resume_host(mmc); + + return ret; +} + +static const struct dev_pm_ops mxs_mmc_pm_ops = { + .suspend = mxs_mmc_suspend, + .resume = mxs_mmc_resume, +}; +#endif + +static struct platform_driver mxs_mmc_driver = { + .probe = mxs_mmc_probe, + .remove = mxs_mmc_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &mxs_mmc_pm_ops, +#endif + }, +}; + +static int __init mxs_mmc_init(void) +{ + return platform_driver_register(&mxs_mmc_driver); +} + +static void __exit mxs_mmc_exit(void) +{ + platform_driver_unregister(&mxs_mmc_driver); +} + +module_init(mxs_mmc_init); +module_exit(mxs_mmc_exit); + +MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral"); +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 24c300199b2f9125169c09ca3e950b17c16e2eab Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Wed, 23 Feb 2011 17:29:11 -0500 Subject: mmc: sdhci-pci: Remove set-but-unused variable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/mmc/host/sdhci-pci.c: In function ‘sdhci_pci_probe_slot’: drivers/mmc/host/sdhci-pci.c:913:18: warning: variable ‘addr’ set but not used [-Wunused-but-set-variable] Signed-off-by: Chris Ball Acked-by: Wolfram Sang --- drivers/mmc/host/sdhci-pci.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index f7e622c539ba..2f8d46854acd 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -908,9 +908,6 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( { struct sdhci_pci_slot *slot; struct sdhci_host *host; - - resource_size_t addr; - int ret; if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { @@ -957,7 +954,6 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( goto free; } - addr = pci_resource_start(pdev, bar); host->ioaddr = pci_ioremap_bar(pdev, bar); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); -- cgit v1.2.2 From b3bd1b5b0054f716e58a65d4e2e449ea0252e9dd Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Wed, 23 Feb 2011 23:17:43 +0000 Subject: mmc: cb710: Return err value in cb710_wait_while_busy() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: drivers/mmc/host/cb710-mmc.c: In function ‘cb710_wait_while_busy’: drivers/mmc/host/cb710-mmc.c:182:6: warning: variable ‘err’ set but not used [-Wunused-but-set-variable] Signed-off-by: Chris Ball Acked-by: MichaÅ‚ MirosÅ‚aw Acked-by: Wolfram Sang --- drivers/mmc/host/cb710-mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index 66b4ce587f4b..ce2a47b71dd6 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -205,7 +205,7 @@ static int cb710_wait_while_busy(struct cb710_slot *slot, uint8_t mask) "WAIT12: waited %d loops, mask %02X, entry val %08X, exit val %08X\n", limit, mask, e, x); #endif - return 0; + return err; } static void cb710_mmc_set_transfer_size(struct cb710_slot *slot, -- cgit v1.2.2 From e7054ba1f73c0a0e2489251499bdbc21b88b4190 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Wed, 23 Feb 2011 17:29:13 -0500 Subject: mmc: via-sdmmc: Remove set-but-unused variable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/mmc/host/via-sdmmc.c: In function ‘via_reset_pcictrl’: drivers/mmc/host/via-sdmmc.c:805:8: warning: variable ‘addrbase’ set but not used [-Wunused-but-set-variable] Signed-off-by: Chris Ball Cc: Harald Welte Acked-by: Wolfram Sang --- drivers/mmc/host/via-sdmmc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 9ed84ddb4780..8c5b4881ccd6 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -802,12 +802,9 @@ static const struct mmc_host_ops via_sdc_ops = { static void via_reset_pcictrl(struct via_crdr_mmc_host *host) { - void __iomem *addrbase; unsigned long flags; u8 gatt; - addrbase = host->pcictrl_mmiobase; - spin_lock_irqsave(&host->lock, flags); via_save_pcictrlreg(host); -- cgit v1.2.2 From 41babf753cc82ab6208903625a084bf305c32d06 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 24 Feb 2011 13:46:11 +0900 Subject: mmc: dw_mmc: support DDR mode This patch adds DDR mode support to dw_mmc. If we set any bit in UHS_REG bit[16:31], the card of that slot is supported for DDR mode. For example, if UHS_REG[16] is set, card number 0 is DDR mode. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Acked-by: Will Newton Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 8 ++++++++ drivers/mmc/host/dw_mmc.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 62c8440ff04b..58476c1bb056 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -662,6 +662,7 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct dw_mci_slot *slot = mmc_priv(mmc); + u32 regs; /* set default 1 bit mode */ slot->ctype = SDMMC_CTYPE_1BIT; @@ -678,6 +679,13 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; } + /* DDR mode set */ + if (ios->ddr) { + regs = mci_readl(slot->host, UHS_REG); + regs |= (0x1 << slot->id) << 16; + mci_writel(slot->host, UHS_REG, regs); + } + if (ios->clock) { /* * Use mirror of ios->clock to prevent race with mmc diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 5dd55a75233d..23c662af5616 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -43,6 +43,7 @@ #define SDMMC_USRID 0x068 #define SDMMC_VERID 0x06c #define SDMMC_HCON 0x070 +#define SDMMC_UHS_REG 0x074 #define SDMMC_BMOD 0x080 #define SDMMC_PLDMND 0x084 #define SDMMC_DBADDR 0x088 @@ -51,7 +52,6 @@ #define SDMMC_DSCADDR 0x094 #define SDMMC_BUFADDR 0x098 #define SDMMC_DATA 0x100 -#define SDMMC_DATA_ADR 0x100 /* shift bit field */ #define _SBF(f, v) ((v) << (f)) -- cgit v1.2.2 From 8c4037b501acd2ec3abc7925e66af8af40a2da9d Mon Sep 17 00:00:00 2001 From: David Dillow Date: Fri, 14 Jan 2011 17:02:23 -0500 Subject: IB/srp: always avoid non-zero offsets into an FMR It is unclear exactly how this code works around Mellanox SRP targets, or if the problem is on the target side or in the HCA itself. In an abundance of caution, we should always enable the workaround. Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 83664ed2804f..197e26cc2b0b 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -72,12 +72,6 @@ module_param(topspin_workarounds, int, 0444); MODULE_PARM_DESC(topspin_workarounds, "Enable workarounds for Topspin/Cisco SRP target bugs if != 0"); -static int mellanox_workarounds = 1; - -module_param(mellanox_workarounds, int, 0444); -MODULE_PARM_DESC(mellanox_workarounds, - "Enable workarounds for Mellanox SRP target bugs if != 0"); - static void srp_add_one(struct ib_device *device); static void srp_remove_one(struct ib_device *device); static void srp_recv_completion(struct ib_cq *cq, void *target_ptr); @@ -114,14 +108,6 @@ static int srp_target_is_topspin(struct srp_target_port *target) !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui)); } -static int srp_target_is_mellanox(struct srp_target_port *target) -{ - static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 }; - - return mellanox_workarounds && - !memcmp(&target->ioc_guid, mellanox_oui, sizeof mellanox_oui); -} - static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size, gfp_t gfp_mask, enum dma_data_direction direction) @@ -662,8 +648,7 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat, if (!dev->fmr_pool) return -ENODEV; - if (srp_target_is_mellanox(target) && - (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask)) + if (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask) return -EINVAL; len = page_cnt = 0; -- cgit v1.2.2 From 961e0be89a5120a1409ebc525cca6f603615a8a8 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Fri, 14 Jan 2011 17:32:07 -0500 Subject: IB/srp: move IB CM setup completion into its own function This is to clean up prior to further changes. Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 144 ++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 197e26cc2b0b..060e6a84f18f 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1213,6 +1213,78 @@ err: return -ENOMEM; } +static void srp_cm_rep_handler(struct ib_cm_id *cm_id, + struct srp_login_rsp *lrsp, + struct srp_target_port *target) +{ + struct ib_qp_attr *qp_attr = NULL; + int attr_mask = 0; + int ret; + int i; + + if (lrsp->opcode == SRP_LOGIN_RSP) { + target->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len); + target->req_lim = be32_to_cpu(lrsp->req_lim_delta); + + /* + * Reserve credits for task management so we don't + * bounce requests back to the SCSI mid-layer. + */ + target->scsi_host->can_queue + = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE, + target->scsi_host->can_queue); + } else { + shost_printk(KERN_WARNING, target->scsi_host, + PFX "Unhandled RSP opcode %#x\n", lrsp->opcode); + ret = -ECONNRESET; + goto error; + } + + if (!target->rx_ring[0]) { + ret = srp_alloc_iu_bufs(target); + if (ret) + goto error; + } + + ret = -ENOMEM; + qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); + if (!qp_attr) + goto error; + + qp_attr->qp_state = IB_QPS_RTR; + ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); + if (ret) + goto error_free; + + ret = ib_modify_qp(target->qp, qp_attr, attr_mask); + if (ret) + goto error_free; + + for (i = 0; i < SRP_RQ_SIZE; i++) { + struct srp_iu *iu = target->rx_ring[i]; + ret = srp_post_recv(target, iu); + if (ret) + goto error_free; + } + + qp_attr->qp_state = IB_QPS_RTS; + ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); + if (ret) + goto error_free; + + ret = ib_modify_qp(target->qp, qp_attr, attr_mask); + if (ret) + goto error_free; + + ret = ib_send_cm_rtu(cm_id, NULL, 0); + +error_free: + kfree(qp_attr); + +error: + target->status = ret; +} + static void srp_cm_rej_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event, struct srp_target_port *target) @@ -1296,11 +1368,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id, static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) { struct srp_target_port *target = cm_id->context; - struct ib_qp_attr *qp_attr = NULL; - int attr_mask = 0; int comp = 0; - int opcode = 0; - int i; switch (event->event) { case IB_CM_REQ_ERROR: @@ -1312,71 +1380,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) case IB_CM_REP_RECEIVED: comp = 1; - opcode = *(u8 *) event->private_data; - - if (opcode == SRP_LOGIN_RSP) { - struct srp_login_rsp *rsp = event->private_data; - - target->max_ti_iu_len = be32_to_cpu(rsp->max_ti_iu_len); - target->req_lim = be32_to_cpu(rsp->req_lim_delta); - - /* - * Reserve credits for task management so we don't - * bounce requests back to the SCSI mid-layer. - */ - target->scsi_host->can_queue - = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE, - target->scsi_host->can_queue); - } else { - shost_printk(KERN_WARNING, target->scsi_host, - PFX "Unhandled RSP opcode %#x\n", opcode); - target->status = -ECONNRESET; - break; - } - - if (!target->rx_ring[0]) { - target->status = srp_alloc_iu_bufs(target); - if (target->status) - break; - } - - qp_attr = kmalloc(sizeof *qp_attr, GFP_KERNEL); - if (!qp_attr) { - target->status = -ENOMEM; - break; - } - - qp_attr->qp_state = IB_QPS_RTR; - target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); - if (target->status) - break; - - target->status = ib_modify_qp(target->qp, qp_attr, attr_mask); - if (target->status) - break; - - for (i = 0; i < SRP_RQ_SIZE; i++) { - struct srp_iu *iu = target->rx_ring[i]; - target->status = srp_post_recv(target, iu); - if (target->status) - break; - } - if (target->status) - break; - - qp_attr->qp_state = IB_QPS_RTS; - target->status = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask); - if (target->status) - break; - - target->status = ib_modify_qp(target->qp, qp_attr, attr_mask); - if (target->status) - break; - - target->status = ib_send_cm_rtu(cm_id, NULL, 0); - if (target->status) - break; - + srp_cm_rep_handler(cm_id, event->private_data, target); break; case IB_CM_REJ_RECEIVED: @@ -1416,8 +1420,6 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) if (comp) complete(&target->done); - kfree(qp_attr); - return 0; } -- cgit v1.2.2 From 4924864404d0ce2c32a6d20b27b5b6fcb31e481d Mon Sep 17 00:00:00 2001 From: David Dillow Date: Fri, 14 Jan 2011 18:23:24 -0500 Subject: IB/srp: allow sg_tablesize to be set for each target Different configurations of target software allow differing max sizes of the command IU. Allowing this to be changed per-target allows all targets on an initiator to get an optimal setting. We deprecate srp_sg_tablesize and replace it with cmd_sg_entries in preparation for allowing more indirect descriptors than can fit in the IU. Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 81 ++++++++++++++++++++++++++----------- drivers/infiniband/ulp/srp/ib_srp.h | 2 + 2 files changed, 59 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 060e6a84f18f..6f8ee0c7ef5f 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -59,14 +59,16 @@ MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator " "v" DRV_VERSION " (" DRV_RELDATE ")"); MODULE_LICENSE("Dual BSD/GPL"); -static int srp_sg_tablesize = SRP_DEF_SG_TABLESIZE; -static int srp_max_iu_len; +static unsigned int srp_sg_tablesize; +static unsigned int cmd_sg_entries; +static int topspin_workarounds = 1; -module_param(srp_sg_tablesize, int, 0444); -MODULE_PARM_DESC(srp_sg_tablesize, - "Max number of gather/scatter entries per I/O (default is 12, max 255)"); +module_param(srp_sg_tablesize, uint, 0444); +MODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries"); -static int topspin_workarounds = 1; +module_param(cmd_sg_entries, uint, 0444); +MODULE_PARM_DESC(cmd_sg_entries, + "Default number of gather/scatter entries in the SRP command (default is 12, max 255)"); module_param(topspin_workarounds, int, 0444); MODULE_PARM_DESC(topspin_workarounds, @@ -364,7 +366,7 @@ static int srp_send_req(struct srp_target_port *target) req->priv.opcode = SRP_LOGIN_REQ; req->priv.tag = 0; - req->priv.req_it_iu_len = cpu_to_be32(srp_max_iu_len); + req->priv.req_it_iu_len = cpu_to_be32(target->max_iu_len); req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT); /* @@ -1125,7 +1127,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) spin_unlock_irqrestore(&target->lock, flags); dev = target->srp_host->srp_dev->dev; - ib_dma_sync_single_for_cpu(dev, iu->dma, srp_max_iu_len, + ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_iu_len, DMA_TO_DEVICE); scmnd->result = 0; @@ -1149,7 +1151,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) goto err_iu; } - ib_dma_sync_single_for_device(dev, iu->dma, srp_max_iu_len, + ib_dma_sync_single_for_device(dev, iu->dma, target->max_iu_len, DMA_TO_DEVICE); if (srp_post_send(target, iu, len)) { @@ -1189,7 +1191,7 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target) for (i = 0; i < SRP_SQ_SIZE; ++i) { target->tx_ring[i] = srp_alloc_iu(target->srp_host, - srp_max_iu_len, + target->max_iu_len, GFP_KERNEL, DMA_TO_DEVICE); if (!target->tx_ring[i]) goto err; @@ -1645,6 +1647,14 @@ static ssize_t show_local_ib_device(struct device *dev, return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name); } +static ssize_t show_cmd_sg_entries(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct srp_target_port *target = host_to_target(class_to_shost(dev)); + + return sprintf(buf, "%u\n", target->cmd_sg_cnt); +} + static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); @@ -1655,6 +1665,7 @@ static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL); static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); +static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL); static struct device_attribute *srp_host_attrs[] = { &dev_attr_id_ext, @@ -1667,6 +1678,7 @@ static struct device_attribute *srp_host_attrs[] = { &dev_attr_zero_req_lim, &dev_attr_local_ib_port, &dev_attr_local_ib_device, + &dev_attr_cmd_sg_entries, NULL }; @@ -1679,6 +1691,7 @@ static struct scsi_host_template srp_template = { .eh_abort_handler = srp_abort, .eh_device_reset_handler = srp_reset_device, .eh_host_reset_handler = srp_reset_host, + .sg_tablesize = SRP_DEF_SG_TABLESIZE, .can_queue = SRP_CMD_SQ_SIZE, .this_id = -1, .cmd_per_lun = SRP_CMD_SQ_SIZE, @@ -1750,6 +1763,7 @@ enum { SRP_OPT_MAX_CMD_PER_LUN = 1 << 6, SRP_OPT_IO_CLASS = 1 << 7, SRP_OPT_INITIATOR_EXT = 1 << 8, + SRP_OPT_CMD_SG_ENTRIES = 1 << 9, SRP_OPT_ALL = (SRP_OPT_ID_EXT | SRP_OPT_IOC_GUID | SRP_OPT_DGID | @@ -1767,6 +1781,7 @@ static const match_table_t srp_opt_tokens = { { SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" }, { SRP_OPT_IO_CLASS, "io_class=%x" }, { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, + { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" }, { SRP_OPT_ERR, NULL } }; @@ -1894,6 +1909,14 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) kfree(p); break; + case SRP_OPT_CMD_SG_ENTRIES: + if (match_int(args, &token) || token < 1 || token > 255) { + printk(KERN_WARNING PFX "bad max cmd_sg_entries parameter '%s'\n", p); + goto out; + } + target->cmd_sg_cnt = token; + break; + default: printk(KERN_WARNING PFX "unknown parameter or missing value " "'%s' in target creation request\n", p); @@ -1932,17 +1955,18 @@ static ssize_t srp_create_target(struct device *dev, if (!target_host) return -ENOMEM; - target_host->transportt = ib_srp_transport_template; + target_host->transportt = ib_srp_transport_template; target_host->max_lun = SRP_MAX_LUN; target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb; target = host_to_target(target_host); - target->io_class = SRP_REV16A_IB_IO_CLASS; - target->scsi_host = target_host; - target->srp_host = host; - target->lkey = host->srp_dev->mr->lkey; - target->rkey = host->srp_dev->mr->rkey; + target->io_class = SRP_REV16A_IB_IO_CLASS; + target->scsi_host = target_host; + target->srp_host = host; + target->lkey = host->srp_dev->mr->lkey; + target->rkey = host->srp_dev->mr->rkey; + target->cmd_sg_cnt = cmd_sg_entries; spin_lock_init(&target->lock); INIT_LIST_HEAD(&target->free_tx); @@ -1956,6 +1980,11 @@ static ssize_t srp_create_target(struct device *dev, if (ret) goto err; + target_host->sg_tablesize = target->cmd_sg_cnt; + target->max_iu_len = sizeof (struct srp_cmd) + + sizeof (struct srp_indirect_buf) + + target->cmd_sg_cnt * sizeof (struct srp_direct_buf); + ib_query_gid(host->srp_dev->dev, host->port, 0, &target->path.sgid); shost_printk(KERN_DEBUG, target->scsi_host, PFX @@ -2217,9 +2246,18 @@ static int __init srp_init_module(void) BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *)); - if (srp_sg_tablesize > 255) { - printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n"); - srp_sg_tablesize = 255; + if (srp_sg_tablesize) { + printk(KERN_WARNING PFX "srp_sg_tablesize is deprecated, please use cmd_sg_entries\n"); + if (!cmd_sg_entries) + cmd_sg_entries = srp_sg_tablesize; + } + + if (!cmd_sg_entries) + cmd_sg_entries = SRP_DEF_SG_TABLESIZE; + + if (cmd_sg_entries > 255) { + printk(KERN_WARNING PFX "Clamping cmd_sg_entries to 255\n"); + cmd_sg_entries = 255; } ib_srp_transport_template = @@ -2227,11 +2265,6 @@ static int __init srp_init_module(void) if (!ib_srp_transport_template) return -ENOMEM; - srp_template.sg_tablesize = srp_sg_tablesize; - srp_max_iu_len = (sizeof (struct srp_cmd) + - sizeof (struct srp_indirect_buf) + - srp_sg_tablesize * 16); - ret = class_register(&srp_class); if (ret) { printk(KERN_ERR PFX "couldn't register class infiniband_srp\n"); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 9dc6fc3fd894..db39dbf76216 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -130,6 +130,8 @@ struct srp_target_port { u32 lkey; u32 rkey; enum srp_target_state state; + unsigned int max_iu_len; + unsigned int cmd_sg_cnt; /* Everything above this point is used in the hot path of * command processing. Try to keep them packed into cachelines. -- cgit v1.2.2 From 8f26c9ff9cd0317ad867bce972f69e0c6c2cbe3c Mon Sep 17 00:00:00 2001 From: David Dillow Date: Fri, 14 Jan 2011 19:45:50 -0500 Subject: IB/srp: rework mapping engine to use multiple FMR entries Instead of forcing all of the S/G entries to fit in one FMR, and falling back to indirect descriptors if that fails, allow the use of as many FMRs as needed to map the request. This lays the groundwork for allowing indirect descriptor tables that are larger than can fit in the command IU, but should marginally improve performance now by reducing the number of indirect descriptors needed. We increase the minimum page size for the FMR pool to 4K, as larger pages help increase the coverage of each FMR, and it is rare that the kernel would send down a request with scattered 512 byte fragments. This patch also move some of the target initialization code afte the parsing of options, to keep it together with the new code that needs to allocate memory based on the options given. Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 367 ++++++++++++++++++++++++------------ drivers/infiniband/ulp/srp/ib_srp.h | 28 ++- 2 files changed, 266 insertions(+), 129 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 6f8ee0c7ef5f..9ce129ab3beb 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -444,6 +444,17 @@ static bool srp_change_state(struct srp_target_port *target, return changed; } +static void srp_free_req_data(struct srp_target_port *target) +{ + struct srp_request *req; + int i; + + for (i = 0, req = target->req_ring; i < SRP_CMD_SQ_SIZE; ++i, ++req) { + kfree(req->fmr_list); + kfree(req->map_page); + } +} + static void srp_remove_work(struct work_struct *work) { struct srp_target_port *target = @@ -460,6 +471,7 @@ static void srp_remove_work(struct work_struct *work) scsi_remove_host(target->scsi_host); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); + srp_free_req_data(target); scsi_host_put(target->scsi_host); } @@ -523,18 +535,20 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, struct srp_request *req) { + struct ib_device *ibdev = target->srp_host->srp_dev->dev; + struct ib_pool_fmr **pfmr; + if (!scsi_sglist(scmnd) || (scmnd->sc_data_direction != DMA_TO_DEVICE && scmnd->sc_data_direction != DMA_FROM_DEVICE)) return; - if (req->fmr) { - ib_fmr_pool_unmap(req->fmr); - req->fmr = NULL; - } + pfmr = req->fmr_list; + while (req->nfmr--) + ib_fmr_pool_unmap(*pfmr++); - ib_dma_unmap_sg(target->srp_host->srp_dev->dev, scsi_sglist(scmnd), - scsi_sg_count(scmnd), scmnd->sc_data_direction); + ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd), + scmnd->sc_data_direction); } static void srp_remove_req(struct srp_target_port *target, @@ -633,95 +647,152 @@ err: return ret; } -static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat, - int sg_cnt, struct srp_request *req, - struct srp_direct_buf *buf) +static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, + unsigned int dma_len, u32 rkey) { - u64 io_addr = 0; - u64 *dma_pages; - u32 len; - int page_cnt; - int i, j; - int ret; - struct srp_device *dev = target->srp_host->srp_dev; - struct ib_device *ibdev = dev->dev; - struct scatterlist *sg; + struct srp_direct_buf *desc = state->desc; - if (!dev->fmr_pool) - return -ENODEV; + desc->va = cpu_to_be64(dma_addr); + desc->key = cpu_to_be32(rkey); + desc->len = cpu_to_be32(dma_len); - if (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask) - return -EINVAL; + state->total_len += dma_len; + state->desc++; + state->ndesc++; +} - len = page_cnt = 0; - scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) { - unsigned int dma_len = ib_sg_dma_len(ibdev, sg); +static int srp_map_finish_fmr(struct srp_map_state *state, + struct srp_target_port *target) +{ + struct srp_device *dev = target->srp_host->srp_dev; + struct ib_pool_fmr *fmr; + u64 io_addr = 0; - if (ib_sg_dma_address(ibdev, sg) & ~dev->fmr_page_mask) { - if (i > 0) - return -EINVAL; - else - ++page_cnt; - } - if ((ib_sg_dma_address(ibdev, sg) + dma_len) & - ~dev->fmr_page_mask) { - if (i < sg_cnt - 1) - return -EINVAL; - else - ++page_cnt; - } + if (!state->npages) + return 0; - len += dma_len; + if (state->npages == 1) { + srp_map_desc(state, state->base_dma_addr, state->fmr_len, + target->rkey); + state->npages = state->fmr_len = 0; + return 0; } - page_cnt += len >> dev->fmr_page_shift; - if (page_cnt > SRP_FMR_SIZE) - return -ENOMEM; + fmr = ib_fmr_pool_map_phys(dev->fmr_pool, state->pages, + state->npages, io_addr); + if (IS_ERR(fmr)) + return PTR_ERR(fmr); - dma_pages = kmalloc(sizeof (u64) * page_cnt, GFP_ATOMIC); - if (!dma_pages) - return -ENOMEM; + *state->next_fmr++ = fmr; + state->nfmr++; - page_cnt = 0; - scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) { - unsigned int dma_len = ib_sg_dma_len(ibdev, sg); + srp_map_desc(state, 0, state->fmr_len, fmr->fmr->rkey); + state->npages = state->fmr_len = 0; + return 0; +} + +static void srp_map_update_start(struct srp_map_state *state, + struct scatterlist *sg, int sg_index, + dma_addr_t dma_addr) +{ + state->unmapped_sg = sg; + state->unmapped_index = sg_index; + state->unmapped_addr = dma_addr; +} - for (j = 0; j < dma_len; j += dev->fmr_page_size) - dma_pages[page_cnt++] = - (ib_sg_dma_address(ibdev, sg) & - dev->fmr_page_mask) + j; +static int srp_map_sg_entry(struct srp_map_state *state, + struct srp_target_port *target, + struct scatterlist *sg, int sg_index, + int use_fmr) +{ + struct srp_device *dev = target->srp_host->srp_dev; + struct ib_device *ibdev = dev->dev; + dma_addr_t dma_addr = ib_sg_dma_address(ibdev, sg); + unsigned int dma_len = ib_sg_dma_len(ibdev, sg); + unsigned int len; + int ret; + + if (!dma_len) + return 0; + + if (use_fmr == SRP_MAP_NO_FMR) { + /* Once we're in direct map mode for a request, we don't + * go back to FMR mode, so no need to update anything + * other than the descriptor. + */ + srp_map_desc(state, dma_addr, dma_len, target->rkey); + return 0; } - req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool, - dma_pages, page_cnt, io_addr); - if (IS_ERR(req->fmr)) { - ret = PTR_ERR(req->fmr); - req->fmr = NULL; - goto out; + /* If we start at an offset into the FMR page, don't merge into + * the current FMR. Finish it out, and use the kernel's MR for this + * sg entry. This is to avoid potential bugs on some SRP targets + * that were never quite defined, but went away when the initiator + * avoided using FMR on such page fragments. + */ + if (dma_addr & ~dev->fmr_page_mask || dma_len > dev->fmr_max_size) { + ret = srp_map_finish_fmr(state, target); + if (ret) + return ret; + + srp_map_desc(state, dma_addr, dma_len, target->rkey); + srp_map_update_start(state, NULL, 0, 0); + return 0; } - buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, &scat[0]) & - ~dev->fmr_page_mask); - buf->key = cpu_to_be32(req->fmr->fmr->rkey); - buf->len = cpu_to_be32(len); + /* If this is the first sg to go into the FMR, save our position. + * We need to know the first unmapped entry, its index, and the + * first unmapped address within that entry to be able to restart + * mapping after an error. + */ + if (!state->unmapped_sg) + srp_map_update_start(state, sg, sg_index, dma_addr); - ret = 0; + while (dma_len) { + if (state->npages == SRP_FMR_SIZE) { + ret = srp_map_finish_fmr(state, target); + if (ret) + return ret; -out: - kfree(dma_pages); + srp_map_update_start(state, sg, sg_index, dma_addr); + } + + len = min_t(unsigned int, dma_len, dev->fmr_page_size); + if (!state->npages) + state->base_dma_addr = dma_addr; + state->pages[state->npages++] = dma_addr; + state->fmr_len += len; + dma_addr += len; + dma_len -= len; + } + + /* If the last entry of the FMR wasn't a full page, then we need to + * close it out and start a new one -- we can only merge at page + * boundries. + */ + ret = 0; + if (len != dev->fmr_page_size) { + ret = srp_map_finish_fmr(state, target); + if (!ret) + srp_map_update_start(state, NULL, 0, 0); + } return ret; } static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, struct srp_request *req) { - struct scatterlist *scat; + struct scatterlist *scat, *sg; struct srp_cmd *cmd = req->cmd->buf; - int len, nents, count; - u8 fmt = SRP_DATA_DESC_DIRECT; + int i, len, nents, count, use_fmr; struct srp_device *dev; struct ib_device *ibdev; + struct srp_map_state state; + struct srp_indirect_buf *indirect_hdr; + dma_addr_t indirect_addr; + u32 table_len; + u8 fmt; if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) return sizeof (struct srp_cmd); @@ -741,6 +812,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, ibdev = dev->dev; count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction); + if (unlikely(count == 0)) + return -EIO; fmt = SRP_DATA_DESC_DIRECT; len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); @@ -757,49 +830,80 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat)); buf->key = cpu_to_be32(target->rkey); buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat)); - } else if (srp_map_fmr(target, scat, count, req, - (void *) cmd->add_data)) { - /* - * FMR mapping failed, and the scatterlist has more - * than one entry. Generate an indirect memory - * descriptor. - */ - struct srp_indirect_buf *buf = (void *) cmd->add_data; - struct scatterlist *sg; - u32 datalen = 0; - int i; - - fmt = SRP_DATA_DESC_INDIRECT; - len = sizeof (struct srp_cmd) + - sizeof (struct srp_indirect_buf) + - count * sizeof (struct srp_direct_buf); - - scsi_for_each_sg(scmnd, sg, count, i) { - unsigned int dma_len = ib_sg_dma_len(ibdev, sg); - - buf->desc_list[i].va = - cpu_to_be64(ib_sg_dma_address(ibdev, sg)); - buf->desc_list[i].key = - cpu_to_be32(target->rkey); - buf->desc_list[i].len = cpu_to_be32(dma_len); - datalen += dma_len; + + req->nfmr = 0; + goto map_complete; + } + + /* We have more than one scatter/gather entry, so build our indirect + * descriptor table, trying to merge as many entries with FMR as we + * can. + */ + indirect_hdr = (void *) cmd->add_data; + + memset(&state, 0, sizeof(state)); + state.desc = indirect_hdr->desc_list; + state.pages = req->map_page; + state.next_fmr = req->fmr_list; + + use_fmr = dev->fmr_pool ? SRP_MAP_ALLOW_FMR : SRP_MAP_NO_FMR; + + for_each_sg(scat, sg, count, i) { + if (srp_map_sg_entry(&state, target, sg, i, use_fmr)) { + /* FMR mapping failed, so backtrack to the first + * unmapped entry and continue on without using FMR. + */ + dma_addr_t dma_addr; + unsigned int dma_len; + +backtrack: + sg = state.unmapped_sg; + i = state.unmapped_index; + + dma_addr = ib_sg_dma_address(ibdev, sg); + dma_len = ib_sg_dma_len(ibdev, sg); + dma_len -= (state.unmapped_addr - dma_addr); + dma_addr = state.unmapped_addr; + use_fmr = SRP_MAP_NO_FMR; + srp_map_desc(&state, dma_addr, dma_len, target->rkey); } + } - if (scmnd->sc_data_direction == DMA_TO_DEVICE) - cmd->data_out_desc_cnt = count; - else - cmd->data_in_desc_cnt = count; + if (use_fmr == SRP_MAP_ALLOW_FMR && srp_map_finish_fmr(&state, target)) + goto backtrack; - buf->table_desc.va = - cpu_to_be64(req->cmd->dma + sizeof *cmd + sizeof *buf); - buf->table_desc.key = - cpu_to_be32(target->rkey); - buf->table_desc.len = - cpu_to_be32(count * sizeof (struct srp_direct_buf)); + /* We've mapped the request, fill in the command buffer. + */ + req->nfmr = state.nfmr; + if (state.ndesc == 1) { + /* FMR mapping was able to collapse this to one entry, + * so use a direct descriptor. + */ + struct srp_direct_buf *buf = (void *) cmd->add_data; - buf->len = cpu_to_be32(datalen); + *buf = indirect_hdr->desc_list[0]; + goto map_complete; } + table_len = state.ndesc * sizeof (struct srp_direct_buf); + + fmt = SRP_DATA_DESC_INDIRECT; + len = sizeof(struct srp_cmd) + sizeof (struct srp_indirect_buf); + len += table_len; + + indirect_addr = req->cmd->dma + sizeof *cmd + sizeof *indirect_hdr; + + indirect_hdr->table_desc.va = cpu_to_be64(indirect_addr); + indirect_hdr->table_desc.key = cpu_to_be32(target->rkey); + indirect_hdr->table_desc.len = cpu_to_be32(table_len); + indirect_hdr->len = cpu_to_be32(state.total_len); + + if (scmnd->sc_data_direction == DMA_TO_DEVICE) + cmd->data_out_desc_cnt = state.ndesc; + else + cmd->data_in_desc_cnt = state.ndesc; + +map_complete: if (scmnd->sc_data_direction == DMA_TO_DEVICE) cmd->buf_fmt = fmt << 4; else @@ -1947,8 +2051,7 @@ static ssize_t srp_create_target(struct device *dev, container_of(dev, struct srp_host, dev); struct Scsi_Host *target_host; struct srp_target_port *target; - int ret; - int i; + int i, ret; target_host = scsi_host_alloc(&srp_template, sizeof (struct srp_target_port)); @@ -1968,14 +2071,6 @@ static ssize_t srp_create_target(struct device *dev, target->rkey = host->srp_dev->mr->rkey; target->cmd_sg_cnt = cmd_sg_entries; - spin_lock_init(&target->lock); - INIT_LIST_HEAD(&target->free_tx); - INIT_LIST_HEAD(&target->free_reqs); - for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { - target->req_ring[i].index = i; - list_add_tail(&target->req_ring[i].list, &target->free_reqs); - } - ret = srp_parse_options(buf, target); if (ret) goto err; @@ -1985,6 +2080,23 @@ static ssize_t srp_create_target(struct device *dev, sizeof (struct srp_indirect_buf) + target->cmd_sg_cnt * sizeof (struct srp_direct_buf); + spin_lock_init(&target->lock); + INIT_LIST_HEAD(&target->free_tx); + INIT_LIST_HEAD(&target->free_reqs); + for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { + struct srp_request *req = &target->req_ring[i]; + + req->fmr_list = kmalloc(target->cmd_sg_cnt * sizeof (void *), + GFP_KERNEL); + req->map_page = kmalloc(SRP_FMR_SIZE * sizeof (void *), + GFP_KERNEL); + if (!req->fmr_list || !req->map_page) + goto err_free_mem; + + req->index = i; + list_add_tail(&req->list, &target->free_reqs); + } + ib_query_gid(host->srp_dev->dev, host->port, 0, &target->path.sgid); shost_printk(KERN_DEBUG, target->scsi_host, PFX @@ -1998,11 +2110,11 @@ static ssize_t srp_create_target(struct device *dev, ret = srp_create_target_ib(target); if (ret) - goto err; + goto err_free_mem; ret = srp_new_cm_id(target); if (ret) - goto err_free; + goto err_free_ib; target->qp_in_error = 0; ret = srp_connect_target(target); @@ -2024,9 +2136,12 @@ err_disconnect: err_cm_id: ib_destroy_cm_id(target->cm_id); -err_free: +err_free_ib: srp_free_target_ib(target); +err_free_mem: + srp_free_req_data(target); + err: scsi_host_put(target_host); @@ -2099,7 +2214,7 @@ static void srp_add_one(struct ib_device *device) struct ib_device_attr *dev_attr; struct ib_fmr_pool_param fmr_param; struct srp_host *host; - int s, e, p; + int fmr_page_shift, s, e, p; dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); if (!dev_attr) @@ -2117,12 +2232,13 @@ static void srp_add_one(struct ib_device *device) /* * Use the smallest page size supported by the HCA, down to a - * minimum of 512 bytes (which is the smallest sector that a - * SCSI command will ever carry). + * minimum of 4096 bytes. We're unlikely to build large sglists + * out of smaller entries. */ - srp_dev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1); - srp_dev->fmr_page_size = 1 << srp_dev->fmr_page_shift; - srp_dev->fmr_page_mask = ~((u64) srp_dev->fmr_page_size - 1); + fmr_page_shift = max(12, ffs(dev_attr->page_size_cap) - 1); + srp_dev->fmr_page_size = 1 << fmr_page_shift; + srp_dev->fmr_page_mask = ~((u64) srp_dev->fmr_page_size - 1); + srp_dev->fmr_max_size = srp_dev->fmr_page_size * SRP_FMR_SIZE; INIT_LIST_HEAD(&srp_dev->dev_list); @@ -2143,7 +2259,7 @@ static void srp_add_one(struct ib_device *device) fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; fmr_param.cache = 1; fmr_param.max_pages_per_fmr = SRP_FMR_SIZE; - fmr_param.page_shift = srp_dev->fmr_page_shift; + fmr_param.page_shift = fmr_page_shift; fmr_param.access = (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ); @@ -2223,6 +2339,7 @@ static void srp_remove_one(struct ib_device *device) srp_disconnect_target(target); ib_destroy_cm_id(target->cm_id); srp_free_target_ib(target); + srp_free_req_data(target); scsi_host_put(target->scsi_host); } diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index db39dbf76216..b43b5e7acbde 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -71,7 +71,10 @@ enum { SRP_FMR_SIZE = 256, SRP_FMR_POOL_SIZE = 1024, - SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4 + SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4, + + SRP_MAP_ALLOW_FMR = 0, + SRP_MAP_NO_FMR = 1, }; enum srp_target_state { @@ -93,9 +96,9 @@ struct srp_device { struct ib_pd *pd; struct ib_mr *mr; struct ib_fmr_pool *fmr_pool; - int fmr_page_shift; - int fmr_page_size; u64 fmr_page_mask; + int fmr_page_size; + int fmr_max_size; }; struct srp_host { @@ -112,7 +115,9 @@ struct srp_request { struct list_head list; struct scsi_cmnd *scmnd; struct srp_iu *cmd; - struct ib_pool_fmr *fmr; + struct ib_pool_fmr **fmr_list; + u64 *map_page; + short nfmr; short index; }; @@ -181,4 +186,19 @@ struct srp_iu { enum dma_data_direction direction; }; +struct srp_map_state { + struct ib_pool_fmr **next_fmr; + struct srp_direct_buf *desc; + u64 *pages; + dma_addr_t base_dma_addr; + u32 fmr_len; + u32 total_len; + unsigned int npages; + unsigned int nfmr; + unsigned int ndesc; + struct scatterlist *unmapped_sg; + int unmapped_index; + dma_addr_t unmapped_addr; +}; + #endif /* IB_SRP_H */ -- cgit v1.2.2 From c07d424d6118d528ef71b22b7424bfc359c307a5 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Sun, 16 Jan 2011 13:57:10 -0500 Subject: IB/srp: add support for indirect tables that don't fit in SRP_CMD This allows us to guarantee the ability to submit up to 8 MB requests based on the current value of SCSI_MAX_SG_CHAIN_SEGMENTS. While FMR will usually condense the requests into 8 SG entries, it is imperative that the target support external tables in case the FMR mapping fails or is not supported. We add a safety valve to allow targets without the needed support to reap the benefits of the large tables, but fail in a manner that lets the user know that the data didn't make it to the device. The user must add "allow_ext_sg=1" to the target parameters to indicate that the target has the needed support. If indirect_sg_entries is not specified in the modules options, then the sg_tablesize for the target will default to cmd_sg_entries unless overridden by the target options. Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 117 ++++++++++++++++++++++++++++++++---- drivers/infiniband/ulp/srp/ib_srp.h | 5 ++ 2 files changed, 110 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 9ce129ab3beb..4ec7dddbbf49 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -61,6 +61,8 @@ MODULE_LICENSE("Dual BSD/GPL"); static unsigned int srp_sg_tablesize; static unsigned int cmd_sg_entries; +static unsigned int indirect_sg_entries; +static bool allow_ext_sg; static int topspin_workarounds = 1; module_param(srp_sg_tablesize, uint, 0444); @@ -70,6 +72,14 @@ module_param(cmd_sg_entries, uint, 0444); MODULE_PARM_DESC(cmd_sg_entries, "Default number of gather/scatter entries in the SRP command (default is 12, max 255)"); +module_param(indirect_sg_entries, uint, 0444); +MODULE_PARM_DESC(indirect_sg_entries, + "Default max number of gather/scatter entries (default is 12, max is " __stringify(SCSI_MAX_SG_CHAIN_SEGMENTS) ")"); + +module_param(allow_ext_sg, bool, 0444); +MODULE_PARM_DESC(allow_ext_sg, + "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)"); + module_param(topspin_workarounds, int, 0444); MODULE_PARM_DESC(topspin_workarounds, "Enable workarounds for Topspin/Cisco SRP target bugs if != 0"); @@ -446,12 +456,19 @@ static bool srp_change_state(struct srp_target_port *target, static void srp_free_req_data(struct srp_target_port *target) { + struct ib_device *ibdev = target->srp_host->srp_dev->dev; struct srp_request *req; int i; for (i = 0, req = target->req_ring; i < SRP_CMD_SQ_SIZE; ++i, ++req) { kfree(req->fmr_list); kfree(req->map_page); + if (req->indirect_dma_addr) { + ib_dma_unmap_single(ibdev, req->indirect_dma_addr, + target->indirect_size, + DMA_TO_DEVICE); + } + kfree(req->indirect_desc); } } @@ -790,7 +807,6 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, struct ib_device *ibdev; struct srp_map_state state; struct srp_indirect_buf *indirect_hdr; - dma_addr_t indirect_addr; u32 table_len; u8 fmt; @@ -841,8 +857,11 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, */ indirect_hdr = (void *) cmd->add_data; + ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr, + target->indirect_size, DMA_TO_DEVICE); + memset(&state, 0, sizeof(state)); - state.desc = indirect_hdr->desc_list; + state.desc = req->indirect_desc; state.pages = req->map_page; state.next_fmr = req->fmr_list; @@ -872,7 +891,11 @@ backtrack: if (use_fmr == SRP_MAP_ALLOW_FMR && srp_map_finish_fmr(&state, target)) goto backtrack; - /* We've mapped the request, fill in the command buffer. + /* We've mapped the request, now pull as much of the indirect + * descriptor table as we can into the command buffer. If this + * target is not using an external indirect table, we are + * guaranteed to fit into the command, as the SCSI layer won't + * give us more S/G entries than we allow. */ req->nfmr = state.nfmr; if (state.ndesc == 1) { @@ -881,27 +904,39 @@ backtrack: */ struct srp_direct_buf *buf = (void *) cmd->add_data; - *buf = indirect_hdr->desc_list[0]; + *buf = req->indirect_desc[0]; goto map_complete; } + if (unlikely(target->cmd_sg_cnt < state.ndesc && + !target->allow_ext_sg)) { + shost_printk(KERN_ERR, target->scsi_host, + "Could not fit S/G list into SRP_CMD\n"); + return -EIO; + } + + count = min(state.ndesc, target->cmd_sg_cnt); table_len = state.ndesc * sizeof (struct srp_direct_buf); fmt = SRP_DATA_DESC_INDIRECT; len = sizeof(struct srp_cmd) + sizeof (struct srp_indirect_buf); - len += table_len; + len += count * sizeof (struct srp_direct_buf); - indirect_addr = req->cmd->dma + sizeof *cmd + sizeof *indirect_hdr; + memcpy(indirect_hdr->desc_list, req->indirect_desc, + count * sizeof (struct srp_direct_buf)); - indirect_hdr->table_desc.va = cpu_to_be64(indirect_addr); + indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); indirect_hdr->table_desc.key = cpu_to_be32(target->rkey); indirect_hdr->table_desc.len = cpu_to_be32(table_len); indirect_hdr->len = cpu_to_be32(state.total_len); if (scmnd->sc_data_direction == DMA_TO_DEVICE) - cmd->data_out_desc_cnt = state.ndesc; + cmd->data_out_desc_cnt = count; else - cmd->data_in_desc_cnt = state.ndesc; + cmd->data_in_desc_cnt = count; + + ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len, + DMA_TO_DEVICE); map_complete: if (scmnd->sc_data_direction == DMA_TO_DEVICE) @@ -1759,6 +1794,14 @@ static ssize_t show_cmd_sg_entries(struct device *dev, return sprintf(buf, "%u\n", target->cmd_sg_cnt); } +static ssize_t show_allow_ext_sg(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct srp_target_port *target = host_to_target(class_to_shost(dev)); + + return sprintf(buf, "%s\n", target->allow_ext_sg ? "true" : "false"); +} + static DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL); static DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL); static DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL); @@ -1770,6 +1813,7 @@ static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL); static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL); static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL); static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL); +static DEVICE_ATTR(allow_ext_sg, S_IRUGO, show_allow_ext_sg, NULL); static struct device_attribute *srp_host_attrs[] = { &dev_attr_id_ext, @@ -1783,6 +1827,7 @@ static struct device_attribute *srp_host_attrs[] = { &dev_attr_local_ib_port, &dev_attr_local_ib_device, &dev_attr_cmd_sg_entries, + &dev_attr_allow_ext_sg, NULL }; @@ -1868,6 +1913,8 @@ enum { SRP_OPT_IO_CLASS = 1 << 7, SRP_OPT_INITIATOR_EXT = 1 << 8, SRP_OPT_CMD_SG_ENTRIES = 1 << 9, + SRP_OPT_ALLOW_EXT_SG = 1 << 10, + SRP_OPT_SG_TABLESIZE = 1 << 11, SRP_OPT_ALL = (SRP_OPT_ID_EXT | SRP_OPT_IOC_GUID | SRP_OPT_DGID | @@ -1886,6 +1933,8 @@ static const match_table_t srp_opt_tokens = { { SRP_OPT_IO_CLASS, "io_class=%x" }, { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" }, { SRP_OPT_CMD_SG_ENTRIES, "cmd_sg_entries=%u" }, + { SRP_OPT_ALLOW_EXT_SG, "allow_ext_sg=%u" }, + { SRP_OPT_SG_TABLESIZE, "sg_tablesize=%u" }, { SRP_OPT_ERR, NULL } }; @@ -2021,6 +2070,23 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target) target->cmd_sg_cnt = token; break; + case SRP_OPT_ALLOW_EXT_SG: + if (match_int(args, &token)) { + printk(KERN_WARNING PFX "bad allow_ext_sg parameter '%s'\n", p); + goto out; + } + target->allow_ext_sg = !!token; + break; + + case SRP_OPT_SG_TABLESIZE: + if (match_int(args, &token) || token < 1 || + token > SCSI_MAX_SG_CHAIN_SEGMENTS) { + printk(KERN_WARNING PFX "bad max sg_tablesize parameter '%s'\n", p); + goto out; + } + target->sg_tablesize = token; + break; + default: printk(KERN_WARNING PFX "unknown parameter or missing value " "'%s' in target creation request\n", p); @@ -2051,6 +2117,8 @@ static ssize_t srp_create_target(struct device *dev, container_of(dev, struct srp_host, dev); struct Scsi_Host *target_host; struct srp_target_port *target; + struct ib_device *ibdev = host->srp_dev->dev; + dma_addr_t dma_addr; int i, ret; target_host = scsi_host_alloc(&srp_template, @@ -2070,12 +2138,22 @@ static ssize_t srp_create_target(struct device *dev, target->lkey = host->srp_dev->mr->lkey; target->rkey = host->srp_dev->mr->rkey; target->cmd_sg_cnt = cmd_sg_entries; + target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; + target->allow_ext_sg = allow_ext_sg; ret = srp_parse_options(buf, target); if (ret) goto err; - target_host->sg_tablesize = target->cmd_sg_cnt; + if (!host->srp_dev->fmr_pool && !target->allow_ext_sg && + target->cmd_sg_cnt < target->sg_tablesize) { + printk(KERN_WARNING PFX "No FMR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n"); + target->sg_tablesize = target->cmd_sg_cnt; + } + + target_host->sg_tablesize = target->sg_tablesize; + target->indirect_size = target->sg_tablesize * + sizeof (struct srp_direct_buf); target->max_iu_len = sizeof (struct srp_cmd) + sizeof (struct srp_indirect_buf) + target->cmd_sg_cnt * sizeof (struct srp_direct_buf); @@ -2090,14 +2168,22 @@ static ssize_t srp_create_target(struct device *dev, GFP_KERNEL); req->map_page = kmalloc(SRP_FMR_SIZE * sizeof (void *), GFP_KERNEL); - if (!req->fmr_list || !req->map_page) + req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL); + if (!req->fmr_list || !req->map_page || !req->indirect_desc) goto err_free_mem; + dma_addr = ib_dma_map_single(ibdev, req->indirect_desc, + target->indirect_size, + DMA_TO_DEVICE); + if (ib_dma_mapping_error(ibdev, dma_addr)) + goto err_free_mem; + + req->indirect_dma_addr = dma_addr; req->index = i; list_add_tail(&req->list, &target->free_reqs); } - ib_query_gid(host->srp_dev->dev, host->port, 0, &target->path.sgid); + ib_query_gid(ibdev, host->port, 0, &target->path.sgid); shost_printk(KERN_DEBUG, target->scsi_host, PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " @@ -2377,6 +2463,13 @@ static int __init srp_init_module(void) cmd_sg_entries = 255; } + if (!indirect_sg_entries) + indirect_sg_entries = cmd_sg_entries; + else if (indirect_sg_entries < cmd_sg_entries) { + printk(KERN_WARNING PFX "Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n", cmd_sg_entries); + indirect_sg_entries = cmd_sg_entries; + } + ib_srp_transport_template = srp_attach_transport(&ib_srp_transport_functions); if (!ib_srp_transport_template) diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index b43b5e7acbde..cf696218eeeb 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -117,6 +117,8 @@ struct srp_request { struct srp_iu *cmd; struct ib_pool_fmr **fmr_list; u64 *map_page; + struct srp_direct_buf *indirect_desc; + dma_addr_t indirect_dma_addr; short nfmr; short index; }; @@ -137,6 +139,8 @@ struct srp_target_port { enum srp_target_state state; unsigned int max_iu_len; unsigned int cmd_sg_cnt; + unsigned int indirect_size; + bool allow_ext_sg; /* Everything above this point is used in the hot path of * command processing. Try to keep them packed into cachelines. @@ -151,6 +155,7 @@ struct srp_target_port { struct Scsi_Host *scsi_host; char target_name[32]; unsigned int scsi_id; + unsigned int sg_tablesize; struct ib_sa_path_rec path; __be16 orig_dgid[8]; -- cgit v1.2.2 From be8b981453a4904399cb090c1660618e250092d8 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Tue, 18 Jan 2011 21:58:09 -0500 Subject: IB/srp: try to use larger FMR sizes to cover our mappings Now that we can get larger SG lists, we can take advantage of HCAs that allow us to use larger FMR sizes. In many cases, we can use up to 512 entries, so start there and work our way down. Signed-off-by: David Dillow --- drivers/infiniband/ulp/srp/ib_srp.c | 31 +++++++++++++++++++------------ drivers/infiniband/ulp/srp/ib_srp.h | 3 ++- 2 files changed, 21 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 4ec7dddbbf49..376d640487d2 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2300,7 +2300,7 @@ static void srp_add_one(struct ib_device *device) struct ib_device_attr *dev_attr; struct ib_fmr_pool_param fmr_param; struct srp_host *host; - int fmr_page_shift, s, e, p; + int max_pages_per_fmr, fmr_page_shift, s, e, p; dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL); if (!dev_attr) @@ -2340,17 +2340,24 @@ static void srp_add_one(struct ib_device *device) if (IS_ERR(srp_dev->mr)) goto err_pd; - memset(&fmr_param, 0, sizeof fmr_param); - fmr_param.pool_size = SRP_FMR_POOL_SIZE; - fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; - fmr_param.cache = 1; - fmr_param.max_pages_per_fmr = SRP_FMR_SIZE; - fmr_param.page_shift = fmr_page_shift; - fmr_param.access = (IB_ACCESS_LOCAL_WRITE | - IB_ACCESS_REMOTE_WRITE | - IB_ACCESS_REMOTE_READ); - - srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param); + for (max_pages_per_fmr = SRP_FMR_SIZE; + max_pages_per_fmr >= SRP_FMR_MIN_SIZE; + max_pages_per_fmr /= 2, srp_dev->fmr_max_size /= 2) { + memset(&fmr_param, 0, sizeof fmr_param); + fmr_param.pool_size = SRP_FMR_POOL_SIZE; + fmr_param.dirty_watermark = SRP_FMR_DIRTY_SIZE; + fmr_param.cache = 1; + fmr_param.max_pages_per_fmr = max_pages_per_fmr; + fmr_param.page_shift = fmr_page_shift; + fmr_param.access = (IB_ACCESS_LOCAL_WRITE | + IB_ACCESS_REMOTE_WRITE | + IB_ACCESS_REMOTE_READ); + + srp_dev->fmr_pool = ib_create_fmr_pool(srp_dev->pd, &fmr_param); + if (!IS_ERR(srp_dev->fmr_pool)) + break; + } + if (IS_ERR(srp_dev->fmr_pool)) srp_dev->fmr_pool = NULL; diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index cf696218eeeb..020caf0c3789 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -69,7 +69,8 @@ enum { SRP_TAG_NO_REQ = ~0U, SRP_TAG_TSK_MGMT = 1U << 31, - SRP_FMR_SIZE = 256, + SRP_FMR_SIZE = 512, + SRP_FMR_MIN_SIZE = 128, SRP_FMR_POOL_SIZE = 1024, SRP_FMR_DIRTY_SIZE = SRP_FMR_POOL_SIZE / 4, -- cgit v1.2.2 From b119601d4e226e42a067ff33116774d79dd9afbc Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Tue, 8 Mar 2011 17:15:54 +0530 Subject: OMAP4: DSS2: Add display type HDMI to DSS2 Adding display type HDMI in dss_features, overlay and the manager so that HDMI type of display will be recognized. Signed-off-by: Mythri P K Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/display.c | 2 ++ drivers/video/omap2/dss/dss_features.c | 2 +- drivers/video/omap2/dss/manager.c | 9 +++++++-- drivers/video/omap2/dss/overlay.c | 6 ++++-- 4 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 7d96b724c992..c40bcbd2e140 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -342,6 +342,7 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) return 16; case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_SDI: + case OMAP_DISPLAY_TYPE_HDMI: return 24; default: BUG(); @@ -368,6 +369,7 @@ bool dss_use_replication(struct omap_dss_device *dssdev, case OMAP_DISPLAY_TYPE_DPI: bpp = dssdev->phy.dpi.data_lines; break; + case OMAP_DISPLAY_TYPE_HDMI: case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_SDI: bpp = 24; diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 06b18f73449b..aa1622241d0d 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c @@ -130,7 +130,7 @@ static const enum omap_display_type omap4_dss_supported_displays[] = { OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI, /* OMAP_DSS_CHANNEL_DIGIT */ - OMAP_DISPLAY_TYPE_VENC, + OMAP_DISPLAY_TYPE_VENC | OMAP_DISPLAY_TYPE_HDMI, /* OMAP_DSS_CHANNEL_LCD2 */ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 1f53bf20b6cb..bcd37ec86952 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -515,6 +515,8 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD; + } else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) { + irq = DISPC_IRQ_EVSYNC_EVEN; } else { if (mgr->id == OMAP_DSS_CHANNEL_LCD) irq = DISPC_IRQ_VSYNC; @@ -536,7 +538,8 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return 0; - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC + || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { @@ -613,7 +616,8 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return 0; - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC + || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; } else { if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { @@ -1377,6 +1381,7 @@ static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) case OMAP_DISPLAY_TYPE_DBI: case OMAP_DISPLAY_TYPE_SDI: case OMAP_DISPLAY_TYPE_VENC: + case OMAP_DISPLAY_TYPE_HDMI: default_get_overlay_fifo_thresholds(ovl->id, size, &oc->burst_size, &oc->fifo_low, &oc->fifo_high); diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 996e9a4f6771..f1aca6d04011 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -679,7 +679,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) lcd2_mgr->set_device(lcd2_mgr, dssdev); mgr = lcd2_mgr; } - } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) { + } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC + && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) { if (!lcd_mgr->device || force) { if (lcd_mgr->device) lcd_mgr->unset_device(lcd_mgr); @@ -688,7 +689,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) } } - if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC + || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { if (!tv_mgr->device || force) { if (tv_mgr->device) tv_mgr->unset_device(tv_mgr); -- cgit v1.2.2 From 7ed024aa280cb38c8aa5c188d2d2c98f5daede10 Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Wed, 9 Mar 2011 16:31:38 +0530 Subject: OMAP4: DSS2: HDMI: Select between HDMI VENC clock source. Adding function to select between HDMI or VENC clock source. Signed-off-by: Mythri P K Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 5 +++++ drivers/video/omap2/dss/dss.h | 6 ++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 562d8d28d4f2..f1628bd850d1 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -605,6 +605,11 @@ void dss_set_dac_pwrdn_bgz(bool enable) REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ } +void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) +{ + REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ +} + static int dss_init(void) { int r; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 26a43c93e489..eb05d39ef17c 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -126,6 +126,11 @@ enum dss_clk_source { * OMAP4: DSS_FCLK */ }; +enum dss_hdmi_venc_clk_source_select { + DSS_VENC_TV_CLK = 0, + DSS_HDMI_M_PCLK = 1, +}; + struct dss_clock_info { /* rates that we get with dividers below */ unsigned long fck; @@ -214,6 +219,7 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); int dss_init_platform_driver(void); void dss_uninit_platform_driver(void); +void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); void dss_save_context(void); void dss_restore_context(void); void dss_clk_enable(enum dss_clock clks); -- cgit v1.2.2 From d3862610c95564a586951d5be291b9b0200d39fe Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Fri, 11 Mar 2011 18:02:49 +0530 Subject: OMAP4: DSS2: HDMI: Dispc gamma enable set/reset function for TV. Adding function to reset/set gamma table bit for TV interface, currently only support for disabled is added. Signed-off-by: Mythri P K Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 14 ++++++++++++++ drivers/video/omap2/dss/dss.h | 1 + 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b8c576a0bc02..7804779c9da1 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1008,6 +1008,20 @@ void dispc_set_burst_size(enum omap_plane plane, enable_clocks(0); } +void dispc_enable_gamma_table(bool enable) +{ + /* + * This is partially implemented to support only disabling of + * the gamma table. + */ + if (enable) { + DSSWARN("Gamma table enabling for TV not yet supported"); + return; + } + + REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); +} + static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) { u32 val; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index eb05d39ef17c..ab20270d761a 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -370,6 +370,7 @@ void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height); void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out); +void dispc_enable_gamma_table(bool enable); int dispc_setup_plane(enum omap_plane plane, u32 paddr, u16 screen_width, u16 pos_x, u16 pos_y, -- cgit v1.2.2 From 26adeece88ffe172db7e26f856b576cccfb0ec85 Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Tue, 8 Mar 2011 17:27:56 +0530 Subject: OMAP4: DSS2: HDMI: HDMI driver header file addition Adding the hdmi interface driver header file (hdmi.h) to the dss driver. Register and structure declaration done here. Signed-off-by: Mythri P K Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/hdmi.h | 415 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 drivers/video/omap2/dss/hdmi.h (limited to 'drivers') diff --git a/drivers/video/omap2/dss/hdmi.h b/drivers/video/omap2/dss/hdmi.h new file mode 100644 index 000000000000..9887ab96da3c --- /dev/null +++ b/drivers/video/omap2/dss/hdmi.h @@ -0,0 +1,415 @@ +/* + * hdmi.h + * + * HDMI driver definition for TI OMAP4 processors. + * + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef _OMAP4_DSS_HDMI_H_ +#define _OMAP4_DSS_HDMI_H_ + +#include +#include + +#define HDMI_WP 0x0 +#define HDMI_CORE_SYS 0x400 +#define HDMI_CORE_AV 0x900 +#define HDMI_PLLCTRL 0x200 +#define HDMI_PHY 0x300 + +struct hdmi_reg { u16 idx; }; + +#define HDMI_REG(idx) ((const struct hdmi_reg) { idx }) + +/* HDMI Wrapper */ +#define HDMI_WP_REG(idx) HDMI_REG(HDMI_WP + idx) + +#define HDMI_WP_REVISION HDMI_WP_REG(0x0) +#define HDMI_WP_SYSCONFIG HDMI_WP_REG(0x10) +#define HDMI_WP_IRQSTATUS_RAW HDMI_WP_REG(0x24) +#define HDMI_WP_IRQSTATUS HDMI_WP_REG(0x28) +#define HDMI_WP_PWR_CTRL HDMI_WP_REG(0x40) +#define HDMI_WP_IRQENABLE_SET HDMI_WP_REG(0x2C) +#define HDMI_WP_VIDEO_CFG HDMI_WP_REG(0x50) +#define HDMI_WP_VIDEO_SIZE HDMI_WP_REG(0x60) +#define HDMI_WP_VIDEO_TIMING_H HDMI_WP_REG(0x68) +#define HDMI_WP_VIDEO_TIMING_V HDMI_WP_REG(0x6C) +#define HDMI_WP_WP_CLK HDMI_WP_REG(0x70) + +/* HDMI IP Core System */ +#define HDMI_CORE_SYS_REG(idx) HDMI_REG(HDMI_CORE_SYS + idx) + +#define HDMI_CORE_SYS_VND_IDL HDMI_CORE_SYS_REG(0x0) +#define HDMI_CORE_SYS_DEV_IDL HDMI_CORE_SYS_REG(0x8) +#define HDMI_CORE_SYS_DEV_IDH HDMI_CORE_SYS_REG(0xC) +#define HDMI_CORE_SYS_DEV_REV HDMI_CORE_SYS_REG(0x10) +#define HDMI_CORE_SYS_SRST HDMI_CORE_SYS_REG(0x14) +#define HDMI_CORE_CTRL1 HDMI_CORE_SYS_REG(0x20) +#define HDMI_CORE_SYS_SYS_STAT HDMI_CORE_SYS_REG(0x24) +#define HDMI_CORE_SYS_VID_ACEN HDMI_CORE_SYS_REG(0x124) +#define HDMI_CORE_SYS_VID_MODE HDMI_CORE_SYS_REG(0x128) +#define HDMI_CORE_SYS_INTR_STATE HDMI_CORE_SYS_REG(0x1C0) +#define HDMI_CORE_SYS_INTR1 HDMI_CORE_SYS_REG(0x1C4) +#define HDMI_CORE_SYS_INTR2 HDMI_CORE_SYS_REG(0x1C8) +#define HDMI_CORE_SYS_INTR3 HDMI_CORE_SYS_REG(0x1CC) +#define HDMI_CORE_SYS_INTR4 HDMI_CORE_SYS_REG(0x1D0) +#define HDMI_CORE_SYS_UMASK1 HDMI_CORE_SYS_REG(0x1D4) +#define HDMI_CORE_SYS_TMDS_CTRL HDMI_CORE_SYS_REG(0x208) +#define HDMI_CORE_SYS_DE_DLY HDMI_CORE_SYS_REG(0xC8) +#define HDMI_CORE_SYS_DE_CTRL HDMI_CORE_SYS_REG(0xCC) +#define HDMI_CORE_SYS_DE_TOP HDMI_CORE_SYS_REG(0xD0) +#define HDMI_CORE_SYS_DE_CNTL HDMI_CORE_SYS_REG(0xD8) +#define HDMI_CORE_SYS_DE_CNTH HDMI_CORE_SYS_REG(0xDC) +#define HDMI_CORE_SYS_DE_LINL HDMI_CORE_SYS_REG(0xE0) +#define HDMI_CORE_SYS_DE_LINH_1 HDMI_CORE_SYS_REG(0xE4) +#define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC 0x1 +#define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC 0x1 +#define HDMI_CORE_CTRL1_BSEL_24BITBUS 0x1 +#define HDMI_CORE_CTRL1_EDGE_RISINGEDGE 0x1 + +/* HDMI DDC E-DID */ +#define HDMI_CORE_DDC_CMD HDMI_CORE_SYS_REG(0x3CC) +#define HDMI_CORE_DDC_STATUS HDMI_CORE_SYS_REG(0x3C8) +#define HDMI_CORE_DDC_ADDR HDMI_CORE_SYS_REG(0x3B4) +#define HDMI_CORE_DDC_OFFSET HDMI_CORE_SYS_REG(0x3BC) +#define HDMI_CORE_DDC_COUNT1 HDMI_CORE_SYS_REG(0x3C0) +#define HDMI_CORE_DDC_COUNT2 HDMI_CORE_SYS_REG(0x3C4) +#define HDMI_CORE_DDC_DATA HDMI_CORE_SYS_REG(0x3D0) +#define HDMI_CORE_DDC_SEGM HDMI_CORE_SYS_REG(0x3B8) + +/* HDMI IP Core Audio Video */ +#define HDMI_CORE_AV_REG(idx) HDMI_REG(HDMI_CORE_AV + idx) + +#define HDMI_CORE_AV_HDMI_CTRL HDMI_CORE_AV_REG(0xBC) +#define HDMI_CORE_AV_DPD HDMI_CORE_AV_REG(0xF4) +#define HDMI_CORE_AV_PB_CTRL1 HDMI_CORE_AV_REG(0xF8) +#define HDMI_CORE_AV_PB_CTRL2 HDMI_CORE_AV_REG(0xFC) +#define HDMI_CORE_AV_AVI_TYPE HDMI_CORE_AV_REG(0x100) +#define HDMI_CORE_AV_AVI_VERS HDMI_CORE_AV_REG(0x104) +#define HDMI_CORE_AV_AVI_LEN HDMI_CORE_AV_REG(0x108) +#define HDMI_CORE_AV_AVI_CHSUM HDMI_CORE_AV_REG(0x10C) +#define HDMI_CORE_AV_AVI_DBYTE(n) HDMI_CORE_AV_REG(n * 4 + 0x110) +#define HDMI_CORE_AV_AVI_DBYTE_NELEMS HDMI_CORE_AV_REG(15) +#define HDMI_CORE_AV_SPD_DBYTE HDMI_CORE_AV_REG(0x190) +#define HDMI_CORE_AV_SPD_DBYTE_NELEMS HDMI_CORE_AV_REG(27) +#define HDMI_CORE_AV_MPEG_DBYTE HDMI_CORE_AV_REG(0x290) +#define HDMI_CORE_AV_MPEG_DBYTE_NELEMS HDMI_CORE_AV_REG(27) +#define HDMI_CORE_AV_GEN_DBYTE HDMI_CORE_AV_REG(0x300) +#define HDMI_CORE_AV_GEN_DBYTE_NELEMS HDMI_CORE_AV_REG(31) +#define HDMI_CORE_AV_GEN2_DBYTE HDMI_CORE_AV_REG(0x380) +#define HDMI_CORE_AV_GEN2_DBYTE_NELEMS HDMI_CORE_AV_REG(31) +#define HDMI_CORE_AV_ACR_CTRL HDMI_CORE_AV_REG(0x4) +#define HDMI_CORE_AV_FREQ_SVAL HDMI_CORE_AV_REG(0x8) +#define HDMI_CORE_AV_N_SVAL1 HDMI_CORE_AV_REG(0xC) +#define HDMI_CORE_AV_N_SVAL2 HDMI_CORE_AV_REG(0x10) +#define HDMI_CORE_AV_N_SVAL3 HDMI_CORE_AV_REG(0x14) +#define HDMI_CORE_AV_CTS_SVAL1 HDMI_CORE_AV_REG(0x18) +#define HDMI_CORE_AV_CTS_SVAL2 HDMI_CORE_AV_REG(0x1C) +#define HDMI_CORE_AV_CTS_SVAL3 HDMI_CORE_AV_REG(0x20) +#define HDMI_CORE_AV_CTS_HVAL1 HDMI_CORE_AV_REG(0x24) +#define HDMI_CORE_AV_CTS_HVAL2 HDMI_CORE_AV_REG(0x28) +#define HDMI_CORE_AV_CTS_HVAL3 HDMI_CORE_AV_REG(0x2C) +#define HDMI_CORE_AV_AUD_MODE HDMI_CORE_AV_REG(0x50) +#define HDMI_CORE_AV_SPDIF_CTRL HDMI_CORE_AV_REG(0x54) +#define HDMI_CORE_AV_HW_SPDIF_FS HDMI_CORE_AV_REG(0x60) +#define HDMI_CORE_AV_SWAP_I2S HDMI_CORE_AV_REG(0x64) +#define HDMI_CORE_AV_SPDIF_ERTH HDMI_CORE_AV_REG(0x6C) +#define HDMI_CORE_AV_I2S_IN_MAP HDMI_CORE_AV_REG(0x70) +#define HDMI_CORE_AV_I2S_IN_CTRL HDMI_CORE_AV_REG(0x74) +#define HDMI_CORE_AV_I2S_CHST0 HDMI_CORE_AV_REG(0x78) +#define HDMI_CORE_AV_I2S_CHST1 HDMI_CORE_AV_REG(0x7C) +#define HDMI_CORE_AV_I2S_CHST2 HDMI_CORE_AV_REG(0x80) +#define HDMI_CORE_AV_I2S_CHST4 HDMI_CORE_AV_REG(0x84) +#define HDMI_CORE_AV_I2S_CHST5 HDMI_CORE_AV_REG(0x88) +#define HDMI_CORE_AV_ASRC HDMI_CORE_AV_REG(0x8C) +#define HDMI_CORE_AV_I2S_IN_LEN HDMI_CORE_AV_REG(0x90) +#define HDMI_CORE_AV_HDMI_CTRL HDMI_CORE_AV_REG(0xBC) +#define HDMI_CORE_AV_AUDO_TXSTAT HDMI_CORE_AV_REG(0xC0) +#define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 HDMI_CORE_AV_REG(0xCC) +#define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 HDMI_CORE_AV_REG(0xD0) +#define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 HDMI_CORE_AV_REG(0xD4) +#define HDMI_CORE_AV_TEST_TXCTRL HDMI_CORE_AV_REG(0xF0) +#define HDMI_CORE_AV_DPD HDMI_CORE_AV_REG(0xF4) +#define HDMI_CORE_AV_PB_CTRL1 HDMI_CORE_AV_REG(0xF8) +#define HDMI_CORE_AV_PB_CTRL2 HDMI_CORE_AV_REG(0xFC) +#define HDMI_CORE_AV_AVI_TYPE HDMI_CORE_AV_REG(0x100) +#define HDMI_CORE_AV_AVI_VERS HDMI_CORE_AV_REG(0x104) +#define HDMI_CORE_AV_AVI_LEN HDMI_CORE_AV_REG(0x108) +#define HDMI_CORE_AV_AVI_CHSUM HDMI_CORE_AV_REG(0x10C) +#define HDMI_CORE_AV_SPD_TYPE HDMI_CORE_AV_REG(0x180) +#define HDMI_CORE_AV_SPD_VERS HDMI_CORE_AV_REG(0x184) +#define HDMI_CORE_AV_SPD_LEN HDMI_CORE_AV_REG(0x188) +#define HDMI_CORE_AV_SPD_CHSUM HDMI_CORE_AV_REG(0x18C) +#define HDMI_CORE_AV_MPEG_TYPE HDMI_CORE_AV_REG(0x280) +#define HDMI_CORE_AV_MPEG_VERS HDMI_CORE_AV_REG(0x284) +#define HDMI_CORE_AV_MPEG_LEN HDMI_CORE_AV_REG(0x288) +#define HDMI_CORE_AV_MPEG_CHSUM HDMI_CORE_AV_REG(0x28C) +#define HDMI_CORE_AV_CP_BYTE1 HDMI_CORE_AV_REG(0x37C) +#define HDMI_CORE_AV_CEC_ADDR_ID HDMI_CORE_AV_REG(0x3FC) +#define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4 +#define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4 +#define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4 +#define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4 + +/* PLL */ +#define HDMI_PLL_REG(idx) HDMI_REG(HDMI_PLLCTRL + idx) + +#define PLLCTRL_PLL_CONTROL HDMI_PLL_REG(0x0) +#define PLLCTRL_PLL_STATUS HDMI_PLL_REG(0x4) +#define PLLCTRL_PLL_GO HDMI_PLL_REG(0x8) +#define PLLCTRL_CFG1 HDMI_PLL_REG(0xC) +#define PLLCTRL_CFG2 HDMI_PLL_REG(0x10) +#define PLLCTRL_CFG3 HDMI_PLL_REG(0x14) +#define PLLCTRL_CFG4 HDMI_PLL_REG(0x20) + +/* HDMI PHY */ +#define HDMI_PHY_REG(idx) HDMI_REG(HDMI_PHY + idx) + +#define HDMI_TXPHY_TX_CTRL HDMI_PHY_REG(0x0) +#define HDMI_TXPHY_DIGITAL_CTRL HDMI_PHY_REG(0x4) +#define HDMI_TXPHY_POWER_CTRL HDMI_PHY_REG(0x8) +#define HDMI_TXPHY_PAD_CFG_CTRL HDMI_PHY_REG(0xC) + +/* HDMI EDID Length */ +#define HDMI_EDID_MAX_LENGTH 256 +#define EDID_TIMING_DESCRIPTOR_SIZE 0x12 +#define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36 +#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80 +#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 +#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 + +#define OMAP_HDMI_TIMINGS_NB 34 + +#define REG_FLD_MOD(idx, val, start, end) \ + hdmi_write_reg(idx, FLD_MOD(hdmi_read_reg(idx), val, start, end)) +#define REG_GET(idx, start, end) \ + FLD_GET(hdmi_read_reg(idx), start, end) + +/* HDMI timing structure */ +struct hdmi_timings { + struct omap_video_timings timings; + int vsync_pol; + int hsync_pol; +}; + +enum hdmi_phy_pwr { + HDMI_PHYPWRCMD_OFF = 0, + HDMI_PHYPWRCMD_LDOON = 1, + HDMI_PHYPWRCMD_TXON = 2 +}; + +enum hdmi_pll_pwr { + HDMI_PLLPWRCMD_ALLOFF = 0, + HDMI_PLLPWRCMD_PLLONLY = 1, + HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2, + HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3 +}; + +enum hdmi_clk_refsel { + HDMI_REFSEL_PCLK = 0, + HDMI_REFSEL_REF1 = 1, + HDMI_REFSEL_REF2 = 2, + HDMI_REFSEL_SYSCLK = 3 +}; + +enum hdmi_core_inputbus_width { + HDMI_INPUT_8BIT = 0, + HDMI_INPUT_10BIT = 1, + HDMI_INPUT_12BIT = 2 +}; + +enum hdmi_core_dither_trunc { + HDMI_OUTPUTTRUNCATION_8BIT = 0, + HDMI_OUTPUTTRUNCATION_10BIT = 1, + HDMI_OUTPUTTRUNCATION_12BIT = 2, + HDMI_OUTPUTDITHER_8BIT = 3, + HDMI_OUTPUTDITHER_10BIT = 4, + HDMI_OUTPUTDITHER_12BIT = 5 +}; + +enum hdmi_core_deepcolor_ed { + HDMI_DEEPCOLORPACKECTDISABLE = 0, + HDMI_DEEPCOLORPACKECTENABLE = 1 +}; + +enum hdmi_core_packet_mode { + HDMI_PACKETMODERESERVEDVALUE = 0, + HDMI_PACKETMODE24BITPERPIXEL = 4, + HDMI_PACKETMODE30BITPERPIXEL = 5, + HDMI_PACKETMODE36BITPERPIXEL = 6, + HDMI_PACKETMODE48BITPERPIXEL = 7 +}; + +enum hdmi_core_hdmi_dvi { + HDMI_DVI = 0, + HDMI_HDMI = 1 +}; + +enum hdmi_core_tclkselclkmult { + HDMI_FPLL05IDCK = 0, + HDMI_FPLL10IDCK = 1, + HDMI_FPLL20IDCK = 2, + HDMI_FPLL40IDCK = 3 +}; + +enum hdmi_core_packet_ctrl { + HDMI_PACKETENABLE = 1, + HDMI_PACKETDISABLE = 0, + HDMI_PACKETREPEATON = 1, + HDMI_PACKETREPEATOFF = 0 +}; + +/* INFOFRAME_AVI_ definitions */ +enum hdmi_core_infoframe { + HDMI_INFOFRAME_AVI_DB1Y_RGB = 0, + HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1, + HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2, + HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0, + HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON = 1, + HDMI_INFOFRAME_AVI_DB1B_NO = 0, + HDMI_INFOFRAME_AVI_DB1B_VERT = 1, + HDMI_INFOFRAME_AVI_DB1B_HORI = 2, + HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3, + HDMI_INFOFRAME_AVI_DB1S_0 = 0, + HDMI_INFOFRAME_AVI_DB1S_1 = 1, + HDMI_INFOFRAME_AVI_DB1S_2 = 2, + HDMI_INFOFRAME_AVI_DB2C_NO = 0, + HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1, + HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2, + HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3, + HDMI_INFOFRAME_AVI_DB2M_NO = 0, + HDMI_INFOFRAME_AVI_DB2M_43 = 1, + HDMI_INFOFRAME_AVI_DB2M_169 = 2, + HDMI_INFOFRAME_AVI_DB2R_SAME = 8, + HDMI_INFOFRAME_AVI_DB2R_43 = 9, + HDMI_INFOFRAME_AVI_DB2R_169 = 10, + HDMI_INFOFRAME_AVI_DB2R_149 = 11, + HDMI_INFOFRAME_AVI_DB3ITC_NO = 0, + HDMI_INFOFRAME_AVI_DB3ITC_YES = 1, + HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0, + HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1, + HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0, + HDMI_INFOFRAME_AVI_DB3Q_LR = 1, + HDMI_INFOFRAME_AVI_DB3Q_FR = 2, + HDMI_INFOFRAME_AVI_DB3SC_NO = 0, + HDMI_INFOFRAME_AVI_DB3SC_HORI = 1, + HDMI_INFOFRAME_AVI_DB3SC_VERT = 2, + HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3, + HDMI_INFOFRAME_AVI_DB5PR_NO = 0, + HDMI_INFOFRAME_AVI_DB5PR_2 = 1, + HDMI_INFOFRAME_AVI_DB5PR_3 = 2, + HDMI_INFOFRAME_AVI_DB5PR_4 = 3, + HDMI_INFOFRAME_AVI_DB5PR_5 = 4, + HDMI_INFOFRAME_AVI_DB5PR_6 = 5, + HDMI_INFOFRAME_AVI_DB5PR_7 = 6, + HDMI_INFOFRAME_AVI_DB5PR_8 = 7, + HDMI_INFOFRAME_AVI_DB5PR_9 = 8, + HDMI_INFOFRAME_AVI_DB5PR_10 = 9 +}; + +enum hdmi_packing_mode { + HDMI_PACK_10b_RGB_YUV444 = 0, + HDMI_PACK_24b_RGB_YUV444_YUV422 = 1, + HDMI_PACK_20b_YUV422 = 2, + HDMI_PACK_ALREADYPACKED = 7 +}; + +struct hdmi_core_video_config { + enum hdmi_core_inputbus_width ip_bus_width; + enum hdmi_core_dither_trunc op_dither_truc; + enum hdmi_core_deepcolor_ed deep_color_pkt; + enum hdmi_core_packet_mode pkt_mode; + enum hdmi_core_hdmi_dvi hdmi_dvi; + enum hdmi_core_tclkselclkmult tclk_sel_clkmult; +}; + +/* + * Refer to section 8.2 in HDMI 1.3 specification for + * details about infoframe databytes + */ +struct hdmi_core_infoframe_avi { + u8 db1_format; + /* Y0, Y1 rgb,yCbCr */ + u8 db1_active_info; + /* A0 Active information Present */ + u8 db1_bar_info_dv; + /* B0, B1 Bar info data valid */ + u8 db1_scan_info; + /* S0, S1 scan information */ + u8 db2_colorimetry; + /* C0, C1 colorimetry */ + u8 db2_aspect_ratio; + /* M0, M1 Aspect ratio (4:3, 16:9) */ + u8 db2_active_fmt_ar; + /* R0...R3 Active format aspect ratio */ + u8 db3_itc; + /* ITC IT content. */ + u8 db3_ec; + /* EC0, EC1, EC2 Extended colorimetry */ + u8 db3_q_range; + /* Q1, Q0 Quantization range */ + u8 db3_nup_scaling; + /* SC1, SC0 Non-uniform picture scaling */ + u8 db4_videocode; + /* VIC0..6 Video format identification */ + u8 db5_pixel_repeat; + /* PR0..PR3 Pixel repetition factor */ + u16 db6_7_line_eoftop; + /* Line number end of top bar */ + u16 db8_9_line_sofbottom; + /* Line number start of bottom bar */ + u16 db10_11_pixel_eofleft; + /* Pixel number end of left bar */ + u16 db12_13_pixel_sofright; + /* Pixel number start of right bar */ +}; + +struct hdmi_core_packet_enable_repeat { + u32 audio_pkt; + u32 audio_pkt_repeat; + u32 avi_infoframe; + u32 avi_infoframe_repeat; + u32 gen_cntrl_pkt; + u32 gen_cntrl_pkt_repeat; + u32 generic_pkt; + u32 generic_pkt_repeat; +}; + +struct hdmi_video_format { + enum hdmi_packing_mode packing_mode; + u32 y_res; /* Line per panel */ + u32 x_res; /* pixel per line */ +}; + +struct hdmi_video_interface { + int vsp; /* Vsync polarity */ + int hsp; /* Hsync polarity */ + int interlacing; + int tm; /* Timing mode */ +}; + +struct hdmi_cm { + int code; + int mode; +}; + +struct hdmi_config { + struct hdmi_timings timings; + u16 interlace; + struct hdmi_cm cm; +}; + +#endif -- cgit v1.2.2 From c3198a5e83121d6e3d01816f15164f158f4301d8 Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Sat, 12 Mar 2011 12:04:27 +0530 Subject: OMAP4: DSS2: HDMI: HDMI driver addition in the DSS Adding the hdmi interface driver(hdmi.c) to the dss driver. It configures the audio and video portion of HDMI based on functionality called by the panel driver. Signed-off-by: Mythri P K Signed-off-by: Yong Zhi Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/display.c | 3 + drivers/video/omap2/dss/dss.h | 34 + drivers/video/omap2/dss/hdmi.c | 1332 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1369 insertions(+) create mode 100644 drivers/video/omap2/dss/hdmi.c (limited to 'drivers') diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index c40bcbd2e140..a85a6f38b40c 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -418,6 +418,9 @@ void dss_init_device(struct platform_device *pdev, r = dsi_init_display(dssdev); break; #endif + case OMAP_DISPLAY_TYPE_HDMI: + r = hdmi_init_display(dssdev); + break; default: DSSERR("Support for display '%s' not compiled in.\n", dssdev->name); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index ab20270d761a..91ed3fa8e60d 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -173,6 +173,16 @@ struct dsi_clock_info { bool use_sys_clk; }; +/* HDMI PLL structure */ +struct hdmi_pll_info { + u16 regn; + u16 regm; + u32 regmf; + u16 regm2; + u16 regsd; + u16 dcofreq; +}; + struct seq_file; struct platform_device; @@ -444,6 +454,30 @@ static inline void venc_uninit_platform_driver(void) } #endif +/* HDMI */ +#ifdef CONFIG_OMAP4_DSS_HDMI +int hdmi_init_platform_driver(void); +void hdmi_uninit_platform_driver(void); +int hdmi_init_display(struct omap_dss_device *dssdev); +#else +static inline int hdmi_init_display(struct omap_dss_device *dssdev) +{ + return 0; +} +static inline int hdmi_init_platform_driver(void) +{ + return 0; +} +static inline void hdmi_uninit_platform_driver(void) +{ +} +#endif +int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); +void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); +int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + /* RFBI */ #ifdef CONFIG_OMAP2_DSS_RFBI int rfbi_init_platform_driver(void); diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c new file mode 100644 index 000000000000..0d44f070ef36 --- /dev/null +++ b/drivers/video/omap2/dss/hdmi.c @@ -0,0 +1,1332 @@ +/* + * hdmi.c + * + * HDMI interface DSS driver setting for TI's OMAP4 family of processor. + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Authors: Yong Zhi + * Mythri pk + * + * 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#define DSS_SUBSYS_NAME "HDMI" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dss.h" +#include "hdmi.h" + +static struct { + struct mutex lock; + struct omap_display_platform_data *pdata; + struct platform_device *pdev; + void __iomem *base_wp; /* HDMI wrapper */ + int code; + int mode; + u8 edid[HDMI_EDID_MAX_LENGTH]; + u8 edid_set; + bool custom_set; + struct hdmi_config cfg; +} hdmi; + +/* + * Logic for the below structure : + * user enters the CEA or VESA timings by specifying the HDMI/DVI code. + * There is a correspondence between CEA/VESA timing and code, please + * refer to section 6.3 in HDMI 1.3 specification for timing code. + * + * In the below structure, cea_vesa_timings corresponds to all OMAP4 + * supported CEA and VESA timing values.code_cea corresponds to the CEA + * code, It is used to get the timing from cea_vesa_timing array.Similarly + * with code_vesa. Code_index is used for back mapping, that is once EDID + * is read from the TV, EDID is parsed to find the timing values and then + * map it to corresponding CEA or VESA index. + */ + +static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = { + { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0}, + { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1}, + { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}, + { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0}, + { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0}, + { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0}, + { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0}, + { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1}, + { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1}, + { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1}, + { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0}, + { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0}, + { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1}, + { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0}, + { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1}, + /* VESA From Here */ + { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0}, + { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1}, + { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1}, + { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0}, + { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0}, + { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1}, + { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1}, + { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1}, + { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0}, + { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0}, + { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0}, + { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0}, + { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1}, + { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1}, + { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1}, + { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1}, + { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1}, + { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1}, + { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1} +}; + +/* + * This is a static mapping array which maps the timing values + * with corresponding CEA / VESA code + */ +static const int code_index[OMAP_HDMI_TIMINGS_NB] = { + 1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32, + /* <--15 CEA 17--> vesa*/ + 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A, + 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B +}; + +/* + * This is reverse static mapping which maps the CEA / VESA code + * to the corresponding timing values + */ +static const int code_cea[39] = { + -1, 0, 3, 3, 2, 8, 5, 5, -1, -1, + -1, -1, -1, -1, -1, -1, 9, 10, 10, 1, + 7, 6, 6, -1, -1, -1, -1, -1, -1, 11, + 11, 12, 14, -1, -1, 13, 13, 4, 4 +}; + +static const int code_vesa[85] = { + -1, -1, -1, -1, 15, -1, -1, -1, -1, 16, + -1, -1, -1, -1, 17, -1, 23, -1, -1, -1, + -1, -1, 29, 18, -1, -1, -1, 32, 19, -1, + -1, -1, 21, -1, -1, 22, -1, -1, -1, 20, + -1, 30, 24, -1, -1, -1, -1, 25, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 31, 26, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 27, 28, -1, 33}; + +static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0}; + +static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val) +{ + __raw_writel(val, hdmi.base_wp + idx.idx); +} + +static inline u32 hdmi_read_reg(const struct hdmi_reg idx) +{ + return __raw_readl(hdmi.base_wp + idx.idx); +} + +static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx, + int b2, int b1, u32 val) +{ + u32 t = 0; + while (val != REG_GET(idx, b2, b1)) { + udelay(1); + if (t++ > 10000) + return !val; + } + return val; +} + +int hdmi_init_display(struct omap_dss_device *dssdev) +{ + DSSDBG("init_display\n"); + + return 0; +} + +static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq, + struct hdmi_pll_info *fmt, u16 sd) +{ + u32 r; + + /* PLL start always use manual mode */ + REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0); + + r = hdmi_read_reg(PLLCTRL_CFG1); + r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ + r = FLD_MOD(r, fmt->regn, 8, 1); /* CFG1_PLL_REGN */ + + hdmi_write_reg(PLLCTRL_CFG1, r); + + r = hdmi_read_reg(PLLCTRL_CFG2); + + r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ + r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ + r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ + + if (dcofreq) { + /* divider programming for frequency beyond 1000Mhz */ + REG_FLD_MOD(PLLCTRL_CFG3, sd, 17, 10); + r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ + } else { + r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ + } + + hdmi_write_reg(PLLCTRL_CFG2, r); + + r = hdmi_read_reg(PLLCTRL_CFG4); + r = FLD_MOD(r, fmt->regm2, 24, 18); + r = FLD_MOD(r, fmt->regmf, 17, 0); + + hdmi_write_reg(PLLCTRL_CFG4, r); + + /* go now */ + REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0); + + /* wait for bit change */ + if (hdmi_wait_for_bit_change(PLLCTRL_PLL_GO, 0, 0, 1) != 1) { + DSSERR("PLL GO bit not set\n"); + return -ETIMEDOUT; + } + + /* Wait till the lock bit is set in PLL status */ + if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { + DSSWARN("cannot lock PLL\n"); + DSSWARN("CFG1 0x%x\n", + hdmi_read_reg(PLLCTRL_CFG1)); + DSSWARN("CFG2 0x%x\n", + hdmi_read_reg(PLLCTRL_CFG2)); + DSSWARN("CFG4 0x%x\n", + hdmi_read_reg(PLLCTRL_CFG4)); + return -ETIMEDOUT; + } + + DSSDBG("PLL locked!\n"); + + return 0; +} + +/* PHY_PWR_CMD */ +static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val) +{ + /* Command for power control of HDMI PHY */ + REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6); + + /* Status of the power control of HDMI PHY */ + if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 5, 4, val) != val) { + DSSERR("Failed to set PHY power mode to %d\n", val); + return -ETIMEDOUT; + } + + return 0; +} + +/* PLL_PWR_CMD */ +static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val) +{ + /* Command for power control of HDMI PLL */ + REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2); + + /* wait till PHY_PWR_STATUS is set */ + if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) { + DSSERR("Failed to set PHY_PWR_STATUS\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int hdmi_pll_reset(void) +{ + /* SYSRESET controlled by power FSM */ + REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3); + + /* READ 0x0 reset is in progress */ + if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) { + DSSERR("Failed to sysreset PLL\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int hdmi_phy_init(void) +{ + u16 r = 0; + + r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON); + if (r) + return r; + + r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON); + if (r) + return r; + + /* + * Read address 0 in order to get the SCP reset done completed + * Dummy access performed to make sure reset is done + */ + hdmi_read_reg(HDMI_TXPHY_TX_CTRL); + + /* + * Write to phy address 0 to configure the clock + * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field + */ + REG_FLD_MOD(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30); + + /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ + hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); + + /* Setup max LDO voltage */ + REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); + + /* Write to phy address 3 to change the polarity control */ + REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); + + return 0; +} + +static int hdmi_wait_softreset(void) +{ + /* reset W1 */ + REG_FLD_MOD(HDMI_WP_SYSCONFIG, 0x1, 0, 0); + + /* wait till SOFTRESET == 0 */ + if (hdmi_wait_for_bit_change(HDMI_WP_SYSCONFIG, 0, 0, 0) != 0) { + DSSERR("sysconfig reset failed\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int hdmi_pll_program(struct hdmi_pll_info *fmt) +{ + u16 r = 0; + enum hdmi_clk_refsel refsel; + + /* wait for wrapper reset */ + r = hdmi_wait_softreset(); + if (r) + return r; + + r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); + if (r) + return r; + + r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS); + if (r) + return r; + + r = hdmi_pll_reset(); + if (r) + return r; + + refsel = HDMI_REFSEL_SYSCLK; + + r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd); + if (r) + return r; + + return 0; +} + +static void hdmi_phy_off(void) +{ + hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF); +} + +static int hdmi_core_ddc_edid(u8 *pedid, int ext) +{ + u32 i, j; + char checksum = 0; + u32 offset = 0; + + /* Turn on CLK for DDC */ + REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0); + + /* + * SW HACK : Without the Delay DDC(i2c bus) reads 0 values / + * right shifted values( The behavior is not consistent and seen only + * with some TV's) + */ + usleep_range(800, 1000); + + if (!ext) { + /* Clk SCL Devices */ + REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0); + + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Failed to program DDC\n"); + return -ETIMEDOUT; + } + + /* Clear FIFO */ + REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0); + + /* HDMI_CORE_DDC_STATUS_IN_PROG */ + if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, + 4, 4, 0) != 0) { + DSSERR("Failed to program DDC\n"); + return -ETIMEDOUT; + } + + } else { + if (ext % 2 != 0) + offset = 0x80; + } + + /* Load Segment Address Register */ + REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0); + + /* Load Slave Address Register */ + REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); + + /* Load Offset Address Register */ + REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0); + + /* Load Byte Count */ + REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); + REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); + + /* Set DDC_CMD */ + if (ext) + REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0); + else + REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0); + + /* HDMI_CORE_DDC_STATUS_BUS_LOW */ + if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) { + DSSWARN("I2C Bus Low?\n"); + return -EIO; + } + /* HDMI_CORE_DDC_STATUS_NO_ACK */ + if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) { + DSSWARN("I2C No Ack\n"); + return -EIO; + } + + i = ext * 128; + j = 0; + while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) || + (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) && + j < 128) { + + if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) { + /* FIFO not empty */ + pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0); + j++; + } + } + + for (j = 0; j < 128; j++) + checksum += pedid[j]; + + if (checksum != 0) { + DSSERR("E-EDID checksum failed!!\n"); + return -EIO; + } + + return 0; +} + +static int read_edid(u8 *pedid, u16 max_length) +{ + int r = 0, n = 0, i = 0; + int max_ext_blocks = (max_length / 128) - 1; + + r = hdmi_core_ddc_edid(pedid, 0); + if (r) { + return r; + } else { + n = pedid[0x7e]; + + /* + * README: need to comply with max_length set by the caller. + * Better implementation should be to allocate necessary + * memory to store EDID according to nb_block field found + * in first block + */ + if (n > max_ext_blocks) + n = max_ext_blocks; + + for (i = 1; i <= n; i++) { + r = hdmi_core_ddc_edid(pedid, i); + if (r) + return r; + } + } + return 0; +} + +static int get_timings_index(void) +{ + int code; + + if (hdmi.mode == 0) + code = code_vesa[hdmi.code]; + else + code = code_cea[hdmi.code]; + + if (code == -1) { + /* HDMI code 4 corresponds to 640 * 480 VGA */ + hdmi.code = 4; + /* DVI mode 1 corresponds to HDMI 0 to DVI */ + hdmi.mode = HDMI_DVI; + + code = code_vesa[hdmi.code]; + } + return code; +} + +static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) +{ + int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0; + int timing_vsync = 0, timing_hsync = 0; + struct omap_video_timings temp; + struct hdmi_cm cm = {-1}; + DSSDBG("hdmi_get_code\n"); + + for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) { + temp = cea_vesa_timings[i].timings; + if ((temp.pixel_clock == timing->pixel_clock) && + (temp.x_res == timing->x_res) && + (temp.y_res == timing->y_res)) { + + temp_hsync = temp.hfp + temp.hsw + temp.hbp; + timing_hsync = timing->hfp + timing->hsw + timing->hbp; + temp_vsync = temp.vfp + temp.vsw + temp.vbp; + timing_vsync = timing->vfp + timing->vsw + timing->vbp; + + DSSDBG("temp_hsync = %d , temp_vsync = %d" + "timing_hsync = %d, timing_vsync = %d\n", + temp_hsync, temp_hsync, + timing_hsync, timing_vsync); + + if ((temp_hsync == timing_hsync) && + (temp_vsync == timing_vsync)) { + code = i; + cm.code = code_index[i]; + if (code < 14) + cm.mode = HDMI_HDMI; + else + cm.mode = HDMI_DVI; + DSSDBG("Hdmi_code = %d mode = %d\n", + cm.code, cm.mode); + break; + } + } + } + + return cm; +} + +static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid , + struct omap_video_timings *timings) +{ + /* X and Y resolution */ + timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) | + edid[current_descriptor_addrs + 2]); + timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) | + edid[current_descriptor_addrs + 5]); + + timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) | + edid[current_descriptor_addrs]); + + timings->pixel_clock = 10 * timings->pixel_clock; + + /* HORIZONTAL FRONT PORCH */ + timings->hfp = edid[current_descriptor_addrs + 8] | + ((edid[current_descriptor_addrs + 11] & 0xc0) << 2); + /* HORIZONTAL SYNC WIDTH */ + timings->hsw = edid[current_descriptor_addrs + 9] | + ((edid[current_descriptor_addrs + 11] & 0x30) << 4); + /* HORIZONTAL BACK PORCH */ + timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) | + edid[current_descriptor_addrs + 3]) - + (timings->hfp + timings->hsw); + /* VERTICAL FRONT PORCH */ + timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) | + ((edid[current_descriptor_addrs + 11] & 0x0f) << 2); + /* VERTICAL SYNC WIDTH */ + timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) | + ((edid[current_descriptor_addrs + 11] & 0x03) << 4); + /* VERTICAL BACK PORCH */ + timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) | + edid[current_descriptor_addrs + 6]) - + (timings->vfp + timings->vsw); + +} + +/* Description : This function gets the resolution information from EDID */ +static void get_edid_timing_data(u8 *edid) +{ + u8 count; + u16 current_descriptor_addrs; + struct hdmi_cm cm; + struct omap_video_timings edid_timings; + + /* seach block 0, there are 4 DTDs arranged in priority order */ + for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) { + current_descriptor_addrs = + EDID_DESCRIPTOR_BLOCK0_ADDRESS + + count * EDID_TIMING_DESCRIPTOR_SIZE; + get_horz_vert_timing_info(current_descriptor_addrs, + edid, &edid_timings); + cm = hdmi_get_code(&edid_timings); + DSSDBG("Block0[%d] value matches code = %d , mode = %d\n", + count, cm.code, cm.mode); + if (cm.code == -1) { + continue; + } else { + hdmi.code = cm.code; + hdmi.mode = cm.mode; + DSSDBG("code = %d , mode = %d\n", + hdmi.code, hdmi.mode); + return; + } + } + if (edid[0x7e] != 0x00) { + for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR; + count++) { + current_descriptor_addrs = + EDID_DESCRIPTOR_BLOCK1_ADDRESS + + count * EDID_TIMING_DESCRIPTOR_SIZE; + get_horz_vert_timing_info(current_descriptor_addrs, + edid, &edid_timings); + cm = hdmi_get_code(&edid_timings); + DSSDBG("Block1[%d] value matches code = %d, mode = %d", + count, cm.code, cm.mode); + if (cm.code == -1) { + continue; + } else { + hdmi.code = cm.code; + hdmi.mode = cm.mode; + DSSDBG("code = %d , mode = %d\n", + hdmi.code, hdmi.mode); + return; + } + } + } + + DSSINFO("no valid timing found , falling back to VGA\n"); + hdmi.code = 4; /* setting default value of 640 480 VGA */ + hdmi.mode = HDMI_DVI; +} + +static void hdmi_read_edid(struct omap_video_timings *dp) +{ + int ret = 0, code; + + memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH); + + if (!hdmi.edid_set) + ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH); + + if (!ret) { + if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) { + /* search for timings of default resolution */ + get_edid_timing_data(hdmi.edid); + hdmi.edid_set = true; + } + } else { + DSSWARN("failed to read E-EDID\n"); + } + + if (!hdmi.edid_set) { + DSSINFO("fallback to VGA\n"); + hdmi.code = 4; /* setting default value of 640 480 VGA */ + hdmi.mode = HDMI_DVI; + } + + code = get_timings_index(); + + *dp = cea_vesa_timings[code].timings; +} + +static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, + struct hdmi_core_infoframe_avi *avi_cfg, + struct hdmi_core_packet_enable_repeat *repeat_cfg) +{ + DSSDBG("Enter hdmi_core_init\n"); + + /* video core */ + video_cfg->ip_bus_width = HDMI_INPUT_8BIT; + video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT; + video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE; + video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE; + video_cfg->hdmi_dvi = HDMI_DVI; + video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK; + + /* info frame */ + avi_cfg->db1_format = 0; + avi_cfg->db1_active_info = 0; + avi_cfg->db1_bar_info_dv = 0; + avi_cfg->db1_scan_info = 0; + avi_cfg->db2_colorimetry = 0; + avi_cfg->db2_aspect_ratio = 0; + avi_cfg->db2_active_fmt_ar = 0; + avi_cfg->db3_itc = 0; + avi_cfg->db3_ec = 0; + avi_cfg->db3_q_range = 0; + avi_cfg->db3_nup_scaling = 0; + avi_cfg->db4_videocode = 0; + avi_cfg->db5_pixel_repeat = 0; + avi_cfg->db6_7_line_eoftop = 0 ; + avi_cfg->db8_9_line_sofbottom = 0; + avi_cfg->db10_11_pixel_eofleft = 0; + avi_cfg->db12_13_pixel_sofright = 0; + + /* packet enable and repeat */ + repeat_cfg->audio_pkt = 0; + repeat_cfg->audio_pkt_repeat = 0; + repeat_cfg->avi_infoframe = 0; + repeat_cfg->avi_infoframe_repeat = 0; + repeat_cfg->gen_cntrl_pkt = 0; + repeat_cfg->gen_cntrl_pkt_repeat = 0; + repeat_cfg->generic_pkt = 0; + repeat_cfg->generic_pkt_repeat = 0; +} + +static void hdmi_core_powerdown_disable(void) +{ + DSSDBG("Enter hdmi_core_powerdown_disable\n"); + REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0); +} + +static void hdmi_core_swreset_release(void) +{ + DSSDBG("Enter hdmi_core_swreset_release\n"); + REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0); +} + +static void hdmi_core_swreset_assert(void) +{ + DSSDBG("Enter hdmi_core_swreset_assert\n"); + REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0); +} + +/* DSS_HDMI_CORE_VIDEO_CONFIG */ +static void hdmi_core_video_config(struct hdmi_core_video_config *cfg) +{ + u32 r = 0; + + /* sys_ctrl1 default configuration not tunable */ + r = hdmi_read_reg(HDMI_CORE_CTRL1); + r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5); + r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4); + r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2); + r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1); + hdmi_write_reg(HDMI_CORE_CTRL1, r); + + REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6); + + /* Vid_Mode */ + r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE); + + /* dither truncation configuration */ + if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) { + r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6); + r = FLD_MOD(r, 1, 5, 5); + } else { + r = FLD_MOD(r, cfg->op_dither_truc, 7, 6); + r = FLD_MOD(r, 0, 5, 5); + } + hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r); + + /* HDMI_Ctrl */ + r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL); + r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6); + r = FLD_MOD(r, cfg->pkt_mode, 5, 3); + r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0); + hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r); + + /* TMDS_CTRL */ + REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL, + cfg->tclk_sel_clkmult, 6, 5); +} + +static void hdmi_core_aux_infoframe_avi_config( + struct hdmi_core_infoframe_avi info_avi) +{ + u32 val; + char sum = 0, checksum = 0; + + sum += 0x82 + 0x002 + 0x00D; + hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082); + hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002); + hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D); + + val = (info_avi.db1_format << 5) | + (info_avi.db1_active_info << 4) | + (info_avi.db1_bar_info_dv << 2) | + (info_avi.db1_scan_info); + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val); + sum += val; + + val = (info_avi.db2_colorimetry << 6) | + (info_avi.db2_aspect_ratio << 4) | + (info_avi.db2_active_fmt_ar); + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val); + sum += val; + + val = (info_avi.db3_itc << 7) | + (info_avi.db3_ec << 4) | + (info_avi.db3_q_range << 2) | + (info_avi.db3_nup_scaling); + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val); + sum += val; + + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode); + sum += info_avi.db4_videocode; + + val = info_avi.db5_pixel_repeat; + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val); + sum += val; + + val = info_avi.db6_7_line_eoftop & 0x00FF; + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val); + sum += val; + + val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF); + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val); + sum += val; + + val = info_avi.db8_9_line_sofbottom & 0x00FF; + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val); + sum += val; + + val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF); + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val); + sum += val; + + val = info_avi.db10_11_pixel_eofleft & 0x00FF; + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val); + sum += val; + + val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF); + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val); + sum += val; + + val = info_avi.db12_13_pixel_sofright & 0x00FF; + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val); + sum += val; + + val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF); + hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val); + sum += val; + + checksum = 0x100 - sum; + hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum); +} + +static void hdmi_core_av_packet_config( + struct hdmi_core_packet_enable_repeat repeat_cfg) +{ + /* enable/repeat the infoframe */ + hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1, + (repeat_cfg.audio_pkt << 5) | + (repeat_cfg.audio_pkt_repeat << 4) | + (repeat_cfg.avi_infoframe << 1) | + (repeat_cfg.avi_infoframe_repeat)); + + /* enable/repeat the packet */ + hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2, + (repeat_cfg.gen_cntrl_pkt << 3) | + (repeat_cfg.gen_cntrl_pkt_repeat << 2) | + (repeat_cfg.generic_pkt << 1) | + (repeat_cfg.generic_pkt_repeat)); +} + +static void hdmi_wp_init(struct omap_video_timings *timings, + struct hdmi_video_format *video_fmt, + struct hdmi_video_interface *video_int) +{ + DSSDBG("Enter hdmi_wp_init\n"); + + timings->hbp = 0; + timings->hfp = 0; + timings->hsw = 0; + timings->vbp = 0; + timings->vfp = 0; + timings->vsw = 0; + + video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; + video_fmt->y_res = 0; + video_fmt->x_res = 0; + + video_int->vsp = 0; + video_int->hsp = 0; + + video_int->interlacing = 0; + video_int->tm = 0; /* HDMI_TIMING_SLAVE */ + +} + +static void hdmi_wp_video_start(bool start) +{ + REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31); +} + +static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, + struct omap_video_timings *timings, struct hdmi_config *param) +{ + DSSDBG("Enter hdmi_wp_video_init_format\n"); + + video_fmt->y_res = param->timings.timings.y_res; + video_fmt->x_res = param->timings.timings.x_res; + + timings->hbp = param->timings.timings.hbp; + timings->hfp = param->timings.timings.hfp; + timings->hsw = param->timings.timings.hsw; + timings->vbp = param->timings.timings.vbp; + timings->vfp = param->timings.timings.vfp; + timings->vsw = param->timings.timings.vsw; +} + +static void hdmi_wp_video_config_format( + struct hdmi_video_format *video_fmt) +{ + u32 l = 0; + + REG_FLD_MOD(HDMI_WP_VIDEO_CFG, video_fmt->packing_mode, 10, 8); + + l |= FLD_VAL(video_fmt->y_res, 31, 16); + l |= FLD_VAL(video_fmt->x_res, 15, 0); + hdmi_write_reg(HDMI_WP_VIDEO_SIZE, l); +} + +static void hdmi_wp_video_config_interface( + struct hdmi_video_interface *video_int) +{ + u32 r; + DSSDBG("Enter hdmi_wp_video_config_interface\n"); + + r = hdmi_read_reg(HDMI_WP_VIDEO_CFG); + r = FLD_MOD(r, video_int->vsp, 7, 7); + r = FLD_MOD(r, video_int->hsp, 6, 6); + r = FLD_MOD(r, video_int->interlacing, 3, 3); + r = FLD_MOD(r, video_int->tm, 1, 0); + hdmi_write_reg(HDMI_WP_VIDEO_CFG, r); +} + +static void hdmi_wp_video_config_timing( + struct omap_video_timings *timings) +{ + u32 timing_h = 0; + u32 timing_v = 0; + + DSSDBG("Enter hdmi_wp_video_config_timing\n"); + + timing_h |= FLD_VAL(timings->hbp, 31, 20); + timing_h |= FLD_VAL(timings->hfp, 19, 8); + timing_h |= FLD_VAL(timings->hsw, 7, 0); + hdmi_write_reg(HDMI_WP_VIDEO_TIMING_H, timing_h); + + timing_v |= FLD_VAL(timings->vbp, 31, 20); + timing_v |= FLD_VAL(timings->vfp, 19, 8); + timing_v |= FLD_VAL(timings->vsw, 7, 0); + hdmi_write_reg(HDMI_WP_VIDEO_TIMING_V, timing_v); +} + +static void hdmi_basic_configure(struct hdmi_config *cfg) +{ + /* HDMI */ + struct omap_video_timings video_timing; + struct hdmi_video_format video_format; + struct hdmi_video_interface video_interface; + /* HDMI core */ + struct hdmi_core_infoframe_avi avi_cfg; + struct hdmi_core_video_config v_core_cfg; + struct hdmi_core_packet_enable_repeat repeat_cfg; + + hdmi_wp_init(&video_timing, &video_format, + &video_interface); + + hdmi_core_init(&v_core_cfg, + &avi_cfg, + &repeat_cfg); + + hdmi_wp_video_init_format(&video_format, + &video_timing, cfg); + + hdmi_wp_video_config_timing(&video_timing); + + /* video config */ + video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422; + + hdmi_wp_video_config_format(&video_format); + + video_interface.vsp = cfg->timings.vsync_pol; + video_interface.hsp = cfg->timings.hsync_pol; + video_interface.interlacing = cfg->interlace; + video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */ + + hdmi_wp_video_config_interface(&video_interface); + + /* + * configure core video part + * set software reset in the core + */ + hdmi_core_swreset_assert(); + + /* power down off */ + hdmi_core_powerdown_disable(); + + v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL; + v_core_cfg.hdmi_dvi = cfg->cm.mode; + + hdmi_core_video_config(&v_core_cfg); + + /* release software reset in the core */ + hdmi_core_swreset_release(); + + /* + * configure packet + * info frame video see doc CEA861-D page 65 + */ + avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; + avi_cfg.db1_active_info = + HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; + avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; + avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; + avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; + avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; + avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; + avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; + avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; + avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; + avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; + avi_cfg.db4_videocode = cfg->cm.code; + avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; + avi_cfg.db6_7_line_eoftop = 0; + avi_cfg.db8_9_line_sofbottom = 0; + avi_cfg.db10_11_pixel_eofleft = 0; + avi_cfg.db12_13_pixel_sofright = 0; + + hdmi_core_aux_infoframe_avi_config(avi_cfg); + + /* enable/repeat the infoframe */ + repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; + repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; + /* wakeup */ + repeat_cfg.audio_pkt = HDMI_PACKETENABLE; + repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; + hdmi_core_av_packet_config(repeat_cfg); +} + +static void update_hdmi_timings(struct hdmi_config *cfg, + struct omap_video_timings *timings, int code) +{ + cfg->timings.timings.x_res = timings->x_res; + cfg->timings.timings.y_res = timings->y_res; + cfg->timings.timings.hbp = timings->hbp; + cfg->timings.timings.hfp = timings->hfp; + cfg->timings.timings.hsw = timings->hsw; + cfg->timings.timings.vbp = timings->vbp; + cfg->timings.timings.vfp = timings->vfp; + cfg->timings.timings.vsw = timings->vsw; + cfg->timings.timings.pixel_clock = timings->pixel_clock; + cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol; + cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol; +} + +static void hdmi_compute_pll(unsigned long clkin, int phy, + int n, struct hdmi_pll_info *pi) +{ + unsigned long refclk; + u32 mf; + + /* + * Input clock is predivided by N + 1 + * out put of which is reference clk + */ + refclk = clkin / (n + 1); + pi->regn = n; + + /* + * multiplier is pixel_clk/ref_clk + * Multiplying by 100 to avoid fractional part removal + */ + pi->regm = (phy * 100/(refclk))/100; + pi->regm2 = 1; + + /* + * fractional multiplier is remainder of the difference between + * multiplier and actual phy(required pixel clock thus should be + * multiplied by 2^18(262144) divided by the reference clock + */ + mf = (phy - pi->regm * refclk) * 262144; + pi->regmf = mf/(refclk); + + /* + * Dcofreq should be set to 1 if required pixel clock + * is greater than 1000MHz + */ + pi->dcofreq = phy > 1000 * 100; + pi->regsd = ((pi->regm * clkin / 10) / ((n + 1) * 250) + 5) / 10; + + DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf); + DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); +} + +static void hdmi_enable_clocks(int enable) +{ + if (enable) + dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK | + DSS_CLK_SYSCK | DSS_CLK_VIDFCK); + else + dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK | + DSS_CLK_SYSCK | DSS_CLK_VIDFCK); +} + +static int hdmi_power_on(struct omap_dss_device *dssdev) +{ + int r, code = 0; + struct hdmi_pll_info pll_data; + struct omap_video_timings *p; + int clkin, n, phy; + + hdmi_enable_clocks(1); + + dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); + + p = &dssdev->panel.timings; + + DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", + dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + + if (!hdmi.custom_set) { + DSSDBG("Read EDID as no EDID is not set on poweron\n"); + hdmi_read_edid(p); + } + code = get_timings_index(); + dssdev->panel.timings = cea_vesa_timings[code].timings; + update_hdmi_timings(&hdmi.cfg, p, code); + + clkin = 3840; /* 38.4 MHz */ + n = 15; /* this is a constant for our math */ + phy = p->pixel_clock; + + hdmi_compute_pll(clkin, phy, n, &pll_data); + + hdmi_wp_video_start(0); + + /* config the PLL and PHY first */ + r = hdmi_pll_program(&pll_data); + if (r) { + DSSDBG("Failed to lock PLL\n"); + goto err; + } + + r = hdmi_phy_init(); + if (r) { + DSSDBG("Failed to start PHY\n"); + goto err; + } + + hdmi.cfg.cm.mode = hdmi.mode; + hdmi.cfg.cm.code = hdmi.code; + hdmi_basic_configure(&hdmi.cfg); + + /* Make selection of HDMI in DSS */ + dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); + + /* Select the dispc clock source as PRCM clock, to ensure that it is not + * DSI PLL source as the clock selected by DSI PLL might not be + * sufficient for the resolution selected / that can be changed + * dynamically by user. This can be moved to single location , say + * Boardfile. + */ + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); + + /* bypass TV gamma table */ + dispc_enable_gamma_table(0); + + /* tv size */ + dispc_set_digit_size(dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + + dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1); + + hdmi_wp_video_start(1); + + return 0; +err: + hdmi_enable_clocks(0); + return -EIO; +} + +static void hdmi_power_off(struct omap_dss_device *dssdev) +{ + dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); + + hdmi_wp_video_start(0); + hdmi_phy_off(); + hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); + hdmi_enable_clocks(0); + + hdmi.edid_set = 0; +} + +int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + struct hdmi_cm cm; + + cm = hdmi_get_code(timings); + if (cm.code == -1) { + DSSERR("Invalid timing entered\n"); + return -EINVAL; + } + + return 0; + +} + +void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) +{ + struct hdmi_cm cm; + + hdmi.custom_set = 1; + cm = hdmi_get_code(&dssdev->panel.timings); + hdmi.code = cm.code; + hdmi.mode = cm.mode; + omapdss_hdmi_display_enable(dssdev); + hdmi.custom_set = 0; +} + +int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + + DSSDBG("ENTER hdmi_display_enable\n"); + + mutex_lock(&hdmi.lock); + + r = omap_dss_start_device(dssdev); + if (r) { + DSSERR("failed to start device\n"); + goto err0; + } + + if (dssdev->platform_enable) { + r = dssdev->platform_enable(dssdev); + if (r) { + DSSERR("failed to enable GPIO's\n"); + goto err1; + } + } + + r = hdmi_power_on(dssdev); + if (r) { + DSSERR("failed to power on device\n"); + goto err2; + } + + mutex_unlock(&hdmi.lock); + return 0; + +err2: + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); +err1: + omap_dss_stop_device(dssdev); +err0: + mutex_unlock(&hdmi.lock); + return r; +} + +void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) +{ + DSSDBG("Enter hdmi_display_disable\n"); + + mutex_lock(&hdmi.lock); + + hdmi_power_off(dssdev); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); + + omap_dss_stop_device(dssdev); + + mutex_unlock(&hdmi.lock); +} + +/* HDMI HW IP initialisation */ +static int omapdss_hdmihw_probe(struct platform_device *pdev) +{ + struct resource *hdmi_mem; + + hdmi.pdata = pdev->dev.platform_data; + hdmi.pdev = pdev; + + mutex_init(&hdmi.lock); + + hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); + if (!hdmi_mem) { + DSSERR("can't get IORESOURCE_MEM HDMI\n"); + return -EINVAL; + } + + /* Base address taken from platform */ + hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem)); + if (!hdmi.base_wp) { + DSSERR("can't ioremap WP\n"); + return -ENOMEM; + } + + hdmi_panel_init(); + + return 0; +} + +static int omapdss_hdmihw_remove(struct platform_device *pdev) +{ + hdmi_panel_exit(); + + iounmap(hdmi.base_wp); + + return 0; +} + +static struct platform_driver omapdss_hdmihw_driver = { + .probe = omapdss_hdmihw_probe, + .remove = omapdss_hdmihw_remove, + .driver = { + .name = "omapdss_hdmi", + .owner = THIS_MODULE, + }, +}; + +int hdmi_init_platform_driver(void) +{ + return platform_driver_register(&omapdss_hdmihw_driver); +} + +void hdmi_uninit_platform_driver(void) +{ + return platform_driver_unregister(&omapdss_hdmihw_driver); +} -- cgit v1.2.2 From 70be83235ea2815f6c2a5fd45753de406be6c6aa Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Thu, 10 Mar 2011 15:48:48 +0530 Subject: OMAP4: DSS2: HDMI: HDMI panel driver addition in the DSS The panel driver(hdmi_omap4_panel.c) in omap2/dss acts as a controller to manage the enable and disable requests and synchronize audio and video. Signed-off-by: Mythri P K Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.h | 2 + drivers/video/omap2/dss/hdmi_omap4_panel.c | 222 +++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 drivers/video/omap2/dss/hdmi_omap4_panel.c (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 91ed3fa8e60d..c2f582bb19c0 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -477,6 +477,8 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, struct omap_video_timings *timings); +int hdmi_panel_init(void); +void hdmi_panel_exit(void); /* RFBI */ #ifdef CONFIG_OMAP2_DSS_RFBI diff --git a/drivers/video/omap2/dss/hdmi_omap4_panel.c b/drivers/video/omap2/dss/hdmi_omap4_panel.c new file mode 100644 index 000000000000..ffb5de94131f --- /dev/null +++ b/drivers/video/omap2/dss/hdmi_omap4_panel.c @@ -0,0 +1,222 @@ +/* + * hdmi_omap4_panel.c + * + * HDMI library support functions for TI OMAP4 processors. + * + * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ + * Authors: Mythri P k + * + * 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. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "dss.h" + +static struct { + struct mutex hdmi_lock; +} hdmi; + + +static int hdmi_panel_probe(struct omap_dss_device *dssdev) +{ + DSSDBG("ENTER hdmi_panel_probe\n"); + + dssdev->panel.config = OMAP_DSS_LCD_TFT | + OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS; + + /* + * Initialize the timings to 640 * 480 + * This is only for framebuffer update not for TV timing setting + * Setting TV timing will be done only on enable + */ + dssdev->panel.timings.x_res = 640; + dssdev->panel.timings.y_res = 480; + + DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", + dssdev->panel.timings.x_res, + dssdev->panel.timings.y_res); + return 0; +} + +static void hdmi_panel_remove(struct omap_dss_device *dssdev) +{ + +} + +static int hdmi_panel_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + DSSDBG("ENTER hdmi_panel_enable\n"); + + mutex_lock(&hdmi.hdmi_lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { + r = -EINVAL; + goto err; + } + + r = omapdss_hdmi_display_enable(dssdev); + if (r) { + DSSERR("failed to power on\n"); + goto err; + } + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + +err: + mutex_unlock(&hdmi.hdmi_lock); + + return r; +} + +static void hdmi_panel_disable(struct omap_dss_device *dssdev) +{ + mutex_lock(&hdmi.hdmi_lock); + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) + omapdss_hdmi_display_disable(dssdev); + + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + + mutex_unlock(&hdmi.hdmi_lock); +} + +static int hdmi_panel_suspend(struct omap_dss_device *dssdev) +{ + int r = 0; + + mutex_lock(&hdmi.hdmi_lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { + r = -EINVAL; + goto err; + } + + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; + + omapdss_hdmi_display_disable(dssdev); + +err: + mutex_unlock(&hdmi.hdmi_lock); + + return r; +} + +static int hdmi_panel_resume(struct omap_dss_device *dssdev) +{ + int r = 0; + + mutex_lock(&hdmi.hdmi_lock); + + if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { + r = -EINVAL; + goto err; + } + + r = omapdss_hdmi_display_enable(dssdev); + if (r) { + DSSERR("failed to power on\n"); + goto err; + } + + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + +err: + mutex_unlock(&hdmi.hdmi_lock); + + return r; +} + +static void hdmi_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + mutex_lock(&hdmi.hdmi_lock); + + *timings = dssdev->panel.timings; + + mutex_unlock(&hdmi.hdmi_lock); +} + +static void hdmi_set_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + DSSDBG("hdmi_set_timings\n"); + + mutex_lock(&hdmi.hdmi_lock); + + dssdev->panel.timings = *timings; + + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { + /* turn the hdmi off and on to get new timings to use */ + omapdss_hdmi_display_disable(dssdev); + omapdss_hdmi_display_set_timing(dssdev); + } + + mutex_unlock(&hdmi.hdmi_lock); +} + +static int hdmi_check_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings) +{ + int r = 0; + + DSSDBG("hdmi_check_timings\n"); + + mutex_lock(&hdmi.hdmi_lock); + + r = omapdss_hdmi_display_check_timing(dssdev, timings); + if (r) { + DSSERR("Timing cannot be applied\n"); + goto err; + } +err: + mutex_unlock(&hdmi.hdmi_lock); + return r; +} + +static struct omap_dss_driver hdmi_driver = { + .probe = hdmi_panel_probe, + .remove = hdmi_panel_remove, + .enable = hdmi_panel_enable, + .disable = hdmi_panel_disable, + .suspend = hdmi_panel_suspend, + .resume = hdmi_panel_resume, + .get_timings = hdmi_get_timings, + .set_timings = hdmi_set_timings, + .check_timings = hdmi_check_timings, + .driver = { + .name = "hdmi_panel", + .owner = THIS_MODULE, + }, +}; + +int hdmi_panel_init(void) +{ + mutex_init(&hdmi.hdmi_lock); + + omap_dss_register_driver(&hdmi_driver); + + return 0; +} + +void hdmi_panel_exit(void) +{ + omap_dss_unregister_driver(&hdmi_driver); + +} -- cgit v1.2.2 From 642e21bff200610b1d4c0e706d0a6b16ae4e25db Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Thu, 10 Mar 2011 15:12:48 +0530 Subject: OMAP4: DSS2: HDMI: Add makefile and kconfig changes to enable HDMI in OMAP4 Adding kconfig and makefile changes to add support for HDMI in OMAP4. Signed-off-by: Mythri P K Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/Kconfig | 8 ++++++++ drivers/video/omap2/dss/Makefile | 2 ++ 2 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index db01473c3307..bfc5da0e9700 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig @@ -60,6 +60,14 @@ config OMAP2_DSS_VENC help OMAP Video Encoder support for S-Video and composite TV-out. +config OMAP4_DSS_HDMI + bool "HDMI support" + depends on ARCH_OMAP4 + default y + help + HDMI Interface. This adds the High Definition Multimedia Interface. + See http://www.hdmi.org/ for HDMI specification. + config OMAP2_DSS_SDI bool "SDI support" depends on ARCH_OMAP3 diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 7db17b5e570c..10d9d3bb3e24 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -5,3 +5,5 @@ omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o +omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ + hdmi_omap4_panel.o -- cgit v1.2.2 From adbc2feee11aef2b3b0f4eff427d2ea5c211e798 Mon Sep 17 00:00:00 2001 From: Mythri P K Date: Wed, 9 Mar 2011 15:40:02 +0530 Subject: OMAP4: DSS: HDMI: Call to HDMI module init to register driver. calling the platform registration of HDMI driver from core during initialization. Signed-off-by: Mythri P K Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index c2f930bf2844..1aa2ed1e786e 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c @@ -209,6 +209,12 @@ static int omap_dss_probe(struct platform_device *pdev) goto err_dsi; } + r = hdmi_init_platform_driver(); + if (r) { + DSSERR("Failed to initialize hdmi\n"); + goto err_hdmi; + } + r = dss_initialize_debugfs(); if (r) goto err_debugfs; @@ -238,6 +244,8 @@ static int omap_dss_probe(struct platform_device *pdev) err_register: dss_uninitialize_debugfs(); err_debugfs: + hdmi_uninit_platform_driver(); +err_hdmi: dsi_uninit_platform_driver(); err_dsi: venc_uninit_platform_driver(); @@ -263,6 +271,7 @@ static int omap_dss_remove(struct platform_device *pdev) dispc_uninit_platform_driver(); rfbi_uninit_platform_driver(); dsi_uninit_platform_driver(); + hdmi_uninit_platform_driver(); dss_uninit_platform_driver(); dss_uninit_overlays(pdev); -- cgit v1.2.2 From 64dcddd888998f7db9929e19fc063e75e3ea21f5 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Tue, 15 Mar 2011 22:32:39 -0700 Subject: Input: tca6416-keypad - suspend/resume wakeup support Extend the tca6416 driver to use enable_irq_wake() and disable_irq_wake() in the suspend/resume hooks. This makes it possible to wake up from suspend-to-ram using a tca6416 key on the sh7372 mackerel board. Signed-off-by: Magnus Damm Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca6416-keypad.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 800fbccf1f0f..3afea3f89718 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -297,6 +297,7 @@ static int __devinit tca6416_keypad_probe(struct i2c_client *client, } i2c_set_clientdata(client, chip); + device_init_wakeup(&client->dev, 1); return 0; @@ -326,10 +327,37 @@ static int __devexit tca6416_keypad_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM_SLEEP +static int tca6416_keypad_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev)) + enable_irq_wake(chip->irqnum); + + return 0; +} + +static int tca6416_keypad_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev)) + disable_irq_wake(chip->irqnum); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops, + tca6416_keypad_suspend, tca6416_keypad_resume); static struct i2c_driver tca6416_keypad_driver = { .driver = { .name = "tca6416-keypad", + .pm = &tca6416_keypad_dev_pm_ops, }, .probe = tca6416_keypad_probe, .remove = __devexit_p(tca6416_keypad_remove), -- cgit v1.2.2 From 53a2b81c4e659d894aadc56715c8d8a9afa60d67 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 15 Mar 2011 23:18:00 -0700 Subject: Input: tc3589x-keypad - fix 'double const' warning Also rearrange driver structure initializer a bit. Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tc3589x-keypad.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index dbbe761778d2..99122f59e988 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -402,7 +402,7 @@ static int __devexit tc3589x_keypad_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int tc3589x_keypad_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); @@ -439,19 +439,19 @@ static int tc3589x_keypad_resume(struct device *dev) return 0; } - -static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, - tc3589x_keypad_suspend, tc3589x_keypad_resume); #endif +static SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops, + tc3589x_keypad_suspend, tc3589x_keypad_resume); + static struct platform_driver tc3589x_keypad_driver = { - .driver.name = "tc3589x-keypad", - .driver.owner = THIS_MODULE, -#ifdef CONFIG_PM - .driver.pm = &tc3589x_keypad_dev_pm_ops, -#endif - .probe = tc3589x_keypad_probe, - .remove = __devexit_p(tc3589x_keypad_remove), + .driver = { + .name = "tc3589x-keypad", + .owner = THIS_MODULE, + .pm = &tc3589x_keypad_dev_pm_ops, + }, + .probe = tc3589x_keypad_probe, + .remove = __devexit_p(tc3589x_keypad_remove), }; static int __init tc3589x_keypad_init(void) -- cgit v1.2.2 From e593106ca409e5e37d18121d922fc4f449c60d41 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Jan 2011 18:40:49 +0100 Subject: ARM: pxa: Use gpio arrays in colibri_pcmcia driver Use gpio_request_array() / gpio_free_array(), this makes the code cleaner and less error prone. Signed-off-by: Marek Vasut --- drivers/pcmcia/pxa2xx_colibri.c | 133 +++++++++++++++------------------------- 1 file changed, 49 insertions(+), 84 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_colibri.c b/drivers/pcmcia/pxa2xx_colibri.c index a52039564e74..443cb7fc872d 100644 --- a/drivers/pcmcia/pxa2xx_colibri.c +++ b/drivers/pcmcia/pxa2xx_colibri.c @@ -34,14 +34,24 @@ #define COLIBRI320_DETECT_GPIO 81 #define COLIBRI320_READY_GPIO 29 -static struct { - int reset_gpio; - int ppen_gpio; - int bvd1_gpio; - int bvd2_gpio; - int detect_gpio; - int ready_gpio; -} colibri_pcmcia_gpio; +enum { + DETECT = 0, + READY = 1, + BVD1 = 2, + BVD2 = 3, + PPEN = 4, + RESET = 5, +}; + +/* Contents of this array are configured on-the-fly in init function */ +static struct gpio colibri_pcmcia_gpios[] = { + { 0, GPIOF_IN, "PCMCIA Detect" }, + { 0, GPIOF_IN, "PCMCIA Ready" }, + { 0, GPIOF_IN, "PCMCIA BVD1" }, + { 0, GPIOF_IN, "PCMCIA BVD2" }, + { 0, GPIOF_INIT_LOW, "PCMCIA PPEN" }, + { 0, GPIOF_INIT_HIGH,"PCMCIA Reset" }, +}; static struct pcmcia_irqs colibri_irqs[] = { { @@ -54,88 +64,42 @@ static int colibri_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; - ret = gpio_request(colibri_pcmcia_gpio.detect_gpio, "DETECT"); + ret = gpio_request_array(colibri_pcmcia_gpios, + ARRAY_SIZE(colibri_pcmcia_gpios)); if (ret) goto err1; - ret = gpio_direction_input(colibri_pcmcia_gpio.detect_gpio); - if (ret) - goto err2; - - ret = gpio_request(colibri_pcmcia_gpio.ready_gpio, "READY"); - if (ret) - goto err2; - ret = gpio_direction_input(colibri_pcmcia_gpio.ready_gpio); - if (ret) - goto err3; - ret = gpio_request(colibri_pcmcia_gpio.bvd1_gpio, "BVD1"); - if (ret) - goto err3; - ret = gpio_direction_input(colibri_pcmcia_gpio.bvd1_gpio); - if (ret) - goto err4; + colibri_irqs[0].irq = gpio_to_irq(colibri_pcmcia_gpios[DETECT].gpio); + skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpios[READY].gpio); - ret = gpio_request(colibri_pcmcia_gpio.bvd2_gpio, "BVD2"); - if (ret) - goto err4; - ret = gpio_direction_input(colibri_pcmcia_gpio.bvd2_gpio); - if (ret) - goto err5; - - ret = gpio_request(colibri_pcmcia_gpio.ppen_gpio, "PPEN"); - if (ret) - goto err5; - ret = gpio_direction_output(colibri_pcmcia_gpio.ppen_gpio, 0); - if (ret) - goto err6; - - ret = gpio_request(colibri_pcmcia_gpio.reset_gpio, "RESET"); - if (ret) - goto err6; - ret = gpio_direction_output(colibri_pcmcia_gpio.reset_gpio, 1); + ret = soc_pcmcia_request_irqs(skt, colibri_irqs, + ARRAY_SIZE(colibri_irqs)); if (ret) - goto err7; - - colibri_irqs[0].irq = gpio_to_irq(colibri_pcmcia_gpio.detect_gpio); - skt->socket.pci_irq = gpio_to_irq(colibri_pcmcia_gpio.ready_gpio); + goto err2; - return soc_pcmcia_request_irqs(skt, colibri_irqs, - ARRAY_SIZE(colibri_irqs)); + return ret; -err7: - gpio_free(colibri_pcmcia_gpio.detect_gpio); -err6: - gpio_free(colibri_pcmcia_gpio.ready_gpio); -err5: - gpio_free(colibri_pcmcia_gpio.bvd1_gpio); -err4: - gpio_free(colibri_pcmcia_gpio.bvd2_gpio); -err3: - gpio_free(colibri_pcmcia_gpio.reset_gpio); err2: - gpio_free(colibri_pcmcia_gpio.ppen_gpio); + gpio_free_array(colibri_pcmcia_gpios, + ARRAY_SIZE(colibri_pcmcia_gpios)); err1: return ret; } static void colibri_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - gpio_free(colibri_pcmcia_gpio.detect_gpio); - gpio_free(colibri_pcmcia_gpio.ready_gpio); - gpio_free(colibri_pcmcia_gpio.bvd1_gpio); - gpio_free(colibri_pcmcia_gpio.bvd2_gpio); - gpio_free(colibri_pcmcia_gpio.reset_gpio); - gpio_free(colibri_pcmcia_gpio.ppen_gpio); + gpio_free_array(colibri_pcmcia_gpios, + ARRAY_SIZE(colibri_pcmcia_gpios)); } static void colibri_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) { - state->detect = !!gpio_get_value(colibri_pcmcia_gpio.detect_gpio); - state->ready = !!gpio_get_value(colibri_pcmcia_gpio.ready_gpio); - state->bvd1 = !!gpio_get_value(colibri_pcmcia_gpio.bvd1_gpio); - state->bvd2 = !!gpio_get_value(colibri_pcmcia_gpio.bvd2_gpio); + state->detect = !!gpio_get_value(colibri_pcmcia_gpios[DETECT].gpio); + state->ready = !!gpio_get_value(colibri_pcmcia_gpios[READY].gpio); + state->bvd1 = !!gpio_get_value(colibri_pcmcia_gpios[BVD1].gpio); + state->bvd2 = !!gpio_get_value(colibri_pcmcia_gpios[BVD2].gpio); state->wrprot = 0; state->vs_3v = 1; state->vs_Xv = 0; @@ -145,9 +109,10 @@ static int colibri_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { - gpio_set_value(colibri_pcmcia_gpio.ppen_gpio, + gpio_set_value(colibri_pcmcia_gpios[PPEN].gpio, !(state->Vcc == 33 && state->Vpp < 50)); - gpio_set_value(colibri_pcmcia_gpio.reset_gpio, state->flags & SS_RESET); + gpio_set_value(colibri_pcmcia_gpios[RESET].gpio, + state->flags & SS_RESET); return 0; } @@ -190,20 +155,20 @@ static int __init colibri_pcmcia_init(void) /* Colibri PXA270 */ if (machine_is_colibri()) { - colibri_pcmcia_gpio.reset_gpio = COLIBRI270_RESET_GPIO; - colibri_pcmcia_gpio.ppen_gpio = COLIBRI270_PPEN_GPIO; - colibri_pcmcia_gpio.bvd1_gpio = COLIBRI270_BVD1_GPIO; - colibri_pcmcia_gpio.bvd2_gpio = COLIBRI270_BVD2_GPIO; - colibri_pcmcia_gpio.detect_gpio = COLIBRI270_DETECT_GPIO; - colibri_pcmcia_gpio.ready_gpio = COLIBRI270_READY_GPIO; + colibri_pcmcia_gpios[RESET].gpio = COLIBRI270_RESET_GPIO; + colibri_pcmcia_gpios[PPEN].gpio = COLIBRI270_PPEN_GPIO; + colibri_pcmcia_gpios[BVD1].gpio = COLIBRI270_BVD1_GPIO; + colibri_pcmcia_gpios[BVD2].gpio = COLIBRI270_BVD2_GPIO; + colibri_pcmcia_gpios[DETECT].gpio = COLIBRI270_DETECT_GPIO; + colibri_pcmcia_gpios[READY].gpio = COLIBRI270_READY_GPIO; /* Colibri PXA320 */ } else if (machine_is_colibri320()) { - colibri_pcmcia_gpio.reset_gpio = COLIBRI320_RESET_GPIO; - colibri_pcmcia_gpio.ppen_gpio = COLIBRI320_PPEN_GPIO; - colibri_pcmcia_gpio.bvd1_gpio = COLIBRI320_BVD1_GPIO; - colibri_pcmcia_gpio.bvd2_gpio = COLIBRI320_BVD2_GPIO; - colibri_pcmcia_gpio.detect_gpio = COLIBRI320_DETECT_GPIO; - colibri_pcmcia_gpio.ready_gpio = COLIBRI320_READY_GPIO; + colibri_pcmcia_gpios[RESET].gpio = COLIBRI320_RESET_GPIO; + colibri_pcmcia_gpios[PPEN].gpio = COLIBRI320_PPEN_GPIO; + colibri_pcmcia_gpios[BVD1].gpio = COLIBRI320_BVD1_GPIO; + colibri_pcmcia_gpios[BVD2].gpio = COLIBRI320_BVD2_GPIO; + colibri_pcmcia_gpios[DETECT].gpio = COLIBRI320_DETECT_GPIO; + colibri_pcmcia_gpios[READY].gpio = COLIBRI320_READY_GPIO; } ret = platform_device_add_data(colibri_pcmcia_device, -- cgit v1.2.2 From 2070417dffa9e75b370a5c0dee8c5dc3605e1c4d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Jan 2011 18:49:07 +0100 Subject: ARM: pxa: Use gpio arrays in palmld_pcmcia driver Use gpio_request_array() / gpio_free_array(), this makes the code cleaner and less error prone. Signed-off-by: Marek Vasut --- drivers/pcmcia/pxa2xx_palmld.c | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c index 6fb6f7f0672e..59f84053ebf9 100644 --- a/drivers/pcmcia/pxa2xx_palmld.c +++ b/drivers/pcmcia/pxa2xx_palmld.c @@ -20,49 +20,27 @@ #include #include "soc_common.h" +static struct gpio palmld_pcmcia_gpios[] = { + { GPIO_NR_PALMLD_PCMCIA_POWER, GPIOF_INIT_LOW, "PCMCIA Power" }, + { GPIO_NR_PALMLD_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" }, + { GPIO_NR_PALMLD_PCMCIA_READY, GPIOF_IN, "PCMCIA Ready" }, +}; + static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; - ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_POWER, "PCMCIA PWR"); - if (ret) - goto err1; - ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_POWER, 0); - if (ret) - goto err2; - - ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_RESET, "PCMCIA RST"); - if (ret) - goto err2; - ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_RESET, 1); - if (ret) - goto err3; - - ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_READY, "PCMCIA RDY"); - if (ret) - goto err3; - ret = gpio_direction_input(GPIO_NR_PALMLD_PCMCIA_READY); - if (ret) - goto err4; + ret = gpio_request_array(palmld_pcmcia_gpios, + ARRAY_SIZE(palmld_pcmcia_gpios)); skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMLD_PCMCIA_READY); - return 0; -err4: - gpio_free(GPIO_NR_PALMLD_PCMCIA_READY); -err3: - gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET); -err2: - gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER); -err1: return ret; } static void palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - gpio_free(GPIO_NR_PALMLD_PCMCIA_READY); - gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET); - gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER); + gpio_free_array(palmld_pcmcia_gpios, ARRAY_SIZE(palmld_pcmcia_gpios)); } static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt, -- cgit v1.2.2 From ba388307946cf86050d63cd398b4b341e2fb5043 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Jan 2011 18:59:43 +0100 Subject: ARM: pxa: Use gpio arrays in palmtc_pcmcia driver Use gpio_request_array() / gpio_free_array(), this makes the code cleaner and less error prone. Signed-off-by: Marek Vasut --- drivers/pcmcia/pxa2xx_palmtc.c | 73 +++++++----------------------------------- 1 file changed, 12 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_palmtc.c b/drivers/pcmcia/pxa2xx_palmtc.c index 459a232d66be..e655af98dbcd 100644 --- a/drivers/pcmcia/pxa2xx_palmtc.c +++ b/drivers/pcmcia/pxa2xx_palmtc.c @@ -21,79 +21,30 @@ #include #include "soc_common.h" +static struct gpio palmtc_pcmcia_gpios[] = { + { GPIO_NR_PALMTC_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" }, + { GPIO_NR_PALMTC_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" }, + { GPIO_NR_PALMTC_PCMCIA_POWER3, GPIOF_INIT_LOW, "PCMCIA Power 3" }, + { GPIO_NR_PALMTC_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" }, + { GPIO_NR_PALMTC_PCMCIA_READY, GPIOF_IN, "PCMCIA Ready" }, + { GPIO_NR_PALMTC_PCMCIA_PWRREADY, GPIOF_IN, "PCMCIA Power Ready" }, +}; + static int palmtc_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; - ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER1, "PCMCIA PWR1"); - if (ret) - goto err1; - ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER1, 0); - if (ret) - goto err2; - - ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER2, "PCMCIA PWR2"); - if (ret) - goto err2; - ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER2, 0); - if (ret) - goto err3; - - ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_POWER3, "PCMCIA PWR3"); - if (ret) - goto err3; - ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_POWER3, 0); - if (ret) - goto err4; - - ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_RESET, "PCMCIA RST"); - if (ret) - goto err4; - ret = gpio_direction_output(GPIO_NR_PALMTC_PCMCIA_RESET, 1); - if (ret) - goto err5; - - ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_READY, "PCMCIA RDY"); - if (ret) - goto err5; - ret = gpio_direction_input(GPIO_NR_PALMTC_PCMCIA_READY); - if (ret) - goto err6; - - ret = gpio_request(GPIO_NR_PALMTC_PCMCIA_PWRREADY, "PCMCIA PWRRDY"); - if (ret) - goto err6; - ret = gpio_direction_input(GPIO_NR_PALMTC_PCMCIA_PWRREADY); - if (ret) - goto err7; + ret = gpio_request_array(palmtc_pcmcia_gpios, + ARRAY_SIZE(palmtc_pcmcia_gpios)); skt->socket.pci_irq = IRQ_GPIO(GPIO_NR_PALMTC_PCMCIA_READY); - return 0; -err7: - gpio_free(GPIO_NR_PALMTC_PCMCIA_PWRREADY); -err6: - gpio_free(GPIO_NR_PALMTC_PCMCIA_READY); -err5: - gpio_free(GPIO_NR_PALMTC_PCMCIA_RESET); -err4: - gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER3); -err3: - gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER2); -err2: - gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER1); -err1: return ret; } static void palmtc_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - gpio_free(GPIO_NR_PALMTC_PCMCIA_PWRREADY); - gpio_free(GPIO_NR_PALMTC_PCMCIA_READY); - gpio_free(GPIO_NR_PALMTC_PCMCIA_RESET); - gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER3); - gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER2); - gpio_free(GPIO_NR_PALMTC_PCMCIA_POWER1); + gpio_free_array(palmtc_pcmcia_gpios, ARRAY_SIZE(palmtc_pcmcia_gpios)); } static void palmtc_pcmcia_socket_state(struct soc_pcmcia_socket *skt, -- cgit v1.2.2 From 235a175c401ab2d79d63f08257acebe1558a0621 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Jan 2011 18:59:55 +0100 Subject: ARM: pxa: Use gpio arrays in palmtx_pcmcia driver Use gpio_request_array() / gpio_free_array(), this makes the code cleaner and less error prone. Signed-off-by: Marek Vasut --- drivers/pcmcia/pxa2xx_palmtx.c | 55 +++++++++--------------------------------- 1 file changed, 11 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_palmtx.c b/drivers/pcmcia/pxa2xx_palmtx.c index b07b247a399f..06f7f141543b 100644 --- a/drivers/pcmcia/pxa2xx_palmtx.c +++ b/drivers/pcmcia/pxa2xx_palmtx.c @@ -13,67 +13,34 @@ #include #include +#include #include - -#include #include - #include "soc_common.h" +static struct gpio palmtx_pcmcia_gpios[] = { + { GPIO_NR_PALMTX_PCMCIA_POWER1, GPIOF_INIT_LOW, "PCMCIA Power 1" }, + { GPIO_NR_PALMTX_PCMCIA_POWER2, GPIOF_INIT_LOW, "PCMCIA Power 2" }, + { GPIO_NR_PALMTX_PCMCIA_RESET, GPIOF_INIT_HIGH,"PCMCIA Reset" }, + { GPIO_NR_PALMTX_PCMCIA_READY, GPIOF_IN, "PCMCIA Ready" }, +}; + static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { int ret; - ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_POWER1, "PCMCIA PWR1"); - if (ret) - goto err1; - ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_POWER1, 0); - if (ret) - goto err2; - - ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_POWER2, "PCMCIA PWR2"); - if (ret) - goto err2; - ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_POWER2, 0); - if (ret) - goto err3; - - ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_RESET, "PCMCIA RST"); - if (ret) - goto err3; - ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_RESET, 1); - if (ret) - goto err4; - - ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_READY, "PCMCIA RDY"); - if (ret) - goto err4; - ret = gpio_direction_input(GPIO_NR_PALMTX_PCMCIA_READY); - if (ret) - goto err5; + ret = gpio_request_array(palmtx_pcmcia_gpios, + ARRAY_SIZE(palmtx_pcmcia_gpios)); skt->socket.pci_irq = gpio_to_irq(GPIO_NR_PALMTX_PCMCIA_READY); - return 0; -err5: - gpio_free(GPIO_NR_PALMTX_PCMCIA_READY); -err4: - gpio_free(GPIO_NR_PALMTX_PCMCIA_RESET); -err3: - gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER2); -err2: - gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER1); -err1: return ret; } static void palmtx_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - gpio_free(GPIO_NR_PALMTX_PCMCIA_READY); - gpio_free(GPIO_NR_PALMTX_PCMCIA_RESET); - gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER2); - gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER1); + gpio_free_array(palmtx_pcmcia_gpios, ARRAY_SIZE(palmtx_pcmcia_gpios)); } static void palmtx_pcmcia_socket_state(struct soc_pcmcia_socket *skt, -- cgit v1.2.2 From e27af7edda008d225ad542c3b6645483683a7e91 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Jan 2011 19:11:16 +0100 Subject: ARM: pxa: Use gpio arrays in vpac270_pcmcia driver Use gpio_request_array() / gpio_free_array(), this makes the code cleaner and less error prone. Signed-off-by: Marek Vasut --- drivers/pcmcia/pxa2xx_vpac270.c | 107 +++++++++++----------------------------- 1 file changed, 29 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c index 55627eccee8e..c13f4111e334 100644 --- a/drivers/pcmcia/pxa2xx_vpac270.c +++ b/drivers/pcmcia/pxa2xx_vpac270.c @@ -22,6 +22,19 @@ #include "soc_common.h" +static struct gpio vpac270_pcmcia_gpios[] = { + { GPIO84_VPAC270_PCMCIA_CD, GPIOF_IN, "PCMCIA Card Detect" }, + { GPIO35_VPAC270_PCMCIA_RDY, GPIOF_IN, "PCMCIA Ready" }, + { GPIO107_VPAC270_PCMCIA_PPEN, GPIOF_INIT_LOW, "PCMCIA PPEN" }, + { GPIO11_VPAC270_PCMCIA_RESET, GPIOF_INIT_LOW, "PCMCIA Reset" }, +}; + +static struct gpio vpac270_cf_gpios[] = { + { GPIO17_VPAC270_CF_CD, GPIOF_IN, "CF Card Detect" }, + { GPIO12_VPAC270_CF_RDY, GPIOF_IN, "CF Ready" }, + { GPIO16_VPAC270_CF_RESET, GPIOF_INIT_LOW, "CF Reset" }, +}; + static struct pcmcia_irqs cd_irqs[] = { { .sock = 0, @@ -40,96 +53,34 @@ static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt) int ret; if (skt->nr == 0) { - ret = gpio_request(GPIO84_VPAC270_PCMCIA_CD, "PCMCIA CD"); - if (ret) - goto err1; - ret = gpio_direction_input(GPIO84_VPAC270_PCMCIA_CD); - if (ret) - goto err2; - - ret = gpio_request(GPIO35_VPAC270_PCMCIA_RDY, "PCMCIA RDY"); - if (ret) - goto err2; - ret = gpio_direction_input(GPIO35_VPAC270_PCMCIA_RDY); - if (ret) - goto err3; - - ret = gpio_request(GPIO107_VPAC270_PCMCIA_PPEN, "PCMCIA PPEN"); - if (ret) - goto err3; - ret = gpio_direction_output(GPIO107_VPAC270_PCMCIA_PPEN, 0); - if (ret) - goto err4; - - ret = gpio_request(GPIO11_VPAC270_PCMCIA_RESET, "PCMCIA RESET"); - if (ret) - goto err4; - ret = gpio_direction_output(GPIO11_VPAC270_PCMCIA_RESET, 0); - if (ret) - goto err5; + ret = gpio_request_array(vpac270_pcmcia_gpios, + ARRAY_SIZE(vpac270_pcmcia_gpios)); skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY); - return soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1); - -err5: - gpio_free(GPIO11_VPAC270_PCMCIA_RESET); -err4: - gpio_free(GPIO107_VPAC270_PCMCIA_PPEN); -err3: - gpio_free(GPIO35_VPAC270_PCMCIA_RDY); -err2: - gpio_free(GPIO84_VPAC270_PCMCIA_CD); -err1: - return ret; - + if (!ret) + ret = soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1); } else { - ret = gpio_request(GPIO17_VPAC270_CF_CD, "CF CD"); - if (ret) - goto err6; - ret = gpio_direction_input(GPIO17_VPAC270_CF_CD); - if (ret) - goto err7; - - ret = gpio_request(GPIO12_VPAC270_CF_RDY, "CF RDY"); - if (ret) - goto err7; - ret = gpio_direction_input(GPIO12_VPAC270_CF_RDY); - if (ret) - goto err8; - - ret = gpio_request(GPIO16_VPAC270_CF_RESET, "CF RESET"); - if (ret) - goto err8; - ret = gpio_direction_output(GPIO16_VPAC270_CF_RESET, 0); - if (ret) - goto err9; + ret = gpio_request_array(vpac270_cf_gpios, + ARRAY_SIZE(vpac270_cf_gpios)); skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY); - return soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1); - -err9: - gpio_free(GPIO16_VPAC270_CF_RESET); -err8: - gpio_free(GPIO12_VPAC270_CF_RDY); -err7: - gpio_free(GPIO17_VPAC270_CF_CD); -err6: - return ret; - + if (!ret) + ret = soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1); } + + return ret; } static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - gpio_free(GPIO11_VPAC270_PCMCIA_RESET); - gpio_free(GPIO107_VPAC270_PCMCIA_PPEN); - gpio_free(GPIO35_VPAC270_PCMCIA_RDY); - gpio_free(GPIO84_VPAC270_PCMCIA_CD); - gpio_free(GPIO16_VPAC270_CF_RESET); - gpio_free(GPIO12_VPAC270_CF_RDY); - gpio_free(GPIO17_VPAC270_CF_CD); + if (skt->nr == 0) + gpio_request_array(vpac270_pcmcia_gpios, + ARRAY_SIZE(vpac270_pcmcia_gpios)); + else + gpio_request_array(vpac270_cf_gpios, + ARRAY_SIZE(vpac270_cf_gpios)); } static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt, -- cgit v1.2.2 From 6b1e3fca6ffb981db05688b1660a5d03d242edd4 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Jan 2011 19:19:05 +0100 Subject: ARM: pxa: Use gpio arrays in palmld_hdd driver Use gpio_request_array() / gpio_free_array(), this makes the code cleaner and less error prone. This patch also properly frees GPIOs in case ata_host_activate() call fails. Signed-off-by: Marek Vasut --- drivers/ata/pata_palmld.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c index 11fb4ccc74b4..fecf527e8366 100644 --- a/drivers/ata/pata_palmld.c +++ b/drivers/ata/pata_palmld.c @@ -33,6 +33,11 @@ #define DRV_NAME "pata_palmld" +static struct gpio palmld_hdd_gpios[] = { + { GPIO_NR_PALMLD_IDE_PWEN, GPIOF_INIT_HIGH, "HDD Power" }, + { GPIO_NR_PALMLD_IDE_RESET, GPIOF_INIT_LOW, "HDD Reset" }, +}; + static struct scsi_host_template palmld_sht = { ATA_PIO_SHT(DRV_NAME), }; @@ -52,28 +57,23 @@ static __devinit int palmld_pata_probe(struct platform_device *pdev) /* allocate host */ host = ata_host_alloc(&pdev->dev, 1); - if (!host) - return -ENOMEM; + if (!host) { + ret = -ENOMEM; + goto err1; + } /* remap drive's physical memory address */ mem = devm_ioremap(&pdev->dev, PALMLD_IDE_PHYS, 0x1000); - if (!mem) - return -ENOMEM; + if (!mem) { + ret = -ENOMEM; + goto err1; + } /* request and activate power GPIO, IRQ GPIO */ - ret = gpio_request(GPIO_NR_PALMLD_IDE_PWEN, "HDD PWR"); + ret = gpio_request_array(palmld_hdd_gpios, + ARRAY_SIZE(palmld_hdd_gpios)); if (ret) goto err1; - ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_PWEN, 1); - if (ret) - goto err2; - - ret = gpio_request(GPIO_NR_PALMLD_IDE_RESET, "HDD RST"); - if (ret) - goto err2; - ret = gpio_direction_output(GPIO_NR_PALMLD_IDE_RESET, 0); - if (ret) - goto err3; /* reset the drive */ gpio_set_value(GPIO_NR_PALMLD_IDE_RESET, 0); @@ -96,13 +96,15 @@ static __devinit int palmld_pata_probe(struct platform_device *pdev) ata_sff_std_ports(&ap->ioaddr); /* activate host */ - return ata_host_activate(host, 0, NULL, IRQF_TRIGGER_RISING, + ret = ata_host_activate(host, 0, NULL, IRQF_TRIGGER_RISING, &palmld_sht); + if (ret) + goto err2; + + return ret; -err3: - gpio_free(GPIO_NR_PALMLD_IDE_RESET); err2: - gpio_free(GPIO_NR_PALMLD_IDE_PWEN); + gpio_free_array(palmld_hdd_gpios, ARRAY_SIZE(palmld_hdd_gpios)); err1: return ret; } @@ -116,8 +118,7 @@ static __devexit int palmld_pata_remove(struct platform_device *dev) /* power down the HDD */ gpio_set_value(GPIO_NR_PALMLD_IDE_PWEN, 0); - gpio_free(GPIO_NR_PALMLD_IDE_RESET); - gpio_free(GPIO_NR_PALMLD_IDE_PWEN); + gpio_free_array(palmld_hdd_gpios, ARRAY_SIZE(palmld_hdd_gpios)); return 0; } -- cgit v1.2.2 From 9ed3fbf1cbc2b747b3532985059f4738c15f4c07 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 15 Jan 2011 19:22:19 +0100 Subject: ARM: pxa: Update copyright notices for Palm devices Signed-off-by: Marek Vasut --- drivers/pcmcia/pxa2xx_palmld.c | 2 +- drivers/pcmcia/pxa2xx_palmtc.c | 2 +- drivers/pcmcia/pxa2xx_palmtx.c | 2 +- drivers/pcmcia/pxa2xx_vpac270.c | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c index 59f84053ebf9..69f73670949a 100644 --- a/drivers/pcmcia/pxa2xx_palmld.c +++ b/drivers/pcmcia/pxa2xx_palmld.c @@ -4,7 +4,7 @@ * Driver for Palm LifeDrive PCMCIA * * Copyright (C) 2006 Alex Osborne - * Copyright (C) 2007-2008 Marek Vasut + * Copyright (C) 2007-2011 Marek Vasut * * 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 diff --git a/drivers/pcmcia/pxa2xx_palmtc.c b/drivers/pcmcia/pxa2xx_palmtc.c index e655af98dbcd..d0ad6a76bbde 100644 --- a/drivers/pcmcia/pxa2xx_palmtc.c +++ b/drivers/pcmcia/pxa2xx_palmtc.c @@ -4,7 +4,7 @@ * Driver for Palm Tungsten|C PCMCIA * * Copyright (C) 2008 Alex Osborne - * Copyright (C) 2009 Marek Vasut + * Copyright (C) 2009-2011 Marek Vasut * * 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 diff --git a/drivers/pcmcia/pxa2xx_palmtx.c b/drivers/pcmcia/pxa2xx_palmtx.c index 06f7f141543b..1a2580450402 100644 --- a/drivers/pcmcia/pxa2xx_palmtx.c +++ b/drivers/pcmcia/pxa2xx_palmtx.c @@ -3,7 +3,7 @@ * * Driver for Palm T|X PCMCIA * - * Copyright (C) 2007-2008 Marek Vasut + * Copyright (C) 2007-2011 Marek Vasut * * 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 diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c index c13f4111e334..435002dfc3ca 100644 --- a/drivers/pcmcia/pxa2xx_vpac270.c +++ b/drivers/pcmcia/pxa2xx_vpac270.c @@ -3,8 +3,7 @@ * * Driver for Voipac PXA270 PCMCIA and CF sockets * - * Copyright (C) 2010 - * Marek Vasut + * Copyright (C) 2010-2011 Marek Vasut * * 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 -- cgit v1.2.2 From a8ecc860ef117f9405758d8d1378553afcdd9ca3 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 14 Feb 2011 15:33:19 +0300 Subject: ARM: pxa25x_udc: stop handling gpio-vbus internally Stop handling gpio-vbus internally. All boards that depended on this functionality have been converted to use gpio-vbus tranceiver. All new boards can use it right from the start. Drop unused code. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Eric Miao --- drivers/usb/gadget/pxa25x_udc.c | 76 ++++------------------------------------- 1 file changed, 7 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index b37f92cb71bc..444b60aa15e9 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -139,24 +139,6 @@ static const char ep0name [] = "ep0"; static void pxa25x_ep_fifo_flush (struct usb_ep *ep); static void nuke (struct pxa25x_ep *, int status); -/* one GPIO should be used to detect VBUS from the host */ -static int is_vbus_present(void) -{ - struct pxa2xx_udc_mach_info *mach = the_controller->mach; - - if (gpio_is_valid(mach->gpio_vbus)) { - int value = gpio_get_value(mach->gpio_vbus); - - if (mach->gpio_vbus_inverted) - return !value; - else - return !!value; - } - if (mach->udc_is_connected) - return mach->udc_is_connected(); - return 1; -} - /* one GPIO should control a D+ pullup, so host sees this device (or not) */ static void pullup_off(void) { @@ -1055,7 +1037,7 @@ udc_seq_show(struct seq_file *m, void *_d) "%s version: %s\nGadget driver: %s\nHost %s\n\n", driver_name, DRIVER_VERSION SIZE_STR "(pio)", dev->driver ? dev->driver->driver.name : "(none)", - is_vbus_present() ? "full speed" : "disconnected"); + dev->gadget.speed == USB_SPEED_FULL ? "full speed" : "disconnected"); /* registers for device and ep0 */ seq_printf(m, @@ -1094,7 +1076,7 @@ udc_seq_show(struct seq_file *m, void *_d) (tmp & UDCCFR_ACM) ? " acm" : ""); } - if (!is_vbus_present() || !dev->driver) + if (dev->gadget.speed != USB_SPEED_FULL || !dev->driver) goto done; seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n", @@ -1435,14 +1417,6 @@ lubbock_vbus_irq(int irq, void *_dev) #endif -static irqreturn_t udc_vbus_irq(int irq, void *_dev) -{ - struct pxa25x_udc *dev = _dev; - - pxa25x_udc_vbus_session(&dev->gadget, is_vbus_present()); - return IRQ_HANDLED; -} - /*-------------------------------------------------------------------------*/ @@ -1766,12 +1740,9 @@ pxa25x_udc_irq(int irq, void *_dev) if (unlikely(udccr & UDCCR_SUSIR)) { udc_ack_int_UDCCR(UDCCR_SUSIR); handled = 1; - DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present() - ? "" : "+disconnect"); + DBG(DBG_VERBOSE, "USB suspend\n"); - if (!is_vbus_present()) - stop_activity(dev, dev->driver); - else if (dev->gadget.speed != USB_SPEED_UNKNOWN + if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->suspend) dev->driver->suspend(&dev->gadget); @@ -1786,8 +1757,7 @@ pxa25x_udc_irq(int irq, void *_dev) if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver - && dev->driver->resume - && is_vbus_present()) + && dev->driver->resume) dev->driver->resume(&dev->gadget); } @@ -2137,7 +2107,7 @@ static struct pxa25x_udc memory = { static int __init pxa25x_udc_probe(struct platform_device *pdev) { struct pxa25x_udc *dev = &memory; - int retval, vbus_irq, irq; + int retval, irq; u32 chiprev; /* insist on Intel/ARM/XScale */ @@ -2199,19 +2169,6 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) dev->transceiver = otg_get_transceiver(); - if (gpio_is_valid(dev->mach->gpio_vbus)) { - if ((retval = gpio_request(dev->mach->gpio_vbus, - "pxa25x_udc GPIO VBUS"))) { - dev_dbg(&pdev->dev, - "can't get vbus gpio %d, err: %d\n", - dev->mach->gpio_vbus, retval); - goto err_gpio_vbus; - } - gpio_direction_input(dev->mach->gpio_vbus); - vbus_irq = gpio_to_irq(dev->mach->gpio_vbus); - } else - vbus_irq = 0; - if (gpio_is_valid(dev->mach->gpio_pullup)) { if ((retval = gpio_request(dev->mach->gpio_pullup, "pca25x_udc GPIO PULLUP"))) { @@ -2237,7 +2194,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev) udc_disable(dev); udc_reinit(dev); - dev->vbus = !!is_vbus_present(); + dev->vbus = 0; /* irq setup after old hardware state is cleaned up */ retval = request_irq(irq, pxa25x_udc_irq, @@ -2273,22 +2230,10 @@ lubbock_fail0: } } else #endif - if (vbus_irq) { - retval = request_irq(vbus_irq, udc_vbus_irq, - IRQF_DISABLED | IRQF_SAMPLE_RANDOM | - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - driver_name, dev); - if (retval != 0) { - pr_err("%s: can't get irq %i, err %d\n", - driver_name, vbus_irq, retval); - goto err_vbus_irq; - } - } create_debug_files(dev); return 0; - err_vbus_irq: #ifdef CONFIG_ARCH_LUBBOCK free_irq(LUBBOCK_USB_DISC_IRQ, dev); err_irq_lub: @@ -2298,9 +2243,6 @@ lubbock_fail0: if (gpio_is_valid(dev->mach->gpio_pullup)) gpio_free(dev->mach->gpio_pullup); err_gpio_pullup: - if (gpio_is_valid(dev->mach->gpio_vbus)) - gpio_free(dev->mach->gpio_vbus); - err_gpio_vbus: if (dev->transceiver) { otg_put_transceiver(dev->transceiver); dev->transceiver = NULL; @@ -2337,10 +2279,6 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev) free_irq(LUBBOCK_USB_IRQ, dev); } #endif - if (gpio_is_valid(dev->mach->gpio_vbus)) { - free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev); - gpio_free(dev->mach->gpio_vbus); - } if (gpio_is_valid(dev->mach->gpio_pullup)) gpio_free(dev->mach->gpio_pullup); -- cgit v1.2.2 From 1b98d7c4491e5eaba7c403ec1bc5997e6596e569 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Fri, 11 Mar 2011 11:20:47 +0200 Subject: ARM: pxafb: rework pxafb overlay memory management PXAFB overlay memory management is something messy: - it allocates memory dynamically on open/release, and it results in memory allocation failure after ~1h of uptime (system does not have 115k of physically contiguous memory) - in release callback it tries to free memory even if it was not allocated. Also driver touches FDADR1 on main plane reconfiguration, and it can cause problems if overlay1 is enabled. This patch attempts to fix those issues. Patch is based on Russell King's work. Signed-off-by: Vasily Khoruzhick Signed-off-by: Eric Miao --- drivers/video/pxafb.c | 121 ++++++++++++++++++++++++++++++++------------------ drivers/video/pxafb.h | 3 +- 2 files changed, 81 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 825b665245bb..0764759a2eed 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -627,7 +627,12 @@ static void overlay1fb_enable(struct pxafb_layer *ofb) static void overlay1fb_disable(struct pxafb_layer *ofb) { - uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5); + uint32_t lccr5; + + if (!(lcd_readl(ofb->fbi, OVL1C1) & OVLxC1_OEN)) + return; + + lccr5 = lcd_readl(ofb->fbi, LCCR5); lcd_writel(ofb->fbi, OVL1C1, ofb->control[0] & ~OVLxC1_OEN); @@ -685,7 +690,12 @@ static void overlay2fb_enable(struct pxafb_layer *ofb) static void overlay2fb_disable(struct pxafb_layer *ofb) { - uint32_t lccr5 = lcd_readl(ofb->fbi, LCCR5); + uint32_t lccr5; + + if (!(lcd_readl(ofb->fbi, OVL2C1) & OVLxC1_OEN)) + return; + + lccr5 = lcd_readl(ofb->fbi, LCCR5); lcd_writel(ofb->fbi, OVL2C1, ofb->control[0] & ~OVLxC1_OEN); @@ -720,12 +730,10 @@ static int overlayfb_open(struct fb_info *info, int user) if (user == 0) return -ENODEV; - /* allow only one user at a time */ - if (atomic_inc_and_test(&ofb->usage)) - return -EBUSY; + if (ofb->usage++ == 0) + /* unblank the base framebuffer */ + fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK); - /* unblank the base framebuffer */ - fb_blank(&ofb->fbi->fb, FB_BLANK_UNBLANK); return 0; } @@ -733,12 +741,15 @@ static int overlayfb_release(struct fb_info *info, int user) { struct pxafb_layer *ofb = (struct pxafb_layer*) info; - atomic_dec(&ofb->usage); - ofb->ops->disable(ofb); + if (ofb->usage == 1) { + ofb->ops->disable(ofb); + ofb->fb.var.height = -1; + ofb->fb.var.width = -1; + ofb->fb.var.xres = ofb->fb.var.xres_virtual = 0; + ofb->fb.var.yres = ofb->fb.var.yres_virtual = 0; - free_pages_exact(ofb->video_mem, ofb->video_mem_size); - ofb->video_mem = NULL; - ofb->video_mem_size = 0; + ofb->usage--; + } return 0; } @@ -794,7 +805,7 @@ static int overlayfb_check_var(struct fb_var_screeninfo *var, return 0; } -static int overlayfb_map_video_memory(struct pxafb_layer *ofb) +static int overlayfb_check_video_memory(struct pxafb_layer *ofb) { struct fb_var_screeninfo *var = &ofb->fb.var; int pfor = NONSTD_TO_PFOR(var->nonstd); @@ -812,27 +823,11 @@ static int overlayfb_map_video_memory(struct pxafb_layer *ofb) size = PAGE_ALIGN(ofb->fb.fix.line_length * var->yres_virtual); - /* don't re-allocate if the original video memory is enough */ if (ofb->video_mem) { if (ofb->video_mem_size >= size) return 0; - - free_pages_exact(ofb->video_mem, ofb->video_mem_size); } - - ofb->video_mem = alloc_pages_exact(size, GFP_KERNEL | __GFP_ZERO); - if (ofb->video_mem == NULL) - return -ENOMEM; - - ofb->video_mem_phys = virt_to_phys(ofb->video_mem); - ofb->video_mem_size = size; - - mutex_lock(&ofb->fb.mm_lock); - ofb->fb.fix.smem_start = ofb->video_mem_phys; - ofb->fb.fix.smem_len = ofb->fb.fix.line_length * var->yres_virtual; - mutex_unlock(&ofb->fb.mm_lock); - ofb->fb.screen_base = ofb->video_mem; - return 0; + return -EINVAL; } static int overlayfb_set_par(struct fb_info *info) @@ -841,7 +836,7 @@ static int overlayfb_set_par(struct fb_info *info) struct fb_var_screeninfo *var = &info->var; int xpos, ypos, pfor, bpp, ret; - ret = overlayfb_map_video_memory(ofb); + ret = overlayfb_check_video_memory(ofb); if (ret) return ret; @@ -891,7 +886,7 @@ static void __devinit init_pxafb_overlay(struct pxafb_info *fbi, ofb->id = id; ofb->ops = &ofb_ops[id]; - atomic_set(&ofb->usage, 0); + ofb->usage = 0; ofb->fbi = fbi; init_completion(&ofb->branch_done); } @@ -904,20 +899,54 @@ static inline int pxafb_overlay_supported(void) return 0; } -static int __devinit pxafb_overlay_init(struct pxafb_info *fbi) +static int __devinit pxafb_overlay_map_video_memory(struct pxafb_info *pxafb, + struct pxafb_layer *ofb) +{ + /* We assume that user will use at most video_mem_size for overlay fb, + * anyway, it's useless to use 16bpp main plane and 24bpp overlay + */ + ofb->video_mem = alloc_pages_exact(PAGE_ALIGN(pxafb->video_mem_size), + GFP_KERNEL | __GFP_ZERO); + if (ofb->video_mem == NULL) + return -ENOMEM; + + ofb->video_mem_phys = virt_to_phys(ofb->video_mem); + ofb->video_mem_size = PAGE_ALIGN(pxafb->video_mem_size); + + mutex_lock(&ofb->fb.mm_lock); + ofb->fb.fix.smem_start = ofb->video_mem_phys; + ofb->fb.fix.smem_len = pxafb->video_mem_size; + mutex_unlock(&ofb->fb.mm_lock); + + ofb->fb.screen_base = ofb->video_mem; + + return 0; +} + +static void __devinit pxafb_overlay_init(struct pxafb_info *fbi) { int i, ret; if (!pxafb_overlay_supported()) - return 0; + return; for (i = 0; i < 2; i++) { - init_pxafb_overlay(fbi, &fbi->overlay[i], i); - ret = register_framebuffer(&fbi->overlay[i].fb); + struct pxafb_layer *ofb = &fbi->overlay[i]; + init_pxafb_overlay(fbi, ofb, i); + ret = register_framebuffer(&ofb->fb); if (ret) { dev_err(fbi->dev, "failed to register overlay %d\n", i); - return ret; + continue; + } + ret = pxafb_overlay_map_video_memory(fbi, ofb); + if (ret) { + dev_err(fbi->dev, + "failed to map video memory for overlay %d\n", + i); + unregister_framebuffer(&ofb->fb); + continue; } + ofb->registered = 1; } /* mask all IU/BS/EOF/SOF interrupts */ @@ -926,7 +955,6 @@ static int __devinit pxafb_overlay_init(struct pxafb_info *fbi) /* place overlay(s) on top of base */ fbi->lccr0 |= LCCR0_OUC; pr_info("PXA Overlay driver loaded successfully!\n"); - return 0; } static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi) @@ -936,8 +964,15 @@ static void __devexit pxafb_overlay_exit(struct pxafb_info *fbi) if (!pxafb_overlay_supported()) return; - for (i = 0; i < 2; i++) - unregister_framebuffer(&fbi->overlay[i].fb); + for (i = 0; i < 2; i++) { + struct pxafb_layer *ofb = &fbi->overlay[i]; + if (ofb->registered) { + if (ofb->video_mem) + free_pages_exact(ofb->video_mem, + ofb->video_mem_size); + unregister_framebuffer(&ofb->fb); + } + } } #else static inline void pxafb_overlay_init(struct pxafb_info *fbi) {} @@ -1368,7 +1403,8 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) || (lcd_readl(fbi, LCCR4) != fbi->reg_lccr4) || (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) || - (lcd_readl(fbi, FDADR1) != fbi->fdadr[1])) + ((fbi->lccr0 & LCCR0_SDS) && + (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))) pxafb_schedule_work(fbi, C_REENABLE); return 0; @@ -1420,7 +1456,8 @@ static void pxafb_enable_controller(struct pxafb_info *fbi) lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB); lcd_writel(fbi, FDADR0, fbi->fdadr[0]); - lcd_writel(fbi, FDADR1, fbi->fdadr[1]); + if (fbi->lccr0 & LCCR0_SDS) + lcd_writel(fbi, FDADR1, fbi->fdadr[1]); lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB); } diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index 2353521c5c8c..26ba9fa3f737 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h @@ -92,7 +92,8 @@ struct pxafb_layer_ops { struct pxafb_layer { struct fb_info fb; int id; - atomic_t usage; + int registered; + uint32_t usage; uint32_t control[2]; struct pxafb_layer_ops *ops; -- cgit v1.2.2 From 7779cee3f45122d2f81397f55d7a14f654a0b276 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Fri, 11 Mar 2011 11:20:48 +0200 Subject: ARM: pxafb: fix plane Z-ordering problem pxafb_overlay_init is not right place to change Z-ordering, move it to main plane initialization. Signed-off-by: Vasily Khoruzhick Signed-off-by: Eric Miao --- drivers/video/pxafb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 0764759a2eed..e2f643ef9516 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -952,8 +952,6 @@ static void __devinit pxafb_overlay_init(struct pxafb_info *fbi) /* mask all IU/BS/EOF/SOF interrupts */ lcd_writel(fbi, LCCR5, ~0); - /* place overlay(s) on top of base */ - fbi->lccr0 |= LCCR0_OUC; pr_info("PXA Overlay driver loaded successfully!\n"); } @@ -1843,6 +1841,12 @@ static struct pxafb_info * __devinit pxafb_init_fbinfo(struct device *dev) pxafb_decode_mach_info(fbi, inf); +#ifdef CONFIG_FB_PXA_OVERLAY + /* place overlay(s) on top of base */ + if (pxafb_overlay_supported()) + fbi->lccr0 |= LCCR0_OUC; +#endif + init_waitqueue_head(&fbi->ctrlr_wait); INIT_WORK(&fbi->task, pxafb_task); mutex_init(&fbi->ctrlr_lock); -- cgit v1.2.2 From dcf8eee94f7eb2671e6d5774e81d45ad06b4f980 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Fri, 11 Mar 2011 11:20:49 +0200 Subject: ARM: pxafb: fix typo in ypos assignment Sascha Hauer pointed that ypos takes value of xpos due to typo. Signed-off-by: Vasily Khoruzhick Signed-off-by: Eric Miao --- drivers/video/pxafb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index e2f643ef9516..a3bdcc152671 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -761,7 +761,7 @@ static int overlayfb_check_var(struct fb_var_screeninfo *var, int xpos, ypos, pfor, bpp; xpos = NONSTD_TO_XPOS(var->nonstd); - ypos = NONSTD_TO_XPOS(var->nonstd); + ypos = NONSTD_TO_YPOS(var->nonstd); pfor = NONSTD_TO_PFOR(var->nonstd); bpp = pxafb_var_to_bpp(var); @@ -842,7 +842,7 @@ static int overlayfb_set_par(struct fb_info *info) bpp = pxafb_var_to_bpp(var); xpos = NONSTD_TO_XPOS(var->nonstd); - ypos = NONSTD_TO_XPOS(var->nonstd); + ypos = NONSTD_TO_YPOS(var->nonstd); pfor = NONSTD_TO_PFOR(var->nonstd); ofb->control[0] = OVLxC1_PPL(var->xres) | OVLxC1_LPO(var->yres) | -- cgit v1.2.2 From 27be9a9e378dad166fc81df310e052e7b67cb667 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Fri, 11 Mar 2011 11:20:50 +0200 Subject: ARM: pxafb: don't disable controller on cpufreq transition if overlay in use It's not safe to disable controller if overlay(s) is enabled (results in system hang). So we avoid to disable controller in this case. Userspace should choose proper governor to avoid freq changing when overlay is in use, otherwise LCD may blink. Signed-off-by: Vasily Khoruzhick Signed-off-by: Eric Miao --- drivers/video/pxafb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index a3bdcc152671..a2e5b5100ab4 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -1648,7 +1648,8 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) switch (val) { case CPUFREQ_PRECHANGE: - set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); + if (!fbi->overlay[0].usage && !fbi->overlay[1].usage) + set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); break; case CPUFREQ_POSTCHANGE: -- cgit v1.2.2 From f8d878ddbb3c08bc2f876975df674484208536ac Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 14 Mar 2011 21:12:39 +0100 Subject: s3c_adc_battery: Fix method names when PM not set s3c_adc_battery declares wrong method names when CONFIG_PM is not set. Signed-off-by: Heiko Stuebner Acked-by: Vasily Khoruzhick Signed-off-by: Anton Vorontsov --- drivers/power/s3c_adc_battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index 4255f2358b13..d36c289aaef5 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c @@ -406,8 +406,8 @@ static int s3c_adc_bat_resume(struct platform_device *pdev) return 0; } #else -#define s3c_adc_battery_suspend NULL -#define s3c_adc_battery_resume NULL +#define s3c_adc_bat_suspend NULL +#define s3c_adc_bat_resume NULL #endif static struct platform_driver s3c_adc_bat_driver = { -- cgit v1.2.2 From a223246f7280422f77c15b71455fe3362d3604b4 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Fri, 11 Mar 2011 15:09:32 +0200 Subject: z2_battery: Fix count of properties PROP_STATUS property was not counted, as result VOLTAGE_MIN property is missing in sysfs. Fix it. Signed-off-by: Vasily Khoruzhick Acked-by: Marek Vasut Signed-off-by: Anton Vorontsov --- drivers/power/z2_battery.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index 81304c0bb9d3..2a9ab89f83b8 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c @@ -134,6 +134,8 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props) enum power_supply_property *prop; struct z2_battery_info *info = charger->info; + if (info->charge_gpio >= 0) + props++; /* POWER_SUPPLY_PROP_STATUS */ if (info->batt_tech >= 0) props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */ if (info->batt_I2C_reg >= 0) -- cgit v1.2.2 From a7d9ace4eb3a6a3c3fcb12fb05510c1893808263 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Wed, 9 Mar 2011 16:18:02 -0800 Subject: bq20z75: Fix issues with present and suspend There are a few issues found around the battery not being present. If the battery isn't present, then a few undesirable things happen. The first was excessive reporting of failed properties. This was fixed by instead returning ENODATA for all properties other than PRESENT if the battery isn't present. That way the callers can identify the difference between a failure and the battery not being there. The next issue was in the suspend logic. It was found that if the battery wasn't present, then it would return a failure, preventing the system from going into suspend. If there is no battery present, the io is expected to fail, so in that case, we shouldn't return the failure and just acknowledge that it was expected. I also found that when a gpio was used, i didn't maintain the internal is_present state properly. I added a set of that to fix that. Lastly, the code to see io's fail and figure out that the battery isn't present when not using a gpio had a problem. In that code, it looked for the read to fail and if it did, then handled it. The problem is that in function to get the property, it first writes a value and that write can fail, causing the code to never reach the logic after the read. Fix is to move the logic till after the write. Signed-off-by: Rhyland Klein Signed-off-by: Anton Vorontsov --- drivers/power/bq20z75.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index 8018e8cc7a74..5615c92bef66 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c @@ -171,7 +171,7 @@ static int bq20z75_read_word_data(struct i2c_client *client, u8 address) } if (ret < 0) { - dev_warn(&client->dev, + dev_dbg(&client->dev, "%s: i2c read at address 0x%x failed\n", __func__, address); return ret; @@ -199,7 +199,7 @@ static int bq20z75_write_word_data(struct i2c_client *client, u8 address, } if (ret < 0) { - dev_warn(&client->dev, + dev_dbg(&client->dev, "%s: i2c write to address 0x%x failed\n", __func__, address); return ret; @@ -223,6 +223,7 @@ static int bq20z75_get_battery_presence_and_health( val->intval = 1; else val->intval = 0; + bq20z75_device->is_present = val->intval; return ret; } @@ -232,18 +233,17 @@ static int bq20z75_get_battery_presence_and_health( ret = bq20z75_write_word_data(client, bq20z75_data[REG_MANUFACTURER_DATA].addr, MANUFACTURER_ACCESS_STATUS); - if (ret < 0) - return ret; - - - ret = bq20z75_read_word_data(client, - bq20z75_data[REG_MANUFACTURER_DATA].addr); if (ret < 0) { if (psp == POWER_SUPPLY_PROP_PRESENT) val->intval = 0; /* battery removed */ return ret; } + ret = bq20z75_read_word_data(client, + bq20z75_data[REG_MANUFACTURER_DATA].addr); + if (ret < 0) + return ret; + if (ret < bq20z75_data[REG_MANUFACTURER_DATA].min_value || ret > bq20z75_data[REG_MANUFACTURER_DATA].max_value) { val->intval = 0; @@ -455,6 +455,8 @@ static int bq20z75_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_HEALTH: ret = bq20z75_get_battery_presence_and_health(client, psp, val); + if (psp == POWER_SUPPLY_PROP_PRESENT) + return 0; break; case POWER_SUPPLY_PROP_TECHNOLOGY: @@ -516,9 +518,16 @@ done: } dev_dbg(&client->dev, - "%s: property = %d, value = %d\n", __func__, psp, val->intval); + "%s: property = %d, value = %x\n", __func__, psp, val->intval); + + if (ret && bq20z75_device->is_present) + return ret; + + /* battery not present, so return NODATA for properties */ + if (ret) + return -ENODATA; - return ret; + return 0; } static irqreturn_t bq20z75_irq(int irq, void *devid) @@ -643,13 +652,14 @@ static int __devexit bq20z75_remove(struct i2c_client *client) static int bq20z75_suspend(struct i2c_client *client, pm_message_t state) { + struct bq20z75_info *bq20z75_device = i2c_get_clientdata(client); s32 ret; /* write to manufacturer access with sleep command */ ret = bq20z75_write_word_data(client, bq20z75_data[REG_MANUFACTURER_DATA].addr, MANUFACTURER_ACCESS_SLEEP); - if (ret < 0) + if (bq20z75_device->is_present && ret < 0) return ret; return 0; -- cgit v1.2.2 From 909a78b320b31ca9709d7ea5f602ec1bd2015192 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Sun, 27 Feb 2011 17:41:48 -0800 Subject: bq20z75: Fix time and temp units MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrected temperature and time to empty/full conversions. Temperature is in 0.1°C, time is in seconds. Corrected units in comment. "Convert to µWh." Signed-off-by: Benson Leung Acked-by: Rhyland Klein Signed-off-by: Anton Vorontsov --- drivers/power/bq20z75.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/power/bq20z75.c b/drivers/power/bq20z75.c index 5615c92bef66..506585e31a5b 100644 --- a/drivers/power/bq20z75.c +++ b/drivers/power/bq20z75.c @@ -318,12 +318,15 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, { #define BASE_UNIT_CONVERSION 1000 #define BATTERY_MODE_CAP_MULT_WATT (10 * BASE_UNIT_CONVERSION) -#define TIME_UNIT_CONVERSION 600 -#define TEMP_KELVIN_TO_CELCIUS 2731 +#define TIME_UNIT_CONVERSION 60 +#define TEMP_KELVIN_TO_CELSIUS 2731 switch (psp) { case POWER_SUPPLY_PROP_ENERGY_NOW: case POWER_SUPPLY_PROP_ENERGY_FULL: case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: + /* bq20z75 provides energy in units of 10mWh. + * Convert to µWh + */ val->intval *= BATTERY_MODE_CAP_MULT_WATT; break; @@ -337,14 +340,17 @@ static void bq20z75_unit_adjustment(struct i2c_client *client, break; case POWER_SUPPLY_PROP_TEMP: - /* bq20z75 provides battery tempreture in 0.1°K - * so convert it to 0.1°C */ - val->intval -= TEMP_KELVIN_TO_CELCIUS; - val->intval *= 10; + /* bq20z75 provides battery temperature in 0.1K + * so convert it to 0.1°C + */ + val->intval -= TEMP_KELVIN_TO_CELSIUS; break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: + /* bq20z75 provides time to empty and time to full in minutes. + * Convert to seconds + */ val->intval *= TIME_UNIT_CONVERSION; break; -- cgit v1.2.2 From 2f94e55ae5ddad83e661002985d2ea11b6d51d3d Mon Sep 17 00:00:00 2001 From: Philip Rakity Date: Sun, 13 Feb 2011 23:12:28 -0800 Subject: mmc: core: comment on why sdio_reset is done at init time sdio_reset sends a CMD52 to reset the sdio card. This is highly recommended for sdio cards being reinitialized. Since we do not know if the card is being reinitialized we just send the command. SD/eMMC cards are supposed to ignore the CMD before the CMD0. Document why we are doing this. Signed-off-by: Philip Rakity Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 2af2ee1a2265..c47e13b79eee 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1494,6 +1494,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) mmc_hostname(host), __func__, host->f_init); #endif mmc_power_up(host); + + /* + * sdio_reset sends CMD52 to reset card. Since we do not know + * if the card is being re-initialized, just send it. CMD52 + * should be ignored by SD/eMMC cards. + */ sdio_reset(host); mmc_go_idle(host); -- cgit v1.2.2 From b676f0391a5f6816c047cbd1e2ad2a897f3c161a Mon Sep 17 00:00:00 2001 From: Philip Rakity Date: Sun, 13 Feb 2011 23:13:09 -0800 Subject: mmc: check if mmc cards < 2GB do sector addressing Some TOSHIBA MMC cards only support sector addressing even though the size is < 2GB. According to JEDEC Spec JESD84-A441-1 the ocr register (bits 30, 29) determine byte/sector mode. Use them. Signed-off-by: Philip Rakity Signed-off-by: Chris Ball --- drivers/mmc/core/mmc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6396c5d98e85..14e95f39a7bf 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -421,6 +421,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, int err, ddr = 0; u32 cid[4]; unsigned int max_dtr; + u32 rocr; BUG_ON(!host); WARN_ON(!host->claimed); @@ -434,7 +435,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_go_idle(host); /* The extra bit indicates that we support high capacity */ - err = mmc_send_op_cond(host, ocr | (1 << 30), NULL); + err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr); if (err) goto err; @@ -522,6 +523,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_read_ext_csd(card); if (err) goto free_card; + + /* If doing byte addressing, check if required to do sector + * addressing. Handle the case of <2GB cards needing sector + * addressing. See section 8.1 JEDEC Standard JED84-A441; + * ocr register has bit 30 set for sector addressing. + */ + if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30))) + mmc_card_set_blockaddr(card); + /* Erase size depends on CSD and Extended CSD */ mmc_set_erase_size(card); } -- cgit v1.2.2 From f5e0cec4495398b259b3ede7cbc3ce4bd0e1cef0 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 25 Feb 2011 16:58:38 +0100 Subject: mmc: sh_mmcif: support aggressive clock gating To support MMC aggressive clock gating the driver has to stop the interface clock when the .set_ios() method is called with .clock == 0. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index aea86262ed66..af97015a2fc7 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -844,15 +844,15 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct sh_mmcif_host *host = mmc_priv(mmc); struct sh_mmcif_plat_data *p = host->pd->dev.platform_data; - if (ios->power_mode == MMC_POWER_OFF) { + if (ios->power_mode == MMC_POWER_UP) { + if (p->set_pwr) + p->set_pwr(host->pd, ios->power_mode); + } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { /* clock stop */ sh_mmcif_clock_control(host, 0); - if (p->down_pwr) + if (ios->power_mode == MMC_POWER_OFF && p->down_pwr) p->down_pwr(host->pd); return; - } else if (ios->power_mode == MMC_POWER_UP) { - if (p->set_pwr) - p->set_pwr(host->pd, ios->power_mode); } if (ios->clock) -- cgit v1.2.2 From 726abbc7957a2feeaf6f5e3d72579b3fd0211134 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Wed, 16 Mar 2011 16:31:32 +0000 Subject: viafb: refresh rate bug collection This patch fixes multiple issues with the handling of refresh rates especially for multi-display setups. If you experienced problems with wrong refresh rates this patch might fix them. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/chip.h | 1 - drivers/video/via/hw.c | 17 +++++++---------- drivers/video/via/hw.h | 3 +-- drivers/video/via/viafbdev.c | 45 +++++++++++++++++++++++++++----------------- 4 files changed, 36 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h index 781f3aa66b42..29d70244a21f 100644 --- a/drivers/video/via/chip.h +++ b/drivers/video/via/chip.h @@ -139,7 +139,6 @@ struct chip_information { struct crt_setting_information { int iga_path; - int refresh_rate; }; struct tmds_setting_information { diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 5728fd76bc11..dc4c778877ce 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2002,13 +2002,15 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, int i; int index = 0; int h_addr, v_addr; - u32 pll_D_N, clock; + u32 pll_D_N, clock, refresh = viafb_refresh; + + if (viafb_SAMM_ON && set_iga == IGA2) + refresh = viafb_refresh1; for (i = 0; i < video_mode->mode_array; i++) { index = i; - if (crt_table[i].refresh_rate == viaparinfo-> - crt_setting_info->refresh_rate) + if (crt_table[i].refresh_rate == refresh) break; } @@ -2019,7 +2021,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, if ((viafb_LCD_ON | viafb_DVI_ON) && video_mode->crtc[0].crtc.hor_addr == 640 && video_mode->crtc[0].crtc.ver_addr == 480 - && viaparinfo->crt_setting_info->refresh_rate == 60) { + && refresh == 60) { /* The border is 8 pixels. */ crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8; @@ -2070,7 +2072,6 @@ void __devinit viafb_init_chip_info(int chip_type) init_lvds_chip_info(); viaparinfo->crt_setting_info->iga_path = IGA1; - viaparinfo->crt_setting_info->refresh_rate = viafb_refresh; /*Set IGA path for each device */ viafb_set_iga_path(); @@ -2083,13 +2084,9 @@ void __devinit viafb_init_chip_info(int chip_type) viaparinfo->lvds_setting_info->lcd_mode; } -void viafb_update_device_setting(int hres, int vres, - int bpp, int vmode_refresh, int flag) +void viafb_update_device_setting(int hres, int vres, int bpp, int flag) { if (flag == 0) { - viaparinfo->crt_setting_info->refresh_rate = - vmode_refresh; - viaparinfo->tmds_setting_info->h_active = hres; viaparinfo->tmds_setting_info->v_active = vres; diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 7295263299f7..8858593405aa 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -949,8 +949,7 @@ void __devinit viafb_init_chip_info(int chip_type); void __devinit viafb_init_dac(int set_iga); int viafb_get_pixclock(int hres, int vres, int vmode_refresh); int viafb_get_refresh(int hres, int vres, u32 float_refresh); -void viafb_update_device_setting(int hres, int vres, int bpp, - int vmode_refresh, int flag); +void viafb_update_device_setting(int hres, int vres, int bpp, int flag); void viafb_set_iga_path(void); void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index f555b891cc72..fd6a15f0decd 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -182,13 +182,24 @@ static int viafb_release(struct fb_info *info, int user) return 0; } +static inline int get_var_refresh(struct fb_var_screeninfo *var) +{ + u32 htotal, vtotal; + + htotal = var->left_margin + var->xres + var->right_margin + + var->hsync_len; + vtotal = var->upper_margin + var->yres + var->lower_margin + + var->vsync_len; + return PICOS2KHZ(var->pixclock) * 1000 / (htotal * vtotal); +} + static int viafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { - int htotal, vtotal, depth; + int depth, refresh; struct VideoModeTable *vmode_entry; struct viafb_par *ppar = info->par; - u32 long_refresh, line; + u32 line; DEBUG_MSG(KERN_INFO "viafb_check_var!\n"); /* Sanity check */ @@ -231,17 +242,11 @@ static int viafb_check_var(struct fb_var_screeninfo *var, /* Based on var passed in to calculate the refresh, * because our driver use some modes special. */ - htotal = var->xres + var->left_margin + - var->right_margin + var->hsync_len; - vtotal = var->yres + var->upper_margin + - var->lower_margin + var->vsync_len; - long_refresh = 1000000000UL / var->pixclock * 1000; - long_refresh /= (htotal * vtotal); - - viafb_refresh = viafb_get_refresh(var->xres, var->yres, long_refresh); + refresh = viafb_get_refresh(var->xres, var->yres, + get_var_refresh(var)); /* Adjust var according to our driver's own table */ - viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry); + viafb_fill_var_timing_info(var, refresh, vmode_entry); if (var->accel_flags & FB_ACCELF_TEXT && !ppar->shared->vdev->engine_mmio) var->accel_flags = 0; @@ -253,12 +258,13 @@ static int viafb_set_par(struct fb_info *info) { struct viafb_par *viapar = info->par; struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL; + int refresh; DEBUG_MSG(KERN_INFO "viafb_set_par!\n"); viafb_update_fix(info); viapar->depth = fb_get_color_depth(&info->var, &info->fix); viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres, - viafbinfo->var.bits_per_pixel, viafb_refresh, 0); + viafbinfo->var.bits_per_pixel, 0); vmode_entry = viafb_get_mode(viafbinfo->var.xres, viafbinfo->var.yres); if (viafb_dual_fb) { @@ -266,7 +272,7 @@ static int viafb_set_par(struct fb_info *info) viafbinfo1->var.yres); viafb_update_device_setting(viafbinfo1->var.xres, viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel, - viafb_refresh1, 1); + 1); } else if (viafb_SAMM_ON == 1) { DEBUG_MSG(KERN_INFO "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n", @@ -275,14 +281,19 @@ static int viafb_set_par(struct fb_info *info) viafb_second_yres); viafb_update_device_setting(viafb_second_xres, - viafb_second_yres, viafb_bpp1, viafb_refresh1, 1); + viafb_second_yres, viafb_bpp1, 1); } + refresh = viafb_get_refresh(info->var.xres, info->var.yres, + get_var_refresh(&info->var)); if (vmode_entry) { - if (viafb_dual_fb && viapar->iga_path == IGA2) + if (viafb_dual_fb && viapar->iga_path == IGA2) { viafb_bpp1 = info->var.bits_per_pixel; - else + viafb_refresh1 = refresh; + } else { viafb_bpp = info->var.bits_per_pixel; + viafb_refresh = refresh; + } if (info->var.accel_flags & FB_ACCELF_TEXT) info->flags &= ~FBINFO_HWACCEL_DISABLED; @@ -1843,7 +1854,7 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) default_var.bits_per_pixel = viafb_bpp1; default_var.pixclock = viafb_get_pixclock(viafb_second_xres, viafb_second_yres, - viafb_refresh); + viafb_refresh1); default_var.left_margin = (viafb_second_xres >> 3) & 0xf8; default_var.right_margin = 32; default_var.upper_margin = 16; -- cgit v1.2.2 From 8c3c283e6bf463ab498d6e7823aff6c4762314b6 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Wed, 16 Mar 2011 22:11:46 -0700 Subject: Input: xen-kbdfront - advertise either absolute or relative coordinates A virtualized display device is usually viewed with the vncviewer application, either by 'xm vnc domU' or with vncviewer localhost:port. vncviewer and the RFB protocol provides absolute coordinates to the virtual display. These coordinates are either passed through to a PV guest or converted to relative coordinates for a HVM guest. A PV guest receives these coordinates and passes them to the kernels evdev driver. There it can be picked up by applications such as the xorg-input drivers. Using absolute coordinates avoids issues such as guest mouse pointer not tracking host mouse pointer due to wrong mouse acceleration settings in the guests X display. Advertise either absolute or relative coordinates to the input system and the evdev driver, depending on what dom0 provides. The xorg-input driver prefers relative coordinates even if a devices provides both. Signed-off-by: Olaf Hering Signed-off-by: Stefano Stabellini Signed-off-by: Dmitry Torokhov --- drivers/input/xen-kbdfront.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index 7f85a862ad11..53e62732ee96 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -110,7 +110,7 @@ static irqreturn_t input_handler(int rq, void *dev_id) static int __devinit xenkbd_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { - int ret, i; + int ret, i, abs; struct xenkbd_info *info; struct input_dev *kbd, *ptr; @@ -128,6 +128,11 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, if (!info->page) goto error_nomem; + if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) + abs = 0; + if (abs) + xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); + /* keyboard */ kbd = input_allocate_device(); if (!kbd) @@ -137,11 +142,12 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, kbd->id.bustype = BUS_PCI; kbd->id.vendor = 0x5853; kbd->id.product = 0xffff; - kbd->evbit[0] = BIT(EV_KEY); + + __set_bit(EV_KEY, kbd->evbit); for (i = KEY_ESC; i < KEY_UNKNOWN; i++) - set_bit(i, kbd->keybit); + __set_bit(i, kbd->keybit); for (i = KEY_OK; i < KEY_MAX; i++) - set_bit(i, kbd->keybit); + __set_bit(i, kbd->keybit); ret = input_register_device(kbd); if (ret) { @@ -160,12 +166,20 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, ptr->id.bustype = BUS_PCI; ptr->id.vendor = 0x5853; ptr->id.product = 0xfffe; - ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + + if (abs) { + __set_bit(EV_ABS, ptr->evbit); + input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + } else { + input_set_capability(ptr, EV_REL, REL_X); + input_set_capability(ptr, EV_REL, REL_Y); + } + input_set_capability(ptr, EV_REL, REL_WHEEL); + + __set_bit(EV_KEY, ptr->evbit); for (i = BTN_LEFT; i <= BTN_TASK; i++) - set_bit(i, ptr->keybit); - ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL); - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + __set_bit(i, ptr->keybit); ret = input_register_device(ptr); if (ret) { @@ -272,7 +286,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int ret, val; + int val; switch (backend_state) { case XenbusStateInitialising: @@ -285,16 +299,6 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, case XenbusStateInitWait: InitWait: - ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "feature-abs-pointer", "%d", &val); - if (ret < 0) - val = 0; - if (val) { - ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, - "request-abs-pointer", "1"); - if (ret) - pr_warning("can't request abs-pointer\n"); - } xenbus_switch_state(dev, XenbusStateConnected); break; -- cgit v1.2.2 From 0a4dfa5ddb5fc0aff331e255da282b01a74a6cd3 Mon Sep 17 00:00:00 2001 From: Daniel De Graaf Date: Wed, 16 Mar 2011 22:52:42 -0700 Subject: Input: xen-kbdfront - add grant reference for shared page Without a grant reference, full access to the domain's memory is required to use the shared page. Add an additional parameter in xenstore to allow grant mapping to be used. Signed-off-by: Daniel De Graaf Signed-off-by: Konrad Rzeszutek Wilk Acked-by: Ian Campbell Signed-off-by: Dmitry Torokhov --- drivers/input/xen-kbdfront.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index 53e62732ee96..7077f9bf5ead 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -11,12 +11,6 @@ * more details. */ -/* - * TODO: - * - * Switch to grant tables together with xen-fbfront.c. - */ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -30,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -38,6 +34,7 @@ struct xenkbd_info { struct input_dev *kbd; struct input_dev *ptr; struct xenkbd_page *page; + int gref; int irq; struct xenbus_device *xbdev; char phys[32]; @@ -122,6 +119,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev, dev_set_drvdata(&dev->dev, info); info->xbdev = dev; info->irq = -1; + info->gref = -1; snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); @@ -232,15 +230,20 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, int ret, evtchn; struct xenbus_transaction xbt; + ret = gnttab_grant_foreign_access(dev->otherend_id, + virt_to_mfn(info->page), 0); + if (ret < 0) + return ret; + info->gref = ret; + ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) - return ret; + goto error_grant; ret = bind_evtchn_to_irqhandler(evtchn, input_handler, 0, dev->devicetype, info); if (ret < 0) { - xenbus_free_evtchn(dev, evtchn); xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); - return ret; + goto error_evtchan; } info->irq = ret; @@ -248,10 +251,13 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, ret = xenbus_transaction_start(&xbt); if (ret) { xenbus_dev_fatal(dev, ret, "starting transaction"); - return ret; + goto error_irqh; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", @@ -263,7 +269,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, if (ret == -EAGAIN) goto again; xenbus_dev_fatal(dev, ret, "completing transaction"); - return ret; + goto error_irqh; } xenbus_switch_state(dev, XenbusStateInitialised); @@ -272,6 +278,14 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, error_xenbus: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, ret, "writing xenstore"); + error_irqh: + unbind_from_irqhandler(info->irq, info); + info->irq = -1; + error_evtchan: + xenbus_free_evtchn(dev, evtchn); + error_grant: + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; return ret; } @@ -280,6 +294,9 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info) if (info->irq >= 0) unbind_from_irqhandler(info->irq, info); info->irq = -1; + if (info->gref >= 0) + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; } static void xenkbd_backend_changed(struct xenbus_device *dev, -- cgit v1.2.2 From 49851ca04c7f941ef6f5ca04751b0e0fefe9d50d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:56:03 -0700 Subject: Input: xen-kbdfront - move to drivers/input/misc drivers/input is reserved for input core code and input handlers with drivers belonging to one of the sub-directories. Signed-off-by: Dmitry Torokhov --- drivers/input/Kconfig | 10 - drivers/input/Makefile | 2 - drivers/input/misc/Kconfig | 13 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/xen-kbdfront.c | 385 ++++++++++++++++++++++++++++++++++++++ drivers/input/xen-kbdfront.c | 385 -------------------------------------- 6 files changed, 399 insertions(+), 397 deletions(-) create mode 100644 drivers/input/misc/xen-kbdfront.c delete mode 100644 drivers/input/xen-kbdfront.c (limited to 'drivers') diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 1903c0f5b925..23e82e46656d 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -161,16 +161,6 @@ config INPUT_APMPOWER To compile this driver as a module, choose M here: the module will be called apm-power. -config XEN_KBDDEV_FRONTEND - tristate "Xen virtual keyboard and mouse support" - depends on XEN_FBDEV_FRONTEND - default y - select XEN_XENBUS_FRONTEND - help - This driver implements the front-end of the Xen virtual - keyboard and mouse device driver. It communicates with a back-end - in another domain. - comment "Input Device Drivers" source "drivers/input/keyboard/Kconfig" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 09614ce74961..0c789490e0b3 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -24,5 +24,3 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o - -obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index b0c6772851a9..f9cf0881b0e3 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -454,4 +454,17 @@ config INPUT_CMA3000_I2C To compile this driver as a module, choose M here: the module will be called cma3000_d0x_i2c. +config INPUT_XEN_KBDDEV_FRONTEND + tristate "Xen virtual keyboard and mouse support" + depends on XEN_FBDEV_FRONTEND + default y + select XEN_XENBUS_FRONTEND + help + This driver implements the front-end of the Xen virtual + keyboard and mouse device driver. It communicates with a back-end + in another domain. + + To compile this driver as a module, choose M here: the + module will be called xen-kbdfront. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9b4797112c9a..e3f7984e6274 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -42,5 +42,6 @@ obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o +obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c new file mode 100644 index 000000000000..7077f9bf5ead --- /dev/null +++ b/drivers/input/misc/xen-kbdfront.c @@ -0,0 +1,385 @@ +/* + * Xen para-virtual input device + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster + * + * Based on linux/drivers/input/mouse/sermouse.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct xenkbd_info { + struct input_dev *kbd; + struct input_dev *ptr; + struct xenkbd_page *page; + int gref; + int irq; + struct xenbus_device *xbdev; + char phys[32]; +}; + +static int xenkbd_remove(struct xenbus_device *); +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); +static void xenkbd_disconnect_backend(struct xenkbd_info *); + +/* + * Note: if you need to send out events, see xenfb_do_update() for how + * to do that. + */ + +static irqreturn_t input_handler(int rq, void *dev_id) +{ + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; + __u32 cons, prod; + + prod = page->in_prod; + if (prod == page->in_cons) + return IRQ_HANDLED; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->in_cons; cons != prod; cons++) { + union xenkbd_in_event *event; + struct input_dev *dev; + event = &XENKBD_IN_RING_REF(page, cons); + + dev = info->ptr; + switch (event->type) { + case XENKBD_TYPE_MOTION: + input_report_rel(dev, REL_X, event->motion.rel_x); + input_report_rel(dev, REL_Y, event->motion.rel_y); + if (event->motion.rel_z) + input_report_rel(dev, REL_WHEEL, + -event->motion.rel_z); + break; + case XENKBD_TYPE_KEY: + dev = NULL; + if (test_bit(event->key.keycode, info->kbd->keybit)) + dev = info->kbd; + if (test_bit(event->key.keycode, info->ptr->keybit)) + dev = info->ptr; + if (dev) + input_report_key(dev, event->key.keycode, + event->key.pressed); + else + pr_warning("unhandled keycode 0x%x\n", + event->key.keycode); + break; + case XENKBD_TYPE_POS: + input_report_abs(dev, ABS_X, event->pos.abs_x); + input_report_abs(dev, ABS_Y, event->pos.abs_y); + if (event->pos.rel_z) + input_report_rel(dev, REL_WHEEL, + -event->pos.rel_z); + break; + } + if (dev) + input_sync(dev); + } + mb(); /* ensure we got ring contents */ + page->in_cons = cons; + notify_remote_via_irq(info->irq); + + return IRQ_HANDLED; +} + +static int __devinit xenkbd_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int ret, i, abs; + struct xenkbd_info *info; + struct input_dev *kbd, *ptr; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev_set_drvdata(&dev->dev, info); + info->xbdev = dev; + info->irq = -1; + info->gref = -1; + snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); + + info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); + if (!info->page) + goto error_nomem; + + if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) + abs = 0; + if (abs) + xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); + + /* keyboard */ + kbd = input_allocate_device(); + if (!kbd) + goto error_nomem; + kbd->name = "Xen Virtual Keyboard"; + kbd->phys = info->phys; + kbd->id.bustype = BUS_PCI; + kbd->id.vendor = 0x5853; + kbd->id.product = 0xffff; + + __set_bit(EV_KEY, kbd->evbit); + for (i = KEY_ESC; i < KEY_UNKNOWN; i++) + __set_bit(i, kbd->keybit); + for (i = KEY_OK; i < KEY_MAX; i++) + __set_bit(i, kbd->keybit); + + ret = input_register_device(kbd); + if (ret) { + input_free_device(kbd); + xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); + goto error; + } + info->kbd = kbd; + + /* pointing device */ + ptr = input_allocate_device(); + if (!ptr) + goto error_nomem; + ptr->name = "Xen Virtual Pointer"; + ptr->phys = info->phys; + ptr->id.bustype = BUS_PCI; + ptr->id.vendor = 0x5853; + ptr->id.product = 0xfffe; + + if (abs) { + __set_bit(EV_ABS, ptr->evbit); + input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + } else { + input_set_capability(ptr, EV_REL, REL_X); + input_set_capability(ptr, EV_REL, REL_Y); + } + input_set_capability(ptr, EV_REL, REL_WHEEL); + + __set_bit(EV_KEY, ptr->evbit); + for (i = BTN_LEFT; i <= BTN_TASK; i++) + __set_bit(i, ptr->keybit); + + ret = input_register_device(ptr); + if (ret) { + input_free_device(ptr); + xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); + goto error; + } + info->ptr = ptr; + + ret = xenkbd_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenkbd_remove(dev); + return ret; +} + +static int xenkbd_resume(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); + + xenkbd_disconnect_backend(info); + memset(info->page, 0, PAGE_SIZE); + return xenkbd_connect_backend(dev, info); +} + +static int xenkbd_remove(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); + + xenkbd_disconnect_backend(info); + if (info->kbd) + input_unregister_device(info->kbd); + if (info->ptr) + input_unregister_device(info->ptr); + free_page((unsigned long)info->page); + kfree(info); + return 0; +} + +static int xenkbd_connect_backend(struct xenbus_device *dev, + struct xenkbd_info *info) +{ + int ret, evtchn; + struct xenbus_transaction xbt; + + ret = gnttab_grant_foreign_access(dev->otherend_id, + virt_to_mfn(info->page), 0); + if (ret < 0) + return ret; + info->gref = ret; + + ret = xenbus_alloc_evtchn(dev, &evtchn); + if (ret) + goto error_grant; + ret = bind_evtchn_to_irqhandler(evtchn, input_handler, + 0, dev->devicetype, info); + if (ret < 0) { + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + goto error_evtchan; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + goto error_irqh; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + goto error_irqh; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + error_irqh: + unbind_from_irqhandler(info->irq, info); + info->irq = -1; + error_evtchan: + xenbus_free_evtchn(dev, evtchn); + error_grant: + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; + return ret; +} + +static void xenkbd_disconnect_backend(struct xenkbd_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; + if (info->gref >= 0) + gnttab_end_foreign_access_ref(info->gref, 0); + info->gref = -1; +} + +static void xenkbd_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenkbd_info *info = dev_get_drvdata(&dev->dev); + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateReconfiguring: + case XenbusStateReconfigured: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: +InitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + + /* Set input abs params to match backend screen res */ + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "width", "%d", &val) > 0) + input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "height", "%d", &val) > 0) + input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); + + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static const struct xenbus_device_id xenkbd_ids[] = { + { "vkbd" }, + { "" } +}; + +static struct xenbus_driver xenkbd_driver = { + .name = "vkbd", + .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, + .resume = xenkbd_resume, + .otherend_changed = xenkbd_backend_changed, +}; + +static int __init xenkbd_init(void) +{ + if (!xen_pv_domain()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (xen_initial_domain()) + return -ENODEV; + + return xenbus_register_frontend(&xenkbd_driver); +} + +static void __exit xenkbd_cleanup(void) +{ + xenbus_unregister_driver(&xenkbd_driver); +} + +module_init(xenkbd_init); +module_exit(xenkbd_cleanup); + +MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("xen:vkbd"); diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c deleted file mode 100644 index 7077f9bf5ead..000000000000 --- a/drivers/input/xen-kbdfront.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Xen para-virtual input device - * - * Copyright (C) 2005 Anthony Liguori - * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster - * - * Based on linux/drivers/input/mouse/sermouse.c - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -struct xenkbd_info { - struct input_dev *kbd; - struct input_dev *ptr; - struct xenkbd_page *page; - int gref; - int irq; - struct xenbus_device *xbdev; - char phys[32]; -}; - -static int xenkbd_remove(struct xenbus_device *); -static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); -static void xenkbd_disconnect_backend(struct xenkbd_info *); - -/* - * Note: if you need to send out events, see xenfb_do_update() for how - * to do that. - */ - -static irqreturn_t input_handler(int rq, void *dev_id) -{ - struct xenkbd_info *info = dev_id; - struct xenkbd_page *page = info->page; - __u32 cons, prod; - - prod = page->in_prod; - if (prod == page->in_cons) - return IRQ_HANDLED; - rmb(); /* ensure we see ring contents up to prod */ - for (cons = page->in_cons; cons != prod; cons++) { - union xenkbd_in_event *event; - struct input_dev *dev; - event = &XENKBD_IN_RING_REF(page, cons); - - dev = info->ptr; - switch (event->type) { - case XENKBD_TYPE_MOTION: - input_report_rel(dev, REL_X, event->motion.rel_x); - input_report_rel(dev, REL_Y, event->motion.rel_y); - if (event->motion.rel_z) - input_report_rel(dev, REL_WHEEL, - -event->motion.rel_z); - break; - case XENKBD_TYPE_KEY: - dev = NULL; - if (test_bit(event->key.keycode, info->kbd->keybit)) - dev = info->kbd; - if (test_bit(event->key.keycode, info->ptr->keybit)) - dev = info->ptr; - if (dev) - input_report_key(dev, event->key.keycode, - event->key.pressed); - else - pr_warning("unhandled keycode 0x%x\n", - event->key.keycode); - break; - case XENKBD_TYPE_POS: - input_report_abs(dev, ABS_X, event->pos.abs_x); - input_report_abs(dev, ABS_Y, event->pos.abs_y); - if (event->pos.rel_z) - input_report_rel(dev, REL_WHEEL, - -event->pos.rel_z); - break; - } - if (dev) - input_sync(dev); - } - mb(); /* ensure we got ring contents */ - page->in_cons = cons; - notify_remote_via_irq(info->irq); - - return IRQ_HANDLED; -} - -static int __devinit xenkbd_probe(struct xenbus_device *dev, - const struct xenbus_device_id *id) -{ - int ret, i, abs; - struct xenkbd_info *info; - struct input_dev *kbd, *ptr; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); - return -ENOMEM; - } - dev_set_drvdata(&dev->dev, info); - info->xbdev = dev; - info->irq = -1; - info->gref = -1; - snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); - - info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); - if (!info->page) - goto error_nomem; - - if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-abs-pointer", "%d", &abs) < 0) - abs = 0; - if (abs) - xenbus_printf(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); - - /* keyboard */ - kbd = input_allocate_device(); - if (!kbd) - goto error_nomem; - kbd->name = "Xen Virtual Keyboard"; - kbd->phys = info->phys; - kbd->id.bustype = BUS_PCI; - kbd->id.vendor = 0x5853; - kbd->id.product = 0xffff; - - __set_bit(EV_KEY, kbd->evbit); - for (i = KEY_ESC; i < KEY_UNKNOWN; i++) - __set_bit(i, kbd->keybit); - for (i = KEY_OK; i < KEY_MAX; i++) - __set_bit(i, kbd->keybit); - - ret = input_register_device(kbd); - if (ret) { - input_free_device(kbd); - xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); - goto error; - } - info->kbd = kbd; - - /* pointing device */ - ptr = input_allocate_device(); - if (!ptr) - goto error_nomem; - ptr->name = "Xen Virtual Pointer"; - ptr->phys = info->phys; - ptr->id.bustype = BUS_PCI; - ptr->id.vendor = 0x5853; - ptr->id.product = 0xfffe; - - if (abs) { - __set_bit(EV_ABS, ptr->evbit); - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); - } else { - input_set_capability(ptr, EV_REL, REL_X); - input_set_capability(ptr, EV_REL, REL_Y); - } - input_set_capability(ptr, EV_REL, REL_WHEEL); - - __set_bit(EV_KEY, ptr->evbit); - for (i = BTN_LEFT; i <= BTN_TASK; i++) - __set_bit(i, ptr->keybit); - - ret = input_register_device(ptr); - if (ret) { - input_free_device(ptr); - xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); - goto error; - } - info->ptr = ptr; - - ret = xenkbd_connect_backend(dev, info); - if (ret < 0) - goto error; - - return 0; - - error_nomem: - ret = -ENOMEM; - xenbus_dev_fatal(dev, ret, "allocating device memory"); - error: - xenkbd_remove(dev); - return ret; -} - -static int xenkbd_resume(struct xenbus_device *dev) -{ - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - - xenkbd_disconnect_backend(info); - memset(info->page, 0, PAGE_SIZE); - return xenkbd_connect_backend(dev, info); -} - -static int xenkbd_remove(struct xenbus_device *dev) -{ - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - - xenkbd_disconnect_backend(info); - if (info->kbd) - input_unregister_device(info->kbd); - if (info->ptr) - input_unregister_device(info->ptr); - free_page((unsigned long)info->page); - kfree(info); - return 0; -} - -static int xenkbd_connect_backend(struct xenbus_device *dev, - struct xenkbd_info *info) -{ - int ret, evtchn; - struct xenbus_transaction xbt; - - ret = gnttab_grant_foreign_access(dev->otherend_id, - virt_to_mfn(info->page), 0); - if (ret < 0) - return ret; - info->gref = ret; - - ret = xenbus_alloc_evtchn(dev, &evtchn); - if (ret) - goto error_grant; - ret = bind_evtchn_to_irqhandler(evtchn, input_handler, - 0, dev->devicetype, info); - if (ret < 0) { - xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); - goto error_evtchan; - } - info->irq = ret; - - again: - ret = xenbus_transaction_start(&xbt); - if (ret) { - xenbus_dev_fatal(dev, ret, "starting transaction"); - goto error_irqh; - } - ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", - virt_to_mfn(info->page)); - if (ret) - goto error_xenbus; - ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); - if (ret) - goto error_xenbus; - ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", - evtchn); - if (ret) - goto error_xenbus; - ret = xenbus_transaction_end(xbt, 0); - if (ret) { - if (ret == -EAGAIN) - goto again; - xenbus_dev_fatal(dev, ret, "completing transaction"); - goto error_irqh; - } - - xenbus_switch_state(dev, XenbusStateInitialised); - return 0; - - error_xenbus: - xenbus_transaction_end(xbt, 1); - xenbus_dev_fatal(dev, ret, "writing xenstore"); - error_irqh: - unbind_from_irqhandler(info->irq, info); - info->irq = -1; - error_evtchan: - xenbus_free_evtchn(dev, evtchn); - error_grant: - gnttab_end_foreign_access_ref(info->gref, 0); - info->gref = -1; - return ret; -} - -static void xenkbd_disconnect_backend(struct xenkbd_info *info) -{ - if (info->irq >= 0) - unbind_from_irqhandler(info->irq, info); - info->irq = -1; - if (info->gref >= 0) - gnttab_end_foreign_access_ref(info->gref, 0); - info->gref = -1; -} - -static void xenkbd_backend_changed(struct xenbus_device *dev, - enum xenbus_state backend_state) -{ - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int val; - - switch (backend_state) { - case XenbusStateInitialising: - case XenbusStateInitialised: - case XenbusStateReconfiguring: - case XenbusStateReconfigured: - case XenbusStateUnknown: - case XenbusStateClosed: - break; - - case XenbusStateInitWait: -InitWait: - xenbus_switch_state(dev, XenbusStateConnected); - break; - - case XenbusStateConnected: - /* - * Work around xenbus race condition: If backend goes - * through InitWait to Connected fast enough, we can - * get Connected twice here. - */ - if (dev->state != XenbusStateConnected) - goto InitWait; /* no InitWait seen yet, fudge it */ - - /* Set input abs params to match backend screen res */ - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "width", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); - - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "height", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); - - break; - - case XenbusStateClosing: - xenbus_frontend_closed(dev); - break; - } -} - -static const struct xenbus_device_id xenkbd_ids[] = { - { "vkbd" }, - { "" } -}; - -static struct xenbus_driver xenkbd_driver = { - .name = "vkbd", - .owner = THIS_MODULE, - .ids = xenkbd_ids, - .probe = xenkbd_probe, - .remove = xenkbd_remove, - .resume = xenkbd_resume, - .otherend_changed = xenkbd_backend_changed, -}; - -static int __init xenkbd_init(void) -{ - if (!xen_pv_domain()) - return -ENODEV; - - /* Nothing to do if running in dom0. */ - if (xen_initial_domain()) - return -ENODEV; - - return xenbus_register_frontend(&xenkbd_driver); -} - -static void __exit xenkbd_cleanup(void) -{ - xenbus_unregister_driver(&xenkbd_driver); -} - -module_init(xenkbd_init); -module_exit(xenkbd_cleanup); - -MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("xen:vkbd"); -- cgit v1.2.2 From 37bd44694c7215e3e46e6ee4a930d197325a7168 Mon Sep 17 00:00:00 2001 From: Lauri Leukkunen Date: Wed, 16 Mar 2011 22:07:36 -0700 Subject: Input: introduce tsc2005 driver Discussions: http://www.mail-archive.com/linux-omap@vger.kernel.org/msg26748.html Introduce a driver for the Texas Instruments TSC2005 touchscreen controller (http://focus.ti.com/docs/prod/folders/print/tsc2005.html). The patch is based on a driver by Lauri Leukkunen, with modifications by David Brownell, Phil Carmody, Imre Deak, Hiroshi DOYU, Ari Kauppi, Tony Lindgren, Jarkko Nikula, Eero Nurkkala and Roman Tereshonkov. Signed-off-by: Lauri Leukkunen [aaro.koskinen@nokia.com: patch description, rebasing & cleanup] Signed-off-by: Aaro Koskinen [ext-srikar.1.bhavanarayana@nokia.com: various fixes] Signed-off-by: Srikar Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 11 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/tsc2005.c | 713 ++++++++++++++++++++++++++++++++++++ 3 files changed, 725 insertions(+) create mode 100644 drivers/input/touchscreen/tsc2005.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 06ea8da95c62..30703ad363f3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -629,6 +629,17 @@ config TOUCHSCREEN_TOUCHIT213 To compile this driver as a module, choose M here: the module will be called touchit213. +config TOUCHSCREEN_TSC2005 + tristate "TSC2005 based touchscreens" + depends on SPI_MASTER + help + Say Y here if you have a TSC2005 based touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called tsc2005. + config TOUCHSCREEN_TSC2007 tristate "TSC2007 based touchscreens" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 7cc1b4f4b677..34b26ad65cee 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o +obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c new file mode 100644 index 000000000000..f95f968f18e1 --- /dev/null +++ b/drivers/input/touchscreen/tsc2005.c @@ -0,0 +1,713 @@ +/* + * TSC2005 touchscreen driver + * + * Copyright (C) 2006-2010 Nokia Corporation + * + * Author: Lauri Leukkunen + * based on TSC2301 driver by Klaus K. Pedersen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * The touchscreen interface operates as follows: + * + * 1) Pen is pressed against the touchscreen. + * 2) TSC2005 performs AD conversion. + * 3) After the conversion is done TSC2005 drives DAV line down. + * 4) GPIO IRQ is received and tsc2005_irq_thread() is scheduled. + * 5) tsc2005_irq_thread() queues up an spi transfer to fetch the x, y, z1, z2 + * values. + * 6) tsc2005_irq_thread() reports coordinates to input layer and sets up + * tsc2005_penup_timer() to be called after TSC2005_PENUP_TIME_MS (40ms). + * 7) When the penup timer expires, there have not been touch or DAV interrupts + * during the last 40ms which means the pen has been lifted. + * + * ESD recovery via a hardware reset is done if the TSC2005 doesn't respond + * after a configurable period (in ms) of activity. If esd_timeout is 0, the + * watchdog is disabled. + */ + +/* control byte 1 */ +#define TSC2005_CMD 0x80 +#define TSC2005_CMD_NORMAL 0x00 +#define TSC2005_CMD_STOP 0x01 +#define TSC2005_CMD_12BIT 0x04 + +/* control byte 0 */ +#define TSC2005_REG_READ 0x0001 +#define TSC2005_REG_PND0 0x0002 +#define TSC2005_REG_X 0x0000 +#define TSC2005_REG_Y 0x0008 +#define TSC2005_REG_Z1 0x0010 +#define TSC2005_REG_Z2 0x0018 +#define TSC2005_REG_TEMP_HIGH 0x0050 +#define TSC2005_REG_CFR0 0x0060 +#define TSC2005_REG_CFR1 0x0068 +#define TSC2005_REG_CFR2 0x0070 + +/* configuration register 0 */ +#define TSC2005_CFR0_PRECHARGE_276US 0x0040 +#define TSC2005_CFR0_STABTIME_1MS 0x0300 +#define TSC2005_CFR0_CLOCK_1MHZ 0x1000 +#define TSC2005_CFR0_RESOLUTION12 0x2000 +#define TSC2005_CFR0_PENMODE 0x8000 +#define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS | \ + TSC2005_CFR0_CLOCK_1MHZ | \ + TSC2005_CFR0_RESOLUTION12 | \ + TSC2005_CFR0_PRECHARGE_276US | \ + TSC2005_CFR0_PENMODE) + +/* bits common to both read and write of configuration register 0 */ +#define TSC2005_CFR0_RW_MASK 0x3fff + +/* configuration register 1 */ +#define TSC2005_CFR1_BATCHDELAY_4MS 0x0003 +#define TSC2005_CFR1_INITVALUE TSC2005_CFR1_BATCHDELAY_4MS + +/* configuration register 2 */ +#define TSC2005_CFR2_MAVE_Z 0x0004 +#define TSC2005_CFR2_MAVE_Y 0x0008 +#define TSC2005_CFR2_MAVE_X 0x0010 +#define TSC2005_CFR2_AVG_7 0x0800 +#define TSC2005_CFR2_MEDIUM_15 0x3000 +#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_MAVE_X | \ + TSC2005_CFR2_MAVE_Y | \ + TSC2005_CFR2_MAVE_Z | \ + TSC2005_CFR2_MEDIUM_15 | \ + TSC2005_CFR2_AVG_7) + +#define MAX_12BIT 0xfff +#define TSC2005_SPI_MAX_SPEED_HZ 10000000 +#define TSC2005_PENUP_TIME_MS 40 + +struct tsc2005_spi_rd { + struct spi_transfer spi_xfer; + u32 spi_tx; + u32 spi_rx; +}; + +struct tsc2005 { + struct spi_device *spi; + + struct spi_message spi_read_msg; + struct tsc2005_spi_rd spi_x; + struct tsc2005_spi_rd spi_y; + struct tsc2005_spi_rd spi_z1; + struct tsc2005_spi_rd spi_z2; + + struct input_dev *idev; + char phys[32]; + + struct mutex mutex; + + /* raw copy of previous x,y,z */ + int in_x; + int in_y; + int in_z1; + int in_z2; + + struct timer_list penup_timer; + struct work_struct penup_work; + + unsigned int esd_timeout; + struct timer_list esd_timer; + struct work_struct esd_work; + + unsigned int x_plate_ohm; + + bool disabled; + unsigned int disable_depth; + unsigned int pen_down; + + void (*set_reset)(bool enable); +}; + +static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) +{ + u8 tx; + struct spi_message msg; + struct spi_transfer xfer = { 0 }; + + tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; + + xfer.tx_buf = &tx; + xfer.rx_buf = NULL; + xfer.len = 1; + xfer.bits_per_word = 8; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + spi_sync(ts->spi, &msg); +} + +static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) +{ + u32 tx; + struct spi_message msg; + struct spi_transfer xfer = { 0 }; + + tx = (reg | TSC2005_REG_PND0) << 16; + tx |= value; + + xfer.tx_buf = &tx; + xfer.rx_buf = NULL; + xfer.len = 4; + xfer.bits_per_word = 24; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + spi_sync(ts->spi, &msg); +} + +static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) +{ + rd->spi_tx = (reg | TSC2005_REG_READ) << 16; + rd->spi_xfer.tx_buf = &rd->spi_tx; + rd->spi_xfer.rx_buf = &rd->spi_rx; + rd->spi_xfer.len = 4; + rd->spi_xfer.bits_per_word = 24; + rd->spi_xfer.cs_change = !last; +} + +static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) +{ + struct spi_message msg; + struct tsc2005_spi_rd spi_rd = { { 0 }, 0, 0 }; + + tsc2005_setup_read(&spi_rd, reg, 1); + + spi_message_init(&msg); + spi_message_add_tail(&spi_rd.spi_xfer, &msg); + spi_sync(ts->spi, &msg); + *value = spi_rd.spi_rx; +} + +static void tsc2005_update_pen_state(struct tsc2005 *ts, + int x, int y, int pressure) +{ + if (pressure) { + input_report_abs(ts->idev, ABS_X, x); + input_report_abs(ts->idev, ABS_Y, y); + input_report_abs(ts->idev, ABS_PRESSURE, pressure); + if (!ts->pen_down) { + input_report_key(ts->idev, BTN_TOUCH, !!pressure); + ts->pen_down = 1; + } + } else { + input_report_abs(ts->idev, ABS_PRESSURE, 0); + if (ts->pen_down) { + input_report_key(ts->idev, BTN_TOUCH, 0); + ts->pen_down = 0; + } + } + input_sync(ts->idev); + dev_dbg(&ts->spi->dev, "point(%4d,%4d), pressure (%4d)\n", x, y, + pressure); +} + +static irqreturn_t tsc2005_irq_handler(int irq, void *dev_id) +{ + struct tsc2005 *ts = dev_id; + + /* update the penup timer only if it's pending */ + mod_timer_pending(&ts->penup_timer, + jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) +{ + struct tsc2005 *ts = _ts; + unsigned int pressure; + u32 x; + u32 y; + u32 z1; + u32 z2; + + mutex_lock(&ts->mutex); + + if (unlikely(ts->disable_depth)) + goto out; + + /* read the coordinates */ + spi_sync(ts->spi, &ts->spi_read_msg); + x = ts->spi_x.spi_rx; + y = ts->spi_y.spi_rx; + z1 = ts->spi_z1.spi_rx; + z2 = ts->spi_z2.spi_rx; + + /* validate position */ + if (unlikely(x > MAX_12BIT || y > MAX_12BIT)) + goto out; + + /* skip coords if the pressure components are out of range */ + if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2)) + goto out; + + /* skip point if this is a pen down with the exact same values as + * the value before pen-up - that implies SPI fed us stale data + */ + if (!ts->pen_down && + ts->in_x == x && + ts->in_y == y && + ts->in_z1 == z1 && + ts->in_z2 == z2) + goto out; + + /* At this point we are happy we have a valid and useful reading. + * Remember it for later comparisons. We may now begin downsampling + */ + ts->in_x = x; + ts->in_y = y; + ts->in_z1 = z1; + ts->in_z2 = z2; + + /* compute touch pressure resistance using equation #1 */ + pressure = x * (z2 - z1) / z1; + pressure = pressure * ts->x_plate_ohm / 4096; + if (unlikely(pressure > MAX_12BIT)) + goto out; + + tsc2005_update_pen_state(ts, x, y, pressure); + + /* set the penup timer */ + mod_timer(&ts->penup_timer, + jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); + + if (!ts->esd_timeout) + goto out; + + /* update the watchdog timer */ + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + +out: + mutex_unlock(&ts->mutex); + return IRQ_HANDLED; +} + +static void tsc2005_penup_timer(unsigned long data) +{ + struct tsc2005 *ts = (struct tsc2005 *)data; + + schedule_work(&ts->penup_work); +} + +static void tsc2005_penup_work(struct work_struct *work) +{ + struct tsc2005 *ts = container_of(work, struct tsc2005, penup_work); + + mutex_lock(&ts->mutex); + tsc2005_update_pen_state(ts, 0, 0, 0); + mutex_unlock(&ts->mutex); +} + +static void tsc2005_start_scan(struct tsc2005 *ts) +{ + tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); + tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); + tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); + tsc2005_cmd(ts, TSC2005_CMD_NORMAL); +} + +static void tsc2005_stop_scan(struct tsc2005 *ts) +{ + tsc2005_cmd(ts, TSC2005_CMD_STOP); +} + +/* must be called with mutex held */ +static void tsc2005_disable(struct tsc2005 *ts) +{ + if (ts->disable_depth++ != 0) + return; + disable_irq(ts->spi->irq); + if (ts->esd_timeout) + del_timer_sync(&ts->esd_timer); + del_timer_sync(&ts->penup_timer); + tsc2005_stop_scan(ts); +} + +/* must be called with mutex held */ +static void tsc2005_enable(struct tsc2005 *ts) +{ + if (--ts->disable_depth != 0) + return; + tsc2005_start_scan(ts); + enable_irq(ts->spi->irq); + if (!ts->esd_timeout) + return; + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); +} + +static ssize_t tsc2005_disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tsc2005 *ts = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", ts->disabled); +} + +static ssize_t tsc2005_disable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tsc2005 *ts = dev_get_drvdata(dev); + unsigned long res; + int i; + + if (strict_strtoul(buf, 10, &res) < 0) + return -EINVAL; + i = res ? 1 : 0; + + mutex_lock(&ts->mutex); + if (i == ts->disabled) + goto out; + ts->disabled = i; + if (i) + tsc2005_disable(ts); + else + tsc2005_enable(ts); +out: + mutex_unlock(&ts->mutex); + return count; +} +static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); + +static ssize_t tsc2005_selftest_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct tsc2005 *ts = dev_get_drvdata(dev); + u16 temp_high; + u16 temp_high_orig; + u16 temp_high_test; + unsigned int result; + + if (!ts->set_reset) { + dev_warn(&ts->spi->dev, + "unable to selftest: no reset function\n"); + result = 0; + goto out; + } + + mutex_lock(&ts->mutex); + + /* + * Test TSC2005 communications via temp high register. + */ + tsc2005_disable(ts); + result = 1; + tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + temp_high_test = (temp_high_orig - 1) & MAX_12BIT; + tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); + tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (temp_high != temp_high_test) { + dev_warn(dev, "selftest failed: %d != %d\n", + temp_high, temp_high_test); + result = 0; + } + + /* hardware reset */ + ts->set_reset(0); + usleep_range(100, 500); /* only 10us required */ + ts->set_reset(1); + tsc2005_enable(ts); + + /* test that the reset really happened */ + tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (temp_high != temp_high_orig) { + dev_warn(dev, "selftest failed after reset: %d != %d\n", + temp_high, temp_high_orig); + result = 0; + } + + mutex_unlock(&ts->mutex); + +out: + return sprintf(buf, "%u\n", result); +} +static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); + +static void tsc2005_esd_timer(unsigned long data) +{ + struct tsc2005 *ts = (struct tsc2005 *)data; + + schedule_work(&ts->esd_work); +} + +static void tsc2005_esd_work(struct work_struct *work) +{ + struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); + u16 r; + + mutex_lock(&ts->mutex); + + if (ts->disable_depth) + goto out; + + /* + * If we cannot read our known value from configuration register 0 then + * reset the controller as if from power-up and start scanning again. + */ + tsc2005_read(ts, TSC2005_REG_CFR0, &r); + if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) { + dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); + ts->set_reset(0); + tsc2005_update_pen_state(ts, 0, 0, 0); + usleep_range(100, 500); /* only 10us required */ + ts->set_reset(1); + tsc2005_start_scan(ts); + } + + /* re-arm the watchdog */ + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + +out: + mutex_unlock(&ts->mutex); +} + +static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) +{ + tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); + tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, 0); + tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, 0); + tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, 1); + + spi_message_init(&ts->spi_read_msg); + spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg); + spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg); + spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg); + spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); +} + +static struct attribute *tsc2005_attrs[] = { + &dev_attr_disable.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group tsc2005_attr_group = { + .attrs = tsc2005_attrs, +}; + +static int __devinit tsc2005_setup(struct tsc2005 *ts, + struct tsc2005_platform_data *pdata) +{ + int r; + int fudge_x; + int fudge_y; + int fudge_p; + int p_max; + int x_max; + int y_max; + + mutex_init(&ts->mutex); + + tsc2005_setup_spi_xfer(ts); + + init_timer(&ts->penup_timer); + setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); + INIT_WORK(&ts->penup_work, tsc2005_penup_work); + + fudge_x = pdata->ts_x_fudge ? : 4; + fudge_y = pdata->ts_y_fudge ? : 8; + fudge_p = pdata->ts_pressure_fudge ? : 2; + x_max = pdata->ts_x_max ? : MAX_12BIT; + y_max = pdata->ts_y_max ? : MAX_12BIT; + p_max = pdata->ts_pressure_max ? : MAX_12BIT; + ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280; + ts->esd_timeout = pdata->esd_timeout_ms; + ts->set_reset = pdata->set_reset; + + ts->idev = input_allocate_device(); + if (ts->idev == NULL) + return -ENOMEM; + ts->idev->name = "TSC2005 touchscreen"; + snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", + dev_name(&ts->spi->dev)); + ts->idev->phys = ts->phys; + ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); + ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); + ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(ts->idev, ABS_X, 0, x_max, fudge_x, 0); + input_set_abs_params(ts->idev, ABS_Y, 0, y_max, fudge_y, 0); + input_set_abs_params(ts->idev, ABS_PRESSURE, 0, p_max, fudge_p, 0); + + r = request_threaded_irq(ts->spi->irq, tsc2005_irq_handler, + tsc2005_irq_thread, IRQF_TRIGGER_RISING, + "tsc2005", ts); + if (r) { + dev_err(&ts->spi->dev, "request_threaded_irq(): %d\n", r); + goto err1; + } + set_irq_wake(ts->spi->irq, 1); + + r = input_register_device(ts->idev); + if (r) { + dev_err(&ts->spi->dev, "input_register_device(): %d\n", r); + goto err2; + } + + r = sysfs_create_group(&ts->spi->dev.kobj, &tsc2005_attr_group); + if (r) + dev_warn(&ts->spi->dev, "sysfs entry creation failed: %d\n", r); + + tsc2005_start_scan(ts); + + if (!ts->esd_timeout || !ts->set_reset) + goto done; + + /* start the optional ESD watchdog */ + setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); + INIT_WORK(&ts->esd_work, tsc2005_esd_work); + mod_timer(&ts->esd_timer, + round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + +done: + return 0; + +err2: + free_irq(ts->spi->irq, ts); + +err1: + input_free_device(ts->idev); + return r; +} + +static int __devinit tsc2005_probe(struct spi_device *spi) +{ + struct tsc2005_platform_data *pdata = spi->dev.platform_data; + struct tsc2005 *ts; + int r; + + if (spi->irq < 0) { + dev_dbg(&spi->dev, "no irq\n"); + return -ENODEV; + } + + if (!pdata) { + dev_dbg(&spi->dev, "no platform data\n"); + return -ENODEV; + } + + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + if (ts == NULL) + return -ENOMEM; + + dev_set_drvdata(&spi->dev, ts); + ts->spi = spi; + spi->dev.power.power_state = PMSG_ON; + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ; + spi_setup(spi); + + r = tsc2005_setup(ts, pdata); + if (r) + kfree(ts); + return r; +} + +static int __devexit tsc2005_remove(struct spi_device *spi) +{ + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + + mutex_lock(&ts->mutex); + tsc2005_disable(ts); + mutex_unlock(&ts->mutex); + + if (ts->esd_timeout) + del_timer_sync(&ts->esd_timer); + del_timer_sync(&ts->penup_timer); + + flush_work(&ts->esd_work); + flush_work(&ts->penup_work); + + sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); + free_irq(ts->spi->irq, ts); + input_unregister_device(ts->idev); + kfree(ts); + + return 0; +} + +#ifdef CONFIG_PM +static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) +{ + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + + mutex_lock(&ts->mutex); + tsc2005_disable(ts); + mutex_unlock(&ts->mutex); + + return 0; +} + +static int tsc2005_resume(struct spi_device *spi) +{ + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + + mutex_lock(&ts->mutex); + tsc2005_enable(ts); + mutex_unlock(&ts->mutex); + + return 0; +} +#endif + +static struct spi_driver tsc2005_driver = { + .driver = { + .name = "tsc2005", + .owner = THIS_MODULE, + }, +#ifdef CONFIG_PM + .suspend = tsc2005_suspend, + .resume = tsc2005_resume, +#endif + .probe = tsc2005_probe, + .remove = __devexit_p(tsc2005_remove), +}; + +static int __init tsc2005_init(void) +{ + printk(KERN_INFO "TSC2005 driver initializing\n"); + return spi_register_driver(&tsc2005_driver); +} +module_init(tsc2005_init); + +static void __exit tsc2005_exit(void) +{ + spi_unregister_driver(&tsc2005_driver); +} +module_exit(tsc2005_exit); + +MODULE_AUTHOR("Lauri Leukkunen "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:tsc2005"); -- cgit v1.2.2 From 6b007d62fabb279b51c784c7c8abc6848b66a917 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:08 -0700 Subject: Input: tsc2005 - use spi_get/set_drvdata() Instead of peeking into underlying device and using dev_get/set_drvdata(), let's use SPI layer's implementation to access driver-private data (which may be different from driver-core private data). Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index f95f968f18e1..5dad30a4b153 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -366,7 +366,8 @@ static void tsc2005_enable(struct tsc2005 *ts) static ssize_t tsc2005_disable_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct tsc2005 *ts = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); return sprintf(buf, "%u\n", ts->disabled); } @@ -375,7 +376,8 @@ static ssize_t tsc2005_disable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct tsc2005 *ts = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); unsigned long res; int i; @@ -401,7 +403,8 @@ static ssize_t tsc2005_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct tsc2005 *ts = dev_get_drvdata(dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); u16 temp_high; u16 temp_high_orig; u16 temp_high_test; @@ -620,7 +623,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) if (ts == NULL) return -ENOMEM; - dev_set_drvdata(&spi->dev, ts); + spi_set_drvdata(spi, ts); ts->spi = spi; spi->dev.power.power_state = PMSG_ON; spi->mode = SPI_MODE_0; @@ -637,7 +640,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) static int __devexit tsc2005_remove(struct spi_device *spi) { - struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); tsc2005_disable(ts); @@ -661,7 +664,8 @@ static int __devexit tsc2005_remove(struct spi_device *spi) #ifdef CONFIG_PM static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) { - struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); tsc2005_disable(ts); @@ -672,7 +676,8 @@ static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) static int tsc2005_resume(struct spi_device *spi) { - struct tsc2005 *ts = dev_get_drvdata(&spi->dev); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); tsc2005_enable(ts); -- cgit v1.2.2 From 3ff8ff53aae7b7e46dec6a50c29b8a022ec299ba Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:26 -0700 Subject: Input: tsc2005 - convert to using dev_pm_ops Newer code should not be using legacy suspend/resume methods but rather supply dev_pm_ops structure as it allows better control over power management. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 5dad30a4b153..109efbffe5ad 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -661,8 +662,8 @@ static int __devexit tsc2005_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM -static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) +#ifdef CONFIG_PM_SLEEP +static int tsc2005_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); @@ -674,7 +675,7 @@ static int tsc2005_suspend(struct spi_device *spi, pm_message_t mesg) return 0; } -static int tsc2005_resume(struct spi_device *spi) +static int tsc2005_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); @@ -687,17 +688,16 @@ static int tsc2005_resume(struct spi_device *spi) } #endif +static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume); + static struct spi_driver tsc2005_driver = { - .driver = { - .name = "tsc2005", - .owner = THIS_MODULE, + .driver = { + .name = "tsc2005", + .owner = THIS_MODULE, + .pm = &tsc2005_pm_ops, }, -#ifdef CONFIG_PM - .suspend = tsc2005_suspend, - .resume = tsc2005_resume, -#endif - .probe = tsc2005_probe, - .remove = __devexit_p(tsc2005_remove), + .probe = tsc2005_probe, + .remove = __devexit_p(tsc2005_remove), }; static int __init tsc2005_init(void) -- cgit v1.2.2 From ef5a672f8d67c45fe2739c3a98a4e41d96b5cabc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:39 -0700 Subject: Input: tsc2005 - remove incorrect module alias TSC2005 is not a platform driver so it should not define "platform:tsc2005" module alias. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 109efbffe5ad..8c2e02402f32 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -715,4 +715,3 @@ module_exit(tsc2005_exit); MODULE_AUTHOR("Lauri Leukkunen "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:tsc2005"); -- cgit v1.2.2 From bcd11879fb5c84b3ca9167022b4c2b66d0935c52 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:08:53 -0700 Subject: Input: tsc2005 - remove driver banner message The boot process is noisy as it is and input core already announces all new device so let's get rid of the banner message in the driver. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 8c2e02402f32..2435235db627 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -702,7 +702,6 @@ static struct spi_driver tsc2005_driver = { static int __init tsc2005_init(void) { - printk(KERN_INFO "TSC2005 driver initializing\n"); return spi_register_driver(&tsc2005_driver); } module_init(tsc2005_init); -- cgit v1.2.2 From b88aa494c27552e6fa94e4abaa5ea4f9b2f170a8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:03 -0700 Subject: Input: tsc2005 - add module description Add proper module description so that it would show in 'modinfo' output. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 2435235db627..596fd1f01b22 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -713,4 +713,5 @@ static void __exit tsc2005_exit(void) module_exit(tsc2005_exit); MODULE_AUTHOR("Lauri Leukkunen "); +MODULE_DESCRIPTION("TSC2005 Touchscreen Driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 2721a89ac41f2e7705484c1582c293c4eee5344d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:09 -0700 Subject: Input: tsc2005 - clear driver data after unbinding We should not leave garbage pointers in driver structure after we unbind it from the device or if bind fails. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 596fd1f01b22..732c81e9a3e6 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -634,8 +634,10 @@ static int __devinit tsc2005_probe(struct spi_device *spi) spi_setup(spi); r = tsc2005_setup(ts, pdata); - if (r) + if (r) { kfree(ts); + spi_set_drvdata(spi, NULL); + } return r; } @@ -659,6 +661,7 @@ static int __devexit tsc2005_remove(struct spi_device *spi) input_unregister_device(ts->idev); kfree(ts); + spi_set_drvdata(spi, NULL); return 0; } -- cgit v1.2.2 From b4b480a8d643cbdef6f925e55759c18a674fa454 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:25 -0700 Subject: Input: tsc2005 - set up parent device Set up SPI device as parent of the input device so it gets placed into proper place in sysfs tree. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 732c81e9a3e6..e294648a97c9 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -555,6 +555,7 @@ static int __devinit tsc2005_setup(struct tsc2005 *ts, snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(&ts->spi->dev)); ts->idev->phys = ts->phys; + ts->idev->dev.parent = &ts->spi->dev; ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); -- cgit v1.2.2 From f8a67139c68eb8a58907906622c9aa02cd6a1dd1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:32 -0700 Subject: Input: tsc2005 - set up bus type in input device We know what bus we are residing on (SPI) so let's make this data available to the users. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index e294648a97c9..09cbcb0b19fe 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -555,6 +555,7 @@ static int __devinit tsc2005_setup(struct tsc2005 *ts, snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(&ts->spi->dev)); ts->idev->phys = ts->phys; + ts->idev->id.bustype = BUS_SPI; ts->idev->dev.parent = &ts->spi->dev; ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); -- cgit v1.2.2 From 99bb892d8a3f4f384d61e5d20499247a7cdd3d74 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:09:38 -0700 Subject: Input: tsc2005 - rework driver initialization code We need to make sure we have time/work initialized before requesting and enabling interrupts, otherwise we might start using them way too early. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 215 ++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 110 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 09cbcb0b19fe..de170e9dc54a 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -495,6 +495,16 @@ out: mutex_unlock(&ts->mutex); } +static struct attribute *tsc2005_attrs[] = { + &dev_attr_disable.attr, + &dev_attr_selftest.attr, + NULL +}; + +static struct attribute_group tsc2005_attr_group = { + .attrs = tsc2005_attrs, +}; + static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) { tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); @@ -509,144 +519,130 @@ static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); } -static struct attribute *tsc2005_attrs[] = { - &dev_attr_disable.attr, - &dev_attr_selftest.attr, - NULL -}; - -static struct attribute_group tsc2005_attr_group = { - .attrs = tsc2005_attrs, -}; - -static int __devinit tsc2005_setup(struct tsc2005 *ts, - struct tsc2005_platform_data *pdata) +static int __devinit tsc2005_probe(struct spi_device *spi) { - int r; - int fudge_x; - int fudge_y; - int fudge_p; - int p_max; - int x_max; - int y_max; + const struct tsc2005_platform_data *pdata = spi->dev.platform_data; + struct tsc2005 *ts; + struct input_dev *input_dev; + unsigned int max_x, max_y, max_p; + unsigned int fudge_x, fudge_y, fudge_p; + int error; - mutex_init(&ts->mutex); + if (!pdata) { + dev_dbg(&spi->dev, "no platform data\n"); + return -ENODEV; + } - tsc2005_setup_spi_xfer(ts); + fudge_x = pdata->ts_x_fudge ? : 4; + fudge_y = pdata->ts_y_fudge ? : 8; + fudge_p = pdata->ts_pressure_fudge ? : 2; + max_x = pdata->ts_x_max ? : MAX_12BIT; + max_y = pdata->ts_y_max ? : MAX_12BIT; + max_p = pdata->ts_pressure_max ? : MAX_12BIT; - init_timer(&ts->penup_timer); - setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); - INIT_WORK(&ts->penup_work, tsc2005_penup_work); + if (spi->irq <= 0) { + dev_dbg(&spi->dev, "no irq\n"); + return -ENODEV; + } - fudge_x = pdata->ts_x_fudge ? : 4; - fudge_y = pdata->ts_y_fudge ? : 8; - fudge_p = pdata->ts_pressure_fudge ? : 2; - x_max = pdata->ts_x_max ? : MAX_12BIT; - y_max = pdata->ts_y_max ? : MAX_12BIT; - p_max = pdata->ts_pressure_max ? : MAX_12BIT; - ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280; - ts->esd_timeout = pdata->esd_timeout_ms; - ts->set_reset = pdata->set_reset; + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ; - ts->idev = input_allocate_device(); - if (ts->idev == NULL) - return -ENOMEM; - ts->idev->name = "TSC2005 touchscreen"; - snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", - dev_name(&ts->spi->dev)); - ts->idev->phys = ts->phys; - ts->idev->id.bustype = BUS_SPI; - ts->idev->dev.parent = &ts->spi->dev; - ts->idev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); - ts->idev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); - ts->idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - - input_set_abs_params(ts->idev, ABS_X, 0, x_max, fudge_x, 0); - input_set_abs_params(ts->idev, ABS_Y, 0, y_max, fudge_y, 0); - input_set_abs_params(ts->idev, ABS_PRESSURE, 0, p_max, fudge_p, 0); - - r = request_threaded_irq(ts->spi->irq, tsc2005_irq_handler, - tsc2005_irq_thread, IRQF_TRIGGER_RISING, - "tsc2005", ts); - if (r) { - dev_err(&ts->spi->dev, "request_threaded_irq(): %d\n", r); - goto err1; - } - set_irq_wake(ts->spi->irq, 1); + error = spi_setup(spi); + if (error) + return error; - r = input_register_device(ts->idev); - if (r) { - dev_err(&ts->spi->dev, "input_register_device(): %d\n", r); - goto err2; + ts = kzalloc(sizeof(*ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!ts || !input_dev) { + error = -ENOMEM; + goto err_free_mem; } - r = sysfs_create_group(&ts->spi->dev.kobj, &tsc2005_attr_group); - if (r) - dev_warn(&ts->spi->dev, "sysfs entry creation failed: %d\n", r); + ts->spi = spi; + ts->idev = input_dev; + + ts->x_plate_ohm = pdata->ts_x_plate_ohm ? : 280; + ts->esd_timeout = pdata->esd_timeout_ms; + ts->set_reset = pdata->set_reset; - tsc2005_start_scan(ts); + mutex_init(&ts->mutex); - if (!ts->esd_timeout || !ts->set_reset) - goto done; + setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); + INIT_WORK(&ts->penup_work, tsc2005_penup_work); - /* start the optional ESD watchdog */ setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); INIT_WORK(&ts->esd_work, tsc2005_esd_work); - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); - -done: - return 0; -err2: - free_irq(ts->spi->irq, ts); - -err1: - input_free_device(ts->idev); - return r; -} - -static int __devinit tsc2005_probe(struct spi_device *spi) -{ - struct tsc2005_platform_data *pdata = spi->dev.platform_data; - struct tsc2005 *ts; - int r; + tsc2005_setup_spi_xfer(ts); - if (spi->irq < 0) { - dev_dbg(&spi->dev, "no irq\n"); - return -ENODEV; + snprintf(ts->phys, sizeof(ts->phys), + "%s/input-ts", dev_name(&spi->dev)); + + input_dev->name = "TSC2005 touchscreen"; + input_dev->phys = ts->phys; + input_dev->id.bustype = BUS_SPI; + input_dev->dev.parent = &spi->dev; + input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0); + input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); + + error = request_threaded_irq(spi->irq, + tsc2005_irq_handler, tsc2005_irq_thread, + IRQF_TRIGGER_RISING, "tsc2005", ts); + if (error) { + dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); + goto err_free_mem; } - if (!pdata) { - dev_dbg(&spi->dev, "no platform data\n"); - return -ENODEV; + spi_set_drvdata(spi, ts); + error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); + if (error) { + dev_err(&spi->dev, + "Failed to create sysfs attributes, err: %d\n", error); + goto err_clear_drvdata; } - ts = kzalloc(sizeof(*ts), GFP_KERNEL); - if (ts == NULL) - return -ENOMEM; + error = input_register_device(ts->idev); + if (error) { + dev_err(&spi->dev, + "Failed to register input device, err: %d\n", error); + goto err_remove_sysfs; + } - spi_set_drvdata(spi, ts); - ts->spi = spi; - spi->dev.power.power_state = PMSG_ON; - spi->mode = SPI_MODE_0; - spi->bits_per_word = 8; - if (!spi->max_speed_hz) - spi->max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ; - spi_setup(spi); + tsc2005_start_scan(ts); - r = tsc2005_setup(ts, pdata); - if (r) { - kfree(ts); - spi_set_drvdata(spi, NULL); + if (ts->esd_timeout && ts->set_reset) { + /* start the optional ESD watchdog */ + mod_timer(&ts->esd_timer, round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); } - return r; + + set_irq_wake(spi->irq, 1); + return 0; + +err_remove_sysfs: + sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); +err_clear_drvdata: + spi_set_drvdata(spi, NULL); + free_irq(spi->irq, ts); +err_free_mem: + input_free_device(input_dev); + kfree(ts); + return error; } static int __devexit tsc2005_remove(struct spi_device *spi) { struct tsc2005 *ts = spi_get_drvdata(spi); + sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); + mutex_lock(&ts->mutex); tsc2005_disable(ts); mutex_unlock(&ts->mutex); @@ -658,7 +654,6 @@ static int __devexit tsc2005_remove(struct spi_device *spi) flush_work(&ts->esd_work); flush_work(&ts->penup_work); - sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); free_irq(ts->spi->irq, ts); input_unregister_device(ts->idev); kfree(ts); -- cgit v1.2.2 From 8dbcc432c2b4adf4ff7183afc5f2b42276b2a987 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:10:37 -0700 Subject: Input: tsc2005 - hide selftest attribute if we can't reset If implementation to perform self-test/reset has not been provided by the platform code hide 'selftest' sysfs attribute instead of returning error when someone tries to use it. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 46 ++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index de170e9dc54a..bc7e2f974b7e 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -411,13 +411,6 @@ static ssize_t tsc2005_selftest_show(struct device *dev, u16 temp_high_test; unsigned int result; - if (!ts->set_reset) { - dev_warn(&ts->spi->dev, - "unable to selftest: no reset function\n"); - result = 0; - goto out; - } - mutex_lock(&ts->mutex); /* @@ -451,11 +444,38 @@ static ssize_t tsc2005_selftest_show(struct device *dev, mutex_unlock(&ts->mutex); -out: return sprintf(buf, "%u\n", result); } + static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); +static struct attribute *tsc2005_attrs[] = { + &dev_attr_disable.attr, + &dev_attr_selftest.attr, + NULL +}; + +static mode_t tsc2005_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct spi_device *spi = to_spi_device(dev); + struct tsc2005 *ts = spi_get_drvdata(spi); + mode_t mode = attr->mode; + + if (attr == &dev_attr_selftest.attr) { + if (!ts->set_reset) + mode = 0; + } + + return mode; +} + +static const struct attribute_group tsc2005_attr_group = { + .is_visible = tsc2005_attr_is_visible, + .attrs = tsc2005_attrs, +}; + static void tsc2005_esd_timer(unsigned long data) { struct tsc2005 *ts = (struct tsc2005 *)data; @@ -495,16 +515,6 @@ out: mutex_unlock(&ts->mutex); } -static struct attribute *tsc2005_attrs[] = { - &dev_attr_disable.attr, - &dev_attr_selftest.attr, - NULL -}; - -static struct attribute_group tsc2005_attr_group = { - .attrs = tsc2005_attrs, -}; - static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) { tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); -- cgit v1.2.2 From c8b6846a7559e64d7ac4ba1ccdba05f3ee2e34e8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:10:46 -0700 Subject: Input: tsc2005 - use true/false for boolean variables Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index bc7e2f974b7e..f457cb95b95b 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -140,7 +140,8 @@ struct tsc2005 { bool disabled; unsigned int disable_depth; - unsigned int pen_down; + + bool pen_down; void (*set_reset)(bool enable); }; @@ -197,7 +198,7 @@ static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) struct spi_message msg; struct tsc2005_spi_rd spi_rd = { { 0 }, 0, 0 }; - tsc2005_setup_read(&spi_rd, reg, 1); + tsc2005_setup_read(&spi_rd, reg, true); spi_message_init(&msg); spi_message_add_tail(&spi_rd.spi_xfer, &msg); @@ -214,13 +215,13 @@ static void tsc2005_update_pen_state(struct tsc2005 *ts, input_report_abs(ts->idev, ABS_PRESSURE, pressure); if (!ts->pen_down) { input_report_key(ts->idev, BTN_TOUCH, !!pressure); - ts->pen_down = 1; + ts->pen_down = true; } } else { input_report_abs(ts->idev, ABS_PRESSURE, 0); if (ts->pen_down) { input_report_key(ts->idev, BTN_TOUCH, 0); - ts->pen_down = 0; + ts->pen_down = false; } } input_sync(ts->idev); @@ -429,9 +430,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev, } /* hardware reset */ - ts->set_reset(0); + ts->set_reset(false); usleep_range(100, 500); /* only 10us required */ - ts->set_reset(1); + ts->set_reset(true); tsc2005_enable(ts); /* test that the reset really happened */ @@ -500,10 +501,10 @@ static void tsc2005_esd_work(struct work_struct *work) tsc2005_read(ts, TSC2005_REG_CFR0, &r); if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) { dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); - ts->set_reset(0); + ts->set_reset(false); tsc2005_update_pen_state(ts, 0, 0, 0); usleep_range(100, 500); /* only 10us required */ - ts->set_reset(1); + ts->set_reset(true); tsc2005_start_scan(ts); } @@ -517,10 +518,10 @@ out: static void __devinit tsc2005_setup_spi_xfer(struct tsc2005 *ts) { - tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, 0); - tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, 0); - tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, 0); - tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, 1); + tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false); + tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false); + tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false); + tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true); spi_message_init(&ts->spi_read_msg); spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg); -- cgit v1.2.2 From 9a6e180af78247e3a7680460240bb450c39d3a5b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:10:52 -0700 Subject: Input: tsc2005 - do not use 0 in place of NULL Sparse in unhappy when people use 0 instead of NULL for pointers so let's rework the way we initialize spi_transfer structure in tsc2005_cmd() and tsc2005_write(). Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index f457cb95b95b..289057e1b9a2 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -148,16 +148,13 @@ struct tsc2005 { static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) { - u8 tx; + u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; + struct spi_transfer xfer = { + .tx_buf = &tx, + .len = 1, + .bits_per_word = 8, + }; struct spi_message msg; - struct spi_transfer xfer = { 0 }; - - tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; - - xfer.tx_buf = &tx; - xfer.rx_buf = NULL; - xfer.len = 1; - xfer.bits_per_word = 8; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -166,17 +163,13 @@ static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) { - u32 tx; + u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; + struct spi_transfer xfer = { + .tx_buf = &tx, + .len = 4, + .bits_per_word = 24, + }; struct spi_message msg; - struct spi_transfer xfer = { 0 }; - - tx = (reg | TSC2005_REG_PND0) << 16; - tx |= value; - - xfer.tx_buf = &tx; - xfer.rx_buf = NULL; - xfer.len = 4; - xfer.bits_per_word = 24; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); @@ -185,6 +178,8 @@ static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) { + memset(rd, 0, sizeof(*rd)); + rd->spi_tx = (reg | TSC2005_REG_READ) << 16; rd->spi_xfer.tx_buf = &rd->spi_tx; rd->spi_xfer.rx_buf = &rd->spi_rx; @@ -195,14 +190,15 @@ static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) { + struct tsc2005_spi_rd spi_rd; struct spi_message msg; - struct tsc2005_spi_rd spi_rd = { { 0 }, 0, 0 }; tsc2005_setup_read(&spi_rd, reg, true); spi_message_init(&msg); spi_message_add_tail(&spi_rd.spi_xfer, &msg); spi_sync(ts->spi, &msg); + *value = spi_rd.spi_rx; } -- cgit v1.2.2 From 80cc2f0c928ddf58051f2809e1c2e7d0172d0291 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:08 -0700 Subject: Input: tsc2005 - don't use work for 'pen up' handling We do not need process context to send input events so let's switch to a regular timer. I am going to get rid of taking ts->mutex in tsc2005_irq_thread() later. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 58 +++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 289057e1b9a2..dc309da59fca 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -129,8 +129,8 @@ struct tsc2005 { int in_z1; int in_z2; + spinlock_t lock; struct timer_list penup_timer; - struct work_struct penup_work; unsigned int esd_timeout; struct timer_list esd_timer; @@ -239,11 +239,10 @@ static irqreturn_t tsc2005_irq_handler(int irq, void *dev_id) static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) { struct tsc2005 *ts = _ts; + unsigned long flags; unsigned int pressure; - u32 x; - u32 y; - u32 z1; - u32 z2; + u32 x, y; + u32 z1, z2; mutex_lock(&ts->mutex); @@ -261,46 +260,50 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) if (unlikely(x > MAX_12BIT || y > MAX_12BIT)) goto out; - /* skip coords if the pressure components are out of range */ + /* Skip reading if the pressure components are out of range */ if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2)) goto out; - /* skip point if this is a pen down with the exact same values as + /* + * Skip point if this is a pen down with the exact same values as * the value before pen-up - that implies SPI fed us stale data */ if (!ts->pen_down && - ts->in_x == x && - ts->in_y == y && - ts->in_z1 == z1 && - ts->in_z2 == z2) + ts->in_x == x && ts->in_y == y && + ts->in_z1 == z1 && ts->in_z2 == z2) { goto out; + } - /* At this point we are happy we have a valid and useful reading. - * Remember it for later comparisons. We may now begin downsampling - */ + /* + * At this point we are happy we have a valid and useful reading. + * Remember it for later comparisons. We may now begin downsampling. + */ ts->in_x = x; ts->in_y = y; ts->in_z1 = z1; ts->in_z2 = z2; - /* compute touch pressure resistance using equation #1 */ + /* Compute touch pressure resistance using equation #1 */ pressure = x * (z2 - z1) / z1; pressure = pressure * ts->x_plate_ohm / 4096; if (unlikely(pressure > MAX_12BIT)) goto out; + spin_lock_irqsave(&ts->lock, flags); + tsc2005_update_pen_state(ts, x, y, pressure); /* set the penup timer */ mod_timer(&ts->penup_timer, jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); - if (!ts->esd_timeout) - goto out; + if (ts->esd_timeout && ts->set_reset) { + /* update the watchdog timer */ + mod_timer(&ts->esd_timer, round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); + } - /* update the watchdog timer */ - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + spin_unlock_irqrestore(&ts->lock, flags); out: mutex_unlock(&ts->mutex); @@ -310,17 +313,11 @@ out: static void tsc2005_penup_timer(unsigned long data) { struct tsc2005 *ts = (struct tsc2005 *)data; + unsigned long flags; - schedule_work(&ts->penup_work); -} - -static void tsc2005_penup_work(struct work_struct *work) -{ - struct tsc2005 *ts = container_of(work, struct tsc2005, penup_work); - - mutex_lock(&ts->mutex); + spin_lock_irqsave(&ts->lock, flags); tsc2005_update_pen_state(ts, 0, 0, 0); - mutex_unlock(&ts->mutex); + spin_unlock_irqrestore(&ts->lock, flags); } static void tsc2005_start_scan(struct tsc2005 *ts) @@ -577,8 +574,8 @@ static int __devinit tsc2005_probe(struct spi_device *spi) mutex_init(&ts->mutex); + spin_lock_init(&ts->lock); setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); - INIT_WORK(&ts->penup_work, tsc2005_penup_work); setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); INIT_WORK(&ts->esd_work, tsc2005_esd_work); @@ -659,7 +656,6 @@ static int __devexit tsc2005_remove(struct spi_device *spi) del_timer_sync(&ts->penup_timer); flush_work(&ts->esd_work); - flush_work(&ts->penup_work); free_irq(ts->spi->irq, ts); input_unregister_device(ts->idev); -- cgit v1.2.2 From dacb650f125c7dc7ead9735d081bc078325b6d23 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:14 -0700 Subject: Input: tsc2005 - do not rearm timer in hardirq handler We will most likely rearm it yet again the IRQ thread so doing it here is pointless. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index dc309da59fca..7a7653390187 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -225,17 +225,6 @@ static void tsc2005_update_pen_state(struct tsc2005 *ts, pressure); } -static irqreturn_t tsc2005_irq_handler(int irq, void *dev_id) -{ - struct tsc2005 *ts = dev_id; - - /* update the penup timer only if it's pending */ - mod_timer_pending(&ts->penup_timer, - jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); - - return IRQ_WAKE_THREAD; -} - static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) { struct tsc2005 *ts = _ts; @@ -596,8 +585,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); - error = request_threaded_irq(spi->irq, - tsc2005_irq_handler, tsc2005_irq_thread, + error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, IRQF_TRIGGER_RISING, "tsc2005", ts); if (error) { dev_err(&spi->dev, "Failed to request irq, err: %d\n", error); -- cgit v1.2.2 From 71f80045d48f259ea423bae3c14c2361e010a9ce Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:25 -0700 Subject: Input: tsc2005 - handle read errors from SPI layer Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 100 +++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 7a7653390187..5a15919ec4c7 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -146,7 +146,7 @@ struct tsc2005 { void (*set_reset)(bool enable); }; -static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) +static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd) { u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd; struct spi_transfer xfer = { @@ -155,13 +155,22 @@ static void tsc2005_cmd(struct tsc2005 *ts, u8 cmd) .bits_per_word = 8, }; struct spi_message msg; + int error; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); - spi_sync(ts->spi, &msg); + + error = spi_sync(ts->spi, &msg); + if (error) { + dev_err(&ts->spi->dev, "%s: failed, command: %x, error: %d\n", + __func__, cmd, error); + return error; + } + + return 0; } -static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) +static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) { u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; struct spi_transfer xfer = { @@ -170,10 +179,20 @@ static void tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) .bits_per_word = 24, }; struct spi_message msg; + int error; spi_message_init(&msg); spi_message_add_tail(&xfer, &msg); - spi_sync(ts->spi, &msg); + + error = spi_sync(ts->spi, &msg); + if (error) { + dev_err(&ts->spi->dev, + "%s: failed, register: %x, value: %x, error: %d\n", + __func__, reg, value, error); + return error; + } + + return 0; } static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) @@ -188,18 +207,23 @@ static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) rd->spi_xfer.cs_change = !last; } -static void tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) +static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) { struct tsc2005_spi_rd spi_rd; struct spi_message msg; + int error; tsc2005_setup_read(&spi_rd, reg, true); spi_message_init(&msg); spi_message_add_tail(&spi_rd.spi_xfer, &msg); - spi_sync(ts->spi, &msg); + + error = spi_sync(ts->spi, &msg); + if (error) + return error; *value = spi_rd.spi_rx; + return 0; } static void tsc2005_update_pen_state(struct tsc2005 *ts, @@ -232,6 +256,7 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) unsigned int pressure; u32 x, y; u32 z1, z2; + int error; mutex_lock(&ts->mutex); @@ -239,7 +264,10 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) goto out; /* read the coordinates */ - spi_sync(ts->spi, &ts->spi_read_msg); + error = spi_sync(ts->spi, &ts->spi_read_msg); + if (unlikely(error)) + goto out; + x = ts->spi_x.spi_rx; y = ts->spi_y.spi_rx; z1 = ts->spi_z1.spi_rx; @@ -392,7 +420,8 @@ static ssize_t tsc2005_selftest_show(struct device *dev, u16 temp_high; u16 temp_high_orig; u16 temp_high_test; - unsigned int result; + bool success = true; + int error; mutex_lock(&ts->mutex); @@ -400,34 +429,65 @@ static ssize_t tsc2005_selftest_show(struct device *dev, * Test TSC2005 communications via temp high register. */ tsc2005_disable(ts); - result = 1; - tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + + error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + if (error) { + dev_warn(dev, "selftest failed: read error %d\n", error); + success = false; + goto out; + } + temp_high_test = (temp_high_orig - 1) & MAX_12BIT; - tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); - tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + + error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); + if (error) { + dev_warn(dev, "selftest failed: write error %d\n", error); + success = false; + goto out; + } + + error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (error) { + dev_warn(dev, "selftest failed: read error %d after write\n", + error); + success = false; + goto out; + } + if (temp_high != temp_high_test) { dev_warn(dev, "selftest failed: %d != %d\n", temp_high, temp_high_test); - result = 0; + success = false; } /* hardware reset */ ts->set_reset(false); usleep_range(100, 500); /* only 10us required */ ts->set_reset(true); - tsc2005_enable(ts); + + if (!success) + goto out; /* test that the reset really happened */ - tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + if (error) { + dev_warn(dev, "selftest failed: read error %d after reset\n", + error); + success = false; + goto out; + } + if (temp_high != temp_high_orig) { dev_warn(dev, "selftest failed after reset: %d != %d\n", temp_high, temp_high_orig); - result = 0; + success = false; } +out: + tsc2005_enable(ts); mutex_unlock(&ts->mutex); - return sprintf(buf, "%u\n", result); + return sprintf(buf, "%d\n", success); } static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); @@ -469,6 +529,7 @@ static void tsc2005_esd_timer(unsigned long data) static void tsc2005_esd_work(struct work_struct *work) { struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); + int error; u16 r; mutex_lock(&ts->mutex); @@ -480,8 +541,9 @@ static void tsc2005_esd_work(struct work_struct *work) * If we cannot read our known value from configuration register 0 then * reset the controller as if from power-up and start scanning again. */ - tsc2005_read(ts, TSC2005_REG_CFR0, &r); - if ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK) { + error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); + if (error || + ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); ts->set_reset(false); tsc2005_update_pen_state(ts, 0, 0, 0); -- cgit v1.2.2 From 0b950d3d7ce4c1e870b8efc4ae0faaf0ef53532c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:34 -0700 Subject: Input: tsc2005 - add open/close Introduce open and close methods for the input device to keep the device powered down when it is not in use. Also rework interaction between interrupt thread and starting/shutting off/resetting the device: instead of taking a mutex in the intterrupt thread and elsewhere disable interrupts before transitioning the device in a new state. The ESD handling is also separated from the IRQ thread; we poll regularly at a given interval and simply skip reads if we see that valid interrupt happened not so long ago. This allows us not cancel and reschedule ESD work from interrupt context all the time. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 218 ++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 5a15919ec4c7..3e1c9c297f33 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -133,13 +133,14 @@ struct tsc2005 { struct timer_list penup_timer; unsigned int esd_timeout; - struct timer_list esd_timer; - struct work_struct esd_work; + struct delayed_work esd_work; + unsigned long last_valid_interrupt; unsigned int x_plate_ohm; bool disabled; - unsigned int disable_depth; + bool opened; + bool suspended; bool pen_down; @@ -258,11 +259,6 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) u32 z1, z2; int error; - mutex_lock(&ts->mutex); - - if (unlikely(ts->disable_depth)) - goto out; - /* read the coordinates */ error = spi_sync(ts->spi, &ts->spi_read_msg); if (unlikely(error)) @@ -309,21 +305,13 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) spin_lock_irqsave(&ts->lock, flags); tsc2005_update_pen_state(ts, x, y, pressure); - - /* set the penup timer */ mod_timer(&ts->penup_timer, jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); - if (ts->esd_timeout && ts->set_reset) { - /* update the watchdog timer */ - mod_timer(&ts->esd_timer, round_jiffies(jiffies + - msecs_to_jiffies(ts->esd_timeout))); - } - spin_unlock_irqrestore(&ts->lock, flags); + ts->last_valid_interrupt = jiffies; out: - mutex_unlock(&ts->mutex); return IRQ_HANDLED; } @@ -350,29 +338,31 @@ static void tsc2005_stop_scan(struct tsc2005 *ts) tsc2005_cmd(ts, TSC2005_CMD_STOP); } -/* must be called with mutex held */ -static void tsc2005_disable(struct tsc2005 *ts) +/* must be called with ts->mutex held */ +static void __tsc2005_disable(struct tsc2005 *ts) { - if (ts->disable_depth++ != 0) - return; + tsc2005_stop_scan(ts); + disable_irq(ts->spi->irq); - if (ts->esd_timeout) - del_timer_sync(&ts->esd_timer); del_timer_sync(&ts->penup_timer); - tsc2005_stop_scan(ts); + + cancel_delayed_work_sync(&ts->esd_work); + + enable_irq(ts->spi->irq); } -/* must be called with mutex held */ -static void tsc2005_enable(struct tsc2005 *ts) +/* must be called with ts->mutex held */ +static void __tsc2005_enable(struct tsc2005 *ts) { - if (--ts->disable_depth != 0) - return; tsc2005_start_scan(ts); - enable_irq(ts->spi->irq); - if (!ts->esd_timeout) - return; - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + + if (ts->esd_timeout && ts->set_reset) { + ts->last_valid_interrupt = jiffies; + schedule_delayed_work(&ts->esd_work, + round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); + } + } static ssize_t tsc2005_disable_show(struct device *dev, @@ -390,23 +380,29 @@ static ssize_t tsc2005_disable_store(struct device *dev, { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); - unsigned long res; - int i; + unsigned long val; + int error; - if (strict_strtoul(buf, 10, &res) < 0) - return -EINVAL; - i = res ? 1 : 0; + error = strict_strtoul(buf, 10, &val); + if (error) + return error; mutex_lock(&ts->mutex); - if (i == ts->disabled) - goto out; - ts->disabled = i; - if (i) - tsc2005_disable(ts); - else - tsc2005_enable(ts); -out: + + if (!ts->suspended && ts->opened) { + if (val) { + if (!ts->disabled) + __tsc2005_disable(ts); + } else { + if (ts->disabled) + __tsc2005_enable(ts); + } + } + + ts->disabled = !!val; + mutex_unlock(&ts->mutex); + return count; } static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); @@ -428,7 +424,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, /* * Test TSC2005 communications via temp high register. */ - tsc2005_disable(ts); + __tsc2005_disable(ts); error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); if (error) { @@ -484,7 +480,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, } out: - tsc2005_enable(ts); + __tsc2005_enable(ts); mutex_unlock(&ts->mutex); return sprintf(buf, "%d\n", success); @@ -519,44 +515,79 @@ static const struct attribute_group tsc2005_attr_group = { .attrs = tsc2005_attrs, }; -static void tsc2005_esd_timer(unsigned long data) -{ - struct tsc2005 *ts = (struct tsc2005 *)data; - - schedule_work(&ts->esd_work); -} - static void tsc2005_esd_work(struct work_struct *work) { - struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work); + struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work); int error; u16 r; mutex_lock(&ts->mutex); - if (ts->disable_depth) + if (time_is_after_jiffies(ts->last_valid_interrupt + + msecs_to_jiffies(ts->esd_timeout))) goto out; - /* - * If we cannot read our known value from configuration register 0 then - * reset the controller as if from power-up and start scanning again. - */ + /* We should be able to read register without disabling interrupts. */ error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); - if (error || - ((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { - dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); - ts->set_reset(false); - tsc2005_update_pen_state(ts, 0, 0, 0); - usleep_range(100, 500); /* only 10us required */ - ts->set_reset(true); - tsc2005_start_scan(ts); + if (!error && + !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { + goto out; } - /* re-arm the watchdog */ - mod_timer(&ts->esd_timer, - round_jiffies(jiffies + msecs_to_jiffies(ts->esd_timeout))); + /* + * If we could not read our known value from configuration register 0 + * then we should reset the controller as if from power-up and start + * scanning again. + */ + dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n"); + + disable_irq(ts->spi->irq); + del_timer_sync(&ts->penup_timer); + + tsc2005_update_pen_state(ts, 0, 0, 0); + + ts->set_reset(false); + usleep_range(100, 500); /* only 10us required */ + ts->set_reset(true); + + enable_irq(ts->spi->irq); + tsc2005_start_scan(ts); out: + /* re-arm the watchdog */ + schedule_delayed_work(&ts->esd_work, + round_jiffies(jiffies + + msecs_to_jiffies(ts->esd_timeout))); + mutex_unlock(&ts->mutex); +} + +static int tsc2005_open(struct input_dev *input) +{ + struct tsc2005 *ts = input_get_drvdata(input); + + mutex_lock(&ts->mutex); + + if (!ts->suspended && !ts->disabled) + __tsc2005_enable(ts); + + ts->opened = true; + + mutex_unlock(&ts->mutex); + + return 0; +} + +static void tsc2005_close(struct input_dev *input) +{ + struct tsc2005 *ts = input_get_drvdata(input); + + mutex_lock(&ts->mutex); + + if (!ts->suspended && !ts->disabled) + __tsc2005_disable(ts); + + ts->opened = false; + mutex_unlock(&ts->mutex); } @@ -628,8 +659,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) spin_lock_init(&ts->lock); setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts); - setup_timer(&ts->esd_timer, tsc2005_esd_timer, (unsigned long)ts); - INIT_WORK(&ts->esd_work, tsc2005_esd_work); + INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work); tsc2005_setup_spi_xfer(ts); @@ -647,6 +677,14 @@ static int __devinit tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); + input_dev->open = tsc2005_open; + input_dev->close = tsc2005_close; + + input_set_drvdata(input_dev, ts); + + /* Ensure the touchscreen is off */ + tsc2005_stop_scan(ts); + error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread, IRQF_TRIGGER_RISING, "tsc2005", ts); if (error) { @@ -669,14 +707,6 @@ static int __devinit tsc2005_probe(struct spi_device *spi) goto err_remove_sysfs; } - tsc2005_start_scan(ts); - - if (ts->esd_timeout && ts->set_reset) { - /* start the optional ESD watchdog */ - mod_timer(&ts->esd_timer, round_jiffies(jiffies + - msecs_to_jiffies(ts->esd_timeout))); - } - set_irq_wake(spi->irq, 1); return 0; @@ -697,16 +727,6 @@ static int __devexit tsc2005_remove(struct spi_device *spi) sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group); - mutex_lock(&ts->mutex); - tsc2005_disable(ts); - mutex_unlock(&ts->mutex); - - if (ts->esd_timeout) - del_timer_sync(&ts->esd_timer); - del_timer_sync(&ts->penup_timer); - - flush_work(&ts->esd_work); - free_irq(ts->spi->irq, ts); input_unregister_device(ts->idev); kfree(ts); @@ -722,7 +742,12 @@ static int tsc2005_suspend(struct device *dev) struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); - tsc2005_disable(ts); + + if (!ts->suspended && !ts->disabled && ts->opened) + __tsc2005_disable(ts); + + ts->suspended = true; + mutex_unlock(&ts->mutex); return 0; @@ -734,7 +759,12 @@ static int tsc2005_resume(struct device *dev) struct tsc2005 *ts = spi_get_drvdata(spi); mutex_lock(&ts->mutex); - tsc2005_enable(ts); + + if (ts->suspended && !ts->disabled && ts->opened) + __tsc2005_enable(ts); + + ts->suspended = false; + mutex_unlock(&ts->mutex); return 0; -- cgit v1.2.2 From 5cb81d19bae47adcb073a5e5a3bc40dd252f239e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 16 Mar 2011 22:11:41 -0700 Subject: Input: tsc2005 - remove 'disable' sysfs attribute I believe that enable/disable functionality should not be implemented on the individual driver level but rather in device core, potentially reusing parts of PM framework. Therefore the driver-specific "disable" attribute is removed from the mainline driver. Tested-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 52 +++---------------------------------- 1 file changed, 4 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 3e1c9c297f33..87420616efa4 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -138,7 +138,6 @@ struct tsc2005 { unsigned int x_plate_ohm; - bool disabled; bool opened; bool suspended; @@ -365,48 +364,6 @@ static void __tsc2005_enable(struct tsc2005 *ts) } -static ssize_t tsc2005_disable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); - - return sprintf(buf, "%u\n", ts->disabled); -} - -static ssize_t tsc2005_disable_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); - unsigned long val; - int error; - - error = strict_strtoul(buf, 10, &val); - if (error) - return error; - - mutex_lock(&ts->mutex); - - if (!ts->suspended && ts->opened) { - if (val) { - if (!ts->disabled) - __tsc2005_disable(ts); - } else { - if (ts->disabled) - __tsc2005_enable(ts); - } - } - - ts->disabled = !!val; - - mutex_unlock(&ts->mutex); - - return count; -} -static DEVICE_ATTR(disable, 0664, tsc2005_disable_show, tsc2005_disable_store); - static ssize_t tsc2005_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -489,7 +446,6 @@ out: static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL); static struct attribute *tsc2005_attrs[] = { - &dev_attr_disable.attr, &dev_attr_selftest.attr, NULL }; @@ -567,7 +523,7 @@ static int tsc2005_open(struct input_dev *input) mutex_lock(&ts->mutex); - if (!ts->suspended && !ts->disabled) + if (!ts->suspended) __tsc2005_enable(ts); ts->opened = true; @@ -583,7 +539,7 @@ static void tsc2005_close(struct input_dev *input) mutex_lock(&ts->mutex); - if (!ts->suspended && !ts->disabled) + if (!ts->suspended) __tsc2005_disable(ts); ts->opened = false; @@ -743,7 +699,7 @@ static int tsc2005_suspend(struct device *dev) mutex_lock(&ts->mutex); - if (!ts->suspended && !ts->disabled && ts->opened) + if (!ts->suspended && ts->opened) __tsc2005_disable(ts); ts->suspended = true; @@ -760,7 +716,7 @@ static int tsc2005_resume(struct device *dev) mutex_lock(&ts->mutex); - if (ts->suspended && !ts->disabled && ts->opened) + if (ts->suspended && ts->opened) __tsc2005_enable(ts); ts->suspended = false; -- cgit v1.2.2 From a91a2785b200864aef2270ed6a3babac7a253a20 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Thu, 17 Mar 2011 11:11:05 +0100 Subject: block: Require subsystems to explicitly allocate bio_set integrity mempool MD and DM create a new bio_set for every metadevice. Each bio_set has an integrity mempool attached regardless of whether the metadevice is capable of passing integrity metadata. This is a waste of memory. Instead we defer the allocation decision to MD and DM since we know at metadevice creation time whether integrity passthrough is needed or not. Automatic integrity mempool allocation can then be removed from bioset_create() and we make an explicit integrity allocation for the fs_bio_set. Signed-off-by: Martin K. Petersen Reported-by: Zdenek Kabelac Acked-by: Mike Snitzer Signed-off-by: Jens Axboe --- drivers/md/dm-table.c | 7 +++++-- drivers/md/dm.c | 12 +++++++++--- drivers/md/dm.h | 2 +- drivers/md/linear.c | 3 +-- drivers/md/md.c | 8 ++++++-- drivers/md/multipath.c | 7 +++++-- drivers/md/raid0.c | 3 +-- drivers/md/raid1.c | 5 ++--- drivers/md/raid10.c | 7 +++++-- 9 files changed, 35 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index f50a7b952257..416d4e258df6 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -55,6 +55,7 @@ struct dm_table { struct dm_target *targets; unsigned discards_supported:1; + unsigned integrity_supported:1; /* * Indicates the rw permissions for the new logical @@ -859,7 +860,7 @@ int dm_table_alloc_md_mempools(struct dm_table *t) return -EINVAL; } - t->mempools = dm_alloc_md_mempools(type); + t->mempools = dm_alloc_md_mempools(type, t->integrity_supported); if (!t->mempools) return -ENOMEM; @@ -935,8 +936,10 @@ static int dm_table_prealloc_integrity(struct dm_table *t, struct mapped_device struct dm_dev_internal *dd; list_for_each_entry(dd, devices, list) - if (bdev_get_integrity(dd->dm_dev.bdev)) + if (bdev_get_integrity(dd->dm_dev.bdev)) { + t->integrity_supported = 1; return blk_integrity_register(dm_disk(md), NULL); + } return 0; } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index d22b9905c168..88820704a191 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -2620,9 +2620,10 @@ int dm_noflush_suspending(struct dm_target *ti) } EXPORT_SYMBOL_GPL(dm_noflush_suspending); -struct dm_md_mempools *dm_alloc_md_mempools(unsigned type) +struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity) { struct dm_md_mempools *pools = kmalloc(sizeof(*pools), GFP_KERNEL); + unsigned int pool_size = (type == DM_TYPE_BIO_BASED) ? 16 : MIN_IOS; if (!pools) return NULL; @@ -2639,13 +2640,18 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type) if (!pools->tio_pool) goto free_io_pool_and_out; - pools->bs = (type == DM_TYPE_BIO_BASED) ? - bioset_create(16, 0) : bioset_create(MIN_IOS, 0); + pools->bs = bioset_create(pool_size, 0); if (!pools->bs) goto free_tio_pool_and_out; + if (integrity && bioset_integrity_create(pools->bs, pool_size)) + goto free_bioset_and_out; + return pools; +free_bioset_and_out: + bioset_free(pools->bs); + free_tio_pool_and_out: mempool_destroy(pools->tio_pool); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 0c2dd5f4af76..1aaf16746da8 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -149,7 +149,7 @@ void dm_kcopyd_exit(void); /* * Mempool operations */ -struct dm_md_mempools *dm_alloc_md_mempools(unsigned type); +struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity); void dm_free_md_mempools(struct dm_md_mempools *pools); #endif diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 338804f8fb3b..abfb59a61ede 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -210,8 +210,7 @@ static int linear_run (mddev_t *mddev) blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec); mddev->queue->backing_dev_info.congested_fn = linear_congested; mddev->queue->backing_dev_info.congested_data = mddev; - md_integrity_register(mddev); - return 0; + return md_integrity_register(mddev); } static void free_conf(struct rcu_head *head) diff --git a/drivers/md/md.c b/drivers/md/md.c index 86ba66c0b28a..1876761f1828 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1803,8 +1803,12 @@ int md_integrity_register(mddev_t *mddev) mdname(mddev)); return -EINVAL; } - printk(KERN_NOTICE "md: data integrity on %s enabled\n", - mdname(mddev)); + printk(KERN_NOTICE "md: data integrity enabled on %s\n", mdname(mddev)); + if (bioset_integrity_create(mddev->bio_set, BIO_POOL_SIZE)) { + printk(KERN_ERR "md: failed to create integrity pool for %s\n", + mdname(mddev)); + return -EINVAL; + } return 0; } EXPORT_SYMBOL(md_integrity_register); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 5e694b151c30..c35890990985 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -315,7 +315,7 @@ static int multipath_remove_disk(mddev_t *mddev, int number) p->rdev = rdev; goto abort; } - md_integrity_register(mddev); + err = md_integrity_register(mddev); } abort: @@ -489,7 +489,10 @@ static int multipath_run (mddev_t *mddev) mddev->queue->backing_dev_info.congested_fn = multipath_congested; mddev->queue->backing_dev_info.congested_data = mddev; - md_integrity_register(mddev); + + if (md_integrity_register(mddev)) + goto out_free_conf; + return 0; out_free_conf: diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 95916fd6394a..e86bf3682e1e 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -379,8 +379,7 @@ static int raid0_run(mddev_t *mddev) blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec); dump_zones(mddev); - md_integrity_register(mddev); - return 0; + return md_integrity_register(mddev); } static int raid0_stop(mddev_t *mddev) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 8f34ad5c478b..c2a21ae56d97 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1132,7 +1132,7 @@ static int raid1_remove_disk(mddev_t *mddev, int number) p->rdev = rdev; goto abort; } - md_integrity_register(mddev); + err = md_integrity_register(mddev); } abort: @@ -2017,8 +2017,7 @@ static int run(mddev_t *mddev) mddev->queue->backing_dev_info.congested_fn = raid1_congested; mddev->queue->backing_dev_info.congested_data = mddev; - md_integrity_register(mddev); - return 0; + return md_integrity_register(mddev); } static int stop(mddev_t *mddev) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c0d0f5f7e407..f7b62370b374 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1188,7 +1188,7 @@ static int raid10_remove_disk(mddev_t *mddev, int number) p->rdev = rdev; goto abort; } - md_integrity_register(mddev); + err = md_integrity_register(mddev); } abort: @@ -2343,7 +2343,10 @@ static int run(mddev_t *mddev) if (conf->near_copies < conf->raid_disks) blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec); - md_integrity_register(mddev); + + if (md_integrity_register(mddev)) + goto out_free_conf; + return 0; out_free_conf: -- cgit v1.2.2 From 8ec3b8432e4fe8d452f88f1ed9a3450e715bb797 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:36 -0800 Subject: char: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/char/mwave/Makefile | 4 ++-- drivers/char/mwave/README | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/mwave/Makefile b/drivers/char/mwave/Makefile index 26b4fce217b6..efa6a82e543d 100644 --- a/drivers/char/mwave/Makefile +++ b/drivers/char/mwave/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_MWAVE) += mwave.o mwave-y := mwavedd.o smapi.o tp3780i.o 3780i.o # To have the mwave driver disable other uarts if necessary -# EXTRA_CFLAGS += -DMWAVE_FUTZ_WITH_OTHER_DEVICES +# ccflags-y := -DMWAVE_FUTZ_WITH_OTHER_DEVICES # To compile in lots (~20 KiB) of run-time enablable printk()s for debugging: -ccflags-y := -DMW_TRACE +ccflags-y += -DMW_TRACE diff --git a/drivers/char/mwave/README b/drivers/char/mwave/README index 480251fc78e2..c2a58f428bc8 100644 --- a/drivers/char/mwave/README +++ b/drivers/char/mwave/README @@ -11,7 +11,7 @@ are not saved by the BIOS and so do not persist after unload and reload. 0x0008 tp3780i tracing Tracing only occurs if the driver has been compiled with the - MW_TRACE macro #defined (i.e. let EXTRA_CFLAGS += -DMW_TRACE + MW_TRACE macro #defined (i.e. let ccflags-y := -DMW_TRACE in the Makefile). mwave_3780i_irq=5/7/10/11/15 -- cgit v1.2.2 From 990710ca5ddf28aef9c34594b3ffe71544e5faa4 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:37 -0800 Subject: dma: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/dma/Makefile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 64b21f5cd740..1be065a62f8c 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -1,9 +1,5 @@ -ifeq ($(CONFIG_DMADEVICES_DEBUG),y) - ccflags-y += -DDEBUG -endif -ifeq ($(CONFIG_DMADEVICES_VDEBUG),y) - ccflags-y += -DVERBOSE_DEBUG -endif +ccflags-$(CONFIG_DMADEVICES_DEBUG) := -DDEBUG +ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG obj-$(CONFIG_DMA_ENGINE) += dmaengine.o obj-$(CONFIG_NET_DMA) += iovlock.o -- cgit v1.2.2 From 5c39e31195f49f6725f04b22921eca2388a3f909 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:38 -0800 Subject: hwmon: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Acked-by: Guenter Roeck Signed-off-by: Michal Marek --- drivers/hwmon/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index dde02d99c238..974f9cc766b2 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -112,7 +112,5 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o -ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG -- cgit v1.2.2 From 732f36d82fc4acfd2fa77c939494edeee390b080 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:39 -0800 Subject: ide: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Acked-by: David S. Miller Signed-off-by: Michal Marek --- drivers/ide/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index 81df925f0e8b..7f879b2397b0 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -2,7 +2,7 @@ # link order is important here # -EXTRA_CFLAGS += -Idrivers/ide +ccflags-y := -Idrivers/ide ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \ ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \ -- cgit v1.2.2 From 76e150392402c154036db94fcc295469fce48c66 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:40 -0800 Subject: ieee802154: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Acked-by: Dmitry Eremin-Solenikov Signed-off-by: Michal Marek --- drivers/ieee802154/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile index e0e8e1a184ff..68999137dedf 100644 --- a/drivers/ieee802154/Makefile +++ b/drivers/ieee802154/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o -EXTRA_CFLAGS += -DDEBUG -DCONFIG_FFD +ccflags-y := -DDEBUG -DCONFIG_FFD -- cgit v1.2.2 From f656c25b71b986b98dce2f8d268524f792b7e43f Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:41 -0800 Subject: isdn: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Acked-by: David S. Miller Signed-off-by: Michal Marek --- drivers/isdn/hisax/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile index ab638b083df9..646368fe41c9 100644 --- a/drivers/isdn/hisax/Makefile +++ b/drivers/isdn/hisax/Makefile @@ -4,7 +4,7 @@ # Define maximum number of cards -EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) +ccflags-y := -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o -- cgit v1.2.2 From 41d9c644fc4dd5fa399682c0f8d0d1f79b77a199 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:42 -0800 Subject: memstick: change to new flag variable The EXTRA_CFLAGS assignment in memstick/Makefile was not accomplishing anything because this flag only has effect on sources at the same level as the makefile (i.e., per directory). Since both core/ and host/ rely on MEMSTICK_DEBUG, the subdir-ccflags-y variant seems to be the appropriate choice. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/memstick/Makefile | 4 +--- drivers/memstick/core/Makefile | 4 ---- drivers/memstick/host/Makefile | 4 ---- 3 files changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/Makefile b/drivers/memstick/Makefile index dc160fb43515..98623590c7fe 100644 --- a/drivers/memstick/Makefile +++ b/drivers/memstick/Makefile @@ -2,9 +2,7 @@ # Makefile for the kernel MemoryStick device drivers. # -ifeq ($(CONFIG_MEMSTICK_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif +subdir-ccflags-$(CONFIG_MEMSTICK_DEBUG) := -DDEBUG obj-$(CONFIG_MEMSTICK) += core/ obj-$(CONFIG_MEMSTICK) += host/ diff --git a/drivers/memstick/core/Makefile b/drivers/memstick/core/Makefile index 8b2b5293877e..ecd029937738 100644 --- a/drivers/memstick/core/Makefile +++ b/drivers/memstick/core/Makefile @@ -2,10 +2,6 @@ # Makefile for the kernel MemoryStick core. # -ifeq ($(CONFIG_MEMSTICK_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif - obj-$(CONFIG_MEMSTICK) += memstick.o obj-$(CONFIG_MSPRO_BLOCK) += mspro_block.o diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index 12530e4311d3..a1815e9dd019 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile @@ -2,9 +2,5 @@ # Makefile for MemoryStick host controller drivers # -ifeq ($(CONFIG_MEMSTICK_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif - obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o -- cgit v1.2.2 From d100d406044b76475c7baec72ab6770306ea1a8d Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:43 -0800 Subject: message: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/message/fusion/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile index 95c9532cb07c..d182a24b3195 100644 --- a/drivers/message/fusion/Makefile +++ b/drivers/message/fusion/Makefile @@ -2,7 +2,7 @@ # enable verbose logging # CONFIG_FUSION_LOGGING needs to be enabled in Kconfig -#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE +#ccflags-y := -DMPT_DEBUG_VERBOSE #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC -- cgit v1.2.2 From 8ac727c1e65ba98fc2d82bb28288312cc3b7473b Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:44 -0800 Subject: misc: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/misc/cb710/Makefile | 4 +--- drivers/misc/sgi-gru/Makefile | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cb710/Makefile b/drivers/misc/cb710/Makefile index 7b80cbf1a609..467c8e9ca3c9 100644 --- a/drivers/misc/cb710/Makefile +++ b/drivers/misc/cb710/Makefile @@ -1,6 +1,4 @@ -ifeq ($(CONFIG_CB710_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_CB710_DEBUG) := -DDEBUG obj-$(CONFIG_CB710_CORE) += cb710.o diff --git a/drivers/misc/sgi-gru/Makefile b/drivers/misc/sgi-gru/Makefile index 7c4c306dfa8a..0003a1d56f7f 100644 --- a/drivers/misc/sgi-gru/Makefile +++ b/drivers/misc/sgi-gru/Makefile @@ -1,6 +1,4 @@ -ifdef CONFIG_SGI_GRU_DEBUG - EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_SGI_GRU_DEBUG) := -DDEBUG obj-$(CONFIG_SGI_GRU) := gru.o gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o grukdump.o -- cgit v1.2.2 From 5a8b7cdc7424d63467cff1d20461acf48ffcb72f Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:45 -0800 Subject: net: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Acked-by: Sjur Braendeland Acked-by: David S. Miller Acked-by: John W. Linville Signed-off-by: Michal Marek --- drivers/net/caif/Makefile | 4 +--- drivers/net/skfp/Makefile | 2 +- drivers/net/wan/lmc/Makefile | 2 +- drivers/net/wireless/hostap/hostap_config.h | 4 ++-- drivers/net/wireless/zd1211rw/Makefile | 4 +--- 5 files changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile index b38d987da67d..9560b9d624bd 100644 --- a/drivers/net/caif/Makefile +++ b/drivers/net/caif/Makefile @@ -1,6 +1,4 @@ -ifeq ($(CONFIG_CAIF_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_CAIF_DEBUG) := -DDEBUG # Serial interface obj-$(CONFIG_CAIF_TTY) += caif_serial.o diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile index cb23580fcffa..b0be0234abf6 100644 --- a/drivers/net/skfp/Makefile +++ b/drivers/net/skfp/Makefile @@ -17,4 +17,4 @@ skfp-objs := skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ # projects. To keep the source common for all those drivers (and # thus simplify fixes to it), please do not clean it up! -EXTRA_CFLAGS += -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes +ccflags-y := -Idrivers/net/skfp -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes diff --git a/drivers/net/wan/lmc/Makefile b/drivers/net/wan/lmc/Makefile index dabdcfed4efd..609710d64eb5 100644 --- a/drivers/net/wan/lmc/Makefile +++ b/drivers/net/wan/lmc/Makefile @@ -14,4 +14,4 @@ lmc-objs := lmc_debug.o lmc_media.o lmc_main.o lmc_proto.o # -DDEBUG \ # -DLMC_PACKET_LOG -EXTRA_CFLAGS += -I. $(DBGDEF) +ccflags-y := -I. $(DBGDEF) diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h index 30acd39d76a2..2c8f71f0ed45 100644 --- a/drivers/net/wireless/hostap/hostap_config.h +++ b/drivers/net/wireless/hostap/hostap_config.h @@ -30,9 +30,9 @@ /* Following defines can be used to remove unneeded parts of the driver, e.g., * to limit the size of the kernel module. Definitions can be added here in - * hostap_config.h or they can be added to make command with EXTRA_CFLAGS, + * hostap_config.h or they can be added to make command with ccflags-y, * e.g., - * 'make pccard EXTRA_CFLAGS="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' + * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' */ /* Do not include debug messages into the driver */ diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index 1907eafb9b16..5728a918e508 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -5,7 +5,5 @@ zd1211rw-objs := zd_chip.o zd_mac.o \ zd_rf_al7230b.o zd_rf_uw2453.o \ zd_rf.o zd_usb.o -ifeq ($(CONFIG_ZD1211RW_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_ZD1211RW_DEBUG) := -DDEBUG -- cgit v1.2.2 From 26a082dc5334ee003167bb9feeee681c150e5b11 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:46 -0800 Subject: pps: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/pps/clients/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile index 42517da07049..4feb7e9e71ee 100644 --- a/drivers/pps/clients/Makefile +++ b/drivers/pps/clients/Makefile @@ -6,6 +6,4 @@ obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o -ifeq ($(CONFIG_PPS_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG -- cgit v1.2.2 From 4ebdd58f46d305c2ab382b6193d4ed0cd201b0dc Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:47 -0800 Subject: rapidio: change to new flag variable switches/ depends on RAPIDIO_DEBUG so the subdir-ccflags-y variant seems to be appropriate here. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/rapidio/Makefile | 4 +--- drivers/rapidio/switches/Makefile | 4 ---- 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/Makefile b/drivers/rapidio/Makefile index b6139fe187bf..89b8eca825b5 100644 --- a/drivers/rapidio/Makefile +++ b/drivers/rapidio/Makefile @@ -5,6 +5,4 @@ obj-y += rio.o rio-access.o rio-driver.o rio-scan.o rio-sysfs.o obj-$(CONFIG_RAPIDIO) += switches/ -ifeq ($(CONFIG_RAPIDIO_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif +subdir-ccflags-$(CONFIG_RAPIDIO_DEBUG) := -DDEBUG diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile index 48d67a6b98c8..c4d3acc3c715 100644 --- a/drivers/rapidio/switches/Makefile +++ b/drivers/rapidio/switches/Makefile @@ -7,7 +7,3 @@ obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o - -ifeq ($(CONFIG_RAPIDIO_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG -endif -- cgit v1.2.2 From 76aea3e9fe1e6b74e8f7c75324fde940701346d4 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:48 -0800 Subject: rtc: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/rtc/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2afdaf3ff986..5f6c3838dcf6 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -2,9 +2,7 @@ # Makefile for RTC class/drivers. # -ifeq ($(CONFIG_RTC_DEBUG),y) - EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG obj-$(CONFIG_RTC_LIB) += rtc-lib.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o -- cgit v1.2.2 From bfbec92075a296eaaddd53b3327ccc259b377299 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:49 -0800 Subject: scsi: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/scsi/aacraid/Makefile | 2 +- drivers/scsi/aic94xx/Makefile | 4 +--- drivers/scsi/libsas/Makefile | 2 +- drivers/scsi/lpfc/Makefile | 6 ++---- drivers/scsi/mvsas/Makefile | 4 +--- drivers/scsi/pcmcia/Makefile | 2 +- 6 files changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile index f1cca4ee5410..92df4d6b6147 100644 --- a/drivers/scsi/aacraid/Makefile +++ b/drivers/scsi/aacraid/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_SCSI_AACRAID) := aacraid.o aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ dpcsup.o rx.o sa.o rkt.o nark.o -EXTRA_CFLAGS := -Idrivers/scsi +ccflags-y := -Idrivers/scsi diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile index e78ce0fa44d2..c0a15c754585 100644 --- a/drivers/scsi/aic94xx/Makefile +++ b/drivers/scsi/aic94xx/Makefile @@ -22,9 +22,7 @@ # along with the aic94xx driver; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -ifeq ($(CONFIG_AIC94XX_DEBUG),y) - EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT -endif +ccflags-$(CONFIG_AIC94XX_DEBUG) := -DASD_DEBUG -DASD_ENTER_EXIT obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o aic94xx-y += aic94xx_init.o \ diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile index 1ad1323c60fa..ae48b52e7645 100644 --- a/drivers/scsi/libsas/Makefile +++ b/drivers/scsi/libsas/Makefile @@ -36,4 +36,4 @@ libsas-y += sas_init.o \ sas_scsi_host.o \ sas_task.o libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o -libsas-$(CONFIG_SCSI_SAS_HOST_SMP) += sas_host_smp.o \ No newline at end of file +libsas-$(CONFIG_SCSI_SAS_HOST_SMP) += sas_host_smp.o diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index ad05d6edb8f6..14de249917f8 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -19,10 +19,8 @@ # *******************************************************************/ ###################################################################### -ifneq ($(GCOV),) - EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage - EXTRA_CFLAGS += -O0 -endif +ccflags-$(GCOV) := -fprofile-arcs -ftest-coverage +ccflags-$(GCOV) += -O0 obj-$(CONFIG_SCSI_LPFC) := lpfc.o diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile index 52ac4264677d..ffbf759e46f1 100644 --- a/drivers/scsi/mvsas/Makefile +++ b/drivers/scsi/mvsas/Makefile @@ -21,9 +21,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA -ifeq ($(CONFIG_SCSI_MVSAS_DEBUG),y) - EXTRA_CFLAGS += -DMV_DEBUG -endif +ccflags-$(CONFIG_SCSI_MVSAS_DEBUG) := -DMV_DEBUG obj-$(CONFIG_SCSI_MVSAS) += mvsas.o mvsas-y += mv_init.o \ diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile index eca379059db6..683bf148b5b7 100644 --- a/drivers/scsi/pcmcia/Makefile +++ b/drivers/scsi/pcmcia/Makefile @@ -1,5 +1,5 @@ -EXTRA_CFLAGS += -Idrivers/scsi +ccflags-y := -Idrivers/scsi # 16-bit client drivers obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o -- cgit v1.2.2 From 22942c00a6ad6e9e93b53811a6de72c821c15d22 Mon Sep 17 00:00:00 2001 From: matt mooney Date: Fri, 14 Jan 2011 06:12:50 -0800 Subject: video: change to new flag variable Replace EXTRA_CFLAGS with ccflags-y. Signed-off-by: matt mooney Acked-by: WANG Cong Signed-off-by: Michal Marek --- drivers/video/intelfb/Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile index 6c782d3ae1be..f7d631ebee8e 100644 --- a/drivers/video/intelfb/Makefile +++ b/drivers/video/intelfb/Makefile @@ -4,7 +4,4 @@ intelfb-y := intelfbdrv.o intelfbhw.o intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o intelfb-objs := $(intelfb-y) -ifdef CONFIG_FB_INTEL_DEBUG -#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP -EXTRA_CFLAGS += -DDEBUG -DREGDUMP -endif +ccflags-$(CONFIG_FB_INTEL_DEBUG) := -DDEBUG -DREGDUMP -- cgit v1.2.2 From f0ff1357ce391265edbf844792da7da9a694f4bd Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 17 Mar 2011 15:02:51 +0100 Subject: drbd: need include for bitops functions declarations Signed-off-by: Stephen Rothwell Signed-off-by: Jens Axboe --- drivers/block/drbd/drbd_bitmap.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index b62dd5f26c5d..f0ae63d2df65 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -28,6 +28,9 @@ #include #include #include + +#include + #include "drbd_int.h" -- cgit v1.2.2 From dffc55adfa2676a02a838d56a0cc4edd3809510c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 16 Feb 2011 23:28:53 +0100 Subject: mmc: msm_sdcc: remove needless cache flush after dma_unmap_sg() dma_unmap_sg() already flushes the cache, I don't get what this code is doing here. Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/host/msm_sdcc.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index 153ab977a013..67b08819556d 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -266,14 +266,6 @@ msmsdcc_dma_complete_tlet(unsigned long data) dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, host->dma.dir); - if (host->curr.user_pages) { - struct scatterlist *sg = host->dma.sg; - int i; - - for (i = 0; i < host->dma.num_ents; i++) - flush_dcache_page(sg_page(sg++)); - } - host->dma.sg = NULL; host->dma.busy = 0; -- cgit v1.2.2 From 0c6d49ce53bc18c0ac637fb137f1e01ee9082201 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 26 Feb 2011 14:44:39 +0100 Subject: mmc: sdhci-esdhc-imx: add write protect on custom GPIO on mx25/35 Signed-off-by: Wolfram Sang Tested-by: Marc Reilly Tested-by: Eric Benard Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-esdhc-imx.c | 52 ++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 9b82910b9dbb..65df00bb00dd 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include #include "sdhci.h" #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" @@ -100,10 +102,31 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) return clk_get_rate(pltfm_host->clk) / 256 / 16; } +static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) +{ + struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; + + if (boarddata && gpio_is_valid(boarddata->wp_gpio)) + return gpio_get_value(boarddata->wp_gpio); + else + return -ENOSYS; +} + +static struct sdhci_ops sdhci_esdhc_ops = { + .read_w = esdhc_readw_le, + .write_w = esdhc_writew_le, + .write_b = esdhc_writeb_le, + .set_clock = esdhc_set_clock, + .get_max_clock = esdhc_pltfm_get_max_clock, + .get_min_clock = esdhc_pltfm_get_min_clock, +}; + static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; struct clk *clk; + int err; clk = clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { @@ -116,9 +139,21 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd if (cpu_is_mx35() || cpu_is_mx51()) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; - /* Fix errata ENGcm07207 which is present on i.MX25 and i.MX35 */ - if (cpu_is_mx25() || cpu_is_mx35()) + if (cpu_is_mx25() || cpu_is_mx35()) { + /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; + /* write_protect can't be routed to controller, use gpio */ + sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; + } + + if (boarddata) { + err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); + if (err) { + dev_warn(mmc_dev(host->mmc), + "no write-protect pin available!\n"); + boarddata->wp_gpio = err; + } + } return 0; } @@ -126,20 +161,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd static void esdhc_pltfm_exit(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; + + if (boarddata && gpio_is_valid(boarddata->wp_gpio)) + gpio_free(boarddata->wp_gpio); clk_disable(pltfm_host->clk); clk_put(pltfm_host->clk); } -static struct sdhci_ops sdhci_esdhc_ops = { - .read_w = esdhc_readw_le, - .write_w = esdhc_writew_le, - .write_b = esdhc_writeb_le, - .set_clock = esdhc_set_clock, - .get_max_clock = esdhc_pltfm_get_max_clock, - .get_min_clock = esdhc_pltfm_get_min_clock, -}; - struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA, /* ADMA has issues. Might be fixable */ -- cgit v1.2.2 From 3bb2a9f6a7c0887a7f79b59c5b9bff349a03247e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 26 Feb 2011 14:44:40 +0100 Subject: mmc: sdhci-esdhc: broken card detection is not a default quirk It can be worked around using a GPIO which will be done for i.MX later. Signed-off-by: Wolfram Sang Acked-by: Anton Vorontsov Tested-by: Marc Reilly Tested-by: Eric Benard Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-esdhc-imx.c | 3 ++- drivers/mmc/host/sdhci-esdhc.h | 1 - drivers/mmc/host/sdhci-of-esdhc.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 65df00bb00dd..49c9801ef122 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -171,7 +171,8 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) } struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA, + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA + | SDHCI_QUIRK_BROKEN_CARD_DETECTION, /* ADMA has issues. Might be fixable */ .ops = &sdhci_esdhc_ops, .init = esdhc_pltfm_init, diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index afaf1bc4913a..c55aae828aac 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -19,7 +19,6 @@ */ #define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ - SDHCI_QUIRK_BROKEN_CARD_DETECTION | \ SDHCI_QUIRK_NO_BUSY_IRQ | \ SDHCI_QUIRK_NONSTANDARD_CLOCK | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index fcd0e1fcba44..08161f690ae8 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -73,7 +73,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) } struct sdhci_of_data sdhci_esdhc = { - .quirks = ESDHC_DEFAULT_QUIRKS, + /* card detection could be handled via GPIO */ + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION, .ops = { .read_l = sdhci_be32bs_readl, .read_w = esdhc_readw, -- cgit v1.2.2 From 7e29c3060369c2cd003b8069972b8535944310e4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 26 Feb 2011 14:44:41 +0100 Subject: mmc: sdhci-esdhc-imx: add card detect on custom GPIO for mx25/35 Signed-off-by: Wolfram Sang Tested-by: Marc Reilly Tested-by: Eric Benard Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-esdhc-imx.c | 79 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 49c9801ef122..3b5248567973 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -32,6 +32,39 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); } +static u32 esdhc_readl_le(struct sdhci_host *host, int reg) +{ + /* fake CARD_PRESENT flag on mx25/35 */ + u32 val = readl(host->ioaddr + reg); + + if (unlikely(reg == SDHCI_PRESENT_STATE)) { + struct esdhc_platform_data *boarddata = + host->mmc->parent->platform_data; + + if (boarddata && gpio_is_valid(boarddata->cd_gpio) + && gpio_get_value(boarddata->cd_gpio)) + /* no card, if a valid gpio says so... */ + val &= SDHCI_CARD_PRESENT; + else + /* ... in all other cases assume card is present */ + val |= SDHCI_CARD_PRESENT; + } + + return val; +} + +static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) +{ + if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) + /* + * these interrupts won't work with a custom card_detect gpio + * (only applied to mx25/35) + */ + val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); + + writel(val, host->ioaddr + reg); +} + static u16 esdhc_readw_le(struct sdhci_host *host, int reg) { if (unlikely(reg == SDHCI_HOST_VERSION)) @@ -121,6 +154,14 @@ static struct sdhci_ops sdhci_esdhc_ops = { .get_min_clock = esdhc_pltfm_get_min_clock, }; +static irqreturn_t cd_irq(int irq, void *data) +{ + struct sdhci_host *sdhost = (struct sdhci_host *)data; + + tasklet_schedule(&sdhost->card_tasklet); + return IRQ_HANDLED; +}; + static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -153,9 +194,40 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd "no write-protect pin available!\n"); boarddata->wp_gpio = err; } + + err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); + if (err) { + dev_warn(mmc_dev(host->mmc), + "no card-detect pin available!\n"); + goto no_card_detect_pin; + } + + /* i.MX5x has issues to be researched */ + if (!cpu_is_mx25() && !cpu_is_mx35()) + goto not_supported; + + err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + mmc_hostname(host->mmc), host); + if (err) { + dev_warn(mmc_dev(host->mmc), "request irq error\n"); + goto no_card_detect_irq; + } + + sdhci_esdhc_ops.write_l = esdhc_writel_le; + sdhci_esdhc_ops.read_l = esdhc_readl_le; + /* Now we have a working card_detect again */ + host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; } return 0; + + no_card_detect_irq: + gpio_free(boarddata->cd_gpio); + no_card_detect_pin: + boarddata->cd_gpio = err; + not_supported: + return 0; } static void esdhc_pltfm_exit(struct sdhci_host *host) @@ -166,6 +238,13 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) if (boarddata && gpio_is_valid(boarddata->wp_gpio)) gpio_free(boarddata->wp_gpio); + if (boarddata && gpio_is_valid(boarddata->cd_gpio)) { + gpio_free(boarddata->cd_gpio); + + if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)) + free_irq(gpio_to_irq(boarddata->cd_gpio), host); + } + clk_disable(pltfm_host->clk); clk_put(pltfm_host->clk); } -- cgit v1.2.2 From ba6a902d9d89b976bf64a435ec97a490cd160dec Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 28 Feb 2011 16:45:10 -0500 Subject: mmc: dw_mmc: Remove set-but-unused variable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit count is only ever used by assigning to old_len if count == 0, and then old_len isn't ever used at all. So, both are redundant. Fixes: drivers/mmc/host/dw_mmc.c: In function ‘dw_mci_read_data_pio’: drivers/mmc/host/dw_mmc.c:1034:32: warning: variable ‘old_len’ set but not used [-Wunused-but-set-variable] Signed-off-by: Chris Ball Acked-by: Will Newton --- drivers/mmc/host/dw_mmc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 58476c1bb056..299c1d61b6b3 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1031,13 +1031,10 @@ static void dw_mci_read_data_pio(struct dw_mci *host) struct mmc_data *data = host->data; int shift = host->data_shift; u32 status; - unsigned int nbytes = 0, len, old_len, count = 0; + unsigned int nbytes = 0, len; do { len = SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift; - if (count == 0) - old_len = len; - if (offset + len <= sg->length) { host->pull_data(host, (void *)(buf + offset), len); @@ -1082,7 +1079,6 @@ static void dw_mci_read_data_pio(struct dw_mci *host) tasklet_schedule(&host->tasklet); return; } - count++; } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ len = SDMMC_GET_FCNT(mci_readl(host, STATUS)); host->pio_offset = offset; -- cgit v1.2.2 From 0aab3995485b8a994bf29a995a008c9ea4a28054 Mon Sep 17 00:00:00 2001 From: Stefan Nilsson XK Date: Tue, 1 Mar 2011 14:41:04 +0100 Subject: mmc: sdio: remember new card RCA when redetecting card During redetection of a SDIO card, a request for a new card RCA was submitted to the card, but was then overwritten by the old RCA. This caused the card to be deselected instead of selected when using the incorrect RCA. This bug's been present since the "oldcard" handling was introduced in 2.6.32. Signed-off-by: Stefan Nilsson XK Reviewed-by: Ulf Hansson Reviewed-by: Pawel Wieczorkiewicz Signed-off-by: Linus Walleij Cc: Signed-off-by: Chris Ball --- drivers/mmc/core/sdio.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c9fbb777440d..db0f0b44d684 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -395,6 +395,14 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, if (err) goto remove; + /* + * Update oldcard with the new RCA received from the SDIO + * device -- we're doing this so that it's updated in the + * "card" struct when oldcard overwrites that later. + */ + if (oldcard) + oldcard->rca = card->rca; + mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } -- cgit v1.2.2 From ab1efd271704416c9e6e9cb4e5f58e7e4c4260e6 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Mar 2011 09:11:02 +0100 Subject: mmc: core: export function mmc_do_release_host() When using mmc_try_claim_host the corresponding release function is mmc_do_release_host, which then also must be exported. Reviewed-by: Jonas Aberg Reviewed-by: Sebastian Rasmussen Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c47e13b79eee..4956da133be4 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -527,7 +527,14 @@ int mmc_try_claim_host(struct mmc_host *host) } EXPORT_SYMBOL(mmc_try_claim_host); -static void mmc_do_release_host(struct mmc_host *host) +/** + * mmc_do_release_host - release a claimed host + * @host: mmc host to release + * + * If you successfully claimed a host, this function will + * release it again. + */ +void mmc_do_release_host(struct mmc_host *host) { unsigned long flags; @@ -542,6 +549,7 @@ static void mmc_do_release_host(struct mmc_host *host) wake_up(&host->wq); } } +EXPORT_SYMBOL(mmc_do_release_host); void mmc_host_deeper_disable(struct work_struct *work) { -- cgit v1.2.2 From b33d46c398fd071dccd0815f33620924684860cd Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Sat, 5 Mar 2011 14:36:24 +0100 Subject: mmc: core: reset card voltage after power off At power off, reset OCR mask to be the highest possible voltage supported for the current mmc host. This solves the re-initialization during the power up sequence. The voltage may have been decreased due to the card accepts a lower voltage than the voltage used during the initialization sequence. We need to reset the voltage to by the host highest possible value since according to specification the initialization must always be done at high voltage. Reviewed-by: Jonas Aberg Signed-off-by: Ulf Hansson Signed-off-by: Linus Walleij Signed-off-by: Chris Ball --- drivers/mmc/core/core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 4956da133be4..1f453acc8682 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1009,6 +1009,13 @@ static void mmc_power_off(struct mmc_host *host) { host->ios.clock = 0; host->ios.vdd = 0; + + /* + * Reset ocr mask to be the highest possible voltage supported for + * this mmc host. This value will be used at next power up. + */ + host->ocr = 1 << (fls(host->ocr_avail) - 1); + if (!mmc_host_is_spi(host)) { host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.chip_select = MMC_CS_DONTCARE; -- cgit v1.2.2 From 860cfe796c793bfad1e666de9600852f2d653c57 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 11 Mar 2011 08:30:14 +0100 Subject: mmc: tmio: fix address in kunmap_atomic() calls Currently kunmap_atomic() doesn't take into account the offset, used with kmap_atomic(). On platforms, where kunmap_atomic() is not a NOP, this will lead to problems, when offset != 0. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 0e4998fa6fc5..ac52eb65395e 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -219,9 +219,9 @@ static char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; } -static void tmio_mmc_kunmap_atomic(void *virt, unsigned long *flags) +static void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) { - kunmap_atomic(virt, KM_BIO_SRC_IRQ); + kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); local_irq_restore(*flags); } @@ -510,7 +510,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) host->sg_off += count; - tmio_mmc_kunmap_atomic(sg_virt, &flags); + tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt); if (host->sg_off == host->sg_ptr->length) tmio_mmc_next_sg(host); @@ -770,7 +770,7 @@ static void tmio_check_bounce_buffer(struct tmio_mmc_host *host) unsigned long flags; void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(sg_vaddr, &flags); + tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); } } @@ -897,7 +897,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(sg_vaddr, &flags); + tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); host->sg_ptr = &host->bounce_sg; sg = host->sg_ptr; } -- cgit v1.2.2 From fc3d7720541d4b70cbae25ac121d7e6343125090 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 25 Feb 2011 11:08:15 +0900 Subject: mmc: dw_mmc: add quirks for unreliable card detect, and capabilities This patch adds quirks and capabilities to platdata. Some cards don't use the CDn pin; in that case, we assume the card's inserted. Some boards need other capabilities. So, we add capabilities in the board's platdata. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Acked-by: Will Newton Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 299c1d61b6b3..94ec6502bdde 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -729,7 +729,9 @@ static int dw_mci_get_cd(struct mmc_host *mmc) struct dw_mci_board *brd = slot->host->pdata; /* Use platform get_cd function, else try onboard card detect */ - if (brd->get_cd) + if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) + present = 1; + else if (brd->get_cd) present = !brd->get_cd(slot->id); else present = (mci_readl(slot->host, CDETECT) & (1 << slot->id)) @@ -1403,7 +1405,11 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (host->pdata->setpower) host->pdata->setpower(id, 0); - mmc->caps = 0; + if (host->pdata->caps) + mmc->caps = host->pdata->caps; + else + mmc->caps = 0; + if (host->pdata->get_bus_wd) if (host->pdata->get_bus_wd(slot->id) >= 4) mmc->caps |= MMC_CAP_4_BIT_DATA; -- cgit v1.2.2 From e61cf1184d72e574460492fd6c6b6d8a3ace2089 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 17 Mar 2011 20:32:33 +0900 Subject: mmc: dw_mmc: fix suspend/resume operation This patch is related to re-init processing on suspend/resume. When card is resuming, some register is reset. If card is removable, maybe controller should be rescan for card. But if assume card is non-removable, need to restore the old value at registers. We store the value of FIFOTH at probe time and then restore it in dw_mci_resume(). Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Acked-by: Will Newton Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 94ec6502bdde..51ee2f5909d4 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1639,8 +1639,9 @@ static int dw_mci_probe(struct platform_device *pdev) */ fifo_size = mci_readl(host, FIFOTH); fifo_size = (fifo_size >> 16) & 0x7ff; - mci_writel(host, FIFOTH, ((0x2 << 28) | ((fifo_size/2 - 1) << 16) | - ((fifo_size/2) << 0))); + host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) | + ((fifo_size/2) << 0)); + mci_writel(host, FIFOTH, host->fifoth_val); /* disable clock to CIU */ mci_writel(host, CLKENA, 0); @@ -1772,6 +1773,23 @@ static int dw_mci_resume(struct platform_device *pdev) int i, ret; struct dw_mci *host = platform_get_drvdata(pdev); + if (host->dma_ops->init) + host->dma_ops->init(host); + + if (!mci_wait_reset(&pdev->dev, host)) { + ret = -ENODEV; + return ret; + } + + /* Restore the old value at FIFOTH register */ + mci_writel(host, FIFOTH, host->fifoth_val); + + mci_writel(host, RINTSTS, 0xFFFFFFFF); + mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | + SDMMC_INT_TXDR | SDMMC_INT_RXDR | + DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); + mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); + for (i = 0; i < host->num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; if (!slot) -- cgit v1.2.2 From c07946a3350244d7c3d9bc1032325e04dd11575b Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 25 Feb 2011 11:08:14 +0900 Subject: mmc: dw_mmc: support mmc power control with regulator This patch adds support for power regulators. Signed-off-by: Jaehoon Chung Signed-off-by: kyungmin Park Acked-by: Will Newton Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 51ee2f5909d4..5a614069cb00 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "dw_mmc.h" @@ -1440,6 +1441,13 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) } #endif /* CONFIG_MMC_DW_IDMAC */ + host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); + if (IS_ERR(host->vmmc)) { + printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); + host->vmmc = NULL; + } else + regulator_enable(host->vmmc); + if (dw_mci_get_cd(mmc)) set_bit(DW_MMC_CARD_PRESENT, &slot->flags); else @@ -1704,6 +1712,12 @@ err_dmaunmap: host->sg_cpu, host->sg_dma); iounmap(host->regs); + if (host->vmmc) { + regulator_disable(host->vmmc); + regulator_put(host->vmmc); + } + + err_freehost: kfree(host); return ret; @@ -1735,6 +1749,11 @@ static int __exit dw_mci_remove(struct platform_device *pdev) if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); + if (host->vmmc) { + regulator_disable(host->vmmc); + regulator_put(host->vmmc); + } + iounmap(host->regs); kfree(host); @@ -1750,6 +1769,9 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) int i, ret; struct dw_mci *host = platform_get_drvdata(pdev); + if (host->vmmc) + regulator_enable(host->vmmc); + for (i = 0; i < host->num_slots; i++) { struct dw_mci_slot *slot = host->slot[i]; if (!slot) @@ -1765,6 +1787,9 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg) } } + if (host->vmmc) + regulator_disable(host->vmmc); + return 0; } -- cgit v1.2.2 From 1bdd6384c2b43cac9be8d6f2c298bcf39f50cd07 Mon Sep 17 00:00:00 2001 From: Sean Hefty Date: Thu, 17 Mar 2011 23:35:39 +0000 Subject: RDMA/addr: Fix return of uninitialized ret value Commit b23dd4fe42b4 ("ipv4: Make output route lookup return rtable directly") resulted in leaving ret uninitialized, where it may later be returned. Signed-off-by: Sean Hefty Signed-off-by: Roland Dreier --- drivers/infiniband/core/addr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index e0ef5fdc361e..4ffc224faa7f 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -204,7 +204,7 @@ static int addr4_resolve(struct sockaddr_in *src_in, /* If the device does ARP internally, return 'done' */ if (rt->dst.dev->flags & IFF_NOARP) { - rdma_copy_addr(addr, rt->dst.dev, NULL); + ret = rdma_copy_addr(addr, rt->dst.dev, NULL); goto put; } -- cgit v1.2.2 From 0acf659f1469725fb6e39d53af970f36c5f69a41 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Mar 2011 07:28:57 -0500 Subject: OMAP: DSS2: Clean up for dpll4_m4_ck handling OMAP2 does not have dpll4_m4_ck source clock for dss functional clock, but later OMAPs do. Currently we check for cpu type in multiple places to find out if dpll4_m4_ck is available. This patch cleans up dss.c by using the fact that dss.dpll4_m4_ck pointer is NULL on OMAP2. This allows us to remove many of the cpu checks. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 93 +++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index f1628bd850d1..9d2390299df7 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -239,30 +239,40 @@ void dss_dump_clocks(struct seq_file *s) { unsigned long dpll4_ck_rate; unsigned long dpll4_m4_ck_rate; + const char *fclk_name, *fclk_real_name; + unsigned long fclk_rate; dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK); - dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); - seq_printf(s, "- DSS -\n"); - seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); + fclk_name = dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK); + fclk_real_name = dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK); + fclk_rate = dss_clk_get_rate(DSS_CLK_FCK); - if (cpu_is_omap3630()) - seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", - dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK), - dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK), - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - dss_clk_get_rate(DSS_CLK_FCK)); - else - seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", - dss_get_generic_clk_source_name(DSS_CLK_SRC_FCK), - dss_feat_get_clk_source_name(DSS_CLK_SRC_FCK), - dpll4_ck_rate, - dpll4_ck_rate / dpll4_m4_ck_rate, - dss_clk_get_rate(DSS_CLK_FCK)); + if (dss.dpll4_m4_ck) { + dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); + dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); + + seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); + + if (cpu_is_omap3630()) + seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", + fclk_name, fclk_real_name, + dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + fclk_rate); + else + seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", + fclk_name, fclk_real_name, + dpll4_ck_rate, + dpll4_ck_rate / dpll4_m4_ck_rate, + fclk_rate); + } else { + seq_printf(s, "%s (%s) = %lu\n", + fclk_name, fclk_real_name, + fclk_rate); + } dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK); } @@ -382,31 +392,40 @@ enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) /* calculate clock rates using dividers in cinfo */ int dss_calc_clock_rates(struct dss_clock_info *cinfo) { - unsigned long prate; + if (dss.dpll4_m4_ck) { + unsigned long prate; - if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) || - cinfo->fck_div == 0) - return -EINVAL; + if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) || + cinfo->fck_div == 0) + return -EINVAL; - prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - cinfo->fck = prate / cinfo->fck_div; + cinfo->fck = prate / cinfo->fck_div; + } else { + if (cinfo->fck_div != 0) + return -EINVAL; + cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); + } return 0; } int dss_set_clock_div(struct dss_clock_info *cinfo) { - unsigned long prate; - int r; + if (dss.dpll4_m4_ck) { + unsigned long prate; + int r; - if (cpu_is_omap34xx()) { prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); DSSDBG("dpll4_m4 = %ld\n", prate); r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); if (r) return r; + } else { + if (cinfo->fck_div != 0) + return -EINVAL; } DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); @@ -418,9 +437,11 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) { cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK); - if (cpu_is_omap34xx()) { + if (dss.dpll4_m4_ck) { unsigned long prate; + prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); + if (cpu_is_omap3630()) cinfo->fck_div = prate / (cinfo->fck); else @@ -434,7 +455,7 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) unsigned long dss_get_dpll4_rate(void) { - if (cpu_is_omap34xx()) + if (dss.dpll4_m4_ck) return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); else return 0; @@ -615,6 +636,7 @@ static int dss_init(void) int r; u32 rev; struct resource *dss_mem; + struct clk *dpll4_m4_ck; dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); if (!dss_mem) { @@ -655,16 +677,19 @@ static int dss_init(void) REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ #endif - if (cpu_is_omap34xx()) { - dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); - if (IS_ERR(dss.dpll4_m4_ck)) { + dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck"); + if (IS_ERR(dpll4_m4_ck)) { DSSERR("Failed to get dpll4_m4_ck\n"); - r = PTR_ERR(dss.dpll4_m4_ck); + r = PTR_ERR(dpll4_m4_ck); goto fail1; } + } else { /* omap24xx */ + dpll4_m4_ck = NULL; } + dss.dpll4_m4_ck = dpll4_m4_ck; + dss.dsi_clk_source = DSS_CLK_SRC_FCK; dss.dispc_clk_source = DSS_CLK_SRC_FCK; dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; @@ -686,7 +711,7 @@ fail0: static void dss_exit(void) { - if (cpu_is_omap34xx()) + if (dss.dpll4_m4_ck) clk_put(dss.dpll4_m4_ck); iounmap(dss.base); -- cgit v1.2.2 From 2de110868f455b74e91111801ce63a3c9d06f091 Mon Sep 17 00:00:00 2001 From: "Murthy, Raghuveer" Date: Mon, 14 Mar 2011 07:28:58 -0500 Subject: OMAP: DSS2: Implement OMAP4 DSS fclk support Add dss.dpll4_m4_ck (DSS FCLK) initialization for OMAP4. This is used to compute the pixel clock for DPI interface and also to reconfigure the DSS FCLK to the desired rate, corresponding to the rate computed for pixel clock. Adding these cpu_is_44xx() checks are meant to be temporary, until a cleaner implementation to manage these checks are added. Currently this is needed to get DVI display running on OMAP4 PandaBoard Signed-off-by: Raghuveer Murthy [tomi.valkeinen@ti.com: minor changes due to conflicts] Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dss.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 9d2390299df7..3f1fee63c678 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -256,7 +256,7 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); - if (cpu_is_omap3630()) + if (cpu_is_omap3630() || cpu_is_omap44xx()) seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", fclk_name, fclk_real_name, dpll4_ck_rate, @@ -394,9 +394,12 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) { if (dss.dpll4_m4_ck) { unsigned long prate; + u16 fck_div_max = 16; - if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) || - cinfo->fck_div == 0) + if (cpu_is_omap3630() || cpu_is_omap44xx()) + fck_div_max = 32; + + if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) return -EINVAL; prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); @@ -442,7 +445,7 @@ int dss_get_clock_div(struct dss_clock_info *cinfo) prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); - if (cpu_is_omap3630()) + if (cpu_is_omap3630() || cpu_is_omap44xx()) cinfo->fck_div = prate / (cinfo->fck); else cinfo->fck_div = prate / (cinfo->fck / 2); @@ -471,7 +474,7 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck, unsigned long fck, max_dss_fck; - u16 fck_div; + u16 fck_div, fck_div_max = 16; int match = 0; int min_fck_per_pck; @@ -504,7 +507,7 @@ retry: memset(&best_dss, 0, sizeof(best_dss)); memset(&best_dispc, 0, sizeof(best_dispc)); - if (cpu_is_omap24xx()) { + if (dss.dpll4_m4_ck == NULL) { struct dispc_clock_info cur_dispc; /* XXX can we change the clock on omap2? */ fck = dss_clk_get_rate(DSS_CLK_FCK); @@ -519,12 +522,14 @@ retry: best_dispc = cur_dispc; goto found; - } else if (cpu_is_omap34xx()) { - for (fck_div = (cpu_is_omap3630() ? 32 : 16); - fck_div > 0; --fck_div) { + } else { + if (cpu_is_omap3630() || cpu_is_omap44xx()) + fck_div_max = 32; + + for (fck_div = fck_div_max; fck_div > 0; --fck_div) { struct dispc_clock_info cur_dispc; - if (cpu_is_omap3630()) + if (fck_div_max == 32) fck = prate / fck_div; else fck = prate / fck_div * 2; @@ -552,8 +557,6 @@ retry: goto found; } } - } else { - BUG(); } found: @@ -684,6 +687,13 @@ static int dss_init(void) r = PTR_ERR(dpll4_m4_ck); goto fail1; } + } else if (cpu_is_omap44xx()) { + dpll4_m4_ck = clk_get(NULL, "dpll_per_m5x2_ck"); + if (IS_ERR(dpll4_m4_ck)) { + DSSERR("Failed to get dpll4_m4_ck\n"); + r = PTR_ERR(dpll4_m4_ck); + goto fail1; + } } else { /* omap24xx */ dpll4_m4_ck = NULL; } -- cgit v1.2.2 From 748bfd9c1ded8419e7fdba4ca6f0c1dc1642df63 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 18 Mar 2011 08:52:30 -0700 Subject: RDMA/nes: Don't print success message at level KERN_ERR There's no reason to print "NetEffect RNIC driver successfully loaded" at level KERN_ERR (where it will uglify the console on a quiet boot). Change it to KERN_INFO. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 3d7f3664b67b..13de1192927c 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -694,7 +694,7 @@ static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_i nesdev->netdev_count++; nesdev->nesadapter->netdev_count++; - printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n", + printk(KERN_INFO PFX "%s: NetEffect RNIC driver successfully loaded.\n", pci_name(pcidev)); return 0; -- cgit v1.2.2 From 1eba843dd7678b9033a0d1ccff21c21b857de77b Mon Sep 17 00:00:00 2001 From: Michael Heinz Date: Fri, 11 Feb 2011 21:44:30 +0000 Subject: IB/mad: Improve an error message so error code is included Signed-off-by: Michael Heinz Signed-off-by: Roland Dreier --- drivers/infiniband/core/agent.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c index 91916a8d5de4..2bc7f5af64f4 100644 --- a/drivers/infiniband/core/agent.c +++ b/drivers/infiniband/core/agent.c @@ -101,7 +101,8 @@ void agent_send_response(struct ib_mad *mad, struct ib_grh *grh, agent = port_priv->agent[qpn]; ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num); if (IS_ERR(ah)) { - printk(KERN_ERR SPFX "ib_create_ah_from_wc error\n"); + printk(KERN_ERR SPFX "ib_create_ah_from_wc error %ld\n", + PTR_ERR(ah)); return; } -- cgit v1.2.2 From e1620d591a75a10b15cf61dbf8243a0b7e6731a2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 18 Mar 2011 19:55:36 +0100 Subject: USB: Move runtime PM callbacks to usb_device_pm_ops USB defines usb_device_type pointing to usb_device_pm_ops that provides system-wide PM callbacks only and usb_bus_type pointing to usb_bus_pm_ops that provides runtime PM callbacks only. However, the USB runtime PM callbacks may be defined in usb_device_pm_ops which makes it possible to drop usb_bus_pm_ops and will allow us to consolidate the handling of subsystems by the PM core code. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 15 +++------------ drivers/usb/core/usb.c | 5 +++++ drivers/usb/core/usb.h | 3 +++ 3 files changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 38072e4e74bd..e35a17687c05 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1646,7 +1646,7 @@ static int autosuspend_check(struct usb_device *udev) return 0; } -static int usb_runtime_suspend(struct device *dev) +int usb_runtime_suspend(struct device *dev) { struct usb_device *udev = to_usb_device(dev); int status; @@ -1667,7 +1667,7 @@ static int usb_runtime_suspend(struct device *dev) return status; } -static int usb_runtime_resume(struct device *dev) +int usb_runtime_resume(struct device *dev) { struct usb_device *udev = to_usb_device(dev); int status; @@ -1679,7 +1679,7 @@ static int usb_runtime_resume(struct device *dev) return status; } -static int usb_runtime_idle(struct device *dev) +int usb_runtime_idle(struct device *dev) { struct usb_device *udev = to_usb_device(dev); @@ -1691,19 +1691,10 @@ static int usb_runtime_idle(struct device *dev) return 0; } -static const struct dev_pm_ops usb_bus_pm_ops = { - .runtime_suspend = usb_runtime_suspend, - .runtime_resume = usb_runtime_resume, - .runtime_idle = usb_runtime_idle, -}; - #endif /* CONFIG_USB_SUSPEND */ struct bus_type usb_bus_type = { .name = "usb", .match = usb_device_match, .uevent = usb_uevent, -#ifdef CONFIG_USB_SUSPEND - .pm = &usb_bus_pm_ops, -#endif }; diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 079cb57bab4f..d9d4b169404f 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -315,6 +315,11 @@ static const struct dev_pm_ops usb_device_pm_ops = { .thaw = usb_dev_thaw, .poweroff = usb_dev_poweroff, .restore = usb_dev_restore, +#ifdef CONFIG_USB_SUSPEND + .runtime_suspend = usb_runtime_suspend, + .runtime_resume = usb_runtime_resume, + .runtime_idle = usb_runtime_idle, +#endif }; #endif /* CONFIG_PM */ diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index a9cf484ecae4..d450b742137e 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -77,6 +77,9 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg) extern void usb_autosuspend_device(struct usb_device *udev); extern int usb_autoresume_device(struct usb_device *udev); extern int usb_remote_wakeup(struct usb_device *dev); +extern int usb_runtime_suspend(struct device *dev); +extern int usb_runtime_resume(struct device *dev); +extern int usb_runtime_idle(struct device *dev); #else -- cgit v1.2.2 From 4363c2fddb1399b728ef21ee8101c148a311ea45 Mon Sep 17 00:00:00 2001 From: Alex Dubov Date: Wed, 16 Mar 2011 17:57:13 +0000 Subject: gianfar: Fall back to software tcp/udp checksum on older controllers As specified by errata eTSEC49 of MPC8548 and errata eTSEC12 of MPC83xx, older revisions of gianfar controllers will be unable to calculate a TCP/UDP packet checksum for some alignments of the appropriate FCB. This patch checks for FCB alignment on such controllers and falls back to software checksumming if the alignment is known to be bad. Signed-off-by: Alex Dubov Signed-off-by: David S. Miller --- drivers/net/gianfar.c | 16 ++++++++++++++-- drivers/net/gianfar.h | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index ccb231c4d933..2a0ad9a501bb 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -949,6 +949,11 @@ static void gfar_detect_errata(struct gfar_private *priv) (pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0)) priv->errata |= GFAR_ERRATA_A002; + /* MPC8313 Rev < 2.0, MPC8548 rev 2.0 */ + if ((pvr == 0x80850010 && mod == 0x80b0 && rev < 0x0020) || + (pvr == 0x80210020 && mod == 0x8030 && rev == 0x0020)) + priv->errata |= GFAR_ERRATA_12; + if (priv->errata) dev_info(dev, "enabled errata workarounds, flags: 0x%x\n", priv->errata); @@ -2154,8 +2159,15 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Set up checksumming */ if (CHECKSUM_PARTIAL == skb->ip_summed) { fcb = gfar_add_fcb(skb); - lstatus |= BD_LFLAG(TXBD_TOE); - gfar_tx_checksum(skb, fcb); + /* as specified by errata */ + if (unlikely(gfar_has_errata(priv, GFAR_ERRATA_12) + && ((unsigned long)fcb % 0x20) > 0x18)) { + __skb_pull(skb, GMAC_FCB_LEN); + skb_checksum_help(skb); + } else { + lstatus |= BD_LFLAG(TXBD_TOE); + gfar_tx_checksum(skb, fcb); + } } if (vlan_tx_tag_present(skb)) { diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index 54de4135e932..ec5d595ce2e2 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -1039,6 +1039,7 @@ enum gfar_errata { GFAR_ERRATA_74 = 0x01, GFAR_ERRATA_76 = 0x02, GFAR_ERRATA_A002 = 0x04, + GFAR_ERRATA_12 = 0x08, /* a.k.a errata eTSEC49 */ }; /* Struct stolen almost completely (and shamelessly) from the FCC enet source -- cgit v1.2.2 From 4d3fbff26c8e91474e30e575c2b7476be11afd83 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 10 Mar 2011 21:21:23 +0100 Subject: ACPI: Remove the unused EC sysdev class The ACPI EC driver defines a sysdev class, but it doesn't use it, so it can be removed. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/ec_sys.c | 4 ---- drivers/acpi/internal.h | 3 --- 2 files changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 411620ef84c2..05b44201a614 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -24,10 +24,6 @@ MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may " #define EC_SPACE_SIZE 256 -struct sysdev_class acpi_ec_sysdev_class = { - .name = "ec", -}; - static struct dentry *acpi_ec_debugfs_dir; static int acpi_ec_open_io(struct inode *i, struct file *f) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index b1cc81a0431b..4bfb759deb10 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -21,8 +21,6 @@ #ifndef _ACPI_INTERNAL_H_ #define _ACPI_INTERNAL_H_ -#include - #define PREFIX "ACPI: " int init_acpi_device_notify(void); @@ -64,7 +62,6 @@ struct acpi_ec { struct list_head list; struct transaction *curr; spinlock_t curr_lock; - struct sys_device sysdev; }; extern struct acpi_ec *first_ec; -- cgit v1.2.2 From c3146df2b735912eddd1d7c080c9377d5df0ae94 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 12 Mar 2011 22:16:51 +0100 Subject: ACPI: Use syscore_ops instead of sysdev class and sysdev ACPI uses a sysdev class and a sysdev for executing irqrouter_resume() before turning on interrupts on the boot CPU. However, since irqrouter_resume() ignores its argument, the entire mechanism may be replaced with a struct syscore_ops object which is considerably simpler. Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/pci_link.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 9ff80a7e9f6a..4a29763b8eb4 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -29,7 +29,7 @@ * for IRQ management (e.g. start()->_SRS). */ -#include +#include #include #include #include @@ -757,14 +757,13 @@ static int acpi_pci_link_resume(struct acpi_pci_link *link) return 0; } -static int irqrouter_resume(struct sys_device *dev) +static void irqrouter_resume(void) { struct acpi_pci_link *link; list_for_each_entry(link, &acpi_link_list, list) { acpi_pci_link_resume(link); } - return 0; } static int acpi_pci_link_remove(struct acpi_device *device, int type) @@ -871,32 +870,19 @@ static int __init acpi_irq_balance_set(char *str) __setup("acpi_irq_balance", acpi_irq_balance_set); -/* FIXME: we will remove this interface after all drivers call pci_disable_device */ -static struct sysdev_class irqrouter_sysdev_class = { - .name = "irqrouter", +static struct syscore_ops irqrouter_syscore_ops = { .resume = irqrouter_resume, }; -static struct sys_device device_irqrouter = { - .id = 0, - .cls = &irqrouter_sysdev_class, -}; - -static int __init irqrouter_init_sysfs(void) +static int __init irqrouter_init_ops(void) { - int error; + if (!acpi_disabled && !acpi_noirq) + register_syscore_ops(&irqrouter_syscore_ops); - if (acpi_disabled || acpi_noirq) - return 0; - - error = sysdev_class_register(&irqrouter_sysdev_class); - if (!error) - error = sysdev_register(&device_irqrouter); - - return error; + return 0; } -device_initcall(irqrouter_init_sysfs); +device_initcall(irqrouter_init_ops); static int __init acpi_pci_link_init(void) { -- cgit v1.2.2 From 4fa8eebb045a6d798011f3935a38dd29de30e6c9 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Fri, 18 Mar 2011 16:53:21 -0700 Subject: hwspinlock: depend on OMAP4 Currently only OMAP4 supports hwspinlocks, so don't bother asking anyone else. Signed-off-by: Ohad Ben-Cohen Signed-off-by: Tony Lindgren --- drivers/hwspinlock/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index eb4af28f8567..1f29bab6b3e5 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -4,6 +4,7 @@ config HWSPINLOCK tristate "Generic Hardware Spinlock framework" + depends on ARCH_OMAP4 help Say y here to support the generic hardware spinlock framework. You only need to enable this if you have hardware spinlock module -- cgit v1.2.2 From 93d03203d5a165d7a757546245dd1543dfe0ff80 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 18 Mar 2011 21:53:03 -0700 Subject: ftmac100: use resource_size() The calculation is off-by-one. It should be "end - start + 1". This patch fixes it to use resource_size() instead. Oddly, the code already uses resource size correctly a couple lines earlier when it calls request_mem_region() for this memory. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ftmac100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index 1d6f4b8d393a..a31661948c42 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -1102,7 +1102,7 @@ static int ftmac100_probe(struct platform_device *pdev) goto err_req_mem; } - priv->base = ioremap(res->start, res->end - res->start); + priv->base = ioremap(res->start, resource_size(res)); if (!priv->base) { dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n"); err = -EIO; -- cgit v1.2.2 From dadaa10b077133e5c03333131b82ecb13679af2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20de=20Peslo=C3=BCan?= Date: Sat, 19 Mar 2011 13:36:18 -0700 Subject: bonding: fix a typo in a comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicolas de Pesloüan Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1a6e9eb7af43..338bea147c64 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2130,7 +2130,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } /* -* First release a slave and than destroy the bond if no more slaves are left. +* First release a slave and then destroy the bond if no more slaves are left. * Must be under rtnl_lock when this function is called. */ static int bond_release_and_destroy(struct net_device *bond_dev, -- cgit v1.2.2 From b26fa4e0275426450238a14158bc1db24bb696e6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 19 Mar 2011 05:39:11 +0000 Subject: r8169: fix a bug in rtl8169_init_phy() commit 54405cde7624 (r8169: support control of advertising.) introduced a bug in rtl8169_init_phy() Reported-by: Piotr Hosowicz Signed-off-by: Eric Dumazet Cc: Oliver Neukum Cc: Francois Romieu Tested-by: Anca Emanuel Tested-by: Piotr Hosowicz Signed-off-by: David S. Miller --- drivers/net/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 5e403511289d..493b0de3848b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2685,9 +2685,9 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | - tp->mii.supports_gmii ? + (tp->mii.supports_gmii ? ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full : 0); + ADVERTISED_1000baseT_Full : 0)); if (RTL_R8(PHYstatus) & TBI_Enable) netif_info(tp, link, dev, "TBI auto-negotiating\n"); -- cgit v1.2.2 From a769f4968396093d5cc1b1a86204cef579784b24 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 19 Mar 2011 23:06:33 -0700 Subject: niu: Rename NIU parent platform device name to fix conflict. When the OF device driver bits were converted over to the platform device infrastructure in commit 74888760d40b3ac9054f9c5fa07b566c0676ba2d ("dt/net: Eliminate users of of_platform_{,un}register_driver") we inadvertantly created probing problems in the OF case. The NIU driver creates a dummy platform device to represent the board that contains one or more child NIU devices. Unfortunately we use the same name, "niu", as the OF device driver itself uses. The result is that we try to probe the dummy "niu" parent device we create, and since it has a NULL ofdevice pointer etc. everything explodes: [783019.128243] niu: niu.c:v1.1 (Apr 22, 2010) [783019.128810] Unable to handle kernel NULL pointer dereference [783019.128949] tsk->{mm,active_mm}->context = 000000000000039e [783019.129078] tsk->{mm,active_mm}->pgd = fffff803afc5a000 [783019.129206] \|/ ____ \|/ [783019.129213] "@'/ .. \`@" [783019.129220] /_| \__/ |_\ [783019.129226] \__U_/ [783019.129378] modprobe(2004): Oops [#1] [783019.129423] TSTATE: 0000000011001602 TPC: 0000000010052ff8 TNPC: 000000000061bbb4 Y: 00000000 Not tainted [783019.129542] TPC: [783019.129624] g0: 8080000000000000 g1: 0000000000000000 g2: 0000000010056000 g3: 0000000000000002 [783019.129733] g4: fffff803fc1da0c0 g5: fffff800441e2000 g6: fffff803fba84000 g7: 0000000000000000 [783019.129842] o0: fffff803fe7df010 o1: 0000000010055700 o2: 0000000000000000 o3: fffff803fbacaca0 [783019.129951] o4: 0000000000000080 o5: 0000000000777908 sp: fffff803fba866e1 ret_pc: 0000000010052ff4 [783019.130083] RPC: [783019.130165] l0: fffff803fe7df010 l1: fffff803fbacafc0 l2: fffff803fbacaca0 l3: ffffffffffffffed [783019.130273] l4: 0000000000000000 l5: 000000007fffffff l6: fffff803fba86f40 l7: 0000000000000001 [783019.130382] i0: fffff803fe7df000 i1: fffff803fc20aba0 i2: 0000000000000000 i3: 0000000000000001 [783019.130490] i4: 0000000000000000 i5: 0000000000000000 i6: fffff803fba867a1 i7: 000000000062038c [783019.130614] I7: Fix by simply renaming the parent device to "niu-board". Signed-off-by: David S. Miller --- drivers/net/niu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 40fa59e2fd5c..32678b6c6b39 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -9501,7 +9501,7 @@ static struct niu_parent * __devinit niu_new_parent(struct niu *np, struct niu_parent *p; int i; - plat_dev = platform_device_register_simple("niu", niu_parent_index, + plat_dev = platform_device_register_simple("niu-board", niu_parent_index, NULL, 0); if (IS_ERR(plat_dev)) return NULL; -- cgit v1.2.2 From 950a5097855e2d0ac2c91a33f67eeac3be802bf5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 20 Mar 2011 14:50:52 +0100 Subject: i2c-boardinfo: Fix typo in comment Signed-off-by: Wolfram Sang Signed-off-by: Jean Delvare --- drivers/i2c/i2c-boardinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 7e6a63b57165..3ca2e012e789 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -1,5 +1,5 @@ /* - * i2c-boardinfo.h - collect pre-declarations of I2C devices + * i2c-boardinfo.c - collect pre-declarations of I2C devices * * 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 -- cgit v1.2.2 From d735b34db30b7891ff76b552d18ecb0ce04a2bc2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 20 Mar 2011 14:50:52 +0100 Subject: i2c: make i2c_get_adapter prototype clearer Rename the parameter of i2c_get_adapter() to "nr", to make it clear we are passing an adapter number and not an adapter ID (which have gone away by now.) Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 045ba6efea48..f7620cada782 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1581,12 +1581,12 @@ i2c_new_probed_device(struct i2c_adapter *adap, } EXPORT_SYMBOL_GPL(i2c_new_probed_device); -struct i2c_adapter *i2c_get_adapter(int id) +struct i2c_adapter *i2c_get_adapter(int nr) { struct i2c_adapter *adapter; mutex_lock(&core_lock); - adapter = idr_find(&i2c_adapter_idr, id); + adapter = idr_find(&i2c_adapter_idr, nr); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; -- cgit v1.2.2 From 7ae31482a8376fb0df3a0c5ff0677a92820c06b7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 20 Mar 2011 14:50:52 +0100 Subject: i2c: Export i2c_for_each_dev Introduce i2c_for_each_dev(), an i2c device iterator with proper locking for use by i2c-dev. This is needed so that we can get rid of the attach_adapter and detach_adapter legacy callback functions. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f7620cada782..b9fa1d0320b4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1091,6 +1091,18 @@ EXPORT_SYMBOL(i2c_del_adapter); /* ------------------------------------------------------------------------- */ +int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)) +{ + int res; + + mutex_lock(&core_lock); + res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn); + mutex_unlock(&core_lock); + + return res; +} +EXPORT_SYMBOL_GPL(i2c_for_each_dev); + static int __process_new_driver(struct device *dev, void *data) { if (dev->type != &i2c_adapter_type) @@ -1134,9 +1146,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ - mutex_lock(&core_lock); - bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver); - mutex_unlock(&core_lock); + i2c_for_each_dev(driver, __process_new_driver); return 0; } @@ -1156,9 +1166,7 @@ static int __process_removed_driver(struct device *dev, void *data) */ void i2c_del_driver(struct i2c_driver *driver) { - mutex_lock(&core_lock); - bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver); - mutex_unlock(&core_lock); + i2c_for_each_dev(driver, __process_removed_driver); driver_unregister(&driver->driver); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); -- cgit v1.2.2 From 9ea3e941d161f41f920462c50e9b651cc00eccc7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 20 Mar 2011 14:50:52 +0100 Subject: i2c-dev: Use standard bus notification mechanism Use the standard driver core mechanism to keep track of i2c adapters present on the system: i2c_for_each_dev and a notifier. This will let us deprecate and ultimately remove the legacy attach_adapter and detach_adapter callbacks in i2c_driver. Signed-off-by: Jean Delvare --- drivers/i2c/i2c-dev.c | 60 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index cec0f3ba97f8..c90ce50b619f 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -28,6 +28,8 @@ #include #include +#include +#include #include #include #include @@ -37,16 +39,13 @@ #include #include -static struct i2c_driver i2cdev_driver; - /* * An i2c_dev represents an i2c_adapter ... an I2C or SMBus master, not a * slave (i2c_client) with which messages will be exchanged. It's coupled * with a character special file which is accessed by user mode drivers. * * The list of i2c_dev structures is parallel to the i2c_adapter lists - * maintained by the driver model, and is updated using notifications - * delivered to the i2cdev_driver. + * maintained by the driver model, and is updated using bus notifications. */ struct i2c_dev { struct list_head list; @@ -491,7 +490,6 @@ static int i2cdev_open(struct inode *inode, struct file *file) return -ENOMEM; } snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); - client->driver = &i2cdev_driver; client->adapter = adap; file->private_data = client; @@ -522,19 +520,18 @@ static const struct file_operations i2cdev_fops = { /* ------------------------------------------------------------------------- */ -/* - * The legacy "i2cdev_driver" is used primarily to get notifications when - * I2C adapters are added or removed, so that each one gets an i2c_dev - * and is thus made available to userspace driver code. - */ - static struct class *i2c_dev_class; -static int i2cdev_attach_adapter(struct i2c_adapter *adap) +static int i2cdev_attach_adapter(struct device *dev, void *dummy) { + struct i2c_adapter *adap; struct i2c_dev *i2c_dev; int res; + if (dev->type != &i2c_adapter_type) + return 0; + adap = to_i2c_adapter(dev); + i2c_dev = get_free_i2c_dev(adap); if (IS_ERR(i2c_dev)) return PTR_ERR(i2c_dev); @@ -561,10 +558,15 @@ error: return res; } -static int i2cdev_detach_adapter(struct i2c_adapter *adap) +static int i2cdev_detach_adapter(struct device *dev, void *dummy) { + struct i2c_adapter *adap; struct i2c_dev *i2c_dev; + if (dev->type != &i2c_adapter_type) + return 0; + adap = to_i2c_adapter(dev); + i2c_dev = i2c_dev_get_by_minor(adap->nr); if (!i2c_dev) /* attach_adapter must have failed */ return 0; @@ -577,12 +579,23 @@ static int i2cdev_detach_adapter(struct i2c_adapter *adap) return 0; } -static struct i2c_driver i2cdev_driver = { - .driver = { - .name = "dev_driver", - }, - .attach_adapter = i2cdev_attach_adapter, - .detach_adapter = i2cdev_detach_adapter, +int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + return i2cdev_attach_adapter(dev, NULL); + case BUS_NOTIFY_DEL_DEVICE: + return i2cdev_detach_adapter(dev, NULL); + } + + return 0; +} + +static struct notifier_block i2cdev_notifier = { + .notifier_call = i2cdev_notifier_call, }; /* ------------------------------------------------------------------------- */ @@ -607,10 +620,14 @@ static int __init i2c_dev_init(void) goto out_unreg_chrdev; } - res = i2c_add_driver(&i2cdev_driver); + /* Keep track of adapters which will be added or removed later */ + res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); if (res) goto out_unreg_class; + /* Bind to already existing adapters right away */ + i2c_for_each_dev(NULL, i2cdev_attach_adapter); + return 0; out_unreg_class: @@ -624,7 +641,8 @@ out: static void __exit i2c_dev_exit(void) { - i2c_del_driver(&i2cdev_driver); + bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier); + i2c_for_each_dev(NULL, i2cdev_detach_adapter); class_destroy(i2c_dev_class); unregister_chrdev(I2C_MAJOR, "i2c"); } -- cgit v1.2.2 From fe6fc25857d293546bd400432cdb77866c797c9b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 20 Mar 2011 14:50:53 +0100 Subject: i2c: Deprecate i2c_driver.attach_adapter and .detach_adapter The last legitimate user of i2c_driver.attach_adapter and .detach_adapter is gone, so we can finally deprecate these callbacks. The last few drivers which still use these will have to be updated to make use of standard I2C device instantiation ways instead. Signed-off-by: Jean Delvare --- drivers/i2c/Makefile | 1 + drivers/i2c/i2c-core.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 23ac61e2db39..beee6b2d361d 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_I2C_MUX) += i2c-mux.o obj-y += algos/ busses/ muxes/ ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG +CFLAGS_i2c-core.o := -Wno-deprecated-declarations diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b9fa1d0320b4..e5f76a0372fd 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -797,6 +797,9 @@ static int i2c_do_add_adapter(struct i2c_driver *driver, /* Let legacy drivers scan this bus for matching devices */ if (driver->attach_adapter) { + dev_warn(&adap->dev, "attach_adapter method is deprecated\n"); + dev_warn(&adap->dev, "Please use another way to instantiate " + "your i2c_client\n"); /* We ignore the return code; if it fails, too bad */ driver->attach_adapter(adap); } @@ -981,6 +984,7 @@ static int i2c_do_del_adapter(struct i2c_driver *driver, if (!driver->detach_adapter) return 0; + dev_warn(&adapter->dev, "detach_adapter method is deprecated\n"); res = driver->detach_adapter(adapter); if (res) dev_err(&adapter->dev, "detach_adapter failed (%d) " -- cgit v1.2.2 From 662cda8abb278f58237fa12b8ab3060ebefca4b8 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Sun, 20 Mar 2011 14:50:53 +0100 Subject: i2c-i801: SMBus patch for Intel DH89xxCC DeviceIDs Add the SMBus Controller DeviceIDs for the Intel DH89xxCC PCH. Signed-off-by: Seth Heasley Signed-off-by: Jean Delvare --- drivers/i2c/busses/Kconfig | 3 ++- drivers/i2c/busses/i2c-i801.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 230601e8853f..ad415e6ec5a1 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -98,8 +98,9 @@ config I2C_I801 EP80579 (Tolapai) ICH10 5/3400 Series (PCH) - Cougar Point (PCH) + 6 Series (PCH) Patsburg (PCH) + DH89xxCC (PCH) This driver can also be built as a module. If so, the module will be called i2c-i801. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 7979aef7ee7b..ed2e0c5ea37c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -44,11 +44,12 @@ ICH10 0x3a30 32 hard yes yes yes ICH10 0x3a60 32 hard yes yes yes 5/3400 Series (PCH) 0x3b30 32 hard yes yes yes - Cougar Point (PCH) 0x1c22 32 hard yes yes yes + 6 Series (PCH) 0x1c22 32 hard yes yes yes Patsburg (PCH) 0x1d22 32 hard yes yes yes Patsburg (PCH) IDF 0x1d70 32 hard yes yes yes Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes + DH89xxCC (PCH) 0x2330 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -621,6 +622,7 @@ static const struct pci_device_id i801_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, { 0, } }; -- cgit v1.2.2 From dd5eeb99f47d18c05efffcd247c0aa07eaa9ffaa Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 7 Mar 2011 11:21:15 +0100 Subject: firewire: core: increase default SPLIT_TIMEOUT value The SPLIT_TIMEOUT mechanism is intended to detect requests that somehow got lost. However, when the timeout value is too low, transactions that could have been completed successfully will be cancelled. Furthermore, there are chips whose firmwares ignore the configured split timeout and send late split response; known examples are the DM1x00 (BeBoB), TCD22x0 (DICE), and some OXUF936QSE firmwares. This patch changes the default timeout to two seconds, which happens to be the default on other OSes, too. Actual lost requests are extremely rare, so there should be no practical downside to increasing the split timeout even on devices that work correctly. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter --- drivers/firewire/core-card.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 3241dc4e1fc9..3c44fbc81acb 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -75,6 +75,13 @@ static size_t config_rom_length = 1 + 4 + 1 + 1; #define BIB_IRMC ((1) << 31) #define NODE_CAPABILITIES 0x0c0083c0 /* per IEEE 1394 clause 8.3.2.6.5.2 */ +/* + * IEEE-1394 specifies a default SPLIT_TIMEOUT value of 800 cycles (100 ms), + * but we have to make it longer because there are many devices whose firmware + * is just too slow for that. + */ +#define DEFAULT_SPLIT_TIMEOUT (2 * 8000) + #define CANON_OUI 0x000085 static void generate_config_rom(struct fw_card *card, __be32 *config_rom) @@ -512,10 +519,11 @@ void fw_card_initialize(struct fw_card *card, card->device = device; card->current_tlabel = 0; card->tlabel_mask = 0; - card->split_timeout_hi = 0; - card->split_timeout_lo = 800 << 19; - card->split_timeout_cycles = 800; - card->split_timeout_jiffies = DIV_ROUND_UP(HZ, 10); + card->split_timeout_hi = DEFAULT_SPLIT_TIMEOUT / 8000; + card->split_timeout_lo = (DEFAULT_SPLIT_TIMEOUT % 8000) << 19; + card->split_timeout_cycles = DEFAULT_SPLIT_TIMEOUT; + card->split_timeout_jiffies = + DIV_ROUND_UP(DEFAULT_SPLIT_TIMEOUT * HZ, 8000); card->color = 0; card->broadcast_channel = BROADCAST_CHANNEL_INITIAL; -- cgit v1.2.2 From 7a4e1e9c682cd87fe8a749b435b13afeef083c34 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Tue, 15 Mar 2011 00:04:42 +0100 Subject: firewire: sbp2: revert obsolete 'fix stall with "Unsolicited response"' Now that firewire-core sets the local node's SPLIT_TIMEOUT to 2 seconds per default, commit a481e97d3cdc40b9d58271675bd4f0abb79d4872 is no longer required. Signed-off-by: Stefan Richter --- drivers/firewire/sbp2.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index afa576a75a8e..77ed589b360d 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -472,18 +472,12 @@ static void complete_transaction(struct fw_card *card, int rcode, * So this callback only sets the rcode if it hasn't already * been set and only does the cleanup if the transaction * failed and we didn't already get a status write. - * - * Here we treat RCODE_CANCELLED like RCODE_COMPLETE because some - * OXUF936QSE firmwares occasionally respond after Split_Timeout and - * complete the ORB just fine. Note, we also get RCODE_CANCELLED - * from sbp2_cancel_orbs() if fw_cancel_transaction() == 0. */ spin_lock_irqsave(&card->lock, flags); if (orb->rcode == -1) orb->rcode = rcode; - - if (orb->rcode != RCODE_COMPLETE && orb->rcode != RCODE_CANCELLED) { + if (orb->rcode != RCODE_COMPLETE) { list_del(&orb->link); spin_unlock_irqrestore(&card->lock, flags); @@ -532,7 +526,8 @@ static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) list_for_each_entry_safe(orb, next, &list, link) { retval = 0; - fw_cancel_transaction(device->card, &orb->t); + if (fw_cancel_transaction(device->card, &orb->t) == 0) + continue; orb->rcode = RCODE_CANCELLED; orb->callback(orb, NULL); -- cgit v1.2.2 From 115881d395959b75c8c3bb94913f2ce869b8aa7a Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Tue, 15 Mar 2011 00:08:41 +0100 Subject: firewire: core: ignore link-active bit of new nodes, fix device recognition Like the older ieee1394 core driver, firewire-core skipped scanning of any new node whose PHY sent a self ID without "link active" bit. If a device had this bit off mistakenly, it meant that it was inaccessible to kernel drivers with the old IEEE 1394 driver stack but could still be accessed by userspace drivers through the raw1394 interface. But with firewire-core, userspace drivers don't get to see such buggy devices anymore. This is effectively a driver regression since this device bug is otherwise harmless. We now attempt to scan all devices, even repeaters that don't have a link or powered-down devices that have everything but their PHY shut down when plugged in. This results in futile repeated scanning attempts in case of such devices that really don't have an active link, but this doesn't hurt since recent workqueue infrastructure lets us run more concurrent scanning jobs than we can shake a stick at. This should fix accessibility of Focusrite Saffire PRO 26 I/O: http://sourceforge.net/mailarchive/forum.php?thread_name=20110314215622.5c751bb0%40stein&forum_name=ffado-user Signed-off-by: Stefan Richter --- drivers/firewire/core-device.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 57461923bacf..9a262439e3a7 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -955,8 +955,9 @@ static void fw_device_init(struct work_struct *work) device->config_rom_retries++; schedule_delayed_work(&device->work, RETRY_DELAY); } else { - fw_notify("giving up on config rom for node id %x\n", - device->node_id); + if (device->node->link_on) + fw_notify("giving up on config rom for node id %x\n", + device->node_id); if (device->node == device->card->root_node) fw_schedule_bm_work(device->card, 0); fw_device_release(&device->device); @@ -1169,9 +1170,12 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) switch (event) { case FW_NODE_CREATED: - case FW_NODE_LINK_ON: - if (!node->link_on) - break; + /* + * Attempt to scan the node, regardless whether its self ID has + * the L (link active) flag set or not. Some broken devices + * send L=0 but have an up-and-running link; others send L=1 + * without actually having a link. + */ create: device = kzalloc(sizeof(*device), GFP_ATOMIC); if (device == NULL) @@ -1214,6 +1218,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) break; case FW_NODE_INITIATED_RESET: + case FW_NODE_LINK_ON: device = node->data; if (device == NULL) goto create; @@ -1231,10 +1236,10 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) break; case FW_NODE_UPDATED: - if (!node->link_on || node->data == NULL) + device = node->data; + if (device == NULL) break; - device = node->data; device->node_id = node->node_id; smp_wmb(); /* update node_id before generation */ device->generation = card->generation; -- cgit v1.2.2 From b74ad5ae14def5e81ad0be3dddb96e485b861b1b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 17 Mar 2011 22:33:33 +0000 Subject: drm: Fix use-after-free in drm_gem_vm_close() As we may release the last reference, we need to store the device in a local variable in order to unlock afterwards. [ 60.140768] BUG: unable to handle kernel paging request at 6b6b6b9f [ 60.140973] IP: [] __mutex_unlock_slowpath+0x5a/0x111 [ 60.141014] *pdpt = 0000000024a54001 *pde = 0000000000000000 [ 60.141014] Oops: 0002 [#1] PREEMPT SMP [ 60.141014] last sysfs file: /sys/devices/LNXSYSTM:00/device:00/PNP0A08:00/PNP0C0A:00/power_supply/BAT0/voltage_now [ 60.141014] Modules linked in: uvcvideo ath9k pegasus ath9k_common ath9k_hw hid_egalax ath3k joydev asus_laptop sparse_keymap battery input_polldev [ 60.141014] [ 60.141014] Pid: 771, comm: meego-ux-daemon Not tainted 2.6.37.2-7.1 #1 EXOPC EXOPG06411/EXOPG06411 [ 60.141014] EIP: 0060:[] EFLAGS: 00010046 CPU: 0 [ 60.141014] EIP is at __mutex_unlock_slowpath+0x5a/0x111 [ 60.141014] EAX: 00000100 EBX: 6b6b6b9b ECX: e9b4a1b0 EDX: e4a4e580 [ 60.141014] ESI: db162558 EDI: 00000246 EBP: e480be50 ESP: e480be44 [ 60.141014] DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 [ 60.141014] Process meego-ux-daemon (pid: 771, ti=e480a000 task=e9b4a1b0 task.ti=e480a000) [ 60.141014] Stack: [ 60.141014] e4a4e580 db162558 f5a2f838 e480be58 c1536dd0 e480be68 c125ab1b db162558 [ 60.141014] db1624e0 e480be78 c10ba071 db162558 f760241c e480be94 c10bb0bc 000155fe [ 60.141014] f760241c f5a2f838 f5a2f8c8 00000000 e480bea4 c1037c24 00000000 f5a2f838 [ 60.141014] Call Trace: [ 60.141014] [] ? mutex_unlock+0x8/0xa [ 60.141014] [] ? drm_gem_vm_close+0x39/0x3d [ 60.141014] [] ? remove_vma+0x2d/0x58 [ 60.141014] [] ? exit_mmap+0x126/0x13f [ 60.141014] [] ? mmput+0x37/0x9a [ 60.141014] [] ? exec_mmap+0x178/0x19c [ 60.141014] [] ? _raw_spin_unlock+0x1d/0x36 [ 60.141014] [] ? flush_old_exec+0x42/0x75 [ 60.141014] [] ? load_elf_binary+0x32a/0x922 [ 60.141014] [] ? search_binary_handler+0x200/0x2ea [ 60.141014] [] ? search_binary_handler+0x159/0x2ea [ 60.141014] [] ? load_elf_binary+0x0/0x922 [ 60.141014] [] ? do_execve+0x1ff/0x2e6 [ 60.141014] [] ? sys_execve+0x2d/0x55 [ 60.141014] [] ? ptregs_execve+0x12/0x18 [ 60.141014] [] ? sysenter_do_call+0x12/0x3c [ 60.141014] [] ? init_centaur+0x9c/0x1ba [ 60.141014] Code: c1 00 75 0f ba 38 01 00 00 b8 8c 3a 6c c1 e8 cc 2e b0 ff 9c 58 8d 74 26 00 89 c7 fa 90 8d 74 26 00 e8 d2 b4 b2 ff b8 00 01 00 00 66 0f c1 43 04 38 e0 74 07 f3 90 8a 43 04 eb f5 83 3d 64 ef [ 60.141014] EIP: [] __mutex_unlock_slowpath+0x5a/0x111 SS:ESP 0068:e480be44 [ 60.141014] CR2: 000000006b6b6b9f Reported-by: Rusty Lynch Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_gem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 57ce27c9a747..74e4ff578017 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -499,11 +499,12 @@ EXPORT_SYMBOL(drm_gem_vm_open); void drm_gem_vm_close(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; + struct drm_device *dev = obj->dev; - mutex_lock(&obj->dev->struct_mutex); + mutex_lock(&dev->struct_mutex); drm_vm_close_locked(vma); drm_gem_object_unreference(obj); - mutex_unlock(&obj->dev->struct_mutex); + mutex_unlock(&dev->struct_mutex); } EXPORT_SYMBOL(drm_gem_vm_close); -- cgit v1.2.2 From 19b01b5fbf0b78930b3b06ee6080539c17b5d1fd Mon Sep 17 00:00:00 2001 From: Ilija Hadzic Date: Fri, 18 Mar 2011 16:58:04 -0500 Subject: drm/kernel: vblank wait on crtc > 1 Below is a patch against drm-next branch of 2.6.38-rc8+ kernel that adds the capability to wait on vblank events for CRTCs that are greater than 1 and thus cannot be represented with primary/secondary flags in the legacy interface. It was discussed on the dri-devel list in these two threads: http://lists.freedesktop.org/archives/dri-devel/2011-March/009009.html http://lists.freedesktop.org/archives/dri-devel/2011-March/009025.html This patch extends the interface to drm_wait_vblank ioctl so that crtc>1 can be represented. It also adds a new capability to drm_getcap ioctl so that the user space can check whether the new interface to drm_wait_vblank is supported (and fall back to the legacy interface if not) Signed-off-by: Ilija Hadzic Reviewed-by: Mario Kleiner Acked-by: Mario Kleiner Reviewed-by: Alex Deucher Tested-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_ioctl.c | 3 +++ drivers/gpu/drm/drm_irq.c | 15 ++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 7f6912a16761..3617b4c4bb57 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -280,6 +280,9 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) if (dev->driver->dumb_create) req->value = 1; break; + case DRM_CAP_HIGH_CRTC: + req->value = 1; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index a34ef97d3c81..741457bd1c46 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1125,7 +1125,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, { union drm_wait_vblank *vblwait = data; int ret = 0; - unsigned int flags, seq, crtc; + unsigned int flags, seq, crtc, high_crtc; if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled)) return -EINVAL; @@ -1134,16 +1134,21 @@ int drm_wait_vblank(struct drm_device *dev, void *data, return -EINVAL; if (vblwait->request.type & - ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { + ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | + _DRM_VBLANK_HIGH_CRTC_MASK)) { DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", vblwait->request.type, - (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); + (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK | + _DRM_VBLANK_HIGH_CRTC_MASK)); return -EINVAL; } flags = vblwait->request.type & _DRM_VBLANK_FLAGS_MASK; - crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; - + high_crtc = (vblwait->request.type & _DRM_VBLANK_HIGH_CRTC_MASK); + if (high_crtc) + crtc = high_crtc >> _DRM_VBLANK_HIGH_CRTC_SHIFT; + else + crtc = flags & _DRM_VBLANK_SECONDARY ? 1 : 0; if (crtc >= dev->num_crtcs) return -EINVAL; -- cgit v1.2.2 From 6b7d815c3f37f22c355b00362bc7c7d0bac9baea Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 25 Feb 2011 18:54:51 +0100 Subject: i2c-mxs: set controller to pio queue mode after reset mxs_reset_block() clears the PIO_QUEUE_MODE bit. So we have to set it again after a controller reset. Signed-off-by: Sascha Hauer Signed-off-by: Wolfram Sang Cc: Ben Dooks Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-mxs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 8022e2390a5a..caf96dc8ca1b 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -118,6 +118,8 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) { mxs_reset_block(i2c->regs); writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); + writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, + i2c->regs + MXS_I2C_QUEUECTRL_SET); } static void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len, @@ -347,8 +349,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev) /* Do reset to enforce correct startup after pinmuxing */ mxs_i2c_reset(i2c); - writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, - i2c->regs + MXS_I2C_QUEUECTRL_SET); adap = &i2c->adapter; strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name)); -- cgit v1.2.2 From fb3b06c8a1fd1a80298f13b738ab38ef8c73baff Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 8 Feb 2011 13:55:21 +1000 Subject: drm: check for modesetting on modeset ioctls Noticed this while working on some other things, helps if we check for modeset enabled on modesetting ioctls. Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_crtc.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 4c95b5fd9df3..799e1490cf24 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1073,6 +1073,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, uint32_t __user *encoder_id; struct drm_mode_group *mode_group; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); /* @@ -1244,6 +1247,9 @@ int drm_mode_getcrtc(struct drm_device *dev, struct drm_mode_object *obj; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, crtc_resp->crtc_id, @@ -1312,6 +1318,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, uint64_t __user *prop_values; uint32_t __user *encoder_ptr; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); @@ -1431,6 +1440,9 @@ int drm_mode_getencoder(struct drm_device *dev, void *data, struct drm_encoder *encoder; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, enc_resp->encoder_id, DRM_MODE_OBJECT_ENCODER); @@ -1486,6 +1498,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, int ret = 0; int i; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, crtc_req->crtc_id, DRM_MODE_OBJECT_CRTC); @@ -1603,6 +1618,9 @@ int drm_mode_cursor_ioctl(struct drm_device *dev, struct drm_crtc *crtc; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + if (!req->flags) { DRM_ERROR("no operation set\n"); return -EINVAL; @@ -1667,6 +1685,9 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_framebuffer *fb; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + if ((config->min_width > r->width) || (r->width > config->max_width)) { DRM_ERROR("mode new framebuffer width not within limits\n"); return -EINVAL; @@ -1724,6 +1745,9 @@ int drm_mode_rmfb(struct drm_device *dev, int ret = 0; int found = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); /* TODO check that we realy get a framebuffer back. */ @@ -1780,6 +1804,9 @@ int drm_mode_getfb(struct drm_device *dev, struct drm_framebuffer *fb; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { @@ -1813,6 +1840,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, int num_clips; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB); if (!obj) { @@ -1996,6 +2026,9 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); @@ -2042,6 +2075,9 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, struct drm_mode_modeinfo *umode = &mode_cmd->mode; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR); @@ -2211,6 +2247,9 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, uint64_t __user *values_ptr; uint32_t __user *blob_length_ptr; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); if (!obj) { @@ -2333,6 +2372,9 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, int ret = 0; void *blob_ptr; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); if (!obj) { @@ -2393,6 +2435,9 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, int ret = -EINVAL; int i; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); @@ -2509,6 +2554,9 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, int size; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { @@ -2560,6 +2608,9 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, int size; int ret = 0; + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC); if (!obj) { -- cgit v1.2.2 From db552b3331766e16c35550a4b83c3a42671ba73e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 19 Mar 2011 16:39:11 +0100 Subject: r8169: fix a bug in rtl8169_init_phy() commit 54405cde7624 (r8169: support control of advertising.) introduced a bug in rtl8169_init_phy() Reported-and-tested-by: Piotr Hosowicz Reported-and-tested-by: Linus Torvalds Signed-off-by: Eric Dumazet Acked-by:: Oliver Neukum Cc: Francois Romieu Tested-by: Anca Emanuel Signed-off-by: Linus Torvalds --- drivers/net/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 5e403511289d..493b0de3848b 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -2685,9 +2685,9 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL, ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | - tp->mii.supports_gmii ? + (tp->mii.supports_gmii ? ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full : 0); + ADVERTISED_1000baseT_Full : 0)); if (RTL_R8(PHYstatus) & TBI_Enable) netif_info(tp, link, dev, "TBI auto-negotiating\n"); -- cgit v1.2.2 From d6668c7cd4defdab1a74c8dd271b5ca23d99b627 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 23 Feb 2011 12:38:15 +0100 Subject: i2c-pxa2xx: use dynamic register layout This will prepare the driver to handle register layouts where certain registers are not available at all. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pxa.c | 70 +++++++++++++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index f4c19a97e0b3..a011455650e9 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -38,29 +38,49 @@ #include #include +struct pxa_reg_layout { + u32 ibmr; + u32 idbr; + u32 icr; + u32 isr; + u32 isar; +}; + +enum pxa_i2c_types { + REGS_PXA2XX, + REGS_PXA3XX, +}; + /* - * I2C register offsets will be shifted 0 or 1 bit left, depending on - * different SoCs + * I2C registers definitions */ -#define REG_SHIFT_0 (0 << 0) -#define REG_SHIFT_1 (1 << 0) -#define REG_SHIFT(d) ((d) & 0x1) +static struct pxa_reg_layout pxa_reg_layout[] = { + [REGS_PXA2XX] = { + .ibmr = 0x00, + .idbr = 0x10, + .icr = 0x20, + .isr = 0x30, + .isar = 0x40, + }, + [REGS_PXA3XX] = { + .ibmr = 0x00, + .idbr = 0x08, + .icr = 0x10, + .isr = 0x18, + .isar = 0x20, + }, +}; static const struct platform_device_id i2c_pxa_id_table[] = { - { "pxa2xx-i2c", REG_SHIFT_1 }, - { "pxa3xx-pwri2c", REG_SHIFT_0 }, + { "pxa2xx-i2c", REGS_PXA2XX }, + { "pxa3xx-pwri2c", REGS_PXA3XX }, { }, }; MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); /* - * I2C registers and bit definitions + * I2C bit definitions */ -#define IBMR (0x00) -#define IDBR (0x08) -#define ICR (0x10) -#define ISR (0x18) -#define ISAR (0x20) #define ICR_START (1 << 0) /* start bit */ #define ICR_STOP (1 << 1) /* stop bit */ @@ -111,7 +131,11 @@ struct pxa_i2c { u32 icrlog[32]; void __iomem *reg_base; - unsigned int reg_shift; + void __iomem *reg_ibmr; + void __iomem *reg_idbr; + void __iomem *reg_icr; + void __iomem *reg_isr; + void __iomem *reg_isar; unsigned long iobase; unsigned long iosize; @@ -121,11 +145,11 @@ struct pxa_i2c { unsigned int fast_mode :1; }; -#define _IBMR(i2c) ((i2c)->reg_base + (0x0 << (i2c)->reg_shift)) -#define _IDBR(i2c) ((i2c)->reg_base + (0x4 << (i2c)->reg_shift)) -#define _ICR(i2c) ((i2c)->reg_base + (0x8 << (i2c)->reg_shift)) -#define _ISR(i2c) ((i2c)->reg_base + (0xc << (i2c)->reg_shift)) -#define _ISAR(i2c) ((i2c)->reg_base + (0x10 << (i2c)->reg_shift)) +#define _IBMR(i2c) ((i2c)->reg_ibmr) +#define _IDBR(i2c) ((i2c)->reg_idbr) +#define _ICR(i2c) ((i2c)->reg_icr) +#define _ISR(i2c) ((i2c)->reg_isr) +#define _ISAR(i2c) ((i2c)->reg_isar) /* * I2C Slave mode address @@ -1001,6 +1025,7 @@ static int i2c_pxa_probe(struct platform_device *dev) struct resource *res; struct i2c_pxa_platform_data *plat = dev->dev.platform_data; const struct platform_device_id *id = platform_get_device_id(dev); + enum pxa_i2c_types i2c_type = id->driver_data; int ret; int irq; @@ -1044,7 +1069,12 @@ static int i2c_pxa_probe(struct platform_device *dev) ret = -EIO; goto eremap; } - i2c->reg_shift = REG_SHIFT(id->driver_data); + + i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr; + i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; + i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr; + i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr; + i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; i2c->iobase = res->start; i2c->iosize = resource_size(res); -- cgit v1.2.2 From b459396ee9398bdf61e3118ca730394f58e90c9c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 23 Feb 2011 12:38:16 +0100 Subject: ARM: pxa2xx: reorganize I2C files This patch moves the platform data definition from arch/arm/plat-pxa/include/plat/i2c.h to include/linux/i2c/pxa-i2c.h so it can be accessed from x86 the same way as on ARM. This change should make no functional change to the PXA code. The move is verified by building the following defconfigs: cm_x2xx_defconfig corgi_defconfig em_x270_defconfig ezx_defconfig imote2_defconfig pxa3xx_defconfig spitz_defconfig zeus_defconfig raumfeld_defconfig magician_defconfig mmp2_defconfig pxa168_defconfig pxa910_defconfig Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Dirk Brandewie Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index a011455650e9..fc2a90ed14cc 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -34,9 +34,9 @@ #include #include #include +#include #include -#include struct pxa_reg_layout { u32 ibmr; -- cgit v1.2.2 From 7e94dd154e934aa2137c427c3b1c8e9a6e465fcd Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 2 Mar 2011 11:26:53 +0100 Subject: i2c-pxa2xx: Add PCI support for PXA I2C controller The Sodaville I2C controller is almost the same as found on PXA2xx. The difference: - the register are at a different offset - no slave support The PCI probe code adds three platform devices which are probed then by the platform code. The X86 part also adds dummy clock defines because we don't have HW clock support. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Dirk Brandewie Signed-off-by: Ben Dooks --- drivers/i2c/busses/Kconfig | 7 +- drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-pxa-pci.c | 176 +++++++++++++++++++++++++++++++++++++++ drivers/i2c/busses/i2c-pxa.c | 27 +++++- 4 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 drivers/i2c/busses/i2c-pxa-pci.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 230601e8853f..b6e53c277276 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -546,15 +546,18 @@ config I2C_PUV3 config I2C_PXA tristate "Intel PXA2XX I2C adapter" - depends on ARCH_PXA || ARCH_MMP + depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF) help If you have devices in the PXA I2C bus, say yes to this option. This driver can also be built as a module. If so, the module will be called i2c-pxa. +config I2C_PXA_PCI + def_bool I2C_PXA && X86_32 && PCI && OF + config I2C_PXA_SLAVE bool "Intel PXA2XX I2C Slave comms support" - depends on I2C_PXA + depends on I2C_PXA && !X86_32 help Support I2C slave mode communications on the PXA I2C bus. This is necessary for systems where the PXA may be a target on the diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3878c959d4fa..1dd554e51440 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o +obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_S6000) += i2c-s6000.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c new file mode 100644 index 000000000000..6659d269b841 --- /dev/null +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -0,0 +1,176 @@ +/* + * The CE4100's I2C device is more or less the same one as found on PXA. + * It does not support slave mode, the register slightly moved. This PCI + * device provides three bars, every contains a single I2C controller. + */ +#include +#include +#include +#include +#include +#include + +#define CE4100_PCI_I2C_DEVS 3 + +struct ce4100_devices { + struct platform_device *pdev[CE4100_PCI_I2C_DEVS]; +}; + +static struct platform_device *add_i2c_device(struct pci_dev *dev, int bar) +{ + struct platform_device *pdev; + struct i2c_pxa_platform_data pdata; + struct resource res[2]; + struct device_node *child; + static int devnum; + int ret; + + memset(&pdata, 0, sizeof(struct i2c_pxa_platform_data)); + memset(&res, 0, sizeof(res)); + + res[0].flags = IORESOURCE_MEM; + res[0].start = pci_resource_start(dev, bar); + res[0].end = pci_resource_end(dev, bar); + + res[1].flags = IORESOURCE_IRQ; + res[1].start = dev->irq; + res[1].end = dev->irq; + + for_each_child_of_node(dev->dev.of_node, child) { + const void *prop; + struct resource r; + int ret; + + ret = of_address_to_resource(child, 0, &r); + if (ret < 0) + continue; + if (r.start != res[0].start) + continue; + if (r.end != res[0].end) + continue; + if (r.flags != res[0].flags) + continue; + + prop = of_get_property(child, "fast-mode", NULL); + if (prop) + pdata.fast_mode = 1; + + break; + } + + if (!child) { + dev_err(&dev->dev, "failed to match a DT node for bar %d.\n", + bar); + ret = -EINVAL; + goto out; + } + + pdev = platform_device_alloc("ce4100-i2c", devnum); + if (!pdev) { + of_node_put(child); + ret = -ENOMEM; + goto out; + } + pdev->dev.parent = &dev->dev; + pdev->dev.of_node = child; + + ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); + if (ret) + goto err; + + ret = platform_device_add_data(pdev, &pdata, sizeof(pdata)); + if (ret) + goto err; + + ret = platform_device_add(pdev); + if (ret) + goto err; + devnum++; + return pdev; +err: + platform_device_put(pdev); +out: + return ERR_PTR(ret); +} + +static int __devinit ce4100_i2c_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + int ret; + int i; + struct ce4100_devices *sds; + + ret = pci_enable_device_mem(dev); + if (ret) + return ret; + + if (!dev->dev.of_node) { + dev_err(&dev->dev, "Missing device tree node.\n"); + return -EINVAL; + } + sds = kzalloc(sizeof(*sds), GFP_KERNEL); + if (!sds) + goto err_mem; + + for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) { + sds->pdev[i] = add_i2c_device(dev, i); + if (IS_ERR(sds->pdev[i])) { + while (--i >= 0) + platform_device_unregister(sds->pdev[i]); + goto err_dev_add; + } + } + pci_set_drvdata(dev, sds); + return 0; + +err_dev_add: + pci_set_drvdata(dev, NULL); + kfree(sds); +err_mem: + pci_disable_device(dev); + return ret; +} + +static void __devexit ce4100_i2c_remove(struct pci_dev *dev) +{ + struct ce4100_devices *sds; + unsigned int i; + + sds = pci_get_drvdata(dev); + pci_set_drvdata(dev, NULL); + + for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) + platform_device_unregister(sds->pdev[i]); + + pci_disable_device(dev); + kfree(sds); +} + +static struct pci_device_id ce4100_i2c_devices[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, + { }, +}; +MODULE_DEVICE_TABLE(pci, ce4100_i2c_devices); + +static struct pci_driver ce4100_i2c_driver = { + .name = "ce4100_i2c", + .id_table = ce4100_i2c_devices, + .probe = ce4100_i2c_probe, + .remove = __devexit_p(ce4100_i2c_remove), +}; + +static int __init ce4100_i2c_init(void) +{ + return pci_register_driver(&ce4100_i2c_driver); +} +module_init(ce4100_i2c_init); + +static void __exit ce4100_i2c_exit(void) +{ + pci_unregister_driver(&ce4100_i2c_driver); +} +module_exit(ce4100_i2c_exit); + +MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Sebastian Andrzej Siewior "); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index fc2a90ed14cc..ab59b7e492ed 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -38,6 +38,13 @@ #include +#ifndef CONFIG_HAVE_CLK +#define clk_get(dev, id) NULL +#define clk_put(clk) do { } while (0) +#define clk_disable(clk) do { } while (0) +#define clk_enable(clk) do { } while (0) +#endif + struct pxa_reg_layout { u32 ibmr; u32 idbr; @@ -49,6 +56,7 @@ struct pxa_reg_layout { enum pxa_i2c_types { REGS_PXA2XX, REGS_PXA3XX, + REGS_CE4100, }; /* @@ -69,11 +77,19 @@ static struct pxa_reg_layout pxa_reg_layout[] = { .isr = 0x18, .isar = 0x20, }, + [REGS_CE4100] = { + .ibmr = 0x14, + .idbr = 0x0c, + .icr = 0x00, + .isr = 0x04, + /* no isar register */ + }, }; static const struct platform_device_id i2c_pxa_id_table[] = { { "pxa2xx-i2c", REGS_PXA2XX }, { "pxa3xx-pwri2c", REGS_PXA3XX }, + { "ce4100-i2c", REGS_CE4100 }, { }, }; MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); @@ -442,7 +458,8 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) writel(I2C_ISR_INIT, _ISR(i2c)); writel(readl(_ICR(i2c)) & ~ICR_UR, _ICR(i2c)); - writel(i2c->slave_addr, _ISAR(i2c)); + if (i2c->reg_isar) + writel(i2c->slave_addr, _ISAR(i2c)); /* set control register values */ writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c)); @@ -1074,7 +1091,8 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr; i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr; - i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; + if (i2c_type != REGS_CE4100) + i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; i2c->iobase = res->start; i2c->iosize = resource_size(res); @@ -1113,7 +1131,10 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &dev->dev; - ret = i2c_add_numbered_adapter(&i2c->adap); + if (i2c_type == REGS_CE4100) + ret = i2c_add_adapter(&i2c->adap); + else + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { printk(KERN_INFO "I2C: Failed to add bus\n"); goto eadapt; -- cgit v1.2.2 From c66dc529194be374556d166ee7ddb84a7d1d302b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 23 Feb 2011 12:38:18 +0100 Subject: i2c-pxa2xx: add support for shared IRQ handler Sodaville has three of them on a single IRQ. IRQF_DISABLED is removed because it is a NOP allready and scheduled for removal. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Dirk Brandewie Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pxa.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index ab59b7e492ed..fa8dd2c634d9 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -956,11 +956,17 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr) writel(icr, _ICR(i2c)); } +#define VALID_INT_SOURCE (ISR_SSD | ISR_ALD | ISR_ITE | ISR_IRF | \ + ISR_SAD | ISR_BED) static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) { struct pxa_i2c *i2c = dev_id; u32 isr = readl(_ISR(i2c)); + isr &= VALID_INT_SOURCE; + if (!isr) + return IRQ_NONE; + if (i2c_debug > 2 && 0) { dev_dbg(&i2c->adap.dev, "%s: ISR=%08x, ICR=%08x, IBMR=%02x\n", __func__, isr, readl(_ICR(i2c)), readl(_IBMR(i2c))); @@ -975,7 +981,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) /* * Always clear all pending IRQs. */ - writel(isr & (ISR_SSD|ISR_ALD|ISR_ITE|ISR_IRF|ISR_SAD|ISR_BED), _ISR(i2c)); + writel(isr, _ISR(i2c)); if (isr & ISR_SAD) i2c_pxa_slave_start(i2c, isr); @@ -1120,7 +1126,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.algo = &i2c_pxa_pio_algorithm; } else { i2c->adap.algo = &i2c_pxa_algorithm; - ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, + ret = request_irq(irq, i2c_pxa_handler, IRQF_SHARED, i2c->adap.name, i2c); if (ret) goto ereqirq; -- cgit v1.2.2 From 93c92cfdec8c3f8764894b37606c174f68fd9338 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 23 Feb 2011 12:38:19 +0100 Subject: i2c-pxa2xx: check timeout correctly timeout here maybe 0 if the event occured and a task with a higher priority stole the cpu and we were sleeping longer than the timeout value we specified. In case of a real timeout I changed the error code to I2C_RETRY so we retry the transfer. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Dirk Brandewie Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pxa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index fa8dd2c634d9..86128363a57f 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -770,8 +770,10 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) */ ret = i2c->msg_idx; - if (timeout == 0) + if (!timeout && i2c->msg_num) { i2c_pxa_scream_blue_murder(i2c, "timeout"); + ret = I2C_RETRY; + } out: return ret; -- cgit v1.2.2 From baa8cab012ff07d6835580b19c2fd93a20627823 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 23 Feb 2011 12:38:20 +0100 Subject: i2c-pxa2xx: pass of_node from platform driver to adapter and publish the of_node will auto-publish devices which are added to the device tree. Commit 925bb9c6 aka ("of/i2c: Fix module load order issue caused by of_i2c.c) moved the of_i2c_register_devices() function from the i2c core back to the drivers. This patch does the same thing for the pxa driver. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Dirk Brandewie Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pxa.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 86128363a57f..27b28e78666e 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1138,6 +1139,9 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &dev->dev; +#ifdef CONFIG_OF + i2c->adap.dev.of_node = dev->dev.of_node; +#endif if (i2c_type == REGS_CE4100) ret = i2c_add_adapter(&i2c->adap); @@ -1147,6 +1151,7 @@ static int i2c_pxa_probe(struct platform_device *dev) printk(KERN_INFO "I2C: Failed to add bus\n"); goto eadapt; } + of_i2c_register_devices(&i2c->adap); platform_set_drvdata(dev, i2c); -- cgit v1.2.2 From 23e74a86ab43e5cccbf90edb76fc396e36acc998 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Sun, 13 Mar 2011 15:53:28 +0200 Subject: i2c-pxa2xx: Fix register offsets Fix regression that was introduced by dynamic register layout. Signed-off-by: Vasily Khoruzhick Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pxa.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 27b28e78666e..b914184748c9 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -65,19 +65,19 @@ enum pxa_i2c_types { */ static struct pxa_reg_layout pxa_reg_layout[] = { [REGS_PXA2XX] = { - .ibmr = 0x00, - .idbr = 0x10, - .icr = 0x20, - .isr = 0x30, - .isar = 0x40, - }, - [REGS_PXA3XX] = { .ibmr = 0x00, .idbr = 0x08, .icr = 0x10, .isr = 0x18, .isar = 0x20, }, + [REGS_PXA3XX] = { + .ibmr = 0x00, + .idbr = 0x04, + .icr = 0x08, + .isr = 0x0c, + .isar = 0x10, + }, [REGS_CE4100] = { .ibmr = 0x14, .idbr = 0x0c, -- cgit v1.2.2 From d586dca06adddc6cee7177b013ee93eaffc9fe0e Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 21 Mar 2011 13:54:22 +0100 Subject: HID: add support for Skycable 0x3f07 wireless presenter This device contains the very same bug in report descriptor as the Ortek ones do (i.e. LogicalMinimum == 1, which is wrong for the key array). As we have more reports for the Ortek devices, we are keeping the driver name for now. Apparently there is a chip producer which sells chip with this buggy descriptor to multiple vendors. Thus if such reports start to come at highger frequency, we'll either have to rename the driver accordingly, or come up with more generic workaround. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 11 +++++++++-- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-ortek.c | 16 +++++++++++++--- 4 files changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index b7ec4057841d..111da3c6965b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -340,10 +340,17 @@ config HID_NTRIG Support for N-Trig touch screen. config HID_ORTEK - tristate "Ortek PKB-1700/WKB-2000 wireless keyboard and mouse trackpad" + tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad" depends on USB_HID ---help--- - Support for Ortek PKB-1700/WKB-2000 wireless keyboard + mouse trackpad. + There are certain devices which have LogicalMaximum wrong in the keyboard + usage page of their report descriptor. The most prevailing ones so far + are manufactured by Ortek, thus the name of the driver. Currently + supported devices by this driver are + + - Ortek PKB-1700 + - Ortek WKB-2000 + - Skycable wireless presenter config HID_PANTHERLORD tristate "Pantherlord/GreenAsia game controller" diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d66269ed7d..9809b58e3c7d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1448,6 +1448,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d485894ff4db..56e8e4ab65d0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -521,6 +521,9 @@ #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600 +#define USB_VENDOR_ID_SKYCABLE 0x1223 +#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07 + #define USB_VENDOR_ID_SONY 0x054c #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c index f9b7dd4f607f..0ffa1d2d64f0 100644 --- a/drivers/hid/hid-ortek.c +++ b/drivers/hid/hid-ortek.c @@ -1,8 +1,14 @@ /* - * HID driver for Ortek PKB-1700/WKB-2000 (wireless keyboard + mouse trackpad). - * Fixes LogicalMaximum error in HID report description. + * HID driver for various devices which are apparently based on the same chipset + * from certain vendor which produces chips that contain wrong LogicalMaximum + * value in their HID report descriptor. Currently supported devices are: + * + * Ortek PKB-1700 + * Ortek WKB-2000 + * Skycable wireless presenter * * Copyright (c) 2010 Johnathon Harris + * Copyright (c) 2011 Jiri Kosina */ /* @@ -22,8 +28,11 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) { - hid_info(hdev, "Fixing up Ortek WKB-2000 report descriptor\n"); + hid_info(hdev, "Fixing up logical minimum in report descriptor (Ortek)\n"); rdesc[55] = 0x92; + } else if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) { + hid_info(hdev, "Fixing up logical minimum in report descriptor (Skycable)\n"); + rdesc[53] = 0x65; } return rdesc; } @@ -31,6 +40,7 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc, static const struct hid_device_id ortek_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, { } }; MODULE_DEVICE_TABLE(hid, ortek_devices); -- cgit v1.2.2 From 9498f954a4ec389806333041a1018909c6fe0518 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 18 Mar 2011 14:27:52 +0100 Subject: HID: hid-multitouch: Auto detection of maxcontacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch enables support of autodetection of maxcontacts. When adding support for a new device, one is now able to let the device tell how many contacts it supports, or to manually set the value if the device happens to provide wrong information. Signed-off-by: Benjamin Tissoires Reviewed-by: Stéphane Chatty Reviewed-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 52 +++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index ee01e65e22d6..b9f9eeceaa98 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -60,8 +60,9 @@ struct mt_device { __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ __u8 num_received; /* how many contacts we received */ __u8 num_expected; /* expected last contact index */ + __u8 maxcontacts; bool curvalid; /* is the current contact valid? */ - struct mt_slot slots[0]; /* first slot */ + struct mt_slot *slots; }; struct mt_class { @@ -79,6 +80,8 @@ struct mt_class { #define MT_CLS_CYPRESS 4 #define MT_CLS_EGALAX 5 +#define MT_DEFAULT_MAXCONTACT 10 + /* * these device-dependent functions determine what slot corresponds * to a valid contact that was just read. @@ -95,12 +98,12 @@ static int cypress_compute_slot(struct mt_device *td) static int find_slot_from_contactid(struct mt_device *td) { int i; - for (i = 0; i < td->mtclass->maxcontacts; ++i) { + for (i = 0; i < td->maxcontacts; ++i) { if (td->slots[i].contactid == td->curdata.contactid && td->slots[i].touch_state) return i; } - for (i = 0; i < td->mtclass->maxcontacts; ++i) { + for (i = 0; i < td->maxcontacts; ++i) { if (!td->slots[i].seen_in_this_frame && !td->slots[i].touch_state) return i; @@ -113,8 +116,7 @@ static int find_slot_from_contactid(struct mt_device *td) struct mt_class mt_classes[] = { { .name = MT_CLS_DEFAULT, - .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, - .maxcontacts = 10 }, + .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, { .name = MT_CLS_DUAL_INRANGE_CONTACTID, .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTID, @@ -142,9 +144,19 @@ struct mt_class mt_classes[] = { static void mt_feature_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { - if (usage->hid == HID_DG_INPUTMODE) { - struct mt_device *td = hid_get_drvdata(hdev); + struct mt_device *td = hid_get_drvdata(hdev); + + switch (usage->hid) { + case HID_DG_INPUTMODE: td->inputmode = field->report->id; + break; + case HID_DG_CONTACTMAX: + td->maxcontacts = field->value[0]; + if (td->mtclass->maxcontacts) + /* check if the maxcontacts is given by the class */ + td->maxcontacts = td->mtclass->maxcontacts; + + break; } } @@ -208,8 +220,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, td->last_slot_field = usage->hid; return 1; case HID_DG_CONTACTID: - input_mt_init_slots(hi->input, - td->mtclass->maxcontacts); + input_mt_init_slots(hi->input, td->maxcontacts); td->last_slot_field = usage->hid; return 1; case HID_DG_WIDTH: @@ -292,7 +303,7 @@ static void mt_complete_slot(struct mt_device *td) if (td->curvalid) { int slotnum = mt_compute_slot(td); - if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts) + if (slotnum >= 0 && slotnum < td->maxcontacts) td->slots[slotnum] = td->curdata; } td->num_received++; @@ -307,7 +318,7 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) { int i; - for (i = 0; i < td->mtclass->maxcontacts; ++i) { + for (i = 0; i < td->maxcontacts; ++i) { struct mt_slot *s = &(td->slots[i]); if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && !s->seen_in_this_frame) { @@ -341,7 +352,7 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, struct mt_device *td = hid_get_drvdata(hid); __s32 quirks = td->mtclass->quirks; - if (hid->claimed & HID_CLAIMED_INPUT) { + if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { switch (usage->hid) { case HID_DG_INRANGE: if (quirks & MT_QUIRK_VALID_IS_INRANGE) @@ -442,9 +453,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) */ hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; - td = kzalloc(sizeof(struct mt_device) + - mtclass->maxcontacts * sizeof(struct mt_slot), - GFP_KERNEL); + td = kzalloc(sizeof(struct mt_device), GFP_KERNEL); if (!td) { dev_err(&hdev->dev, "cannot allocate multitouch data\n"); return -ENOMEM; @@ -461,6 +470,18 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto fail; + if (!td->maxcontacts) + td->maxcontacts = MT_DEFAULT_MAXCONTACT; + + td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), + GFP_KERNEL); + if (!td->slots) { + dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); + hid_hw_stop(hdev); + ret = -ENOMEM; + goto fail; + } + mt_set_input_mode(hdev); return 0; @@ -482,6 +503,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); hid_hw_stop(hdev); + kfree(td->slots); kfree(td); hid_set_drvdata(hdev, NULL); } -- cgit v1.2.2 From 043b403aede4a528ed99ceaf050f567f1283a23e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 18 Mar 2011 14:27:53 +0100 Subject: HID: hid-multitouch: migrate support for Stantum panels to the unified driver. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch merges hid-stantum to the generic multitouch driver. Signed-off-by: Benjamin Tissoires Reviewed-by: Stéphane Chatty Reviewed-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +- drivers/hid/Makefile | 1 - drivers/hid/hid-multitouch.c | 15 +++ drivers/hid/hid-stantum.c | 286 ------------------------------------------- 4 files changed, 16 insertions(+), 293 deletions(-) delete mode 100644 drivers/hid/hid-stantum.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index b7ec4057841d..3c72f16e725f 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -327,6 +327,7 @@ config HID_MULTITOUCH - 'Sensing Win7-TwoFinger' panel by GeneralTouch - eGalax dual-touch panels, including the Joojoo and Wetab tablets + - Stantum multitouch panels If unsure, say N. @@ -493,12 +494,6 @@ config HID_SONY ---help--- Support for Sony PS3 controller. -config HID_STANTUM - tristate "Stantum multitouch panel" - depends on USB_HID - ---help--- - Support for Stantum multitouch panel. - config HID_SUNPLUS tristate "Sunplus wireless desktop" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 06c68ae3abee..a13cb4e99fff 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -66,7 +66,6 @@ obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o -obj-$(CONFIG_HID_STANTUM) += hid-stantum.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index b9f9eeceaa98..5983e5559e81 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -79,6 +79,7 @@ struct mt_class { #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3 #define MT_CLS_CYPRESS 4 #define MT_CLS_EGALAX 5 +#define MT_CLS_STANTUM 6 #define MT_DEFAULT_MAXCONTACT 10 @@ -138,6 +139,9 @@ struct mt_class mt_classes[] = { .sn_move = 4096, .sn_pressure = 32, }, + { .name = MT_CLS_STANTUM, + .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, + { } }; @@ -552,6 +556,17 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, + /* Stantum panels */ + { .driver_data = MT_CLS_STANTUM, + HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, + USB_DEVICE_ID_MTP)}, + { .driver_data = MT_CLS_STANTUM, + HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, + USB_DEVICE_ID_MTP_STM)}, + { .driver_data = MT_CLS_STANTUM, + HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, + USB_DEVICE_ID_MTP_SITRONIX)}, + { } }; MODULE_DEVICE_TABLE(hid, mt_devices); diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c deleted file mode 100644 index b2be1d11916b..000000000000 --- a/drivers/hid/hid-stantum.c +++ /dev/null @@ -1,286 +0,0 @@ -/* - * HID driver for Stantum multitouch panels - * - * Copyright (c) 2009 Stephane Chatty - * - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include -#include -#include -#include - -MODULE_AUTHOR("Stephane Chatty "); -MODULE_DESCRIPTION("Stantum HID multitouch panels"); -MODULE_LICENSE("GPL"); - -#include "hid-ids.h" - -struct stantum_data { - __s32 x, y, z, w, h; /* x, y, pressure, width, height */ - __u16 id; /* touch id */ - bool valid; /* valid finger data, or just placeholder? */ - bool first; /* first finger in the HID packet? */ - bool activity; /* at least one active finger so far? */ -}; - -static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_GENDESK: - switch (usage->hid) { - case HID_GD_X: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_X); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_X, - field->logical_minimum, - field->logical_maximum, 0, 0); - return 1; - case HID_GD_Y: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_Y); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_Y, - field->logical_minimum, - field->logical_maximum, 0, 0); - return 1; - } - return 0; - - case HID_UP_DIGITIZER: - switch (usage->hid) { - case HID_DG_INRANGE: - case HID_DG_CONFIDENCE: - case HID_DG_INPUTMODE: - case HID_DG_DEVICEINDEX: - case HID_DG_CONTACTCOUNT: - case HID_DG_CONTACTMAX: - return -1; - - case HID_DG_TIPSWITCH: - /* touchscreen emulation */ - hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); - return 1; - - case HID_DG_WIDTH: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MAJOR); - return 1; - case HID_DG_HEIGHT: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MINOR); - input_set_abs_params(hi->input, ABS_MT_ORIENTATION, - 1, 1, 0, 0); - return 1; - case HID_DG_TIPPRESSURE: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_PRESSURE); - return 1; - - case HID_DG_CONTACTID: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TRACKING_ID); - return 1; - - } - return 0; - - case 0xff000000: - /* no input-oriented meaning */ - return -1; - } - - return 0; -} - -static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - if (usage->type == EV_KEY || usage->type == EV_ABS) - clear_bit(usage->code, *bit); - - return 0; -} - -/* - * this function is called when a whole finger has been parsed, - * so that it can decide what to send to the input layer. - */ -static void stantum_filter_event(struct stantum_data *sd, - struct input_dev *input) -{ - bool wide; - - if (!sd->valid) { - /* - * touchscreen emulation: if the first finger is not valid and - * there previously was finger activity, this is a release - */ - if (sd->first && sd->activity) { - input_event(input, EV_KEY, BTN_TOUCH, 0); - sd->activity = false; - } - return; - } - - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id); - input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y); - - wide = (sd->w > sd->h); - input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); - input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h); - input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w); - - input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z); - - input_mt_sync(input); - sd->valid = false; - - /* touchscreen emulation */ - if (sd->first) { - if (!sd->activity) { - input_event(input, EV_KEY, BTN_TOUCH, 1); - sd->activity = true; - } - input_event(input, EV_ABS, ABS_X, sd->x); - input_event(input, EV_ABS, ABS_Y, sd->y); - } - sd->first = false; -} - - -static int stantum_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct stantum_data *sd = hid_get_drvdata(hid); - - if (hid->claimed & HID_CLAIMED_INPUT) { - struct input_dev *input = field->hidinput->input; - - switch (usage->hid) { - case HID_DG_INRANGE: - /* this is the last field in a finger */ - stantum_filter_event(sd, input); - break; - case HID_DG_WIDTH: - sd->w = value; - break; - case HID_DG_HEIGHT: - sd->h = value; - break; - case HID_GD_X: - sd->x = value; - break; - case HID_GD_Y: - sd->y = value; - break; - case HID_DG_TIPPRESSURE: - sd->z = value; - break; - case HID_DG_CONTACTID: - sd->id = value; - break; - case HID_DG_CONFIDENCE: - sd->valid = !!value; - break; - case 0xff000002: - /* this comes only before the first finger */ - sd->first = true; - break; - - default: - /* ignore the others */ - return 1; - } - } - - /* we have handled the hidinput part, now remains hiddev */ - if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) - hid->hiddev_hid_event(hid, field, usage, value); - - return 1; -} - -static int stantum_probe(struct hid_device *hdev, - const struct hid_device_id *id) -{ - int ret; - struct stantum_data *sd; - - sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL); - if (!sd) { - hid_err(hdev, "cannot allocate Stantum data\n"); - return -ENOMEM; - } - sd->valid = false; - sd->first = false; - sd->activity = false; - hid_set_drvdata(hdev, sd); - - ret = hid_parse(hdev); - if (!ret) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - - if (ret) - kfree(sd); - - return ret; -} - -static void stantum_remove(struct hid_device *hdev) -{ - hid_hw_stop(hdev); - kfree(hid_get_drvdata(hdev)); - hid_set_drvdata(hdev, NULL); -} - -static const struct hid_device_id stantum_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) }, - { } -}; -MODULE_DEVICE_TABLE(hid, stantum_devices); - -static const struct hid_usage_id stantum_grabbed_usages[] = { - { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, - { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} -}; - -static struct hid_driver stantum_driver = { - .name = "stantum", - .id_table = stantum_devices, - .probe = stantum_probe, - .remove = stantum_remove, - .input_mapping = stantum_input_mapping, - .input_mapped = stantum_input_mapped, - .usage_table = stantum_grabbed_usages, - .event = stantum_event, -}; - -static int __init stantum_init(void) -{ - return hid_register_driver(&stantum_driver); -} - -static void __exit stantum_exit(void) -{ - hid_unregister_driver(&stantum_driver); -} - -module_init(stantum_init); -module_exit(stantum_exit); - -- cgit v1.2.2 From a841b62c5d5f75ce3676fde755696d30cc8de99a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 18 Mar 2011 14:27:54 +0100 Subject: HID: hid-multitouch: migrate Cando dual touch panels to hid-multitouch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch merges hid-cando into the unified multitouch driver. Signed-off-by: Benjamin Tissoires Reviewed-by: Stéphane Chatty Reviewed-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +- drivers/hid/Makefile | 1 - drivers/hid/hid-cando.c | 276 ------------------------------------------- drivers/hid/hid-multitouch.c | 14 +++ 4 files changed, 15 insertions(+), 283 deletions(-) delete mode 100644 drivers/hid/hid-cando.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 3c72f16e725f..1edb0bd72a60 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -100,12 +100,6 @@ config HID_BELKIN ---help--- Support for Belkin Flip KVM and Wireless keyboard. -config HID_CANDO - tristate "Cando dual touch panel" - depends on USB_HID - ---help--- - Support for Cando dual touch panel. - config HID_CHERRY tristate "Cherry Cymotion keyboard" if EXPERT depends on USB_HID @@ -320,6 +314,7 @@ config HID_MULTITOUCH Generic support for HID multitouch panels. Say Y here if you have one of the following devices: + - Cando dual touch panel - Cypress TrueTouch panels - Hanvon dual touch panels - IrTouch Infrared USB panels diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index a13cb4e99fff..f8b90e4e4841 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -30,7 +30,6 @@ obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o -obj-$(CONFIG_HID_CANDO) += hid-cando.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c deleted file mode 100644 index 1ea066c55201..000000000000 --- a/drivers/hid/hid-cando.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * HID driver for Cando dual-touch panels - * - * Copyright (c) 2010 Stephane Chatty - * - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include -#include -#include -#include - -MODULE_AUTHOR("Stephane Chatty "); -MODULE_DESCRIPTION("Cando dual-touch panel"); -MODULE_LICENSE("GPL"); - -#include "hid-ids.h" - -struct cando_data { - __u16 x, y; - __u8 id; - __s8 oldest; /* id of the oldest finger in previous frame */ - bool valid; /* valid finger data, or just placeholder? */ - bool first; /* is this the first finger in this frame? */ - __s8 firstid; /* id of the first finger in the frame */ - __u16 firstx, firsty; /* (x, y) of the first finger in the frame */ -}; - -static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_GENDESK: - switch (usage->hid) { - case HID_GD_X: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_X); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_X, - field->logical_minimum, - field->logical_maximum, 0, 0); - return 1; - case HID_GD_Y: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_Y); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_Y, - field->logical_minimum, - field->logical_maximum, 0, 0); - return 1; - } - return 0; - - case HID_UP_DIGITIZER: - switch (usage->hid) { - case HID_DG_TIPSWITCH: - case HID_DG_CONTACTMAX: - return -1; - case HID_DG_INRANGE: - /* touchscreen emulation */ - hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); - return 1; - case HID_DG_CONTACTID: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TRACKING_ID); - return 1; - } - return 0; - } - - return 0; -} - -static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - if (usage->type == EV_KEY || usage->type == EV_ABS) - clear_bit(usage->code, *bit); - - return 0; -} - -/* - * this function is called when a whole finger has been parsed, - * so that it can decide what to send to the input layer. - */ -static void cando_filter_event(struct cando_data *td, struct input_dev *input) -{ - td->first = !td->first; /* touchscreen emulation */ - - if (!td->valid) { - /* - * touchscreen emulation: if this is the second finger and - * the first was valid, the first was the oldest; if the - * first was not valid and there was a valid finger in the - * previous frame, this is a release. - */ - if (td->first) { - td->firstid = -1; - } else if (td->firstid >= 0) { - input_event(input, EV_ABS, ABS_X, td->firstx); - input_event(input, EV_ABS, ABS_Y, td->firsty); - td->oldest = td->firstid; - } else if (td->oldest >= 0) { - input_event(input, EV_KEY, BTN_TOUCH, 0); - td->oldest = -1; - } - - return; - } - - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); - input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); - - input_mt_sync(input); - - /* - * touchscreen emulation: if there was no touching finger previously, - * emit touch event - */ - if (td->oldest < 0) { - input_event(input, EV_KEY, BTN_TOUCH, 1); - td->oldest = td->id; - } - - /* - * touchscreen emulation: if this is the first finger, wait for the - * second; the oldest is then the second if it was the oldest already - * or if there was no first, the first otherwise. - */ - if (td->first) { - td->firstx = td->x; - td->firsty = td->y; - td->firstid = td->id; - } else { - int x, y, oldest; - if (td->id == td->oldest || td->firstid < 0) { - x = td->x; - y = td->y; - oldest = td->id; - } else { - x = td->firstx; - y = td->firsty; - oldest = td->firstid; - } - input_event(input, EV_ABS, ABS_X, x); - input_event(input, EV_ABS, ABS_Y, y); - td->oldest = oldest; - } -} - - -static int cando_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct cando_data *td = hid_get_drvdata(hid); - - if (hid->claimed & HID_CLAIMED_INPUT) { - struct input_dev *input = field->hidinput->input; - - switch (usage->hid) { - case HID_DG_INRANGE: - td->valid = value; - break; - case HID_DG_CONTACTID: - td->id = value; - break; - case HID_GD_X: - td->x = value; - break; - case HID_GD_Y: - td->y = value; - cando_filter_event(td, input); - break; - case HID_DG_TIPSWITCH: - /* avoid interference from generic hidinput handling */ - break; - - default: - /* fallback to the generic hidinput handling */ - return 0; - } - } - - /* we have handled the hidinput part, now remains hiddev */ - if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) - hid->hiddev_hid_event(hid, field, usage, value); - - return 1; -} - -static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - int ret; - struct cando_data *td; - - td = kmalloc(sizeof(struct cando_data), GFP_KERNEL); - if (!td) { - hid_err(hdev, "cannot allocate Cando Touch data\n"); - return -ENOMEM; - } - hid_set_drvdata(hdev, td); - td->first = false; - td->oldest = -1; - td->valid = false; - - ret = hid_parse(hdev); - if (!ret) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - - if (ret) - kfree(td); - - return ret; -} - -static void cando_remove(struct hid_device *hdev) -{ - hid_hw_stop(hdev); - kfree(hid_get_drvdata(hdev)); - hid_set_drvdata(hdev, NULL); -} - -static const struct hid_device_id cando_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, - { } -}; -MODULE_DEVICE_TABLE(hid, cando_devices); - -static const struct hid_usage_id cando_grabbed_usages[] = { - { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, - { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} -}; - -static struct hid_driver cando_driver = { - .name = "cando-touch", - .id_table = cando_devices, - .probe = cando_probe, - .remove = cando_remove, - .input_mapping = cando_input_mapping, - .input_mapped = cando_input_mapped, - .usage_table = cando_grabbed_usages, - .event = cando_event, -}; - -static int __init cando_init(void) -{ - return hid_register_driver(&cando_driver); -} - -static void __exit cando_exit(void) -{ - hid_unregister_driver(&cando_driver); -} - -module_init(cando_init); -module_exit(cando_exit); - diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 5983e5559e81..e6e1ea251490 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -514,6 +514,20 @@ static void mt_remove(struct hid_device *hdev) static const struct hid_device_id mt_devices[] = { + /* Cando panels */ + { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, + HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, + { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, + HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, + { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, + HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, + { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, + HID_USB_DEVICE(USB_VENDOR_ID_CANDO, + USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, + /* Cypress panel */ { .driver_data = MT_CLS_CYPRESS, HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, -- cgit v1.2.2 From 1e648a13720ef5de51f132501acf3e443d1a36d4 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 18 Mar 2011 14:27:55 +0100 Subject: HID: hid-multitouch: refactor initialization of ABS_MT_ORIENTATION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The way the input_set_abs_params was called for the new composite field ABS_MT_ORIENTATION was not very clear at second reading. We can remove the non-necessary call to set_abs and use the simple call to input_set_abs_params. Signed-off-by: Benjamin Tissoires Reviewed-by: Stéphane Chatty Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index e6e1ea251490..d31301e85c56 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -235,9 +235,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); - field->logical_maximum = 1; - field->logical_minimum = 0; - set_abs(hi->input, ABS_MT_ORIENTATION, field, 0); + input_set_abs_params(hi->input, + ABS_MT_ORIENTATION, 0, 1, 0, 0); td->last_slot_field = usage->hid; return 1; case HID_DG_TIPPRESSURE: -- cgit v1.2.2 From 8b8bae901ce23addbdcdb54fa1696fb2d049feb5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 5 Mar 2011 13:21:51 +0100 Subject: PCI/ACPI: Report ASPM support to BIOS if not disabled from command line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to distinguish the situation in which ASPM support is disabled from the command line or through .config from the situation in which it is disabled, because the hardware or BIOS can't handle it. In the former case we should not report ASPM support to the BIOS through ACPI _OSC, but in the latter case we should do that. Introduce pcie_aspm_support_enabled() that can be used by acpi_pci_root_add() to determine whether or not it should report ASPM support to the BIOS through _OSC. Cc: stable@kernel.org References: https://bugzilla.kernel.org/show_bug.cgi?id=29722 References: https://bugzilla.kernel.org/show_bug.cgi?id=20232 Reported-and-tested-by: Ortwin Glück Reviewed-by: Kenji Kaneshige Tested-by: Kenji Kaneshige Signed-off-by: Rafael J. Wysocki Signed-off-by: Jesse Barnes --- drivers/acpi/pci_root.c | 2 +- drivers/pci/pcie/aspm.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 85249395623b..c7358dd68b31 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -564,7 +564,7 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) /* Indicate support for various _OSC capabilities. */ if (pci_ext_cfg_avail(root->bus->self)) flags |= OSC_EXT_PCI_CONFIG_SUPPORT; - if (pcie_aspm_enabled()) + if (pcie_aspm_support_enabled()) flags |= OSC_ACTIVE_STATE_PWR_SUPPORT | OSC_CLOCK_PWR_CAPABILITY_SUPPORT; if (pci_msi_enabled()) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 3188cd96b338..bbdb4fd85b9c 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -69,6 +69,7 @@ struct pcie_link_state { }; static int aspm_disabled, aspm_force, aspm_clear_state; +static bool aspm_support_enabled = true; static DEFINE_MUTEX(aspm_lock); static LIST_HEAD(link_list); @@ -896,6 +897,7 @@ static int __init pcie_aspm_disable(char *str) { if (!strcmp(str, "off")) { aspm_disabled = 1; + aspm_support_enabled = false; printk(KERN_INFO "PCIe ASPM is disabled\n"); } else if (!strcmp(str, "force")) { aspm_force = 1; @@ -930,3 +932,8 @@ int pcie_aspm_enabled(void) } EXPORT_SYMBOL(pcie_aspm_enabled); +bool pcie_aspm_support_enabled(void) +{ + return aspm_support_enabled; +} +EXPORT_SYMBOL(pcie_aspm_support_enabled); -- cgit v1.2.2 From 1a680b7c325882188865f05b9a88d32f75f26495 Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Mon, 21 Mar 2011 03:29:08 +0000 Subject: PCI: PCIe links may not get configured for ASPM under POWERSAVE mode v3 -> v2: Moved ASPM enabling logic to pci_set_power_state() v2 -> v1: Preserved the logic in pci_raw_set_power_state() : Added ASPM enabling logic after scanning Root Bridge : http://marc.info/?l=linux-pci&m=130046996216391&w=2 v1 : http://marc.info/?l=linux-pci&m=130013164703283&w=2 The assumption made in commit 41cd766b065970ff6f6c89dd1cf55fa706c84a3d (PCI: Don't enable aspm before drivers have had a chance to veto it) that pci_enable_device() will result in re-configuring ASPM when aspm_policy is POWERSAVE is no longer valid. This is due to commit 97c145f7c87453cec90e91238fba5fe2c1561b32 (PCI: read current power state at enable time) which resets dev->current_state to D0. Due to this the call to pcie_aspm_pm_state_change() is never made. Note the equality check (below) that returns early: ./drivers/pci/pci.c: pci_raw_set_pci_power_state() 546 /* Check if we're already there */ 547 if (dev->current_state == state) 548 return 0; Therefore OSPM never configures the PCIe links for ASPM to turn them "on". Fix it by configuring ASPM from the pci_enable_device() code path. This also allows a driver such as the e1000e networking driver a chance to disable ASPM (L0s, L1), if need be, prior to enabling the device. A driver may perform this action if the device is known to mis-behave wrt ASPM. Signed-off-by: Naga Chumbalkar Acked-by: Rafael J. Wysocki Cc: Matthew Garrett Signed-off-by: Jesse Barnes --- drivers/pci/pci.c | 6 ++++++ drivers/pci/pcie/aspm.c | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b714d787bddd..2472e7177b4b 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -740,6 +740,12 @@ int pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (!__pci_complete_power_transition(dev, state)) error = 0; + /* + * When aspm_policy is "powersave" this call ensures + * that ASPM is configured. + */ + if (!error && dev->bus->self) + pcie_aspm_powersave_config_link(dev->bus->self); return error; } diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index bbdb4fd85b9c..e61b82e611c2 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -708,6 +708,28 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev) up_read(&pci_bus_sem); } +void pcie_aspm_powersave_config_link(struct pci_dev *pdev) +{ + struct pcie_link_state *link = pdev->link_state; + + if (aspm_disabled || !pci_is_pcie(pdev) || !link) + return; + + if (aspm_policy != POLICY_POWERSAVE) + return; + + if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && + (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + pcie_config_aspm_path(link); + pcie_set_clkpm(link, policy_to_clkpm_state(link)); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + /* * pci_disable_link_state - disable pci device's link state, so the link will * never enter specific states -- cgit v1.2.2 From bbfa306a1e5d9618231aa0de3d52a8eb1219d0c3 Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Mon, 21 Mar 2011 03:29:14 +0000 Subject: PCI: Changing ASPM policy, via /sys, to POWERSAVE could cause NMIs v3 -> v2: Modified the text that describes the problem v2 -> v1: Returned -EPERM v1 : http://marc.info/?l=linux-pci&m=130013194803727&w=2 For servers whose hardware cannot handle ASPM the BIOS ought to set the FADT bit shown below: In Sec 5.2.9.3 (IA-PC Boot Arch. Flags) of ACPI4.0a Specification, please see Table 5-11: PCIe ASPM Controls: If set, indicates to OSPM that it must not enable OPSM ASPM control on this platform. However there are shipping servers whose BIOS did not set this bit. (An example is the HP ProLiant DL385 G6. A Maintenance BIOS will fix that). For such servers even if a call is made via pci_no_aspm(), based on _OSC support in the BIOS, it may be too late because the ASPM code may have already allocated and filled its "link_list". So if a user sets the ASPM "policy" to "powersave" via /sys then pcie_aspm_set_policy() will run through the "link_list" and re-configure ASPM policy on devices that advertise ASPM L0s/L1 capability: # echo powersave > /sys/module/pcie_aspm/parameters/policy # cat /sys/module/pcie_aspm/parameters/policy default performance [powersave] That can cause NMIs since the hardware doesn't play well with ASPM: [ 1651.906015] NMI: PCI system error (SERR) for reason b1 on CPU 0. [ 1651.906015] Dazed and confused, but trying to continue Ideally, the BIOS should have set that FADT bit in the first place but we could be more robust - especially given the fact that Windows doesn't cause NMIs in the above scenario. There should be a sanity check to not allow a user to modify ASPM policy when aspm_disabled is set. Signed-off-by: Naga Chumbalkar Acked-by: Rafael J. Wysocki Cc: Matthew Garrett Signed-off-by: Jesse Barnes --- drivers/pci/pcie/aspm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index e61b82e611c2..eee09f756ec9 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -770,6 +770,8 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) int i; struct pcie_link_state *link; + if (aspm_disabled) + return -EPERM; for (i = 0; i < ARRAY_SIZE(policy_str); i++) if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) break; @@ -824,6 +826,8 @@ static ssize_t link_state_store(struct device *dev, struct pcie_link_state *link, *root = pdev->link_state->root; u32 val = buf[0] - '0', state = 0; + if (aspm_disabled) + return -EPERM; if (n < 1 || val > 3) return -EINVAL; -- cgit v1.2.2 From eca67315e0e0d5fd91264d79c88694006dbc7d31 Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Mon, 21 Mar 2011 03:29:20 +0000 Subject: PCI: Disable ASPM when _OSC control is not granted for PCIe services v3 -> v2: Added text to describe the problem v2 -> v1: Split this patch from v1 v1 : Part of: http://marc.info/?l=linux-pci&m=130042212003242&w=2 Disable ASPM when no _OSC control for PCIe services is granted by the BIOS. This is to protect systems with a buggy BIOS that did not set the ACPI FADT "ASPM Controls" bit even though the underlying HW can't do ASPM. To turn "on" ASPM the minimum the BIOS needs to do: 1. Clear the ACPI FADT "ASPM Controls" bit. 2. Support _OSC appropriately There is no _OSC Control bit for ASPM. However, we expect the BIOS to support _OSC for a Root Bridge that originates a PCIe hierarchy. If this is not the case - we are better off not enabling ASPM on that server. Commit 852972acff8f10f3a15679be2059bb94916cba5d (ACPI: Disable ASPM if the Platform won't provide _OSC control for PCIe) describes the above scenario. To quote verbatim from there: [The PCI SIG documentation for the _OSC OS/firmware handshaking interface states: "If the _OSC control method is absent from the scope of a host bridge device, then the operating system must not enable or attempt to use any features defined in this section for the hierarchy originated by the host bridge." The obvious interpretation of this is that the OS should not attempt to use PCIe hotplug, PME or AER - however, the specification also notes that an _OSC method is *required* for PCIe hierarchies, and experimental validation with An Alternative OS indicates that it doesn't use any PCIe functionality if the _OSC method is missing. That arguably means we shouldn't be using MSI or extended config space, but right now our problems seem to be limited to vendors being surprised when ASPM gets enabled on machines when other OSs refuse to do so. So, for now, let's just disable ASPM if the _OSC method doesn't exist or refuses to hand over PCIe capability control.] Signed-off-by: Naga Chumbalkar Cc: Rafael J. Wysocki Cc: Matthew Garrett Signed-off-by: Jesse Barnes --- drivers/acpi/pci_root.c | 9 +++++++-- drivers/pci/pcie/portdrv_core.c | 5 +---- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index c7358dd68b31..f911a2f8cc34 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -591,12 +592,16 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) status = acpi_pci_osc_control_set(device->handle, &flags, OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); - if (ACPI_SUCCESS(status)) + if (ACPI_SUCCESS(status)) { dev_info(root->bus->bridge, "ACPI _OSC control (0x%02x) granted\n", flags); - else + } else { dev_dbg(root->bus->bridge, "ACPI _OSC request failed (code %d)\n", status); + printk(KERN_INFO "Unable to assume _OSC PCIe control. " + "Disabling ASPM\n"); + pcie_no_aspm(); + } } pci_acpi_add_bus_pm_notifier(device, root->bus); diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index 5130d0d22390..595654a1a6a6 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "../pci.h" #include "portdrv.h" @@ -356,10 +355,8 @@ int pcie_port_device_register(struct pci_dev *dev) /* Get and check PCI Express port services */ capabilities = get_port_device_capability(dev); - if (!capabilities) { - pcie_no_aspm(); + if (!capabilities) return 0; - } pci_set_master(dev); /* -- cgit v1.2.2 From 396bd766a604b823369962ee0203c603b9c0bdec Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Mon, 21 Mar 2011 17:59:35 +0100 Subject: hwmon: (sht15) Spelling fix Remove one too many "n" in a word. Signed-off-by: Justin P. Mattock Acked-by: Jean Delvare --- drivers/hwmon/sht15.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index a610e7880fb3..3ba7dd82589a 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -610,7 +610,7 @@ static int __devexit sht15_remove(struct platform_device *pdev) struct sht15_data *data = platform_get_drvdata(pdev); /* Make sure any reads from the device are done and - * prevent new ones beginnning */ + * prevent new ones from beginning */ mutex_lock(&data->read_lock); hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group); -- cgit v1.2.2 From ccd32e735de7a941906e093f8dca924bb05c5794 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 21 Mar 2011 17:59:35 +0100 Subject: hwmon: (sht15) Fix integer overflow in humidity calculation An integer overflow occurs in the calculation of RHlinear when the relative humidity is greater than around 30%. The consequence is a subtle (but noticeable) error in the resulting humidity measurement. Signed-off-by: Vivien Didelot Signed-off-by: Jean Delvare Cc: stable@kernel.org Cc: Jonathan Cameron --- drivers/hwmon/sht15.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 3ba7dd82589a..1a9c32d6893a 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -333,11 +333,11 @@ static inline int sht15_calc_humid(struct sht15_data *data) const int c1 = -4; const int c2 = 40500; /* x 10 ^ -6 */ - const int c3 = -2800; /* x10 ^ -9 */ + const int c3 = -28; /* x 10 ^ -7 */ RHlinear = c1*1000 + c2 * data->val_humid/1000 - + (data->val_humid * data->val_humid * c3)/1000000; + + (data->val_humid * data->val_humid * c3) / 10000; return (temp - 25000) * (10000 + 80 * data->val_humid) / 1000000 + RHlinear; } -- cgit v1.2.2 From 39c3e721d65793373e7bc6f5dad0591ef6d09268 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 21 Mar 2011 17:59:35 +0100 Subject: Let Kconfig handle lis3lv02d dependencies The dependencies between the various lis3lv02d drivers make it impossible to split them to different directories, while we really want to do this. Move handling of dependencies from Makefile to Kconfig, to make the move possible at all. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck Acked-by: Eric Piel Acked-by: Jonathan Cameron Tested-by: Eric Piel Tested-by: Takashi Iwai --- drivers/hwmon/Kconfig | 43 +++++++++++++++++++------------------------ drivers/hwmon/Makefile | 9 ++++++--- 2 files changed, 25 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 1bfb4439e4e1..c48101cf58f4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2,6 +2,12 @@ # Hardware monitoring chip drivers configuration # +config SENSORS_LIS3LV02D + tristate + depends on INPUT + select INPUT_POLLDEV + default n + menuconfig HWMON tristate "Hardware Monitoring support" depends on HAS_IOMEM @@ -1218,7 +1224,7 @@ config SENSORS_ULTRA45 config SENSORS_LIS3_SPI tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" depends on !ACPI && SPI_MASTER && INPUT - select INPUT_POLLDEV + select SENSORS_LIS3LV02D default n help This driver provides support for the LIS3LV02Dx accelerometer connected @@ -1235,7 +1241,7 @@ config SENSORS_LIS3_SPI config SENSORS_LIS3_I2C tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)" depends on I2C && INPUT - select INPUT_POLLDEV + select SENSORS_LIS3LV02D default n help This driver provides support for the LIS3LV02Dx accelerometer connected @@ -1296,35 +1302,24 @@ config SENSORS_ATK0110 This driver can also be built as a module. If so, the module will be called asus_atk0110. -config SENSORS_LIS3LV02D - tristate "STMicroeletronics LIS3* three-axis digital accelerometer" +config HP_ACCEL + tristate "HP laptop accelerometer" depends on INPUT - select INPUT_POLLDEV + select SENSORS_LIS3LV02D select NEW_LEDS select LEDS_CLASS default n help - This driver provides support for the LIS3* accelerometers, such as the - LIS3LV02DL or the LIS331DL. In particular, it can be found in a number - of HP laptops, which have the "Mobile Data Protection System 3D" or - "3D DriveGuard" feature. On such systems the driver should load - automatically (via ACPI alias). The accelerometer might also be found - in other systems, connected via SPI or I2C. The accelerometer data is - readable via /sys/devices/platform/lis3lv02d. + This driver provides support for the "Mobile Data Protection System 3D" + or "3D DriveGuard" feature of HP laptops. On such systems the driver + should load automatically (via ACPI alias). - This driver also provides an absolute input class device, allowing - a laptop to act as a pinball machine-esque joystick. It provides also - a misc device which can be used to detect free-fall. On HP laptops, - if the led infrastructure is activated, support for a led indicating - disk protection will be provided as hp::hddprotect. For more - information on the feature, refer to Documentation/hwmon/lis3lv02d. + Support for a led indicating disk protection will be provided as + hp::hddprotect. For more information on the feature, refer to + Documentation/hwmon/lis3lv02d. - This driver can also be built as modules. If so, the core module - will be called lis3lv02d and a specific module for HP laptops will be - called hp_accel. - - Say Y here if you have an applicable laptop and want to experience - the awesome power of lis3lv02d. + To compile this driver as a module, choose M here: the module will + be called hp_accel. endif # ACPI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8a238dec5691..94bf27482979 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -5,8 +5,12 @@ obj-$(CONFIG_HWMON) += hwmon.o obj-$(CONFIG_HWMON_VID) += hwmon-vid.o +# Helper drivers +obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o + # APCI drivers obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o +obj-$(CONFIG_HP_ACCEL) += hp_accel.o # Native drivers # asb100, then w83781d go first, as they can override other drivers' addresses. @@ -63,9 +67,8 @@ obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o -obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o -obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o -obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d.o lis3lv02d_i2c.o +obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d_spi.o +obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d_i2c.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM70) += lm70.o obj-$(CONFIG_SENSORS_LM73) += lm73.o -- cgit v1.2.2 From efcfed9bad88be8193ee6a1b8e72d7381e7b0e0e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: Move hp_accel to drivers/platform/x86 The hp_accel driver isn't a hardware monitoring driver, so it doesn't belong to drivers/hwmon. Move it to drivers/platform/x86, assuming HP doesn't ship non-x86 laptops. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck Acked-by: Eric Piel Acked-by: Jonathan Cameron Tested-by: Eric Piel Tested-by: Takashi Iwai --- drivers/hwmon/Kconfig | 19 -- drivers/hwmon/Makefile | 1 - drivers/hwmon/hp_accel.c | 405 ---------------------------------------- drivers/platform/x86/Kconfig | 18 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/hp_accel.c | 404 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 423 insertions(+), 425 deletions(-) delete mode 100644 drivers/hwmon/hp_accel.c create mode 100644 drivers/platform/x86/hp_accel.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c48101cf58f4..3f8c895417de 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1302,25 +1302,6 @@ config SENSORS_ATK0110 This driver can also be built as a module. If so, the module will be called asus_atk0110. -config HP_ACCEL - tristate "HP laptop accelerometer" - depends on INPUT - select SENSORS_LIS3LV02D - select NEW_LEDS - select LEDS_CLASS - default n - help - This driver provides support for the "Mobile Data Protection System 3D" - or "3D DriveGuard" feature of HP laptops. On such systems the driver - should load automatically (via ACPI alias). - - Support for a led indicating disk protection will be provided as - hp::hddprotect. For more information on the feature, refer to - Documentation/hwmon/lis3lv02d. - - To compile this driver as a module, choose M here: the module will - be called hp_accel. - endif # ACPI endif # HWMON diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 94bf27482979..55ba906def74 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o # APCI drivers obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o -obj-$(CONFIG_HP_ACCEL) += hp_accel.o # Native drivers # asb100, then w83781d go first, as they can override other drivers' addresses. diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c deleted file mode 100644 index 3d21fa2b97cd..000000000000 --- a/drivers/hwmon/hp_accel.c +++ /dev/null @@ -1,405 +0,0 @@ -/* - * hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS - * - * Copyright (C) 2007-2008 Yan Burman - * Copyright (C) 2008 Eric Piel - * Copyright (C) 2008-2009 Pavel Machek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lis3lv02d.h" - -#define DRIVER_NAME "lis3lv02d" -#define ACPI_MDPS_CLASS "accelerometer" - -/* Delayed LEDs infrastructure ------------------------------------ */ - -/* Special LED class that can defer work */ -struct delayed_led_classdev { - struct led_classdev led_classdev; - struct work_struct work; - enum led_brightness new_brightness; - - unsigned int led; /* For driver */ - void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value); -}; - -static inline void delayed_set_status_worker(struct work_struct *work) -{ - struct delayed_led_classdev *data = - container_of(work, struct delayed_led_classdev, work); - - data->set_brightness(data, data->new_brightness); -} - -static inline void delayed_sysfs_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - struct delayed_led_classdev *data = container_of(led_cdev, - struct delayed_led_classdev, led_classdev); - data->new_brightness = brightness; - schedule_work(&data->work); -} - -/* HP-specific accelerometer driver ------------------------------------ */ - -/* For automatic insertion of the module */ -static struct acpi_device_id lis3lv02d_device_ids[] = { - {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); - - -/** - * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. - * @lis3: pointer to the device struct - * - * Returns 0 on success. - */ -int lis3lv02d_acpi_init(struct lis3lv02d *lis3) -{ - struct acpi_device *dev = lis3->bus_priv; - if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI, - NULL, NULL) != AE_OK) - return -EINVAL; - - return 0; -} - -/** - * lis3lv02d_acpi_read - ACPI ALRD method: read a register - * @lis3: pointer to the device struct - * @reg: the register to read - * @ret: result of the operation - * - * Returns 0 on success. - */ -int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret) -{ - struct acpi_device *dev = lis3->bus_priv; - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; - unsigned long long lret; - acpi_status status; - - arg0.integer.value = reg; - - status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret); - *ret = lret; - return (status != AE_OK) ? -EINVAL : 0; -} - -/** - * lis3lv02d_acpi_write - ACPI ALWR method: write to a register - * @lis3: pointer to the device struct - * @reg: the register to write to - * @val: the value to write - * - * Returns 0 on success. - */ -int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val) -{ - struct acpi_device *dev = lis3->bus_priv; - unsigned long long ret; /* Not used when writting */ - union acpi_object in_obj[2]; - struct acpi_object_list args = { 2, in_obj }; - - in_obj[0].type = ACPI_TYPE_INTEGER; - in_obj[0].integer.value = reg; - in_obj[1].type = ACPI_TYPE_INTEGER; - in_obj[1].integer.value = val; - - if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK) - return -EINVAL; - - return 0; -} - -static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) -{ - lis3_dev.ac = *((union axis_conversion *)dmi->driver_data); - pr_info("hardware type %s found\n", dmi->ident); - - return 1; -} - -/* Represents, for each axis seen by userspace, the corresponding hw axis (+1). - * If the value is negative, the opposite of the hw value is used. */ -#define DEFINE_CONV(name, x, y, z) \ - static union axis_conversion lis3lv02d_axis_##name = \ - { .as_array = { x, y, z } } -DEFINE_CONV(normal, 1, 2, 3); -DEFINE_CONV(y_inverted, 1, -2, 3); -DEFINE_CONV(x_inverted, -1, 2, 3); -DEFINE_CONV(z_inverted, 1, 2, -3); -DEFINE_CONV(xy_swap, 2, 1, 3); -DEFINE_CONV(xy_rotated_left, -2, 1, 3); -DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3); -DEFINE_CONV(xy_swap_inverted, -2, -1, 3); -DEFINE_CONV(xy_rotated_right, 2, -1, 3); -DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3); - -#define AXIS_DMI_MATCH(_ident, _name, _axis) { \ - .ident = _ident, \ - .callback = lis3lv02d_dmi_matched, \ - .matches = { \ - DMI_MATCH(DMI_PRODUCT_NAME, _name) \ - }, \ - .driver_data = &lis3lv02d_axis_##_axis \ -} - -#define AXIS_DMI_MATCH2(_ident, _class1, _name1, \ - _class2, _name2, \ - _axis) { \ - .ident = _ident, \ - .callback = lis3lv02d_dmi_matched, \ - .matches = { \ - DMI_MATCH(DMI_##_class1, _name1), \ - DMI_MATCH(DMI_##_class2, _name2), \ - }, \ - .driver_data = &lis3lv02d_axis_##_axis \ -} -static struct dmi_system_id lis3lv02d_dmi_ids[] = { - /* product names are truncated to match all kinds of a same model */ - AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), - AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted), - AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), - AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), - AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), - AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap), - AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), - AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), - AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted), - AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), - AXIS_DMI_MATCH("NC6730b", "HP Compaq 6730b", xy_rotated_left_usd), - AXIS_DMI_MATCH("NC6730s", "HP Compaq 6730s", xy_swap), - AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), - AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted), - AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted), - AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right), - AXIS_DMI_MATCH("NC693xx", "HP EliteBook 853", xy_swap), - /* Intel-based HP Pavilion dv5 */ - AXIS_DMI_MATCH2("HPDV5_I", - PRODUCT_NAME, "HP Pavilion dv5", - BOARD_NAME, "3603", - x_inverted), - /* AMD-based HP Pavilion dv5 */ - AXIS_DMI_MATCH2("HPDV5_A", - PRODUCT_NAME, "HP Pavilion dv5", - BOARD_NAME, "3600", - y_inverted), - AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted), - AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted), - AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted), - AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left), - AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), - AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), - AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), - AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted), - AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd), - { NULL, } -/* Laptop models without axis info (yet): - * "NC6910" "HP Compaq 6910" - * "NC2400" "HP Compaq nc2400" - * "NX74x0" "HP Compaq nx74" - * "NX6325" "HP Compaq nx6325" - * "NC4400" "HP Compaq nc4400" - */ -}; - -static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) -{ - struct acpi_device *dev = lis3_dev.bus_priv; - unsigned long long ret; /* Not used when writing */ - union acpi_object in_obj[1]; - struct acpi_object_list args = { 1, in_obj }; - - in_obj[0].type = ACPI_TYPE_INTEGER; - in_obj[0].integer.value = !!value; - - acpi_evaluate_integer(dev->handle, "ALED", &args, &ret); -} - -static struct delayed_led_classdev hpled_led = { - .led_classdev = { - .name = "hp::hddprotect", - .default_trigger = "none", - .brightness_set = delayed_sysfs_set, - .flags = LED_CORE_SUSPENDRESUME, - }, - .set_brightness = hpled_set, -}; - -static acpi_status -lis3lv02d_get_resource(struct acpi_resource *resource, void *context) -{ - if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { - struct acpi_resource_extended_irq *irq; - u32 *device_irq = context; - - irq = &resource->data.extended_irq; - *device_irq = irq->interrupts[0]; - } - - return AE_OK; -} - -static void lis3lv02d_enum_resources(struct acpi_device *device) -{ - acpi_status status; - - status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, - lis3lv02d_get_resource, &lis3_dev.irq); - if (ACPI_FAILURE(status)) - printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n"); -} - -static int lis3lv02d_add(struct acpi_device *device) -{ - int ret; - - if (!device) - return -EINVAL; - - lis3_dev.bus_priv = device; - lis3_dev.init = lis3lv02d_acpi_init; - lis3_dev.read = lis3lv02d_acpi_read; - lis3_dev.write = lis3lv02d_acpi_write; - strcpy(acpi_device_name(device), DRIVER_NAME); - strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); - device->driver_data = &lis3_dev; - - /* obtain IRQ number of our device from ACPI */ - lis3lv02d_enum_resources(device); - - /* If possible use a "standard" axes order */ - if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) { - pr_info("Using custom axes %d,%d,%d\n", - lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z); - } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { - pr_info("laptop model unknown, using default axes configuration\n"); - lis3_dev.ac = lis3lv02d_axis_normal; - } - - /* call the core layer do its init */ - ret = lis3lv02d_init_device(&lis3_dev); - if (ret) - return ret; - - INIT_WORK(&hpled_led.work, delayed_set_status_worker); - ret = led_classdev_register(NULL, &hpled_led.led_classdev); - if (ret) { - lis3lv02d_joystick_disable(); - lis3lv02d_poweroff(&lis3_dev); - flush_work(&hpled_led.work); - return ret; - } - - return ret; -} - -static int lis3lv02d_remove(struct acpi_device *device, int type) -{ - if (!device) - return -EINVAL; - - lis3lv02d_joystick_disable(); - lis3lv02d_poweroff(&lis3_dev); - - led_classdev_unregister(&hpled_led.led_classdev); - flush_work(&hpled_led.work); - - return lis3lv02d_remove_fs(&lis3_dev); -} - - -#ifdef CONFIG_PM -static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) -{ - /* make sure the device is off when we suspend */ - lis3lv02d_poweroff(&lis3_dev); - return 0; -} - -static int lis3lv02d_resume(struct acpi_device *device) -{ - lis3lv02d_poweron(&lis3_dev); - return 0; -} -#else -#define lis3lv02d_suspend NULL -#define lis3lv02d_resume NULL -#endif - -/* For the HP MDPS aka 3D Driveguard */ -static struct acpi_driver lis3lv02d_driver = { - .name = DRIVER_NAME, - .class = ACPI_MDPS_CLASS, - .ids = lis3lv02d_device_ids, - .ops = { - .add = lis3lv02d_add, - .remove = lis3lv02d_remove, - .suspend = lis3lv02d_suspend, - .resume = lis3lv02d_resume, - } -}; - -static int __init lis3lv02d_init_module(void) -{ - int ret; - - if (acpi_disabled) - return -ENODEV; - - ret = acpi_bus_register_driver(&lis3lv02d_driver); - if (ret < 0) - return ret; - - pr_info("driver loaded\n"); - - return 0; -} - -static void __exit lis3lv02d_exit_module(void) -{ - acpi_bus_unregister_driver(&lis3lv02d_driver); -} - -MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED."); -MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); -MODULE_LICENSE("GPL"); - -module_init(lis3lv02d_init_module); -module_exit(lis3lv02d_exit_module); - diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index a59af5b24f0a..222dfb737b11 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -138,6 +138,24 @@ config TC1100_WMI This is a driver for the WMI extensions (wireless and bluetooth power control) of the HP Compaq TC1100 tablet. +config HP_ACCEL + tristate "HP laptop accelerometer" + depends on INPUT && ACPI + select SENSORS_LIS3LV02D + select NEW_LEDS + select LEDS_CLASS + help + This driver provides support for the "Mobile Data Protection System 3D" + or "3D DriveGuard" feature of HP laptops. On such systems the driver + should load automatically (via ACPI alias). + + Support for a led indicating disk protection will be provided as + hp::hddprotect. For more information on the feature, refer to + Documentation/hwmon/lis3lv02d. + + To compile this driver as a module, choose M here: the module will + be called hp_accel. + config HP_WMI tristate "HP WMI extras" depends on ACPI_WMI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 4ec4ff8f9182..299aefb3e74c 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ACERHDF) += acerhdf.o +obj-$(CONFIG_HP_ACCEL) += hp_accel.o obj-$(CONFIG_HP_WMI) += hp-wmi.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c new file mode 100644 index 000000000000..23f09c1b234b --- /dev/null +++ b/drivers/platform/x86/hp_accel.c @@ -0,0 +1,404 @@ +/* + * hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS + * + * Copyright (C) 2007-2008 Yan Burman + * Copyright (C) 2008 Eric Piel + * Copyright (C) 2008-2009 Pavel Machek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../hwmon/lis3lv02d.h" + +#define DRIVER_NAME "lis3lv02d" +#define ACPI_MDPS_CLASS "accelerometer" + +/* Delayed LEDs infrastructure ------------------------------------ */ + +/* Special LED class that can defer work */ +struct delayed_led_classdev { + struct led_classdev led_classdev; + struct work_struct work; + enum led_brightness new_brightness; + + unsigned int led; /* For driver */ + void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value); +}; + +static inline void delayed_set_status_worker(struct work_struct *work) +{ + struct delayed_led_classdev *data = + container_of(work, struct delayed_led_classdev, work); + + data->set_brightness(data, data->new_brightness); +} + +static inline void delayed_sysfs_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct delayed_led_classdev *data = container_of(led_cdev, + struct delayed_led_classdev, led_classdev); + data->new_brightness = brightness; + schedule_work(&data->work); +} + +/* HP-specific accelerometer driver ------------------------------------ */ + +/* For automatic insertion of the module */ +static struct acpi_device_id lis3lv02d_device_ids[] = { + {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); + + +/** + * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. + * @lis3: pointer to the device struct + * + * Returns 0 on success. + */ +int lis3lv02d_acpi_init(struct lis3lv02d *lis3) +{ + struct acpi_device *dev = lis3->bus_priv; + if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI, + NULL, NULL) != AE_OK) + return -EINVAL; + + return 0; +} + +/** + * lis3lv02d_acpi_read - ACPI ALRD method: read a register + * @lis3: pointer to the device struct + * @reg: the register to read + * @ret: result of the operation + * + * Returns 0 on success. + */ +int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret) +{ + struct acpi_device *dev = lis3->bus_priv; + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + struct acpi_object_list args = { 1, &arg0 }; + unsigned long long lret; + acpi_status status; + + arg0.integer.value = reg; + + status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret); + *ret = lret; + return (status != AE_OK) ? -EINVAL : 0; +} + +/** + * lis3lv02d_acpi_write - ACPI ALWR method: write to a register + * @lis3: pointer to the device struct + * @reg: the register to write to + * @val: the value to write + * + * Returns 0 on success. + */ +int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val) +{ + struct acpi_device *dev = lis3->bus_priv; + unsigned long long ret; /* Not used when writting */ + union acpi_object in_obj[2]; + struct acpi_object_list args = { 2, in_obj }; + + in_obj[0].type = ACPI_TYPE_INTEGER; + in_obj[0].integer.value = reg; + in_obj[1].type = ACPI_TYPE_INTEGER; + in_obj[1].integer.value = val; + + if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK) + return -EINVAL; + + return 0; +} + +static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) +{ + lis3_dev.ac = *((union axis_conversion *)dmi->driver_data); + pr_info("hardware type %s found\n", dmi->ident); + + return 1; +} + +/* Represents, for each axis seen by userspace, the corresponding hw axis (+1). + * If the value is negative, the opposite of the hw value is used. */ +#define DEFINE_CONV(name, x, y, z) \ + static union axis_conversion lis3lv02d_axis_##name = \ + { .as_array = { x, y, z } } +DEFINE_CONV(normal, 1, 2, 3); +DEFINE_CONV(y_inverted, 1, -2, 3); +DEFINE_CONV(x_inverted, -1, 2, 3); +DEFINE_CONV(z_inverted, 1, 2, -3); +DEFINE_CONV(xy_swap, 2, 1, 3); +DEFINE_CONV(xy_rotated_left, -2, 1, 3); +DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3); +DEFINE_CONV(xy_swap_inverted, -2, -1, 3); +DEFINE_CONV(xy_rotated_right, 2, -1, 3); +DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3); + +#define AXIS_DMI_MATCH(_ident, _name, _axis) { \ + .ident = _ident, \ + .callback = lis3lv02d_dmi_matched, \ + .matches = { \ + DMI_MATCH(DMI_PRODUCT_NAME, _name) \ + }, \ + .driver_data = &lis3lv02d_axis_##_axis \ +} + +#define AXIS_DMI_MATCH2(_ident, _class1, _name1, \ + _class2, _name2, \ + _axis) { \ + .ident = _ident, \ + .callback = lis3lv02d_dmi_matched, \ + .matches = { \ + DMI_MATCH(DMI_##_class1, _name1), \ + DMI_MATCH(DMI_##_class2, _name2), \ + }, \ + .driver_data = &lis3lv02d_axis_##_axis \ +} +static struct dmi_system_id lis3lv02d_dmi_ids[] = { + /* product names are truncated to match all kinds of a same model */ + AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), + AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted), + AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), + AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), + AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), + AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap), + AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), + AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), + AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted), + AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), + AXIS_DMI_MATCH("NC6730b", "HP Compaq 6730b", xy_rotated_left_usd), + AXIS_DMI_MATCH("NC6730s", "HP Compaq 6730s", xy_swap), + AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), + AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted), + AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted), + AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right), + AXIS_DMI_MATCH("NC693xx", "HP EliteBook 853", xy_swap), + /* Intel-based HP Pavilion dv5 */ + AXIS_DMI_MATCH2("HPDV5_I", + PRODUCT_NAME, "HP Pavilion dv5", + BOARD_NAME, "3603", + x_inverted), + /* AMD-based HP Pavilion dv5 */ + AXIS_DMI_MATCH2("HPDV5_A", + PRODUCT_NAME, "HP Pavilion dv5", + BOARD_NAME, "3600", + y_inverted), + AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted), + AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted), + AXIS_DMI_MATCH("HDX18", "HP HDX 18", x_inverted), + AXIS_DMI_MATCH("HPB432x", "HP ProBook 432", xy_rotated_left), + AXIS_DMI_MATCH("HPB442x", "HP ProBook 442", xy_rotated_left), + AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted), + AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap), + AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted), + AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd), + { NULL, } +/* Laptop models without axis info (yet): + * "NC6910" "HP Compaq 6910" + * "NC2400" "HP Compaq nc2400" + * "NX74x0" "HP Compaq nx74" + * "NX6325" "HP Compaq nx6325" + * "NC4400" "HP Compaq nc4400" + */ +}; + +static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) +{ + struct acpi_device *dev = lis3_dev.bus_priv; + unsigned long long ret; /* Not used when writing */ + union acpi_object in_obj[1]; + struct acpi_object_list args = { 1, in_obj }; + + in_obj[0].type = ACPI_TYPE_INTEGER; + in_obj[0].integer.value = !!value; + + acpi_evaluate_integer(dev->handle, "ALED", &args, &ret); +} + +static struct delayed_led_classdev hpled_led = { + .led_classdev = { + .name = "hp::hddprotect", + .default_trigger = "none", + .brightness_set = delayed_sysfs_set, + .flags = LED_CORE_SUSPENDRESUME, + }, + .set_brightness = hpled_set, +}; + +static acpi_status +lis3lv02d_get_resource(struct acpi_resource *resource, void *context) +{ + if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { + struct acpi_resource_extended_irq *irq; + u32 *device_irq = context; + + irq = &resource->data.extended_irq; + *device_irq = irq->interrupts[0]; + } + + return AE_OK; +} + +static void lis3lv02d_enum_resources(struct acpi_device *device) +{ + acpi_status status; + + status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, + lis3lv02d_get_resource, &lis3_dev.irq); + if (ACPI_FAILURE(status)) + printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n"); +} + +static int lis3lv02d_add(struct acpi_device *device) +{ + int ret; + + if (!device) + return -EINVAL; + + lis3_dev.bus_priv = device; + lis3_dev.init = lis3lv02d_acpi_init; + lis3_dev.read = lis3lv02d_acpi_read; + lis3_dev.write = lis3lv02d_acpi_write; + strcpy(acpi_device_name(device), DRIVER_NAME); + strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); + device->driver_data = &lis3_dev; + + /* obtain IRQ number of our device from ACPI */ + lis3lv02d_enum_resources(device); + + /* If possible use a "standard" axes order */ + if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) { + pr_info("Using custom axes %d,%d,%d\n", + lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z); + } else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { + pr_info("laptop model unknown, using default axes configuration\n"); + lis3_dev.ac = lis3lv02d_axis_normal; + } + + /* call the core layer do its init */ + ret = lis3lv02d_init_device(&lis3_dev); + if (ret) + return ret; + + INIT_WORK(&hpled_led.work, delayed_set_status_worker); + ret = led_classdev_register(NULL, &hpled_led.led_classdev); + if (ret) { + lis3lv02d_joystick_disable(); + lis3lv02d_poweroff(&lis3_dev); + flush_work(&hpled_led.work); + return ret; + } + + return ret; +} + +static int lis3lv02d_remove(struct acpi_device *device, int type) +{ + if (!device) + return -EINVAL; + + lis3lv02d_joystick_disable(); + lis3lv02d_poweroff(&lis3_dev); + + led_classdev_unregister(&hpled_led.led_classdev); + flush_work(&hpled_led.work); + + return lis3lv02d_remove_fs(&lis3_dev); +} + + +#ifdef CONFIG_PM +static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) +{ + /* make sure the device is off when we suspend */ + lis3lv02d_poweroff(&lis3_dev); + return 0; +} + +static int lis3lv02d_resume(struct acpi_device *device) +{ + lis3lv02d_poweron(&lis3_dev); + return 0; +} +#else +#define lis3lv02d_suspend NULL +#define lis3lv02d_resume NULL +#endif + +/* For the HP MDPS aka 3D Driveguard */ +static struct acpi_driver lis3lv02d_driver = { + .name = DRIVER_NAME, + .class = ACPI_MDPS_CLASS, + .ids = lis3lv02d_device_ids, + .ops = { + .add = lis3lv02d_add, + .remove = lis3lv02d_remove, + .suspend = lis3lv02d_suspend, + .resume = lis3lv02d_resume, + } +}; + +static int __init lis3lv02d_init_module(void) +{ + int ret; + + if (acpi_disabled) + return -ENODEV; + + ret = acpi_bus_register_driver(&lis3lv02d_driver); + if (ret < 0) + return ret; + + pr_info("driver loaded\n"); + + return 0; +} + +static void __exit lis3lv02d_exit_module(void) +{ + acpi_bus_unregister_driver(&lis3lv02d_driver); +} + +MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED."); +MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); +MODULE_LICENSE("GPL"); + +module_init(lis3lv02d_init_module); +module_exit(lis3lv02d_exit_module); -- cgit v1.2.2 From ff606677f6a47c63329cf8e6c7cf978c29f2d736 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: Move lis3lv02d drivers to drivers/misc The lis3lv02d drivers aren't hardware monitoring drivers, so the don't belong to drivers/hwmon. Move them to drivers/misc, short of a better home. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck Acked-by: Eric Piel Acked-by: Jonathan Cameron Tested-by: Eric Piel Tested-by: Takashi Iwai --- drivers/hwmon/Kconfig | 40 -- drivers/hwmon/Makefile | 5 - drivers/hwmon/lis3lv02d.c | 1000 -------------------------------- drivers/hwmon/lis3lv02d.h | 291 ---------- drivers/hwmon/lis3lv02d_i2c.c | 279 --------- drivers/hwmon/lis3lv02d_spi.c | 145 ----- drivers/misc/Kconfig | 9 + drivers/misc/Makefile | 1 + drivers/misc/lis3lv02d/Kconfig | 37 ++ drivers/misc/lis3lv02d/Makefile | 7 + drivers/misc/lis3lv02d/lis3lv02d.c | 999 +++++++++++++++++++++++++++++++ drivers/misc/lis3lv02d/lis3lv02d.h | 291 ++++++++++ drivers/misc/lis3lv02d/lis3lv02d_i2c.c | 279 +++++++++ drivers/misc/lis3lv02d/lis3lv02d_spi.c | 145 +++++ drivers/platform/x86/hp_accel.c | 2 +- 15 files changed, 1769 insertions(+), 1761 deletions(-) delete mode 100644 drivers/hwmon/lis3lv02d.c delete mode 100644 drivers/hwmon/lis3lv02d.h delete mode 100644 drivers/hwmon/lis3lv02d_i2c.c delete mode 100644 drivers/hwmon/lis3lv02d_spi.c create mode 100644 drivers/misc/lis3lv02d/Kconfig create mode 100644 drivers/misc/lis3lv02d/Makefile create mode 100644 drivers/misc/lis3lv02d/lis3lv02d.c create mode 100644 drivers/misc/lis3lv02d/lis3lv02d.h create mode 100644 drivers/misc/lis3lv02d/lis3lv02d_i2c.c create mode 100644 drivers/misc/lis3lv02d/lis3lv02d_spi.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 3f8c895417de..47621abb9a05 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -2,12 +2,6 @@ # Hardware monitoring chip drivers configuration # -config SENSORS_LIS3LV02D - tristate - depends on INPUT - select INPUT_POLLDEV - default n - menuconfig HWMON tristate "Hardware Monitoring support" depends on HAS_IOMEM @@ -1221,40 +1215,6 @@ config SENSORS_ULTRA45 This driver provides support for the Ultra45 workstation environmental sensors. -config SENSORS_LIS3_SPI - tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" - depends on !ACPI && SPI_MASTER && INPUT - select SENSORS_LIS3LV02D - default n - help - This driver provides support for the LIS3LV02Dx accelerometer connected - via SPI. The accelerometer data is readable via - /sys/devices/platform/lis3lv02d. - - This driver also provides an absolute input class device, allowing - the laptop to act as a pinball machine-esque joystick. - - This driver can also be built as modules. If so, the core module - will be called lis3lv02d and a specific module for the SPI transport - is called lis3lv02d_spi. - -config SENSORS_LIS3_I2C - tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)" - depends on I2C && INPUT - select SENSORS_LIS3LV02D - default n - help - This driver provides support for the LIS3LV02Dx accelerometer connected - via I2C. The accelerometer data is readable via - /sys/devices/platform/lis3lv02d. - - This driver also provides an absolute input class device, allowing - the device to act as a pinball machine-esque joystick. - - This driver can also be built as modules. If so, the core module - will be called lis3lv02d and a specific module for the I2C transport - is called lis3lv02d_i2c. - config SENSORS_APPLESMC tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" depends on INPUT && X86 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 55ba906def74..c068f82082cd 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -5,9 +5,6 @@ obj-$(CONFIG_HWMON) += hwmon.o obj-$(CONFIG_HWMON_VID) += hwmon-vid.o -# Helper drivers -obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o - # APCI drivers obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o @@ -66,8 +63,6 @@ obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o -obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d_spi.o -obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d_i2c.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM70) += lm70.o obj-$(CONFIG_SENSORS_LM73) += lm73.o diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c deleted file mode 100644 index d805e8e57967..000000000000 --- a/drivers/hwmon/lis3lv02d.c +++ /dev/null @@ -1,1000 +0,0 @@ -/* - * lis3lv02d.c - ST LIS3LV02DL accelerometer driver - * - * Copyright (C) 2007-2008 Yan Burman - * Copyright (C) 2008 Eric Piel - * Copyright (C) 2008-2009 Pavel Machek - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "lis3lv02d.h" - -#define DRIVER_NAME "lis3lv02d" - -/* joystick device poll interval in milliseconds */ -#define MDPS_POLL_INTERVAL 50 -#define MDPS_POLL_MIN 0 -#define MDPS_POLL_MAX 2000 - -#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */ - -#define SELFTEST_OK 0 -#define SELFTEST_FAIL -1 -#define SELFTEST_IRQ -2 - -#define IRQ_LINE0 0 -#define IRQ_LINE1 1 - -/* - * The sensor can also generate interrupts (DRDY) but it's pretty pointless - * because they are generated even if the data do not change. So it's better - * to keep the interrupt for the free-fall event. The values are updated at - * 40Hz (at the lowest frequency), but as it can be pretty time consuming on - * some low processor, we poll the sensor only at 20Hz... enough for the - * joystick. - */ - -#define LIS3_PWRON_DELAY_WAI_12B (5000) -#define LIS3_PWRON_DELAY_WAI_8B (3000) - -/* - * LIS3LV02D spec says 1024 LSBs corresponds 1 G -> 1LSB is 1000/1024 mG - * LIS302D spec says: 18 mG / digit - * LIS3_ACCURACY is used to increase accuracy of the intermediate - * calculation results. - */ -#define LIS3_ACCURACY 1024 -/* Sensitivity values for -2G +2G scale */ -#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024) -#define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY) - -#define LIS3_DEFAULT_FUZZ_12B 3 -#define LIS3_DEFAULT_FLAT_12B 3 -#define LIS3_DEFAULT_FUZZ_8B 1 -#define LIS3_DEFAULT_FLAT_8B 1 - -struct lis3lv02d lis3_dev = { - .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait), -}; - -EXPORT_SYMBOL_GPL(lis3_dev); - -/* just like param_set_int() but does sanity-check so that it won't point - * over the axis array size - */ -static int param_set_axis(const char *val, const struct kernel_param *kp) -{ - int ret = param_set_int(val, kp); - if (!ret) { - int val = *(int *)kp->arg; - if (val < 0) - val = -val; - if (!val || val > 3) - return -EINVAL; - } - return ret; -} - -static struct kernel_param_ops param_ops_axis = { - .set = param_set_axis, - .get = param_get_int, -}; - -module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644); -MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions"); - -static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg) -{ - s8 lo; - if (lis3->read(lis3, reg, &lo) < 0) - return 0; - - return lo; -} - -static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg) -{ - u8 lo, hi; - - lis3->read(lis3, reg - 1, &lo); - lis3->read(lis3, reg, &hi); - /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ - return (s16)((hi << 8) | lo); -} - -/** - * lis3lv02d_get_axis - For the given axis, give the value converted - * @axis: 1,2,3 - can also be negative - * @hw_values: raw values returned by the hardware - * - * Returns the converted value. - */ -static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3]) -{ - if (axis > 0) - return hw_values[axis - 1]; - else - return -hw_values[-axis - 1]; -} - -/** - * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer - * @lis3: pointer to the device struct - * @x: where to store the X axis value - * @y: where to store the Y axis value - * @z: where to store the Z axis value - * - * Note that 40Hz input device can eat up about 10% CPU at 800MHZ - */ -static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) -{ - int position[3]; - int i; - - if (lis3->blkread) { - if (lis3_dev.whoami == WAI_12B) { - u16 data[3]; - lis3->blkread(lis3, OUTX_L, 6, (u8 *)data); - for (i = 0; i < 3; i++) - position[i] = (s16)le16_to_cpu(data[i]); - } else { - u8 data[5]; - /* Data: x, dummy, y, dummy, z */ - lis3->blkread(lis3, OUTX, 5, data); - for (i = 0; i < 3; i++) - position[i] = (s8)data[i * 2]; - } - } else { - position[0] = lis3->read_data(lis3, OUTX); - position[1] = lis3->read_data(lis3, OUTY); - position[2] = lis3->read_data(lis3, OUTZ); - } - - for (i = 0; i < 3; i++) - position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; - - *x = lis3lv02d_get_axis(lis3->ac.x, position); - *y = lis3lv02d_get_axis(lis3->ac.y, position); - *z = lis3lv02d_get_axis(lis3->ac.z, position); -} - -/* conversion btw sampling rate and the register values */ -static int lis3_12_rates[4] = {40, 160, 640, 2560}; -static int lis3_8_rates[2] = {100, 400}; -static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; - -/* ODR is Output Data Rate */ -static int lis3lv02d_get_odr(void) -{ - u8 ctrl; - int shift; - - lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); - ctrl &= lis3_dev.odr_mask; - shift = ffs(lis3_dev.odr_mask) - 1; - return lis3_dev.odrs[(ctrl >> shift)]; -} - -static int lis3lv02d_set_odr(int rate) -{ - u8 ctrl; - int i, len, shift; - - if (!rate) - return -EINVAL; - - lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); - ctrl &= ~lis3_dev.odr_mask; - len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */ - shift = ffs(lis3_dev.odr_mask) - 1; - - for (i = 0; i < len; i++) - if (lis3_dev.odrs[i] == rate) { - lis3_dev.write(&lis3_dev, CTRL_REG1, - ctrl | (i << shift)); - return 0; - } - return -EINVAL; -} - -static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) -{ - u8 ctlreg, reg; - s16 x, y, z; - u8 selftest; - int ret; - u8 ctrl_reg_data; - unsigned char irq_cfg; - - mutex_lock(&lis3->mutex); - - irq_cfg = lis3->irq_cfg; - if (lis3_dev.whoami == WAI_8B) { - lis3->data_ready_count[IRQ_LINE0] = 0; - lis3->data_ready_count[IRQ_LINE1] = 0; - - /* Change interrupt cfg to data ready for selftest */ - atomic_inc(&lis3_dev.wake_thread); - lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY; - lis3->read(lis3, CTRL_REG3, &ctrl_reg_data); - lis3->write(lis3, CTRL_REG3, (ctrl_reg_data & - ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) | - (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY)); - } - - if (lis3_dev.whoami == WAI_3DC) { - ctlreg = CTRL_REG4; - selftest = CTRL4_ST0; - } else { - ctlreg = CTRL_REG1; - if (lis3_dev.whoami == WAI_12B) - selftest = CTRL1_ST; - else - selftest = CTRL1_STP; - } - - lis3->read(lis3, ctlreg, ®); - lis3->write(lis3, ctlreg, (reg | selftest)); - msleep(lis3->pwron_delay / lis3lv02d_get_odr()); - - /* Read directly to avoid axis remap */ - x = lis3->read_data(lis3, OUTX); - y = lis3->read_data(lis3, OUTY); - z = lis3->read_data(lis3, OUTZ); - - /* back to normal settings */ - lis3->write(lis3, ctlreg, reg); - msleep(lis3->pwron_delay / lis3lv02d_get_odr()); - - results[0] = x - lis3->read_data(lis3, OUTX); - results[1] = y - lis3->read_data(lis3, OUTY); - results[2] = z - lis3->read_data(lis3, OUTZ); - - ret = 0; - - if (lis3_dev.whoami == WAI_8B) { - /* Restore original interrupt configuration */ - atomic_dec(&lis3_dev.wake_thread); - lis3->write(lis3, CTRL_REG3, ctrl_reg_data); - lis3->irq_cfg = irq_cfg; - - if ((irq_cfg & LIS3_IRQ1_MASK) && - lis3->data_ready_count[IRQ_LINE0] < 2) { - ret = SELFTEST_IRQ; - goto fail; - } - - if ((irq_cfg & LIS3_IRQ2_MASK) && - lis3->data_ready_count[IRQ_LINE1] < 2) { - ret = SELFTEST_IRQ; - goto fail; - } - } - - if (lis3->pdata) { - int i; - for (i = 0; i < 3; i++) { - /* Check against selftest acceptance limits */ - if ((results[i] < lis3->pdata->st_min_limits[i]) || - (results[i] > lis3->pdata->st_max_limits[i])) { - ret = SELFTEST_FAIL; - goto fail; - } - } - } - - /* test passed */ -fail: - mutex_unlock(&lis3->mutex); - return ret; -} - -/* - * Order of registers in the list affects to order of the restore process. - * Perhaps it is a good idea to set interrupt enable register as a last one - * after all other configurations - */ -static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1, - FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2, - CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ, - CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW, - CTRL_REG1, CTRL_REG2, CTRL_REG3}; - -static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H, - FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H, - DD_THSE_L, DD_THSE_H, - CTRL_REG1, CTRL_REG3, CTRL_REG2}; - -static inline void lis3_context_save(struct lis3lv02d *lis3) -{ - int i; - for (i = 0; i < lis3->regs_size; i++) - lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]); - lis3->regs_stored = true; -} - -static inline void lis3_context_restore(struct lis3lv02d *lis3) -{ - int i; - if (lis3->regs_stored) - for (i = 0; i < lis3->regs_size; i++) - lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]); -} - -void lis3lv02d_poweroff(struct lis3lv02d *lis3) -{ - if (lis3->reg_ctrl) - lis3_context_save(lis3); - /* disable X,Y,Z axis and power down */ - lis3->write(lis3, CTRL_REG1, 0x00); - if (lis3->reg_ctrl) - lis3->reg_ctrl(lis3, LIS3_REG_OFF); -} -EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); - -void lis3lv02d_poweron(struct lis3lv02d *lis3) -{ - u8 reg; - - lis3->init(lis3); - - /* - * Common configuration - * BDU: (12 bits sensors only) LSB and MSB values are not updated until - * both have been read. So the value read will always be correct. - * Set BOOT bit to refresh factory tuning values. - */ - lis3->read(lis3, CTRL_REG2, ®); - if (lis3->whoami == WAI_12B) - reg |= CTRL2_BDU | CTRL2_BOOT; - else - reg |= CTRL2_BOOT_8B; - lis3->write(lis3, CTRL_REG2, reg); - - /* LIS3 power on delay is quite long */ - msleep(lis3->pwron_delay / lis3lv02d_get_odr()); - - if (lis3->reg_ctrl) - lis3_context_restore(lis3); -} -EXPORT_SYMBOL_GPL(lis3lv02d_poweron); - - -static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) -{ - int x, y, z; - - mutex_lock(&lis3_dev.mutex); - lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); - input_report_abs(pidev->input, ABS_X, x); - input_report_abs(pidev->input, ABS_Y, y); - input_report_abs(pidev->input, ABS_Z, z); - input_sync(pidev->input); - mutex_unlock(&lis3_dev.mutex); -} - -static void lis3lv02d_joystick_open(struct input_polled_dev *pidev) -{ - if (lis3_dev.pm_dev) - pm_runtime_get_sync(lis3_dev.pm_dev); - - if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev) - atomic_set(&lis3_dev.wake_thread, 1); - /* - * Update coordinates for the case where poll interval is 0 and - * the chip in running purely under interrupt control - */ - lis3lv02d_joystick_poll(pidev); -} - -static void lis3lv02d_joystick_close(struct input_polled_dev *pidev) -{ - atomic_set(&lis3_dev.wake_thread, 0); - if (lis3_dev.pm_dev) - pm_runtime_put(lis3_dev.pm_dev); -} - -static irqreturn_t lis302dl_interrupt(int irq, void *dummy) -{ - if (!test_bit(0, &lis3_dev.misc_opened)) - goto out; - - /* - * Be careful: on some HP laptops the bios force DD when on battery and - * the lid is closed. This leads to interrupts as soon as a little move - * is done. - */ - atomic_inc(&lis3_dev.count); - - wake_up_interruptible(&lis3_dev.misc_wait); - kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); -out: - if (atomic_read(&lis3_dev.wake_thread)) - return IRQ_WAKE_THREAD; - return IRQ_HANDLED; -} - -static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) -{ - struct input_dev *dev = lis3->idev->input; - u8 click_src; - - mutex_lock(&lis3->mutex); - lis3->read(lis3, CLICK_SRC, &click_src); - - if (click_src & CLICK_SINGLE_X) { - input_report_key(dev, lis3->mapped_btns[0], 1); - input_report_key(dev, lis3->mapped_btns[0], 0); - } - - if (click_src & CLICK_SINGLE_Y) { - input_report_key(dev, lis3->mapped_btns[1], 1); - input_report_key(dev, lis3->mapped_btns[1], 0); - } - - if (click_src & CLICK_SINGLE_Z) { - input_report_key(dev, lis3->mapped_btns[2], 1); - input_report_key(dev, lis3->mapped_btns[2], 0); - } - input_sync(dev); - mutex_unlock(&lis3->mutex); -} - -static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index) -{ - int dummy; - - /* Dummy read to ack interrupt */ - lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy); - lis3->data_ready_count[index]++; -} - -static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) -{ - struct lis3lv02d *lis3 = data; - u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK; - - if (irq_cfg == LIS3_IRQ1_CLICK) - lis302dl_interrupt_handle_click(lis3); - else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY)) - lis302dl_data_ready(lis3, IRQ_LINE0); - else - lis3lv02d_joystick_poll(lis3->idev); - - return IRQ_HANDLED; -} - -static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) -{ - struct lis3lv02d *lis3 = data; - u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK; - - if (irq_cfg == LIS3_IRQ2_CLICK) - lis302dl_interrupt_handle_click(lis3); - else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY)) - lis302dl_data_ready(lis3, IRQ_LINE1); - else - lis3lv02d_joystick_poll(lis3->idev); - - return IRQ_HANDLED; -} - -static int lis3lv02d_misc_open(struct inode *inode, struct file *file) -{ - if (test_and_set_bit(0, &lis3_dev.misc_opened)) - return -EBUSY; /* already open */ - - if (lis3_dev.pm_dev) - pm_runtime_get_sync(lis3_dev.pm_dev); - - atomic_set(&lis3_dev.count, 0); - return 0; -} - -static int lis3lv02d_misc_release(struct inode *inode, struct file *file) -{ - fasync_helper(-1, file, 0, &lis3_dev.async_queue); - clear_bit(0, &lis3_dev.misc_opened); /* release the device */ - if (lis3_dev.pm_dev) - pm_runtime_put(lis3_dev.pm_dev); - return 0; -} - -static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, - size_t count, loff_t *pos) -{ - DECLARE_WAITQUEUE(wait, current); - u32 data; - unsigned char byte_data; - ssize_t retval = 1; - - if (count < 1) - return -EINVAL; - - add_wait_queue(&lis3_dev.misc_wait, &wait); - while (true) { - set_current_state(TASK_INTERRUPTIBLE); - data = atomic_xchg(&lis3_dev.count, 0); - if (data) - break; - - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - goto out; - } - - schedule(); - } - - if (data < 255) - byte_data = data; - else - byte_data = 255; - - /* make sure we are not going into copy_to_user() with - * TASK_INTERRUPTIBLE state */ - set_current_state(TASK_RUNNING); - if (copy_to_user(buf, &byte_data, sizeof(byte_data))) - retval = -EFAULT; - -out: - __set_current_state(TASK_RUNNING); - remove_wait_queue(&lis3_dev.misc_wait, &wait); - - return retval; -} - -static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &lis3_dev.misc_wait, wait); - if (atomic_read(&lis3_dev.count)) - return POLLIN | POLLRDNORM; - return 0; -} - -static int lis3lv02d_misc_fasync(int fd, struct file *file, int on) -{ - return fasync_helper(fd, file, on, &lis3_dev.async_queue); -} - -static const struct file_operations lis3lv02d_misc_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = lis3lv02d_misc_read, - .open = lis3lv02d_misc_open, - .release = lis3lv02d_misc_release, - .poll = lis3lv02d_misc_poll, - .fasync = lis3lv02d_misc_fasync, -}; - -static struct miscdevice lis3lv02d_misc_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "freefall", - .fops = &lis3lv02d_misc_fops, -}; - -int lis3lv02d_joystick_enable(void) -{ - struct input_dev *input_dev; - int err; - int max_val, fuzz, flat; - int btns[] = {BTN_X, BTN_Y, BTN_Z}; - - if (lis3_dev.idev) - return -EINVAL; - - lis3_dev.idev = input_allocate_polled_device(); - if (!lis3_dev.idev) - return -ENOMEM; - - lis3_dev.idev->poll = lis3lv02d_joystick_poll; - lis3_dev.idev->open = lis3lv02d_joystick_open; - lis3_dev.idev->close = lis3lv02d_joystick_close; - lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; - lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN; - lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX; - input_dev = lis3_dev.idev->input; - - input_dev->name = "ST LIS3LV02DL Accelerometer"; - input_dev->phys = DRIVER_NAME "/input0"; - input_dev->id.bustype = BUS_HOST; - input_dev->id.vendor = 0; - input_dev->dev.parent = &lis3_dev.pdev->dev; - - set_bit(EV_ABS, input_dev->evbit); - max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY; - if (lis3_dev.whoami == WAI_12B) { - fuzz = LIS3_DEFAULT_FUZZ_12B; - flat = LIS3_DEFAULT_FLAT_12B; - } else { - fuzz = LIS3_DEFAULT_FUZZ_8B; - flat = LIS3_DEFAULT_FLAT_8B; - } - fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY; - flat = (flat * lis3_dev.scale) / LIS3_ACCURACY; - - input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat); - input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); - input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); - - lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns); - lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns); - lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns); - - err = input_register_polled_device(lis3_dev.idev); - if (err) { - input_free_polled_device(lis3_dev.idev); - lis3_dev.idev = NULL; - } - - return err; -} -EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); - -void lis3lv02d_joystick_disable(void) -{ - if (lis3_dev.irq) - free_irq(lis3_dev.irq, &lis3_dev); - if (lis3_dev.pdata && lis3_dev.pdata->irq2) - free_irq(lis3_dev.pdata->irq2, &lis3_dev); - - if (!lis3_dev.idev) - return; - - if (lis3_dev.irq) - misc_deregister(&lis3lv02d_misc_device); - input_unregister_polled_device(lis3_dev.idev); - input_free_polled_device(lis3_dev.idev); - lis3_dev.idev = NULL; -} -EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); - -/* Sysfs stuff */ -static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) -{ - /* - * SYSFS functions are fast visitors so put-call - * immediately after the get-call. However, keep - * chip running for a while and schedule delayed - * suspend. This way periodic sysfs calls doesn't - * suffer from relatively long power up time. - */ - - if (lis3->pm_dev) { - pm_runtime_get_sync(lis3->pm_dev); - pm_runtime_put_noidle(lis3->pm_dev); - pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY); - } -} - -static ssize_t lis3lv02d_selftest_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - s16 values[3]; - - static const char ok[] = "OK"; - static const char fail[] = "FAIL"; - static const char irq[] = "FAIL_IRQ"; - const char *res; - - lis3lv02d_sysfs_poweron(&lis3_dev); - switch (lis3lv02d_selftest(&lis3_dev, values)) { - case SELFTEST_FAIL: - res = fail; - break; - case SELFTEST_IRQ: - res = irq; - break; - case SELFTEST_OK: - default: - res = ok; - break; - } - return sprintf(buf, "%s %d %d %d\n", res, - values[0], values[1], values[2]); -} - -static ssize_t lis3lv02d_position_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int x, y, z; - - lis3lv02d_sysfs_poweron(&lis3_dev); - mutex_lock(&lis3_dev.mutex); - lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); - mutex_unlock(&lis3_dev.mutex); - return sprintf(buf, "(%d,%d,%d)\n", x, y, z); -} - -static ssize_t lis3lv02d_rate_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - lis3lv02d_sysfs_poweron(&lis3_dev); - return sprintf(buf, "%d\n", lis3lv02d_get_odr()); -} - -static ssize_t lis3lv02d_rate_set(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - unsigned long rate; - - if (strict_strtoul(buf, 0, &rate)) - return -EINVAL; - - lis3lv02d_sysfs_poweron(&lis3_dev); - if (lis3lv02d_set_odr(rate)) - return -EINVAL; - - return count; -} - -static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL); -static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); -static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show, - lis3lv02d_rate_set); - -static struct attribute *lis3lv02d_attributes[] = { - &dev_attr_selftest.attr, - &dev_attr_position.attr, - &dev_attr_rate.attr, - NULL -}; - -static struct attribute_group lis3lv02d_attribute_group = { - .attrs = lis3lv02d_attributes -}; - - -static int lis3lv02d_add_fs(struct lis3lv02d *lis3) -{ - lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); - if (IS_ERR(lis3->pdev)) - return PTR_ERR(lis3->pdev); - - return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); -} - -int lis3lv02d_remove_fs(struct lis3lv02d *lis3) -{ - sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); - platform_device_unregister(lis3->pdev); - if (lis3->pm_dev) { - /* Barrier after the sysfs remove */ - pm_runtime_barrier(lis3->pm_dev); - - /* SYSFS may have left chip running. Turn off if necessary */ - if (!pm_runtime_suspended(lis3->pm_dev)) - lis3lv02d_poweroff(&lis3_dev); - - pm_runtime_disable(lis3->pm_dev); - pm_runtime_set_suspended(lis3->pm_dev); - } - kfree(lis3->reg_cache); - return 0; -} -EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); - -static void lis3lv02d_8b_configure(struct lis3lv02d *dev, - struct lis3lv02d_platform_data *p) -{ - int err; - int ctrl2 = p->hipass_ctrl; - - if (p->click_flags) { - dev->write(dev, CLICK_CFG, p->click_flags); - dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); - dev->write(dev, CLICK_LATENCY, p->click_latency); - dev->write(dev, CLICK_WINDOW, p->click_window); - dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); - dev->write(dev, CLICK_THSY_X, - (p->click_thresh_x & 0xf) | - (p->click_thresh_y << 4)); - - if (dev->idev) { - struct input_dev *input_dev = lis3_dev.idev->input; - input_set_capability(input_dev, EV_KEY, BTN_X); - input_set_capability(input_dev, EV_KEY, BTN_Y); - input_set_capability(input_dev, EV_KEY, BTN_Z); - } - } - - if (p->wakeup_flags) { - dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); - dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); - /* pdata value + 1 to keep this backward compatible*/ - dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1); - ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/ - } - - if (p->wakeup_flags2) { - dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2); - dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f); - /* pdata value + 1 to keep this backward compatible*/ - dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1); - ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/ - } - /* Configure hipass filters */ - dev->write(dev, CTRL_REG2, ctrl2); - - if (p->irq2) { - err = request_threaded_irq(p->irq2, - NULL, - lis302dl_interrupt_thread2_8b, - IRQF_TRIGGER_RISING | IRQF_ONESHOT | - (p->irq_flags2 & IRQF_TRIGGER_MASK), - DRIVER_NAME, &lis3_dev); - if (err < 0) - pr_err("No second IRQ. Limited functionality\n"); - } -} - -/* - * Initialise the accelerometer and the various subsystems. - * Should be rather independent of the bus system. - */ -int lis3lv02d_init_device(struct lis3lv02d *dev) -{ - int err; - irq_handler_t thread_fn; - int irq_flags = 0; - - dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); - - switch (dev->whoami) { - case WAI_12B: - pr_info("12 bits sensor found\n"); - dev->read_data = lis3lv02d_read_12; - dev->mdps_max_val = 2048; - dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B; - dev->odrs = lis3_12_rates; - dev->odr_mask = CTRL1_DF0 | CTRL1_DF1; - dev->scale = LIS3_SENSITIVITY_12B; - dev->regs = lis3_wai12_regs; - dev->regs_size = ARRAY_SIZE(lis3_wai12_regs); - break; - case WAI_8B: - pr_info("8 bits sensor found\n"); - dev->read_data = lis3lv02d_read_8; - dev->mdps_max_val = 128; - dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; - dev->odrs = lis3_8_rates; - dev->odr_mask = CTRL1_DR; - dev->scale = LIS3_SENSITIVITY_8B; - dev->regs = lis3_wai8_regs; - dev->regs_size = ARRAY_SIZE(lis3_wai8_regs); - break; - case WAI_3DC: - pr_info("8 bits 3DC sensor found\n"); - dev->read_data = lis3lv02d_read_8; - dev->mdps_max_val = 128; - dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; - dev->odrs = lis3_3dc_rates; - dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3; - dev->scale = LIS3_SENSITIVITY_8B; - break; - default: - pr_err("unknown sensor type 0x%X\n", dev->whoami); - return -EINVAL; - } - - dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), - sizeof(lis3_wai12_regs)), GFP_KERNEL); - - if (dev->reg_cache == NULL) { - printk(KERN_ERR DRIVER_NAME "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->mutex); - atomic_set(&dev->wake_thread, 0); - - lis3lv02d_add_fs(dev); - lis3lv02d_poweron(dev); - - if (dev->pm_dev) { - pm_runtime_set_active(dev->pm_dev); - pm_runtime_enable(dev->pm_dev); - } - - if (lis3lv02d_joystick_enable()) - pr_err("joystick initialization failed\n"); - - /* passing in platform specific data is purely optional and only - * used by the SPI transport layer at the moment */ - if (dev->pdata) { - struct lis3lv02d_platform_data *p = dev->pdata; - - if (dev->whoami == WAI_8B) - lis3lv02d_8b_configure(dev, p); - - irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK; - - dev->irq_cfg = p->irq_cfg; - if (p->irq_cfg) - dev->write(dev, CTRL_REG3, p->irq_cfg); - - if (p->default_rate) - lis3lv02d_set_odr(p->default_rate); - } - - /* bail if we did not get an IRQ from the bus layer */ - if (!dev->irq) { - pr_debug("No IRQ. Disabling /dev/freefall\n"); - goto out; - } - - /* - * The sensor can generate interrupts for free-fall and direction - * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep - * the things simple and _fast_ we activate it only for free-fall, so - * no need to read register (very slow with ACPI). For the same reason, - * we forbid shared interrupts. - * - * IRQF_TRIGGER_RISING seems pointless on HP laptops because the - * io-apic is not configurable (and generates a warning) but I keep it - * in case of support for other hardware. - */ - if (dev->pdata && dev->whoami == WAI_8B) - thread_fn = lis302dl_interrupt_thread1_8b; - else - thread_fn = NULL; - - err = request_threaded_irq(dev->irq, lis302dl_interrupt, - thread_fn, - IRQF_TRIGGER_RISING | IRQF_ONESHOT | - irq_flags, - DRIVER_NAME, &lis3_dev); - - if (err < 0) { - pr_err("Cannot get IRQ\n"); - goto out; - } - - if (misc_register(&lis3lv02d_misc_device)) - pr_err("misc_register failed\n"); -out: - return 0; -} -EXPORT_SYMBOL_GPL(lis3lv02d_init_device); - -MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); -MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); -MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h deleted file mode 100644 index a1939589eb2c..000000000000 --- a/drivers/hwmon/lis3lv02d.h +++ /dev/null @@ -1,291 +0,0 @@ -/* - * lis3lv02d.h - ST LIS3LV02DL accelerometer driver - * - * Copyright (C) 2007-2008 Yan Burman - * Copyright (C) 2008-2009 Eric Piel - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include - -/* - * This driver tries to support the "digital" accelerometer chips from - * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL, - * LIS35DE, or LIS202DL. They are very similar in terms of programming, with - * almost the same registers. In addition to differing on physical properties, - * they differ on the number of axes (2/3), precision (8/12 bits), and special - * features (freefall detection, click...). Unfortunately, not all the - * differences can be probed via a register. - * They can be connected either via I²C or SPI. - */ - -#include - -enum lis3_reg { - WHO_AM_I = 0x0F, - OFFSET_X = 0x16, - OFFSET_Y = 0x17, - OFFSET_Z = 0x18, - GAIN_X = 0x19, - GAIN_Y = 0x1A, - GAIN_Z = 0x1B, - CTRL_REG1 = 0x20, - CTRL_REG2 = 0x21, - CTRL_REG3 = 0x22, - CTRL_REG4 = 0x23, - HP_FILTER_RESET = 0x23, - STATUS_REG = 0x27, - OUTX_L = 0x28, - OUTX_H = 0x29, - OUTX = 0x29, - OUTY_L = 0x2A, - OUTY_H = 0x2B, - OUTY = 0x2B, - OUTZ_L = 0x2C, - OUTZ_H = 0x2D, - OUTZ = 0x2D, -}; - -enum lis302d_reg { - FF_WU_CFG_1 = 0x30, - FF_WU_SRC_1 = 0x31, - FF_WU_THS_1 = 0x32, - FF_WU_DURATION_1 = 0x33, - FF_WU_CFG_2 = 0x34, - FF_WU_SRC_2 = 0x35, - FF_WU_THS_2 = 0x36, - FF_WU_DURATION_2 = 0x37, - CLICK_CFG = 0x38, - CLICK_SRC = 0x39, - CLICK_THSY_X = 0x3B, - CLICK_THSZ = 0x3C, - CLICK_TIMELIMIT = 0x3D, - CLICK_LATENCY = 0x3E, - CLICK_WINDOW = 0x3F, -}; - -enum lis3lv02d_reg { - FF_WU_CFG = 0x30, - FF_WU_SRC = 0x31, - FF_WU_ACK = 0x32, - FF_WU_THS_L = 0x34, - FF_WU_THS_H = 0x35, - FF_WU_DURATION = 0x36, - DD_CFG = 0x38, - DD_SRC = 0x39, - DD_ACK = 0x3A, - DD_THSI_L = 0x3C, - DD_THSI_H = 0x3D, - DD_THSE_L = 0x3E, - DD_THSE_H = 0x3F, -}; - -enum lis3_who_am_i { - WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */ - WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */ - WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */ - WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ -}; - -enum lis3lv02d_ctrl1_12b { - CTRL1_Xen = 0x01, - CTRL1_Yen = 0x02, - CTRL1_Zen = 0x04, - CTRL1_ST = 0x08, - CTRL1_DF0 = 0x10, - CTRL1_DF1 = 0x20, - CTRL1_PD0 = 0x40, - CTRL1_PD1 = 0x80, -}; - -/* Delta to ctrl1_12b version */ -enum lis3lv02d_ctrl1_8b { - CTRL1_STM = 0x08, - CTRL1_STP = 0x10, - CTRL1_FS = 0x20, - CTRL1_PD = 0x40, - CTRL1_DR = 0x80, -}; - -enum lis3lv02d_ctrl1_3dc { - CTRL1_ODR0 = 0x10, - CTRL1_ODR1 = 0x20, - CTRL1_ODR2 = 0x40, - CTRL1_ODR3 = 0x80, -}; - -enum lis3lv02d_ctrl2 { - CTRL2_DAS = 0x01, - CTRL2_SIM = 0x02, - CTRL2_DRDY = 0x04, - CTRL2_IEN = 0x08, - CTRL2_BOOT = 0x10, - CTRL2_BLE = 0x20, - CTRL2_BDU = 0x40, /* Block Data Update */ - CTRL2_FS = 0x80, /* Full Scale selection */ -}; - -enum lis3lv02d_ctrl4_3dc { - CTRL4_SIM = 0x01, - CTRL4_ST0 = 0x02, - CTRL4_ST1 = 0x04, - CTRL4_FS0 = 0x10, - CTRL4_FS1 = 0x20, -}; - -enum lis302d_ctrl2 { - HP_FF_WU2 = 0x08, - HP_FF_WU1 = 0x04, - CTRL2_BOOT_8B = 0x40, -}; - -enum lis3lv02d_ctrl3 { - CTRL3_CFS0 = 0x01, - CTRL3_CFS1 = 0x02, - CTRL3_FDS = 0x10, - CTRL3_HPFF = 0x20, - CTRL3_HPDD = 0x40, - CTRL3_ECK = 0x80, -}; - -enum lis3lv02d_status_reg { - STATUS_XDA = 0x01, - STATUS_YDA = 0x02, - STATUS_ZDA = 0x04, - STATUS_XYZDA = 0x08, - STATUS_XOR = 0x10, - STATUS_YOR = 0x20, - STATUS_ZOR = 0x40, - STATUS_XYZOR = 0x80, -}; - -enum lis3lv02d_ff_wu_cfg { - FF_WU_CFG_XLIE = 0x01, - FF_WU_CFG_XHIE = 0x02, - FF_WU_CFG_YLIE = 0x04, - FF_WU_CFG_YHIE = 0x08, - FF_WU_CFG_ZLIE = 0x10, - FF_WU_CFG_ZHIE = 0x20, - FF_WU_CFG_LIR = 0x40, - FF_WU_CFG_AOI = 0x80, -}; - -enum lis3lv02d_ff_wu_src { - FF_WU_SRC_XL = 0x01, - FF_WU_SRC_XH = 0x02, - FF_WU_SRC_YL = 0x04, - FF_WU_SRC_YH = 0x08, - FF_WU_SRC_ZL = 0x10, - FF_WU_SRC_ZH = 0x20, - FF_WU_SRC_IA = 0x40, -}; - -enum lis3lv02d_dd_cfg { - DD_CFG_XLIE = 0x01, - DD_CFG_XHIE = 0x02, - DD_CFG_YLIE = 0x04, - DD_CFG_YHIE = 0x08, - DD_CFG_ZLIE = 0x10, - DD_CFG_ZHIE = 0x20, - DD_CFG_LIR = 0x40, - DD_CFG_IEND = 0x80, -}; - -enum lis3lv02d_dd_src { - DD_SRC_XL = 0x01, - DD_SRC_XH = 0x02, - DD_SRC_YL = 0x04, - DD_SRC_YH = 0x08, - DD_SRC_ZL = 0x10, - DD_SRC_ZH = 0x20, - DD_SRC_IA = 0x40, -}; - -enum lis3lv02d_click_src_8b { - CLICK_SINGLE_X = 0x01, - CLICK_DOUBLE_X = 0x02, - CLICK_SINGLE_Y = 0x04, - CLICK_DOUBLE_Y = 0x08, - CLICK_SINGLE_Z = 0x10, - CLICK_DOUBLE_Z = 0x20, - CLICK_IA = 0x40, -}; - -enum lis3lv02d_reg_state { - LIS3_REG_OFF = 0x00, - LIS3_REG_ON = 0x01, -}; - -union axis_conversion { - struct { - int x, y, z; - }; - int as_array[3]; - -}; - -struct lis3lv02d { - void *bus_priv; /* used by the bus layer only */ - struct device *pm_dev; /* for pm_runtime purposes */ - int (*init) (struct lis3lv02d *lis3); - int (*write) (struct lis3lv02d *lis3, int reg, u8 val); - int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret); - int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret); - int (*reg_ctrl) (struct lis3lv02d *lis3, bool state); - - int *odrs; /* Supported output data rates */ - u8 *regs; /* Regs to store / restore */ - int regs_size; - u8 *reg_cache; - bool regs_stored; - u8 odr_mask; /* ODR bit mask */ - u8 whoami; /* indicates measurement precision */ - s16 (*read_data) (struct lis3lv02d *lis3, int reg); - int mdps_max_val; - int pwron_delay; - int scale; /* - * relationship between 1 LBS and mG - * (1/1000th of earth gravity) - */ - - struct input_polled_dev *idev; /* input device */ - struct platform_device *pdev; /* platform device */ - struct regulator_bulk_data regulators[2]; - atomic_t count; /* interrupt count after last read */ - union axis_conversion ac; /* hw -> logical axis */ - int mapped_btns[3]; - - u32 irq; /* IRQ number */ - struct fasync_struct *async_queue; /* queue for the misc device */ - wait_queue_head_t misc_wait; /* Wait queue for the misc device */ - unsigned long misc_opened; /* bit0: whether the device is open */ - int data_ready_count[2]; - atomic_t wake_thread; - unsigned char irq_cfg; - - struct lis3lv02d_platform_data *pdata; /* for passing board config */ - struct mutex mutex; /* Serialize poll and selftest */ -}; - -int lis3lv02d_init_device(struct lis3lv02d *lis3); -int lis3lv02d_joystick_enable(void); -void lis3lv02d_joystick_disable(void); -void lis3lv02d_poweroff(struct lis3lv02d *lis3); -void lis3lv02d_poweron(struct lis3lv02d *lis3); -int lis3lv02d_remove_fs(struct lis3lv02d *lis3); - -extern struct lis3lv02d lis3_dev; diff --git a/drivers/hwmon/lis3lv02d_i2c.c b/drivers/hwmon/lis3lv02d_i2c.c deleted file mode 100644 index 8853afce85ce..000000000000 --- a/drivers/hwmon/lis3lv02d_i2c.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * drivers/hwmon/lis3lv02d_i2c.c - * - * Implements I2C interface for lis3lv02d (STMicroelectronics) accelerometer. - * Driver is based on corresponding SPI driver written by Daniel Mack - * (lis3lv02d_spi.c (C) 2009 Daniel Mack ). - * - * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). - * - * Contact: Samu Onkalo - * - * 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. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include "lis3lv02d.h" - -#define DRV_NAME "lis3lv02d_i2c" - -static const char reg_vdd[] = "Vdd"; -static const char reg_vdd_io[] = "Vdd_IO"; - -static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state) -{ - int ret; - if (state == LIS3_REG_OFF) { - ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators), - lis3->regulators); - } else { - ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators), - lis3->regulators); - /* Chip needs time to wakeup. Not mentioned in datasheet */ - usleep_range(10000, 20000); - } - return ret; -} - -static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value) -{ - struct i2c_client *c = lis3->bus_priv; - return i2c_smbus_write_byte_data(c, reg, value); -} - -static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v) -{ - struct i2c_client *c = lis3->bus_priv; - *v = i2c_smbus_read_byte_data(c, reg); - return 0; -} - -static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len, - u8 *v) -{ - struct i2c_client *c = lis3->bus_priv; - reg |= (1 << 7); /* 7th bit enables address auto incrementation */ - return i2c_smbus_read_i2c_block_data(c, reg, len, v); -} - -static int lis3_i2c_init(struct lis3lv02d *lis3) -{ - u8 reg; - int ret; - - if (lis3->reg_ctrl) - lis3_reg_ctrl(lis3, LIS3_REG_ON); - - lis3->read(lis3, WHO_AM_I, ®); - if (reg != lis3->whoami) - printk(KERN_ERR "lis3: power on failure\n"); - - /* power up the device */ - ret = lis3->read(lis3, CTRL_REG1, ®); - if (ret < 0) - return ret; - - reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; - return lis3->write(lis3, CTRL_REG1, reg); -} - -/* Default axis mapping but it can be overwritten by platform data */ -static union axis_conversion lis3lv02d_axis_map = - { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } }; - -static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int ret = 0; - struct lis3lv02d_platform_data *pdata = client->dev.platform_data; - - if (pdata) { - /* Regulator control is optional */ - if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL) - lis3_dev.reg_ctrl = lis3_reg_ctrl; - - if ((pdata->driver_features & LIS3_USE_BLOCK_READ) && - (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_I2C_BLOCK))) - lis3_dev.blkread = lis3_i2c_blockread; - - if (pdata->axis_x) - lis3lv02d_axis_map.x = pdata->axis_x; - - if (pdata->axis_y) - lis3lv02d_axis_map.y = pdata->axis_y; - - if (pdata->axis_z) - lis3lv02d_axis_map.z = pdata->axis_z; - - if (pdata->setup_resources) - ret = pdata->setup_resources(); - - if (ret) - goto fail; - } - - if (lis3_dev.reg_ctrl) { - lis3_dev.regulators[0].supply = reg_vdd; - lis3_dev.regulators[1].supply = reg_vdd_io; - ret = regulator_bulk_get(&client->dev, - ARRAY_SIZE(lis3_dev.regulators), - lis3_dev.regulators); - if (ret < 0) - goto fail; - } - - lis3_dev.pdata = pdata; - lis3_dev.bus_priv = client; - lis3_dev.init = lis3_i2c_init; - lis3_dev.read = lis3_i2c_read; - lis3_dev.write = lis3_i2c_write; - lis3_dev.irq = client->irq; - lis3_dev.ac = lis3lv02d_axis_map; - lis3_dev.pm_dev = &client->dev; - - i2c_set_clientdata(client, &lis3_dev); - - /* Provide power over the init call */ - if (lis3_dev.reg_ctrl) - lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON); - - ret = lis3lv02d_init_device(&lis3_dev); - - if (lis3_dev.reg_ctrl) - lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF); - - if (ret == 0) - return 0; -fail: - if (pdata && pdata->release_resources) - pdata->release_resources(); - return ret; -} - -static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) -{ - struct lis3lv02d *lis3 = i2c_get_clientdata(client); - struct lis3lv02d_platform_data *pdata = client->dev.platform_data; - - if (pdata && pdata->release_resources) - pdata->release_resources(); - - lis3lv02d_joystick_disable(); - lis3lv02d_remove_fs(&lis3_dev); - - if (lis3_dev.reg_ctrl) - regulator_bulk_free(ARRAY_SIZE(lis3->regulators), - lis3_dev.regulators); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int lis3lv02d_i2c_suspend(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct lis3lv02d *lis3 = i2c_get_clientdata(client); - - if (!lis3->pdata || !lis3->pdata->wakeup_flags) - lis3lv02d_poweroff(lis3); - return 0; -} - -static int lis3lv02d_i2c_resume(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct lis3lv02d *lis3 = i2c_get_clientdata(client); - - /* - * pm_runtime documentation says that devices should always - * be powered on at resume. Pm_runtime turns them off after system - * wide resume is complete. - */ - if (!lis3->pdata || !lis3->pdata->wakeup_flags || - pm_runtime_suspended(dev)) - lis3lv02d_poweron(lis3); - - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM_RUNTIME -static int lis3_i2c_runtime_suspend(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct lis3lv02d *lis3 = i2c_get_clientdata(client); - - lis3lv02d_poweroff(lis3); - return 0; -} - -static int lis3_i2c_runtime_resume(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct lis3lv02d *lis3 = i2c_get_clientdata(client); - - lis3lv02d_poweron(lis3); - return 0; -} -#endif /* CONFIG_PM_RUNTIME */ - -static const struct i2c_device_id lis3lv02d_id[] = { - {"lis3lv02d", 0 }, - {} -}; - -MODULE_DEVICE_TABLE(i2c, lis3lv02d_id); - -static const struct dev_pm_ops lis3_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend, - lis3lv02d_i2c_resume) - SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend, - lis3_i2c_runtime_resume, - NULL) -}; - -static struct i2c_driver lis3lv02d_i2c_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - .pm = &lis3_pm_ops, - }, - .probe = lis3lv02d_i2c_probe, - .remove = __devexit_p(lis3lv02d_i2c_remove), - .id_table = lis3lv02d_id, -}; - -static int __init lis3lv02d_init(void) -{ - return i2c_add_driver(&lis3lv02d_i2c_driver); -} - -static void __exit lis3lv02d_exit(void) -{ - i2c_del_driver(&lis3lv02d_i2c_driver); -} - -MODULE_AUTHOR("Nokia Corporation"); -MODULE_DESCRIPTION("lis3lv02d I2C interface"); -MODULE_LICENSE("GPL"); - -module_init(lis3lv02d_init); -module_exit(lis3lv02d_exit); diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c deleted file mode 100644 index c1f8a8fbf694..000000000000 --- a/drivers/hwmon/lis3lv02d_spi.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * lis3lv02d_spi - SPI glue layer for lis3lv02d - * - * Copyright (c) 2009 Daniel Mack - * - * 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 - * publishhed by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lis3lv02d.h" - -#define DRV_NAME "lis3lv02d_spi" -#define LIS3_SPI_READ 0x80 - -static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) -{ - struct spi_device *spi = lis3->bus_priv; - int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); - if (ret < 0) - return -EINVAL; - - *v = (u8) ret; - return 0; -} - -static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) -{ - u8 tmp[2] = { reg, val }; - struct spi_device *spi = lis3->bus_priv; - return spi_write(spi, tmp, sizeof(tmp)); -} - -static int lis3_spi_init(struct lis3lv02d *lis3) -{ - u8 reg; - int ret; - - /* power up the device */ - ret = lis3->read(lis3, CTRL_REG1, ®); - if (ret < 0) - return ret; - - reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; - return lis3->write(lis3, CTRL_REG1, reg); -} - -static union axis_conversion lis3lv02d_axis_normal = - { .as_array = { 1, 2, 3 } }; - -static int __devinit lis302dl_spi_probe(struct spi_device *spi) -{ - int ret; - - spi->bits_per_word = 8; - spi->mode = SPI_MODE_0; - ret = spi_setup(spi); - if (ret < 0) - return ret; - - lis3_dev.bus_priv = spi; - lis3_dev.init = lis3_spi_init; - lis3_dev.read = lis3_spi_read; - lis3_dev.write = lis3_spi_write; - lis3_dev.irq = spi->irq; - lis3_dev.ac = lis3lv02d_axis_normal; - lis3_dev.pdata = spi->dev.platform_data; - spi_set_drvdata(spi, &lis3_dev); - - return lis3lv02d_init_device(&lis3_dev); -} - -static int __devexit lis302dl_spi_remove(struct spi_device *spi) -{ - struct lis3lv02d *lis3 = spi_get_drvdata(spi); - lis3lv02d_joystick_disable(); - lis3lv02d_poweroff(lis3); - - return lis3lv02d_remove_fs(&lis3_dev); -} - -#ifdef CONFIG_PM_SLEEP -static int lis3lv02d_spi_suspend(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - struct lis3lv02d *lis3 = spi_get_drvdata(spi); - - if (!lis3->pdata || !lis3->pdata->wakeup_flags) - lis3lv02d_poweroff(&lis3_dev); - - return 0; -} - -static int lis3lv02d_spi_resume(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - struct lis3lv02d *lis3 = spi_get_drvdata(spi); - - if (!lis3->pdata || !lis3->pdata->wakeup_flags) - lis3lv02d_poweron(lis3); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend, - lis3lv02d_spi_resume); - -static struct spi_driver lis302dl_spi_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - .pm = &lis3lv02d_spi_pm, - }, - .probe = lis302dl_spi_probe, - .remove = __devexit_p(lis302dl_spi_remove), -}; - -static int __init lis302dl_init(void) -{ - return spi_register_driver(&lis302dl_spi_driver); -} - -static void __exit lis302dl_exit(void) -{ - spi_unregister_driver(&lis302dl_spi_driver); -} - -module_init(lis302dl_init); -module_exit(lis302dl_exit); - -MODULE_AUTHOR("Daniel Mack "); -MODULE_DESCRIPTION("lis3lv02d SPI glue layer"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b7d5ef234ac9..203500d9b848 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -2,6 +2,14 @@ # Misc strange devices # +# This one has to live outside of the MISC_DEVICES conditional, +# because it may be selected by drivers/platform/x86/hp_accel. +config SENSORS_LIS3LV02D + tristate + depends on INPUT + select INPUT_POLLDEV + default n + menuconfig MISC_DEVICES bool "Misc devices" ---help--- @@ -462,5 +470,6 @@ source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" +source "drivers/misc/lis3lv02d/Kconfig" endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 98009cc20cb9..804f421bc079 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o obj-$(CONFIG_PCH_PHUB) += pch_phub.o obj-y += ti-st/ obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o +obj-y += lis3lv02d/ diff --git a/drivers/misc/lis3lv02d/Kconfig b/drivers/misc/lis3lv02d/Kconfig new file mode 100644 index 000000000000..8f474e6fc7b4 --- /dev/null +++ b/drivers/misc/lis3lv02d/Kconfig @@ -0,0 +1,37 @@ +# +# STMicroelectonics LIS3LV02D and similar accelerometers +# + +config SENSORS_LIS3_SPI + tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" + depends on !ACPI && SPI_MASTER && INPUT + select SENSORS_LIS3LV02D + default n + help + This driver provides support for the LIS3LV02Dx accelerometer connected + via SPI. The accelerometer data is readable via + /sys/devices/platform/lis3lv02d. + + This driver also provides an absolute input class device, allowing + the laptop to act as a pinball machine-esque joystick. + + This driver can also be built as modules. If so, the core module + will be called lis3lv02d and a specific module for the SPI transport + is called lis3lv02d_spi. + +config SENSORS_LIS3_I2C + tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)" + depends on I2C && INPUT + select SENSORS_LIS3LV02D + default n + help + This driver provides support for the LIS3LV02Dx accelerometer connected + via I2C. The accelerometer data is readable via + /sys/devices/platform/lis3lv02d. + + This driver also provides an absolute input class device, allowing + the device to act as a pinball machine-esque joystick. + + This driver can also be built as modules. If so, the core module + will be called lis3lv02d and a specific module for the I2C transport + is called lis3lv02d_i2c. diff --git a/drivers/misc/lis3lv02d/Makefile b/drivers/misc/lis3lv02d/Makefile new file mode 100644 index 000000000000..4bf58b16fcf8 --- /dev/null +++ b/drivers/misc/lis3lv02d/Makefile @@ -0,0 +1,7 @@ +# +# STMicroelectonics LIS3LV02D and similar accelerometers +# + +obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o +obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d_spi.o +obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d_i2c.o diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c new file mode 100644 index 000000000000..b928bc14e97b --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -0,0 +1,999 @@ +/* + * lis3lv02d.c - ST LIS3LV02DL accelerometer driver + * + * Copyright (C) 2007-2008 Yan Burman + * Copyright (C) 2008 Eric Piel + * Copyright (C) 2008-2009 Pavel Machek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lis3lv02d.h" + +#define DRIVER_NAME "lis3lv02d" + +/* joystick device poll interval in milliseconds */ +#define MDPS_POLL_INTERVAL 50 +#define MDPS_POLL_MIN 0 +#define MDPS_POLL_MAX 2000 + +#define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */ + +#define SELFTEST_OK 0 +#define SELFTEST_FAIL -1 +#define SELFTEST_IRQ -2 + +#define IRQ_LINE0 0 +#define IRQ_LINE1 1 + +/* + * The sensor can also generate interrupts (DRDY) but it's pretty pointless + * because they are generated even if the data do not change. So it's better + * to keep the interrupt for the free-fall event. The values are updated at + * 40Hz (at the lowest frequency), but as it can be pretty time consuming on + * some low processor, we poll the sensor only at 20Hz... enough for the + * joystick. + */ + +#define LIS3_PWRON_DELAY_WAI_12B (5000) +#define LIS3_PWRON_DELAY_WAI_8B (3000) + +/* + * LIS3LV02D spec says 1024 LSBs corresponds 1 G -> 1LSB is 1000/1024 mG + * LIS302D spec says: 18 mG / digit + * LIS3_ACCURACY is used to increase accuracy of the intermediate + * calculation results. + */ +#define LIS3_ACCURACY 1024 +/* Sensitivity values for -2G +2G scale */ +#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024) +#define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY) + +#define LIS3_DEFAULT_FUZZ_12B 3 +#define LIS3_DEFAULT_FLAT_12B 3 +#define LIS3_DEFAULT_FUZZ_8B 1 +#define LIS3_DEFAULT_FLAT_8B 1 + +struct lis3lv02d lis3_dev = { + .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait), +}; +EXPORT_SYMBOL_GPL(lis3_dev); + +/* just like param_set_int() but does sanity-check so that it won't point + * over the axis array size + */ +static int param_set_axis(const char *val, const struct kernel_param *kp) +{ + int ret = param_set_int(val, kp); + if (!ret) { + int val = *(int *)kp->arg; + if (val < 0) + val = -val; + if (!val || val > 3) + return -EINVAL; + } + return ret; +} + +static struct kernel_param_ops param_ops_axis = { + .set = param_set_axis, + .get = param_get_int, +}; + +module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644); +MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions"); + +static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg) +{ + s8 lo; + if (lis3->read(lis3, reg, &lo) < 0) + return 0; + + return lo; +} + +static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg) +{ + u8 lo, hi; + + lis3->read(lis3, reg - 1, &lo); + lis3->read(lis3, reg, &hi); + /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ + return (s16)((hi << 8) | lo); +} + +/** + * lis3lv02d_get_axis - For the given axis, give the value converted + * @axis: 1,2,3 - can also be negative + * @hw_values: raw values returned by the hardware + * + * Returns the converted value. + */ +static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3]) +{ + if (axis > 0) + return hw_values[axis - 1]; + else + return -hw_values[-axis - 1]; +} + +/** + * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer + * @lis3: pointer to the device struct + * @x: where to store the X axis value + * @y: where to store the Y axis value + * @z: where to store the Z axis value + * + * Note that 40Hz input device can eat up about 10% CPU at 800MHZ + */ +static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) +{ + int position[3]; + int i; + + if (lis3->blkread) { + if (lis3_dev.whoami == WAI_12B) { + u16 data[3]; + lis3->blkread(lis3, OUTX_L, 6, (u8 *)data); + for (i = 0; i < 3; i++) + position[i] = (s16)le16_to_cpu(data[i]); + } else { + u8 data[5]; + /* Data: x, dummy, y, dummy, z */ + lis3->blkread(lis3, OUTX, 5, data); + for (i = 0; i < 3; i++) + position[i] = (s8)data[i * 2]; + } + } else { + position[0] = lis3->read_data(lis3, OUTX); + position[1] = lis3->read_data(lis3, OUTY); + position[2] = lis3->read_data(lis3, OUTZ); + } + + for (i = 0; i < 3; i++) + position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; + + *x = lis3lv02d_get_axis(lis3->ac.x, position); + *y = lis3lv02d_get_axis(lis3->ac.y, position); + *z = lis3lv02d_get_axis(lis3->ac.z, position); +} + +/* conversion btw sampling rate and the register values */ +static int lis3_12_rates[4] = {40, 160, 640, 2560}; +static int lis3_8_rates[2] = {100, 400}; +static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; + +/* ODR is Output Data Rate */ +static int lis3lv02d_get_odr(void) +{ + u8 ctrl; + int shift; + + lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); + ctrl &= lis3_dev.odr_mask; + shift = ffs(lis3_dev.odr_mask) - 1; + return lis3_dev.odrs[(ctrl >> shift)]; +} + +static int lis3lv02d_set_odr(int rate) +{ + u8 ctrl; + int i, len, shift; + + if (!rate) + return -EINVAL; + + lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); + ctrl &= ~lis3_dev.odr_mask; + len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */ + shift = ffs(lis3_dev.odr_mask) - 1; + + for (i = 0; i < len; i++) + if (lis3_dev.odrs[i] == rate) { + lis3_dev.write(&lis3_dev, CTRL_REG1, + ctrl | (i << shift)); + return 0; + } + return -EINVAL; +} + +static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) +{ + u8 ctlreg, reg; + s16 x, y, z; + u8 selftest; + int ret; + u8 ctrl_reg_data; + unsigned char irq_cfg; + + mutex_lock(&lis3->mutex); + + irq_cfg = lis3->irq_cfg; + if (lis3_dev.whoami == WAI_8B) { + lis3->data_ready_count[IRQ_LINE0] = 0; + lis3->data_ready_count[IRQ_LINE1] = 0; + + /* Change interrupt cfg to data ready for selftest */ + atomic_inc(&lis3_dev.wake_thread); + lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY; + lis3->read(lis3, CTRL_REG3, &ctrl_reg_data); + lis3->write(lis3, CTRL_REG3, (ctrl_reg_data & + ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) | + (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY)); + } + + if (lis3_dev.whoami == WAI_3DC) { + ctlreg = CTRL_REG4; + selftest = CTRL4_ST0; + } else { + ctlreg = CTRL_REG1; + if (lis3_dev.whoami == WAI_12B) + selftest = CTRL1_ST; + else + selftest = CTRL1_STP; + } + + lis3->read(lis3, ctlreg, ®); + lis3->write(lis3, ctlreg, (reg | selftest)); + msleep(lis3->pwron_delay / lis3lv02d_get_odr()); + + /* Read directly to avoid axis remap */ + x = lis3->read_data(lis3, OUTX); + y = lis3->read_data(lis3, OUTY); + z = lis3->read_data(lis3, OUTZ); + + /* back to normal settings */ + lis3->write(lis3, ctlreg, reg); + msleep(lis3->pwron_delay / lis3lv02d_get_odr()); + + results[0] = x - lis3->read_data(lis3, OUTX); + results[1] = y - lis3->read_data(lis3, OUTY); + results[2] = z - lis3->read_data(lis3, OUTZ); + + ret = 0; + + if (lis3_dev.whoami == WAI_8B) { + /* Restore original interrupt configuration */ + atomic_dec(&lis3_dev.wake_thread); + lis3->write(lis3, CTRL_REG3, ctrl_reg_data); + lis3->irq_cfg = irq_cfg; + + if ((irq_cfg & LIS3_IRQ1_MASK) && + lis3->data_ready_count[IRQ_LINE0] < 2) { + ret = SELFTEST_IRQ; + goto fail; + } + + if ((irq_cfg & LIS3_IRQ2_MASK) && + lis3->data_ready_count[IRQ_LINE1] < 2) { + ret = SELFTEST_IRQ; + goto fail; + } + } + + if (lis3->pdata) { + int i; + for (i = 0; i < 3; i++) { + /* Check against selftest acceptance limits */ + if ((results[i] < lis3->pdata->st_min_limits[i]) || + (results[i] > lis3->pdata->st_max_limits[i])) { + ret = SELFTEST_FAIL; + goto fail; + } + } + } + + /* test passed */ +fail: + mutex_unlock(&lis3->mutex); + return ret; +} + +/* + * Order of registers in the list affects to order of the restore process. + * Perhaps it is a good idea to set interrupt enable register as a last one + * after all other configurations + */ +static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1, + FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2, + CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ, + CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW, + CTRL_REG1, CTRL_REG2, CTRL_REG3}; + +static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H, + FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H, + DD_THSE_L, DD_THSE_H, + CTRL_REG1, CTRL_REG3, CTRL_REG2}; + +static inline void lis3_context_save(struct lis3lv02d *lis3) +{ + int i; + for (i = 0; i < lis3->regs_size; i++) + lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]); + lis3->regs_stored = true; +} + +static inline void lis3_context_restore(struct lis3lv02d *lis3) +{ + int i; + if (lis3->regs_stored) + for (i = 0; i < lis3->regs_size; i++) + lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]); +} + +void lis3lv02d_poweroff(struct lis3lv02d *lis3) +{ + if (lis3->reg_ctrl) + lis3_context_save(lis3); + /* disable X,Y,Z axis and power down */ + lis3->write(lis3, CTRL_REG1, 0x00); + if (lis3->reg_ctrl) + lis3->reg_ctrl(lis3, LIS3_REG_OFF); +} +EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); + +void lis3lv02d_poweron(struct lis3lv02d *lis3) +{ + u8 reg; + + lis3->init(lis3); + + /* + * Common configuration + * BDU: (12 bits sensors only) LSB and MSB values are not updated until + * both have been read. So the value read will always be correct. + * Set BOOT bit to refresh factory tuning values. + */ + lis3->read(lis3, CTRL_REG2, ®); + if (lis3->whoami == WAI_12B) + reg |= CTRL2_BDU | CTRL2_BOOT; + else + reg |= CTRL2_BOOT_8B; + lis3->write(lis3, CTRL_REG2, reg); + + /* LIS3 power on delay is quite long */ + msleep(lis3->pwron_delay / lis3lv02d_get_odr()); + + if (lis3->reg_ctrl) + lis3_context_restore(lis3); +} +EXPORT_SYMBOL_GPL(lis3lv02d_poweron); + + +static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) +{ + int x, y, z; + + mutex_lock(&lis3_dev.mutex); + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); + input_report_abs(pidev->input, ABS_X, x); + input_report_abs(pidev->input, ABS_Y, y); + input_report_abs(pidev->input, ABS_Z, z); + input_sync(pidev->input); + mutex_unlock(&lis3_dev.mutex); +} + +static void lis3lv02d_joystick_open(struct input_polled_dev *pidev) +{ + if (lis3_dev.pm_dev) + pm_runtime_get_sync(lis3_dev.pm_dev); + + if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev) + atomic_set(&lis3_dev.wake_thread, 1); + /* + * Update coordinates for the case where poll interval is 0 and + * the chip in running purely under interrupt control + */ + lis3lv02d_joystick_poll(pidev); +} + +static void lis3lv02d_joystick_close(struct input_polled_dev *pidev) +{ + atomic_set(&lis3_dev.wake_thread, 0); + if (lis3_dev.pm_dev) + pm_runtime_put(lis3_dev.pm_dev); +} + +static irqreturn_t lis302dl_interrupt(int irq, void *dummy) +{ + if (!test_bit(0, &lis3_dev.misc_opened)) + goto out; + + /* + * Be careful: on some HP laptops the bios force DD when on battery and + * the lid is closed. This leads to interrupts as soon as a little move + * is done. + */ + atomic_inc(&lis3_dev.count); + + wake_up_interruptible(&lis3_dev.misc_wait); + kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); +out: + if (atomic_read(&lis3_dev.wake_thread)) + return IRQ_WAKE_THREAD; + return IRQ_HANDLED; +} + +static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) +{ + struct input_dev *dev = lis3->idev->input; + u8 click_src; + + mutex_lock(&lis3->mutex); + lis3->read(lis3, CLICK_SRC, &click_src); + + if (click_src & CLICK_SINGLE_X) { + input_report_key(dev, lis3->mapped_btns[0], 1); + input_report_key(dev, lis3->mapped_btns[0], 0); + } + + if (click_src & CLICK_SINGLE_Y) { + input_report_key(dev, lis3->mapped_btns[1], 1); + input_report_key(dev, lis3->mapped_btns[1], 0); + } + + if (click_src & CLICK_SINGLE_Z) { + input_report_key(dev, lis3->mapped_btns[2], 1); + input_report_key(dev, lis3->mapped_btns[2], 0); + } + input_sync(dev); + mutex_unlock(&lis3->mutex); +} + +static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index) +{ + int dummy; + + /* Dummy read to ack interrupt */ + lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy); + lis3->data_ready_count[index]++; +} + +static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) +{ + struct lis3lv02d *lis3 = data; + u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK; + + if (irq_cfg == LIS3_IRQ1_CLICK) + lis302dl_interrupt_handle_click(lis3); + else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY)) + lis302dl_data_ready(lis3, IRQ_LINE0); + else + lis3lv02d_joystick_poll(lis3->idev); + + return IRQ_HANDLED; +} + +static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) +{ + struct lis3lv02d *lis3 = data; + u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK; + + if (irq_cfg == LIS3_IRQ2_CLICK) + lis302dl_interrupt_handle_click(lis3); + else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY)) + lis302dl_data_ready(lis3, IRQ_LINE1); + else + lis3lv02d_joystick_poll(lis3->idev); + + return IRQ_HANDLED; +} + +static int lis3lv02d_misc_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &lis3_dev.misc_opened)) + return -EBUSY; /* already open */ + + if (lis3_dev.pm_dev) + pm_runtime_get_sync(lis3_dev.pm_dev); + + atomic_set(&lis3_dev.count, 0); + return 0; +} + +static int lis3lv02d_misc_release(struct inode *inode, struct file *file) +{ + fasync_helper(-1, file, 0, &lis3_dev.async_queue); + clear_bit(0, &lis3_dev.misc_opened); /* release the device */ + if (lis3_dev.pm_dev) + pm_runtime_put(lis3_dev.pm_dev); + return 0; +} + +static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + DECLARE_WAITQUEUE(wait, current); + u32 data; + unsigned char byte_data; + ssize_t retval = 1; + + if (count < 1) + return -EINVAL; + + add_wait_queue(&lis3_dev.misc_wait, &wait); + while (true) { + set_current_state(TASK_INTERRUPTIBLE); + data = atomic_xchg(&lis3_dev.count, 0); + if (data) + break; + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + schedule(); + } + + if (data < 255) + byte_data = data; + else + byte_data = 255; + + /* make sure we are not going into copy_to_user() with + * TASK_INTERRUPTIBLE state */ + set_current_state(TASK_RUNNING); + if (copy_to_user(buf, &byte_data, sizeof(byte_data))) + retval = -EFAULT; + +out: + __set_current_state(TASK_RUNNING); + remove_wait_queue(&lis3_dev.misc_wait, &wait); + + return retval; +} + +static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &lis3_dev.misc_wait, wait); + if (atomic_read(&lis3_dev.count)) + return POLLIN | POLLRDNORM; + return 0; +} + +static int lis3lv02d_misc_fasync(int fd, struct file *file, int on) +{ + return fasync_helper(fd, file, on, &lis3_dev.async_queue); +} + +static const struct file_operations lis3lv02d_misc_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = lis3lv02d_misc_read, + .open = lis3lv02d_misc_open, + .release = lis3lv02d_misc_release, + .poll = lis3lv02d_misc_poll, + .fasync = lis3lv02d_misc_fasync, +}; + +static struct miscdevice lis3lv02d_misc_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "freefall", + .fops = &lis3lv02d_misc_fops, +}; + +int lis3lv02d_joystick_enable(void) +{ + struct input_dev *input_dev; + int err; + int max_val, fuzz, flat; + int btns[] = {BTN_X, BTN_Y, BTN_Z}; + + if (lis3_dev.idev) + return -EINVAL; + + lis3_dev.idev = input_allocate_polled_device(); + if (!lis3_dev.idev) + return -ENOMEM; + + lis3_dev.idev->poll = lis3lv02d_joystick_poll; + lis3_dev.idev->open = lis3lv02d_joystick_open; + lis3_dev.idev->close = lis3lv02d_joystick_close; + lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; + lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN; + lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX; + input_dev = lis3_dev.idev->input; + + input_dev->name = "ST LIS3LV02DL Accelerometer"; + input_dev->phys = DRIVER_NAME "/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0; + input_dev->dev.parent = &lis3_dev.pdev->dev; + + set_bit(EV_ABS, input_dev->evbit); + max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY; + if (lis3_dev.whoami == WAI_12B) { + fuzz = LIS3_DEFAULT_FUZZ_12B; + flat = LIS3_DEFAULT_FLAT_12B; + } else { + fuzz = LIS3_DEFAULT_FUZZ_8B; + flat = LIS3_DEFAULT_FLAT_8B; + } + fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY; + flat = (flat * lis3_dev.scale) / LIS3_ACCURACY; + + input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat); + input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); + input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); + + lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns); + lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns); + lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns); + + err = input_register_polled_device(lis3_dev.idev); + if (err) { + input_free_polled_device(lis3_dev.idev); + lis3_dev.idev = NULL; + } + + return err; +} +EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); + +void lis3lv02d_joystick_disable(void) +{ + if (lis3_dev.irq) + free_irq(lis3_dev.irq, &lis3_dev); + if (lis3_dev.pdata && lis3_dev.pdata->irq2) + free_irq(lis3_dev.pdata->irq2, &lis3_dev); + + if (!lis3_dev.idev) + return; + + if (lis3_dev.irq) + misc_deregister(&lis3lv02d_misc_device); + input_unregister_polled_device(lis3_dev.idev); + input_free_polled_device(lis3_dev.idev); + lis3_dev.idev = NULL; +} +EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); + +/* Sysfs stuff */ +static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) +{ + /* + * SYSFS functions are fast visitors so put-call + * immediately after the get-call. However, keep + * chip running for a while and schedule delayed + * suspend. This way periodic sysfs calls doesn't + * suffer from relatively long power up time. + */ + + if (lis3->pm_dev) { + pm_runtime_get_sync(lis3->pm_dev); + pm_runtime_put_noidle(lis3->pm_dev); + pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY); + } +} + +static ssize_t lis3lv02d_selftest_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + s16 values[3]; + + static const char ok[] = "OK"; + static const char fail[] = "FAIL"; + static const char irq[] = "FAIL_IRQ"; + const char *res; + + lis3lv02d_sysfs_poweron(&lis3_dev); + switch (lis3lv02d_selftest(&lis3_dev, values)) { + case SELFTEST_FAIL: + res = fail; + break; + case SELFTEST_IRQ: + res = irq; + break; + case SELFTEST_OK: + default: + res = ok; + break; + } + return sprintf(buf, "%s %d %d %d\n", res, + values[0], values[1], values[2]); +} + +static ssize_t lis3lv02d_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int x, y, z; + + lis3lv02d_sysfs_poweron(&lis3_dev); + mutex_lock(&lis3_dev.mutex); + lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); + mutex_unlock(&lis3_dev.mutex); + return sprintf(buf, "(%d,%d,%d)\n", x, y, z); +} + +static ssize_t lis3lv02d_rate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + lis3lv02d_sysfs_poweron(&lis3_dev); + return sprintf(buf, "%d\n", lis3lv02d_get_odr()); +} + +static ssize_t lis3lv02d_rate_set(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + unsigned long rate; + + if (strict_strtoul(buf, 0, &rate)) + return -EINVAL; + + lis3lv02d_sysfs_poweron(&lis3_dev); + if (lis3lv02d_set_odr(rate)) + return -EINVAL; + + return count; +} + +static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL); +static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); +static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show, + lis3lv02d_rate_set); + +static struct attribute *lis3lv02d_attributes[] = { + &dev_attr_selftest.attr, + &dev_attr_position.attr, + &dev_attr_rate.attr, + NULL +}; + +static struct attribute_group lis3lv02d_attribute_group = { + .attrs = lis3lv02d_attributes +}; + + +static int lis3lv02d_add_fs(struct lis3lv02d *lis3) +{ + lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + if (IS_ERR(lis3->pdev)) + return PTR_ERR(lis3->pdev); + + return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); +} + +int lis3lv02d_remove_fs(struct lis3lv02d *lis3) +{ + sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); + platform_device_unregister(lis3->pdev); + if (lis3->pm_dev) { + /* Barrier after the sysfs remove */ + pm_runtime_barrier(lis3->pm_dev); + + /* SYSFS may have left chip running. Turn off if necessary */ + if (!pm_runtime_suspended(lis3->pm_dev)) + lis3lv02d_poweroff(&lis3_dev); + + pm_runtime_disable(lis3->pm_dev); + pm_runtime_set_suspended(lis3->pm_dev); + } + kfree(lis3->reg_cache); + return 0; +} +EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); + +static void lis3lv02d_8b_configure(struct lis3lv02d *dev, + struct lis3lv02d_platform_data *p) +{ + int err; + int ctrl2 = p->hipass_ctrl; + + if (p->click_flags) { + dev->write(dev, CLICK_CFG, p->click_flags); + dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); + dev->write(dev, CLICK_LATENCY, p->click_latency); + dev->write(dev, CLICK_WINDOW, p->click_window); + dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); + dev->write(dev, CLICK_THSY_X, + (p->click_thresh_x & 0xf) | + (p->click_thresh_y << 4)); + + if (dev->idev) { + struct input_dev *input_dev = lis3_dev.idev->input; + input_set_capability(input_dev, EV_KEY, BTN_X); + input_set_capability(input_dev, EV_KEY, BTN_Y); + input_set_capability(input_dev, EV_KEY, BTN_Z); + } + } + + if (p->wakeup_flags) { + dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); + dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); + /* pdata value + 1 to keep this backward compatible*/ + dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1); + ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/ + } + + if (p->wakeup_flags2) { + dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2); + dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f); + /* pdata value + 1 to keep this backward compatible*/ + dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1); + ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/ + } + /* Configure hipass filters */ + dev->write(dev, CTRL_REG2, ctrl2); + + if (p->irq2) { + err = request_threaded_irq(p->irq2, + NULL, + lis302dl_interrupt_thread2_8b, + IRQF_TRIGGER_RISING | IRQF_ONESHOT | + (p->irq_flags2 & IRQF_TRIGGER_MASK), + DRIVER_NAME, &lis3_dev); + if (err < 0) + pr_err("No second IRQ. Limited functionality\n"); + } +} + +/* + * Initialise the accelerometer and the various subsystems. + * Should be rather independent of the bus system. + */ +int lis3lv02d_init_device(struct lis3lv02d *dev) +{ + int err; + irq_handler_t thread_fn; + int irq_flags = 0; + + dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); + + switch (dev->whoami) { + case WAI_12B: + pr_info("12 bits sensor found\n"); + dev->read_data = lis3lv02d_read_12; + dev->mdps_max_val = 2048; + dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B; + dev->odrs = lis3_12_rates; + dev->odr_mask = CTRL1_DF0 | CTRL1_DF1; + dev->scale = LIS3_SENSITIVITY_12B; + dev->regs = lis3_wai12_regs; + dev->regs_size = ARRAY_SIZE(lis3_wai12_regs); + break; + case WAI_8B: + pr_info("8 bits sensor found\n"); + dev->read_data = lis3lv02d_read_8; + dev->mdps_max_val = 128; + dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; + dev->odrs = lis3_8_rates; + dev->odr_mask = CTRL1_DR; + dev->scale = LIS3_SENSITIVITY_8B; + dev->regs = lis3_wai8_regs; + dev->regs_size = ARRAY_SIZE(lis3_wai8_regs); + break; + case WAI_3DC: + pr_info("8 bits 3DC sensor found\n"); + dev->read_data = lis3lv02d_read_8; + dev->mdps_max_val = 128; + dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; + dev->odrs = lis3_3dc_rates; + dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3; + dev->scale = LIS3_SENSITIVITY_8B; + break; + default: + pr_err("unknown sensor type 0x%X\n", dev->whoami); + return -EINVAL; + } + + dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), + sizeof(lis3_wai12_regs)), GFP_KERNEL); + + if (dev->reg_cache == NULL) { + printk(KERN_ERR DRIVER_NAME "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->mutex); + atomic_set(&dev->wake_thread, 0); + + lis3lv02d_add_fs(dev); + lis3lv02d_poweron(dev); + + if (dev->pm_dev) { + pm_runtime_set_active(dev->pm_dev); + pm_runtime_enable(dev->pm_dev); + } + + if (lis3lv02d_joystick_enable()) + pr_err("joystick initialization failed\n"); + + /* passing in platform specific data is purely optional and only + * used by the SPI transport layer at the moment */ + if (dev->pdata) { + struct lis3lv02d_platform_data *p = dev->pdata; + + if (dev->whoami == WAI_8B) + lis3lv02d_8b_configure(dev, p); + + irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK; + + dev->irq_cfg = p->irq_cfg; + if (p->irq_cfg) + dev->write(dev, CTRL_REG3, p->irq_cfg); + + if (p->default_rate) + lis3lv02d_set_odr(p->default_rate); + } + + /* bail if we did not get an IRQ from the bus layer */ + if (!dev->irq) { + pr_debug("No IRQ. Disabling /dev/freefall\n"); + goto out; + } + + /* + * The sensor can generate interrupts for free-fall and direction + * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep + * the things simple and _fast_ we activate it only for free-fall, so + * no need to read register (very slow with ACPI). For the same reason, + * we forbid shared interrupts. + * + * IRQF_TRIGGER_RISING seems pointless on HP laptops because the + * io-apic is not configurable (and generates a warning) but I keep it + * in case of support for other hardware. + */ + if (dev->pdata && dev->whoami == WAI_8B) + thread_fn = lis302dl_interrupt_thread1_8b; + else + thread_fn = NULL; + + err = request_threaded_irq(dev->irq, lis302dl_interrupt, + thread_fn, + IRQF_TRIGGER_RISING | IRQF_ONESHOT | + irq_flags, + DRIVER_NAME, &lis3_dev); + + if (err < 0) { + pr_err("Cannot get IRQ\n"); + goto out; + } + + if (misc_register(&lis3lv02d_misc_device)) + pr_err("misc_register failed\n"); +out: + return 0; +} +EXPORT_SYMBOL_GPL(lis3lv02d_init_device); + +MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); +MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h new file mode 100644 index 000000000000..a1939589eb2c --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d.h @@ -0,0 +1,291 @@ +/* + * lis3lv02d.h - ST LIS3LV02DL accelerometer driver + * + * Copyright (C) 2007-2008 Yan Burman + * Copyright (C) 2008-2009 Eric Piel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include + +/* + * This driver tries to support the "digital" accelerometer chips from + * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL, + * LIS35DE, or LIS202DL. They are very similar in terms of programming, with + * almost the same registers. In addition to differing on physical properties, + * they differ on the number of axes (2/3), precision (8/12 bits), and special + * features (freefall detection, click...). Unfortunately, not all the + * differences can be probed via a register. + * They can be connected either via I²C or SPI. + */ + +#include + +enum lis3_reg { + WHO_AM_I = 0x0F, + OFFSET_X = 0x16, + OFFSET_Y = 0x17, + OFFSET_Z = 0x18, + GAIN_X = 0x19, + GAIN_Y = 0x1A, + GAIN_Z = 0x1B, + CTRL_REG1 = 0x20, + CTRL_REG2 = 0x21, + CTRL_REG3 = 0x22, + CTRL_REG4 = 0x23, + HP_FILTER_RESET = 0x23, + STATUS_REG = 0x27, + OUTX_L = 0x28, + OUTX_H = 0x29, + OUTX = 0x29, + OUTY_L = 0x2A, + OUTY_H = 0x2B, + OUTY = 0x2B, + OUTZ_L = 0x2C, + OUTZ_H = 0x2D, + OUTZ = 0x2D, +}; + +enum lis302d_reg { + FF_WU_CFG_1 = 0x30, + FF_WU_SRC_1 = 0x31, + FF_WU_THS_1 = 0x32, + FF_WU_DURATION_1 = 0x33, + FF_WU_CFG_2 = 0x34, + FF_WU_SRC_2 = 0x35, + FF_WU_THS_2 = 0x36, + FF_WU_DURATION_2 = 0x37, + CLICK_CFG = 0x38, + CLICK_SRC = 0x39, + CLICK_THSY_X = 0x3B, + CLICK_THSZ = 0x3C, + CLICK_TIMELIMIT = 0x3D, + CLICK_LATENCY = 0x3E, + CLICK_WINDOW = 0x3F, +}; + +enum lis3lv02d_reg { + FF_WU_CFG = 0x30, + FF_WU_SRC = 0x31, + FF_WU_ACK = 0x32, + FF_WU_THS_L = 0x34, + FF_WU_THS_H = 0x35, + FF_WU_DURATION = 0x36, + DD_CFG = 0x38, + DD_SRC = 0x39, + DD_ACK = 0x3A, + DD_THSI_L = 0x3C, + DD_THSI_H = 0x3D, + DD_THSE_L = 0x3E, + DD_THSE_H = 0x3F, +}; + +enum lis3_who_am_i { + WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */ + WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */ + WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */ + WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ +}; + +enum lis3lv02d_ctrl1_12b { + CTRL1_Xen = 0x01, + CTRL1_Yen = 0x02, + CTRL1_Zen = 0x04, + CTRL1_ST = 0x08, + CTRL1_DF0 = 0x10, + CTRL1_DF1 = 0x20, + CTRL1_PD0 = 0x40, + CTRL1_PD1 = 0x80, +}; + +/* Delta to ctrl1_12b version */ +enum lis3lv02d_ctrl1_8b { + CTRL1_STM = 0x08, + CTRL1_STP = 0x10, + CTRL1_FS = 0x20, + CTRL1_PD = 0x40, + CTRL1_DR = 0x80, +}; + +enum lis3lv02d_ctrl1_3dc { + CTRL1_ODR0 = 0x10, + CTRL1_ODR1 = 0x20, + CTRL1_ODR2 = 0x40, + CTRL1_ODR3 = 0x80, +}; + +enum lis3lv02d_ctrl2 { + CTRL2_DAS = 0x01, + CTRL2_SIM = 0x02, + CTRL2_DRDY = 0x04, + CTRL2_IEN = 0x08, + CTRL2_BOOT = 0x10, + CTRL2_BLE = 0x20, + CTRL2_BDU = 0x40, /* Block Data Update */ + CTRL2_FS = 0x80, /* Full Scale selection */ +}; + +enum lis3lv02d_ctrl4_3dc { + CTRL4_SIM = 0x01, + CTRL4_ST0 = 0x02, + CTRL4_ST1 = 0x04, + CTRL4_FS0 = 0x10, + CTRL4_FS1 = 0x20, +}; + +enum lis302d_ctrl2 { + HP_FF_WU2 = 0x08, + HP_FF_WU1 = 0x04, + CTRL2_BOOT_8B = 0x40, +}; + +enum lis3lv02d_ctrl3 { + CTRL3_CFS0 = 0x01, + CTRL3_CFS1 = 0x02, + CTRL3_FDS = 0x10, + CTRL3_HPFF = 0x20, + CTRL3_HPDD = 0x40, + CTRL3_ECK = 0x80, +}; + +enum lis3lv02d_status_reg { + STATUS_XDA = 0x01, + STATUS_YDA = 0x02, + STATUS_ZDA = 0x04, + STATUS_XYZDA = 0x08, + STATUS_XOR = 0x10, + STATUS_YOR = 0x20, + STATUS_ZOR = 0x40, + STATUS_XYZOR = 0x80, +}; + +enum lis3lv02d_ff_wu_cfg { + FF_WU_CFG_XLIE = 0x01, + FF_WU_CFG_XHIE = 0x02, + FF_WU_CFG_YLIE = 0x04, + FF_WU_CFG_YHIE = 0x08, + FF_WU_CFG_ZLIE = 0x10, + FF_WU_CFG_ZHIE = 0x20, + FF_WU_CFG_LIR = 0x40, + FF_WU_CFG_AOI = 0x80, +}; + +enum lis3lv02d_ff_wu_src { + FF_WU_SRC_XL = 0x01, + FF_WU_SRC_XH = 0x02, + FF_WU_SRC_YL = 0x04, + FF_WU_SRC_YH = 0x08, + FF_WU_SRC_ZL = 0x10, + FF_WU_SRC_ZH = 0x20, + FF_WU_SRC_IA = 0x40, +}; + +enum lis3lv02d_dd_cfg { + DD_CFG_XLIE = 0x01, + DD_CFG_XHIE = 0x02, + DD_CFG_YLIE = 0x04, + DD_CFG_YHIE = 0x08, + DD_CFG_ZLIE = 0x10, + DD_CFG_ZHIE = 0x20, + DD_CFG_LIR = 0x40, + DD_CFG_IEND = 0x80, +}; + +enum lis3lv02d_dd_src { + DD_SRC_XL = 0x01, + DD_SRC_XH = 0x02, + DD_SRC_YL = 0x04, + DD_SRC_YH = 0x08, + DD_SRC_ZL = 0x10, + DD_SRC_ZH = 0x20, + DD_SRC_IA = 0x40, +}; + +enum lis3lv02d_click_src_8b { + CLICK_SINGLE_X = 0x01, + CLICK_DOUBLE_X = 0x02, + CLICK_SINGLE_Y = 0x04, + CLICK_DOUBLE_Y = 0x08, + CLICK_SINGLE_Z = 0x10, + CLICK_DOUBLE_Z = 0x20, + CLICK_IA = 0x40, +}; + +enum lis3lv02d_reg_state { + LIS3_REG_OFF = 0x00, + LIS3_REG_ON = 0x01, +}; + +union axis_conversion { + struct { + int x, y, z; + }; + int as_array[3]; + +}; + +struct lis3lv02d { + void *bus_priv; /* used by the bus layer only */ + struct device *pm_dev; /* for pm_runtime purposes */ + int (*init) (struct lis3lv02d *lis3); + int (*write) (struct lis3lv02d *lis3, int reg, u8 val); + int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret); + int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret); + int (*reg_ctrl) (struct lis3lv02d *lis3, bool state); + + int *odrs; /* Supported output data rates */ + u8 *regs; /* Regs to store / restore */ + int regs_size; + u8 *reg_cache; + bool regs_stored; + u8 odr_mask; /* ODR bit mask */ + u8 whoami; /* indicates measurement precision */ + s16 (*read_data) (struct lis3lv02d *lis3, int reg); + int mdps_max_val; + int pwron_delay; + int scale; /* + * relationship between 1 LBS and mG + * (1/1000th of earth gravity) + */ + + struct input_polled_dev *idev; /* input device */ + struct platform_device *pdev; /* platform device */ + struct regulator_bulk_data regulators[2]; + atomic_t count; /* interrupt count after last read */ + union axis_conversion ac; /* hw -> logical axis */ + int mapped_btns[3]; + + u32 irq; /* IRQ number */ + struct fasync_struct *async_queue; /* queue for the misc device */ + wait_queue_head_t misc_wait; /* Wait queue for the misc device */ + unsigned long misc_opened; /* bit0: whether the device is open */ + int data_ready_count[2]; + atomic_t wake_thread; + unsigned char irq_cfg; + + struct lis3lv02d_platform_data *pdata; /* for passing board config */ + struct mutex mutex; /* Serialize poll and selftest */ +}; + +int lis3lv02d_init_device(struct lis3lv02d *lis3); +int lis3lv02d_joystick_enable(void); +void lis3lv02d_joystick_disable(void); +void lis3lv02d_poweroff(struct lis3lv02d *lis3); +void lis3lv02d_poweron(struct lis3lv02d *lis3); +int lis3lv02d_remove_fs(struct lis3lv02d *lis3); + +extern struct lis3lv02d lis3_dev; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c new file mode 100644 index 000000000000..b20dfb4522d2 --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -0,0 +1,279 @@ +/* + * drivers/hwmon/lis3lv02d_i2c.c + * + * Implements I2C interface for lis3lv02d (STMicroelectronics) accelerometer. + * Driver is based on corresponding SPI driver written by Daniel Mack + * (lis3lv02d_spi.c (C) 2009 Daniel Mack ). + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: Samu Onkalo + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include "lis3lv02d.h" + +#define DRV_NAME "lis3lv02d_i2c" + +static const char reg_vdd[] = "Vdd"; +static const char reg_vdd_io[] = "Vdd_IO"; + +static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state) +{ + int ret; + if (state == LIS3_REG_OFF) { + ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators), + lis3->regulators); + } else { + ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators), + lis3->regulators); + /* Chip needs time to wakeup. Not mentioned in datasheet */ + usleep_range(10000, 20000); + } + return ret; +} + +static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value) +{ + struct i2c_client *c = lis3->bus_priv; + return i2c_smbus_write_byte_data(c, reg, value); +} + +static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v) +{ + struct i2c_client *c = lis3->bus_priv; + *v = i2c_smbus_read_byte_data(c, reg); + return 0; +} + +static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len, + u8 *v) +{ + struct i2c_client *c = lis3->bus_priv; + reg |= (1 << 7); /* 7th bit enables address auto incrementation */ + return i2c_smbus_read_i2c_block_data(c, reg, len, v); +} + +static int lis3_i2c_init(struct lis3lv02d *lis3) +{ + u8 reg; + int ret; + + if (lis3->reg_ctrl) + lis3_reg_ctrl(lis3, LIS3_REG_ON); + + lis3->read(lis3, WHO_AM_I, ®); + if (reg != lis3->whoami) + printk(KERN_ERR "lis3: power on failure\n"); + + /* power up the device */ + ret = lis3->read(lis3, CTRL_REG1, ®); + if (ret < 0) + return ret; + + reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + return lis3->write(lis3, CTRL_REG1, reg); +} + +/* Default axis mapping but it can be overwritten by platform data */ +static union axis_conversion lis3lv02d_axis_map = + { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } }; + +static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct lis3lv02d_platform_data *pdata = client->dev.platform_data; + + if (pdata) { + /* Regulator control is optional */ + if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL) + lis3_dev.reg_ctrl = lis3_reg_ctrl; + + if ((pdata->driver_features & LIS3_USE_BLOCK_READ) && + (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK))) + lis3_dev.blkread = lis3_i2c_blockread; + + if (pdata->axis_x) + lis3lv02d_axis_map.x = pdata->axis_x; + + if (pdata->axis_y) + lis3lv02d_axis_map.y = pdata->axis_y; + + if (pdata->axis_z) + lis3lv02d_axis_map.z = pdata->axis_z; + + if (pdata->setup_resources) + ret = pdata->setup_resources(); + + if (ret) + goto fail; + } + + if (lis3_dev.reg_ctrl) { + lis3_dev.regulators[0].supply = reg_vdd; + lis3_dev.regulators[1].supply = reg_vdd_io; + ret = regulator_bulk_get(&client->dev, + ARRAY_SIZE(lis3_dev.regulators), + lis3_dev.regulators); + if (ret < 0) + goto fail; + } + + lis3_dev.pdata = pdata; + lis3_dev.bus_priv = client; + lis3_dev.init = lis3_i2c_init; + lis3_dev.read = lis3_i2c_read; + lis3_dev.write = lis3_i2c_write; + lis3_dev.irq = client->irq; + lis3_dev.ac = lis3lv02d_axis_map; + lis3_dev.pm_dev = &client->dev; + + i2c_set_clientdata(client, &lis3_dev); + + /* Provide power over the init call */ + if (lis3_dev.reg_ctrl) + lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON); + + ret = lis3lv02d_init_device(&lis3_dev); + + if (lis3_dev.reg_ctrl) + lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF); + + if (ret == 0) + return 0; +fail: + if (pdata && pdata->release_resources) + pdata->release_resources(); + return ret; +} + +static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) +{ + struct lis3lv02d *lis3 = i2c_get_clientdata(client); + struct lis3lv02d_platform_data *pdata = client->dev.platform_data; + + if (pdata && pdata->release_resources) + pdata->release_resources(); + + lis3lv02d_joystick_disable(); + lis3lv02d_remove_fs(&lis3_dev); + + if (lis3_dev.reg_ctrl) + regulator_bulk_free(ARRAY_SIZE(lis3->regulators), + lis3_dev.regulators); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int lis3lv02d_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct lis3lv02d *lis3 = i2c_get_clientdata(client); + + if (!lis3->pdata || !lis3->pdata->wakeup_flags) + lis3lv02d_poweroff(lis3); + return 0; +} + +static int lis3lv02d_i2c_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct lis3lv02d *lis3 = i2c_get_clientdata(client); + + /* + * pm_runtime documentation says that devices should always + * be powered on at resume. Pm_runtime turns them off after system + * wide resume is complete. + */ + if (!lis3->pdata || !lis3->pdata->wakeup_flags || + pm_runtime_suspended(dev)) + lis3lv02d_poweron(lis3); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_RUNTIME +static int lis3_i2c_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct lis3lv02d *lis3 = i2c_get_clientdata(client); + + lis3lv02d_poweroff(lis3); + return 0; +} + +static int lis3_i2c_runtime_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct lis3lv02d *lis3 = i2c_get_clientdata(client); + + lis3lv02d_poweron(lis3); + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +static const struct i2c_device_id lis3lv02d_id[] = { + {"lis3lv02d", 0 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lis3lv02d_id); + +static const struct dev_pm_ops lis3_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend, + lis3lv02d_i2c_resume) + SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend, + lis3_i2c_runtime_resume, + NULL) +}; + +static struct i2c_driver lis3lv02d_i2c_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &lis3_pm_ops, + }, + .probe = lis3lv02d_i2c_probe, + .remove = __devexit_p(lis3lv02d_i2c_remove), + .id_table = lis3lv02d_id, +}; + +static int __init lis3lv02d_init(void) +{ + return i2c_add_driver(&lis3lv02d_i2c_driver); +} + +static void __exit lis3lv02d_exit(void) +{ + i2c_del_driver(&lis3lv02d_i2c_driver); +} + +MODULE_AUTHOR("Nokia Corporation"); +MODULE_DESCRIPTION("lis3lv02d I2C interface"); +MODULE_LICENSE("GPL"); + +module_init(lis3lv02d_init); +module_exit(lis3lv02d_exit); diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c new file mode 100644 index 000000000000..c1f8a8fbf694 --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -0,0 +1,145 @@ +/* + * lis3lv02d_spi - SPI glue layer for lis3lv02d + * + * Copyright (c) 2009 Daniel Mack + * + * 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 + * publishhed by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lis3lv02d.h" + +#define DRV_NAME "lis3lv02d_spi" +#define LIS3_SPI_READ 0x80 + +static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) +{ + struct spi_device *spi = lis3->bus_priv; + int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); + if (ret < 0) + return -EINVAL; + + *v = (u8) ret; + return 0; +} + +static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) +{ + u8 tmp[2] = { reg, val }; + struct spi_device *spi = lis3->bus_priv; + return spi_write(spi, tmp, sizeof(tmp)); +} + +static int lis3_spi_init(struct lis3lv02d *lis3) +{ + u8 reg; + int ret; + + /* power up the device */ + ret = lis3->read(lis3, CTRL_REG1, ®); + if (ret < 0) + return ret; + + reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; + return lis3->write(lis3, CTRL_REG1, reg); +} + +static union axis_conversion lis3lv02d_axis_normal = + { .as_array = { 1, 2, 3 } }; + +static int __devinit lis302dl_spi_probe(struct spi_device *spi) +{ + int ret; + + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + ret = spi_setup(spi); + if (ret < 0) + return ret; + + lis3_dev.bus_priv = spi; + lis3_dev.init = lis3_spi_init; + lis3_dev.read = lis3_spi_read; + lis3_dev.write = lis3_spi_write; + lis3_dev.irq = spi->irq; + lis3_dev.ac = lis3lv02d_axis_normal; + lis3_dev.pdata = spi->dev.platform_data; + spi_set_drvdata(spi, &lis3_dev); + + return lis3lv02d_init_device(&lis3_dev); +} + +static int __devexit lis302dl_spi_remove(struct spi_device *spi) +{ + struct lis3lv02d *lis3 = spi_get_drvdata(spi); + lis3lv02d_joystick_disable(); + lis3lv02d_poweroff(lis3); + + return lis3lv02d_remove_fs(&lis3_dev); +} + +#ifdef CONFIG_PM_SLEEP +static int lis3lv02d_spi_suspend(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct lis3lv02d *lis3 = spi_get_drvdata(spi); + + if (!lis3->pdata || !lis3->pdata->wakeup_flags) + lis3lv02d_poweroff(&lis3_dev); + + return 0; +} + +static int lis3lv02d_spi_resume(struct device *dev) +{ + struct spi_device *spi = to_spi_device(dev); + struct lis3lv02d *lis3 = spi_get_drvdata(spi); + + if (!lis3->pdata || !lis3->pdata->wakeup_flags) + lis3lv02d_poweron(lis3); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend, + lis3lv02d_spi_resume); + +static struct spi_driver lis302dl_spi_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &lis3lv02d_spi_pm, + }, + .probe = lis302dl_spi_probe, + .remove = __devexit_p(lis302dl_spi_remove), +}; + +static int __init lis302dl_init(void) +{ + return spi_register_driver(&lis302dl_spi_driver); +} + +static void __exit lis302dl_exit(void) +{ + spi_unregister_driver(&lis302dl_spi_driver); +} + +module_init(lis302dl_init); +module_exit(lis302dl_exit); + +MODULE_AUTHOR("Daniel Mack "); +MODULE_DESCRIPTION("lis3lv02d SPI glue layer"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c index 23f09c1b234b..0a52711a6362 100644 --- a/drivers/platform/x86/hp_accel.c +++ b/drivers/platform/x86/hp_accel.c @@ -37,7 +37,7 @@ #include #include #include -#include "../../hwmon/lis3lv02d.h" +#include "../../misc/lis3lv02d/lis3lv02d.h" #define DRIVER_NAME "lis3lv02d" #define ACPI_MDPS_CLASS "accelerometer" -- cgit v1.2.2 From 96b4b9bfea28e38c38d26ca47e82ac0fbe2f28b6 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: hp_accel: Fix driver name I suspect that the "lis3lv02d" driver name is a legacy from before the split into several modules. Use a specific name for the hp_accel driver, for better error messages and easier investigation of issues. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck Acked-by: Eric Piel Acked-by: Jonathan Cameron Tested-by: Eric Piel Tested-by: Takashi Iwai --- drivers/platform/x86/hp_accel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c index 0a52711a6362..1b52d00e2f90 100644 --- a/drivers/platform/x86/hp_accel.c +++ b/drivers/platform/x86/hp_accel.c @@ -39,7 +39,7 @@ #include #include "../../misc/lis3lv02d/lis3lv02d.h" -#define DRIVER_NAME "lis3lv02d" +#define DRIVER_NAME "hp_accel" #define ACPI_MDPS_CLASS "accelerometer" /* Delayed LEDs infrastructure ------------------------------------ */ -- cgit v1.2.2 From 05e82fe40faee8499b4e3ba12fddaaf013d84203 Mon Sep 17 00:00:00 2001 From: Len Sorensen Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: hwmon: (lm75) Add detection of the National Semiconductor LM75A Add support for detection of the National Semiconductor LM75A using the ID register value. Signed-off-by: Len Sorensen Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/lm75.c | 56 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 47621abb9a05..19d72bcf966a 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -521,7 +521,7 @@ config SENSORS_LM75 - Dallas Semiconductor DS75 and DS1775 - Maxim MAX6625 and MAX6626 - Microchip MCP980x - - National Semiconductor LM75 + - National Semiconductor LM75, LM75A - NXP's LM75A - ST Microelectronics STDS75 - TelCom (now Microchip) TCN75 diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index f36eb80d227f..638dd0586e3f 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -232,6 +232,8 @@ static const struct i2c_device_id lm75_ids[] = { }; MODULE_DEVICE_TABLE(i2c, lm75_ids); +#define LM75A_ID 0xA1 + /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm75_detect(struct i2c_client *new_client, struct i2c_board_info *info) @@ -239,6 +241,7 @@ static int lm75_detect(struct i2c_client *new_client, struct i2c_adapter *adapter = new_client->adapter; int i; int cur, conf, hyst, os; + bool is_lm75a = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) @@ -250,23 +253,43 @@ static int lm75_detect(struct i2c_client *new_client, addresses 0x04-0x07 returning the last read value. The cycling+unused addresses combination is not tested, since it would significantly slow the detection down and would - hardly add any value. */ + hardly add any value. + + The National Semiconductor LM75A is different than earlier + LM75s. It has an ID byte of 0xaX (where X is the chip + revision, with 1 being the only revision in existence) in + register 7, and unused registers return 0xff rather than the + last read value. */ - /* Unused addresses */ cur = i2c_smbus_read_word_data(new_client, 0); conf = i2c_smbus_read_byte_data(new_client, 1); - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 4) != hyst - || i2c_smbus_read_word_data(new_client, 5) != hyst - || i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) - return -ENODEV; - os = i2c_smbus_read_word_data(new_client, 3); - if (i2c_smbus_read_word_data(new_client, 4) != os - || i2c_smbus_read_word_data(new_client, 5) != os - || i2c_smbus_read_word_data(new_client, 6) != os - || i2c_smbus_read_word_data(new_client, 7) != os) - return -ENODEV; + + /* First check for LM75A */ + if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { + /* LM75A returns 0xff on unused registers so + just to be sure we check for that too. */ + if (i2c_smbus_read_byte_data(new_client, 4) != 0xff + || i2c_smbus_read_byte_data(new_client, 5) != 0xff + || i2c_smbus_read_byte_data(new_client, 6) != 0xff) + return -ENODEV; + is_lm75a = 1; + hyst = i2c_smbus_read_word_data(new_client, 2); + os = i2c_smbus_read_word_data(new_client, 3); + } else { /* Traditional style LM75 detection */ + /* Unused addresses */ + hyst = i2c_smbus_read_word_data(new_client, 2); + if (i2c_smbus_read_word_data(new_client, 4) != hyst + || i2c_smbus_read_word_data(new_client, 5) != hyst + || i2c_smbus_read_word_data(new_client, 6) != hyst + || i2c_smbus_read_word_data(new_client, 7) != hyst) + return -ENODEV; + os = i2c_smbus_read_word_data(new_client, 3); + if (i2c_smbus_read_word_data(new_client, 4) != os + || i2c_smbus_read_word_data(new_client, 5) != os + || i2c_smbus_read_word_data(new_client, 6) != os + || i2c_smbus_read_word_data(new_client, 7) != os) + return -ENODEV; + } /* Unused bits */ if (conf & 0xe0) @@ -278,9 +301,12 @@ static int lm75_detect(struct i2c_client *new_client, || i2c_smbus_read_word_data(new_client, i + 2) != hyst || i2c_smbus_read_word_data(new_client, i + 3) != os) return -ENODEV; + if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) + != LM75A_ID) + return -ENODEV; } - strlcpy(info->type, "lm75", I2C_NAME_SIZE); + strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE); return 0; } -- cgit v1.2.2 From e76f67b5babc65cd620d395a1fd231409808df90 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: hwmon: (lm75) Speed up detection Make the LM75/LM75A device detection faster: * Don't read the current temperature value when we don't use it. * Check for unused bits in the configuration register as soon as we have read its value. * Don't use word reads, not all devices support this, and some which don't misbehave when you try. * Check for cycling register values every 40 register addresses instead of every 8, it's 5 times faster and just as efficient. Some of these improvements come straight from the user-space sensors-detect script, so both detection routines are in line now. Signed-off-by: Jean Delvare Cc: Len Sorensen Acked-by: Guenter Roeck --- drivers/hwmon/lm75.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 638dd0586e3f..ef902d5d06ab 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -240,7 +240,7 @@ static int lm75_detect(struct i2c_client *new_client, { struct i2c_adapter *adapter = new_client->adapter; int i; - int cur, conf, hyst, os; + int conf, hyst, os; bool is_lm75a = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | @@ -261,8 +261,10 @@ static int lm75_detect(struct i2c_client *new_client, register 7, and unused registers return 0xff rather than the last read value. */ - cur = i2c_smbus_read_word_data(new_client, 0); + /* Unused bits */ conf = i2c_smbus_read_byte_data(new_client, 1); + if (conf & 0xe0) + return -ENODEV; /* First check for LM75A */ if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) { @@ -273,33 +275,29 @@ static int lm75_detect(struct i2c_client *new_client, || i2c_smbus_read_byte_data(new_client, 6) != 0xff) return -ENODEV; is_lm75a = 1; - hyst = i2c_smbus_read_word_data(new_client, 2); - os = i2c_smbus_read_word_data(new_client, 3); + hyst = i2c_smbus_read_byte_data(new_client, 2); + os = i2c_smbus_read_byte_data(new_client, 3); } else { /* Traditional style LM75 detection */ /* Unused addresses */ - hyst = i2c_smbus_read_word_data(new_client, 2); - if (i2c_smbus_read_word_data(new_client, 4) != hyst - || i2c_smbus_read_word_data(new_client, 5) != hyst - || i2c_smbus_read_word_data(new_client, 6) != hyst - || i2c_smbus_read_word_data(new_client, 7) != hyst) + hyst = i2c_smbus_read_byte_data(new_client, 2); + if (i2c_smbus_read_byte_data(new_client, 4) != hyst + || i2c_smbus_read_byte_data(new_client, 5) != hyst + || i2c_smbus_read_byte_data(new_client, 6) != hyst + || i2c_smbus_read_byte_data(new_client, 7) != hyst) return -ENODEV; - os = i2c_smbus_read_word_data(new_client, 3); - if (i2c_smbus_read_word_data(new_client, 4) != os - || i2c_smbus_read_word_data(new_client, 5) != os - || i2c_smbus_read_word_data(new_client, 6) != os - || i2c_smbus_read_word_data(new_client, 7) != os) + os = i2c_smbus_read_byte_data(new_client, 3); + if (i2c_smbus_read_byte_data(new_client, 4) != os + || i2c_smbus_read_byte_data(new_client, 5) != os + || i2c_smbus_read_byte_data(new_client, 6) != os + || i2c_smbus_read_byte_data(new_client, 7) != os) return -ENODEV; } - /* Unused bits */ - if (conf & 0xe0) - return -ENODEV; - /* Addresses cycling */ - for (i = 8; i < 0xff; i += 8) { + for (i = 8; i <= 248; i += 40) { if (i2c_smbus_read_byte_data(new_client, i + 1) != conf - || i2c_smbus_read_word_data(new_client, i + 2) != hyst - || i2c_smbus_read_word_data(new_client, i + 3) != os) + || i2c_smbus_read_byte_data(new_client, i + 2) != hyst + || i2c_smbus_read_byte_data(new_client, i + 3) != os) return -ENODEV; if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7) != LM75A_ID) -- cgit v1.2.2 From 93d0cc588345a9de304285781e010e298f74e06e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: hwmon: (abituguru*) Update my email address Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare --- drivers/hwmon/abituguru.c | 4 ++-- drivers/hwmon/abituguru3.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 8f07a9dda152..0e05aa179eaa 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1,5 +1,5 @@ /* - abituguru.c Copyright (c) 2005-2006 Hans de Goede + abituguru.c Copyright (c) 2005-2006 Hans de Goede 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 @@ -1505,7 +1505,7 @@ static void __exit abituguru_exit(void) platform_driver_unregister(&abituguru_driver); } -MODULE_AUTHOR("Hans de Goede "); +MODULE_AUTHOR("Hans de Goede "); MODULE_DESCRIPTION("Abit uGuru Sensor device"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 48d21e22e930..034cebfcd273 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -1,7 +1,7 @@ /* abituguru3.c - Copyright (c) 2006-2008 Hans de Goede + Copyright (c) 2006-2008 Hans de Goede Copyright (c) 2008 Alistair John Strachan This program is free software; you can redistribute it and/or modify @@ -1266,7 +1266,7 @@ static void __exit abituguru3_exit(void) platform_driver_unregister(&abituguru3_driver); } -MODULE_AUTHOR("Hans de Goede "); +MODULE_AUTHOR("Hans de Goede "); MODULE_DESCRIPTION("Abit uGuru3 Sensor device"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From a98d506c08ffe754fa013c7f70c4d578b991fb4b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: hwmon: New driver for SMSC SCH5627 SMSC SCH5627 Super I/O chips include complete hardware monitoring capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures. The hardware monitoring part of the SMSC SCH5627 is accessed by talking through an embedded microcontroller. An application note describing the protocol for communicating with the microcontroller is available upon request. Please mail me if you want a copy. Signed-off-by: Hans de Goede Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 9 + drivers/hwmon/Makefile | 1 + drivers/hwmon/sch5627.c | 858 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 868 insertions(+) create mode 100644 drivers/hwmon/sch5627.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 19d72bcf966a..6fad9f082f67 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -959,6 +959,15 @@ config SENSORS_SMSC47B397 This driver can also be built as a module. If so, the module will be called smsc47b397. +config SENSORS_SCH5627 + tristate "SMSC SCH5627" + help + If you say yes here you get support for the hardware monitoring + features of the SMSC SCH5627 Super-I/O chip. + + This driver can also be built as a module. If so, the module + will be called sch5627. + config SENSORS_ADS7828 tristate "Texas Instruments ADS7828" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index c068f82082cd..4d0122c52219 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -90,6 +90,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o +obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SHT21) += sht21.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c new file mode 100644 index 000000000000..9a51dcca9b0d --- /dev/null +++ b/drivers/hwmon/sch5627.c @@ -0,0 +1,858 @@ +/*************************************************************************** + * Copyright (C) 2010-2011 Hans de Goede * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "sch5627" +#define DEVNAME DRVNAME /* We only support one model */ + +#define SIO_SCH5627_EM_LD 0x0C /* Embedded Microcontroller LD */ +#define SIO_UNLOCK_KEY 0x55 /* Key to enable Super-I/O */ +#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x66 /* Logical device address (2 bytes) */ + +#define SIO_SCH5627_ID 0xC6 /* Chipset ID */ + +#define REGION_LENGTH 9 + +#define SCH5627_HWMON_ID 0xa5 +#define SCH5627_COMPANY_ID 0x5c +#define SCH5627_PRIMARY_ID 0xa0 + +#define SCH5627_REG_BUILD_CODE 0x39 +#define SCH5627_REG_BUILD_ID 0x3a +#define SCH5627_REG_HWMON_ID 0x3c +#define SCH5627_REG_HWMON_REV 0x3d +#define SCH5627_REG_COMPANY_ID 0x3e +#define SCH5627_REG_PRIMARY_ID 0x3f +#define SCH5627_REG_CTRL 0x40 + +#define SCH5627_NO_TEMPS 8 +#define SCH5627_NO_FANS 4 +#define SCH5627_NO_IN 5 + +static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = { + 0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 }; +static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = { + 0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 }; +static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = { + 0, 0, 1, 1, 0, 0, 0, 1 }; +static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = { + 0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 }; +static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = { + 0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 }; + +static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = { + 0x2C, 0x2E, 0x30, 0x32 }; +static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = { + 0x62, 0x64, 0x66, 0x68 }; + +static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = { + 0x22, 0x23, 0x24, 0x25, 0x189 }; +static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = { + 0xE4, 0xE4, 0xE3, 0xE3, 0x18A }; +static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = { + 1, 0, 1, 0, 1 }; +static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = { + 10745, 3660, 9765, 10745, 3660 }; +static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = { + "VCC", "VTT", "VBAT", "VTR", "V_IN" }; + +struct sch5627_data { + unsigned short addr; + struct device *hwmon_dev; + u8 temp_max[SCH5627_NO_TEMPS]; + u8 temp_crit[SCH5627_NO_TEMPS]; + u16 fan_min[SCH5627_NO_FANS]; + + struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + u16 temp[SCH5627_NO_TEMPS]; + u16 fan[SCH5627_NO_FANS]; + u16 in[SCH5627_NO_IN]; +}; + +static struct platform_device *sch5627_pdev; + +/* Super I/O functions */ +static inline int superio_inb(int base, int reg) +{ + outb(reg, base); + return inb(base + 1); +} + +static inline int superio_enter(int base) +{ + /* Don't step on other drivers' I/O space by accident */ + if (!request_muxed_region(base, 2, DRVNAME)) { + pr_err("I/O address 0x%04x already in use\n", base); + return -EBUSY; + } + + outb(SIO_UNLOCK_KEY, base); + + return 0; +} + +static inline void superio_select(int base, int ld) +{ + outb(SIO_REG_LDSEL, base); + outb(ld, base + 1); +} + +static inline void superio_exit(int base) +{ + outb(SIO_LOCK_KEY, base); + release_region(base, 2); +} + +static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg) +{ + u8 val; + int i; + /* + * According to SMSC for the commands we use the maximum time for + * the EM to respond is 15 ms, but testing shows in practice it + * responds within 15-32 reads, so we first busy poll, and if + * that fails sleep a bit and try again until we are way past + * the 15 ms maximum response time. + */ + const int max_busy_polls = 64; + const int max_lazy_polls = 32; + + /* (Optional) Write-Clear the EC to Host Mailbox Register */ + val = inb(data->addr + 1); + outb(val, data->addr + 1); + + /* Set Mailbox Address Pointer to first location in Region 1 */ + outb(0x00, data->addr + 2); + outb(0x80, data->addr + 3); + + /* Write Request Packet Header */ + outb(0x02, data->addr + 4); /* Access Type: VREG read */ + outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */ + outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */ + + /* Write Address field */ + outb(reg & 0xff, data->addr + 6); + outb(reg >> 8, data->addr + 7); + + /* Execute the Random Access Command */ + outb(0x01, data->addr); /* Write 01h to the Host-to-EC register */ + + /* EM Interface Polling "Algorithm" */ + for (i = 0; i < max_busy_polls + max_lazy_polls; i++) { + if (i >= max_busy_polls) + msleep(1); + /* Read Interrupt source Register */ + val = inb(data->addr + 8); + /* Write Clear the interrupt source bits */ + if (val) + outb(val, data->addr + 8); + /* Command Completed ? */ + if (val & 0x01) + break; + } + if (i == max_busy_polls + max_lazy_polls) { + pr_err("Max retries exceeded reading virtual " + "register 0x%04hx (%d)\n", reg, 1); + return -EIO; + } + + /* + * According to SMSC we may need to retry this, but sofar I've always + * seen this succeed in 1 try. + */ + for (i = 0; i < max_busy_polls; i++) { + /* Read EC-to-Host Register */ + val = inb(data->addr + 1); + /* Command Completed ? */ + if (val == 0x01) + break; + + if (i == 0) + pr_warn("EC reports: 0x%02x reading virtual register " + "0x%04hx\n", (unsigned int)val, reg); + } + if (i == max_busy_polls) { + pr_err("Max retries exceeded reading virtual " + "register 0x%04hx (%d)\n", reg, 2); + return -EIO; + } + + /* + * According to the SMSC app note we should now do: + * + * Set Mailbox Address Pointer to first location in Region 1 * + * outb(0x00, data->addr + 2); + * outb(0x80, data->addr + 3); + * + * But if we do that things don't work, so let's not. + */ + + /* Read Data from Mailbox */ + return inb(data->addr + 4); +} + +static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg) +{ + int lsb, msb; + + /* Read LSB first, this will cause the matching MSB to be latched */ + lsb = sch5627_read_virtual_reg(data, reg); + if (lsb < 0) + return lsb; + + msb = sch5627_read_virtual_reg(data, reg + 1); + if (msb < 0) + return msb; + + return lsb | (msb << 8); +} + +static int sch5627_read_virtual_reg12(struct sch5627_data *data, u16 msb_reg, + u16 lsn_reg, int high_nibble) +{ + int msb, lsn; + + /* Read MSB first, this will cause the matching LSN to be latched */ + msb = sch5627_read_virtual_reg(data, msb_reg); + if (msb < 0) + return msb; + + lsn = sch5627_read_virtual_reg(data, lsn_reg); + if (lsn < 0) + return lsn; + + if (high_nibble) + return (msb << 4) | (lsn >> 4); + else + return (msb << 4) | (lsn & 0x0f); +} + +static struct sch5627_data *sch5627_update_device(struct device *dev) +{ + struct sch5627_data *data = dev_get_drvdata(dev); + struct sch5627_data *ret = data; + int i, val; + + mutex_lock(&data->update_lock); + + /* Cache the values for 1 second */ + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + for (i = 0; i < SCH5627_NO_TEMPS; i++) { + val = sch5627_read_virtual_reg12(data, + SCH5627_REG_TEMP_MSB[i], + SCH5627_REG_TEMP_LSN[i], + SCH5627_REG_TEMP_HIGH_NIBBLE[i]); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + data->temp[i] = val; + } + + for (i = 0; i < SCH5627_NO_FANS; i++) { + val = sch5627_read_virtual_reg16(data, + SCH5627_REG_FAN[i]); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + data->fan[i] = val; + } + + for (i = 0; i < SCH5627_NO_IN; i++) { + val = sch5627_read_virtual_reg12(data, + SCH5627_REG_IN_MSB[i], + SCH5627_REG_IN_LSN[i], + SCH5627_REG_IN_HIGH_NIBBLE[i]); + if (unlikely(val < 0)) { + ret = ERR_PTR(val); + goto abort; + } + data->in[i] = val; + } + + data->last_updated = jiffies; + data->valid = 1; + } +abort: + mutex_unlock(&data->update_lock); + return ret; +} + +static int __devinit sch5627_read_limits(struct sch5627_data *data) +{ + int i, val; + + for (i = 0; i < SCH5627_NO_TEMPS; i++) { + /* + * Note what SMSC calls ABS, is what lm_sensors calls max + * (aka high), and HIGH is what lm_sensors calls crit. + */ + val = sch5627_read_virtual_reg(data, SCH5627_REG_TEMP_ABS[i]); + if (val < 0) + return val; + data->temp_max[i] = val; + + val = sch5627_read_virtual_reg(data, SCH5627_REG_TEMP_HIGH[i]); + if (val < 0) + return val; + data->temp_crit[i] = val; + } + for (i = 0; i < SCH5627_NO_FANS; i++) { + val = sch5627_read_virtual_reg16(data, SCH5627_REG_FAN_MIN[i]); + if (val < 0) + return val; + data->fan_min[i] = val; + } + + return 0; +} + +static int reg_to_temp(u16 reg) +{ + return (reg * 625) / 10 - 64000; +} + +static int reg_to_temp_limit(u8 reg) +{ + return (reg - 64) * 1000; +} + +static int reg_to_rpm(u16 reg) +{ + if (reg == 0) + return -EIO; + if (reg == 0xffff) + return 0; + + return 5400540 / reg; +} + +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = sch5627_update_device(dev); + int val; + + if (IS_ERR(data)) + return PTR_ERR(data); + + val = reg_to_temp(data->temp[attr->index]); + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t show_temp_fault(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = sch5627_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return snprintf(buf, PAGE_SIZE, "%d\n", data->temp[attr->index] == 0); +} + +static ssize_t show_temp_max(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = dev_get_drvdata(dev); + int val; + + val = reg_to_temp_limit(data->temp_max[attr->index]); + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t show_temp_crit(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = dev_get_drvdata(dev); + int val; + + val = reg_to_temp_limit(data->temp_crit[attr->index]); + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t show_fan(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = sch5627_update_device(dev); + int val; + + if (IS_ERR(data)) + return PTR_ERR(data); + + val = reg_to_rpm(data->fan[attr->index]); + if (val < 0) + return val; + + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t show_fan_fault(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = sch5627_update_device(dev); + + if (IS_ERR(data)) + return PTR_ERR(data); + + return snprintf(buf, PAGE_SIZE, "%d\n", + data->fan[attr->index] == 0xffff); +} + +static ssize_t show_fan_min(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = dev_get_drvdata(dev); + int val = reg_to_rpm(data->fan_min[attr->index]); + if (val < 0) + return val; + + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t show_in(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct sch5627_data *data = sch5627_update_device(dev); + int val; + + if (IS_ERR(data)) + return PTR_ERR(data); + + val = DIV_ROUND_CLOSEST( + data->in[attr->index] * SCH5627_REG_IN_FACTOR[attr->index], + 10000); + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t show_in_label(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return snprintf(buf, PAGE_SIZE, "%s\n", + SCH5627_IN_LABELS[attr->index]); +} + +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7); +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_temp_fault, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_temp_fault, NULL, 7); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_max, S_IRUGO, show_temp_max, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_max, S_IRUGO, show_temp_max, NULL, 7); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_crit, S_IRUGO, show_temp_crit, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_crit, S_IRUGO, show_temp_crit, NULL, 7); + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); +static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3); +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan_min, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan_min, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO, show_fan_min, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_min, S_IRUGO, show_fan_min, NULL, 3); + +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4); +static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_in_label, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_in_label, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_in_label, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_in_label, NULL, 3); + +static struct attribute *sch5627_attributes[] = { + &dev_attr_name.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, + &sensor_dev_attr_temp5_fault.dev_attr.attr, + &sensor_dev_attr_temp6_fault.dev_attr.attr, + &sensor_dev_attr_temp7_fault.dev_attr.attr, + &sensor_dev_attr_temp8_fault.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + &sensor_dev_attr_temp6_max.dev_attr.attr, + &sensor_dev_attr_temp7_max.dev_attr.attr, + &sensor_dev_attr_temp8_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &sensor_dev_attr_temp4_crit.dev_attr.attr, + &sensor_dev_attr_temp5_crit.dev_attr.attr, + &sensor_dev_attr_temp6_crit.dev_attr.attr, + &sensor_dev_attr_temp7_crit.dev_attr.attr, + &sensor_dev_attr_temp8_crit.dev_attr.attr, + + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan1_fault.dev_attr.attr, + &sensor_dev_attr_fan2_fault.dev_attr.attr, + &sensor_dev_attr_fan3_fault.dev_attr.attr, + &sensor_dev_attr_fan4_fault.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in0_label.dev_attr.attr, + &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_in2_label.dev_attr.attr, + &sensor_dev_attr_in3_label.dev_attr.attr, + /* No in4_label as in4 is a generic input pin */ + + NULL +}; + +static const struct attribute_group sch5627_group = { + .attrs = sch5627_attributes, +}; + +static int sch5627_remove(struct platform_device *pdev) +{ + struct sch5627_data *data = platform_get_drvdata(pdev); + + if (data->hwmon_dev) + hwmon_device_unregister(data->hwmon_dev); + + sysfs_remove_group(&pdev->dev.kobj, &sch5627_group); + platform_set_drvdata(pdev, NULL); + kfree(data); + + return 0; +} + +static int __devinit sch5627_probe(struct platform_device *pdev) +{ + struct sch5627_data *data; + int err, build_code, build_id, hwmon_rev, val; + + data = kzalloc(sizeof(struct sch5627_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; + mutex_init(&data->update_lock); + platform_set_drvdata(pdev, data); + + val = sch5627_read_virtual_reg(data, SCH5627_REG_HWMON_ID); + if (val < 0) { + err = val; + goto error; + } + if (val != SCH5627_HWMON_ID) { + pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon", + val, SCH5627_HWMON_ID); + err = -ENODEV; + goto error; + } + + val = sch5627_read_virtual_reg(data, SCH5627_REG_COMPANY_ID); + if (val < 0) { + err = val; + goto error; + } + if (val != SCH5627_COMPANY_ID) { + pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company", + val, SCH5627_COMPANY_ID); + err = -ENODEV; + goto error; + } + + val = sch5627_read_virtual_reg(data, SCH5627_REG_PRIMARY_ID); + if (val < 0) { + err = val; + goto error; + } + if (val != SCH5627_PRIMARY_ID) { + pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary", + val, SCH5627_PRIMARY_ID); + err = -ENODEV; + goto error; + } + + build_code = sch5627_read_virtual_reg(data, SCH5627_REG_BUILD_CODE); + if (build_code < 0) { + err = build_code; + goto error; + } + + build_id = sch5627_read_virtual_reg16(data, SCH5627_REG_BUILD_ID); + if (build_id < 0) { + err = build_id; + goto error; + } + + hwmon_rev = sch5627_read_virtual_reg(data, SCH5627_REG_HWMON_REV); + if (hwmon_rev < 0) { + err = hwmon_rev; + goto error; + } + + val = sch5627_read_virtual_reg(data, SCH5627_REG_CTRL); + if (val < 0) { + err = val; + goto error; + } + if (!(val & 0x01)) { + pr_err("hardware monitoring not enabled\n"); + err = -ENODEV; + goto error; + } + + /* + * Read limits, we do this only once as reading a register on + * the sch5627 is quite expensive (and they don't change). + */ + err = sch5627_read_limits(data); + if (err) + goto error; + + pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n", + build_code, build_id, hwmon_rev); + + /* Register sysfs interface files */ + err = sysfs_create_group(&pdev->dev.kobj, &sch5627_group); + if (err) + goto error; + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + data->hwmon_dev = NULL; + goto error; + } + + return 0; + +error: + sch5627_remove(pdev); + return err; +} + +static int __init sch5627_find(int sioaddr, unsigned short *address) +{ + u8 devid; + int err = superio_enter(sioaddr); + if (err) + return err; + + devid = superio_inb(sioaddr, SIO_REG_DEVID); + if (devid != SIO_SCH5627_ID) { + pr_debug("Unsupported device id: 0x%02x\n", + (unsigned int)devid); + err = -ENODEV; + goto exit; + } + + superio_select(sioaddr, SIO_SCH5627_EM_LD); + + if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { + pr_warn("Device not activated\n"); + err = -ENODEV; + goto exit; + } + + /* + * Warning the order of the low / high byte is the other way around + * as on most other superio devices!! + */ + *address = superio_inb(sioaddr, SIO_REG_ADDR) | + superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8; + if (*address == 0) { + pr_warn("Base address not set\n"); + err = -ENODEV; + goto exit; + } + + pr_info("Found %s chip at %#hx\n", DEVNAME, *address); +exit: + superio_exit(sioaddr); + return err; +} + +static int __init sch5627_device_add(unsigned short address) +{ + struct resource res = { + .start = address, + .end = address + REGION_LENGTH - 1, + .flags = IORESOURCE_IO, + }; + int err; + + sch5627_pdev = platform_device_alloc(DRVNAME, address); + if (!sch5627_pdev) + return -ENOMEM; + + res.name = sch5627_pdev->name; + err = acpi_check_resource_conflict(&res); + if (err) + goto exit_device_put; + + err = platform_device_add_resources(sch5627_pdev, &res, 1); + if (err) { + pr_err("Device resource addition failed\n"); + goto exit_device_put; + } + + err = platform_device_add(sch5627_pdev); + if (err) { + pr_err("Device addition failed\n"); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(sch5627_pdev); + + return err; +} + +static struct platform_driver sch5627_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = sch5627_probe, + .remove = sch5627_remove, +}; + +static int __init sch5627_init(void) +{ + int err = -ENODEV; + unsigned short address; + + if (sch5627_find(0x4e, &address) && sch5627_find(0x2e, &address)) + goto exit; + + err = platform_driver_register(&sch5627_driver); + if (err) + goto exit; + + err = sch5627_device_add(address); + if (err) + goto exit_driver; + + return 0; + +exit_driver: + platform_driver_unregister(&sch5627_driver); +exit: + return err; +} + +static void __exit sch5627_exit(void) +{ + platform_device_unregister(sch5627_pdev); + platform_driver_unregister(&sch5627_driver); +} + +MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver"); +MODULE_AUTHOR("Hans de Goede (hdegoede@redhat.com)"); +MODULE_LICENSE("GPL"); + +module_init(sch5627_init); +module_exit(sch5627_exit); -- cgit v1.2.2 From 8c22a8f57516275afcd81c84f3724ac08cf6aa7b Mon Sep 17 00:00:00 2001 From: Dirk Eibach Date: Mon, 21 Mar 2011 17:59:36 +0100 Subject: hwmon: Add support for Texas Instruments ADS1015 Signed-off-by: Dirk Eibach Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/ads1015.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 drivers/hwmon/ads1015.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 6fad9f082f67..e4bd13b3cd8b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -968,6 +968,16 @@ config SENSORS_SCH5627 This driver can also be built as a module. If so, the module will be called sch5627. +config SENSORS_ADS1015 + tristate "Texas Instruments ADS1015" + depends on I2C + help + If you say yes here you get support for Texas Instruments ADS1015 + 12-bit 4-input ADC device. + + This driver can also be built as a module. If so, the module + will be called ads1015. + config SENSORS_ADS7828 tristate "Texas Instruments ADS7828" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 4d0122c52219..54ca5939d028 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c new file mode 100644 index 000000000000..9e1585c3152e --- /dev/null +++ b/drivers/hwmon/ads1015.c @@ -0,0 +1,282 @@ +/* + * ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC + * (C) Copyright 2010 + * Dirk Eibach, Guntermann & Drunck GmbH + * + * Based on the ads7828 driver by Steve Hardy. + * + * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* ADS1015 registers */ +enum { + ADS1015_CONVERSION = 0, + ADS1015_CONFIG = 1, +}; + +/* PGA fullscale voltages in mV */ +static const unsigned int fullscale_table[8] = { + 6144, 4096, 2048, 1024, 512, 256, 256, 256 }; + +#define ADS1015_CONFIG_CHANNELS 8 +#define ADS1015_DEFAULT_CHANNELS 0xff + +struct ads1015_data { + struct device *hwmon_dev; + struct mutex update_lock; /* mutex protect updates */ + struct attribute *attr_table[ADS1015_CONFIG_CHANNELS + 1]; + struct attribute_group attr_group; +}; + +static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg) +{ + s32 data = i2c_smbus_read_word_data(client, reg); + + return (data < 0) ? data : swab16(data); +} + +static s32 ads1015_write_reg(struct i2c_client *client, unsigned int reg, + u16 val) +{ + return i2c_smbus_write_word_data(client, reg, swab16(val)); +} + +static int ads1015_read_value(struct i2c_client *client, unsigned int channel, + int *value) +{ + u16 config; + s16 conversion; + unsigned int pga; + int fullscale; + unsigned int k; + struct ads1015_data *data = i2c_get_clientdata(client); + int res; + + mutex_lock(&data->update_lock); + + /* get fullscale voltage */ + res = ads1015_read_reg(client, ADS1015_CONFIG); + if (res < 0) + goto err_unlock; + config = res; + pga = (config >> 9) & 0x0007; + fullscale = fullscale_table[pga]; + + /* set channel and start single conversion */ + config &= ~(0x0007 << 12); + config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12; + + /* wait until conversion finished */ + res = ads1015_write_reg(client, ADS1015_CONFIG, config); + if (res < 0) + goto err_unlock; + for (k = 0; k < 5; ++k) { + msleep(1); + res = ads1015_read_reg(client, ADS1015_CONFIG); + if (res < 0) + goto err_unlock; + config = res; + if (config & (1 << 15)) + break; + } + if (k == 5) { + res = -EIO; + goto err_unlock; + } + + res = ads1015_read_reg(client, ADS1015_CONVERSION); + if (res < 0) + goto err_unlock; + conversion = res; + + mutex_unlock(&data->update_lock); + + *value = DIV_ROUND_CLOSEST(conversion * fullscale, 0x7ff0); + + return 0; + +err_unlock: + mutex_unlock(&data->update_lock); + return res; +} + +/* sysfs callback function */ +static ssize_t show_in(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + int in; + int res; + + res = ads1015_read_value(client, attr->index, &in); + + return (res < 0) ? res : sprintf(buf, "%d\n", in); +} + +#define in_reg(offset)\ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ + NULL, offset) + +in_reg(0); +in_reg(1); +in_reg(2); +in_reg(3); +in_reg(4); +in_reg(5); +in_reg(6); +in_reg(7); + +static struct attribute *all_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, +}; + +/* + * Driver interface + */ + +static int ads1015_remove(struct i2c_client *client) +{ + struct ads1015_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->attr_group); + kfree(data); + return 0; +} + +static unsigned int ads1015_get_exported_channels(struct i2c_client *client) +{ + struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev); +#ifdef CONFIG_OF + struct device_node *np = client->dev.of_node; + const __be32 *of_channels; + int of_channels_size; +#endif + + /* prefer platform data */ + if (pdata) + return pdata->exported_channels; + +#ifdef CONFIG_OF + /* fallback on OF */ + of_channels = of_get_property(np, "exported-channels", + &of_channels_size); + if (of_channels && (of_channels_size == sizeof(*of_channels))) + return be32_to_cpup(of_channels); +#endif + + /* fallback on default configuration */ + return ADS1015_DEFAULT_CHANNELS; +} + +static int ads1015_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ads1015_data *data; + int err; + unsigned int exported_channels; + unsigned int k; + unsigned int n = 0; + + data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + /* build sysfs attribute group */ + data->attr_group.attrs = data->attr_table; + exported_channels = ads1015_get_exported_channels(client); + for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) { + if (!(exported_channels & (1<attr_table[n++] = all_attributes[k]; + } + err = sysfs_create_group(&client->dev.kobj, &data->attr_group); + if (err) + goto exit_free; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->attr_group); +exit_free: + kfree(data); +exit: + return err; +} + +static const struct i2c_device_id ads1015_id[] = { + { "ads1015", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ads1015_id); + +static struct i2c_driver ads1015_driver = { + .driver = { + .name = "ads1015", + }, + .probe = ads1015_probe, + .remove = ads1015_remove, + .id_table = ads1015_id, +}; + +static int __init sensors_ads1015_init(void) +{ + return i2c_add_driver(&ads1015_driver); +} + +static void __exit sensors_ads1015_exit(void) +{ + i2c_del_driver(&ads1015_driver); +} + +MODULE_AUTHOR("Dirk Eibach "); +MODULE_DESCRIPTION("ADS1015 driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_ads1015_init); +module_exit(sensors_ads1015_exit); -- cgit v1.2.2 From fdf241a8ed93236915c70717a4b6dfb856274496 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 21 Mar 2011 17:59:37 +0100 Subject: hwmon: (ads1015) Drop dynamic attribute group It is cheaper to handle attributes individually. Signed-off-by: Jean Delvare Acked-by: Dirk Eibach --- drivers/hwmon/ads1015.c | 50 ++++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index 9e1585c3152e..fa02f20b79ff 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -51,8 +51,6 @@ static const unsigned int fullscale_table[8] = { struct ads1015_data { struct device *hwmon_dev; struct mutex update_lock; /* mutex protect updates */ - struct attribute *attr_table[ADS1015_CONFIG_CHANNELS + 1]; - struct attribute_group attr_group; }; static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg) @@ -141,28 +139,15 @@ static ssize_t show_in(struct device *dev, struct device_attribute *da, return (res < 0) ? res : sprintf(buf, "%d\n", in); } -#define in_reg(offset)\ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ - NULL, offset) - -in_reg(0); -in_reg(1); -in_reg(2); -in_reg(3); -in_reg(4); -in_reg(5); -in_reg(6); -in_reg(7); - -static struct attribute *all_attributes[] = { - &sensor_dev_attr_in0_input.dev_attr.attr, - &sensor_dev_attr_in1_input.dev_attr.attr, - &sensor_dev_attr_in2_input.dev_attr.attr, - &sensor_dev_attr_in3_input.dev_attr.attr, - &sensor_dev_attr_in4_input.dev_attr.attr, - &sensor_dev_attr_in5_input.dev_attr.attr, - &sensor_dev_attr_in6_input.dev_attr.attr, - &sensor_dev_attr_in7_input.dev_attr.attr, +static const struct sensor_device_attribute ads1015_in[] = { + SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), + SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), + SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), + SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), + SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), + SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), + SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), + SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), }; /* @@ -172,8 +157,11 @@ static struct attribute *all_attributes[] = { static int ads1015_remove(struct i2c_client *client) { struct ads1015_data *data = i2c_get_clientdata(client); + int k; + hwmon_device_unregister(data->hwmon_dev); - sysfs_remove_group(&client->dev.kobj, &data->attr_group); + for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) + device_remove_file(&client->dev, &ads1015_in[k].dev_attr); kfree(data); return 0; } @@ -210,7 +198,6 @@ static int ads1015_probe(struct i2c_client *client, int err; unsigned int exported_channels; unsigned int k; - unsigned int n = 0; data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL); if (!data) { @@ -222,16 +209,14 @@ static int ads1015_probe(struct i2c_client *client, mutex_init(&data->update_lock); /* build sysfs attribute group */ - data->attr_group.attrs = data->attr_table; exported_channels = ads1015_get_exported_channels(client); for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) { if (!(exported_channels & (1<attr_table[n++] = all_attributes[k]; + err = device_create_file(&client->dev, &ads1015_in[k].dev_attr); + if (err) + goto exit_free; } - err = sysfs_create_group(&client->dev.kobj, &data->attr_group); - if (err) - goto exit_free; data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { @@ -242,7 +227,8 @@ static int ads1015_probe(struct i2c_client *client, return 0; exit_remove: - sysfs_remove_group(&client->dev.kobj, &data->attr_group); + for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) + device_remove_file(&client->dev, &ads1015_in[k].dev_attr); exit_free: kfree(data); exit: -- cgit v1.2.2 From c0046867f34bb81ec3f237ebbc5241ae678b8379 Mon Sep 17 00:00:00 2001 From: Dirk Eibach Date: Mon, 21 Mar 2011 17:59:37 +0100 Subject: hwmon: (ads1015) Make gain and datarate configurable Configuration for ads1015 gain and datarate is possible via devicetree or platform data. This is a followup patch to previous ads1015 patches on Jean Delvares tree. Signed-off-by: Dirk Eibach Signed-off-by: Jean Delvare --- drivers/hwmon/ads1015.c | 149 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index fa02f20b79ff..e9beeda4cbe5 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -45,12 +45,18 @@ enum { static const unsigned int fullscale_table[8] = { 6144, 4096, 2048, 1024, 512, 256, 256, 256 }; -#define ADS1015_CONFIG_CHANNELS 8 +/* Data rates in samples per second */ +static const unsigned int data_rate_table[8] = { + 128, 250, 490, 920, 1600, 2400, 3300, 3300 }; + #define ADS1015_DEFAULT_CHANNELS 0xff +#define ADS1015_DEFAULT_PGA 2 +#define ADS1015_DEFAULT_DATA_RATE 4 struct ads1015_data { struct device *hwmon_dev; struct mutex update_lock; /* mutex protect updates */ + struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; }; static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg) @@ -71,40 +77,42 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel, { u16 config; s16 conversion; - unsigned int pga; - int fullscale; - unsigned int k; struct ads1015_data *data = i2c_get_clientdata(client); + unsigned int pga = data->channel_data[channel].pga; + int fullscale; + unsigned int data_rate = data->channel_data[channel].data_rate; + unsigned int conversion_time_ms; int res; mutex_lock(&data->update_lock); - /* get fullscale voltage */ + /* get channel parameters */ res = ads1015_read_reg(client, ADS1015_CONFIG); if (res < 0) goto err_unlock; config = res; - pga = (config >> 9) & 0x0007; fullscale = fullscale_table[pga]; + conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]); - /* set channel and start single conversion */ - config &= ~(0x0007 << 12); - config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12; + /* setup and start single conversion */ + config &= 0x001f; + config |= (1 << 15) | (1 << 8); + config |= (channel & 0x0007) << 12; + config |= (pga & 0x0007) << 9; + config |= (data_rate & 0x0007) << 5; - /* wait until conversion finished */ res = ads1015_write_reg(client, ADS1015_CONFIG, config); if (res < 0) goto err_unlock; - for (k = 0; k < 5; ++k) { - msleep(1); - res = ads1015_read_reg(client, ADS1015_CONFIG); - if (res < 0) - goto err_unlock; - config = res; - if (config & (1 << 15)) - break; - } - if (k == 5) { + + /* wait until conversion finished */ + msleep(conversion_time_ms); + res = ads1015_read_reg(client, ADS1015_CONFIG); + if (res < 0) + goto err_unlock; + config = res; + if (!(config & (1 << 15))) { + /* conversion not finished in time */ res = -EIO; goto err_unlock; } @@ -160,35 +168,97 @@ static int ads1015_remove(struct i2c_client *client) int k; hwmon_device_unregister(data->hwmon_dev); - for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) + for (k = 0; k < ADS1015_CHANNELS; ++k) device_remove_file(&client->dev, &ads1015_in[k].dev_attr); kfree(data); return 0; } -static unsigned int ads1015_get_exported_channels(struct i2c_client *client) -{ - struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev); #ifdef CONFIG_OF - struct device_node *np = client->dev.of_node; - const __be32 *of_channels; - int of_channels_size; +static int ads1015_get_channels_config_of(struct i2c_client *client) +{ + struct ads1015_data *data = i2c_get_clientdata(client); + struct device_node *node; + + if (!client->dev.of_node + || !of_get_next_child(client->dev.of_node, NULL)) + return -EINVAL; + + for_each_child_of_node(client->dev.of_node, node) { + const __be32 *property; + int len; + unsigned int channel; + unsigned int pga = ADS1015_DEFAULT_PGA; + unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE; + + property = of_get_property(node, "reg", &len); + if (!property || len != sizeof(int)) { + dev_err(&client->dev, "invalid reg on %s\n", + node->full_name); + continue; + } + + channel = be32_to_cpup(property); + if (channel > ADS1015_CHANNELS) { + dev_err(&client->dev, + "invalid channel index %d on %s\n", + channel, node->full_name); + continue; + } + + property = of_get_property(node, "ti,gain", &len); + if (property && len == sizeof(int)) { + pga = be32_to_cpup(property); + if (pga > 6) { + dev_err(&client->dev, + "invalid gain on %s\n", + node->full_name); + } + } + + property = of_get_property(node, "ti,datarate", &len); + if (property && len == sizeof(int)) { + data_rate = be32_to_cpup(property); + if (data_rate > 7) { + dev_err(&client->dev, + "invalid data_rate on %s\n", + node->full_name); + } + } + + data->channel_data[channel].enabled = true; + data->channel_data[channel].pga = pga; + data->channel_data[channel].data_rate = data_rate; + } + + return 0; +} #endif +static void ads1015_get_channels_config(struct i2c_client *client) +{ + unsigned int k; + struct ads1015_data *data = i2c_get_clientdata(client); + struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev); + /* prefer platform data */ - if (pdata) - return pdata->exported_channels; + if (pdata) { + memcpy(data->channel_data, pdata->channel_data, + sizeof(data->channel_data)); + return; + } #ifdef CONFIG_OF - /* fallback on OF */ - of_channels = of_get_property(np, "exported-channels", - &of_channels_size); - if (of_channels && (of_channels_size == sizeof(*of_channels))) - return be32_to_cpup(of_channels); + if (!ads1015_get_channels_config_of(client)) + return; #endif /* fallback on default configuration */ - return ADS1015_DEFAULT_CHANNELS; + for (k = 0; k < ADS1015_CHANNELS; ++k) { + data->channel_data[k].enabled = true; + data->channel_data[k].pga = ADS1015_DEFAULT_PGA; + data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE; + } } static int ads1015_probe(struct i2c_client *client, @@ -196,7 +266,6 @@ static int ads1015_probe(struct i2c_client *client, { struct ads1015_data *data; int err; - unsigned int exported_channels; unsigned int k; data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL); @@ -209,9 +278,9 @@ static int ads1015_probe(struct i2c_client *client, mutex_init(&data->update_lock); /* build sysfs attribute group */ - exported_channels = ads1015_get_exported_channels(client); - for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) { - if (!(exported_channels & (1<channel_data[k].enabled) continue; err = device_create_file(&client->dev, &ads1015_in[k].dev_attr); if (err) @@ -227,7 +296,7 @@ static int ads1015_probe(struct i2c_client *client, return 0; exit_remove: - for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) + for (k = 0; k < ADS1015_CHANNELS; ++k) device_remove_file(&client->dev, &ads1015_in[k].dev_attr); exit_free: kfree(data); -- cgit v1.2.2 From 3f086fe93f734ba76f2e130777687f81e0cbb318 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 21 Mar 2011 17:01:07 +0000 Subject: viafb: initialize margins correct This patch initializes the margins for the initial mode correct. This is required to get the desired initial refresh rate. Also do more verbose sanity checking to prevent misbehavior. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/viafbdev.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index fd6a15f0decd..9d9bb9b4ed3f 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1806,14 +1806,9 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) default_var.xres_virtual = default_xres; default_var.yres_virtual = default_yres; default_var.bits_per_pixel = viafb_bpp; - default_var.pixclock = - viafb_get_pixclock(default_xres, default_yres, viafb_refresh); - default_var.left_margin = (default_xres >> 3) & 0xf8; - default_var.right_margin = 32; - default_var.upper_margin = 16; - default_var.lower_margin = 4; - default_var.hsync_len = default_var.left_margin; - default_var.vsync_len = 4; + viafb_fill_var_timing_info(&default_var, viafb_get_refresh( + default_var.xres, default_var.yres, viafb_refresh), + viafb_get_mode(default_var.xres, default_var.yres)); viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo); viafbinfo->var = default_var; @@ -1852,15 +1847,9 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) default_var.xres_virtual = viafb_second_virtual_xres; default_var.yres_virtual = viafb_second_virtual_yres; default_var.bits_per_pixel = viafb_bpp1; - default_var.pixclock = - viafb_get_pixclock(viafb_second_xres, viafb_second_yres, - viafb_refresh1); - default_var.left_margin = (viafb_second_xres >> 3) & 0xf8; - default_var.right_margin = 32; - default_var.upper_margin = 16; - default_var.lower_margin = 4; - default_var.hsync_len = default_var.left_margin; - default_var.vsync_len = 4; + viafb_fill_var_timing_info(&default_var, viafb_get_refresh( + default_var.xres, default_var.yres, viafb_refresh1), + viafb_get_mode(default_var.xres, default_var.yres)); viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1); viafb_check_var(&default_var, viafbinfo1); @@ -2015,15 +2004,17 @@ static int __init viafb_setup(char *options) */ int __init viafb_init(void) { - u32 dummy; + u32 dummy_x, dummy_y; #ifndef MODULE char *option = NULL; if (fb_get_options("viafb", &option)) return -ENODEV; viafb_setup(option); #endif - if (parse_mode(viafb_mode, &dummy, &dummy) - || parse_mode(viafb_mode1, &dummy, &dummy) + if (parse_mode(viafb_mode, &dummy_x, &dummy_y) + || !viafb_get_mode(dummy_x, dummy_y) + || parse_mode(viafb_mode1, &dummy_x, &dummy_y) + || !viafb_get_mode(dummy_x, dummy_y) || viafb_bpp < 0 || viafb_bpp > 32 || viafb_bpp1 < 0 || viafb_bpp1 > 32 || parse_active_dev()) -- cgit v1.2.2 From 9011cd250e26d9159943895adf29453af1b93298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B5nu=20Samuel?= Date: Sat, 12 Mar 2011 11:29:25 +0200 Subject: zd1211rw: TrendNet TEW-509UB id added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tõnu Samuel Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 81e80489a052..58236e6d0921 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -60,6 +60,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x3207), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ -- cgit v1.2.2 From f8a22a2b165c79a46e275097fcadab7fd151c504 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 Mar 2011 10:01:58 +0300 Subject: iwlwifi: missing unlock on error path We should unlock here instead of returning -EINVAL directly. Signed-off-by: Dan Carpenter Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 581dc9f10273..321b18b59135 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -3009,14 +3009,17 @@ static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (!priv->_agn.offchan_tx_skb) - return -EINVAL; + if (!priv->_agn.offchan_tx_skb) { + ret = -EINVAL; + goto unlock; + } priv->_agn.offchan_tx_skb = NULL; ret = iwl_scan_cancel_timeout(priv, 200); if (ret) ret = -EIO; +unlock: mutex_unlock(&priv->mutex); return ret; -- cgit v1.2.2 From 3bf184a7e96ff21965fa524260f60af8ab4d9133 Mon Sep 17 00:00:00 2001 From: Joe Gunn Date: Tue, 15 Mar 2011 08:41:19 -0700 Subject: orinoco: Maintain lock until entry removed from list Removing an entry from the scan_list should be performed while holding the lock. Signed-off-by: Joseph J. Gunn Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index f3d396e7544b..62c6b2b37dbe 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1376,13 +1376,13 @@ static void orinoco_process_scan_results(struct work_struct *work) spin_lock_irqsave(&priv->scan_lock, flags); list_for_each_entry_safe(sd, temp, &priv->scan_list, list) { - spin_unlock_irqrestore(&priv->scan_lock, flags); buf = sd->buf; len = sd->len; type = sd->type; list_del(&sd->list); + spin_unlock_irqrestore(&priv->scan_lock, flags); kfree(sd); if (len > 0) { -- cgit v1.2.2 From 2cea5b3c0ce976eae78bdaa192223f952185045c Mon Sep 17 00:00:00 2001 From: Peter Lemenkov Date: Wed, 16 Mar 2011 17:12:15 +0300 Subject: rt2x00: Add rt2870 device id Add ID for Asus USB-N11 Wi-FI adapter. Tested by me. Signed-off-by: Peter Lemenkov Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f1a92144996f..12f5b2f940e4 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -719,6 +719,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -913,7 +914,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) }, /* AzureWave */ { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v1.2.2 From 7a2a75bcc2a54c9b87c8b3831c5369717fcf513d Mon Sep 17 00:00:00 2001 From: Peter Lemenkov Date: Wed, 16 Mar 2011 17:12:16 +0300 Subject: rt2x00: Add Planex Communications, Inc. RT8070 Add Planex Communications, Inc. RT8070 under CONFIG_RT2800USB_UNKNOWN Signed-off-by: Peter Lemenkov Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 12f5b2f940e4..1f73cfaad962 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -961,6 +961,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ + { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Qcom */ { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) }, -- cgit v1.2.2 From 9a74597235e54c16c31da62835e2e9285c631044 Mon Sep 17 00:00:00 2001 From: Peter Lemenkov Date: Wed, 16 Mar 2011 17:12:17 +0300 Subject: rt2x00: Add 2L Central Europe BV 8070 Add 2L Central Europe BV 8070 under CONFIG_RT2800USB_UNKNOWN Signed-off-by: Peter Lemenkov Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 1f73cfaad962..38adae9c0e0b 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -937,6 +937,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Edimax */ + { USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Encore */ { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Gemtek */ -- cgit v1.2.2 From 5da201a4c86aac6c46a071c5c8255601090b65b2 Mon Sep 17 00:00:00 2001 From: Peter Lemenkov Date: Wed, 16 Mar 2011 17:12:18 +0300 Subject: rt2x00: Add unknown Toshiba device Add unknown Toshiba device, mentioned in rt3572sta sources, under CONFIG_RT2800USB_UNKNOWN Signed-off-by: Peter Lemenkov Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 38adae9c0e0b..4e368657a83c 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -975,6 +975,8 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Sweex */ { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Toshiba */ + { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, #endif -- cgit v1.2.2 From 6e9d592f02f657361168c94e22d9602cad71a09c Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Thu, 17 Mar 2011 14:08:57 -0400 Subject: rtlwifi: Fix memset argument order These were found using the following semantic match: // @@expression E1; type T;@@ * memset(E1, ... * sizeof(T) * ..., ...); // Also take this opportunity to remove the unnecessary void* casts. Signed-off-by: Ilia Mirkin Tested-by: Larry Finger Acked-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/efuse.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index 4f92cba6810a..f74a8701c67d 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -410,8 +410,8 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) if (!efuse_shadow_update_chk(hw)) { efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); - memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, @@ -446,9 +446,9 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) if (word_en != 0x0F) { u8 tmpdata[8]; - memcpy((void *)tmpdata, - (void *)(&rtlefuse-> - efuse_map[EFUSE_MODIFY_MAP][base]), 8); + memcpy(tmpdata, + &rtlefuse->efuse_map[EFUSE_MODIFY_MAP][base], + 8); RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("U-efuse\n"), tmpdata, 8); @@ -465,8 +465,8 @@ bool efuse_shadow_update(struct ieee80211_hw *hw) efuse_power_switch(hw, true, false); efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); - memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("<---\n")); @@ -479,13 +479,12 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); if (rtlefuse->autoload_failflag == true) { - memset((void *)(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0]), 128, - 0xFF); + memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128); } else efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]); - memcpy((void *)&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], - (void *)&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], + memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0], + &rtlefuse->efuse_map[EFUSE_INIT_MAP][0], rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); } @@ -694,8 +693,8 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) if (offset > 15) return false; - memset((void *)data, PGPKT_DATA_SIZE * sizeof(u8), 0xff); - memset((void *)tmpdata, PGPKT_DATA_SIZE * sizeof(u8), 0xff); + memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8)); while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) { if (readstate & PG_STATE_HEADER) { @@ -862,7 +861,7 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr, tmp_word_cnts = efuse_calculate_word_cnts(tmp_pkt.word_en); - memset((void *)originaldata, 8 * sizeof(u8), 0xff); + memset(originaldata, 0xff, 8 * sizeof(u8)); if (efuse_pg_packet_read(hw, tmp_pkt.offset, originaldata)) { badworden = efuse_word_enable_data_write(hw, @@ -917,7 +916,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw, target_pkt.offset = offset; target_pkt.word_en = word_en; - memset((void *)target_pkt.data, 8 * sizeof(u8), 0xFF); + memset(target_pkt.data, 0xFF, 8 * sizeof(u8)); efuse_word_enable_data_read(word_en, data, target_pkt.data); target_word_cnts = efuse_calculate_word_cnts(target_pkt.word_en); @@ -1022,7 +1021,7 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw, u8 badworden = 0x0F; u8 tmpdata[8]; - memset((void *)tmpdata, PGPKT_DATA_SIZE, 0xff); + memset(tmpdata, 0xff, PGPKT_DATA_SIZE); RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD, ("word_en = %x efuse_addr=%x\n", word_en, efuse_addr)); -- cgit v1.2.2 From 61e1b0b00c793ad5a32fe2181c9f77115fed5dc4 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 21 Mar 2011 18:27:21 +0530 Subject: ath9k: Fix kernel panic in AR2427 Kernel panic occurs just after AR2427 establishes connection with AP. Unless aggregation is enabled we don't initialize the TID structure. Thus accesing the elements of the TID structure when aggregation is disabled, leads to NULL pointer dereferencing. [ 191.320358] Call Trace: [ 191.320364] [] ? ath9k_tx+0xa7/0x200 [ath9k] [ 191.320376] [] ? __ieee80211_tx+0x5c/0x1e0 [mac80211] [ 191.320386] [] ? ieee80211_tx+0x7b/0x90 [mac80211] [ 191.320395] [] ? ieee80211_xmit+0x9d/0x1d0 [mac80211] [ 191.320401] [] ? wake_up_state+0xf/0x20 [ 191.320405] [] ? signal_wake_up+0x28/0x40 [ 191.320410] [] ? default_spin_lock_flags+0x8/0x10 [ 191.320420] [] ? ieee80211_subif_start_xmit+0x2e8/0x7c0 [mac80211] [ 191.320425] [] ? do_page_fault+0x295/0x3a0 [ 191.320431] [] ? dev_hard_start_xmit+0x1ad/0x210 [ 191.320436] [] ? sch_direct_xmit+0x105/0x170 [ 191.320445] [] ? get_sta_flags+0x2a/0x40 [mac80211] [ 191.320449] [] ? dev_queue_xmit+0x37f/0x4b0 [ 191.320452] [] ? eth_header+0x0/0xb0 [ 191.320456] [] ? neigh_resolve_output+0xe9/0x310 [ 191.320461] [] ? ip6_output_finish+0xa5/0x110 [ 191.320464] [] ? ip6_output2+0x134/0x250 [ 191.320468] [] ? ip6_output+0x6d/0x100 [ 191.320471] [] ? mld_sendpack+0x395/0x3e0 [ 191.320475] [] ? add_grhead+0x31/0xa0 [ 191.320478] [] ? mld_send_cr+0x1bc/0x2b0 [ 191.320482] [] ? irq_exit+0x39/0x70 [ 191.320485] [] ? mld_ifc_timer_expire+0x10/0x40 [ 191.320489] [] ? run_timer_softirq+0x13e/0x2c0 [ 191.320493] [] ? common_interrupt+0x30/0x40 [ 191.320498] [] ? mld_ifc_timer_expire+0x0/0x40 [ 191.320502] [] ? __do_softirq+0x98/0x1b0 [ 191.320506] [] ? do_softirq+0x45/0x50 [ 191.320509] [] ? irq_exit+0x65/0x70 [ 191.320513] [] ? smp_apic_timer_interrupt+0x5c/0x8b [ 191.320516] [] ? apic_timer_interrupt+0x31/0x40 [ 191.320521] [] ? k_getrusage+0x12b/0x2f0 [ 191.320525] [] ? acpi_idle_enter_simple+0x117/0x148 [ 191.320529] [] ? cpuidle_idle_call+0x7a/0x100 [ 191.320532] [] ? cpu_idle+0x94/0xd0 [ 191.320536] [] ? rest_init+0x58/0x60 [ 191.320541] [] ? start_kernel+0x351/0x357 [ 191.320544] [] ? unknown_bootoption+0x0/0x19e [ 191.320548] [] ? i386_start_kernel+0xaa/0xb1 [ 191.320550] Code: 03 66 3d 00 03 0f 84 7c 02 00 00 83 c3 18 0f b6 03 8b 4d e0 89 c3 83 e3 0f 6b c3 48 89 5d d8 8d 04 06 8d 50 0c 89 55 d0 8b 40 20 <8b> 00 3b 01 0f 85 8e 02 00 00 f6 47 20 40 0f 84 29 ff ff ff 8b [ 191.320634] EIP: [] ath_tx_start+0x474/0x770 [ath9k] SS:ESP 0068:c0761a90 [ 191.320642] CR2: 0000000000000000 [ 191.320647] ---[ end trace 9296ef23b9076ece ]--- [ 191.320650] Kernel panic - not syncing: Fatal exception in interrupt Cc: stable@kernel.org Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index ef22096d40c9..26734e53b37f 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1725,8 +1725,8 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, u8 tidno; spin_lock_bh(&txctl->txq->axq_lock); - - if (ieee80211_is_data_qos(hdr->frame_control) && txctl->an) { + if ((sc->sc_flags & SC_OP_TXAGGR) && txctl->an && + ieee80211_is_data_qos(hdr->frame_control)) { tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; tid = ATH_AN_2_TID(txctl->an, tidno); -- cgit v1.2.2 From 38f7aa23c4dd5f9af13dffca49879c42a61b0a01 Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Mon, 21 Mar 2011 10:28:59 -0700 Subject: matroxfb: remove incorrect Matrox G200eV support Remove incorrect Matrox G200eV support that was previously added by commit e3a1938805d2e81b27d3d348788644f3bad004f2 A serious issue with the incorrect G200eV support that reproduces on the Matrox G200eV equipped IBM x3650 M2 is the total lack of text (login banner, login prompt, etc) on the console when X is not running and total lack of text on all of the virtual consoles after X is started. Any concerns that the incorrect code (upstream since October 2008) has been successfully used on non-IBM G200eV equipped system(s) appear to be unwarranted. In addition to the serious/non-intermittent nature of issues that have been spotted on IBM systems, complete removal of the incorrect code is clearly supported by the following Matrox (Yannick Heneault) provided input: "It impossible that this patch should have work on a system. The patch only declare the G200eV as a regular G200 which is not case. Many registers are different, including at least the PLL programming sequence. If the G200eV is programmed like a regular G200, it will not display anything." v1 - Initial patch that removed the incorrect code for _all_ G200eV equipped systems. v2 - Darrick Wong provided patch that blacklisted the incorrect code on G200eV equipped IBM systems leaving it enabled on all G200eV equipped non-IBM systems. v3 - Same code changes included with v1 plus additional justification for complete removal of the incorrect code. Signed-off-by: Gary Hade Cc: Darrick J. Wong Cc: Krzysztof Helt Cc: Petr Vandrovec Cc: Andrew Morton Cc: Linus Torvalds Cc: Yannick Heneault Cc: Christian Toutant Signed-off-by: Linus Torvalds --- drivers/video/matrox/matroxfb_base.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index a082debe824b..a74439affce9 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1461,13 +1461,6 @@ static struct board { MGA_G100, &vbG100, "MGA-G100 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI, 0xFF, - 0, 0, - DEVF_G200, - 230000, - MGA_G200, - &vbG200, - "MGA-G200eV (PCI)"}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, 0, 0, DEVF_G200, @@ -2119,8 +2112,6 @@ static struct pci_device_id matroxfb_devices[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, -- cgit v1.2.2 From 0bf8c869701039b12c3520cb1bb1689595ab108b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 21 Mar 2011 20:47:31 +0100 Subject: Reduce sequential pointer derefs in scsi_error.c and reduce size as well This patch reduces the number of sequential pointer derefs in drivers/scsi/scsi_error.c This has been submitted a number of times over a couple of years. I believe this version adresses all comments it has gathered over time. Please apply or reject with a reason. The benefits are: - makes the code easier to read. Lots of sequential derefs of the same pointers is not easy on the eye. - theoretically at least, just dereferencing the pointers once can allow the compiler to generally slightly faster code, so in theory this could also be a micro speed optimization. - reduces size of object file (tiny effect: on x86-64, in at least one configuration, the text size decreased from 9439 bytes to 9400) - removes some pointless (mostly trailing) whitespace. Signed-off-by: Jesper Juhl Signed-off-by: Linus Torvalds --- drivers/scsi/scsi_error.c | 94 ++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 991de3c15cfc..633c2395a92a 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -3,14 +3,14 @@ * * SCSI error/timeout handling * Initial versions: Eric Youngdale. Based upon conversations with - * Leonard Zubkoff and David Miller at Linux Expo, + * Leonard Zubkoff and David Miller at Linux Expo, * ideas originating from all over the place. * * Restructured scsi_unjam_host and associated functions. * September 04, 2002 Mike Anderson (andmike@us.ibm.com) * * Forward port of Russell King's (rmk@arm.linux.org.uk) changes and - * minor cleanups. + * minor cleanups. * September 30, 2002 Mike Anderson (andmike@us.ibm.com) */ @@ -129,14 +129,15 @@ enum blk_eh_timer_return scsi_times_out(struct request *req) { struct scsi_cmnd *scmd = req->special; enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED; + struct Scsi_Host *host = scmd->device->host; trace_scsi_dispatch_cmd_timeout(scmd); scsi_log_completion(scmd, TIMEOUT_ERROR); - if (scmd->device->host->transportt->eh_timed_out) - rtn = scmd->device->host->transportt->eh_timed_out(scmd); - else if (scmd->device->host->hostt->eh_timed_out) - rtn = scmd->device->host->hostt->eh_timed_out(scmd); + if (host->transportt->eh_timed_out) + rtn = host->transportt->eh_timed_out(scmd); + else if (host->hostt->eh_timed_out) + rtn = host->hostt->eh_timed_out(scmd); if (unlikely(rtn == BLK_EH_NOT_HANDLED && !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { @@ -195,7 +196,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, ++total_failures; if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) ++cmd_cancel; - else + else ++cmd_failed; } } @@ -214,7 +215,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d" " devices require eh work\n", - total_failures, devices_failed)); + total_failures, devices_failed)); } #endif @@ -294,7 +295,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) return NEEDS_RETRY; } /* - * if the device is in the process of becoming ready, we + * if the device is in the process of becoming ready, we * should retry. */ if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01)) @@ -488,7 +489,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) */ static void scsi_eh_done(struct scsi_cmnd *scmd) { - struct completion *eh_action; + struct completion *eh_action; SCSI_LOG_ERROR_RECOVERY(3, printk("%s scmd: %p result: %x\n", @@ -507,22 +508,23 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd) { unsigned long flags; int rtn; + struct Scsi_Host *host = scmd->device->host; + struct scsi_host_template *hostt = host->hostt; SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n", __func__)); - if (!scmd->device->host->hostt->eh_host_reset_handler) + if (!hostt->eh_host_reset_handler) return FAILED; - rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd); + rtn = hostt->eh_host_reset_handler(scmd); if (rtn == SUCCESS) { - if (!scmd->device->host->hostt->skip_settle_delay) + if (!hostt->skip_settle_delay) ssleep(HOST_RESET_SETTLE_TIME); - spin_lock_irqsave(scmd->device->host->host_lock, flags); - scsi_report_bus_reset(scmd->device->host, - scmd_channel(scmd)); - spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); + scsi_report_bus_reset(host, scmd_channel(scmd)); + spin_unlock_irqrestore(host->host_lock, flags); } return rtn; @@ -536,22 +538,23 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) { unsigned long flags; int rtn; + struct Scsi_Host *host = scmd->device->host; + struct scsi_host_template *hostt = host->hostt; SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n", __func__)); - if (!scmd->device->host->hostt->eh_bus_reset_handler) + if (!hostt->eh_bus_reset_handler) return FAILED; - rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd); + rtn = hostt->eh_bus_reset_handler(scmd); if (rtn == SUCCESS) { - if (!scmd->device->host->hostt->skip_settle_delay) + if (!hostt->skip_settle_delay) ssleep(BUS_RESET_SETTLE_TIME); - spin_lock_irqsave(scmd->device->host->host_lock, flags); - scsi_report_bus_reset(scmd->device->host, - scmd_channel(scmd)); - spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); + scsi_report_bus_reset(host, scmd_channel(scmd)); + spin_unlock_irqrestore(host->host_lock, flags); } return rtn; @@ -577,16 +580,18 @@ static int scsi_try_target_reset(struct scsi_cmnd *scmd) { unsigned long flags; int rtn; + struct Scsi_Host *host = scmd->device->host; + struct scsi_host_template *hostt = host->hostt; - if (!scmd->device->host->hostt->eh_target_reset_handler) + if (!hostt->eh_target_reset_handler) return FAILED; - rtn = scmd->device->host->hostt->eh_target_reset_handler(scmd); + rtn = hostt->eh_target_reset_handler(scmd); if (rtn == SUCCESS) { - spin_lock_irqsave(scmd->device->host->host_lock, flags); + spin_lock_irqsave(host->host_lock, flags); __starget_for_each_device(scsi_target(scmd->device), NULL, __scsi_report_device_reset); - spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + spin_unlock_irqrestore(host->host_lock, flags); } return rtn; @@ -605,27 +610,28 @@ static int scsi_try_target_reset(struct scsi_cmnd *scmd) static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) { int rtn; + struct scsi_host_template *hostt = scmd->device->host->hostt; - if (!scmd->device->host->hostt->eh_device_reset_handler) + if (!hostt->eh_device_reset_handler) return FAILED; - rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd); + rtn = hostt->eh_device_reset_handler(scmd); if (rtn == SUCCESS) __scsi_report_device_reset(scmd->device, NULL); return rtn; } -static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) +static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt, struct scsi_cmnd *scmd) { - if (!scmd->device->host->hostt->eh_abort_handler) + if (!hostt->eh_abort_handler) return FAILED; - return scmd->device->host->hostt->eh_abort_handler(scmd); + return hostt->eh_abort_handler(scmd); } static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) { - if (scsi_try_to_abort_cmd(scmd) != SUCCESS) + if (scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd) != SUCCESS) if (scsi_try_bus_device_reset(scmd) != SUCCESS) if (scsi_try_target_reset(scmd) != SUCCESS) if (scsi_try_bus_reset(scmd) != SUCCESS) @@ -846,7 +852,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); * * Description: * See if we need to request sense information. if so, then get it - * now, so we have a better idea of what to do. + * now, so we have a better idea of what to do. * * Notes: * This has the unfortunate side effect that if a shost adapter does @@ -958,7 +964,7 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting cmd:" "0x%p\n", current->comm, scmd)); - rtn = scsi_try_to_abort_cmd(scmd); + rtn = scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd); if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD; if (!scsi_device_online(scmd->device) || @@ -966,7 +972,6 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, !scsi_eh_tur(scmd)) { scsi_eh_finish_cmd(scmd, done_q); } - } else SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting" " cmd failed:" @@ -1010,7 +1015,7 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) * * Notes: * If commands are failing due to not ready, initializing command required, - * try revalidating the device, which will end up sending a start unit. + * try revalidating the device, which will end up sending a start unit. */ static int scsi_eh_stu(struct Scsi_Host *shost, struct list_head *work_q, @@ -1064,7 +1069,7 @@ static int scsi_eh_stu(struct Scsi_Host *shost, * Try a bus device reset. Still, look to see whether we have multiple * devices that are jammed or not - if we have multiple devices, it * makes no sense to try bus_device_reset - we really would need to try - * a bus_reset instead. + * a bus_reset instead. */ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, struct list_head *work_q, @@ -1164,7 +1169,7 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost, } /** - * scsi_eh_bus_reset - send a bus reset + * scsi_eh_bus_reset - send a bus reset * @shost: &scsi host being recovered. * @work_q: &list_head for pending commands. * @done_q: &list_head for processed commands. @@ -1181,7 +1186,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, * we really want to loop over the various channels, and do this on * a channel by channel basis. we should also check to see if any * of the failed commands are on soft_reset devices, and if so, skip - * the reset. + * the reset. */ for (channel = 0; channel <= shost->max_channel; channel++) { @@ -1223,7 +1228,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, } /** - * scsi_eh_host_reset - send a host reset + * scsi_eh_host_reset - send a host reset * @work_q: list_head for processed commands. * @done_q: list_head for processed commands. */ @@ -1376,7 +1381,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) return SUCCESS; /* * when the low level driver returns did_soft_error, - * it is responsible for keeping an internal retry counter + * it is responsible for keeping an internal retry counter * in order to avoid endless loops (db) * * actually this is a bug in this function here. we should @@ -1414,7 +1419,6 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) */ break; /* fallthrough */ - case DID_BUS_BUSY: case DID_PARITY: goto maybe_retry; @@ -1982,7 +1986,7 @@ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, if (sb_len > 7) sshdr->additional_length = sense_buffer[7]; } else { - /* + /* * fixed format */ if (sb_len > 2) -- cgit v1.2.2 From 97491ba3f64c2137101efdfe7593305d692d7d63 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Sun, 13 Mar 2011 15:53:29 +0200 Subject: i2c-pxa2xx: Don't clear isr bits too early isr is passed later into i2c_pxa_irq_txempty and i2c_pxa_irq_rxfull and they may use some other bits than irq sources. Signed-off-by: Vasily Khoruzhick Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pxa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index b914184748c9..f59224a5c761 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -966,8 +966,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) struct pxa_i2c *i2c = dev_id; u32 isr = readl(_ISR(i2c)); - isr &= VALID_INT_SOURCE; - if (!isr) + if (!(isr & VALID_INT_SOURCE)) return IRQ_NONE; if (i2c_debug > 2 && 0) { @@ -984,7 +983,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) /* * Always clear all pending IRQs. */ - writel(isr, _ISR(i2c)); + writel(isr & VALID_INT_SOURCE, _ISR(i2c)); if (isr & ISR_SAD) i2c_pxa_slave_start(i2c, isr); -- cgit v1.2.2 From b4797048f70e142a65ee2139085edb44b166d238 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 10 Oct 2010 13:45:54 -0300 Subject: [media] stv090x: added function to control GPIOs from the outside This patch STV090X adds and exports a function to control the GPIOs of the stv090x-devices. Cc: Manu Abraham Signed-off-by: Martin Wilks Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x.c | 14 ++++++++++++++ drivers/media/dvb/frontends/stv090x.h | 12 ++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 4e0fc2c8a41c..63cb4f8fa6c8 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -4516,6 +4516,20 @@ err: return -1; } +int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, + u8 xor_value) +{ + struct stv090x_state *state = fe->demodulator_priv; + u8 reg = 0; + + STV090x_SETFIELD(reg, GPIOx_OPD_FIELD, dir); + STV090x_SETFIELD(reg, GPIOx_CONFIG_FIELD, value); + STV090x_SETFIELD(reg, GPIOx_XOR_FIELD, xor_value); + + return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); +} +EXPORT_SYMBOL(stv090x_set_gpio); + static struct dvb_frontend_ops stv090x_ops = { .info = { diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h index dd1b93ae4e9d..11754f2f6437 100644 --- a/drivers/media/dvb/frontends/stv090x.h +++ b/drivers/media/dvb/frontends/stv090x.h @@ -104,6 +104,11 @@ struct stv090x_config { extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, struct i2c_adapter *i2c, enum stv090x_demodulator demod); + +/* dir = 0 -> output, dir = 1 -> input/open-drain */ +extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, + u8 dir, u8 value, u8 xor_value); + #else static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, @@ -113,6 +118,13 @@ static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *c printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } + +static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, + u8 opd, u8 value, u8 xor_value) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif /* CONFIG_DVB_STV090x */ #endif /* __STV090x_H */ -- cgit v1.2.2 From 4f7200a8a0253e7a4b74cbf1a0a3868cccdee647 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sat, 9 Oct 2010 10:12:34 -0300 Subject: [media] stv090x: add tei-field to config-structure Some backends want to receive the full transport stream including uncorrected packets. To have that feature this patchs add a field to the config-structure called TEI (transport stream error indicator). Cc: Manu Abraham Signed-off-by: Martin Wilks Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x.c | 8 ++++++++ drivers/media/dvb/frontends/stv090x.h | 3 +++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 63cb4f8fa6c8..dba2c0407fd1 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -4169,6 +4169,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) switch (state->config->ts1_mode) { case STV090x_TSMODE_PARALLEL_PUNCTURED: reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) @@ -4177,6 +4178,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) case STV090x_TSMODE_DVBCI: reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) @@ -4185,6 +4187,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) case STV090x_TSMODE_SERIAL_PUNCTURED: reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) @@ -4193,6 +4196,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) case STV090x_TSMODE_SERIAL_CONTINUOUS: reg = stv090x_read_reg(state, STV090x_P1_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts1_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0) @@ -4206,6 +4210,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) switch (state->config->ts2_mode) { case STV090x_TSMODE_PARALLEL_PUNCTURED: reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) @@ -4214,6 +4219,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) case STV090x_TSMODE_DVBCI: reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) @@ -4222,6 +4228,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) case STV090x_TSMODE_SERIAL_PUNCTURED: reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00); if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) @@ -4230,6 +4237,7 @@ static int stv090x_set_tspath(struct stv090x_state *state) case STV090x_TSMODE_SERIAL_CONTINUOUS: reg = stv090x_read_reg(state, STV090x_P2_TSCFGH); + STV090x_SETFIELD_Px(reg, TSFIFO_TEIUPDATE_FIELD, state->config->ts2_tei); STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01); STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01); if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0) diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h index 11754f2f6437..a3fefa717ed6 100644 --- a/drivers/media/dvb/frontends/stv090x.h +++ b/drivers/media/dvb/frontends/stv090x.h @@ -78,6 +78,9 @@ struct stv090x_config { u32 ts1_clk; u32 ts2_clk; + u8 ts1_tei : 1; + u8 ts2_tei : 1; + enum stv090x_i2crpt repeater_level; u8 tuner_bbgain; /* default: 10db */ -- cgit v1.2.2 From 739ff04f63ba6498b287021649cb999e639c3c83 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 31 Oct 2010 16:24:19 -0300 Subject: [media] technisat-usb2: added driver for Technisat's USB2.0 DVB-S/S2 receiver This patch is adding support for Technisat's new USB2.0 DVB-S/S2 receiver device. The development was sponsored by Technisat. The Green led is toggle depending on the frontend-state. The Red LED is turned on all the time. The MAC address reading from the EEPROM along with the LRC-method to check whether its valid. Support for the IR-receiver of the Technisat USB2 box. The keys of small, black remote-control are built-in, repeated key behaviour are simulated. The i2c-mutex of the dvb-usb-structure is used as a general mutex for USB requests, as there are 3 threads racing for atomic requests consisting of multiple usb-requests. A module option is there which disables the toggling of LEDs by the driver on certain triggers. Useful when being used in a "dark" environment. [mchehab@redhat.com: Fix merge conflicts with RC renaming patches] Signed-off-by: Martin Wilks Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 8 + drivers/media/dvb/dvb-usb/Makefile | 3 + drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + drivers/media/dvb/dvb-usb/dvb-usb-remote.c | 2 +- drivers/media/dvb/dvb-usb/dvb-usb.h | 2 + drivers/media/dvb/dvb-usb/technisat-usb2.c | 808 +++++++++++++++++++++++++++ drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-technisat-usb2.c | 93 +++ 8 files changed, 917 insertions(+), 1 deletion(-) create mode 100644 drivers/media/dvb/dvb-usb/technisat-usb2.c create mode 100644 drivers/media/rc/keymaps/rc-technisat-usb2.c (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 3d48ba019342..fe4f894183ff 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -358,3 +358,11 @@ config DVB_USB_LME2510 select DVB_IX2505V if !DVB_FE_CUSTOMISE help Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . + +config DVB_USB_TECHNISAT_USB2 + tristate "Technisat DVB-S/S2 USB2.0 support" + depends on DVB_USB + select DVB_STB0899 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + help + Say Y here to support the Technisat USB2 DVB-S/S2 device diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 5b1d12f2d591..4bac13da0c39 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -91,6 +91,9 @@ obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o dvb-usb-lmedm04-objs = lmedm04.o obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o +dvb-usb-technisat-usb2-objs = technisat-usb2.o +obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o + EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 1a6310b61923..d0bce0445cc7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -312,4 +312,5 @@ #define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac #define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001 #define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002 +#define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500 #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index 23005b3cf30b..f511418b144a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -246,7 +246,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) dev->map_name = d->props.rc.core.rc_codes; dev->change_protocol = d->props.rc.core.change_protocol; dev->allowed_protos = d->props.rc.core.allowed_protos; - dev->driver_type = RC_DRIVER_SCANCODE; + dev->driver_type = d->props.rc.core.driver_type; usb_to_input_id(d->udev, &dev->input_id); dev->input_name = "IR-receiver inside an USB DVB receiver"; dev->input_phys = d->rc_phys; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 65fa9268e7f7..76a80968482a 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -181,6 +181,7 @@ struct dvb_rc_legacy { * @rc_codes: name of rc codes table * @protocol: type of protocol(s) currently used by the driver * @allowed_protos: protocol(s) supported by the driver + * @driver_type: Used to point if a device supports raw mode * @change_protocol: callback to change protocol * @rc_query: called to query an event event. * @rc_interval: time in ms between two queries. @@ -190,6 +191,7 @@ struct dvb_rc { char *rc_codes; u64 protocol; u64 allowed_protos; + enum rc_driver_type driver_type; int (*change_protocol)(struct rc_dev *dev, u64 rc_type); char *module_name; int (*rc_query) (struct dvb_usb_device *d); diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c new file mode 100644 index 000000000000..406602a1499d --- /dev/null +++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c @@ -0,0 +1,808 @@ +/* + * Linux driver for Technisat DVB-S/S2 USB 2.0 device + * + * Copyright (C) 2010 Patrick Boettcher, + * Kernel Labs Inc. PO Box 745, St James, NY 11780 + * + * Development was sponsored by Technisat Digital UK Limited, whose + * registered office is Witan Gate House 500 - 600 Witan Gate West, + * Milton Keynes, MK9 1SH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND + * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER + * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the + * GNU General Public License for more details. + */ + +#define DVB_USB_LOG_PREFIX "technisat-usb2" +#include "dvb-usb.h" + +#include "stv6110x.h" +#include "stv090x.h" + +/* module parameters */ +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, + "set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \ + DVB_USB_DEBUG_STATUS); + +/* disables all LED control command and + * also does not start the signal polling thread */ +static int disable_led_control; +module_param(disable_led_control, int, 0444); +MODULE_PARM_DESC(disable_led_control, + "disable LED control of the device " + "(default: 0 - LED control is active)."); + +/* device private data */ +struct technisat_usb2_state { + struct dvb_usb_device *dev; + struct delayed_work green_led_work; + u8 power_state; + + u16 last_scan_code; +}; + +/* debug print helpers */ +#define deb_info(args...) dprintk(debug, 0x01, args) +#define deb_eeprom(args...) dprintk(debug, 0x02, args) +#define deb_i2c(args...) dprintk(debug, 0x04, args) +#define deb_rc(args...) dprintk(debug, 0x08, args) + +/* vendor requests */ +#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3 +#define SET_FRONT_END_RESET_VENDOR_REQUEST 0xB4 +#define GET_VERSION_INFO_VENDOR_REQUEST 0xB5 +#define SET_GREEN_LED_VENDOR_REQUEST 0xB6 +#define SET_RED_LED_VENDOR_REQUEST 0xB7 +#define GET_IR_DATA_VENDOR_REQUEST 0xB8 +#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST 0xB9 +#define SET_USB_REENUMERATION 0xBA + +/* i2c-access methods */ +#define I2C_SPEED_100KHZ_BIT 0x40 + +#define I2C_STATUS_NAK 7 +#define I2C_STATUS_OK 8 + +static int technisat_usb2_i2c_access(struct usb_device *udev, + u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen) +{ + u8 b[64]; + int ret, actual_length; + + deb_i2c("i2c-access: %02x, tx: ", device_addr); + debug_dump(tx, txlen, deb_i2c); + deb_i2c(" "); + + if (txlen > 62) { + err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)", + device_addr); + txlen = 62; + } + if (rxlen > 62) { + err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)", + device_addr); + txlen = 62; + } + + b[0] = I2C_SPEED_100KHZ_BIT; + b[1] = device_addr << 1; + + if (rx != NULL) { + b[0] |= rxlen; + b[1] |= 1; + } + + memcpy(&b[2], tx, txlen); + ret = usb_bulk_msg(udev, + usb_sndbulkpipe(udev, 0x01), + b, 2 + txlen, + NULL, 1000); + + if (ret < 0) { + err("i2c-error: out failed %02x = %d", device_addr, ret); + return -ENODEV; + } + + ret = usb_bulk_msg(udev, + usb_rcvbulkpipe(udev, 0x01), + b, 64, &actual_length, 1000); + if (ret < 0) { + err("i2c-error: in failed %02x = %d", device_addr, ret); + return -ENODEV; + } + + if (b[0] != I2C_STATUS_OK) { + err("i2c-error: %02x = %d", device_addr, b[0]); + /* handle tuner-i2c-nak */ + if (!(b[0] == I2C_STATUS_NAK && + device_addr == 0x60 + /* && device_is_technisat_usb2 */)) + return -ENODEV; + } + + deb_i2c("status: %d, ", b[0]); + + if (rx != NULL) { + memcpy(rx, &b[2], rxlen); + + deb_i2c("rx (%d): ", rxlen); + debug_dump(rx, rxlen, deb_i2c); + } + + deb_i2c("\n"); + + return 0; +} + +static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, + int num) +{ + int ret = 0, i; + struct dvb_usb_device *d = i2c_get_adapdata(adap); + + /* Ensure nobody else hits the i2c bus while we're sending our + sequence of messages, (such as the remote control thread) */ + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + for (i = 0; i < num; i++) { + if (i+1 < num && msg[i+1].flags & I2C_M_RD) { + ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr, + msg[i].buf, msg[i].len, + msg[i+1].buf, msg[i+1].len); + if (ret != 0) + break; + i++; + } else { + ret = technisat_usb2_i2c_access(d->udev, msg[i].addr, + msg[i].buf, msg[i].len, + NULL, 0); + if (ret != 0) + break; + } + } + + if (ret == 0) + ret = i; + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm technisat_usb2_i2c_algo = { + .master_xfer = technisat_usb2_i2c_xfer, + .functionality = technisat_usb2_i2c_func, +}; + +#if 0 +static void technisat_usb2_frontend_reset(struct usb_device *udev) +{ + usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SET_FRONT_END_RESET_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 10, 0, + NULL, 0, 500); +} +#endif + +/* LED control */ +enum technisat_usb2_led_state { + LED_OFF, + LED_BLINK, + LED_ON, + LED_UNDEFINED +}; + +static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state) +{ + int ret; + + u8 led[8] = { + red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, + 0 + }; + + if (disable_led_control && state != LED_OFF) + return 0; + + switch (state) { + case LED_ON: + led[1] = 0x82; + break; + case LED_BLINK: + led[1] = 0x82; + if (red) { + led[2] = 0x02; + led[3] = 10; + led[4] = 10; + } else { + led[2] = 0xff; + led[3] = 50; + led[4] = 50; + } + led[5] = 1; + break; + + default: + case LED_OFF: + led[1] = 0x80; + break; + } + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + led, sizeof(led), 500); + + mutex_unlock(&d->i2c_mutex); + return ret; +} + +static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green) +{ + int ret; + u8 b = 0; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + SET_LED_TIMER_DIVIDER_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + (red << 8) | green, 0, + &b, 1, 500); + + mutex_unlock(&d->i2c_mutex); + + return ret; +} + +static void technisat_usb2_green_led_control(struct work_struct *work) +{ + struct technisat_usb2_state *state = + container_of(work, struct technisat_usb2_state, green_led_work.work); + struct dvb_frontend *fe = state->dev->adapter[0].fe; + + if (state->power_state == 0) + goto schedule; + + if (fe != NULL) { + enum fe_status status; + + if (fe->ops.read_status(fe, &status) != 0) + goto schedule; + + if (status & FE_HAS_LOCK) { + u32 ber; + + if (fe->ops.read_ber(fe, &ber) != 0) + goto schedule; + + if (ber > 1000) + technisat_usb2_set_led(state->dev, 0, LED_BLINK); + else + technisat_usb2_set_led(state->dev, 0, LED_ON); + } else + technisat_usb2_set_led(state->dev, 0, LED_OFF); + } + +schedule: + schedule_delayed_work(&state->green_led_work, + msecs_to_jiffies(500)); +} + +/* method to find out whether the firmware has to be downloaded or not */ +static int technisat_usb2_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, int *cold) +{ + int ret; + u8 version[3]; + + /* first select the interface */ + if (usb_set_interface(udev, 0, 1) != 0) { + err("could not set alternate setting to 0"); + } else { + info("set alternate setting"); + } + + *cold = 0; /* by default do not download a firmware - just in case something is wrong */ + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + GET_VERSION_INFO_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_IN, + 0, 0, + version, sizeof(version), 500); + + if (ret < 0) + *cold = 1; + else { + info("firmware version: %d.%d", version[1], version[2]); + *cold = 0; + } + + return 0; +} + +/* power control */ +static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level) +{ + struct technisat_usb2_state *state = d->priv; + + state->power_state = level; + + if (disable_led_control) + return 0; + + /* green led is turned off in any case - will be turned on when tuning */ + technisat_usb2_set_led(d, 0, LED_OFF); + /* red led is turned on all the time */ + technisat_usb2_set_led(d, 1, LED_ON); + return 0; +} + +/* mac address reading - from the eeprom */ +#if 0 +static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d) +{ + u8 reg; + u8 b[16]; + int i,j; + + /* full EEPROM dump */ + for (j = 0; j < 256 * 4; j += 16) { + reg = j; + if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, ®, 1, b, 16) != 0) + break; + + deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg); + for (i = 0; i < 16; i++) + deb_eeprom("%02x ", b[i]); + deb_eeprom("\n"); + } +} +#endif + +static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length) +{ + u8 lrc = 0; + while (--length) + lrc ^= *b++; + return lrc; +} + +static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d, + u16 offset, u8 *b, u16 length, u8 tries) +{ + u8 bo = offset & 0xff; + struct i2c_msg msg[] = { + { + .addr = 0x50 | ((offset >> 8) & 0x3), + .buf = &bo, + .len = 1 + }, { + .addr = 0x50 | ((offset >> 8) & 0x3), + .flags = I2C_M_RD, + .buf = b, + .len = length + } + }; + + while (tries--) { + int status; + + if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) + break; + + status = + technisat_usb2_calc_lrc(b, length - 1) == b[length - 1]; + + if (status) + return 0; + } + + return -EREMOTEIO; +} + +#define EEPROM_MAC_START 0x3f8 +#define EEPROM_MAC_TOTAL 8 +static int technisat_usb2_read_mac_address(struct dvb_usb_device *d, + u8 mac[]) +{ + u8 buf[EEPROM_MAC_TOTAL]; + + if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START, + buf, EEPROM_MAC_TOTAL, 4) != 0) + return -ENODEV; + + memcpy(mac, buf, 6); + return 0; +} + +/* frontend attach */ +static int technisat_usb2_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + int i; + u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */ + + gpio[2] = 1; /* high - voltage ? */ + + switch (voltage) { + case SEC_VOLTAGE_13: + gpio[0] = 1; + break; + case SEC_VOLTAGE_18: + gpio[0] = 1; + gpio[1] = 1; + break; + default: + case SEC_VOLTAGE_OFF: + break; + } + + for (i = 0; i < 3; i++) + if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0) + return -EREMOTEIO; + return 0; +} + +static struct stv090x_config technisat_usb2_stv090x_config = { + .device = STV0903, + .demod_mode = STV090x_SINGLE, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 8000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_DVBCI, + .ts1_clk = 13400000, + .ts1_tei = 1, + + .repeater_level = STV090x_RPTLEVEL_64, + + .tuner_bbgain = 6, +}; + +static struct stv6110x_config technisat_usb2_stv6110x_config = { + .addr = 0x60, + .refclk = 16000000, + .clk_div = 2, +}; + +static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) +{ + struct usb_device *udev = a->dev->udev; + int ret; + + a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, + &a->dev->i2c_adap, STV090x_DEMODULATOR_0); + + if (a->fe) { + struct stv6110x_devctl *ctl; + + ctl = dvb_attach(stv6110x_attach, + a->fe, + &technisat_usb2_stv6110x_config, + &a->dev->i2c_adap); + + if (ctl) { + technisat_usb2_stv090x_config.tuner_init = ctl->tuner_init; + technisat_usb2_stv090x_config.tuner_sleep = ctl->tuner_sleep; + technisat_usb2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + technisat_usb2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + technisat_usb2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + technisat_usb2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + technisat_usb2_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + if (a->fe->ops.init) + a->fe->ops.init(a->fe); + + if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) + return -EAGAIN; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + NULL, 0, 500); + mutex_unlock(&a->dev->i2c_mutex); + + if (ret != 0) + err("could not set IF_CLK to external"); + + a->fe->ops.set_voltage = technisat_usb2_set_voltage; + + /* if everything was successful assign a nice name to the frontend */ + strlcpy(a->fe->ops.info.name, a->dev->desc->name, + sizeof(a->fe->ops.info.name)); + } else { + dvb_frontend_detach(a->fe); + a->fe = NULL; + } + } + + technisat_usb2_set_led_timer(a->dev, 1, 1); + + return a->fe == NULL ? -ENODEV : 0; +} + +/* Remote control */ + +/* the device is giving providing raw IR-signals to the host mapping + * it only to one remote control is just the default implementation + */ +#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889 +#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US) + +#define FIRMWARE_CLOCK_TICK 83333 +#define FIRMWARE_CLOCK_DIVISOR 256 + +#define IR_PERCENT_TOLERANCE 15 + +#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) +#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR) + +#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK) +#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR) + +#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) +#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) + +#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) +#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100)) + +static int technisat_usb2_get_ir(struct dvb_usb_device *d) +{ + u8 buf[62], *b; + int ret; + struct ir_raw_event ev; + + buf[0] = GET_IR_DATA_VENDOR_REQUEST; + buf[1] = 0x08; + buf[2] = 0x8f; + buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT; + buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT; + + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), + GET_IR_DATA_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_OUT, + 0, 0, + buf, 5, 500); + if (ret < 0) + goto unlock; + + buf[1] = 0; + buf[2] = 0; + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), + GET_IR_DATA_VENDOR_REQUEST, + USB_TYPE_VENDOR | USB_DIR_IN, + 0x8080, 0, + buf, sizeof(buf), 500); + +unlock: + mutex_unlock(&d->i2c_mutex); + + if (ret < 0) + return ret; + + if (ret == 1) + return 0; /* no key pressed */ + + /* decoding */ + b = buf+1; + +#if 0 + deb_rc("RC: %d ", ret); + debug_dump(b, ret, deb_rc); +#endif + + ev.pulse = 0; + while (1) { + ev.pulse = !ev.pulse; + ev.duration = (*b * FIRMWARE_CLOCK_DIVISOR * FIRMWARE_CLOCK_TICK) / 1000; + ir_raw_event_store(d->rc_dev, &ev); + + b++; + if (*b == 0xff) { + ev.pulse = 0; + ev.duration = 888888*2; + ir_raw_event_store(d->rc_dev, &ev); + break; + } + } + + ir_raw_event_handle(d->rc_dev); + + return 1; +} + +static int technisat_usb2_rc_query(struct dvb_usb_device *d) +{ + int ret = technisat_usb2_get_ir(d); + + if (ret < 0) + return ret; + + if (ret == 0) + return 0; + + if (!disable_led_control) + technisat_usb2_set_led(d, 1, LED_BLINK); + + return 0; +} + +/* DVB-USB and USB stuff follows */ +static struct usb_device_id technisat_usb2_id_table[] = { + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, + { 0 } /* Terminating entry */ +}; + +/* device description */ +static struct dvb_usb_device_properties technisat_usb2_devices = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .identify_state = technisat_usb2_identify_state, + .firmware = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw", + + .size_of_priv = sizeof(struct technisat_usb2_state), + + .i2c_algo = &technisat_usb2_i2c_algo, + + .power_ctrl = technisat_usb2_power_ctrl, + .read_mac_address = technisat_usb2_read_mac_address, + + .num_adapters = 1, + .adapter = { + { + .frontend_attach = technisat_usb2_frontend_attach, + + .stream = { + .type = USB_ISOC, + .count = 8, + .endpoint = 0x2, + .u = { + .isoc = { + .framesperurb = 32, + .framesize = 2048, + .interval = 3, + } + } + }, + + .size_of_priv = 0, + }, + }, + + .num_device_descs = 1, + .devices = { + { "Technisat SkyStar USB HD (DVB-S/S2)", + { &technisat_usb2_id_table[0], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = 100, + .rc_codes = RC_MAP_TECHNISAT_USB2, + .module_name = "technisat-usb2", + .rc_query = technisat_usb2_rc_query, + .allowed_protos = RC_TYPE_ALL, + .driver_type = RC_DRIVER_IR_RAW, + } +}; + +static int technisat_usb2_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct dvb_usb_device *dev; + + if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE, + &dev, adapter_nr) != 0) + return -ENODEV; + + if (dev) { + struct technisat_usb2_state *state = dev->priv; + state->dev = dev; + + if (!disable_led_control) { + INIT_DELAYED_WORK(&state->green_led_work, + technisat_usb2_green_led_control); + schedule_delayed_work(&state->green_led_work, + msecs_to_jiffies(500)); + } + } + + return 0; +} + +static void technisat_usb2_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *dev = usb_get_intfdata(intf); + + /* work and stuff was only created when the device is is hot-state */ + if (dev != NULL) { + struct technisat_usb2_state *state = dev->priv; + if (state != NULL) { + cancel_rearming_delayed_work(&state->green_led_work); + flush_scheduled_work(); + } + } + + dvb_usb_device_exit(intf); +} + +static struct usb_driver technisat_usb2_driver = { + .name = "dvb_usb_technisat_usb2", + .probe = technisat_usb2_probe, + .disconnect = technisat_usb2_disconnect, + .id_table = technisat_usb2_id_table, +}; + +/* module stuff */ +static int __init technisat_usb2_module_init(void) +{ + int result = usb_register(&technisat_usb2_driver); + if (result) { + err("usb_register failed. Code %d", result); + return result; + } + + return 0; +} + +static void __exit technisat_usb2_module_exit(void) +{ + usb_deregister(&technisat_usb2_driver); +} + +module_init(technisat_usb2_module_init); +module_exit(technisat_usb2_module_exit); + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 0659e9f50144..f0c80559b303 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-real-audio-220-32-keys.o \ rc-streamzap.o \ rc-tbs-nec.o \ + rc-technisat-usb2.o \ rc-terratec-cinergy-xs.o \ rc-terratec-slim.o \ rc-tevii-nec.o \ diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c new file mode 100644 index 000000000000..4afe5774f192 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -0,0 +1,93 @@ +/* rc-technisat-usb2.c - Keytable for SkyStar HD USB + * + * Copyright (C) 2010 Patrick Boettcher, + * Kernel Labs Inc. PO Box 745, St James, NY 11780 + * + * Development was sponsored by Technisat Digital UK Limited, whose + * registered office is Witan Gate House 500 - 600 Witan Gate West, + * Milton Keynes, MK9 1SH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND + * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR + * FITNESS FOR A PARTICULAR PURPOSE. NEITHER THE COPYRIGHT HOLDER + * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the + * GNU General Public License for more details. + */ + +#include + +static struct rc_map_table technisat_usb2[] = { + {0x0a0c, KEY_POWER}, + {0x0a01, KEY_1}, + {0x0a02, KEY_2}, + {0x0a03, KEY_3}, + {0x0a0d, KEY_MUTE}, + {0x0a04, KEY_4}, + {0x0a05, KEY_5}, + {0x0a06, KEY_6}, + {0x0a38, KEY_VIDEO}, /* EXT */ + {0x0a07, KEY_7}, + {0x0a08, KEY_8}, + {0x0a09, KEY_9}, + {0x0a00, KEY_0}, + {0x0a4f, KEY_INFO}, + {0x0a20, KEY_CHANNELUP}, + {0x0a52, KEY_MENU}, + {0x0a11, KEY_VOLUMEUP}, + {0x0a57, KEY_OK}, + {0x0a10, KEY_VOLUMEDOWN}, + {0x0a2f, KEY_EPG}, + {0x0a21, KEY_CHANNELDOWN}, + {0x0a22, KEY_REFRESH}, + {0x0a3c, KEY_TEXT}, + {0x0a76, KEY_ENTER}, /* HOOK */ + {0x0a0f, KEY_HELP}, + {0x0a6b, KEY_RED}, + {0x0a6c, KEY_GREEN}, + {0x0a6d, KEY_YELLOW}, + {0x0a6e, KEY_BLUE}, + {0x0a29, KEY_STOP}, + {0x0a23, KEY_LANGUAGE}, + {0x0a53, KEY_TV}, + {0x0a0a, KEY_PROGRAM}, +}; + +static struct rc_map_list technisat_usb2_map = { + .map = { + .scan = technisat_usb2, + .size = ARRAY_SIZE(technisat_usb2), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_TECHNISAT_USB2, + } +}; + +static int __init init_rc_map(void) +{ + return rc_map_register(&technisat_usb2_map); +} + +static void __exit exit_rc_map(void) +{ + rc_map_unregister(&technisat_usb2_map); +} + +module_init(init_rc_map) +module_exit(exit_rc_map) + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 4ec02ea0d88d811f61e2c7765418eff770936871 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 Jan 2011 21:42:12 -0200 Subject: [media] technisat-usb2: Don't use a deprecated call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/dvb/dvb-usb/technisat-usb2.c: In function ‘technisat_usb2_disconnect’: drivers/media/dvb/dvb-usb/technisat-usb2.c:770: warning: ‘cancel_rearming_delayed_work’ is deprecated (declared at include/linux/workqueue.h:421) Cc: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/technisat-usb2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c index 406602a1499d..10151aa49239 100644 --- a/drivers/media/dvb/dvb-usb/technisat-usb2.c +++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c @@ -767,7 +767,7 @@ static void technisat_usb2_disconnect(struct usb_interface *intf) if (dev != NULL) { struct technisat_usb2_state *state = dev->priv; if (state != NULL) { - cancel_rearming_delayed_work(&state->green_led_work); + cancel_delayed_work_sync(&state->green_led_work); flush_scheduled_work(); } } -- cgit v1.2.2 From f8f3914cf922f5f9e1d60e9e10f6fb92742907ad Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Thu, 29 Jul 2010 14:44:25 -0300 Subject: [media] v4l: Add multi-planar API definitions to the V4L2 API Multi-planar API is as a backwards-compatible extension of the V4L2 API, which allows video buffers to consist of one or more planes. Planes are separate memory buffers; each has its own mapping, backed by usually separate physical memory buffers. Many different uses for the multi-planar API are possible, examples include: - embedded devices requiring video components to be placed in physically separate buffers, e.g. for Samsung S3C/S5P SoC series' video codec, Y and interleaved Cb/Cr components reside in buffers in different memory banks; - applications may receive (or choose to store) video data of one video buffer in separate memory buffers; such data would have to be temporarily copied together into one buffer before passing it to a V4L2 device; - applications or drivers may want to pass metadata related to a buffer and it may not be possible to place it in the same buffer, together with video data. [mchehab@redhat.com: CodingStyle fixes] Signed-off-by: Pawel Osciak Signed-off-by: Kyungmin Park Reviewed-by: Marek Szyprowski Signed-off-by: Marek Szyprowski Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ioctl.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index f51327ef6757..1a9d90ab666b 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -165,6 +165,8 @@ const char *v4l2_type_names[] = { [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "vid-out-overlay", + [V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane", + [V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane", }; EXPORT_SYMBOL(v4l2_type_names); -- cgit v1.2.2 From d14e6d76ebf740fd0d0bd296933993a555938896 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Thu, 23 Dec 2010 04:15:27 -0300 Subject: [media] v4l: Add multi-planar ioctl handling code Add multi-planar API core ioctl handling and conversion functions. [mchehab@redhat.com: CondingStyle fixup] Signed-off-by: Pawel Osciak Signed-off-by: Kyungmin Park Reviewed-by: Marek Szyprowski Signed-off-by: Marek Szyprowski Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ioctl.c | 453 +++++++++++++++++++++++++++++++++++---- 1 file changed, 409 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 1a9d90ab666b..8360ed2d933a 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -428,20 +428,33 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, struct v4l2_buffer *p) { struct v4l2_timecode *tc = &p->timecode; + struct v4l2_plane *plane; + int i; dbgarg(cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, " - "bytesused=%d, flags=0x%08d, " - "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx, length=%d\n", + "flags=0x%08d, field=%0d, sequence=%d, memory=%s\n", p->timestamp.tv_sec / 3600, (int)(p->timestamp.tv_sec / 60) % 60, (int)(p->timestamp.tv_sec % 60), (long)p->timestamp.tv_usec, p->index, prt_names(p->type, v4l2_type_names), - p->bytesused, p->flags, - p->field, p->sequence, - prt_names(p->memory, v4l2_memory_names), - p->m.userptr, p->length); + p->flags, p->field, p->sequence, + prt_names(p->memory, v4l2_memory_names)); + + if (V4L2_TYPE_IS_MULTIPLANAR(p->type) && p->m.planes) { + for (i = 0; i < p->length; ++i) { + plane = &p->m.planes[i]; + dbgarg2("plane %d: bytesused=%d, data_offset=0x%08x " + "offset/userptr=0x%08lx, length=%d\n", + i, plane->bytesused, plane->data_offset, + plane->m.userptr, plane->length); + } + } else { + dbgarg2("bytesused=%d, offset/userptr=0x%08lx, length=%d\n", + p->bytesused, p->m.userptr, p->length); + } + dbgarg2("timecode=%02d:%02d:%02d type=%d, " "flags=0x%08d, frames=%d, userbits=0x%08x\n", tc->hours, tc->minutes, tc->seconds, @@ -469,6 +482,27 @@ static inline void v4l_print_pix_fmt(struct video_device *vfd, fmt->bytesperline, fmt->sizeimage, fmt->colorspace); }; +static inline void v4l_print_pix_fmt_mplane(struct video_device *vfd, + struct v4l2_pix_format_mplane *fmt) +{ + int i; + + dbgarg2("width=%d, height=%d, format=%c%c%c%c, field=%s, " + "colorspace=%d, num_planes=%d\n", + fmt->width, fmt->height, + (fmt->pixelformat & 0xff), + (fmt->pixelformat >> 8) & 0xff, + (fmt->pixelformat >> 16) & 0xff, + (fmt->pixelformat >> 24) & 0xff, + prt_names(fmt->field, v4l2_field_names), + fmt->colorspace, fmt->num_planes); + + for (i = 0; i < fmt->num_planes; ++i) + dbgarg2("plane %d: bytesperline=%d sizeimage=%d\n", i, + fmt->plane_fmt[i].bytesperline, + fmt->plane_fmt[i].sizeimage); +} + static inline void v4l_print_ext_ctrls(unsigned int cmd, struct video_device *vfd, struct v4l2_ext_controls *c, int show_vals) { @@ -522,7 +556,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_g_fmt_vid_cap) + if (ops->vidioc_g_fmt_vid_cap || + ops->vidioc_g_fmt_vid_cap_mplane) + return 0; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (ops->vidioc_g_fmt_vid_cap_mplane) return 0; break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: @@ -530,7 +569,12 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_g_fmt_vid_out) + if (ops->vidioc_g_fmt_vid_out || + ops->vidioc_g_fmt_vid_out_mplane) + return 0; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (ops->vidioc_g_fmt_vid_out_mplane) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: @@ -561,12 +605,70 @@ static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) return -EINVAL; } +/** + * fmt_sp_to_mp() - Convert a single-plane format to its multi-planar 1-plane + * equivalent + */ +static int fmt_sp_to_mp(const struct v4l2_format *f_sp, + struct v4l2_format *f_mp) +{ + struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; + const struct v4l2_pix_format *pix = &f_sp->fmt.pix; + + if (f_sp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + f_mp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else if (f_sp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + f_mp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + else + return -EINVAL; + + pix_mp->width = pix->width; + pix_mp->height = pix->height; + pix_mp->pixelformat = pix->pixelformat; + pix_mp->field = pix->field; + pix_mp->colorspace = pix->colorspace; + pix_mp->num_planes = 1; + pix_mp->plane_fmt[0].sizeimage = pix->sizeimage; + pix_mp->plane_fmt[0].bytesperline = pix->bytesperline; + + return 0; +} + +/** + * fmt_mp_to_sp() - Convert a multi-planar 1-plane format to its single-planar + * equivalent + */ +static int fmt_mp_to_sp(const struct v4l2_format *f_mp, + struct v4l2_format *f_sp) +{ + const struct v4l2_pix_format_mplane *pix_mp = &f_mp->fmt.pix_mp; + struct v4l2_pix_format *pix = &f_sp->fmt.pix; + + if (f_mp->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + f_sp->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + else if (f_mp->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + f_sp->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + else + return -EINVAL; + + pix->width = pix_mp->width; + pix->height = pix_mp->height; + pix->pixelformat = pix_mp->pixelformat; + pix->field = pix_mp->field; + pix->colorspace = pix_mp->colorspace; + pix->sizeimage = pix_mp->plane_fmt[0].sizeimage; + pix->bytesperline = pix_mp->plane_fmt[0].bytesperline; + + return 0; +} + static long __video_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vfd = video_devdata(file); const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; void *fh = file->private_data; + struct v4l2_format f_copy; long ret = -EINVAL; if (ops == NULL) { @@ -635,6 +737,11 @@ static long __video_do_ioctl(struct file *file, if (ops->vidioc_enum_fmt_vid_cap) ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (ops->vidioc_enum_fmt_vid_cap_mplane) + ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, + fh, f); + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (ops->vidioc_enum_fmt_vid_overlay) ret = ops->vidioc_enum_fmt_vid_overlay(file, @@ -644,6 +751,11 @@ static long __video_do_ioctl(struct file *file, if (ops->vidioc_enum_fmt_vid_out) ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (ops->vidioc_enum_fmt_vid_out_mplane) + ret = ops->vidioc_enum_fmt_vid_out_mplane(file, + fh, f); + break; case V4L2_BUF_TYPE_PRIVATE: if (ops->vidioc_enum_fmt_type_private) ret = ops->vidioc_enum_fmt_type_private(file, @@ -672,22 +784,90 @@ static long __video_do_ioctl(struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_g_fmt_vid_cap) + if (ops->vidioc_g_fmt_vid_cap) { ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); + } else if (ops->vidioc_g_fmt_vid_cap_mplane) { + if (fmt_sp_to_mp(f, &f_copy)) + break; + ret = ops->vidioc_g_fmt_vid_cap_mplane(file, fh, + &f_copy); + if (ret) + break; + + /* Driver is currently in multi-planar format, + * we can't return it in single-planar API*/ + if (f_copy.fmt.pix_mp.num_planes > 1) { + ret = -EBUSY; + break; + } + + ret = fmt_mp_to_sp(&f_copy, f); + } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (ops->vidioc_g_fmt_vid_cap_mplane) { + ret = ops->vidioc_g_fmt_vid_cap_mplane(file, + fh, f); + } else if (ops->vidioc_g_fmt_vid_cap) { + if (fmt_mp_to_sp(f, &f_copy)) + break; + ret = ops->vidioc_g_fmt_vid_cap(file, + fh, &f_copy); + if (ret) + break; + + ret = fmt_sp_to_mp(&f_copy, f); + } + if (!ret) + v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (ops->vidioc_g_fmt_vid_overlay) ret = ops->vidioc_g_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_g_fmt_vid_out) + if (ops->vidioc_g_fmt_vid_out) { ret = ops->vidioc_g_fmt_vid_out(file, fh, f); + } else if (ops->vidioc_g_fmt_vid_out_mplane) { + if (fmt_sp_to_mp(f, &f_copy)) + break; + ret = ops->vidioc_g_fmt_vid_out_mplane(file, fh, + &f_copy); + if (ret) + break; + + /* Driver is currently in multi-planar format, + * we can't return it in single-planar API*/ + if (f_copy.fmt.pix_mp.num_planes > 1) { + ret = -EBUSY; + break; + } + + ret = fmt_mp_to_sp(&f_copy, f); + } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (ops->vidioc_g_fmt_vid_out_mplane) { + ret = ops->vidioc_g_fmt_vid_out_mplane(file, + fh, f); + } else if (ops->vidioc_g_fmt_vid_out) { + if (fmt_mp_to_sp(f, &f_copy)) + break; + ret = ops->vidioc_g_fmt_vid_out(file, + fh, &f_copy); + if (ret) + break; + + ret = fmt_sp_to_mp(&f_copy, f); + } + if (!ret) + v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (ops->vidioc_g_fmt_vid_out_overlay) ret = ops->vidioc_g_fmt_vid_out_overlay(file, @@ -731,8 +911,44 @@ static long __video_do_ioctl(struct file *file, case V4L2_BUF_TYPE_VIDEO_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.pix); v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_cap) + if (ops->vidioc_s_fmt_vid_cap) { ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); + } else if (ops->vidioc_s_fmt_vid_cap_mplane) { + if (fmt_sp_to_mp(f, &f_copy)) + break; + ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh, + &f_copy); + if (ret) + break; + + if (f_copy.fmt.pix_mp.num_planes > 1) { + /* Drivers shouldn't adjust from 1-plane + * to more than 1-plane formats */ + ret = -EBUSY; + WARN_ON(1); + break; + } + + ret = fmt_mp_to_sp(&f_copy, f); + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + CLEAR_AFTER_FIELD(f, fmt.pix_mp); + v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + if (ops->vidioc_s_fmt_vid_cap_mplane) { + ret = ops->vidioc_s_fmt_vid_cap_mplane(file, + fh, f); + } else if (ops->vidioc_s_fmt_vid_cap && + f->fmt.pix_mp.num_planes == 1) { + if (fmt_mp_to_sp(f, &f_copy)) + break; + ret = ops->vidioc_s_fmt_vid_cap(file, + fh, &f_copy); + if (ret) + break; + + ret = fmt_sp_to_mp(&f_copy, f); + } break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); @@ -743,8 +959,44 @@ static long __video_do_ioctl(struct file *file, case V4L2_BUF_TYPE_VIDEO_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.pix); v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (ops->vidioc_s_fmt_vid_out) + if (ops->vidioc_s_fmt_vid_out) { ret = ops->vidioc_s_fmt_vid_out(file, fh, f); + } else if (ops->vidioc_s_fmt_vid_out_mplane) { + if (fmt_sp_to_mp(f, &f_copy)) + break; + ret = ops->vidioc_s_fmt_vid_out_mplane(file, fh, + &f_copy); + if (ret) + break; + + if (f_copy.fmt.pix_mp.num_planes > 1) { + /* Drivers shouldn't adjust from 1-plane + * to more than 1-plane formats */ + ret = -EBUSY; + WARN_ON(1); + break; + } + + ret = fmt_mp_to_sp(&f_copy, f); + } + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + CLEAR_AFTER_FIELD(f, fmt.pix_mp); + v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + if (ops->vidioc_s_fmt_vid_out_mplane) { + ret = ops->vidioc_s_fmt_vid_out_mplane(file, + fh, f); + } else if (ops->vidioc_s_fmt_vid_out && + f->fmt.pix_mp.num_planes == 1) { + if (fmt_mp_to_sp(f, &f_copy)) + break; + ret = ops->vidioc_s_fmt_vid_out(file, + fh, &f_copy); + if (ret) + break; + + ret = fmt_mp_to_sp(&f_copy, f); + } break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); @@ -793,11 +1045,47 @@ static long __video_do_ioctl(struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_cap) + if (ops->vidioc_try_fmt_vid_cap) { ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); + } else if (ops->vidioc_try_fmt_vid_cap_mplane) { + if (fmt_sp_to_mp(f, &f_copy)) + break; + ret = ops->vidioc_try_fmt_vid_cap_mplane(file, + fh, &f_copy); + if (ret) + break; + + if (f_copy.fmt.pix_mp.num_planes > 1) { + /* Drivers shouldn't adjust from 1-plane + * to more than 1-plane formats */ + ret = -EBUSY; + WARN_ON(1); + break; + } + ret = fmt_mp_to_sp(&f_copy, f); + } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + CLEAR_AFTER_FIELD(f, fmt.pix_mp); + if (ops->vidioc_try_fmt_vid_cap_mplane) { + ret = ops->vidioc_try_fmt_vid_cap_mplane(file, + fh, f); + } else if (ops->vidioc_try_fmt_vid_cap && + f->fmt.pix_mp.num_planes == 1) { + if (fmt_mp_to_sp(f, &f_copy)) + break; + ret = ops->vidioc_try_fmt_vid_cap(file, + fh, &f_copy); + if (ret) + break; + + ret = fmt_sp_to_mp(&f_copy, f); + } + if (!ret) + v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); if (ops->vidioc_try_fmt_vid_overlay) @@ -806,11 +1094,47 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.pix); - if (ops->vidioc_try_fmt_vid_out) + if (ops->vidioc_try_fmt_vid_out) { ret = ops->vidioc_try_fmt_vid_out(file, fh, f); + } else if (ops->vidioc_try_fmt_vid_out_mplane) { + if (fmt_sp_to_mp(f, &f_copy)) + break; + ret = ops->vidioc_try_fmt_vid_out_mplane(file, + fh, &f_copy); + if (ret) + break; + + if (f_copy.fmt.pix_mp.num_planes > 1) { + /* Drivers shouldn't adjust from 1-plane + * to more than 1-plane formats */ + ret = -EBUSY; + WARN_ON(1); + break; + } + ret = fmt_mp_to_sp(&f_copy, f); + } if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + CLEAR_AFTER_FIELD(f, fmt.pix_mp); + if (ops->vidioc_try_fmt_vid_out_mplane) { + ret = ops->vidioc_try_fmt_vid_out_mplane(file, + fh, f); + } else if (ops->vidioc_try_fmt_vid_out && + f->fmt.pix_mp.num_planes == 1) { + if (fmt_mp_to_sp(f, &f_copy)) + break; + ret = ops->vidioc_try_fmt_vid_out(file, + fh, &f_copy); + if (ret) + break; + + ret = fmt_sp_to_mp(&f_copy, f); + } + if (!ret) + v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); + break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); if (ops->vidioc_try_fmt_vid_out_overlay) @@ -1975,7 +2299,7 @@ static unsigned long cmd_input_size(unsigned int cmd) switch (cmd) { CMDINSIZE(ENUM_FMT, fmtdesc, type); CMDINSIZE(G_FMT, format, type); - CMDINSIZE(QUERYBUF, buffer, type); + CMDINSIZE(QUERYBUF, buffer, length); CMDINSIZE(G_PARM, streamparm, type); CMDINSIZE(ENUMSTD, standard, index); CMDINSIZE(ENUMINPUT, input, index); @@ -2000,6 +2324,49 @@ static unsigned long cmd_input_size(unsigned int cmd) } } +static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, + void * __user *user_ptr, void ***kernel_ptr) +{ + int ret = 0; + + switch (cmd) { + case VIDIOC_QUERYBUF: + case VIDIOC_QBUF: + case VIDIOC_DQBUF: { + struct v4l2_buffer *buf = parg; + + if (V4L2_TYPE_IS_MULTIPLANAR(buf->type) && buf->length > 0) { + if (buf->length > VIDEO_MAX_PLANES) { + ret = -EINVAL; + break; + } + *user_ptr = (void __user *)buf->m.planes; + *kernel_ptr = (void **)&buf->m.planes; + *array_size = sizeof(struct v4l2_plane) * buf->length; + ret = 1; + } + break; + } + + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: { + struct v4l2_ext_controls *ctrls = parg; + + if (ctrls->count != 0) { + *user_ptr = (void __user *)ctrls->controls; + *kernel_ptr = (void **)&ctrls->controls; + *array_size = sizeof(struct v4l2_ext_control) + * ctrls->count; + ret = 1; + } + break; + } + } + + return ret; +} + long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2007,16 +2374,14 @@ long video_ioctl2(struct file *file, void *mbuf = NULL; void *parg = (void *)arg; long err = -EINVAL; - int is_ext_ctrl; - size_t ctrls_size = 0; + bool has_array_args; + size_t array_size = 0; void __user *user_ptr = NULL; + void **kernel_ptr = NULL; #ifdef __OLD_VIDIOC_ cmd = video_fix_command(cmd); #endif - is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || - cmd == VIDIOC_TRY_EXT_CTRLS); - /* Copy arguments into temp kernel buffer */ if (_IOC_DIR(cmd) != _IOC_NONE) { if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { @@ -2045,43 +2410,43 @@ long video_ioctl2(struct file *file, } } - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; + err = check_array_args(cmd, parg, &array_size, &user_ptr, &kernel_ptr); + if (err < 0) + goto out; + has_array_args = err; - /* In case of an error, tell the caller that it wasn't - a specific control that caused it. */ - p->error_idx = p->count; - user_ptr = (void __user *)p->controls; - if (p->count) { - ctrls_size = sizeof(struct v4l2_ext_control) * p->count; - /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ - mbuf = kmalloc(ctrls_size, GFP_KERNEL); - err = -ENOMEM; - if (NULL == mbuf) - goto out_ext_ctrl; - err = -EFAULT; - if (copy_from_user(mbuf, user_ptr, ctrls_size)) - goto out_ext_ctrl; - p->controls = mbuf; - } + if (has_array_args) { + /* + * When adding new types of array args, make sure that the + * parent argument to ioctl (which contains the pointer to the + * array) fits into sbuf (so that mbuf will still remain + * unused up to here). + */ + mbuf = kmalloc(array_size, GFP_KERNEL); + err = -ENOMEM; + if (NULL == mbuf) + goto out_array_args; + err = -EFAULT; + if (copy_from_user(mbuf, user_ptr, array_size)) + goto out_array_args; + *kernel_ptr = mbuf; } /* Handles IOCTL */ err = __video_do_ioctl(file, cmd, parg); if (err == -ENOIOCTLCMD) err = -EINVAL; - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; - p->controls = (void *)user_ptr; - if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) + if (has_array_args) { + *kernel_ptr = user_ptr; + if (copy_to_user(user_ptr, mbuf, array_size)) err = -EFAULT; - goto out_ext_ctrl; + goto out_array_args; } if (err < 0) goto out; -out_ext_ctrl: +out_array_args: /* Copy results into user buffer */ switch (_IOC_DIR(cmd)) { case _IOC_READ: -- cgit v1.2.2 From 52a3082fea41ffe77003be76ac1496d60bb7908e Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Thu, 29 Jul 2010 14:56:47 -0300 Subject: [media] v4l: Add compat functions for the multi-planar API Add multi-planar ioctl handling to the 32bit compatibility layer. [mchehab@redhat.com: Merged with a fixup patch from Pawel] Signed-off-by: Pawel Osciak Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-compat-ioctl32.c | 229 +++++++++++++++++++++++++----- 1 file changed, 195 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index dc82eb83c1d4..c19208a07b48 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -97,6 +97,14 @@ static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi return 0; } +static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, + struct v4l2_pix_format_mplane __user *up) +{ + if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane))) + return -EFAULT; + return 0; +} + static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up) { if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format))) @@ -104,6 +112,14 @@ static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pi return 0; } +static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp, + struct v4l2_pix_format_mplane __user *up) +{ + if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane))) + return -EFAULT; + return 0; +} + static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up) { if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format))) @@ -136,6 +152,7 @@ struct v4l2_format32 { enum v4l2_buf_type type; union { struct v4l2_pix_format pix; + struct v4l2_pix_format_mplane pix_mp; struct v4l2_window32 win; struct v4l2_vbi_format vbi; struct v4l2_sliced_vbi_format sliced; @@ -152,6 +169,10 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp, + &up->fmt.pix_mp); case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return get_v4l2_window32(&kp->fmt.win, &up->fmt.win); @@ -181,6 +202,10 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp, + &up->fmt.pix_mp); case V4L2_BUF_TYPE_VIDEO_OVERLAY: case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: return put_v4l2_window32(&kp->fmt.win, &up->fmt.win); @@ -232,6 +257,17 @@ static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 return 0; } +struct v4l2_plane32 { + __u32 bytesused; + __u32 length; + union { + __u32 mem_offset; + compat_long_t userptr; + } m; + __u32 data_offset; + __u32 reserved[11]; +}; + struct v4l2_buffer32 { __u32 index; enum v4l2_buf_type type; @@ -247,14 +283,64 @@ struct v4l2_buffer32 { union { __u32 offset; compat_long_t userptr; + compat_caddr_t planes; } m; __u32 length; __u32 input; __u32 reserved; }; +static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, + enum v4l2_memory memory) +{ + void __user *up_pln; + compat_long_t p; + + if (copy_in_user(up, up32, 2 * sizeof(__u32)) || + copy_in_user(&up->data_offset, &up32->data_offset, + sizeof(__u32))) + return -EFAULT; + + if (memory == V4L2_MEMORY_USERPTR) { + if (get_user(p, &up32->m.userptr)) + return -EFAULT; + up_pln = compat_ptr(p); + if (put_user((unsigned long)up_pln, &up->m.userptr)) + return -EFAULT; + } else { + if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, + sizeof(__u32))) + return -EFAULT; + } + + return 0; +} + +static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, + enum v4l2_memory memory) +{ + if (copy_in_user(up32, up, 2 * sizeof(__u32)) || + copy_in_user(&up32->data_offset, &up->data_offset, + sizeof(__u32))) + return -EFAULT; + + /* For MMAP, driver might've set up the offset, so copy it back. + * USERPTR stays the same (was userspace-provided), so no copying. */ + if (memory == V4L2_MEMORY_MMAP) + if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, + sizeof(__u32))) + return -EFAULT; + + return 0; +} + static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) { + struct v4l2_plane32 __user *uplane32; + struct v4l2_plane __user *uplane; + compat_caddr_t p; + int num_planes; + int ret; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || get_user(kp->index, &up->index) || @@ -263,33 +349,84 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user get_user(kp->memory, &up->memory) || get_user(kp->input, &up->input)) return -EFAULT; - switch (kp->memory) { - case V4L2_MEMORY_MMAP: - if (get_user(kp->length, &up->length) || - get_user(kp->m.offset, &up->m.offset)) + + if (V4L2_TYPE_IS_OUTPUT(kp->type)) + if (get_user(kp->bytesused, &up->bytesused) || + get_user(kp->field, &up->field) || + get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || + get_user(kp->timestamp.tv_usec, + &up->timestamp.tv_usec)) return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: - { - compat_long_t tmp; - if (get_user(kp->length, &up->length) || - get_user(tmp, &up->m.userptr)) + if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { + if (get_user(kp->length, &up->length)) return -EFAULT; - kp->m.userptr = (unsigned long)compat_ptr(tmp); + num_planes = kp->length; + if (num_planes == 0) { + kp->m.planes = NULL; + /* num_planes == 0 is legal, e.g. when userspace doesn't + * need planes array on DQBUF*/ + return 0; } - break; - case V4L2_MEMORY_OVERLAY: - if (get_user(kp->m.offset, &up->m.offset)) + + if (get_user(p, &up->m.planes)) return -EFAULT; - break; + + uplane32 = compat_ptr(p); + if (!access_ok(VERIFY_READ, uplane32, + num_planes * sizeof(struct v4l2_plane32))) + return -EFAULT; + + /* We don't really care if userspace decides to kill itself + * by passing a very big num_planes value */ + uplane = compat_alloc_user_space(num_planes * + sizeof(struct v4l2_plane)); + kp->m.planes = uplane; + + while (--num_planes >= 0) { + ret = get_v4l2_plane32(uplane, uplane32, kp->memory); + if (ret) + return ret; + ++uplane; + ++uplane32; + } + } else { + switch (kp->memory) { + case V4L2_MEMORY_MMAP: + if (get_user(kp->length, &up->length) || + get_user(kp->m.offset, &up->m.offset)) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: + { + compat_long_t tmp; + + if (get_user(kp->length, &up->length) || + get_user(tmp, &up->m.userptr)) + return -EFAULT; + + kp->m.userptr = (unsigned long)compat_ptr(tmp); + } + break; + case V4L2_MEMORY_OVERLAY: + if (get_user(kp->m.offset, &up->m.offset)) + return -EFAULT; + break; + } } + return 0; } static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up) { + struct v4l2_plane32 __user *uplane32; + struct v4l2_plane __user *uplane; + compat_caddr_t p; + int num_planes; + int ret; + if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) || put_user(kp->index, &up->index) || put_user(kp->type, &up->type) || @@ -297,22 +434,7 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user put_user(kp->memory, &up->memory) || put_user(kp->input, &up->input)) return -EFAULT; - switch (kp->memory) { - case V4L2_MEMORY_MMAP: - if (put_user(kp->length, &up->length) || - put_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; - case V4L2_MEMORY_USERPTR: - if (put_user(kp->length, &up->length) || - put_user(kp->m.userptr, &up->m.userptr)) - return -EFAULT; - break; - case V4L2_MEMORY_OVERLAY: - if (put_user(kp->m.offset, &up->m.offset)) - return -EFAULT; - break; - } + if (put_user(kp->bytesused, &up->bytesused) || put_user(kp->field, &up->field) || put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) || @@ -321,6 +443,43 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user put_user(kp->sequence, &up->sequence) || put_user(kp->reserved, &up->reserved)) return -EFAULT; + + if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { + num_planes = kp->length; + if (num_planes == 0) + return 0; + + uplane = kp->m.planes; + if (get_user(p, &up->m.planes)) + return -EFAULT; + uplane32 = compat_ptr(p); + + while (--num_planes >= 0) { + ret = put_v4l2_plane32(uplane, uplane32, kp->memory); + if (ret) + return ret; + ++uplane; + ++uplane32; + } + } else { + switch (kp->memory) { + case V4L2_MEMORY_MMAP: + if (put_user(kp->length, &up->length) || + put_user(kp->m.offset, &up->m.offset)) + return -EFAULT; + break; + case V4L2_MEMORY_USERPTR: + if (put_user(kp->length, &up->length) || + put_user(kp->m.userptr, &up->m.userptr)) + return -EFAULT; + break; + case V4L2_MEMORY_OVERLAY: + if (put_user(kp->m.offset, &up->m.offset)) + return -EFAULT; + break; + } + } + return 0; } @@ -442,12 +601,13 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control))) + if (!access_ok(VERIFY_READ, ucontrols, + n * sizeof(struct v4l2_ext_control32))) return -EFAULT; kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); kp->controls = kcontrols; while (--n >= 0) { - if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols))) + if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) return -EFAULT; if (ctrl_is_pointer(kcontrols->id)) { void __user *s; @@ -483,7 +643,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); - if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control))) + if (!access_ok(VERIFY_WRITE, ucontrols, + n * sizeof(struct v4l2_ext_control32))) return -EFAULT; while (--n >= 0) { -- cgit v1.2.2 From e23ccc0ad9258634e6d52cedf473b35dc34416c7 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Mon, 11 Oct 2010 10:56:41 -0300 Subject: [media] v4l: add videobuf2 Video for Linux 2 driver framework Videobuf2 is a Video for Linux 2 API-compatible driver framework for multimedia devices. It acts as an intermediate layer between userspace applications and device drivers. It also provides low-level, modular memory management functions for drivers. Videobuf2 eases driver development, reduces drivers' code size and aids in proper and consistent implementation of V4L2 API in drivers. Videobuf2 memory management backend is fully modular. This allows custom memory management routines for devices and platforms with non-standard memory management requirements to be plugged in, without changing the high-level buffer management functions and API. The framework provides: - implementations of streaming I/O V4L2 ioctls and file operations - high-level video buffer, video queue and state management functions - video buffer memory allocation and management Signed-off-by: Pawel Osciak Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 3 + drivers/media/video/Makefile | 2 + drivers/media/video/videobuf2-core.c | 1405 ++++++++++++++++++++++++++++++++++ 3 files changed, 1410 insertions(+) create mode 100644 drivers/media/video/videobuf2-core.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index aa021600e9df..a4a6aa703c26 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -44,6 +44,9 @@ config V4L2_MEM2MEM_DEV tristate depends on VIDEOBUF_GEN +config VIDEOBUF2_CORE + tristate + # # Multimedia Video device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index a509d317e258..6a1feba87869 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -111,6 +111,8 @@ obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o +obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o + obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c new file mode 100644 index 000000000000..b856bd105d77 --- /dev/null +++ b/drivers/media/video/videobuf2-core.c @@ -0,0 +1,1405 @@ +/* + * videobuf2-core.c - V4L2 driver helper framework + * + * Copyright (C) 2010 Samsung Electronics + * + * Author: Pawel Osciak + * Marek Szyprowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static int debug; +module_param(debug, int, 0644); + +#define dprintk(level, fmt, arg...) \ + do { \ + if (debug >= level) \ + printk(KERN_DEBUG "vb2: " fmt, ## arg); \ + } while (0) + +#define call_memop(q, plane, op, args...) \ + (((q)->mem_ops->op) ? \ + ((q)->mem_ops->op(args)) : 0) + +#define call_qop(q, op, args...) \ + (((q)->ops->op) ? ((q)->ops->op(args)) : 0) + +/** + * __vb2_buf_mem_alloc() - allocate video memory for the given buffer + */ +static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, + unsigned long *plane_sizes) +{ + struct vb2_queue *q = vb->vb2_queue; + void *mem_priv; + int plane; + + /* Allocate memory for all planes in this buffer */ + for (plane = 0; plane < vb->num_planes; ++plane) { + mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], + plane_sizes[plane]); + if (!mem_priv) + goto free; + + /* Associate allocator private data with this plane */ + vb->planes[plane].mem_priv = mem_priv; + vb->v4l2_planes[plane].length = plane_sizes[plane]; + } + + return 0; +free: + /* Free already allocated memory if one of the allocations failed */ + for (; plane > 0; --plane) + call_memop(q, plane, put, vb->planes[plane - 1].mem_priv); + + return -ENOMEM; +} + +/** + * __vb2_buf_mem_free() - free memory of the given buffer + */ +static void __vb2_buf_mem_free(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + unsigned int plane; + + for (plane = 0; plane < vb->num_planes; ++plane) { + call_memop(q, plane, put, vb->planes[plane].mem_priv); + vb->planes[plane].mem_priv = NULL; + dprintk(3, "Freed plane %d of buffer %d\n", + plane, vb->v4l2_buf.index); + } +} + +/** + * __vb2_buf_userptr_put() - release userspace memory associated with + * a USERPTR buffer + */ +static void __vb2_buf_userptr_put(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + unsigned int plane; + + for (plane = 0; plane < vb->num_planes; ++plane) { + void *mem_priv = vb->planes[plane].mem_priv; + + if (mem_priv) { + call_memop(q, plane, put_userptr, mem_priv); + vb->planes[plane].mem_priv = NULL; + } + } +} + +/** + * __setup_offsets() - setup unique offsets ("cookies") for every plane in + * every buffer on the queue + */ +static void __setup_offsets(struct vb2_queue *q) +{ + unsigned int buffer, plane; + struct vb2_buffer *vb; + unsigned long off = 0; + + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + vb = q->bufs[buffer]; + if (!vb) + continue; + + for (plane = 0; plane < vb->num_planes; ++plane) { + vb->v4l2_planes[plane].m.mem_offset = off; + + dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n", + buffer, plane, off); + + off += vb->v4l2_planes[plane].length; + off = PAGE_ALIGN(off); + } + } +} + +/** + * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type) + * video buffer memory for all buffers/planes on the queue and initializes the + * queue + * + * Returns the number of buffers successfully allocated. + */ +static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory, + unsigned int num_buffers, unsigned int num_planes, + unsigned long plane_sizes[]) +{ + unsigned int buffer; + struct vb2_buffer *vb; + int ret; + + for (buffer = 0; buffer < num_buffers; ++buffer) { + /* Allocate videobuf buffer structures */ + vb = kzalloc(q->buf_struct_size, GFP_KERNEL); + if (!vb) { + dprintk(1, "Memory alloc for buffer struct failed\n"); + break; + } + + /* Length stores number of planes for multiplanar buffers */ + if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) + vb->v4l2_buf.length = num_planes; + + vb->state = VB2_BUF_STATE_DEQUEUED; + vb->vb2_queue = q; + vb->num_planes = num_planes; + vb->v4l2_buf.index = buffer; + vb->v4l2_buf.type = q->type; + vb->v4l2_buf.memory = memory; + + /* Allocate video buffer memory for the MMAP type */ + if (memory == V4L2_MEMORY_MMAP) { + ret = __vb2_buf_mem_alloc(vb, plane_sizes); + if (ret) { + dprintk(1, "Failed allocating memory for " + "buffer %d\n", buffer); + kfree(vb); + break; + } + /* + * Call the driver-provided buffer initialization + * callback, if given. An error in initialization + * results in queue setup failure. + */ + ret = call_qop(q, buf_init, vb); + if (ret) { + dprintk(1, "Buffer %d %p initialization" + " failed\n", buffer, vb); + __vb2_buf_mem_free(vb); + kfree(vb); + break; + } + } + + q->bufs[buffer] = vb; + } + + q->num_buffers = buffer; + + __setup_offsets(q); + + dprintk(1, "Allocated %d buffers, %d plane(s) each\n", + q->num_buffers, num_planes); + + return buffer; +} + +/** + * __vb2_free_mem() - release all video buffer memory for a given queue + */ +static void __vb2_free_mem(struct vb2_queue *q) +{ + unsigned int buffer; + struct vb2_buffer *vb; + + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + vb = q->bufs[buffer]; + if (!vb) + continue; + + /* Free MMAP buffers or release USERPTR buffers */ + if (q->memory == V4L2_MEMORY_MMAP) + __vb2_buf_mem_free(vb); + else + __vb2_buf_userptr_put(vb); + } +} + +/** + * __vb2_queue_free() - free the queue - video memory and related information + * and return the queue to an uninitialized state. Might be called even if the + * queue has already been freed. + */ +static int __vb2_queue_free(struct vb2_queue *q) +{ + unsigned int buffer; + + /* Call driver-provided cleanup function for each buffer, if provided */ + if (q->ops->buf_cleanup) { + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + if (NULL == q->bufs[buffer]) + continue; + q->ops->buf_cleanup(q->bufs[buffer]); + } + } + + /* Release video buffer memory */ + __vb2_free_mem(q); + + /* Free videobuf buffers */ + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + kfree(q->bufs[buffer]); + q->bufs[buffer] = NULL; + } + + q->num_buffers = 0; + q->memory = 0; + + return 0; +} + +/** + * __verify_planes_array() - verify that the planes array passed in struct + * v4l2_buffer from userspace can be safely used + */ +static int __verify_planes_array(struct vb2_buffer *vb, struct v4l2_buffer *b) +{ + /* Is memory for copying plane information present? */ + if (NULL == b->m.planes) { + dprintk(1, "Multi-planar buffer passed but " + "planes array not provided\n"); + return -EINVAL; + } + + if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) { + dprintk(1, "Incorrect planes array length, " + "expected %d, got %d\n", vb->num_planes, b->length); + return -EINVAL; + } + + return 0; +} + +/** + * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be + * returned to userspace + */ +static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) +{ + struct vb2_queue *q = vb->vb2_queue; + int ret = 0; + + /* Copy back data such as timestamp, input, etc. */ + memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); + b->input = vb->v4l2_buf.input; + b->reserved = vb->v4l2_buf.reserved; + + if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { + ret = __verify_planes_array(vb, b); + if (ret) + return ret; + + /* + * Fill in plane-related data if userspace provided an array + * for it. The memory and size is verified above. + */ + memcpy(b->m.planes, vb->v4l2_planes, + b->length * sizeof(struct v4l2_plane)); + } else { + /* + * We use length and offset in v4l2_planes array even for + * single-planar buffers, but userspace does not. + */ + b->length = vb->v4l2_planes[0].length; + b->bytesused = vb->v4l2_planes[0].bytesused; + if (q->memory == V4L2_MEMORY_MMAP) + b->m.offset = vb->v4l2_planes[0].m.mem_offset; + else if (q->memory == V4L2_MEMORY_USERPTR) + b->m.userptr = vb->v4l2_planes[0].m.userptr; + } + + b->flags = 0; + + switch (vb->state) { + case VB2_BUF_STATE_QUEUED: + case VB2_BUF_STATE_ACTIVE: + b->flags |= V4L2_BUF_FLAG_QUEUED; + break; + case VB2_BUF_STATE_ERROR: + b->flags |= V4L2_BUF_FLAG_ERROR; + /* fall through */ + case VB2_BUF_STATE_DONE: + b->flags |= V4L2_BUF_FLAG_DONE; + break; + case VB2_BUF_STATE_DEQUEUED: + /* nothing */ + break; + } + + if (vb->num_planes_mapped == vb->num_planes) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + return ret; +} + +/** + * vb2_querybuf() - query video buffer information + * @q: videobuf queue + * @b: buffer struct passed from userspace to vidioc_querybuf handler + * in driver + * + * Should be called from vidioc_querybuf ioctl handler in driver. + * This function will verify the passed v4l2_buffer structure and fill the + * relevant information for the userspace. + * + * The return values from this function are intended to be directly returned + * from vidioc_querybuf handler in driver. + */ +int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) +{ + struct vb2_buffer *vb; + + if (b->type != q->type) { + dprintk(1, "querybuf: wrong buffer type\n"); + return -EINVAL; + } + + if (b->index >= q->num_buffers) { + dprintk(1, "querybuf: buffer index out of range\n"); + return -EINVAL; + } + vb = q->bufs[b->index]; + + return __fill_v4l2_buffer(vb, b); +} +EXPORT_SYMBOL(vb2_querybuf); + +/** + * __verify_userptr_ops() - verify that all memory operations required for + * USERPTR queue type have been provided + */ +static int __verify_userptr_ops(struct vb2_queue *q) +{ + if (!(q->io_modes & VB2_USERPTR) || !q->mem_ops->get_userptr || + !q->mem_ops->put_userptr) + return -EINVAL; + + return 0; +} + +/** + * __verify_mmap_ops() - verify that all memory operations required for + * MMAP queue type have been provided + */ +static int __verify_mmap_ops(struct vb2_queue *q) +{ + if (!(q->io_modes & VB2_MMAP) || !q->mem_ops->alloc || + !q->mem_ops->put || !q->mem_ops->mmap) + return -EINVAL; + + return 0; +} + +/** + * __buffers_in_use() - return true if any buffers on the queue are in use and + * the queue cannot be freed (by the means of REQBUFS(0)) call + */ +static bool __buffers_in_use(struct vb2_queue *q) +{ + unsigned int buffer, plane; + struct vb2_buffer *vb; + + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + vb = q->bufs[buffer]; + for (plane = 0; plane < vb->num_planes; ++plane) { + /* + * If num_users() has not been provided, call_memop + * will return 0, apparently nobody cares about this + * case anyway. If num_users() returns more than 1, + * we are not the only user of the plane's memory. + */ + if (call_memop(q, plane, num_users, + vb->planes[plane].mem_priv) > 1) + return true; + } + } + + return false; +} + +/** + * vb2_reqbufs() - Initiate streaming + * @q: videobuf2 queue + * @req: struct passed from userspace to vidioc_reqbufs handler in driver + * + * Should be called from vidioc_reqbufs ioctl handler of a driver. + * This function: + * 1) verifies streaming parameters passed from the userspace, + * 2) sets up the queue, + * 3) negotiates number of buffers and planes per buffer with the driver + * to be used during streaming, + * 4) allocates internal buffer structures (struct vb2_buffer), according to + * the agreed parameters, + * 5) for MMAP memory type, allocates actual video memory, using the + * memory handling/allocation routines provided during queue initialization + * + * If req->count is 0, all the memory will be freed instead. + * If the queue has been allocated previously (by a previous vb2_reqbufs) call + * and the queue is not busy, memory will be reallocated. + * + * The return values from this function are intended to be directly returned + * from vidioc_reqbufs handler in driver. + */ +int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) +{ + unsigned int num_buffers, num_planes; + unsigned long plane_sizes[VIDEO_MAX_PLANES]; + int ret = 0; + + if (req->memory != V4L2_MEMORY_MMAP + && req->memory != V4L2_MEMORY_USERPTR) { + dprintk(1, "reqbufs: unsupported memory type\n"); + return -EINVAL; + } + + if (req->type != q->type) { + dprintk(1, "reqbufs: requested type is incorrect\n"); + return -EINVAL; + } + + if (q->streaming) { + dprintk(1, "reqbufs: streaming active\n"); + return -EBUSY; + } + + /* + * Make sure all the required memory ops for given memory type + * are available. + */ + if (req->memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) { + dprintk(1, "reqbufs: MMAP for current setup unsupported\n"); + return -EINVAL; + } + + if (req->memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) { + dprintk(1, "reqbufs: USERPTR for current setup unsupported\n"); + return -EINVAL; + } + + if (req->count == 0 || q->num_buffers != 0) { + /* + * We already have buffers allocated, so first check if they + * are not in use and can be freed. + */ + if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) { + dprintk(1, "reqbufs: memory in use, cannot free\n"); + return -EBUSY; + } + + ret = __vb2_queue_free(q); + if (ret != 0) + return ret; + } + + /* + * Make sure the requested values and current defaults are sane. + */ + num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); + memset(plane_sizes, 0, sizeof(plane_sizes)); + memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + + /* + * Ask the driver how many buffers and planes per buffer it requires. + * Driver also sets the size and allocator context for each plane. + */ + ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, + plane_sizes, q->alloc_ctx); + if (ret) + return ret; + + /* Finally, allocate buffers and video memory */ + ret = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes, + plane_sizes); + if (ret < 0) { + dprintk(1, "Memory allocation failed with error: %d\n", ret); + return ret; + } + + /* + * Check if driver can handle the allocated number of buffers. + */ + if (ret < num_buffers) { + unsigned int orig_num_buffers; + + orig_num_buffers = num_buffers = ret; + ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes, + plane_sizes, q->alloc_ctx); + if (ret) + goto free_mem; + + if (orig_num_buffers < num_buffers) { + ret = -ENOMEM; + goto free_mem; + } + + /* + * Ok, driver accepted smaller number of buffers. + */ + ret = num_buffers; + } + + q->memory = req->memory; + + /* + * Return the number of successfully allocated buffers + * to the userspace. + */ + req->count = ret; + + return 0; + +free_mem: + __vb2_queue_free(q); + return ret; +} +EXPORT_SYMBOL_GPL(vb2_reqbufs); + +/** + * vb2_plane_vaddr() - Return a kernel virtual address of a given plane + * @vb: vb2_buffer to which the plane in question belongs to + * @plane_no: plane number for which the address is to be returned + * + * This function returns a kernel virtual address of a given plane if + * such a mapping exist, NULL otherwise. + */ +void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no) +{ + struct vb2_queue *q = vb->vb2_queue; + + if (plane_no > vb->num_planes) + return NULL; + + return call_memop(q, plane_no, vaddr, vb->planes[plane_no].mem_priv); + +} +EXPORT_SYMBOL_GPL(vb2_plane_vaddr); + +/** + * vb2_plane_cookie() - Return allocator specific cookie for the given plane + * @vb: vb2_buffer to which the plane in question belongs to + * @plane_no: plane number for which the cookie is to be returned + * + * This function returns an allocator specific cookie for a given plane if + * available, NULL otherwise. The allocator should provide some simple static + * inline function, which would convert this cookie to the allocator specific + * type that can be used directly by the driver to access the buffer. This can + * be for example physical address, pointer to scatter list or IOMMU mapping. + */ +void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no) +{ + struct vb2_queue *q = vb->vb2_queue; + + if (plane_no > vb->num_planes) + return NULL; + + return call_memop(q, plane_no, cookie, vb->planes[plane_no].mem_priv); +} +EXPORT_SYMBOL_GPL(vb2_plane_cookie); + +/** + * vb2_buffer_done() - inform videobuf that an operation on a buffer is finished + * @vb: vb2_buffer returned from the driver + * @state: either VB2_BUF_STATE_DONE if the operation finished successfully + * or VB2_BUF_STATE_ERROR if the operation finished with an error + * + * This function should be called by the driver after a hardware operation on + * a buffer is finished and the buffer may be returned to userspace. The driver + * cannot use this buffer anymore until it is queued back to it by videobuf + * by the means of buf_queue callback. Only buffers previously queued to the + * driver by buf_queue can be passed to this function. + */ +void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) +{ + struct vb2_queue *q = vb->vb2_queue; + unsigned long flags; + + if (vb->state != VB2_BUF_STATE_ACTIVE) + return; + + if (state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR) + return; + + dprintk(4, "Done processing on buffer %d, state: %d\n", + vb->v4l2_buf.index, vb->state); + + /* Add the buffer to the done buffers list */ + spin_lock_irqsave(&q->done_lock, flags); + vb->state = state; + list_add_tail(&vb->done_entry, &q->done_list); + atomic_dec(&q->queued_count); + spin_unlock_irqrestore(&q->done_lock, flags); + + /* Inform any processes that may be waiting for buffers */ + wake_up(&q->done_wq); +} +EXPORT_SYMBOL_GPL(vb2_buffer_done); + +/** + * __fill_vb2_buffer() - fill a vb2_buffer with information provided in + * a v4l2_buffer by the userspace + */ +static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, + struct v4l2_plane *v4l2_planes) +{ + unsigned int plane; + int ret; + + if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { + /* + * Verify that the userspace gave us a valid array for + * plane information. + */ + ret = __verify_planes_array(vb, b); + if (ret) + return ret; + + /* Fill in driver-provided information for OUTPUT types */ + if (V4L2_TYPE_IS_OUTPUT(b->type)) { + /* + * Will have to go up to b->length when API starts + * accepting variable number of planes. + */ + for (plane = 0; plane < vb->num_planes; ++plane) { + v4l2_planes[plane].bytesused = + b->m.planes[plane].bytesused; + v4l2_planes[plane].data_offset = + b->m.planes[plane].data_offset; + } + } + + if (b->memory == V4L2_MEMORY_USERPTR) { + for (plane = 0; plane < vb->num_planes; ++plane) { + v4l2_planes[plane].m.userptr = + b->m.planes[plane].m.userptr; + v4l2_planes[plane].length = + b->m.planes[plane].length; + } + } + } else { + /* + * Single-planar buffers do not use planes array, + * so fill in relevant v4l2_buffer struct fields instead. + * In videobuf we use our internal V4l2_planes struct for + * single-planar buffers as well, for simplicity. + */ + if (V4L2_TYPE_IS_OUTPUT(b->type)) + v4l2_planes[0].bytesused = b->bytesused; + + if (b->memory == V4L2_MEMORY_USERPTR) { + v4l2_planes[0].m.userptr = b->m.userptr; + v4l2_planes[0].length = b->length; + } + } + + vb->v4l2_buf.field = b->field; + vb->v4l2_buf.timestamp = b->timestamp; + + return 0; +} + +/** + * __qbuf_userptr() - handle qbuf of a USERPTR buffer + */ +static int __qbuf_userptr(struct vb2_buffer *vb, struct v4l2_buffer *b) +{ + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + struct vb2_queue *q = vb->vb2_queue; + void *mem_priv; + unsigned int plane; + int ret; + int write = !V4L2_TYPE_IS_OUTPUT(q->type); + + /* Verify and copy relevant information provided by the userspace */ + ret = __fill_vb2_buffer(vb, b, planes); + if (ret) + return ret; + + for (plane = 0; plane < vb->num_planes; ++plane) { + /* Skip the plane if already verified */ + if (vb->v4l2_planes[plane].m.userptr == planes[plane].m.userptr + && vb->v4l2_planes[plane].length == planes[plane].length) + continue; + + dprintk(3, "qbuf: userspace address for plane %d changed, " + "reacquiring memory\n", plane); + + /* Release previously acquired memory if present */ + if (vb->planes[plane].mem_priv) + call_memop(q, plane, put_userptr, + vb->planes[plane].mem_priv); + + vb->planes[plane].mem_priv = NULL; + + /* Acquire each plane's memory */ + if (q->mem_ops->get_userptr) { + mem_priv = q->mem_ops->get_userptr(q->alloc_ctx[plane], + planes[plane].m.userptr, + planes[plane].length, + write); + if (IS_ERR(mem_priv)) { + dprintk(1, "qbuf: failed acquiring userspace " + "memory for plane %d\n", plane); + ret = PTR_ERR(mem_priv); + goto err; + } + vb->planes[plane].mem_priv = mem_priv; + } + } + + /* + * Call driver-specific initialization on the newly acquired buffer, + * if provided. + */ + ret = call_qop(q, buf_init, vb); + if (ret) { + dprintk(1, "qbuf: buffer initialization failed\n"); + goto err; + } + + /* + * Now that everything is in order, copy relevant information + * provided by userspace. + */ + for (plane = 0; plane < vb->num_planes; ++plane) + vb->v4l2_planes[plane] = planes[plane]; + + return 0; +err: + /* In case of errors, release planes that were already acquired */ + for (; plane > 0; --plane) { + call_memop(q, plane, put_userptr, + vb->planes[plane - 1].mem_priv); + vb->planes[plane - 1].mem_priv = NULL; + } + + return ret; +} + +/** + * __qbuf_mmap() - handle qbuf of an MMAP buffer + */ +static int __qbuf_mmap(struct vb2_buffer *vb, struct v4l2_buffer *b) +{ + return __fill_vb2_buffer(vb, b, vb->v4l2_planes); +} + +/** + * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing + */ +static void __enqueue_in_driver(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + + vb->state = VB2_BUF_STATE_ACTIVE; + atomic_inc(&q->queued_count); + q->ops->buf_queue(vb); +} + +/** + * vb2_qbuf() - Queue a buffer from userspace + * @q: videobuf2 queue + * @b: buffer structure passed from userspace to vidioc_qbuf handler + * in driver + * + * Should be called from vidioc_qbuf ioctl handler of a driver. + * This function: + * 1) verifies the passed buffer, + * 2) calls buf_prepare callback in the driver (if provided), in which + * driver-specific buffer initialization can be performed, + * 3) if streaming is on, queues the buffer in driver by the means of buf_queue + * callback for processing. + * + * The return values from this function are intended to be directly returned + * from vidioc_qbuf handler in driver. + */ +int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) +{ + struct vb2_buffer *vb; + int ret = 0; + + if (b->type != q->type) { + dprintk(1, "qbuf: invalid buffer type\n"); + return -EINVAL; + } + + if (b->index >= q->num_buffers) { + dprintk(1, "qbuf: buffer index out of range\n"); + return -EINVAL; + } + + vb = q->bufs[b->index]; + if (NULL == vb) { + /* Should never happen */ + dprintk(1, "qbuf: buffer is NULL\n"); + return -EINVAL; + } + + if (b->memory != q->memory) { + dprintk(1, "qbuf: invalid memory type\n"); + return -EINVAL; + } + + if (vb->state != VB2_BUF_STATE_DEQUEUED) { + dprintk(1, "qbuf: buffer already in use\n"); + return -EINVAL; + } + + if (q->memory == V4L2_MEMORY_MMAP) + ret = __qbuf_mmap(vb, b); + else if (q->memory == V4L2_MEMORY_USERPTR) + ret = __qbuf_userptr(vb, b); + else { + WARN(1, "Invalid queue type\n"); + return -EINVAL; + } + + if (ret) + return ret; + + ret = call_qop(q, buf_prepare, vb); + if (ret) { + dprintk(1, "qbuf: buffer preparation failed\n"); + return ret; + } + + /* + * Add to the queued buffers list, a buffer will stay on it until + * dequeued in dqbuf. + */ + list_add_tail(&vb->queued_entry, &q->queued_list); + vb->state = VB2_BUF_STATE_QUEUED; + + /* + * If already streaming, give the buffer to driver for processing. + * If not, the buffer will be given to driver on next streamon. + */ + if (q->streaming) + __enqueue_in_driver(vb); + + dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index); + return 0; +} +EXPORT_SYMBOL_GPL(vb2_qbuf); + +/** + * __vb2_wait_for_done_vb() - wait for a buffer to become available + * for dequeuing + * + * Will sleep if required for nonblocking == false. + */ +static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) +{ + /* + * All operations on vb_done_list are performed under done_lock + * spinlock protection. However, buffers may be removed from + * it and returned to userspace only while holding both driver's + * lock and the done_lock spinlock. Thus we can be sure that as + * long as we hold the driver's lock, the list will remain not + * empty if list_empty() check succeeds. + */ + + for (;;) { + int ret; + + if (!q->streaming) { + dprintk(1, "Streaming off, will not wait for buffers\n"); + return -EINVAL; + } + + if (!list_empty(&q->done_list)) { + /* + * Found a buffer that we were waiting for. + */ + break; + } + + if (nonblocking) { + dprintk(1, "Nonblocking and no buffers to dequeue, " + "will not wait\n"); + return -EAGAIN; + } + + /* + * We are streaming and blocking, wait for another buffer to + * become ready or for streamoff. Driver's lock is released to + * allow streamoff or qbuf to be called while waiting. + */ + call_qop(q, wait_prepare, q); + + /* + * All locks have been released, it is safe to sleep now. + */ + dprintk(3, "Will sleep waiting for buffers\n"); + ret = wait_event_interruptible(q->done_wq, + !list_empty(&q->done_list) || !q->streaming); + + /* + * We need to reevaluate both conditions again after reacquiring + * the locks or return an error if one occurred. + */ + call_qop(q, wait_finish, q); + if (ret) + return ret; + } + return 0; +} + +/** + * __vb2_get_done_vb() - get a buffer ready for dequeuing + * + * Will sleep if required for nonblocking == false. + */ +static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, + int nonblocking) +{ + unsigned long flags; + int ret; + + /* + * Wait for at least one buffer to become available on the done_list. + */ + ret = __vb2_wait_for_done_vb(q, nonblocking); + if (ret) + return ret; + + /* + * Driver's lock has been held since we last verified that done_list + * is not empty, so no need for another list_empty(done_list) check. + */ + spin_lock_irqsave(&q->done_lock, flags); + *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); + list_del(&(*vb)->done_entry); + spin_unlock_irqrestore(&q->done_lock, flags); + + return 0; +} + +/** + * vb2_wait_for_all_buffers() - wait until all buffers are given back to vb2 + * @q: videobuf2 queue + * + * This function will wait until all buffers that have been given to the driver + * by buf_queue() are given back to vb2 with vb2_buffer_done(). It doesn't call + * wait_prepare, wait_finish pair. It is intended to be called with all locks + * taken, for example from stop_streaming() callback. + */ +int vb2_wait_for_all_buffers(struct vb2_queue *q) +{ + if (!q->streaming) { + dprintk(1, "Streaming off, will not wait for buffers\n"); + return -EINVAL; + } + + wait_event(q->done_wq, !atomic_read(&q->queued_count)); + return 0; +} +EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); + +/** + * vb2_dqbuf() - Dequeue a buffer to the userspace + * @q: videobuf2 queue + * @b: buffer structure passed from userspace to vidioc_dqbuf handler + * in driver + * @nonblocking: if true, this call will not sleep waiting for a buffer if no + * buffers ready for dequeuing are present. Normally the driver + * would be passing (file->f_flags & O_NONBLOCK) here + * + * Should be called from vidioc_dqbuf ioctl handler of a driver. + * This function: + * 1) verifies the passed buffer, + * 2) calls buf_finish callback in the driver (if provided), in which + * driver can perform any additional operations that may be required before + * returning the buffer to userspace, such as cache sync, + * 3) the buffer struct members are filled with relevant information for + * the userspace. + * + * The return values from this function are intended to be directly returned + * from vidioc_dqbuf handler in driver. + */ +int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) +{ + struct vb2_buffer *vb = NULL; + int ret; + + if (b->type != q->type) { + dprintk(1, "dqbuf: invalid buffer type\n"); + return -EINVAL; + } + + ret = __vb2_get_done_vb(q, &vb, nonblocking); + if (ret < 0) { + dprintk(1, "dqbuf: error getting next done buffer\n"); + return ret; + } + + ret = call_qop(q, buf_finish, vb); + if (ret) { + dprintk(1, "dqbuf: buffer finish failed\n"); + return ret; + } + + switch (vb->state) { + case VB2_BUF_STATE_DONE: + dprintk(3, "dqbuf: Returning done buffer\n"); + break; + case VB2_BUF_STATE_ERROR: + dprintk(3, "dqbuf: Returning done buffer with errors\n"); + break; + default: + dprintk(1, "dqbuf: Invalid buffer state\n"); + return -EINVAL; + } + + /* Fill buffer information for the userspace */ + __fill_v4l2_buffer(vb, b); + /* Remove from videobuf queue */ + list_del(&vb->queued_entry); + + dprintk(1, "dqbuf of buffer %d, with state %d\n", + vb->v4l2_buf.index, vb->state); + + vb->state = VB2_BUF_STATE_DEQUEUED; + return 0; +} +EXPORT_SYMBOL_GPL(vb2_dqbuf); + +/** + * vb2_streamon - start streaming + * @q: videobuf2 queue + * @type: type argument passed from userspace to vidioc_streamon handler + * + * Should be called from vidioc_streamon handler of a driver. + * This function: + * 1) verifies current state + * 2) starts streaming and passes any previously queued buffers to the driver + * + * The return values from this function are intended to be directly returned + * from vidioc_streamon handler in the driver. + */ +int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) +{ + struct vb2_buffer *vb; + + if (type != q->type) { + dprintk(1, "streamon: invalid stream type\n"); + return -EINVAL; + } + + if (q->streaming) { + dprintk(1, "streamon: already streaming\n"); + return -EBUSY; + } + + /* + * Cannot start streaming on an OUTPUT device if no buffers have + * been queued yet. + */ + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + if (list_empty(&q->queued_list)) { + dprintk(1, "streamon: no output buffers queued\n"); + return -EINVAL; + } + } + + q->streaming = 1; + + /* + * Let driver notice that streaming state has been enabled. + */ + call_qop(q, start_streaming, q); + + /* + * If any buffers were queued before streamon, + * we can now pass them to driver for processing. + */ + list_for_each_entry(vb, &q->queued_list, queued_entry) + __enqueue_in_driver(vb); + + dprintk(3, "Streamon successful\n"); + return 0; +} +EXPORT_SYMBOL_GPL(vb2_streamon); + +/** + * __vb2_queue_cancel() - cancel and stop (pause) streaming + * + * Removes all queued buffers from driver's queue and all buffers queued by + * userspace from videobuf's queue. Returns to state after reqbufs. + */ +static void __vb2_queue_cancel(struct vb2_queue *q) +{ + unsigned int i; + + /* + * Tell driver to stop all transactions and release all queued + * buffers. + */ + if (q->streaming) + call_qop(q, stop_streaming, q); + q->streaming = 0; + + /* + * Remove all buffers from videobuf's list... + */ + INIT_LIST_HEAD(&q->queued_list); + /* + * ...and done list; userspace will not receive any buffers it + * has not already dequeued before initiating cancel. + */ + INIT_LIST_HEAD(&q->done_list); + wake_up_all(&q->done_wq); + + /* + * Reinitialize all buffers for next use. + */ + for (i = 0; i < q->num_buffers; ++i) + q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED; +} + +/** + * vb2_streamoff - stop streaming + * @q: videobuf2 queue + * @type: type argument passed from userspace to vidioc_streamoff handler + * + * Should be called from vidioc_streamoff handler of a driver. + * This function: + * 1) verifies current state, + * 2) stop streaming and dequeues any queued buffers, including those previously + * passed to the driver (after waiting for the driver to finish). + * + * This call can be used for pausing playback. + * The return values from this function are intended to be directly returned + * from vidioc_streamoff handler in the driver + */ +int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) +{ + if (type != q->type) { + dprintk(1, "streamoff: invalid stream type\n"); + return -EINVAL; + } + + if (!q->streaming) { + dprintk(1, "streamoff: not streaming\n"); + return -EINVAL; + } + + /* + * Cancel will pause streaming and remove all buffers from the driver + * and videobuf, effectively returning control over them to userspace. + */ + __vb2_queue_cancel(q); + + dprintk(3, "Streamoff successful\n"); + return 0; +} +EXPORT_SYMBOL_GPL(vb2_streamoff); + +/** + * __find_plane_by_offset() - find plane associated with the given offset off + */ +static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, + unsigned int *_buffer, unsigned int *_plane) +{ + struct vb2_buffer *vb; + unsigned int buffer, plane; + + /* + * Go over all buffers and their planes, comparing the given offset + * with an offset assigned to each plane. If a match is found, + * return its buffer and plane numbers. + */ + for (buffer = 0; buffer < q->num_buffers; ++buffer) { + vb = q->bufs[buffer]; + + for (plane = 0; plane < vb->num_planes; ++plane) { + if (vb->v4l2_planes[plane].m.mem_offset == off) { + *_buffer = buffer; + *_plane = plane; + return 0; + } + } + } + + return -EINVAL; +} + +/** + * vb2_mmap() - map video buffers into application address space + * @q: videobuf2 queue + * @vma: vma passed to the mmap file operation handler in the driver + * + * Should be called from mmap file operation handler of a driver. + * This function maps one plane of one of the available video buffers to + * userspace. To map whole video memory allocated on reqbufs, this function + * has to be called once per each plane per each buffer previously allocated. + * + * When the userspace application calls mmap, it passes to it an offset returned + * to it earlier by the means of vidioc_querybuf handler. That offset acts as + * a "cookie", which is then used to identify the plane to be mapped. + * This function finds a plane with a matching offset and a mapping is performed + * by the means of a provided memory operation. + * + * The return values from this function are intended to be directly returned + * from the mmap handler in driver. + */ +int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) +{ + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + struct vb2_plane *vb_plane; + struct vb2_buffer *vb; + unsigned int buffer, plane; + int ret; + + if (q->memory != V4L2_MEMORY_MMAP) { + dprintk(1, "Queue is not currently set up for mmap\n"); + return -EINVAL; + } + + /* + * Check memory area access mode. + */ + if (!(vma->vm_flags & VM_SHARED)) { + dprintk(1, "Invalid vma flags, VM_SHARED needed\n"); + return -EINVAL; + } + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + if (!(vma->vm_flags & VM_WRITE)) { + dprintk(1, "Invalid vma flags, VM_WRITE needed\n"); + return -EINVAL; + } + } else { + if (!(vma->vm_flags & VM_READ)) { + dprintk(1, "Invalid vma flags, VM_READ needed\n"); + return -EINVAL; + } + } + + /* + * Find the plane corresponding to the offset passed by userspace. + */ + ret = __find_plane_by_offset(q, off, &buffer, &plane); + if (ret) + return ret; + + vb = q->bufs[buffer]; + vb_plane = &vb->planes[plane]; + + ret = q->mem_ops->mmap(vb_plane->mem_priv, vma); + if (ret) + return ret; + + vb_plane->mapped = 1; + vb->num_planes_mapped++; + + dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane); + return 0; +} +EXPORT_SYMBOL_GPL(vb2_mmap); + + +/** + * vb2_poll() - implements poll userspace operation + * @q: videobuf2 queue + * @file: file argument passed to the poll file operation handler + * @wait: wait argument passed to the poll file operation handler + * + * This function implements poll file operation handler for a driver. + * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will + * be informed that the file descriptor of a video device is available for + * reading. + * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor + * will be reported as available for writing. + * + * The return values from this function are intended to be directly returned + * from poll handler in driver. + */ +unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) +{ + unsigned long flags; + struct vb2_buffer *vb = NULL; + + /* + * There is nothing to wait for if no buffers have already been queued. + */ + if (list_empty(&q->queued_list)) + return POLLERR; + + poll_wait(file, &q->done_wq, wait); + + /* + * Take first buffer available for dequeuing. + */ + spin_lock_irqsave(&q->done_lock, flags); + if (!list_empty(&q->done_list)) + vb = list_first_entry(&q->done_list, struct vb2_buffer, + done_entry); + spin_unlock_irqrestore(&q->done_lock, flags); + + if (vb && (vb->state == VB2_BUF_STATE_DONE + || vb->state == VB2_BUF_STATE_ERROR)) { + return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM : + POLLIN | POLLRDNORM; + } + return 0; +} +EXPORT_SYMBOL_GPL(vb2_poll); + +/** + * vb2_queue_init() - initialize a videobuf2 queue + * @q: videobuf2 queue; this structure should be allocated in driver + * + * The vb2_queue structure should be allocated by the driver. The driver is + * responsible of clearing it's content and setting initial values for some + * required entries before calling this function. + * q->ops, q->mem_ops, q->type and q->io_modes are mandatory. Please refer + * to the struct vb2_queue description in include/media/videobuf2-core.h + * for more information. + */ +int vb2_queue_init(struct vb2_queue *q) +{ + BUG_ON(!q); + BUG_ON(!q->ops); + BUG_ON(!q->mem_ops); + BUG_ON(!q->type); + BUG_ON(!q->io_modes); + + BUG_ON(!q->ops->queue_setup); + BUG_ON(!q->ops->buf_queue); + + INIT_LIST_HEAD(&q->queued_list); + INIT_LIST_HEAD(&q->done_list); + spin_lock_init(&q->done_lock); + init_waitqueue_head(&q->done_wq); + + if (q->buf_struct_size == 0) + q->buf_struct_size = sizeof(struct vb2_buffer); + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_queue_init); + +/** + * vb2_queue_release() - stop streaming, release the queue and free memory + * @q: videobuf2 queue + * + * This function stops streaming and performs necessary clean ups, including + * freeing video buffer memory. The driver is responsible for freeing + * the vb2_queue structure itself. + */ +void vb2_queue_release(struct vb2_queue *q) +{ + __vb2_queue_cancel(q); + __vb2_queue_free(q); +} +EXPORT_SYMBOL_GPL(vb2_queue_release); + +MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2"); +MODULE_AUTHOR("Pawel Osciak, Marek Szyprowski"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 004cc3781c40a577b0349eef825efaaebc42dd43 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 9 Dec 2010 10:20:47 -0300 Subject: [media] v4l: videobuf2: add generic memory handling routines Add generic memory handling routines for userspace pointer handling, contiguous memory verification and mapping. Signed-off-by: Marek Szyprowski Signed-off-by: Pawel Osciak Signed-off-by: Kyungmin Park CC: Pawel Osciak Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 3 + drivers/media/video/Makefile | 1 + drivers/media/video/videobuf2-memops.c | 232 +++++++++++++++++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 drivers/media/video/videobuf2-memops.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index a4a6aa703c26..aae5005cf86d 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -47,6 +47,9 @@ config V4L2_MEM2MEM_DEV config VIDEOBUF2_CORE tristate +config VIDEOBUF2_MEMOPS + tristate + # # Multimedia Video device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 6a1feba87869..fca0444b66b1 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o +obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c new file mode 100644 index 000000000000..053c15794b8d --- /dev/null +++ b/drivers/media/video/videobuf2-memops.c @@ -0,0 +1,232 @@ +/* + * videobuf2-memops.c - generic memory handling routines for videobuf2 + * + * Copyright (C) 2010 Samsung Electronics + * + * Author: Pawel Osciak + * Marek Szyprowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * vb2_get_vma() - acquire and lock the virtual memory area + * @vma: given virtual memory area + * + * This function attempts to acquire an area mapped in the userspace for + * the duration of a hardware operation. The area is "locked" by performing + * the same set of operation that are done when process calls fork() and + * memory areas are duplicated. + * + * Returns a copy of a virtual memory region on success or NULL. + */ +struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma) +{ + struct vm_area_struct *vma_copy; + + vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL); + if (vma_copy == NULL) + return NULL; + + if (vma->vm_ops && vma->vm_ops->open) + vma->vm_ops->open(vma); + + if (vma->vm_file) + get_file(vma->vm_file); + + memcpy(vma_copy, vma, sizeof(*vma)); + + vma_copy->vm_mm = NULL; + vma_copy->vm_next = NULL; + vma_copy->vm_prev = NULL; + + return vma_copy; +} + +/** + * vb2_put_userptr() - release a userspace virtual memory area + * @vma: virtual memory region associated with the area to be released + * + * This function releases the previously acquired memory area after a hardware + * operation. + */ +void vb2_put_vma(struct vm_area_struct *vma) +{ + if (!vma) + return; + + if (vma->vm_file) + fput(vma->vm_file); + + if (vma->vm_ops && vma->vm_ops->close) + vma->vm_ops->close(vma); + + kfree(vma); +} + +/** + * vb2_get_contig_userptr() - lock physically contiguous userspace mapped memory + * @vaddr: starting virtual address of the area to be verified + * @size: size of the area + * @res_paddr: will return physical address for the given vaddr + * @res_vma: will return locked copy of struct vm_area for the given area + * + * This function will go through memory area of size @size mapped at @vaddr and + * verify that the underlying physical pages are contiguous. If they are + * contiguous the virtual memory area is locked and a @res_vma is filled with + * the copy and @res_pa set to the physical address of the buffer. + * + * Returns 0 on success. + */ +int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, + struct vm_area_struct **res_vma, dma_addr_t *res_pa) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long offset, start, end; + unsigned long this_pfn, prev_pfn; + dma_addr_t pa = 0; + int ret = -EFAULT; + + start = vaddr; + offset = start & ~PAGE_MASK; + end = start + size; + + down_read(&mm->mmap_sem); + vma = find_vma(mm, start); + + if (vma == NULL || vma->vm_end < end) + goto done; + + for (prev_pfn = 0; start < end; start += PAGE_SIZE) { + ret = follow_pfn(vma, start, &this_pfn); + if (ret) + goto done; + + if (prev_pfn == 0) + pa = this_pfn << PAGE_SHIFT; + else if (this_pfn != prev_pfn + 1) { + ret = -EFAULT; + goto done; + } + prev_pfn = this_pfn; + } + + /* + * Memory is contigous, lock vma and return to the caller + */ + *res_vma = vb2_get_vma(vma); + if (*res_vma == NULL) { + ret = -ENOMEM; + goto done; + } + *res_pa = pa + offset; + ret = 0; + +done: + up_read(&mm->mmap_sem); + return ret; +} + +/** + * vb2_mmap_pfn_range() - map physical pages to userspace + * @vma: virtual memory region for the mapping + * @paddr: starting physical address of the memory to be mapped + * @size: size of the memory to be mapped + * @vm_ops: vm operations to be assigned to the created area + * @priv: private data to be associated with the area + * + * Returns 0 on success. + */ +int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, + unsigned long size, + const struct vm_operations_struct *vm_ops, + void *priv) +{ + int ret; + + size = min_t(unsigned long, vma->vm_end - vma->vm_start, size); + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + ret = remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT, + size, vma->vm_page_prot); + if (ret) { + printk(KERN_ERR "Remapping memory failed, error: %d\n", ret); + return ret; + } + + vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; + vma->vm_private_data = priv; + vma->vm_ops = vm_ops; + + vma->vm_ops->open(vma); + + printk(KERN_DEBUG "%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n", + __func__, paddr, vma->vm_start, size); + + return 0; +} + +/** + * vb2_common_vm_open() - increase refcount of the vma + * @vma: virtual memory region for the mapping + * + * This function adds another user to the provided vma. It expects + * struct vb2_vmarea_handler pointer in vma->vm_private_data. + */ +static void vb2_common_vm_open(struct vm_area_struct *vma) +{ + struct vb2_vmarea_handler *h = vma->vm_private_data; + + printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n", + __func__, h, atomic_read(h->refcount), vma->vm_start, + vma->vm_end); + + atomic_inc(h->refcount); +} + +/** + * vb2_common_vm_close() - decrease refcount of the vma + * @vma: virtual memory region for the mapping + * + * This function releases the user from the provided vma. It expects + * struct vb2_vmarea_handler pointer in vma->vm_private_data. + */ +static void vb2_common_vm_close(struct vm_area_struct *vma) +{ + struct vb2_vmarea_handler *h = vma->vm_private_data; + + printk(KERN_DEBUG "%s: %p, refcount: %d, vma: %08lx-%08lx\n", + __func__, h, atomic_read(h->refcount), vma->vm_start, + vma->vm_end); + + h->put(h->arg); +} + +/** + * vb2_common_vm_ops - common vm_ops used for tracking refcount of mmaped + * video buffers + */ +const struct vm_operations_struct vb2_common_vm_ops = { + .open = vb2_common_vm_open, + .close = vb2_common_vm_close, +}; +EXPORT_SYMBOL_GPL(vb2_common_vm_ops); + +MODULE_DESCRIPTION("common memory handling routines for videobuf2"); +MODULE_AUTHOR("Pawel Osciak"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 3c18ff06d811f743d380e6436fac0143ffcf1266 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Mon, 11 Oct 2010 10:58:53 -0300 Subject: [media] v4l: videobuf2: add vmalloc allocator Add an implementation of contiguous virtual memory allocator and handling routines for videobuf2, implemented on top of vmalloc()/vfree() calls. Signed-off-by: Pawel Osciak Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski CC: Pawel Osciak Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 5 ++ drivers/media/video/Makefile | 1 + drivers/media/video/videobuf2-vmalloc.c | 132 ++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 drivers/media/video/videobuf2-vmalloc.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index aae5005cf86d..b8c21a729b86 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -50,6 +50,11 @@ config VIDEOBUF2_CORE config VIDEOBUF2_MEMOPS tristate +config VIDEOBUF2_VMALLOC + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate + # # Multimedia Video device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index fca0444b66b1..e31c88e9ca76 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -113,6 +113,7 @@ obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o +obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c new file mode 100644 index 000000000000..b5e6936fb628 --- /dev/null +++ b/drivers/media/video/videobuf2-vmalloc.c @@ -0,0 +1,132 @@ +/* + * videobuf2-vmalloc.c - vmalloc memory allocator for videobuf2 + * + * Copyright (C) 2010 Samsung Electronics + * + * Author: Pawel Osciak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include + +struct vb2_vmalloc_buf { + void *vaddr; + unsigned long size; + atomic_t refcount; + struct vb2_vmarea_handler handler; +}; + +static void vb2_vmalloc_put(void *buf_priv); + +static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) +{ + struct vb2_vmalloc_buf *buf; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return NULL; + + buf->size = size; + buf->vaddr = vmalloc_user(buf->size); + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_vmalloc_put; + buf->handler.arg = buf; + + if (!buf->vaddr) { + printk(KERN_ERR "vmalloc of size %ld failed\n", buf->size); + kfree(buf); + return NULL; + } + + atomic_inc(&buf->refcount); + printk(KERN_DEBUG "Allocated vmalloc buffer of size %ld at vaddr=%p\n", + buf->size, buf->vaddr); + + return buf; +} + +static void vb2_vmalloc_put(void *buf_priv) +{ + struct vb2_vmalloc_buf *buf = buf_priv; + + if (atomic_dec_and_test(&buf->refcount)) { + printk(KERN_DEBUG "%s: Freeing vmalloc mem at vaddr=%p\n", + __func__, buf->vaddr); + vfree(buf->vaddr); + kfree(buf); + } +} + +static void *vb2_vmalloc_vaddr(void *buf_priv) +{ + struct vb2_vmalloc_buf *buf = buf_priv; + + BUG_ON(!buf); + + if (!buf->vaddr) { + printk(KERN_ERR "Address of an unallocated plane requested\n"); + return NULL; + } + + return buf->vaddr; +} + +static unsigned int vb2_vmalloc_num_users(void *buf_priv) +{ + struct vb2_vmalloc_buf *buf = buf_priv; + return atomic_read(&buf->refcount); +} + +static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + struct vb2_vmalloc_buf *buf = buf_priv; + int ret; + + if (!buf) { + printk(KERN_ERR "No memory to map\n"); + return -EINVAL; + } + + ret = remap_vmalloc_range(vma, buf->vaddr, 0); + if (ret) { + printk(KERN_ERR "Remapping vmalloc memory, error: %d\n", ret); + return ret; + } + + /* + * Make sure that vm_areas for 2 buffers won't be merged together + */ + vma->vm_flags |= VM_DONTEXPAND; + + /* + * Use common vm_area operations to track buffer refcount. + */ + vma->vm_private_data = &buf->handler; + vma->vm_ops = &vb2_common_vm_ops; + + vma->vm_ops->open(vma); + + return 0; +} + +const struct vb2_mem_ops vb2_vmalloc_memops = { + .alloc = vb2_vmalloc_alloc, + .put = vb2_vmalloc_put, + .vaddr = vb2_vmalloc_vaddr, + .mmap = vb2_vmalloc_mmap, + .num_users = vb2_vmalloc_num_users, +}; +EXPORT_SYMBOL_GPL(vb2_vmalloc_memops); + +MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2"); +MODULE_AUTHOR("Pawel Osciak"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 1a758d4e847f7743ac1b5aa79fde3ba2d8b5132b Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Mon, 11 Oct 2010 10:59:36 -0300 Subject: [media] v4l: videobuf2: add DMA coherent allocator Add an implementation of DMA coherent memory allocator and handling routines for videobuf2, implemented on top of dma_alloc_coherent() call. Signed-off-by: Pawel Osciak Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski CC: Pawel Osciak Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 5 + drivers/media/video/Makefile | 1 + drivers/media/video/videobuf2-dma-contig.c | 185 +++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 drivers/media/video/videobuf2-dma-contig.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b8c21a729b86..b64183e06348 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -50,6 +50,11 @@ config VIDEOBUF2_CORE config VIDEOBUF2_MEMOPS tristate +config VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate + config VIDEOBUF2_VMALLOC select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index e31c88e9ca76..106d40bbe724 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -114,6 +114,7 @@ obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o +obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c new file mode 100644 index 000000000000..bb6a5602cf94 --- /dev/null +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -0,0 +1,185 @@ +/* + * videobuf2-dma-contig.c - DMA contig memory allocator for videobuf2 + * + * Copyright (C) 2010 Samsung Electronics + * + * Author: Pawel Osciak + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include + +struct vb2_dc_conf { + struct device *dev; +}; + +struct vb2_dc_buf { + struct vb2_dc_conf *conf; + void *vaddr; + dma_addr_t paddr; + unsigned long size; + struct vm_area_struct *vma; + atomic_t refcount; + struct vb2_vmarea_handler handler; +}; + +static void vb2_dma_contig_put(void *buf_priv); + +static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) +{ + struct vb2_dc_conf *conf = alloc_ctx; + struct vb2_dc_buf *buf; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr, + GFP_KERNEL); + if (!buf->vaddr) { + dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", + buf->size); + kfree(buf); + return ERR_PTR(-ENOMEM); + } + + buf->conf = conf; + buf->size = size; + + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_dma_contig_put; + buf->handler.arg = buf; + + atomic_inc(&buf->refcount); + + return buf; +} + +static void vb2_dma_contig_put(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + if (atomic_dec_and_test(&buf->refcount)) { + dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr, + buf->paddr); + kfree(buf); + } +} + +static void *vb2_dma_contig_cookie(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return (void *)buf->paddr; +} + +static void *vb2_dma_contig_vaddr(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + if (!buf) + return 0; + + return buf->vaddr; +} + +static unsigned int vb2_dma_contig_num_users(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return atomic_read(&buf->refcount); +} + +static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + struct vb2_dc_buf *buf = buf_priv; + + if (!buf) { + printk(KERN_ERR "No buffer to map\n"); + return -EINVAL; + } + + return vb2_mmap_pfn_range(vma, buf->paddr, buf->size, + &vb2_common_vm_ops, &buf->handler); +} + +static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr, + unsigned long size, int write) +{ + struct vb2_dc_buf *buf; + struct vm_area_struct *vma; + dma_addr_t paddr = 0; + int ret; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr); + if (ret) { + printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n", + vaddr); + kfree(buf); + return ERR_PTR(ret); + } + + buf->size = size; + buf->paddr = paddr; + buf->vma = vma; + + return buf; +} + +static void vb2_dma_contig_put_userptr(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + + if (!buf) + return; + + vb2_put_vma(buf->vma); + kfree(buf); +} + +const struct vb2_mem_ops vb2_dma_contig_memops = { + .alloc = vb2_dma_contig_alloc, + .put = vb2_dma_contig_put, + .cookie = vb2_dma_contig_cookie, + .vaddr = vb2_dma_contig_vaddr, + .mmap = vb2_dma_contig_mmap, + .get_userptr = vb2_dma_contig_get_userptr, + .put_userptr = vb2_dma_contig_put_userptr, + .num_users = vb2_dma_contig_num_users, +}; +EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); + +void *vb2_dma_contig_init_ctx(struct device *dev) +{ + struct vb2_dc_conf *conf; + + conf = kzalloc(sizeof *conf, GFP_KERNEL); + if (!conf) + return ERR_PTR(-ENOMEM); + + conf->dev = dev; + + return conf; +} +EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx); + +void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) +{ + kfree(alloc_ctx); +} +EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); + +MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); +MODULE_AUTHOR("Pawel Osciak"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 5ba3f757f0592ca001266b4a6214d0332349909c Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Mon, 29 Nov 2010 11:53:34 -0300 Subject: [media] v4l: videobuf2: add DMA scatter/gather allocator Add an implementation of DMA scatter/gather allocator and handling routines for videobuf2. For mmap operation mode it is implemented on top of alloc_page + sg_set_page/_free_page. For userptr operation mode it is implemented on top of get_user_pages + sg_set_page/put_page. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski CC: Pawel Osciak Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 6 + drivers/media/video/Makefile | 1 + drivers/media/video/videobuf2-dma-sg.c | 292 +++++++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+) create mode 100644 drivers/media/video/videobuf2-dma-sg.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index b64183e06348..8710d90f9e16 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -60,6 +60,12 @@ config VIDEOBUF2_VMALLOC select VIDEOBUF2_MEMOPS tristate + +config VIDEOBUF2_DMA_SG + #depends on HAS_DMA + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate # # Multimedia Video device configuration # diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 106d40bbe724..40833fec34dc 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -115,6 +115,7 @@ obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o +obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c new file mode 100644 index 000000000000..20b5c5dcc0ef --- /dev/null +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -0,0 +1,292 @@ +/* + * videobuf2-dma-sg.c - dma scatter/gather memory allocator for videobuf2 + * + * Copyright (C) 2010 Samsung Electronics + * + * Author: Andrzej Pietrasiewicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct vb2_dma_sg_buf { + void *vaddr; + struct page **pages; + int write; + int offset; + struct vb2_dma_sg_desc sg_desc; + atomic_t refcount; + struct vb2_vmarea_handler handler; +}; + +static void vb2_dma_sg_put(void *buf_priv); + +static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) +{ + struct vb2_dma_sg_buf *buf; + int i; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return NULL; + + buf->vaddr = NULL; + buf->write = 0; + buf->offset = 0; + buf->sg_desc.size = size; + buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + buf->sg_desc.sglist = vmalloc(buf->sg_desc.num_pages * + sizeof(*buf->sg_desc.sglist)); + if (!buf->sg_desc.sglist) + goto fail_sglist_alloc; + memset(buf->sg_desc.sglist, 0, buf->sg_desc.num_pages * + sizeof(*buf->sg_desc.sglist)); + sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages); + + buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *), + GFP_KERNEL); + if (!buf->pages) + goto fail_pages_array_alloc; + + for (i = 0; i < buf->sg_desc.num_pages; ++i) { + buf->pages[i] = alloc_page(GFP_KERNEL); + if (NULL == buf->pages[i]) + goto fail_pages_alloc; + sg_set_page(&buf->sg_desc.sglist[i], + buf->pages[i], PAGE_SIZE, 0); + } + + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_dma_sg_put; + buf->handler.arg = buf; + + atomic_inc(&buf->refcount); + + printk(KERN_DEBUG "%s: Allocated buffer of %d pages\n", + __func__, buf->sg_desc.num_pages); + + if (!buf->vaddr) + buf->vaddr = vm_map_ram(buf->pages, + buf->sg_desc.num_pages, + -1, + PAGE_KERNEL); + return buf; + +fail_pages_alloc: + while (--i >= 0) + __free_page(buf->pages[i]); + +fail_pages_array_alloc: + vfree(buf->sg_desc.sglist); + +fail_sglist_alloc: + kfree(buf); + return NULL; +} + +static void vb2_dma_sg_put(void *buf_priv) +{ + struct vb2_dma_sg_buf *buf = buf_priv; + int i = buf->sg_desc.num_pages; + + if (atomic_dec_and_test(&buf->refcount)) { + printk(KERN_DEBUG "%s: Freeing buffer of %d pages\n", __func__, + buf->sg_desc.num_pages); + if (buf->vaddr) + vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages); + vfree(buf->sg_desc.sglist); + while (--i >= 0) + __free_page(buf->pages[i]); + kfree(buf->pages); + kfree(buf); + } +} + +static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, + unsigned long size, int write) +{ + struct vb2_dma_sg_buf *buf; + unsigned long first, last; + int num_pages_from_user, i; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return NULL; + + buf->vaddr = NULL; + buf->write = write; + buf->offset = vaddr & ~PAGE_MASK; + buf->sg_desc.size = size; + + first = (vaddr & PAGE_MASK) >> PAGE_SHIFT; + last = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT; + buf->sg_desc.num_pages = last - first + 1; + + buf->sg_desc.sglist = vmalloc( + buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist)); + if (!buf->sg_desc.sglist) + goto userptr_fail_sglist_alloc; + + memset(buf->sg_desc.sglist, 0, + buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist)); + sg_init_table(buf->sg_desc.sglist, buf->sg_desc.num_pages); + + buf->pages = kzalloc(buf->sg_desc.num_pages * sizeof(struct page *), + GFP_KERNEL); + if (!buf->pages) + goto userptr_fail_pages_array_alloc; + + down_read(¤t->mm->mmap_sem); + num_pages_from_user = get_user_pages(current, current->mm, + vaddr & PAGE_MASK, + buf->sg_desc.num_pages, + write, + 1, /* force */ + buf->pages, + NULL); + up_read(¤t->mm->mmap_sem); + if (num_pages_from_user != buf->sg_desc.num_pages) + goto userptr_fail_get_user_pages; + + sg_set_page(&buf->sg_desc.sglist[0], buf->pages[0], + PAGE_SIZE - buf->offset, buf->offset); + size -= PAGE_SIZE - buf->offset; + for (i = 1; i < buf->sg_desc.num_pages; ++i) { + sg_set_page(&buf->sg_desc.sglist[i], buf->pages[i], + min_t(size_t, PAGE_SIZE, size), 0); + size -= min_t(size_t, PAGE_SIZE, size); + } + return buf; + +userptr_fail_get_user_pages: + printk(KERN_DEBUG "get_user_pages requested/got: %d/%d]\n", + num_pages_from_user, buf->sg_desc.num_pages); + while (--num_pages_from_user >= 0) + put_page(buf->pages[num_pages_from_user]); + +userptr_fail_pages_array_alloc: + vfree(buf->sg_desc.sglist); + +userptr_fail_sglist_alloc: + kfree(buf); + return NULL; +} + +/* + * @put_userptr: inform the allocator that a USERPTR buffer will no longer + * be used + */ +static void vb2_dma_sg_put_userptr(void *buf_priv) +{ + struct vb2_dma_sg_buf *buf = buf_priv; + int i = buf->sg_desc.num_pages; + + printk(KERN_DEBUG "%s: Releasing userspace buffer of %d pages\n", + __func__, buf->sg_desc.num_pages); + if (buf->vaddr) + vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages); + while (--i >= 0) { + if (buf->write) + set_page_dirty_lock(buf->pages[i]); + put_page(buf->pages[i]); + } + vfree(buf->sg_desc.sglist); + kfree(buf->pages); + kfree(buf); +} + +static void *vb2_dma_sg_vaddr(void *buf_priv) +{ + struct vb2_dma_sg_buf *buf = buf_priv; + + BUG_ON(!buf); + + if (!buf->vaddr) + buf->vaddr = vm_map_ram(buf->pages, + buf->sg_desc.num_pages, + -1, + PAGE_KERNEL); + + /* add offset in case userptr is not page-aligned */ + return buf->vaddr + buf->offset; +} + +static unsigned int vb2_dma_sg_num_users(void *buf_priv) +{ + struct vb2_dma_sg_buf *buf = buf_priv; + + return atomic_read(&buf->refcount); +} + +static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + struct vb2_dma_sg_buf *buf = buf_priv; + unsigned long uaddr = vma->vm_start; + unsigned long usize = vma->vm_end - vma->vm_start; + int i = 0; + + if (!buf) { + printk(KERN_ERR "No memory to map\n"); + return -EINVAL; + } + + do { + int ret; + + ret = vm_insert_page(vma, uaddr, buf->pages[i++]); + if (ret) { + printk(KERN_ERR "Remapping memory, error: %d\n", ret); + return ret; + } + + uaddr += PAGE_SIZE; + usize -= PAGE_SIZE; + } while (usize > 0); + + + /* + * Use common vm_area operations to track buffer refcount. + */ + vma->vm_private_data = &buf->handler; + vma->vm_ops = &vb2_common_vm_ops; + + vma->vm_ops->open(vma); + + return 0; +} + +static void *vb2_dma_sg_cookie(void *buf_priv) +{ + struct vb2_dma_sg_buf *buf = buf_priv; + + return &buf->sg_desc; +} + +const struct vb2_mem_ops vb2_dma_sg_memops = { + .alloc = vb2_dma_sg_alloc, + .put = vb2_dma_sg_put, + .get_userptr = vb2_dma_sg_get_userptr, + .put_userptr = vb2_dma_sg_put_userptr, + .vaddr = vb2_dma_sg_vaddr, + .mmap = vb2_dma_sg_mmap, + .num_users = vb2_dma_sg_num_users, + .cookie = vb2_dma_sg_cookie, +}; +EXPORT_SYMBOL_GPL(vb2_dma_sg_memops); + +MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2"); +MODULE_AUTHOR("Andrzej Pietrasiewicz"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From b25748fe612626d6c9e344482bb028d76c1e11f2 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 6 Dec 2010 05:56:55 -0300 Subject: [media] v4l: videobuf2: add read() and write() emulator Add a generic file io (read and write) emulator for videobuf2. It uses MMAP memory type buffers and generic vb2 calls: req_bufs, qbuf and dqbuf. Video date is being copied from mmap buffers to userspace with standard copy_to_user() function. To add support for file io the driver needs to provide an additional callback - read_setup or write_setup. It should provide the default number of buffers used by emulator and flags. With these flags one can detemine the style of read() or write() emulation. By default 'streaming' style is used. With VB2_FILEIO_READ_ONCE flag one can select 'one shot' mode for read() emulator. With VB2_FILEIO_WRITE_IMMEDIATE flag one can select immediate conversion of write calls to qbuf for write() emulator, so the vb2 will not wait until each buffer is filled completely before queueing it to the driver. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 399 +++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index b856bd105d77..73f3b220b34a 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -453,6 +453,11 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) unsigned long plane_sizes[VIDEO_MAX_PLANES]; int ret = 0; + if (q->fileio) { + dprintk(1, "reqbufs: file io in progress\n"); + return -EBUSY; + } + if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR) { dprintk(1, "reqbufs: unsupported memory type\n"); @@ -824,6 +829,11 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) struct vb2_buffer *vb; int ret = 0; + if (q->fileio) { + dprintk(1, "qbuf: file io in progress\n"); + return -EBUSY; + } + if (b->type != q->type) { dprintk(1, "qbuf: invalid buffer type\n"); return -EINVAL; @@ -1028,6 +1038,11 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) struct vb2_buffer *vb = NULL; int ret; + if (q->fileio) { + dprintk(1, "dqbuf: file io in progress\n"); + return -EBUSY; + } + if (b->type != q->type) { dprintk(1, "dqbuf: invalid buffer type\n"); return -EINVAL; @@ -1087,6 +1102,11 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) { struct vb2_buffer *vb; + if (q->fileio) { + dprintk(1, "streamon: file io in progress\n"); + return -EBUSY; + } + if (type != q->type) { dprintk(1, "streamon: invalid stream type\n"); return -EINVAL; @@ -1180,6 +1200,11 @@ static void __vb2_queue_cancel(struct vb2_queue *q) */ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type) { + if (q->fileio) { + dprintk(1, "streamoff: file io in progress\n"); + return -EBUSY; + } + if (type != q->type) { dprintk(1, "streamoff: invalid stream type\n"); return -EINVAL; @@ -1303,6 +1328,8 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) } EXPORT_SYMBOL_GPL(vb2_mmap); +static int __vb2_init_fileio(struct vb2_queue *q, int read); +static int __vb2_cleanup_fileio(struct vb2_queue *q); /** * vb2_poll() - implements poll userspace operation @@ -1323,8 +1350,29 @@ EXPORT_SYMBOL_GPL(vb2_mmap); unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { unsigned long flags; + unsigned int ret; struct vb2_buffer *vb = NULL; + /* + * Start file io emulator if streaming api has not been used yet. + */ + if (q->num_buffers == 0 && q->fileio == NULL) { + if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) { + ret = __vb2_init_fileio(q, 1); + if (ret) + return ret; + } + if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) { + ret = __vb2_init_fileio(q, 0); + if (ret) + return ret; + /* + * Write to OUTPUT queue can be done immediately. + */ + return POLLOUT | POLLWRNORM; + } + } + /* * There is nothing to wait for if no buffers have already been queued. */ @@ -1395,11 +1443,362 @@ EXPORT_SYMBOL_GPL(vb2_queue_init); */ void vb2_queue_release(struct vb2_queue *q) { + __vb2_cleanup_fileio(q); __vb2_queue_cancel(q); __vb2_queue_free(q); } EXPORT_SYMBOL_GPL(vb2_queue_release); +/** + * struct vb2_fileio_buf - buffer context used by file io emulator + * + * vb2 provides a compatibility layer and emulator of file io (read and + * write) calls on top of streaming API. This structure is used for + * tracking context related to the buffers. + */ +struct vb2_fileio_buf { + void *vaddr; + unsigned int size; + unsigned int pos; + unsigned int queued:1; +}; + +/** + * struct vb2_fileio_data - queue context used by file io emulator + * + * vb2 provides a compatibility layer and emulator of file io (read and + * write) calls on top of streaming API. For proper operation it required + * this structure to save the driver state between each call of the read + * or write function. + */ +struct vb2_fileio_data { + struct v4l2_requestbuffers req; + struct v4l2_buffer b; + struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME]; + unsigned int index; + unsigned int q_count; + unsigned int dq_count; + unsigned int flags; +}; + +/** + * __vb2_init_fileio() - initialize file io emulator + * @q: videobuf2 queue + * @read: mode selector (1 means read, 0 means write) + */ +static int __vb2_init_fileio(struct vb2_queue *q, int read) +{ + struct vb2_fileio_data *fileio; + int i, ret; + unsigned int count = 0; + + /* + * Sanity check + */ + if ((read && !(q->io_modes & VB2_READ)) || + (!read && !(q->io_modes & VB2_WRITE))) + BUG(); + + /* + * Check if device supports mapping buffers to kernel virtual space. + */ + if (!q->mem_ops->vaddr) + return -EBUSY; + + /* + * Check if streaming api has not been already activated. + */ + if (q->streaming || q->num_buffers > 0) + return -EBUSY; + + /* + * Start with count 1, driver can increase it in queue_setup() + */ + count = 1; + + dprintk(3, "setting up file io: mode %s, count %d, flags %08x\n", + (read) ? "read" : "write", count, q->io_flags); + + fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL); + if (fileio == NULL) + return -ENOMEM; + + fileio->flags = q->io_flags; + + /* + * Request buffers and use MMAP type to force driver + * to allocate buffers by itself. + */ + fileio->req.count = count; + fileio->req.memory = V4L2_MEMORY_MMAP; + fileio->req.type = q->type; + ret = vb2_reqbufs(q, &fileio->req); + if (ret) + goto err_kfree; + + /* + * Check if plane_count is correct + * (multiplane buffers are not supported). + */ + if (q->bufs[0]->num_planes != 1) { + fileio->req.count = 0; + ret = -EBUSY; + goto err_reqbufs; + } + + /* + * Get kernel address of each buffer. + */ + for (i = 0; i < q->num_buffers; i++) { + fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0); + if (fileio->bufs[i].vaddr == NULL) + goto err_reqbufs; + fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0); + } + + /* + * Read mode requires pre queuing of all buffers. + */ + if (read) { + /* + * Queue all buffers. + */ + for (i = 0; i < q->num_buffers; i++) { + struct v4l2_buffer *b = &fileio->b; + memset(b, 0, sizeof(*b)); + b->type = q->type; + b->memory = q->memory; + b->index = i; + ret = vb2_qbuf(q, b); + if (ret) + goto err_reqbufs; + fileio->bufs[i].queued = 1; + } + + /* + * Start streaming. + */ + ret = vb2_streamon(q, q->type); + if (ret) + goto err_reqbufs; + } + + q->fileio = fileio; + + return ret; + +err_reqbufs: + vb2_reqbufs(q, &fileio->req); + +err_kfree: + kfree(fileio); + return ret; +} + +/** + * __vb2_cleanup_fileio() - free resourced used by file io emulator + * @q: videobuf2 queue + */ +static int __vb2_cleanup_fileio(struct vb2_queue *q) +{ + struct vb2_fileio_data *fileio = q->fileio; + + if (fileio) { + /* + * Hack fileio context to enable direct calls to vb2 ioctl + * interface. + */ + q->fileio = NULL; + + vb2_streamoff(q, q->type); + fileio->req.count = 0; + vb2_reqbufs(q, &fileio->req); + kfree(fileio); + dprintk(3, "file io emulator closed\n"); + } + return 0; +} + +/** + * __vb2_perform_fileio() - perform a single file io (read or write) operation + * @q: videobuf2 queue + * @data: pointed to target userspace buffer + * @count: number of bytes to read or write + * @ppos: file handle position tracking pointer + * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking) + * @read: access mode selector (1 means read, 0 means write) + */ +static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count, + loff_t *ppos, int nonblock, int read) +{ + struct vb2_fileio_data *fileio; + struct vb2_fileio_buf *buf; + int ret, index; + + dprintk(3, "file io: mode %s, offset %ld, count %ld, %sblocking\n", + read ? "read" : "write", (long)*ppos, count, + nonblock ? "non" : ""); + + if (!data) + return -EINVAL; + + /* + * Initialize emulator on first call. + */ + if (!q->fileio) { + ret = __vb2_init_fileio(q, read); + dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); + if (ret) + return ret; + } + fileio = q->fileio; + + /* + * Hack fileio context to enable direct calls to vb2 ioctl interface. + * The pointer will be restored before returning from this function. + */ + q->fileio = NULL; + + index = fileio->index; + buf = &fileio->bufs[index]; + + /* + * Check if we need to dequeue the buffer. + */ + if (buf->queued) { + struct vb2_buffer *vb; + + /* + * Call vb2_dqbuf to get buffer back. + */ + memset(&fileio->b, 0, sizeof(fileio->b)); + fileio->b.type = q->type; + fileio->b.memory = q->memory; + fileio->b.index = index; + ret = vb2_dqbuf(q, &fileio->b, nonblock); + dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); + if (ret) + goto end; + fileio->dq_count += 1; + + /* + * Get number of bytes filled by the driver + */ + vb = q->bufs[index]; + buf->size = vb2_get_plane_payload(vb, 0); + buf->queued = 0; + } + + /* + * Limit count on last few bytes of the buffer. + */ + if (buf->pos + count > buf->size) { + count = buf->size - buf->pos; + dprintk(5, "reducing read count: %ld\n", count); + } + + /* + * Transfer data to userspace. + */ + dprintk(3, "file io: copying %ld bytes - buffer %d, offset %u\n", + count, index, buf->pos); + if (read) + ret = copy_to_user(data, buf->vaddr + buf->pos, count); + else + ret = copy_from_user(buf->vaddr + buf->pos, data, count); + if (ret) { + dprintk(3, "file io: error copying data\n"); + ret = -EFAULT; + goto end; + } + + /* + * Update counters. + */ + buf->pos += count; + *ppos += count; + + /* + * Queue next buffer if required. + */ + if (buf->pos == buf->size || + (!read && (fileio->flags & VB2_FILEIO_WRITE_IMMEDIATELY))) { + /* + * Check if this is the last buffer to read. + */ + if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) && + fileio->dq_count == 1) { + dprintk(3, "file io: read limit reached\n"); + /* + * Restore fileio pointer and release the context. + */ + q->fileio = fileio; + return __vb2_cleanup_fileio(q); + } + + /* + * Call vb2_qbuf and give buffer to the driver. + */ + memset(&fileio->b, 0, sizeof(fileio->b)); + fileio->b.type = q->type; + fileio->b.memory = q->memory; + fileio->b.index = index; + fileio->b.bytesused = buf->pos; + ret = vb2_qbuf(q, &fileio->b); + dprintk(5, "file io: vb2_dbuf result: %d\n", ret); + if (ret) + goto end; + + /* + * Buffer has been queued, update the status + */ + buf->pos = 0; + buf->queued = 1; + buf->size = q->bufs[0]->v4l2_planes[0].length; + fileio->q_count += 1; + + /* + * Switch to the next buffer + */ + fileio->index = (index + 1) % q->num_buffers; + + /* + * Start streaming if required. + */ + if (!read && !q->streaming) { + ret = vb2_streamon(q, q->type); + if (ret) + goto end; + } + } + + /* + * Return proper number of bytes processed. + */ + if (ret == 0) + ret = count; +end: + /* + * Restore the fileio context and block vb2 ioctl interface. + */ + q->fileio = fileio; + return ret; +} + +size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count, + loff_t *ppos, int nonblocking) +{ + return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1); +} +EXPORT_SYMBOL_GPL(vb2_read); + +size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count, + loff_t *ppos, int nonblocking) +{ + return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 0); +} +EXPORT_SYMBOL_GPL(vb2_write); + MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2"); MODULE_AUTHOR("Pawel Osciak, Marek Szyprowski"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 08b99e26a347441c50c1113802801a122dd1eb7a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 11 Jan 2011 17:12:34 -0300 Subject: [media] vb2 core: Fix a few printk warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/video/videobuf2-core.c: In function ‘__vb2_perform_fileio’: drivers/media/video/videobuf2-core.c:1638: warning: format ‘%ld’ expects type ‘long int’, but argument 4 has type ‘size_t’ drivers/media/video/videobuf2-core.c:1697: warning: format ‘%ld’ expects type ‘long int’, but argument 2 has type ‘size_t’ drivers/media/video/videobuf2-core.c:1703: warning: format ‘%ld’ expects type ‘long int’, but argument 2 has type ‘size_t’ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 73f3b220b34a..cc7ab0a17b68 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -1635,7 +1635,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ struct vb2_fileio_buf *buf; int ret, index; - dprintk(3, "file io: mode %s, offset %ld, count %ld, %sblocking\n", + dprintk(3, "file io: mode %s, offset %ld, count %zd, %sblocking\n", read ? "read" : "write", (long)*ppos, count, nonblock ? "non" : ""); @@ -1694,13 +1694,13 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ */ if (buf->pos + count > buf->size) { count = buf->size - buf->pos; - dprintk(5, "reducing read count: %ld\n", count); + dprintk(5, "reducing read count: %zd\n", count); } /* * Transfer data to userspace. */ - dprintk(3, "file io: copying %ld bytes - buffer %d, offset %u\n", + dprintk(3, "file io: copying %zd bytes - buffer %d, offset %u\n", count, index, buf->pos); if (read) ret = copy_to_user(data, buf->vaddr + buf->pos, count); -- cgit v1.2.2 From 908a0d7c588ef87e5cf0a26805e6002a78ac9d13 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 12 Jan 2011 06:50:24 -0300 Subject: [media] v4l: mem2mem: port to videobuf2 Port memory-to-memory framework to videobuf2 framework. Add support for multi-planar Video for Linux 2 API extensions to the memory-to-memory driver framework. Based on the original patch written by Pawel Osciak. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 4 +- drivers/media/video/v4l2-mem2mem.c | 232 ++++++++++++++++++------------------- 2 files changed, 117 insertions(+), 119 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 8710d90f9e16..3749c8941d0c 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -42,7 +42,7 @@ config VIDEO_TUNER config V4L2_MEM2MEM_DEV tristate - depends on VIDEOBUF_GEN + depends on VIDEOBUF2_CORE config VIDEOBUF2_CORE tristate @@ -989,6 +989,7 @@ if V4L_MEM2MEM_DRIVERS config VIDEO_MEM2MEM_TESTDEV tristate "Virtual test device for mem2mem framework" depends on VIDEO_DEV && VIDEO_V4L2 + depends on BROKEN select VIDEOBUF_VMALLOC select V4L2_MEM2MEM_DEV default n @@ -999,6 +1000,7 @@ config VIDEO_MEM2MEM_TESTDEV config VIDEO_SAMSUNG_S5P_FIMC tristate "Samsung S5P FIMC (video postprocessor) driver" depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P + depends on BROKEN select VIDEOBUF_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/video/v4l2-mem2mem.c index ac832a28e18e..a78e5c9be1a2 100644 --- a/drivers/media/video/v4l2-mem2mem.c +++ b/drivers/media/video/v4l2-mem2mem.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include MODULE_DESCRIPTION("Mem to mem device framework for videobuf"); @@ -65,21 +65,16 @@ struct v4l2_m2m_dev { static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &m2m_ctx->cap_q_ctx; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (V4L2_TYPE_IS_OUTPUT(type)) return &m2m_ctx->out_q_ctx; - default: - printk(KERN_ERR "Invalid buffer type\n"); - return NULL; - } + else + return &m2m_ctx->cap_q_ctx; } /** - * v4l2_m2m_get_vq() - return videobuf_queue for the given type + * v4l2_m2m_get_vq() - return vb2_queue for the given type */ -struct videobuf_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, +struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { struct v4l2_m2m_queue_ctx *q_ctx; @@ -95,27 +90,20 @@ EXPORT_SYMBOL(v4l2_m2m_get_vq); /** * v4l2_m2m_next_buf() - return next buffer from the list of ready buffers */ -void *v4l2_m2m_next_buf(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) +void *v4l2_m2m_next_buf(struct v4l2_m2m_queue_ctx *q_ctx) { - struct v4l2_m2m_queue_ctx *q_ctx; - struct videobuf_buffer *vb = NULL; + struct v4l2_m2m_buffer *b = NULL; unsigned long flags; - q_ctx = get_queue_ctx(m2m_ctx, type); - if (!q_ctx) - return NULL; - - spin_lock_irqsave(q_ctx->q.irqlock, flags); + spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); if (list_empty(&q_ctx->rdy_queue)) goto end; - vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer, queue); - vb->state = VIDEOBUF_ACTIVE; - + b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, list); end: - spin_unlock_irqrestore(q_ctx->q.irqlock, flags); - return vb; + spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); + return &b->vb; } EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf); @@ -123,26 +111,21 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_next_buf); * v4l2_m2m_buf_remove() - take off a buffer from the list of ready buffers and * return it */ -void *v4l2_m2m_buf_remove(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) +void *v4l2_m2m_buf_remove(struct v4l2_m2m_queue_ctx *q_ctx) { - struct v4l2_m2m_queue_ctx *q_ctx; - struct videobuf_buffer *vb = NULL; + struct v4l2_m2m_buffer *b = NULL; unsigned long flags; - q_ctx = get_queue_ctx(m2m_ctx, type); - if (!q_ctx) - return NULL; - - spin_lock_irqsave(q_ctx->q.irqlock, flags); + spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); if (!list_empty(&q_ctx->rdy_queue)) { - vb = list_entry(q_ctx->rdy_queue.next, struct videobuf_buffer, - queue); - list_del(&vb->queue); + b = list_entry(q_ctx->rdy_queue.next, struct v4l2_m2m_buffer, + list); + list_del(&b->list); q_ctx->num_rdy--; } - spin_unlock_irqrestore(q_ctx->q.irqlock, flags); + spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); - return vb; + return &b->vb; } EXPORT_SYMBOL_GPL(v4l2_m2m_buf_remove); @@ -235,20 +218,20 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) return; } - spin_lock_irqsave(m2m_ctx->out_q_ctx.q.irqlock, flags); + spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)) { - spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags); + spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("No input buffers available\n"); return; } if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) { - spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags); + spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("No output buffers available\n"); return; } - spin_unlock_irqrestore(m2m_ctx->out_q_ctx.q.irqlock, flags); + spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); if (m2m_dev->m2m_ops->job_ready && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) { @@ -291,6 +274,7 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, list_del(&m2m_dev->curr_ctx->queue); m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING); + wake_up(&m2m_dev->curr_ctx->finished); m2m_dev->curr_ctx = NULL; spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); @@ -309,10 +293,10 @@ EXPORT_SYMBOL(v4l2_m2m_job_finish); int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_requestbuffers *reqbufs) { - struct videobuf_queue *vq; + struct vb2_queue *vq; vq = v4l2_m2m_get_vq(m2m_ctx, reqbufs->type); - return videobuf_reqbufs(vq, reqbufs); + return vb2_reqbufs(vq, reqbufs); } EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); @@ -324,15 +308,22 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_buffer *buf) { - struct videobuf_queue *vq; - int ret; + struct vb2_queue *vq; + int ret = 0; + unsigned int i; vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); - ret = videobuf_querybuf(vq, buf); - - if (buf->memory == V4L2_MEMORY_MMAP - && vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - buf->m.offset += DST_QUEUE_OFF_BASE; + ret = vb2_querybuf(vq, buf); + + /* Adjust MMAP memory offsets for the CAPTURE queue */ + if (buf->memory == V4L2_MEMORY_MMAP && !V4L2_TYPE_IS_OUTPUT(vq->type)) { + if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { + for (i = 0; i < buf->length; ++i) + buf->m.planes[i].m.mem_offset + += DST_QUEUE_OFF_BASE; + } else { + buf->m.offset += DST_QUEUE_OFF_BASE; + } } return ret; @@ -346,11 +337,11 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf); int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_buffer *buf) { - struct videobuf_queue *vq; + struct vb2_queue *vq; int ret; vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); - ret = videobuf_qbuf(vq, buf); + ret = vb2_qbuf(vq, buf); if (!ret) v4l2_m2m_try_schedule(m2m_ctx); @@ -365,10 +356,10 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf); int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_buffer *buf) { - struct videobuf_queue *vq; + struct vb2_queue *vq; vq = v4l2_m2m_get_vq(m2m_ctx, buf->type); - return videobuf_dqbuf(vq, buf, file->f_flags & O_NONBLOCK); + return vb2_dqbuf(vq, buf, file->f_flags & O_NONBLOCK); } EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); @@ -378,11 +369,11 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { - struct videobuf_queue *vq; + struct vb2_queue *vq; int ret; vq = v4l2_m2m_get_vq(m2m_ctx, type); - ret = videobuf_streamon(vq); + ret = vb2_streamon(vq, type); if (!ret) v4l2_m2m_try_schedule(m2m_ctx); @@ -396,10 +387,10 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamon); int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { - struct videobuf_queue *vq; + struct vb2_queue *vq; vq = v4l2_m2m_get_vq(m2m_ctx, type); - return videobuf_streamoff(vq); + return vb2_streamoff(vq, type); } EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); @@ -414,44 +405,53 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct poll_table_struct *wait) { - struct videobuf_queue *src_q, *dst_q; - struct videobuf_buffer *src_vb = NULL, *dst_vb = NULL; + struct vb2_queue *src_q, *dst_q; + struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; unsigned int rc = 0; + unsigned long flags; src_q = v4l2_m2m_get_src_vq(m2m_ctx); dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); - videobuf_queue_lock(src_q); - videobuf_queue_lock(dst_q); - - if (src_q->streaming && !list_empty(&src_q->stream)) - src_vb = list_first_entry(&src_q->stream, - struct videobuf_buffer, stream); - if (dst_q->streaming && !list_empty(&dst_q->stream)) - dst_vb = list_first_entry(&dst_q->stream, - struct videobuf_buffer, stream); - - if (!src_vb && !dst_vb) { + /* + * There has to be at least one buffer queued on each queued_list, which + * means either in driver already or waiting for driver to claim it + * and start processing. + */ + if ((!src_q->streaming || list_empty(&src_q->queued_list)) + && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { rc = POLLERR; goto end; } - if (src_vb) { - poll_wait(file, &src_vb->done, wait); - if (src_vb->state == VIDEOBUF_DONE - || src_vb->state == VIDEOBUF_ERROR) - rc |= POLLOUT | POLLWRNORM; - } - if (dst_vb) { - poll_wait(file, &dst_vb->done, wait); - if (dst_vb->state == VIDEOBUF_DONE - || dst_vb->state == VIDEOBUF_ERROR) - rc |= POLLIN | POLLRDNORM; - } + if (m2m_ctx->m2m_dev->m2m_ops->unlock) + m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv); + + poll_wait(file, &src_q->done_wq, wait); + poll_wait(file, &dst_q->done_wq, wait); + + if (m2m_ctx->m2m_dev->m2m_ops->lock) + m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv); + + spin_lock_irqsave(&src_q->done_lock, flags); + if (!list_empty(&src_q->done_list)) + src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, + done_entry); + if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE + || src_vb->state == VB2_BUF_STATE_ERROR)) + rc |= POLLOUT | POLLWRNORM; + spin_unlock_irqrestore(&src_q->done_lock, flags); + + spin_lock_irqsave(&dst_q->done_lock, flags); + if (!list_empty(&dst_q->done_list)) + dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, + done_entry); + if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE + || dst_vb->state == VB2_BUF_STATE_ERROR)) + rc |= POLLIN | POLLRDNORM; + spin_unlock_irqrestore(&dst_q->done_lock, flags); end: - videobuf_queue_unlock(dst_q); - videobuf_queue_unlock(src_q); return rc; } EXPORT_SYMBOL_GPL(v4l2_m2m_poll); @@ -470,7 +470,7 @@ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct vm_area_struct *vma) { unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct videobuf_queue *vq; + struct vb2_queue *vq; if (offset < DST_QUEUE_OFF_BASE) { vq = v4l2_m2m_get_src_vq(m2m_ctx); @@ -479,7 +479,7 @@ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); } - return videobuf_mmap_mapper(vq, vma); + return vb2_mmap(vq, vma); } EXPORT_SYMBOL(v4l2_m2m_mmap); @@ -531,36 +531,41 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_release); * * Usually called from driver's open() function. */ -struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(void *priv, struct v4l2_m2m_dev *m2m_dev, - void (*vq_init)(void *priv, struct videobuf_queue *, - enum v4l2_buf_type)) +struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev, + void *drv_priv, + int (*queue_init)(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)) { struct v4l2_m2m_ctx *m2m_ctx; struct v4l2_m2m_queue_ctx *out_q_ctx, *cap_q_ctx; - - if (!vq_init) - return ERR_PTR(-EINVAL); + int ret; m2m_ctx = kzalloc(sizeof *m2m_ctx, GFP_KERNEL); if (!m2m_ctx) return ERR_PTR(-ENOMEM); - m2m_ctx->priv = priv; + m2m_ctx->priv = drv_priv; m2m_ctx->m2m_dev = m2m_dev; + init_waitqueue_head(&m2m_ctx->finished); - out_q_ctx = get_queue_ctx(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - cap_q_ctx = get_queue_ctx(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + out_q_ctx = &m2m_ctx->out_q_ctx; + cap_q_ctx = &m2m_ctx->cap_q_ctx; INIT_LIST_HEAD(&out_q_ctx->rdy_queue); INIT_LIST_HEAD(&cap_q_ctx->rdy_queue); + spin_lock_init(&out_q_ctx->rdy_spinlock); + spin_lock_init(&cap_q_ctx->rdy_spinlock); INIT_LIST_HEAD(&m2m_ctx->queue); - vq_init(priv, &out_q_ctx->q, V4L2_BUF_TYPE_VIDEO_OUTPUT); - vq_init(priv, &cap_q_ctx->q, V4L2_BUF_TYPE_VIDEO_CAPTURE); - out_q_ctx->q.priv_data = cap_q_ctx->q.priv_data = priv; + ret = queue_init(drv_priv, &out_q_ctx->q, &cap_q_ctx->q); + + if (ret) + goto err; return m2m_ctx; +err: + kfree(m2m_ctx); + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init); @@ -572,7 +577,6 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init); void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx) { struct v4l2_m2m_dev *m2m_dev; - struct videobuf_buffer *vb; unsigned long flags; m2m_dev = m2m_ctx->m2m_dev; @@ -582,10 +586,7 @@ void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx) spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); m2m_dev->m2m_ops->job_abort(m2m_ctx->priv); dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx); - vb = v4l2_m2m_next_dst_buf(m2m_ctx); - BUG_ON(NULL == vb); - wait_event(vb->done, vb->state != VIDEOBUF_ACTIVE - && vb->state != VIDEOBUF_QUEUED); + wait_event(m2m_ctx->finished, !(m2m_ctx->job_flags & TRANS_RUNNING)); } else if (m2m_ctx->job_flags & TRANS_QUEUED) { list_del(&m2m_ctx->queue); m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING); @@ -597,11 +598,8 @@ void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx) spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); } - videobuf_stop(&m2m_ctx->cap_q_ctx.q); - videobuf_stop(&m2m_ctx->out_q_ctx.q); - - videobuf_mmap_free(&m2m_ctx->cap_q_ctx.q); - videobuf_mmap_free(&m2m_ctx->out_q_ctx.q); + vb2_queue_release(&m2m_ctx->cap_q_ctx.q); + vb2_queue_release(&m2m_ctx->out_q_ctx.q); kfree(m2m_ctx); } @@ -611,23 +609,21 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_release); * v4l2_m2m_buf_queue() - add a buffer to the proper ready buffers list. * * Call from buf_queue(), videobuf_queue_ops callback. - * - * Locking: Caller holds q->irqlock (taken by videobuf before calling buf_queue - * callback in the driver). */ -void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct videobuf_queue *vq, - struct videobuf_buffer *vb) +void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb) { + struct v4l2_m2m_buffer *b = container_of(vb, struct v4l2_m2m_buffer, vb); struct v4l2_m2m_queue_ctx *q_ctx; + unsigned long flags; - q_ctx = get_queue_ctx(m2m_ctx, vq->type); + q_ctx = get_queue_ctx(m2m_ctx, vb->vb2_queue->type); if (!q_ctx) return; - list_add_tail(&vb->queue, &q_ctx->rdy_queue); + spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); + list_add_tail(&b->list, &q_ctx->rdy_queue); q_ctx->num_rdy++; - - vb->state = VIDEOBUF_QUEUED; + spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); } EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); -- cgit v1.2.2 From d80ee38cd845baadef175893b99df24e7a03ec40 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 12 Jan 2011 06:50:55 -0300 Subject: [media] v4l: mem2mem: port m2m_testdev to vb2 This patch ports mem2mem test device to videobuf2 framework. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 3 +- drivers/media/video/mem2mem_testdev.c | 227 ++++++++++++++++------------------ 2 files changed, 107 insertions(+), 123 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 3749c8941d0c..1c0f080599e8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -989,8 +989,7 @@ if V4L_MEM2MEM_DRIVERS config VIDEO_MEM2MEM_TESTDEV tristate "Virtual test device for mem2mem framework" depends on VIDEO_DEV && VIDEO_V4L2 - depends on BROKEN - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV default n ---help--- diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index e7e717800ee2..e1f96ea45bcb 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev" @@ -201,11 +201,6 @@ struct m2mtest_ctx { struct v4l2_m2m_ctx *m2m_ctx; }; -struct m2mtest_buffer { - /* vb must be first! */ - struct videobuf_buffer vb; -}; - static struct v4l2_queryctrl *get_ctrl(int id) { int i; @@ -219,37 +214,41 @@ static struct v4l2_queryctrl *get_ctrl(int id) } static int device_process(struct m2mtest_ctx *ctx, - struct m2mtest_buffer *in_buf, - struct m2mtest_buffer *out_buf) + struct vb2_buffer *in_vb, + struct vb2_buffer *out_vb) { struct m2mtest_dev *dev = ctx->dev; + struct m2mtest_q_data *q_data; u8 *p_in, *p_out; int x, y, t, w; int tile_w, bytes_left; - struct videobuf_queue *src_q; - struct videobuf_queue *dst_q; + int width, height, bytesperline; - src_q = v4l2_m2m_get_src_vq(ctx->m2m_ctx); - dst_q = v4l2_m2m_get_dst_vq(ctx->m2m_ctx); - p_in = videobuf_queue_to_vaddr(src_q, &in_buf->vb); - p_out = videobuf_queue_to_vaddr(dst_q, &out_buf->vb); + q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); + + width = q_data->width; + height = q_data->height; + bytesperline = (q_data->width * q_data->fmt->depth) >> 3; + + p_in = vb2_plane_vaddr(in_vb, 0); + p_out = vb2_plane_vaddr(out_vb, 0); if (!p_in || !p_out) { v4l2_err(&dev->v4l2_dev, "Acquiring kernel pointers to buffers failed\n"); return -EFAULT; } - if (in_buf->vb.size > out_buf->vb.size) { + if (vb2_plane_size(in_vb, 0) > vb2_plane_size(out_vb, 0)) { v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n"); return -EINVAL; } - tile_w = (in_buf->vb.width * (q_data[V4L2_M2M_DST].fmt->depth >> 3)) + tile_w = (width * (q_data[V4L2_M2M_DST].fmt->depth >> 3)) / MEM2MEM_NUM_TILES; - bytes_left = in_buf->vb.bytesperline - tile_w * MEM2MEM_NUM_TILES; + bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES; w = 0; - for (y = 0; y < in_buf->vb.height; ++y) { + for (y = 0; y < height; ++y) { for (t = 0; t < MEM2MEM_NUM_TILES; ++t) { if (w & 0x1) { for (x = 0; x < tile_w; ++x) @@ -301,6 +300,21 @@ static void job_abort(void *priv) ctx->aborting = 1; } +static void m2mtest_lock(void *priv) +{ + struct m2mtest_ctx *ctx = priv; + struct m2mtest_dev *dev = ctx->dev; + mutex_lock(&dev->dev_mutex); +} + +static void m2mtest_unlock(void *priv) +{ + struct m2mtest_ctx *ctx = priv; + struct m2mtest_dev *dev = ctx->dev; + mutex_unlock(&dev->dev_mutex); +} + + /* device_run() - prepares and starts the device * * This simulates all the immediate preparations required before starting @@ -311,7 +325,7 @@ static void device_run(void *priv) { struct m2mtest_ctx *ctx = priv; struct m2mtest_dev *dev = ctx->dev; - struct m2mtest_buffer *src_buf, *dst_buf; + struct vb2_buffer *src_buf, *dst_buf; src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); @@ -322,12 +336,11 @@ static void device_run(void *priv) schedule_irq(dev, ctx->transtime); } - static void device_isr(unsigned long priv) { struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv; struct m2mtest_ctx *curr_ctx; - struct m2mtest_buffer *src_buf, *dst_buf; + struct vb2_buffer *src_vb, *dst_vb; unsigned long flags; curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev); @@ -338,31 +351,26 @@ static void device_isr(unsigned long priv) return; } - src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + curr_ctx->num_processed++; + spin_lock_irqsave(&m2mtest_dev->irqlock, flags); + v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); + spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags); + if (curr_ctx->num_processed == curr_ctx->translen || curr_ctx->aborting) { dprintk(curr_ctx->dev, "Finishing transaction\n"); curr_ctx->num_processed = 0; - spin_lock_irqsave(&m2mtest_dev->irqlock, flags); - src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE; - wake_up(&src_buf->vb.done); - wake_up(&dst_buf->vb.done); - spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags); v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx); } else { - spin_lock_irqsave(&m2mtest_dev->irqlock, flags); - src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE; - wake_up(&src_buf->vb.done); - wake_up(&dst_buf->vb.done); - spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags); device_run(curr_ctx); } } - /* * video ioctls */ @@ -423,7 +431,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) { - struct videobuf_queue *vq; + struct vb2_queue *vq; struct m2mtest_q_data *q_data; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); @@ -434,7 +442,7 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) f->fmt.pix.width = q_data->width; f->fmt.pix.height = q_data->height; - f->fmt.pix.field = vq->field; + f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.pixelformat = q_data->fmt->fourcc; f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3; f->fmt.pix.sizeimage = q_data->sizeimage; @@ -523,7 +531,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) { struct m2mtest_q_data *q_data; - struct videobuf_queue *vq; + struct vb2_queue *vq; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); if (!vq) @@ -533,7 +541,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) if (!q_data) return -EINVAL; - if (videobuf_queue_is_busy(vq)) { + if (vb2_is_busy(vq)) { v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); return -EBUSY; } @@ -543,7 +551,6 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f) q_data->height = f->fmt.pix.height; q_data->sizeimage = q_data->width * q_data->height * q_data->fmt->depth >> 3; - vq->field = f->fmt.pix.field; dprintk(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d\n", @@ -733,120 +740,94 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = { * Queue operations */ -static void m2mtest_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct m2mtest_ctx *ctx = vq->priv_data; - - dprintk(ctx->dev, "type: %d, index: %d, state: %d\n", - vq->type, vb->i, vb->state); - - videobuf_vmalloc_free(vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static int m2mtest_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int m2mtest_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned long sizes[], + void *alloc_ctxs[]) { - struct m2mtest_ctx *ctx = vq->priv_data; + struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq); struct m2mtest_q_data *q_data; + unsigned int size, count = *nbuffers; q_data = get_q_data(vq->type); - *size = q_data->width * q_data->height * q_data->fmt->depth >> 3; - dprintk(ctx->dev, "size:%d, w/h %d/%d, depth: %d\n", - *size, q_data->width, q_data->height, q_data->fmt->depth); + size = q_data->width * q_data->height * q_data->fmt->depth >> 3; - if (0 == *count) - *count = MEM2MEM_DEF_NUM_BUFS; + while (size * count > MEM2MEM_VID_MEM_LIMIT) + (count)--; - while (*size * *count > MEM2MEM_VID_MEM_LIMIT) - (*count)--; + *nplanes = 1; + *nbuffers = count; + sizes[0] = size; - v4l2_info(&ctx->dev->v4l2_dev, - "%d buffers of size %d set up.\n", *count, *size); + /* + * videobuf2-vmalloc allocator is context-less so no need to set + * alloc_ctxs array. + */ + + dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size); return 0; } -static int m2mtest_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int m2mtest_buf_prepare(struct vb2_buffer *vb) { - struct m2mtest_ctx *ctx = vq->priv_data; + struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct m2mtest_q_data *q_data; - int ret; - dprintk(ctx->dev, "type: %d, index: %d, state: %d\n", - vq->type, vb->i, vb->state); + dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); - q_data = get_q_data(vq->type); + q_data = get_q_data(vb->vb2_queue->type); - if (vb->baddr) { - /* User-provided buffer */ - if (vb->bsize < q_data->sizeimage) { - /* Buffer too small to fit a frame */ - v4l2_err(&ctx->dev->v4l2_dev, - "User-provided buffer too small\n"); - return -EINVAL; - } - } else if (vb->state != VIDEOBUF_NEEDS_INIT - && vb->bsize < q_data->sizeimage) { - /* We provide the buffer, but it's already been initialized - * and is too small */ + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage); return -EINVAL; } - vb->width = q_data->width; - vb->height = q_data->height; - vb->bytesperline = (q_data->width * q_data->fmt->depth) >> 3; - vb->size = q_data->sizeimage; - vb->field = field; - - if (VIDEOBUF_NEEDS_INIT == vb->state) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret) { - v4l2_err(&ctx->dev->v4l2_dev, - "Iolock failed\n"); - goto fail; - } - } - - vb->state = VIDEOBUF_PREPARED; + vb2_set_plane_payload(vb, 0, q_data->sizeimage); return 0; -fail: - m2mtest_buf_release(vq, vb); - return ret; } -static void m2mtest_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void m2mtest_buf_queue(struct vb2_buffer *vb) { - struct m2mtest_ctx *ctx = vq->priv_data; - - v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb); + struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); } -static struct videobuf_queue_ops m2mtest_qops = { - .buf_setup = m2mtest_buf_setup, - .buf_prepare = m2mtest_buf_prepare, - .buf_queue = m2mtest_buf_queue, - .buf_release = m2mtest_buf_release, +static struct vb2_ops m2mtest_qops = { + .queue_setup = m2mtest_queue_setup, + .buf_prepare = m2mtest_buf_prepare, + .buf_queue = m2mtest_buf_queue, }; -static void queue_init(void *priv, struct videobuf_queue *vq, - enum v4l2_buf_type type) +static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { struct m2mtest_ctx *ctx = priv; - struct m2mtest_dev *dev = ctx->dev; + int ret; - videobuf_queue_vmalloc_init(vq, &m2mtest_qops, dev->v4l2_dev.dev, - &dev->irqlock, type, V4L2_FIELD_NONE, - sizeof(struct m2mtest_buffer), priv, - &dev->dev_mutex); -} + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &m2mtest_qops; + src_vq->mem_ops = &vb2_vmalloc_memops; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &m2mtest_qops; + dst_vq->mem_ops = &vb2_vmalloc_memops; + + return vb2_queue_init(dst_vq); +} /* * File operations @@ -866,7 +847,8 @@ static int m2mtest_open(struct file *file) ctx->transtime = MEM2MEM_DEF_TRANSTIME; ctx->num_processed = 0; - ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, dev->m2m_dev, queue_init); + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->m2m_ctx)) { int ret = PTR_ERR(ctx->m2m_ctx); @@ -932,6 +914,8 @@ static struct v4l2_m2m_ops m2m_ops = { .device_run = device_run, .job_ready = job_ready, .job_abort = job_abort, + .lock = m2mtest_lock, + .unlock = m2mtest_unlock, }; static int m2mtest_probe(struct platform_device *pdev) @@ -990,6 +974,7 @@ static int m2mtest_probe(struct platform_device *pdev) return 0; + v4l2_m2m_release(dev->m2m_dev); err_m2m: video_unregister_device(dev->vfd); rel_vdev: -- cgit v1.2.2 From 2dab38e2272e9b30540e2782ef7aa8bc45848144 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 1 Dec 2010 10:14:59 -0300 Subject: [media] s5p-fimc: Porting to videobuf 2 Porting to videobuf 2 and minor cleanup. Separate videobuf_queue_ops are are created for m2m and capture video nodes. Signed-off-by: Sylwester Nawrocki Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 3 +- drivers/media/video/s5p-fimc/fimc-capture.c | 265 +++++++++++++++++++++++++--- drivers/media/video/s5p-fimc/fimc-core.c | 216 +++++++++++------------ drivers/media/video/s5p-fimc/fimc-core.h | 48 ++--- 4 files changed, 363 insertions(+), 169 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 1c0f080599e8..9f20fc5903c2 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -999,8 +999,7 @@ config VIDEO_MEM2MEM_TESTDEV config VIDEO_SAMSUNG_S5P_FIMC tristate "Samsung S5P FIMC (video postprocessor) driver" depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P - depends on BROKEN - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help This is a v4l2 driver for the S5P camera interface diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 2f500809f53d..24b77b76e68d 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -27,8 +27,8 @@ #include #include #include -#include -#include +#include +#include #include "fimc-core.h" @@ -141,7 +141,7 @@ static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index) * Locking: The caller holds fimc->slock spinlock. */ int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, - struct fimc_vid_buffer *fimc_vb) + struct fimc_vid_buffer *fimc_vb) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_ctx *ctx = cap->ctx; @@ -149,7 +149,7 @@ int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, BUG_ON(!fimc || !fimc_vb); - ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame, + ret = fimc_prepare_addr(ctx, &fimc_vb->vb, &ctx->d_frame, &fimc_vb->paddr); if (ret) return ret; @@ -174,7 +174,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc) { unsigned long flags; struct fimc_vid_cap *cap; - int ret; + struct fimc_vid_buffer *buf; cap = &fimc->vid_cap; @@ -199,12 +199,224 @@ static int fimc_stop_capture(struct fimc_dev *fimc) 1 << ST_CAPT_STREAM); fimc->vid_cap.active_buf_cnt = 0; + + /* Release buffers that were enqueued in the driver by videobuf2. */ + while (!list_empty(&cap->pending_buf_q)) { + buf = pending_queue_pop(cap); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + while (!list_empty(&cap->active_buf_q)) { + buf = active_queue_pop(cap); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&fimc->slock, flags); dbg("state: 0x%lx", fimc->state); return 0; } +static int start_streaming(struct vb2_queue *q) +{ + struct fimc_ctx *ctx = q->drv_priv; + struct fimc_dev *fimc = ctx->fimc_dev; + struct s3c_fimc_isp_info *isp_info; + int ret; + + ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) + return ret; + + ret = fimc_prepare_config(ctx, ctx->state); + if (ret) + return ret; + + isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; + fimc_hw_set_camera_type(fimc, isp_info); + fimc_hw_set_camera_source(fimc, isp_info); + fimc_hw_set_camera_offset(fimc, &ctx->s_frame); + + if (ctx->state & FIMC_PARAMS) { + ret = fimc_set_scaler_info(ctx); + if (ret) { + err("Scaler setup error"); + return ret; + } + fimc_hw_set_input_path(ctx); + fimc_hw_set_scaler(ctx); + fimc_hw_set_target_format(ctx); + fimc_hw_set_rotation(ctx); + fimc_hw_set_effect(ctx); + } + + fimc_hw_set_output_path(ctx); + fimc_hw_set_out_dma(ctx); + + INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); + 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); + + return 0; +} + +static int stop_streaming(struct vb2_queue *q) +{ + struct fimc_ctx *ctx = q->drv_priv; + struct fimc_dev *fimc = ctx->fimc_dev; + unsigned long flags; + + spin_lock_irqsave(&fimc->slock, flags); + if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) { + spin_unlock_irqrestore(&fimc->slock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&fimc->slock, flags); + + return fimc_stop_capture(fimc); +} + +static unsigned int get_plane_size(struct fimc_frame *frame, unsigned int plane) +{ + unsigned long size = 0; + + if (!frame || plane > frame->fmt->buff_cnt - 1) + return 0; + + if (1 == frame->fmt->planes_cnt) { + size = (frame->width * frame->height * frame->fmt->depth) >> 3; + } else if (frame->fmt->planes_cnt <= 3) { + switch (plane) { + case 0: + size = frame->width * frame->height; + break; + case 1: + case 2: + if (S5P_FIMC_YCBCR420 == frame->fmt->color + && 2 != frame->fmt->planes_cnt) + size = (frame->width * frame->height) >> 2; + else /* 422 */ + size = (frame->width * frame->height) >> 1; + break; + } + } else { + size = 0; + } + + return size; +} + +static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, + unsigned int *num_planes, unsigned long sizes[], + void *allocators[]) +{ + struct fimc_ctx *ctx = vq->drv_priv; + struct fimc_fmt *fmt = fmt = ctx->d_frame.fmt; + struct fimc_frame *frame; + + if (!fmt) + return -EINVAL; + + *num_planes = fmt->buff_cnt; + + dbg("%s, buffer count=%d, plane count=%d", + __func__, *num_buffers, *num_planes); + + frame = ctx_get_frame(ctx, vq->type); + if (IS_ERR(frame)) + return PTR_ERR(frame); + + sizes[0] = get_plane_size(frame, 0); + allocators[0] = ctx->fimc_dev->alloc_ctx; + + return -EINVAL; +} + +static int buffer_init(struct vb2_buffer *vb) +{ + /* TODO: */ + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct fimc_ctx *ctx = vq->drv_priv; + struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev; + struct fimc_frame *frame; + unsigned long size; + int i; + + frame = ctx_get_frame(ctx, vq->type); + if (IS_ERR(frame)) + return PTR_ERR(frame); + + for (i = 0; i < frame->fmt->buff_cnt; i++) { + size = get_plane_size(frame, i); + + if (vb2_plane_size(vb, i) < size) { + v4l2_err(v4l2_dev, "User buffer too small (%ld < %ld)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, i, size); + } + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_vid_buffer *buf + = container_of(vb, struct fimc_vid_buffer, vb); + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + unsigned long flags; + + spin_lock_irqsave(&fimc->slock, flags); + fimc_vid_cap_buf_queue(fimc, buf); + + dbg("active_buf_cnt: %d", fimc->vid_cap.active_buf_cnt); + + if (vid_cap->active_buf_cnt >= vid_cap->reqbufs_count || + vid_cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) { + if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { + fimc_activate_capture(ctx); + dbg(""); + } + } + spin_unlock_irqrestore(&fimc->slock, flags); +} + +static void fimc_lock(struct vb2_queue *vq) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + mutex_lock(&ctx->fimc_dev->lock); +} + +static void fimc_unlock(struct vb2_queue *vq) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + mutex_unlock(&ctx->fimc_dev->lock); +} + +static struct vb2_ops fimc_capture_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_init = buffer_init, + .wait_prepare = fimc_unlock, + .wait_finish = fimc_lock, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, +}; + static int fimc_capture_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); @@ -244,11 +456,10 @@ static int fimc_capture_close(struct file *file) if (--fimc->vid_cap.refcnt == 0) { fimc_stop_capture(fimc); - - videobuf_stop(&fimc->vid_cap.vbq); - videobuf_mmap_free(&fimc->vid_cap.vbq); + vb2_queue_release(&fimc->vid_cap.vbq); v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n"); + v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); fimc_subdev_unregister(fimc); } @@ -262,13 +473,12 @@ static unsigned int fimc_capture_poll(struct file *file, { struct fimc_ctx *ctx = file->private_data; struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *cap = &fimc->vid_cap; int ret; if (mutex_lock_interruptible(&fimc->lock)) return POLLERR; - ret = videobuf_poll_stream(file, &cap->vbq, wait); + ret = vb2_poll(&fimc->vid_cap.vbq, file, wait); mutex_unlock(&fimc->lock); return ret; @@ -278,13 +488,12 @@ static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) { struct fimc_ctx *ctx = file->private_data; struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *cap = &fimc->vid_cap; int ret; if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; - ret = videobuf_mmap_mapper(&cap->vbq, vma); + ret = vb2_mmap(&fimc->vid_cap.vbq, vma); mutex_unlock(&fimc->lock); return ret; @@ -470,7 +679,7 @@ static int fimc_cap_g_input(struct file *file, void *priv, } static int fimc_cap_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) + enum v4l2_buf_type type) { struct s3c_fimc_isp_info *isp_info; struct fimc_ctx *ctx = priv; @@ -525,7 +734,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, 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); + ret = vb2_streamon(&fimc->vid_cap.vbq, type); s_unlock: mutex_unlock(&fimc->lock); @@ -533,7 +742,7 @@ s_unlock: } static int fimc_cap_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) + enum v4l2_buf_type type) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; @@ -553,7 +762,8 @@ static int fimc_cap_streamoff(struct file *file, void *priv, return -ERESTARTSYS; fimc_stop_capture(fimc); - ret = videobuf_streamoff(&cap->vbq); + ret = vb2_streamoff(&cap->vbq, type); + mutex_unlock(&fimc->lock); return ret; } @@ -572,7 +782,7 @@ static int fimc_cap_reqbufs(struct file *file, void *priv, if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; - ret = videobuf_reqbufs(&cap->vbq, reqbufs); + ret = vb2_reqbufs(&cap->vbq, reqbufs); if (!ret) cap->reqbufs_count = reqbufs->count; @@ -589,7 +799,7 @@ static int fimc_cap_querybuf(struct file *file, void *priv, if (fimc_capture_active(ctx->fimc_dev)) return -EBUSY; - return videobuf_querybuf(&cap->vbq, buf); + return vb2_querybuf(&cap->vbq, buf); } static int fimc_cap_qbuf(struct file *file, void *priv, @@ -603,7 +813,7 @@ static int fimc_cap_qbuf(struct file *file, void *priv, if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; - ret = videobuf_qbuf(&cap->vbq, buf); + ret = vb2_qbuf(&cap->vbq, buf); mutex_unlock(&fimc->lock); return ret; @@ -618,7 +828,7 @@ static int fimc_cap_dqbuf(struct file *file, void *priv, if (mutex_lock_interruptible(&ctx->fimc_dev->lock)) return -ERESTARTSYS; - ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf, + ret = vb2_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); mutex_unlock(&ctx->fimc_dev->lock); @@ -777,6 +987,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc) struct fimc_vid_cap *vid_cap; struct fimc_ctx *ctx; struct v4l2_format f; + struct vb2_queue *q; int ret; ctx = kzalloc(sizeof *ctx, GFP_KERNEL); @@ -827,10 +1038,16 @@ int fimc_register_capture_device(struct fimc_dev *fimc) spin_lock_init(&ctx->slock); vid_cap->ctx = ctx; - 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, NULL); + q = &fimc->vid_cap.vbq; + memset(q, 0, sizeof(*q)); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = fimc->vid_cap.ctx; + q->ops = &fimc_capture_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct fimc_vid_buffer); + + vb2_queue_init(q); 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 817aa66627f6..65d25b374f5c 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -25,7 +25,8 @@ #include #include #include -#include +#include +#include #include "fimc-core.h" @@ -283,7 +284,7 @@ static void fimc_capture_handler(struct fimc_dev *fimc) if (!list_empty(&cap->active_buf_q)) { v_buf = active_queue_pop(cap); - fimc_buf_finish(fimc, v_buf); + vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { @@ -300,10 +301,6 @@ static void fimc_capture_handler(struct fimc_dev *fimc) dbg("hw ptr: %d, sw ptr: %d", fimc_hw_get_frame_index(fimc), cap->buf_index); - spin_lock(&fimc->irqlock); - v_buf->vb.state = VIDEOBUF_ACTIVE; - spin_unlock(&fimc->irqlock); - /* Move the buffer to the capture active queue */ active_queue_add(cap, v_buf); @@ -324,8 +321,6 @@ static void fimc_capture_handler(struct fimc_dev *fimc) static irqreturn_t fimc_isr(int irq, void *priv) { - struct fimc_vid_buffer *src_buf, *dst_buf; - struct fimc_ctx *ctx; struct fimc_dev *fimc = priv; BUG_ON(!fimc); @@ -334,17 +329,17 @@ static irqreturn_t fimc_isr(int irq, void *priv) spin_lock(&fimc->slock); if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { - ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); + struct vb2_buffer *src_vb, *dst_vb; + struct fimc_ctx *ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); + if (!ctx || !ctx->m2m_ctx) goto isr_unlock; - src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - if (src_buf && dst_buf) { - spin_lock(&fimc->irqlock); - src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE; - wake_up(&src_buf->vb.done); - wake_up(&dst_buf->vb.done); - spin_unlock(&fimc->irqlock); + + src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + if (src_vb && dst_vb) { + v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); } goto isr_unlock; @@ -365,13 +360,13 @@ isr_unlock: } /* The color format (planes_cnt, buff_cnt) must be already configured. */ -int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf, +int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, struct fimc_frame *frame, struct fimc_addr *paddr) { int ret = 0; u32 pix_size; - if (buf == NULL || frame == NULL) + if (vb == NULL || frame == NULL) return -EINVAL; pix_size = frame->width * frame->height; @@ -381,7 +376,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf, frame->size, pix_size); if (frame->fmt->buff_cnt == 1) { - paddr->y = videobuf_to_dma_contig(&buf->vb); + paddr->y = vb2_dma_contig_plane_paddr(vb, 0); switch (frame->fmt->planes_cnt) { case 1: paddr->cb = 0; @@ -499,7 +494,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) { struct fimc_frame *s_frame, *d_frame; - struct fimc_vid_buffer *buf = NULL; + struct vb2_buffer *vb = NULL; int ret = 0; s_frame = &ctx->s_frame; @@ -522,15 +517,15 @@ int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags) ctx->scaler.enabled = 1; if (flags & FIMC_SRC_ADDR) { - buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, buf, s_frame, &s_frame->paddr); + vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr); if (ret) return ret; } if (flags & FIMC_DST_ADDR) { - buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, buf, d_frame, &d_frame->paddr); + vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + ret = fimc_prepare_addr(ctx, vb, d_frame, &d_frame->paddr); } return ret; @@ -587,7 +582,8 @@ static void fimc_dma_run(void *priv) fimc_activate_capture(ctx); - ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); + ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP | + FIMC_SRC_FMT | FIMC_DST_FMT); fimc_hw_activate_input_dma(fimc, true); dma_unlock: @@ -599,106 +595,72 @@ static void fimc_job_abort(void *priv) /* Nothing done in job_abort. */ } -static void fimc_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, + unsigned int *num_planes, unsigned long sizes[], + void *allocators[]) { - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + struct fimc_frame *fr; -static int fimc_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - struct fimc_ctx *ctx = vq->priv_data; - struct fimc_frame *frame; + fr = ctx_get_frame(ctx, vq->type); + if (IS_ERR(fr)) + return PTR_ERR(fr); - frame = ctx_get_frame(ctx, vq->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); + *num_planes = 1; + + sizes[0] = (fr->width * fr->height * fr->fmt->depth) >> 3; + allocators[0] = ctx->fimc_dev->alloc_ctx; - *size = (frame->width * frame->height * frame->fmt->depth) >> 3; - if (0 == *count) - *count = 1; return 0; } -static int fimc_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) +static int fimc_buf_prepare(struct vb2_buffer *vb) { - struct fimc_ctx *ctx = vq->priv_data; - struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev; + struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct fimc_frame *frame; - int ret; - frame = ctx_get_frame(ctx, vq->type); + frame = ctx_get_frame(ctx, vb->vb2_queue->type); if (IS_ERR(frame)) return PTR_ERR(frame); - if (vb->baddr) { - if (vb->bsize < frame->size) { - v4l2_err(v4l2_dev, - "User-provided buffer too small (%d < %d)\n", - vb->bsize, frame->size); - WARN_ON(1); - return -EINVAL; - } - } else if (vb->state != VIDEOBUF_NEEDS_INIT - && vb->bsize < frame->size) { + if (vb2_plane_size(vb, 0) < frame->size) { + dbg("%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), (long)frame->size); return -EINVAL; } - vb->width = frame->width; - vb->height = frame->height; - vb->bytesperline = (frame->width * frame->fmt->depth) >> 3; - vb->size = frame->size; - vb->field = field; - - if (VIDEOBUF_NEEDS_INIT == vb->state) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret) { - v4l2_err(v4l2_dev, "Iolock failed\n"); - fimc_buf_release(vq, vb); - return ret; - } - } - vb->state = VIDEOBUF_PREPARED; - + vb2_set_plane_payload(vb, 0, frame->size); return 0; } -static void fimc_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void fimc_buf_queue(struct vb2_buffer *vb) { - struct fimc_ctx *ctx = vq->priv_data; - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *cap = &fimc->vid_cap; - unsigned long flags; + struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state); - if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) { - v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb); - } else if (ctx->state & FIMC_CTX_CAP) { - spin_lock_irqsave(&fimc->slock, flags); - fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb); + if (ctx->m2m_ctx) + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} - dbg("fimc->cap.active_buf_cnt: %d", - fimc->vid_cap.active_buf_cnt); +static void fimc_lock(struct vb2_queue *vq) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + mutex_lock(&ctx->fimc_dev->lock); +} - if (cap->active_buf_cnt >= cap->reqbufs_count || - cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) { - if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) - fimc_activate_capture(ctx); - } - spin_unlock_irqrestore(&fimc->slock, flags); - } +static void fimc_unlock(struct vb2_queue *vq) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + mutex_unlock(&ctx->fimc_dev->lock); } -struct videobuf_queue_ops fimc_qops = { - .buf_setup = fimc_buf_setup, - .buf_prepare = fimc_buf_prepare, - .buf_queue = fimc_buf_queue, - .buf_release = fimc_buf_release, +struct vb2_ops fimc_qops = { + .queue_setup = fimc_queue_setup, + .buf_prepare = fimc_buf_prepare, + .buf_queue = fimc_buf_queue, + .wait_prepare = fimc_unlock, + .wait_finish = fimc_lock, }; static int fimc_m2m_querycap(struct file *file, void *priv, @@ -867,7 +829,7 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev; - struct videobuf_queue *vq; + struct vb2_queue *vq; struct fimc_frame *frame; struct v4l2_pix_format *pix; unsigned long flags; @@ -881,9 +843,8 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) return -ERESTARTSYS; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - mutex_lock(&vq->vb_lock); - if (videobuf_queue_is_busy(vq)) { + if (vb2_is_streaming(vq)) { v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type); ret = -EBUSY; goto sf_out; @@ -921,7 +882,6 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) frame->offs_h = 0; frame->offs_v = 0; frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3; - vq->field = pix->field; spin_lock_irqsave(&ctx->slock, flags); ctx->state |= FIMC_PARAMS; @@ -930,7 +890,6 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height); sf_out: - mutex_unlock(&vq->vb_lock); mutex_unlock(&fimc->lock); return ret; } @@ -968,6 +927,11 @@ static int fimc_m2m_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_ctx *ctx = priv; + + /* The source and target color format need to be set */ + if (~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT)) + return -EINVAL; + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); } @@ -1301,16 +1265,32 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { }; -static void queue_init(void *priv, struct videobuf_queue *vq, - enum v4l2_buf_type type) +static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->drv_priv = ctx; + src_vq->ops = &fimc_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - videobuf_queue_dma_contig_init(vq, &fimc_qops, - &fimc->pdev->dev, - &fimc->irqlock, type, V4L2_FIELD_NONE, - sizeof(struct fimc_vid_buffer), priv, NULL); + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->drv_priv = ctx; + dst_vq->ops = &fimc_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + + return vb2_queue_init(dst_vq); } static int fimc_m2m_open(struct file *file) @@ -1355,7 +1335,7 @@ static int fimc_m2m_open(struct file *file) ctx->out_path = FIMC_DMA; spin_lock_init(&ctx->slock); - ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, fimc->m2m.m2m_dev, queue_init); + ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); if (IS_ERR(ctx->m2m_ctx)) { err = PTR_ERR(ctx->m2m_ctx); kfree(ctx); @@ -1415,7 +1395,6 @@ static struct v4l2_m2m_ops m2m_ops = { .job_abort = fimc_job_abort, }; - static int fimc_register_m2m_device(struct fimc_dev *fimc) { struct video_device *vfd; @@ -1548,7 +1527,6 @@ static int fimc_probe(struct platform_device *pdev) fimc->pdata = pdev->dev.platform_data; fimc->state = ST_IDLE; - spin_lock_init(&fimc->irqlock); init_waitqueue_head(&fimc->irq_queue); spin_lock_init(&fimc->slock); @@ -1597,6 +1575,13 @@ static int fimc_probe(struct platform_device *pdev) goto err_clk; } + /* Initialize contiguous memory allocator */ + fimc->alloc_ctx = vb2_dma_contig_init_ctx(&fimc->pdev->dev); + if (IS_ERR(fimc->alloc_ctx)) { + ret = PTR_ERR(fimc->alloc_ctx); + goto err_irq; + } + ret = fimc_register_m2m_device(fimc); if (ret) goto err_irq; @@ -1656,6 +1641,9 @@ static int __devexit fimc_remove(struct platform_device *pdev) fimc_unregister_capture_device(fimc); fimc_clk_release(fimc); + + vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); + iounmap(fimc->regs); release_resource(fimc->regs_res); kfree(fimc->regs_res); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 4f047d35f8ad..590fbf230792 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -16,7 +16,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -70,13 +71,6 @@ enum fimc_dev_flags { #define fimc_capture_streaming(dev) \ test_bit(ST_CAPT_STREAM, &(dev)->state) -#define fimc_buf_finish(dev, vid_buf) do { \ - spin_lock(&(dev)->irqlock); \ - (vid_buf)->vb.state = VIDEOBUF_DONE; \ - spin_unlock(&(dev)->irqlock); \ - wake_up(&(vid_buf)->vb.done); \ -} while (0) - enum fimc_datapath { FIMC_CAMERA, FIMC_DMA, @@ -260,7 +254,8 @@ struct fimc_addr { * @index: buffer index for the output DMA engine */ struct fimc_vid_buffer { - struct videobuf_buffer vb; + struct vb2_buffer vb; + struct list_head list; struct fimc_addr paddr; int index; }; @@ -331,13 +326,14 @@ struct fimc_m2m_device { */ struct fimc_vid_cap { struct fimc_ctx *ctx; + struct vb2_alloc_ctx *alloc_ctx; struct video_device *vfd; struct v4l2_device v4l2_dev; - struct v4l2_subdev *sd; + struct v4l2_subdev *sd;; struct v4l2_mbus_framefmt fmt; struct list_head pending_buf_q; struct list_head active_buf_q; - struct videobuf_queue vbq; + struct vb2_queue vbq; int active_buf_cnt; int buf_index; unsigned int frame_count; @@ -417,7 +413,6 @@ struct fimc_ctx; * @regs: the mapped hardware registers * @regs_res: the resource claimed for IO registers * @irq: interrupt number of the FIMC subdevice - * @irqlock: spinlock protecting videobuffer queue * @irq_queue: * @m2m: memory-to-memory V4L2 device information * @vid_cap: camera capture device information @@ -434,11 +429,11 @@ struct fimc_dev { void __iomem *regs; struct resource *regs_res; int irq; - spinlock_t irqlock; wait_queue_head_t irq_queue; struct fimc_m2m_device m2m; struct fimc_vid_cap vid_cap; unsigned long state; + struct vb2_alloc_ctx *alloc_ctx; }; /** @@ -482,8 +477,6 @@ struct fimc_ctx { struct v4l2_m2m_ctx *m2m_ctx; }; -extern struct videobuf_queue_ops fimc_qops; - static inline int tiled_fmt(struct fimc_fmt *fmt) { return 0; @@ -622,7 +615,7 @@ struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f); int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); -int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf, +int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, struct fimc_frame *frame, struct fimc_addr *paddr); /* -----------------------------------------------------*/ @@ -649,28 +642,27 @@ static inline void fimc_deactivate_capture(struct fimc_dev *fimc) } /* - * Add video buffer to the active buffers queue. - * The caller holds irqlock spinlock. + * Add buf to the capture active buffers queue. + * Locking: Need to be called with fimc_dev::slock held. */ static inline void active_queue_add(struct fimc_vid_cap *vid_cap, - struct fimc_vid_buffer *buf) + struct fimc_vid_buffer *buf) { - buf->vb.state = VIDEOBUF_ACTIVE; - list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q); + list_add_tail(&buf->list, &vid_cap->active_buf_q); vid_cap->active_buf_cnt++; } /* * Pop a video buffer from the capture active buffers queue - * Locking: Need to be called with dev->slock held. + * Locking: Need to be called with fimc_dev::slock held. */ static inline struct fimc_vid_buffer * active_queue_pop(struct fimc_vid_cap *vid_cap) { struct fimc_vid_buffer *buf; buf = list_entry(vid_cap->active_buf_q.next, - struct fimc_vid_buffer, vb.queue); - list_del(&buf->vb.queue); + struct fimc_vid_buffer, list); + list_del(&buf->list); vid_cap->active_buf_cnt--; return buf; } @@ -679,8 +671,7 @@ active_queue_pop(struct fimc_vid_cap *vid_cap) static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, struct fimc_vid_buffer *buf) { - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q); + list_add_tail(&buf->list, &vid_cap->pending_buf_q); } /* Add video buffer to the capture pending buffers queue */ @@ -689,10 +680,9 @@ pending_queue_pop(struct fimc_vid_cap *vid_cap) { struct fimc_vid_buffer *buf; buf = list_entry(vid_cap->pending_buf_q.next, - struct fimc_vid_buffer, vb.queue); - list_del(&buf->vb.queue); + struct fimc_vid_buffer, list); + list_del(&buf->list); return buf; } - #endif /* FIMC_CORE_H_ */ -- cgit v1.2.2 From ef7af59b2cf950a44576d4364459ffd3d5d1d9bc Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 8 Dec 2010 14:05:08 -0300 Subject: [media] s5p-fimc: Conversion to multiplanar formats Conversion to multiplanar color formats and minor cleanup. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 114 ++++---- drivers/media/video/s5p-fimc/fimc-core.c | 387 ++++++++++++++++------------ drivers/media/video/s5p-fimc/fimc-core.h | 37 ++- drivers/media/video/s5p-fimc/fimc-reg.c | 14 +- 4 files changed, 304 insertions(+), 248 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 24b77b76e68d..e746b684c3b8 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -280,34 +280,16 @@ static int stop_streaming(struct vb2_queue *q) return fimc_stop_capture(fimc); } -static unsigned int get_plane_size(struct fimc_frame *frame, unsigned int plane) +static unsigned int get_plane_size(struct fimc_frame *fr, unsigned int plane) { - unsigned long size = 0; - - if (!frame || plane > frame->fmt->buff_cnt - 1) + if (!fr || plane >= fr->fmt->memplanes) return 0; - if (1 == frame->fmt->planes_cnt) { - size = (frame->width * frame->height * frame->fmt->depth) >> 3; - } else if (frame->fmt->planes_cnt <= 3) { - switch (plane) { - case 0: - size = frame->width * frame->height; - break; - case 1: - case 2: - if (S5P_FIMC_YCBCR420 == frame->fmt->color - && 2 != frame->fmt->planes_cnt) - size = (frame->width * frame->height) >> 2; - else /* 422 */ - size = (frame->width * frame->height) >> 1; - break; - } - } else { - size = 0; - } + dbg("%s: w: %d. h: %d. depth[%d]: %d", + __func__, fr->width, fr->height, plane, fr->fmt->depth[plane]); + + return fr->f_width * fr->f_height * fr->fmt->depth[plane] / 8; - return size; } static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, @@ -315,25 +297,24 @@ static int queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, void *allocators[]) { struct fimc_ctx *ctx = vq->drv_priv; - struct fimc_fmt *fmt = fmt = ctx->d_frame.fmt; - struct fimc_frame *frame; + struct fimc_fmt *fmt = ctx->d_frame.fmt; + int i; if (!fmt) return -EINVAL; - *num_planes = fmt->buff_cnt; + *num_planes = fmt->memplanes; dbg("%s, buffer count=%d, plane count=%d", __func__, *num_buffers, *num_planes); - - frame = ctx_get_frame(ctx, vq->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - sizes[0] = get_plane_size(frame, 0); - allocators[0] = ctx->fimc_dev->alloc_ctx; + for (i = 0; i < fmt->memplanes; i++) { + sizes[i] = get_plane_size(&ctx->d_frame, i); + dbg("plane: %u, plane_size: %lu", i, sizes[i]); + allocators[i] = ctx->fimc_dev->alloc_ctx; + } - return -EINVAL; + return 0; } static int buffer_init(struct vb2_buffer *vb) @@ -347,16 +328,13 @@ static int buffer_prepare(struct vb2_buffer *vb) struct vb2_queue *vq = vb->vb2_queue; struct fimc_ctx *ctx = vq->drv_priv; struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev; - struct fimc_frame *frame; - unsigned long size; int i; - frame = ctx_get_frame(ctx, vq->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); + if (!ctx->d_frame.fmt || vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; - for (i = 0; i < frame->fmt->buff_cnt; i++) { - size = get_plane_size(frame, i); + for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) { + unsigned long size = get_plane_size(&ctx->d_frame, i); if (vb2_plane_size(vb, i) < size) { v4l2_err(v4l2_dev, "User buffer too small (%ld < %ld)\n", @@ -451,7 +429,6 @@ static int fimc_capture_close(struct file *file) if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; - dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); if (--fimc->vid_cap.refcnt == 0) { @@ -519,7 +496,8 @@ static int fimc_vidioc_querycap_capture(struct file *file, void *priv, strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE; return 0; } @@ -560,19 +538,20 @@ static int sync_capture_fmt(struct fimc_ctx *ctx) return 0; } -static int fimc_cap_s_fmt(struct file *file, void *priv, - struct v4l2_format *f) +static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *frame; - struct v4l2_pix_format *pix; + struct v4l2_pix_format_mplane *pix; int ret; + int i; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - ret = fimc_vidioc_try_fmt(file, priv, f); + ret = fimc_vidioc_try_fmt_mplane(file, priv, f); if (ret) return ret; @@ -583,10 +562,12 @@ static int fimc_cap_s_fmt(struct file *file, void *priv, ret = -EBUSY; goto sf_unlock; } + if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) + return -EBUSY; frame = &ctx->d_frame; - pix = &f->fmt.pix; + pix = &f->fmt.pix_mp; frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM); if (!frame->fmt) { err("fimc target format not found\n"); @@ -594,14 +575,17 @@ static int fimc_cap_s_fmt(struct file *file, void *priv, goto sf_unlock; } + for (i = 0; i < frame->fmt->colplanes; i++) + frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + /* Output DMA frame pixel size and offsets. */ - frame->f_width = pix->bytesperline * 8 / frame->fmt->depth; + frame->f_width = pix->plane_fmt[0].bytesperline * 8 + / frame->fmt->depth[0]; frame->f_height = pix->height; frame->width = pix->width; frame->height = pix->height; frame->o_width = pix->width; frame->o_height = pix->height; - frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3; frame->offs_h = 0; frame->offs_v = 0; @@ -769,7 +753,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv, } static int fimc_cap_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) + struct v4l2_requestbuffers *reqbufs) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; @@ -870,13 +854,13 @@ static int fimc_cap_cropcap(struct file *file, void *fh, struct fimc_ctx *ctx = fh; struct fimc_dev *fimc = ctx->fimc_dev; - if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 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; @@ -953,10 +937,10 @@ sc_unlock: static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_querycap = fimc_vidioc_querycap_capture, - .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt, - .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt, - .vidioc_s_fmt_vid_cap = fimc_cap_s_fmt, - .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt, + .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = fimc_vidioc_try_fmt_mplane, + .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = fimc_vidioc_g_fmt_mplane, .vidioc_reqbufs = fimc_cap_reqbufs, .vidioc_querybuf = fimc_cap_querybuf, @@ -980,6 +964,7 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_g_input = fimc_cap_g_input, }; +/* fimc->lock must be already initialized */ int fimc_register_capture_device(struct fimc_dev *fimc) { struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev; @@ -987,6 +972,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc) struct fimc_vid_cap *vid_cap; struct fimc_ctx *ctx; struct v4l2_format f; + struct fimc_frame *fr; struct vb2_queue *q; int ret; @@ -999,8 +985,12 @@ int fimc_register_capture_device(struct fimc_dev *fimc) ctx->out_path = FIMC_DMA; ctx->state = FIMC_CTX_CAP; - f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; - ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M); + /* Default format of the output frames */ + f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32; + fr = &ctx->d_frame; + fr->fmt = find_format(&f, FMT_FLAGS_M2M); + fr->width = fr->f_width = fr->o_width = 640; + fr->height = fr->f_height = fr->o_height = 480; if (!v4l2_dev->name[0]) snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), @@ -1030,7 +1020,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc) vid_cap->active_buf_cnt = 0; vid_cap->reqbufs_count = 0; vid_cap->refcnt = 0; - /* The default color format for image sensor. */ + /* Default color format for image sensor */ vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; INIT_LIST_HEAD(&vid_cap->pending_buf_q); @@ -1040,7 +1030,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc) q = &fimc->vid_cap.vbq; memset(q, 0, sizeof(*q)); - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; q->io_modes = VB2_MMAP | VB2_USERPTR; q->drv_priv = fimc->vid_cap.ctx; q->ops = &fimc_capture_qops; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 65d25b374f5c..fe210976f30b 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -34,106 +34,130 @@ static char *fimc_clock_name[NUM_FIMC_CLOCKS] = { "sclk_fimc", "fimc" }; static struct fimc_fmt fimc_formats[] = { { - .name = "RGB565", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = 16, - .color = S5P_FIMC_RGB565, - .buff_cnt = 1, - .planes_cnt = 1, - .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE, - .flags = FMT_FLAGS_M2M, + .name = "RGB565", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = { 16 }, + .color = S5P_FIMC_RGB565, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE, + .flags = FMT_FLAGS_M2M, }, { - .name = "BGR666", - .fourcc = V4L2_PIX_FMT_BGR666, - .depth = 32, - .color = S5P_FIMC_RGB666, - .buff_cnt = 1, - .planes_cnt = 1, - .flags = FMT_FLAGS_M2M, + .name = "BGR666", + .fourcc = V4L2_PIX_FMT_BGR666, + .depth = { 32 }, + .color = S5P_FIMC_RGB666, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M, }, { - .name = "XRGB-8-8-8-8, 32 bpp", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = 32, - .color = S5P_FIMC_RGB888, - .buff_cnt = 1, - .planes_cnt = 1, - .flags = FMT_FLAGS_M2M, + .name = "XRGB-8-8-8-8, 32 bpp", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = { 32 }, + .color = S5P_FIMC_RGB888, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:2 packed, YCbYCr", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .color = S5P_FIMC_YCBYCR422, - .buff_cnt = 1, - .planes_cnt = 1, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = { 16 }, + .color = S5P_FIMC_YCBYCR422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, CbYCrY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .color = S5P_FIMC_CBYCRY422, - .buff_cnt = 1, - .planes_cnt = 1, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + .name = "YUV 4:2:2 packed, CbYCrY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = { 16 }, + .color = S5P_FIMC_CBYCRY422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, CrYCbY", - .fourcc = V4L2_PIX_FMT_VYUY, - .depth = 16, - .color = S5P_FIMC_CRYCBY422, - .buff_cnt = 1, - .planes_cnt = 1, - .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + .name = "YUV 4:2:2 packed, CrYCbY", + .fourcc = V4L2_PIX_FMT_VYUY, + .depth = { 16 }, + .color = S5P_FIMC_CRYCBY422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 packed, YCrYCb", - .fourcc = V4L2_PIX_FMT_YVYU, - .depth = 16, - .color = S5P_FIMC_YCRYCB422, - .buff_cnt = 1, - .planes_cnt = 1, - .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + .name = "YUV 4:2:2 packed, YCrYCb", + .fourcc = V4L2_PIX_FMT_YVYU, + .depth = { 16 }, + .color = S5P_FIMC_YCRYCB422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, }, { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", - .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = 12, - .color = S5P_FIMC_YCBCR422, - .buff_cnt = 1, - .planes_cnt = 3, - .flags = FMT_FLAGS_M2M, + .name = "YUV 4:2:2 planar, Y/Cb/Cr", + .fourcc = V4L2_PIX_FMT_YUV422P, + .depth = { 12 }, + .color = S5P_FIMC_YCBYCR422, + .memplanes = 1, + .colplanes = 3, + .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:2 planar, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV16, - .depth = 16, - .color = S5P_FIMC_YCBCR422, - .buff_cnt = 1, - .planes_cnt = 2, - .flags = FMT_FLAGS_M2M, + .name = "YUV 4:2:2 planar, Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV16, + .depth = { 16 }, + .color = S5P_FIMC_YCBYCR422, + .memplanes = 1, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:2 planar, Y/CrCb", - .fourcc = V4L2_PIX_FMT_NV61, - .depth = 16, - .color = S5P_FIMC_RGB565, - .buff_cnt = 1, - .planes_cnt = 2, - .flags = FMT_FLAGS_M2M, + .name = "YUV 4:2:2 planar, Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV61, + .depth = { 16 }, + .color = S5P_FIMC_YCRYCB422, + .memplanes = 1, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV420, - .depth = 12, - .color = S5P_FIMC_YCBCR420, - .buff_cnt = 1, - .planes_cnt = 3, - .flags = FMT_FLAGS_M2M, + .name = "YUV 4:2:0 planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = { 12 }, + .color = S5P_FIMC_YCBCR420, + .memplanes = 1, + .colplanes = 3, + .flags = FMT_FLAGS_M2M, }, { - .name = "YUV 4:2:0 planar, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12, - .depth = 12, - .color = S5P_FIMC_YCBCR420, - .buff_cnt = 1, - .planes_cnt = 2, - .flags = FMT_FLAGS_M2M, + .name = "YUV 4:2:0 planar, Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12, + .depth = { 12 }, + .color = S5P_FIMC_YCBCR420, + .memplanes = 1, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .color = S5P_FIMC_YCBCR420, + .depth = { 8, 4 }, + .memplanes = 2, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr", + .fourcc = V4L2_PIX_FMT_YUV420M, + .color = S5P_FIMC_YCBCR420, + .depth = { 8, 2, 2 }, + .memplanes = 3, + .colplanes = 3, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled", + .fourcc = V4L2_PIX_FMT_NV12MT, + .color = S5P_FIMC_YCBCR420, + .depth = { 8, 4 }, + .memplanes = 2, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, }, }; @@ -359,7 +383,7 @@ isr_unlock: return IRQ_HANDLED; } -/* The color format (planes_cnt, buff_cnt) must be already configured. */ +/* The color format (colplanes, memplanes) must be already configured. */ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, struct fimc_frame *frame, struct fimc_addr *paddr) { @@ -371,13 +395,13 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, pix_size = frame->width * frame->height; - dbg("buff_cnt= %d, planes_cnt= %d, frame->size= %d, pix_size= %d", - frame->fmt->buff_cnt, frame->fmt->planes_cnt, - frame->size, pix_size); + dbg("memplanes= %d, colplanes= %d, pix_size= %d", + frame->fmt->memplanes, frame->fmt->colplanes, pix_size); + + paddr->y = vb2_dma_contig_plane_paddr(vb, 0); - if (frame->fmt->buff_cnt == 1) { - paddr->y = vb2_dma_contig_plane_paddr(vb, 0); - switch (frame->fmt->planes_cnt) { + if (frame->fmt->memplanes == 1) { + switch (frame->fmt->colplanes) { case 1: paddr->cb = 0; paddr->cr = 0; @@ -400,6 +424,12 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, default: return -EINVAL; } + } else { + if (frame->fmt->memplanes >= 2) + paddr->cb = vb2_dma_contig_plane_paddr(vb, 1); + + if (frame->fmt->memplanes == 3) + paddr->cr = vb2_dma_contig_plane_paddr(vb, 2); } dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", @@ -454,10 +484,14 @@ static void fimc_set_yuv_order(struct fimc_ctx *ctx) static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) { struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; + u32 i, depth = 0; + + for (i = 0; i < f->fmt->colplanes; i++) + depth += f->fmt->depth[i]; f->dma_offset.y_h = f->offs_h; if (!variant->pix_hoff) - f->dma_offset.y_h *= (f->fmt->depth >> 3); + f->dma_offset.y_h *= (depth >> 3); f->dma_offset.y_v = f->offs_v; @@ -468,7 +502,7 @@ static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) f->dma_offset.cr_v = f->offs_v; if (!variant->pix_hoff) { - if (f->fmt->planes_cnt == 3) { + if (f->fmt->colplanes == 3) { f->dma_offset.cb_h >>= 1; f->dma_offset.cr_h >>= 1; } @@ -596,20 +630,31 @@ static void fimc_job_abort(void *priv) } static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, - unsigned int *num_planes, unsigned long sizes[], - void *allocators[]) + unsigned int *num_planes, unsigned long sizes[], + void *allocators[]) { struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - struct fimc_frame *fr; + struct fimc_frame *f; + int i; + + f = ctx_get_frame(ctx, vq->type); + if (IS_ERR(f)) + return PTR_ERR(f); - fr = ctx_get_frame(ctx, vq->type); - if (IS_ERR(fr)) - return PTR_ERR(fr); + /* + * Return number of non-contigous planes (plane buffers) + * depending on the configured color format. + */ + if (f->fmt) + *num_planes = f->fmt->memplanes; - *num_planes = 1; + for (i = 0; i < f->fmt->memplanes; i++) { + sizes[i] = (f->width * f->height * f->fmt->depth[i]) >> 3; + allocators[i] = ctx->fimc_dev->alloc_ctx; + } - sizes[0] = (fr->width * fr->height * fr->fmt->depth) >> 3; - allocators[0] = ctx->fimc_dev->alloc_ctx; + if (*num_buffers == 0) + *num_buffers = 1; return 0; } @@ -618,18 +663,15 @@ static int fimc_buf_prepare(struct vb2_buffer *vb) { struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct fimc_frame *frame; + int i; frame = ctx_get_frame(ctx, vb->vb2_queue->type); if (IS_ERR(frame)) return PTR_ERR(frame); - if (vb2_plane_size(vb, 0) < frame->size) { - dbg("%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), (long)frame->size); - return -EINVAL; - } + for (i = 0; i < frame->fmt->memplanes; i++) + vb2_set_plane_payload(vb, i, frame->payload[i]); - vb2_set_plane_payload(vb, 0, frame->size); return 0; } @@ -674,12 +716,13 @@ static int fimc_m2m_querycap(struct file *file, void *priv, cap->bus_info[0] = 0; cap->version = KERNEL_VERSION(1, 0, 0); cap->capabilities = V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT; + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; return 0; } -int fimc_vidioc_enum_fmt(struct file *file, void *priv, +int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct fimc_fmt *fmt; @@ -694,7 +737,8 @@ int fimc_vidioc_enum_fmt(struct file *file, void *priv, return 0; } -int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; @@ -747,29 +791,28 @@ struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, } -int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; struct samsung_fimc_variant *variant = fimc->variant; - struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct fimc_fmt *fmt; u32 max_width, mod_x, mod_y, mask; - int ret = -EINVAL, is_output = 0; + int ret, i, is_output = 0; - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->state & FIMC_CTX_CAP) return -EINVAL; is_output = 1; - } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { return -EINVAL; } - dbg("w: %d, h: %d, bpl: %d", - pix->width, pix->height, pix->bytesperline); - if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; + dbg("w: %d, h: %d", pix->width, pix->height); mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM; fmt = find_format(f, mask); @@ -796,7 +839,7 @@ int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) mod_x = 6; /* 64 x 32 pixels tile */ mod_y = 5; } else { - if (fimc->id == 1 && fimc->variant->pix_hoff) + if (fimc->id == 1 && variant->pix_hoff) mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; else mod_y = mod_x; @@ -807,15 +850,26 @@ int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) v4l_bound_align_image(&pix->width, 16, max_width, mod_x, &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); - if (pix->bytesperline == 0 || - (pix->bytesperline * 8 / fmt->depth) > pix->width) - pix->bytesperline = (pix->width * fmt->depth) >> 3; + pix->num_planes = fmt->memplanes; + + for (i = 0; i < pix->num_planes; ++i) { + int bpl = pix->plane_fmt[i].bytesperline; + + dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d", + i, bpl, fmt->depth[i], pix->width, pix->height); - if (pix->sizeimage == 0) - pix->sizeimage = pix->height * pix->bytesperline; + if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width) + bpl = (pix->width * fmt->depth[0]) >> 3; - dbg("w: %d, h: %d, bpl: %d, depth: %d", - pix->width, pix->height, pix->bytesperline, fmt->depth); + if (!pix->plane_fmt[i].sizeimage) + pix->plane_fmt[i].sizeimage = pix->height * bpl; + + pix->plane_fmt[i].bytesperline = bpl; + + dbg("[%d]: bpl: %d, sizeimage: %d", + i, pix->plane_fmt[i].bytesperline, + pix->plane_fmt[i].sizeimage); + } ret = 0; @@ -824,18 +878,18 @@ tf_out: return ret; } -static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev; struct vb2_queue *vq; struct fimc_frame *frame; - struct v4l2_pix_format *pix; + struct v4l2_pix_format_mplane *pix; unsigned long flags; - int ret = 0; + int i, ret = 0; - ret = fimc_vidioc_try_fmt(file, priv, f); + ret = fimc_vidioc_try_fmt_mplane(file, priv, f); if (ret) return ret; @@ -845,35 +899,40 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); if (vb2_is_streaming(vq)) { - v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type); + v4l2_err(&fimc->vid_cap.v4l2_dev, "%s: queue (%d) busy\n", + __func__, f->type); ret = -EBUSY; goto sf_out; } spin_lock_irqsave(&ctx->slock, flags); - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { frame = &ctx->s_frame; ctx->state |= FIMC_SRC_FMT; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { frame = &ctx->d_frame; ctx->state |= FIMC_DST_FMT; } else { spin_unlock_irqrestore(&ctx->slock, flags); - v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, + v4l2_err(&fimc->m2m.v4l2_dev, "Wrong buffer/video queue type (%d)\n", f->type); ret = -EINVAL; goto sf_out; } spin_unlock_irqrestore(&ctx->slock, flags); - pix = &f->fmt.pix; + pix = &f->fmt.pix_mp; frame->fmt = find_format(f, FMT_FLAGS_M2M); if (!frame->fmt) { ret = -EINVAL; goto sf_out; } - frame->f_width = pix->bytesperline * 8 / frame->fmt->depth; + for (i = 0; i < frame->fmt->colplanes; i++) + frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + + frame->f_width = pix->plane_fmt[0].bytesperline * 8 / + frame->fmt->depth[0]; frame->f_height = pix->height; frame->width = pix->width; frame->height = pix->height; @@ -881,7 +940,6 @@ static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f) frame->o_height = pix->height; frame->offs_h = 0; frame->offs_v = 0; - frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3; spin_lock_irqsave(&ctx->slock, flags); ctx->state |= FIMC_PARAMS; @@ -929,8 +987,12 @@ static int fimc_m2m_streamon(struct file *file, void *priv, struct fimc_ctx *ctx = priv; /* The source and target color format need to be set */ - if (~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT)) + if (V4L2_TYPE_IS_OUTPUT(type)) { + if (~ctx->state & FIMC_SRC_FMT) + return -EINVAL; + } else if (~ctx->state & FIMC_DST_FMT) { return -EINVAL; + } return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); } @@ -1134,7 +1196,8 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) { struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *f; - u32 min_size, halign; + u32 min_size, halign, depth = 0; + int i; if (cr->c.top < 0 || cr->c.left < 0) { v4l2_err(&fimc->m2m.v4l2_dev, @@ -1142,9 +1205,9 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) return -EINVAL; } - if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame; - else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && ctx->state & FIMC_CTX_M2M) f = &ctx->s_frame; else @@ -1164,10 +1227,13 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) halign = 4; } + for (i = 0; i < f->fmt->colplanes; i++) + depth += f->fmt->depth[i]; + v4l_bound_align_image(&cr->c.width, min_size, f->o_width, ffs(min_size) - 1, &cr->c.height, min_size, f->o_height, - halign, 64/(ALIGN(f->fmt->depth, 8))); + halign, 64/(ALIGN(depth, 8))); /* adjust left/top if cropping rectangle is out of bounds */ if (cr->c.left + cr->c.width > f->o_width) @@ -1199,7 +1265,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) if (ret) return ret; - f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? + f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->s_frame : &ctx->d_frame; if (mutex_lock_interruptible(&fimc->lock)) @@ -1208,7 +1274,7 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) 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 */ - if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); else ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame); @@ -1234,17 +1300,17 @@ scr_unlock: static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_querycap = fimc_m2m_querycap, - .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt, - .vidioc_enum_fmt_vid_out = fimc_vidioc_enum_fmt, + .vidioc_enum_fmt_vid_cap_mplane = fimc_vidioc_enum_fmt_mplane, + .vidioc_enum_fmt_vid_out_mplane = fimc_vidioc_enum_fmt_mplane, - .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt, - .vidioc_g_fmt_vid_out = fimc_vidioc_g_fmt, + .vidioc_g_fmt_vid_cap_mplane = fimc_vidioc_g_fmt_mplane, + .vidioc_g_fmt_vid_out_mplane = fimc_vidioc_g_fmt_mplane, - .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt, - .vidioc_try_fmt_vid_out = fimc_vidioc_try_fmt, + .vidioc_try_fmt_vid_cap_mplane = fimc_vidioc_try_fmt_mplane, + .vidioc_try_fmt_vid_out_mplane = fimc_vidioc_try_fmt_mplane, - .vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt, - .vidioc_s_fmt_vid_out = fimc_m2m_s_fmt, + .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, + .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, .vidioc_reqbufs = fimc_m2m_reqbufs, .vidioc_querybuf = fimc_m2m_querybuf, @@ -1265,7 +1331,8 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { }; -static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) { struct fimc_ctx *ctx = priv; int ret; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 590fbf230792..187af60bcf69 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -84,7 +84,6 @@ enum fimc_color_fmt { S5P_FIMC_RGB888, S5P_FIMC_RGB30_LOCAL, S5P_FIMC_YCBCR420 = 0x20, - S5P_FIMC_YCBCR422, S5P_FIMC_YCBYCR422, S5P_FIMC_YCRYCB422, S5P_FIMC_CBYCRY422, @@ -151,18 +150,18 @@ enum fimc_color_fmt { * @name: format description * @fourcc: the fourcc code for this format, 0 if not applicable * @color: the corresponding fimc_color_fmt - * @depth: driver's private 'number of bits per pixel' - * @buff_cnt: number of physically non-contiguous data planes - * @planes_cnt: number of physically contiguous data planes + * @depth: per plane driver's private 'number of bits per pixel' + * @memplanes: number of physically non-contiguous data planes + * @colplanes: number of physically contiguous data planes */ struct fimc_fmt { enum v4l2_mbus_pixelcode mbus_code; char *name; u32 fourcc; u32 color; - u16 buff_cnt; - u16 planes_cnt; - u16 depth; + u16 memplanes; + u16 colplanes; + u8 depth[VIDEO_MAX_PLANES]; u16 flags; #define FMT_FLAGS_CAM (1 << 0) #define FMT_FLAGS_M2M (1 << 1) @@ -272,7 +271,7 @@ struct fimc_vid_buffer { * @height: image pixel weight * @paddr: image frame buffer physical addresses * @buf_cnt: number of buffers depending on a color format - * @size: image size in bytes + * @payload: image size in bytes (w x h x bpp) * @color: color format * @dma_offset: DMA offset in bytes */ @@ -285,7 +284,7 @@ struct fimc_frame { u32 offs_v; u32 width; u32 height; - u32 size; + unsigned long payload[VIDEO_MAX_PLANES]; struct fimc_addr paddr; struct fimc_dma_offset dma_offset; struct fimc_fmt *fmt; @@ -479,7 +478,7 @@ struct fimc_ctx { static inline int tiled_fmt(struct fimc_fmt *fmt) { - return 0; + return fmt->fourcc == V4L2_PIX_FMT_NV12MT; } static inline void fimc_hw_clear_irq(struct fimc_dev *dev) @@ -535,12 +534,12 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, { struct fimc_frame *frame; - if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) { + if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) { if (ctx->state & FIMC_CTX_M2M) frame = &ctx->s_frame; else return ERR_PTR(-EINVAL); - } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) { + } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) { frame = &ctx->d_frame; } else { v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev, @@ -582,7 +581,7 @@ void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_output_path(struct fimc_ctx *ctx); void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, - int index); + int index); int fimc_hw_set_camera_source(struct fimc_dev *fimc, struct s3c_fimc_isp_info *cam); int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f); @@ -593,12 +592,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, /* -----------------------------------------------------*/ /* fimc-core.c */ -int fimc_vidioc_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f); -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_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f); +int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f); +int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f); 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/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 511631a2e5c3..5ed8f06ca015 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -143,7 +143,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx) case S5P_FIMC_YCRYCB422: case S5P_FIMC_CBYCRY422: case S5P_FIMC_CRYCBY422: - if (frame->fmt->planes_cnt == 1) + if (frame->fmt->colplanes == 1) cfg |= S5P_CITRGFMT_YCBCR422_1P; else cfg |= S5P_CITRGFMT_YCBCR422; @@ -219,11 +219,11 @@ void fimc_hw_set_out_dma(struct fimc_ctx *ctx) cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK | S5P_CIOCTRL_YCBCR_PLANE_MASK); - if (frame->fmt->planes_cnt == 1) + if (frame->fmt->colplanes == 1) cfg |= ctx->out_order_1p; - else if (frame->fmt->planes_cnt == 2) + else if (frame->fmt->colplanes == 2) cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE; - else if (frame->fmt->planes_cnt == 3) + else if (frame->fmt->colplanes == 3) cfg |= S5P_CIOCTRL_YCBCR_3PLANE; writel(cfg, dev->regs + S5P_CIOCTRL); @@ -428,7 +428,7 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) case S5P_FIMC_YCBCR420: cfg |= S5P_MSCTRL_INFORMAT_YCBCR420; - if (frame->fmt->planes_cnt == 2) + if (frame->fmt->colplanes == 2) cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE; else cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; @@ -438,13 +438,13 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) case S5P_FIMC_YCRYCB422: case S5P_FIMC_CBYCRY422: case S5P_FIMC_CRYCBY422: - if (frame->fmt->planes_cnt == 1) { + if (frame->fmt->colplanes == 1) { cfg |= ctx->in_order_1p | S5P_MSCTRL_INFORMAT_YCBCR422_1P; } else { cfg |= S5P_MSCTRL_INFORMAT_YCBCR422; - if (frame->fmt->planes_cnt == 2) + if (frame->fmt->colplanes == 2) cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE; else -- cgit v1.2.2 From 8293ebfce2053242e30069e65427e7560aff1fee Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 1 Dec 2010 10:25:18 -0300 Subject: [media] s5p-fimc: Use v4l core mutex in ioctl and file operations Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 208 ++++------------------------ drivers/media/video/s5p-fimc/fimc-core.c | 115 ++++----------- 2 files changed, 58 insertions(+), 265 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index e746b684c3b8..3b208f8325ae 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -406,29 +406,23 @@ static int fimc_capture_open(struct file *file) if (fimc_m2m_active(fimc)) return -EBUSY; - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - if (++fimc->vid_cap.refcnt == 1) { ret = fimc_isp_subdev_init(fimc, -1); if (ret) { fimc->vid_cap.refcnt--; - ret = -EIO; + return -EIO; } } file->private_data = fimc->vid_cap.ctx; - mutex_unlock(&fimc->lock); - return ret; + return 0; } static int fimc_capture_close(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); if (--fimc->vid_cap.refcnt == 0) { @@ -441,7 +435,6 @@ static int fimc_capture_close(struct file *file) fimc_subdev_unregister(fimc); } - mutex_unlock(&fimc->lock); return 0; } @@ -450,30 +443,16 @@ static unsigned int fimc_capture_poll(struct file *file, { struct fimc_ctx *ctx = file->private_data; struct fimc_dev *fimc = ctx->fimc_dev; - int ret; - if (mutex_lock_interruptible(&fimc->lock)) - return POLLERR; - - ret = vb2_poll(&fimc->vid_cap.vbq, file, wait); - mutex_unlock(&fimc->lock); - - return ret; + return vb2_poll(&fimc->vid_cap.vbq, file, wait); } static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) { struct fimc_ctx *ctx = file->private_data; struct fimc_dev *fimc = ctx->fimc_dev; - int ret; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - ret = vb2_mmap(&fimc->vid_cap.vbq, vma); - mutex_unlock(&fimc->lock); - - return ret; + return vb2_mmap(&fimc->vid_cap.vbq, vma); } /* video device file operations */ @@ -555,13 +534,6 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, if (ret) return ret; - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - - if (fimc_capture_active(fimc)) { - ret = -EBUSY; - goto sf_unlock; - } if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) return -EBUSY; @@ -571,8 +543,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM); if (!frame->fmt) { err("fimc target format not found\n"); - ret = -EINVAL; - goto sf_unlock; + return -EINVAL; } for (i = 0; i < frame->fmt->colplanes; i++) @@ -589,12 +560,9 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, frame->offs_h = 0; frame->offs_v = 0; - ret = sync_capture_fmt(ctx); - ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT); -sf_unlock: - mutex_unlock(&fimc->lock); + ret = sync_capture_fmt(ctx); return ret; } @@ -623,21 +591,16 @@ static int fimc_cap_s_input(struct file *file, void *priv, struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; struct s3c_platform_fimc *pdata = fimc->pdata; - int ret; if (fimc_capture_active(ctx->fimc_dev)) return -EBUSY; - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; + if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) + return -EINVAL; - if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) { - ret = -EINVAL; - goto si_unlock; - } if (fimc->vid_cap.sd) { - ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); + int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); if (ret) err("s_power failed: %d", ret); } @@ -645,11 +608,7 @@ static int fimc_cap_s_input(struct file *file, void *priv, /* Release the attached sensor subdevice. */ fimc_subdev_unregister(fimc); - ret = fimc_isp_subdev_init(fimc, i); - -si_unlock: - mutex_unlock(&fimc->lock); - return ret; + return fimc_isp_subdev_init(fimc, i); } static int fimc_cap_g_input(struct file *file, void *priv, @@ -665,112 +624,41 @@ static int fimc_cap_g_input(struct file *file, void *priv, static int fimc_cap_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s3c_fimc_isp_info *isp_info; struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; - int ret = -EBUSY; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; if (fimc_capture_active(fimc) || !fimc->vid_cap.sd) - goto s_unlock; + return -EBUSY; if (!(ctx->state & FIMC_DST_FMT)) { v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n"); - ret = -EINVAL; - goto s_unlock; - } - - ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) - goto s_unlock; - - ret = fimc_prepare_config(ctx, ctx->state); - if (ret) - goto s_unlock; - - isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; - fimc_hw_set_camera_type(fimc, isp_info); - fimc_hw_set_camera_source(fimc, isp_info); - fimc_hw_set_camera_offset(fimc, &ctx->s_frame); - - if (ctx->state & FIMC_PARAMS) { - ret = fimc_set_scaler_info(ctx); - if (ret) { - err("Scaler setup error"); - goto s_unlock; - } - fimc_hw_set_input_path(ctx); - fimc_hw_set_scaler(ctx); - fimc_hw_set_target_format(ctx); - fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); + return -EINVAL; } - fimc_hw_set_output_path(ctx); - fimc_hw_set_out_dma(ctx); - - INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q); - 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 = vb2_streamon(&fimc->vid_cap.vbq, type); - -s_unlock: - mutex_unlock(&fimc->lock); - return ret; + return vb2_streamon(&fimc->vid_cap.vbq, type); } static int fimc_cap_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) + enum v4l2_buf_type type) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *cap = &fimc->vid_cap; - unsigned long flags; - int ret; - - spin_lock_irqsave(&fimc->slock, flags); - if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) { - spin_unlock_irqrestore(&fimc->slock, flags); - dbg("state: 0x%lx", fimc->state); - return -EINVAL; - } - spin_unlock_irqrestore(&fimc->slock, flags); - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - fimc_stop_capture(fimc); - ret = vb2_streamoff(&cap->vbq, type); - - mutex_unlock(&fimc->lock); - return ret; + return vb2_streamoff(&fimc->vid_cap.vbq, type); } static int fimc_cap_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; int ret; - if (fimc_capture_active(ctx->fimc_dev)) - return -EBUSY; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; ret = vb2_reqbufs(&cap->vbq, reqbufs); if (!ret) cap->reqbufs_count = reqbufs->count; - mutex_unlock(&fimc->lock); return ret; } @@ -780,9 +668,6 @@ static int fimc_cap_querybuf(struct file *file, void *priv, struct fimc_ctx *ctx = priv; struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; - if (fimc_capture_active(ctx->fimc_dev)) - return -EBUSY; - return vb2_querybuf(&cap->vbq, buf); } @@ -790,33 +675,16 @@ static int fimc_cap_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *cap = &fimc->vid_cap; - int ret; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - - ret = vb2_qbuf(&cap->vbq, buf); - - mutex_unlock(&fimc->lock); - return ret; + struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap; + return vb2_qbuf(&cap->vbq, buf); } static int fimc_cap_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { struct fimc_ctx *ctx = priv; - int ret; - - if (mutex_lock_interruptible(&ctx->fimc_dev->lock)) - return -ERESTARTSYS; - - ret = vb2_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf, + return vb2_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); - - mutex_unlock(&ctx->fimc_dev->lock); - return ret; } static int fimc_cap_s_ctrl(struct file *file, void *priv, @@ -825,9 +693,6 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv, struct fimc_ctx *ctx = priv; int ret = -EINVAL; - if (mutex_lock_interruptible(&ctx->fimc_dev->lock)) - return -ERESTARTSYS; - /* Allow any controls but 90/270 rotation while streaming */ if (!fimc_capture_active(ctx->fimc_dev) || ctrl->id != V4L2_CID_ROTATE || @@ -842,8 +707,6 @@ static int fimc_cap_s_ctrl(struct file *file, void *priv, if (ret == -EINVAL) ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, core, s_ctrl, ctrl); - - mutex_unlock(&ctx->fimc_dev->lock); return ret; } @@ -852,13 +715,10 @@ static int fimc_cap_cropcap(struct file *file, void *fh, { struct fimc_frame *f; struct fimc_ctx *ctx = fh; - struct fimc_dev *fimc = ctx->fimc_dev; if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; f = &ctx->s_frame; cr->bounds.left = 0; @@ -867,7 +727,6 @@ static int fimc_cap_cropcap(struct file *file, void *fh, cr->bounds.height = f->o_height; cr->defrect = cr->bounds; - mutex_unlock(&fimc->lock); return 0; } @@ -875,19 +734,14 @@ 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; } @@ -906,13 +760,10 @@ static int fimc_cap_s_crop(struct file *file, void *fh, if (ret) return ret; - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - if (!(ctx->state & FIMC_DST_FMT)) { v4l2_err(&fimc->vid_cap.v4l2_dev, "Capture color format not set\n"); - goto sc_unlock; + return -EINVAL; /* TODO: make sure this is the right value */ } f = &ctx->s_frame; @@ -920,17 +771,15 @@ static int fimc_cap_s_crop(struct file *file, void *fh, ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); if (ret) { v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range"); - } else { - ret = 0; - f->offs_h = cr->c.left; - f->offs_v = cr->c.top; - f->width = cr->c.width; - f->height = cr->c.height; + return ret; } -sc_unlock: - mutex_unlock(&fimc->lock); - return ret; + f->offs_h = cr->c.left; + f->offs_v = cr->c.top; + f->width = cr->c.width; + f->height = cr->c.height; + + return 0; } @@ -1013,6 +862,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc) vfd->ioctl_ops = &fimc_capture_ioctl_ops; vfd->minor = -1; vfd->release = video_device_release; + vfd->lock = &fimc->lock; video_set_drvdata(vfd, fimc); vid_cap = &fimc->vid_cap; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index fe210976f30b..9ebb92530053 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -741,22 +741,17 @@ int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *frame; frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) return PTR_ERR(frame); - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - f->fmt.pix.width = frame->width; f->fmt.pix.height = frame->height; f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.pixelformat = frame->fmt->fourcc; - mutex_unlock(&fimc->lock); return 0; } @@ -800,7 +795,8 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct fimc_fmt *fmt; u32 max_width, mod_x, mod_y, mask; - int ret, i, is_output = 0; + int i, is_output = 0; + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->state & FIMC_CTX_CAP) @@ -810,8 +806,6 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, return -EINVAL; } - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; dbg("w: %d, h: %d", pix->width, pix->height); mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM; @@ -819,13 +813,13 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, if (!fmt) { v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n", pix->pixelformat); - goto tf_out; + return -EINVAL; } if (pix->field == V4L2_FIELD_ANY) pix->field = V4L2_FIELD_NONE; else if (V4L2_FIELD_NONE != pix->field) - goto tf_out; + return -EINVAL; if (is_output) { max_width = variant->pix_limit->scaler_dis_w; @@ -871,11 +865,7 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, pix->plane_fmt[i].sizeimage); } - ret = 0; - -tf_out: - mutex_unlock(&fimc->lock); - return ret; + return 0; } static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, @@ -888,45 +878,33 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, struct v4l2_pix_format_mplane *pix; unsigned long flags; int i, ret = 0; + u32 tmp; ret = fimc_vidioc_try_fmt_mplane(file, priv, f); if (ret) return ret; - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); if (vb2_is_streaming(vq)) { - v4l2_err(&fimc->vid_cap.v4l2_dev, "%s: queue (%d) busy\n", - __func__, f->type); - ret = -EBUSY; - goto sf_out; + v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type); + return -EBUSY; } - spin_lock_irqsave(&ctx->slock, flags); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { frame = &ctx->s_frame; - ctx->state |= FIMC_SRC_FMT; } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { frame = &ctx->d_frame; - ctx->state |= FIMC_DST_FMT; } else { - spin_unlock_irqrestore(&ctx->slock, flags); v4l2_err(&fimc->m2m.v4l2_dev, "Wrong buffer/video queue type (%d)\n", f->type); - ret = -EINVAL; - goto sf_out; + return -EINVAL; } - spin_unlock_irqrestore(&ctx->slock, flags); pix = &f->fmt.pix_mp; frame->fmt = find_format(f, FMT_FLAGS_M2M); - if (!frame->fmt) { - ret = -EINVAL; - goto sf_out; - } + if (!frame->fmt) + return -EINVAL; for (i = 0; i < frame->fmt->colplanes; i++) frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; @@ -942,14 +920,13 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, frame->offs_v = 0; spin_lock_irqsave(&ctx->slock, flags); - ctx->state |= FIMC_PARAMS; + tmp = (frame == &ctx->d_frame) ? FIMC_DST_FMT : FIMC_SRC_FMT; + ctx->state |= FIMC_PARAMS | tmp; spin_unlock_irqrestore(&ctx->slock, flags); dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height); -sf_out: - mutex_unlock(&fimc->lock); - return ret; + return 0; } static int fimc_m2m_reqbufs(struct file *file, void *priv, @@ -1018,11 +995,8 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv, } 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, + return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, core, queryctrl, qc); - mutex_unlock(&ctx->fimc_dev->lock); } return ret; } @@ -1032,10 +1006,6 @@ int fimc_vidioc_g_ctrl(struct file *file, void *priv, { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; - int ret = 0; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; switch (ctrl->id) { case V4L2_CID_HFLIP: @@ -1049,18 +1019,17 @@ int fimc_vidioc_g_ctrl(struct file *file, void *priv, break; default: if (ctx->state & FIMC_CTX_CAP) { - ret = v4l2_subdev_call(fimc->vid_cap.sd, core, - g_ctrl, ctrl); + return v4l2_subdev_call(fimc->vid_cap.sd, core, + g_ctrl, ctrl); } else { v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); - ret = -EINVAL; + return -EINVAL; } } dbg("ctrl->value= %d", ctrl->value); - mutex_unlock(&fimc->lock); - return ret; + return 0; } int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl) @@ -1151,22 +1120,17 @@ static int fimc_m2m_cropcap(struct file *file, void *fh, { struct fimc_frame *frame; struct fimc_ctx *ctx = fh; - struct fimc_dev *fimc = ctx->fimc_dev; frame = ctx_get_frame(ctx, cr->type); if (IS_ERR(frame)) return PTR_ERR(frame); - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - cr->bounds.left = 0; cr->bounds.top = 0; cr->bounds.width = frame->f_width; cr->bounds.height = frame->f_height; cr->defrect = cr->bounds; - mutex_unlock(&fimc->lock); return 0; } @@ -1174,21 +1138,16 @@ 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; - struct fimc_dev *fimc = ctx->fimc_dev; frame = ctx_get_frame(ctx, cr->type); if (IS_ERR(frame)) return PTR_ERR(frame); - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - cr->c.left = frame->offs_h; cr->c.top = frame->offs_v; cr->c.width = frame->width; cr->c.height = frame->height; - mutex_unlock(&fimc->lock); return 0; } @@ -1268,9 +1227,6 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &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 */ @@ -1280,8 +1236,8 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame); if (ret) { v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); - ret = -EINVAL; - goto scr_unlock; + spin_unlock_irqrestore(&ctx->slock, flags); + return -EINVAL; } } ctx->state |= FIMC_PARAMS; @@ -1291,9 +1247,7 @@ 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; } @@ -1364,10 +1318,6 @@ static int fimc_m2m_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = NULL; - int err = 0; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; dbg("pid: %d, state: 0x%lx, refcnt: %d", task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt); @@ -1376,19 +1326,15 @@ static int fimc_m2m_open(struct file *file) * Return if the corresponding video capture node * is already opened. */ - if (fimc->vid_cap.refcnt > 0) { - err = -EBUSY; - goto err_unlock; - } + if (fimc->vid_cap.refcnt > 0) + return -EBUSY; fimc->m2m.refcnt++; set_bit(ST_OUTDMA_RUN, &fimc->state); ctx = kzalloc(sizeof *ctx, GFP_KERNEL); - if (!ctx) { - err = -ENOMEM; - goto err_unlock; - } + if (!ctx) + return -ENOMEM; file->private_data = ctx; ctx->fimc_dev = fimc; @@ -1404,13 +1350,12 @@ static int fimc_m2m_open(struct file *file) ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); if (IS_ERR(ctx->m2m_ctx)) { - err = PTR_ERR(ctx->m2m_ctx); + int err = PTR_ERR(ctx->m2m_ctx); kfree(ctx); + return err; } -err_unlock: - mutex_unlock(&fimc->lock); - return err; + return 0; } static int fimc_m2m_release(struct file *file) @@ -1418,8 +1363,6 @@ static int fimc_m2m_release(struct file *file) struct fimc_ctx *ctx = file->private_data; struct fimc_dev *fimc = ctx->fimc_dev; - mutex_lock(&fimc->lock); - dbg("pid: %d, state: 0x%lx, refcnt= %d", task_pid_nr(current), fimc->state, fimc->m2m.refcnt); @@ -1428,7 +1371,6 @@ static int fimc_m2m_release(struct file *file) if (--fimc->m2m.refcnt <= 0) clear_bit(ST_OUTDMA_RUN, &fimc->state); - mutex_unlock(&fimc->lock); return 0; } @@ -1494,6 +1436,7 @@ static int fimc_register_m2m_device(struct fimc_dev *fimc) vfd->ioctl_ops = &fimc_m2m_ioctl_ops; vfd->minor = -1; vfd->release = video_device_release; + vfd->lock = &fimc->lock; snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", dev_name(&pdev->dev)); -- cgit v1.2.2 From df7e09a351199ad9a70eb9ae3b072cc4fc59a9bb Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 27 Dec 2010 14:42:15 -0300 Subject: [media] s5p-fimc: Rename s3c_fimc* to s5p_fimc* Change s3c_fimc.h header file name to s5p_fimc.h, replace s3c_fimc_* names with s5p_fimc_*. s3c_fimc need to be reserved for S3C series and s5p-fimc driver will not cover CAMIF devices in S3C SoC series. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 16 ++++++++-------- drivers/media/video/s5p-fimc/fimc-core.h | 10 +++++----- drivers/media/video/s5p-fimc/fimc-reg.c | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 3b208f8325ae..2dc6e82c8084 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -33,7 +33,7 @@ #include "fimc-core.h" static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc, - struct s3c_fimc_isp_info *isp_info) + struct s5p_fimc_isp_info *isp_info) { struct i2c_adapter *i2c_adap; struct fimc_vid_cap *vid_cap = &fimc->vid_cap; @@ -86,8 +86,8 @@ static void fimc_subdev_unregister(struct fimc_dev *fimc) static int fimc_subdev_attach(struct fimc_dev *fimc, int index) { struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct s3c_platform_fimc *pdata = fimc->pdata; - struct s3c_fimc_isp_info *isp_info; + struct s5p_platform_fimc *pdata = fimc->pdata; + struct s5p_fimc_isp_info *isp_info; struct v4l2_subdev *sd; int i; @@ -115,7 +115,7 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index) static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index) { - struct s3c_fimc_isp_info *isp_info; + struct s5p_fimc_isp_info *isp_info; int ret; ret = fimc_subdev_attach(fimc, index); @@ -221,7 +221,7 @@ static int start_streaming(struct vb2_queue *q) { struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; - struct s3c_fimc_isp_info *isp_info; + struct s5p_fimc_isp_info *isp_info; int ret; ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); @@ -570,8 +570,8 @@ static int fimc_cap_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct fimc_ctx *ctx = priv; - struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata; - struct s3c_fimc_isp_info *isp_info; + struct s5p_platform_fimc *pldata = ctx->fimc_dev->pdata; + struct s5p_fimc_isp_info *isp_info; if (i->index >= FIMC_MAX_CAMIF_CLIENTS) return -EINVAL; @@ -590,7 +590,7 @@ static int fimc_cap_s_input(struct file *file, void *priv, { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc = ctx->fimc_dev; - struct s3c_platform_fimc *pdata = fimc->pdata; + struct s5p_platform_fimc *pdata = fimc->pdata; if (fimc_capture_active(ctx->fimc_dev)) return -EBUSY; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 187af60bcf69..b23d492796e9 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "regs-fimc.h" @@ -421,7 +421,7 @@ struct fimc_dev { spinlock_t slock; struct mutex lock; struct platform_device *pdev; - struct s3c_platform_fimc *pdata; + struct s5p_platform_fimc *pdata; struct samsung_fimc_variant *variant; int id; struct clk *clock[NUM_FIMC_CLOCKS]; @@ -583,12 +583,12 @@ void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, int index); int fimc_hw_set_camera_source(struct fimc_dev *fimc, - struct s3c_fimc_isp_info *cam); + struct s5p_fimc_isp_info *cam); int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f); int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct s3c_fimc_isp_info *cam); + struct s5p_fimc_isp_info *cam); int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct s3c_fimc_isp_info *cam); + struct s5p_fimc_isp_info *cam); /* -----------------------------------------------------*/ /* fimc-core.c */ diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 5ed8f06ca015..ae33bc1c7bd4 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "fimc-core.h" @@ -532,7 +532,7 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev, } int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct s3c_fimc_isp_info *cam) + struct s5p_fimc_isp_info *cam) { u32 cfg = readl(fimc->regs + S5P_CIGCTRL); @@ -557,7 +557,7 @@ int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, } int fimc_hw_set_camera_source(struct fimc_dev *fimc, - struct s3c_fimc_isp_info *cam) + struct s5p_fimc_isp_info *cam) { struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; u32 cfg = 0; @@ -624,7 +624,7 @@ int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) } int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct s3c_fimc_isp_info *cam) + struct s5p_fimc_isp_info *cam) { u32 cfg, tmp; struct fimc_vid_cap *vid_cap = &fimc->vid_cap; -- cgit v1.2.2 From 3d0ce7ed037af9bafec498246d0e4af8302d993a Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 27 Dec 2010 15:02:16 -0300 Subject: [media] s5p-fimc: Derive camera bus width from mediabus pixelcode Remove bus_width from s5p_fimc_isp_info data structure. Determine camera data bus width based on mediabus pixel format. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-reg.c | 49 ++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index ae33bc1c7bd4..63660119ef7f 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -561,37 +561,42 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, { struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; u32 cfg = 0; + u32 bus_width; + int i; + + static const struct { + u32 pixelcode; + u32 cisrcfmt; + u16 bus_width; + } pix_desc[] = { + { V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 }, + { V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 }, + { V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 }, + { V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 }, + /* TODO: Add pixel codes for 16-bit bus width */ + }; if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) { + for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { + if (fimc->vid_cap.fmt.code == pix_desc[i].pixelcode) { + cfg = pix_desc[i].cisrcfmt; + bus_width = pix_desc[i].bus_width; + break; + } + } - switch (fimc->vid_cap.fmt.code) { - case V4L2_MBUS_FMT_YUYV8_2X8: - cfg = S5P_CISRCFMT_ORDER422_YCBYCR; - break; - case V4L2_MBUS_FMT_YVYU8_2X8: - cfg = S5P_CISRCFMT_ORDER422_YCRYCB; - break; - case V4L2_MBUS_FMT_VYUY8_2X8: - cfg = S5P_CISRCFMT_ORDER422_CRYCBY; - break; - case V4L2_MBUS_FMT_UYVY8_2X8: - cfg = S5P_CISRCFMT_ORDER422_CBYCRY; - break; - default: - err("camera image format not supported: %d", - fimc->vid_cap.fmt.code); + if (i == ARRAY_SIZE(pix_desc)) { + v4l2_err(&fimc->vid_cap.v4l2_dev, + "Camera color format not supported: %d\n", + fimc->vid_cap.fmt.code); return -EINVAL; } if (cam->bus_type == FIMC_ITU_601) { - if (cam->bus_width == 8) { + if (bus_width == 8) cfg |= S5P_CISRCFMT_ITU601_8BIT; - } else if (cam->bus_width == 16) { + else if (bus_width == 16) cfg |= S5P_CISRCFMT_ITU601_16BIT; - } else { - err("invalid bus width: %d", cam->bus_width); - return -EINVAL; - } } /* else defaults to ITU-R BT.656 8-bit */ } -- cgit v1.2.2 From e9654ef28740867c0aa151bbaec93f090f60cd24 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 27 Dec 2010 15:05:58 -0300 Subject: [media] s5p-fimc: Enable interworking without subdev s_stream Prevent VIDIOC_STREAMON failing when s_stream callback is not implemented by a sensor subdev driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 2dc6e82c8084..c6689a24c85b 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -191,7 +191,8 @@ static int fimc_stop_capture(struct fimc_dev *fimc) FIMC_SHUTDOWN_TIMEOUT); ret = v4l2_subdev_call(cap->sd, video, s_stream, 0); - if (ret) + + if (ret && ret != -ENOIOCTLCMD) v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n"); spin_lock_irqsave(&fimc->slock, flags); -- cgit v1.2.2 From d9160afd31565e44ebbd909b283baad8c9a3c224 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 8 Dec 2010 12:48:23 -0300 Subject: [media] s5p-fimc: Use default input DMA burst count Increase the input DMA "successive burst count" to default value 4 to improve DMA performance. Minor cleanup. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-reg.c | 11 +++-------- drivers/media/video/s5p-fimc/regs-fimc.h | 4 ++-- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 63660119ef7f..c4703b5800c4 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -417,12 +417,10 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) | S5P_MSCTRL_C_INT_IN_MASK | S5P_MSCTRL_2P_IN_ORDER_MASK); - cfg |= (S5P_MSCTRL_FRAME_COUNT(1) | S5P_MSCTRL_INPUT_MEMORY); + cfg |= S5P_MSCTRL_IN_BURST_COUNT(4) | S5P_MSCTRL_INPUT_MEMORY; switch (frame->fmt->color) { - case S5P_FIMC_RGB565: - case S5P_FIMC_RGB666: - case S5P_FIMC_RGB888: + case S5P_FIMC_RGB565...S5P_FIMC_RGB888: cfg |= S5P_MSCTRL_INFORMAT_RGB; break; case S5P_FIMC_YCBCR420: @@ -434,10 +432,7 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) cfg |= S5P_MSCTRL_C_INT_IN_3PLANE; break; - case S5P_FIMC_YCBYCR422: - case S5P_FIMC_YCRYCB422: - case S5P_FIMC_CBYCRY422: - case S5P_FIMC_CRYCBY422: + case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422: if (frame->fmt->colplanes == 1) { cfg |= ctx->in_order_1p | S5P_MSCTRL_INFORMAT_YCBCR422_1P; diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index 57e33f84fcfa..74ca705df765 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -210,7 +210,7 @@ /* Input DMA control */ #define S5P_MSCTRL 0xfc -#define S5P_MSCTRL_IN_BURST_COUNT_MASK (3 << 24) +#define S5P_MSCTRL_IN_BURST_COUNT_MASK (0xF << 24) #define S5P_MSCTRL_2P_IN_ORDER_MASK (3 << 16) #define S5P_MSCTRL_2P_IN_ORDER_SHIFT 16 #define S5P_MSCTRL_C_INT_IN_3PLANE (0 << 15) @@ -237,7 +237,7 @@ #define S5P_MSCTRL_INFORMAT_RGB (3 << 1) #define S5P_MSCTRL_INFORMAT_MASK (3 << 1) #define S5P_MSCTRL_ENVID (1 << 0) -#define S5P_MSCTRL_FRAME_COUNT(x) ((x) << 24) +#define S5P_MSCTRL_IN_BURST_COUNT(x) ((x) << 24) /* Output DMA Y/Cb/Cr offset */ #define S5P_CIOYOFF 0x168 -- cgit v1.2.2 From ac75934cc644051dc1b33b234448ea4a0990f31f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 27 Dec 2010 14:47:32 -0300 Subject: [media] s5p-fimc: Enable simultaneous rotation and flipping Map all (0, 90, 180, 270) deg counterclockwise rotation and horizontal and vertical flip controls to (0, 90) deg rotation, horizontal and vertical flip transformations available in the device. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-core.c | 9 +--- drivers/media/video/s5p-fimc/fimc-reg.c | 74 +++++++++++++------------------- 2 files changed, 31 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 9ebb92530053..b8d59f44a088 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1055,13 +1055,6 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) struct fimc_dev *fimc = ctx->fimc_dev; unsigned long flags; - if (ctx->rotation != 0 && - (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) { - v4l2_err(&fimc->m2m.v4l2_dev, - "Simultaneous flip and rotation is not supported\n"); - return -EINVAL; - } - spin_lock_irqsave(&ctx->slock, flags); switch (ctrl->id) { @@ -1102,7 +1095,7 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) } static int fimc_m2m_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) + struct v4l2_control *ctrl) { struct fimc_ctx *ctx = priv; int ret = 0; diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index c4703b5800c4..c14c8316ea13 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -37,11 +37,11 @@ void fimc_hw_reset(struct fimc_dev *dev) writel(cfg, dev->regs + S5P_CIGCTRL); } -static u32 fimc_hw_get_in_flip(u32 ctx_flip) +static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) { u32 flip = S5P_MSCTRL_FLIP_NORMAL; - switch (ctx_flip) { + switch (ctx->flip) { case FLIP_X_AXIS: flip = S5P_MSCTRL_FLIP_X_MIRROR; break; @@ -51,16 +51,20 @@ static u32 fimc_hw_get_in_flip(u32 ctx_flip) case FLIP_XY_AXIS: flip = S5P_MSCTRL_FLIP_180; break; + default: + break; } + if (ctx->rotation <= 90) + return flip; - return flip; + return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180; } -static u32 fimc_hw_get_target_flip(u32 ctx_flip) +static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) { u32 flip = S5P_CITRGFMT_FLIP_NORMAL; - switch (ctx_flip) { + switch (ctx->flip) { case FLIP_X_AXIS: flip = S5P_CITRGFMT_FLIP_X_MIRROR; break; @@ -70,11 +74,13 @@ static u32 fimc_hw_get_target_flip(u32 ctx_flip) case FLIP_XY_AXIS: flip = S5P_CITRGFMT_FLIP_180; break; - case FLIP_NONE: + default: break; - } - return flip; + if (ctx->rotation <= 90) + return flip; + + return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180; } void fimc_hw_set_rotation(struct fimc_ctx *ctx) @@ -84,10 +90,7 @@ void fimc_hw_set_rotation(struct fimc_ctx *ctx) cfg = readl(dev->regs + S5P_CITRGFMT); cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 | - S5P_CITRGFMT_FLIP_180); - - flip = readl(dev->regs + S5P_MSCTRL); - flip &= ~S5P_MSCTRL_FLIP_MASK; + S5P_CITRGFMT_FLIP_180); /* * The input and output rotator cannot work simultaneously. @@ -95,26 +98,22 @@ void fimc_hw_set_rotation(struct fimc_ctx *ctx) * in direct fifo output mode. */ if (ctx->rotation == 90 || ctx->rotation == 270) { - if (ctx->out_path == FIMC_LCDFIFO) { - cfg |= S5P_CITRGFMT_INROT90; - if (ctx->rotation == 270) - flip |= S5P_MSCTRL_FLIP_180; - } else { - cfg |= S5P_CITRGFMT_OUTROT90; - if (ctx->rotation == 270) - cfg |= S5P_CITRGFMT_FLIP_180; - } - } else if (ctx->rotation == 180) { if (ctx->out_path == FIMC_LCDFIFO) - flip |= S5P_MSCTRL_FLIP_180; + cfg |= S5P_CITRGFMT_INROT90; else - cfg |= S5P_CITRGFMT_FLIP_180; + cfg |= S5P_CITRGFMT_OUTROT90; } - if (ctx->rotation == 180 || ctx->rotation == 270) - writel(flip, dev->regs + S5P_MSCTRL); - cfg |= fimc_hw_get_target_flip(ctx->flip); - writel(cfg, dev->regs + S5P_CITRGFMT); + if (ctx->out_path == FIMC_DMA) { + cfg |= fimc_hw_get_target_flip(ctx); + writel(cfg, dev->regs + S5P_CITRGFMT); + } else { + /* LCD FIFO path */ + flip = readl(dev->regs + S5P_MSCTRL); + flip &= ~S5P_MSCTRL_FLIP_MASK; + flip |= fimc_hw_get_in_flip(ctx); + writel(flip, dev->regs + S5P_MSCTRL); + } } void fimc_hw_set_target_format(struct fimc_ctx *ctx) @@ -131,18 +130,13 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx) S5P_CITRGFMT_VSIZE_MASK); switch (frame->fmt->color) { - case S5P_FIMC_RGB565: - case S5P_FIMC_RGB666: - case S5P_FIMC_RGB888: + case S5P_FIMC_RGB565...S5P_FIMC_RGB888: cfg |= S5P_CITRGFMT_RGB; break; case S5P_FIMC_YCBCR420: cfg |= S5P_CITRGFMT_YCBCR420; break; - case S5P_FIMC_YCBYCR422: - case S5P_FIMC_YCRYCB422: - case S5P_FIMC_CBYCRY422: - case S5P_FIMC_CRYCBY422: + case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422: if (frame->fmt->colplanes == 1) cfg |= S5P_CITRGFMT_YCBCR422_1P; else @@ -410,8 +404,7 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) /* Set the input DMA to process single frame only. */ cfg = readl(dev->regs + S5P_MSCTRL); - cfg &= ~(S5P_MSCTRL_FLIP_MASK - | S5P_MSCTRL_INFORMAT_MASK + cfg &= ~(S5P_MSCTRL_INFORMAT_MASK | S5P_MSCTRL_IN_BURST_COUNT_MASK | S5P_MSCTRL_INPUT_MASK | S5P_MSCTRL_C_INT_IN_MASK @@ -450,13 +443,6 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) break; } - /* - * Input DMA flip mode (and rotation). - * Do not allow simultaneous rotation and flipping. - */ - if (!ctx->rotation && ctx->out_path == FIMC_LCDFIFO) - cfg |= fimc_hw_get_in_flip(ctx->flip); - writel(cfg, dev->regs + S5P_MSCTRL); /* Input/output DMA linear/tiled mode. */ -- cgit v1.2.2 From a25be18dfb6e1b172498a9f6c9793d67057000b0 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 27 Dec 2010 15:34:43 -0300 Subject: [media] s5p-fimc: Add control of the external sensor clock Manage the camera sensor clock in the host driver rather than leaving this task for sensor drivers. The clock frequency must be passed in the sensor's and host driver's platform data. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 45 +++++++++++++++------- drivers/media/video/s5p-fimc/fimc-core.c | 59 ++++++++++++++++++----------- drivers/media/video/s5p-fimc/fimc-core.h | 18 ++++++--- 3 files changed, 80 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index c6689a24c85b..03ddf5d6164f 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -113,26 +113,43 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index) return -ENODEV; } -static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index) +static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) { struct s5p_fimc_isp_info *isp_info; int ret; + if (index >= FIMC_MAX_CAMIF_CLIENTS) + return -EINVAL; + + isp_info = fimc->pdata->isp_info[index]; + if (!isp_info) + return -EINVAL; + + if (isp_info->clk_frequency) + clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency); + + ret = clk_enable(fimc->clock[CLK_CAM]); + if (ret) + return ret; + ret = fimc_subdev_attach(fimc, index); if (ret) return ret; - isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; ret = fimc_hw_set_camera_polarity(fimc, isp_info); - if (!ret) { - ret = v4l2_subdev_call(fimc->vid_cap.sd, core, - s_power, 1); - if (!ret) - return ret; - } + if (ret) + return ret; + + ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1); + if (!ret) + return ret; + /* enabling power failed so unregister subdev */ fimc_subdev_unregister(fimc); - err("ISP initialization failed: %d", ret); + + v4l2_err(&fimc->vid_cap.v4l2_dev, "ISP initialization failed: %d\n", + ret); + return ret; } @@ -190,10 +207,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc) test_bit(ST_CAPT_SHUT, &fimc->state), FIMC_SHUTDOWN_TIMEOUT); - ret = v4l2_subdev_call(cap->sd, video, s_stream, 0); - - if (ret && ret != -ENOIOCTLCMD) - v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n"); + v4l2_subdev_call(cap->sd, video, s_stream, 0); spin_lock_irqsave(&fimc->slock, flags); fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | @@ -408,7 +422,7 @@ static int fimc_capture_open(struct file *file) return -EBUSY; if (++fimc->vid_cap.refcnt == 1) { - ret = fimc_isp_subdev_init(fimc, -1); + ret = fimc_isp_subdev_init(fimc, 0); if (ret) { fimc->vid_cap.refcnt--; return -EIO; @@ -433,6 +447,7 @@ static int fimc_capture_close(struct file *file) v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n"); v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); + clk_disable(fimc->clock[CLK_CAM]); fimc_subdev_unregister(fimc); } @@ -604,6 +619,8 @@ static int fimc_cap_s_input(struct file *file, void *priv, int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); if (ret) err("s_power failed: %d", ret); + + clk_disable(fimc->clock[CLK_CAM]); } /* Release the attached sensor subdevice. */ diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index b8d59f44a088..db249e6c355d 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -30,7 +30,9 @@ #include "fimc-core.h" -static char *fimc_clock_name[NUM_FIMC_CLOCKS] = { "sclk_fimc", "fimc" }; +static char *fimc_clocks[MAX_FIMC_CLOCKS] = { + "sclk_fimc", "fimc", "sclk_cam" +}; static struct fimc_fmt fimc_formats[] = { { @@ -1478,7 +1480,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc) static void fimc_clk_release(struct fimc_dev *fimc) { int i; - for (i = 0; i < NUM_FIMC_CLOCKS; i++) { + for (i = 0; i < fimc->num_clocks; i++) { if (fimc->clock[i]) { clk_disable(fimc->clock[i]); clk_put(fimc->clock[i]); @@ -1489,15 +1491,16 @@ static void fimc_clk_release(struct fimc_dev *fimc) static int fimc_clk_get(struct fimc_dev *fimc) { int i; - for (i = 0; i < NUM_FIMC_CLOCKS; i++) { - fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clock_name[i]); - if (IS_ERR(fimc->clock[i])) { - dev_err(&fimc->pdev->dev, - "failed to get fimc clock: %s\n", - fimc_clock_name[i]); - return -ENXIO; + for (i = 0; i < fimc->num_clocks; i++) { + fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); + + if (!IS_ERR_OR_NULL(fimc->clock[i])) { + clk_enable(fimc->clock[i]); + continue; } - clk_enable(fimc->clock[i]); + dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", + fimc_clocks[i]); + return -ENXIO; } return 0; } @@ -1508,6 +1511,7 @@ static int fimc_probe(struct platform_device *pdev) struct resource *res; struct samsung_fimc_driverdata *drv_data; int ret = 0; + int cap_input_index = -1; dev_dbg(&pdev->dev, "%s():\n", __func__); @@ -1557,10 +1561,26 @@ static int fimc_probe(struct platform_device *pdev) goto err_req_region; } + fimc->num_clocks = MAX_FIMC_CLOCKS - 1; + /* + * Check if vide capture node needs to be registered for this device + * instance. + */ + if (fimc->pdata) { + int i; + for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) + if (fimc->pdata->isp_info[i]) + break; + if (i < FIMC_MAX_CAMIF_CLIENTS) { + cap_input_index = i; + fimc->num_clocks++; + } + } + ret = fimc_clk_get(fimc); if (ret) goto err_regs_unmap; - clk_set_rate(fimc->clock[0], drv_data->lclk_frequency); + clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { @@ -1590,19 +1610,12 @@ static int fimc_probe(struct platform_device *pdev) goto err_irq; /* At least one camera sensor is required to register capture node */ - if (fimc->pdata) { - int i; - for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) - if (fimc->pdata->isp_info[i]) - break; - - if (i < FIMC_MAX_CAMIF_CLIENTS) { - ret = fimc_register_capture_device(fimc); - if (ret) - goto err_m2m; - } + if (cap_input_index >= 0) { + ret = fimc_register_capture_device(fimc); + if (ret) + goto err_m2m; + clk_disable(fimc->clock[CLK_CAM]); } - /* * Exclude the additional output DMA address registers by masking * them out on HW revisions that provide extended capabilites. diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index b23d492796e9..1c6aa6924550 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -37,7 +37,7 @@ /* Time to wait for next frame VSYNC interrupt while stopping operation. */ #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) -#define NUM_FIMC_CLOCKS 2 +#define MAX_FIMC_CLOCKS 3 #define MODULE_NAME "s5p-fimc" #define FIMC_MAX_DEVS 4 #define FIMC_MAX_OUT_BUFS 4 @@ -45,7 +45,13 @@ #define SCALER_MAX_VRATIO 64 #define DMA_MIN_SIZE 8 -/* FIMC device state flags */ +/* indices to the clocks array */ +enum { + CLK_BUS, + CLK_GATE, + CLK_CAM, +}; + enum fimc_dev_flags { /* for m2m node */ ST_IDLE, @@ -407,7 +413,8 @@ struct fimc_ctx; * @lock: the mutex protecting this data structure * @pdev: pointer to the FIMC platform device * @pdata: pointer to the device platform data - * @id: FIMC device index (0..2) + * @id: FIMC device index (0..FIMC_MAX_DEVS) + * @num_clocks: the number of clocks managed by this device instance * @clock[]: the clocks required for FIMC operation * @regs: the mapped hardware registers * @regs_res: the resource claimed for IO registers @@ -423,8 +430,9 @@ struct fimc_dev { struct platform_device *pdev; struct s5p_platform_fimc *pdata; struct samsung_fimc_variant *variant; - int id; - struct clk *clock[NUM_FIMC_CLOCKS]; + u16 id; + u16 num_clocks; + struct clk *clock[MAX_FIMC_CLOCKS]; void __iomem *regs; struct resource *regs_res; int irq; -- cgit v1.2.2 From 10038bea7a729bcb8c51a2c856f5b58b33646d65 Mon Sep 17 00:00:00 2001 From: Hyunwoong Kim Date: Wed, 22 Dec 2010 00:56:05 -0300 Subject: [media] s5p-fimc: fix the value of YUV422 1-plane formats Some color formats are mismatched in s5p-fimc driver. CIOCTRL[1:0], order422_out, should be set 2b'00 not 2b'11 to use V4L2_PIX_FMT_YUYV. Because in V4L2 standard V4L2_PIX_FMT_YUYV means "start + 0: Y'00 Cb00 Y'01 Cr00 Y'02 Cb01 Y'03 Cr01". According to datasheet 2b'00 is right value for V4L2_PIX_FMT_YUYV. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-core.c | 16 ++++++++-------- drivers/media/video/s5p-fimc/fimc-core.h | 12 ------------ drivers/media/video/s5p-fimc/regs-fimc.h | 12 ++++++------ 3 files changed, 14 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index db249e6c355d..70d6b4c9760f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -450,34 +450,34 @@ static void fimc_set_yuv_order(struct fimc_ctx *ctx) /* Set order for 1 plane input formats. */ switch (ctx->s_frame.fmt->color) { case S5P_FIMC_YCRYCB422: - ctx->in_order_1p = S5P_FIMC_IN_YCRYCB; + ctx->in_order_1p = S5P_MSCTRL_ORDER422_CBYCRY; break; case S5P_FIMC_CBYCRY422: - ctx->in_order_1p = S5P_FIMC_IN_CBYCRY; + ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCRYCB; break; case S5P_FIMC_CRYCBY422: - ctx->in_order_1p = S5P_FIMC_IN_CRYCBY; + ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCBYCR; break; case S5P_FIMC_YCBYCR422: default: - ctx->in_order_1p = S5P_FIMC_IN_YCBYCR; + ctx->in_order_1p = S5P_MSCTRL_ORDER422_CRYCBY; break; } dbg("ctx->in_order_1p= %d", ctx->in_order_1p); switch (ctx->d_frame.fmt->color) { case S5P_FIMC_YCRYCB422: - ctx->out_order_1p = S5P_FIMC_OUT_YCRYCB; + ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CBYCRY; break; case S5P_FIMC_CBYCRY422: - ctx->out_order_1p = S5P_FIMC_OUT_CBYCRY; + ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCRYCB; break; case S5P_FIMC_CRYCBY422: - ctx->out_order_1p = S5P_FIMC_OUT_CRYCBY; + ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCBYCR; break; case S5P_FIMC_YCBYCR422: default: - ctx->out_order_1p = S5P_FIMC_OUT_YCBYCR; + ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CRYCBY; break; } dbg("ctx->out_order_1p= %d", ctx->out_order_1p); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 1c6aa6924550..562d15d7059a 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -99,18 +99,6 @@ enum fimc_color_fmt { #define fimc_fmt_is_rgb(x) ((x) & 0x10) -/* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */ -#define S5P_FIMC_OUT_CRYCBY S5P_CIOCTRL_ORDER422_CRYCBY -#define S5P_FIMC_OUT_CBYCRY S5P_CIOCTRL_ORDER422_YCRYCB -#define S5P_FIMC_OUT_YCRYCB S5P_CIOCTRL_ORDER422_CBYCRY -#define S5P_FIMC_OUT_YCBYCR S5P_CIOCTRL_ORDER422_YCBYCR - -/* Input Y/Cb/Cr components order for 1 plane YCbCr 4:2:2 color formats. */ -#define S5P_FIMC_IN_CRYCBY S5P_MSCTRL_ORDER422_CRYCBY -#define S5P_FIMC_IN_CBYCRY S5P_MSCTRL_ORDER422_YCRYCB -#define S5P_FIMC_IN_YCRYCB S5P_MSCTRL_ORDER422_CBYCRY -#define S5P_FIMC_IN_YCBYCR S5P_MSCTRL_ORDER422_YCBYCR - /* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */ #define S5P_FIMC_LSB_CRCB S5P_CIOCTRL_ORDER422_2P_LSB_CRCB diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index 74ca705df765..fe19b4b0fb6a 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -98,8 +98,8 @@ #define S5P_CIOCTRL 0x4c #define S5P_CIOCTRL_ORDER422_MASK (3 << 0) #define S5P_CIOCTRL_ORDER422_CRYCBY (0 << 0) -#define S5P_CIOCTRL_ORDER422_YCRYCB (1 << 0) -#define S5P_CIOCTRL_ORDER422_CBYCRY (2 << 0) +#define S5P_CIOCTRL_ORDER422_CBYCRY (1 << 0) +#define S5P_CIOCTRL_ORDER422_YCRYCB (2 << 0) #define S5P_CIOCTRL_ORDER422_YCBYCR (3 << 0) #define S5P_CIOCTRL_LASTIRQ_ENABLE (1 << 2) #define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3) @@ -223,10 +223,10 @@ #define S5P_MSCTRL_FLIP_Y_MIRROR (2 << 13) #define S5P_MSCTRL_FLIP_180 (3 << 13) #define S5P_MSCTRL_ORDER422_SHIFT 4 -#define S5P_MSCTRL_ORDER422_CRYCBY (0 << 4) -#define S5P_MSCTRL_ORDER422_YCRYCB (1 << 4) -#define S5P_MSCTRL_ORDER422_CBYCRY (2 << 4) -#define S5P_MSCTRL_ORDER422_YCBYCR (3 << 4) +#define S5P_MSCTRL_ORDER422_YCBYCR (0 << 4) +#define S5P_MSCTRL_ORDER422_CBYCRY (1 << 4) +#define S5P_MSCTRL_ORDER422_YCRYCB (2 << 4) +#define S5P_MSCTRL_ORDER422_CRYCBY (3 << 4) #define S5P_MSCTRL_ORDER422_MASK (3 << 4) #define S5P_MSCTRL_INPUT_EXTCAM (0 << 3) #define S5P_MSCTRL_INPUT_MEMORY (1 << 3) -- cgit v1.2.2 From b241c6d6f4ceddddfd8097c702dcfdd6b38fbe18 Mon Sep 17 00:00:00 2001 From: Hyunwoong Kim Date: Tue, 28 Dec 2010 11:27:13 -0300 Subject: [media] s5p-fimc: Configure scaler registers depending on FIMC version The main scaler has four SFRs for main scaler ratio depending on FIMC version. FIMC 4.x has only two SFRs and FIMC 5.x has four SFRs for main scaler. Those are MainHorRatio, MainHorRatio_ext, MainVerRatio and MainverRatio_ext. The FIMC 5.x has 15 bit resolution for scaling ratio as below. {MainHorRatio,MainHorRatio_ext} = {[14:6],[5:0]}. {MainVerRatio,MainVerRatio_ext} = {[14:6],[5:0]}. MainHorRatio = CISCCTRL[24:16], MainHorRatio_ext = CIEXTEN[15:10] MainVerRatio = CISCCTRL[8:0], MainVerRatio_ext = CIEXTEN[5:0] This patch supports FIMC 4.x and FIMC 5.x using platform_device_id::driver_data. Reviewed-by: Jonghun Han Signed-off-by: Hyunwoong Kim Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 7 +++- drivers/media/video/s5p-fimc/fimc-core.c | 22 ++++++++++-- drivers/media/video/s5p-fimc/fimc-core.h | 7 +++- drivers/media/video/s5p-fimc/fimc-reg.c | 52 +++++++++++++++++++++++++---- drivers/media/video/s5p-fimc/regs-fimc.h | 12 +++++-- 5 files changed, 87 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 03ddf5d6164f..91304eef812b 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -237,6 +237,7 @@ static int start_streaming(struct vb2_queue *q) struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; struct s5p_fimc_isp_info *isp_info; + struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; int ret; ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); @@ -259,7 +260,11 @@ static int start_streaming(struct vb2_queue *q) return ret; } fimc_hw_set_input_path(ctx); - fimc_hw_set_scaler(ctx); + fimc_hw_set_prescaler(ctx); + if (variant->has_mainscaler_ext) + fimc_hw_set_mainscaler_ext(ctx); + else + fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 70d6b4c9760f..59fa5126fc2d 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -248,6 +248,7 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) struct fimc_scaler *sc = &ctx->scaler; struct fimc_frame *s_frame = &ctx->s_frame; struct fimc_frame *d_frame = &ctx->d_frame; + struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; int tx, ty, sx, sy; int ret; @@ -286,8 +287,14 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) sc->pre_dst_width = sx / sc->pre_hratio; sc->pre_dst_height = sy / sc->pre_vratio; - sc->main_hratio = (sx << 8) / (tx << sc->hfactor); - sc->main_vratio = (sy << 8) / (ty << sc->vfactor); + if (variant->has_mainscaler_ext) { + sc->main_hratio = (sx << 14) / (tx << sc->hfactor); + sc->main_vratio = (sy << 14) / (ty << sc->vfactor); + } else { + sc->main_hratio = (sx << 8) / (tx << sc->hfactor); + sc->main_vratio = (sy << 8) / (ty << sc->vfactor); + + } sc->scaleup_h = (tx >= sx) ? 1 : 0; sc->scaleup_v = (ty >= sy) ? 1 : 0; @@ -571,6 +578,7 @@ static void fimc_dma_run(void *priv) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc; + struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; unsigned long flags; u32 ret; @@ -603,7 +611,12 @@ static void fimc_dma_run(void *priv) err("Scaler setup error"); goto dma_unlock; } - fimc_hw_set_scaler(ctx); + + fimc_hw_set_prescaler(ctx); + if (variant->has_mainscaler_ext) + fimc_hw_set_mainscaler_ext(ctx); + else + fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); @@ -1730,6 +1743,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, + .has_mainscaler_ext = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 1, @@ -1751,6 +1765,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { .has_inp_rot = 1, .has_out_rot = 1, .has_cistatus2 = 1, + .has_mainscaler_ext = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 1, @@ -1761,6 +1776,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { static struct samsung_fimc_variant fimc2_variant_s5pv310 = { .pix_hoff = 1, .has_cistatus2 = 1, + .has_mainscaler_ext = 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 562d15d7059a..8aee9e3207f9 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -361,6 +361,8 @@ struct fimc_pix_limit { * @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 + * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register + * are 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 @@ -372,6 +374,7 @@ struct samsung_fimc_variant { unsigned int has_inp_rot:1; unsigned int has_out_rot:1; unsigned int has_cistatus2:1; + unsigned int has_mainscaler_ext:1; struct fimc_pix_limit *pix_limit; u16 min_inp_pixsize; u16 min_out_pixsize; @@ -569,7 +572,9 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx); void fimc_hw_set_out_dma(struct fimc_ctx *ctx); void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable); void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); -void fimc_hw_set_scaler(struct fimc_ctx *ctx); +void fimc_hw_set_prescaler(struct fimc_ctx *ctx); +void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); +void fimc_hw_set_mainscaler_ext(struct fimc_ctx *ctx); void fimc_hw_en_capture(struct fimc_ctx *ctx); void fimc_hw_set_effect(struct fimc_ctx *ctx); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index c14c8316ea13..064fa0a8b893 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -243,7 +243,7 @@ void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) writel(cfg, dev->regs + S5P_CIOCTRL); } -static void fimc_hw_set_prescaler(struct fimc_ctx *ctx) +void fimc_hw_set_prescaler(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; struct fimc_scaler *sc = &ctx->scaler; @@ -261,7 +261,7 @@ static void fimc_hw_set_prescaler(struct fimc_ctx *ctx) writel(cfg, dev->regs + S5P_CISCPREDST); } -void fimc_hw_set_scaler(struct fimc_ctx *ctx) +static void fimc_hw_set_scaler(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; struct fimc_scaler *sc = &ctx->scaler; @@ -269,8 +269,6 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx) struct fimc_frame *dst_frame = &ctx->d_frame; u32 cfg = 0; - fimc_hw_set_prescaler(ctx); - if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE); @@ -310,13 +308,55 @@ void fimc_hw_set_scaler(struct fimc_ctx *ctx) cfg |= S5P_CISCCTRL_INTERLACE; } + writel(cfg, dev->regs + S5P_CISCCTRL); +} + +void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_scaler *sc = &ctx->scaler; + u32 cfg; + + dbg("main_hratio= 0x%X main_vratio= 0x%X", + sc->main_hratio, sc->main_vratio); + + fimc_hw_set_scaler(ctx); + + cfg = readl(dev->regs + S5P_CISCCTRL); + cfg &= ~S5P_CISCCTRL_MHRATIO_MASK; + cfg &= ~S5P_CISCCTRL_MVRATIO_MASK; + cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio); + cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio); + + writel(cfg, dev->regs + S5P_CISCCTRL); +} + +void fimc_hw_set_mainscaler_ext(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_scaler *sc = &ctx->scaler; + u32 cfg, cfg_ext; + dbg("main_hratio= 0x%X main_vratio= 0x%X", sc->main_hratio, sc->main_vratio); - cfg |= S5P_CISCCTRL_SC_HORRATIO(sc->main_hratio); - cfg |= S5P_CISCCTRL_SC_VERRATIO(sc->main_vratio); + fimc_hw_set_scaler(ctx); + + cfg = readl(dev->regs + S5P_CISCCTRL); + cfg &= ~S5P_CISCCTRL_MHRATIO_MASK; + cfg &= ~S5P_CISCCTRL_MVRATIO_MASK; + cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio); + cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio); writel(cfg, dev->regs + S5P_CISCCTRL); + + cfg_ext = readl(dev->regs + S5P_CIEXTEN); + cfg_ext &= ~S5P_CIEXTEN_MHRATIO_EXT_MASK; + cfg_ext &= ~S5P_CIEXTEN_MVRATIO_EXT_MASK; + cfg_ext |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio); + cfg_ext |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio); + + writel(cfg_ext, dev->regs + S5P_CIEXTEN); } void fimc_hw_en_capture(struct fimc_ctx *ctx) diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index fe19b4b0fb6a..04669a54a3c2 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -139,8 +139,12 @@ #define S5P_CISCCTRL_OUTRGB_FMT_MASK (3 << 11) #define S5P_CISCCTRL_RGB_EXT (1 << 10) #define S5P_CISCCTRL_ONE2ONE (1 << 9) -#define S5P_CISCCTRL_SC_HORRATIO(x) ((x) << 16) -#define S5P_CISCCTRL_SC_VERRATIO(x) ((x) << 0) +#define S5P_CISCCTRL_MHRATIO(x) ((x) << 16) +#define S5P_CISCCTRL_MVRATIO(x) ((x) << 0) +#define S5P_CISCCTRL_MHRATIO_MASK (0x1ff << 16) +#define S5P_CISCCTRL_MVRATIO_MASK (0x1ff << 0) +#define S5P_CISCCTRL_MHRATIO_EXT(x) (((x) >> 6) << 16) +#define S5P_CISCCTRL_MVRATIO_EXT(x) (((x) >> 6) << 0) /* Target area */ #define S5P_CITAREA 0x5c @@ -263,6 +267,10 @@ /* Real output DMA image size (extension register) */ #define S5P_CIEXTEN 0x188 +#define S5P_CIEXTEN_MHRATIO_EXT(x) (((x) & 0x3f) << 10) +#define S5P_CIEXTEN_MVRATIO_EXT(x) ((x) & 0x3f) +#define S5P_CIEXTEN_MHRATIO_EXT_MASK (0x3f << 10) +#define S5P_CIEXTEN_MVRATIO_EXT_MASK 0x3f #define S5P_CIDMAPARAM 0x18c #define S5P_CIDMAPARAM_R_LINEAR (0 << 29) -- cgit v1.2.2 From 70f66ea2aafbd9022a5dcdfd823538e540873585 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 28 Dec 2010 11:37:55 -0300 Subject: [media] s5p-fimc: Move scaler details handling to the register API file Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 6 +--- drivers/media/video/s5p-fimc/fimc-core.c | 6 +--- drivers/media/video/s5p-fimc/fimc-core.h | 1 - drivers/media/video/s5p-fimc/fimc-reg.c | 49 +++++++++++------------------ 4 files changed, 20 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 91304eef812b..2b03c956d0f6 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -237,7 +237,6 @@ static int start_streaming(struct vb2_queue *q) struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; struct s5p_fimc_isp_info *isp_info; - struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; int ret; ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); @@ -261,10 +260,7 @@ static int start_streaming(struct vb2_queue *q) } fimc_hw_set_input_path(ctx); fimc_hw_set_prescaler(ctx); - if (variant->has_mainscaler_ext) - fimc_hw_set_mainscaler_ext(ctx); - else - fimc_hw_set_mainscaler(ctx); + fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 59fa5126fc2d..09bfac45ea32 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -578,7 +578,6 @@ static void fimc_dma_run(void *priv) { struct fimc_ctx *ctx = priv; struct fimc_dev *fimc; - struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; unsigned long flags; u32 ret; @@ -613,10 +612,7 @@ static void fimc_dma_run(void *priv) } fimc_hw_set_prescaler(ctx); - if (variant->has_mainscaler_ext) - fimc_hw_set_mainscaler_ext(ctx); - else - fimc_hw_set_mainscaler(ctx); + fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 8aee9e3207f9..1c15358b43b6 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -574,7 +574,6 @@ void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable); void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); void fimc_hw_set_prescaler(struct fimc_ctx *ctx); void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); -void fimc_hw_set_mainscaler_ext(struct fimc_ctx *ctx); void fimc_hw_en_capture(struct fimc_ctx *ctx); void fimc_hw_set_effect(struct fimc_ctx *ctx); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 064fa0a8b893..8e5a0bbae580 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -314,6 +314,7 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx) void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; + struct samsung_fimc_variant *variant = dev->variant; struct fimc_scaler *sc = &ctx->scaler; u32 cfg; @@ -323,40 +324,26 @@ void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) fimc_hw_set_scaler(ctx); cfg = readl(dev->regs + S5P_CISCCTRL); - cfg &= ~S5P_CISCCTRL_MHRATIO_MASK; - cfg &= ~S5P_CISCCTRL_MVRATIO_MASK; - cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio); - cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio); - writel(cfg, dev->regs + S5P_CISCCTRL); -} + if (variant->has_mainscaler_ext) { + cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); + cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio); + cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio); + writel(cfg, dev->regs + S5P_CISCCTRL); -void fimc_hw_set_mainscaler_ext(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_scaler *sc = &ctx->scaler; - u32 cfg, cfg_ext; + cfg = readl(dev->regs + S5P_CIEXTEN); - dbg("main_hratio= 0x%X main_vratio= 0x%X", - sc->main_hratio, sc->main_vratio); - - fimc_hw_set_scaler(ctx); - - cfg = readl(dev->regs + S5P_CISCCTRL); - cfg &= ~S5P_CISCCTRL_MHRATIO_MASK; - cfg &= ~S5P_CISCCTRL_MVRATIO_MASK; - cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio); - cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio); - - writel(cfg, dev->regs + S5P_CISCCTRL); - - cfg_ext = readl(dev->regs + S5P_CIEXTEN); - cfg_ext &= ~S5P_CIEXTEN_MHRATIO_EXT_MASK; - cfg_ext &= ~S5P_CIEXTEN_MVRATIO_EXT_MASK; - cfg_ext |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio); - cfg_ext |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio); - - writel(cfg_ext, dev->regs + S5P_CIEXTEN); + cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK | + S5P_CIEXTEN_MHRATIO_EXT_MASK); + cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio); + cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio); + writel(cfg, dev->regs + S5P_CIEXTEN); + } else { + cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); + cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio); + cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio); + writel(cfg, dev->regs + S5P_CISCCTRL); + } } void fimc_hw_en_capture(struct fimc_ctx *ctx) -- cgit v1.2.2 From 1b09f292eb99fd6a3601e8421c463905dbb0a866 Mon Sep 17 00:00:00 2001 From: Hyunwoong Kim Date: Tue, 28 Dec 2010 22:12:43 -0300 Subject: [media] s5p-fimc: update checking scaling ratio range Horizontal and vertical scaling range are according to the following equations. If (SRC_Width >= 64 x DST_Width) { Exit(-1); /* Out of Horizontal scale range} If (SRC_Height >= 64 x DST_Height) { Exit(-1); /* Out of Vertical scale range} fimc_check_scaler_ratio() is used to check if horizontal and vertical scale range are valid or not. To use fimc_check_scaler_ratio, source and destination format should be set by VIDIOC_S_FMT. And in case of scaling up, it doesn't have to check the scale range. Reviewed-by: Jonghun Han Signed-off-by: Hyunwoong Kim Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 4 +- drivers/media/video/s5p-fimc/fimc-core.c | 59 +++++++++++++++++++---------- drivers/media/video/s5p-fimc/fimc-core.h | 2 +- 3 files changed, 44 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 2b03c956d0f6..c326f6bbf290 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -787,7 +787,9 @@ static int fimc_cap_s_crop(struct file *file, void *fh, f = &ctx->s_frame; /* Check for the pixel scaling ratio when cropping input image. */ - ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); + ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, + ctx->d_frame.width, ctx->d_frame.height, + ctx->rotation); if (ret) { v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range"); return ret; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 09bfac45ea32..560cd21dae28 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -200,24 +200,21 @@ static struct v4l2_queryctrl *get_ctrl(int id) return NULL; } -int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f) +int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot) { - if (r->width > f->width) { - if (f->width > (r->width * SCALER_MAX_HRATIO)) - return -EINVAL; - } else { - if ((f->width * SCALER_MAX_HRATIO) < r->width) - return -EINVAL; - } + int tx, ty; - if (r->height > f->height) { - if (f->height > (r->height * SCALER_MAX_VRATIO)) - return -EINVAL; + if (rot == 90 || rot == 270) { + ty = dw; + tx = dh; } else { - if ((f->height * SCALER_MAX_VRATIO) < r->height) - return -EINVAL; + tx = dw; + ty = dh; } + if ((sw >= SCALER_MAX_HRATIO * tx) || (sh >= SCALER_MAX_VRATIO * ty)) + return -EINVAL; + return 0; } @@ -1065,6 +1062,7 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; struct fimc_dev *fimc = ctx->fimc_dev; unsigned long flags; + int ret = 0; spin_lock_irqsave(&ctx->slock, flags); @@ -1084,6 +1082,20 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) break; case V4L2_CID_ROTATE: + if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) { + ret = fimc_check_scaler_ratio(ctx->s_frame.width, + ctx->s_frame.height, + ctx->d_frame.width, + ctx->d_frame.height, + ctrl->value); + if (ret) { + v4l2_err(&fimc->m2m.v4l2_dev, + "Out of scaler range"); + spin_unlock_irqrestore(&ctx->slock, flags); + return -EINVAL; + } + } + /* Check for the output rotator availability */ if ((ctrl->value == 90 || ctrl->value == 270) && (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) { @@ -1232,18 +1244,27 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) &ctx->s_frame : &ctx->d_frame; 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 */ - if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame); - else - ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame); + /* Check to see if scaling ratio is within supported range */ + if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) { + if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, + ctx->d_frame.width, + ctx->d_frame.height, + ctx->rotation); + } else { + ret = fimc_check_scaler_ratio(ctx->s_frame.width, + ctx->s_frame.height, + cr->c.width, cr->c.height, + ctx->rotation); + } + if (ret) { v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); spin_unlock_irqrestore(&ctx->slock, flags); return -EINVAL; } } + ctx->state |= FIMC_PARAMS; f->offs_h = cr->c.left; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 1c15358b43b6..57bff0d21962 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -611,7 +611,7 @@ struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask); struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f, unsigned int mask); -int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f); +int fimc_check_scaler_ratio(int sw, int sh, int dw, int dh, int rot); int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, -- cgit v1.2.2 From 65777e5c58bd3b25fcba39eddb98d8a8ce35d3be Mon Sep 17 00:00:00 2001 From: Hyunwoong Kim Date: Wed, 29 Dec 2010 04:47:49 -0300 Subject: [media] s5p-fimc: Support stop_streaming and job_abort This patch adds callback functions, stop_streaming and job_abort, to abort or finish any DMA in progress. stop_streaming is called by videobuf2 framework and job_abort is called by m2m framework. ST_M2M_PEND state is added to discard the next job. Reviewed-by: Jonghun Han Signed-off-by: Hyunwoong Kim Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-core.c | 35 ++++++++++++++++++++++++++++++-- drivers/media/video/s5p-fimc/fimc-core.h | 1 + 2 files changed, 34 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 560cd21dae28..cd8a3003f1aa 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -307,6 +307,23 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) return 0; } +static int stop_streaming(struct vb2_queue *q) +{ + struct fimc_ctx *ctx = q->drv_priv; + struct fimc_dev *fimc = ctx->fimc_dev; + + if (!fimc_m2m_pending(fimc)) + return 0; + + set_bit(ST_M2M_SHUT, &fimc->state); + + wait_event_timeout(fimc->irq_queue, + !test_bit(ST_M2M_SHUT, &fimc->state), + FIMC_SHUTDOWN_TIMEOUT); + + return 0; +} + static void fimc_capture_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; @@ -358,7 +375,10 @@ static irqreturn_t fimc_isr(int irq, void *priv) spin_lock(&fimc->slock); - if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { + if (test_and_clear_bit(ST_M2M_SHUT, &fimc->state)) { + wake_up(&fimc->irq_queue); + goto isr_unlock; + } else if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { struct vb2_buffer *src_vb, *dst_vb; struct fimc_ctx *ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); @@ -634,7 +654,17 @@ dma_unlock: static void fimc_job_abort(void *priv) { - /* Nothing done in job_abort. */ + struct fimc_ctx *ctx = priv; + struct fimc_dev *fimc = ctx->fimc_dev; + + if (!fimc_m2m_pending(fimc)) + return; + + set_bit(ST_M2M_SHUT, &fimc->state); + + wait_event_timeout(fimc->irq_queue, + !test_bit(ST_M2M_SHUT, &fimc->state), + FIMC_SHUTDOWN_TIMEOUT); } static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, @@ -711,6 +741,7 @@ struct vb2_ops fimc_qops = { .buf_queue = fimc_buf_queue, .wait_prepare = fimc_unlock, .wait_finish = fimc_lock, + .stop_streaming = stop_streaming, }; static int fimc_m2m_querycap(struct file *file, void *priv, diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 57bff0d21962..4829a2515076 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -57,6 +57,7 @@ enum fimc_dev_flags { ST_IDLE, ST_OUTDMA_RUN, ST_M2M_PEND, + ST_M2M_SHUT, /* for capture node */ ST_CAPT_PEND, ST_CAPT_RUN, -- cgit v1.2.2 From 5bbe425e57d3ca715cfe9c98bac5f8f07a96c81a Mon Sep 17 00:00:00 2001 From: Hyunwoong Kim Date: Wed, 29 Dec 2010 07:08:32 -0300 Subject: [media] s5p-fimc: fix MSCTRL.FIFO_CTRL for performance enhancement This patch fixes the value of FIFO_CTRL in MSCTRL. Main-scaler has the value to specify a basis FIFO control of input DMA. The description of FIFO_CTRL has been changed as below. 0 = FIFO Empty (Next burst transaction is possible when FIFO is empty) 1 = FIFO Full (Next burst transaction is possible except Full FIFO) Value '1' is recommended to enhance the FIMC operation performance. Reviewed-by: Jonghun Han Signed-off-by: Hyunwoong Kim Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-reg.c | 4 +++- drivers/media/video/s5p-fimc/regs-fimc.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 8e5a0bbae580..10684aef5b2d 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -437,7 +437,9 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) | S5P_MSCTRL_C_INT_IN_MASK | S5P_MSCTRL_2P_IN_ORDER_MASK); - cfg |= S5P_MSCTRL_IN_BURST_COUNT(4) | S5P_MSCTRL_INPUT_MEMORY; + cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4) + | S5P_MSCTRL_INPUT_MEMORY + | S5P_MSCTRL_FIFO_CTRL_FULL); switch (frame->fmt->color) { case S5P_FIMC_RGB565...S5P_FIMC_RGB888: diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h index 04669a54a3c2..0fea3e635d76 100644 --- a/drivers/media/video/s5p-fimc/regs-fimc.h +++ b/drivers/media/video/s5p-fimc/regs-fimc.h @@ -226,6 +226,7 @@ #define S5P_MSCTRL_FLIP_X_MIRROR (1 << 13) #define S5P_MSCTRL_FLIP_Y_MIRROR (2 << 13) #define S5P_MSCTRL_FLIP_180 (3 << 13) +#define S5P_MSCTRL_FIFO_CTRL_FULL (1 << 12) #define S5P_MSCTRL_ORDER422_SHIFT 4 #define S5P_MSCTRL_ORDER422_YCBYCR (0 << 4) #define S5P_MSCTRL_ORDER422_CBYCRY (1 << 4) -- cgit v1.2.2 From ba10795ed1018488964e6054b5076ec31a471d96 Mon Sep 17 00:00:00 2001 From: Sungchun Kang Date: Thu, 30 Dec 2010 02:35:28 -0300 Subject: [media] s5p-fimc: fimc_stop_capture bug fix When is called fimc_stop_capture, it seems that wait_event_timeout used improperly. It should be wake up by irq handler. Reviewed-by Jonghun Han Signed-off-by: Sungchun Kang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index c326f6bbf290..5159cc8a0e1c 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -204,7 +204,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc) spin_unlock_irqrestore(&fimc->slock, flags); wait_event_timeout(fimc->irq_queue, - test_bit(ST_CAPT_SHUT, &fimc->state), + !test_bit(ST_CAPT_SHUT, &fimc->state), FIMC_SHUTDOWN_TIMEOUT); v4l2_subdev_call(cap->sd, video, s_stream, 0); -- cgit v1.2.2 From f8e2e3eab8f70103fb4680e2da202e14199c199a Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 3 Jan 2011 08:07:30 -0300 Subject: [media] Add v4l2 subdev driver for NOON010PC30L image sensor Add I2C/V4L2 subdev driver for Siliconfile NOON010PC30 CIF camera. The driver implements basic functionality, i.e. CIF/QCIF/QQCIF resolution and color format selection, automatic/manual color balance control. Other functions like cropping, rotation/flip, exposure etc. can be easily implemented if needed. Reviewed-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 6 + drivers/media/video/Makefile | 1 + drivers/media/video/noon010pc30.c | 792 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 799 insertions(+) create mode 100644 drivers/media/video/noon010pc30.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9f20fc5903c2..f86e407c2218 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -740,6 +740,12 @@ config VIDEO_VIA_CAMERA Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems with ov7670 sensors. +config VIDEO_NOON010PC30 + tristate "NOON010PC30 CIF camera sensor support" + depends on I2C && VIDEO_V4L2 + ---help--- + This driver supports NOON010PC30 CIF camera from Siliconfile + config SOC_CAMERA tristate "SoC camera support" depends on VIDEO_V4L2 && HAS_DMA && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 40833fec34dc..251b7cac3f91 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o +obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o diff --git a/drivers/media/video/noon010pc30.c b/drivers/media/video/noon010pc30.c new file mode 100644 index 000000000000..35f722a88f76 --- /dev/null +++ b/drivers/media/video/noon010pc30.c @@ -0,0 +1,792 @@ +/* + * Driver for SiliconFile NOON010PC30 CIF (1/11") Image Sensor with ISP + * + * Copyright (C) 2010 Samsung Electronics + * Contact: Sylwester Nawrocki, + * + * Initial register configuration based on a driver authored by + * HeungJun Kim . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later vergsion. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable."); + +#define MODULE_NAME "NOON010PC30" + +/* + * Register offsets within a page + * b15..b8 - page id, b7..b0 - register address + */ +#define POWER_CTRL_REG 0x0001 +#define PAGEMODE_REG 0x03 +#define DEVICE_ID_REG 0x0004 +#define NOON010PC30_ID 0x86 +#define VDO_CTL_REG(n) (0x0010 + (n)) +#define SYNC_CTL_REG 0x0012 +/* Window size and position */ +#define WIN_ROWH_REG 0x0013 +#define WIN_ROWL_REG 0x0014 +#define WIN_COLH_REG 0x0015 +#define WIN_COLL_REG 0x0016 +#define WIN_HEIGHTH_REG 0x0017 +#define WIN_HEIGHTL_REG 0x0018 +#define WIN_WIDTHH_REG 0x0019 +#define WIN_WIDTHL_REG 0x001A +#define HBLANKH_REG 0x001B +#define HBLANKL_REG 0x001C +#define VSYNCH_REG 0x001D +#define VSYNCL_REG 0x001E +/* VSYNC control */ +#define VS_CTL_REG(n) (0x00A1 + (n)) +/* page 1 */ +#define ISP_CTL_REG(n) (0x0110 + (n)) +#define YOFS_REG 0x0119 +#define DARK_YOFS_REG 0x011A +#define SAT_CTL_REG 0x0120 +#define BSAT_REG 0x0121 +#define RSAT_REG 0x0122 +/* Color correction */ +#define CMC_CTL_REG 0x0130 +#define CMC_OFSGH_REG 0x0133 +#define CMC_OFSGL_REG 0x0135 +#define CMC_SIGN_REG 0x0136 +#define CMC_GOFS_REG 0x0137 +#define CMC_COEF_REG(n) (0x0138 + (n)) +#define CMC_OFS_REG(n) (0x0141 + (n)) +/* Gamma correction */ +#define GMA_CTL_REG 0x0160 +#define GMA_COEF_REG(n) (0x0161 + (n)) +/* Lens Shading */ +#define LENS_CTRL_REG 0x01D0 +#define LENS_XCEN_REG 0x01D1 +#define LENS_YCEN_REG 0x01D2 +#define LENS_RC_REG 0x01D3 +#define LENS_GC_REG 0x01D4 +#define LENS_BC_REG 0x01D5 +#define L_AGON_REG 0x01D6 +#define L_AGOFF_REG 0x01D7 +/* Page 3 - Auto Exposure */ +#define AE_CTL_REG(n) (0x0310 + (n)) +#define AE_CTL9_REG 0x032C +#define AE_CTL10_REG 0x032D +#define AE_YLVL_REG 0x031C +#define AE_YTH_REG(n) (0x031D + (n)) +#define AE_WGT_REG 0x0326 +#define EXP_TIMEH_REG 0x0333 +#define EXP_TIMEM_REG 0x0334 +#define EXP_TIMEL_REG 0x0335 +#define EXP_MMINH_REG 0x0336 +#define EXP_MMINL_REG 0x0337 +#define EXP_MMAXH_REG 0x0338 +#define EXP_MMAXM_REG 0x0339 +#define EXP_MMAXL_REG 0x033A +/* Page 4 - Auto White Balance */ +#define AWB_CTL_REG(n) (0x0410 + (n)) +#define AWB_ENABE 0x80 +#define AWB_WGHT_REG 0x0419 +#define BGAIN_PAR_REG(n) (0x044F + (n)) +/* Manual white balance, when AWB_CTL2[0]=1 */ +#define MWB_RGAIN_REG 0x0466 +#define MWB_BGAIN_REG 0x0467 + +/* The token to mark an array end */ +#define REG_TERM 0xFFFF + +struct noon010_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 ispctl1_reg; +}; + +struct noon010_frmsize { + u16 width; + u16 height; + int vid_ctl1; +}; + +static const char * const noon010_supply_name[] = { + "vdd_core", "vddio", "vdda" +}; + +#define NOON010_NUM_SUPPLIES ARRAY_SIZE(noon010_supply_name) + +struct noon010_info { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + const struct noon010pc30_platform_data *pdata; + const struct noon010_format *curr_fmt; + const struct noon010_frmsize *curr_win; + unsigned int hflip:1; + unsigned int vflip:1; + unsigned int power:1; + u8 i2c_reg_page; + struct regulator_bulk_data supply[NOON010_NUM_SUPPLIES]; + u32 gpio_nreset; + u32 gpio_nstby; +}; + +struct i2c_regval { + u16 addr; + u16 val; +}; + +/* Supported resolutions. */ +static const struct noon010_frmsize noon010_sizes[] = { + { + .width = 352, + .height = 288, + .vid_ctl1 = 0, + }, { + .width = 176, + .height = 144, + .vid_ctl1 = 0x10, + }, { + .width = 88, + .height = 72, + .vid_ctl1 = 0x20, + }, +}; + +/* Supported pixel formats. */ +static const struct noon010_format noon010_formats[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x03, + }, { + .code = V4L2_MBUS_FMT_YVYU8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x02, + }, { + .code = V4L2_MBUS_FMT_VYUY8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0, + }, { + .code = V4L2_MBUS_FMT_UYVY8_2X8, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x01, + }, { + .code = V4L2_MBUS_FMT_RGB565_2X8_BE, + .colorspace = V4L2_COLORSPACE_JPEG, + .ispctl1_reg = 0x40, + }, +}; + +static const struct i2c_regval noon010_base_regs[] = { + { WIN_COLL_REG, 0x06 }, { HBLANKL_REG, 0x7C }, + /* Color corection and saturation */ + { ISP_CTL_REG(0), 0x30 }, { ISP_CTL_REG(2), 0x30 }, + { YOFS_REG, 0x80 }, { DARK_YOFS_REG, 0x04 }, + { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 }, + { CMC_CTL_REG, 0x0F }, { CMC_OFSGH_REG, 0x3C }, + { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x3F }, + { CMC_COEF_REG(0), 0x79 }, { CMC_OFS_REG(0), 0x00 }, + { CMC_COEF_REG(1), 0x39 }, { CMC_OFS_REG(1), 0x00 }, + { CMC_COEF_REG(2), 0x00 }, { CMC_OFS_REG(2), 0x00 }, + { CMC_COEF_REG(3), 0x11 }, { CMC_OFS_REG(3), 0x8B }, + { CMC_COEF_REG(4), 0x65 }, { CMC_OFS_REG(4), 0x07 }, + { CMC_COEF_REG(5), 0x14 }, { CMC_OFS_REG(5), 0x04 }, + { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x9C }, + { CMC_COEF_REG(7), 0x33 }, { CMC_OFS_REG(7), 0x89 }, + { CMC_COEF_REG(8), 0x74 }, { CMC_OFS_REG(8), 0x25 }, + /* Automatic white balance */ + { AWB_CTL_REG(0), 0x78 }, { AWB_CTL_REG(1), 0x2E }, + { AWB_CTL_REG(2), 0x20 }, { AWB_CTL_REG(3), 0x85 }, + /* Auto exposure */ + { AE_CTL_REG(0), 0xDC }, { AE_CTL_REG(1), 0x81 }, + { AE_CTL_REG(2), 0x30 }, { AE_CTL_REG(3), 0xA5 }, + { AE_CTL_REG(4), 0x40 }, { AE_CTL_REG(5), 0x51 }, + { AE_CTL_REG(6), 0x33 }, { AE_CTL_REG(7), 0x7E }, + { AE_CTL9_REG, 0x00 }, { AE_CTL10_REG, 0x02 }, + { AE_YLVL_REG, 0x44 }, { AE_YTH_REG(0), 0x34 }, + { AE_YTH_REG(1), 0x30 }, { AE_WGT_REG, 0xD5 }, + /* Lens shading compensation */ + { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 }, + { LENS_YCEN_REG, 0x70 }, { LENS_RC_REG, 0x53 }, + { LENS_GC_REG, 0x40 }, { LENS_BC_REG, 0x3E }, + { REG_TERM, 0 }, +}; + +static inline struct noon010_info *to_noon010(struct v4l2_subdev *sd) +{ + return container_of(sd, struct noon010_info, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct noon010_info, hdl)->sd; +} + +static inline int set_i2c_page(struct noon010_info *info, + struct i2c_client *client, unsigned int reg) +{ + u32 page = reg >> 8 & 0xFF; + int ret = 0; + + if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) { + ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page); + if (!ret) + info->i2c_reg_page = page; + } + return ret; +} + +static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct noon010_info *info = to_noon010(sd); + int ret = set_i2c_page(info, client, reg_addr); + + if (ret) + return ret; + return i2c_smbus_read_byte_data(client, reg_addr & 0xFF); +} + +static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct noon010_info *info = to_noon010(sd); + int ret = set_i2c_page(info, client, reg_addr); + + if (ret) + return ret; + return i2c_smbus_write_byte_data(client, reg_addr & 0xFF, val); +} + +static inline int noon010_bulk_write_reg(struct v4l2_subdev *sd, + const struct i2c_regval *msg) +{ + while (msg->addr != REG_TERM) { + int ret = cam_i2c_write(sd, msg->addr, msg->val); + + if (ret) + return ret; + msg++; + } + return 0; +} + +/* Device reset and sleep mode control */ +static int noon010_power_ctrl(struct v4l2_subdev *sd, bool reset, bool sleep) +{ + struct noon010_info *info = to_noon010(sd); + u8 reg = sleep ? 0xF1 : 0xF0; + int ret = 0; + + if (reset) + ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02); + if (!ret) { + ret = cam_i2c_write(sd, POWER_CTRL_REG, reg); + if (reset && !ret) + info->i2c_reg_page = -1; + } + return ret; +} + +/* Automatic white balance control */ +static int noon010_enable_autowhitebalance(struct v4l2_subdev *sd, int on) +{ + int ret; + + ret = cam_i2c_write(sd, AWB_CTL_REG(1), on ? 0x2E : 0x2F); + if (!ret) + ret = cam_i2c_write(sd, AWB_CTL_REG(0), on ? 0xFB : 0x7B); + return ret; +} + +static int noon010_set_flip(struct v4l2_subdev *sd, int hflip, int vflip) +{ + struct noon010_info *info = to_noon010(sd); + int reg, ret; + + reg = cam_i2c_read(sd, VDO_CTL_REG(1)); + if (reg < 0) + return reg; + + reg &= 0x7C; + if (hflip) + reg |= 0x01; + if (vflip) + reg |= 0x02; + + ret = cam_i2c_write(sd, VDO_CTL_REG(1), reg | 0x80); + if (!ret) { + info->hflip = hflip; + info->vflip = vflip; + } + return ret; +} + +/* Configure resolution and color format */ +static int noon010_set_params(struct v4l2_subdev *sd) +{ + struct noon010_info *info = to_noon010(sd); + int ret; + + if (!info->curr_win) + return -EINVAL; + + ret = cam_i2c_write(sd, VDO_CTL_REG(0), info->curr_win->vid_ctl1); + + if (!ret && info->curr_fmt) + ret = cam_i2c_write(sd, ISP_CTL_REG(0), + info->curr_fmt->ispctl1_reg); + return ret; +} + +/* Find nearest matching image pixel size. */ +static int noon010_try_frame_size(struct v4l2_mbus_framefmt *mf) +{ + unsigned int min_err = ~0; + int i = ARRAY_SIZE(noon010_sizes); + const struct noon010_frmsize *fsize = &noon010_sizes[0], + *match = NULL; + + while (i--) { + int err = abs(fsize->width - mf->width) + + abs(fsize->height - mf->height); + + if (err < min_err) { + min_err = err; + match = fsize; + } + fsize++; + } + if (match) { + mf->width = match->width; + mf->height = match->height; + return 0; + } + return -EINVAL; +} + +static int power_enable(struct noon010_info *info) +{ + int ret; + + if (info->power) { + v4l2_info(&info->sd, "%s: sensor is already on\n", __func__); + return 0; + } + + if (gpio_is_valid(info->gpio_nstby)) + gpio_set_value(info->gpio_nstby, 0); + + if (gpio_is_valid(info->gpio_nreset)) + gpio_set_value(info->gpio_nreset, 0); + + ret = regulator_bulk_enable(NOON010_NUM_SUPPLIES, info->supply); + if (ret) + return ret; + + if (gpio_is_valid(info->gpio_nreset)) { + msleep(50); + gpio_set_value(info->gpio_nreset, 1); + } + if (gpio_is_valid(info->gpio_nstby)) { + udelay(1000); + gpio_set_value(info->gpio_nstby, 1); + } + if (gpio_is_valid(info->gpio_nreset)) { + udelay(1000); + gpio_set_value(info->gpio_nreset, 0); + msleep(100); + gpio_set_value(info->gpio_nreset, 1); + msleep(20); + } + info->power = 1; + + v4l2_dbg(1, debug, &info->sd, "%s: sensor is on\n", __func__); + return 0; +} + +static int power_disable(struct noon010_info *info) +{ + int ret; + + if (!info->power) { + v4l2_info(&info->sd, "%s: sensor is already off\n", __func__); + return 0; + } + + ret = regulator_bulk_disable(NOON010_NUM_SUPPLIES, info->supply); + if (ret) + return ret; + + if (gpio_is_valid(info->gpio_nstby)) + gpio_set_value(info->gpio_nstby, 0); + + if (gpio_is_valid(info->gpio_nreset)) + gpio_set_value(info->gpio_nreset, 0); + + info->power = 0; + + v4l2_dbg(1, debug, &info->sd, "%s: sensor is off\n", __func__); + + return 0; +} + +static int noon010_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + + v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n", + __func__, ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + return noon010_enable_autowhitebalance(sd, ctrl->val); + case V4L2_CID_BLUE_BALANCE: + return cam_i2c_write(sd, MWB_BGAIN_REG, ctrl->val); + case V4L2_CID_RED_BALANCE: + return cam_i2c_write(sd, MWB_RGAIN_REG, ctrl->val); + default: + return -EINVAL; + } +} + +static int noon010_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (!code || index >= ARRAY_SIZE(noon010_formats)) + return -EINVAL; + + *code = noon010_formats[index].code; + return 0; +} + +static int noon010_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) +{ + struct noon010_info *info = to_noon010(sd); + int ret; + + if (!mf) + return -EINVAL; + + if (!info->curr_win || !info->curr_fmt) { + ret = noon010_set_params(sd); + if (ret) + return ret; + } + + mf->width = info->curr_win->width; + mf->height = info->curr_win->height; + mf->code = info->curr_fmt->code; + mf->colorspace = info->curr_fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +/* Return nearest media bus frame format. */ +static const struct noon010_format *try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + int i = ARRAY_SIZE(noon010_formats); + + noon010_try_frame_size(mf); + + while (i--) + if (mf->code == noon010_formats[i].code) + break; + + mf->code = noon010_formats[i].code; + + return &noon010_formats[i]; +} + +static int noon010_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + if (!sd || !mf) + return -EINVAL; + + try_fmt(sd, mf); + return 0; +} + +static int noon010_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct noon010_info *info = to_noon010(sd); + + if (!sd || !mf) + return -EINVAL; + + info->curr_fmt = try_fmt(sd, mf); + + return noon010_set_params(sd); +} + +static int noon010_base_config(struct v4l2_subdev *sd) +{ + struct noon010_info *info = to_noon010(sd); + int ret; + + ret = noon010_bulk_write_reg(sd, noon010_base_regs); + if (!ret) { + info->curr_fmt = &noon010_formats[0]; + info->curr_win = &noon010_sizes[0]; + ret = noon010_set_params(sd); + } + if (!ret) + ret = noon010_set_flip(sd, 1, 0); + if (!ret) + ret = noon010_power_ctrl(sd, false, false); + + /* sync the handler and the registers state */ + v4l2_ctrl_handler_setup(&to_noon010(sd)->hdl); + return ret; +} + +static int noon010_s_power(struct v4l2_subdev *sd, int on) +{ + struct noon010_info *info = to_noon010(sd); + const struct noon010pc30_platform_data *pdata = info->pdata; + int ret = 0; + + if (WARN(pdata == NULL, "No platform data!\n")) + return -ENOMEM; + + if (on) { + ret = power_enable(info); + if (ret) + return ret; + ret = noon010_base_config(sd); + } else { + noon010_power_ctrl(sd, false, true); + ret = power_disable(info); + info->curr_win = NULL; + info->curr_fmt = NULL; + } + + return ret; +} + +static int noon010_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *chip) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return v4l2_chip_ident_i2c_client(client, chip, + V4L2_IDENT_NOON010PC30, 0); +} + +static int noon010_log_status(struct v4l2_subdev *sd) +{ + struct noon010_info *info = to_noon010(sd); + + v4l2_ctrl_handler_log_status(&info->hdl, sd->name); + return 0; +} + +static const struct v4l2_ctrl_ops noon010_ctrl_ops = { + .s_ctrl = noon010_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops noon010_core_ops = { + .g_chip_ident = noon010_g_chip_ident, + .s_power = noon010_s_power, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .log_status = noon010_log_status, +}; + +static const struct v4l2_subdev_video_ops noon010_video_ops = { + .g_mbus_fmt = noon010_g_fmt, + .s_mbus_fmt = noon010_s_fmt, + .try_mbus_fmt = noon010_try_fmt, + .enum_mbus_fmt = noon010_enum_fmt, +}; + +static const struct v4l2_subdev_ops noon010_ops = { + .core = &noon010_core_ops, + .video = &noon010_video_ops, +}; + +/* Return 0 if NOON010PC30L sensor type was detected or -ENODEV otherwise. */ +static int noon010_detect(struct i2c_client *client, struct noon010_info *info) +{ + int ret; + + ret = power_enable(info); + if (ret) + return ret; + + ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG); + if (ret < 0) + dev_err(&client->dev, "I2C read failed: 0x%X\n", ret); + + power_disable(info); + + return ret == NOON010PC30_ID ? 0 : -ENODEV; +} + +static int noon010_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct noon010_info *info; + struct v4l2_subdev *sd; + const struct noon010pc30_platform_data *pdata + = client->dev.platform_data; + int ret; + int i; + + if (!pdata) { + dev_err(&client->dev, "No platform data!\n"); + return -EIO; + } + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + sd = &info->sd; + strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); + v4l2_i2c_subdev_init(sd, client, &noon010_ops); + + v4l2_ctrl_handler_init(&info->hdl, 3); + + v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 127, 1, 64); + v4l2_ctrl_new_std(&info->hdl, &noon010_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 127, 1, 64); + + sd->ctrl_handler = &info->hdl; + + ret = info->hdl.error; + if (ret) + goto np_err; + + info->pdata = client->dev.platform_data; + info->i2c_reg_page = -1; + info->gpio_nreset = -EINVAL; + info->gpio_nstby = -EINVAL; + + if (gpio_is_valid(pdata->gpio_nreset)) { + ret = gpio_request(pdata->gpio_nreset, "NOON010PC30 NRST"); + if (ret) { + dev_err(&client->dev, "GPIO request error: %d\n", ret); + goto np_err; + } + info->gpio_nreset = pdata->gpio_nreset; + gpio_direction_output(info->gpio_nreset, 0); + gpio_export(info->gpio_nreset, 0); + } + + if (gpio_is_valid(pdata->gpio_nstby)) { + ret = gpio_request(pdata->gpio_nstby, "NOON010PC30 NSTBY"); + if (ret) { + dev_err(&client->dev, "GPIO request error: %d\n", ret); + goto np_gpio_err; + } + info->gpio_nstby = pdata->gpio_nstby; + gpio_direction_output(info->gpio_nstby, 0); + gpio_export(info->gpio_nstby, 0); + } + + for (i = 0; i < NOON010_NUM_SUPPLIES; i++) + info->supply[i].supply = noon010_supply_name[i]; + + ret = regulator_bulk_get(&client->dev, NOON010_NUM_SUPPLIES, + info->supply); + if (ret) + goto np_reg_err; + + ret = noon010_detect(client, info); + if (!ret) + return 0; + + /* the sensor detection failed */ + regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); +np_reg_err: + if (gpio_is_valid(info->gpio_nstby)) + gpio_free(info->gpio_nstby); +np_gpio_err: + if (gpio_is_valid(info->gpio_nreset)) + gpio_free(info->gpio_nreset); +np_err: + v4l2_ctrl_handler_free(&info->hdl); + v4l2_device_unregister_subdev(sd); + kfree(info); + return ret; +} + +static int noon010_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct noon010_info *info = to_noon010(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&info->hdl); + + regulator_bulk_free(NOON010_NUM_SUPPLIES, info->supply); + + if (gpio_is_valid(info->gpio_nreset)) + gpio_free(info->gpio_nreset); + + if (gpio_is_valid(info->gpio_nstby)) + gpio_free(info->gpio_nstby); + + kfree(info); + return 0; +} + +static const struct i2c_device_id noon010_id[] = { + { MODULE_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, noon010_id); + + +static struct i2c_driver noon010_i2c_driver = { + .driver = { + .name = MODULE_NAME + }, + .probe = noon010_probe, + .remove = noon010_remove, + .id_table = noon010_id, +}; + +static int __init noon010_init(void) +{ + return i2c_add_driver(&noon010_i2c_driver); +} + +static void __exit noon010_exit(void) +{ + i2c_del_driver(&noon010_i2c_driver); +} + +module_init(noon010_init); +module_exit(noon010_exit); + +MODULE_DESCRIPTION("Siliconfile NOON010PC30 camera driver"); +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 7757ddda6f4febbc52342d82440dd4f7a7d4f14f Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 3 Jan 2011 15:30:14 -0300 Subject: [media] DiB0700: add function to change I2C-speed This commit adds a function to the DiB0700 USB driver which allows drivers to change the I2C clock speed. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700.h | 2 ++ drivers/media/dvb/dvb-usb/dib0700_core.c | 42 +++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 3537d65c04bc..b2a87f2c2c3e 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -32,6 +32,7 @@ extern int dvb_usb_dib0700_debug; // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) +#define REQUEST_SET_I2C_PARAM 0x10 #define REQUEST_SET_RC 0x11 #define REQUEST_NEW_I2C_READ 0x12 #define REQUEST_NEW_I2C_WRITE 0x13 @@ -61,6 +62,7 @@ extern struct i2c_algorithm dib0700_i2c_algo; extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, int *cold); extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type); +extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz); extern int dib0700_device_count; extern int dvb_usb_dib0700_ir_proto; diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 98ffb40728e3..ebda77dde97e 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -328,6 +328,30 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, return dib0700_ctrl_wr(d, b, 10); } +int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) +{ + u16 divider; + u8 b[8]; + + if (scl_kHz == 0) + return -EINVAL; + + b[0] = REQUEST_SET_I2C_PARAM; + divider = (u16) (30000 / scl_kHz); + b[2] = (u8) (divider >> 8); + b[3] = (u8) (divider & 0xff); + divider = (u16) (72000 / scl_kHz); + b[4] = (u8) (divider >> 8); + b[5] = (u8) (divider & 0xff); + divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */ + b[6] = (u8) (divider >> 8); + b[7] = (u8) (divider & 0xff); + + deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", (b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz); + return dib0700_ctrl_wr(d, b, 8); +} + + int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3) { switch (clk_MHz) { @@ -459,10 +483,20 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); - if (onoff) - st->channel_state |= 1 << adap->id; - else - st->channel_state &= ~(1 << adap->id); + st->channel_state &= ~0x3; + if ((adap->stream.props.endpoint != 2) && (adap->stream.props.endpoint != 3)) { + deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint); + if (onoff) + st->channel_state |= 1 << (adap->id); + else + st->channel_state |= 1 << ~(adap->id); + } + else { + if (onoff) + st->channel_state |= 1 << (adap->stream.props.endpoint-2); + else + st->channel_state |= 1 << (3-adap->stream.props.endpoint); + } b[2] |= st->channel_state; -- cgit v1.2.2 From 4c70e074f8c496dc06798188d71be13162115d32 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 3 Jan 2011 15:33:37 -0300 Subject: [media] DiB8000: add diversity support This patch adds a set a functions which allow the handling of multiple demodulator in a diversity reception chain. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib8000.c | 814 +++++++++++++++++++++------------- drivers/media/dvb/frontends/dib8000.h | 19 + 2 files changed, 532 insertions(+), 301 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index df17b91b3250..625e4210d2dd 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -22,6 +22,7 @@ #define LAYER_C 3 #define FE_CALLBACK_TIME_NEVER 0xffffffff +#define MAX_NUMBER_OF_FRONTENDS 6 static int debug; module_param(debug, int, 0644); @@ -37,7 +38,6 @@ struct i2c_device { }; struct dib8000_state { - struct dvb_frontend fe; struct dib8000_config cfg; struct i2c_device i2c; @@ -68,6 +68,8 @@ struct dib8000_state { u8 isdbt_cfg_loaded; enum frontend_tune_state tune_state; u32 status; + + struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; }; enum dib8000_power_mode { @@ -122,111 +124,111 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) return dib8000_i2c_write16(&state->i2c, reg, val); } -static const int16_t coeff_2k_sb_1seg_dqpsk[8] = { +static const s16 coeff_2k_sb_1seg_dqpsk[8] = { (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, - (920 << 5) | 0x09 + (920 << 5) | 0x09 }; -static const int16_t coeff_2k_sb_1seg[8] = { +static const s16 coeff_2k_sb_1seg[8] = { (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f }; -static const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const s16 coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, - (-931 << 5) | 0x0f + (-931 << 5) | 0x0f }; -static const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { +static const s16 coeff_2k_sb_3seg_0dqpsk[8] = { (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, - (982 << 5) | 0x0c + (982 << 5) | 0x0c }; -static const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { +static const s16 coeff_2k_sb_3seg_1dqpsk[8] = { (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, - (-720 << 5) | 0x0d + (-720 << 5) | 0x0d }; -static const int16_t coeff_2k_sb_3seg[8] = { +static const s16 coeff_2k_sb_3seg[8] = { (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, - (-610 << 5) | 0x0a + (-610 << 5) | 0x0a }; -static const int16_t coeff_4k_sb_1seg_dqpsk[8] = { +static const s16 coeff_4k_sb_1seg_dqpsk[8] = { (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, - (-922 << 5) | 0x0d + (-922 << 5) | 0x0d }; -static const int16_t coeff_4k_sb_1seg[8] = { +static const s16 coeff_4k_sb_1seg[8] = { (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, - (-655 << 5) | 0x0a + (-655 << 5) | 0x0a }; -static const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const s16 coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, - (-958 << 5) | 0x13 + (-958 << 5) | 0x13 }; -static const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { +static const s16 coeff_4k_sb_3seg_0dqpsk[8] = { (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, - (-568 << 5) | 0x0f + (-568 << 5) | 0x0f }; -static const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { +static const s16 coeff_4k_sb_3seg_1dqpsk[8] = { (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, - (-848 << 5) | 0x13 + (-848 << 5) | 0x13 }; -static const int16_t coeff_4k_sb_3seg[8] = { +static const s16 coeff_4k_sb_3seg[8] = { (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, - (-869 << 5) | 0x13 + (-869 << 5) | 0x13 }; -static const int16_t coeff_8k_sb_1seg_dqpsk[8] = { +static const s16 coeff_8k_sb_1seg_dqpsk[8] = { (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, - (-598 << 5) | 0x10 + (-598 << 5) | 0x10 }; -static const int16_t coeff_8k_sb_1seg[8] = { +static const s16 coeff_8k_sb_1seg[8] = { (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, - (585 << 5) | 0x0f + (585 << 5) | 0x0f }; -static const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const s16 coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, - (0 << 5) | 0x14 + (0 << 5) | 0x14 }; -static const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { +static const s16 coeff_8k_sb_3seg_0dqpsk[8] = { (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, - (-877 << 5) | 0x15 + (-877 << 5) | 0x15 }; -static const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { +static const s16 coeff_8k_sb_3seg_1dqpsk[8] = { (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, - (-921 << 5) | 0x14 + (-921 << 5) | 0x14 }; -static const int16_t coeff_8k_sb_3seg[8] = { +static const s16 coeff_8k_sb_3seg[8] = { (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, - (690 << 5) | 0x14 + (690 << 5) | 0x14 }; -static const int16_t ana_fe_coeff_3seg[24] = { +static const s16 ana_fe_coeff_3seg[24] = { 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 }; -static const int16_t ana_fe_coeff_1seg[24] = { +static const s16 ana_fe_coeff_1seg[24] = { 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 }; -static const int16_t ana_fe_coeff_13seg[24] = { +static const s16 ana_fe_coeff_13seg[24] = { 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 }; static u16 fft_to_mode(struct dib8000_state *state) { u16 mode; - switch (state->fe.dtv_property_cache.transmission_mode) { + switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: mode = 1; break; @@ -249,16 +251,17 @@ static void dib8000_set_acquisition_mode(struct dib8000_state *state) dprintk("acquisition mode activated"); dib8000_write_word(state, 298, nud); } - -static int dib8000_set_output_mode(struct dib8000_state *state, int mode) +static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) { + struct dib8000_state *state = fe->demodulator_priv; + u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ outreg = 0; fifo_threshold = 1792; smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d", &state->fe, mode); + dprintk("-I- Setting output mode for demod %p to %d", &state->fe[0], mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -292,7 +295,7 @@ static int dib8000_set_output_mode(struct dib8000_state *state, int mode) break; default: - dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe); + dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]); return -EINVAL; } @@ -342,7 +345,7 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow { /* by default everything is going to be powered off */ u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, - reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; + reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; /* now, depending on the requested mode, we power on */ switch (mode) { @@ -411,8 +414,9 @@ static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_s return ret; } -static int dib8000_set_bandwidth(struct dib8000_state *state, u32 bw) +static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) { + struct dib8000_state *state = fe->demodulator_priv; u32 timf; if (bw == 0) @@ -478,7 +482,7 @@ static void dib8000_reset_pll(struct dib8000_state *state) // clk_cfg1 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | - (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | (pll->pll_range << 1) | (pll->pll_reset << 0); + (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | (pll->pll_range << 1) | (pll->pll_reset << 0); dib8000_write_word(state, 902, clk_cfg1); clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); @@ -491,7 +495,7 @@ static void dib8000_reset_pll(struct dib8000_state *state) dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); else if (state->cfg.refclksel != 0) dib8000_write_word(state, 904, - (0 << 15) | (1 << 12) | ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | (pll-> + (0 << 15) | (1 << 12) | ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | (pll-> ADClkSrc << 7) | (0 << 1)); else dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); @@ -560,7 +564,7 @@ static const u16 dib8000_defaults[] = { 0xd4c0, /*1, 32, - 0x6680 // P_corm_thres Lock algorithms configuration */ + 0x6680 // P_corm_thres Lock algorithms configuration */ 11, 80, /* set ADC level to -16 */ (1 << 13) - 825 - 117, @@ -627,10 +631,10 @@ static const u16 dib8000_defaults[] = { 1, 338, (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 - (1 << 10) | // P_ctrl_pre_freq_mode_sat=1 - (0 << 9) | // P_ctrl_pre_freq_inh=0 - (3 << 5) | // P_ctrl_pre_freq_step=3 - (1 << 0), // P_pre_freq_win_len=1 + (1 << 10) | // P_ctrl_pre_freq_mode_sat=1 + (0 << 9) | // P_ctrl_pre_freq_inh=0 + (3 << 5) | // P_ctrl_pre_freq_step=3 + (1 << 0), // P_pre_freq_win_len=1 1, 903, (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW) @@ -717,7 +721,7 @@ static int dib8000_reset(struct dvb_frontend *fe) if (dib8000_reset_gpio(state) != 0) dprintk("GPIO reset was not successful."); - if (dib8000_set_output_mode(state, OUTMODE_HIGH_Z) != 0) + if (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0) dprintk("OUTPUT_MODE could not be resetted."); state->current_agc = NULL; @@ -752,7 +756,7 @@ static int dib8000_reset(struct dvb_frontend *fe) /* unforce divstr regardless whether i2c enumeration was done or not */ dib8000_write_word(state, 1285, dib8000_read_word(state, 1285) & ~(1 << 1)); - dib8000_set_bandwidth(state, 6000); + dib8000_set_bandwidth(fe, 6000); dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib8000_sad_calib(state); @@ -778,7 +782,7 @@ static int dib8000_update_lna(struct dib8000_state *state) // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib8000_read_word(state, 390); - if (state->cfg.update_lna(&state->fe, dyn_gain)) { // LNA has changed + if (state->cfg.update_lna(state->fe[0], dyn_gain)) { // LNA has changed dib8000_restart_agc(state); return 1; } @@ -865,7 +869,7 @@ static int dib8000_agc_soft_split(struct dib8000_state *state) split_offset = state->current_agc->split.max; else split_offset = state->current_agc->split.max * - (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); + (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); dprintk("AGC split_offset: %d", split_offset); @@ -900,7 +904,7 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) case CT_AGC_STEP_0: //AGC initialization if (state->cfg.agc_control) - state->cfg.agc_control(&state->fe, 1); + state->cfg.agc_control(fe, 1); dib8000_restart_agc(state); @@ -924,7 +928,7 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) dib8000_agc_soft_split(state); if (state->cfg.agc_control) - state->cfg.agc_control(&state->fe, 0); + state->cfg.agc_control(fe, 0); *tune_state = CT_AGC_STOP; break; @@ -936,29 +940,29 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) } -static const int32_t lut_1000ln_mant[] = +static const s32 lut_1000ln_mant[] = { 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 }; -int32_t dib8000_get_adc_power(struct dvb_frontend *fe, uint8_t mode) +s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) { - struct dib8000_state *state = fe->demodulator_priv; - uint32_t ix = 0, tmp_val = 0, exp = 0, mant = 0; - int32_t val; - - val = dib8000_read32(state, 384); - /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */ - if (mode) { - tmp_val = val; - while (tmp_val >>= 1) - exp++; - mant = (val * 1000 / (1<demodulator_priv; + u32 ix = 0, tmp_val = 0, exp = 0, mant = 0; + s32 val; + + val = dib8000_read32(state, 384); + /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */ + if (mode) { + tmp_val = val; + while (tmp_val >>= 1) + exp++; + mant = (val * 1000 / (1<fe.dtv_property_cache.inversion ^ i); + dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion ^ i); - if (state->fe.dtv_property_cache.isdbt_sb_mode) { + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { //compute new dds_freq for the seg and adjust prbs int seg_offset = - state->fe.dtv_property_cache.isdbt_sb_segment_idx - (state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) - - (state->fe.dtv_property_cache.isdbt_sb_segment_count % 2); + state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) - + (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2); int clk = state->cfg.pll->internal; u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26) int dds_offset = seg_offset * segtodds; int new_dds, sub_channel; - if ((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0) // if even + if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) // if even dds_offset -= (int)(segtodds / 2); if (state->cfg.pll->ifreq == 0) { - if ((state->fe.dtv_property_cache.inversion ^ i) == 0) { + if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) { dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); new_dds = dds_offset; } else @@ -1027,35 +1031,34 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // - the segment of center frequency with an odd total number of segments // - the segment to the left of center frequency with an even total number of segments // - the segment to the right of center frequency with an even total number of segments - if ((state->fe.dtv_property_cache.delivery_system == SYS_ISDBT) && (state->fe.dtv_property_cache.isdbt_sb_mode == 1) - && - (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) - && (state->fe.dtv_property_cache.isdbt_sb_segment_idx == - ((state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - || (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe.dtv_property_cache.isdbt_sb_segment_idx == (state->fe.dtv_property_cache.isdbt_sb_segment_count / 2))) - || (((state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe.dtv_property_cache.isdbt_sb_segment_idx == - ((state->fe.dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - )) { + if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT) && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) + && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) + && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == + ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) + || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2))) + || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) + && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == + ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) + )) { new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26) } } else { - if ((state->fe.dtv_property_cache.inversion ^ i) == 0) + if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) new_dds = state->cfg.pll->ifreq - dds_offset; else new_dds = state->cfg.pll->ifreq + dds_offset; } dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff)); dib8000_write_word(state, 28, (u16) (new_dds & 0xffff)); - if (state->fe.dtv_property_cache.isdbt_sb_segment_count % 2) // if odd - sub_channel = ((state->fe.dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3; + if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) // if odd + sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3; else // if even - sub_channel = ((state->fe.dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3; + sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3; sub_channel -= 6; - if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K - || state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K + || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1 dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1 } else { @@ -1063,7 +1066,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0 } - switch (state->fe.dtv_property_cache.transmission_mode) { + switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: switch (sub_channel) { case -6: @@ -1209,7 +1212,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear } break; } - } else { // if not state->fe.dtv_property_cache.isdbt_sb_mode + } else { // if not state->fe[0]->dtv_property_cache.isdbt_sb_mode dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff)); dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff)); dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003)); @@ -1218,7 +1221,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 10, (seq << 4)); // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000); - switch (state->fe.dtv_property_cache.guard_interval) { + switch (state->fe[0]->dtv_property_cache.guard_interval) { case GUARD_INTERVAL_1_32: guard = 0; break; @@ -1238,7 +1241,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear max_constellation = DQPSK; for (i = 0; i < 3; i++) { - switch (state->fe.dtv_property_cache.layer[i].modulation) { + switch (state->fe[0]->dtv_property_cache.layer[i].modulation) { case DQPSK: constellation = 0; break; @@ -1254,7 +1257,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear break; } - switch (state->fe.dtv_property_cache.layer[i].fec) { + switch (state->fe[0]->dtv_property_cache.layer[i].fec) { case FEC_1_2: crate = 1; break; @@ -1273,26 +1276,26 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear break; } - if ((state->fe.dtv_property_cache.layer[i].interleaving > 0) && - ((state->fe.dtv_property_cache.layer[i].interleaving <= 3) || - (state->fe.dtv_property_cache.layer[i].interleaving == 4 && state->fe.dtv_property_cache.isdbt_sb_mode == 1)) - ) - timeI = state->fe.dtv_property_cache.layer[i].interleaving; + if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) && + ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) || + (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)) + ) + timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving; else timeI = 0; - dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe.dtv_property_cache.layer[i].segment_count & 0xf) << 6) | - (crate << 3) | timeI); - if (state->fe.dtv_property_cache.layer[i].segment_count > 0) { + dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) | + (crate << 3) | timeI); + if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { switch (max_constellation) { case DQPSK: case QPSK: - if (state->fe.dtv_property_cache.layer[i].modulation == QAM_16 || - state->fe.dtv_property_cache.layer[i].modulation == QAM_64) - max_constellation = state->fe.dtv_property_cache.layer[i].modulation; + if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 || + state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) + max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; break; case QAM_16: - if (state->fe.dtv_property_cache.layer[i].modulation == QAM_64) - max_constellation = state->fe.dtv_property_cache.layer[i].modulation; + if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) + max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; break; } } @@ -1303,34 +1306,34 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/ dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | - ((state->fe.dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe.dtv_property_cache. + ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache. isdbt_sb_mode & 1) << 4)); - dprintk("mode = %d ; guard = %d", mode, state->fe.dtv_property_cache.guard_interval); + dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval); /* signal optimization parameter */ - if (state->fe.dtv_property_cache.isdbt_partial_reception) { - seg_diff_mask = (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) { + seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; for (i = 1; i < 3; i++) nbseg_diff += - (state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * state->fe.dtv_property_cache.layer[i].segment_count; + (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; for (i = 0; i < nbseg_diff; i++) seg_diff_mask |= 1 << permu_seg[i + 1]; } else { for (i = 0; i < 3; i++) nbseg_diff += - (state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * state->fe.dtv_property_cache.layer[i].segment_count; + (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; for (i = 0; i < nbseg_diff; i++) seg_diff_mask |= 1 << permu_seg[i]; } dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask); state->differential_constellation = (seg_diff_mask != 0); - dib8000_set_diversity_in(&state->fe, state->diversity_onoff); + dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb - if (state->fe.dtv_property_cache.isdbt_partial_reception == 1) // 3-segments + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) // 3-segments seg_mask13 = 0x00E0; else // 1-segment seg_mask13 = 0x0040; @@ -1340,7 +1343,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // WRITE: Mode & Diff mask dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask); - if ((seg_diff_mask) || (state->fe.dtv_property_cache.isdbt_sb_mode)) + if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode)) dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); else dib8000_write_word(state, 268, (2 << 9) | 39); //init value @@ -1351,26 +1354,26 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 353, seg_mask13); // ADDR 353 -/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */ - // dib8000_write_word(state, 351, (state->fe.dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5 ); +/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */ + // dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5 ); // ---- SMALL ---- - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { - switch (state->fe.dtv_property_cache.transmission_mode) { + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg - if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK ncoeff = coeff_2k_sb_1seg_dqpsk; else // QPSK or QAM ncoeff = coeff_2k_sb_1seg; } else { // 3-segments - if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment - if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; else // QPSK or QAM on external segments ncoeff = coeff_2k_sb_3seg_0dqpsk; } else { // QPSK or QAM on central segment - if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments ncoeff = coeff_2k_sb_3seg_1dqpsk; else // QPSK or QAM on external segments ncoeff = coeff_2k_sb_3seg; @@ -1379,20 +1382,20 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear break; case TRANSMISSION_MODE_4K: - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg - if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK ncoeff = coeff_4k_sb_1seg_dqpsk; else // QPSK or QAM ncoeff = coeff_4k_sb_1seg; } else { // 3-segments - if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment - if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; } else { // QPSK or QAM on external segments ncoeff = coeff_4k_sb_3seg_0dqpsk; } } else { // QPSK or QAM on central segment - if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments ncoeff = coeff_4k_sb_3seg_1dqpsk; } else // QPSK or QAM on external segments ncoeff = coeff_4k_sb_3seg; @@ -1403,20 +1406,20 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear case TRANSMISSION_MODE_AUTO: case TRANSMISSION_MODE_8K: default: - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg - if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK ncoeff = coeff_8k_sb_1seg_dqpsk; else // QPSK or QAM ncoeff = coeff_8k_sb_1seg; } else { // 3-segments - if (state->fe.dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment - if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; } else { // QPSK or QAM on external segments ncoeff = coeff_8k_sb_3seg_0dqpsk; } } else { // QPSK or QAM on central segment - if (state->fe.dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments ncoeff = coeff_8k_sb_3seg_1dqpsk; } else // QPSK or QAM on external segments ncoeff = coeff_8k_sb_3seg; @@ -1430,22 +1433,22 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 dib8000_write_word(state, 351, - (state->fe.dtv_property_cache.isdbt_sb_mode << 9) | (state->fe.dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); + (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); // ---- COFF ---- // Carloff, the most robust - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { // Sound Broadcasting mode - use both TMCC and AC pilots + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // Sound Broadcasting mode - use both TMCC and AC pilots // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64 // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 dib8000_write_word(state, 187, - (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe.dtv_property_cache.isdbt_partial_reception & 1) << 2) - | 0x3); + (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) + | 0x3); -/* // P_small_coef_ext_enable = 1 */ -/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */ +/* // P_small_coef_ext_enable = 1 */ +/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */ - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1) if (mode == 3) @@ -1469,10 +1472,10 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 186, 80); } else { // Sound Broadcasting mode 3 seg // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15 - /* if (mode == 3) */ - /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */ - /* else */ - /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */ + /* if (mode == 3) */ + /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */ + /* else */ + /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */ dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, @@ -1509,7 +1512,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); } // ---- FFT ---- - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1 && state->fe.dtv_property_cache.isdbt_partial_reception == 0) // 1-seg + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // 1-seg dib8000_write_word(state, 178, 64); // P_fft_powrange=64 else dib8000_write_word(state, 178, 32); // P_fft_powrange=32 @@ -1518,12 +1521,12 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) */ /* if ( ( nbseg_diff>0)&&(nbseg_diff<13)) - dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */ + dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */ dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */ dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */ dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */ - if ((!state->fe.dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0)) + if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0)) dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ else dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */ @@ -1538,8 +1541,8 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */ /* offset loop parameters */ - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40); @@ -1551,8 +1554,8 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80); - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */ dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode)); @@ -1564,7 +1567,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode)); /* P_dvsy_sync_wait - reuse mode */ - switch (state->fe.dtv_property_cache.transmission_mode) { + switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_8K: mode = 256; break; @@ -1624,15 +1627,15 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear } // ---- ANA_FE ---- - if (state->fe.dtv_property_cache.isdbt_sb_mode) { - if (state->fe.dtv_property_cache.isdbt_partial_reception == 1) // 3-segments + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) // 3-segments ana_fe = ana_fe_coeff_3seg; else // 1-segment ana_fe = ana_fe_coeff_1seg; } else ana_fe = ana_fe_coeff_13seg; - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0) + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0) for (mode = 0; mode < 24; mode++) dib8000_write_word(state, 117 + mode, ana_fe[mode]); @@ -1648,11 +1651,11 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // "P_cspu_left_edge" not used => do not care // "P_cspu_right_edge" not used => do not care - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0 - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0 // 1-segment - && state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 // 1-segment + && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) { //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0 dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15 } @@ -1664,7 +1667,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // ---- TMCC ---- for (i = 0; i < 3; i++) tmcc_pow += - (((state->fe.dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe.dtv_property_cache.layer[i].segment_count); + (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count); // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); // Threshold is set at 1/4 of max power. tmcc_pow *= (1 << (9 - 2)); @@ -1678,7 +1681,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear if (state->isdbt_cfg_loaded == 0) dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */ - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) state->isdbt_cfg_loaded = 0; else state->isdbt_cfg_loaded = 1; @@ -1693,38 +1696,38 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) int slist = 0; - state->fe.dtv_property_cache.inversion = 0; - if (!state->fe.dtv_property_cache.isdbt_sb_mode) - state->fe.dtv_property_cache.layer[0].segment_count = 13; - state->fe.dtv_property_cache.layer[0].modulation = QAM_64; - state->fe.dtv_property_cache.layer[0].fec = FEC_2_3; - state->fe.dtv_property_cache.layer[0].interleaving = 0; + state->fe[0]->dtv_property_cache.inversion = 0; + if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode) + state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; + state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; + state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; + state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; //choose the right list, in sb, always do everything - if (state->fe.dtv_property_cache.isdbt_sb_mode) { - state->fe.dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - state->fe.dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; slist = 7; dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); } else { - if (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { - if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { + if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { slist = 7; dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2 } else slist = 3; } else { - if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { slist = 2; dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 } else slist = 0; } - if (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) - state->fe.dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - if (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) - state->fe.dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; dprintk("using list for autosearch : %d", slist); dib8000_set_channel(state, (unsigned char)slist, 1); @@ -1786,7 +1789,7 @@ static int dib8000_tune(struct dvb_frontend *fe) if (state == NULL) return -EINVAL; - dib8000_set_bandwidth(state, state->fe.dtv_property_cache.bandwidth_hz / 1000); + dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000); dib8000_set_channel(state, 0, 0); // restart demod @@ -1799,17 +1802,16 @@ static int dib8000_tune(struct dvb_frontend *fe) // never achieved a lock before - wait for timfreq to update if (state->timf == 0) { - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg msleep(300); else // Sound Broadcasting mode 3 seg msleep(500); } else // 13 seg msleep(200); } - //dump_reg(state); - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe.dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */ dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40); @@ -1854,26 +1856,38 @@ static int dib8000_tune(struct dvb_frontend *fe) static int dib8000_wakeup(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend; + int ret; dib8000_set_power_mode(state, DIB8000M_POWER_ALL); dib8000_set_adc_state(state, DIBX000_ADC_ON); if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) dprintk("could not start Slow ADC"); + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); + if (ret<0) + return ret; + } + return 0; } static int dib8000_sleep(struct dvb_frontend *fe) { - struct dib8000_state *st = fe->demodulator_priv; - if (1) { - dib8000_set_output_mode(st, OUTMODE_HIGH_Z); - dib8000_set_power_mode(st, DIB8000M_POWER_INTERFACE_ONLY); - return dib8000_set_adc_state(st, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(st, DIBX000_ADC_OFF); - } else { + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend; + int ret; - return 0; + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); + if (ret < 0) + return ret; } + + dib8000_set_output_mode(fe, OUTMODE_HIGH_Z); + dib8000_set_power_mode(state, DIB8000M_POWER_INTERFACE_ONLY); + return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); } enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) @@ -1891,16 +1905,40 @@ int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun } EXPORT_SYMBOL(dib8000_set_tune_state); - - - static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dib8000_state *state = fe->demodulator_priv; u16 i, val = 0; + fe_status_t stat; + u8 index_frontend, sub_index_frontend; fe->dtv_property_cache.bandwidth_hz = 6000000; + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); + if (stat&FE_HAS_SYNC) { + dprintk("TMCC lock on the slave%i", index_frontend); + /* synchronize the cache with the other frontends */ + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + for (sub_index_frontend=0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { + if (sub_index_frontend != index_frontend) { + state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; + state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; + state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; + state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; + state->fe[sub_index_frontend]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; + for (i = 0; i < 3; i++) { + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; + state->fe[sub_index_frontend]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; + } + } + } + return 0; + } + } + fe->dtv_property_cache.isdbt_sb_mode = dib8000_read_word(state, 508) & 0x1; val = dib8000_read_word(state, 570); @@ -1992,112 +2030,201 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par break; } } + + /* synchronize the cache with the other frontends */ + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode; + state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; + state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; + state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; + state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception = fe->dtv_property_cache.isdbt_partial_reception; + for (i = 0; i < 3; i++) { + state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count = fe->dtv_property_cache.layer[i].segment_count; + state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving = fe->dtv_property_cache.layer[i].interleaving; + state->fe[index_frontend]->dtv_property_cache.layer[i].fec = fe->dtv_property_cache.layer[i].fec; + state->fe[index_frontend]->dtv_property_cache.layer[i].modulation = fe->dtv_property_cache.layer[i].modulation; + } + } return 0; } static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dib8000_state *state = fe->demodulator_priv; + u8 nbr_pending, exit_condition, index_frontend; + s8 index_frontend_success = -1; int time, ret; + int time_slave = FE_CALLBACK_TIME_NEVER; + + if (state->fe[0]->dtv_property_cache.frequency == 0) { + dprintk("dib8000: must at least specify frequency "); + return 0; + } + + if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { + dprintk("dib8000: no bandwidth specified, set to default "); + state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000; + } - fe->dtv_property_cache.delivery_system = SYS_ISDBT; + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + /* synchronization of the cache */ + state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; + memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); - dib8000_set_output_mode(state, OUTMODE_HIGH_Z); + dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); + if (state->fe[index_frontend]->ops.tuner_ops.set_params) + state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend], fep); - if (fe->ops.tuner_ops.set_params) - fe->ops.tuner_ops.set_params(fe, fep); + dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); + } /* start up the AGC */ - state->tune_state = CT_AGC_START; do { - time = dib8000_agc_startup(fe); + time = dib8000_agc_startup(state->fe[0]); + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + time_slave = dib8000_agc_startup(state->fe[index_frontend]); + if (time == FE_CALLBACK_TIME_NEVER) + time = time_slave; + else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time)) + time = time_slave; + } if (time != FE_CALLBACK_TIME_NEVER) msleep(time / 10); else break; - } while (state->tune_state != CT_AGC_STOP); - - if (state->fe.dtv_property_cache.frequency == 0) { - dprintk("dib8000: must at least specify frequency "); - return 0; + exit_condition = 1; + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { + exit_condition = 0; + break; + } + } + } while (exit_condition == 0); + + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); + + if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || + (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) || + (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || + (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && + (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && + (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && + (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) || + ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && + ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || + ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && + ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { + int i = 80000; + u8 found = 0; + u8 tune_failed = 0; + + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); + dib8000_autosearch_start(state->fe[index_frontend]); + } + + do { + msleep(10); + nbr_pending = 0; + exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (((tune_failed >> index_frontend) & 0x1) == 0) { + found = dib8000_autosearch_irq(state->fe[index_frontend]); + switch (found) { + case 0: /* tune pending */ + nbr_pending++; + break; + case 2: + dprintk("autosearch succeed on the frontend%i", index_frontend); + exit_condition = 2; + index_frontend_success = index_frontend; + break; + default: + dprintk("unhandled autosearch result"); + case 1: + tune_failed |= (1 << index_frontend); + dprintk("autosearch failed for the frontend%i", index_frontend); + break; + } + } + } + + /* if all tune are done and no success, exit: tune failed */ + if ((nbr_pending == 0) && (exit_condition == 0)) + exit_condition = 1; + } while ((exit_condition == 0) && i--); + + if (exit_condition == 1) { /* tune failed */ + dprintk("tune failed"); + return 0; + } + + dprintk("tune success on frontend%i", index_frontend_success); + + dib8000_get_frontend(fe, fep); + } + + for (index_frontend=0, ret=0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = dib8000_tune(state->fe[index_frontend]); } - if (state->fe.dtv_property_cache.bandwidth_hz == 0) { - dprintk("dib8000: no bandwidth specified, set to default "); - state->fe.dtv_property_cache.bandwidth_hz = 6000000; + /* set output mode and diversity input */ + dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); + dib8000_set_diversity_in(state->fe[index_frontend-1], 1); } - state->tune_state = CT_DEMOD_START; - - if ((state->fe.dtv_property_cache.delivery_system != SYS_ISDBT) || - (state->fe.dtv_property_cache.inversion == INVERSION_AUTO) || - (state->fe.dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || - (state->fe.dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || - (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && - (state->fe.dtv_property_cache.layer[0].segment_count != 0xff) && - (state->fe.dtv_property_cache.layer[0].segment_count != 0) && - ((state->fe.dtv_property_cache.layer[0].modulation == QAM_AUTO) || - (state->fe.dtv_property_cache.layer[0].fec == FEC_AUTO))) || - (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && - (state->fe.dtv_property_cache.layer[1].segment_count != 0xff) && - (state->fe.dtv_property_cache.layer[1].segment_count != 0) && - ((state->fe.dtv_property_cache.layer[1].modulation == QAM_AUTO) || - (state->fe.dtv_property_cache.layer[1].fec == FEC_AUTO))) || - (((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && - (state->fe.dtv_property_cache.layer[2].segment_count != 0xff) && - (state->fe.dtv_property_cache.layer[2].segment_count != 0) && - ((state->fe.dtv_property_cache.layer[2].modulation == QAM_AUTO) || - (state->fe.dtv_property_cache.layer[2].fec == FEC_AUTO))) || - (((state->fe.dtv_property_cache.layer[0].segment_count == 0) || - ((state->fe.dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && - ((state->fe.dtv_property_cache.layer[1].segment_count == 0) || - ((state->fe.dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && - ((state->fe.dtv_property_cache.layer[2].segment_count == 0) || ((state->fe.dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { - int i = 800, found; - - dib8000_set_bandwidth(state, fe->dtv_property_cache.bandwidth_hz / 1000); - dib8000_autosearch_start(fe); - do { - msleep(10); - found = dib8000_autosearch_irq(fe); - } while (found == 0 && i--); - - dprintk("Frequency %d Hz, autosearch returns: %d", fep->frequency, found); - - if (found == 0 || found == 1) - return 0; // no channel found - - dib8000_get_frontend(fe, fep); - } + /* turn off the diversity of the last chip */ + dib8000_set_diversity_in(state->fe[index_frontend-1], 0); - ret = dib8000_tune(fe); + return ret; +} - /* make this a config parameter */ - dib8000_set_output_mode(state, state->cfg.output_mode); +static u16 dib8000_read_lock(struct dvb_frontend *fe) { + struct dib8000_state *state = fe->demodulator_priv; - return ret; + return dib8000_read_word(state, 568); } static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) { struct dib8000_state *state = fe->demodulator_priv; - u16 lock = dib8000_read_word(state, 568); + u16 lock_slave = 0, lock = dib8000_read_word(state, 568); + u8 index_frontend; + + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + lock_slave |= dib8000_read_lock(state->fe[index_frontend]); *stat = 0; - if ((lock >> 13) & 1) + if (((lock >> 13) & 1) || ((lock_slave >> 13) & 1)) *stat |= FE_HAS_SIGNAL; - if ((lock >> 8) & 1) /* Equal */ + if (((lock >> 8) & 1) || ((lock_slave >> 8) & 1)) /* Equal */ *stat |= FE_HAS_CARRIER; - if (((lock >> 1) & 0xf) == 0xf) /* TMCC_SYNC */ + if ((((lock >> 1) & 0xf) == 0xf) || (((lock_slave >> 1) & 0xf) == 0xf)) /* TMCC_SYNC */ *stat |= FE_HAS_SYNC; - if (((lock >> 12) & 1) && ((lock >> 5) & 7)) /* FEC MPEG */ + if ((((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) && ((lock >> 5) & 7)) /* FEC MPEG */ *stat |= FE_HAS_LOCK; - if ((lock >> 12) & 1) { + if (((lock >> 12) & 1) || ((lock_slave >> 12) & 1)) { lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ if (lock & 0x01) *stat |= FE_HAS_VITERBI; @@ -2131,44 +2258,120 @@ static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) { struct dib8000_state *state = fe->demodulator_priv; - u16 val = dib8000_read_word(state, 390); - *strength = 65535 - val; + u8 index_frontend; + u16 val; + + *strength = 0; + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; + } + + val = 65535 - dib8000_read_word(state, 390); + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; return 0; } -static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) +static u32 dib8000_get_snr(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; + u32 n, s, exp; u16 val; - s32 signal_mant, signal_exp, noise_mant, noise_exp; - u32 result = 0; val = dib8000_read_word(state, 542); - noise_mant = (val >> 6) & 0xff; - noise_exp = (val & 0x3f); + n = (val >> 6) & 0xff; + exp = (val & 0x3f); + if ((exp & 0x20) != 0) + exp -= 0x40; + n <<= exp+16; val = dib8000_read_word(state, 543); - signal_mant = (val >> 6) & 0xff; - signal_exp = (val & 0x3f); + s = (val >> 6) & 0xff; + exp = (val & 0x3f); + if ((exp & 0x20) != 0) + exp -= 0x40; + s <<= exp+16; + + if (n > 0) { + u32 t = (s/n) << 16; + return t + ((s << 16) - n*t) / n; + } + return 0xffffffff; +} + +static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend; + u32 snr_master; - if ((noise_exp & 0x20) != 0) - noise_exp -= 0x40; - if ((signal_exp & 0x20) != 0) - signal_exp -= 0x40; + snr_master = dib8000_get_snr(fe); + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + snr_master += dib8000_get_snr(state->fe[index_frontend]); - if (signal_mant != 0) - result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant); - else - result = intlog10(2) * 10 * signal_exp - 100; - if (noise_mant != 0) - result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant); + if (snr_master != 0) { + snr_master = 10*intlog10(snr_master>>16); + *snr = snr_master / ((1 << 24) / 10); + } else - result -= intlog10(2) * 10 * noise_exp - 100; + *snr = 0; - *snr = result / ((1 << 24) / 10); return 0; } +int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { + dprintk("set slave fe %p to index %i", fe_slave, index_frontend); + state->fe[index_frontend] = fe_slave; + return 0; + } + + dprintk("too many slave frontend"); + return -ENOMEM; +} +EXPORT_SYMBOL(dib8000_set_slave_frontend); + +int dib8000_remove_slave_frontend(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend != 1) { + dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); + state->fe[index_frontend] = NULL; + return 0; + } + + dprintk("no frontend to be removed"); + return -ENODEV; +} +EXPORT_SYMBOL(dib8000_remove_slave_frontend); + +struct dvb_frontend * dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ + struct dib8000_state *state = fe->demodulator_priv; + + if (slave_index >= MAX_NUMBER_OF_FRONTENDS) + return NULL; + return state->fe[slave_index]; +} +EXPORT_SYMBOL(dib8000_get_slave_frontend); + + int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) { int k = 0; @@ -2227,7 +2430,13 @@ static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_fron static void dib8000_release(struct dvb_frontend *fe) { struct dib8000_state *st = fe->demodulator_priv; + u8 index_frontend; + + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) + dvb_frontend_detach(st->fe[index_frontend]); + dibx000_exit_i2c_master(&st->i2c_master); + kfree(st->fe[0]); kfree(st); } @@ -2242,19 +2451,19 @@ EXPORT_SYMBOL(dib8000_get_i2c_master); int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { struct dib8000_state *st = fe->demodulator_priv; - u16 val = dib8000_read_word(st, 299) & 0xffef; - val |= (onoff & 0x1) << 4; + u16 val = dib8000_read_word(st, 299) & 0xffef; + val |= (onoff & 0x1) << 4; - dprintk("pid filter enabled %d", onoff); - return dib8000_write_word(st, 299, val); + dprintk("pid filter enabled %d", onoff); + return dib8000_write_word(st, 299, val); } EXPORT_SYMBOL(dib8000_pid_filter_ctrl); int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib8000_state *st = fe->demodulator_priv; - dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); - return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); + dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); } EXPORT_SYMBOL(dib8000_pid_filter); @@ -2298,6 +2507,9 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); if (state == NULL) return NULL; + fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); + if (fe == NULL) + return NULL; memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); state->i2c.adap = i2c_adap; @@ -2311,9 +2523,9 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s if ((state->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (state->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) state->cfg.output_mode = OUTMODE_MPEG2_FIFO; - fe = &state->fe; + state->fe[0] = fe; fe->demodulator_priv = state; - memcpy(&state->fe.ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->fe[0]->ops, &dib8000_ops, sizeof(struct dvb_frontend_ops)); state->timf_default = cfg->pll->timf; diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index e0a9ded11df4..558b7e83c722 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h @@ -50,6 +50,9 @@ extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_st extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); +extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); +extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe); +extern struct dvb_frontend * dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); #else static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) { @@ -111,6 +114,22 @@ static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return 0; } +static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +int dib8000_remove_slave_frontend(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct dvb_frontend * dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} #endif #endif -- cgit v1.2.2 From b994d19268756b640ccc76f0b0d47ee13c0f8af9 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 3 Jan 2011 15:39:35 -0300 Subject: [media] DiBx000: add addition i2c-interface names This patch adds the possibitity to use different I2C-ports to talk to slave-devices than the standard ones. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dibx000_common.c | 284 +++++++++++++++++++++++++-- drivers/media/dvb/frontends/dibx000_common.h | 23 ++- 2 files changed, 285 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 2311c0a3406c..9bd95a978a1c 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -17,9 +17,144 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) struct i2c_msg msg = { .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4 }; + return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } +static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) +{ + u8 wb[2] = { reg >> 8, reg & 0xff }; + u8 rb[2]; + struct i2c_msg msg[2] = { + {.addr = mst->i2c_addr,.flags = 0,.buf = wb,.len = 2}, + {.addr = mst->i2c_addr,.flags = I2C_M_RD,.buf = rb,.len = 2}, + }; + + if (i2c_transfer(mst->i2c_adap, msg, 2) != 2) + dprintk("i2c read error on %d", reg); + + return (rb[0] << 8) | rb[1]; +} + +static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) +{ + int i = 100; // max_i2c_polls; + u16 status; + + while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0); + + /* i2c timed out */ + if (i == 0) + return -EREMOTEIO; + + /* no acknowledge */ + if ((status & 0x0080) == 0) + return -EREMOTEIO; + + return 0; +} + +static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop) +{ + u16 data; + u16 da; + u16 i; + u16 txlen = msg->len, len; + const u8 *b = msg->buf; + + while (txlen) { + dibx000_read_word(mst, mst->base_reg + 2); // reset fifo ptr + + len = txlen > 8 ? 8 : txlen; + for (i = 0; i < len; i += 2) { + data = *b++ << 8; + if (i+1 < len) + data |= *b++; + dibx000_write_word(mst, mst->base_reg, data); + } + da = (((u8) (msg->addr)) << 9) | // addr + (1 << 8) | // master + (1 << 7) | // rq + (0 << 6) | // stop + (0 << 5) | // start + ((len & 0x7) << 2) | // nb 8 bytes == 0 here + (0 << 1) | // rw + (0 << 0); // irqen + + if (txlen == msg->len) + da |= 1 << 5; /* start */ + + if (txlen-len == 0 && stop) + da |= 1 << 6; /* stop */ + + dibx000_write_word(mst, mst->base_reg+1, da); + + if (dibx000_is_i2c_done(mst) != 0) + return -EREMOTEIO; + txlen -= len; + } + + return 0; +} + +static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg) +{ + u16 da; + u8 *b = msg->buf; + u16 rxlen = msg->len, len; + + while (rxlen) { + len = rxlen > 8 ? 8 : rxlen; + da = (((u8) (msg->addr)) << 9) | // addr + (1 << 8) | // master + (1 << 7) | // rq + (0 << 6) | // stop + (0 << 5) | // start + ((len & 0x7) << 2) | // nb + (1 << 1) | // rw + (0 << 0); // irqen + + if (rxlen == msg->len) + da |= 1 << 5; /* start */ + + if (rxlen-len == 0) + da |= 1 << 6; /* stop */ + dibx000_write_word(mst, mst->base_reg+1, da); + + if (dibx000_is_i2c_done(mst) != 0) + return -EREMOTEIO; + + rxlen -= len; + + while (len) { + da = dibx000_read_word(mst, mst->base_reg); + *b++ = (da >> 8) & 0xff; + len--; + if (len >= 1) { + *b++ = da & 0xff; + len--; + } + } + } + + return 0; +} + +int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed) +{ + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + + if (mst->device_rev < DIB7000MC && speed < 235) + speed = 235; + return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed)); + +} +EXPORT_SYMBOL(dibx000_i2c_set_speed); + +static u32 dibx000_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf) @@ -32,6 +167,66 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, return 0; } +static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int msg_index; + int ret = 0; + + dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2); + for (msg_index = 0; msg_indexi2c_addr; + m[0].buf = tx_open; + m[0].len = 4; + + memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); + + dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0); + m[num + 1].addr = mst->i2c_addr; + m[num + 1].buf = tx_close; + m[num + 1].len = 4; + + return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO; } +static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { + .master_xfer = dibx000_i2c_gated_gpio67_xfer, + .functionality = dibx000_i2c_func, +}; + static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { @@ -91,8 +312,8 @@ static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { }; struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, - enum dibx000_i2c_interface intf, - int gating) + enum dibx000_i2c_interface intf, + int gating) { struct i2c_adapter *i2c = NULL; @@ -101,6 +322,18 @@ struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, if (gating) i2c = &mst->gated_tuner_i2c_adap; break; + case DIBX000_I2C_INTERFACE_GPIO_1_2: + if (!gating) + i2c = &mst->master_i2c_adap_gpio12; + break; + case DIBX000_I2C_INTERFACE_GPIO_3_4: + if (!gating) + i2c = &mst->master_i2c_adap_gpio34; + break; + case DIBX000_I2C_INTERFACE_GPIO_6_7: + if (gating) + i2c = &mst->master_i2c_adap_gpio67; + break; default: printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); break; @@ -126,8 +359,8 @@ void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst) EXPORT_SYMBOL(dibx000_reset_i2c_master); static int i2c_adapter_init(struct i2c_adapter *i2c_adap, - struct i2c_algorithm *algo, const char *name, - struct dibx000_i2c_master *mst) + struct i2c_algorithm *algo, const char *name, + struct dibx000_i2c_master *mst) { strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); i2c_adap->algo = algo; @@ -139,7 +372,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, } int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, - struct i2c_adapter *i2c_adap, u8 i2c_addr) + struct i2c_adapter *i2c_adap, u8 i2c_addr) { u8 tx[4]; struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; @@ -153,11 +386,33 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, else mst->base_reg = 768; + mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent; + if (i2c_adapter_init + (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, + "DiBX000 tuner I2C bus", mst) != 0) + printk(KERN_ERR + "DiBX000: could not initialize the tuner i2c_adapter\n"); + + mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent; + if (i2c_adapter_init + (&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo, + "DiBX000 master GPIO12 I2C bus", mst) != 0) + printk(KERN_ERR + "DiBX000: could not initialize the master i2c_adapter\n"); + + mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent; + if (i2c_adapter_init + (&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo, + "DiBX000 master GPIO34 I2C bus", mst) != 0) + printk(KERN_ERR + "DiBX000: could not initialize the master i2c_adapter\n"); + + mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent; if (i2c_adapter_init - (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, - "DiBX000 tuner I2C bus", mst) != 0) + (&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo, + "DiBX000 master GPIO67 I2C bus", mst) != 0) printk(KERN_ERR - "DiBX000: could not initialize the tuner i2c_adapter\n"); + "DiBX000: could not initialize the master i2c_adapter\n"); /* initialize the i2c-master by closing the gate */ dibx000_i2c_gate_ctrl(mst, tx, 0, 0); @@ -170,16 +425,19 @@ EXPORT_SYMBOL(dibx000_init_i2c_master); void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) { i2c_del_adapter(&mst->gated_tuner_i2c_adap); + i2c_del_adapter(&mst->master_i2c_adap_gpio12); + i2c_del_adapter(&mst->master_i2c_adap_gpio34); + i2c_del_adapter(&mst->master_i2c_adap_gpio67); } EXPORT_SYMBOL(dibx000_exit_i2c_master); u32 systime(void) { - struct timespec t; + struct timespec t; - t = current_kernel_time(); - return (t.tv_sec * 10000) + (t.tv_nsec / 100000); + t = current_kernel_time(); + return (t.tv_sec * 10000) + (t.tv_nsec / 100000); } EXPORT_SYMBOL(systime); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 4f5d141a308d..b7ad066b7e52 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -4,7 +4,8 @@ enum dibx000_i2c_interface { DIBX000_I2C_INTERFACE_TUNER = 0, DIBX000_I2C_INTERFACE_GPIO_1_2 = 1, - DIBX000_I2C_INTERFACE_GPIO_3_4 = 2 + DIBX000_I2C_INTERFACE_GPIO_3_4 = 2, + DIBX000_I2C_INTERFACE_GPIO_6_7 = 3 }; struct dibx000_i2c_master { @@ -17,8 +18,11 @@ struct dibx000_i2c_master { enum dibx000_i2c_interface selected_interface; -// struct i2c_adapter tuner_i2c_adap; +// struct i2c_adapter tuner_i2c_adap; struct i2c_adapter gated_tuner_i2c_adap; + struct i2c_adapter master_i2c_adap_gpio12; + struct i2c_adapter master_i2c_adap_gpio34; + struct i2c_adapter master_i2c_adap_gpio67; struct i2c_adapter *i2c_adap; u8 i2c_addr; @@ -27,14 +31,15 @@ struct dibx000_i2c_master { }; extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, - u16 device_rev, struct i2c_adapter *i2c_adap, - u8 i2c_addr); + u16 device_rev, struct i2c_adapter *i2c_adap, + u8 i2c_addr); extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master - *mst, - enum dibx000_i2c_interface - intf, int gating); + *mst, + enum dibx000_i2c_interface + intf, int gating); extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); +extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed); extern u32 systime(void); @@ -42,10 +47,10 @@ extern u32 systime(void); #define BAND_UHF 0x02 #define BAND_VHF 0x04 #define BAND_SBAND 0x08 -#define BAND_FM 0x10 +#define BAND_FM 0x10 #define BAND_CBAND 0x20 -#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \ +#define BAND_OF_FREQUENCY(freq_kHz) ( (freq_kHz) <= 170000 ? BAND_CBAND : \ (freq_kHz) <= 115000 ? BAND_FM : \ (freq_kHz) <= 250000 ? BAND_VHF : \ (freq_kHz) <= 863000 ? BAND_UHF : \ -- cgit v1.2.2 From 28fafca78797be701208c0880ec1c79ffa267f9d Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Tue, 4 Jan 2011 04:27:11 -0300 Subject: [media] DiB0090: misc improvements This patch adds several performance improvements and prepares the usage of firmware-based devices. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib0090.c | 1650 ++++++++++++++++++++++++++------- drivers/media/dvb/frontends/dib0090.h | 31 + 2 files changed, 1346 insertions(+), 335 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index 65240b7801e8..0e87a0bdf7ab 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c @@ -45,6 +45,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); } \ } while (0) +#define CONFIG_SYS_DVBT #define CONFIG_SYS_ISDBT #define CONFIG_BAND_CBAND #define CONFIG_BAND_VHF @@ -76,6 +77,34 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define EN_SBD 0x44E9 #define EN_CAB 0x88E9 +/* Calibration defines */ +#define DC_CAL 0x1 +#define WBD_CAL 0x2 +#define TEMP_CAL 0x4 +#define CAPTRIM_CAL 0x8 + +#define KROSUS_PLL_LOCKED 0x800 +#define KROSUS 0x2 + +/* Use those defines to identify SOC version */ +#define SOC 0x02 +#define SOC_7090_P1G_11R1 0x82 +#define SOC_7090_P1G_21R1 0x8a +#define SOC_8090_P1G_11R1 0x86 +#define SOC_8090_P1G_21R1 0x8e + +/* else use thos ones to check */ +#define P1A_B 0x0 +#define P1C 0x1 +#define P1D_E_F 0x3 +#define P1G 0x7 +#define P1G_21R2 0xf + +#define MP001 0x1 /* Single 9090/8096 */ +#define MP005 0x4 /* Single Sband */ +#define MP008 0x6 /* Dual diversity VHF-UHF-LBAND */ +#define MP009 0x7 /* Dual diversity 29098 CBAND-UHF-LBAND-SBAND */ + #define pgm_read_word(w) (*w) struct dc_calibration; @@ -84,7 +113,7 @@ struct dib0090_tuning { u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ u8 switch_trim; u8 lna_tune; - u8 lna_bias; + u16 lna_bias; u16 v2i; u16 mix; u16 load; @@ -99,13 +128,19 @@ struct dib0090_pll { u8 topresc; }; +struct dib0090_identity { + u8 version; + u8 product; + u8 p1g; + u8 in_soc; +}; + struct dib0090_state { struct i2c_adapter *i2c; struct dvb_frontend *fe; const struct dib0090_config *config; u8 current_band; - u16 revision; enum frontend_tune_state tune_state; u32 current_rf; @@ -143,15 +178,34 @@ struct dib0090_state { u8 tuner_is_tuned; u8 agc_freeze; - u8 reset; + struct dib0090_identity identity; + + u32 rf_request; + u8 current_standard; + + u8 calibrate; + u32 rest; + u16 bias; + s16 temperature; + + u8 wbd_calibration_gain; + const struct dib0090_wbd_slope *current_wbd_table; + u16 wbdmux; +}; + +struct dib0090_fw_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + struct dib0090_identity identity; + const struct dib0090_config *config; }; static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) { u8 b[2]; struct i2c_msg msg[2] = { - {.addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1}, - {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2}, + {.addr = state->config->i2c_address,.flags = 0,.buf = ®,.len = 1}, + {.addr = state->config->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2}, }; if (i2c_transfer(state->i2c, msg, 2) != 2) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); @@ -163,7 +217,29 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) { u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; - struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 }; + struct i2c_msg msg = {.addr = state->config->i2c_address,.flags = 0,.buf = b,.len = 3 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) +{ + u8 b[2]; + struct i2c_msg msg = {.addr = reg,.flags = I2C_M_RD,.buf = b,.len = 2 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C read failed\n"); + return 0; + } + return (b[0] << 8) | b[1]; +} + +static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) +{ + u8 b[2] = { val >> 8, val & 0xff }; + struct i2c_msg msg = {.addr = reg,.flags = 0,.buf = b,.len = 2 }; if (i2c_transfer(state->i2c, &msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); return -EREMOTEIO; @@ -183,89 +259,329 @@ static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, } while (--c); } -static u16 dib0090_identify(struct dvb_frontend *fe) +static int dib0090_identify(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; u16 v; + struct dib0090_identity *identity = &state->identity; v = dib0090_read_reg(state, 0x1a); -#ifdef FIRMWARE_FIREFLY - /* pll is not locked locked */ - if (!(v & 0x800)) - dprintk("FE%d : Identification : pll is not yet locked", fe->id); -#endif + identity->p1g = 0; + identity->in_soc = 0; + + dprintk("Tuner identification (Version = 0x%04x)", v); /* without PLL lock info */ - v &= 0x3ff; - dprintk("P/V: %04x:", v); + v &= ~KROSUS_PLL_LOCKED; - if ((v >> 8) & 0xf) - dprintk("FE%d : Product ID = 0x%x : KROSUS", fe->id, (v >> 8) & 0xf); - else - return 0xff; - - v &= 0xff; - if (((v >> 5) & 0x7) == 0x1) - dprintk("FE%d : MP001 : 9090/8096", fe->id); - else if (((v >> 5) & 0x7) == 0x4) - dprintk("FE%d : MP005 : Single Sband", fe->id); - else if (((v >> 5) & 0x7) == 0x6) - dprintk("FE%d : MP008 : diversity VHF-UHF-LBAND", fe->id); - else if (((v >> 5) & 0x7) == 0x7) - dprintk("FE%d : MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND", fe->id); - else - return 0xff; - - /* revision only */ - if ((v & 0x1f) == 0x3) - dprintk("FE%d : P1-D/E/F detected", fe->id); - else if ((v & 0x1f) == 0x1) - dprintk("FE%d : P1C detected", fe->id); - else if ((v & 0x1f) == 0x0) { -#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT - dprintk("FE%d : P1-A/B detected: using previous driver - support will be removed soon", fe->id); - dib0090_p1b_register(fe); -#else - dprintk("FE%d : P1-A/B detected: driver is deactivated - not available", fe->id); - return 0xff; -#endif + identity->version = v & 0xff; + identity->product = (v >> 8) & 0xf; + + if (identity->product != KROSUS) + goto identification_error; + + if ((identity->version & 0x3) == SOC) { + identity->in_soc = 1; + switch (identity->version) { + case SOC_8090_P1G_11R1: + dprintk("SOC 8090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_8090_P1G_21R1: + dprintk("SOC 8090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_11R1: + dprintk("SOC 7090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_21R1: + dprintk("SOC 7090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + default: + goto identification_error; + } + } else { + switch ((identity->version >> 5) & 0x7) { + case MP001: + dprintk("MP001 : 9090/8096"); + break; + case MP005: + dprintk("MP005 : Single Sband"); + break; + case MP008: + dprintk("MP008 : diversity VHF-UHF-LBAND"); + break; + case MP009: + dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); + break; + default: + goto identification_error; + } + + switch (identity->version & 0x1f) { + case P1G_21R2: + dprintk("P1G_21R2 detected"); + identity->p1g = 1; + break; + case P1G: + dprintk("P1G detected"); + identity->p1g = 1; + break; + case P1D_E_F: + dprintk("P1D/E/F detected"); + break; + case P1C: + dprintk("P1C detected"); + break; + case P1A_B: + dprintk("P1-A/B detected: driver is deactivated - not available"); + goto identification_error; + break; + default: + goto identification_error; + } } - return v; + return 0; + + identification_error: + return -EIO; +} + +static int dib0090_fw_identify(struct dvb_frontend *fe) +{ + struct dib0090_fw_state *state = fe->tuner_priv; + struct dib0090_identity *identity = &state->identity; + + u16 v = dib0090_fw_read_reg(state, 0x1a); + identity->p1g = 0; + identity->in_soc = 0; + + dprintk("FE: Tuner identification (Version = 0x%04x)", v); + + /* without PLL lock info */ + v &= ~KROSUS_PLL_LOCKED; + + identity->version = v & 0xff; + identity->product = (v >> 8) & 0xf; + + if (identity->product != KROSUS) + goto identification_error; + + //From the SOC the version definition has changed + + if ((identity->version & 0x3) == SOC) { + identity->in_soc = 1; + switch (identity->version) { + case SOC_8090_P1G_11R1: + dprintk("SOC 8090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_8090_P1G_21R1: + dprintk("SOC 8090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_11R1: + dprintk("SOC 7090 P1-G11R1 Has been detected"); + identity->p1g = 1; + break; + case SOC_7090_P1G_21R1: + dprintk("SOC 7090 P1-G21R1 Has been detected"); + identity->p1g = 1; + break; + default: + goto identification_error; + } + } else { + switch ((identity->version >> 5) & 0x7) { + case MP001: + dprintk("MP001 : 9090/8096"); + break; + case MP005: + dprintk("MP005 : Single Sband"); + break; + case MP008: + dprintk("MP008 : diversity VHF-UHF-LBAND"); + break; + case MP009: + dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); + break; + default: + goto identification_error; + } + + switch (identity->version & 0x1f) { + case P1G_21R2: + dprintk("P1G_21R2 detected"); + identity->p1g = 1; + break; + case P1G: + dprintk("P1G detected"); + identity->p1g = 1; + break; + case P1D_E_F: + dprintk("P1D/E/F detected"); + break; + case P1C: + dprintk("P1C detected"); + break; + case P1A_B: + dprintk("P1-A/B detected: driver is deactivated - not available"); + goto identification_error; + break; + default: + goto identification_error; + } + } + + return 0; + + identification_error: + return -EIO;; } static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) { struct dib0090_state *state = fe->tuner_priv; + u16 PllCfg, i, v; HARD_RESET(state); - dib0090_write_reg(state, 0x24, EN_PLL); + dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ - /* adcClkOutRatio=8->7, release reset */ - dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); + if (!cfg->in_soc) { + /* adcClkOutRatio=8->7, release reset */ + dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); + if (cfg->clkoutdrive != 0) + dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) + | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); + else + dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) + | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); + } + + /* Read Pll current config * */ + PllCfg = dib0090_read_reg(state, 0x21); + + /** Reconfigure PLL if current setting is different from default setting **/ + if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && (!cfg->in_soc) + && !cfg->io.pll_bypass) { + + /* Set Bypass mode */ + PllCfg |= (1 << 15); + dib0090_write_reg(state, 0x21, PllCfg); + + /* Set Reset Pll */ + PllCfg &= ~(1 << 13); + dib0090_write_reg(state, 0x21, PllCfg); + + /*** Set new Pll configuration in bypass and reset state ***/ + PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv); + dib0090_write_reg(state, 0x21, PllCfg); + + /* Remove Reset Pll */ + PllCfg |= (1 << 13); + dib0090_write_reg(state, 0x21, PllCfg); + + /*** Wait for PLL lock ***/ + i = 100; + do { + v = !!(dib0090_read_reg(state, 0x1a) & 0x800); + if (v) + break; + } while (--i); + + if (i == 0) { + dprintk("Pll: Unable to lock Pll"); + return; + } + + /* Finally Remove Bypass mode */ + PllCfg &= ~(1 << 15); + dib0090_write_reg(state, 0x21, PllCfg); + } + + if (cfg->io.pll_bypass) { + PllCfg |= (cfg->io.pll_bypass << 15); + dib0090_write_reg(state, 0x21, PllCfg); + } +} + +static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) +{ + struct dib0090_fw_state *state = fe->tuner_priv; + u16 PllCfg; + u16 v; + int i; + + dprintk("fw reset digital"); + HARD_RESET(state); + + dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); + dib0090_fw_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ + + dib0090_fw_write_reg(state, 0x20, + ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (cfg->data_tx_drv << 4) | cfg->ls_cfg_pad_drv); + + v = (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 9) | (0 << 8) | (cfg->clkouttobamse << 4) | (0 << 2) | (0); if (cfg->clkoutdrive != 0) - dib0090_write_reg(state, 0x23, - (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (cfg->clkoutdrive << 5) | (cfg-> - clkouttobamse - << 4) | (0 - << - 2) - | (0)); + v |= cfg->clkoutdrive << 5; else - dib0090_write_reg(state, 0x23, - (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (7 << 5) | (cfg-> - clkouttobamse << 4) | (0 - << - 2) - | (0)); + v |= 7 << 5; + + v |= 2 << 10; + dib0090_fw_write_reg(state, 0x23, v); + + /* Read Pll current config * */ + PllCfg = dib0090_fw_read_reg(state, 0x21); + + /** Reconfigure PLL if current setting is different from default setting **/ + if ((PllCfg & 0x1FFF) != ((cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)) && !cfg->io.pll_bypass) { - /* enable pll, de-activate reset, ratio: 2/1 = 60MHz */ - dib0090_write_reg(state, 0x21, - (cfg->io.pll_bypass << 15) | (1 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)); + /* Set Bypass mode */ + PllCfg |= (1 << 15); + dib0090_fw_write_reg(state, 0x21, PllCfg); + /* Set Reset Pll */ + PllCfg &= ~(1 << 13); + dib0090_fw_write_reg(state, 0x21, PllCfg); + + /*** Set new Pll configuration in bypass and reset state ***/ + PllCfg = (1 << 15) | (0 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv); + dib0090_fw_write_reg(state, 0x21, PllCfg); + + /* Remove Reset Pll */ + PllCfg |= (1 << 13); + dib0090_fw_write_reg(state, 0x21, PllCfg); + + /*** Wait for PLL lock ***/ + i = 100; + do { + v = !!(dib0090_fw_read_reg(state, 0x1a) & 0x800); + if (v) + break; + } while (--i); + + if (i == 0) { + dprintk("Pll: Unable to lock Pll"); + return -EIO; + } + + /* Finally Remove Bypass mode */ + PllCfg &= ~(1 << 15); + dib0090_fw_write_reg(state, 0x21, PllCfg); + } + + if (cfg->io.pll_bypass) { + PllCfg |= (cfg->io.pll_bypass << 15); + dib0090_fw_write_reg(state, 0x21, PllCfg); + } + + return dib0090_fw_identify(fe); } static int dib0090_wakeup(struct dvb_frontend *fe) @@ -273,6 +589,9 @@ static int dib0090_wakeup(struct dvb_frontend *fe) struct dib0090_state *state = fe->tuner_priv; if (state->config->sleep) state->config->sleep(fe, 0); + + /* enable dataTX in case we have been restarted in the wrong moment */ + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); return 0; } @@ -292,8 +611,75 @@ void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) else dib0090_write_reg(state, 0x04, 1); } + EXPORT_SYMBOL(dib0090_dcc_freq); +static const u16 bb_ramp_pwm_normal_socs[] = { + 550, /* max BB gain in 10th of dB */ + (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ + 440, + (4 << 9) | 0, /* BB_RAMP3 = 26dB */ + (0 << 9) | 208, /* BB_RAMP4 */ + (4 << 9) | 208, /* BB_RAMP5 = 29dB */ + (0 << 9) | 440, /* BB_RAMP6 */ +}; + +static const u16 rf_ramp_pwm_cband_7090[] = { + 280, /* max RF gain in 10th of dB */ + 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 504, /* ramp_max = maximum X used on the ramp */ + (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */ + (0 << 10) | 504, /* RF_RAMP6, LNA 1 */ + (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */ + (0 << 10) | 364, /* RF_RAMP8, LNA 2 */ + (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */ + (0 << 10) | 228, /* GAIN_4_2, LNA 3 */ + (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ + (0 << 10) | 109, /* RF_RAMP4, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_cband_8090[] = { + 345, /* max RF gain in 10th of dB */ + 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 1000, /* ramp_max = maximum X used on the ramp */ + (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */ + (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */ + (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */ + (0 << 10) | 772, /* RF_RAMP6, LNA 2 */ + (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */ + (0 << 10) | 496, /* RF_RAMP8, LNA 3 */ + (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */ + (0 << 10) | 200, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_uhf_7090[] = { + 407, /* max RF gain in 10th of dB */ + 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 529, /* ramp_max = maximum X used on the ramp */ + (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ + (0 << 10) | 176, /* RF_RAMP4, LNA 1 */ + (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */ + (0 << 10) | 529, /* RF_RAMP6, LNA 2 */ + (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */ + (0 << 10) | 400, /* RF_RAMP8, LNA 3 */ + (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */ + (0 << 10) | 316, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_uhf_8090[] = { + 388, /* max RF gain in 10th of dB */ + 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 1008, /* ramp_max = maximum X used on the ramp */ + (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ + (0 << 10) | 369, /* RF_RAMP4, LNA 1 */ + (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */ + (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */ + (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */ + (0 << 10) | 809, /* RF_RAMP8, LNA 3 */ + (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */ + (0 << 10) | 659, /* GAIN_4_2, LNA 4 */ +}; + static const u16 rf_ramp_pwm_cband[] = { 0, /* max RF gain in 10th of dB */ 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ @@ -326,6 +712,16 @@ static const u16 rf_ramp_uhf[] = { 0, 0, 127, /* CBAND : 0.0 dB */ }; +static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */ +{ + 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */ + 84, 314, 127, /* LNA1 */ + 80, 230, 255, /* LNA2 */ + 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */ + 70, 70, 127, /* LNA4 */ + 0, 0, 127, /* CBAND */ +}; + static const u16 rf_ramp_cband[] = { 332, /* max RF gain in 10th of dB */ 132, 252, 127, /* LNA1, dB */ @@ -380,8 +776,8 @@ static const u16 bb_ramp_pwm_normal[] = { }; struct slope { - int16_t range; - int16_t slope; + s16 range; + s16 slope; }; static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val) { @@ -597,19 +993,40 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) #endif #ifdef CONFIG_BAND_CBAND if (state->current_band == BAND_CBAND) { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + if (state->identity.in_soc) { + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); + if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090); + else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); + } else { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } } else #endif #ifdef CONFIG_BAND_VHF if (state->current_band == BAND_VHF) { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + if (state->identity.in_soc) { + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); + //dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf_socs); /* TODO */ + } else { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } } else #endif { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + if (state->identity.in_soc) { + if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090); + else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); + } else { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } } if (state->rf_ramp[0] != 0) @@ -617,11 +1034,22 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) else dib0090_write_reg(state, 0x32, (0 << 11)); + dib0090_write_reg(state, 0x04, 0x01); dib0090_write_reg(state, 0x39, (1 << 10)); } } + EXPORT_SYMBOL(dib0090_pwm_gain_reset); +static u32 dib0090_get_slow_adc_val(struct dib0090_state *state) +{ + u16 adc_val = dib0090_read_reg(state, 0x1d); + if (state->identity.in_soc) { + adc_val >>= 2; + } + return adc_val; +} + int dib0090_gain_control(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; @@ -643,18 +1071,21 @@ int dib0090_gain_control(struct dvb_frontend *fe) } else #endif #ifdef CONFIG_BAND_VHF - if (state->current_band == BAND_VHF) { + if (state->current_band == BAND_VHF && !state->identity.p1g) { dib0090_set_rframp(state, rf_ramp_vhf); dib0090_set_bbramp(state, bb_ramp_boost); } else #endif #ifdef CONFIG_BAND_CBAND - if (state->current_band == BAND_CBAND) { + if (state->current_band == BAND_CBAND && !state->identity.p1g) { dib0090_set_rframp(state, rf_ramp_cband); dib0090_set_bbramp(state, bb_ramp_boost); } else #endif - { + if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) { + dib0090_set_rframp(state, rf_ramp_cband_broadmatching); + dib0090_set_bbramp(state, bb_ramp_boost); + } else { dib0090_set_rframp(state, rf_ramp_uhf); dib0090_set_bbramp(state, bb_ramp_boost); } @@ -669,17 +1100,25 @@ int dib0090_gain_control(struct dvb_frontend *fe) *tune_state = CT_AGC_STEP_0; } else if (!state->agc_freeze) { - s16 wbd; + s16 wbd = 0, i, cnt; int adc; - wbd_val = dib0090_read_reg(state, 0x1d); + wbd_val = dib0090_get_slow_adc_val(state); - /* read and calc the wbd power */ - wbd = dib0090_wbd_to_db(state, wbd_val); + if (*tune_state == CT_AGC_STEP_0) + cnt = 5; + else + cnt = 1; + + for (i = 0; i < cnt; i++) { + wbd_val = dib0090_get_slow_adc_val(state); + wbd += dib0090_wbd_to_db(state, wbd_val); + } + wbd /= cnt; wbd_error = state->wbd_target - wbd; if (*tune_state == CT_AGC_STEP_0) { - if (wbd_error < 0 && state->rf_gain_limit > 0) { + if (wbd_error < 0 && state->rf_gain_limit > 0 && !state->identity.p1g) { #ifdef CONFIG_BAND_CBAND /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */ u8 ltg2 = (state->rf_lt_def >> 10) & 0x7; @@ -700,39 +1139,39 @@ int dib0090_gain_control(struct dvb_frontend *fe) adc_error = (s16) (((s32) ADC_TARGET) - adc); #ifdef CONFIG_STANDARD_DAB if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) - adc_error += 130; + adc_error -= 10; #endif #ifdef CONFIG_STANDARD_DVBT if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT && - (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) + (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) adc_error += 60; #endif #ifdef CONFIG_SYS_ISDBT if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count > - 0) - && - ((state->fe->dtv_property_cache.layer[0].modulation == - QAM_64) - || (state->fe->dtv_property_cache.layer[0]. - modulation == QAM_16))) - || - ((state->fe->dtv_property_cache.layer[1].segment_count > - 0) - && - ((state->fe->dtv_property_cache.layer[1].modulation == - QAM_64) - || (state->fe->dtv_property_cache.layer[1]. - modulation == QAM_16))) - || - ((state->fe->dtv_property_cache.layer[2].segment_count > - 0) - && - ((state->fe->dtv_property_cache.layer[2].modulation == - QAM_64) - || (state->fe->dtv_property_cache.layer[2]. - modulation == QAM_16))) - ) - ) + 0) + && + ((state->fe->dtv_property_cache.layer[0].modulation == + QAM_64) + || (state->fe->dtv_property_cache. + layer[0].modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[1].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[1].modulation == + QAM_64) + || (state->fe->dtv_property_cache. + layer[1].modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[2].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[2].modulation == + QAM_64) + || (state->fe->dtv_property_cache. + layer[2].modulation == QAM_16))) + ) + ) adc_error += 60; #endif @@ -760,9 +1199,9 @@ int dib0090_gain_control(struct dvb_frontend *fe) } #ifdef DEBUG_AGC dprintk - ("FE: %d, tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", - (u32) fe->id, (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, - (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); + ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", + (u32) * tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, + (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); #endif } @@ -771,6 +1210,7 @@ int dib0090_gain_control(struct dvb_frontend *fe) dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly); return ret; } + EXPORT_SYMBOL(dib0090_gain_control); void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) @@ -785,13 +1225,53 @@ void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * if (rflt) *rflt = (state->rf_lt_def >> 10) & 0x7; } + EXPORT_SYMBOL(dib0090_get_current_gain); -u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) { - struct dib0090_state *st = tuner->tuner_priv; - return st->wbd_offset; + struct dib0090_state *state = fe->tuner_priv; + u32 f_MHz = state->fe->dtv_property_cache.frequency / 1000000; + s32 current_temp = state->temperature; + s32 wbd_thot, wbd_tcold; + const struct dib0090_wbd_slope *wbd = state->current_wbd_table; + + while (f_MHz > wbd->max_freq) + wbd++; + + dprintk("using wbd-table-entry with max freq %d", wbd->max_freq); + + if (current_temp < 0) + current_temp = 0; + if (current_temp > 128) + current_temp = 128; + + //What Wbd gain to apply for this range of frequency + state->wbdmux &= ~(7 << 13); + if (wbd->wbd_gain != 0) + state->wbdmux |= (wbd->wbd_gain << 13); + else + state->wbdmux |= (4 << 13); // 4 is the default WBD gain + + dib0090_write_reg(state, 0x10, state->wbdmux); + + //All the curves are linear with slope*f/64+offset + wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6); + wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6); + + // Iet assumes that thot-tcold = 130 equiv 128, current temperature ref is -30deg + + wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7; + + //for (offset = 0; offset < 1000; offset += 4) + // dbgp("offset = %d -> %d\n", offset, dib0090_wbd_to_db(state, offset)); + state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold); // get the value in dBm from the offset + dprintk("wbd-target: %d dB", (u32) state->wbd_target); + dprintk("wbd offset applied is %d", wbd_tcold); + + return state->wbd_offset + wbd_tcold; } + EXPORT_SYMBOL(dib0090_get_wbd_offset); static const u16 dib0090_defaults[] = { @@ -801,7 +1281,7 @@ static const u16 dib0090_defaults[] = { 0x99a0, 0x6008, 0x0000, - 0x8acb, + 0x8bcb, 0x0000, 0x0405, 0x0000, @@ -829,8 +1309,6 @@ static const u16 dib0090_defaults[] = { 1, 0x39, 0x0000, - 1, 0x1b, - EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL, 2, 0x1e, 0x07FF, 0x0007, @@ -844,50 +1322,126 @@ static const u16 dib0090_defaults[] = { 0 }; -static int dib0090_reset(struct dvb_frontend *fe) -{ - struct dib0090_state *state = fe->tuner_priv; - u16 l, r, *n; +static const u16 dib0090_p1g_additionnal_defaults[] = { + // additionnal INITIALISATION for p1g to be written after dib0090_defaults + 1, 0x05, + 0xabcd, - dib0090_reset_digital(fe, state->config); - state->revision = dib0090_identify(fe); - - /* Revision definition */ - if (state->revision == 0xff) - return -EINVAL; -#ifdef EFUSE - else if ((state->revision & 0x1f) >= 3) /* Update the efuse : Only available for KROSUS > P1C */ - dib0090_set_EFUSE(state); -#endif + 1, 0x11, + 0x00b4, -#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT - if (!(state->revision & 0x1)) /* it is P1B - reset is already done */ - return 0; -#endif + 1, 0x1c, + 0xfffd, + + 1, 0x40, + 0x108, + 0 +}; + +static void dib0090_set_default_config(struct dib0090_state *state, const u16 * n) +{ + u16 l, r; - /* Upload the default values */ - n = (u16 *) dib0090_defaults; l = pgm_read_word(n++); while (l) { r = pgm_read_word(n++); do { - /* DEBUG_TUNER */ - /* dprintk("%d, %d, %d", l, r, pgm_read_word(n)); */ dib0090_write_reg(state, r, pgm_read_word(n++)); r++; } while (--l); l = pgm_read_word(n++); } +} + +#define CAP_VALUE_MIN (u8) 9 +#define CAP_VALUE_MAX (u8) 40 +#define HR_MIN (u8) 25 +#define HR_MAX (u8) 40 +#define POLY_MIN (u8) 0 +#define POLY_MAX (u8) 8 + +void dib0090_set_EFUSE(struct dib0090_state *state) +{ + u8 c,h,n; + u16 e2,e4; + u16 cal; + + e2=dib0090_read_reg(state,0x26); + e4=dib0090_read_reg(state,0x28); + + if ((state->identity.version == P1D_E_F) || // All P1F uses the internal calibration + (state->identity.version == P1G) || (e2 == 0xffff)) { //W0090G11R1 and W0090G11R1-D : We will find the calibration Value of the Baseband + + dib0090_write_reg(state,0x22,0x10); //Start the Calib + cal = (dib0090_read_reg(state,0x22)>>6) & 0x3ff; + + if ((cal<670) || (cal==1023)) //Cal at 800 would give too high value for the n + cal=850; //Recenter the n to 32 + n = 165 - ((cal * 10)>>6) ; + e2 = e4 = (3<<12) | (34<<6) | (n); + } + + if (e2!=e4) { + e2 &= e4; /* Remove the redundancy */ + } + + if (e2 != 0xffff) { + c = e2 & 0x3f; + n = (e2 >> 12) & 0xf; + h= (e2 >> 6) & 0x3f; + + if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN)) + c=32; + if ((h >= HR_MAX) || (h <= HR_MIN)) + h=34; + if ((n >= POLY_MAX) || (n <= POLY_MIN)) + n=3; + + dib0090_write_reg(state,0x13, (h << 10)) ; + e2 = (n<<11) | ((h>>2)<<6) | (c); + dib0090_write_reg(state,0x2, e2) ; /* Load the BB_2 */ + } +} + +static int dib0090_reset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + + dib0090_reset_digital(fe, state->config); + if (dib0090_identify(fe) < 0) + return -EIO; + +#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT + if (!(state->identity.version & 0x1)) /* it is P1B - reset is already done */ + return 0; +#endif + + if (!state->identity.in_soc) { + if ((dib0090_read_reg(state, 0x1a) >> 5) & 0x2) + dib0090_write_reg(state, 0x1b, (EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL)); + else + dib0090_write_reg(state, 0x1b, (EN_DIGCLK | EN_PLL | EN_CRYSTAL)); + } + + dib0090_set_default_config(state, dib0090_defaults); + + if (state->identity.in_soc) + dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */ + + if (state->identity.p1g) + dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults); + + if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/ + dib0090_set_EFUSE(state); /* Congigure in function of the crystal */ if (state->config->io.clock_khz >= 24000) - l = 1; + dib0090_write_reg(state, 0x14, 1); else - l = 2; - dib0090_write_reg(state, 0x14, l); + dib0090_write_reg(state, 0x14, 2); dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); - state->reset = 3; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ + state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ return 0; } @@ -927,11 +1481,11 @@ static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_st } struct dc_calibration { - uint8_t addr; - uint8_t offset; - uint8_t pga:1; - uint16_t bb1; - uint8_t i:1; + u8 addr; + u8 offset; + u8 pga:1; + u16 bb1; + u8 i:1; }; static const struct dc_calibration dc_table[] = { @@ -944,6 +1498,17 @@ static const struct dc_calibration dc_table[] = { {0}, }; +static const struct dc_calibration dc_p1g_table[] = { + /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ + /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */ + {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1}, // offset_trim2_i_chann 0 0 5 0 0 1 6 9 5 + {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0}, // offset_trim2_q_chann 0 0 5 0 0 1 7 15 11 + /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ + {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1}, // offset_trim1_i_chann 0 0 5 0 0 1 6 4 0 + {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0}, // offset_trim1_q_chann 0 0 5 0 0 1 6 14 10 + {0}, +}; + static void dib0090_set_trim(struct dib0090_state *state) { u16 *val; @@ -962,41 +1527,45 @@ static void dib0090_set_trim(struct dib0090_state *state) static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) { int ret = 0; + u16 reg; switch (*tune_state) { - case CT_TUNER_START: - /* init */ - dprintk("Internal DC calibration"); - - /* the LNA is off */ - dib0090_write_reg(state, 0x24, 0x02ed); + dprintk("Start DC offset calibration"); /* force vcm2 = 0.8V */ state->bb6 = 0; state->bb7 = 0x040d; + /* the LNA AND LO are off */ + reg = dib0090_read_reg(state, 0x24) & 0x0ffb; /* shutdown lna and lo */ + dib0090_write_reg(state, 0x24, reg); + + state->wbdmux = dib0090_read_reg(state, 0x10); + dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3); // connect BB, disable WDB enable* + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); //Discard the DataTX + state->dc = dc_table; + if (state->identity.p1g) + state->dc = dc_p1g_table; *tune_state = CT_TUNER_STEP_0; /* fall through */ case CT_TUNER_STEP_0: + dprintk("Sart/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q"); dib0090_write_reg(state, 0x01, state->dc->bb1); dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); state->step = 0; - state->min_adc_diff = 1023; - *tune_state = CT_TUNER_STEP_1; ret = 50; break; case CT_TUNER_STEP_1: dib0090_set_trim(state); - *tune_state = CT_TUNER_STEP_2; break; @@ -1007,7 +1576,13 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front break; case CT_TUNER_STEP_5: /* found an offset */ - dprintk("FE%d: IQC read=%d, current=%x", state->fe->id, (u32) state->adc_diff, state->step); + dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step); + if (state->step == 0 && state->adc_diff < 0) { + state->min_adc_diff = -1023; + dprintk("Change of sign of the minimum adc diff"); + } + + dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step); /* first turn for this frequency */ if (state->step == 0) { @@ -1017,20 +1592,21 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front state->step = 0x10; } - state->adc_diff = ABS(state->adc_diff); - - if (state->adc_diff < state->min_adc_diff && steps(state->step) < 15) { /* stop search when the delta to 0 is increasing */ + /* Look for a change of Sign in the Adc_diff.min_adc_diff is used to STORE the setp N-1 */ + if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) { + /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */ state->step++; - state->min_adc_diff = state->adc_diff; + state->min_adc_diff = state->adc_diff; //min is used as N-1 *tune_state = CT_TUNER_STEP_1; } else { - /* the minimum was what we have seen in the step before */ - state->step--; - dib0090_set_trim(state); + if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { //Come back to the previous state since the delta was better + dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff); + state->step--; + } - dprintk("FE%d: BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->fe->id, state->dc->addr, state->adc_diff, - state->step); + dib0090_set_trim(state); + dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step); state->dc++; if (state->dc->addr == 0) /* done */ @@ -1042,10 +1618,10 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front break; case CT_TUNER_STEP_6: - dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); + dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); //Force the test bus to be off dib0090_write_reg(state, 0x1f, 0x7); *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ - state->reset &= ~0x1; + state->calibrate &= ~DC_CAL; default: break; } @@ -1054,21 +1630,43 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) { + u8 wbd_gain; + const struct dib0090_wbd_slope *wbd = state->current_wbd_table; + switch (*tune_state) { case CT_TUNER_START: - /* WBD-mode=log, Bias=2, Gain=6, Testmode=1, en=1, WBDMUX=1 */ - dib0090_write_reg(state, 0x10, 0xdb09 | (1 << 10)); - dib0090_write_reg(state, 0x24, EN_UHF & 0x0fff); + while (state->current_rf / 1000 > wbd->max_freq) + wbd++; + if (wbd->wbd_gain != 0) + wbd_gain = wbd->wbd_gain; + else { + wbd_gain = 4; +#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) + if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) + wbd_gain = 2; +#endif + } + if (wbd_gain == state->wbd_calibration_gain) { /* the WBD calibration has already been done */ + *tune_state = CT_TUNER_START; + state->calibrate &= ~WBD_CAL; + return 0; + } + + dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3)); // Force: WBD enable,gain to 4, mux to WBD + + dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1))); //Discard all LNA but crystal !!! *tune_state = CT_TUNER_STEP_0; + state->wbd_calibration_gain = wbd_gain; return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ + case CT_TUNER_STEP_0: - state->wbd_offset = dib0090_read_reg(state, 0x1d); + state->wbd_offset = dib0090_get_slow_adc_val(state); dprintk("WBD calibration offset = %d", state->wbd_offset); - *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ - state->reset &= ~0x2; + state->calibrate &= ~WBD_CAL; break; + default: break; } @@ -1092,6 +1690,15 @@ static void dib0090_set_bandwidth(struct dib0090_state *state) state->bb_1_def |= tmp; dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */ + + dib0090_write_reg(state, 0x03, 0x6008); /* = 0x6008 : vcm3_trim = 1 ; filter2_gm1_trim = 8 ; filter2_cutoff_freq = 0 */ + dib0090_write_reg(state, 0x04, 0x1); /* 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast */ + if (state->identity.in_soc) { + dib0090_write_reg(state, 0x05, 0x9bcf); /* attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 1 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 15 */ + } else { + dib0090_write_reg(state, 0x02, (5 << 11) | (8 << 6) | (22 & 0x3f)); /* 22 = cap_value */ + dib0090_write_reg(state, 0x05, 0xabcd); /* = 0xabcd : attenuator_ibias_tri = 2 ; input_stage_ibias_tr = 2 ; nc = 11 ; ext_gm_trim = 1 ; obuf_ibias_trim = 4 ; filter13_gm2_ibias_t = 13 */ + } } static const struct dib0090_pll dib0090_pll_table[] = { @@ -1180,6 +1787,266 @@ static const struct dib0090_tuning dib0090_tuning_table[] = { #endif }; +static const struct dib0090_tuning dib0090_p1g_tuning_table[] = { + //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable; +#ifdef CONFIG_BAND_CBAND + {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB}, // FM EN_CAB +#endif +#ifdef CONFIG_BAND_VHF + {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF + {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF + {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF +#endif +#ifdef CONFIG_BAND_UHF + {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, // SBD EN_SBD + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, // SBD EN_SBD +#endif +}; + +static const struct dib0090_pll dib0090_p1g_pll_table[] = { +#ifdef CONFIG_BAND_CBAND + {57000, 0, 11, 48, 6}, // CAB + {70000, 1, 11, 48, 6}, // CAB + {86000, 0, 10, 32, 4}, // CAB + {105000, 1, 10, 32, 4}, // FM + {115000, 0, 9, 24, 6}, // FM + {140000, 1, 9, 24, 6}, // MID FM VHF + {170000, 0, 8, 16, 4}, // MID FM VHF +#endif +#ifdef CONFIG_BAND_VHF + {200000, 1, 8, 16, 4}, // VHF + {230000, 0, 7, 12, 6}, // VHF + {280000, 1, 7, 12, 6}, // MID VHF UHF + {340000, 0, 6, 8, 4}, // MID VHF UHF + {380000, 1, 6, 8, 4}, // MID VHF UHF + {455000, 0, 5, 6, 6}, // MID VHF UHF +#endif +#ifdef CONFIG_BAND_UHF + {580000, 1, 5, 6, 6}, // UHF + {680000, 0, 4, 4, 4}, // UHF + {860000, 1, 4, 4, 4}, // UHF +#endif +#ifdef CONFIG_BAND_LBAND + {1800000, 1, 2, 2, 4}, // LBD +#endif +#ifdef CONFIG_BAND_SBAND + {2900000, 0, 1, 1, 6}, // SBD +#endif +}; + +static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = { + //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable; +#ifdef CONFIG_BAND_CBAND + {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB // 0x8190 Good perf but higher current //0x4187 Low current + {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB + {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, // SBD EN_SBD + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, // SBD EN_SBD +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = { + //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable; +#ifdef CONFIG_BAND_CBAND + //{ 184000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB }, // 0x81ce 0x8190 Good perf but higher current //0x4187 Low current + {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, + {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, //0x4187 + {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, + {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, +#endif +}; + +static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = 0; + u16 lo4 = 0xe900; + + s16 adc_target; + u16 adc; + s8 step_sign; + u8 force_soft_search = 0; + + if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) + force_soft_search = 1; + + if (*tune_state == CT_TUNER_START) { + dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO"); + dib0090_write_reg(state, 0x10, 0x2B1); + dib0090_write_reg(state, 0x1e, 0x0032); + + if (!state->tuner_is_tuned) { + /* prepare a complete captrim */ + if (!state->identity.p1g || force_soft_search) + state->step = state->captrim = state->fcaptrim = 64; + + state->current_rf = state->rf_request; + } else { /* we are already tuned to this frequency - the configuration is correct */ + if (!state->identity.p1g || force_soft_search) { + /* do a minimal captrim even if the frequency has not changed */ + state->step = 4; + state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; + } + } + state->adc_diff = 3000; // start with a unreachable high number : only set for KROSUS < P1G */ + *tune_state = CT_TUNER_STEP_0; + + } else if (*tune_state == CT_TUNER_STEP_0) { + if (state->identity.p1g && !force_soft_search) { + // 30MHz => Code 15 for the ration => 128us to lock. Giving approximately + u8 ratio = 31; // (state->config->io.clock_khz / 1024 + 1) & 0x1f; + + dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1); + dib0090_read_reg(state, 0x40); + //dib0090_write_reg(state, 0x40, (3<<7) | ((((state->config->io.clock_khz >> 11)+1) & 0x1f)<<2) | (1<<1) | 1); + ret = 50; + } else { + state->step /= 2; + dib0090_write_reg(state, 0x18, lo4 | state->captrim); + + if (state->identity.in_soc) + ret = 25; + } + *tune_state = CT_TUNER_STEP_1; + + } else if (*tune_state == CT_TUNER_STEP_1) { + if (state->identity.p1g && !force_soft_search) { + dib0090_write_reg(state, 0x40, 0x18c | (0 << 1) | 0); + dib0090_read_reg(state, 0x40); + + state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F; + dprintk("***Final Captrim= 0x%x", state->fcaptrim); + *tune_state = CT_TUNER_STEP_3; + + } else { + /* MERGE for all krosus before P1G */ + adc = dib0090_get_slow_adc_val(state); + dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024); + + if (state->rest == 0 || state->identity.in_soc) { /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */ + adc_target = 200; + } else + adc_target = 400; + + if (adc >= adc_target) { + adc -= adc_target; + step_sign = -1; + } else { + adc = adc_target - adc; + step_sign = 1; + } + + if (adc < state->adc_diff) { + dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff); + state->adc_diff = adc; + state->fcaptrim = state->captrim; + //we could break here, to save time, if we reached a close-enough value + //e.g.: if (state->adc_diff < 20) + //break; + } + + state->captrim += step_sign * state->step; + if (state->step >= 1) + *tune_state = CT_TUNER_STEP_0; + else + *tune_state = CT_TUNER_STEP_2; + + ret = 25; //LOLO changed from 15 + } + } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */ + /*write the final cptrim config */ + dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); + + *tune_state = CT_TUNER_STEP_3; + + } else if (*tune_state == CT_TUNER_STEP_3) { + state->calibrate &= ~CAPTRIM_CAL; + *tune_state = CT_TUNER_STEP_0; + } + + return ret; +} + +static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = 15; + s16 val; + + //The assumption is that the AGC is not active + switch (*tune_state) { + case CT_TUNER_START: + state->wbdmux = dib0090_read_reg(state, 0x10); + dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3)); //Move to the bias and clear the wbd enable + + state->bias = dib0090_read_reg(state, 0x13); + dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8)); //Move to the Ref + + *tune_state = CT_TUNER_STEP_0; + /* wait for the WBDMUX to switch and for the ADC to sample */ + break; + + case CT_TUNER_STEP_0: + state->adc_diff = dib0090_get_slow_adc_val(state); // Get the value for the Ref + dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8)); //Move to the Ptat + *tune_state = CT_TUNER_STEP_1; + break; + + case CT_TUNER_STEP_1: + val = dib0090_get_slow_adc_val(state); // Get the value for the Ptat + state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55; // +55 is defined as = -30deg + + dprintk("temperature: %d C", state->temperature - 30); + + *tune_state = CT_TUNER_STEP_2; + break; + + case CT_TUNER_STEP_2: + //Reload the start values. + dib0090_write_reg(state, 0x13, state->bias); + dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */ + + *tune_state = CT_TUNER_START; + state->calibrate &= ~TEMP_CAL; + if (state->config->analog_output == 0) + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); //Set the DataTX + + break; + + default: + ret = 0; + break; + } + return ret; +} + #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ static int dib0090_tune(struct dvb_frontend *fe) { @@ -1188,91 +2055,139 @@ static int dib0090_tune(struct dvb_frontend *fe) const struct dib0090_pll *pll = state->current_pll_table_index; enum frontend_tune_state *tune_state = &state->tune_state; - u32 rf; - u16 lo4 = 0xe900, lo5, lo6, Den; + u16 lo5, lo6, Den, tmp; u32 FBDiv, Rest, FREF, VCOF_kHz = 0; - u16 tmp, adc; - int8_t step_sign; int ret = 10; /* 1ms is the default delay most of the time */ u8 c, i; - state->current_band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); - rf = fe->dtv_property_cache.frequency / 1000 + (state->current_band == - BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->freq_offset_khz_vhf); - /* in any case we first need to do a reset if needed */ - if (state->reset & 0x1) - return dib0090_dc_offset_calibration(state, tune_state); - else if (state->reset & 0x2) - return dib0090_wbd_calibration(state, tune_state); - - /************************* VCO ***************************/ + /************************* VCO ***************************/ /* Default values for FG */ /* from these are needed : */ /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */ -#ifdef CONFIG_SYS_ISDBT - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) - rf += 850; -#endif + /* in any case we first need to do a calibration if needed */ + if (*tune_state == CT_TUNER_START) { + /* deactivate DataTX before some calibrations */ + if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL)) + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); + else /* Activate DataTX in case a calibration has been done before */ if (state->config->analog_output == 0) + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); + } - if (state->current_rf != rf) { - state->tuner_is_tuned = 0; + if (state->calibrate & DC_CAL) + return dib0090_dc_offset_calibration(state, tune_state); + else if (state->calibrate & WBD_CAL) { + if (state->current_rf == 0) { + state->current_rf = state->fe->dtv_property_cache.frequency / 1000; + } + return dib0090_wbd_calibration(state, tune_state); + } else if (state->calibrate & TEMP_CAL) + return dib0090_get_temperature(state, tune_state); + else if (state->calibrate & CAPTRIM_CAL) + return dib0090_captrim_search(state, tune_state); - tune = dib0090_tuning_table; + if (*tune_state == CT_TUNER_START) { + /* if soc and AGC pwm control, disengage mux to be able to R/W access to 0x01 register to set the right filter (cutoff_freq_select) during the tune sequence, otherwise, SOC SERPAR error when accessing to 0x01 */ + if (state->config->use_pwm_agc && state->identity.in_soc) { + tmp = dib0090_read_reg(state, 0x39); + if ((tmp >> 10) & 0x1) + dib0090_write_reg(state, 0x39, tmp & ~(1 << 10)); // disengage mux : en_mux_bb1 = 0 + } - tmp = (state->revision >> 5) & 0x7; - if (tmp == 0x4 || tmp == 0x7) { - /* CBAND tuner version for VHF */ - if (state->current_band == BAND_FM || state->current_band == BAND_VHF) { - /* Force CBAND */ - state->current_band = BAND_CBAND; - tune = dib0090_tuning_table_fm_vhf_on_cband; + state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000); + state->rf_request = + state->fe->dtv_property_cache.frequency / 1000 + (state->current_band == + BAND_UHF ? state->config->freq_offset_khz_uhf : state->config-> + freq_offset_khz_vhf); + + /* in ISDB-T 1seg we shift tuning frequency */ + if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1 + && state->fe->dtv_property_cache.isdbt_partial_reception == 0)) { + const struct dib0090_low_if_offset_table *LUT_offset = state->config->low_if; + u8 found_offset = 0; + u32 margin_khz = 100; + + if (LUT_offset != NULL) { + while (LUT_offset->RF_freq != 0xffff) { + if (((state->rf_request > (LUT_offset->RF_freq - margin_khz)) + && (state->rf_request < (LUT_offset->RF_freq + margin_khz))) + && LUT_offset->std == state->fe->dtv_property_cache.delivery_system) { + state->rf_request += LUT_offset->offset_khz; + found_offset = 1; + break; + } + LUT_offset++; + } } + + if (found_offset == 0) + state->rf_request += 400; } + if (state->current_rf != state->rf_request || (state->current_standard != state->fe->dtv_property_cache.delivery_system)) { + state->tuner_is_tuned = 0; + state->current_rf = 0; + state->current_standard = 0; - pll = dib0090_pll_table; - /* Look for the interval */ - while (rf > tune->max_freq) - tune++; - while (rf > pll->max_freq) - pll++; - state->current_tune_table_index = tune; - state->current_pll_table_index = pll; - } + tune = dib0090_tuning_table; + if (state->identity.p1g) + tune = dib0090_p1g_tuning_table; - if (*tune_state == CT_TUNER_START) { + tmp = (state->identity.version >> 5) & 0x7; - if (state->tuner_is_tuned == 0) - state->current_rf = 0; + if (state->identity.in_soc) { + if (state->config->force_cband_input) { /* Use the CBAND input for all band */ + if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF + || state->current_band & BAND_UHF) { + state->current_band = BAND_CBAND; + tune = dib0090_tuning_table_cband_7090; + } + } else { /* Use the CBAND input for all band under UHF */ + if (state->current_band & BAND_CBAND || state->current_band & BAND_FM || state->current_band & BAND_VHF) { + state->current_band = BAND_CBAND; + tune = dib0090_tuning_table_cband_7090; + } + } + } else + if (tmp == 0x4 || tmp == 0x7) { + /* CBAND tuner version for VHF */ + if (state->current_band == BAND_FM || state->current_band == BAND_CBAND || state->current_band == BAND_VHF) { + state->current_band = BAND_CBAND; /* Force CBAND */ + + tune = dib0090_tuning_table_fm_vhf_on_cband; + if (state->identity.p1g) + tune = dib0090_p1g_tuning_table_fm_vhf_on_cband; + } + } - if (state->current_rf != rf) { + pll = dib0090_pll_table; + if (state->identity.p1g) + pll = dib0090_p1g_pll_table; - dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); + /* Look for the interval */ + while (state->rf_request > tune->max_freq) + tune++; + while (state->rf_request > pll->max_freq) + pll++; - /* external loop filter, otherwise: - * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; - * lo6 = 0x0e34 */ - if (pll->vco_band) - lo5 = 0x049e; - else if (state->config->analog_output) - lo5 = 0x041d; - else - lo5 = 0x041c; + state->current_tune_table_index = tune; + state->current_pll_table_index = pll; - lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ - - if (!state->config->io.pll_int_loop_filt) - lo6 = 0xff28; - else - lo6 = (state->config->io.pll_int_loop_filt << 3); + // select internal switch + dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); - VCOF_kHz = (pll->hfdiv * rf) * 2; + // Find the VCO frequency in MHz + VCOF_kHz = (pll->hfdiv * state->rf_request) * 2; - FREF = state->config->io.clock_khz; + FREF = state->config->io.clock_khz; // REFDIV is 1FREF Has to be as Close as possible to 10MHz + if (state->config->fref_clock_ratio != 0) + FREF /= state->config->fref_clock_ratio; + // Determine the FB divider + // The reference is 10MHz, Therefore the FBdivider is on the first digits FBDiv = (VCOF_kHz / pll->topresc / FREF); - Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; + Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; //in kHz + // Avoid Spurs in the loopfilter bandwidth if (Rest < LPF) Rest = 0; else if (Rest < 2 * LPF) @@ -1280,147 +2195,155 @@ static int dib0090_tune(struct dvb_frontend *fe) else if (Rest > (FREF - LPF)) { Rest = 0; FBDiv += 1; - } else if (Rest > (FREF - 2 * LPF)) + } //Go to the next FB + else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; Rest = (Rest * 6528) / (FREF / 10); + state->rest = Rest; - Den = 1; + /* external loop filter, otherwise: + * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; + * lo6 = 0x0e34 */ + + if (Rest == 0) { + if (pll->vco_band) + lo5 = 0x049f; + //else if (state->config->analog_output) + // lo5 = 0x041f; + else + lo5 = 0x041f; + } else { + if (pll->vco_band) + lo5 = 0x049e; + else if (state->config->analog_output) + lo5 = 0x041d; + else + lo5 = 0x041c; + } + + if (state->identity.p1g) { /* Bias is done automatically in P1G */ + if (state->identity.in_soc) { + if (state->identity.version == SOC_8090_P1G_11R1) + lo5 = 0x46f; + else + lo5 = 0x42f; + } else + lo5 = 0x42c; //BIAS Lo set to 4 by default in case of the Captrim search does not take care of the VCO Bias + } + + lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ + + //Internal loop filter set... + if (!state->config->io.pll_int_loop_filt) { + if (state->identity.in_soc) + lo6 = 0xff98; + else if (state->identity.p1g || (Rest == 0)) + lo6 = 0xfff8; + else + lo6 = 0xff28; + } else + lo6 = (state->config->io.pll_int_loop_filt << 3); // take the loop filter value given by the layout + //dprintk("lo6 = 0x%04x", (u32)lo6); - dprintk(" ***** ******* Rest value = %d", Rest); + Den = 1; if (Rest > 0) { if (state->config->analog_output) - lo6 |= (1 << 2) | 2; - else - lo6 |= (1 << 2) | 1; + lo6 |= (1 << 2) | 2; //SigmaDelta and Dither + else { + if (state->identity.in_soc) + lo6 |= (1 << 2) | 2; //SigmaDelta and Dither + else + lo6 |= (1 << 2) | 2; //SigmaDelta and Dither + } Den = 255; } -#ifdef CONFIG_BAND_SBAND - if (state->current_band == BAND_SBAND) - lo6 &= 0xfffb; -#endif - + // Now we have to define the Num and Denum + // LO1 gets the FBdiv dib0090_write_reg(state, 0x15, (u16) FBDiv); - - dib0090_write_reg(state, 0x16, (Den << 8) | 1); - + // LO2 gets the REFDiv + if (state->config->fref_clock_ratio != 0) + dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio); + else + dib0090_write_reg(state, 0x16, (Den << 8) | 1); + // LO3 for the Numerator dib0090_write_reg(state, 0x17, (u16) Rest); - + // VCO and HF DIV dib0090_write_reg(state, 0x19, lo5); - + // SIGMA Delta dib0090_write_reg(state, 0x1c, lo6); + // Check if the 0090 is analogged configured + //Disable ADC and DigPLL =0xFF9F, 0xffbf for test purposes. + //Enable The Outputs of the BB on DATA_Tx lo6 = tune->tuner_enable; if (state->config->analog_output) lo6 = (lo6 & 0xff9f) | 0x2; - dib0090_write_reg(state, 0x24, lo6 | EN_LO -#ifdef CONFIG_DIB0090_USE_PWM_AGC - | state->config->use_pwm_agc * EN_CRYSTAL -#endif - ); - - state->current_rf = rf; + dib0090_write_reg(state, 0x24, lo6 | EN_LO | state->config->use_pwm_agc * EN_CRYSTAL); - /* prepare a complete captrim */ - state->step = state->captrim = state->fcaptrim = 64; - - } else { /* we are already tuned to this frequency - the configuration is correct */ - - /* do a minimal captrim even if the frequency has not changed */ - state->step = 4; - state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; } - state->adc_diff = 3000; - dib0090_write_reg(state, 0x10, 0x2B1); - - dib0090_write_reg(state, 0x1e, 0x0032); + state->current_rf = state->rf_request; + state->current_standard = state->fe->dtv_property_cache.delivery_system; ret = 20; - *tune_state = CT_TUNER_STEP_1; - } else if (*tune_state == CT_TUNER_STEP_0) { - /* nothing */ - } else if (*tune_state == CT_TUNER_STEP_1) { - state->step /= 2; - dib0090_write_reg(state, 0x18, lo4 | state->captrim); - *tune_state = CT_TUNER_STEP_2; - } else if (*tune_state == CT_TUNER_STEP_2) { - - adc = dib0090_read_reg(state, 0x1d); - dprintk("FE %d CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) fe->id, (u32) state->captrim, (u32) adc, - (u32) (adc) * (u32) 1800 / (u32) 1024); - - if (adc >= 400) { - adc -= 400; - step_sign = -1; - } else { - adc = 400 - adc; - step_sign = 1; - } + state->calibrate = CAPTRIM_CAL; /* captrim serach now */ + } - if (adc < state->adc_diff) { - dprintk("FE %d CAPTRIM=%d is closer to target (%d/%d)", (u32) fe->id, (u32) state->captrim, (u32) adc, (u32) state->adc_diff); - state->adc_diff = adc; - state->fcaptrim = state->captrim; + else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */ + const struct dib0090_wbd_slope *wbd = state->current_wbd_table; - } +// if(!state->identity.p1g) { + while (state->current_rf / 1000 > wbd->max_freq) + wbd++; +// } - state->captrim += step_sign * state->step; - if (state->step >= 1) - *tune_state = CT_TUNER_STEP_1; - else - *tune_state = CT_TUNER_STEP_3; + dib0090_write_reg(state, 0x1e, 0x07ff); + dprintk("Final Captrim: %d", (u32) state->fcaptrim); + dprintk("HFDIV code: %d", (u32) pll->hfdiv_code); + dprintk("VCO = %d", (u32) pll->vco_band); + dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request); + dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz); + dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); + dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8), + (u32) dib0090_read_reg(state, 0x1c) & 0x3); - ret = 15; - } else if (*tune_state == CT_TUNER_STEP_3) { - /*write the final cptrim config */ - dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); +#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ + c = 4; + i = 3; //wbdmux_bias -#ifdef CONFIG_TUNER_DIB0090_CAPTRIM_MEMORY - state->memory[state->memory_index].cap = state->fcaptrim; -#endif + if (wbd->wbd_gain != 0) //&& !state->identity.p1g) + c = wbd->wbd_gain; - *tune_state = CT_TUNER_STEP_4; - } else if (*tune_state == CT_TUNER_STEP_4) { - dib0090_write_reg(state, 0x1e, 0x07ff); + //Store wideband mux register. + state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1)); + dib0090_write_reg(state, 0x10, state->wbdmux); - dprintk("FE %d Final Captrim: %d", (u32) fe->id, (u32) state->fcaptrim); - dprintk("FE %d HFDIV code: %d", (u32) fe->id, (u32) pll->hfdiv_code); - dprintk("FE %d VCO = %d", (u32) fe->id, (u32) pll->vco_band); - dprintk("FE %d VCOF in kHz: %d ((%d*%d) << 1))", (u32) fe->id, (u32) ((pll->hfdiv * rf) * 2), (u32) pll->hfdiv, (u32) rf); - dprintk("FE %d REFDIV: %d, FREF: %d", (u32) fe->id, (u32) 1, (u32) state->config->io.clock_khz); - dprintk("FE %d FBDIV: %d, Rest: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); - dprintk("FE %d Num: %d, Den: %d, SD: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x17), - (u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3); + if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) { + dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune); + dib0090_write_reg(state, 0x09, tune->lna_bias); + dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim)); + } else + dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | tune->lna_bias); - c = 4; - i = 3; -#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) - if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) { - c = 2; - i = 2; - } -#endif - dib0090_write_reg(state, 0x10, (c << 13) | (i << 11) | (WBD -#ifdef CONFIG_DIB0090_USE_PWM_AGC - | (state->config->use_pwm_agc << 1) -#endif - )); - dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | (tune->lna_bias << 0)); dib0090_write_reg(state, 0x0c, tune->v2i); dib0090_write_reg(state, 0x0d, tune->mix); dib0090_write_reg(state, 0x0e, tune->load); + *tune_state = CT_TUNER_STEP_1; - *tune_state = CT_TUNER_STEP_5; - } else if (*tune_state == CT_TUNER_STEP_5) { - + } else if (*tune_state == CT_TUNER_STEP_1) { /* initialize the lt gain register */ state->rf_lt_def = 0x7c00; - dib0090_write_reg(state, 0x0f, state->rf_lt_def); + // dib0090_write_reg(state, 0x0f, state->rf_lt_def); dib0090_set_bandwidth(state); state->tuner_is_tuned = 1; + +// if(!state->identity.p1g) + state->calibrate |= WBD_CAL; // TODO: only do the WBD calibration for new tune +// + state->calibrate |= TEMP_CAL; // Force the Temperature to be remesured at next TUNE. *tune_state = CT_TUNER_STOP; } else ret = FE_CALLBACK_TIME_NEVER; @@ -1440,6 +2363,7 @@ enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) return state->tune_state; } + EXPORT_SYMBOL(dib0090_get_tune_state); int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) @@ -1449,6 +2373,7 @@ int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tun state->tune_state = tune_state; return 0; } + EXPORT_SYMBOL(dib0090_set_tune_state); static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) @@ -1462,7 +2387,7 @@ static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct dib0090_state *state = fe->tuner_priv; - uint32_t ret; + u32 ret; state->tune_state = CT_TUNER_START; @@ -1492,6 +2417,29 @@ static const struct dvb_tuner_ops dib0090_ops = { .get_frequency = dib0090_get_frequency, }; +static const struct dvb_tuner_ops dib0090_fw_ops = { + .info = { + .name = "DiBcom DiB0090", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0090_release, + + .init = NULL, + .sleep = NULL, + .set_params = NULL, + .get_frequency = NULL, +}; + +static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = { + {470, 0, 250, 0, 100, 4}, + {860, 51, 866, 21, 375, 4}, + {1700, 0, 800, 0, 850, 4}, //LBAND Predefinition , to calibrate + {2900, 0, 250, 0, 100, 6}, //SBAND Predefinition , NOT tested Yet + {0xFFFF, 0, 0, 0, 0, 0}, +}; + struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) { struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL); @@ -1503,6 +2451,11 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte st->fe = fe; fe->tuner_priv = st; + if (config->wbd == NULL) + st->current_wbd_table = dib0090_wbd_table_default; + else + st->current_wbd_table = config->wbd; + if (dib0090_reset(fe) != 0) goto free_mem; @@ -1515,8 +2468,35 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte fe->tuner_priv = NULL; return NULL; } + EXPORT_SYMBOL(dib0090_register); +struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) +{ + struct dib0090_fw_state *st = kzalloc(sizeof(struct dib0090_fw_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + st->config = config; + st->i2c = i2c; + st->fe = fe; + fe->tuner_priv = st; + + if (dib0090_fw_reset_digital(fe, st->config) != 0) + goto free_mem; + + dprintk("DiB0090 FW: successfully identified"); + memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops)); + + return fe; + free_mem: + kfree(st); + fe->tuner_priv = NULL; + return NULL; +} + +EXPORT_SYMBOL(dib0090_fw_register); + MODULE_AUTHOR("Patrick Boettcher "); MODULE_AUTHOR("Olivier Grenie "); MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner"); diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h index aa7711e88776..13d85244ec16 100644 --- a/drivers/media/dvb/frontends/dib0090.h +++ b/drivers/media/dvb/frontends/dib0090.h @@ -27,6 +27,21 @@ struct dib0090_io_config { u16 pll_int_loop_filt; }; +struct dib0090_wbd_slope { + u16 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u16 slope_cold; + u16 offset_cold; + u16 slope_hot; + u16 offset_hot; + u8 wbd_gain; +}; + +struct dib0090_low_if_offset_table { + int std; + u32 RF_freq; + s32 offset_khz; +}; + struct dib0090_config { struct dib0090_io_config io; int (*reset) (struct dvb_frontend *, int); @@ -47,10 +62,20 @@ struct dib0090_config { u16 wbd_cband_offset; u8 use_pwm_agc; u8 clkoutdrive; + + u8 ls_cfg_pad_drv; + u8 data_tx_drv; + + u8 in_soc; + const struct dib0090_low_if_offset_table *low_if; + u8 fref_clock_ratio; + u16 force_cband_input; + struct dib0090_wbd_slope *wbd; }; #if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); +extern struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); @@ -65,6 +90,12 @@ static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, str return NULL; } +static inline struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); -- cgit v1.2.2 From dd316c6bacc2bdb22288507fd479bd2181eb7a7b Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Tue, 4 Jan 2011 04:28:59 -0300 Subject: [media] DIB9000: initial support added This patchs add initial support for the DiB9000-device. This demodulator is firmware-driven. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 8 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/dib9000.c | 2358 ++++++++++++++++++++++++++ drivers/media/dvb/frontends/dib9000.h | 130 ++ drivers/media/dvb/frontends/dibx000_common.h | 47 +- 5 files changed, 2543 insertions(+), 1 deletion(-) create mode 100644 drivers/media/dvb/frontends/dib9000.c create mode 100644 drivers/media/dvb/frontends/dib9000.h (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index b8519ba511e5..a20c1532726a 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -349,6 +349,14 @@ config DVB_DIB7000P A DVB-T tuner module. Designed for mobile usage. Say Y when you want to support this frontend. +config DVB_DIB9000 + tristate "DiBcom 9000" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T tuner module. Designed for mobile usage. Say Y when you want + to support this frontend. + config DVB_TDA10048 tristate "Philips TDA10048HN based" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index b1d9525aa7e3..31dd201c57ce 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o obj-$(CONFIG_DVB_DIB7000M) += dib7000m.o dibx000_common.o obj-$(CONFIG_DVB_DIB7000P) += dib7000p.o dibx000_common.o obj-$(CONFIG_DVB_DIB8000) += dib8000.o dibx000_common.o +obj-$(CONFIG_DVB_DIB9000) += dib9000.o dibx000_common.o obj-$(CONFIG_DVB_MT312) += mt312.o obj-$(CONFIG_DVB_VES1820) += ves1820.o obj-$(CONFIG_DVB_VES1X93) += ves1x93.o diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c new file mode 100644 index 000000000000..a41e02dc08ec --- /dev/null +++ b/drivers/media/dvb/frontends/dib9000.c @@ -0,0 +1,2358 @@ +/* + * Linux-DVB Driver for DiBcom's DiB9000 and demodulator-family. + * + * Copyright (C) 2005-10 DiBcom (http://www.dibcom.fr/) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + */ +#include +#include +#include + +#include "dvb_math.h" +#include "dvb_frontend.h" + +#include "dib9000.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB9000: "); printk(args); printk("\n"); } } while (0) +#define MAX_NUMBER_OF_FRONTENDS 6 + +struct i2c_device { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; +}; + +/* lock */ +#define DIB_LOCK struct mutex +#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock)<0) dprintk("could not get the lock"); } while (0) +#define DibReleaseLock(lock) mutex_unlock(lock) +#define DibInitLock(lock) mutex_init(lock) +#define DibFreeLock(lock) + +struct dib9000_state { + struct i2c_device i2c; + + struct dibx000_i2c_master i2c_master; + struct i2c_adapter tuner_adap; + struct i2c_adapter component_bus; + + u16 revision; + u8 reg_offs; + + enum frontend_tune_state tune_state; + u32 status; + struct dvb_frontend_parametersContext channel_status; + + u8 fe_id; + +#define DIB9000_GPIO_DEFAULT_DIRECTIONS 0xffff + u16 gpio_dir; +#define DIB9000_GPIO_DEFAULT_VALUES 0x0000 + u16 gpio_val; +#define DIB9000_GPIO_DEFAULT_PWM_POS 0xffff + u16 gpio_pwm_pos; + + union { /* common for all chips */ + struct { + u8 mobile_mode:1; + } host; + + struct { + struct dib9000_fe_memory_map { + u16 addr; + u16 size; + } fe_mm[18]; + u8 memcmd; + + DIB_LOCK mbx_if_lock; /* to protect read/write operations */ + DIB_LOCK mbx_lock; /* to protect the whole mailbox handling */ + + DIB_LOCK mem_lock; /* to protect the memory accesses */ + DIB_LOCK mem_mbx_lock; /* to protect the memory-based mailbox */ + +#define MBX_MAX_WORDS (256 - 200 - 2) +#define DIB9000_MSG_CACHE_SIZE 2 + u16 message_cache[DIB9000_MSG_CACHE_SIZE][MBX_MAX_WORDS]; + u8 fw_is_running; + } risc; + } platform; + + union { /* common for all platforms */ + struct { + struct dib9000_config cfg; + } d9; + } chip; + + struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; + u16 component_bus_speed; +}; + +u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 +}; + +enum dib9000_power_mode { + DIB9000_POWER_ALL = 0, + + DIB9000_POWER_NO, + DIB9000_POWER_INTERF_ANALOG_AGC, + DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD, + DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD, + DIB9000_POWER_INTERFACE_ONLY, +}; + +enum dib9000_out_messages { + OUT_MSG_HBM_ACK, + OUT_MSG_HOST_BUF_FAIL, + OUT_MSG_REQ_VERSION, + OUT_MSG_BRIDGE_I2C_W, + OUT_MSG_BRIDGE_I2C_R, + OUT_MSG_BRIDGE_APB_W, + OUT_MSG_BRIDGE_APB_R, + OUT_MSG_SCAN_CHANNEL, + OUT_MSG_MONIT_DEMOD, + OUT_MSG_CONF_GPIO, + OUT_MSG_DEBUG_HELP, + OUT_MSG_SUBBAND_SEL, + OUT_MSG_ENABLE_TIME_SLICE, + OUT_MSG_FE_FW_DL, + OUT_MSG_FE_CHANNEL_SEARCH, + OUT_MSG_FE_CHANNEL_TUNE, + OUT_MSG_FE_SLEEP, + OUT_MSG_FE_SYNC, + OUT_MSG_CTL_MONIT, + + OUT_MSG_CONF_SVC, + OUT_MSG_SET_HBM, + OUT_MSG_INIT_DEMOD, + OUT_MSG_ENABLE_DIVERSITY, + OUT_MSG_SET_OUTPUT_MODE, + OUT_MSG_SET_PRIORITARY_CHANNEL, + OUT_MSG_ACK_FRG, + OUT_MSG_INIT_PMU, +}; + +enum dib9000_in_messages { + IN_MSG_DATA, + IN_MSG_FRAME_INFO, + IN_MSG_CTL_MONIT, + IN_MSG_ACK_FREE_ITEM, + IN_MSG_DEBUG_BUF, + IN_MSG_MPE_MONITOR, + IN_MSG_RAWTS_MONITOR, + IN_MSG_END_BRIDGE_I2C_RW, + IN_MSG_END_BRIDGE_APB_RW, + IN_MSG_VERSION, + IN_MSG_END_OF_SCAN, + IN_MSG_MONIT_DEMOD, + IN_MSG_ERROR, + IN_MSG_FE_FW_DL_DONE, + IN_MSG_EVENT, + IN_MSG_ACK_CHANGE_SVC, + IN_MSG_HBM_PROF, +}; + +/* memory_access requests */ +#define FE_MM_W_CHANNEL 0 +#define FE_MM_W_FE_INFO 1 +#define FE_MM_RW_SYNC 2 + +#define FE_SYNC_CHANNEL 1 +#define FE_SYNC_W_GENERIC_MONIT 2 +#define FE_SYNC_COMPONENT_ACCESS 3 + +#define FE_MM_R_CHANNEL_SEARCH_STATE 3 +#define FE_MM_R_CHANNEL_UNION_CONTEXT 4 +#define FE_MM_R_FE_INFO 5 +#define FE_MM_R_FE_MONITOR 6 + +#define FE_MM_W_CHANNEL_HEAD 7 +#define FE_MM_W_CHANNEL_UNION 8 +#define FE_MM_W_CHANNEL_CONTEXT 9 +#define FE_MM_R_CHANNEL_UNION 10 +#define FE_MM_R_CHANNEL_CONTEXT 11 +#define FE_MM_R_CHANNEL_TUNE_STATE 12 + +#define FE_MM_R_GENERIC_MONITORING_SIZE 13 +#define FE_MM_W_GENERIC_MONITORING 14 +#define FE_MM_R_GENERIC_MONITORING 15 + +#define FE_MM_W_COMPONENT_ACCESS 16 +#define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17 +static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, + u8 * b, u32 len); +static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len); + +static u16 to_fw_output_mode(u16 mode) +{ + switch (mode) { + case OUTMODE_HIGH_Z: + return 0; + case OUTMODE_MPEG2_PAR_GATED_CLK: + return 4; + case OUTMODE_MPEG2_PAR_CONT_CLK: + return 8; + case OUTMODE_MPEG2_SERIAL: + return 16; + case OUTMODE_DIVERSITY: + return 128; + case OUTMODE_MPEG2_FIFO: + return 2; + case OUTMODE_ANALOG_ADC: + return 1; + default: + return 0; + } +} + +static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 len, u16 attribute) +{ + u32 chunk_size = 126; + u32 l; + int ret; + u8 wb[2] = { reg >> 8, reg & 0xff }; + struct i2c_msg msg[2] = { + {.addr = state->i2c.i2c_addr >> 1,.flags = 0,.buf = wb,.len = 2}, + {.addr = state->i2c.i2c_addr >> 1,.flags = I2C_M_RD,.buf = b,.len = len}, + }; + + if (state->platform.risc.fw_is_running && (reg < 1024)) + return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len); + + if (attribute & DATA_BUS_ACCESS_MODE_8BIT) + wb[0] |= (1 << 5); + if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + wb[0] |= (1 << 4); + + do { + l = len < chunk_size ? len : chunk_size; + msg[1].len = l; + msg[1].buf = b; + ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0; + if (ret != 0) { + dprintk("i2c read error on %d", reg); + return -EREMOTEIO; + } + + b += l; + len -= l; + + if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) + reg += l / 2; + } while ((ret == 0) && len); + + return 0; +} + +static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) +{ + u8 b[2]; + u8 wb[2] = { reg >> 8, reg & 0xff }; + struct i2c_msg msg[2] = { + {.addr = i2c->i2c_addr >> 1,.flags = 0,.buf = wb,.len = 2}, + {.addr = i2c->i2c_addr >> 1,.flags = I2C_M_RD,.buf = b,.len = 2}, + }; + + if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { + dprintk("read register %x error", reg); + return 0; + } + + return (b[0] << 8) | b[1]; +} + +static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg) +{ + u8 b[2]; + if (dib9000_read16_attr(state, reg, b, 2, 0) != 0) + return 0; + return (b[0] << 8 | b[1]); +} + +static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute) +{ + u8 b[2]; + if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0) + return 0; + return (b[0] << 8 | b[1]); +} + +#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + +static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute) +{ + u8 b[255]; + u32 chunk_size = 126; + u32 l; + int ret; + + struct i2c_msg msg = { + .addr = state->i2c.i2c_addr >> 1,.flags = 0,.buf = b,.len = len + 2 + }; + + if (state->platform.risc.fw_is_running && (reg < 1024)) { + if (dib9000_risc_apb_access_write + (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) + return -EINVAL; + return 0; + } + + b[0] = (reg >> 8) & 0xff; + b[1] = (reg) & 0xff; + + if (attribute & DATA_BUS_ACCESS_MODE_8BIT) + b[0] |= (1 << 5); + if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + b[0] |= (1 << 4); + + do { + l = len < chunk_size ? len : chunk_size; + msg.len = l + 2; + memcpy(&b[2], buf, l); + + ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; + + buf += l; + len -= l; + + if (!(attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)) + reg += l / 2; + } while ((ret == 0) && len); + + return ret; +} + +static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) +{ + u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff }; + struct i2c_msg msg = { + .addr = i2c->i2c_addr >> 1,.flags = 0,.buf = b,.len = 4 + }; + + return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; +} + +static inline int dib9000_write_word(struct dib9000_state *state, u16 reg, u16 val) +{ + u8 b[2] = { val >> 8, val & 0xff }; + return dib9000_write16_attr(state, reg, b, 2, 0); +} + +static inline int dib9000_write_word_attr(struct dib9000_state *state, u16 reg, u16 val, u16 attribute) +{ + u8 b[2] = { val >> 8, val & 0xff }; + return dib9000_write16_attr(state, reg, b, 2, attribute); +} + +#define dib9000_write(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, 0) +#define dib9000_write16_noinc(state, reg, buf, len) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) +#define dib9000_write16_noinc_attr(state, reg, buf, len, attribute) dib9000_write16_attr(state, reg, buf, len, DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | (attribute)) + +#define dib9000_mbx_send(state, id, data, len) dib9000_mbx_send_attr(state, id, data, len, 0) +#define dib9000_mbx_get_message(state, id, msg, len) dib9000_mbx_get_message_attr(state, id, msg, len, 0) + +#define MAC_IRQ (1 << 1) +#define IRQ_POL_MSK (1 << 4) + +#define dib9000_risc_mem_read_chunks(state, b, len) dib9000_read16_attr(state, 1063, b, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) +#define dib9000_risc_mem_write_chunks(state, buf, len) dib9000_write16_attr(state, 1063, buf, len, DATA_BUS_ACCESS_MODE_8BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT) + +static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u32 len, u8 reading) +{ + u8 b[14] = { 0 }; + +// dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); +// b[0] = 0 << 7; + b[1] = 1; + +// b[2] = 0; // 1057 +// b[3] = 0; + b[4] = (u8) (addr >> 8); // 1058 + b[5] = (u8) (addr & 0xff); + +// b[10] = 0; // 1061 +// b[11] = 0; + b[12] = (u8) (addr >> 8); // 1062 + b[13] = (u8) (addr & 0xff); + + addr += len; +// b[6] = 0; // 1059 +// b[7] = 0; + b[8] = (u8) (addr >> 8); // 1060 + b[9] = (u8) (addr & 0xff); + + dib9000_write(state, 1056, b, 14); + if (reading) + dib9000_write_word(state, 1056, (1 << 15) | 1); + state->platform.risc.memcmd = -1; /* if it was called directly reset it - to force a future setup-call to set it */ +} + +static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd) +{ + struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f]; + /* decide whether we need to "refresh" the memory controller */ + if (state->platform.risc.memcmd == cmd && /* same command */ + !(cmd & 0x80 && m->size < 67)) /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */ + return; + dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80); + state->platform.risc.memcmd = cmd; +} + +static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u16 len) +{ + if (!state->platform.risc.fw_is_running) + return -EIO; + + DibAcquireLock(&state->platform.risc.mem_lock); + dib9000_risc_mem_setup(state, cmd | 0x80); + dib9000_risc_mem_read_chunks(state, b, len); + DibReleaseLock(&state->platform.risc.mem_lock); + return 0; +} + +static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 * b) +{ + struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd]; + if (!state->platform.risc.fw_is_running) + return -EIO; + + DibAcquireLock(&state->platform.risc.mem_lock); + dib9000_risc_mem_setup(state, cmd); + dib9000_risc_mem_write_chunks(state, b, m->size); + DibReleaseLock(&state->platform.risc.mem_lock); + return 0; +} + +static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u16 key, const u8 * code, u32 len) +{ + u16 offs; + + if (risc_id == 1) + offs = 16; + else + offs = 0; + + /* config crtl reg */ + dib9000_write_word(state, 1024 + offs, 0x000f); + dib9000_write_word(state, 1025 + offs, 0); + dib9000_write_word(state, 1031 + offs, key); + + dprintk("going to download %dB of microcode", len); + if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) { + dprintk("error while downloading microcode for RISC %c", 'A' + risc_id); + return -EIO; + } + + dprintk("Microcode for RISC %c loaded", 'A' + risc_id); + + return 0; +} + +static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id) +{ + u16 mbox_offs; + u16 reset_reg; + u16 tries = 1000; + + if (risc_id == 1) + mbox_offs = 16; + else + mbox_offs = 0; + + /* Reset mailbox */ + dib9000_write_word(state, 1027 + mbox_offs, 0x8000); + + /* Read reset status */ + do { + reset_reg = dib9000_read_word(state, 1027 + mbox_offs); + msleep(100); + } while ((reset_reg & 0x8000) && --tries); + + if (reset_reg & 0x8000) { + dprintk("MBX: init ERROR, no response from RISC %c", 'A' + risc_id); + return -EIO; + } + dprintk("MBX: initialized"); + return 0; +} + +#define MAX_MAILBOX_TRY 100 +static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr) +{ + u8 ret = 0, *d, b[2]; + u16 tmp; + u16 size; + u32 i; + + if (!state->platform.risc.fw_is_running) + return -EINVAL; + + DibAcquireLock(&state->platform.risc.mbx_if_lock); + tmp = MAX_MAILBOX_TRY; + do { + size = dib9000_read_word_attr(state, 1043, attr) & 0xff; + if ((size + len + 1) > MBX_MAX_WORDS && --tmp) { + dprintk("MBX: RISC mbx full, retrying"); + msleep(100); + } else + break; + } while (1); + + //dprintk( "MBX: size: %d", size); + + if (tmp == 0) { + ret = -EINVAL; + goto out; + } +#ifdef DUMP_MSG + dprintk("--> %02x %d ", id, len + 1); + for (i = 0; i < len; i++) + dprintk("%04x ", data[i]); + dprintk("\n"); +#endif + + /* byte-order conversion - works on big (where it is not necessary) or little endian */ + d = (u8 *) data; + for (i = 0; i < len; i++) { + tmp = data[i]; + *d++ = tmp >> 8; + *d++ = tmp & 0xff; + } + + /* write msg */ + b[0] = id; + b[1] = len + 1; + if (dib9000_write16_noinc_attr(state, 1045, b, 2, attr) != 0 || dib9000_write16_noinc_attr(state, 1045, (u8 *) data, len * 2, attr) != 0) { + ret = -EIO; + goto out; + } + + /* update register nb_mes_in_RX */ + ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); + + out: + DibReleaseLock(&state->platform.risc.mbx_if_lock); + + return ret; +} + +static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, u16 attr) +{ +#ifdef DUMP_MSG + u16 *d = data; +#endif + + u16 tmp, i; + u8 size; + u8 mc_base; + + if (!state->platform.risc.fw_is_running) + return 0; + + DibAcquireLock(&state->platform.risc.mbx_if_lock); + if (risc_id == 1) + mc_base = 16; + else + mc_base = 0; + + /* Length and type in the first word */ + *data = dib9000_read_word_attr(state, 1029 + mc_base, attr); + + size = *data & 0xff; + if (size <= MBX_MAX_WORDS) { + data++; + size--; /* Initial word already read */ + + dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, size * 2, attr); + + /* to word conversion */ + for (i = 0; i < size; i++) { + tmp = *data; + *data = (tmp >> 8) | (tmp << 8); + data++; + } + +#ifdef DUMP_MSG + dprintk("<-- "); + for (i = 0; i < size + 1; i++) + dprintk("%04x ", d[i]); + dprintk("\n"); +#endif + } else { + dprintk("MBX: message is too big for message cache (%d), flushing message", size); + size--; /* Initial word already read */ + while (size--) + dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr); + } + /* Update register nb_mes_in_TX */ + dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr); + + DibReleaseLock(&state->platform.risc.mbx_if_lock); + + return size + 1; +} + +static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 size) +{ + u32 ts = data[1] << 16 | data[0]; + char *b = (char *)&data[2]; + + b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */ + if (*b == '~') { + b++; + dprintk(b); + } else + dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : ""); + return 1; +} + +static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) +{ + int i; + u8 size; + u16 *block; + /* find a free slot */ + for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { + block = state->platform.risc.message_cache[i]; + if (*block == 0) { + size = dib9000_mbx_read(state, block, 1, attr); + +// dprintk( "MBX: fetched %04x message to cache", *block); + + switch (*block >> 8) { + case IN_MSG_DEBUG_BUF: + dib9000_risc_debug_buf(state, block + 1, size); /* debug-messages are going to be printed right away */ + *block = 0; /* free the block */ + break; +#if 0 + case IN_MSG_DATA: /* FE-TRACE */ + dib9000_risc_data_process(state, block + 1, size); + *block = 0; + break; +#endif + default: + break; + } + + return 1; + } + } + dprintk("MBX: no free cache-slot found for new message..."); + return -1; +} + +static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr) +{ + if (risc_id == 0) + return (u8) (dib9000_read_word_attr(state, 1028, attr) >> 10) & 0x1f; /* 5 bit field */ + else + return (u8) (dib9000_read_word_attr(state, 1044, attr) >> 8) & 0x7f; /* 7 bit field */ +} + +static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) +{ + int ret = 0; + u16 tmp; + + if (!state->platform.risc.fw_is_running) + return -1; + + DibAcquireLock(&state->platform.risc.mbx_lock); + + if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */ + ret = dib9000_mbx_fetch_to_cache(state, attr); + + tmp = dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ +// if (tmp) +// dprintk( "cleared IRQ: %x", tmp); + DibReleaseLock(&state->platform.risc.mbx_lock); + + return ret; +} + +static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 * msg, u8 * size, u16 attr) +{ + u8 i; + u16 *block; + u16 timeout = 30; + + *msg = 0; + do { + /* dib9000_mbx_get_from_cache(); */ + for (i = 0; i < DIB9000_MSG_CACHE_SIZE; i++) { + block = state->platform.risc.message_cache[i]; + if ((*block >> 8) == id) { + *size = (*block & 0xff) - 1; + memcpy(msg, block + 1, (*size) * 2); + *block = 0; /* free the block */ + i = 0; /* signal that we found a message */ + break; + } + } + + if (i == 0) + break; + + if (dib9000_mbx_process(state, attr) == -1) /* try to fetch one message - if any */ + return -1; + + } while (--timeout); + + if (timeout == 0) { + dprintk("waiting for message %d timed out", id); + return -1; + } + + return i == 0; +} + +static int dib9000_risc_check_version(struct dib9000_state *state) +{ + u8 r[4]; + u8 size; + u16 fw_version = 0; + + if (dib9000_mbx_send(state, OUT_MSG_REQ_VERSION, &fw_version, 1) != 0) + return -EIO; + + if (dib9000_mbx_get_message(state, IN_MSG_VERSION, (u16 *) r, &size) < 0) + return -EIO; + + fw_version = (r[0] << 8) | r[1]; + dprintk("RISC: ver: %d.%02d (IC: %d)", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]); + + if ((fw_version >> 10) != 7) + return -EINVAL; + + switch (fw_version & 0x3ff) { + case 11: + case 12: + case 14: + case 15: + case 16: + case 17: + break; + default: + dprintk("RISC: invalid firmware version"); + return -EINVAL; + } + + dprintk("RISC: valid firmware version"); + return 0; +} + +static int dib9000_fw_boot(struct dib9000_state *state, const u8 * codeA, u32 lenA, const u8 * codeB, u32 lenB) +{ + /* Reconfig pool mac ram */ + dib9000_write_word(state, 1225, 0x02); /* A: 8k C, 4 k D - B: 32k C 6 k D - IRAM 96k */ + dib9000_write_word(state, 1226, 0x05); + + /* Toggles IP crypto to Host APB interface. */ + dib9000_write_word(state, 1542, 1); + + /* Set jump and no jump in the dma box */ + dib9000_write_word(state, 1074, 0); + dib9000_write_word(state, 1075, 0); + + /* Set MAC as APB Master. */ + dib9000_write_word(state, 1237, 0); + + /* Reset the RISCs */ + if (codeA != NULL) + dib9000_write_word(state, 1024, 2); + else + dib9000_write_word(state, 1024, 15); + if (codeB != NULL) + dib9000_write_word(state, 1040, 2); + + if (codeA != NULL) + dib9000_firmware_download(state, 0, 0x1234, codeA, lenA); + if (codeB != NULL) + dib9000_firmware_download(state, 1, 0x1234, codeB, lenB); + + /* Run the RISCs */ + if (codeA != NULL) + dib9000_write_word(state, 1024, 0); + if (codeB != NULL) + dib9000_write_word(state, 1040, 0); + + if (codeA != NULL) + if (dib9000_mbx_host_init(state, 0) != 0) + return -EIO; + if (codeB != NULL) + if (dib9000_mbx_host_init(state, 1) != 0) + return -EIO; + + msleep(100); + state->platform.risc.fw_is_running = 1; + + if (dib9000_risc_check_version(state) != 0) + return -EINVAL; + + state->platform.risc.memcmd = 0xff; + return 0; +} + +static u16 dib9000_identify(struct i2c_device *client) +{ + u16 value; + + if ((value = dib9000_i2c_read16(client, 896)) != 0x01b3) { + dprintk("wrong Vendor ID (0x%x)", value); + return 0; + } + + value = dib9000_i2c_read16(client, 897); + if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) { + dprintk("wrong Device ID (0x%x)", value); + return 0; + } + + /* protect this driver to be used with 7000PC */ + if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) { + dprintk("this driver does not work with DiB7000PC"); + return 0; + } + + switch (value) { + case 0x4000: + dprintk("found DiB7000MA/PA/MB/PB"); + break; + case 0x4001: + dprintk("found DiB7000HC"); + break; + case 0x4002: + dprintk("found DiB7000MC"); + break; + case 0x4003: + dprintk("found DiB9000A"); + break; + case 0x4004: + dprintk("found DiB9000H"); + break; + case 0x4005: + dprintk("found DiB9000M"); + break; + } + + return value; +} + +static void dib9000_set_power_mode(struct dib9000_state *state, enum dib9000_power_mode mode) +{ + /* by default everything is going to be powered off */ + u16 reg_903 = 0x3fff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906; + u8 offset; + + if (state->revision == 0x4003 || state->revision == 0x4004 || state->revision == 0x4005) + offset = 1; + else + offset = 0; + + reg_906 = dib9000_read_word(state, 906 + offset) | 0x3; /* keep settings for RISC */ + + /* now, depending on the requested mode, we power on */ + switch (mode) { + /* power up everything in the demod */ + case DIB9000_POWER_ALL: + reg_903 = 0x0000; + reg_904 = 0x0000; + reg_905 = 0x0000; + reg_906 = 0x0000; + break; + + /* just leave power on the control-interfaces: GPIO and (I2C or SDIO or SRAM) */ + case DIB9000_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C or SRAM */ + reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 2)); + break; + + case DIB9000_POWER_INTERF_ANALOG_AGC: + reg_903 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10)); + reg_905 &= ~((1 << 7) | (1 << 6) | (1 << 5) | (1 << 4) | (1 << 2)); + reg_906 &= ~((1 << 0)); + break; + + case DIB9000_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD: + reg_903 = 0x0000; + reg_904 = 0x801f; + reg_905 = 0x0000; + reg_906 &= ~((1 << 0)); + break; + + case DIB9000_POWER_COR4_CRY_ESRAM_MOUT_NUD: + reg_903 = 0x0000; + reg_904 = 0x8000; + reg_905 = 0x010b; + reg_906 &= ~((1 << 0)); + break; + default: + case DIB9000_POWER_NO: + break; + } + + /* always power down unused parts */ + if (!state->platform.host.mobile_mode) + reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1); + + /* P_sdio_select_clk = 0 on MC and after */ + if (state->revision != 0x4000) + reg_906 <<= 1; + + dib9000_write_word(state, 903 + offset, reg_903); + dib9000_write_word(state, 904 + offset, reg_904); + dib9000_write_word(state, 905 + offset, reg_905); + dib9000_write_word(state, 906 + offset, reg_906); +} + +static int dib9000_fw_reset(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + + dib9000_write_word(state, 1817, 0x0003); // SRAM read lead in + P_host_rdy_cmos=1 + + dib9000_write_word(state, 1227, 1); + dib9000_write_word(state, 1227, 0); + + switch ((state->revision = dib9000_identify(&state->i2c))) { + case 0x4003: + case 0x4004: + case 0x4005: + state->reg_offs = 1; + break; + default: + return -EINVAL; + } + + /* reset the i2c-master to use the host interface */ + dibx000_reset_i2c_master(&state->i2c_master); + + dib9000_set_power_mode(state, DIB9000_POWER_ALL); + + /* unforce divstr regardless whether i2c enumeration was done or not */ + dib9000_write_word(state, 1794, dib9000_read_word(state, 1794) & ~(1 << 1)); + dib9000_write_word(state, 1796, 0); + dib9000_write_word(state, 1805, 0x805); + + /* restart all parts */ + dib9000_write_word(state, 898, 0xffff); + dib9000_write_word(state, 899, 0xffff); + dib9000_write_word(state, 900, 0x0001); + dib9000_write_word(state, 901, 0xff19); + dib9000_write_word(state, 902, 0x003c); + + dib9000_write_word(state, 898, 0); + dib9000_write_word(state, 899, 0); + dib9000_write_word(state, 900, 0); + dib9000_write_word(state, 901, 0); + dib9000_write_word(state, 902, 0); + + dib9000_write_word(state, 911, state->chip.d9.cfg.if_drives); + + dib9000_set_power_mode(state, DIB9000_POWER_INTERFACE_ONLY); + + return 0; +} + +static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, + u8 * b, u32 len) +{ + u16 mb[10]; + u8 i, s; + + if (address >= 1024 || !state->platform.risc.fw_is_running) + return -EINVAL; + + //dprintk( "APB access thru rd fw %d %x", address, attribute); + + mb[0] = (u16) address; + mb[1] = len / 2; + dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute); + switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) { + case 1: + s--; // address + for (i = 0; i < s; i++) { + b[i * 2] = (mb[i + 1] >> 8) & 0xff; + b[i * 2 + 1] = (mb[i + 1]) & 0xff; + } + return 0; + default: + return -EIO; + } + return -EIO; +} + +static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len) +{ + u16 mb[10]; + u8 s, i; + + if (address >= 1024 || !state->platform.risc.fw_is_running) + return -EINVAL; + + //dprintk( "APB access thru wr fw %d %x", address, attribute); + + mb[0] = (unsigned short)address; + for (i = 0; i < len && i < 20; i += 2) // 20 bytes max + mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]); + + dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute); + return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL; +} + +static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i) +{ + u8 index_loop = 10; + + if (!state->platform.risc.fw_is_running) + return 0; + dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i); + do { + dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1); + } while (i && index_loop--); + + if (index_loop > 0) + return 0; + return -EIO; +} + +static int dib9000_fw_init(struct dib9000_state *state) +{ + struct dibGPIOFunction *f; + u16 b[40] = { 0 }; + u8 i; + u8 size; + + if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0) + //if (dib9000_fw_boot(state, microcode_A_buffer, microcode_A_size, microcode_B_buffer, microcode_B_size) != 0) + return -EIO; + + /* initialize the firmware */ + for (i = 0; i < ARRAY_SIZE(state->chip.d9.cfg.gpio_function); i++) { + f = &state->chip.d9.cfg.gpio_function[i]; + if (f->mask) { + switch (f->function) { + case BOARD_GPIO_FUNCTION_COMPONENT_ON: + b[0] = (u16) f->mask; + b[1] = (u16) f->direction; + b[2] = (u16) f->value; + break; + case BOARD_GPIO_FUNCTION_COMPONENT_OFF: + b[3] = (u16) f->mask; + b[4] = (u16) f->direction; + b[5] = (u16) f->value; + break; + } + } + } + if (dib9000_mbx_send(state, OUT_MSG_CONF_GPIO, b, 15) != 0) + return -EIO; + + /* subband */ + b[0] = state->chip.d9.cfg.subband.size; /* type == 0 -> GPIO - PWM not yet supported */ + for (i = 0; i < state->chip.d9.cfg.subband.size; i++) { + b[1 + i * 4] = state->chip.d9.cfg.subband.subband[i].f_mhz; + b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask; + b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction; + b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value; + //dprintk( "SBS: %d %d %x %x %x\n", i, b[1 + i*4], b[2 + i*4], b[3 + i*4], b[4 + i*4]); + } + b[1 + i * 4] = 0; /* fe_id */ + if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0) + return -EIO; + + /* 0 - id, 1 - no_of_frontends */ + b[0] = (0 << 8) | 1; + /* 0 = i2c-address demod, 0 = tuner */ + b[1] = (0 << 8) | (0); //st->i2c_addr ) ); + b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff); + b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff); + b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff); + b[5] = (u16) ((state->chip.d9.cfg.vcxo_timer) & 0xffff); + b[6] = (u16) ((state->chip.d9.cfg.timing_frequency >> 16) & 0xffff); + b[7] = (u16) ((state->chip.d9.cfg.timing_frequency) & 0xffff); + b[29] = state->chip.d9.cfg.if_drives; + if (dib9000_mbx_send(state, OUT_MSG_INIT_DEMOD, b, ARRAY_SIZE(b)) != 0) + return -EIO; + + if (dib9000_mbx_send(state, OUT_MSG_FE_FW_DL, NULL, 0) != 0) + return -EIO; + + if (dib9000_mbx_get_message(state, IN_MSG_FE_FW_DL_DONE, b, &size) < 0) + return -EIO; + + if (size > ARRAY_SIZE(b)) { + dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size, (int)ARRAY_SIZE(b)); + return -EINVAL; + } + + for (i = 0; i < size; i += 2) { + state->platform.risc.fe_mm[i / 2].addr = b[i + 0]; + state->platform.risc.fe_mm[i / 2].size = b[i + 1]; + //dprintk( "MM: %d %d %d", state->platform.risc.fe_mm[i/2].addr, state->platform.risc.fe_mm[i/2].size, ARRAY_SIZE(state->platform.risc.fe_mm)); + } + + return 0; +} + +static void dib9000_fw_set_channel_head(struct dib9000_state *state, struct dvb_frontend_parameters *ch) +{ + u8 b[9]; + u32 freq = state->fe[0]->dtv_property_cache.frequency / 1000; + if (state->fe_id % 2) + freq += 101; + + b[0] = (u8) ((freq >> 0) & 0xff); + b[1] = (u8) ((freq >> 8) & 0xff); + b[2] = (u8) ((freq >> 16) & 0xff); + b[3] = (u8) ((freq >> 24) & 0xff); + b[4] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 0) & 0xff); + b[5] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 8) & 0xff); + b[6] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 16) & 0xff); + b[7] = (u8) ((state->fe[0]->dtv_property_cache.bandwidth_hz / 1000 >> 24) & 0xff); + b[8] = 0x80; /* do not wait for CELL ID when doing autosearch */ + if (state->fe[0]->dtv_property_cache.delivery_system == SYS_DVBT) + b[8] |= 1; + dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_HEAD, b); +} + +static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +{ + struct dib9000_state *state = fe->demodulator_priv; + struct dibDVBTChannel { + s8 spectrum_inversion; + + s8 nfft; + s8 guard; + s8 constellation; + + s8 hrch; + s8 alpha; + s8 code_rate_hp; + s8 code_rate_lp; + s8 select_hp; + + s8 intlv_native; + }; + struct dibDVBTChannel ch; + int ret = 0; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + goto error; + ret = -EIO; + } + + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) & ch, sizeof(struct dibDVBTChannel)); + + switch (ch.spectrum_inversion&0x7) { + case 1: + state->fe[0]->dtv_property_cache.inversion = INVERSION_ON; + break; + case 0: + state->fe[0]->dtv_property_cache.inversion = INVERSION_OFF; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO; + break; + } + switch (ch.nfft) { + case 0: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 2: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K; + break; + case 1: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO; + break; + } + switch (ch.guard) { + case 0: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO; + break; + } + switch (ch.constellation) { + case 2: + state->fe[0]->dtv_property_cache.modulation = QAM_64; + break; + case 1: + state->fe[0]->dtv_property_cache.modulation = QAM_16; + break; + case 0: + state->fe[0]->dtv_property_cache.modulation = QPSK; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.modulation = QAM_AUTO; + break; + } + switch (ch.hrch) { + case 0: + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE; + break; + case 1: + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_1; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO; + break; + } + switch (ch.code_rate_hp) { + case 1: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2; + break; + case 2: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_2_3; + break; + case 3: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_3_4; + break; + case 5: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_5_6; + break; + case 7: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_7_8; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO; + break; + } + switch (ch.code_rate_lp) { + case 1: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2; + break; + case 2: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_2_3; + break; + case 3: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_3_4; + break; + case 5: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_5_6; + break; + case 7: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_7_8; + break; + default: + case -1: + state->fe[0]->dtv_property_cache.code_rate_LP = FEC_AUTO; + break; + } + + error: + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + return ret; +} + +static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_frontend_parameters *channel) +{ + struct dib9000_state *state = fe->demodulator_priv; + struct dibDVBTChannel { + s8 spectrum_inversion; + + s8 nfft; + s8 guard; + s8 constellation; + + s8 hrch; + s8 alpha; + s8 code_rate_hp; + s8 code_rate_lp; + s8 select_hp; + + s8 intlv_native; + }; + struct dibDVBTChannel ch; + + switch (state->fe[0]->dtv_property_cache.inversion) { + case INVERSION_ON: + ch.spectrum_inversion = 1; + break; + case INVERSION_OFF: + ch.spectrum_inversion = 0; + break; + default: + case INVERSION_AUTO: + ch.spectrum_inversion = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_2K: + ch.nfft = 0; + break; + case TRANSMISSION_MODE_4K: + ch.nfft = 2; + break; + case TRANSMISSION_MODE_8K: + ch.nfft = 1; + break; + default: + case TRANSMISSION_MODE_AUTO: + ch.nfft = 1; + break; + } + switch (state->fe[0]->dtv_property_cache.guard_interval) { + case GUARD_INTERVAL_1_32: + ch.guard = 0; + break; + case GUARD_INTERVAL_1_16: + ch.guard = 1; + break; + case GUARD_INTERVAL_1_8: + ch.guard = 2; + break; + case GUARD_INTERVAL_1_4: + ch.guard = 3; + break; + default: + case GUARD_INTERVAL_AUTO: + ch.guard = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.modulation) { + case QAM_64: + ch.constellation = 2; + break; + case QAM_16: + ch.constellation = 1; + break; + case QPSK: + ch.constellation = 0; + break; + default: + case QAM_AUTO: + ch.constellation = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.hierarchy) { + case HIERARCHY_NONE: + ch.hrch = 0; + break; + case HIERARCHY_1: + case HIERARCHY_2: + case HIERARCHY_4: + ch.hrch = 1; + break; + default: + case HIERARCHY_AUTO: + ch.hrch = -1; + break; + } + ch.alpha = 1; + switch (state->fe[0]->dtv_property_cache.code_rate_HP) { + case FEC_1_2: + ch.code_rate_hp = 1; + break; + case FEC_2_3: + ch.code_rate_hp = 2; + break; + case FEC_3_4: + ch.code_rate_hp = 3; + break; + case FEC_5_6: + ch.code_rate_hp = 5; + break; + case FEC_7_8: + ch.code_rate_hp = 7; + break; + default: + case FEC_AUTO: + ch.code_rate_hp = -1; + break; + } + switch (state->fe[0]->dtv_property_cache.code_rate_LP) { + case FEC_1_2: + ch.code_rate_lp = 1; + break; + case FEC_2_3: + ch.code_rate_lp = 2; + break; + case FEC_3_4: + ch.code_rate_lp = 3; + break; + case FEC_5_6: + ch.code_rate_lp = 5; + break; + case FEC_7_8: + ch.code_rate_lp = 7; + break; + default: + case FEC_AUTO: + ch.code_rate_lp = -1; + break; + } + ch.select_hp = 1; + ch.intlv_native = 1; + + dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) & ch); + + return 0; +} + +static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) +{ + struct dib9000_state *state = fe->demodulator_priv; + int ret = 10, search = state->channel_status.status == CHANNEL_STATUS_PARAMETERS_UNKNOWN; + s8 i; + + switch (state->tune_state) { + case CT_DEMOD_START: + dib9000_fw_set_channel_head(state, ch); + + /* write the channel context - a channel is initialized to 0, so it is OK */ + dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_CONTEXT, (u8 *) fe_info); + dib9000_risc_mem_write(state, FE_MM_W_FE_INFO, (u8 *) fe_info); + + if (search) + dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_SEARCH, NULL, 0); + else { + dib9000_fw_set_channel_union(fe, ch); + dib9000_mbx_send(state, OUT_MSG_FE_CHANNEL_TUNE, NULL, 0); + } + state->tune_state = CT_DEMOD_STEP_1; + break; + case CT_DEMOD_STEP_1: + if (search) + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) & i, 1); + else + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) & i, 1); + switch (i) { /* something happened */ + case 0: + break; + case -2: /* tps locks are "slower" than MPEG locks -> even in autosearch data is OK here */ + if (search) + state->status = FE_STATUS_DEMOD_SUCCESS; + else { + state->tune_state = CT_DEMOD_STOP; + state->status = FE_STATUS_LOCKED; + } + break; + default: + state->status = FE_STATUS_TUNE_FAILED; + state->tune_state = CT_DEMOD_STOP; + break; + } + break; + default: + ret = FE_CALLBACK_TIME_NEVER; + break; + } + + return ret; +} + +static int dib9000_fw_set_diversity_in(struct dvb_frontend *fe, int onoff) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 mode = (u16) onoff; + return dib9000_mbx_send(state, OUT_MSG_ENABLE_DIVERSITY, &mode, 1); +} + +static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 outreg, smo_mode; + + dprintk("setting output mode for demod %p to %d", fe, mode); + + switch (mode) { + case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock + outreg = (1 << 10); /* 0x0400 */ + break; + case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock + outreg = (1 << 10) | (1 << 6); /* 0x0440 */ + break; + case OUTMODE_MPEG2_SERIAL: // STBs with serial input + outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ + break; + case OUTMODE_DIVERSITY: + outreg = (1 << 10) | (4 << 6); /* 0x0500 */ + break; + case OUTMODE_MPEG2_FIFO: // e.g. USB feeding + outreg = (1 << 10) | (5 << 6); + break; + case OUTMODE_HIGH_Z: // disable + outreg = 0; + break; + default: + dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]); + return -EINVAL; + } + + dib9000_write_word(state, 1795, outreg); // has to be written from outside + + switch (mode) { + case OUTMODE_MPEG2_PAR_GATED_CLK: + case OUTMODE_MPEG2_PAR_CONT_CLK: + case OUTMODE_MPEG2_SERIAL: + case OUTMODE_MPEG2_FIFO: + smo_mode = (dib9000_read_word(state, 295) & 0x0010) | (1 << 1); + if (state->chip.d9.cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + dib9000_write_word(state, 295, smo_mode); + break; + } + + outreg = to_fw_output_mode(mode); + return dib9000_mbx_send(state, OUT_MSG_SET_OUTPUT_MODE, &outreg, 1); +} + +static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib9000_state *state = i2c_get_adapdata(i2c_adap); + u16 i, len, t, index_msg; + + for (index_msg = 0; index_msg < num; index_msg++) { + if (msg[index_msg].flags & I2C_M_RD) { /* read */ + len = msg[index_msg].len; + if (len > 16) + len = 16; + + if (dib9000_read_word(state, 790) != 0) + dprintk("TunerITF: read busy"); + + dib9000_write_word(state, 784, (u16) (msg[index_msg].addr)); + dib9000_write_word(state, 787, (len / 2) - 1); + dib9000_write_word(state, 786, 1); /* start read */ + + i = 1000; + while (dib9000_read_word(state, 790) != (len / 2) && i) + i--; + + if (i == 0) + dprintk("TunerITF: read failed"); + + for (i = 0; i < len; i += 2) { + t = dib9000_read_word(state, 785); + msg[index_msg].buf[i] = (t >> 8) & 0xff; + msg[index_msg].buf[i + 1] = (t) & 0xff; + } + if (dib9000_read_word(state, 790) != 0) + dprintk("TunerITF: read more data than expected"); + } else { + i = 1000; + while (dib9000_read_word(state, 789) && i) + i--; + if (i == 0) + dprintk("TunerITF: write busy"); + + len = msg[index_msg].len; + if (len > 16) + len = 16; + + for (i = 0; i < len; i += 2) + dib9000_write_word(state, 785, (msg[index_msg].buf[i] << 8) | msg[index_msg].buf[i + 1]); + dib9000_write_word(state, 784, (u16) msg[index_msg].addr); + dib9000_write_word(state, 787, (len / 2) - 1); + dib9000_write_word(state, 786, 0); /* start write */ + + i = 1000; + while (dib9000_read_word(state, 791) > 0 && i) + i--; + if (i == 0) + dprintk("TunerITF: write failed"); + } + } + return num; +} + +int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) +{ + struct dib9000_state *state = fe->demodulator_priv; + + state->component_bus_speed = speed; + return 0; +} +EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed); + +static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib9000_state *state = i2c_get_adapdata(i2c_adap); + u8 type = 0; /* I2C */ + u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4; + u16 scl = state->component_bus_speed; /* SCL frequency */ + //u16 scl = 208; /* SCL frequency */ + struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER]; + u8 p[13] = { 0 }; + + p[0] = type; + p[1] = port; + p[2] = msg[0].addr << 1; + + p[3] = (u8) scl & 0xff; /* scl */ + p[4] = (u8) (scl >> 8); + +// p[5] = 0; /* attr */ +// p[6] = 0; + +// p[7] = (u8) (msg[0].addr << 1 ); +// p[8] = (u8) (msg[0].addr >> 7 ); + p[7] = 0; + p[8] = 0; + + p[9] = (u8) (msg[0].len); + p[10] = (u8) (msg[0].len >> 8); + if ((num > 1) && (msg[1].flags & I2C_M_RD)) { + p[11] = (u8) (msg[1].len); + p[12] = (u8) (msg[1].len >> 8); + } else { + p[11] = 0; + p[12] = 0; + } + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + + dib9000_risc_mem_write(state, FE_MM_W_COMPONENT_ACCESS, p); + + { /* write-part */ + dib9000_risc_mem_setup_cmd(state, m->addr, msg[0].len, 0); + dib9000_risc_mem_write_chunks(state, msg[0].buf, msg[0].len); + } + + /* do the transaction */ + if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) { + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + return 0; + } + + /* read back any possible result */ + if ((num > 1) && (msg[1].flags & I2C_M_RD)) + dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len); + + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + return num; +} + +static u32 dib9000_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dib9000_tuner_algo = { + .master_xfer = dib9000_tuner_xfer, + .functionality = dib9000_i2c_func, +}; + +static struct i2c_algorithm dib9000_component_bus_algo = { + .master_xfer = dib9000_fw_component_bus_xfer, + .functionality = dib9000_i2c_func, +}; + +struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) +{ + struct dib9000_state *st = fe->demodulator_priv; + return &st->tuner_adap; +} + +EXPORT_SYMBOL(dib9000_get_tuner_interface); + +struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) +{ + struct dib9000_state *st = fe->demodulator_priv; + return &st->component_bus; +} + +EXPORT_SYMBOL(dib9000_get_component_bus_interface); + +struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) +{ + struct dib9000_state *st = fe->demodulator_priv; + return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); +} + +EXPORT_SYMBOL(dib9000_get_i2c_master); + +int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) +{ + struct dib9000_state *st = fe->demodulator_priv; + + st->i2c.i2c_adap = i2c; + return 0; +} + +EXPORT_SYMBOL(dib9000_set_i2c_adapter); + +static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val) +{ + st->gpio_dir = dib9000_read_word(st, 773); + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + dib9000_write_word(st, 773, st->gpio_dir); + + st->gpio_val = dib9000_read_word(st, 774); + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ + dib9000_write_word(st, 774, st->gpio_val); + + dprintk("gpio dir: %04x: gpio val: %04x", st->gpio_dir, st->gpio_val); + + return 0; +} + +int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + struct dib9000_state *state = fe->demodulator_priv; + return dib9000_cfg_gpio(state, num, dir, val); +} + +EXPORT_SYMBOL(dib9000_set_gpio); +int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 val = dib9000_read_word(state, 294 + 1) & 0xffef; + val |= (onoff & 0x1) << 4; + + dprintk("PID filter enabled %d", onoff); + return dib9000_write_word(state, 294 + 1, val); +} + +EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); +int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + struct dib9000_state *state = fe->demodulator_priv; + dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); +} + +EXPORT_SYMBOL(dib9000_fw_pid_filter); + +int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + return dib9000_fw_init(state); +} + +EXPORT_SYMBOL(dib9000_firmware_post_pll_init); + +static void dib9000_release(struct dvb_frontend *demod) +{ + struct dib9000_state *st = demod->demodulator_priv; + u8 index_frontend; + + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) + dvb_frontend_detach(st->fe[index_frontend]); + + DibFreeLock(&state->platform.risc.mbx_if_lock); + DibFreeLock(&state->platform.risc.mbx_lock); + DibFreeLock(&state->platform.risc.mem_lock); + DibFreeLock(&state->platform.risc.mem_mbx_lock); + dibx000_exit_i2c_master(&st->i2c_master); + + i2c_del_adapter(&st->tuner_adap); + i2c_del_adapter(&st->component_bus); + kfree(st->fe[0]); + kfree(st); +} + +static int dib9000_wakeup(struct dvb_frontend *fe) +{ + return 0; +} + +static int dib9000_sleep(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + int ret; + + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); + if (ret < 0) + return ret; + } + return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); +} + +static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 1000; + return 0; +} + +static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend, sub_index_frontend; + fe_status_t stat; + int ret; + + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); + if (stat & FE_HAS_SYNC) { + dprintk("TPS lock on the slave%i", index_frontend); + + /* synchronize the cache with the other frontends */ + state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); + for (sub_index_frontend=0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { + if (sub_index_frontend != index_frontend) { + state->fe[sub_index_frontend]->dtv_property_cache.modulation = state->fe[index_frontend]->dtv_property_cache.modulation; + state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; + state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; + state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; + state->fe[sub_index_frontend]->dtv_property_cache.hierarchy = state->fe[index_frontend]->dtv_property_cache.hierarchy; + state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP = state->fe[index_frontend]->dtv_property_cache.code_rate_HP; + state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP = state->fe[index_frontend]->dtv_property_cache.code_rate_LP; + state->fe[sub_index_frontend]->dtv_property_cache.rolloff = state->fe[index_frontend]->dtv_property_cache.rolloff; + } + } + return 0; + } + } + + /* get the channel from master chip */ + ret = dib9000_fw_get_channel(fe, fep); + if (ret != 0) + return ret; + + /* synchronize the cache with the other frontends */ + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; + state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; + state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; + state->fe[index_frontend]->dtv_property_cache.modulation = fe->dtv_property_cache.modulation; + state->fe[index_frontend]->dtv_property_cache.hierarchy = fe->dtv_property_cache.hierarchy; + state->fe[index_frontend]->dtv_property_cache.code_rate_HP = fe->dtv_property_cache.code_rate_HP; + state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP; + state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff; + } + + return 0; +} + +static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib9000_state *state = fe->demodulator_priv; + state->tune_state = tune_state; + if (tune_state == CT_DEMOD_START) + state->status = FE_STATUS_TUNE_PENDING; + + return 0; +} + +static u32 dib9000_get_status(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + return state->status; +} + +static int dib9000_set_channel_status(struct dvb_frontend *fe, struct dvb_frontend_parametersContext *channel_status) +{ + struct dib9000_state *state = fe->demodulator_priv; + + memcpy(&state->channel_status, channel_status, sizeof(struct dvb_frontend_parametersContext)); + return 0; +} + +static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dib9000_state *state = fe->demodulator_priv; + int sleep_time, sleep_time_slave; + u32 frontend_status; + u8 nbr_pending, exit_condition, index_frontend, index_frontend_success; + struct dvb_frontend_parametersContext channel_status; + + /* check that the correct parameters are set */ + if (state->fe[0]->dtv_property_cache.frequency == 0) { + dprintk("dib9000: must specify frequency "); + return 0; + } + + if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { + dprintk("dib9000: must specify bandwidth "); + return 0; + } + fe->dtv_property_cache.delivery_system = SYS_DVBT; + + /* set the master status */ + if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || + fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + /* no channel specified, autosearch the channel */ + state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; + } else + state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; + + /* set mode and status for the different frontends */ + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib9000_fw_set_diversity_in(state->fe[index_frontend], 1); + + /* synchronization of the cache */ + memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); + + state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_DVBT; + dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_HIGH_Z); + + dib9000_set_channel_status(state->fe[index_frontend], &state->channel_status); + dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); + } + + /* actual tune */ + exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ + index_frontend_success = 0; + do { + sleep_time = dib9000_fw_tune(state->fe[0], NULL); + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + if (sleep_time == FE_CALLBACK_TIME_NEVER) + sleep_time = sleep_time_slave; + else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) + sleep_time = sleep_time_slave; + } + if (sleep_time != FE_CALLBACK_TIME_NEVER) + msleep(sleep_time / 10); + else + break; + + nbr_pending = 0; + exit_condition = 0; + index_frontend_success = 0; + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + frontend_status = -dib9000_get_status(state->fe[index_frontend]); + if (frontend_status > -FE_STATUS_TUNE_PENDING) { + exit_condition = 2; /* tune success */ + index_frontend_success = index_frontend; + break; + } + if (frontend_status == -FE_STATUS_TUNE_PENDING) + nbr_pending++; /* some frontends are still tuning */ + } + if ((exit_condition != 2) && (nbr_pending == 0)) + exit_condition = 1; /* if all tune are done and no success, exit: tune failed */ + + } while (exit_condition == 0); + + /* check the tune result */ + if (exit_condition == 1) { /* tune failed */ + dprintk("tune failed"); + return 0; + } + + dprintk("tune success on frontend%i", index_frontend_success); + + /* synchronize all the channel cache */ + dib9000_get_frontend(state->fe[0], fep); + + /* retune the other frontends with the found channel */ + channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + /* only retune the frontends which was not tuned success */ + if (index_frontend != index_frontend_success) { + dib9000_set_channel_status(state->fe[index_frontend], &channel_status); + dib9000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); + } + } + do { + sleep_time = FE_CALLBACK_TIME_NEVER; + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (index_frontend != index_frontend_success) { + sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); + if (sleep_time == FE_CALLBACK_TIME_NEVER) + sleep_time = sleep_time_slave; + else if ((sleep_time_slave != FE_CALLBACK_TIME_NEVER) && (sleep_time_slave > sleep_time)) + sleep_time = sleep_time_slave; + } + } + if (sleep_time != FE_CALLBACK_TIME_NEVER) + msleep(sleep_time / 10); + else + break; + + nbr_pending = 0; + for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (index_frontend != index_frontend_success) { + frontend_status = -dib9000_get_status(state->fe[index_frontend]); + if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING)) + nbr_pending++; /* some frontends are still tuning */ + } + } + } while (nbr_pending != 0); + + /* set the output mode */ + dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode); + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); + + /* turn off the diversity for the last frontend */ + dib9000_fw_set_diversity_in(state->fe[index_frontend-1], 0); + + return 0; +} + +static u16 dib9000_read_lock(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + + return dib9000_read_word(state, 535); +} + +static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + u16 lock = 0, lock_slave = 0; + + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + lock_slave |= dib9000_read_lock(state->fe[index_frontend]); + + lock = dib9000_read_word(state, 535); + + *stat = 0; + + if ((lock & 0x8000) || (lock_slave & 0x8000)) + *stat |= FE_HAS_SIGNAL; + if ((lock & 0x3000) || (lock_slave & 0x3000)) + *stat |= FE_HAS_CARRIER; + if ((lock & 0x0100) || (lock_slave & 0x0100)) + *stat |= FE_HAS_VITERBI; + if (((lock & 0x0038) == 0x38) || ((lock_slave & 0x0038) == 0x38)) + *stat |= FE_HAS_SYNC; + if ((lock & 0x0008) || (lock_slave & 0x0008)) + *stat |= FE_HAS_LOCK; + + return 0; +} + +static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 c[16]; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + *ber = c[10] << 16 | c[11]; + return 0; +} + +static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + u16 c[16]; + u16 val; + + *strength = 0; + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; + } + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + val = 65535 - c[4]; + if (val > 65535 - *strength) + *strength = 65535; + else + *strength += val; + return 0; +} + +static u32 dib9000_get_snr(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 c[16]; + u32 n, s, exp; + u16 val; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + val = c[7]; + n = (val >> 4) & 0xff; + exp = ((val & 0xf) << 2); + val = c[8]; + exp += ((val >> 14) & 0x3); + if ((exp & 0x20) != 0) + exp -= 0x40; + n <<= exp + 16; + + s = (val >> 6) & 0xFF; + exp = (val & 0x3F); + if ((exp & 0x20) != 0) + exp -= 0x40; + s <<= exp + 16; + + if (n > 0) { + u32 t = (s / n) << 16; + return t + ((s << 16) - n * t) / n; + } + return 0xffffffff; +} + +static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend; + u32 snr_master; + + snr_master = dib9000_get_snr(fe); + for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + snr_master += dib9000_get_snr(state->fe[index_frontend]); + + if ((snr_master >> 16) != 0) { + snr_master = 10 * intlog10(snr_master >> 16); + *snr = snr_master / ((1 << 24) / 10); + } else + *snr = 0; + + return 0; +} + +static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) +{ + struct dib9000_state *state = fe->demodulator_priv; + u16 c[16]; + + DibAcquireLock(&state->platform.risc.mem_mbx_lock); + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) + return -EIO; + dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c)); + DibReleaseLock(&state->platform.risc.mem_mbx_lock); + + *unc = c[12]; + return 0; +} + +int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) +{ + int k = 0; + u8 new_addr = 0; + struct i2c_device client = {.i2c_adap = i2c }; + + client.i2c_addr = default_addr + 16; + dib9000_i2c_write16(&client, 1796, 0x0); // select DVB-T output + + for (k = no_of_demods - 1; k >= 0; k--) { + /* designated i2c address */ + new_addr = first_addr + (k << 1); + client.i2c_addr = default_addr; + + dib9000_i2c_write16(&client, 1817, 3); + dib9000_i2c_write16(&client, 1796, 0); + dib9000_i2c_write16(&client, 1227, 1); + dib9000_i2c_write16(&client, 1227, 0); + + client.i2c_addr = new_addr; + dib9000_i2c_write16(&client, 1817, 3); + dib9000_i2c_write16(&client, 1796, 0); + dib9000_i2c_write16(&client, 1227, 1); + dib9000_i2c_write16(&client, 1227, 0); + + if (dib9000_identify(&client) == 0) { + client.i2c_addr = default_addr; + if (dib9000_identify(&client) == 0) { + dprintk("DiB9000 #%d: not identified", k); + return -EIO; + } + } + + dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6)); + dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2); + + dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + } + + for (k = 0; k < no_of_demods; k++) { + new_addr = first_addr | (k << 1); + client.i2c_addr = new_addr; + + dib9000_i2c_write16(&client, 1794, (new_addr << 2)); + dib9000_i2c_write16(&client, 1795, 0); + } + + return 0; +} + +EXPORT_SYMBOL(dib9000_i2c_enumeration); + +int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { + dprintk("set slave fe %p to index %i", fe_slave, index_frontend); + state->fe[index_frontend] = fe_slave; + return 0; + } + + dprintk("too many slave frontend"); + return -ENOMEM; +} +EXPORT_SYMBOL(dib9000_set_slave_frontend); + +int dib9000_remove_slave_frontend(struct dvb_frontend *fe) +{ + struct dib9000_state *state = fe->demodulator_priv; + u8 index_frontend = 1; + + while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) + index_frontend++; + if (index_frontend != 1) { + dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); + state->fe[index_frontend] = NULL; + return 0; + } + + dprintk("no frontend to be removed"); + return -ENODEV; +} +EXPORT_SYMBOL(dib9000_remove_slave_frontend); + +struct dvb_frontend * dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ + struct dib9000_state *state = fe->demodulator_priv; + + if (slave_index >= MAX_NUMBER_OF_FRONTENDS) + return NULL; + return state->fe[slave_index]; +} +EXPORT_SYMBOL(dib9000_get_slave_frontend); + +static struct dvb_frontend_ops dib9000_ops; +struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg) +{ + struct dvb_frontend *fe; + struct dib9000_state *st; + st = kzalloc(sizeof(struct dib9000_state), GFP_KERNEL); + if (st == NULL) + return NULL; + fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); + if (fe == NULL) + return NULL; + + memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config)); + st->i2c.i2c_adap = i2c_adap; + st->i2c.i2c_addr = i2c_addr; + + st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS; + st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES; + st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS; + + DibInitLock(&st->platform.risc.mbx_if_lock); + DibInitLock(&st->platform.risc.mbx_lock); + DibInitLock(&st->platform.risc.mem_lock); + DibInitLock(&st->platform.risc.mem_mbx_lock); + + st->fe[0] = fe; + fe->demodulator_priv = st; + memcpy(&st->fe[0]->ops, &dib9000_ops, sizeof(struct dvb_frontend_ops)); + + /* Ensure the output mode remains at the previous default if it's + * not specifically set by the caller. + */ + if ((st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->chip.d9.cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) + st->chip.d9.cfg.output_mode = OUTMODE_MPEG2_FIFO; + + if (dib9000_identify(&st->i2c) == 0) + goto error; + + dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr); + + st->tuner_adap.dev.parent = i2c_adap->dev.parent; + strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name)); + st->tuner_adap.algo = &dib9000_tuner_algo; + st->tuner_adap.algo_data = NULL; + i2c_set_adapdata(&st->tuner_adap, st); + if (i2c_add_adapter(&st->tuner_adap) < 0) + goto error; + + st->component_bus.dev.parent = i2c_adap->dev.parent; + strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name)); + st->component_bus.algo = &dib9000_component_bus_algo; + st->component_bus.algo_data = NULL; + st->component_bus_speed = 340; + i2c_set_adapdata(&st->component_bus, st); + if (i2c_add_adapter(&st->component_bus) < 0) + goto component_bus_add_error; + + dib9000_fw_reset(fe); + + return fe; + + component_bus_add_error: + i2c_del_adapter(&st->tuner_adap); + error: + kfree(st); + return NULL; +} + +EXPORT_SYMBOL(dib9000_attach); + +static struct dvb_frontend_ops dib9000_ops = { + .info = { + .name = "DiBcom 9000", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib9000_release, + + .init = dib9000_wakeup, + .sleep = dib9000_sleep, + + .set_frontend = dib9000_set_frontend, + .get_tune_settings = dib9000_fe_get_tune_settings, + .get_frontend = dib9000_get_frontend, + + .read_status = dib9000_read_status, + .read_ber = dib9000_read_ber, + .read_signal_strength = dib9000_read_signal_strength, + .read_snr = dib9000_read_snr, + .read_ucblocks = dib9000_read_unc_blocks, +}; + +MODULE_AUTHOR("Patrick Boettcher "); +MODULE_AUTHOR("Olivier Grenie "); +MODULE_DESCRIPTION("Driver for the DiBcom 9000 COFDM demodulator"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib9000.h b/drivers/media/dvb/frontends/dib9000.h new file mode 100644 index 000000000000..995e4bc48a7d --- /dev/null +++ b/drivers/media/dvb/frontends/dib9000.h @@ -0,0 +1,130 @@ +#ifndef DIB9000_H +#define DIB9000_H + +#include "dibx000_common.h" + +struct dib9000_config { + u8 dvbt_mode; + u8 output_mpeg2_in_188_bytes; + u8 hostbus_diversity; + struct dibx000_bandwidth_config *bw; + + u16 if_drives; + + u32 timing_frequency; + u32 xtal_clock_khz; + u32 vcxo_timer; + u32 demod_clock_khz; + + const u8 *microcode_B_fe_buffer; + u32 microcode_B_fe_size; + + struct dibGPIOFunction gpio_function[2]; + struct dibSubbandSelection subband; + + u8 output_mode; +}; + +#define DEFAULT_DIB9000_I2C_ADDRESS 18 + +#if defined(CONFIG_DVB_DIB9000) || (defined(CONFIG_DVB_DIB9000_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg); +extern int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr); +extern struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe); +extern struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating); +extern int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val); +extern int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); +extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff); +extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe); +extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); +extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe); +extern struct dvb_frontend * dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); +extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe); +extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c); +extern int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed); +#else +static inline struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib9000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib9000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +int dib9000_remove_slave_frontend(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct dvb_frontend * dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif + +#endif diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index b7ad066b7e52..c4fd62f8df51 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -219,6 +219,51 @@ struct dvb_frontend_parametersContext { #define FE_CALLBACK_TIME_NEVER 0xffffffff -#define ABS(x) ((x < 0) ? (-x) : (x)) +#define ABS(x) ((x<0)?(-x):(x)) + +#define DATA_BUS_ACCESS_MODE_8BIT 0x01 +#define DATA_BUS_ACCESS_MODE_16BIT 0x02 +#define DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT 0x10 + +struct dibGPIOFunction { +#define BOARD_GPIO_COMPONENT_BUS_ADAPTER 1 +#define BOARD_GPIO_COMPONENT_DEMOD 2 + u8 component; + +#define BOARD_GPIO_FUNCTION_BOARD_ON 1 +#define BOARD_GPIO_FUNCTION_BOARD_OFF 2 +#define BOARD_GPIO_FUNCTION_COMPONENT_ON 3 +#define BOARD_GPIO_FUNCTION_COMPONENT_OFF 4 +#define BOARD_GPIO_FUNCTION_SUBBAND_PWM 5 +#define BOARD_GPIO_FUNCTION_SUBBAND_GPIO 6 + u8 function; + +/* mask, direction and value are used specify which GPIO to change GPIO0 + * is LSB and possible GPIO31 is MSB. The same bit-position as in the + * mask is used for the direction and the value. Direction == 1 is OUT, + * 0 == IN. For direction "OUT" value is either 1 or 0, for direction IN + * value has no meaning. + * + * In case of BOARD_GPIO_FUNCTION_PWM mask is giving the GPIO to be + * used to do the PWM. Direction gives the PWModulator to be used. + * Value gives the PWM value in device-dependent scale. + */ + u32 mask; + u32 direction; + u32 value; +}; + +#define MAX_NB_SUBBANDS 8 +struct dibSubbandSelection { + u8 size; /* Actual number of subbands. */ + struct { + u16 f_mhz; + struct dibGPIOFunction gpio; + } subband[MAX_NB_SUBBANDS]; +}; + +#define DEMOD_TIMF_SET 0x00 +#define DEMOD_TIMF_GET 0x01 +#define DEMOD_TIMF_UPDATE 0x02 #endif -- cgit v1.2.2 From 713d54a8bd812229410a1902cd9b332a2a27af9f Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Tue, 4 Jan 2011 04:54:31 -0300 Subject: [media] DiB7090: add support for the dib7090 based This patch adds support for the SoC DiB7090 DVB-T demodulator and its melt-in UHF/VHF RF tuner. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib7000p.c | 1950 +++++++++++++++++++------- drivers/media/dvb/frontends/dib7000p.h | 96 +- drivers/media/dvb/frontends/dibx000_common.h | 84 +- 3 files changed, 1543 insertions(+), 587 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 6aa02cb80733..18495bd166e6 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -26,24 +26,29 @@ MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (defau #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) +struct i2c_device { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; +}; + struct dib7000p_state { struct dvb_frontend demod; - struct dib7000p_config cfg; + struct dib7000p_config cfg; u8 i2c_addr; - struct i2c_adapter *i2c_adap; + struct i2c_adapter *i2c_adap; struct dibx000_i2c_master i2c_master; u16 wbd_ref; - u8 current_band; + u8 current_band; u32 current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; - u8 div_force_off : 1; - u8 div_state : 1; + u8 div_force_off:1; + u8 div_state:1; u16 div_sync_wait; u8 agc_state; @@ -51,7 +56,13 @@ struct dib7000p_state { u16 gpio_dir; u16 gpio_val; - u8 sfn_workaround_active :1; + u8 sfn_workaround_active:1; + +#define SOC7090 0x7090 + u16 version; + + u16 tuner_enable; + struct i2c_adapter dib7090_tuner_adap; }; enum dib7000p_power_mode { @@ -60,17 +71,20 @@ enum dib7000p_power_mode { DIB7000P_POWER_INTERFACE_ONLY, }; +static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode); +static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); + static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) { u8 wb[2] = { reg >> 8, reg & 0xff }; u8 rb[2]; struct i2c_msg msg[2] = { - { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 }, - { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 }, + {.addr = state->i2c_addr >> 1,.flags = 0,.buf = wb,.len = 2}, + {.addr = state->i2c_addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2}, }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) - dprintk("i2c read error on %d",reg); + dprintk("i2c read error on %d", reg); return (rb[0] << 8) | rb[1]; } @@ -82,11 +96,12 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) (val >> 8) & 0xff, val & 0xff, }; struct i2c_msg msg = { - .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 + .addr = state->i2c_addr >> 1,.flags = 0,.buf = b,.len = 4 }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } -static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf) + +static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) { u16 l = 0, r, *n; n = buf; @@ -104,54 +119,54 @@ static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf) static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) { - int ret = 0; + int ret = 0; u16 outreg, fifo_threshold, smo_mode; outreg = 0; fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); - dprintk( "setting output mode for demod %p to %d", - &state->demod, mode); + dprintk("setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock - outreg = (1 << 10); /* 0x0400 */ - break; - case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock - outreg = (1 << 10) | (1 << 6); /* 0x0440 */ - break; - case OUTMODE_MPEG2_SERIAL: // STBs with serial input - outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */ - break; - case OUTMODE_DIVERSITY: - if (state->cfg.hostbus_diversity) - outreg = (1 << 10) | (4 << 6); /* 0x0500 */ - else - outreg = (1 << 11); - break; - case OUTMODE_MPEG2_FIFO: // e.g. USB feeding - smo_mode |= (3 << 1); - fifo_threshold = 512; - outreg = (1 << 10) | (5 << 6); - break; - case OUTMODE_ANALOG_ADC: - outreg = (1 << 10) | (3 << 6); - break; - case OUTMODE_HIGH_Z: // disable - outreg = 0; - break; - default: - dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); - break; + case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock + outreg = (1 << 10); /* 0x0400 */ + break; + case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock + outreg = (1 << 10) | (1 << 6); /* 0x0440 */ + break; + case OUTMODE_MPEG2_SERIAL: // STBs with serial input + outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */ + break; + case OUTMODE_DIVERSITY: + if (state->cfg.hostbus_diversity) + outreg = (1 << 10) | (4 << 6); /* 0x0500 */ + else + outreg = (1 << 11); + break; + case OUTMODE_MPEG2_FIFO: // e.g. USB feeding + smo_mode |= (3 << 1); + fifo_threshold = 512; + outreg = (1 << 10) | (5 << 6); + break; + case OUTMODE_ANALOG_ADC: + outreg = (1 << 10) | (3 << 6); + break; + case OUTMODE_HIGH_Z: // disable + outreg = 0; + break; + default: + dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod); + break; } if (state->cfg.output_mpeg2_in_188_bytes) - smo_mode |= (1 << 5) ; + smo_mode |= (1 << 5); - ret |= dib7000p_write_word(state, 235, smo_mode); - ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ - ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */ + ret |= dib7000p_write_word(state, 235, smo_mode); + ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ + if (state->version != SOC7090) + ret |= dib7000p_write_word(state, 1286, outreg); /* P_Div_active */ return ret; } @@ -161,13 +176,13 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) struct dib7000p_state *state = demod->demodulator_priv; if (state->div_force_off) { - dprintk( "diversity combination deactivated - forced by COFDM parameters"); + dprintk("diversity combination deactivated - forced by COFDM parameters"); onoff = 0; dib7000p_write_word(state, 207, 0); } else dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0)); - state->div_state = (u8)onoff; + state->div_state = (u8) onoff; if (onoff) { dib7000p_write_word(state, 204, 6); @@ -184,37 +199,48 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode) { /* by default everything is powered off */ - u16 reg_774 = 0xffff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, - reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff); + u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0x0007, reg_899 = 0x0003, reg_1280 = (0xfe00) | (dib7000p_read_word(state, 1280) & 0x01ff); /* now, depending on the requested mode, we power on */ switch (mode) { /* power up everything in the demod */ - case DIB7000P_POWER_ALL: - reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff; - break; - - case DIB7000P_POWER_ANALOG_ADC: - /* dem, cfg, iqc, sad, agc */ - reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); - /* nud */ - reg_776 &= ~((1 << 0)); - /* Dout */ + case DIB7000P_POWER_ALL: + reg_774 = 0x0000; + reg_775 = 0x0000; + reg_776 = 0x0; + reg_899 = 0x0; + if (state->version == SOC7090) + reg_1280 &= 0x001f; + else + reg_1280 &= 0x01ff; + break; + + case DIB7000P_POWER_ANALOG_ADC: + /* dem, cfg, iqc, sad, agc */ + reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9)); + /* nud */ + reg_776 &= ~((1 << 0)); + /* Dout */ + if (state->version != SOC7090) reg_1280 &= ~((1 << 11)); - /* fall through wanted to enable the interfaces */ + reg_1280 &= ~(1 << 6); + /* fall through wanted to enable the interfaces */ /* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */ - case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ + case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */ + if (state->version == SOC7090) + reg_1280 &= ~((1 << 7) | (1 << 5)); + else reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10)); - break; + break; /* TODO following stuff is just converted from the dib7000-driver - check when is used what */ } - dib7000p_write_word(state, 774, reg_774); - dib7000p_write_word(state, 775, reg_775); - dib7000p_write_word(state, 776, reg_776); - dib7000p_write_word(state, 899, reg_899); + dib7000p_write_word(state, 774, reg_774); + dib7000p_write_word(state, 775, reg_775); + dib7000p_write_word(state, 776, reg_776); + dib7000p_write_word(state, 899, reg_899); dib7000p_write_word(state, 1280, reg_1280); return 0; @@ -222,40 +248,57 @@ static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_p static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_adc_states no) { - u16 reg_908 = dib7000p_read_word(state, 908), - reg_909 = dib7000p_read_word(state, 909); + u16 reg_908 = dib7000p_read_word(state, 908), reg_909 = dib7000p_read_word(state, 909); + u16 reg; switch (no) { - case DIBX000_SLOW_ADC_ON: + case DIBX000_SLOW_ADC_ON: + if (state->version == SOC7090) { + reg = dib7000p_read_word(state, 1925); + + dib7000p_write_word(state, 1925, reg | (1 << 4) | (1 << 2)); /* en_slowAdc = 1 & reset_sladc = 1 */ + + reg = dib7000p_read_word(state, 1925); /* read acces to make it works... strange ... */ + msleep(200); + dib7000p_write_word(state, 1925, reg & ~(1 << 4)); /* en_slowAdc = 1 & reset_sladc = 0 */ + + reg = dib7000p_read_word(state, 72) & ~((0x3 << 14) | (0x3 << 12)); + dib7000p_write_word(state, 72, reg | (1 << 14) | (3 << 12) | 524); /* ref = Vin1 => Vbg ; sel = Vin0 or Vin3 ; (Vin2 = Vcm) */ + } else { reg_909 |= (1 << 1) | (1 << 0); dib7000p_write_word(state, 909, reg_909); reg_909 &= ~(1 << 1); - break; + } + break; - case DIBX000_SLOW_ADC_OFF: - reg_909 |= (1 << 1) | (1 << 0); - break; + case DIBX000_SLOW_ADC_OFF: + if (state->version == SOC7090) { + reg = dib7000p_read_word(state, 1925); + dib7000p_write_word(state, 1925, (reg & ~(1 << 2)) | (1 << 4)); /* reset_sladc = 1 en_slowAdc = 0 */ + } else + reg_909 |= (1 << 1) | (1 << 0); + break; - case DIBX000_ADC_ON: - reg_908 &= 0x0fff; - reg_909 &= 0x0003; - break; + case DIBX000_ADC_ON: + reg_908 &= 0x0fff; + reg_909 &= 0x0003; + break; - case DIBX000_ADC_OFF: // leave the VBG voltage on - reg_908 |= (1 << 14) | (1 << 13) | (1 << 12); - reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); - break; + case DIBX000_ADC_OFF: // leave the VBG voltage on + reg_908 |= (1 << 14) | (1 << 13) | (1 << 12); + reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); + break; - case DIBX000_VBG_ENABLE: - reg_908 &= ~(1 << 15); - break; + case DIBX000_VBG_ENABLE: + reg_908 &= ~(1 << 15); + break; - case DIBX000_VBG_DISABLE: - reg_908 |= (1 << 15); - break; + case DIBX000_VBG_DISABLE: + reg_908 |= (1 << 15); + break; - default: - break; + default: + break; } // dprintk( "908: %x, 909: %x\n", reg_908, reg_909); @@ -275,17 +318,17 @@ static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) state->current_bandwidth = bw; if (state->timf == 0) { - dprintk( "using default timf"); + dprintk("using default timf"); timf = state->cfg.bw->timf; } else { - dprintk( "using updated timf"); + dprintk("using updated timf"); timf = state->timf; } timf = timf * (bw / 50) / 160; dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff)); - dib7000p_write_word(state, 24, (u16) ((timf ) & 0xffff)); + dib7000p_write_word(state, 24, (u16) ((timf) & 0xffff)); return 0; } @@ -295,7 +338,11 @@ static int dib7000p_sad_calib(struct dib7000p_state *state) /* internal */ // dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); - dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096 + + if (state->version == SOC7090) + dib7000p_write_word(state, 74, 2048); // P_sad_calib_value = (0.9/1.8)*4096 + else + dib7000p_write_word(state, 74, 776); // P_sad_calib_value = 0.625*3.3 / 4096 /* do the calibration */ dib7000p_write_word(state, 73, (1 << 0)); @@ -314,37 +361,92 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value) state->wbd_ref = value; return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value); } - EXPORT_SYMBOL(dib7000p_set_wbd_ref); + static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; u16 clk_cfg0; - /* force PLL bypass */ - clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | - (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | - (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); + if (state->version == SOC7090) { + dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv)); - dib7000p_write_word(state, 900, clk_cfg0); + while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) { + } + + dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15)); + } else { + /* force PLL bypass */ + clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) | + (bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0); - /* P_pll_cfg */ - dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); - clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); - dib7000p_write_word(state, 900, clk_cfg0); + dib7000p_write_word(state, 900, clk_cfg0); + + /* P_pll_cfg */ + dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset); + clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff); + dib7000p_write_word(state, 900, clk_cfg0); + } - dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff)); - dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000 ) & 0xffff)); - dib7000p_write_word(state, 21, (u16) ( (bw->ifreq >> 16) & 0xffff)); - dib7000p_write_word(state, 22, (u16) ( (bw->ifreq ) & 0xffff)); + dib7000p_write_word(state, 18, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) ((bw->internal * 1000) & 0xffff)); + dib7000p_write_word(state, 21, (u16) ((bw->ifreq >> 16) & 0xffff)); + dib7000p_write_word(state, 22, (u16) ((bw->ifreq) & 0xffff)); dib7000p_write_word(state, 72, bw->sad_cfg); } +static u32 dib7000p_get_internal_freq(struct dib7000p_state *state) +{ + u32 internal = (u32) dib7000p_read_word(state, 18) << 16; + internal |= (u32) dib7000p_read_word(state, 19); + internal /= 1000; + + return internal; +} + +int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856); + u8 loopdiv, prediv; + u32 internal, xtal; + + /* get back old values */ + prediv = reg_1856 & 0x3f; + loopdiv = (reg_1856 >> 6) & 0x3f; + + if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) { + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); + reg_1856 &= 0xf000; + reg_1857 = dib7000p_read_word(state, 1857); + dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); // desable pll + + dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f)); + + /* write new system clk into P_sec_len */ + internal = dib7000p_get_internal_freq(state); + xtal = (internal / loopdiv) * prediv; + internal = 1000 * (xtal / bw->pll_prediv) * bw->pll_ratio; /* new internal */ + dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff)); + dib7000p_write_word(state, 19, (u16) (internal & 0xffff)); + + dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); // enable pll + + while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) { + dprintk("Waiting for PLL to lock"); + } + + return 0; + } + return -EIO; +} +EXPORT_SYMBOL(dib7000p_update_pll); + static int dib7000p_reset_gpio(struct dib7000p_state *st) { /* reset the GPIOs */ - dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos); + dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); @@ -360,13 +462,13 @@ static int dib7000p_reset_gpio(struct dib7000p_state *st) static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val) { st->gpio_dir = dib7000p_read_word(st, 1029); - st->gpio_dir &= ~(1 << num); /* reset the direction bit */ - st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ + st->gpio_dir &= ~(1 << num); /* reset the direction bit */ + st->gpio_dir |= (dir & 0x1) << num; /* set the new direction */ dib7000p_write_word(st, 1029, st->gpio_dir); st->gpio_val = dib7000p_read_word(st, 1030); - st->gpio_val &= ~(1 << num); /* reset the direction bit */ - st->gpio_val |= (val & 0x01) << num; /* set the new value */ + st->gpio_val &= ~(1 << num); /* reset the direction bit */ + st->gpio_val |= (val & 0x01) << num; /* set the new value */ dib7000p_write_word(st, 1030, st->gpio_val); return 0; @@ -377,96 +479,97 @@ int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val) struct dib7000p_state *state = demod->demodulator_priv; return dib7000p_cfg_gpio(state, num, dir, val); } - EXPORT_SYMBOL(dib7000p_set_gpio); -static u16 dib7000p_defaults[] = -{ +static u16 dib7000p_defaults[] = { // auto search configuration 3, 2, - 0x0004, - 0x1000, - 0x0814, /* Equal Lock */ + 0x0004, + 0x1000, + 0x0814, /* Equal Lock */ 12, 6, - 0x001b, - 0x7740, - 0x005b, - 0x8d80, - 0x01c9, - 0xc380, - 0x0000, - 0x0080, - 0x0000, - 0x0090, - 0x0001, - 0xd4c0, + 0x001b, + 0x7740, + 0x005b, + 0x8d80, + 0x01c9, + 0xc380, + 0x0000, + 0x0080, + 0x0000, + 0x0090, + 0x0001, + 0xd4c0, 1, 26, - 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 + 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 /* set ADC level to -16 */ 11, 79, - (1 << 13) - 825 - 117, - (1 << 13) - 837 - 117, - (1 << 13) - 811 - 117, - (1 << 13) - 766 - 117, - (1 << 13) - 737 - 117, - (1 << 13) - 693 - 117, - (1 << 13) - 648 - 117, - (1 << 13) - 619 - 117, - (1 << 13) - 575 - 117, - (1 << 13) - 531 - 117, - (1 << 13) - 501 - 117, + (1 << 13) - 825 - 117, + (1 << 13) - 837 - 117, + (1 << 13) - 811 - 117, + (1 << 13) - 766 - 117, + (1 << 13) - 737 - 117, + (1 << 13) - 693 - 117, + (1 << 13) - 648 - 117, + (1 << 13) - 619 - 117, + (1 << 13) - 575 - 117, + (1 << 13) - 531 - 117, + (1 << 13) - 501 - 117, 1, 142, - 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 + 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 /* disable power smoothing */ 8, 145, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 1, 154, - 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 + 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 1, 168, - 0x0ccd, // P_pha3_thres, default 0x3000 + 0x0ccd, // P_pha3_thres, default 0x3000 // 1, 169, // 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 1, 183, - 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + + 1, 212, + 0x169, // P_vit_ksi_dwn = 5 P_vit_ksi_up = 5 0x1e1, // P_vit_ksi_dwn = 4 P_vit_ksi_up = 7 5, 187, - 0x023d, // P_adp_regul_cnt=573, default: 410 - 0x00a4, // P_adp_noise_cnt= - 0x00a4, // P_adp_regul_ext - 0x7ff0, // P_adp_noise_ext - 0x3ccc, // P_adp_fil + 0x023d, // P_adp_regul_cnt=573, default: 410 + 0x00a4, // P_adp_noise_cnt= + 0x00a4, // P_adp_regul_ext + 0x7ff0, // P_adp_noise_ext + 0x3ccc, // P_adp_fil 1, 198, - 0x800, // P_equal_thres_wgn + 0x800, // P_equal_thres_wgn 1, 222, - 0x0010, // P_fec_ber_rs_len=2 + 0x0010, // P_fec_ber_rs_len=2 1, 235, - 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard 2, 901, - 0x0006, // P_clk_cfg1 - (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 + 0x0006, // P_clk_cfg1 + (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 1, 905, - 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive + 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive 0, }; @@ -475,51 +578,65 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) { dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + if (state->version == SOC7090) + dibx000_reset_i2c_master(&state->i2c_master); + dib7000p_set_adc_state(state, DIBX000_VBG_ENABLE); /* restart all parts */ - dib7000p_write_word(state, 770, 0xffff); - dib7000p_write_word(state, 771, 0xffff); - dib7000p_write_word(state, 772, 0x001f); - dib7000p_write_word(state, 898, 0x0003); - /* except i2c, sdio, gpio - control interfaces */ - dib7000p_write_word(state, 1280, 0x01fc - ((1 << 7) | (1 << 6) | (1 << 5)) ); - - dib7000p_write_word(state, 770, 0); - dib7000p_write_word(state, 771, 0); - dib7000p_write_word(state, 772, 0); - dib7000p_write_word(state, 898, 0); + dib7000p_write_word(state, 770, 0xffff); + dib7000p_write_word(state, 771, 0xffff); + dib7000p_write_word(state, 772, 0x001f); + dib7000p_write_word(state, 898, 0x0003); + dib7000p_write_word(state, 1280, 0x001f - ((1 << 4) | (1 << 3))); + + dib7000p_write_word(state, 770, 0); + dib7000p_write_word(state, 771, 0); + dib7000p_write_word(state, 772, 0); + dib7000p_write_word(state, 898, 0); dib7000p_write_word(state, 1280, 0); /* default */ dib7000p_reset_pll(state); if (dib7000p_reset_gpio(state) != 0) - dprintk( "GPIO reset was not successful."); + dprintk("GPIO reset was not successful."); - if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk( "OUTPUT_MODE could not be reset."); + if (state->version == SOC7090) { + dib7000p_write_word(state, 899, 0); - /* unforce divstr regardless whether i2c enumeration was done or not */ - dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) ); - - dib7000p_set_bandwidth(state, 8000); + /* impulse noise */ + dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */ + dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */ + dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */ + //dib7000p_write_word(state, 273, (1<<6) | 10); /* P_vit_inoise_sel = 1, P_vit_inoise_gain = 10*/ + dib7000p_write_word(state, 273, (1<<6) | 30); //26/* P_vit_inoise_sel = 1, P_vit_inoise_gain = 26*/// FAG + } + if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) + dprintk("OUTPUT_MODE could not be reset."); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib7000p_sad_calib(state); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF); - // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... - if(state->cfg.tuner_is_baseband) - dib7000p_write_word(state, 36,0x0755); - else - dib7000p_write_word(state, 36,0x1f55); + /* unforce divstr regardless whether i2c enumeration was done or not */ + dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1)); + + dib7000p_set_bandwidth(state, 8000); + + if(state->version == SOC7090) { + dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ + } else { // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... + if (state->cfg.tuner_is_baseband) + dib7000p_write_word(state, 36, 0x0755); + else + dib7000p_write_word(state, 36, 0x1f55); + } dib7000p_write_tab(state, dib7000p_defaults); dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); - return 0; } @@ -527,9 +644,9 @@ static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) { u16 tmp = 0; tmp = dib7000p_read_word(state, 903); - dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll + dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll tmp = dib7000p_read_word(state, 900); - dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock + dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock } static void dib7000p_restart_agc(struct dib7000p_state *state) @@ -547,7 +664,7 @@ static int dib7000p_update_lna(struct dib7000p_state *state) if (state->cfg.update_lna) { // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000p_read_word(state, 394); - if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed + if (state->cfg.update_lna(&state->demod, dyn_gain)) { // LNA has changed dib7000p_restart_agc(state); return 1; } @@ -571,24 +688,24 @@ static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) } if (agc == NULL) { - dprintk( "no valid AGC configuration found for band 0x%02x",band); + dprintk("no valid AGC configuration found for band 0x%02x", band); return -EINVAL; } state->current_agc = agc; /* AGC */ - dib7000p_write_word(state, 75 , agc->setup ); - dib7000p_write_word(state, 76 , agc->inv_gain ); - dib7000p_write_word(state, 77 , agc->time_stabiliz ); + dib7000p_write_word(state, 75, agc->setup); + dib7000p_write_word(state, 76, agc->inv_gain); + dib7000p_write_word(state, 77, agc->time_stabiliz); dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock); // Demod AGC loop configuration dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp); - dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); + dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); /* AGC continued */ - dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); if (state->wbd_ref != 0) @@ -598,101 +715,139 @@ static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8)); - dib7000p_write_word(state, 107, agc->agc1_max); - dib7000p_write_word(state, 108, agc->agc1_min); - dib7000p_write_word(state, 109, agc->agc2_max); - dib7000p_write_word(state, 110, agc->agc2_min); - dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); - dib7000p_write_word(state, 112, agc->agc1_pt3); + dib7000p_write_word(state, 107, agc->agc1_max); + dib7000p_write_word(state, 108, agc->agc1_min); + dib7000p_write_word(state, 109, agc->agc2_max); + dib7000p_write_word(state, 110, agc->agc2_min); + dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2); + dib7000p_write_word(state, 112, agc->agc1_pt3); dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2); - dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); + dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2); dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2); return 0; } +static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) +{ + u32 internal = dib7000p_get_internal_freq(state); + s32 unit_khz_dds_val = 67108864 / (internal); /* 2**26 / Fsampling is the unit 1KHz offset */ + u32 abs_offset_khz = ABS(offset_khz); + u32 dds = state->cfg.bw->ifreq & 0x1ffffff; + u8 invert = !!(state->cfg.bw->ifreq & (1 << 25)); + + dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert); + + if (offset_khz < 0) + unit_khz_dds_val *= -1; + + /* IF tuner */ + if (invert) + dds -= (abs_offset_khz * unit_khz_dds_val); /* /100 because of /100 on the unit_khz_dds_val line calc for better accuracy */ + else + dds += (abs_offset_khz * unit_khz_dds_val); + + if (abs_offset_khz <= (internal / 2)) { /* Max dds offset is the half of the demod freq */ + dib7000p_write_word(state, 21, (u16) (((dds >> 16) & 0x1ff) | (0 << 10) | (invert << 9))); + dib7000p_write_word(state, 22, (u16) (dds & 0xffff)); + } +} + static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) { struct dib7000p_state *state = demod->demodulator_priv; int ret = -1; u8 *agc_state = &state->agc_state; u8 agc_split; + u16 reg; + u32 upd_demod_gain_period = 0x1000; switch (state->agc_state) { - case 0: - // set power-up level: interf+analog+AGC - dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + case 0: + // set power-up level: interf+analog+AGC + dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); + if (state->version == SOC7090) { + reg = dib7000p_read_word(state, 0x79b) & 0xff00; + dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */ + dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF)); // bit 14 = enDemodGain + + /* enable adc i & q */ + reg = dib7000p_read_word(state, 0x780); + dib7000p_write_word(state, 0x780, (reg | (0x3)) & (~(1 << 7))); + } else { dib7000p_set_adc_state(state, DIBX000_ADC_ON); dib7000p_pll_clk_cfg(state); + } - if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0) - return -1; - - ret = 7; - (*agc_state)++; - break; + if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0) + return -1; - case 1: - // AGC initialization - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 1); - - dib7000p_write_word(state, 78, 32768); - if (!state->current_agc->perform_agc_softsplit) { - /* we are using the wbd - so slow AGC startup */ - /* force 0 split on WBD and restart AGC */ - dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); - (*agc_state)++; - ret = 5; - } else { - /* default AGC startup */ - (*agc_state) = 4; - /* wait AGC rough lock time */ - ret = 7; - } + dib7000p_set_dds(state, 0); + ret = 7; + (*agc_state)++; + break; - dib7000p_restart_agc(state); - break; + case 1: + // AGC initialization + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 1); - case 2: /* fast split search path after 5sec */ - dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ - dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + dib7000p_write_word(state, 78, 32768); + if (!state->current_agc->perform_agc_softsplit) { + /* we are using the wbd - so slow AGC startup */ + /* force 0 split on WBD and restart AGC */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8)); (*agc_state)++; - ret = 14; - break; + ret = 5; + } else { + /* default AGC startup */ + (*agc_state) = 4; + /* wait AGC rough lock time */ + ret = 7; + } - case 3: /* split search ended */ - agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */ - dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ + dib7000p_restart_agc(state); + break; - dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ - dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ + case 2: /* fast split search path after 5sec */ + dib7000p_write_word(state, 75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */ + (*agc_state)++; + ret = 14; + break; - dib7000p_restart_agc(state); + case 3: /* split search ended */ + agc_split = (u8) dib7000p_read_word(state, 396); /* store the split value for the next time */ + dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */ - dprintk( "SPLIT %p: %hd", demod, agc_split); + dib7000p_write_word(state, 75, state->current_agc->setup); /* std AGC loop */ + dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */ - (*agc_state)++; - ret = 5; - break; + dib7000p_restart_agc(state); - case 4: /* LNA startup */ - // wait AGC accurate lock time - ret = 7; + dprintk("SPLIT %p: %hd", demod, agc_split); - if (dib7000p_update_lna(state)) - // wait only AGC rough lock time - ret = 5; - else // nothing was done, go to the next state - (*agc_state)++; - break; + (*agc_state)++; + ret = 5; + break; - case 5: - if (state->cfg.agc_control) - state->cfg.agc_control(&state->demod, 0); + case 4: /* LNA startup */ + // wait AGC accurate lock time + ret = 7; + + if (dib7000p_update_lna(state)) + // wait only AGC rough lock time + ret = 5; + else // nothing was done, go to the next state (*agc_state)++; - break; - default: - break; + break; + + case 5: + if (state->cfg.agc_control) + state->cfg.agc_control(&state->demod, 0); + (*agc_state)++; + break; + default: + break; } return ret; } @@ -703,45 +858,89 @@ static void dib7000p_update_timf(struct dib7000p_state *state) state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000p_write_word(state, 23, (u16) (timf >> 16)); dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf); + dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf); + +} +u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) +{ + struct dib7000p_state *state = fe->demodulator_priv; + switch (op) { + case DEMOD_TIMF_SET: + state->timf = timf; + break; + case DEMOD_TIMF_UPDATE: + dib7000p_update_timf(state); + break; + case DEMOD_TIMF_GET: + break; + } + dib7000p_set_bandwidth(state, state->current_bandwidth); + return state->timf; } +EXPORT_SYMBOL(dib7000p_ctrl_timf); static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq) { u16 value, est[4]; - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); /* nfft, guard, qam, alpha */ value = 0; switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: value |= (0 << 7); break; - case TRANSMISSION_MODE_4K: value |= (2 << 7); break; - default: - case TRANSMISSION_MODE_8K: value |= (1 << 7); break; + case TRANSMISSION_MODE_2K: + value |= (0 << 7); + break; + case TRANSMISSION_MODE_4K: + value |= (2 << 7); + break; + default: + case TRANSMISSION_MODE_8K: + value |= (1 << 7); + break; } switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_32: value |= (0 << 5); break; - case GUARD_INTERVAL_1_16: value |= (1 << 5); break; - case GUARD_INTERVAL_1_4: value |= (3 << 5); break; - default: - case GUARD_INTERVAL_1_8: value |= (2 << 5); break; + case GUARD_INTERVAL_1_32: + value |= (0 << 5); + break; + case GUARD_INTERVAL_1_16: + value |= (1 << 5); + break; + case GUARD_INTERVAL_1_4: + value |= (3 << 5); + break; + default: + case GUARD_INTERVAL_1_8: + value |= (2 << 5); + break; } switch (ch->u.ofdm.constellation) { - case QPSK: value |= (0 << 3); break; - case QAM_16: value |= (1 << 3); break; - default: - case QAM_64: value |= (2 << 3); break; + case QPSK: + value |= (0 << 3); + break; + case QAM_16: + value |= (1 << 3); + break; + default: + case QAM_64: + value |= (2 << 3); + break; } switch (HIERARCHY_1) { - case HIERARCHY_2: value |= 2; break; - case HIERARCHY_4: value |= 4; break; - default: - case HIERARCHY_1: value |= 1; break; + case HIERARCHY_2: + value |= 2; + break; + case HIERARCHY_4: + value |= 4; + break; + default: + case HIERARCHY_1: + value |= 1; + break; } dib7000p_write_word(state, 0, value); - dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ + dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */ /* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */ value = 0; @@ -752,39 +951,63 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte if (1 == 1) value |= 1; switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) { - case FEC_2_3: value |= (2 << 1); break; - case FEC_3_4: value |= (3 << 1); break; - case FEC_5_6: value |= (5 << 1); break; - case FEC_7_8: value |= (7 << 1); break; - default: - case FEC_1_2: value |= (1 << 1); break; + case FEC_2_3: + value |= (2 << 1); + break; + case FEC_3_4: + value |= (3 << 1); + break; + case FEC_5_6: + value |= (5 << 1); + break; + case FEC_7_8: + value |= (7 << 1); + break; + default: + case FEC_1_2: + value |= (1 << 1); + break; } dib7000p_write_word(state, 208, value); /* offset loop parameters */ - dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) - dib7000p_write_word(state, 29, 0x1273); // isi - dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) + dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) + dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) + dib7000p_write_word(state, 29, 0x1273); // isi + dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) /* P_dvsy_sync_wait */ switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_8K: value = 256; break; - case TRANSMISSION_MODE_4K: value = 128; break; - case TRANSMISSION_MODE_2K: - default: value = 64; break; + case TRANSMISSION_MODE_8K: + value = 256; + break; + case TRANSMISSION_MODE_4K: + value = 128; + break; + case TRANSMISSION_MODE_2K: + default: + value = 64; + break; } switch (ch->u.ofdm.guard_interval) { - case GUARD_INTERVAL_1_16: value *= 2; break; - case GUARD_INTERVAL_1_8: value *= 4; break; - case GUARD_INTERVAL_1_4: value *= 8; break; - default: - case GUARD_INTERVAL_1_32: value *= 1; break; + case GUARD_INTERVAL_1_16: + value *= 2; + break; + case GUARD_INTERVAL_1_8: + value *= 4; + break; + case GUARD_INTERVAL_1_4: + value *= 8; + break; + default: + case GUARD_INTERVAL_1_32: + value *= 1; + break; } if (state->cfg.diversity_delay == 0) - state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo + state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo else - state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo + state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo /* deactive the possibility of diversity reception if extended interleaver */ state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; @@ -792,24 +1015,24 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte /* channel estimation fine configuration */ switch (ch->u.ofdm.constellation) { - case QAM_64: - est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ - est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ - est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ - break; - case QAM_16: - est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ - est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ - est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ - break; - default: - est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ - est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ - est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ - est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ - break; + case QAM_64: + est[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ + est[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ + est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + est[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ + break; + case QAM_16: + est[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ + est[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ + est[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ + est[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ + break; + default: + est[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ + est[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ + est[2] = 0x0333; /* P_adp_regul_ext 0.1 */ + est[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ + break; } for (value = 0; value < 4; value++) dib7000p_write_word(state, 187 + value, est[value]); @@ -820,14 +1043,15 @@ static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_fron struct dib7000p_state *state = demod->demodulator_priv; struct dvb_frontend_parameters schan; u32 value, factor; + u32 internal = dib7000p_get_internal_freq(state); schan = *ch; schan.u.ofdm.constellation = QAM_64; - schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; - schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; - schan.u.ofdm.code_rate_HP = FEC_2_3; - schan.u.ofdm.code_rate_LP = FEC_3_4; - schan.u.ofdm.hierarchy_information = 0; + schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + schan.u.ofdm.code_rate_HP = FEC_2_3; + schan.u.ofdm.code_rate_LP = FEC_3_4; + schan.u.ofdm.hierarchy_information = 0; dib7000p_set_channel(state, &schan, 7); @@ -838,15 +1062,15 @@ static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_fron factor = 6; // always use the setting for 8MHz here lock_time for 7,6 MHz are longer - value = 30 * state->cfg.bw->internal * factor; - dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time - dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.bw->internal * factor; - dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time - dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time - value = 500 * state->cfg.bw->internal * factor; - dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time - dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time + value = 30 * internal * factor; + dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time + dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time + value = 100 * internal * factor; + dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time + dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time + value = 500 * internal * factor; + dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time + dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time value = dib7000p_read_word(state, 0); dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); @@ -861,101 +1085,101 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) struct dib7000p_state *state = demod->demodulator_priv; u16 irq_pending = dib7000p_read_word(state, 1284); - if (irq_pending & 0x1) // failed + if (irq_pending & 0x1) // failed return 1; - if (irq_pending & 0x2) // succeeded + if (irq_pending & 0x2) // succeeded return 2; - return 0; // still pending + return 0; // still pending } static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) { - static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392}; - static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, - 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, - 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, - 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, - 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, - 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, - 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, - 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, - 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, - 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, - 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, - 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, - 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, - 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255}; + static s16 notch[] = { 16143, 14402, 12238, 9713, 6902, 3888, 759, -2392 }; + static u8 sine[] = { 0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22, + 24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51, + 53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80, + 82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105, + 107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126, + 128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146, + 147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165, + 166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182, + 183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212, + 213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224, + 225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235, + 235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243, + 244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249, + 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254, + 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255 + }; u32 xtal = state->cfg.bw->xtal_hz / 1000; int f_rel = DIV_ROUND_CLOSEST(rf_khz, xtal) * xtal - rf_khz; int k; - int coef_re[8],coef_im[8]; + int coef_re[8], coef_im[8]; int bw_khz = bw; u32 pha; - dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); - - if (f_rel < -bw_khz/2 || f_rel > bw_khz/2) + if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2) return; bw_khz /= 100; - dib7000p_write_word(state, 142 ,0x0610); + dib7000p_write_word(state, 142, 0x0610); for (k = 0; k < 8; k++) { - pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff; + pha = ((f_rel * (k + 1) * 112 * 80 / bw_khz) / 1000) & 0x3ff; - if (pha==0) { + if (pha == 0) { coef_re[k] = 256; coef_im[k] = 0; - } else if(pha < 256) { - coef_re[k] = sine[256-(pha&0xff)]; - coef_im[k] = sine[pha&0xff]; + } else if (pha < 256) { + coef_re[k] = sine[256 - (pha & 0xff)]; + coef_im[k] = sine[pha & 0xff]; } else if (pha == 256) { coef_re[k] = 0; coef_im[k] = 256; } else if (pha < 512) { - coef_re[k] = -sine[pha&0xff]; - coef_im[k] = sine[256 - (pha&0xff)]; + coef_re[k] = -sine[pha & 0xff]; + coef_im[k] = sine[256 - (pha & 0xff)]; } else if (pha == 512) { coef_re[k] = -256; coef_im[k] = 0; } else if (pha < 768) { - coef_re[k] = -sine[256-(pha&0xff)]; - coef_im[k] = -sine[pha&0xff]; + coef_re[k] = -sine[256 - (pha & 0xff)]; + coef_im[k] = -sine[pha & 0xff]; } else if (pha == 768) { coef_re[k] = 0; coef_im[k] = -256; } else { - coef_re[k] = sine[pha&0xff]; - coef_im[k] = -sine[256 - (pha&0xff)]; + coef_re[k] = sine[pha & 0xff]; + coef_im[k] = -sine[256 - (pha & 0xff)]; } coef_re[k] *= notch[k]; - coef_re[k] += (1<<14); - if (coef_re[k] >= (1<<24)) - coef_re[k] = (1<<24) - 1; - coef_re[k] /= (1<<15); + coef_re[k] += (1 << 14); + if (coef_re[k] >= (1 << 24)) + coef_re[k] = (1 << 24) - 1; + coef_re[k] /= (1 << 15); coef_im[k] *= notch[k]; - coef_im[k] += (1<<14); - if (coef_im[k] >= (1<<24)) - coef_im[k] = (1<<24)-1; - coef_im[k] /= (1<<15); + coef_im[k] += (1 << 14); + if (coef_im[k] >= (1 << 24)) + coef_im[k] = (1 << 24) - 1; + coef_im[k] /= (1 << 15); - dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); } - dib7000p_write_word(state,143 ,0); + dib7000p_write_word(state, 143, 0); } static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch) @@ -976,11 +1200,11 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); if (state->sfn_workaround_active) { - dprintk( "SFN workaround is active"); + dprintk("SFN workaround is active"); tmp |= (1 << 9); - dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift + dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift } else { - dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift + dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift } dib7000p_write_word(state, 29, tmp); @@ -993,51 +1217,72 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet /* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */ tmp = (6 << 8) | 0x80; switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break; - case TRANSMISSION_MODE_4K: tmp |= (8 << 12); break; - default: - case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break; + case TRANSMISSION_MODE_2K: + tmp |= (2 << 12); + break; + case TRANSMISSION_MODE_4K: + tmp |= (3 << 12); + break; + default: + case TRANSMISSION_MODE_8K: + tmp |= (4 << 12); + break; } - dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ + dib7000p_write_word(state, 26, tmp); /* timf_a(6xxx) */ /* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */ tmp = (0 << 4); switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: tmp |= 0x6; break; - case TRANSMISSION_MODE_4K: tmp |= 0x7; break; - default: - case TRANSMISSION_MODE_8K: tmp |= 0x8; break; + case TRANSMISSION_MODE_2K: + tmp |= 0x6; + break; + case TRANSMISSION_MODE_4K: + tmp |= 0x7; + break; + default: + case TRANSMISSION_MODE_8K: + tmp |= 0x8; + break; } - dib7000p_write_word(state, 32, tmp); + dib7000p_write_word(state, 32, tmp); /* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */ tmp = (0 << 4); switch (ch->u.ofdm.transmission_mode) { - case TRANSMISSION_MODE_2K: tmp |= 0x6; break; - case TRANSMISSION_MODE_4K: tmp |= 0x7; break; - default: - case TRANSMISSION_MODE_8K: tmp |= 0x8; break; + case TRANSMISSION_MODE_2K: + tmp |= 0x6; + break; + case TRANSMISSION_MODE_4K: + tmp |= 0x7; + break; + default: + case TRANSMISSION_MODE_8K: + tmp |= 0x8; + break; } - dib7000p_write_word(state, 33, tmp); + dib7000p_write_word(state, 33, tmp); - tmp = dib7000p_read_word(state,509); + tmp = dib7000p_read_word(state, 509); if (!((tmp >> 6) & 0x1)) { /* restart the fec */ - tmp = dib7000p_read_word(state,771); + tmp = dib7000p_read_word(state, 771); dib7000p_write_word(state, 771, tmp | (1 << 1)); dib7000p_write_word(state, 771, tmp); - msleep(10); - tmp = dib7000p_read_word(state,509); + msleep(40); + tmp = dib7000p_read_word(state, 509); } - // we achieved a lock - it's time to update the osc freq - if ((tmp >> 6) & 0x1) + if ((tmp >> 6) & 0x1) { dib7000p_update_timf(state); + /* P_timf_alpha += 2 */ + tmp = dib7000p_read_word(state, 26); + dib7000p_write_word(state, 26, (tmp & ~(0xf << 12)) | ((((tmp >> 12) & 0xf) + 5) << 12)); + } if (state->cfg.spur_protect) - dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); + dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)); return 0; } @@ -1046,63 +1291,82 @@ static int dib7000p_wakeup(struct dvb_frontend *demod) struct dib7000p_state *state = demod->demodulator_priv; dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); + if (state->version == SOC7090) + dib7000p_sad_calib(state); return 0; } static int dib7000p_sleep(struct dvb_frontend *demod) { struct dib7000p_state *state = demod->demodulator_priv; + if (state->version == SOC7090) + return dib7090_set_output_mode(demod, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); return dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) | dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY); } static int dib7000p_identify(struct dib7000p_state *st) { u16 value; - dprintk( "checking demod on I2C address: %d (%x)", - st->i2c_addr, st->i2c_addr); + dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk( "wrong Vendor ID (read=0x%x)",value); + dprintk("wrong Vendor ID (read=0x%x)", value); return -EREMOTEIO; } if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk( "wrong Device ID (%x)",value); + dprintk("wrong Device ID (%x)", value); return -EREMOTEIO; } return 0; } - -static int dib7000p_get_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - u16 tps = dib7000p_read_word(state,463); + u16 tps = dib7000p_read_word(state, 463); fep->inversion = INVERSION_AUTO; fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); switch ((tps >> 8) & 0x3) { - case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; - case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; + case 0: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; + break; + case 1: + fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; + break; /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ } switch (tps & 0x3) { - case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break; - case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break; - case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break; - case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break; + case 0: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; + break; } switch ((tps >> 14) & 0x3) { - case 0: fep->u.ofdm.constellation = QPSK; break; - case 1: fep->u.ofdm.constellation = QAM_16; break; - case 2: - default: fep->u.ofdm.constellation = QAM_64; break; + case 0: + fep->u.ofdm.constellation = QPSK; + break; + case 1: + fep->u.ofdm.constellation = QAM_16; + break; + case 2: + default: + fep->u.ofdm.constellation = QAM_64; + break; } /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */ @@ -1110,22 +1374,42 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe, fep->u.ofdm.hierarchy_information = HIERARCHY_NONE; switch ((tps >> 5) & 0x7) { - case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_HP = FEC_7_8; break; + case 1: + fep->u.ofdm.code_rate_HP = FEC_1_2; + break; + case 2: + fep->u.ofdm.code_rate_HP = FEC_2_3; + break; + case 3: + fep->u.ofdm.code_rate_HP = FEC_3_4; + break; + case 5: + fep->u.ofdm.code_rate_HP = FEC_5_6; + break; + case 7: + default: + fep->u.ofdm.code_rate_HP = FEC_7_8; + break; } switch ((tps >> 2) & 0x7) { - case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break; - case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break; - case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break; - case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break; - case 7: - default: fep->u.ofdm.code_rate_LP = FEC_7_8; break; + case 1: + fep->u.ofdm.code_rate_LP = FEC_1_2; + break; + case 2: + fep->u.ofdm.code_rate_LP = FEC_2_3; + break; + case 3: + fep->u.ofdm.code_rate_LP = FEC_3_4; + break; + case 5: + fep->u.ofdm.code_rate_LP = FEC_5_6; + break; + case 7: + default: + fep->u.ofdm.code_rate_LP = FEC_7_8; + break; } /* native interleaver: (dib7000p_read_word(state, 464) >> 5) & 0x1 */ @@ -1133,15 +1417,19 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe, return 0; } -static int dib7000p_set_frontend(struct dvb_frontend* fe, - struct dvb_frontend_parameters *fep) +static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; int time, ret; - dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); + if (state->version == SOC7090) { + dib7090_set_diversity_in(fe, 0); + dib7090_set_output_mode(fe, OUTMODE_HIGH_Z); + } + else + dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); - /* maybe the parameter has been changed */ + /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) @@ -1156,9 +1444,7 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, } while (time != -1); if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || - fep->u.ofdm.constellation == QAM_AUTO || - fep->u.ofdm.code_rate_HP == FEC_AUTO) { + fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { int i = 800, found; dib7000p_autosearch_start(fe, fep); @@ -1167,9 +1453,9 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, found = dib7000p_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d",found); + dprintk("autosearch returns: %d", found); if (found == 0 || found == 1) - return 0; // no channel found + return 0; // no channel found dib7000p_get_frontend(fe, fep); } @@ -1177,11 +1463,15 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, ret = dib7000p_tune(fe, fep); /* make this a config parameter */ - dib7000p_set_output_mode(state, state->cfg.output_mode); - return ret; + if (state->version == SOC7090) + dib7090_set_output_mode(fe, state->cfg.output_mode); + else + dib7000p_set_output_mode(state, state->cfg.output_mode); + + return ret; } -static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) +static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat) { struct dib7000p_state *state = fe->demodulator_priv; u16 lock = dib7000p_read_word(state, 509); @@ -1196,27 +1486,27 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) *stat |= FE_HAS_VITERBI; if (lock & 0x0010) *stat |= FE_HAS_SYNC; - if ((lock & 0x0038) == 0x38) + if ((lock & 0x0038) == 0x38) *stat |= FE_HAS_LOCK; return 0; } -static int dib7000p_read_ber(struct dvb_frontend *fe, u32 *ber) +static int dib7000p_read_ber(struct dvb_frontend *fe, u32 * ber) { struct dib7000p_state *state = fe->demodulator_priv; *ber = (dib7000p_read_word(state, 500) << 16) | dib7000p_read_word(state, 501); return 0; } -static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) +static int dib7000p_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) { struct dib7000p_state *state = fe->demodulator_priv; *unc = dib7000p_read_word(state, 506); return 0; } -static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength) { struct dib7000p_state *state = fe->demodulator_priv; u16 val = dib7000p_read_word(state, 394); @@ -1224,7 +1514,7 @@ static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; } -static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr) +static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr) { struct dib7000p_state *state = fe->demodulator_priv; u16 val; @@ -1240,19 +1530,17 @@ static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr) noise_exp -= 0x40; signal_mant = (val >> 6) & 0xFF; - signal_exp = (val & 0x3F); + signal_exp = (val & 0x3F); if ((signal_exp & 0x20) != 0) signal_exp -= 0x40; if (signal_mant != 0) - result = intlog10(2) * 10 * signal_exp + 10 * - intlog10(signal_mant); + result = intlog10(2) * 10 * signal_exp + 10 * intlog10(signal_mant); else result = intlog10(2) * 10 * signal_exp - 100; if (noise_mant != 0) - result -= intlog10(2) * 10 * noise_exp + 10 * - intlog10(noise_mant); + result -= intlog10(2) * 10 * noise_exp + 10 * intlog10(noise_mant); else result -= intlog10(2) * 10 * noise_exp - 100; @@ -1260,7 +1548,7 @@ static int dib7000p_read_snr(struct dvb_frontend* fe, u16 *snr) return 0; } -static int dib7000p_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) { tune->min_delay_ms = 1000; return 0; @@ -1270,6 +1558,7 @@ static void dib7000p_release(struct dvb_frontend *demod) { struct dib7000p_state *st = demod->demodulator_priv; dibx000_exit_i2c_master(&st->i2c_master); + i2c_del_adapter(&st->dib7090_tuner_adap); kfree(st); } @@ -1277,8 +1566,8 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) { u8 tx[2], rx[2]; struct i2c_msg msg[2] = { - { .addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2 }, - { .addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2 }, + {.addr = 18 >> 1,.flags = 0,.buf = tx,.len = 2}, + {.addr = 18 >> 1,.flags = I2C_M_RD,.buf = rx,.len = 2}, }; tx[0] = 0x03; @@ -1303,7 +1592,7 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) } EXPORT_SYMBOL(dib7000pc_detection); -struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) +struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating) { struct dib7000p_state *st = demod->demodulator_priv; return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); @@ -1312,19 +1601,19 @@ EXPORT_SYMBOL(dib7000p_get_i2c_master); int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { - struct dib7000p_state *state = fe->demodulator_priv; - u16 val = dib7000p_read_word(state, 235) & 0xffef; - val |= (onoff & 0x1) << 4; - dprintk("PID filter enabled %d", onoff); - return dib7000p_write_word(state, 235, val); + struct dib7000p_state *state = fe->demodulator_priv; + u16 val = dib7000p_read_word(state, 235) & 0xffef; + val |= (onoff & 0x1) << 4; + dprintk("PID filter enabled %d", onoff); + return dib7000p_write_word(state, 235, val); } EXPORT_SYMBOL(dib7000p_pid_filter_ctrl); int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { - struct dib7000p_state *state = fe->demodulator_priv; - dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); - return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0); + struct dib7000p_state *state = fe->demodulator_priv; + dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); + return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0); } EXPORT_SYMBOL(dib7000p_pid_filter); @@ -1340,16 +1629,19 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau dpst->i2c_adap = i2c; - for (k = no_of_demods-1; k >= 0; k--) { + for (k = no_of_demods - 1; k >= 0; k--) { dpst->cfg = cfg[k]; /* designated i2c address */ - new_addr = (0x40 + k) << 1; + if (cfg[k].default_i2c_addr != 0) + new_addr = cfg[k].default_i2c_addr + (k << 1); + else + new_addr = (0x40 + k) << 1; dpst->i2c_addr = new_addr; - dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ + dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ if (dib7000p_identify(dpst) != 0) { dpst->i2c_addr = default_addr; - dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ + dib7000p_write_word(dpst, 1287, 0x0003); /* sram lead in, rdy */ if (dib7000p_identify(dpst) != 0) { dprintk("DiB7000P #%d: not identified\n", k); kfree(dpst); @@ -1368,7 +1660,10 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau for (k = 0; k < no_of_demods; k++) { dpst->cfg = cfg[k]; - dpst->i2c_addr = (0x40 + k) << 1; + if (cfg[k].default_i2c_addr != 0) + dpst->i2c_addr = (cfg[k].default_i2c_addr + k) << 1; + else + dpst->i2c_addr = (0x40 + k) << 1; // unforce divstr dib7000p_write_word(dpst, 1285, dpst->i2c_addr << 2); @@ -1382,8 +1677,616 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau } EXPORT_SYMBOL(dib7000p_i2c_enumeration); +static const s32 lut_1000ln_mant[] = { + 6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600 +}; + +static s32 dib7000p_get_adc_power(struct dvb_frontend *fe) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u32 tmp_val = 0, exp = 0, mant = 0; + s32 pow_i; + u16 buf[2]; + u8 ix = 0; + + buf[0] = dib7000p_read_word(state, 0x184); + buf[1] = dib7000p_read_word(state, 0x185); + pow_i = (buf[0] << 16) | buf[1]; + dprintk("raw pow_i = %d", pow_i); + + tmp_val = pow_i; + while (tmp_val >>= 1) + exp++; + + mant = (pow_i * 1000 / (1 << exp)); + dprintk(" mant = %d exp = %d", mant / 1000, exp); + + ix = (u8) ((mant - 1000) / 100); /* index of the LUT */ + dprintk(" ix = %d", ix); + + pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908); + pow_i = (pow_i << 8) / 1000; + dprintk(" pow_i = %d", pow_i); + + return pow_i; +} + +static int map_addr_to_serpar_number(struct i2c_msg *msg) +{ + if ((msg->buf[0] <= 15)) + msg->buf[0] -= 1; + else if (msg->buf[0] == 17) + msg->buf[0] = 15; + else if (msg->buf[0] == 16) + msg->buf[0] = 17; + else if (msg->buf[0] == 19) + msg->buf[0] = 16; + else if (msg->buf[0] >= 21 && msg->buf[0] <= 25) + msg->buf[0] -= 3; + else if (msg->buf[0] == 28) + msg->buf[0] = 23; + else { + return -EINVAL; + } + return 0; +} + +static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + + while (n_overflow == 1 && i) { + n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("Tuner ITF: write busy (overflow)"); + } + dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); + dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); + + return num; +} + +static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + u8 n_overflow = 1, n_empty = 1; + u16 i = 1000; + u16 serpar_num = msg[0].buf[0]; + u16 read_word; + + while (n_overflow == 1 && i) { + n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (overflow)"); + } + dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f)); + + i = 1000; + while (n_empty == 1 && i) { + n_empty = dib7000p_read_word(state, 1984) & 0x1; + i--; + if (i == 0) + dprintk("TunerITF: read busy (empty)"); + } + read_word = dib7000p_read_word(state, 1987); + msg[1].buf[0] = (read_word >> 8) & 0xff; + msg[1].buf[1] = (read_word) & 0xff; + + return num; +} + +static int w7090p_tuner_rw_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + if (map_addr_to_serpar_number(&msg[0]) == 0) { /* else = Tuner regs to ignore : DIG_CFG, CTRL_RF_LT, PLL_CFG, PWM1_REG, ADCCLK, DIG_CFG_3; SLEEP_EN... */ + if (num == 1) { /* write */ + return w7090p_tuner_write_serpar(i2c_adap, msg, 1); + } else { /* read */ + return w7090p_tuner_read_serpar(i2c_adap, msg, 2); + } + } + return num; +} + +int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num, u16 apb_address) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + u16 word; + + if (num == 1) { /* write */ + dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); + } else { + word = dib7000p_read_word(state, apb_address); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + } + + return num; +} + +static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) +{ + struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); + + u16 apb_address = 0, word; + int i = 0; + switch (msg[0].buf[0]) { + case 0x12: + apb_address = 1920; + break; + case 0x14: + apb_address = 1921; + break; + case 0x24: + apb_address = 1922; + break; + case 0x1a: + apb_address = 1923; + break; + case 0x22: + apb_address = 1924; + break; + case 0x33: + apb_address = 1926; + break; + case 0x34: + apb_address = 1927; + break; + case 0x35: + apb_address = 1928; + break; + case 0x36: + apb_address = 1929; + break; + case 0x37: + apb_address = 1930; + break; + case 0x38: + apb_address = 1931; + break; + case 0x39: + apb_address = 1932; + break; + case 0x2a: + apb_address = 1935; + break; + case 0x2b: + apb_address = 1936; + break; + case 0x2c: + apb_address = 1937; + break; + case 0x2d: + apb_address = 1938; + break; + case 0x2e: + apb_address = 1939; + break; + case 0x2f: + apb_address = 1940; + break; + case 0x30: + apb_address = 1941; + break; + case 0x31: + apb_address = 1942; + break; + case 0x32: + apb_address = 1943; + break; + case 0x3e: + apb_address = 1944; + break; + case 0x3f: + apb_address = 1945; + break; + case 0x40: + apb_address = 1948; + break; + case 0x25: + apb_address = 914; + break; + case 0x26: + apb_address = 915; + break; + case 0x27: + apb_address = 916; + break; + case 0x28: + apb_address = 917; + break; + case 0x1d: + i = ((dib7000p_read_word(state, 72) >> 12) & 0x3); + word = dib7000p_read_word(state, 384 + i); + msg[1].buf[0] = (word >> 8) & 0xff; + msg[1].buf[1] = (word) & 0xff; + return num; + case 0x1f: + if (num == 1) { /* write */ + word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]); + word &= 0x3; + word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12); //Mask bit 12,13 + dib7000p_write_word(state, 72, word); /* Set the proper input */ + return num; + } + } + + if (apb_address != 0) /* R/W acces via APB */ + return dib7090p_rw_on_apb(i2c_adap, msg, num, apb_address); + else /* R/W access via SERPAR */ + return w7090p_tuner_rw_serpar(i2c_adap, msg, num); + + return 0; +} + +static u32 dib7000p_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C; +} + +static struct i2c_algorithm dib7090_tuner_xfer_algo = { + .master_xfer = dib7090_tuner_xfer, + .functionality = dib7000p_i2c_func, +}; + +struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe) +{ + struct dib7000p_state *st = fe->demodulator_priv; + return &st->dib7090_tuner_adap; +} +EXPORT_SYMBOL(dib7090_get_i2c_tuner); + +static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive) +{ + u16 reg; + + /* drive host bus 2, 3, 4 */ + reg = dib7000p_read_word(state, 1798) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); + reg |= (drive << 12) | (drive << 6) | drive; + dib7000p_write_word(state, 1798, reg); + + /* drive host bus 5,6 */ + reg = dib7000p_read_word(state, 1799) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive << 8) | (drive << 2); + dib7000p_write_word(state, 1799, reg); + + /* drive host bus 7, 8, 9 */ + reg = dib7000p_read_word(state, 1800) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); + reg |= (drive << 12) | (drive << 6) | drive; + dib7000p_write_word(state, 1800, reg); + + /* drive host bus 10, 11 */ + reg = dib7000p_read_word(state, 1801) & ~((0x7 << 2) | (0x7 << 8)); + reg |= (drive << 8) | (drive << 2); + dib7000p_write_word(state, 1801, reg); + + /* drive host bus 12, 13, 14 */ + reg = dib7000p_read_word(state, 1802) & ~((0x7) | (0x7 << 6) | (0x7 << 12)); + reg |= (drive << 12) | (drive << 6) | drive; + dib7000p_write_word(state, 1802, reg); + + return 0; +} + +static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 syncSize) +{ + u32 quantif = 3; + u32 nom = (insertExtSynchro * P_Kin + syncSize); + u32 denom = P_Kout; + u32 syncFreq = ((nom << quantif) / denom); + + if ((syncFreq & ((1 << quantif) - 1)) != 0) + syncFreq = (syncFreq >> quantif) + 1; + else + syncFreq = (syncFreq >> quantif); + + if (syncFreq != 0) + syncFreq = syncFreq - 1; + + return syncFreq; +} + +static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) +{ + u8 index_buf; + u16 rx_copy_buf[22]; + + dprintk("Configure DibStream Tx"); + for (index_buf = 0; index_buf<22; index_buf++) + rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf); + + dib7000p_write_word(state, 1615, 1); + dib7000p_write_word(state, 1603, P_Kin); + dib7000p_write_word(state, 1605, P_Kout); + dib7000p_write_word(state, 1606, insertExtSynchro); + dib7000p_write_word(state, 1608, synchroMode); + dib7000p_write_word(state, 1609, (syncWord >> 16) & 0xffff); + dib7000p_write_word(state, 1610, syncWord & 0xffff); + dib7000p_write_word(state, 1612, syncSize); + dib7000p_write_word(state, 1615, 0); + + for (index_buf = 0; index_buf<22; index_buf++) + dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]); + + return 0; +} + +static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 synchroMode, u32 insertExtSynchro, u32 syncWord, u32 syncSize, + u32 dataOutRate) +{ + u32 syncFreq; + + dprintk("Configure DibStream Rx"); + if ((P_Kin != 0) && (P_Kout != 0)) + { + syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize); + dib7000p_write_word(state, 1542, syncFreq); + } + dib7000p_write_word(state, 1554, 1); + dib7000p_write_word(state, 1536, P_Kin); + dib7000p_write_word(state, 1537, P_Kout); + dib7000p_write_word(state, 1539, synchroMode); + dib7000p_write_word(state, 1540, (syncWord >> 16) & 0xffff); + dib7000p_write_word(state, 1541, syncWord & 0xffff); + dib7000p_write_word(state, 1543, syncSize); + dib7000p_write_word(state, 1544, dataOutRate); + dib7000p_write_word(state, 1554, 0); + + return 0; +} + +static int dib7090_enDivOnHostBus(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Enable Diversity on host bus"); + reg = (1 << 8) | (1 << 5); // P_enDivOutOnDibTx = 1 ; P_enDibTxOnHostBus = 1 + dib7000p_write_word(state, 1288, reg); + + return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); +} + +static int dib7090_enAdcOnHostBus(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Enable ADC on host bus"); + reg = (1 << 7) | (1 << 5); //P_enAdcOnDibTx = 1 ; P_enDibTxOnHostBus = 1 + dib7000p_write_word(state, 1288, reg); + + return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); +} + +static int dib7090_enMpegOnHostBus(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Enable Mpeg on host bus"); + reg = (1 << 9) | (1 << 5); //P_enMpegOnDibTx = 1 ; P_enDibTxOnHostBus = 1 + dib7000p_write_word(state, 1288, reg); + + return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); +} + +static int dib7090_enMpegInput(struct dib7000p_state *state) +{ + dprintk("Enable Mpeg input"); + return dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ +} + +static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) +{ + u16 reg = (1 << 7) | ((pulseWidth & 0x1f) << 2) | ((enSerialMode & 0x1) << 1) | (enSerialClkDiv2 & 0x1); + + dprintk("Enable Mpeg mux"); + dib7000p_write_word(state, 1287, reg); + + reg &= ~(1 << 7); // P_restart_mpegMux = 0 + dib7000p_write_word(state, 1287, reg); + + reg = (1 << 4); //P_enMpegMuxOnHostBus = 1 + dib7000p_write_word(state, 1288, reg); + + return 0; +} + +static int dib7090_disableMpegMux(struct dib7000p_state *state) +{ + u16 reg; + + dprintk("Disable Mpeg mux"); + dib7000p_write_word(state, 1288, 0); //P_enMpegMuxOnHostBus = 0 + + reg = dib7000p_read_word(state, 1287); + reg &= ~(1 << 7); // P_restart_mpegMux = 0 + dib7000p_write_word(state, 1287, reg); + + return 0; +} + +static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode) +{ + struct dib7000p_state *state = fe->demodulator_priv; + + switch(mode) { + case INPUT_MODE_DIVERSITY: + dprintk("Enable diversity INPUT"); + dib7090_cfg_DibRx(state, 5,5,0,0,0,0,0); + break; + case INPUT_MODE_MPEG: + dprintk("Enable Mpeg INPUT"); + dib7090_cfg_DibRx(state, 8,5,0,0,0,8,0); /*outputRate = 8 */ + break; + case INPUT_MODE_OFF: + default: + dprintk("Disable INPUT"); + dib7090_cfg_DibRx(state, 0,0,0,0,0,0,0); + break; + } + return 0; +} + +static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) +{ + switch (onoff) { + case 0: /* only use the internal way - not the diversity input */ + dib7090_set_input_mode(fe, INPUT_MODE_MPEG); + break; + case 1: /* both ways */ + case 2: /* only the diversity input */ + dib7090_set_input_mode(fe, INPUT_MODE_DIVERSITY); + break; + } + + return 0; +} + +static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) +{ + struct dib7000p_state *state = fe->demodulator_priv; + + u16 outreg, smo_mode, fifo_threshold; + u8 prefer_mpeg_mux_use = 1; + int ret = 0; + + dib7090_host_bus_drive(state, 1); + + fifo_threshold = 1792; + smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); + outreg = dib7000p_read_word(state, 1286) & ~((1 << 10) | (0x7 << 6) | (1 << 1)); + + switch (mode) { + case OUTMODE_HIGH_Z: + outreg = 0; + break; + + case OUTMODE_MPEG2_SERIAL: + if (prefer_mpeg_mux_use) { + dprintk("Sip 7090P setting output mode TS_SERIAL using Mpeg Mux"); + dib7090_enMpegOnHostBus(state); + dib7090_enMpegInput(state); + if (state->cfg.enMpegOutput == 1) + dib7090_enMpegMux(state, 3, 1, 1); + + } else { /* Use Smooth block */ + dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + outreg |= (2 << 6) | (0 << 1); + } + break; + + case OUTMODE_MPEG2_PAR_GATED_CLK: + if (prefer_mpeg_mux_use) { + dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dib7090_enMpegOnHostBus(state); + dib7090_enMpegInput(state); + if (state->cfg.enMpegOutput == 1) + dib7090_enMpegMux(state, 2, 0, 0); + } else { /* Use Smooth block */ + dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + outreg |= (0 << 6); + } + break; + + case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ + dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + outreg |= (1 << 6); + break; + + case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ + dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block"); + dib7090_disableMpegMux(state); + dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + outreg |= (5 << 6); + smo_mode |= (3 << 1); + fifo_threshold = 512; + break; + + case OUTMODE_DIVERSITY: + dprintk("Sip 7090P setting output mode MODE_DIVERSITY"); + dib7090_disableMpegMux(state); + dib7090_enDivOnHostBus(state); + break; + + case OUTMODE_ANALOG_ADC: + dprintk("Sip 7090P setting output mode MODE_ANALOG_ADC"); + dib7090_enAdcOnHostBus(state); + break; + } + + if (state->cfg.output_mpeg2_in_188_bytes) + smo_mode |= (1 << 5); + + ret |= dib7000p_write_word(state, 235, smo_mode); + ret |= dib7000p_write_word(state, 236, fifo_threshold); /* synchronous fread */ + ret |= dib7000p_write_word(state, 1286, outreg | (1 << 10)); /* allways set Dout active = 1 !!! */ + + return ret; +} + +int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 en_cur_state; + + dprintk("sleep dib7090: %d", onoff); + + en_cur_state = dib7000p_read_word(state, 1922); + + if (en_cur_state > 0xff) { //LNAs and MIX are ON and therefore it is a valid configuration + state->tuner_enable = en_cur_state; + } + + if (onoff) + en_cur_state &= 0x00ff; //Mask to be applied + else { + if (state->tuner_enable != 0) + en_cur_state = state->tuner_enable; + } + + dib7000p_write_word(state, 1922, en_cur_state); + + return 0; +} +EXPORT_SYMBOL(dib7090_tuner_sleep); + +int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) +{ + dprintk("AGC restart callback: %d", restart); + return 0; +} +EXPORT_SYMBOL(dib7090_agc_restart); + +int dib7090_get_adc_power(struct dvb_frontend *fe) +{ + return dib7000p_get_adc_power(fe); +} +EXPORT_SYMBOL(dib7090_get_adc_power); + +int dib7090_slave_reset(struct dvb_frontend *fe) +{ + struct dib7000p_state *state = fe->demodulator_priv; + u16 reg; + + reg = dib7000p_read_word(state, 1794); + dib7000p_write_word(state, 1794, reg | (4 << 12)); + + dib7000p_write_word(state, 1032, 0xffff); + return 0; +} +EXPORT_SYMBOL(dib7090_slave_reset); + static struct dvb_frontend_ops dib7000p_ops; -struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) +struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) { struct dvb_frontend *demod; struct dib7000p_state *st; @@ -1400,31 +2303,44 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, /* Ensure the output mode remains at the previous default if it's * not specifically set by the caller. */ - if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && - (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) + if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) st->cfg.output_mode = OUTMODE_MPEG2_FIFO; - demod = &st->demod; + demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); - dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ + dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ if (dib7000p_identify(st) != 0) goto error; + st->version = dib7000p_read_word(st, 897); + /* FIXME: make sure the dev.parent field is initialized, or else - request_firmware() will hit an OOPS (this should be moved somewhere - more common) */ - st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; + request_firmware() will hit an OOPS (this should be moved somewhere + more common) */ dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); + /* init 7090 tuner adapter */ + strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name)); + st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo; + st->dib7090_tuner_adap.algo_data = NULL; + st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent; + i2c_set_adapdata(&st->dib7090_tuner_adap, st); + i2c_add_adapter(&st->dib7090_tuner_adap); + dib7000p_demod_reset(st); + if (st->version == SOC7090) { + dib7090_set_output_mode(demod, st->cfg.output_mode); + dib7090_set_diversity_in(demod, 0); + } + return demod; -error: + error: kfree(st); return NULL; } @@ -1432,37 +2348,35 @@ EXPORT_SYMBOL(dib7000p_attach); static struct dvb_frontend_ops dib7000p_ops = { .info = { - .name = "DiBcom 7000PC", - .type = FE_OFDM, - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 62500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = dib7000p_release, - - .init = dib7000p_wakeup, - .sleep = dib7000p_sleep, - - .set_frontend = dib7000p_set_frontend, - .get_tune_settings = dib7000p_fe_get_tune_settings, - .get_frontend = dib7000p_get_frontend, - - .read_status = dib7000p_read_status, - .read_ber = dib7000p_read_ber, + .name = "DiBcom 7000PC", + .type = FE_OFDM, + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 62500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | FE_CAN_HIERARCHY_AUTO, + }, + + .release = dib7000p_release, + + .init = dib7000p_wakeup, + .sleep = dib7000p_sleep, + + .set_frontend = dib7000p_set_frontend, + .get_tune_settings = dib7000p_fe_get_tune_settings, + .get_frontend = dib7000p_get_frontend, + + .read_status = dib7000p_read_status, + .read_ber = dib7000p_read_ber, .read_signal_strength = dib7000p_read_signal_strength, - .read_snr = dib7000p_read_snr, - .read_ucblocks = dib7000p_read_unc_blocks, + .read_snr = dib7000p_read_snr, + .read_ucblocks = dib7000p_read_unc_blocks, }; +MODULE_AUTHOR("Olivier Grenie "); MODULE_AUTHOR("Patrick Boettcher "); MODULE_DESCRIPTION("Driver for the DiBcom 7000PC COFDM demodulator"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index da17345bf5bd..4e3ffc888341 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -33,59 +33,54 @@ struct dib7000p_config { int (*agc_control) (struct dvb_frontend *, u8 before); u8 output_mode; - u8 disable_sample_and_hold : 1; + u8 disable_sample_and_hold:1; - u8 enable_current_mirror : 1; - u8 diversity_delay; + u8 enable_current_mirror:1; + u16 diversity_delay; + u8 default_i2c_addr; + u8 enMpegOutput : 1; }; #define DEFAULT_DIB7000P_I2C_ADDRESS 18 #if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \ - defined(MODULE)) -extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, - u8 i2c_addr, - struct dib7000p_config *cfg); -extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, - enum dibx000_i2c_interface, - int); -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, - int no_of_demods, u8 default_addr, - struct dib7000p_config cfg[]); + defined(MODULE)) +extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff); +extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw); +extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf); +extern int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart); +extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff); +extern int dib7090_get_adc_power(struct dvb_frontend *fe); +extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe); +extern int dib7090_slave_reset(struct dvb_frontend *fe); #else -static inline -struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, - struct dib7000p_config *cfg) +static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -static inline -struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, - enum dibx000_i2c_interface i, - int x) +static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, - int no_of_demods, u8 default_addr, - struct dib7000p_config cfg[]) +static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -static inline int dib7000p_set_gpio(struct dvb_frontend *fe, - u8 num, u8 dir, u8 val) +static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; @@ -102,16 +97,59 @@ static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap) printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } + static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; } static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline int dib7090_get_adc_power(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline int dib7090_slave_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; } #endif diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index c4fd62f8df51..cc0fafe0436d 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -141,8 +141,8 @@ enum dibx000_adc_states { }; #define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \ - (v) == BANDWIDTH_7_MHZ ? 7000 : \ - (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) + (v) == BANDWIDTH_7_MHZ ? 7000 : \ + (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) #define BANDWIDTH_TO_INDEX(v) ( \ (v) == 8000 ? BANDWIDTH_8_MHZ : \ @@ -158,53 +158,57 @@ enum dibx000_adc_states { #define OUTMODE_MPEG2_FIFO 5 #define OUTMODE_ANALOG_ADC 6 +#define INPUT_MODE_OFF 0x11 +#define INPUT_MODE_DIVERSITY 0x12 +#define INPUT_MODE_MPEG 0x13 + enum frontend_tune_state { - CT_TUNER_START = 10, - CT_TUNER_STEP_0, - CT_TUNER_STEP_1, - CT_TUNER_STEP_2, - CT_TUNER_STEP_3, - CT_TUNER_STEP_4, - CT_TUNER_STEP_5, - CT_TUNER_STEP_6, - CT_TUNER_STEP_7, - CT_TUNER_STOP, - - CT_AGC_START = 20, - CT_AGC_STEP_0, - CT_AGC_STEP_1, - CT_AGC_STEP_2, - CT_AGC_STEP_3, - CT_AGC_STEP_4, - CT_AGC_STOP, + CT_TUNER_START = 10, + CT_TUNER_STEP_0, + CT_TUNER_STEP_1, + CT_TUNER_STEP_2, + CT_TUNER_STEP_3, + CT_TUNER_STEP_4, + CT_TUNER_STEP_5, + CT_TUNER_STEP_6, + CT_TUNER_STEP_7, + CT_TUNER_STOP, + + CT_AGC_START = 20, + CT_AGC_STEP_0, + CT_AGC_STEP_1, + CT_AGC_STEP_2, + CT_AGC_STEP_3, + CT_AGC_STEP_4, + CT_AGC_STOP, CT_DEMOD_START = 30, - CT_DEMOD_STEP_1, - CT_DEMOD_STEP_2, - CT_DEMOD_STEP_3, - CT_DEMOD_STEP_4, - CT_DEMOD_STEP_5, - CT_DEMOD_STEP_6, - CT_DEMOD_STEP_7, - CT_DEMOD_STEP_8, - CT_DEMOD_STEP_9, - CT_DEMOD_STEP_10, - CT_DEMOD_SEARCH_NEXT = 41, - CT_DEMOD_STEP_LOCKED, - CT_DEMOD_STOP, - - CT_DONE = 100, - CT_SHUTDOWN, + CT_DEMOD_STEP_1, + CT_DEMOD_STEP_2, + CT_DEMOD_STEP_3, + CT_DEMOD_STEP_4, + CT_DEMOD_STEP_5, + CT_DEMOD_STEP_6, + CT_DEMOD_STEP_7, + CT_DEMOD_STEP_8, + CT_DEMOD_STEP_9, + CT_DEMOD_STEP_10, + CT_DEMOD_SEARCH_NEXT = 41, + CT_DEMOD_STEP_LOCKED, + CT_DEMOD_STOP, + + CT_DONE = 100, + CT_SHUTDOWN, }; struct dvb_frontend_parametersContext { #define CHANNEL_STATUS_PARAMETERS_UNKNOWN 0x01 #define CHANNEL_STATUS_PARAMETERS_SET 0x02 - u8 status; - u32 tune_time_estimation[2]; - s32 tps_available; - u16 tps[9]; + u8 status; + u32 tune_time_estimation[2]; + s32 tps_available; + u16 tps[9]; }; #define FE_STATUS_TUNE_FAILED 0 -- cgit v1.2.2 From be9bae10ffa5aeeef051e893c3b15a5d10eb657d Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Tue, 4 Jan 2011 05:42:19 -0300 Subject: [media] DiB0700: add support for several board-layouts This patchs adds support for DiBcom's NIM8096MD, NIM9090M, NIM9090MD, NIM7090, TFE7090PVR (no diversity) reference designs. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_core.c | 4 +- drivers/media/dvb/dvb-usb/dib0700_devices.c | 1401 ++++++++++++++++++++++++--- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 5 + 3 files changed, 1280 insertions(+), 130 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index ebda77dde97e..9ab57132b444 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -186,7 +186,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, msg[i].len, USB_CTRL_GET_TIMEOUT); if (result < 0) { - err("i2c read error (status = %d)\n", result); + deb_info("i2c read error (status = %d)\n", result); break; } @@ -215,7 +215,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, 0, 0, buf, msg[i].len + 4, USB_CTRL_GET_TIMEOUT); if (result < 0) { - err("i2c write error (status = %d)\n", result); + deb_info("i2c write error (status = %d)\n", result); break; } } diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 193cdb77b76a..2b919034db87 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -12,6 +12,7 @@ #include "dib7000m.h" #include "dib7000p.h" #include "dib8000.h" +#include "dib9000.h" #include "mt2060.h" #include "mt2266.h" #include "tuner-xc2028.h" @@ -29,6 +30,7 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif struct dib0700_adapter_state { int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *); + const struct firmware *frontend_firmware; }; /* Hauppauge Nova-T 500 (aka Bristol) @@ -1243,13 +1245,13 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib8000_pid_filter(adapter->fe, index, pid, onoff); + return dib8000_pid_filter(adapter->fe, index, pid, onoff); } static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, - int onoff) + int onoff) { - return dib8000_pid_filter_ctrl(adapter->fe, onoff); + return dib8000_pid_filter_ctrl(adapter->fe, onoff); } /* STK807x */ @@ -1321,11 +1323,11 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) /* STK8096GP */ struct dibx000_agc_config dib8090_agc_config[2] = { - { + { BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), @@ -1362,12 +1364,12 @@ struct dibx000_agc_config dib8090_agc_config[2] = { 51, 0, - }, - { + }, + { BAND_CBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, - * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, - * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), @@ -1404,159 +1406,1098 @@ struct dibx000_agc_config dib8090_agc_config[2] = { 51, 0, - } + } }; static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { - 54000, 13500, - 1, 18, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (599 << 0), - (0 << 25) | 0, - 20199727, - 12000000, + 54000, 13500, + 1, 18, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (599 << 0), + (0 << 25) | 0, + 20199727, + 12000000, }; static int dib8090_get_adc_power(struct dvb_frontend *fe) { - return dib8000_get_adc_power(fe, 1); + return dib8000_get_adc_power(fe, 1); +} + +static struct dib8000_config dib809x_dib8000_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + .diversity_delay = 48, + .refclksel = 3, + },{ + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_DIVERSITY, + .drives = 0x2d08, + .diversity_delay = 1, + .refclksel = 3, + } +}; + +static struct dib0090_wbd_slope dib8090_wbd_table[] = { + /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */ + { 120, 0, 500, 0, 500, 4 }, /* CBAND */ + { 170, 0, 450, 0, 450, 4 }, /* CBAND */ + { 380, 48, 373, 28, 259, 6 }, /* VHF */ + { 860, 34, 700, 36, 616, 6 }, /* high UHF */ + { 0xFFFF, 34, 700, 36, 616, 6 }, /* default */ +}; + +static struct dib0090_config dib809x_dib0090_config = { + .io.pll_bypass = 1, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 20, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 12000, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 1, + .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, + .use_pwm_agc = 1, + .clkoutdrive = 1, + .get_adc_power = dib8090_get_adc_power, + .freq_offset_khz_uhf = -63, + .freq_offset_khz_vhf = -143, + .wbd = dib8090_wbd_table, + .fref_clock_ratio = 6, +}; + +static int dib8096_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u16 target; + int ret = 0; + enum frontend_tune_state tune_state = CT_SHUTDOWN; + u16 ltgain, rf_gain_limit; + + ret = state->set_param_save(fe, fep); + if (ret < 0) + return ret; + + target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; + dib8000_set_wbd_ref(fe, target); + + + if (band == BAND_CBAND) { + deb_info("tuning in CBAND - soft-AGC startup\n"); + /* TODO specific wbd target for dib0090 - needed for startup ? */ + dib0090_set_tune_state(fe, CT_AGC_START); + do { + ret = dib0090_gain_control(fe); + msleep(ret); + tune_state = dib0090_get_tune_state(fe); + if (tune_state == CT_AGC_STEP_0) + dib8000_set_gpio(fe, 6, 0, 1); + else if (tune_state == CT_AGC_STEP_1) { + dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); + if (rf_gain_limit == 0) + dib8000_set_gpio(fe, 6, 0, 0); + } + } while (tune_state < CT_AGC_STOP); + dib0090_pwm_gain_reset(fe); + dib8000_pwm_agc_reset(fe); + dib8000_set_tune_state(fe, CT_DEMOD_START); + } else { + deb_info("not tuning in CBAND - standard AGC startup\n"); + dib0090_pwm_gain_reset(fe); + } + + return 0; +} + +static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + return 0; +} + +static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c; + struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe, 1); + + if (fe_slave) { + tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + fe_slave->dvb = adap->fe->dvb; + fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; + } + tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + + return 0; +} + +static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe_slave; + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(1000); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + if (adap->fe == NULL) + return -ENODEV; + + fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); + dib8000_set_slave_frontend(adap->fe, fe_slave); + + return fe_slave == NULL ? -ENODEV : 0; +} + +/* STK9090M */ +static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +{ + return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff); +} + +static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +{ + return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff); +} + +static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib9000_set_gpio(fe, 5, 0, !onoff); +} + +static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return dib9000_set_gpio(fe, 0, 0, onoff); +} + +static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) +{ + u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 }; + u8 rb[2]; + struct i2c_msg msg[2] = { + {.addr = 0x1e >> 1,.flags = 0,.buf = wb,.len = 2}, + {.addr = 0x1e >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2}, + }; + u8 index_data; + + dibx000_i2c_set_speed(i2c, 250); + + if (i2c_transfer(i2c, msg, 2) != 2) + return -EIO; + + switch (rb[0] << 8 | rb[1]) { + case 0: + deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n"); + return -EIO; + case 1: + deb_info("Found DiB0170 rev2"); + break; + case 2: + deb_info("Found DiB0190 rev2"); + break; + default: + deb_info("DiB01x0 not found"); + return -EIO; + } + + for (index_data = 0; index_data < len; index_data += 2) { + wb[2] = (data[index_data + 1] >> 8) & 0xff; + wb[3] = (data[index_data + 1]) & 0xff; + + if (data[index_data] == 0) { + wb[0] = (data[index_data] >> 8) & 0xff; + wb[1] = (data[index_data]) & 0xff; + msg[0].len = 2; + if (i2c_transfer(i2c, msg, 2) != 2) + return -EIO; + wb[2] |= rb[0]; + wb[3] |= rb[1] & ~(3 << 4); + } + + wb[0] = (data[index_data ] >> 8)&0xff; + wb[1] = (data[index_data ] )&0xff; + msg[0].len = 4; + if (i2c_transfer(i2c, &msg[0], 1) != 1) + return -EIO; + } + return 0; +} + +static struct dib9000_config stk9090m_config = { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_MPEG2_FIFO, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + .subband = { + 2, + { + { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */ + { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */ + { 0 }, + }, + }, + .gpio_function = { + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, + }, +}; + +static struct dib9000_config nim9090md_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_MPEG2_FIFO, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + }, { + .output_mpeg2_in_188_bytes = 1, + .output_mode = OUTMODE_DIVERSITY, + .vcxo_timer = 279620, + .timing_frequency = 20452225, + .demod_clock_khz = 60000, + .xtal_clock_khz = 30000, + .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0), + .subband = { + 2, + { + { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */ + { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */ + { 0 }, + }, + }, + .gpio_function = { + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 }, + { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 }, + }, + } +}; + +static struct dib0090_config dib9090_dib0090_config = { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 0, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, +}; + +static struct dib0090_config nim9090md_dib0090_config[2] = { + { + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + },{ + .io.pll_bypass = 0, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 8, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 30000, + .reset = dib90x0_tuner_reset, + .sleep = dib90x0_tuner_sleep, + .clkouttobamse = 0, + .analog_output = 0, + .use_pwm_agc = 0, + .clkoutdrive = 0, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + } +}; + + +static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct dib0700_state *st = adap->dev->priv; + u32 fw_version; + + /* Make use of the new i2c functions from FW 1.20 */ + dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); + if (fw_version >= 0x10200) + st->fw_use_new_i2c_api = 1; + dib0700_set_i2c_speed(adap->dev, 340); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80); + + if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { + deb_info("%s: Upload failed. (file not found?)\n", __func__); + return -ENODEV; + } else { + deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); + } + stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; + stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; + + adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe); + u16 data_dib190[10] = { + 1, 0x1374, + 2, 0x01a2, + 7, 0x0020, + 0, 0x00ef, + 8, 0x0486, + }; + + if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL) + return -ENODEV; + i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) + return -ENODEV; + dib0700_set_i2c_speed(adap->dev, 2000); + if (dib9000_firmware_post_pll_init(adap->fe) < 0) + return -ENODEV; + release_firmware(state->frontend_firmware); + return 0; +} + +static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *i2c; + struct dvb_frontend *fe_slave; + u32 fw_version; + + /* Make use of the new i2c functions from FW 1.20 */ + dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); + if (fw_version >= 0x10200) + st->fw_use_new_i2c_api = 1; + dib0700_set_i2c_speed(adap->dev, 340); + + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { + deb_info("%s: Upload failed. (file not found?)\n", __func__); + return -EIO; + } else { + deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size); + } + nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size; + nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data; + nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size; + nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; + + dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); + adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); + + if (adap->fe == NULL) + return -ENODEV; + + i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); + dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); + + fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); + dib9000_set_slave_frontend(adap->fe, fe_slave); + + return fe_slave == NULL ? -ENODEV : 0; } -static struct dib8000_config dib809x_dib8000_config = { - .output_mpeg2_in_188_bytes = 1, - - .agc_config_count = 2, - .agc = dib8090_agc_config, - .agc_control = dib0090_dcc_freq, - .pll = &dib8090_pll_config_12mhz, - .tuner_is_baseband = 1, - - .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, - - .hostbus_diversity = 1, - .div_cfg = 0x31, - .output_mode = OUTMODE_MPEG2_FIFO, - .drives = 0x2d98, - .diversity_delay = 144, - .refclksel = 3, +static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *state = adap->priv; + struct i2c_adapter *i2c; + struct dvb_frontend *fe_slave; + u16 data_dib190[10] = { + 1, 0x5374, + 2, 0x01ae, + 7, 0x0020, + 0, 0x00ef, + 8, 0x0406, + }; + i2c = dib9000_get_tuner_interface(adap->fe); + if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL) + return -ENODEV; + i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) + return -ENODEV; + dib0700_set_i2c_speed(adap->dev, 2000); + if (dib9000_firmware_post_pll_init(adap->fe) < 0) + return -ENODEV; + + fe_slave = dib9000_get_slave_frontend(adap->fe, 1); + if (fe_slave != NULL) { + i2c = dib9000_get_component_bus_interface(adap->fe); + dib9000_set_i2c_adapter(fe_slave, i2c); + + i2c = dib9000_get_tuner_interface(fe_slave); + if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) + return -ENODEV; + fe_slave->dvb = adap->fe->dvb; + dib9000_fw_set_component_bus_speed(adap->fe, 2000); + if (dib9000_firmware_post_pll_init(fe_slave) < 0) + return -ENODEV; + } + release_firmware(state->frontend_firmware); + + return 0; +} + +/* NIM7090 */ +struct dib7090p_best_adc { + u32 timf; + u32 pll_loopdiv; + u32 pll_prediv; +}; + +static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc) +{ + u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1; + + u16 xtal = 12000; + u32 fcp_min = 1900; /* PLL Minimum Frequency comparator KHz */ + u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */ + u32 fdem_max = 76000; + u32 fdem_min = 69500; + u32 fcp = 0, fs = 0, fdem = 0; + u32 harmonic_id = 0; + + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + adc->timf = 0; + + deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min); + + /* Find Min and Max prediv */ + while((xtal/max_prediv) >= fcp_min) + max_prediv++; + + max_prediv--; + min_prediv = max_prediv; + while((xtal/min_prediv) <= fcp_max) { + min_prediv--; + if(min_prediv == 1) + break; + } + deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv); + + min_prediv = 2; + + for(prediv = min_prediv ; prediv < max_prediv; prediv ++) { + fcp = xtal / prediv; + if(fcp > fcp_min && fcp < fcp_max) { + for(loopdiv = 1 ; loopdiv < 64 ; loopdiv++) { + fdem = ((xtal/prediv) * loopdiv); + fs = fdem / 4; + /* test min/max system restrictions */ + + if((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) { + spur = 0; + /* test fs harmonics positions */ + for(harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ; harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) { + if(((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) && ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) { + spur = 1; + break; + } + } + + if(!spur) { + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + adc->timf = 2396745143UL/fdem*(1<<9); + adc->timf+= ((2396745143UL%fdem)<< 9)/fdem; + deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf); + break; + } + } + } + } + if (!spur) + break; + } + + + if(adc->pll_loopdiv == 0 && adc->pll_prediv == 0) { + return -EINVAL; + } else + return 0; +} + +static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + struct dibx000_bandwidth_config pll; + u16 target; + struct dib7090p_best_adc adc; + int ret; + + ret = state->set_param_save(fe, fep); + if (ret < 0) + return ret; + + memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); + dib0090_pwm_gain_reset(fe); + target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2; + dib7000p_set_wbd_ref(fe, target); + + if(dib7090p_get_best_sampling(fe, &adc) == 0) { + pll.pll_ratio = adc.pll_loopdiv; + pll.pll_prediv = adc.pll_prediv; + + dib7000p_update_pll(fe, &pll); + dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); + } + return 0; +} + +static struct dib0090_wbd_slope dib7090_wbd_table[] = { + { 380, 81, 850, 64, 540 ,4}, + { 860, 51, 866, 21, 375 ,4}, + {1700, 0, 250, 0, 100, 6}, //LBAND Predefinition , NOT tested Yet + {2600, 0, 250, 0, 100, 6}, //SBAND Predefinition , NOT tested Yet + { 0xFFFF, 0, 0, 0, 0 ,0}, }; -static struct dib0090_config dib809x_dib0090_config = { - .io.pll_bypass = 1, - .io.pll_range = 1, - .io.pll_prediv = 1, - .io.pll_loopdiv = 20, - .io.adc_clock_ratio = 8, - .io.pll_int_loop_filt = 0, - .io.clock_khz = 12000, - .reset = dib80xx_tuner_reset, - .sleep = dib80xx_tuner_sleep, - .clkouttobamse = 1, - .analog_output = 1, - .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, - .wbd_vhf_offset = 100, - .wbd_cband_offset = 450, - .use_pwm_agc = 1, - .clkoutdrive = 1, - .get_adc_power = dib8090_get_adc_power, - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = -143, -}; +struct dibx000_agc_config dib7090_agc_config[2] = { + { + .band_caps = BAND_UHF, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + .inv_gain = 687,// inv_gain = 1/ 95.4dB // no boost, lower gain due to ramp quantification + .time_stabiliz = 10, // time_stabiliz + + .alpha_level = 0, // alpha_level + .thlock = 118, // thlock + + .wbd_inv = 0, // wbd_inv + .wbd_ref = 1200, // wbd_ref + .wbd_sel = 3, // wbd_sel + .wbd_alpha = 5, // wbd_alpha + + .agc1_max = 65535, // agc1_max + .agc1_min = 0, // agc1_min + + .agc2_max = 65535, // agc2_max + .agc2_min = 0, // agc2_min + + .agc1_pt1 = 0, // agc1_pt1 + .agc1_pt2 = 32, // agc1_pt2 + .agc1_pt3 = 114, // agc1_pt3 // 40.4dB + .agc1_slope1 = 143, // agc1_slope1 + .agc1_slope2 = 144, // agc1_slope2 + .agc2_pt1 = 114, // agc2_pt1 + .agc2_pt2 = 227, // agc2_pt2 + .agc2_slope1 = 116, // agc2_slope1 + .agc2_slope2 = 117, // agc2_slope2 + + .alpha_mant = 18, // alpha_mant // 5Hz with 95.4dB + .alpha_exp = 0, // alpha_exp + .beta_mant = 20, // beta_mant + .beta_exp = 59, // beta_exp + + .perform_agc_softsplit = 0, // perform_agc_softsplit + } , { + .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, + * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + + .inv_gain = 732,// inv_gain = 1/ 89.5dB // no boost, lower gain due to ramp quantification + .time_stabiliz = 10, // time_stabiliz + + .alpha_level = 0, // alpha_level + .thlock = 118, // thlock + + .wbd_inv = 0, // wbd_inv + .wbd_ref = 1200, // wbd_ref + .wbd_sel = 3, // wbd_sel + .wbd_alpha = 5, // wbd_alpha + + .agc1_max = 65535, // agc1_max : 1 + .agc1_min = 0, // agc1_min + + .agc2_max = 65535, // agc2_max + .agc2_min = 0, // agc2_min + + .agc1_pt1 = 0, // agc1_pt1 + .agc1_pt2 = 0, // agc1_pt2 + .agc1_pt3 = 98, // agc1_pt3 // 34.5dB CBAND P1G + 55dB BB boost = 89.5dB + .agc1_slope1 = 0, // agc1_slope1 + .agc1_slope2 = 167, // agc1_slope2 = Dy/Dx * 2**6 * 2**8 = 1/98 * 2**6 *2**8 : Dy = 1 + .agc1_pt1 = 98, // agc2_pt1 + .agc2_pt2 = 255, // agc2_pt2 + .agc2_slope1 = 104, // agc2_slope1 = Dy/Dx * 2**6 * 2**8 = 1/(255-98) * 2**6 *2**8 + .agc2_slope2 = 0, // agc2_slope2 + + .alpha_mant = 18, // alpha_mant // 5Hz with 95.4dB + .alpha_exp = 0, // alpha_exp + .beta_mant = 20, // beta_mant + .beta_exp = 59, // beta_exp + + .perform_agc_softsplit = 0, // perform_agc_softsplit + } +}; + +static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = { + 60000, 15000, // internal, sampling + 1, 5, 0, 0, 0, // pll_cfg: prediv, ratio, range, reset, bypass + 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo + (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k + (0 << 25) | 0, // ifreq = 0.000000 MHz + 20452225, // timf + 15000000, // xtal_hz +}; + +static struct dib7000p_config nim7090_dib7000p_config = { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_FIFO, + .enMpegOutput = 1, +}; + +static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { + { + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .default_i2c_addr = 0x90, + .enMpegOutput = 1, + },{ + .output_mpeg2_in_188_bytes = 1, + .hostbus_diversity = 1, + .tuner_is_baseband = 1, + .update_lna = NULL, + + .agc_config_count = 2, + .agc = dib7090_agc_config, + + .bw = &dib7090_clock_config_12_mhz, + + .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .pwm_freq_div = 0, + + .agc_control = dib7090_agc_restart, + + .spur_protect = 0, + .disable_sample_and_hold = 0, + .enable_current_mirror = 0, + .diversity_delay = 0, + + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .default_i2c_addr = 0x92, + .enMpegOutput = 0, + } +}; + +static const struct dib0090_config nim7090_dib0090_config = { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = 0, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, +}; + +static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { + { + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = 50, + .freq_offset_khz_vhf = 70, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + },{ + .io.clock_khz = 12000, + .io.pll_bypass = 0, + .io.pll_range = 0, + .io.pll_prediv = 3, + .io.pll_loopdiv = 6, + .io.adc_clock_ratio = 0, + .io.pll_int_loop_filt = 0, + .reset = dib7090_tuner_sleep, + .sleep = dib7090_tuner_sleep, + + .freq_offset_khz_uhf = -50, + .freq_offset_khz_vhf = -70, + + .get_adc_power = dib7090_get_adc_power, + + .clkouttobamse = 1, + .analog_output = 0, + + .wbd_vhf_offset = 0, + .wbd_cband_offset = 0, + .use_pwm_agc = 1, + .clkoutdrive = 0, + + .fref_clock_ratio = 0, + + .wbd = dib7090_wbd_table, + + .ls_cfg_pad_drv = 0, + .data_tx_drv = 0, + .low_if = NULL, + .in_soc = 1, + } +}; + +static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); -static int dib8096_set_param_override(struct dvb_frontend *fe, - struct dvb_frontend_parameters *fep) -{ - struct dvb_usb_adapter *adap = fe->dvb->priv; - struct dib0700_adapter_state *state = adap->priv; - u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); - u16 offset; - int ret = 0; - enum frontend_tune_state tune_state = CT_SHUTDOWN; - u16 ltgain, rf_gain_limit; - - ret = state->set_param_save(fe, fep); - if (ret < 0) - return ret; - - switch (band) { - case BAND_VHF: - offset = 100; - break; - case BAND_UHF: - offset = 550; - break; - default: - offset = 0; - break; - } - offset += (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; - dib8000_set_wbd_ref(fe, offset); - - - if (band == BAND_CBAND) { - deb_info("tuning in CBAND - soft-AGC startup\n"); - /* TODO specific wbd target for dib0090 - needed for startup ? */ - dib0090_set_tune_state(fe, CT_AGC_START); - do { - ret = dib0090_gain_control(fe); - msleep(ret); - tune_state = dib0090_get_tune_state(fe); - if (tune_state == CT_AGC_STEP_0) - dib8000_set_gpio(fe, 6, 0, 1); - else if (tune_state == CT_AGC_STEP_1) { - dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); - if (rf_gain_limit == 0) - dib8000_set_gpio(fe, 6, 0, 0); - } - } while (tune_state < CT_AGC_STOP); - dib0090_pwm_gain_reset(fe); - dib8000_pwm_agc_reset(fe); - dib8000_set_tune_state(fe, CT_DEMOD_START); - } else { - deb_info("not tuning in CBAND - standard AGC startup\n"); - dib0090_pwm_gain_reset(fe); - } + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); - return 0; + return adap->fe == NULL ? -ENODEV : 0; } -static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) +static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) { - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL) + return -ENODEV; - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) - return -ENODEV; + dib7000p_set_gpio(adap->fe, 8, 0, 1); - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; - return 0; + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; } -static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) +static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) { + struct dib0700_state *st = adap->dev->priv; + + /* The TFE7090 requires the dib0700 to not be in master mode */ + st->disable_streaming_master_mode = 1; + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - dib0700_ctrl_clock(adap->dev, 72, 1); - msleep(10); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); + /* initialize IC 0 */ + if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config); + dib0700_set_i2c_speed(adap->dev, 340); + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + dib7090_slave_reset(adap->fe); + + if (adap->fe == NULL) + return -ENODEV; + + return 0; +} + +static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) +{ + struct i2c_adapter *i2c; + + if (adap->dev->adapter[0].fe == NULL) { + err("the master dib7090 has to be initialized first"); + return -ENODEV; /* the master device has not been initialized */ + } + + i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { + err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + return -ENODEV; + } + + adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); + dib0700_set_i2c_speed(adap->dev, 200); + + return adap->fe == NULL ? -ENODEV : 0; +} + +static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe, 8, 0, 1); + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; +} + +static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) + return -ENODEV; + + dib7000p_set_gpio(adap->fe, 8, 0, 1); + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + return 0; } /* STK7070PD */ @@ -1856,6 +2797,11 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DIVERSITY) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090M) }, +/* 70 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM8096MD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090MD) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -2609,6 +3555,205 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = dib90x0_pid_filter, + .pid_filter_ctrl = dib90x0_pid_filter_ctrl, + .frontend_attach = stk9090m_frontend_attach, + .tuner_attach = dib9090_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK9090M reference design", + { &dib0700_usb_id_table[69], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = nim8096md_frontend_attach, + .tuner_attach = nim8096md_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM8096MD reference design", + { &dib0700_usb_id_table[70], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = dib90x0_pid_filter, + .pid_filter_ctrl = dib90x0_pid_filter_ctrl, + .frontend_attach = nim9090md_frontend_attach, + .tuner_attach = nim9090md_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM9090MD reference design", + { &dib0700_usb_id_table[71], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = nim7090_frontend_attach, + .tuner_attach = nim7090_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom NIM7090 reference design", + { &dib0700_usb_id_table[72], NULL }, + { NULL }, + }, + }, + + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_DIB0700_RC5_TABLE, + .module_name = "dib0700", + .rc_query = dib0700_rc_query_old_firmware, + .allowed_protos = RC_TYPE_RC5 | + RC_TYPE_RC6 | + RC_TYPE_NEC, + .change_protocol = dib0700_change_protocol, + }, + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 2, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090pvr_frontend0_attach, + .tuner_attach = tfe7090pvr_tuner0_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x03), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk70x0p_pid_filter, + .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, + .frontend_attach = tfe7090pvr_frontend1_attach, + .tuner_attach = tfe7090pvr_tuner1_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom TFE7090PVR reference design", + { &dib0700_usb_id_table[73], NULL }, + { NULL }, + }, + }, + .rc.core = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index d0bce0445cc7..b71540d7e070 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -106,8 +106,13 @@ #define USB_PID_DIBCOM_STK807XP 0x1f90 #define USB_PID_DIBCOM_STK807XPVR 0x1f98 #define USB_PID_DIBCOM_STK8096GP 0x1fa0 +#define USB_PID_DIBCOM_NIM8096MD 0x1fa8 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DIBCOM_STK7770P 0x1e80 +#define USB_PID_DIBCOM_NIM7090 0x1bb2 +#define USB_PID_DIBCOM_TFE7090PVR 0x1bb4 +#define USB_PID_DIBCOM_NIM9090M 0x2383 +#define USB_PID_DIBCOM_NIM9090MD 0x2384 #define USB_PID_DPOSH_M9206_COLD 0x9206 #define USB_PID_DPOSH_M9206_WARM 0xa090 #define USB_PID_E3C_EC168 0x1689 -- cgit v1.2.2 From b4d6046e841955be9cc49164b03b91c9524f9c2e Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Tue, 4 Jan 2011 13:08:14 -0300 Subject: [media] DiBxxxx: Codingstype updates This patchs fix several conding-style violations. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_core.c | 9 +- drivers/media/dvb/dvb-usb/dib0700_devices.c | 263 +++++++++++---------- drivers/media/dvb/frontends/dib0090.c | 337 ++++++++++++--------------- drivers/media/dvb/frontends/dib7000p.c | 205 ++++++++-------- drivers/media/dvb/frontends/dib7000p.h | 2 +- drivers/media/dvb/frontends/dib8000.c | 163 ++++++------- drivers/media/dvb/frontends/dib8000.h | 7 +- drivers/media/dvb/frontends/dib9000.c | 204 ++++++++-------- drivers/media/dvb/frontends/dib9000.h | 5 +- drivers/media/dvb/frontends/dibx000_common.c | 61 +++-- drivers/media/dvb/frontends/dibx000_common.h | 10 +- 11 files changed, 598 insertions(+), 668 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 9ab57132b444..b79af68c54ae 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -347,7 +347,8 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) b[6] = (u8) (divider >> 8); b[7] = (u8) (divider & 0xff); - deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", (b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz); + deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", + (b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz); return dib0700_ctrl_wr(d, b, 8); } @@ -484,14 +485,14 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id); st->channel_state &= ~0x3; - if ((adap->stream.props.endpoint != 2) && (adap->stream.props.endpoint != 3)) { + if ((adap->stream.props.endpoint != 2) + && (adap->stream.props.endpoint != 3)) { deb_info("the endpoint number (%i) is not correct, use the adapter id instead", adap->stream.props.endpoint); if (onoff) st->channel_state |= 1 << (adap->id); else st->channel_state |= 1 << ~(adap->id); - } - else { + } else { if (onoff) st->channel_state |= 1 << (adap->stream.props.endpoint-2); else diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 2b919034db87..c25b4281cff4 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1444,7 +1444,7 @@ static struct dib8000_config dib809x_dib8000_config[2] = { .drives = 0x2d98, .diversity_delay = 48, .refclksel = 3, - },{ + }, { .output_mpeg2_in_188_bytes = 1, .agc_config_count = 2, @@ -1517,27 +1517,26 @@ static int dib8096_set_param_override(struct dvb_frontend *fe, if (band == BAND_CBAND) { - deb_info("tuning in CBAND - soft-AGC startup\n"); - /* TODO specific wbd target for dib0090 - needed for startup ? */ - dib0090_set_tune_state(fe, CT_AGC_START); - do { - ret = dib0090_gain_control(fe); - msleep(ret); - tune_state = dib0090_get_tune_state(fe); - if (tune_state == CT_AGC_STEP_0) - dib8000_set_gpio(fe, 6, 0, 1); - else if (tune_state == CT_AGC_STEP_1) { - dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); - if (rf_gain_limit == 0) - dib8000_set_gpio(fe, 6, 0, 0); - } - } while (tune_state < CT_AGC_STOP); - dib0090_pwm_gain_reset(fe); - dib8000_pwm_agc_reset(fe); - dib8000_set_tune_state(fe, CT_DEMOD_START); + deb_info("tuning in CBAND - soft-AGC startup\n"); + dib0090_set_tune_state(fe, CT_AGC_START); + do { + ret = dib0090_gain_control(fe); + msleep(ret); + tune_state = dib0090_get_tune_state(fe); + if (tune_state == CT_AGC_STEP_0) + dib8000_set_gpio(fe, 6, 0, 1); + else if (tune_state == CT_AGC_STEP_1) { + dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); + if (rf_gain_limit == 0) + dib8000_set_gpio(fe, 6, 0, 0); + } + } while (tune_state < CT_AGC_STOP); + dib0090_pwm_gain_reset(fe); + dib8000_pwm_agc_reset(fe); + dib8000_set_tune_state(fe, CT_DEMOD_START); } else { - deb_info("not tuning in CBAND - standard AGC startup\n"); - dib0090_pwm_gain_reset(fe); + deb_info("not tuning in CBAND - standard AGC startup\n"); + dib0090_pwm_gain_reset(fe); } return 0; @@ -1608,7 +1607,7 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) struct dvb_frontend *fe_slave; dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(1000); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); @@ -1619,9 +1618,9 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) dib0700_ctrl_clock(adap->dev, 72, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); @@ -1662,8 +1661,8 @@ static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 }; u8 rb[2]; struct i2c_msg msg[2] = { - {.addr = 0x1e >> 1,.flags = 0,.buf = wb,.len = 2}, - {.addr = 0x1e >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2}, + {.addr = 0x1e >> 1, .flags = 0, .buf = wb, .len = 2}, + {.addr = 0x1e >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, }; u8 index_data; @@ -1673,19 +1672,19 @@ static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) return -EIO; switch (rb[0] << 8 | rb[1]) { - case 0: + case 0: deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n"); return -EIO; - case 1: + case 1: deb_info("Found DiB0170 rev2"); break; - case 2: + case 2: deb_info("Found DiB0190 rev2"); break; - default: + default: deb_info("DiB01x0 not found"); return -EIO; - } + } for (index_data = 0; index_data < len; index_data += 2) { wb[2] = (data[index_data + 1] >> 8) & 0xff; @@ -1701,8 +1700,8 @@ static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len) wb[3] |= rb[1] & ~(3 << 4); } - wb[0] = (data[index_data ] >> 8)&0xff; - wb[1] = (data[index_data ] )&0xff; + wb[0] = (data[index_data] >> 8)&0xff; + wb[1] = (data[index_data])&0xff; msg[0].len = 4; if (i2c_transfer(i2c, &msg[0], 1) != 1) return -EIO; @@ -1799,7 +1798,7 @@ static struct dib0090_config nim9090md_dib0090_config[2] = { .clkoutdrive = 0, .freq_offset_khz_uhf = 0, .freq_offset_khz_vhf = 0, - },{ + }, { .io.pll_bypass = 0, .io.pll_range = 1, .io.pll_prediv = 1, @@ -1832,7 +1831,7 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 340); dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); @@ -1840,9 +1839,9 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) dib0700_ctrl_clock(adap->dev, 72, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80); @@ -1881,7 +1880,7 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 2000); if (dib9000_firmware_post_pll_init(adap->fe) < 0) return -ENODEV; - release_firmware(state->frontend_firmware); + release_firmware(state->frontend_firmware); return 0; } @@ -1900,7 +1899,7 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 340); dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); @@ -1908,9 +1907,9 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) dib0700_ctrl_clock(adap->dev, 72, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) { @@ -1974,7 +1973,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) if (dib9000_firmware_post_pll_init(fe_slave) < 0) return -ENODEV; } - release_firmware(state->frontend_firmware); + release_firmware(state->frontend_firmware); return 0; } @@ -2005,43 +2004,43 @@ static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_ deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min); /* Find Min and Max prediv */ - while((xtal/max_prediv) >= fcp_min) + while ((xtal/max_prediv) >= fcp_min) max_prediv++; max_prediv--; min_prediv = max_prediv; - while((xtal/min_prediv) <= fcp_max) { + while ((xtal/min_prediv) <= fcp_max) { min_prediv--; - if(min_prediv == 1) + if (min_prediv == 1) break; } deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv); min_prediv = 2; - for(prediv = min_prediv ; prediv < max_prediv; prediv ++) { + for (prediv = min_prediv ; prediv < max_prediv; prediv++) { fcp = xtal / prediv; - if(fcp > fcp_min && fcp < fcp_max) { - for(loopdiv = 1 ; loopdiv < 64 ; loopdiv++) { + if (fcp > fcp_min && fcp < fcp_max) { + for (loopdiv = 1 ; loopdiv < 64 ; loopdiv++) { fdem = ((xtal/prediv) * loopdiv); fs = fdem / 4; /* test min/max system restrictions */ - if((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) { + if ((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) { spur = 0; /* test fs harmonics positions */ - for(harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ; harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) { - if(((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) && ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) { + for (harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ; harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) { + if (((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) && ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) { spur = 1; break; } } - if(!spur) { + if (!spur) { adc->pll_loopdiv = loopdiv; adc->pll_prediv = prediv; - adc->timf = 2396745143UL/fdem*(1<<9); - adc->timf+= ((2396745143UL%fdem)<< 9)/fdem; + adc->timf = 2396745143UL/fdem*(1 << 9); + adc->timf += ((2396745143UL%fdem) << 9)/fdem; deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf); break; } @@ -2053,9 +2052,9 @@ static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_ } - if(adc->pll_loopdiv == 0 && adc->pll_prediv == 0) { + if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0) return -EINVAL; - } else + else return 0; } @@ -2077,7 +2076,7 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2; dib7000p_set_wbd_ref(fe, target); - if(dib7090p_get_best_sampling(fe, &adc) == 0) { + if (dib7090p_get_best_sampling(fe, &adc) == 0) { pll.pll_ratio = adc.pll_loopdiv; pll.pll_prediv = adc.pll_prediv; @@ -2088,11 +2087,11 @@ static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_para } static struct dib0090_wbd_slope dib7090_wbd_table[] = { - { 380, 81, 850, 64, 540 ,4}, - { 860, 51, 866, 21, 375 ,4}, - {1700, 0, 250, 0, 100, 6}, //LBAND Predefinition , NOT tested Yet - {2600, 0, 250, 0, 100, 6}, //SBAND Predefinition , NOT tested Yet - { 0xFFFF, 0, 0, 0, 0 ,0}, + { 380, 81, 850, 64, 540, 4}, + { 860, 51, 866, 21, 375, 4}, + {1700, 0, 250, 0, 100, 6}, + {2600, 0, 250, 0, 100, 6}, + { 0xFFFF, 0, 0, 0, 0, 0}, }; struct dibx000_agc_config dib7090_agc_config[2] = { @@ -2100,91 +2099,91 @@ struct dibx000_agc_config dib7090_agc_config[2] = { .band_caps = BAND_UHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - .inv_gain = 687,// inv_gain = 1/ 95.4dB // no boost, lower gain due to ramp quantification - .time_stabiliz = 10, // time_stabiliz + .inv_gain = 687, + .time_stabiliz = 10, - .alpha_level = 0, // alpha_level - .thlock = 118, // thlock + .alpha_level = 0, + .thlock = 118, - .wbd_inv = 0, // wbd_inv - .wbd_ref = 1200, // wbd_ref - .wbd_sel = 3, // wbd_sel - .wbd_alpha = 5, // wbd_alpha + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, - .agc1_max = 65535, // agc1_max - .agc1_min = 0, // agc1_min + .agc1_max = 65535, + .agc1_min = 0, - .agc2_max = 65535, // agc2_max - .agc2_min = 0, // agc2_min + .agc2_max = 65535, + .agc2_min = 0, - .agc1_pt1 = 0, // agc1_pt1 - .agc1_pt2 = 32, // agc1_pt2 - .agc1_pt3 = 114, // agc1_pt3 // 40.4dB - .agc1_slope1 = 143, // agc1_slope1 - .agc1_slope2 = 144, // agc1_slope2 - .agc2_pt1 = 114, // agc2_pt1 - .agc2_pt2 = 227, // agc2_pt2 - .agc2_slope1 = 116, // agc2_slope1 - .agc2_slope2 = 117, // agc2_slope2 + .agc1_pt1 = 0, + .agc1_pt2 = 32, + .agc1_pt3 = 114, + .agc1_slope1 = 143, + .agc1_slope2 = 144, + .agc2_pt1 = 114, + .agc2_pt2 = 227, + .agc2_slope1 = 116, + .agc2_slope2 = 117, - .alpha_mant = 18, // alpha_mant // 5Hz with 95.4dB - .alpha_exp = 0, // alpha_exp - .beta_mant = 20, // beta_mant - .beta_exp = 59, // beta_exp + .alpha_mant = 18, + .alpha_exp = 0, + .beta_mant = 20, + .beta_exp = 59, - .perform_agc_softsplit = 0, // perform_agc_softsplit + .perform_agc_softsplit = 0, } , { .band_caps = BAND_FM | BAND_VHF | BAND_CBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - .inv_gain = 732,// inv_gain = 1/ 89.5dB // no boost, lower gain due to ramp quantification - .time_stabiliz = 10, // time_stabiliz + .inv_gain = 732, + .time_stabiliz = 10, - .alpha_level = 0, // alpha_level - .thlock = 118, // thlock + .alpha_level = 0, + .thlock = 118, - .wbd_inv = 0, // wbd_inv - .wbd_ref = 1200, // wbd_ref - .wbd_sel = 3, // wbd_sel - .wbd_alpha = 5, // wbd_alpha + .wbd_inv = 0, + .wbd_ref = 1200, + .wbd_sel = 3, + .wbd_alpha = 5, - .agc1_max = 65535, // agc1_max : 1 - .agc1_min = 0, // agc1_min + .agc1_max = 65535, + .agc1_min = 0, - .agc2_max = 65535, // agc2_max - .agc2_min = 0, // agc2_min + .agc2_max = 65535, + .agc2_min = 0, - .agc1_pt1 = 0, // agc1_pt1 - .agc1_pt2 = 0, // agc1_pt2 - .agc1_pt3 = 98, // agc1_pt3 // 34.5dB CBAND P1G + 55dB BB boost = 89.5dB - .agc1_slope1 = 0, // agc1_slope1 - .agc1_slope2 = 167, // agc1_slope2 = Dy/Dx * 2**6 * 2**8 = 1/98 * 2**6 *2**8 : Dy = 1 - .agc1_pt1 = 98, // agc2_pt1 - .agc2_pt2 = 255, // agc2_pt2 - .agc2_slope1 = 104, // agc2_slope1 = Dy/Dx * 2**6 * 2**8 = 1/(255-98) * 2**6 *2**8 - .agc2_slope2 = 0, // agc2_slope2 + .agc1_pt1 = 0, + .agc1_pt2 = 0, + .agc1_pt3 = 98, + .agc1_slope1 = 0, + .agc1_slope2 = 167, + .agc1_pt1 = 98, + .agc2_pt2 = 255, + .agc2_slope1 = 104, + .agc2_slope2 = 0, - .alpha_mant = 18, // alpha_mant // 5Hz with 95.4dB - .alpha_exp = 0, // alpha_exp - .beta_mant = 20, // beta_mant - .beta_exp = 59, // beta_exp + .alpha_mant = 18, + .alpha_exp = 0, + .beta_mant = 20, + .beta_exp = 59, - .perform_agc_softsplit = 0, // perform_agc_softsplit + .perform_agc_softsplit = 0, } }; static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = { - 60000, 15000, // internal, sampling - 1, 5, 0, 0, 0, // pll_cfg: prediv, ratio, range, reset, bypass - 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo - (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k - (0 << 25) | 0, // ifreq = 0.000000 MHz - 20452225, // timf - 15000000, // xtal_hz + 60000, 15000, + 1, 5, 0, 0, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20452225, + 15000000, }; static struct dib7000p_config nim7090_dib7000p_config = { @@ -2243,7 +2242,7 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, .default_i2c_addr = 0x90, .enMpegOutput = 1, - },{ + }, { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, @@ -2340,7 +2339,7 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { .data_tx_drv = 0, .low_if = NULL, .in_soc = 1, - },{ + }, { .io.clock_khz = 12000, .io.pll_bypass = 0, .io.pll_range = 0, @@ -2378,15 +2377,15 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) { dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { @@ -2421,15 +2420,15 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) st->disable_streaming_master_mode = 1; dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(10); + msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); /* initialize IC 0 */ @@ -2441,7 +2440,7 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 340); adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - dib7090_slave_reset(adap->fe); + dib7090_slave_reset(adap->fe); if (adap->fe == NULL) return -ENODEV; diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index 0e87a0bdf7ab..52ff1a252a90 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c @@ -204,8 +204,8 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) { u8 b[2]; struct i2c_msg msg[2] = { - {.addr = state->config->i2c_address,.flags = 0,.buf = ®,.len = 1}, - {.addr = state->config->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2}, + {.addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1}, + {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2}, }; if (i2c_transfer(state->i2c, msg, 2) != 2) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); @@ -217,7 +217,7 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) { u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; - struct i2c_msg msg = {.addr = state->config->i2c_address,.flags = 0,.buf = b,.len = 3 }; + struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 }; if (i2c_transfer(state->i2c, &msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); return -EREMOTEIO; @@ -228,7 +228,7 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) { u8 b[2]; - struct i2c_msg msg = {.addr = reg,.flags = I2C_M_RD,.buf = b,.len = 2 }; + struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 }; if (i2c_transfer(state->i2c, &msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); return 0; @@ -239,7 +239,7 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) { u8 b[2] = { val >> 8, val & 0xff }; - struct i2c_msg msg = {.addr = reg,.flags = 0,.buf = b,.len = 2 }; + struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 }; if (i2c_transfer(state->i2c, &msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); return -EREMOTEIO; @@ -347,7 +347,7 @@ static int dib0090_identify(struct dvb_frontend *fe) return 0; - identification_error: +identification_error: return -EIO; } @@ -371,8 +371,6 @@ static int dib0090_fw_identify(struct dvb_frontend *fe) if (identity->product != KROSUS) goto identification_error; - //From the SOC the version definition has changed - if ((identity->version & 0x3) == SOC) { identity->in_soc = 1; switch (identity->version) { @@ -439,7 +437,7 @@ static int dib0090_fw_identify(struct dvb_frontend *fe) return 0; - identification_error: +identification_error: return -EIO;; } @@ -1009,7 +1007,6 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) if (state->current_band == BAND_VHF) { if (state->identity.in_soc) { dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); - //dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf_socs); /* TODO */ } else { dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); @@ -1044,9 +1041,8 @@ EXPORT_SYMBOL(dib0090_pwm_gain_reset); static u32 dib0090_get_slow_adc_val(struct dib0090_state *state) { u16 adc_val = dib0090_read_reg(state, 0x1d); - if (state->identity.in_soc) { + if (state->identity.in_soc) adc_val >>= 2; - } return adc_val; } @@ -1200,7 +1196,7 @@ int dib0090_gain_control(struct dvb_frontend *fe) #ifdef DEBUG_AGC dprintk ("tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", - (u32) * tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, + (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); #endif } @@ -1246,26 +1242,20 @@ u16 dib0090_get_wbd_offset(struct dvb_frontend *fe) if (current_temp > 128) current_temp = 128; - //What Wbd gain to apply for this range of frequency state->wbdmux &= ~(7 << 13); if (wbd->wbd_gain != 0) state->wbdmux |= (wbd->wbd_gain << 13); else - state->wbdmux |= (4 << 13); // 4 is the default WBD gain + state->wbdmux |= (4 << 13); dib0090_write_reg(state, 0x10, state->wbdmux); - //All the curves are linear with slope*f/64+offset wbd_thot = wbd->offset_hot - (((u32) wbd->slope_hot * f_MHz) >> 6); wbd_tcold = wbd->offset_cold - (((u32) wbd->slope_cold * f_MHz) >> 6); - // Iet assumes that thot-tcold = 130 equiv 128, current temperature ref is -30deg - wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7; - //for (offset = 0; offset < 1000; offset += 4) - // dbgp("offset = %d -> %d\n", offset, dib0090_wbd_to_db(state, offset)); - state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold); // get the value in dBm from the offset + state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold); dprintk("wbd-target: %d dB", (u32) state->wbd_target); dprintk("wbd offset applied is %d", wbd_tcold); @@ -1323,7 +1313,6 @@ static const u16 dib0090_defaults[] = { }; static const u16 dib0090_p1g_additionnal_defaults[] = { - // additionnal INITIALISATION for p1g to be written after dib0090_defaults 1, 0x05, 0xabcd, @@ -1362,45 +1351,44 @@ static void dib0090_set_default_config(struct dib0090_state *state, const u16 * void dib0090_set_EFUSE(struct dib0090_state *state) { - u8 c,h,n; - u16 e2,e4; - u16 cal; - - e2=dib0090_read_reg(state,0x26); - e4=dib0090_read_reg(state,0x28); - - if ((state->identity.version == P1D_E_F) || // All P1F uses the internal calibration - (state->identity.version == P1G) || (e2 == 0xffff)) { //W0090G11R1 and W0090G11R1-D : We will find the calibration Value of the Baseband - - dib0090_write_reg(state,0x22,0x10); //Start the Calib - cal = (dib0090_read_reg(state,0x22)>>6) & 0x3ff; - - if ((cal<670) || (cal==1023)) //Cal at 800 would give too high value for the n - cal=850; //Recenter the n to 32 - n = 165 - ((cal * 10)>>6) ; - e2 = e4 = (3<<12) | (34<<6) | (n); - } - - if (e2!=e4) { - e2 &= e4; /* Remove the redundancy */ - } - - if (e2 != 0xffff) { - c = e2 & 0x3f; - n = (e2 >> 12) & 0xf; - h= (e2 >> 6) & 0x3f; - - if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN)) - c=32; - if ((h >= HR_MAX) || (h <= HR_MIN)) - h=34; - if ((n >= POLY_MAX) || (n <= POLY_MIN)) - n=3; - - dib0090_write_reg(state,0x13, (h << 10)) ; - e2 = (n<<11) | ((h>>2)<<6) | (c); - dib0090_write_reg(state,0x2, e2) ; /* Load the BB_2 */ - } + u8 c, h, n; + u16 e2, e4; + u16 cal; + + e2 = dib0090_read_reg(state, 0x26); + e4 = dib0090_read_reg(state, 0x28); + + if ((state->identity.version == P1D_E_F) || + (state->identity.version == P1G) || (e2 == 0xffff)) { + + dib0090_write_reg(state, 0x22, 0x10); + cal = (dib0090_read_reg(state, 0x22) >> 6) & 0x3ff; + + if ((cal < 670) || (cal == 1023)) + cal = 850; + n = 165 - ((cal * 10)>>6) ; + e2 = e4 = (3<<12) | (34<<6) | (n); + } + + if (e2 != e4) + e2 &= e4; /* Remove the redundancy */ + + if (e2 != 0xffff) { + c = e2 & 0x3f; + n = (e2 >> 12) & 0xf; + h = (e2 >> 6) & 0x3f; + + if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN)) + c = 32; + if ((h >= HR_MAX) || (h <= HR_MIN)) + h = 34; + if ((n >= POLY_MAX) || (n <= POLY_MIN)) + n = 3; + + dib0090_write_reg(state, 0x13, (h << 10)) ; + e2 = (n<<11) | ((h>>2)<<6) | (c); + dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */ + } } static int dib0090_reset(struct dvb_frontend *fe) @@ -1425,14 +1413,15 @@ static int dib0090_reset(struct dvb_frontend *fe) dib0090_set_default_config(state, dib0090_defaults); - if (state->identity.in_soc) - dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */ + if (state->identity.in_soc) + dib0090_write_reg(state, 0x18, 0x2910); /* charge pump current = 0 */ if (state->identity.p1g) dib0090_set_default_config(state, dib0090_p1g_additionnal_defaults); - if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/ - dib0090_set_EFUSE(state); + /* Update the efuse : Only available for KROSUS > P1C and SOC as well*/ + if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc)) + dib0090_set_EFUSE(state); /* Congigure in function of the crystal */ if (state->config->io.clock_khz >= 24000) @@ -1501,11 +1490,11 @@ static const struct dc_calibration dc_table[] = { static const struct dc_calibration dc_p1g_table[] = { /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ /* addr ; trim reg offset ; pga ; CTRL_BB1 value ; i or q */ - {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1}, // offset_trim2_i_chann 0 0 5 0 0 1 6 9 5 - {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0}, // offset_trim2_q_chann 0 0 5 0 0 1 7 15 11 + {0x06, 5, 1, (1 << 13) | (0 << 8) | (15 << 3), 1}, + {0x07, 11, 1, (1 << 13) | (0 << 8) | (15 << 3), 0}, /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ - {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1}, // offset_trim1_i_chann 0 0 5 0 0 1 6 4 0 - {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0}, // offset_trim1_q_chann 0 0 5 0 0 1 6 14 10 + {0x06, 0, 0, (1 << 13) | (29 << 8) | (15 << 3), 1}, + {0x06, 10, 0, (1 << 13) | (29 << 8) | (15 << 3), 0}, {0}, }; @@ -1542,8 +1531,8 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front dib0090_write_reg(state, 0x24, reg); state->wbdmux = dib0090_read_reg(state, 0x10); - dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3); // connect BB, disable WDB enable* - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); //Discard the DataTX + dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x7 << 3) | 0x3); + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); state->dc = dc_table; @@ -1596,11 +1585,11 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front if ((state->adc_diff & 0x8000) == (state->min_adc_diff & 0x8000) && steps(state->step) < 15) { /* stop search when the delta the sign is changing and Steps =15 and Step=0 is force for continuance */ state->step++; - state->min_adc_diff = state->adc_diff; //min is used as N-1 + state->min_adc_diff = state->adc_diff; *tune_state = CT_TUNER_STEP_1; } else { /* the minimum was what we have seen in the step before */ - if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { //Come back to the previous state since the delta was better + if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff); state->step--; } @@ -1618,7 +1607,7 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front break; case CT_TUNER_STEP_6: - dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); //Force the test bus to be off + dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); dib0090_write_reg(state, 0x1f, 0x7); *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ state->calibrate &= ~DC_CAL; @@ -1653,9 +1642,9 @@ static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tu return 0; } - dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3)); // Force: WBD enable,gain to 4, mux to WBD + dib0090_write_reg(state, 0x10, 0x1b81 | (1 << 10) | (wbd_gain << 13) | (1 << 3)); - dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1))); //Discard all LNA but crystal !!! + dib0090_write_reg(state, 0x24, ((EN_UHF & 0x0fff) | (1 << 1))); *tune_state = CT_TUNER_STEP_0; state->wbd_calibration_gain = wbd_gain; return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ @@ -1788,98 +1777,94 @@ static const struct dib0090_tuning dib0090_tuning_table[] = { }; static const struct dib0090_tuning dib0090_p1g_tuning_table[] = { - //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable; #ifdef CONFIG_BAND_CBAND - {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB}, // FM EN_CAB + {170000, 4, 1, 0x820f, 0x300, 0x2d22, 0x82cb, EN_CAB}, #endif #ifdef CONFIG_BAND_VHF - {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF - {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF - {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, // VHF EN_VHF + {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, #endif #ifdef CONFIG_BAND_UHF - {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {510000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {540000, 2, 1, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {600000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {630000, 2, 4, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {680000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {720000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, #endif #ifdef CONFIG_BAND_LBAND - {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD - {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD - {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, #endif #ifdef CONFIG_BAND_SBAND - {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, // SBD EN_SBD - {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, // SBD EN_SBD + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, #endif }; static const struct dib0090_pll dib0090_p1g_pll_table[] = { #ifdef CONFIG_BAND_CBAND - {57000, 0, 11, 48, 6}, // CAB - {70000, 1, 11, 48, 6}, // CAB - {86000, 0, 10, 32, 4}, // CAB - {105000, 1, 10, 32, 4}, // FM - {115000, 0, 9, 24, 6}, // FM - {140000, 1, 9, 24, 6}, // MID FM VHF - {170000, 0, 8, 16, 4}, // MID FM VHF + {57000, 0, 11, 48, 6}, + {70000, 1, 11, 48, 6}, + {86000, 0, 10, 32, 4}, + {105000, 1, 10, 32, 4}, + {115000, 0, 9, 24, 6}, + {140000, 1, 9, 24, 6}, + {170000, 0, 8, 16, 4}, #endif #ifdef CONFIG_BAND_VHF - {200000, 1, 8, 16, 4}, // VHF - {230000, 0, 7, 12, 6}, // VHF - {280000, 1, 7, 12, 6}, // MID VHF UHF - {340000, 0, 6, 8, 4}, // MID VHF UHF - {380000, 1, 6, 8, 4}, // MID VHF UHF - {455000, 0, 5, 6, 6}, // MID VHF UHF + {200000, 1, 8, 16, 4}, + {230000, 0, 7, 12, 6}, + {280000, 1, 7, 12, 6}, + {340000, 0, 6, 8, 4}, + {380000, 1, 6, 8, 4}, + {455000, 0, 5, 6, 6}, #endif #ifdef CONFIG_BAND_UHF - {580000, 1, 5, 6, 6}, // UHF - {680000, 0, 4, 4, 4}, // UHF - {860000, 1, 4, 4, 4}, // UHF + {580000, 1, 5, 6, 6}, + {680000, 0, 4, 4, 4}, + {860000, 1, 4, 4, 4}, #endif #ifdef CONFIG_BAND_LBAND - {1800000, 1, 2, 2, 4}, // LBD + {1800000, 1, 2, 2, 4}, #endif #ifdef CONFIG_BAND_SBAND - {2900000, 0, 1, 1, 6}, // SBD + {2900000, 0, 1, 1, 6}, #endif }; static const struct dib0090_tuning dib0090_p1g_tuning_table_fm_vhf_on_cband[] = { - //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable; #ifdef CONFIG_BAND_CBAND - {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB // 0x8190 Good perf but higher current //0x4187 Low current - {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB - {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, // FM EN_CAB + {184000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, + {227000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, + {380000, 4, 3, 0x4187, 0x2c0, 0x2d22, 0x81cb, EN_CAB}, #endif #ifdef CONFIG_BAND_UHF - {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF - {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, // UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, #endif #ifdef CONFIG_BAND_LBAND - {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD - {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD - {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, // LBD EN_LBD + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, #endif #ifdef CONFIG_BAND_SBAND - {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, // SBD EN_SBD - {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, // SBD EN_SBD + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, #endif }; static const struct dib0090_tuning dib0090_tuning_table_cband_7090[] = { - //max_freq, switch_trim, lna_tune, lna_bias, v2i, mix, load, tuner_enable; #ifdef CONFIG_BAND_CBAND - //{ 184000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB }, // 0x81ce 0x8190 Good perf but higher current //0x4187 Low current {300000, 4, 3, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, - {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, //0x4187 + {380000, 4, 10, 0x018F, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, {570000, 4, 10, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, {858000, 4, 5, 0x8190, 0x2c0, 0x2d22, 0xb9ce, EN_CAB}, #endif @@ -1916,17 +1901,15 @@ static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tun state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; } } - state->adc_diff = 3000; // start with a unreachable high number : only set for KROSUS < P1G */ + state->adc_diff = 3000; *tune_state = CT_TUNER_STEP_0; } else if (*tune_state == CT_TUNER_STEP_0) { if (state->identity.p1g && !force_soft_search) { - // 30MHz => Code 15 for the ration => 128us to lock. Giving approximately - u8 ratio = 31; // (state->config->io.clock_khz / 1024 + 1) & 0x1f; + u8 ratio = 31; dib0090_write_reg(state, 0x40, (3 << 7) | (ratio << 2) | (1 << 1) | 1); dib0090_read_reg(state, 0x40); - //dib0090_write_reg(state, 0x40, (3<<7) | ((((state->config->io.clock_khz >> 11)+1) & 0x1f)<<2) | (1<<1) | 1); ret = 50; } else { state->step /= 2; @@ -1968,9 +1951,6 @@ static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tun dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff); state->adc_diff = adc; state->fcaptrim = state->captrim; - //we could break here, to save time, if we reached a close-enough value - //e.g.: if (state->adc_diff < 20) - //break; } state->captrim += step_sign * state->step; @@ -1979,7 +1959,7 @@ static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tun else *tune_state = CT_TUNER_STEP_2; - ret = 25; //LOLO changed from 15 + ret = 25; } } else if (*tune_state == CT_TUNER_STEP_2) { /* this step is only used by krosus < P1G */ /*write the final cptrim config */ @@ -2000,28 +1980,27 @@ static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tu int ret = 15; s16 val; - //The assumption is that the AGC is not active switch (*tune_state) { case CT_TUNER_START: state->wbdmux = dib0090_read_reg(state, 0x10); - dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3)); //Move to the bias and clear the wbd enable + dib0090_write_reg(state, 0x10, (state->wbdmux & ~(0xff << 3)) | (0x8 << 3)); state->bias = dib0090_read_reg(state, 0x13); - dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8)); //Move to the Ref + dib0090_write_reg(state, 0x13, state->bias | (0x3 << 8)); *tune_state = CT_TUNER_STEP_0; /* wait for the WBDMUX to switch and for the ADC to sample */ break; case CT_TUNER_STEP_0: - state->adc_diff = dib0090_get_slow_adc_val(state); // Get the value for the Ref - dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8)); //Move to the Ptat + state->adc_diff = dib0090_get_slow_adc_val(state); + dib0090_write_reg(state, 0x13, (state->bias & ~(0x3 << 8)) | (0x2 << 8)); *tune_state = CT_TUNER_STEP_1; break; case CT_TUNER_STEP_1: - val = dib0090_get_slow_adc_val(state); // Get the value for the Ptat - state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55; // +55 is defined as = -30deg + val = dib0090_get_slow_adc_val(state); + state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55; dprintk("temperature: %d C", state->temperature - 30); @@ -2029,14 +2008,13 @@ static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tu break; case CT_TUNER_STEP_2: - //Reload the start values. dib0090_write_reg(state, 0x13, state->bias); dib0090_write_reg(state, 0x10, state->wbdmux); /* write back original WBDMUX */ *tune_state = CT_TUNER_START; state->calibrate &= ~TEMP_CAL; if (state->config->analog_output == 0) - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); //Set the DataTX + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); break; @@ -2070,16 +2048,17 @@ static int dib0090_tune(struct dvb_frontend *fe) /* deactivate DataTX before some calibrations */ if (state->calibrate & (DC_CAL | TEMP_CAL | WBD_CAL)) dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) & ~(1 << 14)); - else /* Activate DataTX in case a calibration has been done before */ if (state->config->analog_output == 0) - dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); + else + /* Activate DataTX in case a calibration has been done before */ + if (state->config->analog_output == 0) + dib0090_write_reg(state, 0x23, dib0090_read_reg(state, 0x23) | (1 << 14)); } if (state->calibrate & DC_CAL) return dib0090_dc_offset_calibration(state, tune_state); else if (state->calibrate & WBD_CAL) { - if (state->current_rf == 0) { + if (state->current_rf == 0) state->current_rf = state->fe->dtv_property_cache.frequency / 1000; - } return dib0090_wbd_calibration(state, tune_state); } else if (state->calibrate & TEMP_CAL) return dib0090_get_temperature(state, tune_state); @@ -2091,7 +2070,7 @@ static int dib0090_tune(struct dvb_frontend *fe) if (state->config->use_pwm_agc && state->identity.in_soc) { tmp = dib0090_read_reg(state, 0x39); if ((tmp >> 10) & 0x1) - dib0090_write_reg(state, 0x39, tmp & ~(1 << 10)); // disengage mux : en_mux_bb1 = 0 + dib0090_write_reg(state, 0x39, tmp & ~(1 << 10)); } state->current_band = (u8) BAND_OF_FREQUENCY(state->fe->dtv_property_cache.frequency / 1000); @@ -2172,22 +2151,17 @@ static int dib0090_tune(struct dvb_frontend *fe) state->current_tune_table_index = tune; state->current_pll_table_index = pll; - // select internal switch dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); - // Find the VCO frequency in MHz VCOF_kHz = (pll->hfdiv * state->rf_request) * 2; - FREF = state->config->io.clock_khz; // REFDIV is 1FREF Has to be as Close as possible to 10MHz + FREF = state->config->io.clock_khz; if (state->config->fref_clock_ratio != 0) FREF /= state->config->fref_clock_ratio; - // Determine the FB divider - // The reference is 10MHz, Therefore the FBdivider is on the first digits FBDiv = (VCOF_kHz / pll->topresc / FREF); - Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; //in kHz + Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; - // Avoid Spurs in the loopfilter bandwidth if (Rest < LPF) Rest = 0; else if (Rest < 2 * LPF) @@ -2195,8 +2169,7 @@ static int dib0090_tune(struct dvb_frontend *fe) else if (Rest > (FREF - LPF)) { Rest = 0; FBDiv += 1; - } //Go to the next FB - else if (Rest > (FREF - 2 * LPF)) + } else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF; Rest = (Rest * 6528) / (FREF / 10); state->rest = Rest; @@ -2208,8 +2181,6 @@ static int dib0090_tune(struct dvb_frontend *fe) if (Rest == 0) { if (pll->vco_band) lo5 = 0x049f; - //else if (state->config->analog_output) - // lo5 = 0x041f; else lo5 = 0x041f; } else { @@ -2228,12 +2199,11 @@ static int dib0090_tune(struct dvb_frontend *fe) else lo5 = 0x42f; } else - lo5 = 0x42c; //BIAS Lo set to 4 by default in case of the Captrim search does not take care of the VCO Bias + lo5 = 0x42c; } lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ - //Internal loop filter set... if (!state->config->io.pll_int_loop_filt) { if (state->identity.in_soc) lo6 = 0xff98; @@ -2242,40 +2212,30 @@ static int dib0090_tune(struct dvb_frontend *fe) else lo6 = 0xff28; } else - lo6 = (state->config->io.pll_int_loop_filt << 3); // take the loop filter value given by the layout - //dprintk("lo6 = 0x%04x", (u32)lo6); + lo6 = (state->config->io.pll_int_loop_filt << 3); Den = 1; if (Rest > 0) { if (state->config->analog_output) - lo6 |= (1 << 2) | 2; //SigmaDelta and Dither + lo6 |= (1 << 2) | 2; else { if (state->identity.in_soc) - lo6 |= (1 << 2) | 2; //SigmaDelta and Dither + lo6 |= (1 << 2) | 2; else - lo6 |= (1 << 2) | 2; //SigmaDelta and Dither + lo6 |= (1 << 2) | 2; } Den = 255; } - // Now we have to define the Num and Denum - // LO1 gets the FBdiv dib0090_write_reg(state, 0x15, (u16) FBDiv); - // LO2 gets the REFDiv if (state->config->fref_clock_ratio != 0) dib0090_write_reg(state, 0x16, (Den << 8) | state->config->fref_clock_ratio); else dib0090_write_reg(state, 0x16, (Den << 8) | 1); - // LO3 for the Numerator dib0090_write_reg(state, 0x17, (u16) Rest); - // VCO and HF DIV dib0090_write_reg(state, 0x19, lo5); - // SIGMA Delta dib0090_write_reg(state, 0x1c, lo6); - // Check if the 0090 is analogged configured - //Disable ADC and DigPLL =0xFF9F, 0xffbf for test purposes. - //Enable The Outputs of the BB on DATA_Tx lo6 = tune->tuner_enable; if (state->config->analog_output) lo6 = (lo6 & 0xff9f) | 0x2; @@ -2294,10 +2254,8 @@ static int dib0090_tune(struct dvb_frontend *fe) else if (*tune_state == CT_TUNER_STEP_0) { /* Warning : because of captrim cal, if you change this step, change it also in _cal.c file because it is the step following captrim cal state machine */ const struct dib0090_wbd_slope *wbd = state->current_wbd_table; -// if(!state->identity.p1g) { while (state->current_rf / 1000 > wbd->max_freq) wbd++; -// } dib0090_write_reg(state, 0x1e, 0x07ff); dprintk("Final Captrim: %d", (u32) state->fcaptrim); @@ -2311,12 +2269,11 @@ static int dib0090_tune(struct dvb_frontend *fe) #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ c = 4; - i = 3; //wbdmux_bias + i = 3; - if (wbd->wbd_gain != 0) //&& !state->identity.p1g) + if (wbd->wbd_gain != 0) c = wbd->wbd_gain; - //Store wideband mux register. state->wbdmux = (c << 13) | (i << 11) | (WBD | (state->config->use_pwm_agc << 1)); dib0090_write_reg(state, 0x10, state->wbdmux); @@ -2335,15 +2292,12 @@ static int dib0090_tune(struct dvb_frontend *fe) } else if (*tune_state == CT_TUNER_STEP_1) { /* initialize the lt gain register */ state->rf_lt_def = 0x7c00; - // dib0090_write_reg(state, 0x0f, state->rf_lt_def); dib0090_set_bandwidth(state); state->tuner_is_tuned = 1; -// if(!state->identity.p1g) - state->calibrate |= WBD_CAL; // TODO: only do the WBD calibration for new tune -// - state->calibrate |= TEMP_CAL; // Force the Temperature to be remesured at next TUNE. + state->calibrate |= WBD_CAL; + state->calibrate |= TEMP_CAL; *tune_state = CT_TUNER_STOP; } else ret = FE_CALLBACK_TIME_NEVER; @@ -2435,8 +2389,8 @@ static const struct dvb_tuner_ops dib0090_fw_ops = { static const struct dib0090_wbd_slope dib0090_wbd_table_default[] = { {470, 0, 250, 0, 100, 4}, {860, 51, 866, 21, 375, 4}, - {1700, 0, 800, 0, 850, 4}, //LBAND Predefinition , to calibrate - {2900, 0, 250, 0, 100, 6}, //SBAND Predefinition , NOT tested Yet + {1700, 0, 800, 0, 850, 4}, + {2900, 0, 250, 0, 100, 6}, {0xFFFF, 0, 0, 0, 0, 0}, }; @@ -2489,12 +2443,11 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops)); return fe; - free_mem: +free_mem: kfree(st); fe->tuner_priv = NULL; return NULL; } - EXPORT_SYMBOL(dib0090_fw_register); MODULE_AUTHOR("Patrick Boettcher "); diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 18495bd166e6..b3ca3e2f8d53 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -79,8 +79,8 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) u8 wb[2] = { reg >> 8, reg & 0xff }; u8 rb[2]; struct i2c_msg msg[2] = { - {.addr = state->i2c_addr >> 1,.flags = 0,.buf = wb,.len = 2}, - {.addr = state->i2c_addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2}, + {.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, + {.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2}, }; if (i2c_transfer(state->i2c_adap, msg, 2) != 2) @@ -96,7 +96,7 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) (val >> 8) & 0xff, val & 0xff, }; struct i2c_msg msg = { - .addr = state->i2c_addr >> 1,.flags = 0,.buf = b,.len = 4 + .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 }; return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; } @@ -129,13 +129,13 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) dprintk("setting output mode for demod %p to %d", &state->demod, mode); switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock + case OUTMODE_MPEG2_PAR_GATED_CLK: outreg = (1 << 10); /* 0x0400 */ break; - case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock + case OUTMODE_MPEG2_PAR_CONT_CLK: outreg = (1 << 10) | (1 << 6); /* 0x0440 */ break; - case OUTMODE_MPEG2_SERIAL: // STBs with serial input + case OUTMODE_MPEG2_SERIAL: outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0480 */ break; case OUTMODE_DIVERSITY: @@ -144,7 +144,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) else outreg = (1 << 11); break; - case OUTMODE_MPEG2_FIFO: // e.g. USB feeding + case OUTMODE_MPEG2_FIFO: smo_mode |= (3 << 1); fifo_threshold = 512; outreg = (1 << 10) | (5 << 6); @@ -152,7 +152,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) case OUTMODE_ANALOG_ADC: outreg = (1 << 10) | (3 << 6); break; - case OUTMODE_HIGH_Z: // disable + case OUTMODE_HIGH_Z: outreg = 0; break; default: @@ -284,7 +284,7 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad reg_909 &= 0x0003; break; - case DIBX000_ADC_OFF: // leave the VBG voltage on + case DIBX000_ADC_OFF: reg_908 |= (1 << 14) | (1 << 13) | (1 << 12); reg_909 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2); break; @@ -336,13 +336,12 @@ static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) static int dib7000p_sad_calib(struct dib7000p_state *state) { /* internal */ -// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth dib7000p_write_word(state, 73, (0 << 1) | (0 << 0)); if (state->version == SOC7090) - dib7000p_write_word(state, 74, 2048); // P_sad_calib_value = (0.9/1.8)*4096 + dib7000p_write_word(state, 74, 2048); else - dib7000p_write_word(state, 74, 776); // P_sad_calib_value = 0.625*3.3 / 4096 + dib7000p_write_word(state, 74, 776); /* do the calibration */ dib7000p_write_word(state, 73, (1 << 0)); @@ -371,8 +370,8 @@ static void dib7000p_reset_pll(struct dib7000p_state *state) if (state->version == SOC7090) { dib7000p_write_word(state, 1856, (!bw->pll_reset << 13) | (bw->pll_range << 12) | (bw->pll_ratio << 6) | (bw->pll_prediv)); - while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) { - } + while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) + ; dib7000p_write_word(state, 1857, dib7000p_read_word(state, 1857) | (!bw->pll_bypass << 15)); } else { @@ -420,7 +419,7 @@ int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); reg_1856 &= 0xf000; reg_1857 = dib7000p_read_word(state, 1857); - dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); // desable pll + dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); dib7000p_write_word(state, 1856, reg_1856 | ((bw->pll_ratio & 0x3f) << 6) | (bw->pll_prediv & 0x3f)); @@ -431,11 +430,10 @@ int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config dib7000p_write_word(state, 18, (u16) ((internal >> 16) & 0xffff)); dib7000p_write_word(state, 19, (u16) (internal & 0xffff)); - dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); // enable pll + dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); - while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) { + while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) dprintk("Waiting for PLL to lock"); - } return 0; } @@ -503,7 +501,7 @@ static u16 dib7000p_defaults[] = { 0xd4c0, 1, 26, - 0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26 + 0x6680, /* set ADC level to -16 */ 11, 79, @@ -520,7 +518,7 @@ static u16 dib7000p_defaults[] = { (1 << 13) - 501 - 117, 1, 142, - 0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16 + 0x0410, /* disable power smoothing */ 8, 145, @@ -534,42 +532,39 @@ static u16 dib7000p_defaults[] = { 0, 1, 154, - 1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0 + 1 << 13, 1, 168, - 0x0ccd, // P_pha3_thres, default 0x3000 - -// 1, 169, -// 0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010 + 0x0ccd, 1, 183, - 0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005 + 0x200f, 1, 212, - 0x169, // P_vit_ksi_dwn = 5 P_vit_ksi_up = 5 0x1e1, // P_vit_ksi_dwn = 4 P_vit_ksi_up = 7 + 0x169, 5, 187, - 0x023d, // P_adp_regul_cnt=573, default: 410 - 0x00a4, // P_adp_noise_cnt= - 0x00a4, // P_adp_regul_ext - 0x7ff0, // P_adp_noise_ext - 0x3ccc, // P_adp_fil + 0x023d, + 0x00a4, + 0x00a4, + 0x7ff0, + 0x3ccc, 1, 198, - 0x800, // P_equal_thres_wgn + 0x800, 1, 222, - 0x0010, // P_fec_ber_rs_len=2 + 0x0010, 1, 235, - 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + 0x0062, 2, 901, - 0x0006, // P_clk_cfg1 - (3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1 + 0x0006, + (3 << 10) | (1 << 6), 1, 905, - 0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive + 0x2c8e, 0, }; @@ -609,8 +604,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_write_word(state, 42, (1<<5) | 3); /* P_iqc_thsat_ipc = 1 ; P_iqc_win2 = 3 */ dib7000p_write_word(state, 43, 0x2d4); /*-300 fag P_iqc_dect_min = -280 */ dib7000p_write_word(state, 44, 300); /* 300 fag P_iqc_dect_min = +280 */ - //dib7000p_write_word(state, 273, (1<<6) | 10); /* P_vit_inoise_sel = 1, P_vit_inoise_gain = 10*/ - dib7000p_write_word(state, 273, (1<<6) | 30); //26/* P_vit_inoise_sel = 1, P_vit_inoise_gain = 26*/// FAG + dib7000p_write_word(state, 273, (1<<6) | 30); } if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) dprintk("OUTPUT_MODE could not be reset."); @@ -624,9 +618,9 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_set_bandwidth(state, 8000); - if(state->version == SOC7090) { + if (state->version == SOC7090) { dib7000p_write_word(state, 36, 0x5755);/* P_iqc_impnc_on =1 & P_iqc_corr_inh = 1 for impulsive noise */ - } else { // P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ... + } else { if (state->cfg.tuner_is_baseband) dib7000p_write_word(state, 36, 0x0755); else @@ -644,9 +638,9 @@ static void dib7000p_pll_clk_cfg(struct dib7000p_state *state) { u16 tmp = 0; tmp = dib7000p_read_word(state, 903); - dib7000p_write_word(state, 903, (tmp | 0x1)); //pwr-up pll + dib7000p_write_word(state, 903, (tmp | 0x1)); tmp = dib7000p_read_word(state, 900); - dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); //use High freq clock + dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6)); } static void dib7000p_restart_agc(struct dib7000p_state *state) @@ -660,11 +654,9 @@ static int dib7000p_update_lna(struct dib7000p_state *state) { u16 dyn_gain; - // when there is no LNA to program return immediatly if (state->cfg.update_lna) { - // read dyn_gain here (because it is demod-dependent and not fe) dyn_gain = dib7000p_read_word(state, 394); - if (state->cfg.update_lna(&state->demod, dyn_gain)) { // LNA has changed + if (state->cfg.update_lna(&state->demod, dyn_gain)) { dib7000p_restart_agc(state); return 1; } @@ -763,12 +755,11 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ switch (state->agc_state) { case 0: - // set power-up level: interf+analog+AGC dib7000p_set_power_mode(state, DIB7000P_POWER_ALL); if (state->version == SOC7090) { reg = dib7000p_read_word(state, 0x79b) & 0xff00; dib7000p_write_word(state, 0x79a, upd_demod_gain_period & 0xFFFF); /* lsb */ - dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF)); // bit 14 = enDemodGain + dib7000p_write_word(state, 0x79b, reg | (1 << 14) | ((upd_demod_gain_period >> 16) & 0xFF)); /* enable adc i & q */ reg = dib7000p_read_word(state, 0x780); @@ -787,7 +778,6 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 1: - // AGC initialization if (state->cfg.agc_control) state->cfg.agc_control(&state->demod, 1); @@ -831,13 +821,11 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_ break; case 4: /* LNA startup */ - // wait AGC accurate lock time ret = 7; if (dib7000p_update_lna(state)) - // wait only AGC rough lock time ret = 5; - else // nothing was done, go to the next state + else (*agc_state)++; break; @@ -971,10 +959,10 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte dib7000p_write_word(state, 208, value); /* offset loop parameters */ - dib7000p_write_word(state, 26, 0x6680); // timf(6xxx) - dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3) - dib7000p_write_word(state, 29, 0x1273); // isi - dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5) + dib7000p_write_word(state, 26, 0x6680); + dib7000p_write_word(state, 32, 0x0003); + dib7000p_write_word(state, 29, 0x1273); + dib7000p_write_word(state, 33, 0x0005); /* P_dvsy_sync_wait */ switch (ch->u.ofdm.transmission_mode) { @@ -1005,9 +993,9 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte break; } if (state->cfg.diversity_delay == 0) - state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo + state->div_sync_wait = (value * 3) / 2 + 48; else - state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo + state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; /* deactive the possibility of diversity reception if extended interleaver */ state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K; @@ -1061,16 +1049,15 @@ static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_fron else factor = 6; - // always use the setting for 8MHz here lock_time for 7,6 MHz are longer value = 30 * internal * factor; - dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); // lock0 wait time - dib7000p_write_word(state, 7, (u16) (value & 0xffff)); // lock0 wait time + dib7000p_write_word(state, 6, (u16) ((value >> 16) & 0xffff)); + dib7000p_write_word(state, 7, (u16) (value & 0xffff)); value = 100 * internal * factor; - dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); // lock1 wait time - dib7000p_write_word(state, 9, (u16) (value & 0xffff)); // lock1 wait time + dib7000p_write_word(state, 8, (u16) ((value >> 16) & 0xffff)); + dib7000p_write_word(state, 9, (u16) (value & 0xffff)); value = 500 * internal * factor; - dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time - dib7000p_write_word(state, 11, (u16) (value & 0xffff)); // lock2 wait time + dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); + dib7000p_write_word(state, 11, (u16) (value & 0xffff)); value = dib7000p_read_word(state, 0); dib7000p_write_word(state, 0, (u16) ((1 << 9) | value)); @@ -1085,13 +1072,13 @@ static int dib7000p_autosearch_is_irq(struct dvb_frontend *demod) struct dib7000p_state *state = demod->demodulator_priv; u16 irq_pending = dib7000p_read_word(state, 1284); - if (irq_pending & 0x1) // failed + if (irq_pending & 0x1) return 1; - if (irq_pending & 0x2) // succeeded + if (irq_pending & 0x2) return 2; - return 0; // still pending + return 0; } static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw) @@ -1202,9 +1189,9 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet if (state->sfn_workaround_active) { dprintk("SFN workaround is active"); tmp |= (1 << 9); - dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift + dib7000p_write_word(state, 166, 0x4000); } else { - dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift + dib7000p_write_word(state, 166, 0x0000); } dib7000p_write_word(state, 29, tmp); @@ -1425,8 +1412,7 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa if (state->version == SOC7090) { dib7090_set_diversity_in(fe, 0); dib7090_set_output_mode(fe, OUTMODE_HIGH_Z); - } - else + } else dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); /* maybe the parameter has been changed */ @@ -1455,7 +1441,7 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa dprintk("autosearch returns: %d", found); if (found == 0 || found == 1) - return 0; // no channel found + return 0; dib7000p_get_frontend(fe, fep); } @@ -1566,8 +1552,8 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap) { u8 tx[2], rx[2]; struct i2c_msg msg[2] = { - {.addr = 18 >> 1,.flags = 0,.buf = tx,.len = 2}, - {.addr = 18 >> 1,.flags = I2C_M_RD,.buf = rx,.len = 2}, + {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2}, + {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2}, }; tx[0] = 0x03; @@ -1725,9 +1711,8 @@ static int map_addr_to_serpar_number(struct i2c_msg *msg) msg->buf[0] -= 3; else if (msg->buf[0] == 28) msg->buf[0] = 23; - else { + else return -EINVAL; - } return 0; } @@ -1909,7 +1894,7 @@ static int dib7090_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] if (num == 1) { /* write */ word = (u16) ((msg[0].buf[1] << 8) | msg[0].buf[2]); word &= 0x3; - word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12); //Mask bit 12,13 + word = (dib7000p_read_word(state, 72) & ~(3 << 12)) | (word << 12); dib7000p_write_word(state, 72, word); /* Set the proper input */ return num; } @@ -1996,7 +1981,7 @@ static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout u16 rx_copy_buf[22]; dprintk("Configure DibStream Tx"); - for (index_buf = 0; index_buf<22; index_buf++) + for (index_buf = 0; index_buf < 22; index_buf++) rx_copy_buf[index_buf] = dib7000p_read_word(state, 1536+index_buf); dib7000p_write_word(state, 1615, 1); @@ -2009,7 +1994,7 @@ static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout dib7000p_write_word(state, 1612, syncSize); dib7000p_write_word(state, 1615, 0); - for (index_buf = 0; index_buf<22; index_buf++) + for (index_buf = 0; index_buf < 22; index_buf++) dib7000p_write_word(state, 1536+index_buf, rx_copy_buf[index_buf]); return 0; @@ -2021,8 +2006,7 @@ static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout u32 syncFreq; dprintk("Configure DibStream Rx"); - if ((P_Kin != 0) && (P_Kout != 0)) - { + if ((P_Kin != 0) && (P_Kout != 0)) { syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize); dib7000p_write_word(state, 1542, syncFreq); } @@ -2044,7 +2028,7 @@ static int dib7090_enDivOnHostBus(struct dib7000p_state *state) u16 reg; dprintk("Enable Diversity on host bus"); - reg = (1 << 8) | (1 << 5); // P_enDivOutOnDibTx = 1 ; P_enDibTxOnHostBus = 1 + reg = (1 << 8) | (1 << 5); dib7000p_write_word(state, 1288, reg); return dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); @@ -2055,7 +2039,7 @@ static int dib7090_enAdcOnHostBus(struct dib7000p_state *state) u16 reg; dprintk("Enable ADC on host bus"); - reg = (1 << 7) | (1 << 5); //P_enAdcOnDibTx = 1 ; P_enDibTxOnHostBus = 1 + reg = (1 << 7) | (1 << 5); dib7000p_write_word(state, 1288, reg); return dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); @@ -2066,7 +2050,7 @@ static int dib7090_enMpegOnHostBus(struct dib7000p_state *state) u16 reg; dprintk("Enable Mpeg on host bus"); - reg = (1 << 9) | (1 << 5); //P_enMpegOnDibTx = 1 ; P_enDibTxOnHostBus = 1 + reg = (1 << 9) | (1 << 5); dib7000p_write_word(state, 1288, reg); return dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); @@ -2085,10 +2069,10 @@ static int dib7090_enMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 e dprintk("Enable Mpeg mux"); dib7000p_write_word(state, 1287, reg); - reg &= ~(1 << 7); // P_restart_mpegMux = 0 + reg &= ~(1 << 7); dib7000p_write_word(state, 1287, reg); - reg = (1 << 4); //P_enMpegMuxOnHostBus = 1 + reg = (1 << 4); dib7000p_write_word(state, 1288, reg); return 0; @@ -2099,10 +2083,10 @@ static int dib7090_disableMpegMux(struct dib7000p_state *state) u16 reg; dprintk("Disable Mpeg mux"); - dib7000p_write_word(state, 1288, 0); //P_enMpegMuxOnHostBus = 0 + dib7000p_write_word(state, 1288, 0); reg = dib7000p_read_word(state, 1287); - reg &= ~(1 << 7); // P_restart_mpegMux = 0 + reg &= ~(1 << 7); dib7000p_write_word(state, 1287, reg); return 0; @@ -2112,19 +2096,19 @@ static int dib7090_set_input_mode(struct dvb_frontend *fe, int mode) { struct dib7000p_state *state = fe->demodulator_priv; - switch(mode) { - case INPUT_MODE_DIVERSITY: + switch (mode) { + case INPUT_MODE_DIVERSITY: dprintk("Enable diversity INPUT"); - dib7090_cfg_DibRx(state, 5,5,0,0,0,0,0); + dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); break; - case INPUT_MODE_MPEG: + case INPUT_MODE_MPEG: dprintk("Enable Mpeg INPUT"); - dib7090_cfg_DibRx(state, 8,5,0,0,0,8,0); /*outputRate = 8 */ + dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /*outputRate = 8 */ break; - case INPUT_MODE_OFF: - default: + case INPUT_MODE_OFF: + default: dprintk("Disable INPUT"); - dib7090_cfg_DibRx(state, 0,0,0,0,0,0,0); + dib7090_cfg_DibRx(state, 0, 0, 0, 0, 0, 0, 0); break; } return 0; @@ -2175,7 +2159,7 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) } else { /* Use Smooth block */ dprintk("Sip 7090P setting output mode TS_SERIAL using Smooth bloc"); dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + dib7000p_write_word(state, 1288, (1 << 6)); outreg |= (2 << 6) | (0 << 1); } break; @@ -2190,7 +2174,7 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) } else { /* Use Smooth block */ dprintk("Sip 7090P setting output mode TS_PARALLEL_GATED using Smooth block"); dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + dib7000p_write_word(state, 1288, (1 << 6)); outreg |= (0 << 6); } break; @@ -2198,14 +2182,14 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ dprintk("Sip 7090P setting output mode TS_PARALLEL_CONT using Smooth block"); dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + dib7000p_write_word(state, 1288, (1 << 6)); outreg |= (1 << 6); break; case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ dprintk("Sip 7090P setting output mode TS_FIFO using Smooth block"); dib7090_disableMpegMux(state); - dib7000p_write_word(state, 1288, (1 << 6)); //P_enDemOutInterfOnHostBus = 1 + dib7000p_write_word(state, 1288, (1 << 6)); outreg |= (5 << 6); smo_mode |= (3 << 1); fifo_threshold = 512; @@ -2242,12 +2226,11 @@ int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) en_cur_state = dib7000p_read_word(state, 1922); - if (en_cur_state > 0xff) { //LNAs and MIX are ON and therefore it is a valid configuration + if (en_cur_state > 0xff) state->tuner_enable = en_cur_state; - } if (onoff) - en_cur_state &= 0x00ff; //Mask to be applied + en_cur_state &= 0x00ff; else { if (state->tuner_enable != 0) en_cur_state = state->tuner_enable; @@ -2275,13 +2258,13 @@ EXPORT_SYMBOL(dib7090_get_adc_power); int dib7090_slave_reset(struct dvb_frontend *fe) { struct dib7000p_state *state = fe->demodulator_priv; - u16 reg; + u16 reg; - reg = dib7000p_read_word(state, 1794); - dib7000p_write_word(state, 1794, reg | (4 << 12)); + reg = dib7000p_read_word(state, 1794); + dib7000p_write_word(state, 1794, reg | (4 << 12)); - dib7000p_write_word(state, 1032, 0xffff); - return 0; + dib7000p_write_word(state, 1032, 0xffff); + return 0; } EXPORT_SYMBOL(dib7090_slave_reset); @@ -2340,7 +2323,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, return demod; - error: +error: kfree(st); return NULL; } diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h index 4e3ffc888341..0179f9474bac 100644 --- a/drivers/media/dvb/frontends/dib7000p.h +++ b/drivers/media/dvb/frontends/dib7000p.h @@ -39,7 +39,7 @@ struct dib7000p_config { u16 diversity_delay; u8 default_i2c_addr; - u8 enMpegOutput : 1; + u8 enMpegOutput:1; }; #define DEFAULT_DIB7000P_I2C_ADDRESS 18 diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 625e4210d2dd..3961fed9da6e 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -261,7 +261,8 @@ static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) fifo_threshold = 1792; smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d", &state->fe[0], mode); + dprintk("-I- Setting output mode for demod %p to %d", + &state->fe[0], mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -295,7 +296,8 @@ static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) break; default: - dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]); + dprintk("Unhandled output_mode passed to be set for demod %p", + &state->fe[0]); return -EINVAL; } @@ -345,7 +347,8 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow { /* by default everything is going to be powered off */ u16 reg_774 = 0x3fff, reg_775 = 0xffff, reg_776 = 0xffff, - reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; + reg_900 = (dib8000_read_word(state, 900) & 0xfffc) | 0x3, + reg_1280 = (dib8000_read_word(state, 1280) & 0x00ff) | 0xff00; /* now, depending on the requested mode, we power on */ switch (mode) { @@ -482,7 +485,8 @@ static void dib8000_reset_pll(struct dib8000_state *state) // clk_cfg1 clk_cfg1 = (1 << 10) | (0 << 9) | (pll->IO_CLK_en_core << 8) | - (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | (pll->pll_range << 1) | (pll->pll_reset << 0); + (pll->bypclk_div << 5) | (pll->enable_refdiv << 4) | (1 << 3) | + (pll->pll_range << 1) | (pll->pll_reset << 0); dib8000_write_word(state, 902, clk_cfg1); clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); @@ -492,11 +496,12 @@ static void dib8000_reset_pll(struct dib8000_state *state) /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ if (state->cfg.pll->ADClkSrc == 0) - dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); + dib8000_write_word(state, 904, (0 << 15) | (0 << 12) | (0 << 10) | + (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); else if (state->cfg.refclksel != 0) - dib8000_write_word(state, 904, - (0 << 15) | (1 << 12) | ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | (pll-> - ADClkSrc << 7) | (0 << 1)); + dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | + ((state->cfg.refclksel & 0x3) << 10) | (pll->modulo << 8) | + (pll->ADClkSrc << 7) | (0 << 1)); else dib8000_write_word(state, 904, (0 << 15) | (1 << 12) | (3 << 10) | (pll->modulo << 8) | (pll->ADClkSrc << 7) | (0 << 1)); @@ -627,14 +632,14 @@ static const u16 dib8000_defaults[] = { 1, 285, 0x0020, //p_fec_ 1, 299, - 0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard + 0x0062, /* P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard */ 1, 338, (1 << 12) | // P_ctrl_corm_thres4pre_freq_inh=1 - (1 << 10) | // P_ctrl_pre_freq_mode_sat=1 - (0 << 9) | // P_ctrl_pre_freq_inh=0 - (3 << 5) | // P_ctrl_pre_freq_step=3 - (1 << 0), // P_pre_freq_win_len=1 + (1 << 10) | + (0 << 9) | /* P_ctrl_pre_freq_inh=0 */ + (3 << 5) | /* P_ctrl_pre_freq_step=3 */ + (1 << 0), /* P_pre_freq_win_len=1 */ 1, 903, (0 << 4) | 2, // P_divclksel=0 P_divbitsel=2 (was clk=3,bit=1 for MPW) @@ -782,7 +787,7 @@ static int dib8000_update_lna(struct dib8000_state *state) // read dyn_gain here (because it is demod-dependent and not tuner) dyn_gain = dib8000_read_word(state, 390); - if (state->cfg.update_lna(state->fe[0], dyn_gain)) { // LNA has changed + if (state->cfg.update_lna(state->fe[0], dyn_gain)) { dib8000_restart_agc(state); return 1; } @@ -869,7 +874,8 @@ static int dib8000_agc_soft_split(struct dib8000_state *state) split_offset = state->current_agc->split.max; else split_offset = state->current_agc->split.max * - (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); + (agc - state->current_agc->split.min_thres) / + (state->current_agc->split.max_thres - state->current_agc->split.min_thres); dprintk("AGC split_offset: %d", split_offset); @@ -952,14 +958,13 @@ s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) s32 val; val = dib8000_read32(state, 384); - /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */ if (mode) { tmp_val = val; while (tmp_val >>= 1) exp++; mant = (val * 1000 / (1<fe[0]->dtv_property_cache.inversion ^ i); + dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i); if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { //compute new dds_freq for the seg and adjust prbs int seg_offset = - state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) - + state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx - + (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2); int clk = state->cfg.pll->internal; u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26) int dds_offset = seg_offset * segtodds; int new_dds, sub_channel; - if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) // if even + if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) dds_offset -= (int)(segtodds / 2); if (state->cfg.pll->ifreq == 0) { @@ -1031,7 +1037,8 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // - the segment of center frequency with an odd total number of segments // - the segment to the left of center frequency with an even total number of segments // - the segment to the right of center frequency with an even total number of segments - if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT) && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) + if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT) + && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) @@ -1051,9 +1058,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear } dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff)); dib8000_write_word(state, 28, (u16) (new_dds & 0xffff)); - if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) // if odd + if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3; - else // if even + else sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3; sub_channel -= 6; @@ -1212,7 +1219,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear } break; } - } else { // if not state->fe[0]->dtv_property_cache.isdbt_sb_mode + } else { dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff)); dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff)); dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003)); @@ -1332,8 +1339,8 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear state->differential_constellation = (seg_diff_mask != 0); dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) // 3-segments + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) seg_mask13 = 0x00E0; else // 1-segment seg_mask13 = 0x0040; @@ -1355,25 +1362,24 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 353, seg_mask13); // ADDR 353 /* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */ - // dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5 ); // ---- SMALL ---- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) ncoeff = coeff_2k_sb_1seg_dqpsk; else // QPSK or QAM ncoeff = coeff_2k_sb_1seg; } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; else // QPSK or QAM on external segments ncoeff = coeff_2k_sb_3seg_0dqpsk; } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) ncoeff = coeff_2k_sb_3seg_1dqpsk; else // QPSK or QAM on external segments ncoeff = coeff_2k_sb_3seg; @@ -1382,20 +1388,20 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear break; case TRANSMISSION_MODE_4K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) ncoeff = coeff_4k_sb_1seg_dqpsk; else // QPSK or QAM ncoeff = coeff_4k_sb_1seg; } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; } else { // QPSK or QAM on external segments ncoeff = coeff_4k_sb_3seg_0dqpsk; } } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { ncoeff = coeff_4k_sb_3seg_1dqpsk; } else // QPSK or QAM on external segments ncoeff = coeff_4k_sb_3seg; @@ -1406,20 +1412,20 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear case TRANSMISSION_MODE_AUTO: case TRANSMISSION_MODE_8K: default: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // 1-seg - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) // DQPSK + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) ncoeff = coeff_8k_sb_1seg_dqpsk; else // QPSK or QAM ncoeff = coeff_8k_sb_1seg; } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { // DQPSK on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; } else { // QPSK or QAM on external segments ncoeff = coeff_8k_sb_3seg_0dqpsk; } } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { // DQPSK on external segments + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { ncoeff = coeff_8k_sb_3seg_1dqpsk; } else // QPSK or QAM on external segments ncoeff = coeff_8k_sb_3seg; @@ -1437,7 +1443,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // ---- COFF ---- // Carloff, the most robust - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // Sound Broadcasting mode - use both TMCC and AC pilots + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64 // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 @@ -1448,7 +1454,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear /* // P_small_coef_ext_enable = 1 */ /* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */ - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1) if (mode == 3) @@ -1512,7 +1518,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); } // ---- FFT ---- - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // 1-seg + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) dib8000_write_word(state, 178, 64); // P_fft_powrange=64 else dib8000_write_word(state, 178, 32); // P_fft_powrange=32 @@ -1542,7 +1548,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear /* offset loop parameters */ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40); @@ -1555,7 +1561,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80); if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */ dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode)); @@ -1628,7 +1634,7 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // ---- ANA_FE ---- if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) // 3-segments + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) ana_fe = ana_fe_coeff_3seg; else // 1-segment ana_fe = ana_fe_coeff_1seg; @@ -1651,10 +1657,10 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear // "P_cspu_left_edge" not used => do not care // "P_cspu_right_edge" not used => do not care - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { // ISDB-Tsb + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1 dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0 - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 // 1-segment + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) { //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0 dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15 @@ -1803,7 +1809,7 @@ static int dib8000_tune(struct dvb_frontend *fe) // never achieved a lock before - wait for timfreq to update if (state->timf == 0) { if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) msleep(300); else // Sound Broadcasting mode 3 seg msleep(500); @@ -1811,7 +1817,7 @@ static int dib8000_tune(struct dvb_frontend *fe) msleep(200); } if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { // Sound Broadcasting mode 1 seg + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */ dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40); @@ -1864,9 +1870,9 @@ static int dib8000_wakeup(struct dvb_frontend *fe) if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) dprintk("could not start Slow ADC"); - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.init(state->fe[index_frontend]); - if (ret<0) + if (ret < 0) return ret; } @@ -1879,7 +1885,7 @@ static int dib8000_sleep(struct dvb_frontend *fe) u8 index_frontend; int ret; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); if (ret < 0) return ret; @@ -1914,13 +1920,13 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par fe->dtv_property_cache.bandwidth_hz = 6000000; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); if (stat&FE_HAS_SYNC) { dprintk("TMCC lock on the slave%i", index_frontend); /* synchronize the cache with the other frontends */ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); - for (sub_index_frontend=0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { + for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { if (sub_index_frontend != index_frontend) { state->fe[sub_index_frontend]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; @@ -2032,7 +2038,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } /* synchronize the cache with the other frontends */ - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode = fe->dtv_property_cache.isdbt_sb_mode; state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; @@ -2066,7 +2072,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000; } - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { /* synchronization of the cache */ state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); @@ -2081,7 +2087,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* start up the AGC */ do { time = dib8000_agc_startup(state->fe[0]); - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { time_slave = dib8000_agc_startup(state->fe[index_frontend]); if (time == FE_CALLBACK_TIME_NEVER) time = time_slave; @@ -2093,7 +2099,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par else break; exit_condition = 1; - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) { exit_condition = 0; break; @@ -2101,7 +2107,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } } while (exit_condition == 0); - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || @@ -2132,31 +2138,30 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par u8 found = 0; u8 tune_failed = 0; - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); dib8000_autosearch_start(state->fe[index_frontend]); } do { - msleep(10); + msleep(20); nbr_pending = 0; exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { if (((tune_failed >> index_frontend) & 0x1) == 0) { found = dib8000_autosearch_irq(state->fe[index_frontend]); switch (found) { - case 0: /* tune pending */ + case 0: /* tune pending */ nbr_pending++; break; - case 2: + case 2: dprintk("autosearch succeed on the frontend%i", index_frontend); exit_condition = 2; index_frontend_success = index_frontend; break; - default: + default: dprintk("unhandled autosearch result"); - case 1: - tune_failed |= (1 << index_frontend); + case 1: dprintk("autosearch failed for the frontend%i", index_frontend); break; } @@ -2178,13 +2183,12 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dib8000_get_frontend(fe, fep); } - for (index_frontend=0, ret=0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) ret = dib8000_tune(state->fe[index_frontend]); - } /* set output mode and diversity input */ dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { dib8000_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); dib8000_set_diversity_in(state->fe[index_frontend-1], 1); } @@ -2195,7 +2199,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par return ret; } -static u16 dib8000_read_lock(struct dvb_frontend *fe) { +static u16 dib8000_read_lock(struct dvb_frontend *fe) +{ struct dib8000_state *state = fe->demodulator_priv; return dib8000_read_word(state, 568); @@ -2207,7 +2212,7 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) u16 lock_slave = 0, lock = dib8000_read_word(state, 568); u8 index_frontend; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib8000_read_lock(state->fe[index_frontend]); *stat = 0; @@ -2262,7 +2267,7 @@ static int dib8000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) u16 val; *strength = 0; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); if (val > 65535 - *strength) *strength = 65535; @@ -2312,7 +2317,7 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr) u32 snr_master; snr_master = dib8000_get_snr(fe); - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) snr_master += dib8000_get_snr(state->fe[index_frontend]); if (snr_master != 0) { @@ -2361,7 +2366,7 @@ int dib8000_remove_slave_frontend(struct dvb_frontend *fe) } EXPORT_SYMBOL(dib8000_remove_slave_frontend); -struct dvb_frontend * dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { struct dib8000_state *state = fe->demodulator_priv; @@ -2432,7 +2437,7 @@ static void dib8000_release(struct dvb_frontend *fe) struct dib8000_state *st = fe->demodulator_priv; u8 index_frontend; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) dvb_frontend_detach(st->fe[index_frontend]); dibx000_exit_i2c_master(&st->i2c_master); diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index 558b7e83c722..617f9eba3a09 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h @@ -52,7 +52,7 @@ extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe); -extern struct dvb_frontend * dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); +extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); #else static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) { @@ -126,9 +126,10 @@ int dib8000_remove_slave_frontend(struct dvb_frontend *fe) return -ENODEV; } -static inline struct dvb_frontend * dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { +static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return NULL; + return NULL; } #endif diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index a41e02dc08ec..43fb6e45424a 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -31,7 +31,7 @@ struct i2c_device { /* lock */ #define DIB_LOCK struct mutex -#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock)<0) dprintk("could not get the lock"); } while (0) +#define DibAcquireLock(lock) do { if (mutex_lock_interruptible(lock) < 0) dprintk("could not get the lock"); } while (0) #define DibReleaseLock(lock) mutex_unlock(lock) #define DibInitLock(lock) mutex_init(lock) #define DibFreeLock(lock) @@ -187,8 +187,7 @@ enum dib9000_in_messages { #define FE_MM_W_COMPONENT_ACCESS 16 #define FE_MM_RW_COMPONENT_ACCESS_BUFFER 17 -static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, - u8 * b, u32 len); +static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len); static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 address, u16 attribute, const u8 * b, u32 len); static u16 to_fw_output_mode(u16 mode) @@ -220,8 +219,8 @@ static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32 int ret; u8 wb[2] = { reg >> 8, reg & 0xff }; struct i2c_msg msg[2] = { - {.addr = state->i2c.i2c_addr >> 1,.flags = 0,.buf = wb,.len = 2}, - {.addr = state->i2c.i2c_addr >> 1,.flags = I2C_M_RD,.buf = b,.len = len}, + {.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, + {.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len}, }; if (state->platform.risc.fw_is_running && (reg < 1024)) @@ -257,8 +256,8 @@ static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) u8 b[2]; u8 wb[2] = { reg >> 8, reg & 0xff }; struct i2c_msg msg[2] = { - {.addr = i2c->i2c_addr >> 1,.flags = 0,.buf = wb,.len = 2}, - {.addr = i2c->i2c_addr >> 1,.flags = I2C_M_RD,.buf = b,.len = 2}, + {.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2}, + {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2}, }; if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { @@ -295,12 +294,12 @@ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * int ret; struct i2c_msg msg = { - .addr = state->i2c.i2c_addr >> 1,.flags = 0,.buf = b,.len = len + 2 + .addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2 }; if (state->platform.risc.fw_is_running && (reg < 1024)) { if (dib9000_risc_apb_access_write - (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) + (state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0) return -EINVAL; return 0; } @@ -334,7 +333,7 @@ static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) { u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff }; struct i2c_msg msg = { - .addr = i2c->i2c_addr >> 1,.flags = 0,.buf = b,.len = 4 + .addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4 }; return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0; @@ -369,24 +368,24 @@ static void dib9000_risc_mem_setup_cmd(struct dib9000_state *state, u32 addr, u3 { u8 b[14] = { 0 }; -// dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); -// b[0] = 0 << 7; +/* dprintk("%d memcmd: %d %d %d\n", state->fe_id, addr, addr+len, len); */ +/* b[0] = 0 << 7; */ b[1] = 1; -// b[2] = 0; // 1057 -// b[3] = 0; - b[4] = (u8) (addr >> 8); // 1058 +/* b[2] = 0; */ +/* b[3] = 0; */ + b[4] = (u8) (addr >> 8); b[5] = (u8) (addr & 0xff); -// b[10] = 0; // 1061 -// b[11] = 0; - b[12] = (u8) (addr >> 8); // 1062 +/* b[10] = 0; */ +/* b[11] = 0; */ + b[12] = (u8) (addr >> 8); b[13] = (u8) (addr & 0xff); addr += len; -// b[6] = 0; // 1059 -// b[7] = 0; - b[8] = (u8) (addr >> 8); // 1060 +/* b[6] = 0; */ +/* b[7] = 0; */ + b[8] = (u8) (addr >> 8); b[9] = (u8) (addr & 0xff); dib9000_write(state, 1056, b, 14); @@ -400,7 +399,7 @@ static void dib9000_risc_mem_setup(struct dib9000_state *state, u8 cmd) struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[cmd & 0x7f]; /* decide whether we need to "refresh" the memory controller */ if (state->platform.risc.memcmd == cmd && /* same command */ - !(cmd & 0x80 && m->size < 67)) /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */ + !(cmd & 0x80 && m->size < 67)) /* and we do not want to read something with less than 67 bytes looping - working around a bug in the memory controller */ return; dib9000_risc_mem_setup_cmd(state, m->addr, m->size, cmd & 0x80); state->platform.risc.memcmd = cmd; @@ -506,7 +505,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, break; } while (1); - //dprintk( "MBX: size: %d", size); + /*dprintk( "MBX: size: %d", size); */ if (tmp == 0) { ret = -EINVAL; @@ -538,7 +537,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, /* update register nb_mes_in_RX */ ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr); - out: +out: DibReleaseLock(&state->platform.risc.mbx_if_lock); return ret; @@ -625,7 +624,7 @@ static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) if (*block == 0) { size = dib9000_mbx_read(state, block, 1, attr); -// dprintk( "MBX: fetched %04x message to cache", *block); +/* dprintk( "MBX: fetched %04x message to cache", *block); */ switch (*block >> 8) { case IN_MSG_DEBUG_BUF: @@ -671,8 +670,8 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) ret = dib9000_mbx_fetch_to_cache(state, attr); tmp = dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ -// if (tmp) -// dprintk( "cleared IRQ: %x", tmp); +/* if (tmp) */ +/* dprintk( "cleared IRQ: %x", tmp); */ DibReleaseLock(&state->platform.risc.mbx_lock); return ret; @@ -805,7 +804,8 @@ static u16 dib9000_identify(struct i2c_device *client) { u16 value; - if ((value = dib9000_i2c_read16(client, 896)) != 0x01b3) { + value = dib9000_i2c_read16(client, 896); + if (value != 0x01b3) { dprintk("wrong Vendor ID (0x%x)", value); return 0; } @@ -916,7 +916,7 @@ static int dib9000_fw_reset(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; - dib9000_write_word(state, 1817, 0x0003); // SRAM read lead in + P_host_rdy_cmos=1 + dib9000_write_word(state, 1817, 0x0003); dib9000_write_word(state, 1227, 1); dib9000_write_word(state, 1227, 0); @@ -961,8 +961,7 @@ static int dib9000_fw_reset(struct dvb_frontend *fe) return 0; } -static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, - u8 * b, u32 len) +static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address, u16 attribute, const u8 * tx, u32 txlen, u8 * b, u32 len) { u16 mb[10]; u8 i, s; @@ -970,14 +969,14 @@ static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address if (address >= 1024 || !state->platform.risc.fw_is_running) return -EINVAL; - //dprintk( "APB access thru rd fw %d %x", address, attribute); + /* dprintk( "APB access thru rd fw %d %x", address, attribute); */ mb[0] = (u16) address; mb[1] = len / 2; dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_R, mb, 2, attribute); switch (dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute)) { case 1: - s--; // address + s--; for (i = 0; i < s; i++) { b[i * 2] = (mb[i + 1] >> 8) & 0xff; b[i * 2 + 1] = (mb[i + 1]) & 0xff; @@ -997,10 +996,10 @@ static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 addres if (address >= 1024 || !state->platform.risc.fw_is_running) return -EINVAL; - //dprintk( "APB access thru wr fw %d %x", address, attribute); + /* dprintk( "APB access thru wr fw %d %x", address, attribute); */ mb[0] = (unsigned short)address; - for (i = 0; i < len && i < 20; i += 2) // 20 bytes max + for (i = 0; i < len && i < 20; i += 2) mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]); dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute); @@ -1031,7 +1030,6 @@ static int dib9000_fw_init(struct dib9000_state *state) u8 size; if (dib9000_fw_boot(state, NULL, 0, state->chip.d9.cfg.microcode_B_fe_buffer, state->chip.d9.cfg.microcode_B_fe_size) != 0) - //if (dib9000_fw_boot(state, microcode_A_buffer, microcode_A_size, microcode_B_buffer, microcode_B_size) != 0) return -EIO; /* initialize the firmware */ @@ -1062,7 +1060,6 @@ static int dib9000_fw_init(struct dib9000_state *state) b[2 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.mask; b[3 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.direction; b[4 + i * 4] = (u16) state->chip.d9.cfg.subband.subband[i].gpio.value; - //dprintk( "SBS: %d %d %x %x %x\n", i, b[1 + i*4], b[2 + i*4], b[3 + i*4], b[4 + i*4]); } b[1 + i * 4] = 0; /* fe_id */ if (dib9000_mbx_send(state, OUT_MSG_SUBBAND_SEL, b, 2 + 4 * i) != 0) @@ -1071,7 +1068,7 @@ static int dib9000_fw_init(struct dib9000_state *state) /* 0 - id, 1 - no_of_frontends */ b[0] = (0 << 8) | 1; /* 0 = i2c-address demod, 0 = tuner */ - b[1] = (0 << 8) | (0); //st->i2c_addr ) ); + b[1] = (0 << 8) | (0); b[2] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000) >> 16) & 0xffff); b[3] = (u16) (((state->chip.d9.cfg.xtal_clock_khz * 1000)) & 0xffff); b[4] = (u16) ((state->chip.d9.cfg.vcxo_timer >> 16) & 0xffff); @@ -1089,14 +1086,14 @@ static int dib9000_fw_init(struct dib9000_state *state) return -EIO; if (size > ARRAY_SIZE(b)) { - dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size, (int)ARRAY_SIZE(b)); + dprintk("error : firmware returned %dbytes needed but the used buffer has only %dbytes\n Firmware init ABORTED", size, + (int)ARRAY_SIZE(b)); return -EINVAL; } for (i = 0; i < size; i += 2) { state->platform.risc.fe_mm[i / 2].addr = b[i + 0]; state->platform.risc.fe_mm[i / 2].size = b[i + 1]; - //dprintk( "MM: %d %d %d", state->platform.risc.fe_mm[i/2].addr, state->platform.risc.fe_mm[i/2].size, ARRAY_SIZE(state->platform.risc.fe_mm)); } return 0; @@ -1150,9 +1147,9 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p ret = -EIO; } - dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) & ch, sizeof(struct dibDVBTChannel)); + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel)); - switch (ch.spectrum_inversion&0x7) { + switch (ch.spectrum_inversion & 0x7) { case 1: state->fe[0]->dtv_property_cache.inversion = INVERSION_ON; break; @@ -1267,7 +1264,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p break; } - error: +error: DibReleaseLock(&state->platform.risc.mem_mbx_lock); return ret; } @@ -1412,7 +1409,7 @@ static int dib9000_fw_set_channel_union(struct dvb_frontend *fe, struct dvb_fron ch.select_hp = 1; ch.intlv_native = 1; - dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) & ch); + dib9000_risc_mem_write(state, FE_MM_W_CHANNEL_UNION, (u8 *) &ch); return 0; } @@ -1441,9 +1438,9 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete break; case CT_DEMOD_STEP_1: if (search) - dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) & i, 1); + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1); else - dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) & i, 1); + dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1); switch (i) { /* something happened */ case 0: break; @@ -1484,22 +1481,22 @@ static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) dprintk("setting output mode for demod %p to %d", fe, mode); switch (mode) { - case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock + case OUTMODE_MPEG2_PAR_GATED_CLK: outreg = (1 << 10); /* 0x0400 */ break; - case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock + case OUTMODE_MPEG2_PAR_CONT_CLK: outreg = (1 << 10) | (1 << 6); /* 0x0440 */ break; - case OUTMODE_MPEG2_SERIAL: // STBs with serial input + case OUTMODE_MPEG2_SERIAL: outreg = (1 << 10) | (2 << 6) | (0 << 1); /* 0x0482 */ break; case OUTMODE_DIVERSITY: outreg = (1 << 10) | (4 << 6); /* 0x0500 */ break; - case OUTMODE_MPEG2_FIFO: // e.g. USB feeding + case OUTMODE_MPEG2_FIFO: outreg = (1 << 10) | (5 << 6); break; - case OUTMODE_HIGH_Z: // disable + case OUTMODE_HIGH_Z: outreg = 0; break; default: @@ -1507,7 +1504,7 @@ static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) return -EINVAL; } - dib9000_write_word(state, 1795, outreg); // has to be written from outside + dib9000_write_word(state, 1795, outreg); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: @@ -1596,10 +1593,9 @@ EXPORT_SYMBOL(dib9000_fw_set_component_bus_speed); static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct dib9000_state *state = i2c_get_adapdata(i2c_adap); - u8 type = 0; /* I2C */ + u8 type = 0; /* I2C */ u8 port = DIBX000_I2C_INTERFACE_GPIO_3_4; - u16 scl = state->component_bus_speed; /* SCL frequency */ - //u16 scl = 208; /* SCL frequency */ + u16 scl = state->component_bus_speed; /* SCL frequency */ struct dib9000_fe_memory_map *m = &state->platform.risc.fe_mm[FE_MM_RW_COMPONENT_ACCESS_BUFFER]; u8 p[13] = { 0 }; @@ -1610,11 +1606,6 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 p[3] = (u8) scl & 0xff; /* scl */ p[4] = (u8) (scl >> 8); -// p[5] = 0; /* attr */ -// p[6] = 0; - -// p[7] = (u8) (msg[0].addr << 1 ); -// p[8] = (u8) (msg[0].addr >> 7 ); p[7] = 0; p[8] = 0; @@ -1672,7 +1663,6 @@ struct i2c_adapter *dib9000_get_tuner_interface(struct dvb_frontend *fe) struct dib9000_state *st = fe->demodulator_priv; return &st->tuner_adap; } - EXPORT_SYMBOL(dib9000_get_tuner_interface); struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) @@ -1680,7 +1670,6 @@ struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe) struct dib9000_state *st = fe->demodulator_priv; return &st->component_bus; } - EXPORT_SYMBOL(dib9000_get_component_bus_interface); struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating) @@ -1688,7 +1677,6 @@ struct i2c_adapter *dib9000_get_i2c_master(struct dvb_frontend *fe, enum dibx000 struct dib9000_state *st = fe->demodulator_priv; return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating); } - EXPORT_SYMBOL(dib9000_get_i2c_master); int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) @@ -1698,7 +1686,6 @@ int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c) st->i2c.i2c_adap = i2c; return 0; } - EXPORT_SYMBOL(dib9000_set_i2c_adapter); static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val) @@ -1723,8 +1710,8 @@ int dib9000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) struct dib9000_state *state = fe->demodulator_priv; return dib9000_cfg_gpio(state, num, dir, val); } - EXPORT_SYMBOL(dib9000_set_gpio); + int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; @@ -1734,15 +1721,14 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) dprintk("PID filter enabled %d", onoff); return dib9000_write_word(state, 294 + 1, val); } - EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); + int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); } - EXPORT_SYMBOL(dib9000_fw_pid_filter); int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) @@ -1750,7 +1736,6 @@ int dib9000_firmware_post_pll_init(struct dvb_frontend *fe) struct dib9000_state *state = fe->demodulator_priv; return dib9000_fw_init(state); } - EXPORT_SYMBOL(dib9000_firmware_post_pll_init); static void dib9000_release(struct dvb_frontend *demod) @@ -1758,7 +1743,7 @@ static void dib9000_release(struct dvb_frontend *demod) struct dib9000_state *st = demod->demodulator_priv; u8 index_frontend; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++) dvb_frontend_detach(st->fe[index_frontend]); DibFreeLock(&state->platform.risc.mbx_if_lock); @@ -1784,7 +1769,7 @@ static int dib9000_sleep(struct dvb_frontend *fe) u8 index_frontend; int ret; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); if (ret < 0) return ret; @@ -1805,23 +1790,32 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par fe_status_t stat; int ret; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); if (stat & FE_HAS_SYNC) { dprintk("TPS lock on the slave%i", index_frontend); /* synchronize the cache with the other frontends */ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], fep); - for (sub_index_frontend=0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { + for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); + sub_index_frontend++) { if (sub_index_frontend != index_frontend) { - state->fe[sub_index_frontend]->dtv_property_cache.modulation = state->fe[index_frontend]->dtv_property_cache.modulation; - state->fe[sub_index_frontend]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; - state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; - state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; - state->fe[sub_index_frontend]->dtv_property_cache.hierarchy = state->fe[index_frontend]->dtv_property_cache.hierarchy; - state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP = state->fe[index_frontend]->dtv_property_cache.code_rate_HP; - state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP = state->fe[index_frontend]->dtv_property_cache.code_rate_LP; - state->fe[sub_index_frontend]->dtv_property_cache.rolloff = state->fe[index_frontend]->dtv_property_cache.rolloff; + state->fe[sub_index_frontend]->dtv_property_cache.modulation = + state->fe[index_frontend]->dtv_property_cache.modulation; + state->fe[sub_index_frontend]->dtv_property_cache.inversion = + state->fe[index_frontend]->dtv_property_cache.inversion; + state->fe[sub_index_frontend]->dtv_property_cache.transmission_mode = + state->fe[index_frontend]->dtv_property_cache.transmission_mode; + state->fe[sub_index_frontend]->dtv_property_cache.guard_interval = + state->fe[index_frontend]->dtv_property_cache.guard_interval; + state->fe[sub_index_frontend]->dtv_property_cache.hierarchy = + state->fe[index_frontend]->dtv_property_cache.hierarchy; + state->fe[sub_index_frontend]->dtv_property_cache.code_rate_HP = + state->fe[index_frontend]->dtv_property_cache.code_rate_HP; + state->fe[sub_index_frontend]->dtv_property_cache.code_rate_LP = + state->fe[index_frontend]->dtv_property_cache.code_rate_LP; + state->fe[sub_index_frontend]->dtv_property_cache.rolloff = + state->fe[index_frontend]->dtv_property_cache.rolloff; } } return 0; @@ -1834,7 +1828,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par return ret; /* synchronize the cache with the other frontends */ - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->dtv_property_cache.inversion = fe->dtv_property_cache.inversion; state->fe[index_frontend]->dtv_property_cache.transmission_mode = fe->dtv_property_cache.transmission_mode; state->fe[index_frontend]->dtv_property_cache.guard_interval = fe->dtv_property_cache.guard_interval; @@ -1894,14 +1888,14 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* set the master status */ if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO || - fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { + fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { /* no channel specified, autosearch the channel */ state->channel_status.status = CHANNEL_STATUS_PARAMETERS_UNKNOWN; } else state->channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; /* set mode and status for the different frontends */ - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { dib9000_fw_set_diversity_in(state->fe[index_frontend], 1); /* synchronization of the cache */ @@ -1915,11 +1909,11 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } /* actual tune */ - exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ + exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ index_frontend_success = 0; do { sleep_time = dib9000_fw_tune(state->fe[0], NULL); - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); if (sleep_time == FE_CALLBACK_TIME_NEVER) sleep_time = sleep_time_slave; @@ -1934,23 +1928,23 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par nbr_pending = 0; exit_condition = 0; index_frontend_success = 0; - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { frontend_status = -dib9000_get_status(state->fe[index_frontend]); if (frontend_status > -FE_STATUS_TUNE_PENDING) { - exit_condition = 2; /* tune success */ + exit_condition = 2; /* tune success */ index_frontend_success = index_frontend; break; } if (frontend_status == -FE_STATUS_TUNE_PENDING) - nbr_pending++; /* some frontends are still tuning */ + nbr_pending++; /* some frontends are still tuning */ } if ((exit_condition != 2) && (nbr_pending == 0)) - exit_condition = 1; /* if all tune are done and no success, exit: tune failed */ + exit_condition = 1; /* if all tune are done and no success, exit: tune failed */ } while (exit_condition == 0); /* check the tune result */ - if (exit_condition == 1) { /* tune failed */ + if (exit_condition == 1) { /* tune failed */ dprintk("tune failed"); return 0; } @@ -1962,7 +1956,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* retune the other frontends with the found channel */ channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { /* only retune the frontends which was not tuned success */ if (index_frontend != index_frontend_success) { dib9000_set_channel_status(state->fe[index_frontend], &channel_status); @@ -1971,7 +1965,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } do { sleep_time = FE_CALLBACK_TIME_NEVER; - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { if (index_frontend != index_frontend_success) { sleep_time_slave = dib9000_fw_tune(state->fe[index_frontend], NULL); if (sleep_time == FE_CALLBACK_TIME_NEVER) @@ -1986,22 +1980,22 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par break; nbr_pending = 0; - for (index_frontend=0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { if (index_frontend != index_frontend_success) { frontend_status = -dib9000_get_status(state->fe[index_frontend]); if ((index_frontend != index_frontend_success) && (frontend_status == -FE_STATUS_TUNE_PENDING)) - nbr_pending++; /* some frontends are still tuning */ + nbr_pending++; /* some frontends are still tuning */ } } } while (nbr_pending != 0); /* set the output mode */ dib9000_fw_set_output_mode(state->fe[0], state->chip.d9.cfg.output_mode); - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) dib9000_fw_set_output_mode(state->fe[index_frontend], OUTMODE_DIVERSITY); /* turn off the diversity for the last frontend */ - dib9000_fw_set_diversity_in(state->fe[index_frontend-1], 0); + dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); return 0; } @@ -2019,7 +2013,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) u8 index_frontend; u16 lock = 0, lock_slave = 0; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib9000_read_lock(state->fe[index_frontend]); lock = dib9000_read_word(state, 535); @@ -2063,7 +2057,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) u16 val; *strength = 0; - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); if (val > 65535 - *strength) *strength = 65535; @@ -2127,7 +2121,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) u32 snr_master; snr_master = dib9000_get_snr(fe); - for (index_frontend=1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) + for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) snr_master += dib9000_get_snr(state->fe[index_frontend]); if ((snr_master >> 16) != 0) { @@ -2161,7 +2155,7 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul struct i2c_device client = {.i2c_adap = i2c }; client.i2c_addr = default_addr + 16; - dib9000_i2c_write16(&client, 1796, 0x0); // select DVB-T output + dib9000_i2c_write16(&client, 1796, 0x0); for (k = no_of_demods - 1; k >= 0; k--) { /* designated i2c address */ @@ -2203,7 +2197,6 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul return 0; } - EXPORT_SYMBOL(dib9000_i2c_enumeration); int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave) @@ -2232,7 +2225,7 @@ int dib9000_remove_slave_frontend(struct dvb_frontend *fe) while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) index_frontend++; if (index_frontend != 1) { - dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); + dprintk("remove slave fe %p (index %i)", state->fe[index_frontend - 1], index_frontend - 1); state->fe[index_frontend] = NULL; return 0; } @@ -2242,7 +2235,7 @@ int dib9000_remove_slave_frontend(struct dvb_frontend *fe) } EXPORT_SYMBOL(dib9000_remove_slave_frontend); -struct dvb_frontend * dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { struct dib9000_state *state = fe->demodulator_priv; @@ -2313,13 +2306,12 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c return fe; - component_bus_add_error: +component_bus_add_error: i2c_del_adapter(&st->tuner_adap); - error: +error: kfree(st); return NULL; } - EXPORT_SYMBOL(dib9000_attach); static struct dvb_frontend_ops dib9000_ops = { diff --git a/drivers/media/dvb/frontends/dib9000.h b/drivers/media/dvb/frontends/dib9000.h index 995e4bc48a7d..b5781a48034c 100644 --- a/drivers/media/dvb/frontends/dib9000.h +++ b/drivers/media/dvb/frontends/dib9000.h @@ -38,7 +38,7 @@ extern int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 ono extern int dib9000_firmware_post_pll_init(struct dvb_frontend *fe); extern int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); extern int dib9000_remove_slave_frontend(struct dvb_frontend *fe); -extern struct dvb_frontend * dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); +extern struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); extern struct i2c_adapter *dib9000_get_component_bus_interface(struct dvb_frontend *fe); extern int dib9000_set_i2c_adapter(struct dvb_frontend *fe, struct i2c_adapter *i2c); extern int dib9000_fw_set_component_bus_speed(struct dvb_frontend *fe, u16 speed); @@ -103,7 +103,8 @@ int dib9000_remove_slave_frontend(struct dvb_frontend *fe) return -ENODEV; } -static inline struct dvb_frontend * dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) { +static inline struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int slave_index) +{ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 9bd95a978a1c..f6938f97feb4 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -26,8 +26,8 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) u8 wb[2] = { reg >> 8, reg & 0xff }; u8 rb[2]; struct i2c_msg msg[2] = { - {.addr = mst->i2c_addr,.flags = 0,.buf = wb,.len = 2}, - {.addr = mst->i2c_addr,.flags = I2C_M_RD,.buf = rb,.len = 2}, + {.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2}, + {.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2}, }; if (i2c_transfer(mst->i2c_adap, msg, 2) != 2) @@ -38,10 +38,11 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) { - int i = 100; // max_i2c_polls; + int i = 100; u16 status; - while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0); + while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0) + ; /* i2c timed out */ if (i == 0) @@ -63,7 +64,7 @@ static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_m const u8 *b = msg->buf; while (txlen) { - dibx000_read_word(mst, mst->base_reg + 2); // reset fifo ptr + dibx000_read_word(mst, mst->base_reg + 2); len = txlen > 8 ? 8 : txlen; for (i = 0; i < len; i += 2) { @@ -72,14 +73,14 @@ static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_m data |= *b++; dibx000_write_word(mst, mst->base_reg, data); } - da = (((u8) (msg->addr)) << 9) | // addr - (1 << 8) | // master - (1 << 7) | // rq - (0 << 6) | // stop - (0 << 5) | // start - ((len & 0x7) << 2) | // nb 8 bytes == 0 here - (0 << 1) | // rw - (0 << 0); // irqen + da = (((u8) (msg->addr)) << 9) | + (1 << 8) | + (1 << 7) | + (0 << 6) | + (0 << 5) | + ((len & 0x7) << 2) | + (0 << 1) | + (0 << 0); if (txlen == msg->len) da |= 1 << 5; /* start */ @@ -105,14 +106,14 @@ static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_ms while (rxlen) { len = rxlen > 8 ? 8 : rxlen; - da = (((u8) (msg->addr)) << 9) | // addr - (1 << 8) | // master - (1 << 7) | // rq - (0 << 6) | // stop - (0 << 5) | // start - ((len & 0x7) << 2) | // nb - (1 << 1) | // rw - (0 << 0); // irqen + da = (((u8) (msg->addr)) << 9) | + (1 << 8) | + (1 << 7) | + (0 << 6) | + (0 << 5) | + ((len & 0x7) << 2) | + (1 << 1) | + (0 << 0); if (rxlen == msg->len) da |= 1 << 5; /* start */ @@ -174,15 +175,12 @@ static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i int ret = 0; dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2); - for (msg_index = 0; msg_index Date: Sun, 16 Jan 2011 13:01:20 -0200 Subject: [media] dib7000p: Fix 4-byte wrong alignments for some case statements ERROR: switch and case should be at the same indent switch (ch->u.ofdm.transmission_mode) { [...] + case TRANSMISSION_MODE_4K: WARNING: please, no spaces at the start of a line + case TRANSMISSION_MODE_4K:$ ERROR: switch and case should be at the same indent switch (ch->u.ofdm.transmission_mode) { [...] + case TRANSMISSION_MODE_4K: WARNING: please, no spaces at the start of a line + case TRANSMISSION_MODE_4K:$ ERROR: switch and case should be at the same indent switch (ch->u.ofdm.transmission_mode) { [...] + case TRANSMISSION_MODE_4K: WARNING: please, no spaces at the start of a line + case TRANSMISSION_MODE_4K:$ Cc: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib7000p.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index b3ca3e2f8d53..900af60b9d36 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -880,7 +880,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte case TRANSMISSION_MODE_2K: value |= (0 << 7); break; - case TRANSMISSION_MODE_4K: + case TRANSMISSION_MODE_4K: value |= (2 << 7); break; default: @@ -1207,7 +1207,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet case TRANSMISSION_MODE_2K: tmp |= (2 << 12); break; - case TRANSMISSION_MODE_4K: + case TRANSMISSION_MODE_4K: tmp |= (3 << 12); break; default: @@ -1223,7 +1223,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet case TRANSMISSION_MODE_2K: tmp |= 0x6; break; - case TRANSMISSION_MODE_4K: + case TRANSMISSION_MODE_4K: tmp |= 0x7; break; default: @@ -1325,7 +1325,7 @@ static int dib7000p_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_pa case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break; - /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ + /* case 2: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_4K; break; */ } switch (tps & 0x3) { -- cgit v1.2.2 From 2c2c441b10644a273ff82a43ec18034ec1dd4c4e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 16 Jan 2011 13:02:52 -0200 Subject: [media] dib8000: Fix some wrong alignments Something went wrong with the alignments for the if clause at line 2113. Instead of using one tab for alignments, it used 3 tabs, plus one space character. WARNING: suspect code indent for conditional statements (8, 33) + if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || [...] + int i = 80000; WARNING: suspect code indent for conditional statements (33, 41) + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); WARNING: suspect code indent for conditional statements (33, 41) + do { + msleep(20); WARNING: suspect code indent for conditional statements (41, 49) + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (((tune_failed >> index_frontend) & 0x1) == 0) { WARNING: suspect code indent for conditional statements (49, 57) + if (((tune_failed >> index_frontend) & 0x1) == 0) { + found = dib8000_autosearch_irq(state->fe[index_frontend]); WARNING: suspect code indent for conditional statements (41, 49) + if ((nbr_pending == 0) && (exit_condition == 0)) + exit_condition = 1; Cc: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib8000.c | 96 +++++++++++++++++------------------ 1 file changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 3961fed9da6e..3e20aa8db23b 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -2134,54 +2134,54 @@ static int dib8000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { - int i = 80000; - u8 found = 0; - u8 tune_failed = 0; - - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); - dib8000_autosearch_start(state->fe[index_frontend]); - } - - do { - msleep(20); - nbr_pending = 0; - exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - if (((tune_failed >> index_frontend) & 0x1) == 0) { - found = dib8000_autosearch_irq(state->fe[index_frontend]); - switch (found) { - case 0: /* tune pending */ - nbr_pending++; - break; - case 2: - dprintk("autosearch succeed on the frontend%i", index_frontend); - exit_condition = 2; - index_frontend_success = index_frontend; - break; - default: - dprintk("unhandled autosearch result"); - case 1: - dprintk("autosearch failed for the frontend%i", index_frontend); - break; - } - } - } - - /* if all tune are done and no success, exit: tune failed */ - if ((nbr_pending == 0) && (exit_condition == 0)) - exit_condition = 1; - } while ((exit_condition == 0) && i--); - - if (exit_condition == 1) { /* tune failed */ - dprintk("tune failed"); - return 0; - } - - dprintk("tune success on frontend%i", index_frontend_success); - - dib8000_get_frontend(fe, fep); - } + int i = 80000; + u8 found = 0; + u8 tune_failed = 0; + + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); + dib8000_autosearch_start(state->fe[index_frontend]); + } + + do { + msleep(20); + nbr_pending = 0; + exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (((tune_failed >> index_frontend) & 0x1) == 0) { + found = dib8000_autosearch_irq(state->fe[index_frontend]); + switch (found) { + case 0: /* tune pending */ + nbr_pending++; + break; + case 2: + dprintk("autosearch succeed on the frontend%i", index_frontend); + exit_condition = 2; + index_frontend_success = index_frontend; + break; + default: + dprintk("unhandled autosearch result"); + case 1: + dprintk("autosearch failed for the frontend%i", index_frontend); + break; + } + } + } + + /* if all tune are done and no success, exit: tune failed */ + if ((nbr_pending == 0) && (exit_condition == 0)) + exit_condition = 1; + } while ((exit_condition == 0) && i--); + + if (exit_condition == 1) { /* tune failed */ + dprintk("tune failed"); + return 0; + } + + dprintk("tune success on frontend%i", index_frontend_success); + + dib8000_get_frontend(fe, fep); + } for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) ret = dib8000_tune(state->fe[index_frontend]); -- cgit v1.2.2 From 5bd0dc2d8a0db2f2e119ea50d07bf49e5e038f12 Mon Sep 17 00:00:00 2001 From: Andreas Regel Date: Mon, 10 Jan 2011 06:36:09 -0300 Subject: [media] stv090x: make sleep/wakeup specific to the demod path The STV0900 features two demodulator paths in one chip. Thus it is not possible to use the generic power off function of the chip when sending one of them to standby. The other path will stop working in that case. The sleep function now switches off functionality specific to the demod path. The global stuff is only switched off, when both paths are in sleep mode. The wakeup function always turns on the global functionality and then works specific to the path. Signed-off-by: Andreas Regel Signed-off-by: Oliver Endriss Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x.c | 211 +++++++++++++++++++++++++++++----- 1 file changed, 185 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index dba2c0407fd1..e26bfd765460 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -3846,6 +3846,7 @@ static int stv090x_sleep(struct dvb_frontend *fe) { struct stv090x_state *state = fe->demodulator_priv; u32 reg; + u8 full_standby = 0; if (stv090x_i2c_gate_ctrl(state, 1) < 0) goto err; @@ -3858,24 +3859,119 @@ static int stv090x_sleep(struct dvb_frontend *fe) if (stv090x_i2c_gate_ctrl(state, 0) < 0) goto err; - dprintk(FE_DEBUG, 1, "Set %s to sleep", - state->device == STV0900 ? "STV0900" : "STV0903"); + dprintk(FE_DEBUG, 1, "Set %s(%d) to sleep", + state->device == STV0900 ? "STV0900" : "STV0903", + state->demod); - reg = stv090x_read_reg(state, STV090x_SYNTCTRL); - STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01); - if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) - goto err; + mutex_lock(&state->internal->demod_lock); - reg = stv090x_read_reg(state, STV090x_TSTTNR1); - STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0); - if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) - goto err; + switch (state->demod) { + case STV090x_DEMODULATOR_0: + /* power off ADC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) + goto err; + /* power off DiSEqC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR2); + STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0) + goto err; + + /* check whether path 2 is already sleeping, that is when + ADC2 is off */ + reg = stv090x_read_reg(state, STV090x_TSTTNR3); + if (STV090x_GETFIELD(reg, ADC2_PON_FIELD) == 0) + full_standby = 1; + + /* stop clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 1); + /* ADC 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 1); + /* FEC clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1); + /* viterbi 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 1); + /* TS clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + case STV090x_DEMODULATOR_1: + /* power off ADC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR3); + STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) + goto err; + /* power off DiSEqC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR4); + STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0); + if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0) + goto err; + + /* check whether path 1 is already sleeping, that is when + ADC1 is off */ + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + if (STV090x_GETFIELD(reg, ADC1_PON_FIELD) == 0) + full_standby = 1; + + /* stop clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 1); + /* ADC 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 1); + /* FEC clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1); + /* viterbi 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 1); + /* TS clock is shared between the two paths, only stop it + when full standby is possible */ + if (full_standby) + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + + default: + dprintk(FE_ERROR, 1, "Wrong demodulator!"); + break; + } + + if (full_standby) { + /* general power off */ + reg = stv090x_read_reg(state, STV090x_SYNTCTRL); + STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01); + if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) + goto err; + } + + mutex_unlock(&state->internal->demod_lock); return 0; err_gateoff: stv090x_i2c_gate_ctrl(state, 0); err: + mutex_unlock(&state->internal->demod_lock); dprintk(FE_ERROR, 1, "I/O error"); return -1; } @@ -3885,21 +3981,94 @@ static int stv090x_wakeup(struct dvb_frontend *fe) struct stv090x_state *state = fe->demodulator_priv; u32 reg; - dprintk(FE_DEBUG, 1, "Wake %s from standby", - state->device == STV0900 ? "STV0900" : "STV0903"); + dprintk(FE_DEBUG, 1, "Wake %s(%d) from standby", + state->device == STV0900 ? "STV0900" : "STV0903", + state->demod); + + mutex_lock(&state->internal->demod_lock); + /* general power on */ reg = stv090x_read_reg(state, STV090x_SYNTCTRL); STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00); if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) goto err; - reg = stv090x_read_reg(state, STV090x_TSTTNR1); - STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1); - if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) - goto err; + switch (state->demod) { + case STV090x_DEMODULATOR_0: + /* power on ADC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR1); + STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) + goto err; + /* power on DiSEqC 1 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR2); + STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0) + goto err; + + /* activate clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT1_FIELD, 0); + /* ADC 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI1_FIELD, 0); + /* FEC clock */ + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 0); + /* viterbi 1 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, 0); + /* TS clock */ + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + case STV090x_DEMODULATOR_1: + /* power on ADC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR3); + STV090x_SETFIELD(reg, ADC2_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) + goto err; + /* power on DiSEqC 2 */ + reg = stv090x_read_reg(state, STV090x_TSTTNR4); + STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 1); + if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0) + goto err; + + /* activate clocks */ + reg = stv090x_read_reg(state, STV090x_STOPCLK1); + /* packet delineator 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKPKDT2_FIELD, 0); + /* ADC 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKADCI2_FIELD, 0); + /* FEC clock */ + STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) + goto err; + reg = stv090x_read_reg(state, STV090x_STOPCLK2); + /* sampling 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 0); + /* viterbi 2 clock */ + STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, 0); + /* TS clock */ + STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 0); + if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) + goto err; + break; + + default: + dprintk(FE_ERROR, 1, "Wrong demodulator!"); + break; + } + + mutex_unlock(&state->internal->demod_lock); return 0; err: + mutex_unlock(&state->internal->demod_lock); dprintk(FE_ERROR, 1, "I/O error"); return -1; } @@ -4622,20 +4791,10 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, mutex_init(&state->internal->demod_lock); mutex_init(&state->internal->tuner_lock); - if (stv090x_sleep(&state->frontend) < 0) { - dprintk(FE_ERROR, 1, "Error putting device to sleep"); - goto error; - } - if (stv090x_setup(&state->frontend) < 0) { dprintk(FE_ERROR, 1, "Error setting up device"); goto error; } - if (stv090x_wakeup(&state->frontend) < 0) { - dprintk(FE_ERROR, 1, "Error waking device"); - goto error; - } - dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", state->device == STV0900 ? "STV0900" : "STV0903", demod, -- cgit v1.2.2 From f790bdd00da937845b38467abfebdea09acfea0e Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:10 -0300 Subject: [media] stv090x: Optional external lock routine Card driver may supply its own lock routine now. Signed-off-by: Oliver Endriss Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x.c | 21 ++++++++++++++++----- drivers/media/dvb/frontends/stv090x.h | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index e26bfd765460..eccad06216ce 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -767,8 +767,12 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) * In case of any error, the lock is unlocked and exit within the * relevant operations themselves. */ - if (enable) - mutex_lock(&state->internal->tuner_lock); + if (enable) { + if (state->config->tuner_i2c_lock) + state->config->tuner_i2c_lock(&state->frontend, 1); + else + mutex_lock(&state->internal->tuner_lock); + } reg = STV090x_READ_DEMOD(state, I2CRPT); if (enable) { @@ -784,13 +788,20 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) goto err; } - if (!enable) - mutex_unlock(&state->internal->tuner_lock); + if (!enable) { + if (state->config->tuner_i2c_lock) + state->config->tuner_i2c_lock(&state->frontend, 0); + else + mutex_unlock(&state->internal->tuner_lock); + } return 0; err: dprintk(FE_ERROR, 1, "I/O error"); - mutex_unlock(&state->internal->tuner_lock); + if (state->config->tuner_i2c_lock) + state->config->tuner_i2c_lock(&state->frontend, 0); + else + mutex_unlock(&state->internal->tuner_lock); return -1; } diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h index a3fefa717ed6..29cdc2b71314 100644 --- a/drivers/media/dvb/frontends/stv090x.h +++ b/drivers/media/dvb/frontends/stv090x.h @@ -100,6 +100,7 @@ struct stv090x_config { int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain); int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk); int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status); + void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock); }; #if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE)) -- cgit v1.2.2 From 09961aae7b3ea8640051e464b346ed3984521de8 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:11 -0300 Subject: [media] ngene: Firmware 18 support Small modifications for firmware 18. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index dc073bdc623a..cd5b1f3e902d 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1257,6 +1257,10 @@ static int ngene_load_firm(struct ngene *dev) fw_name = "ngene_17.fw"; dev->cmd_timeout_workaround = true; break; + case 18: + size = 0; + fw_name = "ngene_18.fw"; + break; } if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) { @@ -1266,6 +1270,8 @@ static int ngene_load_firm(struct ngene *dev) ": Copy %s to your hotplug directory!\n", fw_name); return -1; } + if (size == 0) + size = fw->size; if (size != fw->size) { printk(KERN_ERR DEVICE_NAME ": Firmware %s has invalid size!", fw_name); @@ -1365,7 +1371,7 @@ static int ngene_start(struct ngene *dev) if (stat < 0) goto fail; - if (dev->card_info->fw_version == 17) { + if (dev->card_info->fw_version >= 17) { u8 tsin4_config[6] = { 3072 / 64, 3072 / 64, 0, 3072 / 64, 3072 / 64, 0}; u8 default_config[6] = { @@ -1374,7 +1380,7 @@ static int ngene_start(struct ngene *dev) if (dev->card_info->io_type[3] == NGENE_IO_TSIN) bconf = tsin4_config; - dprintk(KERN_DEBUG DEVICE_NAME ": FW 17 buffer config\n"); + dprintk(KERN_DEBUG DEVICE_NAME ": FW 17+ buffer config\n"); stat = ngene_command_config_free_buf(dev, bconf); } else { int bconf = BUFFER_CONFIG_4422; -- cgit v1.2.2 From ac9725d224544954a8d3413a2a66bdf49f735d8b Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:12 -0300 Subject: [media] ngene: Fixes for TS input over I2S Fix TS input over I2S. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 4 ++-- drivers/media/dvb/ngene/ngene-dvb.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index cd5b1f3e902d..8764647e55f3 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -143,7 +143,7 @@ static void demux_tasklet(unsigned long data) } } else { if (chan->HWState == HWSTATE_RUN) { - u32 Flags = 0; + u32 Flags = chan->DataFormatFlags; IBufferExchange *exch1 = chan->pBufferExchange; IBufferExchange *exch2 = chan->pBufferExchange2; if (Cur->ngeneBuffer.SR.Flags & 0x01) @@ -474,7 +474,7 @@ static u8 SPDIFConfiguration[10] = { /* Set NGENE I2S Config to transport stream compatible mode */ -static u8 TS_I2SConfiguration[4] = { 0x3E, 0x1A, 0x00, 0x00 }; /*3e 18 00 00 ?*/ +static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x20, 0x00, 0x00 }; diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c index 3832e5983c19..8bb159370c70 100644 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ b/drivers/media/dvb/ngene/ngene-dvb.c @@ -65,8 +65,11 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) struct ngene_channel *chan = priv; - if (chan->users > 0) + if (chan->users > 0) { + if (flags & DF_SWAP32) + swap_buffer(buf, len); dvb_dmx_swfilter(&chan->demux, buf, len); + } return NULL; } -- cgit v1.2.2 From 5fec18574fec3eaffcab596c1a4e943e2d413cc3 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:13 -0300 Subject: [media] ngene: Support up to 4 tuners Support up to 4 tuners for cineS2 v5, duoflex & mystique v2. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-cards.c | 174 ++++++++++++++++++++++++++++------ 1 file changed, 143 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 4692a41ad95b..5e6b85c3c0fc 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -48,20 +48,27 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) { + struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; struct stv6110x_config *tunerconf = (struct stv6110x_config *) chan->dev->card_info->tuner_config[chan->number]; struct stv6110x_devctl *ctl; - ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, - &chan->i2c_adapter); + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); if (ctl == NULL) { printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); return -ENODEV; } feconf->tuner_init = ctl->tuner_init; + feconf->tuner_sleep = ctl->tuner_sleep; feconf->tuner_set_mode = ctl->tuner_set_mode; feconf->tuner_set_frequency = ctl->tuner_set_frequency; feconf->tuner_get_frequency = ctl->tuner_get_frequency; @@ -78,20 +85,31 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) static int demod_attach_stv0900(struct ngene_channel *chan) { + struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; - chan->fe = dvb_attach(stv090x_attach, - feconf, - &chan->i2c_adapter, - chan->number == 0 ? STV090x_DEMODULATOR_0 : - STV090x_DEMODULATOR_1); + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + /* Note: Both adapters share the same i2c bus, but the demod */ + /* driver requires that each demod has its own i2c adapter */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + chan->fe = dvb_attach(stv090x_attach, feconf, i2c, + (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 + : STV090x_DEMODULATOR_1); if (chan->fe == NULL) { printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); return -ENODEV; } - if (!dvb_attach(lnbh24_attach, chan->fe, &chan->i2c_adapter, 0, + /* store channel info */ + if (feconf->tuner_i2c_lock) + chan->fe->analog_demod_priv = chan; + + if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, 0, chan->dev->card_info->lnb[chan->number])) { printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); dvb_frontend_detach(chan->fe); @@ -101,6 +119,71 @@ static int demod_attach_stv0900(struct ngene_channel *chan) return 0; } +static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) +{ + struct ngene_channel *chan = fe->analog_demod_priv; + + if (lock) + down(&chan->dev->pll_mutex); + else + up(&chan->dev->pll_mutex); +} + +static int cineS2_probe(struct ngene_channel *chan) +{ + struct i2c_adapter *i2c; + struct stv090x_config *fe_conf; + u8 buf[3]; + struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; + int rc; + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + fe_conf = chan->dev->card_info->fe_config[chan->number]; + i2c_msg.addr = fe_conf->address; + + /* probe demod */ + i2c_msg.len = 2; + buf[0] = 0xf1; + buf[1] = 0x00; + rc = i2c_transfer(i2c, &i2c_msg, 1); + if (rc != 1) + return -ENODEV; + + /* demod found, attach it */ + rc = demod_attach_stv0900(chan); + if (rc < 0 || chan->number < 2) + return rc; + + /* demod #2: reprogram outputs DPN1 & DPN2 */ + i2c_msg.len = 3; + buf[0] = 0xf1; + switch (chan->number) { + case 2: + buf[1] = 0x5c; + buf[2] = 0xc2; + break; + case 3: + buf[1] = 0x61; + buf[2] = 0xcc; + break; + default: + return -ENODEV; + } + rc = i2c_transfer(i2c, &i2c_msg, 1); + if (rc != 1) { + printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); + return -EIO; + } + + return 0; +} + + static struct lgdt330x_config aver_m780 = { .demod_address = 0xb2 >> 1, .demod_chip = LGDT3303, @@ -151,6 +234,29 @@ static struct stv090x_config fe_cineS2 = { .adc2_range = STV090x_ADC_1Vpp, .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, +}; + +static struct stv090x_config fe_cineS2_2 = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 27000000, + .address = 0x69, + + .ts1_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + .ts2_mode = STV090x_TSMODE_SERIAL_PUNCTURED, + + .repeater_level = STV090x_RPTLEVEL_16, + + .adc1_range = STV090x_ADC_1Vpp, + .adc2_range = STV090x_ADC_1Vpp, + + .diseqc_envelope_mode = true, + + .tuner_i2c_lock = cineS2_tuner_i2c_lock, }; static struct stv6110x_config tuner_cineS2_0 = { @@ -175,7 +281,8 @@ static struct ngene_info ngene_info_cineS2 = { .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, .lnb = {0x0b, 0x08}, .tsf = {3, 3}, - .fw_version = 15, + .fw_version = 18, + .msi_supported = true, }; static struct ngene_info ngene_info_satixS2 = { @@ -188,46 +295,51 @@ static struct ngene_info ngene_info_satixS2 = { .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, .lnb = {0x0b, 0x08}, .tsf = {3, 3}, - .fw_version = 15, + .fw_version = 18, + .msi_supported = true, }; static struct ngene_info ngene_info_satixS2v2 = { .type = NGENE_SIDEWINDER, .name = "Mystique SaTiX-S2 Dual (v2)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08}, + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, .tsf = {3, 3}, - .fw_version = 15, + .fw_version = 18, + .msi_supported = true, }; static struct ngene_info ngene_info_cineS2v5 = { .type = NGENE_SIDEWINDER, .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08}, + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, .tsf = {3, 3}, - .fw_version = 15, + .fw_version = 18, + .msi_supported = true, }; + static struct ngene_info ngene_info_duoFlexS2 = { .type = NGENE_SIDEWINDER, .name = "Digital Devices DuoFlex S2 miniPCIe", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN}, - .demod_attach = {demod_attach_stv0900, demod_attach_stv0900}, - .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110}, - .fe_config = {&fe_cineS2, &fe_cineS2}, - .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1}, - .lnb = {0x0a, 0x08}, + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN}, + .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, + .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, + .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, + .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, + .lnb = {0x0a, 0x08, 0x0b, 0x09}, .tsf = {3, 3}, - .fw_version = 15, + .fw_version = 18, + .msi_supported = true, }; static struct ngene_info ngene_info_m780 = { -- cgit v1.2.2 From 8a484719c790772bc51c87c56323611752361bef Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:14 -0300 Subject: [media] ngene: Clean-up driver initialisation (part 1) If tuner initialisation failed, the frontend node was not removed. When the frontend was opened, a kernel oops occurred... This is the first step to improve error handling during initialisation. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-cards.c | 1 + drivers/media/dvb/ngene/ngene-core.c | 35 ++++++++++++++++++++++------------- 2 files changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 5e6b85c3c0fc..fc93d1064d4e 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -113,6 +113,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) 0, chan->dev->card_info->lnb[chan->number])) { printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); dvb_frontend_detach(chan->fe); + chan->fe = NULL; return -ENODEV; } diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 8764647e55f3..831b7586e88f 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1482,23 +1482,32 @@ static int init_channel(struct ngene_channel *chan) if (io & NGENE_IO_TSIN) { chan->fe = NULL; - if (ni->demod_attach[nr]) - ni->demod_attach[nr](chan); + if (ni->demod_attach[nr]) { + ret = ni->demod_attach[nr](chan); + if (ret < 0) + goto err_fe; + } + if (chan->fe && ni->tuner_attach[nr]) { + ret = ni->tuner_attach[nr](chan); + if (ret < 0) + goto err_fe; + } if (chan->fe) { - if (dvb_register_frontend(adapter, chan->fe) < 0) { - if (chan->fe->ops.release) - chan->fe->ops.release(chan->fe); - chan->fe = NULL; - } + if (dvb_register_frontend(adapter, chan->fe) < 0) + goto err_fe; } - if (chan->fe && ni->tuner_attach[nr]) - if (ni->tuner_attach[nr] (chan) < 0) { - printk(KERN_ERR DEVICE_NAME - ": Tuner attach failed on channel %d!\n", - nr); - } } return ret; + +err_fe: + if (chan->fe) { + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } +/* FIXME: this causes an oops... */ +/* release_channel(chan); */ +/* return ret; */ + return 0; } static int init_channels(struct ngene *dev) -- cgit v1.2.2 From 0f0b270f905bbb0c8e75988ceaf10ff9a401e712 Mon Sep 17 00:00:00 2001 From: Ralph Metzler Date: Mon, 10 Jan 2011 06:36:15 -0300 Subject: [media] ngene: CXD2099AR Common Interface driver Driver for the Common Interface Controller CXD2099AR. Supports the CI of the cineS2 DVB-S2. For now, data is passed through '/dev/dvb/adapterX/sec0': - Encrypted data must be written to 'sec0'. - Decrypted data can be read from 'sec0'. - Setup the CAM using device 'ca0'. Signed-off-by: Ralph Metzler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/Makefile | 2 +- drivers/media/dvb/ngene/cxd2099.c | 574 ++++++++++++++++++++++++++++++++++ drivers/media/dvb/ngene/cxd2099.h | 32 ++ drivers/media/dvb/ngene/ngene-cards.c | 6 +- drivers/media/dvb/ngene/ngene-core.c | 110 +++++-- drivers/media/dvb/ngene/ngene-dvb.c | 70 ++++- drivers/media/dvb/ngene/ngene.h | 19 ++ 7 files changed, 782 insertions(+), 31 deletions(-) create mode 100644 drivers/media/dvb/ngene/cxd2099.c create mode 100644 drivers/media/dvb/ngene/cxd2099.h (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile index 0608aabb14ee..00d12d6c4618 100644 --- a/drivers/media/dvb/ngene/Makefile +++ b/drivers/media/dvb/ngene/Makefile @@ -2,7 +2,7 @@ # Makefile for the nGene device driver # -ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o +ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o cxd2099.o obj-$(CONFIG_DVB_NGENE) += ngene.o diff --git a/drivers/media/dvb/ngene/cxd2099.c b/drivers/media/dvb/ngene/cxd2099.c new file mode 100644 index 000000000000..b49186c74eb3 --- /dev/null +++ b/drivers/media/dvb/ngene/cxd2099.c @@ -0,0 +1,574 @@ +/* + * cxd2099.c: Driver for the CXD2099AR Common Interface Controller + * + * Copyright (C) 2010 DigitalDevices UG + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cxd2099.h" + +#define MAX_BUFFER_SIZE 248 + +struct cxd { + struct dvb_ca_en50221 en; + + struct i2c_adapter *i2c; + u8 adr; + u8 regs[0x23]; + u8 lastaddress; + u8 clk_reg_f; + u8 clk_reg_b; + int mode; + u32 bitrate; + int ready; + int dr; + int slot_stat; + + u8 amem[1024]; + int amem_read; + + int cammode; + struct mutex lock; +}; + +static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr, + u8 reg, u8 data) +{ + u8 m[2] = {reg, data}; + struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2}; + + if (i2c_transfer(adapter, &msg, 1) != 1) { + printk(KERN_ERR "Failed to write to I2C register %02x@%02x!\n", + reg, adr); + return -1; + } + return 0; +} + +static int i2c_write(struct i2c_adapter *adapter, u8 adr, + u8 *data, u8 len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; + + if (i2c_transfer(adapter, &msg, 1) != 1) { + printk(KERN_ERR "Failed to write to I2C!\n"); + return -1; + } + return 0; +} + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, + u8 reg, u8 *val) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + + if (i2c_transfer(adapter, msgs, 2) != 2) { + printk(KERN_ERR "error in i2c_read_reg\n"); + return -1; + } + return 0; +} + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, + u8 reg, u8 *data, u8 n) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = data, .len = n } }; + + if (i2c_transfer(adapter, msgs, 2) != 2) { + printk(KERN_ERR "error in i2c_read\n"); + return -1; + } + return 0; +} + +static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n) +{ + int status; + + status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); + if (!status) { + ci->lastaddress = adr; + status = i2c_read(ci->i2c, ci->adr, 1, data, n); + } + return status; +} + +static int read_reg(struct cxd *ci, u8 reg, u8 *val) +{ + return read_block(ci, reg, val, 1); +} + + +static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) + status = i2c_read(ci->i2c, ci->adr, 3, data, n); + return status; +} + +static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) { + u8 buf[256] = {3}; + memcpy(buf+1, data, n); + status = i2c_write(ci->i2c, ci->adr, buf, n+1); + } + return status; +} + +static int read_io(struct cxd *ci, u16 address, u8 *val) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) + status = i2c_read(ci->i2c, ci->adr, 3, val, 1); + return status; +} + +static int write_io(struct cxd *ci, u16 address, u8 val) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + u8 buf[2] = { 3, val }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) + status = i2c_write(ci->i2c, ci->adr, buf, 2); + + return status; +} + + +static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) +{ + int status; + + status = i2c_write_reg(ci->i2c, ci->adr, 0, reg); + if (!status && reg >= 6 && reg <= 8 && mask != 0xff) + status = i2c_read_reg(ci->i2c, ci->adr, 1, &ci->regs[reg]); + ci->regs[reg] = (ci->regs[reg]&(~mask))|val; + if (!status) { + ci->lastaddress = reg; + status = i2c_write_reg(ci->i2c, ci->adr, 1, ci->regs[reg]); + } + if (reg == 0x20) + ci->regs[reg] &= 0x7f; + return status; +} + +static int write_reg(struct cxd *ci, u8 reg, u8 val) +{ + return write_regm(ci, reg, val, 0xff); +} + +#ifdef BUFFER_MODE +static int write_block(struct cxd *ci, u8 adr, u8 *data, int n) +{ + int status; + u8 buf[256] = {1}; + + status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); + if (!status) { + ci->lastaddress = adr; + memcpy(buf+1, data, n); + status = i2c_write(ci->i2c, ci->adr, buf, n+1); + } + return status; +} +#endif + +static void set_mode(struct cxd *ci, int mode) +{ + if (mode == ci->mode) + return; + + switch (mode) { + case 0x00: /* IO mem */ + write_regm(ci, 0x06, 0x00, 0x07); + break; + case 0x01: /* ATT mem */ + write_regm(ci, 0x06, 0x02, 0x07); + break; + default: + break; + } + ci->mode = mode; +} + +static void cam_mode(struct cxd *ci, int mode) +{ + if (mode == ci->cammode) + return; + + switch (mode) { + case 0x00: + write_regm(ci, 0x20, 0x80, 0x80); + break; + case 0x01: + printk(KERN_INFO "enable cam buffer mode\n"); + /* write_reg(ci, 0x0d, 0x00); */ + /* write_reg(ci, 0x0e, 0x01); */ + write_regm(ci, 0x08, 0x40, 0x40); + /* read_reg(ci, 0x12, &dummy); */ + write_regm(ci, 0x08, 0x80, 0x80); + break; + default: + break; + } + ci->cammode = mode; +} + + + +#define CHK_ERROR(s) if ((status = s)) break + +static int init(struct cxd *ci) +{ + int status; + + mutex_lock(&ci->lock); + ci->mode = -1; + do { + CHK_ERROR(write_reg(ci, 0x00, 0x00)); + CHK_ERROR(write_reg(ci, 0x01, 0x00)); + CHK_ERROR(write_reg(ci, 0x02, 0x10)); + CHK_ERROR(write_reg(ci, 0x03, 0x00)); + CHK_ERROR(write_reg(ci, 0x05, 0xFF)); + CHK_ERROR(write_reg(ci, 0x06, 0x1F)); + CHK_ERROR(write_reg(ci, 0x07, 0x1F)); + CHK_ERROR(write_reg(ci, 0x08, 0x28)); + CHK_ERROR(write_reg(ci, 0x14, 0x20)); + + CHK_ERROR(write_reg(ci, 0x09, 0x4D)); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */ + CHK_ERROR(write_reg(ci, 0x0A, 0xA7)); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */ + + /* Sync detector */ + CHK_ERROR(write_reg(ci, 0x0B, 0x33)); + CHK_ERROR(write_reg(ci, 0x0C, 0x33)); + + CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F)); + CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b)); + CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F)); + CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f)); + + CHK_ERROR(write_reg(ci, 0x20, 0x28)); /* Integer Divider, Falling Edge, Internal Sync, */ + CHK_ERROR(write_reg(ci, 0x21, 0x00)); /* MCLKI = TICLK/8 */ + CHK_ERROR(write_reg(ci, 0x22, 0x07)); /* MCLKI = TICLK/8 */ + + + CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80)); /* Reset CAM state machine */ + + CHK_ERROR(write_regm(ci, 0x03, 0x02, 02)); /* Enable IREQA Interrupt */ + CHK_ERROR(write_reg(ci, 0x01, 0x04)); /* Enable CD Interrupt */ + CHK_ERROR(write_reg(ci, 0x00, 0x31)); /* Enable TS1,Hot Swap,Slot A */ + CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08)); /* Put TS in bypass */ + ci->cammode = -1; +#ifdef BUFFER_MODE + cam_mode(ci, 0); +#endif + } while (0); + mutex_unlock(&ci->lock); + + return 0; +} + + +static int read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address) +{ + struct cxd *ci = ca->data; + u8 val; + mutex_lock(&ci->lock); + set_mode(ci, 1); + read_pccard(ci, address, &val, 1); + mutex_unlock(&ci->lock); + return val; +} + + +static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, + int address, u8 value) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + set_mode(ci, 1); + write_pccard(ci, address, &value, 1); + mutex_unlock(&ci->lock); + return 0; +} + +static int read_cam_control(struct dvb_ca_en50221 *ca, + int slot, u8 address) +{ + struct cxd *ci = ca->data; + u8 val; + + mutex_lock(&ci->lock); + set_mode(ci, 0); + read_io(ci, address, &val); + mutex_unlock(&ci->lock); + return val; +} + +static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, + u8 address, u8 value) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + set_mode(ci, 0); + write_io(ci, address, value); + mutex_unlock(&ci->lock); + return 0; +} + +static int slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + cam_mode(ci, 0); + write_reg(ci, 0x00, 0x21); + write_reg(ci, 0x06, 0x1F); + write_reg(ci, 0x00, 0x31); + write_regm(ci, 0x20, 0x80, 0x80); + write_reg(ci, 0x03, 0x02); + ci->ready = 0; + ci->mode = -1; + { + int i; + for (i = 0; i < 100; i++) { + msleep(10); + if (ci->ready) + break; + } + } + mutex_unlock(&ci->lock); + /* msleep(500); */ + return 0; +} + +static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + printk(KERN_INFO "slot_shutdown\n"); + mutex_lock(&ci->lock); + /* write_regm(ci, 0x09, 0x08, 0x08); */ + write_regm(ci, 0x20, 0x80, 0x80); + write_regm(ci, 0x06, 0x07, 0x07); + ci->mode = -1; + mutex_unlock(&ci->lock); + return 0; /* shutdown(ci); */ +} + +static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + write_regm(ci, 0x09, 0x00, 0x08); + set_mode(ci, 0); +#ifdef BUFFER_MODE + cam_mode(ci, 1); +#endif + mutex_unlock(&ci->lock); + return 0; +} + + +static int campoll(struct cxd *ci) +{ + u8 istat; + + read_reg(ci, 0x04, &istat); + if (!istat) + return 0; + write_reg(ci, 0x05, istat); + + if (istat&0x40) { + ci->dr = 1; + printk(KERN_INFO "DR\n"); + } + if (istat&0x20) + printk(KERN_INFO "WC\n"); + + if (istat&2) { + u8 slotstat; + + read_reg(ci, 0x01, &slotstat); + if (!(2&slotstat)) { + if (!ci->slot_stat) { + ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; + write_regm(ci, 0x03, 0x08, 0x08); + } + + } else { + if (ci->slot_stat) { + ci->slot_stat = 0; + write_regm(ci, 0x03, 0x00, 0x08); + printk(KERN_INFO "NO CAM\n"); + ci->ready = 0; + } + } + if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { + ci->ready = 1; + ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; + printk(KERN_INFO "READY\n"); + } + } + return 0; +} + + +static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct cxd *ci = ca->data; + u8 slotstat; + + mutex_lock(&ci->lock); + campoll(ci); + read_reg(ci, 0x01, &slotstat); + mutex_unlock(&ci->lock); + + return ci->slot_stat; +} + +#ifdef BUFFER_MODE +static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) +{ + struct cxd *ci = ca->data; + u8 msb, lsb; + u16 len; + + mutex_lock(&ci->lock); + campoll(ci); + mutex_unlock(&ci->lock); + + printk(KERN_INFO "read_data\n"); + if (!ci->dr) + return 0; + + mutex_lock(&ci->lock); + read_reg(ci, 0x0f, &msb); + read_reg(ci, 0x10, &lsb); + len = (msb<<8)|lsb; + read_block(ci, 0x12, ebuf, len); + ci->dr = 0; + mutex_unlock(&ci->lock); + + return len; +} + +static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + printk(KERN_INFO "write_data %d\n", ecount); + write_reg(ci, 0x0d, ecount>>8); + write_reg(ci, 0x0e, ecount&0xff); + write_block(ci, 0x11, ebuf, ecount); + mutex_unlock(&ci->lock); + return ecount; +} +#endif + +static struct dvb_ca_en50221 en_templ = { + .read_attribute_mem = read_attribute_mem, + .write_attribute_mem = write_attribute_mem, + .read_cam_control = read_cam_control, + .write_cam_control = write_cam_control, + .slot_reset = slot_reset, + .slot_shutdown = slot_shutdown, + .slot_ts_enable = slot_ts_enable, + .poll_slot_status = poll_slot_status, +#ifdef BUFFER_MODE + .read_data = read_data, + .write_data = write_data, +#endif + +}; + +struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, + struct i2c_adapter *i2c) +{ + struct cxd *ci = 0; + u32 bitrate = 62000000; + u8 val; + + if (i2c_read_reg(i2c, adr, 0, &val) < 0) { + printk(KERN_ERR "No CXD2099 detected at %02x\n", adr); + return 0; + } + + ci = kmalloc(sizeof(struct cxd), GFP_KERNEL); + if (!ci) + return 0; + memset(ci, 0, sizeof(*ci)); + + mutex_init(&ci->lock); + ci->i2c = i2c; + ci->adr = adr; + ci->lastaddress = 0xff; + ci->clk_reg_b = 0x4a; + ci->clk_reg_f = 0x1b; + ci->bitrate = bitrate; + + memcpy(&ci->en, &en_templ, sizeof(en_templ)); + ci->en.data = ci; + init(ci); + printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->adr); + return &ci->en; +} +EXPORT_SYMBOL(cxd2099_attach); + +MODULE_DESCRIPTION("cxd2099"); +MODULE_AUTHOR("Ralph Metzler "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ngene/cxd2099.h b/drivers/media/dvb/ngene/cxd2099.h new file mode 100644 index 000000000000..f71b807e8bb7 --- /dev/null +++ b/drivers/media/dvb/ngene/cxd2099.h @@ -0,0 +1,32 @@ +/* + * cxd2099.h: Driver for the CXD2099AR Common Interface Controller + * + * Copyright (C) 2010 DigitalDevices UG + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _CXD2099_H_ +#define _CXD2099_H_ + +#include + +struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c); + +#endif diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index fc93d1064d4e..93e6f9e954ca 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -317,7 +317,8 @@ static struct ngene_info ngene_info_satixS2v2 = { static struct ngene_info ngene_info_cineS2v5 = { .type = NGENE_SIDEWINDER, .name = "Linux4Media cineS2 DVB-S2 Twin Tuner (v5)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN}, + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, @@ -332,7 +333,8 @@ static struct ngene_info ngene_info_cineS2v5 = { static struct ngene_info ngene_info_duoFlexS2 = { .type = NGENE_SIDEWINDER, .name = "Digital Devices DuoFlex S2 miniPCIe", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN}, + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 831b7586e88f..deaf72aab058 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -45,7 +45,6 @@ static int one_adapter = 1; module_param(one_adapter, int, 0444); MODULE_PARM_DESC(one_adapter, "Use only one adapter."); - static int debug; module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "Print debugging information."); @@ -476,7 +475,7 @@ static u8 SPDIFConfiguration[10] = { static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 }; -static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x20, 0x00, 0x00 }; +static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 }; static u8 ITUDecoderSetup[4][16] = { {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */ @@ -749,13 +748,11 @@ void set_transfer(struct ngene_channel *chan, int state) if (chan->mode & NGENE_IO_TSOUT) { chan->pBufferExchange = tsout_exchange; /* 0x66666666 = 50MHz *2^33 /250MHz */ - chan->AudioDTOValue = 0x66666666; - /* set_dto(chan, 38810700+1000); */ - /* set_dto(chan, 19392658); */ + chan->AudioDTOValue = 0x80000000; + chan->AudioDTOUpdated = 1; } if (chan->mode & NGENE_IO_TSIN) chan->pBufferExchange = tsin_exchange; - /* ngwritel(0, 0x9310); */ spin_unlock_irq(&chan->state_lock); } else ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", @@ -1168,6 +1165,7 @@ static void ngene_release_buffers(struct ngene *dev) iounmap(dev->iomem); free_common_buffers(dev); vfree(dev->tsout_buf); + vfree(dev->tsin_buf); vfree(dev->ain_buf); vfree(dev->vin_buf); vfree(dev); @@ -1184,6 +1182,13 @@ static int ngene_get_buffers(struct ngene *dev) dvb_ringbuffer_init(&dev->tsout_rbuf, dev->tsout_buf, TSOUT_BUF_SIZE); } + if (dev->card_info->io_type[2]&NGENE_IO_TSIN) { + dev->tsin_buf = vmalloc(TSIN_BUF_SIZE); + if (!dev->tsin_buf) + return -ENOMEM; + dvb_ringbuffer_init(&dev->tsin_rbuf, + dev->tsin_buf, TSIN_BUF_SIZE); + } if (dev->card_info->io_type[2] & NGENE_IO_AIN) { dev->ain_buf = vmalloc(AIN_BUF_SIZE); if (!dev->ain_buf) @@ -1307,6 +1312,35 @@ static void ngene_stop(struct ngene *dev) #endif } +static int ngene_buffer_config(struct ngene *dev) +{ + int stat; + + if (dev->card_info->fw_version >= 17) { + u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; + u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; + u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; + u8 *bconf = tsin12_config; + + if (dev->card_info->io_type[2]&NGENE_IO_TSIN && + dev->card_info->io_type[3]&NGENE_IO_TSIN) { + bconf = tsin1234_config; + if (dev->card_info->io_type[4]&NGENE_IO_TSOUT && + dev->ci.en) + bconf = tsio1235_config; + } + stat = ngene_command_config_free_buf(dev, bconf); + } else { + int bconf = BUFFER_CONFIG_4422; + + if (dev->card_info->io_type[3] == NGENE_IO_TSIN) + bconf = BUFFER_CONFIG_3333; + stat = ngene_command_config_buf(dev, bconf); + } + return stat; +} + + static int ngene_start(struct ngene *dev) { int stat; @@ -1371,23 +1405,6 @@ static int ngene_start(struct ngene *dev) if (stat < 0) goto fail; - if (dev->card_info->fw_version >= 17) { - u8 tsin4_config[6] = { - 3072 / 64, 3072 / 64, 0, 3072 / 64, 3072 / 64, 0}; - u8 default_config[6] = { - 4096 / 64, 4096 / 64, 0, 2048 / 64, 2048 / 64, 0}; - u8 *bconf = default_config; - - if (dev->card_info->io_type[3] == NGENE_IO_TSIN) - bconf = tsin4_config; - dprintk(KERN_DEBUG DEVICE_NAME ": FW 17+ buffer config\n"); - stat = ngene_command_config_free_buf(dev, bconf); - } else { - int bconf = BUFFER_CONFIG_4422; - if (dev->card_info->io_type[3] == NGENE_IO_TSIN) - bconf = BUFFER_CONFIG_3333; - stat = ngene_command_config_buf(dev, bconf); - } if (!stat) return stat; @@ -1403,9 +1420,6 @@ fail2: return stat; } - - - /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ @@ -1422,7 +1436,12 @@ static void release_channel(struct ngene_channel *chan) tasklet_kill(&chan->demux_tasklet); + if (chan->number >= 2 && chan->number <= 3 && dev->ci.en) + return; + if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { + if (chan->ci_dev) + dvb_unregister_device(chan->ci_dev); if (chan->fe) { dvb_unregister_frontend(chan->fe); dvb_frontend_detach(chan->fe); @@ -1458,6 +1477,9 @@ static int init_channel(struct ngene_channel *chan) if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { if (nr >= STREAM_AUDIOIN1) chan->DataFormatFlags = DF_SWAP32; + + if (nr >= 2 && nr <= 3 && dev->ci.en) + return 0; if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { adapter = &dev->adapter[nr]; ret = dvb_register_adapter(adapter, "nGene", @@ -1478,6 +1500,15 @@ static int init_channel(struct ngene_channel *chan) ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, &chan->hw_frontend, &chan->mem_frontend, adapter); + if (dev->ci.en && (io&NGENE_IO_TSOUT)) { + dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); + set_transfer(chan, 1); + set_transfer(&chan->dev->channel[2], 1); + + dvb_register_device(adapter, &chan->ci_dev, + &ngene_dvbdev_ci, (void *) chan, + DVB_DEVICE_SEC); + } } if (io & NGENE_IO_TSIN) { @@ -1525,6 +1556,24 @@ static int init_channels(struct ngene *dev) return 0; } +static void cxd_attach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + ci->en = cxd2099_attach(0x40, dev, &dev->channel[0].i2c_adapter); + ci->dev = dev; + return; +} + +static void cxd_detach(struct ngene *dev) +{ + struct ngene_ci *ci = &dev->ci; + + dvb_ca_en50221_release(ci->en); + kfree(ci->en); + ci->en = 0; +} + /****************************************************************************/ /* device probe/remove calls ************************************************/ /****************************************************************************/ @@ -1537,6 +1586,8 @@ void __devexit ngene_remove(struct pci_dev *pdev) tasklet_kill(&dev->event_tasklet); for (i = MAX_STREAM - 1; i >= 0; i--) release_channel(&dev->channel[i]); + if (dev->ci.en) + cxd_detach(dev); ngene_stop(dev); ngene_release_buffers(dev); pci_set_drvdata(pdev, NULL); @@ -1572,6 +1623,13 @@ int __devinit ngene_probe(struct pci_dev *pci_dev, if (stat < 0) goto fail1; + cxd_attach(dev); + + stat = ngene_buffer_config(dev); + if (stat < 0) + goto fail1; + + dev->i2c_current_bus = -1; /* Register DVB adapters and devices for both channels */ diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c index 8bb159370c70..0b4943233166 100644 --- a/drivers/media/dvb/ngene/ngene-dvb.c +++ b/drivers/media/dvb/ngene/ngene-dvb.c @@ -47,6 +47,64 @@ /* COMMAND API interface ****************************************************/ /****************************************************************************/ +static ssize_t ts_write(struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + + if (wait_event_interruptible(dev->tsout_rbuf.queue, + dvb_ringbuffer_free + (&dev->tsout_rbuf) >= count) < 0) + return 0; + + dvb_ringbuffer_write(&dev->tsout_rbuf, buf, count); + + return count; +} + +static ssize_t ts_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + int left, avail; + + left = count; + while (left) { + if (wait_event_interruptible( + dev->tsin_rbuf.queue, + dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0) + return -EAGAIN; + avail = dvb_ringbuffer_avail(&dev->tsin_rbuf); + if (avail > left) + avail = left; + dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail); + left -= avail; + buf += avail; + } + return count; +} + +static const struct file_operations ci_fops = { + .owner = THIS_MODULE, + .read = ts_read, + .write = ts_write, + .open = dvb_generic_open, + .release = dvb_generic_release, +}; + +struct dvb_device ngene_dvbdev_ci = { + .priv = 0, + .readers = -1, + .writers = -1, + .users = -1, + .fops = &ci_fops, +}; + + /****************************************************************************/ /* DVB functions and API interface ******************************************/ /****************************************************************************/ @@ -63,11 +121,19 @@ static void swap_buffer(u32 *p, u32 len) void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; + struct ngene *dev = chan->dev; + if (flags & DF_SWAP32) + swap_buffer(buf, len); + if (dev->ci.en && chan->number == 2) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) > len) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, len); + wake_up_interruptible(&dev->tsin_rbuf.queue); + } + return 0; + } if (chan->users > 0) { - if (flags & DF_SWAP32) - swap_buffer(buf, len); dvb_dmx_swfilter(&chan->demux, buf, len); } return NULL; diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index 8fb4200f83f8..f7834066386f 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -36,8 +36,10 @@ #include "dmxdev.h" #include "dvbdev.h" #include "dvb_demux.h" +#include "dvb_ca_en50221.h" #include "dvb_frontend.h" #include "dvb_ringbuffer.h" +#include "cxd2099.h" #define DEVICE_NAME "ngene" @@ -644,6 +646,7 @@ struct ngene_channel { struct dmx_frontend mem_frontend; int users; struct video_device *v4l_dev; + struct dvb_device *ci_dev; struct tasklet_struct demux_tasklet; struct SBufferHeader *nextBuffer; @@ -710,6 +713,15 @@ struct ngene_channel { int running; }; + +struct ngene_ci { + struct device device; + struct i2c_adapter i2c_adapter; + + struct ngene *dev; + struct dvb_ca_en50221 *en; +}; + struct ngene; typedef void (rx_cb_t)(struct ngene *, u32, u8); @@ -774,6 +786,10 @@ struct ngene { #define TSOUT_BUF_SIZE (512*188*8) struct dvb_ringbuffer tsout_rbuf; + u8 *tsin_buf; +#define TSIN_BUF_SIZE (512*188*8) + struct dvb_ringbuffer tsin_rbuf; + u8 *ain_buf; #define AIN_BUF_SIZE (128*1024) struct dvb_ringbuffer ain_rbuf; @@ -785,6 +801,8 @@ struct ngene { unsigned long exp_val; int prev_cmd; + + struct ngene_ci ci; }; struct ngene_info { @@ -872,6 +890,7 @@ void FillTSBuffer(void *Buffer, int Length, u32 Flags); int ngene_i2c_init(struct ngene *dev, int dev_nr); /* Provided by ngene-dvb.c */ +extern struct dvb_device ngene_dvbdev_ci; void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags); int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed); -- cgit v1.2.2 From 1b7c41ef33f38c88dcf9a1b7544d9e4eaa045e6f Mon Sep 17 00:00:00 2001 From: Ralph Metzler Date: Mon, 10 Jan 2011 06:36:16 -0300 Subject: [media] ngene: Shutdown workaround Implement shutdown workaround for some chipsets. Signed-off-by: Ralph Metzler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-cards.c | 1 + drivers/media/dvb/ngene/ngene-core.c | 37 +++++++++++++++++++++++++++++++++++ drivers/media/dvb/ngene/ngene.h | 1 + 3 files changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 93e6f9e954ca..6d87427d214a 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -436,6 +436,7 @@ static struct pci_driver ngene_pci_driver = { .probe = ngene_probe, .remove = __devexit_p(ngene_remove), .err_handler = &ngene_errors, + .shutdown = ngene_shutdown, }; static __init int module_init_ngene(void) diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index deaf72aab058..422f83b9dca1 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -45,6 +45,10 @@ static int one_adapter = 1; module_param(one_adapter, int, 0444); MODULE_PARM_DESC(one_adapter, "Use only one adapter."); +static int shutdown_workaround; +module_param(shutdown_workaround, int, 0644); +MODULE_PARM_DESC(one_adapter, "Activate workaround for shutdown problem with some chipsets."); + static int debug; module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "Print debugging information."); @@ -1574,6 +1578,39 @@ static void cxd_detach(struct ngene *dev) ci->en = 0; } +/***********************************/ +/* workaround for shutdown failure */ +/***********************************/ + +static void ngene_unlink(struct ngene *dev) +{ + struct ngene_command com; + + com.cmd.hdr.Opcode = CMD_MEM_WRITE; + com.cmd.hdr.Length = 3; + com.cmd.MemoryWrite.address = 0x910c; + com.cmd.MemoryWrite.data = 0xff; + com.in_len = 3; + com.out_len = 1; + + down(&dev->cmd_mutex); + ngwritel(0, NGENE_INT_ENABLE); + ngene_command_mutex(dev, &com); + up(&dev->cmd_mutex); +} + +void ngene_shutdown(struct pci_dev *pdev) +{ + struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev); + + if (!dev || !shutdown_workaround) + return; + + printk(KERN_INFO DEVICE_NAME ": shutdown workaround...\n"); + ngene_unlink(dev); + pci_disable_device(pdev); +} + /****************************************************************************/ /* device probe/remove calls ************************************************/ /****************************************************************************/ diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index f7834066386f..c1bb81014fb4 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -881,6 +881,7 @@ struct ngene_buffer { int __devinit ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); void __devexit ngene_remove(struct pci_dev *pdev); +void ngene_shutdown(struct pci_dev *pdev); int ngene_command(struct ngene *dev, struct ngene_command *com); int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); void set_transfer(struct ngene_channel *chan, int state); -- cgit v1.2.2 From cce33c34937dec038567681d4755e75affed9742 Mon Sep 17 00:00:00 2001 From: Ralph Metzler Date: Mon, 10 Jan 2011 06:36:17 -0300 Subject: [media] ngene: Add net device Add dvb net device. Note that the physical address must be setup manually. Signed-off-by: Ralph Metzler Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 3 +++ drivers/media/dvb/ngene/ngene.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 422f83b9dca1..6a097e44a4a8 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1451,6 +1451,7 @@ static void release_channel(struct ngene_channel *chan) dvb_frontend_detach(chan->fe); chan->fe = NULL; } + dvb_net_release(&chan->dvbnet); dvbdemux->dmx.close(&dvbdemux->dmx); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &chan->hw_frontend); @@ -1504,6 +1505,8 @@ static int init_channel(struct ngene_channel *chan) ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, &chan->hw_frontend, &chan->mem_frontend, adapter); + ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); + if (dev->ci.en && (io&NGENE_IO_TSOUT)) { dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); set_transfer(chan, 1); diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index c1bb81014fb4..5894abd91af5 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -39,6 +39,7 @@ #include "dvb_ca_en50221.h" #include "dvb_frontend.h" #include "dvb_ringbuffer.h" +#include "dvb_net.h" #include "cxd2099.h" #define DEVICE_NAME "ngene" @@ -642,6 +643,7 @@ struct ngene_channel { struct dvb_frontend *fe; struct dmxdev dmxdev; struct dvb_demux demux; + struct dvb_net dvbnet; struct dmx_frontend hw_frontend; struct dmx_frontend mem_frontend; int users; -- cgit v1.2.2 From f164396ff54b95d709a5ee5ffc601cf9cd85f298 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:18 -0300 Subject: [media] ngene: Enable CI for Mystique SaTiX-S2 Dual (v2) Enable CI for Mystique SaTiX-S2 Dual (v2). Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-cards.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index 6d87427d214a..fcf4be901ec8 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c @@ -303,7 +303,8 @@ static struct ngene_info ngene_info_satixS2 = { static struct ngene_info ngene_info_satixS2v2 = { .type = NGENE_SIDEWINDER, .name = "Mystique SaTiX-S2 Dual (v2)", - .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN}, + .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, + NGENE_IO_TSOUT}, .demod_attach = {demod_attach_stv0900, demod_attach_stv0900, cineS2_probe, cineS2_probe}, .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, -- cgit v1.2.2 From e549bedf8fd9887529adf1a511501d4c036a2cfe Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:20 -0300 Subject: [media] ngene: Fix copy-paste error Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 6a097e44a4a8..a14b69c44cc1 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -47,7 +47,7 @@ MODULE_PARM_DESC(one_adapter, "Use only one adapter."); static int shutdown_workaround; module_param(shutdown_workaround, int, 0644); -MODULE_PARM_DESC(one_adapter, "Activate workaround for shutdown problem with some chipsets."); +MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets."); static int debug; module_param(debug, int, 0444); -- cgit v1.2.2 From 908f668bfbe4d268462352b9227bfe4cb458feb6 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:21 -0300 Subject: [media] stv090x: Fixed typos in register macros Fixed typos in register macros. Signed-off-by: Oliver Endriss Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x_reg.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x_reg.h b/drivers/media/dvb/frontends/stv090x_reg.h index 2502855dd784..93741ee14297 100644 --- a/drivers/media/dvb/frontends/stv090x_reg.h +++ b/drivers/media/dvb/frontends/stv090x_reg.h @@ -1327,10 +1327,10 @@ #define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD 8 #define STV090x_Px_NOSPLHy(__x, __y) (0xf48f - (__x - 1) * 0x200 - __y * 0x1) -#define STv090x_P1_NOSPLH0 STV090x_Px_NOSPLHy(1, 0) -#define STv090x_P1_NOSPLH1 STV090x_Px_NOSPLHy(1, 1) -#define STv090x_P2_NOSPLH0 STV090x_Px_NOSPLHy(2, 0) -#define STv090x_P2_NOSPLH1 STV090x_Px_NOSPLHy(2, 1) +#define STV090x_P1_NOSPLH0 STV090x_Px_NOSPLHy(1, 0) +#define STV090x_P1_NOSPLH1 STV090x_Px_NOSPLHy(1, 1) +#define STV090x_P2_NOSPLH0 STV090x_Px_NOSPLHy(2, 0) +#define STV090x_P2_NOSPLH1 STV090x_Px_NOSPLHy(2, 1) #define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD 0 #define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD 8 @@ -1406,7 +1406,7 @@ #define STV090x_Px_BCLC2S28(__x) (0xf49d - (__x - 1) * 0x200) #define STV090x_P1_BCLC2S28 STV090x_Px_BCLC2S28(1) -#define STV090x_P2_BCLC2S28 STV090x_Px_BCLC2S28(1) +#define STV090x_P2_BCLC2S28 STV090x_Px_BCLC2S28(2) #define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD 4 #define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD 2 #define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0 @@ -1414,7 +1414,7 @@ #define STV090x_Px_BCLC2S216A(__x) (0xf49e - (__x - 1) * 0x200) #define STV090x_P1_BCLC2S216A STV090x_Px_BCLC2S216A(1) -#define STV090x_P2_BCLC2S216A STV090x_Px_BCLC2S216A(1) +#define STV090x_P2_BCLC2S216A STV090x_Px_BCLC2S216A(2) #define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD 4 #define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD 2 #define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD 0 @@ -1422,7 +1422,7 @@ #define STV090x_Px_BCLC2S232A(__x) (0xf49f - (__x - 1) * 0x200) #define STV090x_P1_BCLC2S232A STV090x_Px_BCLC2S232A(1) -#define STV090x_P2_BCLC2S232A STV090x_Px_BCLC2S232A(1) +#define STV090x_P2_BCLC2S232A STV090x_Px_BCLC2S232A(2) #define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD 4 #define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD 2 #define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD 0 @@ -1602,7 +1602,7 @@ #define STV090x_Px_CCIACC(__x) (0xf4c4 - (__x - 1) * 0x200) #define STV090x_P1_CCIACC STV090x_Px_CCIACC(1) -#define STV090x_P2_CCIACC STV090x_Px_CCIACC(1) +#define STV090x_P2_CCIACC STV090x_Px_CCIACC(2) #define STV090x_OFFST_Px_CCI_VALUE_FIELD 0 #define STV090x_WIDTH_Px_CCI_VALUE_FIELD 8 -- cgit v1.2.2 From 179fd15a99175e8e22516edbb1894c3348842f3a Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:22 -0300 Subject: [media] stv090x: Fix losing lock in dual DVB-S2 mode Do not clear registers ACLC/BCLC in DVB-S2 mode for Cut <= 20. Otherwise, the demod could lose the lock periodically. Verified with cineS2 and Duoflex. Signed-off-by: Oliver Endriss Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index eccad06216ce..e3442a14e5b2 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -2894,10 +2894,12 @@ static int stv090x_optimize_track(struct stv090x_state *state) STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1); if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0) goto err; - if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0) - goto err; - if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0) - goto err; + if (state->internal->dev_ver >= 0x30) { + if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0) + goto err; + if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0) + goto err; + } if (state->frame_len == STV090x_LONG_FRAME) { reg = STV090x_READ_DEMOD(state, DMDMODCOD); modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD); -- cgit v1.2.2 From 3d0cef2c3c7e19a2425f8e1379a535c46427951b Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:23 -0300 Subject: [media] ngene: Improved channel initialisation and release Refactored code for channel initialisation and release: - Do not create device nodes which are not required. - Better error handling. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 109 +++++++++++++++++++---------------- drivers/media/dvb/ngene/ngene.h | 2 + 2 files changed, 60 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index a14b69c44cc1..175a0f6c2a4c 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1432,25 +1432,24 @@ static void release_channel(struct ngene_channel *chan) { struct dvb_demux *dvbdemux = &chan->demux; struct ngene *dev = chan->dev; - struct ngene_info *ni = dev->card_info; - int io = ni->io_type[chan->number]; - if (chan->dev->cmd_timeout_workaround && chan->running) + if (chan->running) set_transfer(chan, 0); tasklet_kill(&chan->demux_tasklet); - if (chan->number >= 2 && chan->number <= 3 && dev->ci.en) - return; + if (chan->ci_dev) { + dvb_unregister_device(chan->ci_dev); + chan->ci_dev = NULL; + } - if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { - if (chan->ci_dev) - dvb_unregister_device(chan->ci_dev); - if (chan->fe) { - dvb_unregister_frontend(chan->fe); - dvb_frontend_detach(chan->fe); - chan->fe = NULL; - } + if (chan->fe) { + dvb_unregister_frontend(chan->fe); + dvb_frontend_detach(chan->fe); + chan->fe = NULL; + } + + if (chan->has_demux) { dvb_net_release(&chan->dvbnet); dvbdemux->dmx.close(&dvbdemux->dmx); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, @@ -1459,9 +1458,12 @@ static void release_channel(struct ngene_channel *chan) &chan->mem_frontend); dvb_dmxdev_release(&chan->dmxdev); dvb_dmx_release(&chan->demux); + chan->has_demux = false; + } - if (chan->number == 0 || !one_adapter) - dvb_unregister_adapter(&dev->adapter[chan->number]); + if (chan->has_adapter) { + dvb_unregister_adapter(&dev->adapter[chan->number]); + chan->has_adapter = false; } } @@ -1479,12 +1481,27 @@ static int init_channel(struct ngene_channel *chan) chan->type = io; chan->mode = chan->type; /* for now only one mode */ + if (io & NGENE_IO_TSIN) { + chan->fe = NULL; + if (ni->demod_attach[nr]) { + ret = ni->demod_attach[nr](chan); + if (ret < 0) + goto err; + } + if (chan->fe && ni->tuner_attach[nr]) { + ret = ni->tuner_attach[nr](chan); + if (ret < 0) + goto err; + } + } + + if (!dev->ci.en && (io & NGENE_IO_TSOUT)) + return 0; + if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) { if (nr >= STREAM_AUDIOIN1) chan->DataFormatFlags = DF_SWAP32; - if (nr >= 2 && nr <= 3 && dev->ci.en) - return 0; if (nr == 0 || !one_adapter || dev->first_adapter == NULL) { adapter = &dev->adapter[nr]; ret = dvb_register_adapter(adapter, "nGene", @@ -1492,13 +1509,32 @@ static int init_channel(struct ngene_channel *chan) &chan->dev->pci_dev->dev, adapter_nr); if (ret < 0) - return ret; + goto err; if (dev->first_adapter == NULL) dev->first_adapter = adapter; - } else { + chan->has_adapter = true; + } else adapter = dev->first_adapter; - } + } + + if (dev->ci.en && (io & NGENE_IO_TSOUT)) { + dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); + set_transfer(chan, 1); + set_transfer(&chan->dev->channel[2], 1); + dvb_register_device(adapter, &chan->ci_dev, + &ngene_dvbdev_ci, (void *) chan, + DVB_DEVICE_SEC); + if (!chan->ci_dev) + goto err; + } + if (chan->fe) { + if (dvb_register_frontend(adapter, chan->fe) < 0) + goto err; + chan->has_demux = true; + } + + if (chan->has_demux) { ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", ngene_start_feed, ngene_stop_feed, chan); @@ -1506,45 +1542,16 @@ static int init_channel(struct ngene_channel *chan) &chan->hw_frontend, &chan->mem_frontend, adapter); ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); - - if (dev->ci.en && (io&NGENE_IO_TSOUT)) { - dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); - set_transfer(chan, 1); - set_transfer(&chan->dev->channel[2], 1); - - dvb_register_device(adapter, &chan->ci_dev, - &ngene_dvbdev_ci, (void *) chan, - DVB_DEVICE_SEC); - } } - if (io & NGENE_IO_TSIN) { - chan->fe = NULL; - if (ni->demod_attach[nr]) { - ret = ni->demod_attach[nr](chan); - if (ret < 0) - goto err_fe; - } - if (chan->fe && ni->tuner_attach[nr]) { - ret = ni->tuner_attach[nr](chan); - if (ret < 0) - goto err_fe; - } - if (chan->fe) { - if (dvb_register_frontend(adapter, chan->fe) < 0) - goto err_fe; - } - } return ret; -err_fe: +err: if (chan->fe) { dvb_frontend_detach(chan->fe); chan->fe = NULL; } -/* FIXME: this causes an oops... */ -/* release_channel(chan); */ -/* return ret; */ + release_channel(chan); return 0; } diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index 5894abd91af5..40fce9e3ae66 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h @@ -639,6 +639,8 @@ struct ngene_channel { int number; int type; int mode; + bool has_adapter; + bool has_demux; struct dvb_frontend *fe; struct dmxdev dmxdev; -- cgit v1.2.2 From 4862d6b2e23f0573ef60c784341e05e1ac0804eb Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Mon, 10 Jan 2011 06:36:24 -0300 Subject: [media] stv090x: 22kHz workaround must also be performed for the 2nd frontend 22kHz workaround must also be performed for the 2nd frontend. Signed-off-by: Oliver Endriss Signed-off-by: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index e3442a14e5b2..d3362d0407eb 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -4696,10 +4696,6 @@ static int stv090x_setup(struct dvb_frontend *fe) if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0) goto err; - /* workaround for stuck DiSEqC output */ - if (config->diseqc_envelope_mode) - stv090x_send_diseqc_burst(fe, SEC_MINI_A); - return 0; err: dprintk(FE_ERROR, 1, "I/O error"); @@ -4784,11 +4780,6 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, state->internal = temp_int->internal; state->internal->num_used++; dprintk(FE_INFO, 1, "Found Internal Structure!"); - dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", - state->device == STV0900 ? "STV0900" : "STV0903", - demod, - state->internal->dev_ver); - return &state->frontend; } else { state->internal = kmalloc(sizeof(struct stv090x_internal), GFP_KERNEL); @@ -4799,15 +4790,20 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, state->internal->i2c_adap = state->i2c; state->internal->i2c_addr = state->config->address; dprintk(FE_INFO, 1, "Create New Internal Structure!"); - } - mutex_init(&state->internal->demod_lock); - mutex_init(&state->internal->tuner_lock); + mutex_init(&state->internal->demod_lock); + mutex_init(&state->internal->tuner_lock); - if (stv090x_setup(&state->frontend) < 0) { - dprintk(FE_ERROR, 1, "Error setting up device"); - goto error; + if (stv090x_setup(&state->frontend) < 0) { + dprintk(FE_ERROR, 1, "Error setting up device"); + goto error; + } } + + /* workaround for stuck DiSEqC output */ + if (config->diseqc_envelope_mode) + stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); + dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", state->device == STV0900 ? "STV0900" : "STV0903", demod, -- cgit v1.2.2 From 8112248a1b66440f6c562c2669aba6950ef48199 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 17 Jan 2011 14:20:49 -0200 Subject: [media] Move CI cxd2099 driver to staging This driver is abusing the kernel<=>userspace API, due to the lack of a proper solution for it. A discussion were done at: http://www.mail-archive.com/linux-media@vger.kernel.org/msg22196.html But there's not a solution for it yet. So, move the driver to staging, while we don't have a final solution. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/Makefile | 5 +- drivers/media/dvb/ngene/cxd2099.c | 574 -------------------------------------- drivers/media/dvb/ngene/cxd2099.h | 32 --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/cxd2099/Kconfig | 11 + drivers/staging/cxd2099/Makefile | 5 + drivers/staging/cxd2099/TODO | 12 + drivers/staging/cxd2099/cxd2099.c | 574 ++++++++++++++++++++++++++++++++++++++ drivers/staging/cxd2099/cxd2099.h | 41 +++ 10 files changed, 650 insertions(+), 607 deletions(-) delete mode 100644 drivers/media/dvb/ngene/cxd2099.c delete mode 100644 drivers/media/dvb/ngene/cxd2099.h create mode 100644 drivers/staging/cxd2099/Kconfig create mode 100644 drivers/staging/cxd2099/Makefile create mode 100644 drivers/staging/cxd2099/TODO create mode 100644 drivers/staging/cxd2099/cxd2099.c create mode 100644 drivers/staging/cxd2099/cxd2099.h (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile index 00d12d6c4618..2bc96874d044 100644 --- a/drivers/media/dvb/ngene/Makefile +++ b/drivers/media/dvb/ngene/Makefile @@ -2,10 +2,13 @@ # Makefile for the nGene device driver # -ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o cxd2099.o +ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o obj-$(CONFIG_DVB_NGENE) += ngene.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ EXTRA_CFLAGS += -Idrivers/media/common/tuners/ + +# For the staging CI driver cxd2099 +EXTRA_CFLAGS += -Idrivers/staging/cxd2099/ diff --git a/drivers/media/dvb/ngene/cxd2099.c b/drivers/media/dvb/ngene/cxd2099.c deleted file mode 100644 index b49186c74eb3..000000000000 --- a/drivers/media/dvb/ngene/cxd2099.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * cxd2099.c: Driver for the CXD2099AR Common Interface Controller - * - * Copyright (C) 2010 DigitalDevices UG - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cxd2099.h" - -#define MAX_BUFFER_SIZE 248 - -struct cxd { - struct dvb_ca_en50221 en; - - struct i2c_adapter *i2c; - u8 adr; - u8 regs[0x23]; - u8 lastaddress; - u8 clk_reg_f; - u8 clk_reg_b; - int mode; - u32 bitrate; - int ready; - int dr; - int slot_stat; - - u8 amem[1024]; - int amem_read; - - int cammode; - struct mutex lock; -}; - -static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 data) -{ - u8 m[2] = {reg, data}; - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - printk(KERN_ERR "Failed to write to I2C register %02x@%02x!\n", - reg, adr); - return -1; - } - return 0; -} - -static int i2c_write(struct i2c_adapter *adapter, u8 adr, - u8 *data, u8 len) -{ - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - printk(KERN_ERR "Failed to write to I2C!\n"); - return -1; - } - return 0; -} - -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *val) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - printk(KERN_ERR "error in i2c_read_reg\n"); - return -1; - } - return 0; -} - -static int i2c_read(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *data, u8 n) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1 }, - {.addr = adr, .flags = I2C_M_RD, - .buf = data, .len = n } }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - printk(KERN_ERR "error in i2c_read\n"); - return -1; - } - return 0; -} - -static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n) -{ - int status; - - status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); - if (!status) { - ci->lastaddress = adr; - status = i2c_read(ci->i2c, ci->adr, 1, data, n); - } - return status; -} - -static int read_reg(struct cxd *ci, u8 reg, u8 *val) -{ - return read_block(ci, reg, val, 1); -} - - -static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) - status = i2c_read(ci->i2c, ci->adr, 3, data, n); - return status; -} - -static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) { - u8 buf[256] = {3}; - memcpy(buf+1, data, n); - status = i2c_write(ci->i2c, ci->adr, buf, n+1); - } - return status; -} - -static int read_io(struct cxd *ci, u16 address, u8 *val) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) - status = i2c_read(ci->i2c, ci->adr, 3, val, 1); - return status; -} - -static int write_io(struct cxd *ci, u16 address, u8 val) -{ - int status; - u8 addr[3] = { 2, address&0xff, address>>8 }; - u8 buf[2] = { 3, val }; - - status = i2c_write(ci->i2c, ci->adr, addr, 3); - if (!status) - status = i2c_write(ci->i2c, ci->adr, buf, 2); - - return status; -} - - -static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) -{ - int status; - - status = i2c_write_reg(ci->i2c, ci->adr, 0, reg); - if (!status && reg >= 6 && reg <= 8 && mask != 0xff) - status = i2c_read_reg(ci->i2c, ci->adr, 1, &ci->regs[reg]); - ci->regs[reg] = (ci->regs[reg]&(~mask))|val; - if (!status) { - ci->lastaddress = reg; - status = i2c_write_reg(ci->i2c, ci->adr, 1, ci->regs[reg]); - } - if (reg == 0x20) - ci->regs[reg] &= 0x7f; - return status; -} - -static int write_reg(struct cxd *ci, u8 reg, u8 val) -{ - return write_regm(ci, reg, val, 0xff); -} - -#ifdef BUFFER_MODE -static int write_block(struct cxd *ci, u8 adr, u8 *data, int n) -{ - int status; - u8 buf[256] = {1}; - - status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); - if (!status) { - ci->lastaddress = adr; - memcpy(buf+1, data, n); - status = i2c_write(ci->i2c, ci->adr, buf, n+1); - } - return status; -} -#endif - -static void set_mode(struct cxd *ci, int mode) -{ - if (mode == ci->mode) - return; - - switch (mode) { - case 0x00: /* IO mem */ - write_regm(ci, 0x06, 0x00, 0x07); - break; - case 0x01: /* ATT mem */ - write_regm(ci, 0x06, 0x02, 0x07); - break; - default: - break; - } - ci->mode = mode; -} - -static void cam_mode(struct cxd *ci, int mode) -{ - if (mode == ci->cammode) - return; - - switch (mode) { - case 0x00: - write_regm(ci, 0x20, 0x80, 0x80); - break; - case 0x01: - printk(KERN_INFO "enable cam buffer mode\n"); - /* write_reg(ci, 0x0d, 0x00); */ - /* write_reg(ci, 0x0e, 0x01); */ - write_regm(ci, 0x08, 0x40, 0x40); - /* read_reg(ci, 0x12, &dummy); */ - write_regm(ci, 0x08, 0x80, 0x80); - break; - default: - break; - } - ci->cammode = mode; -} - - - -#define CHK_ERROR(s) if ((status = s)) break - -static int init(struct cxd *ci) -{ - int status; - - mutex_lock(&ci->lock); - ci->mode = -1; - do { - CHK_ERROR(write_reg(ci, 0x00, 0x00)); - CHK_ERROR(write_reg(ci, 0x01, 0x00)); - CHK_ERROR(write_reg(ci, 0x02, 0x10)); - CHK_ERROR(write_reg(ci, 0x03, 0x00)); - CHK_ERROR(write_reg(ci, 0x05, 0xFF)); - CHK_ERROR(write_reg(ci, 0x06, 0x1F)); - CHK_ERROR(write_reg(ci, 0x07, 0x1F)); - CHK_ERROR(write_reg(ci, 0x08, 0x28)); - CHK_ERROR(write_reg(ci, 0x14, 0x20)); - - CHK_ERROR(write_reg(ci, 0x09, 0x4D)); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */ - CHK_ERROR(write_reg(ci, 0x0A, 0xA7)); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */ - - /* Sync detector */ - CHK_ERROR(write_reg(ci, 0x0B, 0x33)); - CHK_ERROR(write_reg(ci, 0x0C, 0x33)); - - CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F)); - CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b)); - CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F)); - CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f)); - - CHK_ERROR(write_reg(ci, 0x20, 0x28)); /* Integer Divider, Falling Edge, Internal Sync, */ - CHK_ERROR(write_reg(ci, 0x21, 0x00)); /* MCLKI = TICLK/8 */ - CHK_ERROR(write_reg(ci, 0x22, 0x07)); /* MCLKI = TICLK/8 */ - - - CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80)); /* Reset CAM state machine */ - - CHK_ERROR(write_regm(ci, 0x03, 0x02, 02)); /* Enable IREQA Interrupt */ - CHK_ERROR(write_reg(ci, 0x01, 0x04)); /* Enable CD Interrupt */ - CHK_ERROR(write_reg(ci, 0x00, 0x31)); /* Enable TS1,Hot Swap,Slot A */ - CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08)); /* Put TS in bypass */ - ci->cammode = -1; -#ifdef BUFFER_MODE - cam_mode(ci, 0); -#endif - } while (0); - mutex_unlock(&ci->lock); - - return 0; -} - - -static int read_attribute_mem(struct dvb_ca_en50221 *ca, - int slot, int address) -{ - struct cxd *ci = ca->data; - u8 val; - mutex_lock(&ci->lock); - set_mode(ci, 1); - read_pccard(ci, address, &val, 1); - mutex_unlock(&ci->lock); - return val; -} - - -static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, - int address, u8 value) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - set_mode(ci, 1); - write_pccard(ci, address, &value, 1); - mutex_unlock(&ci->lock); - return 0; -} - -static int read_cam_control(struct dvb_ca_en50221 *ca, - int slot, u8 address) -{ - struct cxd *ci = ca->data; - u8 val; - - mutex_lock(&ci->lock); - set_mode(ci, 0); - read_io(ci, address, &val); - mutex_unlock(&ci->lock); - return val; -} - -static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, - u8 address, u8 value) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - set_mode(ci, 0); - write_io(ci, address, value); - mutex_unlock(&ci->lock); - return 0; -} - -static int slot_reset(struct dvb_ca_en50221 *ca, int slot) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - cam_mode(ci, 0); - write_reg(ci, 0x00, 0x21); - write_reg(ci, 0x06, 0x1F); - write_reg(ci, 0x00, 0x31); - write_regm(ci, 0x20, 0x80, 0x80); - write_reg(ci, 0x03, 0x02); - ci->ready = 0; - ci->mode = -1; - { - int i; - for (i = 0; i < 100; i++) { - msleep(10); - if (ci->ready) - break; - } - } - mutex_unlock(&ci->lock); - /* msleep(500); */ - return 0; -} - -static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -{ - struct cxd *ci = ca->data; - - printk(KERN_INFO "slot_shutdown\n"); - mutex_lock(&ci->lock); - /* write_regm(ci, 0x09, 0x08, 0x08); */ - write_regm(ci, 0x20, 0x80, 0x80); - write_regm(ci, 0x06, 0x07, 0x07); - ci->mode = -1; - mutex_unlock(&ci->lock); - return 0; /* shutdown(ci); */ -} - -static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - write_regm(ci, 0x09, 0x00, 0x08); - set_mode(ci, 0); -#ifdef BUFFER_MODE - cam_mode(ci, 1); -#endif - mutex_unlock(&ci->lock); - return 0; -} - - -static int campoll(struct cxd *ci) -{ - u8 istat; - - read_reg(ci, 0x04, &istat); - if (!istat) - return 0; - write_reg(ci, 0x05, istat); - - if (istat&0x40) { - ci->dr = 1; - printk(KERN_INFO "DR\n"); - } - if (istat&0x20) - printk(KERN_INFO "WC\n"); - - if (istat&2) { - u8 slotstat; - - read_reg(ci, 0x01, &slotstat); - if (!(2&slotstat)) { - if (!ci->slot_stat) { - ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; - write_regm(ci, 0x03, 0x08, 0x08); - } - - } else { - if (ci->slot_stat) { - ci->slot_stat = 0; - write_regm(ci, 0x03, 0x00, 0x08); - printk(KERN_INFO "NO CAM\n"); - ci->ready = 0; - } - } - if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { - ci->ready = 1; - ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; - printk(KERN_INFO "READY\n"); - } - } - return 0; -} - - -static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -{ - struct cxd *ci = ca->data; - u8 slotstat; - - mutex_lock(&ci->lock); - campoll(ci); - read_reg(ci, 0x01, &slotstat); - mutex_unlock(&ci->lock); - - return ci->slot_stat; -} - -#ifdef BUFFER_MODE -static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) -{ - struct cxd *ci = ca->data; - u8 msb, lsb; - u16 len; - - mutex_lock(&ci->lock); - campoll(ci); - mutex_unlock(&ci->lock); - - printk(KERN_INFO "read_data\n"); - if (!ci->dr) - return 0; - - mutex_lock(&ci->lock); - read_reg(ci, 0x0f, &msb); - read_reg(ci, 0x10, &lsb); - len = (msb<<8)|lsb; - read_block(ci, 0x12, ebuf, len); - ci->dr = 0; - mutex_unlock(&ci->lock); - - return len; -} - -static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) -{ - struct cxd *ci = ca->data; - - mutex_lock(&ci->lock); - printk(KERN_INFO "write_data %d\n", ecount); - write_reg(ci, 0x0d, ecount>>8); - write_reg(ci, 0x0e, ecount&0xff); - write_block(ci, 0x11, ebuf, ecount); - mutex_unlock(&ci->lock); - return ecount; -} -#endif - -static struct dvb_ca_en50221 en_templ = { - .read_attribute_mem = read_attribute_mem, - .write_attribute_mem = write_attribute_mem, - .read_cam_control = read_cam_control, - .write_cam_control = write_cam_control, - .slot_reset = slot_reset, - .slot_shutdown = slot_shutdown, - .slot_ts_enable = slot_ts_enable, - .poll_slot_status = poll_slot_status, -#ifdef BUFFER_MODE - .read_data = read_data, - .write_data = write_data, -#endif - -}; - -struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, - struct i2c_adapter *i2c) -{ - struct cxd *ci = 0; - u32 bitrate = 62000000; - u8 val; - - if (i2c_read_reg(i2c, adr, 0, &val) < 0) { - printk(KERN_ERR "No CXD2099 detected at %02x\n", adr); - return 0; - } - - ci = kmalloc(sizeof(struct cxd), GFP_KERNEL); - if (!ci) - return 0; - memset(ci, 0, sizeof(*ci)); - - mutex_init(&ci->lock); - ci->i2c = i2c; - ci->adr = adr; - ci->lastaddress = 0xff; - ci->clk_reg_b = 0x4a; - ci->clk_reg_f = 0x1b; - ci->bitrate = bitrate; - - memcpy(&ci->en, &en_templ, sizeof(en_templ)); - ci->en.data = ci; - init(ci); - printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->adr); - return &ci->en; -} -EXPORT_SYMBOL(cxd2099_attach); - -MODULE_DESCRIPTION("cxd2099"); -MODULE_AUTHOR("Ralph Metzler "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/ngene/cxd2099.h b/drivers/media/dvb/ngene/cxd2099.h deleted file mode 100644 index f71b807e8bb7..000000000000 --- a/drivers/media/dvb/ngene/cxd2099.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * cxd2099.h: Driver for the CXD2099AR Common Interface Controller - * - * Copyright (C) 2010 DigitalDevices UG - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 only, as published by the Free Software Foundation. - * - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - -#ifndef _CXD2099_H_ -#define _CXD2099_H_ - -#include - -struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c); - -#endif diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 5c8fcfc42c3e..4a88e69bb9bb 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -51,6 +51,8 @@ source "drivers/staging/cx25821/Kconfig" source "drivers/staging/tm6000/Kconfig" +source "drivers/staging/cxd2099/Kconfig" + source "drivers/staging/dabusb/Kconfig" source "drivers/staging/se401/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index d53886317826..80ee49ab59de 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_VIDEO_GO7007) += go7007/ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_TM6000) += tm6000/ +obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_USB_DABUSB) += dabusb/ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_SE401) += se401/ diff --git a/drivers/staging/cxd2099/Kconfig b/drivers/staging/cxd2099/Kconfig new file mode 100644 index 000000000000..9d638c30735d --- /dev/null +++ b/drivers/staging/cxd2099/Kconfig @@ -0,0 +1,11 @@ +config DVB_CXD2099 + tristate "CXD2099AR Common Interface driver" + depends on DVB_CORE && PCI && I2C && DVB_NGENE + ---help--- + Support for the CI module found on cineS2 DVB-S2, supported by + the Micronas PCIe device driver (ngene). + + For now, data is passed through '/dev/dvb/adapterX/sec0': + - Encrypted data must be written to 'sec0'. + - Decrypted data can be read from 'sec0'. + - Setup the CAM using device 'ca0'. diff --git a/drivers/staging/cxd2099/Makefile b/drivers/staging/cxd2099/Makefile new file mode 100644 index 000000000000..72b14558c119 --- /dev/null +++ b/drivers/staging/cxd2099/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_DVB_CXD2099) += cxd2099.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ diff --git a/drivers/staging/cxd2099/TODO b/drivers/staging/cxd2099/TODO new file mode 100644 index 000000000000..375bb6f8ee2c --- /dev/null +++ b/drivers/staging/cxd2099/TODO @@ -0,0 +1,12 @@ +For now, data is passed through '/dev/dvb/adapterX/sec0': + - Encrypted data must be written to 'sec0'. + - Decrypted data can be read from 'sec0'. + - Setup the CAM using device 'ca0'. + +But this is wrong. There are some discussions about the proper way for +doing it, as seen at: + http://www.mail-archive.com/linux-media@vger.kernel.org/msg22196.html + +While there's no proper fix for it, the driver should be kept in staging. + +Patches should be submitted to: linux-media@vger.kernel.org. diff --git a/drivers/staging/cxd2099/cxd2099.c b/drivers/staging/cxd2099/cxd2099.c new file mode 100644 index 000000000000..b49186c74eb3 --- /dev/null +++ b/drivers/staging/cxd2099/cxd2099.c @@ -0,0 +1,574 @@ +/* + * cxd2099.c: Driver for the CXD2099AR Common Interface Controller + * + * Copyright (C) 2010 DigitalDevices UG + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cxd2099.h" + +#define MAX_BUFFER_SIZE 248 + +struct cxd { + struct dvb_ca_en50221 en; + + struct i2c_adapter *i2c; + u8 adr; + u8 regs[0x23]; + u8 lastaddress; + u8 clk_reg_f; + u8 clk_reg_b; + int mode; + u32 bitrate; + int ready; + int dr; + int slot_stat; + + u8 amem[1024]; + int amem_read; + + int cammode; + struct mutex lock; +}; + +static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr, + u8 reg, u8 data) +{ + u8 m[2] = {reg, data}; + struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2}; + + if (i2c_transfer(adapter, &msg, 1) != 1) { + printk(KERN_ERR "Failed to write to I2C register %02x@%02x!\n", + reg, adr); + return -1; + } + return 0; +} + +static int i2c_write(struct i2c_adapter *adapter, u8 adr, + u8 *data, u8 len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; + + if (i2c_transfer(adapter, &msg, 1) != 1) { + printk(KERN_ERR "Failed to write to I2C!\n"); + return -1; + } + return 0; +} + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, + u8 reg, u8 *val) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + + if (i2c_transfer(adapter, msgs, 2) != 2) { + printk(KERN_ERR "error in i2c_read_reg\n"); + return -1; + } + return 0; +} + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, + u8 reg, u8 *data, u8 n) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1 }, + {.addr = adr, .flags = I2C_M_RD, + .buf = data, .len = n } }; + + if (i2c_transfer(adapter, msgs, 2) != 2) { + printk(KERN_ERR "error in i2c_read\n"); + return -1; + } + return 0; +} + +static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n) +{ + int status; + + status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); + if (!status) { + ci->lastaddress = adr; + status = i2c_read(ci->i2c, ci->adr, 1, data, n); + } + return status; +} + +static int read_reg(struct cxd *ci, u8 reg, u8 *val) +{ + return read_block(ci, reg, val, 1); +} + + +static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) + status = i2c_read(ci->i2c, ci->adr, 3, data, n); + return status; +} + +static int write_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) { + u8 buf[256] = {3}; + memcpy(buf+1, data, n); + status = i2c_write(ci->i2c, ci->adr, buf, n+1); + } + return status; +} + +static int read_io(struct cxd *ci, u16 address, u8 *val) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) + status = i2c_read(ci->i2c, ci->adr, 3, val, 1); + return status; +} + +static int write_io(struct cxd *ci, u16 address, u8 val) +{ + int status; + u8 addr[3] = { 2, address&0xff, address>>8 }; + u8 buf[2] = { 3, val }; + + status = i2c_write(ci->i2c, ci->adr, addr, 3); + if (!status) + status = i2c_write(ci->i2c, ci->adr, buf, 2); + + return status; +} + + +static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask) +{ + int status; + + status = i2c_write_reg(ci->i2c, ci->adr, 0, reg); + if (!status && reg >= 6 && reg <= 8 && mask != 0xff) + status = i2c_read_reg(ci->i2c, ci->adr, 1, &ci->regs[reg]); + ci->regs[reg] = (ci->regs[reg]&(~mask))|val; + if (!status) { + ci->lastaddress = reg; + status = i2c_write_reg(ci->i2c, ci->adr, 1, ci->regs[reg]); + } + if (reg == 0x20) + ci->regs[reg] &= 0x7f; + return status; +} + +static int write_reg(struct cxd *ci, u8 reg, u8 val) +{ + return write_regm(ci, reg, val, 0xff); +} + +#ifdef BUFFER_MODE +static int write_block(struct cxd *ci, u8 adr, u8 *data, int n) +{ + int status; + u8 buf[256] = {1}; + + status = i2c_write_reg(ci->i2c, ci->adr, 0, adr); + if (!status) { + ci->lastaddress = adr; + memcpy(buf+1, data, n); + status = i2c_write(ci->i2c, ci->adr, buf, n+1); + } + return status; +} +#endif + +static void set_mode(struct cxd *ci, int mode) +{ + if (mode == ci->mode) + return; + + switch (mode) { + case 0x00: /* IO mem */ + write_regm(ci, 0x06, 0x00, 0x07); + break; + case 0x01: /* ATT mem */ + write_regm(ci, 0x06, 0x02, 0x07); + break; + default: + break; + } + ci->mode = mode; +} + +static void cam_mode(struct cxd *ci, int mode) +{ + if (mode == ci->cammode) + return; + + switch (mode) { + case 0x00: + write_regm(ci, 0x20, 0x80, 0x80); + break; + case 0x01: + printk(KERN_INFO "enable cam buffer mode\n"); + /* write_reg(ci, 0x0d, 0x00); */ + /* write_reg(ci, 0x0e, 0x01); */ + write_regm(ci, 0x08, 0x40, 0x40); + /* read_reg(ci, 0x12, &dummy); */ + write_regm(ci, 0x08, 0x80, 0x80); + break; + default: + break; + } + ci->cammode = mode; +} + + + +#define CHK_ERROR(s) if ((status = s)) break + +static int init(struct cxd *ci) +{ + int status; + + mutex_lock(&ci->lock); + ci->mode = -1; + do { + CHK_ERROR(write_reg(ci, 0x00, 0x00)); + CHK_ERROR(write_reg(ci, 0x01, 0x00)); + CHK_ERROR(write_reg(ci, 0x02, 0x10)); + CHK_ERROR(write_reg(ci, 0x03, 0x00)); + CHK_ERROR(write_reg(ci, 0x05, 0xFF)); + CHK_ERROR(write_reg(ci, 0x06, 0x1F)); + CHK_ERROR(write_reg(ci, 0x07, 0x1F)); + CHK_ERROR(write_reg(ci, 0x08, 0x28)); + CHK_ERROR(write_reg(ci, 0x14, 0x20)); + + CHK_ERROR(write_reg(ci, 0x09, 0x4D)); /* Input Mode C, BYPass Serial, TIVAL = low, MSB */ + CHK_ERROR(write_reg(ci, 0x0A, 0xA7)); /* TOSTRT = 8, Mode B (gated clock), falling Edge, Serial, POL=HIGH, MSB */ + + /* Sync detector */ + CHK_ERROR(write_reg(ci, 0x0B, 0x33)); + CHK_ERROR(write_reg(ci, 0x0C, 0x33)); + + CHK_ERROR(write_regm(ci, 0x14, 0x00, 0x0F)); + CHK_ERROR(write_reg(ci, 0x15, ci->clk_reg_b)); + CHK_ERROR(write_regm(ci, 0x16, 0x00, 0x0F)); + CHK_ERROR(write_reg(ci, 0x17, ci->clk_reg_f)); + + CHK_ERROR(write_reg(ci, 0x20, 0x28)); /* Integer Divider, Falling Edge, Internal Sync, */ + CHK_ERROR(write_reg(ci, 0x21, 0x00)); /* MCLKI = TICLK/8 */ + CHK_ERROR(write_reg(ci, 0x22, 0x07)); /* MCLKI = TICLK/8 */ + + + CHK_ERROR(write_regm(ci, 0x20, 0x80, 0x80)); /* Reset CAM state machine */ + + CHK_ERROR(write_regm(ci, 0x03, 0x02, 02)); /* Enable IREQA Interrupt */ + CHK_ERROR(write_reg(ci, 0x01, 0x04)); /* Enable CD Interrupt */ + CHK_ERROR(write_reg(ci, 0x00, 0x31)); /* Enable TS1,Hot Swap,Slot A */ + CHK_ERROR(write_regm(ci, 0x09, 0x08, 0x08)); /* Put TS in bypass */ + ci->cammode = -1; +#ifdef BUFFER_MODE + cam_mode(ci, 0); +#endif + } while (0); + mutex_unlock(&ci->lock); + + return 0; +} + + +static int read_attribute_mem(struct dvb_ca_en50221 *ca, + int slot, int address) +{ + struct cxd *ci = ca->data; + u8 val; + mutex_lock(&ci->lock); + set_mode(ci, 1); + read_pccard(ci, address, &val, 1); + mutex_unlock(&ci->lock); + return val; +} + + +static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, + int address, u8 value) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + set_mode(ci, 1); + write_pccard(ci, address, &value, 1); + mutex_unlock(&ci->lock); + return 0; +} + +static int read_cam_control(struct dvb_ca_en50221 *ca, + int slot, u8 address) +{ + struct cxd *ci = ca->data; + u8 val; + + mutex_lock(&ci->lock); + set_mode(ci, 0); + read_io(ci, address, &val); + mutex_unlock(&ci->lock); + return val; +} + +static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, + u8 address, u8 value) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + set_mode(ci, 0); + write_io(ci, address, value); + mutex_unlock(&ci->lock); + return 0; +} + +static int slot_reset(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + cam_mode(ci, 0); + write_reg(ci, 0x00, 0x21); + write_reg(ci, 0x06, 0x1F); + write_reg(ci, 0x00, 0x31); + write_regm(ci, 0x20, 0x80, 0x80); + write_reg(ci, 0x03, 0x02); + ci->ready = 0; + ci->mode = -1; + { + int i; + for (i = 0; i < 100; i++) { + msleep(10); + if (ci->ready) + break; + } + } + mutex_unlock(&ci->lock); + /* msleep(500); */ + return 0; +} + +static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + printk(KERN_INFO "slot_shutdown\n"); + mutex_lock(&ci->lock); + /* write_regm(ci, 0x09, 0x08, 0x08); */ + write_regm(ci, 0x20, 0x80, 0x80); + write_regm(ci, 0x06, 0x07, 0x07); + ci->mode = -1; + mutex_unlock(&ci->lock); + return 0; /* shutdown(ci); */ +} + +static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + write_regm(ci, 0x09, 0x00, 0x08); + set_mode(ci, 0); +#ifdef BUFFER_MODE + cam_mode(ci, 1); +#endif + mutex_unlock(&ci->lock); + return 0; +} + + +static int campoll(struct cxd *ci) +{ + u8 istat; + + read_reg(ci, 0x04, &istat); + if (!istat) + return 0; + write_reg(ci, 0x05, istat); + + if (istat&0x40) { + ci->dr = 1; + printk(KERN_INFO "DR\n"); + } + if (istat&0x20) + printk(KERN_INFO "WC\n"); + + if (istat&2) { + u8 slotstat; + + read_reg(ci, 0x01, &slotstat); + if (!(2&slotstat)) { + if (!ci->slot_stat) { + ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; + write_regm(ci, 0x03, 0x08, 0x08); + } + + } else { + if (ci->slot_stat) { + ci->slot_stat = 0; + write_regm(ci, 0x03, 0x00, 0x08); + printk(KERN_INFO "NO CAM\n"); + ci->ready = 0; + } + } + if (istat&8 && ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) { + ci->ready = 1; + ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY; + printk(KERN_INFO "READY\n"); + } + } + return 0; +} + + +static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) +{ + struct cxd *ci = ca->data; + u8 slotstat; + + mutex_lock(&ci->lock); + campoll(ci); + read_reg(ci, 0x01, &slotstat); + mutex_unlock(&ci->lock); + + return ci->slot_stat; +} + +#ifdef BUFFER_MODE +static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) +{ + struct cxd *ci = ca->data; + u8 msb, lsb; + u16 len; + + mutex_lock(&ci->lock); + campoll(ci); + mutex_unlock(&ci->lock); + + printk(KERN_INFO "read_data\n"); + if (!ci->dr) + return 0; + + mutex_lock(&ci->lock); + read_reg(ci, 0x0f, &msb); + read_reg(ci, 0x10, &lsb); + len = (msb<<8)|lsb; + read_block(ci, 0x12, ebuf, len); + ci->dr = 0; + mutex_unlock(&ci->lock); + + return len; +} + +static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount) +{ + struct cxd *ci = ca->data; + + mutex_lock(&ci->lock); + printk(KERN_INFO "write_data %d\n", ecount); + write_reg(ci, 0x0d, ecount>>8); + write_reg(ci, 0x0e, ecount&0xff); + write_block(ci, 0x11, ebuf, ecount); + mutex_unlock(&ci->lock); + return ecount; +} +#endif + +static struct dvb_ca_en50221 en_templ = { + .read_attribute_mem = read_attribute_mem, + .write_attribute_mem = write_attribute_mem, + .read_cam_control = read_cam_control, + .write_cam_control = write_cam_control, + .slot_reset = slot_reset, + .slot_shutdown = slot_shutdown, + .slot_ts_enable = slot_ts_enable, + .poll_slot_status = poll_slot_status, +#ifdef BUFFER_MODE + .read_data = read_data, + .write_data = write_data, +#endif + +}; + +struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, + struct i2c_adapter *i2c) +{ + struct cxd *ci = 0; + u32 bitrate = 62000000; + u8 val; + + if (i2c_read_reg(i2c, adr, 0, &val) < 0) { + printk(KERN_ERR "No CXD2099 detected at %02x\n", adr); + return 0; + } + + ci = kmalloc(sizeof(struct cxd), GFP_KERNEL); + if (!ci) + return 0; + memset(ci, 0, sizeof(*ci)); + + mutex_init(&ci->lock); + ci->i2c = i2c; + ci->adr = adr; + ci->lastaddress = 0xff; + ci->clk_reg_b = 0x4a; + ci->clk_reg_f = 0x1b; + ci->bitrate = bitrate; + + memcpy(&ci->en, &en_templ, sizeof(en_templ)); + ci->en.data = ci; + init(ci); + printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->adr); + return &ci->en; +} +EXPORT_SYMBOL(cxd2099_attach); + +MODULE_DESCRIPTION("cxd2099"); +MODULE_AUTHOR("Ralph Metzler "); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/cxd2099/cxd2099.h b/drivers/staging/cxd2099/cxd2099.h new file mode 100644 index 000000000000..a313dc26b962 --- /dev/null +++ b/drivers/staging/cxd2099/cxd2099.h @@ -0,0 +1,41 @@ +/* + * cxd2099.h: Driver for the CXD2099AR Common Interface Controller + * + * Copyright (C) 2010 DigitalDevices UG + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 only, as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +#ifndef _CXD2099_H_ +#define _CXD2099_H_ + +#include + +#if defined(CONFIG_DVB_CXD2099) || \ + (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE)) +struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c); +#else +struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif -- cgit v1.2.2 From dbf05b279b8ed398a8e92b0c1187882f6df2bf7f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 17 Jan 2011 22:18:02 -0200 Subject: [media] ngene: Fix compilation when cxd2099 is not enabled drivers/media/dvb/ngene/ngene-i2c.o: In function `cxd2099_attach': ngene-i2c.c:(.text+0x195): multiple definition of `cxd2099_attach' drivers/media/dvb/ngene/ngene-core.o:ngene-core.c:(.text+0x100): first defined here drivers/media/dvb/ngene/ngene-cards.o: In function `cxd2099_attach': ngene-cards.c:(.text+0x116): multiple definition of `cxd2099_attach' drivers/media/dvb/ngene/ngene-core.o:ngene-core.c:(.text+0x100): first defined here drivers/media/dvb/ngene/ngene-dvb.o: In function `cxd2099_attach': ngene-dvb.c:(.text+0x7ad): multiple definition of `cxd2099_attach' drivers/media/dvb/ngene/ngene-core.o:ngene-core.c:(.text+0x100): first defined here Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/cxd2099/cxd2099.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/cxd2099/cxd2099.h b/drivers/staging/cxd2099/cxd2099.h index a313dc26b962..bed54ff3e30b 100644 --- a/drivers/staging/cxd2099/cxd2099.h +++ b/drivers/staging/cxd2099/cxd2099.h @@ -31,7 +31,7 @@ (defined(CONFIG_DVB_CXD2099_MODULE) && defined(MODULE)) struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c); #else -struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c) +static inline struct dvb_ca_en50221 *cxd2099_attach(u8 adr, void *priv, struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; -- cgit v1.2.2 From e007a32526e9c5fc2746f0b84a32d3355f129634 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Wed, 19 Jan 2011 13:02:29 -0200 Subject: [media] v4l: vivi: port to videobuf2 Make vivi use videobuf2 in place of videobuf. Signed-off-by: Pawel Osciak Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 +- drivers/media/video/vivi.c | 357 ++++++++++++++++++++++++-------------------- 2 files changed, 200 insertions(+), 159 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index f86e407c2218..d40a8fc01bfd 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -549,7 +549,7 @@ config VIDEO_VIVI depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE select FONT_8x16 - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC default n ---help--- Enables a virtual video driver. This device shows a color bar diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index c49c39386bd0..9ed3831b34bd 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -7,6 +7,9 @@ * John Sokol * http://v4l.videotechnology.com/ * + * Conversion to videobuf2 by Pawel Osciak & Marek Szyprowski + * Copyright (c) 2010 Samsung Electronics + * * This program is free software; you can redistribute it and/or modify * it under the terms of the BSD Licence, GNU General Public License * as published by the Free Software Foundation; either version 2 of the @@ -23,10 +26,8 @@ #include #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) #include -#endif -#include +#include #include #include #include @@ -42,7 +43,7 @@ #define MAX_HEIGHT 1200 #define VIVI_MAJOR_VERSION 0 -#define VIVI_MINOR_VERSION 7 +#define VIVI_MINOR_VERSION 8 #define VIVI_RELEASE 0 #define VIVI_VERSION \ KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) @@ -133,16 +134,11 @@ static struct vivi_fmt *get_format(struct v4l2_format *f) return &formats[k]; } -struct sg_to_addr { - int pos; - struct scatterlist *sg; -}; - /* buffer for one video frame */ struct vivi_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - + struct vb2_buffer vb; + struct list_head list; struct vivi_fmt *fmt; }; @@ -190,9 +186,11 @@ struct vivi_dev { /* video capture */ struct vivi_fmt *fmt; unsigned int width, height; - struct videobuf_queue vb_vidq; + struct vb2_queue vb_vidq; + enum v4l2_field field; + unsigned int field_count; - unsigned long generating; + unsigned int open_count; u8 bars[9][3]; u8 line[MAX_WIDTH * 4]; }; @@ -443,10 +441,10 @@ static void gen_text(struct vivi_dev *dev, char *basep, static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) { - int hmax = buf->vb.height; - int wmax = buf->vb.width; + int wmax = dev->width; + int hmax = dev->height; struct timeval ts; - void *vbuf = videobuf_to_vmalloc(&buf->vb); + void *vbuf = vb2_plane_vaddr(&buf->vb, 0); unsigned ms; char str[100]; int h, line = 1; @@ -483,11 +481,11 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) dev->mv_count += 2; - /* Advice that buffer was filled */ - buf->vb.field_count++; + buf->vb.v4l2_buf.field = dev->field; + dev->field_count++; + buf->vb.v4l2_buf.sequence = dev->field_count >> 1; do_gettimeofday(&ts); - buf->vb.ts = ts; - buf->vb.state = VIDEOBUF_DONE; + buf->vb.v4l2_buf.timestamp = ts; } static void vivi_thread_tick(struct vivi_dev *dev) @@ -504,23 +502,17 @@ static void vivi_thread_tick(struct vivi_dev *dev) goto unlock; } - buf = list_entry(dma_q->active.next, - struct vivi_buffer, vb.queue); - - /* Nobody is waiting on this buffer, return */ - if (!waitqueue_active(&buf->vb.done)) - goto unlock; + buf = list_entry(dma_q->active.next, struct vivi_buffer, list); + list_del(&buf->list); - list_del(&buf->vb.queue); - - do_gettimeofday(&buf->vb.ts); + do_gettimeofday(&buf->vb.v4l2_buf.timestamp); /* Fill buffer */ vivi_fillbuff(dev, buf); dprintk(dev, 1, "filled buffer %p\n", buf); - wake_up(&buf->vb.done); - dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); unlock: spin_unlock_irqrestore(&dev->slock, flags); } @@ -571,17 +563,12 @@ static int vivi_thread(void *data) return 0; } -static void vivi_start_generating(struct file *file) +static int vivi_start_generating(struct vivi_dev *dev) { - struct vivi_dev *dev = video_drvdata(file); struct vivi_dmaqueue *dma_q = &dev->vidq; dprintk(dev, 1, "%s\n", __func__); - if (test_and_set_bit(0, &dev->generating)) - return; - file->private_data = dev; - /* Resets frame counters */ dev->ms = 0; dev->mv_count = 0; @@ -593,146 +580,200 @@ static void vivi_start_generating(struct file *file) if (IS_ERR(dma_q->kthread)) { v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - clear_bit(0, &dev->generating); - return; + return PTR_ERR(dma_q->kthread); } /* Wakes thread */ wake_up_interruptible(&dma_q->wq); dprintk(dev, 1, "returning from %s\n", __func__); + return 0; } -static void vivi_stop_generating(struct file *file) +static void vivi_stop_generating(struct vivi_dev *dev) { - struct vivi_dev *dev = video_drvdata(file); struct vivi_dmaqueue *dma_q = &dev->vidq; dprintk(dev, 1, "%s\n", __func__); - if (!file->private_data) - return; - if (!test_and_clear_bit(0, &dev->generating)) - return; - /* shutdown control thread */ if (dma_q->kthread) { kthread_stop(dma_q->kthread); dma_q->kthread = NULL; } - videobuf_stop(&dev->vb_vidq); - videobuf_mmap_free(&dev->vb_vidq); -} -static int vivi_is_generating(struct vivi_dev *dev) -{ - return test_bit(0, &dev->generating); + /* + * Typical driver might need to wait here until dma engine stops. + * In this case we can abort imiedetly, so it's just a noop. + */ + + /* Release all active buffers */ + while (!list_empty(&dma_q->active)) { + struct vivi_buffer *buf; + buf = list_entry(dma_q->active.next, struct vivi_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); + } } - /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/ -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) +static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned long sizes[], + void *alloc_ctxs[]) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vq); + unsigned long size; + + size = dev->width * dev->height * 2; - *size = dev->width * dev->height * 2; + if (0 == *nbuffers) + *nbuffers = 32; - if (0 == *count) - *count = 32; + while (size * *nbuffers > vid_limit * 1024 * 1024) + (*nbuffers)--; - while (*size * *count > vid_limit * 1024 * 1024) - (*count)--; + *nplanes = 1; - dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, - *count, *size); + sizes[0] = size; + + /* + * videobuf2-vmalloc allocator is context-less so no need to set + * alloc_ctxs array. + */ + + dprintk(dev, 1, "%s, count=%d, size=%ld\n", __func__, + *nbuffers, size); return 0; } -static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) +static int buffer_init(struct vb2_buffer *vb) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state); + BUG_ON(NULL == dev->fmt); - videobuf_vmalloc_free(&buf->vb); - dprintk(dev, 1, "free_buffer: freed\n"); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + /* + * This callback is called once per buffer, after its allocation. + * + * Vivi does not allow changing format during streaming, but it is + * possible to do so when streaming is paused (i.e. in streamoff state). + * Buffers however are not freed when going into streamoff and so + * buffer size verification has to be done in buffer_prepare, on each + * qbuf. + * It would be best to move verification code here to buf_init and + * s_fmt though. + */ + + return 0; } -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) +static int buffer_prepare(struct vb2_buffer *vb) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); - int rc; + unsigned long size; - dprintk(dev, 1, "%s, field=%d\n", __func__, field); + dprintk(dev, 1, "%s, field=%d\n", __func__, vb->v4l2_buf.field); BUG_ON(NULL == dev->fmt); + /* + * Theses properties only change when queue is idle, see s_fmt. + * The below checks should not be performed here, on each + * buffer_prepare (i.e. on each qbuf). Most of the code in this function + * should thus be moved to buffer_init and s_fmt. + */ if (dev->width < 48 || dev->width > MAX_WIDTH || dev->height < 32 || dev->height > MAX_HEIGHT) return -EINVAL; - buf->vb.size = dev->width * dev->height * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + size = dev->width * dev->height * 2; + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb, 0, size); - /* These properties only change when queue is idle, see s_fmt */ - buf->fmt = dev->fmt; - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; + buf->fmt = dev->fmt; precalculate_bars(dev); precalculate_line(dev); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } + return 0; +} - buf->vb.state = VIDEOBUF_PREPARED; +static int buffer_finish(struct vb2_buffer *vb) +{ + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + dprintk(dev, 1, "%s\n", __func__); return 0; +} + +static void buffer_cleanup(struct vb2_buffer *vb) +{ + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + dprintk(dev, 1, "%s\n", __func__); -fail: - free_buffer(vq, buf); - return rc; } -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - struct vivi_dev *dev = vq->priv_data; + struct vivi_dev *dev = vb2_get_drv_priv(vb->vb2_queue); struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_dmaqueue *vidq = &dev->vidq; + unsigned long flags = 0; dprintk(dev, 1, "%s\n", __func__); - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->list, &vidq->active); + spin_unlock_irqrestore(&dev->slock, flags); } -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static int start_streaming(struct vb2_queue *vq) { - struct vivi_dev *dev = vq->priv_data; - struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); + struct vivi_dev *dev = vb2_get_drv_priv(vq); + dprintk(dev, 1, "%s\n", __func__); + return vivi_start_generating(dev); +} +/* abort streaming and wait for last buffer */ +static int stop_streaming(struct vb2_queue *vq) +{ + struct vivi_dev *dev = vb2_get_drv_priv(vq); dprintk(dev, 1, "%s\n", __func__); + vivi_stop_generating(dev); + return 0; +} + +static void vivi_lock(struct vb2_queue *vq) +{ + struct vivi_dev *dev = vb2_get_drv_priv(vq); + mutex_lock(&dev->mutex); +} - free_buffer(vq, buf); +static void vivi_unlock(struct vb2_queue *vq) +{ + struct vivi_dev *dev = vb2_get_drv_priv(vq); + mutex_unlock(&dev->mutex); } -static struct videobuf_queue_ops vivi_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, + +static struct vb2_ops vivi_video_qops = { + .queue_setup = queue_setup, + .buf_init = buffer_init, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_cleanup = buffer_cleanup, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vivi_unlock, + .wait_finish = vivi_lock, }; /* ------------------------------------------------------------------ @@ -774,7 +815,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; - f->fmt.pix.field = dev->vb_vidq.field; + f->fmt.pix.field = dev->field; f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3; @@ -820,82 +861,60 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivi_dev *dev = video_drvdata(file); + struct vb2_queue *q = &dev->vb_vidq; int ret = vidioc_try_fmt_vid_cap(file, priv, f); if (ret < 0) return ret; - if (vivi_is_generating(dev)) { + if (vb2_is_streaming(q)) { dprintk(dev, 1, "%s device busy\n", __func__); - ret = -EBUSY; - goto out; + return -EBUSY; } dev->fmt = get_format(f); dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; - dev->vb_vidq.field = f->fmt.pix.field; - ret = 0; -out: - return ret; + dev->field = f->fmt.pix.field; + + return 0; } static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { struct vivi_dev *dev = video_drvdata(file); - - return videobuf_reqbufs(&dev->vb_vidq, p); + return vb2_reqbufs(&dev->vb_vidq, p); } static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct vivi_dev *dev = video_drvdata(file); - - return videobuf_querybuf(&dev->vb_vidq, p); + return vb2_querybuf(&dev->vb_vidq, p); } static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct vivi_dev *dev = video_drvdata(file); - - return videobuf_qbuf(&dev->vb_vidq, p); + return vb2_qbuf(&dev->vb_vidq, p); } static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct vivi_dev *dev = video_drvdata(file); - - return videobuf_dqbuf(&dev->vb_vidq, p, - file->f_flags & O_NONBLOCK); + return vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK); } static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_dev *dev = video_drvdata(file); - int ret; - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - ret = videobuf_streamon(&dev->vb_vidq); - if (ret) - return ret; - - vivi_start_generating(file); - return 0; + return vb2_streamon(&dev->vb_vidq, i); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct vivi_dev *dev = video_drvdata(file); - int ret; - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - ret = videobuf_streamoff(&dev->vb_vidq); - if (!ret) - vivi_stop_generating(file); - return ret; + return vb2_streamoff(&dev->vb_vidq, i); } static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) @@ -1018,26 +1037,33 @@ static int vidioc_s_ctrl(struct file *file, void *priv, File operations for the device ------------------------------------------------------------------*/ +static int vivi_open(struct file *file) +{ + struct vivi_dev *dev = video_drvdata(file); + + dprintk(dev, 1, "%s, %p\n", __func__, file); + dev->open_count++; + return 0; +} + static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct vivi_dev *dev = video_drvdata(file); - vivi_start_generating(file); - return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); + dprintk(dev, 1, "read called\n"); + return vb2_read(&dev->vb_vidq, data, count, ppos, + file->f_flags & O_NONBLOCK); } static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_dev *dev = video_drvdata(file); - struct videobuf_queue *q = &dev->vb_vidq; + struct vb2_queue *q = &dev->vb_vidq; dprintk(dev, 1, "%s\n", __func__); - - vivi_start_generating(file); - return videobuf_poll_stream(file, q, wait); + return vb2_poll(q, file, wait); } static int vivi_close(struct file *file) @@ -1045,10 +1071,11 @@ static int vivi_close(struct file *file) struct video_device *vdev = video_devdata(file); struct vivi_dev *dev = video_drvdata(file); - vivi_stop_generating(file); + dprintk(dev, 1, "close called (dev=%s), file %p\n", + video_device_node_name(vdev), file); - dprintk(dev, 1, "close called (dev=%s)\n", - video_device_node_name(vdev)); + if (--dev->open_count == 0) + vb2_queue_release(&dev->vb_vidq); return 0; } @@ -1059,8 +1086,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma) dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - ret = videobuf_mmap_mapper(&dev->vb_vidq, vma); - + ret = vb2_mmap(&dev->vb_vidq, vma); dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, @@ -1070,6 +1096,7 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma) static const struct v4l2_file_operations vivi_fops = { .owner = THIS_MODULE, + .open = vivi_open, .release = vivi_close, .read = vivi_read, .poll = vivi_poll, @@ -1136,6 +1163,7 @@ static int __init vivi_create_instance(int inst) { struct vivi_dev *dev; struct video_device *vfd; + struct vb2_queue *q; int ret; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1159,12 +1187,20 @@ static int __init vivi_create_instance(int inst) /* initialize locks */ spin_lock_init(&dev->slock); - mutex_init(&dev->mutex); - videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops, - NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct vivi_buffer), dev, &dev->mutex); + /* initialize queue */ + q = &dev->vb_vidq; + memset(q, 0, sizeof(dev->vb_vidq)); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivi_buffer); + q->ops = &vivi_video_qops; + q->mem_ops = &vb2_vmalloc_memops; + + vb2_queue_init(q); + + mutex_init(&dev->mutex); /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); @@ -1178,6 +1214,11 @@ static int __init vivi_create_instance(int inst) *vfd = vivi_template; vfd->debug = debug; vfd->v4l2_dev = &dev->v4l2_dev; + + /* + * Provide a mutex to v4l2 core. It will be used to protect + * all fops and v4l2 ioctls. + */ vfd->lock = &dev->mutex; ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); -- cgit v1.2.2 From 0cda12556bf3ebe47ee98eb6767a085c204ee35e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Jan 2011 16:05:30 -0200 Subject: [media] tuner-simple: add support for Tena TNF5337 MFD Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tuner-types.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 58a513bcd747..afba6dc5e080 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c @@ -971,6 +971,22 @@ static struct tuner_params tuner_tena_9533_di_params[] = { }, }; +/* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */ + +static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = { + { 16 * 166.25 /*MHz*/, 0x86, 0x01, }, + { 16 * 466.25 /*MHz*/, 0x86, 0x02, }, + { 16 * 999.99 , 0x86, 0x08, }, +}; + +static struct tuner_params tuner_tena_tnf_5337_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tena_tnf_5337_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges), + }, +}; + /* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { @@ -1842,6 +1858,11 @@ struct tunertype tuners[] = { .params = tuner_philips_fq1236_mk5_params, .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), }, + [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */ + .name = "Tena TNF5337 MFD", + .params = tuner_tena_tnf_5337_params, + .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), + }, }; EXPORT_SYMBOL(tuners); -- cgit v1.2.2 From 99fb079aad031712283d555aa87251706aa60212 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Jan 2011 16:11:58 -0200 Subject: [media] saa7134: Properly report when a board doesn't have eeprom When a device is not detected, the driver prints a warning message. That's ok, except for the fact that, even on newer devices that have eeprom but aren't yet supported, it prints a message saying that the device doesn't have eeprom. Fix it by having a separate message for devices with eeprom, but not yet known by the driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-core.c | 35 ++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 6abeecff6da7..41f836fc93ec 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -752,19 +752,28 @@ static int saa7134_hwfini(struct saa7134_dev *dev) return 0; } -static void __devinit must_configure_manually(void) +static void __devinit must_configure_manually(int has_eeprom) { unsigned int i,p; - printk(KERN_WARNING - "saa7134: \n" - "saa7134: Congratulations! Your TV card vendor saved a few\n" - "saa7134: cents for a eeprom, thus your pci board has no\n" - "saa7134: subsystem ID and I can't identify it automatically\n" - "saa7134: \n" - "saa7134: I feel better now. Ok, here are the good news:\n" - "saa7134: You can use the card= insmod option to specify\n" - "saa7134: which board do you have. The list:\n"); + if (!has_eeprom) + printk(KERN_WARNING + "saa7134: \n" + "saa7134: Congratulations! Your TV card vendor saved a few\n" + "saa7134: cents for a eeprom, thus your pci board has no\n" + "saa7134: subsystem ID and I can't identify it automatically\n" + "saa7134: \n" + "saa7134: I feel better now. Ok, here are the good news:\n" + "saa7134: You can use the card= insmod option to specify\n" + "saa7134: which board do you have. The list:\n"); + else + printk(KERN_WARNING + "saa7134: Board is currently unknown. You might try to use the card=\n" + "saa7134: insmod option to specify which board do you have, but this is\n" + "saa7134: somewhat risky, as might damage your card. It is better to ask\n" + "saa7134: for support at linux-media@vger.kernel.org.\n" + "saa7134: The supported cards are:\n"); + for (i = 0; i < saa7134_bcount; i++) { printk(KERN_WARNING "saa7134: card=%d -> %-40.40s", i,saa7134_boards[i].name); @@ -936,8 +945,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, if (card[dev->nr] >= 0 && card[dev->nr] < saa7134_bcount) dev->board = card[dev->nr]; - if (SAA7134_BOARD_NOAUTO == dev->board) { - must_configure_manually(); + if (SAA7134_BOARD_UNKNOWN == dev->board) + must_configure_manually(0); + else if (SAA7134_BOARD_NOAUTO == dev->board) { + must_configure_manually(1); dev->board = SAA7134_BOARD_UNKNOWN; } dev->autodetected = card[dev->nr] != dev->board; -- cgit v1.2.2 From d642f2f3c5be4737ec021c6d6e9cda99262564f8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Jan 2011 16:25:17 -0200 Subject: [media] add support for Encore FM3 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-cards.c | 39 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 1 + drivers/media/video/saa7134/saa7134.h | 1 + 3 files changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index deb8fcf4aa49..74467c18e69a 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -3620,6 +3620,38 @@ struct saa7134_board saa7134_boards[] = { .amux = 0, }, }, + [SAA7134_BOARD_ENCORE_ENLTV_FM3] = { + .name = "Encore ENLTV-FM 3", + .audio_clock = 0x02187de7, + .tuner_type = TUNER_TENA_TNF_5337, + .radio_type = TUNER_TEA5767, + .tuner_addr = 0x61, + .radio_addr = 0x60, + .inputs = { { + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .vmux = 1, + .amux = LINE1, + }, + .mute = { + .name = name_mute, + .amux = LINE1, + .gpio = 0x43000, + }, + }, [SAA7134_BOARD_CINERGY_HT_PCI] = { .name = "Terratec Cinergy HT PCI", .audio_clock = 0x00187de7, @@ -6385,6 +6417,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x1a7f, .subdevice = 0x2008, .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM53, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1a7f, + .subdevice = 0x2108, + .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM3, }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -7102,6 +7140,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_ENCORE_ENLTV: case SAA7134_BOARD_ENCORE_ENLTV_FM: case SAA7134_BOARD_ENCORE_ENLTV_FM53: + case SAA7134_BOARD_ENCORE_ENLTV_FM3: case SAA7134_BOARD_10MOONSTVMASTER3: case SAA7134_BOARD_BEHOLD_401: case SAA7134_BOARD_BEHOLD_403: diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index dc646e65edb7..c9eff0336aa6 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -681,6 +681,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) polling = 50; // ms break; case SAA7134_BOARD_ENCORE_ENLTV_FM53: + case SAA7134_BOARD_ENCORE_ENLTV_FM3: ir_codes = RC_MAP_ENCORE_ENLTV_FM53; mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */ mask_keyup = 0x0040000; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 5b0a347b0b8f..f96cd5d761f9 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -327,6 +327,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181 #define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182 #define SAA7134_BOARD_VIDEOMATE_M1F 183 +#define SAA7134_BOARD_ENCORE_ENLTV_FM3 184 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.2 From 1f075d1f1bfb7101be9a651a4d087193b4f05b23 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Nov 2010 22:31:40 -0200 Subject: [media] technisat-usb2: CodingStyle cleanups Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/technisat-usb2.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c index 10151aa49239..08f8842ad280 100644 --- a/drivers/media/dvb/dvb-usb/technisat-usb2.c +++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c @@ -331,11 +331,10 @@ static int technisat_usb2_identify_state(struct usb_device *udev, u8 version[3]; /* first select the interface */ - if (usb_set_interface(udev, 0, 1) != 0) { + if (usb_set_interface(udev, 0, 1) != 0) err("could not set alternate setting to 0"); - } else { + else info("set alternate setting"); - } *cold = 0; /* by default do not download a firmware - just in case something is wrong */ @@ -378,7 +377,7 @@ static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d) { u8 reg; u8 b[16]; - int i,j; + int i, j; /* full EEPROM dump */ for (j = 0; j < 256 * 4; j += 16) { @@ -496,9 +495,9 @@ static struct stv090x_config technisat_usb2_stv090x_config = { }; static struct stv6110x_config technisat_usb2_stv6110x_config = { - .addr = 0x60, - .refclk = 16000000, - .clk_div = 2, + .addr = 0x60, + .refclk = 16000000, + .clk_div = 2, }; static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) -- cgit v1.2.2 From 34a078da8e20ca40a09bfa635ff2c4e2c4b648b1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 07:53:28 -0300 Subject: [media] cs5345: use the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cs5345.c | 87 ++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index 9358fe77e562..5909f2557ab4 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -25,6 +25,7 @@ #include #include #include +#include MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); MODULE_AUTHOR("Hans Verkuil"); @@ -36,6 +37,20 @@ module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); +struct cs5345_state { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; +}; + +static inline struct cs5345_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct cs5345_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct cs5345_state, hdl)->sd; +} /* ----------------------------------------------------------------------- */ @@ -65,33 +80,20 @@ static int cs5345_s_routing(struct v4l2_subdev *sd, return 0; } -static int cs5345_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl) { - if (ctrl->id == V4L2_CID_AUDIO_MUTE) { - ctrl->value = (cs5345_read(sd, 0x04) & 0x08) != 0; - return 0; - } - if (ctrl->id != V4L2_CID_AUDIO_VOLUME) - return -EINVAL; - ctrl->value = cs5345_read(sd, 0x07) & 0x3f; - if (ctrl->value >= 32) - ctrl->value = ctrl->value - 64; - return 0; -} + struct v4l2_subdev *sd = to_sd(ctrl); -static int cs5345_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - if (ctrl->id == V4L2_CID_AUDIO_MUTE) { - cs5345_write(sd, 0x04, ctrl->value ? 0x80 : 0); + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + cs5345_write(sd, 0x04, ctrl->val ? 0x80 : 0); + return 0; + case V4L2_CID_AUDIO_VOLUME: + cs5345_write(sd, 0x07, ((u8)ctrl->val) & 0x3f); + cs5345_write(sd, 0x08, ((u8)ctrl->val) & 0x3f); return 0; } - if (ctrl->id != V4L2_CID_AUDIO_VOLUME) - return -EINVAL; - if (ctrl->value > 24 || ctrl->value < -24) - return -EINVAL; - cs5345_write(sd, 0x07, ((u8)ctrl->value) & 0x3f); - cs5345_write(sd, 0x08, ((u8)ctrl->value) & 0x3f); - return 0; + return -EINVAL; } #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -144,11 +146,20 @@ static int cs5345_log_status(struct v4l2_subdev *sd) /* ----------------------------------------------------------------------- */ +static const struct v4l2_ctrl_ops cs5345_ctrl_ops = { + .s_ctrl = cs5345_s_ctrl, +}; + static const struct v4l2_subdev_core_ops cs5345_core_ops = { .log_status = cs5345_log_status, .g_chip_ident = cs5345_g_chip_ident, - .g_ctrl = cs5345_g_ctrl, - .s_ctrl = cs5345_s_ctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = cs5345_g_register, .s_register = cs5345_s_register, @@ -169,6 +180,7 @@ static const struct v4l2_subdev_ops cs5345_ops = { static int cs5345_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct cs5345_state *state; struct v4l2_subdev *sd; /* Check if the adapter supports the needed features */ @@ -178,11 +190,28 @@ static int cs5345_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); - if (sd == NULL) + state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL); + if (state == NULL) return -ENOMEM; + sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &cs5345_ops); + v4l2_ctrl_handler_init(&state->hdl, 2); + v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, -24, 24, 1, 0); + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + /* set volume/mute */ + v4l2_ctrl_handler_setup(&state->hdl); + cs5345_write(sd, 0x02, 0x00); cs5345_write(sd, 0x04, 0x01); cs5345_write(sd, 0x09, 0x01); @@ -194,9 +223,11 @@ static int cs5345_probe(struct i2c_client *client, static int cs5345_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct cs5345_state *state = to_state(sd); v4l2_device_unregister_subdev(sd); - kfree(sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); return 0; } -- cgit v1.2.2 From a75b9be1c2fb52dee765d35f29031dd788d522eb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 31 Dec 2010 10:22:52 -0300 Subject: [media] cx18: Use the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-av-audio.c | 92 ++-------- drivers/media/video/cx18/cx18-av-core.c | 175 ++++++++----------- drivers/media/video/cx18/cx18-av-core.h | 12 +- drivers/media/video/cx18/cx18-controls.c | 285 ++++--------------------------- drivers/media/video/cx18/cx18-controls.h | 7 +- drivers/media/video/cx18/cx18-driver.c | 30 ++-- drivers/media/video/cx18/cx18-driver.h | 2 +- drivers/media/video/cx18/cx18-fileops.c | 32 +--- drivers/media/video/cx18/cx18-ioctl.c | 24 ++- drivers/media/video/cx18/cx18-mailbox.c | 5 +- drivers/media/video/cx18/cx18-mailbox.h | 5 - drivers/media/video/cx18/cx18-streams.c | 16 +- 12 files changed, 173 insertions(+), 512 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c index 43d09a24b262..4a24ffb17a7d 100644 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -342,17 +342,6 @@ void cx18_av_audio_set_path(struct cx18 *cx) } } -static int get_volume(struct cx18 *cx) -{ - /* Volume runs +18dB to -96dB in 1/2dB steps - * change to fit the msp3400 -114dB to +12dB range */ - - /* check PATH1_VOLUME */ - int vol = 228 - cx18_av_read(cx, 0x8d4); - vol = (vol / 2) + 23; - return vol << 9; -} - static void set_volume(struct cx18 *cx, int volume) { /* First convert the volume to msp3400 values (0-127) */ @@ -369,52 +358,18 @@ static void set_volume(struct cx18 *cx, int volume) cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); } -static int get_bass(struct cx18 *cx) -{ - /* bass is 49 steps +12dB to -12dB */ - - /* check PATH1_EQ_BASS_VOL */ - int bass = cx18_av_read(cx, 0x8d9) & 0x3f; - bass = (((48 - bass) * 0xffff) + 47) / 48; - return bass; -} - static void set_bass(struct cx18 *cx, int bass) { /* PATH1_EQ_BASS_VOL */ cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); } -static int get_treble(struct cx18 *cx) -{ - /* treble is 49 steps +12dB to -12dB */ - - /* check PATH1_EQ_TREBLE_VOL */ - int treble = cx18_av_read(cx, 0x8db) & 0x3f; - treble = (((48 - treble) * 0xffff) + 47) / 48; - return treble; -} - static void set_treble(struct cx18 *cx, int treble) { /* PATH1_EQ_TREBLE_VOL */ cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); } -static int get_balance(struct cx18 *cx) -{ - /* balance is 7 bit, 0 to -96dB */ - - /* check PATH1_BAL_LEVEL */ - int balance = cx18_av_read(cx, 0x8d5) & 0x7f; - /* check PATH1_BAL_LEFT */ - if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0) - balance = 0x80 - balance; - else - balance = 0x80 + balance; - return balance << 8; -} - static void set_balance(struct cx18 *cx, int balance) { int bal = balance >> 8; @@ -431,12 +386,6 @@ static void set_balance(struct cx18 *cx, int balance) } } -static int get_mute(struct cx18 *cx) -{ - /* check SRC1_MUTE_EN */ - return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0; -} - static void set_mute(struct cx18 *cx, int mute) { struct cx18_av_state *state = &cx->av_state; @@ -490,50 +439,33 @@ int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq) return retval; } -int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl) +static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl) { - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = get_volume(cx); - break; - case V4L2_CID_AUDIO_BASS: - ctrl->value = get_bass(cx); - break; - case V4L2_CID_AUDIO_TREBLE: - ctrl->value = get_treble(cx); - break; - case V4L2_CID_AUDIO_BALANCE: - ctrl->value = get_balance(cx); - break; - case V4L2_CID_AUDIO_MUTE: - ctrl->value = get_mute(cx); - break; - default: - return -EINVAL; - } - return 0; -} + struct v4l2_subdev *sd = to_sd(ctrl); + struct cx18 *cx = v4l2_get_subdevdata(sd); -int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl) -{ switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: - set_volume(cx, ctrl->value); + set_volume(cx, ctrl->val); break; case V4L2_CID_AUDIO_BASS: - set_bass(cx, ctrl->value); + set_bass(cx, ctrl->val); break; case V4L2_CID_AUDIO_TREBLE: - set_treble(cx, ctrl->value); + set_treble(cx, ctrl->val); break; case V4L2_CID_AUDIO_BALANCE: - set_balance(cx, ctrl->value); + set_balance(cx, ctrl->val); break; case V4L2_CID_AUDIO_MUTE: - set_mute(cx, ctrl->value); + set_mute(cx, ctrl->val); break; default: return -EINVAL; } return 0; } + +const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = { + .s_ctrl = cx18_av_audio_s_ctrl, +}; diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c index a41951cab276..f164b7f610a5 100644 --- a/drivers/media/video/cx18/cx18-av-core.c +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -129,6 +129,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd) { struct cx18_av_state *state = to_cx18_av_state(sd); struct cx18 *cx = v4l2_get_subdevdata(sd); + int default_volume; u32 v; cx18_av_loadfw(cx); @@ -247,8 +248,23 @@ static void cx18_av_initialize(struct v4l2_subdev *sd) /* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ /* } */ cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); - state->default_volume = 228 - cx18_av_read(cx, 0x8d4); - state->default_volume = ((state->default_volume / 2) + 23) << 9; + default_volume = cx18_av_read(cx, 0x8d4); + /* + * Enforce the legacy 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; + cx18_av_write(cx, 0x8d4, 228); + } else if (default_volume < 20) { + /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ + default_volume = 20; + cx18_av_write(cx, 0x8d4, 20); + } + default_volume = (((228 - default_volume) >> 1) + 23) << 9; + state->volume->cur.val = state->volume->default_value = default_volume; + v4l2_ctrl_handler_setup(&state->hdl); } static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) @@ -901,126 +917,35 @@ static int cx18_av_s_radio(struct v4l2_subdev *sd) return 0; } -static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = to_sd(ctrl); struct cx18 *cx = v4l2_get_subdevdata(sd); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - if (ctrl->value < 0 || ctrl->value > 255) { - CX18_ERR_DEV(sd, "invalid brightness setting %d\n", - ctrl->value); - return -ERANGE; - } - - cx18_av_write(cx, 0x414, ctrl->value - 128); + cx18_av_write(cx, 0x414, ctrl->val - 128); break; case V4L2_CID_CONTRAST: - if (ctrl->value < 0 || ctrl->value > 127) { - CX18_ERR_DEV(sd, "invalid contrast setting %d\n", - ctrl->value); - return -ERANGE; - } - - cx18_av_write(cx, 0x415, ctrl->value << 1); + cx18_av_write(cx, 0x415, ctrl->val << 1); break; case V4L2_CID_SATURATION: - if (ctrl->value < 0 || ctrl->value > 127) { - CX18_ERR_DEV(sd, "invalid saturation setting %d\n", - ctrl->value); - return -ERANGE; - } - - cx18_av_write(cx, 0x420, ctrl->value << 1); - cx18_av_write(cx, 0x421, ctrl->value << 1); + cx18_av_write(cx, 0x420, ctrl->val << 1); + cx18_av_write(cx, 0x421, ctrl->val << 1); break; case V4L2_CID_HUE: - if (ctrl->value < -128 || ctrl->value > 127) { - CX18_ERR_DEV(sd, "invalid hue setting %d\n", - ctrl->value); - return -ERANGE; - } - - cx18_av_write(cx, 0x422, ctrl->value); + cx18_av_write(cx, 0x422, ctrl->val); break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_MUTE: - return cx18_av_audio_s_ctrl(cx, ctrl); - - default: - return -EINVAL; - } - return 0; -} - -static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128; - break; - case V4L2_CID_CONTRAST: - ctrl->value = cx18_av_read(cx, 0x415) >> 1; - break; - case V4L2_CID_SATURATION: - ctrl->value = cx18_av_read(cx, 0x420) >> 1; - break; - case V4L2_CID_HUE: - ctrl->value = (s8)cx18_av_read(cx, 0x422); - break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_MUTE: - return cx18_av_audio_g_ctrl(cx, ctrl); default: return -EINVAL; } return 0; } -static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); - default: - break; - } - - switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, - 65535 / 100, state->default_volume); - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); - default: - return -EINVAL; - } - return -EINVAL; -} - static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { struct cx18_av_state *state = to_cx18_av_state(sd); @@ -1356,14 +1281,22 @@ static int cx18_av_s_register(struct v4l2_subdev *sd, } #endif +static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = { + .s_ctrl = cx18_av_s_ctrl, +}; + static const struct v4l2_subdev_core_ops cx18_av_general_ops = { .g_chip_ident = cx18_av_g_chip_ident, .log_status = cx18_av_log_status, .load_fw = cx18_av_load_fw, .reset = cx18_av_reset, - .queryctrl = cx18_av_queryctrl, - .g_ctrl = cx18_av_g_ctrl, - .s_ctrl = cx18_av_s_ctrl, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, .s_std = cx18_av_s_std, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = cx18_av_g_register, @@ -1427,8 +1360,42 @@ int cx18_av_probe(struct cx18 *cx) snprintf(sd->name, sizeof(sd->name), "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); sd->grp_id = CX18_HW_418_AV; + v4l2_ctrl_handler_init(&state->hdl, 9); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_CONTRAST, 0, 127, 1, 64); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_SATURATION, 0, 127, 1, 64); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + + state->volume = v4l2_ctrl_new_std(&state->hdl, + &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, + 0, 65535, 65535 / 100, 0); + v4l2_ctrl_new_std(&state->hdl, + &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, + 0, 1, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, + V4L2_CID_AUDIO_BALANCE, + 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, + V4L2_CID_AUDIO_BASS, + 0, 65535, 65535 / 100, 32768); + v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, + V4L2_CID_AUDIO_TREBLE, + 0, 65535, 65535 / 100, 32768); + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + return err; + } err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); - if (!err) + if (err) + v4l2_ctrl_handler_free(&state->hdl); + else cx18_av_init(cx); return err; } diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h index 1956991795e3..188c9c3d2db1 100644 --- a/drivers/media/video/cx18/cx18-av-core.h +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -26,6 +26,7 @@ #define _CX18_AV_CORE_H_ #include +#include struct cx18; @@ -95,13 +96,14 @@ enum cx18_av_audio_input { struct cx18_av_state { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *volume; int radio; v4l2_std_id std; enum cx18_av_video_input vid_input; enum cx18_av_audio_input aud_input; u32 audclk_freq; int audmode; - int default_volume; u32 id; u32 rev; int is_initialized; @@ -347,6 +349,11 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd) return container_of(sd, struct cx18_av_state, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd; +} + /* ----------------------------------------------------------------------- */ /* cx18_av-core.c */ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); @@ -369,10 +376,9 @@ int cx18_av_loadfw(struct cx18 *cx); /* ----------------------------------------------------------------------- */ /* cx18_av-audio.c */ -int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl); -int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl); int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); void cx18_av_audio_set_path(struct cx18 *cx); +extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops; /* ----------------------------------------------------------------------- */ /* cx18_av-vbi.c */ diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 97d7b7e100a3..282a3d29fdaa 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c @@ -30,152 +30,11 @@ #include "cx18-mailbox.h" #include "cx18-controls.h" -/* Must be sorted from low to high control ID! */ -static const u32 user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_BALANCE, - V4L2_CID_AUDIO_BASS, - V4L2_CID_AUDIO_TREBLE, - V4L2_CID_AUDIO_MUTE, - V4L2_CID_AUDIO_LOUDNESS, - 0 -}; - -static const u32 *ctrl_classes[] = { - user_ctrls, - cx2341x_mpeg_ctrls, - NULL -}; - -int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) -{ - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - const char *name; - - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - switch (qctrl->id) { - /* Standard V4L2 controls */ - case V4L2_CID_USER_CLASS: - return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0); - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_HUE: - case V4L2_CID_SATURATION: - case V4L2_CID_CONTRAST: - if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_LOUDNESS: - if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - - default: - if (cx2341x_ctrl_query(&cx->params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - } - strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); - qctrl->name[sizeof(qctrl->name) - 1] = 0; - return 0; -} - -int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu) +static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - cx18_queryctrl(file, fh, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&cx->params, qmenu->id)); -} - -static int cx18_try_ctrl(struct file *file, void *fh, - struct v4l2_ext_control *vctrl) -{ - struct v4l2_queryctrl qctrl; - const char * const *menu_items = NULL; - int err; - - qctrl.id = vctrl->id; - err = cx18_queryctrl(file, fh, &qctrl); - if (err) - return err; - if (qctrl.type == V4L2_CTRL_TYPE_MENU) - menu_items = v4l2_ctrl_get_menu(qctrl.id); - return v4l2_ctrl_check(vctrl, &qctrl, menu_items); -} - -static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) -{ - switch (vctrl->id) { - /* Standard V4L2 controls */ - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_HUE: - case V4L2_CID_SATURATION: - case V4L2_CID_CONTRAST: - return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl); - - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_LOUDNESS: - return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl); - - default: - CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); - return -EINVAL; - } - return 0; -} - -static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) -{ - switch (vctrl->id) { - /* Standard V4L2 controls */ - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_HUE: - case V4L2_CID_SATURATION: - case V4L2_CID_CONTRAST: - return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl); - - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_LOUDNESS: - return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl); + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); + int type = cxhdl->stream_type->val; - default: - CX18_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id); - return -EINVAL; - } - return 0; -} - -static int cx18_setup_vbi_fmt(struct cx18 *cx, - enum v4l2_mpeg_stream_vbi_fmt fmt, - enum v4l2_mpeg_stream_type type) -{ - if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) - return -EINVAL; if (atomic_read(&cx->ana_capturing) > 0) return -EBUSY; @@ -230,121 +89,43 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, return 0; } -int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; - struct v4l2_control ctrl; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = cx18_g_ctrl(cx, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } - } - return err; - } - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS); - return -EINVAL; + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); + int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_mbus_framefmt fmt; + + /* fix videodecoder resolution */ + fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + fmt.height = cxhdl->height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); + return 0; } -int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) { - struct cx18_open_id *id = fh; - struct cx18 *cx = id->cx; - int ret; - struct v4l2_control ctrl; - - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; - - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - ctrl.id = c->controls[i].id; - ctrl.value = c->controls[i].value; - err = cx18_s_ctrl(cx, &ctrl); - c->controls[i].value = ctrl.value; - if (err) { - c->error_idx = i; - break; - } - } - return err; - } - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - static u32 freqs[3] = { 44100, 48000, 32000 }; - struct cx18_api_func_private priv; - struct cx2341x_mpeg_params p = cx->params; - int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), - c, VIDIOC_S_EXT_CTRLS); - unsigned int idx; - - if (err) - return err; + static const u32 freqs[3] = { 44100, 48000, 32000 }; + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - if (p.video_encoding != cx->params.video_encoding) { - int is_mpeg1 = p.video_encoding == - V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; - - /* fix videodecoder resolution */ - fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1); - fmt.height = cx->params.height; - fmt.code = V4L2_MBUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); - } - priv.cx = cx; - priv.s = &cx->streams[id->type]; - err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p); - if (!err && - (cx->params.stream_vbi_fmt != p.stream_vbi_fmt || - cx->params.stream_type != p.stream_type)) - err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt, - p.stream_type); - cx->params = p; - cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; - idx = p.audio_properties & 0x03; - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (idx < ARRAY_SIZE(freqs)) - cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); - return err; - } - return -EINVAL; + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < ARRAY_SIZE(freqs)) + cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); + return 0; } -int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) +static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { - int i; - int err = 0; - - for (i = 0; i < c->count; i++) { - err = cx18_try_ctrl(file, fh, &c->controls[i]); - if (err) { - c->error_idx = i; - break; - } - } - return err; - } - if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) - return cx2341x_ext_ctrls(&cx->params, - atomic_read(&cx->ana_capturing), - c, VIDIOC_TRY_EXT_CTRLS); - return -EINVAL; + cx->dualwatch_stereo_mode = val; + return 0; } + +struct cx2341x_handler_ops cx18_cxhdl_ops = { + .s_audio_mode = cx18_s_audio_mode, + .s_audio_sampling_freq = cx18_s_audio_sampling_freq, + .s_video_encoding = cx18_s_video_encoding, + .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt, +}; diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h index e46323700b81..cb5dfc7b2054 100644 --- a/drivers/media/video/cx18/cx18-controls.h +++ b/drivers/media/video/cx18/cx18-controls.h @@ -21,9 +21,4 @@ * 02111-1307 USA */ -int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); -int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); -int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); -int cx18_try_ext_ctrls(struct file *file, void *fh, - struct v4l2_ext_controls *a); -int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a); +extern struct cx2341x_handler_ops cx18_cxhdl_ops; diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index b1c3cbd92743..b988ec62af58 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -36,6 +36,7 @@ #include "cx18-scb.h" #include "cx18-mailbox.h" #include "cx18-ioctl.h" +#include "cx18-controls.h" #include "tuner-xc2028.h" #include @@ -729,15 +730,21 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) cx->open_id = 1; /* Initial settings */ - cx2341x_fill_defaults(&cx->params); - cx->temporal_strength = cx->params.video_temporal_filter; - cx->spatial_strength = cx->params.video_spatial_filter; - cx->filter_mode = cx->params.video_spatial_filter_mode | - (cx->params.video_temporal_filter_mode << 1) | - (cx->params.video_median_filter_type << 2); - cx->params.port = CX2341X_PORT_MEMORY; - cx->params.capabilities = - CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; + cx->cxhdl.port = CX2341X_PORT_MEMORY; + cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; + cx->cxhdl.ops = &cx18_cxhdl_ops; + cx->cxhdl.func = cx18_api_func; + ret = cx2341x_handler_init(&cx->cxhdl, 50); + if (ret) + return ret; + cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl; + + cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val; + cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val; + cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val | + (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) | + (cx->cxhdl.video_median_filter_type->cur.val << 2); + init_waitqueue_head(&cx->cap_w); init_waitqueue_head(&cx->mb_apu_waitq); init_waitqueue_head(&cx->mb_cpu_waitq); @@ -1049,7 +1056,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, else cx->is_50hz = 1; - cx->params.video_gop_size = cx->is_60hz ? 15 : 12; + cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); if (cx->options.radio > 0) cx->v4l2_cap |= V4L2_CAP_RADIO; @@ -1095,7 +1102,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, /* Load cx18 submodules (cx18-alsa) */ request_modules(cx); - return 0; free_streams: @@ -1278,6 +1284,8 @@ static void cx18_remove(struct pci_dev *pci_dev) for (i = 0; i < CX18_VBI_FRAMES; i++) kfree(cx->vbi.sliced_mpeg_data[i]); + v4l2_ctrl_handler_free(&cx->av_state.hdl); + CX18_INFO("Removed %s\n", cx->card_name); v4l2_device_unregister(v4l2_dev); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index f736679d2517..de2457741e26 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -565,7 +565,7 @@ struct cx18 { struct cx18_av_state av_state; /* codec settings */ - struct cx2341x_mpeg_params params; + struct cx2341x_handler cxhdl; u32 filter_mode; u32 temporal_strength; u32 spatial_strength; diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 9f23b90732f2..98ef33e4326a 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -160,13 +160,10 @@ EXPORT_SYMBOL(cx18_release_stream); static void cx18_dualwatch(struct cx18 *cx) { struct v4l2_tuner vt; - u32 new_bitmap; u32 new_stereo_mode; - const u32 stereo_mask = 0x0300; const u32 dual = 0x0200; - u32 h; - new_stereo_mode = cx->params.audio_properties & stereo_mask; + new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); memset(&vt, 0, sizeof(vt)); cx18_call_all(cx, tuner, g_tuner, &vt); if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && @@ -176,25 +173,10 @@ static void cx18_dualwatch(struct cx18 *cx) if (new_stereo_mode == cx->dualwatch_stereo_mode) return; - new_bitmap = new_stereo_mode - | (cx->params.audio_properties & ~stereo_mask); - - CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. " - "new audio_bitmask=0x%ux\n", - cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); - - h = cx18_find_handle(cx); - if (h == CX18_INVALID_TASK_HANDLE) { - CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n"); - return; - } - - if (cx18_vapi(cx, - CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) { - cx->dualwatch_stereo_mode = new_stereo_mode; - return; - } - CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); + CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", + cx->dualwatch_stereo_mode, new_stereo_mode); + if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) + CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); } @@ -724,8 +706,8 @@ int cx18_v4l2_close(struct file *filp) if (atomic_read(&cx->ana_capturing) > 0) { /* Undo video mute */ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, - cx->params.video_mute | - (cx->params.video_mute_yuv << 8)); + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); } /* Done! Unmute and continue. */ cx18_unmute(cx); diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 7150195740dc..36b018c943e5 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -152,8 +152,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, struct cx18 *cx = id->cx; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - pixfmt->width = cx->params.width; - pixfmt->height = cx->params.height; + pixfmt->width = cx->cxhdl.width; + pixfmt->height = cx->cxhdl.height; pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; pixfmt->field = V4L2_FIELD_INTERLACED; pixfmt->priv = 0; @@ -287,14 +287,14 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, w = fmt->fmt.pix.width; h = fmt->fmt.pix.height; - if (cx->params.width == w && cx->params.height == h) + if (cx->cxhdl.width == w && cx->cxhdl.height == h) return 0; if (atomic_read(&cx->ana_capturing) > 0) return -EBUSY; - mbus_fmt.width = cx->params.width = w; - mbus_fmt.height = cx->params.height = h; + mbus_fmt.width = cx->cxhdl.width = w; + mbus_fmt.height = cx->cxhdl.height = h; mbus_fmt.code = V4L2_MBUS_FMT_FIXED; v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); return cx18_g_fmt_vid_cap(file, fh, fmt); @@ -696,9 +696,10 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) cx->std = *std; cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; - cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; - cx->params.width = 720; - cx->params.height = cx->is_50hz ? 576 : 480; + cx->is_50hz = !cx->is_60hz; + cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); + cx->cxhdl.width = 720; + cx->cxhdl.height = cx->is_50hz ? 576 : 480; cx->vbi.count = cx->is_50hz ? 18 : 12; cx->vbi.start[0] = cx->is_50hz ? 6 : 10; cx->vbi.start[1] = cx->is_50hz ? 318 : 273; @@ -1035,7 +1036,7 @@ static int cx18_log_status(struct file *file, void *fh) mutex_unlock(&cx->gpio_lock); CX18_INFO("Tuner: %s\n", test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); - cx2341x_log_status(&cx->params, cx->v4l2_dev.name); + v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name); CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; @@ -1136,11 +1137,6 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_s_register = cx18_s_register, #endif .vidioc_default = cx18_default, - .vidioc_queryctrl = cx18_queryctrl, - .vidioc_querymenu = cx18_querymenu, - .vidioc_g_ext_ctrls = cx18_g_ext_ctrls, - .vidioc_s_ext_ctrls = cx18_s_ext_ctrls, - .vidioc_try_ext_ctrls = cx18_try_ext_ctrls, }; void cx18_set_funcs(struct video_device *vdev) diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c index c545f3beef78..9605d54bd083 100644 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -716,9 +716,8 @@ static int cx18_set_filter_param(struct cx18_stream *s) int cx18_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { - struct cx18_api_func_private *api_priv = priv; - struct cx18 *cx = api_priv->cx; - struct cx18_stream *s = api_priv->s; + struct cx18_stream *s = priv; + struct cx18 *cx = s->cx; switch (cmd) { case CX2341X_ENC_SET_OUTPUT_PORT: diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h index 077952fcbcca..05fe6bdbe062 100644 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -81,11 +81,6 @@ struct cx18_mailbox { struct cx18_stream; -struct cx18_api_func_private { - struct cx18 *cx; - struct cx18_stream *s; -}; - int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, int args, ...); diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 94f5d7967c5c..2d248560770e 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -572,7 +572,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s) * Set the MDL size to the exact size needed for one frame. * Use enough buffers per MDL to cover the MDL size */ - s->mdl_size = 720 * s->cx->params.height * 3 / 2; + s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; s->bufs_per_mdl = s->mdl_size / s->buf_size; if (s->mdl_size % s->buf_size) s->bufs_per_mdl++; @@ -607,7 +607,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) u32 data[MAX_MB_ARGUMENTS]; struct cx18 *cx = s->cx; int captype = 0; - struct cx18_api_func_private priv; struct cx18_stream *s_idx; if (!cx18_stream_enabled(s)) @@ -620,7 +619,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) captype = CAPTURE_CHANNEL_TYPE_MPEG; cx->mpg_data_received = cx->vbi_data_inserted = 0; cx->dualwatch_jiffies = jiffies; - cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300; + cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); cx->search_pack_header = 0; break; @@ -710,21 +709,21 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); /* Call out to the common CX2341x API setup for user controls */ - priv.cx = cx; - priv.s = s; - cx2341x_update(&priv, cx18_api_func, NULL, &cx->params); + cx->cxhdl.priv = s; + cx2341x_handler_setup(&cx->cxhdl); /* * When starting a capture and we're set for radio, * ensure the video is muted, despite the user control. */ - if (!cx->params.video_mute && + if (!cx->cxhdl.video_mute && test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, - (cx->params.video_mute_yuv << 8) | 1); + (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); } if (atomic_read(&cx->tot_capturing) == 0) { + cx2341x_handler_set_busy(&cx->cxhdl, 1); clear_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); } @@ -826,6 +825,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) if (atomic_read(&cx->tot_capturing) > 0) return 0; + cx2341x_handler_set_busy(&cx->cxhdl, 0); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); wake_up(&s->waitq); -- cgit v1.2.2 From ceed52d67e1cf7866fa96514525c615554a0e44e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:19:16 -0300 Subject: [media] adv7343: use control framework Also fixed a memory leak in the probe function if an error occurred. The gain control range was also fixed (a proper range from -64 to 64). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/adv7343.c | 167 ++++++++++++++----------------------- drivers/media/video/adv7343_regs.h | 8 +- 2 files changed, 63 insertions(+), 112 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c index 41b2930d0ce4..021fab23070d 100644 --- a/drivers/media/video/adv7343.c +++ b/drivers/media/video/adv7343.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "adv7343_regs.h" @@ -41,15 +42,13 @@ MODULE_PARM_DESC(debug, "Debug level 0-1"); struct adv7343_state { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; u8 reg00; u8 reg01; u8 reg02; u8 reg35; u8 reg80; u8 reg82; - int bright; - int hue; - int gain; u32 output; v4l2_std_id std; }; @@ -59,6 +58,11 @@ static inline struct adv7343_state *to_state(struct v4l2_subdev *sd) return container_of(sd, struct adv7343_state, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd; +} + static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -268,111 +272,22 @@ static int adv7343_log_status(struct v4l2_subdev *sd) return 0; } -static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN, - ADV7343_BRIGHTNESS_MAX, 1, - ADV7343_BRIGHTNESS_DEF); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN, - ADV7343_HUE_MAX, 1 , - ADV7343_HUE_DEF); - case V4L2_CID_GAIN: - return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN, - ADV7343_GAIN_MAX, 1, - ADV7343_GAIN_DEF); - default: - break; - } - - return 0; -} - -static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct adv7343_state *state = to_state(sd); - int err = 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value < ADV7343_BRIGHTNESS_MIN || - ctrl->value > ADV7343_BRIGHTNESS_MAX) { - v4l2_dbg(1, debug, sd, - "invalid brightness settings %d\n", - ctrl->value); - return -ERANGE; - } - - state->bright = ctrl->value; - err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, - state->bright); - break; - - case V4L2_CID_HUE: - if (ctrl->value < ADV7343_HUE_MIN || - ctrl->value > ADV7343_HUE_MAX) { - v4l2_dbg(1, debug, sd, "invalid hue settings %d\n", - ctrl->value); - return -ERANGE; - } - - state->hue = ctrl->value; - err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue); - break; - - case V4L2_CID_GAIN: - if (ctrl->value < ADV7343_GAIN_MIN || - ctrl->value > ADV7343_GAIN_MAX) { - v4l2_dbg(1, debug, sd, "invalid gain settings %d\n", - ctrl->value); - return -ERANGE; - } - - if ((ctrl->value > POSITIVE_GAIN_MAX) && - (ctrl->value < NEGATIVE_GAIN_MIN)) { - v4l2_dbg(1, debug, sd, - "gain settings not within the specified range\n"); - return -ERANGE; - } - - state->gain = ctrl->value; - err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain); - break; - - default: - return -EINVAL; - } - - if (err < 0) - v4l2_err(sd, "Failed to set the encoder controls\n"); - - return err; -} - -static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl) { - struct adv7343_state *state = to_state(sd); + struct v4l2_subdev *sd = to_sd(ctrl); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - ctrl->value = state->bright; - break; + return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS, + ctrl->val); case V4L2_CID_HUE: - ctrl->value = state->hue; - break; + return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val); case V4L2_CID_GAIN: - ctrl->value = state->gain; - break; - - default: - return -EINVAL; + return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val); } - - return 0; + return -EINVAL; } static int adv7343_g_chip_ident(struct v4l2_subdev *sd, @@ -383,12 +298,20 @@ static int adv7343_g_chip_ident(struct v4l2_subdev *sd, return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0); } +static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { + .s_ctrl = adv7343_s_ctrl, +}; + static const struct v4l2_subdev_core_ops adv7343_core_ops = { - .log_status = adv7343_log_status, - .g_chip_ident = adv7343_g_chip_ident, - .g_ctrl = adv7343_g_ctrl, - .s_ctrl = adv7343_s_ctrl, - .queryctrl = adv7343_queryctrl, + .log_status = adv7343_log_status, + .g_chip_ident = adv7343_g_chip_ident, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, }; static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) @@ -468,6 +391,7 @@ static int adv7343_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adv7343_state *state; + int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -490,15 +414,46 @@ static int adv7343_probe(struct i2c_client *client, state->std = V4L2_STD_NTSC; v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops); - return adv7343_initialize(&state->sd); + + v4l2_ctrl_handler_init(&state->hdl, 2); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN, + ADV7343_BRIGHTNESS_MAX, 1, + ADV7343_BRIGHTNESS_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_HUE, ADV7343_HUE_MIN, + ADV7343_HUE_MAX, 1, + ADV7343_HUE_DEF); + v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops, + V4L2_CID_GAIN, ADV7343_GAIN_MIN, + ADV7343_GAIN_MAX, 1, + ADV7343_GAIN_DEF); + state->sd.ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + v4l2_ctrl_handler_setup(&state->hdl); + + err = adv7343_initialize(&state->sd); + if (err) { + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + } + return err; } static int adv7343_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct adv7343_state *state = to_state(sd); v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); return 0; } diff --git a/drivers/media/video/adv7343_regs.h b/drivers/media/video/adv7343_regs.h index 3431045b33da..446606764346 100644 --- a/drivers/media/video/adv7343_regs.h +++ b/drivers/media/video/adv7343_regs.h @@ -102,10 +102,6 @@ struct adv7343_std_info { /* Bit masks for DAC output levels */ #define DAC_OUTPUT_LEVEL_MASK (0xFF) -#define POSITIVE_GAIN_MAX (0x40) -#define POSITIVE_GAIN_MIN (0x00) -#define NEGATIVE_GAIN_MAX (0xFF) -#define NEGATIVE_GAIN_MIN (0xC0) /* Bit masks for soft reset register */ #define SOFT_RESET (0x02) @@ -178,8 +174,8 @@ struct adv7343_std_info { #define ADV7343_HUE_MAX (255) #define ADV7343_HUE_MIN (0) #define ADV7343_HUE_DEF (127) -#define ADV7343_GAIN_MAX (255) -#define ADV7343_GAIN_MIN (0) +#define ADV7343_GAIN_MAX (64) +#define ADV7343_GAIN_MIN (-64) #define ADV7343_GAIN_DEF (0) #endif -- cgit v1.2.2 From bd84a65aefbd669bcd2ff7bcee96f0f666d7a820 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:19:41 -0300 Subject: [media] bt819: use control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/bt819.c | 129 +++++++++++++++++--------------------------- 1 file changed, 49 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c index c38300fc0b1d..f87204461cb4 100644 --- a/drivers/media/video/bt819.c +++ b/drivers/media/video/bt819.c @@ -37,6 +37,7 @@ #include #include #include +#include #include MODULE_DESCRIPTION("Brooktree-819 video decoder driver"); @@ -52,16 +53,13 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); struct bt819 { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; unsigned char reg[32]; v4l2_std_id norm; int ident; int input; int enable; - int bright; - int contrast; - int hue; - int sat; }; static inline struct bt819 *to_bt819(struct v4l2_subdev *sd) @@ -69,6 +67,11 @@ static inline struct bt819 *to_bt819(struct v4l2_subdev *sd) return container_of(sd, struct bt819, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct bt819, hdl)->sd; +} + struct timing { int hactive; int hdelay; @@ -333,71 +336,35 @@ static int bt819_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int bt819_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); - break; - - case V4L2_CID_CONTRAST: - v4l2_ctrl_query_fill(qc, 0, 511, 1, 256); - break; - - case V4L2_CID_SATURATION: - v4l2_ctrl_query_fill(qc, 0, 511, 1, 256); - break; - - case V4L2_CID_HUE: - v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int bt819_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = to_sd(ctrl); struct bt819 *decoder = to_bt819(sd); int temp; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - if (decoder->bright == ctrl->value) - break; - decoder->bright = ctrl->value; - bt819_write(decoder, 0x0a, decoder->bright); + bt819_write(decoder, 0x0a, ctrl->val); break; case V4L2_CID_CONTRAST: - if (decoder->contrast == ctrl->value) - break; - decoder->contrast = ctrl->value; - bt819_write(decoder, 0x0c, decoder->contrast & 0xff); - bt819_setbit(decoder, 0x0b, 2, ((decoder->contrast >> 8) & 0x01)); + bt819_write(decoder, 0x0c, ctrl->val & 0xff); + bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01)); break; case V4L2_CID_SATURATION: - if (decoder->sat == ctrl->value) - break; - decoder->sat = ctrl->value; - bt819_write(decoder, 0x0d, (decoder->sat >> 7) & 0xff); - bt819_setbit(decoder, 0x0b, 1, ((decoder->sat >> 15) & 0x01)); + bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff); + bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01)); /* Ratio between U gain and V gain must stay the same as the ratio between the default U and V gain values. */ - temp = (decoder->sat * 180) / 254; + temp = (ctrl->val * 180) / 254; bt819_write(decoder, 0x0e, (temp >> 7) & 0xff); bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01); break; case V4L2_CID_HUE: - if (decoder->hue == ctrl->value) - break; - decoder->hue = ctrl->value; - bt819_write(decoder, 0x0f, decoder->hue); + bt819_write(decoder, 0x0f, ctrl->val); break; default: @@ -406,29 +373,6 @@ static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return 0; } -static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct bt819 *decoder = to_bt819(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = decoder->bright; - break; - case V4L2_CID_CONTRAST: - ctrl->value = decoder->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = decoder->sat; - break; - case V4L2_CID_HUE: - ctrl->value = decoder->hue; - break; - default: - return -EINVAL; - } - return 0; -} - static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct bt819 *decoder = to_bt819(sd); @@ -439,11 +383,19 @@ static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident /* ----------------------------------------------------------------------- */ +static const struct v4l2_ctrl_ops bt819_ctrl_ops = { + .s_ctrl = bt819_s_ctrl, +}; + static const struct v4l2_subdev_core_ops bt819_core_ops = { .g_chip_ident = bt819_g_chip_ident, - .g_ctrl = bt819_g_ctrl, - .s_ctrl = bt819_s_ctrl, - .queryctrl = bt819_queryctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, .s_std = bt819_s_std, }; @@ -505,23 +457,40 @@ static int bt819_probe(struct i2c_client *client, decoder->norm = V4L2_STD_NTSC; decoder->input = 0; decoder->enable = 1; - decoder->bright = 0; - decoder->contrast = 0xd8; /* 100% of original signal */ - decoder->hue = 0; - decoder->sat = 0xfe; /* 100% of original signal */ i = bt819_init(sd); if (i < 0) v4l2_dbg(1, debug, sd, "init status %d\n", i); + + v4l2_ctrl_handler_init(&decoder->hdl, 4); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_CONTRAST, 0, 511, 1, 0xd8); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_SATURATION, 0, 511, 1, 0xfe); + v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + sd->ctrl_handler = &decoder->hdl; + if (decoder->hdl.error) { + int err = decoder->hdl.error; + + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); + return err; + } + v4l2_ctrl_handler_setup(&decoder->hdl); return 0; } static int bt819_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct bt819 *decoder = to_bt819(sd); v4l2_device_unregister_subdev(sd); - kfree(to_bt819(sd)); + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); return 0; } -- cgit v1.2.2 From 4744ebf631bc9276f7c10e37801f05c8ceea7bab Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:27:48 -0300 Subject: [media] saa7110: use control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7110.c | 115 +++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c index 7913f93979b8..99664205ef4e 100644 --- a/drivers/media/video/saa7110.c +++ b/drivers/media/video/saa7110.c @@ -36,6 +36,7 @@ #include #include #include +#include MODULE_DESCRIPTION("Philips SAA7110 video decoder driver"); MODULE_AUTHOR("Pauline Middelink"); @@ -53,15 +54,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); struct saa7110 { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; u8 reg[SAA7110_NR_REG]; v4l2_std_id norm; int input; int enable; - int bright; - int contrast; - int hue; - int sat; wait_queue_head_t wq; }; @@ -71,6 +69,11 @@ static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd) return container_of(sd, struct saa7110, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct saa7110, hdl)->sd; +} + /* ----------------------------------------------------------------------- */ /* I2C support functions */ /* ----------------------------------------------------------------------- */ @@ -326,73 +329,22 @@ static int saa7110_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int saa7110_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); - default: - return -EINVAL; - } - return 0; -} - -static int saa7110_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct saa7110 *decoder = to_saa7110(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = decoder->bright; - break; - case V4L2_CID_CONTRAST: - ctrl->value = decoder->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = decoder->sat; - break; - case V4L2_CID_HUE: - ctrl->value = decoder->hue; - break; - default: - return -EINVAL; - } - return 0; -} - -static int saa7110_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl) { - struct saa7110 *decoder = to_saa7110(sd); + struct v4l2_subdev *sd = to_sd(ctrl); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - if (decoder->bright != ctrl->value) { - decoder->bright = ctrl->value; - saa7110_write(sd, 0x19, decoder->bright); - } + saa7110_write(sd, 0x19, ctrl->val); break; case V4L2_CID_CONTRAST: - if (decoder->contrast != ctrl->value) { - decoder->contrast = ctrl->value; - saa7110_write(sd, 0x13, decoder->contrast); - } + saa7110_write(sd, 0x13, ctrl->val); break; case V4L2_CID_SATURATION: - if (decoder->sat != ctrl->value) { - decoder->sat = ctrl->value; - saa7110_write(sd, 0x12, decoder->sat); - } + saa7110_write(sd, 0x12, ctrl->val); break; case V4L2_CID_HUE: - if (decoder->hue != ctrl->value) { - decoder->hue = ctrl->value; - saa7110_write(sd, 0x07, decoder->hue); - } + saa7110_write(sd, 0x07, ctrl->val); break; default: return -EINVAL; @@ -409,11 +361,19 @@ static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide /* ----------------------------------------------------------------------- */ +static const struct v4l2_ctrl_ops saa7110_ctrl_ops = { + .s_ctrl = saa7110_s_ctrl, +}; + static const struct v4l2_subdev_core_ops saa7110_core_ops = { .g_chip_ident = saa7110_g_chip_ident, - .g_ctrl = saa7110_g_ctrl, - .s_ctrl = saa7110_s_ctrl, - .queryctrl = saa7110_queryctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, .s_std = saa7110_s_std, }; @@ -454,10 +414,25 @@ static int saa7110_probe(struct i2c_client *client, decoder->norm = V4L2_STD_PAL; decoder->input = 0; decoder->enable = 1; - decoder->bright = 32768; - decoder->contrast = 32768; - decoder->hue = 32768; - decoder->sat = 32768; + v4l2_ctrl_handler_init(&decoder->hdl, 2); + v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, + V4L2_CID_CONTRAST, 0, 127, 1, 64); + v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, + V4L2_CID_SATURATION, 0, 127, 1, 64); + v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + sd->ctrl_handler = &decoder->hdl; + if (decoder->hdl.error) { + int err = decoder->hdl.error; + + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); + return err; + } + v4l2_ctrl_handler_setup(&decoder->hdl); + init_waitqueue_head(&decoder->wq); rv = saa7110_write_block(sd, initseq, sizeof(initseq)); @@ -490,9 +465,11 @@ static int saa7110_probe(struct i2c_client *client, static int saa7110_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct saa7110 *decoder = to_saa7110(sd); v4l2_device_unregister_subdev(sd); - kfree(to_saa7110(sd)); + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); return 0; } -- cgit v1.2.2 From e3d5ef0410806d94cf58afd87a753ad5932ca8a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:45:04 -0300 Subject: [media] tlv320aic23b: use control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tlv320aic23b.c | 74 ++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index dfc4dd7c5097..286ec7e7062a 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -31,6 +31,7 @@ #include #include #include +#include MODULE_DESCRIPTION("tlv320aic23b driver"); MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); @@ -41,7 +42,7 @@ MODULE_LICENSE("GPL"); struct tlv320aic23b_state { struct v4l2_subdev sd; - u8 muted; + struct v4l2_ctrl_handler hdl; }; static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd) @@ -49,6 +50,11 @@ static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd) return container_of(sd, struct tlv320aic23b_state, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct tlv320aic23b_state, hdl)->sd; +} + static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -85,44 +91,44 @@ static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq) return 0; } -static int tlv320aic23b_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct tlv320aic23b_state *state = to_state(sd); - - if (ctrl->id != V4L2_CID_AUDIO_MUTE) - return -EINVAL; - ctrl->value = state->muted; - return 0; -} - -static int tlv320aic23b_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int tlv320aic23b_s_ctrl(struct v4l2_ctrl *ctrl) { - struct tlv320aic23b_state *state = to_state(sd); - - if (ctrl->id != V4L2_CID_AUDIO_MUTE) - return -EINVAL; - state->muted = ctrl->value; - tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */ - /* set gain on both channels to +3.0 dB */ - if (!state->muted) - tlv320aic23b_write(sd, 0, 0x119); - return 0; + struct v4l2_subdev *sd = to_sd(ctrl); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */ + /* set gain on both channels to +3.0 dB */ + if (!ctrl->val) + tlv320aic23b_write(sd, 0, 0x119); + return 0; + } + return -EINVAL; } static int tlv320aic23b_log_status(struct v4l2_subdev *sd) { struct tlv320aic23b_state *state = to_state(sd); - v4l2_info(sd, "Input: %s\n", state->muted ? "muted" : "active"); + v4l2_ctrl_handler_log_status(&state->hdl, sd->name); return 0; } /* ----------------------------------------------------------------------- */ +static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = { + .s_ctrl = tlv320aic23b_s_ctrl, +}; + static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = { .log_status = tlv320aic23b_log_status, - .g_ctrl = tlv320aic23b_g_ctrl, - .s_ctrl = tlv320aic23b_s_ctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = { @@ -161,7 +167,6 @@ static int tlv320aic23b_probe(struct i2c_client *client, return -ENOMEM; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops); - state->muted = 0; /* Initialize tlv320aic23b */ @@ -177,15 +182,30 @@ static int tlv320aic23b_probe(struct i2c_client *client, tlv320aic23b_write(sd, 8, 0x000); /* activate digital interface */ tlv320aic23b_write(sd, 9, 0x001); + + v4l2_ctrl_handler_init(&state->hdl, 1); + v4l2_ctrl_new_std(&state->hdl, &tlv320aic23b_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + v4l2_ctrl_handler_setup(&state->hdl); return 0; } static int tlv320aic23b_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct tlv320aic23b_state *state = to_state(sd); v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); return 0; } -- cgit v1.2.2 From cf6832afe59f37b154bf0e41bf5e59cfd7f46d24 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:45:22 -0300 Subject: [media] tvp514x: use the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp514x.c | 236 ++++++++++-------------------------------- 1 file changed, 57 insertions(+), 179 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c index 45bcf0358a1d..9b3e828b0775 100644 --- a/drivers/media/video/tvp514x.c +++ b/drivers/media/video/tvp514x.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "tvp514x_regs.h" @@ -97,6 +98,7 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); */ struct tvp514x_decoder { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)]; const struct tvp514x_platform_data *pdata; @@ -238,6 +240,11 @@ static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd) return container_of(sd, struct tvp514x_decoder, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct tvp514x_decoder, hdl)->sd; +} + /** * tvp514x_read_reg() - Read a value from a register in an TVP5146/47. @@ -718,214 +725,55 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, return 0; } -/** - * tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl - * @sd: pointer to standard V4L2 sub-device structure - * @qctrl: standard V4L2 v4l2_queryctrl structure - * - * If the requested control is supported, returns the control information. - * Otherwise, returns -EINVAL if the control is not supported. - */ -static int -tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl) -{ - int err = -EINVAL; - - if (qctrl == NULL) - return err; - - switch (qctrl->id) { - case V4L2_CID_BRIGHTNESS: - /* Brightness supported is (0-255), */ - err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); - break; - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - /** - * Saturation and Contrast supported is - - * Contrast: 0 - 255 (Default - 128) - * Saturation: 0 - 255 (Default - 128) - */ - err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128); - break; - case V4L2_CID_HUE: - /* Hue Supported is - - * Hue - -180 - +180 (Default - 0, Step - +180) - */ - err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0); - break; - case V4L2_CID_AUTOGAIN: - /** - * Auto Gain supported is - - * 0 - 1 (Default - 1) - */ - err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1); - break; - default: - v4l2_err(sd, "invalid control id %d\n", qctrl->id); - return err; - } - - v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n", - qctrl->name, qctrl->minimum, qctrl->maximum, - qctrl->default_value); - - return err; -} - -/** - * tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl - * @sd: pointer to standard V4L2 sub-device structure - * @ctrl: pointer to v4l2_control structure - * - * If the requested control is supported, returns the control's current - * value from the decoder. Otherwise, returns -EINVAL if the control is not - * supported. - */ -static int -tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - - if (ctrl == NULL) - return -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val; - break; - case V4L2_CID_CONTRAST: - ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val; - break; - case V4L2_CID_SATURATION: - ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val; - break; - case V4L2_CID_HUE: - ctrl->value = decoder->tvp514x_regs[REG_HUE].val; - if (ctrl->value == 0x7F) - ctrl->value = 180; - else if (ctrl->value == 0x80) - ctrl->value = -180; - else - ctrl->value = 0; - - break; - case V4L2_CID_AUTOGAIN: - ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val; - if ((ctrl->value & 0x3) == 3) - ctrl->value = 1; - else - ctrl->value = 0; - - break; - default: - v4l2_err(sd, "invalid control id %d\n", ctrl->id); - return -EINVAL; - } - - v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n", - ctrl->id, ctrl->value); - return 0; -} - /** * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl - * @sd: pointer to standard V4L2 sub-device structure - * @ctrl: pointer to v4l2_control structure + * @ctrl: pointer to v4l2_ctrl structure * * If the requested control is supported, sets the control's current * value in HW. Otherwise, returns -EINVAL if the control is not supported. */ -static int -tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = to_sd(ctrl); struct tvp514x_decoder *decoder = to_decoder(sd); int err = -EINVAL, value; - if (ctrl == NULL) - return err; - - value = ctrl->value; + value = ctrl->val; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - if (ctrl->value < 0 || ctrl->value > 255) { - v4l2_err(sd, "invalid brightness setting %d\n", - ctrl->value); - return -ERANGE; - } - err = tvp514x_write_reg(sd, REG_BRIGHTNESS, - value); - if (err) - return err; - - decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; + err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value); + if (!err) + decoder->tvp514x_regs[REG_BRIGHTNESS].val = value; break; case V4L2_CID_CONTRAST: - if (ctrl->value < 0 || ctrl->value > 255) { - v4l2_err(sd, "invalid contrast setting %d\n", - ctrl->value); - return -ERANGE; - } err = tvp514x_write_reg(sd, REG_CONTRAST, value); - if (err) - return err; - - decoder->tvp514x_regs[REG_CONTRAST].val = value; + if (!err) + decoder->tvp514x_regs[REG_CONTRAST].val = value; break; case V4L2_CID_SATURATION: - if (ctrl->value < 0 || ctrl->value > 255) { - v4l2_err(sd, "invalid saturation setting %d\n", - ctrl->value); - return -ERANGE; - } err = tvp514x_write_reg(sd, REG_SATURATION, value); - if (err) - return err; - - decoder->tvp514x_regs[REG_SATURATION].val = value; + if (!err) + decoder->tvp514x_regs[REG_SATURATION].val = value; break; case V4L2_CID_HUE: if (value == 180) value = 0x7F; else if (value == -180) value = 0x80; - else if (value == 0) - value = 0; - else { - v4l2_err(sd, "invalid hue setting %d\n", ctrl->value); - return -ERANGE; - } err = tvp514x_write_reg(sd, REG_HUE, value); - if (err) - return err; - - decoder->tvp514x_regs[REG_HUE].val = value; + if (!err) + decoder->tvp514x_regs[REG_HUE].val = value; break; case V4L2_CID_AUTOGAIN: - if (value == 1) - value = 0x0F; - else if (value == 0) - value = 0x0C; - else { - v4l2_err(sd, "invalid auto gain setting %d\n", - ctrl->value); - return -ERANGE; - } - err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value); - if (err) - return err; - - decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; + err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c); + if (!err) + decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value; break; - default: - v4l2_err(sd, "invalid control id %d\n", ctrl->id); - return err; } v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n", - ctrl->id, ctrl->value); - + ctrl->id, ctrl->val); return err; } @@ -1104,10 +952,18 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable) return err; } -static const struct v4l2_subdev_core_ops tvp514x_core_ops = { - .queryctrl = tvp514x_queryctrl, - .g_ctrl = tvp514x_g_ctrl, +static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = { .s_ctrl = tvp514x_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops tvp514x_core_ops = { + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, .s_std = tvp514x_s_std, }; @@ -1190,6 +1046,27 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) sd = &decoder->sd; v4l2_i2c_subdev_init(sd, client, &tvp514x_ops); + v4l2_ctrl_handler_init(&decoder->hdl, 5); + v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, + V4L2_CID_HUE, -180, 180, 180, 0); + v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + sd->ctrl_handler = &decoder->hdl; + if (decoder->hdl.error) { + int err = decoder->hdl.error; + + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); + return err; + } + v4l2_ctrl_handler_setup(&decoder->hdl); + v4l2_info(sd, "%s decoder driver registered !!\n", sd->name); return 0; @@ -1209,6 +1086,7 @@ static int tvp514x_remove(struct i2c_client *client) struct tvp514x_decoder *decoder = to_decoder(sd); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&decoder->hdl); kfree(decoder); return 0; } -- cgit v1.2.2 From 6c45ec718e3b641da41654b31f35ae3e13306264 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:45:43 -0300 Subject: [media] tvp5150: use the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp5150.c | 157 +++++++++++++----------------------------- 1 file changed, 46 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 58927664d3ea..959d690363bb 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "tvp5150_reg.h" @@ -24,58 +25,14 @@ static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-2)"); -/* supported controls */ -static struct v4l2_queryctrl tvp5150_qctrl[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - .flags = 0, - }, { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 128, - .flags = 0, - }, { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 0x1, - .default_value = 128, - .flags = 0, - }, { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -128, - .maximum = 127, - .step = 0x1, - .default_value = 0, - .flags = 0, - } -}; - struct tvp5150 { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; v4l2_std_id norm; /* Current set standard */ u32 input; u32 output; int enable; - int bright; - int contrast; - int hue; - int sat; }; static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) @@ -83,6 +40,11 @@ static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd) return container_of(sd, struct tvp5150, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct tvp5150, hdl)->sd; +} + static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) { struct i2c_client *c = v4l2_get_subdevdata(sd); @@ -810,64 +772,28 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) tvp5150_write_inittab(sd, tvp5150_init_enable); /* Initialize image preferences */ - tvp5150_write(sd, TVP5150_BRIGHT_CTL, decoder->bright); - tvp5150_write(sd, TVP5150_CONTRAST_CTL, decoder->contrast); - tvp5150_write(sd, TVP5150_SATURATION_CTL, decoder->contrast); - tvp5150_write(sd, TVP5150_HUE_CTL, decoder->hue); + v4l2_ctrl_handler_setup(&decoder->hdl); tvp5150_set_std(sd, decoder->norm); return 0; }; -static int tvp5150_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - v4l2_dbg(1, debug, sd, "g_ctrl called\n"); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = tvp5150_read(sd, TVP5150_BRIGHT_CTL); - return 0; - case V4L2_CID_CONTRAST: - ctrl->value = tvp5150_read(sd, TVP5150_CONTRAST_CTL); - return 0; - case V4L2_CID_SATURATION: - ctrl->value = tvp5150_read(sd, TVP5150_SATURATION_CTL); - return 0; - case V4L2_CID_HUE: - ctrl->value = tvp5150_read(sd, TVP5150_HUE_CTL); - return 0; - } - return -EINVAL; -} - -static int tvp5150_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) { - u8 i, n; - n = ARRAY_SIZE(tvp5150_qctrl); - - for (i = 0; i < n; i++) { - if (ctrl->id != tvp5150_qctrl[i].id) - continue; - if (ctrl->value < tvp5150_qctrl[i].minimum || - ctrl->value > tvp5150_qctrl[i].maximum) - return -ERANGE; - v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n", - ctrl->id, ctrl->value); - break; - } + struct v4l2_subdev *sd = to_sd(ctrl); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->value); + tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val); return 0; case V4L2_CID_CONTRAST: - tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->value); + tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val); return 0; case V4L2_CID_SATURATION: - tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->value); + tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val); return 0; case V4L2_CID_HUE: - tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->value); + tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val); return 0; } return -EINVAL; @@ -995,29 +921,21 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int tvp5150_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - int i; - - v4l2_dbg(1, debug, sd, "queryctrl called\n"); - - for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++) - if (qc->id && qc->id == tvp5150_qctrl[i].id) { - memcpy(qc, &(tvp5150_qctrl[i]), - sizeof(*qc)); - return 0; - } - - return -EINVAL; -} - /* ----------------------------------------------------------------------- */ +static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { + .s_ctrl = tvp5150_s_ctrl, +}; + static const struct v4l2_subdev_core_ops tvp5150_core_ops = { .log_status = tvp5150_log_status, - .g_ctrl = tvp5150_g_ctrl, - .s_ctrl = tvp5150_s_ctrl, - .queryctrl = tvp5150_queryctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, .s_std = tvp5150_s_std, .reset = tvp5150_reset, .g_chip_ident = tvp5150_g_chip_ident, @@ -1077,10 +995,25 @@ static int tvp5150_probe(struct i2c_client *c, core->norm = V4L2_STD_ALL; /* Default is autodetect */ core->input = TVP5150_COMPOSITE1; core->enable = 1; - core->bright = 128; - core->contrast = 128; - core->hue = 0; - core->sat = 128; + + v4l2_ctrl_handler_init(&core->hdl, 4); + v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + sd->ctrl_handler = &core->hdl; + if (core->hdl.error) { + int err = core->hdl.error; + + v4l2_ctrl_handler_free(&core->hdl); + kfree(core); + return err; + } + v4l2_ctrl_handler_setup(&core->hdl); if (debug > 1) tvp5150_log_status(sd); @@ -1090,12 +1023,14 @@ static int tvp5150_probe(struct i2c_client *c, static int tvp5150_remove(struct i2c_client *c) { struct v4l2_subdev *sd = i2c_get_clientdata(c); + struct tvp5150 *decoder = to_tvp5150(sd); v4l2_dbg(1, debug, sd, "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", c->addr << 1); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&decoder->hdl); kfree(to_tvp5150(sd)); return 0; } -- cgit v1.2.2 From 9a775323ee0cbc93b5a1801c7b9264226fb0885c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:45:59 -0300 Subject: [media] vpx3220: use control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vpx3220.c | 137 ++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 91a01b3cdf8c..75301d10a838 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -28,6 +28,7 @@ #include #include #include +#include MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver"); MODULE_AUTHOR("Laurent Pinchart"); @@ -44,16 +45,13 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); struct vpx3220 { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; unsigned char reg[255]; v4l2_std_id norm; int ident; int input; int enable; - int bright; - int contrast; - int hue; - int sat; }; static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd) @@ -61,6 +59,11 @@ static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd) return container_of(sd, struct vpx3220, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct vpx3220, hdl)->sd; +} + static char *inputs[] = { "internal", "composite", "svideo" }; /* ----------------------------------------------------------------------- */ @@ -417,88 +420,26 @@ static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); - break; - - case V4L2_CID_CONTRAST: - v4l2_ctrl_query_fill(qc, 0, 63, 1, 32); - break; - - case V4L2_CID_SATURATION: - v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048); - break; - - case V4L2_CID_HUE: - v4l2_ctrl_query_fill(qc, -512, 511, 1, 0); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vpx3220 *decoder = to_vpx3220(sd); + struct v4l2_subdev *sd = to_sd(ctrl); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - ctrl->value = decoder->bright; - break; + vpx3220_write(sd, 0xe6, ctrl->val); + return 0; case V4L2_CID_CONTRAST: - ctrl->value = decoder->contrast; - break; + /* Bit 7 and 8 is for noise shaping */ + vpx3220_write(sd, 0xe7, ctrl->val + 192); + return 0; case V4L2_CID_SATURATION: - ctrl->value = decoder->sat; - break; + vpx3220_fp_write(sd, 0xa0, ctrl->val); + return 0; case V4L2_CID_HUE: - ctrl->value = decoder->hue; - break; - default: - return -EINVAL; + vpx3220_fp_write(sd, 0x1c, ctrl->val); + return 0; } - return 0; -} - -static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct vpx3220 *decoder = to_vpx3220(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (decoder->bright != ctrl->value) { - decoder->bright = ctrl->value; - vpx3220_write(sd, 0xe6, decoder->bright); - } - break; - case V4L2_CID_CONTRAST: - if (decoder->contrast != ctrl->value) { - /* Bit 7 and 8 is for noise shaping */ - decoder->contrast = ctrl->value; - vpx3220_write(sd, 0xe7, decoder->contrast + 192); - } - break; - case V4L2_CID_SATURATION: - if (decoder->sat != ctrl->value) { - decoder->sat = ctrl->value; - vpx3220_fp_write(sd, 0xa0, decoder->sat); - } - break; - case V4L2_CID_HUE: - if (decoder->hue != ctrl->value) { - decoder->hue = ctrl->value; - vpx3220_fp_write(sd, 0x1c, decoder->hue); - } - break; - default: - return -EINVAL; - } - return 0; + return -EINVAL; } static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) @@ -511,12 +452,20 @@ static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide /* ----------------------------------------------------------------------- */ +static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = { + .s_ctrl = vpx3220_s_ctrl, +}; + static const struct v4l2_subdev_core_ops vpx3220_core_ops = { .g_chip_ident = vpx3220_g_chip_ident, .init = vpx3220_init, - .g_ctrl = vpx3220_g_ctrl, - .s_ctrl = vpx3220_s_ctrl, - .queryctrl = vpx3220_queryctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, .s_std = vpx3220_s_std, }; @@ -558,10 +507,24 @@ static int vpx3220_probe(struct i2c_client *client, decoder->norm = V4L2_STD_PAL; decoder->input = 0; decoder->enable = 1; - decoder->bright = 32768; - decoder->contrast = 32768; - decoder->hue = 32768; - decoder->sat = 32768; + v4l2_ctrl_handler_init(&decoder->hdl, 4); + v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, + V4L2_CID_CONTRAST, 0, 63, 1, 32); + v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, + V4L2_CID_SATURATION, 0, 4095, 1, 2048); + v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops, + V4L2_CID_HUE, -512, 511, 1, 0); + sd->ctrl_handler = &decoder->hdl; + if (decoder->hdl.error) { + int err = decoder->hdl.error; + + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); + return err; + } + v4l2_ctrl_handler_setup(&decoder->hdl); ver = i2c_smbus_read_byte_data(client, 0x00); pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) + @@ -599,9 +562,11 @@ static int vpx3220_probe(struct i2c_client *client, static int vpx3220_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct vpx3220 *decoder = to_vpx3220(sd); v4l2_device_unregister_subdev(sd); - kfree(to_vpx3220(sd)); + v4l2_ctrl_handler_free(&decoder->hdl); + kfree(decoder); return 0; } -- cgit v1.2.2 From 0eb73de019da80facad559c8a5ef21a4b357d8d5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 12 Dec 2010 08:46:15 -0300 Subject: [media] tvp7002: use control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp7002.c | 117 ++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 74 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c index c799e4eb6fcd..b799851bf3d0 100644 --- a/drivers/media/video/tvp7002.c +++ b/drivers/media/video/tvp7002.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "tvp7002_reg.h" MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver"); @@ -421,13 +422,13 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { /* Device definition */ struct tvp7002 { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; const struct tvp7002_config *pdata; int ver; int streaming; const struct tvp7002_preset_definition *current_preset; - u8 gain; }; /* @@ -441,6 +442,11 @@ static inline struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd) return container_of(sd, struct tvp7002, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct tvp7002, hdl)->sd; +} + /* * tvp7002_read - Read a value from a register in an TVP7002 * @sd: ptr to v4l2_subdev struct @@ -605,79 +611,26 @@ static int tvp7002_s_dv_preset(struct v4l2_subdev *sd, return -EINVAL; } -/* - * tvp7002_g_ctrl() - Get a control - * @sd: ptr to v4l2_subdev struct - * @ctrl: ptr to v4l2_control struct - * - * Get a control for a TVP7002 decoder device. - * Returns zero when successful or -EINVAL if register access fails. - */ -static int tvp7002_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct tvp7002 *device = to_tvp7002(sd); - - switch (ctrl->id) { - case V4L2_CID_GAIN: - ctrl->value = device->gain; - return 0; - default: - return -EINVAL; - } -} - /* * tvp7002_s_ctrl() - Set a control - * @sd: ptr to v4l2_subdev struct - * @ctrl: ptr to v4l2_control struct + * @ctrl: ptr to v4l2_ctrl struct * * Set a control in TVP7002 decoder device. * Returns zero when successful or -EINVAL if register access fails. */ -static int tvp7002_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl) { - struct tvp7002 *device = to_tvp7002(sd); + struct v4l2_subdev *sd = to_sd(ctrl); int error = 0; switch (ctrl->id) { case V4L2_CID_GAIN: - tvp7002_write_err(sd, TVP7002_R_FINE_GAIN, - ctrl->value & 0xff, &error); - tvp7002_write_err(sd, TVP7002_G_FINE_GAIN, - ctrl->value & 0xff, &error); - tvp7002_write_err(sd, TVP7002_B_FINE_GAIN, - ctrl->value & 0xff, &error); - - if (error < 0) - return error; - - /* Set only after knowing there is no error */ - device->gain = ctrl->value & 0xff; - return 0; - default: - return -EINVAL; - } -} - -/* - * tvp7002_queryctrl() - Query a control - * @sd: ptr to v4l2_subdev struct - * @qc: ptr to v4l2_queryctrl struct - * - * Query a control of a TVP7002 decoder device. - * Returns zero when successful or -EINVAL if register read fails. - */ -static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_GAIN: - /* - * Gain is supported [0-255, default=0, step=1] - */ - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0); - default: - return -EINVAL; + tvp7002_write_err(sd, TVP7002_R_FINE_GAIN, ctrl->val, &error); + tvp7002_write_err(sd, TVP7002_G_FINE_GAIN, ctrl->val, &error); + tvp7002_write_err(sd, TVP7002_B_FINE_GAIN, ctrl->val, &error); + return error; } + return -EINVAL; } /* @@ -924,7 +877,7 @@ static int tvp7002_log_status(struct v4l2_subdev *sd) device->streaming ? "yes" : "no"); /* Print the current value of the gain control */ - v4l2_info(sd, "Gain: %u\n", device->gain); + v4l2_ctrl_handler_log_status(&device->hdl, sd->name); return 0; } @@ -946,13 +899,21 @@ static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd, return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset); } +static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = { + .s_ctrl = tvp7002_s_ctrl, +}; + /* V4L2 core operation handlers */ static const struct v4l2_subdev_core_ops tvp7002_core_ops = { .g_chip_ident = tvp7002_g_chip_ident, .log_status = tvp7002_log_status, - .g_ctrl = tvp7002_g_ctrl, - .s_ctrl = tvp7002_s_ctrl, - .queryctrl = tvp7002_queryctrl, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = tvp7002_g_register, .s_register = tvp7002_s_register, @@ -977,12 +938,6 @@ static const struct v4l2_subdev_ops tvp7002_ops = { .video = &tvp7002_video_ops, }; -static struct tvp7002 tvp7002_dev = { - .streaming = 0, - .current_preset = tvp7002_presets, - .gain = 0, -}; - /* * tvp7002_probe - Probe a TVP7002 device * @c: ptr to i2c_client struct @@ -1013,14 +968,14 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) return -ENODEV; } - device = kmalloc(sizeof(struct tvp7002), GFP_KERNEL); + device = kzalloc(sizeof(struct tvp7002), GFP_KERNEL); if (!device) return -ENOMEM; - *device = tvp7002_dev; sd = &device->sd; device->pdata = c->dev.platform_data; + device->current_preset = tvp7002_presets; /* Tell v4l2 the device is ready */ v4l2_i2c_subdev_init(sd, c, &tvp7002_ops); @@ -1060,6 +1015,19 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) preset.preset = device->current_preset->preset; error = tvp7002_s_dv_preset(sd, &preset); + v4l2_ctrl_handler_init(&device->hdl, 1); + v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 0); + sd->ctrl_handler = &device->hdl; + if (device->hdl.error) { + int err = device->hdl.error; + + v4l2_ctrl_handler_free(&device->hdl); + kfree(device); + return err; + } + v4l2_ctrl_handler_setup(&device->hdl); + found_error: if (error < 0) kfree(device); @@ -1083,6 +1051,7 @@ static int tvp7002_remove(struct i2c_client *c) "on address 0x%x\n", c->addr); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&device->hdl); kfree(device); return 0; } -- cgit v1.2.2 From 7e996afa81f71ade7870eb26b1b17350b4395646 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 23 Jan 2011 12:33:16 -0200 Subject: [media] vivi: convert to the control framework and add test controls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 228 +++++++++++++++++++++++++++------------------ 1 file changed, 139 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 9ed3831b34bd..66ce69e2833b 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #define VIVI_MODULE_NAME "vivi" @@ -158,13 +159,20 @@ static LIST_HEAD(vivi_devlist); struct vivi_dev { struct list_head vivi_devlist; struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; /* controls */ - int brightness; - int contrast; - int saturation; - int hue; - int volume; + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *hue; + struct v4l2_ctrl *volume; + struct v4l2_ctrl *button; + struct v4l2_ctrl *boolean; + struct v4l2_ctrl *int32; + struct v4l2_ctrl *int64; + struct v4l2_ctrl *menu; + struct v4l2_ctrl *string; spinlock_t slock; struct mutex mutex; @@ -177,6 +185,7 @@ struct vivi_dev { /* Several counters */ unsigned ms; unsigned long jiffies; + unsigned button_pressed; int mv_count; /* Controls bars movement */ @@ -470,14 +479,30 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) dev->width, dev->height, dev->input); gen_text(dev, vbuf, line++ * 16, 16, str); + mutex_lock(&dev->ctrl_handler.lock); snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ", - dev->brightness, - dev->contrast, - dev->saturation, - dev->hue); + dev->brightness->cur.val, + dev->contrast->cur.val, + dev->saturation->cur.val, + dev->hue->cur.val); gen_text(dev, vbuf, line++ * 16, 16, str); - snprintf(str, sizeof(str), " volume %3d ", dev->volume); + snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val); gen_text(dev, vbuf, line++ * 16, 16, str); + snprintf(str, sizeof(str), " int32 %d, int64 %lld ", + dev->int32->cur.val, + dev->int64->cur.val64); + gen_text(dev, vbuf, line++ * 16, 16, str); + snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", + dev->boolean->cur.val, + dev->menu->qmenu[dev->menu->cur.val], + dev->string->cur.string); + mutex_unlock(&dev->ctrl_handler.lock); + gen_text(dev, vbuf, line++ * 16, 16, str); + if (dev->button_pressed) { + dev->button_pressed--; + snprintf(str, sizeof(str), " button pressed!"); + gen_text(dev, vbuf, line++ * 16, 16, str); + } dev->mv_count += 2; @@ -957,80 +982,14 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) } /* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200); - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); - } - return -EINVAL; -} -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +static int vivi_s_ctrl(struct v4l2_ctrl *ctrl) { - struct vivi_dev *dev = video_drvdata(file); + struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler); - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = dev->volume; - return 0; - case V4L2_CID_BRIGHTNESS: - ctrl->value = dev->brightness; - return 0; - case V4L2_CID_CONTRAST: - ctrl->value = dev->contrast; - return 0; - case V4L2_CID_SATURATION: - ctrl->value = dev->saturation; - return 0; - case V4L2_CID_HUE: - ctrl->value = dev->hue; - return 0; - } - return -EINVAL; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct vivi_dev *dev = video_drvdata(file); - struct v4l2_queryctrl qc; - int err; - - qc.id = ctrl->id; - err = vidioc_queryctrl(file, priv, &qc); - if (err < 0) - return err; - if (ctrl->value < qc.minimum || ctrl->value > qc.maximum) - return -ERANGE; - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - dev->volume = ctrl->value; - return 0; - case V4L2_CID_BRIGHTNESS: - dev->brightness = ctrl->value; - return 0; - case V4L2_CID_CONTRAST: - dev->contrast = ctrl->value; - return 0; - case V4L2_CID_SATURATION: - dev->saturation = ctrl->value; - return 0; - case V4L2_CID_HUE: - dev->hue = ctrl->value; - return 0; - } - return -EINVAL; + if (ctrl == dev->button) + dev->button_pressed = 30; + return 0; } /* ------------------------------------------------------------------ @@ -1094,6 +1053,79 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma) return ret; } +static const struct v4l2_ctrl_ops vivi_ctrl_ops = { + .s_ctrl = vivi_s_ctrl, +}; + +#define VIVI_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) + +static const struct v4l2_ctrl_config vivi_ctrl_button = { + .ops = &vivi_ctrl_ops, + .id = VIVI_CID_CUSTOM_BASE + 0, + .name = "Button", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivi_ctrl_boolean = { + .ops = &vivi_ctrl_ops, + .id = VIVI_CID_CUSTOM_BASE + 1, + .name = "Boolean", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static const struct v4l2_ctrl_config vivi_ctrl_int32 = { + .ops = &vivi_ctrl_ops, + .id = VIVI_CID_CUSTOM_BASE + 2, + .name = "Integer 32 Bits", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = -2147483648, + .max = 2147483647, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivi_ctrl_int64 = { + .ops = &vivi_ctrl_ops, + .id = VIVI_CID_CUSTOM_BASE + 3, + .name = "Integer 64 Bits", + .type = V4L2_CTRL_TYPE_INTEGER64, +}; + +static const char * const vivi_ctrl_menu_strings[] = { + "Menu Item 0 (Skipped)", + "Menu Item 1", + "Menu Item 2 (Skipped)", + "Menu Item 3", + "Menu Item 4", + "Menu Item 5 (Skipped)", + NULL, +}; + +static const struct v4l2_ctrl_config vivi_ctrl_menu = { + .ops = &vivi_ctrl_ops, + .id = VIVI_CID_CUSTOM_BASE + 4, + .name = "Menu", + .type = V4L2_CTRL_TYPE_MENU, + .min = 1, + .max = 4, + .def = 3, + .menu_skip_mask = 0x04, + .qmenu = vivi_ctrl_menu_strings, +}; + +static const struct v4l2_ctrl_config vivi_ctrl_string = { + .ops = &vivi_ctrl_ops, + .id = VIVI_CID_CUSTOM_BASE + 5, + .name = "String", + .type = V4L2_CTRL_TYPE_STRING, + .min = 2, + .max = 4, + .step = 1, +}; + static const struct v4l2_file_operations vivi_fops = { .owner = THIS_MODULE, .open = vivi_open, @@ -1120,9 +1152,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_s_input = vidioc_s_input, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static struct video_device vivi_template = { @@ -1153,6 +1182,7 @@ static int vivi_release(void) video_device_node_name(dev->vfd)); video_unregister_device(dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); + v4l2_ctrl_handler_free(&dev->ctrl_handler); kfree(dev); } @@ -1163,6 +1193,7 @@ static int __init vivi_create_instance(int inst) { struct vivi_dev *dev; struct video_device *vfd; + struct v4l2_ctrl_handler *hdl; struct vb2_queue *q; int ret; @@ -1179,11 +1210,29 @@ static int __init vivi_create_instance(int inst) dev->fmt = &formats[0]; dev->width = 640; dev->height = 480; - dev->volume = 200; - dev->brightness = 127; - dev->contrast = 16; - dev->saturation = 127; - dev->hue = 0; + hdl = &dev->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 11); + dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); + dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); + dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 16); + dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 127); + dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL); + dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL); + dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL); + dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL); + dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL); + dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL); + if (hdl->error) { + ret = hdl->error; + goto unreg_dev; + } + dev->v4l2_dev.ctrl_handler = hdl; /* initialize locks */ spin_lock_init(&dev->slock); @@ -1241,6 +1290,7 @@ static int __init vivi_create_instance(int inst) rel_vdev: video_device_release(vfd); unreg_dev: + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); free_dev: kfree(dev); -- cgit v1.2.2 From 5b2830298dc0534eb33277a31f353bb524e2cc2e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Jan 2011 17:32:28 -0300 Subject: [media] vivi: fix compiler warning drivers/media/video/vivi.c:1059: warning: this decimal constant is unsigned only in ISO C90 Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 66ce69e2833b..bd104d0ad36c 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1082,8 +1082,8 @@ static const struct v4l2_ctrl_config vivi_ctrl_int32 = { .id = VIVI_CID_CUSTOM_BASE + 2, .name = "Integer 32 Bits", .type = V4L2_CTRL_TYPE_INTEGER, - .min = -2147483648, - .max = 2147483647, + .min = 0x80000000, + .max = 0x7fffffff, .step = 1, }; -- cgit v1.2.2 From b577f962d27c055571f72ddd73ae3aded39a6261 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Jan 2011 05:05:36 -0300 Subject: [media] pwc: convert to core-assisted locking Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pwc/pwc-if.c | 16 +++------------- drivers/media/video/pwc/pwc-v4l.c | 2 ++ 2 files changed, 5 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index bd1519a4ecb4..4aa70faaae8c 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1098,7 +1098,6 @@ static int pwc_video_open(struct file *file) return -EBUSY; } - mutex_lock(&pdev->modlock); pwc_construct(pdev); /* set min/max sizes correct */ if (!pdev->usb_init) { PWC_DEBUG_OPEN("Doing first time initialization.\n"); @@ -1130,7 +1129,6 @@ static int pwc_video_open(struct file *file) if (i < 0) { PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n"); pwc_free_buffers(pdev); - mutex_unlock(&pdev->modlock); return i; } @@ -1171,7 +1169,6 @@ static int pwc_video_open(struct file *file) if (i) { PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n"); pwc_free_buffers(pdev); - mutex_unlock(&pdev->modlock); return i; } @@ -1181,7 +1178,6 @@ static int pwc_video_open(struct file *file) pdev->vopen++; file->private_data = vdev; - mutex_unlock(&pdev->modlock); PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); return 0; } @@ -1210,7 +1206,6 @@ static int pwc_video_close(struct file *file) PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); pdev = video_get_drvdata(vdev); - mutex_lock(&pdev->modlock); if (pdev->vopen == 0) PWC_DEBUG_MODULE("video_close() called on closed device?\n"); @@ -1248,7 +1243,6 @@ static int pwc_video_close(struct file *file) if (device_hint[hint].pdev == pdev) device_hint[hint].pdev = NULL; } - mutex_unlock(&pdev->modlock); return 0; } @@ -1283,7 +1277,6 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, if (pdev == NULL) return -EFAULT; - mutex_lock(&pdev->modlock); if (pdev->error_status) { rv = -pdev->error_status; /* Something happened, report what. */ goto err_out; @@ -1318,8 +1311,10 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, rv = -ERESTARTSYS; goto err_out; } + mutex_unlock(&pdev->modlock); schedule(); set_current_state(TASK_INTERRUPTIBLE); + mutex_lock(&pdev->modlock); } remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); @@ -1352,10 +1347,8 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, pdev->image_read_pos = 0; pwc_next_image(pdev); } - mutex_unlock(&pdev->modlock); return count; err_out: - mutex_unlock(&pdev->modlock); return rv; } @@ -1372,9 +1365,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) return -EFAULT; /* Start the stream (if not already started) */ - mutex_lock(&pdev->modlock); ret = pwc_isoc_init(pdev); - mutex_unlock(&pdev->modlock); if (ret) return ret; @@ -1398,10 +1389,8 @@ static long pwc_video_ioctl(struct file *file, goto out; pdev = video_get_drvdata(vdev); - mutex_lock(&pdev->modlock); if (!pdev->unplugged) r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl); - mutex_unlock(&pdev->modlock); out: return r; } @@ -1754,6 +1743,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id } memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); pdev->vdev->parent = &intf->dev; + pdev->vdev->lock = &pdev->modlock; strcpy(pdev->vdev->name, name); video_set_drvdata(pdev->vdev, pdev); diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 8ca4d22b4384..8a7e52c3b8f5 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -830,8 +830,10 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) set_current_state(TASK_RUNNING); return -ERESTARTSYS; } + mutex_unlock(&pdev->modlock); schedule(); set_current_state(TASK_INTERRUPTIBLE); + mutex_lock(&pdev->modlock); } remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); -- cgit v1.2.2 From afa38521614dcdfe12c765ff76d4c137a056e905 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 22 Jan 2011 06:34:55 -0300 Subject: [media] pwc: convert to video_ioctl2 Tested with a Logitech QuickCam Pro 4000. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pwc/pwc-if.c | 22 +- drivers/media/video/pwc/pwc-v4l.c | 1034 ++++++++++++++++++------------------- drivers/media/video/pwc/pwc.h | 3 +- 3 files changed, 494 insertions(+), 565 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 4aa70faaae8c..780af5f81642 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -151,8 +151,6 @@ static int pwc_video_close(struct file *file); static ssize_t pwc_video_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); -static long pwc_video_ioctl(struct file *file, - unsigned int ioctlnr, unsigned long arg); static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); static const struct v4l2_file_operations pwc_fops = { @@ -162,7 +160,7 @@ static const struct v4l2_file_operations pwc_fops = { .read = pwc_video_read, .poll = pwc_video_poll, .mmap = pwc_video_mmap, - .unlocked_ioctl = pwc_video_ioctl, + .unlocked_ioctl = video_ioctl2, }; static struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ @@ -1378,23 +1376,6 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) return 0; } -static long pwc_video_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct video_device *vdev = file->private_data; - struct pwc_device *pdev; - long r = -ENODEV; - - if (!vdev) - goto out; - pdev = video_get_drvdata(vdev); - - if (!pdev->unplugged) - r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl); -out: - return r; -} - static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *vdev = file->private_data; @@ -1744,6 +1725,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); pdev->vdev->parent = &intf->dev; pdev->vdev->lock = &pdev->modlock; + pdev->vdev->ioctl_ops = &pwc_ioctl_ops; strcpy(pdev->vdev->name, name); video_set_drvdata(pdev->vdev, pdev); diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 8a7e52c3b8f5..68a5313a52d5 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -341,606 +341,554 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) } -long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) +static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { struct video_device *vdev = video_devdata(file); - struct pwc_device *pdev; - DECLARE_WAITQUEUE(wait, current); - - if (vdev == NULL) - return -EFAULT; - pdev = video_get_drvdata(vdev); - if (pdev == NULL) - return -EFAULT; + struct pwc_device *pdev = video_drvdata(file); + + strcpy(cap->driver, PWC_NAME); + strlcpy(cap->card, vdev->name, sizeof(cap->card)); + usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); + cap->version = PWC_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + return 0; +} -#ifdef CONFIG_USB_PWC_DEBUG - if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) { - v4l_printk_ioctl(cmd); - printk("\n"); - } -#endif - - - switch (cmd) { - /* V4L2 Layer */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\ - "try to use the v4l2 layer\n"); - strcpy(cap->driver,PWC_NAME); - strlcpy(cap->card, vdev->name, sizeof(cap->card)); - usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info)); - cap->version = PWC_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - return 0; - } +static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i) +{ + if (i->index) /* Only one INPUT is supported */ + return -EINVAL; - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; + strcpy(i->name, "usb"); + return 0; +} - if ( i->index ) /* Only one INPUT is supported */ - return -EINVAL; +static int pwc_g_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + return 0; +} - memset(i, 0, sizeof(struct v4l2_input)); - strcpy(i->name, "usb"); - return 0; - } +static int pwc_s_input(struct file *file, void *fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = 0; /* Only one INPUT is supported */ - return 0; - } - case VIDIOC_S_INPUT: - { - int *i = arg; +static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) +{ + int i; - if ( *i ) { /* Only one INPUT is supported */ - PWC_DEBUG_IOCTL("Only one input source is"\ - " supported with this webcam.\n"); - return -EINVAL; - } + for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) { + if (pwc_controls[i].id == c->id) { + PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); + memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl)); return 0; } + } + return -EINVAL; +} - /* TODO: */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *c = arg; - int i; - - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id); - for (i=0; iid) { - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); - memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl)); - return 0; - } - } - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n"); +static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct pwc_device *pdev = video_drvdata(file); + int ret; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = pwc_get_brightness(pdev); + if (c->value < 0) return -EINVAL; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *c = arg; - int ret; - - switch (c->id) - { - case V4L2_CID_BRIGHTNESS: - c->value = pwc_get_brightness(pdev); - if (c->value<0) - return -EINVAL; - return 0; - case V4L2_CID_CONTRAST: - c->value = pwc_get_contrast(pdev); - if (c->value<0) - return -EINVAL; - return 0; - case V4L2_CID_SATURATION: - ret = pwc_get_saturation(pdev, &c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_GAMMA: - c->value = pwc_get_gamma(pdev); - if (c->value<0) - return -EINVAL; - return 0; - case V4L2_CID_RED_BALANCE: - ret = pwc_get_red_gain(pdev, &c->value); - if (ret<0) - return -EINVAL; - c->value >>= 8; - return 0; - case V4L2_CID_BLUE_BALANCE: - ret = pwc_get_blue_gain(pdev, &c->value); - if (ret<0) - return -EINVAL; - c->value >>= 8; - return 0; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = pwc_get_awb(pdev); - if (ret<0) - return -EINVAL; - c->value = (ret == PWC_WB_MANUAL)?0:1; - return 0; - case V4L2_CID_GAIN: - ret = pwc_get_agc(pdev, &c->value); - if (ret<0) - return -EINVAL; - c->value >>= 8; - return 0; - case V4L2_CID_AUTOGAIN: - ret = pwc_get_agc(pdev, &c->value); - if (ret<0) - return -EINVAL; - c->value = (c->value < 0)?1:0; - return 0; - case V4L2_CID_EXPOSURE: - ret = pwc_get_shutter_speed(pdev, &c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_COLOUR_MODE: - ret = pwc_get_colour_mode(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_AUTOCONTOUR: - ret = pwc_get_contour(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value=(c->value == -1?1:0); - return 0; - case V4L2_CID_PRIVATE_CONTOUR: - ret = pwc_get_contour(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value >>= 10; - return 0; - case V4L2_CID_PRIVATE_BACKLIGHT: - ret = pwc_get_backlight(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_FLICKERLESS: - ret = pwc_get_flicker(pdev, &c->value); - if (ret < 0) - return -EINVAL; - c->value=(c->value?1:0); - return 0; - case V4L2_CID_PRIVATE_NOISE_REDUCTION: - ret = pwc_get_dynamic_noise(pdev, &c->value); - if (ret < 0) - return -EINVAL; - return 0; - - case V4L2_CID_PRIVATE_SAVE_USER: - case V4L2_CID_PRIVATE_RESTORE_USER: - case V4L2_CID_PRIVATE_RESTORE_FACTORY: - return -EINVAL; - } + return 0; + case V4L2_CID_CONTRAST: + c->value = pwc_get_contrast(pdev); + if (c->value < 0) return -EINVAL; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *c = arg; - int ret; - - switch (c->id) - { - case V4L2_CID_BRIGHTNESS: - c->value <<= 9; - ret = pwc_set_brightness(pdev, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_CONTRAST: - c->value <<= 10; - ret = pwc_set_contrast(pdev, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_SATURATION: - ret = pwc_set_saturation(pdev, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_GAMMA: - c->value <<= 11; - ret = pwc_set_gamma(pdev, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_RED_BALANCE: - c->value <<= 8; - ret = pwc_set_red_gain(pdev, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_BLUE_BALANCE: - c->value <<= 8; - ret = pwc_set_blue_gain(pdev, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_AUTO_WHITE_BALANCE: - c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO; - ret = pwc_set_awb(pdev, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_EXPOSURE: - c->value <<= 8; - ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_AUTOGAIN: - /* autogain off means nothing without a gain */ - if (c->value == 0) - return 0; - ret = pwc_set_agc(pdev, c->value, 0); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_GAIN: - c->value <<= 8; - ret = pwc_set_agc(pdev, 0, c->value); - if (ret<0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_SAVE_USER: - if (pwc_save_user(pdev)) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_RESTORE_USER: - if (pwc_restore_user(pdev)) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_RESTORE_FACTORY: - if (pwc_restore_factory(pdev)) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_COLOUR_MODE: - ret = pwc_set_colour_mode(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_AUTOCONTOUR: - c->value=(c->value == 1)?-1:0; - ret = pwc_set_contour(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_CONTOUR: - c->value <<= 10; - ret = pwc_set_contour(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_BACKLIGHT: - ret = pwc_set_backlight(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - case V4L2_CID_PRIVATE_FLICKERLESS: - ret = pwc_set_flicker(pdev, c->value); - if (ret < 0) - return -EINVAL; - case V4L2_CID_PRIVATE_NOISE_REDUCTION: - ret = pwc_set_dynamic_noise(pdev, c->value); - if (ret < 0) - return -EINVAL; - return 0; - - } + return 0; + case V4L2_CID_SATURATION: + ret = pwc_get_saturation(pdev, &c->value); + if (ret < 0) return -EINVAL; - } + return 0; + case V4L2_CID_GAMMA: + c->value = pwc_get_gamma(pdev); + if (c->value < 0) + return -EINVAL; + return 0; + case V4L2_CID_RED_BALANCE: + ret = pwc_get_red_gain(pdev, &c->value); + if (ret < 0) + return -EINVAL; + c->value >>= 8; + return 0; + case V4L2_CID_BLUE_BALANCE: + ret = pwc_get_blue_gain(pdev, &c->value); + if (ret < 0) + return -EINVAL; + c->value >>= 8; + return 0; + case V4L2_CID_AUTO_WHITE_BALANCE: + ret = pwc_get_awb(pdev); + if (ret < 0) + return -EINVAL; + c->value = (ret == PWC_WB_MANUAL) ? 0 : 1; + return 0; + case V4L2_CID_GAIN: + ret = pwc_get_agc(pdev, &c->value); + if (ret < 0) + return -EINVAL; + c->value >>= 8; + return 0; + case V4L2_CID_AUTOGAIN: + ret = pwc_get_agc(pdev, &c->value); + if (ret < 0) + return -EINVAL; + c->value = (c->value < 0) ? 1 : 0; + return 0; + case V4L2_CID_EXPOSURE: + ret = pwc_get_shutter_speed(pdev, &c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_COLOUR_MODE: + ret = pwc_get_colour_mode(pdev, &c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_AUTOCONTOUR: + ret = pwc_get_contour(pdev, &c->value); + if (ret < 0) + return -EINVAL; + c->value = (c->value == -1 ? 1 : 0); + return 0; + case V4L2_CID_PRIVATE_CONTOUR: + ret = pwc_get_contour(pdev, &c->value); + if (ret < 0) + return -EINVAL; + c->value >>= 10; + return 0; + case V4L2_CID_PRIVATE_BACKLIGHT: + ret = pwc_get_backlight(pdev, &c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_FLICKERLESS: + ret = pwc_get_flicker(pdev, &c->value); + if (ret < 0) + return -EINVAL; + c->value = (c->value ? 1 : 0); + return 0; + case V4L2_CID_PRIVATE_NOISE_REDUCTION: + ret = pwc_get_dynamic_noise(pdev, &c->value); + if (ret < 0) + return -EINVAL; + return 0; - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - int index; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* We only support two format: the raw format, and YUV */ - index = f->index; - memset(f,0,sizeof(struct v4l2_fmtdesc)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->index = index; - switch(index) - { - case 0: - /* RAW format */ - f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2; - f->flags = V4L2_FMT_FLAG_COMPRESSED; - strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description)); - break; - case 1: - f->pixelformat = V4L2_PIX_FMT_YUV420; - strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description)); - break; - default: - return -EINVAL; - } - return 0; - } + case V4L2_CID_PRIVATE_SAVE_USER: + case V4L2_CID_PRIVATE_RESTORE_USER: + case V4L2_CID_PRIVATE_RESTORE_FACTORY: + return -EINVAL; + } + return -EINVAL; +} - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; +static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) +{ + struct pwc_device *pdev = video_drvdata(file); + int ret; + + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value <<= 9; + ret = pwc_set_brightness(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_CONTRAST: + c->value <<= 10; + ret = pwc_set_contrast(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_SATURATION: + ret = pwc_set_saturation(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_GAMMA: + c->value <<= 11; + ret = pwc_set_gamma(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_RED_BALANCE: + c->value <<= 8; + ret = pwc_set_red_gain(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_BLUE_BALANCE: + c->value <<= 8; + ret = pwc_set_blue_gain(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_AUTO_WHITE_BALANCE: + c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO; + ret = pwc_set_awb(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_EXPOSURE: + c->value <<= 8; + ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_AUTOGAIN: + /* autogain off means nothing without a gain */ + if (c->value == 0) + return 0; + ret = pwc_set_agc(pdev, c->value, 0); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_GAIN: + c->value <<= 8; + ret = pwc_set_agc(pdev, 0, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_SAVE_USER: + if (pwc_save_user(pdev)) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_RESTORE_USER: + if (pwc_restore_user(pdev)) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_RESTORE_FACTORY: + if (pwc_restore_factory(pdev)) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_COLOUR_MODE: + ret = pwc_set_colour_mode(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_AUTOCONTOUR: + c->value = (c->value == 1) ? -1 : 0; + ret = pwc_set_contour(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_CONTOUR: + c->value <<= 10; + ret = pwc_set_contour(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_BACKLIGHT: + ret = pwc_set_backlight(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; + case V4L2_CID_PRIVATE_FLICKERLESS: + ret = pwc_set_flicker(pdev, c->value); + if (ret < 0) + return -EINVAL; + case V4L2_CID_PRIVATE_NOISE_REDUCTION: + ret = pwc_set_dynamic_noise(pdev, c->value); + if (ret < 0) + return -EINVAL; + return 0; - PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y); - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + } + return -EINVAL; +} - pwc_vidioc_fill_fmt(pdev, f); +static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct pwc_device *pdev = video_drvdata(file); + + /* We only support two format: the raw format, and YUV */ + switch (f->index) { + case 0: + /* RAW format */ + f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2; + f->flags = V4L2_FMT_FLAG_COMPRESSED; + strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description)); + break; + case 1: + f->pixelformat = V4L2_PIX_FMT_YUV420; + strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description)); + break; + default: + return -EINVAL; + } + return 0; +} - return 0; - } +static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct pwc_device *pdev = video_drvdata(file); - case VIDIOC_TRY_FMT: - return pwc_vidioc_try_fmt(pdev, arg); + PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n", + pdev->image.x, pdev->image.y); + pwc_vidioc_fill_fmt(pdev, f); + return 0; +} - case VIDIOC_S_FMT: - return pwc_vidioc_set_fmt(pdev, arg); +static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct pwc_device *pdev = video_drvdata(file); - case VIDIOC_G_STD: - { - v4l2_std_id *std = arg; - *std = V4L2_STD_UNKNOWN; - return 0; - } + return pwc_vidioc_try_fmt(pdev, f); +} - case VIDIOC_S_STD: - { - v4l2_std_id *std = arg; - if (*std != V4L2_STD_UNKNOWN) - return -EINVAL; - return 0; - } +static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct pwc_device *pdev = video_drvdata(file); - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *std = arg; - if (std->index != 0) - return -EINVAL; - std->id = V4L2_STD_UNKNOWN; - strlcpy(std->name, "webcam", sizeof(std->name)); - return 0; - } + return pwc_vidioc_set_fmt(pdev, f); +} - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - int nbuffers; +static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) +{ + int nbuffers; - PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count); - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; + PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count); + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; - nbuffers = rb->count; - if (nbuffers < 2) - nbuffers = 2; - else if (nbuffers > pwc_mbufs) - nbuffers = pwc_mbufs; - /* Force to use our # of buffers */ - rb->count = pwc_mbufs; - return 0; - } + nbuffers = rb->count; + if (nbuffers < 2) + nbuffers = 2; + else if (nbuffers > pwc_mbufs) + nbuffers = pwc_mbufs; + /* Force to use our # of buffers */ + rb->count = pwc_mbufs; + return 0; +} - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *buf = arg; - int index; +static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + struct pwc_device *pdev = video_drvdata(file); + int index; - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index); - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n"); - return -EINVAL; - } - if (buf->memory != V4L2_MEMORY_MMAP) { - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n"); - return -EINVAL; - } - index = buf->index; - if (index < 0 || index >= pwc_mbufs) { - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index); - return -EINVAL; - } + PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n"); + return -EINVAL; + } + index = buf->index; + if (index < 0 || index >= pwc_mbufs) { + PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index); + return -EINVAL; + } - memset(buf, 0, sizeof(struct v4l2_buffer)); - buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->index = index; - buf->m.offset = index * pdev->len_per_image; - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); - else - buf->bytesused = pdev->view.size; - buf->field = V4L2_FIELD_NONE; - buf->memory = V4L2_MEMORY_MMAP; - //buf->flags = V4L2_BUF_FLAG_MAPPED; - buf->length = pdev->len_per_image; - - PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index); - PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset); - PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused); + buf->m.offset = index * pdev->len_per_image; + if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) + buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); + else + buf->bytesused = pdev->view.size; + buf->field = V4L2_FIELD_NONE; + buf->memory = V4L2_MEMORY_MMAP; + /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/ + buf->length = pdev->len_per_image; - return 0; - } + PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index); + PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset); + PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused); - case VIDIOC_QBUF: - { - struct v4l2_buffer *buf = arg; + return 0; +} - PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index); - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (buf->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - if (buf->index >= pwc_mbufs) - return -EINVAL; +static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index); + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (buf->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + if (buf->index >= pwc_mbufs) + return -EINVAL; - buf->flags |= V4L2_BUF_FLAG_QUEUED; - buf->flags &= ~V4L2_BUF_FLAG_DONE; + buf->flags |= V4L2_BUF_FLAG_QUEUED; + buf->flags &= ~V4L2_BUF_FLAG_DONE; - return 0; - } + return 0; +} - case VIDIOC_DQBUF: - { - struct v4l2_buffer *buf = arg; - int ret; +static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) +{ + DECLARE_WAITQUEUE(wait, current); + struct pwc_device *pdev = video_drvdata(file); + int ret; - PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); + PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; - /* Add ourselves to the frame wait-queue. - - FIXME: needs auditing for safety. - QUESTION: In what respect? I think that using the - frameq is safe now. - */ - add_wait_queue(&pdev->frameq, &wait); - while (pdev->full_frames == NULL) { - if (pdev->error_status) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -pdev->error_status; - } + add_wait_queue(&pdev->frameq, &wait); + while (pdev->full_frames == NULL) { + if (pdev->error_status) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -pdev->error_status; + } - if (signal_pending(current)) { - remove_wait_queue(&pdev->frameq, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - mutex_unlock(&pdev->modlock); - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - mutex_lock(&pdev->modlock); - } + if (signal_pending(current)) { remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + mutex_unlock(&pdev->modlock); + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + mutex_lock(&pdev->modlock); + } + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); - /* Decompress data in pdev->images[pdev->fill_image] */ - ret = pwc_handle_frame(pdev); - if (ret) - return -EFAULT; - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); - - buf->index = pdev->fill_image; - if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) - buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); - else - buf->bytesused = pdev->view.size; - buf->flags = V4L2_BUF_FLAG_MAPPED; - buf->field = V4L2_FIELD_NONE; - do_gettimeofday(&buf->timestamp); - buf->sequence = 0; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = pdev->fill_image * pdev->len_per_image; - buf->length = pdev->len_per_image; - pwc_next_image(pdev); - - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused); - PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); - return 0; + PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); + /* Decompress data in pdev->images[pdev->fill_image] */ + ret = pwc_handle_frame(pdev); + if (ret) + return -EFAULT; + PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); + + buf->index = pdev->fill_image; + if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) + buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); + else + buf->bytesused = pdev->view.size; + buf->flags = V4L2_BUF_FLAG_MAPPED; + buf->field = V4L2_FIELD_NONE; + do_gettimeofday(&buf->timestamp); + buf->sequence = 0; + buf->memory = V4L2_MEMORY_MMAP; + buf->m.offset = pdev->fill_image * pdev->len_per_image; + buf->length = pdev->len_per_image; + pwc_next_image(pdev); + + PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index); + PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length); + PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset); + PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused); + PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); + return 0; - } +} - case VIDIOC_STREAMON: - { - return pwc_isoc_init(pdev); - } +static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) +{ + struct pwc_device *pdev = video_drvdata(file); - case VIDIOC_STREAMOFF: - { - pwc_isoc_cleanup(pdev); - return 0; - } + return pwc_isoc_init(pdev); +} - case VIDIOC_ENUM_FRAMESIZES: - { - struct v4l2_frmsizeenum *fsize = arg; - unsigned int i = 0, index = fsize->index; - - if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { - for (i = 0; i < PSZ_MAX; i++) { - if (pdev->image_mask & (1UL << i)) { - if (!index--) { - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pwc_image_sizes[i].x; - fsize->discrete.height = pwc_image_sizes[i].y; - return 0; - } - } - } - } else if (fsize->index == 0 && - ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || - (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = pdev->abs_max.x; - fsize->discrete.height = pdev->abs_max.y; - return 0; - } - return -EINVAL; - } +static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) +{ + struct pwc_device *pdev = video_drvdata(file); - case VIDIOC_ENUM_FRAMEINTERVALS: - { - struct v4l2_frmivalenum *fival = arg; - int size = -1; - unsigned int i; - - for (i = 0; i < PSZ_MAX; i++) { - if (pwc_image_sizes[i].x == fival->width && - pwc_image_sizes[i].y == fival->height) { - size = i; - break; + pwc_isoc_cleanup(pdev); + return 0; +} + +static int pwc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct pwc_device *pdev = video_drvdata(file); + unsigned int i = 0, index = fsize->index; + + if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { + for (i = 0; i < PSZ_MAX; i++) { + if (pdev->image_mask & (1UL << i)) { + if (!index--) { + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = pwc_image_sizes[i].x; + fsize->discrete.height = pwc_image_sizes[i].y; + return 0; } } + } + } else if (fsize->index == 0 && + ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || + (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = pdev->abs_max.x; + fsize->discrete.height = pdev->abs_max.y; + return 0; + } + return -EINVAL; +} - /* TODO: Support raw format */ - if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) { - return -EINVAL; - } +static int pwc_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct pwc_device *pdev = video_drvdata(file); + int size = -1; + unsigned int i; + + for (i = 0; i < PSZ_MAX; i++) { + if (pwc_image_sizes[i].x == fival->width && + pwc_image_sizes[i].y == fival->height) { + size = i; + break; + } + } - i = pwc_get_fps(pdev, fival->index, size); - if (!i) - return -EINVAL; + /* TODO: Support raw format */ + if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) + return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete.numerator = 1; - fival->discrete.denominator = i; + i = pwc_get_fps(pdev, fival->index, size); + if (!i) + return -EINVAL; - return 0; - } + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.numerator = 1; + fival->discrete.denominator = i; - default: - return pwc_ioctl(pdev, cmd, arg); - } /* ..switch */ return 0; } +static long pwc_default(struct file *file, void *fh, int cmd, void *arg) +{ + struct pwc_device *pdev = video_drvdata(file); + + return pwc_ioctl(pdev, cmd, arg); +} + +const struct v4l2_ioctl_ops pwc_ioctl_ops = { + .vidioc_querycap = pwc_querycap, + .vidioc_enum_input = pwc_enum_input, + .vidioc_g_input = pwc_g_input, + .vidioc_s_input = pwc_s_input, + .vidioc_enum_fmt_vid_cap = pwc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, + .vidioc_queryctrl = pwc_queryctrl, + .vidioc_g_ctrl = pwc_g_ctrl, + .vidioc_s_ctrl = pwc_s_ctrl, + .vidioc_reqbufs = pwc_reqbufs, + .vidioc_querybuf = pwc_querybuf, + .vidioc_qbuf = pwc_qbuf, + .vidioc_dqbuf = pwc_dqbuf, + .vidioc_streamon = pwc_streamon, + .vidioc_streamoff = pwc_streamoff, + .vidioc_enum_framesizes = pwc_enum_framesizes, + .vidioc_enum_frameintervals = pwc_enum_frameintervals, + .vidioc_default = pwc_default, +}; + + /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 16bbc6df9b07..e947766337d6 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h @@ -339,8 +339,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power); /* Private ioctl()s; see pwc-ioctl.h */ extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); -/** Functions in pwc-v4l.c */ -extern long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg); +extern const struct v4l2_ioctl_ops pwc_ioctl_ops; /** pwc-uncompress.c */ /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ -- cgit v1.2.2 From cbfb3daa66bc43f4e2d4f2063db7472a8b2837f5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 22 Jan 2011 06:36:02 -0300 Subject: [media] cpia2: convert to video_ioctl2 Unable to test this due to lack of hardware. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cpia2/cpia2_v4l.c | 373 ++++++++++++---------------------- 1 file changed, 126 insertions(+), 247 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 9bad39842936..363fe098b748 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -395,10 +395,14 @@ static int sync(struct camera_data *cam, int frame_nr) * *****************************************************************************/ -static int ioctl_set_gpio(void *arg, struct camera_data *cam) +static long cpia2_default(struct file *file, void *fh, int cmd, void *arg) { + struct camera_data *cam = video_drvdata(file); __u32 gpio_val; + if (cmd != CPIA2_CID_GPIO) + return -EINVAL; + gpio_val = *(__u32*) arg; if (gpio_val &~ 0xFFU) @@ -415,11 +419,10 @@ static int ioctl_set_gpio(void *arg, struct camera_data *cam) * *****************************************************************************/ -static int ioctl_querycap(void *arg, struct camera_data *cam) +static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *vc) { - struct v4l2_capability *vc = arg; + struct camera_data *cam = video_drvdata(file); - memset(vc, 0, sizeof(*vc)); strcpy(vc->driver, "cpia2"); if (cam->params.pnp_id.product == 0x151) @@ -479,22 +482,26 @@ static int ioctl_querycap(void *arg, struct camera_data *cam) * *****************************************************************************/ -static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam) +static int cpia2_enum_input(struct file *file, void *fh, struct v4l2_input *i) { - struct v4l2_input *i = arg; - - if(ioclt_nr != VIDIOC_G_INPUT) { - if (i->index != 0) - return -EINVAL; - } - - memset(i, 0, sizeof(*i)); + if (i->index) + return -EINVAL; strcpy(i->name, "Camera"); i->type = V4L2_INPUT_TYPE_CAMERA; + return 0; +} +static int cpia2_g_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; return 0; } +static int cpia2_s_input(struct file *file, void *fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + /****************************************************************************** * * ioctl_enum_fmt @@ -503,9 +510,9 @@ static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_enum_fmt(void *arg,struct camera_data *cam) +static int cpia2_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) { - struct v4l2_fmtdesc *f = arg; int index = f->index; if (index < 0 || index > 1) @@ -539,12 +546,10 @@ static int ioctl_enum_fmt(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_try_fmt(void *arg,struct camera_data *cam) +static int cpia2_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) { - struct v4l2_format *f = arg; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + struct camera_data *cam = video_drvdata(file); if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) @@ -603,12 +608,17 @@ static int ioctl_try_fmt(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh) +static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh, + struct v4l2_format *f) { - struct v4l2_format *f = arg; + struct camera_data *cam = video_drvdata(file); + struct cpia2_fh *fh = _fh; int err, frame; - err = ioctl_try_fmt(arg, cam); + err = v4l2_prio_check(&cam->prio, fh->prio); + if (err) + return err; + err = cpia2_try_fmt_vid_cap(file, _fh, f); if(err != 0) return err; @@ -658,12 +668,10 @@ static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh) * *****************************************************************************/ -static int ioctl_get_fmt(void *arg,struct camera_data *cam) +static int cpia2_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) { - struct v4l2_format *f = arg; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + struct camera_data *cam = video_drvdata(file); f->fmt.pix.width = cam->width; f->fmt.pix.height = cam->height; @@ -686,9 +694,9 @@ static int ioctl_get_fmt(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_cropcap(void *arg,struct camera_data *cam) +static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c) { - struct v4l2_cropcap *c = arg; + struct camera_data *cam = video_drvdata(file); if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -715,9 +723,9 @@ static int ioctl_cropcap(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_queryctrl(void *arg,struct camera_data *cam) +static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) { - struct v4l2_queryctrl *c = arg; + struct camera_data *cam = video_drvdata(file); int i; for(i=0; iname, 0, sizeof(m->name)); - m->reserved = 0; + struct camera_data *cam = video_drvdata(file); switch(m->id) { case CPIA2_CID_FLICKER_MODE: @@ -837,9 +842,9 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_g_ctrl(void *arg,struct camera_data *cam) +static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) { - struct v4l2_control *c = arg; + struct camera_data *cam = video_drvdata(file); switch(c->id) { case V4L2_CID_BRIGHTNESS: @@ -955,9 +960,9 @@ static int ioctl_g_ctrl(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_s_ctrl(void *arg,struct camera_data *cam) +static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) { - struct v4l2_control *c = arg; + struct camera_data *cam = video_drvdata(file); int i; int retval = 0; @@ -1031,9 +1036,9 @@ static int ioctl_s_ctrl(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam) +static int cpia2_g_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) { - struct v4l2_jpegcompression *parms = arg; + struct camera_data *cam = video_drvdata(file); memset(parms, 0, sizeof(*parms)); @@ -1072,9 +1077,9 @@ static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam) +static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompression *parms) { - struct v4l2_jpegcompression *parms = arg; + struct camera_data *cam = video_drvdata(file); DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", parms->APP_len, parms->COM_len); @@ -1121,9 +1126,9 @@ static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_reqbufs(void *arg,struct camera_data *cam) +static int cpia2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) { - struct v4l2_requestbuffers *req = arg; + struct camera_data *cam = video_drvdata(file); if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || req->memory != V4L2_MEMORY_MMAP) @@ -1144,9 +1149,9 @@ static int ioctl_reqbufs(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_querybuf(void *arg,struct camera_data *cam) +static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct v4l2_buffer *buf = arg; + struct camera_data *cam = video_drvdata(file); if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || buf->index > cam->num_frames) @@ -1192,9 +1197,9 @@ static int ioctl_querybuf(void *arg,struct camera_data *cam) * *****************************************************************************/ -static int ioctl_qbuf(void *arg,struct camera_data *cam) +static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct v4l2_buffer *buf = arg; + struct camera_data *cam = video_drvdata(file); if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || buf->memory != V4L2_MEMORY_MMAP || @@ -1248,9 +1253,9 @@ static int find_earliest_filled_buffer(struct camera_data *cam) * *****************************************************************************/ -static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) +static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct v4l2_buffer *buf = arg; + struct camera_data *cam = video_drvdata(file); int frame; if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || @@ -1296,210 +1301,56 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) return 0; } -/****************************************************************************** - * - * cpia2_ioctl - * - *****************************************************************************/ -static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg) +static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p) { - struct camera_data *cam = video_drvdata(file); - long retval = 0; - - if (!cam) - return -ENOTTY; - - if (!cam->present) - return -ENODEV; - - /* Priority check */ - switch (cmd) { - case VIDIOC_S_FMT: - { - struct cpia2_fh *fh = file->private_data; - retval = v4l2_prio_check(&cam->prio, fh->prio); - if (retval) - return retval; - break; - } - default: - break; - } - - switch (cmd) { - /* CPIA2 extension to Video4Linux API */ - case CPIA2_IOC_SET_GPIO: - retval = ioctl_set_gpio(arg, cam); - break; - case VIDIOC_QUERYCAP: - retval = ioctl_querycap(arg,cam); - break; - - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - retval = ioctl_input(cmd, arg, cam); - break; - - case VIDIOC_ENUM_FMT: - retval = ioctl_enum_fmt(arg,cam); - break; - case VIDIOC_TRY_FMT: - retval = ioctl_try_fmt(arg,cam); - break; - case VIDIOC_G_FMT: - retval = ioctl_get_fmt(arg,cam); - break; - case VIDIOC_S_FMT: - retval = ioctl_set_fmt(arg,cam,file->private_data); - break; + struct cpia2_fh *fh = _fh; - case VIDIOC_CROPCAP: - retval = ioctl_cropcap(arg,cam); - break; - case VIDIOC_G_CROP: - case VIDIOC_S_CROP: - // TODO: I think cropping can be implemented - SJB - retval = -EINVAL; - break; - - case VIDIOC_QUERYCTRL: - retval = ioctl_queryctrl(arg,cam); - break; - case VIDIOC_QUERYMENU: - retval = ioctl_querymenu(arg,cam); - break; - case VIDIOC_G_CTRL: - retval = ioctl_g_ctrl(arg,cam); - break; - case VIDIOC_S_CTRL: - retval = ioctl_s_ctrl(arg,cam); - break; - - case VIDIOC_G_JPEGCOMP: - retval = ioctl_g_jpegcomp(arg,cam); - break; - case VIDIOC_S_JPEGCOMP: - retval = ioctl_s_jpegcomp(arg,cam); - break; - - case VIDIOC_G_PRIORITY: - { - struct cpia2_fh *fh = file->private_data; - *(enum v4l2_priority*)arg = fh->prio; - break; - } - case VIDIOC_S_PRIORITY: - { - struct cpia2_fh *fh = file->private_data; - enum v4l2_priority prio; - prio = *(enum v4l2_priority*)arg; - if(cam->streaming && - prio != fh->prio && - fh->prio == V4L2_PRIORITY_RECORD) { - /* Can't drop record priority while streaming */ - retval = -EBUSY; - } else if(prio == V4L2_PRIORITY_RECORD && - prio != fh->prio && - v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) { - /* Only one program can record at a time */ - retval = -EBUSY; - } else { - retval = v4l2_prio_change(&cam->prio, &fh->prio, prio); - } - break; - } - - case VIDIOC_REQBUFS: - retval = ioctl_reqbufs(arg,cam); - break; - case VIDIOC_QUERYBUF: - retval = ioctl_querybuf(arg,cam); - break; - case VIDIOC_QBUF: - retval = ioctl_qbuf(arg,cam); - break; - case VIDIOC_DQBUF: - retval = ioctl_dqbuf(arg,cam,file); - break; - case VIDIOC_STREAMON: - { - int type; - DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); - type = *(int*)arg; - if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - retval = -EINVAL; - - if(!cam->streaming) { - retval = cpia2_usb_stream_start(cam, - cam->params.camera_state.stream_mode); - } else { - retval = -EINVAL; - } - - break; - } - case VIDIOC_STREAMOFF: - { - int type; - DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); - type = *(int*)arg; - if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - retval = -EINVAL; - - if(cam->streaming) { - retval = cpia2_usb_stream_stop(cam); - } else { - retval = -EINVAL; - } - - break; - } - - case VIDIOC_ENUMOUTPUT: - case VIDIOC_G_OUTPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_G_MODULATOR: - case VIDIOC_S_MODULATOR: - - case VIDIOC_ENUMAUDIO: - case VIDIOC_G_AUDIO: - case VIDIOC_S_AUDIO: + *p = fh->prio; + return 0; +} - case VIDIOC_ENUMAUDOUT: - case VIDIOC_G_AUDOUT: - case VIDIOC_S_AUDOUT: +static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio) +{ + struct camera_data *cam = video_drvdata(file); + struct cpia2_fh *fh = fh; - case VIDIOC_ENUMSTD: - case VIDIOC_QUERYSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: + if (cam->streaming && prio != fh->prio && + fh->prio == V4L2_PRIORITY_RECORD) + /* Can't drop record priority while streaming */ + return -EBUSY; - case VIDIOC_G_TUNER: - case VIDIOC_S_TUNER: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: + if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio && + v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) + /* Only one program can record at a time */ + return -EBUSY; + return v4l2_prio_change(&cam->prio, &fh->prio, prio); +} - case VIDIOC_OVERLAY: - case VIDIOC_G_FBUF: - case VIDIOC_S_FBUF: +static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct camera_data *cam = video_drvdata(file); - case VIDIOC_G_PARM: - case VIDIOC_S_PARM: - retval = -EINVAL; - break; - default: - retval = -ENOIOCTLCMD; - break; - } + DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); + if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; - return retval; + if (!cam->streaming) + return cpia2_usb_stream_start(cam, + cam->params.camera_state.stream_mode); + return -EINVAL; } -static long cpia2_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { - return video_usercopy(file, cmd, arg, cpia2_do_ioctl); + struct camera_data *cam = video_drvdata(file); + + DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); + if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (cam->streaming) + return cpia2_usb_stream_stop(cam); + return -EINVAL; } /****************************************************************************** @@ -1550,6 +1401,33 @@ static void reset_camera_struct_v4l(struct camera_data *cam) v4l2_prio_init(&cam->prio); } +static const struct v4l2_ioctl_ops cpia2_ioctl_ops = { + .vidioc_querycap = cpia2_querycap, + .vidioc_enum_input = cpia2_enum_input, + .vidioc_g_input = cpia2_g_input, + .vidioc_s_input = cpia2_s_input, + .vidioc_enum_fmt_vid_cap = cpia2_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap, + .vidioc_queryctrl = cpia2_queryctrl, + .vidioc_querymenu = cpia2_querymenu, + .vidioc_g_ctrl = cpia2_g_ctrl, + .vidioc_s_ctrl = cpia2_s_ctrl, + .vidioc_g_jpegcomp = cpia2_g_jpegcomp, + .vidioc_s_jpegcomp = cpia2_s_jpegcomp, + .vidioc_cropcap = cpia2_cropcap, + .vidioc_reqbufs = cpia2_reqbufs, + .vidioc_querybuf = cpia2_querybuf, + .vidioc_qbuf = cpia2_qbuf, + .vidioc_dqbuf = cpia2_dqbuf, + .vidioc_streamon = cpia2_streamon, + .vidioc_streamoff = cpia2_streamoff, + .vidioc_g_priority = cpia2_g_priority, + .vidioc_s_priority = cpia2_s_priority, + .vidioc_default = cpia2_default, +}; + /*** * The v4l video device structure initialized for this device ***/ @@ -1559,7 +1437,7 @@ static const struct v4l2_file_operations cpia2_fops = { .release = cpia2_close, .read = cpia2_v4l_read, .poll = cpia2_v4l_poll, - .unlocked_ioctl = cpia2_ioctl, + .unlocked_ioctl = video_ioctl2, .mmap = cpia2_mmap, }; @@ -1567,6 +1445,7 @@ static struct video_device cpia2_template = { /* I could not find any place for the old .initialize initializer?? */ .name = "CPiA2 Camera", .fops = &cpia2_fops, + .ioctl_ops = &cpia2_ioctl_ops, .release = video_device_release, }; -- cgit v1.2.2 From 8e030cabf1bb8601ad3efe09b9dc65a441a294ec Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Thu, 20 Jan 2011 03:05:08 -0300 Subject: [media] tm6000: add/rework reg.defines Rework registers defines. Add TM6000 specific registers defines. Add marks and comments for TM6010 specific registers. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-regs.h | 63 ++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-regs.h b/drivers/staging/tm6000/tm6000-regs.h index 1f0ced8fa20f..5375a8347374 100644 --- a/drivers/staging/tm6000/tm6000-regs.h +++ b/drivers/staging/tm6000/tm6000-regs.h @@ -97,6 +97,34 @@ enum { TM6000_URB_MSG_ERR, }; +/* Define specific TM6000 Video decoder registers */ +#define TM6000_REQ07_RD8_TEST_SEL 0x07, 0xd8 +#define TM6000_REQ07_RD9_A_SIM_SEL 0x07, 0xd9 +#define TM6000_REQ07_RDA_CLK_SEL 0x07, 0xda +#define TM6000_REQ07_RDB_OUT_SEL 0x07, 0xdb +#define TM6000_REQ07_RDC_NSEL_I2S 0x07, 0xdc +#define TM6000_REQ07_RDD_GPIO2_MDRV 0x07, 0xdd +#define TM6000_REQ07_RDE_GPIO1_MDRV 0x07, 0xde +#define TM6000_REQ07_RDF_PWDOWN_ACLK 0x07, 0xdf +#define TM6000_REQ07_RE0_VADC_REF_CTL 0x07, 0xe0 +#define TM6000_REQ07_RE1_VADC_DACLIMP 0x07, 0xe1 +#define TM6000_REQ07_RE2_VADC_STATUS_CTL 0x07, 0xe2 +#define TM6000_REQ07_RE3_VADC_INP_LPF_SEL1 0x07, 0xe3 +#define TM6000_REQ07_RE4_VADC_TARGET1 0x07, 0xe4 +#define TM6000_REQ07_RE5_VADC_INP_LPF_SEL2 0x07, 0xe5 +#define TM6000_REQ07_RE6_VADC_TARGET2 0x07, 0xe6 +#define TM6000_REQ07_RE7_VADC_AGAIN_CTL 0x07, 0xe7 +#define TM6000_REQ07_RE8_VADC_PWDOWN_CTL 0x07, 0xe8 +#define TM6000_REQ07_RE9_VADC_INPUT_CTL1 0x07, 0xe9 +#define TM6000_REQ07_REA_VADC_INPUT_CTL2 0x07, 0xea +#define TM6000_REQ07_REB_VADC_AADC_MODE 0x07, 0xeb +#define TM6000_REQ07_REC_VADC_AADC_LVOL 0x07, 0xec +#define TM6000_REQ07_RED_VADC_AADC_RVOL 0x07, 0xed +#define TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL 0x07, 0xee +#define TM6000_REQ07_REF_VADC_GAIN_MAP_CTL 0x07, 0xef +#define TM6000_REQ07_RFD_BIST_ERR_VST_LOW 0x07, 0xfd +#define TM6000_REQ07_RFE_BIST_ERR_VST_HIGH 0x07, 0xfe + /* Define TM6000/TM6010 Video decoder registers */ #define TM6010_REQ07_R00_VIDEO_CONTROL0 0x07, 0x00 #define TM6010_REQ07_R01_VIDEO_CONTROL1 0x07, 0x01 @@ -241,6 +269,7 @@ enum { #define TM6010_REQ07_RC9_VEND1 0x07, 0xc9 #define TM6010_REQ07_RCA_VEND0 0x07, 0xca #define TM6010_REQ07_RCB_DELAY 0x07, 0xcb +/* ONLY for TM6010 */ #define TM6010_REQ07_RCC_ACTIVE_VIDEO_IF 0x07, 0xcc #define TM6010_REQ07_RD0_USB_PERIPHERY_CONTROL 0x07, 0xd0 #define TM6010_REQ07_RD1_ADDR_FOR_REQ1 0x07, 0xd1 @@ -250,32 +279,59 @@ enum { #define TM6010_REQ07_RD5_POWERSAVE 0x07, 0xd5 #define TM6010_REQ07_RD6_ENDP_REQ1_REQ2 0x07, 0xd6 #define TM6010_REQ07_RD7_ENDP_REQ3_REQ4 0x07, 0xd7 +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR 0x07, 0xd8 +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR_BSIZE 0x07, 0xd9 +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR_WAKEUP_SEL 0x07, 0xda +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR_WAKEUP_ADD 0x07, 0xdb +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR_LEADER1 0x07, 0xdc +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR_LEADER0 0x07, 0xdd +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR_PULSE_CNT1 0x07, 0xde +/* ONLY for TM6010 */ #define TM6010_REQ07_RD8_IR_PULSE_CNT0 0x07, 0xdf +/* ONLY for TM6010 */ #define TM6010_REQ07_RE0_DVIDEO_SOURCE 0x07, 0xe0 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE0_DVIDEO_SOURCE_IF 0x07, 0xe1 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE2_OUT_SEL2 0x07, 0xe2 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE3_OUT_SEL1 0x07, 0xe3 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE4_OUT_SEL0 0x07, 0xe4 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE5_REMOTE_WAKEUP 0x07, 0xe5 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE7_PUB_GPIO 0x07, 0xe7 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE8_TYPESEL_MOS_I2S 0x07, 0xe8 +/* ONLY for TM6010 */ #define TM6010_REQ07_RE9_TYPESEL_MOS_TS 0x07, 0xe9 +/* ONLY for TM6010 */ #define TM6010_REQ07_REA_TYPESEL_MOS_CCIR 0x07, 0xea +/* ONLY for TM6010 */ #define TM6010_REQ07_RF0_BIST_CRC_RESULT0 0x07, 0xf0 +/* ONLY for TM6010 */ #define TM6010_REQ07_RF1_BIST_CRC_RESULT1 0x07, 0xf1 +/* ONLY for TM6010 */ #define TM6010_REQ07_RF2_BIST_CRC_RESULT2 0x07, 0xf2 +/* ONLY for TM6010 */ #define TM6010_REQ07_RF3_BIST_CRC_RESULT3 0x07, 0xf3 +/* ONLY for TM6010 */ #define TM6010_REQ07_RF4_BIST_ERR_VST2 0x07, 0xf4 +/* ONLY for TM6010 */ #define TM6010_REQ07_RF5_BIST_ERR_VST1 0x07, 0xf5 +/* ONLY for TM6010 */ #define TM6010_REQ07_RF6_BIST_ERR_VST0 0x07, 0xf6 +/* ONLY for TM6010 */ #define TM6010_REQ07_RF7_BIST 0x07, 0xf7 +/* ONLY for TM6010 */ #define TM6010_REQ07_RFE_POWER_DOWN 0x07, 0xfe #define TM6010_REQ07_RFF_SOFT_RESET 0x07, 0xff @@ -477,7 +533,8 @@ enum { #define TM6010_REQ05_RC4_DATA_FIFO14 0x05, 0xf8 #define TM6010_REQ05_RC4_DATA_FIFO15 0x05, 0xfc -/* Define TM6000/TM6010 Audio decoder registers */ +/* Define TM6010 Audio decoder registers */ +/* This core available only in TM6010 */ #define TM6010_REQ08_R00_A_VERSION 0x08, 0x00 #define TM6010_REQ08_R01_A_INIT 0x08, 0x01 #define TM6010_REQ08_R02_A_FIX_GAIN_CTRL 0x08, 0x02 @@ -518,7 +575,7 @@ enum { #define TM6010_REQ08_R27_A_NOISE_AMP 0x08, 0x27 #define TM6010_REQ08_R28_A_AUDIO_MODE_RES 0x08, 0x28 -/* Define TM6000/TM6010 Video ADC registers */ +/* Define TM6010 Video ADC registers */ #define TM6010_REQ08_RE0_ADC_REF 0x08, 0xe0 #define TM6010_REQ08_RE1_DAC_CLMP 0x08, 0xe1 #define TM6010_REQ08_RE2_POWER_DOWN_CTRL1 0x08, 0xe2 @@ -534,7 +591,7 @@ enum { #define TM6010_REQ08_REC_REVERSE_YC_CTRL 0x08, 0xec #define TM6010_REQ08_RED_GAIN_SEL 0x08, 0xed -/* Define TM6000/TM6010 Audio ADC registers */ +/* Define TM6010 Audio ADC registers */ #define TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG 0x08, 0xf0 #define TM6010_REQ08_RF1_AADC_POWER_DOWN 0x08, 0xf1 #define TM6010_REQ08_RF2_LEFT_CHANNEL_VOL 0x08, 0xf2 -- cgit v1.2.2 From 2b97e2201eb76d56c4901d39e8ed276f2de0e2e9 Mon Sep 17 00:00:00 2001 From: iceberg Date: Fri, 21 Jan 2011 15:00:25 -0300 Subject: [media] double mutex lock in drivers/media/radio/si470x/radio-si470x- KERNEL_VERSION: 2.6.37 common.c in function ssize_t si470x_fops_read. 1. First mutex_lock on &radio->lock in line 441 2. Second in line 462 I think that mutex in line 462 is not needed. 433static ssize_t si470x_fops_read(struct file *file, char __user *buf, 434 size_t count, loff_t *ppos) 435{ .... 441 mutex_lock(&radio->lock); 442 if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) 443 si470x_rds_on(radio); 444 445 /* block if no new data available */ 446 while (radio->wr_index == radio->rd_index) { 447 if (file->f_flags & O_NONBLOCK) { 448 retval = -EWOULDBLOCK; 449 goto done; 450 } 451 if (wait_event_interruptible(radio->read_queue, 452 radio->wr_index != radio->rd_index) < 0) { 453 retval = -EINTR; 454 goto done; 455 } 456 } 457 458 /* calculate block count from byte count */ 459 count /= 3; 460 461 /* copy RDS block out of internal buffer and to user buffer */ 462 mutex_lock(&radio->lock); Found by Linux Device Drivers Verification Project Remove second mutex. Signed-off-by: Alexander Strakh Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-common.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 60c176fe328e..38ae6cd65790 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -460,7 +460,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, count /= 3; /* copy RDS block out of internal buffer and to user buffer */ - mutex_lock(&radio->lock); while (block_count < count) { if (radio->rd_index == radio->wr_index) break; -- cgit v1.2.2 From b8bc77db1e23c6e141734511db873902c66bec8c Mon Sep 17 00:00:00 2001 From: Alina Friedrichsen Date: Sun, 23 Jan 2011 12:27:05 -0300 Subject: [media] tuner-xc2028: More firmware loading retries My Hauppauge WinTV HVR-1400 needs sometimes more then only one retry to load the firmware successfully. Signed-off-by: Alina Friedrichsen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tuner-xc2028.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index b6ce528e1889..d95f3b256e30 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -685,7 +685,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, { struct xc2028_data *priv = fe->tuner_priv; struct firmware_properties new_fw; - int rc = 0, is_retry = 0; + int rc = 0, retry_count = 0; u16 version, hwmodel; v4l2_std_id std0; @@ -855,9 +855,9 @@ read_not_reliable: fail: memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); - if (!is_retry) { + if (retry_count < 8) { msleep(50); - is_retry = 1; + retry_count++; tuner_dbg("Retrying firmware load\n"); goto retry; } -- cgit v1.2.2 From 8bb84227d1ba41d6c1ec9350a4424ece5fe00e33 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 29 Jan 2011 22:10:56 -0300 Subject: [media] cx231xx: Simplify interface checking logic at probe Just a cleanup patch. Removes one indent level by moving the return -ENODEV to happen before the device register logic, if the interface is not the audio/video (int 1). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-cards.c | 192 ++++++++++++++-------------- 1 file changed, 96 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 588f3e8f028b..ca2b24b0b166 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -844,110 +844,110 @@ static int cx231xx_usb_probe(struct usb_interface *interface, udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; - if (ifnum == 1) { - /* - * Interface number 0 - IR interface - */ - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); - cx231xx_devused |= 1 << nr; - - if (nr >= CX231XX_MAXBOARDS) { - cx231xx_err(DRIVER_NAME - ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS); - cx231xx_devused &= ~(1 << nr); - return -ENOMEM; - } - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - cx231xx_err(DRIVER_NAME ": out of memory!\n"); - cx231xx_devused &= ~(1 << nr); - return -ENOMEM; - } - - snprintf(dev->name, 29, "cx231xx #%d", nr); - dev->devno = nr; - dev->model = id->driver_info; - dev->video_mode.alt = -1; - dev->interface_count++; - - /* reset gpio dir and value */ - dev->gpio_dir = 0; - dev->gpio_val = 0; - dev->xc_fw_load_done = 0; - dev->has_alsa_audio = 1; - dev->power_mode = -1; - atomic_set(&dev->devlist_count, 0); - - /* 0 - vbi ; 1 -sliced cc mode */ - dev->vbi_or_sliced_cc_mode = 0; - - /* get maximum no.of IAD interfaces */ - assoc_desc = udev->actconfig->intf_assoc[0]; - dev->max_iad_interface_count = assoc_desc->bInterfaceCount; - - /* init CIR module TBD */ + /* + * Interface number 0 - IR interface (handled by mceusb driver) + * Interface number 1 - AV interface (handled by this driver) + */ + if (ifnum != 1) + return -ENODEV; - /* store the current interface */ - lif = interface; + /* Check to see next free device and mark as used */ + nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS); + cx231xx_devused |= 1 << nr; - /*mode_tv: digital=1 or analog=0*/ - dev->mode_tv = 0; + if (nr >= CX231XX_MAXBOARDS) { + cx231xx_err(DRIVER_NAME + ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS); + cx231xx_devused &= ~(1 << nr); + return -ENOMEM; + } - dev->USE_ISO = transfer_mode; + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + cx231xx_err(DRIVER_NAME ": out of memory!\n"); + cx231xx_devused &= ~(1 << nr); + return -ENOMEM; + } - switch (udev->speed) { - case USB_SPEED_LOW: - speed = "1.5"; - break; - case USB_SPEED_UNKNOWN: - case USB_SPEED_FULL: - speed = "12"; - break; - case USB_SPEED_HIGH: - speed = "480"; - break; - default: - speed = "unknown"; - } + snprintf(dev->name, 29, "cx231xx #%d", nr); + dev->devno = nr; + dev->model = id->driver_info; + dev->video_mode.alt = -1; + + dev->interface_count++; + /* reset gpio dir and value */ + dev->gpio_dir = 0; + dev->gpio_val = 0; + dev->xc_fw_load_done = 0; + dev->has_alsa_audio = 1; + dev->power_mode = -1; + atomic_set(&dev->devlist_count, 0); + + /* 0 - vbi ; 1 -sliced cc mode */ + dev->vbi_or_sliced_cc_mode = 0; + + /* get maximum no.of IAD interfaces */ + assoc_desc = udev->actconfig->intf_assoc[0]; + dev->max_iad_interface_count = assoc_desc->bInterfaceCount; + + /* init CIR module TBD */ + + /* store the current interface */ + lif = interface; + + /*mode_tv: digital=1 or analog=0*/ + dev->mode_tv = 0; + + dev->USE_ISO = transfer_mode; + + switch (udev->speed) { + case USB_SPEED_LOW: + speed = "1.5"; + break; + case USB_SPEED_UNKNOWN: + case USB_SPEED_FULL: + speed = "12"; + break; + case USB_SPEED_HIGH: + speed = "480"; + break; + default: + speed = "unknown"; + } - if (udev->manufacturer) - strlcpy(descr, udev->manufacturer, sizeof(descr)); + if (udev->manufacturer) + strlcpy(descr, udev->manufacturer, sizeof(descr)); - if (udev->product) { - if (*descr) - strlcat(descr, " ", sizeof(descr)); - strlcat(descr, udev->product, sizeof(descr)); - } + if (udev->product) { if (*descr) strlcat(descr, " ", sizeof(descr)); - - cx231xx_info("New device %s@ %s Mbps " - "(%04x:%04x) with %d interfaces\n", - descr, - speed, - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct), - dev->max_iad_interface_count); - - /* store the interface 0 back */ - lif = udev->actconfig->interface[0]; - - /* increment interface count */ - dev->interface_count++; - - /* get device number */ - nr = dev->devno; - - assoc_desc = udev->actconfig->intf_assoc[0]; - if (assoc_desc->bFirstInterface != ifnum) { - cx231xx_err(DRIVER_NAME ": Not found " - "matching IAD interface\n"); - return -ENODEV; - } - } else { + strlcat(descr, udev->product, sizeof(descr)); + } + if (*descr) + strlcat(descr, " ", sizeof(descr)); + + cx231xx_info("New device %s@ %s Mbps " + "(%04x:%04x) with %d interfaces\n", + descr, + speed, + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), + dev->max_iad_interface_count); + + /* store the interface 0 back */ + lif = udev->actconfig->interface[0]; + + /* increment interface count */ + dev->interface_count++; + + /* get device number */ + nr = dev->devno; + + assoc_desc = udev->actconfig->intf_assoc[0]; + if (assoc_desc->bFirstInterface != ifnum) { + cx231xx_err(DRIVER_NAME ": Not found " + "matching IAD interface\n"); return -ENODEV; } -- cgit v1.2.2 From 3f25ffa2cd946333d29a668993f5aa78e9b56a02 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 30 Jan 2011 09:03:24 -0300 Subject: [media] cx231xx: Use a generic check for TUNER_XC5000 The check for xc5000 assumes that the tuner will always be using the same bus and will have the same address. As those are configurable via dev->board, it should use, instead, the values defined there. Also, a similar type of test will be needed by other tuners (for example, for TUNER_XC2028) Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-i2c.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-i2c.c b/drivers/media/video/cx231xx/cx231xx-i2c.c index 835670623dfb..925f3a04e53c 100644 --- a/drivers/media/video/cx231xx/cx231xx-i2c.c +++ b/drivers/media/video/cx231xx/cx231xx-i2c.c @@ -54,6 +54,21 @@ do { \ } \ } while (0) +static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus, + const struct i2c_msg *msg, int tuner_type) +{ + if (bus->nr != dev->board.tuner_i2c_master) + return false; + + if (msg->addr != dev->board.tuner_addr) + return false; + + if (dev->tuner_type != tuner_type) + return false; + + return true; +} + /* * cx231xx_i2c_send_bytes() */ @@ -71,9 +86,7 @@ int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap, u16 saddr = 0; u8 need_gpio = 0; - if ((bus->nr == 1) && (msg->addr == 0x61) - && (dev->tuner_type == TUNER_XC5000)) { - + if (is_tuner(dev, bus, msg, TUNER_XC5000)) { size = msg->len; if (size == 2) { /* register write sub addr */ @@ -180,9 +193,7 @@ static int cx231xx_i2c_recv_bytes(struct i2c_adapter *i2c_adap, u16 saddr = 0; u8 need_gpio = 0; - if ((bus->nr == 1) && (msg->addr == 0x61) - && dev->tuner_type == TUNER_XC5000) { - + if (is_tuner(dev, bus, msg, TUNER_XC5000)) { if (msg->len == 2) saddr = msg->buf[0] << 8 | msg->buf[1]; else if (msg->len == 1) @@ -274,9 +285,7 @@ static int cx231xx_i2c_recv_bytes_with_saddr(struct i2c_adapter *i2c_adap, else if (msg1->len == 1) saddr = msg1->buf[0]; - if ((bus->nr == 1) && (msg2->addr == 0x61) - && dev->tuner_type == TUNER_XC5000) { - + if (is_tuner(dev, bus, msg2, TUNER_XC5000)) { if ((msg2->len < 16)) { dprintk1(1, @@ -454,8 +463,8 @@ static char *i2c_devs[128] = { [0x32 >> 1] = "GeminiIII", [0x02 >> 1] = "Aquarius", [0xa0 >> 1] = "eeprom", - [0xc0 >> 1] = "tuner/XC3028", - [0xc2 >> 1] = "tuner/XC5000", + [0xc0 >> 1] = "tuner", + [0xc2 >> 1] = "tuner", }; /* -- cgit v1.2.2 From 2f86138706d3b5c85a69e72ca2959717372386dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 31 Jan 2011 22:12:15 -0300 Subject: [media] cx231xx: Use parameters to describe some board variants Instead of per-model tests all over the code, use some parameters at the board entries to describe the model variants for: - devices with 417 MPEG encoder; - devices that use external AV; - devices where vbi VANC endpoint doesn't work; - devices with xc5000 that require different IF initialization (and probably will cover also xc3028). - devices with xceive tuner that require a reset during init. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-avcore.c | 12 ++++-------- drivers/media/video/cx231xx/cx231xx-cards.c | 7 ++++++- drivers/media/video/cx231xx/cx231xx-core.c | 16 +++++++--------- drivers/media/video/cx231xx/cx231xx-video.c | 20 ++++++++++---------- drivers/media/video/cx231xx/cx231xx.h | 3 +++ 5 files changed, 30 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c index c53e97295a0d..b80bccfa9b2d 100644 --- a/drivers/media/video/cx231xx/cx231xx-avcore.c +++ b/drivers/media/video/cx231xx/cx231xx-avcore.c @@ -759,11 +759,8 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev, case CX231XX_VMUX_TELEVISION: case CX231XX_VMUX_CABLE: default: - switch (dev->model) { - case CX231XX_BOARD_CNXT_CARRAERA: - case CX231XX_BOARD_CNXT_RDE_250: - case CX231XX_BOARD_CNXT_SHELBY: - case CX231XX_BOARD_CNXT_RDU_250: + /* TODO: Test if this is also needed for xc2028/xc3028 */ + if (dev->board.tuner_type == TUNER_XC5000) { /* Disable the use of DIF */ status = vid_blk_read_word(dev, AFE_CTRL, &value); @@ -820,8 +817,7 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev, MODE_CTRL, FLD_INPUT_MODE, cx231xx_set_field(FLD_INPUT_MODE, INPUT_MODE_CVBS_0)); - break; - default: + } else { /* Enable the DIF for the tuner */ /* Reinitialize the DIF */ @@ -2550,7 +2546,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type) case 4: /* ts1 */ cx231xx_info("%s: set ts1 registers", __func__); - if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) { + if (dev->board.has_417) { cx231xx_info(" MPEG\n"); value &= 0xFFFFFFFC; value |= 0x3; diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index ca2b24b0b166..e04c955bd2f1 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -261,6 +261,9 @@ struct cx231xx_board cx231xx_boards[] = { .agc_analog_digital_select_gpio = 0x1c, .gpio_pin_status_mask = 0x4001000, .norm = V4L2_STD_PAL, + .no_alt_vanc = 1, + .external_av = 1, + .has_417 = 1, .input = {{ .type = CX231XX_VMUX_COMPOSITE1, @@ -382,6 +385,8 @@ struct cx231xx_board cx231xx_boards[] = { .agc_analog_digital_select_gpio = 0x0c, .gpio_pin_status_mask = 0x4001000, .norm = V4L2_STD_NTSC, + .no_alt_vanc = 1, + .external_av = 1, .input = {{ .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, @@ -772,7 +777,7 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev, /* Reset other chips required if they are tied up with GPIO pins */ cx231xx_add_into_devlist(dev); - if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) { + if (dev->board.has_417) { printk(KERN_INFO "attach 417 %d\n", dev->model); if (cx231xx_417_register(dev) < 0) { printk(KERN_ERR diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index 7d62d58617f5..abe500feb7dd 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c @@ -571,6 +571,8 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt) alt]; break; case INDEX_VANC: + if (dev->board.no_alt_vanc) + return 0; usb_interface_index = dev->current_pcb_config.hs_config_info[0].interface_info. vanc_index + 1; @@ -600,8 +602,7 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt) usb_interface_index, alt); /*To workaround error number=-71 on EP0 for videograbber, need add following codes.*/ - if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER && - dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2) + if (dev->board.no_alt_vanc) return -1; } @@ -1301,8 +1302,7 @@ int cx231xx_dev_init(struct cx231xx *dev) /* init hardware */ /* Note : with out calling set power mode function, afe can not be set up correctly */ - if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER || - dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) { + if (dev->board.external_av) { errCode = cx231xx_set_power_mode(dev, POLARIS_AVMODE_ENXTERNAL_AV); if (errCode < 0) { @@ -1322,11 +1322,9 @@ int cx231xx_dev_init(struct cx231xx *dev) } } - /* reset the Tuner */ - if ((dev->model == CX231XX_BOARD_CNXT_CARRAERA) || - (dev->model == CX231XX_BOARD_CNXT_RDE_250) || - (dev->model == CX231XX_BOARD_CNXT_SHELBY) || - (dev->model == CX231XX_BOARD_CNXT_RDU_250)) + /* reset the Tuner, if it is a Xceive tuner */ + if ((dev->board.tuner_type == TUNER_XC5000) || + (dev->board.tuner_type == TUNER_XC2028)) cx231xx_gpio_set(dev, dev->board.tuner_gpio); /* initialize Colibri block */ diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index 7e3e8c4f19b7..ffd5af914c44 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -2190,8 +2190,7 @@ static int cx231xx_v4l2_open(struct file *filp) dev->height = norm_maxh(dev); /* Power up in Analog TV mode */ - if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER || - dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) + if (dev->board.external_av) cx231xx_set_power_mode(dev, POLARIS_AVMODE_ENXTERNAL_AV); else @@ -2231,9 +2230,7 @@ static int cx231xx_v4l2_open(struct file *filp) if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { /* Set the required alternate setting VBI interface works in Bulk mode only */ - if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER && - dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2) - cx231xx_set_alt_setting(dev, INDEX_VANC, 0); + cx231xx_set_alt_setting(dev, INDEX_VANC, 0); videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops, NULL, &dev->vbi_mode.slock, @@ -2275,7 +2272,7 @@ void cx231xx_release_analog_resources(struct cx231xx *dev) cx231xx_info("V4L2 device %s deregistered\n", video_device_node_name(dev->vdev)); - if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) + if (dev->board.has_417) cx231xx_417_unregister(dev); if (video_is_registered(dev->vdev)) @@ -2302,10 +2299,13 @@ static int cx231xx_v4l2_close(struct file *filp) if (res_check(fh)) res_free(fh); - /*To workaround error number=-71 on EP0 for VideoGrabber, - need exclude following.*/ - if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER && - dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2) + /* + * To workaround error number=-71 on EP0 for VideoGrabber, + * need exclude following. + * FIXME: It is probably safe to remove most of these, as we're + * now avoiding the alternate setting for INDEX_VANC + */ + if (!dev->board.no_alt_vanc) if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 72bbea2bcd56..b72503d625b5 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -353,7 +353,10 @@ struct cx231xx_board { unsigned int max_range_640_480:1; unsigned int has_dvb:1; + unsigned int has_417:1; unsigned int valid:1; + unsigned int no_alt_vanc:1; + unsigned int external_av:1; unsigned char xclk, i2c_speed; -- cgit v1.2.2 From 38f5ddc1bf12887c0abe287de359e853e12fcc19 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 31 Jan 2011 16:25:39 -0300 Subject: [media] cx231xx: Allow some boards to not use I2C port 3 Some devices don't need to use it. So allow to just disable this logic. Having it enabled on some devices cause power management to complain, generating error -71. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-avcore.c | 2 ++ drivers/media/video/cx231xx/cx231xx.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c index b80bccfa9b2d..62843d39817c 100644 --- a/drivers/media/video/cx231xx/cx231xx-avcore.c +++ b/drivers/media/video/cx231xx/cx231xx-avcore.c @@ -1271,6 +1271,8 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3) int status = 0; bool current_is_port_3; + if (dev->board.dont_use_port_3) + is_port_3 = false; status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value, 4); if (status < 0) diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index b72503d625b5..e1c222b05204 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -357,6 +357,7 @@ struct cx231xx_board { unsigned int valid:1; unsigned int no_alt_vanc:1; unsigned int external_av:1; + unsigned int dont_use_port_3:1; unsigned char xclk, i2c_speed; -- cgit v1.2.2 From 4e105039da20f57958a2f538048a0f1bfb576b8b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 31 Jan 2011 22:18:21 -0300 Subject: [media] cx231xx: Add support for PV Xcapture USB Adds support for Pixelviex Xcapture USB grabber device. This device has one composite and one s-video entry only, plus a button. For now, the button is not supported. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-cards.c | 31 +++++++++++++++++++++++++++++ drivers/media/video/cx231xx/cx231xx.h | 1 + 2 files changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index e04c955bd2f1..6540b8dfb6bb 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -440,6 +440,35 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = 0, } }, }, + [CX231XX_BOARD_PV_XCAPTURE_USB] = { + .name = "Pixelview Xcapture USB", + .tuner_type = TUNER_ABSENT, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .demod_xfer_mode = 0, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + .gpio_pin_status_mask = 0x4001000, + .norm = V4L2_STD_NTSC, + .no_alt_vanc = 1, + .external_av = 1, + .dont_use_port_3 = 1, + + .input = {{ + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -469,6 +498,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2}, {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001), .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID}, + {USB_DEVICE(USB_VID_PIXELVIEW, 0x5014), + .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB}, {}, }; diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index e1c222b05204..2d5ab0cd79d7 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -64,6 +64,7 @@ #define CX231XX_BOARD_HAUPPAUGE_EXETER 8 #define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9 #define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10 +#define CX231XX_BOARD_PV_XCAPTURE_USB 11 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 -- cgit v1.2.2 From b618726414f3eb7b0b122e459efe3c5edc36b2fc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Feb 2011 21:52:02 -0300 Subject: [media] cx88: use unlocked_ioctl for cx88-video. cx88-video has locks. don't use the locked ioctl version, as it is not needed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 508dabbed986..e2fc45509b03 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1672,7 +1672,7 @@ static const struct v4l2_file_operations video_fops = .read = video_read, .poll = video_poll, .mmap = video_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1722,7 +1722,7 @@ static const struct v4l2_file_operations radio_fops = .owner = THIS_MODULE, .open = video_open, .release = video_release, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { -- cgit v1.2.2 From 121ec13267fabcf2c81e4584f1505069e234b30d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 14 Feb 2011 07:01:51 -0300 Subject: [media] cx88: Don't allow opening a device while it is not ready After registering the cdev, it would be possible do have an open on it. In a matter of fact, some versions of udev do this. So, move registration to the end and protect it with a mutex. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-video.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index e2fc45509b03..f814886ccd17 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1882,6 +1882,15 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, request_module("ir-kbd-i2c"); } + /* Sets device info at pci_dev */ + pci_set_drvdata(pci_dev, dev); + + /* initial device configuration */ + mutex_lock(&core->lock); + cx88_set_tvnorm(core, core->tvnorm); + init_controls(core); + cx88_video_mux(core, 0); + /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); @@ -1923,16 +1932,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->name, video_device_node_name(dev->radio_dev)); } - /* everything worked */ - pci_set_drvdata(pci_dev,dev); - - /* initial device configuration */ - mutex_lock(&core->lock); - cx88_set_tvnorm(core,core->tvnorm); - init_controls(core); - cx88_video_mux(core,0); - mutex_unlock(&core->lock); - /* start tvaudio thread */ if (core->board.tuner_type != TUNER_ABSENT) { core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); @@ -1942,11 +1941,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->name, err); } } + mutex_unlock(&core->lock); + return 0; fail_unreg: cx8800_unregister_video(dev); free_irq(pci_dev->irq, dev); + mutex_unlock(&core->lock); fail_core: cx88_core_put(core,dev->pci); fail_free: -- cgit v1.2.2 From 5620094a2eaa6527d7f038ad3d65ce6a76c8272a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 3 Feb 2011 22:05:23 -0300 Subject: [media] tuner-core: Remove V4L1/V4L2 API switch V4L1 was removed. So, the code there is just dead code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 1cec1224913f..6041c7d41189 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -80,7 +80,6 @@ struct tuner { struct i2c_client *i2c; struct v4l2_subdev sd; struct list_head list; - unsigned int using_v4l2:1; /* keep track of the current settings */ v4l2_std_id std; @@ -717,19 +716,6 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, return 0; } -#define switch_v4l2() if (!t->using_v4l2) \ - tuner_dbg("switching to v4l2\n"); \ - t->using_v4l2 = 1; - -static inline int check_v4l2(struct tuner *t) -{ - /* bttv still uses both v4l1 and v4l2 calls to the tuner (v4l2 for - TV, v4l1 for radio), until that is fixed this code is disabled. - Otherwise the radio (v4l1) wouldn't tune after using the TV (v4l2) - first. */ - return 0; -} - static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type) { struct tuner *t = to_tuner(sd); @@ -803,8 +789,6 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "s_std") == -EINVAL) return 0; - switch_v4l2(); - t->std = std; tuner_fixup_std(t); if (t->tv_freq) @@ -819,7 +803,6 @@ static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) if (set_mode(client, t, f->type, "s_frequency") == -EINVAL) return 0; - switch_v4l2(); set_freq(client, f->frequency); return 0; @@ -832,7 +815,6 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) if (check_mode(t, "g_frequency") == -EINVAL) return 0; - switch_v4l2(); f->type = t->mode; if (fe_tuner_ops->get_frequency) { u32 abs_freq; @@ -856,7 +838,6 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (check_mode(t, "g_tuner") == -EINVAL) return 0; - switch_v4l2(); vt->type = t->mode; if (analog_ops->get_afc) @@ -906,8 +887,6 @@ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (check_mode(t, "s_tuner") == -EINVAL) return 0; - switch_v4l2(); - /* do nothing unless we're a radio tuner */ if (t->mode != V4L2_TUNER_RADIO) return 0; -- cgit v1.2.2 From 04f590e82bdd5fa6fc36d7abf806006d27ea9e5d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 3 Feb 2011 22:18:14 -0300 Subject: [media] tuner-core: remove the legacy is_stereo() call Nobody is using this legacy call. Just remove it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-core/dvb_frontend.h | 1 - drivers/media/video/tuner-core.c | 10 ---------- 2 files changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index f9f19be77181..3b860504bf04 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -239,7 +239,6 @@ struct analog_demod_ops { void (*set_params)(struct dvb_frontend *fe, struct analog_parameters *params); int (*has_signal)(struct dvb_frontend *fe); - int (*is_stereo)(struct dvb_frontend *fe); int (*get_afc)(struct dvb_frontend *fe); void (*tuner_status)(struct dvb_frontend *fe); void (*standby)(struct dvb_frontend *fe); diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 6041c7d41189..912d8e87658f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -682,9 +682,6 @@ static void tuner_status(struct dvb_frontend *fe) if (analog_ops->has_signal) tuner_info("Signal strength: %d\n", analog_ops->has_signal(fe)); - if (analog_ops->is_stereo) - tuner_info("Stereo: %s\n", - analog_ops->is_stereo(fe) ? "yes" : "no"); } /* ---------------------------------------------------------------------- */ @@ -861,13 +858,6 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) (tuner_status & TUNER_STATUS_STEREO) ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - } else { - if (analog_ops->is_stereo) { - vt->rxsubchans = - analog_ops->is_stereo(&t->fe) ? - V4L2_TUNER_SUB_STEREO : - V4L2_TUNER_SUB_MONO; - } } if (analog_ops->has_signal) vt->signal = analog_ops->has_signal(&t->fe); -- cgit v1.2.2 From b77bdb028807bb1f78b5b50127456e1f664bd501 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 3 Feb 2011 23:03:19 -0300 Subject: [media] tuner-core: move some messages to the proper place Move the frequency set debug printk's to the code that actually are changing it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 912d8e87658f..f497f5299e88 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -246,6 +246,9 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) freq = tv_range[1] * 16; } params.frequency = freq; + tuner_dbg("tv freq set to %lu.%02lu\n", + freq / 16, freq % 16 * 100 / 16); + t->tv_freq = freq; analog_ops->set_params(&t->fe, ¶ms); } @@ -281,6 +284,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } params.frequency = freq; + tuner_dbg("radio freq set to %lu.%02lu\n", + freq / 16000, freq % 16000 * 100 / 16000); + t->radio_freq = freq; analog_ops->set_params(&t->fe, ¶ms); } @@ -291,17 +297,11 @@ static void set_freq(struct i2c_client *c, unsigned long freq) switch (t->mode) { case V4L2_TUNER_RADIO: - tuner_dbg("radio freq set to %lu.%02lu\n", - freq / 16000, freq % 16000 * 100 / 16000); set_radio_freq(c, freq); - t->radio_freq = freq; break; case V4L2_TUNER_ANALOG_TV: case V4L2_TUNER_DIGITAL_TV: - tuner_dbg("tv freq set to %lu.%02lu\n", - freq / 16, freq % 16 * 100 / 16); set_tv_freq(c, freq); - t->tv_freq = freq; break; default: tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); -- cgit v1.2.2 From 9f3f71ef6d9a6179a16f82287f062cbf3f112ec6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 3 Feb 2011 23:32:07 -0300 Subject: [media] tuner-core: Reorganize the functions internally This is a big patch with no functional changes. It just rearranges everything inside the driver, and prepares to break TV and Radio into two separate fops groups. Currently, it has an heuristics logic to determine if the call came from radio or video. However, the caller driver knows for sure, so tuner-core shouldn't try to guess it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 1023 ++++++++++++++++++++------------------ 1 file changed, 527 insertions(+), 496 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index f497f5299e88..5c3da21d188e 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -34,6 +34,99 @@ #define PREFIX t->i2c->driver->driver.name +/* + * Driver modprobe parameters + */ + +/* insmod options used at init time => read/only */ +static unsigned int addr; +static unsigned int no_autodetect; +static unsigned int show_i2c; + +module_param(addr, int, 0444); +module_param(no_autodetect, int, 0444); +module_param(show_i2c, int, 0444); + +/* insmod options used at runtime => read/write */ +static int tuner_debug; +static unsigned int tv_range[2] = { 44, 958 }; +static unsigned int radio_range[2] = { 65, 108 }; +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +module_param_named(debug,tuner_debug, int, 0644); +module_param_array(tv_range, int, NULL, 0644); +module_param_array(radio_range, int, NULL, 0644); +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); + +/* + * Static vars + */ + +static struct xc5000_config xc5000_cfg; +static LIST_HEAD(tuner_list); + +/* + * Debug macros + */ + +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_dbg(fmt, arg...) do { \ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +/* + * Internal struct used inside the driver + */ + +struct tuner { + /* device */ + struct dvb_frontend fe; + struct i2c_client *i2c; + struct v4l2_subdev sd; + struct list_head list; + + /* keep track of the current settings */ + v4l2_std_id std; + unsigned int tv_freq; + unsigned int radio_freq; + unsigned int audmode; + + unsigned int mode; + unsigned int mode_mask; /* Combination of allowable modes */ + + unsigned int type; /* chip type id */ + unsigned int config; + const char *name; +}; + +/* + * tuner attach/detach logic + */ + /** This macro allows us to probe dynamically, avoiding static links */ #ifdef CONFIG_MEDIA_ATTACH #define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ @@ -74,91 +167,15 @@ static void tuner_detach(struct dvb_frontend *fe) } #endif -struct tuner { - /* device */ - struct dvb_frontend fe; - struct i2c_client *i2c; - struct v4l2_subdev sd; - struct list_head list; - - /* keep track of the current settings */ - v4l2_std_id std; - unsigned int tv_freq; - unsigned int radio_freq; - unsigned int audmode; - - unsigned int mode; - unsigned int mode_mask; /* Combination of allowable modes */ - - unsigned int type; /* chip type id */ - unsigned int config; - const char *name; -}; static inline struct tuner *to_tuner(struct v4l2_subdev *sd) { return container_of(sd, struct tuner, sd); } - -/* insmod options used at init time => read/only */ -static unsigned int addr; -static unsigned int no_autodetect; -static unsigned int show_i2c; - -/* insmod options used at runtime => read/write */ -static int tuner_debug; - -#define tuner_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_dbg(fmt, arg...) do { \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -/* ------------------------------------------------------------------------ */ - -static unsigned int tv_range[2] = { 44, 958 }; -static unsigned int radio_range[2] = { 65, 108 }; - -static char pal[] = "--"; -static char secam[] = "--"; -static char ntsc[] = "-"; - - -module_param(addr, int, 0444); -module_param(no_autodetect, int, 0444); -module_param(show_i2c, int, 0444); -module_param_named(debug,tuner_debug, int, 0644); -module_param_string(pal, pal, sizeof(pal), 0644); -module_param_string(secam, secam, sizeof(secam), 0644); -module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); -module_param_array(tv_range, int, NULL, 0644); -module_param_array(radio_range, int, NULL, 0644); - -MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); -MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); -MODULE_LICENSE("GPL"); - -/* ---------------------------------------------------------------------- */ +/* + * struct analog_demod_ops callbacks + */ static void fe_set_params(struct dvb_frontend *fe, struct analog_parameters *params) @@ -214,101 +231,13 @@ static struct analog_demod_ops tuner_analog_ops = { .tuner_status = tuner_status }; -/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ -static void set_tv_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - struct analog_parameters params = { - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; - - if (t->type == UNSET) { - tuner_warn ("tuner type not set\n"); - return; - } - if (NULL == analog_ops->set_params) { - tuner_warn ("Tuner has no way to set tv freq\n"); - return; - } - if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { - tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", - freq / 16, freq % 16 * 100 / 16, tv_range[0], - tv_range[1]); - /* V4L2 spec: if the freq is not possible then the closest - possible value should be selected */ - if (freq < tv_range[0] * 16) - freq = tv_range[0] * 16; - else - freq = tv_range[1] * 16; - } - params.frequency = freq; - tuner_dbg("tv freq set to %lu.%02lu\n", - freq / 16, freq % 16 * 100 / 16); - t->tv_freq = freq; - - analog_ops->set_params(&t->fe, ¶ms); -} - -static void set_radio_freq(struct i2c_client *c, unsigned int freq) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - struct analog_parameters params = { - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; - - if (t->type == UNSET) { - tuner_warn ("tuner type not set\n"); - return; - } - if (NULL == analog_ops->set_params) { - tuner_warn ("tuner has no way to set radio frequency\n"); - return; - } - if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) { - tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", - freq / 16000, freq % 16000 * 100 / 16000, - radio_range[0], radio_range[1]); - /* V4L2 spec: if the freq is not possible then the closest - possible value should be selected */ - if (freq < radio_range[0] * 16000) - freq = radio_range[0] * 16000; - else - freq = radio_range[1] * 16000; - } - params.frequency = freq; - tuner_dbg("radio freq set to %lu.%02lu\n", - freq / 16000, freq % 16000 * 100 / 16000); - t->radio_freq = freq; - - analog_ops->set_params(&t->fe, ¶ms); -} - -static void set_freq(struct i2c_client *c, unsigned long freq) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - - switch (t->mode) { - case V4L2_TUNER_RADIO: - set_radio_freq(c, freq); - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - set_tv_freq(c, freq); - break; - default: - tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); - } -} +/* + * Functions that are common to both TV and radio + */ -static struct xc5000_config xc5000_cfg; +static void set_tv_freq(struct i2c_client *c, unsigned int freq); +static void set_radio_freq(struct i2c_client *c, unsigned int freq); +static const struct v4l2_subdev_ops tuner_ops; static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, @@ -429,103 +358,329 @@ static void set_type(struct i2c_client *c, unsigned int type, .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, }; - if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr, - t->i2c->adapter, &cfg)) - goto attach_failed; - tune_now = 0; - break; + if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr, + t->i2c->adapter, &cfg)) + goto attach_failed; + tune_now = 0; + break; + } + default: + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) + goto attach_failed; + + break; + } + + if ((NULL == analog_ops->set_params) && + (fe_tuner_ops->set_analog_params)) { + + t->name = fe_tuner_ops->info.name; + + t->fe.analog_demod_priv = t; + memcpy(analog_ops, &tuner_analog_ops, + sizeof(struct analog_demod_ops)); + + } else { + t->name = analog_ops->info.name; + } + + tuner_dbg("type set to %s\n", t->name); + + if (t->mode_mask == T_UNINITIALIZED) + t->mode_mask = new_mode_mask; + + /* Some tuners require more initialization setup before use, + such as firmware download or device calibration. + trying to set a frequency here will just fail + FIXME: better to move set_freq to the tuner code. This is needed + on analog tuners for PLL to properly work + */ + if (tune_now) { + if (V4L2_TUNER_RADIO == t->mode) + set_radio_freq(c, t->radio_freq); + else + set_tv_freq(c, t->tv_freq); + } + + tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", + c->adapter->name, c->driver->driver.name, c->addr << 1, type, + t->mode_mask); + return; + +attach_failed: + tuner_dbg("Tuner attach for type = %d failed.\n", t->type); + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + + return; +} + +/* + * This function apply tuner config to tuner specified + * by tun_setup structure. I addr is unset, then admin status + * and tun addr status is more precise then current status, + * it's applied. Otherwise status and type are applied only to + * tuner with exactly the same addr. +*/ + +static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) +{ + struct tuner *t = to_tuner(i2c_get_clientdata(c)); + + if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && + (t->mode_mask & tun_setup->mode_mask))) || + (tun_setup->addr == c->addr)) { + set_type(c, tun_setup->type, tun_setup->mode_mask, + tun_setup->config, tun_setup->tuner_callback); + } else + tuner_dbg("set addr discarded for type %i, mask %x. " + "Asked to change tuner at addr 0x%02x, with mask %x\n", + t->type, t->mode_mask, + tun_setup->addr, tun_setup->mode_mask); +} + +static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type) +{ + struct tuner *t = to_tuner(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", + type->type, + type->addr, + type->mode_mask, + type->config); + + set_addr(client, type); + return 0; +} + +static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg) +{ + struct tuner *t = to_tuner(sd); + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + + if (t->type != cfg->tuner) + return 0; + + if (analog_ops->set_config) { + analog_ops->set_config(&t->fe, cfg->priv); + return 0; + } + + tuner_dbg("Tuner frontend module has no way to set config\n"); + return 0; +} + +/* Search for existing radio and/or TV tuners on the given I2C adapter. + Note that when this function is called from tuner_probe you can be + certain no other devices will be added/deleted at the same time, I2C + core protects against that. */ +static void tuner_lookup(struct i2c_adapter *adap, + struct tuner **radio, struct tuner **tv) +{ + struct tuner *pos; + + *radio = NULL; + *tv = NULL; + + list_for_each_entry(pos, &tuner_list, list) { + int mode_mask; + + if (pos->i2c->adapter != adap || + strcmp(pos->i2c->driver->driver.name, "tuner")) + continue; + + mode_mask = pos->mode_mask & ~T_STANDBY; + if (*radio == NULL && mode_mask == T_RADIO) + *radio = pos; + /* Note: currently TDA9887 is the only demod-only + device. If other devices appear then we need to + make this test more general. */ + else if (*tv == NULL && pos->type != TUNER_TDA9887 && + (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) + *tv = pos; + } +} + +/* During client attach, set_type is called by adapter's attach_inform callback. + set_type must then be completed by tuner_probe. + */ +static int tuner_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tuner *t; + struct tuner *radio; + struct tuner *tv; + + t = kzalloc(sizeof(struct tuner), GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops); + t->i2c = client; + t->name = "(tuner unset)"; + t->type = UNSET; + t->audmode = V4L2_TUNER_MODE_STEREO; + t->mode_mask = T_UNINITIALIZED; + + if (show_i2c) { + unsigned char buffer[16]; + int i, rc; + + memset(buffer, 0, sizeof(buffer)); + rc = i2c_master_recv(client, buffer, sizeof(buffer)); + tuner_info("I2C RECV = "); + for (i = 0; i < rc; i++) + printk(KERN_CONT "%02x ", buffer[i]); + printk("\n"); + } + + /* autodetection code based on the i2c addr */ + if (!no_autodetect) { + switch (client->addr) { + case 0x10: + if (tuner_symbol_probe(tea5761_autodetection, + t->i2c->adapter, + t->i2c->addr) >= 0) { + t->type = TUNER_TEA5761; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + kfree(t); + return -ENODEV; + case 0x42: + case 0x43: + case 0x4a: + case 0x4b: + /* If chip is not tda8290, don't register. + since it can be tda9887*/ + if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, + t->i2c->addr) >= 0) { + tuner_dbg("tda829x detected\n"); + } else { + /* Default is being tda9887 */ + t->type = TUNER_TDA9887; + t->mode_mask = T_RADIO | T_ANALOG_TV | + T_DIGITAL_TV; + t->mode = T_STANDBY; + goto register_client; + } + break; + case 0x60: + if (tuner_symbol_probe(tea5767_autodetection, + t->i2c->adapter, t->i2c->addr) + >= 0) { + t->type = TUNER_TEA5767; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + } } - default: - if (!dvb_attach(simple_tuner_attach, &t->fe, - t->i2c->adapter, t->i2c->addr, t->type)) - goto attach_failed; - break; + /* Initializes only the first TV tuner on this adapter. Why only the + first? Because there are some devices (notably the ones with TI + tuners) that have more than one i2c address for the *same* device. + Experience shows that, except for just one case, the first + address is the right one. The exception is a Russian tuner + (ACORP_Y878F). So, the desired behavior is just to enable the + first found TV tuner. */ + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv == NULL) { + t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + if (radio == NULL) + t->mode_mask |= T_RADIO; + tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); + t->tv_freq = 400 * 16; /* Sets freq to VHF High */ + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ } - if ((NULL == analog_ops->set_params) && - (fe_tuner_ops->set_analog_params)) { - - t->name = fe_tuner_ops->info.name; - - t->fe.analog_demod_priv = t; - memcpy(analog_ops, &tuner_analog_ops, - sizeof(struct analog_demod_ops)); + /* Should be just before return */ +register_client: + tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1, + client->adapter->name); + /* Sets a default mode */ + if (t->mode_mask & T_ANALOG_TV) { + t->mode = V4L2_TUNER_ANALOG_TV; + } else if (t->mode_mask & T_RADIO) { + t->mode = V4L2_TUNER_RADIO; } else { - t->name = analog_ops->info.name; + t->mode = V4L2_TUNER_DIGITAL_TV; } + set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); + list_add_tail(&t->list, &tuner_list); + return 0; +} - tuner_dbg("type set to %s\n", t->name); - - if (t->mode_mask == T_UNINITIALIZED) - t->mode_mask = new_mode_mask; - - /* Some tuners require more initialization setup before use, - such as firmware download or device calibration. - trying to set a frequency here will just fail - FIXME: better to move set_freq to the tuner code. This is needed - on analog tuners for PLL to properly work - */ - if (tune_now) - set_freq(c, (V4L2_TUNER_RADIO == t->mode) ? - t->radio_freq : t->tv_freq); - - tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", - c->adapter->name, c->driver->driver.name, c->addr << 1, type, - t->mode_mask); - return; +static int tuner_remove(struct i2c_client *client) +{ + struct tuner *t = to_tuner(i2c_get_clientdata(client)); -attach_failed: - tuner_dbg("Tuner attach for type = %d failed.\n", t->type); - t->type = TUNER_ABSENT; - t->mode_mask = T_UNINITIALIZED; + v4l2_device_unregister_subdev(&t->sd); + tuner_detach(&t->fe); + t->fe.analog_demod_priv = NULL; - return; + list_del(&t->list); + kfree(t); + return 0; } /* - * This function apply tuner config to tuner specified - * by tun_setup structure. I addr is unset, then admin status - * and tun addr status is more precise then current status, - * it's applied. Otherwise status and type are applied only to - * tuner with exactly the same addr. -*/ + * Functions that are specific for TV mode + */ -static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) +/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ +static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && - (t->mode_mask & tun_setup->mode_mask))) || - (tun_setup->addr == c->addr)) { - set_type(c, tun_setup->type, tun_setup->mode_mask, - tun_setup->config, tun_setup->tuner_callback); - } else - tuner_dbg("set addr discarded for type %i, mask %x. " - "Asked to change tuner at addr 0x%02x, with mask %x\n", - t->type, t->mode_mask, - tun_setup->addr, tun_setup->mode_mask); -} + struct analog_parameters params = { + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; -static inline int check_mode(struct tuner *t, char *cmd) -{ - if ((1 << t->mode & t->mode_mask) == 0) { - return -EINVAL; + if (t->type == UNSET) { + tuner_warn ("tuner type not set\n"); + return; } - - switch (t->mode) { - case V4L2_TUNER_RADIO: - tuner_dbg("Cmd %s accepted for radio\n", cmd); - break; - case V4L2_TUNER_ANALOG_TV: - tuner_dbg("Cmd %s accepted for analog TV\n", cmd); - break; - case V4L2_TUNER_DIGITAL_TV: - tuner_dbg("Cmd %s accepted for digital TV\n", cmd); - break; + if (NULL == analog_ops->set_params) { + tuner_warn ("Tuner has no way to set tv freq\n"); + return; } - return 0; + if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { + tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", + freq / 16, freq % 16 * 100 / 16, tv_range[0], + tv_range[1]); + /* V4L2 spec: if the freq is not possible then the closest + possible value should be selected */ + if (freq < tv_range[0] * 16) + freq = tv_range[0] * 16; + else + freq = tv_range[1] * 16; + } + params.frequency = freq; + tuner_dbg("tv freq set to %d.%02d\n", + freq / 16, freq % 16 * 100 / 16); + t->tv_freq = freq; + + analog_ops->set_params(&t->fe, ¶ms); } /* get more precise norm info from insmod option */ @@ -641,7 +796,117 @@ static int tuner_fixup_std(struct tuner *t) break; } } - return 0; + return 0; +} + +/* + * Functions that are specific for Radio mode + */ + +static void set_radio_freq(struct i2c_client *c, unsigned int freq) +{ + struct tuner *t = to_tuner(i2c_get_clientdata(c)); + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + + struct analog_parameters params = { + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; + + if (t->type == UNSET) { + tuner_warn ("tuner type not set\n"); + return; + } + if (NULL == analog_ops->set_params) { + tuner_warn ("tuner has no way to set radio frequency\n"); + return; + } + if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) { + tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", + freq / 16000, freq % 16000 * 100 / 16000, + radio_range[0], radio_range[1]); + /* V4L2 spec: if the freq is not possible then the closest + possible value should be selected */ + if (freq < radio_range[0] * 16000) + freq = radio_range[0] * 16000; + else + freq = radio_range[1] * 16000; + } + params.frequency = freq; + tuner_dbg("radio freq set to %d.%02d\n", + freq / 16000, freq % 16000 * 100 / 16000); + t->radio_freq = freq; + + analog_ops->set_params(&t->fe, ¶ms); +} + +/* + * Functions that should be broken into separate radio/TV functions + */ + +static inline int check_mode(struct tuner *t, char *cmd) +{ + if ((1 << t->mode & t->mode_mask) == 0) { + return -EINVAL; + } + + switch (t->mode) { + case V4L2_TUNER_RADIO: + tuner_dbg("Cmd %s accepted for radio\n", cmd); + break; + case V4L2_TUNER_ANALOG_TV: + tuner_dbg("Cmd %s accepted for analog TV\n", cmd); + break; + case V4L2_TUNER_DIGITAL_TV: + tuner_dbg("Cmd %s accepted for digital TV\n", cmd); + break; + } + return 0; +} + +/* + * Switch tuner to other mode. If tuner support both tv and radio, + * set another frequency to some value (This is needed for some pal + * tuners to avoid locking). Otherwise, just put second tuner in + * standby mode. + */ + +static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) +{ + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + + if (mode == t->mode) + return 0; + + t->mode = mode; + + if (check_mode(t, cmd) == -EINVAL) { + tuner_dbg("Tuner doesn't support this mode. " + "Putting tuner to sleep\n"); + t->mode = T_STANDBY; + if (analog_ops->standby) + analog_ops->standby(&t->fe); + return -EINVAL; + } + return 0; +} + +static void set_freq(struct i2c_client *c, unsigned long freq) +{ + struct tuner *t = to_tuner(i2c_get_clientdata(c)); + + switch (t->mode) { + case V4L2_TUNER_RADIO: + set_radio_freq(c, freq); + break; + case V4L2_TUNER_ANALOG_TV: + case V4L2_TUNER_DIGITAL_TV: + set_tv_freq(c, freq); + break; + default: + tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); + } } static void tuner_status(struct dvb_frontend *fe) @@ -684,62 +949,6 @@ static void tuner_status(struct dvb_frontend *fe) analog_ops->has_signal(fe)); } -/* ---------------------------------------------------------------------- */ - -/* - * Switch tuner to other mode. If tuner support both tv and radio, - * set another frequency to some value (This is needed for some pal - * tuners to avoid locking). Otherwise, just put second tuner in - * standby mode. - */ - -static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) -{ - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - if (mode == t->mode) - return 0; - - t->mode = mode; - - if (check_mode(t, cmd) == -EINVAL) { - tuner_dbg("Tuner doesn't support this mode. " - "Putting tuner to sleep\n"); - t->mode = T_STANDBY; - if (analog_ops->standby) - analog_ops->standby(&t->fe); - return -EINVAL; - } - return 0; -} - -static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", - type->type, - type->addr, - type->mode_mask, - type->config); - - set_addr(client, type); - return 0; -} - -static int tuner_s_radio(struct v4l2_subdev *sd) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode(client, t, V4L2_TUNER_RADIO, "s_radio") == -EINVAL) - return 0; - if (t->radio_freq) - set_freq(client, t->radio_freq); - return 0; -} - static int tuner_s_power(struct v4l2_subdev *sd, int on) { struct tuner *t = to_tuner(sd); @@ -758,20 +967,18 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) return 0; } -static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg) +/* ---------------------------------------------------------------------- */ + + +static int tuner_s_radio(struct v4l2_subdev *sd) { struct tuner *t = to_tuner(sd); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - if (t->type != cfg->tuner) - return 0; + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (analog_ops->set_config) { - analog_ops->set_config(&t->fe, cfg->priv); + if (set_mode(client, t, V4L2_TUNER_RADIO, "s_radio") == -EINVAL) return 0; - } - - tuner_dbg("Tuner frontend module has no way to set config\n"); + if (t->radio_freq) + set_freq(client, t->radio_freq); return 0; } @@ -956,178 +1163,6 @@ static const struct v4l2_subdev_ops tuner_ops = { .tuner = &tuner_tuner_ops, }; -/* ---------------------------------------------------------------------- */ - -static LIST_HEAD(tuner_list); - -/* Search for existing radio and/or TV tuners on the given I2C adapter. - Note that when this function is called from tuner_probe you can be - certain no other devices will be added/deleted at the same time, I2C - core protects against that. */ -static void tuner_lookup(struct i2c_adapter *adap, - struct tuner **radio, struct tuner **tv) -{ - struct tuner *pos; - - *radio = NULL; - *tv = NULL; - - list_for_each_entry(pos, &tuner_list, list) { - int mode_mask; - - if (pos->i2c->adapter != adap || - strcmp(pos->i2c->driver->driver.name, "tuner")) - continue; - - mode_mask = pos->mode_mask & ~T_STANDBY; - if (*radio == NULL && mode_mask == T_RADIO) - *radio = pos; - /* Note: currently TDA9887 is the only demod-only - device. If other devices appear then we need to - make this test more general. */ - else if (*tv == NULL && pos->type != TUNER_TDA9887 && - (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) - *tv = pos; - } -} - -/* During client attach, set_type is called by adapter's attach_inform callback. - set_type must then be completed by tuner_probe. - */ -static int tuner_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tuner *t; - struct tuner *radio; - struct tuner *tv; - - t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - v4l2_i2c_subdev_init(&t->sd, client, &tuner_ops); - t->i2c = client; - t->name = "(tuner unset)"; - t->type = UNSET; - t->audmode = V4L2_TUNER_MODE_STEREO; - t->mode_mask = T_UNINITIALIZED; - - if (show_i2c) { - unsigned char buffer[16]; - int i, rc; - - memset(buffer, 0, sizeof(buffer)); - rc = i2c_master_recv(client, buffer, sizeof(buffer)); - tuner_info("I2C RECV = "); - for (i = 0; i < rc; i++) - printk(KERN_CONT "%02x ", buffer[i]); - printk("\n"); - } - - /* autodetection code based on the i2c addr */ - if (!no_autodetect) { - switch (client->addr) { - case 0x10: - if (tuner_symbol_probe(tea5761_autodetection, - t->i2c->adapter, - t->i2c->addr) >= 0) { - t->type = TUNER_TEA5761; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - /* Sets freq to FM range */ - t->radio_freq = 87.5 * 16000; - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - kfree(t); - return -ENODEV; - case 0x42: - case 0x43: - case 0x4a: - case 0x4b: - /* If chip is not tda8290, don't register. - since it can be tda9887*/ - if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, - t->i2c->addr) >= 0) { - tuner_dbg("tda829x detected\n"); - } else { - /* Default is being tda9887 */ - t->type = TUNER_TDA9887; - t->mode_mask = T_RADIO | T_ANALOG_TV | - T_DIGITAL_TV; - t->mode = T_STANDBY; - goto register_client; - } - break; - case 0x60: - if (tuner_symbol_probe(tea5767_autodetection, - t->i2c->adapter, t->i2c->addr) - >= 0) { - t->type = TUNER_TEA5767; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - /* Sets freq to FM range */ - t->radio_freq = 87.5 * 16000; - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv) - tv->mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - } - } - - /* Initializes only the first TV tuner on this adapter. Why only the - first? Because there are some devices (notably the ones with TI - tuners) that have more than one i2c address for the *same* device. - Experience shows that, except for just one case, the first - address is the right one. The exception is a Russian tuner - (ACORP_Y878F). So, the desired behavior is just to enable the - first found TV tuner. */ - tuner_lookup(t->i2c->adapter, &radio, &tv); - if (tv == NULL) { - t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - if (radio == NULL) - t->mode_mask |= T_RADIO; - tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); - t->tv_freq = 400 * 16; /* Sets freq to VHF High */ - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - } - - /* Should be just before return */ -register_client: - tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1, - client->adapter->name); - - /* Sets a default mode */ - if (t->mode_mask & T_ANALOG_TV) { - t->mode = V4L2_TUNER_ANALOG_TV; - } else if (t->mode_mask & T_RADIO) { - t->mode = V4L2_TUNER_RADIO; - } else { - t->mode = V4L2_TUNER_DIGITAL_TV; - } - set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); - list_add_tail(&t->list, &tuner_list); - return 0; -} - -static int tuner_remove(struct i2c_client *client) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(client)); - - v4l2_device_unregister_subdev(&t->sd); - tuner_detach(&t->fe); - t->fe.analog_demod_priv = NULL; - - list_del(&t->list); - kfree(t); - return 0; -} - /* ----------------------------------------------------------------------- */ /* This driver supports many devices and the idea is to let the driver @@ -1165,10 +1200,6 @@ static __exit void exit_tuner(void) module_init(init_tuner); module_exit(exit_tuner); -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ +MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); +MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From e2d25a2474a8c0178bac4919729ab092783bd916 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 4 Feb 2011 10:09:07 -0300 Subject: [media] tuner-core: Some cleanups at check_mode/set_mode Properly document those functions and do some cleanups around that. There's just one behavior change on this patchset: it will now restore TV frequency when changing from radio to TV mode. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 72 +++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 5c3da21d188e..7cdfe3af6e74 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -841,38 +841,39 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) analog_ops->set_params(&t->fe, ¶ms); } -/* - * Functions that should be broken into separate radio/TV functions +/** + * check_mode - Verify if tuner supports the requested mode + * @t - a pointer to the module's internal struct_tuner + * + * This function checks if the tuner is capable of tuning analog TV, + * digital TV or radio, depending on what the caller wants. If the + * tuner can't support that mode, it returns -EINVAL. Otherwise, it + * returns 0. + * This function is needed for boards that have a separate tuner for + * radio (like devices with tea5767). */ - -static inline int check_mode(struct tuner *t, char *cmd) +static inline int check_mode(struct tuner *t) { if ((1 << t->mode & t->mode_mask) == 0) { return -EINVAL; } - - switch (t->mode) { - case V4L2_TUNER_RADIO: - tuner_dbg("Cmd %s accepted for radio\n", cmd); - break; - case V4L2_TUNER_ANALOG_TV: - tuner_dbg("Cmd %s accepted for analog TV\n", cmd); - break; - case V4L2_TUNER_DIGITAL_TV: - tuner_dbg("Cmd %s accepted for digital TV\n", cmd); - break; - } return 0; } -/* - * Switch tuner to other mode. If tuner support both tv and radio, - * set another frequency to some value (This is needed for some pal - * tuners to avoid locking). Otherwise, just put second tuner in - * standby mode. +/** + * set_mode - Switch tuner to other mode. + * @client - struct i2c_client pointer + * @t - a pointer to the module's internal struct_tuner + * @mode - enum v4l2_type + T_STANDBY mode + * @cmd - string for the command to be executed (for debug messages) + * + * If tuner doesn't support the needed mode (radio or TV), prints a + * debug message and returns -EINVAL, changing internal state to T_STANDBY. + * Otherwise, changes the state and sets frequency to the last value, if + * the tuner can sleep or if it supports both Radio and TV. */ - -static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) +static inline int set_mode(struct i2c_client *client, struct tuner *t, + int mode, char *cmd) { struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; @@ -881,7 +882,7 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, t->mode = mode; - if (check_mode(t, cmd) == -EINVAL) { + if (check_mode(t) == -EINVAL) { tuner_dbg("Tuner doesn't support this mode. " "Putting tuner to sleep\n"); t->mode = T_STANDBY; @@ -889,9 +890,22 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, analog_ops->standby(&t->fe); return -EINVAL; } + + if (t->mode == V4L2_TUNER_RADIO) { + if (t->radio_freq) + set_radio_freq(client, t->radio_freq); + } else { + if (t->tv_freq) + set_tv_freq(client, t->tv_freq); + } + return 0; } +/* + * Functions that should be broken into separate radio/TV functions + */ + static void set_freq(struct i2c_client *c, unsigned long freq) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); @@ -959,7 +973,7 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) tuner_dbg("Putting tuner to sleep\n"); - if (check_mode(t, "s_power") == -EINVAL) + if (check_mode(t) == -EINVAL) return 0; t->mode = T_STANDBY; if (analog_ops->standby) @@ -977,8 +991,6 @@ static int tuner_s_radio(struct v4l2_subdev *sd) if (set_mode(client, t, V4L2_TUNER_RADIO, "s_radio") == -EINVAL) return 0; - if (t->radio_freq) - set_freq(client, t->radio_freq); return 0; } @@ -1017,7 +1029,7 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) struct tuner *t = to_tuner(sd); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - if (check_mode(t, "g_frequency") == -EINVAL) + if (check_mode(t) == -EINVAL) return 0; f->type = t->mode; if (fe_tuner_ops->get_frequency) { @@ -1040,7 +1052,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - if (check_mode(t, "g_tuner") == -EINVAL) + if (check_mode(t) == -EINVAL) return 0; vt->type = t->mode; @@ -1081,7 +1093,7 @@ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) struct tuner *t = to_tuner(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (check_mode(t, "s_tuner") == -EINVAL) + if (check_mode(t) == -EINVAL) return 0; /* do nothing unless we're a radio tuner */ -- cgit v1.2.2 From cbde689823776d187ba1b307a171625dbc02dd4f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 4 Feb 2011 10:42:09 -0300 Subject: [media] tuner-core: Better implement standby mode In the past, T_STANDBY were used on devices with a separate radio tuner to mark a tuner that were disabled. With the time, it got newer meanings. Also, due to a bug at the logic, the driver might incorrectly return T_STANDBY to userspace. So, instead of keeping the abuse, just use a boolean for storing such information. We can't remove T_STANDBY yet, as this is used on two other drivers. A latter patch will address its usage outside tuner-core. Thanks-to: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 189 ++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 7cdfe3af6e74..e6855a46f433 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -115,9 +115,11 @@ struct tuner { unsigned int radio_freq; unsigned int audmode; - unsigned int mode; + enum v4l2_tuner_type mode; unsigned int mode_mask; /* Combination of allowable modes */ + bool standby; /* Standby mode */ + unsigned int type; /* chip type id */ unsigned int config; const char *name; @@ -262,12 +264,6 @@ static void set_type(struct i2c_client *c, unsigned int type, t->fe.callback = tuner_callback; } - if (t->mode == T_UNINITIALIZED) { - tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); - - return; - } - /* discard private data, in case set_type() was previously called */ tuner_detach(&t->fe); t->fe.analog_demod_priv = NULL; @@ -387,8 +383,7 @@ static void set_type(struct i2c_client *c, unsigned int type, tuner_dbg("type set to %s\n", t->name); - if (t->mode_mask == T_UNINITIALIZED) - t->mode_mask = new_mode_mask; + t->mode_mask = new_mode_mask; /* Some tuners require more initialization setup before use, such as firmware download or device calibration. @@ -411,7 +406,6 @@ static void set_type(struct i2c_client *c, unsigned int type, attach_failed: tuner_dbg("Tuner attach for type = %d failed.\n", t->type); t->type = TUNER_ABSENT; - t->mode_mask = T_UNINITIALIZED; return; } @@ -429,10 +423,10 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) struct tuner *t = to_tuner(i2c_get_clientdata(c)); if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && - (t->mode_mask & tun_setup->mode_mask))) || - (tun_setup->addr == c->addr)) { - set_type(c, tun_setup->type, tun_setup->mode_mask, - tun_setup->config, tun_setup->tuner_callback); + (t->mode_mask & tun_setup->mode_mask))) || + (tun_setup->addr == c->addr)) { + set_type(c, tun_setup->type, tun_setup->mode_mask, + tun_setup->config, tun_setup->tuner_callback); } else tuner_dbg("set addr discarded for type %i, mask %x. " "Asked to change tuner at addr 0x%02x, with mask %x\n", @@ -491,7 +485,8 @@ static void tuner_lookup(struct i2c_adapter *adap, strcmp(pos->i2c->driver->driver.name, "tuner")) continue; - mode_mask = pos->mode_mask & ~T_STANDBY; + mode_mask = pos->mode_mask; + pos->standby = 1; if (*radio == NULL && mode_mask == T_RADIO) *radio = pos; /* Note: currently TDA9887 is the only demod-only @@ -521,7 +516,9 @@ static int tuner_probe(struct i2c_client *client, t->name = "(tuner unset)"; t->type = UNSET; t->audmode = V4L2_TUNER_MODE_STEREO; - t->mode_mask = T_UNINITIALIZED; + t->standby = 1; + t->radio_freq = 87.5 * 16000; /* Initial freq range */ + t->tv_freq = 400 * 16; /* Sets freq to VHF High - needed for some PLL's to properly start */ if (show_i2c) { unsigned char buffer[16]; @@ -544,9 +541,6 @@ static int tuner_probe(struct i2c_client *client, t->i2c->addr) >= 0) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - /* Sets freq to FM range */ - t->radio_freq = 87.5 * 16000; tuner_lookup(t->i2c->adapter, &radio, &tv); if (tv) tv->mode_mask &= ~T_RADIO; @@ -569,7 +563,6 @@ static int tuner_probe(struct i2c_client *client, t->type = TUNER_TDA9887; t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; - t->mode = T_STANDBY; goto register_client; } break; @@ -579,9 +572,7 @@ static int tuner_probe(struct i2c_client *client, >= 0) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; - t->mode = T_STANDBY; /* Sets freq to FM range */ - t->radio_freq = 87.5 * 16000; tuner_lookup(t->i2c->adapter, &radio, &tv); if (tv) tv->mode_mask &= ~T_RADIO; @@ -605,15 +596,10 @@ static int tuner_probe(struct i2c_client *client, if (radio == NULL) t->mode_mask |= T_RADIO; tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); - t->tv_freq = 400 * 16; /* Sets freq to VHF High */ - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ } /* Should be just before return */ register_client: - tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1, - client->adapter->name); - /* Sets a default mode */ if (t->mode_mask & T_ANALOG_TV) { t->mode = V4L2_TUNER_ANALOG_TV; @@ -624,6 +610,12 @@ register_client: } set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); list_add_tail(&t->list, &tuner_list); + + tuner_info("Tuner %d found with type(s)%s%s%s.\n", + t->type, + t->mode_mask & T_RADIO ? " radio" : "", + t->mode_mask & T_ANALOG_TV ? " TV" : "", + t->mode_mask & T_ANALOG_TV ? " DTV" : ""); return 0; } @@ -679,6 +671,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("tv freq set to %d.%02d\n", freq / 16, freq % 16 * 100 / 16); t->tv_freq = freq; + t->standby = false; analog_ops->set_params(&t->fe, ¶ms); } @@ -837,13 +830,14 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) tuner_dbg("radio freq set to %d.%02d\n", freq / 16000, freq % 16000 * 100 / 16000); t->radio_freq = freq; + t->standby = false; analog_ops->set_params(&t->fe, ¶ms); } /** * check_mode - Verify if tuner supports the requested mode - * @t - a pointer to the module's internal struct_tuner + * @t: a pointer to the module's internal struct_tuner * * This function checks if the tuner is capable of tuning analog TV, * digital TV or radio, depending on what the caller wants. If the @@ -852,51 +846,51 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) * This function is needed for boards that have a separate tuner for * radio (like devices with tea5767). */ -static inline int check_mode(struct tuner *t) +static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) { - if ((1 << t->mode & t->mode_mask) == 0) { + if ((1 << mode & t->mode_mask) == 0) { return -EINVAL; } return 0; } /** - * set_mode - Switch tuner to other mode. - * @client - struct i2c_client pointer - * @t - a pointer to the module's internal struct_tuner - * @mode - enum v4l2_type + T_STANDBY mode - * @cmd - string for the command to be executed (for debug messages) + * set_mode_freq - Switch tuner to other mode. + * @client: struct i2c_client pointer + * @t: a pointer to the module's internal struct_tuner + * @mode: enum v4l2_type (radio or TV) + * @freq: frequency to set (0 means to use the previous one) * * If tuner doesn't support the needed mode (radio or TV), prints a * debug message and returns -EINVAL, changing internal state to T_STANDBY. * Otherwise, changes the state and sets frequency to the last value, if * the tuner can sleep or if it supports both Radio and TV. */ -static inline int set_mode(struct i2c_client *client, struct tuner *t, - int mode, char *cmd) +static int set_mode_freq(struct i2c_client *client, struct tuner *t, + enum v4l2_tuner_type mode, unsigned int freq) { struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (mode == t->mode) - return 0; - - t->mode = mode; - - if (check_mode(t) == -EINVAL) { - tuner_dbg("Tuner doesn't support this mode. " - "Putting tuner to sleep\n"); - t->mode = T_STANDBY; - if (analog_ops->standby) - analog_ops->standby(&t->fe); - return -EINVAL; + if (mode != t->mode) { + if (check_mode(t, mode) == -EINVAL) { + tuner_dbg("Tuner doesn't support mode %d. " + "Putting tuner to sleep\n", mode); + t->standby = true; + if (analog_ops->standby) + analog_ops->standby(&t->fe); + return -EINVAL; + } + t->mode = mode; + tuner_dbg("Changing to mode %d\n", mode); } - if (t->mode == V4L2_TUNER_RADIO) { - if (t->radio_freq) - set_radio_freq(client, t->radio_freq); + if (freq) + t->radio_freq = freq; + set_radio_freq(client, t->radio_freq); } else { - if (t->tv_freq) - set_tv_freq(client, t->tv_freq); + if (freq) + t->tv_freq = freq; + set_tv_freq(client, t->tv_freq); } return 0; @@ -923,6 +917,13 @@ static void set_freq(struct i2c_client *c, unsigned long freq) } } +/** + * tuner_status - Dumps the current tuner status at dmesg + * @fe: pointer to struct dvb_frontend + * + * This callback is used only for driver debug purposes, answering to + * VIDIOC_LOG_STATUS. No changes should happen on this call. + */ static void tuner_status(struct dvb_frontend *fe) { struct tuner *t = fe->analog_demod_priv; @@ -932,10 +933,16 @@ static void tuner_status(struct dvb_frontend *fe) const char *p; switch (t->mode) { - case V4L2_TUNER_RADIO: p = "radio"; break; - case V4L2_TUNER_ANALOG_TV: p = "analog TV"; break; - case V4L2_TUNER_DIGITAL_TV: p = "digital TV"; break; - default: p = "undefined"; break; + case V4L2_TUNER_RADIO: + p = "radio"; + break; + case V4L2_TUNER_DIGITAL_TV: + p = "digital TV"; + break; + case V4L2_TUNER_ANALOG_TV: + default: + p = "analog TV"; + break; } if (t->mode == V4L2_TUNER_RADIO) { freq = t->radio_freq / 16000; @@ -944,7 +951,8 @@ static void tuner_status(struct dvb_frontend *fe) freq = t->tv_freq / 16; freq_fraction = (t->tv_freq % 16) * 100 / 16; } - tuner_info("Tuner mode: %s\n", p); + tuner_info("Tuner mode: %s%s\n", p, + t->standby ? " on standby mode" : ""); tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) @@ -963,19 +971,22 @@ static void tuner_status(struct dvb_frontend *fe) analog_ops->has_signal(fe)); } +/** + * tuner_s_power - controls the power state of the tuner + * @sd: pointer to struct v4l2_subdev + * @on: a zero value puts the tuner to sleep + */ static int tuner_s_power(struct v4l2_subdev *sd, int on) { struct tuner *t = to_tuner(sd); struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + /* FIXME: Why this function don't wake the tuner if on != 0 ? */ if (on) return 0; tuner_dbg("Putting tuner to sleep\n"); - - if (check_mode(t) == -EINVAL) - return 0; - t->mode = T_STANDBY; + t->standby = true; if (analog_ops->standby) analog_ops->standby(&t->fe); return 0; @@ -983,13 +994,12 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) /* ---------------------------------------------------------------------- */ - static int tuner_s_radio(struct v4l2_subdev *sd) { struct tuner *t = to_tuner(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode(client, t, V4L2_TUNER_RADIO, "s_radio") == -EINVAL) + if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL) return 0; return 0; } @@ -1002,13 +1012,12 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) struct tuner *t = to_tuner(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode(client, t, V4L2_TUNER_ANALOG_TV, "s_std") == -EINVAL) + if (set_mode_freq(client, t, V4L2_TUNER_ANALOG_TV, 0) == -EINVAL) return 0; t->std = std; tuner_fixup_std(t); - if (t->tv_freq) - set_freq(client, t->tv_freq); + return 0; } @@ -1017,9 +1026,8 @@ static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) struct tuner *t = to_tuner(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (set_mode(client, t, f->type, "s_frequency") == -EINVAL) + if (set_mode_freq(client, t, f->type, f->frequency) == -EINVAL) return 0; - set_freq(client, f->frequency); return 0; } @@ -1029,20 +1037,20 @@ static int tuner_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) struct tuner *t = to_tuner(sd); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - if (check_mode(t) == -EINVAL) + if (check_mode(t, f->type) == -EINVAL) return 0; f->type = t->mode; - if (fe_tuner_ops->get_frequency) { + if (fe_tuner_ops->get_frequency && !t->standby) { u32 abs_freq; fe_tuner_ops->get_frequency(&t->fe, &abs_freq); f->frequency = (V4L2_TUNER_RADIO == t->mode) ? DIV_ROUND_CLOSEST(abs_freq * 2, 125) : DIV_ROUND_CLOSEST(abs_freq, 62500); - return 0; + } else { + f->frequency = (V4L2_TUNER_RADIO == t->mode) ? + t->radio_freq : t->tv_freq; } - f->frequency = (V4L2_TUNER_RADIO == t->mode) ? - t->radio_freq : t->tv_freq; return 0; } @@ -1052,9 +1060,8 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - if (check_mode(t) == -EINVAL) + if (check_mode(t, vt->type) == -EINVAL) return 0; - vt->type = t->mode; if (analog_ops->get_afc) vt->afc = analog_ops->get_afc(&t->fe); @@ -1067,8 +1074,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) } /* radio mode */ - vt->rxsubchans = - V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (fe_tuner_ops->get_status) { u32 tuner_status; @@ -1080,11 +1086,11 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) } if (analog_ops->has_signal) vt->signal = analog_ops->has_signal(&t->fe); - vt->capability |= - V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + vt->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; vt->audmode = t->audmode; vt->rangelow = radio_range[0] * 16000; vt->rangehigh = radio_range[1] * 16000; + return 0; } @@ -1093,14 +1099,12 @@ static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) struct tuner *t = to_tuner(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - if (check_mode(t) == -EINVAL) + if (set_mode_freq(client, t, vt->type, 0) == -EINVAL) return 0; - /* do nothing unless we're a radio tuner */ - if (t->mode != V4L2_TUNER_RADIO) - return 0; - t->audmode = vt->audmode; - set_radio_freq(client, t->radio_freq); + if (t->mode == V4L2_TUNER_RADIO) + t->audmode = vt->audmode; + return 0; } @@ -1128,13 +1132,10 @@ static int tuner_resume(struct i2c_client *c) struct tuner *t = to_tuner(i2c_get_clientdata(c)); tuner_dbg("resume\n"); - if (V4L2_TUNER_RADIO == t->mode) { - if (t->radio_freq) - set_freq(c, t->radio_freq); - } else { - if (t->tv_freq) - set_freq(c, t->tv_freq); - } + if (V4L2_TUNER_RADIO == t->mode) + set_freq(c, t->radio_freq); + else + set_freq(c, t->tv_freq); return 0; } -- cgit v1.2.2 From e2f63d9ba51efe8930bf1c952c66b971047d355d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 4 Feb 2011 11:15:21 -0300 Subject: [media] tuner-core: do the right thing for suspend/resume Power down tuners at suspend. At resume, if the tuner is in standby, calls set_mode, that will turn it on and set the latest frequencies. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e6855a46f433..e6b63e9c0b34 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1121,9 +1121,13 @@ static int tuner_log_status(struct v4l2_subdev *sd) static int tuner_suspend(struct i2c_client *c, pm_message_t state) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; tuner_dbg("suspend\n"); - /* FIXME: power down ??? */ + + if (!t->standby && analog_ops->standby) + analog_ops->standby(&t->fe); + return 0; } @@ -1132,10 +1136,10 @@ static int tuner_resume(struct i2c_client *c) struct tuner *t = to_tuner(i2c_get_clientdata(c)); tuner_dbg("resume\n"); - if (V4L2_TUNER_RADIO == t->mode) - set_freq(c, t->radio_freq); - else - set_freq(c, t->tv_freq); + + if (!t->standby) + set_mode_freq(c, t, t->type, 0); + return 0; } -- cgit v1.2.2 From 7d275bf840a8f390b8fd3d686545e09ef01f7915 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 4 Feb 2011 11:28:00 -0300 Subject: [media] tuner-core: CodingStyle cleanups Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 92 ++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index e6b63e9c0b34..70ff416c0ced 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -32,7 +32,7 @@ #define UNSET (-1U) -#define PREFIX t->i2c->driver->driver.name +#define PREFIX (t->i2c->driver->driver.name) /* * Driver modprobe parameters @@ -55,7 +55,7 @@ static char pal[] = "--"; static char secam[] = "--"; static char ntsc[] = "-"; -module_param_named(debug,tuner_debug, int, 0644); +module_param_named(debug, tuner_debug, int, 0644); module_param_array(tv_range, int, NULL, 0644); module_param_array(radio_range, int, NULL, 0644); module_param_string(pal, pal, sizeof(pal), 0644); @@ -252,7 +252,7 @@ static void set_type(struct i2c_client *c, unsigned int type, int tune_now = 1; if (type == UNSET || type == TUNER_ABSENT) { - tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr); + tuner_dbg("tuner 0x%02x: Tuner type absent\n", c->addr); return; } @@ -422,9 +422,9 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); - if ( (t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && - (t->mode_mask & tun_setup->mode_mask))) || - (tun_setup->addr == c->addr)) { + if ((t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && + (t->mode_mask & tun_setup->mode_mask))) || + (tun_setup->addr == c->addr)) { set_type(c, tun_setup->type, tun_setup->mode_mask, tun_setup->config, tun_setup->tuner_callback); } else @@ -449,7 +449,8 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type) return 0; } -static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg) +static int tuner_s_config(struct v4l2_subdev *sd, + const struct v4l2_priv_tun_config *cfg) { struct tuner *t = to_tuner(sd); struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; @@ -601,13 +602,12 @@ static int tuner_probe(struct i2c_client *client, /* Should be just before return */ register_client: /* Sets a default mode */ - if (t->mode_mask & T_ANALOG_TV) { + if (t->mode_mask & T_ANALOG_TV) t->mode = V4L2_TUNER_ANALOG_TV; - } else if (t->mode_mask & T_RADIO) { + else if (t->mode_mask & T_RADIO) t->mode = V4L2_TUNER_RADIO; - } else { + else t->mode = V4L2_TUNER_DIGITAL_TV; - } set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); list_add_tail(&t->list, &tuner_list); @@ -649,15 +649,15 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) }; if (t->type == UNSET) { - tuner_warn ("tuner type not set\n"); + tuner_warn("tuner type not set\n"); return; } if (NULL == analog_ops->set_params) { - tuner_warn ("Tuner has no way to set tv freq\n"); + tuner_warn("Tuner has no way to set tv freq\n"); return; } if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { - tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n", + tuner_dbg("TV freq (%d.%02d) out of range (%d-%d)\n", freq / 16, freq % 16 * 100 / 16, tv_range[0], tv_range[1]); /* V4L2 spec: if the freq is not possible then the closest @@ -682,31 +682,31 @@ static int tuner_fixup_std(struct tuner *t) if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { switch (pal[0]) { case '6': - tuner_dbg ("insmod fixup: PAL => PAL-60\n"); + tuner_dbg("insmod fixup: PAL => PAL-60\n"); t->std = V4L2_STD_PAL_60; break; case 'b': case 'B': case 'g': case 'G': - tuner_dbg ("insmod fixup: PAL => PAL-BG\n"); + tuner_dbg("insmod fixup: PAL => PAL-BG\n"); t->std = V4L2_STD_PAL_BG; break; case 'i': case 'I': - tuner_dbg ("insmod fixup: PAL => PAL-I\n"); + tuner_dbg("insmod fixup: PAL => PAL-I\n"); t->std = V4L2_STD_PAL_I; break; case 'd': case 'D': case 'k': case 'K': - tuner_dbg ("insmod fixup: PAL => PAL-DK\n"); + tuner_dbg("insmod fixup: PAL => PAL-DK\n"); t->std = V4L2_STD_PAL_DK; break; case 'M': case 'm': - tuner_dbg ("insmod fixup: PAL => PAL-M\n"); + tuner_dbg("insmod fixup: PAL => PAL-M\n"); t->std = V4L2_STD_PAL_M; break; case 'N': @@ -715,7 +715,7 @@ static int tuner_fixup_std(struct tuner *t) tuner_dbg("insmod fixup: PAL => PAL-Nc\n"); t->std = V4L2_STD_PAL_Nc; } else { - tuner_dbg ("insmod fixup: PAL => PAL-N\n"); + tuner_dbg("insmod fixup: PAL => PAL-N\n"); t->std = V4L2_STD_PAL_N; } break; @@ -723,7 +723,7 @@ static int tuner_fixup_std(struct tuner *t) /* default parameter, do nothing */ break; default: - tuner_warn ("pal= argument not recognised\n"); + tuner_warn("pal= argument not recognised\n"); break; } } @@ -736,22 +736,24 @@ static int tuner_fixup_std(struct tuner *t) case 'h': case 'H': tuner_dbg("insmod fixup: SECAM => SECAM-BGH\n"); - t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + t->std = V4L2_STD_SECAM_B | + V4L2_STD_SECAM_G | + V4L2_STD_SECAM_H; break; case 'd': case 'D': case 'k': case 'K': - tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n"); + tuner_dbg("insmod fixup: SECAM => SECAM-DK\n"); t->std = V4L2_STD_SECAM_DK; break; case 'l': case 'L': - if ((secam[1]=='C')||(secam[1]=='c')) { - tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n"); + if ((secam[1] == 'C') || (secam[1] == 'c')) { + tuner_dbg("insmod fixup: SECAM => SECAM-L'\n"); t->std = V4L2_STD_SECAM_LC; } else { - tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); + tuner_dbg("insmod fixup: SECAM => SECAM-L\n"); t->std = V4L2_STD_SECAM_L; } break; @@ -759,7 +761,7 @@ static int tuner_fixup_std(struct tuner *t) /* default parameter, do nothing */ break; default: - tuner_warn ("secam= argument not recognised\n"); + tuner_warn("secam= argument not recognised\n"); break; } } @@ -808,15 +810,15 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) }; if (t->type == UNSET) { - tuner_warn ("tuner type not set\n"); + tuner_warn("tuner type not set\n"); return; } if (NULL == analog_ops->set_params) { - tuner_warn ("tuner has no way to set radio frequency\n"); + tuner_warn("tuner has no way to set radio frequency\n"); return; } if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) { - tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n", + tuner_dbg("radio freq (%d.%02d) out of range (%d-%d)\n", freq / 16000, freq % 16000 * 100 / 16000, radio_range[0], radio_range[1]); /* V4L2 spec: if the freq is not possible then the closest @@ -848,9 +850,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) */ static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) { - if ((1 << mode & t->mode_mask) == 0) { + if ((1 << mode & t->mode_mask) == 0) return -EINVAL; - } + return 0; } @@ -867,7 +869,7 @@ static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) * the tuner can sleep or if it supports both Radio and TV. */ static int set_mode_freq(struct i2c_client *client, struct tuner *t, - enum v4l2_tuner_type mode, unsigned int freq) + enum v4l2_tuner_type mode, unsigned int freq) { struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; @@ -913,7 +915,7 @@ static void set_freq(struct i2c_client *c, unsigned long freq) set_tv_freq(c, freq); break; default: - tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); + tuner_dbg("freq set: unknown mode: 0x%04x!\n", t->mode); } } @@ -933,16 +935,16 @@ static void tuner_status(struct dvb_frontend *fe) const char *p; switch (t->mode) { - case V4L2_TUNER_RADIO: - p = "radio"; - break; - case V4L2_TUNER_DIGITAL_TV: - p = "digital TV"; - break; - case V4L2_TUNER_ANALOG_TV: - default: - p = "analog TV"; - break; + case V4L2_TUNER_RADIO: + p = "radio"; + break; + case V4L2_TUNER_DIGITAL_TV: + p = "digital TV"; + break; + case V4L2_TUNER_ANALOG_TV: + default: + p = "analog TV"; + break; } if (t->mode == V4L2_TUNER_RADIO) { freq = t->radio_freq / 16000; @@ -956,7 +958,7 @@ static void tuner_status(struct dvb_frontend *fe) tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) - return; + return; if (fe_tuner_ops->get_status) { u32 tuner_status; -- cgit v1.2.2 From 900f734b3bafb4e111b9ec5d865c448a9911b2ab Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 4 Feb 2011 12:56:39 -0300 Subject: [media] tuner-core: Don't use a static var for xc5000_cfg A static var is evil, especially if a device has two boards with xc5000. Instead, just like the other drivers, use stack to store its config during setup. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 70ff416c0ced..16939cad987c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -66,7 +66,6 @@ module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); * Static vars */ -static struct xc5000_config xc5000_cfg; static LIST_HEAD(tuner_list); /* @@ -338,9 +337,12 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_XC5000: { - xc5000_cfg.i2c_address = t->i2c->addr; - /* if_khz will be set when the digital dvb_attach() occurs */ - xc5000_cfg.if_khz = 0; + struct xc5000_config xc5000_cfg = { + .i2c_address = t->i2c->addr, + /* if_khz will be set at dvb_attach() */ + .if_khz = 0, + }; + if (!dvb_attach(xc5000_attach, &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; -- cgit v1.2.2 From a34ec5f3743950cadb8f512c884b8c9dbaa9a7a5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 15 Feb 2011 00:55:18 -0300 Subject: [media] tuner-core: dead code removal Remove the now obsolete set_freq. Also merge set_addr and set_type_addr. In the past, it used to have two different setup calls, one to set just the tuner type to any tuner found, and another to set the type only if the address matches. Those two internal calls were grouped together, but the functions weren't merged, making the code uglier. No functional changes are done in this patch. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 47 +++++++++------------------------------- 1 file changed, 10 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 16939cad987c..2a0bea145a78 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -419,10 +419,17 @@ attach_failed: * it's applied. Otherwise status and type are applied only to * tuner with exactly the same addr. */ - -static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) +static int tuner_s_type_addr(struct v4l2_subdev *sd, + struct tuner_setup *tun_setup) { - struct tuner *t = to_tuner(i2c_get_clientdata(c)); + struct tuner *t = to_tuner(sd); + struct i2c_client *c = v4l2_get_subdevdata(sd); + + tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", + tun_setup->type, + tun_setup->addr, + tun_setup->mode_mask, + tun_setup->config); if ((t->type == UNSET && ((tun_setup->addr == ADDR_UNSET) && (t->mode_mask & tun_setup->mode_mask))) || @@ -434,20 +441,7 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup) "Asked to change tuner at addr 0x%02x, with mask %x\n", t->type, t->mode_mask, tun_setup->addr, tun_setup->mode_mask); -} - -static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *type) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", - type->type, - type->addr, - type->mode_mask, - type->config); - - set_addr(client, type); return 0; } @@ -900,27 +894,6 @@ static int set_mode_freq(struct i2c_client *client, struct tuner *t, return 0; } -/* - * Functions that should be broken into separate radio/TV functions - */ - -static void set_freq(struct i2c_client *c, unsigned long freq) -{ - struct tuner *t = to_tuner(i2c_get_clientdata(c)); - - switch (t->mode) { - case V4L2_TUNER_RADIO: - set_radio_freq(c, freq); - break; - case V4L2_TUNER_ANALOG_TV: - case V4L2_TUNER_DIGITAL_TV: - set_tv_freq(c, freq); - break; - default: - tuner_dbg("freq set: unknown mode: 0x%04x!\n", t->mode); - } -} - /** * tuner_status - Dumps the current tuner status at dmesg * @fe: pointer to struct dvb_frontend -- cgit v1.2.2 From 0ae79d993cd5ce425bedebcbd2f8c4fa310acfe6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 15 Feb 2011 01:10:20 -0300 Subject: [media] tuner-core: Fix a few comments on it Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2a0bea145a78..dcf03face265 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -128,7 +128,7 @@ struct tuner { * tuner attach/detach logic */ -/** This macro allows us to probe dynamically, avoiding static links */ +/* This macro allows us to probe dynamically, avoiding static links */ #ifdef CONFIG_MEDIA_ATTACH #define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ int __r = -EINVAL; \ @@ -412,13 +412,20 @@ attach_failed: return; } -/* - * This function apply tuner config to tuner specified - * by tun_setup structure. I addr is unset, then admin status - * and tun addr status is more precise then current status, - * it's applied. Otherwise status and type are applied only to - * tuner with exactly the same addr. -*/ +/** + * tuner_s_type_addr - Sets the tuner type for a device + * + * @sd: subdev descriptor + * @tun_setup: type to be associated to a given tuner i2c address + * + * This function applys the tuner config to tuner specified + * by tun_setup structure. + * If tuner I2C address is UNSET, then it will only set the device + * if the tuner supports the mode specified in the call. + * If the address is specified, the change will be applied only if + * tuner I2C address matches. + * The call can change the tuner number and the tuner mode. + */ static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner_setup *tun_setup) { -- cgit v1.2.2 From 2d351df443b0b324a440b5fd053074562d36a7f5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 14 Feb 2011 18:53:12 -0200 Subject: [media] Remove the remaining usages for T_STANDBY tda9887 used to use the T_STANDBY type internally, while tea5761 used it to put the device to sleep. Fix the code for it to work properly with the tuner core changes and remove this flag from tuner.h. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda9887.c | 9 ++++++--- drivers/media/common/tuners/tea5761.c | 33 ++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda9887.c b/drivers/media/common/tuners/tda9887.c index bf14bd79e2fc..cdb645d57438 100644 --- a/drivers/media/common/tuners/tda9887.c +++ b/drivers/media/common/tuners/tda9887.c @@ -36,6 +36,8 @@ struct tda9887_priv { unsigned int mode; unsigned int audmode; v4l2_std_id std; + + bool standby; }; /* ---------------------------------------------------------------------- */ @@ -568,7 +570,7 @@ static void tda9887_configure(struct dvb_frontend *fe) tda9887_do_config(fe); tda9887_set_insmod(fe); - if (priv->mode == T_STANDBY) + if (priv->standby) priv->data[1] |= cForcedMuteAudioON; tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", @@ -616,7 +618,7 @@ static void tda9887_standby(struct dvb_frontend *fe) { struct tda9887_priv *priv = fe->analog_demod_priv; - priv->mode = T_STANDBY; + priv->standby = true; tda9887_configure(fe); } @@ -626,6 +628,7 @@ static void tda9887_set_params(struct dvb_frontend *fe, { struct tda9887_priv *priv = fe->analog_demod_priv; + priv->standby = false; priv->mode = params->mode; priv->audmode = params->audmode; priv->std = params->std; @@ -686,7 +689,7 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, return NULL; case 1: fe->analog_demod_priv = priv; - priv->mode = T_STANDBY; + priv->standby = true; tuner_info("tda988[5/6/7] found\n"); break; default: diff --git a/drivers/media/common/tuners/tea5761.c b/drivers/media/common/tuners/tea5761.c index 925399dffbed..bf78cb9fc52c 100644 --- a/drivers/media/common/tuners/tea5761.c +++ b/drivers/media/common/tuners/tea5761.c @@ -23,6 +23,7 @@ struct tea5761_priv { struct tuner_i2c_props i2c_props; u32 frequency; + bool standby; }; /*****************************************************************************/ @@ -135,18 +136,19 @@ static void tea5761_status_dump(unsigned char *buffer) } /* Freq should be specifyed at 62.5 Hz */ -static int set_radio_freq(struct dvb_frontend *fe, - struct analog_parameters *params) +static int __set_radio_freq(struct dvb_frontend *fe, + unsigned int freq, + bool mono) { struct tea5761_priv *priv = fe->tuner_priv; - unsigned int frq = params->frequency; + unsigned int frq = freq; unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; unsigned div; int rc; tuner_dbg("radio freq counter %d\n", frq); - if (params->mode == T_STANDBY) { + if (priv->standby) { tuner_dbg("TEA5761 set to standby mode\n"); buffer[5] |= TEA5761_TNCTRL_MU; } else { @@ -154,7 +156,7 @@ static int set_radio_freq(struct dvb_frontend *fe, } - if (params->audmode == V4L2_TUNER_MODE_MONO) { + if (mono) { tuner_dbg("TEA5761 set to mono\n"); buffer[5] |= TEA5761_TNCTRL_MST; } else { @@ -176,6 +178,26 @@ static int set_radio_freq(struct dvb_frontend *fe, return 0; } +static int set_radio_freq(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tea5761_priv *priv = fe->analog_demod_priv; + + priv->standby = false; + + return __set_radio_freq(fe, params->frequency, + params->audmode == V4L2_TUNER_MODE_MONO); +} + +static int set_radio_sleep(struct dvb_frontend *fe) +{ + struct tea5761_priv *priv = fe->analog_demod_priv; + + priv->standby = true; + + return __set_radio_freq(fe, priv->frequency, false); +} + static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) { struct tea5761_priv *priv = fe->tuner_priv; @@ -284,6 +306,7 @@ static struct dvb_tuner_ops tea5761_tuner_ops = { .name = "tea5761", // Philips TEA5761HN FM Radio }, .set_analog_params = set_radio_freq, + .sleep = set_radio_sleep, .release = tea5761_release, .get_frequency = tea5761_get_frequency, .get_status = tea5761_get_status, -- cgit v1.2.2 From ad020dc2fe9039628cf6cef42cd1b76531ee8411 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 15 Feb 2011 09:30:50 -0200 Subject: [media] tuner-core: remove usage of DIGITAL_TV tuner-core has no business to do with digital TV. So, don't use T_DIGITAL_TV on it, as it has no code to distinguish between them, and nobody fills T_DIGITAL_TV right. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/au0828/au0828-cards.c | 3 +-- drivers/media/video/bt8xx/bttv-cards.c | 2 +- drivers/media/video/cx88/cx88-cards.c | 4 +--- drivers/media/video/saa7134/saa7134-cards.c | 4 +--- drivers/media/video/tuner-core.c | 18 +++++++----------- 5 files changed, 11 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 01be89fa5c78..39fc923fc46b 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c @@ -185,8 +185,7 @@ void au0828_card_setup(struct au0828_dev *dev) static u8 eeprom[256]; struct tuner_setup tun_setup; struct v4l2_subdev *sd; - unsigned int mode_mask = T_ANALOG_TV | - T_DIGITAL_TV; + unsigned int mode_mask = T_ANALOG_TV; dprintk(1, "%s()\n", __func__); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 7f58756d72c8..242f0d512238 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -3616,7 +3616,7 @@ void __devinit bttv_init_tuner(struct bttv *btv) &btv->c.i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD)); - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + tun_setup.mode_mask = T_ANALOG_TV; tun_setup.type = btv->tuner_type; tun_setup.addr = addr; diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 4e6ee5584cb3..8128b936c686 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -3165,9 +3165,7 @@ static void cx88_card_setup(struct cx88_core *core) { static u8 eeprom[256]; struct tuner_setup tun_setup; - unsigned int mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; + unsigned int mode_mask = T_RADIO | T_ANALOG_TV; memset(&tun_setup, 0, sizeof(tun_setup)); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 74467c18e69a..61c6007c8ea6 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -7333,9 +7333,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) static void saa7134_tuner_setup(struct saa7134_dev *dev) { struct tuner_setup tun_setup; - unsigned int mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; + unsigned int mode_mask = T_RADIO | T_ANALOG_TV; memset(&tun_setup, 0, sizeof(tun_setup)); tun_setup.tuner_callback = saa7134_tuner_callback; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index dcf03face265..5e1437c358f8 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -497,7 +497,7 @@ static void tuner_lookup(struct i2c_adapter *adap, device. If other devices appear then we need to make this test more general. */ else if (*tv == NULL && pos->type != TUNER_TDA9887 && - (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) + (pos->mode_mask & T_ANALOG_TV)) *tv = pos; } } @@ -565,8 +565,7 @@ static int tuner_probe(struct i2c_client *client, } else { /* Default is being tda9887 */ t->type = TUNER_TDA9887; - t->mode_mask = T_RADIO | T_ANALOG_TV | - T_DIGITAL_TV; + t->mode_mask = T_RADIO | T_ANALOG_TV; goto register_client; } break; @@ -596,7 +595,7 @@ static int tuner_probe(struct i2c_client *client, first found TV tuner. */ tuner_lookup(t->i2c->adapter, &radio, &tv); if (tv == NULL) { - t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + t->mode_mask = T_ANALOG_TV; if (radio == NULL) t->mode_mask |= T_RADIO; tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); @@ -607,18 +606,15 @@ register_client: /* Sets a default mode */ if (t->mode_mask & T_ANALOG_TV) t->mode = V4L2_TUNER_ANALOG_TV; - else if (t->mode_mask & T_RADIO) - t->mode = V4L2_TUNER_RADIO; else - t->mode = V4L2_TUNER_DIGITAL_TV; + t->mode = V4L2_TUNER_RADIO; set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); list_add_tail(&t->list, &tuner_list); - tuner_info("Tuner %d found with type(s)%s%s%s.\n", + tuner_info("Tuner %d found with type(s)%s%s.\n", t->type, - t->mode_mask & T_RADIO ? " radio" : "", - t->mode_mask & T_ANALOG_TV ? " TV" : "", - t->mode_mask & T_ANALOG_TV ? " DTV" : ""); + t->mode_mask & T_RADIO ? " Radio" : "", + t->mode_mask & T_ANALOG_TV ? " TV" : ""); return 0; } -- cgit v1.2.2 From a2894e3f8ed691b4873c8122e66902fbf0e78e0b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 15 Feb 2011 10:15:19 -0200 Subject: [media] tuner-core: Improve function documentation This driver is complex, and used by everyone. Better to have it properly documented. No functional changes are done in this patch. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 139 ++++++++++++++++++++++++++++++++------- 1 file changed, 116 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 5e1437c358f8..2c7fe18cedeb 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1,7 +1,17 @@ /* - * * i2c tv tuner chip device driver * core core, i.e. kernel interfaces, registering and so on + * + * Copyright(c) by Ralph Metzler, Gerd Knorr, Gunther Mayer + * + * Copyright(c) 2005-2011 by Mauro Carvalho Chehab + * - Added support for a separate Radio tuner + * - Major rework and cleanups at the code + * + * This driver supports many devices and the idea is to let the driver + * detect which device is present. So rather than listing all supported + * devices here, we pretend to support a single, fake device type that will + * handle both radio and analog TV tuning. */ #include @@ -67,6 +77,7 @@ module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); */ static LIST_HEAD(tuner_list); +static const struct v4l2_subdev_ops tuner_ops; /* * Debug macros @@ -124,6 +135,13 @@ struct tuner { const char *name; }; +/* + * Function prototypes + */ + +static void set_tv_freq(struct i2c_client *c, unsigned int freq); +static void set_radio_freq(struct i2c_client *c, unsigned int freq); + /* * tuner attach/detach logic */ @@ -233,13 +251,24 @@ static struct analog_demod_ops tuner_analog_ops = { }; /* - * Functions that are common to both TV and radio + * Functions to select between radio and TV and tuner probe functions */ -static void set_tv_freq(struct i2c_client *c, unsigned int freq); -static void set_radio_freq(struct i2c_client *c, unsigned int freq); -static const struct v4l2_subdev_ops tuner_ops; - +/** + * set_type - Sets the tuner type for a given device + * + * @c: i2c_client descriptoy + * @type: type of the tuner (e. g. tuner number) + * @new_mode_mask: Indicates if tuner supports TV and/or Radio + * @new_config: an optional parameter ranging from 0-255 used by + a few tuners to adjust an internal parameter, + like LNA mode + * @tuner_callback: an optional function to be called when switching + * to analog mode + * + * This function applys the tuner config to tuner specified + * by tun_setup structure. It contains several per-tuner initialization "magic" + */ static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int component, int cmd, int arg)) @@ -452,6 +481,15 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd, return 0; } +/** + * tuner_s_config - Sets tuner configuration + * + * @sd: subdev descriptor + * @cfg: tuner configuration + * + * Calls tuner set_config() private function to set some tuner-internal + * parameters + */ static int tuner_s_config(struct v4l2_subdev *sd, const struct v4l2_priv_tun_config *cfg) { @@ -470,10 +508,20 @@ static int tuner_s_config(struct v4l2_subdev *sd, return 0; } -/* Search for existing radio and/or TV tuners on the given I2C adapter. - Note that when this function is called from tuner_probe you can be - certain no other devices will be added/deleted at the same time, I2C - core protects against that. */ +/** + * tuner_lookup - Seek for tuner adapters + * + * @adap: i2c_adapter struct + * @radio: pointer to be filled if the adapter is radio + * @tv: pointer to be filled if the adapter is TV + * + * Search for existing radio and/or TV tuners on the given I2C adapter, + * discarding demod-only adapters (tda9887). + * + * Note that when this function is called from tuner_probe you can be + * certain no other devices will be added/deleted at the same time, I2C + * core protects against that. + */ static void tuner_lookup(struct i2c_adapter *adap, struct tuner **radio, struct tuner **tv) { @@ -502,8 +550,20 @@ static void tuner_lookup(struct i2c_adapter *adap, } } -/* During client attach, set_type is called by adapter's attach_inform callback. - set_type must then be completed by tuner_probe. +/** + *tuner_probe - Probes the existing tuners on an I2C bus + * + * @client: i2c_client descriptor + * @id: not used + * + * This routine probes for tuners at the expected I2C addresses. On most + * cases, if a device answers to a given I2C address, it assumes that the + * device is a tuner. On a few cases, however, an additional logic is needed + * to double check if the device is really a tuner, or to identify the tuner + * type, like on tea5767/5761 devices. + * + * During client attach, set_type is called by adapter's attach_inform callback. + * set_type must then be completed by tuner_probe. */ static int tuner_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -618,6 +678,12 @@ register_client: return 0; } +/** + * tuner_remove - detaches a tuner + * + * @client: i2c_client descriptor + */ + static int tuner_remove(struct i2c_client *client) { struct tuner *t = to_tuner(i2c_get_clientdata(client)); @@ -635,7 +701,12 @@ static int tuner_remove(struct i2c_client *client) * Functions that are specific for TV mode */ -/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ +/** + * set_tv_freq - Set tuner frequency, freq in Units of 62.5 kHz = 1/16MHz + * + * @c: i2c_client descriptor + * @freq: frequency + */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); @@ -675,7 +746,19 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) analog_ops->set_params(&t->fe, ¶ms); } -/* get more precise norm info from insmod option */ +/** + * tuner_fixup_std - force a given video standard variant + * + * @t: tuner internal struct + * + * A few devices or drivers have problem to detect some standard variations. + * On other operational systems, the drivers generally have a per-country + * code, and some logic to apply per-country hacks. V4L2 API doesn't provide + * such hacks. Instead, it relies on a proper video standard selection from + * the userspace application. However, as some apps are buggy, not allowing + * to distinguish all video standard variations, a modprobe parameter can + * be used to force a video standard match. + */ static int tuner_fixup_std(struct tuner *t) { if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) { @@ -797,6 +880,12 @@ static int tuner_fixup_std(struct tuner *t) * Functions that are specific for Radio mode */ +/** + * set_radio_freq - Set tuner frequency, freq in Units of 62.5 Hz = 1/16kHz + * + * @c: i2c_client descriptor + * @freq: frequency + */ static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); @@ -972,7 +1061,9 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) return 0; } -/* ---------------------------------------------------------------------- */ +/* + * Function to splicitly change mode to radio. Probably not needed anymore + */ static int tuner_s_radio(struct v4l2_subdev *sd) { @@ -984,9 +1075,10 @@ static int tuner_s_radio(struct v4l2_subdev *sd) return 0; } -/* --- v4l ioctls --- */ -/* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ +/* + * Tuner callbacks to handle userspace ioctl's + */ + static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct tuner *t = to_tuner(sd); @@ -1137,7 +1229,9 @@ static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg) return -ENOIOCTLCMD; } -/* ----------------------------------------------------------------------- */ +/* + * Callback structs + */ static const struct v4l2_subdev_core_ops tuner_core_ops = { .log_status = tuner_log_status, @@ -1160,11 +1254,10 @@ static const struct v4l2_subdev_ops tuner_ops = { .tuner = &tuner_tuner_ops, }; -/* ----------------------------------------------------------------------- */ +/* + * I2C structs and module init functions + */ -/* This driver supports many devices and the idea is to let the driver - detect which device is present. So rather than listing all supported - devices here, we pretend to support a single, fake device type. */ static const struct i2c_device_id tuner_id[] = { { "tuner", }, /* autodetect */ { } -- cgit v1.2.2 From 0eec66c0dfc1b066e6addbc6af755c779f65fd87 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 15 Feb 2011 10:27:03 -0200 Subject: [media] tuner-core: Rearrange some functions to better document Group a few functions together and add/fix comments for each block of the driver. This is just a cleanup patch meant to improve driver readability. No functional changes in this patch. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 168 +++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2c7fe18cedeb..a91a29978f9c 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -251,7 +251,7 @@ static struct analog_demod_ops tuner_analog_ops = { }; /* - * Functions to select between radio and TV and tuner probe functions + * Functions to select between radio and TV and tuner probe/remove functions */ /** @@ -697,6 +697,75 @@ static int tuner_remove(struct i2c_client *client) return 0; } +/* + * Functions to switch between Radio and TV + * + * A few cards have a separate I2C tuner for radio. Those routines + * take care of switching between TV/Radio mode, filtering only the + * commands that apply to the Radio or TV tuner. + */ + +/** + * check_mode - Verify if tuner supports the requested mode + * @t: a pointer to the module's internal struct_tuner + * + * This function checks if the tuner is capable of tuning analog TV, + * digital TV or radio, depending on what the caller wants. If the + * tuner can't support that mode, it returns -EINVAL. Otherwise, it + * returns 0. + * This function is needed for boards that have a separate tuner for + * radio (like devices with tea5767). + */ +static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) +{ + if ((1 << mode & t->mode_mask) == 0) + return -EINVAL; + + return 0; +} + +/** + * set_mode_freq - Switch tuner to other mode. + * @client: struct i2c_client pointer + * @t: a pointer to the module's internal struct_tuner + * @mode: enum v4l2_type (radio or TV) + * @freq: frequency to set (0 means to use the previous one) + * + * If tuner doesn't support the needed mode (radio or TV), prints a + * debug message and returns -EINVAL, changing its state to standby. + * Otherwise, changes the state and sets frequency to the last value, if + * the tuner can sleep or if it supports both Radio and TV. + */ +static int set_mode_freq(struct i2c_client *client, struct tuner *t, + enum v4l2_tuner_type mode, unsigned int freq) +{ + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + + if (mode != t->mode) { + if (check_mode(t, mode) == -EINVAL) { + tuner_dbg("Tuner doesn't support mode %d. " + "Putting tuner to sleep\n", mode); + t->standby = true; + if (analog_ops->standby) + analog_ops->standby(&t->fe); + return -EINVAL; + } + t->mode = mode; + tuner_dbg("Changing to mode %d\n", mode); + } + if (t->mode == V4L2_TUNER_RADIO) { + if (freq) + t->radio_freq = freq; + set_radio_freq(client, t->radio_freq); + } else { + if (freq) + t->tv_freq = freq; + set_tv_freq(client, t->tv_freq); + } + + return 0; +} + /* * Functions that are specific for TV mode */ @@ -925,66 +994,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) analog_ops->set_params(&t->fe, ¶ms); } -/** - * check_mode - Verify if tuner supports the requested mode - * @t: a pointer to the module's internal struct_tuner - * - * This function checks if the tuner is capable of tuning analog TV, - * digital TV or radio, depending on what the caller wants. If the - * tuner can't support that mode, it returns -EINVAL. Otherwise, it - * returns 0. - * This function is needed for boards that have a separate tuner for - * radio (like devices with tea5767). - */ -static inline int check_mode(struct tuner *t, enum v4l2_tuner_type mode) -{ - if ((1 << mode & t->mode_mask) == 0) - return -EINVAL; - - return 0; -} - -/** - * set_mode_freq - Switch tuner to other mode. - * @client: struct i2c_client pointer - * @t: a pointer to the module's internal struct_tuner - * @mode: enum v4l2_type (radio or TV) - * @freq: frequency to set (0 means to use the previous one) - * - * If tuner doesn't support the needed mode (radio or TV), prints a - * debug message and returns -EINVAL, changing internal state to T_STANDBY. - * Otherwise, changes the state and sets frequency to the last value, if - * the tuner can sleep or if it supports both Radio and TV. +/* + * Debug function for reporting tuner status to userspace */ -static int set_mode_freq(struct i2c_client *client, struct tuner *t, - enum v4l2_tuner_type mode, unsigned int freq) -{ - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - - if (mode != t->mode) { - if (check_mode(t, mode) == -EINVAL) { - tuner_dbg("Tuner doesn't support mode %d. " - "Putting tuner to sleep\n", mode); - t->standby = true; - if (analog_ops->standby) - analog_ops->standby(&t->fe); - return -EINVAL; - } - t->mode = mode; - tuner_dbg("Changing to mode %d\n", mode); - } - if (t->mode == V4L2_TUNER_RADIO) { - if (freq) - t->radio_freq = freq; - set_radio_freq(client, t->radio_freq); - } else { - if (freq) - t->tv_freq = freq; - set_tv_freq(client, t->tv_freq); - } - - return 0; -} /** * tuner_status - Dumps the current tuner status at dmesg @@ -1040,6 +1052,24 @@ static void tuner_status(struct dvb_frontend *fe) analog_ops->has_signal(fe)); } +/* + * Function to splicitly change mode to radio. Probably not needed anymore + */ + +static int tuner_s_radio(struct v4l2_subdev *sd) +{ + struct tuner *t = to_tuner(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL) + return 0; + return 0; +} + +/* + * Tuner callbacks to handle userspace ioctl's + */ + /** * tuner_s_power - controls the power state of the tuner * @sd: pointer to struct v4l2_subdev @@ -1061,24 +1091,6 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) return 0; } -/* - * Function to splicitly change mode to radio. Probably not needed anymore - */ - -static int tuner_s_radio(struct v4l2_subdev *sd) -{ - struct tuner *t = to_tuner(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (set_mode_freq(client, t, V4L2_TUNER_RADIO, 0) == -EINVAL) - return 0; - return 0; -} - -/* - * Tuner callbacks to handle userspace ioctl's - */ - static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct tuner *t = to_tuner(sd); -- cgit v1.2.2 From 550df5a450928172e284cb0f857ae73e5e705305 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 15 Feb 2011 10:31:01 -0200 Subject: [media] tuner-core: Don't touch at standby during tuner_lookup It makes no sense that tuner_lookup would touch at the standby state. Remove it. Thanks-to: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tuner-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index a91a29978f9c..9363ed91a4cb 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -538,7 +538,6 @@ static void tuner_lookup(struct i2c_adapter *adap, continue; mode_mask = pos->mode_mask; - pos->standby = 1; if (*radio == NULL && mode_mask == T_RADIO) *radio = pos; /* Note: currently TDA9887 is the only demod-only -- cgit v1.2.2 From 437f5fa34225db0d981536692678afc590e5c87f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 21 Feb 2011 21:03:59 -0300 Subject: [media] tuner: Remove remaining usages of T_DIGITAL_TV A few places used T_DIGITAL_TV internally. Remove the usage of this obsolete mode mask. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tuner-xc2028.c | 8 ++++---- drivers/staging/tm6000/tm6000-cards.c | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index d95f3b256e30..efcbc3ed0aea 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -933,7 +933,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * that xc2028 will be in a safe state. * Maybe this might also be needed for DTV. */ - if (new_mode == T_ANALOG_TV) { + if (new_mode == V4L2_TUNER_ANALOG_TV) { rc = send_seq(priv, {0x00, 0x00}); /* Analog modes require offset = 0 */ @@ -1054,7 +1054,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, if (priv->ctrl.input1) type |= INPUT1; return generic_set_freq(fe, (625l * p->frequency) / 10, - T_RADIO, type, 0, 0); + V4L2_TUNER_RADIO, type, 0, 0); } /* if std is not defined, choose one */ @@ -1069,7 +1069,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe, p->std |= parse_audio_std_option(); return generic_set_freq(fe, 62500l * p->frequency, - T_ANALOG_TV, type, p->std, 0); + V4L2_TUNER_ANALOG_TV, type, p->std, 0); } static int xc2028_set_params(struct dvb_frontend *fe, @@ -1174,7 +1174,7 @@ static int xc2028_set_params(struct dvb_frontend *fe, } return generic_set_freq(fe, p->frequency, - T_DIGITAL_TV, type, 0, demod); + V4L2_TUNER_DIGITAL_TV, type, 0, demod); } static int xc2028_sleep(struct dvb_frontend *fe) diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 455038bdfc9f..22a222241cc4 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -588,8 +588,6 @@ static void tm6000_config_tuner(struct tm6000_core *dev) tun_setup.mode_mask = 0; if (dev->caps.has_tuner) tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO); - if (dev->caps.has_dvb) - tun_setup.mode_mask |= T_DIGITAL_TV; switch (dev->tuner_type) { case TUNER_XC2028: -- cgit v1.2.2 From 0e09a3c92bfd54a6ac03f8225c4fd10f50111beb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Feb 2011 00:10:22 -0300 Subject: [media] tvp5150: device detection should be done only once Having the device detection happening at reset is bad, as every time, it will produce a message like: tvp5150 2-005c: tvp5150am1 detected. This only polutes the log and for an accidental kernel hacker, it looks like a real problem. So, move those printk's to happen during device probe. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tvp5150.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 959d690363bb..e927d25e0d35 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -737,27 +737,6 @@ static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) static int tvp5150_reset(struct v4l2_subdev *sd, u32 val) { struct tvp5150 *decoder = to_tvp5150(sd); - u8 msb_id, lsb_id, msb_rom, lsb_rom; - - msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID); - lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID); - msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER); - lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER); - - if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */ - v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id); - - /* ITU-T BT.656.4 timing */ - tvp5150_write(sd, TVP5150_REV_SELECT, 0); - } else { - if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */ - v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id); - } else { - v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n", - msb_id, lsb_id); - v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom); - } - } /* Initializes TVP5150 to its default values */ tvp5150_write_inittab(sd, tvp5150_init_default); @@ -977,6 +956,7 @@ static int tvp5150_probe(struct i2c_client *c, { struct tvp5150 *core; struct v4l2_subdev *sd; + u8 msb_id, lsb_id, msb_rom, lsb_rom; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(c->adapter, @@ -992,6 +972,26 @@ static int tvp5150_probe(struct i2c_client *c, v4l_info(c, "chip found @ 0x%02x (%s)\n", c->addr << 1, c->adapter->name); + msb_id = tvp5150_read(sd, TVP5150_MSB_DEV_ID); + lsb_id = tvp5150_read(sd, TVP5150_LSB_DEV_ID); + msb_rom = tvp5150_read(sd, TVP5150_ROM_MAJOR_VER); + lsb_rom = tvp5150_read(sd, TVP5150_ROM_MINOR_VER); + + if (msb_rom == 4 && lsb_rom == 0) { /* Is TVP5150AM1 */ + v4l2_info(sd, "tvp%02x%02xam1 detected.\n", msb_id, lsb_id); + + /* ITU-T BT.656.4 timing */ + tvp5150_write(sd, TVP5150_REV_SELECT, 0); + } else { + if (msb_rom == 3 || lsb_rom == 0x21) { /* Is TVP5150A */ + v4l2_info(sd, "tvp%02x%02xa detected.\n", msb_id, lsb_id); + } else { + v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n", + msb_id, lsb_id); + v4l2_info(sd, "*** Rom ver is %d.%d\n", msb_rom, lsb_rom); + } + } + core->norm = V4L2_STD_ALL; /* Default is autodetect */ core->input = TVP5150_COMPOSITE1; core->enable = 1; -- cgit v1.2.2 From 78e51566f0c56daa58f7bbe2591336b7d478c148 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Feb 2011 00:27:41 -0300 Subject: [media] em28xx: Fix return value for s_ctrl On some cases, driver returns 1. This should be OK, but qv4l2 is too strict about return values. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index f34d524ccb09..1ddd3ee22812 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1452,7 +1452,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, rc = em28xx_audio_analog_set(dev); } } - return rc; + return (rc < 0) ? rc : 0; } static int vidioc_g_tuner(struct file *file, void *priv, -- cgit v1.2.2 From fb8decfabdf841a199b297076ff9f890dee55e53 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Feb 2011 01:00:58 -0300 Subject: [media] em28xx: properly handle subdev controls Subdev controls return codes are evil, as they return -EINVAL to mean both unsupported and invalid arguments. Due to that, we need to use a trick to identify what controls are supported by a subdev. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-video.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 1ddd3ee22812..a83131bd00b2 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -1387,6 +1387,27 @@ static int vidioc_queryctrl(struct file *file, void *priv, return -EINVAL; } +/* + * FIXME: This is an indirect way to check if a control exists at a + * subdev. Instead of that hack, maybe the better would be to change all + * subdevs to return -ENOIOCTLCMD, if an ioctl is not supported. + */ +static int check_subdev_ctrl(struct em28xx *dev, int id) +{ + struct v4l2_queryctrl qc; + + memset(&qc, 0, sizeof(qc)); + qc.id = id; + + /* enumerate V4L2 device controls */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc); + + if (qc.type) + return 0; + else + return -EINVAL; +} + static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { @@ -1399,7 +1420,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv, return rc; rc = 0; - /* Set an AC97 control */ if (dev->audio_mode.ac97 != EM28XX_NO_AC97) rc = ac97_get_ctrl(dev, ctrl); @@ -1408,6 +1428,9 @@ static int vidioc_g_ctrl(struct file *file, void *priv, /* It were not an AC97 control. Sends it to the v4l2 dev interface */ if (rc == 1) { + if (check_subdev_ctrl(dev, ctrl->id)) + return -EINVAL; + v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); rc = 0; } @@ -1434,8 +1457,10 @@ static int vidioc_s_ctrl(struct file *file, void *priv, /* It isn't an AC97 control. Sends it to the v4l2 dev interface */ if (rc == 1) { - rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); - + rc = check_subdev_ctrl(dev, ctrl->id); + if (!rc) + v4l2_device_call_all(&dev->v4l2_dev, 0, + core, s_ctrl, ctrl); /* * In the case of non-AC97 volume controls, we still need * to do some setups at em28xx, in order to mute/unmute -- cgit v1.2.2 From 87a0c94ce616b231f3c0bd09d7dbd39d43b0557a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 22 Feb 2011 12:31:07 -0300 Subject: [media] v4l2-ctrls: Fix control enumeration for multiple subdevs with ctrl v4l2-ctl and qv4l2 enumerate controls using V4L2_CTRL_FLAG_NEXT_CTRL, falling back to the old method if the flag isn't supported. The v4l2_subdev_queryctrl function will currently handle that flag, but for the controls of the subdev only. This isn't right, it should refuse this flag, otherwise v4l2-ctl will only see the controls of the first subdev. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ctrls.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index ef66d2af0c57..2412f08527aa 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -1364,6 +1364,8 @@ EXPORT_SYMBOL(v4l2_queryctrl); int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) { + if (qc->id & V4L2_CTRL_FLAG_NEXT_CTRL) + return -EINVAL; return v4l2_queryctrl(sd->ctrl_handler, qc); } EXPORT_SYMBOL(v4l2_subdev_queryctrl); -- cgit v1.2.2 From 0f77f40c300c18c15e7aeb2f9eee510aa96d58fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 07:01:30 -0300 Subject: [media] gspca - sonixj: Move the avg lum computation to a separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 44 ++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index d6f39ce1b7e1..c4147072b73e 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2757,6 +2757,29 @@ static void do_autogain(struct gspca_dev *gspca_dev) } } +/* set the average luminosity from an isoc marker */ +static void set_lum(struct sd *sd, + u8 *data) +{ + int avg_lum; + + /* w0 w1 w2 + * w3 w4 w5 + * w6 w7 w8 + */ + avg_lum = (data[27] << 8) + data[28] /* w3 */ + + + (data[31] << 8) + data[32] /* w5 */ + + + (data[23] << 8) + data[24] /* w1 */ + + + (data[35] << 8) + data[36] /* w7 */ + + + (data[29] << 10) + (data[30] << 2); /* w4 * 4 */ + avg_lum >>= 10; + atomic_set(&sd->avg_lum, avg_lum); +} + /* scan the URB packets */ /* This function is run at interrupt level. */ static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -2764,7 +2787,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - int sof, avg_lum; + int sof; /* the image ends on a 64 bytes block starting with * ff d9 ff ff 00 c4 c4 96 @@ -2795,23 +2818,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* end of image found - remove the trailing data */ gspca_dev->image_len = sof + 2; gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - if (sd->ag_cnt < 0) - return; -/* w1 w2 w3 */ -/* w4 w5 w6 */ -/* w7 w8 */ -/* w4 */ - avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6; -/* w6 */ - avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6; -/* w2 */ - avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6; -/* w8 */ - avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6; -/* w5 */ - avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4; - avg_lum >>= 4; - atomic_set(&sd->avg_lum, avg_lum); + if (sd->ag_cnt >= 0) + set_lum(sd, data + sof + 2); } static int sd_set_jcomp(struct gspca_dev *gspca_dev, -- cgit v1.2.2 From a4a3076ffcdbcf40358edc2068aa4d9103fe0a28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 07:15:24 -0300 Subject: [media] gspca - sonixj: Better scanning of isochronous packets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A marker 'ff ff 00 c4 c4 96' indicates an end of frame. It is 62 bytes long and may be splitted on 2 packets. It contains a flag 'USB full' which indicates that the frame is truncated. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 119 +++++++++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index c4147072b73e..21f0330885dd 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -57,6 +57,8 @@ struct sd { atomic_t avg_lum; u32 exposure; + s8 short_mark; + u8 quality; /* image quality */ #define QUALITY_MIN 60 #define QUALITY_MAX 95 @@ -2787,39 +2789,104 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - int sof; - - /* the image ends on a 64 bytes block starting with - * ff d9 ff ff 00 c4 c4 96 - * and followed by various information including luminosity */ - /* this block may be splitted between two packets */ - /* a new image always starts in a new packet */ - switch (gspca_dev->last_packet_type) { - case DISCARD_PACKET: /* restart image building */ - sof = len - 64; - if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); - return; - case LAST_PACKET: /* put the JPEG 422 header */ + int i; + + /* + * A frame ends on the marker + * ff ff 00 c4 c4 96 .. + * which is 62 bytes long and is followed by various information + * including statuses and luminosity. + * + * A marker may be splitted on two packets. + * + * The 6th byte of a marker contains the bits: + * 0x08: USB full + * 0xc0: frame sequence + * When the bit 'USB full' is set, the frame must be discarded; + * this is also the case when the 2 bytes before the marker are + * not the JPEG end of frame ('ff d9'). + */ + +/*fixme: assumption about the following code: + * - there can be only one marker in a packet + */ + + /* skip the remaining bytes of a short marker */ + i = sd->short_mark; + if (i != 0) { + sd->short_mark = 0; + if (i < 0 /* if 'ff' at end of previous packet */ + && data[0] == 0xff + && data[1] == 0x00) + goto marker_found; + if (data[0] == 0xff && data[1] == 0xff) { + i = 0; + goto marker_found; + } + len -= i; + if (len <= 0) + return; + data += i; + } + + /* search backwards if there is a marker in the packet */ + for (i = len - 1; --i >= 0; ) { + if (data[i] != 0xff) { + i--; + continue; + } + if (data[i + 1] == 0xff) { + + /* (there may be 'ff ff' inside a marker) */ + if (i + 2 >= len || data[i + 2] == 0x00) + goto marker_found; + } + } + + /* no marker found */ + /* add the JPEG header if first fragment */ + if (data[len - 1] == 0xff) + sd->short_mark = -1; + if (gspca_dev->last_packet_type == LAST_PACKET) gspca_frame_add(gspca_dev, FIRST_PACKET, sd->jpeg_hdr, JPEG_HDR_SZ); - break; - } gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + return; + + /* marker found */ + /* if some error, discard the frame */ +marker_found: + if (i > 2) { + if (data[i - 2] != 0xff || data[i - 1] != 0xd9) { + gspca_dev->last_packet_type = DISCARD_PACKET; + } + } else if (i + 6 < len) { + if (data[i + 6] & 0x08) { + gspca_dev->last_packet_type = DISCARD_PACKET; + } + } - data = gspca_dev->image; - if (data == NULL) - return; - sof = gspca_dev->image_len - 64; - if (data[sof] != 0xff - || data[sof + 1] != 0xd9) + gspca_frame_add(gspca_dev, LAST_PACKET, data, i); + + /* if the marker is smaller than 62 bytes, + * memorize the number of bytes to skip in the next packet */ + if (i + 62 > len) { /* no more usable data */ + sd->short_mark = i + 62 - len; return; + } - /* end of image found - remove the trailing data */ - gspca_dev->image_len = sof + 2; - gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); if (sd->ag_cnt >= 0) - set_lum(sd, data + sof + 2); + set_lum(sd, data + i); + + /* if more data, start a new frame */ + i += 62; + if (i < len) { + data += i; + len -= i; + gspca_frame_add(gspca_dev, FIRST_PACKET, + sd->jpeg_hdr, JPEG_HDR_SZ); + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } } static int sd_set_jcomp(struct gspca_dev *gspca_dev, -- cgit v1.2.2 From dccdcccdd36bf7570967ff53411c7401b8e645d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 07:30:03 -0300 Subject: [media] gspca - sonixj: Have the same JPEG quality for encoding and decoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 21f0330885dd..d465022b8022 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -63,7 +63,6 @@ struct sd { #define QUALITY_MIN 60 #define QUALITY_MAX 95 #define QUALITY_DEF 80 - u8 jpegqual; /* webcam quality */ u8 reg01; u8 reg17; @@ -1786,7 +1785,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->ag_cnt = -1; sd->quality = QUALITY_DEF; - sd->jpegqual = 80; return 0; } @@ -2273,18 +2271,12 @@ static void setfreq(struct gspca_dev *gspca_dev) static void setjpegqual(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int i, sc; - if (sd->jpegqual < 50) - sc = 5000 / sd->jpegqual; - else - sc = 200 - sd->jpegqual * 2; + jpeg_set_qual(sd->jpeg_hdr, sd->quality); #if USB_BUF_SZ < 64 #error "No room enough in usb_buf for quantization table" #endif - for (i = 0; i < 64; i++) - gspca_dev->usb_buf[i] = - (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100; + memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0x08, @@ -2292,9 +2284,7 @@ static void setjpegqual(struct gspca_dev *gspca_dev) 0x0100, 0, gspca_dev->usb_buf, 64, 500); - for (i = 0; i < 64; i++) - gspca_dev->usb_buf[i] = - (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100; + memcpy(gspca_dev->usb_buf, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64); usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0x08, @@ -2340,7 +2330,6 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); /* initialize the bridge */ sn9c1xx = sn_tb[sd->sensor]; @@ -2901,7 +2890,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, else sd->quality = jcomp->quality; if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + setjpegqual(gspca_dev); return 0; } -- cgit v1.2.2 From b96cfc33e74f5ee5a206b2d43bf0bc3898c5a572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 07:38:58 -0300 Subject: [media] gspca - sonixj: Update the JPEG quality for best image transfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During image capture, the filling rate of the isoc packets is computed. It is then used by a work queue to update the current JPEG quality. Tested-by: Franck Bourdonnec Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 109 +++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index d465022b8022..2bfb8df9168b 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -57,12 +57,18 @@ struct sd { atomic_t avg_lum; u32 exposure; + struct work_struct work; + struct workqueue_struct *work_thread; + + u32 pktsz; /* (used by pkt_scan) */ + u16 npkt; + u8 nchg; s8 short_mark; u8 quality; /* image quality */ -#define QUALITY_MIN 60 -#define QUALITY_MAX 95 -#define QUALITY_DEF 80 +#define QUALITY_MIN 25 +#define QUALITY_MAX 90 +#define QUALITY_DEF 70 u8 reg01; u8 reg17; @@ -100,6 +106,8 @@ enum sensors { SENSOR_SP80708, }; +static void qual_upd(struct work_struct *work); + /* device flags */ #define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */ #define F_ILLUM 0x02 /* presence of illuminator */ @@ -1786,6 +1794,8 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->ag_cnt = -1; sd->quality = QUALITY_DEF; + INIT_WORK(&sd->work, qual_upd); + return 0; } @@ -2297,6 +2307,19 @@ static void setjpegqual(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x18, sd->reg18); } +/* JPEG quality update */ +/* This function is executed from a work queue. */ +static void qual_upd(struct work_struct *work) +{ + struct sd *sd = container_of(work, struct sd, work); + struct gspca_dev *gspca_dev = &sd->gspca_dev; + + mutex_lock(&gspca_dev->usb_lock); + PDEBUG(D_STREAM, "qual_upd %d%%", sd->quality); + setjpegqual(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); +} + /* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { @@ -2610,6 +2633,11 @@ static int sd_start(struct gspca_dev *gspca_dev) setcolors(gspca_dev); setautogain(gspca_dev); setfreq(gspca_dev); + + sd->pktsz = sd->npkt = 0; + sd->nchg = sd->short_mark = 0; + sd->work_thread = create_singlethread_workqueue(MODULE_NAME); + return gspca_dev->usb_err; } @@ -2686,6 +2714,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* reg_w1(gspca_dev, 0xf1, 0x01); */ } +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->work_thread != NULL) { + mutex_unlock(&gspca_dev->usb_lock); + destroy_workqueue(sd->work_thread); + mutex_lock(&gspca_dev->usb_lock); + sd->work_thread = NULL; + } +} + static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -2778,7 +2820,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - int i; + int i, new_qual; /* * A frame ends on the marker @@ -2818,6 +2860,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data += i; } + /* count the packets and their size */ + sd->npkt++; + sd->pktsz += len; + /* search backwards if there is a marker in the packet */ for (i = len - 1; --i >= 0; ) { if (data[i] != 0xff) { @@ -2843,27 +2889,60 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, return; /* marker found */ - /* if some error, discard the frame */ + /* if some error, discard the frame and decrease the quality */ marker_found: + new_qual = 0; if (i > 2) { if (data[i - 2] != 0xff || data[i - 1] != 0xd9) { gspca_dev->last_packet_type = DISCARD_PACKET; + new_qual = -3; } } else if (i + 6 < len) { if (data[i + 6] & 0x08) { gspca_dev->last_packet_type = DISCARD_PACKET; + new_qual = -5; } } gspca_frame_add(gspca_dev, LAST_PACKET, data, i); + /* compute the filling rate and a new JPEG quality */ + if (new_qual == 0) { + int r; + + r = (sd->pktsz * 100) / + (sd->npkt * + gspca_dev->urb[0]->iso_frame_desc[0].length); + if (r >= 85) + new_qual = -3; + else if (r < 75) + new_qual = 2; + } + if (new_qual != 0) { + sd->nchg += new_qual; + if (sd->nchg < -6 || sd->nchg >= 12) { + sd->nchg = 0; + new_qual += sd->quality; + if (new_qual < QUALITY_MIN) + new_qual = QUALITY_MIN; + else if (new_qual > QUALITY_MAX) + new_qual = QUALITY_MAX; + if (new_qual != sd->quality) { + sd->quality = new_qual; + queue_work(sd->work_thread, &sd->work); + } + } + } else { + sd->nchg = 0; + } + sd->pktsz = sd->npkt = 0; + /* if the marker is smaller than 62 bytes, * memorize the number of bytes to skip in the next packet */ if (i + 62 > len) { /* no more usable data */ sd->short_mark = i + 62 - len; return; } - if (sd->ag_cnt >= 0) set_lum(sd, data + i); @@ -2878,22 +2957,6 @@ marker_found: } } -static int sd_set_jcomp(struct gspca_dev *gspca_dev, - struct v4l2_jpegcompression *jcomp) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - setjpegqual(gspca_dev); - return 0; -} - static int sd_get_jcomp(struct gspca_dev *gspca_dev, struct v4l2_jpegcompression *jcomp) { @@ -2955,10 +3018,10 @@ static const struct sd_desc sd_desc = { .init = sd_init, .start = sd_start, .stopN = sd_stopN, + .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, .get_jcomp = sd_get_jcomp, - .set_jcomp = sd_set_jcomp, .querymenu = sd_querymenu, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) .int_pkt_scan = sd_int_pkt_scan, -- cgit v1.2.2 From 804632201f2d749b7cb35fce42fc28552ad595c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 07:44:59 -0300 Subject: [media] gspca - sonixj: Fix start sequence of sensor mt9v111 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 2bfb8df9168b..01ee39be2c75 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -856,18 +856,8 @@ static const u8 mt9v111_sensor_init[][8] = { {0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */ {0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */ {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, /* op mode ctrl */ - {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x03, 0x01, 0xe1, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x04, 0x02, 0x81, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10}, {0xb1, 0x5c, 0x01, 0x00, 0x04, 0x00, 0x00, 0x10}, /* sensor select */ - {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x03, 0x01, 0xe6, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x04, 0x02, 0x86, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x05, 0x00, 0x04, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xb1, 0x5c, 0x08, 0x00, 0x08, 0x00, 0x00, 0x10}, /* row start */ - {0xb1, 0x5c, 0x0e, 0x00, 0x08, 0x00, 0x00, 0x10}, {0xb1, 0x5c, 0x02, 0x00, 0x16, 0x00, 0x00, 0x10}, /* col start */ {0xb1, 0x5c, 0x03, 0x01, 0xe7, 0x00, 0x00, 0x10}, /* window height */ {0xb1, 0x5c, 0x04, 0x02, 0x87, 0x00, 0x00, 0x10}, /* window width */ @@ -881,15 +871,10 @@ static const u8 mt9v111_sensor_init[][8] = { {} }; static const u8 mt9v111_sensor_param1[][8] = { - {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x5c, 0x09, 0x01, 0x2c, 0x00, 0x00, 0x10}, - {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10}, /* green1 gain */ - {0xd1, 0x5c, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10}, /* red gain */ - /*******/ - {0xb1, 0x5c, 0x06, 0x00, 0x1e, 0x00, 0x00, 0x10}, /* vert blanking */ - {0xb1, 0x5c, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x10}, /* horiz blanking */ - {0xd1, 0x5c, 0x2c, 0x00, 0xad, 0x00, 0xad, 0x10}, /* blue gain */ + {0xd1, 0x5c, 0x2b, 0x00, 0x33, 0x00, 0xad, 0x10}, /* G1 and B gains */ + {0xd1, 0x5c, 0x2d, 0x00, 0xad, 0x00, 0x33, 0x10}, /* R and G2 gains */ + {0xb1, 0x5c, 0x06, 0x00, 0x40, 0x00, 0x00, 0x10}, /* vert blanking */ + {0xb1, 0x5c, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10}, /* horiz blanking */ {0xb1, 0x5c, 0x35, 0x01, 0xc0, 0x00, 0x00, 0x10}, /* global gain */ {} }; -- cgit v1.2.2 From 222036765ccbdb1ff4feef22d8e2fc687a9cdcfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 07:49:32 -0300 Subject: [media] gspca - sonixj: Adjust autogain for sensor mt9v111 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gain/expo adjustment was too long. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 01ee39be2c75..b7a7e96d3bd8 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1939,10 +1939,10 @@ static u32 setexposure(struct gspca_dev *gspca_dev, u8 expo_c1[] = { 0xb1, 0x5c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x10 }; - if (expo > 0x0280) - expo = 0x0280; - else if (expo < 0x0040) - expo = 0x0040; + if (expo > 0x0390) + expo = 0x0390; + else if (expo < 0x0060) + expo = 0x0060; expo_c1[3] = expo >> 8; expo_c1[4] = expo; i2c_w8(gspca_dev, expo_c1); @@ -1999,10 +1999,13 @@ static void setbrightness(struct gspca_dev *gspca_dev) sd->exposure = setexposure(gspca_dev, expo); break; case SENSOR_GC0307: - case SENSOR_MT9V111: expo = brightness; sd->exposure = setexposure(gspca_dev, expo); return; /* don't set the Y offset */ + case SENSOR_MT9V111: + expo = brightness << 2; + sd->exposure = setexposure(gspca_dev, expo); + return; /* don't set the Y offset */ case SENSOR_OM6802: expo = brightness << 2; sd->exposure = setexposure(gspca_dev, expo); @@ -2750,6 +2753,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) (unsigned int) (expotimes << 8)); break; case SENSOR_OM6802: + case SENSOR_MT9V111: expotimes = sd->exposure; expotimes += (luma_mean - delta) >> 2; if (expotimes < 0) @@ -2762,7 +2766,6 @@ static void do_autogain(struct gspca_dev *gspca_dev) /* case SENSOR_MO4000: */ /* case SENSOR_MI0360: */ /* case SENSOR_MI0360B: */ -/* case SENSOR_MT9V111: */ expotimes = sd->exposure; expotimes += (luma_mean - delta) >> 6; if (expotimes < 0) -- cgit v1.2.2 From e6a92a7445cc33bbfe2775eb50473fb43bb3a2da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 07:52:58 -0300 Subject: [media] gspca - sonixj: Simplify GPIO setting when audio present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index b7a7e96d3bd8..bfc09b97b061 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1789,7 +1789,7 @@ static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; const u8 *sn9c1xx; - u8 regGpio[] = { 0x29, 0x74 }; /* with audio */ + u8 regGpio[] = { 0x29, 0x70 }; /* no audio */ u8 regF1; /* setup a selector by bridge */ @@ -1801,6 +1801,8 @@ static int sd_init(struct gspca_dev *gspca_dev) if (gspca_dev->usb_err < 0) return gspca_dev->usb_err; PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1); + if (gspca_dev->audio) + regGpio[1] |= 0x04; /* with audio */ switch (sd->bridge) { case BRIDGE_SN9C102P: case BRIDGE_SN9C105: @@ -1840,7 +1842,6 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x02, 0x62); break; case BRIDGE_SN9C120: - regGpio[1] = 0x70; /* no audio */ reg_w(gspca_dev, 0x01, regGpio, 2); break; } -- cgit v1.2.2 From 336d23ef88fd71564fb07fdc1d1d871f8e1eeadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 08:00:40 -0300 Subject: [media] gspca - sonixj: Same init for all bridges but the sn9c102p MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index bfc09b97b061..571d086eabe5 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1835,13 +1835,7 @@ static int sd_init(struct gspca_dev *gspca_dev) case BRIDGE_SN9C102P: reg_w1(gspca_dev, 0x02, regGpio[1]); break; - case BRIDGE_SN9C105: - reg_w(gspca_dev, 0x01, regGpio, 2); - break; - case BRIDGE_SN9C110: - reg_w1(gspca_dev, 0x02, 0x62); - break; - case BRIDGE_SN9C120: + default: reg_w(gspca_dev, 0x01, regGpio, 2); break; } -- cgit v1.2.2 From 5c95606b1d94a6dc62df0af2bc0d3e0e9a2e6cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 08:03:24 -0300 Subject: [media] gspca - sonixj: Set both pins for infrared of mt9v111 webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids to define the webcam model. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 571d086eabe5..eb7b2613ab45 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -29,8 +29,6 @@ MODULE_AUTHOR("Jean-François Moine "); MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); MODULE_LICENSE("GPL"); -static int starcam; - /* controls */ enum e_ctrl { BRIGHTNESS, @@ -2192,14 +2190,11 @@ static void setillum(struct gspca_dev *gspca_dev) sd->ctrls[ILLUM].val ? 0x64 : 0x60); break; case SENSOR_MT9V111: - if (starcam) - reg_w1(gspca_dev, 0x02, - sd->ctrls[ILLUM].val ? - 0x55 : 0x54); /* 370i */ - else - reg_w1(gspca_dev, 0x02, - sd->ctrls[ILLUM].val ? - 0x66 : 0x64); /* Clip */ + reg_w1(gspca_dev, 0x02, + sd->ctrls[ILLUM].val ? 0x77 : 0x74); +/* should have been: */ +/* 0x55 : 0x54); * 370i */ +/* 0x66 : 0x64); * Clip */ break; } } @@ -3114,7 +3109,3 @@ static void __exit sd_mod_exit(void) module_init(sd_mod_init); module_exit(sd_mod_exit); - -module_param(starcam, int, 0644); -MODULE_PARM_DESC(starcam, - "StarCam model. 0: Clip, 1: 370i"); -- cgit v1.2.2 From 062909f64981678899a1abbe16a616b0e92fc615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 08:10:50 -0300 Subject: [media] gspca - sonixj, zc3xx: Let some bandwidth for audio when USB 1.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 4 ++++ drivers/media/video/gspca/zc3xx.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index eb7b2613ab45..a1f82a92833d 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -1777,6 +1777,10 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->ag_cnt = -1; sd->quality = QUALITY_DEF; + /* if USB 1.1, let some bandwidth for the audio device */ + if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) + gspca_dev->nbalt--; + INIT_WORK(&sd->work, qual_upd); return 0; diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 47236a58bf33..b2014915f9c1 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -6414,6 +6414,10 @@ static int sd_config(struct gspca_dev *gspca_dev, gspca_dev->cam.ctrls = sd->ctrls; sd->quality = QUALITY_DEF; + /* if USB 1.1, let some bandwidth for the audio device */ + if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH) + gspca_dev->nbalt--; + return 0; } -- cgit v1.2.2 From 228dd2660c4cee10fda47aa105b0152f8de7a766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 09:34:57 -0300 Subject: [media] gspca - ov534: Use the new control mechanism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov534.c | 455 ++++++++++---------------------------- 1 file changed, 113 insertions(+), 342 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 04da22802736..ee6c1df76022 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -49,54 +49,51 @@ MODULE_AUTHOR("Antonio Ospite "); MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); MODULE_LICENSE("GPL"); +/* controls */ +enum e_ctrl { + BRIGHTNESS, + CONTRAST, + GAIN, + EXPOSURE, + AGC, + AWB, + AEC, + SHARPNESS, + HFLIP, + VFLIP, + LIGHTFREQ, + NCTRLS /* number of controls */ +}; + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + __u32 last_pts; u16 last_fid; u8 frame_rate; - u8 brightness; - u8 contrast; - u8 gain; - u8 exposure; - u8 agc; - u8 awb; - u8 aec; - s8 sharpness; - u8 hflip; - u8 vflip; - u8 freqfltr; }; /* V4L2 controls supported by the driver */ -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static void setbrightness(struct gspca_dev *gspca_dev); +static void setcontrast(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getagc(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setaec(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getaec(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreqfltr(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreqfltr(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu); +static void setawb(struct gspca_dev *gspca_dev); +static void setaec(struct gspca_dev *gspca_dev); +static void setsharpness(struct gspca_dev *gspca_dev); +static void sethvflip(struct gspca_dev *gspca_dev); +static void setlightfreq(struct gspca_dev *gspca_dev); + +static int sd_start(struct gspca_dev *gspca_dev); +static void sd_stopN(struct gspca_dev *gspca_dev); static const struct ctrl sd_ctrls[] = { - { /* 0 */ +[BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -104,13 +101,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 255, .step = 1, -#define BRIGHTNESS_DEF 0 - .default_value = BRIGHTNESS_DEF, + .default_value = 0, }, - .set = sd_setbrightness, - .get = sd_getbrightness, + .set_control = setbrightness }, - { /* 1 */ +[CONTRAST] = { { .id = V4L2_CID_CONTRAST, .type = V4L2_CTRL_TYPE_INTEGER, @@ -118,13 +113,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 255, .step = 1, -#define CONTRAST_DEF 32 - .default_value = CONTRAST_DEF, + .default_value = 32, }, - .set = sd_setcontrast, - .get = sd_getcontrast, + .set_control = setcontrast }, - { /* 2 */ +[GAIN] = { { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, @@ -132,13 +125,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 63, .step = 1, -#define GAIN_DEF 20 - .default_value = GAIN_DEF, + .default_value = 20, }, - .set = sd_setgain, - .get = sd_getgain, + .set_control = setgain }, - { /* 3 */ +[EXPOSURE] = { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, @@ -146,13 +137,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 255, .step = 1, -#define EXPO_DEF 120 - .default_value = EXPO_DEF, + .default_value = 120, }, - .set = sd_setexposure, - .get = sd_getexposure, + .set_control = setexposure }, - { /* 4 */ +[AGC] = { { .id = V4L2_CID_AUTOGAIN, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -160,14 +149,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define AGC_DEF 1 - .default_value = AGC_DEF, + .default_value = 1, }, - .set = sd_setagc, - .get = sd_getagc, + .set = sd_setagc }, -#define AWB_IDX 5 - { /* 5 */ +[AWB] = { { .id = V4L2_CID_AUTO_WHITE_BALANCE, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -175,13 +161,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define AWB_DEF 1 - .default_value = AWB_DEF, + .default_value = 1, }, - .set = sd_setawb, - .get = sd_getawb, + .set_control = setawb }, - { /* 6 */ +[AEC] = { { .id = V4L2_CID_EXPOSURE_AUTO, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -189,13 +173,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define AEC_DEF 1 - .default_value = AEC_DEF, + .default_value = 1, }, - .set = sd_setaec, - .get = sd_getaec, + .set_control = setaec }, - { /* 7 */ +[SHARPNESS] = { { .id = V4L2_CID_SHARPNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -203,13 +185,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 63, .step = 1, -#define SHARPNESS_DEF 0 - .default_value = SHARPNESS_DEF, + .default_value = 0, }, - .set = sd_setsharpness, - .get = sd_getsharpness, + .set_control = setsharpness }, - { /* 8 */ +[HFLIP] = { { .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -217,13 +197,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define HFLIP_DEF 0 - .default_value = HFLIP_DEF, + .default_value = 0, }, - .set = sd_sethflip, - .get = sd_gethflip, + .set_control = sethvflip }, - { /* 9 */ +[VFLIP] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -231,13 +209,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define VFLIP_DEF 0 - .default_value = VFLIP_DEF, + .default_value = 0, }, - .set = sd_setvflip, - .get = sd_getvflip, + .set_control = sethvflip }, - { /* 10 */ +[LIGHTFREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, .type = V4L2_CTRL_TYPE_MENU, @@ -245,11 +221,9 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, -#define FREQFLTR_DEF 0 - .default_value = FREQFLTR_DEF, + .default_value = 0, }, - .set = sd_setfreqfltr, - .get = sd_getfreqfltr, + .set_control = setlightfreq }, }; @@ -670,14 +644,14 @@ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - sccb_reg_write(gspca_dev, 0x9b, sd->brightness); + sccb_reg_write(gspca_dev, 0x9b, sd->ctrls[BRIGHTNESS].val); } static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - sccb_reg_write(gspca_dev, 0x9c, sd->contrast); + sccb_reg_write(gspca_dev, 0x9c, sd->ctrls[CONTRAST].val); } static void setgain(struct gspca_dev *gspca_dev) @@ -685,10 +659,10 @@ static void setgain(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; - if (sd->agc) + if (sd->ctrls[AGC].val) return; - val = sd->gain; + val = sd->ctrls[GAIN].val; switch (val & 0x30) { case 0x00: val &= 0x0f; @@ -715,7 +689,7 @@ static void setexposure(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; - if (sd->aec) + if (sd->ctrls[AEC].val) return; /* 'val' is one byte and represents half of the exposure value we are @@ -724,7 +698,7 @@ static void setexposure(struct gspca_dev *gspca_dev) * MSB: ((u16) val << 1) >> 8 == val >> 7 * LSB: ((u16) val << 1) & 0xff == val << 1 */ - val = sd->exposure; + val = sd->ctrls[EXPOSURE].val; sccb_reg_write(gspca_dev, 0x08, val >> 7); sccb_reg_write(gspca_dev, 0x10, val << 1); } @@ -733,7 +707,7 @@ static void setagc(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->agc) { + if (sd->ctrls[AGC].val) { sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) | 0x04); sccb_reg_write(gspca_dev, 0x64, @@ -752,7 +726,7 @@ static void setawb(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->awb) { + if (sd->ctrls[AWB].val) { sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) | 0x02); sccb_reg_write(gspca_dev, 0x63, @@ -769,7 +743,7 @@ static void setaec(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->aec) + if (sd->ctrls[AEC].val) sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) | 0x01); else { @@ -784,40 +758,30 @@ static void setsharpness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; - val = sd->sharpness; + val = sd->ctrls[SHARPNESS].val; sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */ sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */ } -static void sethflip(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->hflip == 0) - sccb_reg_write(gspca_dev, 0x0c, - sccb_reg_read(gspca_dev, 0x0c) | 0x40); - else - sccb_reg_write(gspca_dev, 0x0c, - sccb_reg_read(gspca_dev, 0x0c) & ~0x40); -} - -static void setvflip(struct gspca_dev *gspca_dev) +static void sethvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + u8 val; - if (sd->vflip == 0) - sccb_reg_write(gspca_dev, 0x0c, - sccb_reg_read(gspca_dev, 0x0c) | 0x80); - else - sccb_reg_write(gspca_dev, 0x0c, - sccb_reg_read(gspca_dev, 0x0c) & ~0x80); + val = sccb_reg_read(gspca_dev, 0x0c); + val &= ~0xc0; + if (sd->ctrls[HFLIP].val == 0) + val |= 0x40; + if (sd->ctrls[VFLIP].val == 0) + val |= 0x80; + sccb_reg_write(gspca_dev, 0x0c, val); } -static void setfreqfltr(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (sd->freqfltr == 0) + if (sd->ctrls[LIGHTFREQ].val == 0) sccb_reg_write(gspca_dev, 0x2b, 0x00); else sccb_reg_write(gspca_dev, 0x2b, 0x9e); @@ -833,6 +797,12 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; + cam->ctrls = sd->ctrls; + + /* the auto white balance control works only when auto gain is set */ + if (sd_ctrls[AGC].qctrl.default_value == 0) + gspca_dev->ctrl_inac |= (1 << AWB); + cam->cam_mode = ov772x_mode; cam->nmodes = ARRAY_SIZE(ov772x_mode); cam->mode_framerates = ov772x_framerates; @@ -843,22 +813,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->frame_rate = 30; - sd->brightness = BRIGHTNESS_DEF; - sd->contrast = CONTRAST_DEF; - sd->gain = GAIN_DEF; - sd->exposure = EXPO_DEF; -#if AGC_DEF != 0 - sd->agc = AGC_DEF; -#else - gspca_dev->ctrl_inac |= (1 << AWB_IDX); -#endif - sd->awb = AWB_DEF; - sd->aec = AEC_DEF; - sd->sharpness = SHARPNESS_DEF; - sd->hflip = HFLIP_DEF; - sd->vflip = VFLIP_DEF; - sd->freqfltr = FREQFLTR_DEF; - return 0; } @@ -917,17 +871,19 @@ static int sd_start(struct gspca_dev *gspca_dev) } set_frame_rate(gspca_dev); - setagc(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << AGC))) + setagc(gspca_dev); setawb(gspca_dev); setaec(gspca_dev); - setgain(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << GAIN))) + setgain(gspca_dev); setexposure(gspca_dev); setbrightness(gspca_dev); setcontrast(gspca_dev); - setsharpness(gspca_dev); - setvflip(gspca_dev); - sethflip(gspca_dev); - setfreqfltr(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS))) + setsharpness(gspca_dev); + sethvflip(gspca_dev); + setlightfreq(gspca_dev); ov534_set_led(gspca_dev, 1); ov534_reg_write(gspca_dev, 0xe0, 0x00); @@ -1026,212 +982,27 @@ scan_next: } while (remaining_len > 0); } -/* controls */ -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - static int sd_setagc(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - sd->agc = val; + sd->ctrls[AGC].val = val; - if (gspca_dev->streaming) { - - /* the auto white balance control works only - * when auto gain is set */ - if (val) - gspca_dev->ctrl_inac &= ~(1 << AWB_IDX); - else - gspca_dev->ctrl_inac |= (1 << AWB_IDX); - setagc(gspca_dev); + /* the auto white balance control works only + * when auto gain is set */ + if (val) { + gspca_dev->ctrl_inac &= ~(1 << AWB); + } else { + gspca_dev->ctrl_inac |= (1 << AWB); + if (sd->ctrls[AWB].val) { + sd->ctrls[AWB].val = 0; + if (gspca_dev->streaming) + setawb(gspca_dev); + } } - return 0; -} - -static int sd_getagc(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->agc; - return 0; -} - -static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->awb = val; - if (gspca_dev->streaming) - setawb(gspca_dev); - return 0; -} - -static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->awb; - return 0; -} - -static int sd_setaec(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->aec = val; - if (gspca_dev->streaming) - setaec(gspca_dev); - return 0; -} - -static int sd_getaec(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->aec; - return 0; -} - -static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->sharpness = val; - if (gspca_dev->streaming) - setsharpness(gspca_dev); - return 0; -} - -static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->sharpness; - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) - sethflip(gspca_dev); - return 0; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - return 0; -} - -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vflip = val; - if (gspca_dev->streaming) - setvflip(gspca_dev); - return 0; -} - -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->vflip; - return 0; -} - -static int sd_setfreqfltr(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->freqfltr = val; if (gspca_dev->streaming) - setfreqfltr(gspca_dev); - return 0; -} - -static int sd_getfreqfltr(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freqfltr; - return 0; + setagc(gspca_dev); + return gspca_dev->usb_err; } static int sd_querymenu(struct gspca_dev *gspca_dev, -- cgit v1.2.2 From 458efe2d558b51fff38026e8ede9374899340e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 10:11:04 -0300 Subject: [media] gspca - ov534: Add the webcam 06f8:3002 and sensor ov767x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov534.c | 518 +++++++++++++++++++++++++++++++++----- 1 file changed, 458 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index ee6c1df76022..8dada2b745bc 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -1,5 +1,5 @@ /* - * ov534-ov772x gspca driver + * ov534-ov7xxx gspca driver * * Copyright (C) 2008 Antonio Ospite * Copyright (C) 2008 Jim Paris @@ -75,6 +75,12 @@ struct sd { u16 last_fid; u8 frame_rate; + u8 sensor; +}; +enum sensors { + SENSOR_OV767x, + SENSOR_OV772x, + NSENSORS }; /* V4L2 controls supported by the driver */ @@ -239,6 +245,16 @@ static const struct v4l2_pix_format ov772x_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; +static const struct v4l2_pix_format ov767x_mode[] = { + {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, + {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8 + 590, + .colorspace = V4L2_COLORSPACE_JPEG}, +}; static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30}; static const u8 vga_rates[] = {60, 50, 40, 30, 15}; @@ -254,7 +270,288 @@ static const struct framerates ov772x_framerates[] = { }, }; -static const u8 bridge_init[][2] = { +struct reg_array { + const u8 (*val)[2]; + int len; +}; + +static const u8 bridge_init_767x[][2] = { +/* comments from the ms-win file apollo7670.set */ +/* str1 */ + {0xf1, 0x42}, + {0x88, 0xf8}, + {0x89, 0xff}, + {0x76, 0x03}, + {0x92, 0x03}, + {0x95, 0x10}, + {0xe2, 0x00}, + {0xe7, 0x3e}, + {0x8d, 0x1c}, + {0x8e, 0x00}, + {0x8f, 0x00}, + {0x1f, 0x00}, + {0xc3, 0xf9}, + {0x89, 0xff}, + {0x88, 0xf8}, + {0x76, 0x03}, + {0x92, 0x01}, + {0x93, 0x18}, + {0x1c, 0x00}, + {0x1d, 0x48}, + {0x1d, 0x00}, + {0x1d, 0xff}, + {0x1d, 0x02}, + {0x1d, 0x58}, + {0x1d, 0x00}, + {0x1c, 0x0a}, + {0x1d, 0x0a}, + {0x1d, 0x0e}, + {0xc0, 0x50}, /* HSize 640 */ + {0xc1, 0x3c}, /* VSize 480 */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xc2, 0x0c}, /* Input YUV */ + {0xc3, 0xf9}, /* enable PRE */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xe7, 0x2e}, /* this solves failure of "SuspendResumeTest" */ + {0x31, 0xf9}, /* enable 1.8V Suspend */ + {0x35, 0x02}, /* turn on JPEG */ + {0xd9, 0x10}, + {0x25, 0x42}, /* GPIO[8]:Input */ + {0x94, 0x11}, /* If the default setting is loaded when + * system boots up, this flag is closed here */ +}; +static const u8 sensor_init_767x[][2] = { + {0x12, 0x80}, + {0x11, 0x03}, + {0x3a, 0x04}, + {0x12, 0x00}, + {0x17, 0x13}, + {0x18, 0x01}, + {0x32, 0xb6}, + {0x19, 0x02}, + {0x1a, 0x7a}, + {0x03, 0x0a}, + {0x0c, 0x00}, + {0x3e, 0x00}, + {0x70, 0x3a}, + {0x71, 0x35}, + {0x72, 0x11}, + {0x73, 0xf0}, + {0xa2, 0x02}, + {0x7a, 0x2a}, /* set Gamma=1.6 below */ + {0x7b, 0x12}, + {0x7c, 0x1d}, + {0x7d, 0x2d}, + {0x7e, 0x45}, + {0x7f, 0x50}, + {0x80, 0x59}, + {0x81, 0x62}, + {0x82, 0x6b}, + {0x83, 0x73}, + {0x84, 0x7b}, + {0x85, 0x8a}, + {0x86, 0x98}, + {0x87, 0xb2}, + {0x88, 0xca}, + {0x89, 0xe0}, + {0x13, 0xe0}, + {0x00, 0x00}, + {0x10, 0x00}, + {0x0d, 0x40}, + {0x14, 0x38}, /* gain max 16x */ + {0xa5, 0x05}, + {0xab, 0x07}, + {0x24, 0x95}, + {0x25, 0x33}, + {0x26, 0xe3}, + {0x9f, 0x78}, + {0xa0, 0x68}, + {0xa1, 0x03}, + {0xa6, 0xd8}, + {0xa7, 0xd8}, + {0xa8, 0xf0}, + {0xa9, 0x90}, + {0xaa, 0x94}, + {0x13, 0xe5}, + {0x0e, 0x61}, + {0x0f, 0x4b}, + {0x16, 0x02}, + {0x21, 0x02}, + {0x22, 0x91}, + {0x29, 0x07}, + {0x33, 0x0b}, + {0x35, 0x0b}, + {0x37, 0x1d}, + {0x38, 0x71}, + {0x39, 0x2a}, + {0x3c, 0x78}, + {0x4d, 0x40}, + {0x4e, 0x20}, + {0x69, 0x00}, + {0x6b, 0x4a}, + {0x74, 0x10}, + {0x8d, 0x4f}, + {0x8e, 0x00}, + {0x8f, 0x00}, + {0x90, 0x00}, + {0x91, 0x00}, + {0x96, 0x00}, + {0x9a, 0x80}, + {0xb0, 0x84}, + {0xb1, 0x0c}, + {0xb2, 0x0e}, + {0xb3, 0x82}, + {0xb8, 0x0a}, + {0x43, 0x0a}, + {0x44, 0xf0}, + {0x45, 0x34}, + {0x46, 0x58}, + {0x47, 0x28}, + {0x48, 0x3a}, + {0x59, 0x88}, + {0x5a, 0x88}, + {0x5b, 0x44}, + {0x5c, 0x67}, + {0x5d, 0x49}, + {0x5e, 0x0e}, + {0x6c, 0x0a}, + {0x6d, 0x55}, + {0x6e, 0x11}, + {0x6f, 0x9f}, + {0x6a, 0x40}, + {0x01, 0x40}, + {0x02, 0x40}, + {0x13, 0xe7}, + {0x4f, 0x80}, + {0x50, 0x80}, + {0x51, 0x00}, + {0x52, 0x22}, + {0x53, 0x5e}, + {0x54, 0x80}, + {0x58, 0x9e}, + {0x41, 0x08}, + {0x3f, 0x00}, + {0x75, 0x04}, + {0x76, 0xe1}, + {0x4c, 0x00}, + {0x77, 0x01}, + {0x3d, 0xc2}, + {0x4b, 0x09}, + {0xc9, 0x60}, + {0x41, 0x38}, /* jfm: auto sharpness + auto de-noise */ + {0x56, 0x40}, + {0x34, 0x11}, + {0x3b, 0xc2}, + {0xa4, 0x8a}, /* Night mode trigger point */ + {0x96, 0x00}, + {0x97, 0x30}, + {0x98, 0x20}, + {0x99, 0x20}, + {0x9a, 0x84}, + {0x9b, 0x29}, + {0x9c, 0x03}, + {0x9d, 0x4c}, + {0x9e, 0x3f}, + {0x78, 0x04}, + {0x79, 0x01}, + {0xc8, 0xf0}, + {0x79, 0x0f}, + {0xc8, 0x00}, + {0x79, 0x10}, + {0xc8, 0x7e}, + {0x79, 0x0a}, + {0xc8, 0x80}, + {0x79, 0x0b}, + {0xc8, 0x01}, + {0x79, 0x0c}, + {0xc8, 0x0f}, + {0x79, 0x0d}, + {0xc8, 0x20}, + {0x79, 0x09}, + {0xc8, 0x80}, + {0x79, 0x02}, + {0xc8, 0xc0}, + {0x79, 0x03}, + {0xc8, 0x20}, + {0x79, 0x26}, +}; +static const u8 bridge_start_vga_767x[][2] = { +/* str59 JPG */ + {0x94, 0xaa}, + {0xf1, 0x42}, + {0xe5, 0x04}, + {0xc0, 0x50}, + {0xc1, 0x3c}, + {0xc2, 0x0c}, + {0x35, 0x02}, /* turn on JPEG */ + {0xd9, 0x10}, + {0xda, 0x00}, /* for higher clock rate(30fps) */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xc3, 0xf9}, /* enable PRE */ + {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ + {0x8d, 0x1c}, /* output YUV */ +/* {0x34, 0x05}, * enable Audio Suspend mode (?) */ + {0x50, 0x00}, /* H/V divider=0 */ + {0x51, 0xa0}, /* input H=640/4 */ + {0x52, 0x3c}, /* input V=480/4 */ + {0x53, 0x00}, /* offset X=0 */ + {0x54, 0x00}, /* offset Y=0 */ + {0x55, 0x00}, /* H/V size[8]=0 */ + {0x57, 0x00}, /* H-size[9]=0 */ + {0x5c, 0x00}, /* output size[9:8]=0 */ + {0x5a, 0xa0}, /* output H=640/4 */ + {0x5b, 0x78}, /* output V=480/4 */ + {0x1c, 0x0a}, + {0x1d, 0x0a}, + {0x94, 0x11}, +}; +static const u8 sensor_start_vga_767x[][2] = { + {0x11, 0x01}, + {0x1e, 0x04}, + {0x19, 0x02}, + {0x1a, 0x7a}, +}; +static const u8 bridge_start_qvga_767x[][2] = { +/* str86 JPG */ + {0x94, 0xaa}, + {0xf1, 0x42}, + {0xe5, 0x04}, + {0xc0, 0x80}, + {0xc1, 0x60}, + {0xc2, 0x0c}, + {0x35, 0x02}, /* turn on JPEG */ + {0xd9, 0x10}, + {0xc0, 0x50}, /* CIF HSize 640 */ + {0xc1, 0x3c}, /* CIF VSize 480 */ + {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ + {0x8d, 0x1c}, /* output YUV */ + {0x34, 0x05}, /* enable Audio Suspend mode */ + {0xc2, 0x4c}, /* output YUV and Enable DCW */ + {0xc3, 0xf9}, /* enable PRE */ + {0x1c, 0x00}, /* indirect addressing */ + {0x1d, 0x48}, /* output YUV422 */ + {0x50, 0x89}, /* H/V divider=/2; plus DCW AVG */ + {0x51, 0xa0}, /* DCW input H=640/4 */ + {0x52, 0x78}, /* DCW input V=480/4 */ + {0x53, 0x00}, /* offset X=0 */ + {0x54, 0x00}, /* offset Y=0 */ + {0x55, 0x00}, /* H/V size[8]=0 */ + {0x57, 0x00}, /* H-size[9]=0 */ + {0x5c, 0x00}, /* DCW output size[9:8]=0 */ + {0x5a, 0x50}, /* DCW output H=320/4 */ + {0x5b, 0x3c}, /* DCW output V=240/4 */ + {0x1c, 0x0a}, + {0x1d, 0x0a}, + {0x94, 0x11}, +}; +static const u8 sensor_start_qvga_767x[][2] = { + {0x11, 0x01}, + {0x1e, 0x04}, + {0x19, 0x02}, + {0x1a, 0x7a}, +}; + +static const u8 bridge_init_772x[][2] = { { 0xc2, 0x0c }, { 0x88, 0xf8 }, { 0xc3, 0x69 }, @@ -312,7 +609,7 @@ static const u8 bridge_init[][2] = { { 0xc1, 0x3c }, { 0xc2, 0x0c }, }; -static const u8 sensor_init[][2] = { +static const u8 sensor_init_772x[][2] = { { 0x12, 0x80 }, { 0x11, 0x01 }, /*fixme: better have a delay?*/ @@ -405,7 +702,7 @@ static const u8 sensor_init[][2] = { { 0x8e, 0x00 }, /* De-noise threshold */ { 0x0c, 0xd0 } }; -static const u8 bridge_start_vga[][2] = { +static const u8 bridge_start_vga_772x[][2] = { {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, @@ -416,7 +713,7 @@ static const u8 bridge_start_vga[][2] = { {0xc0, 0x50}, {0xc1, 0x3c}, }; -static const u8 sensor_start_vga[][2] = { +static const u8 sensor_start_vga_772x[][2] = { {0x12, 0x00}, {0x17, 0x26}, {0x18, 0xa0}, @@ -426,7 +723,7 @@ static const u8 sensor_start_vga[][2] = { {0x2c, 0xf0}, {0x65, 0x20}, }; -static const u8 bridge_start_qvga[][2] = { +static const u8 bridge_start_qvga_772x[][2] = { {0x1c, 0x00}, {0x1d, 0x40}, {0x1d, 0x02}, @@ -437,7 +734,7 @@ static const u8 bridge_start_qvga[][2] = { {0xc0, 0x28}, {0xc1, 0x1e}, }; -static const u8 sensor_start_qvga[][2] = { +static const u8 sensor_start_qvga_772x[][2] = { {0x12, 0x40}, {0x17, 0x3f}, {0x18, 0x50}, @@ -620,6 +917,8 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) {30, 0x04, 0x41, 0x04}, }; + if (sd->sensor != SENSOR_OV772x) + return; if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { r = rate_0; i = ARRAY_SIZE(rate_0); @@ -643,15 +942,28 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + int val; - sccb_reg_write(gspca_dev, 0x9b, sd->ctrls[BRIGHTNESS].val); + val = sd->ctrls[BRIGHTNESS].val; + if (sd->sensor == SENSOR_OV767x) { + if (val < 0) + val = 0x80 - val; + sccb_reg_write(gspca_dev, 0x55, val); /* bright */ + } else { + sccb_reg_write(gspca_dev, 0x9b, val); + } } static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + u8 val; - sccb_reg_write(gspca_dev, 0x9c, sd->ctrls[CONTRAST].val); + val = sd->ctrls[CONTRAST].val; + if (sd->sensor == SENSOR_OV767x) + sccb_reg_write(gspca_dev, 0x56, val); /* contras */ + else + sccb_reg_write(gspca_dev, 0x9c, val); } static void setgain(struct gspca_dev *gspca_dev) @@ -692,15 +1004,22 @@ static void setexposure(struct gspca_dev *gspca_dev) if (sd->ctrls[AEC].val) return; - /* 'val' is one byte and represents half of the exposure value we are - * going to set into registers, a two bytes value: - * - * MSB: ((u16) val << 1) >> 8 == val >> 7 - * LSB: ((u16) val << 1) & 0xff == val << 1 - */ val = sd->ctrls[EXPOSURE].val; - sccb_reg_write(gspca_dev, 0x08, val >> 7); - sccb_reg_write(gspca_dev, 0x10, val << 1); + if (sd->sensor == SENSOR_OV767x) { + + /* set only aec[9:2] */ + sccb_reg_write(gspca_dev, 0x10, val); /* aech */ + } else { + + /* 'val' is one byte and represents half of the exposure value + * we are going to set into registers, a two bytes value: + * + * MSB: ((u16) val << 1) >> 8 == val >> 7 + * LSB: ((u16) val << 1) & 0xff == val << 1 + */ + sccb_reg_write(gspca_dev, 0x08, val >> 7); + sccb_reg_write(gspca_dev, 0x10, val << 1); + } } static void setagc(struct gspca_dev *gspca_dev) @@ -729,12 +1048,14 @@ static void setawb(struct gspca_dev *gspca_dev) if (sd->ctrls[AWB].val) { sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) | 0x02); - sccb_reg_write(gspca_dev, 0x63, + if (sd->sensor == SENSOR_OV772x) + sccb_reg_write(gspca_dev, 0x63, sccb_reg_read(gspca_dev, 0x63) | 0xc0); } else { sccb_reg_write(gspca_dev, 0x13, sccb_reg_read(gspca_dev, 0x13) & ~0x02); - sccb_reg_write(gspca_dev, 0x63, + if (sd->sensor == SENSOR_OV772x) + sccb_reg_write(gspca_dev, 0x63, sccb_reg_read(gspca_dev, 0x63) & ~0xc0); } } @@ -742,14 +1063,22 @@ static void setawb(struct gspca_dev *gspca_dev) static void setaec(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + u8 data; + data = sd->sensor == SENSOR_OV767x ? + 0x05 : /* agc + aec */ + 0x01; /* agc */ if (sd->ctrls[AEC].val) sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) | 0x01); + sccb_reg_read(gspca_dev, 0x13) | data); else { sccb_reg_write(gspca_dev, 0x13, - sccb_reg_read(gspca_dev, 0x13) & ~0x01); - setexposure(gspca_dev); + sccb_reg_read(gspca_dev, 0x13) & ~data); + if (sd->sensor == SENSOR_OV767x) + sd->ctrls[EXPOSURE].val = + sccb_reg_read(gspca_dev, 10); /* aech */ + else + setexposure(gspca_dev); } } @@ -768,23 +1097,37 @@ static void sethvflip(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val; - val = sccb_reg_read(gspca_dev, 0x0c); - val &= ~0xc0; - if (sd->ctrls[HFLIP].val == 0) - val |= 0x40; - if (sd->ctrls[VFLIP].val == 0) - val |= 0x80; - sccb_reg_write(gspca_dev, 0x0c, val); + if (sd->sensor == SENSOR_OV767x) { + val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */ + val &= ~0x30; + if (sd->ctrls[HFLIP].val) + val |= 0x20; + if (sd->ctrls[VFLIP].val) + val |= 0x10; + sccb_reg_write(gspca_dev, 0x1e, val); + } else { + val = sccb_reg_read(gspca_dev, 0x0c); + val &= ~0xc0; + if (sd->ctrls[HFLIP].val == 0) + val |= 0x40; + if (sd->ctrls[VFLIP].val == 0) + val |= 0x80; + sccb_reg_write(gspca_dev, 0x0c, val); + } } static void setlightfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + u8 val; - if (sd->ctrls[LIGHTFREQ].val == 0) - sccb_reg_write(gspca_dev, 0x2b, 0x00); - else - sccb_reg_write(gspca_dev, 0x2b, 0x9e); + val = sd->ctrls[LIGHTFREQ].val ? 0x9e : 0x00; + if (sd->sensor == SENSOR_OV767x) { + sccb_reg_write(gspca_dev, 0x2a, 0x00); + if (val) + val = 0x9d; /* insert dummy to 25fps for 50Hz */ + } + sccb_reg_write(gspca_dev, 0x2b, val); } @@ -805,11 +1148,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = ov772x_mode; cam->nmodes = ARRAY_SIZE(ov772x_mode); - cam->mode_framerates = ov772x_framerates; - - cam->bulk = 1; - cam->bulk_size = 16384; - cam->bulk_nurbs = 2; sd->frame_rate = 30; @@ -819,7 +1157,16 @@ static int sd_config(struct gspca_dev *gspca_dev, /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; u16 sensor_id; + static const struct reg_array bridge_init[NSENSORS] = { + [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)}, + [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)}, + }; + static const struct reg_array sensor_init[NSENSORS] = { + [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)}, + [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)}, + }; /* reset bridge */ ov534_reg_write(gspca_dev, 0xe7, 0x3a); @@ -840,35 +1187,82 @@ static int sd_init(struct gspca_dev *gspca_dev) sensor_id |= sccb_reg_read(gspca_dev, 0x0b); PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); + if ((sensor_id & 0xfff0) == 0x7670) { + sd->sensor = SENSOR_OV767x; + gspca_dev->ctrl_dis = (1 << GAIN) | + (1 << AGC) | + (1 << SHARPNESS); /* auto */ + sd->ctrls[BRIGHTNESS].min = -127; + sd->ctrls[BRIGHTNESS].max = 127; + sd->ctrls[BRIGHTNESS].def = 0; + sd->ctrls[CONTRAST].max = 0x80; + sd->ctrls[CONTRAST].def = 0x40; + sd->ctrls[EXPOSURE].min = 0x08; + sd->ctrls[EXPOSURE].max = 0x60; + sd->ctrls[EXPOSURE].def = 0x13; + sd->ctrls[SHARPNESS].max = 9; + sd->ctrls[SHARPNESS].def = 4; + sd->ctrls[HFLIP].def = 1; + gspca_dev->cam.cam_mode = ov767x_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); + } else { + sd->sensor = SENSOR_OV772x; + gspca_dev->cam.bulk = 1; + gspca_dev->cam.bulk_size = 16384; + gspca_dev->cam.bulk_nurbs = 2; + gspca_dev->cam.mode_framerates = ov772x_framerates; + } + /* initialize */ - reg_w_array(gspca_dev, bridge_init, - ARRAY_SIZE(bridge_init)); + reg_w_array(gspca_dev, bridge_init[sd->sensor].val, + bridge_init[sd->sensor].len); ov534_set_led(gspca_dev, 1); - sccb_w_array(gspca_dev, sensor_init, - ARRAY_SIZE(sensor_init)); - ov534_reg_write(gspca_dev, 0xe0, 0x09); - ov534_set_led(gspca_dev, 0); - set_frame_rate(gspca_dev); + sccb_w_array(gspca_dev, sensor_init[sd->sensor].val, + sensor_init[sd->sensor].len); + if (sd->sensor == SENSOR_OV767x) + sd_start(gspca_dev); + sd_stopN(gspca_dev); +/* set_frame_rate(gspca_dev); */ return gspca_dev->usb_err; } static int sd_start(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; int mode; + static const struct reg_array bridge_start[NSENSORS][2] = { + [SENSOR_OV767x] = {{bridge_start_qvga_767x, + ARRAY_SIZE(bridge_start_qvga_767x)}, + {bridge_start_vga_767x, + ARRAY_SIZE(bridge_start_vga_767x)}}, + [SENSOR_OV772x] = {{bridge_start_qvga_772x, + ARRAY_SIZE(bridge_start_qvga_772x)}, + {bridge_start_vga_772x, + ARRAY_SIZE(bridge_start_vga_772x)}}, + }; + static const struct reg_array sensor_start[NSENSORS][2] = { + [SENSOR_OV767x] = {{sensor_start_qvga_767x, + ARRAY_SIZE(sensor_start_qvga_767x)}, + {sensor_start_vga_767x, + ARRAY_SIZE(sensor_start_vga_767x)}}, + [SENSOR_OV772x] = {{sensor_start_qvga_772x, + ARRAY_SIZE(sensor_start_qvga_772x)}, + {sensor_start_vga_772x, + ARRAY_SIZE(sensor_start_vga_772x)}}, + }; + + /* (from ms-win trace) */ + if (sd->sensor == SENSOR_OV767x) + sccb_reg_write(gspca_dev, 0x1e, 0x04); + /* black sun enable ? */ + + mode = gspca_dev->curr_mode; /* 0: 320x240, 1: 640x480 */ + reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val, + bridge_start[sd->sensor][mode].len); + sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val, + sensor_start[sd->sensor][mode].len); - mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - if (mode != 0) { /* 320x240 */ - reg_w_array(gspca_dev, bridge_start_qvga, - ARRAY_SIZE(bridge_start_qvga)); - sccb_w_array(gspca_dev, sensor_start_qvga, - ARRAY_SIZE(sensor_start_qvga)); - } else { /* 640x480 */ - reg_w_array(gspca_dev, bridge_start_vga, - ARRAY_SIZE(bridge_start_vga)); - sccb_w_array(gspca_dev, sensor_start_vga, - ARRAY_SIZE(sensor_start_vga)); - } set_frame_rate(gspca_dev); if (!(gspca_dev->ctrl_dis & (1 << AGC))) @@ -913,9 +1307,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, __u32 this_pts; u16 this_fid; int remaining_len = len; + int payload_len; + payload_len = gspca_dev->cam.bulk ? 2048 : 2040; do { - len = min(remaining_len, 2048); + len = min(remaining_len, payload_len); /* Payloads are prefixed with a UVC-style header. We consider a frame to start when the FID toggles, or the PTS @@ -955,8 +1351,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* If this packet is marked as EOF, end the frame */ } else if (data[1] & UVC_STREAM_EOF) { sd->last_pts = 0; - if (gspca_dev->image_len + len - 12 != - gspca_dev->width * gspca_dev->height * 2) { + if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV + && gspca_dev->image_len + len - 12 != + gspca_dev->width * gspca_dev->height * 2) { PDEBUG(D_PACK, "wrong sized frame"); goto discard; } @@ -1073,6 +1470,7 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x1415, 0x2000)}, + {USB_DEVICE(0x06f8, 0x3002)}, {} }; -- cgit v1.2.2 From d57747f1e738cf1aa4a743ea10e0fb640b502c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 10:15:45 -0300 Subject: [media] gspca - ov534: Add saturation control for ov767x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov534.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 8dada2b745bc..0c6369b7fe18 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -61,6 +61,7 @@ enum e_ctrl { SHARPNESS, HFLIP, VFLIP, + COLORS, LIGHTFREQ, NCTRLS /* number of controls */ }; @@ -93,6 +94,7 @@ static void setawb(struct gspca_dev *gspca_dev); static void setaec(struct gspca_dev *gspca_dev); static void setsharpness(struct gspca_dev *gspca_dev); static void sethvflip(struct gspca_dev *gspca_dev); +static void setcolors(struct gspca_dev *gspca_dev); static void setlightfreq(struct gspca_dev *gspca_dev); static int sd_start(struct gspca_dev *gspca_dev); @@ -219,6 +221,18 @@ static const struct ctrl sd_ctrls[] = { }, .set_control = sethvflip }, +[COLORS] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 3, + }, + .set_control = setcolors + }, [LIGHTFREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -1116,6 +1130,26 @@ static void sethvflip(struct gspca_dev *gspca_dev) } } +static void setcolors(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val; + int i; + static u8 color_tb[][6] = { + {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, + {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, + {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, + {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, + {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, + {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, + {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, + }; + + val = sd->ctrls[COLORS].val; + for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) + sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); +} + static void setlightfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1207,6 +1241,7 @@ static int sd_init(struct gspca_dev *gspca_dev) gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); } else { sd->sensor = SENSOR_OV772x; + gspca_dev->ctrl_dis = (1 << COLORS); gspca_dev->cam.bulk = 1; gspca_dev->cam.bulk_size = 16384; gspca_dev->cam.bulk_nurbs = 2; @@ -1277,6 +1312,8 @@ static int sd_start(struct gspca_dev *gspca_dev) if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS))) setsharpness(gspca_dev); sethvflip(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << COLORS))) + setcolors(gspca_dev); setlightfreq(gspca_dev); ov534_set_led(gspca_dev, 1); -- cgit v1.2.2 From 20c957b360f85c293fbb6bcec9d1ec11b241ef1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 13:18:58 -0300 Subject: [media] gspca - sonixj: The pin S_PWR_DN is inverted for sensor mi0360 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index a1f82a92833d..6415aff5cbd1 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -408,7 +408,7 @@ static const u8 sn_hv7131[0x1c] = { static const u8 sn_mi0360[0x1c] = { /* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, + 0x00, 0x63, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, /* reg8 reg9 rega regb regc regd rege regf */ 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ -- cgit v1.2.2 From 07c6c9c6d0e797590a7cc76fc8f0b740f34d21a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 13:32:22 -0300 Subject: [media] gspca - ov519: Add the sensor ov2610ae MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov519.c | 67 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 8ab2c452c25e..cda7ee2c8bb4 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -118,6 +118,7 @@ struct sd { }; enum sensors { SEN_OV2610, + SEN_OV2610AE, SEN_OV3610, SEN_OV6620, SEN_OV6630, @@ -239,6 +240,8 @@ static const struct ctrl sd_ctrls[] = { static const unsigned ctrl_dis[] = { [SEN_OV2610] = (1 << NCTRL) - 1, /* no control */ +[SEN_OV2610AE] = (1 << NCTRL) - 1, /* no control */ + [SEN_OV3610] = (1 << NCTRL) - 1, /* no control */ [SEN_OV6620] = (1 << HFLIP) | @@ -656,6 +659,24 @@ static const struct ov_i2c_regvals norm_2610[] = { { 0x12, 0x80 }, /* reset */ }; +static const struct ov_i2c_regvals norm_2610ae[] = { + {0x12, 0x80}, /* reset */ + {0x13, 0xcd}, + {0x09, 0x01}, + {0x0d, 0x00}, + {0x11, 0x80}, + {0x12, 0x20}, /* 1600x1200 */ + {0x33, 0x0c}, + {0x35, 0x90}, + {0x36, 0x37}, +/* ms-win traces */ + {0x11, 0x83}, /* clock / 3 ? */ + {0x2d, 0x00}, /* 60 Hz filter */ + {0x24, 0xb0}, /* normal colors */ + {0x25, 0x90}, + {0x10, 0x43}, +}; + static const struct ov_i2c_regvals norm_3620b[] = { /* * From the datasheet: "Note that after writing to register COMH @@ -2621,6 +2642,9 @@ static void ov_hires_configure(struct sd *sd) if (high == 0x96 && low == 0x40) { PDEBUG(D_PROBE, "Sensor is an OV2610"); sd->sensor = SEN_OV2610; + } else if (high == 0x96 && low == 0x41) { + PDEBUG(D_PROBE, "Sensor is an OV2610AE"); + sd->sensor = SEN_OV2610AE; } else if (high == 0x36 && (low & 0x0f) == 0x00) { PDEBUG(D_PROBE, "Sensor is an OV3610"); sd->sensor = SEN_OV3610; @@ -3295,15 +3319,22 @@ static int sd_init(struct gspca_dev *gspca_dev) } break; case BRIDGE_OVFX2: - if (sd->sensor == SEN_OV2610) { + switch (sd->sensor) { + case SEN_OV2610: + case SEN_OV2610AE: cam->cam_mode = ovfx2_ov2610_mode; cam->nmodes = ARRAY_SIZE(ovfx2_ov2610_mode); - } else if (sd->sensor == SEN_OV3610) { + break; + case SEN_OV3610: cam->cam_mode = ovfx2_ov3610_mode; cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode); - } else if (sd->sif) { - cam->cam_mode = ov519_sif_mode; - cam->nmodes = ARRAY_SIZE(ov519_sif_mode); + break; + default: + if (sd->sif) { + cam->cam_mode = ov519_sif_mode; + cam->nmodes = ARRAY_SIZE(ov519_sif_mode); + } + break; } break; case BRIDGE_W9968CF: @@ -3325,6 +3356,12 @@ static int sd_init(struct gspca_dev *gspca_dev) /* Enable autogain, autoexpo, awb, bandfilter */ i2c_w_mask(sd, 0x13, 0x27, 0x27); break; + case SEN_OV2610AE: + write_i2c_regvals(sd, norm_2610ae, ARRAY_SIZE(norm_2610ae)); + + /* enable autoexpo */ + i2c_w_mask(sd, 0x13, 0x05, 0x05); + break; case SEN_OV3610: write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b)); @@ -3827,6 +3864,25 @@ static void mode_init_ov_sensor_regs(struct sd *sd) i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0); i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20); return; + case SEN_OV2610AE: { + u8 v; + + /* frame rates: + * 10fps / 5 fps for 1600x1200 + * 40fps / 20fps for 800x600 + */ + v = 80; + if (qvga) { + if (sd->frame_rate < 25) + v = 0x81; + } else { + if (sd->frame_rate < 10) + v = 0x81; + } + i2c_w(sd, 0x11, v); + i2c_w(sd, 0x12, qvga ? 0x60 : 0x20); + return; + } case SEN_OV3610: if (qvga) { xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4); @@ -3975,6 +4031,7 @@ static void set_ov_sensor_window(struct sd *sd) /* mode setup is fully handled in mode_init_ov_sensor_regs for these */ switch (sd->sensor) { case SEN_OV2610: + case SEN_OV2610AE: case SEN_OV3610: case SEN_OV7670: mode_init_ov_sensor_regs(sd); -- cgit v1.2.2 From c42cedbb658bde9b7bea0ce24e2388b7c717fdb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Thu, 10 Feb 2011 13:37:48 -0300 Subject: [media] gspca - ov519: Add the 800x600 resolution for sensors ov2610/2610ae MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov519.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index cda7ee2c8bb4..42670ec7ef3b 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -431,6 +431,11 @@ static const struct v4l2_pix_format ovfx2_cif_mode[] = { .priv = 0}, }; static const struct v4l2_pix_format ovfx2_ov2610_mode[] = { + {800, 600, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, {1600, 1200, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 1600, .sizeimage = 1600 * 1200, @@ -547,6 +552,7 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = { * buffers, there are some pretty strict real time constraints for * isochronous transfer for larger frame sizes). */ +/*jfm: this value works well for 1600x1200, but not 800x600 - see isoc_init */ #define OVFX2_BULK_SIZE (13 * 4096) /* I2C registers */ @@ -3434,6 +3440,22 @@ error: return -EINVAL; } +/* function called at start time before URB creation */ +static int sd_isoc_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + case BRIDGE_OVFX2: + if (gspca_dev->width == 1600) + gspca_dev->cam.bulk_size = OVFX2_BULK_SIZE; + else + gspca_dev->cam.bulk_size = 7 * 4096; + break; + } + return 0; +} + /* Set up the OV511/OV511+ with the given image parameters. * * Do not put any sensor-specific code in here (including I2C I/O functions) @@ -4788,6 +4810,7 @@ static const struct sd_desc sd_desc = { .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, -- cgit v1.2.2 From 9839029b052f094b9c14cb60e7c729950dd28712 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Tue, 25 Jan 2011 13:40:55 -0300 Subject: [media] tm6000: relabeling any registers relabeling any registers Signed-off-by: Stefan Ringel Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-core.c | 64 ++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 96aed4ace467..5162cd4a8288 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -268,11 +268,11 @@ int tm6000_init_analog_mode(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80); tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23); + tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23); tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0); tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8); tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f); + tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f); /* AP Software reset */ tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); @@ -284,8 +284,8 @@ int tm6000_init_analog_mode(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); /* E3: Select input 0 - TV tuner */ - tm6000_set_reg(dev, TM6010_REQ07_RE3_OUT_SEL1, 0x00); - tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60); + tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00); + tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x60); /* This controls input */ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0); @@ -344,21 +344,21 @@ int tm6000_init_digital_mode(struct tm6000_core *dev) tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08); - tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c); - tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff); - tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8); + tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08); + tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); + tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); + tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8); tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40); tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09); - tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x37); + tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37); tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8); tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0); tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60); - tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c); - tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff); - tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08); + tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c); + tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff); + tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08); msleep(50); tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); @@ -388,18 +388,19 @@ struct reg_init { /* The meaning of those initializations are unknown */ struct reg_init tm6000_init_tab[] = { /* REG VALUE */ - { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f }, + { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f }, { TM6010_REQ07_RFF_SOFT_RESET, 0x08 }, { TM6010_REQ07_RFF_SOFT_RESET, 0x00 }, { TM6010_REQ07_RD5_POWERSAVE, 0x4f }, - { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23 }, - { TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0x08 }, - { TM6010_REQ07_RE2_OUT_SEL2, 0x00 }, - { TM6010_REQ07_RE3_OUT_SEL1, 0x10 }, - { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0x00 }, - { TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0x00 }, - { REQ_07_SET_GET_AVREG, 0xeb, 0x64 }, /* 48000 bits/sample, external input */ - { REQ_07_SET_GET_AVREG, 0xee, 0xc2 }, + { TM6000_REQ07_RDA_CLK_SEL, 0x23 }, + { TM6000_REQ07_RDB_OUT_SEL, 0x08 }, + { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 }, + { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 }, + { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 }, + { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 }, + { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 }, /* 48000 bits/sample, external input */ + { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 }, + { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */ { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, @@ -592,6 +593,7 @@ int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) { int val; + /* enable I2S, if we use sif or external I2S device */ if (dev->dev_type == TM6010) { val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0); if (val < 0) @@ -602,9 +604,17 @@ int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) return val; } - val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0); - if (val < 0) - return val; + /* different reg's to set audio bitrate */ + if (dev->dev_type == TM6010) { + val = tm6000_get_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + 0x0); + if (val < 0) + return val; + } else { + val = tm6000_get_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x0); + if (val < 0) + return val; + } val &= 0x0f; /* Preserve the audio input control bits */ switch (bitrate) { @@ -617,7 +627,11 @@ int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) dev->audio_bitrate = bitrate; break; } - val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val); + if (dev->dev_type == TM6010) + val = tm6000_set_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + val); + else + val = tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, val); return val; } -- cgit v1.2.2 From 8bc50f354047f4afb31fc85f0efb6bfe28ce9e57 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 16 Feb 2011 07:11:14 -0300 Subject: [media] gspca_sn9c20x: Fix colored borders with ov7660 sensor Tested with a camera with usb-id: 0c45:62bb Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sn9c20x.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index fcf29897b713..40e316ac3951 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -884,6 +884,9 @@ static struct i2c_reg_u8 ov7660_init[] = { {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3}, {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40}, {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a}, + /* HDG Set hstart and hstop, datasheet default 0x11, 0x61, using + 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */ + {0x17, 0x10}, {0x18, 0x61}, {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43}, {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6}, {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50}, @@ -1334,8 +1337,8 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev) } /* disable hflip and vflip */ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); - sd->hstart = 1; - sd->vstart = 1; + sd->hstart = 3; + sd->vstart = 3; return 0; } -- cgit v1.2.2 From 779b51f7a5ec0e95dcc3690cd68c2631a971a65e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 16 Feb 2011 08:17:36 -0300 Subject: [media] gspca_sn9c20x: Add hflip and vflip controls for the ov7660 sensor Tested with a camera with usb-id: 0c45:62bb Also enable dmi based flopped laptop detection for the 0c45:627b ov7660 model. Some of the MSI laptops with upside down camera have this one instead of the 0c45:624f. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sn9c20x.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 40e316ac3951..ccc89c113bad 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -1335,8 +1335,6 @@ static int ov7660_init_sensor(struct gspca_dev *gspca_dev) return -ENODEV; } } - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX); sd->hstart = 3; sd->vstart = 3; return 0; @@ -1611,6 +1609,18 @@ static int set_hvflip(struct gspca_dev *gspca_dev) } switch (sd->sensor) { + case SENSOR_OV7660: + value = 0x01; + if (hflip) + value |= 0x20; + if (vflip) { + value |= 0x10; + sd->vstart = 2; + } else + sd->vstart = 3; + reg_w1(gspca_dev, 0x1182, sd->vstart); + i2c_w1(gspca_dev, 0x1e, value); + break; case SENSOR_OV9650: i2c_r1(gspca_dev, 0x1e, &value); value &= ~0x30; @@ -2485,7 +2495,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6253), SN9C20X(OV9650, 0x30, 0)}, {USB_DEVICE(0x0c45, 0x6260), SN9C20X(OV7670, 0x21, 0)}, {USB_DEVICE(0x0c45, 0x6270), SN9C20X(MT9VPRB, 0x00, 0)}, - {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x627b), SN9C20X(OV7660, 0x21, FLIP_DETECT)}, {USB_DEVICE(0x0c45, 0x627c), SN9C20X(HV7131R, 0x11, 0)}, {USB_DEVICE(0x0c45, 0x627f), SN9C20X(OV9650, 0x30, 0)}, {USB_DEVICE(0x0c45, 0x6280), SN9C20X(MT9M001, 0x5d, 0)}, -- cgit v1.2.2 From b39e0cb9018bf95348078ad74b3e0171e985389a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 16 Feb 2011 08:33:16 -0300 Subject: [media] gspca_sn9c20x: Add LED_REVERSE flag for 0c45:62bb This fixes the led not working on this camera Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sn9c20x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index ccc89c113bad..52f44a5c1b2f 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -2507,7 +2507,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x62a0), SN9C20X(OV7670, 0x21, 0)}, {USB_DEVICE(0x0c45, 0x62b0), SN9C20X(MT9VPRB, 0x00, 0)}, {USB_DEVICE(0x0c45, 0x62b3), SN9C20X(OV9655, 0x30, 0)}, - {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, 0)}, + {USB_DEVICE(0x0c45, 0x62bb), SN9C20X(OV7660, 0x21, LED_REVERSE)}, {USB_DEVICE(0x0c45, 0x62bc), SN9C20X(HV7131R, 0x11, 0)}, {USB_DEVICE(0x045e, 0x00f4), SN9C20X(OV9650, 0x30, 0)}, {USB_DEVICE(0x145f, 0x013d), SN9C20X(OV7660, 0x21, 0)}, -- cgit v1.2.2 From 6899a9c7778a6d19edc74e2ef7dfb6daf21dc366 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 16 Feb 2011 08:37:54 -0300 Subject: [media] gspca_sn9c20x: Make buffers slightly larger for JPEG frames In good lighting conditions (lots of details visible) the current buffers are sometimes too small. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sn9c20x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 52f44a5c1b2f..f51579c4e9dc 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -369,7 +369,7 @@ static const struct v4l2_pix_format vga_mode[] = { .priv = SCALE_160x120}, {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, + .sizeimage = 320 * 240 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = SCALE_320x240 | MODE_JPEG}, {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, @@ -384,7 +384,7 @@ static const struct v4l2_pix_format vga_mode[] = { .priv = SCALE_320x240}, {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, + .sizeimage = 640 * 480 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = SCALE_640x480 | MODE_JPEG}, {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, @@ -417,7 +417,7 @@ static const struct v4l2_pix_format sxga_mode[] = { .priv = SCALE_160x120}, {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 590, + .sizeimage = 320 * 240 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = SCALE_320x240 | MODE_JPEG}, {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, @@ -432,7 +432,7 @@ static const struct v4l2_pix_format sxga_mode[] = { .priv = SCALE_320x240}, {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 640, - .sizeimage = 640 * 480 * 3 / 8 + 590, + .sizeimage = 640 * 480 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = SCALE_640x480 | MODE_JPEG}, {640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, -- cgit v1.2.2 From bcc6f669066d490f10484f44561f9c2ebb38c25b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 17 Feb 2011 06:27:57 -0300 Subject: [media] gspca_sn9c20x: Add another MSI laptop to the sn9c20x upside down list Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sn9c20x.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index f51579c4e9dc..c431900cd292 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -151,6 +151,13 @@ static const struct dmi_system_id flip_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "MS-1632") } }, + { + .ident = "MSI MS-1633X", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "MSI"), + DMI_MATCH(DMI_BOARD_NAME, "MS-1633X") + } + }, { .ident = "MSI MS-1635X", .matches = { -- cgit v1.2.2 From 49b61ec9b5afdb739e07bc085ed12678bc932a22 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 21 Feb 2011 11:06:29 -0300 Subject: [media] gspca: Add new vicam subdriver This is a complete rewrite of the old v4l1 vicam subdriver, featuring multiple resolutions, gain + exposure control and still has less code. Oh and it is a v4l2 driver rather then v4l1 ofcourse :) Many thanks to Devin Heitmueller for donating his 3com homeconnect to me, which made this rewrite possible. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/Kconfig | 10 + drivers/media/video/gspca/Makefile | 2 + drivers/media/video/gspca/vicam.c | 381 +++++++++++++++++++++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 drivers/media/video/gspca/vicam.c (limited to 'drivers') diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index dda56ff834f4..a20f6ae88250 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -346,6 +346,16 @@ config USB_GSPCA_VC032X To compile this driver as a module, choose M here: the module will be called gspca_vc032x. +config USB_GSPCA_VICAM + tristate "ViCam USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for the 3com homeconnect camera + (vicam). + + To compile this driver as a module, choose M here: the + module will be called gspca_vicam. + config USB_GSPCA_XIRLINK_CIT tristate "Xirlink C-It USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 24e695b8b077..a0dbcfbab29c 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o +obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o @@ -73,6 +74,7 @@ gspca_sunplus-objs := sunplus.o gspca_t613-objs := t613.o gspca_tv8532-objs := tv8532.o gspca_vc032x-objs := vc032x.o +gspca_vicam-objs := vicam.o gspca_xirlink_cit-objs := xirlink_cit.o gspca_zc3xx-objs := zc3xx.o diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c new file mode 100644 index 000000000000..84dfbab923b5 --- /dev/null +++ b/drivers/media/video/gspca/vicam.c @@ -0,0 +1,381 @@ +/* + * gspca ViCam subdriver + * + * Copyright (C) 2011 Hans de Goede + * + * Based on the usbvideo vicam driver, which is: + * + * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), + * Christopher L Cheney (ccheney@cheney.cx), + * Pavel Machek (pavel@ucw.cz), + * John Tyner (jtyner@cs.ucr.edu), + * Monroe Williams (monroe@pobox.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "vicam" +#define HEADER_SIZE 64 + +#include +#include +#include +#include +#include "gspca.h" + +MODULE_AUTHOR("Hans de Goede "); +MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver"); +MODULE_LICENSE("GPL"); + +enum e_ctrl { + GAIN, + EXPOSURE, + NCTRL /* number of controls */ +}; + +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + struct work_struct work_struct; + struct workqueue_struct *work_thread; + struct gspca_ctrl ctrls[NCTRL]; +}; + +/* The vicam sensor has a resolution of 512 x 244, with I believe square + pixels, but this is forced to a 4:3 ratio by optics. So it has + non square pixels :( */ +static struct v4l2_pix_format vicam_mode[] = { + { 256, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 256, + .sizeimage = 256 * 122, + .colorspace = V4L2_COLORSPACE_SRGB,}, + /* 2 modes with somewhat more square pixels */ + { 256, 200, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 256, + .sizeimage = 256 * 200, + .colorspace = V4L2_COLORSPACE_SRGB,}, + { 256, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 256, + .sizeimage = 256 * 240, + .colorspace = V4L2_COLORSPACE_SRGB,}, +#if 0 /* This mode has extremely non square pixels, testing use only */ + { 512, 122, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 512, + .sizeimage = 512 * 122, + .colorspace = V4L2_COLORSPACE_SRGB,}, +#endif + { 512, 244, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, + .bytesperline = 512, + .sizeimage = 512 * 244, + .colorspace = V4L2_COLORSPACE_SRGB,}, +}; + +static const struct ctrl sd_ctrls[] = { +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 200, + }, + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 2047, + .step = 1, + .default_value = 256, + }, + }, +}; + +static int vicam_control_msg(struct gspca_dev *gspca_dev, u8 request, + u16 value, u16 index, u8 *data, u16 len) +{ + int ret; + + ret = usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, data, len, 1000); + if (ret < 0) + err("control msg req %02X error %d", request, ret); + + return ret; +} + +static int vicam_set_camera_power(struct gspca_dev *gspca_dev, int state) +{ + int ret; + + ret = vicam_control_msg(gspca_dev, 0x50, state, 0, NULL, 0); + if (ret < 0) + return ret; + + if (state) + ret = vicam_control_msg(gspca_dev, 0x55, 1, 0, NULL, 0); + + return ret; +} + +/* + * request and read a block of data - see warning on vicam_command. + */ +static int vicam_read_frame(struct gspca_dev *gspca_dev, u8 *data, int size) +{ + struct sd *sd = (struct sd *)gspca_dev; + int ret, unscaled_height, act_len = 0; + u8 *req_data = gspca_dev->usb_buf; + + memset(req_data, 0, 16); + req_data[0] = sd->ctrls[GAIN].val; + if (gspca_dev->width == 256) + req_data[1] |= 0x01; /* low nibble x-scale */ + if (gspca_dev->height <= 122) { + req_data[1] |= 0x10; /* high nibble y-scale */ + unscaled_height = gspca_dev->height * 2; + } else + unscaled_height = gspca_dev->height; + req_data[2] = 0x90; /* unknown, does not seem to do anything */ + if (unscaled_height <= 200) + req_data[3] = 0x06; /* vend? */ + else if (unscaled_height <= 242) /* Yes 242 not 240 */ + req_data[3] = 0x07; /* vend? */ + else /* Up to 244 lines with req_data[3] == 0x08 */ + req_data[3] = 0x08; /* vend? */ + + if (sd->ctrls[EXPOSURE].val < 256) { + /* Frame rate maxed out, use partial frame expo time */ + req_data[4] = 255 - sd->ctrls[EXPOSURE].val; + req_data[5] = 0x00; + req_data[6] = 0x00; + req_data[7] = 0x01; + } else { + /* Modify frame rate */ + req_data[4] = 0x00; + req_data[5] = 0x00; + req_data[6] = sd->ctrls[EXPOSURE].val & 0xFF; + req_data[7] = sd->ctrls[EXPOSURE].val >> 8; + } + req_data[8] = ((244 - unscaled_height) / 2) & ~0x01; /* vstart */ + /* bytes 9-15 do not seem to affect exposure or image quality */ + + mutex_lock(&gspca_dev->usb_lock); + ret = vicam_control_msg(gspca_dev, 0x51, 0x80, 0, req_data, 16); + mutex_unlock(&gspca_dev->usb_lock); + if (ret < 0) + return ret; + + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x81), + data, size, &act_len, 10000); + /* successful, it returns 0, otherwise negative */ + if (ret < 0 || act_len != size) { + err("bulk read fail (%d) len %d/%d", + ret, act_len, size); + return -EIO; + } + return 0; +} + +/* This function is called as a workqueue function and runs whenever the camera + * is streaming data. Because it is a workqueue function it is allowed to sleep + * so we can use synchronous USB calls. To avoid possible collisions with other + * threads attempting to use the camera's USB interface we take the gspca + * usb_lock when performing USB operations. In practice the only thing we need + * to protect against is the usb_set_interface call that gspca makes during + * stream_off as the camera doesn't provide any controls that the user could try + * to change. + */ +static void vicam_dostream(struct work_struct *work) +{ + struct sd *sd = container_of(work, struct sd, work_struct); + struct gspca_dev *gspca_dev = &sd->gspca_dev; + int ret, frame_sz; + u8 *buffer; + + frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage + + HEADER_SIZE; + buffer = kmalloc(frame_sz, GFP_KERNEL | GFP_DMA); + if (!buffer) { + err("Couldn't allocate USB buffer"); + goto exit; + } + + while (gspca_dev->present && gspca_dev->streaming) { + ret = vicam_read_frame(gspca_dev, buffer, frame_sz); + if (ret < 0) + break; + + /* Note the frame header contents seem to be completely + constant, they do not change with either image, or + settings. So we simply discard it. The frames have + a very similar 64 byte footer, which we don't even + bother reading from the cam */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + buffer + HEADER_SIZE, + frame_sz - HEADER_SIZE); + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + } +exit: + kfree(buffer); +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam = &gspca_dev->cam; + struct sd *sd = (struct sd *)gspca_dev; + + /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk = 1; + cam->bulk_size = 64; + cam->cam_mode = vicam_mode; + cam->nmodes = ARRAY_SIZE(vicam_mode); + cam->ctrls = sd->ctrls; + + INIT_WORK(&sd->work_struct, vicam_dostream); + + return 0; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + int ret; + const struct ihex_binrec *rec; + const struct firmware *uninitialized_var(fw); + u8 *firmware_buf; + + ret = request_ihex_firmware(&fw, "vicam/firmware.fw", + &gspca_dev->dev->dev); + if (ret) { + err("Failed to load \"vicam/firmware.fw\": %d\n", ret); + return ret; + } + + firmware_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!firmware_buf) { + ret = -ENOMEM; + goto exit; + } + for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { + memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len)); + ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, + be16_to_cpu(rec->len)); + if (ret < 0) + break; + } + + kfree(firmware_buf); +exit: + release_firmware(fw); + return ret; +} + +/* Set up for getting frames. */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + int ret; + + ret = vicam_set_camera_power(gspca_dev, 1); + if (ret < 0) + return ret; + + /* Start the workqueue function to do the streaming */ + sd->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(sd->work_thread, &sd->work_struct); + + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *)gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + /* This waits for vicam_dostream to finish */ + destroy_workqueue(dev->work_thread); + dev->work_thread = NULL; + mutex_lock(&gspca_dev->usb_lock); + + vicam_set_camera_power(gspca_dev, 0); +} + +/* Table of supported USB devices */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x04c1, 0x009d)}, + {USB_DEVICE(0x0602, 0x1001)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, + sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); -- cgit v1.2.2 From 76fafe78df9e4062b9b6595f3225a2c0c2847ae5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 21 Feb 2011 11:30:30 -0300 Subject: [media] gspca_cpia1: Don't allow the framerate divisor to go above 2 Having a framerate divisor of 3 is not really necesarry and leads to various troubles (frames going missing, compression issues) when allowed. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/cpia1.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index 4bf2cab98d64..2a4a428f2018 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -1,7 +1,7 @@ /* * cpia CPiA (1) gspca driver * - * Copyright (C) 2010 Hans de Goede + * Copyright (C) 2010-2011 Hans de Goede * * This module is adapted from the in kernel v4l1 cpia driver which is : * @@ -1400,7 +1400,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev) if ((sd->exposure_status == EXPOSURE_VERY_DARK || sd->exposure_status == EXPOSURE_DARK) && sd->exposure_count >= DARK_TIME * framerate && - sd->params.sensorFps.divisor < 3) { + sd->params.sensorFps.divisor < 2) { /* dark for too long */ ++sd->params.sensorFps.divisor; @@ -1456,7 +1456,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev) if ((sd->exposure_status == EXPOSURE_VERY_DARK || sd->exposure_status == EXPOSURE_DARK) && sd->exposure_count >= DARK_TIME * framerate && - sd->params.sensorFps.divisor < 3) { + sd->params.sensorFps.divisor < 2) { /* dark for too long */ ++sd->params.sensorFps.divisor; -- cgit v1.2.2 From 37d803ed0b86a3252457da971e0e9a8a937c2ba4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 22 Feb 2011 13:39:36 -0300 Subject: [media] staging-usbvideo: remove With the new gspca v4l2 vicam driver, there is no more reason to keep the old v4l1 usbvideo vicam driver around, and since that is the last usbvideo framework using driver, the old usbvideo framework itself can go too. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/usbvideo/Kconfig | 15 - drivers/staging/usbvideo/Makefile | 2 - drivers/staging/usbvideo/TODO | 5 - drivers/staging/usbvideo/usbvideo.c | 2230 ----------------------------------- drivers/staging/usbvideo/usbvideo.h | 395 ------- drivers/staging/usbvideo/vicam.c | 952 --------------- drivers/staging/usbvideo/videodev.h | 318 ----- 9 files changed, 3920 deletions(-) delete mode 100644 drivers/staging/usbvideo/Kconfig delete mode 100644 drivers/staging/usbvideo/Makefile delete mode 100644 drivers/staging/usbvideo/TODO delete mode 100644 drivers/staging/usbvideo/usbvideo.c delete mode 100644 drivers/staging/usbvideo/usbvideo.h delete mode 100644 drivers/staging/usbvideo/vicam.c delete mode 100644 drivers/staging/usbvideo/videodev.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 4a88e69bb9bb..a3f340bb6b59 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -57,8 +57,6 @@ source "drivers/staging/dabusb/Kconfig" source "drivers/staging/se401/Kconfig" -source "drivers/staging/usbvideo/Kconfig" - source "drivers/staging/usbip/Kconfig" source "drivers/staging/winbond/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 80ee49ab59de..532331ceb12d 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_USB_DABUSB) += dabusb/ -obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_SE401) += se401/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_USB_IP_COMMON) += usbip/ diff --git a/drivers/staging/usbvideo/Kconfig b/drivers/staging/usbvideo/Kconfig deleted file mode 100644 index 566d659e6ff3..000000000000 --- a/drivers/staging/usbvideo/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config VIDEO_USBVIDEO - tristate - -config USB_VICAM - tristate "USB 3com HomeConnect (aka vicam) support (DEPRECATED)" - depends on VIDEO_DEV && VIDEO_V4L2_COMMON && USB - select VIDEO_USBVIDEO - ---help--- - Say Y here if you have 3com homeconnect camera (vicam). - - This driver uses the deprecated V4L1 API and will be removed in - 2.6.39, unless someone converts it to the V4L2 API. - - To compile this driver as a module, choose M here: the - module will be called vicam. diff --git a/drivers/staging/usbvideo/Makefile b/drivers/staging/usbvideo/Makefile deleted file mode 100644 index 3c99a9a2d8d3..000000000000 --- a/drivers/staging/usbvideo/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o -obj-$(CONFIG_USB_VICAM) += vicam.o diff --git a/drivers/staging/usbvideo/TODO b/drivers/staging/usbvideo/TODO deleted file mode 100644 index 3b2c03836286..000000000000 --- a/drivers/staging/usbvideo/TODO +++ /dev/null @@ -1,5 +0,0 @@ -This is an obsolete driver for some old webcams that still use V4L1 API. -As V4L1 support is being removed from kernel, if nobody take care on it, -the driver will be removed for 2.6.39. - -Please send patches to linux-media@vger.kernel.org diff --git a/drivers/staging/usbvideo/usbvideo.c b/drivers/staging/usbvideo/usbvideo.c deleted file mode 100644 index f1fcf9744961..000000000000 --- a/drivers/staging/usbvideo/usbvideo.c +++ /dev/null @@ -1,2230 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "usbvideo.h" - -#if defined(MAP_NR) -#define virt_to_page(v) MAP_NR(v) /* Kernels 2.2.x */ -#endif - -static int video_nr = -1; -module_param(video_nr, int, 0); - -/* - * Local prototypes. - */ -static void usbvideo_Disconnect(struct usb_interface *intf); -static void usbvideo_CameraRelease(struct uvd *uvd); - -static long usbvideo_v4l_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); -static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma); -static int usbvideo_v4l_open(struct file *file); -static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); -static int usbvideo_v4l_close(struct file *file); - -static int usbvideo_StartDataPump(struct uvd *uvd); -static void usbvideo_StopDataPump(struct uvd *uvd); -static int usbvideo_GetFrame(struct uvd *uvd, int frameNum); -static int usbvideo_NewFrame(struct uvd *uvd, int framenum); -static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, - struct usbvideo_frame *frame); - -/*******************************/ -/* Memory management functions */ -/*******************************/ -static void *usbvideo_rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void usbvideo_rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - -static void RingQueue_Initialize(struct RingQueue *rq) -{ - assert(rq != NULL); - init_waitqueue_head(&rq->wqh); -} - -static void RingQueue_Allocate(struct RingQueue *rq, int rqLen) -{ - /* Make sure the requested size is a power of 2 and - round up if necessary. This allows index wrapping - using masks rather than modulo */ - - int i = 1; - assert(rq != NULL); - assert(rqLen > 0); - - while(rqLen >> i) - i++; - if(rqLen != 1 << (i-1)) - rqLen = 1 << i; - - rq->length = rqLen; - rq->ri = rq->wi = 0; - rq->queue = usbvideo_rvmalloc(rq->length); - assert(rq->queue != NULL); -} - -static int RingQueue_IsAllocated(const struct RingQueue *rq) -{ - if (rq == NULL) - return 0; - return (rq->queue != NULL) && (rq->length > 0); -} - -static void RingQueue_Free(struct RingQueue *rq) -{ - assert(rq != NULL); - if (RingQueue_IsAllocated(rq)) { - usbvideo_rvfree(rq->queue, rq->length); - rq->queue = NULL; - rq->length = 0; - } -} - -int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len) -{ - int rql, toread; - - assert(rq != NULL); - assert(dst != NULL); - - rql = RingQueue_GetLength(rq); - if(!rql) - return 0; - - /* Clip requested length to available data */ - if(len > rql) - len = rql; - - toread = len; - if(rq->ri > rq->wi) { - /* Read data from tail */ - int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri; - memcpy(dst, rq->queue + rq->ri, read); - toread -= read; - dst += read; - rq->ri = (rq->ri + read) & (rq->length-1); - } - if(toread) { - /* Read data from head */ - memcpy(dst, rq->queue + rq->ri, toread); - rq->ri = (rq->ri + toread) & (rq->length-1); - } - return len; -} - -EXPORT_SYMBOL(RingQueue_Dequeue); - -int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n) -{ - int enqueued = 0; - - assert(rq != NULL); - assert(cdata != NULL); - assert(rq->length > 0); - while (n > 0) { - int m, q_avail; - - /* Calculate the largest chunk that fits the tail of the ring */ - q_avail = rq->length - rq->wi; - if (q_avail <= 0) { - rq->wi = 0; - q_avail = rq->length; - } - m = n; - assert(q_avail > 0); - if (m > q_avail) - m = q_avail; - - memcpy(rq->queue + rq->wi, cdata, m); - RING_QUEUE_ADVANCE_INDEX(rq, wi, m); - cdata += m; - enqueued += m; - n -= m; - } - return enqueued; -} - -EXPORT_SYMBOL(RingQueue_Enqueue); - -static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq) -{ - assert(rq != NULL); - interruptible_sleep_on(&rq->wqh); -} - -void RingQueue_WakeUpInterruptible(struct RingQueue *rq) -{ - assert(rq != NULL); - if (waitqueue_active(&rq->wqh)) - wake_up_interruptible(&rq->wqh); -} - -EXPORT_SYMBOL(RingQueue_WakeUpInterruptible); - -void RingQueue_Flush(struct RingQueue *rq) -{ - assert(rq != NULL); - rq->ri = 0; - rq->wi = 0; -} - -EXPORT_SYMBOL(RingQueue_Flush); - - -/* - * usbvideo_VideosizeToString() - * - * This procedure converts given videosize value to readable string. - * - * History: - * 07-Aug-2000 Created. - * 19-Oct-2000 Reworked for usbvideo module. - */ -static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs) -{ - char tmp[40]; - int n; - - n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs)); - assert(n < sizeof(tmp)); - if ((buf == NULL) || (bufLen < n)) - err("usbvideo_VideosizeToString: buffer is too small."); - else - memmove(buf, tmp, n); -} - -/* - * usbvideo_OverlayChar() - * - * History: - * 01-Feb-2000 Created. - */ -static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame, - int x, int y, int ch) -{ - static const unsigned short digits[16] = { - 0xF6DE, /* 0 */ - 0x2492, /* 1 */ - 0xE7CE, /* 2 */ - 0xE79E, /* 3 */ - 0xB792, /* 4 */ - 0xF39E, /* 5 */ - 0xF3DE, /* 6 */ - 0xF492, /* 7 */ - 0xF7DE, /* 8 */ - 0xF79E, /* 9 */ - 0x77DA, /* a */ - 0xD75C, /* b */ - 0xF24E, /* c */ - 0xD6DC, /* d */ - 0xF34E, /* e */ - 0xF348 /* f */ - }; - unsigned short digit; - int ix, iy; - int value; - - if ((uvd == NULL) || (frame == NULL)) - return; - - value = hex_to_bin(ch); - if (value < 0) - return; - digit = digits[value]; - - for (iy=0; iy < 5; iy++) { - for (ix=0; ix < 3; ix++) { - if (digit & 0x8000) { - if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) { -/* TODO */ RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF); - } - } - digit = digit << 1; - } - } -} - -/* - * usbvideo_OverlayString() - * - * History: - * 01-Feb-2000 Created. - */ -static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame, - int x, int y, const char *str) -{ - while (*str) { - usbvideo_OverlayChar(uvd, frame, x, y, *str); - str++; - x += 4; /* 3 pixels character + 1 space */ - } -} - -/* - * usbvideo_OverlayStats() - * - * Overlays important debugging information. - * - * History: - * 01-Feb-2000 Created. - */ -static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame) -{ - const int y_diff = 8; - char tmp[16]; - int x = 10, y=10; - long i, j, barLength; - const int qi_x1 = 60, qi_y1 = 10; - const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10; - - /* Call the user callback, see if we may proceed after that */ - if (VALID_CALLBACK(uvd, overlayHook)) { - if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0) - return; - } - - /* - * We draw a (mostly) hollow rectangle with qi_xxx coordinates. - * Left edge symbolizes the queue index 0; right edge symbolizes - * the full capacity of the queue. - */ - barLength = qi_x2 - qi_x1 - 2; - if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) { -/* TODO */ long u_lo, u_hi, q_used; - long m_ri, m_wi, m_lo, m_hi; - - /* - * Determine fill zones (used areas of the queue): - * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length - * - * if u_lo < 0 then there is no first filler. - */ - - q_used = RingQueue_GetLength(&uvd->dp); - if ((uvd->dp.ri + q_used) >= uvd->dp.length) { - u_hi = uvd->dp.length; - u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1); - } else { - u_hi = (q_used + uvd->dp.ri); - u_lo = -1; - } - - /* Convert byte indices into screen units */ - m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length); - m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length); - m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1; - m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length); - - for (j=qi_y1; j < (qi_y1 + qi_h); j++) { - for (i=qi_x1; i < qi_x2; i++) { - /* Draw border lines */ - if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) || - (i == qi_x1) || (i == (qi_x2 - 1))) { - RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF); - continue; - } - /* For all other points the Y coordinate does not matter */ - if ((i >= m_ri) && (i <= (m_ri + 3))) { - RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00); - } else if ((i >= m_wi) && (i <= (m_wi + 3))) { - RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00); - } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi))) - RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF); - } - } - } - - sprintf(tmp, "%8lx", uvd->stats.frame_num); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.urb_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.urb_length); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.data_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.header_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.iso_skip_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8lx", uvd->stats.iso_err_count); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.colour); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.hue); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.brightness >> 8); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8x", uvd->vpic.contrast >> 12); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; - - sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8); - usbvideo_OverlayString(uvd, frame, x, y, tmp); - y += y_diff; -} - -/* - * usbvideo_ReportStatistics() - * - * This procedure prints packet and transfer statistics. - * - * History: - * 14-Jan-2000 Corrected default multiplier. - */ -static void usbvideo_ReportStatistics(const struct uvd *uvd) -{ - if ((uvd != NULL) && (uvd->stats.urb_count > 0)) { - unsigned long allPackets, badPackets, goodPackets, percent; - allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES; - badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count; - goodPackets = allPackets - badPackets; - /* Calculate percentage wisely, remember integer limits */ - assert(allPackets != 0); - if (goodPackets < (((unsigned long)-1)/100)) - percent = (100 * goodPackets) / allPackets; - else - percent = goodPackets / (allPackets / 100); - dev_info(&uvd->dev->dev, - "Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%\n", - allPackets, badPackets, percent); - if (uvd->iso_packet_len > 0) { - unsigned long allBytes, xferBytes; - char multiplier = ' '; - allBytes = allPackets * uvd->iso_packet_len; - xferBytes = uvd->stats.data_count; - assert(allBytes != 0); - if (xferBytes < (((unsigned long)-1)/100)) - percent = (100 * xferBytes) / allBytes; - else - percent = xferBytes / (allBytes / 100); - /* Scale xferBytes for easy reading */ - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'K'; - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'M'; - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'G'; - if (xferBytes > 10*1024) { - xferBytes /= 1024; - multiplier = 'T'; - } - } - } - } - dev_info(&uvd->dev->dev, - "Transfer Statistics: Transferred=%lu%cB Usage=%lu%%\n", - xferBytes, multiplier, percent); - } - } -} - -/* - * usbvideo_TestPattern() - * - * Procedure forms a test pattern (yellow grid on blue background). - * - * Parameters: - * fullframe: if TRUE then entire frame is filled, otherwise the procedure - * continues from the current scanline. - * pmode 0: fill the frame with solid blue color (like on VCR or TV) - * 1: Draw a colored grid - * - * History: - * 01-Feb-2000 Created. - */ -void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode) -{ - struct usbvideo_frame *frame; - int num_cell = 0; - int scan_length = 0; - static int num_pass; - - if (uvd == NULL) { - err("%s: uvd == NULL", __func__); - return; - } - if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) { - err("%s: uvd->curframe=%d.", __func__, uvd->curframe); - return; - } - - /* Grab the current frame */ - frame = &uvd->frame[uvd->curframe]; - - /* Optionally start at the beginning */ - if (fullframe) { - frame->curline = 0; - frame->seqRead_Length = 0; - } -#if 0 - { /* For debugging purposes only */ - char tmp[20]; - usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request); - dev_info(&uvd->dev->dev, "testpattern: frame=%s\n", tmp); - } -#endif - /* Form every scan line */ - for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) { - int i; - unsigned char *f = frame->data + - (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline); - for (i=0; i < VIDEOSIZE_X(frame->request); i++) { - unsigned char cb=0x80; - unsigned char cg = 0; - unsigned char cr = 0; - - if (pmode == 1) { - if (frame->curline % 32 == 0) - cb = 0, cg = cr = 0xFF; - else if (i % 32 == 0) { - if (frame->curline % 32 == 1) - num_cell++; - cb = 0, cg = cr = 0xFF; - } else { - cb = ((num_cell*7) + num_pass) & 0xFF; - cg = ((num_cell*5) + num_pass*2) & 0xFF; - cr = ((num_cell*3) + num_pass*3) & 0xFF; - } - } else { - /* Just the blue screen */ - } - - *f++ = cb; - *f++ = cg; - *f++ = cr; - scan_length += 3; - } - } - - frame->frameState = FrameState_Done; - frame->seqRead_Length += scan_length; - ++num_pass; - - /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */ - usbvideo_OverlayStats(uvd, frame); -} - -EXPORT_SYMBOL(usbvideo_TestPattern); - - -#ifdef DEBUG -/* - * usbvideo_HexDump() - * - * A debugging tool. Prints hex dumps. - * - * History: - * 29-Jul-2000 Added printing of offsets. - */ -void usbvideo_HexDump(const unsigned char *data, int len) -{ - const int bytes_per_line = 32; - char tmp[128]; /* 32*3 + 5 */ - int i, k; - - for (i=k=0; len > 0; i++, len--) { - if (i > 0 && ((i % bytes_per_line) == 0)) { - printk("%s\n", tmp); - k=0; - } - if ((i % bytes_per_line) == 0) - k += sprintf(&tmp[k], "%04x: ", i); - k += sprintf(&tmp[k], "%02x ", data[i]); - } - if (k > 0) - printk("%s\n", tmp); -} - -EXPORT_SYMBOL(usbvideo_HexDump); - -#endif - -/* ******************************************************************** */ - -/* XXX: this piece of crap really wants some error handling.. */ -static int usbvideo_ClientIncModCount(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: uvd == NULL", __func__); - return -EINVAL; - } - if (uvd->handle == NULL) { - err("%s: uvd->handle == NULL", __func__); - return -EINVAL; - } - if (!try_module_get(uvd->handle->md_module)) { - err("%s: try_module_get() == 0", __func__); - return -ENODEV; - } - return 0; -} - -static void usbvideo_ClientDecModCount(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: uvd == NULL", __func__); - return; - } - if (uvd->handle == NULL) { - err("%s: uvd->handle == NULL", __func__); - return; - } - if (uvd->handle->md_module == NULL) { - err("%s: uvd->handle->md_module == NULL", __func__); - return; - } - module_put(uvd->handle->md_module); -} - -int usbvideo_register( - struct usbvideo **pCams, - const int num_cams, - const int num_extra, - const char *driverName, - const struct usbvideo_cb *cbTbl, - struct module *md, - const struct usb_device_id *id_table) -{ - struct usbvideo *cams; - int i, base_size, result; - - /* Check parameters for sanity */ - if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) { - err("%s: Illegal call", __func__); - return -EINVAL; - } - - /* Check registration callback - must be set! */ - if (cbTbl->probe == NULL) { - err("%s: probe() is required!", __func__); - return -EINVAL; - } - - base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo); - cams = kzalloc(base_size, GFP_KERNEL); - if (cams == NULL) { - err("Failed to allocate %d. bytes for usbvideo struct", base_size); - return -ENOMEM; - } - dbg("%s: Allocated $%p (%d. bytes) for %d. cameras", - __func__, cams, base_size, num_cams); - - /* Copy callbacks, apply defaults for those that are not set */ - memmove(&cams->cb, cbTbl, sizeof(cams->cb)); - if (cams->cb.getFrame == NULL) - cams->cb.getFrame = usbvideo_GetFrame; - if (cams->cb.disconnect == NULL) - cams->cb.disconnect = usbvideo_Disconnect; - if (cams->cb.startDataPump == NULL) - cams->cb.startDataPump = usbvideo_StartDataPump; - if (cams->cb.stopDataPump == NULL) - cams->cb.stopDataPump = usbvideo_StopDataPump; - - cams->num_cameras = num_cams; - cams->cam = (struct uvd *) &cams[1]; - cams->md_module = md; - mutex_init(&cams->lock); /* to 1 == available */ - - for (i = 0; i < num_cams; i++) { - struct uvd *up = &cams->cam[i]; - - up->handle = cams; - - /* Allocate user_data separately because of kmalloc's limits */ - if (num_extra > 0) { - up->user_size = num_cams * num_extra; - up->user_data = kmalloc(up->user_size, GFP_KERNEL); - if (up->user_data == NULL) { - err("%s: Failed to allocate user_data (%d. bytes)", - __func__, up->user_size); - while (i) { - up = &cams->cam[--i]; - kfree(up->user_data); - } - kfree(cams); - return -ENOMEM; - } - dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)", - __func__, i, up->user_data, up->user_size); - } - } - - /* - * Register ourselves with USB stack. - */ - strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown"); - cams->usbdrv.name = cams->drvName; - cams->usbdrv.probe = cams->cb.probe; - cams->usbdrv.disconnect = cams->cb.disconnect; - cams->usbdrv.id_table = id_table; - - /* - * Update global handle to usbvideo. This is very important - * because probe() can be called before usb_register() returns. - * If the handle is not yet updated then the probe() will fail. - */ - *pCams = cams; - result = usb_register(&cams->usbdrv); - if (result) { - for (i = 0; i < num_cams; i++) { - struct uvd *up = &cams->cam[i]; - kfree(up->user_data); - } - kfree(cams); - } - - return result; -} - -EXPORT_SYMBOL(usbvideo_register); - -/* - * usbvideo_Deregister() - * - * Procedure frees all usbvideo and user data structures. Be warned that - * if you had some dynamically allocated components in ->user field then - * you should free them before calling here. - */ -void usbvideo_Deregister(struct usbvideo **pCams) -{ - struct usbvideo *cams; - int i; - - if (pCams == NULL) { - err("%s: pCams == NULL", __func__); - return; - } - cams = *pCams; - if (cams == NULL) { - err("%s: cams == NULL", __func__); - return; - } - - dbg("%s: Deregistering %s driver.", __func__, cams->drvName); - usb_deregister(&cams->usbdrv); - - dbg("%s: Deallocating cams=$%p (%d. cameras)", __func__, cams, cams->num_cameras); - for (i=0; i < cams->num_cameras; i++) { - struct uvd *up = &cams->cam[i]; - int warning = 0; - - if (up->user_data != NULL) { - if (up->user_size <= 0) - ++warning; - } else { - if (up->user_size > 0) - ++warning; - } - if (warning) { - err("%s: Warning: user_data=$%p user_size=%d.", - __func__, up->user_data, up->user_size); - } else { - dbg("%s: Freeing %d. $%p->user_data=$%p", - __func__, i, up, up->user_data); - kfree(up->user_data); - } - } - /* Whole array was allocated in one chunk */ - dbg("%s: Freed %d uvd structures", - __func__, cams->num_cameras); - kfree(cams); - *pCams = NULL; -} - -EXPORT_SYMBOL(usbvideo_Deregister); - -/* - * usbvideo_Disconnect() - * - * This procedure stops all driver activity. Deallocation of - * the interface-private structure (pointed by 'ptr') is done now - * (if we don't have any open files) or later, when those files - * are closed. After that driver should be removable. - * - * This code handles surprise removal. The uvd->user is a counter which - * increments on open() and decrements on close(). If we see here that - * this counter is not 0 then we have a client who still has us opened. - * We set uvd->remove_pending flag as early as possible, and after that - * all access to the camera will gracefully fail. These failures should - * prompt client to (eventually) close the video device, and then - in - * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter. - * - * History: - * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone. - * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close() - * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - * 19-Oct-2000 Moved to usbvideo module. - */ -static void usbvideo_Disconnect(struct usb_interface *intf) -{ - struct uvd *uvd = usb_get_intfdata (intf); - int i; - - if (uvd == NULL) { - err("%s($%p): Illegal call.", __func__, intf); - return; - } - - usb_set_intfdata (intf, NULL); - - usbvideo_ClientIncModCount(uvd); - if (uvd->debug > 0) - dev_info(&intf->dev, "%s(%p.)\n", __func__, intf); - - mutex_lock(&uvd->lock); - uvd->remove_pending = 1; /* Now all ISO data will be ignored */ - - /* At this time we ask to cancel outstanding URBs */ - GET_CALLBACK(uvd, stopDataPump)(uvd); - - for (i=0; i < USBVIDEO_NUMSBUF; i++) - usb_free_urb(uvd->sbuf[i].urb); - - usb_put_dev(uvd->dev); - uvd->dev = NULL; /* USB device is no more */ - - video_unregister_device(&uvd->vdev); - if (uvd->debug > 0) - dev_info(&intf->dev, "%s: Video unregistered.\n", __func__); - - if (uvd->user) - dev_info(&intf->dev, "%s: In use, disconnect pending.\n", - __func__); - else - usbvideo_CameraRelease(uvd); - mutex_unlock(&uvd->lock); - dev_info(&intf->dev, "USB camera disconnected.\n"); - - usbvideo_ClientDecModCount(uvd); -} - -/* - * usbvideo_CameraRelease() - * - * This code does final release of uvd. This happens - * after the device is disconnected -and- all clients - * closed their files. - * - * History: - * 27-Jan-2000 Created. - */ -static void usbvideo_CameraRelease(struct uvd *uvd) -{ - if (uvd == NULL) { - err("%s: Illegal call", __func__); - return; - } - - RingQueue_Free(&uvd->dp); - if (VALID_CALLBACK(uvd, userFree)) - GET_CALLBACK(uvd, userFree)(uvd); - uvd->uvd_used = 0; /* This is atomic, no need to take mutex */ -} - -/* - * usbvideo_find_struct() - * - * This code searches the array of preallocated (static) structures - * and returns index of the first one that isn't in use. Returns -1 - * if there are no free structures. - * - * History: - * 27-Jan-2000 Created. - */ -static int usbvideo_find_struct(struct usbvideo *cams) -{ - int u, rv = -1; - - if (cams == NULL) { - err("No usbvideo handle?"); - return -1; - } - mutex_lock(&cams->lock); - for (u = 0; u < cams->num_cameras; u++) { - struct uvd *uvd = &cams->cam[u]; - if (!uvd->uvd_used) /* This one is free */ - { - uvd->uvd_used = 1; /* In use now */ - mutex_init(&uvd->lock); /* to 1 == available */ - uvd->dev = NULL; - rv = u; - break; - } - } - mutex_unlock(&cams->lock); - return rv; -} - -static const struct v4l2_file_operations usbvideo_fops = { - .owner = THIS_MODULE, - .open = usbvideo_v4l_open, - .release =usbvideo_v4l_close, - .read = usbvideo_v4l_read, - .mmap = usbvideo_v4l_mmap, - .ioctl = usbvideo_v4l_ioctl, -}; -static const struct video_device usbvideo_template = { - .fops = &usbvideo_fops, -}; - -struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams) -{ - int i, devnum; - struct uvd *uvd = NULL; - - if (cams == NULL) { - err("No usbvideo handle?"); - return NULL; - } - - devnum = usbvideo_find_struct(cams); - if (devnum == -1) { - err("IBM USB camera driver: Too many devices!"); - return NULL; - } - uvd = &cams->cam[devnum]; - dbg("Device entry #%d. at $%p", devnum, uvd); - - /* Not relying upon caller we increase module counter ourselves */ - usbvideo_ClientIncModCount(uvd); - - mutex_lock(&uvd->lock); - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); - if (uvd->sbuf[i].urb == NULL) { - err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC); - uvd->uvd_used = 0; - uvd = NULL; - goto allocate_done; - } - } - uvd->user=0; - uvd->remove_pending = 0; - uvd->last_error = 0; - RingQueue_Initialize(&uvd->dp); - - /* Initialize video device structure */ - uvd->vdev = usbvideo_template; - sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName); - /* - * The client is free to overwrite those because we - * return control to the client's probe function right now. - */ -allocate_done: - mutex_unlock(&uvd->lock); - usbvideo_ClientDecModCount(uvd); - return uvd; -} - -EXPORT_SYMBOL(usbvideo_AllocateDevice); - -int usbvideo_RegisterVideoDevice(struct uvd *uvd) -{ - char tmp1[20], tmp2[20]; /* Buffers for printing */ - - if (uvd == NULL) { - err("%s: Illegal call.", __func__); - return -EINVAL; - } - if (uvd->video_endp == 0) { - dev_info(&uvd->dev->dev, - "%s: No video endpoint specified; data pump disabled.\n", - __func__); - } - if (uvd->paletteBits == 0) { - err("%s: No palettes specified!", __func__); - return -EINVAL; - } - if (uvd->defaultPalette == 0) { - dev_info(&uvd->dev->dev, "%s: No default palette!\n", - __func__); - } - - uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) * - VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL; - usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize); - usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas); - - if (uvd->debug > 0) { - dev_info(&uvd->dev->dev, - "%s: iface=%d. endpoint=$%02x paletteBits=$%08lx\n", - __func__, uvd->iface, uvd->video_endp, - uvd->paletteBits); - } - if (uvd->dev == NULL) { - err("%s: uvd->dev == NULL", __func__); - return -EINVAL; - } - uvd->vdev.parent = &uvd->dev->dev; - uvd->vdev.release = video_device_release_empty; - if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { - err("%s: video_register_device failed", __func__); - return -EPIPE; - } - if (uvd->debug > 1) { - dev_info(&uvd->dev->dev, - "%s: video_register_device() successful\n", __func__); - } - - dev_info(&uvd->dev->dev, "%s on %s: canvas=%s videosize=%s\n", - (uvd->handle != NULL) ? uvd->handle->drvName : "???", - video_device_node_name(&uvd->vdev), tmp2, tmp1); - - usb_get_dev(uvd->dev); - return 0; -} - -EXPORT_SYMBOL(usbvideo_RegisterVideoDevice); - -/* ******************************************************************** */ - -static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct uvd *uvd = file->private_data; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - - if (!CAMERA_IS_OPERATIONAL(uvd)) - return -EFAULT; - - if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) - return -EINVAL; - - pos = (unsigned long) uvd->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return 0; -} - -/* - * usbvideo_v4l_open() - * - * This is part of Video 4 Linux API. The driver can be opened by one - * client only (checks internal counter 'uvdser'). The procedure - * then allocates buffers needed for video processing. - * - * History: - * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the - * camera is also initialized here (once per connect), at - * expense of V4L client (it waits on open() call). - * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. - * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT). - */ -static int usbvideo_v4l_open(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct uvd *uvd = (struct uvd *) dev; - const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len; - int i, errCode = 0; - - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev); - - if (usbvideo_ClientIncModCount(uvd) < 0) - return -ENODEV; - mutex_lock(&uvd->lock); - - if (uvd->user) { - err("%s: Someone tried to open an already opened device!", __func__); - errCode = -EBUSY; - } else { - /* Clear statistics */ - memset(&uvd->stats, 0, sizeof(uvd->stats)); - - /* Clean pointers so we know if we allocated something */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) - uvd->sbuf[i].data = NULL; - - /* Allocate memory for the frame buffers */ - uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size; - uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size); - RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE); - if ((uvd->fbuf == NULL) || - (!RingQueue_IsAllocated(&uvd->dp))) { - err("%s: Failed to allocate fbuf or dp", __func__); - errCode = -ENOMEM; - } else { - /* Allocate all buffers */ - for (i=0; i < USBVIDEO_NUMFRAMES; i++) { - uvd->frame[i].frameState = FrameState_Unused; - uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size); - /* - * Set default sizes in case IOCTL (VIDIOCMCAPTURE) - * is not used (using read() instead). - */ - uvd->frame[i].canvas = uvd->canvas; - uvd->frame[i].seqRead_Index = 0; - } - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL); - if (uvd->sbuf[i].data == NULL) { - errCode = -ENOMEM; - break; - } - } - } - if (errCode != 0) { - /* Have to free all that memory */ - if (uvd->fbuf != NULL) { - usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); - uvd->fbuf = NULL; - } - RingQueue_Free(&uvd->dp); - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - kfree(uvd->sbuf[i].data); - uvd->sbuf[i].data = NULL; - } - } - } - - /* If so far no errors then we shall start the camera */ - if (errCode == 0) { - /* Start data pump if we have valid endpoint */ - if (uvd->video_endp != 0) - errCode = GET_CALLBACK(uvd, startDataPump)(uvd); - if (errCode == 0) { - if (VALID_CALLBACK(uvd, setupOnOpen)) { - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, - "%s: setupOnOpen callback\n", - __func__); - errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd); - if (errCode < 0) { - err("%s: setupOnOpen callback failed (%d.).", - __func__, errCode); - } else if (uvd->debug > 1) { - dev_info(&uvd->dev->dev, - "%s: setupOnOpen callback successful\n", - __func__); - } - } - if (errCode == 0) { - uvd->settingsAdjusted = 0; - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, - "%s: Open succeeded.\n", - __func__); - uvd->user++; - file->private_data = uvd; - } - } - } - mutex_unlock(&uvd->lock); - if (errCode != 0) - usbvideo_ClientDecModCount(uvd); - if (uvd->debug > 0) - dev_info(&uvd->dev->dev, "%s: Returning %d.\n", __func__, - errCode); - return errCode; -} - -/* - * usbvideo_v4l_close() - * - * This is part of Video 4 Linux API. The procedure - * stops streaming and deallocates all buffers that were earlier - * allocated in usbvideo_v4l_open(). - * - * History: - * 22-Jan-2000 Moved scratch buffer deallocation here. - * 27-Jan-2000 Used USBVIDEO_NUMSBUF as number of URB buffers. - * 24-May-2000 Moved MOD_DEC_USE_COUNT outside of code that can sleep. - */ -static int usbvideo_v4l_close(struct file *file) -{ - struct video_device *dev = file->private_data; - struct uvd *uvd = (struct uvd *) dev; - int i; - - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev); - - mutex_lock(&uvd->lock); - GET_CALLBACK(uvd, stopDataPump)(uvd); - usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size); - uvd->fbuf = NULL; - RingQueue_Free(&uvd->dp); - - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - kfree(uvd->sbuf[i].data); - uvd->sbuf[i].data = NULL; - } - -#if USBVIDEO_REPORT_STATS - usbvideo_ReportStatistics(uvd); -#endif - - uvd->user--; - if (uvd->remove_pending) { - if (uvd->debug > 0) - dev_info(&uvd->dev->dev, "%s: Final disconnect.\n", - __func__); - usbvideo_CameraRelease(uvd); - } - mutex_unlock(&uvd->lock); - usbvideo_ClientDecModCount(uvd); - - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, "%s: Completed.\n", __func__); - file->private_data = NULL; - return 0; -} - -/* - * usbvideo_v4l_ioctl() - * - * This is part of Video 4 Linux API. The procedure handles ioctl() calls. - * - * History: - * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings. - */ -static long usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg) -{ - struct uvd *uvd = file->private_data; - - if (!CAMERA_IS_OPERATIONAL(uvd)) - return -EIO; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - *b = uvd->vcap; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - *v = uvd->vchan; - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGPICT: - { - struct video_picture *pic = arg; - *pic = uvd->vpic; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *pic = arg; - /* - * Use temporary 'video_picture' structure to preserve our - * own settings (such as color depth, palette) that we - * aren't allowing everyone (V4L client) to change. - */ - uvd->vpic.brightness = pic->brightness; - uvd->vpic.hue = pic->hue; - uvd->vpic.colour = pic->colour; - uvd->vpic.contrast = pic->contrast; - uvd->settingsAdjusted = 0; /* Will force new settings */ - return 0; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - - if(VALID_CALLBACK(uvd, setVideoMode)) { - return GET_CALLBACK(uvd, setVideoMode)(uvd, vw); - } - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (vw->width != VIDEOSIZE_X(uvd->canvas)) - return -EINVAL; - if (vw->height != VIDEOSIZE_Y(uvd->canvas)) - return -EINVAL; - - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; - vw->y = 0; - vw->width = VIDEOSIZE_X(uvd->videosize); - vw->height = VIDEOSIZE_Y(uvd->videosize); - vw->chromakey = 0; - if (VALID_CALLBACK(uvd, getFPS)) - vw->flags = GET_CALLBACK(uvd, getFPS)(uvd); - else - vw->flags = 10; /* FIXME: do better! */ - return 0; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - int i; - - memset(vm, 0, sizeof(*vm)); - vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES; - vm->frames = USBVIDEO_NUMFRAMES; - for(i = 0; i < USBVIDEO_NUMFRAMES; i++) - vm->offsets[i] = i * uvd->max_frame_size; - - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - - if (uvd->debug >= 1) { - dev_info(&uvd->dev->dev, - "VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.\n", - vm->frame, vm->width, vm->height, vm->format); - } - /* - * Check if the requested size is supported. If the requestor - * requests too big a frame then we may be tricked into accessing - * outside of own preallocated frame buffer (in uvd->frame). - * This will cause oops or a security hole. Theoretically, we - * could only clamp the size down to acceptable bounds, but then - * we'd need to figure out how to insert our smaller buffer into - * larger caller's buffer... this is not an easy question. So we - * here just flatly reject too large requests, assuming that the - * caller will resubmit with smaller size. Callers should know - * what size we support (returned by VIDIOCGCAP). However vidcat, - * for one, does not care and allows to ask for any size. - */ - if ((vm->width > VIDEOSIZE_X(uvd->canvas)) || - (vm->height > VIDEOSIZE_Y(uvd->canvas))) { - if (uvd->debug > 0) { - dev_info(&uvd->dev->dev, - "VIDIOCMCAPTURE: Size=%dx%d " - "too large; allowed only up " - "to %ldx%ld\n", vm->width, - vm->height, - VIDEOSIZE_X(uvd->canvas), - VIDEOSIZE_Y(uvd->canvas)); - } - return -EINVAL; - } - /* Check if the palette is supported */ - if (((1L << vm->format) & uvd->paletteBits) == 0) { - if (uvd->debug > 0) { - dev_info(&uvd->dev->dev, - "VIDIOCMCAPTURE: format=%d. " - "not supported " - "(paletteBits=$%08lx)\n", - vm->format, uvd->paletteBits); - } - return -EINVAL; - } - if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) { - err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1); - return -EINVAL; - } - if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) { - /* Not an error - can happen */ - } - uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height); - uvd->frame[vm->frame].palette = vm->format; - - /* Mark it as ready */ - uvd->frame[vm->frame].frameState = FrameState_Ready; - - return usbvideo_NewFrame(uvd, vm->frame); - } - case VIDIOCSYNC: - { - int *frameNum = arg; - int ret; - - if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES) - return -EINVAL; - - if (uvd->debug >= 1) - dev_info(&uvd->dev->dev, - "VIDIOCSYNC: syncing to frame %d.\n", - *frameNum); - if (uvd->flags & FLAGS_NO_DECODING) - ret = usbvideo_GetFrame(uvd, *frameNum); - else if (VALID_CALLBACK(uvd, getFrame)) { - ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum); - if ((ret < 0) && (uvd->debug >= 1)) { - err("VIDIOCSYNC: getFrame() returned %d.", ret); - } - } else { - err("VIDIOCSYNC: getFrame is not set"); - ret = -EFAULT; - } - - /* - * The frame is in FrameState_Done_Hold state. Release it - * right now because its data is already mapped into - * the user space and it's up to the application to - * make use of it until it asks for another frame. - */ - uvd->frame[*frameNum].frameState = FrameState_Unused; - return ret; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - memset(vb, 0, sizeof(*vb)); - return 0; - } - case VIDIOCKEY: - return 0; - - case VIDIOCCAPTURE: - return -EINVAL; - - case VIDIOCSFBUF: - - case VIDIOCGTUNER: - case VIDIOCSTUNER: - - case VIDIOCGFREQ: - case VIDIOCSFREQ: - - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static long usbvideo_v4l_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(file, cmd, arg, usbvideo_v4l_do_ioctl); -} - -/* - * usbvideo_v4l_read() - * - * This is mostly boring stuff. We simply ask for a frame and when it - * arrives copy all the video data from it into user space. There is - * no obvious need to override this method. - * - * History: - * 20-Oct-2000 Created. - * 01-Nov-2000 Added mutex (uvd->lock). - */ -static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct uvd *uvd = file->private_data; - int noblock = file->f_flags & O_NONBLOCK; - int frmx = -1, i; - struct usbvideo_frame *frame; - - if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL)) - return -EFAULT; - - if (uvd->debug >= 1) - dev_info(&uvd->dev->dev, - "%s: %Zd. bytes, noblock=%d.\n", - __func__, count, noblock); - - mutex_lock(&uvd->lock); - - /* See if a frame is completed, then use it. */ - for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { - if ((uvd->frame[i].frameState == FrameState_Done) || - (uvd->frame[i].frameState == FrameState_Done_Hold) || - (uvd->frame[i].frameState == FrameState_Error)) { - frmx = i; - break; - } - } - - /* FIXME: If we don't start a frame here then who ever does? */ - if (noblock && (frmx == -1)) { - count = -EAGAIN; - goto read_done; - } - - /* - * If no FrameState_Done, look for a FrameState_Grabbing state. - * See if a frame is in process (grabbing), then use it. - * We will need to wait until it becomes cooked, of course. - */ - if (frmx == -1) { - for(i = 0; i < USBVIDEO_NUMFRAMES; i++) { - if (uvd->frame[i].frameState == FrameState_Grabbing) { - frmx = i; - break; - } - } - } - - /* - * If no frame is active, start one. We don't care which one - * it will be, so #0 is as good as any. - * In read access mode we don't have convenience of VIDIOCMCAPTURE - * to specify the requested palette (video format) on per-frame - * basis. This means that we have to return data in -some- format - * and just hope that the client knows what to do with it. - * The default format is configured in uvd->defaultPalette field - * as one of VIDEO_PALETTE_xxx values. We stuff it into the new - * frame and initiate the frame filling process. - */ - if (frmx == -1) { - if (uvd->defaultPalette == 0) { - err("%s: No default palette; don't know what to do!", __func__); - count = -EFAULT; - goto read_done; - } - frmx = 0; - /* - * We have no per-frame control over video size. - * Therefore we only can use whatever size was - * specified as default. - */ - uvd->frame[frmx].request = uvd->videosize; - uvd->frame[frmx].palette = uvd->defaultPalette; - uvd->frame[frmx].frameState = FrameState_Ready; - usbvideo_NewFrame(uvd, frmx); - /* Now frame 0 is supposed to start filling... */ - } - - /* - * Get a pointer to the active frame. It is either previously - * completed frame or frame in progress but not completed yet. - */ - frame = &uvd->frame[frmx]; - - /* - * Sit back & wait until the frame gets filled and postprocessed. - * If we fail to get the picture [in time] then return the error. - * In this call we specify that we want the frame to be waited for, - * postprocessed and switched into FrameState_Done_Hold state. This - * state is used to hold the frame as "fully completed" between - * subsequent partial reads of the same frame. - */ - if (frame->frameState != FrameState_Done_Hold) { - long rv = -EFAULT; - if (uvd->flags & FLAGS_NO_DECODING) - rv = usbvideo_GetFrame(uvd, frmx); - else if (VALID_CALLBACK(uvd, getFrame)) - rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx); - else - err("getFrame is not set"); - if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) { - count = rv; - goto read_done; - } - } - - /* - * Copy bytes to user space. We allow for partial reads, which - * means that the user application can request read less than - * the full frame size. It is up to the application to issue - * subsequent calls until entire frame is read. - * - * First things first, make sure we don't copy more than we - * have - even if the application wants more. That would be - * a big security embarassment! - */ - if ((count + frame->seqRead_Index) > frame->seqRead_Length) - count = frame->seqRead_Length - frame->seqRead_Index; - - /* - * Copy requested amount of data to user space. We start - * copying from the position where we last left it, which - * will be zero for a new frame (not read before). - */ - if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) { - count = -EFAULT; - goto read_done; - } - - /* Update last read position */ - frame->seqRead_Index += count; - if (uvd->debug >= 1) { - err("%s: {copy} count used=%Zd, new seqRead_Index=%ld", - __func__, count, frame->seqRead_Index); - } - - /* Finally check if the frame is done with and "release" it */ - if (frame->seqRead_Index >= frame->seqRead_Length) { - /* All data has been read */ - frame->seqRead_Index = 0; - - /* Mark it as available to be used again. */ - uvd->frame[frmx].frameState = FrameState_Unused; - if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) { - err("%s: usbvideo_NewFrame failed.", __func__); - } - } -read_done: - mutex_unlock(&uvd->lock); - return count; -} - -/* - * Make all of the blocks of data contiguous - */ -static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb) -{ - char *cdata; - int i, totlen = 0; - - for (i = 0; i < urb->number_of_packets; i++) { - int n = urb->iso_frame_desc[i].actual_length; - int st = urb->iso_frame_desc[i].status; - - cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - /* Detect and ignore errored packets */ - if (st < 0) { - if (uvd->debug >= 1) - err("Data error: packet=%d. len=%d. status=%d.", i, n, st); - uvd->stats.iso_err_count++; - continue; - } - - /* Detect and ignore empty packets */ - if (n <= 0) { - uvd->stats.iso_skip_count++; - continue; - } - totlen += n; /* Little local accounting */ - RingQueue_Enqueue(&uvd->dp, cdata, n); - } - return totlen; -} - -static void usbvideo_IsocIrq(struct urb *urb) -{ - int i, ret, len; - struct uvd *uvd = urb->context; - - /* We don't want to do anything if we are about to be removed! */ - if (!CAMERA_IS_OPERATIONAL(uvd)) - return; -#if 0 - if (urb->actual_length > 0) { - dev_info(&uvd->dev->dev, - "urb=$%p status=%d. errcount=%d. length=%d.\n", - urb, urb->status, urb->error_count, - urb->actual_length); - } else { - static int c = 0; - if (c++ % 100 == 0) - dev_info(&uvd->dev->dev, "No Isoc data\n"); - } -#endif - - if (!uvd->streaming) { - if (uvd->debug >= 1) - dev_info(&uvd->dev->dev, - "Not streaming, but interrupt!\n"); - return; - } - - uvd->stats.urb_count++; - if (urb->actual_length <= 0) - goto urb_done_with; - - /* Copy the data received into ring queue */ - len = usbvideo_CompressIsochronous(uvd, urb); - uvd->stats.urb_length = len; - if (len <= 0) - goto urb_done_with; - - /* Here we got some data */ - uvd->stats.data_count += len; - RingQueue_WakeUpInterruptible(&uvd->dp); - -urb_done_with: - for (i = 0; i < FRAMES_PER_DESC; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - urb->dev = uvd->dev; - ret = usb_submit_urb (urb, GFP_KERNEL); - if(ret) - err("usb_submit_urb error (%d)", ret); - return; -} - -/* - * usbvideo_StartDataPump() - * - * History: - * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead - * of hardcoded values. Simplified by using for loop, - * allowed any number of URBs. - */ -static int usbvideo_StartDataPump(struct uvd *uvd) -{ - struct usb_device *dev = uvd->dev; - int i, errFlag; - - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd); - - if (!CAMERA_IS_OPERATIONAL(uvd)) { - err("%s: Camera is not operational", __func__); - return -EFAULT; - } - uvd->curframe = -1; - - /* Alternate interface 1 is is the biggest frame size */ - i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive); - if (i < 0) { - err("%s: usb_set_interface error", __func__); - uvd->last_error = i; - return -EBUSY; - } - if (VALID_CALLBACK(uvd, videoStart)) - GET_CALLBACK(uvd, videoStart)(uvd); - else - err("%s: videoStart not set", __func__); - - /* We double buffer the Iso lists */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - int j, k; - struct urb *urb = uvd->sbuf[i].urb; - urb->dev = dev; - urb->context = uvd; - urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp); - urb->interval = 1; - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = uvd->sbuf[i].data; - urb->complete = usbvideo_IsocIrq; - urb->number_of_packets = FRAMES_PER_DESC; - urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC; - for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = uvd->iso_packet_len; - } - } - - /* Submit all URBs */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL); - if (errFlag) - err("%s: usb_submit_isoc(%d) ret %d", __func__, i, errFlag); - } - - uvd->streaming = 1; - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, - "%s: streaming=1 video_endp=$%02x\n", __func__, - uvd->video_endp); - return 0; -} - -/* - * usbvideo_StopDataPump() - * - * This procedure stops streaming and deallocates URBs. Then it - * activates zero-bandwidth alt. setting of the video interface. - * - * History: - * 22-Jan-2000 Corrected order of actions to work after surprise removal. - * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values. - */ -static void usbvideo_StopDataPump(struct uvd *uvd) -{ - int i, j; - - if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL)) - return; - - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd); - - /* Unschedule all of the iso td's */ - for (i=0; i < USBVIDEO_NUMSBUF; i++) { - usb_kill_urb(uvd->sbuf[i].urb); - } - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, "%s: streaming=0\n", __func__); - uvd->streaming = 0; - - if (!uvd->remove_pending) { - /* Invoke minidriver's magic to stop the camera */ - if (VALID_CALLBACK(uvd, videoStop)) - GET_CALLBACK(uvd, videoStop)(uvd); - else - err("%s: videoStop not set", __func__); - - /* Set packet size to 0 */ - j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive); - if (j < 0) { - err("%s: usb_set_interface() error %d.", __func__, j); - uvd->last_error = j; - } - } -} - -/* - * usbvideo_NewFrame() - * - * History: - * 29-Mar-00 Added copying of previous frame into the current one. - * 6-Aug-00 Added model 3 video sizes, removed redundant width, height. - */ -static int usbvideo_NewFrame(struct uvd *uvd, int framenum) -{ - struct usbvideo_frame *frame; - int n; - - if (uvd->debug > 1) - dev_info(&uvd->dev->dev, "usbvideo_NewFrame($%p,%d.)\n", uvd, - framenum); - - /* If we're not grabbing a frame right now and the other frame is */ - /* ready to be grabbed into, then use it instead */ - if (uvd->curframe != -1) - return 0; - - /* If necessary we adjust picture settings between frames */ - if (!uvd->settingsAdjusted) { - if (VALID_CALLBACK(uvd, adjustPicture)) - GET_CALLBACK(uvd, adjustPicture)(uvd); - uvd->settingsAdjusted = 1; - } - - n = (framenum + 1) % USBVIDEO_NUMFRAMES; - if (uvd->frame[n].frameState == FrameState_Ready) - framenum = n; - - frame = &uvd->frame[framenum]; - - frame->frameState = FrameState_Grabbing; - frame->scanstate = ScanState_Scanning; - frame->seqRead_Length = 0; /* Accumulated in xxx_parse_data() */ - frame->deinterlace = Deinterlace_None; - frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */ - uvd->curframe = framenum; - - /* - * Normally we would want to copy previous frame into the current one - * before we even start filling it with data; this allows us to stop - * filling at any moment; top portion of the frame will be new and - * bottom portion will stay as it was in previous frame. If we don't - * do that then missing chunks of video stream will result in flickering - * portions of old data whatever it was before. - * - * If we choose not to copy previous frame (to, for example, save few - * bus cycles - the frame can be pretty large!) then we have an option - * to clear the frame before using. If we experience losses in this - * mode then missing picture will be black (no flickering). - * - * Finally, if user chooses not to clean the current frame before - * filling it with data then the old data will be visible if we fail - * to refill entire frame with new data. - */ - if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) { - /* This copies previous frame into this one to mask losses */ - int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES; - memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size); - } else { - if (uvd->flags & FLAGS_CLEAN_FRAMES) { - /* This provides a "clean" frame but slows things down */ - memset(frame->data, 0, uvd->max_frame_size); - } - } - return 0; -} - -/* - * usbvideo_CollectRawData() - * - * This procedure can be used instead of 'processData' callback if you - * only want to dump the raw data from the camera into the output - * device (frame buffer). You can look at it with V4L client, but the - * image will be unwatchable. The main purpose of this code and of the - * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from - * new, unknown cameras. This procedure will be automatically invoked - * instead of the specified callback handler when uvd->flags has bit - * FLAGS_NO_DECODING set. Therefore, any regular build of any driver - * based on usbvideo can use this feature at any time. - */ -static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame) -{ - int n; - - assert(uvd != NULL); - assert(frame != NULL); - - /* Try to move data from queue into frame buffer */ - n = RingQueue_GetLength(&uvd->dp); - if (n > 0) { - int m; - /* See how much space we have left */ - m = uvd->max_frame_size - frame->seqRead_Length; - if (n > m) - n = m; - /* Now move that much data into frame buffer */ - RingQueue_Dequeue( - &uvd->dp, - frame->data + frame->seqRead_Length, - m); - frame->seqRead_Length += m; - } - /* See if we filled the frame */ - if (frame->seqRead_Length >= uvd->max_frame_size) { - frame->frameState = FrameState_Done; - uvd->curframe = -1; - uvd->stats.frame_num++; - } -} - -static int usbvideo_GetFrame(struct uvd *uvd, int frameNum) -{ - struct usbvideo_frame *frame = &uvd->frame[frameNum]; - - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, "%s($%p,%d.)\n", __func__, uvd, - frameNum); - - switch (frame->frameState) { - case FrameState_Unused: - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, "%s: FrameState_Unused\n", - __func__); - return -EINVAL; - case FrameState_Ready: - case FrameState_Grabbing: - case FrameState_Error: - { - int ntries, signalPending; - redo: - if (!CAMERA_IS_OPERATIONAL(uvd)) { - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, - "%s: Camera is not operational (1)\n", - __func__); - return -EIO; - } - ntries = 0; - do { - RingQueue_InterruptibleSleepOn(&uvd->dp); - signalPending = signal_pending(current); - if (!CAMERA_IS_OPERATIONAL(uvd)) { - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, - "%s: Camera is not " - "operational (2)\n", __func__); - return -EIO; - } - assert(uvd->fbuf != NULL); - if (signalPending) { - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, - "%s: Signal=$%08x\n", __func__, - signalPending); - if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) { - usbvideo_TestPattern(uvd, 1, 0); - uvd->curframe = -1; - uvd->stats.frame_num++; - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, - "%s: Forced test " - "pattern screen\n", - __func__); - return 0; - } else { - /* Standard answer: Interrupted! */ - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, - "%s: Interrupted!\n", - __func__); - return -EINTR; - } - } else { - /* No signals - we just got new data in dp queue */ - if (uvd->flags & FLAGS_NO_DECODING) - usbvideo_CollectRawData(uvd, frame); - else if (VALID_CALLBACK(uvd, processData)) - GET_CALLBACK(uvd, processData)(uvd, frame); - else - err("%s: processData not set", __func__); - } - } while (frame->frameState == FrameState_Grabbing); - if (uvd->debug >= 2) { - dev_info(&uvd->dev->dev, - "%s: Grabbing done; state=%d. (%lu. bytes)\n", - __func__, frame->frameState, - frame->seqRead_Length); - } - if (frame->frameState == FrameState_Error) { - int ret = usbvideo_NewFrame(uvd, frameNum); - if (ret < 0) { - err("%s: usbvideo_NewFrame() failed (%d.)", __func__, ret); - return ret; - } - goto redo; - } - /* Note that we fall through to meet our destiny below */ - } - case FrameState_Done: - /* - * Do all necessary postprocessing of data prepared in - * "interrupt" code and the collecting code above. The - * frame gets marked as FrameState_Done by queue parsing code. - * This status means that we collected enough data and - * most likely processed it as we went through. However - * the data may need postprocessing, such as deinterlacing - * or picture adjustments implemented in software (horror!) - * - * As soon as the frame becomes "final" it gets promoted to - * FrameState_Done_Hold status where it will remain until the - * caller consumed all the video data from the frame. Then - * the empty shell of ex-frame is thrown out for dogs to eat. - * But we, worried about pets, will recycle the frame! - */ - uvd->stats.frame_num++; - if ((uvd->flags & FLAGS_NO_DECODING) == 0) { - if (VALID_CALLBACK(uvd, postProcess)) - GET_CALLBACK(uvd, postProcess)(uvd, frame); - if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST) - usbvideo_SoftwareContrastAdjustment(uvd, frame); - } - frame->frameState = FrameState_Done_Hold; - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, - "%s: Entered FrameState_Done_Hold state.\n", - __func__); - return 0; - - case FrameState_Done_Hold: - /* - * We stay in this state indefinitely until someone external, - * like ioctl() or read() call finishes digesting the frame - * data. Then it will mark the frame as FrameState_Unused and - * it will be released back into the wild to roam freely. - */ - if (uvd->debug >= 2) - dev_info(&uvd->dev->dev, - "%s: FrameState_Done_Hold state.\n", - __func__); - return 0; - } - - /* Catch-all for other cases. We shall not be here. */ - err("%s: Invalid state %d.", __func__, frame->frameState); - frame->frameState = FrameState_Unused; - return 0; -} - -/* - * usbvideo_DeinterlaceFrame() - * - * This procedure deinterlaces the given frame. Some cameras produce - * only half of scanlines - sometimes only even lines, sometimes only - * odd lines. The deinterlacing method is stored in frame->deinterlace - * variable. - * - * Here we scan the frame vertically and replace missing scanlines with - * average between surrounding ones - before and after. If we have no - * line above then we just copy next line. Similarly, if we need to - * create a last line then preceding line is used. - */ -void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame) -{ - if ((uvd == NULL) || (frame == NULL)) - return; - - if ((frame->deinterlace == Deinterlace_FillEvenLines) || - (frame->deinterlace == Deinterlace_FillOddLines)) - { - const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1; - - for (; i < VIDEOSIZE_Y(frame->request); i += 2) { - const unsigned char *fs1, *fs2; - unsigned char *fd; - int ip, in, j; /* Previous and next lines */ - - /* - * Need to average lines before and after 'i'. - * If we go out of bounds seeking those lines then - * we point back to existing line. - */ - ip = i - 1; /* First, get rough numbers */ - in = i + 1; - - /* Now validate */ - if (ip < 0) - ip = in; - if (in >= VIDEOSIZE_Y(frame->request)) - in = ip; - - /* Sanity check */ - if ((ip < 0) || (in < 0) || - (ip >= VIDEOSIZE_Y(frame->request)) || - (in >= VIDEOSIZE_Y(frame->request))) - { - err("Error: ip=%d. in=%d. req.height=%ld.", - ip, in, VIDEOSIZE_Y(frame->request)); - break; - } - - /* Now we need to average lines 'ip' and 'in' to produce line 'i' */ - fs1 = frame->data + (v4l_linesize * ip); - fs2 = frame->data + (v4l_linesize * in); - fd = frame->data + (v4l_linesize * i); - - /* Average lines around destination */ - for (j=0; j < v4l_linesize; j++) { - fd[j] = (unsigned char)((((unsigned) fs1[j]) + - ((unsigned)fs2[j])) >> 1); - } - } - } - - /* Optionally display statistics on the screen */ - if (uvd->flags & FLAGS_OVERLAY_STATS) - usbvideo_OverlayStats(uvd, frame); -} - -EXPORT_SYMBOL(usbvideo_DeinterlaceFrame); - -/* - * usbvideo_SoftwareContrastAdjustment() - * - * This code adjusts the contrast of the frame, assuming RGB24 format. - * As most software image processing, this job is CPU-intensive. - * Get a camera that supports hardware adjustment! - * - * History: - * 09-Feb-2001 Created. - */ -static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd, - struct usbvideo_frame *frame) -{ - int i, j, v4l_linesize; - signed long adj; - const int ccm = 128; /* Color correction median - see below */ - - if ((uvd == NULL) || (frame == NULL)) { - err("%s: Illegal call.", __func__); - return; - } - adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/ - RESTRICT_TO_RANGE(adj, -ccm, ccm+1); - if (adj == 0) { - /* In rare case of no adjustment */ - return; - } - v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL; - for (i=0; i < VIDEOSIZE_Y(frame->request); i++) { - unsigned char *fd = frame->data + (v4l_linesize * i); - for (j=0; j < v4l_linesize; j++) { - signed long v = (signed long) fd[j]; - /* Magnify up to 2 times, reduce down to zero */ - v = 128 + ((ccm + adj) * (v - 128)) / ccm; - RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */ - fd[j] = (unsigned char) v; - } - } -} - -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/usbvideo/usbvideo.h b/drivers/staging/usbvideo/usbvideo.h deleted file mode 100644 index 95638a072b19..000000000000 --- a/drivers/staging/usbvideo/usbvideo.h +++ /dev/null @@ -1,395 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef usbvideo_h -#define usbvideo_h - -#include "videodev.h" -#include -#include -#include -#include - -/* Most helpful debugging aid */ -#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__)))) - -#define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */ - -/* Bit flags (options) */ -#define FLAGS_RETRY_VIDIOCSYNC (1 << 0) -#define FLAGS_MONOCHROME (1 << 1) -#define FLAGS_DISPLAY_HINTS (1 << 2) -#define FLAGS_OVERLAY_STATS (1 << 3) -#define FLAGS_FORCE_TESTPATTERN (1 << 4) -#define FLAGS_SEPARATE_FRAMES (1 << 5) -#define FLAGS_CLEAN_FRAMES (1 << 6) -#define FLAGS_NO_DECODING (1 << 7) - -/* Bit flags for frames (apply to the frame where they are specified) */ -#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST (1 << 0) - -/* Camera capabilities (maximum) */ -#define CAMERA_URB_FRAMES 32 -#define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */ -#define FRAMES_PER_DESC (CAMERA_URB_FRAMES) -#define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET) - -/* This macro restricts an int variable to an inclusive range */ -#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } - -#define V4L_BYTES_PER_PIXEL 3 /* Because we produce RGB24 */ - -/* - * Use this macro to construct constants for different video sizes. - * We have to deal with different video sizes that have to be - * configured in the device or compared against when we receive - * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y - * #defines and that's the end of story. However this solution - * does not allow to convert between real pixel sizes and the - * constant (integer) value that may be used to tag a frame or - * whatever. The set of macros below constructs videosize constants - * from the pixel size and allows to reconstruct the pixel size - * from the combined value later. - */ -#define VIDEOSIZE(x,y) (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16)) -#define VIDEOSIZE_X(vs) ((vs) & 0xFFFFL) -#define VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL) -typedef unsigned long videosize_t; - -/* - * This macro checks if the camera is still operational. The 'uvd' - * pointer must be valid, uvd->dev must be valid, we are not - * removing the device and the device has not erred on us. - */ -#define CAMERA_IS_OPERATIONAL(uvd) (\ - (uvd != NULL) && \ - ((uvd)->dev != NULL) && \ - ((uvd)->last_error == 0) && \ - (!(uvd)->remove_pending)) - -/* - * We use macros to do YUV -> RGB conversion because this is - * very important for speed and totally unimportant for size. - * - * YUV -> RGB Conversion - * --------------------- - * - * B = 1.164*(Y-16) + 2.018*(V-128) - * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128) - * R = 1.164*(Y-16) + 1.596*(U-128) - * - * If you fancy integer arithmetics (as you should), hear this: - * - * 65536*B = 76284*(Y-16) + 132252*(V-128) - * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128) - * 65536*R = 76284*(Y-16) + 104595*(U-128) - * - * Make sure the output values are within [0..255] range. - */ -#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x))) -#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \ - int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \ - mm_y = (my) - 16; \ - mm_u = (mu) - 128; \ - mm_v = (mv) - 128; \ - mm_yc= mm_y * 76284; \ - mm_b = (mm_yc + 132252*mm_v ) >> 16; \ - mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \ - mm_r = (mm_yc + 104595*mm_u ) >> 16; \ - mb = LIMIT_RGB(mm_b); \ - mg = LIMIT_RGB(mm_g); \ - mr = LIMIT_RGB(mm_r); \ -} - -#define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */ -#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1) -#define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) -#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)]) - -struct RingQueue { - unsigned char *queue; /* Data from the Isoc data pump */ - int length; /* How many bytes allocated for the queue */ - int wi; /* That's where we write */ - int ri; /* Read from here until you hit write index */ - wait_queue_head_t wqh; /* Processes waiting */ -}; - -enum ScanState { - ScanState_Scanning, /* Scanning for header */ - ScanState_Lines /* Parsing lines */ -}; - -/* Completion states of the data parser */ -enum ParseState { - scan_Continue, /* Just parse next item */ - scan_NextFrame, /* Frame done, send it to V4L */ - scan_Out, /* Not enough data for frame */ - scan_EndParse /* End parsing */ -}; - -enum FrameState { - FrameState_Unused, /* Unused (no MCAPTURE) */ - FrameState_Ready, /* Ready to start grabbing */ - FrameState_Grabbing, /* In the process of being grabbed into */ - FrameState_Done, /* Finished grabbing, but not been synced yet */ - FrameState_Done_Hold, /* Are syncing or reading */ - FrameState_Error, /* Something bad happened while processing */ -}; - -/* - * Some frames may contain only even or odd lines. This type - * specifies what type of deinterlacing is required. - */ -enum Deinterlace { - Deinterlace_None=0, - Deinterlace_FillOddLines, - Deinterlace_FillEvenLines -}; - -#define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */ -#define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */ - -/* This structure represents one Isoc request - URB and buffer */ -struct usbvideo_sbuf { - char *data; - struct urb *urb; -}; - -struct usbvideo_frame { - char *data; /* Frame buffer */ - unsigned long header; /* Significant bits from the header */ - - videosize_t canvas; /* The canvas (max. image) allocated */ - videosize_t request; /* That's what the application asked for */ - unsigned short palette; /* The desired format */ - - enum FrameState frameState;/* State of grabbing */ - enum ScanState scanstate; /* State of scanning */ - enum Deinterlace deinterlace; - int flags; /* USBVIDEO_FRAME_FLAG_xxx bit flags */ - - int curline; /* Line of frame we're working on */ - - long seqRead_Length; /* Raw data length of frame */ - long seqRead_Index; /* Amount of data that has been already read */ - - void *user; /* Additional data that user may need */ -}; - -/* Statistics that can be overlaid on screen */ -struct usbvideo_statistics { - unsigned long frame_num; /* Sequential number of the frame */ - unsigned long urb_count; /* How many URBs we received so far */ - unsigned long urb_length; /* Length of last URB */ - unsigned long data_count; /* How many bytes we received */ - unsigned long header_count; /* How many frame headers we found */ - unsigned long iso_skip_count; /* How many empty ISO packets received */ - unsigned long iso_err_count; /* How many bad ISO packets received */ -}; - -struct usbvideo; - -struct uvd { - struct video_device vdev; /* Must be the first field! */ - struct usb_device *dev; - struct usbvideo *handle; /* Points back to the struct usbvideo */ - void *user_data; /* Camera-dependent data */ - int user_size; /* Size of that camera-dependent data */ - int debug; /* Debug level for usbvideo */ - unsigned char iface; /* Video interface number */ - unsigned char video_endp; - unsigned char ifaceAltActive; - unsigned char ifaceAltInactive; /* Alt settings */ - unsigned long flags; /* FLAGS_USBVIDEO_xxx */ - unsigned long paletteBits; /* Which palettes we accept? */ - unsigned short defaultPalette; /* What palette to use for read() */ - struct mutex lock; - int user; /* user count for exclusive use */ - - videosize_t videosize; /* Current setting */ - videosize_t canvas; /* This is the width,height of the V4L canvas */ - int max_frame_size; /* Bytes in one video frame */ - - int uvd_used; /* Is this structure in use? */ - int streaming; /* Are we streaming Isochronous? */ - int grabbing; /* Are we grabbing? */ - int settingsAdjusted; /* Have we adjusted contrast etc.? */ - int last_error; /* What calamity struck us? */ - - char *fbuf; /* Videodev buffer area */ - int fbuf_size; /* Videodev buffer size */ - - int curframe; - int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */ - - struct RingQueue dp; /* Isoc data pump */ - struct usbvideo_frame frame[USBVIDEO_NUMFRAMES]; - struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF]; - - volatile int remove_pending; /* If set then about to exit */ - - struct video_picture vpic, vpic_old; /* Picture settings */ - struct video_capability vcap; /* Video capabilities */ - struct video_channel vchan; /* May be used for tuner support */ - struct usbvideo_statistics stats; - char videoName[32]; /* Holds name like "video7" */ -}; - -/* - * usbvideo callbacks (virtual methods). They are set when usbvideo - * services are registered. All of these default to NULL, except those - * that default to usbvideo-provided methods. - */ -struct usbvideo_cb { - int (*probe)(struct usb_interface *, const struct usb_device_id *); - void (*userFree)(struct uvd *); - void (*disconnect)(struct usb_interface *); - int (*setupOnOpen)(struct uvd *); - void (*videoStart)(struct uvd *); - void (*videoStop)(struct uvd *); - void (*processData)(struct uvd *, struct usbvideo_frame *); - void (*postProcess)(struct uvd *, struct usbvideo_frame *); - void (*adjustPicture)(struct uvd *); - int (*getFPS)(struct uvd *); - int (*overlayHook)(struct uvd *, struct usbvideo_frame *); - int (*getFrame)(struct uvd *, int); - int (*startDataPump)(struct uvd *uvd); - void (*stopDataPump)(struct uvd *uvd); - int (*setVideoMode)(struct uvd *uvd, struct video_window *vw); -}; - -struct usbvideo { - int num_cameras; /* As allocated */ - struct usb_driver usbdrv; /* Interface to the USB stack */ - char drvName[80]; /* Driver name */ - struct mutex lock; /* Mutex protecting camera structures */ - struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */ - struct video_device vdt; /* Video device template */ - struct uvd *cam; /* Array of camera structures */ - struct module *md_module; /* Minidriver module */ -}; - - -/* - * This macro retrieves callback address from the struct uvd object. - * No validity checks are done here, so be sure to check the - * callback beforehand with VALID_CALLBACK. - */ -#define GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName) - -/* - * This macro returns either callback pointer or NULL. This is safe - * macro, meaning that most of components of data structures involved - * may be NULL - this only results in NULL being returned. You may - * wish to use this macro to make sure that the callback is callable. - * However keep in mind that those checks take time. - */ -#define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ - ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) - -int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len); -int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n); -void RingQueue_WakeUpInterruptible(struct RingQueue *rq); -void RingQueue_Flush(struct RingQueue *rq); - -static inline int RingQueue_GetLength(const struct RingQueue *rq) -{ - return (rq->wi - rq->ri + rq->length) & (rq->length-1); -} - -static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq) -{ - return rq->length - RingQueue_GetLength(rq); -} - -void usbvideo_DrawLine( - struct usbvideo_frame *frame, - int x1, int y1, - int x2, int y2, - unsigned char cr, unsigned char cg, unsigned char cb); -void usbvideo_HexDump(const unsigned char *data, int len); -void usbvideo_SayAndWait(const char *what); -void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode); - -/* Memory allocation routines */ -unsigned long usbvideo_kvirt_to_pa(unsigned long adr); - -int usbvideo_register( - struct usbvideo **pCams, - const int num_cams, - const int num_extra, - const char *driverName, - const struct usbvideo_cb *cbTable, - struct module *md, - const struct usb_device_id *id_table); -struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams); -int usbvideo_RegisterVideoDevice(struct uvd *uvd); -void usbvideo_Deregister(struct usbvideo **uvt); - -int usbvideo_v4l_initialize(struct video_device *dev); - -void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame); - -/* - * This code performs bounds checking - use it when working with - * new formats, or else you may get oopses all over the place. - * If pixel falls out of bounds then it gets shoved back (as close - * to place of offence as possible) and is painted bright red. - * - * There are two important concepts: frame width, height and - * V4L canvas width, height. The former is the area requested by - * the application -for this very frame-. The latter is the largest - * possible frame that we can serve (we advertise that via V4L ioctl). - * The frame data is expected to be formatted as lines of length - * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines. - */ -static inline void RGB24_PUTPIXEL( - struct usbvideo_frame *fr, - int ix, int iy, - unsigned char vr, - unsigned char vg, - unsigned char vb) -{ - register unsigned char *pf; - int limiter = 0, mx, my; - mx = ix; - my = iy; - if (mx < 0) { - mx=0; - limiter++; - } else if (mx >= VIDEOSIZE_X((fr)->request)) { - mx= VIDEOSIZE_X((fr)->request) - 1; - limiter++; - } - if (my < 0) { - my = 0; - limiter++; - } else if (my >= VIDEOSIZE_Y((fr)->request)) { - my = VIDEOSIZE_Y((fr)->request) - 1; - limiter++; - } - pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix)); - if (limiter) { - *pf++ = 0; - *pf++ = 0; - *pf++ = 0xFF; - } else { - *pf++ = (vb); - *pf++ = (vg); - *pf++ = (vr); - } -} - -#endif /* usbvideo_h */ diff --git a/drivers/staging/usbvideo/vicam.c b/drivers/staging/usbvideo/vicam.c deleted file mode 100644 index ecdb121297c9..000000000000 --- a/drivers/staging/usbvideo/vicam.c +++ /dev/null @@ -1,952 +0,0 @@ -/* - * USB ViCam WebCam driver - * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), - * Christopher L Cheney (ccheney@cheney.cx), - * Pavel Machek (pavel@ucw.cz), - * John Tyner (jtyner@cs.ucr.edu), - * Monroe Williams (monroe@pobox.com) - * - * Supports 3COM HomeConnect PC Digital WebCam - * Supports Compro PS39U WebCam - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This source code is based heavily on the CPiA webcam driver which was - * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt - * - * Portions of this code were also copied from usbvideo.c - * - * Special thanks to the whole team at Sourceforge for help making - * this driver become a reality. Notably: - * Andy Armstrong who reverse engineered the color encoding and - * Pavel Machek and Chris Cheney who worked on reverse engineering the - * camera controls and wrote the first generation driver. - */ - -#include -#include -#include -#include "videodev.h" -#include -#include -#include -#include -#include -#include -#include -#include "usbvideo.h" - -// #define VICAM_DEBUG - -#ifdef VICAM_DEBUG -#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args) -#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) -#else -#define DBG(fmn,args...) do {} while(0) -#endif - -#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" -#define DRIVER_DESC "ViCam WebCam Driver" - -/* Define these values to match your device */ -#define USB_VICAM_VENDOR_ID 0x04c1 -#define USB_VICAM_PRODUCT_ID 0x009d -#define USB_COMPRO_VENDOR_ID 0x0602 -#define USB_COMPRO_PRODUCT_ID 0x1001 - -#define VICAM_BYTES_PER_PIXEL 3 -#define VICAM_MAX_READ_SIZE (512*242+128) -#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) -#define VICAM_FRAMES 2 - -#define VICAM_HEADER_SIZE 64 - -/* rvmalloc / rvfree copied from usbvideo.c - * - * Not sure why these are not yet non-statics which I can reference through - * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime - * in the future. - * -*/ -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - -struct vicam_camera { - u16 shutter_speed; // capture shutter speed - u16 gain; // capture gain - - u8 *raw_image; // raw data captured from the camera - u8 *framebuf; // processed data in RGB24 format - u8 *cntrlbuf; // area used to send control msgs - - struct video_device vdev; // v4l video device - struct usb_device *udev; // usb device - - /* guard against simultaneous accesses to the camera */ - struct mutex cam_lock; - - int is_initialized; - u8 open_count; - u8 bulkEndpoint; - int needsDummyRead; -}; - -static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); -static void vicam_disconnect(struct usb_interface *intf); -static void read_frame(struct vicam_camera *cam, int framenum); -static void vicam_decode_color(const u8 *, u8 *); - -static int __send_control_msg(struct vicam_camera *cam, - u8 request, - u16 value, - u16 index, - unsigned char *cp, - u16 size) -{ - int status; - - /* cp must be memory that has been allocated by kmalloc */ - - status = usb_control_msg(cam->udev, - usb_sndctrlpipe(cam->udev, 0), - request, - USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, value, index, - cp, size, 1000); - - status = min(status, 0); - - if (status < 0) { - printk(KERN_INFO "Failed sending control message, error %d.\n", - status); - } - - return status; -} - -static int send_control_msg(struct vicam_camera *cam, - u8 request, - u16 value, - u16 index, - unsigned char *cp, - u16 size) -{ - int status = -ENODEV; - mutex_lock(&cam->cam_lock); - if (cam->udev) { - status = __send_control_msg(cam, request, value, - index, cp, size); - } - mutex_unlock(&cam->cam_lock); - return status; -} -static int -initialize_camera(struct vicam_camera *cam) -{ - int err; - const struct ihex_binrec *rec; - const struct firmware *uninitialized_var(fw); - - err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev); - if (err) { - printk(KERN_ERR "Failed to load \"vicam/firmware.fw\": %d\n", - err); - return err; - } - - for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { - memcpy(cam->cntrlbuf, rec->data, be16_to_cpu(rec->len)); - - err = send_control_msg(cam, 0xff, 0, 0, - cam->cntrlbuf, be16_to_cpu(rec->len)); - if (err) - break; - } - - release_firmware(fw); - - return err; -} - -static int -set_camera_power(struct vicam_camera *cam, int state) -{ - int status; - - if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) - return status; - - if (state) { - send_control_msg(cam, 0x55, 1, 0, NULL, 0); - } - - return 0; -} - -static long -vicam_ioctl(struct file *file, unsigned int ioctlnr, unsigned long arg) -{ - void __user *user_arg = (void __user *)arg; - struct vicam_camera *cam = file->private_data; - long retval = 0; - - if (!cam) - return -ENODEV; - - switch (ioctlnr) { - /* query capabilities */ - case VIDIOCGCAP: - { - struct video_capability b; - - DBG("VIDIOCGCAP\n"); - memset(&b, 0, sizeof(b)); - strcpy(b.name, "ViCam-based Camera"); - b.type = VID_TYPE_CAPTURE; - b.channels = 1; - b.audios = 0; - b.maxwidth = 320; /* VIDEOSIZE_CIF */ - b.maxheight = 240; - b.minwidth = 320; /* VIDEOSIZE_48_48 */ - b.minheight = 240; - - if (copy_to_user(user_arg, &b, sizeof(b))) - retval = -EFAULT; - - break; - } - /* get/set video source - we are a camera and nothing else */ - case VIDIOCGCHAN: - { - struct video_channel v; - - DBG("VIDIOCGCHAN\n"); - if (copy_from_user(&v, user_arg, sizeof(v))) { - retval = -EFAULT; - break; - } - if (v.channel != 0) { - retval = -EINVAL; - break; - } - - v.channel = 0; - strcpy(v.name, "Camera"); - v.tuners = 0; - v.flags = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = 0; - - if (copy_to_user(user_arg, &v, sizeof(v))) - retval = -EFAULT; - break; - } - - case VIDIOCSCHAN: - { - int v; - - if (copy_from_user(&v, user_arg, sizeof(v))) - retval = -EFAULT; - DBG("VIDIOCSCHAN %d\n", v); - - if (retval == 0 && v != 0) - retval = -EINVAL; - - break; - } - - /* image properties */ - case VIDIOCGPICT: - { - struct video_picture vp; - DBG("VIDIOCGPICT\n"); - memset(&vp, 0, sizeof (struct video_picture)); - vp.brightness = cam->gain << 8; - vp.depth = 24; - vp.palette = VIDEO_PALETTE_RGB24; - if (copy_to_user(user_arg, &vp, sizeof (struct video_picture))) - retval = -EFAULT; - break; - } - - case VIDIOCSPICT: - { - struct video_picture vp; - - if (copy_from_user(&vp, user_arg, sizeof(vp))) { - retval = -EFAULT; - break; - } - - DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth, - vp.palette); - - cam->gain = vp.brightness >> 8; - - if (vp.depth != 24 - || vp.palette != VIDEO_PALETTE_RGB24) - retval = -EINVAL; - - break; - } - - /* get/set capture window */ - case VIDIOCGWIN: - { - struct video_window vw; - vw.x = 0; - vw.y = 0; - vw.width = 320; - vw.height = 240; - vw.chromakey = 0; - vw.flags = 0; - vw.clips = NULL; - vw.clipcount = 0; - - DBG("VIDIOCGWIN\n"); - - if (copy_to_user(user_arg, (void *)&vw, sizeof(vw))) - retval = -EFAULT; - - // I'm not sure what the deal with a capture window is, it is very poorly described - // in the doc. So I won't support it now. - break; - } - - case VIDIOCSWIN: - { - - struct video_window vw; - - if (copy_from_user(&vw, user_arg, sizeof(vw))) { - retval = -EFAULT; - break; - } - - DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height); - - if ( vw.width != 320 || vw.height != 240 ) - retval = -EFAULT; - - break; - } - - /* mmap interface */ - case VIDIOCGMBUF: - { - struct video_mbuf vm; - int i; - - DBG("VIDIOCGMBUF\n"); - memset(&vm, 0, sizeof (vm)); - vm.size = - VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; - vm.frames = VICAM_FRAMES; - for (i = 0; i < VICAM_FRAMES; i++) - vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; - - if (copy_to_user(user_arg, (void *)&vm, sizeof(vm))) - retval = -EFAULT; - - break; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - // int video_size; - - if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) { - retval = -EFAULT; - break; - } - - DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); - - if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) - retval = -EINVAL; - - // in theory right here we'd start the image capturing - // (fill in a bulk urb and submit it asynchronously) - // - // Instead we're going to do a total hack job for now and - // retrieve the frame in VIDIOCSYNC - - break; - } - - case VIDIOCSYNC: - { - int frame; - - if (copy_from_user((void *)&frame, user_arg, sizeof(int))) { - retval = -EFAULT; - break; - } - DBG("VIDIOCSYNC: %d\n", frame); - - read_frame(cam, frame); - vicam_decode_color(cam->raw_image, - cam->framebuf + - frame * VICAM_MAX_FRAME_SIZE ); - - break; - } - - /* pointless to implement overlay with this camera */ - case VIDIOCCAPTURE: - case VIDIOCGFBUF: - case VIDIOCSFBUF: - case VIDIOCKEY: - retval = -EINVAL; - break; - - /* tuner interface - we have none */ - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - retval = -EINVAL; - break; - - /* audio interface - we have none */ - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - retval = -EINVAL; - break; - default: - retval = -ENOIOCTLCMD; - break; - } - - return retval; -} - -static int -vicam_open(struct file *file) -{ - struct vicam_camera *cam = video_drvdata(file); - - DBG("open\n"); - - if (!cam) { - printk(KERN_ERR - "vicam video_device improperly initialized"); - return -EINVAL; - } - - /* cam_lock/open_count protects us from simultaneous opens - * ... for now. we probably shouldn't rely on this fact forever. - */ - - mutex_lock(&cam->cam_lock); - if (cam->open_count > 0) { - printk(KERN_INFO - "vicam_open called on already opened camera"); - mutex_unlock(&cam->cam_lock); - return -EBUSY; - } - - cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); - if (!cam->raw_image) { - mutex_unlock(&cam->cam_lock); - return -ENOMEM; - } - - cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - if (!cam->framebuf) { - kfree(cam->raw_image); - mutex_unlock(&cam->cam_lock); - return -ENOMEM; - } - - cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!cam->cntrlbuf) { - kfree(cam->raw_image); - rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - mutex_unlock(&cam->cam_lock); - return -ENOMEM; - } - - cam->needsDummyRead = 1; - cam->open_count++; - - file->private_data = cam; - mutex_unlock(&cam->cam_lock); - - - // First upload firmware, then turn the camera on - - if (!cam->is_initialized) { - initialize_camera(cam); - - cam->is_initialized = 1; - } - - set_camera_power(cam, 1); - - return 0; -} - -static int -vicam_close(struct file *file) -{ - struct vicam_camera *cam = file->private_data; - int open_count; - struct usb_device *udev; - - DBG("close\n"); - - /* it's not the end of the world if - * we fail to turn the camera off. - */ - - set_camera_power(cam, 0); - - kfree(cam->raw_image); - rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - kfree(cam->cntrlbuf); - - mutex_lock(&cam->cam_lock); - - cam->open_count--; - open_count = cam->open_count; - udev = cam->udev; - - mutex_unlock(&cam->cam_lock); - - if (!open_count && !udev) { - kfree(cam); - } - - return 0; -} - -static void vicam_decode_color(const u8 *data, u8 *rgb) -{ - /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB - * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) - */ - - int i, prevY, nextY; - - prevY = 512; - nextY = 512; - - data += VICAM_HEADER_SIZE; - - for( i = 0; i < 240; i++, data += 512 ) { - const int y = ( i * 242 ) / 240; - - int j, prevX, nextX; - int Y, Cr, Cb; - - if ( y == 242 - 1 ) { - nextY = -512; - } - - prevX = 1; - nextX = 1; - - for ( j = 0; j < 320; j++, rgb += 3 ) { - const int x = ( j * 512 ) / 320; - const u8 * const src = &data[x]; - - if ( x == 512 - 1 ) { - nextX = -1; - } - - Cr = ( src[prevX] - src[0] ) + - ( src[nextX] - src[0] ); - Cr /= 2; - - Cb = ( src[prevY] - src[prevX + prevY] ) + - ( src[prevY] - src[nextX + prevY] ) + - ( src[nextY] - src[prevX + nextY] ) + - ( src[nextY] - src[nextX + nextY] ); - Cb /= 4; - - Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); - - if ( i & 1 ) { - int Ct = Cr; - Cr = Cb; - Cb = Ct; - } - - if ( ( x ^ i ) & 1 ) { - Cr = -Cr; - Cb = -Cb; - } - - rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + - 500 ) / 900, 0, 255 ); - rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - - ( 813 * Cr ) ) + - 500 ) / 1000, 0, 255 ); - rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + - 500 ) / 1300, 0, 255 ); - - prevX = -1; - } - - prevY = -512; - } -} - -static void -read_frame(struct vicam_camera *cam, int framenum) -{ - unsigned char *request = cam->cntrlbuf; - int realShutter; - int n; - int actual_length; - - if (cam->needsDummyRead) { - cam->needsDummyRead = 0; - read_frame(cam, framenum); - } - - memset(request, 0, 16); - request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain - - request[1] = 0; // 512x242 capture - - request[2] = 0x90; // the function of these two bytes - request[3] = 0x07; // is not yet understood - - if (cam->shutter_speed > 60) { - // Short exposure - realShutter = - ((-15631900 / cam->shutter_speed) + 260533) / 1000; - request[4] = realShutter & 0xFF; - request[5] = (realShutter >> 8) & 0xFF; - request[6] = 0x03; - request[7] = 0x01; - } else { - // Long exposure - realShutter = 15600 / cam->shutter_speed - 1; - request[4] = 0; - request[5] = 0; - request[6] = realShutter & 0xFF; - request[7] = realShutter >> 8; - } - - // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 - request[8] = 0; - // bytes 9-15 do not seem to affect exposure or image quality - - mutex_lock(&cam->cam_lock); - - if (!cam->udev) { - goto done; - } - - n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); - - if (n < 0) { - printk(KERN_ERR - " Problem sending frame capture control message"); - goto done; - } - - n = usb_bulk_msg(cam->udev, - usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), - cam->raw_image, - 512 * 242 + 128, &actual_length, 10000); - - if (n < 0) { - printk(KERN_ERR "Problem during bulk read of frame data: %d\n", - n); - } - - done: - mutex_unlock(&cam->cam_lock); -} - -static ssize_t -vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos ) -{ - struct vicam_camera *cam = file->private_data; - - DBG("read %d bytes.\n", (int) count); - - if (*ppos >= VICAM_MAX_FRAME_SIZE) { - *ppos = 0; - return 0; - } - - if (*ppos == 0) { - read_frame(cam, 0); - vicam_decode_color(cam->raw_image, - cam->framebuf + - 0 * VICAM_MAX_FRAME_SIZE); - } - - count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); - - if (copy_to_user(buf, &cam->framebuf[*ppos], count)) { - count = -EFAULT; - } else { - *ppos += count; - } - - if (count == VICAM_MAX_FRAME_SIZE) { - *ppos = 0; - } - - return count; -} - - -static int -vicam_mmap(struct file *file, struct vm_area_struct *vma) -{ - // TODO: allocate the raw frame buffer if necessary - unsigned long page, pos; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - struct vicam_camera *cam = file->private_data; - - if (!cam) - return -ENODEV; - - DBG("vicam_mmap: %ld\n", size); - - /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes - * to the size the application requested for mmap and it was screwing apps up. - if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) - return -EINVAL; - */ - - pos = (unsigned long)cam->framebuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - - return 0; -} - -static const struct v4l2_file_operations vicam_fops = { - .owner = THIS_MODULE, - .open = vicam_open, - .release = vicam_close, - .read = vicam_read, - .mmap = vicam_mmap, - .ioctl = vicam_ioctl, -}; - -static struct video_device vicam_template = { - .name = "ViCam-based USB Camera", - .fops = &vicam_fops, - .release = video_device_release_empty, -}; - -/* table of devices that work with this driver */ -static struct usb_device_id vicam_table[] = { - {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, - {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, vicam_table); - -static struct usb_driver vicam_driver = { - .name = "vicam", - .probe = vicam_probe, - .disconnect = vicam_disconnect, - .id_table = vicam_table -}; - -/** - * vicam_probe - * @intf: the interface - * @id: the device id - * - * Called by the usb core when a new device is connected that it thinks - * this driver might be interested in. - */ -static int -vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - int bulkEndpoint = 0; - const struct usb_host_interface *interface; - const struct usb_endpoint_descriptor *endpoint; - struct vicam_camera *cam; - - printk(KERN_INFO "ViCam based webcam connected\n"); - - interface = intf->cur_altsetting; - - DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", - interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints)); - endpoint = &interface->endpoint[0].desc; - - if (usb_endpoint_is_bulk_in(endpoint)) { - /* we found a bulk in endpoint */ - bulkEndpoint = endpoint->bEndpointAddress; - } else { - printk(KERN_ERR - "No bulk in endpoint was found ?! (this is bad)\n"); - } - - if ((cam = - kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { - printk(KERN_WARNING - "could not allocate kernel memory for vicam_camera struct\n"); - return -ENOMEM; - } - - - cam->shutter_speed = 15; - - mutex_init(&cam->cam_lock); - - memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template)); - video_set_drvdata(&cam->vdev, cam); - - cam->udev = dev; - cam->bulkEndpoint = bulkEndpoint; - - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) { - kfree(cam); - printk(KERN_WARNING "video_register_device failed\n"); - return -EIO; - } - - printk(KERN_INFO "ViCam webcam driver now controlling device %s\n", - video_device_node_name(&cam->vdev)); - - usb_set_intfdata (intf, cam); - - return 0; -} - -static void -vicam_disconnect(struct usb_interface *intf) -{ - int open_count; - struct vicam_camera *cam = usb_get_intfdata (intf); - usb_set_intfdata (intf, NULL); - - /* we must unregister the device before taking its - * cam_lock. This is because the video open call - * holds the same lock as video unregister. if we - * unregister inside of the cam_lock and open also - * uses the cam_lock, we get deadlock. - */ - - video_unregister_device(&cam->vdev); - - /* stop the camera from being used */ - - mutex_lock(&cam->cam_lock); - - /* mark the camera as gone */ - - cam->udev = NULL; - - /* the only thing left to do is synchronize with - * our close/release function on who should release - * the camera memory. if there are any users using the - * camera, it's their job. if there are no users, - * it's ours. - */ - - open_count = cam->open_count; - - mutex_unlock(&cam->cam_lock); - - if (!open_count) { - kfree(cam); - } - - printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); -} - -/* - */ -static int __init -usb_vicam_init(void) -{ - int retval; - DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); - retval = usb_register(&vicam_driver); - if (retval) - printk(KERN_WARNING "usb_register failed!\n"); - return retval; -} - -static void __exit -usb_vicam_exit(void) -{ - DBG(KERN_INFO - "ViCam-based WebCam driver shutdown\n"); - - usb_deregister(&vicam_driver); -} - -module_init(usb_vicam_init); -module_exit(usb_vicam_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("vicam/firmware.fw"); diff --git a/drivers/staging/usbvideo/videodev.h b/drivers/staging/usbvideo/videodev.h deleted file mode 100644 index f11efbef1c05..000000000000 --- a/drivers/staging/usbvideo/videodev.h +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Video for Linux version 1 - OBSOLETE - * - * Header file for v4l1 drivers and applications, for - * Linux kernels 2.2.x or 2.4.x. - * - * Provides header for legacy drivers and applications - * - * See http://linuxtv.org for more info - * - */ -#ifndef __LINUX_VIDEODEV_H -#define __LINUX_VIDEODEV_H - -#include -#include -#include - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ - -struct video_capability -{ - char name[32]; - int type; - int channels; /* Num channels */ - int audios; /* Num audio devices */ - int maxwidth; /* Supported width */ - int maxheight; /* And height */ - int minwidth; /* Supported width */ - int minheight; /* And height */ -}; - - -struct video_channel -{ - int channel; - char name[32]; - int tuners; - __u32 flags; -#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ -#define VIDEO_VC_AUDIO 2 /* Channel has audio */ - __u16 type; -#define VIDEO_TYPE_TV 1 -#define VIDEO_TYPE_CAMERA 2 - __u16 norm; /* Norm set by channel */ -}; - -struct video_tuner -{ - int tuner; - char name[32]; - unsigned long rangelow, rangehigh; /* Tuner range */ - __u32 flags; -#define VIDEO_TUNER_PAL 1 -#define VIDEO_TUNER_NTSC 2 -#define VIDEO_TUNER_SECAM 4 -#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ -#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ -#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ -#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ -#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ - __u16 mode; /* PAL/NTSC/SECAM/OTHER */ -#define VIDEO_MODE_PAL 0 -#define VIDEO_MODE_NTSC 1 -#define VIDEO_MODE_SECAM 2 -#define VIDEO_MODE_AUTO 3 - __u16 signal; /* Signal strength 16bit scale */ -}; - -struct video_picture -{ - __u16 brightness; - __u16 hue; - __u16 colour; - __u16 contrast; - __u16 whiteness; /* Black and white only */ - __u16 depth; /* Capture depth */ - __u16 palette; /* Palette in use */ -#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ -#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ -#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ -#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ -#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ -#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ -#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ -#define VIDEO_PALETTE_YUYV 8 -#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ -#define VIDEO_PALETTE_YUV420 10 -#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ -#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ -#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ -#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ -#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ -#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ -#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ -#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ -}; - -struct video_audio -{ - int audio; /* Audio channel */ - __u16 volume; /* If settable */ - __u16 bass, treble; - __u32 flags; -#define VIDEO_AUDIO_MUTE 1 -#define VIDEO_AUDIO_MUTABLE 2 -#define VIDEO_AUDIO_VOLUME 4 -#define VIDEO_AUDIO_BASS 8 -#define VIDEO_AUDIO_TREBLE 16 -#define VIDEO_AUDIO_BALANCE 32 - char name[16]; -#define VIDEO_SOUND_MONO 1 -#define VIDEO_SOUND_STEREO 2 -#define VIDEO_SOUND_LANG1 4 -#define VIDEO_SOUND_LANG2 8 - __u16 mode; - __u16 balance; /* Stereo balance */ - __u16 step; /* Step actual volume uses */ -}; - -struct video_clip -{ - __s32 x,y; - __s32 width, height; - struct video_clip *next; /* For user use/driver use only */ -}; - -struct video_window -{ - __u32 x,y; /* Position of window */ - __u32 width,height; /* Its size */ - __u32 chromakey; - __u32 flags; - struct video_clip __user *clips; /* Set only */ - int clipcount; -#define VIDEO_WINDOW_INTERLACE 1 -#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ -#define VIDEO_CLIP_BITMAP -1 -/* bitmap is 1024x625, a '1' bit represents a clipped pixel */ -#define VIDEO_CLIPMAP_SIZE (128 * 625) -}; - -struct video_capture -{ - __u32 x,y; /* Offsets into image */ - __u32 width, height; /* Area to capture */ - __u16 decimation; /* Decimation divider */ - __u16 flags; /* Flags for capture */ -#define VIDEO_CAPTURE_ODD 0 /* Temporal */ -#define VIDEO_CAPTURE_EVEN 1 -}; - -struct video_buffer -{ - void *base; - int height,width; - int depth; - int bytesperline; -}; - -struct video_mmap -{ - unsigned int frame; /* Frame (0 - n) for double buffer */ - int height,width; - unsigned int format; /* should be VIDEO_PALETTE_* */ -}; - -struct video_key -{ - __u8 key[8]; - __u32 flags; -}; - -struct video_mbuf -{ - int size; /* Total memory to map */ - int frames; /* Frames */ - int offsets[VIDEO_MAX_FRAME]; -}; - -#define VIDEO_NO_UNIT (-1) - -struct video_unit -{ - int video; /* Video minor */ - int vbi; /* VBI minor */ - int radio; /* Radio minor */ - int audio; /* Audio minor */ - int teletext; /* Teletext minor */ -}; - -struct vbi_format { - __u32 sampling_rate; /* in Hz */ - __u32 samples_per_line; - __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ - __s32 start[2]; /* starting line for each frame */ - __u32 count[2]; /* count of lines for each frame */ - __u32 flags; -#define VBI_UNSYNC 1 /* can distingues between top/bottom field */ -#define VBI_INTERLACED 2 /* lines are interlaced */ -}; - -/* video_info is biased towards hardware mpeg encode/decode */ -/* but it could apply generically to any hardware compressor/decompressor */ -struct video_info -{ - __u32 frame_count; /* frames output since decode/encode began */ - __u32 h_size; /* current unscaled horizontal size */ - __u32 v_size; /* current unscaled veritcal size */ - __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */ - __u32 picture_type; /* current picture type */ - __u32 temporal_reference; /* current temporal reference */ - __u8 user_data[256]; /* user data last found in compressed stream */ - /* user_data[0] contains user data flags, user_data[1] has count */ -}; - -/* generic structure for setting playback modes */ -struct video_play_mode -{ - int mode; - int p1; - int p2; -}; - -/* for loading microcode / fpga programming */ -struct video_code -{ - char loadwhat[16]; /* name or tag of file being passed */ - int datasize; - __u8 *data; -}; - -#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ -#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ -#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ -#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ -#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ -#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ -#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ -#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ -#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ -#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ -#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ -#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ -#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ -#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ -#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ -#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ -#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ -#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ -#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ -#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ -#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ -#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ -#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ -#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ -#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ -#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ -#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ -#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ -#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ - - -#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ - -/* VIDIOCSWRITEMODE */ -#define VID_WRITE_MPEG_AUD 0 -#define VID_WRITE_MPEG_VID 1 -#define VID_WRITE_OSD 2 -#define VID_WRITE_TTX 3 -#define VID_WRITE_CC 4 -#define VID_WRITE_MJPEG 5 - -/* VIDIOCSPLAYMODE */ -#define VID_PLAY_VID_OUT_MODE 0 - /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ -#define VID_PLAY_GENLOCK 1 - /* p1: 0 = OFF, 1 = ON */ - /* p2: GENLOCK FINE DELAY value */ -#define VID_PLAY_NORMAL 2 -#define VID_PLAY_PAUSE 3 -#define VID_PLAY_SINGLE_FRAME 4 -#define VID_PLAY_FAST_FORWARD 5 -#define VID_PLAY_SLOW_MOTION 6 -#define VID_PLAY_IMMEDIATE_NORMAL 7 -#define VID_PLAY_SWITCH_CHANNELS 8 -#define VID_PLAY_FREEZE_FRAME 9 -#define VID_PLAY_STILL_MODE 10 -#define VID_PLAY_MASTER_MODE 11 - /* p1: see below */ -#define VID_PLAY_MASTER_NONE 1 -#define VID_PLAY_MASTER_VIDEO 2 -#define VID_PLAY_MASTER_AUDIO 3 -#define VID_PLAY_ACTIVE_SCANLINES 12 - /* p1 = first active; p2 = last active */ -#define VID_PLAY_RESET 13 -#define VID_PLAY_END_MARK 14 - -#endif /* __LINUX_VIDEODEV_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.2 From b287db119edb92548b53f63f05fd593c43cba200 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 5 Feb 2011 09:25:02 -0300 Subject: [media] se401: remove last V4L1 driver This driver is for obsolete hardware that the old maintainer didn't care (or not have the hardware anymore), and that no other developer could find any hardware to buy. The V4L1 API is no longer supported, and since nobody stepped in to convert them to V4L2 the decision was made to remove them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/se401/Kconfig | 13 - drivers/staging/se401/Makefile | 1 - drivers/staging/se401/TODO | 5 - drivers/staging/se401/se401.c | 1492 -------------------------------------- drivers/staging/se401/se401.h | 236 ------ drivers/staging/se401/videodev.h | 318 -------- 8 files changed, 2068 deletions(-) delete mode 100644 drivers/staging/se401/Kconfig delete mode 100644 drivers/staging/se401/Makefile delete mode 100644 drivers/staging/se401/TODO delete mode 100644 drivers/staging/se401/se401.c delete mode 100644 drivers/staging/se401/se401.h delete mode 100644 drivers/staging/se401/videodev.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index a3f340bb6b59..fa5c007e74c8 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -55,8 +55,6 @@ source "drivers/staging/cxd2099/Kconfig" source "drivers/staging/dabusb/Kconfig" -source "drivers/staging/se401/Kconfig" - source "drivers/staging/usbip/Kconfig" source "drivers/staging/winbond/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 532331ceb12d..2bdd703ed208 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_USB_DABUSB) += dabusb/ -obj-$(CONFIG_USB_SE401) += se401/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_USB_IP_COMMON) += usbip/ obj-$(CONFIG_W35UND) += winbond/ diff --git a/drivers/staging/se401/Kconfig b/drivers/staging/se401/Kconfig deleted file mode 100644 index b7f8222ad21b..000000000000 --- a/drivers/staging/se401/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config USB_SE401 - tristate "USB SE401 Camera support (DEPRECATED)" - depends on VIDEO_DEV && VIDEO_V4L2_COMMON && USB - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. See - for more information and for a list of supported cameras. - - This driver uses the deprecated V4L1 API and will be removed in - 2.6.39, unless someone converts it to the V4L2 API. - - To compile this driver as a module, choose M here: the - module will be called se401. diff --git a/drivers/staging/se401/Makefile b/drivers/staging/se401/Makefile deleted file mode 100644 index b465d49783af..000000000000 --- a/drivers/staging/se401/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_USB_SE401) += se401.o diff --git a/drivers/staging/se401/TODO b/drivers/staging/se401/TODO deleted file mode 100644 index 3b2c03836286..000000000000 --- a/drivers/staging/se401/TODO +++ /dev/null @@ -1,5 +0,0 @@ -This is an obsolete driver for some old webcams that still use V4L1 API. -As V4L1 support is being removed from kernel, if nobody take care on it, -the driver will be removed for 2.6.39. - -Please send patches to linux-media@vger.kernel.org diff --git a/drivers/staging/se401/se401.c b/drivers/staging/se401/se401.c deleted file mode 100644 index 41360d7c3e96..000000000000 --- a/drivers/staging/se401/se401.c +++ /dev/null @@ -1,1492 +0,0 @@ -/* - * Endpoints (formerly known as AOX) se401 USB Camera Driver - * - * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org) - * - * Still somewhat based on the Linux ov511 driver. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on - * their chipset available and supporting me while writing this driver. - * - Jeroen Vreeken - */ - -static const char version[] = "0.24"; - -#include -#include -#include -#include -#include -#include -#include "se401.h" - -static int flickerless; -static int video_nr = -1; - -static struct usb_device_id device_table[] = { - { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */ - { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */ - { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */ - { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */ - { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */ - { } -}; - -MODULE_DEVICE_TABLE(usb, device_table); - -MODULE_AUTHOR("Jeroen Vreeken "); -MODULE_DESCRIPTION("SE401 USB Camera Driver"); -MODULE_LICENSE("GPL"); -module_param(flickerless, int, 0); -MODULE_PARM_DESC(flickerless, - "Net frequency to adjust exposure time to (0/50/60)"); -module_param(video_nr, int, 0); - -static struct usb_driver se401_driver; - - -/********************************************************************** - * - * Memory management - * - **********************************************************************/ -static void *rvmalloc(unsigned long size) -{ - void *mem; - unsigned long adr; - - size = PAGE_ALIGN(size); - mem = vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr = (unsigned long) mem; - while (size > 0) { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - - return mem; -} - -static void rvfree(void *mem, unsigned long size) -{ - unsigned long adr; - - if (!mem) - return; - - adr = (unsigned long) mem; - while ((long) size > 0) { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); -} - - - -/**************************************************************************** - * - * se401 register read/write functions - * - ***************************************************************************/ - -static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req, - unsigned short value, unsigned char *cp, int size) -{ - return usb_control_msg( - se401->dev, - set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0), - req, - (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, - 0, - cp, - size, - 1000 - ); -} - -static int se401_set_feature(struct usb_se401 *se401, unsigned short selector, - unsigned short param) -{ - /* specs say that the selector (address) should go in the value field - and the param in index, but in the logs of the windows driver they do - this the other way around... - */ - return usb_control_msg( - se401->dev, - usb_sndctrlpipe(se401->dev, 0), - SE401_REQ_SET_EXT_FEATURE, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - param, - selector, - NULL, - 0, - 1000 - ); -} - -static unsigned short se401_get_feature(struct usb_se401 *se401, - unsigned short selector) -{ - /* For 'set' the selecetor should be in index, not sure if the spec is - wrong here to.... - */ - unsigned char cp[2]; - usb_control_msg( - se401->dev, - usb_rcvctrlpipe(se401->dev, 0), - SE401_REQ_GET_EXT_FEATURE, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, - selector, - cp, - 2, - 1000 - ); - return cp[0]+cp[1]*256; -} - -/**************************************************************************** - * - * Camera control - * - ***************************************************************************/ - - -static int se401_send_pict(struct usb_se401 *se401) -{ - /* integration time low */ - se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l); - /* integration time mid */ - se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m); - /* integration time mid */ - se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h); - /* reset level value */ - se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel); - /* red color gain */ - se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain); - /* green color gain */ - se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain); - /* blue color gain */ - se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain); - - return 0; -} - -static void se401_set_exposure(struct usb_se401 *se401, int brightness) -{ - int integration = brightness << 5; - - if (flickerless == 50) - integration = integration-integration % 106667; - if (flickerless == 60) - integration = integration-integration % 88889; - se401->brightness = integration >> 5; - se401->expose_h = (integration >> 16) & 0xff; - se401->expose_m = (integration >> 8) & 0xff; - se401->expose_l = integration & 0xff; -} - -static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p) -{ - p->brightness = se401->brightness; - if (se401->enhance) - p->whiteness = 32768; - else - p->whiteness = 0; - - p->colour = 65535; - p->contrast = 65535; - p->hue = se401->rgain << 10; - p->palette = se401->palette; - p->depth = 3; /* rgb24 */ - return 0; -} - - -static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p) -{ - if (p->palette != VIDEO_PALETTE_RGB24) - return 1; - se401->palette = p->palette; - if (p->hue != se401->hue) { - se401->rgain = p->hue >> 10; - se401->bgain = 0x40-(p->hue >> 10); - se401->hue = p->hue; - } - if (p->brightness != se401->brightness) - se401_set_exposure(se401, p->brightness); - - if (p->whiteness >= 32768) - se401->enhance = 1; - else - se401->enhance = 0; - se401_send_pict(se401); - se401_send_pict(se401); - return 0; -} - -/* - Hyundai have some really nice docs about this and other sensor related - stuff on their homepage: www.hei.co.kr -*/ -static void se401_auto_resetlevel(struct usb_se401 *se401) -{ - unsigned int ahrc, alrc; - int oldreset = se401->resetlevel; - - /* For some reason this normally read-only register doesn't get reset - to zero after reading them just once... - */ - se401_get_feature(se401, HV7131_REG_HIREFNOH); - se401_get_feature(se401, HV7131_REG_HIREFNOL); - se401_get_feature(se401, HV7131_REG_LOREFNOH); - se401_get_feature(se401, HV7131_REG_LOREFNOL); - ahrc = 256*se401_get_feature(se401, HV7131_REG_HIREFNOH) + - se401_get_feature(se401, HV7131_REG_HIREFNOL); - alrc = 256*se401_get_feature(se401, HV7131_REG_LOREFNOH) + - se401_get_feature(se401, HV7131_REG_LOREFNOL); - - /* Not an exact science, but it seems to work pretty well... */ - if (alrc > 10) { - while (alrc >= 10 && se401->resetlevel < 63) { - se401->resetlevel++; - alrc /= 2; - } - } else if (ahrc > 20) { - while (ahrc >= 20 && se401->resetlevel > 0) { - se401->resetlevel--; - ahrc /= 2; - } - } - if (se401->resetlevel != oldreset) - se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel); - - return; -} - -/* irq handler for snapshot button */ -static void se401_button_irq(struct urb *urb) -{ - struct usb_se401 *se401 = urb->context; - int status; - - if (!se401->dev) { - dev_info(&urb->dev->dev, "device vapourished\n"); - return; - } - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, urb->status); - return; - default: - dbg("%s - nonzero urb status received: %d", - __func__, urb->status); - goto exit; - } - - if (urb->actual_length >= 2) - if (se401->button) - se401->buttonpressed = 1; -exit: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - err("%s - usb_submit_urb failed with result %d", - __func__, status); -} - -static void se401_video_irq(struct urb *urb) -{ - struct usb_se401 *se401 = urb->context; - int length = urb->actual_length; - - /* ohoh... */ - if (!se401->streaming) - return; - - if (!se401->dev) { - dev_info(&urb->dev->dev, "device vapourished\n"); - return; - } - - /* 0 sized packets happen if we are to fast, but sometimes the camera - keeps sending them forever... - */ - if (length && !urb->status) { - se401->nullpackets = 0; - switch (se401->scratch[se401->scratch_next].state) { - case BUFFER_READY: - case BUFFER_BUSY: - se401->dropped++; - break; - case BUFFER_UNUSED: - memcpy(se401->scratch[se401->scratch_next].data, - (unsigned char *)urb->transfer_buffer, length); - se401->scratch[se401->scratch_next].state - = BUFFER_READY; - se401->scratch[se401->scratch_next].offset - = se401->bayeroffset; - se401->scratch[se401->scratch_next].length = length; - if (waitqueue_active(&se401->wq)) - wake_up_interruptible(&se401->wq); - se401->scratch_overflow = 0; - se401->scratch_next++; - if (se401->scratch_next >= SE401_NUMSCRATCH) - se401->scratch_next = 0; - break; - } - se401->bayeroffset += length; - if (se401->bayeroffset >= se401->cheight * se401->cwidth) - se401->bayeroffset = 0; - } else { - se401->nullpackets++; - if (se401->nullpackets > SE401_MAX_NULLPACKETS) - if (waitqueue_active(&se401->wq)) - wake_up_interruptible(&se401->wq); - } - - /* Resubmit urb for new data */ - urb->status = 0; - urb->dev = se401->dev; - if (usb_submit_urb(urb, GFP_KERNEL)) - dev_info(&urb->dev->dev, "urb burned down\n"); - return; -} - -static void se401_send_size(struct usb_se401 *se401, int width, int height) -{ - int i = 0; - int mode = 0x03; /* No compression */ - int sendheight = height; - int sendwidth = width; - - /* JangGu compression can only be used with the camera supported sizes, - but bayer seems to work with any size that fits on the sensor. - We check if we can use compression with the current size with either - 4 or 16 times subcapturing, if not we use uncompressed bayer data - but this will result in cutouts of the maximum size.... - */ - while (i < se401->sizes && !(se401->width[i] == width && - se401->height[i] == height)) - i++; - while (i < se401->sizes) { - if (se401->width[i] == width * 2 && - se401->height[i] == height * 2) { - sendheight = se401->height[i]; - sendwidth = se401->width[i]; - mode = 0x40; - } - if (se401->width[i] == width * 4 && - se401->height[i] == height * 4) { - sendheight = se401->height[i]; - sendwidth = se401->width[i]; - mode = 0x42; - } - i++; - } - - se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0); - se401_set_feature(se401, SE401_OPERATINGMODE, mode); - - if (mode == 0x03) - se401->format = FMT_BAYER; - else - se401->format = FMT_JANGGU; -} - -/* - In this function se401_send_pict is called several times, - for some reason (depending on the state of the sensor and the phase of - the moon :) doing this only in either place doesn't always work... -*/ -static int se401_start_stream(struct usb_se401 *se401) -{ - struct urb *urb; - int err = 0, i; - se401->streaming = 1; - - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); - - /* Set picture settings */ - /* windowed + pix intg */ - se401_set_feature(se401, HV7131_REG_MODE_B, 0x05); - se401_send_pict(se401); - - se401_send_size(se401, se401->cwidth, se401->cheight); - - se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, - 0, NULL, 0); - - /* Do some memory allocation */ - for (i = 0; i < SE401_NUMFRAMES; i++) { - se401->frame[i].data = se401->fbuf + i * se401->maxframesize; - se401->frame[i].curpix = 0; - } - for (i = 0; i < SE401_NUMSBUF; i++) { - se401->sbuf[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL); - if (!se401->sbuf[i].data) { - for (i = i - 1; i >= 0; i--) { - kfree(se401->sbuf[i].data); - se401->sbuf[i].data = NULL; - } - return -ENOMEM; - } - } - - se401->bayeroffset = 0; - se401->scratch_next = 0; - se401->scratch_use = 0; - se401->scratch_overflow = 0; - for (i = 0; i < SE401_NUMSCRATCH; i++) { - se401->scratch[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL); - if (!se401->scratch[i].data) { - for (i = i - 1; i >= 0; i--) { - kfree(se401->scratch[i].data); - se401->scratch[i].data = NULL; - } - goto nomem_sbuf; - } - se401->scratch[i].state = BUFFER_UNUSED; - } - - for (i = 0; i < SE401_NUMSBUF; i++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - for (i = i - 1; i >= 0; i--) { - usb_kill_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i] = NULL; - } - goto nomem_scratch; - } - - usb_fill_bulk_urb(urb, se401->dev, - usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT), - se401->sbuf[i].data, SE401_PACKETSIZE, - se401_video_irq, - se401); - - se401->urb[i] = urb; - - err = usb_submit_urb(se401->urb[i], GFP_KERNEL); - if (err) - err("urb burned down"); - } - - se401->framecount = 0; - - return 0; - - nomem_scratch: - for (i = 0; i < SE401_NUMSCRATCH; i++) { - kfree(se401->scratch[i].data); - se401->scratch[i].data = NULL; - } - nomem_sbuf: - for (i = 0; i < SE401_NUMSBUF; i++) { - kfree(se401->sbuf[i].data); - se401->sbuf[i].data = NULL; - } - return -ENOMEM; -} - -static int se401_stop_stream(struct usb_se401 *se401) -{ - int i; - - if (!se401->streaming || !se401->dev) - return 1; - - se401->streaming = 0; - - se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0); - - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); - - for (i = 0; i < SE401_NUMSBUF; i++) - if (se401->urb[i]) { - usb_kill_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i] = NULL; - kfree(se401->sbuf[i].data); - } - for (i = 0; i < SE401_NUMSCRATCH; i++) { - kfree(se401->scratch[i].data); - se401->scratch[i].data = NULL; - } - - return 0; -} - -static int se401_set_size(struct usb_se401 *se401, int width, int height) -{ - int wasstreaming = se401->streaming; - /* Check to see if we need to change */ - if (se401->cwidth == width && se401->cheight == height) - return 0; - - /* Check for a valid mode */ - if (!width || !height) - return 1; - if ((width & 1) || (height & 1)) - return 1; - if (width > se401->width[se401->sizes-1]) - return 1; - if (height > se401->height[se401->sizes-1]) - return 1; - - /* Stop a current stream and start it again at the new size */ - if (wasstreaming) - se401_stop_stream(se401); - se401->cwidth = width; - se401->cheight = height; - if (wasstreaming) - se401_start_stream(se401); - return 0; -} - - -/**************************************************************************** - * - * Video Decoding - * - ***************************************************************************/ - -/* - This shouldn't really be done in a v4l driver.... - But it does make the image look a lot more usable. - Basically it lifts the dark pixels more than the light pixels. -*/ -static inline void enhance_picture(unsigned char *frame, int len) -{ - while (len--) { - *frame = (((*frame^255)*(*frame^255))/255)^255; - frame++; - } -} - -static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data) -{ - struct se401_frame *frame = &se401->frame[se401->curframe]; - int linelength = se401->cwidth * 3; - - if (frame->curlinepix >= linelength) { - frame->curlinepix = 0; - frame->curline += linelength; - } - - /* First three are absolute, all others relative. - * Format is rgb from right to left (mirrorred image), - * we flip it to get bgr from left to right. */ - if (frame->curlinepix < 3) - *(frame->curline-frame->curlinepix) = 1 + data * 4; - else - *(frame->curline-frame->curlinepix) = - *(frame->curline-frame->curlinepix + 3) + data * 4; - frame->curlinepix++; -} - -static inline void decode_JangGu_vlc(struct usb_se401 *se401, - unsigned char *data, int bit_exp, int packetlength) -{ - int pos = 0; - int vlc_cod = 0; - int vlc_size = 0; - int vlc_data = 0; - int bit_cur; - int bit; - data += 4; - while (pos < packetlength) { - bit_cur = 8; - while (bit_cur && bit_exp) { - bit = ((*data) >> (bit_cur-1))&1; - if (!vlc_cod) { - if (bit) { - vlc_size++; - } else { - if (!vlc_size) - decode_JangGu_integrate(se401, 0); - else { - vlc_cod = 2; - vlc_data = 0; - } - } - } else { - if (vlc_cod == 2) { - if (!bit) - vlc_data = -(1 << vlc_size) + 1; - vlc_cod--; - } - vlc_size--; - vlc_data += bit << vlc_size; - if (!vlc_size) { - decode_JangGu_integrate(se401, vlc_data); - vlc_cod = 0; - } - } - bit_cur--; - bit_exp--; - } - pos++; - data++; - } -} - -static inline void decode_JangGu(struct usb_se401 *se401, - struct se401_scratch *buffer) -{ - unsigned char *data = buffer->data; - int len = buffer->length; - int bit_exp = 0, pix_exp = 0, frameinfo = 0, packetlength = 0, size; - int datapos = 0; - - /* New image? */ - if (!se401->frame[se401->curframe].curpix) { - se401->frame[se401->curframe].curlinepix = 0; - se401->frame[se401->curframe].curline = - se401->frame[se401->curframe].data+ - se401->cwidth * 3 - 1; - if (se401->frame[se401->curframe].grabstate == FRAME_READY) - se401->frame[se401->curframe].grabstate = FRAME_GRABBING; - se401->vlcdatapos = 0; - } - while (datapos < len) { - size = 1024 - se401->vlcdatapos; - if (size+datapos > len) - size = len-datapos; - memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size); - se401->vlcdatapos += size; - packetlength = 0; - if (se401->vlcdatapos >= 4) { - bit_exp = se401->vlcdata[3] + (se401->vlcdata[2] << 8); - pix_exp = se401->vlcdata[1] + - ((se401->vlcdata[0] & 0x3f) << 8); - frameinfo = se401->vlcdata[0] & 0xc0; - packetlength = ((bit_exp + 47) >> 4) << 1; - if (packetlength > 1024) { - se401->vlcdatapos = 0; - datapos = len; - packetlength = 0; - se401->error++; - se401->frame[se401->curframe].curpix = 0; - } - } - if (packetlength && se401->vlcdatapos >= packetlength) { - decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, - packetlength); - se401->frame[se401->curframe].curpix += pix_exp * 3; - datapos += size-(se401->vlcdatapos-packetlength); - se401->vlcdatapos = 0; - if (se401->frame[se401->curframe].curpix >= se401->cwidth * se401->cheight * 3) { - if (se401->frame[se401->curframe].curpix == se401->cwidth * se401->cheight * 3) { - if (se401->frame[se401->curframe].grabstate == FRAME_GRABBING) { - se401->frame[se401->curframe].grabstate = FRAME_DONE; - se401->framecount++; - se401->readcount++; - } - if (se401->frame[(se401->curframe + 1) & (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) - se401->curframe = (se401->curframe + 1) & (SE401_NUMFRAMES - 1); - } else - se401->error++; - se401->frame[se401->curframe].curpix = 0; - datapos = len; - } - } else - datapos += size; - } -} - -static inline void decode_bayer(struct usb_se401 *se401, - struct se401_scratch *buffer) -{ - unsigned char *data = buffer->data; - int len = buffer->length; - int offset = buffer->offset; - int datasize = se401->cwidth * se401->cheight; - struct se401_frame *frame = &se401->frame[se401->curframe]; - unsigned char *framedata = frame->data, *curline, *nextline; - int width = se401->cwidth; - int blineoffset = 0, bline; - int linelength = width * 3, i; - - - if (frame->curpix == 0) { - if (frame->grabstate == FRAME_READY) - frame->grabstate = FRAME_GRABBING; - - frame->curline = framedata + linelength; - frame->curlinepix = 0; - } - - if (offset != frame->curpix) { - /* Regard frame as lost :( */ - frame->curpix = 0; - se401->error++; - return; - } - - /* Check if we have to much data */ - if (frame->curpix + len > datasize) - len = datasize-frame->curpix; - - if (se401->cheight % 4) - blineoffset = 1; - bline = frame->curpix / se401->cwidth+blineoffset; - - curline = frame->curline; - nextline = curline + linelength; - if (nextline >= framedata+datasize * 3) - nextline = curline; - while (len) { - if (frame->curlinepix >= width) { - frame->curlinepix -= width; - bline = frame->curpix / width + blineoffset; - curline += linelength*2; - nextline += linelength*2; - if (curline >= framedata+datasize * 3) { - frame->curlinepix++; - curline -= 3; - nextline -= 3; - len--; - data++; - frame->curpix++; - } - if (nextline >= framedata+datasize*3) - nextline = curline; - } - if (bline & 1) { - if (frame->curlinepix & 1) { - *(curline + 2) = *data; - *(curline - 1) = *data; - *(nextline + 2) = *data; - *(nextline - 1) = *data; - } else { - *(curline + 1) = - (*(curline + 1) + *data) / 2; - *(curline-2) = - (*(curline - 2) + *data) / 2; - *(nextline + 1) = *data; - *(nextline - 2) = *data; - } - } else { - if (frame->curlinepix & 1) { - *(curline + 1) = - (*(curline + 1) + *data) / 2; - *(curline - 2) = - (*(curline - 2) + *data) / 2; - *(nextline + 1) = *data; - *(nextline - 2) = *data; - } else { - *curline = *data; - *(curline - 3) = *data; - *nextline = *data; - *(nextline - 3) = *data; - } - } - frame->curlinepix++; - curline -= 3; - nextline -= 3; - len--; - data++; - frame->curpix++; - } - frame->curline = curline; - - if (frame->curpix >= datasize) { - /* Fix the top line */ - framedata += linelength; - for (i = 0; i < linelength; i++) { - framedata--; - *framedata = *(framedata + linelength); - } - /* Fix the left side (green is already present) */ - for (i = 0; i < se401->cheight; i++) { - *framedata = *(framedata + 3); - *(framedata + 1) = *(framedata + 4); - *(framedata + 2) = *(framedata + 5); - framedata += linelength; - } - frame->curpix = 0; - frame->grabstate = FRAME_DONE; - se401->framecount++; - se401->readcount++; - if (se401->frame[(se401->curframe + 1) & - (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) { - se401->curframe = (se401->curframe+1) & - (SE401_NUMFRAMES-1); - } - } -} - -static int se401_newframe(struct usb_se401 *se401, int framenr) -{ - DECLARE_WAITQUEUE(wait, current); - int errors = 0; - - while (se401->streaming && - (se401->frame[framenr].grabstate == FRAME_READY || - se401->frame[framenr].grabstate == FRAME_GRABBING)) { - if (!se401->frame[framenr].curpix) - errors++; - - wait_interruptible( - se401->scratch[se401->scratch_use].state != BUFFER_READY, - &se401->wq, &wait); - if (se401->nullpackets > SE401_MAX_NULLPACKETS) { - se401->nullpackets = 0; - dev_info(&se401->dev->dev, - "too many null length packets, restarting capture\n"); - se401_stop_stream(se401); - se401_start_stream(se401); - } else { - if (se401->scratch[se401->scratch_use].state != - BUFFER_READY) { - se401->frame[framenr].grabstate = FRAME_ERROR; - return -EIO; - } - se401->scratch[se401->scratch_use].state = BUFFER_BUSY; - if (se401->format == FMT_JANGGU) - decode_JangGu(se401, - &se401->scratch[se401->scratch_use]); - else - decode_bayer(se401, - &se401->scratch[se401->scratch_use]); - - se401->scratch[se401->scratch_use].state = - BUFFER_UNUSED; - se401->scratch_use++; - if (se401->scratch_use >= SE401_NUMSCRATCH) - se401->scratch_use = 0; - if (errors > SE401_MAX_ERRORS) { - errors = 0; - dev_info(&se401->dev->dev, - "too many errors, restarting capture\n"); - se401_stop_stream(se401); - se401_start_stream(se401); - } - } - } - - if (se401->frame[framenr].grabstate == FRAME_DONE) - if (se401->enhance) - enhance_picture(se401->frame[framenr].data, - se401->cheight * se401->cwidth * 3); - return 0; -} - -static void usb_se401_remove_disconnected(struct usb_se401 *se401) -{ - int i; - - se401->dev = NULL; - - for (i = 0; i < SE401_NUMSBUF; i++) - if (se401->urb[i]) { - usb_kill_urb(se401->urb[i]); - usb_free_urb(se401->urb[i]); - se401->urb[i] = NULL; - kfree(se401->sbuf[i].data); - } - - for (i = 0; i < SE401_NUMSCRATCH; i++) - kfree(se401->scratch[i].data); - - if (se401->inturb) { - usb_kill_urb(se401->inturb); - usb_free_urb(se401->inturb); - } - dev_info(&se401->dev->dev, "%s disconnected", se401->camera_name); - - /* Free the memory */ - kfree(se401->width); - kfree(se401->height); - kfree(se401); -} - - - -/**************************************************************************** - * - * Video4Linux - * - ***************************************************************************/ - - -static int se401_open(struct file *file) -{ - struct video_device *dev = video_devdata(file); - struct usb_se401 *se401 = (struct usb_se401 *)dev; - int err = 0; - - mutex_lock(&se401->lock); - if (se401->user) { - mutex_unlock(&se401->lock); - return -EBUSY; - } - se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES); - if (se401->fbuf) - file->private_data = dev; - else - err = -ENOMEM; - se401->user = !err; - mutex_unlock(&se401->lock); - - return err; -} - -static int se401_close(struct file *file) -{ - struct video_device *dev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)dev; - int i; - - rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES); - if (se401->removed) { - dev_info(&se401->dev->dev, "device unregistered\n"); - usb_se401_remove_disconnected(se401); - } else { - for (i = 0; i < SE401_NUMFRAMES; i++) - se401->frame[i].grabstate = FRAME_UNUSED; - if (se401->streaming) - se401_stop_stream(se401); - se401->user = 0; - } - file->private_data = NULL; - return 0; -} - -static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg) -{ - struct video_device *vdev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)vdev; - - if (!se401->dev) - return -EIO; - - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - strcpy(b->name, se401->camera_name); - b->type = VID_TYPE_CAPTURE; - b->channels = 1; - b->audios = 0; - b->maxwidth = se401->width[se401->sizes-1]; - b->maxheight = se401->height[se401->sizes-1]; - b->minwidth = se401->width[0]; - b->minheight = se401->height[0]; - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - - if (v->channel != 0) - return -EINVAL; - return 0; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - - se401_get_pict(se401, p); - return 0; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - - if (se401_set_pict(se401, p)) - return -EINVAL; - return 0; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; - if (se401_set_size(se401, vw->width, vw->height)) - return -EINVAL; - return 0; - } - case VIDIOCGWIN: - { - struct video_window *vw = arg; - - vw->x = 0; /* FIXME */ - vw->y = 0; - vw->chromakey = 0; - vw->flags = 0; - vw->clipcount = 0; - vw->width = se401->cwidth; - vw->height = se401->cheight; - return 0; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - int i; - - memset(vm, 0, sizeof(*vm)); - vm->size = SE401_NUMFRAMES * se401->maxframesize; - vm->frames = SE401_NUMFRAMES; - for (i = 0; i < SE401_NUMFRAMES; i++) - vm->offsets[i] = se401->maxframesize * i; - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - - if (vm->format != VIDEO_PALETTE_RGB24) - return -EINVAL; - if (vm->frame >= SE401_NUMFRAMES) - return -EINVAL; - if (se401->frame[vm->frame].grabstate != FRAME_UNUSED) - return -EBUSY; - - /* Is this according to the v4l spec??? */ - if (se401_set_size(se401, vm->width, vm->height)) - return -EINVAL; - se401->frame[vm->frame].grabstate = FRAME_READY; - - if (!se401->streaming) - se401_start_stream(se401); - - /* Set the picture properties */ - if (se401->framecount == 0) - se401_send_pict(se401); - /* Calibrate the reset level after a few frames. */ - if (se401->framecount % 20 == 1) - se401_auto_resetlevel(se401); - - return 0; - } - case VIDIOCSYNC: - { - int *frame = arg; - int ret = 0; - - if (*frame < 0 || *frame >= SE401_NUMFRAMES) - return -EINVAL; - - ret = se401_newframe(se401, *frame); - se401->frame[*frame].grabstate = FRAME_UNUSED; - return ret; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - - memset(vb, 0, sizeof(*vb)); - return 0; - } - case VIDIOCKEY: - return 0; - case VIDIOCCAPTURE: - return -EINVAL; - case VIDIOCSFBUF: - return -EINVAL; - case VIDIOCGTUNER: - case VIDIOCSTUNER: - return -EINVAL; - case VIDIOCGFREQ: - case VIDIOCSFREQ: - return -EINVAL; - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return -EINVAL; - default: - return -ENOIOCTLCMD; - } /* end switch */ - - return 0; -} - -static long se401_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(file, cmd, arg, se401_do_ioctl); -} - -static ssize_t se401_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - int realcount = count, ret = 0; - struct video_device *dev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)dev; - - - if (se401->dev == NULL) - return -EIO; - if (realcount > se401->cwidth*se401->cheight*3) - realcount = se401->cwidth*se401->cheight*3; - - /* Shouldn't happen: */ - if (se401->frame[0].grabstate == FRAME_GRABBING) - return -EBUSY; - se401->frame[0].grabstate = FRAME_READY; - se401->frame[1].grabstate = FRAME_UNUSED; - se401->curframe = 0; - - if (!se401->streaming) - se401_start_stream(se401); - - /* Set the picture properties */ - if (se401->framecount == 0) - se401_send_pict(se401); - /* Calibrate the reset level after a few frames. */ - if (se401->framecount%20 == 1) - se401_auto_resetlevel(se401); - - ret = se401_newframe(se401, 0); - - se401->frame[0].grabstate = FRAME_UNUSED; - if (ret) - return ret; - if (copy_to_user(buf, se401->frame[0].data, realcount)) - return -EFAULT; - - return realcount; -} - -static int se401_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *dev = file->private_data; - struct usb_se401 *se401 = (struct usb_se401 *)dev; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - - mutex_lock(&se401->lock); - - if (se401->dev == NULL) { - mutex_unlock(&se401->lock); - return -EIO; - } - if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) - & ~(PAGE_SIZE - 1))) { - mutex_unlock(&se401->lock); - return -EINVAL; - } - pos = (unsigned long)se401->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&se401->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } - mutex_unlock(&se401->lock); - - return 0; -} - -static const struct v4l2_file_operations se401_fops = { - .owner = THIS_MODULE, - .open = se401_open, - .release = se401_close, - .read = se401_read, - .mmap = se401_mmap, - .ioctl = se401_ioctl, -}; -static struct video_device se401_template = { - .name = "se401 USB camera", - .fops = &se401_fops, - .release = video_device_release_empty, -}; - - - -/***************************/ -static int se401_init(struct usb_se401 *se401, int button) -{ - int i = 0, rc; - unsigned char cp[0x40]; - char temp[200]; - int slen; - - /* led on */ - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); - - /* get camera descriptor */ - rc = se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, - cp, sizeof(cp)); - if (cp[1] != 0x41) { - err("Wrong descriptor type"); - return 1; - } - slen = snprintf(temp, 200, "ExtraFeatures: %d", cp[3]); - - se401->sizes = cp[4] + cp[5] * 256; - se401->width = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); - if (!se401->width) - return 1; - se401->height = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL); - if (!se401->height) { - kfree(se401->width); - return 1; - } - for (i = 0; i < se401->sizes; i++) { - se401->width[i] = cp[6 + i * 4 + 0] + cp[6 + i*4 + 1] * 256; - se401->height[i] = cp[6 + i * 4 + 2] + cp[6 + i * 4 + 3] * 256; - } - slen += snprintf(temp + slen, 200 - slen, " Sizes:"); - for (i = 0; i < se401->sizes; i++) { - slen += snprintf(temp + slen, 200 - slen, - " %dx%d", se401->width[i], se401->height[i]); - } - dev_info(&se401->dev->dev, "%s\n", temp); - se401->maxframesize = se401->width[se401->sizes-1] * - se401->height[se401->sizes - 1] * 3; - - rc = se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp)); - se401->cwidth = cp[0]+cp[1]*256; - rc = se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp)); - se401->cheight = cp[0]+cp[1]*256; - - if (!(cp[2] & SE401_FORMAT_BAYER)) { - err("Bayer format not supported!"); - return 1; - } - /* set output mode (BAYER) */ - se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, - SE401_FORMAT_BAYER, NULL, 0); - - rc = se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp)); - se401->brightness = cp[0]+cp[1]*256; - /* some default values */ - se401->resetlevel = 0x2d; - se401->rgain = 0x20; - se401->ggain = 0x20; - se401->bgain = 0x20; - se401_set_exposure(se401, 20000); - se401->palette = VIDEO_PALETTE_RGB24; - se401->enhance = 1; - se401->dropped = 0; - se401->error = 0; - se401->framecount = 0; - se401->readcount = 0; - - /* Start interrupt transfers for snapshot button */ - if (button) { - se401->inturb = usb_alloc_urb(0, GFP_KERNEL); - if (!se401->inturb) { - dev_info(&se401->dev->dev, - "Allocation of inturb failed\n"); - return 1; - } - usb_fill_int_urb(se401->inturb, se401->dev, - usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT), - &se401->button, sizeof(se401->button), - se401_button_irq, - se401, - 8 - ); - if (usb_submit_urb(se401->inturb, GFP_KERNEL)) { - dev_info(&se401->dev->dev, "int urb burned down\n"); - return 1; - } - } else - se401->inturb = NULL; - - /* Flash the led */ - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0); - se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0); - - return 0; -} - -static int se401_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_interface_descriptor *interface; - struct usb_se401 *se401; - char *camera_name = NULL; - int button = 1; - - /* We don't handle multi-config cameras */ - if (dev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - interface = &intf->cur_altsetting->desc; - - /* Is it an se401? */ - if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 && - le16_to_cpu(dev->descriptor.idProduct) == 0x0004) { - camera_name = "Endpoints/Aox SE401"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 && - le16_to_cpu(dev->descriptor.idProduct) == 0x030b) { - camera_name = "Philips PCVC665K"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5001) { - camera_name = "Kensington VideoCAM 67014"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5002) { - camera_name = "Kensington VideoCAM 6701(5/7)"; - } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d && - le16_to_cpu(dev->descriptor.idProduct) == 0x5003) { - camera_name = "Kensington VideoCAM 67016"; - button = 0; - } else - return -ENODEV; - - /* Checking vendor/product should be enough, but what the hell */ - if (interface->bInterfaceClass != 0x00) - return -ENODEV; - if (interface->bInterfaceSubClass != 0x00) - return -ENODEV; - - /* We found one */ - dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name); - - se401 = kzalloc(sizeof(*se401), GFP_KERNEL); - if (se401 == NULL) { - err("couldn't kmalloc se401 struct"); - return -ENOMEM; - } - - se401->dev = dev; - se401->iface = interface->bInterfaceNumber; - se401->camera_name = camera_name; - - dev_info(&intf->dev, "firmware version: %02x\n", - le16_to_cpu(dev->descriptor.bcdDevice) & 255); - - if (se401_init(se401, button)) { - kfree(se401); - return -EIO; - } - - memcpy(&se401->vdev, &se401_template, sizeof(se401_template)); - memcpy(se401->vdev.name, se401->camera_name, - strlen(se401->camera_name)); - init_waitqueue_head(&se401->wq); - mutex_init(&se401->lock); - wmb(); - - if (video_register_device(&se401->vdev, - VFL_TYPE_GRABBER, video_nr) < 0) { - kfree(se401); - err("video_register_device failed"); - return -EIO; - } - dev_info(&intf->dev, "registered new video device: %s\n", - video_device_node_name(&se401->vdev)); - - usb_set_intfdata(intf, se401); - return 0; -} - -static void se401_disconnect(struct usb_interface *intf) -{ - struct usb_se401 *se401 = usb_get_intfdata(intf); - - usb_set_intfdata(intf, NULL); - if (se401) { - video_unregister_device(&se401->vdev); - if (!se401->user) - usb_se401_remove_disconnected(se401); - else { - se401->frame[0].grabstate = FRAME_ERROR; - se401->frame[0].grabstate = FRAME_ERROR; - - se401->streaming = 0; - - wake_up_interruptible(&se401->wq); - se401->removed = 1; - } - } -} - -static struct usb_driver se401_driver = { - .name = "se401", - .id_table = device_table, - .probe = se401_probe, - .disconnect = se401_disconnect, -}; - - - -/**************************************************************************** - * - * Module routines - * - ***************************************************************************/ - -static int __init usb_se401_init(void) -{ - printk(KERN_INFO "SE401 usb camera driver version %s registering\n", - version); - if (flickerless) - if (flickerless != 50 && flickerless != 60) { - printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n"); - return -1; - } - return usb_register(&se401_driver); -} - -static void __exit usb_se401_exit(void) -{ - usb_deregister(&se401_driver); - printk(KERN_INFO "SE401 driver deregistered\frame"); -} - -module_init(usb_se401_init); -module_exit(usb_se401_exit); diff --git a/drivers/staging/se401/se401.h b/drivers/staging/se401/se401.h deleted file mode 100644 index 2758f4716c3d..000000000000 --- a/drivers/staging/se401/se401.h +++ /dev/null @@ -1,236 +0,0 @@ - -#ifndef __LINUX_se401_H -#define __LINUX_se401_H - -#include -#include "videodev.h" -#include -#include -#include - -#define se401_DEBUG /* Turn on debug messages */ - -#ifdef se401_DEBUG -# define PDEBUG(level, fmt, args...) \ -if (debug >= level) \ - info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args) -#else -# define PDEBUG(level, fmt, args...) do {} while (0) -#endif - -/* An almost drop-in replacement for sleep_on_interruptible */ -#define wait_interruptible(test, queue, wait) \ -{ \ - add_wait_queue(queue, wait); \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (test) \ - schedule(); \ - remove_wait_queue(queue, wait); \ - set_current_state(TASK_RUNNING); \ - if (signal_pending(current)) \ - break; \ -} - -#define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06 -#define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41 -#define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42 -#define SE401_REQ_CAPTURE_FRAME 0x43 -#define SE401_REQ_GET_BRT 0x44 -#define SE401_REQ_SET_BRT 0x45 -#define SE401_REQ_GET_WIDTH 0x4c -#define SE401_REQ_SET_WIDTH 0x4d -#define SE401_REQ_GET_HEIGHT 0x4e -#define SE401_REQ_SET_HEIGHT 0x4f -#define SE401_REQ_GET_OUTPUT_MODE 0x50 -#define SE401_REQ_SET_OUTPUT_MODE 0x51 -#define SE401_REQ_GET_EXT_FEATURE 0x52 -#define SE401_REQ_SET_EXT_FEATURE 0x53 -#define SE401_REQ_CAMERA_POWER 0x56 -#define SE401_REQ_LED_CONTROL 0x57 -#define SE401_REQ_BIOS 0xff - -#define SE401_BIOS_READ 0x07 - -#define SE401_FORMAT_BAYER 0x40 - -/* Hyundai hv7131b registers - 7121 and 7141 should be the same (haven't really checked...) */ -/* Mode registers: */ -#define HV7131_REG_MODE_A 0x00 -#define HV7131_REG_MODE_B 0x01 -#define HV7131_REG_MODE_C 0x02 -/* Frame registers: */ -#define HV7131_REG_FRSU 0x10 -#define HV7131_REG_FRSL 0x11 -#define HV7131_REG_FCSU 0x12 -#define HV7131_REG_FCSL 0x13 -#define HV7131_REG_FWHU 0x14 -#define HV7131_REG_FWHL 0x15 -#define HV7131_REG_FWWU 0x16 -#define HV7131_REG_FWWL 0x17 -/* Timing registers: */ -#define HV7131_REG_THBU 0x20 -#define HV7131_REG_THBL 0x21 -#define HV7131_REG_TVBU 0x22 -#define HV7131_REG_TVBL 0x23 -#define HV7131_REG_TITU 0x25 -#define HV7131_REG_TITM 0x26 -#define HV7131_REG_TITL 0x27 -#define HV7131_REG_TMCD 0x28 -/* Adjust Registers: */ -#define HV7131_REG_ARLV 0x30 -#define HV7131_REG_ARCG 0x31 -#define HV7131_REG_AGCG 0x32 -#define HV7131_REG_ABCG 0x33 -#define HV7131_REG_APBV 0x34 -#define HV7131_REG_ASLP 0x54 -/* Offset Registers: */ -#define HV7131_REG_OFSR 0x50 -#define HV7131_REG_OFSG 0x51 -#define HV7131_REG_OFSB 0x52 -/* REset level statistics registers: */ -#define HV7131_REG_LOREFNOH 0x57 -#define HV7131_REG_LOREFNOL 0x58 -#define HV7131_REG_HIREFNOH 0x59 -#define HV7131_REG_HIREFNOL 0x5a - -/* se401 registers */ -#define SE401_OPERATINGMODE 0x2000 - - -/* size of usb transfers */ -#define SE401_PACKETSIZE 4096 -/* number of queued bulk transfers to use, should be about 8 */ -#define SE401_NUMSBUF 1 -/* read the usb specs for this one :) */ -#define SE401_VIDEO_ENDPOINT 1 -#define SE401_BUTTON_ENDPOINT 2 -/* number of frames supported by the v4l part */ -#define SE401_NUMFRAMES 2 -/* scratch buffers for passing data to the decoders */ -#define SE401_NUMSCRATCH 32 -/* maximum amount of data in a JangGu packet */ -#define SE401_VLCDATALEN 1024 -/* number of nul sized packets to receive before kicking the camera */ -#define SE401_MAX_NULLPACKETS 4000 -/* number of decoding errors before kicking the camera */ -#define SE401_MAX_ERRORS 200 - -struct usb_device; - -struct se401_sbuf { - unsigned char *data; -}; - -enum { - FRAME_UNUSED, /* Unused (no MCAPTURE) */ - FRAME_READY, /* Ready to start grabbing */ - FRAME_GRABBING, /* In the process of being grabbed into */ - FRAME_DONE, /* Finished grabbing, but not been synced yet */ - FRAME_ERROR, /* Something bad happened while processing */ -}; - -enum { - FMT_BAYER, - FMT_JANGGU, -}; - -enum { - BUFFER_UNUSED, - BUFFER_READY, - BUFFER_BUSY, - BUFFER_DONE, -}; - -struct se401_scratch { - unsigned char *data; - volatile int state; - int offset; - int length; -}; - -struct se401_frame { - unsigned char *data; /* Frame buffer */ - - volatile int grabstate; /* State of grabbing */ - - unsigned char *curline; - int curlinepix; - int curpix; -}; - -struct usb_se401 { - struct video_device vdev; - - /* Device structure */ - struct usb_device *dev; - - unsigned char iface; - - char *camera_name; - - int change; - int brightness; - int hue; - int rgain; - int ggain; - int bgain; - int expose_h; - int expose_m; - int expose_l; - int resetlevel; - - int enhance; - - int format; - int sizes; - int *width; - int *height; - int cwidth; /* current width */ - int cheight; /* current height */ - int palette; - int maxframesize; - int cframesize; /* current framesize */ - - struct mutex lock; - int user; /* user count for exclusive use */ - int removed; /* device disconnected */ - - int streaming; /* Are we streaming video? */ - - char *fbuf; /* Videodev buffer area */ - - struct urb *urb[SE401_NUMSBUF]; - struct urb *inturb; - - int button; - int buttonpressed; - - int curframe; /* Current receiving frame */ - struct se401_frame frame[SE401_NUMFRAMES]; - int readcount; - int framecount; - int error; - int dropped; - - int scratch_next; - int scratch_use; - int scratch_overflow; - struct se401_scratch scratch[SE401_NUMSCRATCH]; - - /* Decoder specific data: */ - unsigned char vlcdata[SE401_VLCDATALEN]; - int vlcdatapos; - int bayeroffset; - - struct se401_sbuf sbuf[SE401_NUMSBUF]; - - wait_queue_head_t wq; /* Processes waiting */ - - int nullpackets; -}; - - - -#endif - diff --git a/drivers/staging/se401/videodev.h b/drivers/staging/se401/videodev.h deleted file mode 100644 index f11efbef1c05..000000000000 --- a/drivers/staging/se401/videodev.h +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Video for Linux version 1 - OBSOLETE - * - * Header file for v4l1 drivers and applications, for - * Linux kernels 2.2.x or 2.4.x. - * - * Provides header for legacy drivers and applications - * - * See http://linuxtv.org for more info - * - */ -#ifndef __LINUX_VIDEODEV_H -#define __LINUX_VIDEODEV_H - -#include -#include -#include - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ - -struct video_capability -{ - char name[32]; - int type; - int channels; /* Num channels */ - int audios; /* Num audio devices */ - int maxwidth; /* Supported width */ - int maxheight; /* And height */ - int minwidth; /* Supported width */ - int minheight; /* And height */ -}; - - -struct video_channel -{ - int channel; - char name[32]; - int tuners; - __u32 flags; -#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ -#define VIDEO_VC_AUDIO 2 /* Channel has audio */ - __u16 type; -#define VIDEO_TYPE_TV 1 -#define VIDEO_TYPE_CAMERA 2 - __u16 norm; /* Norm set by channel */ -}; - -struct video_tuner -{ - int tuner; - char name[32]; - unsigned long rangelow, rangehigh; /* Tuner range */ - __u32 flags; -#define VIDEO_TUNER_PAL 1 -#define VIDEO_TUNER_NTSC 2 -#define VIDEO_TUNER_SECAM 4 -#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ -#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ -#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ -#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ -#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ - __u16 mode; /* PAL/NTSC/SECAM/OTHER */ -#define VIDEO_MODE_PAL 0 -#define VIDEO_MODE_NTSC 1 -#define VIDEO_MODE_SECAM 2 -#define VIDEO_MODE_AUTO 3 - __u16 signal; /* Signal strength 16bit scale */ -}; - -struct video_picture -{ - __u16 brightness; - __u16 hue; - __u16 colour; - __u16 contrast; - __u16 whiteness; /* Black and white only */ - __u16 depth; /* Capture depth */ - __u16 palette; /* Palette in use */ -#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ -#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ -#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ -#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ -#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ -#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ -#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ -#define VIDEO_PALETTE_YUYV 8 -#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ -#define VIDEO_PALETTE_YUV420 10 -#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ -#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ -#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ -#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ -#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ -#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ -#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ -#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ -}; - -struct video_audio -{ - int audio; /* Audio channel */ - __u16 volume; /* If settable */ - __u16 bass, treble; - __u32 flags; -#define VIDEO_AUDIO_MUTE 1 -#define VIDEO_AUDIO_MUTABLE 2 -#define VIDEO_AUDIO_VOLUME 4 -#define VIDEO_AUDIO_BASS 8 -#define VIDEO_AUDIO_TREBLE 16 -#define VIDEO_AUDIO_BALANCE 32 - char name[16]; -#define VIDEO_SOUND_MONO 1 -#define VIDEO_SOUND_STEREO 2 -#define VIDEO_SOUND_LANG1 4 -#define VIDEO_SOUND_LANG2 8 - __u16 mode; - __u16 balance; /* Stereo balance */ - __u16 step; /* Step actual volume uses */ -}; - -struct video_clip -{ - __s32 x,y; - __s32 width, height; - struct video_clip *next; /* For user use/driver use only */ -}; - -struct video_window -{ - __u32 x,y; /* Position of window */ - __u32 width,height; /* Its size */ - __u32 chromakey; - __u32 flags; - struct video_clip __user *clips; /* Set only */ - int clipcount; -#define VIDEO_WINDOW_INTERLACE 1 -#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ -#define VIDEO_CLIP_BITMAP -1 -/* bitmap is 1024x625, a '1' bit represents a clipped pixel */ -#define VIDEO_CLIPMAP_SIZE (128 * 625) -}; - -struct video_capture -{ - __u32 x,y; /* Offsets into image */ - __u32 width, height; /* Area to capture */ - __u16 decimation; /* Decimation divider */ - __u16 flags; /* Flags for capture */ -#define VIDEO_CAPTURE_ODD 0 /* Temporal */ -#define VIDEO_CAPTURE_EVEN 1 -}; - -struct video_buffer -{ - void *base; - int height,width; - int depth; - int bytesperline; -}; - -struct video_mmap -{ - unsigned int frame; /* Frame (0 - n) for double buffer */ - int height,width; - unsigned int format; /* should be VIDEO_PALETTE_* */ -}; - -struct video_key -{ - __u8 key[8]; - __u32 flags; -}; - -struct video_mbuf -{ - int size; /* Total memory to map */ - int frames; /* Frames */ - int offsets[VIDEO_MAX_FRAME]; -}; - -#define VIDEO_NO_UNIT (-1) - -struct video_unit -{ - int video; /* Video minor */ - int vbi; /* VBI minor */ - int radio; /* Radio minor */ - int audio; /* Audio minor */ - int teletext; /* Teletext minor */ -}; - -struct vbi_format { - __u32 sampling_rate; /* in Hz */ - __u32 samples_per_line; - __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ - __s32 start[2]; /* starting line for each frame */ - __u32 count[2]; /* count of lines for each frame */ - __u32 flags; -#define VBI_UNSYNC 1 /* can distingues between top/bottom field */ -#define VBI_INTERLACED 2 /* lines are interlaced */ -}; - -/* video_info is biased towards hardware mpeg encode/decode */ -/* but it could apply generically to any hardware compressor/decompressor */ -struct video_info -{ - __u32 frame_count; /* frames output since decode/encode began */ - __u32 h_size; /* current unscaled horizontal size */ - __u32 v_size; /* current unscaled veritcal size */ - __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */ - __u32 picture_type; /* current picture type */ - __u32 temporal_reference; /* current temporal reference */ - __u8 user_data[256]; /* user data last found in compressed stream */ - /* user_data[0] contains user data flags, user_data[1] has count */ -}; - -/* generic structure for setting playback modes */ -struct video_play_mode -{ - int mode; - int p1; - int p2; -}; - -/* for loading microcode / fpga programming */ -struct video_code -{ - char loadwhat[16]; /* name or tag of file being passed */ - int datasize; - __u8 *data; -}; - -#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ -#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ -#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ -#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ -#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ -#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ -#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ -#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ -#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ -#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ -#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ -#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ -#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ -#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ -#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ -#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ -#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ -#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ -#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ -#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ -#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ -#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ -#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ -#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ -#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ -#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ -#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ -#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ -#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ - - -#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ - -/* VIDIOCSWRITEMODE */ -#define VID_WRITE_MPEG_AUD 0 -#define VID_WRITE_MPEG_VID 1 -#define VID_WRITE_OSD 2 -#define VID_WRITE_TTX 3 -#define VID_WRITE_CC 4 -#define VID_WRITE_MJPEG 5 - -/* VIDIOCSPLAYMODE */ -#define VID_PLAY_VID_OUT_MODE 0 - /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ -#define VID_PLAY_GENLOCK 1 - /* p1: 0 = OFF, 1 = ON */ - /* p2: GENLOCK FINE DELAY value */ -#define VID_PLAY_NORMAL 2 -#define VID_PLAY_PAUSE 3 -#define VID_PLAY_SINGLE_FRAME 4 -#define VID_PLAY_FAST_FORWARD 5 -#define VID_PLAY_SLOW_MOTION 6 -#define VID_PLAY_IMMEDIATE_NORMAL 7 -#define VID_PLAY_SWITCH_CHANNELS 8 -#define VID_PLAY_FREEZE_FRAME 9 -#define VID_PLAY_STILL_MODE 10 -#define VID_PLAY_MASTER_MODE 11 - /* p1: see below */ -#define VID_PLAY_MASTER_NONE 1 -#define VID_PLAY_MASTER_VIDEO 2 -#define VID_PLAY_MASTER_AUDIO 3 -#define VID_PLAY_ACTIVE_SCANLINES 12 - /* p1 = first active; p2 = last active */ -#define VID_PLAY_RESET 13 -#define VID_PLAY_END_MARK 14 - -#endif /* __LINUX_VIDEODEV_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ -- cgit v1.2.2 From dae86ccbc3c185aebfc396e8e668aa3d73d748d8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 5 Feb 2011 09:29:31 -0300 Subject: [media] dabusb: remove obsolete driver The dabusb driver was conceived as an experimental driver for a test device. The driver never supported any shipped product, and, while there were some updates for it in 2003, for an ancient product, those changes were never submitted upstream. Also, there's no DocBook for its API, nor any upstream discussion. So it was decided to remove it in 2.6.39. Future support for a DAB API should be discussed on the linux-media list first. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/dabusb/Kconfig | 14 - drivers/staging/dabusb/Makefile | 2 - drivers/staging/dabusb/TODO | 5 - drivers/staging/dabusb/dabusb.c | 914 ---------------------------------------- drivers/staging/dabusb/dabusb.h | 85 ---- 7 files changed, 1023 deletions(-) delete mode 100644 drivers/staging/dabusb/Kconfig delete mode 100644 drivers/staging/dabusb/Makefile delete mode 100644 drivers/staging/dabusb/TODO delete mode 100644 drivers/staging/dabusb/dabusb.c delete mode 100644 drivers/staging/dabusb/dabusb.h (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index fa5c007e74c8..a2742d8102c1 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -53,8 +53,6 @@ source "drivers/staging/tm6000/Kconfig" source "drivers/staging/cxd2099/Kconfig" -source "drivers/staging/dabusb/Kconfig" - source "drivers/staging/usbip/Kconfig" source "drivers/staging/winbond/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 2bdd703ed208..4ddd3ce780e0 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_VIDEO_GO7007) += go7007/ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ -obj-$(CONFIG_USB_DABUSB) += dabusb/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_USB_IP_COMMON) += usbip/ obj-$(CONFIG_W35UND) += winbond/ diff --git a/drivers/staging/dabusb/Kconfig b/drivers/staging/dabusb/Kconfig deleted file mode 100644 index 87bdc425d3c5..000000000000 --- a/drivers/staging/dabusb/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config USB_DABUSB - tristate "DABUSB driver" - depends on USB - ---help--- - A Digital Audio Broadcasting (DAB) Receiver for USB and Linux - brought to you by the DAB-Team - . This driver can be taken - as an example for URB-based bulk, control, and isochronous - transactions. URB's are explained in - . - - To compile this driver as a module, choose M here: the - module will be called dabusb. - diff --git a/drivers/staging/dabusb/Makefile b/drivers/staging/dabusb/Makefile deleted file mode 100644 index 2ff2f228e5f9..000000000000 --- a/drivers/staging/dabusb/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_USB_DABUSB) += dabusb.o - diff --git a/drivers/staging/dabusb/TODO b/drivers/staging/dabusb/TODO deleted file mode 100644 index f9c0314ea0c1..000000000000 --- a/drivers/staging/dabusb/TODO +++ /dev/null @@ -1,5 +0,0 @@ -This is a driver for an experimental sample developed in 2003. The driver -never supported any commercial product, nor had any known user. -If nobody takes care on it, the driver will be removed for 2.6.39. - -Please send patches to linux-media@vger.kernel.org diff --git a/drivers/staging/dabusb/dabusb.c b/drivers/staging/dabusb/dabusb.c deleted file mode 100644 index f3e25e91366d..000000000000 --- a/drivers/staging/dabusb/dabusb.c +++ /dev/null @@ -1,914 +0,0 @@ -/*****************************************************************************/ - -/* - * dabusb.c -- dab usb driver. - * - * Copyright (C) 1999 Deti Fliegl (deti@fliegl.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * - * $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $ - * - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dabusb.h" - -/* - * Version Information - */ -#define DRIVER_VERSION "v1.54" -#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de" -#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999" - -/* --------------------------------------------------------------------- */ - -#ifdef CONFIG_USB_DYNAMIC_MINORS -#define NRDABUSB 256 -#else -#define NRDABUSB 4 -#endif - -/*-------------------------------------------------------------------*/ - -static dabusb_t dabusb[NRDABUSB]; -static int buffers = 256; -static struct usb_driver dabusb_driver; - -/*-------------------------------------------------------------------*/ - -static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src) -{ - unsigned long flags; - struct list_head *tmp; - int ret = 0; - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty (src)) { - // no elements in source buffer - ret = -1; - goto err; - } - tmp = src->next; - list_move_tail (tmp, dst); - - err: spin_unlock_irqrestore (&s->lock, flags); - return ret; -} -/*-------------------------------------------------------------------*/ -#ifdef DEBUG -static void dump_urb (struct urb *urb) -{ - dbg("urb :%p", urb); - dbg("dev :%p", urb->dev); - dbg("pipe :%08X", urb->pipe); - dbg("status :%d", urb->status); - dbg("transfer_flags :%08X", urb->transfer_flags); - dbg("transfer_buffer :%p", urb->transfer_buffer); - dbg("transfer_buffer_length:%d", urb->transfer_buffer_length); - dbg("actual_length :%d", urb->actual_length); - dbg("setup_packet :%p", urb->setup_packet); - dbg("start_frame :%d", urb->start_frame); - dbg("number_of_packets :%d", urb->number_of_packets); - dbg("interval :%d", urb->interval); - dbg("error_count :%d", urb->error_count); - dbg("context :%p", urb->context); - dbg("complete :%p", urb->complete); -} -#endif -/*-------------------------------------------------------------------*/ -static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q) -{ - unsigned long flags; - pbuff_t b; - - dbg("dabusb_cancel_queue"); - - spin_lock_irqsave (&s->lock, flags); - - list_for_each_entry(b, q, buff_list) { -#ifdef DEBUG - dump_urb(b->purb); -#endif - usb_unlink_urb (b->purb); - } - spin_unlock_irqrestore (&s->lock, flags); - return 0; -} -/*-------------------------------------------------------------------*/ -static int dabusb_free_queue (struct list_head *q) -{ - struct list_head *tmp; - struct list_head *p; - pbuff_t b; - - dbg("dabusb_free_queue"); - for (p = q->next; p != q;) { - b = list_entry (p, buff_t, buff_list); - -#ifdef DEBUG - dump_urb(b->purb); -#endif - kfree(b->purb->transfer_buffer); - usb_free_urb(b->purb); - tmp = p->next; - list_del (p); - kfree (b); - p = tmp; - } - - return 0; -} -/*-------------------------------------------------------------------*/ -static int dabusb_free_buffers (pdabusb_t s) -{ - unsigned long flags; - dbg("dabusb_free_buffers"); - - spin_lock_irqsave(&s->lock, flags); - - dabusb_free_queue (&s->free_buff_list); - dabusb_free_queue (&s->rec_buff_list); - - spin_unlock_irqrestore(&s->lock, flags); - - s->got_mem = 0; - return 0; -} -/*-------------------------------------------------------------------*/ -static void dabusb_iso_complete (struct urb *purb) -{ - pbuff_t b = purb->context; - pdabusb_t s = b->s; - int i; - int len; - int dst = 0; - void *buf = purb->transfer_buffer; - - dbg("dabusb_iso_complete"); - - // process if URB was not killed - if (purb->status != -ENOENT) { - unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE); - int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe)); - for (i = 0; i < purb->number_of_packets; i++) - if (!purb->iso_frame_desc[i].status) { - len = purb->iso_frame_desc[i].actual_length; - if (len <= pipesize) { - memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len); - dst += len; - } - else - dev_err(&purb->dev->dev, - "dabusb_iso_complete: invalid len %d\n", len); - } - else - dev_warn(&purb->dev->dev, "dabusb_iso_complete: corrupted packet status: %d\n", purb->iso_frame_desc[i].status); - if (dst != purb->actual_length) - dev_err(&purb->dev->dev, - "dst!=purb->actual_length:%d!=%d\n", - dst, purb->actual_length); - } - - if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) { - s->overruns++; - dev_err(&purb->dev->dev, "overrun (%d)\n", s->overruns); - } - wake_up (&s->wait); -} -/*-------------------------------------------------------------------*/ -static int dabusb_alloc_buffers (pdabusb_t s) -{ - int transfer_len = 0; - pbuff_t b; - unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE); - int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe)); - int packets = _ISOPIPESIZE / pipesize; - int transfer_buffer_length = packets * pipesize; - int i; - - dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d", - pipesize, packets, transfer_buffer_length); - - while (transfer_len < (s->total_buffer_size << 10)) { - b = kzalloc(sizeof (buff_t), GFP_KERNEL); - if (!b) { - dev_err(&s->usbdev->dev, - "kzalloc(sizeof(buff_t))==NULL\n"); - goto err; - } - b->s = s; - b->purb = usb_alloc_urb(packets, GFP_KERNEL); - if (!b->purb) { - dev_err(&s->usbdev->dev, "usb_alloc_urb == NULL\n"); - kfree (b); - goto err; - } - - b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL); - if (!b->purb->transfer_buffer) { - kfree (b->purb); - kfree (b); - dev_err(&s->usbdev->dev, - "kmalloc(%d)==NULL\n", transfer_buffer_length); - goto err; - } - - b->purb->transfer_buffer_length = transfer_buffer_length; - b->purb->number_of_packets = packets; - b->purb->complete = dabusb_iso_complete; - b->purb->context = b; - b->purb->dev = s->usbdev; - b->purb->pipe = pipe; - b->purb->transfer_flags = URB_ISO_ASAP; - - for (i = 0; i < packets; i++) { - b->purb->iso_frame_desc[i].offset = i * pipesize; - b->purb->iso_frame_desc[i].length = pipesize; - } - - transfer_len += transfer_buffer_length; - list_add_tail (&b->buff_list, &s->free_buff_list); - } - s->got_mem = transfer_len; - - return 0; - - err: - dabusb_free_buffers (s); - return -ENOMEM; -} -/*-------------------------------------------------------------------*/ -static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb) -{ - int ret; - unsigned int pipe; - int actual_length; - - dbg("dabusb_bulk"); - - if (!pb->pipe) - pipe = usb_rcvbulkpipe (s->usbdev, 2); - else - pipe = usb_sndbulkpipe (s->usbdev, 2); - - ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100); - if(ret<0) { - dev_err(&s->usbdev->dev, - "usb_bulk_msg failed(%d)\n", ret); - - if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { - dev_err(&s->usbdev->dev, "set_interface failed\n"); - return -EINVAL; - } - - } - - if( ret == -EPIPE ) { - dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n"); - if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe))) - dev_err(&s->usbdev->dev, "request failed\n"); - } - - pb->size = actual_length; - return ret; -} -/* --------------------------------------------------------------------- */ -static int dabusb_writemem (pdabusb_t s, int pos, const unsigned char *data, - int len) -{ - int ret; - unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL); - - if (!transfer_buffer) { - dev_err(&s->usbdev->dev, - "dabusb_writemem: kmalloc(%d) failed.\n", len); - return -ENOMEM; - } - - memcpy (transfer_buffer, data, len); - - ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300); - - kfree (transfer_buffer); - return ret; -} -/* --------------------------------------------------------------------- */ -static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit) -{ - dbg("dabusb_8051_reset: %d",reset_bit); - return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1); -} -/* --------------------------------------------------------------------- */ -static int dabusb_loadmem (pdabusb_t s, const char *fname) -{ - int ret; - const struct ihex_binrec *rec; - const struct firmware *uninitialized_var(fw); - - dbg("Enter dabusb_loadmem (internal)"); - - ret = request_ihex_firmware(&fw, "dabusb/firmware.fw", &s->usbdev->dev); - if (ret) { - dev_err(&s->usbdev->dev, - "Failed to load \"dabusb/firmware.fw\": %d\n", ret); - goto out; - } - ret = dabusb_8051_reset (s, 1); - - for (rec = (const struct ihex_binrec *)fw->data; rec; - rec = ihex_next_binrec(rec)) { - dbg("dabusb_writemem: %04X %p %d)", be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len)); - - ret = dabusb_writemem(s, be32_to_cpu(rec->addr), rec->data, - be16_to_cpu(rec->len)); - if (ret < 0) { - dev_err(&s->usbdev->dev, - "dabusb_writemem failed (%d %04X %p %d)\n", - ret, be32_to_cpu(rec->addr), - rec->data, be16_to_cpu(rec->len)); - break; - } - } - ret = dabusb_8051_reset (s, 0); - release_firmware(fw); - out: - dbg("dabusb_loadmem: exit"); - - return ret; -} -/* --------------------------------------------------------------------- */ -static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b) -{ - b->size = 4; - b->data[0] = 0x2a; - b->data[1] = 0; - b->data[2] = 0; - b->data[3] = 0; - - dbg("dabusb_fpga_clear"); - - return dabusb_bulk (s, b); -} -/* --------------------------------------------------------------------- */ -static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b) -{ - b->size = 4; - b->data[0] = 0x2c; - b->data[1] = 0; - b->data[2] = 0; - b->data[3] = 0; - - dbg("dabusb_fpga_init"); - - return dabusb_bulk (s, b); -} -/* --------------------------------------------------------------------- */ -static int dabusb_fpga_download (pdabusb_t s, const char *fname) -{ - pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL); - const struct firmware *fw; - unsigned int blen, n; - int ret; - - dbg("Enter dabusb_fpga_download (internal)"); - - if (!b) { - dev_err(&s->usbdev->dev, - "kmalloc(sizeof(bulk_transfer_t))==NULL\n"); - return -ENOMEM; - } - - ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev); - if (ret) { - dev_err(&s->usbdev->dev, - "Failed to load \"dabusb/bitstream.bin\": %d\n", ret); - kfree(b); - return ret; - } - - b->pipe = 1; - ret = dabusb_fpga_clear (s, b); - mdelay (10); - blen = fw->data[73] + (fw->data[72] << 8); - - dbg("Bitstream len: %i", blen); - - b->data[0] = 0x2b; - b->data[1] = 0; - b->data[2] = 0; - b->data[3] = 60; - - for (n = 0; n <= blen + 60; n += 60) { - // some cclks for startup - b->size = 64; - memcpy (b->data + 4, fw->data + 74 + n, 60); - ret = dabusb_bulk (s, b); - if (ret < 0) { - dev_err(&s->usbdev->dev, "dabusb_bulk failed.\n"); - break; - } - mdelay (1); - } - - ret = dabusb_fpga_init (s, b); - kfree (b); - release_firmware(fw); - - dbg("exit dabusb_fpga_download"); - - return ret; -} - -static int dabusb_stop (pdabusb_t s) -{ - dbg("dabusb_stop"); - - s->state = _stopped; - dabusb_cancel_queue (s, &s->rec_buff_list); - - dbg("pending_io: %d", s->pending_io.counter); - - s->pending_io.counter = 0; - return 0; -} - -static int dabusb_startrek (pdabusb_t s) -{ - if (!s->got_mem && s->state != _started) { - - dbg("dabusb_startrek"); - - if (dabusb_alloc_buffers (s) < 0) - return -ENOMEM; - dabusb_stop (s); - s->state = _started; - s->readptr = 0; - } - - if (!list_empty (&s->free_buff_list)) { - pbuff_t end; - int ret; - - while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) { - - dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list); - - end = list_entry (s->rec_buff_list.prev, buff_t, buff_list); - - ret = usb_submit_urb (end->purb, GFP_KERNEL); - if (ret) { - dev_err(&s->usbdev->dev, - "usb_submit_urb returned:%d\n", ret); - if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) - dev_err(&s->usbdev->dev, - "startrek: dabusb_add_buf_tail failed\n"); - break; - } - else - atomic_inc (&s->pending_io); - } - dbg("pending_io: %d",s->pending_io.counter); - } - - return 0; -} - -static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos) -{ - pdabusb_t s = (pdabusb_t) file->private_data; - unsigned long flags; - unsigned ret = 0; - int rem; - int cnt; - pbuff_t b; - struct urb *purb = NULL; - - dbg("dabusb_read"); - - if (*ppos) - return -ESPIPE; - - if (s->remove_pending) - return -EIO; - - - if (!s->usbdev) - return -EIO; - - while (count > 0) { - dabusb_startrek (s); - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty (&s->rec_buff_list)) { - - spin_unlock_irqrestore(&s->lock, flags); - - dev_err(&s->usbdev->dev, - "error: rec_buf_list is empty\n"); - goto err; - } - - b = list_entry (s->rec_buff_list.next, buff_t, buff_list); - purb = b->purb; - - spin_unlock_irqrestore(&s->lock, flags); - - if (purb->status == -EINPROGRESS) { - if (file->f_flags & O_NONBLOCK) // return nonblocking - { - if (!ret) - ret = -EAGAIN; - goto err; - } - - interruptible_sleep_on (&s->wait); - - if (signal_pending (current)) { - if (!ret) - ret = -ERESTARTSYS; - goto err; - } - - spin_lock_irqsave (&s->lock, flags); - - if (list_empty (&s->rec_buff_list)) { - spin_unlock_irqrestore(&s->lock, flags); - dev_err(&s->usbdev->dev, - "error: still no buffer available.\n"); - goto err; - } - spin_unlock_irqrestore(&s->lock, flags); - s->readptr = 0; - } - if (s->remove_pending) { - ret = -EIO; - goto err; - } - - rem = purb->actual_length - s->readptr; // set remaining bytes to copy - - if (count >= rem) - cnt = rem; - else - cnt = count; - - dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt); - - if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) { - dev_err(&s->usbdev->dev, "read: copy_to_user failed\n"); - if (!ret) - ret = -EFAULT; - goto err; - } - - s->readptr += cnt; - count -= cnt; - buf += cnt; - ret += cnt; - - if (s->readptr == purb->actual_length) { - // finished, take next buffer - if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list)) - dev_err(&s->usbdev->dev, - "read: dabusb_add_buf_tail failed\n"); - s->readptr = 0; - } - } - err: //mutex_unlock(&s->mutex); - return ret; -} - -static int dabusb_open (struct inode *inode, struct file *file) -{ - int devnum = iminor(inode); - pdabusb_t s; - int r; - - if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB)) - return -EIO; - - s = &dabusb[devnum - DABUSB_MINOR]; - - dbg("dabusb_open"); - mutex_lock(&s->mutex); - - while (!s->usbdev || s->opened) { - mutex_unlock(&s->mutex); - - if (file->f_flags & O_NONBLOCK) - return -EBUSY; - msleep_interruptible(500); - - if (signal_pending (current)) - return -EAGAIN; - mutex_lock(&s->mutex); - } - if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) { - mutex_unlock(&s->mutex); - dev_err(&s->usbdev->dev, "set_interface failed\n"); - return -EINVAL; - } - s->opened = 1; - mutex_unlock(&s->mutex); - - file->f_pos = 0; - file->private_data = s; - - r = nonseekable_open(inode, file); - return r; -} - -static int dabusb_release (struct inode *inode, struct file *file) -{ - pdabusb_t s = (pdabusb_t) file->private_data; - - dbg("dabusb_release"); - - mutex_lock(&s->mutex); - dabusb_stop (s); - dabusb_free_buffers (s); - mutex_unlock(&s->mutex); - - if (!s->remove_pending) { - if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) - dev_err(&s->usbdev->dev, "set_interface failed\n"); - } - else - wake_up (&s->remove_ok); - - s->opened = 0; - return 0; -} - -static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg) -{ - pdabusb_t s = (pdabusb_t) file->private_data; - pbulk_transfer_t pbulk; - int ret = 0; - int version = DABUSB_VERSION; - - dbg("dabusb_ioctl"); - - if (s->remove_pending) - return -EIO; - - mutex_lock(&s->mutex); - - if (!s->usbdev) { - mutex_unlock(&s->mutex); - return -EIO; - } - - switch (cmd) { - - case IOCTL_DAB_BULK: - pbulk = memdup_user((void __user *)arg, - sizeof(bulk_transfer_t)); - - if (IS_ERR(pbulk)) { - ret = PTR_ERR(pbulk); - break; - } - - ret=dabusb_bulk (s, pbulk); - if(ret==0) - if (copy_to_user((void __user *)arg, pbulk, - sizeof(bulk_transfer_t))) - ret = -EFAULT; - kfree (pbulk); - break; - - case IOCTL_DAB_OVERRUNS: - ret = put_user (s->overruns, (unsigned int __user *) arg); - break; - - case IOCTL_DAB_VERSION: - ret = put_user (version, (unsigned int __user *) arg); - break; - - default: - ret = -ENOIOCTLCMD; - break; - } - mutex_unlock(&s->mutex); - return ret; -} - -static const struct file_operations dabusb_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = dabusb_read, - .unlocked_ioctl = dabusb_ioctl, - .open = dabusb_open, - .release = dabusb_release, -}; - -static char *dabusb_devnode(struct device *dev, mode_t *mode) -{ - return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev)); -} - -static struct usb_class_driver dabusb_class = { - .name = "dabusb%d", - .devnode = dabusb_devnode, - .fops = &dabusb_fops, - .minor_base = DABUSB_MINOR, -}; - - -/* --------------------------------------------------------------------- */ -static int dabusb_probe (struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usbdev = interface_to_usbdev(intf); - int retval; - pdabusb_t s; - - dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct), - intf->altsetting->desc.bInterfaceNumber); - - /* We don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) - return -ENODEV; - - if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && - le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999) - return -ENODEV; - - - - s = &dabusb[intf->minor]; - - mutex_lock(&s->mutex); - s->remove_pending = 0; - s->usbdev = usbdev; - s->devnum = intf->minor; - - if (usb_reset_configuration (usbdev) < 0) { - dev_err(&intf->dev, "reset_configuration failed\n"); - goto reject; - } - if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) { - dabusb_loadmem (s, NULL); - goto reject; - } - else { - dabusb_fpga_download (s, NULL); - - if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) { - dev_err(&intf->dev, "set_interface failed\n"); - goto reject; - } - } - dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber); - usb_set_intfdata (intf, s); - mutex_unlock(&s->mutex); - - retval = usb_register_dev(intf, &dabusb_class); - if (retval) { - usb_set_intfdata (intf, NULL); - return -ENOMEM; - } - - return 0; - - reject: - mutex_unlock(&s->mutex); - s->usbdev = NULL; - return -ENODEV; -} - -static void dabusb_disconnect (struct usb_interface *intf) -{ - wait_queue_t __wait; - pdabusb_t s = usb_get_intfdata (intf); - - dbg("dabusb_disconnect"); - - init_waitqueue_entry(&__wait, current); - - usb_set_intfdata (intf, NULL); - if (s) { - usb_deregister_dev (intf, &dabusb_class); - s->remove_pending = 1; - wake_up (&s->wait); - add_wait_queue(&s->remove_ok, &__wait); - set_current_state(TASK_UNINTERRUPTIBLE); - if (s->state == _started) - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&s->remove_ok, &__wait); - - s->usbdev = NULL; - s->overruns = 0; - } -} - -static struct usb_device_id dabusb_ids [] = { - // { USB_DEVICE(0x0547, 0x2131) }, /* An2131 chip, no boot ROM */ - { USB_DEVICE(0x0547, 0x9999) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, dabusb_ids); - -static struct usb_driver dabusb_driver = { - .name = "dabusb", - .probe = dabusb_probe, - .disconnect = dabusb_disconnect, - .id_table = dabusb_ids, -}; - -/* --------------------------------------------------------------------- */ - -static int __init dabusb_init (void) -{ - int retval; - unsigned u; - - /* initialize struct */ - for (u = 0; u < NRDABUSB; u++) { - pdabusb_t s = &dabusb[u]; - memset (s, 0, sizeof (dabusb_t)); - mutex_init (&s->mutex); - s->usbdev = NULL; - s->total_buffer_size = buffers; - init_waitqueue_head (&s->wait); - init_waitqueue_head (&s->remove_ok); - spin_lock_init (&s->lock); - INIT_LIST_HEAD (&s->free_buff_list); - INIT_LIST_HEAD (&s->rec_buff_list); - } - - /* register misc device */ - retval = usb_register(&dabusb_driver); - if (retval) - goto out; - - dbg("dabusb_init: driver registered"); - - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - -out: - return retval; -} - -static void __exit dabusb_cleanup (void) -{ - dbg("dabusb_cleanup"); - - usb_deregister (&dabusb_driver); -} - -/* --------------------------------------------------------------------- */ - -MODULE_AUTHOR( DRIVER_AUTHOR ); -MODULE_DESCRIPTION( DRIVER_DESC ); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("dabusb/firmware.fw"); -MODULE_FIRMWARE("dabusb/bitstream.bin"); - -module_param(buffers, int, 0); -MODULE_PARM_DESC (buffers, "Number of buffers (default=256)"); - -module_init (dabusb_init); -module_exit (dabusb_cleanup); - -/* --------------------------------------------------------------------- */ diff --git a/drivers/staging/dabusb/dabusb.h b/drivers/staging/dabusb/dabusb.h deleted file mode 100644 index 00eb34c863eb..000000000000 --- a/drivers/staging/dabusb/dabusb.h +++ /dev/null @@ -1,85 +0,0 @@ -#define _BULK_DATA_LEN 64 -typedef struct -{ - unsigned char data[_BULK_DATA_LEN]; - unsigned int size; - unsigned int pipe; -}bulk_transfer_t,*pbulk_transfer_t; - -#define DABUSB_MINOR 240 /* some unassigned USB minor */ -#define DABUSB_VERSION 0x1000 -#define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t) -#define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int) -#define IOCTL_DAB_VERSION _IOR('d', 0x3f, int) - -#ifdef __KERNEL__ - -typedef enum { _stopped=0, _started } driver_state_t; - -typedef struct -{ - struct mutex mutex; - struct usb_device *usbdev; - wait_queue_head_t wait; - wait_queue_head_t remove_ok; - spinlock_t lock; - atomic_t pending_io; - driver_state_t state; - int remove_pending; - int got_mem; - int total_buffer_size; - unsigned int overruns; - int readptr; - int opened; - int devnum; - struct list_head free_buff_list; - struct list_head rec_buff_list; -} dabusb_t,*pdabusb_t; - -typedef struct -{ - pdabusb_t s; - struct urb *purb; - struct list_head buff_list; -} buff_t,*pbuff_t; - -typedef struct -{ - wait_queue_head_t wait; -} bulk_completion_context_t, *pbulk_completion_context_t; - - -#define _DABUSB_IF 2 -#define _DABUSB_ISOPIPE 0x09 -#define _ISOPIPESIZE 16384 - -#define _BULK_DATA_LEN 64 -// Vendor specific request code for Anchor Upload/Download -// This one is implemented in the core -#define ANCHOR_LOAD_INTERNAL 0xA0 - -// EZ-USB Control and Status Register. Bit 0 controls 8051 reset -#define CPUCS_REG 0x7F92 -#define _TOTAL_BUFFERS 384 - -#define MAX_INTEL_HEX_RECORD_LENGTH 16 - -#ifndef _BYTE_DEFINED -#define _BYTE_DEFINED -typedef unsigned char BYTE; -#endif // !_BYTE_DEFINED - -#ifndef _WORD_DEFINED -#define _WORD_DEFINED -typedef unsigned short WORD; -#endif // !_WORD_DEFINED - -typedef struct _INTEL_HEX_RECORD -{ - BYTE Length; - WORD Address; - BYTE Type; - BYTE Data[MAX_INTEL_HEX_RECORD_LENGTH]; -} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD; - -#endif -- cgit v1.2.2 From 7ee40aadabd59b6cab60835f0ef9cdbe385df438 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 5 Feb 2011 10:10:38 -0300 Subject: [media] v4l: removal of old, obsolete ioctls Some ioctl's were defined wrong on 2.6.2 and 2.6.6, using the wrong type of R/W arguments. They were fixed, but the old ioctl names are still there, maintained to avoid breaking binary compatibility: There's no sense on preserving those forever, as it is very doubtful that someone would try to use a such old binary with a modern kernel. Removing them will allow us to remove some magic done at the V4L ioctl handler. Note that any application compiled with a videodev2.h from 2.6.7 or later will be using the correct ioctls. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 1 - drivers/media/video/v4l2-compat-ioctl32.c | 15 ------------ drivers/media/video/v4l2-ioctl.c | 38 ------------------------------- drivers/staging/easycap/easycap_ioctl.c | 5 ---- 4 files changed, 59 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 810eef43c216..940b5db3463e 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -59,7 +59,6 @@ #include #include #include -#define __OLD_VIDIOC_ /* To allow fixing old calls*/ #include #include #include diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index c19208a07b48..7c2694738b31 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -14,7 +14,6 @@ */ #include -#define __OLD_VIDIOC_ /* To allow fixing old calls*/ #include #include #include @@ -678,9 +677,6 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32) #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32) -#ifdef __OLD_VIDIOC_ -#define VIDIOC_OVERLAY32_OLD _IOWR('V', 14, s32) -#endif #define VIDIOC_STREAMON32 _IOW ('V', 18, s32) #define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32) #define VIDIOC_G_INPUT32 _IOR ('V', 38, s32) @@ -720,9 +716,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break; case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break; case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break; -#ifdef __OLD_VIDIOC_ - case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break; -#endif case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break; case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break; case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break; @@ -856,14 +849,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) return ret; switch (cmd) { -#ifdef __OLD_VIDIOC_ - case VIDIOC_OVERLAY32_OLD: - case VIDIOC_S_PARM_OLD: - case VIDIOC_S_CTRL_OLD: - case VIDIOC_G_AUDIO_OLD: - case VIDIOC_G_AUDOUT_OLD: - case VIDIOC_CROPCAP_OLD: -#endif case VIDIOC_QUERYCAP: case VIDIOC_RESERVED: case VIDIOC_ENUM_FMT: diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 8360ed2d933a..7a720745c3fa 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -17,7 +17,6 @@ #include #include -#define __OLD_VIDIOC_ /* To allow fixing old calls */ #include #include @@ -297,37 +296,6 @@ EXPORT_SYMBOL(v4l_printk_ioctl); /* * helper function -- handles userspace copying for ioctl arguments - */ - -#ifdef __OLD_VIDIOC_ -static unsigned int -video_fix_command(unsigned int cmd) -{ - switch (cmd) { - case VIDIOC_OVERLAY_OLD: - cmd = VIDIOC_OVERLAY; - break; - case VIDIOC_S_PARM_OLD: - cmd = VIDIOC_S_PARM; - break; - case VIDIOC_S_CTRL_OLD: - cmd = VIDIOC_S_CTRL; - break; - case VIDIOC_G_AUDIO_OLD: - cmd = VIDIOC_G_AUDIO; - break; - case VIDIOC_G_AUDOUT_OLD: - cmd = VIDIOC_G_AUDOUT; - break; - case VIDIOC_CROPCAP_OLD: - cmd = VIDIOC_CROPCAP; - break; - } - return cmd; -} -#endif - -/* * Obsolete usercopy function - Should be removed soon */ long @@ -342,9 +310,6 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, size_t ctrls_size = 0; void __user *user_ptr = NULL; -#ifdef __OLD_VIDIOC_ - cmd = video_fix_command(cmd); -#endif is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || cmd == VIDIOC_TRY_EXT_CTRLS); @@ -2379,9 +2344,6 @@ long video_ioctl2(struct file *file, void __user *user_ptr = NULL; void **kernel_ptr = NULL; -#ifdef __OLD_VIDIOC_ - cmd = video_fix_command(cmd); -#endif /* Copy arguments into temp kernel buffer */ if (_IOC_DIR(cmd) != _IOC_NONE) { if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c index 447953a4e80c..7ac43da4e252 100644 --- a/drivers/staging/easycap/easycap_ioctl.c +++ b/drivers/staging/easycap/easycap_ioctl.c @@ -1399,11 +1399,6 @@ case VIDIOC_G_CTRL: { break; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -#if defined(VIDIOC_S_CTRL_OLD) -case VIDIOC_S_CTRL_OLD: { - JOM(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n"); -} -#endif /*VIDIOC_S_CTRL_OLD*/ case VIDIOC_S_CTRL: { struct v4l2_control v4l2_control; -- cgit v1.2.2 From e68044e2351ee937997c1e014fbbbe1c97b935cf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 5 Feb 2011 10:07:39 -0300 Subject: [media] firedtv: remove obsolete ieee1394 backend code drivers/ieee1394/ has been removed in Linux 2.6.37. The corresponding backend code in firedtv is no longer built in now and can be deleted. Firedtv continues to work with drivers/firewire/. Also, fix a Kconfig menu comment: Removal of CONFIG_IEEE1394 made the "Supported FireWire (IEEE 1394) Adapters" comment disappear; bring it back with corrected dependency. Signed-off-by: Hans Verkuil Reviewed-by: Stefan Richter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/Kconfig | 2 +- drivers/media/dvb/firewire/Kconfig | 8 +- drivers/media/dvb/firewire/Makefile | 5 +- drivers/media/dvb/firewire/firedtv-1394.c | 300 ------------------------------ drivers/media/dvb/firewire/firedtv-dvb.c | 5 - drivers/media/dvb/firewire/firedtv.h | 14 -- 6 files changed, 3 insertions(+), 331 deletions(-) delete mode 100644 drivers/media/dvb/firewire/firedtv-1394.c (limited to 'drivers') diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 161ccfd471cb..ee214c3b63d7 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -65,7 +65,7 @@ comment "Supported SDMC DM1105 Adapters" source "drivers/media/dvb/dm1105/Kconfig" comment "Supported FireWire (IEEE 1394) Adapters" - depends on DVB_CORE && IEEE1394 + depends on DVB_CORE && FIREWIRE source "drivers/media/dvb/firewire/Kconfig" comment "Supported Earthsoft PT1 Adapters" diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig index 4afa29256df1..f3e9448c3955 100644 --- a/drivers/media/dvb/firewire/Kconfig +++ b/drivers/media/dvb/firewire/Kconfig @@ -1,6 +1,6 @@ config DVB_FIREDTV tristate "FireDTV and FloppyDTV" - depends on DVB_CORE && (FIREWIRE || IEEE1394) + depends on DVB_CORE && FIREWIRE help Support for DVB receivers from Digital Everywhere which are connected via IEEE 1394 (FireWire). @@ -13,12 +13,6 @@ config DVB_FIREDTV if DVB_FIREDTV -config DVB_FIREDTV_FIREWIRE - def_bool FIREWIRE = y || (FIREWIRE = m && DVB_FIREDTV = m) - -config DVB_FIREDTV_IEEE1394 - def_bool IEEE1394 = y || (IEEE1394 = m && DVB_FIREDTV = m) - config DVB_FIREDTV_INPUT def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile index da84203d51c6..357b3aab186b 100644 --- a/drivers/media/dvb/firewire/Makefile +++ b/drivers/media/dvb/firewire/Makefile @@ -1,9 +1,6 @@ obj-$(CONFIG_DVB_FIREDTV) += firedtv.o -firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o -firedtv-$(CONFIG_DVB_FIREDTV_FIREWIRE) += firedtv-fw.o -firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o +firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o ccflags-y += -Idrivers/media/dvb/dvb-core -ccflags-$(CONFIG_DVB_FIREDTV_IEEE1394) += -Idrivers/ieee1394 diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c deleted file mode 100644 index b34ca7afb0e6..000000000000 --- a/drivers/media/dvb/firewire/firedtv-1394.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * FireDTV driver -- ieee1394 I/O backend - * - * Copyright (C) 2004 Andreas Monitzer - * Copyright (C) 2007-2008 Ben Backx - * Copyright (C) 2008 Henrik Kurelid - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "firedtv.h" - -static LIST_HEAD(node_list); -static DEFINE_SPINLOCK(node_list_lock); - -#define CIP_HEADER_SIZE 8 -#define MPEG2_TS_HEADER_SIZE 4 -#define MPEG2_TS_SOURCE_PACKET_SIZE (4 + 188) - -static void rawiso_activity_cb(struct hpsb_iso *iso) -{ - struct firedtv *f, *fdtv = NULL; - unsigned int i, num, packet; - unsigned char *buf; - unsigned long flags; - int count; - - spin_lock_irqsave(&node_list_lock, flags); - list_for_each_entry(f, &node_list, list) - if (f->backend_data == iso) { - fdtv = f; - break; - } - spin_unlock_irqrestore(&node_list_lock, flags); - - packet = iso->first_packet; - num = hpsb_iso_n_ready(iso); - - if (!fdtv) { - pr_err("received at unknown iso channel\n"); - goto out; - } - - for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) { - buf = dma_region_i(&iso->data_buf, unsigned char, - iso->infos[packet].offset + CIP_HEADER_SIZE); - count = (iso->infos[packet].len - CIP_HEADER_SIZE) / - MPEG2_TS_SOURCE_PACKET_SIZE; - - /* ignore empty packet */ - if (iso->infos[packet].len <= CIP_HEADER_SIZE) - continue; - - while (count--) { - if (buf[MPEG2_TS_HEADER_SIZE] == 0x47) - dvb_dmx_swfilter_packets(&fdtv->demux, - &buf[MPEG2_TS_HEADER_SIZE], 1); - else - dev_err(fdtv->device, - "skipping invalid packet\n"); - buf += MPEG2_TS_SOURCE_PACKET_SIZE; - } - } -out: - hpsb_iso_recv_release_packets(iso, num); -} - -static inline struct node_entry *node_of(struct firedtv *fdtv) -{ - return container_of(fdtv->device, struct unit_directory, device)->ne; -} - -static int node_lock(struct firedtv *fdtv, u64 addr, void *data) -{ - quadlet_t *d = data; - int ret; - - ret = hpsb_node_lock(node_of(fdtv), addr, - EXTCODE_COMPARE_SWAP, &d[1], d[0]); - d[0] = d[1]; - - return ret; -} - -static int node_read(struct firedtv *fdtv, u64 addr, void *data) -{ - return hpsb_node_read(node_of(fdtv), addr, data, 4); -} - -static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) -{ - return hpsb_node_write(node_of(fdtv), addr, data, len); -} - -#define FDTV_ISO_BUFFER_PACKETS 256 -#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200) - -static int start_iso(struct firedtv *fdtv) -{ - struct hpsb_iso *iso_handle; - int ret; - - iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host, - FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS, - fdtv->isochannel, HPSB_ISO_DMA_DEFAULT, - -1, /* stat.config.irq_interval */ - rawiso_activity_cb); - if (iso_handle == NULL) { - dev_err(fdtv->device, "cannot initialize iso receive\n"); - return -ENOMEM; - } - fdtv->backend_data = iso_handle; - - ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0); - if (ret != 0) { - dev_err(fdtv->device, "cannot start iso receive\n"); - hpsb_iso_shutdown(iso_handle); - fdtv->backend_data = NULL; - } - return ret; -} - -static void stop_iso(struct firedtv *fdtv) -{ - struct hpsb_iso *iso_handle = fdtv->backend_data; - - if (iso_handle != NULL) { - hpsb_iso_stop(iso_handle); - hpsb_iso_shutdown(iso_handle); - } - fdtv->backend_data = NULL; -} - -static const struct firedtv_backend fdtv_1394_backend = { - .lock = node_lock, - .read = node_read, - .write = node_write, - .start_iso = start_iso, - .stop_iso = stop_iso, -}; - -static void fcp_request(struct hpsb_host *host, int nodeid, int direction, - int cts, u8 *data, size_t length) -{ - struct firedtv *f, *fdtv = NULL; - unsigned long flags; - int su; - - if (length == 0 || (data[0] & 0xf0) != 0) - return; - - su = data[1] & 0x7; - - spin_lock_irqsave(&node_list_lock, flags); - list_for_each_entry(f, &node_list, list) - if (node_of(f)->host == host && - node_of(f)->nodeid == nodeid && - (f->subunit == su || (f->subunit == 0 && su == 0x7))) { - fdtv = f; - break; - } - spin_unlock_irqrestore(&node_list_lock, flags); - - if (fdtv) - avc_recv(fdtv, data, length); -} - -static int node_probe(struct device *dev) -{ - struct unit_directory *ud = - container_of(dev, struct unit_directory, device); - struct firedtv *fdtv; - int kv_len, err; - void *kv_str; - - if (ud->model_name_kv) { - kv_len = (ud->model_name_kv->value.leaf.len - 2) * 4; - kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv); - } else { - kv_len = 0; - kv_str = NULL; - } - fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len); - if (!fdtv) - return -ENOMEM; - - /* - * Work around a bug in udev's path_id script: Use the fw-host's dev - * instead of the unit directory's dev as parent of the input device. - */ - err = fdtv_register_rc(fdtv, dev->parent->parent); - if (err) - goto fail_free; - - spin_lock_irq(&node_list_lock); - list_add_tail(&fdtv->list, &node_list); - spin_unlock_irq(&node_list_lock); - - err = avc_identify_subunit(fdtv); - if (err) - goto fail; - - err = fdtv_dvb_register(fdtv); - if (err) - goto fail; - - avc_register_remote_control(fdtv); - - return 0; -fail: - spin_lock_irq(&node_list_lock); - list_del(&fdtv->list); - spin_unlock_irq(&node_list_lock); - fdtv_unregister_rc(fdtv); -fail_free: - kfree(fdtv); - - return err; -} - -static int node_remove(struct device *dev) -{ - struct firedtv *fdtv = dev_get_drvdata(dev); - - fdtv_dvb_unregister(fdtv); - - spin_lock_irq(&node_list_lock); - list_del(&fdtv->list); - spin_unlock_irq(&node_list_lock); - - fdtv_unregister_rc(fdtv); - kfree(fdtv); - - return 0; -} - -static int node_update(struct unit_directory *ud) -{ - struct firedtv *fdtv = dev_get_drvdata(&ud->device); - - if (fdtv->isochannel >= 0) - cmp_establish_pp_connection(fdtv, fdtv->subunit, - fdtv->isochannel); - return 0; -} - -static struct hpsb_protocol_driver fdtv_driver = { - .name = "firedtv", - .id_table = fdtv_id_table, - .update = node_update, - .driver = { - .probe = node_probe, - .remove = node_remove, - }, -}; - -static struct hpsb_highlevel fdtv_highlevel = { - .name = "firedtv", - .fcp_request = fcp_request, -}; - -int __init fdtv_1394_init(void) -{ - int ret; - - hpsb_register_highlevel(&fdtv_highlevel); - ret = hpsb_register_protocol(&fdtv_driver); - if (ret) { - printk(KERN_ERR "firedtv: failed to register protocol\n"); - hpsb_unregister_highlevel(&fdtv_highlevel); - } - return ret; -} - -void __exit fdtv_1394_exit(void) -{ - hpsb_unregister_protocol(&fdtv_driver); - hpsb_unregister_highlevel(&fdtv_highlevel); -} diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c index 079e8c5b0475..86349db75250 100644 --- a/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -351,16 +351,11 @@ static int __init fdtv_init(void) if (ret < 0) return ret; - ret = fdtv_1394_init(); - if (ret < 0) - fdtv_fw_exit(); - return ret; } static void __exit fdtv_exit(void) { - fdtv_1394_exit(); fdtv_fw_exit(); } diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h index 78cc28f36914..4a87049c9132 100644 --- a/drivers/media/dvb/firewire/firedtv.h +++ b/drivers/media/dvb/firewire/firedtv.h @@ -118,15 +118,6 @@ struct firedtv { u8 avc_data[512]; }; -/* firedtv-1394.c */ -#ifdef CONFIG_DVB_FIREDTV_IEEE1394 -int fdtv_1394_init(void); -void fdtv_1394_exit(void); -#else -static inline int fdtv_1394_init(void) { return 0; } -static inline void fdtv_1394_exit(void) {} -#endif - /* firedtv-avc.c */ int avc_recv(struct firedtv *fdtv, void *data, size_t length); int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat); @@ -170,13 +161,8 @@ extern const struct ieee1394_device_id fdtv_id_table[]; void fdtv_frontend_init(struct firedtv *fdtv); /* firedtv-fw.c */ -#ifdef CONFIG_DVB_FIREDTV_FIREWIRE int fdtv_fw_init(void); void fdtv_fw_exit(void); -#else -static inline int fdtv_fw_init(void) { return 0; } -static inline void fdtv_fw_exit(void) {} -#endif /* firedtv-rc.c */ #ifdef CONFIG_DVB_FIREDTV_INPUT -- cgit v1.2.2 From d63044401a107ef22521e62c7f9b30c40b7c44ed Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 7 Feb 2011 04:37:38 -0300 Subject: [media] saa7134-empress: add missing MPEG controls Reported by, and based on a patch from, Martin Dauskardt. The AUDIO_AC3_BITRATE control is still missing from this list, but such optional controls are a bit hard to handle. This will be fixed automatically when we switch to the control framework. Signed-off-by: Hans Verkuil Reported-by: Martin Dauskardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-empress.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 6b8459c7728e..18294db38a01 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -373,6 +373,10 @@ static int empress_queryctrl(struct file *file, void *priv, static const u32 mpeg_ctrls[] = { V4L2_CID_MPEG_CLASS, V4L2_CID_MPEG_STREAM_TYPE, + V4L2_CID_MPEG_STREAM_PID_PMT, + V4L2_CID_MPEG_STREAM_PID_AUDIO, + V4L2_CID_MPEG_STREAM_PID_VIDEO, + V4L2_CID_MPEG_STREAM_PID_PCR, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, V4L2_CID_MPEG_AUDIO_ENCODING, V4L2_CID_MPEG_AUDIO_L2_BITRATE, -- cgit v1.2.2 From ed5b65dc362d488958075381d97931d865e77259 Mon Sep 17 00:00:00 2001 From: Qing Xu Date: Thu, 20 Jan 2011 05:19:40 -0300 Subject: [media] V4L: soc-camera: add enum-frame-size ioctl add vidioc_enum_framesizes implementation, follow default_g_parm() and g_mbus_fmt() method Signed-off-by: Qing Xu Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index a66811b43710..a7820a549f1b 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -191,6 +191,15 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) return v4l2_subdev_call(sd, core, s_std, *a); } +static int soc_camera_enum_fsizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + + return ici->ops->enum_fsizes(icd, fsize); +} + static int soc_camera_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { @@ -1175,6 +1184,31 @@ static int default_s_parm(struct soc_camera_device *icd, return v4l2_subdev_call(sd, video, s_parm, parm); } +static int default_enum_fsizes(struct soc_camera_device *icd, + struct v4l2_frmsizeenum *fsize) +{ + int ret; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + __u32 pixfmt = fsize->pixel_format; + struct v4l2_frmsizeenum fsize_mbus = *fsize; + + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); + if (!xlate) + return -EINVAL; + /* map xlate-code to pixel_format, sensor only handle xlate-code*/ + fsize_mbus.pixel_format = xlate->code; + + ret = v4l2_subdev_call(sd, video, enum_mbus_fsizes, &fsize_mbus); + if (ret < 0) + return ret; + + *fsize = fsize_mbus; + fsize->pixel_format = pixfmt; + + return 0; +} + static void soc_camera_device_init(struct device *dev, void *pdata) { dev->platform_data = pdata; @@ -1210,6 +1244,8 @@ int soc_camera_host_register(struct soc_camera_host *ici) ici->ops->set_parm = default_s_parm; if (!ici->ops->get_parm) ici->ops->get_parm = default_g_parm; + if (!ici->ops->enum_fsizes) + ici->ops->enum_fsizes = default_enum_fsizes; mutex_lock(&list_lock); list_for_each_entry(ix, &hosts, list) { @@ -1317,6 +1353,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { .vidioc_g_input = soc_camera_g_input, .vidioc_s_input = soc_camera_s_input, .vidioc_s_std = soc_camera_s_std, + .vidioc_enum_framesizes = soc_camera_enum_fsizes, .vidioc_reqbufs = soc_camera_reqbufs, .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, .vidioc_querybuf = soc_camera_querybuf, -- cgit v1.2.2 From 7fdbd85bce033e2d0f74e5d326ab43906653cb81 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 31 Jan 2011 09:19:32 -0300 Subject: [media] V4L: soc-camera: start stream after queueing the buffers Some camera systems have strong requirement for capturing an exact number of frames after starting the stream and do not tolerate losing captured frames. By starting the stream after the videobuf has queued the buffers, we ensure that no frame will be lost. Signed-off-by: Anatolij Gustschin Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index a7820a549f1b..67611ad6af96 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -655,10 +655,10 @@ static int soc_camera_streamon(struct file *file, void *priv, if (icd->streamer != file) return -EBUSY; - v4l2_subdev_call(sd, video, s_stream, 1); - /* This calls buf_queue from host driver's videobuf_queue_ops */ ret = videobuf_streamon(&icd->vb_vidq); + if (!ret) + v4l2_subdev_call(sd, video, s_stream, 1); return ret; } -- cgit v1.2.2 From 48a3c77338d725d4976fa792d822eb940ce5c296 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Wed, 12 Jan 2011 08:16:19 -0300 Subject: [media] V4L: soc_mediabus: add a method to obtain the number of samples per pixel Add a function to calculate the number of samples on the media-bus, required to retrieve one pixel of a certain format. Signed-off-by: Alberto Panizzo Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_mediabus.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c index 91391214c682..73b4138709e4 100644 --- a/drivers/media/video/soc_mediabus.c +++ b/drivers/media/video/soc_mediabus.c @@ -132,6 +132,20 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = { }, }; +int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf) +{ + switch (mf->packing) { + case SOC_MBUS_PACKING_NONE: + case SOC_MBUS_PACKING_EXTEND16: + return 1; + case SOC_MBUS_PACKING_2X8_PADHI: + case SOC_MBUS_PACKING_2X8_PADLO: + return 2; + } + return -EINVAL; +} +EXPORT_SYMBOL(soc_mbus_samples_per_pixel); + s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) { switch (mf->packing) { -- cgit v1.2.2 From 5bccd60852fc0a5ccc1980c10266896df99b8bda Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 30 Jan 2011 07:05:58 -0300 Subject: [media] V4L: omap1_camera: fix use after free Even though clk_put() is a no-op on most architectures it is not for some ARM implementations. To not fail on those, release the clock timer before freeing the surrounding structure. This bug was spotted by the semantic patch tool coccinelle using the script found at scripts/coccinelle/free/kfree.cocci. More information about semantic patching is available at http://coccinelle.lip6.fr/ Signed-off-by: Mathias Krause Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap1_camera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 0a2fb2bfdbfb..9ed1513122c1 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -1664,10 +1664,10 @@ static int __exit omap1_cam_remove(struct platform_device *pdev) res = pcdev->res; release_mem_region(res->start, resource_size(res)); - kfree(pcdev); - clk_put(pcdev->clk); + kfree(pcdev); + dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n"); return 0; -- cgit v1.2.2 From 44facdc8c43a8b5172d6cbe995845c9889561aa0 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Mon, 31 Jan 2011 09:58:01 -0300 Subject: [media] V4L: mx3_camera: correct 'sizeimage' value reporting The 'pix->width' field may be updated in mx3_camera_set_fmt() to fulfill the IPU stride line alignment requirements. If this update takes place, the 'fmt.pix.sizeimage' field in the struct v4l2_format stucture returned by VIDIOC_S_FMT is wrong. We need to update the 'pix->sizeimage' field in the mx3_camera_set_fmt() function to fix this issue. Signed-off-by: Anatolij Gustschin Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx3_camera.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index b9cb4a436959..1cfff4132a0b 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -918,6 +918,12 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, pix->colorspace = mf.colorspace; icd->current_fmt = xlate; + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; + pix->sizeimage = pix->height * pix->bytesperline; + dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); return ret; -- cgit v1.2.2 From a48be1d626ceb05b58a980a962214431af8041e8 Mon Sep 17 00:00:00 2001 From: Alberto Panizzo Date: Mon, 17 Jan 2011 06:52:10 -0300 Subject: [media] V4L: mx3_camera: fix capture issues for non 8-bit per pixel formats If the camera was set to output formats like RGB565 YUYV or SBGGR10, the resulting image was scrambled due to erroneous interpretations of horizontal parameter's units. This patch in fourcc_to_ipu_pix, eliminate also the pixel formats mappings that, first are not used within mainline code and second, standing at the datasheets, they will not work properly: The IPU internal bus support only the following data formatting (44.1.1.3 Data Flows and Formats): 1 YUV 4:4:4 or RGB-8 bits per color component 2 YUV 4:4:4 or RGB-10 bits per color component 3 Generic data (from sensor to the system memory only) And format conversions are done: - from memory: unpacking from other formats to IPU supported ones - to memory: packing in the inverse order. So, assigning a packing/unpacking strategy to the IPU for those formats will produce a packing to memory and not the inverse. Signed-off-by: Alberto Panizzo Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx3_camera.c | 64 +++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 1cfff4132a0b..c8c6c03a6a62 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -324,14 +324,10 @@ static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) { /* Add more formats as need arises and test possibilities appear... */ switch (fourcc) { - case V4L2_PIX_FMT_RGB565: - return IPU_PIX_FMT_RGB565; case V4L2_PIX_FMT_RGB24: return IPU_PIX_FMT_RGB24; - case V4L2_PIX_FMT_RGB332: - return IPU_PIX_FMT_RGB332; - case V4L2_PIX_FMT_YUV422P: - return IPU_PIX_FMT_YVU422P; + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_RGB565: default: return IPU_PIX_FMT_GENERIC; } @@ -359,9 +355,31 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, /* This is the configuration of one sg-element */ video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); - video->out_width = icd->user_width; - video->out_height = icd->user_height; - video->out_stride = icd->user_width; + + if (video->out_pixel_fmt == IPU_PIX_FMT_GENERIC) { + /* + * If the IPU DMA channel is configured to transport + * generic 8-bit data, we have to set up correctly the + * geometry parameters upon the current pixel format. + * So, since the DMA horizontal parameters are expressed + * in bytes not pixels, convert these in the right unit. + */ + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + BUG_ON(bytes_per_line <= 0); + + video->out_width = bytes_per_line; + video->out_height = icd->user_height; + video->out_stride = bytes_per_line; + } else { + /* + * For IPU known formats the pixel unit will be managed + * successfully by the IPU code + */ + video->out_width = icd->user_width; + video->out_height = icd->user_height; + video->out_stride = icd->user_width; + } #ifdef DEBUG /* helps to see what DMA actually has written */ @@ -734,18 +752,36 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id if (xlate) { xlate->host_fmt = fmt; xlate->code = code; + dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", + (fmt->fourcc >> (0*8)) & 0xFF, + (fmt->fourcc >> (1*8)) & 0xFF, + (fmt->fourcc >> (2*8)) & 0xFF, + (fmt->fourcc >> (3*8)) & 0xFF); xlate++; - dev_dbg(dev, "Providing format %x in pass-through mode\n", - xlate->host_fmt->fourcc); } return formats; } static void configure_geometry(struct mx3_camera_dev *mx3_cam, - unsigned int width, unsigned int height) + unsigned int width, unsigned int height, + enum v4l2_mbus_pixelcode code) { u32 ctrl, width_field, height_field; + const struct soc_mbus_pixelfmt *fmt; + + fmt = soc_mbus_get_fmtdesc(code); + BUG_ON(!fmt); + + if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) { + /* + * As the CSI will be configured to output BAYER, here + * the width parameter count the number of samples to + * capture to complete the whole image width. + */ + width *= soc_mbus_samples_per_pixel(fmt); + BUG_ON(width < 0); + } /* Setup frame size - this cannot be changed on-the-fly... */ width_field = width - 1; @@ -854,7 +890,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, return ret; } - configure_geometry(mx3_cam, mf.width, mf.height); + configure_geometry(mx3_cam, mf.width, mf.height, mf.code); } dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", @@ -897,7 +933,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, * mxc_v4l2_s_fmt() */ - configure_geometry(mx3_cam, pix->width, pix->height); + configure_geometry(mx3_cam, pix->width, pix->height, xlate->code); mf.width = pix->width; mf.height = pix->height; -- cgit v1.2.2 From 353c2129fdff2047237193932971e50734c64336 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 2 Feb 2011 17:38:22 -0300 Subject: [media] V4L: omap1_camera: join split format lines Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap1_camera.c | 62 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index 9ed1513122c1..eab31cbd68eb 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -811,8 +811,8 @@ static irqreturn_t cam_isr(int irq, void *data) spin_lock_irqsave(&pcdev->lock, flags); if (WARN_ON(!buf)) { - dev_warn(dev, "%s: unhandled camera interrupt, status == " - "%#x\n", __func__, it_status); + dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n", + __func__, it_status); suspend_capture(pcdev); disable_capture(pcdev); goto out; @@ -1088,15 +1088,15 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, xlate->host_fmt = &omap1_cam_formats[code]; xlate->code = code; xlate++; - dev_dbg(dev, "%s: providing format %s " - "as byte swapped code #%d\n", __func__, - omap1_cam_formats[code].name, code); + dev_dbg(dev, + "%s: providing format %s as byte swapped code #%d\n", + __func__, omap1_cam_formats[code].name, code); } default: if (xlate) - dev_dbg(dev, "%s: providing format %s " - "in pass-through mode\n", __func__, - fmt->name); + dev_dbg(dev, + "%s: providing format %s in pass-through mode\n", + __func__, fmt->name); } formats++; if (xlate) { @@ -1139,29 +1139,29 @@ static int dma_align(int *width, int *height, return 1; } -#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \ -({ \ - struct soc_camera_sense sense = { \ - .master_clock = pcdev->camexclk, \ - .pixel_clock_max = 0, \ - }; \ - int __ret; \ - \ - if (pcdev->pdata) \ - sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ - icd->sense = &sense; \ - __ret = v4l2_subdev_call(sd, video, function, ##args); \ - icd->sense = NULL; \ - \ - if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ - if (sense.pixel_clock > sense.pixel_clock_max) { \ - dev_err(dev, "%s: pixel clock %lu " \ - "set by the camera too high!\n", \ - __func__, sense.pixel_clock); \ - __ret = -EINVAL; \ - } \ - } \ - __ret; \ +#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \ +({ \ + struct soc_camera_sense sense = { \ + .master_clock = pcdev->camexclk, \ + .pixel_clock_max = 0, \ + }; \ + int __ret; \ + \ + if (pcdev->pdata) \ + sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ + icd->sense = &sense; \ + __ret = v4l2_subdev_call(sd, video, function, ##args); \ + icd->sense = NULL; \ + \ + if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ + if (sense.pixel_clock > sense.pixel_clock_max) { \ + dev_err(dev, \ + "%s: pixel clock %lu set by the camera too high!\n", \ + __func__, sense.pixel_clock); \ + __ret = -EINVAL; \ + } \ + } \ + __ret; \ }) static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev, -- cgit v1.2.2 From bd94f588283b167f7fa8c2dc2164dcd2f4a4a7a5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 28 Jan 2011 21:06:19 -0300 Subject: [media] V4L: add missing EXPORT_SYMBOL* statements to vb2 videobuf2-memops and videobuf2-core can be compiled as modules, in which case 3 more symbols from videobuf2-memops.c have to be exported. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-memops.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c index 053c15794b8d..a3eb6567dea5 100644 --- a/drivers/media/video/videobuf2-memops.c +++ b/drivers/media/video/videobuf2-memops.c @@ -77,6 +77,7 @@ void vb2_put_vma(struct vm_area_struct *vma) kfree(vma); } +EXPORT_SYMBOL_GPL(vb2_put_vma); /** * vb2_get_contig_userptr() - lock physically contiguous userspace mapped memory @@ -141,6 +142,7 @@ done: up_read(&mm->mmap_sem); return ret; } +EXPORT_SYMBOL_GPL(vb2_get_contig_userptr); /** * vb2_mmap_pfn_range() - map physical pages to userspace @@ -180,6 +182,7 @@ int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, return 0; } +EXPORT_SYMBOL_GPL(vb2_mmap_pfn_range); /** * vb2_common_vm_open() - increase refcount of the vma -- cgit v1.2.2 From 592c2aba266ca5be0dce300d0400817d943d49af Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 29 Jan 2011 12:44:51 -0300 Subject: [media] V4L: soc-camera: extend to also support videobuf2 Extend soc-camera core to also support the videobuf2 API. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 1 + drivers/media/video/soc_camera.c | 90 ++++++++++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d40a8fc01bfd..07c5baaa2d0f 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -750,6 +750,7 @@ config SOC_CAMERA tristate "SoC camera support" depends on VIDEO_V4L2 && HAS_DMA && I2C select VIDEOBUF_GEN + select VIDEOBUF2_CORE help SoC Camera is a common API to several cameras, not connecting over a bus like PCI or USB. For example some i2c camera connected diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 67611ad6af96..fa80a4a914d4 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -34,6 +34,7 @@ #include #include #include +#include #include /* Default to VGA resolution */ @@ -212,11 +213,16 @@ static int soc_camera_reqbufs(struct file *file, void *priv, if (icd->streamer && icd->streamer != file) return -EBUSY; - ret = videobuf_reqbufs(&icd->vb_vidq, p); - if (ret < 0) - return ret; + if (ici->ops->init_videobuf) { + ret = videobuf_reqbufs(&icd->vb_vidq, p); + if (ret < 0) + return ret; + + ret = ici->ops->reqbufs(icd, p); + } else { + ret = vb2_reqbufs(&icd->vb2_vidq, p); + } - ret = ici->ops->reqbufs(icd, p); if (!ret && !icd->streamer) icd->streamer = file; @@ -227,36 +233,48 @@ static int soc_camera_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); - return videobuf_querybuf(&icd->vb_vidq, p); + if (ici->ops->init_videobuf) + return videobuf_querybuf(&icd->vb_vidq, p); + else + return vb2_querybuf(&icd->vb2_vidq, p); } static int soc_camera_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); if (icd->streamer != file) return -EBUSY; - return videobuf_qbuf(&icd->vb_vidq, p); + if (ici->ops->init_videobuf) + return videobuf_qbuf(&icd->vb_vidq, p); + else + return vb2_qbuf(&icd->vb2_vidq, p); } static int soc_camera_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); if (icd->streamer != file) return -EBUSY; - return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK); + if (ici->ops->init_videobuf) + return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK); + else + return vb2_dqbuf(&icd->vb2_vidq, p, file->f_flags & O_NONBLOCK); } /* Always entered with .video_lock held */ @@ -372,8 +390,9 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, icd->user_width = pix->width; icd->user_height = pix->height; icd->colorspace = pix->colorspace; - icd->vb_vidq.field = - icd->field = pix->field; + icd->field = pix->field; + if (ici->ops->init_videobuf) + icd->vb_vidq.field = pix->field; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", @@ -453,7 +472,13 @@ static int soc_camera_open(struct file *file) if (ret < 0) goto esfmt; - ici->ops->init_videobuf(&icd->vb_vidq, icd); + if (ici->ops->init_videobuf) { + ici->ops->init_videobuf(&icd->vb_vidq, icd); + } else { + ret = ici->ops->init_videobuf2(&icd->vb2_vidq, icd); + if (ret < 0) + goto einitvb; + } } file->private_data = icd; @@ -465,6 +490,7 @@ static int soc_camera_open(struct file *file) * First four errors are entered with the .video_lock held * and use_count == 1 */ +einitvb: esfmt: pm_runtime_disable(&icd->vdev->dev); eresume: @@ -491,6 +517,8 @@ static int soc_camera_close(struct file *file) pm_runtime_disable(&icd->vdev->dev); ici->ops->remove(icd); + if (ici->ops->init_videobuf2) + vb2_queue_release(&icd->vb2_vidq); soc_camera_power_set(icd, icl, 0); } @@ -519,6 +547,7 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf, static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) { struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); int err; dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma); @@ -526,7 +555,10 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) if (icd->streamer != file) return -EBUSY; - err = videobuf_mmap_mapper(&icd->vb_vidq, vma); + if (ici->ops->init_videobuf) + err = videobuf_mmap_mapper(&icd->vb_vidq, vma); + else + err = vb2_mmap(&icd->vb2_vidq, vma); dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, @@ -544,7 +576,7 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) if (icd->streamer != file) return -EBUSY; - if (list_empty(&icd->vb_vidq.stream)) { + if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) { dev_err(&icd->dev, "Trying to poll with no queued buffers!\n"); return POLLERR; } @@ -552,6 +584,20 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt) return ici->ops->poll(file, pt); } +void soc_camera_lock(struct vb2_queue *vq) +{ + struct soc_camera_device *icd = vb2_get_drv_priv(vq); + mutex_lock(&icd->video_lock); +} +EXPORT_SYMBOL(soc_camera_lock); + +void soc_camera_unlock(struct vb2_queue *vq) +{ + struct soc_camera_device *icd = vb2_get_drv_priv(vq); + mutex_unlock(&icd->video_lock); +} +EXPORT_SYMBOL(soc_camera_unlock); + static struct v4l2_file_operations soc_camera_fops = { .owner = THIS_MODULE, .open = soc_camera_open, @@ -615,7 +661,7 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, pix->width = icd->user_width; pix->height = icd->user_height; - pix->field = icd->vb_vidq.field; + pix->field = icd->field; pix->pixelformat = icd->current_fmt->host_fmt->fourcc; pix->bytesperline = soc_mbus_bytes_per_line(pix->width, icd->current_fmt->host_fmt); @@ -644,6 +690,7 @@ static int soc_camera_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct soc_camera_device *icd = file->private_data; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct v4l2_subdev *sd = soc_camera_to_subdev(icd); int ret; @@ -656,7 +703,11 @@ static int soc_camera_streamon(struct file *file, void *priv, return -EBUSY; /* This calls buf_queue from host driver's videobuf_queue_ops */ - ret = videobuf_streamon(&icd->vb_vidq); + if (ici->ops->init_videobuf) + ret = videobuf_streamon(&icd->vb_vidq); + else + ret = vb2_streamon(&icd->vb2_vidq, i); + if (!ret) v4l2_subdev_call(sd, video, s_stream, 1); @@ -668,6 +719,7 @@ static int soc_camera_streamoff(struct file *file, void *priv, { struct soc_camera_device *icd = file->private_data; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); WARN_ON(priv != file->private_data); @@ -681,7 +733,10 @@ static int soc_camera_streamoff(struct file *file, void *priv, * This calls buf_release from host driver's videobuf_queue_ops for all * remaining buffers. When the last buffer is freed, stop capture */ - videobuf_streamoff(&icd->vb_vidq); + if (ici->ops->init_videobuf) + videobuf_streamoff(&icd->vb_vidq); + else + vb2_streamoff(&icd->vb2_vidq, i); v4l2_subdev_call(sd, video, s_stream, 0); @@ -1226,8 +1281,9 @@ int soc_camera_host_register(struct soc_camera_host *ici) !ici->ops->set_fmt || !ici->ops->set_bus_param || !ici->ops->querycap || - !ici->ops->init_videobuf || - !ici->ops->reqbufs || + ((!ici->ops->init_videobuf || + !ici->ops->reqbufs) && + !ici->ops->init_videobuf2) || !ici->ops->add || !ici->ops->remove || !ici->ops->poll || -- cgit v1.2.2 From a616898d6df29b8ffaea5742f678b3ac223b307c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 18 Feb 2011 05:30:15 -0300 Subject: [media] V4L: sh_mobile_ceu_camera: convert to videobuf2 Convert the sh_mobile_ceu_camera driver to the videobuf2 API. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 +- drivers/media/video/sh_mobile_ceu_camera.c | 264 ++++++++++++----------------- 2 files changed, 112 insertions(+), 154 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 07c5baaa2d0f..cf81bd536a71 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -877,7 +877,7 @@ config VIDEO_SH_MOBILE_CSI2 config VIDEO_SH_MOBILE_CEU tristate "SuperH Mobile CEU Interface driver" depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG ---help--- This is a v4l2 driver for the SuperH Mobile CEU Interface diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 954222bc3458..325f50d0adee 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include @@ -87,7 +87,8 @@ /* per video frame buffer */ struct sh_mobile_ceu_buffer { - struct videobuf_buffer vb; /* v4l buffer must be first */ + struct vb2_buffer vb; /* v4l buffer must be first */ + struct list_head queue; enum v4l2_mbus_pixelcode code; }; @@ -99,16 +100,17 @@ struct sh_mobile_ceu_dev { void __iomem *base; unsigned long video_limit; - /* lock used to protect videobuf */ - spinlock_t lock; + spinlock_t lock; /* Protects video buffer lists */ struct list_head capture; - struct videobuf_buffer *active; + struct vb2_buffer *active; + struct vb2_alloc_ctx *alloc_ctx; struct sh_mobile_ceu_info *pdata; u32 cflcr; enum v4l2_field field; + int sequence; unsigned int image_mode:1; unsigned int is_16bit:1; @@ -133,6 +135,11 @@ struct sh_mobile_ceu_cam { enum v4l2_mbus_pixelcode code; }; +static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb) +{ + return container_of(vb, struct sh_mobile_ceu_buffer, vb); +} + static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) { unsigned long flags; @@ -205,11 +212,11 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev) /* * Videobuf operations */ -static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, - unsigned int *count, - unsigned int *size) +static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq, + unsigned int *count, unsigned int *num_planes, + unsigned long sizes[], void *alloc_ctxs[]) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, @@ -218,39 +225,25 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, if (bytes_per_line < 0) return bytes_per_line; - *size = bytes_per_line * icd->user_height; + *num_planes = 1; + + pcdev->sequence = 0; + sizes[0] = bytes_per_line * icd->user_height; + alloc_ctxs[0] = pcdev->alloc_ctx; - if (0 == *count) + if (!*count) *count = 2; if (pcdev->video_limit) { - if (PAGE_ALIGN(*size) * *count > pcdev->video_limit) - *count = pcdev->video_limit / PAGE_ALIGN(*size); + if (PAGE_ALIGN(sizes[0]) * *count > pcdev->video_limit) + *count = pcdev->video_limit / PAGE_ALIGN(sizes[0]); } - dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); + dev_dbg(icd->dev.parent, "count=%d, size=%lu\n", *count, sizes[0]); return 0; } -static void free_buffer(struct videobuf_queue *vq, - struct sh_mobile_ceu_buffer *buf) -{ - struct soc_camera_device *icd = vq->priv_data; - struct device *dev = icd->dev.parent; - - dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, - &buf->vb, buf->vb.baddr, buf->vb.bsize); - - if (in_interrupt()) - BUG(); - - videobuf_waiton(vq, &buf->vb, 0, 0); - videobuf_dma_contig_free(vq, &buf->vb); - dev_dbg(dev, "%s freed\n", __func__); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - #define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */ #define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */ #define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */ @@ -309,7 +302,10 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) bottom2 = CDBCR; } - phys_addr_top = videobuf_to_dma_contig(pcdev->active); + /* mem_ops->cookie must not be NULL */ + phys_addr_top = (dma_addr_t)icd->vb2_vidq.mem_ops->cookie(pcdev-> + active->planes[0].mem_priv); + ceu_write(pcdev, top1, phys_addr_top); if (V4L2_FIELD_NONE != pcdev->field) { phys_addr_bottom = phys_addr_top + icd->user_width; @@ -330,87 +326,67 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) } } - pcdev->active->state = VIDEOBUF_ACTIVE; ceu_write(pcdev, CAPSR, 0x1); /* start capture */ return ret; } -static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int sh_mobile_ceu_videobuf_prepare(struct vb2_buffer *vb) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); struct sh_mobile_ceu_buffer *buf; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - int ret; + unsigned long size; if (bytes_per_line < 0) return bytes_per_line; - buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); + buf = to_ceu_vb(vb); - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, - vb, vb->baddr, vb->bsize); + dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, + vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); /* Added list head initialization on alloc */ - WARN_ON(!list_empty(&vb->queue)); + WARN(!list_empty(&buf->queue), "Buffer %p on queue!\n", vb); #ifdef DEBUG /* * This can be useful if you want to see if we actually fill * the buffer with something */ - memset((void *)vb->baddr, 0xaa, vb->bsize); + if (vb2_plane_vaddr(vb, 0)) + memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); #endif BUG_ON(NULL == icd->current_fmt); - if (buf->code != icd->current_fmt->code || - vb->width != icd->user_width || - vb->height != icd->user_height || - vb->field != field) { - buf->code = icd->current_fmt->code; - vb->width = icd->user_width; - vb->height = icd->user_height; - vb->field = field; - vb->state = VIDEOBUF_NEEDS_INIT; - } + size = icd->user_height * bytes_per_line; - vb->size = vb->height * bytes_per_line; - if (0 != vb->baddr && vb->bsize < vb->size) { - ret = -EINVAL; - goto out; + if (vb2_plane_size(vb, 0) < size) { + dev_err(icd->dev.parent, "Buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -ENOBUFS; } - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret) - goto fail; - vb->state = VIDEOBUF_PREPARED; - } + vb2_set_plane_payload(vb, 0, size); return 0; -fail: - free_buffer(vq, buf); -out: - return ret; } -/* Called under spinlock_irqsave(&pcdev->lock, ...) */ -static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; + struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); + unsigned long flags; - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, - vb, vb->baddr, vb->bsize); + dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__, + vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0)); - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &pcdev->capture); + spin_lock_irqsave(&pcdev->lock, flags); + list_add_tail(&buf->queue, &pcdev->capture); if (!pcdev->active) { /* @@ -421,13 +397,14 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, pcdev->active = vb; sh_mobile_ceu_capture(pcdev); } + spin_unlock_irqrestore(&pcdev->lock, flags); } -static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = container_of(vb->vb2_queue, struct soc_camera_device, vb2_vidq); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb); struct sh_mobile_ceu_dev *pcdev = ici->priv; unsigned long flags; @@ -439,53 +416,60 @@ static void sh_mobile_ceu_videobuf_release(struct videobuf_queue *vq, pcdev->active = NULL; } - if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && - !list_empty(&vb->queue)) { - vb->state = VIDEOBUF_ERROR; - list_del_init(&vb->queue); - } + /* Doesn't hurt also if the list is empty */ + list_del_init(&buf->queue); spin_unlock_irqrestore(&pcdev->lock, flags); +} - free_buffer(vq, container_of(vb, struct sh_mobile_ceu_buffer, vb)); +static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb) +{ + /* This is for locking debugging only */ + INIT_LIST_HEAD(&to_ceu_vb(vb)->queue); + return 0; } -static struct videobuf_queue_ops sh_mobile_ceu_videobuf_ops = { - .buf_setup = sh_mobile_ceu_videobuf_setup, - .buf_prepare = sh_mobile_ceu_videobuf_prepare, - .buf_queue = sh_mobile_ceu_videobuf_queue, - .buf_release = sh_mobile_ceu_videobuf_release, +static struct vb2_ops sh_mobile_ceu_videobuf_ops = { + .queue_setup = sh_mobile_ceu_videobuf_setup, + .buf_prepare = sh_mobile_ceu_videobuf_prepare, + .buf_queue = sh_mobile_ceu_videobuf_queue, + .buf_cleanup = sh_mobile_ceu_videobuf_release, + .buf_init = sh_mobile_ceu_videobuf_init, + .wait_prepare = soc_camera_unlock, + .wait_finish = soc_camera_lock, }; static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) { struct sh_mobile_ceu_dev *pcdev = data; - struct videobuf_buffer *vb; - unsigned long flags; + struct vb2_buffer *vb; + int ret; - spin_lock_irqsave(&pcdev->lock, flags); + spin_lock(&pcdev->lock); vb = pcdev->active; if (!vb) /* Stale interrupt from a released buffer */ goto out; - list_del_init(&vb->queue); + list_del_init(&to_ceu_vb(vb)->queue); if (!list_empty(&pcdev->capture)) - pcdev->active = list_entry(pcdev->capture.next, - struct videobuf_buffer, queue); + pcdev->active = &list_entry(pcdev->capture.next, + struct sh_mobile_ceu_buffer, queue)->vb; else pcdev->active = NULL; - vb->state = (sh_mobile_ceu_capture(pcdev) < 0) ? - VIDEOBUF_ERROR : VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - wake_up(&vb->done); + ret = sh_mobile_ceu_capture(pcdev); + do_gettimeofday(&vb->v4l2_buf.timestamp); + if (!ret) { + vb->v4l2_buf.field = pcdev->field; + vb->v4l2_buf.sequence = pcdev->sequence++; + } + vb2_buffer_done(vb, ret < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); out: - spin_unlock_irqrestore(&pcdev->lock, flags); + spin_unlock(&pcdev->lock); return IRQ_HANDLED; } @@ -529,9 +513,8 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) /* make sure active buffer is canceled */ spin_lock_irqsave(&pcdev->lock, flags); if (pcdev->active) { - list_del(&pcdev->active->queue); - pcdev->active->state = VIDEOBUF_ERROR; - wake_up_all(&pcdev->active->done); + list_del_init(&to_ceu_vb(pcdev->active)->queue); + vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR); pcdev->active = NULL; } spin_unlock_irqrestore(&pcdev->lock, flags); @@ -686,6 +669,7 @@ static void capture_restore(struct sh_mobile_ceu_dev *pcdev, u32 capsr) ceu_write(pcdev, CAPSR, capsr); } +/* Capture is not running, no interrupts, no locking needed */ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) { @@ -1726,43 +1710,11 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, return ret; } -static int sh_mobile_ceu_reqbufs(struct soc_camera_device *icd, - struct v4l2_requestbuffers *p) -{ - int i; - - /* - * This is for locking debugging only. I removed spinlocks and now I - * check whether .prepare is ever called on a linked buffer, or whether - * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered - */ - for (i = 0; i < p->count; i++) { - struct sh_mobile_ceu_buffer *buf; - - buf = container_of(icd->vb_vidq.bufs[i], - struct sh_mobile_ceu_buffer, vb); - INIT_LIST_HEAD(&buf->vb.queue); - } - - return 0; -} - static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt) { struct soc_camera_device *icd = file->private_data; - struct sh_mobile_ceu_buffer *buf; - - buf = list_entry(icd->vb_vidq.stream.next, - struct sh_mobile_ceu_buffer, vb.stream); - - poll_wait(file, &buf->vb.done, pt); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - return POLLIN|POLLRDNORM; - - return 0; + return vb2_poll(&icd->vb2_vidq, file, pt); } static int sh_mobile_ceu_querycap(struct soc_camera_host *ici, @@ -1774,19 +1726,17 @@ static int sh_mobile_ceu_querycap(struct soc_camera_host *ici, return 0; } -static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, - struct soc_camera_device *icd) +static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, + struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct sh_mobile_ceu_dev *pcdev = ici->priv; - - videobuf_queue_dma_contig_init(q, - &sh_mobile_ceu_videobuf_ops, - icd->dev.parent, &pcdev->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - pcdev->field, - sizeof(struct sh_mobile_ceu_buffer), - icd, &icd->video_lock); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = icd; + q->ops = &sh_mobile_ceu_videobuf_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); + + return vb2_queue_init(q); } static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd, @@ -1850,11 +1800,10 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = { .try_fmt = sh_mobile_ceu_try_fmt, .set_ctrl = sh_mobile_ceu_set_ctrl, .get_ctrl = sh_mobile_ceu_get_ctrl, - .reqbufs = sh_mobile_ceu_reqbufs, .poll = sh_mobile_ceu_poll, .querycap = sh_mobile_ceu_querycap, .set_bus_param = sh_mobile_ceu_set_bus_param, - .init_videobuf = sh_mobile_ceu_init_videobuf, + .init_videobuf2 = sh_mobile_ceu_init_videobuf, .controls = sh_mobile_ceu_controls, .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), }; @@ -2005,12 +1954,20 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) } } + pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(pcdev->alloc_ctx)) { + err = PTR_ERR(pcdev->alloc_ctx); + goto exit_module_put; + } + err = soc_camera_host_register(&pcdev->ici); if (err) - goto exit_module_put; + goto exit_free_ctx; return 0; +exit_free_ctx: + vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); exit_module_put: if (csi2 && csi2->driver) module_put(csi2->driver->owner); @@ -2041,6 +1998,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev) if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) dma_release_declared_memory(&pdev->dev); iounmap(pcdev->base); + vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx); if (csi2 && csi2->driver) module_put(csi2->driver->owner); kfree(pcdev); -- cgit v1.2.2 From 379fa5d3567ca2c20843bdba06e456de51b195e9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 21 Feb 2011 07:14:01 -0300 Subject: [media] V4L: mx3_camera: convert to videobuf2 Now that soc-camera supports videobuf API v1 and v2, camera-host drivers can be converted to videobuf2 individually. This patch converts the mx3_camera driver. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mx3_camera.c | 345 ++++++++++++++++----------------------- 1 file changed, 141 insertions(+), 204 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index c8c6c03a6a62..502e2a40964c 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -62,10 +62,16 @@ #define MAX_VIDEO_MEM 16 +enum csi_buffer_state { + CSI_BUF_NEEDS_INIT, + CSI_BUF_PREPARED, +}; + struct mx3_camera_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - enum v4l2_mbus_pixelcode code; + struct vb2_buffer vb; + enum csi_buffer_state state; + struct list_head queue; /* One descriptot per scatterlist (per frame) */ struct dma_async_tx_descriptor *txd; @@ -108,6 +114,9 @@ struct mx3_camera_dev { struct list_head capture; spinlock_t lock; /* Protects video buffer lists */ struct mx3_camera_buffer *active; + struct vb2_alloc_ctx *alloc_ctx; + enum v4l2_field field; + int sequence; /* IDMAC / dmaengine interface */ struct idmac_channel *idmac_channel[1]; /* We need one channel */ @@ -130,6 +139,11 @@ static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg) __raw_writel(value, mx3->base + reg); } +static struct mx3_camera_buffer *to_mx3_vb(struct vb2_buffer *vb) +{ + return container_of(vb, struct mx3_camera_buffer, vb); +} + /* Called from the IPU IDMAC ISR */ static void mx3_cam_dma_done(void *arg) { @@ -137,20 +151,20 @@ static void mx3_cam_dma_done(void *arg) struct dma_chan *chan = desc->txd.chan; struct idmac_channel *ichannel = to_idmac_chan(chan); struct mx3_camera_dev *mx3_cam = ichannel->client; - struct videobuf_buffer *vb; dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n", desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0); spin_lock(&mx3_cam->lock); if (mx3_cam->active) { - vb = &mx3_cam->active->vb; - - list_del_init(&vb->queue); - vb->state = VIDEOBUF_DONE; - do_gettimeofday(&vb->ts); - vb->field_count++; - wake_up(&vb->done); + struct vb2_buffer *vb = &mx3_cam->active->vb; + struct mx3_camera_buffer *buf = to_mx3_vb(vb); + + list_del_init(&buf->queue); + do_gettimeofday(&vb->v4l2_buf.timestamp); + vb->v4l2_buf.field = mx3_cam->field; + vb->v4l2_buf.sequence = mx3_cam->sequence++; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); } if (list_empty(&mx3_cam->capture)) { @@ -165,50 +179,22 @@ static void mx3_cam_dma_done(void *arg) } mx3_cam->active = list_entry(mx3_cam->capture.next, - struct mx3_camera_buffer, vb.queue); - mx3_cam->active->vb.state = VIDEOBUF_ACTIVE; + struct mx3_camera_buffer, queue); spin_unlock(&mx3_cam->lock); } -static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf) -{ - struct soc_camera_device *icd = vq->priv_data; - struct videobuf_buffer *vb = &buf->vb; - struct dma_async_tx_descriptor *txd = buf->txd; - struct idmac_channel *ichan; - - BUG_ON(in_interrupt()); - - dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, - vb, vb->baddr, vb->bsize); - - /* - * This waits until this buffer is out of danger, i.e., until it is no - * longer in STATE_QUEUED or STATE_ACTIVE - */ - videobuf_waiton(vq, vb, 0, 0); - if (txd) { - ichan = to_idmac_chan(txd->chan); - async_tx_ack(txd); - } - videobuf_dma_contig_free(vq, vb); - buf->txd = NULL; - - vb->state = VIDEOBUF_NEEDS_INIT; -} - /* * Videobuf operations */ /* * Calculate the __buffer__ (not data) size and number of buffers. - * Called with .vb_lock held */ -static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int mx3_videobuf_setup(struct vb2_queue *vq, + unsigned int *count, unsigned int *num_planes, + unsigned long sizes[], void *alloc_ctxs[]) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = soc_camera_from_vb2q(vq); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, @@ -220,104 +206,66 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, if (!mx3_cam->idmac_channel[0]) return -EINVAL; - *size = bytes_per_line * icd->user_height; + *num_planes = 1; + + mx3_cam->sequence = 0; + sizes[0] = bytes_per_line * icd->user_height; + alloc_ctxs[0] = mx3_cam->alloc_ctx; if (!*count) *count = 32; - if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024) - *count = MAX_VIDEO_MEM * 1024 * 1024 / *size; + if (sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024) + *count = MAX_VIDEO_MEM * 1024 * 1024 / sizes[0]; return 0; } -/* Called with .vb_lock held */ -static int mx3_videobuf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) +static int mx3_videobuf_prepare(struct vb2_buffer *vb) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = - container_of(vb, struct mx3_camera_buffer, vb); + struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; + struct scatterlist *sg; + struct mx3_camera_buffer *buf; size_t new_size; - int ret; int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); if (bytes_per_line < 0) return bytes_per_line; - new_size = bytes_per_line * icd->user_height; - - /* - * I think, in buf_prepare you only have to protect global data, - * the actual buffer is yours - */ + buf = to_mx3_vb(vb); + sg = &buf->sg; - if (buf->code != icd->current_fmt->code || - vb->width != icd->user_width || - vb->height != icd->user_height || - vb->field != field) { - buf->code = icd->current_fmt->code; - vb->width = icd->user_width; - vb->height = icd->user_height; - vb->field = field; - if (vb->state != VIDEOBUF_NEEDS_INIT) - free_buffer(vq, buf); - } + new_size = bytes_per_line * icd->user_height; - if (vb->baddr && vb->bsize < new_size) { - /* User provided buffer, but it is too small */ - ret = -ENOMEM; - goto out; + if (vb2_plane_size(vb, 0) < new_size) { + dev_err(icd->dev.parent, "Buffer too small (%lu < %zu)\n", + vb2_plane_size(vb, 0), new_size); + return -ENOBUFS; } - if (vb->state == VIDEOBUF_NEEDS_INIT) { - struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - struct scatterlist *sg = &buf->sg; - - /* - * The total size of video-buffers that will be allocated / mapped. - * *size that we calculated in videobuf_setup gets assigned to - * vb->bsize, and now we use the same calculation to get vb->size. - */ - vb->size = new_size; - - /* This actually (allocates and) maps buffers */ - ret = videobuf_iolock(vq, vb, NULL); - if (ret) - goto fail; - - /* - * We will have to configure the IDMAC channel. It has two slots - * for DMA buffers, we shall enter the first two buffers there, - * and then submit new buffers in DMA-ready interrupts - */ - sg_init_table(sg, 1); - sg_dma_address(sg) = videobuf_to_dma_contig(vb); - sg_dma_len(sg) = vb->size; + if (buf->state == CSI_BUF_NEEDS_INIT) { + sg_dma_address(sg) = vb2_dma_contig_plane_paddr(vb, 0); + sg_dma_len(sg) = new_size; buf->txd = ichan->dma_chan.device->device_prep_slave_sg( &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE, DMA_PREP_INTERRUPT); - if (!buf->txd) { - ret = -EIO; - goto fail; - } + if (!buf->txd) + return -EIO; buf->txd->callback_param = buf->txd; buf->txd->callback = mx3_cam_dma_done; - vb->state = VIDEOBUF_PREPARED; + buf->state = CSI_BUF_PREPARED; } - return 0; + vb2_set_plane_payload(vb, 0, new_size); -fail: - free_buffer(vq, buf); -out: - return ret; + return 0; } static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) @@ -333,25 +281,18 @@ static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc) } } -/* - * Called with .vb_lock mutex held and - * under spinlock_irqsave(&mx3_cam->lock, ...) - */ -static void mx3_videobuf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void mx3_videobuf_queue(struct vb2_buffer *vb) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = - container_of(vb, struct mx3_camera_buffer, vb); + struct mx3_camera_buffer *buf = to_mx3_vb(vb); struct dma_async_tx_descriptor *txd = buf->txd; struct idmac_channel *ichan = to_idmac_chan(txd->chan); struct idmac_video_param *video = &ichan->params.video; dma_cookie_t cookie; u32 fourcc = icd->current_fmt->host_fmt->fourcc; - - BUG_ON(!irqs_disabled()); + unsigned long flags; /* This is the configuration of one sg-element */ video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); @@ -383,17 +324,15 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, #ifdef DEBUG /* helps to see what DMA actually has written */ - memset((void *)vb->baddr, 0xaa, vb->bsize); + if (vb2_plane_vaddr(vb, 0)) + memset(vb2_plane_vaddr(vb, 0), 0xaa, vb2_get_plane_payload(vb, 0)); #endif - list_add_tail(&vb->queue, &mx3_cam->capture); + spin_lock_irqsave(&mx3_cam->lock, flags); + list_add_tail(&buf->queue, &mx3_cam->capture); - if (!mx3_cam->active) { + if (!mx3_cam->active) mx3_cam->active = buf; - vb->state = VIDEOBUF_ACTIVE; - } else { - vb->state = VIDEOBUF_QUEUED; - } spin_unlock_irq(&mx3_cam->lock); @@ -401,67 +340,87 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, dev_dbg(icd->dev.parent, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg)); - spin_lock_irq(&mx3_cam->lock); - if (cookie >= 0) return; - /* Submit error */ - vb->state = VIDEOBUF_PREPARED; + spin_lock_irq(&mx3_cam->lock); - list_del_init(&vb->queue); + /* Submit error */ + list_del_init(&buf->queue); if (mx3_cam->active == buf) mx3_cam->active = NULL; + + spin_unlock_irqrestore(&mx3_cam->lock, flags); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); } -/* Called with .vb_lock held */ -static void mx3_videobuf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void mx3_videobuf_release(struct vb2_buffer *vb) { - struct soc_camera_device *icd = vq->priv_data; + struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; - struct mx3_camera_buffer *buf = - container_of(vb, struct mx3_camera_buffer, vb); + struct mx3_camera_buffer *buf = to_mx3_vb(vb); + struct dma_async_tx_descriptor *txd = buf->txd; unsigned long flags; dev_dbg(icd->dev.parent, - "Release%s DMA 0x%08x (state %d), queue %sempty\n", + "Release%s DMA 0x%08x, queue %sempty\n", mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg), - vb->state, list_empty(&vb->queue) ? "" : "not "); + list_empty(&buf->queue) ? "" : "not "); + spin_lock_irqsave(&mx3_cam->lock, flags); - if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) && - !list_empty(&vb->queue)) { - vb->state = VIDEOBUF_ERROR; - list_del_init(&vb->queue); - if (mx3_cam->active == buf) - mx3_cam->active = NULL; + if (mx3_cam->active == buf) + mx3_cam->active = NULL; + + /* Doesn't hurt also if the list is empty */ + list_del_init(&buf->queue); + buf->state = CSI_BUF_NEEDS_INIT; + + if (txd) { + buf->txd = NULL; + if (mx3_cam->idmac_channel[0]) + async_tx_ack(txd); } + spin_unlock_irqrestore(&mx3_cam->lock, flags); - free_buffer(vq, buf); } -static struct videobuf_queue_ops mx3_videobuf_ops = { - .buf_setup = mx3_videobuf_setup, - .buf_prepare = mx3_videobuf_prepare, - .buf_queue = mx3_videobuf_queue, - .buf_release = mx3_videobuf_release, +static int mx3_videobuf_init(struct vb2_buffer *vb) +{ + struct mx3_camera_buffer *buf = to_mx3_vb(vb); + /* This is for locking debugging only */ + INIT_LIST_HEAD(&buf->queue); + sg_init_table(&buf->sg, 1); + + buf->state = CSI_BUF_NEEDS_INIT; + buf->txd = NULL; + + return 0; +} + +static struct vb2_ops mx3_videobuf_ops = { + .queue_setup = mx3_videobuf_setup, + .buf_prepare = mx3_videobuf_prepare, + .buf_queue = mx3_videobuf_queue, + .buf_cleanup = mx3_videobuf_release, + .buf_init = mx3_videobuf_init, + .wait_prepare = soc_camera_unlock, + .wait_finish = soc_camera_lock, }; -static void mx3_camera_init_videobuf(struct videobuf_queue *q, +static int mx3_camera_init_videobuf(struct vb2_queue *q, struct soc_camera_device *icd) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - - videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, icd->dev.parent, - &mx3_cam->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_NONE, - sizeof(struct mx3_camera_buffer), icd, - &icd->video_lock); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = icd; + q->ops = &mx3_videobuf_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct mx3_camera_buffer); + + return vb2_queue_init(q); } /* First part of ipu_csi_init_interface() */ @@ -556,18 +515,6 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd) icd->devnum); } -static bool channel_change_requested(struct soc_camera_device *icd, - struct v4l2_rect *rect) -{ - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct mx3_camera_dev *mx3_cam = ici->priv; - struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; - - /* Do buffers have to be re-allocated or channel re-configured? */ - return ichan && rect->width * rect->height > - icd->user_width * icd->user_height; -} - static int test_platform_param(struct mx3_camera_dev *mx3_cam, unsigned char buswidth, unsigned long *flags) { @@ -808,18 +755,6 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) struct dma_chan_request rq = {.mx3_cam = mx3_cam, .id = IDMAC_IC_7}; - if (*ichan) { - struct videobuf_buffer *vb, *_vb; - dma_release_channel(&(*ichan)->dma_chan); - *ichan = NULL; - mx3_cam->active = NULL; - list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) { - list_del_init(&vb->queue); - vb->state = VIDEOBUF_ERROR; - wake_up(&vb->done); - } - } - dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_PRIVATE, mask); @@ -879,19 +814,8 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, return ret; } - if (mf.width != icd->user_width || mf.height != icd->user_height) { - /* - * We now know pixel formats and can decide upon DMA-channel(s) - * So far only direct camera-to-memory is supported - */ - if (channel_change_requested(icd, rect)) { - ret = acquire_dma_channel(mx3_cam); - if (ret < 0) - return ret; - } - + if (mf.width != icd->user_width || mf.height != icd->user_height) configure_geometry(mx3_cam, mf.width, mf.height, mf.code); - } dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", mf.width, mf.height); @@ -923,10 +847,6 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, stride_align(&pix->width); dev_dbg(icd->dev.parent, "Set format %dx%d\n", pix->width, pix->height); - ret = acquire_dma_channel(mx3_cam); - if (ret < 0) - return ret; - /* * Might have to perform a complete interface initialisation like in * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider @@ -948,9 +868,16 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, if (mf.code != xlate->code) return -EINVAL; + if (!mx3_cam->idmac_channel[0]) { + ret = acquire_dma_channel(mx3_cam); + if (ret < 0) + return ret; + } + pix->width = mf.width; pix->height = mf.height; pix->field = mf.field; + mx3_cam->field = mf.field; pix->colorspace = mf.colorspace; icd->current_fmt = xlate; @@ -1033,7 +960,7 @@ static unsigned int mx3_camera_poll(struct file *file, poll_table *pt) { struct soc_camera_device *icd = file->private_data; - return videobuf_poll_stream(file, &icd->vb_vidq, pt); + return vb2_poll(&icd->vb2_vidq, file, pt); } static int mx3_camera_querycap(struct soc_camera_host *ici, @@ -1207,7 +1134,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = { .set_fmt = mx3_camera_set_fmt, .try_fmt = mx3_camera_try_fmt, .get_formats = mx3_camera_get_formats, - .init_videobuf = mx3_camera_init_videobuf, + .init_videobuf2 = mx3_camera_init_videobuf, .reqbufs = mx3_camera_reqbufs, .poll = mx3_camera_poll, .querycap = mx3_camera_querycap, @@ -1283,6 +1210,12 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) soc_host->v4l2_dev.dev = &pdev->dev; soc_host->nr = pdev->id; + mx3_cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(mx3_cam->alloc_ctx)) { + err = PTR_ERR(mx3_cam->alloc_ctx); + goto eallocctx; + } + err = soc_camera_host_register(soc_host); if (err) goto ecamhostreg; @@ -1293,6 +1226,8 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) return 0; ecamhostreg: + vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); +eallocctx: iounmap(base); eioremap: clk_put(mx3_cam->clk); @@ -1322,6 +1257,8 @@ static int __devexit mx3_camera_remove(struct platform_device *pdev) if (WARN_ON(mx3_cam->idmac_channel[0])) dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan); + vb2_dma_contig_cleanup_ctx(mx3_cam->alloc_ctx); + vfree(mx3_cam); dmaengine_put(); -- cgit v1.2.2 From 787d0f9d5ca3e98f23af94037094a9a3fafec665 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 16 Feb 2011 18:42:24 -0300 Subject: [media] V4l: sh_mobile_ceu_camera: fix cropping offset calculation Use the correct scales to calculate cropping offsets. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 325f50d0adee..61f37012b4f8 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -1348,7 +1348,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, struct device *dev = icd->dev.parent; struct v4l2_mbus_framefmt mf; unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v, - out_width, out_height, scale_h, scale_v; + out_width, out_height; int interm_width, interm_height; u32 capsr, cflcr; int ret; @@ -1406,10 +1406,6 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, scale_ceu_h = calc_scale(interm_width, &out_width); scale_ceu_v = calc_scale(interm_height, &out_height); - /* Calculate camera scales */ - scale_h = calc_generic_scale(cam_rect->width, out_width); - scale_v = calc_generic_scale(cam_rect->height, out_height); - dev_geo(dev, "5: CEU scales %u:%u\n", scale_ceu_h, scale_ceu_v); /* Apply CEU scales. */ @@ -1421,8 +1417,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, icd->user_width = out_width; icd->user_height = out_height; - cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_h) & ~1; - cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_v) & ~1; + cam->ceu_left = scale_down(rect->left - cam_rect->left, scale_cam_h) & ~1; + cam->ceu_top = scale_down(rect->top - cam_rect->top, scale_cam_v) & ~1; /* 6. Use CEU cropping to crop to the new window. */ sh_mobile_ceu_set_rect(icd); @@ -1433,7 +1429,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, icd->user_width, icd->user_height, cam->ceu_left, cam->ceu_top); - /* Restore capture */ + /* Restore capture. The CE bit can be cleared by the hardware */ if (pcdev->active) capsr |= 1; capture_restore(pcdev, capsr); -- cgit v1.2.2 From 9bd060e492a2725c55404988ceed473a090bd04d Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Thu, 17 Feb 2011 19:14:33 -0300 Subject: [media] V4L: Initial submit of OV9740 driver This soc_camera driver is for Omnivision's OV9740 sensor. This initial submission provides support for YUV422 output at 1280x720 (720p), which is the sensor's native resolution. 640x480 (VGA) is also supported, with cropping and scaling performed by the sensor's ISP. This driver is heavily based off of the existing OV9640 driver. Signed-off-by: Andrew Chew Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 6 + drivers/media/video/Makefile | 1 + drivers/media/video/ov9740.c | 1009 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1016 insertions(+) create mode 100644 drivers/media/video/ov9740.c (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index cf81bd536a71..e2f5a69aa400 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -838,6 +838,12 @@ config SOC_CAMERA_OV9640 help This is a ov9640 camera driver +config SOC_CAMERA_OV9740 + tristate "ov9740 camera support" + depends on SOC_CAMERA && I2C + help + This is a ov9740 camera driver + config MX1_VIDEO bool diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 251b7cac3f91..ac54652396e3 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o +obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c new file mode 100644 index 000000000000..4d4ee4faca69 --- /dev/null +++ b/drivers/media/video/ov9740.c @@ -0,0 +1,1009 @@ +/* + * OmniVision OV9740 Camera Driver + * + * Copyright (C) 2011 NVIDIA Corporation + * + * Based on ov9640 camera driver. + * + * 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 +#include +#include +#include +#include +#include + +#define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) + +/* General Status Registers */ +#define OV9740_MODEL_ID_HI 0x0000 +#define OV9740_MODEL_ID_LO 0x0001 +#define OV9740_REVISION_NUMBER 0x0002 +#define OV9740_MANUFACTURER_ID 0x0003 +#define OV9740_SMIA_VERSION 0x0004 + +/* General Setup Registers */ +#define OV9740_MODE_SELECT 0x0100 +#define OV9740_IMAGE_ORT 0x0101 +#define OV9740_SOFTWARE_RESET 0x0103 +#define OV9740_GRP_PARAM_HOLD 0x0104 +#define OV9740_MSK_CORRUP_FM 0x0105 + +/* Timing Setting */ +#define OV9740_FRM_LENGTH_LN_HI 0x0340 /* VTS */ +#define OV9740_FRM_LENGTH_LN_LO 0x0341 /* VTS */ +#define OV9740_LN_LENGTH_PCK_HI 0x0342 /* HTS */ +#define OV9740_LN_LENGTH_PCK_LO 0x0343 /* HTS */ +#define OV9740_X_ADDR_START_HI 0x0344 +#define OV9740_X_ADDR_START_LO 0x0345 +#define OV9740_Y_ADDR_START_HI 0x0346 +#define OV9740_Y_ADDR_START_LO 0x0347 +#define OV9740_X_ADDR_END_HI 0x0348 +#define OV9740_X_ADDR_END_LO 0x0349 +#define OV9740_Y_ADDR_END_HI 0x034A +#define OV9740_Y_ADDR_END_LO 0x034B +#define OV9740_X_OUTPUT_SIZE_HI 0x034C +#define OV9740_X_OUTPUT_SIZE_LO 0x034D +#define OV9740_Y_OUTPUT_SIZE_HI 0x034E +#define OV9740_Y_OUTPUT_SIZE_LO 0x034F + +/* IO Control Registers */ +#define OV9740_IO_CREL00 0x3002 +#define OV9740_IO_CREL01 0x3004 +#define OV9740_IO_CREL02 0x3005 +#define OV9740_IO_OUTPUT_SEL01 0x3026 +#define OV9740_IO_OUTPUT_SEL02 0x3027 + +/* AWB Registers */ +#define OV9740_AWB_MANUAL_CTRL 0x3406 + +/* Analog Control Registers */ +#define OV9740_ANALOG_CTRL01 0x3601 +#define OV9740_ANALOG_CTRL02 0x3602 +#define OV9740_ANALOG_CTRL03 0x3603 +#define OV9740_ANALOG_CTRL04 0x3604 +#define OV9740_ANALOG_CTRL10 0x3610 +#define OV9740_ANALOG_CTRL12 0x3612 +#define OV9740_ANALOG_CTRL20 0x3620 +#define OV9740_ANALOG_CTRL21 0x3621 +#define OV9740_ANALOG_CTRL22 0x3622 +#define OV9740_ANALOG_CTRL30 0x3630 +#define OV9740_ANALOG_CTRL31 0x3631 +#define OV9740_ANALOG_CTRL32 0x3632 +#define OV9740_ANALOG_CTRL33 0x3633 + +/* Sensor Control */ +#define OV9740_SENSOR_CTRL03 0x3703 +#define OV9740_SENSOR_CTRL04 0x3704 +#define OV9740_SENSOR_CTRL05 0x3705 +#define OV9740_SENSOR_CTRL07 0x3707 + +/* Timing Control */ +#define OV9740_TIMING_CTRL17 0x3817 +#define OV9740_TIMING_CTRL19 0x3819 +#define OV9740_TIMING_CTRL33 0x3833 +#define OV9740_TIMING_CTRL35 0x3835 + +/* Banding Filter */ +#define OV9740_AEC_MAXEXPO_60_H 0x3A02 +#define OV9740_AEC_MAXEXPO_60_L 0x3A03 +#define OV9740_AEC_B50_STEP_HI 0x3A08 +#define OV9740_AEC_B50_STEP_LO 0x3A09 +#define OV9740_AEC_B60_STEP_HI 0x3A0A +#define OV9740_AEC_B60_STEP_LO 0x3A0B +#define OV9740_AEC_CTRL0D 0x3A0D +#define OV9740_AEC_CTRL0E 0x3A0E +#define OV9740_AEC_MAXEXPO_50_H 0x3A14 +#define OV9740_AEC_MAXEXPO_50_L 0x3A15 + +/* AEC/AGC Control */ +#define OV9740_AEC_ENABLE 0x3503 +#define OV9740_GAIN_CEILING_01 0x3A18 +#define OV9740_GAIN_CEILING_02 0x3A19 +#define OV9740_AEC_HI_THRESHOLD 0x3A11 +#define OV9740_AEC_3A1A 0x3A1A +#define OV9740_AEC_CTRL1B_WPT2 0x3A1B +#define OV9740_AEC_CTRL0F_WPT 0x3A0F +#define OV9740_AEC_CTRL10_BPT 0x3A10 +#define OV9740_AEC_CTRL1E_BPT2 0x3A1E +#define OV9740_AEC_LO_THRESHOLD 0x3A1F + +/* BLC Control */ +#define OV9740_BLC_AUTO_ENABLE 0x4002 +#define OV9740_BLC_MODE 0x4005 + +/* VFIFO */ +#define OV9740_VFIFO_READ_START_HI 0x4608 +#define OV9740_VFIFO_READ_START_LO 0x4609 + +/* DVP Control */ +#define OV9740_DVP_VSYNC_CTRL02 0x4702 +#define OV9740_DVP_VSYNC_MODE 0x4704 +#define OV9740_DVP_VSYNC_CTRL06 0x4706 + +/* PLL Setting */ +#define OV9740_PLL_MODE_CTRL01 0x3104 +#define OV9740_PRE_PLL_CLK_DIV 0x0305 +#define OV9740_PLL_MULTIPLIER 0x0307 +#define OV9740_VT_SYS_CLK_DIV 0x0303 +#define OV9740_VT_PIX_CLK_DIV 0x0301 +#define OV9740_PLL_CTRL3010 0x3010 +#define OV9740_VFIFO_CTRL00 0x460E + +/* ISP Control */ +#define OV9740_ISP_CTRL00 0x5000 +#define OV9740_ISP_CTRL01 0x5001 +#define OV9740_ISP_CTRL03 0x5003 +#define OV9740_ISP_CTRL05 0x5005 +#define OV9740_ISP_CTRL12 0x5012 +#define OV9740_ISP_CTRL19 0x5019 +#define OV9740_ISP_CTRL1A 0x501A +#define OV9740_ISP_CTRL1E 0x501E +#define OV9740_ISP_CTRL1F 0x501F +#define OV9740_ISP_CTRL20 0x5020 +#define OV9740_ISP_CTRL21 0x5021 + +/* AWB */ +#define OV9740_AWB_CTRL00 0x5180 +#define OV9740_AWB_CTRL01 0x5181 +#define OV9740_AWB_CTRL02 0x5182 +#define OV9740_AWB_CTRL03 0x5183 +#define OV9740_AWB_ADV_CTRL01 0x5184 +#define OV9740_AWB_ADV_CTRL02 0x5185 +#define OV9740_AWB_ADV_CTRL03 0x5186 +#define OV9740_AWB_ADV_CTRL04 0x5187 +#define OV9740_AWB_ADV_CTRL05 0x5188 +#define OV9740_AWB_ADV_CTRL06 0x5189 +#define OV9740_AWB_ADV_CTRL07 0x518A +#define OV9740_AWB_ADV_CTRL08 0x518B +#define OV9740_AWB_ADV_CTRL09 0x518C +#define OV9740_AWB_ADV_CTRL10 0x518D +#define OV9740_AWB_ADV_CTRL11 0x518E +#define OV9740_AWB_CTRL0F 0x518F +#define OV9740_AWB_CTRL10 0x5190 +#define OV9740_AWB_CTRL11 0x5191 +#define OV9740_AWB_CTRL12 0x5192 +#define OV9740_AWB_CTRL13 0x5193 +#define OV9740_AWB_CTRL14 0x5194 + +/* MIPI Control */ +#define OV9740_MIPI_CTRL00 0x4800 +#define OV9740_MIPI_3837 0x3837 +#define OV9740_MIPI_CTRL01 0x4801 +#define OV9740_MIPI_CTRL03 0x4803 +#define OV9740_MIPI_CTRL05 0x4805 +#define OV9740_VFIFO_RD_CTRL 0x4601 +#define OV9740_MIPI_CTRL_3012 0x3012 +#define OV9740_SC_CMMM_MIPI_CTR 0x3014 + +/* supported resolutions */ +enum { + OV9740_VGA, + OV9740_720P, +}; + +struct ov9740_resolution { + unsigned int width; + unsigned int height; +}; + +static struct ov9740_resolution ov9740_resolutions[] = { + [OV9740_VGA] = { + .width = 640, + .height = 480, + }, + [OV9740_720P] = { + .width = 1280, + .height = 720, + }, +}; + +/* Misc. structures */ +struct ov9740_reg { + u16 reg; + u8 val; +}; + +struct ov9740_priv { + struct v4l2_subdev subdev; + + int ident; + u16 model; + u8 revision; + u8 manid; + u8 smiaver; + + bool flag_vflip; + bool flag_hflip; +}; + +static const struct ov9740_reg ov9740_defaults[] = { + /* Banding Filter */ + { OV9740_AEC_B50_STEP_HI, 0x00 }, + { OV9740_AEC_B50_STEP_LO, 0xe8 }, + { OV9740_AEC_CTRL0E, 0x03 }, + { OV9740_AEC_MAXEXPO_50_H, 0x15 }, + { OV9740_AEC_MAXEXPO_50_L, 0xc6 }, + { OV9740_AEC_B60_STEP_HI, 0x00 }, + { OV9740_AEC_B60_STEP_LO, 0xc0 }, + { OV9740_AEC_CTRL0D, 0x04 }, + { OV9740_AEC_MAXEXPO_60_H, 0x18 }, + { OV9740_AEC_MAXEXPO_60_L, 0x20 }, + + /* LC */ + { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 }, + { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc }, + + /* Un-documented OV9740 registers */ + { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 }, + { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c }, + { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580A, 0x0e }, { 0x580B, 0x16 }, + { 0x580C, 0x06 }, { 0x580D, 0x02 }, { 0x580E, 0x00 }, { 0x580F, 0x00 }, + { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 }, + { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 }, + { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581A, 0x07 }, { 0x581B, 0x08 }, + { 0x581C, 0x0b }, { 0x581D, 0x14 }, { 0x581E, 0x28 }, { 0x581F, 0x23 }, + { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a }, + { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f }, + { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582A, 0x8f }, { 0x582B, 0x9e }, + { 0x582C, 0x8f }, { 0x582D, 0x9f }, { 0x582E, 0x4f }, { 0x582F, 0x87 }, + { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f }, + { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf }, + { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583A, 0x9f }, { 0x583B, 0x7f }, + { 0x583C, 0x5f }, + + /* Y Gamma */ + { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e }, + { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 }, + { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548A, 0xa4 }, { 0x548B, 0xb1 }, + { 0x548C, 0xc6 }, { 0x548D, 0xd8 }, { 0x548E, 0xe9 }, + + /* UV Gamma */ + { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 }, + { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 }, + { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549A, 0x02 }, { 0x549B, 0xeb }, + { 0x549C, 0x02 }, { 0x549D, 0xa0 }, { 0x549E, 0x02 }, { 0x549F, 0x67 }, + { 0x54A0, 0x02 }, { 0x54A1, 0x3b }, { 0x54A2, 0x02 }, { 0x54A3, 0x18 }, + { 0x54A4, 0x01 }, { 0x54A5, 0xe7 }, { 0x54A6, 0x01 }, { 0x54A7, 0xc3 }, + { 0x54A8, 0x01 }, { 0x54A9, 0x94 }, { 0x54AA, 0x01 }, { 0x54AB, 0x72 }, + { 0x54AC, 0x01 }, { 0x54AD, 0x57 }, + + /* AWB */ + { OV9740_AWB_CTRL00, 0xf0 }, + { OV9740_AWB_CTRL01, 0x00 }, + { OV9740_AWB_CTRL02, 0x41 }, + { OV9740_AWB_CTRL03, 0x42 }, + { OV9740_AWB_ADV_CTRL01, 0x8a }, + { OV9740_AWB_ADV_CTRL02, 0x61 }, + { OV9740_AWB_ADV_CTRL03, 0xce }, + { OV9740_AWB_ADV_CTRL04, 0xa8 }, + { OV9740_AWB_ADV_CTRL05, 0x17 }, + { OV9740_AWB_ADV_CTRL06, 0x1f }, + { OV9740_AWB_ADV_CTRL07, 0x27 }, + { OV9740_AWB_ADV_CTRL08, 0x41 }, + { OV9740_AWB_ADV_CTRL09, 0x34 }, + { OV9740_AWB_ADV_CTRL10, 0xf0 }, + { OV9740_AWB_ADV_CTRL11, 0x10 }, + { OV9740_AWB_CTRL0F, 0xff }, + { OV9740_AWB_CTRL10, 0x00 }, + { OV9740_AWB_CTRL11, 0xff }, + { OV9740_AWB_CTRL12, 0x00 }, + { OV9740_AWB_CTRL13, 0xff }, + { OV9740_AWB_CTRL14, 0x00 }, + + /* CIP */ + { 0x530D, 0x12 }, + + /* CMX */ + { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 }, + { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 }, + { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538A, 0x00 }, { 0x538B, 0x20 }, + { 0x538C, 0x00 }, { 0x538D, 0x00 }, { 0x538E, 0x00 }, { 0x538F, 0x16 }, + { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 }, + { 0x5394, 0x18 }, + + /* 50/60 Detection */ + { 0x3C0A, 0x9c }, { 0x3C0B, 0x3f }, + + /* Output Select */ + { OV9740_IO_OUTPUT_SEL01, 0x00 }, + { OV9740_IO_OUTPUT_SEL02, 0x00 }, + { OV9740_IO_CREL00, 0x00 }, + { OV9740_IO_CREL01, 0x00 }, + { OV9740_IO_CREL02, 0x00 }, + + /* AWB Control */ + { OV9740_AWB_MANUAL_CTRL, 0x00 }, + + /* Analog Control */ + { OV9740_ANALOG_CTRL03, 0xaa }, + { OV9740_ANALOG_CTRL32, 0x2f }, + { OV9740_ANALOG_CTRL20, 0x66 }, + { OV9740_ANALOG_CTRL21, 0xc0 }, + { OV9740_ANALOG_CTRL31, 0x52 }, + { OV9740_ANALOG_CTRL33, 0x50 }, + { OV9740_ANALOG_CTRL30, 0xca }, + { OV9740_ANALOG_CTRL04, 0x0c }, + { OV9740_ANALOG_CTRL01, 0x40 }, + { OV9740_ANALOG_CTRL02, 0x16 }, + { OV9740_ANALOG_CTRL10, 0xa1 }, + { OV9740_ANALOG_CTRL12, 0x24 }, + { OV9740_ANALOG_CTRL22, 0x9f }, + + /* Sensor Control */ + { OV9740_SENSOR_CTRL03, 0x42 }, + { OV9740_SENSOR_CTRL04, 0x10 }, + { OV9740_SENSOR_CTRL05, 0x45 }, + { OV9740_SENSOR_CTRL07, 0x14 }, + + /* Timing Control */ + { OV9740_TIMING_CTRL33, 0x04 }, + { OV9740_TIMING_CTRL35, 0x02 }, + { OV9740_TIMING_CTRL19, 0x6e }, + { OV9740_TIMING_CTRL17, 0x94 }, + + /* AEC/AGC Control */ + { OV9740_AEC_ENABLE, 0x10 }, + { OV9740_GAIN_CEILING_01, 0x00 }, + { OV9740_GAIN_CEILING_02, 0x7f }, + { OV9740_AEC_HI_THRESHOLD, 0xa0 }, + { OV9740_AEC_3A1A, 0x05 }, + { OV9740_AEC_CTRL1B_WPT2, 0x50 }, + { OV9740_AEC_CTRL0F_WPT, 0x50 }, + { OV9740_AEC_CTRL10_BPT, 0x4c }, + { OV9740_AEC_CTRL1E_BPT2, 0x4c }, + { OV9740_AEC_LO_THRESHOLD, 0x26 }, + + /* BLC Control */ + { OV9740_BLC_AUTO_ENABLE, 0x45 }, + { OV9740_BLC_MODE, 0x18 }, + + /* DVP Control */ + { OV9740_DVP_VSYNC_CTRL02, 0x04 }, + { OV9740_DVP_VSYNC_MODE, 0x00 }, + { OV9740_DVP_VSYNC_CTRL06, 0x08 }, + + /* PLL Setting */ + { OV9740_PLL_MODE_CTRL01, 0x20 }, + { OV9740_PRE_PLL_CLK_DIV, 0x03 }, + { OV9740_PLL_MULTIPLIER, 0x4c }, + { OV9740_VT_SYS_CLK_DIV, 0x01 }, + { OV9740_VT_PIX_CLK_DIV, 0x08 }, + { OV9740_PLL_CTRL3010, 0x01 }, + { OV9740_VFIFO_CTRL00, 0x82 }, + + /* Timing Setting */ + /* VTS */ + { OV9740_FRM_LENGTH_LN_HI, 0x03 }, + { OV9740_FRM_LENGTH_LN_LO, 0x07 }, + /* HTS */ + { OV9740_LN_LENGTH_PCK_HI, 0x06 }, + { OV9740_LN_LENGTH_PCK_LO, 0x62 }, + + /* MIPI Control */ + { OV9740_MIPI_CTRL00, 0x44 }, + { OV9740_MIPI_3837, 0x01 }, + { OV9740_MIPI_CTRL01, 0x0f }, + { OV9740_MIPI_CTRL03, 0x05 }, + { OV9740_MIPI_CTRL05, 0x10 }, + { OV9740_VFIFO_RD_CTRL, 0x16 }, + { OV9740_MIPI_CTRL_3012, 0x70 }, + { OV9740_SC_CMMM_MIPI_CTR, 0x01 }, +}; + +static const struct ov9740_reg ov9740_regs_vga[] = { + { OV9740_X_ADDR_START_HI, 0x00 }, + { OV9740_X_ADDR_START_LO, 0xa0 }, + { OV9740_Y_ADDR_START_HI, 0x00 }, + { OV9740_Y_ADDR_START_LO, 0x00 }, + { OV9740_X_ADDR_END_HI, 0x04 }, + { OV9740_X_ADDR_END_LO, 0x63 }, + { OV9740_Y_ADDR_END_HI, 0x02 }, + { OV9740_Y_ADDR_END_LO, 0xd3 }, + { OV9740_X_OUTPUT_SIZE_HI, 0x02 }, + { OV9740_X_OUTPUT_SIZE_LO, 0x80 }, + { OV9740_Y_OUTPUT_SIZE_HI, 0x01 }, + { OV9740_Y_OUTPUT_SIZE_LO, 0xe0 }, + { OV9740_ISP_CTRL1E, 0x03 }, + { OV9740_ISP_CTRL1F, 0xc0 }, + { OV9740_ISP_CTRL20, 0x02 }, + { OV9740_ISP_CTRL21, 0xd0 }, + { OV9740_VFIFO_READ_START_HI, 0x01 }, + { OV9740_VFIFO_READ_START_LO, 0x40 }, + { OV9740_ISP_CTRL00, 0xff }, + { OV9740_ISP_CTRL01, 0xff }, + { OV9740_ISP_CTRL03, 0xff }, +}; + +static const struct ov9740_reg ov9740_regs_720p[] = { + { OV9740_X_ADDR_START_HI, 0x00 }, + { OV9740_X_ADDR_START_LO, 0x00 }, + { OV9740_Y_ADDR_START_HI, 0x00 }, + { OV9740_Y_ADDR_START_LO, 0x00 }, + { OV9740_X_ADDR_END_HI, 0x05 }, + { OV9740_X_ADDR_END_LO, 0x03 }, + { OV9740_Y_ADDR_END_HI, 0x02 }, + { OV9740_Y_ADDR_END_LO, 0xd3 }, + { OV9740_X_OUTPUT_SIZE_HI, 0x05 }, + { OV9740_X_OUTPUT_SIZE_LO, 0x00 }, + { OV9740_Y_OUTPUT_SIZE_HI, 0x02 }, + { OV9740_Y_OUTPUT_SIZE_LO, 0xd0 }, + { OV9740_ISP_CTRL1E, 0x05 }, + { OV9740_ISP_CTRL1F, 0x00 }, + { OV9740_ISP_CTRL20, 0x02 }, + { OV9740_ISP_CTRL21, 0xd0 }, + { OV9740_VFIFO_READ_START_HI, 0x02 }, + { OV9740_VFIFO_READ_START_LO, 0x30 }, + { OV9740_ISP_CTRL00, 0xff }, + { OV9740_ISP_CTRL01, 0xef }, + { OV9740_ISP_CTRL03, 0xff }, +}; + +static enum v4l2_mbus_pixelcode ov9740_codes[] = { + V4L2_MBUS_FMT_YUYV8_2X8, +}; + +static const struct v4l2_queryctrl ov9740_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, +}; + +/* read a register */ +static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) +{ + int ret; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = (u8 *)®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = val, + }, + }; + + reg = swab16(reg); + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) { + dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg); + return ret; + } + + return 0; +} + +/* write a register */ +static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val) +{ + struct i2c_msg msg; + struct { + u16 reg; + u8 val; + } __packed buf; + int ret; + + reg = swab16(reg); + + buf.reg = reg; + buf.val = val; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 3; + msg.buf = (u8 *)&buf; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg); + return ret; + } + + return 0; +} + + +/* Read a register, alter its bits, write it back */ +static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset) +{ + u8 val; + int ret; + + ret = ov9740_reg_read(client, reg, &val); + if (ret < 0) { + dev_err(&client->dev, + "[Read]-Modify-Write of register %02x failed!\n", reg); + return ret; + } + + val |= set; + val &= ~unset; + + ret = ov9740_reg_write(client, reg, val); + if (ret < 0) { + dev_err(&client->dev, + "Read-Modify-[Write] of register %02x failed!\n", reg); + return ret; + } + + return 0; +} + +static int ov9740_reg_write_array(struct i2c_client *client, + const struct ov9740_reg *regarray, + int regarraylen) +{ + int i; + int ret; + + for (i = 0; i < regarraylen; i++) { + ret = ov9740_reg_write(client, + regarray[i].reg, regarray[i].val); + if (ret < 0) + return ret; + } + + return 0; +} + +/* Start/Stop streaming from the device */ +static int ov9740_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov9740_priv *priv = to_ov9740(sd); + int ret; + + /* Program orientation register. */ + if (priv->flag_vflip) + ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0); + else + ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2); + if (ret < 0) + return ret; + + if (priv->flag_hflip) + ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0); + else + ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1); + if (ret < 0) + return ret; + + if (enable) { + dev_dbg(&client->dev, "Enabling Streaming\n"); + /* Start Streaming */ + ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01); + + } else { + dev_dbg(&client->dev, "Disabling Streaming\n"); + /* Software Reset */ + ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01); + if (!ret) + /* Setting Streaming to Standby */ + ret = ov9740_reg_write(client, OV9740_MODE_SELECT, + 0x00); + } + + return ret; +} + +/* Alter bus settings on camera side */ +static int ov9740_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +/* Request bus settings on camera side */ +static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd) +{ + struct soc_camera_link *icl = to_soc_camera_link(icd); + + unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | + SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +/* Get status of additional camera capabilities */ +static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct ov9740_priv *priv = to_ov9740(sd); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + ctrl->value = priv->flag_vflip; + break; + case V4L2_CID_HFLIP: + ctrl->value = priv->flag_hflip; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* Set status of additional camera capabilities */ +static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +{ + struct ov9740_priv *priv = to_ov9740(sd); + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + priv->flag_vflip = ctrl->value; + break; + case V4L2_CID_HFLIP: + priv->flag_hflip = ctrl->value; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* Get chip identification */ +static int ov9740_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct ov9740_priv *priv = to_ov9740(sd); + + id->ident = priv->ident; + id->revision = priv->revision; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov9740_get_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u8 val; + + if (reg->reg & ~0xffff) + return -EINVAL; + + reg->size = 2; + + ret = ov9740_reg_read(client, reg->reg, &val); + if (ret) + return ret; + + reg->val = (__u64)val; + + return ret; +} + +static int ov9740_set_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg & ~0xffff || reg->val & ~0xff) + return -EINVAL; + + return ov9740_reg_write(client, reg->reg, reg->val); +} +#endif + +/* select nearest higher resolution for capture */ +static void ov9740_res_roundup(u32 *width, u32 *height) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ov9740_resolutions); i++) + if ((ov9740_resolutions[i].width >= *width) && + (ov9740_resolutions[i].height >= *height)) { + *width = ov9740_resolutions[i].width; + *height = ov9740_resolutions[i].height; + return; + } + + *width = ov9740_resolutions[OV9740_720P].width; + *height = ov9740_resolutions[OV9740_720P].height; +} + +/* Setup registers according to resolution and color encoding */ +static int ov9740_set_res(struct i2c_client *client, u32 width) +{ + int ret; + + /* select register configuration for given resolution */ + if (width == ov9740_resolutions[OV9740_VGA].width) { + dev_dbg(&client->dev, "Setting image size to 640x480\n"); + ret = ov9740_reg_write_array(client, ov9740_regs_vga, + ARRAY_SIZE(ov9740_regs_vga)); + } else if (width == ov9740_resolutions[OV9740_720P].width) { + dev_dbg(&client->dev, "Setting image size to 1280x720\n"); + ret = ov9740_reg_write_array(client, ov9740_regs_720p, + ARRAY_SIZE(ov9740_regs_720p)); + } else { + dev_err(&client->dev, "Failed to select resolution!\n"); + return -EINVAL; + } + + return ret; +} + +/* set the format we will capture in */ +static int ov9740_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + enum v4l2_colorspace cspace; + enum v4l2_mbus_pixelcode code = mf->code; + int ret; + + ov9740_res_roundup(&mf->width, &mf->height); + + switch (code) { + case V4L2_MBUS_FMT_YUYV8_2X8: + cspace = V4L2_COLORSPACE_SRGB; + break; + default: + return -EINVAL; + } + + ret = ov9740_reg_write_array(client, ov9740_defaults, + ARRAY_SIZE(ov9740_defaults)); + if (ret < 0) + return ret; + + ret = ov9740_set_res(client, mf->width); + if (ret < 0) + return ret; + + mf->code = code; + mf->colorspace = cspace; + + return ret; +} + +static int ov9740_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + ov9740_res_roundup(&mf->width, &mf->height); + + mf->field = V4L2_FIELD_NONE; + mf->code = V4L2_MBUS_FMT_YUYV8_2X8; + mf->colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + +static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(ov9740_codes)) + return -EINVAL; + + *code = ov9740_codes[index]; + + return 0; +} + +static int ov9740_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = 0; + a->bounds.top = 0; + a->bounds.width = ov9740_resolutions[OV9740_720P].width; + a->bounds.height = ov9740_resolutions[OV9740_720P].height; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + a->c.left = 0; + a->c.top = 0; + a->c.width = ov9740_resolutions[OV9740_720P].width; + a->c.height = ov9740_resolutions[OV9740_720P].height; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int ov9740_video_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9740_priv *priv = to_ov9740(sd); + u8 modelhi, modello; + int ret; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) { + dev_err(&client->dev, "Parent missing or invalid!\n"); + ret = -ENODEV; + goto err; + } + + /* + * check and show product ID and manufacturer ID + */ + ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi); + if (ret < 0) + goto err; + + ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello); + if (ret < 0) + goto err; + + priv->model = (modelhi << 8) | modello; + + ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision); + if (ret < 0) + goto err; + + ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid); + if (ret < 0) + goto err; + + ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver); + if (ret < 0) + goto err; + + if (priv->model != 0x9740) { + ret = -ENODEV; + goto err; + } + + priv->ident = V4L2_IDENT_OV9740; + + dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, " + "Manufacturer 0x%02x, SMIA Version 0x%02x\n", + priv->model, priv->revision, priv->manid, priv->smiaver); + +err: + return ret; +} + +static struct soc_camera_ops ov9740_ops = { + .set_bus_param = ov9740_set_bus_param, + .query_bus_param = ov9740_query_bus_param, + .controls = ov9740_controls, + .num_controls = ARRAY_SIZE(ov9740_controls), +}; + +static struct v4l2_subdev_core_ops ov9740_core_ops = { + .g_ctrl = ov9740_g_ctrl, + .s_ctrl = ov9740_s_ctrl, + .g_chip_ident = ov9740_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov9740_get_register, + .s_register = ov9740_set_register, +#endif + +}; + +static struct v4l2_subdev_video_ops ov9740_video_ops = { + .s_stream = ov9740_s_stream, + .s_mbus_fmt = ov9740_s_fmt, + .try_mbus_fmt = ov9740_try_fmt, + .enum_mbus_fmt = ov9740_enum_fmt, + .cropcap = ov9740_cropcap, + .g_crop = ov9740_g_crop, +}; + +static struct v4l2_subdev_ops ov9740_subdev_ops = { + .core = &ov9740_core_ops, + .video = &ov9740_video_ops, +}; + +/* + * i2c_driver function + */ +static int ov9740_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct ov9740_priv *priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "Missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "Missing platform_data for driver\n"); + return -EINVAL; + } + + priv = kzalloc(sizeof(struct ov9740_priv), GFP_KERNEL); + if (!priv) { + dev_err(&client->dev, "Failed to allocate private data!\n"); + return -ENOMEM; + } + + v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); + + icd->ops = &ov9740_ops; + + ret = ov9740_video_probe(icd, client); + if (ret < 0) { + icd->ops = NULL; + kfree(priv); + } + + return ret; +} + +static int ov9740_remove(struct i2c_client *client) +{ + struct ov9740_priv *priv = i2c_get_clientdata(client); + + kfree(priv); + + return 0; +} + +static const struct i2c_device_id ov9740_id[] = { + { "ov9740", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov9740_id); + +static struct i2c_driver ov9740_i2c_driver = { + .driver = { + .name = "ov9740", + }, + .probe = ov9740_probe, + .remove = ov9740_remove, + .id_table = ov9740_id, +}; + +static int __init ov9740_module_init(void) +{ + return i2c_add_driver(&ov9740_i2c_driver); +} + +static void __exit ov9740_module_exit(void) +{ + i2c_del_driver(&ov9740_i2c_driver); +} + +module_init(ov9740_module_init); +module_exit(ov9740_module_exit); + +MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740"); +MODULE_AUTHOR("Andrew Chew "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From f72cfd859b0e436d9f680790cb665ad1390187ae Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 25 Jan 2011 17:38:52 -0300 Subject: [media] video/cx231xx: Fix sparse warning: Using plain integer as NULL pointer This patch fixes the warning "Using plain integer as NULL pointer", generated by sparse, by replacing the offending 0s with NULL. Signed-off-by: Peter Huewe Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx-417.c | 4 ++-- drivers/media/video/cx231xx/cx231xx-cards.c | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c index fc9526a5b746..f8f0e59cd583 100644 --- a/drivers/media/video/cx231xx/cx231xx-417.c +++ b/drivers/media/video/cx231xx/cx231xx-417.c @@ -942,13 +942,13 @@ static int cx231xx_load_firmware(struct cx231xx *dev) p_current_fw = vmalloc(1884180 * 4); p_fw = p_current_fw; - if (p_current_fw == 0) { + if (p_current_fw == NULL) { dprintk(2, "FAIL!!!\n"); return -1; } p_buffer = vmalloc(4096); - if (p_buffer == 0) { + if (p_buffer == NULL) { dprintk(2, "FAIL!!!\n"); return -1; } diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 6540b8dfb6bb..f49230d170e6 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -360,19 +360,19 @@ struct cx231xx_board cx231xx_boards[] = { .type = CX231XX_VMUX_TELEVISION, .vmux = CX231XX_VIN_3_1, .amux = CX231XX_AMUX_VIDEO, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | (CX231XX_VIN_1_2 << 8) | CX25840_SVIDEO_ON, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, } }, }, [CX231XX_BOARD_HAUPPAUGE_USBLIVE2] = { @@ -391,14 +391,14 @@ struct cx231xx_board cx231xx_boards[] = { .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | (CX231XX_VIN_1_2 << 8) | CX25840_SVIDEO_ON, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, } }, }, [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = { @@ -425,19 +425,19 @@ struct cx231xx_board cx231xx_boards[] = { .type = CX231XX_VMUX_TELEVISION, .vmux = CX231XX_VIN_3_1, .amux = CX231XX_AMUX_VIDEO, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | (CX231XX_VIN_1_2 << 8) | CX25840_SVIDEO_ON, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, } }, }, [CX231XX_BOARD_PV_XCAPTURE_USB] = { -- cgit v1.2.2 From fa766c9be58bd872784b081074a7d15a3ce61c5f Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:00:00 -0300 Subject: [media] Altera FPGA firmware download module It uses STAPL files and programs Altera FPGA through JTAG. Interface to JTAG must be provided from main device module, for example through cx23885 GPIO. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/altera-stapl/Kconfig | 8 + drivers/staging/altera-stapl/Makefile | 3 + drivers/staging/altera-stapl/altera-comp.c | 142 ++ drivers/staging/altera-stapl/altera-exprt.h | 33 + drivers/staging/altera-stapl/altera-jtag.c | 1020 +++++++++++ drivers/staging/altera-stapl/altera-jtag.h | 113 ++ drivers/staging/altera-stapl/altera-lpt.c | 70 + drivers/staging/altera-stapl/altera.c | 2527 +++++++++++++++++++++++++++ 10 files changed, 3919 insertions(+) create mode 100644 drivers/staging/altera-stapl/Kconfig create mode 100644 drivers/staging/altera-stapl/Makefile create mode 100644 drivers/staging/altera-stapl/altera-comp.c create mode 100644 drivers/staging/altera-stapl/altera-exprt.h create mode 100644 drivers/staging/altera-stapl/altera-jtag.c create mode 100644 drivers/staging/altera-stapl/altera-jtag.h create mode 100644 drivers/staging/altera-stapl/altera-lpt.c create mode 100644 drivers/staging/altera-stapl/altera.c (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index a2742d8102c1..74a8b272154f 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -175,5 +175,7 @@ source "drivers/staging/cptm1217/Kconfig" source "drivers/staging/ste_rmi4/Kconfig" +source "drivers/staging/altera-stapl/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 4ddd3ce780e0..9f50ec90f9d8 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -66,5 +66,6 @@ obj-$(CONFIG_BCM_WIMAX) += bcm/ obj-$(CONFIG_FT1000) += ft1000/ obj-$(CONFIG_SND_INTEL_SST) += intel_sst/ obj-$(CONFIG_SPEAKUP) += speakup/ +obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ diff --git a/drivers/staging/altera-stapl/Kconfig b/drivers/staging/altera-stapl/Kconfig new file mode 100644 index 000000000000..7f01d8e93992 --- /dev/null +++ b/drivers/staging/altera-stapl/Kconfig @@ -0,0 +1,8 @@ +comment "Altera FPGA firmware download module" + +config ALTERA_STAPL + tristate "Altera FPGA firmware download module" + depends on I2C + default n + help + An Altera FPGA module. Say Y when you want to support this tool. diff --git a/drivers/staging/altera-stapl/Makefile b/drivers/staging/altera-stapl/Makefile new file mode 100644 index 000000000000..055f61ee781a --- /dev/null +++ b/drivers/staging/altera-stapl/Makefile @@ -0,0 +1,3 @@ +altera-stapl-objs = altera-lpt.o altera-jtag.o altera-comp.o altera.o + +obj-$(CONFIG_ALTERA_STAPL) += altera-stapl.o diff --git a/drivers/staging/altera-stapl/altera-comp.c b/drivers/staging/altera-stapl/altera-comp.c new file mode 100644 index 000000000000..49b103bedaaf --- /dev/null +++ b/drivers/staging/altera-stapl/altera-comp.c @@ -0,0 +1,142 @@ +/* + * altera-comp.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include "altera-exprt.h" + +#define SHORT_BITS 16 +#define CHAR_BITS 8 +#define DATA_BLOB_LENGTH 3 +#define MATCH_DATA_LENGTH 8192 +#define ALTERA_REQUEST_SIZE 1024 +#define ALTERA_BUFFER_SIZE (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE) + +static u32 altera_bits_req(u32 n) +{ + u32 result = SHORT_BITS; + + if (n == 0) + result = 1; + else { + /* Look for the highest non-zero bit position */ + while ((n & (1 << (SHORT_BITS - 1))) == 0) { + n <<= 1; + --result; + } + } + + return result; +} + +static u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail, + u32 *in_index) +{ + u32 result = 0; + u32 shift = 0; + u32 databyte = 0; + + while (bits > 0) { + databyte = buffer[*in_index]; + result |= (((databyte >> (CHAR_BITS - *bits_avail)) + & (0xff >> (CHAR_BITS - *bits_avail))) << shift); + + if (bits <= *bits_avail) { + result &= (0xffff >> (SHORT_BITS - (bits + shift))); + *bits_avail -= bits; + bits = 0; + } else { + ++(*in_index); + shift += *bits_avail; + bits -= *bits_avail; + *bits_avail = CHAR_BITS; + } + } + + return result; +} + +u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version) +{ + u32 i, j, data_length = 0L; + u32 offset, length; + u32 match_data_length = MATCH_DATA_LENGTH; + u32 bits_avail = CHAR_BITS; + u32 in_index = 0L; + + if (version > 0) + --match_data_length; + + for (i = 0; i < out_length; ++i) + out[i] = 0; + + /* Read number of bytes in data. */ + for (i = 0; i < sizeof(in_length); ++i) { + data_length = data_length | ( + altera_read_packed(in, + CHAR_BITS, + &bits_avail, + &in_index) << (i * CHAR_BITS)); + } + + if (data_length > out_length) { + data_length = 0L; + return data_length; + } + + i = 0; + while (i < data_length) { + /* A 0 bit indicates literal data. */ + if (altera_read_packed(in, 1, &bits_avail, + &in_index) == 0) { + for (j = 0; j < DATA_BLOB_LENGTH; ++j) { + if (i < data_length) { + out[i] = (u8)altera_read_packed(in, + CHAR_BITS, + &bits_avail, + &in_index); + i++; + } + } + } else { + /* A 1 bit indicates offset/length to follow. */ + offset = altera_read_packed(in, altera_bits_req((s16) + (i > match_data_length ? + match_data_length : i)), + &bits_avail, + &in_index); + length = altera_read_packed(in, CHAR_BITS, + &bits_avail, + &in_index); + for (j = 0; j < length; ++j) { + if (i < data_length) { + out[i] = out[i - offset]; + i++; + } + } + } + } + + return data_length; +} diff --git a/drivers/staging/altera-stapl/altera-exprt.h b/drivers/staging/altera-stapl/altera-exprt.h new file mode 100644 index 000000000000..39c38d84a670 --- /dev/null +++ b/drivers/staging/altera-stapl/altera-exprt.h @@ -0,0 +1,33 @@ +/* + * altera-exprt.h + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef ALTERA_EXPRT_H +#define ALTERA_EXPRT_H + + +u32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version); +int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo); + +#endif /* ALTERA_EXPRT_H */ diff --git a/drivers/staging/altera-stapl/altera-jtag.c b/drivers/staging/altera-stapl/altera-jtag.c new file mode 100644 index 000000000000..6b633b179a7e --- /dev/null +++ b/drivers/staging/altera-stapl/altera-jtag.c @@ -0,0 +1,1020 @@ +/* + * altera-jtag.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include "altera-exprt.h" +#include "altera-jtag.h" + +#define alt_jtag_io(a, b, c)\ + astate->config->jtag_io(astate->config->dev, a, b, c); + +#define alt_malloc(a) kzalloc(a, GFP_KERNEL); + +/* + * This structure shows, for each JTAG state, which state is reached after + * a single TCK clock cycle with TMS high or TMS low, respectively. This + * describes all possible state transitions in the JTAG state machine. + */ +struct altera_jtag_machine { + enum altera_jtag_state tms_high; + enum altera_jtag_state tms_low; +}; + +static const struct altera_jtag_machine altera_transitions[] = { + /* RESET */ { RESET, IDLE }, + /* IDLE */ { DRSELECT, IDLE }, + /* DRSELECT */ { IRSELECT, DRCAPTURE }, + /* DRCAPTURE */ { DREXIT1, DRSHIFT }, + /* DRSHIFT */ { DREXIT1, DRSHIFT }, + /* DREXIT1 */ { DRUPDATE, DRPAUSE }, + /* DRPAUSE */ { DREXIT2, DRPAUSE }, + /* DREXIT2 */ { DRUPDATE, DRSHIFT }, + /* DRUPDATE */ { DRSELECT, IDLE }, + /* IRSELECT */ { RESET, IRCAPTURE }, + /* IRCAPTURE */ { IREXIT1, IRSHIFT }, + /* IRSHIFT */ { IREXIT1, IRSHIFT }, + /* IREXIT1 */ { IRUPDATE, IRPAUSE }, + /* IRPAUSE */ { IREXIT2, IRPAUSE }, + /* IREXIT2 */ { IRUPDATE, IRSHIFT }, + /* IRUPDATE */ { DRSELECT, IDLE } +}; + +/* + * This table contains the TMS value to be used to take the NEXT STEP on + * the path to the desired state. The array index is the current state, + * and the bit position is the desired endstate. To find out which state + * is used as the intermediate state, look up the TMS value in the + * altera_transitions[] table. + */ +static const u16 altera_jtag_path_map[16] = { + /* RST RTI SDRS CDR SDR E1DR PDR E2DR */ + 0x0001, 0xFFFD, 0xFE01, 0xFFE7, 0xFFEF, 0xFF0F, 0xFFBF, 0xFFFF, + /* UDR SIRS CIR SIR E1IR PIR E2IR UIR */ + 0xFEFD, 0x0001, 0xF3FF, 0xF7FF, 0x87FF, 0xDFFF, 0xFFFF, 0x7FFD +}; + +/* Flag bits for alt_jtag_io() function */ +#define TMS_HIGH 1 +#define TMS_LOW 0 +#define TDI_HIGH 1 +#define TDI_LOW 0 +#define READ_TDO 1 +#define IGNORE_TDO 0 + +int altera_jinit(struct altera_state *astate) +{ + struct altera_jtag *js = &astate->js; + + /* initial JTAG state is unknown */ + js->jtag_state = ILLEGAL_JTAG_STATE; + + /* initialize to default state */ + js->drstop_state = IDLE; + js->irstop_state = IDLE; + js->dr_pre = 0; + js->dr_post = 0; + js->ir_pre = 0; + js->ir_post = 0; + js->dr_length = 0; + js->ir_length = 0; + + js->dr_pre_data = NULL; + js->dr_post_data = NULL; + js->ir_pre_data = NULL; + js->ir_post_data = NULL; + js->dr_buffer = NULL; + js->ir_buffer = NULL; + + return 0; +} + +int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state) +{ + js->drstop_state = state; + + return 0; +} + +int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state) +{ + js->irstop_state = state; + + return 0; +} + +int altera_set_dr_pre(struct altera_jtag *js, + u32 count, u32 start_index, + u8 *preamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->dr_pre) { + kfree(js->dr_pre_data); + js->dr_pre_data = (u8 *)alt_malloc((count + 7) >> 3); + if (js->dr_pre_data == NULL) + status = -ENOMEM; + else + js->dr_pre = count; + } else + js->dr_pre = count; + + if (status == 0) { + for (i = 0; i < count; ++i) { + j = i + start_index; + + if (preamble_data == NULL) + js->dr_pre_data[i >> 3] |= (1 << (i & 7)); + else { + if (preamble_data[j >> 3] & (1 << (j & 7))) + js->dr_pre_data[i >> 3] |= + (1 << (i & 7)); + else + js->dr_pre_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + } + + return status; +} + +int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, + u8 *preamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->ir_pre) { + kfree(js->ir_pre_data); + js->ir_pre_data = (u8 *)alt_malloc((count + 7) >> 3); + if (js->ir_pre_data == NULL) + status = -ENOMEM; + else + js->ir_pre = count; + + } else + js->ir_pre = count; + + if (status == 0) { + for (i = 0; i < count; ++i) { + j = i + start_index; + if (preamble_data == NULL) + js->ir_pre_data[i >> 3] |= (1 << (i & 7)); + else { + if (preamble_data[j >> 3] & (1 << (j & 7))) + js->ir_pre_data[i >> 3] |= + (1 << (i & 7)); + else + js->ir_pre_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + } + + return status; +} + +int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->dr_post) { + kfree(js->dr_post_data); + js->dr_post_data = (u8 *)alt_malloc((count + 7) >> 3); + + if (js->dr_post_data == NULL) + status = -ENOMEM; + else + js->dr_post = count; + + } else + js->dr_post = count; + + if (status == 0) { + for (i = 0; i < count; ++i) { + j = i + start_index; + + if (postamble_data == NULL) + js->dr_post_data[i >> 3] |= (1 << (i & 7)); + else { + if (postamble_data[j >> 3] & (1 << (j & 7))) + js->dr_post_data[i >> 3] |= + (1 << (i & 7)); + else + js->dr_post_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + } + + return status; +} + +int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data) +{ + int status = 0; + u32 i; + u32 j; + + if (count > js->ir_post) { + kfree(js->ir_post_data); + js->ir_post_data = (u8 *)alt_malloc((count + 7) >> 3); + if (js->ir_post_data == NULL) + status = -ENOMEM; + else + js->ir_post = count; + + } else + js->ir_post = count; + + if (status != 0) + return status; + + for (i = 0; i < count; ++i) { + j = i + start_index; + + if (postamble_data == NULL) + js->ir_post_data[i >> 3] |= (1 << (i & 7)); + else { + if (postamble_data[j >> 3] & (1 << (j & 7))) + js->ir_post_data[i >> 3] |= (1 << (i & 7)); + else + js->ir_post_data[i >> 3] &= + ~(u32)(1 << (i & 7)); + + } + } + + return status; +} + +static void altera_jreset_idle(struct altera_state *astate) +{ + struct altera_jtag *js = &astate->js; + int i; + /* Go to Test Logic Reset (no matter what the starting state may be) */ + for (i = 0; i < 5; ++i) + alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); + + /* Now step to Run Test / Idle */ + alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); + js->jtag_state = IDLE; +} + +int altera_goto_jstate(struct altera_state *astate, + enum altera_jtag_state state) +{ + struct altera_jtag *js = &astate->js; + int tms; + int count = 0; + int status = 0; + + if (js->jtag_state == ILLEGAL_JTAG_STATE) + /* initialize JTAG chain to known state */ + altera_jreset_idle(astate); + + if (js->jtag_state == state) { + /* + * We are already in the desired state. + * If it is a stable state, loop here. + * Otherwise do nothing (no clock cycles). + */ + if ((state == IDLE) || (state == DRSHIFT) || + (state == DRPAUSE) || (state == IRSHIFT) || + (state == IRPAUSE)) { + alt_jtag_io(TMS_LOW, TDI_LOW, IGNORE_TDO); + } else if (state == RESET) + alt_jtag_io(TMS_HIGH, TDI_LOW, IGNORE_TDO); + + } else { + while ((js->jtag_state != state) && (count < 9)) { + /* Get TMS value to take a step toward desired state */ + tms = (altera_jtag_path_map[js->jtag_state] & + (1 << state)) + ? TMS_HIGH : TMS_LOW; + + /* Take a step */ + alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); + + if (tms) + js->jtag_state = + altera_transitions[js->jtag_state].tms_high; + else + js->jtag_state = + altera_transitions[js->jtag_state].tms_low; + + ++count; + } + } + + if (js->jtag_state != state) + status = -EREMOTEIO; + + return status; +} + +int altera_wait_cycles(struct altera_state *astate, + s32 cycles, + enum altera_jtag_state wait_state) +{ + struct altera_jtag *js = &astate->js; + int tms; + s32 count; + int status = 0; + + if (js->jtag_state != wait_state) + status = altera_goto_jstate(astate, wait_state); + + if (status == 0) { + /* + * Set TMS high to loop in RESET state + * Set TMS low to loop in any other stable state + */ + tms = (wait_state == RESET) ? TMS_HIGH : TMS_LOW; + + for (count = 0L; count < cycles; count++) + alt_jtag_io(tms, TDI_LOW, IGNORE_TDO); + + } + + return status; +} + +int altera_wait_msecs(struct altera_state *astate, + s32 microseconds, enum altera_jtag_state wait_state) +/* + * Causes JTAG hardware to sit in the specified stable + * state for the specified duration of real time. If + * no JTAG operations have been performed yet, then only + * a delay is performed. This permits the WAIT USECS + * statement to be used in VECTOR programs without causing + * any JTAG operations. + * Returns 0 for success, else appropriate error code. + */ +{ + struct altera_jtag *js = &astate->js; + int status = 0; + + if ((js->jtag_state != ILLEGAL_JTAG_STATE) && + (js->jtag_state != wait_state)) + status = altera_goto_jstate(astate, wait_state); + + if (status == 0) + /* Wait for specified time interval */ + udelay(microseconds); + + return status; +} + +static void altera_concatenate_data(u8 *buffer, + u8 *preamble_data, + u32 preamble_count, + u8 *target_data, + u32 start_index, + u32 target_count, + u8 *postamble_data, + u32 postamble_count) +/* + * Copies preamble data, target data, and postamble data + * into one buffer for IR or DR scans. + */ +{ + u32 i, j, k; + + for (i = 0L; i < preamble_count; ++i) { + if (preamble_data[i >> 3L] & (1L << (i & 7L))) + buffer[i >> 3L] |= (1L << (i & 7L)); + else + buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); + + } + + j = start_index; + k = preamble_count + target_count; + for (; i < k; ++i, ++j) { + if (target_data[j >> 3L] & (1L << (j & 7L))) + buffer[i >> 3L] |= (1L << (i & 7L)); + else + buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); + + } + + j = 0L; + k = preamble_count + target_count + postamble_count; + for (; i < k; ++i, ++j) { + if (postamble_data[j >> 3L] & (1L << (j & 7L))) + buffer[i >> 3L] |= (1L << (i & 7L)); + else + buffer[i >> 3L] &= ~(u32)(1L << (i & 7L)); + + } +} + +static int alt_jtag_drscan(struct altera_state *astate, + int start_state, + int count, + u8 *tdi, + u8 *tdo) +{ + int i = 0; + int tdo_bit = 0; + int status = 1; + + /* First go to DRSHIFT state */ + switch (start_state) { + case 0: /* IDLE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(0, 0, 0); /* DRCAPTURE */ + alt_jtag_io(0, 0, 0); /* DRSHIFT */ + break; + + case 1: /* DRPAUSE */ + alt_jtag_io(1, 0, 0); /* DREXIT2 */ + alt_jtag_io(1, 0, 0); /* DRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(0, 0, 0); /* DRCAPTURE */ + alt_jtag_io(0, 0, 0); /* DRSHIFT */ + break; + + case 2: /* IRPAUSE */ + alt_jtag_io(1, 0, 0); /* IREXIT2 */ + alt_jtag_io(1, 0, 0); /* IRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(0, 0, 0); /* DRCAPTURE */ + alt_jtag_io(0, 0, 0); /* DRSHIFT */ + break; + + default: + status = 0; + } + + if (status) { + /* loop in the SHIFT-DR state */ + for (i = 0; i < count; i++) { + tdo_bit = alt_jtag_io( + (i == count - 1), + tdi[i >> 3] & (1 << (i & 7)), + (tdo != NULL)); + + if (tdo != NULL) { + if (tdo_bit) + tdo[i >> 3] |= (1 << (i & 7)); + else + tdo[i >> 3] &= ~(u32)(1 << (i & 7)); + + } + } + + alt_jtag_io(0, 0, 0); /* DRPAUSE */ + } + + return status; +} + +static int alt_jtag_irscan(struct altera_state *astate, + int start_state, + int count, + u8 *tdi, + u8 *tdo) +{ + int i = 0; + int tdo_bit = 0; + int status = 1; + + /* First go to IRSHIFT state */ + switch (start_state) { + case 0: /* IDLE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(1, 0, 0); /* IRSELECT */ + alt_jtag_io(0, 0, 0); /* IRCAPTURE */ + alt_jtag_io(0, 0, 0); /* IRSHIFT */ + break; + + case 1: /* DRPAUSE */ + alt_jtag_io(1, 0, 0); /* DREXIT2 */ + alt_jtag_io(1, 0, 0); /* DRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(1, 0, 0); /* IRSELECT */ + alt_jtag_io(0, 0, 0); /* IRCAPTURE */ + alt_jtag_io(0, 0, 0); /* IRSHIFT */ + break; + + case 2: /* IRPAUSE */ + alt_jtag_io(1, 0, 0); /* IREXIT2 */ + alt_jtag_io(1, 0, 0); /* IRUPDATE */ + alt_jtag_io(1, 0, 0); /* DRSELECT */ + alt_jtag_io(1, 0, 0); /* IRSELECT */ + alt_jtag_io(0, 0, 0); /* IRCAPTURE */ + alt_jtag_io(0, 0, 0); /* IRSHIFT */ + break; + + default: + status = 0; + } + + if (status) { + /* loop in the SHIFT-IR state */ + for (i = 0; i < count; i++) { + tdo_bit = alt_jtag_io( + (i == count - 1), + tdi[i >> 3] & (1 << (i & 7)), + (tdo != NULL)); + if (tdo != NULL) { + if (tdo_bit) + tdo[i >> 3] |= (1 << (i & 7)); + else + tdo[i >> 3] &= ~(u32)(1 << (i & 7)); + + } + } + + alt_jtag_io(0, 0, 0); /* IRPAUSE */ + } + + return status; +} + +static void altera_extract_target_data(u8 *buffer, + u8 *target_data, + u32 start_index, + u32 preamble_count, + u32 target_count) +/* + * Copies target data from scan buffer, filtering out + * preamble and postamble data. + */ +{ + u32 i; + u32 j; + u32 k; + + j = preamble_count; + k = start_index + target_count; + for (i = start_index; i < k; ++i, ++j) { + if (buffer[j >> 3] & (1 << (j & 7))) + target_data[i >> 3] |= (1 << (i & 7)); + else + target_data[i >> 3] &= ~(u32)(1 << (i & 7)); + + } +} + +int altera_irscan(struct altera_state *astate, + u32 count, + u8 *tdi_data, + u32 start_index) +/* Shifts data into instruction register */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->ir_pre + count + js->ir_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->ir_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->ir_buffer); + js->ir_buffer = (u8 *)alt_malloc(alloc_chars); + if (js->ir_buffer == NULL) + status = -ENOMEM; + else + js->ir_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, IR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->ir_buffer, + js->ir_pre_data, + js->ir_pre, + tdi_data, + start_index, + count, + js->ir_post_data, + js->ir_post); + /* Do the IRSCAN */ + alt_jtag_irscan(astate, + start_code, + shift_count, + js->ir_buffer, + NULL); + + /* alt_jtag_irscan() always ends in IRPAUSE state */ + js->jtag_state = IRPAUSE; + } + + if (status == 0) + if (js->irstop_state != IRPAUSE) + status = altera_goto_jstate(astate, js->irstop_state); + + + return status; +} + +int altera_swap_ir(struct altera_state *astate, + u32 count, + u8 *in_data, + u32 in_index, + u8 *out_data, + u32 out_index) +/* Shifts data into instruction register, capturing output data */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->ir_pre + count + js->ir_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->ir_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->ir_buffer); + js->ir_buffer = (u8 *)alt_malloc(alloc_chars); + if (js->ir_buffer == NULL) + status = -ENOMEM; + else + js->ir_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, IR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->ir_buffer, + js->ir_pre_data, + js->ir_pre, + in_data, + in_index, + count, + js->ir_post_data, + js->ir_post); + + /* Do the IRSCAN */ + alt_jtag_irscan(astate, + start_code, + shift_count, + js->ir_buffer, + js->ir_buffer); + + /* alt_jtag_irscan() always ends in IRPAUSE state */ + js->jtag_state = IRPAUSE; + } + + if (status == 0) + if (js->irstop_state != IRPAUSE) + status = altera_goto_jstate(astate, js->irstop_state); + + + if (status == 0) + /* Now extract the returned data from the buffer */ + altera_extract_target_data(js->ir_buffer, + out_data, out_index, + js->ir_pre, count); + + return status; +} + +int altera_drscan(struct altera_state *astate, + u32 count, + u8 *tdi_data, + u32 start_index) +/* Shifts data into data register (ignoring output data) */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->dr_pre + count + js->dr_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->dr_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->dr_buffer); + js->dr_buffer = (u8 *)alt_malloc(alloc_chars); + if (js->dr_buffer == NULL) + status = -ENOMEM; + else + js->dr_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, DR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->dr_buffer, + js->dr_pre_data, + js->dr_pre, + tdi_data, + start_index, + count, + js->dr_post_data, + js->dr_post); + /* Do the DRSCAN */ + alt_jtag_drscan(astate, start_code, shift_count, + js->dr_buffer, NULL); + /* alt_jtag_drscan() always ends in DRPAUSE state */ + js->jtag_state = DRPAUSE; + } + + if (status == 0) + if (js->drstop_state != DRPAUSE) + status = altera_goto_jstate(astate, js->drstop_state); + + return status; +} + +int altera_swap_dr(struct altera_state *astate, u32 count, + u8 *in_data, u32 in_index, + u8 *out_data, u32 out_index) +/* Shifts data into data register, capturing output data */ +{ + struct altera_jtag *js = &astate->js; + int start_code = 0; + u32 alloc_chars = 0; + u32 shift_count = js->dr_pre + count + js->dr_post; + int status = 0; + enum altera_jtag_state start_state = ILLEGAL_JTAG_STATE; + + switch (js->jtag_state) { + case ILLEGAL_JTAG_STATE: + case RESET: + case IDLE: + start_code = 0; + start_state = IDLE; + break; + + case DRSELECT: + case DRCAPTURE: + case DRSHIFT: + case DREXIT1: + case DRPAUSE: + case DREXIT2: + case DRUPDATE: + start_code = 1; + start_state = DRPAUSE; + break; + + case IRSELECT: + case IRCAPTURE: + case IRSHIFT: + case IREXIT1: + case IRPAUSE: + case IREXIT2: + case IRUPDATE: + start_code = 2; + start_state = IRPAUSE; + break; + + default: + status = -EREMOTEIO; + break; + } + + if (status == 0) + if (js->jtag_state != start_state) + status = altera_goto_jstate(astate, start_state); + + if (status == 0) { + if (shift_count > js->dr_length) { + alloc_chars = (shift_count + 7) >> 3; + kfree(js->dr_buffer); + js->dr_buffer = (u8 *)alt_malloc(alloc_chars); + + if (js->dr_buffer == NULL) + status = -ENOMEM; + else + js->dr_length = alloc_chars * 8; + + } + } + + if (status == 0) { + /* + * Copy preamble data, DR data, + * and postamble data into a buffer + */ + altera_concatenate_data(js->dr_buffer, + js->dr_pre_data, + js->dr_pre, + in_data, + in_index, + count, + js->dr_post_data, + js->dr_post); + + /* Do the DRSCAN */ + alt_jtag_drscan(astate, + start_code, + shift_count, + js->dr_buffer, + js->dr_buffer); + + /* alt_jtag_drscan() always ends in DRPAUSE state */ + js->jtag_state = DRPAUSE; + } + + if (status == 0) + if (js->drstop_state != DRPAUSE) + status = altera_goto_jstate(astate, js->drstop_state); + + if (status == 0) + /* Now extract the returned data from the buffer */ + altera_extract_target_data(js->dr_buffer, + out_data, + out_index, + js->dr_pre, + count); + + return status; +} + +void altera_free_buffers(struct altera_state *astate) +{ + struct altera_jtag *js = &astate->js; + /* If the JTAG interface was used, reset it to TLR */ + if (js->jtag_state != ILLEGAL_JTAG_STATE) + altera_jreset_idle(astate); + + kfree(js->dr_pre_data); + js->dr_pre_data = NULL; + + kfree(js->dr_post_data); + js->dr_post_data = NULL; + + kfree(js->dr_buffer); + js->dr_buffer = NULL; + + kfree(js->ir_pre_data); + js->ir_pre_data = NULL; + + kfree(js->ir_post_data); + js->ir_post_data = NULL; + + kfree(js->ir_buffer); + js->ir_buffer = NULL; +} diff --git a/drivers/staging/altera-stapl/altera-jtag.h b/drivers/staging/altera-stapl/altera-jtag.h new file mode 100644 index 000000000000..2f97e36a2fbc --- /dev/null +++ b/drivers/staging/altera-stapl/altera-jtag.h @@ -0,0 +1,113 @@ +/* + * altera-jtag.h + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef ALTERA_JTAG_H +#define ALTERA_JTAG_H + +/* Function Prototypes */ +enum altera_jtag_state { + ILLEGAL_JTAG_STATE = -1, + RESET = 0, + IDLE = 1, + DRSELECT = 2, + DRCAPTURE = 3, + DRSHIFT = 4, + DREXIT1 = 5, + DRPAUSE = 6, + DREXIT2 = 7, + DRUPDATE = 8, + IRSELECT = 9, + IRCAPTURE = 10, + IRSHIFT = 11, + IREXIT1 = 12, + IRPAUSE = 13, + IREXIT2 = 14, + IRUPDATE = 15 + +}; + +struct altera_jtag { + /* Global variable to store the current JTAG state */ + enum altera_jtag_state jtag_state; + + /* Store current stop-state for DR and IR scan commands */ + enum altera_jtag_state drstop_state; + enum altera_jtag_state irstop_state; + + /* Store current padding values */ + u32 dr_pre; + u32 dr_post; + u32 ir_pre; + u32 ir_post; + u32 dr_length; + u32 ir_length; + u8 *dr_pre_data; + u8 *dr_post_data; + u8 *ir_pre_data; + u8 *ir_post_data; + u8 *dr_buffer; + u8 *ir_buffer; +}; + +#define ALTERA_STACK_SIZE 128 +#define ALTERA_MESSAGE_LENGTH 1024 + +struct altera_state { + struct altera_config *config; + struct altera_jtag js; + char msg_buff[ALTERA_MESSAGE_LENGTH + 1]; + long stack[ALTERA_STACK_SIZE]; +}; + +int altera_jinit(struct altera_state *astate); +int altera_set_drstop(struct altera_jtag *js, enum altera_jtag_state state); +int altera_set_irstop(struct altera_jtag *js, enum altera_jtag_state state); +int altera_set_dr_pre(struct altera_jtag *js, u32 count, u32 start_index, + u8 *preamble_data); +int altera_set_ir_pre(struct altera_jtag *js, u32 count, u32 start_index, + u8 *preamble_data); +int altera_set_dr_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data); +int altera_set_ir_post(struct altera_jtag *js, u32 count, u32 start_index, + u8 *postamble_data); +int altera_goto_jstate(struct altera_state *astate, + enum altera_jtag_state state); +int altera_wait_cycles(struct altera_state *astate, s32 cycles, + enum altera_jtag_state wait_state); +int altera_wait_msecs(struct altera_state *astate, s32 microseconds, + enum altera_jtag_state wait_state); +int altera_irscan(struct altera_state *astate, u32 count, + u8 *tdi_data, u32 start_index); +int altera_swap_ir(struct altera_state *astate, + u32 count, u8 *in_data, + u32 in_index, u8 *out_data, + u32 out_index); +int altera_drscan(struct altera_state *astate, u32 count, + u8 *tdi_data, u32 start_index); +int altera_swap_dr(struct altera_state *astate, u32 count, + u8 *in_data, u32 in_index, + u8 *out_data, u32 out_index); +void altera_free_buffers(struct altera_state *astate); +#endif /* ALTERA_JTAG_H */ diff --git a/drivers/staging/altera-stapl/altera-lpt.c b/drivers/staging/altera-stapl/altera-lpt.c new file mode 100644 index 000000000000..91456a03612d --- /dev/null +++ b/drivers/staging/altera-stapl/altera-lpt.c @@ -0,0 +1,70 @@ +/* + * altera-lpt.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Abylay Ospan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include "altera-exprt.h" + +static int lpt_hardware_initialized; + +static void byteblaster_write(int port, int data) +{ + outb((u8)data, (u16)(port + 0x378)); +}; + +static int byteblaster_read(int port) +{ + int data = 0; + data = inb((u16)(port + 0x378)); + return data & 0xff; +}; + +int netup_jtag_io_lpt(void *device, int tms, int tdi, int read_tdo) +{ + int data = 0; + int tdo = 0; + int initial_lpt_ctrl = 0; + + if (!lpt_hardware_initialized) { + initial_lpt_ctrl = byteblaster_read(2); + byteblaster_write(2, (initial_lpt_ctrl | 0x02) & 0xdf); + lpt_hardware_initialized = 1; + } + + data = ((tdi ? 0x40 : 0) | (tms ? 0x02 : 0)); + + byteblaster_write(0, data); + + if (read_tdo) { + tdo = byteblaster_read(1); + tdo = ((tdo & 0x80) ? 0 : 1); + } + + byteblaster_write(0, data | 0x01); + + byteblaster_write(0, data); + + return tdo; +} diff --git a/drivers/staging/altera-stapl/altera.c b/drivers/staging/altera-stapl/altera.c new file mode 100644 index 000000000000..05aad351b120 --- /dev/null +++ b/drivers/staging/altera-stapl/altera.c @@ -0,0 +1,2527 @@ +/* + * altera.c + * + * altera FPGA driver + * + * Copyright (C) Altera Corporation 1998-2001 + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include "altera-exprt.h" +#include "altera-jtag.h" + +static int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debugging information"); + +MODULE_DESCRIPTION("altera FPGA kernel module"); +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_LICENSE("GPL"); + +#define dprintk(args...) \ + if (debug) { \ + printk(KERN_DEBUG args); \ + } + +enum altera_fpga_opcode { + OP_NOP = 0, + OP_DUP, + OP_SWP, + OP_ADD, + OP_SUB, + OP_MULT, + OP_DIV, + OP_MOD, + OP_SHL, + OP_SHR, + OP_NOT, + OP_AND, + OP_OR, + OP_XOR, + OP_INV, + OP_GT, + OP_LT, + OP_RET, + OP_CMPS, + OP_PINT, + OP_PRNT, + OP_DSS, + OP_DSSC, + OP_ISS, + OP_ISSC, + OP_DPR = 0x1c, + OP_DPRL, + OP_DPO, + OP_DPOL, + OP_IPR, + OP_IPRL, + OP_IPO, + OP_IPOL, + OP_PCHR, + OP_EXIT, + OP_EQU, + OP_POPT, + OP_ABS = 0x2c, + OP_BCH0, + OP_PSH0 = 0x2f, + OP_PSHL = 0x40, + OP_PSHV, + OP_JMP, + OP_CALL, + OP_NEXT, + OP_PSTR, + OP_SINT = 0x47, + OP_ST, + OP_ISTP, + OP_DSTP, + OP_SWPN, + OP_DUPN, + OP_POPV, + OP_POPE, + OP_POPA, + OP_JMPZ, + OP_DS, + OP_IS, + OP_DPRA, + OP_DPOA, + OP_IPRA, + OP_IPOA, + OP_EXPT, + OP_PSHE, + OP_PSHA, + OP_DYNA, + OP_EXPV = 0x5c, + OP_COPY = 0x80, + OP_REVA, + OP_DSC, + OP_ISC, + OP_WAIT, + OP_VS, + OP_CMPA = 0xc0, + OP_VSC, +}; + +struct altera_procinfo { + char *name; + u8 attrs; + struct altera_procinfo *next; +}; + +/* This function checks if enough parameters are available on the stack. */ +static int altera_check_stack(int stack_ptr, int count, int *status) +{ + if (stack_ptr < count) { + *status = -EOVERFLOW; + return 0; + } + + return 1; +} + +static void altera_export_int(char *key, s32 value) +{ + dprintk("Export: key = \"%s\", value = %d\n", key, value); +} + +#define HEX_LINE_CHARS 72 +#define HEX_LINE_BITS (HEX_LINE_CHARS * 4) + +static void altera_export_bool_array(char *key, u8 *data, s32 count) +{ + char string[HEX_LINE_CHARS + 1]; + s32 i, offset; + u32 size, line, lines, linebits, value, j, k; + + if (count > HEX_LINE_BITS) { + dprintk("Export: key = \"%s\", %d bits, value = HEX\n", + key, count); + lines = (count + (HEX_LINE_BITS - 1)) / HEX_LINE_BITS; + + for (line = 0; line < lines; ++line) { + if (line < (lines - 1)) { + linebits = HEX_LINE_BITS; + size = HEX_LINE_CHARS; + offset = count - ((line + 1) * HEX_LINE_BITS); + } else { + linebits = + count - ((lines - 1) * HEX_LINE_BITS); + size = (linebits + 3) / 4; + offset = 0L; + } + + string[size] = '\0'; + j = size - 1; + value = 0; + + for (k = 0; k < linebits; ++k) { + i = k + offset; + if (data[i >> 3] & (1 << (i & 7))) + value |= (1 << (i & 3)); + if ((i & 3) == 3) { + sprintf(&string[j], "%1x", value); + value = 0; + --j; + } + } + if ((k & 3) > 0) + sprintf(&string[j], "%1x", value); + + dprintk("%s\n", string); + } + + } else { + size = (count + 3) / 4; + string[size] = '\0'; + j = size - 1; + value = 0; + + for (i = 0; i < count; ++i) { + if (data[i >> 3] & (1 << (i & 7))) + value |= (1 << (i & 3)); + if ((i & 3) == 3) { + sprintf(&string[j], "%1x", value); + value = 0; + --j; + } + } + if ((i & 3) > 0) + sprintf(&string[j], "%1x", value); + + dprintk("Export: key = \"%s\", %d bits, value = HEX %s\n", + key, count, string); + } +} + +static int altera_execute(struct altera_state *astate, + u8 *p, + s32 program_size, + s32 *error_address, + int *exit_code, + int *format_version) +{ + struct altera_config *aconf = astate->config; + char *msg_buff = astate->msg_buff; + long *stack = astate->stack; + int status = 0; + u32 first_word = 0L; + u32 action_table = 0L; + u32 proc_table = 0L; + u32 str_table = 0L; + u32 sym_table = 0L; + u32 data_sect = 0L; + u32 code_sect = 0L; + u32 debug_sect = 0L; + u32 action_count = 0L; + u32 proc_count = 0L; + u32 sym_count = 0L; + long *vars = NULL; + s32 *var_size = NULL; + char *attrs = NULL; + u8 *proc_attributes = NULL; + u32 pc; + u32 opcode_address; + u32 args[3]; + u32 opcode; + u32 name_id; + u8 charbuf[4]; + long long_tmp; + u32 variable_id; + u8 *charptr_tmp; + u8 *charptr_tmp2; + long *longptr_tmp; + int version = 0; + int delta = 0; + int stack_ptr = 0; + u32 arg_count; + int done = 0; + int bad_opcode = 0; + u32 count; + u32 index; + u32 index2; + s32 long_count; + s32 long_idx; + s32 long_idx2; + u32 i; + u32 j; + u32 uncomp_size; + u32 offset; + u32 value; + int current_proc = 0; + int reverse; + + char *name; + + dprintk("%s\n", __func__); + + /* Read header information */ + if (program_size > 52L) { + first_word = get_unaligned_be32(&p[0]); + version = (first_word & 1L); + *format_version = version + 1; + delta = version * 8; + + action_table = get_unaligned_be32(&p[4]); + proc_table = get_unaligned_be32(&p[8]); + str_table = get_unaligned_be32(&p[4 + delta]); + sym_table = get_unaligned_be32(&p[16 + delta]); + data_sect = get_unaligned_be32(&p[20 + delta]); + code_sect = get_unaligned_be32(&p[24 + delta]); + debug_sect = get_unaligned_be32(&p[28 + delta]); + action_count = get_unaligned_be32(&p[40 + delta]); + proc_count = get_unaligned_be32(&p[44 + delta]); + sym_count = get_unaligned_be32(&p[48 + (2 * delta)]); + } + + if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) { + done = 1; + status = -EIO; + goto exit_done; + } + + if (sym_count <= 0) + goto exit_done; + + vars = kzalloc(sym_count * sizeof(long), GFP_KERNEL); + + if (vars == NULL) + status = -ENOMEM; + + if (status == 0) { + var_size = kzalloc(sym_count * sizeof(s32), GFP_KERNEL); + + if (var_size == NULL) + status = -ENOMEM; + } + + if (status == 0) { + attrs = kzalloc(sym_count, GFP_KERNEL); + + if (attrs == NULL) + status = -ENOMEM; + } + + if ((status == 0) && (version > 0)) { + proc_attributes = kzalloc(proc_count, GFP_KERNEL); + + if (proc_attributes == NULL) + status = -ENOMEM; + } + + if (status != 0) + goto exit_done; + + delta = version * 2; + + for (i = 0; i < sym_count; ++i) { + offset = (sym_table + ((11 + delta) * i)); + + value = get_unaligned_be32(&p[offset + 3 + delta]); + + attrs[i] = p[offset]; + + /* + * use bit 7 of attribute byte to indicate that + * this buffer was dynamically allocated + * and should be freed later + */ + attrs[i] &= 0x7f; + + var_size[i] = get_unaligned_be32(&p[offset + 7 + delta]); + + /* + * Attribute bits: + * bit 0: 0 = read-only, 1 = read-write + * bit 1: 0 = not compressed, 1 = compressed + * bit 2: 0 = not initialized, 1 = initialized + * bit 3: 0 = scalar, 1 = array + * bit 4: 0 = Boolean, 1 = integer + * bit 5: 0 = declared variable, + * 1 = compiler created temporary variable + */ + + if ((attrs[i] & 0x0c) == 0x04) + /* initialized scalar variable */ + vars[i] = value; + else if ((attrs[i] & 0x1e) == 0x0e) { + /* initialized compressed Boolean array */ + uncomp_size = get_unaligned_le32(&p[data_sect + value]); + + /* allocate a buffer for the uncompressed data */ + vars[i] = (long)kzalloc(uncomp_size, GFP_KERNEL); + if (vars[i] == 0L) + status = -ENOMEM; + else { + /* set flag so buffer will be freed later */ + attrs[i] |= 0x80; + + /* uncompress the data */ + if (altera_shrink(&p[data_sect + value], + var_size[i], + (u8 *)vars[i], + uncomp_size, + version) != uncomp_size) + /* decompression failed */ + status = -EIO; + else + var_size[i] = uncomp_size * 8L; + + } + } else if ((attrs[i] & 0x1e) == 0x0c) { + /* initialized Boolean array */ + vars[i] = value + data_sect + (long)p; + } else if ((attrs[i] & 0x1c) == 0x1c) { + /* initialized integer array */ + vars[i] = value + data_sect; + } else if ((attrs[i] & 0x0c) == 0x08) { + /* uninitialized array */ + + /* flag attrs so that memory is freed */ + attrs[i] |= 0x80; + + if (var_size[i] > 0) { + u32 size; + + if (attrs[i] & 0x10) + /* integer array */ + size = (var_size[i] * sizeof(s32)); + else + /* Boolean array */ + size = ((var_size[i] + 7L) / 8L); + + vars[i] = (long)kzalloc(size, GFP_KERNEL); + + if (vars[i] == 0) { + status = -ENOMEM; + } else { + /* zero out memory */ + for (j = 0; j < size; ++j) + ((u8 *)(vars[i]))[j] = 0; + + } + } else + vars[i] = 0; + + } else + vars[i] = 0; + + } + +exit_done: + if (status != 0) + done = 1; + + altera_jinit(astate); + + pc = code_sect; + msg_buff[0] = '\0'; + + /* + * For JBC version 2, we will execute the procedures corresponding to + * the selected ACTION + */ + if (version > 0) { + if (aconf->action == NULL) { + status = -EINVAL; + done = 1; + } else { + int action_found = 0; + for (i = 0; (i < action_count) && !action_found; ++i) { + name_id = get_unaligned_be32(&p[action_table + + (12 * i)]); + + name = &p[str_table + name_id]; + + if (strnicmp(aconf->action, name, strlen(name)) == 0) { + action_found = 1; + current_proc = + get_unaligned_be32(&p[action_table + + (12 * i) + 8]); + } + } + + if (!action_found) { + status = -EINVAL; + done = 1; + } + } + + if (status == 0) { + int first_time = 1; + i = current_proc; + while ((i != 0) || first_time) { + first_time = 0; + /* check procedure attribute byte */ + proc_attributes[i] = + (p[proc_table + + (13 * i) + 8] & + 0x03); + + /* + * BIT0 - OPTIONAL + * BIT1 - RECOMMENDED + * BIT6 - FORCED OFF + * BIT7 - FORCED ON + */ + + i = get_unaligned_be32(&p[proc_table + + (13 * i) + 4]); + } + + /* + * Set current_proc to the first procedure + * to be executed + */ + i = current_proc; + while ((i != 0) && + ((proc_attributes[i] == 1) || + ((proc_attributes[i] & 0xc0) == 0x40))) { + i = get_unaligned_be32(&p[proc_table + + (13 * i) + 4]); + } + + if ((i != 0) || ((i == 0) && (current_proc == 0) && + ((proc_attributes[0] != 1) && + ((proc_attributes[0] & 0xc0) != 0x40)))) { + current_proc = i; + pc = code_sect + + get_unaligned_be32(&p[proc_table + + (13 * i) + 9]); + if ((pc < code_sect) || (pc >= debug_sect)) + status = -ERANGE; + } else + /* there are no procedures to execute! */ + done = 1; + + } + } + + msg_buff[0] = '\0'; + + while (!done) { + opcode = (p[pc] & 0xff); + opcode_address = pc; + ++pc; + + if (debug > 1) + printk("opcode: %02x\n", opcode); + + arg_count = (opcode >> 6) & 3; + for (i = 0; i < arg_count; ++i) { + args[i] = get_unaligned_be32(&p[pc]); + pc += 4; + } + + switch (opcode) { + case OP_NOP: + break; + case OP_DUP: + if (altera_check_stack(stack_ptr, 1, &status)) { + stack[stack_ptr] = stack[stack_ptr - 1]; + ++stack_ptr; + } + break; + case OP_SWP: + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + break; + case OP_ADD: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] += stack[stack_ptr]; + } + break; + case OP_SUB: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] -= stack[stack_ptr]; + } + break; + case OP_MULT: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] *= stack[stack_ptr]; + } + break; + case OP_DIV: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] /= stack[stack_ptr]; + } + break; + case OP_MOD: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] %= stack[stack_ptr]; + } + break; + case OP_SHL: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] <<= stack[stack_ptr]; + } + break; + case OP_SHR: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] >>= stack[stack_ptr]; + } + break; + case OP_NOT: + if (altera_check_stack(stack_ptr, 1, &status)) + stack[stack_ptr - 1] ^= (-1L); + + break; + case OP_AND: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] &= stack[stack_ptr]; + } + break; + case OP_OR: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] |= stack[stack_ptr]; + } + break; + case OP_XOR: + if (altera_check_stack(stack_ptr, 2, &status)) { + --stack_ptr; + stack[stack_ptr - 1] ^= stack[stack_ptr]; + } + break; + case OP_INV: + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + stack[stack_ptr - 1] = stack[stack_ptr - 1] ? 0L : 1L; + break; + case OP_GT: + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + --stack_ptr; + stack[stack_ptr - 1] = + (stack[stack_ptr - 1] > stack[stack_ptr]) ? + 1L : 0L; + + break; + case OP_LT: + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + --stack_ptr; + stack[stack_ptr - 1] = + (stack[stack_ptr - 1] < stack[stack_ptr]) ? + 1L : 0L; + + break; + case OP_RET: + if ((version > 0) && (stack_ptr == 0)) { + /* + * We completed one of the main procedures + * of an ACTION. + * Find the next procedure + * to be executed and jump to it. + * If there are no more procedures, then EXIT. + */ + i = get_unaligned_be32(&p[proc_table + + (13 * current_proc) + 4]); + while ((i != 0) && + ((proc_attributes[i] == 1) || + ((proc_attributes[i] & 0xc0) == 0x40))) + i = get_unaligned_be32(&p[proc_table + + (13 * i) + 4]); + + if (i == 0) { + /* no procedures to execute! */ + done = 1; + *exit_code = 0; /* success */ + } else { + current_proc = i; + pc = code_sect + get_unaligned_be32( + &p[proc_table + + (13 * i) + 9]); + if ((pc < code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + } + + } else + if (altera_check_stack(stack_ptr, 1, &status)) { + pc = stack[--stack_ptr] + code_sect; + if ((pc <= code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + + } + + break; + case OP_CMPS: + /* + * Array short compare + * ...stack 0 is source 1 value + * ...stack 1 is source 2 value + * ...stack 2 is mask value + * ...stack 3 is count + */ + if (altera_check_stack(stack_ptr, 4, &status)) { + s32 a = stack[--stack_ptr]; + s32 b = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + count = stack[stack_ptr - 1]; + + if ((count < 1) || (count > 32)) + status = -ERANGE; + else { + long_tmp &= ((-1L) >> (32 - count)); + + stack[stack_ptr - 1] = + ((a & long_tmp) == (b & long_tmp)) + ? 1L : 0L; + } + } + break; + case OP_PINT: + /* + * PRINT add integer + * ...stack 0 is integer value + */ + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + sprintf(&msg_buff[strlen(msg_buff)], + "%ld", stack[--stack_ptr]); + break; + case OP_PRNT: + /* PRINT finish */ + if (debug) + printk(msg_buff, "\n"); + + msg_buff[0] = '\0'; + break; + case OP_DSS: + /* + * DRSCAN short + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_drscan(astate, count, charbuf, 0); + break; + case OP_DSSC: + /* + * DRSCAN short with capture + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[stack_ptr - 1]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_swap_dr(astate, count, charbuf, + 0, charbuf, 0); + stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); + break; + case OP_ISS: + /* + * IRSCAN short + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_irscan(astate, count, charbuf, 0); + break; + case OP_ISSC: + /* + * IRSCAN short with capture + * ...stack 0 is scan data + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + count = stack[stack_ptr - 1]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_swap_ir(astate, count, charbuf, + 0, charbuf, 0); + stack[stack_ptr - 1] = get_unaligned_le32(&charbuf[0]); + break; + case OP_DPR: + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + count = stack[--stack_ptr]; + status = altera_set_dr_pre(&astate->js, count, 0, NULL); + break; + case OP_DPRL: + /* + * DRPRE with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_dr_pre(&astate->js, count, 0, + charbuf); + break; + case OP_DPO: + /* + * DRPOST + * ...stack 0 is count + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + count = stack[--stack_ptr]; + status = altera_set_dr_post(&astate->js, count, + 0, NULL); + } + break; + case OP_DPOL: + /* + * DRPOST with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_dr_post(&astate->js, count, 0, + charbuf); + break; + case OP_IPR: + if (altera_check_stack(stack_ptr, 1, &status)) { + count = stack[--stack_ptr]; + status = altera_set_ir_pre(&astate->js, count, + 0, NULL); + } + break; + case OP_IPRL: + /* + * IRPRE with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (altera_check_stack(stack_ptr, 2, &status)) { + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_ir_pre(&astate->js, count, + 0, charbuf); + } + break; + case OP_IPO: + /* + * IRPOST + * ...stack 0 is count + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + count = stack[--stack_ptr]; + status = altera_set_ir_post(&astate->js, count, + 0, NULL); + } + break; + case OP_IPOL: + /* + * IRPOST with literal data + * ...stack 0 is count + * ...stack 1 is literal data + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + count = stack[--stack_ptr]; + long_tmp = stack[--stack_ptr]; + put_unaligned_le32(long_tmp, &charbuf[0]); + status = altera_set_ir_post(&astate->js, count, 0, + charbuf); + break; + case OP_PCHR: + if (altera_check_stack(stack_ptr, 1, &status)) { + u8 ch; + count = strlen(msg_buff); + ch = (char) stack[--stack_ptr]; + if ((ch < 1) || (ch > 127)) { + /* + * character code out of range + * instead of flagging an error, + * force the value to 127 + */ + ch = 127; + } + msg_buff[count] = ch; + msg_buff[count + 1] = '\0'; + } + break; + case OP_EXIT: + if (altera_check_stack(stack_ptr, 1, &status)) + *exit_code = stack[--stack_ptr]; + + done = 1; + break; + case OP_EQU: + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + --stack_ptr; + stack[stack_ptr - 1] = + (stack[stack_ptr - 1] == stack[stack_ptr]) ? + 1L : 0L; + break; + case OP_POPT: + if (altera_check_stack(stack_ptr, 1, &status)) + --stack_ptr; + + break; + case OP_ABS: + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + if (stack[stack_ptr - 1] < 0) + stack[stack_ptr - 1] = 0 - stack[stack_ptr - 1]; + + break; + case OP_BCH0: + /* + * Batch operation 0 + * SWP + * SWPN 7 + * SWP + * SWPN 6 + * DUPN 8 + * SWPN 2 + * SWP + * DUPN 6 + * DUPN 6 + */ + + /* SWP */ + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWPN 7 */ + index = 7 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWP */ + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWPN 6 */ + index = 6 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* DUPN 8 */ + index = 8 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + + /* SWPN 2 */ + index = 2 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* SWP */ + if (altera_check_stack(stack_ptr, 2, &status)) { + long_tmp = stack[stack_ptr - 2]; + stack[stack_ptr - 2] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + + /* DUPN 6 */ + index = 6 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + + /* DUPN 6 */ + index = 6 + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + break; + case OP_PSH0: + stack[stack_ptr++] = 0; + break; + case OP_PSHL: + stack[stack_ptr++] = (s32) args[0]; + break; + case OP_PSHV: + stack[stack_ptr++] = vars[args[0]]; + break; + case OP_JMP: + pc = args[0] + code_sect; + if ((pc < code_sect) || (pc >= debug_sect)) + status = -ERANGE; + break; + case OP_CALL: + stack[stack_ptr++] = pc; + pc = args[0] + code_sect; + if ((pc < code_sect) || (pc >= debug_sect)) + status = -ERANGE; + break; + case OP_NEXT: + /* + * Process FOR / NEXT loop + * ...argument 0 is variable ID + * ...stack 0 is step value + * ...stack 1 is end value + * ...stack 2 is top address + */ + if (altera_check_stack(stack_ptr, 3, &status)) { + s32 step = stack[stack_ptr - 1]; + s32 end = stack[stack_ptr - 2]; + s32 top = stack[stack_ptr - 3]; + s32 iterator = vars[args[0]]; + int break_out = 0; + + if (step < 0) { + if (iterator <= end) + break_out = 1; + } else if (iterator >= end) + break_out = 1; + + if (break_out) { + stack_ptr -= 3; + } else { + vars[args[0]] = iterator + step; + pc = top + code_sect; + if ((pc < code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + } + } + break; + case OP_PSTR: + /* + * PRINT add string + * ...argument 0 is string ID + */ + count = strlen(msg_buff); + strlcpy(&msg_buff[count], + &p[str_table + args[0]], + ALTERA_MESSAGE_LENGTH - count); + break; + case OP_SINT: + /* + * STATE intermediate state + * ...argument 0 is state code + */ + status = altera_goto_jstate(astate, args[0]); + break; + case OP_ST: + /* + * STATE final state + * ...argument 0 is state code + */ + status = altera_goto_jstate(astate, args[0]); + break; + case OP_ISTP: + /* + * IRSTOP state + * ...argument 0 is state code + */ + status = altera_set_irstop(&astate->js, args[0]); + break; + case OP_DSTP: + /* + * DRSTOP state + * ...argument 0 is state code + */ + status = altera_set_drstop(&astate->js, args[0]); + break; + + case OP_SWPN: + /* + * Exchange top with Nth stack value + * ...argument 0 is 0-based stack entry + * to swap with top element + */ + index = (args[0]) + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + long_tmp = stack[stack_ptr - index]; + stack[stack_ptr - index] = stack[stack_ptr - 1]; + stack[stack_ptr - 1] = long_tmp; + } + break; + case OP_DUPN: + /* + * Duplicate Nth stack value + * ...argument 0 is 0-based stack entry to duplicate + */ + index = (args[0]) + 1; + if (altera_check_stack(stack_ptr, index, &status)) { + stack[stack_ptr] = stack[stack_ptr - index]; + ++stack_ptr; + } + break; + case OP_POPV: + /* + * Pop stack into scalar variable + * ...argument 0 is variable ID + * ...stack 0 is value + */ + if (altera_check_stack(stack_ptr, 1, &status)) + vars[args[0]] = stack[--stack_ptr]; + + break; + case OP_POPE: + /* + * Pop stack into integer array element + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is value + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + variable_id = args[0]; + + /* + * If variable is read-only, + * convert to writable array + */ + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x1c)) { + /* Allocate a writable buffer for this array */ + count = var_size[variable_id]; + long_tmp = vars[variable_id]; + longptr_tmp = kzalloc(count * sizeof(long), + GFP_KERNEL); + vars[variable_id] = (long)longptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* copy previous contents into buffer */ + for (i = 0; i < count; ++i) { + longptr_tmp[i] = + get_unaligned_be32(&p[long_tmp]); + long_tmp += sizeof(long); + } + + /* + * set bit 7 - buffer was + * dynamically allocated + */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + + } + + /* check that variable is a writable integer array */ + if ((attrs[variable_id] & 0x1c) != 0x18) + status = -ERANGE; + else { + longptr_tmp = (long *)vars[variable_id]; + + /* pop the array index */ + index = stack[--stack_ptr]; + + /* pop the value and store it into the array */ + longptr_tmp[index] = stack[--stack_ptr]; + } + + break; + case OP_POPA: + /* + * Pop stack into Boolean array + * ...argument 0 is variable ID + * ...stack 0 is count + * ...stack 1 is array index + * ...stack 2 is value + */ + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + variable_id = args[0]; + + /* + * If variable is read-only, + * convert to writable array + */ + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x0c)) { + /* Allocate a writable buffer for this array */ + long_tmp = + (var_size[variable_id] + 7L) >> 3L; + charptr_tmp2 = (u8 *)vars[variable_id]; + charptr_tmp = + kzalloc(long_tmp, GFP_KERNEL); + vars[variable_id] = (long)charptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* zero the buffer */ + for (long_idx = 0L; + long_idx < long_tmp; + ++long_idx) { + charptr_tmp[long_idx] = 0; + } + + /* copy previous contents into buffer */ + for (long_idx = 0L; + long_idx < var_size[variable_id]; + ++long_idx) { + long_idx2 = long_idx; + + if (charptr_tmp2[long_idx2 >> 3] & + (1 << (long_idx2 & 7))) { + charptr_tmp[long_idx >> 3] |= + (1 << (long_idx & 7)); + } + } + + /* + * set bit 7 - buffer was + * dynamically allocated + */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + + } + + /* + * check that variable is + * a writable Boolean array + */ + if ((attrs[variable_id] & 0x1c) != 0x08) { + status = -ERANGE; + break; + } + + charptr_tmp = (u8 *)vars[variable_id]; + + /* pop the count (number of bits to copy) */ + long_count = stack[--stack_ptr]; + + /* pop the array index */ + long_idx = stack[--stack_ptr]; + + reverse = 0; + + if (version > 0) { + /* + * stack 0 = array right index + * stack 1 = array left index + */ + + if (long_idx > long_count) { + reverse = 1; + long_tmp = long_count; + long_count = 1 + long_idx - + long_count; + long_idx = long_tmp; + + /* reverse POPA is not supported */ + status = -ERANGE; + break; + } else + long_count = 1 + long_count - + long_idx; + + } + + /* pop the data */ + long_tmp = stack[--stack_ptr]; + + if (long_count < 1) { + status = -ERANGE; + break; + } + + for (i = 0; i < long_count; ++i) { + if (long_tmp & (1L << (s32) i)) + charptr_tmp[long_idx >> 3L] |= + (1L << (long_idx & 7L)); + else + charptr_tmp[long_idx >> 3L] &= + ~(1L << (long_idx & 7L)); + + ++long_idx; + } + + break; + case OP_JMPZ: + /* + * Pop stack and branch if zero + * ...argument 0 is address + * ...stack 0 is condition value + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + if (stack[--stack_ptr] == 0) { + pc = args[0] + code_sect; + if ((pc < code_sect) || + (pc >= debug_sect)) + status = -ERANGE; + } + } + break; + case OP_DS: + case OP_IS: + /* + * DRSCAN + * IRSCAN + * ...argument 0 is scan data variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_idx = stack[--stack_ptr]; + long_count = stack[--stack_ptr]; + reverse = 0; + if (version > 0) { + /* + * stack 0 = array right index + * stack 1 = array left index + * stack 2 = count + */ + long_tmp = long_count; + long_count = stack[--stack_ptr]; + + if (long_idx > long_tmp) { + reverse = 1; + long_idx = long_tmp; + } + } + + charptr_tmp = (u8 *)vars[args[0]]; + + if (reverse) { + /* + * allocate a buffer + * and reverse the data order + */ + charptr_tmp2 = charptr_tmp; + charptr_tmp = kzalloc((long_count >> 3) + 1, + GFP_KERNEL); + if (charptr_tmp == NULL) { + status = -ENOMEM; + break; + } + + long_tmp = long_idx + long_count - 1; + long_idx2 = 0; + while (long_idx2 < long_count) { + if (charptr_tmp2[long_tmp >> 3] & + (1 << (long_tmp & 7))) + charptr_tmp[long_idx2 >> 3] |= + (1 << (long_idx2 & 7)); + else + charptr_tmp[long_idx2 >> 3] &= + ~(1 << (long_idx2 & 7)); + + --long_tmp; + ++long_idx2; + } + } + + if (opcode == 0x51) /* DS */ + status = altera_drscan(astate, long_count, + charptr_tmp, long_idx); + else /* IS */ + status = altera_irscan(astate, long_count, + charptr_tmp, long_idx); + + if (reverse) + kfree(charptr_tmp); + + break; + case OP_DPRA: + /* + * DRPRE with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_dr_pre(&astate->js, count, index, + charptr_tmp); + break; + case OP_DPOA: + /* + * DRPOST with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_dr_post(&astate->js, count, index, + charptr_tmp); + break; + case OP_IPRA: + /* + * IRPRE with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_ir_pre(&astate->js, count, index, + charptr_tmp); + + break; + case OP_IPOA: + /* + * IRPOST with array data + * ...argument 0 is variable ID + * ...stack 0 is array index + * ...stack 1 is count + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + index = stack[--stack_ptr]; + count = stack[--stack_ptr]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + charptr_tmp = (u8 *)vars[args[0]]; + status = altera_set_ir_post(&astate->js, count, index, + charptr_tmp); + + break; + case OP_EXPT: + /* + * EXPORT + * ...argument 0 is string ID + * ...stack 0 is integer expression + */ + if (altera_check_stack(stack_ptr, 1, &status)) { + name = &p[str_table + args[0]]; + long_tmp = stack[--stack_ptr]; + altera_export_int(name, long_tmp); + } + break; + case OP_PSHE: + /* + * Push integer array element + * ...argument 0 is variable ID + * ...stack 0 is array index + */ + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + variable_id = args[0]; + index = stack[stack_ptr - 1]; + + /* check variable type */ + if ((attrs[variable_id] & 0x1f) == 0x19) { + /* writable integer array */ + longptr_tmp = (long *)vars[variable_id]; + stack[stack_ptr - 1] = longptr_tmp[index]; + } else if ((attrs[variable_id] & 0x1f) == 0x1c) { + /* read-only integer array */ + long_tmp = vars[variable_id] + + (index * sizeof(long)); + stack[stack_ptr - 1] = + get_unaligned_be32(&p[long_tmp]); + } else + status = -ERANGE; + + break; + case OP_PSHA: + /* + * Push Boolean array + * ...argument 0 is variable ID + * ...stack 0 is count + * ...stack 1 is array index + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + variable_id = args[0]; + + /* check that variable is a Boolean array */ + if ((attrs[variable_id] & 0x18) != 0x08) { + status = -ERANGE; + break; + } + + charptr_tmp = (u8 *)vars[variable_id]; + + /* pop the count (number of bits to copy) */ + count = stack[--stack_ptr]; + + /* pop the array index */ + index = stack[stack_ptr - 1]; + + if (version > 0) + /* + * stack 0 = array right index + * stack 1 = array left index + */ + count = 1 + count - index; + + if ((count < 1) || (count > 32)) { + status = -ERANGE; + break; + } + + long_tmp = 0L; + + for (i = 0; i < count; ++i) + if (charptr_tmp[(i + index) >> 3] & + (1 << ((i + index) & 7))) + long_tmp |= (1L << i); + + stack[stack_ptr - 1] = long_tmp; + + break; + case OP_DYNA: + /* + * Dynamically change size of array + * ...argument 0 is variable ID + * ...stack 0 is new size + */ + if (!altera_check_stack(stack_ptr, 1, &status)) + break; + variable_id = args[0]; + long_tmp = stack[--stack_ptr]; + + if (long_tmp > var_size[variable_id]) { + var_size[variable_id] = long_tmp; + + if (attrs[variable_id] & 0x10) + /* allocate integer array */ + long_tmp *= sizeof(long); + else + /* allocate Boolean array */ + long_tmp = (long_tmp + 7) >> 3; + + /* + * If the buffer was previously allocated, + * free it + */ + if (attrs[variable_id] & 0x80) { + kfree((void *)vars[variable_id]); + vars[variable_id] = 0; + } + + /* + * Allocate a new buffer + * of the requested size + */ + vars[variable_id] = (long) + kzalloc(long_tmp, GFP_KERNEL); + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* + * Set the attribute bit to indicate that + * this buffer was dynamically allocated and + * should be freed later + */ + attrs[variable_id] |= 0x80; + + /* zero out memory */ + count = ((var_size[variable_id] + 7L) / + 8L); + charptr_tmp = (u8 *)(vars[variable_id]); + for (index = 0; index < count; ++index) + charptr_tmp[index] = 0; + + } + + break; + case OP_EXPV: + /* + * Export Boolean array + * ...argument 0 is string ID + * ...stack 0 is variable ID + * ...stack 1 is array right index + * ...stack 2 is array left index + */ + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + if (version == 0) { + /* EXPV is not supported in JBC 1.0 */ + bad_opcode = 1; + break; + } + name = &p[str_table + args[0]]; + variable_id = stack[--stack_ptr]; + long_idx = stack[--stack_ptr];/* right indx */ + long_idx2 = stack[--stack_ptr];/* left indx */ + + if (long_idx > long_idx2) { + /* reverse indices not supported */ + status = -ERANGE; + break; + } + + long_count = 1 + long_idx2 - long_idx; + + charptr_tmp = (u8 *)vars[variable_id]; + charptr_tmp2 = NULL; + + if ((long_idx & 7L) != 0) { + s32 k = long_idx; + charptr_tmp2 = + kzalloc(((long_count + 7L) / 8L), + GFP_KERNEL); + if (charptr_tmp2 == NULL) { + status = -ENOMEM; + break; + } + + for (i = 0; i < long_count; ++i) { + if (charptr_tmp[k >> 3] & + (1 << (k & 7))) + charptr_tmp2[i >> 3] |= + (1 << (i & 7)); + else + charptr_tmp2[i >> 3] &= + ~(1 << (i & 7)); + + ++k; + } + charptr_tmp = charptr_tmp2; + + } else if (long_idx != 0) + charptr_tmp = &charptr_tmp[long_idx >> 3]; + + altera_export_bool_array(name, charptr_tmp, + long_count); + + /* free allocated buffer */ + if ((long_idx & 7L) != 0) + kfree(charptr_tmp2); + + break; + case OP_COPY: { + /* + * Array copy + * ...argument 0 is dest ID + * ...argument 1 is source ID + * ...stack 0 is count + * ...stack 1 is dest index + * ...stack 2 is source index + */ + s32 copy_count; + s32 copy_index; + s32 copy_index2; + s32 destleft; + s32 src_count; + s32 dest_count; + int src_reverse = 0; + int dest_reverse = 0; + + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + + copy_count = stack[--stack_ptr]; + copy_index = stack[--stack_ptr]; + copy_index2 = stack[--stack_ptr]; + reverse = 0; + + if (version > 0) { + /* + * stack 0 = source right index + * stack 1 = source left index + * stack 2 = destination right index + * stack 3 = destination left index + */ + destleft = stack[--stack_ptr]; + + if (copy_count > copy_index) { + src_reverse = 1; + reverse = 1; + src_count = 1 + copy_count - copy_index; + /* copy_index = source start index */ + } else { + src_count = 1 + copy_index - copy_count; + /* source start index */ + copy_index = copy_count; + } + + if (copy_index2 > destleft) { + dest_reverse = 1; + reverse = !reverse; + dest_count = 1 + copy_index2 - destleft; + /* destination start index */ + copy_index2 = destleft; + } else + dest_count = 1 + destleft - copy_index2; + + copy_count = (src_count < dest_count) ? + src_count : dest_count; + + if ((src_reverse || dest_reverse) && + (src_count != dest_count)) + /* + * If either the source or destination + * is reversed, we can't tolerate + * a length mismatch, because we + * "left justify" arrays when copying. + * This won't work correctly + * with reversed arrays. + */ + status = -ERANGE; + + } + + count = copy_count; + index = copy_index; + index2 = copy_index2; + + /* + * If destination is a read-only array, + * allocate a buffer and convert it to a writable array + */ + variable_id = args[1]; + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x0c)) { + /* Allocate a writable buffer for this array */ + long_tmp = + (var_size[variable_id] + 7L) >> 3L; + charptr_tmp2 = (u8 *)vars[variable_id]; + charptr_tmp = + kzalloc(long_tmp, GFP_KERNEL); + vars[variable_id] = (long)charptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* zero the buffer */ + for (long_idx = 0L; long_idx < long_tmp; + ++long_idx) + charptr_tmp[long_idx] = 0; + + /* copy previous contents into buffer */ + for (long_idx = 0L; + long_idx < var_size[variable_id]; + ++long_idx) { + long_idx2 = long_idx; + + if (charptr_tmp2[long_idx2 >> 3] & + (1 << (long_idx2 & 7))) + charptr_tmp[long_idx >> 3] |= + (1 << (long_idx & 7)); + + } + + /* + set bit 7 - buffer was dynamically allocated */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + } + + charptr_tmp = (u8 *)vars[args[1]]; + charptr_tmp2 = (u8 *)vars[args[0]]; + + /* check if destination is a writable Boolean array */ + if ((attrs[args[1]] & 0x1c) != 0x08) { + status = -ERANGE; + break; + } + + if (count < 1) { + status = -ERANGE; + break; + } + + if (reverse) + index2 += (count - 1); + + for (i = 0; i < count; ++i) { + if (charptr_tmp2[index >> 3] & + (1 << (index & 7))) + charptr_tmp[index2 >> 3] |= + (1 << (index2 & 7)); + else + charptr_tmp[index2 >> 3] &= + ~(1 << (index2 & 7)); + + ++index; + if (reverse) + --index2; + else + ++index2; + } + + break; + } + case OP_DSC: + case OP_ISC: { + /* + * DRSCAN with capture + * IRSCAN with capture + * ...argument 0 is scan data variable ID + * ...argument 1 is capture variable ID + * ...stack 0 is capture index + * ...stack 1 is scan data index + * ...stack 2 is count + */ + s32 scan_right, scan_left; + s32 capture_count = 0; + s32 scan_count = 0; + s32 capture_index; + s32 scan_index; + + if (!altera_check_stack(stack_ptr, 3, &status)) + break; + + capture_index = stack[--stack_ptr]; + scan_index = stack[--stack_ptr]; + + if (version > 0) { + /* + * stack 0 = capture right index + * stack 1 = capture left index + * stack 2 = scan right index + * stack 3 = scan left index + * stack 4 = count + */ + scan_right = stack[--stack_ptr]; + scan_left = stack[--stack_ptr]; + capture_count = 1 + scan_index - capture_index; + scan_count = 1 + scan_left - scan_right; + scan_index = scan_right; + } + + long_count = stack[--stack_ptr]; + /* + * If capture array is read-only, allocate a buffer + * and convert it to a writable array + */ + variable_id = args[1]; + if ((version > 0) && + ((attrs[variable_id] & 0x9c) == 0x0c)) { + /* Allocate a writable buffer for this array */ + long_tmp = + (var_size[variable_id] + 7L) >> 3L; + charptr_tmp2 = (u8 *)vars[variable_id]; + charptr_tmp = + kzalloc(long_tmp, GFP_KERNEL); + vars[variable_id] = (long)charptr_tmp; + + if (vars[variable_id] == 0) { + status = -ENOMEM; + break; + } + + /* zero the buffer */ + for (long_idx = 0L; long_idx < long_tmp; + ++long_idx) + charptr_tmp[long_idx] = 0; + + /* copy previous contents into buffer */ + for (long_idx = 0L; + long_idx < var_size[variable_id]; + ++long_idx) { + long_idx2 = long_idx; + + if (charptr_tmp2[long_idx2 >> 3] & + (1 << (long_idx2 & 7))) + charptr_tmp[long_idx >> 3] |= + (1 << (long_idx & 7)); + + } + + /* + * set bit 7 - buffer was + * dynamically allocated + */ + attrs[variable_id] |= 0x80; + + /* clear bit 2 - variable is writable */ + attrs[variable_id] &= ~0x04; + attrs[variable_id] |= 0x01; + + } + + charptr_tmp = (u8 *)vars[args[0]]; + charptr_tmp2 = (u8 *)vars[args[1]]; + + if ((version > 0) && + ((long_count > capture_count) || + (long_count > scan_count))) { + status = -ERANGE; + break; + } + + /* + * check that capture array + * is a writable Boolean array + */ + if ((attrs[args[1]] & 0x1c) != 0x08) { + status = -ERANGE; + break; + } + + if (status == 0) { + if (opcode == 0x82) /* DSC */ + status = altera_swap_dr(astate, + long_count, + charptr_tmp, + scan_index, + charptr_tmp2, + capture_index); + else /* ISC */ + status = altera_swap_ir(astate, + long_count, + charptr_tmp, + scan_index, + charptr_tmp2, + capture_index); + + } + + break; + } + case OP_WAIT: + /* + * WAIT + * ...argument 0 is wait state + * ...argument 1 is end state + * ...stack 0 is cycles + * ...stack 1 is microseconds + */ + if (!altera_check_stack(stack_ptr, 2, &status)) + break; + long_tmp = stack[--stack_ptr]; + + if (long_tmp != 0L) + status = altera_wait_cycles(astate, long_tmp, + args[0]); + + long_tmp = stack[--stack_ptr]; + + if ((status == 0) && (long_tmp != 0L)) + status = altera_wait_msecs(astate, + long_tmp, + args[0]); + + if ((status == 0) && (args[1] != args[0])) + status = altera_goto_jstate(astate, + args[1]); + + if (version > 0) { + --stack_ptr; /* throw away MAX cycles */ + --stack_ptr; /* throw away MAX microseconds */ + } + break; + case OP_CMPA: { + /* + * Array compare + * ...argument 0 is source 1 ID + * ...argument 1 is source 2 ID + * ...argument 2 is mask ID + * ...stack 0 is source 1 index + * ...stack 1 is source 2 index + * ...stack 2 is mask index + * ...stack 3 is count + */ + s32 a, b; + u8 *source1 = (u8 *)vars[args[0]]; + u8 *source2 = (u8 *)vars[args[1]]; + u8 *mask = (u8 *)vars[args[2]]; + u32 index1; + u32 index2; + u32 mask_index; + + if (!altera_check_stack(stack_ptr, 4, &status)) + break; + + index1 = stack[--stack_ptr]; + index2 = stack[--stack_ptr]; + mask_index = stack[--stack_ptr]; + long_count = stack[--stack_ptr]; + + if (version > 0) { + /* + * stack 0 = source 1 right index + * stack 1 = source 1 left index + * stack 2 = source 2 right index + * stack 3 = source 2 left index + * stack 4 = mask right index + * stack 5 = mask left index + */ + s32 mask_right = stack[--stack_ptr]; + s32 mask_left = stack[--stack_ptr]; + /* source 1 count */ + a = 1 + index2 - index1; + /* source 2 count */ + b = 1 + long_count - mask_index; + a = (a < b) ? a : b; + /* mask count */ + b = 1 + mask_left - mask_right; + a = (a < b) ? a : b; + /* source 2 start index */ + index2 = mask_index; + /* mask start index */ + mask_index = mask_right; + long_count = a; + } + + long_tmp = 1L; + + if (long_count < 1) + status = -ERANGE; + else { + count = long_count; + + for (i = 0; i < count; ++i) { + if (mask[mask_index >> 3] & + (1 << (mask_index & 7))) { + a = source1[index1 >> 3] & + (1 << (index1 & 7)) + ? 1 : 0; + b = source2[index2 >> 3] & + (1 << (index2 & 7)) + ? 1 : 0; + + if (a != b) /* failure */ + long_tmp = 0L; + } + ++index1; + ++index2; + ++mask_index; + } + } + + stack[stack_ptr++] = long_tmp; + + break; + } + default: + /* Unrecognized opcode -- ERROR! */ + bad_opcode = 1; + break; + } + + if (bad_opcode) + status = -ENOSYS; + + if ((stack_ptr < 0) || (stack_ptr >= ALTERA_STACK_SIZE)) + status = -EOVERFLOW; + + if (status != 0) { + done = 1; + *error_address = (s32)(opcode_address - code_sect); + } + } + + altera_free_buffers(astate); + + /* Free all dynamically allocated arrays */ + if ((attrs != NULL) && (vars != NULL)) + for (i = 0; i < sym_count; ++i) + if (attrs[i] & 0x80) + kfree((void *)vars[i]); + + kfree(vars); + kfree(var_size); + kfree(attrs); + kfree(proc_attributes); + + return status; +} + +static int altera_get_note(u8 *p, s32 program_size, + s32 *offset, char *key, char *value, int length) +/* + * Gets key and value of NOTE fields in the JBC file. + * Can be called in two modes: if offset pointer is NULL, + * then the function searches for note fields which match + * the key string provided. If offset is not NULL, then + * the function finds the next note field of any key, + * starting at the offset specified by the offset pointer. + * Returns 0 for success, else appropriate error code + */ +{ + int status = -ENODATA; + u32 note_strings = 0L; + u32 note_table = 0L; + u32 note_count = 0L; + u32 first_word = 0L; + int version = 0; + int delta = 0; + char *key_ptr; + char *value_ptr; + int i; + + /* Read header information */ + if (program_size > 52L) { + first_word = get_unaligned_be32(&p[0]); + version = (first_word & 1L); + delta = version * 8; + + note_strings = get_unaligned_be32(&p[8 + delta]); + note_table = get_unaligned_be32(&p[12 + delta]); + note_count = get_unaligned_be32(&p[44 + (2 * delta)]); + } + + if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) + return -EIO; + + if (note_count <= 0L) + return status; + + if (offset == NULL) { + /* + * We will search for the first note with a specific key, + * and return only the value + */ + for (i = 0; (i < note_count) && + (status != 0); ++i) { + key_ptr = &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i)])]; + if ((strnicmp(key, key_ptr, strlen(key_ptr)) == 0) && + (key != NULL)) { + status = 0; + + value_ptr = &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i) + 4])]; + + if (value != NULL) + strlcpy(value, value_ptr, length); + + } + } + } else { + /* + * We will search for the next note, regardless of the key, + * and return both the value and the key + */ + + i = *offset; + + if ((i >= 0) && (i < note_count)) { + status = 0; + + if (key != NULL) + strlcpy(key, &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i)])], + length); + + if (value != NULL) + strlcpy(value, &p[note_strings + + get_unaligned_be32( + &p[note_table + (8 * i) + 4])], + length); + + *offset = i + 1; + } + } + + return status; +} + +static int altera_check_crc(u8 *p, s32 program_size) +{ + int status = 0; + u16 local_expected = 0, + local_actual = 0, + shift_reg = 0xffff; + int bit, feedback; + u8 databyte; + u32 i; + u32 crc_section = 0L; + u32 first_word = 0L; + int version = 0; + int delta = 0; + + if (program_size > 52L) { + first_word = get_unaligned_be32(&p[0]); + version = (first_word & 1L); + delta = version * 8; + + crc_section = get_unaligned_be32(&p[32 + delta]); + } + + if ((first_word != 0x4A414D00L) && (first_word != 0x4A414D01L)) + status = -EIO; + + if (crc_section >= program_size) + status = -EIO; + + if (status == 0) { + local_expected = (u16)get_unaligned_be16(&p[crc_section]); + + for (i = 0; i < crc_section; ++i) { + databyte = p[i]; + for (bit = 0; bit < 8; bit++) { + feedback = (databyte ^ shift_reg) & 0x01; + shift_reg >>= 1; + if (feedback) + shift_reg ^= 0x8408; + + databyte >>= 1; + } + } + + local_actual = (u16)~shift_reg; + + if (local_expected != local_actual) + status = -EILSEQ; + + } + + if (debug || status) { + switch (status) { + case 0: + printk(KERN_INFO "%s: CRC matched: %04x\n", __func__, + local_actual); + break; + case -EILSEQ: + printk(KERN_ERR "%s: CRC mismatch: expected %04x, " + "actual %04x\n", __func__, local_expected, + local_actual); + break; + case -ENODATA: + printk(KERN_ERR "%s: expected CRC not found, " + "actual CRC = %04x\n", __func__, + local_actual); + break; + case -EIO: + printk(KERN_ERR "%s: error: format isn't " + "recognized.\n", __func__); + break; + default: + printk(KERN_ERR "%s: CRC function returned error " + "code %d\n", __func__, status); + break; + } + } + + return status; +} + +static int altera_get_file_info(u8 *p, + s32 program_size, + int *format_version, + int *action_count, + int *procedure_count) +{ + int status = -EIO; + u32 first_word = 0; + int version = 0; + + if (program_size <= 52L) + return status; + + first_word = get_unaligned_be32(&p[0]); + + if ((first_word == 0x4A414D00L) || (first_word == 0x4A414D01L)) { + status = 0; + + version = (first_word & 1L); + *format_version = version + 1; + + if (version > 0) { + *action_count = get_unaligned_be32(&p[48]); + *procedure_count = get_unaligned_be32(&p[52]); + } + } + + return status; +} + +static int altera_get_act_info(u8 *p, + s32 program_size, + int index, + char **name, + char **description, + struct altera_procinfo **proc_list) +{ + int status = -EIO; + struct altera_procinfo *procptr = NULL; + struct altera_procinfo *tmpptr = NULL; + u32 first_word = 0L; + u32 action_table = 0L; + u32 proc_table = 0L; + u32 str_table = 0L; + u32 note_strings = 0L; + u32 action_count = 0L; + u32 proc_count = 0L; + u32 act_name_id = 0L; + u32 act_desc_id = 0L; + u32 act_proc_id = 0L; + u32 act_proc_name = 0L; + u8 act_proc_attribute = 0; + + if (program_size <= 52L) + return status; + /* Read header information */ + first_word = get_unaligned_be32(&p[0]); + + if (first_word != 0x4A414D01L) + return status; + + action_table = get_unaligned_be32(&p[4]); + proc_table = get_unaligned_be32(&p[8]); + str_table = get_unaligned_be32(&p[12]); + note_strings = get_unaligned_be32(&p[16]); + action_count = get_unaligned_be32(&p[48]); + proc_count = get_unaligned_be32(&p[52]); + + if (index >= action_count) + return status; + + act_name_id = get_unaligned_be32(&p[action_table + (12 * index)]); + act_desc_id = get_unaligned_be32(&p[action_table + (12 * index) + 4]); + act_proc_id = get_unaligned_be32(&p[action_table + (12 * index) + 8]); + + *name = &p[str_table + act_name_id]; + + if (act_desc_id < (note_strings - str_table)) + *description = &p[str_table + act_desc_id]; + + do { + act_proc_name = get_unaligned_be32( + &p[proc_table + (13 * act_proc_id)]); + act_proc_attribute = + (p[proc_table + (13 * act_proc_id) + 8] & 0x03); + + procptr = (struct altera_procinfo *) + kzalloc(sizeof(struct altera_procinfo), + GFP_KERNEL); + + if (procptr == NULL) + status = -ENOMEM; + else { + procptr->name = &p[str_table + act_proc_name]; + procptr->attrs = act_proc_attribute; + procptr->next = NULL; + + /* add record to end of linked list */ + if (*proc_list == NULL) + *proc_list = procptr; + else { + tmpptr = *proc_list; + while (tmpptr->next != NULL) + tmpptr = tmpptr->next; + tmpptr->next = procptr; + } + } + + act_proc_id = get_unaligned_be32( + &p[proc_table + (13 * act_proc_id) + 4]); + } while ((act_proc_id != 0) && (act_proc_id < proc_count)); + + return status; +} + +int altera_init(struct altera_config *config, const struct firmware *fw) +{ + struct altera_state *astate = NULL; + struct altera_procinfo *proc_list = NULL; + struct altera_procinfo *procptr = NULL; + char *key = NULL; + char *value = NULL; + char *action_name = NULL; + char *description = NULL; + int exec_result = 0; + int exit_code = 0; + int format_version = 0; + int action_count = 0; + int procedure_count = 0; + int index = 0; + s32 offset = 0L; + s32 error_address = 0L; + + key = kzalloc(33 * sizeof(char), GFP_KERNEL); + if (!key) + return -ENOMEM; + value = kzalloc(257 * sizeof(char), GFP_KERNEL); + if (!value) + return -ENOMEM; + astate = kzalloc(sizeof(struct altera_state), GFP_KERNEL); + if (!astate) + return -ENOMEM; + + astate->config = config; + if (!astate->config->jtag_io) { + dprintk(KERN_INFO "%s: using byteblaster!\n", __func__); + astate->config->jtag_io = netup_jtag_io_lpt; + } + + altera_check_crc((u8 *)fw->data, fw->size); + + if (debug) { + altera_get_file_info((u8 *)fw->data, fw->size, &format_version, + &action_count, &procedure_count); + printk(KERN_INFO "%s: File format is %s ByteCode format\n", + __func__, (format_version == 2) ? "Jam STAPL" : + "pre-standardized Jam 1.1"); + while (altera_get_note((u8 *)fw->data, fw->size, + &offset, key, value, 256) == 0) + printk(KERN_INFO "%s: NOTE \"%s\" = \"%s\"\n", + __func__, key, value); + } + + if (debug && (format_version == 2) && (action_count > 0)) { + printk(KERN_INFO "%s: Actions available:\n", __func__); + for (index = 0; index < action_count; ++index) { + altera_get_act_info((u8 *)fw->data, fw->size, + index, &action_name, + &description, + &proc_list); + + if (description == NULL) + printk(KERN_INFO "%s: %s\n", + __func__, + action_name); + else + printk(KERN_INFO "%s: %s \"%s\"\n", + __func__, + action_name, + description); + + procptr = proc_list; + while (procptr != NULL) { + if (procptr->attrs != 0) + printk(KERN_INFO "%s: %s (%s)\n", + __func__, + procptr->name, + (procptr->attrs == 1) ? + "optional" : "recommended"); + + proc_list = procptr->next; + kfree(procptr); + procptr = proc_list; + } + } + + printk(KERN_INFO "\n"); + } + + exec_result = altera_execute(astate, (u8 *)fw->data, fw->size, + &error_address, &exit_code, &format_version); + + if (exit_code) + exec_result = -EREMOTEIO; + + if ((format_version == 2) && (exec_result == -EINVAL)) { + if (astate->config->action == NULL) + printk(KERN_ERR "%s: error: no action specified for " + "Jam STAPL file.\nprogram terminated.\n", + __func__); + else + printk(KERN_ERR "%s: error: action \"%s\"" + " is not supported " + "for this Jam STAPL file.\n" + "Program terminated.\n", __func__, + astate->config->action); + + } else if (exec_result) + printk(KERN_ERR "%s: error %d\n", __func__, exec_result); + + kfree(key); + kfree(value); + kfree(astate); + + return 0; +} +EXPORT_SYMBOL(altera_init); -- cgit v1.2.2 From 349bcf02e3615556e9c49ea73a04abab2a4d8ed7 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:01:00 -0300 Subject: [media] Altera FPGA based CI driver module An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 9 + drivers/media/video/cx23885/Makefile | 1 + drivers/media/video/cx23885/altera-ci.c | 830 ++++++++++++++++++++++++++++++++ drivers/media/video/cx23885/altera-ci.h | 102 ++++ 4 files changed, 942 insertions(+) create mode 100644 drivers/media/video/cx23885/altera-ci.c create mode 100644 drivers/media/video/cx23885/altera-ci.h (limited to 'drivers') diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 6b4a516addfe..5e5faadd678f 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -33,3 +33,12 @@ config VIDEO_CX23885 To compile this driver as a module, choose M here: the module will be called cx23885 +config MEDIA_ALTERA_CI + tristate "Altera FPGA based CI module" + depends on VIDEO_CX23885 && DVB_CORE + select STAPL_ALTERA + ---help--- + An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. + + To compile this driver as a module, choose M here: the + module will be called altera-ci diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index e2ee95f660d8..23293c7b6ac7 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -5,6 +5,7 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \ cx23885-f300.o obj-$(CONFIG_VIDEO_CX23885) += cx23885.o +obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o EXTRA_CFLAGS += -Idrivers/media/video EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c new file mode 100644 index 000000000000..e5c0873aca15 --- /dev/null +++ b/drivers/media/video/cx23885/altera-ci.c @@ -0,0 +1,830 @@ +/* + * altera-ci.c + * + * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card + * + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * currently cx23885 GPIO's used. + * GPIO-0 ~INT in + * GPIO-1 TMS out + * GPIO-2 ~reset chips out + * GPIO-3 to GPIO-10 data/addr for CA in/out + * GPIO-11 ~CS out + * GPIO-12 AD_RG out + * GPIO-13 ~WR out + * GPIO-14 ~RD out + * GPIO-15 ~RDY in + * GPIO-16 TCK out + * GPIO-17 TDO in + * GPIO-18 TDI out + */ +/* + * Bit definitions for MC417_RWD and MC417_OEN registers + * bits 31-16 + * +-----------+ + * | Reserved | + * +-----------+ + * bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | TDI | TDO | TCK | RDY# | #RD | #WR | AD_RG | #CS | + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0 + * +-------+-------+-------+-------+-------+-------+-------+-------+ + * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| + * +-------+-------+-------+-------+-------+-------+-------+-------+ + */ +#include +#include +#include +#include "altera-ci.h" +#include "dvb_ca_en50221.h" + +/* FPGA regs */ +#define NETUP_CI_INT_CTRL 0x00 +#define NETUP_CI_BUSCTRL2 0x01 +#define NETUP_CI_ADDR0 0x04 +#define NETUP_CI_ADDR1 0x05 +#define NETUP_CI_DATA 0x06 +#define NETUP_CI_BUSCTRL 0x07 +#define NETUP_CI_PID_ADDR0 0x08 +#define NETUP_CI_PID_ADDR1 0x09 +#define NETUP_CI_PID_DATA 0x0a +#define NETUP_CI_TSA_DIV 0x0c +#define NETUP_CI_TSB_DIV 0x0d +#define NETUP_CI_REVISION 0x0f + +/* const for ci op */ +#define NETUP_CI_FLG_CTL 1 +#define NETUP_CI_FLG_RD 1 +#define NETUP_CI_FLG_AD 1 + +static unsigned int ci_dbg; +module_param(ci_dbg, int, 0644); +MODULE_PARM_DESC(ci_dbg, "Enable CI debugging"); + +static unsigned int pid_dbg; +module_param(pid_dbg, int, 0644); +MODULE_PARM_DESC(pid_dbg, "Enable PID filtering debugging"); + +MODULE_DESCRIPTION("altera FPGA CI module"); +MODULE_AUTHOR("Igor M. Liplianin "); +MODULE_LICENSE("GPL"); + +#define ci_dbg_print(args...) \ + do { \ + if (ci_dbg) \ + printk(KERN_DEBUG args); \ + } while (0) + +#define pid_dbg_print(args...) \ + do { \ + if (pid_dbg) \ + printk(KERN_DEBUG args); \ + } while (0) + +struct altera_ci_state; +struct netup_hw_pid_filter; + +struct fpga_internal { + void *dev; + struct mutex fpga_mutex;/* two CI's on the same fpga */ + struct netup_hw_pid_filter *pid_filt[2]; + struct altera_ci_state *state[2]; + struct work_struct work; + int (*fpga_rw) (void *dev, int flag, int data, int rw); + int cis_used; + int filts_used; + int strt_wrk; +}; + +/* stores all private variables for communication with CI */ +struct altera_ci_state { + struct fpga_internal *internal; + struct dvb_ca_en50221 ca; + int status; + int nr; +}; + +/* stores all private variables for hardware pid filtering */ +struct netup_hw_pid_filter { + struct fpga_internal *internal; + struct dvb_demux *demux; + /* save old functions */ + int (*start_feed)(struct dvb_demux_feed *feed); + int (*stop_feed)(struct dvb_demux_feed *feed); + + int status; + int nr; +}; + +/* internal params node */ +struct fpga_inode { + /* pointer for internal params, one for each pair of CI's */ + struct fpga_internal *internal; + struct fpga_inode *next_inode; +}; + +/* first internal params */ +static struct fpga_inode *fpga_first_inode; + +/* find chip by dev */ +static struct fpga_inode *find_inode(void *dev) +{ + struct fpga_inode *temp_chip = fpga_first_inode; + + if (temp_chip == NULL) + return temp_chip; + + /* + Search for the last fpga CI chip or + find it by dev */ + while ((temp_chip != NULL) && + (temp_chip->internal->dev != dev)) + temp_chip = temp_chip->next_inode; + + return temp_chip; +} +/* check demux */ +static struct fpga_internal *check_filter(struct fpga_internal *temp_int, + void *demux_dev, int filt_nr) +{ + if (temp_int == NULL) + return NULL; + + if ((temp_int->pid_filt[filt_nr]) == NULL) + return NULL; + + if (temp_int->pid_filt[filt_nr]->demux == demux_dev) + return temp_int; + + return NULL; +} + +/* find chip by demux */ +static struct fpga_inode *find_dinode(void *demux_dev) +{ + struct fpga_inode *temp_chip = fpga_first_inode; + struct fpga_internal *temp_int; + + /* + * Search of the last fpga CI chip or + * find it by demux + */ + while (temp_chip != NULL) { + if (temp_chip->internal != NULL) { + temp_int = temp_chip->internal; + if (check_filter(temp_int, demux_dev, 0)) + break; + if (check_filter(temp_int, demux_dev, 1)) + break; + } + + temp_chip = temp_chip->next_inode; + } + + return temp_chip; +} + +/* deallocating chip */ +static void remove_inode(struct fpga_internal *internal) +{ + struct fpga_inode *prev_node = fpga_first_inode; + struct fpga_inode *del_node = find_inode(internal->dev); + + if (del_node != NULL) { + if (del_node == fpga_first_inode) { + fpga_first_inode = del_node->next_inode; + } else { + while (prev_node->next_inode != del_node) + prev_node = prev_node->next_inode; + + if (del_node->next_inode == NULL) + prev_node->next_inode = NULL; + else + prev_node->next_inode = + prev_node->next_inode->next_inode; + } + + kfree(del_node); + } +} + +/* allocating new chip */ +static struct fpga_inode *append_internal(struct fpga_internal *internal) +{ + struct fpga_inode *new_node = fpga_first_inode; + + if (new_node == NULL) { + new_node = kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); + fpga_first_inode = new_node; + } else { + while (new_node->next_inode != NULL) + new_node = new_node->next_inode; + + new_node->next_inode = + kmalloc(sizeof(struct fpga_inode), GFP_KERNEL); + if (new_node->next_inode != NULL) + new_node = new_node->next_inode; + else + new_node = NULL; + } + + if (new_node != NULL) { + new_node->internal = internal; + new_node->next_inode = NULL; + } + + return new_node; +} + +static int netup_fpga_op_rw(struct fpga_internal *inter, int addr, + u8 val, u8 read) +{ + inter->fpga_rw(inter->dev, NETUP_CI_FLG_AD, addr, 0); + return inter->fpga_rw(inter->dev, 0, val, read); +} + +/* flag - mem/io, read - read/write */ +int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, + u8 flag, u8 read, int addr, u8 val) +{ + + struct altera_ci_state *state = en50221->data; + struct fpga_internal *inter = state->internal; + + u8 store; + int mem = 0; + + if (0 != slot) + return -EINVAL; + + mutex_lock(&inter->fpga_mutex); + + netup_fpga_op_rw(inter, NETUP_CI_ADDR0, ((addr << 1) & 0xfe), 0); + netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0); + store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + + store &= 0x3f; + store |= ((state->nr << 7) | (flag << 6)); + + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0); + mem = netup_fpga_op_rw(inter, NETUP_CI_DATA, val, read); + + mutex_unlock(&inter->fpga_mutex); + + ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__, + (read) ? "read" : "write", addr, + (flag == NETUP_CI_FLG_CTL) ? "ctl" : "mem", + (read) ? mem : val); + + return mem; +} + +int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr) +{ + return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0); +} + +int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data) +{ + return altera_ci_op_cam(en50221, slot, 0, 0, addr, data); +} + +int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +{ + return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, + NETUP_CI_FLG_RD, addr, 0); +} + +int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, + u8 addr, u8 data) +{ + return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data); +} + +int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct altera_ci_state *state = en50221->data; + struct fpga_internal *inter = state->internal; + /* reasonable timeout for CI reset is 10 seconds */ + unsigned long t_out = jiffies + msecs_to_jiffies(9999); + int ret; + + ci_dbg_print("%s\n", __func__); + + if (0 != slot) + return -EINVAL; + + mutex_lock(&inter->fpga_mutex); + + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, + ret | (1 << (5 - state->nr)), 0); + + for (;;) { + mdelay(50); + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, + 0, NETUP_CI_FLG_RD); + if ((ret & (1 << (5 - state->nr))) == 0) + break; + if (time_after(jiffies, t_out)) + break; + } + + mutex_unlock(&inter->fpga_mutex); + + ci_dbg_print("%s: %d msecs\n", __func__, + jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out)); + + return 0; +} + +int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + /* not implemented */ + return 0; +} + +int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) +{ + struct altera_ci_state *state = en50221->data; + struct fpga_internal *inter = state->internal; + int ret; + + ci_dbg_print("%s\n", __func__); + + if (0 != slot) + return -EINVAL; + + mutex_lock(&inter->fpga_mutex); + + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, + ret | (1 << (3 - state->nr)), 0); + + mutex_unlock(&inter->fpga_mutex); + + return 0; +} + +/* work handler */ +static void netup_read_ci_status(struct work_struct *work) +{ + struct fpga_internal *inter = + container_of(work, struct fpga_internal, work); + int ret; + + ci_dbg_print("%s\n", __func__); + + mutex_lock(&inter->fpga_mutex); + /* ack' irq */ + ret = netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0, NETUP_CI_FLG_RD); + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + + mutex_unlock(&inter->fpga_mutex); + + if (inter->state[1] != NULL) { + inter->state[1]->status = + ((ret & 1) == 0 ? + DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY : 0); + ci_dbg_print("%s: setting CI[1] status = 0x%x\n", + __func__, inter->state[1]->status); + }; + + if (inter->state[0] != NULL) { + inter->state[0]->status = + ((ret & 2) == 0 ? + DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY : 0); + ci_dbg_print("%s: setting CI[0] status = 0x%x\n", + __func__, inter->state[0]->status); + }; +} + +/* CI irq handler */ +int altera_ci_irq(void *dev) +{ + struct fpga_inode *temp_int = NULL; + struct fpga_internal *inter = NULL; + + ci_dbg_print("%s\n", __func__); + + if (dev != NULL) { + temp_int = find_inode(dev); + if (temp_int != NULL) { + inter = temp_int->internal; + schedule_work(&inter->work); + } + } + + return 1; +} +EXPORT_SYMBOL(altera_ci_irq); + +int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, + int open) +{ + struct altera_ci_state *state = en50221->data; + + if (0 != slot) + return -EINVAL; + + return state->status; +} + +void altera_hw_filt_release(void *main_dev, int filt_nr) +{ + struct fpga_inode *temp_int = find_inode(main_dev); + struct netup_hw_pid_filter *pid_filt = NULL; + + ci_dbg_print("%s\n", __func__); + + if (temp_int != NULL) { + pid_filt = temp_int->internal->pid_filt[filt_nr - 1]; + /* stored old feed controls */ + pid_filt->demux->start_feed = pid_filt->start_feed; + pid_filt->demux->stop_feed = pid_filt->stop_feed; + + if (((--(temp_int->internal->filts_used)) <= 0) && + ((temp_int->internal->cis_used) <= 0)) { + + ci_dbg_print("%s: Actually removing\n", __func__); + + remove_inode(temp_int->internal); + kfree(pid_filt->internal); + } + + kfree(pid_filt); + + } + +} +EXPORT_SYMBOL(altera_hw_filt_release); + +void altera_ci_release(void *dev, int ci_nr) +{ + struct fpga_inode *temp_int = find_inode(dev); + struct altera_ci_state *state = NULL; + + ci_dbg_print("%s\n", __func__); + + if (temp_int != NULL) { + state = temp_int->internal->state[ci_nr - 1]; + altera_hw_filt_release(dev, ci_nr); + + + if (((temp_int->internal->filts_used) <= 0) && + ((--(temp_int->internal->cis_used)) <= 0)) { + + ci_dbg_print("%s: Actually removing\n", __func__); + + remove_inode(temp_int->internal); + kfree(state->internal); + } + + if (state != NULL) { + if (state->ca.data != NULL) + dvb_ca_en50221_release(&state->ca); + + kfree(state); + } + } + +} +EXPORT_SYMBOL(altera_ci_release); + +static void altera_pid_control(struct netup_hw_pid_filter *pid_filt, + u16 pid, int onoff) +{ + struct fpga_internal *inter = pid_filt->internal; + u8 store = 0; + + if (pid == 0x2000) + return; + + mutex_lock(&inter->fpga_mutex); + + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, (pid >> 3) & 0xff, 0); + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, + ((pid >> 11) & 0x03) | (pid_filt->nr << 2), 0); + + store = netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, 0, NETUP_CI_FLG_RD); + + if (onoff)/* 0 - on, 1 - off */ + store |= (1 << (pid & 7)); + else + store &= ~(1 << (pid & 7)); + + netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0); + + mutex_unlock(&inter->fpga_mutex); + + pid_dbg_print("%s: (%d) set pid: %5d 0x%04x '%s'\n", __func__, + pid_filt->nr, pid, pid, onoff ? "off" : "on"); +} + +static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt, + int filt_nr, int onoff) +{ + struct fpga_internal *inter = pid_filt->internal; + u8 store = 0; + int i; + + pid_dbg_print("%s: pid_filt->nr[%d] now %s\n", __func__, pid_filt->nr, + onoff ? "off" : "on"); + + if (onoff)/* 0 - on, 1 - off */ + store = 0xff;/* ignore pid */ + else + store = 0;/* enable pid */ + + mutex_lock(&inter->fpga_mutex); + + for (i = 0; i < 1024; i++) { + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR0, i & 0xff, 0); + + netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, + ((i >> 8) & 0x03) | (pid_filt->nr << 2), 0); + + netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0); + } + + mutex_unlock(&inter->fpga_mutex); +} + +int altera_pid_feed_control(void *demux_dev, int filt_nr, + struct dvb_demux_feed *feed, int onoff) +{ + struct fpga_inode *temp_int = find_dinode(demux_dev); + struct fpga_internal *inter = temp_int->internal; + struct netup_hw_pid_filter *pid_filt = inter->pid_filt[filt_nr - 1]; + + altera_pid_control(pid_filt, feed->pid, onoff ? 0 : 1); + /* call old feed proc's */ + if (onoff) + pid_filt->start_feed(feed); + else + pid_filt->stop_feed(feed); + + if (feed->pid == 0x2000) + altera_toggle_fullts_streaming(pid_filt, filt_nr, + onoff ? 0 : 1); + + return 0; +} +EXPORT_SYMBOL(altera_pid_feed_control); + +int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) +{ + altera_pid_feed_control(feed->demux, num, feed, 1); + + return 0; +} + +int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num) +{ + altera_pid_feed_control(feed->demux, num, feed, 0); + + return 0; +} + +int altera_ci_start_feed_1(struct dvb_demux_feed *feed) +{ + return altera_ci_start_feed(feed, 1); +} + +int altera_ci_stop_feed_1(struct dvb_demux_feed *feed) +{ + return altera_ci_stop_feed(feed, 1); +} + +int altera_ci_start_feed_2(struct dvb_demux_feed *feed) +{ + return altera_ci_start_feed(feed, 2); +} + +int altera_ci_stop_feed_2(struct dvb_demux_feed *feed) +{ + return altera_ci_stop_feed(feed, 2); +} + +int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) +{ + struct netup_hw_pid_filter *pid_filt = NULL; + struct fpga_inode *temp_int = find_inode(config->dev); + struct fpga_internal *inter = NULL; + int ret = 0; + + pid_filt = kzalloc(sizeof(struct netup_hw_pid_filter), GFP_KERNEL); + + ci_dbg_print("%s\n", __func__); + + if (!pid_filt) { + ret = -ENOMEM; + goto err; + } + + if (temp_int != NULL) { + inter = temp_int->internal; + (inter->filts_used)++; + ci_dbg_print("%s: Find Internal Structure!\n", __func__); + } else { + inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); + if (!inter) { + ret = -ENOMEM; + goto err; + } + + temp_int = append_internal(inter); + inter->filts_used = 1; + inter->dev = config->dev; + inter->fpga_rw = config->fpga_rw; + mutex_init(&inter->fpga_mutex); + inter->strt_wrk = 1; + ci_dbg_print("%s: Create New Internal Structure!\n", __func__); + } + + ci_dbg_print("%s: setting hw pid filter = 0x%x for ci = %d\n", __func__, + (int)pid_filt, hw_filt_nr - 1); + inter->pid_filt[hw_filt_nr - 1] = pid_filt; + pid_filt->demux = config->demux; + pid_filt->internal = inter; + pid_filt->nr = hw_filt_nr - 1; + /* store old feed controls */ + pid_filt->start_feed = config->demux->start_feed; + pid_filt->stop_feed = config->demux->stop_feed; + /* replace with new feed controls */ + if (hw_filt_nr == 1) { + pid_filt->demux->start_feed = altera_ci_start_feed_1; + pid_filt->demux->stop_feed = altera_ci_stop_feed_1; + } else if (hw_filt_nr == 2) { + pid_filt->demux->start_feed = altera_ci_start_feed_2; + pid_filt->demux->stop_feed = altera_ci_stop_feed_2; + } + + altera_toggle_fullts_streaming(pid_filt, 0, 1); + + return 0; +err: + ci_dbg_print("%s: Can't init hardware filter: Error %d\n", + __func__, ret); + + kfree(pid_filt); + + return ret; +} +EXPORT_SYMBOL(altera_hw_filt_init); + +int altera_ci_init(struct altera_ci_config *config, int ci_nr) +{ + struct altera_ci_state *state; + struct fpga_inode *temp_int = find_inode(config->dev); + struct fpga_internal *inter = NULL; + int ret = 0; + u8 store = 0; + + state = kzalloc(sizeof(struct altera_ci_state), GFP_KERNEL); + + ci_dbg_print("%s\n", __func__); + + if (!state) { + ret = -ENOMEM; + goto err; + } + + if (temp_int != NULL) { + inter = temp_int->internal; + (inter->cis_used)++; + ci_dbg_print("%s: Find Internal Structure!\n", __func__); + } else { + inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); + if (!inter) { + ret = -ENOMEM; + goto err; + } + + temp_int = append_internal(inter); + inter->cis_used = 1; + inter->dev = config->dev; + inter->fpga_rw = config->fpga_rw; + mutex_init(&inter->fpga_mutex); + inter->strt_wrk = 1; + ci_dbg_print("%s: Create New Internal Structure!\n", __func__); + } + + ci_dbg_print("%s: setting state = 0x%x for ci = %d\n", __func__, + (int)state, ci_nr - 1); + inter->state[ci_nr - 1] = state; + state->internal = inter; + state->nr = ci_nr - 1; + + state->ca.owner = THIS_MODULE; + state->ca.read_attribute_mem = altera_ci_read_attribute_mem; + state->ca.write_attribute_mem = altera_ci_write_attribute_mem; + state->ca.read_cam_control = altera_ci_read_cam_ctl; + state->ca.write_cam_control = altera_ci_write_cam_ctl; + state->ca.slot_reset = altera_ci_slot_reset; + state->ca.slot_shutdown = altera_ci_slot_shutdown; + state->ca.slot_ts_enable = altera_ci_slot_ts_ctl; + state->ca.poll_slot_status = altera_poll_ci_slot_status; + state->ca.data = state; + + ret = dvb_ca_en50221_init(config->adapter, + &state->ca, + /* flags */ 0, + /* n_slots */ 1); + if (0 != ret) + goto err; + + altera_hw_filt_init(config, ci_nr); + + if (inter->strt_wrk) { + INIT_WORK(&inter->work, netup_read_ci_status); + inter->strt_wrk = 0; + } + + ci_dbg_print("%s: CI initialized!\n", __func__); + + mutex_lock(&inter->fpga_mutex); + + /* Enable div */ + netup_fpga_op_rw(inter, NETUP_CI_TSA_DIV, 0x0, 0); + netup_fpga_op_rw(inter, NETUP_CI_TSB_DIV, 0x0, 0); + + /* enable TS out */ + store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); + store |= (3 << 4); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); + + ret = netup_fpga_op_rw(inter, NETUP_CI_REVISION, 0, NETUP_CI_FLG_RD); + /* enable irq */ + netup_fpga_op_rw(inter, NETUP_CI_INT_CTRL, 0x44, 0); + + mutex_unlock(&inter->fpga_mutex); + + ci_dbg_print("%s: NetUP CI Revision = 0x%x\n", __func__, ret); + + schedule_work(&inter->work); + + return 0; +err: + ci_dbg_print("%s: Cannot initialize CI: Error %d.\n", __func__, ret); + + kfree(state); + + return ret; +} +EXPORT_SYMBOL(altera_ci_init); + +int altera_ci_tuner_reset(void *dev, int ci_nr) +{ + struct fpga_inode *temp_int = find_inode(dev); + struct fpga_internal *inter = NULL; + u8 store; + + ci_dbg_print("%s\n", __func__); + + if (temp_int == NULL) + return -1; + + if (temp_int->internal == NULL) + return -1; + + inter = temp_int->internal; + + mutex_lock(&inter->fpga_mutex); + + store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, 0, NETUP_CI_FLG_RD); + store &= ~(4 << (2 - ci_nr)); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); + msleep(100); + store |= (4 << (2 - ci_nr)); + netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL2, store, 0); + + mutex_unlock(&inter->fpga_mutex); + + return 0; +} +EXPORT_SYMBOL(altera_ci_tuner_reset); diff --git a/drivers/media/video/cx23885/altera-ci.h b/drivers/media/video/cx23885/altera-ci.h new file mode 100644 index 000000000000..ba0c6c05082a --- /dev/null +++ b/drivers/media/video/cx23885/altera-ci.h @@ -0,0 +1,102 @@ +/* + * altera-ci.c + * + * CI driver in conjunction with NetUp Dual DVB-T/C RF CI card + * + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef __ALTERA_CI_H +#define __ALTERA_CI_H + +#define ALT_DATA 0x000000ff +#define ALT_TDI 0x00008000 +#define ALT_TDO 0x00004000 +#define ALT_TCK 0x00002000 +#define ALT_RDY 0x00001000 +#define ALT_RD 0x00000800 +#define ALT_WR 0x00000400 +#define ALT_AD_RG 0x00000200 +#define ALT_CS 0x00000100 + +struct altera_ci_config { + void *dev;/* main dev, for example cx23885_dev */ + void *adapter;/* for CI to connect to */ + struct dvb_demux *demux;/* for hardware PID filter to connect to */ + int (*fpga_rw) (void *dev, int ad_rg, int val, int rw); +}; + +#if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \ + && defined(MODULE)) + +extern int altera_ci_init(struct altera_ci_config *config, int ci_nr); +extern void altera_ci_release(void *dev, int ci_nr); +extern int altera_ci_irq(void *dev); +extern int altera_ci_tuner_reset(void *dev, int ci_nr); + +#else + +static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline void altera_ci_release(void *dev, int ci_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int altera_ci_irq(void *dev) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static int altera_ci_tuner_reset(void *dev, int ci_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +#endif +#if 0 +static inline int altera_hw_filt_init(struct altera_ci_config *config, + int hw_filt_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline void altera_hw_filt_release(void *dev, int filt_nr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int altera_pid_feed_control(void *dev, int filt_nr, + struct dvb_demux_feed *dvbdmxfeed, int onoff) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +#endif /* CONFIG_MEDIA_ALTERA_CI */ + +#endif /* __ALTERA_CI_H */ -- cgit v1.2.2 From 17cce932e8be9a3e32e1928524b73795b3f0e3aa Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:02:00 -0300 Subject: [media] Support for stv0367 multi-standard demodulator The STV0367 is a multi-standard demodulator which is capable of processing DVB-T as well as DVB-C signals. It is fully compliant with DVB-T and DVB-C recommendations for broadcast services. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/Kconfig | 7 + drivers/media/dvb/frontends/Makefile | 1 + drivers/media/dvb/frontends/stv0367.c | 3441 ++++++++++++++++++++++++++ drivers/media/dvb/frontends/stv0367.h | 66 + drivers/media/dvb/frontends/stv0367_priv.h | 212 ++ drivers/media/dvb/frontends/stv0367_regs.h | 3614 ++++++++++++++++++++++++++++ 6 files changed, 7341 insertions(+) create mode 100644 drivers/media/dvb/frontends/stv0367.c create mode 100644 drivers/media/dvb/frontends/stv0367.h create mode 100644 drivers/media/dvb/frontends/stv0367_priv.h create mode 100644 drivers/media/dvb/frontends/stv0367_regs.h (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index a20c1532726a..83093d1f4f74 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -378,6 +378,13 @@ config DVB_EC100 help Say Y when you want to support this frontend. +config DVB_STV0367 + tristate "ST STV0367 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T/C tuner module. Say Y when you want to support this frontend. + comment "DVB-C (cable) frontends" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 31dd201c57ce..3b0c4bdc4b2b 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -84,3 +84,4 @@ obj-$(CONFIG_DVB_DS3000) += ds3000.o obj-$(CONFIG_DVB_MB86A16) += mb86a16.o obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o obj-$(CONFIG_DVB_IX2505V) += ix2505v.o +obj-$(CONFIG_DVB_STV0367) += stv0367.o diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c new file mode 100644 index 000000000000..eecdf23642eb --- /dev/null +++ b/drivers/media/dvb/frontends/stv0367.c @@ -0,0 +1,3441 @@ +/* + * stv0367.c + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include + +#include "stv0367.h" +#include "stv0367_regs.h" +#include "stv0367_priv.h" + +static int stvdebug; +module_param_named(debug, stvdebug, int, 0644); + +static int i2cdebug; +module_param_named(i2c_debug, i2cdebug, int, 0644); + +#define dprintk(args...) \ + do { \ + if (stvdebug) \ + printk(KERN_DEBUG args); \ + } while (0) + /* DVB-C */ + +struct stv0367cab_state { + enum stv0367_cab_signal_type state; + u32 mclk; + u32 adc_clk; + s32 search_range; + s32 derot_offset; + /* results */ + int locked; /* channel found */ + u32 freq_khz; /* found frequency (in kHz) */ + u32 symbol_rate; /* found symbol rate (in Bds) */ + enum stv0367cab_mod modulation; /* modulation */ + fe_spectral_inversion_t spect_inv; /* Spectrum Inversion */ +}; + +struct stv0367ter_state { + /* DVB-T */ + enum stv0367_ter_signal_type state; + enum stv0367_ter_if_iq_mode if_iq_mode; + enum stv0367_ter_mode mode;/* mode 2K or 8K */ + fe_guard_interval_t guard; + enum stv0367_ter_hierarchy hierarchy; + u32 frequency; + fe_spectral_inversion_t sense; /* current search spectrum */ + u8 force; /* force mode/guard */ + u8 bw; /* channel width 6, 7 or 8 in MHz */ + u8 pBW; /* channel width used during previous lock */ + u32 pBER; + u32 pPER; + u32 ucblocks; + s8 echo_pos; /* echo position */ + u8 first_lock; + u8 unlock_counter; + u32 agc_val; +}; + +struct stv0367_state { + struct dvb_frontend fe; + struct i2c_adapter *i2c; + /* config settings */ + const struct stv0367_config *config; + u8 chip_id; + /* DVB-C */ + struct stv0367cab_state *cab_state; + /* DVB-T */ + struct stv0367ter_state *ter_state; +}; + +struct st_register { + u16 addr; + u8 value; +}; + +/* values for STV4100 XTAL=30M int clk=53.125M*/ +static struct st_register def0367ter[STV0367TER_NBREGS] = { + {R367TER_ID, 0x60}, + {R367TER_I2CRPT, 0xa0}, + /* {R367TER_I2CRPT, 0x22},*/ + {R367TER_TOPCTRL, 0x00},/* for xc5000; was 0x02 */ + {R367TER_IOCFG0, 0x40}, + {R367TER_DAC0R, 0x00}, + {R367TER_IOCFG1, 0x00}, + {R367TER_DAC1R, 0x00}, + {R367TER_IOCFG2, 0x62}, + {R367TER_SDFR, 0x00}, + {R367TER_STATUS, 0xf8}, + {R367TER_AUX_CLK, 0x0a}, + {R367TER_FREESYS1, 0x00}, + {R367TER_FREESYS2, 0x00}, + {R367TER_FREESYS3, 0x00}, + {R367TER_GPIO_CFG, 0x55}, + {R367TER_GPIO_CMD, 0x00}, + {R367TER_AGC2MAX, 0xff}, + {R367TER_AGC2MIN, 0x00}, + {R367TER_AGC1MAX, 0xff}, + {R367TER_AGC1MIN, 0x00}, + {R367TER_AGCR, 0xbc}, + {R367TER_AGC2TH, 0x00}, + {R367TER_AGC12C, 0x00}, + {R367TER_AGCCTRL1, 0x85}, + {R367TER_AGCCTRL2, 0x1f}, + {R367TER_AGC1VAL1, 0x00}, + {R367TER_AGC1VAL2, 0x00}, + {R367TER_AGC2VAL1, 0x6f}, + {R367TER_AGC2VAL2, 0x05}, + {R367TER_AGC2PGA, 0x00}, + {R367TER_OVF_RATE1, 0x00}, + {R367TER_OVF_RATE2, 0x00}, + {R367TER_GAIN_SRC1, 0xaa},/* for xc5000; was 0x2b */ + {R367TER_GAIN_SRC2, 0xd6},/* for xc5000; was 0x04 */ + {R367TER_INC_DEROT1, 0x55}, + {R367TER_INC_DEROT2, 0x55}, + {R367TER_PPM_CPAMP_DIR, 0x2c}, + {R367TER_PPM_CPAMP_INV, 0x00}, + {R367TER_FREESTFE_1, 0x00}, + {R367TER_FREESTFE_2, 0x1c}, + {R367TER_DCOFFSET, 0x00}, + {R367TER_EN_PROCESS, 0x05}, + {R367TER_SDI_SMOOTHER, 0x80}, + {R367TER_FE_LOOP_OPEN, 0x1c}, + {R367TER_FREQOFF1, 0x00}, + {R367TER_FREQOFF2, 0x00}, + {R367TER_FREQOFF3, 0x00}, + {R367TER_TIMOFF1, 0x00}, + {R367TER_TIMOFF2, 0x00}, + {R367TER_EPQ, 0x02}, + {R367TER_EPQAUTO, 0x01}, + {R367TER_SYR_UPDATE, 0xf5}, + {R367TER_CHPFREE, 0x00}, + {R367TER_PPM_STATE_MAC, 0x23}, + {R367TER_INR_THRESHOLD, 0xff}, + {R367TER_EPQ_TPS_ID_CELL, 0xf9}, + {R367TER_EPQ_CFG, 0x00}, + {R367TER_EPQ_STATUS, 0x01}, + {R367TER_AUTORELOCK, 0x81}, + {R367TER_BER_THR_VMSB, 0x00}, + {R367TER_BER_THR_MSB, 0x00}, + {R367TER_BER_THR_LSB, 0x00}, + {R367TER_CCD, 0x83}, + {R367TER_SPECTR_CFG, 0x00}, + {R367TER_CHC_DUMMY, 0x18}, + {R367TER_INC_CTL, 0x88}, + {R367TER_INCTHRES_COR1, 0xb4}, + {R367TER_INCTHRES_COR2, 0x96}, + {R367TER_INCTHRES_DET1, 0x0e}, + {R367TER_INCTHRES_DET2, 0x11}, + {R367TER_IIR_CELLNB, 0x8d}, + {R367TER_IIRCX_COEFF1_MSB, 0x00}, + {R367TER_IIRCX_COEFF1_LSB, 0x00}, + {R367TER_IIRCX_COEFF2_MSB, 0x09}, + {R367TER_IIRCX_COEFF2_LSB, 0x18}, + {R367TER_IIRCX_COEFF3_MSB, 0x14}, + {R367TER_IIRCX_COEFF3_LSB, 0x9c}, + {R367TER_IIRCX_COEFF4_MSB, 0x00}, + {R367TER_IIRCX_COEFF4_LSB, 0x00}, + {R367TER_IIRCX_COEFF5_MSB, 0x36}, + {R367TER_IIRCX_COEFF5_LSB, 0x42}, + {R367TER_FEPATH_CFG, 0x00}, + {R367TER_PMC1_FUNC, 0x65}, + {R367TER_PMC1_FOR, 0x00}, + {R367TER_PMC2_FUNC, 0x00}, + {R367TER_STATUS_ERR_DA, 0xe0}, + {R367TER_DIG_AGC_R, 0xfe}, + {R367TER_COMAGC_TARMSB, 0x0b}, + {R367TER_COM_AGC_TAR_ENMODE, 0x41}, + {R367TER_COM_AGC_CFG, 0x3e}, + {R367TER_COM_AGC_GAIN1, 0x39}, + {R367TER_AUT_AGC_TARGETMSB, 0x0b}, + {R367TER_LOCK_DET_MSB, 0x01}, + {R367TER_AGCTAR_LOCK_LSBS, 0x40}, + {R367TER_AUT_GAIN_EN, 0xf4}, + {R367TER_AUT_CFG, 0xf0}, + {R367TER_LOCKN, 0x23}, + {R367TER_INT_X_3, 0x00}, + {R367TER_INT_X_2, 0x03}, + {R367TER_INT_X_1, 0x8d}, + {R367TER_INT_X_0, 0xa0}, + {R367TER_MIN_ERRX_MSB, 0x00}, + {R367TER_COR_CTL, 0x23}, + {R367TER_COR_STAT, 0xf6}, + {R367TER_COR_INTEN, 0x00}, + {R367TER_COR_INTSTAT, 0x3f}, + {R367TER_COR_MODEGUARD, 0x03}, + {R367TER_AGC_CTL, 0x08}, + {R367TER_AGC_MANUAL1, 0x00}, + {R367TER_AGC_MANUAL2, 0x00}, + {R367TER_AGC_TARG, 0x16}, + {R367TER_AGC_GAIN1, 0x53}, + {R367TER_AGC_GAIN2, 0x1d}, + {R367TER_RESERVED_1, 0x00}, + {R367TER_RESERVED_2, 0x00}, + {R367TER_RESERVED_3, 0x00}, + {R367TER_CAS_CTL, 0x44}, + {R367TER_CAS_FREQ, 0xb3}, + {R367TER_CAS_DAGCGAIN, 0x12}, + {R367TER_SYR_CTL, 0x04}, + {R367TER_SYR_STAT, 0x10}, + {R367TER_SYR_NCO1, 0x00}, + {R367TER_SYR_NCO2, 0x00}, + {R367TER_SYR_OFFSET1, 0x00}, + {R367TER_SYR_OFFSET2, 0x00}, + {R367TER_FFT_CTL, 0x00}, + {R367TER_SCR_CTL, 0x70}, + {R367TER_PPM_CTL1, 0xf8}, + {R367TER_TRL_CTL, 0x14},/* for xc5000; was 0xac */ + {R367TER_TRL_NOMRATE1, 0xae},/* for xc5000; was 0x1e */ + {R367TER_TRL_NOMRATE2, 0x56},/* for xc5000; was 0x58 */ + {R367TER_TRL_TIME1, 0x1d}, + {R367TER_TRL_TIME2, 0xfc}, + {R367TER_CRL_CTL, 0x24}, + {R367TER_CRL_FREQ1, 0xad}, + {R367TER_CRL_FREQ2, 0x9d}, + {R367TER_CRL_FREQ3, 0xff}, + {R367TER_CHC_CTL, 0x01}, + {R367TER_CHC_SNR, 0xf0}, + {R367TER_BDI_CTL, 0x00}, + {R367TER_DMP_CTL, 0x00}, + {R367TER_TPS_RCVD1, 0x30}, + {R367TER_TPS_RCVD2, 0x02}, + {R367TER_TPS_RCVD3, 0x01}, + {R367TER_TPS_RCVD4, 0x00}, + {R367TER_TPS_ID_CELL1, 0x00}, + {R367TER_TPS_ID_CELL2, 0x00}, + {R367TER_TPS_RCVD5_SET1, 0x02}, + {R367TER_TPS_SET2, 0x02}, + {R367TER_TPS_SET3, 0x01}, + {R367TER_TPS_CTL, 0x00}, + {R367TER_CTL_FFTOSNUM, 0x34}, + {R367TER_TESTSELECT, 0x09}, + {R367TER_MSC_REV, 0x0a}, + {R367TER_PIR_CTL, 0x00}, + {R367TER_SNR_CARRIER1, 0xa1}, + {R367TER_SNR_CARRIER2, 0x9a}, + {R367TER_PPM_CPAMP, 0x2c}, + {R367TER_TSM_AP0, 0x00}, + {R367TER_TSM_AP1, 0x00}, + {R367TER_TSM_AP2 , 0x00}, + {R367TER_TSM_AP3, 0x00}, + {R367TER_TSM_AP4, 0x00}, + {R367TER_TSM_AP5, 0x00}, + {R367TER_TSM_AP6, 0x00}, + {R367TER_TSM_AP7, 0x00}, + {R367TER_TSTRES, 0x00}, + {R367TER_ANACTRL, 0x0D},/* PLL stoped, restart at init!!! */ + {R367TER_TSTBUS, 0x00}, + {R367TER_TSTRATE, 0x00}, + {R367TER_CONSTMODE, 0x01}, + {R367TER_CONSTCARR1, 0x00}, + {R367TER_CONSTCARR2, 0x00}, + {R367TER_ICONSTEL, 0x0a}, + {R367TER_QCONSTEL, 0x15}, + {R367TER_TSTBISTRES0, 0x00}, + {R367TER_TSTBISTRES1, 0x00}, + {R367TER_TSTBISTRES2, 0x28}, + {R367TER_TSTBISTRES3, 0x00}, + {R367TER_RF_AGC1, 0xff}, + {R367TER_RF_AGC2, 0x83}, + {R367TER_ANADIGCTRL, 0x19}, + {R367TER_PLLMDIV, 0x01},/* for xc5000; was 0x0c */ + {R367TER_PLLNDIV, 0x06},/* for xc5000; was 0x55 */ + {R367TER_PLLSETUP, 0x18}, + {R367TER_DUAL_AD12, 0x04},/* for xc5000; was 0x00 */ + {R367TER_TSTBIST, 0x00}, + {R367TER_PAD_COMP_CTRL, 0x00}, + {R367TER_PAD_COMP_WR, 0x00}, + {R367TER_PAD_COMP_RD, 0xe0}, + {R367TER_SYR_TARGET_FFTADJT_MSB, 0x00}, + {R367TER_SYR_TARGET_FFTADJT_LSB, 0x00}, + {R367TER_SYR_TARGET_CHCADJT_MSB, 0x00}, + {R367TER_SYR_TARGET_CHCADJT_LSB, 0x00}, + {R367TER_SYR_FLAG, 0x00}, + {R367TER_CRL_TARGET1, 0x00}, + {R367TER_CRL_TARGET2, 0x00}, + {R367TER_CRL_TARGET3, 0x00}, + {R367TER_CRL_TARGET4, 0x00}, + {R367TER_CRL_FLAG, 0x00}, + {R367TER_TRL_TARGET1, 0x00}, + {R367TER_TRL_TARGET2, 0x00}, + {R367TER_TRL_CHC, 0x00}, + {R367TER_CHC_SNR_TARG, 0x00}, + {R367TER_TOP_TRACK, 0x00}, + {R367TER_TRACKER_FREE1, 0x00}, + {R367TER_ERROR_CRL1, 0x00}, + {R367TER_ERROR_CRL2, 0x00}, + {R367TER_ERROR_CRL3, 0x00}, + {R367TER_ERROR_CRL4, 0x00}, + {R367TER_DEC_NCO1, 0x2c}, + {R367TER_DEC_NCO2, 0x0f}, + {R367TER_DEC_NCO3, 0x20}, + {R367TER_SNR, 0xf1}, + {R367TER_SYR_FFTADJ1, 0x00}, + {R367TER_SYR_FFTADJ2, 0x00}, + {R367TER_SYR_CHCADJ1, 0x00}, + {R367TER_SYR_CHCADJ2, 0x00}, + {R367TER_SYR_OFF, 0x00}, + {R367TER_PPM_OFFSET1, 0x00}, + {R367TER_PPM_OFFSET2, 0x03}, + {R367TER_TRACKER_FREE2, 0x00}, + {R367TER_DEBG_LT10, 0x00}, + {R367TER_DEBG_LT11, 0x00}, + {R367TER_DEBG_LT12, 0x00}, + {R367TER_DEBG_LT13, 0x00}, + {R367TER_DEBG_LT14, 0x00}, + {R367TER_DEBG_LT15, 0x00}, + {R367TER_DEBG_LT16, 0x00}, + {R367TER_DEBG_LT17, 0x00}, + {R367TER_DEBG_LT18, 0x00}, + {R367TER_DEBG_LT19, 0x00}, + {R367TER_DEBG_LT1A, 0x00}, + {R367TER_DEBG_LT1B, 0x00}, + {R367TER_DEBG_LT1C, 0x00}, + {R367TER_DEBG_LT1D, 0x00}, + {R367TER_DEBG_LT1E, 0x00}, + {R367TER_DEBG_LT1F, 0x00}, + {R367TER_RCCFGH, 0x00}, + {R367TER_RCCFGM, 0x00}, + {R367TER_RCCFGL, 0x00}, + {R367TER_RCINSDELH, 0x00}, + {R367TER_RCINSDELM, 0x00}, + {R367TER_RCINSDELL, 0x00}, + {R367TER_RCSTATUS, 0x00}, + {R367TER_RCSPEED, 0x6f}, + {R367TER_RCDEBUGM, 0xe7}, + {R367TER_RCDEBUGL, 0x9b}, + {R367TER_RCOBSCFG, 0x00}, + {R367TER_RCOBSM, 0x00}, + {R367TER_RCOBSL, 0x00}, + {R367TER_RCFECSPY, 0x00}, + {R367TER_RCFSPYCFG, 0x00}, + {R367TER_RCFSPYDATA, 0x00}, + {R367TER_RCFSPYOUT, 0x00}, + {R367TER_RCFSTATUS, 0x00}, + {R367TER_RCFGOODPACK, 0x00}, + {R367TER_RCFPACKCNT, 0x00}, + {R367TER_RCFSPYMISC, 0x00}, + {R367TER_RCFBERCPT4, 0x00}, + {R367TER_RCFBERCPT3, 0x00}, + {R367TER_RCFBERCPT2, 0x00}, + {R367TER_RCFBERCPT1, 0x00}, + {R367TER_RCFBERCPT0, 0x00}, + {R367TER_RCFBERERR2, 0x00}, + {R367TER_RCFBERERR1, 0x00}, + {R367TER_RCFBERERR0, 0x00}, + {R367TER_RCFSTATESM, 0x00}, + {R367TER_RCFSTATESL, 0x00}, + {R367TER_RCFSPYBER, 0x00}, + {R367TER_RCFSPYDISTM, 0x00}, + {R367TER_RCFSPYDISTL, 0x00}, + {R367TER_RCFSPYOBS7, 0x00}, + {R367TER_RCFSPYOBS6, 0x00}, + {R367TER_RCFSPYOBS5, 0x00}, + {R367TER_RCFSPYOBS4, 0x00}, + {R367TER_RCFSPYOBS3, 0x00}, + {R367TER_RCFSPYOBS2, 0x00}, + {R367TER_RCFSPYOBS1, 0x00}, + {R367TER_RCFSPYOBS0, 0x00}, + {R367TER_TSGENERAL, 0x00}, + {R367TER_RC1SPEED, 0x6f}, + {R367TER_TSGSTATUS, 0x18}, + {R367TER_FECM, 0x01}, + {R367TER_VTH12, 0xff}, + {R367TER_VTH23, 0xa1}, + {R367TER_VTH34, 0x64}, + {R367TER_VTH56, 0x40}, + {R367TER_VTH67, 0x00}, + {R367TER_VTH78, 0x2c}, + {R367TER_VITCURPUN, 0x12}, + {R367TER_VERROR, 0x01}, + {R367TER_PRVIT, 0x3f}, + {R367TER_VAVSRVIT, 0x00}, + {R367TER_VSTATUSVIT, 0xbd}, + {R367TER_VTHINUSE, 0xa1}, + {R367TER_KDIV12, 0x20}, + {R367TER_KDIV23, 0x40}, + {R367TER_KDIV34, 0x20}, + {R367TER_KDIV56, 0x30}, + {R367TER_KDIV67, 0x00}, + {R367TER_KDIV78, 0x30}, + {R367TER_SIGPOWER, 0x54}, + {R367TER_DEMAPVIT, 0x40}, + {R367TER_VITSCALE, 0x00}, + {R367TER_FFEC1PRG, 0x00}, + {R367TER_FVITCURPUN, 0x12}, + {R367TER_FVERROR, 0x01}, + {R367TER_FVSTATUSVIT, 0xbd}, + {R367TER_DEBUG_LT1, 0x00}, + {R367TER_DEBUG_LT2, 0x00}, + {R367TER_DEBUG_LT3, 0x00}, + {R367TER_TSTSFMET, 0x00}, + {R367TER_SELOUT, 0x00}, + {R367TER_TSYNC, 0x00}, + {R367TER_TSTERR, 0x00}, + {R367TER_TSFSYNC, 0x00}, + {R367TER_TSTSFERR, 0x00}, + {R367TER_TSTTSSF1, 0x01}, + {R367TER_TSTTSSF2, 0x1f}, + {R367TER_TSTTSSF3, 0x00}, + {R367TER_TSTTS1, 0x00}, + {R367TER_TSTTS2, 0x1f}, + {R367TER_TSTTS3, 0x01}, + {R367TER_TSTTS4, 0x00}, + {R367TER_TSTTSRC, 0x00}, + {R367TER_TSTTSRS, 0x00}, + {R367TER_TSSTATEM, 0xb0}, + {R367TER_TSSTATEL, 0x40}, + {R367TER_TSCFGH, 0xC0}, + {R367TER_TSCFGM, 0xc0},/* for xc5000; was 0x00 */ + {R367TER_TSCFGL, 0x20}, + {R367TER_TSSYNC, 0x00}, + {R367TER_TSINSDELH, 0x00}, + {R367TER_TSINSDELM, 0x00}, + {R367TER_TSINSDELL, 0x00}, + {R367TER_TSDIVN, 0x03}, + {R367TER_TSDIVPM, 0x00}, + {R367TER_TSDIVPL, 0x00}, + {R367TER_TSDIVQM, 0x00}, + {R367TER_TSDIVQL, 0x00}, + {R367TER_TSDILSTKM, 0x00}, + {R367TER_TSDILSTKL, 0x00}, + {R367TER_TSSPEED, 0x40},/* for xc5000; was 0x6f */ + {R367TER_TSSTATUS, 0x81}, + {R367TER_TSSTATUS2, 0x6a}, + {R367TER_TSBITRATEM, 0x0f}, + {R367TER_TSBITRATEL, 0xc6}, + {R367TER_TSPACKLENM, 0x00}, + {R367TER_TSPACKLENL, 0xfc}, + {R367TER_TSBLOCLENM, 0x0a}, + {R367TER_TSBLOCLENL, 0x80}, + {R367TER_TSDLYH, 0x90}, + {R367TER_TSDLYM, 0x68}, + {R367TER_TSDLYL, 0x01}, + {R367TER_TSNPDAV, 0x00}, + {R367TER_TSBUFSTATH, 0x00}, + {R367TER_TSBUFSTATM, 0x00}, + {R367TER_TSBUFSTATL, 0x00}, + {R367TER_TSDEBUGM, 0xcf}, + {R367TER_TSDEBUGL, 0x1e}, + {R367TER_TSDLYSETH, 0x00}, + {R367TER_TSDLYSETM, 0x68}, + {R367TER_TSDLYSETL, 0x00}, + {R367TER_TSOBSCFG, 0x00}, + {R367TER_TSOBSM, 0x47}, + {R367TER_TSOBSL, 0x1f}, + {R367TER_ERRCTRL1, 0x95}, + {R367TER_ERRCNT1H, 0x80}, + {R367TER_ERRCNT1M, 0x00}, + {R367TER_ERRCNT1L, 0x00}, + {R367TER_ERRCTRL2, 0x95}, + {R367TER_ERRCNT2H, 0x00}, + {R367TER_ERRCNT2M, 0x00}, + {R367TER_ERRCNT2L, 0x00}, + {R367TER_FECSPY, 0x88}, + {R367TER_FSPYCFG, 0x2c}, + {R367TER_FSPYDATA, 0x3a}, + {R367TER_FSPYOUT, 0x06}, + {R367TER_FSTATUS, 0x61}, + {R367TER_FGOODPACK, 0xff}, + {R367TER_FPACKCNT, 0xff}, + {R367TER_FSPYMISC, 0x66}, + {R367TER_FBERCPT4, 0x00}, + {R367TER_FBERCPT3, 0x00}, + {R367TER_FBERCPT2, 0x36}, + {R367TER_FBERCPT1, 0x36}, + {R367TER_FBERCPT0, 0x14}, + {R367TER_FBERERR2, 0x00}, + {R367TER_FBERERR1, 0x03}, + {R367TER_FBERERR0, 0x28}, + {R367TER_FSTATESM, 0x00}, + {R367TER_FSTATESL, 0x02}, + {R367TER_FSPYBER, 0x00}, + {R367TER_FSPYDISTM, 0x01}, + {R367TER_FSPYDISTL, 0x9f}, + {R367TER_FSPYOBS7, 0xc9}, + {R367TER_FSPYOBS6, 0x99}, + {R367TER_FSPYOBS5, 0x08}, + {R367TER_FSPYOBS4, 0xec}, + {R367TER_FSPYOBS3, 0x01}, + {R367TER_FSPYOBS2, 0x0f}, + {R367TER_FSPYOBS1, 0xf5}, + {R367TER_FSPYOBS0, 0x08}, + {R367TER_SFDEMAP, 0x40}, + {R367TER_SFERROR, 0x00}, + {R367TER_SFAVSR, 0x30}, + {R367TER_SFECSTATUS, 0xcc}, + {R367TER_SFKDIV12, 0x20}, + {R367TER_SFKDIV23, 0x40}, + {R367TER_SFKDIV34, 0x20}, + {R367TER_SFKDIV56, 0x20}, + {R367TER_SFKDIV67, 0x00}, + {R367TER_SFKDIV78, 0x20}, + {R367TER_SFDILSTKM, 0x00}, + {R367TER_SFDILSTKL, 0x00}, + {R367TER_SFSTATUS, 0xb5}, + {R367TER_SFDLYH, 0x90}, + {R367TER_SFDLYM, 0x60}, + {R367TER_SFDLYL, 0x01}, + {R367TER_SFDLYSETH, 0xc0}, + {R367TER_SFDLYSETM, 0x60}, + {R367TER_SFDLYSETL, 0x00}, + {R367TER_SFOBSCFG, 0x00}, + {R367TER_SFOBSM, 0x47}, + {R367TER_SFOBSL, 0x05}, + {R367TER_SFECINFO, 0x40}, + {R367TER_SFERRCTRL, 0x74}, + {R367TER_SFERRCNTH, 0x80}, + {R367TER_SFERRCNTM , 0x00}, + {R367TER_SFERRCNTL, 0x00}, + {R367TER_SYMBRATEM, 0x2f}, + {R367TER_SYMBRATEL, 0x50}, + {R367TER_SYMBSTATUS, 0x7f}, + {R367TER_SYMBCFG, 0x00}, + {R367TER_SYMBFIFOM, 0xf4}, + {R367TER_SYMBFIFOL, 0x0d}, + {R367TER_SYMBOFFSM, 0xf0}, + {R367TER_SYMBOFFSL, 0x2d}, + {R367TER_DEBUG_LT4, 0x00}, + {R367TER_DEBUG_LT5, 0x00}, + {R367TER_DEBUG_LT6, 0x00}, + {R367TER_DEBUG_LT7, 0x00}, + {R367TER_DEBUG_LT8, 0x00}, + {R367TER_DEBUG_LT9, 0x00}, +}; + +#define RF_LOOKUP_TABLE_SIZE 31 +#define RF_LOOKUP_TABLE2_SIZE 16 +/* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/ +s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { + {/*AGC1*/ + 48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 80, 83, 85, 88, + }, {/*RF(dbm)*/ + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 46, 47, + 49, 50, 52, 53, 54, 55, 56, + } +}; +/* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/ +s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = { + {/*AGC2*/ + 28, 29, 31, 32, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, + }, {/*RF(dbm)*/ + 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, + } +}; + +static struct st_register def0367cab[STV0367CAB_NBREGS] = { + {R367CAB_ID, 0x60}, + {R367CAB_I2CRPT, 0xa0}, + /*{R367CAB_I2CRPT, 0x22},*/ + {R367CAB_TOPCTRL, 0x10}, + {R367CAB_IOCFG0, 0x80}, + {R367CAB_DAC0R, 0x00}, + {R367CAB_IOCFG1, 0x00}, + {R367CAB_DAC1R, 0x00}, + {R367CAB_IOCFG2, 0x00}, + {R367CAB_SDFR, 0x00}, + {R367CAB_AUX_CLK, 0x00}, + {R367CAB_FREESYS1, 0x00}, + {R367CAB_FREESYS2, 0x00}, + {R367CAB_FREESYS3, 0x00}, + {R367CAB_GPIO_CFG, 0x55}, + {R367CAB_GPIO_CMD, 0x01}, + {R367CAB_TSTRES, 0x00}, + {R367CAB_ANACTRL, 0x0d},/* was 0x00 need to check - I.M.L.*/ + {R367CAB_TSTBUS, 0x00}, + {R367CAB_RF_AGC1, 0xea}, + {R367CAB_RF_AGC2, 0x82}, + {R367CAB_ANADIGCTRL, 0x0b}, + {R367CAB_PLLMDIV, 0x01}, + {R367CAB_PLLNDIV, 0x08}, + {R367CAB_PLLSETUP, 0x18}, + {R367CAB_DUAL_AD12, 0x04}, + {R367CAB_TSTBIST, 0x00}, + {R367CAB_CTRL_1, 0x00}, + {R367CAB_CTRL_2, 0x03}, + {R367CAB_IT_STATUS1, 0x2b}, + {R367CAB_IT_STATUS2, 0x08}, + {R367CAB_IT_EN1, 0x00}, + {R367CAB_IT_EN2, 0x00}, + {R367CAB_CTRL_STATUS, 0x04}, + {R367CAB_TEST_CTL, 0x00}, + {R367CAB_AGC_CTL, 0x73}, + {R367CAB_AGC_IF_CFG, 0x50}, + {R367CAB_AGC_RF_CFG, 0x00}, + {R367CAB_AGC_PWM_CFG, 0x03}, + {R367CAB_AGC_PWR_REF_L, 0x5a}, + {R367CAB_AGC_PWR_REF_H, 0x00}, + {R367CAB_AGC_RF_TH_L, 0xff}, + {R367CAB_AGC_RF_TH_H, 0x07}, + {R367CAB_AGC_IF_LTH_L, 0x00}, + {R367CAB_AGC_IF_LTH_H, 0x08}, + {R367CAB_AGC_IF_HTH_L, 0xff}, + {R367CAB_AGC_IF_HTH_H, 0x07}, + {R367CAB_AGC_PWR_RD_L, 0xa0}, + {R367CAB_AGC_PWR_RD_M, 0xe9}, + {R367CAB_AGC_PWR_RD_H, 0x03}, + {R367CAB_AGC_PWM_IFCMD_L, 0xe4}, + {R367CAB_AGC_PWM_IFCMD_H, 0x00}, + {R367CAB_AGC_PWM_RFCMD_L, 0xff}, + {R367CAB_AGC_PWM_RFCMD_H, 0x07}, + {R367CAB_IQDEM_CFG, 0x01}, + {R367CAB_MIX_NCO_LL, 0x22}, + {R367CAB_MIX_NCO_HL, 0x96}, + {R367CAB_MIX_NCO_HH, 0x55}, + {R367CAB_SRC_NCO_LL, 0xff}, + {R367CAB_SRC_NCO_LH, 0x0c}, + {R367CAB_SRC_NCO_HL, 0xf5}, + {R367CAB_SRC_NCO_HH, 0x20}, + {R367CAB_IQDEM_GAIN_SRC_L, 0x06}, + {R367CAB_IQDEM_GAIN_SRC_H, 0x01}, + {R367CAB_IQDEM_DCRM_CFG_LL, 0xfe}, + {R367CAB_IQDEM_DCRM_CFG_LH, 0xff}, + {R367CAB_IQDEM_DCRM_CFG_HL, 0x0f}, + {R367CAB_IQDEM_DCRM_CFG_HH, 0x00}, + {R367CAB_IQDEM_ADJ_COEFF0, 0x34}, + {R367CAB_IQDEM_ADJ_COEFF1, 0xae}, + {R367CAB_IQDEM_ADJ_COEFF2, 0x46}, + {R367CAB_IQDEM_ADJ_COEFF3, 0x77}, + {R367CAB_IQDEM_ADJ_COEFF4, 0x96}, + {R367CAB_IQDEM_ADJ_COEFF5, 0x69}, + {R367CAB_IQDEM_ADJ_COEFF6, 0xc7}, + {R367CAB_IQDEM_ADJ_COEFF7, 0x01}, + {R367CAB_IQDEM_ADJ_EN, 0x04}, + {R367CAB_IQDEM_ADJ_AGC_REF, 0x94}, + {R367CAB_ALLPASSFILT1, 0xc9}, + {R367CAB_ALLPASSFILT2, 0x2d}, + {R367CAB_ALLPASSFILT3, 0xa3}, + {R367CAB_ALLPASSFILT4, 0xfb}, + {R367CAB_ALLPASSFILT5, 0xf6}, + {R367CAB_ALLPASSFILT6, 0x45}, + {R367CAB_ALLPASSFILT7, 0x6f}, + {R367CAB_ALLPASSFILT8, 0x7e}, + {R367CAB_ALLPASSFILT9, 0x05}, + {R367CAB_ALLPASSFILT10, 0x0a}, + {R367CAB_ALLPASSFILT11, 0x51}, + {R367CAB_TRL_AGC_CFG, 0x20}, + {R367CAB_TRL_LPF_CFG, 0x28}, + {R367CAB_TRL_LPF_ACQ_GAIN, 0x44}, + {R367CAB_TRL_LPF_TRK_GAIN, 0x22}, + {R367CAB_TRL_LPF_OUT_GAIN, 0x03}, + {R367CAB_TRL_LOCKDET_LTH, 0x04}, + {R367CAB_TRL_LOCKDET_HTH, 0x11}, + {R367CAB_TRL_LOCKDET_TRGVAL, 0x20}, + {R367CAB_IQ_QAM, 0x01}, + {R367CAB_FSM_STATE, 0xa0}, + {R367CAB_FSM_CTL, 0x08}, + {R367CAB_FSM_STS, 0x0c}, + {R367CAB_FSM_SNR0_HTH, 0x00}, + {R367CAB_FSM_SNR1_HTH, 0x00}, + {R367CAB_FSM_SNR2_HTH, 0x23},/* 0x00 */ + {R367CAB_FSM_SNR0_LTH, 0x00}, + {R367CAB_FSM_SNR1_LTH, 0x00}, + {R367CAB_FSM_EQA1_HTH, 0x00}, + {R367CAB_FSM_TEMPO, 0x32}, + {R367CAB_FSM_CONFIG, 0x03}, + {R367CAB_EQU_I_TESTTAP_L, 0x11}, + {R367CAB_EQU_I_TESTTAP_M, 0x00}, + {R367CAB_EQU_I_TESTTAP_H, 0x00}, + {R367CAB_EQU_TESTAP_CFG, 0x00}, + {R367CAB_EQU_Q_TESTTAP_L, 0xff}, + {R367CAB_EQU_Q_TESTTAP_M, 0x00}, + {R367CAB_EQU_Q_TESTTAP_H, 0x00}, + {R367CAB_EQU_TAP_CTRL, 0x00}, + {R367CAB_EQU_CTR_CRL_CONTROL_L, 0x11}, + {R367CAB_EQU_CTR_CRL_CONTROL_H, 0x05}, + {R367CAB_EQU_CTR_HIPOW_L, 0x00}, + {R367CAB_EQU_CTR_HIPOW_H, 0x00}, + {R367CAB_EQU_I_EQU_LO, 0xef}, + {R367CAB_EQU_I_EQU_HI, 0x00}, + {R367CAB_EQU_Q_EQU_LO, 0xee}, + {R367CAB_EQU_Q_EQU_HI, 0x00}, + {R367CAB_EQU_MAPPER, 0xc5}, + {R367CAB_EQU_SWEEP_RATE, 0x80}, + {R367CAB_EQU_SNR_LO, 0x64}, + {R367CAB_EQU_SNR_HI, 0x03}, + {R367CAB_EQU_GAMMA_LO, 0x00}, + {R367CAB_EQU_GAMMA_HI, 0x00}, + {R367CAB_EQU_ERR_GAIN, 0x36}, + {R367CAB_EQU_RADIUS, 0xaa}, + {R367CAB_EQU_FFE_MAINTAP, 0x00}, + {R367CAB_EQU_FFE_LEAKAGE, 0x63}, + {R367CAB_EQU_FFE_MAINTAP_POS, 0xdf}, + {R367CAB_EQU_GAIN_WIDE, 0x88}, + {R367CAB_EQU_GAIN_NARROW, 0x41}, + {R367CAB_EQU_CTR_LPF_GAIN, 0xd1}, + {R367CAB_EQU_CRL_LPF_GAIN, 0xa7}, + {R367CAB_EQU_GLOBAL_GAIN, 0x06}, + {R367CAB_EQU_CRL_LD_SEN, 0x85}, + {R367CAB_EQU_CRL_LD_VAL, 0xe2}, + {R367CAB_EQU_CRL_TFR, 0x20}, + {R367CAB_EQU_CRL_BISTH_LO, 0x00}, + {R367CAB_EQU_CRL_BISTH_HI, 0x00}, + {R367CAB_EQU_SWEEP_RANGE_LO, 0x00}, + {R367CAB_EQU_SWEEP_RANGE_HI, 0x00}, + {R367CAB_EQU_CRL_LIMITER, 0x40}, + {R367CAB_EQU_MODULUS_MAP, 0x90}, + {R367CAB_EQU_PNT_GAIN, 0xa7}, + {R367CAB_FEC_AC_CTR_0, 0x16}, + {R367CAB_FEC_AC_CTR_1, 0x0b}, + {R367CAB_FEC_AC_CTR_2, 0x88}, + {R367CAB_FEC_AC_CTR_3, 0x02}, + {R367CAB_FEC_STATUS, 0x12}, + {R367CAB_RS_COUNTER_0, 0x7d}, + {R367CAB_RS_COUNTER_1, 0xd0}, + {R367CAB_RS_COUNTER_2, 0x19}, + {R367CAB_RS_COUNTER_3, 0x0b}, + {R367CAB_RS_COUNTER_4, 0xa3}, + {R367CAB_RS_COUNTER_5, 0x00}, + {R367CAB_BERT_0, 0x01}, + {R367CAB_BERT_1, 0x25}, + {R367CAB_BERT_2, 0x41}, + {R367CAB_BERT_3, 0x39}, + {R367CAB_OUTFORMAT_0, 0xc2}, + {R367CAB_OUTFORMAT_1, 0x22}, + {R367CAB_SMOOTHER_2, 0x28}, + {R367CAB_TSMF_CTRL_0, 0x01}, + {R367CAB_TSMF_CTRL_1, 0xc6}, + {R367CAB_TSMF_CTRL_3, 0x43}, + {R367CAB_TS_ON_ID_0, 0x00}, + {R367CAB_TS_ON_ID_1, 0x00}, + {R367CAB_TS_ON_ID_2, 0x00}, + {R367CAB_TS_ON_ID_3, 0x00}, + {R367CAB_RE_STATUS_0, 0x00}, + {R367CAB_RE_STATUS_1, 0x00}, + {R367CAB_RE_STATUS_2, 0x00}, + {R367CAB_RE_STATUS_3, 0x00}, + {R367CAB_TS_STATUS_0, 0x00}, + {R367CAB_TS_STATUS_1, 0x00}, + {R367CAB_TS_STATUS_2, 0xa0}, + {R367CAB_TS_STATUS_3, 0x00}, + {R367CAB_T_O_ID_0, 0x00}, + {R367CAB_T_O_ID_1, 0x00}, + {R367CAB_T_O_ID_2, 0x00}, + {R367CAB_T_O_ID_3, 0x00}, +}; + +static +int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len) +{ + u8 buf[len + 2]; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = len + 2 + }; + int ret; + + buf[0] = MSB(reg); + buf[1] = LSB(reg); + memcpy(buf + 2, data, len); + + if (i2cdebug) + printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, buf[2]); + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + printk(KERN_ERR "%s: i2c write error!\n", __func__); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int stv0367_writereg(struct stv0367_state *state, u16 reg, u8 data) +{ + return stv0367_writeregs(state, reg, &data, 1); +} + +static u8 stv0367_readreg(struct stv0367_state *state, u16 reg) +{ + u8 b0[] = { 0, 0 }; + u8 b1[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 2 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + int ret; + + b0[0] = MSB(reg); + b0[1] = LSB(reg); + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + printk(KERN_ERR "%s: i2c read error\n", __func__); + + if (i2cdebug) + printk(KERN_DEBUG "%s: %02x: %02x\n", __func__, reg, b1[0]); + + return b1[0]; +} + +static void extract_mask_pos(u32 label, u8 *mask, u8 *pos) +{ + u8 position = 0, i = 0; + + (*mask) = label & 0xff; + + while ((position == 0) && (i < 8)) { + position = ((*mask) >> i) & 0x01; + i++; + } + + (*pos) = (i - 1); +} + +static void stv0367_writebits(struct stv0367_state *state, u32 label, u8 val) +{ + u8 reg, mask, pos; + + reg = stv0367_readreg(state, (label >> 16) & 0xffff); + extract_mask_pos(label, &mask, &pos); + + val = mask & (val << pos); + + reg = (reg & (~mask)) | val; + stv0367_writereg(state, (label >> 16) & 0xffff, reg); + +} + +static void stv0367_setbits(u8 *reg, u32 label, u8 val) +{ + u8 mask, pos; + + extract_mask_pos(label, &mask, &pos); + + val = mask & (val << pos); + + (*reg) = ((*reg) & (~mask)) | val; +} + +static u8 stv0367_readbits(struct stv0367_state *state, u32 label) +{ + u8 val = 0xff; + u8 mask, pos; + + extract_mask_pos(label, &mask, &pos); + + val = stv0367_readreg(state, label >> 16); + val = (val & mask) >> pos; + + return val; +} + +u8 stv0367_getbits(u8 reg, u32 label) +{ + u8 mask, pos; + + extract_mask_pos(label, &mask, &pos); + + return (reg & mask) >> pos; +} + +static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0367_state *state = fe->demodulator_priv; + u8 tmp = stv0367_readreg(state, R367TER_I2CRPT); + + dprintk("%s:\n", __func__); + + if (enable) { + stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 0); + stv0367_setbits(&tmp, F367TER_I2CT_ON, 1); + } else { + stv0367_setbits(&tmp, F367TER_STOP_ENABLE, 1); + stv0367_setbits(&tmp, F367TER_I2CT_ON, 0); + } + + stv0367_writereg(state, R367TER_I2CRPT, tmp); + + return 0; +} + +static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe) +{ + struct dvb_frontend_ops *frontend_ops = NULL; + struct dvb_tuner_ops *tuner_ops = NULL; + u32 freq = 0; + u32 err = 0; + + dprintk("%s:\n", __func__); + + + if (&fe->ops) + frontend_ops = &fe->ops; + if (&frontend_ops->tuner_ops) + tuner_ops = &frontend_ops->tuner_ops; + if (tuner_ops->get_frequency) { + err = tuner_ops->get_frequency(fe, &freq); + if (err < 0) { + printk(KERN_ERR "%s: Invalid parameter\n", __func__); + return err; + } + + dprintk("%s: frequency=%d\n", __func__, freq); + + } else + return -1; + + return freq; +} + +static u16 CellsCoeffs_8MHz_367cofdm[3][6][5] = { + { + {0x10EF, 0xE205, 0x10EF, 0xCE49, 0x6DA7}, /* CELL 1 COEFFS 27M*/ + {0x2151, 0xc557, 0x2151, 0xc705, 0x6f93}, /* CELL 2 COEFFS */ + {0x2503, 0xc000, 0x2503, 0xc375, 0x7194}, /* CELL 3 COEFFS */ + {0x20E9, 0xca94, 0x20e9, 0xc153, 0x7194}, /* CELL 4 COEFFS */ + {0x06EF, 0xF852, 0x06EF, 0xC057, 0x7207}, /* CELL 5 COEFFS */ + {0x0000, 0x0ECC, 0x0ECC, 0x0000, 0x3647} /* CELL 6 COEFFS */ + }, { + {0x10A0, 0xE2AF, 0x10A1, 0xCE76, 0x6D6D}, /* CELL 1 COEFFS 25M*/ + {0x20DC, 0xC676, 0x20D9, 0xC80A, 0x6F29}, + {0x2532, 0xC000, 0x251D, 0xC391, 0x706F}, + {0x1F7A, 0xCD2B, 0x2032, 0xC15E, 0x711F}, + {0x0698, 0xFA5E, 0x0568, 0xC059, 0x7193}, + {0x0000, 0x0918, 0x149C, 0x0000, 0x3642} /* CELL 6 COEFFS */ + }, { + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} + } +}; + +static u16 CellsCoeffs_7MHz_367cofdm[3][6][5] = { + { + {0x12CA, 0xDDAF, 0x12CA, 0xCCEB, 0x6FB1}, /* CELL 1 COEFFS 27M*/ + {0x2329, 0xC000, 0x2329, 0xC6B0, 0x725F}, /* CELL 2 COEFFS */ + {0x2394, 0xC000, 0x2394, 0xC2C7, 0x7410}, /* CELL 3 COEFFS */ + {0x251C, 0xC000, 0x251C, 0xC103, 0x74D9}, /* CELL 4 COEFFS */ + {0x0804, 0xF546, 0x0804, 0xC040, 0x7544}, /* CELL 5 COEFFS */ + {0x0000, 0x0CD9, 0x0CD9, 0x0000, 0x370A} /* CELL 6 COEFFS */ + }, { + {0x1285, 0xDE47, 0x1285, 0xCD17, 0x6F76}, /*25M*/ + {0x234C, 0xC000, 0x2348, 0xC6DA, 0x7206}, + {0x23B4, 0xC000, 0x23AC, 0xC2DB, 0x73B3}, + {0x253D, 0xC000, 0x25B6, 0xC10B, 0x747F}, + {0x0721, 0xF79C, 0x065F, 0xC041, 0x74EB}, + {0x0000, 0x08FA, 0x1162, 0x0000, 0x36FF} + }, { + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} + } +}; + +static u16 CellsCoeffs_6MHz_367cofdm[3][6][5] = { + { + {0x1699, 0xD5B8, 0x1699, 0xCBC3, 0x713B}, /* CELL 1 COEFFS 27M*/ + {0x2245, 0xC000, 0x2245, 0xC568, 0x74D5}, /* CELL 2 COEFFS */ + {0x227F, 0xC000, 0x227F, 0xC1FC, 0x76C6}, /* CELL 3 COEFFS */ + {0x235E, 0xC000, 0x235E, 0xC0A7, 0x778A}, /* CELL 4 COEFFS */ + {0x0ECB, 0xEA0B, 0x0ECB, 0xC027, 0x77DD}, /* CELL 5 COEFFS */ + {0x0000, 0x0B68, 0x0B68, 0x0000, 0xC89A}, /* CELL 6 COEFFS */ + }, { + {0x1655, 0xD64E, 0x1658, 0xCBEF, 0x70FE}, /*25M*/ + {0x225E, 0xC000, 0x2256, 0xC589, 0x7489}, + {0x2293, 0xC000, 0x2295, 0xC209, 0x767E}, + {0x2377, 0xC000, 0x23AA, 0xC0AB, 0x7746}, + {0x0DC7, 0xEBC8, 0x0D07, 0xC027, 0x7799}, + {0x0000, 0x0888, 0x0E9C, 0x0000, 0x3757} + + }, { + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /* 30M */ + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, + {0x0000, 0x0000, 0x0000, 0x0000, 0x0000} + } +}; + +static u32 stv0367ter_get_mclk(struct stv0367_state *state, u32 ExtClk_Hz) +{ + u32 mclk_Hz = 0; /* master clock frequency (Hz) */ + u32 m, n, p; + + dprintk("%s:\n", __func__); + + if (stv0367_readbits(state, F367TER_BYPASS_PLLXN) == 0) { + n = (u32)stv0367_readbits(state, F367TER_PLL_NDIV); + if (n == 0) + n = n + 1; + + m = (u32)stv0367_readbits(state, F367TER_PLL_MDIV); + if (m == 0) + m = m + 1; + + p = (u32)stv0367_readbits(state, F367TER_PLL_PDIV); + if (p > 5) + p = 5; + + mclk_Hz = ((ExtClk_Hz / 2) * n) / (m * (1 << p)); + + dprintk("N=%d M=%d P=%d mclk_Hz=%d ExtClk_Hz=%d\n", + n, m, p, mclk_Hz, ExtClk_Hz); + } else + mclk_Hz = ExtClk_Hz; + + dprintk("%s: mclk_Hz=%d\n", __func__, mclk_Hz); + + return mclk_Hz; +} + +static int stv0367ter_filt_coeff_init(struct stv0367_state *state, + u16 CellsCoeffs[2][6][5], u32 DemodXtal) +{ + int i, j, k, freq; + + dprintk("%s:\n", __func__); + + freq = stv0367ter_get_mclk(state, DemodXtal); + + if (freq == 53125000) + k = 1; /* equivalent to Xtal 25M on 362*/ + else if (freq == 54000000) + k = 0; /* equivalent to Xtal 27M on 362*/ + else if (freq == 52500000) + k = 2; /* equivalent to Xtal 30M on 362*/ + else + return 0; + + for (i = 1; i <= 6; i++) { + stv0367_writebits(state, F367TER_IIR_CELL_NB, i - 1); + + for (j = 1; j <= 5; j++) { + stv0367_writereg(state, + (R367TER_IIRCX_COEFF1_MSB + 2 * (j - 1)), + MSB(CellsCoeffs[k][i-1][j-1])); + stv0367_writereg(state, + (R367TER_IIRCX_COEFF1_LSB + 2 * (j - 1)), + LSB(CellsCoeffs[k][i-1][j-1])); + } + } + + return 1; + +} + +static void stv0367ter_agc_iir_lock_detect_set(struct stv0367_state *state) +{ + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367TER_LOCK_DETECT_LSB, 0x00); + + /* Lock detect 1 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x00); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04); + + /* Lock detect 2 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x01); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x06); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x04); + + /* Lock detect 3 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x02); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00); + + /* Lock detect 4 */ + stv0367_writebits(state, F367TER_LOCK_DETECT_CHOICE, 0x03); + stv0367_writebits(state, F367TER_LOCK_DETECT_MSB, 0x01); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_LSB, 0x00); + +} + +static int stv0367_iir_filt_init(struct stv0367_state *state, u8 Bandwidth, + u32 DemodXtalValue) +{ + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367TER_NRST_IIR, 0); + + switch (Bandwidth) { + case 6: + if (!stv0367ter_filt_coeff_init(state, + CellsCoeffs_6MHz_367cofdm, + DemodXtalValue)) + return 0; + break; + case 7: + if (!stv0367ter_filt_coeff_init(state, + CellsCoeffs_7MHz_367cofdm, + DemodXtalValue)) + return 0; + break; + case 8: + if (!stv0367ter_filt_coeff_init(state, + CellsCoeffs_8MHz_367cofdm, + DemodXtalValue)) + return 0; + break; + default: + return 0; + } + + stv0367_writebits(state, F367TER_NRST_IIR, 1); + + return 1; +} + +static void stv0367ter_agc_iir_rst(struct stv0367_state *state) +{ + + u8 com_n; + + dprintk("%s:\n", __func__); + + com_n = stv0367_readbits(state, F367TER_COM_N); + + stv0367_writebits(state, F367TER_COM_N, 0x07); + + stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x00); + stv0367_writebits(state, F367TER_COM_AGC_ON, 0x00); + + stv0367_writebits(state, F367TER_COM_SOFT_RSTN, 0x01); + stv0367_writebits(state, F367TER_COM_AGC_ON, 0x01); + + stv0367_writebits(state, F367TER_COM_N, com_n); + +} + +static int stv0367ter_duration(s32 mode, int tempo1, int tempo2, int tempo3) +{ + int local_tempo = 0; + switch (mode) { + case 0: + local_tempo = tempo1; + break; + case 1: + local_tempo = tempo2; + break ; + + case 2: + local_tempo = tempo3; + break; + + default: + break; + } + /* msleep(local_tempo); */ + return local_tempo; +} + +static enum +stv0367_ter_signal_type stv0367ter_check_syr(struct stv0367_state *state) +{ + int wd = 100; + unsigned short int SYR_var; + s32 SYRStatus; + + dprintk("%s:\n", __func__); + + SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK); + + while ((!SYR_var) && (wd > 0)) { + usleep_range(2000, 3000); + wd -= 2; + SYR_var = stv0367_readbits(state, F367TER_SYR_LOCK); + } + + if (!SYR_var) + SYRStatus = FE_TER_NOSYMBOL; + else + SYRStatus = FE_TER_SYMBOLOK; + + dprintk("stv0367ter_check_syr SYRStatus %s\n", + SYR_var == 0 ? "No Symbol" : "OK"); + + return SYRStatus; +} + +static enum +stv0367_ter_signal_type stv0367ter_check_cpamp(struct stv0367_state *state, + s32 FFTmode) +{ + + s32 CPAMPvalue = 0, CPAMPStatus, CPAMPMin; + int wd = 0; + + dprintk("%s:\n", __func__); + + switch (FFTmode) { + case 0: /*2k mode*/ + CPAMPMin = 20; + wd = 10; + break; + case 1: /*8k mode*/ + CPAMPMin = 80; + wd = 55; + break; + case 2: /*4k mode*/ + CPAMPMin = 40; + wd = 30; + break; + default: + CPAMPMin = 0xffff; /*drives to NOCPAMP */ + break; + } + + dprintk("%s: CPAMPMin=%d wd=%d\n", __func__, CPAMPMin, wd); + + CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT); + while ((CPAMPvalue < CPAMPMin) && (wd > 0)) { + usleep_range(1000, 2000); + wd -= 1; + CPAMPvalue = stv0367_readbits(state, F367TER_PPM_CPAMP_DIRECT); + /*dprintk("CPAMPvalue= %d at wd=%d\n",CPAMPvalue,wd); */ + } + dprintk("******last CPAMPvalue= %d at wd=%d\n", CPAMPvalue, wd); + if (CPAMPvalue < CPAMPMin) { + CPAMPStatus = FE_TER_NOCPAMP; + printk(KERN_ERR "CPAMP failed\n"); + } else { + printk(KERN_ERR "CPAMP OK !\n"); + CPAMPStatus = FE_TER_CPAMPOK; + } + + return CPAMPStatus; +} + +enum +stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state) +{ + enum stv0367_ter_signal_type ret_flag; + short int wd, tempo; + u8 try, u_var1 = 0, u_var2 = 0, u_var3 = 0, u_var4 = 0, mode, guard; + u8 tmp, tmp2; + + dprintk("%s:\n", __func__); + + if (state == NULL) + return FE_TER_SWNOK; + + try = 0; + do { + ret_flag = FE_TER_LOCKOK; + + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + + if (state->config->if_iq_mode != 0) + stv0367_writebits(state, F367TER_COM_N, 0x07); + + stv0367_writebits(state, F367TER_GUARD, 3);/* suggest 2k 1/4 */ + stv0367_writebits(state, F367TER_MODE, 0); + stv0367_writebits(state, F367TER_SYR_TR_DIS, 0); + usleep_range(5000, 10000); + + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + + + if (stv0367ter_check_syr(state) == FE_TER_NOSYMBOL) + return FE_TER_NOSYMBOL; + else { /* + if chip locked on wrong mode first try, + it must lock correctly second try */ + mode = stv0367_readbits(state, F367TER_SYR_MODE); + if (stv0367ter_check_cpamp(state, mode) == + FE_TER_NOCPAMP) { + if (try == 0) + ret_flag = FE_TER_NOCPAMP; + + } + } + + try++; + } while ((try < 10) && (ret_flag != FE_TER_LOCKOK)); + + tmp = stv0367_readreg(state, R367TER_SYR_STAT); + tmp2 = stv0367_readreg(state, R367TER_STATUS); + dprintk("state=0x%x\n", (int)state); + dprintk("LOCK OK! mode=%d SYR_STAT=0x%x R367TER_STATUS=0x%x\n", + mode, tmp, tmp2); + + tmp = stv0367_readreg(state, R367TER_PRVIT); + tmp2 = stv0367_readreg(state, R367TER_I2CRPT); + dprintk("PRVIT=0x%x I2CRPT=0x%x\n", tmp, tmp2); + + tmp = stv0367_readreg(state, R367TER_GAIN_SRC1); + dprintk("GAIN_SRC1=0x%x\n", tmp); + + if ((mode != 0) && (mode != 1) && (mode != 2)) + return FE_TER_SWNOK; + + /*guard=stv0367_readbits(state,F367TER_SYR_GUARD); */ + + /*supress EPQ auto for SYR_GARD 1/16 or 1/32 + and set channel predictor in automatic */ +#if 0 + switch (guard) { + + case 0: + case 1: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 0); + stv0367_writereg(state, R367TER_CHC_CTL, 0x01); + break; + case 2: + case 3: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 1); + stv0367_writereg(state, R367TER_CHC_CTL, 0x11); + break; + + default: + return FE_TER_SWNOK; + } +#endif + + /*reset fec an reedsolo FOR 367 only*/ + stv0367_writebits(state, F367TER_RST_SFEC, 1); + stv0367_writebits(state, F367TER_RST_REEDSOLO, 1); + usleep_range(1000, 2000); + stv0367_writebits(state, F367TER_RST_SFEC, 0); + stv0367_writebits(state, F367TER_RST_REEDSOLO, 0); + + u_var1 = stv0367_readbits(state, F367TER_LK); + u_var2 = stv0367_readbits(state, F367TER_PRF); + u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK); + /* u_var4=stv0367_readbits(state,F367TER_TSFIFO_LINEOK); */ + + wd = stv0367ter_duration(mode, 125, 500, 250); + tempo = stv0367ter_duration(mode, 4, 16, 8); + + /*while ( ((!u_var1)||(!u_var2)||(!u_var3)||(!u_var4)) && (wd>=0)) */ + while (((!u_var1) || (!u_var2) || (!u_var3)) && (wd >= 0)) { + usleep_range(1000 * tempo, 1000 * (tempo + 1)); + wd -= tempo; + u_var1 = stv0367_readbits(state, F367TER_LK); + u_var2 = stv0367_readbits(state, F367TER_PRF); + u_var3 = stv0367_readbits(state, F367TER_TPS_LOCK); + /*u_var4=stv0367_readbits(state, F367TER_TSFIFO_LINEOK); */ + } + + if (!u_var1) + return FE_TER_NOLOCK; + + + if (!u_var2) + return FE_TER_NOPRFOUND; + + if (!u_var3) + return FE_TER_NOTPS; + + guard = stv0367_readbits(state, F367TER_SYR_GUARD); + stv0367_writereg(state, R367TER_CHC_CTL, 0x11); + switch (guard) { + case 0: + case 1: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 0); + /*stv0367_writereg(state,R367TER_CHC_CTL, 0x1);*/ + stv0367_writebits(state, F367TER_SYR_FILTER, 0); + break; + case 2: + case 3: + stv0367_writebits(state, F367TER_AUTO_LE_EN, 1); + /*stv0367_writereg(state,R367TER_CHC_CTL, 0x11);*/ + stv0367_writebits(state, F367TER_SYR_FILTER, 1); + break; + + default: + return FE_TER_SWNOK; + } + + /* apply Sfec workaround if 8K 64QAM CR!=1/2*/ + if ((stv0367_readbits(state, F367TER_TPS_CONST) == 2) && + (mode == 1) && + (stv0367_readbits(state, F367TER_TPS_HPCODE) != 0)) { + stv0367_writereg(state, R367TER_SFDLYSETH, 0xc0); + stv0367_writereg(state, R367TER_SFDLYSETM, 0x60); + stv0367_writereg(state, R367TER_SFDLYSETL, 0x0); + } else + stv0367_writereg(state, R367TER_SFDLYSETH, 0x0); + + wd = stv0367ter_duration(mode, 125, 500, 250); + u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK); + + while ((!u_var4) && (wd >= 0)) { + usleep_range(1000 * tempo, 1000 * (tempo + 1)); + wd -= tempo; + u_var4 = stv0367_readbits(state, F367TER_TSFIFO_LINEOK); + } + + if (!u_var4) + return FE_TER_NOLOCK; + + /* for 367 leave COM_N at 0x7 for IQ_mode*/ + /*if(ter_state->if_iq_mode!=FE_TER_NORMAL_IF_TUNER) { + tempo=0; + while ((stv0367_readbits(state,F367TER_COM_USEGAINTRK)!=1) && + (stv0367_readbits(state,F367TER_COM_AGCLOCK)!=1)&&(tempo<100)) { + ChipWaitOrAbort(state,1); + tempo+=1; + } + + stv0367_writebits(state,F367TER_COM_N,0x17); + } */ + + stv0367_writebits(state, F367TER_SYR_TR_DIS, 1); + + dprintk("FE_TER_LOCKOK !!!\n"); + + return FE_TER_LOCKOK; + +} + +static void stv0367ter_set_ts_mode(struct stv0367_state *state, + enum stv0367_ts_mode PathTS) +{ + + dprintk("%s:\n", __func__); + + if (state == NULL) + return; + + stv0367_writebits(state, F367TER_TS_DIS, 0); + switch (PathTS) { + default: + /*for removing warning :default we can assume in parallel mode*/ + case STV0367_PARALLEL_PUNCT_CLOCK: + stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 0); + stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 0); + break; + case STV0367_SERIAL_PUNCT_CLOCK: + stv0367_writebits(state, F367TER_TSFIFO_SERIAL, 1); + stv0367_writebits(state, F367TER_TSFIFO_DVBCI, 1); + break; + } +} + +static void stv0367ter_set_clk_pol(struct stv0367_state *state, + enum stv0367_clk_pol clock) +{ + + dprintk("%s:\n", __func__); + + if (state == NULL) + return; + + switch (clock) { + case STV0367_RISINGEDGE_CLOCK: + stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 1); + break; + case STV0367_FALLINGEDGE_CLOCK: + stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0); + break; + /*case FE_TER_CLOCK_POLARITY_DEFAULT:*/ + default: + stv0367_writebits(state, F367TER_TS_BYTE_CLK_INV, 0); + break; + } +} + +#if 0 +static void stv0367ter_core_sw(struct stv0367_state *state) +{ + + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + msleep(350); +} +#endif +static int stv0367ter_standby(struct dvb_frontend *fe, u8 standby_on) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + if (standby_on) { + stv0367_writebits(state, F367TER_STDBY, 1); + stv0367_writebits(state, F367TER_STDBY_FEC, 1); + stv0367_writebits(state, F367TER_STDBY_CORE, 1); + } else { + stv0367_writebits(state, F367TER_STDBY, 0); + stv0367_writebits(state, F367TER_STDBY_FEC, 0); + stv0367_writebits(state, F367TER_STDBY_CORE, 0); + } + + return 0; +} + +static int stv0367ter_sleep(struct dvb_frontend *fe) +{ + return stv0367ter_standby(fe, 1); +} + +int stv0367ter_init(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + int i; + + dprintk("%s:\n", __func__); + + ter_state->pBER = 0; + + for (i = 0; i < STV0367TER_NBREGS; i++) + stv0367_writereg(state, def0367ter[i].addr, + def0367ter[i].value); + + switch (state->config->xtal) { + /*set internal freq to 53.125MHz */ + case 25000000: + stv0367_writereg(state, R367TER_PLLMDIV, 0xa); + stv0367_writereg(state, R367TER_PLLNDIV, 0x55); + stv0367_writereg(state, R367TER_PLLSETUP, 0x18); + break; + default: + case 27000000: + dprintk("FE_STV0367TER_SetCLKgen for 27Mhz\n"); + stv0367_writereg(state, R367TER_PLLMDIV, 0x1); + stv0367_writereg(state, R367TER_PLLNDIV, 0x8); + stv0367_writereg(state, R367TER_PLLSETUP, 0x18); + break; + case 30000000: + stv0367_writereg(state, R367TER_PLLMDIV, 0xc); + stv0367_writereg(state, R367TER_PLLNDIV, 0x55); + stv0367_writereg(state, R367TER_PLLSETUP, 0x18); + break; + } + + stv0367_writereg(state, R367TER_I2CRPT, 0xa0); + stv0367_writereg(state, R367TER_ANACTRL, 0x00); + + /*Set TS1 and TS2 to serial or parallel mode */ + stv0367ter_set_ts_mode(state, state->config->ts_mode); + stv0367ter_set_clk_pol(state, state->config->clk_pol); + + state->chip_id = stv0367_readreg(state, R367TER_ID); + ter_state->first_lock = 0; + ter_state->unlock_counter = 2; + + return 0; +} + +static int stv0367ter_algo(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + int offset = 0, tempo = 0; + u8 u_var; + u8 /*constell,*/ counter, tps_rcvd[2]; + s8 step; + s32 timing_offset = 0; + u32 trl_nomrate = 0, InternalFreq = 0, temp = 0; + + dprintk("%s:\n", __func__); + + ter_state->frequency = param->frequency; + ter_state->force = FE_TER_FORCENONE + + stv0367_readbits(state, F367TER_FORCE) * 2; + ter_state->if_iq_mode = state->config->if_iq_mode; + switch (state->config->if_iq_mode) { + case FE_TER_NORMAL_IF_TUNER: /* Normal IF mode */ + dprintk("ALGO: FE_TER_NORMAL_IF_TUNER selected\n"); + stv0367_writebits(state, F367TER_TUNER_BB, 0); + stv0367_writebits(state, F367TER_LONGPATH_IF, 0); + stv0367_writebits(state, F367TER_DEMUX_SWAP, 0); + break; + case FE_TER_LONGPATH_IF_TUNER: /* Long IF mode */ + dprintk("ALGO: FE_TER_LONGPATH_IF_TUNER selected\n"); + stv0367_writebits(state, F367TER_TUNER_BB, 0); + stv0367_writebits(state, F367TER_LONGPATH_IF, 1); + stv0367_writebits(state, F367TER_DEMUX_SWAP, 1); + break; + case FE_TER_IQ_TUNER: /* IQ mode */ + dprintk("ALGO: FE_TER_IQ_TUNER selected\n"); + stv0367_writebits(state, F367TER_TUNER_BB, 1); + stv0367_writebits(state, F367TER_PPM_INVSEL, 0); + break; + default: + printk(KERN_ERR "ALGO: wrong TUNER type selected\n"); + return -EINVAL; + } + + usleep_range(5000, 7000); + + switch (param->inversion) { + case INVERSION_AUTO: + default: + dprintk("%s: inversion AUTO\n", __func__); + if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) + stv0367_writebits(state, F367TER_IQ_INVERT, + ter_state->sense); + else + stv0367_writebits(state, F367TER_INV_SPECTR, + ter_state->sense); + + break; + case INVERSION_ON: + case INVERSION_OFF: + if (ter_state->if_iq_mode == FE_TER_IQ_TUNER) + stv0367_writebits(state, F367TER_IQ_INVERT, + param->inversion); + else + stv0367_writebits(state, F367TER_INV_SPECTR, + param->inversion); + + break; + } + + if ((ter_state->if_iq_mode != FE_TER_NORMAL_IF_TUNER) && + (ter_state->pBW != ter_state->bw)) { + stv0367ter_agc_iir_lock_detect_set(state); + + /*set fine agc target to 180 for LPIF or IQ mode*/ + /* set Q_AGCTarget */ + stv0367_writebits(state, F367TER_SEL_IQNTAR, 1); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB); + /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */ + + /* set Q_AGCTarget */ + stv0367_writebits(state, F367TER_SEL_IQNTAR, 0); + stv0367_writebits(state, F367TER_AUT_AGC_TARGET_MSB, 0xB); + /*stv0367_writebits(state,AUT_AGC_TARGET_LSB,0x04); */ + + if (!stv0367_iir_filt_init(state, ter_state->bw, + state->config->xtal)) + return -EINVAL; + /*set IIR filter once for 6,7 or 8MHz BW*/ + ter_state->pBW = ter_state->bw; + + stv0367ter_agc_iir_rst(state); + } + + if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO) + stv0367_writebits(state, F367TER_BDI_LPSEL, 0x01); + else + stv0367_writebits(state, F367TER_BDI_LPSEL, 0x00); + + InternalFreq = stv0367ter_get_mclk(state, state->config->xtal) / 1000; + temp = (int) + ((((ter_state->bw * 64 * (1 << 15) * 100) + / (InternalFreq)) * 10) / 7); + + stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, temp % 2); + temp = temp / 2; + stv0367_writebits(state, F367TER_TRL_NOMRATE_HI, temp / 256); + stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, temp % 256); + + temp = stv0367_readbits(state, F367TER_TRL_NOMRATE_HI) * 512 + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB); + temp = (int)(((1 << 17) * ter_state->bw * 1000) / (7 * (InternalFreq))); + stv0367_writebits(state, F367TER_GAIN_SRC_HI, temp / 256); + stv0367_writebits(state, F367TER_GAIN_SRC_LO, temp % 256); + temp = stv0367_readbits(state, F367TER_GAIN_SRC_HI) * 256 + + stv0367_readbits(state, F367TER_GAIN_SRC_LO); + + temp = (int) + ((InternalFreq - state->config->if_khz) * (1 << 16) + / (InternalFreq)); + + dprintk("DEROT temp=0x%x\n", temp); + stv0367_writebits(state, F367TER_INC_DEROT_HI, temp / 256); + stv0367_writebits(state, F367TER_INC_DEROT_LO, temp % 256); + + ter_state->echo_pos = 0; + ter_state->ucblocks = 0; /* liplianin */ + ter_state->pBER = 0; /* liplianin */ + stv0367_writebits(state, F367TER_LONG_ECHO, ter_state->echo_pos); + + if (stv0367ter_lock_algo(state) != FE_TER_LOCKOK) + return 0; + + ter_state->state = FE_TER_LOCKOK; + /* update results */ + tps_rcvd[0] = stv0367_readreg(state, R367TER_TPS_RCVD2); + tps_rcvd[1] = stv0367_readreg(state, R367TER_TPS_RCVD3); + + ter_state->mode = stv0367_readbits(state, F367TER_SYR_MODE); + ter_state->guard = stv0367_readbits(state, F367TER_SYR_GUARD); + + ter_state->first_lock = 1; /* we know sense now :) */ + + ter_state->agc_val = + (stv0367_readbits(state, F367TER_AGC1_VAL_LO) << 16) + + (stv0367_readbits(state, F367TER_AGC1_VAL_HI) << 24) + + stv0367_readbits(state, F367TER_AGC2_VAL_LO) + + (stv0367_readbits(state, F367TER_AGC2_VAL_HI) << 8); + + /* Carrier offset calculation */ + stv0367_writebits(state, F367TER_FREEZE, 1); + offset = (stv0367_readbits(state, F367TER_CRL_FOFFSET_VHI) << 16) ; + offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_HI) << 8); + offset += (stv0367_readbits(state, F367TER_CRL_FOFFSET_LO)); + stv0367_writebits(state, F367TER_FREEZE, 0); + if (offset > 8388607) + offset -= 16777216; + + offset = offset * 2 / 16384; + + if (ter_state->mode == FE_TER_MODE_2K) + offset = (offset * 4464) / 1000;/*** 1 FFT BIN=4.464khz***/ + else if (ter_state->mode == FE_TER_MODE_4K) + offset = (offset * 223) / 100;/*** 1 FFT BIN=2.23khz***/ + else if (ter_state->mode == FE_TER_MODE_8K) + offset = (offset * 111) / 100;/*** 1 FFT BIN=1.1khz***/ + + if (stv0367_readbits(state, F367TER_PPM_INVSEL) == 1) { + if ((stv0367_readbits(state, F367TER_INV_SPECTR) == + (stv0367_readbits(state, + F367TER_STATUS_INV_SPECRUM) == 1))) + offset = offset * -1; + } + + if (ter_state->bw == 6) + offset = (offset * 6) / 8; + else if (ter_state->bw == 7) + offset = (offset * 7) / 8; + + ter_state->frequency += offset; + + tempo = 10; /* exit even if timing_offset stays null */ + while ((timing_offset == 0) && (tempo > 0)) { + usleep_range(10000, 20000); /*was 20ms */ + /* fine tuning of timing offset if required */ + timing_offset = stv0367_readbits(state, F367TER_TRL_TOFFSET_LO) + + 256 * stv0367_readbits(state, + F367TER_TRL_TOFFSET_HI); + if (timing_offset >= 32768) + timing_offset -= 65536; + trl_nomrate = (512 * stv0367_readbits(state, + F367TER_TRL_NOMRATE_HI) + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LO) * 2 + + stv0367_readbits(state, F367TER_TRL_NOMRATE_LSB)); + + timing_offset = ((signed)(1000000 / trl_nomrate) * + timing_offset) / 2048; + tempo--; + } + + if (timing_offset <= 0) { + timing_offset = (timing_offset - 11) / 22; + step = -1; + } else { + timing_offset = (timing_offset + 11) / 22; + step = 1; + } + + for (counter = 0; counter < abs(timing_offset); counter++) { + trl_nomrate += step; + stv0367_writebits(state, F367TER_TRL_NOMRATE_LSB, + trl_nomrate % 2); + stv0367_writebits(state, F367TER_TRL_NOMRATE_LO, + trl_nomrate / 2); + usleep_range(1000, 2000); + } + + usleep_range(5000, 6000); + /* unlocks could happen in case of trl centring big step, + then a core off/on restarts demod */ + u_var = stv0367_readbits(state, F367TER_LK); + + if (!u_var) { + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + msleep(20); + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + } + + return 0; +} + +static int stv0367ter_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + + /*u8 trials[2]; */ + s8 num_trials, index; + u8 SenseTrials[] = { INVERSION_ON, INVERSION_OFF }; + + stv0367ter_init(fe); + + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + switch (op->transmission_mode) { + default: + case TRANSMISSION_MODE_AUTO: + case TRANSMISSION_MODE_2K: + ter_state->mode = FE_TER_MODE_2K; + break; +/* case TRANSMISSION_MODE_4K: + pLook.mode = FE_TER_MODE_4K; + break;*/ + case TRANSMISSION_MODE_8K: + ter_state->mode = FE_TER_MODE_8K; + break; + } + + switch (op->guard_interval) { + default: + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_1_16: + case GUARD_INTERVAL_1_8: + case GUARD_INTERVAL_1_4: + ter_state->guard = op->guard_interval; + break; + case GUARD_INTERVAL_AUTO: + ter_state->guard = GUARD_INTERVAL_1_32; + break; + } + + switch (op->bandwidth) { + case BANDWIDTH_6_MHZ: + ter_state->bw = FE_TER_CHAN_BW_6M; + break; + case BANDWIDTH_7_MHZ: + ter_state->bw = FE_TER_CHAN_BW_7M; + break; + case BANDWIDTH_8_MHZ: + default: + ter_state->bw = FE_TER_CHAN_BW_8M; + } + + ter_state->hierarchy = FE_TER_HIER_NONE; + + switch (param->inversion) { + case INVERSION_OFF: + case INVERSION_ON: + num_trials = 1; + break; + default: + num_trials = 2; + if (ter_state->first_lock) + num_trials = 1; + break; + } + + ter_state->state = FE_TER_NOLOCK; + index = 0; + + while (((index) < num_trials) && (ter_state->state != FE_TER_LOCKOK)) { + if (!ter_state->first_lock) { + if (param->inversion == INVERSION_AUTO) + ter_state->sense = SenseTrials[index]; + + } + stv0367ter_algo(fe,/* &pLook, result,*/ param); + + if ((ter_state->state == FE_TER_LOCKOK) && + (param->inversion == INVERSION_AUTO) && + (index == 1)) { + /* invert spectrum sense */ + SenseTrials[index] = SenseTrials[0]; + SenseTrials[(index + 1) % 2] = (SenseTrials[1] + 1) % 2; + } + + index++; + } + + return 0; +} + +static int stv0367ter_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + u32 errs = 0; + + /*wait for counting completion*/ + if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) { + errs = + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1) + * (1 << 16)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI) + * (1 << 8)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO)); + ter_state->ucblocks = errs; + } + + (*ucblocks) = ter_state->ucblocks; + + return 0; +} + +static int stv0367ter_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + int error = 0; + enum stv0367_ter_mode mode; + int constell = 0,/* snr = 0,*/ Data = 0; + + param->frequency = stv0367_get_tuner_freq(fe); + if (param->frequency < 0) + param->frequency = c->frequency; + + constell = stv0367_readbits(state, F367TER_TPS_CONST); + if (constell == 0) + op->constellation = QPSK; + else if (constell == 1) + op->constellation = QAM_16; + else + op->constellation = QAM_64; + + param->inversion = stv0367_readbits(state, F367TER_INV_SPECTR); + + /* Get the Hierarchical mode */ + Data = stv0367_readbits(state, F367TER_TPS_HIERMODE); + + switch (Data) { + case 0: + op->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + op->hierarchy_information = HIERARCHY_1; + break; + case 2: + op->hierarchy_information = HIERARCHY_2; + break; + case 3: + op->hierarchy_information = HIERARCHY_4; + break; + default: + op->hierarchy_information = HIERARCHY_AUTO; + break; /* error */ + } + + /* Get the FEC Rate */ + if (ter_state->hierarchy == FE_TER_HIER_LOW_PRIO) + Data = stv0367_readbits(state, F367TER_TPS_LPCODE); + else + Data = stv0367_readbits(state, F367TER_TPS_HPCODE); + + switch (Data) { + case 0: + op->code_rate_HP = FEC_1_2; + break; + case 1: + op->code_rate_HP = FEC_2_3; + break; + case 2: + op->code_rate_HP = FEC_3_4; + break; + case 3: + op->code_rate_HP = FEC_5_6; + break; + case 4: + op->code_rate_HP = FEC_7_8; + break; + default: + op->code_rate_HP = FEC_AUTO; + break; /* error */ + } + + mode = stv0367_readbits(state, F367TER_SYR_MODE); + + switch (mode) { + case FE_TER_MODE_2K: + op->transmission_mode = TRANSMISSION_MODE_2K; + break; +/* case FE_TER_MODE_4K: + op->transmission_mode = TRANSMISSION_MODE_4K; + break;*/ + case FE_TER_MODE_8K: + op->transmission_mode = TRANSMISSION_MODE_8K; + break; + default: + op->transmission_mode = TRANSMISSION_MODE_AUTO; + } + + op->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); + + return error; +} + +static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 snru32 = 0; + int cpt = 0; + u8 cut = stv0367_readbits(state, F367TER_IDENTIFICATIONREG); + + while (cpt < 10) { + usleep_range(2000, 3000); + if (cut == 0x50) /*cut 1.0 cut 1.1*/ + snru32 += stv0367_readbits(state, F367TER_CHCSNR) / 4; + else /*cu2.0*/ + snru32 += 125 * stv0367_readbits(state, F367TER_CHCSNR); + + cpt++; + } + + snru32 /= 10;/*average on 10 values*/ + + *snr = snru32 / 1000; + + return 0; +} + +#if 0 +static int stv0367ter_status(struct dvb_frontend *fe) +{ + + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + int locked = FALSE; + + locked = (stv0367_readbits(state, F367TER_LK)); + if (!locked) + ter_state->unlock_counter += 1; + else + ter_state->unlock_counter = 0; + + if (ter_state->unlock_counter > 2) { + if (!stv0367_readbits(state, F367TER_TPS_LOCK) || + (!stv0367_readbits(state, F367TER_LK))) { + stv0367_writebits(state, F367TER_CORE_ACTIVE, 0); + usleep_range(2000, 3000); + stv0367_writebits(state, F367TER_CORE_ACTIVE, 1); + msleep(350); + locked = (stv0367_readbits(state, F367TER_TPS_LOCK)) && + (stv0367_readbits(state, F367TER_LK)); + } + + } + + return locked; +} +#endif +static int stv0367ter_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + *status = 0; + + if (stv0367_readbits(state, F367TER_LK)) { + *status |= FE_HAS_LOCK; + dprintk("%s: stv0367 has locked\n", __func__); + } + + return 0; +} + +static int stv0367ter_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367ter_state *ter_state = state->ter_state; + u32 Errors = 0, tber = 0, temporary = 0; + int abc = 0, def = 0; + + + /*wait for counting completion*/ + if (stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 0) + Errors = ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT) + * (1 << 16)) + + ((u32)stv0367_readbits(state, F367TER_SFEC_ERR_CNT_HI) + * (1 << 8)) + + ((u32)stv0367_readbits(state, + F367TER_SFEC_ERR_CNT_LO)); + /*measurement not completed, load previous value*/ + else { + tber = ter_state->pBER; + return 0; + } + + abc = stv0367_readbits(state, F367TER_SFEC_ERR_SOURCE); + def = stv0367_readbits(state, F367TER_SFEC_NUM_EVENT); + + if (Errors == 0) { + tber = 0; + } else if (abc == 0x7) { + if (Errors <= 4) { + temporary = (Errors * 1000000000) / (8 * (1 << 14)); + temporary = temporary; + } else if (Errors <= 42) { + temporary = (Errors * 100000000) / (8 * (1 << 14)); + temporary = temporary * 10; + } else if (Errors <= 429) { + temporary = (Errors * 10000000) / (8 * (1 << 14)); + temporary = temporary * 100; + } else if (Errors <= 4294) { + temporary = (Errors * 1000000) / (8 * (1 << 14)); + temporary = temporary * 1000; + } else if (Errors <= 42949) { + temporary = (Errors * 100000) / (8 * (1 << 14)); + temporary = temporary * 10000; + } else if (Errors <= 429496) { + temporary = (Errors * 10000) / (8 * (1 << 14)); + temporary = temporary * 100000; + } else { /*if (Errors<4294967) 2^22 max error*/ + temporary = (Errors * 1000) / (8 * (1 << 14)); + temporary = temporary * 100000; /* still to *10 */ + } + + /* Byte error*/ + if (def == 2) + /*tber=Errors/(8*(1 <<14));*/ + tber = temporary; + else if (def == 3) + /*tber=Errors/(8*(1 <<16));*/ + tber = temporary / 4; + else if (def == 4) + /*tber=Errors/(8*(1 <<18));*/ + tber = temporary / 16; + else if (def == 5) + /*tber=Errors/(8*(1 <<20));*/ + tber = temporary / 64; + else if (def == 6) + /*tber=Errors/(8*(1 <<22));*/ + tber = temporary / 256; + else + /* should not pass here*/ + tber = 0; + + if ((Errors < 4294967) && (Errors > 429496)) + tber *= 10; + + } + + /* save actual value */ + ter_state->pBER = tber; + + (*ber) = tber; + + return 0; +} +#if 0 +static u32 stv0367ter_get_per(struct stv0367_state *state) +{ + struct stv0367ter_state *ter_state = state->ter_state; + u32 Errors = 0, Per = 0, temporary = 0; + int abc = 0, def = 0, cpt = 0; + + while (((stv0367_readbits(state, F367TER_SFERRC_OLDVALUE) == 1) && + (cpt < 400)) || ((Errors == 0) && (cpt < 400))) { + usleep_range(1000, 2000); + Errors = ((u32)stv0367_readbits(state, F367TER_ERR_CNT1) + * (1 << 16)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_HI) + * (1 << 8)) + + ((u32)stv0367_readbits(state, F367TER_ERR_CNT1_LO)); + cpt++; + } + abc = stv0367_readbits(state, F367TER_ERR_SRC1); + def = stv0367_readbits(state, F367TER_NUM_EVT1); + + if (Errors == 0) + Per = 0; + else if (abc == 0x9) { + if (Errors <= 4) { + temporary = (Errors * 1000000000) / (8 * (1 << 8)); + temporary = temporary; + } else if (Errors <= 42) { + temporary = (Errors * 100000000) / (8 * (1 << 8)); + temporary = temporary * 10; + } else if (Errors <= 429) { + temporary = (Errors * 10000000) / (8 * (1 << 8)); + temporary = temporary * 100; + } else if (Errors <= 4294) { + temporary = (Errors * 1000000) / (8 * (1 << 8)); + temporary = temporary * 1000; + } else if (Errors <= 42949) { + temporary = (Errors * 100000) / (8 * (1 << 8)); + temporary = temporary * 10000; + } else { /*if(Errors<=429496) 2^16 errors max*/ + temporary = (Errors * 10000) / (8 * (1 << 8)); + temporary = temporary * 100000; + } + + /* pkt error*/ + if (def == 2) + /*Per=Errors/(1 << 8);*/ + Per = temporary; + else if (def == 3) + /*Per=Errors/(1 << 10);*/ + Per = temporary / 4; + else if (def == 4) + /*Per=Errors/(1 << 12);*/ + Per = temporary / 16; + else if (def == 5) + /*Per=Errors/(1 << 14);*/ + Per = temporary / 64; + else if (def == 6) + /*Per=Errors/(1 << 16);*/ + Per = temporary / 256; + else + Per = 0; + + } + /* save actual value */ + ter_state->pPER = Per; + + return Per; +} +#endif +static int stv0367_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings + *fe_tune_settings) +{ + fe_tune_settings->min_delay_ms = 1000; + fe_tune_settings->step_size = 0; + fe_tune_settings->max_drift = 0; + + return 0; +} + +static void stv0367_release(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + + kfree(state->ter_state); + kfree(state->cab_state); + kfree(state); +} + +static struct dvb_frontend_ops stv0367ter_ops = { + .info = { + .name = "ST STV0367 DVB-T", + .type = FE_OFDM, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_stepsize = 15625, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | + FE_CAN_INVERSION_AUTO | + FE_CAN_MUTE_TS + }, + .release = stv0367_release, + .init = stv0367ter_init, + .sleep = stv0367ter_sleep, + .i2c_gate_ctrl = stv0367ter_gate_ctrl, + .set_frontend = stv0367ter_set_frontend, + .get_frontend = stv0367ter_get_frontend, + .get_tune_settings = stv0367_get_tune_settings, + .read_status = stv0367ter_read_status, + .read_ber = stv0367ter_read_ber,/* too slow */ +/* .read_signal_strength = stv0367_read_signal_strength,*/ + .read_snr = stv0367ter_read_snr, + .read_ucblocks = stv0367ter_read_ucblocks, +}; + +struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + struct stv0367_state *state = NULL; + struct stv0367ter_state *ter_state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL); + if (state == NULL) + goto error; + ter_state = kzalloc(sizeof(struct stv0367ter_state), GFP_KERNEL); + if (ter_state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + state->config = config; + state->ter_state = ter_state; + state->fe.ops = stv0367ter_ops; + state->fe.demodulator_priv = state; + state->chip_id = stv0367_readreg(state, 0xf000); + + dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id); + + /* check if the demod is there */ + if ((state->chip_id != 0x50) && (state->chip_id != 0x60)) + goto error; + + return &state->fe; + +error: + kfree(ter_state); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stv0367ter_attach); + +static int stv0367cab_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + stv0367_writebits(state, F367CAB_I2CT_ON, (enable > 0) ? 1 : 0); + + return 0; +} + +static u32 stv0367cab_get_mclk(struct dvb_frontend *fe, u32 ExtClk_Hz) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 mclk_Hz = 0;/* master clock frequency (Hz) */ + u32 M, N, P; + + + if (stv0367_readbits(state, F367CAB_BYPASS_PLLXN) == 0) { + N = (u32)stv0367_readbits(state, F367CAB_PLL_NDIV); + if (N == 0) + N = N + 1; + + M = (u32)stv0367_readbits(state, F367CAB_PLL_MDIV); + if (M == 0) + M = M + 1; + + P = (u32)stv0367_readbits(state, F367CAB_PLL_PDIV); + + if (P > 5) + P = 5; + + mclk_Hz = ((ExtClk_Hz / 2) * N) / (M * (1 << P)); + dprintk("stv0367cab_get_mclk BYPASS_PLLXN mclk_Hz=%d\n", + mclk_Hz); + } else + mclk_Hz = ExtClk_Hz; + + dprintk("stv0367cab_get_mclk final mclk_Hz=%d\n", mclk_Hz); + + return mclk_Hz; +} + +static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz) +{ + u32 ADCClk_Hz = ExtClk_Hz; + + ADCClk_Hz = stv0367cab_get_mclk(fe, ExtClk_Hz); + + return ADCClk_Hz; +} + +enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state, + u32 SymbolRate, + enum stv0367cab_mod QAMSize) +{ + /* Set QAM size */ + stv0367_writebits(state, F367CAB_QAM_MODE, QAMSize); + + /* Set Registers settings specific to the QAM size */ + switch (QAMSize) { + case FE_CAB_MOD_QAM4: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + break; + case FE_CAB_MOD_QAM16: + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x64); + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + stv0367_writereg(state, R367CAB_FSM_STATE, 0x90); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x8a); + break; + case FE_CAB_MOD_QAM32: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x6e); + stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xb7); + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x9d); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); + break; + case FE_CAB_MOD_QAM64: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x82); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a); + if (SymbolRate > 45000000) { + stv0367_writereg(state, R367CAB_FSM_STATE, 0xb0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa5); + } else if (SymbolRate > 25000000) { + stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6); + } else { + stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1); + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + } + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x95); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0x99); + break; + case FE_CAB_MOD_QAM128: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x76); + stv0367_writereg(state, R367CAB_FSM_STATE, 0x90); + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xb1); + if (SymbolRate > 45000000) + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + else if (SymbolRate > 25000000) + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa6); + else + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0x97); + + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x8e); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x7f); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); + break; + case FE_CAB_MOD_QAM256: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x94); + stv0367_writereg(state, R367CAB_AGC_PWR_REF_L, 0x5a); + stv0367_writereg(state, R367CAB_FSM_STATE, 0xa0); + if (SymbolRate > 45000000) + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + else if (SymbolRate > 25000000) + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xc1); + else + stv0367_writereg(state, R367CAB_EQU_CTR_LPF_GAIN, 0xd1); + + stv0367_writereg(state, R367CAB_EQU_CRL_LPF_GAIN, 0xa7); + stv0367_writereg(state, R367CAB_EQU_CRL_LD_SEN, 0x85); + stv0367_writereg(state, R367CAB_EQU_CRL_LIMITER, 0x40); + stv0367_writereg(state, R367CAB_EQU_PNT_GAIN, 0xa7); + break; + case FE_CAB_MOD_QAM512: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + break; + case FE_CAB_MOD_QAM1024: + stv0367_writereg(state, R367CAB_IQDEM_ADJ_AGC_REF, 0x00); + break; + default: + break; + } + + return QAMSize; +} + +static u32 stv0367cab_set_derot_freq(struct stv0367_state *state, + u32 adc_hz, s32 derot_hz) +{ + u32 sampled_if = 0; + u32 adc_khz; + + adc_khz = adc_hz / 1000; + + dprintk("%s: adc_hz=%d derot_hz=%d\n", __func__, adc_hz, derot_hz); + + if (adc_khz != 0) { + if (derot_hz < 1000000) + derot_hz = adc_hz / 4; /* ZIF operation */ + if (derot_hz > adc_hz) + derot_hz = derot_hz - adc_hz; + sampled_if = (u32)derot_hz / 1000; + sampled_if *= 32768; + sampled_if /= adc_khz; + sampled_if *= 256; + } + + if (sampled_if > 8388607) + sampled_if = 8388607; + + dprintk("%s: sampled_if=0x%x\n", __func__, sampled_if); + + stv0367_writereg(state, R367CAB_MIX_NCO_LL, sampled_if); + stv0367_writereg(state, R367CAB_MIX_NCO_HL, (sampled_if >> 8)); + stv0367_writebits(state, F367CAB_MIX_NCO_INC_HH, (sampled_if >> 16)); + + return derot_hz; +} + +static u32 stv0367cab_get_derot_freq(struct stv0367_state *state, u32 adc_hz) +{ + u32 sampled_if; + + sampled_if = stv0367_readbits(state, F367CAB_MIX_NCO_INC_LL) + + (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HL) << 8) + + (stv0367_readbits(state, F367CAB_MIX_NCO_INC_HH) << 16); + + sampled_if /= 256; + sampled_if *= (adc_hz / 1000); + sampled_if += 1; + sampled_if /= 32768; + + return sampled_if; +} + +static u32 stv0367cab_set_srate(struct stv0367_state *state, u32 adc_hz, + u32 mclk_hz, u32 SymbolRate, + enum stv0367cab_mod QAMSize) +{ + u32 QamSizeCorr = 0; + u32 u32_tmp = 0, u32_tmp1 = 0; + u32 adp_khz; + + dprintk("%s:\n", __func__); + + /* Set Correction factor of SRC gain */ + switch (QAMSize) { + case FE_CAB_MOD_QAM4: + QamSizeCorr = 1110; + break; + case FE_CAB_MOD_QAM16: + QamSizeCorr = 1032; + break; + case FE_CAB_MOD_QAM32: + QamSizeCorr = 954; + break; + case FE_CAB_MOD_QAM64: + QamSizeCorr = 983; + break; + case FE_CAB_MOD_QAM128: + QamSizeCorr = 957; + break; + case FE_CAB_MOD_QAM256: + QamSizeCorr = 948; + break; + case FE_CAB_MOD_QAM512: + QamSizeCorr = 0; + break; + case FE_CAB_MOD_QAM1024: + QamSizeCorr = 944; + break; + default: + break; + } + + /* Transfer ratio calculation */ + if (adc_hz != 0) { + u32_tmp = 256 * SymbolRate; + u32_tmp = u32_tmp / adc_hz; + } + stv0367_writereg(state, R367CAB_EQU_CRL_TFR, (u8)u32_tmp); + + /* Symbol rate and SRC gain calculation */ + adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */ + if (adp_khz != 0) { + u32_tmp = SymbolRate; + u32_tmp1 = SymbolRate; + + if (u32_tmp < 2097152) { /* 2097152 = 2^21 */ + /* Symbol rate calculation */ + u32_tmp *= 2048; /* 2048 = 2^11 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2^14 */ + u32_tmp /= 125 ; /* 125 = 1000/2^3 */ + u32_tmp = u32_tmp * 8; /* 8 = 2^3 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 2048; /* *2*2^10 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 10000000; + + } else if (u32_tmp < 4194304) { /* 4194304 = 2**22 */ + /* Symbol rate calculation */ + u32_tmp *= 1024 ; /* 1024 = 2**10 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */ + u32_tmp /= 125 ; /* 125 = 1000/2**3 */ + u32_tmp = u32_tmp * 16; /* 16 = 2**4 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 1024; /* *2*2^9 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz)*/ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 5000000; + } else if (u32_tmp < 8388607) { /* 8388607 = 2**23 */ + /* Symbol rate calculation */ + u32_tmp *= 512 ; /* 512 = 2**9 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2**14 */ + u32_tmp /= 125 ; /* 125 = 1000/2**3 */ + u32_tmp = u32_tmp * 32; /* 32 = 2**5 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 512; /* *2*2^8 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 2500000; + } else { + /* Symbol rate calculation */ + u32_tmp *= 256 ; /* 256 = 2**8 */ + u32_tmp = u32_tmp / adp_khz; + u32_tmp = u32_tmp * 16384; /* 16384 = 2**13 */ + u32_tmp /= 125 ; /* 125 = 1000/2**3 */ + u32_tmp = u32_tmp * 64; /* 64 = 2**6 */ + + /* SRC Gain Calculation */ + u32_tmp1 *= 256; /* 2*2^7 */ + u32_tmp1 /= 439; /* *2/878 */ + u32_tmp1 *= 256; /* *2^8 */ + u32_tmp1 = u32_tmp1 / adp_khz; /* /(AdpClk in kHz) */ + u32_tmp1 *= QamSizeCorr * 9; /* *1000*corr factor */ + u32_tmp1 = u32_tmp1 / 1250000; + } + } +#if 0 + /* Filters' coefficients are calculated and written + into registers only if the filters are enabled */ + if (stv0367_readbits(state, F367CAB_ADJ_EN)) { + stv0367cab_SetIirAdjacentcoefficient(state, mclk_hz, + SymbolRate); + /* AllPass filter must be enabled + when the adjacents filter is used */ + stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 1); + stv0367cab_SetAllPasscoefficient(state, mclk_hz, SymbolRate); + } else + /* AllPass filter must be disabled + when the adjacents filter is not used */ +#endif + stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); + + stv0367_writereg(state, R367CAB_SRC_NCO_LL, u32_tmp); + stv0367_writereg(state, R367CAB_SRC_NCO_LH, (u32_tmp >> 8)); + stv0367_writereg(state, R367CAB_SRC_NCO_HL, (u32_tmp >> 16)); + stv0367_writereg(state, R367CAB_SRC_NCO_HH, (u32_tmp >> 24)); + + stv0367_writereg(state, R367CAB_IQDEM_GAIN_SRC_L, u32_tmp1 & 0x00ff); + stv0367_writebits(state, F367CAB_GAIN_SRC_HI, (u32_tmp1 >> 8) & 0x00ff); + + return SymbolRate ; +} + +static u32 stv0367cab_GetSymbolRate(struct stv0367_state *state, u32 mclk_hz) +{ + u32 regsym; + u32 adp_khz; + + regsym = stv0367_readreg(state, R367CAB_SRC_NCO_LL) + + (stv0367_readreg(state, R367CAB_SRC_NCO_LH) << 8) + + (stv0367_readreg(state, R367CAB_SRC_NCO_HL) << 16) + + (stv0367_readreg(state, R367CAB_SRC_NCO_HH) << 24); + + adp_khz = (mclk_hz >> 1) / 1000;/* TRL works at half the system clock */ + + if (regsym < 134217728) { /* 134217728L = 2**27*/ + regsym = regsym * 32; /* 32 = 2**5 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3 */ + regsym /= 2048 ; /* 2048 = 2**11 */ + } else if (regsym < 268435456) { /* 268435456L = 2**28 */ + regsym = regsym * 16; /* 16 = 2**4 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3*/ + regsym /= 1024 ; /* 256 = 2**10*/ + } else if (regsym < 536870912) { /* 536870912L = 2**29*/ + regsym = regsym * 8; /* 8 = 2**3 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3 */ + regsym /= 512 ; /* 128 = 2**9 */ + } else { + regsym = regsym * 4; /* 4 = 2**2 */ + regsym = regsym / 32768; /* 32768L = 2**15 */ + regsym = adp_khz * regsym; /* AdpClk in kHz */ + regsym = regsym / 128; /* 128 = 2**7 */ + regsym *= 125 ; /* 125 = 1000/2**3 */ + regsym /= 256 ; /* 64 = 2**8 */ + } + + return regsym; +} + +static int stv0367cab_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + *status = 0; + + if (stv0367_readbits(state, F367CAB_QAMFEC_LOCK)) { + *status |= FE_HAS_LOCK; + dprintk("%s: stv0367 has locked\n", __func__); + } + + return 0; +} + +static int stv0367cab_standby(struct dvb_frontend *fe, u8 standby_on) +{ + struct stv0367_state *state = fe->demodulator_priv; + + dprintk("%s:\n", __func__); + + if (standby_on) { + stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x03); + stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x01); + stv0367_writebits(state, F367CAB_STDBY, 1); + stv0367_writebits(state, F367CAB_STDBY_CORE, 1); + stv0367_writebits(state, F367CAB_EN_BUFFER_I, 0); + stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 0); + stv0367_writebits(state, F367CAB_POFFQ, 1); + stv0367_writebits(state, F367CAB_POFFI, 1); + } else { + stv0367_writebits(state, F367CAB_STDBY_PLLXN, 0x00); + stv0367_writebits(state, F367CAB_BYPASS_PLLXN, 0x00); + stv0367_writebits(state, F367CAB_STDBY, 0); + stv0367_writebits(state, F367CAB_STDBY_CORE, 0); + stv0367_writebits(state, F367CAB_EN_BUFFER_I, 1); + stv0367_writebits(state, F367CAB_EN_BUFFER_Q, 1); + stv0367_writebits(state, F367CAB_POFFQ, 0); + stv0367_writebits(state, F367CAB_POFFI, 0); + } + + return 0; +} + +static int stv0367cab_sleep(struct dvb_frontend *fe) +{ + return stv0367cab_standby(fe, 1); +} + +int stv0367cab_init(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367cab_state *cab_state = state->cab_state; + int i; + + dprintk("%s:\n", __func__); + + for (i = 0; i < STV0367CAB_NBREGS; i++) + stv0367_writereg(state, def0367cab[i].addr, + def0367cab[i].value); + + switch (state->config->ts_mode) { + case STV0367_DVBCI_CLOCK: + dprintk("Setting TSMode = STV0367_DVBCI_CLOCK\n"); + stv0367_writebits(state, F367CAB_OUTFORMAT, 0x03); + break; + case STV0367_SERIAL_PUNCT_CLOCK: + case STV0367_SERIAL_CONT_CLOCK: + stv0367_writebits(state, F367CAB_OUTFORMAT, 0x01); + break; + case STV0367_PARALLEL_PUNCT_CLOCK: + case STV0367_OUTPUTMODE_DEFAULT: + stv0367_writebits(state, F367CAB_OUTFORMAT, 0x00); + break; + } + + switch (state->config->clk_pol) { + case STV0367_RISINGEDGE_CLOCK: + stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x00); + break; + case STV0367_FALLINGEDGE_CLOCK: + case STV0367_CLOCKPOLARITY_DEFAULT: + stv0367_writebits(state, F367CAB_CLK_POLARITY, 0x01); + break; + } + + stv0367_writebits(state, F367CAB_SYNC_STRIP, 0x00); + + stv0367_writebits(state, F367CAB_CT_NBST, 0x01); + + stv0367_writebits(state, F367CAB_TS_SWAP, 0x01); + + stv0367_writebits(state, F367CAB_FIFO_BYPASS, 0x00); + + stv0367_writereg(state, R367CAB_ANACTRL, 0x00);/*PLL enabled and used */ + + cab_state->mclk = stv0367cab_get_mclk(fe, state->config->xtal); + cab_state->adc_clk = stv0367cab_get_adc_freq(fe, state->config->xtal); + + return 0; +} +static +enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, + struct dvb_frontend_parameters *param) +{ + struct dvb_qam_parameters *op = ¶m->u.qam; + struct stv0367cab_state *cab_state = state->cab_state; + enum stv0367_cab_signal_type signalType = FE_CAB_NOAGC; + u32 QAMFEC_Lock, QAM_Lock, u32_tmp, + LockTime, TRLTimeOut, AGCTimeOut, CRLSymbols, + CRLTimeOut, EQLTimeOut, DemodTimeOut, FECTimeOut; + u8 TrackAGCAccum; + s32 tmp; + + dprintk("%s:\n", __func__); + + /* Timeouts calculation */ + /* A max lock time of 25 ms is allowed for delayed AGC */ + AGCTimeOut = 25; + /* 100000 symbols needed by the TRL as a maximum value */ + TRLTimeOut = 100000000 / op->symbol_rate; + /* CRLSymbols is the needed number of symbols to achieve a lock + within [-4%, +4%] of the symbol rate. + CRL timeout is calculated + for a lock within [-search_range, +search_range]. + EQL timeout can be changed depending on + the micro-reflections we want to handle. + A characterization must be performed + with these echoes to get new timeout values. + */ + switch (op->modulation) { + case QAM_16: + CRLSymbols = 150000; + EQLTimeOut = 100; + break; + case QAM_32: + CRLSymbols = 250000; + EQLTimeOut = 100; + break; + case QAM_64: + CRLSymbols = 200000; + EQLTimeOut = 100; + break; + case QAM_128: + CRLSymbols = 250000; + EQLTimeOut = 100; + break; + case QAM_256: + CRLSymbols = 250000; + EQLTimeOut = 100; + break; + default: + CRLSymbols = 200000; + EQLTimeOut = 100; + break; + } +#if 0 + if (pIntParams->search_range < 0) { + CRLTimeOut = (25 * CRLSymbols * + (-pIntParams->search_range / 1000)) / + (pIntParams->symbol_rate / 1000); + } else +#endif + CRLTimeOut = (25 * CRLSymbols * (cab_state->search_range / 1000)) / + (op->symbol_rate / 1000); + + CRLTimeOut = (1000 * CRLTimeOut) / op->symbol_rate; + /* Timeouts below 50ms are coerced */ + if (CRLTimeOut < 50) + CRLTimeOut = 50; + /* A maximum of 100 TS packets is needed to get FEC lock even in case + the spectrum inversion needs to be changed. + This is equal to 20 ms in case of the lowest symbol rate of 0.87Msps + */ + FECTimeOut = 20; + DemodTimeOut = AGCTimeOut + TRLTimeOut + CRLTimeOut + EQLTimeOut; + + dprintk("%s: DemodTimeOut=%d\n", __func__, DemodTimeOut); + + /* Reset the TRL to ensure nothing starts until the + AGC is stable which ensures a better lock time + */ + stv0367_writereg(state, R367CAB_CTRL_1, 0x04); + /* Set AGC accumulation time to minimum and lock threshold to maximum + in order to speed up the AGC lock */ + TrackAGCAccum = stv0367_readbits(state, F367CAB_AGC_ACCUMRSTSEL); + stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, 0x0); + /* Modulus Mapper is disabled */ + stv0367_writebits(state, F367CAB_MODULUSMAP_EN, 0); + /* Disable the sweep function */ + stv0367_writebits(state, F367CAB_SWEEP_EN, 0); + /* The sweep function is never used, Sweep rate must be set to 0 */ + /* Set the derotator frequency in Hz */ + stv0367cab_set_derot_freq(state, cab_state->adc_clk, + (1000 * (s32)state->config->if_khz + cab_state->derot_offset)); + /* Disable the Allpass Filter when the symbol rate is out of range */ + if ((op->symbol_rate > 10800000) | (op->symbol_rate < 1800000)) { + stv0367_writebits(state, F367CAB_ADJ_EN, 0); + stv0367_writebits(state, F367CAB_ALLPASSFILT_EN, 0); + } +#if 0 + /* Check if the tuner is locked */ + tuner_lock = stv0367cab_tuner_get_status(fe); + if (tuner_lock == 0) + return FE_367CAB_NOTUNER; +#endif + /* Relase the TRL to start demodulator acquisition */ + /* Wait for QAM lock */ + LockTime = 0; + stv0367_writereg(state, R367CAB_CTRL_1, 0x00); + do { + QAM_Lock = stv0367_readbits(state, F367CAB_FSM_STATUS); + if ((LockTime >= (DemodTimeOut - EQLTimeOut)) && + (QAM_Lock == 0x04)) + /* + * We don't wait longer, the frequency/phase offset + * must be too big + */ + LockTime = DemodTimeOut; + else if ((LockTime >= (AGCTimeOut + TRLTimeOut)) && + (QAM_Lock == 0x02)) + /* + * We don't wait longer, either there is no signal or + * it is not the right symbol rate or it is an analog + * carrier + */ + { + LockTime = DemodTimeOut; + u32_tmp = stv0367_readbits(state, + F367CAB_AGC_PWR_WORD_LO) + + (stv0367_readbits(state, + F367CAB_AGC_PWR_WORD_ME) << 8) + + (stv0367_readbits(state, + F367CAB_AGC_PWR_WORD_HI) << 16); + if (u32_tmp >= 131072) + u32_tmp = 262144 - u32_tmp; + u32_tmp = u32_tmp / (1 << (11 - stv0367_readbits(state, + F367CAB_AGC_IF_BWSEL))); + + if (u32_tmp < stv0367_readbits(state, + F367CAB_AGC_PWRREF_LO) + + 256 * stv0367_readbits(state, + F367CAB_AGC_PWRREF_HI) - 10) + QAM_Lock = 0x0f; + } else { + usleep_range(10000, 20000); + LockTime += 10; + } + dprintk("QAM_Lock=0x%x LockTime=%d\n", QAM_Lock, LockTime); + tmp = stv0367_readreg(state, R367CAB_IT_STATUS1); + + dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp); + + } while (((QAM_Lock != 0x0c) && (QAM_Lock != 0x0b)) && + (LockTime < DemodTimeOut)); + + dprintk("QAM_Lock=0x%x\n", QAM_Lock); + + tmp = stv0367_readreg(state, R367CAB_IT_STATUS1); + dprintk("R367CAB_IT_STATUS1=0x%x\n", tmp); + tmp = stv0367_readreg(state, R367CAB_IT_STATUS2); + dprintk("R367CAB_IT_STATUS2=0x%x\n", tmp); + + tmp = stv0367cab_get_derot_freq(state, cab_state->adc_clk); + dprintk("stv0367cab_get_derot_freq=0x%x\n", tmp); + + if ((QAM_Lock == 0x0c) || (QAM_Lock == 0x0b)) { + /* Wait for FEC lock */ + LockTime = 0; + do { + usleep_range(5000, 7000); + LockTime += 5; + QAMFEC_Lock = stv0367_readbits(state, + F367CAB_QAMFEC_LOCK); + } while (!QAMFEC_Lock && (LockTime < FECTimeOut)); + } else + QAMFEC_Lock = 0; + + if (QAMFEC_Lock) { + signalType = FE_CAB_DATAOK; + cab_state->modulation = op->modulation; + cab_state->spect_inv = stv0367_readbits(state, + F367CAB_QUAD_INV); +#if 0 +/* not clear for me */ + if (state->config->if_khz != 0) { + if (state->config->if_khz > cab_state->adc_clk / 1000) { + cab_state->freq_khz = + FE_Cab_TunerGetFrequency(pIntParams->hTuner) + - stv0367cab_get_derot_freq(state, cab_state->adc_clk) + - cab_state->adc_clk / 1000 + state->config->if_khz; + } else { + cab_state->freq_khz = + FE_Cab_TunerGetFrequency(pIntParams->hTuner) + - stv0367cab_get_derot_freq(state, cab_state->adc_clk) + + state->config->if_khz; + } + } else { + cab_state->freq_khz = + FE_Cab_TunerGetFrequency(pIntParams->hTuner) + + stv0367cab_get_derot_freq(state, + cab_state->adc_clk) - + cab_state->adc_clk / 4000; + } +#endif + cab_state->symbol_rate = stv0367cab_GetSymbolRate(state, + cab_state->mclk); + cab_state->locked = 1; + + /* stv0367_setbits(state, F367CAB_AGC_ACCUMRSTSEL,7);*/ + } else { + switch (QAM_Lock) { + case 1: + signalType = FE_CAB_NOAGC; + break; + case 2: + signalType = FE_CAB_NOTIMING; + break; + case 3: + signalType = FE_CAB_TIMINGOK; + break; + case 4: + signalType = FE_CAB_NOCARRIER; + break; + case 5: + signalType = FE_CAB_CARRIEROK; + break; + case 7: + signalType = FE_CAB_NOBLIND; + break; + case 8: + signalType = FE_CAB_BLINDOK; + break; + case 10: + signalType = FE_CAB_NODEMOD; + break; + case 11: + signalType = FE_CAB_DEMODOK; + break; + case 12: + signalType = FE_CAB_DEMODOK; + break; + case 13: + signalType = FE_CAB_NODEMOD; + break; + case 14: + signalType = FE_CAB_NOBLIND; + break; + case 15: + signalType = FE_CAB_NOSIGNAL; + break; + default: + break; + } + + } + + /* Set the AGC control values to tracking values */ + stv0367_writebits(state, F367CAB_AGC_ACCUMRSTSEL, TrackAGCAccum); + return signalType; +} + +static int stv0367cab_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367cab_state *cab_state = state->cab_state; + struct dvb_qam_parameters *op = ¶m->u.qam; + enum stv0367cab_mod QAMSize = 0; + + dprintk("%s: freq = %d, srate = %d\n", __func__, + param->frequency, op->symbol_rate); + + cab_state->derot_offset = 0; + + switch (op->modulation) { + case QAM_16: + QAMSize = FE_CAB_MOD_QAM16; + break; + case QAM_32: + QAMSize = FE_CAB_MOD_QAM32; + break; + case QAM_64: + QAMSize = FE_CAB_MOD_QAM64; + break; + case QAM_128: + QAMSize = FE_CAB_MOD_QAM128; + break; + case QAM_256: + QAMSize = FE_CAB_MOD_QAM256; + break; + default: + break; + } + + stv0367cab_init(fe); + + /* Tuner Frequency Setting */ + if (fe->ops.tuner_ops.set_params) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + stv0367cab_SetQamSize( + state, + op->symbol_rate, + QAMSize); + + stv0367cab_set_srate(state, + cab_state->adc_clk, + cab_state->mclk, + op->symbol_rate, + QAMSize); + /* Search algorithm launch, [-1.1*RangeOffset, +1.1*RangeOffset] scan */ + cab_state->state = stv0367cab_algo(state, param); + return 0; +} + +static int stv0367cab_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct stv0367cab_state *cab_state = state->cab_state; + struct dvb_qam_parameters *op = ¶m->u.qam; + + enum stv0367cab_mod QAMSize; + + dprintk("%s:\n", __func__); + + op->symbol_rate = stv0367cab_GetSymbolRate(state, cab_state->mclk); + + QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); + switch (QAMSize) { + case FE_CAB_MOD_QAM16: + op->modulation = QAM_16; + break; + case FE_CAB_MOD_QAM32: + op->modulation = QAM_32; + break; + case FE_CAB_MOD_QAM64: + op->modulation = QAM_64; + break; + case FE_CAB_MOD_QAM128: + op->modulation = QAM_128; + break; + case QAM_256: + op->modulation = QAM_256; + break; + default: + break; + } + + param->frequency = stv0367_get_tuner_freq(fe); + + dprintk("%s: tuner frequency = %d\n", __func__, param->frequency); + + if (state->config->if_khz == 0) { + param->frequency += + (stv0367cab_get_derot_freq(state, cab_state->adc_clk) - + cab_state->adc_clk / 4000); + return 0; + } + + if (state->config->if_khz > cab_state->adc_clk / 1000) + param->frequency += (state->config->if_khz + - stv0367cab_get_derot_freq(state, cab_state->adc_clk) + - cab_state->adc_clk / 1000); + else + param->frequency += (state->config->if_khz + - stv0367cab_get_derot_freq(state, cab_state->adc_clk)); + + return 0; +} + +#if 0 +void stv0367cab_GetErrorCount(state, enum stv0367cab_mod QAMSize, + u32 symbol_rate, FE_367qam_Monitor *Monitor_results) +{ + stv0367cab_OptimiseNByteAndGetBER(state, QAMSize, symbol_rate, Monitor_results); + stv0367cab_GetPacketsCount(state, Monitor_results); + + return; +} + +static int stv0367cab_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct stv0367_state *state = fe->demodulator_priv; + + return 0; +} +#endif +static s32 stv0367cab_get_rf_lvl(struct stv0367_state *state) +{ + s32 rfLevel = 0; + s32 RfAgcPwm = 0, IfAgcPwm = 0; + u8 i; + + stv0367_writebits(state, F367CAB_STDBY_ADCGP, 0x0); + + RfAgcPwm = + (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_LO) & 0x03) + + (stv0367_readbits(state, F367CAB_RF_AGC1_LEVEL_HI) << 2); + RfAgcPwm = 100 * RfAgcPwm / 1023; + + IfAgcPwm = + stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_LO) + + (stv0367_readbits(state, F367CAB_AGC_IF_PWMCMD_HI) << 8); + if (IfAgcPwm >= 2048) + IfAgcPwm -= 2048; + else + IfAgcPwm += 2048; + + IfAgcPwm = 100 * IfAgcPwm / 4095; + + /* For DTT75467 on NIM */ + if (RfAgcPwm < 90 && IfAgcPwm < 28) { + for (i = 0; i < RF_LOOKUP_TABLE_SIZE; i++) { + if (RfAgcPwm <= stv0367cab_RF_LookUp1[0][i]) { + rfLevel = (-1) * stv0367cab_RF_LookUp1[1][i]; + break; + } + } + if (i == RF_LOOKUP_TABLE_SIZE) + rfLevel = -56; + } else { /*if IF AGC>10*/ + for (i = 0; i < RF_LOOKUP_TABLE2_SIZE; i++) { + if (IfAgcPwm <= stv0367cab_RF_LookUp2[0][i]) { + rfLevel = (-1) * stv0367cab_RF_LookUp2[1][i]; + break; + } + } + if (i == RF_LOOKUP_TABLE2_SIZE) + rfLevel = -72; + } + return rfLevel; +} + +static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct stv0367_state *state = fe->demodulator_priv; + + s32 signal = stv0367cab_get_rf_lvl(state); + + dprintk("%s: signal=%d dBm\n", __func__, signal); + + if (signal <= -72) + *strength = 65535; + else + *strength = (22 + signal) * (-1311); + + dprintk("%s: strength=%d\n", __func__, (*strength)); + + return 0; +} + +static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 noisepercentage; + enum stv0367cab_mod QAMSize; + u32 regval = 0, temp = 0; + int power, i; + + QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); + switch (QAMSize) { + case FE_CAB_MOD_QAM4: + power = 21904; + break; + case FE_CAB_MOD_QAM16: + power = 20480; + break; + case FE_CAB_MOD_QAM32: + power = 23040; + break; + case FE_CAB_MOD_QAM64: + power = 21504; + break; + case FE_CAB_MOD_QAM128: + power = 23616; + break; + case FE_CAB_MOD_QAM256: + power = 21760; + break; + case FE_CAB_MOD_QAM512: + power = 1; + break; + case FE_CAB_MOD_QAM1024: + power = 21280; + break; + default: + power = 1; + break; + } + + for (i = 0; i < 10; i++) { + regval += (stv0367_readbits(state, F367CAB_SNR_LO) + + 256 * stv0367_readbits(state, F367CAB_SNR_HI)); + } + + regval /= 10; /*for average over 10 times in for loop above*/ + if (regval != 0) { + temp = power + * (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER))); + temp /= regval; + } + + /* table values, not needed to calculate logarithms */ + if (temp >= 5012) + noisepercentage = 100; + else if (temp >= 3981) + noisepercentage = 93; + else if (temp >= 3162) + noisepercentage = 86; + else if (temp >= 2512) + noisepercentage = 79; + else if (temp >= 1995) + noisepercentage = 72; + else if (temp >= 1585) + noisepercentage = 65; + else if (temp >= 1259) + noisepercentage = 58; + else if (temp >= 1000) + noisepercentage = 50; + else if (temp >= 794) + noisepercentage = 43; + else if (temp >= 501) + noisepercentage = 36; + else if (temp >= 316) + noisepercentage = 29; + else if (temp >= 200) + noisepercentage = 22; + else if (temp >= 158) + noisepercentage = 14; + else if (temp >= 126) + noisepercentage = 7; + else + noisepercentage = 0; + + dprintk("%s: noisepercentage=%d\n", __func__, noisepercentage); + + *snr = (noisepercentage * 65535) / 100; + + return 0; +} + +static struct dvb_frontend_ops stv0367cab_ops = { + .info = { + .name = "ST STV0367 DVB-C", + .type = FE_QAM, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_stepsize = 62500, + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000, + .caps = 0x400 |/* FE_CAN_QAM_4 */ + FE_CAN_QAM_16 | FE_CAN_QAM_32 | + FE_CAN_QAM_64 | FE_CAN_QAM_128 | + FE_CAN_QAM_256 | FE_CAN_FEC_AUTO + }, + .release = stv0367_release, + .init = stv0367cab_init, + .sleep = stv0367cab_sleep, + .i2c_gate_ctrl = stv0367cab_gate_ctrl, + .set_frontend = stv0367cab_set_frontend, + .get_frontend = stv0367cab_get_frontend, + .read_status = stv0367cab_read_status, +/* .read_ber = stv0367cab_read_ber, */ + .read_signal_strength = stv0367cab_read_strength, + .read_snr = stv0367cab_read_snr, +/* .read_ucblocks = stv0367cab_read_ucblcks,*/ + .get_tune_settings = stv0367_get_tune_settings, +}; + +struct dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + struct stv0367_state *state = NULL; + struct stv0367cab_state *cab_state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct stv0367_state), GFP_KERNEL); + if (state == NULL) + goto error; + cab_state = kzalloc(sizeof(struct stv0367cab_state), GFP_KERNEL); + if (cab_state == NULL) + goto error; + + /* setup the state */ + state->i2c = i2c; + state->config = config; + cab_state->search_range = 280000; + state->cab_state = cab_state; + state->fe.ops = stv0367cab_ops; + state->fe.demodulator_priv = state; + state->chip_id = stv0367_readreg(state, 0xf000); + + dprintk("%s: chip_id = 0x%x\n", __func__, state->chip_id); + + /* check if the demod is there */ + if ((state->chip_id != 0x50) && (state->chip_id != 0x60)) + goto error; + + return &state->fe; + +error: + kfree(cab_state); + kfree(state); + return NULL; +} +EXPORT_SYMBOL(stv0367cab_attach); + +MODULE_PARM_DESC(debug, "Set debug"); +MODULE_PARM_DESC(i2c_debug, "Set i2c debug"); + +MODULE_AUTHOR("Igor M. Liplianin"); +MODULE_DESCRIPTION("ST STV0367 DVB-C/T demodulator driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/stv0367.h b/drivers/media/dvb/frontends/stv0367.h new file mode 100644 index 000000000000..822a8e98783f --- /dev/null +++ b/drivers/media/dvb/frontends/stv0367.h @@ -0,0 +1,66 @@ +/* + * stv0367.h + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010 NetUP Inc. + * Copyright (C) 2010 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0367_H +#define STV0367_H + +#include +#include "dvb_frontend.h" + +struct stv0367_config { + u8 demod_address; + u32 xtal; + u32 if_khz;/*4500*/ + int if_iq_mode; + int ts_mode; + int clk_pol; +}; + +#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \ + && defined(MODULE)) +extern struct +dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c); +extern struct +dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c); +#else +static inline struct +dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct +dvb_frontend *stv0367cab_attach(const struct stv0367_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/dvb/frontends/stv0367_priv.h b/drivers/media/dvb/frontends/stv0367_priv.h new file mode 100644 index 000000000000..995db0689ddd --- /dev/null +++ b/drivers/media/dvb/frontends/stv0367_priv.h @@ -0,0 +1,212 @@ +/* + * stv0367_priv.h + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* Common driver error constants */ + +#ifndef STV0367_PRIV_H +#define STV0367_PRIV_H + +#ifndef TRUE + #define TRUE (1 == 1) +#endif +#ifndef FALSE + #define FALSE (!TRUE) +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* MACRO definitions */ +#define ABS(X) ((X) < 0 ? (-1 * (X)) : (X)) +#define MAX(X, Y) ((X) >= (Y) ? (X) : (Y)) +#define MIN(X, Y) ((X) <= (Y) ? (X) : (Y)) +#define INRANGE(X, Y, Z) \ + ((((X) <= (Y)) && ((Y) <= (Z))) || \ + (((Z) <= (Y)) && ((Y) <= (X))) ? 1 : 0) + +#ifndef MAKEWORD +#define MAKEWORD(X, Y) (((X) << 8) + (Y)) +#endif + +#define LSB(X) (((X) & 0xff)) +#define MSB(Y) (((Y) >> 8) & 0xff) +#define MMSB(Y)(((Y) >> 16) & 0xff) + +enum stv0367_ter_signal_type { + FE_TER_NOAGC = 0, + FE_TER_AGCOK = 5, + FE_TER_NOTPS = 6, + FE_TER_TPSOK = 7, + FE_TER_NOSYMBOL = 8, + FE_TER_BAD_CPQ = 9, + FE_TER_PRFOUNDOK = 10, + FE_TER_NOPRFOUND = 11, + FE_TER_LOCKOK = 12, + FE_TER_NOLOCK = 13, + FE_TER_SYMBOLOK = 15, + FE_TER_CPAMPOK = 16, + FE_TER_NOCPAMP = 17, + FE_TER_SWNOK = 18 +}; + +enum stv0367_ts_mode { + STV0367_OUTPUTMODE_DEFAULT, + STV0367_SERIAL_PUNCT_CLOCK, + STV0367_SERIAL_CONT_CLOCK, + STV0367_PARALLEL_PUNCT_CLOCK, + STV0367_DVBCI_CLOCK +}; + +enum stv0367_clk_pol { + STV0367_CLOCKPOLARITY_DEFAULT, + STV0367_RISINGEDGE_CLOCK, + STV0367_FALLINGEDGE_CLOCK +}; + +enum stv0367_ter_bw { + FE_TER_CHAN_BW_6M = 6, + FE_TER_CHAN_BW_7M = 7, + FE_TER_CHAN_BW_8M = 8 +}; + +#if 0 +enum FE_TER_Rate_TPS { + FE_TER_TPS_1_2 = 0, + FE_TER_TPS_2_3 = 1, + FE_TER_TPS_3_4 = 2, + FE_TER_TPS_5_6 = 3, + FE_TER_TPS_7_8 = 4 +}; +#endif + +enum stv0367_ter_mode { + FE_TER_MODE_2K, + FE_TER_MODE_8K, + FE_TER_MODE_4K +}; +#if 0 +enum FE_TER_Hierarchy_Alpha { + FE_TER_HIER_ALPHA_NONE, /* Regular modulation */ + FE_TER_HIER_ALPHA_1, /* Hierarchical modulation a = 1*/ + FE_TER_HIER_ALPHA_2, /* Hierarchical modulation a = 2*/ + FE_TER_HIER_ALPHA_4 /* Hierarchical modulation a = 4*/ +}; +#endif +enum stv0367_ter_hierarchy { + FE_TER_HIER_NONE, /*Hierarchy None*/ + FE_TER_HIER_LOW_PRIO, /*Hierarchy : Low Priority*/ + FE_TER_HIER_HIGH_PRIO, /*Hierarchy : High Priority*/ + FE_TER_HIER_PRIO_ANY /*Hierarchy :Any*/ +}; + +#if 0 +enum fe_stv0367_ter_spec { + FE_TER_INVERSION_NONE = 0, + FE_TER_INVERSION = 1, + FE_TER_INVERSION_AUTO = 2, + FE_TER_INVERSION_UNK = 4 +}; +#endif + +enum stv0367_ter_if_iq_mode { + FE_TER_NORMAL_IF_TUNER = 0, + FE_TER_LONGPATH_IF_TUNER = 1, + FE_TER_IQ_TUNER = 2 + +}; + +#if 0 +enum FE_TER_FECRate { + FE_TER_FEC_NONE = 0x00, /* no FEC rate specified */ + FE_TER_FEC_ALL = 0xFF, /* Logical OR of all FECs */ + FE_TER_FEC_1_2 = 1, + FE_TER_FEC_2_3 = (1 << 1), + FE_TER_FEC_3_4 = (1 << 2), + FE_TER_FEC_4_5 = (1 << 3), + FE_TER_FEC_5_6 = (1 << 4), + FE_TER_FEC_6_7 = (1 << 5), + FE_TER_FEC_7_8 = (1 << 6), + FE_TER_FEC_8_9 = (1 << 7) +}; + +enum FE_TER_Rate { + FE_TER_FE_1_2 = 0, + FE_TER_FE_2_3 = 1, + FE_TER_FE_3_4 = 2, + FE_TER_FE_5_6 = 3, + FE_TER_FE_6_7 = 4, + FE_TER_FE_7_8 = 5 +}; +#endif + +enum stv0367_ter_force { + FE_TER_FORCENONE = 0, + FE_TER_FORCE_M_G = 1 +}; + +enum stv0367cab_mod { + FE_CAB_MOD_QAM4, + FE_CAB_MOD_QAM16, + FE_CAB_MOD_QAM32, + FE_CAB_MOD_QAM64, + FE_CAB_MOD_QAM128, + FE_CAB_MOD_QAM256, + FE_CAB_MOD_QAM512, + FE_CAB_MOD_QAM1024 +}; +#if 0 +enum { + FE_CAB_FEC_A = 1, /* J83 Annex A */ + FE_CAB_FEC_B = (1 << 1),/* J83 Annex B */ + FE_CAB_FEC_C = (1 << 2) /* J83 Annex C */ +} FE_CAB_FECType_t; +#endif +struct stv0367_cab_signal_info { + int locked; + u32 frequency; /* kHz */ + u32 symbol_rate; /* Mbds */ + enum stv0367cab_mod modulation; + fe_spectral_inversion_t spect_inv; + s32 Power_dBmx10; /* Power of the RF signal (dBm x 10) */ + u32 CN_dBx10; /* Carrier to noise ratio (dB x 10) */ + u32 BER; /* Bit error rate (x 10000000) */ +}; + +enum stv0367_cab_signal_type { + FE_CAB_NOTUNER, + FE_CAB_NOAGC, + FE_CAB_NOSIGNAL, + FE_CAB_NOTIMING, + FE_CAB_TIMINGOK, + FE_CAB_NOCARRIER, + FE_CAB_CARRIEROK, + FE_CAB_NOBLIND, + FE_CAB_BLINDOK, + FE_CAB_NODEMOD, + FE_CAB_DEMODOK, + FE_CAB_DATAOK +}; + +#endif diff --git a/drivers/media/dvb/frontends/stv0367_regs.h b/drivers/media/dvb/frontends/stv0367_regs.h new file mode 100644 index 000000000000..a96fbdc7e25e --- /dev/null +++ b/drivers/media/dvb/frontends/stv0367_regs.h @@ -0,0 +1,3614 @@ +/* + * stv0367_regs.h + * + * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. + * + * Copyright (C) ST Microelectronics. + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef STV0367_REGS_H +#define STV0367_REGS_H + +/* ID */ +#define R367TER_ID 0xf000 +#define F367TER_IDENTIFICATIONREG 0xf00000ff + +/* I2CRPT */ +#define R367TER_I2CRPT 0xf001 +#define F367TER_I2CT_ON 0xf0010080 +#define F367TER_ENARPT_LEVEL 0xf0010070 +#define F367TER_SCLT_DELAY 0xf0010008 +#define F367TER_SCLT_NOD 0xf0010004 +#define F367TER_STOP_ENABLE 0xf0010002 +#define F367TER_SDAT_NOD 0xf0010001 + +/* TOPCTRL */ +#define R367TER_TOPCTRL 0xf002 +#define F367TER_STDBY 0xf0020080 +#define F367TER_STDBY_FEC 0xf0020040 +#define F367TER_STDBY_CORE 0xf0020020 +#define F367TER_QAM_COFDM 0xf0020010 +#define F367TER_TS_DIS 0xf0020008 +#define F367TER_DIR_CLK_216 0xf0020004 +#define F367TER_TUNER_BB 0xf0020002 +#define F367TER_DVBT_H 0xf0020001 + +/* IOCFG0 */ +#define R367TER_IOCFG0 0xf003 +#define F367TER_OP0_SD 0xf0030080 +#define F367TER_OP0_VAL 0xf0030040 +#define F367TER_OP0_OD 0xf0030020 +#define F367TER_OP0_INV 0xf0030010 +#define F367TER_OP0_DACVALUE_HI 0xf003000f + +/* DAc0R */ +#define R367TER_DAC0R 0xf004 +#define F367TER_OP0_DACVALUE_LO 0xf00400ff + +/* IOCFG1 */ +#define R367TER_IOCFG1 0xf005 +#define F367TER_IP0 0xf0050040 +#define F367TER_OP1_OD 0xf0050020 +#define F367TER_OP1_INV 0xf0050010 +#define F367TER_OP1_DACVALUE_HI 0xf005000f + +/* DAC1R */ +#define R367TER_DAC1R 0xf006 +#define F367TER_OP1_DACVALUE_LO 0xf00600ff + +/* IOCFG2 */ +#define R367TER_IOCFG2 0xf007 +#define F367TER_OP2_LOCK_CONF 0xf00700e0 +#define F367TER_OP2_OD 0xf0070010 +#define F367TER_OP2_VAL 0xf0070008 +#define F367TER_OP1_LOCK_CONF 0xf0070007 + +/* SDFR */ +#define R367TER_SDFR 0xf008 +#define F367TER_OP0_FREQ 0xf00800f0 +#define F367TER_OP1_FREQ 0xf008000f + +/* STATUS */ +#define R367TER_STATUS 0xf009 +#define F367TER_TPS_LOCK 0xf0090080 +#define F367TER_SYR_LOCK 0xf0090040 +#define F367TER_AGC_LOCK 0xf0090020 +#define F367TER_PRF 0xf0090010 +#define F367TER_LK 0xf0090008 +#define F367TER_PR 0xf0090007 + +/* AUX_CLK */ +#define R367TER_AUX_CLK 0xf00a +#define F367TER_AUXFEC_CTL 0xf00a00c0 +#define F367TER_DIS_CKX4 0xf00a0020 +#define F367TER_CKSEL 0xf00a0018 +#define F367TER_CKDIV_PROG 0xf00a0006 +#define F367TER_AUXCLK_ENA 0xf00a0001 + +/* FREESYS1 */ +#define R367TER_FREESYS1 0xf00b +#define F367TER_FREE_SYS1 0xf00b00ff + +/* FREESYS2 */ +#define R367TER_FREESYS2 0xf00c +#define F367TER_FREE_SYS2 0xf00c00ff + +/* FREESYS3 */ +#define R367TER_FREESYS3 0xf00d +#define F367TER_FREE_SYS3 0xf00d00ff + +/* GPIO_CFG */ +#define R367TER_GPIO_CFG 0xf00e +#define F367TER_GPIO7_NOD 0xf00e0080 +#define F367TER_GPIO7_CFG 0xf00e0040 +#define F367TER_GPIO6_NOD 0xf00e0020 +#define F367TER_GPIO6_CFG 0xf00e0010 +#define F367TER_GPIO5_NOD 0xf00e0008 +#define F367TER_GPIO5_CFG 0xf00e0004 +#define F367TER_GPIO4_NOD 0xf00e0002 +#define F367TER_GPIO4_CFG 0xf00e0001 + +/* GPIO_CMD */ +#define R367TER_GPIO_CMD 0xf00f +#define F367TER_GPIO7_VAL 0xf00f0008 +#define F367TER_GPIO6_VAL 0xf00f0004 +#define F367TER_GPIO5_VAL 0xf00f0002 +#define F367TER_GPIO4_VAL 0xf00f0001 + +/* AGC2MAX */ +#define R367TER_AGC2MAX 0xf010 +#define F367TER_AGC2_MAX 0xf01000ff + +/* AGC2MIN */ +#define R367TER_AGC2MIN 0xf011 +#define F367TER_AGC2_MIN 0xf01100ff + +/* AGC1MAX */ +#define R367TER_AGC1MAX 0xf012 +#define F367TER_AGC1_MAX 0xf01200ff + +/* AGC1MIN */ +#define R367TER_AGC1MIN 0xf013 +#define F367TER_AGC1_MIN 0xf01300ff + +/* AGCR */ +#define R367TER_AGCR 0xf014 +#define F367TER_RATIO_A 0xf01400e0 +#define F367TER_RATIO_B 0xf0140018 +#define F367TER_RATIO_C 0xf0140007 + +/* AGC2TH */ +#define R367TER_AGC2TH 0xf015 +#define F367TER_AGC2_THRES 0xf01500ff + +/* AGC12c */ +#define R367TER_AGC12C 0xf016 +#define F367TER_AGC1_IV 0xf0160080 +#define F367TER_AGC1_OD 0xf0160040 +#define F367TER_AGC1_LOAD 0xf0160020 +#define F367TER_AGC2_IV 0xf0160010 +#define F367TER_AGC2_OD 0xf0160008 +#define F367TER_AGC2_LOAD 0xf0160004 +#define F367TER_AGC12_MODE 0xf0160003 + +/* AGCCTRL1 */ +#define R367TER_AGCCTRL1 0xf017 +#define F367TER_DAGC_ON 0xf0170080 +#define F367TER_INVERT_AGC12 0xf0170040 +#define F367TER_AGC1_MODE 0xf0170008 +#define F367TER_AGC2_MODE 0xf0170007 + +/* AGCCTRL2 */ +#define R367TER_AGCCTRL2 0xf018 +#define F367TER_FRZ2_CTRL 0xf0180060 +#define F367TER_FRZ1_CTRL 0xf0180018 +#define F367TER_TIME_CST 0xf0180007 + +/* AGC1VAL1 */ +#define R367TER_AGC1VAL1 0xf019 +#define F367TER_AGC1_VAL_LO 0xf01900ff + +/* AGC1VAL2 */ +#define R367TER_AGC1VAL2 0xf01a +#define F367TER_AGC1_VAL_HI 0xf01a000f + +/* AGC2VAL1 */ +#define R367TER_AGC2VAL1 0xf01b +#define F367TER_AGC2_VAL_LO 0xf01b00ff + +/* AGC2VAL2 */ +#define R367TER_AGC2VAL2 0xf01c +#define F367TER_AGC2_VAL_HI 0xf01c000f + +/* AGC2PGA */ +#define R367TER_AGC2PGA 0xf01d +#define F367TER_AGC2_PGA 0xf01d00ff + +/* OVF_RATE1 */ +#define R367TER_OVF_RATE1 0xf01e +#define F367TER_OVF_RATE_HI 0xf01e000f + +/* OVF_RATE2 */ +#define R367TER_OVF_RATE2 0xf01f +#define F367TER_OVF_RATE_LO 0xf01f00ff + +/* GAIN_SRC1 */ +#define R367TER_GAIN_SRC1 0xf020 +#define F367TER_INV_SPECTR 0xf0200080 +#define F367TER_IQ_INVERT 0xf0200040 +#define F367TER_INR_BYPASS 0xf0200020 +#define F367TER_STATUS_INV_SPECRUM 0xf0200010 +#define F367TER_GAIN_SRC_HI 0xf020000f + +/* GAIN_SRC2 */ +#define R367TER_GAIN_SRC2 0xf021 +#define F367TER_GAIN_SRC_LO 0xf02100ff + +/* INC_DEROT1 */ +#define R367TER_INC_DEROT1 0xf022 +#define F367TER_INC_DEROT_HI 0xf02200ff + +/* INC_DEROT2 */ +#define R367TER_INC_DEROT2 0xf023 +#define F367TER_INC_DEROT_LO 0xf02300ff + +/* PPM_CPAMP_DIR */ +#define R367TER_PPM_CPAMP_DIR 0xf024 +#define F367TER_PPM_CPAMP_DIRECT 0xf02400ff + +/* PPM_CPAMP_INV */ +#define R367TER_PPM_CPAMP_INV 0xf025 +#define F367TER_PPM_CPAMP_INVER 0xf02500ff + +/* FREESTFE_1 */ +#define R367TER_FREESTFE_1 0xf026 +#define F367TER_SYMBOL_NUMBER_INC 0xf02600c0 +#define F367TER_SEL_LSB 0xf0260004 +#define F367TER_AVERAGE_ON 0xf0260002 +#define F367TER_DC_ADJ 0xf0260001 + +/* FREESTFE_2 */ +#define R367TER_FREESTFE_2 0xf027 +#define F367TER_SEL_SRCOUT 0xf02700c0 +#define F367TER_SEL_SYRTHR 0xf027001f + +/* DCOFFSET */ +#define R367TER_DCOFFSET 0xf028 +#define F367TER_SELECT_I_Q 0xf0280080 +#define F367TER_DC_OFFSET 0xf028007f + +/* EN_PROCESS */ +#define R367TER_EN_PROCESS 0xf029 +#define F367TER_FREE 0xf02900f0 +#define F367TER_ENAB_MANUAL 0xf0290001 + +/* SDI_SMOOTHER */ +#define R367TER_SDI_SMOOTHER 0xf02a +#define F367TER_DIS_SMOOTH 0xf02a0080 +#define F367TER_SDI_INC_SMOOTHER 0xf02a007f + +/* FE_LOOP_OPEN */ +#define R367TER_FE_LOOP_OPEN 0xf02b +#define F367TER_TRL_LOOP_OP 0xf02b0002 +#define F367TER_CRL_LOOP_OP 0xf02b0001 + +/* FREQOFF1 */ +#define R367TER_FREQOFF1 0xf02c +#define F367TER_FREQ_OFFSET_LOOP_OPEN_VHI 0xf02c00ff + +/* FREQOFF2 */ +#define R367TER_FREQOFF2 0xf02d +#define F367TER_FREQ_OFFSET_LOOP_OPEN_HI 0xf02d00ff + +/* FREQOFF3 */ +#define R367TER_FREQOFF3 0xf02e +#define F367TER_FREQ_OFFSET_LOOP_OPEN_LO 0xf02e00ff + +/* TIMOFF1 */ +#define R367TER_TIMOFF1 0xf02f +#define F367TER_TIM_OFFSET_LOOP_OPEN_HI 0xf02f00ff + +/* TIMOFF2 */ +#define R367TER_TIMOFF2 0xf030 +#define F367TER_TIM_OFFSET_LOOP_OPEN_LO 0xf03000ff + +/* EPQ */ +#define R367TER_EPQ 0xf031 +#define F367TER_EPQ1 0xf03100ff + +/* EPQAUTO */ +#define R367TER_EPQAUTO 0xf032 +#define F367TER_EPQ2 0xf03200ff + +/* SYR_UPDATE */ +#define R367TER_SYR_UPDATE 0xf033 +#define F367TER_SYR_PROTV 0xf0330080 +#define F367TER_SYR_PROTV_GAIN 0xf0330060 +#define F367TER_SYR_FILTER 0xf0330010 +#define F367TER_SYR_TRACK_THRES 0xf033000c + +/* CHPFREE */ +#define R367TER_CHPFREE 0xf034 +#define F367TER_CHP_FREE 0xf03400ff + +/* PPM_STATE_MAC */ +#define R367TER_PPM_STATE_MAC 0xf035 +#define F367TER_PPM_STATE_MACHINE_DECODER 0xf035003f + +/* INR_THRESHOLD */ +#define R367TER_INR_THRESHOLD 0xf036 +#define F367TER_INR_THRESH 0xf03600ff + +/* EPQ_TPS_ID_CELL */ +#define R367TER_EPQ_TPS_ID_CELL 0xf037 +#define F367TER_ENABLE_LGTH_TO_CF 0xf0370080 +#define F367TER_DIS_TPS_RSVD 0xf0370040 +#define F367TER_DIS_BCH 0xf0370020 +#define F367TER_DIS_ID_CEL 0xf0370010 +#define F367TER_TPS_ADJUST_SYM 0xf037000f + +/* EPQ_CFG */ +#define R367TER_EPQ_CFG 0xf038 +#define F367TER_EPQ_RANGE 0xf0380002 +#define F367TER_EPQ_SOFT 0xf0380001 + +/* EPQ_STATUS */ +#define R367TER_EPQ_STATUS 0xf039 +#define F367TER_SLOPE_INC 0xf03900fc +#define F367TER_TPS_FIELD 0xf0390003 + +/* AUTORELOCK */ +#define R367TER_AUTORELOCK 0xf03a +#define F367TER_BYPASS_BER_TEMPO 0xf03a0080 +#define F367TER_BER_TEMPO 0xf03a0070 +#define F367TER_BYPASS_COFDM_TEMPO 0xf03a0008 +#define F367TER_COFDM_TEMPO 0xf03a0007 + +/* BER_THR_VMSB */ +#define R367TER_BER_THR_VMSB 0xf03b +#define F367TER_BER_THRESHOLD_HI 0xf03b00ff + +/* BER_THR_MSB */ +#define R367TER_BER_THR_MSB 0xf03c +#define F367TER_BER_THRESHOLD_MID 0xf03c00ff + +/* BER_THR_LSB */ +#define R367TER_BER_THR_LSB 0xf03d +#define F367TER_BER_THRESHOLD_LO 0xf03d00ff + +/* CCD */ +#define R367TER_CCD 0xf03e +#define F367TER_CCD_DETECTED 0xf03e0080 +#define F367TER_CCD_RESET 0xf03e0040 +#define F367TER_CCD_THRESHOLD 0xf03e000f + +/* SPECTR_CFG */ +#define R367TER_SPECTR_CFG 0xf03f +#define F367TER_SPECT_CFG 0xf03f0003 + +/* CONSTMU_MSB */ +#define R367TER_CONSTMU_MSB 0xf040 +#define F367TER_CONSTMU_FREEZE 0xf0400080 +#define F367TER_CONSTNU_FORCE_EN 0xf0400040 +#define F367TER_CONST_MU_MSB 0xf040003f + +/* CONSTMU_LSB */ +#define R367TER_CONSTMU_LSB 0xf041 +#define F367TER_CONST_MU_LSB 0xf04100ff + +/* CONSTMU_MAX_MSB */ +#define R367TER_CONSTMU_MAX_MSB 0xf042 +#define F367TER_CONST_MU_MAX_MSB 0xf042003f + +/* CONSTMU_MAX_LSB */ +#define R367TER_CONSTMU_MAX_LSB 0xf043 +#define F367TER_CONST_MU_MAX_LSB 0xf04300ff + +/* ALPHANOISE */ +#define R367TER_ALPHANOISE 0xf044 +#define F367TER_USE_ALLFILTER 0xf0440080 +#define F367TER_INTER_ON 0xf0440040 +#define F367TER_ALPHA_NOISE 0xf044001f + +/* MAXGP_MSB */ +#define R367TER_MAXGP_MSB 0xf045 +#define F367TER_MUFILTER_LENGTH 0xf04500f0 +#define F367TER_MAX_GP_MSB 0xf045000f + +/* MAXGP_LSB */ +#define R367TER_MAXGP_LSB 0xf046 +#define F367TER_MAX_GP_LSB 0xf04600ff + +/* ALPHAMSB */ +#define R367TER_ALPHAMSB 0xf047 +#define F367TER_CHC_DATARATE 0xf04700c0 +#define F367TER_ALPHA_MSB 0xf047003f + +/* ALPHALSB */ +#define R367TER_ALPHALSB 0xf048 +#define F367TER_ALPHA_LSB 0xf04800ff + +/* PILOT_ACCU */ +#define R367TER_PILOT_ACCU 0xf049 +#define F367TER_USE_SCAT4ADDAPT 0xf0490080 +#define F367TER_PILOT_ACC 0xf049001f + +/* PILOTMU_ACCU */ +#define R367TER_PILOTMU_ACCU 0xf04a +#define F367TER_DISCARD_BAD_SP 0xf04a0080 +#define F367TER_DISCARD_BAD_CP 0xf04a0040 +#define F367TER_PILOT_MU_ACCU 0xf04a001f + +/* FILT_CHANNEL_EST */ +#define R367TER_FILT_CHANNEL_EST 0xf04b +#define F367TER_USE_FILT_PILOT 0xf04b0080 +#define F367TER_FILT_CHANNEL 0xf04b007f + +/* ALPHA_NOPISE_FREQ */ +#define R367TER_ALPHA_NOPISE_FREQ 0xf04c +#define F367TER_NOISE_FREQ_FILT 0xf04c0040 +#define F367TER_ALPHA_NOISE_FREQ 0xf04c003f + +/* RATIO_PILOT */ +#define R367TER_RATIO_PILOT 0xf04d +#define F367TER_RATIO_MEAN_SP 0xf04d00f0 +#define F367TER_RATIO_MEAN_CP 0xf04d000f + +/* CHC_CTL */ +#define R367TER_CHC_CTL 0xf04e +#define F367TER_TRACK_EN 0xf04e0080 +#define F367TER_NOISE_NORM_EN 0xf04e0040 +#define F367TER_FORCE_CHC_RESET 0xf04e0020 +#define F367TER_SHORT_TIME 0xf04e0010 +#define F367TER_FORCE_STATE_EN 0xf04e0008 +#define F367TER_FORCE_STATE 0xf04e0007 + +/* EPQ_ADJUST */ +#define R367TER_EPQ_ADJUST 0xf04f +#define F367TER_ADJUST_SCAT_IND 0xf04f00c0 +#define F367TER_ONE_SYMBOL 0xf04f0010 +#define F367TER_EPQ_DECAY 0xf04f000e +#define F367TER_HOLD_SLOPE 0xf04f0001 + +/* EPQ_THRES */ +#define R367TER_EPQ_THRES 0xf050 +#define F367TER_EPQ_THR 0xf05000ff + +/* OMEGA_CTL */ +#define R367TER_OMEGA_CTL 0xf051 +#define F367TER_OMEGA_RST 0xf0510080 +#define F367TER_FREEZE_OMEGA 0xf0510040 +#define F367TER_OMEGA_SEL 0xf051003f + +/* GP_CTL */ +#define R367TER_GP_CTL 0xf052 +#define F367TER_CHC_STATE 0xf05200e0 +#define F367TER_FREEZE_GP 0xf0520010 +#define F367TER_GP_SEL 0xf052000f + +/* MUMSB */ +#define R367TER_MUMSB 0xf053 +#define F367TER_MU_MSB 0xf053007f + +/* MULSB */ +#define R367TER_MULSB 0xf054 +#define F367TER_MU_LSB 0xf05400ff + +/* GPMSB */ +#define R367TER_GPMSB 0xf055 +#define F367TER_CSI_THRESHOLD 0xf05500e0 +#define F367TER_GP_MSB 0xf055000f + +/* GPLSB */ +#define R367TER_GPLSB 0xf056 +#define F367TER_GP_LSB 0xf05600ff + +/* OMEGAMSB */ +#define R367TER_OMEGAMSB 0xf057 +#define F367TER_OMEGA_MSB 0xf057007f + +/* OMEGALSB */ +#define R367TER_OMEGALSB 0xf058 +#define F367TER_OMEGA_LSB 0xf05800ff + +/* SCAT_NB */ +#define R367TER_SCAT_NB 0xf059 +#define F367TER_CHC_TEST 0xf05900f8 +#define F367TER_SCAT_NUMB 0xf0590003 + +/* CHC_DUMMY */ +#define R367TER_CHC_DUMMY 0xf05a +#define F367TER_CHC_DUM 0xf05a00ff + +/* INC_CTL */ +#define R367TER_INC_CTL 0xf05b +#define F367TER_INC_BYPASS 0xf05b0080 +#define F367TER_INC_NDEPTH 0xf05b000c +#define F367TER_INC_MADEPTH 0xf05b0003 + +/* INCTHRES_COR1 */ +#define R367TER_INCTHRES_COR1 0xf05c +#define F367TER_INC_THRES_COR1 0xf05c00ff + +/* INCTHRES_COR2 */ +#define R367TER_INCTHRES_COR2 0xf05d +#define F367TER_INC_THRES_COR2 0xf05d00ff + +/* INCTHRES_DET1 */ +#define R367TER_INCTHRES_DET1 0xf05e +#define F367TER_INC_THRES_DET1 0xf05e003f + +/* INCTHRES_DET2 */ +#define R367TER_INCTHRES_DET2 0xf05f +#define F367TER_INC_THRES_DET2 0xf05f003f + +/* IIR_CELLNB */ +#define R367TER_IIR_CELLNB 0xf060 +#define F367TER_NRST_IIR 0xf0600080 +#define F367TER_IIR_CELL_NB 0xf0600007 + +/* IIRCX_COEFF1_MSB */ +#define R367TER_IIRCX_COEFF1_MSB 0xf061 +#define F367TER_IIR_CX_COEFF1_MSB 0xf06100ff + +/* IIRCX_COEFF1_LSB */ +#define R367TER_IIRCX_COEFF1_LSB 0xf062 +#define F367TER_IIR_CX_COEFF1_LSB 0xf06200ff + +/* IIRCX_COEFF2_MSB */ +#define R367TER_IIRCX_COEFF2_MSB 0xf063 +#define F367TER_IIR_CX_COEFF2_MSB 0xf06300ff + +/* IIRCX_COEFF2_LSB */ +#define R367TER_IIRCX_COEFF2_LSB 0xf064 +#define F367TER_IIR_CX_COEFF2_LSB 0xf06400ff + +/* IIRCX_COEFF3_MSB */ +#define R367TER_IIRCX_COEFF3_MSB 0xf065 +#define F367TER_IIR_CX_COEFF3_MSB 0xf06500ff + +/* IIRCX_COEFF3_LSB */ +#define R367TER_IIRCX_COEFF3_LSB 0xf066 +#define F367TER_IIR_CX_COEFF3_LSB 0xf06600ff + +/* IIRCX_COEFF4_MSB */ +#define R367TER_IIRCX_COEFF4_MSB 0xf067 +#define F367TER_IIR_CX_COEFF4_MSB 0xf06700ff + +/* IIRCX_COEFF4_LSB */ +#define R367TER_IIRCX_COEFF4_LSB 0xf068 +#define F367TER_IIR_CX_COEFF4_LSB 0xf06800ff + +/* IIRCX_COEFF5_MSB */ +#define R367TER_IIRCX_COEFF5_MSB 0xf069 +#define F367TER_IIR_CX_COEFF5_MSB 0xf06900ff + +/* IIRCX_COEFF5_LSB */ +#define R367TER_IIRCX_COEFF5_LSB 0xf06a +#define F367TER_IIR_CX_COEFF5_LSB 0xf06a00ff + +/* FEPATH_CFG */ +#define R367TER_FEPATH_CFG 0xf06b +#define F367TER_DEMUX_SWAP 0xf06b0004 +#define F367TER_DIGAGC_SWAP 0xf06b0002 +#define F367TER_LONGPATH_IF 0xf06b0001 + +/* PMC1_FUNC */ +#define R367TER_PMC1_FUNC 0xf06c +#define F367TER_SOFT_RSTN 0xf06c0080 +#define F367TER_PMC1_AVERAGE_TIME 0xf06c0078 +#define F367TER_PMC1_WAIT_TIME 0xf06c0006 +#define F367TER_PMC1_2N_SEL 0xf06c0001 + +/* PMC1_FOR */ +#define R367TER_PMC1_FOR 0xf06d +#define F367TER_PMC1_FORCE 0xf06d0080 +#define F367TER_PMC1_FORCE_VALUE 0xf06d007c + +/* PMC2_FUNC */ +#define R367TER_PMC2_FUNC 0xf06e +#define F367TER_PMC2_SOFT_STN 0xf06e0080 +#define F367TER_PMC2_ACCU_TIME 0xf06e0070 +#define F367TER_PMC2_CMDP_MN 0xf06e0008 +#define F367TER_PMC2_SWAP 0xf06e0004 + +/* STATUS_ERR_DA */ +#define R367TER_STATUS_ERR_DA 0xf06f +#define F367TER_COM_USEGAINTRK 0xf06f0080 +#define F367TER_COM_AGCLOCK 0xf06f0040 +#define F367TER_AUT_AGCLOCK 0xf06f0020 +#define F367TER_MIN_ERR_X_LSB 0xf06f000f + +/* DIG_AGC_R */ +#define R367TER_DIG_AGC_R 0xf070 +#define F367TER_COM_SOFT_RSTN 0xf0700080 +#define F367TER_COM_AGC_ON 0xf0700040 +#define F367TER_COM_EARLY 0xf0700020 +#define F367TER_AUT_SOFT_RESETN 0xf0700010 +#define F367TER_AUT_AGC_ON 0xf0700008 +#define F367TER_AUT_EARLY 0xf0700004 +#define F367TER_AUT_ROT_EN 0xf0700002 +#define F367TER_LOCK_SOFT_RESETN 0xf0700001 + +/* COMAGC_TARMSB */ +#define R367TER_COMAGC_TARMSB 0xf071 +#define F367TER_COM_AGC_TARGET_MSB 0xf07100ff + +/* COM_AGC_TAR_ENMODE */ +#define R367TER_COM_AGC_TAR_ENMODE 0xf072 +#define F367TER_COM_AGC_TARGET_LSB 0xf07200f0 +#define F367TER_COM_ENMODE 0xf072000f + +/* COM_AGC_CFG */ +#define R367TER_COM_AGC_CFG 0xf073 +#define F367TER_COM_N 0xf07300f8 +#define F367TER_COM_STABMODE 0xf0730006 +#define F367TER_ERR_SEL 0xf0730001 + +/* COM_AGC_GAIN1 */ +#define R367TER_COM_AGC_GAIN1 0xf074 +#define F367TER_COM_GAIN1aCK 0xf07400f0 +#define F367TER_COM_GAIN1TRK 0xf074000f + +/* AUT_AGC_TARGETMSB */ +#define R367TER_AUT_AGC_TARGETMSB 0xf075 +#define F367TER_AUT_AGC_TARGET_MSB 0xf07500ff + +/* LOCK_DET_MSB */ +#define R367TER_LOCK_DET_MSB 0xf076 +#define F367TER_LOCK_DETECT_MSB 0xf07600ff + +/* AGCTAR_LOCK_LSBS */ +#define R367TER_AGCTAR_LOCK_LSBS 0xf077 +#define F367TER_AUT_AGC_TARGET_LSB 0xf07700f0 +#define F367TER_LOCK_DETECT_LSB 0xf077000f + +/* AUT_GAIN_EN */ +#define R367TER_AUT_GAIN_EN 0xf078 +#define F367TER_AUT_ENMODE 0xf07800f0 +#define F367TER_AUT_GAIN2 0xf078000f + +/* AUT_CFG */ +#define R367TER_AUT_CFG 0xf079 +#define F367TER_AUT_N 0xf07900f8 +#define F367TER_INT_CHOICE 0xf0790006 +#define F367TER_INT_LOAD 0xf0790001 + +/* LOCKN */ +#define R367TER_LOCKN 0xf07a +#define F367TER_LOCK_N 0xf07a00f8 +#define F367TER_SEL_IQNTAR 0xf07a0004 +#define F367TER_LOCK_DETECT_CHOICE 0xf07a0003 + +/* INT_X_3 */ +#define R367TER_INT_X_3 0xf07b +#define F367TER_INT_X3 0xf07b00ff + +/* INT_X_2 */ +#define R367TER_INT_X_2 0xf07c +#define F367TER_INT_X2 0xf07c00ff + +/* INT_X_1 */ +#define R367TER_INT_X_1 0xf07d +#define F367TER_INT_X1 0xf07d00ff + +/* INT_X_0 */ +#define R367TER_INT_X_0 0xf07e +#define F367TER_INT_X0 0xf07e00ff + +/* MIN_ERRX_MSB */ +#define R367TER_MIN_ERRX_MSB 0xf07f +#define F367TER_MIN_ERR_X_MSB 0xf07f00ff + +/* COR_CTL */ +#define R367TER_COR_CTL 0xf080 +#define F367TER_CORE_ACTIVE 0xf0800020 +#define F367TER_HOLD 0xf0800010 +#define F367TER_CORE_STATE_CTL 0xf080000f + +/* COR_STAT */ +#define R367TER_COR_STAT 0xf081 +#define F367TER_SCATT_LOCKED 0xf0810080 +#define F367TER_TPS_LOCKED 0xf0810040 +#define F367TER_SYR_LOCKED_COR 0xf0810020 +#define F367TER_AGC_LOCKED_STAT 0xf0810010 +#define F367TER_CORE_STATE_STAT 0xf081000f + +/* COR_INTEN */ +#define R367TER_COR_INTEN 0xf082 +#define F367TER_INTEN 0xf0820080 +#define F367TER_INTEN_SYR 0xf0820020 +#define F367TER_INTEN_FFT 0xf0820010 +#define F367TER_INTEN_AGC 0xf0820008 +#define F367TER_INTEN_TPS1 0xf0820004 +#define F367TER_INTEN_TPS2 0xf0820002 +#define F367TER_INTEN_TPS3 0xf0820001 + +/* COR_INTSTAT */ +#define R367TER_COR_INTSTAT 0xf083 +#define F367TER_INTSTAT_SYR 0xf0830020 +#define F367TER_INTSTAT_FFT 0xf0830010 +#define F367TER_INTSAT_AGC 0xf0830008 +#define F367TER_INTSTAT_TPS1 0xf0830004 +#define F367TER_INTSTAT_TPS2 0xf0830002 +#define F367TER_INTSTAT_TPS3 0xf0830001 + +/* COR_MODEGUARD */ +#define R367TER_COR_MODEGUARD 0xf084 +#define F367TER_FORCE 0xf0840010 +#define F367TER_MODE 0xf084000c +#define F367TER_GUARD 0xf0840003 + +/* AGC_CTL */ +#define R367TER_AGC_CTL 0xf085 +#define F367TER_AGC_TIMING_FACTOR 0xf08500e0 +#define F367TER_AGC_LAST 0xf0850010 +#define F367TER_AGC_GAIN 0xf085000c +#define F367TER_AGC_NEG 0xf0850002 +#define F367TER_AGC_SET 0xf0850001 + +/* AGC_MANUAL1 */ +#define R367TER_AGC_MANUAL1 0xf086 +#define F367TER_AGC_VAL_LO 0xf08600ff + +/* AGC_MANUAL2 */ +#define R367TER_AGC_MANUAL2 0xf087 +#define F367TER_AGC_VAL_HI 0xf087000f + +/* AGC_TARG */ +#define R367TER_AGC_TARG 0xf088 +#define F367TER_AGC_TARGET 0xf08800ff + +/* AGC_GAIN1 */ +#define R367TER_AGC_GAIN1 0xf089 +#define F367TER_AGC_GAIN_LO 0xf08900ff + +/* AGC_GAIN2 */ +#define R367TER_AGC_GAIN2 0xf08a +#define F367TER_AGC_LOCKED_GAIN2 0xf08a0010 +#define F367TER_AGC_GAIN_HI 0xf08a000f + +/* RESERVED_1 */ +#define R367TER_RESERVED_1 0xf08b +#define F367TER_RESERVED1 0xf08b00ff + +/* RESERVED_2 */ +#define R367TER_RESERVED_2 0xf08c +#define F367TER_RESERVED2 0xf08c00ff + +/* RESERVED_3 */ +#define R367TER_RESERVED_3 0xf08d +#define F367TER_RESERVED3 0xf08d00ff + +/* CAS_CTL */ +#define R367TER_CAS_CTL 0xf08e +#define F367TER_CCS_ENABLE 0xf08e0080 +#define F367TER_ACS_DISABLE 0xf08e0040 +#define F367TER_DAGC_DIS 0xf08e0020 +#define F367TER_DAGC_GAIN 0xf08e0018 +#define F367TER_CCSMU 0xf08e0007 + +/* CAS_FREQ */ +#define R367TER_CAS_FREQ 0xf08f +#define F367TER_CCS_FREQ 0xf08f00ff + +/* CAS_DAGCGAIN */ +#define R367TER_CAS_DAGCGAIN 0xf090 +#define F367TER_CAS_DAGC_GAIN 0xf09000ff + +/* SYR_CTL */ +#define R367TER_SYR_CTL 0xf091 +#define F367TER_SICTH_ENABLE 0xf0910080 +#define F367TER_LONG_ECHO 0xf0910078 +#define F367TER_AUTO_LE_EN 0xf0910004 +#define F367TER_SYR_BYPASS 0xf0910002 +#define F367TER_SYR_TR_DIS 0xf0910001 + +/* SYR_STAT */ +#define R367TER_SYR_STAT 0xf092 +#define F367TER_SYR_LOCKED_STAT 0xf0920010 +#define F367TER_SYR_MODE 0xf092000c +#define F367TER_SYR_GUARD 0xf0920003 + +/* SYR_NCO1 */ +#define R367TER_SYR_NCO1 0xf093 +#define F367TER_SYR_NCO_LO 0xf09300ff + +/* SYR_NCO2 */ +#define R367TER_SYR_NCO2 0xf094 +#define F367TER_SYR_NCO_HI 0xf094003f + +/* SYR_OFFSET1 */ +#define R367TER_SYR_OFFSET1 0xf095 +#define F367TER_SYR_OFFSET_LO 0xf09500ff + +/* SYR_OFFSET2 */ +#define R367TER_SYR_OFFSET2 0xf096 +#define F367TER_SYR_OFFSET_HI 0xf096003f + +/* FFT_CTL */ +#define R367TER_FFT_CTL 0xf097 +#define F367TER_SHIFT_FFT_TRIG 0xf0970018 +#define F367TER_FFT_TRIGGER 0xf0970004 +#define F367TER_FFT_MANUAL 0xf0970002 +#define F367TER_IFFT_MODE 0xf0970001 + +/* SCR_CTL */ +#define R367TER_SCR_CTL 0xf098 +#define F367TER_SYRADJDECAY 0xf0980070 +#define F367TER_SCR_CPEDIS 0xf0980002 +#define F367TER_SCR_DIS 0xf0980001 + +/* PPM_CTL1 */ +#define R367TER_PPM_CTL1 0xf099 +#define F367TER_PPM_MAXFREQ 0xf0990030 +#define F367TER_PPM_MAXTIM 0xf0990008 +#define F367TER_PPM_INVSEL 0xf0990004 +#define F367TER_PPM_SCATDIS 0xf0990002 +#define F367TER_PPM_BYP 0xf0990001 + +/* TRL_CTL */ +#define R367TER_TRL_CTL 0xf09a +#define F367TER_TRL_NOMRATE_LSB 0xf09a0080 +#define F367TER_TRL_GAIN_FACTOR 0xf09a0078 +#define F367TER_TRL_LOOPGAIN 0xf09a0007 + +/* TRL_NOMRATE1 */ +#define R367TER_TRL_NOMRATE1 0xf09b +#define F367TER_TRL_NOMRATE_LO 0xf09b00ff + +/* TRL_NOMRATE2 */ +#define R367TER_TRL_NOMRATE2 0xf09c +#define F367TER_TRL_NOMRATE_HI 0xf09c00ff + +/* TRL_TIME1 */ +#define R367TER_TRL_TIME1 0xf09d +#define F367TER_TRL_TOFFSET_LO 0xf09d00ff + +/* TRL_TIME2 */ +#define R367TER_TRL_TIME2 0xf09e +#define F367TER_TRL_TOFFSET_HI 0xf09e00ff + +/* CRL_CTL */ +#define R367TER_CRL_CTL 0xf09f +#define F367TER_CRL_DIS 0xf09f0080 +#define F367TER_CRL_GAIN_FACTOR 0xf09f0078 +#define F367TER_CRL_LOOPGAIN 0xf09f0007 + +/* CRL_FREQ1 */ +#define R367TER_CRL_FREQ1 0xf0a0 +#define F367TER_CRL_FOFFSET_LO 0xf0a000ff + +/* CRL_FREQ2 */ +#define R367TER_CRL_FREQ2 0xf0a1 +#define F367TER_CRL_FOFFSET_HI 0xf0a100ff + +/* CRL_FREQ3 */ +#define R367TER_CRL_FREQ3 0xf0a2 +#define F367TER_CRL_FOFFSET_VHI 0xf0a200ff + +/* TPS_SFRAME_CTL */ +#define R367TER_TPS_SFRAME_CTL 0xf0a3 +#define F367TER_TPS_SFRAME_SYNC 0xf0a30001 + +/* CHC_SNR */ +#define R367TER_CHC_SNR 0xf0a4 +#define F367TER_CHCSNR 0xf0a400ff + +/* BDI_CTL */ +#define R367TER_BDI_CTL 0xf0a5 +#define F367TER_BDI_LPSEL 0xf0a50002 +#define F367TER_BDI_SERIAL 0xf0a50001 + +/* DMP_CTL */ +#define R367TER_DMP_CTL 0xf0a6 +#define F367TER_DMP_SCALING_FACTOR 0xf0a6001e +#define F367TER_DMP_SDDIS 0xf0a60001 + +/* TPS_RCVD1 */ +#define R367TER_TPS_RCVD1 0xf0a7 +#define F367TER_TPS_CHANGE 0xf0a70040 +#define F367TER_BCH_OK 0xf0a70020 +#define F367TER_TPS_SYNC 0xf0a70010 +#define F367TER_TPS_FRAME 0xf0a70003 + +/* TPS_RCVD2 */ +#define R367TER_TPS_RCVD2 0xf0a8 +#define F367TER_TPS_HIERMODE 0xf0a80070 +#define F367TER_TPS_CONST 0xf0a80003 + +/* TPS_RCVD3 */ +#define R367TER_TPS_RCVD3 0xf0a9 +#define F367TER_TPS_LPCODE 0xf0a90070 +#define F367TER_TPS_HPCODE 0xf0a90007 + +/* TPS_RCVD4 */ +#define R367TER_TPS_RCVD4 0xf0aa +#define F367TER_TPS_GUARD 0xf0aa0030 +#define F367TER_TPS_MODE 0xf0aa0003 + +/* TPS_ID_CELL1 */ +#define R367TER_TPS_ID_CELL1 0xf0ab +#define F367TER_TPS_ID_CELL_LO 0xf0ab00ff + +/* TPS_ID_CELL2 */ +#define R367TER_TPS_ID_CELL2 0xf0ac +#define F367TER_TPS_ID_CELL_HI 0xf0ac00ff + +/* TPS_RCVD5_SET1 */ +#define R367TER_TPS_RCVD5_SET1 0xf0ad +#define F367TER_TPS_NA 0xf0ad00fC +#define F367TER_TPS_SETFRAME 0xf0ad0003 + +/* TPS_SET2 */ +#define R367TER_TPS_SET2 0xf0ae +#define F367TER_TPS_SETHIERMODE 0xf0ae0070 +#define F367TER_TPS_SETCONST 0xf0ae0003 + +/* TPS_SET3 */ +#define R367TER_TPS_SET3 0xf0af +#define F367TER_TPS_SETLPCODE 0xf0af0070 +#define F367TER_TPS_SETHPCODE 0xf0af0007 + +/* TPS_CTL */ +#define R367TER_TPS_CTL 0xf0b0 +#define F367TER_TPS_IMM 0xf0b00004 +#define F367TER_TPS_BCHDIS 0xf0b00002 +#define F367TER_TPS_UPDDIS 0xf0b00001 + +/* CTL_FFTOSNUM */ +#define R367TER_CTL_FFTOSNUM 0xf0b1 +#define F367TER_SYMBOL_NUMBER 0xf0b1007f + +/* TESTSELECT */ +#define R367TER_TESTSELECT 0xf0b2 +#define F367TER_TEST_SELECT 0xf0b2001f + +/* MSC_REV */ +#define R367TER_MSC_REV 0xf0b3 +#define F367TER_REV_NUMBER 0xf0b300ff + +/* PIR_CTL */ +#define R367TER_PIR_CTL 0xf0b4 +#define F367TER_FREEZE 0xf0b40001 + +/* SNR_CARRIER1 */ +#define R367TER_SNR_CARRIER1 0xf0b5 +#define F367TER_SNR_CARRIER_LO 0xf0b500ff + +/* SNR_CARRIER2 */ +#define R367TER_SNR_CARRIER2 0xf0b6 +#define F367TER_MEAN 0xf0b600c0 +#define F367TER_SNR_CARRIER_HI 0xf0b6001f + +/* PPM_CPAMP */ +#define R367TER_PPM_CPAMP 0xf0b7 +#define F367TER_PPM_CPC 0xf0b700ff + +/* TSM_AP0 */ +#define R367TER_TSM_AP0 0xf0b8 +#define F367TER_ADDRESS_BYTE_0 0xf0b800ff + +/* TSM_AP1 */ +#define R367TER_TSM_AP1 0xf0b9 +#define F367TER_ADDRESS_BYTE_1 0xf0b900ff + +/* TSM_AP2 */ +#define R367TER_TSM_AP2 0xf0bA +#define F367TER_DATA_BYTE_0 0xf0ba00ff + +/* TSM_AP3 */ +#define R367TER_TSM_AP3 0xf0bB +#define F367TER_DATA_BYTE_1 0xf0bb00ff + +/* TSM_AP4 */ +#define R367TER_TSM_AP4 0xf0bC +#define F367TER_DATA_BYTE_2 0xf0bc00ff + +/* TSM_AP5 */ +#define R367TER_TSM_AP5 0xf0bD +#define F367TER_DATA_BYTE_3 0xf0bd00ff + +/* TSM_AP6 */ +#define R367TER_TSM_AP6 0xf0bE +#define F367TER_TSM_AP_6 0xf0be00ff + +/* TSM_AP7 */ +#define R367TER_TSM_AP7 0xf0bF +#define F367TER_MEM_SELECT_BYTE 0xf0bf00ff + +/* TSTRES */ +#define R367TER_TSTRES 0xf0c0 +#define F367TER_FRES_DISPLAY 0xf0c00080 +#define F367TER_FRES_FIFO_AD 0xf0c00020 +#define F367TER_FRESRS 0xf0c00010 +#define F367TER_FRESACS 0xf0c00008 +#define F367TER_FRESFEC 0xf0c00004 +#define F367TER_FRES_PRIF 0xf0c00002 +#define F367TER_FRESCORE 0xf0c00001 + +/* ANACTRL */ +#define R367TER_ANACTRL 0xf0c1 +#define F367TER_BYPASS_XTAL 0xf0c10040 +#define F367TER_BYPASS_PLLXN 0xf0c1000c +#define F367TER_DIS_PAD_OSC 0xf0c10002 +#define F367TER_STDBY_PLLXN 0xf0c10001 + +/* TSTBUS */ +#define R367TER_TSTBUS 0xf0c2 +#define F367TER_TS_BYTE_CLK_INV 0xf0c20080 +#define F367TER_CFG_IP 0xf0c20070 +#define F367TER_CFG_TST 0xf0c2000f + +/* TSTRATE */ +#define R367TER_TSTRATE 0xf0c6 +#define F367TER_FORCEPHA 0xf0c60080 +#define F367TER_FNEWPHA 0xf0c60010 +#define F367TER_FROT90 0xf0c60008 +#define F367TER_FR 0xf0c60007 + +/* CONSTMODE */ +#define R367TER_CONSTMODE 0xf0cb +#define F367TER_TST_PRIF 0xf0cb00e0 +#define F367TER_CAR_TYPE 0xf0cb0018 +#define F367TER_CONST_MODE 0xf0cb0003 + +/* CONSTCARR1 */ +#define R367TER_CONSTCARR1 0xf0cc +#define F367TER_CONST_CARR_LO 0xf0cc00ff + +/* CONSTCARR2 */ +#define R367TER_CONSTCARR2 0xf0cd +#define F367TER_CONST_CARR_HI 0xf0cd001f + +/* ICONSTEL */ +#define R367TER_ICONSTEL 0xf0ce +#define F367TER_PICONSTEL 0xf0ce00ff + +/* QCONSTEL */ +#define R367TER_QCONSTEL 0xf0cf +#define F367TER_PQCONSTEL 0xf0cf00ff + +/* TSTBISTRES0 */ +#define R367TER_TSTBISTRES0 0xf0d0 +#define F367TER_BEND_PPM 0xf0d00080 +#define F367TER_BBAD_PPM 0xf0d00040 +#define F367TER_BEND_FFTW 0xf0d00020 +#define F367TER_BBAD_FFTW 0xf0d00010 +#define F367TER_BEND_FFT_BUF 0xf0d00008 +#define F367TER_BBAD_FFT_BUF 0xf0d00004 +#define F367TER_BEND_SYR 0xf0d00002 +#define F367TER_BBAD_SYR 0xf0d00001 + +/* TSTBISTRES1 */ +#define R367TER_TSTBISTRES1 0xf0d1 +#define F367TER_BEND_CHC_CP 0xf0d10080 +#define F367TER_BBAD_CHC_CP 0xf0d10040 +#define F367TER_BEND_CHCI 0xf0d10020 +#define F367TER_BBAD_CHCI 0xf0d10010 +#define F367TER_BEND_BDI 0xf0d10008 +#define F367TER_BBAD_BDI 0xf0d10004 +#define F367TER_BEND_SDI 0xf0d10002 +#define F367TER_BBAD_SDI 0xf0d10001 + +/* TSTBISTRES2 */ +#define R367TER_TSTBISTRES2 0xf0d2 +#define F367TER_BEND_CHC_INC 0xf0d20080 +#define F367TER_BBAD_CHC_INC 0xf0d20040 +#define F367TER_BEND_CHC_SPP 0xf0d20020 +#define F367TER_BBAD_CHC_SPP 0xf0d20010 +#define F367TER_BEND_CHC_CPP 0xf0d20008 +#define F367TER_BBAD_CHC_CPP 0xf0d20004 +#define F367TER_BEND_CHC_SP 0xf0d20002 +#define F367TER_BBAD_CHC_SP 0xf0d20001 + +/* TSTBISTRES3 */ +#define R367TER_TSTBISTRES3 0xf0d3 +#define F367TER_BEND_QAM 0xf0d30080 +#define F367TER_BBAD_QAM 0xf0d30040 +#define F367TER_BEND_SFEC_VIT 0xf0d30020 +#define F367TER_BBAD_SFEC_VIT 0xf0d30010 +#define F367TER_BEND_SFEC_DLINE 0xf0d30008 +#define F367TER_BBAD_SFEC_DLINE 0xf0d30004 +#define F367TER_BEND_SFEC_HW 0xf0d30002 +#define F367TER_BBAD_SFEC_HW 0xf0d30001 + +/* RF_AGC1 */ +#define R367TER_RF_AGC1 0xf0d4 +#define F367TER_RF_AGC1_LEVEL_HI 0xf0d400ff + +/* RF_AGC2 */ +#define R367TER_RF_AGC2 0xf0d5 +#define F367TER_REF_ADGP 0xf0d50080 +#define F367TER_STDBY_ADCGP 0xf0d50020 +#define F367TER_CHANNEL_SEL 0xf0d5001c +#define F367TER_RF_AGC1_LEVEL_LO 0xf0d50003 + +/* ANADIGCTRL */ +#define R367TER_ANADIGCTRL 0xf0d7 +#define F367TER_SEL_CLKDEM 0xf0d70020 +#define F367TER_EN_BUFFER_Q 0xf0d70010 +#define F367TER_EN_BUFFER_I 0xf0d70008 +#define F367TER_ADC_RIS_EGDE 0xf0d70004 +#define F367TER_SGN_ADC 0xf0d70002 +#define F367TER_SEL_AD12_SYNC 0xf0d70001 + +/* PLLMDIV */ +#define R367TER_PLLMDIV 0xf0d8 +#define F367TER_PLL_MDIV 0xf0d800ff + +/* PLLNDIV */ +#define R367TER_PLLNDIV 0xf0d9 +#define F367TER_PLL_NDIV 0xf0d900ff + +/* PLLSETUP */ +#define R367TER_PLLSETUP 0xf0dA +#define F367TER_PLL_PDIV 0xf0da0070 +#define F367TER_PLL_KDIV 0xf0da000f + +/* DUAL_AD12 */ +#define R367TER_DUAL_AD12 0xf0dB +#define F367TER_FS20M 0xf0db0020 +#define F367TER_FS50M 0xf0db0010 +#define F367TER_INMODe0 0xf0db0008 +#define F367TER_POFFQ 0xf0db0004 +#define F367TER_POFFI 0xf0db0002 +#define F367TER_INMODE1 0xf0db0001 + +/* TSTBIST */ +#define R367TER_TSTBIST 0xf0dC +#define F367TER_TST_BYP_CLK 0xf0dc0080 +#define F367TER_TST_GCLKENA_STD 0xf0dc0040 +#define F367TER_TST_GCLKENA 0xf0dc0020 +#define F367TER_TST_MEMBIST 0xf0dc001f + +/* PAD_COMP_CTRL */ +#define R367TER_PAD_COMP_CTRL 0xf0dD +#define F367TER_COMPTQ 0xf0dd0010 +#define F367TER_COMPEN 0xf0dd0008 +#define F367TER_FREEZE2 0xf0dd0004 +#define F367TER_SLEEP_INHBT 0xf0dd0002 +#define F367TER_CHIP_SLEEP 0xf0dd0001 + +/* PAD_COMP_WR */ +#define R367TER_PAD_COMP_WR 0xf0de +#define F367TER_WR_ASRC 0xf0de007f + +/* PAD_COMP_RD */ +#define R367TER_PAD_COMP_RD 0xf0df +#define F367TER_COMPOK 0xf0df0080 +#define F367TER_RD_ASRC 0xf0df007f + +/* SYR_TARGET_FFTADJT_MSB */ +#define R367TER_SYR_TARGET_FFTADJT_MSB 0xf100 +#define F367TER_SYR_START 0xf1000080 +#define F367TER_SYR_TARGET_FFTADJ_HI 0xf100000f + +/* SYR_TARGET_FFTADJT_LSB */ +#define R367TER_SYR_TARGET_FFTADJT_LSB 0xf101 +#define F367TER_SYR_TARGET_FFTADJ_LO 0xf10100ff + +/* SYR_TARGET_CHCADJT_MSB */ +#define R367TER_SYR_TARGET_CHCADJT_MSB 0xf102 +#define F367TER_SYR_TARGET_CHCADJ_HI 0xf102000f + +/* SYR_TARGET_CHCADJT_LSB */ +#define R367TER_SYR_TARGET_CHCADJT_LSB 0xf103 +#define F367TER_SYR_TARGET_CHCADJ_LO 0xf10300ff + +/* SYR_FLAG */ +#define R367TER_SYR_FLAG 0xf104 +#define F367TER_TRIG_FLG1 0xf1040080 +#define F367TER_TRIG_FLG0 0xf1040040 +#define F367TER_FFT_FLG1 0xf1040008 +#define F367TER_FFT_FLG0 0xf1040004 +#define F367TER_CHC_FLG1 0xf1040002 +#define F367TER_CHC_FLG0 0xf1040001 + +/* CRL_TARGET1 */ +#define R367TER_CRL_TARGET1 0xf105 +#define F367TER_CRL_START 0xf1050080 +#define F367TER_CRL_TARGET_VHI 0xf105000f + +/* CRL_TARGET2 */ +#define R367TER_CRL_TARGET2 0xf106 +#define F367TER_CRL_TARGET_HI 0xf10600ff + +/* CRL_TARGET3 */ +#define R367TER_CRL_TARGET3 0xf107 +#define F367TER_CRL_TARGET_LO 0xf10700ff + +/* CRL_TARGET4 */ +#define R367TER_CRL_TARGET4 0xf108 +#define F367TER_CRL_TARGET_VLO 0xf10800ff + +/* CRL_FLAG */ +#define R367TER_CRL_FLAG 0xf109 +#define F367TER_CRL_FLAG1 0xf1090002 +#define F367TER_CRL_FLAG0 0xf1090001 + +/* TRL_TARGET1 */ +#define R367TER_TRL_TARGET1 0xf10a +#define F367TER_TRL_TARGET_HI 0xf10a00ff + +/* TRL_TARGET2 */ +#define R367TER_TRL_TARGET2 0xf10b +#define F367TER_TRL_TARGET_LO 0xf10b00ff + +/* TRL_CHC */ +#define R367TER_TRL_CHC 0xf10c +#define F367TER_TRL_START 0xf10c0080 +#define F367TER_CHC_START 0xf10c0040 +#define F367TER_TRL_FLAG1 0xf10c0002 +#define F367TER_TRL_FLAG0 0xf10c0001 + +/* CHC_SNR_TARG */ +#define R367TER_CHC_SNR_TARG 0xf10d +#define F367TER_CHC_SNR_TARGET 0xf10d00ff + +/* TOP_TRACK */ +#define R367TER_TOP_TRACK 0xf10e +#define F367TER_TOP_START 0xf10e0080 +#define F367TER_FIRST_FLAG 0xf10e0070 +#define F367TER_TOP_FLAG1 0xf10e0008 +#define F367TER_TOP_FLAG0 0xf10e0004 +#define F367TER_CHC_FLAG1 0xf10e0002 +#define F367TER_CHC_FLAG0 0xf10e0001 + +/* TRACKER_FREE1 */ +#define R367TER_TRACKER_FREE1 0xf10f +#define F367TER_TRACKER_FREE_1 0xf10f00ff + +/* ERROR_CRL1 */ +#define R367TER_ERROR_CRL1 0xf110 +#define F367TER_ERROR_CRL_VHI 0xf11000ff + +/* ERROR_CRL2 */ +#define R367TER_ERROR_CRL2 0xf111 +#define F367TER_ERROR_CRL_HI 0xf11100ff + +/* ERROR_CRL3 */ +#define R367TER_ERROR_CRL3 0xf112 +#define F367TER_ERROR_CRL_LOI 0xf11200ff + +/* ERROR_CRL4 */ +#define R367TER_ERROR_CRL4 0xf113 +#define F367TER_ERROR_CRL_VLO 0xf11300ff + +/* DEC_NCO1 */ +#define R367TER_DEC_NCO1 0xf114 +#define F367TER_DEC_NCO_VHI 0xf11400ff + +/* DEC_NCO2 */ +#define R367TER_DEC_NCO2 0xf115 +#define F367TER_DEC_NCO_HI 0xf11500ff + +/* DEC_NCO3 */ +#define R367TER_DEC_NCO3 0xf116 +#define F367TER_DEC_NCO_LO 0xf11600ff + +/* SNR */ +#define R367TER_SNR 0xf117 +#define F367TER_SNRATIO 0xf11700ff + +/* SYR_FFTADJ1 */ +#define R367TER_SYR_FFTADJ1 0xf118 +#define F367TER_SYR_FFTADJ_HI 0xf11800ff + +/* SYR_FFTADJ2 */ +#define R367TER_SYR_FFTADJ2 0xf119 +#define F367TER_SYR_FFTADJ_LO 0xf11900ff + +/* SYR_CHCADJ1 */ +#define R367TER_SYR_CHCADJ1 0xf11a +#define F367TER_SYR_CHCADJ_HI 0xf11a00ff + +/* SYR_CHCADJ2 */ +#define R367TER_SYR_CHCADJ2 0xf11b +#define F367TER_SYR_CHCADJ_LO 0xf11b00ff + +/* SYR_OFF */ +#define R367TER_SYR_OFF 0xf11c +#define F367TER_SYR_OFFSET 0xf11c00ff + +/* PPM_OFFSET1 */ +#define R367TER_PPM_OFFSET1 0xf11d +#define F367TER_PPM_OFFSET_HI 0xf11d00ff + +/* PPM_OFFSET2 */ +#define R367TER_PPM_OFFSET2 0xf11e +#define F367TER_PPM_OFFSET_LO 0xf11e00ff + +/* TRACKER_FREE2 */ +#define R367TER_TRACKER_FREE2 0xf11f +#define F367TER_TRACKER_FREE_2 0xf11f00ff + +/* DEBG_LT10 */ +#define R367TER_DEBG_LT10 0xf120 +#define F367TER_DEBUG_LT10 0xf12000ff + +/* DEBG_LT11 */ +#define R367TER_DEBG_LT11 0xf121 +#define F367TER_DEBUG_LT11 0xf12100ff + +/* DEBG_LT12 */ +#define R367TER_DEBG_LT12 0xf122 +#define F367TER_DEBUG_LT12 0xf12200ff + +/* DEBG_LT13 */ +#define R367TER_DEBG_LT13 0xf123 +#define F367TER_DEBUG_LT13 0xf12300ff + +/* DEBG_LT14 */ +#define R367TER_DEBG_LT14 0xf124 +#define F367TER_DEBUG_LT14 0xf12400ff + +/* DEBG_LT15 */ +#define R367TER_DEBG_LT15 0xf125 +#define F367TER_DEBUG_LT15 0xf12500ff + +/* DEBG_LT16 */ +#define R367TER_DEBG_LT16 0xf126 +#define F367TER_DEBUG_LT16 0xf12600ff + +/* DEBG_LT17 */ +#define R367TER_DEBG_LT17 0xf127 +#define F367TER_DEBUG_LT17 0xf12700ff + +/* DEBG_LT18 */ +#define R367TER_DEBG_LT18 0xf128 +#define F367TER_DEBUG_LT18 0xf12800ff + +/* DEBG_LT19 */ +#define R367TER_DEBG_LT19 0xf129 +#define F367TER_DEBUG_LT19 0xf12900ff + +/* DEBG_LT1a */ +#define R367TER_DEBG_LT1A 0xf12a +#define F367TER_DEBUG_LT1A 0xf12a00ff + +/* DEBG_LT1b */ +#define R367TER_DEBG_LT1B 0xf12b +#define F367TER_DEBUG_LT1B 0xf12b00ff + +/* DEBG_LT1c */ +#define R367TER_DEBG_LT1C 0xf12c +#define F367TER_DEBUG_LT1C 0xf12c00ff + +/* DEBG_LT1D */ +#define R367TER_DEBG_LT1D 0xf12d +#define F367TER_DEBUG_LT1D 0xf12d00ff + +/* DEBG_LT1E */ +#define R367TER_DEBG_LT1E 0xf12e +#define F367TER_DEBUG_LT1E 0xf12e00ff + +/* DEBG_LT1F */ +#define R367TER_DEBG_LT1F 0xf12f +#define F367TER_DEBUG_LT1F 0xf12f00ff + +/* RCCFGH */ +#define R367TER_RCCFGH 0xf200 +#define F367TER_TSRCFIFO_DVBCI 0xf2000080 +#define F367TER_TSRCFIFO_SERIAL 0xf2000040 +#define F367TER_TSRCFIFO_DISABLE 0xf2000020 +#define F367TER_TSFIFO_2TORC 0xf2000010 +#define F367TER_TSRCFIFO_HSGNLOUT 0xf2000008 +#define F367TER_TSRCFIFO_ERRMODE 0xf2000006 +#define F367TER_RCCFGH_0 0xf2000001 + +/* RCCFGM */ +#define R367TER_RCCFGM 0xf201 +#define F367TER_TSRCFIFO_MANSPEED 0xf20100c0 +#define F367TER_TSRCFIFO_PERMDATA 0xf2010020 +#define F367TER_TSRCFIFO_NONEWSGNL 0xf2010010 +#define F367TER_RCBYTE_OVERSAMPLING 0xf201000e +#define F367TER_TSRCFIFO_INVDATA 0xf2010001 + +/* RCCFGL */ +#define R367TER_RCCFGL 0xf202 +#define F367TER_TSRCFIFO_BCLKDEL1cK 0xf20200c0 +#define F367TER_RCCFGL_5 0xf2020020 +#define F367TER_TSRCFIFO_DUTY50 0xf2020010 +#define F367TER_TSRCFIFO_NSGNL2dATA 0xf2020008 +#define F367TER_TSRCFIFO_DISSERMUX 0xf2020004 +#define F367TER_RCCFGL_1 0xf2020002 +#define F367TER_TSRCFIFO_STOPCKDIS 0xf2020001 + +/* RCINSDELH */ +#define R367TER_RCINSDELH 0xf203 +#define F367TER_TSRCDEL_SYNCBYTE 0xf2030080 +#define F367TER_TSRCDEL_XXHEADER 0xf2030040 +#define F367TER_TSRCDEL_BBHEADER 0xf2030020 +#define F367TER_TSRCDEL_DATAFIELD 0xf2030010 +#define F367TER_TSRCINSDEL_ISCR 0xf2030008 +#define F367TER_TSRCINSDEL_NPD 0xf2030004 +#define F367TER_TSRCINSDEL_RSPARITY 0xf2030002 +#define F367TER_TSRCINSDEL_CRC8 0xf2030001 + +/* RCINSDELM */ +#define R367TER_RCINSDELM 0xf204 +#define F367TER_TSRCINS_BBPADDING 0xf2040080 +#define F367TER_TSRCINS_BCHFEC 0xf2040040 +#define F367TER_TSRCINS_LDPCFEC 0xf2040020 +#define F367TER_TSRCINS_EMODCOD 0xf2040010 +#define F367TER_TSRCINS_TOKEN 0xf2040008 +#define F367TER_TSRCINS_XXXERR 0xf2040004 +#define F367TER_TSRCINS_MATYPE 0xf2040002 +#define F367TER_TSRCINS_UPL 0xf2040001 + +/* RCINSDELL */ +#define R367TER_RCINSDELL 0xf205 +#define F367TER_TSRCINS_DFL 0xf2050080 +#define F367TER_TSRCINS_SYNCD 0xf2050040 +#define F367TER_TSRCINS_BLOCLEN 0xf2050020 +#define F367TER_TSRCINS_SIGPCOUNT 0xf2050010 +#define F367TER_TSRCINS_FIFO 0xf2050008 +#define F367TER_TSRCINS_REALPACK 0xf2050004 +#define F367TER_TSRCINS_TSCONFIG 0xf2050002 +#define F367TER_TSRCINS_LATENCY 0xf2050001 + +/* RCSTATUS */ +#define R367TER_RCSTATUS 0xf206 +#define F367TER_TSRCFIFO_LINEOK 0xf2060080 +#define F367TER_TSRCFIFO_ERROR 0xf2060040 +#define F367TER_TSRCFIFO_DATA7 0xf2060020 +#define F367TER_RCSTATUS_4 0xf2060010 +#define F367TER_TSRCFIFO_DEMODSEL 0xf2060008 +#define F367TER_TSRC1FIFOSPEED_STORE 0xf2060004 +#define F367TER_RCSTATUS_1 0xf2060002 +#define F367TER_TSRCSERIAL_IMPOSSIBLE 0xf2060001 + +/* RCSPEED */ +#define R367TER_RCSPEED 0xf207 +#define F367TER_TSRCFIFO_OUTSPEED 0xf20700ff + +/* RCDEBUGM */ +#define R367TER_RCDEBUGM 0xf208 +#define F367TER_SD_UNSYNC 0xf2080080 +#define F367TER_ULFLOCK_DETECTM 0xf2080040 +#define F367TER_SUL_SELECTOS 0xf2080020 +#define F367TER_DILUL_NOSCRBLE 0xf2080010 +#define F367TER_NUL_SCRB 0xf2080008 +#define F367TER_UL_SCRB 0xf2080004 +#define F367TER_SCRAULBAD 0xf2080002 +#define F367TER_SCRAUL_UNSYNC 0xf2080001 + +/* RCDEBUGL */ +#define R367TER_RCDEBUGL 0xf209 +#define F367TER_RS_ERR 0xf2090080 +#define F367TER_LLFLOCK_DETECTM 0xf2090040 +#define F367TER_NOT_SUL_SELECTOS 0xf2090020 +#define F367TER_DILLL_NOSCRBLE 0xf2090010 +#define F367TER_NLL_SCRB 0xf2090008 +#define F367TER_LL_SCRB 0xf2090004 +#define F367TER_SCRALLBAD 0xf2090002 +#define F367TER_SCRALL_UNSYNC 0xf2090001 + +/* RCOBSCFG */ +#define R367TER_RCOBSCFG 0xf20a +#define F367TER_TSRCFIFO_OBSCFG 0xf20a00ff + +/* RCOBSM */ +#define R367TER_RCOBSM 0xf20b +#define F367TER_TSRCFIFO_OBSDATA_HI 0xf20b00ff + +/* RCOBSL */ +#define R367TER_RCOBSL 0xf20c +#define F367TER_TSRCFIFO_OBSDATA_LO 0xf20c00ff + +/* RCFECSPY */ +#define R367TER_RCFECSPY 0xf210 +#define F367TER_SPYRC_ENABLE 0xf2100080 +#define F367TER_RCNO_SYNCBYTE 0xf2100040 +#define F367TER_RCSERIAL_MODE 0xf2100020 +#define F367TER_RCUNUSUAL_PACKET 0xf2100010 +#define F367TER_BERRCMETER_DATAMODE 0xf210000c +#define F367TER_BERRCMETER_LMODE 0xf2100002 +#define F367TER_BERRCMETER_RESET 0xf2100001 + +/* RCFSPYCFG */ +#define R367TER_RCFSPYCFG 0xf211 +#define F367TER_FECSPYRC_INPUT 0xf21100c0 +#define F367TER_RCRST_ON_ERROR 0xf2110020 +#define F367TER_RCONE_SHOT 0xf2110010 +#define F367TER_RCI2C_MODE 0xf211000c +#define F367TER_SPYRC_HSTERESIS 0xf2110003 + +/* RCFSPYDATA */ +#define R367TER_RCFSPYDATA 0xf212 +#define F367TER_SPYRC_STUFFING 0xf2120080 +#define F367TER_RCNOERR_PKTJITTER 0xf2120040 +#define F367TER_SPYRC_CNULLPKT 0xf2120020 +#define F367TER_SPYRC_OUTDATA_MODE 0xf212001f + +/* RCFSPYOUT */ +#define R367TER_RCFSPYOUT 0xf213 +#define F367TER_FSPYRC_DIRECT 0xf2130080 +#define F367TER_RCFSPYOUT_6 0xf2130040 +#define F367TER_SPYRC_OUTDATA_BUS 0xf2130038 +#define F367TER_RCSTUFF_MODE 0xf2130007 + +/* RCFSTATUS */ +#define R367TER_RCFSTATUS 0xf214 +#define F367TER_SPYRC_ENDSIM 0xf2140080 +#define F367TER_RCVALID_SIM 0xf2140040 +#define F367TER_RCFOUND_SIGNAL 0xf2140020 +#define F367TER_RCDSS_SYNCBYTE 0xf2140010 +#define F367TER_RCRESULT_STATE 0xf214000f + +/* RCFGOODPACK */ +#define R367TER_RCFGOODPACK 0xf215 +#define F367TER_RCGOOD_PACKET 0xf21500ff + +/* RCFPACKCNT */ +#define R367TER_RCFPACKCNT 0xf216 +#define F367TER_RCPACKET_COUNTER 0xf21600ff + +/* RCFSPYMISC */ +#define R367TER_RCFSPYMISC 0xf217 +#define F367TER_RCLABEL_COUNTER 0xf21700ff + +/* RCFBERCPT4 */ +#define R367TER_RCFBERCPT4 0xf218 +#define F367TER_FBERRCMETER_CPT_MMMMSB 0xf21800ff + +/* RCFBERCPT3 */ +#define R367TER_RCFBERCPT3 0xf219 +#define F367TER_FBERRCMETER_CPT_MMMSB 0xf21900ff + +/* RCFBERCPT2 */ +#define R367TER_RCFBERCPT2 0xf21a +#define F367TER_FBERRCMETER_CPT_MMSB 0xf21a00ff + +/* RCFBERCPT1 */ +#define R367TER_RCFBERCPT1 0xf21b +#define F367TER_FBERRCMETER_CPT_MSB 0xf21b00ff + +/* RCFBERCPT0 */ +#define R367TER_RCFBERCPT0 0xf21c +#define F367TER_FBERRCMETER_CPT_LSB 0xf21c00ff + +/* RCFBERERR2 */ +#define R367TER_RCFBERERR2 0xf21d +#define F367TER_FBERRCMETER_ERR_HI 0xf21d00ff + +/* RCFBERERR1 */ +#define R367TER_RCFBERERR1 0xf21e +#define F367TER_FBERRCMETER_ERR 0xf21e00ff + +/* RCFBERERR0 */ +#define R367TER_RCFBERERR0 0xf21f +#define F367TER_FBERRCMETER_ERR_LO 0xf21f00ff + +/* RCFSTATESM */ +#define R367TER_RCFSTATESM 0xf220 +#define F367TER_RCRSTATE_F 0xf2200080 +#define F367TER_RCRSTATE_E 0xf2200040 +#define F367TER_RCRSTATE_D 0xf2200020 +#define F367TER_RCRSTATE_C 0xf2200010 +#define F367TER_RCRSTATE_B 0xf2200008 +#define F367TER_RCRSTATE_A 0xf2200004 +#define F367TER_RCRSTATE_9 0xf2200002 +#define F367TER_RCRSTATE_8 0xf2200001 + +/* RCFSTATESL */ +#define R367TER_RCFSTATESL 0xf221 +#define F367TER_RCRSTATE_7 0xf2210080 +#define F367TER_RCRSTATE_6 0xf2210040 +#define F367TER_RCRSTATE_5 0xf2210020 +#define F367TER_RCRSTATE_4 0xf2210010 +#define F367TER_RCRSTATE_3 0xf2210008 +#define F367TER_RCRSTATE_2 0xf2210004 +#define F367TER_RCRSTATE_1 0xf2210002 +#define F367TER_RCRSTATE_0 0xf2210001 + +/* RCFSPYBER */ +#define R367TER_RCFSPYBER 0xf222 +#define F367TER_RCFSPYBER_7 0xf2220080 +#define F367TER_SPYRCOBS_XORREAD 0xf2220040 +#define F367TER_FSPYRCBER_OBSMODE 0xf2220020 +#define F367TER_FSPYRCBER_SYNCBYT 0xf2220010 +#define F367TER_FSPYRCBER_UNSYNC 0xf2220008 +#define F367TER_FSPYRCBER_CTIME 0xf2220007 + +/* RCFSPYDISTM */ +#define R367TER_RCFSPYDISTM 0xf223 +#define F367TER_RCPKTTIME_DISTANCE_HI 0xf22300ff + +/* RCFSPYDISTL */ +#define R367TER_RCFSPYDISTL 0xf224 +#define F367TER_RCPKTTIME_DISTANCE_LO 0xf22400ff + +/* RCFSPYOBS7 */ +#define R367TER_RCFSPYOBS7 0xf228 +#define F367TER_RCSPYOBS_SPYFAIL 0xf2280080 +#define F367TER_RCSPYOBS_SPYFAIL1 0xf2280040 +#define F367TER_RCSPYOBS_ERROR 0xf2280020 +#define F367TER_RCSPYOBS_STROUT 0xf2280010 +#define F367TER_RCSPYOBS_RESULTSTATE1 0xf228000f + +/* RCFSPYOBS6 */ +#define R367TER_RCFSPYOBS6 0xf229 +#define F367TER_RCSPYOBS_RESULTSTATe0 0xf22900f0 +#define F367TER_RCSPYOBS_RESULTSTATEM1 0xf229000f + +/* RCFSPYOBS5 */ +#define R367TER_RCFSPYOBS5 0xf22a +#define F367TER_RCSPYOBS_BYTEOFPACKET1 0xf22a00ff + +/* RCFSPYOBS4 */ +#define R367TER_RCFSPYOBS4 0xf22b +#define F367TER_RCSPYOBS_BYTEVALUE1 0xf22b00ff + +/* RCFSPYOBS3 */ +#define R367TER_RCFSPYOBS3 0xf22c +#define F367TER_RCSPYOBS_DATA1 0xf22c00ff + +/* RCFSPYOBS2 */ +#define R367TER_RCFSPYOBS2 0xf22d +#define F367TER_RCSPYOBS_DATa0 0xf22d00ff + +/* RCFSPYOBS1 */ +#define R367TER_RCFSPYOBS1 0xf22e +#define F367TER_RCSPYOBS_DATAM1 0xf22e00ff + +/* RCFSPYOBS0 */ +#define R367TER_RCFSPYOBS0 0xf22f +#define F367TER_RCSPYOBS_DATAM2 0xf22f00ff + +/* TSGENERAL */ +#define R367TER_TSGENERAL 0xf230 +#define F367TER_TSGENERAL_7 0xf2300080 +#define F367TER_TSGENERAL_6 0xf2300040 +#define F367TER_TSFIFO_BCLK1aLL 0xf2300020 +#define F367TER_TSGENERAL_4 0xf2300010 +#define F367TER_MUXSTREAM_OUTMODE 0xf2300008 +#define F367TER_TSFIFO_PERMPARAL 0xf2300006 +#define F367TER_RST_REEDSOLO 0xf2300001 + +/* RC1SPEED */ +#define R367TER_RC1SPEED 0xf231 +#define F367TER_TSRCFIFO1_OUTSPEED 0xf23100ff + +/* TSGSTATUS */ +#define R367TER_TSGSTATUS 0xf232 +#define F367TER_TSGSTATUS_7 0xf2320080 +#define F367TER_TSGSTATUS_6 0xf2320040 +#define F367TER_RSMEM_FULL 0xf2320020 +#define F367TER_RS_MULTCALC 0xf2320010 +#define F367TER_RSIN_OVERTIME 0xf2320008 +#define F367TER_TSFIFO3_DEMODSEL 0xf2320004 +#define F367TER_TSFIFO2_DEMODSEL 0xf2320002 +#define F367TER_TSFIFO1_DEMODSEL 0xf2320001 + + +/* FECM */ +#define R367TER_FECM 0xf233 +#define F367TER_DSS_DVB 0xf2330080 +#define F367TER_DEMOD_BYPASS 0xf2330040 +#define F367TER_CMP_SLOWMODE 0xf2330020 +#define F367TER_DSS_SRCH 0xf2330010 +#define F367TER_FECM_3 0xf2330008 +#define F367TER_DIFF_MODEVIT 0xf2330004 +#define F367TER_SYNCVIT 0xf2330002 +#define F367TER_I2CSYM 0xf2330001 + +/* VTH12 */ +#define R367TER_VTH12 0xf234 +#define F367TER_VTH_12 0xf23400ff + +/* VTH23 */ +#define R367TER_VTH23 0xf235 +#define F367TER_VTH_23 0xf23500ff + +/* VTH34 */ +#define R367TER_VTH34 0xf236 +#define F367TER_VTH_34 0xf23600ff + +/* VTH56 */ +#define R367TER_VTH56 0xf237 +#define F367TER_VTH_56 0xf23700ff + +/* VTH67 */ +#define R367TER_VTH67 0xf238 +#define F367TER_VTH_67 0xf23800ff + +/* VTH78 */ +#define R367TER_VTH78 0xf239 +#define F367TER_VTH_78 0xf23900ff + +/* VITCURPUN */ +#define R367TER_VITCURPUN 0xf23a +#define F367TER_VIT_MAPPING 0xf23a00e0 +#define F367TER_VIT_CURPUN 0xf23a001f + +/* VERROR */ +#define R367TER_VERROR 0xf23b +#define F367TER_REGERR_VIT 0xf23b00ff + +/* PRVIT */ +#define R367TER_PRVIT 0xf23c +#define F367TER_PRVIT_7 0xf23c0080 +#define F367TER_DIS_VTHLOCK 0xf23c0040 +#define F367TER_E7_8VIT 0xf23c0020 +#define F367TER_E6_7VIT 0xf23c0010 +#define F367TER_E5_6VIT 0xf23c0008 +#define F367TER_E3_4VIT 0xf23c0004 +#define F367TER_E2_3VIT 0xf23c0002 +#define F367TER_E1_2VIT 0xf23c0001 + +/* VAVSRVIT */ +#define R367TER_VAVSRVIT 0xf23d +#define F367TER_AMVIT 0xf23d0080 +#define F367TER_FROZENVIT 0xf23d0040 +#define F367TER_SNVIT 0xf23d0030 +#define F367TER_TOVVIT 0xf23d000c +#define F367TER_HYPVIT 0xf23d0003 + +/* VSTATUSVIT */ +#define R367TER_VSTATUSVIT 0xf23e +#define F367TER_VITERBI_ON 0xf23e0080 +#define F367TER_END_LOOPVIT 0xf23e0040 +#define F367TER_VITERBI_DEPRF 0xf23e0020 +#define F367TER_PRFVIT 0xf23e0010 +#define F367TER_LOCKEDVIT 0xf23e0008 +#define F367TER_VITERBI_DELOCK 0xf23e0004 +#define F367TER_VIT_DEMODSEL 0xf23e0002 +#define F367TER_VITERBI_COMPOUT 0xf23e0001 + +/* VTHINUSE */ +#define R367TER_VTHINUSE 0xf23f +#define F367TER_VIT_INUSE 0xf23f00ff + +/* KDIV12 */ +#define R367TER_KDIV12 0xf240 +#define F367TER_KDIV12_MANUAL 0xf2400080 +#define F367TER_K_DIVIDER_12 0xf240007f + +/* KDIV23 */ +#define R367TER_KDIV23 0xf241 +#define F367TER_KDIV23_MANUAL 0xf2410080 +#define F367TER_K_DIVIDER_23 0xf241007f + +/* KDIV34 */ +#define R367TER_KDIV34 0xf242 +#define F367TER_KDIV34_MANUAL 0xf2420080 +#define F367TER_K_DIVIDER_34 0xf242007f + +/* KDIV56 */ +#define R367TER_KDIV56 0xf243 +#define F367TER_KDIV56_MANUAL 0xf2430080 +#define F367TER_K_DIVIDER_56 0xf243007f + +/* KDIV67 */ +#define R367TER_KDIV67 0xf244 +#define F367TER_KDIV67_MANUAL 0xf2440080 +#define F367TER_K_DIVIDER_67 0xf244007f + +/* KDIV78 */ +#define R367TER_KDIV78 0xf245 +#define F367TER_KDIV78_MANUAL 0xf2450080 +#define F367TER_K_DIVIDER_78 0xf245007f + +/* SIGPOWER */ +#define R367TER_SIGPOWER 0xf246 +#define F367TER_SIGPOWER_MANUAL 0xf2460080 +#define F367TER_SIG_POWER 0xf246007f + +/* DEMAPVIT */ +#define R367TER_DEMAPVIT 0xf247 +#define F367TER_DEMAPVIT_7 0xf2470080 +#define F367TER_K_DIVIDER_VIT 0xf247007f + +/* VITSCALE */ +#define R367TER_VITSCALE 0xf248 +#define F367TER_NVTH_NOSRANGE 0xf2480080 +#define F367TER_VERROR_MAXMODE 0xf2480040 +#define F367TER_KDIV_MODE 0xf2480030 +#define F367TER_NSLOWSN_LOCKED 0xf2480008 +#define F367TER_DELOCK_PRFLOSS 0xf2480004 +#define F367TER_DIS_RSFLOCK 0xf2480002 +#define F367TER_VITSCALE_0 0xf2480001 + +/* FFEC1PRG */ +#define R367TER_FFEC1PRG 0xf249 +#define F367TER_FDSS_DVB 0xf2490080 +#define F367TER_FDSS_SRCH 0xf2490040 +#define F367TER_FFECPROG_5 0xf2490020 +#define F367TER_FFECPROG_4 0xf2490010 +#define F367TER_FFECPROG_3 0xf2490008 +#define F367TER_FFECPROG_2 0xf2490004 +#define F367TER_FTS1_DISABLE 0xf2490002 +#define F367TER_FTS2_DISABLE 0xf2490001 + +/* FVITCURPUN */ +#define R367TER_FVITCURPUN 0xf24a +#define F367TER_FVIT_MAPPING 0xf24a00e0 +#define F367TER_FVIT_CURPUN 0xf24a001f + +/* FVERROR */ +#define R367TER_FVERROR 0xf24b +#define F367TER_FREGERR_VIT 0xf24b00ff + +/* FVSTATUSVIT */ +#define R367TER_FVSTATUSVIT 0xf24c +#define F367TER_FVITERBI_ON 0xf24c0080 +#define F367TER_F1END_LOOPVIT 0xf24c0040 +#define F367TER_FVITERBI_DEPRF 0xf24c0020 +#define F367TER_FPRFVIT 0xf24c0010 +#define F367TER_FLOCKEDVIT 0xf24c0008 +#define F367TER_FVITERBI_DELOCK 0xf24c0004 +#define F367TER_FVIT_DEMODSEL 0xf24c0002 +#define F367TER_FVITERBI_COMPOUT 0xf24c0001 + +/* DEBUG_LT1 */ +#define R367TER_DEBUG_LT1 0xf24d +#define F367TER_DBG_LT1 0xf24d00ff + +/* DEBUG_LT2 */ +#define R367TER_DEBUG_LT2 0xf24e +#define F367TER_DBG_LT2 0xf24e00ff + +/* DEBUG_LT3 */ +#define R367TER_DEBUG_LT3 0xf24f +#define F367TER_DBG_LT3 0xf24f00ff + +/* TSTSFMET */ +#define R367TER_TSTSFMET 0xf250 +#define F367TER_TSTSFEC_METRIQUES 0xf25000ff + +/* SELOUT */ +#define R367TER_SELOUT 0xf252 +#define F367TER_EN_SYNC 0xf2520080 +#define F367TER_EN_TBUSDEMAP 0xf2520040 +#define F367TER_SELOUT_5 0xf2520020 +#define F367TER_SELOUT_4 0xf2520010 +#define F367TER_TSTSYNCHRO_MODE 0xf2520002 + +/* TSYNC */ +#define R367TER_TSYNC 0xf253 +#define F367TER_CURPUN_INCMODE 0xf2530080 +#define F367TER_CERR_TSTMODE 0xf2530040 +#define F367TER_SHIFTSOF_MODE 0xf2530030 +#define F367TER_SLOWPHA_MODE 0xf2530008 +#define F367TER_PXX_BYPALL 0xf2530004 +#define F367TER_FROTA45_FIRST 0xf2530002 +#define F367TER_TST_BCHERROR 0xf2530001 + +/* TSTERR */ +#define R367TER_TSTERR 0xf254 +#define F367TER_TST_LONGPKT 0xf2540080 +#define F367TER_TST_ISSYION 0xf2540040 +#define F367TER_TST_NPDON 0xf2540020 +#define F367TER_TSTERR_4 0xf2540010 +#define F367TER_TRACEBACK_MODE 0xf2540008 +#define F367TER_TST_RSPARITY 0xf2540004 +#define F367TER_METRIQUE_MODE 0xf2540003 + +/* TSFSYNC */ +#define R367TER_TSFSYNC 0xf255 +#define F367TER_EN_SFECSYNC 0xf2550080 +#define F367TER_EN_SFECDEMAP 0xf2550040 +#define F367TER_SFCERR_TSTMODE 0xf2550020 +#define F367TER_SFECPXX_BYPALL 0xf2550010 +#define F367TER_SFECTSTSYNCHRO_MODE 0xf255000f + +/* TSTSFERR */ +#define R367TER_TSTSFERR 0xf256 +#define F367TER_TSTSTERR_7 0xf2560080 +#define F367TER_TSTSTERR_6 0xf2560040 +#define F367TER_TSTSTERR_5 0xf2560020 +#define F367TER_TSTSTERR_4 0xf2560010 +#define F367TER_SFECTRACEBACK_MODE 0xf2560008 +#define F367TER_SFEC_NCONVPROG 0xf2560004 +#define F367TER_SFECMETRIQUE_MODE 0xf2560003 + +/* TSTTSSF1 */ +#define R367TER_TSTTSSF1 0xf258 +#define F367TER_TSTERSSF 0xf2580080 +#define F367TER_TSTTSSFEN 0xf2580040 +#define F367TER_SFEC_OUTMODE 0xf2580030 +#define F367TER_XLSF_NOFTHRESHOLD 0xf2580008 +#define F367TER_TSTTSSF_STACKSEL 0xf2580007 + +/* TSTTSSF2 */ +#define R367TER_TSTTSSF2 0xf259 +#define F367TER_DILSF_DBBHEADER 0xf2590080 +#define F367TER_TSTTSSF_DISBUG 0xf2590040 +#define F367TER_TSTTSSF_NOBADSTART 0xf2590020 +#define F367TER_TSTTSSF_SELECT 0xf259001f + +/* TSTTSSF3 */ +#define R367TER_TSTTSSF3 0xf25a +#define F367TER_TSTTSSF3_7 0xf25a0080 +#define F367TER_TSTTSSF3_6 0xf25a0040 +#define F367TER_TSTTSSF3_5 0xf25a0020 +#define F367TER_TSTTSSF3_4 0xf25a0010 +#define F367TER_TSTTSSF3_3 0xf25a0008 +#define F367TER_TSTTSSF3_2 0xf25a0004 +#define F367TER_TSTTSSF3_1 0xf25a0002 +#define F367TER_DISSF_CLKENABLE 0xf25a0001 + +/* TSTTS1 */ +#define R367TER_TSTTS1 0xf25c +#define F367TER_TSTERS 0xf25c0080 +#define F367TER_TSFIFO_DSSSYNCB 0xf25c0040 +#define F367TER_TSTTS_FSPYBEFRS 0xf25c0020 +#define F367TER_NFORCE_SYNCBYTE 0xf25c0010 +#define F367TER_XL_NOFTHRESHOLD 0xf25c0008 +#define F367TER_TSTTS_FRFORCEPKT 0xf25c0004 +#define F367TER_DESCR_NOTAUTO 0xf25c0002 +#define F367TER_TSTTSEN 0xf25c0001 + +/* TSTTS2 */ +#define R367TER_TSTTS2 0xf25d +#define F367TER_DIL_DBBHEADER 0xf25d0080 +#define F367TER_TSTTS_NOBADXXX 0xf25d0040 +#define F367TER_TSFIFO_DELSPEEDUP 0xf25d0020 +#define F367TER_TSTTS_SELECT 0xf25d001f + +/* TSTTS3 */ +#define R367TER_TSTTS3 0xf25e +#define F367TER_TSTTS_NOPKTGAIN 0xf25e0080 +#define F367TER_TSTTS_NOPKTENE 0xf25e0040 +#define F367TER_TSTTS_ISOLATION 0xf25e0020 +#define F367TER_TSTTS_DISBUG 0xf25e0010 +#define F367TER_TSTTS_NOBADSTART 0xf25e0008 +#define F367TER_TSTTS_STACKSEL 0xf25e0007 + +/* TSTTS4 */ +#define R367TER_TSTTS4 0xf25f +#define F367TER_TSTTS4_7 0xf25f0080 +#define F367TER_TSTTS4_6 0xf25f0040 +#define F367TER_TSTTS4_5 0xf25f0020 +#define F367TER_TSTTS_DISDSTATE 0xf25f0010 +#define F367TER_TSTTS_FASTNOSYNC 0xf25f0008 +#define F367TER_EXT_FECSPYIN 0xf25f0004 +#define F367TER_TSTTS_NODPZERO 0xf25f0002 +#define F367TER_TSTTS_NODIV3 0xf25f0001 + +/* TSTTSRC */ +#define R367TER_TSTTSRC 0xf26c +#define F367TER_TSTTSRC_7 0xf26c0080 +#define F367TER_TSRCFIFO_DSSSYNCB 0xf26c0040 +#define F367TER_TSRCFIFO_DPUNACTIVE 0xf26c0020 +#define F367TER_TSRCFIFO_DELSPEEDUP 0xf26c0010 +#define F367TER_TSTTSRC_NODIV3 0xf26c0008 +#define F367TER_TSTTSRC_FRFORCEPKT 0xf26c0004 +#define F367TER_SAT25_SDDORIGINE 0xf26c0002 +#define F367TER_TSTTSRC_INACTIVE 0xf26c0001 + +/* TSTTSRS */ +#define R367TER_TSTTSRS 0xf26d +#define F367TER_TSTTSRS_7 0xf26d0080 +#define F367TER_TSTTSRS_6 0xf26d0040 +#define F367TER_TSTTSRS_5 0xf26d0020 +#define F367TER_TSTTSRS_4 0xf26d0010 +#define F367TER_TSTTSRS_3 0xf26d0008 +#define F367TER_TSTTSRS_2 0xf26d0004 +#define F367TER_TSTRS_DISRS2 0xf26d0002 +#define F367TER_TSTRS_DISRS1 0xf26d0001 + +/* TSSTATEM */ +#define R367TER_TSSTATEM 0xf270 +#define F367TER_TSDIL_ON 0xf2700080 +#define F367TER_TSSKIPRS_ON 0xf2700040 +#define F367TER_TSRS_ON 0xf2700020 +#define F367TER_TSDESCRAMB_ON 0xf2700010 +#define F367TER_TSFRAME_MODE 0xf2700008 +#define F367TER_TS_DISABLE 0xf2700004 +#define F367TER_TSACM_MODE 0xf2700002 +#define F367TER_TSOUT_NOSYNC 0xf2700001 + +/* TSSTATEL */ +#define R367TER_TSSTATEL 0xf271 +#define F367TER_TSNOSYNCBYTE 0xf2710080 +#define F367TER_TSPARITY_ON 0xf2710040 +#define F367TER_TSSYNCOUTRS_ON 0xf2710020 +#define F367TER_TSDVBS2_MODE 0xf2710010 +#define F367TER_TSISSYI_ON 0xf2710008 +#define F367TER_TSNPD_ON 0xf2710004 +#define F367TER_TSCRC8_ON 0xf2710002 +#define F367TER_TSDSS_PACKET 0xf2710001 + +/* TSCFGH */ +#define R367TER_TSCFGH 0xf272 +#define F367TER_TSFIFO_DVBCI 0xf2720080 +#define F367TER_TSFIFO_SERIAL 0xf2720040 +#define F367TER_TSFIFO_TEIUPDATE 0xf2720020 +#define F367TER_TSFIFO_DUTY50 0xf2720010 +#define F367TER_TSFIFO_HSGNLOUT 0xf2720008 +#define F367TER_TSFIFO_ERRMODE 0xf2720006 +#define F367TER_RST_HWARE 0xf2720001 + +/* TSCFGM */ +#define R367TER_TSCFGM 0xf273 +#define F367TER_TSFIFO_MANSPEED 0xf27300c0 +#define F367TER_TSFIFO_PERMDATA 0xf2730020 +#define F367TER_TSFIFO_NONEWSGNL 0xf2730010 +#define F367TER_TSFIFO_BITSPEED 0xf2730008 +#define F367TER_NPD_SPECDVBS2 0xf2730004 +#define F367TER_TSFIFO_STOPCKDIS 0xf2730002 +#define F367TER_TSFIFO_INVDATA 0xf2730001 + +/* TSCFGL */ +#define R367TER_TSCFGL 0xf274 +#define F367TER_TSFIFO_BCLKDEL1cK 0xf27400c0 +#define F367TER_BCHERROR_MODE 0xf2740030 +#define F367TER_TSFIFO_NSGNL2dATA 0xf2740008 +#define F367TER_TSFIFO_EMBINDVB 0xf2740004 +#define F367TER_TSFIFO_DPUNACT 0xf2740002 +#define F367TER_TSFIFO_NPDOFF 0xf2740001 + +/* TSSYNC */ +#define R367TER_TSSYNC 0xf275 +#define F367TER_TSFIFO_PERMUTE 0xf2750080 +#define F367TER_TSFIFO_FISCR3B 0xf2750060 +#define F367TER_TSFIFO_SYNCMODE 0xf2750018 +#define F367TER_TSFIFO_SYNCSEL 0xf2750007 + +/* TSINSDELH */ +#define R367TER_TSINSDELH 0xf276 +#define F367TER_TSDEL_SYNCBYTE 0xf2760080 +#define F367TER_TSDEL_XXHEADER 0xf2760040 +#define F367TER_TSDEL_BBHEADER 0xf2760020 +#define F367TER_TSDEL_DATAFIELD 0xf2760010 +#define F367TER_TSINSDEL_ISCR 0xf2760008 +#define F367TER_TSINSDEL_NPD 0xf2760004 +#define F367TER_TSINSDEL_RSPARITY 0xf2760002 +#define F367TER_TSINSDEL_CRC8 0xf2760001 + +/* TSINSDELM */ +#define R367TER_TSINSDELM 0xf277 +#define F367TER_TSINS_BBPADDING 0xf2770080 +#define F367TER_TSINS_BCHFEC 0xf2770040 +#define F367TER_TSINS_LDPCFEC 0xf2770020 +#define F367TER_TSINS_EMODCOD 0xf2770010 +#define F367TER_TSINS_TOKEN 0xf2770008 +#define F367TER_TSINS_XXXERR 0xf2770004 +#define F367TER_TSINS_MATYPE 0xf2770002 +#define F367TER_TSINS_UPL 0xf2770001 + +/* TSINSDELL */ +#define R367TER_TSINSDELL 0xf278 +#define F367TER_TSINS_DFL 0xf2780080 +#define F367TER_TSINS_SYNCD 0xf2780040 +#define F367TER_TSINS_BLOCLEN 0xf2780020 +#define F367TER_TSINS_SIGPCOUNT 0xf2780010 +#define F367TER_TSINS_FIFO 0xf2780008 +#define F367TER_TSINS_REALPACK 0xf2780004 +#define F367TER_TSINS_TSCONFIG 0xf2780002 +#define F367TER_TSINS_LATENCY 0xf2780001 + +/* TSDIVN */ +#define R367TER_TSDIVN 0xf279 +#define F367TER_TSFIFO_LOWSPEED 0xf2790080 +#define F367TER_BYTE_OVERSAMPLING 0xf2790070 +#define F367TER_TSMANUAL_PACKETNBR 0xf279000f + +/* TSDIVPM */ +#define R367TER_TSDIVPM 0xf27a +#define F367TER_TSMANUAL_P_HI 0xf27a00ff + +/* TSDIVPL */ +#define R367TER_TSDIVPL 0xf27b +#define F367TER_TSMANUAL_P_LO 0xf27b00ff + +/* TSDIVQM */ +#define R367TER_TSDIVQM 0xf27c +#define F367TER_TSMANUAL_Q_HI 0xf27c00ff + +/* TSDIVQL */ +#define R367TER_TSDIVQL 0xf27d +#define F367TER_TSMANUAL_Q_LO 0xf27d00ff + +/* TSDILSTKM */ +#define R367TER_TSDILSTKM 0xf27e +#define F367TER_TSFIFO_DILSTK_HI 0xf27e00ff + +/* TSDILSTKL */ +#define R367TER_TSDILSTKL 0xf27f +#define F367TER_TSFIFO_DILSTK_LO 0xf27f00ff + +/* TSSPEED */ +#define R367TER_TSSPEED 0xf280 +#define F367TER_TSFIFO_OUTSPEED 0xf28000ff + +/* TSSTATUS */ +#define R367TER_TSSTATUS 0xf281 +#define F367TER_TSFIFO_LINEOK 0xf2810080 +#define F367TER_TSFIFO_ERROR 0xf2810040 +#define F367TER_TSFIFO_DATA7 0xf2810020 +#define F367TER_TSFIFO_NOSYNC 0xf2810010 +#define F367TER_ISCR_INITIALIZED 0xf2810008 +#define F367TER_ISCR_UPDATED 0xf2810004 +#define F367TER_SOFFIFO_UNREGUL 0xf2810002 +#define F367TER_DIL_READY 0xf2810001 + +/* TSSTATUS2 */ +#define R367TER_TSSTATUS2 0xf282 +#define F367TER_TSFIFO_DEMODSEL 0xf2820080 +#define F367TER_TSFIFOSPEED_STORE 0xf2820040 +#define F367TER_DILXX_RESET 0xf2820020 +#define F367TER_TSSERIAL_IMPOSSIBLE 0xf2820010 +#define F367TER_TSFIFO_UNDERSPEED 0xf2820008 +#define F367TER_BITSPEED_EVENT 0xf2820004 +#define F367TER_UL_SCRAMBDETECT 0xf2820002 +#define F367TER_ULDTV67_FALSELOCK 0xf2820001 + +/* TSBITRATEM */ +#define R367TER_TSBITRATEM 0xf283 +#define F367TER_TSFIFO_BITRATE_HI 0xf28300ff + +/* TSBITRATEL */ +#define R367TER_TSBITRATEL 0xf284 +#define F367TER_TSFIFO_BITRATE_LO 0xf28400ff + +/* TSPACKLENM */ +#define R367TER_TSPACKLENM 0xf285 +#define F367TER_TSFIFO_PACKCPT 0xf28500e0 +#define F367TER_DIL_RPLEN_HI 0xf285001f + +/* TSPACKLENL */ +#define R367TER_TSPACKLENL 0xf286 +#define F367TER_DIL_RPLEN_LO 0xf28600ff + +/* TSBLOCLENM */ +#define R367TER_TSBLOCLENM 0xf287 +#define F367TER_TSFIFO_PFLEN_HI 0xf28700ff + +/* TSBLOCLENL */ +#define R367TER_TSBLOCLENL 0xf288 +#define F367TER_TSFIFO_PFLEN_LO 0xf28800ff + +/* TSDLYH */ +#define R367TER_TSDLYH 0xf289 +#define F367TER_SOFFIFO_TSTIMEVALID 0xf2890080 +#define F367TER_SOFFIFO_SPEEDUP 0xf2890040 +#define F367TER_SOFFIFO_STOP 0xf2890020 +#define F367TER_SOFFIFO_REGULATED 0xf2890010 +#define F367TER_SOFFIFO_REALSBOFF_HI 0xf289000f + +/* TSDLYM */ +#define R367TER_TSDLYM 0xf28a +#define F367TER_SOFFIFO_REALSBOFF_MED 0xf28a00ff + +/* TSDLYL */ +#define R367TER_TSDLYL 0xf28b +#define F367TER_SOFFIFO_REALSBOFF_LO 0xf28b00ff + +/* TSNPDAV */ +#define R367TER_TSNPDAV 0xf28c +#define F367TER_TSNPD_AVERAGE 0xf28c00ff + +/* TSBUFSTATH */ +#define R367TER_TSBUFSTATH 0xf28d +#define F367TER_TSISCR_3BYTES 0xf28d0080 +#define F367TER_TSISCR_NEWDATA 0xf28d0040 +#define F367TER_TSISCR_BUFSTAT_HI 0xf28d003f + +/* TSBUFSTATM */ +#define R367TER_TSBUFSTATM 0xf28e +#define F367TER_TSISCR_BUFSTAT_MED 0xf28e00ff + +/* TSBUFSTATL */ +#define R367TER_TSBUFSTATL 0xf28f +#define F367TER_TSISCR_BUFSTAT_LO 0xf28f00ff + +/* TSDEBUGM */ +#define R367TER_TSDEBUGM 0xf290 +#define F367TER_TSFIFO_ILLPACKET 0xf2900080 +#define F367TER_DIL_NOSYNC 0xf2900040 +#define F367TER_DIL_ISCR 0xf2900020 +#define F367TER_DILOUT_BSYNCB 0xf2900010 +#define F367TER_TSFIFO_EMPTYPKT 0xf2900008 +#define F367TER_TSFIFO_EMPTYRD 0xf2900004 +#define F367TER_SOFFIFO_STOPM 0xf2900002 +#define F367TER_SOFFIFO_SPEEDUPM 0xf2900001 + +/* TSDEBUGL */ +#define R367TER_TSDEBUGL 0xf291 +#define F367TER_TSFIFO_PACKLENFAIL 0xf2910080 +#define F367TER_TSFIFO_SYNCBFAIL 0xf2910040 +#define F367TER_TSFIFO_VITLIBRE 0xf2910020 +#define F367TER_TSFIFO_BOOSTSPEEDM 0xf2910010 +#define F367TER_TSFIFO_UNDERSPEEDM 0xf2910008 +#define F367TER_TSFIFO_ERROR_EVNT 0xf2910004 +#define F367TER_TSFIFO_FULL 0xf2910002 +#define F367TER_TSFIFO_OVERFLOWM 0xf2910001 + +/* TSDLYSETH */ +#define R367TER_TSDLYSETH 0xf292 +#define F367TER_SOFFIFO_OFFSET 0xf29200e0 +#define F367TER_SOFFIFO_SYMBOFFSET_HI 0xf292001f + +/* TSDLYSETM */ +#define R367TER_TSDLYSETM 0xf293 +#define F367TER_SOFFIFO_SYMBOFFSET_MED 0xf29300ff + +/* TSDLYSETL */ +#define R367TER_TSDLYSETL 0xf294 +#define F367TER_SOFFIFO_SYMBOFFSET_LO 0xf29400ff + +/* TSOBSCFG */ +#define R367TER_TSOBSCFG 0xf295 +#define F367TER_TSFIFO_OBSCFG 0xf29500ff + +/* TSOBSM */ +#define R367TER_TSOBSM 0xf296 +#define F367TER_TSFIFO_OBSDATA_HI 0xf29600ff + +/* TSOBSL */ +#define R367TER_TSOBSL 0xf297 +#define F367TER_TSFIFO_OBSDATA_LO 0xf29700ff + +/* ERRCTRL1 */ +#define R367TER_ERRCTRL1 0xf298 +#define F367TER_ERR_SRC1 0xf29800f0 +#define F367TER_ERRCTRL1_3 0xf2980008 +#define F367TER_NUM_EVT1 0xf2980007 + +/* ERRCNT1H */ +#define R367TER_ERRCNT1H 0xf299 +#define F367TER_ERRCNT1_OLDVALUE 0xf2990080 +#define F367TER_ERR_CNT1 0xf299007f + +/* ERRCNT1M */ +#define R367TER_ERRCNT1M 0xf29a +#define F367TER_ERR_CNT1_HI 0xf29a00ff + +/* ERRCNT1L */ +#define R367TER_ERRCNT1L 0xf29b +#define F367TER_ERR_CNT1_LO 0xf29b00ff + +/* ERRCTRL2 */ +#define R367TER_ERRCTRL2 0xf29c +#define F367TER_ERR_SRC2 0xf29c00f0 +#define F367TER_ERRCTRL2_3 0xf29c0008 +#define F367TER_NUM_EVT2 0xf29c0007 + +/* ERRCNT2H */ +#define R367TER_ERRCNT2H 0xf29d +#define F367TER_ERRCNT2_OLDVALUE 0xf29d0080 +#define F367TER_ERR_CNT2_HI 0xf29d007f + +/* ERRCNT2M */ +#define R367TER_ERRCNT2M 0xf29e +#define F367TER_ERR_CNT2_MED 0xf29e00ff + +/* ERRCNT2L */ +#define R367TER_ERRCNT2L 0xf29f +#define F367TER_ERR_CNT2_LO 0xf29f00ff + +/* FECSPY */ +#define R367TER_FECSPY 0xf2a0 +#define F367TER_SPY_ENABLE 0xf2a00080 +#define F367TER_NO_SYNCBYTE 0xf2a00040 +#define F367TER_SERIAL_MODE 0xf2a00020 +#define F367TER_UNUSUAL_PACKET 0xf2a00010 +#define F367TER_BERMETER_DATAMODE 0xf2a0000c +#define F367TER_BERMETER_LMODE 0xf2a00002 +#define F367TER_BERMETER_RESET 0xf2a00001 + +/* FSPYCFG */ +#define R367TER_FSPYCFG 0xf2a1 +#define F367TER_FECSPY_INPUT 0xf2a100c0 +#define F367TER_RST_ON_ERROR 0xf2a10020 +#define F367TER_ONE_SHOT 0xf2a10010 +#define F367TER_I2C_MOD 0xf2a1000c +#define F367TER_SPY_HYSTERESIS 0xf2a10003 + +/* FSPYDATA */ +#define R367TER_FSPYDATA 0xf2a2 +#define F367TER_SPY_STUFFING 0xf2a20080 +#define F367TER_NOERROR_PKTJITTER 0xf2a20040 +#define F367TER_SPY_CNULLPKT 0xf2a20020 +#define F367TER_SPY_OUTDATA_MODE 0xf2a2001f + +/* FSPYOUT */ +#define R367TER_FSPYOUT 0xf2a3 +#define F367TER_FSPY_DIRECT 0xf2a30080 +#define F367TER_FSPYOUT_6 0xf2a30040 +#define F367TER_SPY_OUTDATA_BUS 0xf2a30038 +#define F367TER_STUFF_MODE 0xf2a30007 + +/* FSTATUS */ +#define R367TER_FSTATUS 0xf2a4 +#define F367TER_SPY_ENDSIM 0xf2a40080 +#define F367TER_VALID_SIM 0xf2a40040 +#define F367TER_FOUND_SIGNAL 0xf2a40020 +#define F367TER_DSS_SYNCBYTE 0xf2a40010 +#define F367TER_RESULT_STATE 0xf2a4000f + +/* FGOODPACK */ +#define R367TER_FGOODPACK 0xf2a5 +#define F367TER_FGOOD_PACKET 0xf2a500ff + +/* FPACKCNT */ +#define R367TER_FPACKCNT 0xf2a6 +#define F367TER_FPACKET_COUNTER 0xf2a600ff + +/* FSPYMISC */ +#define R367TER_FSPYMISC 0xf2a7 +#define F367TER_FLABEL_COUNTER 0xf2a700ff + +/* FBERCPT4 */ +#define R367TER_FBERCPT4 0xf2a8 +#define F367TER_FBERMETER_CPT5 0xf2a800ff + +/* FBERCPT3 */ +#define R367TER_FBERCPT3 0xf2a9 +#define F367TER_FBERMETER_CPT4 0xf2a900ff + +/* FBERCPT2 */ +#define R367TER_FBERCPT2 0xf2aa +#define F367TER_FBERMETER_CPT3 0xf2aa00ff + +/* FBERCPT1 */ +#define R367TER_FBERCPT1 0xf2ab +#define F367TER_FBERMETER_CPT2 0xf2ab00ff + +/* FBERCPT0 */ +#define R367TER_FBERCPT0 0xf2ac +#define F367TER_FBERMETER_CPT1 0xf2ac00ff + +/* FBERERR2 */ +#define R367TER_FBERERR2 0xf2ad +#define F367TER_FBERMETER_ERR_HI 0xf2ad00ff + +/* FBERERR1 */ +#define R367TER_FBERERR1 0xf2ae +#define F367TER_FBERMETER_ERR_MED 0xf2ae00ff + +/* FBERERR0 */ +#define R367TER_FBERERR0 0xf2af +#define F367TER_FBERMETER_ERR_LO 0xf2af00ff + +/* FSTATESM */ +#define R367TER_FSTATESM 0xf2b0 +#define F367TER_RSTATE_F 0xf2b00080 +#define F367TER_RSTATE_E 0xf2b00040 +#define F367TER_RSTATE_D 0xf2b00020 +#define F367TER_RSTATE_C 0xf2b00010 +#define F367TER_RSTATE_B 0xf2b00008 +#define F367TER_RSTATE_A 0xf2b00004 +#define F367TER_RSTATE_9 0xf2b00002 +#define F367TER_RSTATE_8 0xf2b00001 + +/* FSTATESL */ +#define R367TER_FSTATESL 0xf2b1 +#define F367TER_RSTATE_7 0xf2b10080 +#define F367TER_RSTATE_6 0xf2b10040 +#define F367TER_RSTATE_5 0xf2b10020 +#define F367TER_RSTATE_4 0xf2b10010 +#define F367TER_RSTATE_3 0xf2b10008 +#define F367TER_RSTATE_2 0xf2b10004 +#define F367TER_RSTATE_1 0xf2b10002 +#define F367TER_RSTATE_0 0xf2b10001 + +/* FSPYBER */ +#define R367TER_FSPYBER 0xf2b2 +#define F367TER_FSPYBER_7 0xf2b20080 +#define F367TER_FSPYOBS_XORREAD 0xf2b20040 +#define F367TER_FSPYBER_OBSMODE 0xf2b20020 +#define F367TER_FSPYBER_SYNCBYTE 0xf2b20010 +#define F367TER_FSPYBER_UNSYNC 0xf2b20008 +#define F367TER_FSPYBER_CTIME 0xf2b20007 + +/* FSPYDISTM */ +#define R367TER_FSPYDISTM 0xf2b3 +#define F367TER_PKTTIME_DISTANCE_HI 0xf2b300ff + +/* FSPYDISTL */ +#define R367TER_FSPYDISTL 0xf2b4 +#define F367TER_PKTTIME_DISTANCE_LO 0xf2b400ff + +/* FSPYOBS7 */ +#define R367TER_FSPYOBS7 0xf2b8 +#define F367TER_FSPYOBS_SPYFAIL 0xf2b80080 +#define F367TER_FSPYOBS_SPYFAIL1 0xf2b80040 +#define F367TER_FSPYOBS_ERROR 0xf2b80020 +#define F367TER_FSPYOBS_STROUT 0xf2b80010 +#define F367TER_FSPYOBS_RESULTSTATE1 0xf2b8000f + +/* FSPYOBS6 */ +#define R367TER_FSPYOBS6 0xf2b9 +#define F367TER_FSPYOBS_RESULTSTATe0 0xf2b900f0 +#define F367TER_FSPYOBS_RESULTSTATEM1 0xf2b9000f + +/* FSPYOBS5 */ +#define R367TER_FSPYOBS5 0xf2ba +#define F367TER_FSPYOBS_BYTEOFPACKET1 0xf2ba00ff + +/* FSPYOBS4 */ +#define R367TER_FSPYOBS4 0xf2bb +#define F367TER_FSPYOBS_BYTEVALUE1 0xf2bb00ff + +/* FSPYOBS3 */ +#define R367TER_FSPYOBS3 0xf2bc +#define F367TER_FSPYOBS_DATA1 0xf2bc00ff + +/* FSPYOBS2 */ +#define R367TER_FSPYOBS2 0xf2bd +#define F367TER_FSPYOBS_DATa0 0xf2bd00ff + +/* FSPYOBS1 */ +#define R367TER_FSPYOBS1 0xf2be +#define F367TER_FSPYOBS_DATAM1 0xf2be00ff + +/* FSPYOBS0 */ +#define R367TER_FSPYOBS0 0xf2bf +#define F367TER_FSPYOBS_DATAM2 0xf2bf00ff + +/* SFDEMAP */ +#define R367TER_SFDEMAP 0xf2c0 +#define F367TER_SFDEMAP_7 0xf2c00080 +#define F367TER_SFEC_K_DIVIDER_VIT 0xf2c0007f + +/* SFERROR */ +#define R367TER_SFERROR 0xf2c1 +#define F367TER_SFEC_REGERR_VIT 0xf2c100ff + +/* SFAVSR */ +#define R367TER_SFAVSR 0xf2c2 +#define F367TER_SFEC_SUMERRORS 0xf2c20080 +#define F367TER_SERROR_MAXMODE 0xf2c20040 +#define F367TER_SN_SFEC 0xf2c20030 +#define F367TER_KDIV_MODE_SFEC 0xf2c2000c +#define F367TER_SFAVSR_1 0xf2c20002 +#define F367TER_SFAVSR_0 0xf2c20001 + +/* SFECSTATUS */ +#define R367TER_SFECSTATUS 0xf2c3 +#define F367TER_SFEC_ON 0xf2c30080 +#define F367TER_SFSTATUS_6 0xf2c30040 +#define F367TER_SFSTATUS_5 0xf2c30020 +#define F367TER_SFSTATUS_4 0xf2c30010 +#define F367TER_LOCKEDSFEC 0xf2c30008 +#define F367TER_SFEC_DELOCK 0xf2c30004 +#define F367TER_SFEC_DEMODSEL1 0xf2c30002 +#define F367TER_SFEC_OVFON 0xf2c30001 + +/* SFKDIV12 */ +#define R367TER_SFKDIV12 0xf2c4 +#define F367TER_SFECKDIV12_MAN 0xf2c40080 +#define F367TER_SFEC_K_DIVIDER_12 0xf2c4007f + +/* SFKDIV23 */ +#define R367TER_SFKDIV23 0xf2c5 +#define F367TER_SFECKDIV23_MAN 0xf2c50080 +#define F367TER_SFEC_K_DIVIDER_23 0xf2c5007f + +/* SFKDIV34 */ +#define R367TER_SFKDIV34 0xf2c6 +#define F367TER_SFECKDIV34_MAN 0xf2c60080 +#define F367TER_SFEC_K_DIVIDER_34 0xf2c6007f + +/* SFKDIV56 */ +#define R367TER_SFKDIV56 0xf2c7 +#define F367TER_SFECKDIV56_MAN 0xf2c70080 +#define F367TER_SFEC_K_DIVIDER_56 0xf2c7007f + +/* SFKDIV67 */ +#define R367TER_SFKDIV67 0xf2c8 +#define F367TER_SFECKDIV67_MAN 0xf2c80080 +#define F367TER_SFEC_K_DIVIDER_67 0xf2c8007f + +/* SFKDIV78 */ +#define R367TER_SFKDIV78 0xf2c9 +#define F367TER_SFECKDIV78_MAN 0xf2c90080 +#define F367TER_SFEC_K_DIVIDER_78 0xf2c9007f + +/* SFDILSTKM */ +#define R367TER_SFDILSTKM 0xf2ca +#define F367TER_SFEC_PACKCPT 0xf2ca00e0 +#define F367TER_SFEC_DILSTK_HI 0xf2ca001f + +/* SFDILSTKL */ +#define R367TER_SFDILSTKL 0xf2cb +#define F367TER_SFEC_DILSTK_LO 0xf2cb00ff + +/* SFSTATUS */ +#define R367TER_SFSTATUS 0xf2cc +#define F367TER_SFEC_LINEOK 0xf2cc0080 +#define F367TER_SFEC_ERROR 0xf2cc0040 +#define F367TER_SFEC_DATA7 0xf2cc0020 +#define F367TER_SFEC_OVERFLOW 0xf2cc0010 +#define F367TER_SFEC_DEMODSEL2 0xf2cc0008 +#define F367TER_SFEC_NOSYNC 0xf2cc0004 +#define F367TER_SFEC_UNREGULA 0xf2cc0002 +#define F367TER_SFEC_READY 0xf2cc0001 + +/* SFDLYH */ +#define R367TER_SFDLYH 0xf2cd +#define F367TER_SFEC_TSTIMEVALID 0xf2cd0080 +#define F367TER_SFEC_SPEEDUP 0xf2cd0040 +#define F367TER_SFEC_STOP 0xf2cd0020 +#define F367TER_SFEC_REGULATED 0xf2cd0010 +#define F367TER_SFEC_REALSYMBOFFSET 0xf2cd000f + +/* SFDLYM */ +#define R367TER_SFDLYM 0xf2ce +#define F367TER_SFEC_REALSYMBOFFSET_HI 0xf2ce00ff + +/* SFDLYL */ +#define R367TER_SFDLYL 0xf2cf +#define F367TER_SFEC_REALSYMBOFFSET_LO 0xf2cf00ff + +/* SFDLYSETH */ +#define R367TER_SFDLYSETH 0xf2d0 +#define F367TER_SFEC_OFFSET 0xf2d000e0 +#define F367TER_SFECDLYSETH_4 0xf2d00010 +#define F367TER_RST_SFEC 0xf2d00008 +#define F367TER_SFECDLYSETH_2 0xf2d00004 +#define F367TER_SFEC_DISABLE 0xf2d00002 +#define F367TER_SFEC_UNREGUL 0xf2d00001 + +/* SFDLYSETM */ +#define R367TER_SFDLYSETM 0xf2d1 +#define F367TER_SFECDLYSETM_7 0xf2d10080 +#define F367TER_SFEC_SYMBOFFSET_HI 0xf2d1007f + +/* SFDLYSETL */ +#define R367TER_SFDLYSETL 0xf2d2 +#define F367TER_SFEC_SYMBOFFSET_LO 0xf2d200ff + +/* SFOBSCFG */ +#define R367TER_SFOBSCFG 0xf2d3 +#define F367TER_SFEC_OBSCFG 0xf2d300ff + +/* SFOBSM */ +#define R367TER_SFOBSM 0xf2d4 +#define F367TER_SFEC_OBSDATA_HI 0xf2d400ff + +/* SFOBSL */ +#define R367TER_SFOBSL 0xf2d5 +#define F367TER_SFEC_OBSDATA_LO 0xf2d500ff + +/* SFECINFO */ +#define R367TER_SFECINFO 0xf2d6 +#define F367TER_SFECINFO_7 0xf2d60080 +#define F367TER_SFEC_SYNCDLSB 0xf2d60070 +#define F367TER_SFCE_S1cPHASE 0xf2d6000f + +/* SFERRCTRL */ +#define R367TER_SFERRCTRL 0xf2d8 +#define F367TER_SFEC_ERR_SOURCE 0xf2d800f0 +#define F367TER_SFERRCTRL_3 0xf2d80008 +#define F367TER_SFEC_NUM_EVENT 0xf2d80007 + +/* SFERRCNTH */ +#define R367TER_SFERRCNTH 0xf2d9 +#define F367TER_SFERRC_OLDVALUE 0xf2d90080 +#define F367TER_SFEC_ERR_CNT 0xf2d9007f + +/* SFERRCNTM */ +#define R367TER_SFERRCNTM 0xf2da +#define F367TER_SFEC_ERR_CNT_HI 0xf2da00ff + +/* SFERRCNTL */ +#define R367TER_SFERRCNTL 0xf2db +#define F367TER_SFEC_ERR_CNT_LO 0xf2db00ff + +/* SYMBRATEM */ +#define R367TER_SYMBRATEM 0xf2e0 +#define F367TER_DEFGEN_SYMBRATE_HI 0xf2e000ff + +/* SYMBRATEL */ +#define R367TER_SYMBRATEL 0xf2e1 +#define F367TER_DEFGEN_SYMBRATE_LO 0xf2e100ff + +/* SYMBSTATUS */ +#define R367TER_SYMBSTATUS 0xf2e2 +#define F367TER_SYMBDLINE2_OFF 0xf2e20080 +#define F367TER_SDDL_REINIT1 0xf2e20040 +#define F367TER_SDD_REINIT1 0xf2e20020 +#define F367TER_TOKENID_ERROR 0xf2e20010 +#define F367TER_SYMBRATE_OVERFLOW 0xf2e20008 +#define F367TER_SYMBRATE_UNDERFLOW 0xf2e20004 +#define F367TER_TOKENID_RSTEVENT 0xf2e20002 +#define F367TER_TOKENID_RESET1 0xf2e20001 + +/* SYMBCFG */ +#define R367TER_SYMBCFG 0xf2e3 +#define F367TER_SYMBCFG_7 0xf2e30080 +#define F367TER_SYMBCFG_6 0xf2e30040 +#define F367TER_SYMBCFG_5 0xf2e30020 +#define F367TER_SYMBCFG_4 0xf2e30010 +#define F367TER_SYMRATE_FSPEED 0xf2e3000c +#define F367TER_SYMRATE_SSPEED 0xf2e30003 + +/* SYMBFIFOM */ +#define R367TER_SYMBFIFOM 0xf2e4 +#define F367TER_SYMBFIFOM_7 0xf2e40080 +#define F367TER_SYMBFIFOM_6 0xf2e40040 +#define F367TER_DEFGEN_SYMFIFO_HI 0xf2e4003f + +/* SYMBFIFOL */ +#define R367TER_SYMBFIFOL 0xf2e5 +#define F367TER_DEFGEN_SYMFIFO_LO 0xf2e500ff + +/* SYMBOFFSM */ +#define R367TER_SYMBOFFSM 0xf2e6 +#define F367TER_TOKENID_RESET2 0xf2e60080 +#define F367TER_SDDL_REINIT2 0xf2e60040 +#define F367TER_SDD_REINIT2 0xf2e60020 +#define F367TER_SYMBOFFSM_4 0xf2e60010 +#define F367TER_SYMBOFFSM_3 0xf2e60008 +#define F367TER_DEFGEN_SYMBOFFSET_HI 0xf2e60007 + +/* SYMBOFFSL */ +#define R367TER_SYMBOFFSL 0xf2e7 +#define F367TER_DEFGEN_SYMBOFFSET_LO 0xf2e700ff + +/* DEBUG_LT4 */ +#define R367TER_DEBUG_LT4 0xf400 +#define F367TER_F_DEBUG_LT4 0xf40000ff + +/* DEBUG_LT5 */ +#define R367TER_DEBUG_LT5 0xf401 +#define F367TER_F_DEBUG_LT5 0xf40100ff + +/* DEBUG_LT6 */ +#define R367TER_DEBUG_LT6 0xf402 +#define F367TER_F_DEBUG_LT6 0xf40200ff + +/* DEBUG_LT7 */ +#define R367TER_DEBUG_LT7 0xf403 +#define F367TER_F_DEBUG_LT7 0xf40300ff + +/* DEBUG_LT8 */ +#define R367TER_DEBUG_LT8 0xf404 +#define F367TER_F_DEBUG_LT8 0xf40400ff + +/* DEBUG_LT9 */ +#define R367TER_DEBUG_LT9 0xf405 +#define F367TER_F_DEBUG_LT9 0xf40500ff + +#define STV0367TER_NBREGS 445 + +/* ID */ +#define R367CAB_ID 0xf000 +#define F367CAB_IDENTIFICATIONREGISTER 0xf00000ff + +/* I2CRPT */ +#define R367CAB_I2CRPT 0xf001 +#define F367CAB_I2CT_ON 0xf0010080 +#define F367CAB_ENARPT_LEVEL 0xf0010070 +#define F367CAB_SCLT_DELAY 0xf0010008 +#define F367CAB_SCLT_NOD 0xf0010004 +#define F367CAB_STOP_ENABLE 0xf0010002 +#define F367CAB_SDAT_NOD 0xf0010001 + +/* TOPCTRL */ +#define R367CAB_TOPCTRL 0xf002 +#define F367CAB_STDBY 0xf0020080 +#define F367CAB_STDBY_CORE 0xf0020020 +#define F367CAB_QAM_COFDM 0xf0020010 +#define F367CAB_TS_DIS 0xf0020008 +#define F367CAB_DIR_CLK_216 0xf0020004 + +/* IOCFG0 */ +#define R367CAB_IOCFG0 0xf003 +#define F367CAB_OP0_SD 0xf0030080 +#define F367CAB_OP0_VAL 0xf0030040 +#define F367CAB_OP0_OD 0xf0030020 +#define F367CAB_OP0_INV 0xf0030010 +#define F367CAB_OP0_DACVALUE_HI 0xf003000f + +/* DAc0R */ +#define R367CAB_DAC0R 0xf004 +#define F367CAB_OP0_DACVALUE_LO 0xf00400ff + +/* IOCFG1 */ +#define R367CAB_IOCFG1 0xf005 +#define F367CAB_IP0 0xf0050040 +#define F367CAB_OP1_OD 0xf0050020 +#define F367CAB_OP1_INV 0xf0050010 +#define F367CAB_OP1_DACVALUE_HI 0xf005000f + +/* DAC1R */ +#define R367CAB_DAC1R 0xf006 +#define F367CAB_OP1_DACVALUE_LO 0xf00600ff + +/* IOCFG2 */ +#define R367CAB_IOCFG2 0xf007 +#define F367CAB_OP2_LOCK_CONF 0xf00700e0 +#define F367CAB_OP2_OD 0xf0070010 +#define F367CAB_OP2_VAL 0xf0070008 +#define F367CAB_OP1_LOCK_CONF 0xf0070007 + +/* SDFR */ +#define R367CAB_SDFR 0xf008 +#define F367CAB_OP0_FREQ 0xf00800f0 +#define F367CAB_OP1_FREQ 0xf008000f + +/* AUX_CLK */ +#define R367CAB_AUX_CLK 0xf00a +#define F367CAB_AUXFEC_CTL 0xf00a00c0 +#define F367CAB_DIS_CKX4 0xf00a0020 +#define F367CAB_CKSEL 0xf00a0018 +#define F367CAB_CKDIV_PROG 0xf00a0006 +#define F367CAB_AUXCLK_ENA 0xf00a0001 + +/* FREESYS1 */ +#define R367CAB_FREESYS1 0xf00b +#define F367CAB_FREESYS_1 0xf00b00ff + +/* FREESYS2 */ +#define R367CAB_FREESYS2 0xf00c +#define F367CAB_FREESYS_2 0xf00c00ff + +/* FREESYS3 */ +#define R367CAB_FREESYS3 0xf00d +#define F367CAB_FREESYS_3 0xf00d00ff + +/* GPIO_CFG */ +#define R367CAB_GPIO_CFG 0xf00e +#define F367CAB_GPIO7_OD 0xf00e0080 +#define F367CAB_GPIO7_CFG 0xf00e0040 +#define F367CAB_GPIO6_OD 0xf00e0020 +#define F367CAB_GPIO6_CFG 0xf00e0010 +#define F367CAB_GPIO5_OD 0xf00e0008 +#define F367CAB_GPIO5_CFG 0xf00e0004 +#define F367CAB_GPIO4_OD 0xf00e0002 +#define F367CAB_GPIO4_CFG 0xf00e0001 + +/* GPIO_CMD */ +#define R367CAB_GPIO_CMD 0xf00f +#define F367CAB_GPIO7_VAL 0xf00f0008 +#define F367CAB_GPIO6_VAL 0xf00f0004 +#define F367CAB_GPIO5_VAL 0xf00f0002 +#define F367CAB_GPIO4_VAL 0xf00f0001 + +/* TSTRES */ +#define R367CAB_TSTRES 0xf0c0 +#define F367CAB_FRES_DISPLAY 0xf0c00080 +#define F367CAB_FRES_FIFO_AD 0xf0c00020 +#define F367CAB_FRESRS 0xf0c00010 +#define F367CAB_FRESACS 0xf0c00008 +#define F367CAB_FRESFEC 0xf0c00004 +#define F367CAB_FRES_PRIF 0xf0c00002 +#define F367CAB_FRESCORE 0xf0c00001 + +/* ANACTRL */ +#define R367CAB_ANACTRL 0xf0c1 +#define F367CAB_BYPASS_XTAL 0xf0c10040 +#define F367CAB_BYPASS_PLLXN 0xf0c1000c +#define F367CAB_DIS_PAD_OSC 0xf0c10002 +#define F367CAB_STDBY_PLLXN 0xf0c10001 + +/* TSTBUS */ +#define R367CAB_TSTBUS 0xf0c2 +#define F367CAB_TS_BYTE_CLK_INV 0xf0c20080 +#define F367CAB_CFG_IP 0xf0c20070 +#define F367CAB_CFG_TST 0xf0c2000f + +/* RF_AGC1 */ +#define R367CAB_RF_AGC1 0xf0d4 +#define F367CAB_RF_AGC1_LEVEL_HI 0xf0d400ff + +/* RF_AGC2 */ +#define R367CAB_RF_AGC2 0xf0d5 +#define F367CAB_REF_ADGP 0xf0d50080 +#define F367CAB_STDBY_ADCGP 0xf0d50020 +#define F367CAB_RF_AGC1_LEVEL_LO 0xf0d50003 + +/* ANADIGCTRL */ +#define R367CAB_ANADIGCTRL 0xf0d7 +#define F367CAB_SEL_CLKDEM 0xf0d70020 +#define F367CAB_EN_BUFFER_Q 0xf0d70010 +#define F367CAB_EN_BUFFER_I 0xf0d70008 +#define F367CAB_ADC_RIS_EGDE 0xf0d70004 +#define F367CAB_SGN_ADC 0xf0d70002 +#define F367CAB_SEL_AD12_SYNC 0xf0d70001 + +/* PLLMDIV */ +#define R367CAB_PLLMDIV 0xf0d8 +#define F367CAB_PLL_MDIV 0xf0d800ff + +/* PLLNDIV */ +#define R367CAB_PLLNDIV 0xf0d9 +#define F367CAB_PLL_NDIV 0xf0d900ff + +/* PLLSETUP */ +#define R367CAB_PLLSETUP 0xf0da +#define F367CAB_PLL_PDIV 0xf0da0070 +#define F367CAB_PLL_KDIV 0xf0da000f + +/* DUAL_AD12 */ +#define R367CAB_DUAL_AD12 0xf0db +#define F367CAB_FS20M 0xf0db0020 +#define F367CAB_FS50M 0xf0db0010 +#define F367CAB_INMODe0 0xf0db0008 +#define F367CAB_POFFQ 0xf0db0004 +#define F367CAB_POFFI 0xf0db0002 +#define F367CAB_INMODE1 0xf0db0001 + +/* TSTBIST */ +#define R367CAB_TSTBIST 0xf0dc +#define F367CAB_TST_BYP_CLK 0xf0dc0080 +#define F367CAB_TST_GCLKENA_STD 0xf0dc0040 +#define F367CAB_TST_GCLKENA 0xf0dc0020 +#define F367CAB_TST_MEMBIST 0xf0dc001f + +/* CTRL_1 */ +#define R367CAB_CTRL_1 0xf402 +#define F367CAB_SOFT_RST 0xf4020080 +#define F367CAB_EQU_RST 0xf4020008 +#define F367CAB_CRL_RST 0xf4020004 +#define F367CAB_TRL_RST 0xf4020002 +#define F367CAB_AGC_RST 0xf4020001 + +/* CTRL_2 */ +#define R367CAB_CTRL_2 0xf403 +#define F367CAB_DEINT_RST 0xf4030008 +#define F367CAB_RS_RST 0xf4030004 + +/* IT_STATUS1 */ +#define R367CAB_IT_STATUS1 0xf408 +#define F367CAB_SWEEP_OUT 0xf4080080 +#define F367CAB_FSM_CRL 0xf4080040 +#define F367CAB_CRL_LOCK 0xf4080020 +#define F367CAB_MFSM 0xf4080010 +#define F367CAB_TRL_LOCK 0xf4080008 +#define F367CAB_TRL_AGC_LIMIT 0xf4080004 +#define F367CAB_ADJ_AGC_LOCK 0xf4080002 +#define F367CAB_AGC_QAM_LOCK 0xf4080001 + +/* IT_STATUS2 */ +#define R367CAB_IT_STATUS2 0xf409 +#define F367CAB_TSMF_CNT 0xf4090080 +#define F367CAB_TSMF_EOF 0xf4090040 +#define F367CAB_TSMF_RDY 0xf4090020 +#define F367CAB_FEC_NOCORR 0xf4090010 +#define F367CAB_SYNCSTATE 0xf4090008 +#define F367CAB_DEINT_LOCK 0xf4090004 +#define F367CAB_FADDING_FRZ 0xf4090002 +#define F367CAB_TAPMON_ALARM 0xf4090001 + +/* IT_EN1 */ +#define R367CAB_IT_EN1 0xf40a +#define F367CAB_SWEEP_OUTE 0xf40a0080 +#define F367CAB_FSM_CRLE 0xf40a0040 +#define F367CAB_CRL_LOCKE 0xf40a0020 +#define F367CAB_MFSME 0xf40a0010 +#define F367CAB_TRL_LOCKE 0xf40a0008 +#define F367CAB_TRL_AGC_LIMITE 0xf40a0004 +#define F367CAB_ADJ_AGC_LOCKE 0xf40a0002 +#define F367CAB_AGC_LOCKE 0xf40a0001 + +/* IT_EN2 */ +#define R367CAB_IT_EN2 0xf40b +#define F367CAB_TSMF_CNTE 0xf40b0080 +#define F367CAB_TSMF_EOFE 0xf40b0040 +#define F367CAB_TSMF_RDYE 0xf40b0020 +#define F367CAB_FEC_NOCORRE 0xf40b0010 +#define F367CAB_SYNCSTATEE 0xf40b0008 +#define F367CAB_DEINT_LOCKE 0xf40b0004 +#define F367CAB_FADDING_FRZE 0xf40b0002 +#define F367CAB_TAPMON_ALARME 0xf40b0001 + +/* CTRL_STATUS */ +#define R367CAB_CTRL_STATUS 0xf40c +#define F367CAB_QAMFEC_LOCK 0xf40c0004 +#define F367CAB_TSMF_LOCK 0xf40c0002 +#define F367CAB_TSMF_ERROR 0xf40c0001 + +/* TEST_CTL */ +#define R367CAB_TEST_CTL 0xf40f +#define F367CAB_TST_BLK_SEL 0xf40f0060 +#define F367CAB_TST_BUS_SEL 0xf40f001f + +/* AGC_CTL */ +#define R367CAB_AGC_CTL 0xf410 +#define F367CAB_AGC_LCK_TH 0xf41000f0 +#define F367CAB_AGC_ACCUMRSTSEL 0xf4100007 + +/* AGC_IF_CFG */ +#define R367CAB_AGC_IF_CFG 0xf411 +#define F367CAB_AGC_IF_BWSEL 0xf41100f0 +#define F367CAB_AGC_IF_FREEZE 0xf4110002 + +/* AGC_RF_CFG */ +#define R367CAB_AGC_RF_CFG 0xf412 +#define F367CAB_AGC_RF_BWSEL 0xf4120070 +#define F367CAB_AGC_RF_FREEZE 0xf4120002 + +/* AGC_PWM_CFG */ +#define R367CAB_AGC_PWM_CFG 0xf413 +#define F367CAB_AGC_RF_PWM_TST 0xf4130080 +#define F367CAB_AGC_RF_PWM_INV 0xf4130040 +#define F367CAB_AGC_IF_PWM_TST 0xf4130008 +#define F367CAB_AGC_IF_PWM_INV 0xf4130004 +#define F367CAB_AGC_PWM_CLKDIV 0xf4130003 + +/* AGC_PWR_REF_L */ +#define R367CAB_AGC_PWR_REF_L 0xf414 +#define F367CAB_AGC_PWRREF_LO 0xf41400ff + +/* AGC_PWR_REF_H */ +#define R367CAB_AGC_PWR_REF_H 0xf415 +#define F367CAB_AGC_PWRREF_HI 0xf4150003 + +/* AGC_RF_TH_L */ +#define R367CAB_AGC_RF_TH_L 0xf416 +#define F367CAB_AGC_RF_TH_LO 0xf41600ff + +/* AGC_RF_TH_H */ +#define R367CAB_AGC_RF_TH_H 0xf417 +#define F367CAB_AGC_RF_TH_HI 0xf417000f + +/* AGC_IF_LTH_L */ +#define R367CAB_AGC_IF_LTH_L 0xf418 +#define F367CAB_AGC_IF_THLO_LO 0xf41800ff + +/* AGC_IF_LTH_H */ +#define R367CAB_AGC_IF_LTH_H 0xf419 +#define F367CAB_AGC_IF_THLO_HI 0xf419000f + +/* AGC_IF_HTH_L */ +#define R367CAB_AGC_IF_HTH_L 0xf41a +#define F367CAB_AGC_IF_THHI_LO 0xf41a00ff + +/* AGC_IF_HTH_H */ +#define R367CAB_AGC_IF_HTH_H 0xf41b +#define F367CAB_AGC_IF_THHI_HI 0xf41b000f + +/* AGC_PWR_RD_L */ +#define R367CAB_AGC_PWR_RD_L 0xf41c +#define F367CAB_AGC_PWR_WORD_LO 0xf41c00ff + +/* AGC_PWR_RD_M */ +#define R367CAB_AGC_PWR_RD_M 0xf41d +#define F367CAB_AGC_PWR_WORD_ME 0xf41d00ff + +/* AGC_PWR_RD_H */ +#define R367CAB_AGC_PWR_RD_H 0xf41e +#define F367CAB_AGC_PWR_WORD_HI 0xf41e0003 + +/* AGC_PWM_IFCMD_L */ +#define R367CAB_AGC_PWM_IFCMD_L 0xf420 +#define F367CAB_AGC_IF_PWMCMD_LO 0xf42000ff + +/* AGC_PWM_IFCMD_H */ +#define R367CAB_AGC_PWM_IFCMD_H 0xf421 +#define F367CAB_AGC_IF_PWMCMD_HI 0xf421000f + +/* AGC_PWM_RFCMD_L */ +#define R367CAB_AGC_PWM_RFCMD_L 0xf422 +#define F367CAB_AGC_RF_PWMCMD_LO 0xf42200ff + +/* AGC_PWM_RFCMD_H */ +#define R367CAB_AGC_PWM_RFCMD_H 0xf423 +#define F367CAB_AGC_RF_PWMCMD_HI 0xf423000f + +/* IQDEM_CFG */ +#define R367CAB_IQDEM_CFG 0xf424 +#define F367CAB_IQDEM_CLK_SEL 0xf4240004 +#define F367CAB_IQDEM_INVIQ 0xf4240002 +#define F367CAB_IQDEM_A2dTYPE 0xf4240001 + +/* MIX_NCO_LL */ +#define R367CAB_MIX_NCO_LL 0xf425 +#define F367CAB_MIX_NCO_INC_LL 0xf42500ff + +/* MIX_NCO_HL */ +#define R367CAB_MIX_NCO_HL 0xf426 +#define F367CAB_MIX_NCO_INC_HL 0xf42600ff + +/* MIX_NCO_HH */ +#define R367CAB_MIX_NCO_HH 0xf427 +#define F367CAB_MIX_NCO_INVCNST 0xf4270080 +#define F367CAB_MIX_NCO_INC_HH 0xf427007f + +/* SRC_NCO_LL */ +#define R367CAB_SRC_NCO_LL 0xf428 +#define F367CAB_SRC_NCO_INC_LL 0xf42800ff + +/* SRC_NCO_LH */ +#define R367CAB_SRC_NCO_LH 0xf429 +#define F367CAB_SRC_NCO_INC_LH 0xf42900ff + +/* SRC_NCO_HL */ +#define R367CAB_SRC_NCO_HL 0xf42a +#define F367CAB_SRC_NCO_INC_HL 0xf42a00ff + +/* SRC_NCO_HH */ +#define R367CAB_SRC_NCO_HH 0xf42b +#define F367CAB_SRC_NCO_INC_HH 0xf42b007f + +/* IQDEM_GAIN_SRC_L */ +#define R367CAB_IQDEM_GAIN_SRC_L 0xf42c +#define F367CAB_GAIN_SRC_LO 0xf42c00ff + +/* IQDEM_GAIN_SRC_H */ +#define R367CAB_IQDEM_GAIN_SRC_H 0xf42d +#define F367CAB_GAIN_SRC_HI 0xf42d0003 + +/* IQDEM_DCRM_CFG_LL */ +#define R367CAB_IQDEM_DCRM_CFG_LL 0xf430 +#define F367CAB_DCRM0_DCIN_L 0xf43000ff + +/* IQDEM_DCRM_CFG_LH */ +#define R367CAB_IQDEM_DCRM_CFG_LH 0xf431 +#define F367CAB_DCRM1_I_DCIN_L 0xf43100fc +#define F367CAB_DCRM0_DCIN_H 0xf4310003 + +/* IQDEM_DCRM_CFG_HL */ +#define R367CAB_IQDEM_DCRM_CFG_HL 0xf432 +#define F367CAB_DCRM1_Q_DCIN_L 0xf43200f0 +#define F367CAB_DCRM1_I_DCIN_H 0xf432000f + +/* IQDEM_DCRM_CFG_HH */ +#define R367CAB_IQDEM_DCRM_CFG_HH 0xf433 +#define F367CAB_DCRM1_FRZ 0xf4330080 +#define F367CAB_DCRM0_FRZ 0xf4330040 +#define F367CAB_DCRM1_Q_DCIN_H 0xf433003f + +/* IQDEM_ADJ_COEFf0 */ +#define R367CAB_IQDEM_ADJ_COEFF0 0xf434 +#define F367CAB_ADJIIR_COEFF10_L 0xf43400ff + +/* IQDEM_ADJ_COEFF1 */ +#define R367CAB_IQDEM_ADJ_COEFF1 0xf435 +#define F367CAB_ADJIIR_COEFF11_L 0xf43500fc +#define F367CAB_ADJIIR_COEFF10_H 0xf4350003 + +/* IQDEM_ADJ_COEFF2 */ +#define R367CAB_IQDEM_ADJ_COEFF2 0xf436 +#define F367CAB_ADJIIR_COEFF12_L 0xf43600f0 +#define F367CAB_ADJIIR_COEFF11_H 0xf436000f + +/* IQDEM_ADJ_COEFF3 */ +#define R367CAB_IQDEM_ADJ_COEFF3 0xf437 +#define F367CAB_ADJIIR_COEFF20_L 0xf43700c0 +#define F367CAB_ADJIIR_COEFF12_H 0xf437003f + +/* IQDEM_ADJ_COEFF4 */ +#define R367CAB_IQDEM_ADJ_COEFF4 0xf438 +#define F367CAB_ADJIIR_COEFF20_H 0xf43800ff + +/* IQDEM_ADJ_COEFF5 */ +#define R367CAB_IQDEM_ADJ_COEFF5 0xf439 +#define F367CAB_ADJIIR_COEFF21_L 0xf43900ff + +/* IQDEM_ADJ_COEFF6 */ +#define R367CAB_IQDEM_ADJ_COEFF6 0xf43a +#define F367CAB_ADJIIR_COEFF22_L 0xf43a00fc +#define F367CAB_ADJIIR_COEFF21_H 0xf43a0003 + +/* IQDEM_ADJ_COEFF7 */ +#define R367CAB_IQDEM_ADJ_COEFF7 0xf43b +#define F367CAB_ADJIIR_COEFF22_H 0xf43b000f + +/* IQDEM_ADJ_EN */ +#define R367CAB_IQDEM_ADJ_EN 0xf43c +#define F367CAB_ALLPASSFILT_EN 0xf43c0008 +#define F367CAB_ADJ_AGC_EN 0xf43c0004 +#define F367CAB_ADJ_COEFF_FRZ 0xf43c0002 +#define F367CAB_ADJ_EN 0xf43c0001 + +/* IQDEM_ADJ_AGC_REF */ +#define R367CAB_IQDEM_ADJ_AGC_REF 0xf43d +#define F367CAB_ADJ_AGC_REF 0xf43d00ff + +/* ALLPASSFILT1 */ +#define R367CAB_ALLPASSFILT1 0xf440 +#define F367CAB_ALLPASSFILT_COEFF1_LO 0xf44000ff + +/* ALLPASSFILT2 */ +#define R367CAB_ALLPASSFILT2 0xf441 +#define F367CAB_ALLPASSFILT_COEFF1_ME 0xf44100ff + +/* ALLPASSFILT3 */ +#define R367CAB_ALLPASSFILT3 0xf442 +#define F367CAB_ALLPASSFILT_COEFF2_LO 0xf44200c0 +#define F367CAB_ALLPASSFILT_COEFF1_HI 0xf442003f + +/* ALLPASSFILT4 */ +#define R367CAB_ALLPASSFILT4 0xf443 +#define F367CAB_ALLPASSFILT_COEFF2_MEL 0xf44300ff + +/* ALLPASSFILT5 */ +#define R367CAB_ALLPASSFILT5 0xf444 +#define F367CAB_ALLPASSFILT_COEFF2_MEH 0xf44400ff + +/* ALLPASSFILT6 */ +#define R367CAB_ALLPASSFILT6 0xf445 +#define F367CAB_ALLPASSFILT_COEFF3_LO 0xf44500f0 +#define F367CAB_ALLPASSFILT_COEFF2_HI 0xf445000f + +/* ALLPASSFILT7 */ +#define R367CAB_ALLPASSFILT7 0xf446 +#define F367CAB_ALLPASSFILT_COEFF3_MEL 0xf44600ff + +/* ALLPASSFILT8 */ +#define R367CAB_ALLPASSFILT8 0xf447 +#define F367CAB_ALLPASSFILT_COEFF3_MEH 0xf44700ff + +/* ALLPASSFILT9 */ +#define R367CAB_ALLPASSFILT9 0xf448 +#define F367CAB_ALLPASSFILT_COEFF4_LO 0xf44800fc +#define F367CAB_ALLPASSFILT_COEFF3_HI 0xf4480003 + +/* ALLPASSFILT10 */ +#define R367CAB_ALLPASSFILT10 0xf449 +#define F367CAB_ALLPASSFILT_COEFF4_ME 0xf44900ff + +/* ALLPASSFILT11 */ +#define R367CAB_ALLPASSFILT11 0xf44a +#define F367CAB_ALLPASSFILT_COEFF4_HI 0xf44a00ff + +/* TRL_AGC_CFG */ +#define R367CAB_TRL_AGC_CFG 0xf450 +#define F367CAB_TRL_AGC_FREEZE 0xf4500080 +#define F367CAB_TRL_AGC_REF 0xf450007f + +/* TRL_LPF_CFG */ +#define R367CAB_TRL_LPF_CFG 0xf454 +#define F367CAB_NYQPOINT_INV 0xf4540040 +#define F367CAB_TRL_SHIFT 0xf4540030 +#define F367CAB_NYQ_COEFF_SEL 0xf454000c +#define F367CAB_TRL_LPF_FREEZE 0xf4540002 +#define F367CAB_TRL_LPF_CRT 0xf4540001 + +/* TRL_LPF_ACQ_GAIN */ +#define R367CAB_TRL_LPF_ACQ_GAIN 0xf455 +#define F367CAB_TRL_GDIR_ACQ 0xf4550070 +#define F367CAB_TRL_GINT_ACQ 0xf4550007 + +/* TRL_LPF_TRK_GAIN */ +#define R367CAB_TRL_LPF_TRK_GAIN 0xf456 +#define F367CAB_TRL_GDIR_TRK 0xf4560070 +#define F367CAB_TRL_GINT_TRK 0xf4560007 + +/* TRL_LPF_OUT_GAIN */ +#define R367CAB_TRL_LPF_OUT_GAIN 0xf457 +#define F367CAB_TRL_GAIN_OUT 0xf4570007 + +/* TRL_LOCKDET_LTH */ +#define R367CAB_TRL_LOCKDET_LTH 0xf458 +#define F367CAB_TRL_LCK_THLO 0xf4580007 + +/* TRL_LOCKDET_HTH */ +#define R367CAB_TRL_LOCKDET_HTH 0xf459 +#define F367CAB_TRL_LCK_THHI 0xf45900ff + +/* TRL_LOCKDET_TRGVAL */ +#define R367CAB_TRL_LOCKDET_TRGVAL 0xf45a +#define F367CAB_TRL_LCK_TRG 0xf45a00ff + +/* IQ_QAM */ +#define R367CAB_IQ_QAM 0xf45c +#define F367CAB_IQ_INPUT 0xf45c0008 +#define F367CAB_DETECT_MODE 0xf45c0007 + +/* FSM_STATE */ +#define R367CAB_FSM_STATE 0xf460 +#define F367CAB_CRL_DFE 0xf4600080 +#define F367CAB_DFE_START 0xf4600040 +#define F367CAB_CTRLG_START 0xf4600030 +#define F367CAB_FSM_FORCESTATE 0xf460000f + +/* FSM_CTL */ +#define R367CAB_FSM_CTL 0xf461 +#define F367CAB_FEC2_EN 0xf4610040 +#define F367CAB_SIT_EN 0xf4610020 +#define F367CAB_TRL_AHEAD 0xf4610010 +#define F367CAB_TRL2_EN 0xf4610008 +#define F367CAB_FSM_EQA1_EN 0xf4610004 +#define F367CAB_FSM_BKP_DIS 0xf4610002 +#define F367CAB_FSM_FORCE_EN 0xf4610001 + +/* FSM_STS */ +#define R367CAB_FSM_STS 0xf462 +#define F367CAB_FSM_STATUS 0xf462000f + +/* FSM_SNR0_HTH */ +#define R367CAB_FSM_SNR0_HTH 0xf463 +#define F367CAB_SNR0_HTH 0xf46300ff + +/* FSM_SNR1_HTH */ +#define R367CAB_FSM_SNR1_HTH 0xf464 +#define F367CAB_SNR1_HTH 0xf46400ff + +/* FSM_SNR2_HTH */ +#define R367CAB_FSM_SNR2_HTH 0xf465 +#define F367CAB_SNR2_HTH 0xf46500ff + +/* FSM_SNR0_LTH */ +#define R367CAB_FSM_SNR0_LTH 0xf466 +#define F367CAB_SNR0_LTH 0xf46600ff + +/* FSM_SNR1_LTH */ +#define R367CAB_FSM_SNR1_LTH 0xf467 +#define F367CAB_SNR1_LTH 0xf46700ff + +/* FSM_EQA1_HTH */ +#define R367CAB_FSM_EQA1_HTH 0xf468 +#define F367CAB_SNR3_HTH_LO 0xf46800f0 +#define F367CAB_EQA1_HTH 0xf468000f + +/* FSM_TEMPO */ +#define R367CAB_FSM_TEMPO 0xf469 +#define F367CAB_SIT 0xf46900c0 +#define F367CAB_WST 0xf4690038 +#define F367CAB_ELT 0xf4690006 +#define F367CAB_SNR3_HTH_HI 0xf4690001 + +/* FSM_CONFIG */ +#define R367CAB_FSM_CONFIG 0xf46a +#define F367CAB_FEC2_DFEOFF 0xf46a0004 +#define F367CAB_PRIT_STATE 0xf46a0002 +#define F367CAB_MODMAP_STATE 0xf46a0001 + +/* EQU_I_TESTTAP_L */ +#define R367CAB_EQU_I_TESTTAP_L 0xf474 +#define F367CAB_I_TEST_TAP_L 0xf47400ff + +/* EQU_I_TESTTAP_M */ +#define R367CAB_EQU_I_TESTTAP_M 0xf475 +#define F367CAB_I_TEST_TAP_M 0xf47500ff + +/* EQU_I_TESTTAP_H */ +#define R367CAB_EQU_I_TESTTAP_H 0xf476 +#define F367CAB_I_TEST_TAP_H 0xf476001f + +/* EQU_TESTAP_CFG */ +#define R367CAB_EQU_TESTAP_CFG 0xf477 +#define F367CAB_TEST_FFE_DFE_SEL 0xf4770040 +#define F367CAB_TEST_TAP_SELECT 0xf477003f + +/* EQU_Q_TESTTAP_L */ +#define R367CAB_EQU_Q_TESTTAP_L 0xf478 +#define F367CAB_Q_TEST_TAP_L 0xf47800ff + +/* EQU_Q_TESTTAP_M */ +#define R367CAB_EQU_Q_TESTTAP_M 0xf479 +#define F367CAB_Q_TEST_TAP_M 0xf47900ff + +/* EQU_Q_TESTTAP_H */ +#define R367CAB_EQU_Q_TESTTAP_H 0xf47a +#define F367CAB_Q_TEST_TAP_H 0xf47a001f + +/* EQU_TAP_CTRL */ +#define R367CAB_EQU_TAP_CTRL 0xf47b +#define F367CAB_MTAP_FRZ 0xf47b0010 +#define F367CAB_PRE_FREEZE 0xf47b0008 +#define F367CAB_DFE_TAPMON_EN 0xf47b0004 +#define F367CAB_FFE_TAPMON_EN 0xf47b0002 +#define F367CAB_MTAP_ONLY 0xf47b0001 + +/* EQU_CTR_CRL_CONTROL_L */ +#define R367CAB_EQU_CTR_CRL_CONTROL_L 0xf47c +#define F367CAB_EQU_CTR_CRL_CONTROL_LO 0xf47c00ff + +/* EQU_CTR_CRL_CONTROL_H */ +#define R367CAB_EQU_CTR_CRL_CONTROL_H 0xf47d +#define F367CAB_EQU_CTR_CRL_CONTROL_HI 0xf47d00ff + +/* EQU_CTR_HIPOW_L */ +#define R367CAB_EQU_CTR_HIPOW_L 0xf47e +#define F367CAB_CTR_HIPOW_L 0xf47e00ff + +/* EQU_CTR_HIPOW_H */ +#define R367CAB_EQU_CTR_HIPOW_H 0xf47f +#define F367CAB_CTR_HIPOW_H 0xf47f00ff + +/* EQU_I_EQU_LO */ +#define R367CAB_EQU_I_EQU_LO 0xf480 +#define F367CAB_EQU_I_EQU_L 0xf48000ff + +/* EQU_I_EQU_HI */ +#define R367CAB_EQU_I_EQU_HI 0xf481 +#define F367CAB_EQU_I_EQU_H 0xf4810003 + +/* EQU_Q_EQU_LO */ +#define R367CAB_EQU_Q_EQU_LO 0xf482 +#define F367CAB_EQU_Q_EQU_L 0xf48200ff + +/* EQU_Q_EQU_HI */ +#define R367CAB_EQU_Q_EQU_HI 0xf483 +#define F367CAB_EQU_Q_EQU_H 0xf4830003 + +/* EQU_MAPPER */ +#define R367CAB_EQU_MAPPER 0xf484 +#define F367CAB_QUAD_AUTO 0xf4840080 +#define F367CAB_QUAD_INV 0xf4840040 +#define F367CAB_QAM_MODE 0xf4840007 + +/* EQU_SWEEP_RATE */ +#define R367CAB_EQU_SWEEP_RATE 0xf485 +#define F367CAB_SNR_PER 0xf48500c0 +#define F367CAB_SWEEP_RATE 0xf485003f + +/* EQU_SNR_LO */ +#define R367CAB_EQU_SNR_LO 0xf486 +#define F367CAB_SNR_LO 0xf48600ff + +/* EQU_SNR_HI */ +#define R367CAB_EQU_SNR_HI 0xf487 +#define F367CAB_SNR_HI 0xf48700ff + +/* EQU_GAMMA_LO */ +#define R367CAB_EQU_GAMMA_LO 0xf488 +#define F367CAB_GAMMA_LO 0xf48800ff + +/* EQU_GAMMA_HI */ +#define R367CAB_EQU_GAMMA_HI 0xf489 +#define F367CAB_GAMMA_ME 0xf48900ff + +/* EQU_ERR_GAIN */ +#define R367CAB_EQU_ERR_GAIN 0xf48a +#define F367CAB_EQA1MU 0xf48a0070 +#define F367CAB_CRL2MU 0xf48a000e +#define F367CAB_GAMMA_HI 0xf48a0001 + +/* EQU_RADIUS */ +#define R367CAB_EQU_RADIUS 0xf48b +#define F367CAB_RADIUS 0xf48b00ff + +/* EQU_FFE_MAINTAP */ +#define R367CAB_EQU_FFE_MAINTAP 0xf48c +#define F367CAB_FFE_MAINTAP_INIT 0xf48c00ff + +/* EQU_FFE_LEAKAGE */ +#define R367CAB_EQU_FFE_LEAKAGE 0xf48e +#define F367CAB_LEAK_PER 0xf48e00f0 +#define F367CAB_EQU_OUTSEL 0xf48e0002 +#define F367CAB_PNT2dFE 0xf48e0001 + +/* EQU_FFE_MAINTAP_POS */ +#define R367CAB_EQU_FFE_MAINTAP_POS 0xf48f +#define F367CAB_FFE_LEAK_EN 0xf48f0080 +#define F367CAB_DFE_LEAK_EN 0xf48f0040 +#define F367CAB_FFE_MAINTAP_POS 0xf48f003f + +/* EQU_GAIN_WIDE */ +#define R367CAB_EQU_GAIN_WIDE 0xf490 +#define F367CAB_DFE_GAIN_WIDE 0xf49000f0 +#define F367CAB_FFE_GAIN_WIDE 0xf490000f + +/* EQU_GAIN_NARROW */ +#define R367CAB_EQU_GAIN_NARROW 0xf491 +#define F367CAB_DFE_GAIN_NARROW 0xf49100f0 +#define F367CAB_FFE_GAIN_NARROW 0xf491000f + +/* EQU_CTR_LPF_GAIN */ +#define R367CAB_EQU_CTR_LPF_GAIN 0xf492 +#define F367CAB_CTR_GTO 0xf4920080 +#define F367CAB_CTR_GDIR 0xf4920070 +#define F367CAB_SWEEP_EN 0xf4920008 +#define F367CAB_CTR_GINT 0xf4920007 + +/* EQU_CRL_LPF_GAIN */ +#define R367CAB_EQU_CRL_LPF_GAIN 0xf493 +#define F367CAB_CRL_GTO 0xf4930080 +#define F367CAB_CRL_GDIR 0xf4930070 +#define F367CAB_SWEEP_DIR 0xf4930008 +#define F367CAB_CRL_GINT 0xf4930007 + +/* EQU_GLOBAL_GAIN */ +#define R367CAB_EQU_GLOBAL_GAIN 0xf494 +#define F367CAB_CRL_GAIN 0xf49400f8 +#define F367CAB_CTR_INC_GAIN 0xf4940004 +#define F367CAB_CTR_FRAC 0xf4940003 + +/* EQU_CRL_LD_SEN */ +#define R367CAB_EQU_CRL_LD_SEN 0xf495 +#define F367CAB_CTR_BADPOINT_EN 0xf4950080 +#define F367CAB_CTR_GAIN 0xf4950070 +#define F367CAB_LIMANEN 0xf4950008 +#define F367CAB_CRL_LD_SEN 0xf4950007 + +/* EQU_CRL_LD_VAL */ +#define R367CAB_EQU_CRL_LD_VAL 0xf496 +#define F367CAB_CRL_BISTH_LIMIT 0xf4960080 +#define F367CAB_CARE_EN 0xf4960040 +#define F367CAB_CRL_LD_PER 0xf4960030 +#define F367CAB_CRL_LD_WST 0xf496000c +#define F367CAB_CRL_LD_TFS 0xf4960003 + +/* EQU_CRL_TFR */ +#define R367CAB_EQU_CRL_TFR 0xf497 +#define F367CAB_CRL_LD_TFR 0xf49700ff + +/* EQU_CRL_BISTH_LO */ +#define R367CAB_EQU_CRL_BISTH_LO 0xf498 +#define F367CAB_CRL_BISTH_LO 0xf49800ff + +/* EQU_CRL_BISTH_HI */ +#define R367CAB_EQU_CRL_BISTH_HI 0xf499 +#define F367CAB_CRL_BISTH_HI 0xf49900ff + +/* EQU_SWEEP_RANGE_LO */ +#define R367CAB_EQU_SWEEP_RANGE_LO 0xf49a +#define F367CAB_SWEEP_RANGE_LO 0xf49a00ff + +/* EQU_SWEEP_RANGE_HI */ +#define R367CAB_EQU_SWEEP_RANGE_HI 0xf49b +#define F367CAB_SWEEP_RANGE_HI 0xf49b00ff + +/* EQU_CRL_LIMITER */ +#define R367CAB_EQU_CRL_LIMITER 0xf49c +#define F367CAB_BISECTOR_EN 0xf49c0080 +#define F367CAB_PHEST128_EN 0xf49c0040 +#define F367CAB_CRL_LIM 0xf49c003f + +/* EQU_MODULUS_MAP */ +#define R367CAB_EQU_MODULUS_MAP 0xf49d +#define F367CAB_PNT_DEPTH 0xf49d00e0 +#define F367CAB_MODULUS_CMP 0xf49d001f + +/* EQU_PNT_GAIN */ +#define R367CAB_EQU_PNT_GAIN 0xf49e +#define F367CAB_PNT_EN 0xf49e0080 +#define F367CAB_MODULUSMAP_EN 0xf49e0040 +#define F367CAB_PNT_GAIN 0xf49e003f + +/* FEC_AC_CTR_0 */ +#define R367CAB_FEC_AC_CTR_0 0xf4a8 +#define F367CAB_BE_BYPASS 0xf4a80020 +#define F367CAB_REFRESH47 0xf4a80010 +#define F367CAB_CT_NBST 0xf4a80008 +#define F367CAB_TEI_ENA 0xf4a80004 +#define F367CAB_DS_ENA 0xf4a80002 +#define F367CAB_TSMF_EN 0xf4a80001 + +/* FEC_AC_CTR_1 */ +#define R367CAB_FEC_AC_CTR_1 0xf4a9 +#define F367CAB_DEINT_DEPTH 0xf4a900ff + +/* FEC_AC_CTR_2 */ +#define R367CAB_FEC_AC_CTR_2 0xf4aa +#define F367CAB_DEINT_M 0xf4aa00f8 +#define F367CAB_DIS_UNLOCK 0xf4aa0004 +#define F367CAB_DESCR_MODE 0xf4aa0003 + +/* FEC_AC_CTR_3 */ +#define R367CAB_FEC_AC_CTR_3 0xf4ab +#define F367CAB_DI_UNLOCK 0xf4ab0080 +#define F367CAB_DI_FREEZE 0xf4ab0040 +#define F367CAB_MISMATCH 0xf4ab0030 +#define F367CAB_ACQ_MODE 0xf4ab000c +#define F367CAB_TRK_MODE 0xf4ab0003 + +/* FEC_STATUS */ +#define R367CAB_FEC_STATUS 0xf4ac +#define F367CAB_DEINT_SMCNTR 0xf4ac00e0 +#define F367CAB_DEINT_SYNCSTATE 0xf4ac0018 +#define F367CAB_DEINT_SYNLOST 0xf4ac0004 +#define F367CAB_DESCR_SYNCSTATE 0xf4ac0002 + +/* RS_COUNTER_0 */ +#define R367CAB_RS_COUNTER_0 0xf4ae +#define F367CAB_BK_CT_L 0xf4ae00ff + +/* RS_COUNTER_1 */ +#define R367CAB_RS_COUNTER_1 0xf4af +#define F367CAB_BK_CT_H 0xf4af00ff + +/* RS_COUNTER_2 */ +#define R367CAB_RS_COUNTER_2 0xf4b0 +#define F367CAB_CORR_CT_L 0xf4b000ff + +/* RS_COUNTER_3 */ +#define R367CAB_RS_COUNTER_3 0xf4b1 +#define F367CAB_CORR_CT_H 0xf4b100ff + +/* RS_COUNTER_4 */ +#define R367CAB_RS_COUNTER_4 0xf4b2 +#define F367CAB_UNCORR_CT_L 0xf4b200ff + +/* RS_COUNTER_5 */ +#define R367CAB_RS_COUNTER_5 0xf4b3 +#define F367CAB_UNCORR_CT_H 0xf4b300ff + +/* BERT_0 */ +#define R367CAB_BERT_0 0xf4b4 +#define F367CAB_RS_NOCORR 0xf4b40004 +#define F367CAB_CT_HOLD 0xf4b40002 +#define F367CAB_CT_CLEAR 0xf4b40001 + +/* BERT_1 */ +#define R367CAB_BERT_1 0xf4b5 +#define F367CAB_BERT_ON 0xf4b50020 +#define F367CAB_BERT_ERR_SRC 0xf4b50010 +#define F367CAB_BERT_ERR_MODE 0xf4b50008 +#define F367CAB_BERT_NBYTE 0xf4b50007 + +/* BERT_2 */ +#define R367CAB_BERT_2 0xf4b6 +#define F367CAB_BERT_ERRCOUNT_L 0xf4b600ff + +/* BERT_3 */ +#define R367CAB_BERT_3 0xf4b7 +#define F367CAB_BERT_ERRCOUNT_H 0xf4b700ff + +/* OUTFORMAT_0 */ +#define R367CAB_OUTFORMAT_0 0xf4b8 +#define F367CAB_CLK_POLARITY 0xf4b80080 +#define F367CAB_FEC_TYPE 0xf4b80040 +#define F367CAB_SYNC_STRIP 0xf4b80008 +#define F367CAB_TS_SWAP 0xf4b80004 +#define F367CAB_OUTFORMAT 0xf4b80003 + +/* OUTFORMAT_1 */ +#define R367CAB_OUTFORMAT_1 0xf4b9 +#define F367CAB_CI_DIVRANGE 0xf4b900ff + +/* SMOOTHER_2 */ +#define R367CAB_SMOOTHER_2 0xf4be +#define F367CAB_FIFO_BYPASS 0xf4be0020 + +/* TSMF_CTRL_0 */ +#define R367CAB_TSMF_CTRL_0 0xf4c0 +#define F367CAB_TS_NUMBER 0xf4c0001e +#define F367CAB_SEL_MODE 0xf4c00001 + +/* TSMF_CTRL_1 */ +#define R367CAB_TSMF_CTRL_1 0xf4c1 +#define F367CAB_CHECK_ERROR_BIT 0xf4c10080 +#define F367CAB_CHCK_F_SYNC 0xf4c10040 +#define F367CAB_H_MODE 0xf4c10008 +#define F367CAB_D_V_MODE 0xf4c10004 +#define F367CAB_MODE 0xf4c10003 + +/* TSMF_CTRL_3 */ +#define R367CAB_TSMF_CTRL_3 0xf4c3 +#define F367CAB_SYNC_IN_COUNT 0xf4c300f0 +#define F367CAB_SYNC_OUT_COUNT 0xf4c3000f + +/* TS_ON_ID_0 */ +#define R367CAB_TS_ON_ID_0 0xf4c4 +#define F367CAB_TS_ID_L 0xf4c400ff + +/* TS_ON_ID_1 */ +#define R367CAB_TS_ON_ID_1 0xf4c5 +#define F367CAB_TS_ID_H 0xf4c500ff + +/* TS_ON_ID_2 */ +#define R367CAB_TS_ON_ID_2 0xf4c6 +#define F367CAB_ON_ID_L 0xf4c600ff + +/* TS_ON_ID_3 */ +#define R367CAB_TS_ON_ID_3 0xf4c7 +#define F367CAB_ON_ID_H 0xf4c700ff + +/* RE_STATUS_0 */ +#define R367CAB_RE_STATUS_0 0xf4c8 +#define F367CAB_RECEIVE_STATUS_L 0xf4c800ff + +/* RE_STATUS_1 */ +#define R367CAB_RE_STATUS_1 0xf4c9 +#define F367CAB_RECEIVE_STATUS_LH 0xf4c900ff + +/* RE_STATUS_2 */ +#define R367CAB_RE_STATUS_2 0xf4ca +#define F367CAB_RECEIVE_STATUS_HL 0xf4ca00ff + +/* RE_STATUS_3 */ +#define R367CAB_RE_STATUS_3 0xf4cb +#define F367CAB_RECEIVE_STATUS_HH 0xf4cb003f + +/* TS_STATUS_0 */ +#define R367CAB_TS_STATUS_0 0xf4cc +#define F367CAB_TS_STATUS_L 0xf4cc00ff + +/* TS_STATUS_1 */ +#define R367CAB_TS_STATUS_1 0xf4cd +#define F367CAB_TS_STATUS_H 0xf4cd007f + +/* TS_STATUS_2 */ +#define R367CAB_TS_STATUS_2 0xf4ce +#define F367CAB_ERROR 0xf4ce0080 +#define F367CAB_EMERGENCY 0xf4ce0040 +#define F367CAB_CRE_TS 0xf4ce0030 +#define F367CAB_VER 0xf4ce000e +#define F367CAB_M_LOCK 0xf4ce0001 + +/* TS_STATUS_3 */ +#define R367CAB_TS_STATUS_3 0xf4cf +#define F367CAB_UPDATE_READY 0xf4cf0080 +#define F367CAB_END_FRAME_HEADER 0xf4cf0040 +#define F367CAB_CONTCNT 0xf4cf0020 +#define F367CAB_TS_IDENTIFIER_SEL 0xf4cf000f + +/* T_O_ID_0 */ +#define R367CAB_T_O_ID_0 0xf4d0 +#define F367CAB_ON_ID_I_L 0xf4d000ff + +/* T_O_ID_1 */ +#define R367CAB_T_O_ID_1 0xf4d1 +#define F367CAB_ON_ID_I_H 0xf4d100ff + +/* T_O_ID_2 */ +#define R367CAB_T_O_ID_2 0xf4d2 +#define F367CAB_TS_ID_I_L 0xf4d200ff + +/* T_O_ID_3 */ +#define R367CAB_T_O_ID_3 0xf4d3 +#define F367CAB_TS_ID_I_H 0xf4d300ff + +#define STV0367CAB_NBREGS 187 + +#endif -- cgit v1.2.2 From e80edce1abfabf637edc68e8dd13ef0af6e46cdf Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:03:00 -0300 Subject: [media] xc5000: add support for DVB-C tuning Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/xc5000.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index 76ac5cd84af7..e3218c97d536 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -683,6 +683,24 @@ static int xc5000_set_params(struct dvb_frontend *fe, return -EINVAL; } priv->rf_mode = XC_RF_MODE_AIR; + } else if (fe->ops.info.type == FE_QAM) { + dprintk(1, "%s() QAM\n", __func__); + switch (params->u.qam.modulation) { + case QAM_16: + case QAM_32: + case QAM_64: + case QAM_128: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __func__); + priv->bandwidth = BANDWIDTH_8_MHZ; + priv->video_standard = DTV7_8; + priv->freq_hz = params->frequency - 2750000; + priv->rf_mode = XC_RF_MODE_CABLE; + break; + default: + return -EINVAL; + } } else { printk(KERN_ERR "xc5000 modulation type not supported!\n"); return -EINVAL; -- cgit v1.2.2 From 78db854757aa4110f9c6873d1529b851037a3405 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:04:00 -0300 Subject: [media] Initial commit to support NetUP Dual DVB-T/C CI RF card The card based on cx23885 PCI-e brige. Altera FPGA for CI, multistandard demods stv0367 from STM for QAM & OFDM, Xcieve xc5000 tuners and additional cx25840 for second analog input. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0367.h | 4 +- drivers/media/video/cx23885/Kconfig | 3 +- drivers/media/video/cx23885/cx23885-cards.c | 103 ++++++++++++++++- drivers/media/video/cx23885/cx23885-core.c | 22 ++-- drivers/media/video/cx23885/cx23885-dvb.c | 172 ++++++++++++++++++++++++++-- drivers/media/video/cx23885/cx23885.h | 4 +- 6 files changed, 286 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0367.h b/drivers/media/dvb/frontends/stv0367.h index 822a8e98783f..93cc4a57eea0 100644 --- a/drivers/media/dvb/frontends/stv0367.h +++ b/drivers/media/dvb/frontends/stv0367.h @@ -4,8 +4,8 @@ * Driver for ST STV0367 DVB-T & DVB-C demodulator IC. * * Copyright (C) ST Microelectronics. - * Copyright (C) 2010 NetUP Inc. - * Copyright (C) 2010 Igor M. Liplianin + * Copyright (C) 2010,2011 NetUP Inc. + * Copyright (C) 2010,2011 Igor M. Liplianin * * 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 diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 5e5faadd678f..3b6e7f28568e 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -1,6 +1,7 @@ config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT + depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND + select SND_PCM select I2C_ALGOBIT select VIDEO_BTCX select VIDEO_TUNER diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index b298b730943c..a3fe26cf6367 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -24,10 +24,14 @@ #include #include #include +#include +#include #include "cx23885.h" #include "tuner-xc2028.h" #include "netup-init.h" +#include "altera-ci.h" +#include "xc5000.h" #include "cx23888-ir.h" static unsigned int enable_885_ir; @@ -187,7 +191,7 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, }, [CX23885_BOARD_NETUP_DUAL_DVBS2_CI] = { - .cimax = 1, + .ci_type = 1, .name = "NetUP Dual DVB-S2 CI", .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, @@ -329,6 +333,19 @@ struct cx23885_board cx23885_boards[] = { CX25840_SVIDEO_CHROMA4, } }, }, + [CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF] = { + .ci_type = 2, + .name = "NetUP Dual DVB-T/C-CI RF", + .porta = CX23885_ANALOG_VIDEO, + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_XC5000, + .tuner_addr = 0x64, + .input = { { + .type = CX23885_VMUX_TELEVISION, + .vmux = CX25840_COMPOSITE1, + } }, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -520,6 +537,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x5654, .subdevice = 0x2390, .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID, + }, { + .subvendor = 0x1b55, + .subdevice = 0xe2e4, + .card = CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -740,6 +761,9 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) /* Tuner Reset Command */ bitmask = 0x02; break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + altera_ci_tuner_reset(dev, port->nr); + break; } if (bitmask) { @@ -998,6 +1022,33 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID: cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + /* GPIO-0 ~INT in + GPIO-1 TMS out + GPIO-2 ~reset chips out + GPIO-3 to GPIO-10 data/addr for CA in/out + GPIO-11 ~CS out + GPIO-12 ADDR out + GPIO-13 ~WR out + GPIO-14 ~RD out + GPIO-15 ~RDY in + GPIO-16 TCK out + GPIO-17 TDO in + GPIO-18 TDI out + */ + cx_set(GP0_IO, 0x00060000); /* GPIO-1,2 as out */ + /* GPIO-0 as INT, reset & TMS low */ + cx_clear(GP0_IO, 0x00010006); + mdelay(100);/* reset delay */ + cx_set(GP0_IO, 0x00000004); /* reset high */ + cx_write(MC417_CTL, 0x00000037);/* enable GPIO-3..18 pins */ + /* GPIO-17 is TDO in, GPIO-15 is ~RDY in, rest is out */ + cx_write(MC417_OEN, 0x00005000); + /* ~RD, ~WR high; ADDR low; ~CS high */ + cx_write(MC417_RWD, 0x00000d00); + /* enable irq */ + cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/ + break; } } @@ -1113,6 +1164,31 @@ void cx23885_ir_fini(struct cx23885_dev *dev) } } +int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) +{ + int data; + int tdo = 0; + struct cx23885_dev *dev = (struct cx23885_dev *)device; + /*TMS*/ + data = ((cx_read(GP0_IO)) & (~0x00000002)); + data |= (tms ? 0x00020002 : 0x00020000); + cx_write(GP0_IO, data); + + /*TDI*/ + data = ((cx_read(MC417_RWD)) & (~0x0000a000)); + data |= (tdi ? 0x00008000 : 0); + cx_write(MC417_RWD, data); + if (read_tdo) + tdo = (data & 0x00004000) ? 1 : 0; /*TDO*/ + + cx_write(MC417_RWD, data | 0x00002000); + udelay(1); + /*TCK*/ + cx_write(MC417_RWD, data); + + return tdo; +} + void cx23885_ir_pci_int_enable(struct cx23885_dev *dev) { switch (dev->board) { @@ -1212,6 +1288,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; @@ -1271,6 +1348,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: case CX23885_BOARD_COMPRO_VIDEOMATE_E650F: case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: case CX23885_BOARD_COMPRO_VIDEOMATE_E800: case CX23885_BOARD_HAUPPAUGE_HVR1850: case CX23885_BOARD_MYGICA_X8506: @@ -1293,6 +1371,29 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: netup_initialize(dev); break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { + int ret; + const struct firmware *fw; + const char *filename = "dvb-netup-altera-01.fw"; + char *action = "configure"; + struct altera_config netup_config = { + .dev = dev, + .action = action, + .jtag_io = netup_jtag_io, + }; + + netup_initialize(dev); + + ret = request_firmware(&fw, filename, &dev->pci->dev); + if (ret != 0) + printk(KERN_ERR "did not find the firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details " + "on firmware-problems.", filename); + else + altera_init(&netup_config, fw); + + break; + } } } diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 359882419b7f..9ad4c9c577e0 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -29,9 +29,11 @@ #include #include #include +#include #include "cx23885.h" #include "cimax2.h" +#include "altera-ci.h" #include "cx23888-ir.h" #include "cx23885-ir.h" #include "cx23885-av.h" @@ -902,8 +904,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); cx23885_irq_add(dev, 0x001f00); - if (cx23885_boards[dev->board].cimax > 0) - cx23885_irq_add(dev, 0x01800000); /* for CiMaxes */ /* External Master 1 Bus */ dev->i2c_bus[0].nr = 0; @@ -1822,14 +1822,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) PCI_MSK_IR); } - if (cx23885_boards[dev->board].cimax > 0 && - ((pci_status & PCI_MSK_GPIO0) || - (pci_status & PCI_MSK_GPIO1))) { + if (cx23885_boards[dev->board].ci_type == 1 && + (pci_status & (PCI_MSK_GPIO1 | PCI_MSK_GPIO0))) + handled += netup_ci_slot_status(dev, pci_status); - if (cx23885_boards[dev->board].cimax > 0) - handled += netup_ci_slot_status(dev, pci_status); - - } + if (cx23885_boards[dev->board].ci_type == 2 && + (pci_status & PCI_MSK_GPIO0)) + handled += altera_ci_irq(dev); if (ts1_status) { if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) @@ -2064,7 +2063,10 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev, switch (dev->board) { case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: - cx23885_irq_add_enable(dev, 0x01800000); /* for NetUP */ + cx23885_irq_add_enable(dev, PCI_MSK_GPIO1 | PCI_MSK_GPIO0); + break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + cx23885_irq_add_enable(dev, PCI_MSK_GPIO0); break; } diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 5958cb882e93..cf36b9b4794e 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -58,6 +58,8 @@ #include "atbm8830.h" #include "ds3000.h" #include "cx23885-f300.h" +#include "altera-ci.h" +#include "stv0367.h" static unsigned int debug; @@ -108,6 +110,22 @@ static void dvb_buf_release(struct videobuf_queue *q, cx23885_free_buffer(q, (struct cx23885_buffer *)vb); } +static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) +{ + struct videobuf_dvb_frontends *f; + struct videobuf_dvb_frontend *fe; + + f = &port->frontends; + + if (f->gate <= 1) /* undefined or fe0 */ + fe = videobuf_dvb_get_frontend(f, 1); + else + fe = videobuf_dvb_get_frontend(f, f->gate); + + if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) + fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); +} + static struct videobuf_queue_ops dvb_qops = { .buf_setup = dvb_buf_setup, .buf_prepare = dvb_buf_prepare, @@ -570,12 +588,84 @@ static struct max2165_config mygic_x8558pro_max2165_cfg2 = { .i2c_address = 0x60, .osc_clk = 20 }; +static struct stv0367_config netup_stv0367_config[] = { + { + .demod_address = 0x1c, + .xtal = 27000000, + .if_khz = 4500, + .if_iq_mode = 0, + .ts_mode = 1, + .clk_pol = 0, + }, { + .demod_address = 0x1d, + .xtal = 27000000, + .if_khz = 4500, + .if_iq_mode = 0, + .ts_mode = 1, + .clk_pol = 0, + }, +}; + +static struct xc5000_config netup_xc5000_config[] = { + { + .i2c_address = 0x61, + .if_khz = 4500, + }, { + .i2c_address = 0x64, + .if_khz = 4500, + }, +}; + +int netup_altera_fpga_rw(void *device, int flag, int data, int read) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)device; + unsigned long timeout = jiffies + msecs_to_jiffies(1); + int mem = 0; + + cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); + if (read) + cx_set(MC417_OEN, ALT_DATA); + else { + cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ + mem = cx_read(MC417_RWD); + mem &= ~ALT_DATA; + mem |= (data & ALT_DATA); + cx_write(MC417_RWD, mem); + } + + if (flag) + cx_set(MC417_RWD, ALT_AD_RG);/* ADDR */ + else + cx_clear(MC417_RWD, ALT_AD_RG);/* VAL */ + + cx_clear(MC417_RWD, ALT_CS);/* ~CS */ + if (read) + cx_clear(MC417_RWD, ALT_RD); + else + cx_clear(MC417_RWD, ALT_WR); + + for (;;) { + mem = cx_read(MC417_RWD); + if ((mem & ALT_RDY) == 0) + break; + if (time_after(jiffies, timeout)) + break; + udelay(1); + } + + cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); + if (read) + return mem & ALT_DATA; + + return 0; +}; static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; - struct videobuf_dvb_frontend *fe0; + struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + int mfe_shared = 0; /* bus not shared by default */ int ret; /* Get the first frontend */ @@ -586,6 +676,12 @@ static int dvb_register(struct cx23885_tsport *port) /* init struct videobuf_dvb */ fe0->dvb.name = dev->name; + /* multi-frontend gate control is undefined or defaults to fe0 */ + port->frontends.gate = 0; + + /* Sets the gate control callback to be used by i2c command calls */ + port->gate_ctrl = cx23885_dvb_gate_ctrl; + /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: @@ -966,20 +1062,61 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; - + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + i2c_bus = &dev->i2c_bus[0]; + mfe_shared = 1;/* MFE */ + port->frontends.gate = 0;/* not clear for me yet */ + /* ports B, C */ + /* MFE frontend 1 DVB-T */ + fe0->dvb.frontend = dvb_attach(stv0367ter_attach, + &netup_stv0367_config[port->nr - 1], + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + if (NULL == dvb_attach(xc5000_attach, + fe0->dvb.frontend, + &i2c_bus->i2c_adap, + &netup_xc5000_config[port->nr - 1])) + goto frontend_detach; + /* MFE frontend 2 */ + fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); + if (fe1 == NULL) + goto frontend_detach; + /* DVB-C init */ + fe1->dvb.frontend = dvb_attach(stv0367cab_attach, + &netup_stv0367_config[port->nr - 1], + &i2c_bus->i2c_adap); + if (fe1->dvb.frontend != NULL) { + fe1->dvb.frontend->id = 1; + if (NULL == dvb_attach(xc5000_attach, + fe1->dvb.frontend, + &i2c_bus->i2c_adap, + &netup_xc5000_config[port->nr - 1])) + goto frontend_detach; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", dev->name); break; } - if (NULL == fe0->dvb.frontend) { + + if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { printk(KERN_ERR "%s: frontend initialization failed\n", - dev->name); - return -1; + dev->name); + goto frontend_detach; } + /* define general-purpose callback pointer */ fe0->dvb.frontend->callback = cx23885_tuner_callback; + if (fe1) + fe1->dvb.frontend->callback = cx23885_tuner_callback; +#if 0 + /* Ensure all frontends negotiate bus access */ + fe0->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; + if (fe1) + fe1->dvb.frontend->ops.ts_bus_ctrl = cx23885_dvb_bus_ctrl; +#endif /* Put the analog decoder in standby to keep it quiet */ call_all(dev, core, s_power, 0); @@ -989,10 +1126,10 @@ static int dvb_register(struct cx23885_tsport *port) /* register everything */ ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, - &dev->pci->dev, adapter_nr, 0, + &dev->pci->dev, adapter_nr, mfe_shared, cx23885_dvb_fe_ioctl_override); if (ret) - return ret; + goto frontend_detach; /* init CI & MAC */ switch (dev->board) { @@ -1008,6 +1145,17 @@ static int dvb_register(struct cx23885_tsport *port) netup_ci_init(port); break; } + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: { + struct altera_ci_config netup_ci_cfg = { + .dev = dev,/* magic number to identify*/ + .adapter = &port->frontends.adapter,/* for CI */ + .demux = &fe0->dvb.demux,/* for hw pid filter */ + .fpga_rw = netup_altera_fpga_rw, + }; + + altera_ci_init(&netup_ci_cfg, port->nr); + break; + } case CX23885_BOARD_TEVII_S470: { u8 eeprom[256]; /* 24C02 i2c eeprom */ @@ -1024,6 +1172,11 @@ static int dvb_register(struct cx23885_tsport *port) } return ret; + +frontend_detach: + port->gate_ctrl = NULL; + videobuf_dvb_dealloc_frontends(&port->frontends); + return -EINVAL; } int cx23885_dvb_register(struct cx23885_tsport *port) @@ -1100,8 +1253,13 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: netup_ci_exit(port); break; + case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: + altera_ci_release(port->dev, port->nr); + break; } + port->gate_ctrl = NULL; + return 0; } diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 62e41ab65810..8b77feabc594 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -85,6 +85,7 @@ #define CX23885_BOARD_MYGICA_X8558PRO 27 #define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28 #define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29 +#define CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF 30 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -220,7 +221,7 @@ struct cx23885_board { */ u32 clk_freq; struct cx23885_input input[MAX_CX23885_INPUT]; - int cimax; /* for NetUP */ + int ci_type; /* for NetUP */ }; struct cx23885_subid { @@ -303,6 +304,7 @@ struct cx23885_tsport { /* Allow a single tsport to have multiple frontends */ u32 num_frontends; + void (*gate_ctrl)(struct cx23885_tsport *port, int open); void *port_priv; }; -- cgit v1.2.2 From 557f48d5720b45dae07788bc9976762c363b8ad0 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:05:00 -0300 Subject: [media] cx23885: implement tuner_bus parameter for cx23885_board structure There is two external I2C buses in cx23885 chip. Currently, analog tuners supported for second I2C bus only In NetUP Dual DVB-T/C CI RF card tuners connected to first bus So, in order to support analog tuners sitting on first bus we need modifications. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 5 +++++ drivers/media/video/cx23885/cx23885-core.c | 5 +++-- drivers/media/video/cx23885/cx23885-video.c | 7 ++++--- drivers/media/video/cx23885/cx23885.h | 2 ++ 4 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index a3fe26cf6367..fb2045af499f 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -94,6 +94,7 @@ struct cx23885_board cx23885_boards[] = { .portc = CX23885_MPEG_DVB, .tuner_type = TUNER_PHILIPS_TDA8290, .tuner_addr = 0x42, /* 0x84 >> 1 */ + .tuner_bus = 1, .input = {{ .type = CX23885_VMUX_TELEVISION, .vmux = CX25840_VIN7_CH3 | @@ -216,6 +217,7 @@ struct cx23885_board cx23885_boards[] = { .name = "Mygica X8506 DMB-TH", .tuner_type = TUNER_XC5000, .tuner_addr = 0x61, + .tuner_bus = 1, .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_DVB, .input = { @@ -245,6 +247,7 @@ struct cx23885_board cx23885_boards[] = { .name = "Magic-Pro ProHDTV Extreme 2", .tuner_type = TUNER_XC5000, .tuner_addr = 0x61, + .tuner_bus = 1, .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_DVB, .input = { @@ -293,6 +296,7 @@ struct cx23885_board cx23885_boards[] = { .porta = CX23885_ANALOG_VIDEO, .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, + .tuner_bus = 1, .input = {{ .type = CX23885_VMUX_TELEVISION, .vmux = CX25840_VIN2_CH1 | @@ -317,6 +321,7 @@ struct cx23885_board cx23885_boards[] = { .name = "GoTView X5 3D Hybrid", .tuner_type = TUNER_XC5000, .tuner_addr = 0x64, + .tuner_bus = 1, .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_DVB, .input = {{ diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 9ad4c9c577e0..d621d76f3a9a 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -970,11 +970,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) /* Assume some sensible defaults */ dev->tuner_type = cx23885_boards[dev->board].tuner_type; dev->tuner_addr = cx23885_boards[dev->board].tuner_addr; + dev->tuner_bus = cx23885_boards[dev->board].tuner_bus; dev->radio_type = cx23885_boards[dev->board].radio_type; dev->radio_addr = cx23885_boards[dev->board].radio_addr; - dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n", - __func__, dev->tuner_type, dev->tuner_addr); + dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x tuner_bus = %d\n", + __func__, dev->tuner_type, dev->tuner_addr, dev->tuner_bus); dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n", __func__, dev->radio_type, dev->radio_addr); diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 644fcb808c0b..ee57f6bedbe3 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -1468,16 +1468,17 @@ int cx23885_video_register(struct cx23885_dev *dev) cx23885_irq_add_enable(dev, 0x01); - if (TUNER_ABSENT != dev->tuner_type) { + if ((TUNER_ABSENT != dev->tuner_type) && + ((dev->tuner_bus == 0) || (dev->tuner_bus == 1))) { struct v4l2_subdev *sd = NULL; if (dev->tuner_addr) sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[1].i2c_adap, + &dev->i2c_bus[dev->tuner_bus].i2c_adap, "tuner", dev->tuner_addr, NULL); else sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_bus[1].i2c_adap, + &dev->i2c_bus[dev->tuner_bus].i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV)); if (sd) { struct tuner_setup tun_setup; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 8b77feabc594..d8c76b05e4d7 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -209,6 +209,7 @@ struct cx23885_board { unsigned int radio_type; unsigned char tuner_addr; unsigned char radio_addr; + unsigned int tuner_bus; /* Vendors can and do run the PCIe bridge at different * clock rates, driven physically by crystals on the PCBs. @@ -364,6 +365,7 @@ struct cx23885_dev { v4l2_std_id tvnorm; unsigned int tuner_type; unsigned char tuner_addr; + unsigned int tuner_bus; unsigned int radio_type; unsigned char radio_addr; unsigned int has_radio; -- cgit v1.2.2 From 10d0dcd73c619d86b8ba1c9cd753ce749f578bf4 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:06:00 -0300 Subject: [media] cx23885: implement num_fds_portb, num_fds_portc parameters for cx23885_board structure This is needed for multifrontend support. NetUP Dual DVB-T/C CI RF card has frontends connected to port B & C Each frontend has two switchable cores - DVB-T & DVB-C Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-cards.c | 2 ++ drivers/media/video/cx23885/cx23885-core.c | 6 ++++++ drivers/media/video/cx23885/cx23885.h | 1 + 3 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index fb2045af499f..ea88722cb4ab 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -344,6 +344,8 @@ struct cx23885_board cx23885_boards[] = { .porta = CX23885_ANALOG_VIDEO, .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, + .num_fds_portb = 2, + .num_fds_portc = 2, .tuner_type = TUNER_XC5000, .tuner_addr = 0x64, .input = { { diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d621d76f3a9a..d778b1ae9217 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1005,6 +1005,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) } if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].num_fds_portb) + dev->ts1.num_frontends = + cx23885_boards[dev->board].num_fds_portb; if (cx23885_dvb_register(&dev->ts1) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", __func__); @@ -1019,6 +1022,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) } if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].num_fds_portc) + dev->ts2.num_frontends = + cx23885_boards[dev->board].num_fds_portc; if (cx23885_dvb_register(&dev->ts2) < 0) { printk(KERN_ERR "%s() Failed to register dvb on VID_C\n", diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index d8c76b05e4d7..8db2797bc7c3 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -205,6 +205,7 @@ typedef enum { struct cx23885_board { char *name; port_t porta, portb, portc; + int num_fds_portb, num_fds_portc; unsigned int tuner_type; unsigned int radio_type; unsigned char tuner_addr; -- cgit v1.2.2 From 702dd7903bda0b83f6f6cb66fdadc4e5bbb60646 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:07:00 -0300 Subject: [media] cx23885: disable MSI for NetUP cards, otherwise CI is not working Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-core.c | 4 ++++ drivers/media/video/cx23885/cx23885-reg.h | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index d778b1ae9217..9933810b4e33 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -1041,6 +1041,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_dev_checkrevision(dev); + /* disable MSI for NetUP cards, otherwise CI is not working */ + if (cx23885_boards[dev->board].ci_type > 0) + cx_clear(RDR_RDRCTL1, 1 << 8); + return 0; } diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index a28772db11f0..c87ac682ebbe 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -292,6 +292,7 @@ Channel manager Data Structure entry = 20 DWORD #define RDR_CFG0 0x00050000 #define RDR_CFG1 0x00050004 #define RDR_CFG2 0x00050008 +#define RDR_RDRCTL1 0x0005030c #define RDR_TLCTL0 0x00050318 /* APB DMAC Current Buffer Pointer */ -- cgit v1.2.2 From 2f2710bd4ee11a06e4c87956be4733566e288a2e Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 25 Jan 2011 17:08:00 -0300 Subject: [media] cx23885, altera-ci: enable all PID's less than 0x20 in hardware PID filter It takes too long time to scan due to low symbol rate PID's like PAT, PMT, CAT, NIT. For that matter we enabled permanently all PID's less 0x20 in hardware PID filter for NetUP Dual DVB-T/C CI RF card to combine rates. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/altera-ci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c index e5c0873aca15..ad6cc68d4b0c 100644 --- a/drivers/media/video/cx23885/altera-ci.c +++ b/drivers/media/video/cx23885/altera-ci.c @@ -521,7 +521,8 @@ static void altera_pid_control(struct netup_hw_pid_filter *pid_filt, struct fpga_internal *inter = pid_filt->internal; u8 store = 0; - if (pid == 0x2000) + /* pid 0-0x1f always enabled, don't touch them */ + if ((pid == 0x2000) || (pid < 0x20)) return; mutex_lock(&inter->fpga_mutex); @@ -567,8 +568,9 @@ static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt, netup_fpga_op_rw(inter, NETUP_CI_PID_ADDR1, ((i >> 8) & 0x03) | (pid_filt->nr << 2), 0); - - netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, store, 0); + /* pid 0-0x1f always enabled */ + netup_fpga_op_rw(inter, NETUP_CI_PID_DATA, + (i > 3 ? store : 0), 0); } mutex_unlock(&inter->fpga_mutex); -- cgit v1.2.2 From 7ee9e64a3d7379fd443090880158374181f754cf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 25 Jan 2011 18:25:39 -0300 Subject: [media] cx18: fix kernel oops when setting MPEG control before capturing The cxhdl->priv field was not set initially, only after capturing started. Signed-off-by: Hans Verkuil Acked-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index b988ec62af58..321c1b79794c 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -734,6 +734,7 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; cx->cxhdl.ops = &cx18_cxhdl_ops; cx->cxhdl.func = cx18_api_func; + cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; ret = cx2341x_handler_init(&cx->cxhdl, 50); if (ret) return ret; -- cgit v1.2.2 From 61ca1500c5ee04f2be34a4f58bb9baed0214b7a9 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Sun, 30 Jan 2011 16:33:01 -0300 Subject: [media] video/saa7164: Fix sparse warning: Using plain integer as NULL pointer This patch fixes the warning "Using plain integer as NULL pointer", generated by sparse, by replacing if (var == 0) with if (!var) after an allocation and all other offending 0s with NULL. KernelVersion: linus' tree-1f0324c Signed-off-by: Peter Huewe Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7164/saa7164-api.c | 10 +++++----- drivers/media/video/saa7164/saa7164-buffer.c | 16 ++++++++-------- drivers/media/video/saa7164/saa7164-bus.c | 8 ++++---- drivers/media/video/saa7164/saa7164-cmd.c | 10 +++++----- drivers/media/video/saa7164/saa7164-core.c | 8 ++++---- drivers/media/video/saa7164/saa7164-dvb.c | 4 ++-- drivers/media/video/saa7164/saa7164-encoder.c | 8 ++++---- drivers/media/video/saa7164/saa7164-fw.c | 2 +- drivers/media/video/saa7164/saa7164-vbi.c | 8 ++++---- 9 files changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c index bd86d970f4c2..8a98ab68239e 100644 --- a/drivers/media/video/saa7164/saa7164-api.c +++ b/drivers/media/video/saa7164/saa7164-api.c @@ -743,7 +743,7 @@ int saa7164_api_configure_dif(struct saa7164_port *port, u32 std) int saa7164_api_initialize_dif(struct saa7164_port *port) { struct saa7164_dev *dev = port->dev; - struct saa7164_port *p = 0; + struct saa7164_port *p = NULL; int ret = -EINVAL; u32 std = 0; @@ -926,9 +926,9 @@ int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev, int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) { - struct saa7164_port *tsport = 0; - struct saa7164_port *encport = 0; - struct saa7164_port *vbiport = 0; + struct saa7164_port *tsport = NULL; + struct saa7164_port *encport = NULL; + struct saa7164_port *vbiport = NULL; u32 idx, next_offset; int i; struct tmComResDescrHeader *hdr, *t; @@ -1340,7 +1340,7 @@ int saa7164_api_enum_subdevs(struct saa7164_dev *dev) /* Allocate enough storage for all of the descs */ buf = kzalloc(buflen, GFP_KERNEL); - if (buf == NULL) + if (!buf) return SAA_ERR_NO_RESOURCES; /* Retrieve them */ diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/video/saa7164/saa7164-buffer.c index ddd25211c9e8..66696fa8341d 100644 --- a/drivers/media/video/saa7164/saa7164-buffer.c +++ b/drivers/media/video/saa7164/saa7164-buffer.c @@ -93,7 +93,7 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, u32 len) { struct tmHWStreamParameters *params = &port->hw_streamingparams; - struct saa7164_buffer *buf = 0; + struct saa7164_buffer *buf = NULL; struct saa7164_dev *dev = port->dev; int i; @@ -103,7 +103,7 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, } buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL); - if (buf == NULL) { + if (!buf) { log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__); goto ret; } @@ -157,7 +157,7 @@ fail2: fail1: kfree(buf); - buf = 0; + buf = NULL; ret: return buf; } @@ -289,14 +289,14 @@ struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, struct saa7164_user_buffer *buf; buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL); - if (buf == 0) - return 0; + if (!buf) + return NULL; buf->data = kzalloc(len, GFP_KERNEL); - if (buf->data == 0) { + if (!buf->data) { kfree(buf); - return 0; + return NULL; } buf->actual_size = len; @@ -315,7 +315,7 @@ void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf) return; kfree(buf->data); - buf->data = 0; + buf->data = NULL; kfree(buf); } diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c index b2b0d97101d0..466e1b02f91f 100644 --- a/drivers/media/video/saa7164/saa7164-bus.c +++ b/drivers/media/video/saa7164/saa7164-bus.c @@ -158,7 +158,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg, return SAA_ERR_BAD_PARAMETER; } - if ((msg->size > 0) && (buf == 0)) { + if ((msg->size > 0) && (buf == NULL)) { printk(KERN_ERR "%s() Missing message buffer\n", __func__); return SAA_ERR_BAD_PARAMETER; } @@ -315,7 +315,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, saa7164_bus_verify(dev); - if (msg == 0) + if (msg == NULL) return ret; if (msg->size > dev->bus.m_wMaxReqSize) { @@ -324,7 +324,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, return ret; } - if ((peekonly == 0) && (msg->size > 0) && (buf == 0)) { + if ((peekonly == 0) && (msg->size > 0) && (buf == NULL)) { printk(KERN_ERR "%s() Missing msg buf, size should be %d bytes\n", __func__, msg->size); @@ -392,7 +392,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, printk(KERN_ERR "%s() Unexpected msg miss-match\n", __func__); saa7164_bus_dumpmsg(dev, msg, buf); - saa7164_bus_dumpmsg(dev, &msg_tmp, 0); + saa7164_bus_dumpmsg(dev, &msg_tmp, NULL); ret = SAA_ERR_INVALID_COMMAND; goto out; } diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/video/saa7164/saa7164-cmd.c index a97ae17b36c2..6a4c217ed3a7 100644 --- a/drivers/media/video/saa7164/saa7164-cmd.c +++ b/drivers/media/video/saa7164/saa7164-cmd.c @@ -84,7 +84,7 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev) { int ret = SAA_OK, i = 0; u32 timeout; - wait_queue_head_t *q = 0; + wait_queue_head_t *q = NULL; u8 tmp[512]; dprintk(DBGLVL_CMD, "%s()\n", __func__); @@ -137,7 +137,7 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev) int loop = 1; int ret; u32 timeout; - wait_queue_head_t *q = 0; + wait_queue_head_t *q = NULL; u8 tmp[512]; dprintk(DBGLVL_CMD, "%s()\n", __func__); @@ -261,7 +261,7 @@ out: */ int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) { - wait_queue_head_t *q = 0; + wait_queue_head_t *q = NULL; int ret = SAA_BUS_TIMEOUT; unsigned long stamp; int r; @@ -357,7 +357,7 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, "sel = 0x%x)\n", __func__, saa7164_unitid_name(dev, id), id, command, controlselector); - if ((size == 0) || (buf == 0)) { + if ((size == 0) || (buf == NULL)) { printk(KERN_ERR "%s() Invalid param\n", __func__); return SAA_ERR_BAD_PARAMETER; } @@ -538,7 +538,7 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, /* Invalid */ dprintk(DBGLVL_CMD, "%s() Invalid\n", __func__); - ret = saa7164_bus_get(dev, presponse_t, 0, 0); + ret = saa7164_bus_get(dev, presponse_t, NULL, 0); if (ret != SAA_OK) { printk(KERN_ERR "get failed\n"); return ret; diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c index 58af67f2278b..b813aec1e456 100644 --- a/drivers/media/video/saa7164/saa7164-core.c +++ b/drivers/media/video/saa7164/saa7164-core.c @@ -277,8 +277,8 @@ static void saa7164_histogram_print(struct saa7164_port *port, static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr) { struct saa7164_dev *dev = port->dev; - struct saa7164_buffer *buf = 0; - struct saa7164_user_buffer *ubuf = 0; + struct saa7164_buffer *buf = NULL; + struct saa7164_user_buffer *ubuf = NULL; struct list_head *c, *n; int i = 0; u8 __iomem *p; @@ -649,7 +649,7 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) u32 intid, intstat[INT_SIZE/4]; int i, handled = 0, bit; - if (dev == 0) { + if (dev == NULL) { printk(KERN_ERR "%s() No device specified\n", __func__); handled = 0; goto out; @@ -945,7 +945,7 @@ static int get_resources(struct saa7164_dev *dev) static int saa7164_port_init(struct saa7164_dev *dev, int portnr) { - struct saa7164_port *port = 0; + struct saa7164_port *port = NULL; if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS)) BUG(); diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c index b305a01b3bde..f65eab63ca87 100644 --- a/drivers/media/video/saa7164/saa7164-dvb.c +++ b/drivers/media/video/saa7164/saa7164-dvb.c @@ -309,8 +309,8 @@ static int dvb_register(struct saa7164_port *port) port->hw_streamingparams.pitch = 188; port->hw_streamingparams.linethreshold = 0; - port->hw_streamingparams.pagetablelistvirt = 0; - port->hw_streamingparams.pagetablelistphys = 0; + port->hw_streamingparams.pagetablelistvirt = NULL; + port->hw_streamingparams.pagetablelistphys = NULL; port->hw_streamingparams.numpagetables = 2 + ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE); diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c index 1838408cd5cb..f9d594698832 100644 --- a/drivers/media/video/saa7164/saa7164-encoder.c +++ b/drivers/media/video/saa7164/saa7164-encoder.c @@ -152,8 +152,8 @@ static int saa7164_encoder_buffers_alloc(struct saa7164_port *port) /* Init and establish defaults */ params->bitspersample = 8; params->linethreshold = 0; - params->pagetablelistvirt = 0; - params->pagetablelistphys = 0; + params->pagetablelistvirt = NULL; + params->pagetablelistphys = NULL; params->numpagetableentries = port->hwcfg.buffercount; /* Allocate the PCI resources, buffers (hard) */ @@ -1108,7 +1108,7 @@ static int fops_release(struct file *file) struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) { - struct saa7164_user_buffer *ubuf = 0; + struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; u32 crc; @@ -1443,7 +1443,7 @@ int saa7164_encoder_register(struct saa7164_port *port) port->v4l_device = saa7164_encoder_alloc(port, dev->pci, &saa7164_mpeg_template, "mpeg"); - if (port->v4l_device == NULL) { + if (!port->v4l_device) { printk(KERN_INFO "%s: can't allocate mpeg device\n", dev->name); result = -ENOMEM; diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/video/saa7164/saa7164-fw.c index ebed6f786a23..b369300cce06 100644 --- a/drivers/media/video/saa7164/saa7164-fw.c +++ b/drivers/media/video/saa7164/saa7164-fw.c @@ -88,7 +88,7 @@ int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize, "%s(image=%p, size=%d, flags=0x%x, dst=%p, dstsize=0x%x)\n", __func__, src, srcsize, dlflags, dst, dstsize); - if ((src == 0) || (dst == 0)) { + if ((src == NULL) || (dst == NULL)) { ret = -EIO; goto out; } diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c index 8abbe6d661e4..9e5b01c29cf5 100644 --- a/drivers/media/video/saa7164/saa7164-vbi.c +++ b/drivers/media/video/saa7164/saa7164-vbi.c @@ -123,8 +123,8 @@ static int saa7164_vbi_buffers_alloc(struct saa7164_port *port) ((params->numberoflines * params->pitch) / PAGE_SIZE); params->bitspersample = 8; params->linethreshold = 0; - params->pagetablelistvirt = 0; - params->pagetablelistphys = 0; + params->pagetablelistvirt = NULL; + params->pagetablelistphys = NULL; params->numpagetableentries = port->hwcfg.buffercount; /* Allocate the PCI resources, buffers (hard) */ @@ -1054,7 +1054,7 @@ static int fops_release(struct file *file) struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) { - struct saa7164_user_buffer *ubuf = 0; + struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; u32 crc; @@ -1334,7 +1334,7 @@ int saa7164_vbi_register(struct saa7164_port *port) port->v4l_device = saa7164_vbi_alloc(port, dev->pci, &saa7164_vbi_template, "vbi"); - if (port->v4l_device == NULL) { + if (!port->v4l_device) { printk(KERN_INFO "%s: can't allocate vbi device\n", dev->name); result = -ENOMEM; -- cgit v1.2.2 From d1303567f7738c07c0e5fd22420a9a8e2f55a0c4 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 31 Jan 2011 09:16:09 -0300 Subject: [media] omap24xxcam: Fix compilation Add linux/sched.h because of missing declaration of TASK_NORMAL. This patch fixes the following error: drivers/media/video/omap24xxcam.c: In function 'omap24xxcam_vbq_complete': drivers/media/video/omap24xxcam.c:415: error: 'TASK_NORMAL' undeclared (first use in this function) drivers/media/video/omap24xxcam.c:415: error: (Each undeclared identifier is reported only once drivers/media/video/omap24xxcam.c:415: error: for each function it appears in.) Signed-off-by: Thomas Weber Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap24xxcam.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index 017552762902..f6626e87dbc5 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include -- cgit v1.2.2 From 724dcbfa9c24af5afdaa2b7e0449e20066d6555a Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Tue, 1 Feb 2011 05:25:19 -0300 Subject: [media] xc5000: add set_config and other Add one more radio input, usefull for tm6010 Add control output amplitude. Add set_config function for configure tuner when TV card hasn't dvb part. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/xc5000.c | 38 ++++++++++++++++++++++++++++++++++-- drivers/media/common/tuners/xc5000.h | 1 + 2 files changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c index e3218c97d536..1e28f7dcb26b 100644 --- a/drivers/media/common/tuners/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c @@ -65,7 +65,7 @@ struct xc5000_priv { }; /* Misc Defines */ -#define MAX_TV_STANDARD 23 +#define MAX_TV_STANDARD 24 #define XC_MAX_I2C_WRITE_LENGTH 64 /* Signal Types */ @@ -92,6 +92,8 @@ struct xc5000_priv { #define XREG_IF_OUT 0x05 #define XREG_SEEK_MODE 0x07 #define XREG_POWER_DOWN 0x0A /* Obsolete */ +/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ +#define XREG_OUTPUT_AMP 0x0B #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ #define XREG_SMOOTHEDCVBS 0x0E #define XREG_XTALFREQ 0x0F @@ -173,6 +175,7 @@ struct XC_TV_STANDARD { #define DTV7 20 #define FM_Radio_INPUT2 21 #define FM_Radio_INPUT1 22 +#define FM_Radio_INPUT1_MONO 23 static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, @@ -197,7 +200,8 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { {"DTV7/8", 0x00C0, 0x801B}, {"DTV7", 0x00C0, 0x8007}, {"FM Radio-INPUT2", 0x9802, 0x9002}, - {"FM Radio-INPUT1", 0x0208, 0x9002} + {"FM Radio-INPUT1", 0x0208, 0x9002}, + {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} }; static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); @@ -732,6 +736,8 @@ static int xc5000_set_params(struct dvb_frontend *fe, return -EIO; } + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); if (debug) @@ -836,6 +842,8 @@ tune_channel: return -EREMOTEIO; } + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); if (debug) @@ -863,6 +871,8 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, radio_input = FM_Radio_INPUT1; else if (priv->radio_input == XC5000_RADIO_FM2) radio_input = FM_Radio_INPUT2; + else if (priv->radio_input == XC5000_RADIO_FM1_MONO) + radio_input = FM_Radio_INPUT1_MONO; else { dprintk(1, "%s() unknown radio input %d\n", __func__, priv->radio_input); @@ -889,6 +899,12 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, return -EREMOTEIO; } + if ((priv->radio_input == XC5000_RADIO_FM1) || + (priv->radio_input == XC5000_RADIO_FM2)) + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); + else if (priv->radio_input == XC5000_RADIO_FM1_MONO) + xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); + xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); return 0; @@ -1039,6 +1055,23 @@ static int xc5000_release(struct dvb_frontend *fe) return 0; } +static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc5000_priv *priv = fe->tuner_priv; + struct xc5000_config *p = priv_cfg; + + dprintk(1, "%s()\n", __func__); + + if (p->if_khz) + priv->if_khz = p->if_khz; + + if (p->radio_input) + priv->radio_input = p->radio_input; + + return 0; +} + + static const struct dvb_tuner_ops xc5000_tuner_ops = { .info = { .name = "Xceive XC5000", @@ -1051,6 +1084,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = { .init = xc5000_init, .sleep = xc5000_sleep, + .set_config = xc5000_set_config, .set_params = xc5000_set_params, .set_analog_params = xc5000_set_analog_params, .get_frequency = xc5000_get_frequency, diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h index 3756e73649be..e2957451b532 100644 --- a/drivers/media/common/tuners/xc5000.h +++ b/drivers/media/common/tuners/xc5000.h @@ -40,6 +40,7 @@ struct xc5000_config { #define XC5000_RADIO_NOT_CONFIGURED 0 #define XC5000_RADIO_FM1 1 #define XC5000_RADIO_FM2 2 +#define XC5000_RADIO_FM1_MONO 3 /* For each bridge framework, when it attaches either analog or digital, * it has to store a reference back to its _core equivalent structure, -- cgit v1.2.2 From 6951803c2402d1af0e76df051cc9b117f504550f Mon Sep 17 00:00:00 2001 From: Lawrence Rust Date: Sun, 6 Feb 2011 17:46:12 -0300 Subject: [media] Add proper audio support for Nova-S Plus with wm8775 ADC This patch adds audio DMA capture and ALSA mixer elements for the line input jack of the Hauppauge Nova-S-plus DVB-S PCI card. The Nova-S-plus has a WM8775 ADC that is currently not detected. This patch enables this chip and exports volume, balance mute and ALC elements for ALSA mixer controls. [mchehab@redhat.com: Changed the patch to only talk with wm8775 if board info says so. Also, added platform_data support, to avoid changing the behaviour for other boards, and fixed CodingStyle] [awalls@md.metrocast.net: Changed patch to make the WM8775_GID defintion bridge driver private and let the bridge driver set the value of v4l2_subdev.grp_id.] -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Andy Walls --- drivers/media/video/cx88/cx88-alsa.c | 118 ++++++++++++++++++++++++++---- drivers/media/video/cx88/cx88-cards.c | 3 +- drivers/media/video/cx88/cx88-tvaudio.c | 8 +- drivers/media/video/cx88/cx88-video.c | 52 ++++++++++++- drivers/media/video/cx88/cx88.h | 13 +++- drivers/media/video/wm8775.c | 126 ++++++++++++++++++++++---------- 6 files changed, 258 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 54b7fcd469a8..a2d688ebed90 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "cx88.h" #include "cx88-reg.h" @@ -577,6 +578,35 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol, return 0; } +static void snd_cx88_wm8775_volume_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; + int left = value->value.integer.value[0]; + int right = value->value.integer.value[1]; + int v, b; + + memset(&client_ctl, 0, sizeof(client_ctl)); + + /* Pass volume & balance onto any WM8775 */ + if (left >= right) { + v = left << 10; + b = left ? (0x8000 * right) / left : 0x8000; + } else { + v = right << 10; + b = right ? 0xffff - (0x8000 * left) / right : 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); +} + /* OK - TODO: test it */ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) @@ -587,25 +617,28 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, int changed = 0; u32 old; + if (core->board.audio_chip == V4L2_IDENT_WM8775) + snd_cx88_wm8775_volume_put(kcontrol, value); + 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_write(AUD_VOL_CTL, (old & ~0x3f) | v); - changed = 1; + cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v); + changed = 1; } - if (cx_read(AUD_BAL_CTL) != b) { - cx_write(AUD_BAL_CTL, b); - changed = 1; + if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) { + cx_write(AUD_BAL_CTL, b); + changed = 1; } spin_unlock_irq(&chip->reg_lock); @@ -618,7 +651,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 = "Playback Volume", + .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put, @@ -649,7 +682,17 @@ 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_write(AUD_VOL_CTL, vol); + cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); + /* Pass mute onto any WM8775 */ + if ((core->board.audio_chip == V4L2_IDENT_WM8775) && + ((1<<6) == bit)) { + struct v4l2_control client_ctl; + + memset(&client_ctl, 0, sizeof(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); + } ret = 1; } spin_unlock_irq(&chip->reg_lock); @@ -658,7 +701,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 = "Playback Switch", + .name = "Audio-Out Switch", .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, @@ -667,13 +710,51 @@ 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 = "Capture Switch", + .name = "Analog-TV 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; + + memset(&client_ctl, 0, sizeof(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; + + memset(&client_ctl, 0, sizeof(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 ****************************************************************************/ @@ -724,7 +805,8 @@ static void snd_cx88_dev_free(struct snd_card * card) static int devno; static int __devinit snd_cx88_create(struct snd_card *card, struct pci_dev *pci, - snd_cx88_card_t **rchip) + snd_cx88_card_t **rchip, + struct cx88_core **core_ptr) { snd_cx88_card_t *chip; struct cx88_core *core; @@ -750,7 +832,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) { dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); err = -EIO; - cx88_core_put(core,pci); + cx88_core_put(core, pci); return err; } @@ -786,6 +868,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); *rchip = chip; + *core_ptr = core; return 0; } @@ -795,6 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, { struct snd_card *card; snd_cx88_card_t *chip; + struct cx88_core *core; int err; if (devno >= SNDRV_CARDS) @@ -812,7 +896,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, card->private_free = snd_cx88_dev_free; - err = snd_cx88_create(card, pci, &chip); + err = snd_cx88_create(card, pci, &chip, &core); if (err < 0) goto error; @@ -830,6 +914,10 @@ 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 */ + if (core->board.audio_chip == V4L2_IDENT_WM8775) + snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip)); + 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 8128b936c686..f735262f4767 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -970,7 +970,8 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_chip = V4L2_IDENT_WM8775, + .audio_chip = V4L2_IDENT_WM8775, + .i2sinputcntl = 2, .input = {{ .type = CX88_VMUX_DVB, .vmux = 0, diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 08220de3d74d..770ec05b5e9b 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c @@ -786,8 +786,12 @@ void cx88_set_tvaudio(struct cx88_core *core) break; case WW_I2SADC: set_audio_start(core, 0x01); - /* Slave/Philips/Autobaud */ - cx_write(AUD_I2SINPUTCNTL, 0); + /* + * Slave/Philips/Autobaud + * NB on Nova-S bit1 NPhilipsSony appears to be inverted: + * 0= Sony, 1=Philips + */ + cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl); /* Switch to "I2S ADC mode" */ cx_write(AUD_I2SCNTL, 0x1); set_audio_finish(core, EN_I2SIN_ENABLE); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index f814886ccd17..287a41ee1c4f 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -40,6 +40,7 @@ #include "cx88.h" #include #include +#include MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); @@ -989,6 +990,32 @@ 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 */ + if (core->board.audio_chip == V4L2_IDENT_WM8775) { + struct v4l2_control client_ctl; + memset(&client_ctl, 0, sizeof(client_ctl)); + 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: @@ -1526,7 +1553,9 @@ 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) { + if (c->id == V4L2_CID_AUDIO_MUTE || + c->id == V4L2_CID_AUDIO_VOLUME || + c->id == V4L2_CID_AUDIO_BALANCE) { for (i = 0; i < CX8800_CTLS; i++) { if (cx8800_ctls[i].v.id == c->id) break; @@ -1856,9 +1885,24 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, /* load and configure helper modules */ - if (core->board.audio_chip == V4L2_IDENT_WM8775) - v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - "wm8775", 0x36 >> 1, NULL); + if (core->board.audio_chip == V4L2_IDENT_WM8775) { + struct i2c_board_info wm8775_info = { + .type = "wm8775", + .addr = 0x36 >> 1, + .platform_data = &core->wm8775_data, + }; + struct v4l2_subdev *sd; + + if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1) + core->wm8775_data.is_nova_s = true; + else + core->wm8775_data.is_nova_s = false; + + sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap, + &wm8775_info, NULL); + if (sd != NULL) + sd->grp_id = WM8775_GID; + } if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { /* This probes for a tda9874 as is used on some diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index c9981e77416a..aaf7d12b77db 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -33,6 +33,7 @@ #include #include #include +#include #include "btcx-risc.h" #include "cx88-reg.h" @@ -273,6 +274,9 @@ struct cx88_board { enum cx88_board_type mpeg; unsigned int audio_chip; int num_frontends; + + /* Used for I2S devices */ + int i2sinputcntl; }; struct cx88_subid { @@ -379,6 +383,7 @@ struct cx88_core { /* I2C remote data */ struct IR_i2c_init_data init_data; + struct wm8775_platform_data wm8775_data; struct mutex lock; /* various v4l controls */ @@ -398,17 +403,21 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_all(core, o, f, args...) \ +#define WM8775_GID (1 << 0) + +#define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, 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/wm8775.c b/drivers/media/video/wm8775.c index fe8ef6419f83..9cedb1e69b58 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -35,6 +35,7 @@ #include #include #include +#include MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); @@ -50,10 +51,16 @@ 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) */ }; @@ -85,6 +92,30 @@ 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) { @@ -102,25 +133,26 @@ static int wm8775_s_routing(struct v4l2_subdev *sd, state->input = input; if (!v4l2_ctrl_g_ctrl(state->mute)) return 0; - wm8775_write(sd, R21, 0x0c0); - wm8775_write(sd, R14, 0x1d4); - wm8775_write(sd, R15, 0x1d4); - wm8775_write(sd, R21, 0x100 + state->input); + if (!v4l2_ctrl_g_ctrl(state->vol)) + return 0; + if (!v4l2_ctrl_g_ctrl(state->bal)) + return 0; + wm8775_set_audio(sd, 1); 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: - 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); + 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); return 0; } return -EINVAL; @@ -144,16 +176,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd) static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) { - 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); + wm8775_set_audio(sd, 0); return 0; } @@ -203,6 +226,13 @@ static int wm8775_probe(struct i2c_client *client, { struct wm8775_state *state; struct v4l2_subdev *sd; + int err; + bool is_nova_s = false; + + if (client->dev.platform_data) { + struct wm8775_platform_data *data = client->dev.platform_data; + is_nova_s = data->is_nova_s; + } /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -218,13 +248,18 @@ static int wm8775_probe(struct i2c_client *client, v4l2_i2c_subdev_init(sd, client, &wm8775_ops); state->input = 2; - v4l2_ctrl_handler_init(&state->hdl, 1); + v4l2_ctrl_handler_init(&state->hdl, 4); 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; - if (state->hdl.error) { - int err = state->hdl.error; - + err = state->hdl.error; + if (err) { v4l2_ctrl_handler_free(&state->hdl); kfree(state); return err; @@ -236,29 +271,44 @@ static int wm8775_probe(struct i2c_client *client, wm8775_write(sd, R23, 0x000); /* Disable zero cross detect timeout */ wm8775_write(sd, R7, 0x000); - /* Left justified, 24-bit mode */ + /* HPF enable, left justified, 24-bit (Philips) mode */ wm8775_write(sd, R11, 0x021); /* Master mode, clock ratio 256fs */ wm8775_write(sd, R12, 0x102); /* Powered up */ wm8775_write(sd, R13, 0x000); - /* 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); + + if (!is_nova_s) { + /* 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); + } else { + /* 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); + } /* 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, lower PGA gain limit -1dB */ - wm8775_write(sd, R20, 0x07a); - /* LRBOTH = 1, use input 2. */ - wm8775_write(sd, R21, 0x102); + if (!is_nova_s) { + /* Transient window 4ms, lower PGA gain limit -1dB */ + wm8775_write(sd, R20, 0x07a); + /* LRBOTH = 1, use input 2. */ + wm8775_write(sd, R21, 0x102); + } else { + /* Transient window 4ms, ALC min gain -5dB */ + wm8775_write(sd, R20, 0x0fb); + + wm8775_set_audio(sd, 1); /* set volume/mute/mux */ + } return 0; } -- cgit v1.2.2 From a0ea298d57153cf71f9f7628830dbba1a9a8a15d Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 1 Feb 2011 19:40:03 -0300 Subject: [media] ds3000: fill in demod init function Make some initializations in init, not in tune function Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index fc61d9230db8..655f182e7ff4 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -1065,10 +1065,6 @@ static int ds3000_tune(struct dvb_frontend *fe, /* Reset status register */ status = 0; /* Tune */ - /* TS2020 init */ - ds3000_tuner_writereg(state, 0x42, 0x73); - ds3000_tuner_writereg(state, 0x05, 0x01); - ds3000_tuner_writereg(state, 0x62, 0xf5); /* unknown */ ds3000_tuner_writereg(state, 0x07, 0x02); ds3000_tuner_writereg(state, 0x10, 0x00); @@ -1306,7 +1302,19 @@ static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe) */ static int ds3000_initfe(struct dvb_frontend *fe) { + struct ds3000_state *state = fe->demodulator_priv; + int ret; + dprintk("%s()\n", __func__); + /* hard reset */ + ds3000_writereg(state, 0x08, 0x01 | ds3000_readreg(state, 0x08)); + msleep(1); + + /* TS2020 init */ + ds3000_tuner_writereg(state, 0x42, 0x73); + ds3000_tuner_writereg(state, 0x05, 0x01); + ds3000_tuner_writereg(state, 0x62, 0xf5); + return 0; } -- cgit v1.2.2 From 2a66bf370c2aca617fad8dd8fe6c276d6bb1b44c Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 1 Feb 2011 19:40:17 -0300 Subject: [media] ds3000: decrease mpeg clock output TeVii s480 works fine with that on DVB-S2 channels Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 655f182e7ff4..41af75adc575 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -1203,7 +1203,7 @@ static int ds3000_tune(struct dvb_frontend *fe, ds3000_writereg(state, ds3000_dvbs2_init_tab[i], ds3000_dvbs2_init_tab[i + 1]); - ds3000_writereg(state, 0xfe, 0x54); + ds3000_writereg(state, 0xfe, 0x98); break; default: return 1; -- cgit v1.2.2 From caa687c805332a384afd292e2b20e25a6282ed66 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 1 Feb 2011 19:40:25 -0300 Subject: [media] ds3000: loading firmware in bigger chunks Decrease firmware loading time. Before it is ~4000 i2c calls, now it is ~256 i2c calls to load ds3000 firmware. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 41af75adc575..b2f0f4e8e512 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -305,7 +305,7 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg, struct i2c_msg msg; u8 *buf; - buf = kmalloc(3, GFP_KERNEL); + buf = kmalloc(33, GFP_KERNEL); if (buf == NULL) { printk(KERN_ERR "Unable to kmalloc\n"); ret = -ENOMEM; @@ -317,10 +317,10 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg, msg.addr = state->config->demod_address; msg.flags = 0; msg.buf = buf; - msg.len = 3; + msg.len = 33; - for (i = 0; i < len; i += 2) { - memcpy(buf + 1, data + i, 2); + for (i = 0; i < len; i += 32) { + memcpy(buf + 1, data + i, 32); dprintk("%s: write reg 0x%02x, len = %d\n", __func__, reg, len); -- cgit v1.2.2 From b9bf2eafaad9c1ef02fb3db38c74568be601a43a Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Tue, 1 Feb 2011 19:40:36 -0300 Subject: [media] ds3000: don't load firmware during demod init Speed up tuning, as firmware is not necessary to load every attempt to tune Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index b2f0f4e8e512..993357383fd4 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -1029,14 +1029,6 @@ static int ds3000_tune(struct dvb_frontend *fe, dprintk("%s() ", __func__); - /* Load the firmware if required */ - ret = ds3000_firmware_ondemand(fe); - if (ret != 0) { - printk(KERN_ERR "%s: Unable initialise the firmware\n", - __func__); - return ret; - } - state->dnxt.delivery = c->modulation; state->dnxt.frequency = c->frequency; state->dnxt.rolloff = 2; /* fixme */ @@ -1314,6 +1306,12 @@ static int ds3000_initfe(struct dvb_frontend *fe) ds3000_tuner_writereg(state, 0x42, 0x73); ds3000_tuner_writereg(state, 0x05, 0x01); ds3000_tuner_writereg(state, 0x62, 0xf5); + /* Load the firmware if required */ + ret = ds3000_firmware_ondemand(fe); + if (ret != 0) { + printk(KERN_ERR "%s: Unable initialize firmware\n", __func__); + return ret; + } return 0; } -- cgit v1.2.2 From 1f65dd365831ff6836eeaf66c9d7bf1ae46ac4d2 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Wed, 2 Feb 2011 12:15:52 -0300 Subject: [media] tm6000: add new TV cards of Beholder Add two new TV cards of Beholder. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-cards.c | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 22a222241cc4..bd99ca7b9f28 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -50,6 +50,8 @@ #define TM6010_BOARD_BEHOLD_VOYAGER 11 #define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12 #define TM6010_BOARD_TWINHAN_TU501 13 +#define TM6010_BOARD_BEHOLD_WANDER_LITE 14 +#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15 #define TM6000_MAXBOARDS 16 static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; @@ -303,6 +305,40 @@ struct tm6000_board tm6000_boards[] = { .dvb_led = TM6010_GPIO_5, .ir = TM6010_GPIO_0, }, + }, + [TM6010_BOARD_BEHOLD_WANDER_LITE] = { + .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0xc2 >> 1, + .demod_addr = 0x1e >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_0, + .demod_reset = TM6010_GPIO_1, + .power_led = TM6010_GPIO_6, + }, + }, + [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = { + .name = "Beholder Voyager Lite TV/FM USB2.0", + .tuner_type = TUNER_XC5000, + .tuner_addr = 0xc2 >> 1, + .type = TM6010, + .caps = { + .has_tuner = 1, + .has_dvb = 0, + .has_zl10353 = 0, + .has_eeprom = 1, + }, + .gpio = { + .tuner_reset = TM6010_GPIO_0, + .power_led = TM6010_GPIO_6, + }, } }; @@ -325,6 +361,8 @@ struct usb_device_id tm6000_id_table[] = { { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, + { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE }, + { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE }, { }, }; @@ -346,6 +384,8 @@ void tm6000_flash_led(struct tm6000_core *dev, u8 state) break; case TM6010_BOARD_BEHOLD_WANDER: case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); break; @@ -362,6 +402,8 @@ void tm6000_flash_led(struct tm6000_core *dev, u8 state) break; case TM6010_BOARD_BEHOLD_WANDER: case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); break; @@ -520,6 +562,7 @@ int tm6000_cards_setup(struct tm6000_core *dev) msleep(15); break; case TM6010_BOARD_BEHOLD_WANDER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: /* Power led on (blue) */ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); msleep(15); @@ -530,6 +573,7 @@ int tm6000_cards_setup(struct tm6000_core *dev) msleep(15); break; case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: /* Power led on (blue) */ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01); msleep(15); @@ -955,6 +999,8 @@ static void tm6000_usb_disconnect(struct usb_interface *interface) break; case TM6010_BOARD_BEHOLD_WANDER: case TM6010_BOARD_BEHOLD_VOYAGER: + case TM6010_BOARD_BEHOLD_WANDER_LITE: + case TM6010_BOARD_BEHOLD_VOYAGER_LITE: /* Power led off */ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00); -- cgit v1.2.2 From 6ca000479fdb80b9059b69c67c82f8dc0d5f5d47 Mon Sep 17 00:00:00 2001 From: Holger Nelson Date: Thu, 3 Feb 2011 01:59:29 -0300 Subject: [media] tm6000: Add support for Terratec Grabster AV 150/250 MX This patch adds support for Terratec Grabster AV 150/250 MX. For now it is only possible to use composite input as switching inputs does not work. [mchehab@redhat.com: Fix merge conflicts and simplify board entries] Signed-off-by: Holger Nelson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-cards.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index bd99ca7b9f28..290037eecd61 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -52,6 +52,7 @@ #define TM6010_BOARD_TWINHAN_TU501 13 #define TM6010_BOARD_BEHOLD_WANDER_LITE 14 #define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15 +#define TM5600_BOARD_TERRATEC_GRABSTER 16 #define TM6000_MAXBOARDS 16 static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET }; @@ -283,6 +284,11 @@ struct tm6000_board tm6000_boards[] = { }, .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, }, + [TM5600_BOARD_TERRATEC_GRABSTER] = { + .name = "Terratec Grabster AV 150/250 MX", + .type = TM5600, + .tuner_type = TUNER_ABSENT, + }, [TM6010_BOARD_TWINHAN_TU501] = { .name = "Twinhan TU501(704D1)", .tuner_type = TUNER_XC2028, /* has a XC3028 */ @@ -339,7 +345,7 @@ struct tm6000_board tm6000_boards[] = { .tuner_reset = TM6010_GPIO_0, .power_led = TM6010_GPIO_6, }, - } + }, }; /* table of devices that work with this driver */ @@ -357,6 +363,7 @@ struct usb_device_id tm6000_id_table[] = { { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER }, { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE }, + { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER }, { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 }, -- cgit v1.2.2 From 8aff8ba95155dff265de5ea6f5d5d92caa7bc728 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Thu, 17 Feb 2011 22:11:05 -0300 Subject: [media] tm6000: add radio support to the driver Changes: Add function tm6000_set_reg_mask for change some bits in regs. Very usefull, simplify some code with this function. Add control mute Add control volume Add control audio input MUX Add support radio Radio works well. TV works too Known bugs: The programm gnomeradio can't set freq for radio, it use old v4l API. Audio over USB works via arecord. The programm mplayer can set freq but no any audio mplayer -v -rawaudio rate=48000 radio://105.2/capture driver=v4l2:alsa:adevice=hw.1,0:amode=1:audiorate=48000:forceaudio:immediatemode=0 When start watch TV very shortly after radio the kernel crashed hardly. Didn't stop all USB URBs, need some time for stop. [mchehab@redhat.com: fix merge conflicts] Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-alsa.c | 13 +- drivers/staging/tm6000/tm6000-cards.c | 11 +- drivers/staging/tm6000/tm6000-core.c | 260 +++++++++++++++++++++++---- drivers/staging/tm6000/tm6000-stds.c | 33 ++-- drivers/staging/tm6000/tm6000-video.c | 327 ++++++++++++++++++++++++++++++---- drivers/staging/tm6000/tm6000.h | 23 ++- 6 files changed, 566 insertions(+), 101 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c index 184cc505ed86..acb03172a887 100644 --- a/drivers/staging/tm6000/tm6000-alsa.c +++ b/drivers/staging/tm6000/tm6000-alsa.c @@ -76,14 +76,11 @@ MODULE_PARM_DESC(debug, "enable debug messages"); static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) { struct tm6000_core *core = chip->core; - int val; dprintk(1, "Starting audio DMA\n"); /* Enables audio */ - val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0); - val |= 0x20; - tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); + tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x40, 0x40); tm6000_set_audio_bitrate(core, 48000); @@ -98,13 +95,11 @@ static int _tm6000_start_audio_dma(struct snd_tm6000_card *chip) static int _tm6000_stop_audio_dma(struct snd_tm6000_card *chip) { struct tm6000_core *core = chip->core; - int val; + dprintk(1, "Stopping audio DMA\n"); - /* Enables audio */ - val = tm6000_get_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x0); - val &= ~0x20; - tm6000_set_reg(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); + /* Disables audio */ + tm6000_set_reg_mask(core, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0x00, 0x40); tm6000_set_reg(core, TM6010_REQ08_R01_A_INIT, 0); diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 290037eecd61..a356ba7aa77c 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -66,6 +66,8 @@ struct tm6000_board { char *name; struct tm6000_capabilities caps; + enum tm6000_inaudio aradio; + enum tm6000_inaudio avideo; enum tm6000_devtype type; /* variant of the chipset */ int tuner_type; /* type of the tuner */ @@ -230,6 +232,8 @@ struct tm6000_board tm6000_boards[] = { .tuner_addr = 0xc2 >> 1, .demod_addr = 0x1e >> 1, .type = TM6010, + .avideo = TM6000_AIP_SIF1, + .aradio = TM6000_AIP_LINE1, .caps = { .has_tuner = 1, .has_dvb = 1, @@ -248,6 +252,8 @@ struct tm6000_board tm6000_boards[] = { .tuner_type = TUNER_XC5000, .tuner_addr = 0xc2 >> 1, .type = TM6010, + .avideo = TM6000_AIP_SIF1, + .aradio = TM6000_AIP_LINE1, .caps = { .has_tuner = 1, .has_dvb = 0, @@ -693,13 +699,12 @@ static void tm6000_config_tuner(struct tm6000_core *dev) struct xc5000_config ctl = { .i2c_address = dev->tuner_addr, .if_khz = 4570, - .radio_input = XC5000_RADIO_FM1, + .radio_input = XC5000_RADIO_FM1_MONO, }; xc5000_cfg.tuner = TUNER_XC5000; xc5000_cfg.priv = &ctl; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc5000_cfg); } @@ -732,6 +737,8 @@ static int tm6000_init_dev(struct tm6000_core *dev) dev->caps = tm6000_boards[dev->model].caps; + dev->avideo = tm6000_boards[dev->model].avideo; + dev->aradio = tm6000_boards[dev->model].aradio; /* initialize hardware */ rc = tm6000_init(dev); if (rc < 0) diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c index 5162cd4a8288..778e53413afb 100644 --- a/drivers/staging/tm6000/tm6000-core.c +++ b/drivers/staging/tm6000/tm6000-core.c @@ -116,6 +116,29 @@ int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) } EXPORT_SYMBOL_GPL(tm6000_get_reg); +int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, + u16 index, u16 mask) +{ + int rc; + u8 buf[1]; + u8 new_index; + + rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, + value, index, buf, 1); + + if (rc < 0) + return rc; + + new_index = (buf[0] & ~mask) | (index & mask); + + if (new_index == index) + return 0; + + return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, + req, value, new_index, NULL, 0); +} +EXPORT_SYMBOL_GPL(tm6000_set_reg_mask); + int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index) { int rc; @@ -245,17 +268,12 @@ int tm6000_init_analog_mode(struct tm6000_core *dev) struct v4l2_frequency f; if (dev->dev_type == TM6010) { - int val; - /* Enable video */ - val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0); - val |= 0x60; - tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); - val = tm6000_get_reg(dev, - TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0); - val &= ~0x40; - tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val); + tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, + 0x60, 0x60); + tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, + 0x00, 0x40); tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc); } else { @@ -471,6 +489,14 @@ struct reg_init tm6010_init_tab[] = { { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 }, { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 }, { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 }, + { TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00}, + { TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80}, + { TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a}, + { TM6010_REQ08_R0D_A_AMD_THRES, 0x40}, + { TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64}, + { TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20}, + { TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe}, + { TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01}, { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc }, { TM6010_REQ07_R3F_RESET, 0x01 }, @@ -591,51 +617,213 @@ int tm6000_init(struct tm6000_core *dev) int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) { - int val; + int val = 0; + u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ + u8 areg_0a = 0x91; /* SIF 48KHz */ + + switch (bitrate) { + case 48000: + areg_f0 = 0x60; /* ADC MCLK = 250 Fs */ + areg_0a = 0x91; /* SIF 48KHz */ + dev->audio_bitrate = bitrate; + break; + case 32000: + areg_f0 = 0x00; /* ADC MCLK = 375 Fs */ + areg_0a = 0x90; /* SIF 32KHz */ + dev->audio_bitrate = bitrate; + break; + default: + return -EINVAL; + } + /* enable I2S, if we use sif or external I2S device */ if (dev->dev_type == TM6010) { - val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0); - if (val < 0) - return val; - val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */ - val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val); + val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a); if (val < 0) return val; - } - /* different reg's to set audio bitrate */ - if (dev->dev_type == TM6010) { - val = tm6000_get_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - 0x0); + val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + areg_f0, 0xf0); if (val < 0) return val; } else { - val = tm6000_get_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x0); + val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, + areg_f0, 0xf0); if (val < 0) return val; } + return 0; +} +EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); - val &= 0x0f; /* Preserve the audio input control bits */ - switch (bitrate) { - case 44100: - val |= 0xd0; - dev->audio_bitrate = bitrate; +int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp) +{ + if (dev->dev_type == TM6010) { + /* Audio crossbar setting, default SIF1 */ + u8 areg_f0 = 0x03; + + switch (ainp) { + case TM6000_AIP_SIF1: + case TM6000_AIP_SIF2: + areg_f0 = 0x03; + break; + case TM6000_AIP_LINE1: + areg_f0 = 0x00; + break; + case TM6000_AIP_LINE2: + areg_f0 = 0x08; + break; + default: + return 0; + break; + } + /* Set audio input crossbar */ + tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, + areg_f0, 0x0f); + } else { + /* Audio setting, default LINE1 */ + u8 areg_eb = 0x00; + + switch (ainp) { + case TM6000_AIP_LINE1: + areg_eb = 0x00; + break; + case TM6000_AIP_LINE2: + areg_eb = 0x04; + break; + default: + return 0; + break; + } + /* Set audio input */ + tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE, + areg_eb, 0x0f); + } + return 0; +} +EXPORT_SYMBOL_GPL(tm6000_set_audio_input); + +void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute) +{ + u8 mute_reg = 0; + + if (mute) + mute_reg = 0x08; + + tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08); +} + +void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute) +{ + u8 mute_reg = 0; + + if (mute) + mute_reg = 0x20; + + if (dev->dev_type == TM6010) { + tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, + mute_reg, 0x20); + tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, + mute_reg, 0x20); + } else { + tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, + mute_reg, 0x20); + tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, + mute_reg, 0x20); + } +} + +int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute) +{ + enum tm6000_inaudio ainp; + + if (dev->radio) + ainp = dev->aradio; + else + ainp = dev->avideo; + + switch (ainp) { + case TM6000_AIP_SIF1: + case TM6000_AIP_SIF2: + if (dev->dev_type == TM6010) + tm6010_set_mute_sif(dev, mute); + else { + printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" + " SIF audio inputs. Please check the %s" + " configuration.\n", dev->name); + return -EINVAL; + } break; - case 48000: - val |= 0x60; - dev->audio_bitrate = bitrate; + case TM6000_AIP_LINE1: + case TM6000_AIP_LINE2: + tm6010_set_mute_adc(dev, mute); + break; + default: + return -EINVAL; break; } - if (dev->dev_type == TM6010) - val = tm6000_set_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, - val); - else - val = tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, val); + return 0; +} +EXPORT_SYMBOL_GPL(tm6000_tvaudio_set_mute); + +void tm6010_set_volume_sif(struct tm6000_core *dev, int vol) +{ + u8 vol_reg; - return val; + vol_reg = vol & 0x0F; + + if (vol < 0) + vol_reg |= 0x40; + + tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg); + tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg); } -EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); + +void tm6010_set_volume_adc(struct tm6000_core *dev, int vol) +{ + u8 vol_reg; + + vol_reg = (vol + 0x10) & 0x1f; + + if (dev->dev_type == TM6010) { + tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg); + tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg); + } else { + tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg); + tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg); + } +} + +void tm6000_set_volume(struct tm6000_core *dev, int vol) +{ + enum tm6000_inaudio ainp; + + if (dev->radio) { + ainp = dev->aradio; + vol += 8; /* Offset to 0 dB */ + } else + ainp = dev->avideo; + + switch (ainp) { + case TM6000_AIP_SIF1: + case TM6000_AIP_SIF2: + if (dev->dev_type == TM6010) + tm6010_set_volume_sif(dev, vol); + else + printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" + " SIF audio inputs. Please check the %s" + " configuration.\n", dev->name); + break; + case TM6000_AIP_LINE1: + case TM6000_AIP_LINE2: + tm6010_set_volume_adc(dev, vol); + break; + default: + break; + } +} +EXPORT_SYMBOL_GPL(tm6000_set_volume); static LIST_HEAD(tm6000_devlist); static DEFINE_MUTEX(tm6000_devlist_mutex); diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c index cc7b8664fc20..a4c07e5a6f1d 100644 --- a/drivers/staging/tm6000/tm6000-stds.c +++ b/drivers/staging/tm6000/tm6000-stds.c @@ -952,6 +952,22 @@ static int tm6000_set_audio_std(struct tm6000_core *dev, uint8_t mono_flag = 0; /* No mono */ uint8_t nicam_flag = 0; /* No NICAM */ + if (dev->radio) { + tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04); + tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80); + tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c); + tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); + tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18); + tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a); + tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x40); + tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc); + tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); + tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); + return 0; + } + switch (std) { #if 0 case DK_MONO: @@ -984,20 +1000,6 @@ static int tm6000_set_audio_std(struct tm6000_core *dev, case EIAJ: areg_05 = 0x02; break; - case FM_RADIO: - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04); - tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x0c); - tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); - tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x18); - tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91); - tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe); - tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01); - tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); - tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); - return 0; - break; case I_NICAM: areg_05 = 0x08; nicam_flag = 1; @@ -1010,6 +1012,9 @@ static int tm6000_set_audio_std(struct tm6000_core *dev, areg_05 = 0x0a; nicam_flag = 1; break; + default: + /* do nothink */ + break; } #if 0 diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index eb9b9f1bc138..b5503409ca55 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -53,11 +53,17 @@ /* Declare static vars that will be used as parameters */ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ +static int radio_nr = -1; /* /dev/radioN, -1 for autodetect */ /* Debug level */ int tm6000_debug; EXPORT_SYMBOL_GPL(tm6000_debug); +static const struct v4l2_queryctrl no_ctrl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + /* supported controls */ static struct v4l2_queryctrl tm6000_qctrl[] = { { @@ -96,9 +102,26 @@ static struct v4l2_queryctrl tm6000_qctrl[] = { .step = 0x1, .default_value = 0, .flags = 0, + }, + /* --- audio --- */ + { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = -15, + .maximum = 15, + .step = 1, + .default_value = 0, + .type = V4L2_CTRL_TYPE_INTEGER, } }; +static const unsigned int CTRLS = ARRAY_SIZE(tm6000_qctrl); static int qctl_regs[ARRAY_SIZE(tm6000_qctrl)]; static struct tm6000_fmt format[] = { @@ -117,6 +140,16 @@ static struct tm6000_fmt format[] = { } }; +static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) +{ + unsigned int i; + + for (i = 0; i < CTRLS; i++) + if (tm6000_qctrl[i].id == id) + return tm6000_qctrl+i; + return NULL; +} + /* ------------------------------------------------------------------ * DMA and thread functions * ------------------------------------------------------------------ @@ -199,13 +232,17 @@ static int copy_streams(u8 *data, unsigned long len, char *voutp = NULL; unsigned int linewidth; - /* get video buffer */ - get_next_buf(dma_q, &vbuf); - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - if (!voutp) - return 0; + if (!dev->radio) { + /* get video buffer */ + get_next_buf(dma_q, &vbuf); + + if (!vbuf) + return rc; + voutp = videobuf_to_vmalloc(&vbuf->vb); + + if (!voutp) + return 0; + } for (ptr = data; ptr < endp;) { if (!dev->isoc_ctl.cmd) { @@ -257,29 +294,31 @@ static int copy_streams(u8 *data, unsigned long len, */ switch (cmd) { case TM6000_URB_MSG_VIDEO: - if ((dev->isoc_ctl.vfield != field) && - (field == 1)) { + if (!dev->radio) { + if ((dev->isoc_ctl.vfield != field) && + (field == 1)) { /* Announces that a new buffer * were filled */ - buffer_filled(dev, dma_q, vbuf); - dprintk(dev, V4L2_DEBUG_ISOC, + buffer_filled(dev, dma_q, vbuf); + dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n"); - get_next_buf(dma_q, &vbuf); - if (!vbuf) - return rc; - voutp = videobuf_to_vmalloc(&vbuf->vb); - if (!voutp) - return rc; - memset(voutp, 0, vbuf->vb.size); - } - linewidth = vbuf->vb.width << 1; - pos = ((line << 1) - field - 1) * linewidth + - block * TM6000_URB_MSG_LEN; - /* Don't allow to write out of the buffer */ - if (pos + size > vbuf->vb.size) - cmd = TM6000_URB_MSG_ERR; - dev->isoc_ctl.vfield = field; + get_next_buf(dma_q, &vbuf); + if (!vbuf) + return rc; + voutp = videobuf_to_vmalloc(&vbuf->vb); + if (!voutp) + return rc; + memset(voutp, 0, vbuf->vb.size); + } + linewidth = vbuf->vb.width << 1; + pos = ((line << 1) - field - 1) * + linewidth + block * TM6000_URB_MSG_LEN; + /* Don't allow to write out of the buffer */ + if (pos + size > vbuf->vb.size) + cmd = TM6000_URB_MSG_ERR; + dev->isoc_ctl.vfield = field; + } break; case TM6000_URB_MSG_VBI: break; @@ -537,7 +576,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev) /* * Allocate URBs and start IRQ */ -static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize) +static int tm6000_prepare_isoc(struct tm6000_core *dev) { struct tm6000_dmaqueue *dma_q = &dev->vidq; int i, j, sb_size, pipe, size, max_packets, num_bufs = 8; @@ -566,11 +605,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize) dev->isoc_ctl.max_pkt_size = size; - max_packets = (framesize + size - 1) / size; - - if (max_packets > TM6000_MAX_ISO_PACKETS) - max_packets = TM6000_MAX_ISO_PACKETS; - + max_packets = TM6000_MAX_ISO_PACKETS; sb_size = max_packets * size; dev->isoc_ctl.num_bufs = num_bufs; @@ -746,7 +781,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, urb_init = 1; if (urb_init) { - rc = tm6000_prepare_isoc(dev, buf->vb.size); + rc = tm6000_prepare_isoc(dev); if (rc < 0) goto fail; @@ -1143,6 +1178,12 @@ static int vidioc_g_ctrl(struct file *file, void *priv, case V4L2_CID_HUE: val = tm6000_get_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, 0); return 0; + case V4L2_CID_AUDIO_MUTE: + val = dev->ctl_mute; + return 0; + case V4L2_CID_AUDIO_VOLUME: + val = dev->ctl_volume; + return 0; default: return -EINVAL; } @@ -1174,6 +1215,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv, case V4L2_CID_HUE: tm6000_set_reg(dev, TM6010_REQ07_R0B_CHROMA_HUE_PHASE_ADJ, val); return 0; + case V4L2_CID_AUDIO_MUTE: + dev->ctl_mute = val; + tm6000_tvaudio_set_mute(dev, val); + return 0; + case V4L2_CID_AUDIO_VOLUME: + dev->ctl_volume = val; + tm6000_set_volume(dev, val); + return 0; } return -EINVAL; } @@ -1221,7 +1270,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, if (unlikely(UNSET == dev->tuner_type)) return -EINVAL; - f->type = V4L2_TUNER_ANALOG_TV; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); @@ -1235,13 +1284,14 @@ static int vidioc_s_frequency(struct file *file, void *priv, struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; - if (unlikely(f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(UNSET == dev->tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) + return -EINVAL; dev->freq = f->frequency; v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); @@ -1249,6 +1299,122 @@ static int vidioc_s_frequency(struct file *file, void *priv, return 0; } +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_core *dev = fh->dev; + + strcpy(cap->driver, "tm6000"); + strlcpy(cap->card, dev->name, sizeof(dev->name)); + sprintf(cap->bus_info, "USB%04x:%04x", + le16_to_cpu(dev->udev->descriptor.idVendor), + le16_to_cpu(dev->udev->descriptor.idProduct)); + cap->version = dev->dev_type; + cap->capabilities = V4L2_CAP_TUNER; + + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_core *dev = fh->dev; + + if (0 != t->index) + return -EINVAL; + + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + + if ((dev->aradio == TM6000_AIP_LINE1) || + (dev->aradio == TM6000_AIP_LINE2)) { + t->rxsubchans = V4L2_TUNER_SUB_MONO; + } + else { + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + } + + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct tm6000_fh *fh = file->private_data; + struct tm6000_core *dev = fh->dev; + + if (0 != t->index) + return -EINVAL; + + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + memset(a, 0, sizeof(*a)); + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ + return 0; +} + +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctrl; + + return 0; +} + /* ------------------------------------------------------------------ File operations for the device ------------------------------------------------------------------*/ @@ -1260,6 +1426,7 @@ static int tm6000_open(struct file *file) struct tm6000_fh *fh; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int i, rc; + int radio = 0; printk(KERN_INFO "tm6000: open called (dev=%s)\n", video_device_node_name(vdev)); @@ -1267,6 +1434,17 @@ static int tm6000_open(struct file *file) dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: open called (dev=%s)\n", video_device_node_name(vdev)); + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } /* If more than one user, mutex should be added */ dev->users++; @@ -1284,8 +1462,9 @@ static int tm6000_open(struct file *file) file->private_data = fh; fh->dev = dev; - - fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fh->radio = radio; + dev->radio = radio; + fh->type = type; dev->fourcc = format[0].fourcc; fh->fmt = format_by_fourcc(dev->fourcc); @@ -1322,6 +1501,19 @@ static int tm6000_open(struct file *file) V4L2_FIELD_INTERLACED, sizeof(struct tm6000_buffer), fh, &dev->lock); + if (fh->radio) { + dprintk(dev, V4L2_DEBUG_OPEN, "video_open: setting radio device\n"); + tm6000_set_audio_input(dev, dev->aradio); + tm6000_set_volume(dev, dev->ctl_volume); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio); + tm6000_prepare_isoc(dev); + tm6000_start_thread(dev); + } + else { + tm6000_set_audio_input(dev, dev->avideo); + tm6000_set_volume(dev, dev->ctl_volume); + } + return 0; } @@ -1445,6 +1637,36 @@ static struct video_device tm6000_template = { .current_norm = V4L2_STD_NTSC_M, }; +static const struct v4l2_file_operations radio_fops = { + .owner = THIS_MODULE, + .open = tm6000_open, + .release = tm6000_release, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +}; + +struct video_device tm6000_radio_template = { + .name = "tm6000", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, +}; + /* ----------------------------------------------------------------- * Initialization and module stuff * ------------------------------------------------------------------ @@ -1499,6 +1721,25 @@ int tm6000_v4l2_register(struct tm6000_core *dev) printk(KERN_INFO "%s: registered device %s\n", dev->name, video_device_node_name(dev->vfd)); + dev->radio_dev = vdev_init(dev, &tm6000_radio_template, + "radio"); + if (!dev->radio_dev) { + printk(KERN_INFO "%s: can't register radio device\n", + dev->name); + return ret; /* FIXME release resource */ + } + + ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr); + if (ret < 0) { + printk(KERN_INFO "%s: can't register radio device\n", + dev->name); + return ret; /* FIXME release resource */ + } + + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->radio_dev)); + printk(KERN_INFO "Trident TVMaster TM5600/TM6000/TM6010 USB2 board (Load status: %d)\n", ret); return ret; } @@ -1507,6 +1748,14 @@ int tm6000_v4l2_unregister(struct tm6000_core *dev) { video_unregister_device(dev->vfd); + if (dev->radio_dev) { + if (video_is_registered(dev->radio_dev)) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } + return 0; } diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index bf11eeec92c7..ccd120fe1340 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -53,6 +53,14 @@ enum tm6000_devtype { TM6010, }; +enum tm6000_inaudio { + TM6000_AIP_UNK = 0, + TM6000_AIP_SIF1, + TM6000_AIP_SIF2, + TM6000_AIP_LINE1, + TM6000_AIP_LINE2, +}; + /* ------------------------------------------------------------------ * Basic structures * ------------------------------------------------------------------ @@ -174,6 +182,8 @@ struct tm6000_core { char *ir_codes; + __u8 radio; + /* Demodulator configuration */ int demod_addr; /* demodulator address */ @@ -194,6 +204,7 @@ struct tm6000_core { bool is_res_read; struct video_device *vfd; + struct video_device *radio_dev; struct tm6000_dmaqueue vidq; struct v4l2_device v4l2_dev; @@ -203,6 +214,9 @@ struct tm6000_core { enum tm6000_mode mode; + int ctl_mute; /* audio */ + int ctl_volume; + /* DVB-T support */ struct tm6000_dvb *dvb; @@ -210,7 +224,8 @@ struct tm6000_core { struct snd_tm6000_card *adev; struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ atomic_t stream_started; /* stream should be running if true */ - + enum tm6000_inaudio avideo; + enum tm6000_inaudio aradio; struct tm6000_IR *ir; @@ -248,6 +263,7 @@ struct tm6000_ops { struct tm6000_fh { struct tm6000_core *dev; + unsigned int radio; /* video capture */ struct tm6000_fmt *fmt; @@ -276,12 +292,17 @@ int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index); int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index); +int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value, + u16 index, u16 mask); int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep); int tm6000_init(struct tm6000_core *dev); int tm6000_init_analog_mode(struct tm6000_core *dev); int tm6000_init_digital_mode(struct tm6000_core *dev); int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate); +int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp); +int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute); +void tm6000_set_volume(struct tm6000_core *dev, int vol); int tm6000_v4l2_register(struct tm6000_core *dev); int tm6000_v4l2_unregister(struct tm6000_core *dev); -- cgit v1.2.2 From 14ddc3188d50855ae2a419a6aced995e2834e5d4 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Fri, 4 Feb 2011 09:23:33 -0300 Subject: [media] video: sn9c102: world-wirtable sysfs files Don't allow everybody to change video settings. Signed-off-by: Vasiliy Kulikov Acked-by: Mauro Carvalho Chehab Acked-by: Luca Risolia Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sn9c102/sn9c102_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 84984f64b234..ce56a1cdbf0a 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1430,9 +1430,9 @@ static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR, sn9c102_show_i2c_reg, sn9c102_store_i2c_reg); static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR, sn9c102_show_i2c_val, sn9c102_store_i2c_val); -static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green); -static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue); -static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red); +static DEVICE_ATTR(green, S_IWUSR, NULL, sn9c102_store_green); +static DEVICE_ATTR(blue, S_IWUSR, NULL, sn9c102_store_blue); +static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red); static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL); -- cgit v1.2.2 From 92374e886c7518387e6816dedfe60fc7bdfa8fdd Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 6 Feb 2011 11:41:44 -0300 Subject: [media] firedtv: drop obsolete backend abstraction Since the drivers/ieee1394/ backend was removed from firedtv, its I/O no longer needs to be abstracted as exchangeable backend methods. Also, ieee1394 variants of module and device probe and removal are no longer there. Move module probe and removal into firedtv-fw.c where device probe and removal are implemented. Signed-off-by: Stefan Richter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/firewire/firedtv-avc.c | 15 ++-- drivers/media/dvb/firewire/firedtv-dvb.c | 130 +-------------------------- drivers/media/dvb/firewire/firedtv-fe.c | 8 +- drivers/media/dvb/firewire/firedtv-fw.c | 146 +++++++++++++++++++++++++------ drivers/media/dvb/firewire/firedtv.h | 31 +++---- 5 files changed, 140 insertions(+), 190 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c index f0f1842fab60..fc5ccd8c923a 100644 --- a/drivers/media/dvb/firewire/firedtv-avc.c +++ b/drivers/media/dvb/firewire/firedtv-avc.c @@ -241,8 +241,8 @@ static int avc_write(struct firedtv *fdtv) if (unlikely(avc_debug)) debug_fcp(fdtv->avc_data, fdtv->avc_data_length); - err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER, - fdtv->avc_data, fdtv->avc_data_length); + err = fdtv_write(fdtv, FCP_COMMAND_REGISTER, + fdtv->avc_data, fdtv->avc_data_length); if (err) { dev_err(fdtv->device, "FCP command write failed\n"); @@ -1322,7 +1322,7 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data) mutex_lock(&fdtv->avc_mutex); - ret = fdtv->backend->read(fdtv, addr, data); + ret = fdtv_read(fdtv, addr, data); if (ret < 0) dev_err(fdtv->device, "CMP: read I/O error\n"); @@ -1340,7 +1340,7 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[]) /* data[] is stack-allocated and should not be DMA-mapped. */ memcpy(fdtv->avc_data, data, 8); - ret = fdtv->backend->lock(fdtv, addr, fdtv->avc_data); + ret = fdtv_lock(fdtv, addr, fdtv->avc_data); if (ret < 0) dev_err(fdtv->device, "CMP: lock I/O error\n"); else @@ -1405,10 +1405,7 @@ repeat: /* FIXME: this is for the worst case - optimize */ set_opcr_overhead_id(opcr, 0); - /* - * FIXME: allocate isochronous channel and bandwidth at IRM - * fdtv->backend->alloc_resources(fdtv, channels_mask, bw); - */ + /* FIXME: allocate isochronous channel and bandwidth at IRM */ } set_opcr_p2p_connections(opcr, get_opcr_p2p_connections(*opcr) + 1); @@ -1424,8 +1421,6 @@ repeat: /* * FIXME: if old_opcr.P2P_Connections > 0, * deallocate isochronous channel and bandwidth at IRM - * if (...) - * fdtv->backend->dealloc_resources(fdtv, channel, bw); */ if (++attempts < 6) /* arbitrary limit */ diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c index 86349db75250..fd8bbbfa5c59 100644 --- a/drivers/media/dvb/firewire/firedtv-dvb.c +++ b/drivers/media/dvb/firewire/firedtv-dvb.c @@ -14,14 +14,9 @@ #include #include #include -#include #include #include -#include -#include #include -#include -#include #include #include @@ -166,11 +161,11 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -int fdtv_dvb_register(struct firedtv *fdtv) +int fdtv_dvb_register(struct firedtv *fdtv, const char *name) { int err; - err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type], + err = dvb_register_adapter(&fdtv->adapter, name, THIS_MODULE, fdtv->device, adapter_nr); if (err < 0) goto fail_log; @@ -210,7 +205,7 @@ int fdtv_dvb_register(struct firedtv *fdtv) dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx); - fdtv_frontend_init(fdtv); + fdtv_frontend_init(fdtv, name); err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe); if (err) goto fail_net_release; @@ -248,122 +243,3 @@ void fdtv_dvb_unregister(struct firedtv *fdtv) dvb_dmx_release(&fdtv->demux); dvb_unregister_adapter(&fdtv->adapter); } - -const char *fdtv_model_names[] = { - [FIREDTV_UNKNOWN] = "unknown type", - [FIREDTV_DVB_S] = "FireDTV S/CI", - [FIREDTV_DVB_C] = "FireDTV C/CI", - [FIREDTV_DVB_T] = "FireDTV T/CI", - [FIREDTV_DVB_S2] = "FireDTV S2 ", -}; - -struct firedtv *fdtv_alloc(struct device *dev, - const struct firedtv_backend *backend, - const char *name, size_t name_len) -{ - struct firedtv *fdtv; - int i; - - fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); - if (!fdtv) - return NULL; - - dev_set_drvdata(dev, fdtv); - fdtv->device = dev; - fdtv->isochannel = -1; - fdtv->voltage = 0xff; - fdtv->tone = 0xff; - fdtv->backend = backend; - - mutex_init(&fdtv->avc_mutex); - init_waitqueue_head(&fdtv->avc_wait); - mutex_init(&fdtv->demux_mutex); - INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); - - for (i = ARRAY_SIZE(fdtv_model_names); --i; ) - if (strlen(fdtv_model_names[i]) <= name_len && - strncmp(name, fdtv_model_names[i], name_len) == 0) - break; - fdtv->type = i; - - return fdtv; -} - -#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ - IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION) - -#define DIGITAL_EVERYWHERE_OUI 0x001287 -#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d -#define AVC_SW_VERSION_ENTRY 0x010001 - -const struct ieee1394_device_id fdtv_id_table[] = { - { - /* FloppyDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000024, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FloppyDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000025, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FloppyDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000026, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FireDTV S/CI and FloppyDTV S2 */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000034, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FireDTV T/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000035, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, { - /* FireDTV C/CI */ - .match_flags = MATCH_FLAGS, - .vendor_id = DIGITAL_EVERYWHERE_OUI, - .model_id = 0x000036, - .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, - .version = AVC_SW_VERSION_ENTRY, - }, {} -}; -MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); - -static int __init fdtv_init(void) -{ - int ret; - - ret = fdtv_fw_init(); - if (ret < 0) - return ret; - - return ret; -} - -static void __exit fdtv_exit(void) -{ - fdtv_fw_exit(); -} - -module_init(fdtv_init); -module_exit(fdtv_exit); - -MODULE_AUTHOR("Andreas Monitzer "); -MODULE_AUTHOR("Ben Backx "); -MODULE_DESCRIPTION("FireDTV DVB Driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c index d10920e2f3a2..8748a61be73d 100644 --- a/drivers/media/dvb/firewire/firedtv-fe.c +++ b/drivers/media/dvb/firewire/firedtv-fe.c @@ -36,14 +36,14 @@ static int fdtv_dvb_init(struct dvb_frontend *fe) return err; } - return fdtv->backend->start_iso(fdtv); + return fdtv_start_iso(fdtv); } static int fdtv_sleep(struct dvb_frontend *fe) { struct firedtv *fdtv = fe->sec_priv; - fdtv->backend->stop_iso(fdtv); + fdtv_stop_iso(fdtv); cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel); fdtv->isochannel = -1; return 0; @@ -165,7 +165,7 @@ static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp) return 0; } -void fdtv_frontend_init(struct firedtv *fdtv) +void fdtv_frontend_init(struct firedtv *fdtv, const char *name) { struct dvb_frontend_ops *ops = &fdtv->fe.ops; struct dvb_frontend_info *fi = &ops->info; @@ -266,7 +266,7 @@ void fdtv_frontend_init(struct firedtv *fdtv) dev_err(fdtv->device, "no frontend for model type %d\n", fdtv->type); } - strcpy(fi->name, fdtv_model_names[fdtv->type]); + strcpy(fi->name, name); fdtv->fe.dvb = &fdtv->adapter; fdtv->fe.sec_priv = fdtv; diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c index 7424b0493f9d..8022b743af91 100644 --- a/drivers/media/dvb/firewire/firedtv-fw.c +++ b/drivers/media/dvb/firewire/firedtv-fw.c @@ -9,11 +9,18 @@ #include #include #include +#include +#include +#include #include #include +#include #include +#include +#include #include +#include #include @@ -41,17 +48,17 @@ static int node_req(struct firedtv *fdtv, u64 addr, void *data, size_t len, return rcode != RCODE_COMPLETE ? -EIO : 0; } -static int node_lock(struct firedtv *fdtv, u64 addr, void *data) +int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data) { return node_req(fdtv, addr, data, 8, TCODE_LOCK_COMPARE_SWAP); } -static int node_read(struct firedtv *fdtv, u64 addr, void *data) +int fdtv_read(struct firedtv *fdtv, u64 addr, void *data) { return node_req(fdtv, addr, data, 4, TCODE_READ_QUADLET_REQUEST); } -static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) +int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) { return node_req(fdtv, addr, data, len, TCODE_WRITE_BLOCK_REQUEST); } @@ -67,7 +74,7 @@ static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len) #define N_PAGES DIV_ROUND_UP(N_PACKETS, PACKETS_PER_PAGE) #define IRQ_INTERVAL 16 -struct firedtv_receive_context { +struct fdtv_ir_context { struct fw_iso_context *context; struct fw_iso_buffer buffer; int interrupt_packet; @@ -75,7 +82,7 @@ struct firedtv_receive_context { char *pages[N_PAGES]; }; -static int queue_iso(struct firedtv_receive_context *ctx, int index) +static int queue_iso(struct fdtv_ir_context *ctx, int index) { struct fw_iso_packet p; @@ -92,7 +99,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle, size_t header_length, void *header, void *data) { struct firedtv *fdtv = data; - struct firedtv_receive_context *ctx = fdtv->backend_data; + struct fdtv_ir_context *ctx = fdtv->ir_context; __be32 *h, *h_end; int length, err, i = ctx->current_packet; char *p, *p_end; @@ -121,9 +128,9 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle, ctx->current_packet = i; } -static int start_iso(struct firedtv *fdtv) +int fdtv_start_iso(struct firedtv *fdtv) { - struct firedtv_receive_context *ctx; + struct fdtv_ir_context *ctx; struct fw_device *device = device_of(fdtv); int i, err; @@ -161,7 +168,7 @@ static int start_iso(struct firedtv *fdtv) if (err) goto fail; - fdtv->backend_data = ctx; + fdtv->ir_context = ctx; return 0; fail: @@ -174,9 +181,9 @@ fail_free: return err; } -static void stop_iso(struct firedtv *fdtv) +void fdtv_stop_iso(struct firedtv *fdtv) { - struct firedtv_receive_context *ctx = fdtv->backend_data; + struct fdtv_ir_context *ctx = fdtv->ir_context; fw_iso_context_stop(ctx->context); fw_iso_buffer_destroy(&ctx->buffer, device_of(fdtv)->card); @@ -184,14 +191,6 @@ static void stop_iso(struct firedtv *fdtv) kfree(ctx); } -static const struct firedtv_backend backend = { - .lock = node_lock, - .read = node_read, - .write = node_write, - .start_iso = start_iso, - .stop_iso = stop_iso, -}; - static void handle_fcp(struct fw_card *card, struct fw_request *request, int tcode, int destination, int source, int generation, unsigned long long offset, void *payload, size_t length, @@ -238,6 +237,14 @@ static const struct fw_address_region fcp_region = { .end = CSR_REGISTER_BASE + CSR_FCP_END, }; +static const char * const model_names[] = { + [FIREDTV_UNKNOWN] = "unknown type", + [FIREDTV_DVB_S] = "FireDTV S/CI", + [FIREDTV_DVB_C] = "FireDTV C/CI", + [FIREDTV_DVB_T] = "FireDTV T/CI", + [FIREDTV_DVB_S2] = "FireDTV S2 ", +}; + /* Adjust the template string if models with longer names appear. */ #define MAX_MODEL_NAME_LEN sizeof("FireDTV ????") @@ -245,15 +252,31 @@ static int node_probe(struct device *dev) { struct firedtv *fdtv; char name[MAX_MODEL_NAME_LEN]; - int name_len, err; - - name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL, - name, sizeof(name)); + int name_len, i, err; - fdtv = fdtv_alloc(dev, &backend, name, name_len >= 0 ? name_len : 0); + fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL); if (!fdtv) return -ENOMEM; + dev_set_drvdata(dev, fdtv); + fdtv->device = dev; + fdtv->isochannel = -1; + fdtv->voltage = 0xff; + fdtv->tone = 0xff; + + mutex_init(&fdtv->avc_mutex); + init_waitqueue_head(&fdtv->avc_wait); + mutex_init(&fdtv->demux_mutex); + INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work); + + name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL, + name, sizeof(name)); + for (i = ARRAY_SIZE(model_names); --i; ) + if (strlen(model_names[i]) <= name_len && + strncmp(name, model_names[i], name_len) == 0) + break; + fdtv->type = i; + err = fdtv_register_rc(fdtv, dev); if (err) goto fail_free; @@ -266,7 +289,7 @@ static int node_probe(struct device *dev) if (err) goto fail; - err = fdtv_dvb_register(fdtv); + err = fdtv_dvb_register(fdtv, model_names[fdtv->type]); if (err) goto fail; @@ -309,6 +332,60 @@ static void node_update(struct fw_unit *unit) fdtv->isochannel); } +#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \ + IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION) + +#define DIGITAL_EVERYWHERE_OUI 0x001287 +#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d +#define AVC_SW_VERSION_ENTRY 0x010001 + +static const struct ieee1394_device_id fdtv_id_table[] = { + { + /* FloppyDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000024, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000025, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FloppyDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000026, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV S/CI and FloppyDTV S2 */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000034, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV T/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000035, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, { + /* FireDTV C/CI */ + .match_flags = MATCH_FLAGS, + .vendor_id = DIGITAL_EVERYWHERE_OUI, + .model_id = 0x000036, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY, + .version = AVC_SW_VERSION_ENTRY, + }, {} +}; +MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table); + static struct fw_driver fdtv_driver = { .driver = { .owner = THIS_MODULE, @@ -321,7 +398,7 @@ static struct fw_driver fdtv_driver = { .id_table = fdtv_id_table, }; -int __init fdtv_fw_init(void) +static int __init fdtv_init(void) { int ret; @@ -329,11 +406,24 @@ int __init fdtv_fw_init(void) if (ret < 0) return ret; - return driver_register(&fdtv_driver.driver); + ret = driver_register(&fdtv_driver.driver); + if (ret < 0) + fw_core_remove_address_handler(&fcp_handler); + + return ret; } -void fdtv_fw_exit(void) +static void __exit fdtv_exit(void) { driver_unregister(&fdtv_driver.driver); fw_core_remove_address_handler(&fcp_handler); } + +module_init(fdtv_init); +module_exit(fdtv_exit); + +MODULE_AUTHOR("Andreas Monitzer "); +MODULE_AUTHOR("Ben Backx "); +MODULE_DESCRIPTION("FireDTV DVB Driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("FireDTV DVB"); diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h index 4a87049c9132..bd00b04e079d 100644 --- a/drivers/media/dvb/firewire/firedtv.h +++ b/drivers/media/dvb/firewire/firedtv.h @@ -70,15 +70,7 @@ enum model_type { struct device; struct input_dev; -struct firedtv; - -struct firedtv_backend { - int (*lock)(struct firedtv *fdtv, u64 addr, void *data); - int (*read)(struct firedtv *fdtv, u64 addr, void *data); - int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len); - int (*start_iso)(struct firedtv *fdtv); - void (*stop_iso)(struct firedtv *fdtv); -}; +struct fdtv_ir_context; struct firedtv { struct device *device; @@ -104,12 +96,11 @@ struct firedtv { enum model_type type; char subunit; char isochannel; + struct fdtv_ir_context *ir_context; + fe_sec_voltage_t voltage; fe_sec_tone_mode_t tone; - const struct firedtv_backend *backend; - void *backend_data; - struct mutex demux_mutex; unsigned long channel_active; u16 channel_pid[16]; @@ -149,20 +140,18 @@ void fdtv_ca_release(struct firedtv *fdtv); /* firedtv-dvb.c */ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed); int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed); -int fdtv_dvb_register(struct firedtv *fdtv); +int fdtv_dvb_register(struct firedtv *fdtv, const char *name); void fdtv_dvb_unregister(struct firedtv *fdtv); -struct firedtv *fdtv_alloc(struct device *dev, - const struct firedtv_backend *backend, - const char *name, size_t name_len); -extern const char *fdtv_model_names[]; -extern const struct ieee1394_device_id fdtv_id_table[]; /* firedtv-fe.c */ -void fdtv_frontend_init(struct firedtv *fdtv); +void fdtv_frontend_init(struct firedtv *fdtv, const char *name); /* firedtv-fw.c */ -int fdtv_fw_init(void); -void fdtv_fw_exit(void); +int fdtv_lock(struct firedtv *fdtv, u64 addr, void *data); +int fdtv_read(struct firedtv *fdtv, u64 addr, void *data); +int fdtv_write(struct firedtv *fdtv, u64 addr, void *data, size_t len); +int fdtv_start_iso(struct firedtv *fdtv); +void fdtv_stop_iso(struct firedtv *fdtv); /* firedtv-rc.c */ #ifdef CONFIG_DVB_FIREDTV_INPUT -- cgit v1.2.2 From 2b74334d12914eb10b8dac90300c3799a2115569 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 6 Feb 2011 12:29:51 -0300 Subject: [media] dvb_pll: DVB-S incorrect tune settings for dw2102/dm1105/cx88/opera1 This tuner PLL has missing initialisation settings resulting in haphazard tuning. The PLL LPF was set to just 22000 symbol rate. Basically, the module is a Sharp BS2F7HZ0194 (STV0299+IX2410) I have had problems implementing the PLL in a new driver and did not want to break the IX2410 out of the PLL. This applies to DW2102, DM1105, CX88 and OPERA1 drivers. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dvb-pll.c | 79 ++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 4d4d0bb5920a..62a65efdf8d6 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -64,6 +64,7 @@ struct dvb_pll_desc { void (*set)(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params); u8 *initdata; + u8 *initdata2; u8 *sleepdata; int count; struct { @@ -321,26 +322,73 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = { static void opera1_bw(struct dvb_frontend *fe, u8 *buf, const struct dvb_frontend_parameters *params) { - if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) - buf[2] |= 0x08; + struct dvb_pll_priv *priv = fe->tuner_priv; + u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000; + struct i2c_msg msg = { + .addr = priv->pll_i2c_address, + .flags = 0, + .buf = buf, + .len = 4 + }; + int result; + u8 lpf; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) + printk(KERN_ERR "%s: i2c_transfer failed:%d", + __func__, result); + + if (b_w <= 10000) + lpf = 0xc; + else if (b_w <= 12000) + lpf = 0x2; + else if (b_w <= 14000) + lpf = 0xa; + else if (b_w <= 16000) + lpf = 0x6; + else if (b_w <= 18000) + lpf = 0xe; + else if (b_w <= 20000) + lpf = 0x1; + else if (b_w <= 22000) + lpf = 0x9; + else if (b_w <= 24000) + lpf = 0x5; + else if (b_w <= 26000) + lpf = 0xd; + else if (b_w <= 28000) + lpf = 0x3; + else + lpf = 0xb; + buf[2] ^= 0x1c; /* Flip bits 3-5 */ + /* Set lpf */ + buf[2] |= ((lpf >> 2) & 0x3) << 3; + buf[3] |= (lpf & 0x3) << 2; + + return; } static struct dvb_pll_desc dvb_pll_opera1 = { .name = "Opera Tuner", .min = 900000, .max = 2250000, + .initdata = (u8[]){ 4, 0x08, 0xe5, 0xe1, 0x00 }, + .initdata2 = (u8[]){ 4, 0x08, 0xe5, 0xe5, 0x00 }, .iffreq= 0, .set = opera1_bw, .count = 8, .entries = { - { 1064000, 500, 0xe5, 0xc6 }, - { 1169000, 500, 0xe5, 0xe6 }, - { 1299000, 500, 0xe5, 0x24 }, - { 1444000, 500, 0xe5, 0x44 }, - { 1606000, 500, 0xe5, 0x64 }, - { 1777000, 500, 0xe5, 0x84 }, - { 1941000, 500, 0xe5, 0xa4 }, - { 2250000, 500, 0xe5, 0xc4 }, + { 1064000, 500, 0xf9, 0xc2 }, + { 1169000, 500, 0xf9, 0xe2 }, + { 1299000, 500, 0xf9, 0x20 }, + { 1444000, 500, 0xf9, 0x40 }, + { 1606000, 500, 0xf9, 0x60 }, + { 1777000, 500, 0xf9, 0x80 }, + { 1941000, 500, 0xf9, 0xa0 }, + { 2250000, 500, 0xf9, 0xc0 }, } }; @@ -648,8 +696,17 @@ static int dvb_pll_init(struct dvb_frontend *fe) int result; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) return result; + if (priv->pll_desc->initdata2) { + msg.buf = priv->pll_desc->initdata2 + 1; + msg.len = priv->pll_desc->initdata2[0]; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + result = i2c_transfer(priv->i2c, &msg, 1); + if (result != 1) + return result; } return 0; } -- cgit v1.2.2 From 9bf98321b4894b1e6787b4b93cd8fb81906a0f79 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 13 Feb 2011 17:31:55 -0300 Subject: [media] pvrusb2: Handle change of mode before handling change of video standard pvrusb2: Recognize and handle mode change before dealing with changes related to the video standard. Even though the video standard should only matter when in analog mode, doing this way is technically cleaner in case there's other stuff that might depend on both. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 66ad516bdfd9..55074a89966f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -3165,6 +3165,19 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) struct pvr2_ctrl *cptr; int disruptive_change; + if (hdw->input_dirty && hdw->state_pathway_ok && + (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ? + PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) != + hdw->pathway_state)) { + /* Change of mode being asked for... */ + hdw->state_pathway_ok = 0; + trace_stbit("state_pathway_ok", hdw->state_pathway_ok); + } + if (!hdw->state_pathway_ok) { + /* Can't commit anything until pathway is ok. */ + return 0; + } + /* Handle some required side effects when the video standard is changed.... */ if (hdw->std_dirty) { @@ -3199,18 +3212,6 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) } } - if (hdw->input_dirty && hdw->state_pathway_ok && - (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ? - PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) != - hdw->pathway_state)) { - /* Change of mode being asked for... */ - hdw->state_pathway_ok = 0; - trace_stbit("state_pathway_ok",hdw->state_pathway_ok); - } - if (!hdw->state_pathway_ok) { - /* Can't commit anything until pathway is ok. */ - return 0; - } /* The broadcast decoder can only scale down, so if * res_*_dirty && crop window < output format ==> enlarge crop. * -- cgit v1.2.2 From 4cfe3319a11613690c3cd755b890149d0532c833 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 13 Feb 2011 17:32:47 -0300 Subject: [media] pvrusb2: Minor cosmetic code tweak Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 55074a89966f..f83e5cf3967f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -5160,8 +5160,7 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw) using v4l2-subdev - therefore we can't support that AT ALL right now. (Of course, no sub-drivers seem to implement it either. But now it's a a chicken and egg problem...) */ - v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, - &hdw->tuner_signal_info); + v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp); pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll" " type=%u strength=%u audio=0x%x cap=0x%x" " low=%u hi=%u", -- cgit v1.2.2 From 35fa5d4c48fbb02d637c3659f00331aa33f0f029 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 13 Feb 2011 17:34:33 -0300 Subject: [media] pvrusb2: Fix a few missing default control values, for cropping Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index f83e5cf3967f..5e6437dd91df 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1114,6 +1114,7 @@ static const struct pvr2_ctl_info control_defs[] = { .internal_id = PVR2_CID_CROPW, .default_value = 720, DEFREF(cropw), + DEFINT(0, 864), .get_max_value = ctrl_cropw_max_get, .get_def_value = ctrl_get_cropcapdw, }, { @@ -1122,6 +1123,7 @@ static const struct pvr2_ctl_info control_defs[] = { .internal_id = PVR2_CID_CROPH, .default_value = 480, DEFREF(croph), + DEFINT(0, 576), .get_max_value = ctrl_croph_max_get, .get_def_value = ctrl_get_cropcapdh, }, { -- cgit v1.2.2 From 6188a0f151204d6f895822e8c0059b8951879a42 Mon Sep 17 00:00:00 2001 From: Servaas Vandenberghe Date: Sun, 13 Feb 2011 17:51:09 -0300 Subject: [media] pvrusb2: width and height maximum values pvrusb2: The origin of the capability bounds rectangle may differ from (left=0,top=0) so the calculation should use absolute coordinates, here below, or use relative coordinates like cropl_val-cap->bounds.left and cropt_val-cap->bounds.top. Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 5e6437dd91df..48859370c57b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -499,31 +499,35 @@ static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top) return 0; } -static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val) +static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *width) { struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); + int stat, bleftend, cleft; + + stat = pvr2_hdw_check_cropcap(cptr->hdw); if (stat != 0) { return stat; } - *val = 0; - if (cap->bounds.width > cptr->hdw->cropl_val) { - *val = cap->bounds.width - cptr->hdw->cropl_val; - } + bleftend = cap->bounds.left+cap->bounds.width; + cleft = cptr->hdw->cropl_val; + + *width = cleft < bleftend ? bleftend-cleft : 0; return 0; } -static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val) +static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *height) { struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; - int stat = pvr2_hdw_check_cropcap(cptr->hdw); + int stat, btopend, ctop; + + stat = pvr2_hdw_check_cropcap(cptr->hdw); if (stat != 0) { return stat; } - *val = 0; - if (cap->bounds.height > cptr->hdw->cropt_val) { - *val = cap->bounds.height - cptr->hdw->cropt_val; - } + btopend = cap->bounds.top+cap->bounds.height; + ctop = cptr->hdw->cropt_val; + + *height = ctop < btopend ? btopend-ctop : 0; return 0; } -- cgit v1.2.2 From 058caa878476a09159e2fcc65463b9174c4fde8d Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 13 Feb 2011 17:53:07 -0300 Subject: [media] pvrusb2: Minor VBI tweak to help potential CC support pvrusb2: Declare closed-caption setup for line 21 - this is needed for sliced VBI capture support. (However none of that works right now anyway.) Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 48859370c57b..d33dd61de263 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2033,6 +2033,8 @@ static void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw) hdw->decoder_client_id); memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + fmt.fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525; + fmt.fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525; v4l2_device_call_all(&hdw->v4l2_dev, hdw->decoder_client_id, vbi, s_sliced_fmt, &fmt.fmt.sliced); } -- cgit v1.2.2 From 19a0a296f2df31c24f87fd3e7ee7f2640e49e5d4 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 13 Feb 2011 17:57:19 -0300 Subject: [media] pvrusb2: Use sysfs_attr_init() where appropriate Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-sysfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 281806b2df62..6ef1335b2858 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -324,36 +324,45 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) } sfp->item_last = cip; + sysfs_attr_init(&cip->attr_name.attr); cip->attr_name.attr.name = "name"; cip->attr_name.attr.mode = S_IRUGO; cip->attr_name.show = show_name; + sysfs_attr_init(&cip->attr_type.attr); cip->attr_type.attr.name = "type"; cip->attr_type.attr.mode = S_IRUGO; cip->attr_type.show = show_type; + sysfs_attr_init(&cip->attr_min.attr); cip->attr_min.attr.name = "min_val"; cip->attr_min.attr.mode = S_IRUGO; cip->attr_min.show = show_min; + sysfs_attr_init(&cip->attr_max.attr); cip->attr_max.attr.name = "max_val"; cip->attr_max.attr.mode = S_IRUGO; cip->attr_max.show = show_max; + sysfs_attr_init(&cip->attr_def.attr); cip->attr_def.attr.name = "def_val"; cip->attr_def.attr.mode = S_IRUGO; cip->attr_def.show = show_def; + sysfs_attr_init(&cip->attr_val.attr); cip->attr_val.attr.name = "cur_val"; cip->attr_val.attr.mode = S_IRUGO; + sysfs_attr_init(&cip->attr_custom.attr); cip->attr_custom.attr.name = "custom_val"; cip->attr_custom.attr.mode = S_IRUGO; + sysfs_attr_init(&cip->attr_enum.attr); cip->attr_enum.attr.name = "enum_val"; cip->attr_enum.attr.mode = S_IRUGO; cip->attr_enum.show = show_enum; + sysfs_attr_init(&cip->attr_bits.attr); cip->attr_bits.attr.name = "bit_val"; cip->attr_bits.attr.mode = S_IRUGO; cip->attr_bits.show = show_bits; -- cgit v1.2.2 From ba0fd56a4fbb92999554a2e417924796c2ad2f8f Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 6 Feb 2011 17:49:02 -0300 Subject: [media] TTUSB DVB: ttusb_boot_dsp() needs to release_firmware() or it leaks memory In drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c:ttusb_boot_dsp() we need to call release_firmware(fw) before returning or we'll leak - no matter if we succeed or fail. Signed-off-by: Jesper Juhl Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 40625b26ac10..cbe2f0de1442 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -334,6 +334,7 @@ static int ttusb_boot_dsp(struct ttusb *ttusb) err = ttusb_cmd(ttusb, b, 4, 0); done: + release_firmware(fw); if (err) { dprintk("%s: usb_bulk_msg() failed, return value %i!\n", __func__, err); -- cgit v1.2.2 From feb16e9833ad06ac00f23c1abf1e7d649192e3f5 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:22 -0300 Subject: [media] dw2102: Extend keymap parameter for not used remote Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 2c307ba0d28b..21be0cca3c89 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -87,7 +87,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." /* keymaps */ static int ir_keymap; module_param_named(keymap, ir_keymap, int, 0644); -MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."); +MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..." + " 256=none"); /* demod probe */ static int demod_probe = 1; @@ -1089,7 +1090,8 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) { keymap = keys_tables[ir_keymap - 1].rc_keys ; keymap_size = keys_tables[ir_keymap - 1].rc_keys_size; - } + } else if (ir_keymap > ARRAY_SIZE(keys_tables)) + return 0; /* none */ *state = REMOTE_NO_KEY_PRESSED; if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) { -- cgit v1.2.2 From 195288da53e03c35f97df8fa08f48f5b625bfb4e Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:22 -0300 Subject: [media] dw2102: use separate firmwares for Prof 1100, TeVii S630, S660 Before this patch we can use only one card type from list due to sharing one firmware name. Now it's fixed. Also driver tries to attach only appropriate demod for this cards. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 72 ++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 21be0cca3c89..f9affdd12d91 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -886,7 +886,7 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) return -EIO; } -static int s6x0_frontend_attach(struct dvb_usb_adapter *d) +static int zl100313_frontend_attach(struct dvb_usb_adapter *d) { d->fe = dvb_attach(mt312_attach, &zl313_config, &d->dev->i2c_adap); @@ -899,6 +899,11 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d) } } + return -EIO; +} + +static int stv0288_frontend_attach(struct dvb_usb_adapter *d) +{ d->fe = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); if (d->fe != NULL) { @@ -910,6 +915,11 @@ static int s6x0_frontend_attach(struct dvb_usb_adapter *d) } } + return -EIO; +} + +static int ds3000_frontend_attach(struct dvb_usb_adapter *d) +{ d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); if (d->fe != NULL) { @@ -1418,7 +1428,7 @@ static struct dvb_usb_device_properties s6x0_properties = { .read_mac_address = s6x0_read_mac_address, .adapter = { { - .frontend_attach = s6x0_frontend_attach, + .frontend_attach = zl100313_frontend_attach, .streaming_ctrl = NULL, .tuner_attach = NULL, .stream = { @@ -1433,23 +1443,29 @@ static struct dvb_usb_device_properties s6x0_properties = { }, } }, - .num_device_descs = 3, + .num_device_descs = 1, .devices = { {"TeVii S630 USB", {&dw2102_table[6], NULL}, {NULL}, }, - {"Prof 1100 USB ", - {&dw2102_table[7], NULL}, - {NULL}, - }, - {"TeVii S660 USB", - {&dw2102_table[8], NULL}, - {NULL}, - }, } }; +struct dvb_usb_device_properties *p1100; +static struct dvb_usb_device_description d1100 = { + "Prof 1100 USB ", + {&dw2102_table[7], NULL}, + {NULL}, +}; + +struct dvb_usb_device_properties *s660; +static struct dvb_usb_device_description d660 = { + "TeVii S660 USB", + {&dw2102_table[8], NULL}, + {NULL}, +}; + struct dvb_usb_device_properties *p7500; static struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", @@ -1460,14 +1476,38 @@ static struct dvb_usb_device_description d7500 = { static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { + p1100 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!p1100) + return -ENOMEM; + /* copy default structure */ + memcpy(p1100, &s6x0_properties, + sizeof(struct dvb_usb_device_properties)); + /* fill only different fields */ + p1100->firmware = "dvb-usb-p1100.fw"; + p1100->devices[0] = d1100; + p1100->rc.legacy.rc_map_table = rc_map_tbs_table; + p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table); + p1100->adapter->frontend_attach = stv0288_frontend_attach; + + s660 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); + if (!s660) { + kfree(p1100); + return -ENOMEM; + } + memcpy(s660, &s6x0_properties, + sizeof(struct dvb_usb_device_properties)); + s660->firmware = "dvb-usb-s660.fw"; + s660->devices[0] = d660; + s660->adapter->frontend_attach = ds3000_frontend_attach; p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); - if (!p7500) + if (!p7500) { + kfree(p1100); + kfree(s660); return -ENOMEM; - /* copy default structure */ + } memcpy(p7500, &s6x0_properties, sizeof(struct dvb_usb_device_properties)); - /* fill only different fields */ p7500->firmware = "dvb-usb-p7500.fw"; p7500->devices[0] = d7500; p7500->rc.legacy.rc_map_table = rc_map_tbs_table; @@ -1482,6 +1522,10 @@ static int dw2102_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &s6x0_properties, THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, p1100, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, s660, + THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, p7500, THIS_MODULE, NULL, adapter_nr)) return 0; -- cgit v1.2.2 From d2ffc447cabb3a497d7f413403abd8793b348329 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:22 -0300 Subject: [media] dw2102: add support for Geniatech SU3000 USB DVB-S2 card The card uses ds3000 demod from Montage. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 287 ++++++++++++++++++++++++++++++++++- drivers/media/dvb/frontends/ds3000.c | 40 +++++ drivers/media/dvb/frontends/ds3000.h | 1 + 3 files changed, 325 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index f9affdd12d91..461c96a816d7 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1,7 +1,8 @@ /* DVB USB framework compliant Linux driver for the * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, * TeVii S600, S630, S650, -* Prof 1100, 7500 Cards +* Prof 1100, 7500, + * Geniatech SU3000 Cards * Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by) * * This program is free software; you can redistribute it and/or modify it @@ -67,6 +68,7 @@ #define REG_21_SYMBOLRATE_BYTE2 0x21 /* on my own*/ #define DW2102_VOLTAGE_CTRL (0x1800) +#define SU3000_STREAM_CTRL (0x1900) #define DW2102_RC_QUERY (0x1a00) #define err_str "did not find the firmware file. (%s) " \ @@ -78,6 +80,10 @@ struct rc_map_dvb_usb_table_table { int rc_keys_size; }; +struct su3000_state { + u8 initialized; +}; + /* debug */ static int dvb_usb_dw2102_debug; module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); @@ -570,6 +576,70 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], return num; } +static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) +{ + struct dvb_usb_device *d = i2c_get_adapdata(adap); + u8 obuf[0x40], ibuf[0x40]; + + if (!d) + return -ENODEV; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + + switch (num) { + case 1: + switch (msg[0].addr) { + case SU3000_STREAM_CTRL: + obuf[0] = msg[0].buf[0] + 0x36; + obuf[1] = 3; + obuf[2] = 0; + if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0) + err("i2c transfer failed."); + break; + case DW2102_RC_QUERY: + obuf[0] = 0x10; + if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0) + err("i2c transfer failed."); + msg[0].buf[1] = ibuf[0]; + msg[0].buf[0] = ibuf[1]; + break; + default: + /* always i2c write*/ + obuf[0] = 0x08; + obuf[1] = msg[0].addr; + obuf[2] = msg[0].len; + + memcpy(&obuf[3], msg[0].buf, msg[0].len); + + if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3, + ibuf, 1, 0) < 0) + err("i2c transfer failed."); + + } + break; + case 2: + /* always i2c read */ + obuf[0] = 0x09; + obuf[1] = msg[0].len; + obuf[2] = msg[1].len; + obuf[3] = msg[0].addr; + memcpy(&obuf[4], msg[0].buf, msg[0].len); + + if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4, + ibuf, msg[1].len + 1, 0) < 0) + err("i2c transfer failed."); + + memcpy(msg[1].buf, &ibuf[1], msg[1].len); + break; + default: + warn("more than 2 i2c messages at a time is not handled yet."); + break; + } + mutex_unlock(&d->i2c_mutex); + return num; +} + static u32 dw210x_i2c_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; @@ -605,6 +675,11 @@ static struct i2c_algorithm s6x0_i2c_algo = { .functionality = dw210x_i2c_func, }; +static struct i2c_algorithm su3000_i2c_algo = { + .master_xfer = su3000_i2c_transfer, + .functionality = dw210x_i2c_func, +}; + static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) { int i; @@ -669,6 +744,82 @@ static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) return 0; }; +static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + static u8 command_start[] = {0x00}; + static u8 command_stop[] = {0x01}; + struct i2c_msg msg = { + .addr = SU3000_STREAM_CTRL, + .flags = 0, + .buf = onoff ? command_start : command_stop, + .len = 1 + }; + + i2c_transfer(&adap->dev->i2c_adap, &msg, 1); + + return 0; +} + +static int su3000_power_ctrl(struct dvb_usb_device *d, int i) +{ + struct su3000_state *state = (struct su3000_state *)d->priv; + u8 obuf[] = {0xde, 0}; + + info("%s: %d, initialized %d\n", __func__, i, state->initialized); + + if (i && !state->initialized) { + state->initialized = 1; + /* reset board */ + dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0); + } + + return 0; +} + +static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +{ + int i; + u8 obuf[] = { 0x1f, 0xf0 }; + u8 ibuf[] = { 0 }; + struct i2c_msg msg[] = { + { + .addr = 0x51, + .flags = 0, + .buf = obuf, + .len = 2, + }, { + .addr = 0x51, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 1, + + } + }; + + for (i = 0; i < 6; i++) { + obuf[1] = 0xf0 + i; + if (i2c_transfer(&d->i2c_adap, msg, 2) != 2) + break; + else + mac[i] = ibuf[0]; + + debug_dump(mac, 6, printk); + } + + return 0; +} + +static int su3000_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + info("%s\n", __func__); + + *cold = 0; + return 0; +} + static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { static u8 command_13v[] = {0x00, 0x01}; @@ -774,6 +925,11 @@ static struct stv0900_config prof_7500_stv0900_config = { .tun1_type = 3, }; +static struct ds3000_config su3000_ds3000_config = { + .demod_address = 0x68, + .ci_mode = 1, +}; + static int dw2104_frontend_attach(struct dvb_usb_adapter *d) { struct dvb_tuner_ops *tuner_ops = NULL; @@ -944,6 +1100,43 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) return 0; } +static int su3000_frontend_attach(struct dvb_usb_adapter *d) +{ + u8 obuf[3] = { 0xe, 0x80, 0 }; + u8 ibuf[] = { 0 }; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 0; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0xe; + obuf[1] = 0x83; + obuf[2] = 1; + + if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0) + err("command 0x0e transfer failed."); + + obuf[0] = 0x51; + + if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) + err("command 0x51 transfer failed."); + + d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, + &d->dev->i2c_adap); + if (d->fe == NULL) + return -EIO; + + info("Attached DS3000!\n"); + + return 0; +} + static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x60, @@ -1078,10 +1271,49 @@ static struct rc_map_table rc_map_tbs_table[] = { { 0xf89b, KEY_MODE } }; +static struct rc_map_table rc_map_su3000_table[] = { + { 0x25, KEY_POWER }, /* right-bottom Red */ + { 0x0a, KEY_MUTE }, /* -/-- */ + { 0x01, KEY_1 }, + { 0x02, KEY_2 }, + { 0x03, KEY_3 }, + { 0x04, KEY_4 }, + { 0x05, KEY_5 }, + { 0x06, KEY_6 }, + { 0x07, KEY_7 }, + { 0x08, KEY_8 }, + { 0x09, KEY_9 }, + { 0x00, KEY_0 }, + { 0x20, KEY_UP }, /* CH+ */ + { 0x21, KEY_DOWN }, /* CH+ */ + { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ + { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */ + { 0x1f, KEY_RECORD }, + { 0x17, KEY_PLAY }, + { 0x16, KEY_PAUSE }, + { 0x0b, KEY_STOP }, + { 0x27, KEY_FASTFORWARD },/* >> */ + { 0x26, KEY_REWIND }, /* << */ + { 0x0d, KEY_OK }, /* Mute */ + { 0x11, KEY_LEFT }, /* VOL- */ + { 0x10, KEY_RIGHT }, /* VOL+ */ + { 0x29, KEY_BACK }, /* button under 9 */ + { 0x2c, KEY_MENU }, /* TTX */ + { 0x2b, KEY_EPG }, /* EPG */ + { 0x1e, KEY_RED }, /* OSD */ + { 0x0e, KEY_GREEN }, /* Window */ + { 0x2d, KEY_YELLOW }, /* button under << */ + { 0x0f, KEY_BLUE }, /* bottom yellow button */ + { 0x14, KEY_AUDIO }, /* Snapshot */ + { 0x38, KEY_TV }, /* TV/Radio */ + { 0x0c, KEY_ESC } /* upper Red buttton */ +}; + static struct rc_map_dvb_usb_table_table keys_tables[] = { { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) }, { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) }, { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) }, + { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) }, }; static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state) @@ -1137,6 +1369,7 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, {USB_DEVICE(0x3034, 0x7500)}, + {USB_DEVICE(0x1f4d, 0x3000)}, { } }; @@ -1473,6 +1706,51 @@ static struct dvb_usb_device_description d7500 = { {NULL}, }; +static struct dvb_usb_device_properties su3000_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct su3000_state), + .power_ctrl = su3000_power_ctrl, + .num_adapters = 1, + .identify_state = su3000_identify_state, + .i2c_algo = &su3000_i2c_algo, + + .rc.legacy = { + .rc_map_table = rc_map_su3000_table, + .rc_map_size = ARRAY_SIZE(rc_map_su3000_table), + .rc_interval = 150, + .rc_query = dw2102_rc_query, + }, + + .read_mac_address = su3000_read_mac_address, + + .generic_bulk_ctrl_endpoint = 0x01, + + .adapter = { + { + .streaming_ctrl = su3000_streaming_ctrl, + .frontend_attach = su3000_frontend_attach, + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + } + } + }, + .num_device_descs = 1, + .devices = { + { "SU3000HD DVB-S USB2.0", + { &dw2102_table[10], NULL }, + { NULL }, + }, + } +}; + static int dw2102_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1527,7 +1805,9 @@ static int dw2102_probe(struct usb_interface *intf, 0 == dvb_usb_device_init(intf, s660, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, p7500, - THIS_MODULE, NULL, adapter_nr)) + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &su3000_properties, + THIS_MODULE, NULL, adapter_nr)) return 0; return -ENODEV; @@ -1561,6 +1841,7 @@ MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," " DVB-C 3101 USB2.0," " TeVii S600, S630, S650, S660 USB2.0," - " Prof 1100, 7500 USB2.0 devices"); + " Prof 1100, 7500 USB2.0," + " Geniatech SU3000 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 993357383fd4..3373890c092e 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -509,6 +509,33 @@ static int ds3000_load_firmware(struct dvb_frontend *fe, return 0; } +static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct ds3000_state *state = fe->demodulator_priv; + u8 data; + + dprintk("%s(%d)\n", __func__, voltage); + + data = ds3000_readreg(state, 0xa2); + data |= 0x03; /* bit0 V/H, bit1 off/on */ + + switch (voltage) { + case SEC_VOLTAGE_18: + data &= ~0x03; + break; + case SEC_VOLTAGE_13: + data &= ~0x03; + data |= 0x01; + break; + case SEC_VOLTAGE_OFF: + break; + } + + ds3000_writereg(state, 0xa2, data); + + return 0; +} + static void ds3000_dump_registers(struct dvb_frontend *fe) { struct ds3000_state *state = fe->demodulator_priv; @@ -1255,6 +1282,18 @@ static int ds3000_tune(struct dvb_frontend *fe, ds3000_writereg(state, 0xfd, 0x42); ds3000_writereg(state, 0x08, 0x07);*/ + if (state->config->ci_mode) { + switch (c->delivery_system) { + case SYS_DVBS: + default: + ds3000_writereg(state, 0xfd, 0x80); + break; + case SYS_DVBS2: + ds3000_writereg(state, 0xfd, 0x01); + break; + } + } + /* ds3000 out of software reset */ ds3000_writereg(state, 0x00, 0x00); /* start ds3000 build-in uC */ @@ -1351,6 +1390,7 @@ static struct dvb_frontend_ops ds3000_ops = { .read_signal_strength = ds3000_read_signal_strength, .read_snr = ds3000_read_snr, .read_ucblocks = ds3000_read_ucblocks, + .set_voltage = ds3000_set_voltage, .set_tone = ds3000_set_tone, .diseqc_send_master_cmd = ds3000_send_diseqc_msg, .diseqc_send_burst = ds3000_diseqc_send_burst, diff --git a/drivers/media/dvb/frontends/ds3000.h b/drivers/media/dvb/frontends/ds3000.h index 67f67038740a..00e4e95590e9 100644 --- a/drivers/media/dvb/frontends/ds3000.h +++ b/drivers/media/dvb/frontends/ds3000.h @@ -27,6 +27,7 @@ struct ds3000_config { /* the demodulator's i2c address */ u8 demod_address; + u8 ci_mode; }; #if defined(CONFIG_DVB_DS3000) || \ -- cgit v1.2.2 From 2adc591fb7764bf70f65a5923ff50c1c1b671c20 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:22 -0300 Subject: [media] dw2102: Add Terratec Cinergy S2 USB HD MarkusF wrote: I accidently got a Terratec Cinergy S2 USB HD (instead of a Terratec Cinergy S2 PCI HD). I found in the windows driver, that the driver is for the usb ids: 0CCD:00A8 1F4D:3000 The dvb-s2 usb adapter has the id 0CCD-00A8. So I patches your driver and added the usb id, where the 1F4D:3000 is and it worked (after I downloaded the firmware dvb-fe-ds3000.fw). w_scan found the channels and vdr is working fine. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 461c96a816d7..57af4c17d54f 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1370,6 +1370,7 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, {USB_DEVICE(0x3034, 0x7500)}, {USB_DEVICE(0x1f4d, 0x3000)}, + {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, { } }; @@ -1742,12 +1743,16 @@ static struct dvb_usb_device_properties su3000_properties = { } } }, - .num_device_descs = 1, + .num_device_descs = 2, .devices = { { "SU3000HD DVB-S USB2.0", { &dw2102_table[10], NULL }, { NULL }, }, + { "Terratec Cinergy S2 USB HD", + { &dw2102_table[11], NULL }, + { NULL }, + }, } }; -- cgit v1.2.2 From fa8bae102fbbabe9ecc4381ace3b74a199684594 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:22 -0300 Subject: [media] dw2102: Prof 7500: Lock LED implemented Code changed for dw2102, stv0900 in order to achieve that. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 29 +++++++++++++++++++++++++++++ drivers/media/dvb/frontends/stv0900.h | 2 ++ drivers/media/dvb/frontends/stv0900_core.c | 23 ++++++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 57af4c17d54f..4ae4fb02164d 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -70,6 +70,7 @@ #define DW2102_VOLTAGE_CTRL (0x1800) #define SU3000_STREAM_CTRL (0x1900) #define DW2102_RC_QUERY (0x1a00) +#define DW2102_LED_CTRL (0x1b00) #define err_str "did not find the firmware file. (%s) " \ "Please see linux/Documentation/dvb/ for more details " \ @@ -509,6 +510,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf, 2, DW210X_WRITE_MSG); break; } + case (DW2102_LED_CTRL): { + u8 obuf[2]; + + obuf[0] = 5; + obuf[1] = msg[j].buf[0]; + ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, + obuf, 2, DW210X_WRITE_MSG); + break; + } /*case 0x55: cx24116 case 0x6a: stv0903 case 0x68: ds3000, stv0903 @@ -844,6 +854,24 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } +static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) +{ + static u8 led_off[] = { 0 }; + static u8 led_on[] = { 1 }; + struct i2c_msg msg = { + .addr = DW2102_LED_CTRL, + .flags = 0, + .buf = led_off, + .len = 1 + }; + struct dvb_usb_adapter *udev_adap = + (struct dvb_usb_adapter *)(fe->dvb->priv); + + if (offon) + msg.buf = led_on; + i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1); +} + static struct stv0299_config sharp_z0194a_config = { .demod_address = 0x68, .inittab = sharp_z0194a_inittab, @@ -923,6 +951,7 @@ static struct stv0900_config prof_7500_stv0900_config = { .tun1_adc = 0,/* 2 Vpp */ .path1_mode = 3, .tun1_type = 3, + .set_lock_led = dw210x_led_ctrl, }; static struct ds3000_config su3000_ds3000_config = { diff --git a/drivers/media/dvb/frontends/stv0900.h b/drivers/media/dvb/frontends/stv0900.h index e3e35d1ce838..91c7ee8b2313 100644 --- a/drivers/media/dvb/frontends/stv0900.h +++ b/drivers/media/dvb/frontends/stv0900.h @@ -53,6 +53,8 @@ struct stv0900_config { u8 tun2_type; /* Set device param to start dma */ int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); + /* Hook for Lock LED */ + void (*set_lock_led)(struct dvb_frontend *fe, int offon); }; #if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \ diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index 4f5e7d3a0e61..1ca1c835048f 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -1660,8 +1660,13 @@ static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status) | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; - } else + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 1); + } else { + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 0); dprintk("DEMOD LOCK FAIL\n"); + } return 0; } @@ -1831,6 +1836,9 @@ static void stv0900_release(struct dvb_frontend *fe) dprintk("%s\n", __func__); + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 0); + if ((--(state->internal->dmds_used)) <= 0) { dprintk("%s: Actually removing\n", __func__); @@ -1842,6 +1850,18 @@ static void stv0900_release(struct dvb_frontend *fe) kfree(state); } +static int stv0900_sleep(struct dvb_frontend *fe) +{ + struct stv0900_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (state->config->set_lock_led) + state->config->set_lock_led(fe, 0); + + return 0; +} + static int stv0900_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { @@ -1876,6 +1896,7 @@ static struct dvb_frontend_ops stv0900_ops = { .release = stv0900_release, .init = stv0900_init, .get_frontend = stv0900_get_frontend, + .sleep = stv0900_sleep, .get_frontend_algo = stv0900_frontend_algo, .i2c_gate_ctrl = stv0900_i2c_gate_ctrl, .diseqc_send_master_cmd = stv0900_send_master_cmd, -- cgit v1.2.2 From 4e59df8f25950520cd6a8b16a39d48b5fa5aeeda Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] dw2102: Prof 7500 remote fix Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 4ae4fb02164d..ea9a01c24fc7 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1118,12 +1118,17 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) { + u8 obuf[] = {7, 1}; + d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, &d->dev->i2c_adap, 0); if (d->fe == NULL) return -EIO; + d->fe->ops.set_voltage = dw210x_set_voltage; + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + info("Attached STV0900+STB6100A!\n"); return 0; -- cgit v1.2.2 From d3210b5f9618fc3d231caf39ffd32fda490e3ea5 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] dw2102: Prof 1100 initialization fix RC keys structure for Prof 1100 already defined, so remove extra initialization. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index ea9a01c24fc7..445819965e66 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1464,11 +1464,6 @@ static int dw2102_load_firmware(struct usb_device *dev, } /* init registers */ switch (dev->descriptor.idProduct) { - case USB_PID_PROF_1100: - s6x0_properties.rc.legacy.rc_map_table = rc_map_tbs_table; - s6x0_properties.rc.legacy.rc_map_size = - ARRAY_SIZE(rc_map_tbs_table); - break; case USB_PID_TEVII_S650: dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table; dw2104_properties.rc.legacy.rc_map_size = -- cgit v1.2.2 From 69519c3eff2a4a164351792d70666efa900b697e Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] dw2102: unnecessary NULL's removed Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 445819965e66..d1ddf7e81735 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1546,8 +1546,6 @@ static struct dvb_usb_device_properties dw2102_properties = { .adapter = { { .frontend_attach = dw2102_frontend_attach, - .streaming_ctrl = NULL, - .tuner_attach = NULL, .stream = { .type = USB_BULK, .count = 8, @@ -1599,8 +1597,6 @@ static struct dvb_usb_device_properties dw2104_properties = { .adapter = { { .frontend_attach = dw2104_frontend_attach, - .streaming_ctrl = NULL, - /*.tuner_attach = dw2104_tuner_attach,*/ .stream = { .type = USB_BULK, .count = 8, @@ -1648,7 +1644,6 @@ static struct dvb_usb_device_properties dw3101_properties = { .adapter = { { .frontend_attach = dw3101_frontend_attach, - .streaming_ctrl = NULL, .tuner_attach = dw3101_tuner_attach, .stream = { .type = USB_BULK, @@ -1692,8 +1687,6 @@ static struct dvb_usb_device_properties s6x0_properties = { .adapter = { { .frontend_attach = zl100313_frontend_attach, - .streaming_ctrl = NULL, - .tuner_attach = NULL, .stream = { .type = USB_BULK, .count = 8, -- cgit v1.2.2 From 52c506e09cd624cbf7d21d9c16283f3e8b32f4bc Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] dw2102: corrections for TeVii s660 LNB power control There are two TeVii s660 modifications with different LNB power control implementations. It is safe to call both methods for each card. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index d1ddf7e81735..0ab377e3d6f2 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -85,6 +85,10 @@ struct su3000_state { u8 initialized; }; +struct s6x0_state { + int (*old_set_voltage)(struct dvb_frontend *f, fe_sec_voltage_t v); +}; + /* debug */ static int dvb_usb_dw2102_debug; module_param_named(debug, dvb_usb_dw2102_debug, int, 0644); @@ -854,6 +858,19 @@ static int dw210x_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } +static int s660_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct dvb_usb_adapter *d = + (struct dvb_usb_adapter *)(fe->dvb->priv); + struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + + dw210x_set_voltage(fe, voltage); + if (st->old_set_voltage) + st->old_set_voltage(fe, voltage); + + return 0; +} + static void dw210x_led_ctrl(struct dvb_frontend *fe, int offon) { static u8 led_off[] = { 0 }; @@ -1105,15 +1122,19 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) static int ds3000_frontend_attach(struct dvb_usb_adapter *d) { + struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached ds3000+ds2020!\n"); - return 0; - } - return -EIO; + if (d->fe == NULL) + return -EIO; + + st->old_set_voltage = d->fe->ops.set_voltage; + d->fe->ops.set_voltage = s660_set_voltage; + info("Attached ds3000+ds2020!\n"); + + return 0; } static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) @@ -1669,6 +1690,7 @@ static struct dvb_usb_device_properties dw3101_properties = { static struct dvb_usb_device_properties s6x0_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, + .size_of_priv = sizeof(struct s6x0_state), .firmware = "dvb-usb-s630.fw", .no_reconnect = 1, -- cgit v1.2.2 From 5a530cbecaa5a21d185e0549ea9a866483661f6f Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] dw2102: fix TeVii s660 remote control Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 0ab377e3d6f2..893149170faa 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -495,10 +495,10 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], for (j = 0; j < num; j++) { switch (msg[j].addr) { case (DW2102_RC_QUERY): { - u8 ibuf[4]; + u8 ibuf[5]; ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, - ibuf, 4, DW210X_READ_MSG); - memcpy(msg[j].buf, ibuf + 1, 2); + ibuf, 5, DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf + 3, 2); break; } case (DW2102_VOLTAGE_CTRL): { @@ -1123,6 +1123,7 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) static int ds3000_frontend_attach(struct dvb_usb_adapter *d) { struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; + u8 obuf[] = {7, 1}; d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); @@ -1132,6 +1133,9 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) st->old_set_voltage = d->fe->ops.set_voltage; d->fe->ops.set_voltage = s660_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + info("Attached ds3000+ds2020!\n"); return 0; -- cgit v1.2.2 From e8f5055ac85fb68eeaa335f0dae14b31cc037f6d Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] dw2102: add support for the TeVii S480 PCIe The card consists of a PCI-e to USB Host Controller and two TeVii S660 equivalent cards. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 893149170faa..c5a0921204bd 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1,6 +1,6 @@ /* DVB USB framework compliant Linux driver for the * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, -* TeVii S600, S630, S650, +* TeVii S600, S630, S650, S480 * Prof 1100, 7500, * Geniatech SU3000 Cards * Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by) @@ -56,6 +56,14 @@ #define USB_PID_TEVII_S660 0xd660 #endif +#ifndef USB_PID_TEVII_S480_1 +#define USB_PID_TEVII_S480_1 0xd481 +#endif + +#ifndef USB_PID_TEVII_S480_2 +#define USB_PID_TEVII_S480_2 0xd482 +#endif + #ifndef USB_PID_PROF_1100 #define USB_PID_PROF_1100 0xb012 #endif @@ -1430,6 +1438,8 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(0x3034, 0x7500)}, {USB_DEVICE(0x1f4d, 0x3000)}, {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, { } }; @@ -1748,6 +1758,18 @@ static struct dvb_usb_device_description d660 = { {NULL}, }; +static struct dvb_usb_device_description d480_1 = { + "TeVii S480.1 USB", + {&dw2102_table[12], NULL}, + {NULL}, +}; + +static struct dvb_usb_device_description d480_2 = { + "TeVii S480.2 USB", + {&dw2102_table[13], NULL}, + {NULL}, +}; + struct dvb_usb_device_properties *p7500; static struct dvb_usb_device_description d7500 = { "Prof 7500 USB DVB-S2", @@ -1828,7 +1850,10 @@ static int dw2102_probe(struct usb_interface *intf, memcpy(s660, &s6x0_properties, sizeof(struct dvb_usb_device_properties)); s660->firmware = "dvb-usb-s660.fw"; + s660->num_device_descs = 3; s660->devices[0] = d660; + s660->devices[1] = d480_1; + s660->devices[2] = d480_2; s660->adapter->frontend_attach = ds3000_frontend_attach; p7500 = kzalloc(sizeof(struct dvb_usb_device_properties), GFP_KERNEL); @@ -1893,7 +1918,7 @@ module_exit(dw2102_module_exit); MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," " DVB-C 3101 USB2.0," - " TeVii S600, S630, S650, S660 USB2.0," + " TeVii S600, S630, S650, S660, S480," " Prof 1100, 7500 USB2.0," " Geniatech SU3000 devices"); MODULE_VERSION("0.1"); -- cgit v1.2.2 From 2f30fb49c347e8696a8784c57810b41d185707ec Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] dw2102: Copyright, cards list updated Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index c5a0921204bd..1a1b84c3a53f 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1,16 +1,16 @@ /* DVB USB framework compliant Linux driver for the -* DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, -* TeVii S600, S630, S650, S480 -* Prof 1100, 7500, + * DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101, + * TeVii S600, S630, S650, S660, S480, + * Prof 1100, 7500, * Geniatech SU3000 Cards -* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by) -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation, version 2. -* -* see Documentation/dvb/README.dvb-usb for more information -*/ + * Copyright (C) 2008-2011 Igor M. Liplianin (liplianin@me.by) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ #include "dw2102.h" #include "si21xx.h" #include "stv0299.h" -- cgit v1.2.2 From 18a73f36a2109563beee00f8be3f19f6c1fe2ff6 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:23 -0300 Subject: [media] ds3000: clean up in tune procedure Variable 'retune' does not make sense. Loop is not needed for only one try. Remove unnecessary dprintk's. Remove a lot of debug messages and delays. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 472 ++++++++++++++++------------------- 1 file changed, 213 insertions(+), 259 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 3373890c092e..882be672f5d2 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -536,25 +536,6 @@ static int ds3000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } -static void ds3000_dump_registers(struct dvb_frontend *fe) -{ - struct ds3000_state *state = fe->demodulator_priv; - int x, y, reg = 0, val; - - for (y = 0; y < 16; y++) { - dprintk("%s: %02x: ", __func__, y); - for (x = 0; x < 16; x++) { - reg = (y << 4) + x; - val = ds3000_readreg(state, reg); - if (x != 15) - dprintk("%02x ", val); - else - dprintk("%02x\n", val); - } - } - dprintk("%s: -- DS3000 DUMP DONE --\n", __func__); -} - static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status) { struct ds3000_state *state = fe->demodulator_priv; @@ -589,16 +570,6 @@ static int ds3000_read_status(struct dvb_frontend *fe, fe_status_t* status) return 0; } -#define FE_IS_TUNED (FE_HAS_SIGNAL + FE_HAS_LOCK) -static int ds3000_is_tuned(struct dvb_frontend *fe) -{ - fe_status_t tunerstat; - - ds3000_read_status(fe, &tunerstat); - - return ((tunerstat & FE_IS_TUNED) == FE_IS_TUNED); -} - /* read DS3000 BER value */ static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber) { @@ -1049,7 +1020,7 @@ static int ds3000_tune(struct dvb_frontend *fe, struct ds3000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret = 0, retune, i; + int i; u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf; u16 value, ndiv; u32 f3db; @@ -1072,252 +1043,235 @@ static int ds3000_tune(struct dvb_frontend *fe, /* discard the 'current' tuning parameters and prepare to tune */ ds3000_clone_params(fe); - retune = 1; /* try 1 times */ - dprintk("%s: retune = %d\n", __func__, retune); - dprintk("%s: frequency = %d\n", __func__, state->dcur.frequency); - dprintk("%s: symbol_rate = %d\n", __func__, state->dcur.symbol_rate); - dprintk("%s: FEC = %d \n", __func__, - state->dcur.fec); - dprintk("%s: Inversion = %d\n", __func__, state->dcur.inversion); - - do { - /* Reset status register */ - status = 0; - /* Tune */ - /* unknown */ - ds3000_tuner_writereg(state, 0x07, 0x02); - ds3000_tuner_writereg(state, 0x10, 0x00); - ds3000_tuner_writereg(state, 0x60, 0x79); - ds3000_tuner_writereg(state, 0x08, 0x01); - ds3000_tuner_writereg(state, 0x00, 0x01); - /* calculate and set freq divider */ - if (state->dcur.frequency < 1146000) { - ds3000_tuner_writereg(state, 0x10, 0x11); - ndiv = ((state->dcur.frequency * (6 + 8) * 4) + - (DS3000_XTAL_FREQ / 2)) / - DS3000_XTAL_FREQ - 1024; - } else { - ds3000_tuner_writereg(state, 0x10, 0x01); - ndiv = ((state->dcur.frequency * (6 + 8) * 2) + - (DS3000_XTAL_FREQ / 2)) / - DS3000_XTAL_FREQ - 1024; - } + /* Reset status register */ + status = 0; + /* Tune */ + /* unknown */ + ds3000_tuner_writereg(state, 0x07, 0x02); + ds3000_tuner_writereg(state, 0x10, 0x00); + ds3000_tuner_writereg(state, 0x60, 0x79); + ds3000_tuner_writereg(state, 0x08, 0x01); + ds3000_tuner_writereg(state, 0x00, 0x01); + /* calculate and set freq divider */ + if (state->dcur.frequency < 1146000) { + ds3000_tuner_writereg(state, 0x10, 0x11); + ndiv = ((state->dcur.frequency * (6 + 8) * 4) + + (DS3000_XTAL_FREQ / 2)) / + DS3000_XTAL_FREQ - 1024; + } else { + ds3000_tuner_writereg(state, 0x10, 0x01); + ndiv = ((state->dcur.frequency * (6 + 8) * 2) + + (DS3000_XTAL_FREQ / 2)) / + DS3000_XTAL_FREQ - 1024; + } - ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8); - ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff); - - /* set pll */ - ds3000_tuner_writereg(state, 0x03, 0x06); - ds3000_tuner_writereg(state, 0x51, 0x0f); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x10); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - /* unknown */ - ds3000_tuner_writereg(state, 0x51, 0x17); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x08); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - value = ds3000_tuner_readreg(state, 0x3d); - value &= 0x0f; - if ((value > 4) && (value < 15)) { - value -= 3; - if (value < 4) - value = 4; - value = ((value << 3) | 0x01) & 0x79; - } + ds3000_tuner_writereg(state, 0x01, (ndiv & 0x0f00) >> 8); + ds3000_tuner_writereg(state, 0x02, ndiv & 0x00ff); + + /* set pll */ + ds3000_tuner_writereg(state, 0x03, 0x06); + ds3000_tuner_writereg(state, 0x51, 0x0f); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x10); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + /* unknown */ + ds3000_tuner_writereg(state, 0x51, 0x17); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x08); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + value = ds3000_tuner_readreg(state, 0x3d); + value &= 0x0f; + if ((value > 4) && (value < 15)) { + value -= 3; + if (value < 4) + value = 4; + value = ((value << 3) | 0x01) & 0x79; + } - ds3000_tuner_writereg(state, 0x60, value); - ds3000_tuner_writereg(state, 0x51, 0x17); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x08); - ds3000_tuner_writereg(state, 0x50, 0x00); - - /* set low-pass filter period */ - ds3000_tuner_writereg(state, 0x04, 0x2e); - ds3000_tuner_writereg(state, 0x51, 0x1b); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x04); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - f3db = ((state->dcur.symbol_rate / 1000) << 2) / 5 + 2000; - if ((state->dcur.symbol_rate / 1000) < 5000) - f3db += 3000; - if (f3db < 7000) - f3db = 7000; - if (f3db > 40000) - f3db = 40000; - - /* set low-pass filter baseband */ - value = ds3000_tuner_readreg(state, 0x26); - mlpf = 0x2e * 207 / ((value << 1) + 151); - mlpf_max = mlpf * 135 / 100; - mlpf_min = mlpf * 78 / 100; - if (mlpf_max > 63) - mlpf_max = 63; - - /* rounded to the closest integer */ - nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2)) - / (2766 * DS3000_XTAL_FREQ); - if (nlpf > 23) - nlpf = 23; - if (nlpf < 1) - nlpf = 1; - - /* rounded to the closest integer */ + ds3000_tuner_writereg(state, 0x60, value); + ds3000_tuner_writereg(state, 0x51, 0x17); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x08); + ds3000_tuner_writereg(state, 0x50, 0x00); + + /* set low-pass filter period */ + ds3000_tuner_writereg(state, 0x04, 0x2e); + ds3000_tuner_writereg(state, 0x51, 0x1b); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x04); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + f3db = ((state->dcur.symbol_rate / 1000) << 2) / 5 + 2000; + if ((state->dcur.symbol_rate / 1000) < 5000) + f3db += 3000; + if (f3db < 7000) + f3db = 7000; + if (f3db > 40000) + f3db = 40000; + + /* set low-pass filter baseband */ + value = ds3000_tuner_readreg(state, 0x26); + mlpf = 0x2e * 207 / ((value << 1) + 151); + mlpf_max = mlpf * 135 / 100; + mlpf_min = mlpf * 78 / 100; + if (mlpf_max > 63) + mlpf_max = 63; + + /* rounded to the closest integer */ + nlpf = ((mlpf * f3db * 1000) + (2766 * DS3000_XTAL_FREQ / 2)) + / (2766 * DS3000_XTAL_FREQ); + if (nlpf > 23) + nlpf = 23; + if (nlpf < 1) + nlpf = 1; + + /* rounded to the closest integer */ + mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) + + (1000 * f3db / 2)) / (1000 * f3db); + + if (mlpf_new < mlpf_min) { + nlpf++; mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) + (1000 * f3db / 2)) / (1000 * f3db); + } - if (mlpf_new < mlpf_min) { - nlpf++; - mlpf_new = ((DS3000_XTAL_FREQ * nlpf * 2766) + - (1000 * f3db / 2)) / (1000 * f3db); - } + if (mlpf_new > mlpf_max) + mlpf_new = mlpf_max; + + ds3000_tuner_writereg(state, 0x04, mlpf_new); + ds3000_tuner_writereg(state, 0x06, nlpf); + ds3000_tuner_writereg(state, 0x51, 0x1b); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x04); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(5); + + /* unknown */ + ds3000_tuner_writereg(state, 0x51, 0x1e); + ds3000_tuner_writereg(state, 0x51, 0x1f); + ds3000_tuner_writereg(state, 0x50, 0x01); + ds3000_tuner_writereg(state, 0x50, 0x00); + msleep(60); + + /* ds3000 global reset */ + ds3000_writereg(state, 0x07, 0x80); + ds3000_writereg(state, 0x07, 0x00); + /* ds3000 build-in uC reset */ + ds3000_writereg(state, 0xb2, 0x01); + /* ds3000 software reset */ + ds3000_writereg(state, 0x00, 0x01); - if (mlpf_new > mlpf_max) - mlpf_new = mlpf_max; - - ds3000_tuner_writereg(state, 0x04, mlpf_new); - ds3000_tuner_writereg(state, 0x06, nlpf); - ds3000_tuner_writereg(state, 0x51, 0x1b); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x04); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(5); - - /* unknown */ - ds3000_tuner_writereg(state, 0x51, 0x1e); - ds3000_tuner_writereg(state, 0x51, 0x1f); - ds3000_tuner_writereg(state, 0x50, 0x01); - ds3000_tuner_writereg(state, 0x50, 0x00); - msleep(60); - - /* ds3000 global reset */ - ds3000_writereg(state, 0x07, 0x80); - ds3000_writereg(state, 0x07, 0x00); - /* ds3000 build-in uC reset */ - ds3000_writereg(state, 0xb2, 0x01); - /* ds3000 software reset */ - ds3000_writereg(state, 0x00, 0x01); + switch (c->delivery_system) { + case SYS_DVBS: + /* initialise the demod in DVB-S mode */ + for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2) + ds3000_writereg(state, + ds3000_dvbs_init_tab[i], + ds3000_dvbs_init_tab[i + 1]); + value = ds3000_readreg(state, 0xfe); + value &= 0xc0; + value |= 0x1b; + ds3000_writereg(state, 0xfe, value); + break; + case SYS_DVBS2: + /* initialise the demod in DVB-S2 mode */ + for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2) + ds3000_writereg(state, + ds3000_dvbs2_init_tab[i], + ds3000_dvbs2_init_tab[i + 1]); + ds3000_writereg(state, 0xfe, 0x98); + break; + default: + return 1; + } + + /* enable 27MHz clock output */ + ds3000_writereg(state, 0x29, 0x80); + /* enable ac coupling */ + ds3000_writereg(state, 0x25, 0x8a); + + /* enhance symbol rate performance */ + if ((state->dcur.symbol_rate / 1000) <= 5000) { + value = 29777 / (state->dcur.symbol_rate / 1000) + 1; + if (value % 2 != 0) + value++; + ds3000_writereg(state, 0xc3, 0x0d); + ds3000_writereg(state, 0xc8, value); + ds3000_writereg(state, 0xc4, 0x10); + ds3000_writereg(state, 0xc7, 0x0e); + } else if ((state->dcur.symbol_rate / 1000) <= 10000) { + value = 92166 / (state->dcur.symbol_rate / 1000) + 1; + if (value % 2 != 0) + value++; + ds3000_writereg(state, 0xc3, 0x07); + ds3000_writereg(state, 0xc8, value); + ds3000_writereg(state, 0xc4, 0x09); + ds3000_writereg(state, 0xc7, 0x12); + } else if ((state->dcur.symbol_rate / 1000) <= 20000) { + value = 64516 / (state->dcur.symbol_rate / 1000) + 1; + ds3000_writereg(state, 0xc3, value); + ds3000_writereg(state, 0xc8, 0x0e); + ds3000_writereg(state, 0xc4, 0x07); + ds3000_writereg(state, 0xc7, 0x18); + } else { + value = 129032 / (state->dcur.symbol_rate / 1000) + 1; + ds3000_writereg(state, 0xc3, value); + ds3000_writereg(state, 0xc8, 0x0a); + ds3000_writereg(state, 0xc4, 0x05); + ds3000_writereg(state, 0xc7, 0x24); + } + + /* normalized symbol rate rounded to the closest integer */ + value = (((state->dcur.symbol_rate / 1000) << 16) + + (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE; + ds3000_writereg(state, 0x61, value & 0x00ff); + ds3000_writereg(state, 0x62, (value & 0xff00) >> 8); + + /* co-channel interference cancellation disabled */ + ds3000_writereg(state, 0x56, 0x00); + + /* equalizer disabled */ + ds3000_writereg(state, 0x76, 0x00); + /*ds3000_writereg(state, 0x08, 0x03); + ds3000_writereg(state, 0xfd, 0x22); + ds3000_writereg(state, 0x08, 0x07); + ds3000_writereg(state, 0xfd, 0x42); + ds3000_writereg(state, 0x08, 0x07);*/ + + if (state->config->ci_mode) { switch (c->delivery_system) { case SYS_DVBS: - /* initialise the demod in DVB-S mode */ - for (i = 0; i < sizeof(ds3000_dvbs_init_tab); i += 2) - ds3000_writereg(state, - ds3000_dvbs_init_tab[i], - ds3000_dvbs_init_tab[i + 1]); - value = ds3000_readreg(state, 0xfe); - value &= 0xc0; - value |= 0x1b; - ds3000_writereg(state, 0xfe, value); - break; + default: + ds3000_writereg(state, 0xfd, 0x80); + break; case SYS_DVBS2: - /* initialise the demod in DVB-S2 mode */ - for (i = 0; i < sizeof(ds3000_dvbs2_init_tab); i += 2) - ds3000_writereg(state, - ds3000_dvbs2_init_tab[i], - ds3000_dvbs2_init_tab[i + 1]); - ds3000_writereg(state, 0xfe, 0x98); + ds3000_writereg(state, 0xfd, 0x01); break; - default: - return 1; - } - - /* enable 27MHz clock output */ - ds3000_writereg(state, 0x29, 0x80); - /* enable ac coupling */ - ds3000_writereg(state, 0x25, 0x8a); - - /* enhance symbol rate performance */ - if ((state->dcur.symbol_rate / 1000) <= 5000) { - value = 29777 / (state->dcur.symbol_rate / 1000) + 1; - if (value % 2 != 0) - value++; - ds3000_writereg(state, 0xc3, 0x0d); - ds3000_writereg(state, 0xc8, value); - ds3000_writereg(state, 0xc4, 0x10); - ds3000_writereg(state, 0xc7, 0x0e); - } else if ((state->dcur.symbol_rate / 1000) <= 10000) { - value = 92166 / (state->dcur.symbol_rate / 1000) + 1; - if (value % 2 != 0) - value++; - ds3000_writereg(state, 0xc3, 0x07); - ds3000_writereg(state, 0xc8, value); - ds3000_writereg(state, 0xc4, 0x09); - ds3000_writereg(state, 0xc7, 0x12); - } else if ((state->dcur.symbol_rate / 1000) <= 20000) { - value = 64516 / (state->dcur.symbol_rate / 1000) + 1; - ds3000_writereg(state, 0xc3, value); - ds3000_writereg(state, 0xc8, 0x0e); - ds3000_writereg(state, 0xc4, 0x07); - ds3000_writereg(state, 0xc7, 0x18); - } else { - value = 129032 / (state->dcur.symbol_rate / 1000) + 1; - ds3000_writereg(state, 0xc3, value); - ds3000_writereg(state, 0xc8, 0x0a); - ds3000_writereg(state, 0xc4, 0x05); - ds3000_writereg(state, 0xc7, 0x24); } + } - /* normalized symbol rate rounded to the closest integer */ - value = (((state->dcur.symbol_rate / 1000) << 16) + - (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE; - ds3000_writereg(state, 0x61, value & 0x00ff); - ds3000_writereg(state, 0x62, (value & 0xff00) >> 8); - - /* co-channel interference cancellation disabled */ - ds3000_writereg(state, 0x56, 0x00); - - /* equalizer disabled */ - ds3000_writereg(state, 0x76, 0x00); - - /*ds3000_writereg(state, 0x08, 0x03); - ds3000_writereg(state, 0xfd, 0x22); - ds3000_writereg(state, 0x08, 0x07); - ds3000_writereg(state, 0xfd, 0x42); - ds3000_writereg(state, 0x08, 0x07);*/ - - if (state->config->ci_mode) { - switch (c->delivery_system) { - case SYS_DVBS: - default: - ds3000_writereg(state, 0xfd, 0x80); - break; - case SYS_DVBS2: - ds3000_writereg(state, 0xfd, 0x01); - break; - } - } + /* ds3000 out of software reset */ + ds3000_writereg(state, 0x00, 0x00); + /* start ds3000 build-in uC */ + ds3000_writereg(state, 0xb2, 0x00); - /* ds3000 out of software reset */ - ds3000_writereg(state, 0x00, 0x00); - /* start ds3000 build-in uC */ - ds3000_writereg(state, 0xb2, 0x00); - - /* TODO: calculate and set carrier offset */ - - /* wait before retrying */ - for (i = 0; i < 30 ; i++) { - if (ds3000_is_tuned(fe)) { - dprintk("%s: Tuned\n", __func__); - ds3000_dump_registers(fe); - goto tuned; - } - msleep(1); - } + /* TODO: calculate and set carrier offset */ - dprintk("%s: Not tuned\n", __func__); - ds3000_dump_registers(fe); + for (i = 0; i < 30 ; i++) { + ds3000_read_status(fe, &status); + if (status && FE_HAS_LOCK) + break; - } while (--retune); + msleep(10); + } -tuned: - return ret; + return 0; } static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe) -- cgit v1.2.2 From cb8f74da107cf593eb50ac4968faaa5f49fbad4a Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:24 -0300 Subject: [media] ds3000: remove unnecessary dnxt, dcur structures All necessary parameters already stored in frontend cache. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 108 +++++------------------------------ 1 file changed, 13 insertions(+), 95 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 882be672f5d2..13f9193d4f4a 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -229,31 +229,11 @@ static u8 ds3000_dvbs2_init_tab[] = { 0xb8, 0x00, }; -/* DS3000 doesn't need some parameters as input and auto-detects them */ -/* save input from the application of those parameters */ -struct ds3000_tuning { - u32 frequency; - u32 symbol_rate; - fe_spectral_inversion_t inversion; - enum fe_code_rate fec; - - /* input values */ - u8 inversion_val; - fe_modulation_t delivery; - u8 rolloff; -}; - struct ds3000_state { struct i2c_adapter *i2c; const struct ds3000_config *config; - struct dvb_frontend frontend; - - struct ds3000_tuning dcur; - struct ds3000_tuning dnxt; - u8 skip_fw_load; - /* previous uncorrected block counter for DVB-S2 */ u16 prevUCBS2; }; @@ -401,45 +381,6 @@ static int ds3000_tuner_readreg(struct ds3000_state *state, u8 reg) return b1[0]; } -static int ds3000_set_inversion(struct ds3000_state *state, - fe_spectral_inversion_t inversion) -{ - dprintk("%s(%d)\n", __func__, inversion); - - switch (inversion) { - case INVERSION_OFF: - case INVERSION_ON: - case INVERSION_AUTO: - break; - default: - return -EINVAL; - } - - state->dnxt.inversion = inversion; - - return 0; -} - -static int ds3000_set_symbolrate(struct ds3000_state *state, u32 rate) -{ - int ret = 0; - - dprintk("%s()\n", __func__); - - dprintk("%s() symbol_rate = %d\n", __func__, state->dnxt.symbol_rate); - - /* check if symbol rate is within limits */ - if ((state->dnxt.symbol_rate > - state->frontend.ops.info.symbol_rate_max) || - (state->dnxt.symbol_rate < - state->frontend.ops.info.symbol_rate_min)) - ret = -EOPNOTSUPP; - - state->dnxt.symbol_rate = rate; - - return ret; -} - static int ds3000_load_firmware(struct dvb_frontend *fe, const struct firmware *fw); @@ -790,13 +731,6 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -/* Overwrite the current tuning params, we are about to tune */ -static void ds3000_clone_params(struct dvb_frontend *fe) -{ - struct ds3000_state *state = fe->demodulator_priv; - memcpy(&state->dcur, &state->dnxt, sizeof(state->dcur)); -} - static int ds3000_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) { struct ds3000_state *state = fe->demodulator_priv; @@ -1027,22 +961,6 @@ static int ds3000_tune(struct dvb_frontend *fe, dprintk("%s() ", __func__); - state->dnxt.delivery = c->modulation; - state->dnxt.frequency = c->frequency; - state->dnxt.rolloff = 2; /* fixme */ - state->dnxt.fec = c->fec_inner; - - ret = ds3000_set_inversion(state, p->inversion); - if (ret != 0) - return ret; - - ret = ds3000_set_symbolrate(state, c->symbol_rate); - if (ret != 0) - return ret; - - /* discard the 'current' tuning parameters and prepare to tune */ - ds3000_clone_params(fe); - /* Reset status register */ status = 0; /* Tune */ @@ -1053,14 +971,14 @@ static int ds3000_tune(struct dvb_frontend *fe, ds3000_tuner_writereg(state, 0x08, 0x01); ds3000_tuner_writereg(state, 0x00, 0x01); /* calculate and set freq divider */ - if (state->dcur.frequency < 1146000) { + if (p->frequency < 1146000) { ds3000_tuner_writereg(state, 0x10, 0x11); - ndiv = ((state->dcur.frequency * (6 + 8) * 4) + + ndiv = ((p->frequency * (6 + 8) * 4) + (DS3000_XTAL_FREQ / 2)) / DS3000_XTAL_FREQ - 1024; } else { ds3000_tuner_writereg(state, 0x10, 0x01); - ndiv = ((state->dcur.frequency * (6 + 8) * 2) + + ndiv = ((p->frequency * (6 + 8) * 2) + (DS3000_XTAL_FREQ / 2)) / DS3000_XTAL_FREQ - 1024; } @@ -1106,8 +1024,8 @@ static int ds3000_tune(struct dvb_frontend *fe, ds3000_tuner_writereg(state, 0x50, 0x00); msleep(5); - f3db = ((state->dcur.symbol_rate / 1000) << 2) / 5 + 2000; - if ((state->dcur.symbol_rate / 1000) < 5000) + f3db = ((c->symbol_rate / 1000) << 2) / 5 + 2000; + if ((c->symbol_rate / 1000) < 5000) f3db += 3000; if (f3db < 7000) f3db = 7000; @@ -1196,30 +1114,30 @@ static int ds3000_tune(struct dvb_frontend *fe, ds3000_writereg(state, 0x25, 0x8a); /* enhance symbol rate performance */ - if ((state->dcur.symbol_rate / 1000) <= 5000) { - value = 29777 / (state->dcur.symbol_rate / 1000) + 1; + if ((c->symbol_rate / 1000) <= 5000) { + value = 29777 / (c->symbol_rate / 1000) + 1; if (value % 2 != 0) value++; ds3000_writereg(state, 0xc3, 0x0d); ds3000_writereg(state, 0xc8, value); ds3000_writereg(state, 0xc4, 0x10); ds3000_writereg(state, 0xc7, 0x0e); - } else if ((state->dcur.symbol_rate / 1000) <= 10000) { - value = 92166 / (state->dcur.symbol_rate / 1000) + 1; + } else if ((c->symbol_rate / 1000) <= 10000) { + value = 92166 / (c->symbol_rate / 1000) + 1; if (value % 2 != 0) value++; ds3000_writereg(state, 0xc3, 0x07); ds3000_writereg(state, 0xc8, value); ds3000_writereg(state, 0xc4, 0x09); ds3000_writereg(state, 0xc7, 0x12); - } else if ((state->dcur.symbol_rate / 1000) <= 20000) { - value = 64516 / (state->dcur.symbol_rate / 1000) + 1; + } else if ((c->symbol_rate / 1000) <= 20000) { + value = 64516 / (c->symbol_rate / 1000) + 1; ds3000_writereg(state, 0xc3, value); ds3000_writereg(state, 0xc8, 0x0e); ds3000_writereg(state, 0xc4, 0x07); ds3000_writereg(state, 0xc7, 0x18); } else { - value = 129032 / (state->dcur.symbol_rate / 1000) + 1; + value = 129032 / (c->symbol_rate / 1000) + 1; ds3000_writereg(state, 0xc3, value); ds3000_writereg(state, 0xc8, 0x0a); ds3000_writereg(state, 0xc4, 0x05); @@ -1227,7 +1145,7 @@ static int ds3000_tune(struct dvb_frontend *fe, } /* normalized symbol rate rounded to the closest integer */ - value = (((state->dcur.symbol_rate / 1000) << 16) + + value = (((c->symbol_rate / 1000) << 16) + (DS3000_SAMPLE_RATE / 2)) / DS3000_SAMPLE_RATE; ds3000_writereg(state, 0x61, value & 0x00ff); ds3000_writereg(state, 0x62, (value & 0xff00) >> 8); -- cgit v1.2.2 From a5bf834b4a29b0c7f813ce1c456563c470d4181f Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:24 -0300 Subject: [media] ds3000: add carrier offset calculation Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 13f9193d4f4a..a0bf70f0d044 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -948,6 +948,25 @@ static int ds3000_get_property(struct dvb_frontend *fe, return 0; } +static int ds3000_set_carrier_offset(struct dvb_frontend *fe, + s32 carrier_offset_khz) +{ + struct ds3000_state *state = fe->demodulator_priv; + s32 tmp; + + tmp = carrier_offset_khz; + tmp *= 65536; + tmp = (2 * tmp + DS3000_SAMPLE_RATE) / (2 * DS3000_SAMPLE_RATE); + + if (tmp < 0) + tmp += 65536; + + ds3000_writereg(state, 0x5f, tmp >> 8); + ds3000_writereg(state, 0x5e, tmp & 0xff); + + return 0; +} + static int ds3000_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { @@ -955,7 +974,8 @@ static int ds3000_tune(struct dvb_frontend *fe, struct dtv_frontend_properties *c = &fe->dtv_property_cache; int i; - u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf; + u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4; + s32 offset_khz; u16 value, ndiv; u32 f3db; @@ -970,9 +990,12 @@ static int ds3000_tune(struct dvb_frontend *fe, ds3000_tuner_writereg(state, 0x60, 0x79); ds3000_tuner_writereg(state, 0x08, 0x01); ds3000_tuner_writereg(state, 0x00, 0x01); + div4 = 0; + /* calculate and set freq divider */ if (p->frequency < 1146000) { ds3000_tuner_writereg(state, 0x10, 0x11); + div4 = 1; ndiv = ((p->frequency * (6 + 8) * 4) + (DS3000_XTAL_FREQ / 2)) / DS3000_XTAL_FREQ - 1024; @@ -1076,6 +1099,9 @@ static int ds3000_tune(struct dvb_frontend *fe, ds3000_tuner_writereg(state, 0x50, 0x00); msleep(60); + offset_khz = (ndiv - ndiv % 2 + 1024) * DS3000_XTAL_FREQ + / (6 + 8) / (div4 + 1) / 2 - p->frequency; + /* ds3000 global reset */ ds3000_writereg(state, 0x07, 0x80); ds3000_writereg(state, 0x07, 0x00); @@ -1179,7 +1205,7 @@ static int ds3000_tune(struct dvb_frontend *fe, /* start ds3000 build-in uC */ ds3000_writereg(state, 0xb2, 0x00); - /* TODO: calculate and set carrier offset */ + ds3000_set_carrier_offset(fe, offset_khz); for (i = 0; i < 30 ; i++) { ds3000_read_status(fe, &status); -- cgit v1.2.2 From dcc8a122230b1c65ee8ba83536fd53fcaf27884d Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:24 -0300 Subject: [media] ds3000: hardware tune algorithm Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index a0bf70f0d044..2ae569989655 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -967,22 +967,21 @@ static int ds3000_set_carrier_offset(struct dvb_frontend *fe, return 0; } -static int ds3000_tune(struct dvb_frontend *fe, +static int ds3000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct ds3000_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int i; - u8 status, mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4; + fe_status_t status; + u8 mlpf, mlpf_new, mlpf_max, mlpf_min, nlpf, div4; s32 offset_khz; u16 value, ndiv; u32 f3db; dprintk("%s() ", __func__); - /* Reset status register */ - status = 0; /* Tune */ /* unknown */ ds3000_tuner_writereg(state, 0x07, 0x02); @@ -1218,10 +1217,16 @@ static int ds3000_tune(struct dvb_frontend *fe, return 0; } +static int ds3000_tune(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + return ds3000_set_frontend(fe, p); +} + static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe) { dprintk("%s()\n", __func__); - return DVBFE_ALGO_SW; + return DVBFE_ALGO_HW; } /* @@ -1296,7 +1301,8 @@ static struct dvb_frontend_ops ds3000_ops = { .set_property = ds3000_set_property, .get_property = ds3000_get_property, - .set_frontend = ds3000_tune, + .set_frontend = ds3000_set_frontend, + .tune = ds3000_tune, }; module_param(debug, int, 0644); -- cgit v1.2.2 From 0cb73639cfbdc9a074cbb7737d173f7a7381036d Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Fri, 25 Feb 2011 18:41:24 -0300 Subject: [media] cx88: add support for TeVii S464 PCI card The card uses ds3000 demod from Montage. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 2 ++ drivers/media/dvb/frontends/ds3000.h | 2 ++ drivers/media/video/cx88/cx88-cards.c | 17 +++++++++++++++++ drivers/media/video/cx88/cx88-dvb.c | 23 +++++++++++++++++++++++ drivers/media/video/cx88/cx88-input.c | 1 + drivers/media/video/cx88/cx88.h | 1 + 6 files changed, 46 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 2ae569989655..7f3d118287c4 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -982,6 +982,8 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, dprintk("%s() ", __func__); + if (state->config->set_ts_params) + state->config->set_ts_params(fe, 0); /* Tune */ /* unknown */ ds3000_tuner_writereg(state, 0x07, 0x02); diff --git a/drivers/media/dvb/frontends/ds3000.h b/drivers/media/dvb/frontends/ds3000.h index 00e4e95590e9..1b736888ea37 100644 --- a/drivers/media/dvb/frontends/ds3000.h +++ b/drivers/media/dvb/frontends/ds3000.h @@ -28,6 +28,8 @@ struct ds3000_config { /* the demodulator's i2c address */ u8 demod_address; u8 ci_mode; + /* Set device param to start dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); }; #if defined(CONFIG_DVB_DS3000) || \ diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index f735262f4767..27222c92b603 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1953,6 +1953,18 @@ static const struct cx88_board cx88_boards[] = { } }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_TEVII_S464] = { + .name = "TeVii S464 DVB-S/S2", + .tuner_type = UNSET, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_DVB, + .vmux = 0, + } }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_OMICOM_SS4_PCI] = { .name = "Omicom SS4 DVB-S/S2 PCI", .tuner_type = UNSET, @@ -2528,6 +2540,10 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0xd460, .subdevice = 0x9022, .card = CX88_BOARD_TEVII_S460, + }, { + .subvendor = 0xd464, + .subdevice = 0x9022, + .card = CX88_BOARD_TEVII_S464, }, { .subvendor = 0xA044, .subdevice = 0x2011, @@ -3286,6 +3302,7 @@ static void cx88_card_setup(struct cx88_core *core) } case CX88_BOARD_TEVII_S420: case CX88_BOARD_TEVII_S460: + case CX88_BOARD_TEVII_S464: case CX88_BOARD_OMICOM_SS4_PCI: case CX88_BOARD_TBS_8910: case CX88_BOARD_TBS_8920: diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 90717ee944ec..7b8c9d3b6efc 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -57,6 +57,7 @@ #include "stb6100.h" #include "stb6100_proc.h" #include "mb86a16.h" +#include "ds3000.h" MODULE_DESCRIPTION("driver for cx2388x based DVB cards"); MODULE_AUTHOR("Chris Pascoe "); @@ -648,6 +649,20 @@ static const struct cx24116_config tevii_s460_config = { .reset_device = cx24116_reset_device, }; +static int ds3000_set_ts_param(struct dvb_frontend *fe, + int is_punctured) +{ + struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 4; + + return 0; +} + +static struct ds3000_config tevii_ds3000_config = { + .demod_address = 0x68, + .set_ts_params = ds3000_set_ts_param, +}; + static const struct stv0900_config prof_7301_stv0900_config = { .demod_address = 0x6a, /* demod_mode = 0,*/ @@ -1381,6 +1396,14 @@ static int dvb_register(struct cx8802_dev *dev) if (fe0->dvb.frontend != NULL) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; break; + case CX88_BOARD_TEVII_S464: + fe0->dvb.frontend = dvb_attach(ds3000_attach, + &tevii_ds3000_config, + &core->i2c_adap); + if (fe0->dvb.frontend != NULL) + fe0->dvb.frontend->ops.set_voltage = + tevii_dvbs_set_voltage; + break; case CX88_BOARD_OMICOM_SS4_PCI: case CX88_BOARD_TBS_8920: case CX88_BOARD_PROF_7300: diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 06f7d1d00944..fbfbba5bec5e 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -373,6 +373,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir_codes = RC_MAP_TBS_NEC; ir->sampling = 0xff00; /* address */ break; + case CX88_BOARD_TEVII_S464: case CX88_BOARD_TEVII_S460: case CX88_BOARD_TEVII_S420: ir_codes = RC_MAP_TEVII_NEC; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index aaf7d12b77db..9b3742a7746c 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -241,6 +241,7 @@ extern const struct sram_channel const cx88_sram_channels[]; #define CX88_BOARD_PROF_7301 83 #define CX88_BOARD_SAMSUNG_SMT_7020 84 #define CX88_BOARD_TWINHAN_VP1027_DVBS 85 +#define CX88_BOARD_TEVII_S464 86 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.2 From 793e71b667856ed6163ad0dc7de1f453e9385590 Mon Sep 17 00:00:00 2001 From: Paul Cassella Date: Tue, 8 Feb 2011 22:22:52 -0300 Subject: [media] ivtv: udma: handle get_user_pages() returning fewer pages than we asked for get_user_pages() may return fewer page than we ask for. As we give up and return an error in this case, we need to put_page() each of the pages we did get. [Andy Walls modified the patch, only removing the braces in the 'for' statement, to eliminate a checkpatch warning.] Signed-off-by: Paul Cassella Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-udma.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c index 1daf1dd65bf7..69cc8166b20b 100644 --- a/drivers/media/video/ivtv/ivtv-udma.c +++ b/drivers/media/video/ivtv/ivtv-udma.c @@ -132,7 +132,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, if (user_dma.page_count != err) { IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", err, user_dma.page_count); - return -EINVAL; + if (err >= 0) { + for (i = 0; i < err; i++) + put_page(dma->map[i]); + return -EINVAL; + } + return err; } dma->page_count = user_dma.page_count; -- cgit v1.2.2 From 0d44b1235c60bf3134f5730ebb4a115f857a2da4 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Tue, 8 Feb 2011 22:39:28 -0300 Subject: [media] ivtv: Fix sparse warning regarding a user pointer in ivtv_write_vbi_from_user() Fix the first, botched attempt at preventing direct use of a user pointer in ivtv_write_vbi(). Reported-by: Dr. David Alan Gilbert Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-vbi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c index 2dfa957b0fd5..b6eb51ce7735 100644 --- a/drivers/media/video/ivtv/ivtv-vbi.c +++ b/drivers/media/video/ivtv/ivtv-vbi.c @@ -174,7 +174,7 @@ ivtv_write_vbi_from_user(struct ivtv *itv, ret = -EFAULT; break; } - ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc); + ivtv_write_vbi_line(itv, &d, &cc, &found_cc); } if (found_cc) -- cgit v1.2.2 From 7fd4b41f053681cccf188cc1731ae43fe38fa969 Mon Sep 17 00:00:00 2001 From: Paul Cassella Date: Sat, 12 Feb 2011 10:39:51 -0300 Subject: [media] ivtv: yuv: handle get_user_pages() -errno returns get_user_pages() may return -errno, such as -EFAULT. So don't blindly use its return value as an offset into dma->map[] for the next get_user_pages() call. Since we'll give up and return an error if either fails, don't even make the second call if the first failed to give us exactly what we were looking for. The old code would also call put_page() on as many elements of dma->map[] as we'd asked for, regardless of how many were valid. [Andy Walls modified this patch to return -EFAULT instead of -EINVAL as Paul's observation "I'm not sure -EINVAL is the best return code vs -EFAULT or -ENOMEM, [...]" was correct. The return value bubbles up as a return code for write(), for which the V4L2 API spec indicates EINVAL is incorrect and EFAULT is correct.] Signed-off-by: Paul Cassella Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-yuv.c | 52 ++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index c0875378acc2..dcbab6ad4c26 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -77,23 +77,51 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* Get user pages for DMA Xfer */ down_read(¤t->mm->mmap_sem); y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL); - uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL); + uv_pages = 0; /* silence gcc. value is set and consumed only if: */ + if (y_pages == y_dma.page_count) { + uv_pages = get_user_pages(current, current->mm, + uv_dma.uaddr, uv_dma.page_count, 0, 1, + &dma->map[y_pages], NULL); + } up_read(¤t->mm->mmap_sem); - dma->page_count = y_dma.page_count + uv_dma.page_count; - - if (y_pages + uv_pages != dma->page_count) { - IVTV_DEBUG_WARN - ("failed to map user pages, returned %d instead of %d\n", - y_pages + uv_pages, dma->page_count); - - for (i = 0; i < dma->page_count; i++) { - put_page(dma->map[i]); + if (y_pages != y_dma.page_count || uv_pages != uv_dma.page_count) { + int rc = -EFAULT; + + if (y_pages == y_dma.page_count) { + IVTV_DEBUG_WARN + ("failed to map uv user pages, returned %d " + "expecting %d\n", uv_pages, uv_dma.page_count); + + if (uv_pages >= 0) { + for (i = 0; i < uv_pages; i++) + put_page(dma->map[y_pages + i]); + rc = -EFAULT; + } else { + rc = uv_pages; + } + } else { + IVTV_DEBUG_WARN + ("failed to map y user pages, returned %d " + "expecting %d\n", y_pages, y_dma.page_count); } - dma->page_count = 0; - return -EINVAL; + if (y_pages >= 0) { + for (i = 0; i < y_pages; i++) + put_page(dma->map[i]); + /* + * Inherit the -EFAULT from rc's + * initialization, but allow it to be + * overriden by uv_pages above if it was an + * actual errno. + */ + } else { + rc = y_pages; + } + return rc; } + dma->page_count = y_pages + uv_pages; + /* Fill & map SG List */ if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) { IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n"); -- cgit v1.2.2 From 8d19824ba2ef37ff989bee5941c87b45c4c6f468 Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Tue, 11 Jan 2011 06:33:18 -0300 Subject: [media] drivers:media:radio: wl128x: FM Driver common header file These are common headers used in FM submodules (FM V4L2, FM common, FM Rx,and FM TX). Signed-off-by: Manjunatha Halli Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv.h | 244 +++++++++++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 drivers/media/radio/wl128x/fmdrv.h (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h new file mode 100644 index 000000000000..5db6fd14cf3c --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv.h @@ -0,0 +1,244 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * + * Common header for all FM driver sub-modules. + * + * Copyright (C) 2011 Texas Instruments + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _FM_DRV_H +#define _FM_DRV_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FM_DRV_VERSION "0.10" +/* Should match with FM_DRV_VERSION */ +#define FM_DRV_RADIO_VERSION KERNEL_VERSION(0, 0, 1) +#define FM_DRV_NAME "ti_fmdrv" +#define FM_DRV_CARD_SHORT_NAME "TI FM Radio" +#define FM_DRV_CARD_LONG_NAME "Texas Instruments FM Radio" + +/* Flag info */ +#define FM_INTTASK_RUNNING 0 +#define FM_INTTASK_SCHEDULE_PENDING 1 +#define FM_FW_DW_INPROGRESS 2 +#define FM_CORE_READY 3 +#define FM_CORE_TRANSPORT_READY 4 +#define FM_AF_SWITCH_INPROGRESS 5 +#define FM_CORE_TX_XMITING 6 + +#define FM_TUNE_COMPLETE 0x1 +#define FM_BAND_LIMIT 0x2 + +#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */ +#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */ + +#define NO_OF_ENTRIES_IN_ARRAY(array) (sizeof(array) / sizeof(array[0])) + +#define fmerr(format, ...) \ + printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__) +#define fmwarn(format, ...) \ + printk(KERN_WARNING "fmdrv: " format, ##__VA_ARGS__) +#ifdef DEBUG +#define fmdbg(format, ...) \ + printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__) +#else /* DEBUG */ +#define fmdbg(format, ...) +#endif +enum { + FM_MODE_OFF, + FM_MODE_TX, + FM_MODE_RX, + FM_MODE_ENTRY_MAX +}; + +#define FM_RX_RDS_INFO_FIELD_MAX 8 /* 4 Group * 2 Bytes */ + +/* RX RDS data format */ +struct fm_rdsdata_format { + union { + struct { + u8 buff[FM_RX_RDS_INFO_FIELD_MAX]; + } groupdatabuff; + struct { + u16 pidata; + u8 blk_b[2]; + u8 blk_c[2]; + u8 blk_d[2]; + } groupgeneral; + struct { + u16 pidata; + u8 blk_b[2]; + u8 af[2]; + u8 ps[2]; + } group0A; + struct { + u16 pi[2]; + u8 blk_b[2]; + u8 ps[2]; + } group0B; + } data; +}; + +/* FM region (Europe/US, Japan) info */ +struct region_info { + u32 chanl_space; + u32 bot_freq; + u32 top_freq; + u8 fm_band; +}; +struct fmdev; +typedef void (*int_handler_prototype) (struct fmdev *); + +/* FM Interrupt processing related info */ +struct fm_irq { + u8 stage; + u16 flag; /* FM interrupt flag */ + u16 mask; /* FM interrupt mask */ + /* Interrupt process timeout handler */ + struct timer_list timer; + u8 retry; + int_handler_prototype *handlers; +}; + +/* RDS info */ +struct fm_rds { + u8 flag; /* RX RDS on/off status */ + u8 last_blk_idx; /* Last received RDS block */ + + /* RDS buffer */ + wait_queue_head_t read_queue; + u32 buf_size; /* Size is always multiple of 3 */ + u32 wr_idx; + u32 rd_idx; + u8 *buff; +}; + +#define FM_RDS_MAX_AF_LIST 25 + +/* + * Current RX channel Alternate Frequency cache. + * This info is used to switch to other freq (AF) + * when current channel signal strengh is below RSSI threshold. + */ +struct tuned_station_info { + u16 picode; + u32 af_cache[FM_RDS_MAX_AF_LIST]; + u8 afcache_size; + u8 af_list_max; +}; + +/* FM RX mode info */ +struct fm_rx { + struct region_info region; /* Current selected band */ + u32 freq; /* Current RX frquency */ + u8 mute_mode; /* Current mute mode */ + u8 deemphasis_mode; /* Current deemphasis mode */ + /* RF dependent soft mute mode */ + u8 rf_depend_mute; + u16 volume; /* Current volume level */ + u16 rssi_threshold; /* Current RSSI threshold level */ + /* Holds the index of the current AF jump */ + u8 afjump_idx; + /* Will hold the frequency before the jump */ + u32 freq_before_jump; + u8 rds_mode; /* RDS operation mode (RDS/RDBS) */ + u8 af_mode; /* Alternate frequency on/off */ + struct tuned_station_info stat_info; + struct fm_rds rds; +}; + +#define FMTX_RDS_TXT_STR_SIZE 25 +/* + * FM TX RDS data + * + * @ text_type: is the text following PS or RT + * @ text: radio text string which could either be PS or RT + * @ af_freq: alternate frequency for Tx + * TODO: to be declared in application + */ +struct tx_rds { + u8 text_type; + u8 text[FMTX_RDS_TXT_STR_SIZE]; + u8 flag; + u32 af_freq; +}; +/* + * FM TX global data + * + * @ pwr_lvl: Power Level of the Transmission from mixer control + * @ xmit_state: Transmission state = Updated locally upon Start/Stop + * @ audio_io: i2S/Analog + * @ tx_frq: Transmission frequency + */ +struct fmtx_data { + u8 pwr_lvl; + u8 xmit_state; + u8 audio_io; + u8 region; + u16 aud_mode; + u32 preemph; + u32 tx_frq; + struct tx_rds rds; +}; + +/* FM driver operation structure */ +struct fmdev { + struct video_device *radio_dev; /* V4L2 video device pointer */ + struct snd_card *card; /* Card which holds FM mixer controls */ + u16 asci_id; + spinlock_t rds_buff_lock; /* To protect access to RDS buffer */ + spinlock_t resp_skb_lock; /* To protect access to received SKB */ + + long flag; /* FM driver state machine info */ + u8 streg_cbdata; /* status of ST registration */ + + struct sk_buff_head rx_q; /* RX queue */ + struct tasklet_struct rx_task; /* RX Tasklet */ + + struct sk_buff_head tx_q; /* TX queue */ + struct tasklet_struct tx_task; /* TX Tasklet */ + unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */ + atomic_t tx_cnt; /* Number of packets can send at a time */ + + struct sk_buff *resp_skb; /* Response from the chip */ + /* Main task completion handler */ + struct completion maintask_comp; + /* Opcode of last command sent to the chip */ + u8 pre_op; + /* Handler used for wakeup when response packet is received */ + struct completion *resp_comp; + struct fm_irq irq_info; + u8 curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */ + struct fm_rx rx; /* FM receiver info */ + struct fmtx_data tx_data; + + /* V4L2 ctrl framwork handler*/ + struct v4l2_ctrl_handler ctrl_handler; + + /* For core assisted locking */ + struct mutex mutex; +}; +#endif -- cgit v1.2.2 From 7e38849631c2f570fe66b52b5b54697fe338f194 Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Tue, 11 Jan 2011 06:34:26 -0300 Subject: [media] drivers:media:radio: wl128x: FM Driver V4L2 sources This module interfaces V4L2 subsystem and FM common module. It registers itself with V4L2 as Radio module. Signed-off-by: Manjunatha Halli Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_v4l2.c | 580 ++++++++++++++++++++++++++++++++ drivers/media/radio/wl128x/fmdrv_v4l2.h | 33 ++ 2 files changed, 613 insertions(+) create mode 100644 drivers/media/radio/wl128x/fmdrv_v4l2.c create mode 100644 drivers/media/radio/wl128x/fmdrv_v4l2.h (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c new file mode 100644 index 000000000000..d50e5ac75ab6 --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -0,0 +1,580 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * This file provides interfaces to V4L2 subsystem. + * + * This module registers with V4L2 subsystem as Radio + * data system interface (/dev/radio). During the registration, + * it will expose two set of function pointers. + * + * 1) File operation related API (open, close, read, write, poll...etc). + * 2) Set of V4L2 IOCTL complaint API. + * + * Copyright (C) 2011 Texas Instruments + * Author: Raja Mani + * Author: Manjunatha Halli + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "fmdrv.h" +#include "fmdrv_v4l2.h" +#include "fmdrv_common.h" +#include "fmdrv_rx.h" +#include "fmdrv_tx.h" + +static struct video_device *gradio_dev; +static u8 radio_disconnected; + +/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */ + +/* Read RX RDS data */ +static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf, + size_t count, loff_t *ppos) +{ + u8 rds_mode; + int ret; + struct fmdev *fmdev; + + fmdev = video_drvdata(file); + + if (!radio_disconnected) { + fmerr("FM device is already disconnected\n"); + return -EIO; + } + + /* Turn on RDS mode , if it is disabled */ + ret = fm_rx_get_rds_mode(fmdev, &rds_mode); + if (ret < 0) { + fmerr("Unable to read current rds mode\n"); + return ret; + } + + if (rds_mode == FM_RDS_DISABLE) { + ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE); + if (ret < 0) { + fmerr("Failed to enable rds mode\n"); + return ret; + } + } + + /* Copy RDS data from internal buffer to user buffer */ + return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count); +} + +/* Write TX RDS data */ +static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf, + size_t count, loff_t *ppos) +{ + struct tx_rds rds; + int ret; + struct fmdev *fmdev; + + ret = copy_from_user(&rds, buf, sizeof(rds)); + fmdbg("(%d)type: %d, text %s, af %d\n", + ret, rds.text_type, rds.text, rds.af_freq); + + fmdev = video_drvdata(file); + fm_tx_set_radio_text(fmdev, rds.text, rds.text_type); + fm_tx_set_af(fmdev, rds.af_freq); + + return 0; +} + +static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts) +{ + int ret; + struct fmdev *fmdev; + + fmdev = video_drvdata(file); + ret = fmc_is_rds_data_available(fmdev, file, pts); + if (ret < 0) + return POLLIN | POLLRDNORM; + + return 0; +} + +/* + * Handle open request for "/dev/radioX" device. + * Start with FM RX mode as default. + */ +static int fm_v4l2_fops_open(struct file *file) +{ + int ret; + struct fmdev *fmdev = NULL; + + /* Don't allow multiple open */ + if (radio_disconnected) { + fmerr("FM device is already opened\n"); + return -EBUSY; + } + + fmdev = video_drvdata(file); + + ret = fmc_prepare(fmdev); + if (ret < 0) { + fmerr("Unable to prepare FM CORE\n"); + return ret; + } + + fmdbg("Load FM RX firmware..\n"); + + ret = fmc_set_mode(fmdev, FM_MODE_RX); + if (ret < 0) { + fmerr("Unable to load FM RX firmware\n"); + return ret; + } + radio_disconnected = 1; + + return ret; +} + +static int fm_v4l2_fops_release(struct file *file) +{ + int ret; + struct fmdev *fmdev; + + fmdev = video_drvdata(file); + if (!radio_disconnected) { + fmdbg("FM device is already closed\n"); + return 0; + } + + ret = fmc_set_mode(fmdev, FM_MODE_OFF); + if (ret < 0) { + fmerr("Unable to turn off the chip\n"); + return ret; + } + + ret = fmc_release(fmdev); + if (ret < 0) { + fmerr("FM CORE release failed\n"); + return ret; + } + radio_disconnected = 0; + + return ret; +} + +/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */ +static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver)); + strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME, + sizeof(capability->card)); + sprintf(capability->bus_info, "UART"); + capability->version = FM_DRV_RADIO_VERSION; + capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | + V4L2_CAP_RDS_CAPTURE; + + return 0; +} + +static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fmdev *fmdev = container_of(ctrl->handler, + struct fmdev, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + ctrl->val = fm_tx_get_tune_cap_val(fmdev); + break; + default: + fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); + break; + } + + return 0; +} + +static int fm_v4l2_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fmdev *fmdev = container_of(ctrl->handler, + struct fmdev, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: /* set volume */ + return fm_rx_set_volume(fmdev, (u16)ctrl->val); + + case V4L2_CID_AUDIO_MUTE: /* set mute */ + return fmc_set_mute_mode(fmdev, (u8)ctrl->val); + + case V4L2_CID_TUNE_POWER_LEVEL: + /* set TX power level - ext control */ + return fm_tx_set_pwr_lvl(fmdev, (u8)ctrl->val); + + case V4L2_CID_TUNE_PREEMPHASIS: + return fm_tx_set_preemph_filter(fmdev, (u8) ctrl->val); + + default: + return -EINVAL; + } +} + +static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + memset(audio, 0, sizeof(*audio)); + strcpy(audio->name, "Radio"); + audio->capability = V4L2_AUDCAP_STEREO; + + return 0; +} + +static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index != 0) + return -EINVAL; + + return 0; +} + +/* Get tuner attributes. If current mode is NOT RX, return error */ +static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct fmdev *fmdev = video_drvdata(file); + u32 bottom_freq; + u32 top_freq; + u16 stereo_mono_mode; + u16 rssilvl; + int ret; + + if (tuner->index != 0) + return -EINVAL; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + ret = fm_rx_get_band_freq_range(fmdev, &bottom_freq, &top_freq); + if (ret != 0) + return ret; + + ret = fm_rx_get_stereo_mono(fmdev, &stereo_mono_mode); + if (ret != 0) + return ret; + + ret = fm_rx_get_rssi_level(fmdev, &rssilvl); + if (ret != 0) + return ret; + + strcpy(tuner->name, "FM"); + tuner->type = V4L2_TUNER_RADIO; + /* Store rangelow and rangehigh freq in unit of 62.5 Hz */ + tuner->rangelow = bottom_freq * 16; + tuner->rangehigh = top_freq * 16; + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | + ((fmdev->rx.rds.flag == FM_RDS_ENABLE) ? V4L2_TUNER_SUB_RDS : 0); + tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_LOW; + tuner->audmode = (stereo_mono_mode ? + V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO); + + /* + * Actual rssi value lies in between -128 to +127. + * Convert this range from 0 to 255 by adding +128 + */ + rssilvl += 128; + + /* + * Return signal strength value should be within 0 to 65535. + * Find out correct signal radio by multiplying (65535/255) = 257 + */ + tuner->signal = rssilvl * 257; + tuner->afc = 0; + + return ret; +} + +/* + * Set tuner attributes. If current mode is NOT RX, set to RX. + * Currently, we set only audio mode (mono/stereo) and RDS state (on/off). + * Should we set other tuner attributes, too? + */ +static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct fmdev *fmdev = video_drvdata(file); + u16 aud_mode; + u8 rds_mode; + int ret; + + if (tuner->index != 0) + return -EINVAL; + + aud_mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ? + FM_STEREO_MODE : FM_MONO_MODE; + rds_mode = (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) ? + FM_RDS_ENABLE : FM_RDS_DISABLE; + + if (fmdev->curr_fmmode != FM_MODE_RX) { + ret = fmc_set_mode(fmdev, FM_MODE_RX); + if (ret < 0) { + fmerr("Failed to set RX mode\n"); + return ret; + } + } + + ret = fmc_set_stereo_mono(fmdev, aud_mode); + if (ret < 0) { + fmerr("Failed to set RX stereo/mono mode\n"); + return ret; + } + + ret = fmc_set_rds_mode(fmdev, rds_mode); + if (ret < 0) + fmerr("Failed to set RX RDS mode\n"); + + return ret; +} + +/* Get tuner or modulator radio frequency */ +static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct fmdev *fmdev = video_drvdata(file); + int ret; + + ret = fmc_get_freq(fmdev, &freq->frequency); + if (ret < 0) { + fmerr("Failed to get frequency\n"); + return ret; + } + + /* Frequency unit of 62.5 Hz*/ + freq->frequency = (u32) freq->frequency * 16; + + return 0; +} + +/* Set tuner or modulator radio frequency */ +static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct fmdev *fmdev = video_drvdata(file); + + /* + * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency + * in units of 62.5 Hz. + */ + freq->frequency = (u32)(freq->frequency / 16); + + return fmc_set_freq(fmdev, freq->frequency); +} + +/* Set hardware frequency seek. If current mode is NOT RX, set it RX. */ +static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv, + struct v4l2_hw_freq_seek *seek) +{ + struct fmdev *fmdev = video_drvdata(file); + int ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) { + ret = fmc_set_mode(fmdev, FM_MODE_RX); + if (ret != 0) { + fmerr("Failed to set RX mode\n"); + return ret; + } + } + + ret = fm_rx_seek(fmdev, seek->seek_upward, seek->wrap_around, + seek->spacing); + if (ret < 0) + fmerr("RX seek failed - %d\n", ret); + + return ret; +} +/* Get modulator attributes. If mode is not TX, return no attributes. */ +static int fm_v4l2_vidioc_g_modulator(struct file *file, void *priv, + struct v4l2_modulator *mod) +{ + struct fmdev *fmdev = video_drvdata(file);; + + if (mod->index != 0) + return -EINVAL; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + mod->txsubchans = ((fmdev->tx_data.aud_mode == FM_STEREO_MODE) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO) | + ((fmdev->tx_data.rds.flag == FM_RDS_ENABLE) ? + V4L2_TUNER_SUB_RDS : 0); + + mod->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_LOW; + + return 0; +} + +/* Set modulator attributes. If mode is not TX, set to TX. */ +static int fm_v4l2_vidioc_s_modulator(struct file *file, void *priv, + struct v4l2_modulator *mod) +{ + struct fmdev *fmdev = video_drvdata(file); + u8 rds_mode; + u16 aud_mode; + int ret; + + if (mod->index != 0) + return -EINVAL; + + if (fmdev->curr_fmmode != FM_MODE_TX) { + ret = fmc_set_mode(fmdev, FM_MODE_TX); + if (ret != 0) { + fmerr("Failed to set TX mode\n"); + return ret; + } + } + + aud_mode = (mod->txsubchans & V4L2_TUNER_SUB_STEREO) ? + FM_STEREO_MODE : FM_MONO_MODE; + rds_mode = (mod->txsubchans & V4L2_TUNER_SUB_RDS) ? + FM_RDS_ENABLE : FM_RDS_DISABLE; + ret = fm_tx_set_stereo_mono(fmdev, aud_mode); + if (ret < 0) { + fmerr("Failed to set mono/stereo mode for TX\n"); + return ret; + } + ret = fm_tx_set_rds_mode(fmdev, rds_mode); + if (ret < 0) + fmerr("Failed to set rds mode for TX\n"); + + return ret; +} + +static const struct v4l2_file_operations fm_drv_fops = { + .owner = THIS_MODULE, + .read = fm_v4l2_fops_read, + .write = fm_v4l2_fops_write, + .poll = fm_v4l2_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = fm_v4l2_fops_open, + .release = fm_v4l2_fops_release, +}; + +static const struct v4l2_ctrl_ops fm_ctrl_ops = { + .s_ctrl = fm_v4l2_s_ctrl, + .g_volatile_ctrl = fm_g_volatile_ctrl, +}; +static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = { + .vidioc_querycap = fm_v4l2_vidioc_querycap, + .vidioc_g_audio = fm_v4l2_vidioc_g_audio, + .vidioc_s_audio = fm_v4l2_vidioc_s_audio, + .vidioc_g_tuner = fm_v4l2_vidioc_g_tuner, + .vidioc_s_tuner = fm_v4l2_vidioc_s_tuner, + .vidioc_g_frequency = fm_v4l2_vidioc_g_freq, + .vidioc_s_frequency = fm_v4l2_vidioc_s_freq, + .vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek, + .vidioc_g_modulator = fm_v4l2_vidioc_g_modulator, + .vidioc_s_modulator = fm_v4l2_vidioc_s_modulator +}; + +/* V4L2 RADIO device parent structure */ +static struct video_device fm_viddev_template = { + .fops = &fm_drv_fops, + .ioctl_ops = &fm_drv_ioctl_ops, + .name = FM_DRV_NAME, + .release = video_device_release, +}; + +int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) +{ + struct v4l2_ctrl *ctrl; + int ret; + + /* Init mutex for core locking */ + mutex_init(&fmdev->mutex); + + /* Allocate new video device */ + gradio_dev = video_device_alloc(); + if (NULL == gradio_dev) { + fmerr("Can't allocate video device\n"); + return -ENOMEM; + } + + /* Setup FM driver's V4L2 properties */ + memcpy(gradio_dev, &fm_viddev_template, sizeof(fm_viddev_template)); + + video_set_drvdata(gradio_dev, fmdev); + + gradio_dev->lock = &fmdev->mutex; + + /* Register with V4L2 subsystem as RADIO device */ + if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) { + video_device_release(gradio_dev); + fmerr("Could not register video device\n"); + return -ENOMEM; + } + + fmdev->radio_dev = gradio_dev; + + /* Register to v4l2 ctrl handler framework */ + fmdev->radio_dev->ctrl_handler = &fmdev->ctrl_handler; + + ret = v4l2_ctrl_handler_init(&fmdev->ctrl_handler, 5); + if (ret < 0) { + fmerr("(fmdev): Can't init ctrl handler\n"); + v4l2_ctrl_handler_free(&fmdev->ctrl_handler); + return -EBUSY; + } + + /* + * Following controls are handled by V4L2 control framework. + * Added in ascending ID order. + */ + v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, FM_RX_VOLUME_MIN, + FM_RX_VOLUME_MAX, 1, FM_RX_VOLUME_MAX); + + v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); + + v4l2_ctrl_new_std_menu(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_TUNE_PREEMPHASIS, V4L2_PREEMPHASIS_75_uS, + 0, V4L2_PREEMPHASIS_75_uS); + + v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_TUNE_POWER_LEVEL, FM_PWR_LVL_LOW, + FM_PWR_LVL_HIGH, 1, FM_PWR_LVL_HIGH); + + ctrl = v4l2_ctrl_new_std(&fmdev->ctrl_handler, &fm_ctrl_ops, + V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, + 255, 1, 255); + + if (ctrl) + ctrl->is_volatile = 1; + + return 0; +} + +void *fm_v4l2_deinit_video_device(void) +{ + struct fmdev *fmdev; + + + fmdev = video_get_drvdata(gradio_dev); + + /* Unregister to v4l2 ctrl handler framework*/ + v4l2_ctrl_handler_free(&fmdev->ctrl_handler); + + /* Unregister RADIO device from V4L2 subsystem */ + video_unregister_device(gradio_dev); + + return fmdev; +} diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.h b/drivers/media/radio/wl128x/fmdrv_v4l2.h new file mode 100644 index 000000000000..0ba79d745e2f --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.h @@ -0,0 +1,33 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * + * FM V4L2 module header. + * + * Copyright (C) 2011 Texas Instruments + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _FMDRV_V4L2_H +#define _FMDRV_V4L2_H + +#include +#include +#include + +int fm_v4l2_init_video_device(struct fmdev *, int); +void *fm_v4l2_deinit_video_device(void); + +#endif -- cgit v1.2.2 From e8454ff7b9a4d56f02c095bff12d3c92ef4c7fa6 Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Tue, 11 Jan 2011 06:35:22 -0300 Subject: [media] drivers:media:radio: wl128x: FM Driver Common sources These are the sources for the common interfaces required by the FM V4L2 driver for TI WL127x and WL128x chips. These implement the FM channel-8 protocol communication with the chip. This makes use of the Shared Transport as its transport. Signed-off-by: Manjunatha Halli Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 1677 +++++++++++++++++++++++++++++ drivers/media/radio/wl128x/fmdrv_common.h | 402 +++++++ 2 files changed, 2079 insertions(+) create mode 100644 drivers/media/radio/wl128x/fmdrv_common.c create mode 100644 drivers/media/radio/wl128x/fmdrv_common.h (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c new file mode 100644 index 000000000000..12f4c656e8e8 --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -0,0 +1,1677 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * + * This sub-module of FM driver is common for FM RX and TX + * functionality. This module is responsible for: + * 1) Forming group of Channel-8 commands to perform particular + * functionality (eg., frequency set require more than + * one Channel-8 command to be sent to the chip). + * 2) Sending each Channel-8 command to the chip and reading + * response back over Shared Transport. + * 3) Managing TX and RX Queues and Tasklets. + * 4) Handling FM Interrupt packet and taking appropriate action. + * 5) Loading FM firmware to the chip (common, FM TX, and FM RX + * firmware files based on mode selection) + * + * Copyright (C) 2011 Texas Instruments + * Author: Raja Mani + * Author: Manjunatha Halli + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include "fmdrv.h" +#include "fmdrv_v4l2.h" +#include "fmdrv_common.h" +#include +#include "fmdrv_rx.h" +#include "fmdrv_tx.h" + +/* Region info */ +static struct region_info region_configs[] = { + /* Europe/US */ + { + .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, + .bot_freq = 87500, /* 87.5 MHz */ + .top_freq = 108000, /* 108 MHz */ + .fm_band = 0, + }, + /* Japan */ + { + .chanl_space = FM_CHANNEL_SPACING_200KHZ * FM_FREQ_MUL, + .bot_freq = 76000, /* 76 MHz */ + .top_freq = 90000, /* 90 MHz */ + .fm_band = 1, + }, +}; + +/* Band selection */ +static u8 default_radio_region; /* Europe/US */ +module_param(default_radio_region, byte, 0); +MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan"); + +/* RDS buffer blocks */ +static u32 default_rds_buf = 300; +module_param(default_rds_buf, uint, 0444); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries"); + +/* Radio Nr */ +static u32 radio_nr = -1; +module_param(radio_nr, int, 0444); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* FM irq handlers forward declaration */ +static void fm_irq_send_flag_getcmd(struct fmdev *); +static void fm_irq_handle_flag_getcmd_resp(struct fmdev *); +static void fm_irq_handle_hw_malfunction(struct fmdev *); +static void fm_irq_handle_rds_start(struct fmdev *); +static void fm_irq_send_rdsdata_getcmd(struct fmdev *); +static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *); +static void fm_irq_handle_rds_finish(struct fmdev *); +static void fm_irq_handle_tune_op_ended(struct fmdev *); +static void fm_irq_handle_power_enb(struct fmdev *); +static void fm_irq_handle_low_rssi_start(struct fmdev *); +static void fm_irq_afjump_set_pi(struct fmdev *); +static void fm_irq_handle_set_pi_resp(struct fmdev *); +static void fm_irq_afjump_set_pimask(struct fmdev *); +static void fm_irq_handle_set_pimask_resp(struct fmdev *); +static void fm_irq_afjump_setfreq(struct fmdev *); +static void fm_irq_handle_setfreq_resp(struct fmdev *); +static void fm_irq_afjump_enableint(struct fmdev *); +static void fm_irq_afjump_enableint_resp(struct fmdev *); +static void fm_irq_start_afjump(struct fmdev *); +static void fm_irq_handle_start_afjump_resp(struct fmdev *); +static void fm_irq_afjump_rd_freq(struct fmdev *); +static void fm_irq_afjump_rd_freq_resp(struct fmdev *); +static void fm_irq_handle_low_rssi_finish(struct fmdev *); +static void fm_irq_send_intmsk_cmd(struct fmdev *); +static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *); + +/* + * When FM common module receives interrupt packet, following handlers + * will be executed one after another to service the interrupt(s) + */ +enum fmc_irq_handler_index { + FM_SEND_FLAG_GETCMD_IDX, + FM_HANDLE_FLAG_GETCMD_RESP_IDX, + + /* HW malfunction irq handler */ + FM_HW_MAL_FUNC_IDX, + + /* RDS threshold reached irq handler */ + FM_RDS_START_IDX, + FM_RDS_SEND_RDS_GETCMD_IDX, + FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX, + FM_RDS_FINISH_IDX, + + /* Tune operation ended irq handler */ + FM_HW_TUNE_OP_ENDED_IDX, + + /* TX power enable irq handler */ + FM_HW_POWER_ENB_IDX, + + /* Low RSSI irq handler */ + FM_LOW_RSSI_START_IDX, + FM_AF_JUMP_SETPI_IDX, + FM_AF_JUMP_HANDLE_SETPI_RESP_IDX, + FM_AF_JUMP_SETPI_MASK_IDX, + FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX, + FM_AF_JUMP_SET_AF_FREQ_IDX, + FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX, + FM_AF_JUMP_ENABLE_INT_IDX, + FM_AF_JUMP_ENABLE_INT_RESP_IDX, + FM_AF_JUMP_START_AFJUMP_IDX, + FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX, + FM_AF_JUMP_RD_FREQ_IDX, + FM_AF_JUMP_RD_FREQ_RESP_IDX, + FM_LOW_RSSI_FINISH_IDX, + + /* Interrupt process post action */ + FM_SEND_INTMSK_CMD_IDX, + FM_HANDLE_INTMSK_CMD_RESP_IDX, +}; + +/* FM interrupt handler table */ +static int_handler_prototype int_handler_table[] = { + fm_irq_send_flag_getcmd, + fm_irq_handle_flag_getcmd_resp, + fm_irq_handle_hw_malfunction, + fm_irq_handle_rds_start, /* RDS threshold reached irq handler */ + fm_irq_send_rdsdata_getcmd, + fm_irq_handle_rdsdata_getcmd_resp, + fm_irq_handle_rds_finish, + fm_irq_handle_tune_op_ended, + fm_irq_handle_power_enb, /* TX power enable irq handler */ + fm_irq_handle_low_rssi_start, + fm_irq_afjump_set_pi, + fm_irq_handle_set_pi_resp, + fm_irq_afjump_set_pimask, + fm_irq_handle_set_pimask_resp, + fm_irq_afjump_setfreq, + fm_irq_handle_setfreq_resp, + fm_irq_afjump_enableint, + fm_irq_afjump_enableint_resp, + fm_irq_start_afjump, + fm_irq_handle_start_afjump_resp, + fm_irq_afjump_rd_freq, + fm_irq_afjump_rd_freq_resp, + fm_irq_handle_low_rssi_finish, + fm_irq_send_intmsk_cmd, /* Interrupt process post action */ + fm_irq_handle_intmsk_cmd_resp +}; + +long (*g_st_write) (struct sk_buff *skb); +static struct completion wait_for_fmdrv_reg_comp; + +static inline void fm_irq_call(struct fmdev *fmdev) +{ + fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); +} + +/* Continue next function in interrupt handler table */ +static inline void fm_irq_call_stage(struct fmdev *fmdev, u8 stage) +{ + fmdev->irq_info.stage = stage; + fm_irq_call(fmdev); +} + +static inline void fm_irq_timeout_stage(struct fmdev *fmdev, u8 stage) +{ + fmdev->irq_info.stage = stage; + mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); +} + +#ifdef FM_DUMP_TXRX_PKT + /* To dump outgoing FM Channel-8 packets */ +inline void dump_tx_skb_data(struct sk_buff *skb) +{ + int len, len_org; + u8 index; + struct fm_cmd_msg_hdr *cmd_hdr; + + cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data; + printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x", + fm_cb(skb)->completion ? " " : "*", cmd_hdr->hdr, + cmd_hdr->len, cmd_hdr->op, + cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen); + + len_org = skb->len - FM_CMD_MSG_HDR_SIZE; + if (len_org > 0) { + printk("\n data(%d): ", cmd_hdr->dlen); + len = min(len_org, 14); + for (index = 0; index < len; index++) + printk("%x ", + skb->data[FM_CMD_MSG_HDR_SIZE + index]); + printk("%s", (len_org > 14) ? ".." : ""); + } + printk("\n"); +} + + /* To dump incoming FM Channel-8 packets */ +inline void dump_rx_skb_data(struct sk_buff *skb) +{ + int len, len_org; + u8 index; + struct fm_event_msg_hdr *evt_hdr; + + evt_hdr = (struct fm_event_msg_hdr *)skb->data; + printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x " + "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len, + evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op, + (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen); + + len_org = skb->len - FM_EVT_MSG_HDR_SIZE; + if (len_org > 0) { + printk("\n data(%d): ", evt_hdr->dlen); + len = min(len_org, 14); + for (index = 0; index < len; index++) + printk("%x ", + skb->data[FM_EVT_MSG_HDR_SIZE + index]); + printk("%s", (len_org > 14) ? ".." : ""); + } + printk("\n"); +} +#endif + +void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set) +{ + fmdev->rx.region = region_configs[region_to_set]; +} + +/* + * FM common sub-module will schedule this tasklet whenever it receives + * FM packet from ST driver. + */ +static void recv_tasklet(unsigned long arg) +{ + struct fmdev *fmdev; + struct fm_irq *irq_info; + struct fm_event_msg_hdr *evt_hdr; + struct sk_buff *skb; + u8 num_fm_hci_cmds; + unsigned long flags; + + fmdev = (struct fmdev *)arg; + irq_info = &fmdev->irq_info; + /* Process all packets in the RX queue */ + while ((skb = skb_dequeue(&fmdev->rx_q))) { + if (skb->len < sizeof(struct fm_event_msg_hdr)) { + fmerr("skb(%p) has only %d bytes" + "atleast need %d bytes to decode\n", skb, + skb->len, sizeof(struct fm_event_msg_hdr)); + kfree_skb(skb); + continue; + } + + evt_hdr = (void *)skb->data; + num_fm_hci_cmds = evt_hdr->num_fm_hci_cmds; + + /* FM interrupt packet? */ + if (evt_hdr->op == FM_INTERRUPT) { + /* FM interrupt handler started already? */ + if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { + set_bit(FM_INTTASK_RUNNING, &fmdev->flag); + if (irq_info->stage != 0) { + fmerr("Inval stage resetting to zero\n"); + irq_info->stage = 0; + } + + /* + * Execute first function in interrupt handler + * table. + */ + irq_info->handlers[irq_info->stage](fmdev); + } else { + set_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag); + } + kfree_skb(skb); + } + /* Anyone waiting for this with completion handler? */ + else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp != NULL) { + + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + fmdev->resp_skb = skb; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + complete(fmdev->resp_comp); + + fmdev->resp_comp = NULL; + atomic_set(&fmdev->tx_cnt, 1); + } + /* Is this for interrupt handler? */ + else if (evt_hdr->op == fmdev->pre_op && fmdev->resp_comp == NULL) { + if (fmdev->resp_skb != NULL) + fmerr("Response SKB ptr not NULL\n"); + + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + fmdev->resp_skb = skb; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + + /* Execute interrupt handler where state index points */ + irq_info->handlers[irq_info->stage](fmdev); + + kfree_skb(skb); + atomic_set(&fmdev->tx_cnt, 1); + } else { + fmerr("Nobody claimed SKB(%p),purging\n", skb); + } + + /* + * Check flow control field. If Num_FM_HCI_Commands field is + * not zero, schedule FM TX tasklet. + */ + if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) + if (!skb_queue_empty(&fmdev->tx_q)) + tasklet_schedule(&fmdev->tx_task); + } +} + +/* FM send tasklet: is scheduled when FM packet has to be sent to chip */ +static void send_tasklet(unsigned long arg) +{ + struct fmdev *fmdev; + struct sk_buff *skb; + int len; + + fmdev = (struct fmdev *)arg; + + if (!atomic_read(&fmdev->tx_cnt)) + return; + + /* Check, is there any timeout happenned to last transmitted packet */ + if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) { + fmerr("TX timeout occurred\n"); + atomic_set(&fmdev->tx_cnt, 1); + } + + /* Send queued FM TX packets */ + skb = skb_dequeue(&fmdev->tx_q); + if (!skb) + return; + + atomic_dec(&fmdev->tx_cnt); + fmdev->pre_op = fm_cb(skb)->fm_op; + + if (fmdev->resp_comp != NULL) + fmerr("Response completion handler is not NULL\n"); + + fmdev->resp_comp = fm_cb(skb)->completion; + + /* Write FM packet to ST driver */ + len = g_st_write(skb); + if (len < 0) { + kfree_skb(skb); + fmdev->resp_comp = NULL; + fmerr("TX tasklet failed to send skb(%p)\n", skb); + atomic_set(&fmdev->tx_cnt, 1); + } else { + fmdev->last_tx_jiffies = jiffies; + } +} + +/* + * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for + * transmission + */ +static u32 fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, + int payload_len, struct completion *wait_completion) +{ + struct sk_buff *skb; + struct fm_cmd_msg_hdr *hdr; + int size; + + if (fm_op >= FM_INTERRUPT) { + fmerr("Invalid fm opcode - %d\n", fm_op); + return -EINVAL; + } + if (test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) && payload == NULL) { + fmerr("Payload data is NULL during fw download\n"); + return -EINVAL; + } + if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag)) + size = + FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len); + else + size = payload_len; + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + fmerr("No memory to create new SKB\n"); + return -ENOMEM; + } + /* + * Don't fill FM header info for the commands which come from + * FM firmware file. + */ + if (!test_bit(FM_FW_DW_INPROGRESS, &fmdev->flag) || + test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) { + /* Fill command header info */ + hdr = (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE); + hdr->hdr = FM_PKT_LOGICAL_CHAN_NUMBER; /* 0x08 */ + + /* 3 (fm_opcode,rd_wr,dlen) + payload len) */ + hdr->len = ((payload == NULL) ? 0 : payload_len) + 3; + + /* FM opcode */ + hdr->op = fm_op; + + /* read/write type */ + hdr->rd_wr = type; + hdr->dlen = payload_len; + fm_cb(skb)->fm_op = fm_op; + + /* + * If firmware download has finished and the command is + * not a read command then payload is != NULL - a write + * command with u16 payload - convert to be16 + */ + if (payload != NULL) + *(u16 *)payload = cpu_to_be16(*(u16 *)payload); + + } else if (payload != NULL) { + fm_cb(skb)->fm_op = *((u8 *)payload + 2); + } + if (payload != NULL) + memcpy(skb_put(skb, payload_len), payload, payload_len); + + fm_cb(skb)->completion = wait_completion; + skb_queue_tail(&fmdev->tx_q, skb); + tasklet_schedule(&fmdev->tx_task); + + return 0; +} + +/* Sends FM Channel-8 command to the chip and waits for the response */ +u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, + unsigned int payload_len, void *response, int *response_len) +{ + struct sk_buff *skb; + struct fm_event_msg_hdr *evt_hdr; + unsigned long flags; + u32 ret; + + init_completion(&fmdev->maintask_comp); + ret = fm_send_cmd(fmdev, fm_op, type, payload, payload_len, + &fmdev->maintask_comp); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT); + if (!ret) { + fmerr("Timeout(%d sec),didn't get reg" + "completion signal from RX tasklet\n", + jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + if (!fmdev->resp_skb) { + fmerr("Reponse SKB is missing\n"); + return -EFAULT; + } + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + skb = fmdev->resp_skb; + fmdev->resp_skb = NULL; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + + evt_hdr = (void *)skb->data; + if (evt_hdr->status != 0) { + fmerr("Received event pkt status(%d) is not zero\n", + evt_hdr->status); + kfree_skb(skb); + return -EIO; + } + /* Send response data to caller */ + if (response != NULL && response_len != NULL && evt_hdr->dlen) { + /* Skip header info and copy only response data */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + memcpy(response, skb->data, evt_hdr->dlen); + *response_len = evt_hdr->dlen; + } else if (response_len != NULL && evt_hdr->dlen == 0) { + *response_len = 0; + } + kfree_skb(skb); + + return 0; +} + +/* --- Helper functions used in FM interrupt handlers ---*/ +static inline u32 check_cmdresp_status(struct fmdev *fmdev, + struct sk_buff **skb) +{ + struct fm_event_msg_hdr *fm_evt_hdr; + unsigned long flags; + + del_timer(&fmdev->irq_info.timer); + + spin_lock_irqsave(&fmdev->resp_skb_lock, flags); + *skb = fmdev->resp_skb; + fmdev->resp_skb = NULL; + spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags); + + fm_evt_hdr = (void *)(*skb)->data; + if (fm_evt_hdr->status != 0) { + fmerr("irq: opcode %x response status is not zero " + "Initiating irq recovery process\n", + fm_evt_hdr->op); + + mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); + return -1; + } + + return 0; +} + +static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage) +{ + struct sk_buff *skb; + + if (!check_cmdresp_status(fmdev, &skb)) + fm_irq_call_stage(fmdev, stage); +} + +/* + * Interrupt process timeout handler. + * One of the irq handler did not get proper response from the chip. So take + * recovery action here. FM interrupts are disabled in the beginning of + * interrupt process. Therefore reset stage index to re-enable default + * interrupts. So that next interrupt will be processed as usual. + */ +static void int_timeout_handler(unsigned long data) +{ + struct fmdev *fmdev; + struct fm_irq *fmirq; + + fmdbg("irq: timeout,trying to re-enable fm interrupts\n"); + fmdev = (struct fmdev *)data; + fmirq = &fmdev->irq_info; + fmirq->retry++; + + if (fmirq->retry > FM_IRQ_TIMEOUT_RETRY_MAX) { + /* Stop recovery action (interrupt reenable process) and + * reset stage index & retry count values */ + fmirq->stage = 0; + fmirq->retry = 0; + fmerr("Recovery action failed during" + "irq processing, max retry reached\n"); + return; + } + fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); +} + +/* --------- FM interrupt handlers ------------*/ +static void fm_irq_send_flag_getcmd(struct fmdev *fmdev) +{ + u16 flag; + + /* Send FLAG_GET command , to know the source of interrupt */ + if (!fm_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, sizeof(flag), NULL)) + fm_irq_timeout_stage(fmdev, FM_HANDLE_FLAG_GETCMD_RESP_IDX); +} + +static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + struct fm_event_msg_hdr *fm_evt_hdr; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + fm_evt_hdr = (void *)skb->data; + + /* Skip header info and copy only response data */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen); + + fmdev->irq_info.flag = be16_to_cpu(fmdev->irq_info.flag); + fmdbg("irq: flag register(0x%x)\n", fmdev->irq_info.flag); + + /* Continue next function in interrupt handler table */ + fm_irq_call_stage(fmdev, FM_HW_MAL_FUNC_IDX); +} + +static void fm_irq_handle_hw_malfunction(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask) + fmerr("irq: HW MAL int received - do nothing\n"); + + /* Continue next function in interrupt handler table */ + fm_irq_call_stage(fmdev, FM_RDS_START_IDX); +} + +static void fm_irq_handle_rds_start(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) { + fmdbg("irq: rds threshold reached\n"); + fmdev->irq_info.stage = FM_RDS_SEND_RDS_GETCMD_IDX; + } else { + /* Continue next function in interrupt handler table */ + fmdev->irq_info.stage = FM_HW_TUNE_OP_ENDED_IDX; + } + + fm_irq_call(fmdev); +} + +static void fm_irq_send_rdsdata_getcmd(struct fmdev *fmdev) +{ + /* Send the command to read RDS data from the chip */ + if (!fm_send_cmd(fmdev, RDS_DATA_GET, REG_RD, NULL, + (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL)) + fm_irq_timeout_stage(fmdev, FM_RDS_HANDLE_RDS_GETCMD_RESP_IDX); +} + +/* Keeps track of current RX channel AF (Alternate Frequency) */ +static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) +{ + struct tuned_station_info *stat_info = &fmdev->rx.stat_info; + u8 reg_idx = fmdev->rx.region.fm_band; + u8 index; + u32 freq; + + /* First AF indicates the number of AF follows. Reset the list */ + if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) { + fmdev->rx.stat_info.af_list_max = (af - FM_RDS_1_AF_FOLLOWS + 1); + fmdev->rx.stat_info.afcache_size = 0; + fmdbg("No of expected AF : %d\n", fmdev->rx.stat_info.af_list_max); + return; + } + + if (af < FM_RDS_MIN_AF) + return; + if (reg_idx == FM_BAND_EUROPE_US && af > FM_RDS_MAX_AF) + return; + if (reg_idx == FM_BAND_JAPAN && af > FM_RDS_MAX_AF_JAPAN) + return; + + freq = fmdev->rx.region.bot_freq + (af * 100); + if (freq == fmdev->rx.freq) { + fmdbg("Current freq(%d) is matching with received AF(%d)\n", + fmdev->rx.freq, freq); + return; + } + /* Do check in AF cache */ + for (index = 0; index < stat_info->afcache_size; index++) { + if (stat_info->af_cache[index] == freq) + break; + } + /* Reached the limit of the list - ignore the next AF */ + if (index == stat_info->af_list_max) { + fmdbg("AF cache is full\n"); + return; + } + /* + * If we reached the end of the list then this AF is not + * in the list - add it. + */ + if (index == stat_info->afcache_size) { + fmdbg("Storing AF %d to cache index %d\n", freq, index); + stat_info->af_cache[index] = freq; + stat_info->afcache_size++; + } +} + +/* + * Converts RDS buffer data from big endian format + * to little endian format. + */ +static void fm_rdsparse_swapbytes(struct fmdev *fmdev, + struct fm_rdsdata_format *rds_format) +{ + u8 byte1; + u8 index = 0; + u8 *rds_buff; + + /* + * Since in Orca the 2 RDS Data bytes are in little endian and + * in Dolphin they are in big endian, the parsing of the RDS data + * is chip dependent + */ + if (fmdev->asci_id != 0x6350) { + rds_buff = &rds_format->data.groupdatabuff.buff[0]; + while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { + byte1 = rds_buff[index]; + rds_buff[index] = rds_buff[index + 1]; + rds_buff[index + 1] = byte1; + index += 2; + } + } +} + +static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + struct fm_rdsdata_format rds_fmt; + struct fm_rds *rds = &fmdev->rx.rds; + unsigned long group_idx, flags; + u8 *rds_data, meta_data, tmpbuf[3]; + u8 type, blk_idx; + u16 cur_picode; + u32 rds_len; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + /* Skip header info */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + rds_data = skb->data; + rds_len = skb->len; + + /* Parse the RDS data */ + while (rds_len >= FM_RDS_BLK_SIZE) { + meta_data = rds_data[2]; + /* Get the type: 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */ + type = (meta_data & 0x07); + + /* Transform the blk type into index sequence (0, 1, 2, 3, 4) */ + blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); + fmdbg("Block index:%d(%s)\n", blk_idx, + (meta_data & FM_RDS_STATUS_ERR_MASK) ? "Bad" : "Ok"); + + if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0) + break; + + if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) { + fmdbg("Block sequence mismatch\n"); + rds->last_blk_idx = -1; + break; + } + + /* Skip checkword (control) byte and copy only data byte */ + memcpy(&rds_fmt.data.groupdatabuff. + buff[blk_idx * (FM_RDS_BLK_SIZE - 1)], + rds_data, (FM_RDS_BLK_SIZE - 1)); + + rds->last_blk_idx = blk_idx; + + /* If completed a whole group then handle it */ + if (blk_idx == FM_RDS_BLK_IDX_D) { + fmdbg("Good block received\n"); + fm_rdsparse_swapbytes(fmdev, &rds_fmt); + + /* + * Extract PI code and store in local cache. + * We need this during AF switch processing. + */ + cur_picode = be16_to_cpu(rds_fmt.data.groupgeneral.pidata); + if (fmdev->rx.stat_info.picode != cur_picode) + fmdev->rx.stat_info.picode = cur_picode; + + fmdbg("picode:%d\n", cur_picode); + + group_idx = (rds_fmt.data.groupgeneral.blk_b[0] >> 3); + fmdbg("(fmdrv):Group:%ld%s\n", group_idx/2, + (group_idx % 2) ? "B" : "A"); + + group_idx = 1 << (rds_fmt.data.groupgeneral.blk_b[0] >> 3); + if (group_idx == FM_RDS_GROUP_TYPE_MASK_0A) { + fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[0]); + fm_rx_update_af_cache(fmdev, rds_fmt.data.group0A.af[1]); + } + } + rds_len -= FM_RDS_BLK_SIZE; + rds_data += FM_RDS_BLK_SIZE; + } + + /* Copy raw rds data to internal rds buffer */ + rds_data = skb->data; + rds_len = skb->len; + + spin_lock_irqsave(&fmdev->rds_buff_lock, flags); + while (rds_len > 0) { + /* + * Fill RDS buffer as per V4L2 specification. + * Store control byte + */ + type = (rds_data[2] & 0x07); + blk_idx = (type <= FM_RDS_BLOCK_C ? type : (type - 1)); + tmpbuf[2] = blk_idx; /* Offset name */ + tmpbuf[2] |= blk_idx << 3; /* Received offset */ + + /* Store data byte */ + tmpbuf[0] = rds_data[0]; + tmpbuf[1] = rds_data[1]; + + memcpy(&rds->buff[rds->wr_idx], &tmpbuf, FM_RDS_BLK_SIZE); + rds->wr_idx = (rds->wr_idx + FM_RDS_BLK_SIZE) % rds->buf_size; + + /* Check for overflow & start over */ + if (rds->wr_idx == rds->rd_idx) { + fmdbg("RDS buffer overflow\n"); + rds->wr_idx = 0; + rds->rd_idx = 0; + break; + } + rds_len -= FM_RDS_BLK_SIZE; + rds_data += FM_RDS_BLK_SIZE; + } + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); + + /* Wakeup read queue */ + if (rds->wr_idx != rds->rd_idx) + wake_up_interruptible(&rds->read_queue); + + fm_irq_call_stage(fmdev, FM_RDS_FINISH_IDX); +} + +static void fm_irq_handle_rds_finish(struct fmdev *fmdev) +{ + fm_irq_call_stage(fmdev, FM_HW_TUNE_OP_ENDED_IDX); +} + +static void fm_irq_handle_tune_op_ended(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev-> + irq_info.mask) { + fmdbg("irq: tune ended/bandlimit reached\n"); + if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) { + fmdev->irq_info.stage = FM_AF_JUMP_RD_FREQ_IDX; + } else { + complete(&fmdev->maintask_comp); + fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; + } + } else + fmdev->irq_info.stage = FM_HW_POWER_ENB_IDX; + + fm_irq_call(fmdev); +} + +static void fm_irq_handle_power_enb(struct fmdev *fmdev) +{ + if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) { + fmdbg("irq: Power Enabled/Disabled\n"); + complete(&fmdev->maintask_comp); + } + + fm_irq_call_stage(fmdev, FM_LOW_RSSI_START_IDX); +} + +static void fm_irq_handle_low_rssi_start(struct fmdev *fmdev) +{ + if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) && + (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) && + (fmdev->rx.freq != FM_UNDEFINED_FREQ) && + (fmdev->rx.stat_info.afcache_size != 0)) { + fmdbg("irq: rssi level has fallen below threshold level\n"); + + /* Disable further low RSSI interrupts */ + fmdev->irq_info.mask &= ~FM_LEV_EVENT; + + fmdev->rx.afjump_idx = 0; + fmdev->rx.freq_before_jump = fmdev->rx.freq; + fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; + } else { + /* Continue next function in interrupt handler table */ + fmdev->irq_info.stage = FM_SEND_INTMSK_CMD_IDX; + } + + fm_irq_call(fmdev); +} + +static void fm_irq_afjump_set_pi(struct fmdev *fmdev) +{ + u16 payload; + + /* Set PI code - must be updated if the AF list is not empty */ + payload = fmdev->rx.stat_info.picode; + if (!fm_send_cmd(fmdev, RDS_PI_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_RESP_IDX); +} + +static void fm_irq_handle_set_pi_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SETPI_MASK_IDX); +} + +/* + * Set PI mask. + * 0xFFFF = Enable PI code matching + * 0x0000 = Disable PI code matching + */ +static void fm_irq_afjump_set_pimask(struct fmdev *fmdev) +{ + u16 payload; + + payload = 0x0000; + if (!fm_send_cmd(fmdev, RDS_PI_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_IDX); +} + +static void fm_irq_handle_set_pimask_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_SET_AF_FREQ_IDX); +} + +static void fm_irq_afjump_setfreq(struct fmdev *fmdev) +{ + u16 frq_index; + u16 payload; + + fmdbg("Swtich to %d KHz\n", fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]); + frq_index = (fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx] - + fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + + payload = frq_index; + if (!fm_send_cmd(fmdev, AF_FREQ_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_SET_AFFREQ_RESP_IDX); +} + +static void fm_irq_handle_setfreq_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_ENABLE_INT_IDX); +} + +static void fm_irq_afjump_enableint(struct fmdev *fmdev) +{ + u16 payload; + + /* Enable FR (tuning operation ended) interrupt */ + payload = FM_FR_EVENT; + if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_ENABLE_INT_RESP_IDX); +} + +static void fm_irq_afjump_enableint_resp(struct fmdev *fmdev) +{ + fm_irq_common_cmd_resp_helper(fmdev, FM_AF_JUMP_START_AFJUMP_IDX); +} + +static void fm_irq_start_afjump(struct fmdev *fmdev) +{ + u16 payload; + + payload = FM_TUNER_AF_JUMP_MODE; + if (!fm_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_IDX); +} + +static void fm_irq_handle_start_afjump_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; + set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag); + clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); +} + +static void fm_irq_afjump_rd_freq(struct fmdev *fmdev) +{ + u16 payload; + + if (!fm_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_AF_JUMP_RD_FREQ_RESP_IDX); +} + +static void fm_irq_afjump_rd_freq_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + u16 read_freq; + u32 curr_freq, jumped_freq; + + if (check_cmdresp_status(fmdev, &skb)) + return; + + /* Skip header info and copy only response data */ + skb_pull(skb, sizeof(struct fm_event_msg_hdr)); + memcpy(&read_freq, skb->data, sizeof(read_freq)); + read_freq = be16_to_cpu(read_freq); + curr_freq = fmdev->rx.region.bot_freq + ((u32)read_freq * FM_FREQ_MUL); + + jumped_freq = fmdev->rx.stat_info.af_cache[fmdev->rx.afjump_idx]; + + /* If the frequency was changed the jump succeeded */ + if ((curr_freq != fmdev->rx.freq_before_jump) && (curr_freq == jumped_freq)) { + fmdbg("Successfully switched to alternate freq %d\n", curr_freq); + fmdev->rx.freq = curr_freq; + fm_rx_reset_rds_cache(fmdev); + + /* AF feature is on, enable low level RSSI interrupt */ + if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) + fmdev->irq_info.mask |= FM_LEV_EVENT; + + fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; + } else { /* jump to the next freq in the AF list */ + fmdev->rx.afjump_idx++; + + /* If we reached the end of the list - stop searching */ + if (fmdev->rx.afjump_idx >= fmdev->rx.stat_info.afcache_size) { + fmdbg("AF switch processing failed\n"); + fmdev->irq_info.stage = FM_LOW_RSSI_FINISH_IDX; + } else { /* AF List is not over - try next one */ + + fmdbg("Trying next freq in AF cache\n"); + fmdev->irq_info.stage = FM_AF_JUMP_SETPI_IDX; + } + } + fm_irq_call(fmdev); +} + +static void fm_irq_handle_low_rssi_finish(struct fmdev *fmdev) +{ + fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); +} + +static void fm_irq_send_intmsk_cmd(struct fmdev *fmdev) +{ + u16 payload; + + /* Re-enable FM interrupts */ + payload = fmdev->irq_info.mask; + + if (!fm_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL)) + fm_irq_timeout_stage(fmdev, FM_HANDLE_INTMSK_CMD_RESP_IDX); +} + +static void fm_irq_handle_intmsk_cmd_resp(struct fmdev *fmdev) +{ + struct sk_buff *skb; + + if (check_cmdresp_status(fmdev, &skb)) + return; + /* + * This is last function in interrupt table to be executed. + * So, reset stage index to 0. + */ + fmdev->irq_info.stage = FM_SEND_FLAG_GETCMD_IDX; + + /* Start processing any pending interrupt */ + if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag)) + fmdev->irq_info.handlers[fmdev->irq_info.stage](fmdev); + else + clear_bit(FM_INTTASK_RUNNING, &fmdev->flag); +} + +/* Returns availability of RDS data in internel buffer */ +u32 fmc_is_rds_data_available(struct fmdev *fmdev, struct file *file, + struct poll_table_struct *pts) +{ + poll_wait(file, &fmdev->rx.rds.read_queue, pts); + if (fmdev->rx.rds.rd_idx != fmdev->rx.rds.wr_idx) + return 0; + + return -EAGAIN; +} + +/* Copies RDS data from internal buffer to user buffer */ +u32 fmc_transfer_rds_from_internal_buff(struct fmdev *fmdev, struct file *file, + u8 __user *buf, size_t count) +{ + u32 block_count; + unsigned long flags; + int ret; + + if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + ret = wait_event_interruptible(fmdev->rx.rds.read_queue, + (fmdev->rx.rds.wr_idx != fmdev->rx.rds.rd_idx)); + if (ret) + return -EINTR; + } + + /* Calculate block count from byte count */ + count /= 3; + block_count = 0; + ret = 0; + + spin_lock_irqsave(&fmdev->rds_buff_lock, flags); + + while (block_count < count) { + if (fmdev->rx.rds.wr_idx == fmdev->rx.rds.rd_idx) + break; + + if (copy_to_user(buf, &fmdev->rx.rds.buff[fmdev->rx.rds.rd_idx], + FM_RDS_BLK_SIZE)) + break; + + fmdev->rx.rds.rd_idx += FM_RDS_BLK_SIZE; + if (fmdev->rx.rds.rd_idx >= fmdev->rx.rds.buf_size) + fmdev->rx.rds.rd_idx = 0; + + block_count++; + buf += FM_RDS_BLK_SIZE; + ret += FM_RDS_BLK_SIZE; + } + spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags); + return ret; +} + +u32 fmc_set_freq(struct fmdev *fmdev, u32 freq_to_set) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_freq(fmdev, freq_to_set); + + case FM_MODE_TX: + return fm_tx_set_freq(fmdev, freq_to_set); + + default: + return -EINVAL; + } +} + +u32 fmc_get_freq(struct fmdev *fmdev, u32 *cur_tuned_frq) +{ + if (fmdev->rx.freq == FM_UNDEFINED_FREQ) { + fmerr("RX frequency is not set\n"); + return -EPERM; + } + if (cur_tuned_frq == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + *cur_tuned_frq = fmdev->rx.freq; + return 0; + + case FM_MODE_TX: + *cur_tuned_frq = 0; /* TODO : Change this later */ + return 0; + + default: + return -EINVAL; + } + +} + +u32 fmc_set_region(struct fmdev *fmdev, u8 region_to_set) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_region(fmdev, region_to_set); + + case FM_MODE_TX: + return fm_tx_set_region(fmdev, region_to_set); + + default: + return -EINVAL; + } +} + +u32 fmc_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_mute_mode(fmdev, mute_mode_toset); + + case FM_MODE_TX: + return fm_tx_set_mute_mode(fmdev, mute_mode_toset); + + default: + return -EINVAL; + } +} + +u32 fmc_set_stereo_mono(struct fmdev *fmdev, u16 mode) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_stereo_mono(fmdev, mode); + + case FM_MODE_TX: + return fm_tx_set_stereo_mono(fmdev, mode); + + default: + return -EINVAL; + } +} + +u32 fmc_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +{ + switch (fmdev->curr_fmmode) { + case FM_MODE_RX: + return fm_rx_set_rds_mode(fmdev, rds_en_dis); + + case FM_MODE_TX: + return fm_tx_set_rds_mode(fmdev, rds_en_dis); + + default: + return -EINVAL; + } +} + +/* Sends power off command to the chip */ +static u32 fm_power_down(struct fmdev *fmdev) +{ + u16 payload; + u32 ret; + + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + fmerr("FM core is not ready\n"); + return -EPERM; + } + if (fmdev->curr_fmmode == FM_MODE_OFF) { + fmdbg("FM chip is already in OFF state\n"); + return 0; + } + + payload = 0x0; + ret = fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return fmc_release(fmdev); +} + +/* Reads init command from FM firmware file and loads to the chip */ +static u32 fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) +{ + const struct firmware *fw_entry; + struct bts_header *fw_header; + struct bts_action *action; + struct bts_action_delay *delay; + u8 *fw_data; + int ret, fw_len, cmd_cnt; + + cmd_cnt = 0; + set_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); + + ret = request_firmware(&fw_entry, fw_name, + &fmdev->radio_dev->dev); + if (ret < 0) { + fmerr("Unable to read firmware(%s) content\n", fw_name); + return ret; + } + fmdbg("Firmware(%s) length : %d bytes\n", fw_name, fw_entry->size); + + fw_data = (void *)fw_entry->data; + fw_len = fw_entry->size; + + fw_header = (struct bts_header *)fw_data; + if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) { + fmerr("%s not a legal TI firmware file\n", fw_name); + ret = -EINVAL; + goto rel_fw; + } + fmdbg("FW(%s) magic number : 0x%x\n", fw_name, fw_header->magic); + + /* Skip file header info , we already verified it */ + fw_data += sizeof(struct bts_header); + fw_len -= sizeof(struct bts_header); + + while (fw_data && fw_len > 0) { + action = (struct bts_action *)fw_data; + + switch (action->type) { + case ACTION_SEND_COMMAND: /* Send */ + if (fmc_send_cmd(fmdev, 0, 0, action->data, + action->size, NULL, NULL)) + goto rel_fw; + + cmd_cnt++; + break; + + case ACTION_DELAY: /* Delay */ + delay = (struct bts_action_delay *)action->data; + mdelay(delay->msec); + break; + } + + fw_data += (sizeof(struct bts_action) + (action->size)); + fw_len -= (sizeof(struct bts_action) + (action->size)); + } + fmdbg("Firmware commands(%d) loaded to chip\n", cmd_cnt); +rel_fw: + release_firmware(fw_entry); + clear_bit(FM_FW_DW_INPROGRESS, &fmdev->flag); + + return ret; +} + +/* Loads default RX configuration to the chip */ +static u32 load_default_rx_configuration(struct fmdev *fmdev) +{ + int ret; + + ret = fm_rx_set_volume(fmdev, FM_DEFAULT_RX_VOLUME); + if (ret < 0) + return ret; + + return fm_rx_set_rssi_threshold(fmdev, FM_DEFAULT_RSSI_THRESHOLD); +} + +/* Does FM power on sequence */ +static u32 fm_power_up(struct fmdev *fmdev, u8 mode) +{ + u16 payload, asic_id, asic_ver; + int resp_len, ret; + u8 fw_name[50]; + + if (mode >= FM_MODE_ENTRY_MAX) { + fmerr("Invalid firmware download option\n"); + return -EINVAL; + } + + /* + * Initialize FM common module. FM GPIO toggling is + * taken care in Shared Transport driver. + */ + ret = fmc_prepare(fmdev); + if (ret < 0) { + fmerr("Unable to prepare FM Common\n"); + return ret; + } + + payload = FM_ENABLE; + if (fmc_send_cmd(fmdev, FM_POWER_MODE, REG_WR, &payload, + sizeof(payload), NULL, NULL)) + goto rel; + + /* Allow the chip to settle down in Channel-8 mode */ + msleep(20); + + if (fmc_send_cmd(fmdev, ASIC_ID_GET, REG_RD, NULL, + sizeof(asic_id), &asic_id, &resp_len)) + goto rel; + + if (fmc_send_cmd(fmdev, ASIC_VER_GET, REG_RD, NULL, + sizeof(asic_ver), &asic_ver, &resp_len)) + goto rel; + + fmdbg("ASIC ID: 0x%x , ASIC Version: %d\n", + be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); + + sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START, + be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); + + ret = fm_download_firmware(fmdev, fw_name); + if (ret < 0) { + fmdbg("Failed to download firmware file %s\n", fw_name); + goto rel; + } + sprintf(fw_name, "%s_%x.%d.bts", (mode == FM_MODE_RX) ? + FM_RX_FW_FILE_START : FM_TX_FW_FILE_START, + be16_to_cpu(asic_id), be16_to_cpu(asic_ver)); + + ret = fm_download_firmware(fmdev, fw_name); + if (ret < 0) { + fmdbg("Failed to download firmware file %s\n", fw_name); + goto rel; + } else + return ret; +rel: + return fmc_release(fmdev); +} + +/* Set FM Modes(TX, RX, OFF) */ +u32 fmc_set_mode(struct fmdev *fmdev, u8 fm_mode) +{ + int ret = 0; + + if (fm_mode >= FM_MODE_ENTRY_MAX) { + fmerr("Invalid FM mode\n"); + return -EINVAL; + } + if (fmdev->curr_fmmode == fm_mode) { + fmdbg("Already fm is in mode(%d)\n", fm_mode); + return ret; + } + + switch (fm_mode) { + case FM_MODE_OFF: /* OFF Mode */ + ret = fm_power_down(fmdev); + if (ret < 0) { + fmerr("Failed to set OFF mode\n"); + return ret; + } + break; + + case FM_MODE_TX: /* TX Mode */ + case FM_MODE_RX: /* RX Mode */ + /* Power down before switching to TX or RX mode */ + if (fmdev->curr_fmmode != FM_MODE_OFF) { + ret = fm_power_down(fmdev); + if (ret < 0) { + fmerr("Failed to set OFF mode\n"); + return ret; + } + msleep(30); + } + ret = fm_power_up(fmdev, fm_mode); + if (ret < 0) { + fmerr("Failed to load firmware\n"); + return ret; + } + } + fmdev->curr_fmmode = fm_mode; + + /* Set default configuration */ + if (fmdev->curr_fmmode == FM_MODE_RX) { + fmdbg("Loading default rx configuration..\n"); + ret = load_default_rx_configuration(fmdev); + if (ret < 0) + fmerr("Failed to load default values\n"); + } + + return ret; +} + +/* Returns current FM mode (TX, RX, OFF) */ +u32 fmc_get_mode(struct fmdev *fmdev, u8 *fmmode) +{ + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + fmerr("FM core is not ready\n"); + return -EPERM; + } + if (fmmode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *fmmode = fmdev->curr_fmmode; + return 0; +} + +/* Called by ST layer when FM packet is available */ +static long fm_st_receive(void *arg, struct sk_buff *skb) +{ + struct fmdev *fmdev; + + fmdev = (struct fmdev *)arg; + + if (skb == NULL) { + fmerr("Invalid SKB received from ST\n"); + return -EFAULT; + } + + if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) { + fmerr("Received SKB (%p) is not FM Channel 8 pkt\n", skb); + return -EINVAL; + } + + memcpy(skb_push(skb, 1), &skb->cb[0], 1); + skb_queue_tail(&fmdev->rx_q, skb); + tasklet_schedule(&fmdev->rx_task); + + return 0; +} + +/* + * Called by ST layer to indicate protocol registration completion + * status. + */ +static void fm_st_reg_comp_cb(void *arg, char data) +{ + struct fmdev *fmdev; + + fmdev = (struct fmdev *)arg; + fmdev->streg_cbdata = data; + complete(&wait_for_fmdrv_reg_comp); +} + +/* + * This function will be called from FM V4L2 open function. + * Register with ST driver and initialize driver data. + */ +u32 fmc_prepare(struct fmdev *fmdev) +{ + static struct st_proto_s fm_st_proto; + u32 ret; + + if (test_bit(FM_CORE_READY, &fmdev->flag)) { + fmdbg("FM Core is already up\n"); + return 0; + } + + memset(&fm_st_proto, 0, sizeof(fm_st_proto)); + fm_st_proto.type = ST_FM; + fm_st_proto.recv = fm_st_receive; + fm_st_proto.match_packet = NULL; + fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb; + fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */ + fm_st_proto.priv_data = fmdev; + + ret = st_register(&fm_st_proto); + if (ret == -EINPROGRESS) { + init_completion(&wait_for_fmdrv_reg_comp); + fmdev->streg_cbdata = -EINPROGRESS; + fmdbg("%s waiting for ST reg completion signal\n", __func__); + + ret = wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, + FM_ST_REG_TIMEOUT); + + if (!ret) { + fmerr("Timeout(%d sec), didn't get reg " + "completion signal from ST\n", + jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + if (fmdev->streg_cbdata != 0) { + fmerr("ST reg comp CB called with error " + "status %d\n", fmdev->streg_cbdata); + return -EAGAIN; + } + + ret = 0; + } else if (ret == -1) { + fmerr("st_register failed %d\n", ret); + return -EAGAIN; + } + + if (fm_st_proto.write != NULL) { + g_st_write = fm_st_proto.write; + } else { + fmerr("Failed to get ST write func pointer\n"); + ret = st_unregister(ST_FM); + if (ret < 0) + fmerr("st_unregister failed %d\n", ret); + return -EAGAIN; + } + + spin_lock_init(&fmdev->rds_buff_lock); + spin_lock_init(&fmdev->resp_skb_lock); + + /* Initialize TX queue and TX tasklet */ + skb_queue_head_init(&fmdev->tx_q); + tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev); + + /* Initialize RX Queue and RX tasklet */ + skb_queue_head_init(&fmdev->rx_q); + tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev); + + fmdev->irq_info.stage = 0; + atomic_set(&fmdev->tx_cnt, 1); + fmdev->resp_comp = NULL; + + init_timer(&fmdev->irq_info.timer); + fmdev->irq_info.timer.function = &int_timeout_handler; + fmdev->irq_info.timer.data = (unsigned long)fmdev; + /*TODO: add FM_STIC_EVENT later */ + fmdev->irq_info.mask = FM_MAL_EVENT; + + /* Region info */ + memcpy(&fmdev->rx.region, ®ion_configs[default_radio_region], + sizeof(struct region_info)); + + fmdev->rx.mute_mode = FM_MUTE_OFF; + fmdev->rx.rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF; + fmdev->rx.rds.flag = FM_RDS_DISABLE; + fmdev->rx.freq = FM_UNDEFINED_FREQ; + fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS; + fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF; + fmdev->irq_info.retry = 0; + + fm_rx_reset_rds_cache(fmdev); + init_waitqueue_head(&fmdev->rx.rds.read_queue); + + fm_rx_reset_station_info(fmdev); + set_bit(FM_CORE_READY, &fmdev->flag); + + return ret; +} + +/* + * This function will be called from FM V4L2 release function. + * Unregister from ST driver. + */ +u32 fmc_release(struct fmdev *fmdev) +{ + u32 ret; + + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + fmdbg("FM Core is already down\n"); + return 0; + } + /* Sevice pending read */ + wake_up_interruptible(&fmdev->rx.rds.read_queue); + + tasklet_kill(&fmdev->tx_task); + tasklet_kill(&fmdev->rx_task); + + skb_queue_purge(&fmdev->tx_q); + skb_queue_purge(&fmdev->rx_q); + + fmdev->resp_comp = NULL; + fmdev->rx.freq = 0; + + ret = st_unregister(ST_FM); + if (ret < 0) + fmerr("Failed to de-register FM from ST %d\n", ret); + else + fmdbg("Successfully unregistered from ST\n"); + + clear_bit(FM_CORE_READY, &fmdev->flag); + return ret; +} + +/* + * Module init function. Ask FM V4L module to register video device. + * Allocate memory for FM driver context and RX RDS buffer. + */ +static int __init fm_drv_init(void) +{ + struct fmdev *fmdev = NULL; + u32 ret = -ENOMEM; + + fmdbg("FM driver version %s\n", FM_DRV_VERSION); + + fmdev = kzalloc(sizeof(struct fmdev), GFP_KERNEL); + if (NULL == fmdev) { + fmerr("Can't allocate operation structure memory\n"); + return ret; + } + fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLK_SIZE; + fmdev->rx.rds.buff = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL); + if (NULL == fmdev->rx.rds.buff) { + fmerr("Can't allocate rds ring buffer\n"); + goto rel_dev; + } + + ret = fm_v4l2_init_video_device(fmdev, radio_nr); + if (ret < 0) + goto rel_rdsbuf; + + fmdev->irq_info.handlers = int_handler_table; + fmdev->curr_fmmode = FM_MODE_OFF; + fmdev->tx_data.pwr_lvl = FM_PWR_LVL_DEF; + fmdev->tx_data.preemph = FM_TX_PREEMPH_50US; + return ret; + +rel_rdsbuf: + kfree(fmdev->rx.rds.buff); +rel_dev: + kfree(fmdev); + + return ret; +} + +/* Module exit function. Ask FM V4L module to unregister video device */ +static void __exit fm_drv_exit(void) +{ + struct fmdev *fmdev = NULL; + + fmdev = fm_v4l2_deinit_video_device(); + if (fmdev != NULL) { + kfree(fmdev->rx.rds.buff); + kfree(fmdev); + } +} + +module_init(fm_drv_init); +module_exit(fm_drv_exit); + +/* ------------- Module Info ------------- */ +MODULE_AUTHOR("Manjunatha Halli "); +MODULE_DESCRIPTION("FM Driver for TI's Connectivity chip. " FM_DRV_VERSION); +MODULE_VERSION(FM_DRV_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h new file mode 100644 index 000000000000..427c4164cece --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_common.h @@ -0,0 +1,402 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * FM Common module header file + * + * Copyright (C) 2011 Texas Instruments + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _FMDRV_COMMON_H +#define _FMDRV_COMMON_H + +#define FM_ST_REG_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */ +#define FM_PKT_LOGICAL_CHAN_NUMBER 0x08 /* Logical channel 8 */ + +#define REG_RD 0x1 +#define REG_WR 0x0 + +struct fm_reg_table { + u8 opcode; + u8 type; + u8 *name; +}; + +#define STEREO_GET 0 +#define RSSI_LVL_GET 1 +#define IF_COUNT_GET 2 +#define FLAG_GET 3 +#define RDS_SYNC_GET 4 +#define RDS_DATA_GET 5 +#define FREQ_SET 10 +#define AF_FREQ_SET 11 +#define MOST_MODE_SET 12 +#define MOST_BLEND_SET 13 +#define DEMPH_MODE_SET 14 +#define SEARCH_LVL_SET 15 +#define BAND_SET 16 +#define MUTE_STATUS_SET 17 +#define RDS_PAUSE_LVL_SET 18 +#define RDS_PAUSE_DUR_SET 19 +#define RDS_MEM_SET 20 +#define RDS_BLK_B_SET 21 +#define RDS_MSK_B_SET 22 +#define RDS_PI_MASK_SET 23 +#define RDS_PI_SET 24 +#define RDS_SYSTEM_SET 25 +#define INT_MASK_SET 26 +#define SEARCH_DIR_SET 27 +#define VOLUME_SET 28 +#define AUDIO_ENABLE_SET 29 +#define PCM_MODE_SET 30 +#define I2S_MODE_CONFIG_SET 31 +#define POWER_SET 32 +#define INTX_CONFIG_SET 33 +#define PULL_EN_SET 34 +#define HILO_SET 35 +#define SWITCH2FREF 36 +#define FREQ_DRIFT_REPORT 37 + +#define PCE_GET 40 +#define FIRM_VER_GET 41 +#define ASIC_VER_GET 42 +#define ASIC_ID_GET 43 +#define MAN_ID_GET 44 +#define TUNER_MODE_SET 45 +#define STOP_SEARCH 46 +#define RDS_CNTRL_SET 47 + +#define WRITE_HARDWARE_REG 100 +#define CODE_DOWNLOAD 101 +#define RESET 102 + +#define FM_POWER_MODE 254 +#define FM_INTERRUPT 255 + +/* Transmitter API */ + +#define CHANL_SET 55 +#define CHANL_BW_SET 56 +#define REF_SET 57 +#define POWER_ENB_SET 90 +#define POWER_ATT_SET 58 +#define POWER_LEV_SET 59 +#define AUDIO_DEV_SET 60 +#define PILOT_DEV_SET 61 +#define RDS_DEV_SET 62 +#define TX_BAND_SET 65 +#define PUPD_SET 91 +#define AUDIO_IO_SET 63 +#define PREMPH_SET 64 +#define MONO_SET 66 +#define MUTE 92 +#define MPX_LMT_ENABLE 67 +#define PI_SET 93 +#define ECC_SET 69 +#define PTY 70 +#define AF 71 +#define DISPLAY_MODE 74 +#define RDS_REP_SET 77 +#define RDS_CONFIG_DATA_SET 98 +#define RDS_DATA_SET 99 +#define RDS_DATA_ENB 94 +#define TA_SET 78 +#define TP_SET 79 +#define DI_SET 80 +#define MS_SET 81 +#define PS_SCROLL_SPEED 82 +#define TX_AUDIO_LEVEL_TEST 96 +#define TX_AUDIO_LEVEL_TEST_THRESHOLD 73 +#define TX_AUDIO_INPUT_LEVEL_RANGE_SET 54 +#define RX_ANTENNA_SELECT 87 +#define I2C_DEV_ADDR_SET 86 +#define REF_ERR_CALIB_PARAM_SET 88 +#define REF_ERR_CALIB_PERIODICITY_SET 89 +#define SOC_INT_TRIGGER 52 +#define SOC_AUDIO_PATH_SET 83 +#define SOC_PCMI_OVERRIDE 84 +#define SOC_I2S_OVERRIDE 85 +#define RSSI_BLOCK_SCAN_FREQ_SET 95 +#define RSSI_BLOCK_SCAN_START 97 +#define RSSI_BLOCK_SCAN_DATA_GET 5 +#define READ_FMANT_TUNE_VALUE 104 + +/* SKB helpers */ +struct fm_skb_cb { + __u8 fm_op; + struct completion *completion; +}; + +#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb)) + +/* FM Channel-8 command message format */ +struct fm_cmd_msg_hdr { + __u8 hdr; /* Logical Channel-8 */ + __u8 len; /* Number of bytes follows */ + __u8 op; /* FM Opcode */ + __u8 rd_wr; /* Read/Write command */ + __u8 dlen; /* Length of payload */ +} __attribute__ ((packed)); + +#define FM_CMD_MSG_HDR_SIZE 5 /* sizeof(struct fm_cmd_msg_hdr) */ + +/* FM Channel-8 event messgage format */ +struct fm_event_msg_hdr { + __u8 header; /* Logical Channel-8 */ + __u8 len; /* Number of bytes follows */ + __u8 status; /* Event status */ + __u8 num_fm_hci_cmds; /* Number of pkts the host allowed to send */ + __u8 op; /* FM Opcode */ + __u8 rd_wr; /* Read/Write command */ + __u8 dlen; /* Length of payload */ +} __attribute__ ((packed)); + +#define FM_EVT_MSG_HDR_SIZE 7 /* sizeof(struct fm_event_msg_hdr) */ + +/* TI's magic number in firmware file */ +#define FM_FW_FILE_HEADER_MAGIC 0x42535442 + +#define FM_ENABLE 1 +#define FM_DISABLE 0 + +/* FLAG_GET register bits */ +#define FM_FR_EVENT (1 << 0) +#define FM_BL_EVENT (1 << 1) +#define FM_RDS_EVENT (1 << 2) +#define FM_BBLK_EVENT (1 << 3) +#define FM_LSYNC_EVENT (1 << 4) +#define FM_LEV_EVENT (1 << 5) +#define FM_IFFR_EVENT (1 << 6) +#define FM_PI_EVENT (1 << 7) +#define FM_PD_EVENT (1 << 8) +#define FM_STIC_EVENT (1 << 9) +#define FM_MAL_EVENT (1 << 10) +#define FM_POW_ENB_EVENT (1 << 11) + +/* + * Firmware files of FM. ASIC ID and ASIC version will be appened to this, + * later. + */ +#define FM_FMC_FW_FILE_START ("fmc_ch8") +#define FM_RX_FW_FILE_START ("fm_rx_ch8") +#define FM_TX_FW_FILE_START ("fm_tx_ch8") + +#define FM_UNDEFINED_FREQ 0xFFFFFFFF + +/* Band types */ +#define FM_BAND_EUROPE_US 0 +#define FM_BAND_JAPAN 1 + +/* Seek directions */ +#define FM_SEARCH_DIRECTION_DOWN 0 +#define FM_SEARCH_DIRECTION_UP 1 + +/* Tunner modes */ +#define FM_TUNER_STOP_SEARCH_MODE 0 +#define FM_TUNER_PRESET_MODE 1 +#define FM_TUNER_AUTONOMOUS_SEARCH_MODE 2 +#define FM_TUNER_AF_JUMP_MODE 3 + +/* Min and Max volume */ +#define FM_RX_VOLUME_MIN 0 +#define FM_RX_VOLUME_MAX 70 + +/* Volume gain step */ +#define FM_RX_VOLUME_GAIN_STEP 0x370 + +/* Mute modes */ +#define FM_MUTE_ON 0 +#define FM_MUTE_OFF 1 +#define FM_MUTE_ATTENUATE 2 + +#define FM_RX_UNMUTE_MODE 0x00 +#define FM_RX_RF_DEP_MODE 0x01 +#define FM_RX_AC_MUTE_MODE 0x02 +#define FM_RX_HARD_MUTE_LEFT_MODE 0x04 +#define FM_RX_HARD_MUTE_RIGHT_MODE 0x08 +#define FM_RX_SOFT_MUTE_FORCE_MODE 0x10 + +/* RF dependent mute mode */ +#define FM_RX_RF_DEPENDENT_MUTE_ON 1 +#define FM_RX_RF_DEPENDENT_MUTE_OFF 0 + +/* RSSI threshold min and max */ +#define FM_RX_RSSI_THRESHOLD_MIN -128 +#define FM_RX_RSSI_THRESHOLD_MAX 127 + +/* Stereo/Mono mode */ +#define FM_STEREO_MODE 0 +#define FM_MONO_MODE 1 +#define FM_STEREO_SOFT_BLEND 1 + +/* FM RX De-emphasis filter modes */ +#define FM_RX_EMPHASIS_FILTER_50_USEC 0 +#define FM_RX_EMPHASIS_FILTER_75_USEC 1 + +/* FM RDS modes */ +#define FM_RDS_DISABLE 0 +#define FM_RDS_ENABLE 1 + +#define FM_NO_PI_CODE 0 + +/* FM and RX RDS block enable/disable */ +#define FM_RX_PWR_SET_FM_ON_RDS_OFF 0x1 +#define FM_RX_PWR_SET_FM_AND_RDS_BLK_ON 0x3 +#define FM_RX_PWR_SET_FM_AND_RDS_BLK_OFF 0x0 + +/* RX RDS */ +#define FM_RX_RDS_FLUSH_FIFO 0x1 +#define FM_RX_RDS_FIFO_THRESHOLD 64 /* tuples */ +#define FM_RDS_BLK_SIZE 3 /* 3 bytes */ + +/* RDS block types */ +#define FM_RDS_BLOCK_A 0 +#define FM_RDS_BLOCK_B 1 +#define FM_RDS_BLOCK_C 2 +#define FM_RDS_BLOCK_Ctag 3 +#define FM_RDS_BLOCK_D 4 +#define FM_RDS_BLOCK_E 5 + +#define FM_RDS_BLK_IDX_A 0 +#define FM_RDS_BLK_IDX_B 1 +#define FM_RDS_BLK_IDX_C 2 +#define FM_RDS_BLK_IDX_D 3 +#define FM_RDS_BLK_IDX_UNKNOWN 0xF0 + +#define FM_RDS_STATUS_ERR_MASK 0x18 + +/* + * Represents an RDS group type & version. + * There are 15 groups, each group has 2 versions: A and B. + */ +#define FM_RDS_GROUP_TYPE_MASK_0A ((unsigned long)1<<0) +#define FM_RDS_GROUP_TYPE_MASK_0B ((unsigned long)1<<1) +#define FM_RDS_GROUP_TYPE_MASK_1A ((unsigned long)1<<2) +#define FM_RDS_GROUP_TYPE_MASK_1B ((unsigned long)1<<3) +#define FM_RDS_GROUP_TYPE_MASK_2A ((unsigned long)1<<4) +#define FM_RDS_GROUP_TYPE_MASK_2B ((unsigned long)1<<5) +#define FM_RDS_GROUP_TYPE_MASK_3A ((unsigned long)1<<6) +#define FM_RDS_GROUP_TYPE_MASK_3B ((unsigned long)1<<7) +#define FM_RDS_GROUP_TYPE_MASK_4A ((unsigned long)1<<8) +#define FM_RDS_GROUP_TYPE_MASK_4B ((unsigned long)1<<9) +#define FM_RDS_GROUP_TYPE_MASK_5A ((unsigned long)1<<10) +#define FM_RDS_GROUP_TYPE_MASK_5B ((unsigned long)1<<11) +#define FM_RDS_GROUP_TYPE_MASK_6A ((unsigned long)1<<12) +#define FM_RDS_GROUP_TYPE_MASK_6B ((unsigned long)1<<13) +#define FM_RDS_GROUP_TYPE_MASK_7A ((unsigned long)1<<14) +#define FM_RDS_GROUP_TYPE_MASK_7B ((unsigned long)1<<15) +#define FM_RDS_GROUP_TYPE_MASK_8A ((unsigned long)1<<16) +#define FM_RDS_GROUP_TYPE_MASK_8B ((unsigned long)1<<17) +#define FM_RDS_GROUP_TYPE_MASK_9A ((unsigned long)1<<18) +#define FM_RDS_GROUP_TYPE_MASK_9B ((unsigned long)1<<19) +#define FM_RDS_GROUP_TYPE_MASK_10A ((unsigned long)1<<20) +#define FM_RDS_GROUP_TYPE_MASK_10B ((unsigned long)1<<21) +#define FM_RDS_GROUP_TYPE_MASK_11A ((unsigned long)1<<22) +#define FM_RDS_GROUP_TYPE_MASK_11B ((unsigned long)1<<23) +#define FM_RDS_GROUP_TYPE_MASK_12A ((unsigned long)1<<24) +#define FM_RDS_GROUP_TYPE_MASK_12B ((unsigned long)1<<25) +#define FM_RDS_GROUP_TYPE_MASK_13A ((unsigned long)1<<26) +#define FM_RDS_GROUP_TYPE_MASK_13B ((unsigned long)1<<27) +#define FM_RDS_GROUP_TYPE_MASK_14A ((unsigned long)1<<28) +#define FM_RDS_GROUP_TYPE_MASK_14B ((unsigned long)1<<29) +#define FM_RDS_GROUP_TYPE_MASK_15A ((unsigned long)1<<30) +#define FM_RDS_GROUP_TYPE_MASK_15B ((unsigned long)1<<31) + +/* RX Alternate Frequency info */ +#define FM_RDS_MIN_AF 1 +#define FM_RDS_MAX_AF 204 +#define FM_RDS_MAX_AF_JAPAN 140 +#define FM_RDS_1_AF_FOLLOWS 225 +#define FM_RDS_25_AF_FOLLOWS 249 + +/* RDS system type (RDS/RBDS) */ +#define FM_RDS_SYSTEM_RDS 0 +#define FM_RDS_SYSTEM_RBDS 1 + +/* AF on/off */ +#define FM_RX_RDS_AF_SWITCH_MODE_ON 1 +#define FM_RX_RDS_AF_SWITCH_MODE_OFF 0 + +/* Retry count when interrupt process goes wrong */ +#define FM_IRQ_TIMEOUT_RETRY_MAX 5 /* 5 times */ + +/* Audio IO set values */ +#define FM_RX_AUDIO_ENABLE_I2S 0x01 +#define FM_RX_AUDIO_ENABLE_ANALOG 0x02 +#define FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG 0x03 +#define FM_RX_AUDIO_ENABLE_DISABLE 0x00 + +/* HI/LO set values */ +#define FM_RX_IFFREQ_TO_HI_SIDE 0x0 +#define FM_RX_IFFREQ_TO_LO_SIDE 0x1 +#define FM_RX_IFFREQ_HILO_AUTOMATIC 0x2 + +/* + * Default RX mode configuration. Chip will be configured + * with this default values after loading RX firmware. + */ +#define FM_DEFAULT_RX_VOLUME 10 +#define FM_DEFAULT_RSSI_THRESHOLD 3 + +/* Range for TX power level in units for dB/uV */ +#define FM_PWR_LVL_LOW 91 +#define FM_PWR_LVL_HIGH 122 + +/* Chip specific default TX power level value */ +#define FM_PWR_LVL_DEF 4 + +/* FM TX Pre-emphasis filter values */ +#define FM_TX_PREEMPH_OFF 1 +#define FM_TX_PREEMPH_50US 0 +#define FM_TX_PREEMPH_75US 2 + +/* FM TX antenna impedence values */ +#define FM_TX_ANT_IMP_50 0 +#define FM_TX_ANT_IMP_200 1 +#define FM_TX_ANT_IMP_500 2 + +/* Functions exported by FM common sub-module */ +u32 fmc_prepare(struct fmdev *); +u32 fmc_release(struct fmdev *); + +void fmc_update_region_info(struct fmdev *, u8); +u32 fmc_send_cmd(struct fmdev *, u8, u16, + void *, unsigned int, void *, int *); +u32 fmc_is_rds_data_available(struct fmdev *, struct file *, + struct poll_table_struct *); +u32 fmc_transfer_rds_from_internal_buff(struct fmdev *, struct file *, + u8 __user *, size_t); + +u32 fmc_set_freq(struct fmdev *, u32); +u32 fmc_set_mode(struct fmdev *, u8); +u32 fmc_set_region(struct fmdev *, u8); +u32 fmc_set_mute_mode(struct fmdev *, u8); +u32 fmc_set_stereo_mono(struct fmdev *, u16); +u32 fmc_set_rds_mode(struct fmdev *, u8); + +u32 fmc_get_freq(struct fmdev *, u32 *); +u32 fmc_get_region(struct fmdev *, u8 *); +u32 fmc_get_mode(struct fmdev *, u8 *); + +/* + * channel spacing + */ +#define FM_CHANNEL_SPACING_50KHZ 1 +#define FM_CHANNEL_SPACING_100KHZ 2 +#define FM_CHANNEL_SPACING_200KHZ 4 +#define FM_FREQ_MUL 50 + +#endif + -- cgit v1.2.2 From 59da522a4e1eaa10e3cbb7b86ec94dc42eff0ede Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Tue, 11 Jan 2011 06:37:17 -0300 Subject: [media] drivers:media:radio: wl128x: FM driver RX sources This has implementation for FM RX functionality. It communicates with FM V4l2 module and FM common module Signed-off-by: Manjunatha Halli Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_rx.c | 847 ++++++++++++++++++++++++++++++++++ drivers/media/radio/wl128x/fmdrv_rx.h | 59 +++ 2 files changed, 906 insertions(+) create mode 100644 drivers/media/radio/wl128x/fmdrv_rx.c create mode 100644 drivers/media/radio/wl128x/fmdrv_rx.h (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c new file mode 100644 index 000000000000..ec529b55b040 --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -0,0 +1,847 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * This sub-module of FM driver implements FM RX functionality. + * + * Copyright (C) 2011 Texas Instruments + * Author: Raja Mani + * Author: Manjunatha Halli + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "fmdrv.h" +#include "fmdrv_common.h" +#include "fmdrv_rx.h" + +void fm_rx_reset_rds_cache(struct fmdev *fmdev) +{ + fmdev->rx.rds.flag = FM_RDS_DISABLE; + fmdev->rx.rds.last_blk_idx = 0; + fmdev->rx.rds.wr_idx = 0; + fmdev->rx.rds.rd_idx = 0; + + if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) + fmdev->irq_info.mask |= FM_LEV_EVENT; +} + +void fm_rx_reset_station_info(struct fmdev *fmdev) +{ + fmdev->rx.stat_info.picode = FM_NO_PI_CODE; + fmdev->rx.stat_info.afcache_size = 0; + fmdev->rx.stat_info.af_list_max = 0; +} + +u32 fm_rx_set_freq(struct fmdev *fmdev, u32 freq) +{ + unsigned long timeleft; + u16 payload, curr_frq, intr_flag; + u32 curr_frq_in_khz; + u32 ret, resp_len; + + if (freq < fmdev->rx.region.bot_freq || freq > fmdev->rx.region.top_freq) { + fmerr("Invalid frequency %d\n", freq); + return -EINVAL; + } + + /* Set audio enable */ + payload = FM_RX_AUDIO_ENABLE_I2S_AND_ANALOG; + + ret = fmc_send_cmd(fmdev, AUDIO_ENABLE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set hilo to automatic selection */ + payload = FM_RX_IFFREQ_HILO_AUTOMATIC; + ret = fmc_send_cmd(fmdev, HILO_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Calculate frequency index and set*/ + payload = (freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Read flags - just to clear any pending interrupts if we had */ + ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); + if (ret < 0) + return ret; + + /* Enable FR, BL interrupts */ + intr_flag = fmdev->irq_info.mask; + fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Start tune */ + payload = FM_TUNER_PRESET_MODE; + ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + goto exit; + + /* Wait for tune ended interrupt */ + init_completion(&fmdev->maintask_comp); + timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_TX_TIMEOUT); + if (!timeleft) { + fmerr("Timeout(%d sec),didn't get tune ended int\n", + jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); + ret = -ETIMEDOUT; + goto exit; + } + + /* Read freq back to confirm */ + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, &curr_frq, &resp_len); + if (ret < 0) + goto exit; + + curr_frq = be16_to_cpu(curr_frq); + curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); + + if (curr_frq_in_khz != freq) { + pr_info("Frequency is set to (%d) but " + "requested freq is (%d)\n", curr_frq_in_khz, freq); + } + + /* Update local cache */ + fmdev->rx.freq = curr_frq_in_khz; +exit: + /* Re-enable default FM interrupts */ + fmdev->irq_info.mask = intr_flag; + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Reset RDS cache and current station pointers */ + fm_rx_reset_rds_cache(fmdev); + fm_rx_reset_station_info(fmdev); + + return ret; +} + +static u32 fm_rx_set_channel_spacing(struct fmdev *fmdev, u32 spacing) +{ + u16 payload; + u32 ret; + + if (spacing > 0 && spacing <= 50000) + spacing = FM_CHANNEL_SPACING_50KHZ; + else if (spacing > 50000 && spacing <= 100000) + spacing = FM_CHANNEL_SPACING_100KHZ; + else + spacing = FM_CHANNEL_SPACING_200KHZ; + + /* set channel spacing */ + payload = spacing; + ret = fmc_send_cmd(fmdev, CHANL_BW_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.region.chanl_space = spacing * FM_FREQ_MUL; + + return ret; +} + +u32 fm_rx_seek(struct fmdev *fmdev, u32 seek_upward, + u32 wrap_around, u32 spacing) +{ + u32 resp_len; + u16 curr_frq, next_frq, last_frq; + u16 payload, int_reason, intr_flag; + u16 offset, space_idx; + unsigned long timeleft; + u32 ret; + + /* Set channel spacing */ + ret = fm_rx_set_channel_spacing(fmdev, spacing); + if (ret < 0) { + fmerr("Failed to set channel spacing\n"); + return ret; + } + + /* Read the current frequency from chip */ + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, + sizeof(curr_frq), &curr_frq, &resp_len); + if (ret < 0) + return ret; + + curr_frq = be16_to_cpu(curr_frq); + last_frq = (fmdev->rx.region.top_freq - fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + + /* Check the offset in order to be aligned to the channel spacing*/ + space_idx = fmdev->rx.region.chanl_space / FM_FREQ_MUL; + offset = curr_frq % space_idx; + + next_frq = seek_upward ? curr_frq + space_idx /* Seek Up */ : + curr_frq - space_idx /* Seek Down */ ; + + /* + * Add or subtract offset in order to stay aligned to the channel + * spacing. + */ + if ((short)next_frq < 0) + next_frq = last_frq - offset; + else if (next_frq > last_frq) + next_frq = 0 + offset; + +again: + /* Set calculated next frequency to perform seek */ + payload = next_frq; + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set search direction (0:Seek Down, 1:Seek Up) */ + payload = (seek_upward ? FM_SEARCH_DIRECTION_UP : FM_SEARCH_DIRECTION_DOWN); + ret = fmc_send_cmd(fmdev, SEARCH_DIR_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Read flags - just to clear any pending interrupts if we had */ + ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, NULL, NULL); + if (ret < 0) + return ret; + + /* Enable FR, BL interrupts */ + intr_flag = fmdev->irq_info.mask; + fmdev->irq_info.mask = (FM_FR_EVENT | FM_BL_EVENT); + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Start seek */ + payload = FM_TUNER_AUTONOMOUS_SEARCH_MODE; + ret = fmc_send_cmd(fmdev, TUNER_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Wait for tune ended/band limit reached interrupt */ + init_completion(&fmdev->maintask_comp); + timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_RX_SEEK_TIMEOUT); + if (!timeleft) { + fmerr("Timeout(%d sec),didn't get tune ended int\n", + jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + + int_reason = fmdev->irq_info.flag & (FM_TUNE_COMPLETE | FM_BAND_LIMIT); + + /* Re-enable default FM interrupts */ + fmdev->irq_info.mask = intr_flag; + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + if (int_reason & FM_BL_EVENT) { + if (wrap_around == 0) { + fmdev->rx.freq = seek_upward ? + fmdev->rx.region.top_freq : + fmdev->rx.region.bot_freq; + } else { + fmdev->rx.freq = seek_upward ? + fmdev->rx.region.bot_freq : + fmdev->rx.region.top_freq; + /* Calculate frequency index to write */ + next_frq = (fmdev->rx.freq - + fmdev->rx.region.bot_freq) / FM_FREQ_MUL; + goto again; + } + } else { + /* Read freq to know where operation tune operation stopped */ + ret = fmc_send_cmd(fmdev, FREQ_SET, REG_RD, NULL, 2, + &curr_frq, &resp_len); + if (ret < 0) + return ret; + + curr_frq = be16_to_cpu(curr_frq); + fmdev->rx.freq = (fmdev->rx.region.bot_freq + + ((u32)curr_frq * FM_FREQ_MUL)); + + } + /* Reset RDS cache and current station pointers */ + fm_rx_reset_rds_cache(fmdev); + fm_rx_reset_station_info(fmdev); + + return ret; +} + +u32 fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) { + fmerr("Volume is not within(%d-%d) range\n", + FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX); + return -EINVAL; + } + vol_to_set *= FM_RX_VOLUME_GAIN_STEP; + + payload = vol_to_set; + ret = fmc_send_cmd(fmdev, VOLUME_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.volume = vol_to_set; + return ret; +} + +/* Get volume */ +u32 fm_rx_get_volume(struct fmdev *fmdev, u16 *curr_vol) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_vol == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_vol = fmdev->rx.volume / FM_RX_VOLUME_GAIN_STEP; + + return 0; +} + +/* To get current band's bottom and top frequency */ +u32 fm_rx_get_band_freq_range(struct fmdev *fmdev, u32 *bot_freq, u32 *top_freq) +{ + if (bot_freq != NULL) + *bot_freq = fmdev->rx.region.bot_freq; + + if (top_freq != NULL) + *top_freq = fmdev->rx.region.top_freq; + + return 0; +} + +/* Returns current band index (0-Europe/US; 1-Japan) */ +void fm_rx_get_region(struct fmdev *fmdev, u8 *region) +{ + *region = fmdev->rx.region.fm_band; +} + +/* Sets band (0-Europe/US; 1-Japan) */ +u32 fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) +{ + u16 payload; + u32 new_frq = 0; + u32 ret; + + if (region_to_set != FM_BAND_EUROPE_US && + region_to_set != FM_BAND_JAPAN) { + fmerr("Invalid band\n"); + return -EINVAL; + } + + if (fmdev->rx.region.fm_band == region_to_set) { + fmerr("Requested band is already configured\n"); + return 0; + } + + /* Send cmd to set the band */ + payload = (u16)region_to_set; + ret = fmc_send_cmd(fmdev, BAND_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmc_update_region_info(fmdev, region_to_set); + + /* Check whether current RX frequency is within band boundary */ + if (fmdev->rx.freq < fmdev->rx.region.bot_freq) + new_frq = fmdev->rx.region.bot_freq; + else if (fmdev->rx.freq > fmdev->rx.region.top_freq) + new_frq = fmdev->rx.region.top_freq; + + if (new_frq) { + fmdbg("Current freq is not within band limit boundary," + "switching to %d KHz\n", new_frq); + /* Current RX frequency is not in range. So, update it */ + ret = fm_rx_set_freq(fmdev, new_frq); + } + + return ret; +} + +/* Reads current mute mode (Mute Off/On/Attenuate)*/ +u32 fm_rx_get_mute_mode(struct fmdev *fmdev, u8 *curr_mute_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_mute_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_mute_mode = fmdev->rx.mute_mode; + + return 0; +} + +static u32 fm_config_rx_mute_reg(struct fmdev *fmdev) +{ + u16 payload, muteval; + u32 ret; + + muteval = 0; + switch (fmdev->rx.mute_mode) { + case FM_MUTE_ON: + muteval = FM_RX_AC_MUTE_MODE; + break; + + case FM_MUTE_OFF: + muteval = FM_RX_UNMUTE_MODE; + break; + + case FM_MUTE_ATTENUATE: + muteval = FM_RX_SOFT_MUTE_FORCE_MODE; + break; + } + if (fmdev->rx.rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON) + muteval |= FM_RX_RF_DEP_MODE; + else + muteval &= ~FM_RX_RF_DEP_MODE; + + payload = muteval; + ret = fmc_send_cmd(fmdev, MUTE_STATUS_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +/* Configures mute mode (Mute Off/On/Attenuate) */ +u32 fm_rx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +{ + u8 org_state; + u32 ret; + + if (fmdev->rx.mute_mode == mute_mode_toset) + return 0; + + org_state = fmdev->rx.mute_mode; + fmdev->rx.mute_mode = mute_mode_toset; + + ret = fm_config_rx_mute_reg(fmdev); + if (ret < 0) { + fmdev->rx.mute_mode = org_state; + return ret; + } + + return 0; +} + +/* Gets RF dependent soft mute mode enable/disable status */ +u32 fm_rx_get_rfdepend_softmute(struct fmdev *fmdev, u8 *curr_mute_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_mute_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_mute_mode = fmdev->rx.rf_depend_mute; + + return 0; +} + +/* Sets RF dependent soft mute mode */ +u32 fm_rx_set_rfdepend_softmute(struct fmdev *fmdev, u8 rfdepend_mute) +{ + u8 org_state; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON && + rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) { + fmerr("Invalid RF dependent soft mute\n"); + return -EINVAL; + } + if (fmdev->rx.rf_depend_mute == rfdepend_mute) + return 0; + + org_state = fmdev->rx.rf_depend_mute; + fmdev->rx.rf_depend_mute = rfdepend_mute; + + ret = fm_config_rx_mute_reg(fmdev); + if (ret < 0) { + fmdev->rx.rf_depend_mute = org_state; + return ret; + } + + return 0; +} + +/* Returns the signal strength level of current channel */ +u32 fm_rx_get_rssi_level(struct fmdev *fmdev, u16 *rssilvl) +{ + u16 curr_rssi_lel; + u32 resp_len; + u32 ret; + + if (rssilvl == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + /* Read current RSSI level */ + ret = fmc_send_cmd(fmdev, RSSI_LVL_GET, REG_RD, NULL, 2, + &curr_rssi_lel, &resp_len); + if (ret < 0) + return ret; + + *rssilvl = be16_to_cpu(curr_rssi_lel); + + return 0; +} + +/* + * Sets the signal strength level that once reached + * will stop the auto search process + */ +u32 fm_rx_set_rssi_threshold(struct fmdev *fmdev, short rssi_lvl_toset) +{ + u16 payload; + u32 ret; + + if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN || + rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) { + fmerr("Invalid RSSI threshold level\n"); + return -EINVAL; + } + payload = (u16)rssi_lvl_toset; + ret = fmc_send_cmd(fmdev, SEARCH_LVL_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.rssi_threshold = rssi_lvl_toset; + + return 0; +} + +/* Returns current RX RSSI threshold value */ +u32 fm_rx_get_rssi_threshold(struct fmdev *fmdev, short *curr_rssi_lvl) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_rssi_lvl == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_rssi_lvl = fmdev->rx.rssi_threshold; + + return 0; +} + +/* Sets RX stereo/mono modes */ +u32 fm_rx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +{ + u16 payload; + u32 ret; + + if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) { + fmerr("Invalid mode\n"); + return -EINVAL; + } + + /* Set stereo/mono mode */ + payload = (u16)mode; + ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set stereo blending mode */ + payload = FM_STEREO_SOFT_BLEND; + ret = fmc_send_cmd(fmdev, MOST_BLEND_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +/* Gets current RX stereo/mono mode */ +u32 fm_rx_get_stereo_mono(struct fmdev *fmdev, u16 *mode) +{ + u16 curr_mode; + u32 ret, resp_len; + + if (mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + ret = fmc_send_cmd(fmdev, MOST_MODE_SET, REG_RD, NULL, 2, + &curr_mode, &resp_len); + if (ret < 0) + return ret; + + *mode = be16_to_cpu(curr_mode); + + return 0; +} + +/* Choose RX de-emphasis filter mode (50us/75us) */ +u32 fm_rx_set_deemphasis_mode(struct fmdev *fmdev, u16 mode) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (mode != FM_RX_EMPHASIS_FILTER_50_USEC && + mode != FM_RX_EMPHASIS_FILTER_75_USEC) { + fmerr("Invalid rx de-emphasis mode (%d)\n", mode); + return -EINVAL; + } + + payload = mode; + ret = fmc_send_cmd(fmdev, DEMPH_MODE_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.deemphasis_mode = mode; + + return 0; +} + +/* Gets current RX de-emphasis filter mode */ +u32 fm_rx_get_deemph_mode(struct fmdev *fmdev, u16 *curr_deemphasis_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_deemphasis_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_deemphasis_mode = fmdev->rx.deemphasis_mode; + + return 0; +} + +/* Enable/Disable RX RDS */ +u32 fm_rx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +{ + u16 payload; + u32 ret; + + if (rds_en_dis != FM_RDS_ENABLE && rds_en_dis != FM_RDS_DISABLE) { + fmerr("Invalid rds option\n"); + return -EINVAL; + } + + if (rds_en_dis == FM_RDS_ENABLE + && fmdev->rx.rds.flag == FM_RDS_DISABLE) { + /* Turn on RX RDS and RDS circuit */ + payload = FM_RX_PWR_SET_FM_AND_RDS_BLK_ON; + ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Clear and reset RDS FIFO */ + payload = FM_RX_RDS_FLUSH_FIFO; + ret = fmc_send_cmd(fmdev, RDS_CNTRL_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Read flags - just to clear any pending interrupts. */ + ret = fmc_send_cmd(fmdev, FLAG_GET, REG_RD, NULL, 2, + NULL, NULL); + if (ret < 0) + return ret; + + /* Set RDS FIFO threshold value */ + payload = FM_RX_RDS_FIFO_THRESHOLD; + ret = fmc_send_cmd(fmdev, RDS_MEM_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Enable RDS interrupt */ + fmdev->irq_info.mask |= FM_RDS_EVENT; + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) { + fmdev->irq_info.mask &= ~FM_RDS_EVENT; + return ret; + } + + /* Update our local flag */ + fmdev->rx.rds.flag = FM_RDS_ENABLE; + } else if (rds_en_dis == FM_RDS_DISABLE + && fmdev->rx.rds.flag == FM_RDS_ENABLE) { + /* Turn off RX RDS */ + payload = FM_RX_PWR_SET_FM_ON_RDS_OFF; + ret = fmc_send_cmd(fmdev, POWER_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Reset RDS pointers */ + fmdev->rx.rds.last_blk_idx = 0; + fmdev->rx.rds.wr_idx = 0; + fmdev->rx.rds.rd_idx = 0; + fm_rx_reset_station_info(fmdev); + + /* Update RDS local cache */ + fmdev->irq_info.mask &= ~(FM_RDS_EVENT); + fmdev->rx.rds.flag = FM_RDS_DISABLE; + } + + return 0; +} + +/* Returns current RX RDS enable/disable status */ +u32 fm_rx_get_rds_mode(struct fmdev *fmdev, u8 *curr_rds_en_dis) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (curr_rds_en_dis == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *curr_rds_en_dis = fmdev->rx.rds.flag; + + return 0; +} + +/* Sets RDS operation mode (RDS/RDBS) */ +u32 fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) { + fmerr("Invalid rds mode\n"); + return -EINVAL; + } + /* Set RDS operation mode */ + payload = (u16)rds_mode; + ret = fmc_send_cmd(fmdev, RDS_SYSTEM_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.rds_mode = rds_mode; + + return 0; +} + +/* Returns current RDS operation mode */ +u32 fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (rds_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *rds_mode = fmdev->rx.rds_mode; + + return 0; +} + +/* Configures Alternate Frequency switch mode */ +u32 fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON && + af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) { + fmerr("Invalid af mode\n"); + return -EINVAL; + } + /* Enable/disable low RSSI interrupt based on af_mode */ + if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) + fmdev->irq_info.mask |= FM_LEV_EVENT; + else + fmdev->irq_info.mask &= ~FM_LEV_EVENT; + + payload = fmdev->irq_info.mask; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->rx.af_mode = af_mode; + + return 0; +} + +/* Returns Alternate Frequency switch status */ +u32 fm_rx_get_af_switch(struct fmdev *fmdev, u8 *af_mode) +{ + if (fmdev->curr_fmmode != FM_MODE_RX) + return -EPERM; + + if (af_mode == NULL) { + fmerr("Invalid memory\n"); + return -ENOMEM; + } + + *af_mode = fmdev->rx.af_mode; + + return 0; +} diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h new file mode 100644 index 000000000000..329e62f6be76 --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_rx.h @@ -0,0 +1,59 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * FM RX module header. + * + * Copyright (C) 2011 Texas Instruments + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _FMDRV_RX_H +#define _FMDRV_RX_H + +u32 fm_rx_set_freq(struct fmdev *, u32); +u32 fm_rx_set_mute_mode(struct fmdev *, u8); +u32 fm_rx_set_stereo_mono(struct fmdev *, u16); +u32 fm_rx_set_rds_mode(struct fmdev *, u8); +u32 fm_rx_set_rds_system(struct fmdev *, u8); +u32 fm_rx_set_volume(struct fmdev *, u16); +u32 fm_rx_set_rssi_threshold(struct fmdev *, short); +u32 fm_rx_set_region(struct fmdev *, u8); +u32 fm_rx_set_rfdepend_softmute(struct fmdev *, u8); +u32 fm_rx_set_deemphasis_mode(struct fmdev *, u16); +u32 fm_rx_set_af_switch(struct fmdev *, u8); + +void fm_rx_reset_rds_cache(struct fmdev *); +void fm_rx_reset_station_info(struct fmdev *); + +u32 fm_rx_seek(struct fmdev *, u32, u32, u32); + +u32 fm_rx_get_rds_mode(struct fmdev *, u8 *); +u32 fm_rx_get_rds_system(struct fmdev *, u8 *); +u32 fm_rx_get_mute_mode(struct fmdev *, u8 *); +u32 fm_rx_get_volume(struct fmdev *, u16 *); +u32 fm_rx_get_band_freq_range(struct fmdev *, + u32 *, u32 *); +u32 fm_rx_get_stereo_mono(struct fmdev *, u16 *); +u32 fm_rx_get_rssi_level(struct fmdev *, u16 *); +u32 fm_rx_get_rssi_threshold(struct fmdev *, short *); +u32 fm_rx_get_rfdepend_softmute(struct fmdev *, u8 *); +u32 fm_rx_get_deemph_mode(struct fmdev *, u16 *); +u32 fm_rx_get_af_switch(struct fmdev *, u8 *); +void fm_rx_get_region(struct fmdev *, u8 *); + +u32 fm_rx_set_chanl_spacing(struct fmdev *, u8); +u32 fm_rx_get_chanl_spacing(struct fmdev *, u8 *); +#endif + -- cgit v1.2.2 From 8b7a186c9b9322a4519af710736210bf8d5aa7a7 Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Tue, 11 Jan 2011 06:37:53 -0300 Subject: [media] drivers:media:radio: wl128x: FM driver TX sources This has implementation for FM TX functionality. It communicates with FM V4l2 module and FM common module. Signed-off-by: Manjunatha Halli Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_tx.c | 425 ++++++++++++++++++++++++++++++++++ drivers/media/radio/wl128x/fmdrv_tx.h | 37 +++ 2 files changed, 462 insertions(+) create mode 100644 drivers/media/radio/wl128x/fmdrv_tx.c create mode 100644 drivers/media/radio/wl128x/fmdrv_tx.h (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_tx.c b/drivers/media/radio/wl128x/fmdrv_tx.c new file mode 100644 index 000000000000..be54068b56a8 --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_tx.c @@ -0,0 +1,425 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * This sub-module of FM driver implements FM TX functionality. + * + * Copyright (C) 2011 Texas Instruments + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include "fmdrv.h" +#include "fmdrv_common.h" +#include "fmdrv_tx.h" + +u32 fm_tx_set_stereo_mono(struct fmdev *fmdev, u16 mode) +{ + u16 payload; + u32 ret; + + if (fmdev->tx_data.aud_mode == mode) + return 0; + + fmdbg("stereo mode: %d\n", mode); + + /* Set Stereo/Mono mode */ + payload = (1 - mode); + ret = fmc_send_cmd(fmdev, MONO_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fmdev->tx_data.aud_mode = mode; + + return ret; +} + +static u32 set_rds_text(struct fmdev *fmdev, u8 *rds_text) +{ + u16 payload; + u32 ret; + + ret = fmc_send_cmd(fmdev, RDS_DATA_SET, REG_WR, rds_text, + strlen(rds_text), NULL, NULL); + if (ret < 0) + return ret; + + /* Scroll mode */ + payload = (u16)0x1; + ret = fmc_send_cmd(fmdev, DISPLAY_MODE, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +static u32 set_rds_data_mode(struct fmdev *fmdev, u8 mode) +{ + u16 payload; + u32 ret; + + /* Setting unique PI TODO: how unique? */ + payload = (u16)0xcafe; + ret = fmc_send_cmd(fmdev, PI_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set decoder id */ + payload = (u16)0xa; + ret = fmc_send_cmd(fmdev, DI_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: RDS_MODE_GET? */ + return 0; +} + +static u32 set_rds_len(struct fmdev *fmdev, u8 type, u16 len) +{ + u16 payload; + u32 ret; + + len |= type << 8; + payload = len; + ret = fmc_send_cmd(fmdev, RDS_CONFIG_DATA_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: LENGTH_GET? */ + return 0; +} + +u32 fm_tx_set_rds_mode(struct fmdev *fmdev, u8 rds_en_dis) +{ + u16 payload; + u32 ret; + u8 rds_text[] = "Zoom2\n"; + + fmdbg("rds_en_dis:%d(E:%d, D:%d)\n", rds_en_dis, + FM_RDS_ENABLE, FM_RDS_DISABLE); + + if (rds_en_dis == FM_RDS_ENABLE) { + /* Set RDS length */ + set_rds_len(fmdev, 0, strlen(rds_text)); + + /* Set RDS text */ + set_rds_text(fmdev, rds_text); + + /* Set RDS mode */ + set_rds_data_mode(fmdev, 0x0); + } + + /* Send command to enable RDS */ + if (rds_en_dis == FM_RDS_ENABLE) + payload = 0x01; + else + payload = 0x00; + + ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + if (rds_en_dis == FM_RDS_ENABLE) { + /* Set RDS length */ + set_rds_len(fmdev, 0, strlen(rds_text)); + + /* Set RDS text */ + set_rds_text(fmdev, rds_text); + } + fmdev->tx_data.rds.flag = rds_en_dis; + + return 0; +} + +u32 fm_tx_set_radio_text(struct fmdev *fmdev, u8 *rds_text, u8 rds_type) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + fm_tx_set_rds_mode(fmdev, 0); + + /* Set RDS length */ + set_rds_len(fmdev, rds_type, strlen(rds_text)); + + /* Set RDS text */ + set_rds_text(fmdev, rds_text); + + /* Set RDS mode */ + set_rds_data_mode(fmdev, 0x0); + + payload = 1; + ret = fmc_send_cmd(fmdev, RDS_DATA_ENB, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +u32 fm_tx_set_af(struct fmdev *fmdev, u32 af) +{ + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + fmdbg("AF: %d\n", af); + + af = (af - 87500) / 100; + payload = (u16)af; + ret = fmc_send_cmd(fmdev, TA_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +u32 fm_tx_set_region(struct fmdev *fmdev, u8 region) +{ + u16 payload; + u32 ret; + + if (region != FM_BAND_EUROPE_US && region != FM_BAND_JAPAN) { + fmerr("Invalid band\n"); + return -EINVAL; + } + + /* Send command to set the band */ + payload = (u16)region; + ret = fmc_send_cmd(fmdev, TX_BAND_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +u32 fm_tx_set_mute_mode(struct fmdev *fmdev, u8 mute_mode_toset) +{ + u16 payload; + u32 ret; + + fmdbg("tx: mute mode %d\n", mute_mode_toset); + + payload = mute_mode_toset; + ret = fmc_send_cmd(fmdev, MUTE, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + return 0; +} + +/* Set TX Audio I/O */ +static u32 set_audio_io(struct fmdev *fmdev) +{ + struct fmtx_data *tx = &fmdev->tx_data; + u16 payload; + u32 ret; + + /* Set Audio I/O Enable */ + payload = tx->audio_io; + ret = fmc_send_cmd(fmdev, AUDIO_IO_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: is audio set? */ + return 0; +} + +/* Start TX Transmission */ +static u32 enable_xmit(struct fmdev *fmdev, u8 new_xmit_state) +{ + struct fmtx_data *tx = &fmdev->tx_data; + unsigned long timeleft; + u16 payload; + u32 ret; + + /* Enable POWER_ENB interrupts */ + payload = FM_POW_ENB_EVENT; + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Set Power Enable */ + payload = new_xmit_state; + ret = fmc_send_cmd(fmdev, POWER_ENB_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* Wait for Power Enabled */ + init_completion(&fmdev->maintask_comp); + timeleft = wait_for_completion_timeout(&fmdev->maintask_comp, + FM_DRV_TX_TIMEOUT); + if (!timeleft) { + fmerr("Timeout(%d sec),didn't get tune ended interrupt\n", + jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); + return -ETIMEDOUT; + } + + set_bit(FM_CORE_TX_XMITING, &fmdev->flag); + tx->xmit_state = new_xmit_state; + + return 0; +} + +/* Set TX power level */ +u32 fm_tx_set_pwr_lvl(struct fmdev *fmdev, u8 new_pwr_lvl) +{ + u16 payload; + struct fmtx_data *tx = &fmdev->tx_data; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + fmdbg("tx: pwr_level_to_set %ld\n", (long int)new_pwr_lvl); + + /* If the core isn't ready update global variable */ + if (!test_bit(FM_CORE_READY, &fmdev->flag)) { + tx->pwr_lvl = new_pwr_lvl; + return 0; + } + + /* Set power level: Application will specify power level value in + * units of dB/uV, whereas range and step are specific to FM chip. + * For TI's WL chips, convert application specified power level value + * to chip specific value by subtracting 122 from it. Refer to TI FM + * data sheet for details. + * */ + + payload = (FM_PWR_LVL_HIGH - new_pwr_lvl); + ret = fmc_send_cmd(fmdev, POWER_LEV_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + /* TODO: is the power level set? */ + tx->pwr_lvl = new_pwr_lvl; + + return 0; +} + +/* + * Sets FM TX pre-emphasis filter value (OFF, 50us, or 75us) + * Convert V4L2 specified filter values to chip specific filter values. + */ +u32 fm_tx_set_preemph_filter(struct fmdev *fmdev, u32 preemphasis) +{ + struct fmtx_data *tx = &fmdev->tx_data; + u16 payload; + u32 ret; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + switch (preemphasis) { + case V4L2_PREEMPHASIS_DISABLED: + payload = FM_TX_PREEMPH_OFF; + break; + case V4L2_PREEMPHASIS_50_uS: + payload = FM_TX_PREEMPH_50US; + break; + case V4L2_PREEMPHASIS_75_uS: + payload = FM_TX_PREEMPH_75US; + break; + } + + ret = fmc_send_cmd(fmdev, PREMPH_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + tx->preemph = payload; + + return ret; +} + +/* Get the TX tuning capacitor value.*/ +u32 fm_tx_get_tune_cap_val(struct fmdev *fmdev) +{ + u16 curr_val; + u32 ret, resp_len; + + if (fmdev->curr_fmmode != FM_MODE_TX) + return -EPERM; + + ret = fmc_send_cmd(fmdev, READ_FMANT_TUNE_VALUE, REG_RD, + NULL, sizeof(curr_val), &curr_val, &resp_len); + if (ret < 0) + return ret; + + curr_val = be16_to_cpu(curr_val); + + return curr_val; +} + +/* Set TX Frequency */ +u32 fm_tx_set_freq(struct fmdev *fmdev, u32 freq_to_set) +{ + struct fmtx_data *tx = &fmdev->tx_data; + u16 payload, chanl_index; + u32 ret; + + if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) { + enable_xmit(fmdev, 0); + clear_bit(FM_CORE_TX_XMITING, &fmdev->flag); + } + + /* Enable FR, BL interrupts */ + payload = (FM_FR_EVENT | FM_BL_EVENT); + ret = fmc_send_cmd(fmdev, INT_MASK_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + tx->tx_frq = (unsigned long)freq_to_set; + fmdbg("tx: freq_to_set %ld\n", (long int)tx->tx_frq); + + chanl_index = freq_to_set / 10; + + /* Set current tuner channel */ + payload = chanl_index; + ret = fmc_send_cmd(fmdev, CHANL_SET, REG_WR, &payload, + sizeof(payload), NULL, NULL); + if (ret < 0) + return ret; + + fm_tx_set_pwr_lvl(fmdev, tx->pwr_lvl); + fm_tx_set_preemph_filter(fmdev, tx->preemph); + + tx->audio_io = 0x01; /* I2S */ + set_audio_io(fmdev); + + enable_xmit(fmdev, 0x01); /* Enable transmission */ + + tx->aud_mode = FM_STEREO_MODE; + tx->rds.flag = FM_RDS_DISABLE; + + return 0; +} + diff --git a/drivers/media/radio/wl128x/fmdrv_tx.h b/drivers/media/radio/wl128x/fmdrv_tx.h new file mode 100644 index 000000000000..e393a2bdd49e --- /dev/null +++ b/drivers/media/radio/wl128x/fmdrv_tx.h @@ -0,0 +1,37 @@ +/* + * FM Driver for Connectivity chip of Texas Instruments. + * FM TX module header. + * + * Copyright (C) 2011 Texas Instruments + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _FMDRV_TX_H +#define _FMDRV_TX_H + +u32 fm_tx_set_freq(struct fmdev *, u32); +u32 fm_tx_set_pwr_lvl(struct fmdev *, u8); +u32 fm_tx_set_region(struct fmdev *, u8); +u32 fm_tx_set_mute_mode(struct fmdev *, u8); +u32 fm_tx_set_stereo_mono(struct fmdev *, u16); +u32 fm_tx_set_rds_mode(struct fmdev *, u8); +u32 fm_tx_set_radio_text(struct fmdev *, u8 *, u8); +u32 fm_tx_set_af(struct fmdev *, u32); +u32 fm_tx_set_preemph_filter(struct fmdev *, u32); +u32 fm_tx_get_tune_cap_val(struct fmdev *); + +#endif + -- cgit v1.2.2 From a68793d2dac1f753b82e55fb5c6b7dccff1ca4e4 Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Tue, 11 Jan 2011 06:39:22 -0300 Subject: [media] drivers:media:radio: wl128x: Kconfig & Makefile for wl128x driver Signed-off-by: Manjunatha Halli Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/Kconfig | 17 +++++++++++++++++ drivers/media/radio/wl128x/Makefile | 6 ++++++ 2 files changed, 23 insertions(+) create mode 100644 drivers/media/radio/wl128x/Kconfig create mode 100644 drivers/media/radio/wl128x/Makefile (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig new file mode 100644 index 000000000000..749f67b192e7 --- /dev/null +++ b/drivers/media/radio/wl128x/Kconfig @@ -0,0 +1,17 @@ +# +# TI's wl128x FM driver based on TI's ST driver. +# +menu "Texas Instruments WL128x FM driver (ST based)" +config RADIO_WL128X + tristate "Texas Instruments WL128x FM Radio" + depends on VIDEO_V4L2 && RFKILL + select TI_ST + help + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . + +endmenu diff --git a/drivers/media/radio/wl128x/Makefile b/drivers/media/radio/wl128x/Makefile new file mode 100644 index 000000000000..32a0ead09845 --- /dev/null +++ b/drivers/media/radio/wl128x/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for TI's shared transport driver based wl128x +# FM radio. +# +obj-$(CONFIG_RADIO_WL128X) += fm_drv.o +fm_drv-objs := fmdrv_common.o fmdrv_rx.o fmdrv_tx.o fmdrv_v4l2.o -- cgit v1.2.2 From 57f05bfa2e90fe52fa36755f4cb91e6f495f8353 Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Mon, 24 Jan 2011 02:26:59 -0300 Subject: [media] drivers:media:radio: Update Kconfig and Makefile for wl128x FM driver Signed-off-by: Manjunatha Halli Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 3 +++ drivers/media/radio/Makefile | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index ecdffa6aac66..f75cdad2df59 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -454,4 +454,7 @@ config RADIO_WL1273 To compile this driver as a module, choose M here: the module will be called radio-wl1273. +# TI's ST based wl128x FM radio +source "drivers/media/radio/wl128x/Kconfig" + endif # RADIO_ADAPTERS diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 717656d2f749..2faa33371986 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o obj-$(CONFIG_RADIO_TEF6862) += tef6862.o obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o +obj-$(CONFIG_RADIO_WL128X) += wl128x/ EXTRA_CFLAGS += -Isound -- cgit v1.2.2 From 07988007f8dd2827ba1eb39e6e3c5bbb29cfc30b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 Feb 2011 07:10:08 -0300 Subject: [media] stv090x: handle allocation failures kmalloc() can fail so check whether state->internal is NULL. append_internal() can return NULL on allocation failures so check that. Also if we hit the error condition later in the function then there is a memory leak and we need to call remove_dev() to fix it. Also Oliver Endriss pointed out an additional leak that I missed in the first version of this patch. Signed-off-by: Dan Carpenter Acked-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv090x.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index d3362d0407eb..41d0f0a6655d 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -4783,7 +4783,13 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, } else { state->internal = kmalloc(sizeof(struct stv090x_internal), GFP_KERNEL); + if (!state->internal) + goto error; temp_int = append_internal(state->internal); + if (!temp_int) { + kfree(state->internal); + goto error; + } state->internal->num_used = 1; state->internal->mclk = 0; state->internal->dev_ver = 0; @@ -4796,7 +4802,7 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, if (stv090x_setup(&state->frontend) < 0) { dprintk(FE_ERROR, 1, "Error setting up device"); - goto error; + goto err_remove; } } @@ -4811,6 +4817,9 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config, return &state->frontend; +err_remove: + remove_dev(state->internal); + kfree(state->internal); error: kfree(state); return NULL; -- cgit v1.2.2 From 498e677cfd78b098342640f382293782bfa0bd63 Mon Sep 17 00:00:00 2001 From: Lukas Max Fisch Date: Tue, 8 Feb 2011 16:51:45 -0300 Subject: [media] Technisat AirStar TeleStick 2 Based on staging 2.6.39. This patch is based on Veit Berwig's work. Signed-off-by: Lukas Fisch Thanks-to: Veit Berwig Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 7 ++++++- drivers/media/dvb/dvb-usb/dvb-usb-ids.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index c25b4281cff4..97af266d7f1d 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -2801,6 +2801,7 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090MD) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, + { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -3410,7 +3411,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { { "DiBcom STK7770P reference design", { &dib0700_usb_id_table[59], NULL }, @@ -3422,6 +3423,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { &dib0700_usb_id_table[60], NULL}, { NULL }, }, + { "TechniSat AirStar TeleStick 2", + { &dib0700_usb_id_table[74], NULL }, + { NULL }, + }, }, .rc.core = { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index b71540d7e070..3a8b7446b7b0 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -317,5 +317,6 @@ #define USB_PID_TERRATEC_DVBS2CI_V2 0x10ac #define USB_PID_TECHNISAT_USB2_HDCI_V1 0x0001 #define USB_PID_TECHNISAT_USB2_HDCI_V2 0x0002 +#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2 0x0004 #define USB_PID_TECHNISAT_USB2_DVB_S2 0x0500 #endif -- cgit v1.2.2 From 0522921c0f89f274a99d5084ca0a6fd370749cc8 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Fri, 11 Feb 2011 18:15:02 -0300 Subject: [media] via-camera: Add suspend/resume support Add suspend/resume support to the via-camera driver, so that the video continues streaming over a suspend-resume cycle. Originally implemented by Jon Corbet. [mchehab@redhat.com: fix a small CodingStyle issue] Signed-off-by: Daniel Drake Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/via-camera.c | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index 2f973cd56408..3f0146fcf752 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -1246,6 +1246,62 @@ static const struct v4l2_ioctl_ops viacam_ioctl_ops = { /* * Power management. */ +#ifdef CONFIG_PM + +static int viacam_suspend(void *priv) +{ + struct via_camera *cam = priv; + enum viacam_opstate state = cam->opstate; + + if (cam->opstate != S_IDLE) { + viacam_stop_engine(cam); + cam->opstate = state; /* So resume restarts */ + } + + return 0; +} + +static int viacam_resume(void *priv) +{ + struct via_camera *cam = priv; + int ret = 0; + + /* + * Get back to a reasonable operating state. + */ + via_write_reg_mask(VIASR, 0x78, 0, 0x80); + via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0); + viacam_int_disable(cam); + set_bit(CF_CONFIG_NEEDED, &cam->flags); + /* + * Make sure the sensor's power state is correct + */ + if (cam->users > 0) + via_sensor_power_up(cam); + else + via_sensor_power_down(cam); + /* + * If it was operating, try to restart it. + */ + if (cam->opstate != S_IDLE) { + mutex_lock(&cam->lock); + ret = viacam_configure_sensor(cam); + if (!ret) + ret = viacam_config_controller(cam); + mutex_unlock(&cam->lock); + if (!ret) + viacam_start_engine(cam); + } + + return ret; +} + +static struct viafb_pm_hooks viacam_pm_hooks = { + .suspend = viacam_suspend, + .resume = viacam_resume +}; + +#endif /* CONFIG_PM */ /* * Setup stuff. @@ -1369,6 +1425,14 @@ static __devinit int viacam_probe(struct platform_device *pdev) goto out_irq; video_set_drvdata(&cam->vdev, cam); +#ifdef CONFIG_PM + /* + * Hook into PM events + */ + viacam_pm_hooks.private = cam; + viafb_pm_register(&viacam_pm_hooks); +#endif + /* Power the sensor down until somebody opens the device */ via_sensor_power_down(cam); return 0; -- cgit v1.2.2 From 1b149bbe9156d2eb2afd5a072bd61ad0d4bfaca7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 27 Feb 2011 14:51:54 -0300 Subject: [media] media/radio/wl1273: fix build errors RADIO_WL1273 needs to make sure that the mfd core is built to avoid build errors: ERROR: "mfd_add_devices" [drivers/mfd/wl1273-core.ko] undefined! ERROR: "mfd_remove_devices" [drivers/mfd/wl1273-core.ko] undefined! Signed-off-by: Randy Dunlap Cc: Matti Aaltonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index f75cdad2df59..299994c3aa74 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -441,6 +441,7 @@ config RADIO_TIMBERDALE config RADIO_WL1273 tristate "Texas Instruments WL1273 I2C FM Radio" depends on I2C && VIDEO_V4L2 + select MFD_CORE select MFD_WL1273_CORE select FW_LOADER ---help--- -- cgit v1.2.2 From d4c9adb742abd1e8025b6f2e3bb24e3efab86da9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 1 Mar 2011 08:17:47 -0300 Subject: matrox: Remove legacy VIDIOC_*_OLD ioctls Those ioctls were produced by the wrong arguments for _IO macros, and were replaced by fixed versions on an early 2.6 kernel. Signed-off-by: Mauro Carvalho Chehab --- drivers/video/matrox/matroxfb_base.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index a082debe824b..8c9dbac9dc1b 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -101,8 +101,6 @@ #include -#define __OLD_VIDIOC_ - #include "matroxfb_base.h" #include "matroxfb_misc.h" #include "matroxfb_accel.h" @@ -1152,7 +1150,6 @@ static int matroxfb_ioctl(struct fb_info *info, return -EFAULT; return err; } - case VIDIOC_S_CTRL_OLD: case VIDIOC_S_CTRL: { struct v4l2_control ctrl; -- cgit v1.2.2 From 94fd5b7401e330498331ea3667d796e74c63d08a Mon Sep 17 00:00:00 2001 From: Matti Aaltonen Date: Tue, 1 Mar 2011 10:10:35 -0300 Subject: [media] MFD: WL1273 FM Radio: MFD driver for the FM radio This is the core of the WL1273 FM radio driver, it connects the two child modules. The two child drivers are drivers/media/radio/radio-wl1273.c and sound/soc/codecs/wl1273.c. The radio-wl1273 driver implements the V4L2 interface and communicates with the device. The ALSA codec offers digital audio, without it only analog audio is available. Signed-off-by: Matti J. Aaltonen Acked-by: Samuel Ortiz Signed-off-by: Mauro Carvalho Chehab --- drivers/mfd/Kconfig | 2 +- drivers/mfd/wl1273-core.c | 149 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fd018366d670..9db079be0e08 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -615,7 +615,7 @@ config MFD_VX855 and/or vx855_gpio drivers for this to do anything useful. config MFD_WL1273_CORE - tristate + tristate "Support for TI WL1273 FM radio." depends on I2C select MFD_CORE default n diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index d2ecc2435736..4025a4bec8d5 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -1,7 +1,7 @@ /* * MFD driver for wl1273 FM radio and audio codec submodules. * - * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2011 Nokia Corporation * Author: Matti Aaltonen * * This program is free software; you can redistribute it and/or modify @@ -31,6 +31,145 @@ static struct i2c_device_id wl1273_driver_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table); +static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value) +{ + struct i2c_client *client = core->client; + u8 b[2]; + int r; + + r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b); + if (r != 2) { + dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg); + return -EREMOTEIO; + } + + *value = (u16)b[0] << 8 | b[1]; + + return 0; +} + +static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param) +{ + struct i2c_client *client = core->client; + u8 buf[] = { (param >> 8) & 0xff, param & 0xff }; + int r; + + r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf); + if (r) { + dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd); + return r; + } + + return 0; +} + +static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len) +{ + struct i2c_client *client = core->client; + struct i2c_msg msg; + int r; + + msg.addr = client->addr; + msg.flags = 0; + msg.buf = data; + msg.len = len; + + r = i2c_transfer(client->adapter, &msg, 1); + if (r != 1) { + dev_err(&client->dev, "%s: write error.\n", __func__); + return -EREMOTEIO; + } + + return 0; +} + +/** + * wl1273_fm_set_audio() - Set audio mode. + * @core: A pointer to the device struct. + * @new_mode: The new audio mode. + * + * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG. + */ +static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode) +{ + int r = 0; + + if (core->mode == WL1273_MODE_OFF || + core->mode == WL1273_MODE_SUSPENDED) + return -EPERM; + + if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) { + r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET, + WL1273_PCM_DEF_MODE); + if (r) + goto out; + + r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, + core->i2s_mode); + if (r) + goto out; + + r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE, + WL1273_AUDIO_ENABLE_I2S); + if (r) + goto out; + + } else if (core->mode == WL1273_MODE_RX && + new_mode == WL1273_AUDIO_ANALOG) { + r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE, + WL1273_AUDIO_ENABLE_ANALOG); + if (r) + goto out; + + } else if (core->mode == WL1273_MODE_TX && + new_mode == WL1273_AUDIO_DIGITAL) { + r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, + core->i2s_mode); + if (r) + goto out; + + r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET, + WL1273_AUDIO_IO_SET_I2S); + if (r) + goto out; + + } else if (core->mode == WL1273_MODE_TX && + new_mode == WL1273_AUDIO_ANALOG) { + r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET, + WL1273_AUDIO_IO_SET_ANALOG); + if (r) + goto out; + } + + core->audio_mode = new_mode; +out: + return r; +} + +/** + * wl1273_fm_set_volume() - Set volume. + * @core: A pointer to the device struct. + * @volume: The new volume value. + */ +static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume) +{ + u16 val; + int r; + + if (volume > WL1273_MAX_VOLUME) + return -EINVAL; + + if (core->volume == volume) + return 0; + + r = wl1273_fm_write_cmd(core, WL1273_VOLUME_SET, volume); + if (r) + return r; + + core->volume = volume; + return 0; +} + static int wl1273_core_remove(struct i2c_client *client) { struct wl1273_core *core = i2c_get_clientdata(client); @@ -38,7 +177,6 @@ static int wl1273_core_remove(struct i2c_client *client) dev_dbg(&client->dev, "%s\n", __func__); mfd_remove_devices(&client->dev); - i2c_set_clientdata(client, NULL); kfree(core); return 0; @@ -83,6 +221,12 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, cell->data_size = sizeof(core); children++; + core->read = wl1273_fm_read_reg; + core->write = wl1273_fm_write_cmd; + core->write_data = wl1273_fm_write_data; + core->set_audio = wl1273_fm_set_audio; + core->set_volume = wl1273_fm_set_volume; + if (pdata->children & WL1273_CODEC_CHILD) { cell = &core->cells[children]; @@ -104,7 +248,6 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, return 0; err: - i2c_set_clientdata(client, NULL); pdata->free_resources(); kfree(core); -- cgit v1.2.2 From 96a9cc681ecfaf2ed9b6c62090888550f604d783 Mon Sep 17 00:00:00 2001 From: Matti Aaltonen Date: Tue, 1 Mar 2011 10:10:36 -0300 Subject: [media] V4L2: WL1273 FM Radio: TI WL1273 FM radio driver This module implements V4L2 controls for the Texas Instruments WL1273 FM Radio and handles the communication with the chip. Signed-off-by: Matti J. Aaltonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-wl1273.c | 360 +++++++++++-------------------------- 1 file changed, 106 insertions(+), 254 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 7ecc8e657663..9e177dccc673 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1,7 +1,7 @@ /* * Driver for the Texas Instruments WL1273 FM radio. * - * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2011 Nokia Corporation * Author: Matti J. Aaltonen * * This program is free software; you can redistribute it and/or @@ -104,58 +104,6 @@ static unsigned int rds_buf = 100; module_param(rds_buf, uint, 0); MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100"); -static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value) -{ - struct i2c_client *client = core->client; - u8 b[2]; - int r; - - r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b); - if (r != 2) { - dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg); - return -EREMOTEIO; - } - - *value = (u16)b[0] << 8 | b[1]; - - return 0; -} - -static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param) -{ - struct i2c_client *client = core->client; - u8 buf[] = { (param >> 8) & 0xff, param & 0xff }; - int r; - - r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf); - if (r) { - dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd); - return r; - } - - return 0; -} - -static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len) -{ - struct i2c_client *client = core->client; - struct i2c_msg msg; - int r; - - msg.addr = client->addr; - msg.flags = 0; - msg.buf = data; - msg.len = len; - - r = i2c_transfer(client->adapter, &msg, 1); - if (r != 1) { - dev_err(&client->dev, "%s: write error.\n", __func__); - return -EREMOTEIO; - } - - return 0; -} - static int wl1273_fm_write_fw(struct wl1273_core *core, __u8 *fw, int len) { @@ -188,94 +136,6 @@ static int wl1273_fm_write_fw(struct wl1273_core *core, return r; } -/** - * wl1273_fm_set_audio() - Set audio mode. - * @core: A pointer to the device struct. - * @new_mode: The new audio mode. - * - * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG. - */ -static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode) -{ - int r = 0; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) { - r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET, - WL1273_PCM_DEF_MODE); - if (r) - goto out; - - r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, - core->i2s_mode); - if (r) - goto out; - - r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE, - WL1273_AUDIO_ENABLE_I2S); - if (r) - goto out; - - } else if (core->mode == WL1273_MODE_RX && - new_mode == WL1273_AUDIO_ANALOG) { - r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE, - WL1273_AUDIO_ENABLE_ANALOG); - if (r) - goto out; - - } else if (core->mode == WL1273_MODE_TX && - new_mode == WL1273_AUDIO_DIGITAL) { - r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET, - core->i2s_mode); - if (r) - goto out; - - r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET, - WL1273_AUDIO_IO_SET_I2S); - if (r) - goto out; - - } else if (core->mode == WL1273_MODE_TX && - new_mode == WL1273_AUDIO_ANALOG) { - r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET, - WL1273_AUDIO_IO_SET_ANALOG); - if (r) - goto out; - } - - core->audio_mode = new_mode; -out: - return r; -} - -/** - * wl1273_fm_set_volume() - Set volume. - * @core: A pointer to the device struct. - * @volume: The new volume value. - */ -static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume) -{ - u16 val; - int r; - - if (volume > WL1273_MAX_VOLUME) - return -EINVAL; - - if (core->volume == volume) - return 0; - - val = volume; - r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val); - if (r) - return r; - - core->volume = volume; - return 0; -} - #define WL1273_FIFO_HAS_DATA(status) (1 << 5 & status) #define WL1273_RDS_CORRECTABLE_ERROR (1 << 3) #define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4) @@ -306,7 +166,7 @@ static int wl1273_fm_rds(struct wl1273_device *radio) if (core->mode != WL1273_MODE_RX) return 0; - r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val); + r = core->read(core, WL1273_RDS_SYNC_GET, &val); if (r) return r; @@ -374,7 +234,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) u16 flags; int r; - r = wl1273_fm_read_reg(core, WL1273_FLAG_GET, &flags); + r = core->read(core, WL1273_FLAG_GET, &flags); if (r) goto out; @@ -398,7 +258,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) if (flags & WL1273_LEV_EVENT) { u16 level; - r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &level); + r = core->read(core, WL1273_RSSI_LVL_GET, &level); if (r) goto out; @@ -439,8 +299,8 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) dev_dbg(radio->dev, "IRQ: FR:\n"); if (core->mode == WL1273_MODE_RX) { - r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET, - TUNER_MODE_STOP_SEARCH); + r = core->write(core, WL1273_TUNER_MODE_SET, + TUNER_MODE_STOP_SEARCH); if (r) { dev_err(radio->dev, "%s: TUNER_MODE_SET fails: %d\n", @@ -448,7 +308,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) goto out; } - r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &freq); + r = core->read(core, WL1273_FREQ_SET, &freq); if (r) goto out; @@ -467,7 +327,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency); } else { - r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &freq); + r = core->read(core, WL1273_CHANL_SET, &freq); if (r) goto out; @@ -477,8 +337,7 @@ static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) } out: - wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, - radio->irq_flags); + core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); complete(&radio->busy); return IRQ_HANDLED; @@ -512,7 +371,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq); /* Set the current tx channel */ - r = wl1273_fm_write_cmd(core, WL1273_CHANL_SET, freq / 10); + r = core->write(core, WL1273_CHANL_SET, freq / 10); if (r) return r; @@ -526,7 +385,7 @@ static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r); /* Enable the output power */ - r = wl1273_fm_write_cmd(core, WL1273_POWER_ENB_SET, 1); + r = core->write(core, WL1273_POWER_ENB_SET, 1); if (r) return r; @@ -566,20 +425,20 @@ static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq); - wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags); + core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); if (radio->band == WL1273_BAND_JAPAN) f = (freq - WL1273_BAND_JAPAN_LOW) / 50; else f = (freq - WL1273_BAND_OTHER_LOW) / 50; - r = wl1273_fm_write_cmd(core, WL1273_FREQ_SET, f); + r = core->write(core, WL1273_FREQ_SET, f); if (r) { dev_err(radio->dev, "FREQ_SET fails\n"); goto err; } - r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET); + r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET); if (r) { dev_err(radio->dev, "TUNER_MODE_SET fails\n"); goto err; @@ -609,7 +468,7 @@ static int wl1273_fm_get_freq(struct wl1273_device *radio) int r; if (core->mode == WL1273_MODE_RX) { - r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &f); + r = core->read(core, WL1273_FREQ_SET, &f); if (r) return r; @@ -619,7 +478,7 @@ static int wl1273_fm_get_freq(struct wl1273_device *radio) else freq = WL1273_BAND_OTHER_LOW + 50 * f; } else { - r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &f); + r = core->read(core, WL1273_CHANL_SET, &f); if (r) return r; @@ -670,7 +529,7 @@ static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio) } /* ignore possible error here */ - wl1273_fm_write_cmd(core, WL1273_RESET, 0); + core->write(core, WL1273_RESET, 0); dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r); out: @@ -683,14 +542,14 @@ static int wl1273_fm_stop(struct wl1273_device *radio) struct wl1273_core *core = radio->core; if (core->mode == WL1273_MODE_RX) { - int r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, + int r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_OFF); if (r) dev_err(radio->dev, "%s: POWER_SET fails: %d\n", __func__, r); } else if (core->mode == WL1273_MODE_TX) { - int r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_OFF); + int r = core->write(core, WL1273_PUPD_SET, + WL1273_PUPD_SET_OFF); if (r) dev_err(radio->dev, "%s: PUPD_SET fails: %d\n", __func__, r); @@ -725,11 +584,11 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) val |= WL1273_POWER_SET_RDS; /* If this fails try again */ - r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val); + r = core->write(core, WL1273_POWER_SET, val); if (r) { msleep(100); - r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val); + r = core->write(core, WL1273_POWER_SET, val); if (r) { dev_err(dev, "%s: POWER_SET fails\n", __func__); goto fail; @@ -742,11 +601,10 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) } else if (new_mode == WL1273_MODE_TX) { /* If this fails try again once */ - r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); + r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_ON); if (r) { msleep(100); - r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET, + r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_ON); if (r) { dev_err(dev, "%s: PUPD_SET fails\n", __func__); @@ -755,9 +613,9 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) } if (radio->rds_on) - r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1); + r = core->write(core, WL1273_RDS_DATA_ENB, 1); else - r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0); + r = core->write(core, WL1273_RDS_DATA_ENB, 0); } else { dev_warn(dev, "%s: Illegal mode.\n", __func__); } @@ -777,14 +635,14 @@ static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) if (radio->rds_on) val |= WL1273_POWER_SET_RDS; - r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val); + r = core->write(core, WL1273_POWER_SET, val); if (r) { dev_err(dev, "%s: POWER_SET fails\n", __func__); goto fail; } } else if (new_mode == WL1273_MODE_TX) { - r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); + r = core->write(core, WL1273_PUPD_SET, + WL1273_PUPD_SET_ON); if (r) { dev_err(dev, "%s: PUPD_SET fails\n", __func__); goto fail; @@ -808,10 +666,10 @@ static int wl1273_fm_suspend(struct wl1273_device *radio) /* Cannot go from OFF to SUSPENDED */ if (core->mode == WL1273_MODE_RX) - r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, + r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_RETENTION); else if (core->mode == WL1273_MODE_TX) - r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET, + r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_RETENTION); else r = -EINVAL; @@ -852,8 +710,7 @@ static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode) } core->mode = mode; - r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, - radio->irq_flags); + r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); if (r) { dev_err(dev, "INT_MASK_SET fails.\n"); goto out; @@ -951,22 +808,21 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio, INIT_COMPLETION(radio->busy); dev_dbg(radio->dev, "%s: BUSY\n", __func__); - r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags); + r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); if (r) goto out; dev_dbg(radio->dev, "%s\n", __func__); - r = wl1273_fm_write_cmd(core, WL1273_SEARCH_LVL_SET, level); + r = core->write(core, WL1273_SEARCH_LVL_SET, level); if (r) goto out; - r = wl1273_fm_write_cmd(core, WL1273_SEARCH_DIR_SET, dir); + r = core->write(core, WL1273_SEARCH_DIR_SET, dir); if (r) goto out; - r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET, - TUNER_MODE_AUTO_SEEK); + r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); if (r) goto out; @@ -994,8 +850,7 @@ static int wl1273_fm_set_seek(struct wl1273_device *radio, INIT_COMPLETION(radio->busy); dev_dbg(radio->dev, "%s: BUSY\n", __func__); - r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET, - TUNER_MODE_AUTO_SEEK); + r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); if (r) goto out; @@ -1020,7 +875,7 @@ static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio) core->mode == WL1273_MODE_SUSPENDED) return -EPERM; - r = wl1273_fm_read_reg(core, WL1273_READ_FMANT_TUNE_VALUE, &val); + r = core->read(core, WL1273_READ_FMANT_TUNE_VALUE, &val); if (r) { dev_err(dev, "%s: read error: %d\n", __func__, r); goto out; @@ -1066,7 +921,7 @@ static int wl1273_fm_set_preemphasis(struct wl1273_device *radio, goto out; } - r = wl1273_fm_write_cmd(core, WL1273_PREMPH_SET, em); + r = core->write(core, WL1273_PREMPH_SET, em); if (r) goto out; @@ -1086,7 +941,7 @@ static int wl1273_fm_rds_on(struct wl1273_device *radio) if (radio->rds_on) return 0; - r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, + r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS); if (r) goto out; @@ -1108,7 +963,7 @@ static int wl1273_fm_rds_off(struct wl1273_device *radio) radio->irq_flags &= ~WL1273_RDS_EVENT; - r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags); + r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); if (r) goto out; @@ -1120,7 +975,7 @@ static int wl1273_fm_rds_off(struct wl1273_device *radio) dev_dbg(radio->dev, "%s\n", __func__); - r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, WL1273_POWER_SET_FM); + r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_FM); if (r) goto out; @@ -1143,14 +998,14 @@ static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode) return -EPERM; if (new_mode == WL1273_RDS_RESET) { - r = wl1273_fm_write_cmd(core, WL1273_RDS_CNTRL_SET, 1); + r = core->write(core, WL1273_RDS_CNTRL_SET, 1); return r; } if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) { - r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0); + r = core->write(core, WL1273_RDS_DATA_ENB, 0); } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) { - r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1); + r = core->write(core, WL1273_RDS_DATA_ENB, 1); } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) { r = wl1273_fm_rds_off(radio); } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) { @@ -1171,12 +1026,13 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); + struct wl1273_core *core = radio->core; u16 val; int r; dev_dbg(radio->dev, "%s\n", __func__); - if (radio->core->mode != WL1273_MODE_TX) + if (core->mode != WL1273_MODE_TX) return count; if (radio->rds_users == 0) { @@ -1184,7 +1040,7 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, return 0; } - if (mutex_lock_interruptible(&radio->core->lock)) + if (mutex_lock_interruptible(&core->lock)) return -EINTR; /* * Multiple processes can open the device, but only @@ -1202,7 +1058,7 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, else val = count; - wl1273_fm_write_cmd(radio->core, WL1273_RDS_CONFIG_DATA_SET, val); + core->write(core, WL1273_RDS_CONFIG_DATA_SET, val); if (copy_from_user(radio->write_buf + 1, buf, val)) { r = -EFAULT; @@ -1213,11 +1069,11 @@ static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf); radio->write_buf[0] = WL1273_RDS_DATA_SET; - wl1273_fm_write_data(radio->core, radio->write_buf, val + 1); + core->write_data(core, radio->write_buf, val + 1); r = val; out: - mutex_unlock(&radio->core->lock); + mutex_unlock(&core->lock); return r; } @@ -1263,8 +1119,8 @@ static int wl1273_fm_fops_open(struct file *file) radio->irq_flags |= WL1273_RDS_EVENT; - r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, - radio->irq_flags); + r = core->write(core, WL1273_INT_MASK_SET, + radio->irq_flags); if (r) { mutex_unlock(&core->lock); goto out; @@ -1295,9 +1151,9 @@ static int wl1273_fm_fops_release(struct file *file) radio->irq_flags &= ~WL1273_RDS_EVENT; if (core->mode == WL1273_MODE_RX) { - r = wl1273_fm_write_cmd(core, - WL1273_INT_MASK_SET, - radio->irq_flags); + r = core->write(core, + WL1273_INT_MASK_SET, + radio->irq_flags); if (r) { mutex_unlock(&core->lock); goto out; @@ -1324,7 +1180,7 @@ static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf, dev_dbg(radio->dev, "%s\n", __func__); - if (radio->core->mode != WL1273_MODE_RX) + if (core->mode != WL1273_MODE_RX) return 0; if (radio->rds_users == 0) { @@ -1345,7 +1201,7 @@ static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf, } radio->owner = file; - r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val); + r = core->read(core, WL1273_RDS_SYNC_GET, &val); if (r) { dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__); goto out; @@ -1466,23 +1322,24 @@ static int wl1273_fm_vidioc_s_input(struct file *file, void *priv, */ static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power) { + struct wl1273_core *core = radio->core; int r; - if (radio->core->mode == WL1273_MODE_OFF || - radio->core->mode == WL1273_MODE_SUSPENDED) + if (core->mode == WL1273_MODE_OFF || + core->mode == WL1273_MODE_SUSPENDED) return -EPERM; - mutex_lock(&radio->core->lock); + mutex_lock(&core->lock); /* Convert the dBuV value to chip presentation */ - r = wl1273_fm_write_cmd(radio->core, WL1273_POWER_LEV_SET, 122 - power); + r = core->write(core, WL1273_POWER_LEV_SET, 122 - power); if (r) goto out; radio->tx_power = power; out: - mutex_unlock(&radio->core->lock); + mutex_unlock(&core->lock); return r; } @@ -1493,23 +1350,24 @@ out: static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio, unsigned int spacing) { + struct wl1273_core *core = radio->core; int r; if (spacing == 0) { - r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_100kHz); radio->spacing = 100; } else if (spacing - 50000 < 25000) { - r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_50kHz); + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_50kHz); radio->spacing = 50; } else if (spacing - 100000 < 50000) { - r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_100kHz); radio->spacing = 100; } else { - r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_200kHz); + r = core->write(core, WL1273_SCAN_SPACING_SET, + WL1273_SPACING_200kHz); radio->spacing = 200; } @@ -1567,17 +1425,17 @@ static int wl1273_fm_vidioc_s_ctrl(struct v4l2_ctrl *ctrl) return -EINTR; if (core->mode == WL1273_MODE_RX && ctrl->val) - r = wl1273_fm_write_cmd(core, - WL1273_MUTE_STATUS_SET, - WL1273_MUTE_HARD_LEFT | - WL1273_MUTE_HARD_RIGHT); + r = core->write(core, + WL1273_MUTE_STATUS_SET, + WL1273_MUTE_HARD_LEFT | + WL1273_MUTE_HARD_RIGHT); else if (core->mode == WL1273_MODE_RX) - r = wl1273_fm_write_cmd(core, - WL1273_MUTE_STATUS_SET, 0x0); + r = core->write(core, + WL1273_MUTE_STATUS_SET, 0x0); else if (core->mode == WL1273_MODE_TX && ctrl->val) - r = wl1273_fm_write_cmd(core, WL1273_MUTE, 1); + r = core->write(core, WL1273_MUTE, 1); else if (core->mode == WL1273_MODE_TX) - r = wl1273_fm_write_cmd(core, WL1273_MUTE, 0); + r = core->write(core, WL1273_MUTE, 0); mutex_unlock(&core->lock); break; @@ -1672,7 +1530,7 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, if (mutex_lock_interruptible(&core->lock)) return -EINTR; - r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val); + r = core->read(core, WL1273_STEREO_GET, &val); if (r) goto out; @@ -1681,7 +1539,7 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, else tuner->rxsubchans = V4L2_TUNER_SUB_MONO; - r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val); + r = core->read(core, WL1273_RSSI_LVL_GET, &val); if (r) goto out; @@ -1690,7 +1548,7 @@ static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, tuner->afc = 0; - r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val); + r = core->read(core, WL1273_RDS_SYNC_GET, &val); if (r) goto out; @@ -1736,8 +1594,7 @@ static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r); if (tuner->audmode == V4L2_TUNER_MODE_MONO) { - r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET, - WL1273_RX_MONO); + r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); if (r < 0) { dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", __func__, r); @@ -1745,8 +1602,7 @@ static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, } radio->stereo = false; } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) { - r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET, - WL1273_RX_STEREO); + r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); if (r < 0) { dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", __func__, r); @@ -1885,10 +1741,10 @@ static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv, r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); if (modulator->txsubchans & V4L2_TUNER_SUB_MONO) - r = wl1273_fm_write_cmd(core, WL1273_MONO_SET, WL1273_TX_MONO); + r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); else - r = wl1273_fm_write_cmd(core, WL1273_MONO_SET, - WL1273_RX_STEREO); + r = core->write(core, WL1273_MONO_SET, + WL1273_RX_STEREO); if (r < 0) dev_warn(radio->dev, WL1273_FM_DRIVER_NAME "MONO_SET fails: %d\n", r); @@ -1923,7 +1779,7 @@ static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv, if (mutex_lock_interruptible(&core->lock)) return -EINTR; - r = wl1273_fm_read_reg(core, WL1273_MONO_SET, &val); + r = core->read(core, WL1273_MONO_SET, &val); if (r) goto out; @@ -1960,38 +1816,38 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) return 0; } - r = wl1273_fm_read_reg(core, WL1273_ASIC_ID_GET, &val); + r = core->read(core, WL1273_ASIC_ID_GET, &val); if (r) dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__); else dev_info(dev, "ASIC_ID: 0x%04x\n", val); - r = wl1273_fm_read_reg(core, WL1273_ASIC_VER_GET, &val); + r = core->read(core, WL1273_ASIC_VER_GET, &val); if (r) dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__); else dev_info(dev, "ASIC Version: 0x%04x\n", val); - r = wl1273_fm_read_reg(core, WL1273_FIRM_VER_GET, &val); + r = core->read(core, WL1273_FIRM_VER_GET, &val); if (r) dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__); else dev_info(dev, "FW version: %d(0x%04x)\n", val, val); - r = wl1273_fm_read_reg(core, WL1273_BAND_SET, &val); + r = core->read(core, WL1273_BAND_SET, &val); if (r) dev_err(dev, "%s: Get BAND fails.\n", __func__); else dev_info(dev, "BAND: %d\n", val); if (core->mode == WL1273_MODE_TX) { - r = wl1273_fm_read_reg(core, WL1273_PUPD_SET, &val); + r = core->read(core, WL1273_PUPD_SET, &val); if (r) dev_err(dev, "%s: Get PUPD fails.\n", __func__); else dev_info(dev, "PUPD: 0x%04x\n", val); - r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &val); + r = core->read(core, WL1273_CHANL_SET, &val); if (r) dev_err(dev, "%s: Get CHANL fails.\n", __func__); else @@ -1999,13 +1855,13 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) } else if (core->mode == WL1273_MODE_RX) { int bf = radio->rangelow; - r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &val); + r = core->read(core, WL1273_FREQ_SET, &val); if (r) dev_err(dev, "%s: Get FREQ fails.\n", __func__); else dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50); - r = wl1273_fm_read_reg(core, WL1273_MOST_MODE_SET, &val); + r = core->read(core, WL1273_MOST_MODE_SET, &val); if (r) dev_err(dev, "%s: Get MOST_MODE fails.\n", __func__); @@ -2016,7 +1872,7 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) else dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val); - r = wl1273_fm_read_reg(core, WL1273_MOST_BLEND_SET, &val); + r = core->read(core, WL1273_MOST_BLEND_SET, &val); if (r) dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__); else if (val == 0) @@ -2027,7 +1883,7 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) else dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val); - r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val); + r = core->read(core, WL1273_STEREO_GET, &val); if (r) dev_err(dev, "%s: Get STEREO fails.\n", __func__); else if (val == 0) @@ -2037,25 +1893,25 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) else dev_info(dev, "STEREO: Unexpected value: %d\n", val); - r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val); + r = core->read(core, WL1273_RSSI_LVL_GET, &val); if (r) dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__); else dev_info(dev, "RX signal strength: %d\n", (s16) val); - r = wl1273_fm_read_reg(core, WL1273_POWER_SET, &val); + r = core->read(core, WL1273_POWER_SET, &val); if (r) dev_err(dev, "%s: Get POWER fails.\n", __func__); else dev_info(dev, "POWER: 0x%04x\n", val); - r = wl1273_fm_read_reg(core, WL1273_INT_MASK_SET, &val); + r = core->read(core, WL1273_INT_MASK_SET, &val); if (r) dev_err(dev, "%s: Get INT_MASK fails.\n", __func__); else dev_info(dev, "INT_MASK: 0x%04x\n", val); - r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val); + r = core->read(core, WL1273_RDS_SYNC_GET, &val); if (r) dev_err(dev, "%s: Get RDS_SYNC fails.\n", __func__); @@ -2067,14 +1923,14 @@ static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) else dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val); - r = wl1273_fm_read_reg(core, WL1273_I2S_MODE_CONFIG_SET, &val); + r = core->read(core, WL1273_I2S_MODE_CONFIG_SET, &val); if (r) dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n", __func__); else dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val); - r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val); + r = core->read(core, WL1273_VOLUME_SET, &val); if (r) dev_err(dev, "%s: Get VOLUME fails.\n", __func__); else @@ -2184,10 +2040,6 @@ static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev) radio->stereo = true; radio->bus_type = "I2C"; - radio->core->write = wl1273_fm_write_cmd; - radio->core->set_audio = wl1273_fm_set_audio; - radio->core->set_volume = wl1273_fm_set_volume; - if (radio->core->pdata->request_resources) { r = radio->core->pdata->request_resources(radio->core->client); if (r) { -- cgit v1.2.2 From ed54c0e33c6ac72c681f00a41b47840f6570262c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Jan 2011 11:27:58 -0300 Subject: [media] dib8000: fix small memory leak on error kfree(state) if fe allocation fails. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib8000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 3e20aa8db23b..c1c3e26906e2 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -2514,7 +2514,7 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s return NULL; fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL); if (fe == NULL) - return NULL; + goto error; memcpy(&state->cfg, cfg, sizeof(struct dib8000_config)); state->i2c.adap = i2c_adap; -- cgit v1.2.2 From b00aff6a36aeafc68cf9044751041ba432ab4495 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Jan 2011 11:28:27 -0300 Subject: [media] dib9000: fix return type in dib9000_mbx_send_attr() dib9000_mbx_send_attr() returns an int. It doesn't work to save negative error codes in an unsigned char, so I've made "ret" an int type. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib9000.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index 43fb6e45424a..91518761a2da 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -486,10 +486,11 @@ static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id) #define MAX_MAILBOX_TRY 100 static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, u8 len, u16 attr) { - u8 ret = 0, *d, b[2]; + u8 *d, b[2]; u16 tmp; u16 size; u32 i; + int ret = 0; if (!state->platform.risc.fw_is_running) return -EINVAL; -- cgit v1.2.2 From 050b648e63b6a3afd22181d6c2113c315113e4db Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 27 Feb 2011 18:08:46 -0300 Subject: [media] cx23885, altera-ci: remove operator return in void procedure Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/altera-ci.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/altera-ci.h b/drivers/media/video/cx23885/altera-ci.h index ba0c6c05082a..bf0aa2c9b070 100644 --- a/drivers/media/video/cx23885/altera-ci.h +++ b/drivers/media/video/cx23885/altera-ci.h @@ -60,7 +60,6 @@ static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr) static inline void altera_ci_release(void *dev, int ci_nr) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; } static inline int altera_ci_irq(void *dev) @@ -87,7 +86,6 @@ static inline int altera_hw_filt_init(struct altera_ci_config *config, static inline void altera_hw_filt_release(void *dev, int filt_nr) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return 0; } static inline int altera_pid_feed_control(void *dev, int filt_nr, -- cgit v1.2.2 From 38cdbce7634bdd914b6c6e673c2f6ebedca30d43 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Mon, 28 Feb 2011 16:52:08 -0300 Subject: [media] stv0900: speed up DVB-S searching Simptoms: After zapping DVB-S2 channel searching for DVB-S tooks long time. Now it takes less than a second. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0900_core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index 1ca1c835048f..0d9b456d34fc 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -1604,6 +1604,9 @@ static enum dvbfe_search stv0900_search(struct dvb_frontend *fe, p_search.standard = STV0900_AUTO_SEARCH; p_search.iq_inversion = STV0900_IQ_AUTO; p_search.search_algo = STV0900_BLIND_SEARCH; + /* Speeds up DVB-S searching */ + if (c->delivery_system == SYS_DVBS) + p_search.standard = STV0900_SEARCH_DVBS1; intp->srch_standard[demod] = p_search.standard; intp->symbol_rate[demod] = p_search.symbol_rate; -- cgit v1.2.2 From 3b30e0a871389eda9034084faec67d43478fb4c0 Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Mon, 14 Feb 2011 16:03:13 -0300 Subject: [media] stv0900: Update status when LOCK is missed Signed-off-by: Abylay Ospan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0900_core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index 0d9b456d34fc..0ca316d6fffa 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -1666,6 +1666,7 @@ static int stv0900_read_status(struct dvb_frontend *fe, enum fe_status *status) if (state->config->set_lock_led) state->config->set_lock_led(fe, 1); } else { + *status = 0; if (state->config->set_lock_led) state->config->set_lock_led(fe, 0); dprintk("DEMOD LOCK FAIL\n"); -- cgit v1.2.2 From 738e8ff90fae01dccc9e7f92e0cfa4819567dbb8 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 27 Feb 2011 17:29:55 -0300 Subject: [media] ds3000: wrong hardware tune function implemented It is taken from another tree, where it is modified. Patch to fix that Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/ds3000.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c index 7f3d118287c4..90bf573308b0 100644 --- a/drivers/media/dvb/frontends/ds3000.c +++ b/drivers/media/dvb/frontends/ds3000.c @@ -1220,9 +1220,20 @@ static int ds3000_set_frontend(struct dvb_frontend *fe, } static int ds3000_tune(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) + struct dvb_frontend_parameters *p, + unsigned int mode_flags, + unsigned int *delay, + fe_status_t *status) { - return ds3000_set_frontend(fe, p); + if (p) { + int ret = ds3000_set_frontend(fe, p); + if (ret) + return ret; + } + + *delay = HZ / 5; + + return ds3000_read_status(fe, status); } static enum dvbfe_algo ds3000_get_algo(struct dvb_frontend *fe) -- cgit v1.2.2 From 5265ea54bf442cef83bcbb8b5da03d1fdb37bcb8 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 27 Feb 2011 16:17:25 -0300 Subject: [media] dw2102: X3M TV SPC1400HD added The card consist of PCI to USB bridge and USB DVB-S2 receiver. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 1a1b84c3a53f..3ec0e8e77bd4 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1440,6 +1440,7 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_TERRATEC, 0x00a8)}, {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, + {USB_DEVICE(0x1f4d, 0x3100)}, { } }; @@ -1813,7 +1814,7 @@ static struct dvb_usb_device_properties su3000_properties = { } } }, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { { "SU3000HD DVB-S USB2.0", { &dw2102_table[10], NULL }, @@ -1823,6 +1824,10 @@ static struct dvb_usb_device_properties su3000_properties = { { &dw2102_table[11], NULL }, { NULL }, }, + { "X3M TV SPC1400HD PCI", + { &dw2102_table[14], NULL }, + { NULL }, + }, } }; -- cgit v1.2.2 From e86e4dfa5a436ccbef9ea4f7c28907aef40b875f Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 27 Feb 2011 16:18:34 -0300 Subject: [media] dw2102: remove unnecessary delays for i2c transfer for some cards Prof 7500 and TeVii s630, s660, s480 works faster now Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 3ec0e8e77bd4..1b75da0aaff3 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -590,8 +590,6 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], break; } } - - msleep(3); } mutex_unlock(&d->i2c_mutex); -- cgit v1.2.2 From a84adf4007d80249cbe04da4ee80689a8cfdffda Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 27 Feb 2011 16:18:38 -0300 Subject: [media] dw2102: i2c transfer corrected for some cards Prof 7500 and TeVii s630, s660, s480 works better now Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 1b75da0aaff3..ac70e7b79e21 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -564,14 +564,15 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i += 16; len -= 16; } while (len > 0); - } else if ((udev->descriptor.idProduct == 0x7500) - && (j < (num - 1))) { + } else if (j < (num - 1)) { /* write register addr before read */ u8 obuf[msg[j].len + 2]; obuf[0] = msg[j + 1].len; obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, 0x92, 0, 0, + ret = dw210x_op_rw(d->udev, + udev->descriptor.idProduct == + 0x7500 ? 0x92 : 0x90, 0, 0, obuf, msg[j].len + 2, DW210X_WRITE_MSG); break; @@ -581,8 +582,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[0] = msg[j].len + 1; obuf[1] = (msg[j].addr << 1); memcpy(obuf + 2, msg[j].buf, msg[j].len); - ret = dw210x_op_rw(d->udev, - (num > 1 ? 0x90 : 0x80), 0, 0, + ret = dw210x_op_rw(d->udev, 0x80, 0, 0, obuf, msg[j].len + 2, DW210X_WRITE_MSG); break; -- cgit v1.2.2 From b16af29a561c92ed76b5b882dd68bb082b07a09b Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 27 Feb 2011 16:22:57 -0300 Subject: [media] dw2102: i2c transfer corrected for yet another cards Related to Acorp DS120 and some revisions of DVBWorld DW2102. If you read three or more registers at one time, you get wrong value for third etc. Actually, it didn't affect the driver as it reads registers only by one at a time. But it needs to correct. Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index ac70e7b79e21..2889d32bec25 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -156,8 +156,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], /* read stv0299 register */ value = msg[0].buf[0];/* register */ for (i = 0; i < msg[1].len; i++) { - value = value + i; - ret = dw210x_op_rw(d->udev, 0xb5, value, 0, + ret = dw210x_op_rw(d->udev, 0xb5, value + i, 0, buf6, 2, DW210X_READ_MSG); msg[1].buf[i] = buf6[0]; } -- cgit v1.2.2 From fd5466d1dfeba87155c7af70b7d53faa60960c19 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 27 Feb 2011 16:22:52 -0300 Subject: [media] dw2102: prof 1100 corrected Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dw2102.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 2889d32bec25..98cf30270f7d 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1111,18 +1111,25 @@ static int zl100313_frontend_attach(struct dvb_usb_adapter *d) static int stv0288_frontend_attach(struct dvb_usb_adapter *d) { + u8 obuf[] = {7, 1}; + d->fe = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - if (dvb_attach(stb6000_attach, d->fe, 0x61, - &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached stv0288+stb6000!\n"); - return 0; - } - } - return -EIO; + if (d->fe == NULL) + return -EIO; + + if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap)) + return -EIO; + + d->fe->ops.set_voltage = dw210x_set_voltage; + + dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); + + info("Attached stv0288+stb6000!\n"); + + return 0; + } static int ds3000_frontend_attach(struct dvb_usb_adapter *d) -- cgit v1.2.2 From dc46b8c8e3d7e6c7c7ddb78fc2137a5462e98679 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Tue, 1 Mar 2011 01:55:11 -0300 Subject: [media] tm6000: add audio conf for new cards Add configuration of an audio for our new TV cards. With my best regards, Dmitry. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-cards.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index a356ba7aa77c..88144a12745d 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -324,6 +324,8 @@ struct tm6000_board tm6000_boards[] = { .tuner_addr = 0xc2 >> 1, .demod_addr = 0x1e >> 1, .type = TM6010, + .avideo = TM6000_AIP_SIF1, + .aradio = TM6000_AIP_LINE1, .caps = { .has_tuner = 1, .has_dvb = 1, @@ -341,6 +343,8 @@ struct tm6000_board tm6000_boards[] = { .tuner_type = TUNER_XC5000, .tuner_addr = 0xc2 >> 1, .type = TM6010, + .avideo = TM6000_AIP_SIF1, + .aradio = TM6000_AIP_LINE1, .caps = { .has_tuner = 1, .has_dvb = 0, -- cgit v1.2.2 From 0cd301f19a91b3e1fb4130dcd9106777003ed4ed Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 2 Mar 2011 17:15:15 -0300 Subject: [media] staging/cx25721: serialize access to devlist Out of the three files accessing the device list, one uses a mutex, one uses the BKL and one does not have any locking. That is of course pointless, so let's make all of them use the same mutex, and get rid of one more BKL user. Signed-off-by: Arnd Bergmann Signed-off-by: Palash Bandyopadhyay Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/cx25821/Kconfig | 1 - drivers/staging/cx25821/cx25821-alsa.c | 2 ++ drivers/staging/cx25821/cx25821-core.c | 16 +++++++--------- drivers/staging/cx25821/cx25821-video.c | 9 ++++----- drivers/staging/cx25821/cx25821.h | 3 ++- 5 files changed, 15 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/cx25821/Kconfig b/drivers/staging/cx25821/Kconfig index b2656957aa8f..5f6b54213713 100644 --- a/drivers/staging/cx25821/Kconfig +++ b/drivers/staging/cx25821/Kconfig @@ -1,7 +1,6 @@ config VIDEO_CX25821 tristate "Conexant cx25821 support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C - depends on BKL # please fix select I2C_ALGOBIT select VIDEO_BTCX select VIDEO_TVEEPROM diff --git a/drivers/staging/cx25821/cx25821-alsa.c b/drivers/staging/cx25821/cx25821-alsa.c index 160f6693aa33..ebdba7c65bc5 100644 --- a/drivers/staging/cx25821/cx25821-alsa.c +++ b/drivers/staging/cx25821/cx25821-alsa.c @@ -770,10 +770,12 @@ static int cx25821_alsa_init(void) struct cx25821_dev *dev = NULL; struct list_head *list; + mutex_lock(&cx25821_devlist_mutex); list_for_each(list, &cx25821_devlist) { dev = list_entry(list, struct cx25821_dev, devlist); cx25821_audio_initdev(dev); } + mutex_unlock(&cx25821_devlist_mutex); if (dev == NULL) pr_info("ERROR ALSA: no cx25821 cards found\n"); diff --git a/drivers/staging/cx25821/cx25821-core.c b/drivers/staging/cx25821/cx25821-core.c index a216b620b718..523ac5e16c1b 100644 --- a/drivers/staging/cx25821/cx25821-core.c +++ b/drivers/staging/cx25821/cx25821-core.c @@ -33,9 +33,6 @@ MODULE_DESCRIPTION("Driver for Athena cards"); MODULE_AUTHOR("Shu Lin - Hiep Huynh"); MODULE_LICENSE("GPL"); -struct list_head cx25821_devlist; -EXPORT_SYMBOL(cx25821_devlist); - static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); @@ -46,8 +43,10 @@ MODULE_PARM_DESC(card, "card type"); static unsigned int cx25821_devcount; -static DEFINE_MUTEX(devlist); +DEFINE_MUTEX(cx25821_devlist_mutex); +EXPORT_SYMBOL(cx25821_devlist_mutex); LIST_HEAD(cx25821_devlist); +EXPORT_SYMBOL(cx25821_devlist); struct sram_channel cx25821_sram_channels[] = { [SRAM_CH00] = { @@ -911,9 +910,9 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) dev->nr = ++cx25821_devcount; sprintf(dev->name, "cx25821[%d]", dev->nr); - mutex_lock(&devlist); + mutex_lock(&cx25821_devlist_mutex); list_add_tail(&dev->devlist, &cx25821_devlist); - mutex_unlock(&devlist); + mutex_unlock(&cx25821_devlist_mutex); strcpy(cx25821_boards[UNKNOWN_BOARD].name, "unknown"); strcpy(cx25821_boards[CX25821_BOARD].name, "cx25821"); @@ -1465,9 +1464,9 @@ static void __devexit cx25821_finidev(struct pci_dev *pci_dev) if (pci_dev->irq) free_irq(pci_dev->irq, dev); - mutex_lock(&devlist); + mutex_lock(&cx25821_devlist_mutex); list_del(&dev->devlist); - mutex_unlock(&devlist); + mutex_unlock(&cx25821_devlist_mutex); cx25821_dev_unregister(dev); v4l2_device_unregister(v4l2_dev); @@ -1501,7 +1500,6 @@ static struct pci_driver cx25821_pci_driver = { static int __init cx25821_init(void) { - INIT_LIST_HEAD(&cx25821_devlist); pr_info("driver version %d.%d.%d loaded\n", (CX25821_VERSION_CODE >> 16) & 0xff, (CX25821_VERSION_CODE >> 8) & 0xff, diff --git a/drivers/staging/cx25821/cx25821-video.c b/drivers/staging/cx25821/cx25821-video.c index 0d8d75670516..ab05392386e8 100644 --- a/drivers/staging/cx25821/cx25821-video.c +++ b/drivers/staging/cx25821/cx25821-video.c @@ -27,7 +27,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include "cx25821-video.h" -#include MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); MODULE_AUTHOR("Hiep Huynh "); @@ -815,7 +814,7 @@ static int video_open(struct file *file) if (NULL == fh) return -ENOMEM; - lock_kernel(); + mutex_lock(&cx25821_devlist_mutex); list_for_each(list, &cx25821_devlist) { @@ -832,8 +831,8 @@ static int video_open(struct file *file) } if (NULL == dev) { - unlock_kernel(); - return -ENODEV; + mutex_unlock(&cx25821_devlist_mutex); + return -ENODEV; } file->private_data = fh; @@ -862,7 +861,7 @@ static int video_open(struct file *file) sizeof(struct cx25821_buffer), fh, NULL); dprintk(1, "post videobuf_queue_init()\n"); - unlock_kernel(); + mutex_unlock(&cx25821_devlist_mutex); return 0; } diff --git a/drivers/staging/cx25821/cx25821.h b/drivers/staging/cx25821/cx25821.h index 55115235f7f6..6230243e2ccb 100644 --- a/drivers/staging/cx25821/cx25821.h +++ b/drivers/staging/cx25821/cx25821.h @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -445,6 +444,8 @@ static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) extern struct list_head cx25821_devlist; +extern struct mutex cx25821_devlist_mutex; + extern struct cx25821_board cx25821_boards[]; extern struct cx25821_subid cx25821_subids[]; -- cgit v1.2.2 From f41e4e99404ad7a6afce2817843336c681b63e46 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Fri, 25 Feb 2011 03:11:17 -0300 Subject: [media] drivers:media:cx23418.h remove one to many l's in the word The patch below removes an extra "l" in the word. Signed-off-by: Justin P. Mattock Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx23418.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h index 7e40035028d2..935f557acbd0 100644 --- a/drivers/media/video/cx18/cx23418.h +++ b/drivers/media/video/cx18/cx23418.h @@ -477,7 +477,7 @@ /* The are no buffers ready. Try again soon! */ #define CXERR_NODATA_AGAIN 0x00001E -/* The stream is stopping. Function not alllowed now! */ +/* The stream is stopping. Function not allowed now! */ #define CXERR_STOPPING_STATUS 0x00001F /* Trying to access hardware when the power is turned OFF */ -- cgit v1.2.2 From b251e618470fee811535123c2775dfcf2b8223ab Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Fri, 25 Feb 2011 03:11:36 -0300 Subject: [media] drivers:media:cx231xx.h remove one to many l's in the word The patch below removes an extra "l" in the word. Signed-off-by: Justin P. Mattock Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx231xx/cx231xx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 2d5ab0cd79d7..bd4a9cf29577 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -469,7 +469,7 @@ struct cx231xx_fh { #define I2C_STOP 0x0 /* 1-- do not transmit STOP at end of transaction */ #define I2C_NOSTOP 0x1 -/* 1--alllow slave to insert clock wait states */ +/* 1--allow slave to insert clock wait states */ #define I2C_SYNC 0x1 struct cx231xx_i2c { -- cgit v1.2.2 From fc0a80798576f80ca10b3f6c9c7097f12fd1d64e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 12 Jul 2010 11:09:41 -0300 Subject: [media] v4l: Share code between video_usercopy and video_ioctl2 The two functions are mostly identical. They handle the copy_from_user and copy_to_user operations related with V4L2 ioctls and call the real ioctl handler. Create a __video_usercopy function that implements the core of video_usercopy and video_ioctl2, and call that function from both. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ioctl.c | 109 ++++----------------------------------- 1 file changed, 11 insertions(+), 98 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 7a720745c3fa..db6ec3868347 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -294,101 +294,6 @@ void v4l_printk_ioctl(unsigned int cmd) } EXPORT_SYMBOL(v4l_printk_ioctl); -/* - * helper function -- handles userspace copying for ioctl arguments - * Obsolete usercopy function - Should be removed soon - */ -long -video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, - v4l2_kioctl func) -{ - char sbuf[128]; - void *mbuf = NULL; - void *parg = NULL; - long err = -EINVAL; - int is_ext_ctrl; - size_t ctrls_size = 0; - void __user *user_ptr = NULL; - - is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || - cmd == VIDIOC_TRY_EXT_CTRLS); - - /* Copy arguments into temp kernel buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: - parg = NULL; - break; - case _IOC_READ: - case _IOC_WRITE: - case (_IOC_WRITE | _IOC_READ): - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; - } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; - } - - err = -EFAULT; - if (_IOC_DIR(cmd) & _IOC_WRITE) - if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) - goto out; - break; - } - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; - - /* In case of an error, tell the caller that it wasn't - a specific control that caused it. */ - p->error_idx = p->count; - user_ptr = (void __user *)p->controls; - if (p->count) { - ctrls_size = sizeof(struct v4l2_ext_control) * p->count; - /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ - mbuf = kmalloc(ctrls_size, GFP_KERNEL); - err = -ENOMEM; - if (NULL == mbuf) - goto out_ext_ctrl; - err = -EFAULT; - if (copy_from_user(mbuf, user_ptr, ctrls_size)) - goto out_ext_ctrl; - p->controls = mbuf; - } - } - - /* call driver */ - err = func(file, cmd, parg); - if (err == -ENOIOCTLCMD) - err = -EINVAL; - if (is_ext_ctrl) { - struct v4l2_ext_controls *p = parg; - - p->controls = (void *)user_ptr; - if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) - err = -EFAULT; - goto out_ext_ctrl; - } - if (err < 0) - goto out; - -out_ext_ctrl: - /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_READ: - case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; - break; - } - -out: - kfree(mbuf); - return err; -} -EXPORT_SYMBOL(video_usercopy); - static void dbgbuf(unsigned int cmd, struct video_device *vfd, struct v4l2_buffer *p) { @@ -2332,8 +2237,9 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, return ret; } -long video_ioctl2(struct file *file, - unsigned int cmd, unsigned long arg) +long +video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, + v4l2_kioctl func) { char sbuf[128]; void *mbuf = NULL; @@ -2395,7 +2301,7 @@ long video_ioctl2(struct file *file, } /* Handles IOCTL */ - err = __video_do_ioctl(file, cmd, parg); + err = func(file, cmd, parg); if (err == -ENOIOCTLCMD) err = -EINVAL; @@ -2422,4 +2328,11 @@ out: kfree(mbuf); return err; } +EXPORT_SYMBOL(video_usercopy); + +long video_ioctl2(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(file, cmd, arg, __video_do_ioctl); +} EXPORT_SYMBOL(video_ioctl2); -- cgit v1.2.2 From 2096a5dcf9704f5a86ecba37169eb813aaf0431c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:38:49 -0300 Subject: [media] v4l: subdev: Add device node support Create a device node named subdevX for every registered subdev. As the device node is registered before the subdev core::s_config function is called, return -EGAIN on open until initialization completes. Signed-off-by: Laurent Pinchart Signed-off-by: Vimarsh Zutshi Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Makefile | 2 +- drivers/media/video/v4l2-dev.c | 27 +++++++----------- drivers/media/video/v4l2-device.c | 37 ++++++++++++++++++++++++ drivers/media/video/v4l2-subdev.c | 60 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 drivers/media/video/v4l2-subdev.c (limited to 'drivers') diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index ac54652396e3..7ea65163090e 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ - v4l2-event.o v4l2-ctrls.o + v4l2-event.o v4l2-ctrls.o v4l2-subdev.o # V4L2 core modules diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 341764a3a990..abe04ef38066 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -408,13 +408,14 @@ static int get_index(struct video_device *vdev) } /** - * video_register_device - register video4linux devices + * __video_register_device - register video4linux devices * @vdev: video device structure we want to register * @type: type of device to register * @nr: which device node number (0 == /dev/video0, 1 == /dev/video1, ... * -1 == first free) * @warn_if_nr_in_use: warn if the desired device node number * was already in use and another number was chosen instead. + * @owner: module that owns the video device node * * The registration code assigns minor numbers and device node numbers * based on the requested type and registers the new device node with @@ -435,9 +436,11 @@ static int get_index(struct video_device *vdev) * %VFL_TYPE_VBI - Vertical blank data (undecoded) * * %VFL_TYPE_RADIO - A radio card + * + * %VFL_TYPE_SUBDEV - A subdevice */ -static int __video_register_device(struct video_device *vdev, int type, int nr, - int warn_if_nr_in_use) +int __video_register_device(struct video_device *vdev, int type, int nr, + int warn_if_nr_in_use, struct module *owner) { int i = 0; int ret; @@ -469,6 +472,9 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, case VFL_TYPE_RADIO: name_base = "radio"; break; + case VFL_TYPE_SUBDEV: + name_base = "v4l-subdev"; + break; default: printk(KERN_ERR "%s called with unknown type: %d\n", __func__, type); @@ -552,7 +558,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, goto cleanup; } vdev->cdev->ops = &v4l2_fops; - vdev->cdev->owner = vdev->fops->owner; + vdev->cdev->owner = owner; ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); if (ret < 0) { printk(KERN_ERR "%s: cdev_add failed\n", __func__); @@ -597,18 +603,7 @@ cleanup: vdev->minor = -1; return ret; } - -int video_register_device(struct video_device *vdev, int type, int nr) -{ - return __video_register_device(vdev, type, nr, 1); -} -EXPORT_SYMBOL(video_register_device); - -int video_register_device_no_warn(struct video_device *vdev, int type, int nr) -{ - return __video_register_device(vdev, type, nr, 0); -} -EXPORT_SYMBOL(video_register_device_no_warn); +EXPORT_SYMBOL(__video_register_device); /** * video_unregister_device - unregister a video4linux device diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index ce64fe16bc60..8c0ad8b372d8 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -124,16 +124,20 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, /* Check for valid input */ if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) return -EINVAL; + /* Warn if we apparently re-register a subdev */ WARN_ON(sd->v4l2_dev != NULL); + if (!try_module_get(sd->owner)) return -ENODEV; + sd->v4l2_dev = v4l2_dev; if (sd->internal_ops && sd->internal_ops->registered) { err = sd->internal_ops->registered(sd); if (err) return err; } + /* This just returns 0 if either of the two args is NULL */ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler); if (err) { @@ -141,24 +145,57 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, sd->internal_ops->unregistered(sd); return err; } + spin_lock(&v4l2_dev->lock); list_add_tail(&sd->list, &v4l2_dev->subdevs); spin_unlock(&v4l2_dev->lock); + return 0; } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); +int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) +{ + struct video_device *vdev; + struct v4l2_subdev *sd; + int err; + + /* Register a device node for every subdev marked with the + * V4L2_SUBDEV_FL_HAS_DEVNODE flag. + */ + list_for_each_entry(sd, &v4l2_dev->subdevs, list) { + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE)) + continue; + + vdev = &sd->devnode; + strlcpy(vdev->name, sd->name, sizeof(vdev->name)); + vdev->v4l2_dev = v4l2_dev; + vdev->fops = &v4l2_subdev_fops; + vdev->release = video_device_release_empty; + err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, + sd->owner); + if (err < 0) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); + void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) { /* return if it isn't registered */ if (sd == NULL || sd->v4l2_dev == NULL) return; + spin_lock(&sd->v4l2_dev->lock); list_del(&sd->list); spin_unlock(&sd->v4l2_dev->lock); if (sd->internal_ops && sd->internal_ops->unregistered) sd->internal_ops->unregistered(sd); sd->v4l2_dev = NULL; + + video_unregister_device(&sd->devnode); module_put(sd->owner); } EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c new file mode 100644 index 000000000000..037aa28a5ed1 --- /dev/null +++ b/drivers/media/video/v4l2-subdev.c @@ -0,0 +1,60 @@ +/* + * V4L2 subdevice support. + * + * Copyright (C) 2010 Nokia Corporation + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include + +static int subdev_open(struct file *file) +{ + return 0; +} + +static int subdev_close(struct file *file) +{ + return 0; +} + +static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) +{ + switch (cmd) { + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static long subdev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return video_usercopy(file, cmd, arg, subdev_do_ioctl); +} + +const struct v4l2_file_operations v4l2_subdev_fops = { + .owner = THIS_MODULE, + .open = subdev_open, + .unlocked_ioctl = subdev_ioctl, + .release = subdev_close, +}; -- cgit v1.2.2 From 3dd5ee0801ee10e5632b40fd8d0495417b32910a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:38:52 -0300 Subject: [media] v4l: subdev: Uninline the v4l2_subdev_init function The function isn't small or performance sensitive enough to be inlined. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 41 ++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 037aa28a5ed1..460b33697c9b 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -1,22 +1,23 @@ /* - * V4L2 subdevice support. + * V4L2 sub-device * - * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Nokia Corporation * - * Contact: Laurent Pinchart + * Contact: Laurent Pinchart + * Sakari Ailus * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. + * 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. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include @@ -58,3 +59,17 @@ const struct v4l2_file_operations v4l2_subdev_fops = { .unlocked_ioctl = subdev_ioctl, .release = subdev_close, }; + +void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) +{ + INIT_LIST_HEAD(&sd->list); + BUG_ON(!ops); + sd->ops = ops; + sd->v4l2_dev = NULL; + sd->flags = 0; + sd->name[0] = '\0'; + sd->grp_id = 0; + sd->dev_priv = NULL; + sd->host_priv = NULL; +} +EXPORT_SYMBOL(v4l2_subdev_init); -- cgit v1.2.2 From ea8aa4349e11c62242a8908fc172de27d7a151d7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:39:54 -0300 Subject: [media] v4l: subdev: Control ioctls support Pass the control-related ioctls to the subdev driver through the control framework. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 460b33697c9b..da10430051c0 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -39,7 +40,31 @@ static int subdev_close(struct file *file) static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + switch (cmd) { + case VIDIOC_QUERYCTRL: + return v4l2_subdev_queryctrl(sd, arg); + + case VIDIOC_QUERYMENU: + return v4l2_subdev_querymenu(sd, arg); + + case VIDIOC_G_CTRL: + return v4l2_subdev_g_ctrl(sd, arg); + + case VIDIOC_S_CTRL: + return v4l2_subdev_s_ctrl(sd, arg); + + case VIDIOC_G_EXT_CTRLS: + return v4l2_subdev_g_ext_ctrls(sd, arg); + + case VIDIOC_S_EXT_CTRLS: + return v4l2_subdev_s_ext_ctrls(sd, arg); + + case VIDIOC_TRY_EXT_CTRLS: + return v4l2_subdev_try_ext_ctrls(sd, arg); + default: return -ENOIOCTLCMD; } -- cgit v1.2.2 From 02adb1cc765b8c29dc83c6602bda19003cce62f1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 3 Mar 2010 12:49:38 -0300 Subject: [media] v4l: subdev: Events support Provide v4l2_subdevs with v4l2_event support. Subdev drivers only need very little to support events. Signed-off-by: Sakari Ailus Signed-off-by: David Cohen Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 78 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index da10430051c0..0c67f5a278fb 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -20,21 +20,66 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include +#include +#include #include #include #include #include +#include +#include static int subdev_open(struct file *file) { + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh; + int ret; + + if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { + vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); + if (vfh == NULL) + return -ENOMEM; + + ret = v4l2_fh_init(vfh, vdev); + if (ret) + goto err; + + ret = v4l2_event_init(vfh); + if (ret) + goto err; + + ret = v4l2_event_alloc(vfh, sd->nevents); + if (ret) + goto err; + + v4l2_fh_add(vfh); + file->private_data = vfh; + } + return 0; + +err: + if (vfh != NULL) { + v4l2_fh_exit(vfh); + kfree(vfh); + } + + return ret; } static int subdev_close(struct file *file) { + struct v4l2_fh *vfh = file->private_data; + + if (vfh != NULL) { + v4l2_fh_del(vfh); + v4l2_fh_exit(vfh); + kfree(vfh); + } + return 0; } @@ -42,6 +87,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *fh = file->private_data; switch (cmd) { case VIDIOC_QUERYCTRL: @@ -65,6 +111,18 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_TRY_EXT_CTRLS: return v4l2_subdev_try_ext_ctrls(sd, arg); + case VIDIOC_DQEVENT: + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return -ENOIOCTLCMD; + + return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); + + case VIDIOC_SUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, subscribe_event, fh, arg); + + case VIDIOC_UNSUBSCRIBE_EVENT: + return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg); + default: return -ENOIOCTLCMD; } @@ -78,11 +136,29 @@ static long subdev_ioctl(struct file *file, unsigned int cmd, return video_usercopy(file, cmd, arg, subdev_do_ioctl); } +static unsigned int subdev_poll(struct file *file, poll_table *wait) +{ + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *fh = file->private_data; + + if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) + return POLLERR; + + poll_wait(file, &fh->events->wait, wait); + + if (v4l2_event_pending(fh)) + return POLLPRI; + + return 0; +} + const struct v4l2_file_operations v4l2_subdev_fops = { .owner = THIS_MODULE, .open = subdev_open, .unlocked_ioctl = subdev_ioctl, .release = subdev_close, + .poll = subdev_poll, }; void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) -- cgit v1.2.2 From 4f2d56c45fec7c15169599cab05e9f6df18769d0 Mon Sep 17 00:00:00 2001 From: Jan Altenberg Date: Mon, 21 Mar 2011 18:19:26 -0700 Subject: can: c_can: Do basic c_can configuration _before_ enabling the interrupts I ran into some trouble while testing the SocketCAN driver for the BOSCH C_CAN controller. The interface is not correctly initialized, if I put some CAN traffic on the line, _while_ the interface is being started (which means: the interface doesn't come up correcty, if there's some RX traffic while doing 'ifconfig can0 up'). The current implementation enables the controller interrupts _before_ doing the basic c_can configuration. I think, this should be done the other way round. The patch below fixes things for me. Signed-off-by: Jan Altenberg Acked-by: Kurt Van Dijck Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/c_can/c_can.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 14050786218a..110eda01843c 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -633,9 +633,6 @@ static void c_can_start(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); - /* enable status change, error and module interrupts */ - c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); - /* basic c_can configuration */ c_can_chip_config(dev); @@ -643,6 +640,9 @@ static void c_can_start(struct net_device *dev) /* reset tx helper pointers */ priv->tx_next = priv->tx_echo = 0; + + /* enable status change, error and module interrupts */ + c_can_enable_all_interrupts(priv, ENABLE_ALL_INTERRUPTS); } static void c_can_stop(struct net_device *dev) -- cgit v1.2.2 From d5cd92448fded12c91f7574e49747c5f7d975a8d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 21 Mar 2011 18:22:22 -0700 Subject: macvlan: Fix use after free of struct macvlan_port. When the macvlan driver was extended to call unregisgter_netdevice_queue in 23289a37e2b127dfc4de1313fba15bb4c9f0cd5b, a use after free of struct macvlan_port was introduced. The code in dellink relied on unregister_netdevice actually unregistering the net device so it would be safe to free macvlan_port. Since unregister_netdevice_queue can just queue up the unregister instead of performing the unregiser immediately we free the macvlan_port too soon and then the code in macvlan_stop removes the macaddress for the set of macaddress to listen for and uses memory that has already been freed. To fix this add a reference count to track when it is safe to free the macvlan_port and move the call of macvlan_port_destroy into macvlan_uninit which is guaranteed to be called after the final macvlan_port_close. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 5b37d3c191e4..78e34e9e4f00 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -39,8 +39,11 @@ struct macvlan_port { struct list_head vlans; struct rcu_head rcu; bool passthru; + int count; }; +static void macvlan_port_destroy(struct net_device *dev); + #define macvlan_port_get_rcu(dev) \ ((struct macvlan_port *) rcu_dereference(dev->rx_handler_data)) #define macvlan_port_get(dev) ((struct macvlan_port *) dev->rx_handler_data) @@ -457,8 +460,13 @@ static int macvlan_init(struct net_device *dev) static void macvlan_uninit(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); + struct macvlan_port *port = vlan->port; free_percpu(vlan->pcpu_stats); + + port->count -= 1; + if (!port->count) + macvlan_port_destroy(port->dev); } static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, @@ -691,12 +699,13 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); if (vlan->mode == MACVLAN_MODE_PASSTHRU) { - if (!list_empty(&port->vlans)) + if (port->count) return -EINVAL; port->passthru = true; memcpy(dev->dev_addr, lowerdev->dev_addr, ETH_ALEN); } + port->count += 1; err = register_netdevice(dev); if (err < 0) goto destroy_port; @@ -707,7 +716,8 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, return 0; destroy_port: - if (list_empty(&port->vlans)) + port->count -= 1; + if (!port->count) macvlan_port_destroy(lowerdev); return err; @@ -725,13 +735,9 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, void macvlan_dellink(struct net_device *dev, struct list_head *head) { struct macvlan_dev *vlan = netdev_priv(dev); - struct macvlan_port *port = vlan->port; list_del(&vlan->list); unregister_netdevice_queue(dev, head); - - if (list_empty(&port->vlans)) - macvlan_port_destroy(port->dev); } EXPORT_SYMBOL_GPL(macvlan_dellink); -- cgit v1.2.2 From 675071a2ef3f4a6d25ee002a7437d50431168344 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 21 Mar 2011 18:24:53 -0700 Subject: veth: Fix the byte counters Commit 44540960 "veth: move loopback logic to common location" introduced a bug in the packet counters. I don't understand why that happened as it is not explained in the comments and the mut check in dev_forward_skb retains the assumption that skb->len is the total length of the packet. I just measured this emperically by setting up a veth pair between two noop network namespaces setting and attempting a telnet connection between the two. I saw three packets in each direction and the byte counters were exactly 14*3 = 42 bytes high in each direction. I got the actual packet lengths with tcpdump. So remove the extra ETH_HLEN from the veth byte count totals. Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller --- drivers/net/veth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 105d7f0630cc..2de9b90c5f8f 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -171,7 +171,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) if (skb->ip_summed == CHECKSUM_NONE) skb->ip_summed = rcv_priv->ip_summed; - length = skb->len + ETH_HLEN; + length = skb->len; if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) goto rx_drop; -- cgit v1.2.2 From 885b976fada5bc6595a9fd3e67e3cb1a3d11f50b Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Mon, 21 Feb 2011 13:54:41 +0800 Subject: ACPI, APEI, Add ERST record ID cache APEI ERST firmware interface and implementation has no multiple users in mind. For example, if there is four records in storage with ID: 1, 2, 3 and 4, if two ERST readers enumerate the records via GET_NEXT_RECORD_ID as follow, reader 1 reader 2 1 2 3 4 -1 -1 where -1 signals there is no more record ID. Reader 1 has no chance to check record 2 and 4, while reader 2 has no chance to check record 1 and 3. And any other GET_NEXT_RECORD_ID will return -1, that is, other readers will has no chance to check any record even they are not cleared by anyone. This makes raw GET_NEXT_RECORD_ID not suitable for used by multiple users. To solve the issue, an in-memory ERST record ID cache is designed and implemented. When enumerating record ID, the ID returned by GET_NEXT_RECORD_ID is added into cache in addition to be returned to caller. So other readers can check the cache to get all record ID available. Signed-off-by: Huang Ying Reviewed-by: Andi Kleen Signed-off-by: Len Brown --- drivers/acpi/apei/erst-dbg.c | 24 ++++- drivers/acpi/apei/erst.c | 235 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 212 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c index de73caf3cebc..a4cfb64c86a1 100644 --- a/drivers/acpi/apei/erst-dbg.c +++ b/drivers/acpi/apei/erst-dbg.c @@ -43,12 +43,27 @@ static DEFINE_MUTEX(erst_dbg_mutex); static int erst_dbg_open(struct inode *inode, struct file *file) { + int rc, *pos; + if (erst_disable) return -ENODEV; + pos = (int *)&file->private_data; + + rc = erst_get_record_id_begin(pos); + if (rc) + return rc; + return nonseekable_open(inode, file); } +static int erst_dbg_release(struct inode *inode, struct file *file) +{ + erst_get_record_id_end(); + + return 0; +} + static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { int rc; @@ -79,18 +94,20 @@ static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg) static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf, size_t usize, loff_t *off) { - int rc; + int rc, *pos; ssize_t len = 0; u64 id; - if (*off != 0) + if (*off) return -EINVAL; if (mutex_lock_interruptible(&erst_dbg_mutex) != 0) return -EINTR; + pos = (int *)&filp->private_data; + retry_next: - rc = erst_get_next_record_id(&id); + rc = erst_get_record_id_next(pos, &id); if (rc) goto out; /* no more record */ @@ -181,6 +198,7 @@ out: static const struct file_operations erst_dbg_ops = { .owner = THIS_MODULE, .open = erst_dbg_open, + .release = erst_dbg_release, .read = erst_dbg_read, .write = erst_dbg_write, .unlocked_ioctl = erst_dbg_ioctl, diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index cf6db6b7662a..8ff8c32fef58 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -429,6 +429,22 @@ ssize_t erst_get_record_count(void) } EXPORT_SYMBOL_GPL(erst_get_record_count); +#define ERST_RECORD_ID_CACHE_SIZE_MIN 16 +#define ERST_RECORD_ID_CACHE_SIZE_MAX 1024 + +struct erst_record_id_cache { + struct mutex lock; + u64 *entries; + int len; + int size; + int refcount; +}; + +static struct erst_record_id_cache erst_record_id_cache = { + .lock = __MUTEX_INITIALIZER(erst_record_id_cache.lock), + .refcount = 0, +}; + static int __erst_get_next_record_id(u64 *record_id) { struct apei_exec_context ctx; @@ -443,26 +459,179 @@ static int __erst_get_next_record_id(u64 *record_id) return 0; } +int erst_get_record_id_begin(int *pos) +{ + int rc; + + if (erst_disable) + return -ENODEV; + + rc = mutex_lock_interruptible(&erst_record_id_cache.lock); + if (rc) + return rc; + erst_record_id_cache.refcount++; + mutex_unlock(&erst_record_id_cache.lock); + + *pos = 0; + + return 0; +} +EXPORT_SYMBOL_GPL(erst_get_record_id_begin); + +/* erst_record_id_cache.lock must be held by caller */ +static int __erst_record_id_cache_add_one(void) +{ + u64 id, prev_id, first_id; + int i, rc; + u64 *entries; + unsigned long flags; + + id = prev_id = first_id = APEI_ERST_INVALID_RECORD_ID; +retry: + raw_spin_lock_irqsave(&erst_lock, flags); + rc = __erst_get_next_record_id(&id); + raw_spin_unlock_irqrestore(&erst_lock, flags); + if (rc == -ENOENT) + return 0; + if (rc) + return rc; + if (id == APEI_ERST_INVALID_RECORD_ID) + return 0; + /* can not skip current ID, or loop back to first ID */ + if (id == prev_id || id == first_id) + return 0; + if (first_id == APEI_ERST_INVALID_RECORD_ID) + first_id = id; + prev_id = id; + + entries = erst_record_id_cache.entries; + for (i = 0; i < erst_record_id_cache.len; i++) { + if (entries[i] == id) + break; + } + /* record id already in cache, try next */ + if (i < erst_record_id_cache.len) + goto retry; + if (erst_record_id_cache.len >= erst_record_id_cache.size) { + int new_size, alloc_size; + u64 *new_entries; + + new_size = erst_record_id_cache.size * 2; + new_size = clamp_val(new_size, ERST_RECORD_ID_CACHE_SIZE_MIN, + ERST_RECORD_ID_CACHE_SIZE_MAX); + if (new_size <= erst_record_id_cache.size) { + if (printk_ratelimit()) + pr_warning(FW_WARN ERST_PFX + "too many record ID!\n"); + return 0; + } + alloc_size = new_size * sizeof(entries[0]); + if (alloc_size < PAGE_SIZE) + new_entries = kmalloc(alloc_size, GFP_KERNEL); + else + new_entries = vmalloc(alloc_size); + if (!new_entries) + return -ENOMEM; + memcpy(new_entries, entries, + erst_record_id_cache.len * sizeof(entries[0])); + if (erst_record_id_cache.size < PAGE_SIZE) + kfree(entries); + else + vfree(entries); + erst_record_id_cache.entries = entries = new_entries; + erst_record_id_cache.size = new_size; + } + entries[i] = id; + erst_record_id_cache.len++; + + return 1; +} + /* * Get the record ID of an existing error record on the persistent * storage. If there is no error record on the persistent storage, the * returned record_id is APEI_ERST_INVALID_RECORD_ID. */ -int erst_get_next_record_id(u64 *record_id) +int erst_get_record_id_next(int *pos, u64 *record_id) { - int rc; - unsigned long flags; + int rc = 0; + u64 *entries; if (erst_disable) return -ENODEV; - raw_spin_lock_irqsave(&erst_lock, flags); - rc = __erst_get_next_record_id(record_id); - raw_spin_unlock_irqrestore(&erst_lock, flags); + /* must be enclosed by erst_get_record_id_begin/end */ + BUG_ON(!erst_record_id_cache.refcount); + BUG_ON(*pos < 0 || *pos > erst_record_id_cache.len); + + mutex_lock(&erst_record_id_cache.lock); + entries = erst_record_id_cache.entries; + for (; *pos < erst_record_id_cache.len; (*pos)++) + if (entries[*pos] != APEI_ERST_INVALID_RECORD_ID) + break; + /* found next record id in cache */ + if (*pos < erst_record_id_cache.len) { + *record_id = entries[*pos]; + (*pos)++; + goto out_unlock; + } + + /* Try to add one more record ID to cache */ + rc = __erst_record_id_cache_add_one(); + if (rc < 0) + goto out_unlock; + /* successfully add one new ID */ + if (rc == 1) { + *record_id = erst_record_id_cache.entries[*pos]; + (*pos)++; + rc = 0; + } else { + *pos = -1; + *record_id = APEI_ERST_INVALID_RECORD_ID; + } +out_unlock: + mutex_unlock(&erst_record_id_cache.lock); return rc; } -EXPORT_SYMBOL_GPL(erst_get_next_record_id); +EXPORT_SYMBOL_GPL(erst_get_record_id_next); + +/* erst_record_id_cache.lock must be held by caller */ +static void __erst_record_id_cache_compact(void) +{ + int i, wpos = 0; + u64 *entries; + + if (erst_record_id_cache.refcount) + return; + + entries = erst_record_id_cache.entries; + for (i = 0; i < erst_record_id_cache.len; i++) { + if (entries[i] == APEI_ERST_INVALID_RECORD_ID) + continue; + if (wpos != i) + memcpy(&entries[wpos], &entries[i], sizeof(entries[i])); + wpos++; + } + erst_record_id_cache.len = wpos; +} + +void erst_get_record_id_end(void) +{ + /* + * erst_disable != 0 should be detected by invoker via the + * return value of erst_get_record_id_begin/next, so this + * function should not be called for erst_disable != 0. + */ + BUG_ON(erst_disable); + + mutex_lock(&erst_record_id_cache.lock); + erst_record_id_cache.refcount--; + BUG_ON(erst_record_id_cache.refcount < 0); + __erst_record_id_cache_compact(); + mutex_unlock(&erst_record_id_cache.lock); +} +EXPORT_SYMBOL_GPL(erst_get_record_id_end); static int __erst_write_to_storage(u64 offset) { @@ -703,56 +872,34 @@ ssize_t erst_read(u64 record_id, struct cper_record_header *record, } EXPORT_SYMBOL_GPL(erst_read); -/* - * If return value > buflen, the buffer size is not big enough, - * else if return value = 0, there is no more record to read, - * else if return value < 0, something goes wrong, - * else everything is OK, and return value is record length - */ -ssize_t erst_read_next(struct cper_record_header *record, size_t buflen) -{ - int rc; - ssize_t len; - unsigned long flags; - u64 record_id; - - if (erst_disable) - return -ENODEV; - - raw_spin_lock_irqsave(&erst_lock, flags); - rc = __erst_get_next_record_id(&record_id); - if (rc) { - raw_spin_unlock_irqrestore(&erst_lock, flags); - return rc; - } - /* no more record */ - if (record_id == APEI_ERST_INVALID_RECORD_ID) { - raw_spin_unlock_irqrestore(&erst_lock, flags); - return 0; - } - - len = __erst_read(record_id, record, buflen); - raw_spin_unlock_irqrestore(&erst_lock, flags); - - return len; -} -EXPORT_SYMBOL_GPL(erst_read_next); - int erst_clear(u64 record_id) { - int rc; + int rc, i; unsigned long flags; + u64 *entries; if (erst_disable) return -ENODEV; + rc = mutex_lock_interruptible(&erst_record_id_cache.lock); + if (rc) + return rc; raw_spin_lock_irqsave(&erst_lock, flags); if (erst_erange.attr & ERST_RANGE_NVRAM) rc = __erst_clear_from_nvram(record_id); else rc = __erst_clear_from_storage(record_id); raw_spin_unlock_irqrestore(&erst_lock, flags); - + if (rc) + goto out; + entries = erst_record_id_cache.entries; + for (i = 0; i < erst_record_id_cache.len; i++) { + if (entries[i] == record_id) + entries[i] = APEI_ERST_INVALID_RECORD_ID; + } + __erst_record_id_cache_compact(); +out: + mutex_unlock(&erst_record_id_cache.lock); return rc; } EXPORT_SYMBOL_GPL(erst_clear); -- cgit v1.2.2 From b64a44146540a4761bb1cf8047fffd9dbf0c3090 Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Mon, 21 Feb 2011 13:54:42 +0800 Subject: PCIe, AER, use pre-generated prefix in error information printing When printing PCIe AER error information, each line is prefixed with PCIe device and driver information. In original implementation, the prefix is generated when each line is printed. In fact, all lines share the same prefix. So this patch pre-generated the prefix, and use that one when each line is printed. In addition to common prefix can be pre-generated, the trailing white spaces in string constants and NULLs in char * array constants can be removed too. These can reduce the object file size further. The size of object file before and after changing is as follow: text data bss dec before: 3038 0 0 3038 after: 2118 0 0 2118 Signed-off-by: Huang Ying CC: Jesse Barnes CC: Zhang Yanmin Signed-off-by: Len Brown --- drivers/pci/pcie/aer/aerdrv_errprint.c | 123 +++++++++++++-------------------- 1 file changed, 48 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 9d3e4c8d0184..7a237f67129e 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -57,86 +57,44 @@ (e & AER_DATA_LINK_LAYER_ERROR_MASK(t)) ? AER_DATA_LINK_LAYER_ERROR : \ AER_TRANSACTION_LAYER_ERROR) -#define AER_PR(info, pdev, fmt, args...) \ - printk("%s%s %s: " fmt, (info->severity == AER_CORRECTABLE) ? \ - KERN_WARNING : KERN_ERR, dev_driver_string(&pdev->dev), \ - dev_name(&pdev->dev), ## args) - /* * AER error strings */ -static char *aer_error_severity_string[] = { +static const char *aer_error_severity_string[] = { "Uncorrected (Non-Fatal)", "Uncorrected (Fatal)", "Corrected" }; -static char *aer_error_layer[] = { +static const char *aer_error_layer[] = { "Physical Layer", "Data Link Layer", "Transaction Layer" }; -static char *aer_correctable_error_string[] = { - "Receiver Error ", /* Bit Position 0 */ - NULL, - NULL, - NULL, - NULL, - NULL, - "Bad TLP ", /* Bit Position 6 */ - "Bad DLLP ", /* Bit Position 7 */ - "RELAY_NUM Rollover ", /* Bit Position 8 */ - NULL, - NULL, - NULL, - "Replay Timer Timeout ", /* Bit Position 12 */ - "Advisory Non-Fatal ", /* Bit Position 13 */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + +static const char *aer_correctable_error_string[] = { + "Receiver Error", /* Bit Position 0 */ NULL, NULL, NULL, NULL, NULL, + "Bad TLP", /* Bit Position 6 */ + "Bad DLLP", /* Bit Position 7 */ + "RELAY_NUM Rollover", /* Bit Position 8 */ NULL, NULL, NULL, + "Replay Timer Timeout", /* Bit Position 12 */ + "Advisory Non-Fatal", /* Bit Position 13 */ }; -static char *aer_uncorrectable_error_string[] = { - NULL, - NULL, - NULL, - NULL, - "Data Link Protocol ", /* Bit Position 4 */ - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "Poisoned TLP ", /* Bit Position 12 */ - "Flow Control Protocol ", /* Bit Position 13 */ - "Completion Timeout ", /* Bit Position 14 */ - "Completer Abort ", /* Bit Position 15 */ - "Unexpected Completion ", /* Bit Position 16 */ - "Receiver Overflow ", /* Bit Position 17 */ - "Malformed TLP ", /* Bit Position 18 */ - "ECRC ", /* Bit Position 19 */ - "Unsupported Request ", /* Bit Position 20 */ +static const char *aer_uncorrectable_error_string[] = { NULL, NULL, NULL, NULL, + "Data Link Protocol", /* Bit Position 4 */ NULL, NULL, NULL, @@ -144,19 +102,29 @@ static char *aer_uncorrectable_error_string[] = { NULL, NULL, NULL, + "Poisoned TLP", /* Bit Position 12 */ + "Flow Control Protocol", /* Bit Position 13 */ + "Completion Timeout", /* Bit Position 14 */ + "Completer Abort", /* Bit Position 15 */ + "Unexpected Completion", /* Bit Position 16 */ + "Receiver Overflow", /* Bit Position 17 */ + "Malformed TLP", /* Bit Position 18 */ + "ECRC", /* Bit Position 19 */ + "Unsupported Request", /* Bit Position 20 */ }; -static char *aer_agent_string[] = { +static const char *aer_agent_string[] = { "Receiver ID", "Requester ID", "Completer ID", "Transmitter ID" }; -static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) +static void __aer_print_error(const char *prefix, + struct aer_err_info *info) { int i, status; - char *errmsg = NULL; + const char *errmsg = NULL; status = (info->status & ~info->mask); @@ -165,15 +133,17 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) continue; if (info->severity == AER_CORRECTABLE) - errmsg = aer_correctable_error_string[i]; + errmsg = i < ARRAY_SIZE(aer_correctable_error_string) ? + aer_correctable_error_string[i] : NULL; else - errmsg = aer_uncorrectable_error_string[i]; + errmsg = i < ARRAY_SIZE(aer_uncorrectable_error_string) ? + aer_uncorrectable_error_string[i] : NULL; if (errmsg) - AER_PR(info, dev, " [%2d] %s%s\n", i, errmsg, + printk("%s"" [%2d] %-22s%s\n", prefix, i, errmsg, info->first_error == i ? " (First)" : ""); else - AER_PR(info, dev, " [%2d] Unknown Error Bit%s\n", i, + printk("%s"" [%2d] Unknown Error Bit%s\n", prefix, i, info->first_error == i ? " (First)" : ""); } } @@ -181,11 +151,15 @@ static void __aer_print_error(struct aer_err_info *info, struct pci_dev *dev) void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) { int id = ((dev->bus->number << 8) | dev->devfn); + char prefix[44]; + + snprintf(prefix, sizeof(prefix), "%s%s %s: ", + (info->severity == AER_CORRECTABLE) ? KERN_WARNING : KERN_ERR, + dev_driver_string(&dev->dev), dev_name(&dev->dev)); if (info->status == 0) { - AER_PR(info, dev, - "PCIe Bus Error: severity=%s, type=Unaccessible, " - "id=%04x(Unregistered Agent ID)\n", + printk("%s""PCIe Bus Error: severity=%s, type=Unaccessible, " + "id=%04x(Unregistered Agent ID)\n", prefix, aer_error_severity_string[info->severity], id); } else { int layer, agent; @@ -193,23 +167,22 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) layer = AER_GET_LAYER_ERROR(info->severity, info->status); agent = AER_GET_AGENT(info->severity, info->status); - AER_PR(info, dev, - "PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", - aer_error_severity_string[info->severity], + printk("%s""PCIe Bus Error: severity=%s, type=%s, id=%04x(%s)\n", + prefix, aer_error_severity_string[info->severity], aer_error_layer[layer], id, aer_agent_string[agent]); - AER_PR(info, dev, - " device [%04x:%04x] error status/mask=%08x/%08x\n", - dev->vendor, dev->device, info->status, info->mask); + printk("%s"" device [%04x:%04x] error status/mask=%08x/%08x\n", + prefix, dev->vendor, dev->device, + info->status, info->mask); - __aer_print_error(info, dev); + __aer_print_error(prefix, info); if (info->tlp_header_valid) { unsigned char *tlp = (unsigned char *) &info->tlp; - AER_PR(info, dev, " TLP Header:" + printk("%s"" TLP Header:" " %02x%02x%02x%02x %02x%02x%02x%02x" " %02x%02x%02x%02x %02x%02x%02x%02x\n", - *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, + prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), *(tlp + 11), *(tlp + 10), *(tlp + 9), *(tlp + 8), *(tlp + 15), *(tlp + 14), @@ -218,8 +191,8 @@ void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) } if (info->id && info->error_dev_num > 1 && info->id == id) - AER_PR(info, dev, - " Error of this Agent(%04x) is reported first\n", id); + printk("%s"" Error of this Agent(%04x) is reported first\n", + prefix, id); } void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) -- cgit v1.2.2 From c413d7682020a127f54744a1b30f597692aea1fd Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Mon, 21 Feb 2011 13:54:43 +0800 Subject: ACPI, APEI, Add PCIe AER error information printing support The AER error information printing support is implemented in drivers/pci/pcie/aer/aer_print.c. So some string constants, functions and macros definitions can be re-used without being exported. The original PCIe AER error information printing function is not re-used directly because the overall format is quite different. And changing the original printing format may make some original users' scripts broken. Signed-off-by: Huang Ying CC: Jesse Barnes CC: Zhang Yanmin Signed-off-by: Len Brown --- drivers/acpi/apei/Kconfig | 7 ++++ drivers/acpi/apei/cper.c | 18 ++++++++--- drivers/pci/pcie/aer/aerdrv.h | 9 +----- drivers/pci/pcie/aer/aerdrv_errprint.c | 59 ++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index fca34ccfd294..9ecf6feae830 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -21,6 +21,13 @@ config ACPI_APEI_GHES by firmware to produce more valuable hardware error information for Linux. +config ACPI_APEI_PCIEAER + bool "APEI PCIe AER logging/recovering support" + depends on ACPI_APEI && PCIEAER + help + PCIe AER errors may be reported via APEI firmware first mode. + Turn on this option to enable the corresponding support. + config ACPI_APEI_EINJ tristate "APEI Error INJection (EINJ)" depends on ACPI_APEI && DEBUG_FS diff --git a/drivers/acpi/apei/cper.c b/drivers/acpi/apei/cper.c index 31464a006d76..5d4189464d63 100644 --- a/drivers/acpi/apei/cper.c +++ b/drivers/acpi/apei/cper.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * CPER record ID need to be unique even after reboot, because record @@ -70,8 +71,8 @@ static const char *cper_severity_str(unsigned int severity) * If the output length is longer than 80, multiple line will be * printed, with @pfx is printed at the beginning of each line. */ -static void cper_print_bits(const char *pfx, unsigned int bits, - const char *strs[], unsigned int strs_size) +void cper_print_bits(const char *pfx, unsigned int bits, + const char *strs[], unsigned int strs_size) { int i, len = 0; const char *str; @@ -81,6 +82,8 @@ static void cper_print_bits(const char *pfx, unsigned int bits, if (!(bits & (1U << i))) continue; str = strs[i]; + if (!str) + continue; if (len && len + strlen(str) + 2 > 80) { printk("%s\n", buf); len = 0; @@ -243,7 +246,8 @@ static const char *cper_pcie_port_type_strs[] = { "root complex event collector", }; -static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie) +static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, + const struct acpi_hest_generic_data *gdata) { if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, @@ -276,6 +280,12 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie) printk( "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", pfx, pcie->bridge.secondary_status, pcie->bridge.control); +#ifdef CONFIG_ACPI_APEI_PCIEAER + if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) { + struct aer_capability_regs *aer_regs = (void *)pcie->aer_info; + cper_print_aer(pfx, gdata->error_severity, aer_regs); + } +#endif } static const char *apei_estatus_section_flag_strs[] = { @@ -322,7 +332,7 @@ static void apei_estatus_print_section( struct cper_sec_pcie *pcie = (void *)(gdata + 1); printk("%s""section_type: PCIe error\n", pfx); if (gdata->error_data_length >= sizeof(*pcie)) - cper_print_pcie(pfx, pcie); + cper_print_pcie(pfx, pcie, gdata); else goto err_section_too_small; } else diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 80c11d131499..3eb77080366a 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -35,13 +35,6 @@ PCI_ERR_UNC_UNX_COMP| \ PCI_ERR_UNC_MALF_TLP) -struct header_log_regs { - unsigned int dw0; - unsigned int dw1; - unsigned int dw2; - unsigned int dw3; -}; - #define AER_MAX_MULTI_ERR_DEVICES 5 /* Not likely to have more */ struct aer_err_info { struct pci_dev *dev[AER_MAX_MULTI_ERR_DEVICES]; @@ -59,7 +52,7 @@ struct aer_err_info { unsigned int status; /* COR/UNCOR Error Status */ unsigned int mask; /* COR/UNCOR Error Mask */ - struct header_log_regs tlp; /* TLP Header */ + struct aer_header_log_regs tlp; /* TLP Header */ }; struct aer_err_source { diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index 7a237f67129e..b07a42e0b350 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "aerdrv.h" @@ -201,3 +202,61 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info) info->multi_error_valid ? "Multiple " : "", aer_error_severity_string[info->severity], info->id); } + +#ifdef CONFIG_ACPI_APEI_PCIEAER +static int cper_severity_to_aer(int cper_severity) +{ + switch (cper_severity) { + case CPER_SEV_RECOVERABLE: + return AER_NONFATAL; + case CPER_SEV_FATAL: + return AER_FATAL; + default: + return AER_CORRECTABLE; + } +} + +void cper_print_aer(const char *prefix, int cper_severity, + struct aer_capability_regs *aer) +{ + int aer_severity, layer, agent, status_strs_size, tlp_header_valid = 0; + u32 status, mask; + const char **status_strs; + + aer_severity = cper_severity_to_aer(cper_severity); + if (aer_severity == AER_CORRECTABLE) { + status = aer->cor_status; + mask = aer->cor_mask; + status_strs = aer_correctable_error_string; + status_strs_size = ARRAY_SIZE(aer_correctable_error_string); + } else { + status = aer->uncor_status; + mask = aer->uncor_mask; + status_strs = aer_uncorrectable_error_string; + status_strs_size = ARRAY_SIZE(aer_uncorrectable_error_string); + tlp_header_valid = status & AER_LOG_TLP_MASKS; + } + layer = AER_GET_LAYER_ERROR(aer_severity, status); + agent = AER_GET_AGENT(aer_severity, status); + printk("%s""aer_status: 0x%08x, aer_mask: 0x%08x\n", + prefix, status, mask); + cper_print_bits(prefix, status, status_strs, status_strs_size); + printk("%s""aer_layer=%s, aer_agent=%s\n", prefix, + aer_error_layer[layer], aer_agent_string[agent]); + if (aer_severity != AER_CORRECTABLE) + printk("%s""aer_uncor_severity: 0x%08x\n", + prefix, aer->uncor_severity); + if (tlp_header_valid) { + const unsigned char *tlp; + tlp = (const unsigned char *)&aer->header_log; + printk("%s""aer_tlp_header:" + " %02x%02x%02x%02x %02x%02x%02x%02x" + " %02x%02x%02x%02x %02x%02x%02x%02x\n", + prefix, *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, + *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), + *(tlp + 11), *(tlp + 10), *(tlp + 9), + *(tlp + 8), *(tlp + 15), *(tlp + 14), + *(tlp + 13), *(tlp + 12)); + } +} +#endif -- cgit v1.2.2 From 9913319fc0b47f3f740633165dee4807d94d0096 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 15 Mar 2011 22:53:18 +0000 Subject: omap: use list_move() instead of list_del()/list_add() combination Signed-off-by: Kirill A. Shutemov Acked-by: Tomi Valkeinen Signed-off-by: Paul Mundt --- drivers/video/omap/blizzard.c | 3 +-- drivers/video/omap/hwa742.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c index 87785c215a52..c0504a8a5079 100644 --- a/drivers/video/omap/blizzard.c +++ b/drivers/video/omap/blizzard.c @@ -397,8 +397,7 @@ static inline void free_req(struct blizzard_request *req) spin_lock_irqsave(&blizzard.req_lock, flags); - list_del(&req->entry); - list_add(&req->entry, &blizzard.free_req_list); + list_move(&req->entry, &blizzard.free_req_list); if (!(req->flags & REQ_FROM_IRQ_POOL)) up(&blizzard.req_sema); diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c index 0016f77cd13f..084aa0ac562b 100644 --- a/drivers/video/omap/hwa742.c +++ b/drivers/video/omap/hwa742.c @@ -269,8 +269,7 @@ static inline void free_req(struct hwa742_request *req) spin_lock_irqsave(&hwa742.req_lock, flags); - list_del(&req->entry); - list_add(&req->entry, &hwa742.free_req_list); + list_move(&req->entry, &hwa742.free_req_list); if (!(req->flags & REQ_FROM_IRQ_POOL)) up(&hwa742.req_sema); -- cgit v1.2.2 From 1721af4d8581587409d66d4fe0be6bc455611e5b Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 15 Mar 2011 22:53:19 +0000 Subject: vmlfb: use list_move() instead of list_del()/list_add() combination Signed-off-by: Kirill A. Shutemov Signed-off-by: Paul Mundt --- drivers/video/vermilion/vermilion.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 931a567f9aff..970e43d13f52 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -891,8 +891,7 @@ static int vmlfb_set_par(struct fb_info *info) int ret; mutex_lock(&vml_mutex); - list_del(&vinfo->head); - list_add(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode); + list_move(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode); ret = vmlfb_set_par_locked(vinfo); mutex_unlock(&vml_mutex); -- cgit v1.2.2 From 83ea0f164c35fb847afd9309be9ba40431fc501d Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 13 Feb 2011 22:11:23 +0000 Subject: sisfb: POST should fail if R/W test fails Currently there is no indication if R/W test fails during POST. This can happen e.g. when user plugs in a card with unsupported type of memory. Since the driver will be unusable, it's better to fail the whole POST if the memory cannot be configured properly. Signed-off-by: Aaro Koskinen Cc: Thomas Winischhofer Signed-off-by: Paul Mundt --- drivers/video/sis/sis_main.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 2fb8c5a660fb..2c5de66dacf8 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -4627,11 +4627,11 @@ sisfb_post_xgi_rwtest(struct sis_video_info *ivideo, int starta, return 1; } -static void __devinit +static int __devinit sisfb_post_xgi_ramsize(struct sis_video_info *ivideo) { unsigned int buswidth, ranksize, channelab, mapsize; - int i, j, k, l; + int i, j, k, l, status; u8 reg, sr14; static const u8 dramsr13[12 * 5] = { 0x02, 0x0e, 0x0b, 0x80, 0x5d, @@ -4673,7 +4673,7 @@ sisfb_post_xgi_ramsize(struct sis_video_info *ivideo) SiS_SetReg(SISSR, 0x13, 0x35); SiS_SetReg(SISSR, 0x14, 0x41); /* TODO */ - return; + return -ENOMEM; } /* Non-interleaving */ @@ -4835,6 +4835,7 @@ bail_out: j = (ivideo->chip == XGI_20) ? 5 : 9; k = (ivideo->chip == XGI_20) ? 12 : 4; + status = -EIO; for(i = 0; i < k; i++) { @@ -4868,11 +4869,15 @@ bail_out: SiS_SetRegANDOR(SISSR, 0x14, 0x0f, (reg & 0xf0)); sisfb_post_xgi_delay(ivideo, 1); - if(sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) + if (sisfb_post_xgi_rwtest(ivideo, j, ((reg >> 4) + channelab - 2 + 20), mapsize)) { + status = 0; break; + } } iounmap(ivideo->video_vbase); + + return status; } static void __devinit @@ -5648,6 +5653,7 @@ sisfb_post_xgi(struct pci_dev *pdev) SiS_SetReg(SISSR, 0x14, bios[regb + 0xe0 + 8]); } else { + int err; /* Set default mode, don't clear screen */ ivideo->SiS_Pr.SiS_UseOEM = false; @@ -5661,10 +5667,16 @@ sisfb_post_xgi(struct pci_dev *pdev) /* Disable read-cache */ SiS_SetRegAND(SISSR, 0x21, 0xdf); - sisfb_post_xgi_ramsize(ivideo); + err = sisfb_post_xgi_ramsize(ivideo); /* Enable read-cache */ SiS_SetRegOR(SISSR, 0x21, 0x20); + if (err) { + dev_err(&pdev->dev, + "%s: RAM size detection failed: %d\n", + __func__, err); + return 0; + } } #if 0 -- cgit v1.2.2 From 74de5f4e52bf6e2ee1fe559d53c5dbf0d9d6e4cd Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 13 Feb 2011 22:11:24 +0000 Subject: sisfb: move XGI POST RAM type detection into a subroutine Move XGI POST RAM type detection into a separate subroutine to make further code changes easier. No changes in functionality Signed-off-by: Aaro Koskinen Cc: Thomas Winischhofer Signed-off-by: Paul Mundt --- drivers/video/sis/sis_main.c | 57 +++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 2c5de66dacf8..364559b12fc5 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -4936,6 +4936,40 @@ sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb) sisfb_post_xgi_delay(ivideo, 0x43); } +static u8 __devinit +sisfb_post_xgi_ramtype(struct sis_video_info *ivideo) +{ + unsigned char *bios = ivideo->bios_abase; + u8 ramtype; + u8 reg; + u8 v1; + + ramtype = 0x00; v1 = 0x10; + if (ivideo->haveXGIROM) { + ramtype = bios[0x62]; + v1 = bios[0x1d2]; + } + if (!(ramtype & 0x80)) { + if (ivideo->chip == XGI_20) { + SiS_SetReg(SISCR, 0x97, v1); + reg = SiS_GetReg(SISCR, 0x97); + if (reg & 0x10) { + ramtype = (reg & 0x01) << 1; + } + } else { + reg = SiS_GetReg(SISSR, 0x39); + ramtype = reg & 0x02; + if (!(ramtype)) { + reg = SiS_GetReg(SISSR, 0x3a); + ramtype = (reg >> 1) & 0x01; + } + } + } + ramtype &= 0x07; + + return ramtype; +} + static int __devinit sisfb_post_xgi(struct pci_dev *pdev) { @@ -5380,28 +5414,7 @@ sisfb_post_xgi(struct pci_dev *pdev) SiS_SetReg(SISSR, 0x1c, 0x00); } - ramtype = 0x00; v1 = 0x10; - if(ivideo->haveXGIROM) { - ramtype = bios[0x62]; - v1 = bios[0x1d2]; - } - if(!(ramtype & 0x80)) { - if(ivideo->chip == XGI_20) { - SiS_SetReg(SISCR, 0x97, v1); - reg = SiS_GetReg(SISCR, 0x97); - if(reg & 0x10) { - ramtype = (reg & 0x01) << 1; - } - } else { - reg = SiS_GetReg(SISSR, 0x39); - ramtype = reg & 0x02; - if(!(ramtype)) { - reg = SiS_GetReg(SISSR, 0x3a); - ramtype = (reg >> 1) & 0x01; - } - } - } - ramtype &= 0x07; + ramtype = sisfb_post_xgi_ramtype(ivideo); regb = 0; /* ! */ -- cgit v1.2.2 From 929c972e9589644805577317a38f1cd6b3ce5fc2 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 13 Feb 2011 22:11:25 +0000 Subject: sisfb: add subroutine for detecting XGI Z9 Z7 and Z9 have the same PCI ID, so additional checking is needed to detect Z9. The method was "documented" in XGI's xgifb driver. Signed-off-by: Aaro Koskinen Cc: Thomas Winischhofer Signed-off-by: Paul Mundt --- drivers/video/sis/sis.h | 1 + drivers/video/sis/sis_main.c | 18 ++++++++++++++++++ drivers/video/sis/vgatypes.h | 1 + 3 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h index eac7a01925f3..1987f1b7212f 100644 --- a/drivers/video/sis/sis.h +++ b/drivers/video/sis/sis.h @@ -495,6 +495,7 @@ struct sis_video_info { unsigned int refresh_rate; unsigned int chip; + unsigned int chip_real_id; u8 revision_id; int sisvga_enabled; /* PCI device was enabled */ diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 364559b12fc5..f0c48e84bcdb 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -4563,6 +4563,11 @@ sisfb_post_sis315330(struct pci_dev *pdev) } #endif +static inline int sisfb_xgi_is21(struct sis_video_info *ivideo) +{ + return ivideo->chip_real_id == XGI_21; +} + static void __devinit sisfb_post_xgi_delay(struct sis_video_info *ivideo, int delay) { @@ -5802,6 +5807,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) #endif ivideo->chip = chipinfo->chip; + ivideo->chip_real_id = chipinfo->chip; ivideo->sisvga_engine = chipinfo->vgaengine; ivideo->hwcursor_size = chipinfo->hwcursor_size; ivideo->CRT2_write_enable = chipinfo->CRT2_write_enable; @@ -6035,6 +6041,18 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) sisfb_detect_custom_timing(ivideo); } +#ifdef CONFIG_FB_SIS_315 + if (ivideo->chip == XGI_20) { + /* Check if our Z7 chip is actually Z9 */ + SiS_SetRegOR(SISCR, 0x4a, 0x40); /* GPIOG EN */ + reg = SiS_GetReg(SISCR, 0x48); + if (reg & 0x02) { /* GPIOG */ + ivideo->chip_real_id = XGI_21; + dev_info(&pdev->dev, "Z9 detected\n"); + } + } +#endif + /* POST card in case this has not been done by the BIOS */ if( (!ivideo->sisvga_enabled) #if !defined(__i386__) && !defined(__x86_64__) diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h index 12c0dfaf2518..e3f9976cfef0 100644 --- a/drivers/video/sis/vgatypes.h +++ b/drivers/video/sis/vgatypes.h @@ -87,6 +87,7 @@ typedef enum _SIS_CHIP_TYPE { SIS_341, SIS_342, XGI_20 = 75, + XGI_21, XGI_40, MAX_SIS_CHIP } SIS_CHIP_TYPE; -- cgit v1.2.2 From 5e8700bf6db24ccf6814c765519d8986f1c16357 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 13 Feb 2011 22:11:26 +0000 Subject: sisfb: add RAM type detection for XGI Z9 Detect the XGI Z9 RAM type as "documented" by the XGI's xgifb driver. Signed-off-by: Aaro Koskinen Cc: Thomas Winischhofer Signed-off-by: Paul Mundt --- drivers/video/sis/sis_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index f0c48e84bcdb..de0356788375 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -4955,7 +4955,13 @@ sisfb_post_xgi_ramtype(struct sis_video_info *ivideo) v1 = bios[0x1d2]; } if (!(ramtype & 0x80)) { - if (ivideo->chip == XGI_20) { + if (sisfb_xgi_is21(ivideo)) { + SiS_SetRegAND(SISCR, 0xb4, 0xfd); /* GPIO control */ + SiS_SetRegOR(SISCR, 0x4a, 0x80); /* GPIOH EN */ + reg = SiS_GetReg(SISCR, 0x48); + SiS_SetRegOR(SISCR, 0xb4, 0x02); + ramtype = reg & 0x01; /* GPIOH */ + } else if (ivideo->chip == XGI_20) { SiS_SetReg(SISCR, 0x97, v1); reg = SiS_GetReg(SISCR, 0x97); if (reg & 0x10) { -- cgit v1.2.2 From c9982d59c5c877a65fbdef3c875e82eaa95c2505 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 13 Feb 2011 22:11:27 +0000 Subject: sisfb: move XGI POST DDR2 bootup code into subroutines Move DDR2 register setting code into separate subroutines. No changes in functionality. Signed-off-by: Aaro Koskinen Cc: Thomas Winischhofer Signed-off-by: Paul Mundt --- drivers/video/sis/sis_main.c | 139 ++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index de0356788375..9c52d7bbef70 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -4941,6 +4941,89 @@ sisfb_post_xgi_setclocks(struct sis_video_info *ivideo, u8 regb) sisfb_post_xgi_delay(ivideo, 0x43); } +static void __devinit +sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, u8 regb) +{ + unsigned char *bios = ivideo->bios_abase; + u8 v1; + + SiS_SetReg(SISSR, 0x28, 0x64); + SiS_SetReg(SISSR, 0x29, 0x63); + sisfb_post_xgi_delay(ivideo, 15); + SiS_SetReg(SISSR, 0x18, 0x00); + SiS_SetReg(SISSR, 0x19, 0x20); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + SiS_SetReg(SISSR, 0x18, 0xc5); + SiS_SetReg(SISSR, 0x19, 0x23); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 1); + SiS_SetReg(SISCR, 0x97, 0x11); + sisfb_post_xgi_setclocks(ivideo, regb); + sisfb_post_xgi_delay(ivideo, 0x46); + SiS_SetReg(SISSR, 0x18, 0xc5); + SiS_SetReg(SISSR, 0x19, 0x23); + SiS_SetReg(SISSR, 0x16, 0x00); + SiS_SetReg(SISSR, 0x16, 0x80); + sisfb_post_xgi_delay(ivideo, 1); + SiS_SetReg(SISSR, 0x1b, 0x04); + sisfb_post_xgi_delay(ivideo, 1); + SiS_SetReg(SISSR, 0x1b, 0x00); + sisfb_post_xgi_delay(ivideo, 1); + v1 = 0x31; + if (ivideo->haveXGIROM) { + v1 = bios[0xf0]; + } + SiS_SetReg(SISSR, 0x18, v1); + SiS_SetReg(SISSR, 0x19, 0x06); + SiS_SetReg(SISSR, 0x16, 0x04); + SiS_SetReg(SISSR, 0x16, 0x84); + sisfb_post_xgi_delay(ivideo, 1); +} + +static void __devinit +sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb) +{ + unsigned char *bios = ivideo->bios_abase; + static const u8 cs158[8] = { + 0x88, 0xaa, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs160[8] = { + 0x44, 0x77, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const u8 cs168[8] = { + 0x48, 0x78, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + u8 reg; + u8 v1; + u8 v2; + u8 v3; + + SiS_SetReg(SISCR, 0x82, 0x77); + SiS_SetReg(SISCR, 0x86, 0x00); + reg = SiS_GetReg(SISCR, 0x86); + SiS_SetReg(SISCR, 0x86, 0x88); + reg = SiS_GetReg(SISCR, 0x86); + v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb]; + if (ivideo->haveXGIROM) { + v1 = bios[regb + 0x168]; + v2 = bios[regb + 0x160]; + v3 = bios[regb + 0x158]; + } + SiS_SetReg(SISCR, 0x86, v1); + SiS_SetReg(SISCR, 0x82, 0x77); + SiS_SetReg(SISCR, 0x85, 0x00); + reg = SiS_GetReg(SISCR, 0x85); + SiS_SetReg(SISCR, 0x85, 0x88); + reg = SiS_GetReg(SISCR, 0x85); + SiS_SetReg(SISCR, 0x85, v2); + SiS_SetReg(SISCR, 0x82, v3); + SiS_SetReg(SISCR, 0x98, 0x01); + SiS_SetReg(SISCR, 0x9a, 0x02); + sisfb_post_xgi_ddr2_default(ivideo, regb); +} + static u8 __devinit sisfb_post_xgi_ramtype(struct sis_video_info *ivideo) { @@ -5514,61 +5597,7 @@ sisfb_post_xgi(struct pci_dev *pdev) SiS_SetReg(SISSR, 0x1b, 0x00); break; case 1: - SiS_SetReg(SISCR, 0x82, 0x77); - SiS_SetReg(SISCR, 0x86, 0x00); - reg = SiS_GetReg(SISCR, 0x86); - SiS_SetReg(SISCR, 0x86, 0x88); - reg = SiS_GetReg(SISCR, 0x86); - v1 = cs168[regb]; v2 = cs160[regb]; v3 = cs158[regb]; - if(ivideo->haveXGIROM) { - v1 = bios[regb + 0x168]; - v2 = bios[regb + 0x160]; - v3 = bios[regb + 0x158]; - } - SiS_SetReg(SISCR, 0x86, v1); - SiS_SetReg(SISCR, 0x82, 0x77); - SiS_SetReg(SISCR, 0x85, 0x00); - reg = SiS_GetReg(SISCR, 0x85); - SiS_SetReg(SISCR, 0x85, 0x88); - reg = SiS_GetReg(SISCR, 0x85); - SiS_SetReg(SISCR, 0x85, v2); - SiS_SetReg(SISCR, 0x82, v3); - SiS_SetReg(SISCR, 0x98, 0x01); - SiS_SetReg(SISCR, 0x9a, 0x02); - - SiS_SetReg(SISSR, 0x28, 0x64); - SiS_SetReg(SISSR, 0x29, 0x63); - sisfb_post_xgi_delay(ivideo, 15); - SiS_SetReg(SISSR, 0x18, 0x00); - SiS_SetReg(SISSR, 0x19, 0x20); - SiS_SetReg(SISSR, 0x16, 0x00); - SiS_SetReg(SISSR, 0x16, 0x80); - SiS_SetReg(SISSR, 0x18, 0xc5); - SiS_SetReg(SISSR, 0x19, 0x23); - SiS_SetReg(SISSR, 0x16, 0x00); - SiS_SetReg(SISSR, 0x16, 0x80); - sisfb_post_xgi_delay(ivideo, 1); - SiS_SetReg(SISCR, 0x97, 0x11); - sisfb_post_xgi_setclocks(ivideo, regb); - sisfb_post_xgi_delay(ivideo, 0x46); - SiS_SetReg(SISSR, 0x18, 0xc5); - SiS_SetReg(SISSR, 0x19, 0x23); - SiS_SetReg(SISSR, 0x16, 0x00); - SiS_SetReg(SISSR, 0x16, 0x80); - sisfb_post_xgi_delay(ivideo, 1); - SiS_SetReg(SISSR, 0x1b, 0x04); - sisfb_post_xgi_delay(ivideo, 1); - SiS_SetReg(SISSR, 0x1b, 0x00); - sisfb_post_xgi_delay(ivideo, 1); - v1 = 0x31; - if(ivideo->haveXGIROM) { - v1 = bios[0xf0]; - } - SiS_SetReg(SISSR, 0x18, v1); - SiS_SetReg(SISSR, 0x19, 0x06); - SiS_SetReg(SISSR, 0x16, 0x04); - SiS_SetReg(SISSR, 0x16, 0x84); - sisfb_post_xgi_delay(ivideo, 1); + sisfb_post_xgi_ddr2(ivideo, regb); break; default: sisfb_post_xgi_setclocks(ivideo, regb); -- cgit v1.2.2 From 42dea903bf56414aa1eb299412a744b0fd269931 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 13 Feb 2011 22:11:28 +0000 Subject: sisfb: add support for XGI Z9 DDR2 POST Add support for ZGI Z9 DDR2 POST. The init sequence is from XGI's xgifb driver. Tested with ARM board using a PCI card with XGI Z9s and 32 MB DDR2 memory. After a cold reset the POST succeeds. Signed-off-by: Aaro Koskinen Cc: Thomas Winischhofer Signed-off-by: Paul Mundt --- drivers/video/sis/sis_main.c | 77 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 9c52d7bbef70..75259845933d 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -4982,6 +4982,48 @@ sisfb_post_xgi_ddr2_mrs_default(struct sis_video_info *ivideo, u8 regb) sisfb_post_xgi_delay(ivideo, 1); } +static void __devinit +sisfb_post_xgi_ddr2_mrs_xg21(struct sis_video_info *ivideo) +{ + sisfb_post_xgi_setclocks(ivideo, 1); + + SiS_SetReg(SISCR, 0x97, 0x11); + sisfb_post_xgi_delay(ivideo, 0x46); + + SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS2 */ + SiS_SetReg(SISSR, 0x19, 0x80); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + + SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS3 */ + SiS_SetReg(SISSR, 0x19, 0xc0); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + + SiS_SetReg(SISSR, 0x18, 0x00); /* EMRS1 */ + SiS_SetReg(SISSR, 0x19, 0x40); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + + SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */ + SiS_SetReg(SISSR, 0x19, 0x02); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + sisfb_post_xgi_delay(ivideo, 1); + + SiS_SetReg(SISSR, 0x1b, 0x04); + sisfb_post_xgi_delay(ivideo, 1); + + SiS_SetReg(SISSR, 0x1b, 0x00); + sisfb_post_xgi_delay(ivideo, 1); + + SiS_SetReg(SISSR, 0x18, 0x42); /* MRS1 */ + SiS_SetReg(SISSR, 0x19, 0x00); + SiS_SetReg(SISSR, 0x16, 0x05); + SiS_SetReg(SISSR, 0x16, 0x85); + sisfb_post_xgi_delay(ivideo, 1); +} + static void __devinit sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb) { @@ -5000,6 +5042,7 @@ sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb) u8 v2; u8 v3; + SiS_SetReg(SISCR, 0xb0, 0x80); /* DDR2 dual frequency mode */ SiS_SetReg(SISCR, 0x82, 0x77); SiS_SetReg(SISCR, 0x86, 0x00); reg = SiS_GetReg(SISCR, 0x86); @@ -5021,7 +5064,10 @@ sisfb_post_xgi_ddr2(struct sis_video_info *ivideo, u8 regb) SiS_SetReg(SISCR, 0x82, v3); SiS_SetReg(SISCR, 0x98, 0x01); SiS_SetReg(SISCR, 0x9a, 0x02); - sisfb_post_xgi_ddr2_default(ivideo, regb); + if (sisfb_xgi_is21(ivideo)) + sisfb_post_xgi_ddr2_mrs_xg21(ivideo); + else + sisfb_post_xgi_ddr2_mrs_default(ivideo, regb); } static u8 __devinit @@ -5346,9 +5392,23 @@ sisfb_post_xgi(struct pci_dev *pdev) SiS_SetReg(SISCR, 0x77, v1); } - /* RAM type */ - - regb = 0; /* ! */ + /* RAM type: + * + * 0 == DDR1, 1 == DDR2, 2..7 == reserved? + * + * The code seems to written so that regb should equal ramtype, + * however, so far it has been hardcoded to 0. Enable other values only + * on XGI Z9, as it passes the POST, and add a warning for others. + */ + ramtype = sisfb_post_xgi_ramtype(ivideo); + if (!sisfb_xgi_is21(ivideo) && ramtype) { + dev_warn(&pdev->dev, + "RAM type something else than expected: %d\n", + ramtype); + regb = 0; + } else { + regb = ramtype; + } v1 = 0xff; if(ivideo->haveXGIROM) { @@ -5500,7 +5560,10 @@ sisfb_post_xgi(struct pci_dev *pdev) } } - SiS_SetReg(SISSR, 0x17, 0x00); + if (regb == 1) + SiS_SetReg(SISSR, 0x17, 0x80); /* DDR2 */ + else + SiS_SetReg(SISSR, 0x17, 0x00); /* DDR1 */ SiS_SetReg(SISSR, 0x1a, 0x87); if(ivideo->chip == XGI_20) { @@ -5508,10 +5571,6 @@ sisfb_post_xgi(struct pci_dev *pdev) SiS_SetReg(SISSR, 0x1c, 0x00); } - ramtype = sisfb_post_xgi_ramtype(ivideo); - - regb = 0; /* ! */ - switch(ramtype) { case 0: sisfb_post_xgi_setclocks(ivideo, regb); -- cgit v1.2.2 From f6b0cc477de99fe715f1071b13ab822daed9a34f Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:49:18 +0000 Subject: svga: Make svga_wattr take an iomem regbase pointer. And use vga_{r,w}(). Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 2 +- drivers/video/svgalib.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 75738a928610..bcbf098a41c7 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -552,7 +552,7 @@ static int s3fb_set_par(struct fb_info *info) } vga_wcrt(NULL, 0x3A, 0x35); - svga_wattr(0x33, 0x00); + svga_wattr(par->state.vgabase, 0x33, 0x00); if (info->var.vmode & FB_VMODE_DOUBLE) svga_wcrt_mask(0x09, 0x80, 0x80); diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index fdb45674e2f6..59c99fd4901b 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -102,14 +102,14 @@ void svga_set_default_atc_regs(void) /* All standard ATC registers (AR00 - AR14) */ for (count = 0; count <= 0xF; count ++) - svga_wattr(count, count); + svga_wattr(NULL, count, count); - svga_wattr(VGA_ATC_MODE, 0x01); -/* svga_wattr(VGA_ATC_MODE, 0x41); */ - svga_wattr(VGA_ATC_OVERSCAN, 0x00); - svga_wattr(VGA_ATC_PLANE_ENABLE, 0x0F); - svga_wattr(VGA_ATC_PEL, 0x00); - svga_wattr(VGA_ATC_COLOR_PAGE, 0x00); + svga_wattr(NULL, VGA_ATC_MODE, 0x01); +/* svga_wattr(NULL, VGA_ATC_MODE, 0x41); */ + svga_wattr(NULL, VGA_ATC_OVERSCAN, 0x00); + svga_wattr(NULL, VGA_ATC_PLANE_ENABLE, 0x0F); + svga_wattr(NULL, VGA_ATC_PEL, 0x00); + svga_wattr(NULL, VGA_ATC_COLOR_PAGE, 0x00); vga_r(NULL, 0x3DA); vga_w(NULL, VGA_ATT_W, 0x20); @@ -159,8 +159,8 @@ void svga_set_textmode_vga_regs(void) vga_r(NULL, 0x3DA); vga_w(NULL, VGA_ATT_W, 0x00); - svga_wattr(0x10, 0x0C); /* Attribute Mode Control Register - text mode, blinking and line graphics */ - svga_wattr(0x13, 0x08); /* Horizontal Pixel Panning Register */ + svga_wattr(NULL, 0x10, 0x0C); /* Attribute Mode Control Register - text mode, blinking and line graphics */ + svga_wattr(NULL, 0x13, 0x08); /* Horizontal Pixel Panning Register */ vga_r(NULL, 0x3DA); vga_w(NULL, VGA_ATT_W, 0x20); -- cgit v1.2.2 From 21da386d0e4c55f6f7482b4637532b942e22b70a Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:49:34 +0000 Subject: svga: Make svga_wcrt_multi take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 9 +++++---- drivers/video/s3fb.c | 13 +++++++------ drivers/video/svgalib.c | 32 ++++++++++++++++---------------- drivers/video/vt8623fb.c | 10 ++++++---- 4 files changed, 34 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 391ac939f011..a54dbf4c7836 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -657,8 +657,8 @@ static int arkfb_set_par(struct fb_info *info) svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); - svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF); - svga_wcrt_multi(ark_start_address_regs, 0); + svga_wcrt_multi(par->state.vgabase, ark_line_compare_regs, 0xFFFFFFFF); + svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, 0); /* ARK specific initialization */ svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */ @@ -676,7 +676,7 @@ static int arkfb_set_par(struct fb_info *info) /* Set the offset register */ pr_debug("fb%d: offset register : %d\n", info->node, offset_value); - svga_wcrt_multi(ark_offset_regs, offset_value); + svga_wcrt_multi(par->state.vgabase, ark_offset_regs, offset_value); /* fix for hi-res textmode */ svga_wcrt_mask(0x40, 0x08, 0x08); @@ -884,6 +884,7 @@ static int arkfb_blank(int blank_mode, struct fb_info *info) static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { + struct arkfb_info *par = info->par; unsigned int offset; /* Calculate the offset */ @@ -897,7 +898,7 @@ static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info } /* Set the offset */ - svga_wcrt_multi(ark_start_address_regs, offset); + svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, offset); return 0; } diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index bcbf098a41c7..3984dcf7ba67 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -518,8 +518,8 @@ static int s3fb_set_par(struct fb_info *info) svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); - svga_wcrt_multi(s3_line_compare_regs, 0xFFFFFFFF); - svga_wcrt_multi(s3_start_address_regs, 0); + svga_wcrt_multi(par->state.vgabase, s3_line_compare_regs, 0xFFFFFFFF); + svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, 0); /* S3 specific initialization */ svga_wcrt_mask(0x58, 0x10, 0x10); /* enable linear framebuffer */ @@ -540,7 +540,7 @@ static int s3fb_set_par(struct fb_info *info) /* Set the offset register */ pr_debug("fb%d: offset register : %d\n", info->node, offset_value); - svga_wcrt_multi(s3_offset_regs, offset_value); + svga_wcrt_multi(par->state.vgabase, s3_offset_regs, offset_value); if (par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && @@ -822,8 +822,9 @@ static int s3fb_blank(int blank_mode, struct fb_info *info) /* Pan the display */ -static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - +static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct s3fb_info *par = info->par; unsigned int offset; /* Calculate the offset */ @@ -837,7 +838,7 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) } /* Set the offset */ - svga_wcrt_multi(s3_start_address_regs, offset); + svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, offset); return 0; } diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 59c99fd4901b..bf3c7a92eeab 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -20,12 +20,12 @@ /* Write a CRT register value spread across multiple registers */ -void svga_wcrt_multi(const struct vga_regset *regset, u32 value) { - +void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value) +{ u8 regval, bitval, bitnum; while (regset->regnum != VGA_REGSET_END_VAL) { - regval = vga_rcrt(NULL, regset->regnum); + regval = vga_rcrt(regbase, regset->regnum); bitnum = regset->lowbit; while (bitnum <= regset->highbit) { bitval = 1 << bitnum; @@ -34,7 +34,7 @@ void svga_wcrt_multi(const struct vga_regset *regset, u32 value) { bitnum ++; value = value >> 1; } - vga_wcrt(NULL, regset->regnum, regval); + vga_wcrt(regbase, regset->regnum, regval); regset ++; } } @@ -516,62 +516,62 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf value = var->xres + var->left_margin + var->right_margin + var->hsync_len; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal total : %d\n", node, value); - svga_wcrt_multi(tm->h_total_regs, (value / 8) - 5); + svga_wcrt_multi(NULL, tm->h_total_regs, (value / 8) - 5); value = var->xres; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal display : %d\n", node, value); - svga_wcrt_multi(tm->h_display_regs, (value / 8) - 1); + svga_wcrt_multi(NULL, tm->h_display_regs, (value / 8) - 1); value = var->xres; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal blank start: %d\n", node, value); - svga_wcrt_multi(tm->h_blank_start_regs, (value / 8) - 1 + hborder); + svga_wcrt_multi(NULL, tm->h_blank_start_regs, (value / 8) - 1 + hborder); value = var->xres + var->left_margin + var->right_margin + var->hsync_len; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal blank end : %d\n", node, value); - svga_wcrt_multi(tm->h_blank_end_regs, (value / 8) - 1 - hborder); + svga_wcrt_multi(NULL, tm->h_blank_end_regs, (value / 8) - 1 - hborder); value = var->xres + var->right_margin; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal sync start : %d\n", node, value); - svga_wcrt_multi(tm->h_sync_start_regs, (value / 8)); + svga_wcrt_multi(NULL, tm->h_sync_start_regs, (value / 8)); value = var->xres + var->right_margin + var->hsync_len; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal sync end : %d\n", node, value); - svga_wcrt_multi(tm->h_sync_end_regs, (value / 8)); + svga_wcrt_multi(NULL, tm->h_sync_end_regs, (value / 8)); value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical total : %d\n", node, value); - svga_wcrt_multi(tm->v_total_regs, value - 2); + svga_wcrt_multi(NULL, tm->v_total_regs, value - 2); value = var->yres; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical display : %d\n", node, value); - svga_wcrt_multi(tm->v_display_regs, value - 1); + svga_wcrt_multi(NULL, tm->v_display_regs, value - 1); value = var->yres; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical blank start : %d\n", node, value); - svga_wcrt_multi(tm->v_blank_start_regs, value); + svga_wcrt_multi(NULL, tm->v_blank_start_regs, value); value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical blank end : %d\n", node, value); - svga_wcrt_multi(tm->v_blank_end_regs, value - 2); + svga_wcrt_multi(NULL, tm->v_blank_end_regs, value - 2); value = var->yres + var->lower_margin; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical sync start : %d\n", node, value); - svga_wcrt_multi(tm->v_sync_start_regs, value); + svga_wcrt_multi(NULL, tm->v_sync_start_regs, value); value = var->yres + var->lower_margin + var->vsync_len; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical sync end : %d\n", node, value); - svga_wcrt_multi(tm->v_sync_end_regs, value); + svga_wcrt_multi(NULL, tm->v_sync_end_regs, value); /* Set horizontal and vertical sync pulse polarity in misc register */ diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index a2965ab92cfb..46f8e06a55e8 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -373,6 +373,7 @@ static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *inf static int vt8623fb_set_par(struct fb_info *info) { u32 mode, offset_value, fetch_value, screen_size; + struct vt8623fb_info *par = info->par; u32 bpp = info->var.bits_per_pixel; if (bpp != 0) { @@ -428,10 +429,10 @@ static int vt8623fb_set_par(struct fb_info *info) svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); - svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF); - svga_wcrt_multi(vt8623_start_address_regs, 0); + svga_wcrt_multi(par->state.vgabase, vt8623_line_compare_regs, 0xFFFFFFFF); + svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, 0); - svga_wcrt_multi(vt8623_offset_regs, offset_value); + svga_wcrt_multi(par->state.vgabase, vt8623_offset_regs, offset_value); svga_wseq_multi(vt8623_fetch_count_regs, fetch_value); /* Clear H/V Skew */ @@ -603,6 +604,7 @@ static int vt8623fb_blank(int blank_mode, struct fb_info *info) static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { + struct vt8623fb_info *par = info->par; unsigned int offset; /* Calculate the offset */ @@ -616,7 +618,7 @@ static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *i } /* Set the offset */ - svga_wcrt_multi(vt8623_start_address_regs, offset); + svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, offset); return 0; } -- cgit v1.2.2 From dc6aff3a5d3e4f565cb07cd5f3b6983850971da7 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:49:49 +0000 Subject: svga: Make svga_wseq_multi take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/svgalib.c | 8 ++++---- drivers/video/vt8623fb.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index bf3c7a92eeab..ed190aa09653 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -40,12 +40,12 @@ void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 } /* Write a sequencer register value spread across multiple registers */ -void svga_wseq_multi(const struct vga_regset *regset, u32 value) { - +void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value) +{ u8 regval, bitval, bitnum; while (regset->regnum != VGA_REGSET_END_VAL) { - regval = vga_rseq(NULL, regset->regnum); + regval = vga_rseq(regbase, regset->regnum); bitnum = regset->lowbit; while (bitnum <= regset->highbit) { bitval = 1 << bitnum; @@ -54,7 +54,7 @@ void svga_wseq_multi(const struct vga_regset *regset, u32 value) { bitnum ++; value = value >> 1; } - vga_wseq(NULL, regset->regnum, regval); + vga_wseq(regbase, regset->regnum, regval); regset ++; } } diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 46f8e06a55e8..f303ea0341bc 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -433,7 +433,7 @@ static int vt8623fb_set_par(struct fb_info *info) svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, 0); svga_wcrt_multi(par->state.vgabase, vt8623_offset_regs, offset_value); - svga_wseq_multi(vt8623_fetch_count_regs, fetch_value); + svga_wseq_multi(par->state.vgabase, vt8623_fetch_count_regs, fetch_value); /* Clear H/V Skew */ svga_wcrt_mask(0x03, 0x00, 0x60); -- cgit v1.2.2 From e2fade2c146ec718796049104b45267ddbfdf7a1 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:50:04 +0000 Subject: svga: Make svga_set_default_gfx_regs take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 2 +- drivers/video/s3fb.c | 2 +- drivers/video/svgalib.c | 26 +++++++++++++------------- drivers/video/vt8623fb.c | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index a54dbf4c7836..e09694f58c2c 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -653,7 +653,7 @@ static int arkfb_set_par(struct fb_info *info) svga_wcrt_mask(0x17, 0x00, 0x80); /* Set default values */ - svga_set_default_gfx_regs(); + svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 3984dcf7ba67..7e34e5a163c4 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -514,7 +514,7 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(0x17, 0x00, 0x80); /* Set default values */ - svga_set_default_gfx_regs(); + svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index ed190aa09653..25f9f87f73dd 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -75,21 +75,21 @@ static unsigned int svga_regset_size(const struct vga_regset *regset) /* Set graphics controller registers to sane values */ -void svga_set_default_gfx_regs(void) +void svga_set_default_gfx_regs(void __iomem *regbase) { /* All standard GFX registers (GR00 - GR08) */ - vga_wgfx(NULL, VGA_GFX_SR_VALUE, 0x00); - vga_wgfx(NULL, VGA_GFX_SR_ENABLE, 0x00); - vga_wgfx(NULL, VGA_GFX_COMPARE_VALUE, 0x00); - vga_wgfx(NULL, VGA_GFX_DATA_ROTATE, 0x00); - vga_wgfx(NULL, VGA_GFX_PLANE_READ, 0x00); - vga_wgfx(NULL, VGA_GFX_MODE, 0x00); -/* vga_wgfx(NULL, VGA_GFX_MODE, 0x20); */ -/* vga_wgfx(NULL, VGA_GFX_MODE, 0x40); */ - vga_wgfx(NULL, VGA_GFX_MISC, 0x05); -/* vga_wgfx(NULL, VGA_GFX_MISC, 0x01); */ - vga_wgfx(NULL, VGA_GFX_COMPARE_MASK, 0x0F); - vga_wgfx(NULL, VGA_GFX_BIT_MASK, 0xFF); + vga_wgfx(regbase, VGA_GFX_SR_VALUE, 0x00); + vga_wgfx(regbase, VGA_GFX_SR_ENABLE, 0x00); + vga_wgfx(regbase, VGA_GFX_COMPARE_VALUE, 0x00); + vga_wgfx(regbase, VGA_GFX_DATA_ROTATE, 0x00); + vga_wgfx(regbase, VGA_GFX_PLANE_READ, 0x00); + vga_wgfx(regbase, VGA_GFX_MODE, 0x00); +/* vga_wgfx(regbase, VGA_GFX_MODE, 0x20); */ +/* vga_wgfx(regbase, VGA_GFX_MODE, 0x40); */ + vga_wgfx(regbase, VGA_GFX_MISC, 0x05); +/* vga_wgfx(regbase, VGA_GFX_MISC, 0x01); */ + vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x0F); + vga_wgfx(regbase, VGA_GFX_BIT_MASK, 0xFF); } /* Set attribute controller registers to sane values */ diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index f303ea0341bc..ccb4a3e78fda 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -425,7 +425,7 @@ static int vt8623fb_set_par(struct fb_info *info) svga_wcrt_mask(0x17, 0x00, 0x80); /* Set default values */ - svga_set_default_gfx_regs(); + svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(); svga_set_default_seq_regs(); svga_set_default_crt_regs(); -- cgit v1.2.2 From f51a14dded14457e45b1f026a6af5ca6a51e4502 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:50:36 +0000 Subject: svga: Make svga_set_default_atc_regs take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 2 +- drivers/video/s3fb.c | 2 +- drivers/video/svgalib.c | 24 ++++++++++++------------ drivers/video/vt8623fb.c | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index e09694f58c2c..1028e329c46b 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -654,7 +654,7 @@ static int arkfb_set_par(struct fb_info *info) /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); - svga_set_default_atc_regs(); + svga_set_default_atc_regs(par->state.vgabase); svga_set_default_seq_regs(); svga_set_default_crt_regs(); svga_wcrt_multi(par->state.vgabase, ark_line_compare_regs, 0xFFFFFFFF); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 7e34e5a163c4..7073cf904ccd 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -515,7 +515,7 @@ static int s3fb_set_par(struct fb_info *info) /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); - svga_set_default_atc_regs(); + svga_set_default_atc_regs(par->state.vgabase); svga_set_default_seq_regs(); svga_set_default_crt_regs(); svga_wcrt_multi(par->state.vgabase, s3_line_compare_regs, 0xFFFFFFFF); diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 25f9f87f73dd..8b97359db502 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -93,26 +93,26 @@ void svga_set_default_gfx_regs(void __iomem *regbase) } /* Set attribute controller registers to sane values */ -void svga_set_default_atc_regs(void) +void svga_set_default_atc_regs(void __iomem *regbase) { u8 count; - vga_r(NULL, 0x3DA); - vga_w(NULL, VGA_ATT_W, 0x00); + vga_r(regbase, 0x3DA); + vga_w(regbase, VGA_ATT_W, 0x00); /* All standard ATC registers (AR00 - AR14) */ for (count = 0; count <= 0xF; count ++) - svga_wattr(NULL, count, count); + svga_wattr(regbase, count, count); - svga_wattr(NULL, VGA_ATC_MODE, 0x01); -/* svga_wattr(NULL, VGA_ATC_MODE, 0x41); */ - svga_wattr(NULL, VGA_ATC_OVERSCAN, 0x00); - svga_wattr(NULL, VGA_ATC_PLANE_ENABLE, 0x0F); - svga_wattr(NULL, VGA_ATC_PEL, 0x00); - svga_wattr(NULL, VGA_ATC_COLOR_PAGE, 0x00); + svga_wattr(regbase, VGA_ATC_MODE, 0x01); +/* svga_wattr(regbase, VGA_ATC_MODE, 0x41); */ + svga_wattr(regbase, VGA_ATC_OVERSCAN, 0x00); + svga_wattr(regbase, VGA_ATC_PLANE_ENABLE, 0x0F); + svga_wattr(regbase, VGA_ATC_PEL, 0x00); + svga_wattr(regbase, VGA_ATC_COLOR_PAGE, 0x00); - vga_r(NULL, 0x3DA); - vga_w(NULL, VGA_ATT_W, 0x20); + vga_r(regbase, 0x3DA); + vga_w(regbase, VGA_ATT_W, 0x20); } /* Set sequencer registers to sane values */ diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index ccb4a3e78fda..310af2dc43cd 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -426,7 +426,7 @@ static int vt8623fb_set_par(struct fb_info *info) /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); - svga_set_default_atc_regs(); + svga_set_default_atc_regs(par->state.vgabase); svga_set_default_seq_regs(); svga_set_default_crt_regs(); svga_wcrt_multi(par->state.vgabase, vt8623_line_compare_regs, 0xFFFFFFFF); -- cgit v1.2.2 From a4ade83948e0ffc317b8227d92107271a0acdda5 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:50:54 +0000 Subject: svga: Make svga_set_default_seq_regs take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 2 +- drivers/video/s3fb.c | 2 +- drivers/video/svgalib.c | 12 ++++++------ drivers/video/vt8623fb.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 1028e329c46b..4cc412126ad3 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -655,7 +655,7 @@ static int arkfb_set_par(struct fb_info *info) /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(par->state.vgabase); - svga_set_default_seq_regs(); + svga_set_default_seq_regs(par->state.vgabase); svga_set_default_crt_regs(); svga_wcrt_multi(par->state.vgabase, ark_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, 0); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 7073cf904ccd..f37c38bbe879 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -516,7 +516,7 @@ static int s3fb_set_par(struct fb_info *info) /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(par->state.vgabase); - svga_set_default_seq_regs(); + svga_set_default_seq_regs(par->state.vgabase); svga_set_default_crt_regs(); svga_wcrt_multi(par->state.vgabase, s3_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, 0); diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 8b97359db502..6d3d39feb891 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -116,14 +116,14 @@ void svga_set_default_atc_regs(void __iomem *regbase) } /* Set sequencer registers to sane values */ -void svga_set_default_seq_regs(void) +void svga_set_default_seq_regs(void __iomem *regbase) { /* Standard sequencer registers (SR01 - SR04), SR00 is not set */ - vga_wseq(NULL, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS); - vga_wseq(NULL, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES); - vga_wseq(NULL, VGA_SEQ_CHARACTER_MAP, 0x00); -/* vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */ - vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE); + vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, VGA_SR01_CHAR_CLK_8DOTS); + vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, VGA_SR02_ALL_PLANES); + vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0x00); +/* vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE | VGA_SR04_CHN_4M); */ + vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM | VGA_SR04_SEQ_MODE); } /* Set CRTC registers to sane values */ diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 310af2dc43cd..9de76811200e 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -427,7 +427,7 @@ static int vt8623fb_set_par(struct fb_info *info) /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(par->state.vgabase); - svga_set_default_seq_regs(); + svga_set_default_seq_regs(par->state.vgabase); svga_set_default_crt_regs(); svga_wcrt_multi(par->state.vgabase, vt8623_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, 0); -- cgit v1.2.2 From d907ec04cc498e11e039e0fff8eb58cf01e885da Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:51:08 +0000 Subject: svga: Make svga_wseq_mask() take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 16 +++++++++------- drivers/video/s3fb.c | 20 +++++++++++--------- drivers/video/svgalib.c | 2 +- drivers/video/vt8623fb.c | 43 +++++++++++++++++++++++-------------------- 4 files changed, 44 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 4cc412126ad3..c351b184b1bd 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -649,7 +649,7 @@ static int arkfb_set_par(struct fb_info *info) svga_wcrt_mask(0x11, 0x00, 0x80); /* Blank screen and turn off sync */ - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); svga_wcrt_mask(0x17, 0x00, 0x80); /* Set default values */ @@ -661,8 +661,8 @@ static int arkfb_set_par(struct fb_info *info) svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, 0); /* ARK specific initialization */ - svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */ - svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */ + svga_wseq_mask(par->state.vgabase, 0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */ + svga_wseq_mask(par->state.vgabase, 0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */ vga_wseq(NULL, 0x13, info->fix.smem_start >> 16); vga_wseq(NULL, 0x14, info->fix.smem_start >> 24); @@ -787,7 +787,7 @@ static int arkfb_set_par(struct fb_info *info) memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ svga_wcrt_mask(0x17, 0x80, 0x80); - svga_wseq_mask(0x01, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); return 0; } @@ -857,22 +857,24 @@ static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int arkfb_blank(int blank_mode, struct fb_info *info) { + struct arkfb_info *par = info->par; + switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); - svga_wseq_mask(0x01, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); svga_wcrt_mask(0x17, 0x80, 0x80); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); svga_wcrt_mask(0x17, 0x80, 0x80); break; case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: sync down\n", info->node); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); svga_wcrt_mask(0x17, 0x00, 0x80); break; } diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index f37c38bbe879..efe77b683bfa 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -510,7 +510,7 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(0x11, 0x00, 0x80); /* Blank screen and turn off sync */ - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); svga_wcrt_mask(0x17, 0x00, 0x80); /* Set default values */ @@ -700,8 +700,8 @@ static int s3fb_set_par(struct fb_info *info) } if (par->chip != CHIP_988_VIRGE_VX) { - svga_wseq_mask(0x15, multiplex ? 0x10 : 0x00, 0x10); - svga_wseq_mask(0x18, multiplex ? 0x80 : 0x00, 0x80); + svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10); + svga_wseq_mask(par->state.vgabase, 0x18, multiplex ? 0x80 : 0x00, 0x80); } s3_set_pixclock(info, info->var.pixclock); @@ -718,7 +718,7 @@ static int s3fb_set_par(struct fb_info *info) memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ svga_wcrt_mask(0x17, 0x80, 0x80); - svga_wseq_mask(0x01, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); return 0; } @@ -788,31 +788,33 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int s3fb_blank(int blank_mode, struct fb_info *info) { + struct s3fb_info *par = info->par; + switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); svga_wcrt_mask(0x56, 0x00, 0x06); - svga_wseq_mask(0x01, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); svga_wcrt_mask(0x56, 0x00, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_HSYNC_SUSPEND: pr_debug("fb%d: hsync\n", info->node); svga_wcrt_mask(0x56, 0x02, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: vsync\n", info->node); svga_wcrt_mask(0x56, 0x04, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_POWERDOWN: pr_debug("fb%d: sync down\n", info->node); svga_wcrt_mask(0x56, 0x06, 0x06); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; } diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 6d3d39feb891..ea7490490de6 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -139,7 +139,7 @@ void svga_set_default_crt_regs(void) void svga_set_textmode_vga_regs(void) { - /* svga_wseq_mask(0x1, 0x00, 0x01); */ /* Switch 8/9 pixel per char */ + /* svga_wseq_mask(NULL, 0x1, 0x00, 0x01); */ /* Switch 8/9 pixel per char */ vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM); vga_wseq(NULL, VGA_SEQ_PLANE_WRITE, 0x03); diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 9de76811200e..edcfee8bc90b 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -253,6 +253,7 @@ static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *re static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock) { + struct vt8623fb_info *par = info->par; u16 m, n, r; u8 regval; int rv; @@ -274,8 +275,8 @@ static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock) udelay(1000); /* PLL reset */ - svga_wseq_mask(0x40, 0x02, 0x02); - svga_wseq_mask(0x40, 0x00, 0x02); + svga_wseq_mask(par->state.vgabase, 0x40, 0x02, 0x02); + svga_wseq_mask(par->state.vgabase, 0x40, 0x00, 0x02); } @@ -415,12 +416,12 @@ static int vt8623fb_set_par(struct fb_info *info) info->var.activate = FB_ACTIVATE_NOW; /* Unlock registers */ - svga_wseq_mask(0x10, 0x01, 0x01); + svga_wseq_mask(par->state.vgabase, 0x10, 0x01, 0x01); svga_wcrt_mask(0x11, 0x00, 0x80); svga_wcrt_mask(0x47, 0x00, 0x01); /* Device, screen and sync off */ - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); svga_wcrt_mask(0x36, 0x30, 0x30); svga_wcrt_mask(0x17, 0x00, 0x80); @@ -444,12 +445,12 @@ static int vt8623fb_set_par(struct fb_info *info) else svga_wcrt_mask(0x09, 0x00, 0x80); - svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus - svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus - svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read threshold + svga_wseq_mask(par->state.vgabase, 0x1E, 0xF0, 0xF0); // DI/DVP bus + svga_wseq_mask(par->state.vgabase, 0x2A, 0x0F, 0x0F); // DI/DVP bus + svga_wseq_mask(par->state.vgabase, 0x16, 0x08, 0xBF); // FIFO read threshold vga_wseq(NULL, 0x17, 0x1F); // FIFO depth vga_wseq(NULL, 0x18, 0x4E); - svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ? + svga_wseq_mask(par->state.vgabase, 0x1A, 0x08, 0x08); // enable MMIO ? vga_wcrt(NULL, 0x32, 0x00); vga_wcrt(NULL, 0x34, 0x00); @@ -466,31 +467,31 @@ static int vt8623fb_set_par(struct fb_info *info) case 0: pr_debug("fb%d: text mode\n", info->node); svga_set_textmode_vga_regs(); - svga_wseq_mask(0x15, 0x00, 0xFE); + svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE); svga_wcrt_mask(0x11, 0x60, 0x70); break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); vga_wgfx(NULL, VGA_GFX_MODE, 0x40); - svga_wseq_mask(0x15, 0x20, 0xFE); + svga_wseq_mask(par->state.vgabase, 0x15, 0x20, 0xFE); svga_wcrt_mask(0x11, 0x00, 0x70); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); - svga_wseq_mask(0x15, 0x00, 0xFE); + svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE); svga_wcrt_mask(0x11, 0x00, 0x70); break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); - svga_wseq_mask(0x15, 0x22, 0xFE); + svga_wseq_mask(par->state.vgabase, 0x15, 0x22, 0xFE); break; case 4: pr_debug("fb%d: 5/6/5 truecolor\n", info->node); - svga_wseq_mask(0x15, 0xB6, 0xFE); + svga_wseq_mask(par->state.vgabase, 0x15, 0xB6, 0xFE); break; case 5: pr_debug("fb%d: 8/8/8 truecolor\n", info->node); - svga_wseq_mask(0x15, 0xAE, 0xFE); + svga_wseq_mask(par->state.vgabase, 0x15, 0xAE, 0xFE); break; default: printk(KERN_ERR "vt8623fb: unsupported mode - bug\n"); @@ -507,7 +508,7 @@ static int vt8623fb_set_par(struct fb_info *info) /* Device and screen back on */ svga_wcrt_mask(0x17, 0x80, 0x80); svga_wcrt_mask(0x36, 0x00, 0x30); - svga_wseq_mask(0x01, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); return 0; } @@ -570,31 +571,33 @@ static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int vt8623fb_blank(int blank_mode, struct fb_info *info) { + struct vt8623fb_info *par = info->par; + switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); svga_wcrt_mask(0x36, 0x00, 0x30); - svga_wseq_mask(0x01, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); svga_wcrt_mask(0x36, 0x00, 0x30); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_HSYNC_SUSPEND: pr_debug("fb%d: DPMS standby (hsync off)\n", info->node); svga_wcrt_mask(0x36, 0x10, 0x30); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node); svga_wcrt_mask(0x36, 0x20, 0x30); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_POWERDOWN: pr_debug("fb%d: DPMS off (no sync)\n", info->node); svga_wcrt_mask(0x36, 0x30, 0x30); - svga_wseq_mask(0x01, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; } -- cgit v1.2.2 From ea770789dce2d27afab39c3891a475624acbd82f Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:51:26 +0000 Subject: svga: Make svga_wcrt_mask() take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 40 ++++++++++---------- drivers/video/s3fb.c | 98 ++++++++++++++++++++++++------------------------ drivers/video/svgalib.c | 8 ++-- drivers/video/vt8623fb.c | 36 +++++++++--------- 4 files changed, 91 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index c351b184b1bd..f24151e01da3 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -646,11 +646,11 @@ static int arkfb_set_par(struct fb_info *info) info->var.activate = FB_ACTIVATE_NOW; /* Unlock registers */ - svga_wcrt_mask(0x11, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80); /* Blank screen and turn off sync */ svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); - svga_wcrt_mask(0x17, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80); /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); @@ -679,17 +679,17 @@ static int arkfb_set_par(struct fb_info *info) svga_wcrt_multi(par->state.vgabase, ark_offset_regs, offset_value); /* fix for hi-res textmode */ - svga_wcrt_mask(0x40, 0x08, 0x08); + svga_wcrt_mask(par->state.vgabase, 0x40, 0x08, 0x08); if (info->var.vmode & FB_VMODE_DOUBLE) - svga_wcrt_mask(0x09, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80); else - svga_wcrt_mask(0x09, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80); if (info->var.vmode & FB_VMODE_INTERLACED) - svga_wcrt_mask(0x44, 0x04, 0x04); + svga_wcrt_mask(par->state.vgabase, 0x44, 0x04, 0x04); else - svga_wcrt_mask(0x44, 0x00, 0x04); + svga_wcrt_mask(par->state.vgabase, 0x44, 0x00, 0x04); hmul = 1; hdiv = 1; @@ -702,7 +702,7 @@ static int arkfb_set_par(struct fb_info *info) svga_set_textmode_vga_regs(); vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ - svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; @@ -711,14 +711,14 @@ static int arkfb_set_par(struct fb_info *info) vga_wgfx(NULL, VGA_GFX_MODE, 0x40); vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ - svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ - svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 3: @@ -728,11 +728,11 @@ static int arkfb_set_par(struct fb_info *info) if (info->var.pixclock > 20000) { pr_debug("fb%d: not using multiplex\n", info->node); - svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); } else { pr_debug("fb%d: using multiplex\n", info->node); - svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_16); hdiv = 2; } @@ -741,21 +741,21 @@ static int arkfb_set_par(struct fb_info *info) pr_debug("fb%d: 5/5/5 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ - svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB1555_16); break; case 5: pr_debug("fb%d: 5/6/5 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ - svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB0565_16); break; case 6: pr_debug("fb%d: 8/8/8 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */ - svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB0888_16); hmul = 3; hdiv = 2; @@ -764,7 +764,7 @@ static int arkfb_set_par(struct fb_info *info) pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */ - svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */ + svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB8888_16); hmul = 2; break; @@ -786,7 +786,7 @@ static int arkfb_set_par(struct fb_info *info) memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ - svga_wcrt_mask(0x17, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80); svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); return 0; @@ -863,19 +863,19 @@ static int arkfb_blank(int blank_mode, struct fb_info *info) case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); - svga_wcrt_mask(0x17, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); - svga_wcrt_mask(0x17, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80); break; case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: sync down\n", info->node); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); - svga_wcrt_mask(0x17, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80); break; } return 0; diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index efe77b683bfa..ece99f2044f4 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -507,11 +507,11 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(NULL, 0x38, 0x48); vga_wcrt(NULL, 0x39, 0xA5); vga_wseq(NULL, 0x08, 0x06); - svga_wcrt_mask(0x11, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80); /* Blank screen and turn off sync */ svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); - svga_wcrt_mask(0x17, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80); /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); @@ -522,20 +522,20 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, 0); /* S3 specific initialization */ - svga_wcrt_mask(0x58, 0x10, 0x10); /* enable linear framebuffer */ - svga_wcrt_mask(0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */ + svga_wcrt_mask(par->state.vgabase, 0x58, 0x10, 0x10); /* enable linear framebuffer */ + svga_wcrt_mask(par->state.vgabase, 0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */ -/* svga_wcrt_mask(0x33, 0x08, 0x08); */ /* DDR ? */ -/* svga_wcrt_mask(0x43, 0x01, 0x01); */ /* DDR ? */ - svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */ - svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */ +/* svga_wcrt_mask(par->state.vgabase, 0x33, 0x08, 0x08); */ /* DDR ? */ +/* svga_wcrt_mask(par->state.vgabase, 0x43, 0x01, 0x01); */ /* DDR ? */ + svga_wcrt_mask(par->state.vgabase, 0x33, 0x00, 0x08); /* no DDR ? */ + svga_wcrt_mask(par->state.vgabase, 0x43, 0x00, 0x01); /* no DDR ? */ - svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */ + svga_wcrt_mask(par->state.vgabase, 0x5D, 0x00, 0x28); /* Clear strange HSlen bits */ -/* svga_wcrt_mask(0x58, 0x03, 0x03); */ +/* svga_wcrt_mask(par->state.vgabase, 0x58, 0x03, 0x03); */ -/* svga_wcrt_mask(0x53, 0x12, 0x13); */ /* enable MMIO */ -/* svga_wcrt_mask(0x40, 0x08, 0x08); */ /* enable write buffer */ +/* svga_wcrt_mask(par->state.vgabase, 0x53, 0x12, 0x13); */ /* enable MMIO */ +/* svga_wcrt_mask(par->state.vgabase, 0x40, 0x08, 0x08); */ /* enable write buffer */ /* Set the offset register */ @@ -555,19 +555,19 @@ static int s3fb_set_par(struct fb_info *info) svga_wattr(par->state.vgabase, 0x33, 0x00); if (info->var.vmode & FB_VMODE_DOUBLE) - svga_wcrt_mask(0x09, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80); else - svga_wcrt_mask(0x09, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80); if (info->var.vmode & FB_VMODE_INTERLACED) - svga_wcrt_mask(0x42, 0x20, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x42, 0x20, 0x20); else - svga_wcrt_mask(0x42, 0x00, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x42, 0x00, 0x20); /* Disable hardware graphics cursor */ - svga_wcrt_mask(0x45, 0x00, 0x01); + svga_wcrt_mask(par->state.vgabase, 0x45, 0x00, 0x01); /* Disable Streams engine */ - svga_wcrt_mask(0x67, 0x00, 0x0C); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0x0C); mode = svga_match_format(s3fb_formats, &(info->var), &(info->fix)); @@ -596,7 +596,7 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(NULL, 0x66, 0x81); } - svga_wcrt_mask(0x31, 0x00, 0x40); + svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40); multiplex = 0; hmul = 1; @@ -607,15 +607,15 @@ static int s3fb_set_par(struct fb_info *info) svga_set_textmode_vga_regs(); /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); /* Disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); if (fasttext) { pr_debug("fb%d: high speed text mode set\n", info->node); - svga_wcrt_mask(0x31, 0x40, 0x40); + svga_wcrt_mask(par->state.vgabase, 0x31, 0x40, 0x40); } break; case 1: @@ -623,32 +623,32 @@ static int s3fb_set_par(struct fb_info *info) vga_wgfx(NULL, VGA_GFX_MODE, 0x40); /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); /* disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); /* Set additional registers like in 8-bit mode */ - svga_wcrt_mask(0x50, 0x00, 0x30); - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); /* disable enhanced mode */ - svga_wcrt_mask(0x3A, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); - svga_wcrt_mask(0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); if (info->var.pixclock > 20000 || par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) - svga_wcrt_mask(0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); else { - svga_wcrt_mask(0x67, 0x10, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x10, 0xF0); multiplex = 1; } break; @@ -656,12 +656,12 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: 5/5/5 truecolor\n", info->node); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) - svga_wcrt_mask(0x67, 0x20, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0); else - svga_wcrt_mask(0x67, 0x30, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); } else { - svga_wcrt_mask(0x50, 0x10, 0x30); - svga_wcrt_mask(0x67, 0x30, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); if (par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) @@ -672,12 +672,12 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: 5/6/5 truecolor\n", info->node); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) - svga_wcrt_mask(0x67, 0x40, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0); else - svga_wcrt_mask(0x67, 0x50, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); } else { - svga_wcrt_mask(0x50, 0x10, 0x30); - svga_wcrt_mask(0x67, 0x50, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); if (par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) @@ -687,12 +687,12 @@ static int s3fb_set_par(struct fb_info *info) case 6: /* VIRGE VX case */ pr_debug("fb%d: 8/8/8 truecolor\n", info->node); - svga_wcrt_mask(0x67, 0xD0, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); break; case 7: pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); - svga_wcrt_mask(0x50, 0x30, 0x30); - svga_wcrt_mask(0x67, 0xD0, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); break; default: printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node); @@ -717,7 +717,7 @@ static int s3fb_set_par(struct fb_info *info) memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ - svga_wcrt_mask(0x17, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80); svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); return 0; @@ -793,27 +793,27 @@ static int s3fb_blank(int blank_mode, struct fb_info *info) switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); - svga_wcrt_mask(0x56, 0x00, 0x06); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); - svga_wcrt_mask(0x56, 0x00, 0x06); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_HSYNC_SUSPEND: pr_debug("fb%d: hsync\n", info->node); - svga_wcrt_mask(0x56, 0x02, 0x06); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x02, 0x06); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: vsync\n", info->node); - svga_wcrt_mask(0x56, 0x04, 0x06); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x04, 0x06); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_POWERDOWN: pr_debug("fb%d: sync down\n", info->node); - svga_wcrt_mask(0x56, 0x06, 0x06); + svga_wcrt_mask(par->state.vgabase, 0x56, 0x06, 0x06); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; } diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index ea7490490de6..3d07287e9322 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -130,9 +130,9 @@ void svga_set_default_seq_regs(void __iomem *regbase) void svga_set_default_crt_regs(void) { /* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */ - svga_wcrt_mask(0x03, 0x80, 0x80); /* Enable vertical retrace EVRA */ + svga_wcrt_mask(NULL, 0x03, 0x80, 0x80); /* Enable vertical retrace EVRA */ vga_wcrt(NULL, VGA_CRTC_PRESET_ROW, 0); - svga_wcrt_mask(VGA_CRTC_MAX_SCAN, 0, 0x1F); + svga_wcrt_mask(NULL, VGA_CRTC_MAX_SCAN, 0, 0x1F); vga_wcrt(NULL, VGA_CRTC_UNDERLINE, 0); vga_wcrt(NULL, VGA_CRTC_MODE, 0xE3); } @@ -145,7 +145,7 @@ void svga_set_textmode_vga_regs(void) vga_wcrt(NULL, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */ vga_wcrt(NULL, VGA_CRTC_UNDERLINE, 0x1f); - svga_wcrt_mask(VGA_CRTC_MODE, 0x23, 0x7f); + svga_wcrt_mask(NULL, VGA_CRTC_MODE, 0x23, 0x7f); vga_wcrt(NULL, VGA_CRTC_CURSOR_START, 0x0d); vga_wcrt(NULL, VGA_CRTC_CURSOR_END, 0x0e); @@ -310,7 +310,7 @@ void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) if (! cursor -> mode) return; - svga_wcrt_mask(0x0A, 0x20, 0x20); /* disable cursor */ + svga_wcrt_mask(NULL, 0x0A, 0x20, 0x20); /* disable cursor */ if (cursor -> shape == FB_TILE_CURSOR_NONE) return; diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index edcfee8bc90b..bc54b57db985 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -417,13 +417,13 @@ static int vt8623fb_set_par(struct fb_info *info) /* Unlock registers */ svga_wseq_mask(par->state.vgabase, 0x10, 0x01, 0x01); - svga_wcrt_mask(0x11, 0x00, 0x80); - svga_wcrt_mask(0x47, 0x00, 0x01); + svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x47, 0x00, 0x01); /* Device, screen and sync off */ svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); - svga_wcrt_mask(0x36, 0x30, 0x30); - svga_wcrt_mask(0x17, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80); /* Set default values */ svga_set_default_gfx_regs(par->state.vgabase); @@ -437,13 +437,13 @@ static int vt8623fb_set_par(struct fb_info *info) svga_wseq_multi(par->state.vgabase, vt8623_fetch_count_regs, fetch_value); /* Clear H/V Skew */ - svga_wcrt_mask(0x03, 0x00, 0x60); - svga_wcrt_mask(0x05, 0x00, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x03, 0x00, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60); if (info->var.vmode & FB_VMODE_DOUBLE) - svga_wcrt_mask(0x09, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80); else - svga_wcrt_mask(0x09, 0x00, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80); svga_wseq_mask(par->state.vgabase, 0x1E, 0xF0, 0xF0); // DI/DVP bus svga_wseq_mask(par->state.vgabase, 0x2A, 0x0F, 0x0F); // DI/DVP bus @@ -468,18 +468,18 @@ static int vt8623fb_set_par(struct fb_info *info) pr_debug("fb%d: text mode\n", info->node); svga_set_textmode_vga_regs(); svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE); - svga_wcrt_mask(0x11, 0x60, 0x70); + svga_wcrt_mask(par->state.vgabase, 0x11, 0x60, 0x70); break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); vga_wgfx(NULL, VGA_GFX_MODE, 0x40); svga_wseq_mask(par->state.vgabase, 0x15, 0x20, 0xFE); - svga_wcrt_mask(0x11, 0x00, 0x70); + svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE); - svga_wcrt_mask(0x11, 0x00, 0x70); + svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70); break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); @@ -506,8 +506,8 @@ static int vt8623fb_set_par(struct fb_info *info) memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ - svga_wcrt_mask(0x17, 0x80, 0x80); - svga_wcrt_mask(0x36, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80); + svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30); svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); return 0; @@ -576,27 +576,27 @@ static int vt8623fb_blank(int blank_mode, struct fb_info *info) switch (blank_mode) { case FB_BLANK_UNBLANK: pr_debug("fb%d: unblank\n", info->node); - svga_wcrt_mask(0x36, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30); svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); break; case FB_BLANK_NORMAL: pr_debug("fb%d: blank\n", info->node); - svga_wcrt_mask(0x36, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x36, 0x00, 0x30); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_HSYNC_SUSPEND: pr_debug("fb%d: DPMS standby (hsync off)\n", info->node); - svga_wcrt_mask(0x36, 0x10, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x36, 0x10, 0x30); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_VSYNC_SUSPEND: pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node); - svga_wcrt_mask(0x36, 0x20, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x36, 0x20, 0x30); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; case FB_BLANK_POWERDOWN: pr_debug("fb%d: DPMS off (no sync)\n", info->node); - svga_wcrt_mask(0x36, 0x30, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x36, 0x30, 0x30); svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); break; } -- cgit v1.2.2 From 1d28fcadb0e277844ebffb528cdfd25d44591035 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:51:41 +0000 Subject: svga: Make svga_set_default_crt_regs() take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 2 +- drivers/video/s3fb.c | 2 +- drivers/video/svgalib.c | 12 ++++++------ drivers/video/vt8623fb.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index f24151e01da3..51fd8affe0c7 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -656,7 +656,7 @@ static int arkfb_set_par(struct fb_info *info) svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(par->state.vgabase); svga_set_default_seq_regs(par->state.vgabase); - svga_set_default_crt_regs(); + svga_set_default_crt_regs(par->state.vgabase); svga_wcrt_multi(par->state.vgabase, ark_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(par->state.vgabase, ark_start_address_regs, 0); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index ece99f2044f4..a7a2463663c4 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -517,7 +517,7 @@ static int s3fb_set_par(struct fb_info *info) svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(par->state.vgabase); svga_set_default_seq_regs(par->state.vgabase); - svga_set_default_crt_regs(); + svga_set_default_crt_regs(par->state.vgabase); svga_wcrt_multi(par->state.vgabase, s3_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, 0); diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 3d07287e9322..b0464977ed9b 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -127,14 +127,14 @@ void svga_set_default_seq_regs(void __iomem *regbase) } /* Set CRTC registers to sane values */ -void svga_set_default_crt_regs(void) +void svga_set_default_crt_regs(void __iomem *regbase) { /* Standard CRT registers CR03 CR08 CR09 CR14 CR17 */ - svga_wcrt_mask(NULL, 0x03, 0x80, 0x80); /* Enable vertical retrace EVRA */ - vga_wcrt(NULL, VGA_CRTC_PRESET_ROW, 0); - svga_wcrt_mask(NULL, VGA_CRTC_MAX_SCAN, 0, 0x1F); - vga_wcrt(NULL, VGA_CRTC_UNDERLINE, 0); - vga_wcrt(NULL, VGA_CRTC_MODE, 0xE3); + svga_wcrt_mask(regbase, 0x03, 0x80, 0x80); /* Enable vertical retrace EVRA */ + vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0); + svga_wcrt_mask(regbase, VGA_CRTC_MAX_SCAN, 0, 0x1F); + vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0); + vga_wcrt(regbase, VGA_CRTC_MODE, 0xE3); } void svga_set_textmode_vga_regs(void) diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index bc54b57db985..a2624a841ecc 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -429,7 +429,7 @@ static int vt8623fb_set_par(struct fb_info *info) svga_set_default_gfx_regs(par->state.vgabase); svga_set_default_atc_regs(par->state.vgabase); svga_set_default_seq_regs(par->state.vgabase); - svga_set_default_crt_regs(); + svga_set_default_crt_regs(par->state.vgabase); svga_wcrt_multi(par->state.vgabase, vt8623_line_compare_regs, 0xFFFFFFFF); svga_wcrt_multi(par->state.vgabase, vt8623_start_address_regs, 0); -- cgit v1.2.2 From 9c96394bb90f855d265116f37897294fa1bdb072 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:51:56 +0000 Subject: svga: Make svga_set_textmode_vga_regs() take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 2 +- drivers/video/s3fb.c | 2 +- drivers/video/svgalib.c | 40 ++++++++++++++++++++-------------------- drivers/video/vt8623fb.c | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 51fd8affe0c7..658fff45332c 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -699,7 +699,7 @@ static int arkfb_set_par(struct fb_info *info) switch (mode) { case 0: pr_debug("fb%d: text mode\n", info->node); - svga_set_textmode_vga_regs(); + svga_set_textmode_vga_regs(par->state.vgabase); vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index a7a2463663c4..017219565800 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -604,7 +604,7 @@ static int s3fb_set_par(struct fb_info *info) switch (mode) { case 0: pr_debug("fb%d: text mode\n", info->node); - svga_set_textmode_vga_regs(); + svga_set_textmode_vga_regs(par->state.vgabase); /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index b0464977ed9b..ecda90ec4056 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -137,33 +137,33 @@ void svga_set_default_crt_regs(void __iomem *regbase) vga_wcrt(regbase, VGA_CRTC_MODE, 0xE3); } -void svga_set_textmode_vga_regs(void) +void svga_set_textmode_vga_regs(void __iomem *regbase) { - /* svga_wseq_mask(NULL, 0x1, 0x00, 0x01); */ /* Switch 8/9 pixel per char */ - vga_wseq(NULL, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM); - vga_wseq(NULL, VGA_SEQ_PLANE_WRITE, 0x03); + /* svga_wseq_mask(regbase, 0x1, 0x00, 0x01); */ /* Switch 8/9 pixel per char */ + vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, VGA_SR04_EXT_MEM); + vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x03); - vga_wcrt(NULL, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */ - vga_wcrt(NULL, VGA_CRTC_UNDERLINE, 0x1f); - svga_wcrt_mask(NULL, VGA_CRTC_MODE, 0x23, 0x7f); + vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, 0x0f); /* 0x4f */ + vga_wcrt(regbase, VGA_CRTC_UNDERLINE, 0x1f); + svga_wcrt_mask(regbase, VGA_CRTC_MODE, 0x23, 0x7f); - vga_wcrt(NULL, VGA_CRTC_CURSOR_START, 0x0d); - vga_wcrt(NULL, VGA_CRTC_CURSOR_END, 0x0e); - vga_wcrt(NULL, VGA_CRTC_CURSOR_HI, 0x00); - vga_wcrt(NULL, VGA_CRTC_CURSOR_LO, 0x00); + vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0x0d); + vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 0x0e); + vga_wcrt(regbase, VGA_CRTC_CURSOR_HI, 0x00); + vga_wcrt(regbase, VGA_CRTC_CURSOR_LO, 0x00); - vga_wgfx(NULL, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */ - vga_wgfx(NULL, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */ - vga_wgfx(NULL, VGA_GFX_COMPARE_MASK, 0x00); + vga_wgfx(regbase, VGA_GFX_MODE, 0x10); /* Odd/even memory mode */ + vga_wgfx(regbase, VGA_GFX_MISC, 0x0E); /* Misc graphics register - text mode enable */ + vga_wgfx(regbase, VGA_GFX_COMPARE_MASK, 0x00); - vga_r(NULL, 0x3DA); - vga_w(NULL, VGA_ATT_W, 0x00); + vga_r(regbase, 0x3DA); + vga_w(regbase, VGA_ATT_W, 0x00); - svga_wattr(NULL, 0x10, 0x0C); /* Attribute Mode Control Register - text mode, blinking and line graphics */ - svga_wattr(NULL, 0x13, 0x08); /* Horizontal Pixel Panning Register */ + svga_wattr(regbase, 0x10, 0x0C); /* Attribute Mode Control Register - text mode, blinking and line graphics */ + svga_wattr(regbase, 0x13, 0x08); /* Horizontal Pixel Panning Register */ - vga_r(NULL, 0x3DA); - vga_w(NULL, VGA_ATT_W, 0x20); + vga_r(regbase, 0x3DA); + vga_w(regbase, VGA_ATT_W, 0x20); } #if 0 diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index a2624a841ecc..e3bb7c5b1bd5 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -466,7 +466,7 @@ static int vt8623fb_set_par(struct fb_info *info) switch (mode) { case 0: pr_debug("fb%d: text mode\n", info->node); - svga_set_textmode_vga_regs(); + svga_set_textmode_vga_regs(par->state.vgabase); svga_wseq_mask(par->state.vgabase, 0x15, 0x00, 0xFE); svga_wcrt_mask(par->state.vgabase, 0x11, 0x60, 0x70); break; -- cgit v1.2.2 From 55db092388455457791cf00216b6b3965a8071f8 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:52:11 +0000 Subject: svga: Make svga_tilecursor() take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 9 ++++++++- drivers/video/s3fb.c | 11 +++++++++-- drivers/video/svgalib.c | 12 ++++++------ drivers/video/vt8623fb.c | 8 +++++++- 4 files changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 658fff45332c..a4cfcf99ceb6 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -158,12 +158,19 @@ static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map) } } +static void arkfb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) +{ + struct arkfb_info *par = info->par; + + svga_tilecursor(par->state.vgabase, info, cursor); +} + static struct fb_tile_ops arkfb_tile_ops = { .fb_settile = arkfb_settile, .fb_tilecopy = svga_tilecopy, .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, - .fb_tilecursor = svga_tilecursor, + .fb_tilecursor = arkfb_tilecursor, .fb_get_tilemax = svga_get_tilemax, }; diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 017219565800..be3802e8108a 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -188,12 +188,19 @@ static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map) } } +static void s3fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) +{ + struct s3fb_info *par = info->par; + + svga_tilecursor(par->state.vgabase, info, cursor); +} + static struct fb_tile_ops s3fb_tile_ops = { .fb_settile = svga_settile, .fb_tilecopy = svga_tilecopy, .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, - .fb_tilecursor = svga_tilecursor, + .fb_tilecursor = s3fb_tilecursor, .fb_get_tilemax = svga_get_tilemax, }; @@ -202,7 +209,7 @@ static struct fb_tile_ops s3fb_fast_tile_ops = { .fb_tilecopy = svga_tilecopy, .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, - .fb_tilecursor = svga_tilecursor, + .fb_tilecursor = s3fb_tilecursor, .fb_get_tilemax = svga_get_tilemax, }; diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index ecda90ec4056..4876be85ecfd 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -299,7 +299,7 @@ void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit) } /* Set cursor in text (tileblit) mode */ -void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) +void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tilecursor *cursor) { u8 cs = 0x0d; u8 ce = 0x0e; @@ -310,7 +310,7 @@ void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) if (! cursor -> mode) return; - svga_wcrt_mask(NULL, 0x0A, 0x20, 0x20); /* disable cursor */ + svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */ if (cursor -> shape == FB_TILE_CURSOR_NONE) return; @@ -334,11 +334,11 @@ void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) } /* set cursor position */ - vga_wcrt(NULL, 0x0E, pos >> 8); - vga_wcrt(NULL, 0x0F, pos & 0xFF); + vga_wcrt(regbase, 0x0E, pos >> 8); + vga_wcrt(regbase, 0x0F, pos & 0xFF); - vga_wcrt(NULL, 0x0B, ce); /* set cursor end */ - vga_wcrt(NULL, 0x0A, cs); /* set cursor start and enable it */ + vga_wcrt(regbase, 0x0B, ce); /* set cursor end */ + vga_wcrt(regbase, 0x0A, cs); /* set cursor start and enable it */ } int svga_get_tilemax(struct fb_info *info) diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index e3bb7c5b1bd5..cedac002fa4b 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -121,13 +121,19 @@ MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, d /* ------------------------------------------------------------------------- */ +static void vt8623fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor) +{ + struct vt8623fb_info *par = info->par; + + svga_tilecursor(par->state.vgabase, info, cursor); +} static struct fb_tile_ops vt8623fb_tile_ops = { .fb_settile = svga_settile, .fb_tilecopy = svga_tilecopy, .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, - .fb_tilecursor = svga_tilecursor, + .fb_tilecursor = vt8623fb_tilecursor, .fb_get_tilemax = svga_get_tilemax, }; -- cgit v1.2.2 From 38d2620ea40c2f9a5f17d6488bf004973570279c Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:52:25 +0000 Subject: svga: Make svga_set_timings() take an iomem regbase pointer. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 2 +- drivers/video/s3fb.c | 2 +- drivers/video/svgalib.c | 33 +++++++++++++++++---------------- drivers/video/vt8623fb.c | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index a4cfcf99ceb6..aded91b42c76 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -781,7 +781,7 @@ static int arkfb_set_par(struct fb_info *info) } ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul); - svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv, + svga_set_timings(par->state.vgabase, &ark_timing_regs, &(info->var), hmul, hdiv, (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1, hmul, info->node); diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index be3802e8108a..23e4724bd439 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -712,7 +712,7 @@ static int s3fb_set_par(struct fb_info *info) } s3_set_pixclock(info, info->var.pixclock); - svga_set_timings(&s3_timing_regs, &(info->var), hmul, 1, + svga_set_timings(par->state.vgabase, &s3_timing_regs, &(info->var), hmul, 1, (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1, hmul, info->node); diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c index 4876be85ecfd..33df9ec91795 100644 --- a/drivers/video/svgalib.c +++ b/drivers/video/svgalib.c @@ -507,8 +507,9 @@ int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screenin } /* Set CRT timing registers */ -void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, - u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node) +void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm, + struct fb_var_screeninfo *var, + u32 hmul, u32 hdiv, u32 vmul, u32 vdiv, u32 hborder, int node) { u8 regval; u32 value; @@ -516,66 +517,66 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf value = var->xres + var->left_margin + var->right_margin + var->hsync_len; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal total : %d\n", node, value); - svga_wcrt_multi(NULL, tm->h_total_regs, (value / 8) - 5); + svga_wcrt_multi(regbase, tm->h_total_regs, (value / 8) - 5); value = var->xres; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal display : %d\n", node, value); - svga_wcrt_multi(NULL, tm->h_display_regs, (value / 8) - 1); + svga_wcrt_multi(regbase, tm->h_display_regs, (value / 8) - 1); value = var->xres; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal blank start: %d\n", node, value); - svga_wcrt_multi(NULL, tm->h_blank_start_regs, (value / 8) - 1 + hborder); + svga_wcrt_multi(regbase, tm->h_blank_start_regs, (value / 8) - 1 + hborder); value = var->xres + var->left_margin + var->right_margin + var->hsync_len; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal blank end : %d\n", node, value); - svga_wcrt_multi(NULL, tm->h_blank_end_regs, (value / 8) - 1 - hborder); + svga_wcrt_multi(regbase, tm->h_blank_end_regs, (value / 8) - 1 - hborder); value = var->xres + var->right_margin; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal sync start : %d\n", node, value); - svga_wcrt_multi(NULL, tm->h_sync_start_regs, (value / 8)); + svga_wcrt_multi(regbase, tm->h_sync_start_regs, (value / 8)); value = var->xres + var->right_margin + var->hsync_len; value = (value * hmul) / hdiv; pr_debug("fb%d: horizontal sync end : %d\n", node, value); - svga_wcrt_multi(NULL, tm->h_sync_end_regs, (value / 8)); + svga_wcrt_multi(regbase, tm->h_sync_end_regs, (value / 8)); value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical total : %d\n", node, value); - svga_wcrt_multi(NULL, tm->v_total_regs, value - 2); + svga_wcrt_multi(regbase, tm->v_total_regs, value - 2); value = var->yres; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical display : %d\n", node, value); - svga_wcrt_multi(NULL, tm->v_display_regs, value - 1); + svga_wcrt_multi(regbase, tm->v_display_regs, value - 1); value = var->yres; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical blank start : %d\n", node, value); - svga_wcrt_multi(NULL, tm->v_blank_start_regs, value); + svga_wcrt_multi(regbase, tm->v_blank_start_regs, value); value = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical blank end : %d\n", node, value); - svga_wcrt_multi(NULL, tm->v_blank_end_regs, value - 2); + svga_wcrt_multi(regbase, tm->v_blank_end_regs, value - 2); value = var->yres + var->lower_margin; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical sync start : %d\n", node, value); - svga_wcrt_multi(NULL, tm->v_sync_start_regs, value); + svga_wcrt_multi(regbase, tm->v_sync_start_regs, value); value = var->yres + var->lower_margin + var->vsync_len; value = (value * vmul) / vdiv; pr_debug("fb%d: vertical sync end : %d\n", node, value); - svga_wcrt_multi(NULL, tm->v_sync_end_regs, value); + svga_wcrt_multi(regbase, tm->v_sync_end_regs, value); /* Set horizontal and vertical sync pulse polarity in misc register */ - regval = vga_r(NULL, VGA_MIS_R); + regval = vga_r(regbase, VGA_MIS_R); if (var->sync & FB_SYNC_HOR_HIGH_ACT) { pr_debug("fb%d: positive horizontal sync\n", node); regval = regval & ~0x80; @@ -590,7 +591,7 @@ void svga_set_timings(const struct svga_timing_regs *tm, struct fb_var_screeninf pr_debug("fb%d: negative vertical sync\n\n", node); regval = regval | 0x40; } - vga_w(NULL, VGA_MIS_W, regval); + vga_w(regbase, VGA_MIS_W, regval); } diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index cedac002fa4b..4764fb2fffc0 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -505,7 +505,7 @@ static int vt8623fb_set_par(struct fb_info *info) } vt8623_set_pixclock(info, info->var.pixclock); - svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1, + svga_set_timings(par->state.vgabase, &vt8623_timing_regs, &(info->var), 1, 1, (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1, 1, info->node); -- cgit v1.2.2 From c5e04633b3b765a06986008e577930555e0f544b Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:52:40 +0000 Subject: arkfb: Pass par->state.vgabase to vga_*() calls. Instead of just plain NULL. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 60 +++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index aded91b42c76..53c66e8dcb0b 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -473,32 +473,40 @@ static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7}; static void ark_dac_read_regs(void *data, u8 *code, int count) { - u8 regval = vga_rseq(NULL, 0x1C); + struct fb_info *info = data; + struct arkfb_info *par; + u8 regval; + par = info->par; + regval = vga_rseq(par->state.vgabase, 0x1C); while (count != 0) { - vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0)); - code[1] = vga_r(NULL, dac_regs[code[0] & 3]); + vga_wseq(par->state.vgabase, 0x1C, regval | (code[0] & 4 ? 0x80 : 0)); + code[1] = vga_r(par->state.vgabase, dac_regs[code[0] & 3]); count--; code += 2; } - vga_wseq(NULL, 0x1C, regval); + vga_wseq(par->state.vgabase, 0x1C, regval); } static void ark_dac_write_regs(void *data, u8 *code, int count) { - u8 regval = vga_rseq(NULL, 0x1C); + struct fb_info *info = data; + struct arkfb_info *par; + u8 regval; + par = info->par; + regval = vga_rseq(par->state.vgabase, 0x1C); while (count != 0) { - vga_wseq(NULL, 0x1C, regval | (code[0] & 4 ? 0x80 : 0)); - vga_w(NULL, dac_regs[code[0] & 3], code[1]); + vga_wseq(par->state.vgabase, 0x1C, regval | (code[0] & 4 ? 0x80 : 0)); + vga_w(par->state.vgabase, dac_regs[code[0] & 3], code[1]); count--; code += 2; } - vga_wseq(NULL, 0x1C, regval); + vga_wseq(par->state.vgabase, 0x1C, regval); } @@ -514,8 +522,8 @@ static void ark_set_pixclock(struct fb_info *info, u32 pixclock) } /* Set VGA misc register */ - regval = vga_r(NULL, VGA_MIS_R); - vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); + regval = vga_r(par->state.vgabase, VGA_MIS_R); + vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); } @@ -671,15 +679,15 @@ static int arkfb_set_par(struct fb_info *info) svga_wseq_mask(par->state.vgabase, 0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */ svga_wseq_mask(par->state.vgabase, 0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */ - vga_wseq(NULL, 0x13, info->fix.smem_start >> 16); - vga_wseq(NULL, 0x14, info->fix.smem_start >> 24); - vga_wseq(NULL, 0x15, 0); - vga_wseq(NULL, 0x16, 0); + vga_wseq(par->state.vgabase, 0x13, info->fix.smem_start >> 16); + vga_wseq(par->state.vgabase, 0x14, info->fix.smem_start >> 24); + vga_wseq(par->state.vgabase, 0x15, 0); + vga_wseq(par->state.vgabase, 0x16, 0); /* Set the FIFO threshold register */ /* It is fascinating way to store 5-bit value in 8-bit register */ regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1; - vga_wseq(NULL, 0x18, regval); + vga_wseq(par->state.vgabase, 0x18, regval); /* Set the offset register */ pr_debug("fb%d: offset register : %d\n", info->node, offset_value); @@ -708,30 +716,30 @@ static int arkfb_set_par(struct fb_info *info) pr_debug("fb%d: text mode\n", info->node); svga_set_textmode_vga_regs(par->state.vgabase); - vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ + vga_wseq(par->state.vgabase, 0x11, 0x10); /* basic VGA mode */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); - vga_wgfx(NULL, VGA_GFX_MODE, 0x40); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); - vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ + vga_wseq(par->state.vgabase, 0x11, 0x10); /* basic VGA mode */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 2: pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node); - vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */ + vga_wseq(par->state.vgabase, 0x11, 0x10); /* basic VGA mode */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x00, 0x04); /* 8bit pixel path */ dac_set_mode(par->dac, DAC_PSEUDO8_8); break; case 3: pr_debug("fb%d: 8 bit pseudocolor\n", info->node); - vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */ + vga_wseq(par->state.vgabase, 0x11, 0x16); /* 8bpp accel mode */ if (info->var.pixclock > 20000) { pr_debug("fb%d: not using multiplex\n", info->node); @@ -747,21 +755,21 @@ static int arkfb_set_par(struct fb_info *info) case 4: pr_debug("fb%d: 5/5/5 truecolor\n", info->node); - vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ + vga_wseq(par->state.vgabase, 0x11, 0x1A); /* 16bpp accel mode */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB1555_16); break; case 5: pr_debug("fb%d: 5/6/5 truecolor\n", info->node); - vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */ + vga_wseq(par->state.vgabase, 0x11, 0x1A); /* 16bpp accel mode */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB0565_16); break; case 6: pr_debug("fb%d: 8/8/8 truecolor\n", info->node); - vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */ + vga_wseq(par->state.vgabase, 0x11, 0x16); /* 8bpp accel mode ??? */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB0888_16); hmul = 3; @@ -770,7 +778,7 @@ static int arkfb_set_par(struct fb_info *info) case 7: pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node); - vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */ + vga_wseq(par->state.vgabase, 0x11, 0x1E); /* 32bpp accel mode */ svga_wcrt_mask(par->state.vgabase, 0x46, 0x04, 0x04); /* 16bit pixel path */ dac_set_mode(par->dac, DAC_RGB8888_16); hmul = 2; @@ -789,7 +797,7 @@ static int arkfb_set_par(struct fb_info *info) /* Set interlaced mode start/end register */ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; value = ((value * hmul / hdiv) / 8) - 5; - vga_wcrt(NULL, 0x42, (value + 1) / 2); + vga_wcrt(par->state.vgabase, 0x42, (value + 1) / 2); memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ @@ -996,7 +1004,7 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ } /* FIXME get memsize */ - regval = vga_rseq(NULL, 0x10); + regval = vga_rseq(par->state.vgabase, 0x10); info->screen_size = (1 << (regval >> 6)) << 20; info->fix.smem_len = info->screen_size; -- cgit v1.2.2 From f8645933513c65ac55f23c63b2649097289795c6 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:52:57 +0000 Subject: s3fb: Pass par->state.vgabase to vga_*() calls. Instead of just plain NULL. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 102 ++++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 23e4724bd439..262490a74bb7 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -348,26 +348,26 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) } /* Set VGA misc register */ - regval = vga_r(NULL, VGA_MIS_R); - vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); + regval = vga_r(par->state.vgabase, VGA_MIS_R); + vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); /* Set S3 clock registers */ if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) { - vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ - vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */ + vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ + vga_wseq(par->state.vgabase, 0x29, r >> 2); /* remaining highest bit of r */ } else - vga_wseq(NULL, 0x12, (n - 2) | (r << 5)); - vga_wseq(NULL, 0x13, m - 2); + vga_wseq(par->state.vgabase, 0x12, (n - 2) | (r << 5)); + vga_wseq(par->state.vgabase, 0x13, m - 2); udelay(1000); /* Activate clock - write 0, 1, 0 to seq/15 bit 5 */ - regval = vga_rseq (NULL, 0x15); /* | 0x80; */ - vga_wseq(NULL, 0x15, regval & ~(1<<5)); - vga_wseq(NULL, 0x15, regval | (1<<5)); - vga_wseq(NULL, 0x15, regval & ~(1<<5)); + regval = vga_rseq (par->state.vgabase, 0x15); /* | 0x80; */ + vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5)); + vga_wseq(par->state.vgabase, 0x15, regval | (1<<5)); + vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5)); } @@ -511,9 +511,9 @@ static int s3fb_set_par(struct fb_info *info) info->var.activate = FB_ACTIVATE_NOW; /* Unlock registers */ - vga_wcrt(NULL, 0x38, 0x48); - vga_wcrt(NULL, 0x39, 0xA5); - vga_wseq(NULL, 0x08, 0x06); + vga_wcrt(par->state.vgabase, 0x38, 0x48); + vga_wcrt(par->state.vgabase, 0x39, 0xA5); + vga_wseq(par->state.vgabase, 0x08, 0x06); svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80); /* Blank screen and turn off sync */ @@ -552,13 +552,13 @@ static int s3fb_set_par(struct fb_info *info) if (par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) { - vga_wcrt(NULL, 0x54, 0x18); /* M parameter */ - vga_wcrt(NULL, 0x60, 0xff); /* N parameter */ - vga_wcrt(NULL, 0x61, 0xff); /* L parameter */ - vga_wcrt(NULL, 0x62, 0xff); /* L parameter */ + vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */ + vga_wcrt(par->state.vgabase, 0x60, 0xff); /* N parameter */ + vga_wcrt(par->state.vgabase, 0x61, 0xff); /* L parameter */ + vga_wcrt(par->state.vgabase, 0x62, 0xff); /* L parameter */ } - vga_wcrt(NULL, 0x3A, 0x35); + vga_wcrt(par->state.vgabase, 0x3A, 0x35); svga_wattr(par->state.vgabase, 0x33, 0x00); if (info->var.vmode & FB_VMODE_DOUBLE) @@ -580,27 +580,27 @@ static int s3fb_set_par(struct fb_info *info) /* S3 virge DX hack */ if (par->chip == CHIP_375_VIRGE_DX) { - vga_wcrt(NULL, 0x86, 0x80); - vga_wcrt(NULL, 0x90, 0x00); + vga_wcrt(par->state.vgabase, 0x86, 0x80); + vga_wcrt(par->state.vgabase, 0x90, 0x00); } /* S3 virge VX hack */ if (par->chip == CHIP_988_VIRGE_VX) { - vga_wcrt(NULL, 0x50, 0x00); - vga_wcrt(NULL, 0x67, 0x50); + vga_wcrt(par->state.vgabase, 0x50, 0x00); + vga_wcrt(par->state.vgabase, 0x67, 0x50); - vga_wcrt(NULL, 0x63, (mode <= 2) ? 0x90 : 0x09); - vga_wcrt(NULL, 0x66, 0x90); + vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); + vga_wcrt(par->state.vgabase, 0x66, 0x90); } if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) { dbytes = info->var.xres * ((bpp+7)/8); - vga_wcrt(NULL, 0x91, (dbytes + 7) / 8); - vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); + vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8); + vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); - vga_wcrt(NULL, 0x66, 0x81); + vga_wcrt(par->state.vgabase, 0x66, 0x81); } svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40); @@ -627,7 +627,7 @@ static int s3fb_set_par(struct fb_info *info) break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); - vga_wgfx(NULL, VGA_GFX_MODE, 0x40); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); @@ -720,7 +720,7 @@ static int s3fb_set_par(struct fb_info *info) /* Set interlaced mode start/end register */ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; value = ((value * hmul) / 8) - 5; - vga_wcrt(NULL, 0x3C, (value + 1) / 2); + vga_wcrt(par->state.vgabase, 0x3C, (value + 1) / 2); memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ @@ -873,12 +873,14 @@ static struct fb_ops s3fb_ops = { /* ------------------------------------------------------------------------- */ -static int __devinit s3_identification(int chip) +static int __devinit s3_identification(struct s3fb_info *par) { + int chip = par->chip; + if (chip == CHIP_XXX_TRIO) { - u8 cr30 = vga_rcrt(NULL, 0x30); - u8 cr2e = vga_rcrt(NULL, 0x2e); - u8 cr2f = vga_rcrt(NULL, 0x2f); + u8 cr30 = vga_rcrt(par->state.vgabase, 0x30); + u8 cr2e = vga_rcrt(par->state.vgabase, 0x2e); + u8 cr2f = vga_rcrt(par->state.vgabase, 0x2f); if ((cr30 == 0xE0) || (cr30 == 0xE1)) { if (cr2e == 0x10) @@ -893,7 +895,7 @@ static int __devinit s3_identification(int chip) } if (chip == CHIP_XXX_TRIO64V2_DXGX) { - u8 cr6f = vga_rcrt(NULL, 0x6f); + u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f); if (! (cr6f & 0x01)) return CHIP_775_TRIO64V2_DX; @@ -902,7 +904,7 @@ static int __devinit s3_identification(int chip) } if (chip == CHIP_XXX_VIRGE_DXGX) { - u8 cr6f = vga_rcrt(NULL, 0x6f); + u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f); if (! (cr6f & 0x01)) return CHIP_375_VIRGE_DX; @@ -911,7 +913,7 @@ static int __devinit s3_identification(int chip) } if (chip == CHIP_36X_TRIO3D_1X_2X) { - switch (vga_rcrt(NULL, 0x2f)) { + switch (vga_rcrt(par->state.vgabase, 0x2f)) { case 0x00: return CHIP_360_TRIO3D_1X; case 0x01: @@ -979,21 +981,21 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i } /* Unlock regs */ - cr38 = vga_rcrt(NULL, 0x38); - cr39 = vga_rcrt(NULL, 0x39); - vga_wseq(NULL, 0x08, 0x06); - vga_wcrt(NULL, 0x38, 0x48); - vga_wcrt(NULL, 0x39, 0xA5); + cr38 = vga_rcrt(par->state.vgabase, 0x38); + cr39 = vga_rcrt(par->state.vgabase, 0x39); + vga_wseq(par->state.vgabase, 0x08, 0x06); + vga_wcrt(par->state.vgabase, 0x38, 0x48); + vga_wcrt(par->state.vgabase, 0x39, 0xA5); /* Identify chip type */ par->chip = id->driver_data & CHIP_MASK; - par->rev = vga_rcrt(NULL, 0x2f); + par->rev = vga_rcrt(par->state.vgabase, 0x2f); if (par->chip & CHIP_UNDECIDED_FLAG) - par->chip = s3_identification(par->chip); + par->chip = s3_identification(par); /* Find how many physical memory there is on card */ /* 0x36 register is accessible even if other registers are locked */ - regval = vga_rcrt(NULL, 0x36); + regval = vga_rcrt(par->state.vgabase, 0x36); if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) { @@ -1012,13 +1014,13 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->fix.smem_len = info->screen_size; /* Find MCLK frequency */ - regval = vga_rseq(NULL, 0x10); - par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); + regval = vga_rseq(par->state.vgabase, 0x10); + par->mclk_freq = ((vga_rseq(par->state.vgabase, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2); par->mclk_freq = par->mclk_freq >> (regval >> 5); /* Restore locks */ - vga_wcrt(NULL, 0x38, cr38); - vga_wcrt(NULL, 0x39, cr39); + vga_wcrt(par->state.vgabase, 0x38, cr38); + vga_wcrt(par->state.vgabase, 0x39, cr39); strcpy(info->fix.id, s3_names [par->chip]); info->fix.mmio_start = 0; @@ -1054,8 +1056,8 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i if (par->chip == CHIP_UNKNOWN) printk(KERN_INFO "fb%d: unknown chip, CR2D=%x, CR2E=%x, CRT2F=%x, CRT30=%x\n", - info->node, vga_rcrt(NULL, 0x2d), vga_rcrt(NULL, 0x2e), - vga_rcrt(NULL, 0x2f), vga_rcrt(NULL, 0x30)); + info->node, vga_rcrt(par->state.vgabase, 0x2d), vga_rcrt(par->state.vgabase, 0x2e), + vga_rcrt(par->state.vgabase, 0x2f), vga_rcrt(par->state.vgabase, 0x30)); /* Record a reference to the driver data */ pci_set_drvdata(dev, info); -- cgit v1.2.2 From ed3eb4c803dec3cf2976701f0b5722f98e642855 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:53:11 +0000 Subject: vt8623fb: Pass par->state.vgabase to vga_*() calls. Instead of just plain NULL. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/vt8623fb.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 4764fb2fffc0..54ddaeb60f0a 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -271,12 +271,12 @@ static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock) } /* Set VGA misc register */ - regval = vga_r(NULL, VGA_MIS_R); - vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); + regval = vga_r(par->state.vgabase, VGA_MIS_R); + vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); /* Set clock registers */ - vga_wseq(NULL, 0x46, (n | (r << 6))); - vga_wseq(NULL, 0x47, m); + vga_wseq(par->state.vgabase, 0x46, (n | (r << 6))); + vga_wseq(par->state.vgabase, 0x47, m); udelay(1000); @@ -454,18 +454,18 @@ static int vt8623fb_set_par(struct fb_info *info) svga_wseq_mask(par->state.vgabase, 0x1E, 0xF0, 0xF0); // DI/DVP bus svga_wseq_mask(par->state.vgabase, 0x2A, 0x0F, 0x0F); // DI/DVP bus svga_wseq_mask(par->state.vgabase, 0x16, 0x08, 0xBF); // FIFO read threshold - vga_wseq(NULL, 0x17, 0x1F); // FIFO depth - vga_wseq(NULL, 0x18, 0x4E); + vga_wseq(par->state.vgabase, 0x17, 0x1F); // FIFO depth + vga_wseq(par->state.vgabase, 0x18, 0x4E); svga_wseq_mask(par->state.vgabase, 0x1A, 0x08, 0x08); // enable MMIO ? - vga_wcrt(NULL, 0x32, 0x00); - vga_wcrt(NULL, 0x34, 0x00); - vga_wcrt(NULL, 0x6A, 0x80); - vga_wcrt(NULL, 0x6A, 0xC0); + vga_wcrt(par->state.vgabase, 0x32, 0x00); + vga_wcrt(par->state.vgabase, 0x34, 0x00); + vga_wcrt(par->state.vgabase, 0x6A, 0x80); + vga_wcrt(par->state.vgabase, 0x6A, 0xC0); - vga_wgfx(NULL, 0x20, 0x00); - vga_wgfx(NULL, 0x21, 0x00); - vga_wgfx(NULL, 0x22, 0x00); + vga_wgfx(par->state.vgabase, 0x20, 0x00); + vga_wgfx(par->state.vgabase, 0x21, 0x00); + vga_wgfx(par->state.vgabase, 0x22, 0x00); /* Set SR15 according to number of bits per pixel */ mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix)); @@ -478,7 +478,7 @@ static int vt8623fb_set_par(struct fb_info *info) break; case 1: pr_debug("fb%d: 4 bit pseudocolor\n", info->node); - vga_wgfx(NULL, VGA_GFX_MODE, 0x40); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); svga_wseq_mask(par->state.vgabase, 0x15, 0x20, 0xFE); svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x70); break; @@ -717,8 +717,8 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi } /* Find how many physical memory there is on card */ - memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1; - memsize2 = vga_rseq(NULL, 0x39) << 2; + memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1; + memsize2 = vga_rseq(par->state.vgabase, 0x39) << 2; if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2)) info->screen_size = memsize1 << 20; -- cgit v1.2.2 From ec70a9435600a7b4c019671aa0b6e6644b60f0b2 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:53:38 +0000 Subject: arkfb: Don't clobber par->state.vgabase during open method. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 53c66e8dcb0b..1c69db310ed5 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -535,7 +535,10 @@ static int arkfb_open(struct fb_info *info, int user) mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { + void __iomem *vgabase = par->state.vgabase; + memset(&(par->state), 0, sizeof(struct vgastate)); + par->state.vgabase = vgabase; par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; par->state.num_crtc = 0x60; par->state.num_seq = 0x30; -- cgit v1.2.2 From 3ff259f2ed21e4438dc7937348710397e5ebd71e Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:53:53 +0000 Subject: s3fb: Don't clobber par->state.vgabase during open method. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 262490a74bb7..b2286f916b5d 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -379,7 +379,10 @@ static int s3fb_open(struct fb_info *info, int user) mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { + void __iomem *vgabase = par->state.vgabase; + memset(&(par->state), 0, sizeof(struct vgastate)); + par->state.vgabase = vgabase; par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; par->state.num_crtc = 0x70; par->state.num_seq = 0x20; -- cgit v1.2.2 From 0144a2568c7d8e58806d3f176f8454c3a3a35ba0 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:54:07 +0000 Subject: vt8623fb: Don't clobber par->state.vgabase during open method. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/vt8623fb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index 54ddaeb60f0a..eee01a2ae8c9 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -292,7 +292,10 @@ static int vt8623fb_open(struct fb_info *info, int user) mutex_lock(&(par->open_lock)); if (par->ref_count == 0) { + void __iomem *vgabase = par->state.vgabase; + memset(&(par->state), 0, sizeof(struct vgastate)); + par->state.vgabase = vgabase; par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP; par->state.num_crtc = 0xA2; par->state.num_seq = 0x50; -- cgit v1.2.2 From 94c322c30bd14ae6cdd369cb4a1f94c5c3809ac9 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:54:21 +0000 Subject: s3fb: Compute VGA base iomem pointer explicitly. This allows the driver to work in multi-domain PCI configurations. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index b2286f916b5d..55a94b94a326 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -934,6 +934,8 @@ static int __devinit s3_identification(struct s3fb_info *par) static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { + struct pci_bus_region bus_reg; + struct resource vga_res; struct fb_info *info; struct s3fb_info *par; int rc; @@ -983,6 +985,15 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i goto err_iomap; } + bus_reg.start = 0; + bus_reg.end = 64 * 1024; + + vga_res.flags = IORESOURCE_IO; + + pcibios_bus_to_resource(dev, &vga_res, &bus_reg); + + par->state.vgabase = (void __iomem *) vga_res.start; + /* Unlock regs */ cr38 = vga_rcrt(par->state.vgabase, 0x38); cr39 = vga_rcrt(par->state.vgabase, 0x39); -- cgit v1.2.2 From 892c24ca40ffebf6d0ca4cc1454e58db131a4f5a Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:54:35 +0000 Subject: arkfb: Compute VGA base iomem pointer explicitly. This allows the driver to work in multi-domain PCI configurations. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 1c69db310ed5..8686429cbdf0 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -951,6 +951,8 @@ static struct fb_ops arkfb_ops = { /* PCI probe */ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { + struct pci_bus_region bus_reg; + struct resource vga_res; struct fb_info *info; struct arkfb_info *par; int rc; @@ -1006,6 +1008,15 @@ static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_ goto err_iomap; } + bus_reg.start = 0; + bus_reg.end = 64 * 1024; + + vga_res.flags = IORESOURCE_IO; + + pcibios_bus_to_resource(dev, &vga_res, &bus_reg); + + par->state.vgabase = (void __iomem *) vga_res.start; + /* FIXME get memsize */ regval = vga_rseq(par->state.vgabase, 0x10); info->screen_size = (1 << (regval >> 6)) << 20; -- cgit v1.2.2 From 6a2f6d5e970afbc1b8b08bafae9d9138a3206960 Mon Sep 17 00:00:00 2001 From: David Miller Date: Tue, 11 Jan 2011 23:55:17 +0000 Subject: vt8623fb: Compute VGA base iomem pointer explicitly. This allows the driver to work in multi-domain PCI configurations. Signed-off-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/vt8623fb.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index eee01a2ae8c9..f9b3e3dc2421 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -661,6 +661,8 @@ static struct fb_ops vt8623fb_ops = { static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { + struct pci_bus_region bus_reg; + struct resource vga_res; struct fb_info *info; struct vt8623fb_info *par; unsigned int memsize1, memsize2; @@ -719,6 +721,15 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi goto err_iomap_2; } + bus_reg.start = 0; + bus_reg.end = 64 * 1024; + + vga_res.flags = IORESOURCE_IO; + + pcibios_bus_to_resource(dev, &vga_res, &bus_reg); + + par->state.vgabase = (void __iomem *) vga_res.start; + /* Find how many physical memory there is on card */ memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1; memsize2 = vga_rseq(par->state.vgabase, 0x39) << 2; -- cgit v1.2.2 From 99d054d8253b1dbc6ab2d4ebcb25ad4a4e6ba1c8 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 1 Mar 2011 19:18:08 +0000 Subject: s3fb: maximize virtual vertical size for fast scrolling Maximize virtual vertical framebuffer size during init to allow fast scrolling (accelerated by panning). Signed-off-by: Ondrej Zary Acked-by: Ondrej Zajicek Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 55a94b94a326..9f9be9f37f2e 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -1053,6 +1053,14 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i goto err_find_mode; } + /* maximize virtual vertical size for fast scrolling */ + info->var.yres_virtual = info->fix.smem_len * 8 / + (info->var.bits_per_pixel * info->var.xres_virtual); + if (info->var.yres_virtual < info->var.yres) { + dev_err(info->device, "virtual vertical size smaller than real\n"); + goto err_find_mode; + } + rc = fb_alloc_cmap(&info->cmap, 256, 0); if (rc < 0) { dev_err(info->device, "cannot allocate colormap\n"); -- cgit v1.2.2 From 5694f9ce5801d58bfc1b011592a5e460cc0a274b Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 1 Mar 2011 19:18:17 +0000 Subject: s3fb: add support for 86C365 Trio3D Add support for S3 Trio3D (86C365) cards to s3fb driver. Tested with one 4MB card. Signed-off-by: Ondrej Zary Acked-by: Ondrej Zajicek Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 9f9be9f37f2e..be12145681f6 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -64,6 +64,8 @@ static const struct svga_fb_format s3fb_formats[] = { static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3, 35000, 240000, 14318}; +static const struct svga_pll s3_trio3d_pll = {3, 129, 3, 31, 0, 4, + 230000, 460000, 14318}; static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512}; @@ -72,7 +74,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge", "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX", "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P", - "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"}; + "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X", + "S3 Trio3D"}; #define CHIP_UNKNOWN 0x00 #define CHIP_732_TRIO32 0x01 @@ -93,6 +96,7 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", #define CHIP_360_TRIO3D_1X 0x10 #define CHIP_362_TRIO3D_2X 0x11 #define CHIP_368_TRIO3D_2X 0x12 +#define CHIP_365_TRIO3D 0x13 #define CHIP_XXX_TRIO 0x80 #define CHIP_XXX_TRIO64V2_DXGX 0x81 @@ -341,7 +345,8 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) u8 regval; int rv; - rv = svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node); + rv = svga_compute_pll((par->chip == CHIP_365_TRIO3D) ? &s3_trio3d_pll : &s3_pll, + 1000000000 / pixclock, &m, &n, &r, info->node); if (rv < 0) { printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node); return; @@ -598,7 +603,8 @@ static int s3fb_set_par(struct fb_info *info) if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || - par->chip == CHIP_368_TRIO3D_2X) { + par->chip == CHIP_368_TRIO3D_2X || + par->chip == CHIP_365_TRIO3D) { dbytes = info->var.xres * ((bpp+7)/8); vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8); vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); @@ -1012,13 +1018,15 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i regval = vga_rcrt(par->state.vgabase, 0x36); if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || - par->chip == CHIP_368_TRIO3D_2X) { + par->chip == CHIP_368_TRIO3D_2X || + par->chip == CHIP_365_TRIO3D) { switch ((regval & 0xE0) >> 5) { case 0: /* 8MB -- only 4MB usable for display */ case 1: /* 4MB with 32-bit bus */ case 2: /* 4MB */ info->screen_size = 4 << 20; break; + case 4: /* 2MB on 365 Trio3D */ case 6: /* 2MB */ info->screen_size = 2 << 20; break; @@ -1226,6 +1234,7 @@ static struct pci_device_id s3_devices[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D}, {0, 0, 0, 0, 0, 0, 0} }; -- cgit v1.2.2 From 3827d10ed4278323b75bf25d09c146c050519254 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 1 Mar 2011 19:18:27 +0000 Subject: s3fb: fix 15/16bpp modes with over 115MHz pixclocks on 86C365 Trio3D Enable pixel multiplexing in 15/16bpp modes when pixclock is over 115MHz on Trio3D (86C365) cards to fix artifacts on the left side of screen. Signed-off-by: Ondrej Zary Acked-by: Ondrej Zajicek Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index be12145681f6..7b8fdc6d9d55 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -675,6 +675,15 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0); else svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); + } else if (par->chip == CHIP_365_TRIO3D) { + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + if (info->var.pixclock > 8695) { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); + hmul = 2; + } else { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0); + multiplex = 1; + } } else { svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); @@ -691,6 +700,15 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0); else svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); + } else if (par->chip == CHIP_365_TRIO3D) { + svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); + if (info->var.pixclock > 8695) { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); + hmul = 2; + } else { + svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0); + multiplex = 1; + } } else { svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); -- cgit v1.2.2 From cb11c048928b519548dbfb7da149dd2521500db0 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 1 Mar 2011 19:18:35 +0000 Subject: s3fb: enable DTPC Enable Data Transfer Position Control (DTPC). This is needed at least on Virge/DX to correctly display at higher pixclocks. Signed-off-by: Ondrej Zary Acked-by: Ondrej Zajicek Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 7b8fdc6d9d55..808db19aa5de 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -126,6 +126,8 @@ static const struct vga_regset s3_line_compare_regs[] = {{0x18, 0, 7}, {0x07, static const struct vga_regset s3_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x31, 4, 5}, {0x51, 0, 1}, VGA_REGSET_END}; static const struct vga_regset s3_offset_regs[] = {{0x13, 0, 7}, {0x51, 4, 5}, VGA_REGSET_END}; /* set 0x43 bit 2 to 0 */ +static const struct vga_regset s3_dtpc_regs[] = {{0x3B, 0, 7}, {0x5D, 6, 6}, VGA_REGSET_END}; + static const struct svga_timing_regs s3_timing_regs = { s3_h_total_regs, s3_h_display_regs, s3_h_blank_start_regs, s3_h_blank_end_regs, s3_h_sync_start_regs, s3_h_sync_end_regs, @@ -485,6 +487,7 @@ static int s3fb_set_par(struct fb_info *info) struct s3fb_info *par = info->par; u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes; u32 bpp = info->var.bits_per_pixel; + u32 htotal, hsstart; if (bpp != 0) { info->fix.ypanstep = 1; @@ -604,7 +607,9 @@ static int s3fb_set_par(struct fb_info *info) if (par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X || - par->chip == CHIP_365_TRIO3D) { + par->chip == CHIP_365_TRIO3D || + par->chip == CHIP_375_VIRGE_DX || + par->chip == CHIP_385_VIRGE_GX) { dbytes = info->var.xres * ((bpp+7)/8); vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8); vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80); @@ -612,6 +617,16 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(par->state.vgabase, 0x66, 0x81); } + if (par->chip == CHIP_356_VIRGE_GX2 || + par->chip == CHIP_357_VIRGE_GX2P || + par->chip == CHIP_359_VIRGE_GX2P || + par->chip == CHIP_360_TRIO3D_1X || + par->chip == CHIP_362_TRIO3D_2X || + par->chip == CHIP_368_TRIO3D_2X) + vga_wcrt(par->state.vgabase, 0x34, 0x00); + else /* enable Data Transfer Position Control (DTPC) */ + vga_wcrt(par->state.vgabase, 0x34, 0x10); + svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40); multiplex = 0; hmul = 1; @@ -745,9 +760,14 @@ static int s3fb_set_par(struct fb_info *info) hmul, info->node); /* Set interlaced mode start/end register */ - value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; - value = ((value * hmul) / 8) - 5; - vga_wcrt(par->state.vgabase, 0x3C, (value + 1) / 2); + htotal = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len; + htotal = ((htotal * hmul) / 8) - 5; + vga_wcrt(par->state.vgabase, 0x3C, (htotal + 1) / 2); + + /* Set Data Transfer Position */ + hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8; + value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1); + svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value); memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ -- cgit v1.2.2 From 7fe029df4245b7765efeebbcfd1b3dfda1432a8e Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 1 Mar 2011 19:18:43 +0000 Subject: s3fb: use new start address register Use "new" start address register 0x69 (bits 16-20) instead of "old" 0x31 (bits 16-17) and 0x51 (bits 18-19). This is needed for panning to work correctly on Trio3D/2X cards (and does no harm on other ones). Signed-off-by: Ondrej Zary Acked-by: Ondrej Zajicek Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 808db19aa5de..ddedad9cd069 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -123,7 +123,7 @@ static const struct vga_regset s3_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, static const struct vga_regset s3_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END}; static const struct vga_regset s3_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x5E, 6, 6}, VGA_REGSET_END}; -static const struct vga_regset s3_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x31, 4, 5}, {0x51, 0, 1}, VGA_REGSET_END}; +static const struct vga_regset s3_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x69, 0, 4}, VGA_REGSET_END}; static const struct vga_regset s3_offset_regs[] = {{0x13, 0, 7}, {0x51, 4, 5}, VGA_REGSET_END}; /* set 0x43 bit 2 to 0 */ static const struct vga_regset s3_dtpc_regs[] = {{0x3B, 0, 7}, {0x5D, 6, 6}, VGA_REGSET_END}; -- cgit v1.2.2 From 56fb22f7ca11ba5f04c297b7f7aa758ac8dbb2ce Mon Sep 17 00:00:00 2001 From: axel lin Date: Sat, 29 Jan 2011 09:33:48 +0000 Subject: video: hpfb: use resource_size() The size calculation is done incorrectly here because it should include both the start and end (end - start + 1). Signed-off-by: Axel Lin Signed-off-by: Paul Mundt --- drivers/video/hpfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index c8e280f1bb0b..ebf8495ff198 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -321,11 +321,11 @@ static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_ unsigned long paddr, vaddr; paddr = d->resource.start; - if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name)) + if (!request_mem_region(d->resource.start, resource_size(&d->resource), d->name)) return -EBUSY; if (d->scode >= DIOII_SCBASE) { - vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start); + vaddr = (unsigned long)ioremap(paddr, resource_size(&d->resource)); } else { vaddr = paddr + DIO_VIRADDRBASE; } @@ -344,7 +344,7 @@ static void __devexit hpfb_remove_one(struct dio_dev *d) unregister_framebuffer(&fb_info); if (d->scode >= DIOII_SCBASE) iounmap((void *)fb_regs); - release_mem_region(d->resource.start, d->resource.end - d->resource.start); + release_mem_region(d->resource.start, resource_size(&d->resource)); } static struct dio_device_id hpfb_dio_tbl[] = { -- cgit v1.2.2 From e0998eab678233fae7dff7b92db08ad0f01acf91 Mon Sep 17 00:00:00 2001 From: axel lin Date: Sat, 29 Jan 2011 09:35:45 +0000 Subject: video: sh7760fb: use resource_size() The size calculation is done incorrectly in request_mem_region because it should include both the start and end (end - start + 1). Signed-off-by: Axel Lin Signed-off-by: Paul Mundt --- drivers/video/sh7760fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index bea38fce2470..8fe19582c460 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c @@ -459,14 +459,14 @@ static int __devinit sh7760fb_probe(struct platform_device *pdev) } par->ioarea = request_mem_region(res->start, - (res->end - res->start), pdev->name); + resource_size(res), pdev->name); if (!par->ioarea) { dev_err(&pdev->dev, "mmio area busy\n"); ret = -EBUSY; goto out_fb; } - par->base = ioremap_nocache(res->start, res->end - res->start + 1); + par->base = ioremap_nocache(res->start, resource_size(res)); if (!par->base) { dev_err(&pdev->dev, "cannot remap\n"); ret = -ENODEV; -- cgit v1.2.2 From beee1f20a185c7e79fd33bb83e04fe44ecd75af3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 21 Mar 2011 15:03:13 +0000 Subject: fbdev: sh_mobile_lcdc: checking NULL instead of IS_ERR() backlight_device_register() returns an ERR_PTR. It doesn't return NULL. Signed-off-by: Dan Carpenter Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index bf2629f83f40..757665bc500f 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1088,8 +1088,9 @@ static struct backlight_device *sh_mobile_lcdc_bl_probe(struct device *parent, bl = backlight_device_register(ch->cfg.bl_info.name, parent, ch, &sh_mobile_lcdc_bl_ops, NULL); - if (!bl) { - dev_err(parent, "unable to register backlight device\n"); + if (IS_ERR(bl)) { + dev_err(parent, "unable to register backlight device: %ld\n", + PTR_ERR(bl)); return NULL; } -- cgit v1.2.2 From 49bb0943329929e73c9a22c97d53c6c8967eb243 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Feb 2011 08:23:10 +0000 Subject: radeonfb: Let hwmon driver probe the "monid" I2C bus Some Radeon cards have an I2C-based thermal sensor chip connected to the "monid" I2C bus. Set the I2C probing class of this bus properly so that hwmon drivers can detect devices on it and bind to them. This closes kernel.org bug #26172. We exclude PPC for the time being, as Benjamin doesn't want us to mess up with them without explicit testing, and there is no evidence that this change is needed for them either. Reported-by: Alexander Goomenyuk Signed-off-by: Jean Delvare Cc: Benjamin Herrenschmidt Signed-off-by: Paul Mundt --- drivers/video/aty/radeon_i2c.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c index 78d1f4cd1fe0..ab1d0fd76316 100644 --- a/drivers/video/aty/radeon_i2c.c +++ b/drivers/video/aty/radeon_i2c.c @@ -100,6 +100,9 @@ void radeon_create_i2c_busses(struct radeonfb_info *rinfo) { rinfo->i2c[0].rinfo = rinfo; rinfo->i2c[0].ddc_reg = GPIO_MONID; +#ifndef CONFIG_PPC + rinfo->i2c[0].adapter.class = I2C_CLASS_HWMON; +#endif radeon_setup_i2c_bus(&rinfo->i2c[0], "monid"); rinfo->i2c[1].rinfo = rinfo; -- cgit v1.2.2 From 7b0e278519eba8050f2b37d7c408958745f30ecd Mon Sep 17 00:00:00 2001 From: axel lin Date: Tue, 8 Feb 2011 14:58:45 +0000 Subject: video: ffb: fix ffb_probe error path Current implementation calls of_iounmap for par->fbc twice in error path. In the case of goto out_unmap_dac, we should call of_iounmap for par->dac. Signed-off-by: Axel Lin Acked-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/ffb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 910c5e6f6702..14102a3f70f5 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -1010,7 +1010,7 @@ out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_dac: - of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); + of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac)); out_unmap_fbc: of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); -- cgit v1.2.2 From 803a4e14a7dceaf01dbc0e02c0fdea2eba4c81b3 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Sat, 27 Nov 2010 14:17:55 +0100 Subject: uvesafb,vesafb: create WC or WB PAT-entries with an PAT-enabled kernel, when using uvesafb or vesafb, these drivers will create uncached-minus PAT entries for the framebuffer memory because they use ioremap() (not the *_cache or *_wc variants). When the framebuffer memory intersects with the video RAM used by Xorg, the complete video RAM will be mapped uncached-minus what results in a serve performance penalty. Here are the correct MTRR entries created by uvesafb: schlicht@netbook:~$ cat /proc/mtrr reg00: base=0x000000000 ( 0MB), size= 2048MB, count=1: write-back reg01: base=0x06ff00000 ( 1791MB), size= 1MB, count=1: uncachable reg02: base=0x070000000 ( 1792MB), size= 256MB, count=1: uncachable reg03: base=0x0d0000000 ( 3328MB), size= 16MB, count=1: write-combining And here are the problematic PAT entries: schlicht@netbook:~$ sudo cat /sys/kernel/debug/x86/pat_memtype_list PAT memtype list: write-back @ 0x0-0x1000 uncached-minus @ 0x6fedd000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee3000-0x6fee4000 uncached-minus @ 0x6fee3000-0x6fee4000 uncached-minus @ 0x6fee3000-0x6fee4000 uncached-minus @ 0xd0000000-0xe0000000 <-- created by xserver-xorg uncached-minus @ 0xd0000000-0xd1194000 <-- created by uvesafb uncached-minus @ 0xf4000000-0xf4009000 uncached-minus @ 0xf4200000-0xf4400000 uncached-minus @ 0xf5000000-0xf5010000 uncached-minus @ 0xf5100000-0xf5104000 uncached-minus @ 0xf5400000-0xf5404000 uncached-minus @ 0xf5404000-0xf5405000 uncached-minus @ 0xf5404000-0xf5405000 uncached-minus @ 0xfed00000-0xfed01000 Therefore I created the attached patch for uvesafb which uses ioremap_wc() to create the correct PAT entries, as shown below: schlicht@netbook:~$ sudo cat /sys/kernel/debug/x86/pat_memtype_list PAT memtype list: write-back @ 0x0-0x1000 uncached-minus @ 0x6fedd000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee2000-0x6fee3000 uncached-minus @ 0x6fee3000-0x6fee4000 uncached-minus @ 0x6fee3000-0x6fee4000 uncached-minus @ 0x6fee3000-0x6fee4000 write-combining @ 0xd0000000-0xe0000000 write-combining @ 0xd0000000-0xd1194000 uncached-minus @ 0xf4000000-0xf4009000 uncached-minus @ 0xf4200000-0xf4400000 uncached-minus @ 0xf5000000-0xf5010000 uncached-minus @ 0xf5100000-0xf5104000 uncached-minus @ 0xf5400000-0xf5404000 uncached-minus @ 0xf5404000-0xf5405000 uncached-minus @ 0xf5404000-0xf5405000 uncached-minus @ 0xfed00000-0xfed01000 This results in a performance gain, objectively measurable with e.g. x11perf -comppixwin10 -comppixwin100 -comppixwin500: 1: x11perf_xaa.log 2: x11perf_xaa_patched.log 1 2 Operation -------- ---------------- ----------------- 124000.0 202000.0 ( 1.63) Composite 10x10 from pixmap to window 3340.0 24400.0 ( 7.31) Composite 100x100 from pixmap to window 131.0 1150.0 ( 8.78) Composite 500x500 from pixmap to window You can see the serve performance gain when composing larger pixmaps to window. The patches replace the ioremap() function with the variant matching the mtrr- parameter. To create "write-back" PAT entries, the ioremap_cache() function must be called after creating the MTRR entries, and the ioremap_cache() region must completely fit into the MTRR region, this is why the MTRR region size is now rounded up to the next power-of-two. Signed-off-by: Thomas Schlichter Signed-off-by: Paul Mundt --- drivers/video/uvesafb.c | 49 +++++++++++++++++++++++++++++++++++-------------- drivers/video/vesafb.c | 44 +++++++++++++++++++++++++++++--------------- 2 files changed, 64 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index 5180a215d781..7f8472cc993b 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -1552,8 +1552,7 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info) int rc; /* Find the largest power-of-two */ - while (temp_size & (temp_size - 1)) - temp_size &= (temp_size - 1); + temp_size = roundup_pow_of_two(temp_size); /* Try and find a power of two to add */ do { @@ -1566,6 +1565,28 @@ static void __devinit uvesafb_init_mtrr(struct fb_info *info) #endif /* CONFIG_MTRR */ } +static void __devinit uvesafb_ioremap(struct fb_info *info) +{ +#ifdef CONFIG_X86 + switch (mtrr) { + case 1: /* uncachable */ + info->screen_base = ioremap_nocache(info->fix.smem_start, info->fix.smem_len); + break; + case 2: /* write-back */ + info->screen_base = ioremap_cache(info->fix.smem_start, info->fix.smem_len); + break; + case 3: /* write-combining */ + info->screen_base = ioremap_wc(info->fix.smem_start, info->fix.smem_len); + break; + case 4: /* write-through */ + default: + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + break; + } +#else + info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); +#endif /* CONFIG_X86 */ +} static ssize_t uvesafb_show_vbe_ver(struct device *dev, struct device_attribute *attr, char *buf) @@ -1736,15 +1757,22 @@ static int __devinit uvesafb_probe(struct platform_device *dev) uvesafb_init_info(info, mode); + if (!request_region(0x3c0, 32, "uvesafb")) { + printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n"); + err = -EIO; + goto out_mode; + } + if (!request_mem_region(info->fix.smem_start, info->fix.smem_len, "uvesafb")) { printk(KERN_ERR "uvesafb: cannot reserve video memory at " "0x%lx\n", info->fix.smem_start); err = -EIO; - goto out_mode; + goto out_reg; } - info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + uvesafb_init_mtrr(info); + uvesafb_ioremap(info); if (!info->screen_base) { printk(KERN_ERR @@ -1755,20 +1783,13 @@ static int __devinit uvesafb_probe(struct platform_device *dev) goto out_mem; } - if (!request_region(0x3c0, 32, "uvesafb")) { - printk(KERN_ERR "uvesafb: request region 0x3c0-0x3e0 failed\n"); - err = -EIO; - goto out_unmap; - } - - uvesafb_init_mtrr(info); platform_set_drvdata(dev, info); if (register_framebuffer(info) < 0) { printk(KERN_ERR "uvesafb: failed to register framebuffer device\n"); err = -EINVAL; - goto out_reg; + goto out_unmap; } printk(KERN_INFO "uvesafb: framebuffer at 0x%lx, mapped to 0x%p, " @@ -1785,12 +1806,12 @@ static int __devinit uvesafb_probe(struct platform_device *dev) return 0; -out_reg: - release_region(0x3c0, 32); out_unmap: iounmap(info->screen_base); out_mem: release_mem_region(info->fix.smem_start, info->fix.smem_len); +out_reg: + release_region(0x3c0, 32); out_mode: if (!list_empty(&info->modelist)) fb_destroy_modelist(&info->modelist); diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 6a069d047914..a99bbe86db13 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -303,19 +303,6 @@ static int __init vesafb_probe(struct platform_device *dev) info->apertures->ranges[0].base = screen_info.lfb_base; info->apertures->ranges[0].size = size_total; - info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); - if (!info->screen_base) { - printk(KERN_ERR - "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", - vesafb_fix.smem_len, vesafb_fix.smem_start); - err = -EIO; - goto err; - } - - printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, " - "using %dk, total %dk\n", - vesafb_fix.smem_start, info->screen_base, - size_remap/1024, size_total/1024); printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages); @@ -438,8 +425,7 @@ static int __init vesafb_probe(struct platform_device *dev) int rc; /* Find the largest power-of-two */ - while (temp_size & (temp_size - 1)) - temp_size &= (temp_size - 1); + temp_size = roundup_pow_of_two(temp_size); /* Try and find a power of two to add */ do { @@ -451,6 +437,34 @@ static int __init vesafb_probe(struct platform_device *dev) } #endif + switch (mtrr) { + case 1: /* uncachable */ + info->screen_base = ioremap_nocache(vesafb_fix.smem_start, vesafb_fix.smem_len); + break; + case 2: /* write-back */ + info->screen_base = ioremap_cache(vesafb_fix.smem_start, vesafb_fix.smem_len); + break; + case 3: /* write-combining */ + info->screen_base = ioremap_wc(vesafb_fix.smem_start, vesafb_fix.smem_len); + break; + case 4: /* write-through */ + default: + info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); + break; + } + if (!info->screen_base) { + printk(KERN_ERR + "vesafb: abort, cannot ioremap video memory 0x%x @ 0x%lx\n", + vesafb_fix.smem_len, vesafb_fix.smem_start); + err = -EIO; + goto err; + } + + printk(KERN_INFO "vesafb: framebuffer at 0x%lx, mapped to 0x%p, " + "using %dk, total %dk\n", + vesafb_fix.smem_start, info->screen_base, + size_remap/1024, size_total/1024); + info->fbops = &vesafb_ops; info->var = vesafb_defined; info->fix = vesafb_fix; -- cgit v1.2.2 From 942b8d05cdf1da396b4449a38b87c677591947c0 Mon Sep 17 00:00:00 2001 From: axel lin Date: Fri, 11 Feb 2011 08:51:10 +0000 Subject: video: s3c-fb: return proper error if clk_get fails Return PTR_ERR(sfb->bus_clk) instead of 0 if clk_get fails. Signed-off-by: Axel Lin Acked-by: Kyungmin Park Signed-off-by: Paul Mundt --- drivers/video/s3c-fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 83ce9a04d872..6817d187d46e 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -1340,6 +1340,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) sfb->bus_clk = clk_get(dev, "lcd"); if (IS_ERR(sfb->bus_clk)) { dev_err(dev, "failed to get bus clock\n"); + ret = PTR_ERR(sfb->bus_clk); goto err_sfb; } -- cgit v1.2.2 From 7cdcdb69bdf51192bcbfb7cf479850fe7c33357d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bie=C3=9Fmann?= Date: Fri, 11 Feb 2011 15:19:43 +0000 Subject: atmel_lcdfb: implement inverted contrast pwm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces lcdc->lcdcon_pol_negative which set CONTRAST_CTR register to inverted polarity. Signed-off-by: Andreas Bießmann Signed-off-by: Paul Mundt --- drivers/video/atmel_lcdfb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index bac163450216..16da8af7425c 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -68,7 +68,7 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, } #endif -static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 +static u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE; @@ -163,6 +163,10 @@ static void exit_backlight(struct atmel_lcdfb_info *sinfo) static void init_contrast(struct atmel_lcdfb_info *sinfo) { + /* contrast pwm can be 'inverted' */ + if (sinfo->lcdcon_pol_negative) + contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); + /* have some default contrast/backlight settings */ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); @@ -816,6 +820,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->guard_time = pdata_sinfo->guard_time; sinfo->smem_len = pdata_sinfo->smem_len; sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; + sinfo->lcdcon_pol_negative = pdata_sinfo->lcdcon_pol_negative; sinfo->lcd_wiring_mode = pdata_sinfo->lcd_wiring_mode; } else { dev_err(dev, "cannot get default configuration\n"); -- cgit v1.2.2 From bed7bddbb434df0e76ffe2ff8cb535fe8f3c0c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Bie=C3=9Fmann?= Date: Fri, 11 Feb 2011 15:19:44 +0000 Subject: atmel_lcdfb: add fb_blank function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Bießmann Signed-off-by: Paul Mundt --- drivers/video/atmel_lcdfb.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 16da8af7425c..59654e29e205 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -714,11 +714,35 @@ static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var, return 0; } +static int atmel_lcdfb_blank(int blank_mode, struct fb_info *info) +{ + struct atmel_lcdfb_info *sinfo = info->par; + + switch (blank_mode) { + case FB_BLANK_UNBLANK: + case FB_BLANK_NORMAL: + atmel_lcdfb_start(sinfo); + break; + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + break; + case FB_BLANK_POWERDOWN: + atmel_lcdfb_stop(sinfo); + break; + default: + return -EINVAL; + } + + /* let fbcon do a soft blank for us */ + return ((blank_mode == FB_BLANK_NORMAL) ? 1 : 0); +} + static struct fb_ops atmel_lcdfb_ops = { .owner = THIS_MODULE, .fb_check_var = atmel_lcdfb_check_var, .fb_set_par = atmel_lcdfb_set_par, .fb_setcolreg = atmel_lcdfb_setcolreg, + .fb_blank = atmel_lcdfb_blank, .fb_pan_display = atmel_lcdfb_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, -- cgit v1.2.2 From 83e61f71d72da7240378fe7ecba5e936a0f159db Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Wed, 16 Feb 2011 06:55:38 +0000 Subject: drivers:video:aty:radeon_base Fix typo occationally to occasionally The below patch fixes a typo occationally to occasionally. Signed-off-by: Justin P. Mattock Signed-off-by: Paul Mundt --- drivers/gpu/drm/radeon/radeon_legacy_crtc.c | 2 +- drivers/video/aty/radeon_base.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 66c9af1b3d96..41a5d48e657b 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -889,7 +889,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } if (rdev->flags & RADEON_IS_MOBILITY) { - /* A temporal workaround for the occational blanking on certain laptop panels. + /* A temporal workaround for the occasional blanking on certain laptop panels. This appears to related to the PLL divider registers (fail to lock?). It occurs even when all dividers are the same with their old settings. In this case we really don't need to fiddle with PLL registers. diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 3c1e13ed1cba..32f8cf6200a7 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -1248,7 +1248,7 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg /* Workaround from XFree */ if (rinfo->is_mobility) { - /* A temporal workaround for the occational blanking on certain laptop + /* A temporal workaround for the occasional blanking on certain laptop * panels. This appears to related to the PLL divider registers * (fail to lock?). It occurs even when all dividers are the same * with their old settings. In this case we really don't need to -- cgit v1.2.2 From 79ac33ec845c1872a23169644c5867528ff05590 Mon Sep 17 00:00:00 2001 From: axel lin Date: Sun, 13 Feb 2011 13:06:23 +0000 Subject: video: hecubafb: add __devexit_p around reference to hecubafb_remove hecubafb_remove is marked __devexit, thus add __devexit_p around reference to hecubafb_remove. Signed-off-by: Axel Lin Signed-off-by: Paul Mundt --- drivers/video/hecubafb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c index c77bcc6ab463..1b94643ecbcf 100644 --- a/drivers/video/hecubafb.c +++ b/drivers/video/hecubafb.c @@ -299,7 +299,7 @@ static int __devexit hecubafb_remove(struct platform_device *dev) static struct platform_driver hecubafb_driver = { .probe = hecubafb_probe, - .remove = hecubafb_remove, + .remove = __devexit_p(hecubafb_remove), .driver = { .owner = THIS_MODULE, .name = "hecubafb", -- cgit v1.2.2 From 1e93f390e56d82c4fcf684c86a45e1c593dc4b28 Mon Sep 17 00:00:00 2001 From: axel lin Date: Sun, 13 Feb 2011 04:02:10 +0000 Subject: video: metronomefb: add __devexit_p around reference to metronomefb_remove metronomefb_remove is marked __devexit, thus add __devexit_p around reference to metronomefb_remove. Signed-off-by: Axel Lin Signed-off-by: Paul Mundt --- drivers/video/metronomefb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index 63ed3b72b01c..ed64edfd2c43 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c @@ -765,7 +765,7 @@ static int __devexit metronomefb_remove(struct platform_device *dev) static struct platform_driver metronomefb_driver = { .probe = metronomefb_probe, - .remove = metronomefb_remove, + .remove = __devexit_p(metronomefb_remove), .driver = { .owner = THIS_MODULE, .name = "metronomefb", -- cgit v1.2.2 From 1e9bb8808ac11094d711d20d580e7b45a4992d0c Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Tue, 22 Mar 2011 08:35:35 +0100 Subject: block: fix non-atomic access to genhd inflight structures After the stack plugging introduction, these are called lockless. Ensure that the counters are updated atomically. Signed-off-by: Shaohua Li Signed-off-by: Jens Axboe --- drivers/md/dm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 88820704a191..0cf68b478878 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -477,7 +477,8 @@ static void start_io_acct(struct dm_io *io) cpu = part_stat_lock(); part_round_stats(cpu, &dm_disk(md)->part0); part_stat_unlock(); - dm_disk(md)->part0.in_flight[rw] = atomic_inc_return(&md->pending[rw]); + atomic_set(&dm_disk(md)->part0.in_flight[rw], + atomic_inc_return(&md->pending[rw])); } static void end_io_acct(struct dm_io *io) @@ -497,8 +498,8 @@ static void end_io_acct(struct dm_io *io) * After this is decremented the bio must not be touched if it is * a flush. */ - dm_disk(md)->part0.in_flight[rw] = pending = - atomic_dec_return(&md->pending[rw]); + pending = atomic_dec_return(&md->pending[rw]); + atomic_set(&dm_disk(md)->part0.in_flight[rw], pending); pending += atomic_read(&md->pending[rw^0x1]); /* nudge anyone waiting on suspend queue */ -- cgit v1.2.2 From 6359691d7efc639bf0f996aa9a694b2653fc6ae6 Mon Sep 17 00:00:00 2001 From: axel lin Date: Tue, 15 Feb 2011 09:35:02 +0000 Subject: video: add missing framebuffer_release in error path This patch fixes a memory leak in the error path. Signed-off-by: Axel Lin Acked-by: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/cg14.c | 1 + drivers/video/cg6.c | 1 + drivers/video/tcx.c | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index e2c85b0db632..f18895006627 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -565,6 +565,7 @@ out_dealloc_cmap: out_unmap_regs: cg14_unmap_regs(op, info, par); + framebuffer_release(info); out_err: return err; diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 4ffad90bde42..179e96cdb323 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -821,6 +821,7 @@ out_dealloc_cmap: out_unmap_regs: cg6_unmap_regs(op, info, par); + framebuffer_release(info); out_err: return err; diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 855b71993f61..07c66e946634 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -480,6 +480,7 @@ out_dealloc_cmap: out_unmap_regs: tcx_unmap_regs(op, info, par); + framebuffer_release(info); out_err: return err; -- cgit v1.2.2 From d6244bc0ed0c52a795e6f4dcab3886daf3e74fac Mon Sep 17 00:00:00 2001 From: Henry Nestler Date: Sun, 20 Feb 2011 20:50:56 +0000 Subject: fbcon: Bugfix soft cursor detection in Tile Blitting Use mask 0x10 for "soft cursor" detection on in function tile_cursor. (Tile Blitting Operation in framebuffer console). The old mask 0x01 for vc_cursor_type detects CUR_NONE, CUR_LOWER_THIRD and every second mode value as "software cursor". This hides the cursor for these modes (cursor.mode = 0). But, only CUR_NONE or "software cursor" should hide the cursor. See also 0x10 in functions add_softcursor, bit_cursor and cw_cursor. Signed-off-by: Henry Nestler Cc: stable@kernel.org Signed-off-by: Paul Mundt --- drivers/video/console/tileblit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c index 0056a41e5c35..15e8e1a89c45 100644 --- a/drivers/video/console/tileblit.c +++ b/drivers/video/console/tileblit.c @@ -83,7 +83,7 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, int softback_lines, int fg, int bg) { struct fb_tilecursor cursor; - int use_sw = (vc->vc_cursor_type & 0x01); + int use_sw = (vc->vc_cursor_type & 0x10); cursor.sx = vc->vc_x; cursor.sy = vc->vc_y; -- cgit v1.2.2 From dfc906daeec03b3f2d306ae260d398d97ba232c5 Mon Sep 17 00:00:00 2001 From: Martin Decky Date: Sun, 13 Feb 2011 19:28:40 +0000 Subject: video: Fix EDID macros H_SYNC_WIDTH and H_SYNC_OFFSET The macros for getting the values for horizontal sync width and offset do not respect the EDID specification. Both these values are 10 bit values according to [1], not 6 bit values. The lower 8 bits are stored in byte 8 and byte 9 of the DTD respectively, while two additional bits for each value are stored in byte 11. The original macros just slammed the bits together. Although the original macros usually worked fine because the higher two bits are rarely used, it can cause severe problems on plasma panels running at 1920x1080 @ 50 Hz with drivers that rely on the correct parsing of the EDID data by fbmon.c (e.g. udlfb). The patch should apply cleanly to both the fbdev-2.6.git branch and linux-next.git branch. [1] VESA Enhanced Extended Display Identification Data Standard, Release A, Revision 2, page 34, notes 7 & 8, VESA, Sep 2006 Signed-off-by: Martin Decky Signed-off-by: Paul Mundt --- drivers/video/edid.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/edid.h b/drivers/video/edid.h index bd89fb3be8c2..d03a232d90b2 100644 --- a/drivers/video/edid.h +++ b/drivers/video/edid.h @@ -101,8 +101,8 @@ #define V_SYNC_WIDTH COMBINE_HI_4LO( V_SYNC_WIDTH_HI, V_SYNC_WIDTH_LO ) #define V_SYNC_OFFSET COMBINE_HI_4LO( V_SYNC_OFFSET_HI, V_SYNC_OFFSET_LO ) -#define H_SYNC_WIDTH COMBINE_HI_4LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) -#define H_SYNC_OFFSET COMBINE_HI_4LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) +#define H_SYNC_WIDTH COMBINE_HI_8LO( H_SYNC_WIDTH_HI, H_SYNC_WIDTH_LO ) +#define H_SYNC_OFFSET COMBINE_HI_8LO( H_SYNC_OFFSET_HI, H_SYNC_OFFSET_LO ) #define H_SIZE_LO (unsigned)block[ 12 ] #define V_SIZE_LO (unsigned)block[ 13 ] -- cgit v1.2.2 From cf4b9211b5680cd9ca004232e517fb7ec5bf5316 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:39:56 -0300 Subject: [media] media: Media device node support The media_devnode structure provides support for registering and unregistering character devices using a dynamic major number. Reference counting is handled internally, making device drivers easier to write without having to solve the open/disconnect race condition issue over and over again. The code is based on video/v4l2-dev.c. [mchehab@redhat.com: Remove linux/smp_lock.h include to not break compilation on bisect] Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 13 ++ drivers/media/Makefile | 6 + drivers/media/media-devnode.c | 320 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/media/media-devnode.c (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 81b3ba83cc65..2466f2b2ecfa 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -13,6 +13,19 @@ if MEDIA_SUPPORT comment "Multimedia core support" +# +# Media controller +# + +config MEDIA_CONTROLLER + bool "Media Controller API (EXPERIMENTAL)" + depends on EXPERIMENTAL + ---help--- + Enable the media controller API used to query media devices internal + topology and configure it dynamically. + + This API is mostly used by camera interfaces in embedded platforms. + # # V4L core and enabled API's # diff --git a/drivers/media/Makefile b/drivers/media/Makefile index b603ea645ede..d56349f6103f 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,6 +2,12 @@ # Makefile for the kernel multimedia device drivers. # +media-objs := media-devnode.o + +ifeq ($(CONFIG_MEDIA_CONTROLLER),y) + obj-$(CONFIG_MEDIA_SUPPORT) += media.o +endif + obj-y += common/ rc/ video/ obj-$(CONFIG_VIDEO_DEV) += radio/ diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c new file mode 100644 index 000000000000..af5263c6625a --- /dev/null +++ b/drivers/media/media-devnode.c @@ -0,0 +1,320 @@ +/* + * Media device node + * + * Copyright (C) 2010 Nokia Corporation + * + * Based on drivers/media/video/v4l2_dev.c code authored by + * Mauro Carvalho Chehab (version 2) + * Alan Cox, (version 1) + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -- + * + * Generic media device node infrastructure to register and unregister + * character devices using a dynamic major number and proper reference + * counting. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MEDIA_NUM_DEVICES 256 +#define MEDIA_NAME "media" + +static dev_t media_dev_t; + +/* + * Active devices + */ +static DEFINE_MUTEX(media_devnode_lock); +static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); + +/* Called when the last user of the media device exits. */ +static void media_devnode_release(struct device *cd) +{ + struct media_devnode *mdev = to_media_devnode(cd); + + mutex_lock(&media_devnode_lock); + + /* Delete the cdev on this minor as well */ + cdev_del(&mdev->cdev); + + /* Mark device node number as free */ + clear_bit(mdev->minor, media_devnode_nums); + + mutex_unlock(&media_devnode_lock); + + /* Release media_devnode and perform other cleanups as needed. */ + if (mdev->release) + mdev->release(mdev); +} + +static struct bus_type media_bus_type = { + .name = MEDIA_NAME, +}; + +static ssize_t media_read(struct file *filp, char __user *buf, + size_t sz, loff_t *off) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!mdev->fops->read) + return -EINVAL; + if (!media_devnode_is_registered(mdev)) + return -EIO; + return mdev->fops->read(filp, buf, sz, off); +} + +static ssize_t media_write(struct file *filp, const char __user *buf, + size_t sz, loff_t *off) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!mdev->fops->write) + return -EINVAL; + if (!media_devnode_is_registered(mdev)) + return -EIO; + return mdev->fops->write(filp, buf, sz, off); +} + +static unsigned int media_poll(struct file *filp, + struct poll_table_struct *poll) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!media_devnode_is_registered(mdev)) + return POLLERR | POLLHUP; + if (!mdev->fops->poll) + return DEFAULT_POLLMASK; + return mdev->fops->poll(filp, poll); +} + +static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + if (!mdev->fops->ioctl) + return -ENOTTY; + + if (!media_devnode_is_registered(mdev)) + return -EIO; + + return mdev->fops->ioctl(filp, cmd, arg); +} + +/* Override for the open function */ +static int media_open(struct inode *inode, struct file *filp) +{ + struct media_devnode *mdev; + int ret; + + /* Check if the media device is available. This needs to be done with + * the media_devnode_lock held to prevent an open/unregister race: + * without the lock, the device could be unregistered and freed between + * the media_devnode_is_registered() and get_device() calls, leading to + * a crash. + */ + mutex_lock(&media_devnode_lock); + mdev = container_of(inode->i_cdev, struct media_devnode, cdev); + /* return ENXIO if the media device has been removed + already or if it is not registered anymore. */ + if (!media_devnode_is_registered(mdev)) { + mutex_unlock(&media_devnode_lock); + return -ENXIO; + } + /* and increase the device refcount */ + get_device(&mdev->dev); + mutex_unlock(&media_devnode_lock); + + filp->private_data = mdev; + + if (mdev->fops->open) { + ret = mdev->fops->open(filp); + if (ret) { + put_device(&mdev->dev); + return ret; + } + } + + return 0; +} + +/* Override for the release function */ +static int media_release(struct inode *inode, struct file *filp) +{ + struct media_devnode *mdev = media_devnode_data(filp); + int ret = 0; + + if (mdev->fops->release) + mdev->fops->release(filp); + + /* decrease the refcount unconditionally since the release() + return value is ignored. */ + put_device(&mdev->dev); + filp->private_data = NULL; + return ret; +} + +static const struct file_operations media_devnode_fops = { + .owner = THIS_MODULE, + .read = media_read, + .write = media_write, + .open = media_open, + .unlocked_ioctl = media_ioctl, + .release = media_release, + .poll = media_poll, + .llseek = no_llseek, +}; + +/** + * media_devnode_register - register a media device node + * @mdev: media device node structure we want to register + * + * The registration code assigns minor numbers and registers the new device node + * with the kernel. An error is returned if no free minor number can be found, + * or if the registration of the device node fails. + * + * Zero is returned on success. + * + * Note that if the media_devnode_register call fails, the release() callback of + * the media_devnode structure is *not* called, so the caller is responsible for + * freeing any data. + */ +int __must_check media_devnode_register(struct media_devnode *mdev) +{ + int minor; + int ret; + + /* Part 1: Find a free minor number */ + mutex_lock(&media_devnode_lock); + minor = find_next_zero_bit(media_devnode_nums, 0, MEDIA_NUM_DEVICES); + if (minor == MEDIA_NUM_DEVICES) { + mutex_unlock(&media_devnode_lock); + printk(KERN_ERR "could not get a free minor\n"); + return -ENFILE; + } + + set_bit(mdev->minor, media_devnode_nums); + mutex_unlock(&media_devnode_lock); + + mdev->minor = minor; + + /* Part 2: Initialize and register the character device */ + cdev_init(&mdev->cdev, &media_devnode_fops); + mdev->cdev.owner = mdev->fops->owner; + + ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1); + if (ret < 0) { + printk(KERN_ERR "%s: cdev_add failed\n", __func__); + goto error; + } + + /* Part 3: Register the media device */ + mdev->dev.bus = &media_bus_type; + mdev->dev.devt = MKDEV(MAJOR(media_dev_t), mdev->minor); + mdev->dev.release = media_devnode_release; + if (mdev->parent) + mdev->dev.parent = mdev->parent; + dev_set_name(&mdev->dev, "media%d", mdev->minor); + ret = device_register(&mdev->dev); + if (ret < 0) { + printk(KERN_ERR "%s: device_register failed\n", __func__); + goto error; + } + + /* Part 4: Activate this minor. The char device can now be used. */ + set_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + + return 0; + +error: + cdev_del(&mdev->cdev); + clear_bit(mdev->minor, media_devnode_nums); + return ret; +} + +/** + * media_devnode_unregister - unregister a media device node + * @mdev: the device node to unregister + * + * This unregisters the passed device. Future open calls will be met with + * errors. + * + * This function can safely be called if the device node has never been + * registered or has already been unregistered. + */ +void media_devnode_unregister(struct media_devnode *mdev) +{ + /* Check if mdev was ever registered at all */ + if (!media_devnode_is_registered(mdev)) + return; + + mutex_lock(&media_devnode_lock); + clear_bit(MEDIA_FLAG_REGISTERED, &mdev->flags); + mutex_unlock(&media_devnode_lock); + device_unregister(&mdev->dev); +} + +/* + * Initialise media for linux + */ +static int __init media_devnode_init(void) +{ + int ret; + + printk(KERN_INFO "Linux media interface: v0.10\n"); + ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES, + MEDIA_NAME); + if (ret < 0) { + printk(KERN_WARNING "media: unable to allocate major\n"); + return ret; + } + + ret = bus_register(&media_bus_type); + if (ret < 0) { + unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); + printk(KERN_WARNING "media: bus_register failed\n"); + return -EIO; + } + + return 0; +} + +static void __exit media_devnode_exit(void) +{ + bus_unregister(&media_bus_type); + unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); +} + +module_init(media_devnode_init) +module_exit(media_devnode_exit) + +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("Device node registration for media drivers"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 176fb0d108f7495ccf9aa127e1342a1a0d87e004 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:39:58 -0300 Subject: [media] media: Media device The media_device structure abstracts functions common to all kind of media devices (v4l2, dvb, alsa, ...). It manages media entities and offers a userspace API to discover and configure the media device internal topology. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Makefile | 2 +- drivers/media/media-device.c | 100 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 drivers/media/media-device.c (limited to 'drivers') diff --git a/drivers/media/Makefile b/drivers/media/Makefile index d56349f6103f..36731aae57ea 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel multimedia device drivers. # -media-objs := media-devnode.o +media-objs := media-device.o media-devnode.o ifeq ($(CONFIG_MEDIA_CONTROLLER),y) obj-$(CONFIG_MEDIA_SUPPORT) += media.o diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c new file mode 100644 index 000000000000..bcd3985d415a --- /dev/null +++ b/drivers/media/media-device.c @@ -0,0 +1,100 @@ +/* + * Media device + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include +#include + +static const struct media_file_operations media_device_fops = { + .owner = THIS_MODULE, +}; + +/* ----------------------------------------------------------------------------- + * sysfs + */ + +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct media_device *mdev = to_media_device(to_media_devnode(cd)); + + return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); +} + +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); + +/* ----------------------------------------------------------------------------- + * Registration/unregistration + */ + +static void media_device_release(struct media_devnode *mdev) +{ +} + +/** + * media_device_register - register a media device + * @mdev: The media device + * + * The caller is responsible for initializing the media device before + * registration. The following fields must be set: + * + * - dev must point to the parent device + * - model must be filled with the device model name + */ +int __must_check media_device_register(struct media_device *mdev) +{ + int ret; + + if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0)) + return -EINVAL; + + /* Register the device node. */ + mdev->devnode.fops = &media_device_fops; + mdev->devnode.parent = mdev->dev; + mdev->devnode.release = media_device_release; + ret = media_devnode_register(&mdev->devnode); + if (ret < 0) + return ret; + + ret = device_create_file(&mdev->devnode.dev, &dev_attr_model); + if (ret < 0) { + media_devnode_unregister(&mdev->devnode); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(media_device_register); + +/** + * media_device_unregister - unregister a media device + * @mdev: The media device + * + */ +void media_device_unregister(struct media_device *mdev) +{ + device_remove_file(&mdev->devnode.dev, &dev_attr_model); + media_devnode_unregister(&mdev->devnode); +} +EXPORT_SYMBOL_GPL(media_device_unregister); -- cgit v1.2.2 From 53e269c102fbaf77e7dc526b1606ad4a48e57200 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:40:00 -0300 Subject: [media] media: Entities, pads and links As video hardware pipelines become increasingly complex and configurable, the current hardware description through v4l2 subdevices reaches its limits. In addition to enumerating and configuring subdevices, video camera drivers need a way to discover and modify at runtime how those subdevices are connected. This is done through new elements called entities, pads and links. An entity is a basic media hardware building block. It can correspond to a large variety of logical blocks such as physical hardware devices (CMOS sensor for instance), logical hardware devices (a building block in a System-on-Chip image processing pipeline), DMA channels or physical connectors. A pad is a connection endpoint through which an entity can interact with other entities. Data (not restricted to video) produced by an entity flows from the entity's output to one or more entity inputs. Pads should not be confused with physical pins at chip boundaries. A link is a point-to-point oriented connection between two pads, either on the same entity or on different entities. Data flows from a source pad to a sink pad. Links are stored in the source entity. To make backwards graph walk faster, a copy of all links is also stored in the sink entity. The copy is known as a backlink and is only used to help graph traversal. The entity API is made of three functions: - media_entity_init() initializes an entity. The caller must provide an array of pads as well as an estimated number of links. The links array is allocated dynamically and will be reallocated if it grows beyond the initial estimate. - media_entity_cleanup() frees resources allocated for an entity. It must be called during the cleanup phase after unregistering the entity and before freeing it. - media_entity_create_link() creates a link between two entities. An entry in the link array of each entity is allocated and stores pointers to source and sink pads. When a media device is unregistered, all its entities are unregistered automatically. The code is based on Hans Verkuil initial work. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Makefile | 2 +- drivers/media/media-device.c | 56 +++++++++++++++++ drivers/media/media-entity.c | 147 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 drivers/media/media-entity.c (limited to 'drivers') diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 36731aae57ea..64755c99ded2 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel multimedia device drivers. # -media-objs := media-device.o media-devnode.o +media-objs := media-device.o media-devnode.o media-entity.o ifeq ($(CONFIG_MEDIA_CONTROLLER),y) obj-$(CONFIG_MEDIA_SUPPORT) += media.o diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index bcd3985d415a..a36509a1df09 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -25,6 +25,7 @@ #include #include +#include static const struct media_file_operations media_device_fops = { .owner = THIS_MODULE, @@ -69,6 +70,10 @@ int __must_check media_device_register(struct media_device *mdev) if (WARN_ON(mdev->dev == NULL || mdev->model[0] == 0)) return -EINVAL; + mdev->entity_id = 1; + INIT_LIST_HEAD(&mdev->entities); + spin_lock_init(&mdev->lock); + /* Register the device node. */ mdev->devnode.fops = &media_device_fops; mdev->devnode.parent = mdev->dev; @@ -94,7 +99,58 @@ EXPORT_SYMBOL_GPL(media_device_register); */ void media_device_unregister(struct media_device *mdev) { + struct media_entity *entity; + struct media_entity *next; + + list_for_each_entry_safe(entity, next, &mdev->entities, list) + media_device_unregister_entity(entity); + device_remove_file(&mdev->devnode.dev, &dev_attr_model); media_devnode_unregister(&mdev->devnode); } EXPORT_SYMBOL_GPL(media_device_unregister); + +/** + * media_device_register_entity - Register an entity with a media device + * @mdev: The media device + * @entity: The entity + */ +int __must_check media_device_register_entity(struct media_device *mdev, + struct media_entity *entity) +{ + /* Warn if we apparently re-register an entity */ + WARN_ON(entity->parent != NULL); + entity->parent = mdev; + + spin_lock(&mdev->lock); + if (entity->id == 0) + entity->id = mdev->entity_id++; + else + mdev->entity_id = max(entity->id + 1, mdev->entity_id); + list_add_tail(&entity->list, &mdev->entities); + spin_unlock(&mdev->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(media_device_register_entity); + +/** + * media_device_unregister_entity - Unregister an entity + * @entity: The entity + * + * If the entity has never been registered this function will return + * immediately. + */ +void media_device_unregister_entity(struct media_entity *entity) +{ + struct media_device *mdev = entity->parent; + + if (mdev == NULL) + return; + + spin_lock(&mdev->lock); + list_del(&entity->list); + spin_unlock(&mdev->lock); + entity->parent = NULL; +} +EXPORT_SYMBOL_GPL(media_device_unregister_entity); diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c new file mode 100644 index 000000000000..5c31df9ed765 --- /dev/null +++ b/drivers/media/media-entity.c @@ -0,0 +1,147 @@ +/* + * Media entity + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +/** + * media_entity_init - Initialize a media entity + * + * @num_pads: Total number of sink and source pads. + * @extra_links: Initial estimate of the number of extra links. + * @pads: Array of 'num_pads' pads. + * + * The total number of pads is an intrinsic property of entities known by the + * entity driver, while the total number of links depends on hardware design + * and is an extrinsic property unknown to the entity driver. However, in most + * use cases the entity driver can guess the number of links which can safely + * be assumed to be equal to or larger than the number of pads. + * + * For those reasons the links array can be preallocated based on the entity + * driver guess and will be reallocated later if extra links need to be + * created. + * + * This function allocates a links array with enough space to hold at least + * 'num_pads' + 'extra_links' elements. The media_entity::max_links field will + * be set to the number of allocated elements. + * + * The pads array is managed by the entity driver and passed to + * media_entity_init() where its pointer will be stored in the entity structure. + */ +int +media_entity_init(struct media_entity *entity, u16 num_pads, + struct media_pad *pads, u16 extra_links) +{ + struct media_link *links; + unsigned int max_links = num_pads + extra_links; + unsigned int i; + + links = kzalloc(max_links * sizeof(links[0]), GFP_KERNEL); + if (links == NULL) + return -ENOMEM; + + entity->group_id = 0; + entity->max_links = max_links; + entity->num_links = 0; + entity->num_backlinks = 0; + entity->num_pads = num_pads; + entity->pads = pads; + entity->links = links; + + for (i = 0; i < num_pads; i++) { + pads[i].entity = entity; + pads[i].index = i; + } + + return 0; +} +EXPORT_SYMBOL_GPL(media_entity_init); + +void +media_entity_cleanup(struct media_entity *entity) +{ + kfree(entity->links); +} +EXPORT_SYMBOL_GPL(media_entity_cleanup); + +static struct media_link *media_entity_add_link(struct media_entity *entity) +{ + if (entity->num_links >= entity->max_links) { + struct media_link *links = entity->links; + unsigned int max_links = entity->max_links + 2; + unsigned int i; + + links = krealloc(links, max_links * sizeof(*links), GFP_KERNEL); + if (links == NULL) + return NULL; + + for (i = 0; i < entity->num_links; i++) + links[i].reverse->reverse = &links[i]; + + entity->max_links = max_links; + entity->links = links; + } + + return &entity->links[entity->num_links++]; +} + +int +media_entity_create_link(struct media_entity *source, u16 source_pad, + struct media_entity *sink, u16 sink_pad, u32 flags) +{ + struct media_link *link; + struct media_link *backlink; + + BUG_ON(source == NULL || sink == NULL); + BUG_ON(source_pad >= source->num_pads); + BUG_ON(sink_pad >= sink->num_pads); + + link = media_entity_add_link(source); + if (link == NULL) + return -ENOMEM; + + link->source = &source->pads[source_pad]; + link->sink = &sink->pads[sink_pad]; + link->flags = flags; + + /* Create the backlink. Backlinks are used to help graph traversal and + * are not reported to userspace. + */ + backlink = media_entity_add_link(sink); + if (backlink == NULL) { + source->num_links--; + return -ENOMEM; + } + + backlink->source = &source->pads[source_pad]; + backlink->sink = &sink->pads[sink_pad]; + backlink->flags = flags; + + link->reverse = backlink; + backlink->reverse = link; + + sink->num_backlinks++; + + return 0; +} +EXPORT_SYMBOL_GPL(media_entity_create_link); -- cgit v1.2.2 From a5ccc48a7c48610e7f92fa599406738d69195d51 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 7 Mar 2010 16:14:14 -0300 Subject: [media] media: Entity graph traversal Add media entity graph traversal. The traversal follows enabled links by depth first. Traversing graph backwards is prevented by comparing the next possible entity in the graph with the previous one. Multiply connected graphs are thus not supported. Signed-off-by: Sakari Ailus Signed-off-by: Laurent Pinchart Signed-off-by: Vimarsh Zutshi Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-entity.c | 115 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) (limited to 'drivers') diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 5c31df9ed765..166f2b5505ce 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -84,6 +84,121 @@ media_entity_cleanup(struct media_entity *entity) } EXPORT_SYMBOL_GPL(media_entity_cleanup); +/* ----------------------------------------------------------------------------- + * Graph traversal + */ + +static struct media_entity * +media_entity_other(struct media_entity *entity, struct media_link *link) +{ + if (link->source->entity == entity) + return link->sink->entity; + else + return link->source->entity; +} + +/* push an entity to traversal stack */ +static void stack_push(struct media_entity_graph *graph, + struct media_entity *entity) +{ + if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) { + WARN_ON(1); + return; + } + graph->top++; + graph->stack[graph->top].link = 0; + graph->stack[graph->top].entity = entity; +} + +static struct media_entity *stack_pop(struct media_entity_graph *graph) +{ + struct media_entity *entity; + + entity = graph->stack[graph->top].entity; + graph->top--; + + return entity; +} + +#define stack_peek(en) ((en)->stack[(en)->top - 1].entity) +#define link_top(en) ((en)->stack[(en)->top].link) +#define stack_top(en) ((en)->stack[(en)->top].entity) + +/** + * media_entity_graph_walk_start - Start walking the media graph at a given entity + * @graph: Media graph structure that will be used to walk the graph + * @entity: Starting entity + * + * This function initializes the graph traversal structure to walk the entities + * graph starting at the given entity. The traversal structure must not be + * modified by the caller during graph traversal. When done the structure can + * safely be freed. + */ +void media_entity_graph_walk_start(struct media_entity_graph *graph, + struct media_entity *entity) +{ + graph->top = 0; + graph->stack[graph->top].entity = NULL; + stack_push(graph, entity); +} +EXPORT_SYMBOL_GPL(media_entity_graph_walk_start); + +/** + * media_entity_graph_walk_next - Get the next entity in the graph + * @graph: Media graph structure + * + * Perform a depth-first traversal of the given media entities graph. + * + * The graph structure must have been previously initialized with a call to + * media_entity_graph_walk_start(). + * + * Return the next entity in the graph or NULL if the whole graph have been + * traversed. + */ +struct media_entity * +media_entity_graph_walk_next(struct media_entity_graph *graph) +{ + if (stack_top(graph) == NULL) + return NULL; + + /* + * Depth first search. Push entity to stack and continue from + * top of the stack until no more entities on the level can be + * found. + */ + while (link_top(graph) < stack_top(graph)->num_links) { + struct media_entity *entity = stack_top(graph); + struct media_link *link = &entity->links[link_top(graph)]; + struct media_entity *next; + + /* The link is not enabled so we do not follow. */ + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { + link_top(graph)++; + continue; + } + + /* Get the entity in the other end of the link . */ + next = media_entity_other(entity, link); + + /* Was it the entity we came here from? */ + if (next == stack_peek(graph)) { + link_top(graph)++; + continue; + } + + /* Push the new entity to stack and start over. */ + link_top(graph)++; + stack_push(graph, next); + } + + return stack_pop(graph); +} +EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); + +/* ----------------------------------------------------------------------------- + * Links management + */ + static struct media_link *media_entity_add_link(struct media_entity *entity) { if (entity->num_links >= entity->max_links) { -- cgit v1.2.2 From 503c3d829eaf48837dd5bff5d97ad66369bb955a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 7 Mar 2010 15:04:59 -0300 Subject: [media] media: Entity use count Due to the wide differences between drivers regarding power management needs, the media controller does not implement power management. However, the media_entity structure includes a use_count field that media drivers can use to track the number of users of every entity for power management needs. The use_count field is owned by media drivers and must not be touched by entity drivers. Access to the field must be protected by the media device graph_mutex lock. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 1 + drivers/media/media-entity.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index a36509a1df09..d2bc809d7a2a 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -73,6 +73,7 @@ int __must_check media_device_register(struct media_device *mdev) mdev->entity_id = 1; INIT_LIST_HEAD(&mdev->entities); spin_lock_init(&mdev->lock); + mutex_init(&mdev->graph_mutex); /* Register the device node. */ mdev->devnode.fops = &media_device_fops; diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 166f2b5505ce..3e7e2d569cec 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -23,6 +23,7 @@ #include #include #include +#include /** * media_entity_init - Initialize a media entity @@ -195,6 +196,51 @@ media_entity_graph_walk_next(struct media_entity_graph *graph) } EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); +/* ----------------------------------------------------------------------------- + * Module use count + */ + +/* + * media_entity_get - Get a reference to the parent module + * @entity: The entity + * + * Get a reference to the parent media device module. + * + * The function will return immediately if @entity is NULL. + * + * Return a pointer to the entity on success or NULL on failure. + */ +struct media_entity *media_entity_get(struct media_entity *entity) +{ + if (entity == NULL) + return NULL; + + if (entity->parent->dev && + !try_module_get(entity->parent->dev->driver->owner)) + return NULL; + + return entity; +} +EXPORT_SYMBOL_GPL(media_entity_get); + +/* + * media_entity_put - Release the reference to the parent module + * @entity: The entity + * + * Release the reference count acquired by media_entity_get(). + * + * The function will return immediately if @entity is NULL. + */ +void media_entity_put(struct media_entity *entity) +{ + if (entity == NULL) + return; + + if (entity->parent->dev) + module_put(entity->parent->dev->driver->owner); +} +EXPORT_SYMBOL_GPL(media_entity_put); + /* ----------------------------------------------------------------------------- * Links management */ -- cgit v1.2.2 From 140d88165c25137e871f9559e67986ed89251105 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 18 Aug 2010 11:41:22 -0300 Subject: [media] media: Media device information query Create the following ioctl and implement it at the media device level to query device information. - MEDIA_IOC_DEVICE_INFO: Query media device information The ioctl and its data structure are defined in the new kernel header linux/media.h available to userspace applications. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 57 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'drivers') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index d2bc809d7a2a..92e0d4eb84b8 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -22,13 +22,70 @@ #include #include +#include #include #include #include +/* ----------------------------------------------------------------------------- + * Userspace API + */ + +static int media_device_open(struct file *filp) +{ + return 0; +} + +static int media_device_close(struct file *filp) +{ + return 0; +} + +static int media_device_get_info(struct media_device *dev, + struct media_device_info __user *__info) +{ + struct media_device_info info; + + memset(&info, 0, sizeof(info)); + + strlcpy(info.driver, dev->dev->driver->name, sizeof(info.driver)); + strlcpy(info.model, dev->model, sizeof(info.model)); + strlcpy(info.serial, dev->serial, sizeof(info.serial)); + strlcpy(info.bus_info, dev->bus_info, sizeof(info.bus_info)); + + info.media_version = MEDIA_API_VERSION; + info.hw_revision = dev->hw_revision; + info.driver_version = dev->driver_version; + + return copy_to_user(__info, &info, sizeof(*__info)); +} + +static long media_device_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *dev = to_media_device(devnode); + long ret; + + switch (cmd) { + case MEDIA_IOC_DEVICE_INFO: + ret = media_device_get_info(dev, + (struct media_device_info __user *)arg); + break; + + default: + ret = -ENOIOCTLCMD; + } + + return ret; +} + static const struct media_file_operations media_device_fops = { .owner = THIS_MODULE, + .open = media_device_open, + .ioctl = media_device_ioctl, + .release = media_device_close, }; /* ----------------------------------------------------------------------------- -- cgit v1.2.2 From 1651333b09743887bc2dd3d158a11853a2be3fe7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:40:01 -0300 Subject: [media] media: Entities, pads and links enumeration Create the following two ioctls and implement them at the media device level to enumerate entities, pads and links. - MEDIA_IOC_ENUM_ENTITIES: Enumerate entities and their properties - MEDIA_IOC_ENUM_LINKS: Enumerate all pads and links for a given entity Entity IDs can be non-contiguous. Userspace applications should enumerate entities using the MEDIA_ENT_ID_FLAG_NEXT flag. When the flag is set in the entity ID, the MEDIA_IOC_ENUM_ENTITIES will return the next entity with an ID bigger than the requested one. Only forward links that originate at one of the entity's source pads are returned during the enumeration process. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 123 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) (limited to 'drivers') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 92e0d4eb84b8..648a9d892ac1 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -61,6 +61,117 @@ static int media_device_get_info(struct media_device *dev, return copy_to_user(__info, &info, sizeof(*__info)); } +static struct media_entity *find_entity(struct media_device *mdev, u32 id) +{ + struct media_entity *entity; + int next = id & MEDIA_ENT_ID_FLAG_NEXT; + + id &= ~MEDIA_ENT_ID_FLAG_NEXT; + + spin_lock(&mdev->lock); + + media_device_for_each_entity(entity, mdev) { + if ((entity->id == id && !next) || + (entity->id > id && next)) { + spin_unlock(&mdev->lock); + return entity; + } + } + + spin_unlock(&mdev->lock); + + return NULL; +} + +static long media_device_enum_entities(struct media_device *mdev, + struct media_entity_desc __user *uent) +{ + struct media_entity *ent; + struct media_entity_desc u_ent; + + if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id))) + return -EFAULT; + + ent = find_entity(mdev, u_ent.id); + + if (ent == NULL) + return -EINVAL; + + u_ent.id = ent->id; + u_ent.name[0] = '\0'; + if (ent->name) + strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); + u_ent.type = ent->type; + u_ent.revision = ent->revision; + u_ent.flags = ent->flags; + u_ent.group_id = ent->group_id; + u_ent.pads = ent->num_pads; + u_ent.links = ent->num_links - ent->num_backlinks; + u_ent.v4l.major = ent->v4l.major; + u_ent.v4l.minor = ent->v4l.minor; + if (copy_to_user(uent, &u_ent, sizeof(u_ent))) + return -EFAULT; + return 0; +} + +static void media_device_kpad_to_upad(const struct media_pad *kpad, + struct media_pad_desc *upad) +{ + upad->entity = kpad->entity->id; + upad->index = kpad->index; + upad->flags = kpad->flags; +} + +static long media_device_enum_links(struct media_device *mdev, + struct media_links_enum __user *ulinks) +{ + struct media_entity *entity; + struct media_links_enum links; + + if (copy_from_user(&links, ulinks, sizeof(links))) + return -EFAULT; + + entity = find_entity(mdev, links.entity); + if (entity == NULL) + return -EINVAL; + + if (links.pads) { + unsigned int p; + + for (p = 0; p < entity->num_pads; p++) { + struct media_pad_desc pad; + media_device_kpad_to_upad(&entity->pads[p], &pad); + if (copy_to_user(&links.pads[p], &pad, sizeof(pad))) + return -EFAULT; + } + } + + if (links.links) { + struct media_link_desc __user *ulink; + unsigned int l; + + for (l = 0, ulink = links.links; l < entity->num_links; l++) { + struct media_link_desc link; + + /* Ignore backlinks. */ + if (entity->links[l].source->entity != entity) + continue; + + media_device_kpad_to_upad(entity->links[l].source, + &link.source); + media_device_kpad_to_upad(entity->links[l].sink, + &link.sink); + link.flags = entity->links[l].flags; + if (copy_to_user(ulink, &link, sizeof(*ulink))) + return -EFAULT; + ulink++; + } + } + if (copy_to_user(ulinks, &links, sizeof(*ulinks))) + return -EFAULT; + return 0; +} + static long media_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -74,6 +185,18 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, (struct media_device_info __user *)arg); break; + case MEDIA_IOC_ENUM_ENTITIES: + ret = media_device_enum_entities(dev, + (struct media_entity_desc __user *)arg); + break; + + case MEDIA_IOC_ENUM_LINKS: + mutex_lock(&dev->graph_mutex); + ret = media_device_enum_links(dev, + (struct media_links_enum __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + default: ret = -ENOIOCTLCMD; } -- cgit v1.2.2 From 97548ed4c4661502cdfd1aabd5d3876fa4f5cc2e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:40:03 -0300 Subject: [media] media: Links setup Create the following ioctl and implement it at the media device level to setup links. - MEDIA_IOC_SETUP_LINK: Modify the properties of a given link The only property that can currently be modified is the ENABLED link flag to enable/disable a link. Links marked with the IMMUTABLE link flag can not be enabled or disabled. Enabling or disabling a link has effects on entities' use count. Those changes are automatically propagated through the graph. Signed-off-by: Laurent Pinchart Signed-off-by: Stanimir Varbanov Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 45 +++++++++++++ drivers/media/media-entity.c | 155 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+) (limited to 'drivers') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 648a9d892ac1..16b70b4412f7 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -172,6 +172,44 @@ static long media_device_enum_links(struct media_device *mdev, return 0; } +static long media_device_setup_link(struct media_device *mdev, + struct media_link_desc __user *_ulink) +{ + struct media_link *link = NULL; + struct media_link_desc ulink; + struct media_entity *source; + struct media_entity *sink; + int ret; + + if (copy_from_user(&ulink, _ulink, sizeof(ulink))) + return -EFAULT; + + /* Find the source and sink entities and link. + */ + source = find_entity(mdev, ulink.source.entity); + sink = find_entity(mdev, ulink.sink.entity); + + if (source == NULL || sink == NULL) + return -EINVAL; + + if (ulink.source.index >= source->num_pads || + ulink.sink.index >= sink->num_pads) + return -EINVAL; + + link = media_entity_find_link(&source->pads[ulink.source.index], + &sink->pads[ulink.sink.index]); + if (link == NULL) + return -EINVAL; + + /* Setup the link on both entities. */ + ret = __media_entity_setup_link(link, ulink.flags); + + if (copy_to_user(_ulink, &ulink, sizeof(ulink))) + return -EFAULT; + + return ret; +} + static long media_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -197,6 +235,13 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, mutex_unlock(&dev->graph_mutex); break; + case MEDIA_IOC_SETUP_LINK: + mutex_lock(&dev->graph_mutex); + ret = media_device_setup_link(dev, + (struct media_link_desc __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + default: ret = -ENOIOCTLCMD; } diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 3e7e2d569cec..6795c920d460 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -306,3 +306,158 @@ media_entity_create_link(struct media_entity *source, u16 source_pad, return 0; } EXPORT_SYMBOL_GPL(media_entity_create_link); + +static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) +{ + const u32 mask = MEDIA_LNK_FL_ENABLED; + int ret; + + /* Notify both entities. */ + ret = media_entity_call(link->source->entity, link_setup, + link->source, link->sink, flags); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + + ret = media_entity_call(link->sink->entity, link_setup, + link->sink, link->source, flags); + if (ret < 0 && ret != -ENOIOCTLCMD) { + media_entity_call(link->source->entity, link_setup, + link->source, link->sink, link->flags); + return ret; + } + + link->flags = (link->flags & ~mask) | (flags & mask); + link->reverse->flags = link->flags; + + return 0; +} + +/** + * __media_entity_setup_link - Configure a media link + * @link: The link being configured + * @flags: Link configuration flags + * + * The bulk of link setup is handled by the two entities connected through the + * link. This function notifies both entities of the link configuration change. + * + * If the link is immutable or if the current and new configuration are + * identical, return immediately. + * + * The user is expected to hold link->source->parent->mutex. If not, + * media_entity_setup_link() should be used instead. + */ +int __media_entity_setup_link(struct media_link *link, u32 flags) +{ + struct media_device *mdev; + struct media_entity *source, *sink; + int ret = -EBUSY; + + if (link == NULL) + return -EINVAL; + + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) + return link->flags == flags ? 0 : -EINVAL; + + if (link->flags == flags) + return 0; + + source = link->source->entity; + sink = link->sink->entity; + + mdev = source->parent; + + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { + ret = mdev->link_notify(link->source, link->sink, + MEDIA_LNK_FL_ENABLED); + if (ret < 0) + return ret; + } + + ret = __media_entity_setup_link_notify(link, flags); + if (ret < 0) + goto err; + + if (!(flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) + mdev->link_notify(link->source, link->sink, 0); + + return 0; + +err: + if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) + mdev->link_notify(link->source, link->sink, 0); + + return ret; +} + +int media_entity_setup_link(struct media_link *link, u32 flags) +{ + int ret; + + mutex_lock(&link->source->entity->parent->graph_mutex); + ret = __media_entity_setup_link(link, flags); + mutex_unlock(&link->source->entity->parent->graph_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(media_entity_setup_link); + +/** + * media_entity_find_link - Find a link between two pads + * @source: Source pad + * @sink: Sink pad + * + * Return a pointer to the link between the two entities. If no such link + * exists, return NULL. + */ +struct media_link * +media_entity_find_link(struct media_pad *source, struct media_pad *sink) +{ + struct media_link *link; + unsigned int i; + + for (i = 0; i < source->entity->num_links; ++i) { + link = &source->entity->links[i]; + + if (link->source->entity == source->entity && + link->source->index == source->index && + link->sink->entity == sink->entity && + link->sink->index == sink->index) + return link; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(media_entity_find_link); + +/** + * media_entity_remote_source - Find the source pad at the remote end of a link + * @pad: Sink pad at the local end of the link + * + * Search for a remote source pad connected to the given sink pad by iterating + * over all links originating or terminating at that pad until an enabled link + * is found. + * + * Return a pointer to the pad at the remote end of the first found enabled + * link, or NULL if no enabled link has been found. + */ +struct media_pad *media_entity_remote_source(struct media_pad *pad) +{ + unsigned int i; + + for (i = 0; i < pad->entity->num_links; i++) { + struct media_link *link = &pad->entity->links[i]; + + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + if (link->source == pad) + return link->sink; + + if (link->sink == pad) + return link->source; + } + + return NULL; + +} +EXPORT_SYMBOL_GPL(media_entity_remote_source); -- cgit v1.2.2 From e02188c90f6ef61f0844c42508fe603c5d4fa42b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 25 Aug 2010 09:00:41 -0300 Subject: [media] media: Pipelines and media streams Drivers often need to associate pipeline objects to entities, and to take stream state into account when configuring entities and links. The pipeline API helps drivers manage that information. When starting streaming, drivers call media_entity_pipeline_start(). The function marks all entities connected to the given entity through enabled links, either directly or indirectly, as streaming. Similarly, when stopping the stream, drivers call media_entity_pipeline_stop(). The media_entity_pipeline_start() function takes a pointer to a media pipeline and stores it in every entity in the graph. Drivers should embed the media_pipeline structure in higher-level pipeline structures and can then access the pipeline through the media_entity structure. Link configuration will fail with -EBUSY by default if either end of the link is a streaming entity, unless the link is marked with the MEDIA_LNK_FL_DYNAMIC flag. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-entity.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'drivers') diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 6795c920d460..23640ed44d85 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -196,6 +196,75 @@ media_entity_graph_walk_next(struct media_entity_graph *graph) } EXPORT_SYMBOL_GPL(media_entity_graph_walk_next); +/* ----------------------------------------------------------------------------- + * Pipeline management + */ + +/** + * media_entity_pipeline_start - Mark a pipeline as streaming + * @entity: Starting entity + * @pipe: Media pipeline to be assigned to all entities in the pipeline. + * + * Mark all entities connected to a given entity through enabled links, either + * directly or indirectly, as streaming. The given pipeline object is assigned to + * every entity in the pipeline and stored in the media_entity pipe field. + * + * Calls to this function can be nested, in which case the same number of + * media_entity_pipeline_stop() calls will be required to stop streaming. The + * pipeline pointer must be identical for all nested calls to + * media_entity_pipeline_start(). + */ +void media_entity_pipeline_start(struct media_entity *entity, + struct media_pipeline *pipe) +{ + struct media_device *mdev = entity->parent; + struct media_entity_graph graph; + + mutex_lock(&mdev->graph_mutex); + + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + entity->stream_count++; + WARN_ON(entity->pipe && entity->pipe != pipe); + entity->pipe = pipe; + } + + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_entity_pipeline_start); + +/** + * media_entity_pipeline_stop - Mark a pipeline as not streaming + * @entity: Starting entity + * + * Mark all entities connected to a given entity through enabled links, either + * directly or indirectly, as not streaming. The media_entity pipe field is + * reset to NULL. + * + * If multiple calls to media_entity_pipeline_start() have been made, the same + * number of calls to this function are required to mark the pipeline as not + * streaming. + */ +void media_entity_pipeline_stop(struct media_entity *entity) +{ + struct media_device *mdev = entity->parent; + struct media_entity_graph graph; + + mutex_lock(&mdev->graph_mutex); + + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + entity->stream_count--; + if (entity->stream_count == 0) + entity->pipe = NULL; + } + + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_entity_pipeline_stop); + /* ----------------------------------------------------------------------------- * Module use count */ @@ -364,6 +433,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) source = link->source->entity; sink = link->sink->entity; + if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) && + (source->stream_count || sink->stream_count)) + return -EBUSY; + mdev = source->parent; if ((flags & MEDIA_LNK_FL_ENABLED) && mdev->link_notify) { -- cgit v1.2.2 From 95db3a60e0652a52df145aacade1a88c5acef659 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:40:05 -0300 Subject: [media] v4l: Add a media_device pointer to the v4l2_device structure The pointer will later be used to register/unregister media entities when registering/unregistering a v4l2_subdev or a video_device. With the introduction of media devices, device drivers need to store a pointer to a driver-specific structure in the device's drvdata. v4l2_device can't claim ownership of the drvdata anymore. To maintain compatibility with drivers that rely on v4l2_device storing a pointer to itself in the device's drvdata, v4l2_device_register() will keep doing so if the drvdata is NULL. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-device.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index 8c0ad8b372d8..cfbd8a38991d 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -47,9 +47,8 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) if (!v4l2_dev->name[0]) snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s %s", dev->driver->name, dev_name(dev)); - if (dev_get_drvdata(dev)) - v4l2_warn(v4l2_dev, "Non-NULL drvdata on register\n"); - dev_set_drvdata(dev, v4l2_dev); + if (!dev_get_drvdata(dev)) + dev_set_drvdata(dev, v4l2_dev); return 0; } EXPORT_SYMBOL_GPL(v4l2_device_register); @@ -72,10 +71,12 @@ EXPORT_SYMBOL_GPL(v4l2_device_set_name); void v4l2_device_disconnect(struct v4l2_device *v4l2_dev) { - if (v4l2_dev->dev) { + if (v4l2_dev->dev == NULL) + return; + + if (dev_get_drvdata(v4l2_dev->dev) == v4l2_dev) dev_set_drvdata(v4l2_dev->dev, NULL); - v4l2_dev->dev = NULL; - } + v4l2_dev->dev = NULL; } EXPORT_SYMBOL_GPL(v4l2_device_disconnect); -- cgit v1.2.2 From 2c0ab67be1b4197a4effac89bb0604832e38be8d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:40:10 -0300 Subject: [media] v4l: Make video_device inherit from media_entity V4L2 devices are media entities. As such they need to inherit from (include) the media_entity structure. When registering/unregistering the device, the media entity is automatically registered/unregistered. The entity is acquired on device open and released on device close. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-dev.c | 49 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index abe04ef38066..e405b8094b94 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -303,6 +303,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) static int v4l2_open(struct inode *inode, struct file *filp) { struct video_device *vdev; +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_entity *entity = NULL; +#endif int ret = 0; /* Check if the video device is available */ @@ -316,6 +319,16 @@ static int v4l2_open(struct inode *inode, struct file *filp) /* and increase the device refcount */ video_get(vdev); mutex_unlock(&videodev_lock); +#if defined(CONFIG_MEDIA_CONTROLLER) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + entity = media_entity_get(&vdev->entity); + if (!entity) { + ret = -EBUSY; + video_put(vdev); + return ret; + } + } +#endif if (vdev->fops->open) { if (vdev->lock && mutex_lock_interruptible(vdev->lock)) { ret = -ERESTARTSYS; @@ -331,8 +344,13 @@ static int v4l2_open(struct inode *inode, struct file *filp) err: /* decrease the refcount in case of an error */ - if (ret) + if (ret) { +#if defined(CONFIG_MEDIA_CONTROLLER) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + media_entity_put(entity); +#endif video_put(vdev); + } return ret; } @@ -349,7 +367,10 @@ static int v4l2_release(struct inode *inode, struct file *filp) if (vdev->lock) mutex_unlock(vdev->lock); } - +#if defined(CONFIG_MEDIA_CONTROLLER) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + media_entity_put(&vdev->entity); +#endif /* decrease the refcount unconditionally since the release() return value is ignored. */ video_put(vdev); @@ -585,12 +606,27 @@ int __video_register_device(struct video_device *vdev, int type, int nr, if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, name_base, nr, video_device_node_name(vdev)); - - /* Part 5: Activate this minor. The char device can now be used. */ +#if defined(CONFIG_MEDIA_CONTROLLER) + /* Part 5: Register the entity. */ + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; + vdev->entity.name = vdev->name; + vdev->entity.v4l.major = VIDEO_MAJOR; + vdev->entity.v4l.minor = vdev->minor; + ret = media_device_register_entity(vdev->v4l2_dev->mdev, + &vdev->entity); + if (ret < 0) + printk(KERN_WARNING + "%s: media_device_register_entity failed\n", + __func__); + } +#endif + /* Part 6: Activate this minor. The char device can now be used. */ set_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_lock(&videodev_lock); video_device[vdev->minor] = vdev; mutex_unlock(&videodev_lock); + return 0; cleanup: @@ -618,6 +654,11 @@ void video_unregister_device(struct video_device *vdev) if (!vdev || !video_is_registered(vdev)) return; +#if defined(CONFIG_MEDIA_CONTROLLER) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + media_device_unregister_entity(&vdev->entity); +#endif + 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. -- cgit v1.2.2 From 61f5db549dde43fb91a8b337f3a4096e4076c2d9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:40:08 -0300 Subject: [media] v4l: Make v4l2_subdev inherit from media_entity V4L2 subdevices are media entities. As such they need to inherit from (include) the media_entity structure. When registering/unregistering the subdevice, the media entity is automatically registered/unregistered. The entity is acquired on device open and released on device close. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-device.c | 36 ++++++++++++++++++++++++++++++++---- drivers/media/video/v4l2-subdev.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index cfbd8a38991d..a1afda352d08 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -118,8 +118,11 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev) EXPORT_SYMBOL_GPL(v4l2_device_unregister); int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, - struct v4l2_subdev *sd) + struct v4l2_subdev *sd) { +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_entity *entity = &sd->entity; +#endif int err; /* Check for valid input */ @@ -147,6 +150,19 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, return err; } +#if defined(CONFIG_MEDIA_CONTROLLER) + /* Register the entity. */ + if (v4l2_dev->mdev) { + err = media_device_register_entity(v4l2_dev->mdev, entity); + if (err < 0) { + if (sd->internal_ops && sd->internal_ops->unregistered) + sd->internal_ops->unregistered(sd); + module_put(sd->owner); + return err; + } + } +#endif + spin_lock(&v4l2_dev->lock); list_add_tail(&sd->list, &v4l2_dev->subdevs); spin_unlock(&v4l2_dev->lock); @@ -177,25 +193,37 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) sd->owner); if (err < 0) return err; +#if defined(CONFIG_MEDIA_CONTROLLER) + sd->entity.v4l.major = VIDEO_MAJOR; + sd->entity.v4l.minor = vdev->minor; +#endif } - return 0; } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) { + struct v4l2_device *v4l2_dev; + /* return if it isn't registered */ if (sd == NULL || sd->v4l2_dev == NULL) return; - spin_lock(&sd->v4l2_dev->lock); + v4l2_dev = sd->v4l2_dev; + + spin_lock(&v4l2_dev->lock); list_del(&sd->list); - spin_unlock(&sd->v4l2_dev->lock); + spin_unlock(&v4l2_dev->lock); + if (sd->internal_ops && sd->internal_ops->unregistered) sd->internal_ops->unregistered(sd); sd->v4l2_dev = NULL; +#if defined(CONFIG_MEDIA_CONTROLLER) + if (v4l2_dev->mdev) + media_device_unregister_entity(&sd->entity); +#endif video_unregister_device(&sd->devnode); module_put(sd->owner); } diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 0c67f5a278fb..85573638aa1e 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -35,7 +35,10 @@ static int subdev_open(struct file *file) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh; +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_entity *entity; +#endif + struct v4l2_fh *vfh = NULL; int ret; if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { @@ -58,11 +61,20 @@ static int subdev_open(struct file *file) v4l2_fh_add(vfh); file->private_data = vfh; } - +#if defined(CONFIG_MEDIA_CONTROLLER) + if (sd->v4l2_dev->mdev) { + entity = media_entity_get(&sd->entity); + if (!entity) { + ret = -EBUSY; + goto err; + } + } +#endif return 0; err: if (vfh != NULL) { + v4l2_fh_del(vfh); v4l2_fh_exit(vfh); kfree(vfh); } @@ -72,8 +84,16 @@ err: static int subdev_close(struct file *file) { +#if defined(CONFIG_MEDIA_CONTROLLER) + struct video_device *vdev = video_devdata(file); + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); +#endif struct v4l2_fh *vfh = file->private_data; +#if defined(CONFIG_MEDIA_CONTROLLER) + if (sd->v4l2_dev->mdev) + media_entity_put(&sd->entity); +#endif if (vfh != NULL) { v4l2_fh_del(vfh); v4l2_fh_exit(vfh); @@ -172,5 +192,9 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) sd->grp_id = 0; sd->dev_priv = NULL; sd->host_priv = NULL; +#if defined(CONFIG_MEDIA_CONTROLLER) + sd->entity.name = sd->name; + sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; +#endif } EXPORT_SYMBOL(v4l2_subdev_init); -- cgit v1.2.2 From 076704332ca6da550cbc279918ef8b88b4ac1e45 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 28 Sep 2010 07:01:44 -0300 Subject: [media] v4l: Rename V4L2_MBUS_FMT_GREY8_1X8 to V4L2_MBUS_FMT_Y8_1X8 For consistency with the V4L2_MBUS_FMT_Y10_1X10 format. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mt9m001.c | 2 +- drivers/media/video/mt9v022.c | 4 ++-- drivers/media/video/ov6650.c | 10 +++++----- drivers/media/video/sh_mobile_csi2.c | 6 +++--- drivers/media/video/soc_mediabus.c | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index f7fc88d240e6..e2bbd8c35c98 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -79,7 +79,7 @@ static const struct mt9m001_datafmt mt9m001_colour_fmts[] = { static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { /* Order important - see above */ {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, }; struct mt9m001 { diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 6a784c87e5ff..e313d8390092 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -95,7 +95,7 @@ static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { /* Order important - see above */ {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, - {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG}, }; struct mt9v022 { @@ -392,7 +392,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, * icd->try_fmt(), datawidth is from our supported format list */ switch (mf->code) { - case V4L2_MBUS_FMT_GREY8_1X8: + case V4L2_MBUS_FMT_Y8_1X8: case V4L2_MBUS_FMT_Y10_1X10: if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) return -EINVAL; diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index cf93de988068..fe8e3ebd9ce4 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -207,7 +207,7 @@ static enum v4l2_mbus_pixelcode ov6650_codes[] = { V4L2_MBUS_FMT_YVYU8_2X8, V4L2_MBUS_FMT_VYUY8_2X8, V4L2_MBUS_FMT_SBGGR8_1X8, - V4L2_MBUS_FMT_GREY8_1X8, + V4L2_MBUS_FMT_Y8_1X8, }; static const struct v4l2_queryctrl ov6650_controls[] = { @@ -800,7 +800,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) /* select color matrix configuration for given color encoding */ switch (code) { - case V4L2_MBUS_FMT_GREY8_1X8: + case V4L2_MBUS_FMT_Y8_1X8: dev_dbg(&client->dev, "pixel format GREY8_1X8\n"); coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP; coma_set |= COMA_BW; @@ -846,7 +846,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) } priv->code = code; - if (code == V4L2_MBUS_FMT_GREY8_1X8 || + if (code == V4L2_MBUS_FMT_Y8_1X8 || code == V4L2_MBUS_FMT_SBGGR8_1X8) { coml_mask = COML_ONE_CHANNEL; coml_set = 0; @@ -936,8 +936,8 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd, switch (mf->code) { case V4L2_MBUS_FMT_Y10_1X10: - mf->code = V4L2_MBUS_FMT_GREY8_1X8; - case V4L2_MBUS_FMT_GREY8_1X8: + mf->code = V4L2_MBUS_FMT_Y8_1X8; + case V4L2_MBUS_FMT_Y8_1X8: case V4L2_MBUS_FMT_YVYU8_2X8: case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_VYUY8_2X8: diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 84a646819318..dd1b81b1442b 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -56,7 +56,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd, switch (mf->code) { case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */ case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */ - case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */ + case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ case V4L2_MBUS_FMT_SBGGR8_1X8: case V4L2_MBUS_FMT_SGRBG8_1X8: break; @@ -67,7 +67,7 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd, break; case SH_CSI2I: switch (mf->code) { - case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */ + case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */ case V4L2_MBUS_FMT_SBGGR8_1X8: case V4L2_MBUS_FMT_SGRBG8_1X8: case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */ @@ -111,7 +111,7 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd, case V4L2_MBUS_FMT_RGB565_2X8_BE: tmp |= 0x22; /* RGB565 */ break; - case V4L2_MBUS_FMT_GREY8_1X8: + case V4L2_MBUS_FMT_Y8_1X8: case V4L2_MBUS_FMT_SBGGR8_1X8: case V4L2_MBUS_FMT_SGRBG8_1X8: tmp |= 0x2a; /* RAW8 */ diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c index 73b4138709e4..ed77aa055b63 100644 --- a/drivers/media/video/soc_mediabus.c +++ b/drivers/media/video/soc_mediabus.c @@ -88,7 +88,7 @@ static const struct soc_mbus_pixelfmt mbus_fmt[] = { .packing = SOC_MBUS_PACKING_EXTEND16, .order = SOC_MBUS_ORDER_LE, }, - [MBUS_IDX(GREY8_1X8)] = { + [MBUS_IDX(Y8_1X8)] = { .fourcc = V4L2_PIX_FMT_GREY, .name = "Grey", .bits_per_sample = 8, -- cgit v1.2.2 From 7cd5a16b22af7dc92190a60f336b6854a6fcb99d Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 21 May 2010 06:04:24 -0300 Subject: [media] v4l: Create v4l2 subdev file handle structure Used for storing subdev information per file handle and hold V4L2 file handle. Signed-off-by: Stanimir Varbanov Signed-off-by: Antti Koskipaa Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 9 +++++ drivers/media/video/v4l2-subdev.c | 85 ++++++++++++++++++++++++++------------- 2 files changed, 67 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 2466f2b2ecfa..6995940b633a 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -53,6 +53,15 @@ config VIDEO_V4L2_COMMON depends on (I2C || I2C=n) && VIDEO_DEV default (I2C || I2C=n) && VIDEO_DEV +config VIDEO_V4L2_SUBDEV_API + bool "V4L2 sub-device userspace API (EXPERIMENTAL)" + depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL + ---help--- + Enables the V4L2 sub-device pad-level userspace API used to configure + video format, size and frame rate between hardware blocks. + + This API is mostly used by camera interfaces in embedded platforms. + # # DVB Core # diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 85573638aa1e..6cef6ad3c9ce 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -31,36 +31,66 @@ #include #include +static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) +{ +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + /* Allocate try format and crop in the same memory block */ + fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)) + * sd->entity.num_pads, GFP_KERNEL); + if (fh->try_fmt == NULL) + return -ENOMEM; + + fh->try_crop = (struct v4l2_rect *) + (fh->try_fmt + sd->entity.num_pads); +#endif + return 0; +} + +static void subdev_fh_free(struct v4l2_subdev_fh *fh) +{ +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + kfree(fh->try_fmt); + fh->try_fmt = NULL; + fh->try_crop = NULL; +#endif +} + static int subdev_open(struct file *file) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_subdev_fh *subdev_fh; #if defined(CONFIG_MEDIA_CONTROLLER) struct media_entity *entity; #endif - struct v4l2_fh *vfh = NULL; int ret; - if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { - vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); - if (vfh == NULL) - return -ENOMEM; + subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL); + if (subdev_fh == NULL) + return -ENOMEM; - ret = v4l2_fh_init(vfh, vdev); - if (ret) - goto err; + ret = subdev_fh_init(subdev_fh, sd); + if (ret) { + kfree(subdev_fh); + return ret; + } + + ret = v4l2_fh_init(&subdev_fh->vfh, vdev); + if (ret) + goto err; - ret = v4l2_event_init(vfh); + if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) { + ret = v4l2_event_init(&subdev_fh->vfh); if (ret) goto err; - ret = v4l2_event_alloc(vfh, sd->nevents); + ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents); if (ret) goto err; - - v4l2_fh_add(vfh); - file->private_data = vfh; } + + v4l2_fh_add(&subdev_fh->vfh); + file->private_data = &subdev_fh->vfh; #if defined(CONFIG_MEDIA_CONTROLLER) if (sd->v4l2_dev->mdev) { entity = media_entity_get(&sd->entity); @@ -70,14 +100,14 @@ static int subdev_open(struct file *file) } } #endif + return 0; err: - if (vfh != NULL) { - v4l2_fh_del(vfh); - v4l2_fh_exit(vfh); - kfree(vfh); - } + v4l2_fh_del(&subdev_fh->vfh); + v4l2_fh_exit(&subdev_fh->vfh); + subdev_fh_free(subdev_fh); + kfree(subdev_fh); return ret; } @@ -89,16 +119,17 @@ static int subdev_close(struct file *file) struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); #endif struct v4l2_fh *vfh = file->private_data; + struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); #if defined(CONFIG_MEDIA_CONTROLLER) if (sd->v4l2_dev->mdev) media_entity_put(&sd->entity); #endif - if (vfh != NULL) { - v4l2_fh_del(vfh); - v4l2_fh_exit(vfh); - kfree(vfh); - } + v4l2_fh_del(vfh); + v4l2_fh_exit(vfh); + subdev_fh_free(subdev_fh); + kfree(subdev_fh); + file->private_data = NULL; return 0; } @@ -107,7 +138,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *vfh = file->private_data; switch (cmd) { case VIDIOC_QUERYCTRL: @@ -135,13 +166,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) return -ENOIOCTLCMD; - return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); case VIDIOC_SUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, subscribe_event, fh, arg); + return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg); case VIDIOC_UNSUBSCRIBE_EVENT: - return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg); + return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); default: return -ENOIOCTLCMD; -- cgit v1.2.2 From f0beea8f46142ea7abd7ed3f44fd0967c603fae0 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 1 Aug 2010 19:05:09 -0300 Subject: [media] v4l: subdev: Add new file operations V4L2 sub-devices store pad formats and crop settings in the file handle. To let drivers initialize those settings properly, add an open operation that is called when the subdev is opened as well as a corresponding close operation. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 6cef6ad3c9ce..bc763db385df 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -61,7 +61,7 @@ static int subdev_open(struct file *file) struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_subdev_fh *subdev_fh; #if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity; + struct media_entity *entity = NULL; #endif int ret; @@ -101,9 +101,19 @@ static int subdev_open(struct file *file) } #endif + if (sd->internal_ops && sd->internal_ops->open) { + ret = sd->internal_ops->open(sd, subdev_fh); + if (ret < 0) + goto err; + } + return 0; err: +#if defined(CONFIG_MEDIA_CONTROLLER) + if (entity) + media_entity_put(entity); +#endif v4l2_fh_del(&subdev_fh->vfh); v4l2_fh_exit(&subdev_fh->vfh); subdev_fh_free(subdev_fh); @@ -114,13 +124,13 @@ err: static int subdev_close(struct file *file) { -#if defined(CONFIG_MEDIA_CONTROLLER) struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); -#endif struct v4l2_fh *vfh = file->private_data; struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); + if (sd->internal_ops && sd->internal_ops->close) + sd->internal_ops->close(sd, subdev_fh); #if defined(CONFIG_MEDIA_CONTROLLER) if (sd->v4l2_dev->mdev) media_entity_put(&sd->entity); -- cgit v1.2.2 From 333c8b97785d5afd5085ba3720b4d259623290f6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 15 Mar 2010 20:26:04 -0300 Subject: [media] v4l: v4l2_subdev userspace format API Add a userspace API to get, set and enumerate the media format on a subdev pad. The format at the output of a subdev usually depends on the format at its input(s). The try format operation is thus not suitable for probing format at individual pads, as it can't modify the device state and thus can't remember the format tried at the input to compute the output format. To fix the problem, pass an extra argument to the get/set format operations to select the 'try' or 'active' format. The try format is used when probing the subdev. Setting the try format must not change the device configuration but can store data for later reuse. Data storage is provided at the file-handle level so applications probing the subdev concurently won't interfere with each other. The active format is used when configuring the subdev. It's identical to the format handled by the usual get/set operations. Signed-off-by: Laurent Pinchart Signed-off-by: Stanimir Varbanov Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index bc763db385df..207cc5cceb29 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -149,6 +149,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_fh *vfh = file->private_data; +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); +#endif switch (cmd) { case VIDIOC_QUERYCTRL: @@ -183,7 +186,53 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_UNSUBSCRIBE_EVENT: return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg); +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + case VIDIOC_SUBDEV_G_FMT: { + struct v4l2_subdev_format *format = arg; + + if (format->which != V4L2_SUBDEV_FORMAT_TRY && + format->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + if (format->pad >= sd->entity.num_pads) + return -EINVAL; + + return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh, format); + } + + case VIDIOC_SUBDEV_S_FMT: { + struct v4l2_subdev_format *format = arg; + + if (format->which != V4L2_SUBDEV_FORMAT_TRY && + format->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + if (format->pad >= sd->entity.num_pads) + return -EINVAL; + return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); + } + + case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { + struct v4l2_subdev_mbus_code_enum *code = arg; + + if (code->pad >= sd->entity.num_pads) + return -EINVAL; + + return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh, + code); + } + + case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { + struct v4l2_subdev_frame_size_enum *fse = arg; + + if (fse->pad >= sd->entity.num_pads) + return -EINVAL; + + return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, + fse); + } +#endif default: return -ENOIOCTLCMD; } -- cgit v1.2.2 From 35c3017a29d278c4405a7f3ab30b814999d156d3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 5 May 2010 11:38:35 -0300 Subject: [media] v4l: v4l2_subdev userspace frame interval API The three new ioctl VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, VIDIOC_SUBDEV_G_FRAME_INTERVAL and VIDIOC_SUBDEV_S_FRAME_INTERVAL can be used to enumerate and configure a subdev's frame rate from userspace. Two new video::g/s_frame_interval subdev operations are introduced to support those ioctls. The existing video::g/s_parm operations are deprecated and shouldn't be used anymore. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 207cc5cceb29..a4a12563ec3c 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -232,6 +232,22 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh, fse); } + + case VIDIOC_SUBDEV_G_FRAME_INTERVAL: + return v4l2_subdev_call(sd, video, g_frame_interval, arg); + + case VIDIOC_SUBDEV_S_FRAME_INTERVAL: + return v4l2_subdev_call(sd, video, s_frame_interval, arg); + + case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { + struct v4l2_subdev_frame_interval_enum *fie = arg; + + if (fie->pad >= sd->entity.num_pads) + return -EINVAL; + + return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, + fie); + } #endif default: return -ENOIOCTLCMD; -- cgit v1.2.2 From f6a5cb1be894468cdc69ec557d47f40c28f64642 Mon Sep 17 00:00:00 2001 From: Antti Koskipaa Date: Wed, 23 Jun 2010 05:03:42 -0300 Subject: [media] v4l: v4l2_subdev userspace crop API This patch adds the VIDIOC_SUBDEV_S_CROP and G_CROP ioctls to the userland API. CROPCAP is not implemented because it's redundant. Signed-off-by: Antti Koskipaa Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index a4a12563ec3c..6e76f734c780 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -213,6 +213,32 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh, format); } + case VIDIOC_SUBDEV_G_CROP: { + struct v4l2_subdev_crop *crop = arg; + + if (crop->which != V4L2_SUBDEV_FORMAT_TRY && + crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + if (crop->pad >= sd->entity.num_pads) + return -EINVAL; + + return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); + } + + case VIDIOC_SUBDEV_S_CROP: { + struct v4l2_subdev_crop *crop = arg; + + if (crop->which != V4L2_SUBDEV_FORMAT_TRY && + crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + if (crop->pad >= sd->entity.num_pads) + return -EINVAL; + + return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); + } + case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; -- cgit v1.2.2 From c30b46e58b31a0fc420049e21117444862fc7cb7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 26 Feb 2010 12:23:10 -0300 Subject: [media] v4l: subdev: Generic ioctl support Instead of returning an error when receiving an ioctl call with an unsupported command, forward the call to the subdev core::ioctl handler. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-subdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c index 6e76f734c780..0b8064490676 100644 --- a/drivers/media/video/v4l2-subdev.c +++ b/drivers/media/video/v4l2-subdev.c @@ -276,7 +276,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) } #endif default: - return -ENOIOCTLCMD; + return v4l2_subdev_call(sd, core, ioctl, cmd, arg); } return 0; -- cgit v1.2.2 From 448de7e7850b804bc8f5efa60305a83333c257bf Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sat, 12 Feb 2011 18:05:06 -0300 Subject: [media] omap3isp: OMAP3 ISP core The Image Signal Processor provides the system interface and the processing capability to connect RAW or YUV image-sensor modules to the OMAP3. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: David Cohen Signed-off-by: Stanimir Varbanov Signed-off-by: Vimarsh Zutshi Signed-off-by: Tuukka Toivonen Signed-off-by: Sergio Aguirre Signed-off-by: Antti Koskipaa Signed-off-by: Ivan T. Ivanov Signed-off-by: RaniSuneela Signed-off-by: Atanas Filipov Signed-off-by: Gjorgji Rosikopulos Signed-off-by: Hiroshi DOYU Signed-off-by: Nayden Kanchev Signed-off-by: Phil Carmody Signed-off-by: Artem Bityutskiy Signed-off-by: Dominic Curran Signed-off-by: Ilkka Myllyperkio Signed-off-by: Pallavi Kulkarni Signed-off-by: Vaibhav Hiremath Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 2220 +++++++++++++++++++++++++++++++++ drivers/media/video/omap3isp/isp.h | 430 +++++++ drivers/media/video/omap3isp/ispreg.h | 1589 +++++++++++++++++++++++ 3 files changed, 4239 insertions(+) create mode 100644 drivers/media/video/omap3isp/isp.c create mode 100644 drivers/media/video/omap3isp/isp.h create mode 100644 drivers/media/video/omap3isp/ispreg.h (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c new file mode 100644 index 000000000000..1a9963bd6d40 --- /dev/null +++ b/drivers/media/video/omap3isp/isp.c @@ -0,0 +1,2220 @@ +/* + * isp.c + * + * TI OMAP3 ISP - Core + * + * Copyright (C) 2006-2010 Nokia Corporation + * Copyright (C) 2007-2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * Contributors: + * Laurent Pinchart + * Sakari Ailus + * David Cohen + * Stanimir Varbanov + * Vimarsh Zutshi + * Tuukka Toivonen + * Sergio Aguirre + * Antti Koskipaa + * Ivan T. Ivanov + * RaniSuneela + * Atanas Filipov + * Gjorgji Rosikopulos + * Hiroshi DOYU + * Nayden Kanchev + * Phil Carmody + * Artem Bityutskiy + * Dominic Curran + * Ilkka Myllyperkio + * Pallavi Kulkarni + * Vaibhav Hiremath + * Mohit Jalori + * Sameer Venkatraman + * Senthilvadivu Guruswamy + * Thara Gopinath + * Toni Leinonen + * Troy Laramy + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "ispccdc.h" +#include "isppreview.h" +#include "ispresizer.h" +#include "ispcsi2.h" +#include "ispccp2.h" +#include "isph3a.h" +#include "isphist.h" + +static unsigned int autoidle; +module_param(autoidle, int, 0444); +MODULE_PARM_DESC(autoidle, "Enable OMAP3ISP AUTOIDLE support"); + +static void isp_save_ctx(struct isp_device *isp); + +static void isp_restore_ctx(struct isp_device *isp); + +static const struct isp_res_mapping isp_res_maps[] = { + { + .isp_rev = ISP_REVISION_2_0, + .map = 1 << OMAP3_ISP_IOMEM_MAIN | + 1 << OMAP3_ISP_IOMEM_CCP2 | + 1 << OMAP3_ISP_IOMEM_CCDC | + 1 << OMAP3_ISP_IOMEM_HIST | + 1 << OMAP3_ISP_IOMEM_H3A | + 1 << OMAP3_ISP_IOMEM_PREV | + 1 << OMAP3_ISP_IOMEM_RESZ | + 1 << OMAP3_ISP_IOMEM_SBL | + 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | + 1 << OMAP3_ISP_IOMEM_CSIPHY2, + }, + { + .isp_rev = ISP_REVISION_15_0, + .map = 1 << OMAP3_ISP_IOMEM_MAIN | + 1 << OMAP3_ISP_IOMEM_CCP2 | + 1 << OMAP3_ISP_IOMEM_CCDC | + 1 << OMAP3_ISP_IOMEM_HIST | + 1 << OMAP3_ISP_IOMEM_H3A | + 1 << OMAP3_ISP_IOMEM_PREV | + 1 << OMAP3_ISP_IOMEM_RESZ | + 1 << OMAP3_ISP_IOMEM_SBL | + 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | + 1 << OMAP3_ISP_IOMEM_CSIPHY2 | + 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 | + 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 | + 1 << OMAP3_ISP_IOMEM_CSIPHY1 | + 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2, + }, +}; + +/* Structure for saving/restoring ISP module registers */ +static struct isp_reg isp_reg_list[] = { + {OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0}, + {OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, 0}, + {OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, 0}, + {0, ISP_TOK_TERM, 0} +}; + +/* + * omap3isp_flush - Post pending L3 bus writes by doing a register readback + * @isp: OMAP3 ISP device + * + * In order to force posting of pending writes, we need to write and + * readback the same register, in this case the revision register. + * + * See this link for reference: + * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html + */ +void omap3isp_flush(struct isp_device *isp) +{ + isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); + isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); +} + +/* + * isp_enable_interrupts - Enable ISP interrupts. + * @isp: OMAP3 ISP device + */ +static void isp_enable_interrupts(struct isp_device *isp) +{ + static const u32 irq = IRQ0ENABLE_CSIA_IRQ + | IRQ0ENABLE_CSIB_IRQ + | IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ + | IRQ0ENABLE_CCDC_LSC_DONE_IRQ + | IRQ0ENABLE_CCDC_VD0_IRQ + | IRQ0ENABLE_CCDC_VD1_IRQ + | IRQ0ENABLE_HS_VS_IRQ + | IRQ0ENABLE_HIST_DONE_IRQ + | IRQ0ENABLE_H3A_AWB_DONE_IRQ + | IRQ0ENABLE_H3A_AF_DONE_IRQ + | IRQ0ENABLE_PRV_DONE_IRQ + | IRQ0ENABLE_RSZ_DONE_IRQ; + + isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); + isp_reg_writel(isp, irq, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE); +} + +/* + * isp_disable_interrupts - Disable ISP interrupts. + * @isp: OMAP3 ISP device + */ +static void isp_disable_interrupts(struct isp_device *isp) +{ + isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE); +} + +/** + * isp_set_xclk - Configures the specified cam_xclk to the desired frequency. + * @isp: OMAP3 ISP device + * @xclk: Desired frequency of the clock in Hz. 0 = stable low, 1 is stable high + * @xclksel: XCLK to configure (0 = A, 1 = B). + * + * Configures the specified MCLK divisor in the ISP timing control register + * (TCTRL_CTRL) to generate the desired xclk clock value. + * + * Divisor = cam_mclk_hz / xclk + * + * Returns the final frequency that is actually being generated + **/ +static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) +{ + u32 divisor; + u32 currentxclk; + unsigned long mclk_hz; + + if (!omap3isp_get(isp)) + return 0; + + mclk_hz = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]); + + if (xclk >= mclk_hz) { + divisor = ISPTCTRL_CTRL_DIV_BYPASS; + currentxclk = mclk_hz; + } else if (xclk >= 2) { + divisor = mclk_hz / xclk; + if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS) + divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1; + currentxclk = mclk_hz / divisor; + } else { + divisor = xclk; + currentxclk = 0; + } + + switch (xclksel) { + case 0: + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, + ISPTCTRL_CTRL_DIVA_MASK, + divisor << ISPTCTRL_CTRL_DIVA_SHIFT); + dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", + currentxclk); + break; + case 1: + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, + ISPTCTRL_CTRL_DIVB_MASK, + divisor << ISPTCTRL_CTRL_DIVB_SHIFT); + dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", + currentxclk); + break; + default: + omap3isp_put(isp); + dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " + "xclk. Must be 0 (A) or 1 (B).\n"); + return -EINVAL; + } + + /* Do we go from stable whatever to clock? */ + if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2) + omap3isp_get(isp); + /* Stopping the clock. */ + else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2) + omap3isp_put(isp); + + isp->xclk_divisor[xclksel] = divisor; + + omap3isp_put(isp); + + return currentxclk; +} + +/* + * isp_power_settings - Sysconfig settings, for Power Management. + * @isp: OMAP3 ISP device + * @idle: Consider idle state. + * + * Sets the power settings for the ISP, and SBL bus. + */ +static void isp_power_settings(struct isp_device *isp, int idle) +{ + isp_reg_writel(isp, + ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY : + ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY) << + ISP_SYSCONFIG_MIDLEMODE_SHIFT) | + ((isp->revision == ISP_REVISION_15_0) ? + ISP_SYSCONFIG_AUTOIDLE : 0), + OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG); + + if (isp->autoidle) + isp_reg_writel(isp, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN, + ISP_CTRL); +} + +/* + * Configure the bridge and lane shifter. Valid inputs are + * + * CCDC_INPUT_PARALLEL: Parallel interface + * CCDC_INPUT_CSI2A: CSI2a receiver + * CCDC_INPUT_CCP2B: CCP2b receiver + * CCDC_INPUT_CSI2C: CSI2c receiver + * + * The bridge and lane shifter are configured according to the selected input + * and the ISP platform data. + */ +void omap3isp_configure_bridge(struct isp_device *isp, + enum ccdc_input_entity input, + const struct isp_parallel_platform_data *pdata) +{ + u32 ispctrl_val; + + ispctrl_val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL); + ispctrl_val &= ~ISPCTRL_SHIFT_MASK; + ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV; + ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK; + ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK; + + switch (input) { + case CCDC_INPUT_PARALLEL: + ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; + ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT; + ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; + ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; + break; + + case CCDC_INPUT_CSI2A: + ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIA; + break; + + case CCDC_INPUT_CCP2B: + ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB; + break; + + case CCDC_INPUT_CSI2C: + ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIC; + break; + + default: + return; + } + + ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; + ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; + + isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL); +} + +/** + * isp_set_pixel_clock - Configures the ISP pixel clock + * @isp: OMAP3 ISP device + * @pixelclk: Average pixel clock in Hz + * + * Set the average pixel clock required by the sensor. The ISP will use the + * lowest possible memory bandwidth settings compatible with the clock. + **/ +static void isp_set_pixel_clock(struct isp_device *isp, unsigned int pixelclk) +{ + isp->isp_ccdc.vpcfg.pixelclk = pixelclk; +} + +void omap3isp_hist_dma_done(struct isp_device *isp) +{ + if (omap3isp_ccdc_busy(&isp->isp_ccdc) || + omap3isp_stat_pcr_busy(&isp->isp_hist)) { + /* Histogram cannot be enabled in this frame anymore */ + atomic_set(&isp->isp_hist.buf_err, 1); + dev_dbg(isp->dev, "hist: Out of synchronization with " + "CCDC. Ignoring next buffer.\n"); + } +} + +static inline void isp_isr_dbg(struct isp_device *isp, u32 irqstatus) +{ + static const char *name[] = { + "CSIA_IRQ", + "res1", + "res2", + "CSIB_LCM_IRQ", + "CSIB_IRQ", + "res5", + "res6", + "res7", + "CCDC_VD0_IRQ", + "CCDC_VD1_IRQ", + "CCDC_VD2_IRQ", + "CCDC_ERR_IRQ", + "H3A_AF_DONE_IRQ", + "H3A_AWB_DONE_IRQ", + "res14", + "res15", + "HIST_DONE_IRQ", + "CCDC_LSC_DONE", + "CCDC_LSC_PREFETCH_COMPLETED", + "CCDC_LSC_PREFETCH_ERROR", + "PRV_DONE_IRQ", + "CBUFF_IRQ", + "res22", + "res23", + "RSZ_DONE_IRQ", + "OVF_IRQ", + "res26", + "res27", + "MMU_ERR_IRQ", + "OCP_ERR_IRQ", + "SEC_ERR_IRQ", + "HS_VS_IRQ", + }; + int i; + + dev_dbg(isp->dev, ""); + + for (i = 0; i < ARRAY_SIZE(name); i++) { + if ((1 << i) & irqstatus) + printk(KERN_CONT "%s ", name[i]); + } + printk(KERN_CONT "\n"); +} + +static void isp_isr_sbl(struct isp_device *isp) +{ + struct device *dev = isp->dev; + u32 sbl_pcr; + + /* + * Handle shared buffer logic overflows for video buffers. + * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored. + */ + sbl_pcr = isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR); + isp_reg_writel(isp, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR); + sbl_pcr &= ~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF; + + if (sbl_pcr) + dev_dbg(dev, "SBL overflow (PCR = 0x%08x)\n", sbl_pcr); + + if (sbl_pcr & (ISPSBL_PCR_CCDC_WBL_OVF | ISPSBL_PCR_CSIA_WBL_OVF + | ISPSBL_PCR_CSIB_WBL_OVF)) { + isp->isp_ccdc.error = 1; + if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) + isp->isp_prev.error = 1; + if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER) + isp->isp_res.error = 1; + } + + if (sbl_pcr & ISPSBL_PCR_PRV_WBL_OVF) { + isp->isp_prev.error = 1; + if (isp->isp_res.input == RESIZER_INPUT_VP && + !(isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER)) + isp->isp_res.error = 1; + } + + if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF + | ISPSBL_PCR_RSZ2_WBL_OVF + | ISPSBL_PCR_RSZ3_WBL_OVF + | ISPSBL_PCR_RSZ4_WBL_OVF)) + isp->isp_res.error = 1; + + if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF) + omap3isp_stat_sbl_overflow(&isp->isp_af); + + if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF) + omap3isp_stat_sbl_overflow(&isp->isp_aewb); +} + +/* + * isp_isr - Interrupt Service Routine for Camera ISP module. + * @irq: Not used currently. + * @_isp: Pointer to the OMAP3 ISP device + * + * Handles the corresponding callback if plugged in. + * + * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the + * IRQ wasn't handled. + */ +static irqreturn_t isp_isr(int irq, void *_isp) +{ + static const u32 ccdc_events = IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ | + IRQ0STATUS_CCDC_LSC_DONE_IRQ | + IRQ0STATUS_CCDC_VD0_IRQ | + IRQ0STATUS_CCDC_VD1_IRQ | + IRQ0STATUS_HS_VS_IRQ; + struct isp_device *isp = _isp; + u32 irqstatus; + int ret; + + irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); + isp_reg_writel(isp, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); + + isp_isr_sbl(isp); + + if (irqstatus & IRQ0STATUS_CSIA_IRQ) { + ret = omap3isp_csi2_isr(&isp->isp_csi2a); + if (ret) + isp->isp_ccdc.error = 1; + } + + if (irqstatus & IRQ0STATUS_CSIB_IRQ) { + ret = omap3isp_ccp2_isr(&isp->isp_ccp2); + if (ret) + isp->isp_ccdc.error = 1; + } + + if (irqstatus & IRQ0STATUS_CCDC_VD0_IRQ) { + if (isp->isp_ccdc.output & CCDC_OUTPUT_PREVIEW) + omap3isp_preview_isr_frame_sync(&isp->isp_prev); + if (isp->isp_ccdc.output & CCDC_OUTPUT_RESIZER) + omap3isp_resizer_isr_frame_sync(&isp->isp_res); + omap3isp_stat_isr_frame_sync(&isp->isp_aewb); + omap3isp_stat_isr_frame_sync(&isp->isp_af); + omap3isp_stat_isr_frame_sync(&isp->isp_hist); + } + + if (irqstatus & ccdc_events) + omap3isp_ccdc_isr(&isp->isp_ccdc, irqstatus & ccdc_events); + + if (irqstatus & IRQ0STATUS_PRV_DONE_IRQ) { + if (isp->isp_prev.output & PREVIEW_OUTPUT_RESIZER) + omap3isp_resizer_isr_frame_sync(&isp->isp_res); + omap3isp_preview_isr(&isp->isp_prev); + } + + if (irqstatus & IRQ0STATUS_RSZ_DONE_IRQ) + omap3isp_resizer_isr(&isp->isp_res); + + if (irqstatus & IRQ0STATUS_H3A_AWB_DONE_IRQ) + omap3isp_stat_isr(&isp->isp_aewb); + + if (irqstatus & IRQ0STATUS_H3A_AF_DONE_IRQ) + omap3isp_stat_isr(&isp->isp_af); + + if (irqstatus & IRQ0STATUS_HIST_DONE_IRQ) + omap3isp_stat_isr(&isp->isp_hist); + + omap3isp_flush(isp); + +#if defined(DEBUG) && defined(ISP_ISR_DEBUG) + isp_isr_dbg(isp, irqstatus); +#endif + + return IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * Pipeline power management + * + * Entities must be powered up when part of a pipeline that contains at least + * one open video device node. + * + * To achieve this use the entity use_count field to track the number of users. + * For entities corresponding to video device nodes the use_count field stores + * the users count of the node. For entities corresponding to subdevs the + * use_count field stores the total number of users of all video device nodes + * in the pipeline. + * + * The omap3isp_pipeline_pm_use() function must be called in the open() and + * close() handlers of video device nodes. It increments or decrements the use + * count of all subdev entities in the pipeline. + * + * To react to link management on powered pipelines, the link setup notification + * callback updates the use count of all entities in the source and sink sides + * of the link. + */ + +/* + * isp_pipeline_pm_use_count - Count the number of users of a pipeline + * @entity: The entity + * + * Return the total number of users of all video device nodes in the pipeline. + */ +static int isp_pipeline_pm_use_count(struct media_entity *entity) +{ + struct media_entity_graph graph; + int use = 0; + + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE) + use += entity->use_count; + } + + return use; +} + +/* + * isp_pipeline_pm_power_one - Apply power change to an entity + * @entity: The entity + * @change: Use count change + * + * Change the entity use count by @change. If the entity is a subdev update its + * power state by calling the core::s_power operation when the use count goes + * from 0 to != 0 or from != 0 to 0. + * + * Return 0 on success or a negative error code on failure. + */ +static int isp_pipeline_pm_power_one(struct media_entity *entity, int change) +{ + struct v4l2_subdev *subdev; + int ret; + + subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV + ? media_entity_to_v4l2_subdev(entity) : NULL; + + if (entity->use_count == 0 && change > 0 && subdev != NULL) { + ret = v4l2_subdev_call(subdev, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + } + + entity->use_count += change; + WARN_ON(entity->use_count < 0); + + if (entity->use_count == 0 && change < 0 && subdev != NULL) + v4l2_subdev_call(subdev, core, s_power, 0); + + return 0; +} + +/* + * isp_pipeline_pm_power - Apply power change to all entities in a pipeline + * @entity: The entity + * @change: Use count change + * + * Walk the pipeline to update the use count and the power state of all non-node + * entities. + * + * Return 0 on success or a negative error code on failure. + */ +static int isp_pipeline_pm_power(struct media_entity *entity, int change) +{ + struct media_entity_graph graph; + struct media_entity *first = entity; + int ret = 0; + + if (!change) + return 0; + + media_entity_graph_walk_start(&graph, entity); + + while (!ret && (entity = media_entity_graph_walk_next(&graph))) + if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) + ret = isp_pipeline_pm_power_one(entity, change); + + if (!ret) + return 0; + + media_entity_graph_walk_start(&graph, first); + + while ((first = media_entity_graph_walk_next(&graph)) + && first != entity) + if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE) + isp_pipeline_pm_power_one(first, -change); + + return ret; +} + +/* + * omap3isp_pipeline_pm_use - Update the use count of an entity + * @entity: The entity + * @use: Use (1) or stop using (0) the entity + * + * Update the use count of all entities in the pipeline and power entities on or + * off accordingly. + * + * Return 0 on success or a negative error code on failure. Powering entities + * off is assumed to never fail. No failure can occur when the use parameter is + * set to 0. + */ +int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) +{ + int change = use ? 1 : -1; + int ret; + + mutex_lock(&entity->parent->graph_mutex); + + /* Apply use count to node. */ + entity->use_count += change; + WARN_ON(entity->use_count < 0); + + /* Apply power change to connected non-nodes. */ + ret = isp_pipeline_pm_power(entity, change); + + mutex_unlock(&entity->parent->graph_mutex); + + return ret; +} + +/* + * isp_pipeline_link_notify - Link management notification callback + * @source: Pad at the start of the link + * @sink: Pad at the end of the link + * @flags: New link flags that will be applied + * + * React to link management on powered pipelines by updating the use count of + * all entities in the source and sink sides of the link. Entities are powered + * on or off accordingly. + * + * Return 0 on success or a negative error code on failure. Powering entities + * off is assumed to never fail. This function will not fail for disconnection + * events. + */ +static int isp_pipeline_link_notify(struct media_pad *source, + struct media_pad *sink, u32 flags) +{ + int source_use = isp_pipeline_pm_use_count(source->entity); + int sink_use = isp_pipeline_pm_use_count(sink->entity); + int ret; + + if (!(flags & MEDIA_LNK_FL_ENABLED)) { + /* Powering off entities is assumed to never fail. */ + isp_pipeline_pm_power(source->entity, -sink_use); + isp_pipeline_pm_power(sink->entity, -source_use); + return 0; + } + + ret = isp_pipeline_pm_power(source->entity, sink_use); + if (ret < 0) + return ret; + + ret = isp_pipeline_pm_power(sink->entity, source_use); + if (ret < 0) + isp_pipeline_pm_power(source->entity, -sink_use); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Pipeline stream management + */ + +/* + * isp_pipeline_enable - Enable streaming on a pipeline + * @pipe: ISP pipeline + * @mode: Stream mode (single shot or continuous) + * + * Walk the entities chain starting at the pipeline output video node and start + * all modules in the chain in the given mode. + * + * Return 0 if successfull, or the return value of the failed video::s_stream + * operation otherwise. + */ +static int isp_pipeline_enable(struct isp_pipeline *pipe, + enum isp_pipeline_stream_state mode) +{ + struct isp_device *isp = pipe->output->isp; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&pipe->lock, flags); + pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT); + spin_unlock_irqrestore(&pipe->lock, flags); + + pipe->do_propagation = false; + + entity = &pipe->output->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + ret = v4l2_subdev_call(subdev, video, s_stream, mode); + if (ret < 0 && ret != -ENOIOCTLCMD) + break; + + if (subdev == &isp->isp_ccdc.subdev) { + v4l2_subdev_call(&isp->isp_aewb.subdev, video, + s_stream, mode); + v4l2_subdev_call(&isp->isp_af.subdev, video, + s_stream, mode); + v4l2_subdev_call(&isp->isp_hist.subdev, video, + s_stream, mode); + pipe->do_propagation = true; + } + } + + /* Frame number propagation. In continuous streaming mode the number + * is incremented in the frame start ISR. In mem-to-mem mode + * singleshot is used and frame start IRQs are not available. + * Thus we have to increment the number here. + */ + if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT) + atomic_inc(&pipe->frame_number); + + return ret; +} + +static int isp_pipeline_wait_resizer(struct isp_device *isp) +{ + return omap3isp_resizer_busy(&isp->isp_res); +} + +static int isp_pipeline_wait_preview(struct isp_device *isp) +{ + return omap3isp_preview_busy(&isp->isp_prev); +} + +static int isp_pipeline_wait_ccdc(struct isp_device *isp) +{ + return omap3isp_stat_busy(&isp->isp_af) + || omap3isp_stat_busy(&isp->isp_aewb) + || omap3isp_stat_busy(&isp->isp_hist) + || omap3isp_ccdc_busy(&isp->isp_ccdc); +} + +#define ISP_STOP_TIMEOUT msecs_to_jiffies(1000) + +static int isp_pipeline_wait(struct isp_device *isp, + int(*busy)(struct isp_device *isp)) +{ + unsigned long timeout = jiffies + ISP_STOP_TIMEOUT; + + while (!time_after(jiffies, timeout)) { + if (!busy(isp)) + return 0; + } + + return 1; +} + +/* + * isp_pipeline_disable - Disable streaming on a pipeline + * @pipe: ISP pipeline + * + * Walk the entities chain starting at the pipeline output video node and stop + * all modules in the chain. Wait synchronously for the modules to be stopped if + * necessary. + * + * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module + * can't be stopped (in which case a software reset of the ISP is probably + * necessary). + */ +static int isp_pipeline_disable(struct isp_pipeline *pipe) +{ + struct isp_device *isp = pipe->output->isp; + struct media_entity *entity; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int failure = 0; + int ret; + + /* + * We need to stop all the modules after CCDC first or they'll + * never stop since they may not get a full frame from CCDC. + */ + entity = &pipe->output->video.entity; + while (1) { + pad = &entity->pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + entity = pad->entity; + subdev = media_entity_to_v4l2_subdev(entity); + + if (subdev == &isp->isp_ccdc.subdev) { + v4l2_subdev_call(&isp->isp_aewb.subdev, + video, s_stream, 0); + v4l2_subdev_call(&isp->isp_af.subdev, + video, s_stream, 0); + v4l2_subdev_call(&isp->isp_hist.subdev, + video, s_stream, 0); + } + + v4l2_subdev_call(subdev, video, s_stream, 0); + + if (subdev == &isp->isp_res.subdev) + ret = isp_pipeline_wait(isp, isp_pipeline_wait_resizer); + else if (subdev == &isp->isp_prev.subdev) + ret = isp_pipeline_wait(isp, isp_pipeline_wait_preview); + else if (subdev == &isp->isp_ccdc.subdev) + ret = isp_pipeline_wait(isp, isp_pipeline_wait_ccdc); + else + ret = 0; + + if (ret) { + dev_info(isp->dev, "Unable to stop %s\n", subdev->name); + failure = -ETIMEDOUT; + } + } + + return failure; +} + +/* + * omap3isp_pipeline_set_stream - Enable/disable streaming on a pipeline + * @pipe: ISP pipeline + * @state: Stream state (stopped, single shot or continuous) + * + * Set the pipeline to the given stream state. Pipelines can be started in + * single-shot or continuous mode. + * + * Return 0 if successfull, or the return value of the failed video::s_stream + * operation otherwise. + */ +int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, + enum isp_pipeline_stream_state state) +{ + int ret; + + if (state == ISP_PIPELINE_STREAM_STOPPED) + ret = isp_pipeline_disable(pipe); + else + ret = isp_pipeline_enable(pipe, state); + pipe->stream_state = state; + + return ret; +} + +/* + * isp_pipeline_resume - Resume streaming on a pipeline + * @pipe: ISP pipeline + * + * Resume video output and input and re-enable pipeline. + */ +static void isp_pipeline_resume(struct isp_pipeline *pipe) +{ + int singleshot = pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT; + + omap3isp_video_resume(pipe->output, !singleshot); + if (singleshot) + omap3isp_video_resume(pipe->input, 0); + isp_pipeline_enable(pipe, pipe->stream_state); +} + +/* + * isp_pipeline_suspend - Suspend streaming on a pipeline + * @pipe: ISP pipeline + * + * Suspend pipeline. + */ +static void isp_pipeline_suspend(struct isp_pipeline *pipe) +{ + isp_pipeline_disable(pipe); +} + +/* + * isp_pipeline_is_last - Verify if entity has an enabled link to the output + * video node + * @me: ISP module's media entity + * + * Returns 1 if the entity has an enabled link to the output video node or 0 + * otherwise. It's true only while pipeline can have no more than one output + * node. + */ +static int isp_pipeline_is_last(struct media_entity *me) +{ + struct isp_pipeline *pipe; + struct media_pad *pad; + + if (!me->pipe) + return 0; + pipe = to_isp_pipeline(me); + if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) + return 0; + pad = media_entity_remote_source(&pipe->output->pad); + return pad->entity == me; +} + +/* + * isp_suspend_module_pipeline - Suspend pipeline to which belongs the module + * @me: ISP module's media entity + * + * Suspend the whole pipeline if module's entity has an enabled link to the + * output video node. It works only while pipeline can have no more than one + * output node. + */ +static void isp_suspend_module_pipeline(struct media_entity *me) +{ + if (isp_pipeline_is_last(me)) + isp_pipeline_suspend(to_isp_pipeline(me)); +} + +/* + * isp_resume_module_pipeline - Resume pipeline to which belongs the module + * @me: ISP module's media entity + * + * Resume the whole pipeline if module's entity has an enabled link to the + * output video node. It works only while pipeline can have no more than one + * output node. + */ +static void isp_resume_module_pipeline(struct media_entity *me) +{ + if (isp_pipeline_is_last(me)) + isp_pipeline_resume(to_isp_pipeline(me)); +} + +/* + * isp_suspend_modules - Suspend ISP submodules. + * @isp: OMAP3 ISP device + * + * Returns 0 if suspend left in idle state all the submodules properly, + * or returns 1 if a general Reset is required to suspend the submodules. + */ +static int isp_suspend_modules(struct isp_device *isp) +{ + unsigned long timeout; + + omap3isp_stat_suspend(&isp->isp_aewb); + omap3isp_stat_suspend(&isp->isp_af); + omap3isp_stat_suspend(&isp->isp_hist); + isp_suspend_module_pipeline(&isp->isp_res.subdev.entity); + isp_suspend_module_pipeline(&isp->isp_prev.subdev.entity); + isp_suspend_module_pipeline(&isp->isp_ccdc.subdev.entity); + isp_suspend_module_pipeline(&isp->isp_csi2a.subdev.entity); + isp_suspend_module_pipeline(&isp->isp_ccp2.subdev.entity); + + timeout = jiffies + ISP_STOP_TIMEOUT; + while (omap3isp_stat_busy(&isp->isp_af) + || omap3isp_stat_busy(&isp->isp_aewb) + || omap3isp_stat_busy(&isp->isp_hist) + || omap3isp_preview_busy(&isp->isp_prev) + || omap3isp_resizer_busy(&isp->isp_res) + || omap3isp_ccdc_busy(&isp->isp_ccdc)) { + if (time_after(jiffies, timeout)) { + dev_info(isp->dev, "can't stop modules.\n"); + return 1; + } + msleep(1); + } + + return 0; +} + +/* + * isp_resume_modules - Resume ISP submodules. + * @isp: OMAP3 ISP device + */ +static void isp_resume_modules(struct isp_device *isp) +{ + omap3isp_stat_resume(&isp->isp_aewb); + omap3isp_stat_resume(&isp->isp_af); + omap3isp_stat_resume(&isp->isp_hist); + isp_resume_module_pipeline(&isp->isp_res.subdev.entity); + isp_resume_module_pipeline(&isp->isp_prev.subdev.entity); + isp_resume_module_pipeline(&isp->isp_ccdc.subdev.entity); + isp_resume_module_pipeline(&isp->isp_csi2a.subdev.entity); + isp_resume_module_pipeline(&isp->isp_ccp2.subdev.entity); +} + +/* + * isp_reset - Reset ISP with a timeout wait for idle. + * @isp: OMAP3 ISP device + */ +static int isp_reset(struct isp_device *isp) +{ + unsigned long timeout = 0; + + isp_reg_writel(isp, + isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG) + | ISP_SYSCONFIG_SOFTRESET, + OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG); + while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, + ISP_SYSSTATUS) & 0x1)) { + if (timeout++ > 10000) { + dev_alert(isp->dev, "cannot reset ISP\n"); + return -ETIMEDOUT; + } + udelay(1); + } + + return 0; +} + +/* + * isp_save_context - Saves the values of the ISP module registers. + * @isp: OMAP3 ISP device + * @reg_list: Structure containing pairs of register address and value to + * modify on OMAP. + */ +static void +isp_save_context(struct isp_device *isp, struct isp_reg *reg_list) +{ + struct isp_reg *next = reg_list; + + for (; next->reg != ISP_TOK_TERM; next++) + next->val = isp_reg_readl(isp, next->mmio_range, next->reg); +} + +/* + * isp_restore_context - Restores the values of the ISP module registers. + * @isp: OMAP3 ISP device + * @reg_list: Structure containing pairs of register address and value to + * modify on OMAP. + */ +static void +isp_restore_context(struct isp_device *isp, struct isp_reg *reg_list) +{ + struct isp_reg *next = reg_list; + + for (; next->reg != ISP_TOK_TERM; next++) + isp_reg_writel(isp, next->val, next->mmio_range, next->reg); +} + +/* + * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context. + * @isp: OMAP3 ISP device + * + * Routine for saving the context of each module in the ISP. + * CCDC, HIST, H3A, PREV, RESZ and MMU. + */ +static void isp_save_ctx(struct isp_device *isp) +{ + isp_save_context(isp, isp_reg_list); + if (isp->iommu) + iommu_save_ctx(isp->iommu); +} + +/* + * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context. + * @isp: OMAP3 ISP device + * + * Routine for restoring the context of each module in the ISP. + * CCDC, HIST, H3A, PREV, RESZ and MMU. + */ +static void isp_restore_ctx(struct isp_device *isp) +{ + isp_restore_context(isp, isp_reg_list); + if (isp->iommu) + iommu_restore_ctx(isp->iommu); + omap3isp_ccdc_restore_context(isp); + omap3isp_preview_restore_context(isp); +} + +/* ----------------------------------------------------------------------------- + * SBL resources management + */ +#define OMAP3_ISP_SBL_READ (OMAP3_ISP_SBL_CSI1_READ | \ + OMAP3_ISP_SBL_CCDC_LSC_READ | \ + OMAP3_ISP_SBL_PREVIEW_READ | \ + OMAP3_ISP_SBL_RESIZER_READ) +#define OMAP3_ISP_SBL_WRITE (OMAP3_ISP_SBL_CSI1_WRITE | \ + OMAP3_ISP_SBL_CSI2A_WRITE | \ + OMAP3_ISP_SBL_CSI2C_WRITE | \ + OMAP3_ISP_SBL_CCDC_WRITE | \ + OMAP3_ISP_SBL_PREVIEW_WRITE) + +void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res) +{ + u32 sbl = 0; + + isp->sbl_resources |= res; + + if (isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ) + sbl |= ISPCTRL_SBL_SHARED_RPORTA; + + if (isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ) + sbl |= ISPCTRL_SBL_SHARED_RPORTB; + + if (isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE) + sbl |= ISPCTRL_SBL_SHARED_WPORTC; + + if (isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE) + sbl |= ISPCTRL_SBL_WR0_RAM_EN; + + if (isp->sbl_resources & OMAP3_ISP_SBL_WRITE) + sbl |= ISPCTRL_SBL_WR1_RAM_EN; + + if (isp->sbl_resources & OMAP3_ISP_SBL_READ) + sbl |= ISPCTRL_SBL_RD_RAM_EN; + + isp_reg_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl); +} + +void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res) +{ + u32 sbl = 0; + + isp->sbl_resources &= ~res; + + if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI1_READ)) + sbl |= ISPCTRL_SBL_SHARED_RPORTA; + + if (!(isp->sbl_resources & OMAP3_ISP_SBL_CCDC_LSC_READ)) + sbl |= ISPCTRL_SBL_SHARED_RPORTB; + + if (!(isp->sbl_resources & OMAP3_ISP_SBL_CSI2C_WRITE)) + sbl |= ISPCTRL_SBL_SHARED_WPORTC; + + if (!(isp->sbl_resources & OMAP3_ISP_SBL_RESIZER_WRITE)) + sbl |= ISPCTRL_SBL_WR0_RAM_EN; + + if (!(isp->sbl_resources & OMAP3_ISP_SBL_WRITE)) + sbl |= ISPCTRL_SBL_WR1_RAM_EN; + + if (!(isp->sbl_resources & OMAP3_ISP_SBL_READ)) + sbl |= ISPCTRL_SBL_RD_RAM_EN; + + isp_reg_clr(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, sbl); +} + +/* + * isp_module_sync_idle - Helper to sync module with its idle state + * @me: ISP submodule's media entity + * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization + * @stopping: flag which tells module wants to stop + * + * This function checks if ISP submodule needs to wait for next interrupt. If + * yes, makes the caller to sleep while waiting for such event. + */ +int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, + atomic_t *stopping) +{ + struct isp_pipeline *pipe = to_isp_pipeline(me); + + if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED || + (pipe->stream_state == ISP_PIPELINE_STREAM_SINGLESHOT && + !isp_pipeline_ready(pipe))) + return 0; + + /* + * atomic_set() doesn't include memory barrier on ARM platform for SMP + * scenario. We'll call it here to avoid race conditions. + */ + atomic_set(stopping, 1); + smp_mb(); + + /* + * If module is the last one, it's writing to memory. In this case, + * it's necessary to check if the module is already paused due to + * DMA queue underrun or if it has to wait for next interrupt to be + * idle. + * If it isn't the last one, the function won't sleep but *stopping + * will still be set to warn next submodule caller's interrupt the + * module wants to be idle. + */ + if (isp_pipeline_is_last(me)) { + struct isp_video *video = pipe->output; + unsigned long flags; + spin_lock_irqsave(&video->queue->irqlock, flags); + if (video->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { + spin_unlock_irqrestore(&video->queue->irqlock, flags); + atomic_set(stopping, 0); + smp_mb(); + return 0; + } + spin_unlock_irqrestore(&video->queue->irqlock, flags); + if (!wait_event_timeout(*wait, !atomic_read(stopping), + msecs_to_jiffies(1000))) { + atomic_set(stopping, 0); + smp_mb(); + return -ETIMEDOUT; + } + } + + return 0; +} + +/* + * omap3isp_module_sync_is_stopped - Helper to verify if module was stopping + * @wait: ISP submodule's wait queue for streamoff/interrupt synchronization + * @stopping: flag which tells module wants to stop + * + * This function checks if ISP submodule was stopping. In case of yes, it + * notices the caller by setting stopping to 0 and waking up the wait queue. + * Returns 1 if it was stopping or 0 otherwise. + */ +int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait, + atomic_t *stopping) +{ + if (atomic_cmpxchg(stopping, 1, 0)) { + wake_up(wait); + return 1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- + * Clock management + */ + +#define ISPCTRL_CLKS_MASK (ISPCTRL_H3A_CLK_EN | \ + ISPCTRL_HIST_CLK_EN | \ + ISPCTRL_RSZ_CLK_EN | \ + (ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN) | \ + (ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN)) + +static void __isp_subclk_update(struct isp_device *isp) +{ + u32 clk = 0; + + if (isp->subclk_resources & OMAP3_ISP_SUBCLK_H3A) + clk |= ISPCTRL_H3A_CLK_EN; + + if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST) + clk |= ISPCTRL_HIST_CLK_EN; + + if (isp->subclk_resources & OMAP3_ISP_SUBCLK_RESIZER) + clk |= ISPCTRL_RSZ_CLK_EN; + + /* NOTE: For CCDC & Preview submodules, we need to affect internal + * RAM aswell. + */ + if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC) + clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN; + + if (isp->subclk_resources & OMAP3_ISP_SUBCLK_PREVIEW) + clk |= ISPCTRL_PREV_CLK_EN | ISPCTRL_PREV_RAM_EN; + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, + ISPCTRL_CLKS_MASK, clk); +} + +void omap3isp_subclk_enable(struct isp_device *isp, + enum isp_subclk_resource res) +{ + isp->subclk_resources |= res; + + __isp_subclk_update(isp); +} + +void omap3isp_subclk_disable(struct isp_device *isp, + enum isp_subclk_resource res) +{ + isp->subclk_resources &= ~res; + + __isp_subclk_update(isp); +} + +/* + * isp_enable_clocks - Enable ISP clocks + * @isp: OMAP3 ISP device + * + * Return 0 if successful, or clk_enable return value if any of tthem fails. + */ +static int isp_enable_clocks(struct isp_device *isp) +{ + int r; + unsigned long rate; + int divisor; + + /* + * cam_mclk clock chain: + * dpll4 -> dpll4_m5 -> dpll4_m5x2 -> cam_mclk + * + * In OMAP3630 dpll4_m5x2 != 2 x dpll4_m5 but both are + * set to the same value. Hence the rate set for dpll4_m5 + * has to be twice of what is set on OMAP3430 to get + * the required value for cam_mclk + */ + if (cpu_is_omap3630()) + divisor = 1; + else + divisor = 2; + + r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); + if (r) { + dev_err(isp->dev, "clk_enable cam_ick failed\n"); + goto out_clk_enable_ick; + } + r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK], + CM_CAM_MCLK_HZ/divisor); + if (r) { + dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n"); + goto out_clk_enable_mclk; + } + r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]); + if (r) { + dev_err(isp->dev, "clk_enable cam_mclk failed\n"); + goto out_clk_enable_mclk; + } + rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]); + if (rate != CM_CAM_MCLK_HZ) + dev_warn(isp->dev, "unexpected cam_mclk rate:\n" + " expected : %d\n" + " actual : %ld\n", CM_CAM_MCLK_HZ, rate); + r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]); + if (r) { + dev_err(isp->dev, "clk_enable csi2_fck failed\n"); + goto out_clk_enable_csi2_fclk; + } + return 0; + +out_clk_enable_csi2_fclk: + clk_disable(isp->clock[ISP_CLK_CAM_MCLK]); +out_clk_enable_mclk: + clk_disable(isp->clock[ISP_CLK_CAM_ICK]); +out_clk_enable_ick: + return r; +} + +/* + * isp_disable_clocks - Disable ISP clocks + * @isp: OMAP3 ISP device + */ +static void isp_disable_clocks(struct isp_device *isp) +{ + clk_disable(isp->clock[ISP_CLK_CAM_ICK]); + clk_disable(isp->clock[ISP_CLK_CAM_MCLK]); + clk_disable(isp->clock[ISP_CLK_CSI2_FCK]); +} + +static const char *isp_clocks[] = { + "cam_ick", + "cam_mclk", + "dpll4_m5_ck", + "csi2_96m_fck", + "l3_ick", +}; + +static void isp_put_clocks(struct isp_device *isp) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) { + if (isp->clock[i]) { + clk_put(isp->clock[i]); + isp->clock[i] = NULL; + } + } +} + +static int isp_get_clocks(struct isp_device *isp) +{ + struct clk *clk; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(isp_clocks); ++i) { + clk = clk_get(isp->dev, isp_clocks[i]); + if (IS_ERR(clk)) { + dev_err(isp->dev, "clk_get %s failed\n", isp_clocks[i]); + isp_put_clocks(isp); + return PTR_ERR(clk); + } + + isp->clock[i] = clk; + } + + return 0; +} + +/* + * omap3isp_get - Acquire the ISP resource. + * + * Initializes the clocks for the first acquire. + * + * Increment the reference count on the ISP. If the first reference is taken, + * enable clocks and power-up all submodules. + * + * Return a pointer to the ISP device structure, or NULL if an error occured. + */ +struct isp_device *omap3isp_get(struct isp_device *isp) +{ + struct isp_device *__isp = isp; + + if (isp == NULL) + return NULL; + + mutex_lock(&isp->isp_mutex); + if (isp->ref_count > 0) + goto out; + + if (isp_enable_clocks(isp) < 0) { + __isp = NULL; + goto out; + } + + /* We don't want to restore context before saving it! */ + if (isp->has_context) + isp_restore_ctx(isp); + else + isp->has_context = 1; + + isp_enable_interrupts(isp); + +out: + if (__isp != NULL) + isp->ref_count++; + mutex_unlock(&isp->isp_mutex); + + return __isp; +} + +/* + * omap3isp_put - Release the ISP + * + * Decrement the reference count on the ISP. If the last reference is released, + * power-down all submodules, disable clocks and free temporary buffers. + */ +void omap3isp_put(struct isp_device *isp) +{ + if (isp == NULL) + return; + + mutex_lock(&isp->isp_mutex); + BUG_ON(isp->ref_count == 0); + if (--isp->ref_count == 0) { + isp_disable_interrupts(isp); + isp_save_ctx(isp); + isp_disable_clocks(isp); + } + mutex_unlock(&isp->isp_mutex); +} + +/* -------------------------------------------------------------------------- + * Platform device driver + */ + +/* + * omap3isp_print_status - Prints the values of the ISP Control Module registers + * @isp: OMAP3 ISP device + */ +#define ISP_PRINT_REGISTER(isp, name)\ + dev_dbg(isp->dev, "###ISP " #name "=0x%08x\n", \ + isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_##name)) +#define SBL_PRINT_REGISTER(isp, name)\ + dev_dbg(isp->dev, "###SBL " #name "=0x%08x\n", \ + isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_##name)) + +void omap3isp_print_status(struct isp_device *isp) +{ + dev_dbg(isp->dev, "-------------ISP Register dump--------------\n"); + + ISP_PRINT_REGISTER(isp, SYSCONFIG); + ISP_PRINT_REGISTER(isp, SYSSTATUS); + ISP_PRINT_REGISTER(isp, IRQ0ENABLE); + ISP_PRINT_REGISTER(isp, IRQ0STATUS); + ISP_PRINT_REGISTER(isp, TCTRL_GRESET_LENGTH); + ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_REPLAY); + ISP_PRINT_REGISTER(isp, CTRL); + ISP_PRINT_REGISTER(isp, TCTRL_CTRL); + ISP_PRINT_REGISTER(isp, TCTRL_FRAME); + ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_DELAY); + ISP_PRINT_REGISTER(isp, TCTRL_STRB_DELAY); + ISP_PRINT_REGISTER(isp, TCTRL_SHUT_DELAY); + ISP_PRINT_REGISTER(isp, TCTRL_PSTRB_LENGTH); + ISP_PRINT_REGISTER(isp, TCTRL_STRB_LENGTH); + ISP_PRINT_REGISTER(isp, TCTRL_SHUT_LENGTH); + + SBL_PRINT_REGISTER(isp, PCR); + SBL_PRINT_REGISTER(isp, SDR_REQ_EXP); + + dev_dbg(isp->dev, "--------------------------------------------\n"); +} + +#ifdef CONFIG_PM + +/* + * Power management support. + * + * As the ISP can't properly handle an input video stream interruption on a non + * frame boundary, the ISP pipelines need to be stopped before sensors get + * suspended. However, as suspending the sensors can require a running clock, + * which can be provided by the ISP, the ISP can't be completely suspended + * before the sensor. + * + * To solve this problem power management support is split into prepare/complete + * and suspend/resume operations. The pipelines are stopped in prepare() and the + * ISP clocks get disabled in suspend(). Similarly, the clocks are reenabled in + * resume(), and the the pipelines are restarted in complete(). + * + * TODO: PM dependencies between the ISP and sensors are not modeled explicitly + * yet. + */ +static int isp_pm_prepare(struct device *dev) +{ + struct isp_device *isp = dev_get_drvdata(dev); + int reset; + + WARN_ON(mutex_is_locked(&isp->isp_mutex)); + + if (isp->ref_count == 0) + return 0; + + reset = isp_suspend_modules(isp); + isp_disable_interrupts(isp); + isp_save_ctx(isp); + if (reset) + isp_reset(isp); + + return 0; +} + +static int isp_pm_suspend(struct device *dev) +{ + struct isp_device *isp = dev_get_drvdata(dev); + + WARN_ON(mutex_is_locked(&isp->isp_mutex)); + + if (isp->ref_count) + isp_disable_clocks(isp); + + return 0; +} + +static int isp_pm_resume(struct device *dev) +{ + struct isp_device *isp = dev_get_drvdata(dev); + + if (isp->ref_count == 0) + return 0; + + return isp_enable_clocks(isp); +} + +static void isp_pm_complete(struct device *dev) +{ + struct isp_device *isp = dev_get_drvdata(dev); + + if (isp->ref_count == 0) + return; + + isp_restore_ctx(isp); + isp_enable_interrupts(isp); + isp_resume_modules(isp); +} + +#else + +#define isp_pm_prepare NULL +#define isp_pm_suspend NULL +#define isp_pm_resume NULL +#define isp_pm_complete NULL + +#endif /* CONFIG_PM */ + +static void isp_unregister_entities(struct isp_device *isp) +{ + omap3isp_csi2_unregister_entities(&isp->isp_csi2a); + omap3isp_ccp2_unregister_entities(&isp->isp_ccp2); + omap3isp_ccdc_unregister_entities(&isp->isp_ccdc); + omap3isp_preview_unregister_entities(&isp->isp_prev); + omap3isp_resizer_unregister_entities(&isp->isp_res); + omap3isp_stat_unregister_entities(&isp->isp_aewb); + omap3isp_stat_unregister_entities(&isp->isp_af); + omap3isp_stat_unregister_entities(&isp->isp_hist); + + v4l2_device_unregister(&isp->v4l2_dev); + media_device_unregister(&isp->media_dev); +} + +/* + * isp_register_subdev_group - Register a group of subdevices + * @isp: OMAP3 ISP device + * @board_info: I2C subdevs board information array + * + * Register all I2C subdevices in the board_info array. The array must be + * terminated by a NULL entry, and the first entry must be the sensor. + * + * Return a pointer to the sensor media entity if it has been successfully + * registered, or NULL otherwise. + */ +static struct v4l2_subdev * +isp_register_subdev_group(struct isp_device *isp, + struct isp_subdev_i2c_board_info *board_info) +{ + struct v4l2_subdev *sensor = NULL; + unsigned int first; + + if (board_info->board_info == NULL) + return NULL; + + for (first = 1; board_info->board_info; ++board_info, first = 0) { + struct v4l2_subdev *subdev; + struct i2c_adapter *adapter; + + adapter = i2c_get_adapter(board_info->i2c_adapter_id); + if (adapter == NULL) { + printk(KERN_ERR "%s: Unable to get I2C adapter %d for " + "device %s\n", __func__, + board_info->i2c_adapter_id, + board_info->board_info->type); + continue; + } + + subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, + board_info->board_info, NULL); + if (subdev == NULL) { + printk(KERN_ERR "%s: Unable to register subdev %s\n", + __func__, board_info->board_info->type); + continue; + } + + if (first) + sensor = subdev; + } + + return sensor; +} + +static int isp_register_entities(struct isp_device *isp) +{ + struct isp_platform_data *pdata = isp->pdata; + struct isp_v4l2_subdevs_group *subdevs; + int ret; + + isp->media_dev.dev = isp->dev; + strlcpy(isp->media_dev.model, "TI OMAP3 ISP", + sizeof(isp->media_dev.model)); + isp->media_dev.link_notify = isp_pipeline_link_notify; + ret = media_device_register(&isp->media_dev); + if (ret < 0) { + printk(KERN_ERR "%s: Media device registration failed (%d)\n", + __func__, ret); + return ret; + } + + isp->v4l2_dev.mdev = &isp->media_dev; + ret = v4l2_device_register(isp->dev, &isp->v4l2_dev); + if (ret < 0) { + printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n", + __func__, ret); + goto done; + } + + /* Register internal entities */ + ret = omap3isp_ccp2_register_entities(&isp->isp_ccp2, &isp->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap3isp_csi2_register_entities(&isp->isp_csi2a, &isp->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap3isp_ccdc_register_entities(&isp->isp_ccdc, &isp->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap3isp_preview_register_entities(&isp->isp_prev, + &isp->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap3isp_resizer_register_entities(&isp->isp_res, &isp->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap3isp_stat_register_entities(&isp->isp_aewb, &isp->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap3isp_stat_register_entities(&isp->isp_af, &isp->v4l2_dev); + if (ret < 0) + goto done; + + ret = omap3isp_stat_register_entities(&isp->isp_hist, &isp->v4l2_dev); + if (ret < 0) + goto done; + + /* Register external entities */ + for (subdevs = pdata->subdevs; subdevs->subdevs; ++subdevs) { + struct v4l2_subdev *sensor; + struct media_entity *input; + unsigned int flags; + unsigned int pad; + + sensor = isp_register_subdev_group(isp, subdevs->subdevs); + if (sensor == NULL) + continue; + + sensor->host_priv = subdevs; + + /* Connect the sensor to the correct interface module. Parallel + * sensors are connected directly to the CCDC, while serial + * sensors are connected to the CSI2a, CCP2b or CSI2c receiver + * through CSIPHY1 or CSIPHY2. + */ + switch (subdevs->interface) { + case ISP_INTERFACE_PARALLEL: + input = &isp->isp_ccdc.subdev.entity; + pad = CCDC_PAD_SINK; + flags = 0; + break; + + case ISP_INTERFACE_CSI2A_PHY2: + input = &isp->isp_csi2a.subdev.entity; + pad = CSI2_PAD_SINK; + flags = MEDIA_LNK_FL_IMMUTABLE + | MEDIA_LNK_FL_ENABLED; + break; + + case ISP_INTERFACE_CCP2B_PHY1: + case ISP_INTERFACE_CCP2B_PHY2: + input = &isp->isp_ccp2.subdev.entity; + pad = CCP2_PAD_SINK; + flags = 0; + break; + + case ISP_INTERFACE_CSI2C_PHY1: + input = &isp->isp_csi2c.subdev.entity; + pad = CSI2_PAD_SINK; + flags = MEDIA_LNK_FL_IMMUTABLE + | MEDIA_LNK_FL_ENABLED; + break; + + default: + printk(KERN_ERR "%s: invalid interface type %u\n", + __func__, subdevs->interface); + ret = -EINVAL; + goto done; + } + + ret = media_entity_create_link(&sensor->entity, 0, input, pad, + flags); + if (ret < 0) + goto done; + } + + ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); + +done: + if (ret < 0) + isp_unregister_entities(isp); + + return ret; +} + +static void isp_cleanup_modules(struct isp_device *isp) +{ + omap3isp_h3a_aewb_cleanup(isp); + omap3isp_h3a_af_cleanup(isp); + omap3isp_hist_cleanup(isp); + omap3isp_resizer_cleanup(isp); + omap3isp_preview_cleanup(isp); + omap3isp_ccdc_cleanup(isp); + omap3isp_ccp2_cleanup(isp); + omap3isp_csi2_cleanup(isp); +} + +static int isp_initialize_modules(struct isp_device *isp) +{ + int ret; + + ret = omap3isp_csiphy_init(isp); + if (ret < 0) { + dev_err(isp->dev, "CSI PHY initialization failed\n"); + goto error_csiphy; + } + + ret = omap3isp_csi2_init(isp); + if (ret < 0) { + dev_err(isp->dev, "CSI2 initialization failed\n"); + goto error_csi2; + } + + ret = omap3isp_ccp2_init(isp); + if (ret < 0) { + dev_err(isp->dev, "CCP2 initialization failed\n"); + goto error_ccp2; + } + + ret = omap3isp_ccdc_init(isp); + if (ret < 0) { + dev_err(isp->dev, "CCDC initialization failed\n"); + goto error_ccdc; + } + + ret = omap3isp_preview_init(isp); + if (ret < 0) { + dev_err(isp->dev, "Preview initialization failed\n"); + goto error_preview; + } + + ret = omap3isp_resizer_init(isp); + if (ret < 0) { + dev_err(isp->dev, "Resizer initialization failed\n"); + goto error_resizer; + } + + ret = omap3isp_hist_init(isp); + if (ret < 0) { + dev_err(isp->dev, "Histogram initialization failed\n"); + goto error_hist; + } + + ret = omap3isp_h3a_aewb_init(isp); + if (ret < 0) { + dev_err(isp->dev, "H3A AEWB initialization failed\n"); + goto error_h3a_aewb; + } + + ret = omap3isp_h3a_af_init(isp); + if (ret < 0) { + dev_err(isp->dev, "H3A AF initialization failed\n"); + goto error_h3a_af; + } + + /* Connect the submodules. */ + ret = media_entity_create_link( + &isp->isp_csi2a.subdev.entity, CSI2_PAD_SOURCE, + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &isp->isp_ccp2.subdev.entity, CCP2_PAD_SOURCE, + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_prev.subdev.entity, PREV_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_OF, + &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &isp->isp_prev.subdev.entity, PREV_PAD_SOURCE, + &isp->isp_res.subdev.entity, RESZ_PAD_SINK, 0); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_aewb.subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_af.subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) + goto error_link; + + ret = media_entity_create_link( + &isp->isp_ccdc.subdev.entity, CCDC_PAD_SOURCE_VP, + &isp->isp_hist.subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret < 0) + goto error_link; + + return 0; + +error_link: + omap3isp_h3a_af_cleanup(isp); +error_h3a_af: + omap3isp_h3a_aewb_cleanup(isp); +error_h3a_aewb: + omap3isp_hist_cleanup(isp); +error_hist: + omap3isp_resizer_cleanup(isp); +error_resizer: + omap3isp_preview_cleanup(isp); +error_preview: + omap3isp_ccdc_cleanup(isp); +error_ccdc: + omap3isp_ccp2_cleanup(isp); +error_ccp2: + omap3isp_csi2_cleanup(isp); +error_csi2: +error_csiphy: + return ret; +} + +/* + * isp_remove - Remove ISP platform device + * @pdev: Pointer to ISP platform device + * + * Always returns 0. + */ +static int isp_remove(struct platform_device *pdev) +{ + struct isp_device *isp = platform_get_drvdata(pdev); + int i; + + isp_unregister_entities(isp); + isp_cleanup_modules(isp); + + omap3isp_get(isp); + iommu_put(isp->iommu); + omap3isp_put(isp); + + free_irq(isp->irq_num, isp); + isp_put_clocks(isp); + + for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) { + if (isp->mmio_base[i]) { + iounmap(isp->mmio_base[i]); + isp->mmio_base[i] = NULL; + } + + if (isp->mmio_base_phys[i]) { + release_mem_region(isp->mmio_base_phys[i], + isp->mmio_size[i]); + isp->mmio_base_phys[i] = 0; + } + } + + regulator_put(isp->isp_csiphy1.vdd); + regulator_put(isp->isp_csiphy2.vdd); + kfree(isp); + + return 0; +} + +static int isp_map_mem_resource(struct platform_device *pdev, + struct isp_device *isp, + enum isp_mem_resources res) +{ + struct resource *mem; + + /* request the mem region for the camera registers */ + + mem = platform_get_resource(pdev, IORESOURCE_MEM, res); + if (!mem) { + dev_err(isp->dev, "no mem resource?\n"); + return -ENODEV; + } + + if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) { + dev_err(isp->dev, + "cannot reserve camera register I/O region\n"); + return -ENODEV; + } + isp->mmio_base_phys[res] = mem->start; + isp->mmio_size[res] = resource_size(mem); + + /* map the region */ + isp->mmio_base[res] = ioremap_nocache(isp->mmio_base_phys[res], + isp->mmio_size[res]); + if (!isp->mmio_base[res]) { + dev_err(isp->dev, "cannot map camera register I/O region\n"); + return -ENODEV; + } + + return 0; +} + +/* + * isp_probe - Probe ISP platform device + * @pdev: Pointer to ISP platform device + * + * Returns 0 if successful, + * -ENOMEM if no memory available, + * -ENODEV if no platform device resources found + * or no space for remapping registers, + * -EINVAL if couldn't install ISR, + * or clk_get return error value. + */ +static int isp_probe(struct platform_device *pdev) +{ + struct isp_platform_data *pdata = pdev->dev.platform_data; + struct isp_device *isp; + int ret; + int i, m; + + if (pdata == NULL) + return -EINVAL; + + isp = kzalloc(sizeof(*isp), GFP_KERNEL); + if (!isp) { + dev_err(&pdev->dev, "could not allocate memory\n"); + return -ENOMEM; + } + + isp->autoidle = autoidle; + isp->platform_cb.set_xclk = isp_set_xclk; + isp->platform_cb.set_pixel_clock = isp_set_pixel_clock; + + mutex_init(&isp->isp_mutex); + spin_lock_init(&isp->stat_lock); + + isp->dev = &pdev->dev; + isp->pdata = pdata; + isp->ref_count = 0; + + isp->raw_dmamask = DMA_BIT_MASK(32); + isp->dev->dma_mask = &isp->raw_dmamask; + isp->dev->coherent_dma_mask = DMA_BIT_MASK(32); + + platform_set_drvdata(pdev, isp); + + /* Regulators */ + isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1"); + isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2"); + + /* Clocks */ + ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN); + if (ret < 0) + goto error; + + ret = isp_get_clocks(isp); + if (ret < 0) + goto error; + + if (omap3isp_get(isp) == NULL) + goto error; + + ret = isp_reset(isp); + if (ret < 0) + goto error_isp; + + /* Memory resources */ + isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); + dev_info(isp->dev, "Revision %d.%d found\n", + (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); + + for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++) + if (isp->revision == isp_res_maps[m].isp_rev) + break; + + if (m == ARRAY_SIZE(isp_res_maps)) { + dev_err(isp->dev, "No resource map found for ISP rev %d.%d\n", + (isp->revision & 0xf0) >> 4, isp->revision & 0xf); + ret = -ENODEV; + goto error_isp; + } + + for (i = 1; i < OMAP3_ISP_IOMEM_LAST; i++) { + if (isp_res_maps[m].map & 1 << i) { + ret = isp_map_mem_resource(pdev, isp, i); + if (ret) + goto error_isp; + } + } + + /* IOMMU */ + isp->iommu = iommu_get("isp"); + if (IS_ERR_OR_NULL(isp->iommu)) { + isp->iommu = NULL; + ret = -ENODEV; + goto error_isp; + } + + /* Interrupt */ + isp->irq_num = platform_get_irq(pdev, 0); + if (isp->irq_num <= 0) { + dev_err(isp->dev, "No IRQ resource\n"); + ret = -ENODEV; + goto error_isp; + } + + if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED, "OMAP3 ISP", isp)) { + dev_err(isp->dev, "Unable to request IRQ\n"); + ret = -EINVAL; + goto error_isp; + } + + /* Entities */ + ret = isp_initialize_modules(isp); + if (ret < 0) + goto error_irq; + + ret = isp_register_entities(isp); + if (ret < 0) + goto error_modules; + + isp_power_settings(isp, 1); + omap3isp_put(isp); + + return 0; + +error_modules: + isp_cleanup_modules(isp); +error_irq: + free_irq(isp->irq_num, isp); +error_isp: + iommu_put(isp->iommu); + omap3isp_put(isp); +error: + isp_put_clocks(isp); + + for (i = 0; i < OMAP3_ISP_IOMEM_LAST; i++) { + if (isp->mmio_base[i]) { + iounmap(isp->mmio_base[i]); + isp->mmio_base[i] = NULL; + } + + if (isp->mmio_base_phys[i]) { + release_mem_region(isp->mmio_base_phys[i], + isp->mmio_size[i]); + isp->mmio_base_phys[i] = 0; + } + } + regulator_put(isp->isp_csiphy2.vdd); + regulator_put(isp->isp_csiphy1.vdd); + platform_set_drvdata(pdev, NULL); + kfree(isp); + + return ret; +} + +static const struct dev_pm_ops omap3isp_pm_ops = { + .prepare = isp_pm_prepare, + .suspend = isp_pm_suspend, + .resume = isp_pm_resume, + .complete = isp_pm_complete, +}; + +static struct platform_device_id omap3isp_id_table[] = { + { "omap3isp", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(platform, omap3isp_id_table); + +static struct platform_driver omap3isp_driver = { + .probe = isp_probe, + .remove = isp_remove, + .id_table = omap3isp_id_table, + .driver = { + .owner = THIS_MODULE, + .name = "omap3isp", + .pm = &omap3isp_pm_ops, + }, +}; + +/* + * isp_init - ISP module initialization. + */ +static int __init isp_init(void) +{ + return platform_driver_register(&omap3isp_driver); +} + +/* + * isp_cleanup - ISP module cleanup. + */ +static void __exit isp_cleanup(void) +{ + platform_driver_unregister(&omap3isp_driver); +} + +module_init(isp_init); +module_exit(isp_cleanup); + +MODULE_AUTHOR("Nokia Corporation"); +MODULE_DESCRIPTION("TI OMAP3 ISP driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h new file mode 100644 index 000000000000..a8dfea413d34 --- /dev/null +++ b/drivers/media/video/omap3isp/isp.h @@ -0,0 +1,430 @@ +/* + * isp.h + * + * TI OMAP3 ISP - Core + * + * Copyright (C) 2009-2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_CORE_H +#define OMAP3_ISP_CORE_H + +#include +#include +#include +#include +#include +#include +#include + +#include "ispstat.h" +#include "ispccdc.h" +#include "ispreg.h" +#include "ispresizer.h" +#include "isppreview.h" +#include "ispcsiphy.h" +#include "ispcsi2.h" +#include "ispccp2.h" + +#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) + +#define ISP_TOK_TERM 0xFFFFFFFF /* + * terminating token for ISP + * modules reg list + */ +#define to_isp_device(ptr_module) \ + container_of(ptr_module, struct isp_device, isp_##ptr_module) +#define to_device(ptr_module) \ + (to_isp_device(ptr_module)->dev) + +enum isp_mem_resources { + OMAP3_ISP_IOMEM_MAIN, + OMAP3_ISP_IOMEM_CCP2, + OMAP3_ISP_IOMEM_CCDC, + OMAP3_ISP_IOMEM_HIST, + OMAP3_ISP_IOMEM_H3A, + OMAP3_ISP_IOMEM_PREV, + OMAP3_ISP_IOMEM_RESZ, + OMAP3_ISP_IOMEM_SBL, + OMAP3_ISP_IOMEM_CSI2A_REGS1, + OMAP3_ISP_IOMEM_CSIPHY2, + OMAP3_ISP_IOMEM_CSI2A_REGS2, + OMAP3_ISP_IOMEM_CSI2C_REGS1, + OMAP3_ISP_IOMEM_CSIPHY1, + OMAP3_ISP_IOMEM_CSI2C_REGS2, + OMAP3_ISP_IOMEM_LAST +}; + +enum isp_sbl_resource { + OMAP3_ISP_SBL_CSI1_READ = 0x1, + OMAP3_ISP_SBL_CSI1_WRITE = 0x2, + OMAP3_ISP_SBL_CSI2A_WRITE = 0x4, + OMAP3_ISP_SBL_CSI2C_WRITE = 0x8, + OMAP3_ISP_SBL_CCDC_LSC_READ = 0x10, + OMAP3_ISP_SBL_CCDC_WRITE = 0x20, + OMAP3_ISP_SBL_PREVIEW_READ = 0x40, + OMAP3_ISP_SBL_PREVIEW_WRITE = 0x80, + OMAP3_ISP_SBL_RESIZER_READ = 0x100, + OMAP3_ISP_SBL_RESIZER_WRITE = 0x200, +}; + +enum isp_subclk_resource { + OMAP3_ISP_SUBCLK_CCDC = (1 << 0), + OMAP3_ISP_SUBCLK_H3A = (1 << 1), + OMAP3_ISP_SUBCLK_HIST = (1 << 2), + OMAP3_ISP_SUBCLK_PREVIEW = (1 << 3), + OMAP3_ISP_SUBCLK_RESIZER = (1 << 4), +}; + +enum isp_interface_type { + ISP_INTERFACE_PARALLEL, + ISP_INTERFACE_CSI2A_PHY2, + ISP_INTERFACE_CCP2B_PHY1, + ISP_INTERFACE_CCP2B_PHY2, + ISP_INTERFACE_CSI2C_PHY1, +}; + +/* ISP: OMAP 34xx ES 1.0 */ +#define ISP_REVISION_1_0 0x10 +/* ISP2: OMAP 34xx ES 2.0, 2.1 and 3.0 */ +#define ISP_REVISION_2_0 0x20 +/* ISP2P: OMAP 36xx */ +#define ISP_REVISION_15_0 0xF0 + +/* + * struct isp_res_mapping - Map ISP io resources to ISP revision. + * @isp_rev: ISP_REVISION_x_x + * @map: bitmap for enum isp_mem_resources + */ +struct isp_res_mapping { + u32 isp_rev; + u32 map; +}; + +/* + * struct isp_reg - Structure for ISP register values. + * @reg: 32-bit Register address. + * @val: 32-bit Register value. + */ +struct isp_reg { + enum isp_mem_resources mmio_range; + u32 reg; + u32 val; +}; + +/** + * struct isp_parallel_platform_data - Parallel interface platform data + * @width: Parallel bus width in bits (8, 10, 11 or 12) + * @data_lane_shift: Data lane shifter + * 0 - CAMEXT[13:0] -> CAM[13:0] + * 1 - CAMEXT[13:2] -> CAM[11:0] + * 2 - CAMEXT[13:4] -> CAM[9:0] + * 3 - CAMEXT[13:6] -> CAM[7:0] + * @clk_pol: Pixel clock polarity + * 0 - Non Inverted, 1 - Inverted + * @bridge: CCDC Bridge input control + * ISPCTRL_PAR_BRIDGE_DISABLE - Disable + * ISPCTRL_PAR_BRIDGE_LENDIAN - Little endian + * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian + */ +struct isp_parallel_platform_data { + unsigned int width; + unsigned int data_lane_shift:2; + unsigned int clk_pol:1; + unsigned int bridge:4; +}; + +/** + * struct isp_ccp2_platform_data - CCP2 interface platform data + * @strobe_clk_pol: Strobe/clock polarity + * 0 - Non Inverted, 1 - Inverted + * @crc: Enable the cyclic redundancy check + * @ccp2_mode: Enable CCP2 compatibility mode + * 0 - MIPI-CSI1 mode, 1 - CCP2 mode + * @phy_layer: Physical layer selection + * ISPCCP2_CTRL_PHY_SEL_CLOCK - Data/clock physical layer + * ISPCCP2_CTRL_PHY_SEL_STROBE - Data/strobe physical layer + * @vpclk_div: Video port output clock control + */ +struct isp_ccp2_platform_data { + unsigned int strobe_clk_pol:1; + unsigned int crc:1; + unsigned int ccp2_mode:1; + unsigned int phy_layer:1; + unsigned int vpclk_div:2; +}; + +/** + * struct isp_csi2_platform_data - CSI2 interface platform data + * @crc: Enable the cyclic redundancy check + * @vpclk_div: Video port output clock control + */ +struct isp_csi2_platform_data { + unsigned crc:1; + unsigned vpclk_div:2; +}; + +struct isp_subdev_i2c_board_info { + struct i2c_board_info *board_info; + int i2c_adapter_id; +}; + +struct isp_v4l2_subdevs_group { + struct isp_subdev_i2c_board_info *subdevs; + enum isp_interface_type interface; + union { + struct isp_parallel_platform_data parallel; + struct isp_ccp2_platform_data ccp2; + struct isp_csi2_platform_data csi2; + } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */ +}; + +struct isp_platform_data { + struct isp_v4l2_subdevs_group *subdevs; +}; + +struct isp_platform_callback { + u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel); + int (*csiphy_config)(struct isp_csiphy *phy, + struct isp_csiphy_dphy_cfg *dphy, + struct isp_csiphy_lanes_cfg *lanes); + void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk); +}; + +/* + * struct isp_device - ISP device structure. + * @dev: Device pointer specific to the OMAP3 ISP. + * @revision: Stores current ISP module revision. + * @irq_num: Currently used IRQ number. + * @mmio_base: Array with kernel base addresses for ioremapped ISP register + * regions. + * @mmio_base_phys: Array with physical L4 bus addresses for ISP register + * regions. + * @mmio_size: Array with ISP register regions size in bytes. + * @raw_dmamask: Raw DMA mask + * @stat_lock: Spinlock for handling statistics + * @isp_mutex: Mutex for serializing requests to ISP. + * @has_context: Context has been saved at least once and can be restored. + * @ref_count: Reference count for handling multiple ISP requests. + * @cam_ick: Pointer to camera interface clock structure. + * @cam_mclk: Pointer to camera functional clock structure. + * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure. + * @csi2_fck: Pointer to camera CSI2 complexIO clock structure. + * @l3_ick: Pointer to OMAP3 L3 bus interface clock. + * @irq: Currently attached ISP ISR callbacks information structure. + * @isp_af: Pointer to current settings for ISP AutoFocus SCM. + * @isp_hist: Pointer to current settings for ISP Histogram SCM. + * @isp_h3a: Pointer to current settings for ISP Auto Exposure and + * White Balance SCM. + * @isp_res: Pointer to current settings for ISP Resizer. + * @isp_prev: Pointer to current settings for ISP Preview. + * @isp_ccdc: Pointer to current settings for ISP CCDC. + * @iommu: Pointer to requested IOMMU instance for ISP. + * @platform_cb: ISP driver callback function pointers for platform code + * + * This structure is used to store the OMAP ISP Information. + */ +struct isp_device { + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct device *dev; + u32 revision; + + /* platform HW resources */ + struct isp_platform_data *pdata; + unsigned int irq_num; + + void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST]; + unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST]; + resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST]; + + u64 raw_dmamask; + + /* ISP Obj */ + spinlock_t stat_lock; /* common lock for statistic drivers */ + struct mutex isp_mutex; /* For handling ref_count field */ + int has_context; + int ref_count; + unsigned int autoidle; + u32 xclk_divisor[2]; /* Two clocks, a and b. */ +#define ISP_CLK_CAM_ICK 0 +#define ISP_CLK_CAM_MCLK 1 +#define ISP_CLK_DPLL4_M5_CK 2 +#define ISP_CLK_CSI2_FCK 3 +#define ISP_CLK_L3_ICK 4 + struct clk *clock[5]; + + /* ISP modules */ + struct ispstat isp_af; + struct ispstat isp_aewb; + struct ispstat isp_hist; + struct isp_res_device isp_res; + struct isp_prev_device isp_prev; + struct isp_ccdc_device isp_ccdc; + struct isp_csi2_device isp_csi2a; + struct isp_csi2_device isp_csi2c; + struct isp_ccp2_device isp_ccp2; + struct isp_csiphy isp_csiphy1; + struct isp_csiphy isp_csiphy2; + + unsigned int sbl_resources; + unsigned int subclk_resources; + + struct iommu *iommu; + + struct isp_platform_callback platform_cb; +}; + +#define v4l2_dev_to_isp_device(dev) \ + container_of(dev, struct isp_device, v4l2_dev) + +void omap3isp_hist_dma_done(struct isp_device *isp); + +void omap3isp_flush(struct isp_device *isp); + +int omap3isp_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait, + atomic_t *stopping); + +int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait, + atomic_t *stopping); + +int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, + enum isp_pipeline_stream_state state); +void omap3isp_configure_bridge(struct isp_device *isp, + enum ccdc_input_entity input, + const struct isp_parallel_platform_data *pdata); + +#define ISP_XCLK_NONE -1 +#define ISP_XCLK_A 0 +#define ISP_XCLK_B 1 + +struct isp_device *omap3isp_get(struct isp_device *isp); +void omap3isp_put(struct isp_device *isp); + +void omap3isp_print_status(struct isp_device *isp); + +void omap3isp_sbl_enable(struct isp_device *isp, enum isp_sbl_resource res); +void omap3isp_sbl_disable(struct isp_device *isp, enum isp_sbl_resource res); + +void omap3isp_subclk_enable(struct isp_device *isp, + enum isp_subclk_resource res); +void omap3isp_subclk_disable(struct isp_device *isp, + enum isp_subclk_resource res); + +int omap3isp_pipeline_pm_use(struct media_entity *entity, int use); + +int omap3isp_register_entities(struct platform_device *pdev, + struct v4l2_device *v4l2_dev); +void omap3isp_unregister_entities(struct platform_device *pdev); + +/* + * isp_reg_readl - Read value of an OMAP3 ISP register + * @dev: Device pointer specific to the OMAP3 ISP. + * @isp_mmio_range: Range to which the register offset refers to. + * @reg_offset: Register offset to read from. + * + * Returns an unsigned 32 bit value with the required register contents. + */ +static inline +u32 isp_reg_readl(struct isp_device *isp, enum isp_mem_resources isp_mmio_range, + u32 reg_offset) +{ + return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset); +} + +/* + * isp_reg_writel - Write value to an OMAP3 ISP register + * @dev: Device pointer specific to the OMAP3 ISP. + * @reg_value: 32 bit value to write to the register. + * @isp_mmio_range: Range to which the register offset refers to. + * @reg_offset: Register offset to write into. + */ +static inline +void isp_reg_writel(struct isp_device *isp, u32 reg_value, + enum isp_mem_resources isp_mmio_range, u32 reg_offset) +{ + __raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset); +} + +/* + * isp_reg_and - Clear individual bits in an OMAP3 ISP register + * @dev: Device pointer specific to the OMAP3 ISP. + * @mmio_range: Range to which the register offset refers to. + * @reg: Register offset to work on. + * @clr_bits: 32 bit value which would be cleared in the register. + */ +static inline +void isp_reg_clr(struct isp_device *isp, enum isp_mem_resources mmio_range, + u32 reg, u32 clr_bits) +{ + u32 v = isp_reg_readl(isp, mmio_range, reg); + + isp_reg_writel(isp, v & ~clr_bits, mmio_range, reg); +} + +/* + * isp_reg_set - Set individual bits in an OMAP3 ISP register + * @dev: Device pointer specific to the OMAP3 ISP. + * @mmio_range: Range to which the register offset refers to. + * @reg: Register offset to work on. + * @set_bits: 32 bit value which would be set in the register. + */ +static inline +void isp_reg_set(struct isp_device *isp, enum isp_mem_resources mmio_range, + u32 reg, u32 set_bits) +{ + u32 v = isp_reg_readl(isp, mmio_range, reg); + + isp_reg_writel(isp, v | set_bits, mmio_range, reg); +} + +/* + * isp_reg_clr_set - Clear and set invidial bits in an OMAP3 ISP register + * @dev: Device pointer specific to the OMAP3 ISP. + * @mmio_range: Range to which the register offset refers to. + * @reg: Register offset to work on. + * @clr_bits: 32 bit value which would be cleared in the register. + * @set_bits: 32 bit value which would be set in the register. + * + * The clear operation is done first, and then the set operation. + */ +static inline +void isp_reg_clr_set(struct isp_device *isp, enum isp_mem_resources mmio_range, + u32 reg, u32 clr_bits, u32 set_bits) +{ + u32 v = isp_reg_readl(isp, mmio_range, reg); + + isp_reg_writel(isp, (v & ~clr_bits) | set_bits, mmio_range, reg); +} + +static inline enum v4l2_buf_type +isp_pad_buffer_type(const struct v4l2_subdev *subdev, int pad) +{ + if (pad >= subdev->entity.num_pads) + return 0; + + if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SINK) + return V4L2_BUF_TYPE_VIDEO_OUTPUT; + else + return V4L2_BUF_TYPE_VIDEO_CAPTURE; +} + +#endif /* OMAP3_ISP_CORE_H */ diff --git a/drivers/media/video/omap3isp/ispreg.h b/drivers/media/video/omap3isp/ispreg.h new file mode 100644 index 000000000000..69f6af6f6b9c --- /dev/null +++ b/drivers/media/video/omap3isp/ispreg.h @@ -0,0 +1,1589 @@ +/* + * ispreg.h + * + * TI OMAP3 ISP - Registers definitions + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_REG_H +#define OMAP3_ISP_REG_H + +#include + + +#define CM_CAM_MCLK_HZ 172800000 /* Hz */ + +/* ISP Submodules offset */ + +#define OMAP3ISP_REG_BASE OMAP3430_ISP_BASE +#define OMAP3ISP_REG(offset) (OMAP3ISP_REG_BASE + (offset)) + +#define OMAP3ISP_CCP2_REG_OFFSET 0x0400 +#define OMAP3ISP_CCP2_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CCP2_REG_OFFSET) +#define OMAP3ISP_CCP2_REG(offset) (OMAP3ISP_CCP2_REG_BASE + (offset)) + +#define OMAP3ISP_CCDC_REG_OFFSET 0x0600 +#define OMAP3ISP_CCDC_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CCDC_REG_OFFSET) +#define OMAP3ISP_CCDC_REG(offset) (OMAP3ISP_CCDC_REG_BASE + (offset)) + +#define OMAP3ISP_HIST_REG_OFFSET 0x0A00 +#define OMAP3ISP_HIST_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_HIST_REG_OFFSET) +#define OMAP3ISP_HIST_REG(offset) (OMAP3ISP_HIST_REG_BASE + (offset)) + +#define OMAP3ISP_H3A_REG_OFFSET 0x0C00 +#define OMAP3ISP_H3A_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_H3A_REG_OFFSET) +#define OMAP3ISP_H3A_REG(offset) (OMAP3ISP_H3A_REG_BASE + (offset)) + +#define OMAP3ISP_PREV_REG_OFFSET 0x0E00 +#define OMAP3ISP_PREV_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_PREV_REG_OFFSET) +#define OMAP3ISP_PREV_REG(offset) (OMAP3ISP_PREV_REG_BASE + (offset)) + +#define OMAP3ISP_RESZ_REG_OFFSET 0x1000 +#define OMAP3ISP_RESZ_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_RESZ_REG_OFFSET) +#define OMAP3ISP_RESZ_REG(offset) (OMAP3ISP_RESZ_REG_BASE + (offset)) + +#define OMAP3ISP_SBL_REG_OFFSET 0x1200 +#define OMAP3ISP_SBL_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_SBL_REG_OFFSET) +#define OMAP3ISP_SBL_REG(offset) (OMAP3ISP_SBL_REG_BASE + (offset)) + +#define OMAP3ISP_CSI2A_REGS1_REG_OFFSET 0x1800 +#define OMAP3ISP_CSI2A_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CSI2A_REGS1_REG_OFFSET) +#define OMAP3ISP_CSI2A_REGS1_REG(offset) \ + (OMAP3ISP_CSI2A_REGS1_REG_BASE + (offset)) + +#define OMAP3ISP_CSIPHY2_REG_OFFSET 0x1970 +#define OMAP3ISP_CSIPHY2_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CSIPHY2_REG_OFFSET) +#define OMAP3ISP_CSIPHY2_REG(offset) (OMAP3ISP_CSIPHY2_REG_BASE + (offset)) + +#define OMAP3ISP_CSI2A_REGS2_REG_OFFSET 0x19C0 +#define OMAP3ISP_CSI2A_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CSI2A_REGS2_REG_OFFSET) +#define OMAP3ISP_CSI2A_REGS2_REG(offset) \ + (OMAP3ISP_CSI2A_REGS2_REG_BASE + (offset)) + +#define OMAP3ISP_CSI2C_REGS1_REG_OFFSET 0x1C00 +#define OMAP3ISP_CSI2C_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CSI2C_REGS1_REG_OFFSET) +#define OMAP3ISP_CSI2C_REGS1_REG(offset) \ + (OMAP3ISP_CSI2C_REGS1_REG_BASE + (offset)) + +#define OMAP3ISP_CSIPHY1_REG_OFFSET 0x1D70 +#define OMAP3ISP_CSIPHY1_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CSIPHY1_REG_OFFSET) +#define OMAP3ISP_CSIPHY1_REG(offset) (OMAP3ISP_CSIPHY1_REG_BASE + (offset)) + +#define OMAP3ISP_CSI2C_REGS2_REG_OFFSET 0x1DC0 +#define OMAP3ISP_CSI2C_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \ + OMAP3ISP_CSI2C_REGS2_REG_OFFSET) +#define OMAP3ISP_CSI2C_REGS2_REG(offset) \ + (OMAP3ISP_CSI2C_REGS2_REG_BASE + (offset)) + +/* ISP module register offset */ + +#define ISP_REVISION (0x000) +#define ISP_SYSCONFIG (0x004) +#define ISP_SYSSTATUS (0x008) +#define ISP_IRQ0ENABLE (0x00C) +#define ISP_IRQ0STATUS (0x010) +#define ISP_IRQ1ENABLE (0x014) +#define ISP_IRQ1STATUS (0x018) +#define ISP_TCTRL_GRESET_LENGTH (0x030) +#define ISP_TCTRL_PSTRB_REPLAY (0x034) +#define ISP_CTRL (0x040) +#define ISP_SECURE (0x044) +#define ISP_TCTRL_CTRL (0x050) +#define ISP_TCTRL_FRAME (0x054) +#define ISP_TCTRL_PSTRB_DELAY (0x058) +#define ISP_TCTRL_STRB_DELAY (0x05C) +#define ISP_TCTRL_SHUT_DELAY (0x060) +#define ISP_TCTRL_PSTRB_LENGTH (0x064) +#define ISP_TCTRL_STRB_LENGTH (0x068) +#define ISP_TCTRL_SHUT_LENGTH (0x06C) +#define ISP_PING_PONG_ADDR (0x070) +#define ISP_PING_PONG_MEM_RANGE (0x074) +#define ISP_PING_PONG_BUF_SIZE (0x078) + +/* CCP2 receiver registers */ + +#define ISPCCP2_REVISION (0x000) +#define ISPCCP2_SYSCONFIG (0x004) +#define ISPCCP2_SYSCONFIG_SOFT_RESET (1 << 1) +#define ISPCCP2_SYSCONFIG_AUTO_IDLE 0x1 +#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12 +#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_FORCE \ + (0x0 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT) +#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_NO \ + (0x1 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT) +#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART \ + (0x2 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT) +#define ISPCCP2_SYSSTATUS (0x008) +#define ISPCCP2_SYSSTATUS_RESET_DONE (1 << 0) +#define ISPCCP2_LC01_IRQENABLE (0x00C) +#define ISPCCP2_LC01_IRQSTATUS (0x010) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ (1 << 11) +#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ (1 << 10) +#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ (1 << 9) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ (1 << 8) +#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ (1 << 7) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ (1 << 5) +#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ (1 << 4) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ (1 << 3) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ (1 << 2) +#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ (1 << 1) +#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ (1 << 0) + +#define ISPCCP2_LC23_IRQENABLE (0x014) +#define ISPCCP2_LC23_IRQSTATUS (0x018) +#define ISPCCP2_LCM_IRQENABLE (0x02C) +#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ (1 << 0) +#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ (1 << 1) +#define ISPCCP2_LCM_IRQSTATUS (0x030) +#define ISPCCP2_CTRL (0x040) +#define ISPCCP2_CTRL_IF_EN (1 << 0) +#define ISPCCP2_CTRL_PHY_SEL (1 << 1) +#define ISPCCP2_CTRL_PHY_SEL_CLOCK (0 << 1) +#define ISPCCP2_CTRL_PHY_SEL_STROBE (1 << 1) +#define ISPCCP2_CTRL_PHY_SEL_MASK 0x1 +#define ISPCCP2_CTRL_PHY_SEL_SHIFT 1 +#define ISPCCP2_CTRL_IO_OUT_SEL (1 << 2) +#define ISPCCP2_CTRL_MODE (1 << 4) +#define ISPCCP2_CTRL_VP_CLK_FORCE_ON (1 << 9) +#define ISPCCP2_CTRL_INV (1 << 10) +#define ISPCCP2_CTRL_INV_MASK 0x1 +#define ISPCCP2_CTRL_INV_SHIFT 10 +#define ISPCCP2_CTRL_VP_ONLY_EN (1 << 11) +#define ISPCCP2_CTRL_VP_CLK_POL (1 << 12) +#define ISPCCP2_CTRL_VPCLK_DIV_SHIFT 15 +#define ISPCCP2_CTRL_VPCLK_DIV_MASK 0x1ffff /* [31:15] */ +#define ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT 8 /* 3430 bits */ +#define ISPCCP2_CTRL_VP_OUT_CTRL_MASK 0x3 /* 3430 bits */ +#define ISPCCP2_DBG (0x044) +#define ISPCCP2_GNQ (0x048) +#define ISPCCP2_LCx_CTRL(x) ((0x050)+0x30*(x)) +#define ISPCCP2_LCx_CTRL_CHAN_EN (1 << 0) +#define ISPCCP2_LCx_CTRL_CRC_EN (1 << 19) +#define ISPCCP2_LCx_CTRL_CRC_MASK 0x1 +#define ISPCCP2_LCx_CTRL_CRC_SHIFT 2 +#define ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0 19 +#define ISPCCP2_LCx_CTRL_REGION_EN (1 << 1) +#define ISPCCP2_LCx_CTRL_REGION_MASK 0x1 +#define ISPCCP2_LCx_CTRL_REGION_SHIFT 1 +#define ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0 0x3f +#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0 0x2 +#define ISPCCP2_LCx_CTRL_FORMAT_MASK 0x1f +#define ISPCCP2_LCx_CTRL_FORMAT_SHIFT 0x3 +#define ISPCCP2_LCx_CODE(x) ((0x054)+0x30*(x)) +#define ISPCCP2_LCx_STAT_START(x) ((0x058)+0x30*(x)) +#define ISPCCP2_LCx_STAT_SIZE(x) ((0x05C)+0x30*(x)) +#define ISPCCP2_LCx_SOF_ADDR(x) ((0x060)+0x30*(x)) +#define ISPCCP2_LCx_EOF_ADDR(x) ((0x064)+0x30*(x)) +#define ISPCCP2_LCx_DAT_START(x) ((0x068)+0x30*(x)) +#define ISPCCP2_LCx_DAT_SIZE(x) ((0x06C)+0x30*(x)) +#define ISPCCP2_LCx_DAT_MASK 0xFFF +#define ISPCCP2_LCx_DAT_SHIFT 16 +#define ISPCCP2_LCx_DAT_PING_ADDR(x) ((0x070)+0x30*(x)) +#define ISPCCP2_LCx_DAT_PONG_ADDR(x) ((0x074)+0x30*(x)) +#define ISPCCP2_LCx_DAT_OFST(x) ((0x078)+0x30*(x)) +#define ISPCCP2_LCM_CTRL (0x1D0) +#define ISPCCP2_LCM_CTRL_CHAN_EN (1 << 0) +#define ISPCCP2_LCM_CTRL_DST_PORT (1 << 2) +#define ISPCCP2_LCM_CTRL_DST_PORT_SHIFT 2 +#define ISPCCP2_LCM_CTRL_READ_THROTTLE_SHIFT 3 +#define ISPCCP2_LCM_CTRL_READ_THROTTLE_MASK 0x11 +#define ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT 5 +#define ISPCCP2_LCM_CTRL_BURST_SIZE_MASK 0x7 +#define ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT 16 +#define ISPCCP2_LCM_CTRL_SRC_FORMAT_MASK 0x7 +#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT 20 +#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_MASK 0x3 +#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED (1 << 22) +#define ISPCCP2_LCM_CTRL_SRC_PACK (1 << 23) +#define ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT 24 +#define ISPCCP2_LCM_CTRL_DST_FORMAT_MASK 0x7 +#define ISPCCP2_LCM_VSIZE (0x1D4) +#define ISPCCP2_LCM_VSIZE_SHIFT 16 +#define ISPCCP2_LCM_HSIZE (0x1D8) +#define ISPCCP2_LCM_HSIZE_SHIFT 16 +#define ISPCCP2_LCM_PREFETCH (0x1DC) +#define ISPCCP2_LCM_PREFETCH_SHIFT 3 +#define ISPCCP2_LCM_SRC_ADDR (0x1E0) +#define ISPCCP2_LCM_SRC_OFST (0x1E4) +#define ISPCCP2_LCM_DST_ADDR (0x1E8) +#define ISPCCP2_LCM_DST_OFST (0x1EC) + +/* CCDC module register offset */ + +#define ISPCCDC_PID (0x000) +#define ISPCCDC_PCR (0x004) +#define ISPCCDC_SYN_MODE (0x008) +#define ISPCCDC_HD_VD_WID (0x00C) +#define ISPCCDC_PIX_LINES (0x010) +#define ISPCCDC_HORZ_INFO (0x014) +#define ISPCCDC_VERT_START (0x018) +#define ISPCCDC_VERT_LINES (0x01C) +#define ISPCCDC_CULLING (0x020) +#define ISPCCDC_HSIZE_OFF (0x024) +#define ISPCCDC_SDOFST (0x028) +#define ISPCCDC_SDR_ADDR (0x02C) +#define ISPCCDC_CLAMP (0x030) +#define ISPCCDC_DCSUB (0x034) +#define ISPCCDC_COLPTN (0x038) +#define ISPCCDC_BLKCMP (0x03C) +#define ISPCCDC_FPC (0x040) +#define ISPCCDC_FPC_ADDR (0x044) +#define ISPCCDC_VDINT (0x048) +#define ISPCCDC_ALAW (0x04C) +#define ISPCCDC_REC656IF (0x050) +#define ISPCCDC_CFG (0x054) +#define ISPCCDC_FMTCFG (0x058) +#define ISPCCDC_FMT_HORZ (0x05C) +#define ISPCCDC_FMT_VERT (0x060) +#define ISPCCDC_FMT_ADDR0 (0x064) +#define ISPCCDC_FMT_ADDR1 (0x068) +#define ISPCCDC_FMT_ADDR2 (0x06C) +#define ISPCCDC_FMT_ADDR3 (0x070) +#define ISPCCDC_FMT_ADDR4 (0x074) +#define ISPCCDC_FMT_ADDR5 (0x078) +#define ISPCCDC_FMT_ADDR6 (0x07C) +#define ISPCCDC_FMT_ADDR7 (0x080) +#define ISPCCDC_PRGEVEN0 (0x084) +#define ISPCCDC_PRGEVEN1 (0x088) +#define ISPCCDC_PRGODD0 (0x08C) +#define ISPCCDC_PRGODD1 (0x090) +#define ISPCCDC_VP_OUT (0x094) + +#define ISPCCDC_LSC_CONFIG (0x098) +#define ISPCCDC_LSC_INITIAL (0x09C) +#define ISPCCDC_LSC_TABLE_BASE (0x0A0) +#define ISPCCDC_LSC_TABLE_OFFSET (0x0A4) + +/* SBL */ +#define ISPSBL_PCR 0x4 +#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF (1 << 16) +#define ISPSBL_PCR_H3A_AF_WBL_OVF (1 << 17) +#define ISPSBL_PCR_RSZ4_WBL_OVF (1 << 18) +#define ISPSBL_PCR_RSZ3_WBL_OVF (1 << 19) +#define ISPSBL_PCR_RSZ2_WBL_OVF (1 << 20) +#define ISPSBL_PCR_RSZ1_WBL_OVF (1 << 21) +#define ISPSBL_PCR_PRV_WBL_OVF (1 << 22) +#define ISPSBL_PCR_CCDC_WBL_OVF (1 << 23) +#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF (1 << 24) +#define ISPSBL_PCR_CSIA_WBL_OVF (1 << 25) +#define ISPSBL_PCR_CSIB_WBL_OVF (1 << 26) +#define ISPSBL_CCDC_WR_0 (0x028) +#define ISPSBL_CCDC_WR_0_DATA_READY (1 << 21) +#define ISPSBL_CCDC_WR_1 (0x02C) +#define ISPSBL_CCDC_WR_2 (0x030) +#define ISPSBL_CCDC_WR_3 (0x034) + +#define ISPSBL_SDR_REQ_EXP 0xF8 +#define ISPSBL_SDR_REQ_HIST_EXP_SHIFT 0 +#define ISPSBL_SDR_REQ_HIST_EXP_MASK (0x3FF) +#define ISPSBL_SDR_REQ_RSZ_EXP_SHIFT 10 +#define ISPSBL_SDR_REQ_RSZ_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT) +#define ISPSBL_SDR_REQ_PRV_EXP_SHIFT 20 +#define ISPSBL_SDR_REQ_PRV_EXP_MASK (0x3FF << ISPSBL_SDR_REQ_PRV_EXP_SHIFT) + +/* Histogram registers */ +#define ISPHIST_PID (0x000) +#define ISPHIST_PCR (0x004) +#define ISPHIST_CNT (0x008) +#define ISPHIST_WB_GAIN (0x00C) +#define ISPHIST_R0_HORZ (0x010) +#define ISPHIST_R0_VERT (0x014) +#define ISPHIST_R1_HORZ (0x018) +#define ISPHIST_R1_VERT (0x01C) +#define ISPHIST_R2_HORZ (0x020) +#define ISPHIST_R2_VERT (0x024) +#define ISPHIST_R3_HORZ (0x028) +#define ISPHIST_R3_VERT (0x02C) +#define ISPHIST_ADDR (0x030) +#define ISPHIST_DATA (0x034) +#define ISPHIST_RADD (0x038) +#define ISPHIST_RADD_OFF (0x03C) +#define ISPHIST_H_V_INFO (0x040) + +/* H3A module registers */ +#define ISPH3A_PID (0x000) +#define ISPH3A_PCR (0x004) +#define ISPH3A_AEWWIN1 (0x04C) +#define ISPH3A_AEWINSTART (0x050) +#define ISPH3A_AEWINBLK (0x054) +#define ISPH3A_AEWSUBWIN (0x058) +#define ISPH3A_AEWBUFST (0x05C) +#define ISPH3A_AFPAX1 (0x008) +#define ISPH3A_AFPAX2 (0x00C) +#define ISPH3A_AFPAXSTART (0x010) +#define ISPH3A_AFIIRSH (0x014) +#define ISPH3A_AFBUFST (0x018) +#define ISPH3A_AFCOEF010 (0x01C) +#define ISPH3A_AFCOEF032 (0x020) +#define ISPH3A_AFCOEF054 (0x024) +#define ISPH3A_AFCOEF076 (0x028) +#define ISPH3A_AFCOEF098 (0x02C) +#define ISPH3A_AFCOEF0010 (0x030) +#define ISPH3A_AFCOEF110 (0x034) +#define ISPH3A_AFCOEF132 (0x038) +#define ISPH3A_AFCOEF154 (0x03C) +#define ISPH3A_AFCOEF176 (0x040) +#define ISPH3A_AFCOEF198 (0x044) +#define ISPH3A_AFCOEF1010 (0x048) + +#define ISPPRV_PCR (0x004) +#define ISPPRV_HORZ_INFO (0x008) +#define ISPPRV_VERT_INFO (0x00C) +#define ISPPRV_RSDR_ADDR (0x010) +#define ISPPRV_RADR_OFFSET (0x014) +#define ISPPRV_DSDR_ADDR (0x018) +#define ISPPRV_DRKF_OFFSET (0x01C) +#define ISPPRV_WSDR_ADDR (0x020) +#define ISPPRV_WADD_OFFSET (0x024) +#define ISPPRV_AVE (0x028) +#define ISPPRV_HMED (0x02C) +#define ISPPRV_NF (0x030) +#define ISPPRV_WB_DGAIN (0x034) +#define ISPPRV_WBGAIN (0x038) +#define ISPPRV_WBSEL (0x03C) +#define ISPPRV_CFA (0x040) +#define ISPPRV_BLKADJOFF (0x044) +#define ISPPRV_RGB_MAT1 (0x048) +#define ISPPRV_RGB_MAT2 (0x04C) +#define ISPPRV_RGB_MAT3 (0x050) +#define ISPPRV_RGB_MAT4 (0x054) +#define ISPPRV_RGB_MAT5 (0x058) +#define ISPPRV_RGB_OFF1 (0x05C) +#define ISPPRV_RGB_OFF2 (0x060) +#define ISPPRV_CSC0 (0x064) +#define ISPPRV_CSC1 (0x068) +#define ISPPRV_CSC2 (0x06C) +#define ISPPRV_CSC_OFFSET (0x070) +#define ISPPRV_CNT_BRT (0x074) +#define ISPPRV_CSUP (0x078) +#define ISPPRV_SETUP_YC (0x07C) +#define ISPPRV_SET_TBL_ADDR (0x080) +#define ISPPRV_SET_TBL_DATA (0x084) +#define ISPPRV_CDC_THR0 (0x090) +#define ISPPRV_CDC_THR1 (ISPPRV_CDC_THR0 + (0x4)) +#define ISPPRV_CDC_THR2 (ISPPRV_CDC_THR0 + (0x4) * 2) +#define ISPPRV_CDC_THR3 (ISPPRV_CDC_THR0 + (0x4) * 3) + +#define ISPPRV_REDGAMMA_TABLE_ADDR 0x0000 +#define ISPPRV_GREENGAMMA_TABLE_ADDR 0x0400 +#define ISPPRV_BLUEGAMMA_TABLE_ADDR 0x0800 +#define ISPPRV_NF_TABLE_ADDR 0x0C00 +#define ISPPRV_YENH_TABLE_ADDR 0x1000 +#define ISPPRV_CFA_TABLE_ADDR 0x1400 + +#define ISPPRV_MAXOUTPUT_WIDTH 1280 +#define ISPPRV_MAXOUTPUT_WIDTH_ES2 3300 +#define ISPPRV_MAXOUTPUT_WIDTH_3630 4096 +#define ISPRSZ_MIN_OUTPUT 64 +#define ISPRSZ_MAX_OUTPUT 3312 + +/* Resizer module register offset */ +#define ISPRSZ_PID (0x000) +#define ISPRSZ_PCR (0x004) +#define ISPRSZ_CNT (0x008) +#define ISPRSZ_OUT_SIZE (0x00C) +#define ISPRSZ_IN_START (0x010) +#define ISPRSZ_IN_SIZE (0x014) +#define ISPRSZ_SDR_INADD (0x018) +#define ISPRSZ_SDR_INOFF (0x01C) +#define ISPRSZ_SDR_OUTADD (0x020) +#define ISPRSZ_SDR_OUTOFF (0x024) +#define ISPRSZ_HFILT10 (0x028) +#define ISPRSZ_HFILT32 (0x02C) +#define ISPRSZ_HFILT54 (0x030) +#define ISPRSZ_HFILT76 (0x034) +#define ISPRSZ_HFILT98 (0x038) +#define ISPRSZ_HFILT1110 (0x03C) +#define ISPRSZ_HFILT1312 (0x040) +#define ISPRSZ_HFILT1514 (0x044) +#define ISPRSZ_HFILT1716 (0x048) +#define ISPRSZ_HFILT1918 (0x04C) +#define ISPRSZ_HFILT2120 (0x050) +#define ISPRSZ_HFILT2322 (0x054) +#define ISPRSZ_HFILT2524 (0x058) +#define ISPRSZ_HFILT2726 (0x05C) +#define ISPRSZ_HFILT2928 (0x060) +#define ISPRSZ_HFILT3130 (0x064) +#define ISPRSZ_VFILT10 (0x068) +#define ISPRSZ_VFILT32 (0x06C) +#define ISPRSZ_VFILT54 (0x070) +#define ISPRSZ_VFILT76 (0x074) +#define ISPRSZ_VFILT98 (0x078) +#define ISPRSZ_VFILT1110 (0x07C) +#define ISPRSZ_VFILT1312 (0x080) +#define ISPRSZ_VFILT1514 (0x084) +#define ISPRSZ_VFILT1716 (0x088) +#define ISPRSZ_VFILT1918 (0x08C) +#define ISPRSZ_VFILT2120 (0x090) +#define ISPRSZ_VFILT2322 (0x094) +#define ISPRSZ_VFILT2524 (0x098) +#define ISPRSZ_VFILT2726 (0x09C) +#define ISPRSZ_VFILT2928 (0x0A0) +#define ISPRSZ_VFILT3130 (0x0A4) +#define ISPRSZ_YENH (0x0A8) + +#define ISP_INT_CLR 0xFF113F11 +#define ISPPRV_PCR_EN 1 +#define ISPPRV_PCR_BUSY (1 << 1) +#define ISPPRV_PCR_SOURCE (1 << 2) +#define ISPPRV_PCR_ONESHOT (1 << 3) +#define ISPPRV_PCR_WIDTH (1 << 4) +#define ISPPRV_PCR_INVALAW (1 << 5) +#define ISPPRV_PCR_DRKFEN (1 << 6) +#define ISPPRV_PCR_DRKFCAP (1 << 7) +#define ISPPRV_PCR_HMEDEN (1 << 8) +#define ISPPRV_PCR_NFEN (1 << 9) +#define ISPPRV_PCR_CFAEN (1 << 10) +#define ISPPRV_PCR_CFAFMT_SHIFT 11 +#define ISPPRV_PCR_CFAFMT_MASK 0x7800 +#define ISPPRV_PCR_CFAFMT_BAYER (0 << 11) +#define ISPPRV_PCR_CFAFMT_SONYVGA (1 << 11) +#define ISPPRV_PCR_CFAFMT_RGBFOVEON (2 << 11) +#define ISPPRV_PCR_CFAFMT_DNSPL (3 << 11) +#define ISPPRV_PCR_CFAFMT_HONEYCOMB (4 << 11) +#define ISPPRV_PCR_CFAFMT_RRGGBBFOVEON (5 << 11) +#define ISPPRV_PCR_YNENHEN (1 << 15) +#define ISPPRV_PCR_SUPEN (1 << 16) +#define ISPPRV_PCR_YCPOS_SHIFT 17 +#define ISPPRV_PCR_YCPOS_YCrYCb (0 << 17) +#define ISPPRV_PCR_YCPOS_YCbYCr (1 << 17) +#define ISPPRV_PCR_YCPOS_CbYCrY (2 << 17) +#define ISPPRV_PCR_YCPOS_CrYCbY (3 << 17) +#define ISPPRV_PCR_RSZPORT (1 << 19) +#define ISPPRV_PCR_SDRPORT (1 << 20) +#define ISPPRV_PCR_SCOMP_EN (1 << 21) +#define ISPPRV_PCR_SCOMP_SFT_SHIFT (22) +#define ISPPRV_PCR_SCOMP_SFT_MASK (7 << 22) +#define ISPPRV_PCR_GAMMA_BYPASS (1 << 26) +#define ISPPRV_PCR_DCOREN (1 << 27) +#define ISPPRV_PCR_DCCOUP (1 << 28) +#define ISPPRV_PCR_DRK_FAIL (1 << 31) + +#define ISPPRV_HORZ_INFO_EPH_SHIFT 0 +#define ISPPRV_HORZ_INFO_EPH_MASK 0x3fff +#define ISPPRV_HORZ_INFO_SPH_SHIFT 16 +#define ISPPRV_HORZ_INFO_SPH_MASK 0x3fff0 + +#define ISPPRV_VERT_INFO_ELV_SHIFT 0 +#define ISPPRV_VERT_INFO_ELV_MASK 0x3fff +#define ISPPRV_VERT_INFO_SLV_SHIFT 16 +#define ISPPRV_VERT_INFO_SLV_MASK 0x3fff0 + +#define ISPPRV_AVE_EVENDIST_SHIFT 2 +#define ISPPRV_AVE_EVENDIST_1 0x0 +#define ISPPRV_AVE_EVENDIST_2 0x1 +#define ISPPRV_AVE_EVENDIST_3 0x2 +#define ISPPRV_AVE_EVENDIST_4 0x3 +#define ISPPRV_AVE_ODDDIST_SHIFT 4 +#define ISPPRV_AVE_ODDDIST_1 0x0 +#define ISPPRV_AVE_ODDDIST_2 0x1 +#define ISPPRV_AVE_ODDDIST_3 0x2 +#define ISPPRV_AVE_ODDDIST_4 0x3 + +#define ISPPRV_HMED_THRESHOLD_SHIFT 0 +#define ISPPRV_HMED_EVENDIST (1 << 8) +#define ISPPRV_HMED_ODDDIST (1 << 9) + +#define ISPPRV_WBGAIN_COEF0_SHIFT 0 +#define ISPPRV_WBGAIN_COEF1_SHIFT 8 +#define ISPPRV_WBGAIN_COEF2_SHIFT 16 +#define ISPPRV_WBGAIN_COEF3_SHIFT 24 + +#define ISPPRV_WBSEL_COEF0 0x0 +#define ISPPRV_WBSEL_COEF1 0x1 +#define ISPPRV_WBSEL_COEF2 0x2 +#define ISPPRV_WBSEL_COEF3 0x3 + +#define ISPPRV_WBSEL_N0_0_SHIFT 0 +#define ISPPRV_WBSEL_N0_1_SHIFT 2 +#define ISPPRV_WBSEL_N0_2_SHIFT 4 +#define ISPPRV_WBSEL_N0_3_SHIFT 6 +#define ISPPRV_WBSEL_N1_0_SHIFT 8 +#define ISPPRV_WBSEL_N1_1_SHIFT 10 +#define ISPPRV_WBSEL_N1_2_SHIFT 12 +#define ISPPRV_WBSEL_N1_3_SHIFT 14 +#define ISPPRV_WBSEL_N2_0_SHIFT 16 +#define ISPPRV_WBSEL_N2_1_SHIFT 18 +#define ISPPRV_WBSEL_N2_2_SHIFT 20 +#define ISPPRV_WBSEL_N2_3_SHIFT 22 +#define ISPPRV_WBSEL_N3_0_SHIFT 24 +#define ISPPRV_WBSEL_N3_1_SHIFT 26 +#define ISPPRV_WBSEL_N3_2_SHIFT 28 +#define ISPPRV_WBSEL_N3_3_SHIFT 30 + +#define ISPPRV_CFA_GRADTH_HOR_SHIFT 0 +#define ISPPRV_CFA_GRADTH_VER_SHIFT 8 + +#define ISPPRV_BLKADJOFF_B_SHIFT 0 +#define ISPPRV_BLKADJOFF_G_SHIFT 8 +#define ISPPRV_BLKADJOFF_R_SHIFT 16 + +#define ISPPRV_RGB_MAT1_MTX_RR_SHIFT 0 +#define ISPPRV_RGB_MAT1_MTX_GR_SHIFT 16 + +#define ISPPRV_RGB_MAT2_MTX_BR_SHIFT 0 +#define ISPPRV_RGB_MAT2_MTX_RG_SHIFT 16 + +#define ISPPRV_RGB_MAT3_MTX_GG_SHIFT 0 +#define ISPPRV_RGB_MAT3_MTX_BG_SHIFT 16 + +#define ISPPRV_RGB_MAT4_MTX_RB_SHIFT 0 +#define ISPPRV_RGB_MAT4_MTX_GB_SHIFT 16 + +#define ISPPRV_RGB_MAT5_MTX_BB_SHIFT 0 + +#define ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT 0 +#define ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT 16 + +#define ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT 0 + +#define ISPPRV_CSC0_RY_SHIFT 0 +#define ISPPRV_CSC0_GY_SHIFT 10 +#define ISPPRV_CSC0_BY_SHIFT 20 + +#define ISPPRV_CSC1_RCB_SHIFT 0 +#define ISPPRV_CSC1_GCB_SHIFT 10 +#define ISPPRV_CSC1_BCB_SHIFT 20 + +#define ISPPRV_CSC2_RCR_SHIFT 0 +#define ISPPRV_CSC2_GCR_SHIFT 10 +#define ISPPRV_CSC2_BCR_SHIFT 20 + +#define ISPPRV_CSC_OFFSET_CR_SHIFT 0 +#define ISPPRV_CSC_OFFSET_CB_SHIFT 8 +#define ISPPRV_CSC_OFFSET_Y_SHIFT 16 + +#define ISPPRV_CNT_BRT_BRT_SHIFT 0 +#define ISPPRV_CNT_BRT_CNT_SHIFT 8 + +#define ISPPRV_CONTRAST_MAX 0x10 +#define ISPPRV_CONTRAST_MIN 0xFF +#define ISPPRV_BRIGHT_MIN 0x00 +#define ISPPRV_BRIGHT_MAX 0xFF + +#define ISPPRV_CSUP_CSUPG_SHIFT 0 +#define ISPPRV_CSUP_THRES_SHIFT 8 +#define ISPPRV_CSUP_HPYF_SHIFT 16 + +#define ISPPRV_SETUP_YC_MINC_SHIFT 0 +#define ISPPRV_SETUP_YC_MAXC_SHIFT 8 +#define ISPPRV_SETUP_YC_MINY_SHIFT 16 +#define ISPPRV_SETUP_YC_MAXY_SHIFT 24 +#define ISPPRV_YC_MAX 0xFF +#define ISPPRV_YC_MIN 0x0 + +/* Define bit fields within selected registers */ +#define ISP_REVISION_SHIFT 0 + +#define ISP_SYSCONFIG_AUTOIDLE (1 << 0) +#define ISP_SYSCONFIG_SOFTRESET (1 << 1) +#define ISP_SYSCONFIG_MIDLEMODE_SHIFT 12 +#define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY 0x0 +#define ISP_SYSCONFIG_MIDLEMODE_NOSTANBY 0x1 +#define ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY 0x2 + +#define ISP_SYSSTATUS_RESETDONE 0 + +#define IRQ0ENABLE_CSIA_IRQ (1 << 0) +#define IRQ0ENABLE_CSIC_IRQ (1 << 1) +#define IRQ0ENABLE_CCP2_LCM_IRQ (1 << 3) +#define IRQ0ENABLE_CCP2_LC0_IRQ (1 << 4) +#define IRQ0ENABLE_CCP2_LC1_IRQ (1 << 5) +#define IRQ0ENABLE_CCP2_LC2_IRQ (1 << 6) +#define IRQ0ENABLE_CCP2_LC3_IRQ (1 << 7) +#define IRQ0ENABLE_CSIB_IRQ (IRQ0ENABLE_CCP2_LCM_IRQ | \ + IRQ0ENABLE_CCP2_LC0_IRQ | \ + IRQ0ENABLE_CCP2_LC1_IRQ | \ + IRQ0ENABLE_CCP2_LC2_IRQ | \ + IRQ0ENABLE_CCP2_LC3_IRQ) + +#define IRQ0ENABLE_CCDC_VD0_IRQ (1 << 8) +#define IRQ0ENABLE_CCDC_VD1_IRQ (1 << 9) +#define IRQ0ENABLE_CCDC_VD2_IRQ (1 << 10) +#define IRQ0ENABLE_CCDC_ERR_IRQ (1 << 11) +#define IRQ0ENABLE_H3A_AF_DONE_IRQ (1 << 12) +#define IRQ0ENABLE_H3A_AWB_DONE_IRQ (1 << 13) +#define IRQ0ENABLE_HIST_DONE_IRQ (1 << 16) +#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ (1 << 17) +#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ (1 << 18) +#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ (1 << 19) +#define IRQ0ENABLE_PRV_DONE_IRQ (1 << 20) +#define IRQ0ENABLE_RSZ_DONE_IRQ (1 << 24) +#define IRQ0ENABLE_OVF_IRQ (1 << 25) +#define IRQ0ENABLE_PING_IRQ (1 << 26) +#define IRQ0ENABLE_PONG_IRQ (1 << 27) +#define IRQ0ENABLE_MMU_ERR_IRQ (1 << 28) +#define IRQ0ENABLE_OCP_ERR_IRQ (1 << 29) +#define IRQ0ENABLE_SEC_ERR_IRQ (1 << 30) +#define IRQ0ENABLE_HS_VS_IRQ (1 << 31) + +#define IRQ0STATUS_CSIA_IRQ (1 << 0) +#define IRQ0STATUS_CSI2C_IRQ (1 << 1) +#define IRQ0STATUS_CCP2_LCM_IRQ (1 << 3) +#define IRQ0STATUS_CCP2_LC0_IRQ (1 << 4) +#define IRQ0STATUS_CSIB_IRQ (IRQ0STATUS_CCP2_LCM_IRQ | \ + IRQ0STATUS_CCP2_LC0_IRQ) + +#define IRQ0STATUS_CSIB_LC1_IRQ (1 << 5) +#define IRQ0STATUS_CSIB_LC2_IRQ (1 << 6) +#define IRQ0STATUS_CSIB_LC3_IRQ (1 << 7) +#define IRQ0STATUS_CCDC_VD0_IRQ (1 << 8) +#define IRQ0STATUS_CCDC_VD1_IRQ (1 << 9) +#define IRQ0STATUS_CCDC_VD2_IRQ (1 << 10) +#define IRQ0STATUS_CCDC_ERR_IRQ (1 << 11) +#define IRQ0STATUS_H3A_AF_DONE_IRQ (1 << 12) +#define IRQ0STATUS_H3A_AWB_DONE_IRQ (1 << 13) +#define IRQ0STATUS_HIST_DONE_IRQ (1 << 16) +#define IRQ0STATUS_CCDC_LSC_DONE_IRQ (1 << 17) +#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ (1 << 18) +#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ (1 << 19) +#define IRQ0STATUS_PRV_DONE_IRQ (1 << 20) +#define IRQ0STATUS_RSZ_DONE_IRQ (1 << 24) +#define IRQ0STATUS_OVF_IRQ (1 << 25) +#define IRQ0STATUS_PING_IRQ (1 << 26) +#define IRQ0STATUS_PONG_IRQ (1 << 27) +#define IRQ0STATUS_MMU_ERR_IRQ (1 << 28) +#define IRQ0STATUS_OCP_ERR_IRQ (1 << 29) +#define IRQ0STATUS_SEC_ERR_IRQ (1 << 30) +#define IRQ0STATUS_HS_VS_IRQ (1 << 31) + +#define TCTRL_GRESET_LEN 0 + +#define TCTRL_PSTRB_REPLAY_DELAY 0 +#define TCTRL_PSTRB_REPLAY_COUNTER_SHIFT 25 + +#define ISPCTRL_PAR_SER_CLK_SEL_PARALLEL 0x0 +#define ISPCTRL_PAR_SER_CLK_SEL_CSIA 0x1 +#define ISPCTRL_PAR_SER_CLK_SEL_CSIB 0x2 +#define ISPCTRL_PAR_SER_CLK_SEL_CSIC 0x3 +#define ISPCTRL_PAR_SER_CLK_SEL_MASK 0x3 + +#define ISPCTRL_PAR_BRIDGE_SHIFT 2 +#define ISPCTRL_PAR_BRIDGE_DISABLE (0x0 << 2) +#define ISPCTRL_PAR_BRIDGE_LENDIAN (0x2 << 2) +#define ISPCTRL_PAR_BRIDGE_BENDIAN (0x3 << 2) +#define ISPCTRL_PAR_BRIDGE_MASK (0x3 << 2) + +#define ISPCTRL_PAR_CLK_POL_SHIFT 4 +#define ISPCTRL_PAR_CLK_POL_INV (1 << 4) +#define ISPCTRL_PING_PONG_EN (1 << 5) +#define ISPCTRL_SHIFT_SHIFT 6 +#define ISPCTRL_SHIFT_0 (0x0 << 6) +#define ISPCTRL_SHIFT_2 (0x1 << 6) +#define ISPCTRL_SHIFT_4 (0x2 << 6) +#define ISPCTRL_SHIFT_MASK (0x3 << 6) + +#define ISPCTRL_CCDC_CLK_EN (1 << 8) +#define ISPCTRL_SCMP_CLK_EN (1 << 9) +#define ISPCTRL_H3A_CLK_EN (1 << 10) +#define ISPCTRL_HIST_CLK_EN (1 << 11) +#define ISPCTRL_PREV_CLK_EN (1 << 12) +#define ISPCTRL_RSZ_CLK_EN (1 << 13) +#define ISPCTRL_SYNC_DETECT_SHIFT 14 +#define ISPCTRL_SYNC_DETECT_HSFALL (0x0 << ISPCTRL_SYNC_DETECT_SHIFT) +#define ISPCTRL_SYNC_DETECT_HSRISE (0x1 << ISPCTRL_SYNC_DETECT_SHIFT) +#define ISPCTRL_SYNC_DETECT_VSFALL (0x2 << ISPCTRL_SYNC_DETECT_SHIFT) +#define ISPCTRL_SYNC_DETECT_VSRISE (0x3 << ISPCTRL_SYNC_DETECT_SHIFT) +#define ISPCTRL_SYNC_DETECT_MASK (0x3 << ISPCTRL_SYNC_DETECT_SHIFT) + +#define ISPCTRL_CCDC_RAM_EN (1 << 16) +#define ISPCTRL_PREV_RAM_EN (1 << 17) +#define ISPCTRL_SBL_RD_RAM_EN (1 << 18) +#define ISPCTRL_SBL_WR1_RAM_EN (1 << 19) +#define ISPCTRL_SBL_WR0_RAM_EN (1 << 20) +#define ISPCTRL_SBL_AUTOIDLE (1 << 21) +#define ISPCTRL_SBL_SHARED_WPORTC (1 << 26) +#define ISPCTRL_SBL_SHARED_RPORTA (1 << 27) +#define ISPCTRL_SBL_SHARED_RPORTB (1 << 28) +#define ISPCTRL_JPEG_FLUSH (1 << 30) +#define ISPCTRL_CCDC_FLUSH (1 << 31) + +#define ISPSECURE_SECUREMODE 0 + +#define ISPTCTRL_CTRL_DIV_LOW 0x0 +#define ISPTCTRL_CTRL_DIV_HIGH 0x1 +#define ISPTCTRL_CTRL_DIV_BYPASS 0x1F + +#define ISPTCTRL_CTRL_DIVA_SHIFT 0 +#define ISPTCTRL_CTRL_DIVA_MASK (0x1F << ISPTCTRL_CTRL_DIVA_SHIFT) + +#define ISPTCTRL_CTRL_DIVB_SHIFT 5 +#define ISPTCTRL_CTRL_DIVB_MASK (0x1F << ISPTCTRL_CTRL_DIVB_SHIFT) + +#define ISPTCTRL_CTRL_DIVC_SHIFT 10 +#define ISPTCTRL_CTRL_DIVC_NOCLOCK (0x0 << 10) + +#define ISPTCTRL_CTRL_SHUTEN (1 << 21) +#define ISPTCTRL_CTRL_PSTRBEN (1 << 22) +#define ISPTCTRL_CTRL_STRBEN (1 << 23) +#define ISPTCTRL_CTRL_SHUTPOL (1 << 24) +#define ISPTCTRL_CTRL_STRBPSTRBPOL (1 << 26) + +#define ISPTCTRL_CTRL_INSEL_SHIFT 27 +#define ISPTCTRL_CTRL_INSEL_PARALLEL (0x0 << 27) +#define ISPTCTRL_CTRL_INSEL_CSIA (0x1 << 27) +#define ISPTCTRL_CTRL_INSEL_CSIB (0x2 << 27) + +#define ISPTCTRL_CTRL_GRESETEn (1 << 29) +#define ISPTCTRL_CTRL_GRESETPOL (1 << 30) +#define ISPTCTRL_CTRL_GRESETDIR (1 << 31) + +#define ISPTCTRL_FRAME_SHUT_SHIFT 0 +#define ISPTCTRL_FRAME_PSTRB_SHIFT 6 +#define ISPTCTRL_FRAME_STRB_SHIFT 12 + +#define ISPCCDC_PID_PREV_SHIFT 0 +#define ISPCCDC_PID_CID_SHIFT 8 +#define ISPCCDC_PID_TID_SHIFT 16 + +#define ISPCCDC_PCR_EN 1 +#define ISPCCDC_PCR_BUSY (1 << 1) + +#define ISPCCDC_SYN_MODE_VDHDOUT 0x1 +#define ISPCCDC_SYN_MODE_FLDOUT (1 << 1) +#define ISPCCDC_SYN_MODE_VDPOL (1 << 2) +#define ISPCCDC_SYN_MODE_HDPOL (1 << 3) +#define ISPCCDC_SYN_MODE_FLDPOL (1 << 4) +#define ISPCCDC_SYN_MODE_EXWEN (1 << 5) +#define ISPCCDC_SYN_MODE_DATAPOL (1 << 6) +#define ISPCCDC_SYN_MODE_FLDMODE (1 << 7) +#define ISPCCDC_SYN_MODE_DATSIZ_MASK (0x7 << 8) +#define ISPCCDC_SYN_MODE_DATSIZ_8_16 (0x0 << 8) +#define ISPCCDC_SYN_MODE_DATSIZ_12 (0x4 << 8) +#define ISPCCDC_SYN_MODE_DATSIZ_11 (0x5 << 8) +#define ISPCCDC_SYN_MODE_DATSIZ_10 (0x6 << 8) +#define ISPCCDC_SYN_MODE_DATSIZ_8 (0x7 << 8) +#define ISPCCDC_SYN_MODE_PACK8 (1 << 11) +#define ISPCCDC_SYN_MODE_INPMOD_MASK (3 << 12) +#define ISPCCDC_SYN_MODE_INPMOD_RAW (0 << 12) +#define ISPCCDC_SYN_MODE_INPMOD_YCBCR16 (1 << 12) +#define ISPCCDC_SYN_MODE_INPMOD_YCBCR8 (2 << 12) +#define ISPCCDC_SYN_MODE_LPF (1 << 14) +#define ISPCCDC_SYN_MODE_FLDSTAT (1 << 15) +#define ISPCCDC_SYN_MODE_VDHDEN (1 << 16) +#define ISPCCDC_SYN_MODE_WEN (1 << 17) +#define ISPCCDC_SYN_MODE_VP2SDR (1 << 18) +#define ISPCCDC_SYN_MODE_SDR2RSZ (1 << 19) + +#define ISPCCDC_HD_VD_WID_VDW_SHIFT 0 +#define ISPCCDC_HD_VD_WID_HDW_SHIFT 16 + +#define ISPCCDC_PIX_LINES_HLPRF_SHIFT 0 +#define ISPCCDC_PIX_LINES_PPLN_SHIFT 16 + +#define ISPCCDC_HORZ_INFO_NPH_SHIFT 0 +#define ISPCCDC_HORZ_INFO_NPH_MASK 0x00007fff +#define ISPCCDC_HORZ_INFO_SPH_SHIFT 16 +#define ISPCCDC_HORZ_INFO_SPH_MASK 0x7fff0000 + +#define ISPCCDC_VERT_START_SLV1_SHIFT 0 +#define ISPCCDC_VERT_START_SLV0_SHIFT 16 +#define ISPCCDC_VERT_START_SLV0_MASK 0x7fff0000 + +#define ISPCCDC_VERT_LINES_NLV_SHIFT 0 +#define ISPCCDC_VERT_LINES_NLV_MASK 0x00007fff + +#define ISPCCDC_CULLING_CULV_SHIFT 0 +#define ISPCCDC_CULLING_CULHODD_SHIFT 16 +#define ISPCCDC_CULLING_CULHEVN_SHIFT 24 + +#define ISPCCDC_HSIZE_OFF_SHIFT 0 + +#define ISPCCDC_SDOFST_FINV (1 << 14) +#define ISPCCDC_SDOFST_FOFST_1L 0 +#define ISPCCDC_SDOFST_FOFST_4L (3 << 12) +#define ISPCCDC_SDOFST_LOFST3_SHIFT 0 +#define ISPCCDC_SDOFST_LOFST2_SHIFT 3 +#define ISPCCDC_SDOFST_LOFST1_SHIFT 6 +#define ISPCCDC_SDOFST_LOFST0_SHIFT 9 +#define EVENEVEN 1 +#define ODDEVEN 2 +#define EVENODD 3 +#define ODDODD 4 + +#define ISPCCDC_CLAMP_OBGAIN_SHIFT 0 +#define ISPCCDC_CLAMP_OBST_SHIFT 10 +#define ISPCCDC_CLAMP_OBSLN_SHIFT 25 +#define ISPCCDC_CLAMP_OBSLEN_SHIFT 28 +#define ISPCCDC_CLAMP_CLAMPEN (1 << 31) + +#define ISPCCDC_COLPTN_R_Ye 0x0 +#define ISPCCDC_COLPTN_Gr_Cy 0x1 +#define ISPCCDC_COLPTN_Gb_G 0x2 +#define ISPCCDC_COLPTN_B_Mg 0x3 +#define ISPCCDC_COLPTN_CP0PLC0_SHIFT 0 +#define ISPCCDC_COLPTN_CP0PLC1_SHIFT 2 +#define ISPCCDC_COLPTN_CP0PLC2_SHIFT 4 +#define ISPCCDC_COLPTN_CP0PLC3_SHIFT 6 +#define ISPCCDC_COLPTN_CP1PLC0_SHIFT 8 +#define ISPCCDC_COLPTN_CP1PLC1_SHIFT 10 +#define ISPCCDC_COLPTN_CP1PLC2_SHIFT 12 +#define ISPCCDC_COLPTN_CP1PLC3_SHIFT 14 +#define ISPCCDC_COLPTN_CP2PLC0_SHIFT 16 +#define ISPCCDC_COLPTN_CP2PLC1_SHIFT 18 +#define ISPCCDC_COLPTN_CP2PLC2_SHIFT 20 +#define ISPCCDC_COLPTN_CP2PLC3_SHIFT 22 +#define ISPCCDC_COLPTN_CP3PLC0_SHIFT 24 +#define ISPCCDC_COLPTN_CP3PLC1_SHIFT 26 +#define ISPCCDC_COLPTN_CP3PLC2_SHIFT 28 +#define ISPCCDC_COLPTN_CP3PLC3_SHIFT 30 + +#define ISPCCDC_BLKCMP_B_MG_SHIFT 0 +#define ISPCCDC_BLKCMP_GB_G_SHIFT 8 +#define ISPCCDC_BLKCMP_GR_CY_SHIFT 16 +#define ISPCCDC_BLKCMP_R_YE_SHIFT 24 + +#define ISPCCDC_FPC_FPNUM_SHIFT 0 +#define ISPCCDC_FPC_FPCEN (1 << 15) +#define ISPCCDC_FPC_FPERR (1 << 16) + +#define ISPCCDC_VDINT_1_SHIFT 0 +#define ISPCCDC_VDINT_1_MASK 0x00007fff +#define ISPCCDC_VDINT_0_SHIFT 16 +#define ISPCCDC_VDINT_0_MASK 0x7fff0000 + +#define ISPCCDC_ALAW_GWDI_12_3 (0x3 << 0) +#define ISPCCDC_ALAW_GWDI_11_2 (0x4 << 0) +#define ISPCCDC_ALAW_GWDI_10_1 (0x5 << 0) +#define ISPCCDC_ALAW_GWDI_9_0 (0x6 << 0) +#define ISPCCDC_ALAW_CCDTBL (1 << 3) + +#define ISPCCDC_REC656IF_R656ON 1 +#define ISPCCDC_REC656IF_ECCFVH (1 << 1) + +#define ISPCCDC_CFG_BW656 (1 << 5) +#define ISPCCDC_CFG_FIDMD_SHIFT 6 +#define ISPCCDC_CFG_WENLOG (1 << 8) +#define ISPCCDC_CFG_WENLOG_AND (0 << 8) +#define ISPCCDC_CFG_WENLOG_OR (1 << 8) +#define ISPCCDC_CFG_Y8POS (1 << 11) +#define ISPCCDC_CFG_BSWD (1 << 12) +#define ISPCCDC_CFG_MSBINVI (1 << 13) +#define ISPCCDC_CFG_VDLC (1 << 15) + +#define ISPCCDC_FMTCFG_FMTEN 0x1 +#define ISPCCDC_FMTCFG_LNALT (1 << 1) +#define ISPCCDC_FMTCFG_LNUM_SHIFT 2 +#define ISPCCDC_FMTCFG_PLEN_ODD_SHIFT 4 +#define ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT 8 +#define ISPCCDC_FMTCFG_VPIN_MASK 0x00007000 +#define ISPCCDC_FMTCFG_VPIN_12_3 (0x3 << 12) +#define ISPCCDC_FMTCFG_VPIN_11_2 (0x4 << 12) +#define ISPCCDC_FMTCFG_VPIN_10_1 (0x5 << 12) +#define ISPCCDC_FMTCFG_VPIN_9_0 (0x6 << 12) +#define ISPCCDC_FMTCFG_VPEN (1 << 15) + +#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK 0x003f0000 +#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT 16 +#define ISPCCDC_FMTCFG_VPIF_FRQ_BY2 (0x0 << 16) +#define ISPCCDC_FMTCFG_VPIF_FRQ_BY3 (0x1 << 16) +#define ISPCCDC_FMTCFG_VPIF_FRQ_BY4 (0x2 << 16) +#define ISPCCDC_FMTCFG_VPIF_FRQ_BY5 (0x3 << 16) +#define ISPCCDC_FMTCFG_VPIF_FRQ_BY6 (0x4 << 16) + +#define ISPCCDC_FMT_HORZ_FMTLNH_SHIFT 0 +#define ISPCCDC_FMT_HORZ_FMTSPH_SHIFT 16 + +#define ISPCCDC_FMT_VERT_FMTLNV_SHIFT 0 +#define ISPCCDC_FMT_VERT_FMTSLV_SHIFT 16 + +#define ISPCCDC_FMT_HORZ_FMTSPH_MASK 0x1fff0000 +#define ISPCCDC_FMT_HORZ_FMTLNH_MASK 0x00001fff + +#define ISPCCDC_FMT_VERT_FMTSLV_MASK 0x1fff0000 +#define ISPCCDC_FMT_VERT_FMTLNV_MASK 0x00001fff + +#define ISPCCDC_VP_OUT_HORZ_ST_SHIFT 0 +#define ISPCCDC_VP_OUT_HORZ_NUM_SHIFT 4 +#define ISPCCDC_VP_OUT_VERT_NUM_SHIFT 17 + +#define ISPRSZ_PID_PREV_SHIFT 0 +#define ISPRSZ_PID_CID_SHIFT 8 +#define ISPRSZ_PID_TID_SHIFT 16 + +#define ISPRSZ_PCR_ENABLE (1 << 0) +#define ISPRSZ_PCR_BUSY (1 << 1) +#define ISPRSZ_PCR_ONESHOT (1 << 2) + +#define ISPRSZ_CNT_HRSZ_SHIFT 0 +#define ISPRSZ_CNT_HRSZ_MASK \ + (0x3FF << ISPRSZ_CNT_HRSZ_SHIFT) +#define ISPRSZ_CNT_VRSZ_SHIFT 10 +#define ISPRSZ_CNT_VRSZ_MASK \ + (0x3FF << ISPRSZ_CNT_VRSZ_SHIFT) +#define ISPRSZ_CNT_HSTPH_SHIFT 20 +#define ISPRSZ_CNT_HSTPH_MASK (0x7 << ISPRSZ_CNT_HSTPH_SHIFT) +#define ISPRSZ_CNT_VSTPH_SHIFT 23 +#define ISPRSZ_CNT_VSTPH_MASK (0x7 << ISPRSZ_CNT_VSTPH_SHIFT) +#define ISPRSZ_CNT_YCPOS (1 << 26) +#define ISPRSZ_CNT_INPTYP (1 << 27) +#define ISPRSZ_CNT_INPSRC (1 << 28) +#define ISPRSZ_CNT_CBILIN (1 << 29) + +#define ISPRSZ_OUT_SIZE_HORZ_SHIFT 0 +#define ISPRSZ_OUT_SIZE_HORZ_MASK \ + (0xFFF << ISPRSZ_OUT_SIZE_HORZ_SHIFT) +#define ISPRSZ_OUT_SIZE_VERT_SHIFT 16 +#define ISPRSZ_OUT_SIZE_VERT_MASK \ + (0xFFF << ISPRSZ_OUT_SIZE_VERT_SHIFT) + +#define ISPRSZ_IN_START_HORZ_ST_SHIFT 0 +#define ISPRSZ_IN_START_HORZ_ST_MASK \ + (0x1FFF << ISPRSZ_IN_START_HORZ_ST_SHIFT) +#define ISPRSZ_IN_START_VERT_ST_SHIFT 16 +#define ISPRSZ_IN_START_VERT_ST_MASK \ + (0x1FFF << ISPRSZ_IN_START_VERT_ST_SHIFT) + +#define ISPRSZ_IN_SIZE_HORZ_SHIFT 0 +#define ISPRSZ_IN_SIZE_HORZ_MASK \ + (0x1FFF << ISPRSZ_IN_SIZE_HORZ_SHIFT) +#define ISPRSZ_IN_SIZE_VERT_SHIFT 16 +#define ISPRSZ_IN_SIZE_VERT_MASK \ + (0x1FFF << ISPRSZ_IN_SIZE_VERT_SHIFT) + +#define ISPRSZ_SDR_INADD_ADDR_SHIFT 0 +#define ISPRSZ_SDR_INADD_ADDR_MASK 0xFFFFFFFF + +#define ISPRSZ_SDR_INOFF_OFFSET_SHIFT 0 +#define ISPRSZ_SDR_INOFF_OFFSET_MASK \ + (0xFFFF << ISPRSZ_SDR_INOFF_OFFSET_SHIFT) + +#define ISPRSZ_SDR_OUTADD_ADDR_SHIFT 0 +#define ISPRSZ_SDR_OUTADD_ADDR_MASK 0xFFFFFFFF + + +#define ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT 0 +#define ISPRSZ_SDR_OUTOFF_OFFSET_MASK \ + (0xFFFF << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT) + +#define ISPRSZ_HFILT_COEF0_SHIFT 0 +#define ISPRSZ_HFILT_COEF0_MASK \ + (0x3FF << ISPRSZ_HFILT_COEF0_SHIFT) +#define ISPRSZ_HFILT_COEF1_SHIFT 16 +#define ISPRSZ_HFILT_COEF1_MASK \ + (0x3FF << ISPRSZ_HFILT_COEF1_SHIFT) + +#define ISPRSZ_HFILT32_COEF2_SHIFT 0 +#define ISPRSZ_HFILT32_COEF2_MASK 0x3FF +#define ISPRSZ_HFILT32_COEF3_SHIFT 16 +#define ISPRSZ_HFILT32_COEF3_MASK 0x3FF0000 + +#define ISPRSZ_HFILT54_COEF4_SHIFT 0 +#define ISPRSZ_HFILT54_COEF4_MASK 0x3FF +#define ISPRSZ_HFILT54_COEF5_SHIFT 16 +#define ISPRSZ_HFILT54_COEF5_MASK 0x3FF0000 + +#define ISPRSZ_HFILT76_COEFF6_SHIFT 0 +#define ISPRSZ_HFILT76_COEFF6_MASK 0x3FF +#define ISPRSZ_HFILT76_COEFF7_SHIFT 16 +#define ISPRSZ_HFILT76_COEFF7_MASK 0x3FF0000 + +#define ISPRSZ_HFILT98_COEFF8_SHIFT 0 +#define ISPRSZ_HFILT98_COEFF8_MASK 0x3FF +#define ISPRSZ_HFILT98_COEFF9_SHIFT 16 +#define ISPRSZ_HFILT98_COEFF9_MASK 0x3FF0000 + +#define ISPRSZ_HFILT1110_COEF10_SHIFT 0 +#define ISPRSZ_HFILT1110_COEF10_MASK 0x3FF +#define ISPRSZ_HFILT1110_COEF11_SHIFT 16 +#define ISPRSZ_HFILT1110_COEF11_MASK 0x3FF0000 + +#define ISPRSZ_HFILT1312_COEFF12_SHIFT 0 +#define ISPRSZ_HFILT1312_COEFF12_MASK 0x3FF +#define ISPRSZ_HFILT1312_COEFF13_SHIFT 16 +#define ISPRSZ_HFILT1312_COEFF13_MASK 0x3FF0000 + +#define ISPRSZ_HFILT1514_COEFF14_SHIFT 0 +#define ISPRSZ_HFILT1514_COEFF14_MASK 0x3FF +#define ISPRSZ_HFILT1514_COEFF15_SHIFT 16 +#define ISPRSZ_HFILT1514_COEFF15_MASK 0x3FF0000 + +#define ISPRSZ_HFILT1716_COEF16_SHIFT 0 +#define ISPRSZ_HFILT1716_COEF16_MASK 0x3FF +#define ISPRSZ_HFILT1716_COEF17_SHIFT 16 +#define ISPRSZ_HFILT1716_COEF17_MASK 0x3FF0000 + +#define ISPRSZ_HFILT1918_COEF18_SHIFT 0 +#define ISPRSZ_HFILT1918_COEF18_MASK 0x3FF +#define ISPRSZ_HFILT1918_COEF19_SHIFT 16 +#define ISPRSZ_HFILT1918_COEF19_MASK 0x3FF0000 + +#define ISPRSZ_HFILT2120_COEF20_SHIFT 0 +#define ISPRSZ_HFILT2120_COEF20_MASK 0x3FF +#define ISPRSZ_HFILT2120_COEF21_SHIFT 16 +#define ISPRSZ_HFILT2120_COEF21_MASK 0x3FF0000 + +#define ISPRSZ_HFILT2322_COEF22_SHIFT 0 +#define ISPRSZ_HFILT2322_COEF22_MASK 0x3FF +#define ISPRSZ_HFILT2322_COEF23_SHIFT 16 +#define ISPRSZ_HFILT2322_COEF23_MASK 0x3FF0000 + +#define ISPRSZ_HFILT2524_COEF24_SHIFT 0 +#define ISPRSZ_HFILT2524_COEF24_MASK 0x3FF +#define ISPRSZ_HFILT2524_COEF25_SHIFT 16 +#define ISPRSZ_HFILT2524_COEF25_MASK 0x3FF0000 + +#define ISPRSZ_HFILT2726_COEF26_SHIFT 0 +#define ISPRSZ_HFILT2726_COEF26_MASK 0x3FF +#define ISPRSZ_HFILT2726_COEF27_SHIFT 16 +#define ISPRSZ_HFILT2726_COEF27_MASK 0x3FF0000 + +#define ISPRSZ_HFILT2928_COEF28_SHIFT 0 +#define ISPRSZ_HFILT2928_COEF28_MASK 0x3FF +#define ISPRSZ_HFILT2928_COEF29_SHIFT 16 +#define ISPRSZ_HFILT2928_COEF29_MASK 0x3FF0000 + +#define ISPRSZ_HFILT3130_COEF30_SHIFT 0 +#define ISPRSZ_HFILT3130_COEF30_MASK 0x3FF +#define ISPRSZ_HFILT3130_COEF31_SHIFT 16 +#define ISPRSZ_HFILT3130_COEF31_MASK 0x3FF0000 + +#define ISPRSZ_VFILT_COEF0_SHIFT 0 +#define ISPRSZ_VFILT_COEF0_MASK \ + (0x3FF << ISPRSZ_VFILT_COEF0_SHIFT) +#define ISPRSZ_VFILT_COEF1_SHIFT 16 +#define ISPRSZ_VFILT_COEF1_MASK \ + (0x3FF << ISPRSZ_VFILT_COEF1_SHIFT) + +#define ISPRSZ_VFILT10_COEF0_SHIFT 0 +#define ISPRSZ_VFILT10_COEF0_MASK 0x3FF +#define ISPRSZ_VFILT10_COEF1_SHIFT 16 +#define ISPRSZ_VFILT10_COEF1_MASK 0x3FF0000 + +#define ISPRSZ_VFILT32_COEF2_SHIFT 0 +#define ISPRSZ_VFILT32_COEF2_MASK 0x3FF +#define ISPRSZ_VFILT32_COEF3_SHIFT 16 +#define ISPRSZ_VFILT32_COEF3_MASK 0x3FF0000 + +#define ISPRSZ_VFILT54_COEF4_SHIFT 0 +#define ISPRSZ_VFILT54_COEF4_MASK 0x3FF +#define ISPRSZ_VFILT54_COEF5_SHIFT 16 +#define ISPRSZ_VFILT54_COEF5_MASK 0x3FF0000 + +#define ISPRSZ_VFILT76_COEFF6_SHIFT 0 +#define ISPRSZ_VFILT76_COEFF6_MASK 0x3FF +#define ISPRSZ_VFILT76_COEFF7_SHIFT 16 +#define ISPRSZ_VFILT76_COEFF7_MASK 0x3FF0000 + +#define ISPRSZ_VFILT98_COEFF8_SHIFT 0 +#define ISPRSZ_VFILT98_COEFF8_MASK 0x3FF +#define ISPRSZ_VFILT98_COEFF9_SHIFT 16 +#define ISPRSZ_VFILT98_COEFF9_MASK 0x3FF0000 + +#define ISPRSZ_VFILT1110_COEF10_SHIFT 0 +#define ISPRSZ_VFILT1110_COEF10_MASK 0x3FF +#define ISPRSZ_VFILT1110_COEF11_SHIFT 16 +#define ISPRSZ_VFILT1110_COEF11_MASK 0x3FF0000 + +#define ISPRSZ_VFILT1312_COEFF12_SHIFT 0 +#define ISPRSZ_VFILT1312_COEFF12_MASK 0x3FF +#define ISPRSZ_VFILT1312_COEFF13_SHIFT 16 +#define ISPRSZ_VFILT1312_COEFF13_MASK 0x3FF0000 + +#define ISPRSZ_VFILT1514_COEFF14_SHIFT 0 +#define ISPRSZ_VFILT1514_COEFF14_MASK 0x3FF +#define ISPRSZ_VFILT1514_COEFF15_SHIFT 16 +#define ISPRSZ_VFILT1514_COEFF15_MASK 0x3FF0000 + +#define ISPRSZ_VFILT1716_COEF16_SHIFT 0 +#define ISPRSZ_VFILT1716_COEF16_MASK 0x3FF +#define ISPRSZ_VFILT1716_COEF17_SHIFT 16 +#define ISPRSZ_VFILT1716_COEF17_MASK 0x3FF0000 + +#define ISPRSZ_VFILT1918_COEF18_SHIFT 0 +#define ISPRSZ_VFILT1918_COEF18_MASK 0x3FF +#define ISPRSZ_VFILT1918_COEF19_SHIFT 16 +#define ISPRSZ_VFILT1918_COEF19_MASK 0x3FF0000 + +#define ISPRSZ_VFILT2120_COEF20_SHIFT 0 +#define ISPRSZ_VFILT2120_COEF20_MASK 0x3FF +#define ISPRSZ_VFILT2120_COEF21_SHIFT 16 +#define ISPRSZ_VFILT2120_COEF21_MASK 0x3FF0000 + +#define ISPRSZ_VFILT2322_COEF22_SHIFT 0 +#define ISPRSZ_VFILT2322_COEF22_MASK 0x3FF +#define ISPRSZ_VFILT2322_COEF23_SHIFT 16 +#define ISPRSZ_VFILT2322_COEF23_MASK 0x3FF0000 + +#define ISPRSZ_VFILT2524_COEF24_SHIFT 0 +#define ISPRSZ_VFILT2524_COEF24_MASK 0x3FF +#define ISPRSZ_VFILT2524_COEF25_SHIFT 16 +#define ISPRSZ_VFILT2524_COEF25_MASK 0x3FF0000 + +#define ISPRSZ_VFILT2726_COEF26_SHIFT 0 +#define ISPRSZ_VFILT2726_COEF26_MASK 0x3FF +#define ISPRSZ_VFILT2726_COEF27_SHIFT 16 +#define ISPRSZ_VFILT2726_COEF27_MASK 0x3FF0000 + +#define ISPRSZ_VFILT2928_COEF28_SHIFT 0 +#define ISPRSZ_VFILT2928_COEF28_MASK 0x3FF +#define ISPRSZ_VFILT2928_COEF29_SHIFT 16 +#define ISPRSZ_VFILT2928_COEF29_MASK 0x3FF0000 + +#define ISPRSZ_VFILT3130_COEF30_SHIFT 0 +#define ISPRSZ_VFILT3130_COEF30_MASK 0x3FF +#define ISPRSZ_VFILT3130_COEF31_SHIFT 16 +#define ISPRSZ_VFILT3130_COEF31_MASK 0x3FF0000 + +#define ISPRSZ_YENH_CORE_SHIFT 0 +#define ISPRSZ_YENH_CORE_MASK \ + (0xFF << ISPRSZ_YENH_CORE_SHIFT) +#define ISPRSZ_YENH_SLOP_SHIFT 8 +#define ISPRSZ_YENH_SLOP_MASK \ + (0xF << ISPRSZ_YENH_SLOP_SHIFT) +#define ISPRSZ_YENH_GAIN_SHIFT 12 +#define ISPRSZ_YENH_GAIN_MASK \ + (0xF << ISPRSZ_YENH_GAIN_SHIFT) +#define ISPRSZ_YENH_ALGO_SHIFT 16 +#define ISPRSZ_YENH_ALGO_MASK \ + (0x3 << ISPRSZ_YENH_ALGO_SHIFT) + +#define ISPH3A_PCR_AEW_ALAW_EN_SHIFT 1 +#define ISPH3A_PCR_AF_MED_TH_SHIFT 3 +#define ISPH3A_PCR_AF_RGBPOS_SHIFT 11 +#define ISPH3A_PCR_AEW_AVE2LMT_SHIFT 22 +#define ISPH3A_PCR_AEW_AVE2LMT_MASK 0xFFC00000 +#define ISPH3A_PCR_BUSYAF (1 << 15) +#define ISPH3A_PCR_BUSYAEAWB (1 << 18) + +#define ISPH3A_AEWWIN1_WINHC_SHIFT 0 +#define ISPH3A_AEWWIN1_WINHC_MASK 0x3F +#define ISPH3A_AEWWIN1_WINVC_SHIFT 6 +#define ISPH3A_AEWWIN1_WINVC_MASK 0x1FC0 +#define ISPH3A_AEWWIN1_WINW_SHIFT 13 +#define ISPH3A_AEWWIN1_WINW_MASK 0xFE000 +#define ISPH3A_AEWWIN1_WINH_SHIFT 24 +#define ISPH3A_AEWWIN1_WINH_MASK 0x7F000000 + +#define ISPH3A_AEWINSTART_WINSH_SHIFT 0 +#define ISPH3A_AEWINSTART_WINSH_MASK 0x0FFF +#define ISPH3A_AEWINSTART_WINSV_SHIFT 16 +#define ISPH3A_AEWINSTART_WINSV_MASK 0x0FFF0000 + +#define ISPH3A_AEWINBLK_WINH_SHIFT 0 +#define ISPH3A_AEWINBLK_WINH_MASK 0x7F +#define ISPH3A_AEWINBLK_WINSV_SHIFT 16 +#define ISPH3A_AEWINBLK_WINSV_MASK 0x0FFF0000 + +#define ISPH3A_AEWSUBWIN_AEWINCH_SHIFT 0 +#define ISPH3A_AEWSUBWIN_AEWINCH_MASK 0x0F +#define ISPH3A_AEWSUBWIN_AEWINCV_SHIFT 8 +#define ISPH3A_AEWSUBWIN_AEWINCV_MASK 0x0F00 + +#define ISPHIST_PCR_ENABLE_SHIFT 0 +#define ISPHIST_PCR_ENABLE_MASK 0x01 +#define ISPHIST_PCR_ENABLE (1 << ISPHIST_PCR_ENABLE_SHIFT) +#define ISPHIST_PCR_BUSY 0x02 + +#define ISPHIST_CNT_DATASIZE_SHIFT 8 +#define ISPHIST_CNT_DATASIZE_MASK 0x0100 +#define ISPHIST_CNT_CLEAR_SHIFT 7 +#define ISPHIST_CNT_CLEAR_MASK 0x080 +#define ISPHIST_CNT_CLEAR (1 << ISPHIST_CNT_CLEAR_SHIFT) +#define ISPHIST_CNT_CFA_SHIFT 6 +#define ISPHIST_CNT_CFA_MASK 0x040 +#define ISPHIST_CNT_BINS_SHIFT 4 +#define ISPHIST_CNT_BINS_MASK 0x030 +#define ISPHIST_CNT_SOURCE_SHIFT 3 +#define ISPHIST_CNT_SOURCE_MASK 0x08 +#define ISPHIST_CNT_SHIFT_SHIFT 0 +#define ISPHIST_CNT_SHIFT_MASK 0x07 + +#define ISPHIST_WB_GAIN_WG00_SHIFT 24 +#define ISPHIST_WB_GAIN_WG00_MASK 0xFF000000 +#define ISPHIST_WB_GAIN_WG01_SHIFT 16 +#define ISPHIST_WB_GAIN_WG01_MASK 0xFF0000 +#define ISPHIST_WB_GAIN_WG02_SHIFT 8 +#define ISPHIST_WB_GAIN_WG02_MASK 0xFF00 +#define ISPHIST_WB_GAIN_WG03_SHIFT 0 +#define ISPHIST_WB_GAIN_WG03_MASK 0xFF + +#define ISPHIST_REG_START_END_MASK 0x3FFF +#define ISPHIST_REG_START_SHIFT 16 +#define ISPHIST_REG_END_SHIFT 0 +#define ISPHIST_REG_START_MASK (ISPHIST_REG_START_END_MASK << \ + ISPHIST_REG_START_SHIFT) +#define ISPHIST_REG_END_MASK (ISPHIST_REG_START_END_MASK << \ + ISPHIST_REG_END_SHIFT) + +#define ISPHIST_REG_MASK (ISPHIST_REG_START_MASK | \ + ISPHIST_REG_END_MASK) + +#define ISPHIST_ADDR_SHIFT 0 +#define ISPHIST_ADDR_MASK 0x3FF + +#define ISPHIST_DATA_SHIFT 0 +#define ISPHIST_DATA_MASK 0xFFFFF + +#define ISPHIST_RADD_SHIFT 0 +#define ISPHIST_RADD_MASK 0xFFFFFFFF + +#define ISPHIST_RADD_OFF_SHIFT 0 +#define ISPHIST_RADD_OFF_MASK 0xFFFF + +#define ISPHIST_HV_INFO_HSIZE_SHIFT 16 +#define ISPHIST_HV_INFO_HSIZE_MASK 0x3FFF0000 +#define ISPHIST_HV_INFO_VSIZE_SHIFT 0 +#define ISPHIST_HV_INFO_VSIZE_MASK 0x3FFF + +#define ISPHIST_HV_INFO_MASK 0x3FFF3FFF + +#define ISPCCDC_LSC_ENABLE 1 +#define ISPCCDC_LSC_BUSY (1 << 7) +#define ISPCCDC_LSC_GAIN_MODE_N_MASK 0x700 +#define ISPCCDC_LSC_GAIN_MODE_N_SHIFT 8 +#define ISPCCDC_LSC_GAIN_MODE_M_MASK 0x3800 +#define ISPCCDC_LSC_GAIN_MODE_M_SHIFT 12 +#define ISPCCDC_LSC_GAIN_FORMAT_MASK 0xE +#define ISPCCDC_LSC_GAIN_FORMAT_SHIFT 1 +#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK (1<<6) + +#define ISPCCDC_LSC_INITIAL_X_MASK 0x3F +#define ISPCCDC_LSC_INITIAL_X_SHIFT 0 +#define ISPCCDC_LSC_INITIAL_Y_MASK 0x3F0000 +#define ISPCCDC_LSC_INITIAL_Y_SHIFT 16 + +/* ----------------------------------------------------------------------------- + * CSI2 receiver registers (ES2.0) + */ + +#define ISPCSI2_REVISION (0x000) +#define ISPCSI2_SYSCONFIG (0x010) +#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12 +#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK \ + (0x3 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) +#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_FORCE \ + (0x0 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) +#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO \ + (0x1 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) +#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART \ + (0x2 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT) +#define ISPCSI2_SYSCONFIG_SOFT_RESET (1 << 1) +#define ISPCSI2_SYSCONFIG_AUTO_IDLE (1 << 0) + +#define ISPCSI2_SYSSTATUS (0x014) +#define ISPCSI2_SYSSTATUS_RESET_DONE (1 << 0) + +#define ISPCSI2_IRQSTATUS (0x018) +#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ (1 << 14) +#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ (1 << 13) +#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 12) +#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ (1 << 11) +#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ (1 << 10) +#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ (1 << 9) +#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ (1 << 8) +#define ISPCSI2_IRQSTATUS_CONTEXT(n) (1 << (n)) + +#define ISPCSI2_IRQENABLE (0x01c) +#define ISPCSI2_CTRL (0x040) +#define ISPCSI2_CTRL_VP_CLK_EN (1 << 15) +#define ISPCSI2_CTRL_VP_ONLY_EN (1 << 11) +#define ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT 8 +#define ISPCSI2_CTRL_VP_OUT_CTRL_MASK \ + (3 << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT) +#define ISPCSI2_CTRL_DBG_EN (1 << 7) +#define ISPCSI2_CTRL_BURST_SIZE_SHIFT 5 +#define ISPCSI2_CTRL_BURST_SIZE_MASK \ + (3 << ISPCSI2_CTRL_BURST_SIZE_SHIFT) +#define ISPCSI2_CTRL_FRAME (1 << 3) +#define ISPCSI2_CTRL_ECC_EN (1 << 2) +#define ISPCSI2_CTRL_SECURE (1 << 1) +#define ISPCSI2_CTRL_IF_EN (1 << 0) + +#define ISPCSI2_DBG_H (0x044) +#define ISPCSI2_GNQ (0x048) +#define ISPCSI2_PHY_CFG (0x050) +#define ISPCSI2_PHY_CFG_RESET_CTRL (1 << 30) +#define ISPCSI2_PHY_CFG_RESET_DONE (1 << 29) +#define ISPCSI2_PHY_CFG_PWR_CMD_SHIFT 27 +#define ISPCSI2_PHY_CFG_PWR_CMD_MASK \ + (0x3 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_CMD_OFF \ + (0x0 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_CMD_ON \ + (0x1 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_CMD_ULPW \ + (0x2 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT 25 +#define ISPCSI2_PHY_CFG_PWR_STATUS_MASK \ + (0x3 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_STATUS_OFF \ + (0x0 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_STATUS_ON \ + (0x1 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_STATUS_ULPW \ + (0x2 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT) +#define ISPCSI2_PHY_CFG_PWR_AUTO (1 << 24) + +#define ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n) (3 + ((n) * 4)) +#define ISPCSI2_PHY_CFG_DATA_POL_MASK(n) \ + (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POL_PN(n) \ + (0x0 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POL_NP(n) \ + (0x1 << ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n)) + +#define ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n) ((n) * 4) +#define ISPCSI2_PHY_CFG_DATA_POSITION_MASK(n) \ + (0x7 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POSITION_NC(n) \ + (0x0 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POSITION_1(n) \ + (0x1 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POSITION_2(n) \ + (0x2 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POSITION_3(n) \ + (0x3 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POSITION_4(n) \ + (0x4 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) +#define ISPCSI2_PHY_CFG_DATA_POSITION_5(n) \ + (0x5 << ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(n)) + +#define ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT 3 +#define ISPCSI2_PHY_CFG_CLOCK_POL_MASK \ + (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT) +#define ISPCSI2_PHY_CFG_CLOCK_POL_PN \ + (0x0 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT) +#define ISPCSI2_PHY_CFG_CLOCK_POL_NP \ + (0x1 << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT) + +#define ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT 0 +#define ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK \ + (0x7 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) +#define ISPCSI2_PHY_CFG_CLOCK_POSITION_1 \ + (0x1 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) +#define ISPCSI2_PHY_CFG_CLOCK_POSITION_2 \ + (0x2 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) +#define ISPCSI2_PHY_CFG_CLOCK_POSITION_3 \ + (0x3 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) +#define ISPCSI2_PHY_CFG_CLOCK_POSITION_4 \ + (0x4 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) +#define ISPCSI2_PHY_CFG_CLOCK_POSITION_5 \ + (0x5 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT) + +#define ISPCSI2_PHY_IRQSTATUS (0x054) +#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT (1 << 26) +#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER (1 << 25) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5 (1 << 24) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4 (1 << 23) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3 (1 << 22) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2 (1 << 21) +#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1 (1 << 20) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5 (1 << 19) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4 (1 << 18) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3 (1 << 17) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2 (1 << 16) +#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1 (1 << 15) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC5 (1 << 14) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC4 (1 << 13) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC3 (1 << 12) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC2 (1 << 11) +#define ISPCSI2_PHY_IRQSTATUS_ERRESC1 (1 << 10) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5 (1 << 9) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4 (1 << 8) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3 (1 << 7) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2 (1 << 6) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1 (1 << 5) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5 (1 << 4) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4 (1 << 3) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3 (1 << 2) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2 (1 << 1) +#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1 1 + +#define ISPCSI2_SHORT_PACKET (0x05c) +#define ISPCSI2_PHY_IRQENABLE (0x060) +#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT (1 << 26) +#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER (1 << 25) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM5 (1 << 24) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM4 (1 << 23) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM3 (1 << 22) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM2 (1 << 21) +#define ISPCSI2_PHY_IRQENABLE_STATEULPM1 (1 << 20) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 (1 << 19) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 (1 << 18) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 (1 << 17) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 (1 << 16) +#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 (1 << 15) +#define ISPCSI2_PHY_IRQENABLE_ERRESC5 (1 << 14) +#define ISPCSI2_PHY_IRQENABLE_ERRESC4 (1 << 13) +#define ISPCSI2_PHY_IRQENABLE_ERRESC3 (1 << 12) +#define ISPCSI2_PHY_IRQENABLE_ERRESC2 (1 << 11) +#define ISPCSI2_PHY_IRQENABLE_ERRESC1 (1 << 10) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 (1 << 9) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 (1 << 8) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 (1 << 7) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 (1 << 6) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 (1 << 5) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 (1 << 4) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 (1 << 3) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 (1 << 2) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 (1 << 1) +#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1 (1 << 0) + +#define ISPCSI2_DBG_P (0x068) +#define ISPCSI2_TIMING (0x06c) +#define ISPCSI2_TIMING_FORCE_RX_MODE_IO(n) (1 << ((16 * ((n) - 1)) + 15)) +#define ISPCSI2_TIMING_STOP_STATE_X16_IO(n) (1 << ((16 * ((n) - 1)) + 14)) +#define ISPCSI2_TIMING_STOP_STATE_X4_IO(n) (1 << ((16 * ((n) - 1)) + 13)) +#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n) (16 * ((n) - 1)) +#define ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(n) \ + (0x1fff << ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(n)) + +#define ISPCSI2_CTX_CTRL1(n) ((0x070) + 0x20 * (n)) +#define ISPCSI2_CTX_CTRL1_COUNT_SHIFT 8 +#define ISPCSI2_CTX_CTRL1_COUNT_MASK \ + (0xff << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) +#define ISPCSI2_CTX_CTRL1_EOF_EN (1 << 7) +#define ISPCSI2_CTX_CTRL1_EOL_EN (1 << 6) +#define ISPCSI2_CTX_CTRL1_CS_EN (1 << 5) +#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK (1 << 4) +#define ISPCSI2_CTX_CTRL1_PING_PONG (1 << 3) +#define ISPCSI2_CTX_CTRL1_CTX_EN (1 << 0) + +#define ISPCSI2_CTX_CTRL2(n) ((0x074) + 0x20 * (n)) +#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13 +#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK \ + (0x3 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT) +#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT 11 +#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK \ + (0x3 << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT) +#define ISPCSI2_CTX_CTRL2_DPCM_PRED (1 << 10) +#define ISPCSI2_CTX_CTRL2_FORMAT_SHIFT 0 +#define ISPCSI2_CTX_CTRL2_FORMAT_MASK \ + (0x3ff << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT) +#define ISPCSI2_CTX_CTRL2_FRAME_SHIFT 16 +#define ISPCSI2_CTX_CTRL2_FRAME_MASK \ + (0xffff << ISPCSI2_CTX_CTRL2_FRAME_SHIFT) + +#define ISPCSI2_CTX_DAT_OFST(n) ((0x078) + 0x20 * (n)) +#define ISPCSI2_CTX_DAT_OFST_OFST_SHIFT 0 +#define ISPCSI2_CTX_DAT_OFST_OFST_MASK \ + (0x1ffe0 << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT) + +#define ISPCSI2_CTX_DAT_PING_ADDR(n) ((0x07c) + 0x20 * (n)) +#define ISPCSI2_CTX_DAT_PONG_ADDR(n) ((0x080) + 0x20 * (n)) +#define ISPCSI2_CTX_IRQENABLE(n) ((0x084) + 0x20 * (n)) +#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ (1 << 8) +#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ (1 << 7) +#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ (1 << 6) +#define ISPCSI2_CTX_IRQENABLE_CS_IRQ (1 << 5) +#define ISPCSI2_CTX_IRQENABLE_LE_IRQ (1 << 3) +#define ISPCSI2_CTX_IRQENABLE_LS_IRQ (1 << 2) +#define ISPCSI2_CTX_IRQENABLE_FE_IRQ (1 << 1) +#define ISPCSI2_CTX_IRQENABLE_FS_IRQ (1 << 0) + +#define ISPCSI2_CTX_IRQSTATUS(n) ((0x088) + 0x20 * (n)) +#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 8) +#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ (1 << 7) +#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ (1 << 6) +#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ (1 << 5) +#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ (1 << 3) +#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ (1 << 2) +#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ (1 << 1) +#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ (1 << 0) + +#define ISPCSI2_CTX_CTRL3(n) ((0x08c) + 0x20 * (n)) +#define ISPCSI2_CTX_CTRL3_ALPHA_SHIFT 5 +#define ISPCSI2_CTX_CTRL3_ALPHA_MASK \ + (0x3fff << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT) + +/* This instance is for OMAP3630 only */ +#define ISPCSI2_CTX_TRANSCODEH(n) (0x000 + 0x8 * (n)) +#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT 16 +#define ISPCSI2_CTX_TRANSCODEH_HCOUNT_MASK \ + (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT) +#define ISPCSI2_CTX_TRANSCODEH_HSKIP_SHIFT 0 +#define ISPCSI2_CTX_TRANSCODEH_HSKIP_MASK \ + (0x1fff << ISPCSI2_CTX_TRANSCODEH_HCOUNT_SHIFT) +#define ISPCSI2_CTX_TRANSCODEV(n) (0x004 + 0x8 * (n)) +#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT 16 +#define ISPCSI2_CTX_TRANSCODEV_VCOUNT_MASK \ + (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT) +#define ISPCSI2_CTX_TRANSCODEV_VSKIP_SHIFT 0 +#define ISPCSI2_CTX_TRANSCODEV_VSKIP_MASK \ + (0x1fff << ISPCSI2_CTX_TRANSCODEV_VCOUNT_SHIFT) + +/* ----------------------------------------------------------------------------- + * CSI PHY registers + */ + +#define ISPCSIPHY_REG0 (0x000) +#define ISPCSIPHY_REG0_THS_TERM_SHIFT 8 +#define ISPCSIPHY_REG0_THS_TERM_MASK \ + (0xff << ISPCSIPHY_REG0_THS_TERM_SHIFT) +#define ISPCSIPHY_REG0_THS_SETTLE_SHIFT 0 +#define ISPCSIPHY_REG0_THS_SETTLE_MASK \ + (0xff << ISPCSIPHY_REG0_THS_SETTLE_SHIFT) + +#define ISPCSIPHY_REG1 (0x004) +#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK (1 << 29) +/* This field is for OMAP3630 only */ +#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS (1 << 25) +#define ISPCSIPHY_REG1_TCLK_TERM_SHIFT 18 +#define ISPCSIPHY_REG1_TCLK_TERM_MASK \ + (0x7f << ISPCSIPHY_REG1_TCLK_TERM_SHIFT) +#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_SHIFT 10 +#define ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN_MASK \ + (0xff << ISPCSIPHY_REG1_DPHY_HS_SYNC_PATTERN) +/* This field is for OMAP3430 only */ +#define ISPCSIPHY_REG1_TCLK_MISS_SHIFT 8 +#define ISPCSIPHY_REG1_TCLK_MISS_MASK \ + (0x3 << ISPCSIPHY_REG1_TCLK_MISS_SHIFT) +/* This field is for OMAP3630 only */ +#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT 8 +#define ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_MASK \ + (0x3 << ISPCSIPHY_REG1_CTRLCLK_DIV_FACTOR_SHIFT) +#define ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT 0 +#define ISPCSIPHY_REG1_TCLK_SETTLE_MASK \ + (0xff << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT) + +/* This register is for OMAP3630 only */ +#define ISPCSIPHY_REG2 (0x008) +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT 30 +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK \ + (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC0_SHIFT) +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT 28 +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK \ + (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC1_SHIFT) +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT 26 +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK \ + (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC2_SHIFT) +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT 24 +#define ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK \ + (0x3 << ISPCSIPHY_REG2_TRIGGER_CMD_RXTRIGESC3_SHIFT) +#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT 0 +#define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_MASK \ + (0x7fffff << ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT) + +#endif /* OMAP3_ISP_REG_H */ -- cgit v1.2.2 From ad614acb7eca429891313f57bafbe5b3924a5aae Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 12 Feb 2011 18:05:06 -0300 Subject: [media] omap3isp: Video devices and buffers queue The OMAP3 ISP video devices and buffers queue modules implement the V4L2 API on all the ISP video nodes. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: David Cohen Signed-off-by: Stanimir Varbanov Signed-off-by: Vimarsh Zutshi Signed-off-by: Tuukka Toivonen Signed-off-by: Sergio Aguirre Signed-off-by: Antti Koskipaa Signed-off-by: Ivan T. Ivanov Signed-off-by: RaniSuneela Signed-off-by: Atanas Filipov Signed-off-by: Gjorgji Rosikopulos Signed-off-by: Hiroshi DOYU Signed-off-by: Nayden Kanchev Signed-off-by: Phil Carmody Signed-off-by: Artem Bityutskiy Signed-off-by: Dominic Curran Signed-off-by: Ilkka Myllyperkio Signed-off-by: Pallavi Kulkarni Signed-off-by: Vaibhav Hiremath Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispqueue.c | 1153 ++++++++++++++++++++++++++++ drivers/media/video/omap3isp/ispqueue.h | 187 +++++ drivers/media/video/omap3isp/ispvideo.c | 1264 +++++++++++++++++++++++++++++++ drivers/media/video/omap3isp/ispvideo.h | 202 +++++ 4 files changed, 2806 insertions(+) create mode 100644 drivers/media/video/omap3isp/ispqueue.c create mode 100644 drivers/media/video/omap3isp/ispqueue.h create mode 100644 drivers/media/video/omap3isp/ispvideo.c create mode 100644 drivers/media/video/omap3isp/ispvideo.h (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c new file mode 100644 index 000000000000..8fddc5806b0d --- /dev/null +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -0,0 +1,1153 @@ +/* + * ispqueue.c + * + * TI OMAP3 ISP - Video buffers queue handling + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ispqueue.h" + +/* ----------------------------------------------------------------------------- + * Video buffers management + */ + +/* + * isp_video_buffer_cache_sync - Keep the buffers coherent between CPU and ISP + * + * The typical operation required here is Cache Invalidation across + * the (user space) buffer address range. And this _must_ be done + * at QBUF stage (and *only* at QBUF). + * + * We try to use optimal cache invalidation function: + * - dmac_map_area: + * - used when the number of pages are _low_. + * - it becomes quite slow as the number of pages increase. + * - for 648x492 viewfinder (150 pages) it takes 1.3 ms. + * - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms. + * + * - flush_cache_all: + * - used when the number of pages are _high_. + * - time taken in the range of 500-900 us. + * - has a higher penalty but, as whole dcache + icache is invalidated + */ +/* + * FIXME: dmac_inv_range crashes randomly on the user space buffer + * address. Fall back to flush_cache_all for now. + */ +#define ISP_CACHE_FLUSH_PAGES_MAX 0 + +static void isp_video_buffer_cache_sync(struct isp_video_buffer *buf) +{ + if (buf->skip_cache) + return; + + if (buf->vbuf.m.userptr == 0 || buf->npages == 0 || + buf->npages > ISP_CACHE_FLUSH_PAGES_MAX) + flush_cache_all(); + else { + dmac_map_area((void *)buf->vbuf.m.userptr, buf->vbuf.length, + DMA_FROM_DEVICE); + outer_inv_range(buf->vbuf.m.userptr, + buf->vbuf.m.userptr + buf->vbuf.length); + } +} + +/* + * isp_video_buffer_lock_vma - Prevent VMAs from being unmapped + * + * Lock the VMAs underlying the given buffer into memory. This avoids the + * userspace buffer mapping from being swapped out, making VIPT cache handling + * easier. + * + * Note that the pages will not be freed as the buffers have been locked to + * memory using by a call to get_user_pages(), but the userspace mapping could + * still disappear if the VMAs are not locked. This is caused by the memory + * management code trying to be as lock-less as possible, which results in the + * userspace mapping manager not finding out that the pages are locked under + * some conditions. + */ +static int isp_video_buffer_lock_vma(struct isp_video_buffer *buf, int lock) +{ + struct vm_area_struct *vma; + unsigned long start; + unsigned long end; + int ret = 0; + + if (buf->vbuf.memory == V4L2_MEMORY_MMAP) + return 0; + + /* We can be called from workqueue context if the current task dies to + * unlock the VMAs. In that case there's no current memory management + * context so unlocking can't be performed, but the VMAs have been or + * are getting destroyed anyway so it doesn't really matter. + */ + if (!current || !current->mm) + return lock ? -EINVAL : 0; + + start = buf->vbuf.m.userptr; + end = buf->vbuf.m.userptr + buf->vbuf.length - 1; + + down_write(¤t->mm->mmap_sem); + spin_lock(¤t->mm->page_table_lock); + + do { + vma = find_vma(current->mm, start); + if (vma == NULL) { + ret = -EFAULT; + goto out; + } + + if (lock) + vma->vm_flags |= VM_LOCKED; + else + vma->vm_flags &= ~VM_LOCKED; + + start = vma->vm_end + 1; + } while (vma->vm_end < end); + + if (lock) + buf->vm_flags |= VM_LOCKED; + else + buf->vm_flags &= ~VM_LOCKED; + +out: + spin_unlock(¤t->mm->page_table_lock); + up_write(¤t->mm->mmap_sem); + return ret; +} + +/* + * isp_video_buffer_sglist_kernel - Build a scatter list for a vmalloc'ed buffer + * + * Iterate over the vmalloc'ed area and create a scatter list entry for every + * page. + */ +static int isp_video_buffer_sglist_kernel(struct isp_video_buffer *buf) +{ + struct scatterlist *sglist; + unsigned int npages; + unsigned int i; + void *addr; + + addr = buf->vaddr; + npages = PAGE_ALIGN(buf->vbuf.length) >> PAGE_SHIFT; + + sglist = vmalloc(npages * sizeof(*sglist)); + if (sglist == NULL) + return -ENOMEM; + + sg_init_table(sglist, npages); + + for (i = 0; i < npages; ++i, addr += PAGE_SIZE) { + struct page *page = vmalloc_to_page(addr); + + if (page == NULL || PageHighMem(page)) { + vfree(sglist); + return -EINVAL; + } + + sg_set_page(&sglist[i], page, PAGE_SIZE, 0); + } + + buf->sglen = npages; + buf->sglist = sglist; + + return 0; +} + +/* + * isp_video_buffer_sglist_user - Build a scatter list for a userspace buffer + * + * Walk the buffer pages list and create a 1:1 mapping to a scatter list. + */ +static int isp_video_buffer_sglist_user(struct isp_video_buffer *buf) +{ + struct scatterlist *sglist; + unsigned int offset = buf->offset; + unsigned int i; + + sglist = vmalloc(buf->npages * sizeof(*sglist)); + if (sglist == NULL) + return -ENOMEM; + + sg_init_table(sglist, buf->npages); + + for (i = 0; i < buf->npages; ++i) { + if (PageHighMem(buf->pages[i])) { + vfree(sglist); + return -EINVAL; + } + + sg_set_page(&sglist[i], buf->pages[i], PAGE_SIZE - offset, + offset); + offset = 0; + } + + buf->sglen = buf->npages; + buf->sglist = sglist; + + return 0; +} + +/* + * isp_video_buffer_sglist_pfnmap - Build a scatter list for a VM_PFNMAP buffer + * + * Create a scatter list of physically contiguous pages starting at the buffer + * memory physical address. + */ +static int isp_video_buffer_sglist_pfnmap(struct isp_video_buffer *buf) +{ + struct scatterlist *sglist; + unsigned int offset = buf->offset; + unsigned long pfn = buf->paddr >> PAGE_SHIFT; + unsigned int i; + + sglist = vmalloc(buf->npages * sizeof(*sglist)); + if (sglist == NULL) + return -ENOMEM; + + sg_init_table(sglist, buf->npages); + + for (i = 0; i < buf->npages; ++i, ++pfn) { + sg_set_page(&sglist[i], pfn_to_page(pfn), PAGE_SIZE - offset, + offset); + /* PFNMAP buffers will not get DMA-mapped, set the DMA address + * manually. + */ + sg_dma_address(&sglist[i]) = (pfn << PAGE_SHIFT) + offset; + offset = 0; + } + + buf->sglen = buf->npages; + buf->sglist = sglist; + + return 0; +} + +/* + * isp_video_buffer_cleanup - Release pages for a userspace VMA. + * + * Release pages locked by a call isp_video_buffer_prepare_user and free the + * pages table. + */ +static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) +{ + enum dma_data_direction direction; + unsigned int i; + + if (buf->queue->ops->buffer_cleanup) + buf->queue->ops->buffer_cleanup(buf); + + if (!(buf->vm_flags & VM_PFNMAP)) { + direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + dma_unmap_sg(buf->queue->dev, buf->sglist, buf->sglen, + direction); + } + + vfree(buf->sglist); + buf->sglist = NULL; + buf->sglen = 0; + + if (buf->pages != NULL) { + isp_video_buffer_lock_vma(buf, 0); + + for (i = 0; i < buf->npages; ++i) + page_cache_release(buf->pages[i]); + + vfree(buf->pages); + buf->pages = NULL; + } + + buf->npages = 0; + buf->skip_cache = false; +} + +/* + * isp_video_buffer_prepare_user - Pin userspace VMA pages to memory. + * + * This function creates a list of pages for a userspace VMA. The number of + * pages is first computed based on the buffer size, and pages are then + * retrieved by a call to get_user_pages. + * + * Pages are pinned to memory by get_user_pages, making them available for DMA + * transfers. However, due to memory management optimization, it seems the + * get_user_pages doesn't guarantee that the pinned pages will not be written + * to swap and removed from the userspace mapping(s). When this happens, a page + * fault can be generated when accessing those unmapped pages. + * + * If the fault is triggered by a page table walk caused by VIPT cache + * management operations, the page fault handler might oops if the MM semaphore + * is held, as it can't handle kernel page faults in that case. To fix that, a + * fixup entry needs to be added to the cache management code, or the userspace + * VMA must be locked to avoid removing pages from the userspace mapping in the + * first place. + * + * If the number of pages retrieved is smaller than the number required by the + * buffer size, the function returns -EFAULT. + */ +static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) +{ + unsigned long data; + unsigned int first; + unsigned int last; + int ret; + + data = buf->vbuf.m.userptr; + first = (data & PAGE_MASK) >> PAGE_SHIFT; + last = ((data + buf->vbuf.length - 1) & PAGE_MASK) >> PAGE_SHIFT; + + buf->offset = data & ~PAGE_MASK; + buf->npages = last - first + 1; + buf->pages = vmalloc(buf->npages * sizeof(buf->pages[0])); + if (buf->pages == NULL) + return -ENOMEM; + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, data & PAGE_MASK, + buf->npages, + buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, + buf->pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (ret != buf->npages) { + buf->npages = ret; + isp_video_buffer_cleanup(buf); + return -EFAULT; + } + + ret = isp_video_buffer_lock_vma(buf, 1); + if (ret < 0) + isp_video_buffer_cleanup(buf); + + return ret; +} + +/* + * isp_video_buffer_prepare_pfnmap - Validate a VM_PFNMAP userspace buffer + * + * Userspace VM_PFNMAP buffers are supported only if they are contiguous in + * memory and if they span a single VMA. + * + * Return 0 if the buffer is valid, or -EFAULT otherwise. + */ +static int isp_video_buffer_prepare_pfnmap(struct isp_video_buffer *buf) +{ + struct vm_area_struct *vma; + unsigned long prev_pfn; + unsigned long this_pfn; + unsigned long start; + unsigned long end; + dma_addr_t pa; + int ret = -EFAULT; + + start = buf->vbuf.m.userptr; + end = buf->vbuf.m.userptr + buf->vbuf.length - 1; + + buf->offset = start & ~PAGE_MASK; + buf->npages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; + buf->pages = NULL; + + down_read(¤t->mm->mmap_sem); + vma = find_vma(current->mm, start); + if (vma == NULL || vma->vm_end < end) + goto done; + + for (prev_pfn = 0; start <= end; start += PAGE_SIZE) { + ret = follow_pfn(vma, start, &this_pfn); + if (ret) + goto done; + + if (prev_pfn == 0) + pa = this_pfn << PAGE_SHIFT; + else if (this_pfn != prev_pfn + 1) { + ret = -EFAULT; + goto done; + } + + prev_pfn = this_pfn; + } + + buf->paddr = pa + buf->offset; + ret = 0; + +done: + up_read(¤t->mm->mmap_sem); + return ret; +} + +/* + * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address + * + * This function locates the VMAs for the buffer's userspace address and checks + * that their flags match. The onlflag that we need to care for at the moment is + * VM_PFNMAP. + * + * The buffer vm_flags field is set to the first VMA flags. + * + * Return -EFAULT if no VMA can be found for part of the buffer, or if the VMAs + * have incompatible flags. + */ +static int isp_video_buffer_prepare_vm_flags(struct isp_video_buffer *buf) +{ + struct vm_area_struct *vma; + pgprot_t vm_page_prot; + unsigned long start; + unsigned long end; + int ret = -EFAULT; + + start = buf->vbuf.m.userptr; + end = buf->vbuf.m.userptr + buf->vbuf.length - 1; + + down_read(¤t->mm->mmap_sem); + + do { + vma = find_vma(current->mm, start); + if (vma == NULL) + goto done; + + if (start == buf->vbuf.m.userptr) { + buf->vm_flags = vma->vm_flags; + vm_page_prot = vma->vm_page_prot; + } + + if ((buf->vm_flags ^ vma->vm_flags) & VM_PFNMAP) + goto done; + + if (vm_page_prot != vma->vm_page_prot) + goto done; + + start = vma->vm_end + 1; + } while (vma->vm_end < end); + + /* Skip cache management to enhance performances for non-cached or + * write-combining buffers. + */ + if (vm_page_prot == pgprot_noncached(vm_page_prot) || + vm_page_prot == pgprot_writecombine(vm_page_prot)) + buf->skip_cache = true; + + ret = 0; + +done: + up_read(¤t->mm->mmap_sem); + return ret; +} + +/* + * isp_video_buffer_prepare - Make a buffer ready for operation + * + * Preparing a buffer involves: + * + * - validating VMAs (userspace buffers only) + * - locking pages and VMAs into memory (userspace buffers only) + * - building page and scatter-gather lists + * - mapping buffers for DMA operation + * - performing driver-specific preparation + * + * The function must be called in userspace context with a valid mm context + * (this excludes cleanup paths such as sys_close when the userspace process + * segfaults). + */ +static int isp_video_buffer_prepare(struct isp_video_buffer *buf) +{ + enum dma_data_direction direction; + int ret; + + switch (buf->vbuf.memory) { + case V4L2_MEMORY_MMAP: + ret = isp_video_buffer_sglist_kernel(buf); + break; + + case V4L2_MEMORY_USERPTR: + ret = isp_video_buffer_prepare_vm_flags(buf); + if (ret < 0) + return ret; + + if (buf->vm_flags & VM_PFNMAP) { + ret = isp_video_buffer_prepare_pfnmap(buf); + if (ret < 0) + return ret; + + ret = isp_video_buffer_sglist_pfnmap(buf); + } else { + ret = isp_video_buffer_prepare_user(buf); + if (ret < 0) + return ret; + + ret = isp_video_buffer_sglist_user(buf); + } + break; + + default: + return -EINVAL; + } + + if (ret < 0) + goto done; + + if (!(buf->vm_flags & VM_PFNMAP)) { + direction = buf->vbuf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE + ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + ret = dma_map_sg(buf->queue->dev, buf->sglist, buf->sglen, + direction); + if (ret != buf->sglen) { + ret = -EFAULT; + goto done; + } + } + + if (buf->queue->ops->buffer_prepare) + ret = buf->queue->ops->buffer_prepare(buf); + +done: + if (ret < 0) { + isp_video_buffer_cleanup(buf); + return ret; + } + + return ret; +} + +/* + * isp_video_queue_query - Query the status of a given buffer + * + * Locking: must be called with the queue lock held. + */ +static void isp_video_buffer_query(struct isp_video_buffer *buf, + struct v4l2_buffer *vbuf) +{ + memcpy(vbuf, &buf->vbuf, sizeof(*vbuf)); + + if (buf->vma_use_count) + vbuf->flags |= V4L2_BUF_FLAG_MAPPED; + + switch (buf->state) { + case ISP_BUF_STATE_ERROR: + vbuf->flags |= V4L2_BUF_FLAG_ERROR; + case ISP_BUF_STATE_DONE: + vbuf->flags |= V4L2_BUF_FLAG_DONE; + case ISP_BUF_STATE_QUEUED: + case ISP_BUF_STATE_ACTIVE: + vbuf->flags |= V4L2_BUF_FLAG_QUEUED; + break; + case ISP_BUF_STATE_IDLE: + default: + break; + } +} + +/* + * isp_video_buffer_wait - Wait for a buffer to be ready + * + * In non-blocking mode, return immediately with 0 if the buffer is ready or + * -EAGAIN if the buffer is in the QUEUED or ACTIVE state. + * + * In blocking mode, wait (interruptibly but with no timeout) on the buffer wait + * queue using the same condition. + */ +static int isp_video_buffer_wait(struct isp_video_buffer *buf, int nonblocking) +{ + if (nonblocking) { + return (buf->state != ISP_BUF_STATE_QUEUED && + buf->state != ISP_BUF_STATE_ACTIVE) + ? 0 : -EAGAIN; + } + + return wait_event_interruptible(buf->wait, + buf->state != ISP_BUF_STATE_QUEUED && + buf->state != ISP_BUF_STATE_ACTIVE); +} + +/* ----------------------------------------------------------------------------- + * Queue management + */ + +/* + * isp_video_queue_free - Free video buffers memory + * + * Buffers can only be freed if the queue isn't streaming and if no buffer is + * mapped to userspace. Return -EBUSY if those conditions aren't statisfied. + * + * This function must be called with the queue lock held. + */ +static int isp_video_queue_free(struct isp_video_queue *queue) +{ + unsigned int i; + + if (queue->streaming) + return -EBUSY; + + for (i = 0; i < queue->count; ++i) { + if (queue->buffers[i]->vma_use_count != 0) + return -EBUSY; + } + + for (i = 0; i < queue->count; ++i) { + struct isp_video_buffer *buf = queue->buffers[i]; + + isp_video_buffer_cleanup(buf); + + vfree(buf->vaddr); + buf->vaddr = NULL; + + kfree(buf); + queue->buffers[i] = NULL; + } + + INIT_LIST_HEAD(&queue->queue); + queue->count = 0; + return 0; +} + +/* + * isp_video_queue_alloc - Allocate video buffers memory + * + * This function must be called with the queue lock held. + */ +static int isp_video_queue_alloc(struct isp_video_queue *queue, + unsigned int nbuffers, + unsigned int size, enum v4l2_memory memory) +{ + struct isp_video_buffer *buf; + unsigned int i; + void *mem; + int ret; + + /* Start by freeing the buffers. */ + ret = isp_video_queue_free(queue); + if (ret < 0) + return ret; + + /* Bail out of no buffers should be allocated. */ + if (nbuffers == 0) + return 0; + + /* Initialize the allocated buffers. */ + for (i = 0; i < nbuffers; ++i) { + buf = kzalloc(queue->bufsize, GFP_KERNEL); + if (buf == NULL) + break; + + if (memory == V4L2_MEMORY_MMAP) { + /* Allocate video buffers memory for mmap mode. Align + * the size to the page size. + */ + mem = vmalloc_32_user(PAGE_ALIGN(size)); + if (mem == NULL) { + kfree(buf); + break; + } + + buf->vbuf.m.offset = i * PAGE_ALIGN(size); + buf->vaddr = mem; + } + + buf->vbuf.index = i; + buf->vbuf.length = size; + buf->vbuf.type = queue->type; + buf->vbuf.field = V4L2_FIELD_NONE; + buf->vbuf.memory = memory; + + buf->queue = queue; + init_waitqueue_head(&buf->wait); + + queue->buffers[i] = buf; + } + + if (i == 0) + return -ENOMEM; + + queue->count = i; + return nbuffers; +} + +/** + * omap3isp_video_queue_cleanup - Clean up the video buffers queue + * @queue: Video buffers queue + * + * Free all allocated resources and clean up the video buffers queue. The queue + * must not be busy (no ongoing video stream) and buffers must have been + * unmapped. + * + * Return 0 on success or -EBUSY if the queue is busy or buffers haven't been + * unmapped. + */ +int omap3isp_video_queue_cleanup(struct isp_video_queue *queue) +{ + return isp_video_queue_free(queue); +} + +/** + * omap3isp_video_queue_init - Initialize the video buffers queue + * @queue: Video buffers queue + * @type: V4L2 buffer type (capture or output) + * @ops: Driver-specific queue operations + * @dev: Device used for DMA operations + * @bufsize: Size of the driver-specific buffer structure + * + * Initialize the video buffers queue with the supplied parameters. + * + * The queue type must be one of V4L2_BUF_TYPE_VIDEO_CAPTURE or + * V4L2_BUF_TYPE_VIDEO_OUTPUT. Other buffer types are not supported yet. + * + * Buffer objects will be allocated using the given buffer size to allow room + * for driver-specific fields. Driver-specific buffer structures must start + * with a struct isp_video_buffer field. Drivers with no driver-specific buffer + * structure must pass the size of the isp_video_buffer structure in the bufsize + * parameter. + * + * Return 0 on success. + */ +int omap3isp_video_queue_init(struct isp_video_queue *queue, + enum v4l2_buf_type type, + const struct isp_video_queue_operations *ops, + struct device *dev, unsigned int bufsize) +{ + INIT_LIST_HEAD(&queue->queue); + mutex_init(&queue->lock); + spin_lock_init(&queue->irqlock); + + queue->type = type; + queue->ops = ops; + queue->dev = dev; + queue->bufsize = bufsize; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 operations + */ + +/** + * omap3isp_video_queue_reqbufs - Allocate video buffers memory + * + * This function is intended to be used as a VIDIOC_REQBUFS ioctl handler. It + * allocated video buffer objects and, for MMAP buffers, buffer memory. + * + * If the number of buffers is 0, all buffers are freed and the function returns + * without performing any allocation. + * + * If the number of buffers is not 0, currently allocated buffers (if any) are + * freed and the requested number of buffers are allocated. Depending on + * driver-specific requirements and on memory availability, a number of buffer + * smaller or bigger than requested can be allocated. This isn't considered as + * an error. + * + * Return 0 on success or one of the following error codes: + * + * -EINVAL if the buffer type or index are invalid + * -EBUSY if the queue is busy (streaming or buffers mapped) + * -ENOMEM if the buffers can't be allocated due to an out-of-memory condition + */ +int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue, + struct v4l2_requestbuffers *rb) +{ + unsigned int nbuffers = rb->count; + unsigned int size; + int ret; + + if (rb->type != queue->type) + return -EINVAL; + + queue->ops->queue_prepare(queue, &nbuffers, &size); + if (size == 0) + return -EINVAL; + + nbuffers = min_t(unsigned int, nbuffers, ISP_VIDEO_MAX_BUFFERS); + + mutex_lock(&queue->lock); + + ret = isp_video_queue_alloc(queue, nbuffers, size, rb->memory); + if (ret < 0) + goto done; + + rb->count = ret; + ret = 0; + +done: + mutex_unlock(&queue->lock); + return ret; +} + +/** + * omap3isp_video_queue_querybuf - Query the status of a buffer in a queue + * + * This function is intended to be used as a VIDIOC_QUERYBUF ioctl handler. It + * returns the status of a given video buffer. + * + * Return 0 on success or -EINVAL if the buffer type or index are invalid. + */ +int omap3isp_video_queue_querybuf(struct isp_video_queue *queue, + struct v4l2_buffer *vbuf) +{ + struct isp_video_buffer *buf; + int ret = 0; + + if (vbuf->type != queue->type) + return -EINVAL; + + mutex_lock(&queue->lock); + + if (vbuf->index >= queue->count) { + ret = -EINVAL; + goto done; + } + + buf = queue->buffers[vbuf->index]; + isp_video_buffer_query(buf, vbuf); + +done: + mutex_unlock(&queue->lock); + return ret; +} + +/** + * omap3isp_video_queue_qbuf - Queue a buffer + * + * This function is intended to be used as a VIDIOC_QBUF ioctl handler. + * + * The v4l2_buffer structure passed from userspace is first sanity tested. If + * sane, the buffer is then processed and added to the main queue and, if the + * queue is streaming, to the IRQ queue. + * + * Before being enqueued, USERPTR buffers are checked for address changes. If + * the buffer has a different userspace address, the old memory area is unlocked + * and the new memory area is locked. + */ +int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, + struct v4l2_buffer *vbuf) +{ + struct isp_video_buffer *buf; + unsigned long flags; + int ret = -EINVAL; + + if (vbuf->type != queue->type) + goto done; + + mutex_lock(&queue->lock); + + if (vbuf->index >= queue->count) + goto done; + + buf = queue->buffers[vbuf->index]; + + if (vbuf->memory != buf->vbuf.memory) + goto done; + + if (buf->state != ISP_BUF_STATE_IDLE) + goto done; + + if (vbuf->memory == V4L2_MEMORY_USERPTR && + vbuf->m.userptr != buf->vbuf.m.userptr) { + isp_video_buffer_cleanup(buf); + buf->vbuf.m.userptr = vbuf->m.userptr; + buf->prepared = 0; + } + + if (!buf->prepared) { + ret = isp_video_buffer_prepare(buf); + if (ret < 0) + goto done; + buf->prepared = 1; + } + + isp_video_buffer_cache_sync(buf); + + buf->state = ISP_BUF_STATE_QUEUED; + list_add_tail(&buf->stream, &queue->queue); + + if (queue->streaming) { + spin_lock_irqsave(&queue->irqlock, flags); + queue->ops->buffer_queue(buf); + spin_unlock_irqrestore(&queue->irqlock, flags); + } + + ret = 0; + +done: + mutex_unlock(&queue->lock); + return ret; +} + +/** + * omap3isp_video_queue_dqbuf - Dequeue a buffer + * + * This function is intended to be used as a VIDIOC_DQBUF ioctl handler. + * + * The v4l2_buffer structure passed from userspace is first sanity tested. If + * sane, the buffer is then processed and added to the main queue and, if the + * queue is streaming, to the IRQ queue. + * + * Before being enqueued, USERPTR buffers are checked for address changes. If + * the buffer has a different userspace address, the old memory area is unlocked + * and the new memory area is locked. + */ +int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, + struct v4l2_buffer *vbuf, int nonblocking) +{ + struct isp_video_buffer *buf; + int ret; + + if (vbuf->type != queue->type) + return -EINVAL; + + mutex_lock(&queue->lock); + + if (list_empty(&queue->queue)) { + ret = -EINVAL; + goto done; + } + + buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); + ret = isp_video_buffer_wait(buf, nonblocking); + if (ret < 0) + goto done; + + list_del(&buf->stream); + + isp_video_buffer_query(buf, vbuf); + buf->state = ISP_BUF_STATE_IDLE; + vbuf->flags &= ~V4L2_BUF_FLAG_QUEUED; + +done: + mutex_unlock(&queue->lock); + return ret; +} + +/** + * omap3isp_video_queue_streamon - Start streaming + * + * This function is intended to be used as a VIDIOC_STREAMON ioctl handler. It + * starts streaming on the queue and calls the buffer_queue operation for all + * queued buffers. + * + * Return 0 on success. + */ +int omap3isp_video_queue_streamon(struct isp_video_queue *queue) +{ + struct isp_video_buffer *buf; + unsigned long flags; + + mutex_lock(&queue->lock); + + if (queue->streaming) + goto done; + + queue->streaming = 1; + + spin_lock_irqsave(&queue->irqlock, flags); + list_for_each_entry(buf, &queue->queue, stream) + queue->ops->buffer_queue(buf); + spin_unlock_irqrestore(&queue->irqlock, flags); + +done: + mutex_unlock(&queue->lock); + return 0; +} + +/** + * omap3isp_video_queue_streamoff - Stop streaming + * + * This function is intended to be used as a VIDIOC_STREAMOFF ioctl handler. It + * stops streaming on the queue and wakes up all the buffers. + * + * Drivers must stop the hardware and synchronize with interrupt handlers and/or + * delayed works before calling this function to make sure no buffer will be + * touched by the driver and/or hardware. + */ +void omap3isp_video_queue_streamoff(struct isp_video_queue *queue) +{ + struct isp_video_buffer *buf; + unsigned long flags; + unsigned int i; + + mutex_lock(&queue->lock); + + if (!queue->streaming) + goto done; + + queue->streaming = 0; + + spin_lock_irqsave(&queue->irqlock, flags); + for (i = 0; i < queue->count; ++i) { + buf = queue->buffers[i]; + + if (buf->state == ISP_BUF_STATE_ACTIVE) + wake_up(&buf->wait); + + buf->state = ISP_BUF_STATE_IDLE; + } + spin_unlock_irqrestore(&queue->irqlock, flags); + + INIT_LIST_HEAD(&queue->queue); + +done: + mutex_unlock(&queue->lock); +} + +/** + * omap3isp_video_queue_discard_done - Discard all buffers marked as DONE + * + * This function is intended to be used with suspend/resume operations. It + * discards all 'done' buffers as they would be too old to be requested after + * resume. + * + * Drivers must stop the hardware and synchronize with interrupt handlers and/or + * delayed works before calling this function to make sure no buffer will be + * touched by the driver and/or hardware. + */ +void omap3isp_video_queue_discard_done(struct isp_video_queue *queue) +{ + struct isp_video_buffer *buf; + unsigned int i; + + mutex_lock(&queue->lock); + + if (!queue->streaming) + goto done; + + for (i = 0; i < queue->count; ++i) { + buf = queue->buffers[i]; + + if (buf->state == ISP_BUF_STATE_DONE) + buf->state = ISP_BUF_STATE_ERROR; + } + +done: + mutex_unlock(&queue->lock); +} + +static void isp_video_queue_vm_open(struct vm_area_struct *vma) +{ + struct isp_video_buffer *buf = vma->vm_private_data; + + buf->vma_use_count++; +} + +static void isp_video_queue_vm_close(struct vm_area_struct *vma) +{ + struct isp_video_buffer *buf = vma->vm_private_data; + + buf->vma_use_count--; +} + +static const struct vm_operations_struct isp_video_queue_vm_ops = { + .open = isp_video_queue_vm_open, + .close = isp_video_queue_vm_close, +}; + +/** + * omap3isp_video_queue_mmap - Map buffers to userspace + * + * This function is intended to be used as an mmap() file operation handler. It + * maps a buffer to userspace based on the VMA offset. + * + * Only buffers of memory type MMAP are supported. + */ +int omap3isp_video_queue_mmap(struct isp_video_queue *queue, + struct vm_area_struct *vma) +{ + struct isp_video_buffer *uninitialized_var(buf); + unsigned long size; + unsigned int i; + int ret = 0; + + mutex_lock(&queue->lock); + + for (i = 0; i < queue->count; ++i) { + buf = queue->buffers[i]; + if ((buf->vbuf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) + break; + } + + if (i == queue->count) { + ret = -EINVAL; + goto done; + } + + size = vma->vm_end - vma->vm_start; + + if (buf->vbuf.memory != V4L2_MEMORY_MMAP || + size != PAGE_ALIGN(buf->vbuf.length)) { + ret = -EINVAL; + goto done; + } + + ret = remap_vmalloc_range(vma, buf->vaddr, 0); + if (ret < 0) + goto done; + + vma->vm_ops = &isp_video_queue_vm_ops; + vma->vm_private_data = buf; + isp_video_queue_vm_open(vma); + +done: + mutex_unlock(&queue->lock); + return ret; +} + +/** + * omap3isp_video_queue_poll - Poll video queue state + * + * This function is intended to be used as a poll() file operation handler. It + * polls the state of the video buffer at the front of the queue and returns an + * events mask. + * + * If no buffer is present at the front of the queue, POLLERR is returned. + */ +unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue, + struct file *file, poll_table *wait) +{ + struct isp_video_buffer *buf; + unsigned int mask = 0; + + mutex_lock(&queue->lock); + if (list_empty(&queue->queue)) { + mask |= POLLERR; + goto done; + } + buf = list_first_entry(&queue->queue, struct isp_video_buffer, stream); + + poll_wait(file, &buf->wait, wait); + if (buf->state == ISP_BUF_STATE_DONE || + buf->state == ISP_BUF_STATE_ERROR) { + if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + mask |= POLLIN | POLLRDNORM; + else + mask |= POLLOUT | POLLWRNORM; + } + +done: + mutex_unlock(&queue->lock); + return mask; +} diff --git a/drivers/media/video/omap3isp/ispqueue.h b/drivers/media/video/omap3isp/ispqueue.h new file mode 100644 index 000000000000..251de3e1679d --- /dev/null +++ b/drivers/media/video/omap3isp/ispqueue.h @@ -0,0 +1,187 @@ +/* + * ispqueue.h + * + * TI OMAP3 ISP - Video buffers queue handling + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_QUEUE_H +#define OMAP3_ISP_QUEUE_H + +#include +#include +#include +#include +#include + +struct isp_video_queue; +struct page; +struct scatterlist; + +#define ISP_VIDEO_MAX_BUFFERS 16 + +/** + * enum isp_video_buffer_state - ISP video buffer state + * @ISP_BUF_STATE_IDLE: The buffer is under userspace control (dequeued + * or not queued yet). + * @ISP_BUF_STATE_QUEUED: The buffer has been queued but isn't used by the + * device yet. + * @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer. + * @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error + * occured. For capture device the buffer likely contains corrupted data or + * no data at all. + * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occured. + * For capture devices the buffer contains valid data. + */ +enum isp_video_buffer_state { + ISP_BUF_STATE_IDLE, + ISP_BUF_STATE_QUEUED, + ISP_BUF_STATE_ACTIVE, + ISP_BUF_STATE_ERROR, + ISP_BUF_STATE_DONE, +}; + +/** + * struct isp_video_buffer - ISP video buffer + * @vma_use_count: Number of times the buffer is mmap'ed to userspace + * @stream: List head for insertion into main queue + * @queue: ISP buffers queue this buffer belongs to + * @prepared: Whether the buffer has been prepared + * @skip_cache: Whether to skip cache management operations for this buffer + * @vaddr: Memory virtual address (for kernel buffers) + * @vm_flags: Buffer VMA flags (for userspace buffers) + * @offset: Offset inside the first page (for userspace buffers) + * @npages: Number of pages (for userspace buffers) + * @pages: Pages table (for userspace non-VM_PFNMAP buffers) + * @paddr: Memory physical address (for userspace VM_PFNMAP buffers) + * @sglen: Number of elements in the scatter list (for non-VM_PFNMAP buffers) + * @sglist: Scatter list (for non-VM_PFNMAP buffers) + * @vbuf: V4L2 buffer + * @irqlist: List head for insertion into IRQ queue + * @state: Current buffer state + * @wait: Wait queue to signal buffer completion + */ +struct isp_video_buffer { + unsigned long vma_use_count; + struct list_head stream; + struct isp_video_queue *queue; + unsigned int prepared:1; + bool skip_cache; + + /* For kernel buffers. */ + void *vaddr; + + /* For userspace buffers. */ + unsigned long vm_flags; + unsigned long offset; + unsigned int npages; + struct page **pages; + dma_addr_t paddr; + + /* For all buffers except VM_PFNMAP. */ + unsigned int sglen; + struct scatterlist *sglist; + + /* Touched by the interrupt handler. */ + struct v4l2_buffer vbuf; + struct list_head irqlist; + enum isp_video_buffer_state state; + wait_queue_head_t wait; +}; + +#define to_isp_video_buffer(vb) container_of(vb, struct isp_video_buffer, vb) + +/** + * struct isp_video_queue_operations - Driver-specific operations + * @queue_prepare: Called before allocating buffers. Drivers should clamp the + * number of buffers according to their requirements, and must return the + * buffer size in bytes. + * @buffer_prepare: Called the first time a buffer is queued, or after changing + * the userspace memory address for a USERPTR buffer, with the queue lock + * held. Drivers should perform device-specific buffer preparation (such as + * mapping the buffer memory in an IOMMU). This operation is optional. + * @buffer_queue: Called when a buffer is being added to the queue with the + * queue irqlock spinlock held. + * @buffer_cleanup: Called before freeing buffers, or before changing the + * userspace memory address for a USERPTR buffer, with the queue lock held. + * Drivers must perform cleanup operations required to undo the + * buffer_prepare call. This operation is optional. + */ +struct isp_video_queue_operations { + void (*queue_prepare)(struct isp_video_queue *queue, + unsigned int *nbuffers, unsigned int *size); + int (*buffer_prepare)(struct isp_video_buffer *buf); + void (*buffer_queue)(struct isp_video_buffer *buf); + void (*buffer_cleanup)(struct isp_video_buffer *buf); +}; + +/** + * struct isp_video_queue - ISP video buffers queue + * @type: Type of video buffers handled by this queue + * @ops: Queue operations + * @dev: Device used for DMA operations + * @bufsize: Size of a driver-specific buffer object + * @count: Number of currently allocated buffers + * @buffers: ISP video buffers + * @lock: Mutex to protect access to the buffers, main queue and state + * @irqlock: Spinlock to protect access to the IRQ queue + * @streaming: Queue state, indicates whether the queue is streaming + * @queue: List of all queued buffers + */ +struct isp_video_queue { + enum v4l2_buf_type type; + const struct isp_video_queue_operations *ops; + struct device *dev; + unsigned int bufsize; + + unsigned int count; + struct isp_video_buffer *buffers[ISP_VIDEO_MAX_BUFFERS]; + struct mutex lock; + spinlock_t irqlock; + + unsigned int streaming:1; + + struct list_head queue; +}; + +int omap3isp_video_queue_cleanup(struct isp_video_queue *queue); +int omap3isp_video_queue_init(struct isp_video_queue *queue, + enum v4l2_buf_type type, + const struct isp_video_queue_operations *ops, + struct device *dev, unsigned int bufsize); + +int omap3isp_video_queue_reqbufs(struct isp_video_queue *queue, + struct v4l2_requestbuffers *rb); +int omap3isp_video_queue_querybuf(struct isp_video_queue *queue, + struct v4l2_buffer *vbuf); +int omap3isp_video_queue_qbuf(struct isp_video_queue *queue, + struct v4l2_buffer *vbuf); +int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue, + struct v4l2_buffer *vbuf, int nonblocking); +int omap3isp_video_queue_streamon(struct isp_video_queue *queue); +void omap3isp_video_queue_streamoff(struct isp_video_queue *queue); +void omap3isp_video_queue_discard_done(struct isp_video_queue *queue); +int omap3isp_video_queue_mmap(struct isp_video_queue *queue, + struct vm_area_struct *vma); +unsigned int omap3isp_video_queue_poll(struct isp_video_queue *queue, + struct file *file, poll_table *wait); + +#endif /* OMAP3_ISP_QUEUE_H */ diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c new file mode 100644 index 000000000000..517a24de5836 --- /dev/null +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -0,0 +1,1264 @@ +/* + * ispvideo.c + * + * TI OMAP3 ISP - Generic video node + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ispvideo.h" +#include "isp.h" + + +/* ----------------------------------------------------------------------------- + * Helper functions + */ + +static struct isp_format_info formats[] = { + { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, + V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, + { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, + V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, + { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, }, + { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, + V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, }, + { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, }, + { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, }, + { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, }, + { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, + V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, }, + { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, }, + { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, }, + { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, + V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, }, + { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, + V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, }, +}; + +const struct isp_format_info * +omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (formats[i].code == code) + return &formats[i]; + } + + return NULL; +} + +/* + * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format + * @video: ISP video instance + * @mbus: v4l2_mbus_framefmt format (input) + * @pix: v4l2_pix_format format (output) + * + * Fill the output pix structure with information from the input mbus format. + * The bytesperline and sizeimage fields are computed from the requested bytes + * per line value in the pix format and information from the video instance. + * + * Return the number of padding bytes at end of line. + */ +static unsigned int isp_video_mbus_to_pix(const struct isp_video *video, + const struct v4l2_mbus_framefmt *mbus, + struct v4l2_pix_format *pix) +{ + unsigned int bpl = pix->bytesperline; + unsigned int min_bpl; + unsigned int i; + + memset(pix, 0, sizeof(*pix)); + pix->width = mbus->width; + pix->height = mbus->height; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (formats[i].code == mbus->code) + break; + } + + if (WARN_ON(i == ARRAY_SIZE(formats))) + return 0; + + min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8; + + /* Clamp the requested bytes per line value. If the maximum bytes per + * line value is zero, the module doesn't support user configurable line + * sizes. Override the requested value with the minimum in that case. + */ + if (video->bpl_max) + bpl = clamp(bpl, min_bpl, video->bpl_max); + else + bpl = min_bpl; + + if (!video->bpl_zero_padding || bpl != min_bpl) + bpl = ALIGN(bpl, video->bpl_alignment); + + pix->pixelformat = formats[i].pixelformat; + pix->bytesperline = bpl; + pix->sizeimage = pix->bytesperline * pix->height; + pix->colorspace = mbus->colorspace; + pix->field = mbus->field; + + return bpl - min_bpl; +} + +static void isp_video_pix_to_mbus(const struct v4l2_pix_format *pix, + struct v4l2_mbus_framefmt *mbus) +{ + unsigned int i; + + memset(mbus, 0, sizeof(*mbus)); + mbus->width = pix->width; + mbus->height = pix->height; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (formats[i].pixelformat == pix->pixelformat) + break; + } + + if (WARN_ON(i == ARRAY_SIZE(formats))) + return; + + mbus->code = formats[i].code; + mbus->colorspace = pix->colorspace; + mbus->field = pix->field; +} + +static struct v4l2_subdev * +isp_video_remote_subdev(struct isp_video *video, u32 *pad) +{ + struct media_pad *remote; + + remote = media_entity_remote_source(&video->pad); + + if (remote == NULL || + media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +/* Return a pointer to the ISP video instance at the far end of the pipeline. */ +static struct isp_video * +isp_video_far_end(struct isp_video *video) +{ + struct media_entity_graph graph; + struct media_entity *entity = &video->video.entity; + struct media_device *mdev = entity->parent; + struct isp_video *far_end = NULL; + + mutex_lock(&mdev->graph_mutex); + media_entity_graph_walk_start(&graph, entity); + + while ((entity = media_entity_graph_walk_next(&graph))) { + if (entity == &video->video.entity) + continue; + + if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) + continue; + + far_end = to_isp_video(media_entity_to_video_device(entity)); + if (far_end->type != video->type) + break; + + far_end = NULL; + } + + mutex_unlock(&mdev->graph_mutex); + return far_end; +} + +/* + * Validate a pipeline by checking both ends of all links for format + * discrepancies. + * + * Compute the minimum time per frame value as the maximum of time per frame + * limits reported by every block in the pipeline. + * + * Return 0 if all formats match, or -EPIPE if at least one link is found with + * different formats on its two ends. + */ +static int isp_video_validate_pipeline(struct isp_pipeline *pipe) +{ + struct isp_device *isp = pipe->output->isp; + struct v4l2_subdev_format fmt_source; + struct v4l2_subdev_format fmt_sink; + struct media_pad *pad; + struct v4l2_subdev *subdev; + int ret; + + pipe->max_rate = pipe->l3_ick; + + subdev = isp_video_remote_subdev(pipe->output, NULL); + if (subdev == NULL) + return -EPIPE; + + while (1) { + /* Retrieve the sink format */ + pad = &subdev->entity.pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + + fmt_sink.pad = pad->index; + fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + /* Update the maximum frame rate */ + if (subdev == &isp->isp_res.subdev) + omap3isp_resizer_max_rate(&isp->isp_res, + &pipe->max_rate); + + /* Check ccdc maximum data rate when data comes from sensor + * TODO: Include ccdc rate in pipe->max_rate and compare the + * total pipe rate with the input data rate from sensor. + */ + if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) { + unsigned int rate = UINT_MAX; + + omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate); + if (isp->isp_ccdc.vpcfg.pixelclk > rate) + return -ENOSPC; + } + + /* Retrieve the source format */ + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + subdev = media_entity_to_v4l2_subdev(pad->entity); + + fmt_source.pad = pad->index; + fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + /* Check if the two ends match */ + if (fmt_source.format.code != fmt_sink.format.code || + fmt_source.format.width != fmt_sink.format.width || + fmt_source.format.height != fmt_sink.format.height) + return -EPIPE; + } + + return 0; +} + +static int +__isp_video_get_format(struct isp_video *video, struct v4l2_format *format) +{ + struct v4l2_subdev_format fmt; + struct v4l2_subdev *subdev; + u32 pad; + int ret; + + subdev = isp_video_remote_subdev(video, &pad); + if (subdev == NULL) + return -EINVAL; + + mutex_lock(&video->mutex); + + fmt.pad = pad; + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret == -ENOIOCTLCMD) + ret = -EINVAL; + + mutex_unlock(&video->mutex); + + if (ret) + return ret; + + format->type = video->type; + return isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix); +} + +static int +isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh) +{ + struct v4l2_format format; + int ret; + + memcpy(&format, &vfh->format, sizeof(format)); + ret = __isp_video_get_format(video, &format); + if (ret < 0) + return ret; + + if (vfh->format.fmt.pix.pixelformat != format.fmt.pix.pixelformat || + vfh->format.fmt.pix.height != format.fmt.pix.height || + vfh->format.fmt.pix.width != format.fmt.pix.width || + vfh->format.fmt.pix.bytesperline != format.fmt.pix.bytesperline || + vfh->format.fmt.pix.sizeimage != format.fmt.pix.sizeimage) + return -EINVAL; + + return ret; +} + +/* ----------------------------------------------------------------------------- + * IOMMU management + */ + +#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8) + +/* + * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list + * @dev: Device pointer specific to the OMAP3 ISP. + * @sglist: Pointer to source Scatter gather list to allocate. + * @sglen: Number of elements of the scatter-gatter list. + * + * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if + * we ran out of memory. + */ +static dma_addr_t +ispmmu_vmap(struct isp_device *isp, const struct scatterlist *sglist, int sglen) +{ + struct sg_table *sgt; + u32 da; + + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (sgt == NULL) + return -ENOMEM; + + sgt->sgl = (struct scatterlist *)sglist; + sgt->nents = sglen; + sgt->orig_nents = sglen; + + da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG); + if (IS_ERR_VALUE(da)) + kfree(sgt); + + return da; +} + +/* + * ispmmu_vunmap - Unmap a device address from the ISP MMU + * @dev: Device pointer specific to the OMAP3 ISP. + * @da: Device address generated from a ispmmu_vmap call. + */ +static void ispmmu_vunmap(struct isp_device *isp, dma_addr_t da) +{ + struct sg_table *sgt; + + sgt = iommu_vunmap(isp->iommu, (u32)da); + kfree(sgt); +} + +/* ----------------------------------------------------------------------------- + * Video queue operations + */ + +static void isp_video_queue_prepare(struct isp_video_queue *queue, + unsigned int *nbuffers, unsigned int *size) +{ + struct isp_video_fh *vfh = + container_of(queue, struct isp_video_fh, queue); + struct isp_video *video = vfh->video; + + *size = vfh->format.fmt.pix.sizeimage; + if (*size == 0) + return; + + *nbuffers = min(*nbuffers, video->capture_mem / PAGE_ALIGN(*size)); +} + +static void isp_video_buffer_cleanup(struct isp_video_buffer *buf) +{ + struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); + struct isp_buffer *buffer = to_isp_buffer(buf); + struct isp_video *video = vfh->video; + + if (buffer->isp_addr) { + ispmmu_vunmap(video->isp, buffer->isp_addr); + buffer->isp_addr = 0; + } +} + +static int isp_video_buffer_prepare(struct isp_video_buffer *buf) +{ + struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); + struct isp_buffer *buffer = to_isp_buffer(buf); + struct isp_video *video = vfh->video; + unsigned long addr; + + addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen); + if (IS_ERR_VALUE(addr)) + return -EIO; + + if (!IS_ALIGNED(addr, 32)) { + dev_dbg(video->isp->dev, "Buffer address must be " + "aligned to 32 bytes boundary.\n"); + ispmmu_vunmap(video->isp, buffer->isp_addr); + return -EINVAL; + } + + buf->vbuf.bytesused = vfh->format.fmt.pix.sizeimage; + buffer->isp_addr = addr; + return 0; +} + +/* + * isp_video_buffer_queue - Add buffer to streaming queue + * @buf: Video buffer + * + * In memory-to-memory mode, start streaming on the pipeline if buffers are + * queued on both the input and the output, if the pipeline isn't already busy. + * If the pipeline is busy, it will be restarted in the output module interrupt + * handler. + */ +static void isp_video_buffer_queue(struct isp_video_buffer *buf) +{ + struct isp_video_fh *vfh = isp_video_queue_to_isp_video_fh(buf->queue); + struct isp_buffer *buffer = to_isp_buffer(buf); + struct isp_video *video = vfh->video; + struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); + enum isp_pipeline_state state; + unsigned long flags; + unsigned int empty; + unsigned int start; + + empty = list_empty(&video->dmaqueue); + list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue); + + if (empty) { + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + state = ISP_PIPELINE_QUEUE_OUTPUT; + else + state = ISP_PIPELINE_QUEUE_INPUT; + + spin_lock_irqsave(&pipe->lock, flags); + pipe->state |= state; + video->ops->queue(video, buffer); + video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED; + + start = isp_pipeline_ready(pipe); + if (start) + pipe->state |= ISP_PIPELINE_STREAM; + spin_unlock_irqrestore(&pipe->lock, flags); + + if (start) + omap3isp_pipeline_set_stream(pipe, + ISP_PIPELINE_STREAM_SINGLESHOT); + } +} + +static const struct isp_video_queue_operations isp_video_queue_ops = { + .queue_prepare = &isp_video_queue_prepare, + .buffer_prepare = &isp_video_buffer_prepare, + .buffer_queue = &isp_video_buffer_queue, + .buffer_cleanup = &isp_video_buffer_cleanup, +}; + +/* + * omap3isp_video_buffer_next - Complete the current buffer and return the next + * @video: ISP video object + * @error: Whether an error occured during capture + * + * Remove the current video buffer from the DMA queue and fill its timestamp, + * field count and state fields before waking up its completion handler. + * + * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0) + * or VIDEOBUF_ERROR otherwise (@error is non-zero). + * + * The DMA queue is expected to contain at least one buffer. + * + * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is + * empty. + */ +struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, + unsigned int error) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); + struct isp_video_queue *queue = video->queue; + enum isp_pipeline_state state; + struct isp_video_buffer *buf; + unsigned long flags; + struct timespec ts; + + spin_lock_irqsave(&queue->irqlock, flags); + if (WARN_ON(list_empty(&video->dmaqueue))) { + spin_unlock_irqrestore(&queue->irqlock, flags); + return NULL; + } + + buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, + irqlist); + list_del(&buf->irqlist); + spin_unlock_irqrestore(&queue->irqlock, flags); + + ktime_get_ts(&ts); + buf->vbuf.timestamp.tv_sec = ts.tv_sec; + buf->vbuf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC; + + /* Do frame number propagation only if this is the output video node. + * Frame number either comes from the CSI receivers or it gets + * incremented here if H3A is not active. + * Note: There is no guarantee that the output buffer will finish + * first, so the input number might lag behind by 1 in some cases. + */ + if (video == pipe->output && !pipe->do_propagation) + buf->vbuf.sequence = atomic_inc_return(&pipe->frame_number); + else + buf->vbuf.sequence = atomic_read(&pipe->frame_number); + + buf->state = error ? ISP_BUF_STATE_ERROR : ISP_BUF_STATE_DONE; + + wake_up(&buf->wait); + + if (list_empty(&video->dmaqueue)) { + if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + state = ISP_PIPELINE_QUEUE_OUTPUT + | ISP_PIPELINE_STREAM; + else + state = ISP_PIPELINE_QUEUE_INPUT + | ISP_PIPELINE_STREAM; + + spin_lock_irqsave(&pipe->lock, flags); + pipe->state &= ~state; + if (video->pipe.stream_state == ISP_PIPELINE_STREAM_CONTINUOUS) + video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; + spin_unlock_irqrestore(&pipe->lock, flags); + return NULL; + } + + if (queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) { + spin_lock_irqsave(&pipe->lock, flags); + pipe->state &= ~ISP_PIPELINE_STREAM; + spin_unlock_irqrestore(&pipe->lock, flags); + } + + buf = list_first_entry(&video->dmaqueue, struct isp_video_buffer, + irqlist); + buf->state = ISP_BUF_STATE_ACTIVE; + return to_isp_buffer(buf); +} + +/* + * omap3isp_video_resume - Perform resume operation on the buffers + * @video: ISP video object + * @continuous: Pipeline is in single shot mode if 0 or continous mode otherwise + * + * This function is intended to be used on suspend/resume scenario. It + * requests video queue layer to discard buffers marked as DONE if it's in + * continuous mode and requests ISP modules to queue again the ACTIVE buffer + * if there's any. + */ +void omap3isp_video_resume(struct isp_video *video, int continuous) +{ + struct isp_buffer *buf = NULL; + + if (continuous && video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + omap3isp_video_queue_discard_done(video->queue); + + if (!list_empty(&video->dmaqueue)) { + buf = list_first_entry(&video->dmaqueue, + struct isp_buffer, buffer.irqlist); + video->ops->queue(video, buf); + video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_QUEUED; + } else { + if (continuous) + video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; + } +} + +/* ----------------------------------------------------------------------------- + * V4L2 ioctls + */ + +static int +isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + struct isp_video *video = video_drvdata(file); + + strlcpy(cap->driver, ISP_VIDEO_DRIVER_NAME, sizeof(cap->driver)); + strlcpy(cap->card, video->video.name, sizeof(cap->card)); + strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); + cap->version = ISP_VIDEO_DRIVER_VERSION; + + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + else + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + + return 0; +} + +static int +isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + + if (format->type != video->type) + return -EINVAL; + + mutex_lock(&video->mutex); + *format = vfh->format; + mutex_unlock(&video->mutex); + + return 0; +} + +static int +isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + struct v4l2_mbus_framefmt fmt; + + if (format->type != video->type) + return -EINVAL; + + mutex_lock(&video->mutex); + + /* Fill the bytesperline and sizeimage fields by converting to media bus + * format and back to pixel format. + */ + isp_video_pix_to_mbus(&format->fmt.pix, &fmt); + isp_video_mbus_to_pix(video, &fmt, &format->fmt.pix); + + vfh->format = *format; + + mutex_unlock(&video->mutex); + return 0; +} + +static int +isp_video_try_format(struct file *file, void *fh, struct v4l2_format *format) +{ + struct isp_video *video = video_drvdata(file); + struct v4l2_subdev_format fmt; + struct v4l2_subdev *subdev; + u32 pad; + int ret; + + if (format->type != video->type) + return -EINVAL; + + subdev = isp_video_remote_subdev(video, &pad); + if (subdev == NULL) + return -EINVAL; + + isp_video_pix_to_mbus(&format->fmt.pix, &fmt.format); + + fmt.pad = pad; + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); + if (ret) + return ret == -ENOIOCTLCMD ? -EINVAL : ret; + + isp_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix); + return 0; +} + +static int +isp_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) +{ + struct isp_video *video = video_drvdata(file); + struct v4l2_subdev *subdev; + int ret; + + subdev = isp_video_remote_subdev(video, NULL); + if (subdev == NULL) + return -EINVAL; + + mutex_lock(&video->mutex); + ret = v4l2_subdev_call(subdev, video, cropcap, cropcap); + mutex_unlock(&video->mutex); + + return ret == -ENOIOCTLCMD ? -EINVAL : ret; +} + +static int +isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct isp_video *video = video_drvdata(file); + struct v4l2_subdev_format format; + struct v4l2_subdev *subdev; + u32 pad; + int ret; + + subdev = isp_video_remote_subdev(video, &pad); + if (subdev == NULL) + return -EINVAL; + + /* Try the get crop operation first and fallback to get format if not + * implemented. + */ + ret = v4l2_subdev_call(subdev, video, g_crop, crop); + if (ret != -ENOIOCTLCMD) + return ret; + + format.pad = pad; + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format); + if (ret < 0) + return ret == -ENOIOCTLCMD ? -EINVAL : ret; + + crop->c.left = 0; + crop->c.top = 0; + crop->c.width = format.format.width; + crop->c.height = format.format.height; + + return 0; +} + +static int +isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop) +{ + struct isp_video *video = video_drvdata(file); + struct v4l2_subdev *subdev; + int ret; + + subdev = isp_video_remote_subdev(video, NULL); + if (subdev == NULL) + return -EINVAL; + + mutex_lock(&video->mutex); + ret = v4l2_subdev_call(subdev, video, s_crop, crop); + mutex_unlock(&video->mutex); + + return ret == -ENOIOCTLCMD ? -EINVAL : ret; +} + +static int +isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + + if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + video->type != a->type) + return -EINVAL; + + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.output.timeperframe = vfh->timeperframe; + + return 0; +} + +static int +isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + + if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + video->type != a->type) + return -EINVAL; + + if (a->parm.output.timeperframe.denominator == 0) + a->parm.output.timeperframe.denominator = 1; + + vfh->timeperframe = a->parm.output.timeperframe; + + return 0; +} + +static int +isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + + return omap3isp_video_queue_reqbufs(&vfh->queue, rb); +} + +static int +isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + + return omap3isp_video_queue_querybuf(&vfh->queue, b); +} + +static int +isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + + return omap3isp_video_queue_qbuf(&vfh->queue, b); +} + +static int +isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + + return omap3isp_video_queue_dqbuf(&vfh->queue, b, + file->f_flags & O_NONBLOCK); +} + +/* + * Stream management + * + * Every ISP pipeline has a single input and a single output. The input can be + * either a sensor or a video node. The output is always a video node. + * + * As every pipeline has an output video node, the ISP video objects at the + * pipeline output stores the pipeline state. It tracks the streaming state of + * both the input and output, as well as the availability of buffers. + * + * In sensor-to-memory mode, frames are always available at the pipeline input. + * Starting the sensor usually requires I2C transfers and must be done in + * interruptible context. The pipeline is started and stopped synchronously + * to the stream on/off commands. All modules in the pipeline will get their + * subdev set stream handler called. The module at the end of the pipeline must + * delay starting the hardware until buffers are available at its output. + * + * In memory-to-memory mode, starting/stopping the stream requires + * synchronization between the input and output. ISP modules can't be stopped + * in the middle of a frame, and at least some of the modules seem to become + * busy as soon as they're started, even if they don't receive a frame start + * event. For that reason frames need to be processed in single-shot mode. The + * driver needs to wait until a frame is completely processed and written to + * memory before restarting the pipeline for the next frame. Pipelined + * processing might be possible but requires more testing. + * + * Stream start must be delayed until buffers are available at both the input + * and output. The pipeline must be started in the videobuf queue callback with + * the buffers queue spinlock held. The modules subdev set stream operation must + * not sleep. + */ +static int +isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + enum isp_pipeline_state state; + struct isp_pipeline *pipe; + struct isp_video *far_end; + unsigned long flags; + int ret; + + if (type != video->type) + return -EINVAL; + + mutex_lock(&video->stream_lock); + + if (video->streaming) { + mutex_unlock(&video->stream_lock); + return -EBUSY; + } + + /* Start streaming on the pipeline. No link touching an entity in the + * pipeline can be activated or deactivated once streaming is started. + */ + pipe = video->video.entity.pipe + ? to_isp_pipeline(&video->video.entity) : &video->pipe; + media_entity_pipeline_start(&video->video.entity, &pipe->pipe); + + /* Verify that the currently configured format matches the output of + * the connected subdev. + */ + ret = isp_video_check_format(video, vfh); + if (ret < 0) + goto error; + + video->bpl_padding = ret; + video->bpl_value = vfh->format.fmt.pix.bytesperline; + + /* Find the ISP video node connected at the far end of the pipeline and + * update the pipeline. + */ + far_end = isp_video_far_end(video); + + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT; + pipe->input = far_end; + pipe->output = video; + } else { + if (far_end == NULL) { + ret = -EPIPE; + goto error; + } + + state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT; + pipe->input = video; + pipe->output = far_end; + } + + /* Make sure the interconnect clock runs fast enough. + * + * Formula from: resource34xx.c set_opp() + * If MPU freq is above 500MHz, make sure the interconnect + * is at 100Mhz or above. + * throughput in KiB/s for 100 Mhz = 100 * 1000 * 4. + * + * We want to be fast enough then set OCP clock to be max as + * possible, in that case 185Mhz then: + * throughput in KiB/s for 185Mhz = 185 * 1000 * 4 = 740000 KiB/s + */ + omap_pm_set_min_bus_tput(video->isp->dev, OCP_INITIATOR_AGENT, 740000); + pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); + + /* Validate the pipeline and update its state. */ + ret = isp_video_validate_pipeline(pipe); + if (ret < 0) + goto error; + + spin_lock_irqsave(&pipe->lock, flags); + pipe->state &= ~ISP_PIPELINE_STREAM; + pipe->state |= state; + spin_unlock_irqrestore(&pipe->lock, flags); + + /* Set the maximum time per frame as the value requested by userspace. + * This is a soft limit that can be overridden if the hardware doesn't + * support the request limit. + */ + if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + pipe->max_timeperframe = vfh->timeperframe; + + video->queue = &vfh->queue; + INIT_LIST_HEAD(&video->dmaqueue); + atomic_set(&pipe->frame_number, -1); + + ret = omap3isp_video_queue_streamon(&vfh->queue); + if (ret < 0) + goto error; + + /* In sensor-to-memory mode, the stream can be started synchronously + * to the stream on command. In memory-to-memory mode, it will be + * started when buffers are queued on both the input and output. + */ + if (pipe->input == NULL) { + ret = omap3isp_pipeline_set_stream(pipe, + ISP_PIPELINE_STREAM_CONTINUOUS); + if (ret < 0) + goto error; + spin_lock_irqsave(&video->queue->irqlock, flags); + if (list_empty(&video->dmaqueue)) + video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN; + spin_unlock_irqrestore(&video->queue->irqlock, flags); + } + +error: + if (ret < 0) { + omap3isp_video_queue_streamoff(&vfh->queue); + omap_pm_set_min_bus_tput(video->isp->dev, + OCP_INITIATOR_AGENT, 0); + media_entity_pipeline_stop(&video->video.entity); + video->queue = NULL; + } + + if (!ret) + video->streaming = 1; + + mutex_unlock(&video->stream_lock); + return ret; +} + +static int +isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video *video = video_drvdata(file); + struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); + enum isp_pipeline_state state; + unsigned int streaming; + unsigned long flags; + + if (type != video->type) + return -EINVAL; + + mutex_lock(&video->stream_lock); + + /* Make sure we're not streaming yet. */ + mutex_lock(&vfh->queue.lock); + streaming = vfh->queue.streaming; + mutex_unlock(&vfh->queue.lock); + + if (!streaming) + goto done; + + /* Update the pipeline state. */ + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + state = ISP_PIPELINE_STREAM_OUTPUT + | ISP_PIPELINE_QUEUE_OUTPUT; + else + state = ISP_PIPELINE_STREAM_INPUT + | ISP_PIPELINE_QUEUE_INPUT; + + spin_lock_irqsave(&pipe->lock, flags); + pipe->state &= ~state; + spin_unlock_irqrestore(&pipe->lock, flags); + + /* Stop the stream. */ + omap3isp_pipeline_set_stream(pipe, ISP_PIPELINE_STREAM_STOPPED); + omap3isp_video_queue_streamoff(&vfh->queue); + video->queue = NULL; + video->streaming = 0; + + omap_pm_set_min_bus_tput(video->isp->dev, OCP_INITIATOR_AGENT, 0); + media_entity_pipeline_stop(&video->video.entity); + +done: + mutex_unlock(&video->stream_lock); + return 0; +} + +static int +isp_video_enum_input(struct file *file, void *fh, struct v4l2_input *input) +{ + if (input->index > 0) + return -EINVAL; + + strlcpy(input->name, "camera", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +static int +isp_video_g_input(struct file *file, void *fh, unsigned int *input) +{ + *input = 0; + + return 0; +} + +static int +isp_video_s_input(struct file *file, void *fh, unsigned int input) +{ + return input == 0 ? 0 : -EINVAL; +} + +static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { + .vidioc_querycap = isp_video_querycap, + .vidioc_g_fmt_vid_cap = isp_video_get_format, + .vidioc_s_fmt_vid_cap = isp_video_set_format, + .vidioc_try_fmt_vid_cap = isp_video_try_format, + .vidioc_g_fmt_vid_out = isp_video_get_format, + .vidioc_s_fmt_vid_out = isp_video_set_format, + .vidioc_try_fmt_vid_out = isp_video_try_format, + .vidioc_cropcap = isp_video_cropcap, + .vidioc_g_crop = isp_video_get_crop, + .vidioc_s_crop = isp_video_set_crop, + .vidioc_g_parm = isp_video_get_param, + .vidioc_s_parm = isp_video_set_param, + .vidioc_reqbufs = isp_video_reqbufs, + .vidioc_querybuf = isp_video_querybuf, + .vidioc_qbuf = isp_video_qbuf, + .vidioc_dqbuf = isp_video_dqbuf, + .vidioc_streamon = isp_video_streamon, + .vidioc_streamoff = isp_video_streamoff, + .vidioc_enum_input = isp_video_enum_input, + .vidioc_g_input = isp_video_g_input, + .vidioc_s_input = isp_video_s_input, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 file operations + */ + +static int isp_video_open(struct file *file) +{ + struct isp_video *video = video_drvdata(file); + struct isp_video_fh *handle; + int ret = 0; + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (handle == NULL) + return -ENOMEM; + + v4l2_fh_init(&handle->vfh, &video->video); + v4l2_fh_add(&handle->vfh); + + /* If this is the first user, initialise the pipeline. */ + if (omap3isp_get(video->isp) == NULL) { + ret = -EBUSY; + goto done; + } + + ret = omap3isp_pipeline_pm_use(&video->video.entity, 1); + if (ret < 0) { + omap3isp_put(video->isp); + goto done; + } + + omap3isp_video_queue_init(&handle->queue, video->type, + &isp_video_queue_ops, video->isp->dev, + sizeof(struct isp_buffer)); + + memset(&handle->format, 0, sizeof(handle->format)); + handle->format.type = video->type; + handle->timeperframe.denominator = 1; + + handle->video = video; + file->private_data = &handle->vfh; + +done: + if (ret < 0) { + v4l2_fh_del(&handle->vfh); + kfree(handle); + } + + return ret; +} + +static int isp_video_release(struct file *file) +{ + struct isp_video *video = video_drvdata(file); + struct v4l2_fh *vfh = file->private_data; + struct isp_video_fh *handle = to_isp_video_fh(vfh); + + /* Disable streaming and free the buffers queue resources. */ + isp_video_streamoff(file, vfh, video->type); + + mutex_lock(&handle->queue.lock); + omap3isp_video_queue_cleanup(&handle->queue); + mutex_unlock(&handle->queue.lock); + + omap3isp_pipeline_pm_use(&video->video.entity, 0); + + /* Release the file handle. */ + v4l2_fh_del(vfh); + kfree(handle); + file->private_data = NULL; + + omap3isp_put(video->isp); + + return 0; +} + +static unsigned int isp_video_poll(struct file *file, poll_table *wait) +{ + struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); + struct isp_video_queue *queue = &vfh->queue; + + return omap3isp_video_queue_poll(queue, file, wait); +} + +static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); + + return omap3isp_video_queue_mmap(&vfh->queue, vma); +} + +static struct v4l2_file_operations isp_video_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = isp_video_open, + .release = isp_video_release, + .poll = isp_video_poll, + .mmap = isp_video_mmap, +}; + +/* ----------------------------------------------------------------------------- + * ISP video core + */ + +static const struct isp_video_operations isp_video_dummy_ops = { +}; + +int omap3isp_video_init(struct isp_video *video, const char *name) +{ + const char *direction; + int ret; + + switch (video->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + direction = "output"; + video->pad.flags = MEDIA_PAD_FL_SINK; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + direction = "input"; + video->pad.flags = MEDIA_PAD_FL_SOURCE; + break; + + default: + return -EINVAL; + } + + ret = media_entity_init(&video->video.entity, 1, &video->pad, 0); + if (ret < 0) + return ret; + + mutex_init(&video->mutex); + atomic_set(&video->active, 0); + + spin_lock_init(&video->pipe.lock); + mutex_init(&video->stream_lock); + + /* Initialize the video device. */ + if (video->ops == NULL) + video->ops = &isp_video_dummy_ops; + + video->video.fops = &isp_video_fops; + snprintf(video->video.name, sizeof(video->video.name), + "OMAP3 ISP %s %s", name, direction); + video->video.vfl_type = VFL_TYPE_GRABBER; + video->video.release = video_device_release_empty; + video->video.ioctl_ops = &isp_video_ioctl_ops; + video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED; + + video_set_drvdata(&video->video, video); + + return 0; +} + +int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) +{ + int ret; + + video->video.v4l2_dev = vdev; + + ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1); + if (ret < 0) + printk(KERN_ERR "%s: could not register video device (%d)\n", + __func__, ret); + + return ret; +} + +void omap3isp_video_unregister(struct isp_video *video) +{ + if (video_is_registered(&video->video)) { + media_entity_cleanup(&video->video.entity); + video_unregister_device(&video->video); + } +} diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h new file mode 100644 index 000000000000..524a1acd0906 --- /dev/null +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -0,0 +1,202 @@ +/* + * ispvideo.h + * + * TI OMAP3 ISP - Generic video node + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_VIDEO_H +#define OMAP3_ISP_VIDEO_H + +#include +#include +#include +#include +#include + +#include "ispqueue.h" + +#define ISP_VIDEO_DRIVER_NAME "ispvideo" +#define ISP_VIDEO_DRIVER_VERSION KERNEL_VERSION(0, 0, 1) + +struct isp_device; +struct isp_video; +struct v4l2_mbus_framefmt; +struct v4l2_pix_format; + +/* + * struct isp_format_info - ISP media bus format information + * @code: V4L2 media bus format code + * @truncated: V4L2 media bus format code for the same format truncated to 10 + * bits. Identical to @code if the format is 10 bits wide or less. + * @uncompressed: V4L2 media bus format code for the corresponding uncompressed + * format. Identical to @code if the format is not DPCM compressed. + * @pixelformat: V4L2 pixel format FCC identifier + * @bpp: Bits per pixel + */ +struct isp_format_info { + enum v4l2_mbus_pixelcode code; + enum v4l2_mbus_pixelcode truncated; + enum v4l2_mbus_pixelcode uncompressed; + u32 pixelformat; + unsigned int bpp; +}; + +enum isp_pipeline_stream_state { + ISP_PIPELINE_STREAM_STOPPED = 0, + ISP_PIPELINE_STREAM_CONTINUOUS = 1, + ISP_PIPELINE_STREAM_SINGLESHOT = 2, +}; + +enum isp_pipeline_state { + /* The stream has been started on the input video node. */ + ISP_PIPELINE_STREAM_INPUT = 1, + /* The stream has been started on the output video node. */ + ISP_PIPELINE_STREAM_OUTPUT = 2, + /* At least one buffer is queued on the input video node. */ + ISP_PIPELINE_QUEUE_INPUT = 4, + /* At least one buffer is queued on the output video node. */ + ISP_PIPELINE_QUEUE_OUTPUT = 8, + /* The input entity is idle, ready to be started. */ + ISP_PIPELINE_IDLE_INPUT = 16, + /* The output entity is idle, ready to be started. */ + ISP_PIPELINE_IDLE_OUTPUT = 32, + /* The pipeline is currently streaming. */ + ISP_PIPELINE_STREAM = 64, +}; + +struct isp_pipeline { + struct media_pipeline pipe; + spinlock_t lock; /* Pipeline state and queue flags */ + unsigned int state; + enum isp_pipeline_stream_state stream_state; + struct isp_video *input; + struct isp_video *output; + unsigned long l3_ick; + unsigned int max_rate; + atomic_t frame_number; + bool do_propagation; /* of frame number */ + struct v4l2_fract max_timeperframe; +}; + +#define to_isp_pipeline(__e) \ + container_of((__e)->pipe, struct isp_pipeline, pipe) + +static inline int isp_pipeline_ready(struct isp_pipeline *pipe) +{ + return pipe->state == (ISP_PIPELINE_STREAM_INPUT | + ISP_PIPELINE_STREAM_OUTPUT | + ISP_PIPELINE_QUEUE_INPUT | + ISP_PIPELINE_QUEUE_OUTPUT | + ISP_PIPELINE_IDLE_INPUT | + ISP_PIPELINE_IDLE_OUTPUT); +} + +/* + * struct isp_buffer - ISP buffer + * @buffer: ISP video buffer + * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer. + */ +struct isp_buffer { + struct isp_video_buffer buffer; + dma_addr_t isp_addr; +}; + +#define to_isp_buffer(buf) container_of(buf, struct isp_buffer, buffer) + +enum isp_video_dmaqueue_flags { + /* Set if DMA queue becomes empty when ISP_PIPELINE_STREAM_CONTINUOUS */ + ISP_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0), + /* Set when queuing buffer to an empty DMA queue */ + ISP_VIDEO_DMAQUEUE_QUEUED = (1 << 1), +}; + +#define isp_video_dmaqueue_flags_clr(video) \ + ({ (video)->dmaqueue_flags = 0; }) + +/* + * struct isp_video_operations - ISP video operations + * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF + * if there was no buffer previously queued. + */ +struct isp_video_operations { + int(*queue)(struct isp_video *video, struct isp_buffer *buffer); +}; + +struct isp_video { + struct video_device video; + enum v4l2_buf_type type; + struct media_pad pad; + + struct mutex mutex; /* format and crop settings */ + atomic_t active; + + struct isp_device *isp; + + unsigned int capture_mem; + unsigned int bpl_alignment; /* alignment value */ + unsigned int bpl_zero_padding; /* whether the alignment is optional */ + unsigned int bpl_max; /* maximum bytes per line value */ + unsigned int bpl_value; /* bytes per line value */ + unsigned int bpl_padding; /* padding at end of line */ + + /* Entity video node streaming */ + unsigned int streaming:1; + + /* Pipeline state */ + struct isp_pipeline pipe; + struct mutex stream_lock; /* pipeline and stream states */ + + /* Video buffers queue */ + struct isp_video_queue *queue; + struct list_head dmaqueue; + enum isp_video_dmaqueue_flags dmaqueue_flags; + + const struct isp_video_operations *ops; +}; + +#define to_isp_video(vdev) container_of(vdev, struct isp_video, video) + +struct isp_video_fh { + struct v4l2_fh vfh; + struct isp_video *video; + struct isp_video_queue queue; + struct v4l2_format format; + struct v4l2_fract timeperframe; +}; + +#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh) +#define isp_video_queue_to_isp_video_fh(q) \ + container_of(q, struct isp_video_fh, queue) + +int omap3isp_video_init(struct isp_video *video, const char *name); +int omap3isp_video_register(struct isp_video *video, + struct v4l2_device *vdev); +void omap3isp_video_unregister(struct isp_video *video); +struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, + unsigned int error); +void omap3isp_video_resume(struct isp_video *video, int continuous); +struct media_pad *omap3isp_video_remote_pad(struct isp_video *video); + +const struct isp_format_info * +omap3isp_video_format_info(enum v4l2_mbus_pixelcode code); + +#endif /* OMAP3_ISP_VIDEO_H */ -- cgit v1.2.2 From 121e9f1c4c49c76aac2425e3a9baef70f73f50a4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 12 Feb 2011 18:05:06 -0300 Subject: [media] omap3isp: CCP2/CSI2 receivers The OMAP3 ISP CCP2 and CSI2 receivers provide an interface to connect serial MIPI sensors to the device. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: David Cohen Signed-off-by: Stanimir Varbanov Signed-off-by: Vimarsh Zutshi Signed-off-by: Tuukka Toivonen Signed-off-by: Sergio Aguirre Signed-off-by: Antti Koskipaa Signed-off-by: Ivan T. Ivanov Signed-off-by: RaniSuneela Signed-off-by: Atanas Filipov Signed-off-by: Gjorgji Rosikopulos Signed-off-by: Hiroshi DOYU Signed-off-by: Nayden Kanchev Signed-off-by: Phil Carmody Signed-off-by: Artem Bityutskiy Signed-off-by: Dominic Curran Signed-off-by: Ilkka Myllyperkio Signed-off-by: Pallavi Kulkarni Signed-off-by: Vaibhav Hiremath Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccp2.c | 1173 ++++++++++++++++++++++++++ drivers/media/video/omap3isp/ispccp2.h | 98 +++ drivers/media/video/omap3isp/ispcsi2.c | 1317 ++++++++++++++++++++++++++++++ drivers/media/video/omap3isp/ispcsi2.h | 166 ++++ drivers/media/video/omap3isp/ispcsiphy.c | 247 ++++++ drivers/media/video/omap3isp/ispcsiphy.h | 74 ++ 6 files changed, 3075 insertions(+) create mode 100644 drivers/media/video/omap3isp/ispccp2.c create mode 100644 drivers/media/video/omap3isp/ispccp2.h create mode 100644 drivers/media/video/omap3isp/ispcsi2.c create mode 100644 drivers/media/video/omap3isp/ispcsi2.h create mode 100644 drivers/media/video/omap3isp/ispcsiphy.c create mode 100644 drivers/media/video/omap3isp/ispcsiphy.h (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c new file mode 100644 index 000000000000..0efef2e78d93 --- /dev/null +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -0,0 +1,1173 @@ +/* + * ispccp2.c + * + * TI OMAP3 ISP - CCP2 module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "ispccp2.h" + +/* Number of LCX channels */ +#define CCP2_LCx_CHANS_NUM 3 +/* Max/Min size for CCP2 video port */ +#define ISPCCP2_DAT_START_MIN 0 +#define ISPCCP2_DAT_START_MAX 4095 +#define ISPCCP2_DAT_SIZE_MIN 0 +#define ISPCCP2_DAT_SIZE_MAX 4095 +#define ISPCCP2_VPCLK_FRACDIV 65536 +#define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP 0x12 +#define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP 0x16 +/* Max/Min size for CCP2 memory channel */ +#define ISPCCP2_LCM_HSIZE_COUNT_MIN 16 +#define ISPCCP2_LCM_HSIZE_COUNT_MAX 8191 +#define ISPCCP2_LCM_HSIZE_SKIP_MIN 0 +#define ISPCCP2_LCM_HSIZE_SKIP_MAX 8191 +#define ISPCCP2_LCM_VSIZE_MIN 1 +#define ISPCCP2_LCM_VSIZE_MAX 8191 +#define ISPCCP2_LCM_HWORDS_MIN 1 +#define ISPCCP2_LCM_HWORDS_MAX 4095 +#define ISPCCP2_LCM_CTRL_BURST_SIZE_32X 5 +#define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL 0 +#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 2 +#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 2 +#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 3 +#define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 3 +#define ISPCCP2_LCM_CTRL_DST_PORT_VP 0 +#define ISPCCP2_LCM_CTRL_DST_PORT_MEM 1 + +/* Set only the required bits */ +#define BIT_SET(var, shift, mask, val) \ + do { \ + var = ((var) & ~((mask) << (shift))) \ + | ((val) << (shift)); \ + } while (0) + +/* + * ccp2_print_status - Print current CCP2 module register values. + */ +#define CCP2_PRINT_REGISTER(isp, name)\ + dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \ + isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name)) + +static void ccp2_print_status(struct isp_ccp2_device *ccp2) +{ + struct isp_device *isp = to_isp_device(ccp2); + + dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n"); + + CCP2_PRINT_REGISTER(isp, SYSCONFIG); + CCP2_PRINT_REGISTER(isp, SYSSTATUS); + CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE); + CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS); + CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE); + CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS); + CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE); + CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS); + CCP2_PRINT_REGISTER(isp, CTRL); + CCP2_PRINT_REGISTER(isp, LCx_CTRL(0)); + CCP2_PRINT_REGISTER(isp, LCx_CODE(0)); + CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0)); + CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0)); + CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0)); + CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0)); + CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0)); + CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0)); + CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0)); + CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0)); + CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0)); + CCP2_PRINT_REGISTER(isp, LCM_CTRL); + CCP2_PRINT_REGISTER(isp, LCM_VSIZE); + CCP2_PRINT_REGISTER(isp, LCM_HSIZE); + CCP2_PRINT_REGISTER(isp, LCM_PREFETCH); + CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR); + CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST); + CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR); + CCP2_PRINT_REGISTER(isp, LCM_DST_OFST); + + dev_dbg(isp->dev, "--------------------------------------------\n"); +} + +/* + * ccp2_reset - Reset the CCP2 + * @ccp2: pointer to ISP CCP2 device + */ +static void ccp2_reset(struct isp_ccp2_device *ccp2) +{ + struct isp_device *isp = to_isp_device(ccp2); + int i = 0; + + /* Reset the CSI1/CCP2B and wait for reset to complete */ + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG, + ISPCCP2_SYSCONFIG_SOFT_RESET); + while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) & + ISPCCP2_SYSSTATUS_RESET_DONE)) { + udelay(10); + if (i++ > 10) { /* try read 10 times */ + dev_warn(isp->dev, + "omap3_isp: timeout waiting for ccp2 reset\n"); + break; + } + } +} + +/* + * ccp2_pwr_cfg - Configure the power mode settings + * @ccp2: pointer to ISP CCP2 device + */ +static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2) +{ + struct isp_device *isp = to_isp_device(ccp2); + + isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART | + ((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ? + ISPCCP2_SYSCONFIG_AUTO_IDLE : 0), + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG); +} + +/* + * ccp2_if_enable - Enable CCP2 interface. + * @ccp2: pointer to ISP CCP2 device + * @enable: enable/disable flag + */ +static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) +{ + struct isp_device *isp = to_isp_device(ccp2); + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); + int i; + + /* Enable/Disable all the LCx channels */ + for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), + ISPCCP2_LCx_CTRL_CHAN_EN, + enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); + + /* Enable/Disable ccp2 interface in ccp2 mode */ + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, + ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, + enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); + + /* For frame count propagation */ + if (pipe->do_propagation) { + /* We may want the Frame Start IRQ from LC0 */ + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, + ISPCCP2_LC01_IRQENABLE, + ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, + ISPCCP2_LC01_IRQENABLE, + ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); + } +} + +/* + * ccp2_mem_enable - Enable CCP2 memory interface. + * @ccp2: pointer to ISP CCP2 device + * @enable: enable/disable flag + */ +static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) +{ + struct isp_device *isp = to_isp_device(ccp2); + + if (enable) + ccp2_if_enable(ccp2, 0); + + /* Enable/Disable ccp2 interface in ccp2 mode */ + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, + ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0); + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL, + ISPCCP2_LCM_CTRL_CHAN_EN, + enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0); +} + +/* + * ccp2_phyif_config - Initialize CCP2 phy interface config + * @ccp2: Pointer to ISP CCP2 device + * @config: CCP2 platform data + * + * Configure the CCP2 physical interface module from platform data. + * + * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. + */ +static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, + const struct isp_ccp2_platform_data *pdata) +{ + struct isp_device *isp = to_isp_device(ccp2); + u32 val; + + /* CCP2B mode */ + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) | + ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; + /* Data/strobe physical layer */ + BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, + pdata->phy_layer); + BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, + pdata->strobe_clk_pol); + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); + + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); + if (!(val & ISPCCP2_CTRL_MODE)) { + if (pdata->ccp2_mode) + dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); + if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE) + /* Strobe mode requires CCP2 */ + return -EIO; + } + + return 0; +} + +/* + * ccp2_vp_config - Initialize CCP2 video port interface. + * @ccp2: Pointer to ISP CCP2 device + * @vpclk_div: Video port divisor + * + * Configure the CCP2 video port with the given clock divisor. The valid divisor + * values depend on the ISP revision: + * + * - revision 1.0 and 2.0 1 to 4 + * - revision 15.0 1 to 65536 + * + * The exact divisor value used might differ from the requested value, as ISP + * revision 15.0 represent the divisor by 65536 divided by an integer. + */ +static void ccp2_vp_config(struct isp_ccp2_device *ccp2, + unsigned int vpclk_div) +{ + struct isp_device *isp = to_isp_device(ccp2); + u32 val; + + /* ISPCCP2_CTRL Video port */ + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); + val |= ISPCCP2_CTRL_VP_ONLY_EN; /* Disable the memory write port */ + + if (isp->revision == ISP_REVISION_15_0) { + vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 65536); + vpclk_div = min(ISPCCP2_VPCLK_FRACDIV / vpclk_div, 65535U); + BIT_SET(val, ISPCCP2_CTRL_VPCLK_DIV_SHIFT, + ISPCCP2_CTRL_VPCLK_DIV_MASK, vpclk_div); + } else { + vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 4); + BIT_SET(val, ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT, + ISPCCP2_CTRL_VP_OUT_CTRL_MASK, vpclk_div - 1); + } + + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); +} + +/* + * ccp2_lcx_config - Initialize CCP2 logical channel interface. + * @ccp2: Pointer to ISP CCP2 device + * @config: Pointer to ISP LCx config structure. + * + * This will analyze the parameters passed by the interface config + * and configure CSI1/CCP2 logical channel + * + */ +static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, + struct isp_interface_lcx_config *config) +{ + struct isp_device *isp = to_isp_device(ccp2); + u32 val, format; + + switch (config->format) { + case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: + format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP; + break; + case V4L2_MBUS_FMT_SGRBG10_1X10: + default: + format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP; /* RAW10+VP */ + break; + } + /* ISPCCP2_LCx_CTRL logical channel #0 */ + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)) + | (ISPCCP2_LCx_CTRL_REGION_EN); /* Region */ + + if (isp->revision == ISP_REVISION_15_0) { + /* CRC */ + BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0, + ISPCCP2_LCx_CTRL_CRC_MASK, + config->crc); + /* Format = RAW10+VP or RAW8+DPCM10+VP*/ + BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0, + ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0, format); + } else { + BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT, + ISPCCP2_LCx_CTRL_CRC_MASK, + config->crc); + + BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT, + ISPCCP2_LCx_CTRL_FORMAT_MASK, format); + } + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)); + + /* ISPCCP2_DAT_START for logical channel #0 */ + isp_reg_writel(isp, config->data_start << ISPCCP2_LCx_DAT_SHIFT, + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_START(0)); + + /* ISPCCP2_DAT_SIZE for logical channel #0 */ + isp_reg_writel(isp, config->data_size << ISPCCP2_LCx_DAT_SHIFT, + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_SIZE(0)); + + /* Enable error IRQs for logical channel #0 */ + val = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; + + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQSTATUS); + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, val); +} + +/* + * ccp2_if_configure - Configure ccp2 with data from sensor + * @ccp2: Pointer to ISP CCP2 device + * + * Return 0 on success or a negative error code + */ +static int ccp2_if_configure(struct isp_ccp2_device *ccp2) +{ + const struct isp_v4l2_subdevs_group *pdata; + struct v4l2_mbus_framefmt *format; + struct media_pad *pad; + struct v4l2_subdev *sensor; + u32 lines = 0; + int ret; + + ccp2_pwr_cfg(ccp2); + + pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]); + sensor = media_entity_to_v4l2_subdev(pad->entity); + pdata = sensor->host_priv; + + ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2); + if (ret < 0) + return ret; + + ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1); + + v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); + + format = &ccp2->formats[CCP2_PAD_SINK]; + + ccp2->if_cfg.data_start = lines; + ccp2->if_cfg.crc = pdata->bus.ccp2.crc; + ccp2->if_cfg.format = format->code; + ccp2->if_cfg.data_size = format->height; + + ccp2_lcx_config(ccp2, &ccp2->if_cfg); + + return 0; +} + +static int ccp2_adjust_bandwidth(struct isp_ccp2_device *ccp2) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); + struct isp_device *isp = to_isp_device(ccp2); + const struct v4l2_mbus_framefmt *ofmt = &ccp2->formats[CCP2_PAD_SOURCE]; + unsigned long l3_ick = pipe->l3_ick; + struct v4l2_fract *timeperframe; + unsigned int vpclk_div = 2; + unsigned int value; + u64 bound; + u64 area; + + /* Compute the minimum clock divisor, based on the pipeline maximum + * data rate. This is an absolute lower bound if we don't want SBL + * overflows, so round the value up. + */ + vpclk_div = max_t(unsigned int, DIV_ROUND_UP(l3_ick, pipe->max_rate), + vpclk_div); + + /* Compute the maximum clock divisor, based on the requested frame rate. + * This is a soft lower bound to achieve a frame rate equal or higher + * than the requested value, so round the value down. + */ + timeperframe = &pipe->max_timeperframe; + + if (timeperframe->numerator) { + area = ofmt->width * ofmt->height; + bound = div_u64(area * timeperframe->denominator, + timeperframe->numerator); + value = min_t(u64, bound, l3_ick); + vpclk_div = max_t(unsigned int, l3_ick / value, vpclk_div); + } + + dev_dbg(isp->dev, "%s: minimum clock divisor = %u\n", __func__, + vpclk_div); + + return vpclk_div; +} + +/* + * ccp2_mem_configure - Initialize CCP2 memory input/output interface + * @ccp2: Pointer to ISP CCP2 device + * @config: Pointer to ISP mem interface config structure + * + * This will analyze the parameters passed by the interface config + * structure, and configure the respective registers for proper + * CSI1/CCP2 memory input. + */ +static void ccp2_mem_configure(struct isp_ccp2_device *ccp2, + struct isp_interface_mem_config *config) +{ + struct isp_device *isp = to_isp_device(ccp2); + u32 sink_pixcode = ccp2->formats[CCP2_PAD_SINK].code; + u32 source_pixcode = ccp2->formats[CCP2_PAD_SOURCE].code; + unsigned int dpcm_decompress = 0; + u32 val, hwords; + + if (sink_pixcode != source_pixcode && + sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) + dpcm_decompress = 1; + + ccp2_pwr_cfg(ccp2); + + /* Hsize, Skip */ + isp_reg_writel(isp, ISPCCP2_LCM_HSIZE_SKIP_MIN | + (config->hsize_count << ISPCCP2_LCM_HSIZE_SHIFT), + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_HSIZE); + + /* Vsize, no. of lines */ + isp_reg_writel(isp, config->vsize_count << ISPCCP2_LCM_VSIZE_SHIFT, + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_VSIZE); + + if (ccp2->video_in.bpl_padding == 0) + config->src_ofst = 0; + else + config->src_ofst = ccp2->video_in.bpl_value; + + isp_reg_writel(isp, config->src_ofst, OMAP3_ISP_IOMEM_CCP2, + ISPCCP2_LCM_SRC_OFST); + + /* Source and Destination formats */ + val = ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 << + ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT; + + if (dpcm_decompress) { + /* source format is RAW8 */ + val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 << + ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; + + /* RAW8 + DPCM10 - simple predictor */ + val |= ISPCCP2_LCM_CTRL_SRC_DPCM_PRED; + + /* enable source DPCM decompression */ + val |= ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 << + ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT; + } else { + /* source format is RAW10 */ + val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 << + ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; + } + + /* Burst size to 32x64 */ + val |= ISPCCP2_LCM_CTRL_BURST_SIZE_32X << + ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT; + + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL); + + /* Prefetch setup */ + if (dpcm_decompress) + hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + + config->hsize_count) >> 3; + else + hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + + config->hsize_count) >> 2; + + isp_reg_writel(isp, hwords << ISPCCP2_LCM_PREFETCH_SHIFT, + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_PREFETCH); + + /* Video port */ + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, + ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE); + ccp2_vp_config(ccp2, ccp2_adjust_bandwidth(ccp2)); + + /* Clear LCM interrupts */ + isp_reg_writel(isp, ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ | + ISPCCP2_LCM_IRQSTATUS_EOF_IRQ, + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS); + + /* Enable LCM interupts */ + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE, + ISPCCP2_LCM_IRQSTATUS_EOF_IRQ | + ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ); +} + +/* + * ccp2_set_inaddr - Sets memory address of input frame. + * @ccp2: Pointer to ISP CCP2 device + * @addr: 32bit memory address aligned on 32byte boundary. + * + * Configures the memory address from which the input frame is to be read. + */ +static void ccp2_set_inaddr(struct isp_ccp2_device *ccp2, u32 addr) +{ + struct isp_device *isp = to_isp_device(ccp2); + + isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_SRC_ADDR); +} + +/* ----------------------------------------------------------------------------- + * Interrupt handling + */ + +static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); + struct isp_buffer *buffer; + + buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error); + if (buffer != NULL) + ccp2_set_inaddr(ccp2, buffer->isp_addr); + + pipe->state |= ISP_PIPELINE_IDLE_INPUT; + + if (ccp2->state == ISP_PIPELINE_STREAM_SINGLESHOT) { + if (isp_pipeline_ready(pipe)) + omap3isp_pipeline_set_stream(pipe, + ISP_PIPELINE_STREAM_SINGLESHOT); + } + + ccp2->error = 0; +} + +/* + * omap3isp_ccp2_isr - Handle ISP CCP2 interrupts + * @ccp2: Pointer to ISP CCP2 device + * + * This will handle the CCP2 interrupts + * + * Returns -EIO in case of error, or 0 on success. + */ +int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) +{ + struct isp_device *isp = to_isp_device(ccp2); + int ret = 0; + static const u32 ISPCCP2_LC01_ERROR = + ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | + ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; + u32 lcx_irqstatus, lcm_irqstatus; + + /* First clear the interrupts */ + lcx_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, + ISPCCP2_LC01_IRQSTATUS); + isp_reg_writel(isp, lcx_irqstatus, OMAP3_ISP_IOMEM_CCP2, + ISPCCP2_LC01_IRQSTATUS); + + lcm_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, + ISPCCP2_LCM_IRQSTATUS); + isp_reg_writel(isp, lcm_irqstatus, OMAP3_ISP_IOMEM_CCP2, + ISPCCP2_LCM_IRQSTATUS); + /* Errors */ + if (lcx_irqstatus & ISPCCP2_LC01_ERROR) { + ccp2->error = 1; + dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus); + return -EIO; + } + + if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) { + ccp2->error = 1; + dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus); + ret = -EIO; + } + + if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping)) + return 0; + + /* Frame number propagation */ + if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) { + struct isp_pipeline *pipe = + to_isp_pipeline(&ccp2->subdev.entity); + if (pipe->do_propagation) + atomic_inc(&pipe->frame_number); + } + + /* Handle queued buffers on frame end interrupts */ + if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ) + ccp2_isr_buffer(ccp2); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +static const unsigned int ccp2_fmts[] = { + V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, +}; + +/* + * __ccp2_get_format - helper function for getting ccp2 format + * @ccp2 : Pointer to ISP CCP2 device + * @fh : V4L2 subdev file handle + * @pad : pad number + * @which : wanted subdev format + * return format structure or NULL on error + */ +static struct v4l2_mbus_framefmt * +__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(fh, pad); + else + return &ccp2->formats[pad]; +} + +/* + * ccp2_try_format - Handle try format by pad subdev method + * @ccp2 : Pointer to ISP CCP2 device + * @fh : V4L2 subdev file handle + * @pad : pad num + * @fmt : pointer to v4l2 mbus format structure + * @which : wanted subdev format + */ +static void ccp2_try_format(struct isp_ccp2_device *ccp2, + struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + + switch (pad) { + case CCP2_PAD_SINK: + if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + + if (ccp2->input == CCP2_INPUT_SENSOR) { + fmt->width = clamp_t(u32, fmt->width, + ISPCCP2_DAT_START_MIN, + ISPCCP2_DAT_START_MAX); + fmt->height = clamp_t(u32, fmt->height, + ISPCCP2_DAT_SIZE_MIN, + ISPCCP2_DAT_SIZE_MAX); + } else if (ccp2->input == CCP2_INPUT_MEMORY) { + fmt->width = clamp_t(u32, fmt->width, + ISPCCP2_LCM_HSIZE_COUNT_MIN, + ISPCCP2_LCM_HSIZE_COUNT_MAX); + fmt->height = clamp_t(u32, fmt->height, + ISPCCP2_LCM_VSIZE_MIN, + ISPCCP2_LCM_VSIZE_MAX); + } + break; + + case CCP2_PAD_SOURCE: + /* Source format - copy sink format and change pixel code + * to SGRBG10_1X10 as we don't support CCP2 write to memory. + * When CCP2 write to memory feature will be added this + * should be changed properly. + */ + format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + break; + } + + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; +} + +/* + * ccp2_enum_mbus_code - Handle pixel format enumeration + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @code : pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + if (code->pad == CCP2_PAD_SINK) { + if (code->index >= ARRAY_SIZE(ccp2_fmts)) + return -EINVAL; + + code->code = ccp2_fmts[code->index]; + } else { + if (code->index != 0) + return -EINVAL; + + format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, + V4L2_SUBDEV_FORMAT_TRY); + code->code = format->code; + } + + return 0; +} + +static int ccp2_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * ccp2_get_format - Handle get format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt : pointer to v4l2 subdev format structure + * return -EINVAL or zero on sucess + */ +static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + return 0; +} + +/* + * ccp2_set_format - Handle set format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt : pointer to v4l2 subdev format structure + * returns zero + */ +static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == CCP2_PAD_SINK) { + format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE, + fmt->which); + *format = fmt->format; + ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which); + } + + return 0; +} + +/* + * ccp2_init_formats - Initialize formats on all pads + * @sd: ISP CCP2 V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. If fh is not NULL, try + * formats are initialized on the file handle. Otherwise active formats are + * initialized on the device. + */ +static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format; + + memset(&format, 0, sizeof(format)); + format.pad = CCP2_PAD_SINK; + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.width = 4096; + format.format.height = 4096; + ccp2_set_format(sd, fh, &format); + + return 0; +} + +/* + * ccp2_s_stream - Enable/Disable streaming on ccp2 subdev + * @sd : pointer to v4l2 subdev structure + * @enable: 1 == Enable, 0 == Disable + * return zero + */ +static int ccp2_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); + struct isp_device *isp = to_isp_device(ccp2); + struct device *dev = to_device(ccp2); + int ret; + + if (ccp2->state == ISP_PIPELINE_STREAM_STOPPED) { + if (enable == ISP_PIPELINE_STREAM_STOPPED) + return 0; + atomic_set(&ccp2->stopping, 0); + ccp2->error = 0; + } + + switch (enable) { + case ISP_PIPELINE_STREAM_CONTINUOUS: + if (ccp2->phy) { + ret = omap3isp_csiphy_acquire(ccp2->phy); + if (ret < 0) + return ret; + } + + ccp2_if_configure(ccp2); + ccp2_print_status(ccp2); + + /* Enable CSI1/CCP2 interface */ + ccp2_if_enable(ccp2, 1); + break; + + case ISP_PIPELINE_STREAM_SINGLESHOT: + if (ccp2->state != ISP_PIPELINE_STREAM_SINGLESHOT) { + struct v4l2_mbus_framefmt *format; + + format = &ccp2->formats[CCP2_PAD_SINK]; + + ccp2->mem_cfg.hsize_count = format->width; + ccp2->mem_cfg.vsize_count = format->height; + ccp2->mem_cfg.src_ofst = 0; + + ccp2_mem_configure(ccp2, &ccp2->mem_cfg); + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI1_READ); + ccp2_print_status(ccp2); + } + ccp2_mem_enable(ccp2, 1); + break; + + case ISP_PIPELINE_STREAM_STOPPED: + if (omap3isp_module_sync_idle(&sd->entity, &ccp2->wait, + &ccp2->stopping)) + dev_dbg(dev, "%s: module stop timeout.\n", sd->name); + if (ccp2->input == CCP2_INPUT_MEMORY) { + ccp2_mem_enable(ccp2, 0); + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI1_READ); + } else if (ccp2->input == CCP2_INPUT_SENSOR) { + /* Disable CSI1/CCP2 interface */ + ccp2_if_enable(ccp2, 0); + if (ccp2->phy) + omap3isp_csiphy_release(ccp2->phy); + } + break; + } + + ccp2->state = enable; + return 0; +} + +/* subdev video operations */ +static const struct v4l2_subdev_video_ops ccp2_sd_video_ops = { + .s_stream = ccp2_s_stream, +}; + +/* subdev pad operations */ +static const struct v4l2_subdev_pad_ops ccp2_sd_pad_ops = { + .enum_mbus_code = ccp2_enum_mbus_code, + .enum_frame_size = ccp2_enum_frame_size, + .get_fmt = ccp2_get_format, + .set_fmt = ccp2_set_format, +}; + +/* subdev operations */ +static const struct v4l2_subdev_ops ccp2_sd_ops = { + .video = &ccp2_sd_video_ops, + .pad = &ccp2_sd_pad_ops, +}; + +/* subdev internal operations */ +static const struct v4l2_subdev_internal_ops ccp2_sd_internal_ops = { + .open = ccp2_init_formats, +}; + +/* -------------------------------------------------------------------------- + * ISP ccp2 video device node + */ + +/* + * ccp2_video_queue - Queue video buffer. + * @video : Pointer to isp video structure + * @buffer: Pointer to isp_buffer structure + * return -EIO or zero on success + */ +static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer) +{ + struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2; + + ccp2_set_inaddr(ccp2, buffer->isp_addr); + return 0; +} + +static const struct isp_video_operations ccp2_video_ops = { + .queue = ccp2_video_queue, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +/* + * ccp2_link_setup - Setup ccp2 connections. + * @entity : Pointer to media entity structure + * @local : Pointer to local pad array + * @remote : Pointer to remote pad array + * @flags : Link flags + * return -EINVAL on error or zero on success + */ +static int ccp2_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); + + switch (local->index | media_entity_type(remote->entity)) { + case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE: + /* read from memory */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (ccp2->input == CCP2_INPUT_SENSOR) + return -EBUSY; + ccp2->input = CCP2_INPUT_MEMORY; + } else { + if (ccp2->input == CCP2_INPUT_MEMORY) + ccp2->input = CCP2_INPUT_NONE; + } + break; + + case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + /* read from sensor/phy */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (ccp2->input == CCP2_INPUT_MEMORY) + return -EBUSY; + ccp2->input = CCP2_INPUT_SENSOR; + } else { + if (ccp2->input == CCP2_INPUT_SENSOR) + ccp2->input = CCP2_INPUT_NONE; + } break; + + case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: + /* write to video port/ccdc */ + if (flags & MEDIA_LNK_FL_ENABLED) + ccp2->output = CCP2_OUTPUT_CCDC; + else + ccp2->output = CCP2_OUTPUT_NONE; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* media operations */ +static const struct media_entity_operations ccp2_media_ops = { + .link_setup = ccp2_link_setup, +}; + +/* + * ccp2_init_entities - Initialize ccp2 subdev and media entity. + * @ccp2: Pointer to ISP CCP2 device + * return negative error code or zero on success + */ +static int ccp2_init_entities(struct isp_ccp2_device *ccp2) +{ + struct v4l2_subdev *sd = &ccp2->subdev; + struct media_pad *pads = ccp2->pads; + struct media_entity *me = &sd->entity; + int ret; + + ccp2->input = CCP2_INPUT_NONE; + ccp2->output = CCP2_OUTPUT_NONE; + + v4l2_subdev_init(sd, &ccp2_sd_ops); + sd->internal_ops = &ccp2_sd_internal_ops; + strlcpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name)); + sd->grp_id = 1 << 16; /* group ID for isp subdevs */ + v4l2_set_subdevdata(sd, ccp2); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + me->ops = &ccp2_media_ops; + ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0); + if (ret < 0) + return ret; + + ccp2_init_formats(sd, NULL); + + /* + * The CCP2 has weird line alignment requirements, possibly caused by + * DPCM8 decompression. Line length for data read from memory must be a + * multiple of 128 bits (16 bytes) in continuous mode (when no padding + * is present at end of lines). Additionally, if padding is used, the + * padded line length must be a multiple of 32 bytes. To simplify the + * implementation we use a fixed 32 bytes alignment regardless of the + * input format and width. If strict 128 bits alignment support is + * required ispvideo will need to be made aware of this special dual + * alignement requirements. + */ + ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + ccp2->video_in.bpl_alignment = 32; + ccp2->video_in.bpl_max = 0xffffffe0; + ccp2->video_in.isp = to_isp_device(ccp2); + ccp2->video_in.ops = &ccp2_video_ops; + ccp2->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; + + ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); + if (ret < 0) + return ret; + + /* Connect the video node to the ccp2 subdev. */ + ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, + &ccp2->subdev.entity, CCP2_PAD_SINK, 0); + if (ret < 0) + return ret; + + return 0; +} + +/* + * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev + * @ccp2: Pointer to ISP CCP2 device + */ +void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) +{ + media_entity_cleanup(&ccp2->subdev.entity); + + v4l2_device_unregister_subdev(&ccp2->subdev); + omap3isp_video_unregister(&ccp2->video_in); +} + +/* + * omap3isp_ccp2_register_entities - Register the subdev media entity + * @ccp2: Pointer to ISP CCP2 device + * @vdev: Pointer to v4l device + * return negative error code or zero on success + */ + +int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccp2->video_in, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccp2_unregister_entities(ccp2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP ccp2 initialisation and cleanup + */ + +/* + * omap3isp_ccp2_cleanup - CCP2 un-initialization + * @isp : Pointer to ISP device + */ +void omap3isp_ccp2_cleanup(struct isp_device *isp) +{ +} + +/* + * omap3isp_ccp2_init - CCP2 initialization. + * @isp : Pointer to ISP device + * return negative error code or zero on success + */ +int omap3isp_ccp2_init(struct isp_device *isp) +{ + struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; + int ret; + + init_waitqueue_head(&ccp2->wait); + + /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with + * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly + * configured. + * + * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c). + */ + if (isp->revision == ISP_REVISION_15_0) + ccp2->phy = &isp->isp_csiphy1; + + ret = ccp2_init_entities(ccp2); + if (ret < 0) + goto out; + + ccp2_reset(ccp2); +out: + if (ret) + omap3isp_ccp2_cleanup(isp); + + return ret; +} diff --git a/drivers/media/video/omap3isp/ispccp2.h b/drivers/media/video/omap3isp/ispccp2.h new file mode 100644 index 000000000000..5505a86a9a74 --- /dev/null +++ b/drivers/media/video/omap3isp/ispccp2.h @@ -0,0 +1,98 @@ +/* + * ispccp2.h + * + * TI OMAP3 ISP - CCP2 module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2010 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_CCP2_H +#define OMAP3_ISP_CCP2_H + +#include + +struct isp_device; +struct isp_csiphy; + +/* Sink and source ccp2 pads */ +#define CCP2_PAD_SINK 0 +#define CCP2_PAD_SOURCE 1 +#define CCP2_PADS_NUM 2 + +/* CCP2 input media entity */ +enum ccp2_input_entity { + CCP2_INPUT_NONE, + CCP2_INPUT_SENSOR, + CCP2_INPUT_MEMORY, +}; + +/* CCP2 output media entity */ +enum ccp2_output_entity { + CCP2_OUTPUT_NONE, + CCP2_OUTPUT_CCDC, + CCP2_OUTPUT_MEMORY, +}; + + +/* Logical channel configuration */ +struct isp_interface_lcx_config { + int crc; + u32 data_start; + u32 data_size; + u32 format; +}; + +/* Memory channel configuration */ +struct isp_interface_mem_config { + u32 dst_port; + u32 vsize_count; + u32 hsize_count; + u32 src_ofst; + u32 dst_ofst; +}; + +/* CCP2 device */ +struct isp_ccp2_device { + struct v4l2_subdev subdev; + struct v4l2_mbus_framefmt formats[CCP2_PADS_NUM]; + struct media_pad pads[CCP2_PADS_NUM]; + + enum ccp2_input_entity input; + enum ccp2_output_entity output; + struct isp_interface_lcx_config if_cfg; + struct isp_interface_mem_config mem_cfg; + struct isp_video video_in; + struct isp_csiphy *phy; + unsigned int error; + enum isp_pipeline_stream_state state; + wait_queue_head_t wait; + atomic_t stopping; +}; + +/* Function declarations */ +int omap3isp_ccp2_init(struct isp_device *isp); +void omap3isp_ccp2_cleanup(struct isp_device *isp); +int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, + struct v4l2_device *vdev); +void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2); +int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2); + +#endif /* OMAP3_ISP_CCP2_H */ diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c new file mode 100644 index 000000000000..fb503f3db3be --- /dev/null +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -0,0 +1,1317 @@ +/* + * ispcsi2.c + * + * TI OMAP3 ISP - CSI2 module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ +#include +#include +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "ispcsi2.h" + +/* + * csi2_if_enable - Enable CSI2 Receiver interface. + * @enable: enable flag + * + */ +static void csi2_if_enable(struct isp_device *isp, + struct isp_csi2_device *csi2, u8 enable) +{ + struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl; + + isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN, + enable ? ISPCSI2_CTRL_IF_EN : 0); + + currctrl->if_enable = enable; +} + +/* + * csi2_recv_config - CSI2 receiver module configuration. + * @currctrl: isp_csi2_ctrl_cfg structure + * + */ +static void csi2_recv_config(struct isp_device *isp, + struct isp_csi2_device *csi2, + struct isp_csi2_ctrl_cfg *currctrl) +{ + u32 reg; + + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL); + + if (currctrl->frame_mode) + reg |= ISPCSI2_CTRL_FRAME; + else + reg &= ~ISPCSI2_CTRL_FRAME; + + if (currctrl->vp_clk_enable) + reg |= ISPCSI2_CTRL_VP_CLK_EN; + else + reg &= ~ISPCSI2_CTRL_VP_CLK_EN; + + if (currctrl->vp_only_enable) + reg |= ISPCSI2_CTRL_VP_ONLY_EN; + else + reg &= ~ISPCSI2_CTRL_VP_ONLY_EN; + + reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK; + reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT; + + if (currctrl->ecc_enable) + reg |= ISPCSI2_CTRL_ECC_EN; + else + reg &= ~ISPCSI2_CTRL_ECC_EN; + + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL); +} + +static const unsigned int csi2_input_fmts[] = { + V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, + V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, + V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, + V4L2_MBUS_FMT_SGBRG10_1X10, + V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, +}; + +/* To set the format on the CSI2 requires a mapping function that takes + * the following inputs: + * - 2 different formats (at this time) + * - 2 destinations (mem, vp+mem) (vp only handled separately) + * - 2 decompression options (on, off) + * - 2 isp revisions (certain format must be handled differently on OMAP3630) + * Output should be CSI2 frame format code + * Array indices as follows: [format][dest][decompr][is_3630] + * Not all combinations are valid. 0 means invalid. + */ +static const u16 __csi2_fmt_map[2][2][2][2] = { + /* RAW10 formats */ + { + /* Output to memory */ + { + /* No DPCM decompression */ + { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 }, + /* DPCM decompression */ + { 0, 0 }, + }, + /* Output to both */ + { + /* No DPCM decompression */ + { CSI2_PIX_FMT_RAW10_EXP16_VP, + CSI2_PIX_FMT_RAW10_EXP16_VP }, + /* DPCM decompression */ + { 0, 0 }, + }, + }, + /* RAW10 DPCM8 formats */ + { + /* Output to memory */ + { + /* No DPCM decompression */ + { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 }, + /* DPCM decompression */ + { CSI2_PIX_FMT_RAW8_DPCM10_EXP16, + CSI2_USERDEF_8BIT_DATA1_DPCM10 }, + }, + /* Output to both */ + { + /* No DPCM decompression */ + { CSI2_PIX_FMT_RAW8_VP, + CSI2_PIX_FMT_RAW8_VP }, + /* DPCM decompression */ + { CSI2_PIX_FMT_RAW8_DPCM10_VP, + CSI2_USERDEF_8BIT_DATA1_DPCM10_VP }, + }, + }, +}; + +/* + * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID + * @csi2: ISP CSI2 device + * + * Returns CSI2 physical format id + */ +static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2) +{ + const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK]; + int fmtidx, destidx, is_3630; + + switch (fmt->code) { + case V4L2_MBUS_FMT_SGRBG10_1X10: + case V4L2_MBUS_FMT_SRGGB10_1X10: + case V4L2_MBUS_FMT_SBGGR10_1X10: + case V4L2_MBUS_FMT_SGBRG10_1X10: + fmtidx = 0; + break; + case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: + case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: + case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: + case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: + fmtidx = 1; + break; + default: + WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n", + fmt->code); + return 0; + } + + if (!(csi2->output & CSI2_OUTPUT_CCDC) && + !(csi2->output & CSI2_OUTPUT_MEMORY)) { + /* Neither output enabled is a valid combination */ + return CSI2_PIX_FMT_OTHERS; + } + + /* If we need to skip frames at the beginning of the stream disable the + * video port to avoid sending the skipped frames to the CCDC. + */ + destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC); + is_3630 = csi2->isp->revision == ISP_REVISION_15_0; + + return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630]; +} + +/* + * csi2_set_outaddr - Set memory address to save output image + * @csi2: Pointer to ISP CSI2a device. + * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. + * + * Sets the memory address where the output will be saved. + * + * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte + * boundary. + */ +static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr) +{ + struct isp_device *isp = csi2->isp; + struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0]; + + ctx->ping_addr = addr; + ctx->pong_addr = addr; + isp_reg_writel(isp, ctx->ping_addr, + csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); + isp_reg_writel(isp, ctx->pong_addr, + csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); +} + +/* + * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should + * be enabled by CSI2. + * @format_id: mapped format id + * + */ +static inline int is_usr_def_mapping(u32 format_id) +{ + return (format_id & 0x40) ? 1 : 0; +} + +/* + * csi2_ctx_enable - Enable specified CSI2 context + * @ctxnum: Context number, valid between 0 and 7 values. + * @enable: enable + * + */ +static void csi2_ctx_enable(struct isp_device *isp, + struct isp_csi2_device *csi2, u8 ctxnum, u8 enable) +{ + struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum]; + unsigned int skip = 0; + u32 reg; + + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); + + if (enable) { + if (csi2->frame_skip) + skip = csi2->frame_skip; + else if (csi2->output & CSI2_OUTPUT_MEMORY) + skip = 1; + + reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK; + reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK + | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) + | ISPCSI2_CTX_CTRL1_CTX_EN; + } else { + reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN; + } + + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); + ctx->enabled = enable; +} + +/* + * csi2_ctx_config - CSI2 context configuration. + * @ctx: context configuration + * + */ +static void csi2_ctx_config(struct isp_device *isp, + struct isp_csi2_device *csi2, + struct isp_csi2_ctx_cfg *ctx) +{ + u32 reg; + + /* Set up CSI2_CTx_CTRL1 */ + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); + + if (ctx->eof_enabled) + reg |= ISPCSI2_CTX_CTRL1_EOF_EN; + else + reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN; + + if (ctx->eol_enabled) + reg |= ISPCSI2_CTX_CTRL1_EOL_EN; + else + reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN; + + if (ctx->checksum_enabled) + reg |= ISPCSI2_CTX_CTRL1_CS_EN; + else + reg &= ~ISPCSI2_CTX_CTRL1_CS_EN; + + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); + + /* Set up CSI2_CTx_CTRL2 */ + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); + + reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK); + reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; + + reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK); + reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT; + + if (ctx->dpcm_decompress) { + if (ctx->dpcm_predictor) + reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED; + else + reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED; + } + + if (is_usr_def_mapping(ctx->format_id)) { + reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK; + reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT; + } + + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); + + /* Set up CSI2_CTx_CTRL3 */ + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); + reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK); + reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT); + + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); + + /* Set up CSI2_CTx_DAT_OFST */ + reg = isp_reg_readl(isp, csi2->regs1, + ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); + reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK; + reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT; + isp_reg_writel(isp, reg, csi2->regs1, + ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); + + isp_reg_writel(isp, ctx->ping_addr, + csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); + + isp_reg_writel(isp, ctx->pong_addr, + csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); +} + +/* + * csi2_timing_config - CSI2 timing configuration. + * @timing: csi2_timing_cfg structure + */ +static void csi2_timing_config(struct isp_device *isp, + struct isp_csi2_device *csi2, + struct isp_csi2_timing_cfg *timing) +{ + u32 reg; + + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING); + + if (timing->force_rx_mode) + reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); + else + reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); + + if (timing->stop_state_16x) + reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); + else + reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); + + if (timing->stop_state_4x) + reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); + else + reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); + + reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum); + reg |= timing->stop_state_counter << + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum); + + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING); +} + +/* + * csi2_irq_ctx_set - Enables CSI2 Context IRQs. + * @enable: Enable/disable CSI2 Context interrupts + */ +static void csi2_irq_ctx_set(struct isp_device *isp, + struct isp_csi2_device *csi2, int enable) +{ + u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ; + int i; + + if (csi2->use_fs_irq) + reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ; + + for (i = 0; i < 8; i++) { + isp_reg_writel(isp, reg, csi2->regs1, + ISPCSI2_CTX_IRQSTATUS(i)); + if (enable) + isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), + reg); + else + isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), + reg); + } +} + +/* + * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs. + * @enable: Enable/disable CSI2 ComplexIO #1 interrupts + */ +static void csi2_irq_complexio1_set(struct isp_device *isp, + struct isp_csi2_device *csi2, int enable) +{ + u32 reg; + reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT | + ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER | + ISPCSI2_PHY_IRQENABLE_STATEULPM5 | + ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 | + ISPCSI2_PHY_IRQENABLE_ERRESC5 | + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 | + ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 | + ISPCSI2_PHY_IRQENABLE_STATEULPM4 | + ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 | + ISPCSI2_PHY_IRQENABLE_ERRESC4 | + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 | + ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 | + ISPCSI2_PHY_IRQENABLE_STATEULPM3 | + ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 | + ISPCSI2_PHY_IRQENABLE_ERRESC3 | + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 | + ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 | + ISPCSI2_PHY_IRQENABLE_STATEULPM2 | + ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 | + ISPCSI2_PHY_IRQENABLE_ERRESC2 | + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 | + ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 | + ISPCSI2_PHY_IRQENABLE_STATEULPM1 | + ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 | + ISPCSI2_PHY_IRQENABLE_ERRESC1 | + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 | + ISPCSI2_PHY_IRQENABLE_ERRSOTHS1; + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); + if (enable) + reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE); + else + reg = 0; + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE); +} + +/* + * csi2_irq_status_set - Enables CSI2 Status IRQs. + * @enable: Enable/disable CSI2 Status interrupts + */ +static void csi2_irq_status_set(struct isp_device *isp, + struct isp_csi2_device *csi2, int enable) +{ + u32 reg; + reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | + ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ | + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | + ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ | + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ | + ISPCSI2_IRQSTATUS_CONTEXT(0); + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS); + if (enable) + reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE); + else + reg = 0; + + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE); +} + +/* + * omap3isp_csi2_reset - Resets the CSI2 module. + * + * Must be called with the phy lock held. + * + * Returns 0 if successful, or -EBUSY if power command didn't respond. + */ +int omap3isp_csi2_reset(struct isp_csi2_device *csi2) +{ + struct isp_device *isp = csi2->isp; + u8 soft_reset_retries = 0; + u32 reg; + int i; + + if (!csi2->available) + return -ENODEV; + + if (csi2->phy->phy_in_use) + return -EBUSY; + + isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, + ISPCSI2_SYSCONFIG_SOFT_RESET); + + do { + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) & + ISPCSI2_SYSSTATUS_RESET_DONE; + if (reg == ISPCSI2_SYSSTATUS_RESET_DONE) + break; + soft_reset_retries++; + if (soft_reset_retries < 5) + udelay(100); + } while (soft_reset_retries < 5); + + if (soft_reset_retries == 5) { + printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n"); + return -EBUSY; + } + + if (isp->revision == ISP_REVISION_15_0) + isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG, + ISPCSI2_PHY_CFG_RESET_CTRL); + + i = 100; + do { + reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1) + & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK; + if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK) + break; + udelay(100); + } while (--i > 0); + + if (i == 0) { + printk(KERN_ERR + "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); + return -EBUSY; + } + + if (isp->autoidle) + isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | + ISPCSI2_SYSCONFIG_AUTO_IDLE, + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART | + ((isp->revision == ISP_REVISION_15_0) ? + ISPCSI2_SYSCONFIG_AUTO_IDLE : 0)); + else + isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | + ISPCSI2_SYSCONFIG_AUTO_IDLE, + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO); + + return 0; +} + +static int csi2_configure(struct isp_csi2_device *csi2) +{ + const struct isp_v4l2_subdevs_group *pdata; + struct isp_device *isp = csi2->isp; + struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; + struct v4l2_subdev *sensor; + struct media_pad *pad; + + /* + * CSI2 fields that can be updated while the context has + * been enabled or the interface has been enabled are not + * updated dynamically currently. So we do not allow to + * reconfigure if either has been enabled + */ + if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) + return -EBUSY; + + pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]); + sensor = media_entity_to_v4l2_subdev(pad->entity); + pdata = sensor->host_priv; + + csi2->frame_skip = 0; + v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); + + csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; + csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; + csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; + + timing->ionum = 1; + timing->force_rx_mode = 1; + timing->stop_state_16x = 1; + timing->stop_state_4x = 1; + timing->stop_state_counter = 0x1FF; + + /* + * The CSI2 receiver can't do any format conversion except DPCM + * decompression, so every set_format call configures both pads + * and enables DPCM decompression as a special case: + */ + if (csi2->formats[CSI2_PAD_SINK].code != + csi2->formats[CSI2_PAD_SOURCE].code) + csi2->dpcm_decompress = true; + else + csi2->dpcm_decompress = false; + + csi2->contexts[0].format_id = csi2_ctx_map_format(csi2); + + if (csi2->video_out.bpl_padding == 0) + csi2->contexts[0].data_offset = 0; + else + csi2->contexts[0].data_offset = csi2->video_out.bpl_value; + + /* + * Enable end of frame and end of line signals generation for + * context 0. These signals are generated from CSI2 receiver to + * qualify the last pixel of a frame and the last pixel of a line. + * Without enabling the signals CSI2 receiver writes data to memory + * beyond buffer size and/or data line offset is not handled correctly. + */ + csi2->contexts[0].eof_enabled = 1; + csi2->contexts[0].eol_enabled = 1; + + csi2_irq_complexio1_set(isp, csi2, 1); + csi2_irq_ctx_set(isp, csi2, 1); + csi2_irq_status_set(isp, csi2, 1); + + /* Set configuration (timings, format and links) */ + csi2_timing_config(isp, csi2, timing); + csi2_recv_config(isp, csi2, &csi2->ctrl); + csi2_ctx_config(isp, csi2, &csi2->contexts[0]); + + return 0; +} + +/* + * csi2_print_status - Prints CSI2 debug information. + */ +#define CSI2_PRINT_REGISTER(isp, regs, name)\ + dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \ + isp_reg_readl(isp, regs, ISPCSI2_##name)) + +static void csi2_print_status(struct isp_csi2_device *csi2) +{ + struct isp_device *isp = csi2->isp; + + if (!csi2->available) + return; + + dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n"); + + CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG); + CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS); + CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE); + CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL); + CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H); + CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ); + CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG); + CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS); + CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET); + CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE); + CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P); + CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0)); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0)); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0)); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0)); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0)); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0)); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0)); + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0)); + + dev_dbg(isp->dev, "--------------------------------------------\n"); +} + +/* ----------------------------------------------------------------------------- + * Interrupt handling + */ + +/* + * csi2_isr_buffer - Does buffer handling at end-of-frame + * when writing to memory. + */ +static void csi2_isr_buffer(struct isp_csi2_device *csi2) +{ + struct isp_device *isp = csi2->isp; + struct isp_buffer *buffer; + + csi2_ctx_enable(isp, csi2, 0, 0); + + buffer = omap3isp_video_buffer_next(&csi2->video_out, 0); + + /* + * Let video queue operation restart engine if there is an underrun + * condition. + */ + if (buffer == NULL) + return; + + csi2_set_outaddr(csi2, buffer->isp_addr); + csi2_ctx_enable(isp, csi2, 0, 1); +} + +static void csi2_isr_ctx(struct isp_csi2_device *csi2, + struct isp_csi2_ctx_cfg *ctx) +{ + struct isp_device *isp = csi2->isp; + unsigned int n = ctx->ctxnum; + u32 status; + + status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); + isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); + + /* Propagate frame number */ + if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) { + struct isp_pipeline *pipe = + to_isp_pipeline(&csi2->subdev.entity); + if (pipe->do_propagation) + atomic_inc(&pipe->frame_number); + } + + if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ)) + return; + + /* Skip interrupts until we reach the frame skip count. The CSI2 will be + * automatically disabled, as the frame skip count has been programmed + * in the CSI2_CTx_CTRL1::COUNT field, so reenable it. + * + * It would have been nice to rely on the FRAME_NUMBER interrupt instead + * but it turned out that the interrupt is only generated when the CSI2 + * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased + * correctly and reaches 0 when data is forwarded to the video port only + * but no interrupt arrives). Maybe a CSI2 hardware bug. + */ + if (csi2->frame_skip) { + csi2->frame_skip--; + if (csi2->frame_skip == 0) { + ctx->format_id = csi2_ctx_map_format(csi2); + csi2_ctx_config(isp, csi2, ctx); + csi2_ctx_enable(isp, csi2, n, 1); + } + return; + } + + if (csi2->output & CSI2_OUTPUT_MEMORY) + csi2_isr_buffer(csi2); +} + +/* + * omap3isp_csi2_isr - CSI2 interrupt handling. + * + * Return -EIO on Transmission error + */ +int omap3isp_csi2_isr(struct isp_csi2_device *csi2) +{ + u32 csi2_irqstatus, cpxio1_irqstatus; + struct isp_device *isp = csi2->isp; + int retval = 0; + + if (!csi2->available) + return -ENODEV; + + csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); + isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); + + /* Failure Cases */ + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) { + cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1, + ISPCSI2_PHY_IRQSTATUS); + isp_reg_writel(isp, cpxio1_irqstatus, + csi2->regs1, ISPCSI2_PHY_IRQSTATUS); + dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " + "%x\n", cpxio1_irqstatus); + retval = -EIO; + } + + if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) { + dev_dbg(isp->dev, "CSI2 Err:" + " OCP:%d," + " Short_pack:%d," + " ECC:%d," + " CPXIO2:%d," + " FIFO_OVF:%d," + "\n", + (csi2_irqstatus & + ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0, + (csi2_irqstatus & + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0, + (csi2_irqstatus & + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0, + (csi2_irqstatus & + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, + (csi2_irqstatus & + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); + retval = -EIO; + } + + if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) + return 0; + + /* Successful cases */ + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) + csi2_isr_ctx(csi2, &csi2->contexts[0]); + + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) + dev_dbg(isp->dev, "CSI2: ECC correction done\n"); + + return retval; +} + +/* ----------------------------------------------------------------------------- + * ISP video operations + */ + +/* + * csi2_queue - Queues the first buffer when using memory output + * @video: The video node + * @buffer: buffer to queue + */ +static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer) +{ + struct isp_device *isp = video->isp; + struct isp_csi2_device *csi2 = &isp->isp_csi2a; + + csi2_set_outaddr(csi2, buffer->isp_addr); + + /* + * If streaming was enabled before there was a buffer queued + * or underrun happened in the ISR, the hardware was not enabled + * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set. + * Enable it now. + */ + if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { + /* Enable / disable context 0 and IRQs */ + csi2_if_enable(isp, csi2, 1); + csi2_ctx_enable(isp, csi2, 0, 1); + isp_video_dmaqueue_flags_clr(&csi2->video_out); + } + + return 0; +} + +static const struct isp_video_operations csi2_ispvideo_ops = { + .queue = csi2_queue, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +static struct v4l2_mbus_framefmt * +__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(fh, pad); + else + return &csi2->formats[pad]; +} + +static void +csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, + unsigned int pad, struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + enum v4l2_mbus_pixelcode pixelcode; + struct v4l2_mbus_framefmt *format; + const struct isp_format_info *info; + unsigned int i; + + switch (pad) { + case CSI2_PAD_SINK: + /* Clamp the width and height to valid range (1-8191). */ + for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) { + if (fmt->code == csi2_input_fmts[i]) + break; + } + + /* If not found, use SGRBG10 as default */ + if (i >= ARRAY_SIZE(csi2_input_fmts)) + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + + fmt->width = clamp_t(u32, fmt->width, 1, 8191); + fmt->height = clamp_t(u32, fmt->height, 1, 8191); + break; + + case CSI2_PAD_SOURCE: + /* Source format same as sink format, except for DPCM + * compression. + */ + pixelcode = fmt->code; + format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + + /* + * Only Allow DPCM decompression, and check that the + * pattern is preserved + */ + info = omap3isp_video_format_info(fmt->code); + if (info->uncompressed == pixelcode) + fmt->code = pixelcode; + break; + } + + /* RGB, non-interlaced */ + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->field = V4L2_FIELD_NONE; +} + +/* + * csi2_enum_mbus_code - Handle pixel format enumeration + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @code : pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int csi2_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + const struct isp_format_info *info; + + if (code->pad == CSI2_PAD_SINK) { + if (code->index >= ARRAY_SIZE(csi2_input_fmts)) + return -EINVAL; + + code->code = csi2_input_fmts[code->index]; + } else { + format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, + V4L2_SUBDEV_FORMAT_TRY); + switch (code->index) { + case 0: + /* Passthrough sink pad code */ + code->code = format->code; + break; + case 1: + /* Uncompressed code */ + info = omap3isp_video_format_info(format->code); + if (info->uncompressed == format->code) + return -EINVAL; + + code->code = info->uncompressed; + break; + default: + return -EINVAL; + } + } + + return 0; +} + +static int csi2_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * csi2_get_format - Handle get format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt: pointer to v4l2 subdev format structure + * return -EINVAL or zero on sucess + */ +static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + return 0; +} + +/* + * csi2_set_format - Handle set format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt: pointer to v4l2 subdev format structure + * return -EINVAL or zero on success + */ +static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == CSI2_PAD_SINK) { + format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, + fmt->which); + *format = fmt->format; + csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); + } + + return 0; +} + +/* + * csi2_init_formats - Initialize formats on all pads + * @sd: ISP CSI2 V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. If fh is not NULL, try + * formats are initialized on the file handle. Otherwise active formats are + * initialized on the device. + */ +static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format; + + memset(&format, 0, sizeof(format)); + format.pad = CSI2_PAD_SINK; + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.width = 4096; + format.format.height = 4096; + csi2_set_format(sd, fh, &format); + + return 0; +} + +/* + * csi2_set_stream - Enable/Disable streaming on the CSI2 module + * @sd: ISP CSI2 V4L2 subdevice + * @enable: ISP pipeline stream state + * + * Return 0 on success or a negative error code otherwise. + */ +static int csi2_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct isp_device *isp = csi2->isp; + struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); + struct isp_video *video_out = &csi2->video_out; + + switch (enable) { + case ISP_PIPELINE_STREAM_CONTINUOUS: + if (omap3isp_csiphy_acquire(csi2->phy) < 0) + return -ENODEV; + csi2->use_fs_irq = pipe->do_propagation; + if (csi2->output & CSI2_OUTPUT_MEMORY) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); + csi2_configure(csi2); + csi2_print_status(csi2); + + /* + * When outputting to memory with no buffer available, let the + * buffer queue handler start the hardware. A DMA queue flag + * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is + * a buffer available. + */ + if (csi2->output & CSI2_OUTPUT_MEMORY && + !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED)) + break; + /* Enable context 0 and IRQs */ + atomic_set(&csi2->stopping, 0); + csi2_ctx_enable(isp, csi2, 0, 1); + csi2_if_enable(isp, csi2, 1); + isp_video_dmaqueue_flags_clr(video_out); + break; + + case ISP_PIPELINE_STREAM_STOPPED: + if (csi2->state == ISP_PIPELINE_STREAM_STOPPED) + return 0; + if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait, + &csi2->stopping)) + dev_dbg(isp->dev, "%s: module stop timeout.\n", + sd->name); + csi2_ctx_enable(isp, csi2, 0, 0); + csi2_if_enable(isp, csi2, 0); + csi2_irq_ctx_set(isp, csi2, 0); + omap3isp_csiphy_release(csi2->phy); + isp_video_dmaqueue_flags_clr(video_out); + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); + break; + } + + csi2->state = enable; + return 0; +} + +/* subdev video operations */ +static const struct v4l2_subdev_video_ops csi2_video_ops = { + .s_stream = csi2_set_stream, +}; + +/* subdev pad operations */ +static const struct v4l2_subdev_pad_ops csi2_pad_ops = { + .enum_mbus_code = csi2_enum_mbus_code, + .enum_frame_size = csi2_enum_frame_size, + .get_fmt = csi2_get_format, + .set_fmt = csi2_set_format, +}; + +/* subdev operations */ +static const struct v4l2_subdev_ops csi2_ops = { + .video = &csi2_video_ops, + .pad = &csi2_pad_ops, +}; + +/* subdev internal operations */ +static const struct v4l2_subdev_internal_ops csi2_internal_ops = { + .open = csi2_init_formats, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +/* + * csi2_link_setup - Setup CSI2 connections. + * @entity : Pointer to media entity structure + * @local : Pointer to local pad array + * @remote : Pointer to remote pad array + * @flags : Link flags + * return -EINVAL or zero on success + */ +static int csi2_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); + struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl; + + /* + * The ISP core doesn't support pipelines with multiple video outputs. + * Revisit this when it will be implemented, and return -EBUSY for now. + */ + + switch (local->index | media_entity_type(remote->entity)) { + case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: + if (flags & MEDIA_LNK_FL_ENABLED) { + if (csi2->output & ~CSI2_OUTPUT_MEMORY) + return -EBUSY; + csi2->output |= CSI2_OUTPUT_MEMORY; + } else { + csi2->output &= ~CSI2_OUTPUT_MEMORY; + } + break; + + case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: + if (flags & MEDIA_LNK_FL_ENABLED) { + if (csi2->output & ~CSI2_OUTPUT_CCDC) + return -EBUSY; + csi2->output |= CSI2_OUTPUT_CCDC; + } else { + csi2->output &= ~CSI2_OUTPUT_CCDC; + } + break; + + default: + /* Link from camera to CSI2 is fixed... */ + return -EINVAL; + } + + ctrl->vp_only_enable = + (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true; + ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC); + + return 0; +} + +/* media operations */ +static const struct media_entity_operations csi2_media_ops = { + .link_setup = csi2_link_setup, +}; + +/* + * csi2_init_entities - Initialize subdev and media entity. + * @csi2: Pointer to csi2 structure. + * return -ENOMEM or zero on success + */ +static int csi2_init_entities(struct isp_csi2_device *csi2) +{ + struct v4l2_subdev *sd = &csi2->subdev; + struct media_pad *pads = csi2->pads; + struct media_entity *me = &sd->entity; + int ret; + + v4l2_subdev_init(sd, &csi2_ops); + sd->internal_ops = &csi2_internal_ops; + strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name)); + + sd->grp_id = 1 << 16; /* group ID for isp subdevs */ + v4l2_set_subdevdata(sd, csi2); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + + me->ops = &csi2_media_ops; + ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0); + if (ret < 0) + return ret; + + csi2_init_formats(sd, NULL); + + /* Video device node */ + csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + csi2->video_out.ops = &csi2_ispvideo_ops; + csi2->video_out.bpl_alignment = 32; + csi2->video_out.bpl_zero_padding = 1; + csi2->video_out.bpl_max = 0x1ffe0; + csi2->video_out.isp = csi2->isp; + csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; + + ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); + if (ret < 0) + return ret; + + /* Connect the CSI2 subdev to the video node. */ + ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, + &csi2->video_out.video.entity, 0, 0); + if (ret < 0) + return ret; + + return 0; +} + +void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) +{ + media_entity_cleanup(&csi2->subdev.entity); + + v4l2_device_unregister_subdev(&csi2->subdev); + omap3isp_video_unregister(&csi2->video_out); +} + +int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &csi2->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&csi2->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_csi2_unregister_entities(csi2); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CSI2 initialisation and cleanup + */ + +/* + * omap3isp_csi2_cleanup - Routine for module driver cleanup + */ +void omap3isp_csi2_cleanup(struct isp_device *isp) +{ +} + +/* + * omap3isp_csi2_init - Routine for module driver init + */ +int omap3isp_csi2_init(struct isp_device *isp) +{ + struct isp_csi2_device *csi2a = &isp->isp_csi2a; + struct isp_csi2_device *csi2c = &isp->isp_csi2c; + int ret; + + csi2a->isp = isp; + csi2a->available = 1; + csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1; + csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2; + csi2a->phy = &isp->isp_csiphy2; + csi2a->state = ISP_PIPELINE_STREAM_STOPPED; + init_waitqueue_head(&csi2a->wait); + + ret = csi2_init_entities(csi2a); + if (ret < 0) + goto fail; + + if (isp->revision == ISP_REVISION_15_0) { + csi2c->isp = isp; + csi2c->available = 1; + csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1; + csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2; + csi2c->phy = &isp->isp_csiphy1; + csi2c->state = ISP_PIPELINE_STREAM_STOPPED; + init_waitqueue_head(&csi2c->wait); + } + + return 0; +fail: + omap3isp_csi2_cleanup(isp); + return ret; +} diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/video/omap3isp/ispcsi2.h new file mode 100644 index 000000000000..456fb7fb8a0f --- /dev/null +++ b/drivers/media/video/omap3isp/ispcsi2.h @@ -0,0 +1,166 @@ +/* + * ispcsi2.h + * + * TI OMAP3 ISP - CSI2 module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_CSI2_H +#define OMAP3_ISP_CSI2_H + +#include +#include + +struct isp_csiphy; + +/* This is not an exhaustive list */ +enum isp_csi2_pix_formats { + CSI2_PIX_FMT_OTHERS = 0, + CSI2_PIX_FMT_YUV422_8BIT = 0x1e, + CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e, + CSI2_PIX_FMT_RAW10_EXP16 = 0xab, + CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f, + CSI2_PIX_FMT_RAW8 = 0x2a, + CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa, + CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a, + CSI2_PIX_FMT_RAW8_VP = 0x12a, + CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340, + CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0, + CSI2_USERDEF_8BIT_DATA1 = 0x40, +}; + +enum isp_csi2_irqevents { + OCP_ERR_IRQ = 0x4000, + SHORT_PACKET_IRQ = 0x2000, + ECC_CORRECTION_IRQ = 0x1000, + ECC_NO_CORRECTION_IRQ = 0x800, + COMPLEXIO2_ERR_IRQ = 0x400, + COMPLEXIO1_ERR_IRQ = 0x200, + FIFO_OVF_IRQ = 0x100, + CONTEXT7 = 0x80, + CONTEXT6 = 0x40, + CONTEXT5 = 0x20, + CONTEXT4 = 0x10, + CONTEXT3 = 0x8, + CONTEXT2 = 0x4, + CONTEXT1 = 0x2, + CONTEXT0 = 0x1, +}; + +enum isp_csi2_ctx_irqevents { + CTX_ECC_CORRECTION = 0x100, + CTX_LINE_NUMBER = 0x80, + CTX_FRAME_NUMBER = 0x40, + CTX_CS = 0x20, + CTX_LE = 0x8, + CTX_LS = 0x4, + CTX_FE = 0x2, + CTX_FS = 0x1, +}; + +enum isp_csi2_frame_mode { + ISP_CSI2_FRAME_IMMEDIATE, + ISP_CSI2_FRAME_AFTERFEC, +}; + +#define ISP_CSI2_MAX_CTX_NUM 7 + +struct isp_csi2_ctx_cfg { + u8 ctxnum; /* context number 0 - 7 */ + u8 dpcm_decompress; + + /* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */ + u8 virtual_id; + u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */ + u8 dpcm_predictor; /* 1: simple, 0: advanced */ + + /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */ + u16 alpha; + u16 data_offset; + u32 ping_addr; + u32 pong_addr; + u8 eof_enabled; + u8 eol_enabled; + u8 checksum_enabled; + u8 enabled; +}; + +struct isp_csi2_timing_cfg { + u8 ionum; /* IO1 or IO2 as in CSI2_TIMING */ + unsigned force_rx_mode:1; + unsigned stop_state_16x:1; + unsigned stop_state_4x:1; + u16 stop_state_counter; +}; + +struct isp_csi2_ctrl_cfg { + bool vp_clk_enable; + bool vp_only_enable; + u8 vp_out_ctrl; + enum isp_csi2_frame_mode frame_mode; + bool ecc_enable; + bool if_enable; +}; + +#define CSI2_PAD_SINK 0 +#define CSI2_PAD_SOURCE 1 +#define CSI2_PADS_NUM 2 + +#define CSI2_OUTPUT_CCDC (1 << 0) +#define CSI2_OUTPUT_MEMORY (1 << 1) + +struct isp_csi2_device { + struct v4l2_subdev subdev; + struct media_pad pads[CSI2_PADS_NUM]; + struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM]; + + struct isp_video video_out; + struct isp_device *isp; + + u8 available; /* Is the IP present on the silicon? */ + + /* mem resources - enums as defined in enum isp_mem_resources */ + u8 regs1; + u8 regs2; + + u32 output; /* output to CCDC, memory or both? */ + bool dpcm_decompress; + unsigned int frame_skip; + bool use_fs_irq; + + struct isp_csiphy *phy; + struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1]; + struct isp_csi2_timing_cfg timing[2]; + struct isp_csi2_ctrl_cfg ctrl; + enum isp_pipeline_stream_state state; + wait_queue_head_t wait; + atomic_t stopping; +}; + +int omap3isp_csi2_isr(struct isp_csi2_device *csi2); +int omap3isp_csi2_reset(struct isp_csi2_device *csi2); +int omap3isp_csi2_init(struct isp_device *isp); +void omap3isp_csi2_cleanup(struct isp_device *isp); +void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2); +int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, + struct v4l2_device *vdev); +#endif /* OMAP3_ISP_CSI2_H */ diff --git a/drivers/media/video/omap3isp/ispcsiphy.c b/drivers/media/video/omap3isp/ispcsiphy.c new file mode 100644 index 000000000000..5be37ce7d0c2 --- /dev/null +++ b/drivers/media/video/omap3isp/ispcsiphy.c @@ -0,0 +1,247 @@ +/* + * ispcsiphy.c + * + * TI OMAP3 ISP - CSI PHY module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "ispcsiphy.h" + +/* + * csiphy_lanes_config - Configuration of CSIPHY lanes. + * + * Updates HW configuration. + * Called with phy->mutex taken. + */ +static void csiphy_lanes_config(struct isp_csiphy *phy) +{ + unsigned int i; + u32 reg; + + reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); + + for (i = 0; i < phy->num_data_lanes; i++) { + reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | + ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); + reg |= (phy->lanes.data[i].pol << + ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1)); + reg |= (phy->lanes.data[i].pos << + ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1)); + } + + reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK | + ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK); + reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; + reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; + + isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); +} + +/* + * csiphy_power_autoswitch_enable + * @enable: Sets or clears the autoswitch function enable flag. + */ +static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable) +{ + isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG, + ISPCSI2_PHY_CFG_PWR_AUTO, + enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0); +} + +/* + * csiphy_set_power + * @power: Power state to be set. + * + * Returns 0 if successful, or -EBUSY if the retry count is exceeded. + */ +static int csiphy_set_power(struct isp_csiphy *phy, u32 power) +{ + u32 reg; + u8 retry_count; + + isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG, + ISPCSI2_PHY_CFG_PWR_CMD_MASK, power); + + retry_count = 0; + do { + udelay(50); + reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) & + ISPCSI2_PHY_CFG_PWR_STATUS_MASK; + + if (reg != power >> 2) + retry_count++; + + } while ((reg != power >> 2) && (retry_count < 100)); + + if (retry_count == 100) { + printk(KERN_ERR "CSI2 CIO set power failed!\n"); + return -EBUSY; + } + + return 0; +} + +/* + * csiphy_dphy_config - Configure CSI2 D-PHY parameters. + * + * Called with phy->mutex taken. + */ +static void csiphy_dphy_config(struct isp_csiphy *phy) +{ + u32 reg; + + /* Set up ISPCSIPHY_REG0 */ + reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0); + + reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | + ISPCSIPHY_REG0_THS_SETTLE_MASK); + reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT; + reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; + + isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); + + /* Set up ISPCSIPHY_REG1 */ + reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1); + + reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | + ISPCSIPHY_REG1_TCLK_MISS_MASK | + ISPCSIPHY_REG1_TCLK_SETTLE_MASK); + reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT; + reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; + reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; + + isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); +} + +static int csiphy_config(struct isp_csiphy *phy, + struct isp_csiphy_dphy_cfg *dphy, + struct isp_csiphy_lanes_cfg *lanes) +{ + unsigned int used_lanes = 0; + unsigned int i; + + /* Clock and data lanes verification */ + for (i = 0; i < phy->num_data_lanes; i++) { + if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3) + return -EINVAL; + + if (used_lanes & (1 << lanes->data[i].pos)) + return -EINVAL; + + used_lanes |= 1 << lanes->data[i].pos; + } + + if (lanes->clk.pol > 1 || lanes->clk.pos > 3) + return -EINVAL; + + if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos)) + return -EINVAL; + + mutex_lock(&phy->mutex); + phy->dphy = *dphy; + phy->lanes = *lanes; + mutex_unlock(&phy->mutex); + + return 0; +} + +int omap3isp_csiphy_acquire(struct isp_csiphy *phy) +{ + int rval; + + if (phy->vdd == NULL) { + dev_err(phy->isp->dev, "Power regulator for CSI PHY not " + "available\n"); + return -ENODEV; + } + + mutex_lock(&phy->mutex); + + rval = regulator_enable(phy->vdd); + if (rval < 0) + goto done; + + omap3isp_csi2_reset(phy->csi2); + + csiphy_dphy_config(phy); + csiphy_lanes_config(phy); + + rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); + if (rval) { + regulator_disable(phy->vdd); + goto done; + } + + csiphy_power_autoswitch_enable(phy, true); + phy->phy_in_use = 1; + +done: + mutex_unlock(&phy->mutex); + return rval; +} + +void omap3isp_csiphy_release(struct isp_csiphy *phy) +{ + mutex_lock(&phy->mutex); + if (phy->phy_in_use) { + csiphy_power_autoswitch_enable(phy, false); + csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); + regulator_disable(phy->vdd); + phy->phy_in_use = 0; + } + mutex_unlock(&phy->mutex); +} + +/* + * omap3isp_csiphy_init - Initialize the CSI PHY frontends + */ +int omap3isp_csiphy_init(struct isp_device *isp) +{ + struct isp_csiphy *phy1 = &isp->isp_csiphy1; + struct isp_csiphy *phy2 = &isp->isp_csiphy2; + + isp->platform_cb.csiphy_config = csiphy_config; + + phy2->isp = isp; + phy2->csi2 = &isp->isp_csi2a; + phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES; + phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1; + phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2; + mutex_init(&phy2->mutex); + + if (isp->revision == ISP_REVISION_15_0) { + phy1->isp = isp; + phy1->csi2 = &isp->isp_csi2c; + phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES; + phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1; + phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1; + mutex_init(&phy1->mutex); + } + + return 0; +} diff --git a/drivers/media/video/omap3isp/ispcsiphy.h b/drivers/media/video/omap3isp/ispcsiphy.h new file mode 100644 index 000000000000..9596dc6830a6 --- /dev/null +++ b/drivers/media/video/omap3isp/ispcsiphy.h @@ -0,0 +1,74 @@ +/* + * ispcsiphy.h + * + * TI OMAP3 ISP - CSI PHY module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_CSI_PHY_H +#define OMAP3_ISP_CSI_PHY_H + +struct isp_csi2_device; +struct regulator; + +struct csiphy_lane { + u8 pos; + u8 pol; +}; + +#define ISP_CSIPHY2_NUM_DATA_LANES 2 +#define ISP_CSIPHY1_NUM_DATA_LANES 1 + +struct isp_csiphy_lanes_cfg { + struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES]; + struct csiphy_lane clk; +}; + +struct isp_csiphy_dphy_cfg { + u8 ths_term; + u8 ths_settle; + u8 tclk_term; + unsigned tclk_miss:1; + u8 tclk_settle; +}; + +struct isp_csiphy { + struct isp_device *isp; + struct mutex mutex; /* serialize csiphy configuration */ + u8 phy_in_use; + struct isp_csi2_device *csi2; + struct regulator *vdd; + + /* mem resources - enums as defined in enum isp_mem_resources */ + unsigned int cfg_regs; + unsigned int phy_regs; + + u8 num_data_lanes; /* number of CSI2 Data Lanes supported */ + struct isp_csiphy_lanes_cfg lanes; + struct isp_csiphy_dphy_cfg dphy; +}; + +int omap3isp_csiphy_acquire(struct isp_csiphy *phy); +void omap3isp_csiphy_release(struct isp_csiphy *phy); +int omap3isp_csiphy_init(struct isp_device *isp); + +#endif /* OMAP3_ISP_CSI_PHY_H */ -- cgit v1.2.2 From de1135d44f4f25bee5a22d92e7cf2de64ded0dca Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 12 Feb 2011 18:05:06 -0300 Subject: [media] omap3isp: CCDC, preview engine and resizer The OMAP3 ISP CCDC, preview engine and resizer entities perform image processing and scaling. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: David Cohen Signed-off-by: Stanimir Varbanov Signed-off-by: Vimarsh Zutshi Signed-off-by: Tuukka Toivonen Signed-off-by: Sergio Aguirre Signed-off-by: Antti Koskipaa Signed-off-by: Ivan T. Ivanov Signed-off-by: RaniSuneela Signed-off-by: Atanas Filipov Signed-off-by: Gjorgji Rosikopulos Signed-off-by: Hiroshi DOYU Signed-off-by: Nayden Kanchev Signed-off-by: Phil Carmody Signed-off-by: Artem Bityutskiy Signed-off-by: Dominic Curran Signed-off-by: Ilkka Myllyperkio Signed-off-by: Pallavi Kulkarni Signed-off-by: Vaibhav Hiremath Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/cfa_coef_table.h | 61 + drivers/media/video/omap3isp/gamma_table.h | 90 + drivers/media/video/omap3isp/ispccdc.c | 2268 +++++++++++++++++++++ drivers/media/video/omap3isp/ispccdc.h | 219 ++ drivers/media/video/omap3isp/isppreview.c | 2113 +++++++++++++++++++ drivers/media/video/omap3isp/isppreview.h | 214 ++ drivers/media/video/omap3isp/ispresizer.c | 1693 +++++++++++++++ drivers/media/video/omap3isp/ispresizer.h | 147 ++ drivers/media/video/omap3isp/luma_enhance_table.h | 42 + drivers/media/video/omap3isp/noise_filter_table.h | 30 + 10 files changed, 6877 insertions(+) create mode 100644 drivers/media/video/omap3isp/cfa_coef_table.h create mode 100644 drivers/media/video/omap3isp/gamma_table.h create mode 100644 drivers/media/video/omap3isp/ispccdc.c create mode 100644 drivers/media/video/omap3isp/ispccdc.h create mode 100644 drivers/media/video/omap3isp/isppreview.c create mode 100644 drivers/media/video/omap3isp/isppreview.h create mode 100644 drivers/media/video/omap3isp/ispresizer.c create mode 100644 drivers/media/video/omap3isp/ispresizer.h create mode 100644 drivers/media/video/omap3isp/luma_enhance_table.h create mode 100644 drivers/media/video/omap3isp/noise_filter_table.h (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/cfa_coef_table.h b/drivers/media/video/omap3isp/cfa_coef_table.h new file mode 100644 index 000000000000..c60df0ed075a --- /dev/null +++ b/drivers/media/video/omap3isp/cfa_coef_table.h @@ -0,0 +1,61 @@ +/* + * cfa_coef_table.h + * + * TI OMAP3 ISP - CFA coefficients table + * + * Copyright (C) 2009-2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, +248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, +247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, +244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, +248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, +247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, +244, 0, 247, 0, 12, 27, 36, 247, 250, 0, 27, 0, 4, 250, 12, 244, +248, 0, 0, 0, 0, 40, 0, 0, 244, 12, 250, 4, 0, 27, 0, 250, +247, 36, 27, 12, 0, 247, 0, 244, 0, 0, 40, 0, 0, 0, 0, 248, + 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4, + 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0, + 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0, + 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4, + 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0, + 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0, + 0, 247, 0, 244, 247, 36, 27, 12, 0, 27, 0, 250, 244, 12, 250, 4, + 0, 0, 0, 248, 0, 0, 40, 0, 4, 250, 12, 244, 250, 0, 27, 0, + 12, 27, 36, 247, 244, 0, 247, 0, 0, 40, 0, 0, 248, 0, 0, 0, + 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0, + 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12, + 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0, + 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0, + 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12, + 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0, + 4, 250, 12, 244, 250, 0, 27, 0, 12, 27, 36, 247, 244, 0, 247, 0, + 0, 0, 0, 248, 0, 0, 40, 0, 0, 247, 0, 244, 247, 36, 27, 12, + 0, 27, 0, 250, 244, 12, 250, 4, 0, 40, 0, 0, 248, 0, 0, 0, +244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, +248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, +250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248, +244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, +248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, +250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248, +244, 12, 250, 4, 0, 27, 0, 250, 247, 36, 27, 12, 0, 247, 0, 244, +248, 0, 0, 0, 0, 40, 0, 0, 244, 0, 247, 0, 12, 27, 36, 247, +250, 0, 27, 0, 4, 250, 12, 244, 0, 0, 40, 0, 0, 0, 0, 248 diff --git a/drivers/media/video/omap3isp/gamma_table.h b/drivers/media/video/omap3isp/gamma_table.h new file mode 100644 index 000000000000..78deebf7d965 --- /dev/null +++ b/drivers/media/video/omap3isp/gamma_table.h @@ -0,0 +1,90 @@ +/* + * gamma_table.h + * + * TI OMAP3 ISP - Default gamma table for all components + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + + 0, 0, 1, 2, 3, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, + 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 36, 37, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 63, 64, 65, 66, 66, 67, 68, 69, 69, 70, + 71, 72, 72, 73, 74, 75, 75, 76, 77, 78, 78, 79, 80, 81, 81, 82, + 83, 84, 84, 85, 86, 87, 88, 88, 89, 90, 91, 91, 92, 93, 94, 94, + 95, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 103, 104, 104, +105, 106, 107, 108, 108, 109, 110, 111, 111, 112, 113, 114, 114, 115, 116, 117, +117, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, +126, 126, 127, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, +134, 134, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141, +142, 142, 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, 148, 148, 149, 149, +150, 150, 151, 151, 152, 152, 153, 153, 153, 153, 154, 154, 154, 154, 155, 155, +156, 156, 157, 157, 158, 158, 158, 159, 159, 159, 160, 160, 160, 161, 161, 162, +162, 163, 163, 164, 164, 164, 164, 165, 165, 165, 165, 166, 166, 167, 167, 168, +168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 171, 172, 172, 173, 173, 174, +174, 175, 175, 176, 176, 176, 176, 177, 177, 177, 177, 178, 178, 178, 178, 179, +179, 179, 179, 180, 180, 180, 180, 181, 181, 181, 181, 182, 182, 182, 182, 183, +183, 183, 183, 184, 184, 184, 184, 185, 185, 185, 185, 186, 186, 186, 186, 187, +187, 187, 187, 188, 188, 188, 188, 189, 189, 189, 189, 190, 190, 190, 190, 191, +191, 191, 191, 192, 192, 192, 192, 193, 193, 193, 193, 194, 194, 194, 194, 195, +195, 195, 195, 196, 196, 196, 196, 197, 197, 197, 197, 198, 198, 198, 198, 199, +199, 199, 199, 200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 203, 203, +203, 203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 207, 207, +207, 207, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 212, 212, 212, 212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +216, 216, 216, 216, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, +226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228, +228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 230, 230, 230, +230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +233, 233, 233, 233, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 235, +235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c new file mode 100644 index 000000000000..5ff9d14ce710 --- /dev/null +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -0,0 +1,2268 @@ +/* + * ispccdc.c + * + * TI OMAP3 ISP - CCDC module + * + * Copyright (C) 2009-2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "ispccdc.h" + +static struct v4l2_mbus_framefmt * +__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which); + +static const unsigned int ccdc_fmts[] = { + V4L2_MBUS_FMT_Y8_1X8, + V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SGBRG10_1X10, + V4L2_MBUS_FMT_SGRBG12_1X12, + V4L2_MBUS_FMT_SRGGB12_1X12, + V4L2_MBUS_FMT_SBGGR12_1X12, + V4L2_MBUS_FMT_SGBRG12_1X12, +}; + +/* + * ccdc_print_status - Print current CCDC Module register values. + * @ccdc: Pointer to ISP CCDC device. + * + * Also prints other debug information stored in the CCDC module. + */ +#define CCDC_PRINT_REGISTER(isp, name)\ + dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \ + isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name)) + +static void ccdc_print_status(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + + dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n"); + + CCDC_PRINT_REGISTER(isp, PCR); + CCDC_PRINT_REGISTER(isp, SYN_MODE); + CCDC_PRINT_REGISTER(isp, HD_VD_WID); + CCDC_PRINT_REGISTER(isp, PIX_LINES); + CCDC_PRINT_REGISTER(isp, HORZ_INFO); + CCDC_PRINT_REGISTER(isp, VERT_START); + CCDC_PRINT_REGISTER(isp, VERT_LINES); + CCDC_PRINT_REGISTER(isp, CULLING); + CCDC_PRINT_REGISTER(isp, HSIZE_OFF); + CCDC_PRINT_REGISTER(isp, SDOFST); + CCDC_PRINT_REGISTER(isp, SDR_ADDR); + CCDC_PRINT_REGISTER(isp, CLAMP); + CCDC_PRINT_REGISTER(isp, DCSUB); + CCDC_PRINT_REGISTER(isp, COLPTN); + CCDC_PRINT_REGISTER(isp, BLKCMP); + CCDC_PRINT_REGISTER(isp, FPC); + CCDC_PRINT_REGISTER(isp, FPC_ADDR); + CCDC_PRINT_REGISTER(isp, VDINT); + CCDC_PRINT_REGISTER(isp, ALAW); + CCDC_PRINT_REGISTER(isp, REC656IF); + CCDC_PRINT_REGISTER(isp, CFG); + CCDC_PRINT_REGISTER(isp, FMTCFG); + CCDC_PRINT_REGISTER(isp, FMT_HORZ); + CCDC_PRINT_REGISTER(isp, FMT_VERT); + CCDC_PRINT_REGISTER(isp, PRGEVEN0); + CCDC_PRINT_REGISTER(isp, PRGEVEN1); + CCDC_PRINT_REGISTER(isp, PRGODD0); + CCDC_PRINT_REGISTER(isp, PRGODD1); + CCDC_PRINT_REGISTER(isp, VP_OUT); + CCDC_PRINT_REGISTER(isp, LSC_CONFIG); + CCDC_PRINT_REGISTER(isp, LSC_INITIAL); + CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE); + CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET); + + dev_dbg(isp->dev, "--------------------------------------------\n"); +} + +/* + * omap3isp_ccdc_busy - Get busy state of the CCDC. + * @ccdc: Pointer to ISP CCDC device. + */ +int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + + return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) & + ISPCCDC_PCR_BUSY; +} + +/* ----------------------------------------------------------------------------- + * Lens Shading Compensation + */ + +/* + * ccdc_lsc_validate_config - Check that LSC configuration is valid. + * @ccdc: Pointer to ISP CCDC device. + * @lsc_cfg: the LSC configuration to check. + * + * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid. + */ +static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc, + struct omap3isp_ccdc_lsc_config *lsc_cfg) +{ + struct isp_device *isp = to_isp_device(ccdc); + struct v4l2_mbus_framefmt *format; + unsigned int paxel_width, paxel_height; + unsigned int paxel_shift_x, paxel_shift_y; + unsigned int min_width, min_height, min_size; + unsigned int input_width, input_height; + + paxel_shift_x = lsc_cfg->gain_mode_m; + paxel_shift_y = lsc_cfg->gain_mode_n; + + if ((paxel_shift_x < 2) || (paxel_shift_x > 6) || + (paxel_shift_y < 2) || (paxel_shift_y > 6)) { + dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n"); + return -EINVAL; + } + + if (lsc_cfg->offset & 3) { + dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of " + "4\n"); + return -EINVAL; + } + + if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) { + dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n"); + return -EINVAL; + } + + format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + input_width = format->width; + input_height = format->height; + + /* Calculate minimum bytesize for validation */ + paxel_width = 1 << paxel_shift_x; + min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1) + >> paxel_shift_x) + 1; + + paxel_height = 1 << paxel_shift_y; + min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1) + >> paxel_shift_y) + 1; + + min_size = 4 * min_width * min_height; + if (min_size > lsc_cfg->size) { + dev_dbg(isp->dev, "CCDC: LSC: too small table\n"); + return -EINVAL; + } + if (lsc_cfg->offset < (min_width * 4)) { + dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n"); + return -EINVAL; + } + if ((lsc_cfg->size / lsc_cfg->offset) < min_height) { + dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n"); + return -EINVAL; + } + return 0; +} + +/* + * ccdc_lsc_program_table - Program Lens Shading Compensation table address. + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc, u32 addr) +{ + isp_reg_writel(to_isp_device(ccdc), addr, + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE); +} + +/* + * ccdc_lsc_setup_regs - Configures the lens shading compensation module + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc, + struct omap3isp_ccdc_lsc_config *cfg) +{ + struct isp_device *isp = to_isp_device(ccdc); + int reg; + + isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_LSC_TABLE_OFFSET); + + reg = 0; + reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT; + reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT; + reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT; + isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG); + + reg = 0; + reg &= ~ISPCCDC_LSC_INITIAL_X_MASK; + reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT; + reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK; + reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT; + isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_LSC_INITIAL); +} + +static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + unsigned int wait; + + isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ, + OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); + + /* timeout 1 ms */ + for (wait = 0; wait < 1000; wait++) { + if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) & + IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) { + isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ, + OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); + return 0; + } + + rmb(); + udelay(1); + } + + return -ETIMEDOUT; +} + +/* + * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module. + * @ccdc: Pointer to ISP CCDC device. + * @enable: 0 Disables LSC, 1 Enables LSC. + */ +static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable) +{ + struct isp_device *isp = to_isp_device(ccdc); + const struct v4l2_mbus_framefmt *format = + __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + + if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) && + (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) && + (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) && + (format->code != V4L2_MBUS_FMT_SGBRG10_1X10)) + return -EINVAL; + + if (enable) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ); + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, + ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0); + + if (enable) { + if (ccdc_lsc_wait_prefetch(ccdc) < 0) { + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE); + ccdc->lsc.state = LSC_STATE_STOPPED; + dev_warn(to_device(ccdc), "LSC prefecth timeout\n"); + return -ETIMEDOUT; + } + ccdc->lsc.state = LSC_STATE_RUNNING; + } else { + ccdc->lsc.state = LSC_STATE_STOPPING; + } + + return 0; +} + +static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + + return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) & + ISPCCDC_LSC_BUSY; +} + +/* __ccdc_lsc_configure - Apply a new configuration to the LSC engine + * @ccdc: Pointer to ISP CCDC device + * @req: New configuration request + * + * context: in_interrupt() + */ +static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc, + struct ispccdc_lsc_config_req *req) +{ + if (!req->enable) + return -EINVAL; + + if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) { + dev_dbg(to_device(ccdc), "Discard LSC configuration\n"); + return -EINVAL; + } + + if (ccdc_lsc_busy(ccdc)) + return -EBUSY; + + ccdc_lsc_setup_regs(ccdc, &req->config); + ccdc_lsc_program_table(ccdc, req->table); + return 0; +} + +/* + * ccdc_lsc_error_handler - Handle LSC prefetch error scenario. + * @ccdc: Pointer to ISP CCDC device. + * + * Disables LSC, and defers enablement to shadow registers update time. + */ +static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + /* + * From OMAP3 TRM: When this event is pending, the module + * goes into transparent mode (output =input). Normal + * operation can be resumed at the start of the next frame + * after: + * 1) Clearing this event + * 2) Disabling the LSC module + * 3) Enabling it + */ + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, + ISPCCDC_LSC_ENABLE); + ccdc->lsc.state = LSC_STATE_STOPPED; +} + +static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc, + struct ispccdc_lsc_config_req *req) +{ + struct isp_device *isp = to_isp_device(ccdc); + + if (req == NULL) + return; + + if (req->iovm) + dma_unmap_sg(isp->dev, req->iovm->sgt->sgl, + req->iovm->sgt->nents, DMA_TO_DEVICE); + if (req->table) + iommu_vfree(isp->iommu, req->table); + kfree(req); +} + +static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc, + struct list_head *queue) +{ + struct ispccdc_lsc_config_req *req, *n; + unsigned long flags; + + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); + list_for_each_entry_safe(req, n, queue, list) { + list_del(&req->list); + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); + ccdc_lsc_free_request(ccdc, req); + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); + } + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); +} + +static void ccdc_lsc_free_table_work(struct work_struct *work) +{ + struct isp_ccdc_device *ccdc; + struct ispccdc_lsc *lsc; + + lsc = container_of(work, struct ispccdc_lsc, table_work); + ccdc = container_of(lsc, struct isp_ccdc_device, lsc); + + ccdc_lsc_free_queue(ccdc, &lsc->free_queue); +} + +/* + * ccdc_lsc_config - Configure the LSC module from a userspace request + * + * Store the request LSC configuration in the LSC engine request pointer. The + * configuration will be applied to the hardware when the CCDC will be enabled, + * or at the next LSC interrupt if the CCDC is already running. + */ +static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, + struct omap3isp_ccdc_update_config *config) +{ + struct isp_device *isp = to_isp_device(ccdc); + struct ispccdc_lsc_config_req *req; + unsigned long flags; + void *table; + u16 update; + int ret; + + update = config->update & + (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC); + if (!update) + return 0; + + if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) { + dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table " + "need to be supplied\n", __func__); + return -EINVAL; + } + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (req == NULL) + return -ENOMEM; + + if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) { + if (copy_from_user(&req->config, config->lsc_cfg, + sizeof(req->config))) { + ret = -EFAULT; + goto done; + } + + req->enable = 1; + + req->table = iommu_vmalloc(isp->iommu, 0, req->config.size, + IOMMU_FLAG); + if (IS_ERR_VALUE(req->table)) { + req->table = 0; + ret = -ENOMEM; + goto done; + } + + req->iovm = find_iovm_area(isp->iommu, req->table); + if (req->iovm == NULL) { + ret = -ENOMEM; + goto done; + } + + if (!dma_map_sg(isp->dev, req->iovm->sgt->sgl, + req->iovm->sgt->nents, DMA_TO_DEVICE)) { + ret = -ENOMEM; + req->iovm = NULL; + goto done; + } + + dma_sync_sg_for_cpu(isp->dev, req->iovm->sgt->sgl, + req->iovm->sgt->nents, DMA_TO_DEVICE); + + table = da_to_va(isp->iommu, req->table); + if (copy_from_user(table, config->lsc, req->config.size)) { + ret = -EFAULT; + goto done; + } + + dma_sync_sg_for_device(isp->dev, req->iovm->sgt->sgl, + req->iovm->sgt->nents, DMA_TO_DEVICE); + } + + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); + if (ccdc->lsc.request) { + list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue); + schedule_work(&ccdc->lsc.table_work); + } + ccdc->lsc.request = req; + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); + + ret = 0; + +done: + if (ret < 0) + ccdc_lsc_free_request(ccdc, req); + + return ret; +} + +static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc) +{ + unsigned long flags; + + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); + if (ccdc->lsc.active) { + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); + return 1; + } + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); + return 0; +} + +static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc) +{ + struct ispccdc_lsc *lsc = &ccdc->lsc; + + if (lsc->state != LSC_STATE_STOPPED) + return -EINVAL; + + if (lsc->active) { + list_add_tail(&lsc->active->list, &lsc->free_queue); + lsc->active = NULL; + } + + if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) { + omap3isp_sbl_disable(to_isp_device(ccdc), + OMAP3_ISP_SBL_CCDC_LSC_READ); + list_add_tail(&lsc->request->list, &lsc->free_queue); + lsc->request = NULL; + goto done; + } + + lsc->active = lsc->request; + lsc->request = NULL; + __ccdc_lsc_enable(ccdc, 1); + +done: + if (!list_empty(&lsc->free_queue)) + schedule_work(&lsc->table_work); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Parameters configuration + */ + +/* + * ccdc_configure_clamp - Configure optical-black or digital clamping + * @ccdc: Pointer to ISP CCDC device. + * + * The CCDC performs either optical-black or digital clamp. Configure and enable + * the selected clamp method. + */ +static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + u32 clamp; + + if (ccdc->obclamp) { + clamp = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT; + clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT; + clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT; + clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT; + isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP); + } else { + isp_reg_writel(isp, ccdc->clamp.dcsubval, + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB); + } + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP, + ISPCCDC_CLAMP_CLAMPEN, + ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0); +} + +/* + * ccdc_configure_fpc - Configure Faulty Pixel Correction + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN); + + if (!ccdc->fpc_en) + return; + + isp_reg_writel(isp, ccdc->fpc.fpcaddr, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_FPC_ADDR); + /* The FPNUM field must be set before enabling FPC. */ + isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC); + isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) | + ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC); +} + +/* + * ccdc_configure_black_comp - Configure Black Level Compensation. + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + u32 blcomp; + + blcomp = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT; + blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT; + blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT; + blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT; + + isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP); +} + +/* + * ccdc_configure_lpf - Configure Low-Pass Filter (LPF). + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE, + ISPCCDC_SYN_MODE_LPF, + ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0); +} + +/* + * ccdc_configure_alaw - Configure A-law compression. + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + u32 alaw = 0; + + switch (ccdc->syncif.datsz) { + case 8: + return; + + case 10: + alaw = ISPCCDC_ALAW_GWDI_9_0; + break; + case 11: + alaw = ISPCCDC_ALAW_GWDI_10_1; + break; + case 12: + alaw = ISPCCDC_ALAW_GWDI_11_2; + break; + case 13: + alaw = ISPCCDC_ALAW_GWDI_12_3; + break; + } + + if (ccdc->alaw) + alaw |= ISPCCDC_ALAW_CCDTBL; + + isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW); +} + +/* + * ccdc_config_imgattr - Configure sensor image specific attributes. + * @ccdc: Pointer to ISP CCDC device. + * @colptn: Color pattern of the sensor. + */ +static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn) +{ + struct isp_device *isp = to_isp_device(ccdc); + + isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN); +} + +/* + * ccdc_config - Set CCDC configuration from userspace + * @ccdc: Pointer to ISP CCDC device. + * @userspace_add: Structure containing CCDC configuration sent from userspace. + * + * Returns 0 if successful, -EINVAL if the pointer to the configuration + * structure is null, or the copy_from_user function fails to copy user space + * memory to kernel space memory. + */ +static int ccdc_config(struct isp_ccdc_device *ccdc, + struct omap3isp_ccdc_update_config *ccdc_struct) +{ + struct isp_device *isp = to_isp_device(ccdc); + unsigned long flags; + + spin_lock_irqsave(&ccdc->lock, flags); + ccdc->shadow_update = 1; + spin_unlock_irqrestore(&ccdc->lock, flags); + + if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) { + ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag); + ccdc->update |= OMAP3ISP_CCDC_ALAW; + } + + if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) { + ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag); + ccdc->update |= OMAP3ISP_CCDC_LPF; + } + + if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) { + if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp, + sizeof(ccdc->clamp))) { + ccdc->shadow_update = 0; + return -EFAULT; + } + + ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag); + ccdc->update |= OMAP3ISP_CCDC_BLCLAMP; + } + + if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) { + if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp, + sizeof(ccdc->blcomp))) { + ccdc->shadow_update = 0; + return -EFAULT; + } + + ccdc->update |= OMAP3ISP_CCDC_BCOMP; + } + + ccdc->shadow_update = 0; + + if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) { + u32 table_old = 0; + u32 table_new; + u32 size; + + if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED) + return -EBUSY; + + ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag); + + if (ccdc->fpc_en) { + if (copy_from_user(&ccdc->fpc, ccdc_struct->fpc, + sizeof(ccdc->fpc))) + return -EFAULT; + + /* + * table_new must be 64-bytes aligned, but it's + * already done by iommu_vmalloc(). + */ + size = ccdc->fpc.fpnum * 4; + table_new = iommu_vmalloc(isp->iommu, 0, size, + IOMMU_FLAG); + if (IS_ERR_VALUE(table_new)) + return -ENOMEM; + + if (copy_from_user(da_to_va(isp->iommu, table_new), + (__force void __user *) + ccdc->fpc.fpcaddr, size)) { + iommu_vfree(isp->iommu, table_new); + return -EFAULT; + } + + table_old = ccdc->fpc.fpcaddr; + ccdc->fpc.fpcaddr = table_new; + } + + ccdc_configure_fpc(ccdc); + if (table_old != 0) + iommu_vfree(isp->iommu, table_old); + } + + return ccdc_lsc_config(ccdc, ccdc_struct); +} + +static void ccdc_apply_controls(struct isp_ccdc_device *ccdc) +{ + if (ccdc->update & OMAP3ISP_CCDC_ALAW) { + ccdc_configure_alaw(ccdc); + ccdc->update &= ~OMAP3ISP_CCDC_ALAW; + } + + if (ccdc->update & OMAP3ISP_CCDC_LPF) { + ccdc_configure_lpf(ccdc); + ccdc->update &= ~OMAP3ISP_CCDC_LPF; + } + + if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) { + ccdc_configure_clamp(ccdc); + ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP; + } + + if (ccdc->update & OMAP3ISP_CCDC_BCOMP) { + ccdc_configure_black_comp(ccdc); + ccdc->update &= ~OMAP3ISP_CCDC_BCOMP; + } +} + +/* + * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers + * @dev: Pointer to ISP device + */ +void omap3isp_ccdc_restore_context(struct isp_device *isp) +{ + struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC); + + ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF + | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP; + ccdc_apply_controls(ccdc); + ccdc_configure_fpc(ccdc); +} + +/* ----------------------------------------------------------------------------- + * Format- and pipeline-related configuration helpers + */ + +/* + * ccdc_config_vp - Configure the Video Port. + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_config_vp(struct isp_ccdc_device *ccdc) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + struct isp_device *isp = to_isp_device(ccdc); + unsigned long l3_ick = pipe->l3_ick; + unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8; + unsigned int div = 0; + u32 fmtcfg_vp; + + fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG) + & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK); + + switch (ccdc->syncif.datsz) { + case 8: + case 10: + fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0; + break; + case 11: + fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1; + break; + case 12: + fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2; + break; + case 13: + fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3; + break; + }; + + if (pipe->input) + div = DIV_ROUND_UP(l3_ick, pipe->max_rate); + else if (ccdc->vpcfg.pixelclk) + div = l3_ick / ccdc->vpcfg.pixelclk; + + div = clamp(div, 2U, max_div); + fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT; + + isp_reg_writel(isp, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG); +} + +/* + * ccdc_enable_vp - Enable Video Port. + * @ccdc: Pointer to ISP CCDC device. + * @enable: 0 Disables VP, 1 Enables VP + * + * This is needed for outputting image to Preview, H3A and HIST ISP submodules. + */ +static void ccdc_enable_vp(struct isp_ccdc_device *ccdc, u8 enable) +{ + struct isp_device *isp = to_isp_device(ccdc); + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG, + ISPCCDC_FMTCFG_VPEN, enable ? ISPCCDC_FMTCFG_VPEN : 0); +} + +/* + * ccdc_config_outlineoffset - Configure memory saving output line offset + * @ccdc: Pointer to ISP CCDC device. + * @offset: Address offset to start a new line. Must be twice the + * Output width and aligned on 32 byte boundary + * @oddeven: Specifies the odd/even line pattern to be chosen to store the + * output. + * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines. + * + * - Configures the output line offset when stored in memory + * - Sets the odd/even line pattern to store the output + * (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4)) + * - Configures the number of even and odd line fields in case of rearranging + * the lines. + */ +static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc, + u32 offset, u8 oddeven, u8 numlines) +{ + struct isp_device *isp = to_isp_device(ccdc); + + isp_reg_writel(isp, offset & 0xffff, + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF); + + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, + ISPCCDC_SDOFST_FINV); + + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, + ISPCCDC_SDOFST_FOFST_4L); + + switch (oddeven) { + case EVENEVEN: + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, + (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT); + break; + case ODDEVEN: + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, + (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT); + break; + case EVENODD: + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, + (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT); + break; + case ODDODD: + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST, + (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT); + break; + default: + break; + } +} + +/* + * ccdc_set_outaddr - Set memory address to save output image + * @ccdc: Pointer to ISP CCDC device. + * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. + * + * Sets the memory address where the output will be saved. + */ +static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr) +{ + struct isp_device *isp = to_isp_device(ccdc); + + isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR); +} + +/* + * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input + * @ccdc: Pointer to ISP CCDC device. + * @max_rate: Maximum calculated data rate. + * + * Returns in *max_rate less value between calculated and passed + */ +void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, + unsigned int *max_rate) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + unsigned int rate; + + if (pipe == NULL) + return; + + /* + * TRM says that for parallel sensors the maximum data rate + * should be 90% form L3/2 clock, otherwise just L3/2. + */ + if (ccdc->input == CCDC_INPUT_PARALLEL) + rate = pipe->l3_ick / 2 * 9 / 10; + else + rate = pipe->l3_ick / 2; + + *max_rate = min(*max_rate, rate); +} + +/* + * ccdc_config_sync_if - Set CCDC sync interface configuration + * @ccdc: Pointer to ISP CCDC device. + * @syncif: Structure containing the sync parameters like field state, CCDC in + * master/slave mode, raw/yuv data, polarity of data, field, hs, vs + * signals. + */ +static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc, + struct ispccdc_syncif *syncif) +{ + struct isp_device *isp = to_isp_device(ccdc); + u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_SYN_MODE); + + syn_mode |= ISPCCDC_SYN_MODE_VDHDEN; + + if (syncif->fldstat) + syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT; + else + syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT; + + syn_mode &= ~ISPCCDC_SYN_MODE_DATSIZ_MASK; + switch (syncif->datsz) { + case 8: + syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8; + break; + case 10: + syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10; + break; + case 11: + syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11; + break; + case 12: + syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12; + break; + }; + + if (syncif->fldmode) + syn_mode |= ISPCCDC_SYN_MODE_FLDMODE; + else + syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE; + + if (syncif->datapol) + syn_mode |= ISPCCDC_SYN_MODE_DATAPOL; + else + syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL; + + if (syncif->fldpol) + syn_mode |= ISPCCDC_SYN_MODE_FLDPOL; + else + syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL; + + if (syncif->hdpol) + syn_mode |= ISPCCDC_SYN_MODE_HDPOL; + else + syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL; + + if (syncif->vdpol) + syn_mode |= ISPCCDC_SYN_MODE_VDPOL; + else + syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL; + + if (syncif->ccdc_mastermode) { + syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT; + isp_reg_writel(isp, + syncif->hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT + | syncif->vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT, + OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_HD_VD_WID); + + isp_reg_writel(isp, + syncif->ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT + | syncif->hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT, + OMAP3_ISP_IOMEM_CCDC, + ISPCCDC_PIX_LINES); + } else + syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT | + ISPCCDC_SYN_MODE_VDHDOUT); + + isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); + + if (!syncif->bt_r656_en) + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, + ISPCCDC_REC656IF_R656ON); +} + +/* CCDC formats descriptions */ +static const u32 ccdc_sgrbg_pattern = + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT; + +static const u32 ccdc_srggb_pattern = + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC0_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC2_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC0_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC1_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC2_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC3_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC0_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC2_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC0_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC1_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC2_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC3_SHIFT; + +static const u32 ccdc_sbggr_pattern = + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC0_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC1_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC2_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC3_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC1_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC3_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC0_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC1_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC2_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC3_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC1_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC3_SHIFT; + +static const u32 ccdc_sgbrg_pattern = + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC0_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC1_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC2_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC3_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC0_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC2_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC0_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC1_SHIFT | + ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC2_SHIFT | + ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC3_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC0_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT | + ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC2_SHIFT | + ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT; + +static void ccdc_configure(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + struct isp_parallel_platform_data *pdata = NULL; + struct v4l2_subdev *sensor; + struct v4l2_mbus_framefmt *format; + struct media_pad *pad; + unsigned long flags; + u32 syn_mode; + u32 ccdc_pattern; + + if (ccdc->input == CCDC_INPUT_PARALLEL) { + pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); + sensor = media_entity_to_v4l2_subdev(pad->entity); + pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) + ->bus.parallel; + } + + omap3isp_configure_bridge(isp, ccdc->input, pdata); + + ccdc->syncif.datsz = pdata ? pdata->width : 10; + ccdc_config_sync_if(ccdc, &ccdc->syncif); + + /* CCDC_PAD_SINK */ + format = &ccdc->formats[CCDC_PAD_SINK]; + + syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); + + /* Use the raw, unprocessed data when writing to memory. The H3A and + * histogram modules are still fed with lens shading corrected data. + */ + syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR; + + if (ccdc->output & CCDC_OUTPUT_MEMORY) + syn_mode |= ISPCCDC_SYN_MODE_WEN; + else + syn_mode &= ~ISPCCDC_SYN_MODE_WEN; + + if (ccdc->output & CCDC_OUTPUT_RESIZER) + syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ; + else + syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ; + + /* Use PACK8 mode for 1byte per pixel formats. */ + if (omap3isp_video_format_info(format->code)->bpp <= 8) + syn_mode |= ISPCCDC_SYN_MODE_PACK8; + else + syn_mode &= ~ISPCCDC_SYN_MODE_PACK8; + + isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE); + + /* Mosaic filter */ + switch (format->code) { + case V4L2_MBUS_FMT_SRGGB10_1X10: + case V4L2_MBUS_FMT_SRGGB12_1X12: + ccdc_pattern = ccdc_srggb_pattern; + break; + case V4L2_MBUS_FMT_SBGGR10_1X10: + case V4L2_MBUS_FMT_SBGGR12_1X12: + ccdc_pattern = ccdc_sbggr_pattern; + break; + case V4L2_MBUS_FMT_SGBRG10_1X10: + case V4L2_MBUS_FMT_SGBRG12_1X12: + ccdc_pattern = ccdc_sgbrg_pattern; + break; + default: + /* Use GRBG */ + ccdc_pattern = ccdc_sgrbg_pattern; + break; + } + ccdc_config_imgattr(ccdc, ccdc_pattern); + + /* Generate VD0 on the last line of the image and VD1 on the + * 2/3 height line. + */ + isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) | + ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT); + + /* CCDC_PAD_SOURCE_OF */ + format = &ccdc->formats[CCDC_PAD_SOURCE_OF]; + + isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) | + ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO); + isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT, + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START); + isp_reg_writel(isp, (format->height - 1) + << ISPCCDC_VERT_LINES_NLV_SHIFT, + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES); + + ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0); + + /* CCDC_PAD_SOURCE_VP */ + format = &ccdc->formats[CCDC_PAD_SOURCE_VP]; + + isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) | + (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ); + isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) | + ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT); + + isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) | + (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT), + OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT); + + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); + if (ccdc->lsc.request == NULL) + goto unlock; + + WARN_ON(ccdc->lsc.active); + + /* Get last good LSC configuration. If it is not supported for + * the current active resolution discard it. + */ + if (ccdc->lsc.active == NULL && + __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) { + ccdc->lsc.active = ccdc->lsc.request; + } else { + list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue); + schedule_work(&ccdc->lsc.table_work); + } + + ccdc->lsc.request = NULL; + +unlock: + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); + + ccdc_apply_controls(ccdc); +} + +static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable) +{ + struct isp_device *isp = to_isp_device(ccdc); + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR, + ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0); +} + +static int ccdc_disable(struct isp_ccdc_device *ccdc) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&ccdc->lock, flags); + if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS) + ccdc->stopping = CCDC_STOP_REQUEST; + spin_unlock_irqrestore(&ccdc->lock, flags); + + ret = wait_event_timeout(ccdc->wait, + ccdc->stopping == CCDC_STOP_FINISHED, + msecs_to_jiffies(2000)); + if (ret == 0) { + ret = -ETIMEDOUT; + dev_warn(to_device(ccdc), "CCDC stop timeout!\n"); + } + + omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ); + + mutex_lock(&ccdc->ioctl_lock); + ccdc_lsc_free_request(ccdc, ccdc->lsc.request); + ccdc->lsc.request = ccdc->lsc.active; + ccdc->lsc.active = NULL; + cancel_work_sync(&ccdc->lsc.table_work); + ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue); + mutex_unlock(&ccdc->ioctl_lock); + + ccdc->stopping = CCDC_STOP_NOT_REQUESTED; + + return ret > 0 ? 0 : ret; +} + +static void ccdc_enable(struct isp_ccdc_device *ccdc) +{ + if (ccdc_lsc_is_configured(ccdc)) + __ccdc_lsc_enable(ccdc, 1); + __ccdc_enable(ccdc, 1); +} + +/* ----------------------------------------------------------------------------- + * Interrupt handling + */ + +/* + * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits + * @ccdc: Pointer to ISP CCDC device. + * + * Returns zero if the CCDC is idle and the image has been written to + * memory, too. + */ +static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc) +{ + struct isp_device *isp = to_isp_device(ccdc); + + return omap3isp_ccdc_busy(ccdc) + | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) & + ISPSBL_CCDC_WR_0_DATA_READY) + | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) & + ISPSBL_CCDC_WR_0_DATA_READY) + | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) & + ISPSBL_CCDC_WR_0_DATA_READY) + | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) & + ISPSBL_CCDC_WR_0_DATA_READY); +} + +/* + * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle + * @ccdc: Pointer to ISP CCDC device. + * @max_wait: Max retry count in us for wait for idle/busy transition. + */ +static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, + unsigned int max_wait) +{ + unsigned int wait = 0; + + if (max_wait == 0) + max_wait = 10000; /* 10 ms */ + + for (wait = 0; wait <= max_wait; wait++) { + if (!ccdc_sbl_busy(ccdc)) + return 0; + + rmb(); + udelay(1); + } + + return -EBUSY; +} + +/* __ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence + * @ccdc: Pointer to ISP CCDC device. + * @event: Pointing which event trigger handler + * + * Return 1 when the event and stopping request combination is satisfyied, + * zero otherwise. + */ +static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) +{ + int rval = 0; + + switch ((ccdc->stopping & 3) | event) { + case CCDC_STOP_REQUEST | CCDC_EVENT_VD1: + if (ccdc->lsc.state != LSC_STATE_STOPPED) + __ccdc_lsc_enable(ccdc, 0); + __ccdc_enable(ccdc, 0); + ccdc->stopping = CCDC_STOP_EXECUTED; + return 1; + + case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0: + ccdc->stopping |= CCDC_STOP_CCDC_FINISHED; + if (ccdc->lsc.state == LSC_STATE_STOPPED) + ccdc->stopping |= CCDC_STOP_LSC_FINISHED; + rval = 1; + break; + + case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE: + ccdc->stopping |= CCDC_STOP_LSC_FINISHED; + rval = 1; + break; + + case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1: + return 1; + } + + if (ccdc->stopping == CCDC_STOP_FINISHED) { + wake_up(&ccdc->wait); + rval = 1; + } + + return rval; +} + +static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) +{ + struct video_device *vdev = &ccdc->subdev.devnode; + struct v4l2_event event; + + memset(&event, 0, sizeof(event)); + event.type = V4L2_EVENT_OMAP3ISP_HS_VS; + + v4l2_event_queue(vdev, &event); +} + +/* + * ccdc_lsc_isr - Handle LSC events + * @ccdc: Pointer to ISP CCDC device. + * @events: LSC events + */ +static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events) +{ + unsigned long flags; + + if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) { + ccdc_lsc_error_handler(ccdc); + ccdc->error = 1; + dev_dbg(to_device(ccdc), "lsc prefetch error\n"); + } + + if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ)) + return; + + /* LSC_DONE interrupt occur, there are two cases + * 1. stopping for reconfiguration + * 2. stopping because of STREAM OFF command + */ + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); + + if (ccdc->lsc.state == LSC_STATE_STOPPING) + ccdc->lsc.state = LSC_STATE_STOPPED; + + if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE)) + goto done; + + if (ccdc->lsc.state != LSC_STATE_RECONFIG) + goto done; + + /* LSC is in STOPPING state, change to the new state */ + ccdc->lsc.state = LSC_STATE_STOPPED; + + /* This is an exception. Start of frame and LSC_DONE interrupt + * have been received on the same time. Skip this event and wait + * for better times. + */ + if (events & IRQ0STATUS_HS_VS_IRQ) + goto done; + + /* The LSC engine is stopped at this point. Enable it if there's a + * pending request. + */ + if (ccdc->lsc.request == NULL) + goto done; + + ccdc_lsc_enable(ccdc); + +done: + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); +} + +static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity); + struct isp_device *isp = to_isp_device(ccdc); + struct isp_buffer *buffer; + int restart = 0; + + /* The CCDC generates VD0 interrupts even when disabled (the datasheet + * doesn't explicitly state if that's supposed to happen or not, so it + * can be considered as a hardware bug or as a feature, but we have to + * deal with it anyway). Disabling the CCDC when no buffer is available + * would thus not be enough, we need to handle the situation explicitly. + */ + if (list_empty(&ccdc->video_out.dmaqueue)) + goto done; + + /* We're in continuous mode, and memory writes were disabled due to a + * buffer underrun. Reenable them now that we have a buffer. The buffer + * address has been set in ccdc_video_queue. + */ + if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) { + restart = 1; + ccdc->underrun = 0; + goto done; + } + + if (ccdc_sbl_wait_idle(ccdc, 1000)) { + dev_info(isp->dev, "CCDC won't become idle!\n"); + goto done; + } + + buffer = omap3isp_video_buffer_next(&ccdc->video_out, ccdc->error); + if (buffer != NULL) { + ccdc_set_outaddr(ccdc, buffer->isp_addr); + restart = 1; + } + + pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; + + if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT && + isp_pipeline_ready(pipe)) + omap3isp_pipeline_set_stream(pipe, + ISP_PIPELINE_STREAM_SINGLESHOT); + +done: + ccdc->error = 0; + return restart; +} + +/* + * ccdc_vd0_isr - Handle VD0 event + * @ccdc: Pointer to ISP CCDC device. + * + * Executes LSC deferred enablement before next frame starts. + */ +static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc) +{ + unsigned long flags; + int restart = 0; + + if (ccdc->output & CCDC_OUTPUT_MEMORY) + restart = ccdc_isr_buffer(ccdc); + + spin_lock_irqsave(&ccdc->lock, flags); + if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) { + spin_unlock_irqrestore(&ccdc->lock, flags); + return; + } + + if (!ccdc->shadow_update) + ccdc_apply_controls(ccdc); + spin_unlock_irqrestore(&ccdc->lock, flags); + + if (restart) + ccdc_enable(ccdc); +} + +/* + * ccdc_vd1_isr - Handle VD1 event + * @ccdc: Pointer to ISP CCDC device. + */ +static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc) +{ + unsigned long flags; + + spin_lock_irqsave(&ccdc->lsc.req_lock, flags); + + /* + * Depending on the CCDC pipeline state, CCDC stopping should be + * handled differently. In SINGLESHOT we emulate an internal CCDC + * stopping because the CCDC hw works only in continuous mode. + * When CONTINUOUS pipeline state is used and the CCDC writes it's + * data to memory the CCDC and LSC are stopped immediately but + * without change the CCDC stopping state machine. The CCDC + * stopping state machine should be used only when user request + * for stopping is received (SINGLESHOT is an exeption). + */ + switch (ccdc->state) { + case ISP_PIPELINE_STREAM_SINGLESHOT: + ccdc->stopping = CCDC_STOP_REQUEST; + break; + + case ISP_PIPELINE_STREAM_CONTINUOUS: + if (ccdc->output & CCDC_OUTPUT_MEMORY) { + if (ccdc->lsc.state != LSC_STATE_STOPPED) + __ccdc_lsc_enable(ccdc, 0); + __ccdc_enable(ccdc, 0); + } + break; + + case ISP_PIPELINE_STREAM_STOPPED: + break; + } + + if (__ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1)) + goto done; + + if (ccdc->lsc.request == NULL) + goto done; + + /* + * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ + * do the appropriate changes in registers + */ + if (ccdc->lsc.state == LSC_STATE_RUNNING) { + __ccdc_lsc_enable(ccdc, 0); + ccdc->lsc.state = LSC_STATE_RECONFIG; + goto done; + } + + /* LSC has been in STOPPED state, enable it */ + if (ccdc->lsc.state == LSC_STATE_STOPPED) + ccdc_lsc_enable(ccdc); + +done: + spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags); +} + +/* + * omap3isp_ccdc_isr - Configure CCDC during interframe time. + * @ccdc: Pointer to ISP CCDC device. + * @events: CCDC events + */ +int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events) +{ + if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) + return 0; + + if (events & IRQ0STATUS_CCDC_VD1_IRQ) + ccdc_vd1_isr(ccdc); + + ccdc_lsc_isr(ccdc, events); + + if (events & IRQ0STATUS_CCDC_VD0_IRQ) + ccdc_vd0_isr(ccdc); + + if (events & IRQ0STATUS_HS_VS_IRQ) + ccdc_hs_vs_isr(ccdc); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * ISP video operations + */ + +static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) +{ + struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc; + + if (!(ccdc->output & CCDC_OUTPUT_MEMORY)) + return -ENODEV; + + ccdc_set_outaddr(ccdc, buffer->isp_addr); + + /* We now have a buffer queued on the output, restart the pipeline in + * on the next CCDC interrupt if running in continuous mode (or when + * starting the stream). + */ + ccdc->underrun = 1; + + return 0; +} + +static const struct isp_video_operations ccdc_video_ops = { + .queue = ccdc_video_queue, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +/* + * ccdc_ioctl - CCDC module private ioctl's + * @sd: ISP CCDC V4L2 subdevice + * @cmd: ioctl command + * @arg: ioctl argument + * + * Return 0 on success or a negative error code otherwise. + */ +static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); + int ret; + + switch (cmd) { + case VIDIOC_OMAP3ISP_CCDC_CFG: + mutex_lock(&ccdc->ioctl_lock); + ret = ccdc_config(ccdc, arg); + mutex_unlock(&ccdc->ioctl_lock); + break; + + default: + return -ENOIOCTLCMD; + } + + return ret; +} + +static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + if (sub->type != V4L2_EVENT_OMAP3ISP_HS_VS) + return -EINVAL; + + return v4l2_event_subscribe(fh, sub); +} + +static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +/* + * ccdc_set_stream - Enable/Disable streaming on the CCDC module + * @sd: ISP CCDC V4L2 subdevice + * @enable: Enable/disable stream + * + * When writing to memory, the CCDC hardware can't be enabled without a memory + * buffer to write to. As the s_stream operation is called in response to a + * STREAMON call without any buffer queued yet, just update the enabled field + * and return immediately. The CCDC will be enabled in ccdc_isr_buffer(). + * + * When not writing to memory enable the CCDC immediately. + */ +static int ccdc_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); + struct isp_device *isp = to_isp_device(ccdc); + int ret = 0; + + if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) { + if (enable == ISP_PIPELINE_STREAM_STOPPED) + return 0; + + omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC); + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, + ISPCCDC_CFG_VDLC); + + ccdc_configure(ccdc); + + /* TODO: Don't configure the video port if all of its output + * links are inactive. + */ + ccdc_config_vp(ccdc); + ccdc_enable_vp(ccdc, 1); + ccdc->error = 0; + ccdc_print_status(ccdc); + } + + switch (enable) { + case ISP_PIPELINE_STREAM_CONTINUOUS: + if (ccdc->output & CCDC_OUTPUT_MEMORY) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE); + + if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY)) + ccdc_enable(ccdc); + + ccdc->underrun = 0; + break; + + case ISP_PIPELINE_STREAM_SINGLESHOT: + if (ccdc->output & CCDC_OUTPUT_MEMORY && + ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE); + + ccdc_enable(ccdc); + break; + + case ISP_PIPELINE_STREAM_STOPPED: + ret = ccdc_disable(ccdc); + if (ccdc->output & CCDC_OUTPUT_MEMORY) + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE); + omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC); + ccdc->underrun = 0; + break; + } + + ccdc->state = enable; + return ret; +} + +static struct v4l2_mbus_framefmt * +__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(fh, pad); + else + return &ccdc->formats[pad]; +} + +/* + * ccdc_try_format - Try video format on a pad + * @ccdc: ISP CCDC device + * @fh : V4L2 subdev file handle + * @pad: Pad number + * @fmt: Format + */ +static void +ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, + unsigned int pad, struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + const struct isp_format_info *info; + unsigned int width = fmt->width; + unsigned int height = fmt->height; + unsigned int i; + + switch (pad) { + case CCDC_PAD_SINK: + /* TODO: If the CCDC output formatter pad is connected directly + * to the resizer, only YUV formats can be used. + */ + for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) { + if (fmt->code == ccdc_fmts[i]) + break; + } + + /* If not found, use SGRBG10 as default */ + if (i >= ARRAY_SIZE(ccdc_fmts)) + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + + /* Clamp the input size. */ + fmt->width = clamp_t(u32, width, 32, 4096); + fmt->height = clamp_t(u32, height, 32, 4096); + break; + + case CCDC_PAD_SOURCE_OF: + format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + + /* The data formatter truncates the number of horizontal output + * pixels to a multiple of 16. To avoid clipping data, allow + * callers to request an output size bigger than the input size + * up to the nearest multiple of 16. + */ + fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15); + fmt->width &= ~15; + fmt->height = clamp_t(u32, height, 32, fmt->height); + break; + + case CCDC_PAD_SOURCE_VP: + format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + + /* The video port interface truncates the data to 10 bits. */ + info = omap3isp_video_format_info(fmt->code); + fmt->code = info->truncated; + + /* The number of lines that can be clocked out from the video + * port output must be at least one line less than the number + * of input lines. + */ + fmt->width = clamp_t(u32, width, 32, fmt->width); + fmt->height = clamp_t(u32, height, 32, fmt->height - 1); + break; + } + + /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is + * stored on 2 bytes. + */ + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->field = V4L2_FIELD_NONE; +} + +/* + * ccdc_enum_mbus_code - Handle pixel format enumeration + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @code : pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int ccdc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + switch (code->pad) { + case CCDC_PAD_SINK: + if (code->index >= ARRAY_SIZE(ccdc_fmts)) + return -EINVAL; + + code->code = ccdc_fmts[code->index]; + break; + + case CCDC_PAD_SOURCE_OF: + case CCDC_PAD_SOURCE_VP: + /* No format conversion inside CCDC */ + if (code->index != 0) + return -EINVAL; + + format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, + V4L2_SUBDEV_FORMAT_TRY); + + code->code = format->code; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int ccdc_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + ccdc_try_format(ccdc, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * ccdc_get_format - Retrieve the video format on a pad + * @sd : ISP CCDC V4L2 subdevice + * @fh : V4L2 subdev file handle + * @fmt: Format + * + * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond + * to the format type. + */ +static int ccdc_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + return 0; +} + +/* + * ccdc_set_format - Set the video format on a pad + * @sd : ISP CCDC V4L2 subdevice + * @fh : V4L2 subdev file handle + * @fmt: Format + * + * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond + * to the format type. + */ +static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + ccdc_try_format(ccdc, fh, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == CCDC_PAD_SINK) { + format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, + fmt->which); + *format = fmt->format; + ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, + fmt->which); + + format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_VP, + fmt->which); + *format = fmt->format; + ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_VP, format, + fmt->which); + } + + return 0; +} + +/* + * ccdc_init_formats - Initialize formats on all pads + * @sd: ISP CCDC V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. If fh is not NULL, try + * formats are initialized on the file handle. Otherwise active formats are + * initialized on the device. + */ +static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format; + + memset(&format, 0, sizeof(format)); + format.pad = CCDC_PAD_SINK; + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.width = 4096; + format.format.height = 4096; + ccdc_set_format(sd, fh, &format); + + return 0; +} + +/* V4L2 subdev core operations */ +static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = { + .ioctl = ccdc_ioctl, + .subscribe_event = ccdc_subscribe_event, + .unsubscribe_event = ccdc_unsubscribe_event, +}; + +/* V4L2 subdev video operations */ +static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = { + .s_stream = ccdc_set_stream, +}; + +/* V4L2 subdev pad operations */ +static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = { + .enum_mbus_code = ccdc_enum_mbus_code, + .enum_frame_size = ccdc_enum_frame_size, + .get_fmt = ccdc_get_format, + .set_fmt = ccdc_set_format, +}; + +/* V4L2 subdev operations */ +static const struct v4l2_subdev_ops ccdc_v4l2_ops = { + .core = &ccdc_v4l2_core_ops, + .video = &ccdc_v4l2_video_ops, + .pad = &ccdc_v4l2_pad_ops, +}; + +/* V4L2 subdev internal operations */ +static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = { + .open = ccdc_init_formats, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +/* + * ccdc_link_setup - Setup CCDC connections + * @entity: CCDC media entity + * @local: Pad at the local end of the link + * @remote: Pad at the remote end of the link + * @flags: Link flags + * + * return -EINVAL or zero on success + */ +static int ccdc_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd); + struct isp_device *isp = to_isp_device(ccdc); + + switch (local->index | media_entity_type(remote->entity)) { + case CCDC_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + /* Read from the sensor (parallel interface), CCP2, CSI2a or + * CSI2c. + */ + if (!(flags & MEDIA_LNK_FL_ENABLED)) { + ccdc->input = CCDC_INPUT_NONE; + break; + } + + if (ccdc->input != CCDC_INPUT_NONE) + return -EBUSY; + + if (remote->entity == &isp->isp_ccp2.subdev.entity) + ccdc->input = CCDC_INPUT_CCP2B; + else if (remote->entity == &isp->isp_csi2a.subdev.entity) + ccdc->input = CCDC_INPUT_CSI2A; + else if (remote->entity == &isp->isp_csi2c.subdev.entity) + ccdc->input = CCDC_INPUT_CSI2C; + else + ccdc->input = CCDC_INPUT_PARALLEL; + + break; + + /* + * The ISP core doesn't support pipelines with multiple video outputs. + * Revisit this when it will be implemented, and return -EBUSY for now. + */ + + case CCDC_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV: + /* Write to preview engine, histogram and H3A. When none of + * those links are active, the video port can be disabled. + */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (ccdc->output & ~CCDC_OUTPUT_PREVIEW) + return -EBUSY; + ccdc->output |= CCDC_OUTPUT_PREVIEW; + } else { + ccdc->output &= ~CCDC_OUTPUT_PREVIEW; + } + break; + + case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_DEVNODE: + /* Write to memory */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (ccdc->output & ~CCDC_OUTPUT_MEMORY) + return -EBUSY; + ccdc->output |= CCDC_OUTPUT_MEMORY; + } else { + ccdc->output &= ~CCDC_OUTPUT_MEMORY; + } + break; + + case CCDC_PAD_SOURCE_OF | MEDIA_ENT_T_V4L2_SUBDEV: + /* Write to resizer */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (ccdc->output & ~CCDC_OUTPUT_RESIZER) + return -EBUSY; + ccdc->output |= CCDC_OUTPUT_RESIZER; + } else { + ccdc->output &= ~CCDC_OUTPUT_RESIZER; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* media operations */ +static const struct media_entity_operations ccdc_media_ops = { + .link_setup = ccdc_link_setup, +}; + +/* + * ccdc_init_entities - Initialize V4L2 subdev and media entity + * @ccdc: ISP CCDC module + * + * Return 0 on success and a negative error code on failure. + */ +static int ccdc_init_entities(struct isp_ccdc_device *ccdc) +{ + struct v4l2_subdev *sd = &ccdc->subdev; + struct media_pad *pads = ccdc->pads; + struct media_entity *me = &sd->entity; + int ret; + + ccdc->input = CCDC_INPUT_NONE; + + v4l2_subdev_init(sd, &ccdc_v4l2_ops); + sd->internal_ops = &ccdc_v4l2_internal_ops; + strlcpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name)); + sd->grp_id = 1 << 16; /* group ID for isp subdevs */ + v4l2_set_subdevdata(sd, ccdc); + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->nevents = OMAP3ISP_CCDC_NEVENTS; + + pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE; + pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE; + + me->ops = &ccdc_media_ops; + ret = media_entity_init(me, CCDC_PADS_NUM, pads, 0); + if (ret < 0) + return ret; + + ccdc_init_formats(sd, NULL); + + ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ccdc->video_out.ops = &ccdc_video_ops; + ccdc->video_out.isp = to_isp_device(ccdc); + ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; + ccdc->video_out.bpl_alignment = 32; + + ret = omap3isp_video_init(&ccdc->video_out, "CCDC"); + if (ret < 0) + return ret; + + /* Connect the CCDC subdev to the video node. */ + ret = media_entity_create_link(&ccdc->subdev.entity, CCDC_PAD_SOURCE_OF, + &ccdc->video_out.video.entity, 0, 0); + if (ret < 0) + return ret; + + return 0; +} + +void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc) +{ + media_entity_cleanup(&ccdc->subdev.entity); + + v4l2_device_unregister_subdev(&ccdc->subdev); + omap3isp_video_unregister(&ccdc->video_out); +} + +int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video node. */ + ret = v4l2_device_register_subdev(vdev, &ccdc->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&ccdc->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_ccdc_unregister_entities(ccdc); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP CCDC initialisation and cleanup + */ + +/* + * omap3isp_ccdc_init - CCDC module initialization. + * @dev: Device pointer specific to the OMAP3 ISP. + * + * TODO: Get the initialisation values from platform data. + * + * Return 0 on success or a negative error code otherwise. + */ +int omap3isp_ccdc_init(struct isp_device *isp) +{ + struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + + spin_lock_init(&ccdc->lock); + init_waitqueue_head(&ccdc->wait); + mutex_init(&ccdc->ioctl_lock); + + ccdc->stopping = CCDC_STOP_NOT_REQUESTED; + + INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work); + ccdc->lsc.state = LSC_STATE_STOPPED; + INIT_LIST_HEAD(&ccdc->lsc.free_queue); + spin_lock_init(&ccdc->lsc.req_lock); + + ccdc->syncif.ccdc_mastermode = 0; + ccdc->syncif.datapol = 0; + ccdc->syncif.datsz = 0; + ccdc->syncif.fldmode = 0; + ccdc->syncif.fldout = 0; + ccdc->syncif.fldpol = 0; + ccdc->syncif.fldstat = 0; + ccdc->syncif.hdpol = 0; + ccdc->syncif.vdpol = 0; + + ccdc->clamp.oblen = 0; + ccdc->clamp.dcsubval = 0; + + ccdc->vpcfg.pixelclk = 0; + + ccdc->update = OMAP3ISP_CCDC_BLCLAMP; + ccdc_apply_controls(ccdc); + + return ccdc_init_entities(ccdc); +} + +/* + * omap3isp_ccdc_cleanup - CCDC module cleanup. + * @dev: Device pointer specific to the OMAP3 ISP. + */ +void omap3isp_ccdc_cleanup(struct isp_device *isp) +{ + struct isp_ccdc_device *ccdc = &isp->isp_ccdc; + + /* Free LSC requests. As the CCDC is stopped there's no active request, + * so only the pending request and the free queue need to be handled. + */ + ccdc_lsc_free_request(ccdc, ccdc->lsc.request); + cancel_work_sync(&ccdc->lsc.table_work); + ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue); + + if (ccdc->fpc.fpcaddr != 0) + iommu_vfree(isp->iommu, ccdc->fpc.fpcaddr); +} diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h new file mode 100644 index 000000000000..d403af5d31d2 --- /dev/null +++ b/drivers/media/video/omap3isp/ispccdc.h @@ -0,0 +1,219 @@ +/* + * ispccdc.h + * + * TI OMAP3 ISP - CCDC module + * + * Copyright (C) 2009-2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_CCDC_H +#define OMAP3_ISP_CCDC_H + +#include +#include + +#include "ispvideo.h" + +enum ccdc_input_entity { + CCDC_INPUT_NONE, + CCDC_INPUT_PARALLEL, + CCDC_INPUT_CSI2A, + CCDC_INPUT_CCP2B, + CCDC_INPUT_CSI2C +}; + +#define CCDC_OUTPUT_MEMORY (1 << 0) +#define CCDC_OUTPUT_PREVIEW (1 << 1) +#define CCDC_OUTPUT_RESIZER (1 << 2) + +#define OMAP3ISP_CCDC_NEVENTS 16 + +/* + * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC + * @ccdc_mastermode: Master mode. 1 - Master, 0 - Slave. + * @fldstat: Field state. 0 - Odd Field, 1 - Even Field. + * @datsz: Data size. + * @fldmode: 0 - Progressive, 1 - Interlaced. + * @datapol: 0 - Positive, 1 - Negative. + * @fldpol: 0 - Positive, 1 - Negative. + * @hdpol: 0 - Positive, 1 - Negative. + * @vdpol: 0 - Positive, 1 - Negative. + * @fldout: 0 - Input, 1 - Output. + * @hs_width: Width of the Horizontal Sync pulse, used for HS/VS Output. + * @vs_width: Width of the Vertical Sync pulse, used for HS/VS Output. + * @ppln: Number of pixels per line, used for HS/VS Output. + * @hlprf: Number of half lines per frame, used for HS/VS Output. + * @bt_r656_en: 1 - Enable ITU-R BT656 mode, 0 - Sync mode. + */ +struct ispccdc_syncif { + u8 ccdc_mastermode; + u8 fldstat; + u8 datsz; + u8 fldmode; + u8 datapol; + u8 fldpol; + u8 hdpol; + u8 vdpol; + u8 fldout; + u8 hs_width; + u8 vs_width; + u8 ppln; + u8 hlprf; + u8 bt_r656_en; +}; + +/* + * struct ispccdc_vp - Structure for Video Port parameters + * @pixelclk: Input pixel clock in Hz + */ +struct ispccdc_vp { + unsigned int pixelclk; +}; + +enum ispccdc_lsc_state { + LSC_STATE_STOPPED = 0, + LSC_STATE_STOPPING = 1, + LSC_STATE_RUNNING = 2, + LSC_STATE_RECONFIG = 3, +}; + +struct ispccdc_lsc_config_req { + struct list_head list; + struct omap3isp_ccdc_lsc_config config; + unsigned char enable; + u32 table; + struct iovm_struct *iovm; +}; + +/* + * ispccdc_lsc - CCDC LSC parameters + * @update_config: Set when user changes config + * @request_enable: Whether LSC is requested to be enabled + * @config: LSC config set by user + * @update_table: Set when user provides a new LSC table to table_new + * @table_new: LSC table set by user, ISP address + * @table_inuse: LSC table currently in use, ISP address + */ +struct ispccdc_lsc { + enum ispccdc_lsc_state state; + struct work_struct table_work; + + /* LSC queue of configurations */ + spinlock_t req_lock; + struct ispccdc_lsc_config_req *request; /* requested configuration */ + struct ispccdc_lsc_config_req *active; /* active configuration */ + struct list_head free_queue; /* configurations for freeing */ +}; + +#define CCDC_STOP_NOT_REQUESTED 0x00 +#define CCDC_STOP_REQUEST 0x01 +#define CCDC_STOP_EXECUTED (0x02 | CCDC_STOP_REQUEST) +#define CCDC_STOP_CCDC_FINISHED 0x04 +#define CCDC_STOP_LSC_FINISHED 0x08 +#define CCDC_STOP_FINISHED \ + (CCDC_STOP_EXECUTED | CCDC_STOP_CCDC_FINISHED | CCDC_STOP_LSC_FINISHED) + +#define CCDC_EVENT_VD1 0x10 +#define CCDC_EVENT_VD0 0x20 +#define CCDC_EVENT_LSC_DONE 0x40 + +/* Sink and source CCDC pads */ +#define CCDC_PAD_SINK 0 +#define CCDC_PAD_SOURCE_OF 1 +#define CCDC_PAD_SOURCE_VP 2 +#define CCDC_PADS_NUM 3 + +/* + * struct isp_ccdc_device - Structure for the CCDC module to store its own + * information + * @subdev: V4L2 subdevice + * @pads: Sink and source media entity pads + * @formats: Active video formats + * @input: Active input + * @output: Active outputs + * @video_out: Output video node + * @error: A hardware error occured during capture + * @alaw: A-law compression enabled (1) or disabled (0) + * @lpf: Low pass filter enabled (1) or disabled (0) + * @obclamp: Optical-black clamp enabled (1) or disabled (0) + * @fpc_en: Faulty pixels correction enabled (1) or disabled (0) + * @blcomp: Black level compensation configuration + * @clamp: Optical-black or digital clamp configuration + * @fpc: Faulty pixels correction configuration + * @lsc: Lens shading compensation configuration + * @update: Bitmask of controls to update during the next interrupt + * @shadow_update: Controls update in progress by userspace + * @syncif: Interface synchronization configuration + * @vpcfg: Video port configuration + * @underrun: A buffer underrun occured and a new buffer has been queued + * @state: Streaming state + * @lock: Serializes shadow_update with interrupt handler + * @wait: Wait queue used to stop the module + * @stopping: Stopping state + * @ioctl_lock: Serializes ioctl calls and LSC requests freeing + */ +struct isp_ccdc_device { + struct v4l2_subdev subdev; + struct media_pad pads[CCDC_PADS_NUM]; + struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM]; + + enum ccdc_input_entity input; + unsigned int output; + struct isp_video video_out; + unsigned int error; + + unsigned int alaw:1, + lpf:1, + obclamp:1, + fpc_en:1; + struct omap3isp_ccdc_blcomp blcomp; + struct omap3isp_ccdc_bclamp clamp; + struct omap3isp_ccdc_fpc fpc; + struct ispccdc_lsc lsc; + unsigned int update; + unsigned int shadow_update; + + struct ispccdc_syncif syncif; + struct ispccdc_vp vpcfg; + + unsigned int underrun:1; + enum isp_pipeline_stream_state state; + spinlock_t lock; + wait_queue_head_t wait; + unsigned int stopping; + struct mutex ioctl_lock; +}; + +struct isp_device; + +int omap3isp_ccdc_init(struct isp_device *isp); +void omap3isp_ccdc_cleanup(struct isp_device *isp); +int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc, + struct v4l2_device *vdev); +void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc); + +int omap3isp_ccdc_busy(struct isp_ccdc_device *isp_ccdc); +int omap3isp_ccdc_isr(struct isp_ccdc_device *isp_ccdc, u32 events); +void omap3isp_ccdc_restore_context(struct isp_device *isp); +void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc, + unsigned int *max_rate); + +#endif /* OMAP3_ISP_CCDC_H */ diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c new file mode 100644 index 000000000000..baf9374201dc --- /dev/null +++ b/drivers/media/video/omap3isp/isppreview.c @@ -0,0 +1,2113 @@ +/* + * isppreview.c + * + * TI OMAP3 ISP driver - Preview module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "isppreview.h" + +/* Default values in Office Flourescent Light for RGBtoRGB Blending */ +static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { + { /* RGB-RGB Matrix */ + {0x01E2, 0x0F30, 0x0FEE}, + {0x0F9B, 0x01AC, 0x0FB9}, + {0x0FE0, 0x0EC0, 0x0260} + }, /* RGB Offset */ + {0x0000, 0x0000, 0x0000} +}; + +/* Default values in Office Flourescent Light for RGB to YUV Conversion*/ +static struct omap3isp_prev_csc flr_prev_csc = { + { /* CSC Coef Matrix */ + {66, 129, 25}, + {-38, -75, 112}, + {112, -94 , -18} + }, /* CSC Offset */ + {0x0, 0x0, 0x0} +}; + +/* Default values in Office Flourescent Light for CFA Gradient*/ +#define FLR_CFA_GRADTHRS_HORZ 0x28 +#define FLR_CFA_GRADTHRS_VERT 0x28 + +/* Default values in Office Flourescent Light for Chroma Suppression*/ +#define FLR_CSUP_GAIN 0x0D +#define FLR_CSUP_THRES 0xEB + +/* Default values in Office Flourescent Light for Noise Filter*/ +#define FLR_NF_STRGTH 0x03 + +/* Default values for White Balance */ +#define FLR_WBAL_DGAIN 0x100 +#define FLR_WBAL_COEF 0x20 + +/* Default values in Office Flourescent Light for Black Adjustment*/ +#define FLR_BLKADJ_BLUE 0x0 +#define FLR_BLKADJ_GREEN 0x0 +#define FLR_BLKADJ_RED 0x0 + +#define DEF_DETECT_CORRECT_VAL 0xe + +#define PREV_MIN_WIDTH 64 +#define PREV_MIN_HEIGHT 8 +#define PREV_MAX_HEIGHT 16384 + +/* + * Coeficient Tables for the submodules in Preview. + * Array is initialised with the values from.the tables text file. + */ + +/* + * CFA Filter Coefficient Table + * + */ +static u32 cfa_coef_table[] = { +#include "cfa_coef_table.h" +}; + +/* + * Default Gamma Correction Table - All components + */ +static u32 gamma_table[] = { +#include "gamma_table.h" +}; + +/* + * Noise Filter Threshold table + */ +static u32 noise_filter_table[] = { +#include "noise_filter_table.h" +}; + +/* + * Luminance Enhancement Table + */ +static u32 luma_enhance_table[] = { +#include "luma_enhance_table.h" +}; + +/* + * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview. + * @enable: 1 - Reverse the A-Law done in CCDC. + */ +static void +preview_enable_invalaw(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW); +} + +/* + * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture. + * @prev - + * @enable: 1 - Enable, 0 - Disable + * + * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also + * The proccess is applied for each captured frame. + */ +static void +preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_DRKFCAP); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_DRKFCAP); +} + +/* + * preview_enable_drkframe - Enable/Disable of the darkframe subtract. + * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is + * subtracted with the pixels in the current frame. + * + * The proccess is applied for each captured frame. + */ +static void +preview_enable_drkframe(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_DRKFEN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_DRKFEN); +} + +/* + * preview_config_drkf_shadcomp - Configures shift value in shading comp. + * @scomp_shtval: 3bit value of shift used in shading compensation. + */ +static void +preview_config_drkf_shadcomp(struct isp_prev_device *prev, + const void *scomp_shtval) +{ + struct isp_device *isp = to_isp_device(prev); + const u32 *shtval = scomp_shtval; + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_SCOMP_SFT_MASK, + *shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT); +} + +/* + * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter. + * @enable: 1 - Enables Horizontal Median Filter. + */ +static void +preview_enable_hmed(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_HMEDEN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_HMEDEN); +} + +/* + * preview_config_hmed - Configures the Horizontal Median Filter. + * @prev_hmed: Structure containing the odd and even distance between the + * pixels in the image along with the filter threshold. + */ +static void +preview_config_hmed(struct isp_prev_device *prev, const void *prev_hmed) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_hmed *hmed = prev_hmed; + + isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) | + (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) | + (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT), + OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED); +} + +/* + * preview_config_noisefilter - Configures the Noise Filter. + * @prev_nf: Structure containing the noisefilter table, strength to be used + * for the noise filter and the defect correction enable flag. + */ +static void +preview_config_noisefilter(struct isp_prev_device *prev, const void *prev_nf) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_nf *nf = prev_nf; + unsigned int i; + + isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF); + isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR, + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); + for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) { + isp_reg_writel(isp, nf->table[i], + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); + } +} + +/* + * preview_config_dcor - Configures the defect correction + * @prev_dcor: Structure containing the defect correct thresholds + */ +static void +preview_config_dcor(struct isp_prev_device *prev, const void *prev_dcor) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_dcor *dcor = prev_dcor; + + isp_reg_writel(isp, dcor->detect_correct[0], + OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0); + isp_reg_writel(isp, dcor->detect_correct[1], + OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1); + isp_reg_writel(isp, dcor->detect_correct[2], + OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2); + isp_reg_writel(isp, dcor->detect_correct[3], + OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3); + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_DCCOUP, + dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0); +} + +/* + * preview_config_cfa - Configures the CFA Interpolation parameters. + * @prev_cfa: Structure containing the CFA interpolation table, CFA format + * in the image, vertical and horizontal gradient threshold. + */ +static void +preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_cfa *cfa = prev_cfa; + unsigned int i; + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_CFAFMT_MASK, + cfa->format << ISPPRV_PCR_CFAFMT_SHIFT); + + isp_reg_writel(isp, + (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) | + (cfa->gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT), + OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA); + + isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR, + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); + + for (i = 0; i < OMAP3ISP_PREV_CFA_TBL_SIZE; i++) { + isp_reg_writel(isp, cfa->table[i], + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); + } +} + +/* + * preview_config_gammacorrn - Configures the Gamma Correction table values + * @gtable: Structure containing the table for red, blue, green gamma table. + */ +static void +preview_config_gammacorrn(struct isp_prev_device *prev, const void *gtable) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_gtables *gt = gtable; + unsigned int i; + + isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR, + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); + for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) + isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV, + ISPPRV_SET_TBL_DATA); + + isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR, + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); + for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) + isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV, + ISPPRV_SET_TBL_DATA); + + isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR, + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); + for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++) + isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV, + ISPPRV_SET_TBL_DATA); +} + +/* + * preview_config_luma_enhancement - Sets the Luminance Enhancement table. + * @ytable: Structure containing the table for Luminance Enhancement table. + */ +static void +preview_config_luma_enhancement(struct isp_prev_device *prev, + const void *ytable) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_luma *yt = ytable; + unsigned int i; + + isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR, + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR); + for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) { + isp_reg_writel(isp, yt->table[i], + OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA); + } +} + +/* + * preview_config_chroma_suppression - Configures the Chroma Suppression. + * @csup: Structure containing the threshold value for suppression + * and the hypass filter enable flag. + */ +static void +preview_config_chroma_suppression(struct isp_prev_device *prev, + const void *csup) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_csup *cs = csup; + + isp_reg_writel(isp, + cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) | + (cs->hypf_en << ISPPRV_CSUP_HPYF_SHIFT), + OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP); +} + +/* + * preview_enable_noisefilter - Enables/Disables the Noise Filter. + * @enable: 1 - Enables the Noise Filter. + */ +static void +preview_enable_noisefilter(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_NFEN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_NFEN); +} + +/* + * preview_enable_dcor - Enables/Disables the defect correction. + * @enable: 1 - Enables the defect correction. + */ +static void +preview_enable_dcor(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_DCOREN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_DCOREN); +} + +/* + * preview_enable_cfa - Enable/Disable the CFA Interpolation. + * @enable: 1 - Enables the CFA. + */ +static void +preview_enable_cfa(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_CFAEN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_CFAEN); +} + +/* + * preview_enable_gammabypass - Enables/Disables the GammaByPass + * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB. + * 0 - Goes through Gamma Correction. input and output is 10bit. + */ +static void +preview_enable_gammabypass(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_GAMMA_BYPASS); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_GAMMA_BYPASS); +} + +/* + * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement + * @enable: 1 - Enable the Luminance Enhancement. + */ +static void +preview_enable_luma_enhancement(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_YNENHEN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_YNENHEN); +} + +/* + * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr. + * @enable: 1 - Enable the Chrominance Suppression. + */ +static void +preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable) +{ + struct isp_device *isp = to_isp_device(prev); + + if (enable) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_SUPEN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_SUPEN); +} + +/* + * preview_config_whitebalance - Configures the White Balance parameters. + * @prev_wbal: Structure containing the digital gain and white balance + * coefficient. + * + * Coefficient matrix always with default values. + */ +static void +preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_wbal *wbal = prev_wbal; + u32 val; + + isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN); + + val = wbal->coef0 << ISPPRV_WBGAIN_COEF0_SHIFT; + val |= wbal->coef1 << ISPPRV_WBGAIN_COEF1_SHIFT; + val |= wbal->coef2 << ISPPRV_WBGAIN_COEF2_SHIFT; + val |= wbal->coef3 << ISPPRV_WBGAIN_COEF3_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN); + + isp_reg_writel(isp, + ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT | + ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT | + ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT | + ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT | + ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_0_SHIFT | + ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_1_SHIFT | + ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N1_2_SHIFT | + ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N1_3_SHIFT | + ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_0_SHIFT | + ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_1_SHIFT | + ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N2_2_SHIFT | + ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N2_3_SHIFT | + ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_0_SHIFT | + ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_1_SHIFT | + ISPPRV_WBSEL_COEF2 << ISPPRV_WBSEL_N3_2_SHIFT | + ISPPRV_WBSEL_COEF3 << ISPPRV_WBSEL_N3_3_SHIFT, + OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL); +} + +/* + * preview_config_blkadj - Configures the Black Adjustment parameters. + * @prev_blkadj: Structure containing the black adjustment towards red, green, + * blue. + */ +static void +preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_blkadj *blkadj = prev_blkadj; + + isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) | + (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) | + (blkadj->red << ISPPRV_BLKADJOFF_R_SHIFT), + OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF); +} + +/* + * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix. + * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb + * offset. + */ +static void +preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_rgbtorgb *rgbrgb = rgb2rgb; + u32 val; + + val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT; + val |= (rgbrgb->matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1); + + val = (rgbrgb->matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT; + val |= (rgbrgb->matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2); + + val = (rgbrgb->matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT; + val |= (rgbrgb->matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3); + + val = (rgbrgb->matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT; + val |= (rgbrgb->matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4); + + val = (rgbrgb->matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5); + + val = (rgbrgb->offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT; + val |= (rgbrgb->offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1); + + val = (rgbrgb->offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2); +} + +/* + * Configures the RGB-YCbYCr conversion matrix + * @prev_csc: Structure containing the RGB to YCbYCr matrix and the + * YCbCr offset. + */ +static void +preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_csc *csc = prev_csc; + u32 val; + + val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT; + val |= (csc->matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT; + val |= (csc->matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0); + + val = (csc->matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT; + val |= (csc->matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT; + val |= (csc->matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1); + + val = (csc->matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT; + val |= (csc->matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT; + val |= (csc->matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2); + + val = (csc->offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT; + val |= (csc->offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT; + val |= (csc->offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT; + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET); +} + +/* + * preview_update_contrast - Updates the contrast. + * @contrast: Pointer to hold the current programmed contrast value. + * + * Value should be programmed before enabling the module. + */ +static void +preview_update_contrast(struct isp_prev_device *prev, u8 contrast) +{ + struct prev_params *params = &prev->params; + + if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) { + params->contrast = contrast * ISPPRV_CONTRAST_UNITS; + prev->update |= PREV_CONTRAST; + } +} + +/* + * preview_config_contrast - Configures the Contrast. + * @params: Contrast value (u8 pointer, U8Q0 format). + * + * Value should be programmed before enabling the module. + */ +static void +preview_config_contrast(struct isp_prev_device *prev, const void *params) +{ + struct isp_device *isp = to_isp_device(prev); + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT, + 0xff << ISPPRV_CNT_BRT_CNT_SHIFT, + *(u8 *)params << ISPPRV_CNT_BRT_CNT_SHIFT); +} + +/* + * preview_update_brightness - Updates the brightness in preview module. + * @brightness: Pointer to hold the current programmed brightness value. + * + */ +static void +preview_update_brightness(struct isp_prev_device *prev, u8 brightness) +{ + struct prev_params *params = &prev->params; + + if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) { + params->brightness = brightness * ISPPRV_BRIGHT_UNITS; + prev->update |= PREV_BRIGHTNESS; + } +} + +/* + * preview_config_brightness - Configures the brightness. + * @params: Brightness value (u8 pointer, U8Q0 format). + */ +static void +preview_config_brightness(struct isp_prev_device *prev, const void *params) +{ + struct isp_device *isp = to_isp_device(prev); + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT, + 0xff << ISPPRV_CNT_BRT_BRT_SHIFT, + *(u8 *)params << ISPPRV_CNT_BRT_BRT_SHIFT); +} + +/* + * preview_config_yc_range - Configures the max and min Y and C values. + * @yclimit: Structure containing the range of Y and C values. + */ +static void +preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit) +{ + struct isp_device *isp = to_isp_device(prev); + const struct omap3isp_prev_yclimit *yc = yclimit; + + isp_reg_writel(isp, + yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT | + yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT | + yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT | + yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT, + OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC); +} + +/* preview parameters update structure */ +struct preview_update { + int cfg_bit; + int feature_bit; + void (*config)(struct isp_prev_device *, const void *); + void (*enable)(struct isp_prev_device *, u8); +}; + +static struct preview_update update_attrs[] = { + {OMAP3ISP_PREV_LUMAENH, PREV_LUMA_ENHANCE, + preview_config_luma_enhancement, + preview_enable_luma_enhancement}, + {OMAP3ISP_PREV_INVALAW, PREV_INVERSE_ALAW, + NULL, + preview_enable_invalaw}, + {OMAP3ISP_PREV_HRZ_MED, PREV_HORZ_MEDIAN_FILTER, + preview_config_hmed, + preview_enable_hmed}, + {OMAP3ISP_PREV_CFA, PREV_CFA, + preview_config_cfa, + preview_enable_cfa}, + {OMAP3ISP_PREV_CHROMA_SUPP, PREV_CHROMA_SUPPRESS, + preview_config_chroma_suppression, + preview_enable_chroma_suppression}, + {OMAP3ISP_PREV_WB, PREV_WB, + preview_config_whitebalance, + NULL}, + {OMAP3ISP_PREV_BLKADJ, PREV_BLKADJ, + preview_config_blkadj, + NULL}, + {OMAP3ISP_PREV_RGB2RGB, PREV_RGB2RGB, + preview_config_rgb_blending, + NULL}, + {OMAP3ISP_PREV_COLOR_CONV, PREV_COLOR_CONV, + preview_config_rgb_to_ycbcr, + NULL}, + {OMAP3ISP_PREV_YC_LIMIT, PREV_YCLIMITS, + preview_config_yc_range, + NULL}, + {OMAP3ISP_PREV_DEFECT_COR, PREV_DEFECT_COR, + preview_config_dcor, + preview_enable_dcor}, + {OMAP3ISP_PREV_GAMMABYPASS, PREV_GAMMA_BYPASS, + NULL, + preview_enable_gammabypass}, + {OMAP3ISP_PREV_DRK_FRM_CAPTURE, PREV_DARK_FRAME_CAPTURE, + NULL, + preview_enable_drkframe_capture}, + {OMAP3ISP_PREV_DRK_FRM_SUBTRACT, PREV_DARK_FRAME_SUBTRACT, + NULL, + preview_enable_drkframe}, + {OMAP3ISP_PREV_LENS_SHADING, PREV_LENS_SHADING, + preview_config_drkf_shadcomp, + preview_enable_drkframe}, + {OMAP3ISP_PREV_NF, PREV_NOISE_FILTER, + preview_config_noisefilter, + preview_enable_noisefilter}, + {OMAP3ISP_PREV_GAMMA, PREV_GAMMA, + preview_config_gammacorrn, + NULL}, + {-1, PREV_CONTRAST, + preview_config_contrast, + NULL}, + {-1, PREV_BRIGHTNESS, + preview_config_brightness, + NULL}, +}; + +/* + * __preview_get_ptrs - helper function which return pointers to members + * of params and config structures. + * @params - pointer to preview_params structure. + * @param - return pointer to appropriate structure field. + * @configs - pointer to update config structure. + * @config - return pointer to appropriate structure field. + * @bit - for which feature to return pointers. + * Return size of coresponding prev_params member + */ +static u32 +__preview_get_ptrs(struct prev_params *params, void **param, + struct omap3isp_prev_update_config *configs, + void __user **config, u32 bit) +{ +#define CHKARG(cfgs, cfg, field) \ + if (cfgs && cfg) { \ + *(cfg) = (cfgs)->field; \ + } + + switch (bit) { + case PREV_HORZ_MEDIAN_FILTER: + *param = ¶ms->hmed; + CHKARG(configs, config, hmed) + return sizeof(params->hmed); + case PREV_NOISE_FILTER: + *param = ¶ms->nf; + CHKARG(configs, config, nf) + return sizeof(params->nf); + break; + case PREV_CFA: + *param = ¶ms->cfa; + CHKARG(configs, config, cfa) + return sizeof(params->cfa); + case PREV_LUMA_ENHANCE: + *param = ¶ms->luma; + CHKARG(configs, config, luma) + return sizeof(params->luma); + case PREV_CHROMA_SUPPRESS: + *param = ¶ms->csup; + CHKARG(configs, config, csup) + return sizeof(params->csup); + case PREV_DEFECT_COR: + *param = ¶ms->dcor; + CHKARG(configs, config, dcor) + return sizeof(params->dcor); + case PREV_BLKADJ: + *param = ¶ms->blk_adj; + CHKARG(configs, config, blkadj) + return sizeof(params->blk_adj); + case PREV_YCLIMITS: + *param = ¶ms->yclimit; + CHKARG(configs, config, yclimit) + return sizeof(params->yclimit); + case PREV_RGB2RGB: + *param = ¶ms->rgb2rgb; + CHKARG(configs, config, rgb2rgb) + return sizeof(params->rgb2rgb); + case PREV_COLOR_CONV: + *param = ¶ms->rgb2ycbcr; + CHKARG(configs, config, csc) + return sizeof(params->rgb2ycbcr); + case PREV_WB: + *param = ¶ms->wbal; + CHKARG(configs, config, wbal) + return sizeof(params->wbal); + case PREV_GAMMA: + *param = ¶ms->gamma; + CHKARG(configs, config, gamma) + return sizeof(params->gamma); + case PREV_CONTRAST: + *param = ¶ms->contrast; + return 0; + case PREV_BRIGHTNESS: + *param = ¶ms->brightness; + return 0; + default: + *param = NULL; + *config = NULL; + break; + } + return 0; +} + +/* + * preview_config - Copy and update local structure with userspace preview + * configuration. + * @prev: ISP preview engine + * @cfg: Configuration + * + * Return zero if success or -EFAULT if the configuration can't be copied from + * userspace. + */ +static int preview_config(struct isp_prev_device *prev, + struct omap3isp_prev_update_config *cfg) +{ + struct prev_params *params; + struct preview_update *attr; + int i, bit, rval = 0; + + params = &prev->params; + + if (prev->state != ISP_PIPELINE_STREAM_STOPPED) { + unsigned long flags; + + spin_lock_irqsave(&prev->lock, flags); + prev->shadow_update = 1; + spin_unlock_irqrestore(&prev->lock, flags); + } + + for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { + attr = &update_attrs[i]; + bit = 0; + + if (!(cfg->update & attr->cfg_bit)) + continue; + + bit = cfg->flag & attr->cfg_bit; + if (bit) { + void *to = NULL, __user *from = NULL; + unsigned long sz = 0; + + sz = __preview_get_ptrs(params, &to, cfg, &from, + bit); + if (to && from && sz) { + if (copy_from_user(to, from, sz)) { + rval = -EFAULT; + break; + } + } + params->features |= attr->feature_bit; + } else { + params->features &= ~attr->feature_bit; + } + + prev->update |= attr->feature_bit; + } + + prev->shadow_update = 0; + return rval; +} + +/* + * preview_setup_hw - Setup preview registers and/or internal memory + * @prev: pointer to preview private structure + * Note: can be called from interrupt context + * Return none + */ +static void preview_setup_hw(struct isp_prev_device *prev) +{ + struct prev_params *params = &prev->params; + struct preview_update *attr; + int i, bit; + void *param_ptr; + + for (i = 0; i < ARRAY_SIZE(update_attrs); i++) { + attr = &update_attrs[i]; + + if (!(prev->update & attr->feature_bit)) + continue; + bit = params->features & attr->feature_bit; + if (bit) { + if (attr->config) { + __preview_get_ptrs(params, ¶m_ptr, NULL, + NULL, bit); + attr->config(prev, param_ptr); + } + if (attr->enable) + attr->enable(prev, 1); + } else + if (attr->enable) + attr->enable(prev, 0); + + prev->update &= ~attr->feature_bit; + } +} + +/* + * preview_config_ycpos - Configure byte layout of YUV image. + * @mode: Indicates the required byte layout. + */ +static void +preview_config_ycpos(struct isp_prev_device *prev, + enum v4l2_mbus_pixelcode pixelcode) +{ + struct isp_device *isp = to_isp_device(prev); + enum preview_ycpos_mode mode; + + switch (pixelcode) { + case V4L2_MBUS_FMT_YUYV8_1X16: + mode = YCPOS_CrYCbY; + break; + case V4L2_MBUS_FMT_UYVY8_1X16: + mode = YCPOS_YCrYCb; + break; + default: + return; + } + + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_YCPOS_CrYCbY, + mode << ISPPRV_PCR_YCPOS_SHIFT); +} + +/* + * preview_config_averager - Enable / disable / configure averager + * @average: Average value to be configured. + */ +static void preview_config_averager(struct isp_prev_device *prev, u8 average) +{ + struct isp_device *isp = to_isp_device(prev); + int reg = 0; + + if (prev->params.cfa.format == OMAP3ISP_CFAFMT_BAYER) + reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT | + ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT | + average; + else if (prev->params.cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON) + reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT | + ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT | + average; + isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE); +} + +/* + * preview_config_input_size - Configure the input frame size + * + * The preview engine crops several rows and columns internally depending on + * which processing blocks are enabled. The driver assumes all those blocks are + * enabled when reporting source pad formats to userspace. If this assumption is + * not true, rows and columns must be manually cropped at the preview engine + * input to avoid overflows at the end of lines and frames. + */ +static void preview_config_input_size(struct isp_prev_device *prev) +{ + struct isp_device *isp = to_isp_device(prev); + struct prev_params *params = &prev->params; + struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK]; + unsigned int sph = 0; + unsigned int eph = format->width - 1; + unsigned int slv = 0; + unsigned int elv = format->height - 1; + + if (prev->input == PREVIEW_INPUT_CCDC) { + sph += 2; + eph -= 2; + } + + /* + * Median filter 4 pixels + * Noise filter 4 pixels, 4 lines + * or faulty pixels correction + * CFA filter 4 pixels, 4 lines in Bayer mode + * 2 lines in other modes + * Color suppression 2 pixels + * or luma enhancement + * ------------------------------------------------------------- + * Maximum total 14 pixels, 8 lines + */ + + if (!(params->features & PREV_CFA)) { + sph += 2; + eph -= 2; + slv += 2; + elv -= 2; + } + if (!(params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER))) { + sph += 2; + eph -= 2; + slv += 2; + elv -= 2; + } + if (!(params->features & PREV_HORZ_MEDIAN_FILTER)) { + sph += 2; + eph -= 2; + } + if (!(params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))) + sph += 2; + + isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph, + OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO); + isp_reg_writel(isp, (slv << ISPPRV_VERT_INFO_SLV_SHIFT) | elv, + OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO); +} + +/* + * preview_config_inlineoffset - Configures the Read address line offset. + * @prev: Preview module + * @offset: Line offset + * + * According to the TRM, the line offset must be aligned on a 32 bytes boundary. + * However, a hardware bug requires the memory start address to be aligned on a + * 64 bytes boundary, so the offset probably should be aligned on 64 bytes as + * well. + */ +static void +preview_config_inlineoffset(struct isp_prev_device *prev, u32 offset) +{ + struct isp_device *isp = to_isp_device(prev); + + isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV, + ISPPRV_RADR_OFFSET); +} + +/* + * preview_set_inaddr - Sets memory address of input frame. + * @addr: 32bit memory address aligned on 32byte boundary. + * + * Configures the memory address from which the input frame is to be read. + */ +static void preview_set_inaddr(struct isp_prev_device *prev, u32 addr) +{ + struct isp_device *isp = to_isp_device(prev); + + isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR); +} + +/* + * preview_config_outlineoffset - Configures the Write address line offset. + * @offset: Line Offset for the preview output. + * + * The offset must be a multiple of 32 bytes. + */ +static void preview_config_outlineoffset(struct isp_prev_device *prev, + u32 offset) +{ + struct isp_device *isp = to_isp_device(prev); + + isp_reg_writel(isp, offset & 0xffff, OMAP3_ISP_IOMEM_PREV, + ISPPRV_WADD_OFFSET); +} + +/* + * preview_set_outaddr - Sets the memory address to store output frame + * @addr: 32bit memory address aligned on 32byte boundary. + * + * Configures the memory address to which the output frame is written. + */ +static void preview_set_outaddr(struct isp_prev_device *prev, u32 addr) +{ + struct isp_device *isp = to_isp_device(prev); + + isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR); +} + +static void preview_adjust_bandwidth(struct isp_prev_device *prev) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity); + struct isp_device *isp = to_isp_device(prev); + const struct v4l2_mbus_framefmt *ifmt = &prev->formats[PREV_PAD_SINK]; + unsigned long l3_ick = pipe->l3_ick; + struct v4l2_fract *timeperframe; + unsigned int cycles_per_frame; + unsigned int requests_per_frame; + unsigned int cycles_per_request; + unsigned int minimum; + unsigned int maximum; + unsigned int value; + + if (prev->input != PREVIEW_INPUT_MEMORY) { + isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, + ISPSBL_SDR_REQ_PRV_EXP_MASK); + return; + } + + /* Compute the minimum number of cycles per request, based on the + * pipeline maximum data rate. This is an absolute lower bound if we + * don't want SBL overflows, so round the value up. + */ + cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1, + pipe->max_rate); + minimum = DIV_ROUND_UP(cycles_per_request, 32); + + /* Compute the maximum number of cycles per request, based on the + * requested frame rate. This is a soft upper bound to achieve a frame + * rate equal or higher than the requested value, so round the value + * down. + */ + timeperframe = &pipe->max_timeperframe; + + requests_per_frame = DIV_ROUND_UP(ifmt->width * 2, 256) * ifmt->height; + cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator, + timeperframe->denominator); + cycles_per_request = cycles_per_frame / requests_per_frame; + + maximum = cycles_per_request / 32; + + value = max(minimum, maximum); + + dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value); + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, + ISPSBL_SDR_REQ_PRV_EXP_MASK, + value << ISPSBL_SDR_REQ_PRV_EXP_SHIFT); +} + +/* + * omap3isp_preview_busy - Gets busy state of preview module. + */ +int omap3isp_preview_busy(struct isp_prev_device *prev) +{ + struct isp_device *isp = to_isp_device(prev); + + return isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR) + & ISPPRV_PCR_BUSY; +} + +/* + * omap3isp_preview_restore_context - Restores the values of preview registers + */ +void omap3isp_preview_restore_context(struct isp_device *isp) +{ + isp->isp_prev.update = PREV_FEATURES_END - 1; + preview_setup_hw(&isp->isp_prev); +} + +/* + * preview_print_status - Dump preview module registers to the kernel log + */ +#define PREV_PRINT_REGISTER(isp, name)\ + dev_dbg(isp->dev, "###PRV " #name "=0x%08x\n", \ + isp_reg_readl(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_##name)) + +static void preview_print_status(struct isp_prev_device *prev) +{ + struct isp_device *isp = to_isp_device(prev); + + dev_dbg(isp->dev, "-------------Preview Register dump----------\n"); + + PREV_PRINT_REGISTER(isp, PCR); + PREV_PRINT_REGISTER(isp, HORZ_INFO); + PREV_PRINT_REGISTER(isp, VERT_INFO); + PREV_PRINT_REGISTER(isp, RSDR_ADDR); + PREV_PRINT_REGISTER(isp, RADR_OFFSET); + PREV_PRINT_REGISTER(isp, DSDR_ADDR); + PREV_PRINT_REGISTER(isp, DRKF_OFFSET); + PREV_PRINT_REGISTER(isp, WSDR_ADDR); + PREV_PRINT_REGISTER(isp, WADD_OFFSET); + PREV_PRINT_REGISTER(isp, AVE); + PREV_PRINT_REGISTER(isp, HMED); + PREV_PRINT_REGISTER(isp, NF); + PREV_PRINT_REGISTER(isp, WB_DGAIN); + PREV_PRINT_REGISTER(isp, WBGAIN); + PREV_PRINT_REGISTER(isp, WBSEL); + PREV_PRINT_REGISTER(isp, CFA); + PREV_PRINT_REGISTER(isp, BLKADJOFF); + PREV_PRINT_REGISTER(isp, RGB_MAT1); + PREV_PRINT_REGISTER(isp, RGB_MAT2); + PREV_PRINT_REGISTER(isp, RGB_MAT3); + PREV_PRINT_REGISTER(isp, RGB_MAT4); + PREV_PRINT_REGISTER(isp, RGB_MAT5); + PREV_PRINT_REGISTER(isp, RGB_OFF1); + PREV_PRINT_REGISTER(isp, RGB_OFF2); + PREV_PRINT_REGISTER(isp, CSC0); + PREV_PRINT_REGISTER(isp, CSC1); + PREV_PRINT_REGISTER(isp, CSC2); + PREV_PRINT_REGISTER(isp, CSC_OFFSET); + PREV_PRINT_REGISTER(isp, CNT_BRT); + PREV_PRINT_REGISTER(isp, CSUP); + PREV_PRINT_REGISTER(isp, SETUP_YC); + PREV_PRINT_REGISTER(isp, SET_TBL_ADDR); + PREV_PRINT_REGISTER(isp, CDC_THR0); + PREV_PRINT_REGISTER(isp, CDC_THR1); + PREV_PRINT_REGISTER(isp, CDC_THR2); + PREV_PRINT_REGISTER(isp, CDC_THR3); + + dev_dbg(isp->dev, "--------------------------------------------\n"); +} + +/* + * preview_init_params - init image processing parameters. + * @prev: pointer to previewer private structure + * return none + */ +static void preview_init_params(struct isp_prev_device *prev) +{ + struct prev_params *params = &prev->params; + int i = 0; + + /* Init values */ + params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS; + params->brightness = ISPPRV_BRIGHT_DEF * ISPPRV_BRIGHT_UNITS; + params->average = NO_AVE; + params->cfa.format = OMAP3ISP_CFAFMT_BAYER; + memcpy(params->cfa.table, cfa_coef_table, + sizeof(params->cfa.table)); + params->cfa.gradthrs_horz = FLR_CFA_GRADTHRS_HORZ; + params->cfa.gradthrs_vert = FLR_CFA_GRADTHRS_VERT; + params->csup.gain = FLR_CSUP_GAIN; + params->csup.thres = FLR_CSUP_THRES; + params->csup.hypf_en = 0; + memcpy(params->luma.table, luma_enhance_table, + sizeof(params->luma.table)); + params->nf.spread = FLR_NF_STRGTH; + memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table)); + params->dcor.couplet_mode_en = 1; + for (i = 0; i < OMAP3ISP_PREV_DETECT_CORRECT_CHANNELS; i++) + params->dcor.detect_correct[i] = DEF_DETECT_CORRECT_VAL; + memcpy(params->gamma.blue, gamma_table, sizeof(params->gamma.blue)); + memcpy(params->gamma.green, gamma_table, sizeof(params->gamma.green)); + memcpy(params->gamma.red, gamma_table, sizeof(params->gamma.red)); + params->wbal.dgain = FLR_WBAL_DGAIN; + params->wbal.coef0 = FLR_WBAL_COEF; + params->wbal.coef1 = FLR_WBAL_COEF; + params->wbal.coef2 = FLR_WBAL_COEF; + params->wbal.coef3 = FLR_WBAL_COEF; + params->blk_adj.red = FLR_BLKADJ_RED; + params->blk_adj.green = FLR_BLKADJ_GREEN; + params->blk_adj.blue = FLR_BLKADJ_BLUE; + params->rgb2rgb = flr_rgb2rgb; + params->rgb2ycbcr = flr_prev_csc; + params->yclimit.minC = ISPPRV_YC_MIN; + params->yclimit.maxC = ISPPRV_YC_MAX; + params->yclimit.minY = ISPPRV_YC_MIN; + params->yclimit.maxY = ISPPRV_YC_MAX; + + params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER + | PREV_GAMMA | PREV_BLKADJ | PREV_YCLIMITS + | PREV_RGB2RGB | PREV_COLOR_CONV | PREV_WB + | PREV_BRIGHTNESS | PREV_CONTRAST; + + prev->update = PREV_FEATURES_END - 1; +} + +/* + * preview_max_out_width - Handle previewer hardware ouput limitations + * @isp_revision : ISP revision + * returns maximum width output for current isp revision + */ +static unsigned int preview_max_out_width(struct isp_prev_device *prev) +{ + struct isp_device *isp = to_isp_device(prev); + + switch (isp->revision) { + case ISP_REVISION_1_0: + return ISPPRV_MAXOUTPUT_WIDTH; + + case ISP_REVISION_2_0: + default: + return ISPPRV_MAXOUTPUT_WIDTH_ES2; + + case ISP_REVISION_15_0: + return ISPPRV_MAXOUTPUT_WIDTH_3630; + } +} + +static void preview_configure(struct isp_prev_device *prev) +{ + struct isp_device *isp = to_isp_device(prev); + struct v4l2_mbus_framefmt *format; + unsigned int max_out_width; + unsigned int format_avg; + + preview_setup_hw(prev); + + if (prev->output & PREVIEW_OUTPUT_MEMORY) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_SDRPORT); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_SDRPORT); + + if (prev->output & PREVIEW_OUTPUT_RESIZER) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_RSZPORT); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_RSZPORT); + + /* PREV_PAD_SINK */ + format = &prev->formats[PREV_PAD_SINK]; + + preview_adjust_bandwidth(prev); + + preview_config_input_size(prev); + + if (prev->input == PREVIEW_INPUT_CCDC) + preview_config_inlineoffset(prev, 0); + else + preview_config_inlineoffset(prev, + ALIGN(format->width, 0x20) * 2); + + /* PREV_PAD_SOURCE */ + format = &prev->formats[PREV_PAD_SOURCE]; + + if (prev->output & PREVIEW_OUTPUT_MEMORY) + preview_config_outlineoffset(prev, + ALIGN(format->width, 0x10) * 2); + + max_out_width = preview_max_out_width(prev); + + format_avg = fls(DIV_ROUND_UP(format->width, max_out_width) - 1); + preview_config_averager(prev, format_avg); + preview_config_ycpos(prev, format->code); +} + +/* ----------------------------------------------------------------------------- + * Interrupt handling + */ + +static void preview_enable_oneshot(struct isp_prev_device *prev) +{ + struct isp_device *isp = to_isp_device(prev); + + /* The PCR.SOURCE bit is automatically reset to 0 when the PCR.ENABLE + * bit is set. As the preview engine is used in single-shot mode, we + * need to set PCR.SOURCE before enabling the preview engine. + */ + if (prev->input == PREVIEW_INPUT_MEMORY) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_SOURCE); + + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT); +} + +void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev) +{ + /* + * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun + * condition, the module was paused and now we have a buffer queued + * on the output again. Restart the pipeline if running in continuous + * mode. + */ + if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS && + prev->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) { + preview_enable_oneshot(prev); + isp_video_dmaqueue_flags_clr(&prev->video_out); + } +} + +static void preview_isr_buffer(struct isp_prev_device *prev) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&prev->subdev.entity); + struct isp_buffer *buffer; + int restart = 0; + + if (prev->input == PREVIEW_INPUT_MEMORY) { + buffer = omap3isp_video_buffer_next(&prev->video_in, + prev->error); + if (buffer != NULL) + preview_set_inaddr(prev, buffer->isp_addr); + pipe->state |= ISP_PIPELINE_IDLE_INPUT; + } + + if (prev->output & PREVIEW_OUTPUT_MEMORY) { + buffer = omap3isp_video_buffer_next(&prev->video_out, + prev->error); + if (buffer != NULL) { + preview_set_outaddr(prev, buffer->isp_addr); + restart = 1; + } + pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; + } + + switch (prev->state) { + case ISP_PIPELINE_STREAM_SINGLESHOT: + if (isp_pipeline_ready(pipe)) + omap3isp_pipeline_set_stream(pipe, + ISP_PIPELINE_STREAM_SINGLESHOT); + break; + + case ISP_PIPELINE_STREAM_CONTINUOUS: + /* If an underrun occurs, the video queue operation handler will + * restart the preview engine. Otherwise restart it immediately. + */ + if (restart) + preview_enable_oneshot(prev); + break; + + case ISP_PIPELINE_STREAM_STOPPED: + default: + return; + } + + prev->error = 0; +} + +/* + * omap3isp_preview_isr - ISP preview engine interrupt handler + * + * Manage the preview engine video buffers and configure shadowed registers. + */ +void omap3isp_preview_isr(struct isp_prev_device *prev) +{ + unsigned long flags; + + if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping)) + return; + + spin_lock_irqsave(&prev->lock, flags); + if (prev->shadow_update) + goto done; + + preview_setup_hw(prev); + preview_config_input_size(prev); + +done: + spin_unlock_irqrestore(&prev->lock, flags); + + if (prev->input == PREVIEW_INPUT_MEMORY || + prev->output & PREVIEW_OUTPUT_MEMORY) + preview_isr_buffer(prev); + else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS) + preview_enable_oneshot(prev); +} + +/* ----------------------------------------------------------------------------- + * ISP video operations + */ + +static int preview_video_queue(struct isp_video *video, + struct isp_buffer *buffer) +{ + struct isp_prev_device *prev = &video->isp->isp_prev; + + if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + preview_set_inaddr(prev, buffer->isp_addr); + + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + preview_set_outaddr(prev, buffer->isp_addr); + + return 0; +} + +static const struct isp_video_operations preview_video_ops = { + .queue = preview_video_queue, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +/* + * preview_s_ctrl - Handle set control subdev method + * @ctrl: pointer to v4l2 control structure + */ +static int preview_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct isp_prev_device *prev = + container_of(ctrl->handler, struct isp_prev_device, ctrls); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + preview_update_brightness(prev, ctrl->val); + break; + case V4L2_CID_CONTRAST: + preview_update_contrast(prev, ctrl->val); + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops preview_ctrl_ops = { + .s_ctrl = preview_s_ctrl, +}; + +/* + * preview_ioctl - Handle preview module private ioctl's + * @prev: pointer to preview context structure + * @cmd: configuration command + * @arg: configuration argument + * return -EINVAL or zero on success + */ +static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_OMAP3ISP_PRV_CFG: + return preview_config(prev, arg); + + default: + return -ENOIOCTLCMD; + } +} + +/* + * preview_set_stream - Enable/Disable streaming on preview subdev + * @sd : pointer to v4l2 subdev structure + * @enable: 1 == Enable, 0 == Disable + * return -EINVAL or zero on sucess + */ +static int preview_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + struct isp_video *video_out = &prev->video_out; + struct isp_device *isp = to_isp_device(prev); + struct device *dev = to_device(prev); + unsigned long flags; + + if (prev->state == ISP_PIPELINE_STREAM_STOPPED) { + if (enable == ISP_PIPELINE_STREAM_STOPPED) + return 0; + + omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_PREVIEW); + preview_configure(prev); + atomic_set(&prev->stopping, 0); + prev->error = 0; + preview_print_status(prev); + } + + switch (enable) { + case ISP_PIPELINE_STREAM_CONTINUOUS: + if (prev->output & PREVIEW_OUTPUT_MEMORY) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); + + if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED || + !(prev->output & PREVIEW_OUTPUT_MEMORY)) + preview_enable_oneshot(prev); + + isp_video_dmaqueue_flags_clr(video_out); + break; + + case ISP_PIPELINE_STREAM_SINGLESHOT: + if (prev->input == PREVIEW_INPUT_MEMORY) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_READ); + if (prev->output & PREVIEW_OUTPUT_MEMORY) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); + + preview_enable_oneshot(prev); + break; + + case ISP_PIPELINE_STREAM_STOPPED: + if (omap3isp_module_sync_idle(&sd->entity, &prev->wait, + &prev->stopping)) + dev_dbg(dev, "%s: stop timeout.\n", sd->name); + spin_lock_irqsave(&prev->lock, flags); + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ); + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE); + omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW); + spin_unlock_irqrestore(&prev->lock, flags); + isp_video_dmaqueue_flags_clr(video_out); + break; + } + + prev->state = enable; + return 0; +} + +static struct v4l2_mbus_framefmt * +__preview_get_format(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(fh, pad); + else + return &prev->formats[pad]; +} + +/* previewer format descriptions */ +static const unsigned int preview_input_fmts[] = { + V4L2_MBUS_FMT_SGRBG10_1X10, + V4L2_MBUS_FMT_SRGGB10_1X10, + V4L2_MBUS_FMT_SBGGR10_1X10, + V4L2_MBUS_FMT_SGBRG10_1X10, +}; + +static const unsigned int preview_output_fmts[] = { + V4L2_MBUS_FMT_UYVY8_1X16, + V4L2_MBUS_FMT_YUYV8_1X16, +}; + +/* + * preview_try_format - Handle try format by pad subdev method + * @prev: ISP preview device + * @fh : V4L2 subdev file handle + * @pad: pad num + * @fmt: pointer to v4l2 format structure + */ +static void preview_try_format(struct isp_prev_device *prev, + struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + unsigned int max_out_width; + enum v4l2_mbus_pixelcode pixelcode; + unsigned int i; + + max_out_width = preview_max_out_width(prev); + + switch (pad) { + case PREV_PAD_SINK: + /* When reading data from the CCDC, the input size has already + * been mangled by the CCDC output pad so it can be accepted + * as-is. + * + * When reading data from memory, clamp the requested width and + * height. The TRM doesn't specify a minimum input height, make + * sure we got enough lines to enable the noise filter and color + * filter array interpolation. + */ + if (prev->input == PREVIEW_INPUT_MEMORY) { + fmt->width = clamp_t(u32, fmt->width, PREV_MIN_WIDTH, + max_out_width * 8); + fmt->height = clamp_t(u32, fmt->height, PREV_MIN_HEIGHT, + PREV_MAX_HEIGHT); + } + + fmt->colorspace = V4L2_COLORSPACE_SRGB; + + for (i = 0; i < ARRAY_SIZE(preview_input_fmts); i++) { + if (fmt->code == preview_input_fmts[i]) + break; + } + + /* If not found, use SGRBG10 as default */ + if (i >= ARRAY_SIZE(preview_input_fmts)) + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; + break; + + case PREV_PAD_SOURCE: + pixelcode = fmt->code; + format = __preview_get_format(prev, fh, PREV_PAD_SINK, which); + memcpy(fmt, format, sizeof(*fmt)); + + /* The preview module output size is configurable through the + * input interface (horizontal and vertical cropping) and the + * averager (horizontal scaling by 1/1, 1/2, 1/4 or 1/8). In + * spite of this, hardcode the output size to the biggest + * possible value for simplicity reasons. + */ + switch (pixelcode) { + case V4L2_MBUS_FMT_YUYV8_1X16: + case V4L2_MBUS_FMT_UYVY8_1X16: + fmt->code = pixelcode; + break; + + default: + fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; + break; + } + + /* The TRM states (12.1.4.7.1.2) that 2 pixels must be cropped + * from the left and right sides when the input source is the + * CCDC. This seems not to be needed in practice, investigation + * is required. + */ + if (prev->input == PREVIEW_INPUT_CCDC) + fmt->width -= 4; + + /* The preview module can output a maximum of 3312 pixels + * horizontally due to fixed memory-line sizes. Compute the + * horizontal averaging factor accordingly. Note that the limit + * applies to the noise filter and CFA interpolation blocks, so + * it doesn't take cropping by further blocks into account. + * + * ES 1.0 hardware revision is limited to 1280 pixels + * horizontally. + */ + fmt->width >>= fls(DIV_ROUND_UP(fmt->width, max_out_width) - 1); + + /* Assume that all blocks are enabled and crop pixels and lines + * accordingly. See preview_config_input_size() for more + * information. + */ + fmt->width -= 14; + fmt->height -= 8; + + fmt->colorspace = V4L2_COLORSPACE_JPEG; + break; + } + + fmt->field = V4L2_FIELD_NONE; +} + +/* + * preview_enum_mbus_code - Handle pixel format enumeration + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @code : pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int preview_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + switch (code->pad) { + case PREV_PAD_SINK: + if (code->index >= ARRAY_SIZE(preview_input_fmts)) + return -EINVAL; + + code->code = preview_input_fmts[code->index]; + break; + case PREV_PAD_SOURCE: + if (code->index >= ARRAY_SIZE(preview_output_fmts)) + return -EINVAL; + + code->code = preview_output_fmts[code->index]; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int preview_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + preview_try_format(prev, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * preview_get_format - Handle get format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt: pointer to v4l2 subdev format structure + * return -EINVAL or zero on sucess + */ +static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __preview_get_format(prev, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + return 0; +} + +/* + * preview_set_format - Handle set format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt: pointer to v4l2 subdev format structure + * return -EINVAL or zero on success + */ +static int preview_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __preview_get_format(prev, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + preview_try_format(prev, fh, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + /* Propagate the format from sink to source */ + if (fmt->pad == PREV_PAD_SINK) { + format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, + fmt->which); + *format = fmt->format; + preview_try_format(prev, fh, PREV_PAD_SOURCE, format, + fmt->which); + } + + return 0; +} + +/* + * preview_init_formats - Initialize formats on all pads + * @sd: ISP preview V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. If fh is not NULL, try + * formats are initialized on the file handle. Otherwise active formats are + * initialized on the device. + */ +static int preview_init_formats(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format; + + memset(&format, 0, sizeof(format)); + format.pad = PREV_PAD_SINK; + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; + format.format.width = 4096; + format.format.height = 4096; + preview_set_format(sd, fh, &format); + + return 0; +} + +/* subdev core operations */ +static const struct v4l2_subdev_core_ops preview_v4l2_core_ops = { + .ioctl = preview_ioctl, +}; + +/* subdev video operations */ +static const struct v4l2_subdev_video_ops preview_v4l2_video_ops = { + .s_stream = preview_set_stream, +}; + +/* subdev pad operations */ +static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = { + .enum_mbus_code = preview_enum_mbus_code, + .enum_frame_size = preview_enum_frame_size, + .get_fmt = preview_get_format, + .set_fmt = preview_set_format, +}; + +/* subdev operations */ +static const struct v4l2_subdev_ops preview_v4l2_ops = { + .core = &preview_v4l2_core_ops, + .video = &preview_v4l2_video_ops, + .pad = &preview_v4l2_pad_ops, +}; + +/* subdev internal operations */ +static const struct v4l2_subdev_internal_ops preview_v4l2_internal_ops = { + .open = preview_init_formats, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +/* + * preview_link_setup - Setup previewer connections. + * @entity : Pointer to media entity structure + * @local : Pointer to local pad array + * @remote : Pointer to remote pad array + * @flags : Link flags + * return -EINVAL or zero on success + */ +static int preview_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct isp_prev_device *prev = v4l2_get_subdevdata(sd); + + switch (local->index | media_entity_type(remote->entity)) { + case PREV_PAD_SINK | MEDIA_ENT_T_DEVNODE: + /* read from memory */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (prev->input == PREVIEW_INPUT_CCDC) + return -EBUSY; + prev->input = PREVIEW_INPUT_MEMORY; + } else { + if (prev->input == PREVIEW_INPUT_MEMORY) + prev->input = PREVIEW_INPUT_NONE; + } + break; + + case PREV_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + /* read from ccdc */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (prev->input == PREVIEW_INPUT_MEMORY) + return -EBUSY; + prev->input = PREVIEW_INPUT_CCDC; + } else { + if (prev->input == PREVIEW_INPUT_CCDC) + prev->input = PREVIEW_INPUT_NONE; + } + break; + + /* + * The ISP core doesn't support pipelines with multiple video outputs. + * Revisit this when it will be implemented, and return -EBUSY for now. + */ + + case PREV_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: + /* write to memory */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (prev->output & ~PREVIEW_OUTPUT_MEMORY) + return -EBUSY; + prev->output |= PREVIEW_OUTPUT_MEMORY; + } else { + prev->output &= ~PREVIEW_OUTPUT_MEMORY; + } + break; + + case PREV_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: + /* write to resizer */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (prev->output & ~PREVIEW_OUTPUT_RESIZER) + return -EBUSY; + prev->output |= PREVIEW_OUTPUT_RESIZER; + } else { + prev->output &= ~PREVIEW_OUTPUT_RESIZER; + } + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* media operations */ +static const struct media_entity_operations preview_media_ops = { + .link_setup = preview_link_setup, +}; + +/* + * review_init_entities - Initialize subdev and media entity. + * @prev : Pointer to preview structure + * return -ENOMEM or zero on success + */ +static int preview_init_entities(struct isp_prev_device *prev) +{ + struct v4l2_subdev *sd = &prev->subdev; + struct media_pad *pads = prev->pads; + struct media_entity *me = &sd->entity; + int ret; + + prev->input = PREVIEW_INPUT_NONE; + + v4l2_subdev_init(sd, &preview_v4l2_ops); + sd->internal_ops = &preview_v4l2_internal_ops; + strlcpy(sd->name, "OMAP3 ISP preview", sizeof(sd->name)); + sd->grp_id = 1 << 16; /* group ID for isp subdevs */ + v4l2_set_subdevdata(sd, prev); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + v4l2_ctrl_handler_init(&prev->ctrls, 2); + v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_BRIGHTNESS, + ISPPRV_BRIGHT_LOW, ISPPRV_BRIGHT_HIGH, + ISPPRV_BRIGHT_STEP, ISPPRV_BRIGHT_DEF); + v4l2_ctrl_new_std(&prev->ctrls, &preview_ctrl_ops, V4L2_CID_CONTRAST, + ISPPRV_CONTRAST_LOW, ISPPRV_CONTRAST_HIGH, + ISPPRV_CONTRAST_STEP, ISPPRV_CONTRAST_DEF); + v4l2_ctrl_handler_setup(&prev->ctrls); + sd->ctrl_handler = &prev->ctrls; + + pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + me->ops = &preview_media_ops; + ret = media_entity_init(me, PREV_PADS_NUM, pads, 0); + if (ret < 0) + return ret; + + preview_init_formats(sd, NULL); + + /* According to the OMAP34xx TRM, video buffers need to be aligned on a + * 32 bytes boundary. However, an undocumented hardware bug requires a + * 64 bytes boundary at the preview engine input. + */ + prev->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + prev->video_in.ops = &preview_video_ops; + prev->video_in.isp = to_isp_device(prev); + prev->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; + prev->video_in.bpl_alignment = 64; + prev->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + prev->video_out.ops = &preview_video_ops; + prev->video_out.isp = to_isp_device(prev); + prev->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; + prev->video_out.bpl_alignment = 32; + + ret = omap3isp_video_init(&prev->video_in, "preview"); + if (ret < 0) + return ret; + + ret = omap3isp_video_init(&prev->video_out, "preview"); + if (ret < 0) + return ret; + + /* Connect the video nodes to the previewer subdev. */ + ret = media_entity_create_link(&prev->video_in.video.entity, 0, + &prev->subdev.entity, PREV_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_entity_create_link(&prev->subdev.entity, PREV_PAD_SOURCE, + &prev->video_out.video.entity, 0, 0); + if (ret < 0) + return ret; + + return 0; +} + +void omap3isp_preview_unregister_entities(struct isp_prev_device *prev) +{ + media_entity_cleanup(&prev->subdev.entity); + + v4l2_device_unregister_subdev(&prev->subdev); + v4l2_ctrl_handler_free(&prev->ctrls); + omap3isp_video_unregister(&prev->video_in); + omap3isp_video_unregister(&prev->video_out); +} + +int omap3isp_preview_register_entities(struct isp_prev_device *prev, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &prev->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&prev->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_preview_unregister_entities(prev); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP previewer initialisation and cleanup + */ + +void omap3isp_preview_cleanup(struct isp_device *isp) +{ +} + +/* + * isp_preview_init - Previewer initialization. + * @dev : Pointer to ISP device + * return -ENOMEM or zero on success + */ +int omap3isp_preview_init(struct isp_device *isp) +{ + struct isp_prev_device *prev = &isp->isp_prev; + int ret; + + spin_lock_init(&prev->lock); + init_waitqueue_head(&prev->wait); + preview_init_params(prev); + + ret = preview_init_entities(prev); + if (ret < 0) + goto out; + +out: + if (ret) + omap3isp_preview_cleanup(isp); + + return ret; +} diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h new file mode 100644 index 000000000000..f2d63ca4bd6f --- /dev/null +++ b/drivers/media/video/omap3isp/isppreview.h @@ -0,0 +1,214 @@ +/* + * isppreview.h + * + * TI OMAP3 ISP - Preview module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_PREVIEW_H +#define OMAP3_ISP_PREVIEW_H + +#include +#include +#include + +#include "ispvideo.h" + +#define ISPPRV_BRIGHT_STEP 0x1 +#define ISPPRV_BRIGHT_DEF 0x0 +#define ISPPRV_BRIGHT_LOW 0x0 +#define ISPPRV_BRIGHT_HIGH 0xFF +#define ISPPRV_BRIGHT_UNITS 0x1 + +#define ISPPRV_CONTRAST_STEP 0x1 +#define ISPPRV_CONTRAST_DEF 0x10 +#define ISPPRV_CONTRAST_LOW 0x0 +#define ISPPRV_CONTRAST_HIGH 0xFF +#define ISPPRV_CONTRAST_UNITS 0x1 + +#define NO_AVE 0x0 +#define AVE_2_PIX 0x1 +#define AVE_4_PIX 0x2 +#define AVE_8_PIX 0x3 + +/* Features list */ +#define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH +#define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW +#define PREV_HORZ_MEDIAN_FILTER OMAP3ISP_PREV_HRZ_MED +#define PREV_CFA OMAP3ISP_PREV_CFA +#define PREV_CHROMA_SUPPRESS OMAP3ISP_PREV_CHROMA_SUPP +#define PREV_WB OMAP3ISP_PREV_WB +#define PREV_BLKADJ OMAP3ISP_PREV_BLKADJ +#define PREV_RGB2RGB OMAP3ISP_PREV_RGB2RGB +#define PREV_COLOR_CONV OMAP3ISP_PREV_COLOR_CONV +#define PREV_YCLIMITS OMAP3ISP_PREV_YC_LIMIT +#define PREV_DEFECT_COR OMAP3ISP_PREV_DEFECT_COR +#define PREV_GAMMA_BYPASS OMAP3ISP_PREV_GAMMABYPASS +#define PREV_DARK_FRAME_CAPTURE OMAP3ISP_PREV_DRK_FRM_CAPTURE +#define PREV_DARK_FRAME_SUBTRACT OMAP3ISP_PREV_DRK_FRM_SUBTRACT +#define PREV_LENS_SHADING OMAP3ISP_PREV_LENS_SHADING +#define PREV_NOISE_FILTER OMAP3ISP_PREV_NF +#define PREV_GAMMA OMAP3ISP_PREV_GAMMA + +#define PREV_CONTRAST (1 << 17) +#define PREV_BRIGHTNESS (1 << 18) +#define PREV_AVERAGER (1 << 19) +#define PREV_FEATURES_END (1 << 20) + +enum preview_input_entity { + PREVIEW_INPUT_NONE, + PREVIEW_INPUT_CCDC, + PREVIEW_INPUT_MEMORY, +}; + +#define PREVIEW_OUTPUT_RESIZER (1 << 1) +#define PREVIEW_OUTPUT_MEMORY (1 << 2) + +/* Configure byte layout of YUV image */ +enum preview_ycpos_mode { + YCPOS_YCrYCb = 0, + YCPOS_YCbYCr = 1, + YCPOS_CbYCrY = 2, + YCPOS_CrYCbY = 3 +}; + +/* + * struct prev_params - Structure for all configuration + * @features: Set of features enabled. + * @cfa: CFA coefficients. + * @csup: Chroma suppression coefficients. + * @luma: Luma enhancement coefficients. + * @nf: Noise filter coefficients. + * @dcor: Noise filter coefficients. + * @gamma: Gamma coefficients. + * @wbal: White Balance parameters. + * @blk_adj: Black adjustment parameters. + * @rgb2rgb: RGB blending parameters. + * @rgb2ycbcr: RGB to ycbcr parameters. + * @hmed: Horizontal median filter. + * @yclimit: YC limits parameters. + * @average: Downsampling rate for averager. + * @contrast: Contrast. + * @brightness: Brightness. + */ +struct prev_params { + u32 features; + struct omap3isp_prev_cfa cfa; + struct omap3isp_prev_csup csup; + struct omap3isp_prev_luma luma; + struct omap3isp_prev_nf nf; + struct omap3isp_prev_dcor dcor; + struct omap3isp_prev_gtables gamma; + struct omap3isp_prev_wbal wbal; + struct omap3isp_prev_blkadj blk_adj; + struct omap3isp_prev_rgbtorgb rgb2rgb; + struct omap3isp_prev_csc rgb2ycbcr; + struct omap3isp_prev_hmed hmed; + struct omap3isp_prev_yclimit yclimit; + u8 average; + u8 contrast; + u8 brightness; +}; + +/* + * struct isptables_update - Structure for Table Configuration. + * @update: Specifies which tables should be updated. + * @flag: Specifies which tables should be enabled. + * @nf: Pointer to structure for Noise Filter + * @lsc: Pointer to LSC gain table. (currently not used) + * @gamma: Pointer to gamma correction tables. + * @cfa: Pointer to color filter array configuration. + * @wbal: Pointer to colour and digital gain configuration. + */ +struct isptables_update { + u32 update; + u32 flag; + struct omap3isp_prev_nf *nf; + u32 *lsc; + struct omap3isp_prev_gtables *gamma; + struct omap3isp_prev_cfa *cfa; + struct omap3isp_prev_wbal *wbal; +}; + +/* Sink and source previewer pads */ +#define PREV_PAD_SINK 0 +#define PREV_PAD_SOURCE 1 +#define PREV_PADS_NUM 2 + +/* + * struct isp_prev_device - Structure for storing ISP Preview module information + * @subdev: V4L2 subdevice + * @pads: Media entity pads + * @formats: Active formats at the subdev pad + * @input: Module currently connected to the input pad + * @output: Bitmask of the active output + * @video_in: Input video entity + * @video_out: Output video entity + * @error: A hardware error occured during capture + * @params: Module configuration data + * @shadow_update: If set, update the hardware configured in the next interrupt + * @underrun: Whether the preview entity has queued buffers on the output + * @state: Current preview pipeline state + * @lock: Shadow update lock + * @update: Bitmask of the parameters to be updated + * + * This structure is used to store the OMAP ISP Preview module Information. + */ +struct isp_prev_device { + struct v4l2_subdev subdev; + struct media_pad pads[PREV_PADS_NUM]; + struct v4l2_mbus_framefmt formats[PREV_PADS_NUM]; + + struct v4l2_ctrl_handler ctrls; + + enum preview_input_entity input; + unsigned int output; + struct isp_video video_in; + struct isp_video video_out; + unsigned int error; + + struct prev_params params; + unsigned int shadow_update:1; + enum isp_pipeline_stream_state state; + wait_queue_head_t wait; + atomic_t stopping; + spinlock_t lock; + u32 update; +}; + +struct isp_device; + +int omap3isp_preview_init(struct isp_device *isp); +void omap3isp_preview_cleanup(struct isp_device *isp); + +int omap3isp_preview_register_entities(struct isp_prev_device *prv, + struct v4l2_device *vdev); +void omap3isp_preview_unregister_entities(struct isp_prev_device *prv); + +void omap3isp_preview_isr_frame_sync(struct isp_prev_device *prev); +void omap3isp_preview_isr(struct isp_prev_device *prev); + +int omap3isp_preview_busy(struct isp_prev_device *isp_prev); + +void omap3isp_preview_restore_context(struct isp_device *isp); + +#endif /* OMAP3_ISP_PREVIEW_H */ diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c new file mode 100644 index 000000000000..75d39b115d42 --- /dev/null +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -0,0 +1,1693 @@ +/* + * ispresizer.c + * + * TI OMAP3 ISP - Resizer module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "ispresizer.h" + +/* + * Resizer Constants + */ +#define MIN_RESIZE_VALUE 64 +#define MID_RESIZE_VALUE 512 +#define MAX_RESIZE_VALUE 1024 + +#define MIN_IN_WIDTH 32 +#define MIN_IN_HEIGHT 32 +#define MAX_IN_WIDTH_MEMORY_MODE 4095 +#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES1 1280 +#define MAX_IN_WIDTH_ONTHEFLY_MODE_ES2 4095 +#define MAX_IN_HEIGHT 4095 + +#define MIN_OUT_WIDTH 16 +#define MIN_OUT_HEIGHT 2 +#define MAX_OUT_HEIGHT 4095 + +/* + * Resizer Use Constraints + * "TRM ES3.1, table 12-46" + */ +#define MAX_4TAP_OUT_WIDTH_ES1 1280 +#define MAX_7TAP_OUT_WIDTH_ES1 640 +#define MAX_4TAP_OUT_WIDTH_ES2 3312 +#define MAX_7TAP_OUT_WIDTH_ES2 1650 +#define MAX_4TAP_OUT_WIDTH_3630 4096 +#define MAX_7TAP_OUT_WIDTH_3630 2048 + +/* + * Constants for ratio calculation + */ +#define RESIZE_DIVISOR 256 +#define DEFAULT_PHASE 1 + +/* + * Default (and only) configuration of filter coefficients. + * 7-tap mode is for scale factors 0.25x to 0.5x. + * 4-tap mode is for scale factors 0.5x to 4.0x. + * There shouldn't be any reason to recalculate these, EVER. + */ +static const struct isprsz_coef filter_coefs = { + /* For 8-phase 4-tap horizontal filter: */ + { + 0x0000, 0x0100, 0x0000, 0x0000, + 0x03FA, 0x00F6, 0x0010, 0x0000, + 0x03F9, 0x00DB, 0x002C, 0x0000, + 0x03FB, 0x00B3, 0x0053, 0x03FF, + 0x03FD, 0x0082, 0x0084, 0x03FD, + 0x03FF, 0x0053, 0x00B3, 0x03FB, + 0x0000, 0x002C, 0x00DB, 0x03F9, + 0x0000, 0x0010, 0x00F6, 0x03FA + }, + /* For 8-phase 4-tap vertical filter: */ + { + 0x0000, 0x0100, 0x0000, 0x0000, + 0x03FA, 0x00F6, 0x0010, 0x0000, + 0x03F9, 0x00DB, 0x002C, 0x0000, + 0x03FB, 0x00B3, 0x0053, 0x03FF, + 0x03FD, 0x0082, 0x0084, 0x03FD, + 0x03FF, 0x0053, 0x00B3, 0x03FB, + 0x0000, 0x002C, 0x00DB, 0x03F9, + 0x0000, 0x0010, 0x00F6, 0x03FA + }, + /* For 4-phase 7-tap horizontal filter: */ + #define DUMMY 0 + { + 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY, + 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY, + 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY, + 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY + }, + /* For 4-phase 7-tap vertical filter: */ + { + 0x0004, 0x0023, 0x005A, 0x0058, 0x0023, 0x0004, 0x0000, DUMMY, + 0x0002, 0x0018, 0x004d, 0x0060, 0x0031, 0x0008, 0x0000, DUMMY, + 0x0001, 0x000f, 0x003f, 0x0062, 0x003f, 0x000f, 0x0001, DUMMY, + 0x0000, 0x0008, 0x0031, 0x0060, 0x004d, 0x0018, 0x0002, DUMMY + } + /* + * The dummy padding is required in 7-tap mode because of how the + * registers are arranged physically. + */ + #undef DUMMY +}; + +/* + * __resizer_get_format - helper function for getting resizer format + * @res : pointer to resizer private structure + * @pad : pad number + * @fh : V4L2 subdev file handle + * @which : wanted subdev format + * return zero + */ +static struct v4l2_mbus_framefmt * +__resizer_get_format(struct isp_res_device *res, struct v4l2_subdev_fh *fh, + unsigned int pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(fh, pad); + else + return &res->formats[pad]; +} + +/* + * __resizer_get_crop - helper function for getting resizer crop rectangle + * @res : pointer to resizer private structure + * @fh : V4L2 subdev file handle + * @which : wanted subdev crop rectangle + */ +static struct v4l2_rect * +__resizer_get_crop(struct isp_res_device *res, struct v4l2_subdev_fh *fh, + enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_crop(fh, RESZ_PAD_SINK); + else + return &res->crop.request; +} + +/* + * resizer_set_filters - Set resizer filters + * @res: Device context. + * @h_coeff: horizontal coefficient + * @v_coeff: vertical coefficient + * Return none + */ +static void resizer_set_filters(struct isp_res_device *res, const u16 *h_coeff, + const u16 *v_coeff) +{ + struct isp_device *isp = to_isp_device(res); + u32 startaddr_h, startaddr_v, tmp_h, tmp_v; + int i; + + startaddr_h = ISPRSZ_HFILT10; + startaddr_v = ISPRSZ_VFILT10; + + for (i = 0; i < COEFF_CNT; i += 2) { + tmp_h = h_coeff[i] | + (h_coeff[i + 1] << ISPRSZ_HFILT_COEF1_SHIFT); + tmp_v = v_coeff[i] | + (v_coeff[i + 1] << ISPRSZ_VFILT_COEF1_SHIFT); + isp_reg_writel(isp, tmp_h, OMAP3_ISP_IOMEM_RESZ, startaddr_h); + isp_reg_writel(isp, tmp_v, OMAP3_ISP_IOMEM_RESZ, startaddr_v); + startaddr_h += 4; + startaddr_v += 4; + } +} + +/* + * resizer_set_bilinear - Chrominance horizontal algorithm select + * @res: Device context. + * @type: Filtering interpolation type. + * + * Filtering that is same as luminance processing is + * intended only for downsampling, and bilinear interpolation + * is intended only for upsampling. + */ +static void resizer_set_bilinear(struct isp_res_device *res, + enum resizer_chroma_algo type) +{ + struct isp_device *isp = to_isp_device(res); + + if (type == RSZ_BILINEAR) + isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_CBILIN); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_CBILIN); +} + +/* + * resizer_set_ycpos - Luminance and chrominance order + * @res: Device context. + * @order: order type. + */ +static void resizer_set_ycpos(struct isp_res_device *res, + enum v4l2_mbus_pixelcode pixelcode) +{ + struct isp_device *isp = to_isp_device(res); + + switch (pixelcode) { + case V4L2_MBUS_FMT_YUYV8_1X16: + isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_YCPOS); + break; + case V4L2_MBUS_FMT_UYVY8_1X16: + isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_YCPOS); + break; + default: + return; + } +} + +/* + * resizer_set_phase - Setup horizontal and vertical starting phase + * @res: Device context. + * @h_phase: horizontal phase parameters. + * @v_phase: vertical phase parameters. + * + * Horizontal and vertical phase range is 0 to 7 + */ +static void resizer_set_phase(struct isp_res_device *res, u32 h_phase, + u32 v_phase) +{ + struct isp_device *isp = to_isp_device(res); + u32 rgval = 0; + + rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & + ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK); + rgval |= (h_phase << ISPRSZ_CNT_HSTPH_SHIFT) & ISPRSZ_CNT_HSTPH_MASK; + rgval |= (v_phase << ISPRSZ_CNT_VSTPH_SHIFT) & ISPRSZ_CNT_VSTPH_MASK; + + isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT); +} + +/* + * resizer_set_luma - Setup luminance enhancer parameters + * @res: Device context. + * @luma: Structure for luminance enhancer parameters. + * + * Algorithm select: + * 0x0: Disable + * 0x1: [-1 2 -1]/2 high-pass filter + * 0x2: [-1 -2 6 -2 -1]/4 high-pass filter + * + * Maximum gain: + * The data is coded in U4Q4 representation. + * + * Slope: + * The data is coded in U4Q4 representation. + * + * Coring offset: + * The data is coded in U8Q0 representation. + * + * The new luminance value is computed as: + * Y += HPF(Y) x max(GAIN, (HPF(Y) - CORE) x SLOP + 8) >> 4. + */ +static void resizer_set_luma(struct isp_res_device *res, + struct resizer_luma_yenh *luma) +{ + struct isp_device *isp = to_isp_device(res); + u32 rgval = 0; + + rgval = (luma->algo << ISPRSZ_YENH_ALGO_SHIFT) + & ISPRSZ_YENH_ALGO_MASK; + rgval |= (luma->gain << ISPRSZ_YENH_GAIN_SHIFT) + & ISPRSZ_YENH_GAIN_MASK; + rgval |= (luma->slope << ISPRSZ_YENH_SLOP_SHIFT) + & ISPRSZ_YENH_SLOP_MASK; + rgval |= (luma->core << ISPRSZ_YENH_CORE_SHIFT) + & ISPRSZ_YENH_CORE_MASK; + + isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH); +} + +/* + * resizer_set_source - Input source select + * @res: Device context. + * @source: Input source type + * + * If this field is set to RESIZER_INPUT_VP, the resizer input is fed from + * Preview/CCDC engine, otherwise from memory. + */ +static void resizer_set_source(struct isp_res_device *res, + enum resizer_input_entity source) +{ + struct isp_device *isp = to_isp_device(res); + + if (source == RESIZER_INPUT_MEMORY) + isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_INPSRC); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_INPSRC); +} + +/* + * resizer_set_ratio - Setup horizontal and vertical resizing value + * @res: Device context. + * @ratio: Structure for ratio parameters. + * + * Resizing range from 64 to 1024 + */ +static void resizer_set_ratio(struct isp_res_device *res, + const struct resizer_ratio *ratio) +{ + struct isp_device *isp = to_isp_device(res); + const u16 *h_filter, *v_filter; + u32 rgval = 0; + + rgval = isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & + ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK); + rgval |= ((ratio->horz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) + & ISPRSZ_CNT_HRSZ_MASK; + rgval |= ((ratio->vert - 1) << ISPRSZ_CNT_VRSZ_SHIFT) + & ISPRSZ_CNT_VRSZ_MASK; + isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT); + + /* prepare horizontal filter coefficients */ + if (ratio->horz > MID_RESIZE_VALUE) + h_filter = &filter_coefs.h_filter_coef_7tap[0]; + else + h_filter = &filter_coefs.h_filter_coef_4tap[0]; + + /* prepare vertical filter coefficients */ + if (ratio->vert > MID_RESIZE_VALUE) + v_filter = &filter_coefs.v_filter_coef_7tap[0]; + else + v_filter = &filter_coefs.v_filter_coef_4tap[0]; + + resizer_set_filters(res, h_filter, v_filter); +} + +/* + * resizer_set_dst_size - Setup the output height and width + * @res: Device context. + * @width: Output width. + * @height: Output height. + * + * Width : + * The value must be EVEN. + * + * Height: + * The number of bytes written to SDRAM must be + * a multiple of 16-bytes if the vertical resizing factor + * is greater than 1x (upsizing) + */ +static void resizer_set_output_size(struct isp_res_device *res, + u32 width, u32 height) +{ + struct isp_device *isp = to_isp_device(res); + u32 rgval = 0; + + dev_dbg(isp->dev, "Output size[w/h]: %dx%d\n", width, height); + rgval = (width << ISPRSZ_OUT_SIZE_HORZ_SHIFT) + & ISPRSZ_OUT_SIZE_HORZ_MASK; + rgval |= (height << ISPRSZ_OUT_SIZE_VERT_SHIFT) + & ISPRSZ_OUT_SIZE_VERT_MASK; + isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE); +} + +/* + * resizer_set_output_offset - Setup memory offset for the output lines. + * @res: Device context. + * @offset: Memory offset. + * + * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte + * boundary; the 5 LSBs are read-only. For optimal use of SDRAM bandwidth, + * the SDRAM line offset must be set on a 256-byte boundary + */ +static void resizer_set_output_offset(struct isp_res_device *res, u32 offset) +{ + struct isp_device *isp = to_isp_device(res); + + isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF); +} + +/* + * resizer_set_start - Setup vertical and horizontal start position + * @res: Device context. + * @left: Horizontal start position. + * @top: Vertical start position. + * + * Vertical start line: + * This field makes sense only when the resizer obtains its input + * from the preview engine/CCDC + * + * Horizontal start pixel: + * Pixels are coded on 16 bits for YUV and 8 bits for color separate data. + * When the resizer gets its input from SDRAM, this field must be set + * to <= 15 for YUV 16-bit data and <= 31 for 8-bit color separate data + */ +static void resizer_set_start(struct isp_res_device *res, u32 left, u32 top) +{ + struct isp_device *isp = to_isp_device(res); + u32 rgval = 0; + + rgval = (left << ISPRSZ_IN_START_HORZ_ST_SHIFT) + & ISPRSZ_IN_START_HORZ_ST_MASK; + rgval |= (top << ISPRSZ_IN_START_VERT_ST_SHIFT) + & ISPRSZ_IN_START_VERT_ST_MASK; + + isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START); +} + +/* + * resizer_set_input_size - Setup the input size + * @res: Device context. + * @width: The range is 0 to 4095 pixels + * @height: The range is 0 to 4095 lines + */ +static void resizer_set_input_size(struct isp_res_device *res, + u32 width, u32 height) +{ + struct isp_device *isp = to_isp_device(res); + u32 rgval = 0; + + dev_dbg(isp->dev, "Input size[w/h]: %dx%d\n", width, height); + + rgval = (width << ISPRSZ_IN_SIZE_HORZ_SHIFT) + & ISPRSZ_IN_SIZE_HORZ_MASK; + rgval |= (height << ISPRSZ_IN_SIZE_VERT_SHIFT) + & ISPRSZ_IN_SIZE_VERT_MASK; + + isp_reg_writel(isp, rgval, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE); +} + +/* + * resizer_set_src_offs - Setup the memory offset for the input lines + * @res: Device context. + * @offset: Memory offset. + * + * The 5 LSBs are forced to be zeros by the hardware to align on a 32-byte + * boundary; the 5 LSBs are read-only. This field must be programmed to be + * 0x0 if the resizer input is from preview engine/CCDC. + */ +static void resizer_set_input_offset(struct isp_res_device *res, u32 offset) +{ + struct isp_device *isp = to_isp_device(res); + + isp_reg_writel(isp, offset, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF); +} + +/* + * resizer_set_intype - Input type select + * @res: Device context. + * @type: Pixel format type. + */ +static void resizer_set_intype(struct isp_res_device *res, + enum resizer_colors_type type) +{ + struct isp_device *isp = to_isp_device(res); + + if (type == RSZ_COLOR8) + isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_INPTYP); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, + ISPRSZ_CNT_INPTYP); +} + +/* + * __resizer_set_inaddr - Helper function for set input address + * @res : pointer to resizer private data structure + * @addr: input address + * return none + */ +static void __resizer_set_inaddr(struct isp_res_device *res, u32 addr) +{ + struct isp_device *isp = to_isp_device(res); + + isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD); +} + +/* + * The data rate at the horizontal resizer output must not exceed half the + * functional clock or 100 MP/s, whichever is lower. According to the TRM + * there's no similar requirement for the vertical resizer output. However + * experience showed that vertical upscaling by 4 leads to SBL overflows (with + * data rates at the resizer output exceeding 300 MP/s). Limiting the resizer + * output data rate to the functional clock or 200 MP/s, whichever is lower, + * seems to get rid of SBL overflows. + * + * The maximum data rate at the output of the horizontal resizer can thus be + * computed with + * + * max intermediate rate <= L3 clock * input height / output height + * max intermediate rate <= L3 clock / 2 + * + * The maximum data rate at the resizer input is then + * + * max input rate <= max intermediate rate * input width / output width + * + * where the input width and height are the resizer input crop rectangle size. + * The TRM doesn't clearly explain if that's a maximum instant data rate or a + * maximum average data rate. + */ +void omap3isp_resizer_max_rate(struct isp_res_device *res, + unsigned int *max_rate) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity); + const struct v4l2_mbus_framefmt *ofmt = &res->formats[RESZ_PAD_SOURCE]; + unsigned long limit = min(pipe->l3_ick, 200000000UL); + unsigned long clock; + + clock = div_u64((u64)limit * res->crop.active.height, ofmt->height); + clock = min(clock, limit / 2); + *max_rate = div_u64((u64)clock * res->crop.active.width, ofmt->width); +} + +/* + * When the resizer processes images from memory, the driver must slow down read + * requests on the input to at least comply with the internal data rate + * requirements. If the application real-time requirements can cope with slower + * processing, the resizer can be slowed down even more to put less pressure on + * the overall system. + * + * When the resizer processes images on the fly (either from the CCDC or the + * preview module), the same data rate requirements apply but they can't be + * enforced at the resizer level. The image input module (sensor, CCP2 or + * preview module) must not provide image data faster than the resizer can + * process. + * + * For live image pipelines, the data rate is set by the frame format, size and + * rate. The sensor output frame rate must not exceed the maximum resizer data + * rate. + * + * The resizer slows down read requests by inserting wait cycles in the SBL + * requests. The maximum number of 256-byte requests per second can be computed + * as (the data rate is multiplied by 2 to convert from pixels per second to + * bytes per second) + * + * request per second = data rate * 2 / 256 + * cycles per request = cycles per second / requests per second + * + * The number of cycles per second is controlled by the L3 clock, leading to + * + * cycles per request = L3 frequency / 2 * 256 / data rate + */ +static void resizer_adjust_bandwidth(struct isp_res_device *res) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity); + struct isp_device *isp = to_isp_device(res); + unsigned long l3_ick = pipe->l3_ick; + struct v4l2_fract *timeperframe; + unsigned int cycles_per_frame; + unsigned int requests_per_frame; + unsigned int cycles_per_request; + unsigned int granularity; + unsigned int minimum; + unsigned int maximum; + unsigned int value; + + if (res->input != RESIZER_INPUT_MEMORY) { + isp_reg_clr(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, + ISPSBL_SDR_REQ_RSZ_EXP_MASK); + return; + } + + switch (isp->revision) { + case ISP_REVISION_1_0: + case ISP_REVISION_2_0: + default: + granularity = 1024; + break; + + case ISP_REVISION_15_0: + granularity = 32; + break; + } + + /* Compute the minimum number of cycles per request, based on the + * pipeline maximum data rate. This is an absolute lower bound if we + * don't want SBL overflows, so round the value up. + */ + cycles_per_request = div_u64((u64)l3_ick / 2 * 256 + pipe->max_rate - 1, + pipe->max_rate); + minimum = DIV_ROUND_UP(cycles_per_request, granularity); + + /* Compute the maximum number of cycles per request, based on the + * requested frame rate. This is a soft upper bound to achieve a frame + * rate equal or higher than the requested value, so round the value + * down. + */ + timeperframe = &pipe->max_timeperframe; + + requests_per_frame = DIV_ROUND_UP(res->crop.active.width * 2, 256) + * res->crop.active.height; + cycles_per_frame = div_u64((u64)l3_ick * timeperframe->numerator, + timeperframe->denominator); + cycles_per_request = cycles_per_frame / requests_per_frame; + + maximum = cycles_per_request / granularity; + + value = max(minimum, maximum); + + dev_dbg(isp->dev, "%s: cycles per request = %u\n", __func__, value); + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_SDR_REQ_EXP, + ISPSBL_SDR_REQ_RSZ_EXP_MASK, + value << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT); +} + +/* + * omap3isp_resizer_busy - Checks if ISP resizer is busy. + * + * Returns busy field from ISPRSZ_PCR register. + */ +int omap3isp_resizer_busy(struct isp_res_device *res) +{ + struct isp_device *isp = to_isp_device(res); + + return isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) & + ISPRSZ_PCR_BUSY; +} + +/* + * resizer_set_inaddr - Sets the memory address of the input frame. + * @addr: 32bit memory address aligned on 32byte boundary. + */ +static void resizer_set_inaddr(struct isp_res_device *res, u32 addr) +{ + res->addr_base = addr; + + /* This will handle crop settings in stream off state */ + if (res->crop_offset) + addr += res->crop_offset & ~0x1f; + + __resizer_set_inaddr(res, addr); +} + +/* + * Configures the memory address to which the output frame is written. + * @addr: 32bit memory address aligned on 32byte boundary. + * Note: For SBL efficiency reasons the address should be on a 256-byte + * boundary. + */ +static void resizer_set_outaddr(struct isp_res_device *res, u32 addr) +{ + struct isp_device *isp = to_isp_device(res); + + /* + * Set output address. This needs to be in its own function + * because it changes often. + */ + isp_reg_writel(isp, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT, + OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD); +} + +/* + * resizer_print_status - Prints the values of the resizer module registers. + */ +#define RSZ_PRINT_REGISTER(isp, name)\ + dev_dbg(isp->dev, "###RSZ " #name "=0x%08x\n", \ + isp_reg_readl(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_##name)) + +static void resizer_print_status(struct isp_res_device *res) +{ + struct isp_device *isp = to_isp_device(res); + + dev_dbg(isp->dev, "-------------Resizer Register dump----------\n"); + + RSZ_PRINT_REGISTER(isp, PCR); + RSZ_PRINT_REGISTER(isp, CNT); + RSZ_PRINT_REGISTER(isp, OUT_SIZE); + RSZ_PRINT_REGISTER(isp, IN_START); + RSZ_PRINT_REGISTER(isp, IN_SIZE); + RSZ_PRINT_REGISTER(isp, SDR_INADD); + RSZ_PRINT_REGISTER(isp, SDR_INOFF); + RSZ_PRINT_REGISTER(isp, SDR_OUTADD); + RSZ_PRINT_REGISTER(isp, SDR_OUTOFF); + RSZ_PRINT_REGISTER(isp, YENH); + + dev_dbg(isp->dev, "--------------------------------------------\n"); +} + +/* + * resizer_calc_ratios - Helper function for calculate resizer ratios + * @res: pointer to resizer private data structure + * @input: input frame size + * @output: output frame size + * @ratio : return calculated ratios + * return none + * + * The resizer uses a polyphase sample rate converter. The upsampling filter + * has a fixed number of phases that depend on the resizing ratio. As the ratio + * computation depends on the number of phases, we need to compute a first + * approximation and then refine it. + * + * The input/output/ratio relationship is given by the OMAP34xx TRM: + * + * - 8-phase, 4-tap mode (RSZ = 64 ~ 512) + * iw = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7 + * ih = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4 + * - 4-phase, 7-tap mode (RSZ = 513 ~ 1024) + * iw = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7 + * ih = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7 + * + * iw and ih are the input width and height after cropping. Those equations need + * to be satisfied exactly for the resizer to work correctly. + * + * Reverting the equations, we can compute the resizing ratios with + * + * - 8-phase, 4-tap mode + * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1) + * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1) + * - 4-phase, 7-tap mode + * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1) + * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) + * + * The ratios are integer values, and must be rounded down to ensure that the + * cropped input size is not bigger than the uncropped input size. As the ratio + * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the + * 7-tap mode equations to compute a ratio approximation. + * + * We first clamp the output size according to the hardware capabilitie to avoid + * auto-cropping the input more than required to satisfy the TRM equations. The + * minimum output size is achieved with a scaling factor of 1024. It is thus + * computed using the 7-tap equations. + * + * min ow = ((iw - 7) * 256 - 32 - 64 * sph) / 1024 + 1 + * min oh = ((ih - 7) * 256 - 32 - 64 * spv) / 1024 + 1 + * + * Similarly, the maximum output size is achieved with a scaling factor of 64 + * and computed using the 4-tap equations. + * + * max ow = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / 64 + 1 + * max oh = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1 + * + * The additional +255 term compensates for the round down operation performed + * by the TRM equations when shifting the value right by 8 bits. + * + * We then compute and clamp the ratios (x1/4 ~ x4). Clamping the output size to + * the maximum value guarantees that the ratio value will never be smaller than + * the minimum, but it could still slightly exceed the maximum. Clamping the + * ratio will thus result in a resizing factor slightly larger than the + * requested value. + * + * To accomodate that, and make sure the TRM equations are satisfied exactly, we + * compute the input crop rectangle as the last step. + * + * As if the situation wasn't complex enough, the maximum output width depends + * on the vertical resizing ratio. Fortunately, the output height doesn't + * depend on the horizontal resizing ratio. We can then start by computing the + * output height and the vertical ratio, and then move to computing the output + * width and the horizontal ratio. + */ +static void resizer_calc_ratios(struct isp_res_device *res, + struct v4l2_rect *input, + struct v4l2_mbus_framefmt *output, + struct resizer_ratio *ratio) +{ + struct isp_device *isp = to_isp_device(res); + const unsigned int spv = DEFAULT_PHASE; + const unsigned int sph = DEFAULT_PHASE; + unsigned int upscaled_width; + unsigned int upscaled_height; + unsigned int min_width; + unsigned int min_height; + unsigned int max_width; + unsigned int max_height; + unsigned int width_alignment; + + /* + * Clamp the output height based on the hardware capabilities and + * compute the vertical resizing ratio. + */ + min_height = ((input->height - 7) * 256 - 32 - 64 * spv) / 1024 + 1; + min_height = max_t(unsigned int, min_height, MIN_OUT_HEIGHT); + max_height = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / 64 + 1; + max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); + output->height = clamp(output->height, min_height, max_height); + + ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + / (output->height - 1); + ratio->vert = clamp_t(unsigned int, ratio->vert, + MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); + + if (ratio->vert <= MID_RESIZE_VALUE) { + upscaled_height = (output->height - 1) * ratio->vert + + 32 * spv + 16; + input->height = (upscaled_height >> 8) + 4; + } else { + upscaled_height = (output->height - 1) * ratio->vert + + 64 * spv + 32; + input->height = (upscaled_height >> 8) + 7; + } + + /* + * Compute the minimum and maximum output widths based on the hardware + * capabilities. The maximum depends on the vertical resizing ratio. + */ + min_width = ((input->width - 7) * 256 - 32 - 64 * sph) / 1024 + 1; + min_width = max_t(unsigned int, min_width, MIN_OUT_WIDTH); + + if (ratio->vert <= MID_RESIZE_VALUE) { + switch (isp->revision) { + case ISP_REVISION_1_0: + max_width = MAX_4TAP_OUT_WIDTH_ES1; + break; + + case ISP_REVISION_2_0: + default: + max_width = MAX_4TAP_OUT_WIDTH_ES2; + break; + + case ISP_REVISION_15_0: + max_width = MAX_4TAP_OUT_WIDTH_3630; + break; + } + } else { + switch (isp->revision) { + case ISP_REVISION_1_0: + max_width = MAX_7TAP_OUT_WIDTH_ES1; + break; + + case ISP_REVISION_2_0: + default: + max_width = MAX_7TAP_OUT_WIDTH_ES2; + break; + + case ISP_REVISION_15_0: + max_width = MAX_7TAP_OUT_WIDTH_3630; + break; + } + } + max_width = min(((input->width - 7) * 256 + 255 - 16 - 32 * sph) / 64 + + 1, max_width); + + /* + * The output width must be even, and must be a multiple of 16 bytes + * when upscaling vertically. Clamp the output width to the valid range. + * Take the alignment into account (the maximum width in 7-tap mode on + * ES2 isn't a multiple of 8) and align the result up to make sure it + * won't be smaller than the minimum. + */ + width_alignment = ratio->vert < 256 ? 8 : 2; + output->width = clamp(output->width, min_width, + max_width & ~(width_alignment - 1)); + output->width = ALIGN(output->width, width_alignment); + + ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + / (output->width - 1); + ratio->horz = clamp_t(unsigned int, ratio->horz, + MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); + + if (ratio->horz <= MID_RESIZE_VALUE) { + upscaled_width = (output->width - 1) * ratio->horz + + 32 * sph + 16; + input->width = (upscaled_width >> 8) + 7; + } else { + upscaled_width = (output->width - 1) * ratio->horz + + 64 * sph + 32; + input->width = (upscaled_width >> 8) + 7; + } +} + +/* + * resizer_set_crop_params - Setup hardware with cropping parameters + * @res : resizer private structure + * @crop_rect : current crop rectangle + * @ratio : resizer ratios + * return none + */ +static void resizer_set_crop_params(struct isp_res_device *res, + const struct v4l2_mbus_framefmt *input, + const struct v4l2_mbus_framefmt *output) +{ + resizer_set_ratio(res, &res->ratio); + + /* Set chrominance horizontal algorithm */ + if (res->ratio.horz >= RESIZE_DIVISOR) + resizer_set_bilinear(res, RSZ_THE_SAME); + else + resizer_set_bilinear(res, RSZ_BILINEAR); + + resizer_adjust_bandwidth(res); + + if (res->input == RESIZER_INPUT_MEMORY) { + /* Calculate additional offset for crop */ + res->crop_offset = (res->crop.active.top * input->width + + res->crop.active.left) * 2; + /* + * Write lowest 4 bits of horizontal pixel offset (in pixels), + * vertical start must be 0. + */ + resizer_set_start(res, (res->crop_offset / 2) & 0xf, 0); + + /* + * Set start (read) address for cropping, in bytes. + * Lowest 5 bits must be zero. + */ + __resizer_set_inaddr(res, + res->addr_base + (res->crop_offset & ~0x1f)); + } else { + /* + * Set vertical start line and horizontal starting pixel. + * If the input is from CCDC/PREV, horizontal start field is + * in bytes (twice number of pixels). + */ + resizer_set_start(res, res->crop.active.left * 2, + res->crop.active.top); + /* Input address and offset must be 0 for preview/ccdc input */ + __resizer_set_inaddr(res, 0); + resizer_set_input_offset(res, 0); + } + + /* Set the input size */ + resizer_set_input_size(res, res->crop.active.width, + res->crop.active.height); +} + +static void resizer_configure(struct isp_res_device *res) +{ + struct v4l2_mbus_framefmt *informat, *outformat; + struct resizer_luma_yenh luma = {0, 0, 0, 0}; + + resizer_set_source(res, res->input); + + informat = &res->formats[RESZ_PAD_SINK]; + outformat = &res->formats[RESZ_PAD_SOURCE]; + + /* RESZ_PAD_SINK */ + if (res->input == RESIZER_INPUT_VP) + resizer_set_input_offset(res, 0); + else + resizer_set_input_offset(res, ALIGN(informat->width, 0x10) * 2); + + /* YUV422 interleaved, default phase, no luma enhancement */ + resizer_set_intype(res, RSZ_YUV422); + resizer_set_ycpos(res, informat->code); + resizer_set_phase(res, DEFAULT_PHASE, DEFAULT_PHASE); + resizer_set_luma(res, &luma); + + /* RESZ_PAD_SOURCE */ + resizer_set_output_offset(res, ALIGN(outformat->width * 2, 32)); + resizer_set_output_size(res, outformat->width, outformat->height); + + resizer_set_crop_params(res, informat, outformat); +} + +/* ----------------------------------------------------------------------------- + * Interrupt handling + */ + +static void resizer_enable_oneshot(struct isp_res_device *res) +{ + struct isp_device *isp = to_isp_device(res); + + isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR, + ISPRSZ_PCR_ENABLE | ISPRSZ_PCR_ONESHOT); +} + +void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res) +{ + /* + * If ISP_VIDEO_DMAQUEUE_QUEUED is set, DMA queue had an underrun + * condition, the module was paused and now we have a buffer queued + * on the output again. Restart the pipeline if running in continuous + * mode. + */ + if (res->state == ISP_PIPELINE_STREAM_CONTINUOUS && + res->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) { + resizer_enable_oneshot(res); + isp_video_dmaqueue_flags_clr(&res->video_out); + } +} + +static void resizer_isr_buffer(struct isp_res_device *res) +{ + struct isp_pipeline *pipe = to_isp_pipeline(&res->subdev.entity); + struct isp_buffer *buffer; + int restart = 0; + + if (res->state == ISP_PIPELINE_STREAM_STOPPED) + return; + + /* Complete the output buffer and, if reading from memory, the input + * buffer. + */ + buffer = omap3isp_video_buffer_next(&res->video_out, res->error); + if (buffer != NULL) { + resizer_set_outaddr(res, buffer->isp_addr); + restart = 1; + } + + pipe->state |= ISP_PIPELINE_IDLE_OUTPUT; + + if (res->input == RESIZER_INPUT_MEMORY) { + buffer = omap3isp_video_buffer_next(&res->video_in, 0); + if (buffer != NULL) + resizer_set_inaddr(res, buffer->isp_addr); + pipe->state |= ISP_PIPELINE_IDLE_INPUT; + } + + if (res->state == ISP_PIPELINE_STREAM_SINGLESHOT) { + if (isp_pipeline_ready(pipe)) + omap3isp_pipeline_set_stream(pipe, + ISP_PIPELINE_STREAM_SINGLESHOT); + } else { + /* If an underrun occurs, the video queue operation handler will + * restart the resizer. Otherwise restart it immediately. + */ + if (restart) + resizer_enable_oneshot(res); + } + + res->error = 0; +} + +/* + * omap3isp_resizer_isr - ISP resizer interrupt handler + * + * Manage the resizer video buffers and configure shadowed and busy-locked + * registers. + */ +void omap3isp_resizer_isr(struct isp_res_device *res) +{ + struct v4l2_mbus_framefmt *informat, *outformat; + + if (omap3isp_module_sync_is_stopping(&res->wait, &res->stopping)) + return; + + if (res->applycrop) { + outformat = __resizer_get_format(res, NULL, RESZ_PAD_SOURCE, + V4L2_SUBDEV_FORMAT_ACTIVE); + informat = __resizer_get_format(res, NULL, RESZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_ACTIVE); + resizer_set_crop_params(res, informat, outformat); + res->applycrop = 0; + } + + resizer_isr_buffer(res); +} + +/* ----------------------------------------------------------------------------- + * ISP video operations + */ + +static int resizer_video_queue(struct isp_video *video, + struct isp_buffer *buffer) +{ + struct isp_res_device *res = &video->isp->isp_res; + + if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + resizer_set_inaddr(res, buffer->isp_addr); + + /* + * We now have a buffer queued on the output. Despite what the + * TRM says, the resizer can't be restarted immediately. + * Enabling it in one shot mode in the middle of a frame (or at + * least asynchronously to the frame) results in the output + * being shifted randomly left/right and up/down, as if the + * hardware didn't synchronize itself to the beginning of the + * frame correctly. + * + * Restart the resizer on the next sync interrupt if running in + * continuous mode or when starting the stream. + */ + if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + resizer_set_outaddr(res, buffer->isp_addr); + + return 0; +} + +static const struct isp_video_operations resizer_video_ops = { + .queue = resizer_video_queue, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +/* + * resizer_set_stream - Enable/Disable streaming on resizer subdev + * @sd: ISP resizer V4L2 subdev + * @enable: 1 == Enable, 0 == Disable + * + * The resizer hardware can't be enabled without a memory buffer to write to. + * As the s_stream operation is called in response to a STREAMON call without + * any buffer queued yet, just update the state field and return immediately. + * The resizer will be enabled in resizer_video_queue(). + */ +static int resizer_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct isp_res_device *res = v4l2_get_subdevdata(sd); + struct isp_video *video_out = &res->video_out; + struct isp_device *isp = to_isp_device(res); + struct device *dev = to_device(res); + + if (res->state == ISP_PIPELINE_STREAM_STOPPED) { + if (enable == ISP_PIPELINE_STREAM_STOPPED) + return 0; + + omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_RESIZER); + resizer_configure(res); + res->error = 0; + resizer_print_status(res); + } + + switch (enable) { + case ISP_PIPELINE_STREAM_CONTINUOUS: + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE); + if (video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED) { + resizer_enable_oneshot(res); + isp_video_dmaqueue_flags_clr(video_out); + } + break; + + case ISP_PIPELINE_STREAM_SINGLESHOT: + if (res->input == RESIZER_INPUT_MEMORY) + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_READ); + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_RESIZER_WRITE); + + resizer_enable_oneshot(res); + break; + + case ISP_PIPELINE_STREAM_STOPPED: + if (omap3isp_module_sync_idle(&sd->entity, &res->wait, + &res->stopping)) + dev_dbg(dev, "%s: module stop timeout.\n", sd->name); + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_RESIZER_READ | + OMAP3_ISP_SBL_RESIZER_WRITE); + omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_RESIZER); + isp_video_dmaqueue_flags_clr(video_out); + break; + } + + res->state = enable; + return 0; +} + +/* + * resizer_g_crop - handle get crop subdev operation + * @sd : pointer to v4l2 subdev structure + * @pad : subdev pad + * @crop : pointer to crop structure + * @which : active or try format + * return zero + */ +static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_res_device *res = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + struct resizer_ratio ratio; + + /* Only sink pad has crop capability */ + if (crop->pad != RESZ_PAD_SINK) + return -EINVAL; + + format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which); + crop->rect = *__resizer_get_crop(res, fh, crop->which); + resizer_calc_ratios(res, &crop->rect, format, &ratio); + + return 0; +} + +/* + * resizer_try_crop - mangles crop parameters. + */ +static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink, + const struct v4l2_mbus_framefmt *source, + struct v4l2_rect *crop) +{ + const unsigned int spv = DEFAULT_PHASE; + const unsigned int sph = DEFAULT_PHASE; + + /* Crop rectangle is constrained to the output size so that zoom ratio + * cannot exceed +/-4.0. + */ + unsigned int min_width = + ((32 * sph + (source->width - 1) * 64 + 16) >> 8) + 7; + unsigned int min_height = + ((32 * spv + (source->height - 1) * 64 + 16) >> 8) + 4; + unsigned int max_width = + ((64 * sph + (source->width - 1) * 1024 + 32) >> 8) + 7; + unsigned int max_height = + ((64 * spv + (source->height - 1) * 1024 + 32) >> 8) + 7; + + crop->width = clamp_t(u32, crop->width, min_width, max_width); + crop->height = clamp_t(u32, crop->height, min_height, max_height); + + /* Crop can not go beyond of the input rectangle */ + crop->left = clamp_t(u32, crop->left, 0, sink->width - MIN_IN_WIDTH); + crop->width = clamp_t(u32, crop->width, MIN_IN_WIDTH, + sink->width - crop->left); + crop->top = clamp_t(u32, crop->top, 0, sink->height - MIN_IN_HEIGHT); + crop->height = clamp_t(u32, crop->height, MIN_IN_HEIGHT, + sink->height - crop->top); +} + +/* + * resizer_s_crop - handle set crop subdev operation + * @sd : pointer to v4l2 subdev structure + * @pad : subdev pad + * @crop : pointer to crop structure + * @which : active or try format + * return -EINVAL or zero when succeed + */ +static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_crop *crop) +{ + struct isp_res_device *res = v4l2_get_subdevdata(sd); + struct isp_device *isp = to_isp_device(res); + struct v4l2_mbus_framefmt *format_sink, *format_source; + struct resizer_ratio ratio; + + /* Only sink pad has crop capability */ + if (crop->pad != RESZ_PAD_SINK) + return -EINVAL; + + format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK, + crop->which); + format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, + crop->which); + + dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__, + crop->rect.left, crop->rect.top, crop->rect.width, + crop->rect.height, crop->which); + + dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__, + format_sink->width, format_sink->height, + format_source->width, format_source->height); + + resizer_try_crop(format_sink, format_source, &crop->rect); + *__resizer_get_crop(res, fh, crop->which) = crop->rect; + resizer_calc_ratios(res, &crop->rect, format_source, &ratio); + + if (crop->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + res->ratio = ratio; + res->crop.active = crop->rect; + + /* + * s_crop can be called while streaming is on. In this case + * the crop values will be set in the next IRQ. + */ + if (res->state != ISP_PIPELINE_STREAM_STOPPED) + res->applycrop = 1; + + return 0; +} + +/* resizer pixel formats */ +static const unsigned int resizer_formats[] = { + V4L2_MBUS_FMT_UYVY8_1X16, + V4L2_MBUS_FMT_YUYV8_1X16, +}; + +static unsigned int resizer_max_in_width(struct isp_res_device *res) +{ + struct isp_device *isp = to_isp_device(res); + + if (res->input == RESIZER_INPUT_MEMORY) { + return MAX_IN_WIDTH_MEMORY_MODE; + } else { + if (isp->revision == ISP_REVISION_1_0) + return MAX_IN_WIDTH_ONTHEFLY_MODE_ES1; + else + return MAX_IN_WIDTH_ONTHEFLY_MODE_ES2; + } +} + +/* + * resizer_try_format - Handle try format by pad subdev method + * @res : ISP resizer device + * @fh : V4L2 subdev file handle + * @pad : pad num + * @fmt : pointer to v4l2 format structure + * @which : wanted subdev format + */ +static void resizer_try_format(struct isp_res_device *res, + struct v4l2_subdev_fh *fh, unsigned int pad, + struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + struct resizer_ratio ratio; + struct v4l2_rect crop; + + switch (pad) { + case RESZ_PAD_SINK: + if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 && + fmt->code != V4L2_MBUS_FMT_UYVY8_1X16) + fmt->code = V4L2_MBUS_FMT_YUYV8_1X16; + + fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH, + resizer_max_in_width(res)); + fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT, + MAX_IN_HEIGHT); + break; + + case RESZ_PAD_SOURCE: + format = __resizer_get_format(res, fh, RESZ_PAD_SINK, which); + fmt->code = format->code; + + crop = *__resizer_get_crop(res, fh, which); + resizer_calc_ratios(res, &crop, fmt, &ratio); + break; + } + + fmt->colorspace = V4L2_COLORSPACE_JPEG; + fmt->field = V4L2_FIELD_NONE; +} + +/* + * resizer_enum_mbus_code - Handle pixel format enumeration + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @code : pointer to v4l2_subdev_mbus_code_enum structure + * return -EINVAL or zero on success + */ +static int resizer_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct isp_res_device *res = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + if (code->pad == RESZ_PAD_SINK) { + if (code->index >= ARRAY_SIZE(resizer_formats)) + return -EINVAL; + + code->code = resizer_formats[code->index]; + } else { + if (code->index != 0) + return -EINVAL; + + format = __resizer_get_format(res, fh, RESZ_PAD_SINK, + V4L2_SUBDEV_FORMAT_TRY); + code->code = format->code; + } + + return 0; +} + +static int resizer_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct isp_res_device *res = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt format; + + if (fse->index != 0) + return -EINVAL; + + format.code = fse->code; + format.width = 1; + format.height = 1; + resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->min_width = format.width; + fse->min_height = format.height; + + if (format.code != fse->code) + return -EINVAL; + + format.code = fse->code; + format.width = -1; + format.height = -1; + resizer_try_format(res, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); + fse->max_width = format.width; + fse->max_height = format.height; + + return 0; +} + +/* + * resizer_get_format - Handle get format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt : pointer to v4l2 subdev format structure + * return -EINVAL or zero on sucess + */ +static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_res_device *res = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + + format = __resizer_get_format(res, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + fmt->format = *format; + return 0; +} + +/* + * resizer_set_format - Handle set format by pads subdev method + * @sd : pointer to v4l2 subdev structure + * @fh : V4L2 subdev file handle + * @fmt : pointer to v4l2 subdev format structure + * return -EINVAL or zero on success + */ +static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct isp_res_device *res = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + format = __resizer_get_format(res, fh, fmt->pad, fmt->which); + if (format == NULL) + return -EINVAL; + + resizer_try_format(res, fh, fmt->pad, &fmt->format, fmt->which); + *format = fmt->format; + + if (fmt->pad == RESZ_PAD_SINK) { + /* reset crop rectangle */ + crop = __resizer_get_crop(res, fh, fmt->which); + crop->left = 0; + crop->top = 0; + crop->width = fmt->format.width; + crop->height = fmt->format.height; + + /* Propagate the format from sink to source */ + format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, + fmt->which); + *format = fmt->format; + resizer_try_format(res, fh, RESZ_PAD_SOURCE, format, + fmt->which); + } + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + /* Compute and store the active crop rectangle and resizer + * ratios. format already points to the source pad active + * format. + */ + res->crop.active = res->crop.request; + resizer_calc_ratios(res, &res->crop.active, format, + &res->ratio); + } + + return 0; +} + +/* + * resizer_init_formats - Initialize formats on all pads + * @sd: ISP resizer V4L2 subdevice + * @fh: V4L2 subdev file handle + * + * Initialize all pad formats with default values. If fh is not NULL, try + * formats are initialized on the file handle. Otherwise active formats are + * initialized on the device. + */ +static int resizer_init_formats(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct v4l2_subdev_format format; + + memset(&format, 0, sizeof(format)); + format.pad = RESZ_PAD_SINK; + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + format.format.code = V4L2_MBUS_FMT_YUYV8_1X16; + format.format.width = 4096; + format.format.height = 4096; + resizer_set_format(sd, fh, &format); + + return 0; +} + +/* subdev video operations */ +static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = { + .s_stream = resizer_set_stream, +}; + +/* subdev pad operations */ +static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = { + .enum_mbus_code = resizer_enum_mbus_code, + .enum_frame_size = resizer_enum_frame_size, + .get_fmt = resizer_get_format, + .set_fmt = resizer_set_format, + .get_crop = resizer_g_crop, + .set_crop = resizer_s_crop, +}; + +/* subdev operations */ +static const struct v4l2_subdev_ops resizer_v4l2_ops = { + .video = &resizer_v4l2_video_ops, + .pad = &resizer_v4l2_pad_ops, +}; + +/* subdev internal operations */ +static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = { + .open = resizer_init_formats, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +/* + * resizer_link_setup - Setup resizer connections. + * @entity : Pointer to media entity structure + * @local : Pointer to local pad array + * @remote : Pointer to remote pad array + * @flags : Link flags + * return -EINVAL or zero on success + */ +static int resizer_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct isp_res_device *res = v4l2_get_subdevdata(sd); + + switch (local->index | media_entity_type(remote->entity)) { + case RESZ_PAD_SINK | MEDIA_ENT_T_DEVNODE: + /* read from memory */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (res->input == RESIZER_INPUT_VP) + return -EBUSY; + res->input = RESIZER_INPUT_MEMORY; + } else { + if (res->input == RESIZER_INPUT_MEMORY) + res->input = RESIZER_INPUT_NONE; + } + break; + + case RESZ_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: + /* read from ccdc or previewer */ + if (flags & MEDIA_LNK_FL_ENABLED) { + if (res->input == RESIZER_INPUT_MEMORY) + return -EBUSY; + res->input = RESIZER_INPUT_VP; + } else { + if (res->input == RESIZER_INPUT_VP) + res->input = RESIZER_INPUT_NONE; + } + break; + + case RESZ_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: + /* resizer always write to memory */ + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* media operations */ +static const struct media_entity_operations resizer_media_ops = { + .link_setup = resizer_link_setup, +}; + +/* + * resizer_init_entities - Initialize resizer subdev and media entity. + * @res : Pointer to resizer device structure + * return -ENOMEM or zero on success + */ +static int resizer_init_entities(struct isp_res_device *res) +{ + struct v4l2_subdev *sd = &res->subdev; + struct media_pad *pads = res->pads; + struct media_entity *me = &sd->entity; + int ret; + + res->input = RESIZER_INPUT_NONE; + + v4l2_subdev_init(sd, &resizer_v4l2_ops); + sd->internal_ops = &resizer_v4l2_internal_ops; + strlcpy(sd->name, "OMAP3 ISP resizer", sizeof(sd->name)); + sd->grp_id = 1 << 16; /* group ID for isp subdevs */ + v4l2_set_subdevdata(sd, res); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + + me->ops = &resizer_media_ops; + ret = media_entity_init(me, RESZ_PADS_NUM, pads, 0); + if (ret < 0) + return ret; + + resizer_init_formats(sd, NULL); + + res->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + res->video_in.ops = &resizer_video_ops; + res->video_in.isp = to_isp_device(res); + res->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; + res->video_in.bpl_alignment = 32; + res->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + res->video_out.ops = &resizer_video_ops; + res->video_out.isp = to_isp_device(res); + res->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 2 * 3; + res->video_out.bpl_alignment = 32; + + ret = omap3isp_video_init(&res->video_in, "resizer"); + if (ret < 0) + return ret; + + ret = omap3isp_video_init(&res->video_out, "resizer"); + if (ret < 0) + return ret; + + /* Connect the video nodes to the resizer subdev. */ + ret = media_entity_create_link(&res->video_in.video.entity, 0, + &res->subdev.entity, RESZ_PAD_SINK, 0); + if (ret < 0) + return ret; + + ret = media_entity_create_link(&res->subdev.entity, RESZ_PAD_SOURCE, + &res->video_out.video.entity, 0, 0); + if (ret < 0) + return ret; + + return 0; +} + +void omap3isp_resizer_unregister_entities(struct isp_res_device *res) +{ + media_entity_cleanup(&res->subdev.entity); + + v4l2_device_unregister_subdev(&res->subdev); + omap3isp_video_unregister(&res->video_in); + omap3isp_video_unregister(&res->video_out); +} + +int omap3isp_resizer_register_entities(struct isp_res_device *res, + struct v4l2_device *vdev) +{ + int ret; + + /* Register the subdev and video nodes. */ + ret = v4l2_device_register_subdev(vdev, &res->subdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_in, vdev); + if (ret < 0) + goto error; + + ret = omap3isp_video_register(&res->video_out, vdev); + if (ret < 0) + goto error; + + return 0; + +error: + omap3isp_resizer_unregister_entities(res); + return ret; +} + +/* ----------------------------------------------------------------------------- + * ISP resizer initialization and cleanup + */ + +void omap3isp_resizer_cleanup(struct isp_device *isp) +{ +} + +/* + * isp_resizer_init - Resizer initialization. + * @isp : Pointer to ISP device + * return -ENOMEM or zero on success + */ +int omap3isp_resizer_init(struct isp_device *isp) +{ + struct isp_res_device *res = &isp->isp_res; + int ret; + + init_waitqueue_head(&res->wait); + atomic_set(&res->stopping, 0); + ret = resizer_init_entities(res); + if (ret < 0) + goto out; + +out: + if (ret) + omap3isp_resizer_cleanup(isp); + + return ret; +} diff --git a/drivers/media/video/omap3isp/ispresizer.h b/drivers/media/video/omap3isp/ispresizer.h new file mode 100644 index 000000000000..76abc2e42126 --- /dev/null +++ b/drivers/media/video/omap3isp/ispresizer.h @@ -0,0 +1,147 @@ +/* + * ispresizer.h + * + * TI OMAP3 ISP - Resizer module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_RESIZER_H +#define OMAP3_ISP_RESIZER_H + +#include + +/* + * Constants for filter coefficents count + */ +#define COEFF_CNT 32 + +/* + * struct isprsz_coef - Structure for resizer filter coeffcients. + * @h_filter_coef_4tap: Horizontal filter coefficients for 8-phase/4-tap + * mode (.5x-4x) + * @v_filter_coef_4tap: Vertical filter coefficients for 8-phase/4-tap + * mode (.5x-4x) + * @h_filter_coef_7tap: Horizontal filter coefficients for 4-phase/7-tap + * mode (.25x-.5x) + * @v_filter_coef_7tap: Vertical filter coefficients for 4-phase/7-tap + * mode (.25x-.5x) + */ +struct isprsz_coef { + u16 h_filter_coef_4tap[32]; + u16 v_filter_coef_4tap[32]; + /* Every 8th value is a dummy value in the following arrays: */ + u16 h_filter_coef_7tap[32]; + u16 v_filter_coef_7tap[32]; +}; + +/* Chrominance horizontal algorithm */ +enum resizer_chroma_algo { + RSZ_THE_SAME = 0, /* Chrominance the same as Luminance */ + RSZ_BILINEAR = 1, /* Chrominance uses bilinear interpolation */ +}; + +/* Resizer input type select */ +enum resizer_colors_type { + RSZ_YUV422 = 0, /* YUV422 color is interleaved */ + RSZ_COLOR8 = 1, /* Color separate data on 8 bits */ +}; + +/* + * Structure for horizontal and vertical resizing value + */ +struct resizer_ratio { + u32 horz; + u32 vert; +}; + +/* + * Structure for luminance enhancer parameters. + */ +struct resizer_luma_yenh { + u8 algo; /* algorithm select. */ + u8 gain; /* maximum gain. */ + u8 slope; /* slope. */ + u8 core; /* core offset. */ +}; + +enum resizer_input_entity { + RESIZER_INPUT_NONE, + RESIZER_INPUT_VP, /* input video port - prev or ccdc */ + RESIZER_INPUT_MEMORY, +}; + +/* Sink and source resizer pads */ +#define RESZ_PAD_SINK 0 +#define RESZ_PAD_SOURCE 1 +#define RESZ_PADS_NUM 2 + +/* + * struct isp_res_device - OMAP3 ISP resizer module + * @crop.request: Crop rectangle requested by the user + * @crop.active: Active crop rectangle (based on hardware requirements) + */ +struct isp_res_device { + struct v4l2_subdev subdev; + struct media_pad pads[RESZ_PADS_NUM]; + struct v4l2_mbus_framefmt formats[RESZ_PADS_NUM]; + + enum resizer_input_entity input; + struct isp_video video_in; + struct isp_video video_out; + unsigned int error; + + u32 addr_base; /* stored source buffer address in memory mode */ + u32 crop_offset; /* additional offset for crop in memory mode */ + struct resizer_ratio ratio; + int pm_state; + unsigned int applycrop:1; + enum isp_pipeline_stream_state state; + wait_queue_head_t wait; + atomic_t stopping; + + struct { + struct v4l2_rect request; + struct v4l2_rect active; + } crop; +}; + +struct isp_device; + +int omap3isp_resizer_init(struct isp_device *isp); +void omap3isp_resizer_cleanup(struct isp_device *isp); + +int omap3isp_resizer_register_entities(struct isp_res_device *res, + struct v4l2_device *vdev); +void omap3isp_resizer_unregister_entities(struct isp_res_device *res); +void omap3isp_resizer_isr_frame_sync(struct isp_res_device *res); +void omap3isp_resizer_isr(struct isp_res_device *isp_res); + +void omap3isp_resizer_max_rate(struct isp_res_device *res, + unsigned int *max_rate); + +void omap3isp_resizer_suspend(struct isp_res_device *isp_res); + +void omap3isp_resizer_resume(struct isp_res_device *isp_res); + +int omap3isp_resizer_busy(struct isp_res_device *isp_res); + +#endif /* OMAP3_ISP_RESIZER_H */ diff --git a/drivers/media/video/omap3isp/luma_enhance_table.h b/drivers/media/video/omap3isp/luma_enhance_table.h new file mode 100644 index 000000000000..098b45e2280f --- /dev/null +++ b/drivers/media/video/omap3isp/luma_enhance_table.h @@ -0,0 +1,42 @@ +/* + * luma_enhance_table.h + * + * TI OMAP3 ISP - Luminance enhancement table + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, +1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, +1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, 1047552, +1047552, 1047552, 1047552, 1047552, 1048575, 1047551, 1046527, 1045503, +1044479, 1043455, 1042431, 1041407, 1040383, 1039359, 1038335, 1037311, +1036287, 1035263, 1034239, 1033215, 1032191, 1031167, 1030143, 1028096, +1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, 1028096, +1028096, 1028100, 1032196, 1036292, 1040388, 1044484, 0, 0, + 0, 5, 5125, 10245, 15365, 20485, 25605, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 31743, 30719, 29695, 28671, 27647, 26623, + 25599, 24575, 23551, 22527, 21503, 20479, 19455, 18431, + 17407, 16383, 15359, 14335, 13311, 12287, 11263, 10239, + 9215, 8191, 7167, 6143, 5119, 4095, 3071, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024 diff --git a/drivers/media/video/omap3isp/noise_filter_table.h b/drivers/media/video/omap3isp/noise_filter_table.h new file mode 100644 index 000000000000..d50451a4a242 --- /dev/null +++ b/drivers/media/video/omap3isp/noise_filter_table.h @@ -0,0 +1,30 @@ +/* + * noise_filter_table.h + * + * TI OMAP3 ISP - Noise filter table + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, +16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, +31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, +31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31 -- cgit v1.2.2 From 68e342b3068cae62f3378cb4a1d385734ea52784 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Sat, 12 Feb 2011 18:05:06 -0300 Subject: [media] omap3isp: Statistics The OMAP3 ISP statistics entities compute histogram and H3A statistics information from capture images. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: David Cohen Signed-off-by: Stanimir Varbanov Signed-off-by: Vimarsh Zutshi Signed-off-by: Tuukka Toivonen Signed-off-by: Sergio Aguirre Signed-off-by: Antti Koskipaa Signed-off-by: Ivan T. Ivanov Signed-off-by: RaniSuneela Signed-off-by: Atanas Filipov Signed-off-by: Gjorgji Rosikopulos Signed-off-by: Hiroshi DOYU Signed-off-by: Nayden Kanchev Signed-off-by: Phil Carmody Signed-off-by: Artem Bityutskiy Signed-off-by: Dominic Curran Signed-off-by: Ilkka Myllyperkio Signed-off-by: Pallavi Kulkarni Signed-off-by: Vaibhav Hiremath Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isph3a.h | 117 +++ drivers/media/video/omap3isp/isph3a_aewb.c | 374 ++++++++++ drivers/media/video/omap3isp/isph3a_af.c | 429 +++++++++++ drivers/media/video/omap3isp/isphist.c | 520 +++++++++++++ drivers/media/video/omap3isp/isphist.h | 40 + drivers/media/video/omap3isp/ispstat.c | 1092 ++++++++++++++++++++++++++++ drivers/media/video/omap3isp/ispstat.h | 169 +++++ 7 files changed, 2741 insertions(+) create mode 100644 drivers/media/video/omap3isp/isph3a.h create mode 100644 drivers/media/video/omap3isp/isph3a_aewb.c create mode 100644 drivers/media/video/omap3isp/isph3a_af.c create mode 100644 drivers/media/video/omap3isp/isphist.c create mode 100644 drivers/media/video/omap3isp/isphist.h create mode 100644 drivers/media/video/omap3isp/ispstat.c create mode 100644 drivers/media/video/omap3isp/ispstat.h (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isph3a.h b/drivers/media/video/omap3isp/isph3a.h new file mode 100644 index 000000000000..fb09fd4ca755 --- /dev/null +++ b/drivers/media/video/omap3isp/isph3a.h @@ -0,0 +1,117 @@ +/* + * isph3a.h + * + * TI OMAP3 ISP - H3A AF module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: David Cohen + * Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_H3A_H +#define OMAP3_ISP_H3A_H + +#include + +/* + * ---------- + * -H3A AEWB- + * ---------- + */ + +#define AEWB_PACKET_SIZE 16 +#define AEWB_SATURATION_LIMIT 0x3ff + +/* Flags for changed registers */ +#define PCR_CHNG (1 << 0) +#define AEWWIN1_CHNG (1 << 1) +#define AEWINSTART_CHNG (1 << 2) +#define AEWINBLK_CHNG (1 << 3) +#define AEWSUBWIN_CHNG (1 << 4) +#define PRV_WBDGAIN_CHNG (1 << 5) +#define PRV_WBGAIN_CHNG (1 << 6) + +/* ISPH3A REGISTERS bits */ +#define ISPH3A_PCR_AF_EN (1 << 0) +#define ISPH3A_PCR_AF_ALAW_EN (1 << 1) +#define ISPH3A_PCR_AF_MED_EN (1 << 2) +#define ISPH3A_PCR_AF_BUSY (1 << 15) +#define ISPH3A_PCR_AEW_EN (1 << 16) +#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17) +#define ISPH3A_PCR_AEW_BUSY (1 << 18) +#define ISPH3A_PCR_AEW_MASK (ISPH3A_PCR_AEW_ALAW_EN | \ + ISPH3A_PCR_AEW_AVE2LMT_MASK) + +/* + * -------- + * -H3A AF- + * -------- + */ + +/* Peripheral Revision */ +#define AFPID 0x0 + +#define AFCOEF_OFFSET 0x00000004 /* COEF base address */ + +/* PCR fields */ +#define AF_BUSYAF (1 << 15) +#define AF_FVMODE (1 << 14) +#define AF_RGBPOS (0x7 << 11) +#define AF_MED_TH (0xFF << 3) +#define AF_MED_EN (1 << 2) +#define AF_ALAW_EN (1 << 1) +#define AF_EN (1 << 0) +#define AF_PCR_MASK (AF_FVMODE | AF_RGBPOS | AF_MED_TH | \ + AF_MED_EN | AF_ALAW_EN) + +/* AFPAX1 fields */ +#define AF_PAXW (0x7F << 16) +#define AF_PAXH 0x7F + +/* AFPAX2 fields */ +#define AF_AFINCV (0xF << 13) +#define AF_PAXVC (0x7F << 6) +#define AF_PAXHC 0x3F + +/* AFPAXSTART fields */ +#define AF_PAXSH (0xFFF<<16) +#define AF_PAXSV 0xFFF + +/* COEFFICIENT MASK */ +#define AF_COEF_MASK0 0xFFF +#define AF_COEF_MASK1 (0xFFF<<16) + +/* BIT SHIFTS */ +#define AF_RGBPOS_SHIFT 11 +#define AF_MED_TH_SHIFT 3 +#define AF_PAXW_SHIFT 16 +#define AF_LINE_INCR_SHIFT 13 +#define AF_VT_COUNT_SHIFT 6 +#define AF_HZ_START_SHIFT 16 +#define AF_COEF_SHIFT 16 + +/* Init and cleanup functions */ +int omap3isp_h3a_aewb_init(struct isp_device *isp); +int omap3isp_h3a_af_init(struct isp_device *isp); + +void omap3isp_h3a_aewb_cleanup(struct isp_device *isp); +void omap3isp_h3a_af_cleanup(struct isp_device *isp); + +#endif /* OMAP3_ISP_H3A_H */ diff --git a/drivers/media/video/omap3isp/isph3a_aewb.c b/drivers/media/video/omap3isp/isph3a_aewb.c new file mode 100644 index 000000000000..8068cefd8d89 --- /dev/null +++ b/drivers/media/video/omap3isp/isph3a_aewb.c @@ -0,0 +1,374 @@ +/* + * isph3a.c + * + * TI OMAP3 ISP - H3A module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: David Cohen + * Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include + +#include "isp.h" +#include "isph3a.h" +#include "ispstat.h" + +/* + * h3a_aewb_update_regs - Helper function to update h3a registers. + */ +static void h3a_aewb_setup_regs(struct ispstat *aewb, void *priv) +{ + struct omap3isp_h3a_aewb_config *conf = priv; + u32 pcr; + u32 win1; + u32 start; + u32 blk; + u32 subwin; + + if (aewb->state == ISPSTAT_DISABLED) + return; + + isp_reg_writel(aewb->isp, aewb->active_buf->iommu_addr, + OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST); + + if (!aewb->update) + return; + + /* Converting config metadata into reg values */ + pcr = conf->saturation_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT; + pcr |= !!conf->alaw_enable << ISPH3A_PCR_AEW_ALAW_EN_SHIFT; + + win1 = ((conf->win_height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT; + win1 |= ((conf->win_width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT; + win1 |= (conf->ver_win_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT; + win1 |= (conf->hor_win_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT; + + start = conf->hor_win_start << ISPH3A_AEWINSTART_WINSH_SHIFT; + start |= conf->ver_win_start << ISPH3A_AEWINSTART_WINSV_SHIFT; + + blk = conf->blk_ver_win_start << ISPH3A_AEWINBLK_WINSV_SHIFT; + blk |= ((conf->blk_win_height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT; + + subwin = ((conf->subsample_ver_inc >> 1) - 1) << + ISPH3A_AEWSUBWIN_AEWINCV_SHIFT; + subwin |= ((conf->subsample_hor_inc >> 1) - 1) << + ISPH3A_AEWSUBWIN_AEWINCH_SHIFT; + + isp_reg_writel(aewb->isp, win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1); + isp_reg_writel(aewb->isp, start, OMAP3_ISP_IOMEM_H3A, + ISPH3A_AEWINSTART); + isp_reg_writel(aewb->isp, blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK); + isp_reg_writel(aewb->isp, subwin, OMAP3_ISP_IOMEM_H3A, + ISPH3A_AEWSUBWIN); + isp_reg_clr_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, + ISPH3A_PCR_AEW_MASK, pcr); + + aewb->update = 0; + aewb->config_counter += aewb->inc_config; + aewb->inc_config = 0; + aewb->buf_size = conf->buf_size; +} + +static void h3a_aewb_enable(struct ispstat *aewb, int enable) +{ + if (enable) { + isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, + ISPH3A_PCR_AEW_EN); + /* This bit is already set if AF is enabled */ + if (aewb->isp->isp_af.state != ISPSTAT_ENABLED) + isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, + ISPCTRL_H3A_CLK_EN); + } else { + isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, + ISPH3A_PCR_AEW_EN); + /* This bit can't be cleared if AF is enabled */ + if (aewb->isp->isp_af.state != ISPSTAT_ENABLED) + isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, + ISPCTRL_H3A_CLK_EN); + } +} + +static int h3a_aewb_busy(struct ispstat *aewb) +{ + return isp_reg_readl(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) + & ISPH3A_PCR_BUSYAEAWB; +} + +static u32 h3a_aewb_get_buf_size(struct omap3isp_h3a_aewb_config *conf) +{ + /* Number of configured windows + extra row for black data */ + u32 win_count = (conf->ver_win_count + 1) * conf->hor_win_count; + + /* + * Unsaturated block counts for each 8 windows. + * 1 extra for the last (win_count % 8) windows if win_count is not + * divisible by 8. + */ + win_count += (win_count + 7) / 8; + + return win_count * AEWB_PACKET_SIZE; +} + +static int h3a_aewb_validate_params(struct ispstat *aewb, void *new_conf) +{ + struct omap3isp_h3a_aewb_config *user_cfg = new_conf; + u32 buf_size; + + if (unlikely(user_cfg->saturation_limit > + OMAP3ISP_AEWB_MAX_SATURATION_LIM)) + return -EINVAL; + + if (unlikely(user_cfg->win_height < OMAP3ISP_AEWB_MIN_WIN_H || + user_cfg->win_height > OMAP3ISP_AEWB_MAX_WIN_H || + user_cfg->win_height & 0x01)) + return -EINVAL; + + if (unlikely(user_cfg->win_width < OMAP3ISP_AEWB_MIN_WIN_W || + user_cfg->win_width > OMAP3ISP_AEWB_MAX_WIN_W || + user_cfg->win_width & 0x01)) + return -EINVAL; + + if (unlikely(user_cfg->ver_win_count < OMAP3ISP_AEWB_MIN_WINVC || + user_cfg->ver_win_count > OMAP3ISP_AEWB_MAX_WINVC)) + return -EINVAL; + + if (unlikely(user_cfg->hor_win_count < OMAP3ISP_AEWB_MIN_WINHC || + user_cfg->hor_win_count > OMAP3ISP_AEWB_MAX_WINHC)) + return -EINVAL; + + if (unlikely(user_cfg->ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART)) + return -EINVAL; + + if (unlikely(user_cfg->hor_win_start > OMAP3ISP_AEWB_MAX_WINSTART)) + return -EINVAL; + + if (unlikely(user_cfg->blk_ver_win_start > OMAP3ISP_AEWB_MAX_WINSTART)) + return -EINVAL; + + if (unlikely(user_cfg->blk_win_height < OMAP3ISP_AEWB_MIN_WIN_H || + user_cfg->blk_win_height > OMAP3ISP_AEWB_MAX_WIN_H || + user_cfg->blk_win_height & 0x01)) + return -EINVAL; + + if (unlikely(user_cfg->subsample_ver_inc < OMAP3ISP_AEWB_MIN_SUB_INC || + user_cfg->subsample_ver_inc > OMAP3ISP_AEWB_MAX_SUB_INC || + user_cfg->subsample_ver_inc & 0x01)) + return -EINVAL; + + if (unlikely(user_cfg->subsample_hor_inc < OMAP3ISP_AEWB_MIN_SUB_INC || + user_cfg->subsample_hor_inc > OMAP3ISP_AEWB_MAX_SUB_INC || + user_cfg->subsample_hor_inc & 0x01)) + return -EINVAL; + + buf_size = h3a_aewb_get_buf_size(user_cfg); + if (buf_size > user_cfg->buf_size) + user_cfg->buf_size = buf_size; + else if (user_cfg->buf_size > OMAP3ISP_AEWB_MAX_BUF_SIZE) + user_cfg->buf_size = OMAP3ISP_AEWB_MAX_BUF_SIZE; + + return 0; +} + +/* + * h3a_aewb_set_params - Helper function to check & store user given params. + * @new_conf: Pointer to AE and AWB parameters struct. + * + * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to + * program them during ISR. + */ +static void h3a_aewb_set_params(struct ispstat *aewb, void *new_conf) +{ + struct omap3isp_h3a_aewb_config *user_cfg = new_conf; + struct omap3isp_h3a_aewb_config *cur_cfg = aewb->priv; + int update = 0; + + if (cur_cfg->saturation_limit != user_cfg->saturation_limit) { + cur_cfg->saturation_limit = user_cfg->saturation_limit; + update = 1; + } + if (cur_cfg->alaw_enable != user_cfg->alaw_enable) { + cur_cfg->alaw_enable = user_cfg->alaw_enable; + update = 1; + } + if (cur_cfg->win_height != user_cfg->win_height) { + cur_cfg->win_height = user_cfg->win_height; + update = 1; + } + if (cur_cfg->win_width != user_cfg->win_width) { + cur_cfg->win_width = user_cfg->win_width; + update = 1; + } + if (cur_cfg->ver_win_count != user_cfg->ver_win_count) { + cur_cfg->ver_win_count = user_cfg->ver_win_count; + update = 1; + } + if (cur_cfg->hor_win_count != user_cfg->hor_win_count) { + cur_cfg->hor_win_count = user_cfg->hor_win_count; + update = 1; + } + if (cur_cfg->ver_win_start != user_cfg->ver_win_start) { + cur_cfg->ver_win_start = user_cfg->ver_win_start; + update = 1; + } + if (cur_cfg->hor_win_start != user_cfg->hor_win_start) { + cur_cfg->hor_win_start = user_cfg->hor_win_start; + update = 1; + } + if (cur_cfg->blk_ver_win_start != user_cfg->blk_ver_win_start) { + cur_cfg->blk_ver_win_start = user_cfg->blk_ver_win_start; + update = 1; + } + if (cur_cfg->blk_win_height != user_cfg->blk_win_height) { + cur_cfg->blk_win_height = user_cfg->blk_win_height; + update = 1; + } + if (cur_cfg->subsample_ver_inc != user_cfg->subsample_ver_inc) { + cur_cfg->subsample_ver_inc = user_cfg->subsample_ver_inc; + update = 1; + } + if (cur_cfg->subsample_hor_inc != user_cfg->subsample_hor_inc) { + cur_cfg->subsample_hor_inc = user_cfg->subsample_hor_inc; + update = 1; + } + + if (update || !aewb->configured) { + aewb->inc_config++; + aewb->update = 1; + cur_cfg->buf_size = h3a_aewb_get_buf_size(cur_cfg); + } +} + +static long h3a_aewb_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct ispstat *stat = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_OMAP3ISP_AEWB_CFG: + return omap3isp_stat_config(stat, arg); + case VIDIOC_OMAP3ISP_STAT_REQ: + return omap3isp_stat_request_statistics(stat, arg); + case VIDIOC_OMAP3ISP_STAT_EN: { + unsigned long *en = arg; + return omap3isp_stat_enable(stat, !!*en); + } + } + + return -ENOIOCTLCMD; +} + +static const struct ispstat_ops h3a_aewb_ops = { + .validate_params = h3a_aewb_validate_params, + .set_params = h3a_aewb_set_params, + .setup_regs = h3a_aewb_setup_regs, + .enable = h3a_aewb_enable, + .busy = h3a_aewb_busy, +}; + +static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = { + .ioctl = h3a_aewb_ioctl, + .subscribe_event = omap3isp_stat_subscribe_event, + .unsubscribe_event = omap3isp_stat_unsubscribe_event, +}; + +static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = { + .s_stream = omap3isp_stat_s_stream, +}; + +static const struct v4l2_subdev_ops h3a_aewb_subdev_ops = { + .core = &h3a_aewb_subdev_core_ops, + .video = &h3a_aewb_subdev_video_ops, +}; + +/* + * omap3isp_h3a_aewb_init - Module Initialisation. + */ +int omap3isp_h3a_aewb_init(struct isp_device *isp) +{ + struct ispstat *aewb = &isp->isp_aewb; + struct omap3isp_h3a_aewb_config *aewb_cfg; + struct omap3isp_h3a_aewb_config *aewb_recover_cfg; + int ret; + + aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL); + if (!aewb_cfg) + return -ENOMEM; + + memset(aewb, 0, sizeof(*aewb)); + aewb->ops = &h3a_aewb_ops; + aewb->priv = aewb_cfg; + aewb->dma_ch = -1; + aewb->event_type = V4L2_EVENT_OMAP3ISP_AEWB; + aewb->isp = isp; + + /* Set recover state configuration */ + aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL); + if (!aewb_recover_cfg) { + dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for " + "recover configuration.\n"); + ret = -ENOMEM; + goto err_recover_alloc; + } + + aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM; + aewb_recover_cfg->win_height = OMAP3ISP_AEWB_MIN_WIN_H; + aewb_recover_cfg->win_width = OMAP3ISP_AEWB_MIN_WIN_W; + aewb_recover_cfg->ver_win_count = OMAP3ISP_AEWB_MIN_WINVC; + aewb_recover_cfg->hor_win_count = OMAP3ISP_AEWB_MIN_WINHC; + aewb_recover_cfg->blk_ver_win_start = aewb_recover_cfg->ver_win_start + + aewb_recover_cfg->win_height * aewb_recover_cfg->ver_win_count; + aewb_recover_cfg->blk_win_height = OMAP3ISP_AEWB_MIN_WIN_H; + aewb_recover_cfg->subsample_ver_inc = OMAP3ISP_AEWB_MIN_SUB_INC; + aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC; + + if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) { + dev_err(aewb->isp->dev, "AEWB: recover configuration is " + "invalid.\n"); + ret = -EINVAL; + goto err_conf; + } + + aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg); + aewb->recover_priv = aewb_recover_cfg; + + ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops); + if (ret) + goto err_conf; + + return 0; + +err_conf: + kfree(aewb_recover_cfg); +err_recover_alloc: + kfree(aewb_cfg); + + return ret; +} + +/* + * omap3isp_h3a_aewb_cleanup - Module exit. + */ +void omap3isp_h3a_aewb_cleanup(struct isp_device *isp) +{ + kfree(isp->isp_aewb.priv); + kfree(isp->isp_aewb.recover_priv); + omap3isp_stat_free(&isp->isp_aewb); +} diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c new file mode 100644 index 000000000000..ba54d0acdecf --- /dev/null +++ b/drivers/media/video/omap3isp/isph3a_af.c @@ -0,0 +1,429 @@ +/* + * isph3a_af.c + * + * TI OMAP3 ISP - H3A AF module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: David Cohen + * Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +/* Linux specific include files */ +#include +#include + +#include "isp.h" +#include "isph3a.h" +#include "ispstat.h" + +#define IS_OUT_OF_BOUNDS(value, min, max) \ + (((value) < (min)) || ((value) > (max))) + +static void h3a_af_setup_regs(struct ispstat *af, void *priv) +{ + struct omap3isp_h3a_af_config *conf = priv; + u32 pcr; + u32 pax1; + u32 pax2; + u32 paxstart; + u32 coef; + u32 base_coef_set0; + u32 base_coef_set1; + int index; + + if (af->state == ISPSTAT_DISABLED) + return; + + isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A, + ISPH3A_AFBUFST); + + if (!af->update) + return; + + /* Configure Hardware Registers */ + pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT; + /* Set height in AFPAX1 */ + pax1 |= (conf->paxel.height >> 1) - 1; + isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1); + + /* Configure AFPAX2 Register */ + /* Set Line Increment in AFPAX2 Register */ + pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT; + /* Set Vertical Count */ + pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT; + /* Set Horizontal Count */ + pax2 |= (conf->paxel.h_cnt - 1); + isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2); + + /* Configure PAXSTART Register */ + /*Configure Horizontal Start */ + paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT; + /* Configure Vertical Start */ + paxstart |= conf->paxel.v_start; + isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A, + ISPH3A_AFPAXSTART); + + /*SetIIRSH Register */ + isp_reg_writel(af->isp, conf->iir.h_start, + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH); + + base_coef_set0 = ISPH3A_AFCOEF010; + base_coef_set1 = ISPH3A_AFCOEF110; + for (index = 0; index <= 8; index += 2) { + /*Set IIR Filter0 Coefficients */ + coef = 0; + coef |= conf->iir.coeff_set0[index]; + coef |= conf->iir.coeff_set0[index + 1] << + AF_COEF_SHIFT; + isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A, + base_coef_set0); + base_coef_set0 += AFCOEF_OFFSET; + + /*Set IIR Filter1 Coefficients */ + coef = 0; + coef |= conf->iir.coeff_set1[index]; + coef |= conf->iir.coeff_set1[index + 1] << + AF_COEF_SHIFT; + isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A, + base_coef_set1); + base_coef_set1 += AFCOEF_OFFSET; + } + /* set AFCOEF0010 Register */ + isp_reg_writel(af->isp, conf->iir.coeff_set0[10], + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010); + /* set AFCOEF1010 Register */ + isp_reg_writel(af->isp, conf->iir.coeff_set1[10], + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010); + + /* PCR Register */ + /* Set RGB Position */ + pcr = conf->rgb_pos << AF_RGBPOS_SHIFT; + /* Set Accumulator Mode */ + if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK) + pcr |= AF_FVMODE; + /* Set A-law */ + if (conf->alaw_enable) + pcr |= AF_ALAW_EN; + /* HMF Configurations */ + if (conf->hmf.enable) { + /* Enable HMF */ + pcr |= AF_MED_EN; + /* Set Median Threshold */ + pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT; + } + /* Set PCR Register */ + isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, + AF_PCR_MASK, pcr); + + af->update = 0; + af->config_counter += af->inc_config; + af->inc_config = 0; + af->buf_size = conf->buf_size; +} + +static void h3a_af_enable(struct ispstat *af, int enable) +{ + if (enable) { + isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, + ISPH3A_PCR_AF_EN); + /* This bit is already set if AEWB is enabled */ + if (af->isp->isp_aewb.state != ISPSTAT_ENABLED) + isp_reg_set(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, + ISPCTRL_H3A_CLK_EN); + } else { + isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, + ISPH3A_PCR_AF_EN); + /* This bit can't be cleared if AEWB is enabled */ + if (af->isp->isp_aewb.state != ISPSTAT_ENABLED) + isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, + ISPCTRL_H3A_CLK_EN); + } +} + +static int h3a_af_busy(struct ispstat *af) +{ + return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) + & ISPH3A_PCR_BUSYAF; +} + +static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf) +{ + return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE; +} + +/* Function to check paxel parameters */ +static int h3a_af_validate_params(struct ispstat *af, void *new_conf) +{ + struct omap3isp_h3a_af_config *user_cfg = new_conf; + struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel; + struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir; + int index; + u32 buf_size; + + /* Check horizontal Count */ + if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt, + OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN, + OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX)) + return -EINVAL; + + /* Check Vertical Count */ + if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt, + OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN, + OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX)) + return -EINVAL; + + if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN, + OMAP3ISP_AF_PAXEL_HEIGHT_MAX) || + paxel_cfg->height % 2) + return -EINVAL; + + /* Check width */ + if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN, + OMAP3ISP_AF_PAXEL_WIDTH_MAX) || + paxel_cfg->width % 2) + return -EINVAL; + + /* Check Line Increment */ + if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc, + OMAP3ISP_AF_PAXEL_INCREMENT_MIN, + OMAP3ISP_AF_PAXEL_INCREMENT_MAX) || + paxel_cfg->line_inc % 2) + return -EINVAL; + + /* Check Horizontal Start */ + if ((paxel_cfg->h_start < iir_cfg->h_start) || + IS_OUT_OF_BOUNDS(paxel_cfg->h_start, + OMAP3ISP_AF_PAXEL_HZSTART_MIN, + OMAP3ISP_AF_PAXEL_HZSTART_MAX)) + return -EINVAL; + + /* Check IIR */ + for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) { + if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX) + return -EINVAL; + + if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX) + return -EINVAL; + } + + if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN, + OMAP3ISP_AF_IIRSH_MAX)) + return -EINVAL; + + /* Hack: If paxel size is 12, the 10th AF window may be corrupted */ + if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) && + (paxel_cfg->width * paxel_cfg->height == 12)) + return -EINVAL; + + buf_size = h3a_af_get_buf_size(user_cfg); + if (buf_size > user_cfg->buf_size) + /* User buf_size request wasn't enough */ + user_cfg->buf_size = buf_size; + else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE) + user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE; + + return 0; +} + +/* Update local parameters */ +static void h3a_af_set_params(struct ispstat *af, void *new_conf) +{ + struct omap3isp_h3a_af_config *user_cfg = new_conf; + struct omap3isp_h3a_af_config *cur_cfg = af->priv; + int update = 0; + int index; + + /* alaw */ + if (cur_cfg->alaw_enable != user_cfg->alaw_enable) { + update = 1; + goto out; + } + + /* hmf */ + if (cur_cfg->hmf.enable != user_cfg->hmf.enable) { + update = 1; + goto out; + } + if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) { + update = 1; + goto out; + } + + /* rgbpos */ + if (cur_cfg->rgb_pos != user_cfg->rgb_pos) { + update = 1; + goto out; + } + + /* iir */ + if (cur_cfg->iir.h_start != user_cfg->iir.h_start) { + update = 1; + goto out; + } + for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) { + if (cur_cfg->iir.coeff_set0[index] != + user_cfg->iir.coeff_set0[index]) { + update = 1; + goto out; + } + if (cur_cfg->iir.coeff_set1[index] != + user_cfg->iir.coeff_set1[index]) { + update = 1; + goto out; + } + } + + /* paxel */ + if ((cur_cfg->paxel.width != user_cfg->paxel.width) || + (cur_cfg->paxel.height != user_cfg->paxel.height) || + (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) || + (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) || + (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) || + (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) || + (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) { + update = 1; + goto out; + } + + /* af_mode */ + if (cur_cfg->fvmode != user_cfg->fvmode) + update = 1; + +out: + if (update || !af->configured) { + memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg)); + af->inc_config++; + af->update = 1; + /* + * User might be asked for a bigger buffer than necessary for + * this configuration. In order to return the right amount of + * data during buffer request, let's calculate the size here + * instead of stick with user_cfg->buf_size. + */ + cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg); + } +} + +static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct ispstat *stat = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_OMAP3ISP_AF_CFG: + return omap3isp_stat_config(stat, arg); + case VIDIOC_OMAP3ISP_STAT_REQ: + return omap3isp_stat_request_statistics(stat, arg); + case VIDIOC_OMAP3ISP_STAT_EN: { + int *en = arg; + return omap3isp_stat_enable(stat, !!*en); + } + } + + return -ENOIOCTLCMD; + +} + +static const struct ispstat_ops h3a_af_ops = { + .validate_params = h3a_af_validate_params, + .set_params = h3a_af_set_params, + .setup_regs = h3a_af_setup_regs, + .enable = h3a_af_enable, + .busy = h3a_af_busy, +}; + +static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = { + .ioctl = h3a_af_ioctl, + .subscribe_event = omap3isp_stat_subscribe_event, + .unsubscribe_event = omap3isp_stat_unsubscribe_event, +}; + +static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = { + .s_stream = omap3isp_stat_s_stream, +}; + +static const struct v4l2_subdev_ops h3a_af_subdev_ops = { + .core = &h3a_af_subdev_core_ops, + .video = &h3a_af_subdev_video_ops, +}; + +/* Function to register the AF character device driver. */ +int omap3isp_h3a_af_init(struct isp_device *isp) +{ + struct ispstat *af = &isp->isp_af; + struct omap3isp_h3a_af_config *af_cfg; + struct omap3isp_h3a_af_config *af_recover_cfg; + int ret; + + af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL); + if (af_cfg == NULL) + return -ENOMEM; + + memset(af, 0, sizeof(*af)); + af->ops = &h3a_af_ops; + af->priv = af_cfg; + af->dma_ch = -1; + af->event_type = V4L2_EVENT_OMAP3ISP_AF; + af->isp = isp; + + /* Set recover state configuration */ + af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL); + if (!af_recover_cfg) { + dev_err(af->isp->dev, "AF: cannot allocate memory for recover " + "configuration.\n"); + ret = -ENOMEM; + goto err_recover_alloc; + } + + af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN; + af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN; + af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN; + af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN; + af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN; + af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN; + if (h3a_af_validate_params(af, af_recover_cfg)) { + dev_err(af->isp->dev, "AF: recover configuration is " + "invalid.\n"); + ret = -EINVAL; + goto err_conf; + } + + af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg); + af->recover_priv = af_recover_cfg; + + ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops); + if (ret) + goto err_conf; + + return 0; + +err_conf: + kfree(af_recover_cfg); +err_recover_alloc: + kfree(af_cfg); + + return ret; +} + +void omap3isp_h3a_af_cleanup(struct isp_device *isp) +{ + kfree(isp->isp_af.priv); + kfree(isp->isp_af.recover_priv); + omap3isp_stat_free(&isp->isp_af); +} diff --git a/drivers/media/video/omap3isp/isphist.c b/drivers/media/video/omap3isp/isphist.c new file mode 100644 index 000000000000..1743856b30d1 --- /dev/null +++ b/drivers/media/video/omap3isp/isphist.c @@ -0,0 +1,520 @@ +/* + * isphist.c + * + * TI OMAP3 ISP - Histogram module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: David Cohen + * Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include +#include + +#include "isp.h" +#include "ispreg.h" +#include "isphist.h" + +#define HIST_CONFIG_DMA 1 + +#define HIST_USING_DMA(hist) ((hist)->dma_ch >= 0) + +/* + * hist_reset_mem - clear Histogram memory before start stats engine. + */ +static void hist_reset_mem(struct ispstat *hist) +{ + struct isp_device *isp = hist->isp; + struct omap3isp_hist_config *conf = hist->priv; + unsigned int i; + + isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); + + /* + * By setting it, the histogram internal buffer is being cleared at the + * same time it's being read. This bit must be cleared afterwards. + */ + isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); + + /* + * We'll clear 4 words at each iteration for optimization. It avoids + * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4. + */ + for (i = OMAP3ISP_HIST_MEM_SIZE / 4; i > 0; i--) { + isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + } + isp_reg_clr(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); + + hist->wait_acc_frames = conf->num_acc_frames; +} + +static void hist_dma_config(struct ispstat *hist) +{ + hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32; + hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT; + hist->dma_config.frame_count = 1; + hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT; + hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA; + hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC; + hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC; +} + +/* + * hist_setup_regs - Helper function to update Histogram registers. + */ +static void hist_setup_regs(struct ispstat *hist, void *priv) +{ + struct isp_device *isp = hist->isp; + struct omap3isp_hist_config *conf = priv; + int c; + u32 cnt; + u32 wb_gain; + u32 reg_hor[OMAP3ISP_HIST_MAX_REGIONS]; + u32 reg_ver[OMAP3ISP_HIST_MAX_REGIONS]; + + if (!hist->update || hist->state == ISPSTAT_DISABLED || + hist->state == ISPSTAT_DISABLING) + return; + + cnt = conf->cfa << ISPHIST_CNT_CFA_SHIFT; + + wb_gain = conf->wg[0] << ISPHIST_WB_GAIN_WG00_SHIFT; + wb_gain |= conf->wg[1] << ISPHIST_WB_GAIN_WG01_SHIFT; + wb_gain |= conf->wg[2] << ISPHIST_WB_GAIN_WG02_SHIFT; + if (conf->cfa == OMAP3ISP_HIST_CFA_BAYER) + wb_gain |= conf->wg[3] << ISPHIST_WB_GAIN_WG03_SHIFT; + + /* Regions size and position */ + for (c = 0; c < OMAP3ISP_HIST_MAX_REGIONS; c++) { + if (c < conf->num_regions) { + reg_hor[c] = conf->region[c].h_start << + ISPHIST_REG_START_SHIFT; + reg_hor[c] = conf->region[c].h_end << + ISPHIST_REG_END_SHIFT; + reg_ver[c] = conf->region[c].v_start << + ISPHIST_REG_START_SHIFT; + reg_ver[c] = conf->region[c].v_end << + ISPHIST_REG_END_SHIFT; + } else { + reg_hor[c] = 0; + reg_ver[c] = 0; + } + } + + cnt |= conf->hist_bins << ISPHIST_CNT_BINS_SHIFT; + switch (conf->hist_bins) { + case OMAP3ISP_HIST_BINS_256: + cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 8) << + ISPHIST_CNT_SHIFT_SHIFT; + break; + case OMAP3ISP_HIST_BINS_128: + cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 7) << + ISPHIST_CNT_SHIFT_SHIFT; + break; + case OMAP3ISP_HIST_BINS_64: + cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 6) << + ISPHIST_CNT_SHIFT_SHIFT; + break; + default: /* OMAP3ISP_HIST_BINS_32 */ + cnt |= (ISPHIST_IN_BIT_WIDTH_CCDC - 5) << + ISPHIST_CNT_SHIFT_SHIFT; + break; + } + + hist_reset_mem(hist); + + isp_reg_writel(isp, cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT); + isp_reg_writel(isp, wb_gain, OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN); + isp_reg_writel(isp, reg_hor[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ); + isp_reg_writel(isp, reg_ver[0], OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT); + isp_reg_writel(isp, reg_hor[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ); + isp_reg_writel(isp, reg_ver[1], OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT); + isp_reg_writel(isp, reg_hor[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ); + isp_reg_writel(isp, reg_ver[2], OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT); + isp_reg_writel(isp, reg_hor[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ); + isp_reg_writel(isp, reg_ver[3], OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT); + + hist->update = 0; + hist->config_counter += hist->inc_config; + hist->inc_config = 0; + hist->buf_size = conf->buf_size; +} + +static void hist_enable(struct ispstat *hist, int enable) +{ + if (enable) { + isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, + ISPHIST_PCR_ENABLE); + isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, + ISPCTRL_HIST_CLK_EN); + } else { + isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, + ISPHIST_PCR_ENABLE); + isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, + ISPCTRL_HIST_CLK_EN); + } +} + +static int hist_busy(struct ispstat *hist) +{ + return isp_reg_readl(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR) + & ISPHIST_PCR_BUSY; +} + +static void hist_dma_cb(int lch, u16 ch_status, void *data) +{ + struct ispstat *hist = data; + + if (ch_status & ~OMAP_DMA_BLOCK_IRQ) { + dev_dbg(hist->isp->dev, "hist: DMA error. status = 0x%04x\n", + ch_status); + omap_stop_dma(lch); + hist_reset_mem(hist); + atomic_set(&hist->buf_err, 1); + } + isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, + ISPHIST_CNT_CLEAR); + + omap3isp_stat_dma_isr(hist); + if (hist->state != ISPSTAT_DISABLED) + omap3isp_hist_dma_done(hist->isp); +} + +static int hist_buf_dma(struct ispstat *hist) +{ + dma_addr_t dma_addr = hist->active_buf->dma_addr; + + if (unlikely(!dma_addr)) { + dev_dbg(hist->isp->dev, "hist: invalid DMA buffer address\n"); + hist_reset_mem(hist); + return STAT_NO_BUF; + } + + isp_reg_writel(hist->isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); + isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, + ISPHIST_CNT_CLEAR); + omap3isp_flush(hist->isp); + hist->dma_config.dst_start = dma_addr; + hist->dma_config.elem_count = hist->buf_size / sizeof(u32); + omap_set_dma_params(hist->dma_ch, &hist->dma_config); + + omap_start_dma(hist->dma_ch); + + return STAT_BUF_WAITING_DMA; +} + +static int hist_buf_pio(struct ispstat *hist) +{ + struct isp_device *isp = hist->isp; + u32 *buf = hist->active_buf->virt_addr; + unsigned int i; + + if (!buf) { + dev_dbg(isp->dev, "hist: invalid PIO buffer address\n"); + hist_reset_mem(hist); + return STAT_NO_BUF; + } + + isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR); + + /* + * By setting it, the histogram internal buffer is being cleared at the + * same time it's being read. This bit must be cleared just after all + * data is acquired. + */ + isp_reg_set(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLEAR); + + /* + * We'll read 4 times a 4-bytes-word at each iteration for + * optimization. It avoids 3/4 of the jumps. We also know buf_size is + * divisible by 16. + */ + for (i = hist->buf_size / 16; i > 0; i--) { + *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + *buf++ = isp_reg_readl(isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); + } + isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, + ISPHIST_CNT_CLEAR); + + return STAT_BUF_DONE; +} + +/* + * hist_buf_process - Callback from ISP driver for HIST interrupt. + */ +static int hist_buf_process(struct ispstat *hist) +{ + struct omap3isp_hist_config *user_cfg = hist->priv; + int ret; + + if (atomic_read(&hist->buf_err) || hist->state != ISPSTAT_ENABLED) { + hist_reset_mem(hist); + return STAT_NO_BUF; + } + + if (--(hist->wait_acc_frames)) + return STAT_NO_BUF; + + if (HIST_USING_DMA(hist)) + ret = hist_buf_dma(hist); + else + ret = hist_buf_pio(hist); + + hist->wait_acc_frames = user_cfg->num_acc_frames; + + return ret; +} + +static u32 hist_get_buf_size(struct omap3isp_hist_config *conf) +{ + return OMAP3ISP_HIST_MEM_SIZE_BINS(conf->hist_bins) * conf->num_regions; +} + +/* + * hist_validate_params - Helper function to check user given params. + * @user_cfg: Pointer to user configuration structure. + * + * Returns 0 on success configuration. + */ +static int hist_validate_params(struct ispstat *hist, void *new_conf) +{ + struct omap3isp_hist_config *user_cfg = new_conf; + int c; + u32 buf_size; + + if (user_cfg->cfa > OMAP3ISP_HIST_CFA_FOVEONX3) + return -EINVAL; + + /* Regions size and position */ + + if ((user_cfg->num_regions < OMAP3ISP_HIST_MIN_REGIONS) || + (user_cfg->num_regions > OMAP3ISP_HIST_MAX_REGIONS)) + return -EINVAL; + + /* Regions */ + for (c = 0; c < user_cfg->num_regions; c++) { + if (user_cfg->region[c].h_start & ~ISPHIST_REG_START_END_MASK) + return -EINVAL; + if (user_cfg->region[c].h_end & ~ISPHIST_REG_START_END_MASK) + return -EINVAL; + if (user_cfg->region[c].v_start & ~ISPHIST_REG_START_END_MASK) + return -EINVAL; + if (user_cfg->region[c].v_end & ~ISPHIST_REG_START_END_MASK) + return -EINVAL; + if (user_cfg->region[c].h_start > user_cfg->region[c].h_end) + return -EINVAL; + if (user_cfg->region[c].v_start > user_cfg->region[c].v_end) + return -EINVAL; + } + + switch (user_cfg->num_regions) { + case 1: + if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_256) + return -EINVAL; + break; + case 2: + if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_128) + return -EINVAL; + break; + default: /* 3 or 4 */ + if (user_cfg->hist_bins > OMAP3ISP_HIST_BINS_64) + return -EINVAL; + break; + } + + buf_size = hist_get_buf_size(user_cfg); + if (buf_size > user_cfg->buf_size) + /* User's buf_size request wasn't enoght */ + user_cfg->buf_size = buf_size; + else if (user_cfg->buf_size > OMAP3ISP_HIST_MAX_BUF_SIZE) + user_cfg->buf_size = OMAP3ISP_HIST_MAX_BUF_SIZE; + + return 0; +} + +static int hist_comp_params(struct ispstat *hist, + struct omap3isp_hist_config *user_cfg) +{ + struct omap3isp_hist_config *cur_cfg = hist->priv; + int c; + + if (cur_cfg->cfa != user_cfg->cfa) + return 1; + + if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames) + return 1; + + if (cur_cfg->hist_bins != user_cfg->hist_bins) + return 1; + + for (c = 0; c < OMAP3ISP_HIST_MAX_WG; c++) { + if (c == 3 && user_cfg->cfa == OMAP3ISP_HIST_CFA_FOVEONX3) + break; + else if (cur_cfg->wg[c] != user_cfg->wg[c]) + return 1; + } + + if (cur_cfg->num_regions != user_cfg->num_regions) + return 1; + + /* Regions */ + for (c = 0; c < user_cfg->num_regions; c++) { + if (cur_cfg->region[c].h_start != user_cfg->region[c].h_start) + return 1; + if (cur_cfg->region[c].h_end != user_cfg->region[c].h_end) + return 1; + if (cur_cfg->region[c].v_start != user_cfg->region[c].v_start) + return 1; + if (cur_cfg->region[c].v_end != user_cfg->region[c].v_end) + return 1; + } + + return 0; +} + +/* + * hist_update_params - Helper function to check and store user given params. + * @new_conf: Pointer to user configuration structure. + */ +static void hist_set_params(struct ispstat *hist, void *new_conf) +{ + struct omap3isp_hist_config *user_cfg = new_conf; + struct omap3isp_hist_config *cur_cfg = hist->priv; + + if (!hist->configured || hist_comp_params(hist, user_cfg)) { + memcpy(cur_cfg, user_cfg, sizeof(*user_cfg)); + if (user_cfg->num_acc_frames == 0) + user_cfg->num_acc_frames = 1; + hist->inc_config++; + hist->update = 1; + /* + * User might be asked for a bigger buffer than necessary for + * this configuration. In order to return the right amount of + * data during buffer request, let's calculate the size here + * instead of stick with user_cfg->buf_size. + */ + cur_cfg->buf_size = hist_get_buf_size(cur_cfg); + + } +} + +static long hist_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + struct ispstat *stat = v4l2_get_subdevdata(sd); + + switch (cmd) { + case VIDIOC_OMAP3ISP_HIST_CFG: + return omap3isp_stat_config(stat, arg); + case VIDIOC_OMAP3ISP_STAT_REQ: + return omap3isp_stat_request_statistics(stat, arg); + case VIDIOC_OMAP3ISP_STAT_EN: { + int *en = arg; + return omap3isp_stat_enable(stat, !!*en); + } + } + + return -ENOIOCTLCMD; + +} + +static const struct ispstat_ops hist_ops = { + .validate_params = hist_validate_params, + .set_params = hist_set_params, + .setup_regs = hist_setup_regs, + .enable = hist_enable, + .busy = hist_busy, + .buf_process = hist_buf_process, +}; + +static const struct v4l2_subdev_core_ops hist_subdev_core_ops = { + .ioctl = hist_ioctl, + .subscribe_event = omap3isp_stat_subscribe_event, + .unsubscribe_event = omap3isp_stat_unsubscribe_event, +}; + +static const struct v4l2_subdev_video_ops hist_subdev_video_ops = { + .s_stream = omap3isp_stat_s_stream, +}; + +static const struct v4l2_subdev_ops hist_subdev_ops = { + .core = &hist_subdev_core_ops, + .video = &hist_subdev_video_ops, +}; + +/* + * omap3isp_hist_init - Module Initialization. + */ +int omap3isp_hist_init(struct isp_device *isp) +{ + struct ispstat *hist = &isp->isp_hist; + struct omap3isp_hist_config *hist_cfg; + int ret = -1; + + hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL); + if (hist_cfg == NULL) + return -ENOMEM; + + memset(hist, 0, sizeof(*hist)); + if (HIST_CONFIG_DMA) + ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST", + hist_dma_cb, hist, &hist->dma_ch); + if (ret) { + if (HIST_CONFIG_DMA) + dev_warn(isp->dev, "hist: DMA request channel failed. " + "Using PIO only.\n"); + hist->dma_ch = -1; + } else { + dev_dbg(isp->dev, "hist: DMA channel = %d\n", hist->dma_ch); + hist_dma_config(hist); + omap_enable_dma_irq(hist->dma_ch, OMAP_DMA_BLOCK_IRQ); + } + + hist->ops = &hist_ops; + hist->priv = hist_cfg; + hist->event_type = V4L2_EVENT_OMAP3ISP_HIST; + hist->isp = isp; + + ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); + if (ret) { + kfree(hist_cfg); + if (HIST_USING_DMA(hist)) + omap_free_dma(hist->dma_ch); + } + + return ret; +} + +/* + * omap3isp_hist_cleanup - Module cleanup. + */ +void omap3isp_hist_cleanup(struct isp_device *isp) +{ + if (HIST_USING_DMA(&isp->isp_hist)) + omap_free_dma(isp->isp_hist.dma_ch); + kfree(isp->isp_hist.priv); + omap3isp_stat_free(&isp->isp_hist); +} diff --git a/drivers/media/video/omap3isp/isphist.h b/drivers/media/video/omap3isp/isphist.h new file mode 100644 index 000000000000..0b2a38ec94c4 --- /dev/null +++ b/drivers/media/video/omap3isp/isphist.h @@ -0,0 +1,40 @@ +/* + * isphist.h + * + * TI OMAP3 ISP - Histogram module + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc. + * + * Contacts: David Cohen + * Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_HIST_H +#define OMAP3_ISP_HIST_H + +#include + +#define ISPHIST_IN_BIT_WIDTH_CCDC 10 + +struct isp_device; + +int omap3isp_hist_init(struct isp_device *isp); +void omap3isp_hist_cleanup(struct isp_device *isp); + +#endif /* OMAP3_ISP_HIST */ diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c new file mode 100644 index 000000000000..b44cb685236a --- /dev/null +++ b/drivers/media/video/omap3isp/ispstat.c @@ -0,0 +1,1092 @@ +/* + * ispstat.c + * + * TI OMAP3 ISP - Statistics core + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc + * + * Contacts: David Cohen + * Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include + +#include "isp.h" + +#define IS_COHERENT_BUF(stat) ((stat)->dma_ch >= 0) + +/* + * MAGIC_SIZE must always be the greatest common divisor of + * AEWB_PACKET_SIZE and AF_PAXEL_SIZE. + */ +#define MAGIC_SIZE 16 +#define MAGIC_NUM 0x55 + +/* HACK: AF module seems to be writing one more paxel data than it should. */ +#define AF_EXTRA_DATA OMAP3ISP_AF_PAXEL_SIZE + +/* + * HACK: H3A modules go to an invalid state after have a SBL overflow. It makes + * the next buffer to start to be written in the same point where the overflow + * occurred instead of the configured address. The only known way to make it to + * go back to a valid state is having a valid buffer processing. Of course it + * requires at least a doubled buffer size to avoid an access to invalid memory + * region. But it does not fix everything. It may happen more than one + * consecutive SBL overflows. In that case, it might be unpredictable how many + * buffers the allocated memory should fit. For that case, a recover + * configuration was created. It produces the minimum buffer size for each H3A + * module and decrease the change for more SBL overflows. This recover state + * will be enabled every time a SBL overflow occur. As the output buffer size + * isn't big, it's possible to have an extra size able to fit many recover + * buffers making it extreamily unlikely to have an access to invalid memory + * region. + */ +#define NUM_H3A_RECOVER_BUFS 10 + +/* + * HACK: Because of HW issues the generic layer sometimes need to have + * different behaviour for different statistic modules. + */ +#define IS_H3A_AF(stat) ((stat) == &(stat)->isp->isp_af) +#define IS_H3A_AEWB(stat) ((stat) == &(stat)->isp->isp_aewb) +#define IS_H3A(stat) (IS_H3A_AF(stat) || IS_H3A_AEWB(stat)) + +static void __isp_stat_buf_sync_magic(struct ispstat *stat, + struct ispstat_buffer *buf, + u32 buf_size, enum dma_data_direction dir, + void (*dma_sync)(struct device *, + dma_addr_t, unsigned long, size_t, + enum dma_data_direction)) +{ + struct device *dev = stat->isp->dev; + struct page *pg; + dma_addr_t dma_addr; + u32 offset; + + /* Initial magic words */ + pg = vmalloc_to_page(buf->virt_addr); + dma_addr = pfn_to_dma(dev, page_to_pfn(pg)); + dma_sync(dev, dma_addr, 0, MAGIC_SIZE, dir); + + /* Final magic words */ + pg = vmalloc_to_page(buf->virt_addr + buf_size); + dma_addr = pfn_to_dma(dev, page_to_pfn(pg)); + offset = ((u32)buf->virt_addr + buf_size) & ~PAGE_MASK; + dma_sync(dev, dma_addr, offset, MAGIC_SIZE, dir); +} + +static void isp_stat_buf_sync_magic_for_device(struct ispstat *stat, + struct ispstat_buffer *buf, + u32 buf_size, + enum dma_data_direction dir) +{ + if (IS_COHERENT_BUF(stat)) + return; + + __isp_stat_buf_sync_magic(stat, buf, buf_size, dir, + dma_sync_single_range_for_device); +} + +static void isp_stat_buf_sync_magic_for_cpu(struct ispstat *stat, + struct ispstat_buffer *buf, + u32 buf_size, + enum dma_data_direction dir) +{ + if (IS_COHERENT_BUF(stat)) + return; + + __isp_stat_buf_sync_magic(stat, buf, buf_size, dir, + dma_sync_single_range_for_cpu); +} + +static int isp_stat_buf_check_magic(struct ispstat *stat, + struct ispstat_buffer *buf) +{ + const u32 buf_size = IS_H3A_AF(stat) ? + buf->buf_size + AF_EXTRA_DATA : buf->buf_size; + u8 *w; + u8 *end; + int ret = -EINVAL; + + isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); + + /* Checking initial magic numbers. They shouldn't be here anymore. */ + for (w = buf->virt_addr, end = w + MAGIC_SIZE; w < end; w++) + if (likely(*w != MAGIC_NUM)) + ret = 0; + + if (ret) { + dev_dbg(stat->isp->dev, "%s: beginning magic check does not " + "match.\n", stat->subdev.name); + return ret; + } + + /* Checking magic numbers at the end. They must be still here. */ + for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE; + w < end; w++) { + if (unlikely(*w != MAGIC_NUM)) { + dev_dbg(stat->isp->dev, "%s: endding magic check does " + "not match.\n", stat->subdev.name); + return -EINVAL; + } + } + + isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, + DMA_FROM_DEVICE); + + return 0; +} + +static void isp_stat_buf_insert_magic(struct ispstat *stat, + struct ispstat_buffer *buf) +{ + const u32 buf_size = IS_H3A_AF(stat) ? + stat->buf_size + AF_EXTRA_DATA : stat->buf_size; + + isp_stat_buf_sync_magic_for_cpu(stat, buf, buf_size, DMA_FROM_DEVICE); + + /* + * Inserting MAGIC_NUM at the beginning and end of the buffer. + * buf->buf_size is set only after the buffer is queued. For now the + * right buf_size for the current configuration is pointed by + * stat->buf_size. + */ + memset(buf->virt_addr, MAGIC_NUM, MAGIC_SIZE); + memset(buf->virt_addr + buf_size, MAGIC_NUM, MAGIC_SIZE); + + isp_stat_buf_sync_magic_for_device(stat, buf, buf_size, + DMA_BIDIRECTIONAL); +} + +static void isp_stat_buf_sync_for_device(struct ispstat *stat, + struct ispstat_buffer *buf) +{ + if (IS_COHERENT_BUF(stat)) + return; + + dma_sync_sg_for_device(stat->isp->dev, buf->iovm->sgt->sgl, + buf->iovm->sgt->nents, DMA_FROM_DEVICE); +} + +static void isp_stat_buf_sync_for_cpu(struct ispstat *stat, + struct ispstat_buffer *buf) +{ + if (IS_COHERENT_BUF(stat)) + return; + + dma_sync_sg_for_cpu(stat->isp->dev, buf->iovm->sgt->sgl, + buf->iovm->sgt->nents, DMA_FROM_DEVICE); +} + +static void isp_stat_buf_clear(struct ispstat *stat) +{ + int i; + + for (i = 0; i < STAT_MAX_BUFS; i++) + stat->buf[i].empty = 1; +} + +static struct ispstat_buffer * +__isp_stat_buf_find(struct ispstat *stat, int look_empty) +{ + struct ispstat_buffer *found = NULL; + int i; + + for (i = 0; i < STAT_MAX_BUFS; i++) { + struct ispstat_buffer *curr = &stat->buf[i]; + + /* + * Don't select the buffer which is being copied to + * userspace or used by the module. + */ + if (curr == stat->locked_buf || curr == stat->active_buf) + continue; + + /* Don't select uninitialised buffers if it's not required */ + if (!look_empty && curr->empty) + continue; + + /* Pick uninitialised buffer over anything else if look_empty */ + if (curr->empty) { + found = curr; + break; + } + + /* Choose the oldest buffer */ + if (!found || + (s32)curr->frame_number - (s32)found->frame_number < 0) + found = curr; + } + + return found; +} + +static inline struct ispstat_buffer * +isp_stat_buf_find_oldest(struct ispstat *stat) +{ + return __isp_stat_buf_find(stat, 0); +} + +static inline struct ispstat_buffer * +isp_stat_buf_find_oldest_or_empty(struct ispstat *stat) +{ + return __isp_stat_buf_find(stat, 1); +} + +static int isp_stat_buf_queue(struct ispstat *stat) +{ + if (!stat->active_buf) + return STAT_NO_BUF; + + do_gettimeofday(&stat->active_buf->ts); + + stat->active_buf->buf_size = stat->buf_size; + if (isp_stat_buf_check_magic(stat, stat->active_buf)) { + dev_dbg(stat->isp->dev, "%s: data wasn't properly written.\n", + stat->subdev.name); + return STAT_NO_BUF; + } + stat->active_buf->config_counter = stat->config_counter; + stat->active_buf->frame_number = stat->frame_number; + stat->active_buf->empty = 0; + stat->active_buf = NULL; + + return STAT_BUF_DONE; +} + +/* Get next free buffer to write the statistics to and mark it active. */ +static void isp_stat_buf_next(struct ispstat *stat) +{ + if (unlikely(stat->active_buf)) + /* Overwriting unused active buffer */ + dev_dbg(stat->isp->dev, "%s: new buffer requested without " + "queuing active one.\n", + stat->subdev.name); + else + stat->active_buf = isp_stat_buf_find_oldest_or_empty(stat); +} + +static void isp_stat_buf_release(struct ispstat *stat) +{ + unsigned long flags; + + isp_stat_buf_sync_for_device(stat, stat->locked_buf); + spin_lock_irqsave(&stat->isp->stat_lock, flags); + stat->locked_buf = NULL; + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); +} + +/* Get buffer to userspace. */ +static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat, + struct omap3isp_stat_data *data) +{ + int rval = 0; + unsigned long flags; + struct ispstat_buffer *buf; + + spin_lock_irqsave(&stat->isp->stat_lock, flags); + + while (1) { + buf = isp_stat_buf_find_oldest(stat); + if (!buf) { + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); + dev_dbg(stat->isp->dev, "%s: cannot find a buffer.\n", + stat->subdev.name); + return ERR_PTR(-EBUSY); + } + if (isp_stat_buf_check_magic(stat, buf)) { + dev_dbg(stat->isp->dev, "%s: current buffer has " + "corrupted data\n.", stat->subdev.name); + /* Mark empty because it doesn't have valid data. */ + buf->empty = 1; + } else { + /* Buffer isn't corrupted. */ + break; + } + } + + stat->locked_buf = buf; + + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); + + if (buf->buf_size > data->buf_size) { + dev_warn(stat->isp->dev, "%s: userspace's buffer size is " + "not enough.\n", stat->subdev.name); + isp_stat_buf_release(stat); + return ERR_PTR(-EINVAL); + } + + isp_stat_buf_sync_for_cpu(stat, buf); + + rval = copy_to_user(data->buf, + buf->virt_addr, + buf->buf_size); + + if (rval) { + dev_info(stat->isp->dev, + "%s: failed copying %d bytes of stat data\n", + stat->subdev.name, rval); + buf = ERR_PTR(-EFAULT); + isp_stat_buf_release(stat); + } + + return buf; +} + +static void isp_stat_bufs_free(struct ispstat *stat) +{ + struct isp_device *isp = stat->isp; + int i; + + for (i = 0; i < STAT_MAX_BUFS; i++) { + struct ispstat_buffer *buf = &stat->buf[i]; + + if (!IS_COHERENT_BUF(stat)) { + if (IS_ERR_OR_NULL((void *)buf->iommu_addr)) + continue; + if (buf->iovm) + dma_unmap_sg(isp->dev, buf->iovm->sgt->sgl, + buf->iovm->sgt->nents, + DMA_FROM_DEVICE); + iommu_vfree(isp->iommu, buf->iommu_addr); + } else { + if (!buf->virt_addr) + continue; + dma_free_coherent(stat->isp->dev, stat->buf_alloc_size, + buf->virt_addr, buf->dma_addr); + } + buf->iommu_addr = 0; + buf->iovm = NULL; + buf->dma_addr = 0; + buf->virt_addr = NULL; + buf->empty = 1; + } + + dev_dbg(stat->isp->dev, "%s: all buffers were freed.\n", + stat->subdev.name); + + stat->buf_alloc_size = 0; + stat->active_buf = NULL; +} + +static int isp_stat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size) +{ + struct isp_device *isp = stat->isp; + int i; + + stat->buf_alloc_size = size; + + for (i = 0; i < STAT_MAX_BUFS; i++) { + struct ispstat_buffer *buf = &stat->buf[i]; + struct iovm_struct *iovm; + + WARN_ON(buf->dma_addr); + buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size, + IOMMU_FLAG); + if (IS_ERR((void *)buf->iommu_addr)) { + dev_err(stat->isp->dev, + "%s: Can't acquire memory for " + "buffer %d\n", stat->subdev.name, i); + isp_stat_bufs_free(stat); + return -ENOMEM; + } + + iovm = find_iovm_area(isp->iommu, buf->iommu_addr); + if (!iovm || + !dma_map_sg(isp->dev, iovm->sgt->sgl, iovm->sgt->nents, + DMA_FROM_DEVICE)) { + isp_stat_bufs_free(stat); + return -ENOMEM; + } + buf->iovm = iovm; + + buf->virt_addr = da_to_va(stat->isp->iommu, + (u32)buf->iommu_addr); + buf->empty = 1; + dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated." + "iommu_addr=0x%08lx virt_addr=0x%08lx", + stat->subdev.name, i, buf->iommu_addr, + (unsigned long)buf->virt_addr); + } + + return 0; +} + +static int isp_stat_bufs_alloc_dma(struct ispstat *stat, unsigned int size) +{ + int i; + + stat->buf_alloc_size = size; + + for (i = 0; i < STAT_MAX_BUFS; i++) { + struct ispstat_buffer *buf = &stat->buf[i]; + + WARN_ON(buf->iommu_addr); + buf->virt_addr = dma_alloc_coherent(stat->isp->dev, size, + &buf->dma_addr, GFP_KERNEL | GFP_DMA); + + if (!buf->virt_addr || !buf->dma_addr) { + dev_info(stat->isp->dev, + "%s: Can't acquire memory for " + "DMA buffer %d\n", stat->subdev.name, i); + isp_stat_bufs_free(stat); + return -ENOMEM; + } + buf->empty = 1; + + dev_dbg(stat->isp->dev, "%s: buffer[%d] allocated." + "dma_addr=0x%08lx virt_addr=0x%08lx\n", + stat->subdev.name, i, (unsigned long)buf->dma_addr, + (unsigned long)buf->virt_addr); + } + + return 0; +} + +static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) +{ + unsigned long flags; + + spin_lock_irqsave(&stat->isp->stat_lock, flags); + + BUG_ON(stat->locked_buf != NULL); + + /* Are the old buffers big enough? */ + if (stat->buf_alloc_size >= size) { + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); + return 0; + } + + if (stat->state != ISPSTAT_DISABLED || stat->buf_processing) { + dev_info(stat->isp->dev, + "%s: trying to allocate memory when busy\n", + stat->subdev.name); + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); + return -EBUSY; + } + + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); + + isp_stat_bufs_free(stat); + + if (IS_COHERENT_BUF(stat)) + return isp_stat_bufs_alloc_dma(stat, size); + else + return isp_stat_bufs_alloc_iommu(stat, size); +} + +static void isp_stat_queue_event(struct ispstat *stat, int err) +{ + struct video_device *vdev = &stat->subdev.devnode; + struct v4l2_event event; + struct omap3isp_stat_event_status *status = (void *)event.u.data; + + memset(&event, 0, sizeof(event)); + if (!err) { + status->frame_number = stat->frame_number; + status->config_counter = stat->config_counter; + } else { + status->buf_err = 1; + } + event.type = stat->event_type; + v4l2_event_queue(vdev, &event); +} + + +/* + * omap3isp_stat_request_statistics - Request statistics. + * @data: Pointer to return statistics data. + * + * Returns 0 if successful. + */ +int omap3isp_stat_request_statistics(struct ispstat *stat, + struct omap3isp_stat_data *data) +{ + struct ispstat_buffer *buf; + + if (stat->state != ISPSTAT_ENABLED) { + dev_dbg(stat->isp->dev, "%s: engine not enabled.\n", + stat->subdev.name); + return -EINVAL; + } + + mutex_lock(&stat->ioctl_lock); + buf = isp_stat_buf_get(stat, data); + if (IS_ERR(buf)) { + mutex_unlock(&stat->ioctl_lock); + return PTR_ERR(buf); + } + + data->ts = buf->ts; + data->config_counter = buf->config_counter; + data->frame_number = buf->frame_number; + data->buf_size = buf->buf_size; + + buf->empty = 1; + isp_stat_buf_release(stat); + mutex_unlock(&stat->ioctl_lock); + + return 0; +} + +/* + * omap3isp_stat_config - Receives new statistic engine configuration. + * @new_conf: Pointer to config structure. + * + * Returns 0 if successful, -EINVAL if new_conf pointer is NULL, -ENOMEM if + * was unable to allocate memory for the buffer, or other errors if parameters + * are invalid. + */ +int omap3isp_stat_config(struct ispstat *stat, void *new_conf) +{ + int ret; + unsigned long irqflags; + struct ispstat_generic_config *user_cfg = new_conf; + u32 buf_size = user_cfg->buf_size; + + if (!new_conf) { + dev_dbg(stat->isp->dev, "%s: configuration is NULL\n", + stat->subdev.name); + return -EINVAL; + } + + mutex_lock(&stat->ioctl_lock); + + dev_dbg(stat->isp->dev, "%s: configuring module with buffer " + "size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size); + + ret = stat->ops->validate_params(stat, new_conf); + if (ret) { + mutex_unlock(&stat->ioctl_lock); + dev_dbg(stat->isp->dev, "%s: configuration values are " + "invalid.\n", stat->subdev.name); + return ret; + } + + if (buf_size != user_cfg->buf_size) + dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size " + "request to 0x%08lx\n", stat->subdev.name, + (unsigned long)user_cfg->buf_size); + + /* + * Hack: H3A modules may need a doubled buffer size to avoid access + * to a invalid memory address after a SBL overflow. + * The buffer size is always PAGE_ALIGNED. + * Hack 2: MAGIC_SIZE is added to buf_size so a magic word can be + * inserted at the end to data integrity check purpose. + * Hack 3: AF module writes one paxel data more than it should, so + * the buffer allocation must consider it to avoid invalid memory + * access. + * Hack 4: H3A need to allocate extra space for the recover state. + */ + if (IS_H3A(stat)) { + buf_size = user_cfg->buf_size * 2 + MAGIC_SIZE; + if (IS_H3A_AF(stat)) + /* + * Adding one extra paxel data size for each recover + * buffer + 2 regular ones. + */ + buf_size += AF_EXTRA_DATA * (NUM_H3A_RECOVER_BUFS + 2); + if (stat->recover_priv) { + struct ispstat_generic_config *recover_cfg = + stat->recover_priv; + buf_size += recover_cfg->buf_size * + NUM_H3A_RECOVER_BUFS; + } + buf_size = PAGE_ALIGN(buf_size); + } else { /* Histogram */ + buf_size = PAGE_ALIGN(user_cfg->buf_size + MAGIC_SIZE); + } + + ret = isp_stat_bufs_alloc(stat, buf_size); + if (ret) { + mutex_unlock(&stat->ioctl_lock); + return ret; + } + + spin_lock_irqsave(&stat->isp->stat_lock, irqflags); + stat->ops->set_params(stat, new_conf); + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + + /* + * Returning the right future config_counter for this setup, so + * userspace can *know* when it has been applied. + */ + user_cfg->config_counter = stat->config_counter + stat->inc_config; + + /* Module has a valid configuration. */ + stat->configured = 1; + dev_dbg(stat->isp->dev, "%s: module has been successfully " + "configured.\n", stat->subdev.name); + + mutex_unlock(&stat->ioctl_lock); + + return 0; +} + +/* + * isp_stat_buf_process - Process statistic buffers. + * @buf_state: points out if buffer is ready to be processed. It's necessary + * because histogram needs to copy the data from internal memory + * before be able to process the buffer. + */ +static int isp_stat_buf_process(struct ispstat *stat, int buf_state) +{ + int ret = STAT_NO_BUF; + + if (!atomic_add_unless(&stat->buf_err, -1, 0) && + buf_state == STAT_BUF_DONE && stat->state == ISPSTAT_ENABLED) { + ret = isp_stat_buf_queue(stat); + isp_stat_buf_next(stat); + } + + return ret; +} + +int omap3isp_stat_pcr_busy(struct ispstat *stat) +{ + return stat->ops->busy(stat); +} + +int omap3isp_stat_busy(struct ispstat *stat) +{ + return omap3isp_stat_pcr_busy(stat) | stat->buf_processing | + (stat->state != ISPSTAT_DISABLED); +} + +/* + * isp_stat_pcr_enable - Disables/Enables statistic engines. + * @pcr_enable: 0/1 - Disables/Enables the engine. + * + * Must be called from ISP driver when the module is idle and synchronized + * with CCDC. + */ +static void isp_stat_pcr_enable(struct ispstat *stat, u8 pcr_enable) +{ + if ((stat->state != ISPSTAT_ENABLING && + stat->state != ISPSTAT_ENABLED) && pcr_enable) + /* Userspace has disabled the module. Aborting. */ + return; + + stat->ops->enable(stat, pcr_enable); + if (stat->state == ISPSTAT_DISABLING && !pcr_enable) + stat->state = ISPSTAT_DISABLED; + else if (stat->state == ISPSTAT_ENABLING && pcr_enable) + stat->state = ISPSTAT_ENABLED; +} + +void omap3isp_stat_suspend(struct ispstat *stat) +{ + unsigned long flags; + + spin_lock_irqsave(&stat->isp->stat_lock, flags); + + if (stat->state != ISPSTAT_DISABLED) + stat->ops->enable(stat, 0); + if (stat->state == ISPSTAT_ENABLED) + stat->state = ISPSTAT_SUSPENDED; + + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); +} + +void omap3isp_stat_resume(struct ispstat *stat) +{ + /* Module will be re-enabled with its pipeline */ + if (stat->state == ISPSTAT_SUSPENDED) + stat->state = ISPSTAT_ENABLING; +} + +static void isp_stat_try_enable(struct ispstat *stat) +{ + unsigned long irqflags; + + if (stat->priv == NULL) + /* driver wasn't initialised */ + return; + + spin_lock_irqsave(&stat->isp->stat_lock, irqflags); + if (stat->state == ISPSTAT_ENABLING && !stat->buf_processing && + stat->buf_alloc_size) { + /* + * Userspace's requested to enable the engine but it wasn't yet. + * Let's do that now. + */ + stat->update = 1; + isp_stat_buf_next(stat); + stat->ops->setup_regs(stat, stat->priv); + isp_stat_buf_insert_magic(stat, stat->active_buf); + + /* + * H3A module has some hw issues which forces the driver to + * ignore next buffers even if it was disabled in the meantime. + * On the other hand, Histogram shouldn't ignore buffers anymore + * if it's being enabled. + */ + if (!IS_H3A(stat)) + atomic_set(&stat->buf_err, 0); + + isp_stat_pcr_enable(stat, 1); + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + dev_dbg(stat->isp->dev, "%s: module is enabled.\n", + stat->subdev.name); + } else { + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + } +} + +void omap3isp_stat_isr_frame_sync(struct ispstat *stat) +{ + isp_stat_try_enable(stat); +} + +void omap3isp_stat_sbl_overflow(struct ispstat *stat) +{ + unsigned long irqflags; + + spin_lock_irqsave(&stat->isp->stat_lock, irqflags); + /* + * Due to a H3A hw issue which prevents the next buffer to start from + * the correct memory address, 2 buffers must be ignored. + */ + atomic_set(&stat->buf_err, 2); + + /* + * If more than one SBL overflow happen in a row, H3A module may access + * invalid memory region. + * stat->sbl_ovl_recover is set to tell to the driver to temporarily use + * a soft configuration which helps to avoid consecutive overflows. + */ + if (stat->recover_priv) + stat->sbl_ovl_recover = 1; + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); +} + +/* + * omap3isp_stat_enable - Disable/Enable statistic engine as soon as possible + * @enable: 0/1 - Disables/Enables the engine. + * + * Client should configure all the module registers before this. + * This function can be called from a userspace request. + */ +int omap3isp_stat_enable(struct ispstat *stat, u8 enable) +{ + unsigned long irqflags; + + dev_dbg(stat->isp->dev, "%s: user wants to %s module.\n", + stat->subdev.name, enable ? "enable" : "disable"); + + /* Prevent enabling while configuring */ + mutex_lock(&stat->ioctl_lock); + + spin_lock_irqsave(&stat->isp->stat_lock, irqflags); + + if (!stat->configured && enable) { + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + mutex_unlock(&stat->ioctl_lock); + dev_dbg(stat->isp->dev, "%s: cannot enable module as it's " + "never been successfully configured so far.\n", + stat->subdev.name); + return -EINVAL; + } + + if (enable) { + if (stat->state == ISPSTAT_DISABLING) + /* Previous disabling request wasn't done yet */ + stat->state = ISPSTAT_ENABLED; + else if (stat->state == ISPSTAT_DISABLED) + /* Module is now being enabled */ + stat->state = ISPSTAT_ENABLING; + } else { + if (stat->state == ISPSTAT_ENABLING) { + /* Previous enabling request wasn't done yet */ + stat->state = ISPSTAT_DISABLED; + } else if (stat->state == ISPSTAT_ENABLED) { + /* Module is now being disabled */ + stat->state = ISPSTAT_DISABLING; + isp_stat_buf_clear(stat); + } + } + + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + mutex_unlock(&stat->ioctl_lock); + + return 0; +} + +int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct ispstat *stat = v4l2_get_subdevdata(subdev); + + if (enable) { + /* + * Only set enable PCR bit if the module was previously + * enabled through ioct. + */ + isp_stat_try_enable(stat); + } else { + unsigned long flags; + /* Disable PCR bit and config enable field */ + omap3isp_stat_enable(stat, 0); + spin_lock_irqsave(&stat->isp->stat_lock, flags); + stat->ops->enable(stat, 0); + spin_unlock_irqrestore(&stat->isp->stat_lock, flags); + + /* + * If module isn't busy, a new interrupt may come or not to + * set the state to DISABLED. As Histogram needs to read its + * internal memory to clear it, let interrupt handler + * responsible of changing state to DISABLED. If the last + * interrupt is coming, it's still safe as the handler will + * ignore the second time when state is already set to DISABLED. + * It's necessary to synchronize Histogram with streamoff, once + * the module may be considered idle before last SDMA transfer + * starts if we return here. + */ + if (!omap3isp_stat_pcr_busy(stat)) + omap3isp_stat_isr(stat); + + dev_dbg(stat->isp->dev, "%s: module is being disabled\n", + stat->subdev.name); + } + + return 0; +} + +/* + * __stat_isr - Interrupt handler for statistic drivers + */ +static void __stat_isr(struct ispstat *stat, int from_dma) +{ + int ret = STAT_BUF_DONE; + int buf_processing; + unsigned long irqflags; + struct isp_pipeline *pipe; + + /* + * stat->buf_processing must be set before disable module. It's + * necessary to not inform too early the buffers aren't busy in case + * of SDMA is going to be used. + */ + spin_lock_irqsave(&stat->isp->stat_lock, irqflags); + if (stat->state == ISPSTAT_DISABLED) { + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + return; + } + buf_processing = stat->buf_processing; + stat->buf_processing = 1; + stat->ops->enable(stat, 0); + + if (buf_processing && !from_dma) { + if (stat->state == ISPSTAT_ENABLED) { + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + dev_err(stat->isp->dev, + "%s: interrupt occurred when module was still " + "processing a buffer.\n", stat->subdev.name); + ret = STAT_NO_BUF; + goto out; + } else { + /* + * Interrupt handler was called from streamoff when + * the module wasn't busy anymore to ensure it is being + * disabled after process last buffer. If such buffer + * processing has already started, no need to do + * anything else. + */ + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + return; + } + } + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + + /* If it's busy we can't process this buffer anymore */ + if (!omap3isp_stat_pcr_busy(stat)) { + if (!from_dma && stat->ops->buf_process) + /* Module still need to copy data to buffer. */ + ret = stat->ops->buf_process(stat); + if (ret == STAT_BUF_WAITING_DMA) + /* Buffer is not ready yet */ + return; + + spin_lock_irqsave(&stat->isp->stat_lock, irqflags); + + /* + * Histogram needs to read its internal memory to clear it + * before be disabled. For that reason, common statistic layer + * can return only after call stat's buf_process() operator. + */ + if (stat->state == ISPSTAT_DISABLING) { + stat->state = ISPSTAT_DISABLED; + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + stat->buf_processing = 0; + return; + } + pipe = to_isp_pipeline(&stat->subdev.entity); + stat->frame_number = atomic_read(&pipe->frame_number); + + /* + * Before this point, 'ret' stores the buffer's status if it's + * ready to be processed. Afterwards, it holds the status if + * it was processed successfully. + */ + ret = isp_stat_buf_process(stat, ret); + + if (likely(!stat->sbl_ovl_recover)) { + stat->ops->setup_regs(stat, stat->priv); + } else { + /* + * Using recover config to increase the chance to have + * a good buffer processing and make the H3A module to + * go back to a valid state. + */ + stat->update = 1; + stat->ops->setup_regs(stat, stat->recover_priv); + stat->sbl_ovl_recover = 0; + + /* + * Set 'update' in case of the module needs to use + * regular configuration after next buffer. + */ + stat->update = 1; + } + + isp_stat_buf_insert_magic(stat, stat->active_buf); + + /* + * Hack: H3A modules may access invalid memory address or send + * corrupted data to userspace if more than 1 SBL overflow + * happens in a row without re-writing its buffer's start memory + * address in the meantime. Such situation is avoided if the + * module is not immediately re-enabled when the ISR misses the + * timing to process the buffer and to setup the registers. + * Because of that, pcr_enable(1) was moved to inside this 'if' + * block. But the next interruption will still happen as during + * pcr_enable(0) the module was busy. + */ + isp_stat_pcr_enable(stat, 1); + spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); + } else { + /* + * If a SBL overflow occurs and the H3A driver misses the timing + * to process the buffer, stat->buf_err is set and won't be + * cleared now. So the next buffer will be correctly ignored. + * It's necessary due to a hw issue which makes the next H3A + * buffer to start from the memory address where the previous + * one stopped, instead of start where it was configured to. + * Do not "stat->buf_err = 0" here. + */ + + if (stat->ops->buf_process) + /* + * Driver may need to erase current data prior to + * process a new buffer. If it misses the timing, the + * next buffer might be wrong. So should be ignored. + * It happens only for Histogram. + */ + atomic_set(&stat->buf_err, 1); + + ret = STAT_NO_BUF; + dev_dbg(stat->isp->dev, "%s: cannot process buffer, " + "device is busy.\n", stat->subdev.name); + } + +out: + stat->buf_processing = 0; + isp_stat_queue_event(stat, ret != STAT_BUF_DONE); +} + +void omap3isp_stat_isr(struct ispstat *stat) +{ + __stat_isr(stat, 0); +} + +void omap3isp_stat_dma_isr(struct ispstat *stat) +{ + __stat_isr(stat, 1); +} + +static int isp_stat_init_entities(struct ispstat *stat, const char *name, + const struct v4l2_subdev_ops *sd_ops) +{ + struct v4l2_subdev *subdev = &stat->subdev; + struct media_entity *me = &subdev->entity; + + v4l2_subdev_init(subdev, sd_ops); + snprintf(subdev->name, V4L2_SUBDEV_NAME_SIZE, "OMAP3 ISP %s", name); + subdev->grp_id = 1 << 16; /* group ID for isp subdevs */ + subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; + subdev->nevents = STAT_NEVENTS; + v4l2_set_subdevdata(subdev, stat); + + stat->pad.flags = MEDIA_PAD_FL_SINK; + me->ops = NULL; + + return media_entity_init(me, 1, &stat->pad, 0); +} + +int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + struct ispstat *stat = v4l2_get_subdevdata(subdev); + + if (sub->type != stat->event_type) + return -EINVAL; + + return v4l2_event_subscribe(fh, sub); +} + +int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + return v4l2_event_unsubscribe(fh, sub); +} + +void omap3isp_stat_unregister_entities(struct ispstat *stat) +{ + media_entity_cleanup(&stat->subdev.entity); + v4l2_device_unregister_subdev(&stat->subdev); +} + +int omap3isp_stat_register_entities(struct ispstat *stat, + struct v4l2_device *vdev) +{ + return v4l2_device_register_subdev(vdev, &stat->subdev); +} + +int omap3isp_stat_init(struct ispstat *stat, const char *name, + const struct v4l2_subdev_ops *sd_ops) +{ + stat->buf = kcalloc(STAT_MAX_BUFS, sizeof(*stat->buf), GFP_KERNEL); + if (!stat->buf) + return -ENOMEM; + isp_stat_buf_clear(stat); + mutex_init(&stat->ioctl_lock); + atomic_set(&stat->buf_err, 0); + + return isp_stat_init_entities(stat, name, sd_ops); +} + +void omap3isp_stat_free(struct ispstat *stat) +{ + isp_stat_bufs_free(stat); + kfree(stat->buf); +} diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h new file mode 100644 index 000000000000..820950c9ef46 --- /dev/null +++ b/drivers/media/video/omap3isp/ispstat.h @@ -0,0 +1,169 @@ +/* + * ispstat.h + * + * TI OMAP3 ISP - Statistics core + * + * Copyright (C) 2010 Nokia Corporation + * Copyright (C) 2009 Texas Instruments, Inc + * + * Contacts: David Cohen + * Laurent Pinchart + * Sakari Ailus + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#ifndef OMAP3_ISP_STAT_H +#define OMAP3_ISP_STAT_H + +#include +#include +#include +#include + +#include "isp.h" +#include "ispvideo.h" + +#define STAT_MAX_BUFS 5 +#define STAT_NEVENTS 8 + +#define STAT_BUF_DONE 0 /* Buffer is ready */ +#define STAT_NO_BUF 1 /* An error has occurred */ +#define STAT_BUF_WAITING_DMA 2 /* Histogram only: DMA is running */ + +struct ispstat; + +struct ispstat_buffer { + unsigned long iommu_addr; + struct iovm_struct *iovm; + void *virt_addr; + dma_addr_t dma_addr; + struct timeval ts; + u32 buf_size; + u32 frame_number; + u16 config_counter; + u8 empty; +}; + +struct ispstat_ops { + /* + * Validate new params configuration. + * new_conf->buf_size value must be changed to the exact buffer size + * necessary for the new configuration if it's smaller. + */ + int (*validate_params)(struct ispstat *stat, void *new_conf); + + /* + * Save new params configuration. + * stat->priv->buf_size value must be set to the exact buffer size for + * the new configuration. + * stat->update is set to 1 if new configuration is different than + * current one. + */ + void (*set_params)(struct ispstat *stat, void *new_conf); + + /* Apply stored configuration. */ + void (*setup_regs)(struct ispstat *stat, void *priv); + + /* Enable/Disable module. */ + void (*enable)(struct ispstat *stat, int enable); + + /* Verify is module is busy. */ + int (*busy)(struct ispstat *stat); + + /* Used for specific operations during generic buf process task. */ + int (*buf_process)(struct ispstat *stat); +}; + +enum ispstat_state_t { + ISPSTAT_DISABLED = 0, + ISPSTAT_DISABLING, + ISPSTAT_ENABLED, + ISPSTAT_ENABLING, + ISPSTAT_SUSPENDED, +}; + +struct ispstat { + struct v4l2_subdev subdev; + struct media_pad pad; /* sink pad */ + + /* Control */ + unsigned configured:1; + unsigned update:1; + unsigned buf_processing:1; + unsigned sbl_ovl_recover:1; + u8 inc_config; + atomic_t buf_err; + enum ispstat_state_t state; /* enabling/disabling state */ + struct omap_dma_channel_params dma_config; + struct isp_device *isp; + void *priv; /* pointer to priv config struct */ + void *recover_priv; /* pointer to recover priv configuration */ + struct mutex ioctl_lock; /* serialize private ioctl */ + + const struct ispstat_ops *ops; + + /* Buffer */ + u8 wait_acc_frames; + u16 config_counter; + u32 frame_number; + u32 buf_size; + u32 buf_alloc_size; + int dma_ch; + unsigned long event_type; + struct ispstat_buffer *buf; + struct ispstat_buffer *active_buf; + struct ispstat_buffer *locked_buf; +}; + +struct ispstat_generic_config { + /* + * Fields must be in the same order as in: + * - isph3a_aewb_config + * - isph3a_af_config + * - isphist_config + */ + u32 buf_size; + u16 config_counter; +}; + +int omap3isp_stat_config(struct ispstat *stat, void *new_conf); +int omap3isp_stat_request_statistics(struct ispstat *stat, + struct omap3isp_stat_data *data); +int omap3isp_stat_init(struct ispstat *stat, const char *name, + const struct v4l2_subdev_ops *sd_ops); +void omap3isp_stat_free(struct ispstat *stat); +int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); +int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub); +int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable); + +int omap3isp_stat_busy(struct ispstat *stat); +int omap3isp_stat_pcr_busy(struct ispstat *stat); +void omap3isp_stat_suspend(struct ispstat *stat); +void omap3isp_stat_resume(struct ispstat *stat); +int omap3isp_stat_enable(struct ispstat *stat, u8 enable); +void omap3isp_stat_sbl_overflow(struct ispstat *stat); +void omap3isp_stat_isr(struct ispstat *stat); +void omap3isp_stat_isr_frame_sync(struct ispstat *stat); +void omap3isp_stat_dma_isr(struct ispstat *stat); +int omap3isp_stat_register_entities(struct ispstat *stat, + struct v4l2_device *vdev); +void omap3isp_stat_unregister_entities(struct ispstat *stat); + +#endif /* OMAP3_ISP_STAT_H */ -- cgit v1.2.2 From 7e8970e1d5ae9237d00909599e70f85fce1fc489 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 12 Feb 2011 18:05:06 -0300 Subject: [media] omap3isp: Kconfig and Makefile Add the OMAP3 ISP driver to the kernel build system. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 13 +++++++++++++ drivers/media/video/Makefile | 2 ++ drivers/media/video/omap3isp/Makefile | 13 +++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 drivers/media/video/omap3isp/Makefile (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index e2f5a69aa400..4498b944dec8 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -746,6 +746,19 @@ config VIDEO_NOON010PC30 ---help--- This driver supports NOON010PC30 CIF camera from Siliconfile +config VIDEO_OMAP3 + tristate "OMAP 3 Camera support (EXPERIMENTAL)" + select OMAP_IOMMU + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 && EXPERIMENTAL + ---help--- + Driver for an OMAP 3 camera controller. + +config VIDEO_OMAP3_DEBUG + bool "OMAP 3 Camera debug messages" + depends on VIDEO_OMAP3 + ---help--- + Enable debug messages on OMAP 3 camera controller driver. + config SOC_CAMERA tristate "SoC camera support" depends on VIDEO_V4L2 && HAS_DMA && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 7ea65163090e..ace5d8b57221 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -129,6 +129,8 @@ obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o +obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ + obj-$(CONFIG_USB_ZR364XX) += zr364xx.o obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o diff --git a/drivers/media/video/omap3isp/Makefile b/drivers/media/video/omap3isp/Makefile new file mode 100644 index 000000000000..b1b344774ae7 --- /dev/null +++ b/drivers/media/video/omap3isp/Makefile @@ -0,0 +1,13 @@ +# Makefile for OMAP3 ISP driver + +ifdef CONFIG_VIDEO_OMAP3_DEBUG +EXTRA_CFLAGS += -DDEBUG +endif + +omap3-isp-objs += \ + isp.o ispqueue.o ispvideo.o \ + ispcsiphy.o ispccp2.o ispcsi2.o \ + ispccdc.o isppreview.o ispresizer.o \ + ispstat.o isph3a_aewb.o isph3a_af.o isphist.o + +obj-$(CONFIG_VIDEO_OMAP3) += omap3-isp.o -- cgit v1.2.2 From 4b0ec19e02fabdd09fc2f4754304894bbefb3f45 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 3 Mar 2011 10:05:22 -0300 Subject: [media] omap3isp: Add set performance callback in isp platform data Replace the omap_pm_set_min_bus_tput() with a callback to board code. This makes the omap3isp driver compilable as a module, and lets board code manage OMAP PM details depending on board requirements. Signed-off-by: Stanimir Varbanov Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.h | 1 + drivers/media/video/omap3isp/ispvideo.c | 21 ++++++--------------- 2 files changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index a8dfea413d34..cf5214e95a92 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -199,6 +199,7 @@ struct isp_v4l2_subdevs_group { struct isp_platform_data { struct isp_v4l2_subdevs_group *subdevs; + void (*set_constraints)(struct isp_device *isp, bool enable); }; struct isp_platform_callback { diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 517a24de5836..a0bb5db9cb8a 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -921,18 +921,8 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) pipe->output = far_end; } - /* Make sure the interconnect clock runs fast enough. - * - * Formula from: resource34xx.c set_opp() - * If MPU freq is above 500MHz, make sure the interconnect - * is at 100Mhz or above. - * throughput in KiB/s for 100 Mhz = 100 * 1000 * 4. - * - * We want to be fast enough then set OCP clock to be max as - * possible, in that case 185Mhz then: - * throughput in KiB/s for 185Mhz = 185 * 1000 * 4 = 740000 KiB/s - */ - omap_pm_set_min_bus_tput(video->isp->dev, OCP_INITIATOR_AGENT, 740000); + if (video->isp->pdata->set_constraints) + video->isp->pdata->set_constraints(video->isp, true); pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); /* Validate the pipeline and update its state. */ @@ -978,8 +968,8 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) error: if (ret < 0) { omap3isp_video_queue_streamoff(&vfh->queue); - omap_pm_set_min_bus_tput(video->isp->dev, - OCP_INITIATOR_AGENT, 0); + if (video->isp->pdata->set_constraints) + video->isp->pdata->set_constraints(video->isp, false); media_entity_pipeline_stop(&video->video.entity); video->queue = NULL; } @@ -1032,7 +1022,8 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) video->queue = NULL; video->streaming = 0; - omap_pm_set_min_bus_tput(video->isp->dev, OCP_INITIATOR_AGENT, 0); + if (video->isp->pdata->set_constraints) + video->isp->pdata->set_constraints(video->isp, false); media_entity_pipeline_stop(&video->video.entity); done: -- cgit v1.2.2 From aa40d194975e23ba7a55936c7b5dae4e964461b5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 6 Mar 2011 09:24:32 -0300 Subject: [media] tuner-xc2028.c: fix compile warning drivers/media/common/tuners/tuner-xc2028.c: In function 'generic_set_freq': drivers/media/common/tuners/tuner-xc2028.c:936:15: warning: comparison between 'enum tuner_mode' and 'enum v4l2_tuner_type' Argument type was enum tuner_mode, but should have been enum v4l2_tuner_type. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tuner-xc2028.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index efcbc3ed0aea..16fba6b59616 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c @@ -907,7 +907,7 @@ ret: #define DIV 15625 static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, - enum tuner_mode new_mode, + enum v4l2_tuner_type new_type, unsigned int type, v4l2_std_id std, u16 int_freq) @@ -933,7 +933,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, * that xc2028 will be in a safe state. * Maybe this might also be needed for DTV. */ - if (new_mode == V4L2_TUNER_ANALOG_TV) { + if (new_type == V4L2_TUNER_ANALOG_TV) { rc = send_seq(priv, {0x00, 0x00}); /* Analog modes require offset = 0 */ -- cgit v1.2.2 From fb661a78699ad34c385a014fe0d17226234f8496 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 6 Mar 2011 09:26:24 -0300 Subject: [media] stv0367.c: fix compiler warning drivers/media/dvb/frontends/stv0367.c: In function 'stv0367ter_lock_algo': drivers/media/dvb/frontends/stv0367.c:1315:2: warning: cast from pointer to integer of different size Use %p to print addresses instead of 0x%x. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index eecdf23642eb..f910d0db8156 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -1312,7 +1312,7 @@ stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state) tmp = stv0367_readreg(state, R367TER_SYR_STAT); tmp2 = stv0367_readreg(state, R367TER_STATUS); - dprintk("state=0x%x\n", (int)state); + dprintk("state=%p\n", state); dprintk("LOCK OK! mode=%d SYR_STAT=0x%x R367TER_STATUS=0x%x\n", mode, tmp, tmp2); -- cgit v1.2.2 From 3920d6b34d7f6d4e81773b6bbd93d53c167b048f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 6 Mar 2011 09:27:44 -0300 Subject: [media] altera-ci.c: fix compiler warnings drivers/media/video/cx23885/altera-ci.c: In function 'altera_hw_filt_init': drivers/media/video/cx23885/altera-ci.c:671:2: warning: cast from pointer to integer of different size drivers/media/video/cx23885/altera-ci.c: In function 'altera_ci_init': drivers/media/video/cx23885/altera-ci.c:739:2: warning: cast from pointer to integer of different size Use %p instead of 0x%x to print addresses. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/altera-ci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c index ad6cc68d4b0c..4269e053830c 100644 --- a/drivers/media/video/cx23885/altera-ci.c +++ b/drivers/media/video/cx23885/altera-ci.c @@ -668,8 +668,8 @@ int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) ci_dbg_print("%s: Create New Internal Structure!\n", __func__); } - ci_dbg_print("%s: setting hw pid filter = 0x%x for ci = %d\n", __func__, - (int)pid_filt, hw_filt_nr - 1); + ci_dbg_print("%s: setting hw pid filter = %p for ci = %d\n", __func__, + pid_filt, hw_filt_nr - 1); inter->pid_filt[hw_filt_nr - 1] = pid_filt; pid_filt->demux = config->demux; pid_filt->internal = inter; @@ -736,8 +736,8 @@ int altera_ci_init(struct altera_ci_config *config, int ci_nr) ci_dbg_print("%s: Create New Internal Structure!\n", __func__); } - ci_dbg_print("%s: setting state = 0x%x for ci = %d\n", __func__, - (int)state, ci_nr - 1); + ci_dbg_print("%s: setting state = %p for ci = %d\n", __func__, + state, ci_nr - 1); inter->state[ci_nr - 1] = state; state->internal = inter; state->nr = ci_nr - 1; -- cgit v1.2.2 From cfa746b39c2db17f2fde301e347324ac89fc5ea9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 6 Mar 2011 09:30:02 -0300 Subject: [media] fmdrv_common.c: fix compiler warning drivers/media/radio/wl128x/fmdrv_common.c: In function 'recv_tasklet': drivers/media/radio/wl128x/fmdrv_common.c:274:4: warning: format '%d' expects type 'int', but argument 4 has type 'long unsigned int' The result of sizeof() should be printed with %zu. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 12f4c656e8e8..64454d39c0ca 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -271,8 +271,8 @@ static void recv_tasklet(unsigned long arg) /* Process all packets in the RX queue */ while ((skb = skb_dequeue(&fmdev->rx_q))) { if (skb->len < sizeof(struct fm_event_msg_hdr)) { - fmerr("skb(%p) has only %d bytes" - "atleast need %d bytes to decode\n", skb, + fmerr("skb(%p) has only %d bytes, " + "at least need %zu bytes to decode\n", skb, skb->len, sizeof(struct fm_event_msg_hdr)); kfree_skb(skb); continue; -- cgit v1.2.2 From d6972cc8a35514a518ef9c9f608327851cd2e856 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 6 Mar 2011 09:31:00 -0300 Subject: [media] cx88-alsa: fix compiler warning drivers/media/video/cx88/cx88-alsa.c: In function 'cx88_audio_initdev': drivers/media/video/cx88/cx88-alsa.c:881:20: warning: 'core' may be used uninitialized in this function The compiler doesn't understand that snd_cx88_create fills in the core pointer. So just initialize it to NULL. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx88/cx88-alsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index a2d688ebed90..423c1af8a782 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -878,7 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, { struct snd_card *card; snd_cx88_card_t *chip; - struct cx88_core *core; + struct cx88_core *core = NULL; int err; if (devno >= SNDRV_CARDS) -- cgit v1.2.2 From fa9448d9bdbae42bb10545f6fcfc980f38f53aa8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 6 Mar 2011 09:49:37 -0300 Subject: [media] altera-ci.h: add missing inline Functions defined in a header should be static inline. This prevents compile warnings like: 'altera_ci_tuner_reset' defined but not used (Actually appeared in the media backwards compatibility build). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/altera-ci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/altera-ci.h b/drivers/media/video/cx23885/altera-ci.h index bf0aa2c9b070..70e4fd69ad9e 100644 --- a/drivers/media/video/cx23885/altera-ci.h +++ b/drivers/media/video/cx23885/altera-ci.h @@ -68,7 +68,7 @@ static inline int altera_ci_irq(void *dev) return 0; } -static int altera_ci_tuner_reset(void *dev, int ci_nr) +static inline int altera_ci_tuner_reset(void *dev, int ci_nr) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return 0; -- cgit v1.2.2 From 972d724caf8b6c461b585c800d6460a12c098a5e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 11 Mar 2011 16:51:18 -0300 Subject: [media] several drivers: Fix a few gcc 4.6 warnings au0828-dvb.c:99:6: warning: variable 'ptr' set but not used [-Wunused-but-set-variable] au0828-video.c:1180:25: warning: variable 'maxheight' set but not used [-Wunused-but-set-variable] au0828-video.c:1180:15: warning: variable 'maxwidth' set but not used [-Wunused-but-set-variable] bttv-input.c:196:16: warning: variable 'current_jiffies' set but not used [-Wunused-but-set-variable] Those variables are not used at all, so just remove them. Cc: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/au0828/au0828-dvb.c | 3 --- drivers/media/video/au0828/au0828-video.c | 4 ---- drivers/media/video/bt8xx/bttv-input.c | 2 -- 3 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c index f1edf1d4afe8..518216743c9c 100644 --- a/drivers/media/video/au0828/au0828-dvb.c +++ b/drivers/media/video/au0828/au0828-dvb.c @@ -96,7 +96,6 @@ static struct tda18271_config hauppauge_woodbury_tunerconfig = { /*-------------------------------------------------------------------*/ static void urb_completion(struct urb *purb) { - u8 *ptr; struct au0828_dev *dev = purb->context; int ptype = usb_pipetype(purb->pipe); @@ -114,8 +113,6 @@ static void urb_completion(struct urb *purb) return; } - ptr = (u8 *)purb->transfer_buffer; - /* Feed the transport payload into the kernel demux */ dvb_dmx_swfilter_packets(&dev->dvb.demux, purb->transfer_buffer, purb->actual_length / 188); diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 9c475c600fc9..6ad83a15d073 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c @@ -1177,10 +1177,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, int ret; int width = format->fmt.pix.width; int height = format->fmt.pix.height; - unsigned int maxwidth, maxheight; - - maxwidth = 720; - maxheight = 480; if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index e8b64bca9db2..677d70c0e1ce 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -193,12 +193,10 @@ static void bttv_rc5_timer_end(unsigned long data) { struct bttv_ir *ir = (struct bttv_ir *)data; struct timeval tv; - unsigned long current_jiffies; u32 gap; u32 rc5 = 0; /* get time */ - current_jiffies = jiffies; do_gettimeofday(&tv); /* avoid overflow with gap >1s */ -- cgit v1.2.2 From 1039752353f1308bcd594a79196f60a22d45975d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 11 Mar 2011 17:00:01 -0300 Subject: [media] cpia2: Fix some gcc 4.6 warnings when debug is disabled cpia2_core.c:529:14: warning: variable 'dir' set but not used [-Wunused-but-set-variable] cpia2_core.c:526:5: warning: variable 'block_index' set but not used [-Wunused-but-set-variable] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cpia2/cpia2_core.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c index aaffca8e13fd..ee91e295c90a 100644 --- a/drivers/media/video/cpia2/cpia2_core.c +++ b/drivers/media/video/cpia2/cpia2_core.c @@ -519,22 +519,16 @@ int cpia2_do_command(struct camera_data *cam, * cpia2_send_command * *****************************************************************************/ + +#define DIR(cmd) ((cmd->direction == TRANSFER_WRITE) ? "Write" : "Read") +#define BINDEX(cmd) (cmd->req_mode & 0x03) + int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd) { u8 count; u8 start; - u8 block_index; u8 *buffer; int retval; - const char* dir; - - if (cmd->direction == TRANSFER_WRITE) { - dir = "Write"; - } else { - dir = "Read"; - } - - block_index = cmd->req_mode & 0x03; switch (cmd->req_mode & 0x0c) { case CAMERAACCESS_TYPE_RANDOM: @@ -542,32 +536,32 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd) start = 0; buffer = (u8 *) & cmd->buffer; if (debugs_on & DEBUG_REG) - DBG("%s Random: Register block %s\n", dir, - block_name[block_index]); + DBG("%s Random: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); break; case CAMERAACCESS_TYPE_BLOCK: count = cmd->reg_count; start = cmd->start; buffer = cmd->buffer.block_data; if (debugs_on & DEBUG_REG) - DBG("%s Block: Register block %s\n", dir, - block_name[block_index]); + DBG("%s Block: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); break; case CAMERAACCESS_TYPE_MASK: count = cmd->reg_count * sizeof(struct cpia2_reg_mask); start = 0; buffer = (u8 *) & cmd->buffer; if (debugs_on & DEBUG_REG) - DBG("%s Mask: Register block %s\n", dir, - block_name[block_index]); + DBG("%s Mask: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); break; case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */ count = cmd->reg_count; start = cmd->start; buffer = cmd->buffer.block_data; if (debugs_on & DEBUG_REG) - DBG("%s Repeat: Register block %s\n", dir, - block_name[block_index]); + DBG("%s Repeat: Register block %s\n", DIR(cmd), + block_name[BINDEX(cmd)]); break; default: LOG("%s: invalid request mode\n",__func__); @@ -584,10 +578,10 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd) for (i = 0; i < cmd->reg_count; i++) { if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK) KINFO("%s Block: [0x%02X] = 0x%02X\n", - dir, start + i, buffer[i]); + DIR(cmd), start + i, buffer[i]); if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM) KINFO("%s Random: [0x%02X] = 0x%02X\n", - dir, cmd->buffer.registers[i].index, + DIR(cmd), cmd->buffer.registers[i].index, cmd->buffer.registers[i].value); } } -- cgit v1.2.2 From d164460f897e2ae8c48ca28c763bb1233d180e7e Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sun, 2 Jan 2011 09:10:00 -0300 Subject: [media] cx23885: Altera FPGA CI interface reworked It decreases I2C traffic. Signed-off-by: Abylay Ospan Signed-off-by: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index cf36b9b4794e..c0e665506750 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -620,29 +620,29 @@ int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; unsigned long timeout = jiffies + msecs_to_jiffies(1); - int mem = 0; + uint32_t mem = 0; - cx_set(MC417_RWD, ALT_RD | ALT_WR | ALT_CS); + mem = cx_read(MC417_RWD); if (read) cx_set(MC417_OEN, ALT_DATA); else { cx_clear(MC417_OEN, ALT_DATA);/* D0-D7 out */ - mem = cx_read(MC417_RWD); mem &= ~ALT_DATA; mem |= (data & ALT_DATA); - cx_write(MC417_RWD, mem); } if (flag) - cx_set(MC417_RWD, ALT_AD_RG);/* ADDR */ + mem |= ALT_AD_RG; else - cx_clear(MC417_RWD, ALT_AD_RG);/* VAL */ + mem &= ~ALT_AD_RG; - cx_clear(MC417_RWD, ALT_CS);/* ~CS */ + mem &= ~ALT_CS; if (read) - cx_clear(MC417_RWD, ALT_RD); + mem = (mem & ~ALT_RD) | ALT_WR; else - cx_clear(MC417_RWD, ALT_WR); + mem = (mem & ~ALT_WR) | ALT_RD; + + cx_write(MC417_RWD, mem); /* start RW cycle */ for (;;) { mem = cx_read(MC417_RWD); -- cgit v1.2.2 From 01a475df3d178d9ace345cc81173537970cf93e2 Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sun, 2 Jan 2011 09:11:00 -0300 Subject: [media] stv0367: change default value for AGC register Signed-off-by: Abylay Ospan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0367.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index f910d0db8156..6d4d49ecbee6 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -286,7 +286,7 @@ static struct st_register def0367ter[STV0367TER_NBREGS] = { {R367TER_PLLMDIV, 0x01},/* for xc5000; was 0x0c */ {R367TER_PLLNDIV, 0x06},/* for xc5000; was 0x55 */ {R367TER_PLLSETUP, 0x18}, - {R367TER_DUAL_AD12, 0x04},/* for xc5000; was 0x00 */ + {R367TER_DUAL_AD12, 0x0C},/* for xc5000 AGC voltage 1.6V */ {R367TER_TSTBIST, 0x00}, {R367TER_PAD_COMP_CTRL, 0x00}, {R367TER_PAD_COMP_WR, 0x00}, @@ -599,7 +599,7 @@ static struct st_register def0367cab[STV0367CAB_NBREGS] = { {R367CAB_PLLMDIV, 0x01}, {R367CAB_PLLNDIV, 0x08}, {R367CAB_PLLSETUP, 0x18}, - {R367CAB_DUAL_AD12, 0x04}, + {R367CAB_DUAL_AD12, 0x0C}, /* for xc5000 AGC voltage 1.6V */ {R367CAB_TSTBIST, 0x00}, {R367CAB_CTRL_1, 0x00}, {R367CAB_CTRL_2, 0x03}, -- cgit v1.2.2 From 78db66e5b2b4ef48eeede17a7159cb0622c7f03d Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sun, 2 Jan 2011 09:12:00 -0300 Subject: [media] stv0367: implement uncorrected blocks counter Signed-off-by: Abylay Ospan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0367.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index 6d4d49ecbee6..120fed8229a8 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -3367,6 +3367,24 @@ static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; } +static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct stv0367_state *state = fe->demodulator_priv; + int corrected, tscount; + + *ucblocks = (stv0367_readreg(state, R367CAB_RS_COUNTER_5) << 8) + | stv0367_readreg(state, R367CAB_RS_COUNTER_4); + corrected = (stv0367_readreg(state, R367CAB_RS_COUNTER_3) << 8) + | stv0367_readreg(state, R367CAB_RS_COUNTER_2); + tscount = (stv0367_readreg(state, R367CAB_RS_COUNTER_2) << 8) + | stv0367_readreg(state, R367CAB_RS_COUNTER_1); + + dprintk("%s: uncorrected blocks=%d corrected blocks=%d tscount=%d\n", + __func__, *ucblocks, corrected, tscount); + + return 0; +}; + static struct dvb_frontend_ops stv0367cab_ops = { .info = { .name = "ST STV0367 DVB-C", @@ -3391,7 +3409,7 @@ static struct dvb_frontend_ops stv0367cab_ops = { /* .read_ber = stv0367cab_read_ber, */ .read_signal_strength = stv0367cab_read_strength, .read_snr = stv0367cab_read_snr, -/* .read_ucblocks = stv0367cab_read_ucblcks,*/ + .read_ucblocks = stv0367cab_read_ucblcks, .get_tune_settings = stv0367_get_tune_settings, }; -- cgit v1.2.2 From 8af81ddb12cf34e2f6eab7e130f1e55e1911ab8f Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sun, 2 Jan 2011 09:14:00 -0300 Subject: [media] Fix CI code for NetUP Dual DVB-T/C CI RF card CI reset takes several seconds on some CAM, so there is no need to lock mutex all that time. Also we need not to preserve CI's reset bits in CIBUSCTRL register, they are handled automatically by FPGA. Set it to 0 explicitly in order to not reset wrong CAM. Signed-off-by: Abylay Ospan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/altera-ci.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/altera-ci.c b/drivers/media/video/cx23885/altera-ci.c index 4269e053830c..678539b2acfa 100644 --- a/drivers/media/video/cx23885/altera-ci.c +++ b/drivers/media/video/cx23885/altera-ci.c @@ -283,7 +283,7 @@ int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, netup_fpga_op_rw(inter, NETUP_CI_ADDR1, ((addr >> 7) & 0x7f), 0); store = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); - store &= 0x3f; + store &= 0x0f; store |= ((state->nr << 7) | (flag << 6)); netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, store, 0); @@ -340,19 +340,25 @@ int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, - ret | (1 << (5 - state->nr)), 0); + (ret & 0xcf) | (1 << (5 - state->nr)), 0); + + mutex_unlock(&inter->fpga_mutex); for (;;) { mdelay(50); + + mutex_lock(&inter->fpga_mutex); + ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); + mutex_unlock(&inter->fpga_mutex); + if ((ret & (1 << (5 - state->nr))) == 0) break; if (time_after(jiffies, t_out)) break; } - mutex_unlock(&inter->fpga_mutex); ci_dbg_print("%s: %d msecs\n", __func__, jiffies_to_msecs(jiffies + msecs_to_jiffies(9999) - t_out)); @@ -381,7 +387,7 @@ int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) ret = netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, 0, NETUP_CI_FLG_RD); netup_fpga_op_rw(inter, NETUP_CI_BUSCTRL, - ret | (1 << (3 - state->nr)), 0); + (ret & 0x0f) | (1 << (3 - state->nr)), 0); mutex_unlock(&inter->fpga_mutex); -- cgit v1.2.2 From 4174ebf5ebd7a09589ff8ff3bc3246ea0a9bd356 Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sun, 2 Jan 2011 09:15:00 -0300 Subject: [media] Force xc5000 firmware loading for NetUP Dual DVB-T/C CI RF card Two xc5000 tuners connected to same i2c bus. Experiments shows that situation when one tuner is not initialized while other is tuned to channel causes TS errors. Signed-off-by: Abylay Ospan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index c0e665506750..3c315f94cc85 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -1071,12 +1071,15 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend = dvb_attach(stv0367ter_attach, &netup_stv0367_config[port->nr - 1], &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) + if (fe0->dvb.frontend != NULL) { if (NULL == dvb_attach(xc5000_attach, fe0->dvb.frontend, &i2c_bus->i2c_adap, &netup_xc5000_config[port->nr - 1])) goto frontend_detach; + /* load xc5000 firmware */ + fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); + } /* MFE frontend 2 */ fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); if (fe1 == NULL) -- cgit v1.2.2 From 8ec737ffccd7fab629e28427b4d0581ce62ffedd Mon Sep 17 00:00:00 2001 From: Sungchun Kang Date: Mon, 7 Feb 2011 15:59:46 -0300 Subject: [media] s5p-fimc: fix ISR and buffer handling for fimc-capture In some cases fimc H/W did not stop although there were no output buffers available. So the capture deactivation interrupt routine is modified and the state of ST_CAPT_RUN is cleared only in the LAST-IRQ call. After LAST-IRQ is generated, H/W pointer will be skipped by 1 frame. (reference by user manual) So, S/W pointer should be increased too. Reviewed-by Jonghun Han Signed-off-by: Sungchun Kang Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 70 +++++++++++------------------ drivers/media/video/s5p-fimc/fimc-core.c | 33 ++++++++------ 2 files changed, 45 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 5159cc8a0e1c..6b6f72e4066c 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -153,40 +153,6 @@ static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) return ret; } -/* - * At least one buffer on the pending_buf_q queue is required. - * Locking: The caller holds fimc->slock spinlock. - */ -int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, - struct fimc_vid_buffer *fimc_vb) -{ - struct fimc_vid_cap *cap = &fimc->vid_cap; - struct fimc_ctx *ctx = cap->ctx; - int ret = 0; - - BUG_ON(!fimc || !fimc_vb); - - ret = fimc_prepare_addr(ctx, &fimc_vb->vb, &ctx->d_frame, - &fimc_vb->paddr); - if (ret) - return ret; - - if (test_bit(ST_CAPT_STREAM, &fimc->state)) { - fimc_pending_queue_add(cap, fimc_vb); - } else { - /* Setup the buffer directly for processing. */ - int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index; - fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id); - - fimc_vb->index = cap->buf_index; - active_queue_add(cap, fimc_vb); - - if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) - cap->buf_index = 0; - } - return ret; -} - static int fimc_stop_capture(struct fimc_dev *fimc) { unsigned long flags; @@ -211,7 +177,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc) spin_lock_irqsave(&fimc->slock, flags); fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | - 1 << ST_CAPT_STREAM); + 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM); fimc->vid_cap.active_buf_cnt = 0; @@ -239,6 +205,8 @@ static int start_streaming(struct vb2_queue *q) struct s5p_fimc_isp_info *isp_info; int ret; + fimc_hw_reset(fimc); + ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) return ret; @@ -273,7 +241,7 @@ static int start_streaming(struct vb2_queue *q) 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); + fimc->vid_cap.buf_index = 0; set_bit(ST_CAPT_PEND, &fimc->state); @@ -372,19 +340,33 @@ static void buffer_queue(struct vb2_buffer *vb) = container_of(vb, struct fimc_vid_buffer, vb); struct fimc_vid_cap *vid_cap = &fimc->vid_cap; unsigned long flags; + int min_bufs; spin_lock_irqsave(&fimc->slock, flags); - fimc_vid_cap_buf_queue(fimc, buf); + fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); + + if (!test_bit(ST_CAPT_STREAM, &fimc->state) + && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { + /* Setup the buffer directly for processing. */ + int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : + vid_cap->buf_index; - dbg("active_buf_cnt: %d", fimc->vid_cap.active_buf_cnt); + fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); + buf->index = vid_cap->buf_index; + active_queue_add(vid_cap, buf); - if (vid_cap->active_buf_cnt >= vid_cap->reqbufs_count || - vid_cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) { - if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { - fimc_activate_capture(ctx); - dbg(""); - } + if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS) + vid_cap->buf_index = 0; + } else { + fimc_pending_queue_add(vid_cap, buf); } + + min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; + + if (vid_cap->active_buf_cnt >= min_bufs && + !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) + fimc_activate_capture(ctx); + spin_unlock_irqrestore(&fimc->slock, flags); } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index cd8a3003f1aa..fdf4270fcb62 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -327,9 +327,10 @@ static int stop_streaming(struct vb2_queue *q) static void fimc_capture_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; - struct fimc_vid_buffer *v_buf = NULL; + struct fimc_vid_buffer *v_buf; - if (!list_empty(&cap->active_buf_q)) { + if (!list_empty(&cap->active_buf_q) && + test_bit(ST_CAPT_RUN, &fimc->state)) { v_buf = active_queue_pop(cap); vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } @@ -345,9 +346,6 @@ static void fimc_capture_handler(struct fimc_dev *fimc) fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); v_buf->index = cap->buf_index; - dbg("hw ptr: %d, sw ptr: %d", - fimc_hw_get_frame_index(fimc), cap->buf_index); - /* Move the buffer to the capture active queue */ active_queue_add(cap, v_buf); @@ -356,19 +354,25 @@ static void fimc_capture_handler(struct fimc_dev *fimc) if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; + } + + if (cap->active_buf_cnt == 0) { + clear_bit(ST_CAPT_RUN, &fimc->state); - } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) && - cap->active_buf_cnt <= 1) { - fimc_deactivate_capture(fimc); + if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) + cap->buf_index = 0; + } else { + set_bit(ST_CAPT_RUN, &fimc->state); } - dbg("frame: %d, active_buf_cnt= %d", + dbg("frame: %d, active_buf_cnt: %d", fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); } static irqreturn_t fimc_isr(int irq, void *priv) { struct fimc_dev *fimc = priv; + struct fimc_vid_cap *cap = &fimc->vid_cap; BUG_ON(!fimc); fimc_hw_clear_irq(fimc); @@ -396,12 +400,13 @@ static irqreturn_t fimc_isr(int irq, void *priv) } - if (test_bit(ST_CAPT_RUN, &fimc->state)) - fimc_capture_handler(fimc); + if (test_bit(ST_CAPT_PEND, &fimc->state)) { + fimc_capture_irq_handler(fimc); - if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) { - set_bit(ST_CAPT_RUN, &fimc->state); - wake_up(&fimc->irq_queue); + if (cap->active_buf_cnt == 1) { + fimc_deactivate_capture(fimc); + clear_bit(ST_CAPT_STREAM, &fimc->state); + } } isr_unlock: -- cgit v1.2.2 From a0f8caefaf3295721ef00415c7d63ec10af253ab Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 11 Feb 2011 12:33:06 -0300 Subject: [media] s5p-fimc: Prevent oops when i2c adapter is not available Prevent invalid pointer dereference on error path. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 6b6f72e4066c..423931c0cfe5 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -98,7 +98,7 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index) continue; sd = fimc_subdev_register(fimc, isp_info); - if (sd) { + if (!IS_ERR_OR_NULL(sd)) { vid_cap->sd = sd; vid_cap->input_index = i; -- cgit v1.2.2 From 4ecbf5d1d2bb7d1e3882de79e512c1a0a2816581 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 23 Feb 2011 08:24:33 -0300 Subject: [media] s5p-fimc: Prevent hanging on device close and fix the locking Rework the locking in m2m driver to assure proper operation on SMP systems. When job_abort or stop_streaming was called to immediately shutdown a memory-to-memory transaction video buffers scheduled for processing were never returned to vb2 and v4l2_m2m_job_finish was not called which led to hanging. Correct this and also return the unprocessed buffers to vb2 marking them as erroneous, in case the end of frame interrupt do not occur. Reported-by: Sewoon Park Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 9 +- drivers/media/video/s5p-fimc/fimc-core.c | 197 ++++++++++++++-------------- drivers/media/video/s5p-fimc/fimc-core.h | 44 +++++-- 3 files changed, 136 insertions(+), 114 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 423931c0cfe5..8312ce465f16 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -252,14 +252,9 @@ static int stop_streaming(struct vb2_queue *q) { struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; - unsigned long flags; - spin_lock_irqsave(&fimc->slock, flags); - if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) { - spin_unlock_irqrestore(&fimc->slock, flags); + if (!fimc_capture_active(fimc)) return -EINVAL; - } - spin_unlock_irqrestore(&fimc->slock, flags); return fimc_stop_capture(fimc); } @@ -773,7 +768,7 @@ static int fimc_cap_s_crop(struct file *file, void *fh, ctx->d_frame.width, ctx->d_frame.height, ctx->rotation); if (ret) { - v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range"); + v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n"); return ret; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index fdf4270fcb62..f506197201c8 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -307,24 +307,57 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) return 0; } -static int stop_streaming(struct vb2_queue *q) +static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) { - struct fimc_ctx *ctx = q->drv_priv; + struct vb2_buffer *src_vb, *dst_vb; struct fimc_dev *fimc = ctx->fimc_dev; + if (!ctx || !ctx->m2m_ctx) + return; + + src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + + if (src_vb && dst_vb) { + v4l2_m2m_buf_done(src_vb, vb_state); + v4l2_m2m_buf_done(dst_vb, vb_state); + v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); + } +} + +/* Complete the transaction which has been scheduled for execution. */ +static void fimc_m2m_shutdown(struct fimc_ctx *ctx) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + if (!fimc_m2m_pending(fimc)) - return 0; + return; - set_bit(ST_M2M_SHUT, &fimc->state); + fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx); - wait_event_timeout(fimc->irq_queue, - !test_bit(ST_M2M_SHUT, &fimc->state), + ret = wait_event_timeout(fimc->irq_queue, + !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), FIMC_SHUTDOWN_TIMEOUT); + /* + * In case of a timeout the buffers are not released in the interrupt + * handler so return them here with the error flag set, if there are + * any on the queue. + */ + if (ret == 0) + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); +} + +static int stop_streaming(struct vb2_queue *q) +{ + struct fimc_ctx *ctx = q->drv_priv; + + fimc_m2m_shutdown(ctx); return 0; } -static void fimc_capture_handler(struct fimc_dev *fimc) +static void fimc_capture_irq_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; @@ -373,33 +406,28 @@ static irqreturn_t fimc_isr(int irq, void *priv) { struct fimc_dev *fimc = priv; struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_ctx *ctx; - BUG_ON(!fimc); fimc_hw_clear_irq(fimc); - spin_lock(&fimc->slock); + if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { + ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); + if (ctx != NULL) { + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); - if (test_and_clear_bit(ST_M2M_SHUT, &fimc->state)) { - wake_up(&fimc->irq_queue); - goto isr_unlock; - } else if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { - struct vb2_buffer *src_vb, *dst_vb; - struct fimc_ctx *ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); - - if (!ctx || !ctx->m2m_ctx) - goto isr_unlock; - - src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - if (src_vb && dst_vb) { - v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); - v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); - v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx); + spin_lock(&ctx->slock); + if (ctx->state & FIMC_CTX_SHUT) { + ctx->state &= ~FIMC_CTX_SHUT; + wake_up(&fimc->irq_queue); + } + spin_unlock(&ctx->slock); } - goto isr_unlock; + return IRQ_HANDLED; } + spin_lock(&fimc->slock); + if (test_bit(ST_CAPT_PEND, &fimc->state)) { fimc_capture_irq_handler(fimc); @@ -409,7 +437,6 @@ static irqreturn_t fimc_isr(int irq, void *priv) } } -isr_unlock: spin_unlock(&fimc->slock); return IRQ_HANDLED; } @@ -613,26 +640,26 @@ static void fimc_dma_run(void *priv) ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR); ret = fimc_prepare_config(ctx, ctx->state); - if (ret) { - err("Wrong parameters"); + if (ret) goto dma_unlock; - } + /* Reconfigure hardware if the context has changed. */ if (fimc->m2m.ctx != ctx) { ctx->state |= FIMC_PARAMS; fimc->m2m.ctx = ctx; } + spin_lock(&fimc->slock); fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr); if (ctx->state & FIMC_PARAMS) { fimc_hw_set_input_path(ctx); fimc_hw_set_in_dma(ctx); - if (fimc_set_scaler_info(ctx)) { - err("Scaler setup error"); + ret = fimc_set_scaler_info(ctx); + if (ret) { + spin_unlock(&fimc->slock); goto dma_unlock; } - fimc_hw_set_prescaler(ctx); fimc_hw_set_mainscaler(ctx); fimc_hw_set_target_format(ctx); @@ -652,6 +679,7 @@ static void fimc_dma_run(void *priv) ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP | FIMC_SRC_FMT | FIMC_DST_FMT); fimc_hw_activate_input_dma(fimc, true); + spin_unlock(&fimc->slock); dma_unlock: spin_unlock_irqrestore(&ctx->slock, flags); @@ -659,17 +687,7 @@ dma_unlock: static void fimc_job_abort(void *priv) { - struct fimc_ctx *ctx = priv; - struct fimc_dev *fimc = ctx->fimc_dev; - - if (!fimc_m2m_pending(fimc)) - return; - - set_bit(ST_M2M_SHUT, &fimc->state); - - wait_event_timeout(fimc->irq_queue, - !test_bit(ST_M2M_SHUT, &fimc->state), - FIMC_SHUTDOWN_TIMEOUT); + fimc_m2m_shutdown(priv); } static int fimc_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, @@ -843,7 +861,7 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (ctx->state & FIMC_CTX_CAP) + if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) return -EINVAL; is_output = 1; } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -920,9 +938,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, struct vb2_queue *vq; struct fimc_frame *frame; struct v4l2_pix_format_mplane *pix; - unsigned long flags; int i, ret = 0; - u32 tmp; ret = fimc_vidioc_try_fmt_mplane(file, priv, f); if (ret) @@ -963,10 +979,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, frame->offs_h = 0; frame->offs_v = 0; - spin_lock_irqsave(&ctx->slock, flags); - tmp = (frame == &ctx->d_frame) ? FIMC_DST_FMT : FIMC_SRC_FMT; - ctx->state |= FIMC_PARAMS | tmp; - spin_unlock_irqrestore(&ctx->slock, flags); + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx); + else + fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx); dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height); @@ -1009,9 +1025,9 @@ static int fimc_m2m_streamon(struct file *file, void *priv, /* The source and target color format need to be set */ if (V4L2_TYPE_IS_OUTPUT(type)) { - if (~ctx->state & FIMC_SRC_FMT) + if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx)) return -EINVAL; - } else if (~ctx->state & FIMC_DST_FMT) { + } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) { return -EINVAL; } @@ -1038,7 +1054,7 @@ int fimc_vidioc_queryctrl(struct file *file, void *priv, return 0; } - if (ctx->state & FIMC_CTX_CAP) { + if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { return v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd, core, queryctrl, qc); } @@ -1062,12 +1078,11 @@ int fimc_vidioc_g_ctrl(struct file *file, void *priv, ctrl->value = ctx->rotation; break; default: - if (ctx->state & FIMC_CTX_CAP) { + if (fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx)) { return v4l2_subdev_call(fimc->vid_cap.sd, core, g_ctrl, ctrl); } else { - v4l2_err(&fimc->m2m.v4l2_dev, - "Invalid control\n"); + v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); return -EINVAL; } } @@ -1097,11 +1112,8 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) { struct samsung_fimc_variant *variant = ctx->fimc_dev->variant; struct fimc_dev *fimc = ctx->fimc_dev; - unsigned long flags; int ret = 0; - spin_lock_irqsave(&ctx->slock, flags); - switch (ctrl->id) { case V4L2_CID_HFLIP: if (ctrl->value) @@ -1118,37 +1130,30 @@ int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl) break; case V4L2_CID_ROTATE: - if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) { + if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { ret = fimc_check_scaler_ratio(ctx->s_frame.width, - ctx->s_frame.height, - ctx->d_frame.width, - ctx->d_frame.height, - ctrl->value); - if (ret) { - v4l2_err(&fimc->m2m.v4l2_dev, - "Out of scaler range"); - spin_unlock_irqrestore(&ctx->slock, flags); - return -EINVAL; - } + ctx->s_frame.height, ctx->d_frame.width, + ctx->d_frame.height, ctrl->value); + } + + if (ret) { + v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); + return -EINVAL; } /* Check for the output rotator availability */ if ((ctrl->value == 90 || ctrl->value == 270) && - (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) { - spin_unlock_irqrestore(&ctx->slock, flags); + (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) return -EINVAL; - } else { - ctx->rotation = ctrl->value; - } + ctx->rotation = ctrl->value; break; default: - spin_unlock_irqrestore(&ctx->slock, flags); v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n"); return -EINVAL; } - ctx->state |= FIMC_PARAMS; - spin_unlock_irqrestore(&ctx->slock, flags); + + fimc_ctx_state_lock_set(FIMC_PARAMS, ctx); return 0; } @@ -1208,6 +1213,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *f; u32 min_size, halign, depth = 0; + bool is_capture_ctx; int i; if (cr->c.top < 0 || cr->c.left < 0) { @@ -1216,10 +1222,12 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) return -EINVAL; } + is_capture_ctx = fimc_ctx_state_is_set(FIMC_CTX_CAP, ctx); + if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame; + f = is_capture_ctx ? &ctx->s_frame : &ctx->d_frame; else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - ctx->state & FIMC_CTX_M2M) + !is_capture_ctx) f = &ctx->s_frame; else return -EINVAL; @@ -1227,15 +1235,15 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) min_size = (f == &ctx->s_frame) ? fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; - if (ctx->state & FIMC_CTX_M2M) { + /* Get pixel alignment constraints. */ + if (is_capture_ctx) { + min_size = 16; + halign = 4; + } else { if (fimc->id == 1 && fimc->variant->pix_hoff) halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; else halign = ffs(min_size) - 1; - /* there are more strict aligment requirements at camera interface */ - } else { - min_size = 16; - halign = 4; } for (i = 0; i < f->fmt->colplanes; i++) @@ -1253,8 +1261,7 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) cr->c.top = f->o_height - cr->c.height; cr->c.left = round_down(cr->c.left, min_size); - cr->c.top = round_down(cr->c.top, - ctx->state & FIMC_CTX_M2M ? 8 : 16); + cr->c.top = round_down(cr->c.top, is_capture_ctx ? 16 : 8); dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", cr->c.left, cr->c.top, cr->c.width, cr->c.height, @@ -1263,12 +1270,10 @@ int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) return 0; } - static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) { struct fimc_ctx *ctx = file->private_data; struct fimc_dev *fimc = ctx->fimc_dev; - unsigned long flags; struct fimc_frame *f; int ret; @@ -1279,9 +1284,8 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->s_frame : &ctx->d_frame; - spin_lock_irqsave(&ctx->slock, flags); /* Check to see if scaling ratio is within supported range */ - if (!(~ctx->state & (FIMC_DST_FMT | FIMC_SRC_FMT))) { + if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ret = fimc_check_scaler_ratio(cr->c.width, cr->c.height, ctx->d_frame.width, @@ -1293,22 +1297,19 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr) cr->c.width, cr->c.height, ctx->rotation); } - if (ret) { - v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range"); - spin_unlock_irqrestore(&ctx->slock, flags); + v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range\n"); return -EINVAL; } } - ctx->state |= FIMC_PARAMS; - f->offs_h = cr->c.left; f->offs_v = cr->c.top; f->width = cr->c.width; f->height = cr->c.height; - spin_unlock_irqrestore(&ctx->slock, flags); + fimc_ctx_state_lock_set(FIMC_PARAMS, ctx); + return 0; } diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 4829a2515076..41b135249d1f 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -14,6 +14,7 @@ /*#define DEBUG*/ #include +#include #include #include #include @@ -57,7 +58,6 @@ enum fimc_dev_flags { ST_IDLE, ST_OUTDMA_RUN, ST_M2M_PEND, - ST_M2M_SHUT, /* for capture node */ ST_CAPT_PEND, ST_CAPT_RUN, @@ -71,13 +71,6 @@ enum fimc_dev_flags { #define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) #define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) -#define fimc_capture_active(dev) \ - (test_bit(ST_CAPT_RUN, &(dev)->state) || \ - test_bit(ST_CAPT_PEND, &(dev)->state)) - -#define fimc_capture_streaming(dev) \ - test_bit(ST_CAPT_STREAM, &(dev)->state) - enum fimc_datapath { FIMC_CAMERA, FIMC_DMA, @@ -119,6 +112,7 @@ enum fimc_color_fmt { #define FIMC_DST_FMT (1 << 4) #define FIMC_CTX_M2M (1 << 5) #define FIMC_CTX_CAP (1 << 6) +#define FIMC_CTX_SHUT (1 << 7) /* Image conversion flags */ #define FIMC_IN_DMA_ACCESS_TILED (1 << 0) @@ -476,6 +470,38 @@ struct fimc_ctx { struct v4l2_m2m_ctx *m2m_ctx; }; +static inline bool fimc_capture_active(struct fimc_dev *fimc) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&fimc->slock, flags); + ret = !!(fimc->state & (1 << ST_CAPT_RUN) || + fimc->state & (1 << ST_CAPT_PEND)); + spin_unlock_irqrestore(&fimc->slock, flags); + return ret; +} + +static inline void fimc_ctx_state_lock_set(u32 state, struct fimc_ctx *ctx) +{ + unsigned long flags; + + spin_lock_irqsave(&ctx->slock, flags); + ctx->state |= state; + spin_unlock_irqrestore(&ctx->slock, flags); +} + +static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&ctx->slock, flags); + ret = (ctx->state & mask) == mask; + spin_unlock_irqrestore(&ctx->slock, flags); + return ret; +} + static inline int tiled_fmt(struct fimc_fmt *fmt) { return fmt->fourcc == V4L2_PIX_FMT_NV12MT; @@ -535,7 +561,7 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, struct fimc_frame *frame; if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) { - if (ctx->state & FIMC_CTX_M2M) + if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx)) frame = &ctx->s_frame; else return ERR_PTR(-EINVAL); -- cgit v1.2.2 From 117182d18399a956719be94d3e6e17aad9210cda Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 28 Feb 2011 11:12:19 -0300 Subject: [media] s5p-fimc: Allow defining number of sensors at runtime Add num_clients field to struct s5p_fimc_isp_info to define exactly size of clients array which simplifies a bit the sensors management. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 23 ++++++++++------------- drivers/media/video/s5p-fimc/fimc-core.c | 22 ++++++++-------------- 2 files changed, 18 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 8312ce465f16..95f8b4e11e46 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -91,10 +91,10 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index) struct v4l2_subdev *sd; int i; - for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) { - isp_info = pdata->isp_info[i]; + for (i = 0; i < pdata->num_clients; ++i) { + isp_info = &pdata->isp_info[i]; - if (!isp_info || (index >= 0 && i != index)) + if (index >= 0 && i != index) continue; sd = fimc_subdev_register(fimc, isp_info); @@ -116,14 +116,13 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index) static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) { struct s5p_fimc_isp_info *isp_info; + struct s5p_platform_fimc *pdata = fimc->pdata; int ret; - if (index >= FIMC_MAX_CAMIF_CLIENTS) + if (index >= pdata->num_clients) return -EINVAL; - isp_info = fimc->pdata->isp_info[index]; - if (!isp_info) - return -EINVAL; + isp_info = &pdata->isp_info[index]; if (isp_info->clk_frequency) clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency); @@ -215,7 +214,7 @@ static int start_streaming(struct vb2_queue *q) if (ret) return ret; - isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; + isp_info = &fimc->pdata->isp_info[fimc->vid_cap.input_index]; fimc_hw_set_camera_type(fimc, isp_info); fimc_hw_set_camera_source(fimc, isp_info); fimc_hw_set_camera_offset(fimc, &ctx->s_frame); @@ -567,12 +566,10 @@ static int fimc_cap_enum_input(struct file *file, void *priv, struct s5p_platform_fimc *pldata = ctx->fimc_dev->pdata; struct s5p_fimc_isp_info *isp_info; - if (i->index >= FIMC_MAX_CAMIF_CLIENTS) + if (i->index >= pldata->num_clients) return -EINVAL; - isp_info = pldata->isp_info[i->index]; - if (isp_info == NULL) - return -EINVAL; + isp_info = &pldata->isp_info[i->index]; i->type = V4L2_INPUT_TYPE_CAMERA; strncpy(i->name, isp_info->board_info->type, 32); @@ -589,7 +586,7 @@ static int fimc_cap_s_input(struct file *file, void *priv, if (fimc_capture_active(ctx->fimc_dev)) return -EBUSY; - if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) + if (i >= pdata->num_clients) return -EINVAL; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index f506197201c8..b29937eba602 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1577,6 +1577,7 @@ static int fimc_probe(struct platform_device *pdev) struct fimc_dev *fimc; struct resource *res; struct samsung_fimc_driverdata *drv_data; + struct s5p_platform_fimc *pdata; int ret = 0; int cap_input_index = -1; @@ -1598,7 +1599,8 @@ static int fimc_probe(struct platform_device *pdev) fimc->id = pdev->id; fimc->variant = drv_data->variant[fimc->id]; fimc->pdev = pdev; - fimc->pdata = pdev->dev.platform_data; + pdata = pdev->dev.platform_data; + fimc->pdata = pdata; fimc->state = ST_IDLE; init_waitqueue_head(&fimc->irq_queue); @@ -1629,19 +1631,11 @@ static int fimc_probe(struct platform_device *pdev) } fimc->num_clocks = MAX_FIMC_CLOCKS - 1; - /* - * Check if vide capture node needs to be registered for this device - * instance. - */ - if (fimc->pdata) { - int i; - for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) - if (fimc->pdata->isp_info[i]) - break; - if (i < FIMC_MAX_CAMIF_CLIENTS) { - cap_input_index = i; - fimc->num_clocks++; - } + + /* Check if a video capture node needs to be registered. */ + if (pdata && pdata->num_clients > 0) { + cap_input_index = 0; + fimc->num_clocks++; } ret = fimc_clk_get(fimc); -- cgit v1.2.2 From e0eec9af8bf599642f2730ed207296a92e6204aa Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 21 Feb 2011 12:09:01 -0300 Subject: [media] s5p-fimc: Add a platform data entry for MIPI-CSI data alignment Allow the MIPI-CSI data alignment to be defined in the board setup as it may be different across various camera sensors. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-reg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 10684aef5b2d..4d929a394521 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -665,10 +665,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, vid_cap->fmt.code); return -EINVAL; } - writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT); + tmp |= (cam->csi_data_align == 32) << 8; + + writel(tmp, fimc->regs + S5P_CSIIMGFMT); } else if (cam->bus_type == FIMC_ITU_601 || - cam->bus_type == FIMC_ITU_656) { + cam->bus_type == FIMC_ITU_656) { if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ cfg |= S5P_CIGCTRL_SELCAM_ITU_A; } else if (cam->bus_type == FIMC_LCD_WB) { -- cgit v1.2.2 From 1e00469599b5841f5b02c436b9958073a0ad576c Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 23 Feb 2011 08:17:57 -0300 Subject: [media] s5p-fimc: Use dynamic debug Use pr_debug instead of printk so it is possible to control debug traces at runtime. E.g. to enable debug trace in file fimc-core.c use command: echo -n 'file fimc-core.c +p' > /sys/kernel/debug/dynamic_debug/control or echo -n 'file fimc-core.c -p' > /sys/kernel/debug/dynamic_debug/control to disable. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-core.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index 41b135249d1f..3beb1e5320ce 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -29,12 +29,8 @@ #define err(fmt, args...) \ printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args) -#ifdef DEBUG #define dbg(fmt, args...) \ - printk(KERN_DEBUG "%s:%d: " fmt "\n", __func__, __LINE__, ##args) -#else -#define dbg(fmt, args...) -#endif + pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args) /* Time to wait for next frame VSYNC interrupt while stopping operation. */ #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) -- cgit v1.2.2 From 91707b8b27a785c42949ba55b65f084027962afa Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sat, 15 Jan 2011 01:17:42 -0300 Subject: [media] s5p-fimc: Fix G_FMT ioctl handler Use pix_mp member of struct v4l2_format to return a format description rather than pix. Also fill in the plane_fmt array. This is a missing bit of conversion to the multiplanar API. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-core.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index b29937eba602..6c919b38a3d8 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -804,15 +804,33 @@ int fimc_vidioc_g_fmt_mplane(struct file *file, void *priv, { struct fimc_ctx *ctx = priv; struct fimc_frame *frame; + struct v4l2_pix_format_mplane *pixm; + int i; frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) return PTR_ERR(frame); - f->fmt.pix.width = frame->width; - f->fmt.pix.height = frame->height; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = frame->fmt->fourcc; + pixm = &f->fmt.pix_mp; + + pixm->width = frame->width; + pixm->height = frame->height; + pixm->field = V4L2_FIELD_NONE; + pixm->pixelformat = frame->fmt->fourcc; + pixm->colorspace = V4L2_COLORSPACE_JPEG; + pixm->num_planes = frame->fmt->memplanes; + + for (i = 0; i < pixm->num_planes; ++i) { + int bpl = frame->o_width; + + if (frame->fmt->colplanes == 1) /* packed formats */ + bpl = (bpl * frame->fmt->depth[0]) / 8; + + pixm->plane_fmt[i].bytesperline = bpl; + + pixm->plane_fmt[i].sizeimage = (frame->o_width * + frame->o_height * frame->fmt->depth[i]) / 8; + } return 0; } @@ -907,6 +925,7 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); pix->num_planes = fmt->memplanes; + pix->colorspace = V4L2_COLORSPACE_JPEG; for (i = 0; i < pix->num_planes; ++i) { int bpl = pix->plane_fmt[i].bytesperline; -- cgit v1.2.2 From 29e3fbd8edb31549fa8302c185bd0b915a43d8b8 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Mar 2011 14:03:24 -0300 Subject: [media] v4l2: vb2: fix queue reallocation and REQBUFS(0) case This patch fixes 2 minor bugs in videobuf2 core: 1. Queue should be reallocated if one change the memory access method without changing the number of buffers. 2. In case of REQBUFS(0), the request should not be passed to the driver. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index cc7ab0a17b68..c5f99c7d3979 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -488,7 +488,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EINVAL; } - if (req->count == 0 || q->num_buffers != 0) { + if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { /* * We already have buffers allocated, so first check if they * are not in use and can be freed. @@ -501,6 +501,13 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ret = __vb2_queue_free(q); if (ret != 0) return ret; + + /* + * In case of REQBUFS(0) return immediately without calling + * driver's queue_setup() callback and allocating resources. + */ + if (req->count == 0) + return 0; } /* -- cgit v1.2.2 From a9bb36aa0d6547aa0ab3d5cfde08e8651bd460bc Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Fri, 28 Jan 2011 09:42:51 -0300 Subject: [media] v4l2: vb2-dma-sg: fix memory leak This patch fixes two minor memory leaks in videobuf2-dma-sg module. They might happen only in case some other operations (like memory allocation) failed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-dma-sg.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c index 20b5c5dcc0ef..d5311ff3fab0 100644 --- a/drivers/media/video/videobuf2-dma-sg.c +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -88,6 +88,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) fail_pages_alloc: while (--i >= 0) __free_page(buf->pages[i]); + kfree(buf->pages); fail_pages_array_alloc: vfree(buf->sg_desc.sglist); @@ -176,6 +177,7 @@ userptr_fail_get_user_pages: num_pages_from_user, buf->sg_desc.num_pages); while (--num_pages_from_user >= 0) put_page(buf->pages[num_pages_from_user]); + kfree(buf->pages); userptr_fail_pages_array_alloc: vfree(buf->sg_desc.sglist); -- cgit v1.2.2 From 31901a078af29c33c736dcbf815656920e904632 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 11 Mar 2011 06:07:27 -0300 Subject: [media] v4l2: vb2: one more fix for REQBUFS() Return immediately if the target number of buffers is the same as the current one and memory access type doesn't change. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index c5f99c7d3979..2baf7dbdc01d 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -488,6 +488,13 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EINVAL; } + /* + * If the same number of buffers and memory access method is requested + * then return immediately. + */ + if (q->memory == req->memory && req->count == q->num_buffers) + return 0; + if (req->count == 0 || q->num_buffers != 0 || q->memory != req->memory) { /* * We already have buffers allocated, so first check if they -- cgit v1.2.2 From 72f1fc33a76a115e8c67f7b052bd7f6e129cda50 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 10 Mar 2011 09:10:49 -0300 Subject: [media] v4l2: vb2: simplify __vb2_queue_free function __vb2_queue_free function doesn't really return anything useful. This patch removes support for the return value to simplify the code. Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 2baf7dbdc01d..3e9b67bd55b9 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -227,7 +227,7 @@ static void __vb2_free_mem(struct vb2_queue *q) * and return the queue to an uninitialized state. Might be called even if the * queue has already been freed. */ -static int __vb2_queue_free(struct vb2_queue *q) +static void __vb2_queue_free(struct vb2_queue *q) { unsigned int buffer; @@ -251,8 +251,6 @@ static int __vb2_queue_free(struct vb2_queue *q) q->num_buffers = 0; q->memory = 0; - - return 0; } /** @@ -505,9 +503,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) return -EBUSY; } - ret = __vb2_queue_free(q); - if (ret != 0) - return ret; + __vb2_queue_free(q); /* * In case of REQBUFS(0) return immediately without calling -- cgit v1.2.2 From 941f896071c5c9120c8473c77246beaf36155247 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 2 Mar 2011 09:12:13 -0300 Subject: [media] v4l2: vb2-dma-sg: fix potential security hole Memory allocated by alloc_page() function might contain some potentially important data from other system processes. The patch adds a flag to zero the allocated page before giving it to videobuf2 (and then to userspace). Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-dma-sg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-dma-sg.c b/drivers/media/video/videobuf2-dma-sg.c index d5311ff3fab0..b2d9485aac75 100644 --- a/drivers/media/video/videobuf2-dma-sg.c +++ b/drivers/media/video/videobuf2-dma-sg.c @@ -62,7 +62,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) goto fail_pages_array_alloc; for (i = 0; i < buf->sg_desc.num_pages; ++i) { - buf->pages[i] = alloc_page(GFP_KERNEL); + buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); if (NULL == buf->pages[i]) goto fail_pages_alloc; sg_set_page(&buf->sg_desc.sglist[i], -- cgit v1.2.2 From 43823c02245a445b5669d43b1ec07b6d8ae710f5 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 13 Mar 2011 20:37:11 -0300 Subject: [media] pvrusb2: Implement support for Terratec Grabster AV400 Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 18 +++++++++++++++++ drivers/media/video/pvrusb2/pvrusb2-devattr.c | 24 +++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 2222da8d0ca6..c514d0b9ffdc 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -99,9 +99,27 @@ static const struct routing_scheme routing_defgv = { .cnt = ARRAY_SIZE(routing_schemegv), }; +/* Specific to grabster av400 device */ +static const struct routing_scheme_item routing_schemeav400[] = { + [PVR2_CVAL_INPUT_COMPOSITE] = { + .vid = CX25840_COMPOSITE1, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_SVIDEO] = { + .vid = (CX25840_SVIDEO_LUMA2|CX25840_SVIDEO_CHROMA4), + .aud = CX25840_AUDIO_SERIAL, + }, +}; + +static const struct routing_scheme routing_defav400 = { + .def = routing_schemeav400, + .cnt = ARRAY_SIZE(routing_schemeav400), +}; + static const struct routing_scheme *routing_schemes[] = { [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv, + [PVR2_ROUTING_SCHEME_AV400] = &routing_defav400, }; void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 3092abfd66a2..e799331389b1 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -156,6 +156,28 @@ static const struct pvr2_device_desc pvr2_device_gotview_2d = { +/*------------------------------------------------------------------------*/ +/* Terratec Grabster AV400 */ + +static const struct pvr2_device_client_desc pvr2_cli_av400[] = { + { .module_id = PVR2_CLIENT_ID_CX25840 }, +}; + +static const struct pvr2_device_desc pvr2_device_av400 = { + .description = "Terratec Grabster AV400", + .shortname = "av400", + .flag_is_experimental = 1, + .client_table.lst = pvr2_cli_av400, + .client_table.cnt = ARRAY_SIZE(pvr2_cli_av400), + .flag_has_cx25840 = !0, + .flag_has_analogtuner = 0, + .flag_has_composite = !0, + .flag_has_svideo = !0, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_AV400, +}; + + + /*------------------------------------------------------------------------*/ /* OnAir Creator */ @@ -517,6 +539,8 @@ struct usb_device_id pvr2_device_table[] = { .driver_info = (kernel_ulong_t)&pvr2_device_750xx}, { USB_DEVICE(0x2040, 0x7501), .driver_info = (kernel_ulong_t)&pvr2_device_751xx}, + { USB_DEVICE(0x0ccd, 0x0039), + .driver_info = (kernel_ulong_t)&pvr2_device_av400}, { } }; -- cgit v1.2.2 From 228ee5928b5d4192a23cda3fdf755a956516c13e Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 13 Mar 2011 22:18:23 -0300 Subject: [media] pvrusb2: Remove dead code This was caught via a compiler warning. Amazingly enough this bit of benign dreck dates all the way back to 2008. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 58617fc656c2..38761142a4d9 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -795,12 +795,10 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_S_CROP: { struct v4l2_crop *crop = (struct v4l2_crop *)arg; - struct v4l2_cropcap cap; if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { ret = -EINVAL; break; } - cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ret = pvr2_ctrl_set_value( pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), crop->c.left); -- cgit v1.2.2 From c05df8b32ab4b8103f8c20cbd3ab7191be613b68 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Sun, 13 Mar 2011 22:32:53 -0300 Subject: [media] pvrusb2: check kmalloc return value allows the driver to proceed and initialize the below two values even if the kmalloc() fails. hdw->std_info_enum.def.type_enum.value_names hdw->std_info_enum.def.type_enum.count Signed-off-by: Xiaochen Wang Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index d33dd61de263..9d0dd08f57f8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -2850,15 +2850,23 @@ static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw) PVR2_TRACE_ERROR_LEGS, "WARNING: Failed to identify any viable standards"); } + + /* Set up the dynamic control for this standard */ hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL); - hdw->std_enum_names[0] = "none"; - for (idx = 0; idx < std_cnt; idx++) { - hdw->std_enum_names[idx+1] = - newstd[idx].name; - } - // Set up the dynamic control for this standard - hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names; - hdw->std_info_enum.def.type_enum.count = std_cnt+1; + if (hdw->std_enum_names) { + hdw->std_enum_names[0] = "none"; + for (idx = 0; idx < std_cnt; idx++) + hdw->std_enum_names[idx+1] = newstd[idx].name; + hdw->std_info_enum.def.type_enum.value_names = + hdw->std_enum_names; + hdw->std_info_enum.def.type_enum.count = std_cnt+1; + } else { + pvr2_trace( + PVR2_TRACE_ERROR_LEGS, + "WARNING: Failed to alloc memory for names"); + hdw->std_info_enum.def.type_enum.value_names = NULL; + hdw->std_info_enum.def.type_enum.count = 0; + } hdw->std_defs = newstd; hdw->std_enum_cnt = std_cnt+1; hdw->std_enum_cur = 0; -- cgit v1.2.2 From c2f644aeeba3a5178767e757e93151959f037db1 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 13 Mar 2011 12:26:14 -0300 Subject: [media] gspca_cpia1: Add support for button Not only the qx3 microscope has a button, but some cameras too. Tested with the Trust sp@cecam 100 (and with a creative and ezcam without button). Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/cpia1.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c index 2a4a428f2018..9ddbac680663 100644 --- a/drivers/media/video/gspca/cpia1.c +++ b/drivers/media/video/gspca/cpia1.c @@ -28,6 +28,7 @@ #define MODULE_NAME "cpia1" +#include #include "gspca.h" MODULE_AUTHOR("Hans de Goede "); @@ -653,10 +654,15 @@ static int do_command(struct gspca_dev *gspca_dev, u16 command, break; case CPIA_COMMAND_ReadMCPorts: - if (!sd->params.qx3.qx3_detected) - break; /* test button press */ - sd->params.qx3.button = ((gspca_dev->usb_buf[1] & 0x02) == 0); + a = ((gspca_dev->usb_buf[1] & 0x02) == 0); + if (a != sd->params.qx3.button) { +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + input_report_key(gspca_dev->input_dev, KEY_CAMERA, a); + input_sync(gspca_dev->input_dev); +#endif + sd->params.qx3.button = a; + } if (sd->params.qx3.button) { /* button pressed - unlock the latch */ do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, @@ -1738,6 +1744,8 @@ static int sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + command_pause(gspca_dev); /* save camera state for later open (developers guide ch 3.5.3) */ @@ -1748,6 +1756,17 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* Update the camera status */ do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); + +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + /* If the last button state is pressed, release it now! */ + if (sd->params.qx3.button) { + /* The camera latch will hold the pressed state until we reset + the latch, so we do not reset sd->params.qx3.button now, to + avoid a false keypress being reported the next sd_start */ + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); + input_sync(gspca_dev->input_dev); + } +#endif } /* this function is called at probe and resume time */ @@ -1852,8 +1871,7 @@ static void sd_dq_callback(struct gspca_dev *gspca_dev) /* Update our knowledge of the camera state */ do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); - if (sd->params.qx3.qx3_detected) - do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); + do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) @@ -2085,6 +2103,9 @@ static const struct sd_desc sd_desc = { .dq_callback = sd_dq_callback, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, +#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) + .other_input = 1, +#endif }; /* -- module initialisation -- */ -- cgit v1.2.2 From 170960fa9a4688299350ea356e4e5a3e76d15711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sat, 26 Feb 2011 08:04:03 -0300 Subject: [media] gspca - zc3xx: Remove double definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/zc3xx-reg.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/zc3xx-reg.h b/drivers/media/video/gspca/zc3xx-reg.h index bfb559c3b713..a1bd94e8ce52 100644 --- a/drivers/media/video/gspca/zc3xx-reg.h +++ b/drivers/media/video/gspca/zc3xx-reg.h @@ -160,8 +160,6 @@ #define ZC3XX_R1A6_YMEANAFTERAE 0x01a6 #define ZC3XX_R1A7_CALCGLOBALMEAN 0x01a7 -#define ZC3XX_R1A2_BLUEMEANAFTERAGC 0x01a2 - /* Matrixes */ /* Color matrix is like : -- cgit v1.2.2 From 4e5144eef436720b08f7bdb1beba4960af23c737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sat, 26 Feb 2011 13:56:20 -0300 Subject: [media] gspca - zc3xx: Cleanup source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - change some comments and copyright - change an erroneous register name - change hdcs2020b to hdcs2020 Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/zc3xx.c | 48 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index b2014915f9c1..6dcb1cf11b5c 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -1,7 +1,7 @@ /* * Z-Star/Vimicro zc301/zc302p/vc30x library * - * Copyright (C) 2009-2010 Jean-Francois Moine + * Copyright (C) 2009-2011 Jean-Francois Moine * Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr * * This program is free software; you can redistribute it and/or modify @@ -73,7 +73,7 @@ enum sensors { SENSOR_CS2102K, SENSOR_GC0303, SENSOR_GC0305, - SENSOR_HDCS2020b, + SENSOR_HDCS2020, SENSOR_HV7131B, SENSOR_HV7131R, SENSOR_ICM105A, @@ -1498,7 +1498,7 @@ static const struct usb_action gc0305_NoFliker[] = { {} }; -static const struct usb_action hdcs2020b_InitialScale[] = { +static const struct usb_action hdcs2020_InitialScale[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* qtable 0x05 */ @@ -1630,7 +1630,7 @@ static const struct usb_action hdcs2020b_InitialScale[] = { {0xa0, 0x40, ZC3XX_R118_BGAIN}, {} }; -static const struct usb_action hdcs2020b_Initial[] = { +static const struct usb_action hdcs2020_Initial[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, @@ -1758,7 +1758,7 @@ static const struct usb_action hdcs2020b_Initial[] = { {0xa0, 0x40, ZC3XX_R118_BGAIN}, {} }; -static const struct usb_action hdcs2020b_50HZ[] = { +static const struct usb_action hdcs2020_50HZ[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x13, 0x0018}, /* 00,13,18,aa */ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ @@ -1779,7 +1779,7 @@ static const struct usb_action hdcs2020b_50HZ[] = { {0xa0, 0x2f, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2f,cc */ {} }; -static const struct usb_action hdcs2020b_60HZ[] = { +static const struct usb_action hdcs2020_60HZ[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x13, 0x0031}, /* 00,13,31,aa */ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ @@ -1800,7 +1800,7 @@ static const struct usb_action hdcs2020b_60HZ[] = { {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */ {} }; -static const struct usb_action hdcs2020b_NoFliker[] = { +static const struct usb_action hdcs2020_NoFliker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ @@ -2126,7 +2126,6 @@ static const struct usb_action hv7131r_Initial[] = { {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW}, {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, @@ -2878,7 +2877,7 @@ static const struct usb_action mc501cb_Initial[] = { {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ - {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */ + {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */ {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ @@ -2998,7 +2997,7 @@ static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */ {0xaa, 0x11, 0x0001}, /* 00,11,01,aa */ {0xaa, 0x30, 0x0000}, /* 00,30,00,aa */ {0xaa, 0x60, 0x0000}, /* 00,60,00,aa */ - {0xaa, 0xa0, ZC3XX_R01A_LASTFRAMESTATE}, /* 00,a0,1a,aa */ + {0xaa, 0xa0, 0x001a}, /* 00,a0,1a,aa */ {0xaa, 0xa1, 0x0000}, /* 00,a1,00,aa */ {0xaa, 0xa2, 0x003f}, /* 00,a2,3f,aa */ {0xaa, 0xa3, 0x0028}, /* 00,a3,28,aa */ @@ -3310,7 +3309,7 @@ static const struct usb_action ov7620_50HZ[] = { {0xaa, 0x10, 0x0082}, /* 00,10,82,aa */ {0xaa, 0x76, 0x0003}, /* 00,76,03,aa */ /* {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, * 00,02,40,cc - if mode0 (640x480) */ + * if mode0 (640x480) */ {} }; static const struct usb_action ov7620_60HZ[] = { @@ -5828,7 +5827,7 @@ static void setmatrix(struct gspca_dev *gspca_dev) [SENSOR_CS2102K] = NULL, [SENSOR_GC0303] = gc0303_matrix, [SENSOR_GC0305] = gc0305_matrix, - [SENSOR_HDCS2020b] = NULL, + [SENSOR_HDCS2020] = NULL, [SENSOR_HV7131B] = NULL, [SENSOR_HV7131R] = po2030_matrix, [SENSOR_ICM105A] = po2030_matrix, @@ -5990,10 +5989,10 @@ static void setlightfreq(struct gspca_dev *gspca_dev) {gc0305_NoFliker, gc0305_NoFliker, gc0305_50HZ, gc0305_50HZ, gc0305_60HZ, gc0305_60HZ}, - [SENSOR_HDCS2020b] = - {hdcs2020b_NoFliker, hdcs2020b_NoFliker, - hdcs2020b_50HZ, hdcs2020b_50HZ, - hdcs2020b_60HZ, hdcs2020b_60HZ}, + [SENSOR_HDCS2020] = + {hdcs2020_NoFliker, hdcs2020_NoFliker, + hdcs2020_50HZ, hdcs2020_50HZ, + hdcs2020_60HZ, hdcs2020_60HZ}, [SENSOR_HV7131B] = {hv7131b_NoFliker, hv7131b_NoFlikerScale, hv7131b_50HZ, hv7131b_50HZScale, @@ -6091,7 +6090,7 @@ static void setautogain(struct gspca_dev *gspca_dev) static void send_unknown(struct gspca_dev *gspca_dev, int sensor) { - reg_w(gspca_dev, 0x01, 0x0000); /* led off */ + reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */ switch (sensor) { case SENSOR_PAS106: reg_w(gspca_dev, 0x03, 0x003a); @@ -6310,6 +6309,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) return 0x0a; /* PB0330 */ } + /* probe gc0303 / gc0305 */ reg_w(gspca_dev, 0x01, 0x0000); reg_w(gspca_dev, 0x01, 0x0001); reg_w(gspca_dev, 0x98, 0x008b); @@ -6433,7 +6433,7 @@ static int sd_init(struct gspca_dev *gspca_dev) [SENSOR_CS2102K] = 5, [SENSOR_GC0303] = 3, [SENSOR_GC0305] = 4, - [SENSOR_HDCS2020b] = 4, + [SENSOR_HDCS2020] = 4, [SENSOR_HV7131B] = 4, [SENSOR_HV7131R] = 4, [SENSOR_ICM105A] = 4, @@ -6454,7 +6454,7 @@ static int sd_init(struct gspca_dev *gspca_dev) [SENSOR_CS2102K] = 1, [SENSOR_GC0303] = 1, [SENSOR_GC0305] = 1, - [SENSOR_HDCS2020b] = 1, + [SENSOR_HDCS2020] = 1, [SENSOR_HV7131B] = 1, [SENSOR_HV7131R] = 1, [SENSOR_ICM105A] = 1, @@ -6517,8 +6517,8 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->sensor = SENSOR_CS2102; break; case 0x08: - PDEBUG(D_PROBE, "Find Sensor HDCS2020(b)"); - sd->sensor = SENSOR_HDCS2020b; + PDEBUG(D_PROBE, "Find Sensor HDCS2020"); + sd->sensor = SENSOR_HDCS2020; break; case 0x0a: PDEBUG(D_PROBE, @@ -6648,8 +6648,8 @@ static int sd_start(struct gspca_dev *gspca_dev) {gc0303_Initial, gc0303_InitialScale}, [SENSOR_GC0305] = {gc0305_Initial, gc0305_InitialScale}, - [SENSOR_HDCS2020b] = - {hdcs2020b_Initial, hdcs2020b_InitialScale}, + [SENSOR_HDCS2020] = + {hdcs2020_Initial, hdcs2020_InitialScale}, [SENSOR_HV7131B] = {hv7131b_Initial, hv7131b_InitialScale}, [SENSOR_HV7131R] = @@ -6743,7 +6743,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* set the gamma tables when not set */ switch (sd->sensor) { case SENSOR_CS2102K: /* gamma set in xxx_Initial */ - case SENSOR_HDCS2020b: + case SENSOR_HDCS2020: case SENSOR_OV7630C: break; default: -- cgit v1.2.2 From fa85bb6f9b101d92940f54c7ab1b8557aaa35a6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sun, 13 Mar 2011 14:38:46 -0300 Subject: [media] gspca: New file autogain_functions.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file contains functions for the auto gain. It must be used with the new control mechanism. Acked-by: Hans de Goede Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/autogain_functions.h | 179 +++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 drivers/media/video/gspca/autogain_functions.h (limited to 'drivers') diff --git a/drivers/media/video/gspca/autogain_functions.h b/drivers/media/video/gspca/autogain_functions.h new file mode 100644 index 000000000000..46777eee678b --- /dev/null +++ b/drivers/media/video/gspca/autogain_functions.h @@ -0,0 +1,179 @@ +/* + * Functions for auto gain. + * + * Copyright (C) 2010-2011 Hans de Goede + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* auto gain and exposure algorithm based on the knee algorithm described here: + http://ytse.tricolour.net/docs/LowLightOptimization.html + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +static inline int auto_gain_n_exposure( + struct gspca_dev *gspca_dev, + int avg_lum, + int desired_avg_lum, + int deadzone, + int gain_knee, + int exposure_knee) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, steps, gain, orig_gain, exposure, orig_exposure; + int retval = 0; + + orig_gain = gain = sd->ctrls[GAIN].val; + orig_exposure = exposure = sd->ctrls[EXPOSURE].val; + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = abs(desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", + avg_lum, desired_avg_lum, steps); + + for (i = 0; i < steps; i++) { + if (avg_lum > desired_avg_lum) { + if (gain > gain_knee) + gain--; + else if (exposure > exposure_knee) + exposure--; + else if (gain > sd->ctrls[GAIN].def) + gain--; + else if (exposure > sd->ctrls[EXPOSURE].min) + exposure--; + else if (gain > sd->ctrls[GAIN].min) + gain--; + else + break; + } else { + if (gain < sd->ctrls[GAIN].def) + gain++; + else if (exposure < exposure_knee) + exposure++; + else if (gain < gain_knee) + gain++; + else if (exposure < sd->ctrls[EXPOSURE].max) + exposure++; + else if (gain < sd->ctrls[GAIN].max) + gain++; + else + break; + } + } + + if (gain != orig_gain) { + sd->ctrls[GAIN].val = gain; + setgain(gspca_dev); + retval = 1; + } + if (exposure != orig_exposure) { + sd->ctrls[EXPOSURE].val = exposure; + setexposure(gspca_dev); + retval = 1; + } + + if (retval) + PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", + gain, exposure); + return retval; +} + +/* Autogain + exposure algorithm for cameras with a coarse exposure control + (usually this means we can only control the clockdiv to change exposure) + As changing the clockdiv so that the fps drops from 30 to 15 fps for + example, will lead to a huge exposure change (it effectively doubles), + this algorithm normally tries to only adjust the gain (between 40 and + 80 %) and if that does not help, only then changes exposure. This leads + to a much more stable image then using the knee algorithm which at + certain points of the knee graph will only try to adjust exposure, + which leads to oscilating as one exposure step is huge. + + Note this assumes that the sd struct for the cam in question has + exp_too_high_cnt and exp_too_high_cnt int members for use by this function. + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +static inline int coarse_grained_expo_autogain( + struct gspca_dev *gspca_dev, + int avg_lum, + int desired_avg_lum, + int deadzone) +{ + struct sd *sd = (struct sd *) gspca_dev; + int steps, gain, orig_gain, exposure, orig_exposure; + int gain_low, gain_high; + int retval = 0; + + orig_gain = gain = sd->ctrls[GAIN].val; + orig_exposure = exposure = sd->ctrls[EXPOSURE].val; + + gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2; + gain_low += sd->ctrls[GAIN].min; + gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4; + gain_high += sd->ctrls[GAIN].min; + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = (desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", + avg_lum, desired_avg_lum, steps); + + if ((gain + steps) > gain_high && + exposure < sd->ctrls[EXPOSURE].max) { + gain = gain_high; + sd->exp_too_low_cnt++; + sd->exp_too_high_cnt = 0; + } else if ((gain + steps) < gain_low && + exposure > sd->ctrls[EXPOSURE].min) { + gain = gain_low; + sd->exp_too_high_cnt++; + sd->exp_too_low_cnt = 0; + } else { + gain += steps; + if (gain > sd->ctrls[GAIN].max) + gain = sd->ctrls[GAIN].max; + else if (gain < sd->ctrls[GAIN].min) + gain = sd->ctrls[GAIN].min; + sd->exp_too_high_cnt = 0; + sd->exp_too_low_cnt = 0; + } + + if (sd->exp_too_high_cnt > 3) { + exposure--; + sd->exp_too_high_cnt = 0; + } else if (sd->exp_too_low_cnt > 3) { + exposure++; + sd->exp_too_low_cnt = 0; + } + + if (gain != orig_gain) { + sd->ctrls[GAIN].val = gain; + setgain(gspca_dev); + retval = 1; + } + if (exposure != orig_exposure) { + sd->ctrls[EXPOSURE].val = exposure; + setexposure(gspca_dev); + retval = 1; + } + + if (retval) + PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", + gain, exposure); + return retval; +} -- cgit v1.2.2 From f51a8caafedfc643b3dfa2ffdfb02da31a13db3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sun, 13 Mar 2011 15:04:11 -0300 Subject: [media] gspca - sonixb: Use the new control mechanism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acked-by: Hans de Goede Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 286 ++++++++++++------------------------- 1 file changed, 93 insertions(+), 193 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index c6cd68d66b53..13cca7a82cb4 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -56,9 +56,22 @@ MODULE_AUTHOR("Michel Xhaard "); MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver"); MODULE_LICENSE("GPL"); +/* controls */ +enum e_ctrl { + BRIGHTNESS, + GAIN, + EXPOSURE, + AUTOGAIN, + FREQ, + NCTRLS /* number of controls */ +}; + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + atomic_t avg_lum; int prev_avg_lum; int exp_too_low_cnt; @@ -66,13 +79,8 @@ struct sd { int header_read; u8 header[12]; /* Header without sof marker */ - unsigned short exposure; - unsigned char gain; - unsigned char brightness; - unsigned char autogain; unsigned char autogain_ignore_frames; unsigned char frames_to_drop; - unsigned char freq; /* light freq filter setting */ __u8 bridge; /* Type of bridge */ #define BRIDGE_101 0 @@ -113,10 +121,9 @@ struct sensor_data { #define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ /* ctrl_dis helper macros */ -#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << COARSE_EXPOSURE_IDX) | \ - (1 << AUTOGAIN_IDX)) -#define NO_FREQ (1 << FREQ_IDX) -#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX) +#define NO_EXPO ((1 << EXPOSURE) | (1 << AUTOGAIN)) +#define NO_FREQ (1 << FREQ) +#define NO_BRIGHTNESS (1 << BRIGHTNESS) #define COMP 0xc7 /* 0x87 //0x07 */ #define COMP1 0xc9 /* 0x89 //0x09 */ @@ -141,20 +148,14 @@ struct sensor_data { #define AUTOGAIN_IGNORE_FRAMES 1 /* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); +static void setbrightness(struct gspca_dev *gspca_dev); +static void setgain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); +static void setfreq(struct gspca_dev *gspca_dev); -static const struct ctrl sd_ctrls[] = { -#define BRIGHTNESS_IDX 0 - { +static const struct ctrl sd_ctrls[NCTRLS] = { +[BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, @@ -162,14 +163,11 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 255, .step = 1, -#define BRIGHTNESS_DEF 127 - .default_value = BRIGHTNESS_DEF, + .default_value = 127, }, - .set = sd_setbrightness, - .get = sd_getbrightness, + .set_control = setbrightness }, -#define GAIN_IDX 1 - { +[GAIN] = { { .id = V4L2_CID_GAIN, .type = V4L2_CTRL_TYPE_INTEGER, @@ -177,48 +175,31 @@ static const struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 255, .step = 1, -#define GAIN_DEF 127 #define GAIN_KNEE 230 - .default_value = GAIN_DEF, + .default_value = 127, }, - .set = sd_setgain, - .get = sd_getgain, + .set_control = setgain }, -#define EXPOSURE_IDX 2 - { +[EXPOSURE] = { { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Exposure", -#define EXPOSURE_DEF 66 /* 33 ms / 30 fps (except on PASXXX) */ -#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */ .minimum = 0, .maximum = 1023, .step = 1, - .default_value = EXPOSURE_DEF, + .default_value = 66, + /* 33 ms / 30 fps (except on PASXXX) */ +#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */ .flags = 0, }, - .set = sd_setexposure, - .get = sd_getexposure, + .set_control = setexposure }, -#define COARSE_EXPOSURE_IDX 3 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", +/* for coarse exposure */ +#define COARSE_EXPOSURE_MIN 2 +#define COARSE_EXPOSURE_MAX 15 #define COARSE_EXPOSURE_DEF 2 /* 30 fps */ - .minimum = 2, - .maximum = 15, - .step = 1, - .default_value = COARSE_EXPOSURE_DEF, - .flags = 0, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, -#define AUTOGAIN_IDX 4 - { +[AUTOGAIN] = { { .id = V4L2_CID_AUTOGAIN, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -231,10 +212,8 @@ static const struct ctrl sd_ctrls[] = { .flags = 0, }, .set = sd_setautogain, - .get = sd_getautogain, }, -#define FREQ_IDX 5 - { +[FREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, .type = V4L2_CTRL_TYPE_MENU, @@ -245,8 +224,7 @@ static const struct ctrl sd_ctrls[] = { #define FREQ_DEF 0 .default_value = FREQ_DEF, }, - .set = sd_setfreq, - .get = sd_getfreq, + .set_control = setfreq }, }; @@ -646,7 +624,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) /* change reg 0x06 */ i2cOV[1] = sensor_data[sd->sensor].sensor_addr; - i2cOV[3] = sd->brightness; + i2cOV[3] = sd->ctrls[BRIGHTNESS].val; if (i2c_w(gspca_dev, i2cOV) < 0) goto err; break; @@ -664,13 +642,13 @@ static void setbrightness(struct gspca_dev *gspca_dev) i2cpdoit[2] = 0x13; } - if (sd->brightness < 127) { + if (sd->ctrls[BRIGHTNESS].val < 127) { /* change reg 0x0b, signreg */ i2cpbright[3] = 0x01; /* set reg 0x0c, offset */ - i2cpbright[4] = 127 - sd->brightness; + i2cpbright[4] = 127 - sd->ctrls[BRIGHTNESS].val; } else - i2cpbright[4] = sd->brightness - 127; + i2cpbright[4] = sd->ctrls[BRIGHTNESS].val - 127; if (i2c_w(gspca_dev, i2cpbright) < 0) goto err; @@ -687,16 +665,16 @@ err: static void setsensorgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - unsigned char gain = sd->gain; + u8 gain = sd->ctrls[GAIN].val; switch (sd->sensor) { case SENSOR_HV7131D: { __u8 i2c[] = {0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17}; - i2c[3] = 0x3f - (sd->gain / 4); - i2c[4] = 0x3f - (sd->gain / 4); - i2c[5] = 0x3f - (sd->gain / 4); + i2c[3] = 0x3f - (gain / 4); + i2c[4] = 0x3f - (gain / 4); + i2c[5] = 0x3f - (gain / 4); if (i2c_w(gspca_dev, i2c) < 0) goto err; @@ -759,11 +737,11 @@ static void setsensorgain(struct gspca_dev *gspca_dev) i2cpdoit[2] = 0x13; } - i2cpgain[3] = sd->gain >> 3; - i2cpcolorgain[3] = sd->gain >> 4; - i2cpcolorgain[4] = sd->gain >> 4; - i2cpcolorgain[5] = sd->gain >> 4; - i2cpcolorgain[6] = sd->gain >> 4; + i2cpgain[3] = gain >> 3; + i2cpcolorgain[3] = gain >> 4; + i2cpcolorgain[4] = gain >> 4; + i2cpcolorgain[5] = gain >> 4; + i2cpcolorgain[6] = gain >> 4; if (i2c_w(gspca_dev, i2cpgain) < 0) goto err; @@ -792,13 +770,13 @@ static void setgain(struct gspca_dev *gspca_dev) } if (sd->bridge == BRIDGE_103) { - gain = sd->gain >> 1; + gain = sd->ctrls[GAIN].val >> 1; buf[0] = gain; /* Red */ buf[1] = gain; /* Green */ buf[2] = gain; /* Blue */ reg_w(gspca_dev, 0x05, buf, 3); } else { - gain = sd->gain >> 4; + gain = sd->ctrls[GAIN].val >> 4; buf[0] = gain << 4 | gain; /* Red and blue */ buf[1] = gain; /* Green */ reg_w(gspca_dev, 0x10, buf, 2); @@ -820,7 +798,8 @@ static void setexposure(struct gspca_dev *gspca_dev) where the framerate starts dropping 2) At 6138 the framerate has already dropped to 2 fps, going any lower makes little sense */ - __u16 reg = sd->exposure * 6; + u16 reg = sd->ctrls[EXPOSURE].val * 6; + i2c[3] = reg >> 8; i2c[4] = reg & 0xff; if (i2c_w(gspca_dev, i2c) != 0) @@ -832,7 +811,8 @@ static void setexposure(struct gspca_dev *gspca_dev) /* register 19's high nibble contains the sn9c10x clock divider The high nibble configures the no fps according to the formula: 60 / high_nibble. With a maximum of 30 fps */ - __u8 reg = sd->exposure; + u8 reg = sd->ctrls[EXPOSURE].val; + reg = (reg << 4) | 0x0b; reg_w(gspca_dev, 0x19, ®, 1); break; @@ -868,7 +848,7 @@ static void setexposure(struct gspca_dev *gspca_dev) } else reg10_max = 0x41; - reg11 = (15 * sd->exposure + 999) / 1000; + reg11 = (15 * sd->ctrls[EXPOSURE].val + 999) / 1000; if (reg11 < 1) reg11 = 1; else if (reg11 > 16) @@ -881,14 +861,16 @@ static void setexposure(struct gspca_dev *gspca_dev) reg11 = 4; /* frame exposure time in ms = 1000 * reg11 / 30 -> - reg10 = (sd->exposure / 2) * reg10_max / (1000 * reg11 / 30) */ - reg10 = (sd->exposure * 15 * reg10_max) / (1000 * reg11); + reg10 = (sd->ctrls[EXPOSURE].val / 2) * reg10_max + / (1000 * reg11 / 30) */ + reg10 = (sd->ctrls[EXPOSURE].val * 15 * reg10_max) + / (1000 * reg11); /* Don't allow this to get below 10 when using autogain, the steps become very large (relatively) when below 10 causing the image to oscilate from much too dark, to much too bright and back again. */ - if (sd->autogain && reg10 < 10) + if (sd->ctrls[AUTOGAIN].val && reg10 < 10) reg10 = 10; else if (reg10 > reg10_max) reg10 = reg10_max; @@ -927,15 +909,16 @@ static void setexposure(struct gspca_dev *gspca_dev) frame exposure times (like we are doing with the ov chips), as that sometimes leads to jumps in the exposure control, which are bad for auto exposure. */ - if (sd->exposure < 200) { - i2cpexpo[3] = 255 - (sd->exposure * 255) / 200; + if (sd->ctrls[EXPOSURE].val < 200) { + i2cpexpo[3] = 255 - (sd->ctrls[EXPOSURE].val * 255) + / 200; framerate_ctrl = 500; } else { /* The PAS202's exposure control goes from 0 - 4095, but anything below 500 causes vsync issues, so scale our 200-1023 to 500-4095 */ - framerate_ctrl = (sd->exposure - 200) * 1000 / 229 + - 500; + framerate_ctrl = (sd->ctrls[EXPOSURE].val - 200) + * 1000 / 229 + 500; } i2cpframerate[3] = framerate_ctrl >> 6; @@ -959,15 +942,15 @@ static void setexposure(struct gspca_dev *gspca_dev) /* For values below 150 use partial frame exposure, above that use framerate ctrl */ - if (sd->exposure < 150) { - i2cpexpo[3] = 150 - sd->exposure; + if (sd->ctrls[EXPOSURE].val < 150) { + i2cpexpo[3] = 150 - sd->ctrls[EXPOSURE].val; framerate_ctrl = 300; } else { /* The PAS106's exposure control goes from 0 - 4095, but anything below 300 causes vsync issues, so scale our 150-1023 to 300-4095 */ - framerate_ctrl = (sd->exposure - 150) * 1000 / 230 + - 300; + framerate_ctrl = (sd->ctrls[EXPOSURE].val - 150) + * 1000 / 230 + 300; } i2cpframerate[3] = framerate_ctrl >> 4; @@ -998,7 +981,7 @@ static void setfreq(struct gspca_dev *gspca_dev) 0x2b register, see ov6630 datasheet. 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */ __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; - switch (sd->freq) { + switch (sd->ctrls[FREQ].val) { default: /* case 0: * no filter*/ /* case 2: * 60 hz */ @@ -1017,7 +1000,7 @@ static void setfreq(struct gspca_dev *gspca_dev) } } -#include "coarse_expo_autogain.h" +#include "autogain_functions.h" static void do_autogain(struct gspca_dev *gspca_dev) { @@ -1025,7 +1008,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int avg_lum = atomic_read(&sd->avg_lum); - if (avg_lum == -1 || !sd->autogain) + if (avg_lum == -1 || !sd->ctrls[AUTOGAIN].val) return; if (sd->autogain_ignore_frames > 0) { @@ -1045,17 +1028,20 @@ static void do_autogain(struct gspca_dev *gspca_dev) } if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) - result = gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum, - sd->brightness * desired_avg_lum / 127, + result = coarse_grained_expo_autogain(gspca_dev, avg_lum, + sd->ctrls[BRIGHTNESS].val + * desired_avg_lum / 127, deadzone); else - result = gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - sd->brightness * desired_avg_lum / 127, + result = auto_gain_n_exposure(gspca_dev, avg_lum, + sd->ctrls[BRIGHTNESS].val + * desired_avg_lum / 127, deadzone, GAIN_KNEE, EXPOSURE_KNEE); if (result) { PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d", - (int)sd->gain, (int)sd->exposure); + (int) sd->ctrls[GAIN].val, + (int) sd->ctrls[EXPOSURE].val); sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; } } @@ -1074,9 +1060,11 @@ static int sd_config(struct gspca_dev *gspca_dev, /* copy the webcam info from the device id */ sd->sensor = id->driver_info >> 8; sd->bridge = id->driver_info & 0xff; + gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis; cam = &gspca_dev->cam; + cam->ctrls = sd->ctrls; if (!(sensor_data[sd->sensor].flags & F_SIF)) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); @@ -1086,20 +1074,11 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam->npkt = 36; /* 36 packets per ISOC message */ - sd->brightness = BRIGHTNESS_DEF; - sd->gain = GAIN_DEF; if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) { - sd->exposure = COARSE_EXPOSURE_DEF; - gspca_dev->ctrl_dis |= (1 << EXPOSURE_IDX); - } else { - sd->exposure = EXPOSURE_DEF; - gspca_dev->ctrl_dis |= (1 << COARSE_EXPOSURE_IDX); + sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN; + sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX; + sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF; } - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) - sd->autogain = 0; /* Disable do_autogain callback */ - else - sd->autogain = AUTOGAIN_DEF; - sd->freq = FREQ_DEF; return 0; } @@ -1398,65 +1377,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - return 0; -} - -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->gain = val; - if (gspca_dev->streaming) - setgain(gspca_dev); - return 0; -} - -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->gain; - return 0; -} - -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->exposure = val; - if (gspca_dev->streaming) - setexposure(gspca_dev); - return 0; -} - -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->exposure; - return 0; -} - static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - sd->autogain = val; + sd->ctrls[AUTOGAIN].val = val; sd->exp_too_high_cnt = 0; sd->exp_too_low_cnt = 0; @@ -1464,9 +1389,10 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) we are on a valid point of the autogain gain / exposure knee graph, and give this change time to take effect before doing autogain. */ - if (sd->autogain && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) { - sd->exposure = EXPOSURE_DEF; - sd->gain = GAIN_DEF; + if (sd->ctrls[AUTOGAIN].val + && !(sensor_data[sd->sensor].flags & F_COARSE_EXPO)) { + sd->ctrls[EXPOSURE].val = sd->ctrls[EXPOSURE].def; + sd->ctrls[GAIN].val = sd->ctrls[GAIN].def; if (gspca_dev->streaming) { sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; setexposure(gspca_dev); @@ -1477,32 +1403,6 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) return 0; } -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->freq = val; - if (gspca_dev->streaming) - setfreq(gspca_dev); - return 0; -} - -static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->freq; - return 0; -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { -- cgit v1.2.2 From f0baad866b3c71d448747b06b1cf6b3493d2f7ce Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 13 Mar 2011 16:05:55 -0300 Subject: [media] gspca - sonixb: Update inactive flags to reflect autogain setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hans de Goede Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 13cca7a82cb4..c6c65f2da351 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -209,7 +209,7 @@ static const struct ctrl sd_ctrls[NCTRLS] = { .step = 1, #define AUTOGAIN_DEF 1 .default_value = AUTOGAIN_DEF, - .flags = 0, + .flags = V4L2_CTRL_FLAG_UPDATE }, .set = sd_setautogain, }, @@ -1008,7 +1008,8 @@ static void do_autogain(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int avg_lum = atomic_read(&sd->avg_lum); - if (avg_lum == -1 || !sd->ctrls[AUTOGAIN].val) + if ((gspca_dev->ctrl_dis & (1 << AUTOGAIN)) || + avg_lum == -1 || !sd->ctrls[AUTOGAIN].val) return; if (sd->autogain_ignore_frames > 0) { @@ -1062,6 +1063,10 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->bridge = id->driver_info & 0xff; gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis; +#if AUTOGAIN_DEF + if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); +#endif cam = &gspca_dev->cam; cam->ctrls = sd->ctrls; @@ -1400,6 +1405,11 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) } } + if (sd->ctrls[AUTOGAIN].val) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); + else + gspca_dev->ctrl_inac = 0; + return 0; } -- cgit v1.2.2 From 75b79ffcc37c6bd05fa895f85d2d6426a9e4c3f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sun, 13 Mar 2011 16:07:25 -0300 Subject: [media] gspca - sonixb: Clenup source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - update copyright and module author - set the sensor table as constant Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index c6c65f2da351..5a08738fba30 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1,9 +1,9 @@ /* * sonix sn9c102 (bayer) library - * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr - * Add Pas106 Stefano Mozzi (C) 2004 * - * V4L2 by Jean-Francois Moine + * Copyright (C) 2009-2011 Jean-François Moine + * Copyright (C) 2003 2004 Michel Xhaard mxhaard@magic.fr + * Add Pas106 Stefano Mozzi (C) 2004 * * 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 @@ -52,7 +52,7 @@ all: #include #include "gspca.h" -MODULE_AUTHOR("Michel Xhaard "); +MODULE_AUTHOR("Jean-François Moine "); MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -531,7 +531,7 @@ static const __u8 tas5130_sensor_init[][8] = { {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}, }; -static struct sensor_data sensor_data[] = { +static const struct sensor_data sensor_data[] = { SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0), SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0), SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60), -- cgit v1.2.2 From 7d47b789ceb456d90a3ace522dbcb2a94d2693ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sun, 13 Mar 2011 16:17:08 -0300 Subject: [media] gspca - jeilinj / stv06xx: Fix some warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/jeilinj.c | 2 -- drivers/media/video/gspca/stv06xx/stv06xx.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c index 06b777f5379e..36dae38b1e38 100644 --- a/drivers/media/video/gspca/jeilinj.c +++ b/drivers/media/video/gspca/jeilinj.c @@ -183,7 +183,6 @@ static void jlj_dostream(struct work_struct *work) struct sd *dev = container_of(work, struct sd, work_struct); struct gspca_dev *gspca_dev = &dev->gspca_dev; int blocks_left; /* 0x200-sized blocks remaining in current frame. */ - int size_in_blocks; int act_len; int packet_type; int ret; @@ -209,7 +208,6 @@ static void jlj_dostream(struct work_struct *work) act_len, JEILINJ_MAX_TRANSFER); if (ret < 0 || act_len < FRAME_HEADER_LEN) goto quit_stream; - size_in_blocks = buffer[0x0a]; blocks_left = buffer[0x0a] - 1; PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left); diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index 7e0661429293..abf1658fa33e 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -525,11 +525,9 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; PDEBUG(D_PROBE, "Configuring camera"); - cam = &gspca_dev->cam; sd->desc = sd_desc; sd->bridge = id->driver_info; gspca_dev->sd_desc = &sd->desc; -- cgit v1.2.2 From 58c92d37e7d34433cfbc3989bec20e48fba0799e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Sun, 13 Mar 2011 16:36:49 -0300 Subject: [media] gspca - ov519: Add exposure and autogain controls for ov2610/2610ae MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/ov519.c | 120 +++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 42670ec7ef3b..fd1b6082c96d 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -1,7 +1,7 @@ /** * OV519 driver * - * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr) + * Copyright (C) 2008-2011 Jean-François Moine * Copyright (C) 2009 Hans de Goede * * This module is adapted from the ov51x-jpeg package, which itself @@ -61,10 +61,12 @@ static int i2c_detect_tries = 10; enum e_ctrl { BRIGHTNESS, CONTRAST, + EXPOSURE, COLORS, HFLIP, VFLIP, AUTOBRIGHT, + AUTOGAIN, FREQ, NCTRL /* number of controls */ }; @@ -142,9 +144,11 @@ enum sensors { /* V4L2 controls supported by the driver */ static void setbrightness(struct gspca_dev *gspca_dev); static void setcontrast(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); static void setcolors(struct gspca_dev *gspca_dev); static void sethvflip(struct gspca_dev *gspca_dev); static void setautobright(struct gspca_dev *gspca_dev); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static void setfreq(struct gspca_dev *gspca_dev); static void setfreq_i(struct sd *sd); @@ -173,6 +177,18 @@ static const struct ctrl sd_ctrls[] = { }, .set_control = setcontrast, }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 127, + }, + .set_control = setexposure, + }, [COLORS] = { { .id = V4L2_CID_SATURATION, @@ -222,6 +238,19 @@ static const struct ctrl sd_ctrls[] = { }, .set_control = setautobright, }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = V4L2_CTRL_FLAG_UPDATE + }, + .set = sd_setautogain, + }, [FREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -238,50 +267,78 @@ static const struct ctrl sd_ctrls[] = { /* table of the disabled controls */ static const unsigned ctrl_dis[] = { -[SEN_OV2610] = (1 << NCTRL) - 1, /* no control */ +[SEN_OV2610] = ((1 << NCTRL) - 1) /* no control */ + ^ ((1 << EXPOSURE) /* but exposure */ + | (1 << AUTOGAIN)), /* and autogain */ -[SEN_OV2610AE] = (1 << NCTRL) - 1, /* no control */ +[SEN_OV2610AE] = ((1 << NCTRL) - 1) /* no control */ + ^ ((1 << EXPOSURE) /* but exposure */ + | (1 << AUTOGAIN)), /* and autogain */ [SEN_OV3610] = (1 << NCTRL) - 1, /* no control */ [SEN_OV6620] = (1 << HFLIP) | - (1 << VFLIP), + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV6630] = (1 << HFLIP) | - (1 << VFLIP), + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV66308AF] = (1 << HFLIP) | - (1 << VFLIP), + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV7610] = (1 << HFLIP) | - (1 << VFLIP), + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV7620] = (1 << HFLIP) | - (1 << VFLIP), + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV7620AE] = (1 << HFLIP) | - (1 << VFLIP), + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV7640] = (1 << HFLIP) | (1 << VFLIP) | (1 << AUTOBRIGHT) | - (1 << CONTRAST), + (1 << CONTRAST) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV7648] = (1 << HFLIP) | (1 << VFLIP) | (1 << AUTOBRIGHT) | - (1 << CONTRAST), + (1 << CONTRAST) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), -[SEN_OV7660] = (1 << AUTOBRIGHT), +[SEN_OV7660] = (1 << AUTOBRIGHT) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV7670] = (1 << COLORS) | - (1 << AUTOBRIGHT), + (1 << AUTOBRIGHT) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV76BE] = (1 << HFLIP) | - (1 << VFLIP), + (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN), [SEN_OV8610] = (1 << HFLIP) | (1 << VFLIP) | + (1 << EXPOSURE) | + (1 << AUTOGAIN) | (1 << FREQ), }; @@ -3201,6 +3258,13 @@ static void ov519_set_fr(struct sd *sd) ov518_i2c_w(sd, OV7670_R11_CLKRC, clock); } +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + i2c_w_mask(sd, 0x13, sd->ctrls[AUTOGAIN].val ? 0x05 : 0x00, 0x05); +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -4189,12 +4253,16 @@ static int sd_start(struct gspca_dev *gspca_dev) setcontrast(gspca_dev); if (!(sd->gspca_dev.ctrl_dis & (1 << BRIGHTNESS))) setbrightness(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << EXPOSURE))) + setexposure(gspca_dev); if (!(sd->gspca_dev.ctrl_dis & (1 << COLORS))) setcolors(gspca_dev); if (!(sd->gspca_dev.ctrl_dis & ((1 << HFLIP) | (1 << VFLIP)))) sethvflip(gspca_dev); if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOBRIGHT))) setautobright(gspca_dev); + if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOGAIN))) + setautogain(gspca_dev); if (!(sd->gspca_dev.ctrl_dis & (1 << FREQ))) setfreq_i(sd); @@ -4608,6 +4676,14 @@ static void setcontrast(struct gspca_dev *gspca_dev) } } +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->ctrls[AUTOGAIN].val) + i2c_w(sd, 0x10, sd->ctrls[EXPOSURE].val); +} + static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -4666,6 +4742,22 @@ static void setautobright(struct gspca_dev *gspca_dev) i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10); } +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AUTOGAIN].val = val; + if (val) { + gspca_dev->ctrl_inac |= (1 << EXPOSURE); + } else { + gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); + sd->ctrls[EXPOSURE].val = i2c_r(sd, 0x10); + } + if (gspca_dev->streaming) + setautogain(gspca_dev); + return gspca_dev->usb_err; +} + static void setfreq_i(struct sd *sd) { if (sd->sensor == SEN_OV7660 -- cgit v1.2.2 From 59929cefa5f573178df3c4abfb36d55f7b33f214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Mon, 14 Mar 2011 05:33:01 -0300 Subject: [media] gspca - main: Cleanup source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - change copyright and erroneous comment - small code optimization - have constant the device template Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index f21f2a258ae0..62881740a0bd 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -1,7 +1,7 @@ /* * Main USB camera driver * - * Copyright (C) 2008-2010 Jean-François Moine + * Copyright (C) 2008-2011 Jean-François Moine * * Camera button input handling by Márton Németh * Copyright (C) 2009-2010 Márton Németh @@ -414,7 +414,6 @@ resubmit: * - 0 or many INTER_PACKETs * - one LAST_PACKET * DISCARD_PACKET invalidates the whole frame. - * On LAST_PACKET, a new frame is returned. */ void gspca_frame_add(struct gspca_dev *gspca_dev, enum gspca_packet_type packet_type, @@ -1525,10 +1524,12 @@ static int vidioc_reqbufs(struct file *file, void *priv, gspca_dev->usb_err = 0; gspca_stream_off(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); + + /* Don't restart the stream when switching from read + * to mmap mode */ + if (gspca_dev->memory == GSPCA_MEMORY_READ) + streaming = 0; } - /* Don't restart the stream when switching from read to mmap mode */ - if (gspca_dev->memory == GSPCA_MEMORY_READ) - streaming = 0; /* free the previous allocated buffers, if any */ if (gspca_dev->nframes != 0) @@ -2152,7 +2153,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_g_chip_ident = vidioc_g_chip_ident, }; -static struct video_device gspca_template = { +static const struct video_device gspca_template = { .name = "gspca main driver", .fops = &dev_fops, .ioctl_ops = &dev_ioctl_ops, -- cgit v1.2.2 From ce5b2acce60405b938d1f1f994024cde4e2cdd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Mon, 14 Mar 2011 08:49:28 -0300 Subject: [media] gspca - nw80x: New subdriver for Divio based webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [mchehab@redhat.com: Fix a few CodingStyle issues] Tested-by: Kjell Claesson Tested-by: Hans de Goede Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/Kconfig | 9 + drivers/media/video/gspca/Makefile | 2 + drivers/media/video/gspca/nw80x.c | 2443 ++++++++++++++++++++++++++++++++++++ 3 files changed, 2454 insertions(+) create mode 100644 drivers/media/video/gspca/nw80x.c (limited to 'drivers') diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index a20f6ae88250..eb04e8b59989 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -104,6 +104,15 @@ config USB_GSPCA_MR97310A To compile this driver as a module, choose M here: the module will be called gspca_mr97310a. +config USB_GSPCA_NW80X + tristate "Divio based (NW80x) USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on the NW80x chips. + + To compile this driver as a module, choose M here: the + module will be called gspca_nw80x. + config USB_GSPCA_OV519 tristate "OV51x / OVFX2 / W996xCF USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index a0dbcfbab29c..855fbc8c9c47 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o +obj-$(CONFIG_USB_GSPCA_NW80X) += gspca_nw80x.o obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o obj-$(CONFIG_USB_GSPCA_OV534) += gspca_ov534.o obj-$(CONFIG_USB_GSPCA_OV534_9) += gspca_ov534_9.o @@ -48,6 +49,7 @@ gspca_jeilinj-objs := jeilinj.o gspca_konica-objs := konica.o gspca_mars-objs := mars.o gspca_mr97310a-objs := mr97310a.o +gspca_nw80x-objs := nw80x.o gspca_ov519-objs := ov519.o gspca_ov534-objs := ov534.o gspca_ov534_9-objs := ov534_9.o diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c new file mode 100644 index 000000000000..1c9d3c2f6670 --- /dev/null +++ b/drivers/media/video/gspca/nw80x.c @@ -0,0 +1,2443 @@ +/* + * DivIO nw80x subdriver + * + * Copyright (C) 2011 Jean-François Moine (http://moinejf.free.fr) + * Copyright (C) 2003 Sylvain Munaut + * Kjell Claesson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "nw80x" + +#include "gspca.h" + +MODULE_AUTHOR("Jean-Francois Moine "); +MODULE_DESCRIPTION("NW80x USB Camera Driver"); +MODULE_LICENSE("GPL"); + +static int webcam; + +/* controls */ +enum e_ctrl { + GAIN, + EXPOSURE, + AUTOGAIN, + NCTRLS /* number of controls */ +}; + +/* specific webcam descriptor */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + + struct gspca_ctrl ctrls[NCTRLS]; + + u32 ae_res; + s8 ag_cnt; +#define AG_CNT_START 13 + + u8 bridge; + u8 webcam; +}; + +enum bridges { + BRIDGE_NW800, /* et31x110 */ + BRIDGE_NW801, + BRIDGE_NW802, +}; +enum webcams { + Generic800, + SpaceCam, /* Trust 120 SpaceCam */ + SpaceCam2, /* other Trust 120 SpaceCam */ + Cvideopro, /* Conceptronic Video Pro */ + Dlink350c, + DS3303u, + Kr651us, + Kritter, + Mustek300, + Proscope, + Twinkle, + DsbC110, + DvcV6, + P35u, + Generic802, + NWEBCAMS /* number of webcams */ +}; + +/* + - webcams: + - Typhoon Webcam 100 USB (06a5:0000) + nw800 + - Trust SpaceCam120 or SpaceCam100 PORTABLE (06a5:d800) + nw801 SpaceCam.init + or trust_space.init if no LED (?) + - Divio Chicony TwinkleCam (06a5:d800) ? + nw800 Twinkle.init + - Plustek Opticam 500U or ProLink DS3303u + nw801 DS3303u.init + - Logitech QuickCam Pro (dark focus ring) (046d:d001) + nw801 + - EZCam Pro p35u (052b:d001, 06a5:d001 and 06be:d001) + nw801 - sensor Sharp IR3Y38M + - AVerMedia Camguard (0728:d001) + nw801 + - Panasonic GP-KR651US (06a5:d001) + nw802 kr651us.init + - iRez Kritter cam + nw802 kritter.init + - D-link dru-350c cam + nw802 d-link-350c.init + - The Scope USB Microscope M2 (ProScope) + = Divio ProLink DS3303u WebCam (06a5:d001) + = Scalar USB Microscope M2 (Proscope) + nw802 proscope.init + - Conceptronic Video Pro 'CVIDEOPRO USB Webcam CCD' (06a5:d001) + nw802 cvideopro.init + - Mustek Wcam 300 mini + nw802 mustek_300_mini.init + - D-Link NetQam Pro 250plus (06a5:d001) + - Showcam NGS webcam (065a:d800) + - sceptre svc300 + - DSB-C110 (06a5:d800) + et31x110 + - DVC V6 (0502:d001) + nw802 + - registers + nw800/et31x110 nw801 nw802 + 0000..009e 0000..00a1 0000..009e + 0200..0211 id id + 0300..0302 id id + 0400..0406 (inex) 0400..0406 + 0500..0505 0500..0506 (inex) + 0600..061a 0600..0601 0600..0601 + 0800..0814 id id + 1000..109c 1000..10a1 1000..109a + + 080c: luma (nw800/nw802) + 080d: luma (nw801) + 1004: LUT (?) + 100b: R gain (0..63) + 100c: B gain + 100d: G gain + 100e: Y gain + 100f: U gain + 1010: V gain + 1019: clock (nw801 - bit 0x08: indoor/outdoor) + 101b: shutter 1 (0..255) + 101c: shutter 2 + 1026: BP = gain (nw801) + 1041, 1052, 1063, 1074: LUT base (nw802) + 1048, 1059, 106a, 107b: LUT base (nw801) + - resolutions + nw800 352x288 + nw801/nw802 320x240 - 640x480 +*/ + +static const struct v4l2_pix_format sif_mode[] = { + {352, 288, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 4 / 8, + .colorspace = V4L2_COLORSPACE_JPEG} +}; +static const struct v4l2_pix_format vga_mode[] = { + {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8, + .colorspace = V4L2_COLORSPACE_JPEG}, + {640, 480, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 8, + .colorspace = V4L2_COLORSPACE_JPEG}, +}; + +/* + * The sequences below contain: + * - 1st and 2nd bytes: either + * - register number (BE) + * - I2C0 + i2c address + * - 3rd byte: data length (=0 for end of sequence) + * - n bytes: data + */ +#define I2C0 0xff +static const u8 nw800_init[] = { + 0x05, 0x00, 0x01, 0x55, + 0x10, 0x9b, 0x01, 0xaa, + 0x05, 0x02, 0x01, 0x02, + 0x06, 0x00, 0x02, 0x04, 0xd9, + 0x05, 0x05, 0x01, 0x00, + 0x05, 0x05, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + + 0x04, 0x06, 0x01, 0xc0, + 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, + 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, + 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0, + 0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + + 0x04, 0x04, 0x01, 0xff, + 0x04, 0x06, 0x01, 0xc4, + + 0x04, 0x06, 0x01, 0xc0, + 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, + 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, + 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0xc0, + 0x05, 0x00, 0x06, 0xe8, 0x00, 0x00, 0x00, 0x20, 0x20, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, + 0x40, + 0x00, 0x80, 0x01, 0xa0, + 0x10, 0x1a, 0x01, 0x00, + 0x00, 0x91, 0x02, 0x6c, 0x01, + 0x00, 0x03, 0x02, 0xc8, 0x01, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0x83, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x10, 0x1b, 0x02, 0x69, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x05, 0x02, 0x01, 0x02, + 0x06, 0x00, 0x02, 0x04, 0xd9, + 0x05, 0x05, 0x01, 0x20, + 0x05, 0x05, 0x01, 0x21, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83, + 0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0, + 0xea, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x13, 0x13, + 0x10, 0x03, 0x01, 0x14, + 0x10, 0x41, 0x11, 0x00, 0x08, 0x21, 0x3d, 0x52, 0x63, 0x75, 0x83, + 0x91, 0x9e, 0xaa, 0xb6, 0xc1, 0xcc, 0xd6, 0xe0, + 0xea, + 0x10, 0x0b, 0x01, 0x14, + 0x10, 0x0d, 0x01, 0x20, + 0x10, 0x0c, 0x01, 0x34, + 0x04, 0x06, 0x01, 0xc3, + 0x04, 0x04, 0x01, 0x00, + 0x05, 0x02, 0x01, 0x02, + 0x06, 0x00, 0x02, 0x00, 0x48, + 0x05, 0x05, 0x01, 0x20, + 0x05, 0x05, 0x01, 0x21, + 0, 0, 0 +}; + +/* 06a5:d001 - nw801 - p35u */ +static const u8 nw801_init_1[] = { + 0x05, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x0e, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, + 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x69, 0xa8, 0x1f, 0x00, + 0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00, + 0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00, + 0x36, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x22, 0x02, 0x80, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, 0x15, 0x08, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x35, 0xfd, 0x07, 0x3d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x02, + 0x00, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x40, 0x20, 0x10, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7, + 0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80, + 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, 0xa4, + 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, 0xcf, + 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, + 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, + 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x82, 0x02, + 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01, + 0xf0, 0x00, + 0, 0, 0, +}; +static const u8 nw801_init_qvga[] = { + 0x02, 0x00, 0x10, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x18, 0x0b, 0x06, 0xa2, 0x86, 0x78, + 0x02, 0x0f, 0x01, 0x6b, + 0x10, 0x1a, 0x01, 0x15, + 0x00, 0x00, 0x01, 0x1e, + 0x10, 0x00, 0x01, 0x2f, + 0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00, + /* AE window */ + 0, 0, 0, +}; +static const u8 nw801_init_vga[] = { + 0x02, 0x00, 0x10, 0x78, 0xa0, 0x97, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xf0, + 0x02, 0x0f, 0x01, 0xd5, + 0x10, 0x1a, 0x01, 0x15, + 0x00, 0x00, 0x01, 0x0e, + 0x10, 0x00, 0x01, 0x22, + 0x10, 0x8c, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, + 0, 0, 0, +}; +static const u8 nw801_init_2[] = { + 0x10, 0x04, 0x01, 0x1a, + 0x10, 0x19, 0x01, 0x09, /* clock */ + 0x10, 0x24, 0x06, 0xc0, 0x00, 0x3f, 0x02, 0x00, 0x01, + /* .. gain .. */ + 0x00, 0x03, 0x02, 0x92, 0x03, + 0x00, 0x1d, 0x04, 0xf2, 0x00, 0x24, 0x07, + 0x00, 0x7b, 0x01, 0xcf, + 0x10, 0x94, 0x01, 0x07, + 0x05, 0x05, 0x01, 0x01, + 0x05, 0x04, 0x01, 0x01, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8, + 0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0, + 0xf0, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x08, + 0x10, 0x48, 0x11, 0x00, 0x37, 0x55, 0x6b, 0x7d, 0x8d, 0x9b, 0xa8, + 0xb4, 0xbf, 0xca, 0xd4, 0xdd, 0xe6, 0xef, 0xf0, + 0xf0, + 0x10, 0x0b, 0x01, 0x0b, + 0x10, 0x0d, 0x01, 0x0b, + 0x10, 0x0c, 0x01, 0x1f, + 0x05, 0x06, 0x01, 0x03, + 0, 0, 0 +}; + +/* nw802 (sharp IR3Y38M?) */ +static const u8 nw802_init[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x4d, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x08, 0x00, 0x18, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0xff, 0x01, 0xc0, 0x00, 0x14, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0xad, + 0x00, 0x00, 0x01, 0x08, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00, + 0x10, 0x1d, 0x08, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, 0x00, 0xa0, + 0x10, 0x0e, 0x01, 0x27, + 0x10, 0x41, 0x11, 0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b, + 0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2, + 0xd8, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x14, 0x14, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, 0x74, + 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, 0xf1, + 0xff, +/* 0x00, 0x0e, 0x35, 0x4f, 0x62, 0x71, 0x7f, 0x8b, + * 0x96, 0xa0, 0xa9, 0xb2, 0xbb, 0xc3, 0xca, 0xd2, + * 0xd8, */ + 0x10, 0x0b, 0x01, 0x10, + 0x10, 0x0d, 0x01, 0x11, + 0x10, 0x0c, 0x01, 0x1c, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; +/* et31x110 - Trust 120 SpaceCam */ +static const u8 spacecam_init[] = { +/*fixme: at connection time*/ + 0x04, 0x05, 0x01, 0x01, + 0x04, 0x04, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x01, 0x00, +/*fixme: add 300ms delay?*/ +/*fixme: at capture start time*/ + 0x04, 0x06, 0x01, 0x44, + 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x3e, 0x00, 0x24, + 0x03, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xa0, 0x48, 0xc3, 0x02, 0x88, 0x0c, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x06, 0x00, 0x08, + 0x00, 0x32, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x7c, 0x00, 0x80, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x83, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + 0x04, 0x06, 0x01, 0xc0, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, + 0x40, + 0x00, 0x80, 0x01, 0xa0, + 0x10, 0x1a, 0x01, 0x00, + 0x00, 0x91, 0x02, 0x32, 0x01, + 0x00, 0x03, 0x02, 0x08, 0x02, + 0x10, 0x00, 0x01, 0x83, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x13, 0x13, + 0x10, 0x03, 0x01, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x64, 0x99, 0xc0, 0xe2, 0xf9, 0xf9, 0xf9, + 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x0b, 0x01, 0x08, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1f, + 0x04, 0x06, 0x01, 0xc3, + 0x04, 0x05, 0x01, 0x40, + 0x04, 0x04, 0x01, 0x40, + 0, 0, 0 +}; +/* et31x110 - other Trust SpaceCam120 */ +static const u8 spacecam2_init[] = { + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x01, 0x00, + 0x04, 0x06, 0x01, 0x44, + 0x04, 0x06, 0x01, 0x00, + 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, + 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, + 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, + 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x04, 0x04, 0x01, 0x40, + 0x04, 0x04, 0x01, 0x00, +#if 1 + I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x05, + I2C0, 0x40, 0x02, 0x11, 0x06, + I2C0, 0x40, 0x02, 0x14, 0x00, + I2C0, 0x40, 0x02, 0x13, 0x01, +#else + 0x06, 0x00, 0x0b, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x05, 0x05, + 0x06, 0x00, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x05, + 0x05, 0x02, 0x02, 0x0c, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x06, + 0x06, 0x00, 0x02, 0x11, 0x06, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x14, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, + 0x40, +#if 1 + I2C0, 0x40, 0x02, 0x02, 0x0c, + I2C0, 0x40, 0x02, 0x0f, 0x00, + I2C0, 0x40, 0x02, 0x13, 0x01, +#else + 0x06, 0x00, 0x01, 0x0c, + 0x06, 0x00, 0x02, 0x02, 0x0c, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x0f, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x00, 0x01, 0x01, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, +#if 1 + I2C0, 0x40, 0x02, 0x05, 0x0f, + I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x07, 0x09, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, + I2C0, 0x40, 0x03, 0x12, 0x04, 0x01, +#else + 0x06, 0x00, 0x01, 0x0f, + 0x06, 0x00, 0x02, 0x05, 0x0f, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x06, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, + 0x06, 0x00, 0x07, 0x09, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, + 0x05, 0x02, 0x02, 0x07, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x04, 0x01, + 0x06, 0x00, 0x03, 0x12, 0x04, 0x01, + 0x05, 0x02, 0x02, 0x03, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x13, 0x13, + 0x10, 0x03, 0x01, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x0b, 0x01, 0x11, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x14, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - Conceptronic Video Pro */ +static const u8 cvideopro_init[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, + 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, + 0x40, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xac, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x3b, 0x01, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x1d, 0x02, 0x40, 0x06, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0, + 0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc, + 0xdc, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x12, 0x12, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x46, 0x62, 0x76, 0x86, 0x94, 0xa0, + 0xab, 0xb6, 0xbf, 0xc8, 0xcf, 0xd7, 0xdc, 0xdc, + 0xdc, + 0x10, 0x0b, 0x01, 0x09, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x2f, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - D-link dru-350c cam */ +static const u8 dlink_init[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, +/* 0xf9, 0x02, = nb pixels per line */ + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, +/* 0x19, v index of clamping pulse */ + 0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, +/* 0x00, 0x03, 0x02, 0x92, 0x03, = nb of pixels per line */ + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0xad, + 0x00, 0x00, 0x01, 0x08, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x51, 0x00, 0xf0, 0x00, 0x3d, 0x00, 0xb4, 0x00, + 0x10, 0x1d, 0x08, 0x40, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x0e, 0x01, 0x20, + 0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f, + 0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf, + 0xea, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x11, 0x11, + 0x10, 0x03, 0x01, 0x10, + 0x10, 0x41, 0x11, 0x00, 0x07, 0x1e, 0x38, 0x4d, 0x60, 0x70, 0x7f, + 0x8e, 0x9b, 0xa8, 0xb4, 0xbf, 0xca, 0xd5, 0xdf, + 0xea, + 0x10, 0x0b, 0x01, 0x19, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1e, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw801 - Plustek Opticam 500U or ProLink DS3303u (Hitachi HD49322BF) */ +static const u8 ds330_init[] = { + 0x05, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x16, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, + 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x22, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa9, 0xa8, 0x1f, 0x00, + 0x0d, 0x02, 0x07, 0x00, 0x01, 0x00, 0x19, 0x00, + 0xf2, 0x00, 0x18, 0x06, 0x10, 0x06, 0x10, 0x00, + 0x36, 0x00, + 0x02, 0x00, 0x12, 0x03, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0x50, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x05, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x2f, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a, + 0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4, + 0x00, 0x01, 0x15, 0xfd, 0x07, 0x3d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8c, 0x04, 0x01, 0x20, + 0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, 0xf7, + 0x10, 0x40, 0x40, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, 0x80, + 0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f, 0x88, + 0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4, 0xcb, + 0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, 0x64, + 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, 0xe2, + 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x10, 0x80, 0x22, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f, 0x01, + 0x00, 0x00, 0xef, 0x00, 0x02, 0x0a, 0x82, 0x02, + 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01, + 0xf0, 0x00, + + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x00, 0xf2, 0x8f, 0x81, + 0x40, + 0x10, 0x1a, 0x01, 0x15, + 0x10, 0x00, 0x01, 0x2f, + 0x10, 0x8c, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x26, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x24, 0x02, 0x40, 0x06, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6, + 0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x16, 0x16, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x48, 0x11, 0x00, 0x15, 0x40, 0x67, 0x84, 0x9d, 0xb2, 0xc6, + 0xd6, 0xe7, 0xf6, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf9, + 0x10, 0x0b, 0x01, 0x26, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1c, + 0x05, 0x06, 0x01, 0x03, + 0x05, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* 06a5:d001 - nw802 - Panasonic GP-KR651US (Philips TDA8786) */ +static const u8 kr651_init_1[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x48, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, + 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0, 0, 0 +}; +static const u8 kr651_init_qvga[] = { + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xac, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x29, 0x00, 0x18, 0x01, 0x1f, 0x00, 0xd2, 0x00, + 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, + 0x10, 0x1d, 0x02, 0x28, 0x01, + 0, 0, 0 +}; +static const u8 kr651_init_vga[] = { + 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x30, 0x03, 0x01, 0x82, 0x82, 0x98, + 0x80, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xa0, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, + + 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, + 0x10, 0x1d, 0x02, 0x68, 0x00, +}; +static const u8 kr651_init_2[] = { + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8, + 0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8, + 0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, + 0x10, 0x0b, 0x01, 0x10, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x2d, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - iRez Kritter cam */ +static const u8 kritter_init[] = { + 0x04, 0x06, 0x01, 0x06, + 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0x94, 0x03, 0x18, 0x00, 0x48, + 0x0f, 0x1e, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0x0a, 0x01, 0x28, + 0x07, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0x0e, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x18, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0b, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x02, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, + 0x40, + 0x10, 0x1a, 0x01, 0x03, + 0x10, 0x00, 0x01, 0xaf, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x3b, 0x01, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, + 0x10, 0x1d, 0x02, 0x00, 0x00, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86, + 0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4, + 0xcb, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0d, 0x0d, + 0x10, 0x03, 0x01, 0x02, + 0x10, 0x41, 0x11, 0x00, 0x0d, 0x36, 0x4e, 0x60, 0x6f, 0x7b, 0x86, + 0x90, 0x98, 0xa1, 0xa9, 0xb1, 0xb7, 0xbe, 0xc4, + 0xcb, + 0x10, 0x0b, 0x01, 0x17, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1e, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw802 - Mustek Wcam 300 mini */ +static const u8 mustek_init[] = { + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, + 0x00, 0x10, 0x06, 0xfc, 0x05, 0x0c, 0x06, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa1, 0x02, 0x80, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xc0, 0x00, 0x14, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x00, + 0x10, 0x00, 0x01, 0xad, + 0x00, 0x00, 0x01, 0x08, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1d, 0x08, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, + 0x10, 0x0e, 0x01, 0x0f, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e, + 0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9, + 0xff, + 0x10, 0x0f, 0x02, 0x11, 0x11, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x29, 0x4a, 0x64, 0x7a, 0x8c, 0x9e, + 0xad, 0xba, 0xc7, 0xd3, 0xde, 0xe8, 0xf1, 0xf9, + 0xff, + 0x10, 0x0b, 0x01, 0x1c, + 0x10, 0x0d, 0x01, 0x1a, + 0x10, 0x0c, 0x01, 0x34, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x40, + 0x04, 0x06, 0x01, 0x03, + 0, 0, 0 +}; + +/* nw802 - Scope USB Microscope M2 (ProScope) (Hitachi HD49322BF) */ +static const u8 proscope_init_1[] = { + 0x04, 0x05, 0x01, 0x21, + 0x04, 0x04, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + 0x00, 0x00, 0x40, 0x10, 0x01, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x04, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x08, 0x00, 0x17, 0x00, 0xce, 0x00, 0xf4, + 0x05, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0xce, 0x00, 0xf8, 0x03, 0x3e, 0x00, 0x86, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0xb6, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xf6, 0x03, 0x34, 0x04, 0xf6, 0x03, 0x34, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xe8, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x1f, 0x0f, 0x08, 0x20, 0xa8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xad, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x1f, 0x10, 0x08, 0x0a, + 0x0a, 0x51, 0x00, 0xf1, 0x00, 0x3c, 0x00, 0xb4, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x8c, 0x04, 0x01, + 0x20, 0x02, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x2d, 0x46, 0x58, 0x67, 0x74, 0x7f, + 0x88, 0x94, 0x9d, 0xa6, 0xae, 0xb5, 0xbd, 0xc4, + 0xcb, 0xd1, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x3f, + 0x01, 0x00, 0x00, 0xef, 0x00, 0x09, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0, 0, 0 +}; +static const u8 proscope_init_qvga[] = { + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, + 0x40, + 0x10, 0x1a, 0x01, 0x06, + 0x00, 0x03, 0x02, 0xf9, 0x02, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x0e, 0x01, 0x10, + 0, 0, 0 +}; +static const u8 proscope_init_vga[] = { + 0x00, 0x03, 0x02, 0xf9, 0x02, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x16, 0x00, 0x00, 0x82, 0x84, 0x00, + 0x80, + 0x10, 0x1a, 0x01, 0x06, + 0x10, 0x00, 0x01, 0xa1, + 0x10, 0x1b, 0x02, 0x00, 0x00, + 0x10, 0x1d, 0x08, 0xc0, 0x0d, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x11, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, + 0x10, 0x0e, 0x01, 0x10, + 0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae, + 0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0, 0, 0 +}; +static const u8 proscope_init_2[] = { + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x0c, + 0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae, + 0xb9, 0xc3, 0xcc, 0xd4, 0xdd, 0xe4, 0xeb, 0xf2, + 0xf9, + 0x10, 0x0b, 0x01, 0x0b, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1b, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x05, 0x01, 0x21, + 0x04, 0x04, 0x01, 0x00, + 0, 0, 0 +}; + +/* nw800 - Divio Chicony TwinkleCam */ +static const u8 twinkle_init[] = { + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x01, 0x00, + + 0x04, 0x06, 0x01, 0x44, + 0x04, 0x06, 0x01, 0x00, + 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, + 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, + 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, + 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x08, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x10, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x00, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + + 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, +/*320 3f ef, 0x00 */ + 0x04, 0x04, 0x01, 0x10, + 0x04, 0x04, 0x01, 0x00, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, +#if 1 + I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, + I2C0, 0x40, 0x02, 0x11, 0x06, + I2C0, 0x40, 0x02, 0x14, 0x00, + I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x02, 0x07, 0x01, +#else + 0x06, 0x00, 0x0b, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, + 0x06, 0x00, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, + 0x05, 0x02, 0x02, 0x0c, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x06, + 0x06, 0x00, 0x02, 0x11, 0x06, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x14, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x07, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, +/* 320 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, */ + 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, +/* 320 0x00, 0x78, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x5c, */ + 0x40, +#if 1 + I2C0, 0x40, 0x02, 0x02, 0x0c, + I2C0, 0x40, 0x02, 0x13, 0x01, +#else + 0x06, 0x00, 0x01, 0x0c, + 0x06, 0x00, 0x02, 0x02, 0x0c, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x00, 0x01, 0x01, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0x20, 0x01, 0x60, 0x01, +/* 320 0xf0, 0x00, 0x40, 0x01, */ +#if 1 + I2C0, 0x40, 0x02, 0x05, 0x0f, + I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, + I2C0, 0x40, 0x03, 0x12, 0x00, 0x01, +#else + 0x06, 0x00, 0x01, 0x0f, + 0x06, 0x00, 0x02, 0x05, 0x0f, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x07, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, + 0x06, 0x00, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, + 0x05, 0x02, 0x02, 0x08, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x00, 0x01, + 0x06, 0x00, 0x03, 0x12, 0x00, 0x01, + 0x05, 0x02, 0x02, 0x03, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, +/* 320 3f ef */ +#if 1 + I2C0, 0x40, 0x02, 0x12, 0x00, + I2C0, 0x40, 0x02, 0x0e, 0x00, + I2C0, 0x40, 0x02, 0x11, 0x06, +#else + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x12, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x0e, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x06, + 0x06, 0x00, 0x02, 0x11, 0x06, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x0b, 0x01, 0x19, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x0d, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x41, + 0, 0, 0 +}; + +/* et31x110 DSB-C110 */ +static const u8 dsbc110_init[] = { + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, + 0x04, 0x06, 0x01, 0x04, + 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x01, 0x00, + + 0x04, 0x06, 0x01, 0x44, + 0x04, 0x06, 0x01, 0x00, + 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, + 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, + 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, + 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, + 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, + 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, + 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, + 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, + 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, + 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, + 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, + 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x08, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x10, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x00, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, + 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, + 0x01, 0x60, 0x01, 0x00, 0x00, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x04, 0x04, 0x01, 0x10, + 0x04, 0x04, 0x01, 0x00, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, +#if 1 + I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, + I2C0, 0x40, 0x02, 0x11, 0x06, + I2C0, 0x40, 0x02, 0x14, 0x00, + I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x02, 0x07, 0x01, +#else + 0x06, 0x00, 0x0b, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, + 0x06, 0x00, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0a, + 0x05, 0x02, 0x02, 0x0c, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x06, + 0x06, 0x00, 0x02, 0x11, 0x06, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x14, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x07, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xe4, + 0x40, +#if 1 + I2C0, 0x40, 0x02, 0x02, 0x0c, + I2C0, 0x40, 0x02, 0x13, 0x01, +#else + 0x06, 0x00, 0x01, 0x1c, + 0x06, 0x00, 0x02, 0x02, 0x1c, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x00, 0x01, 0x01, + 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, + 0xf0, 0x00, 0x40, 0x01, +#if 1 + I2C0, 0x40, 0x02, 0x05, 0x23, + I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x00, + I2C0, 0x40, 0x03, 0x12, 0x00, 0x01, +#else + 0x06, 0x00, 0x01, 0x24, + 0x06, 0x00, 0x02, 0x05, 0x24, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x13, 0x01, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x07, 0x06, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x00, + 0x06, 0x00, 0x08, 0x08, 0x06, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x00, + 0x05, 0x02, 0x02, 0x08, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x02, 0x00, 0x01, + 0x06, 0x00, 0x03, 0x12, 0x00, 0x01, + 0x05, 0x02, 0x02, 0x03, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, +#if 1 + I2C0, 0x40, 0x02, 0x12, 0x00, + I2C0, 0x40, 0x02, 0x0e, 0x00, + I2C0, 0x40, 0x02, 0x11, 0x06, +#else + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x12, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x00, + 0x06, 0x00, 0x02, 0x0e, 0x00, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, + 0x06, 0x00, 0x01, 0x06, + 0x06, 0x00, 0x02, 0x11, 0x06, + 0x05, 0x02, 0x02, 0x02, 0x40, + 0x05, 0x05, 0x01, 0x01, +#endif + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x0c, 0x0c, + 0x10, 0x03, 0x01, 0x06, + 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, + 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, + 0xf9, + 0x10, 0x0b, 0x01, 0x14, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1d, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x41, +}; + +/* nw802 dvc-v6 */ +static const u8 dvcv6_init[] = { + 0x04, 0x06, 0x01, 0x06, + 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, + 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, + 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, + 0x00, 0x0b, 0x00, 0x1b, 0x00, 0xc8, 0x00, 0xf4, + 0x05, 0xb4, 0x00, 0xcc, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa2, 0x00, 0xc6, 0x00, 0x60, 0x00, 0xc6, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x40, 0x40, 0x00, 0xae, 0x00, 0xd2, 0x00, 0xae, 0x00, 0xd2, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0xa8, 0x00, 0xc0, 0x00, 0x66, 0x00, 0xc0, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x0a, 0x00, 0x54, 0x00, 0x0a, 0x00, 0x54, + 0x00, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x5d, 0x00, 0xc7, 0x00, 0x7e, 0x00, 0x30, + 0x00, 0x80, 0x1f, 0x98, 0x43, 0x3f, 0x0d, 0x88, 0x20, 0x80, 0x3f, + 0x47, 0xaf, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, + 0x00, 0x0c, 0x02, 0x0c, 0x00, 0x1c, 0x00, 0x94, + 0x00, 0x10, 0x06, 0x24, 0x00, 0x4a, 0x00, + 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, + 0x40, 0x20, + 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x06, 0x00, 0x02, 0x09, 0x99, + 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x40, 0xa0, 0x02, 0x80, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x0a, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x49, 0x13, 0x00, 0x00, 0xe0, 0x00, 0x0c, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x06, + 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x10, 0x80, + 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, + 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, + 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, + 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, + 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, + 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, + 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, + 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, + 0x10, 0x80, 0x1b, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0x82, + 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, + 0x01, 0xf0, 0x00, + 0x00, 0x03, 0x02, 0x94, 0x03, + 0x00, 0x1d, 0x04, 0x0a, 0x01, 0x28, 0x07, + 0x00, 0x7b, 0x02, 0xe0, 0x00, + 0x10, 0x8d, 0x01, 0x00, + 0x00, 0x09, 0x04, 0x1e, 0x00, 0x0c, 0x02, + 0x00, 0x91, 0x02, 0x0b, 0x02, + 0x10, 0x00, 0x01, 0xaf, + 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8f, 0x3c, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xf0, + 0x40, + 0x10, 0x1a, 0x01, 0x02, + 0x10, 0x00, 0x01, 0xaf, + 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, + 0x10, 0x1b, 0x02, 0x07, 0x01, + 0x10, 0x11, 0x08, 0x61, 0x00, 0xe0, 0x00, 0x49, 0x00, 0xa8, 0x00, + 0x10, 0x1f, 0x06, 0x01, 0x20, 0x02, 0xe8, 0x03, 0x00, + 0x10, 0x1d, 0x02, 0x40, 0x06, + 0x10, 0x0e, 0x01, 0x08, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa, + 0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc, + 0xdc, + 0x10, 0x03, 0x01, 0x00, + 0x10, 0x0f, 0x02, 0x12, 0x12, + 0x10, 0x03, 0x01, 0x11, + 0x10, 0x41, 0x11, 0x00, 0x0f, 0x54, 0x6f, 0x82, 0x91, 0x9f, 0xaa, + 0xb4, 0xbd, 0xc5, 0xcd, 0xd5, 0xdb, 0xdc, 0xdc, + 0xdc, + 0x10, 0x0b, 0x01, 0x16, + 0x10, 0x0d, 0x01, 0x10, + 0x10, 0x0c, 0x01, 0x1a, + 0x04, 0x06, 0x01, 0x03, + 0x04, 0x04, 0x01, 0x00, +}; + +static const u8 *webcam_init[] = { + [Generic800] = nw800_init, + [SpaceCam] = spacecam_init, + [SpaceCam2] = spacecam2_init, + [Cvideopro] = cvideopro_init, + [Dlink350c] = dlink_init, + [DS3303u] = ds330_init, + [Kr651us] = kr651_init_1, + [Kritter] = kritter_init, + [Mustek300] = mustek_init, + [Proscope] = proscope_init_1, + [Twinkle] = twinkle_init, + [DsbC110] = dsbc110_init, + [DvcV6] = dvcv6_init, + [P35u] = nw801_init_1, + [Generic802] = nw802_init, +}; + +/* -- write a register -- */ +static void reg_w(struct gspca_dev *gspca_dev, + u16 index, + const u8 *data, + int len) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + if (len == 1) + PDEBUG(D_USBO, "SET 00 0000 %04x %02x", index, *data); + else + PDEBUG(D_USBO, "SET 00 0000 %04x %02x %02x ...", + index, *data, data[1]); + memcpy(gspca_dev->usb_buf, data, len); + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0x00, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, /* value */ + index, + gspca_dev->usb_buf, + len, + 500); + if (ret < 0) { + err("reg_w err %d", ret); + gspca_dev->usb_err = ret; + } +} + +/* -- read registers in usb_buf -- */ +static void reg_r(struct gspca_dev *gspca_dev, + u16 index, + int len) +{ + struct usb_device *dev = gspca_dev->dev; + int ret; + + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, index, + gspca_dev->usb_buf, len, 500); + if (ret < 0) { + err("reg_r err %d", ret); + gspca_dev->usb_err = ret; + return; + } + if (len == 1) + PDEBUG(D_USBI, "GET 00 0000 %04x %02x", + index, gspca_dev->usb_buf[0]); + else + PDEBUG(D_USBI, "GET 00 0000 %04x %02x %02x ..", + index, gspca_dev->usb_buf[0], + gspca_dev->usb_buf[1]); +} + +static void i2c_w(struct gspca_dev *gspca_dev, + u8 i2c_addr, + const u8 *data, + int len) +{ + u8 val[2]; + int i; + + reg_w(gspca_dev, 0x0600, data + 1, len - 1); + reg_w(gspca_dev, 0x0600, data, len); + val[0] = len; + val[1] = i2c_addr; + reg_w(gspca_dev, 0x0502, val, 2); + val[0] = 0x01; + reg_w(gspca_dev, 0x0501, val, 1); + for (i = 5; --i >= 0; ) { + msleep(4); + reg_r(gspca_dev, 0x0505, 1); + if (gspca_dev->usb_err < 0) + return; + if (gspca_dev->usb_buf[0] == 0) + return; + } + gspca_dev->usb_err = -ETIME; +} + +static void reg_w_buf(struct gspca_dev *gspca_dev, + const u8 *cmd) +{ + u16 reg; + int len; + + for (;;) { + reg = *cmd++ << 8; + reg += *cmd++; + len = *cmd++; + if (len == 0) + break; + if (cmd[-3] != I2C0) + reg_w(gspca_dev, reg, cmd, len); + else + i2c_w(gspca_dev, reg & 0xff, cmd, len); + cmd += len; + } +} + +static int swap_6bits(int v) +{ + int r, i; + + r = 0; + for (i = 0; i < 6; i++) { + r <<= 1; + if (v & 1) + r++; + v >>= 1; + } + return r; +} + +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 val, v[2]; + + val = sd->ctrls[GAIN].val >> 1; /* 0 - 63 -> 0 - 31 */ + reg_w(gspca_dev, 0x100e, &val, 1); /* AE Y gain */ + + switch (sd->webcam) { + case P35u: + /* Note the control goes from 0-255 not 0-127, but anything + above 127 just means amplifying noise */ + val = sd->ctrls[GAIN].val << 1; /* 0 - 63 -> 0 - 127 */ + reg_w(gspca_dev, 0x1026, &val, 1); + break; + case Kr651us: + /* 0 - 63 -> 0 - 0x37 */ + val = (sd->ctrls[GAIN].val * 0x37) / 63; + val = swap_6bits(val); + v[0] = val << 3; + v[1] = val >> 5; + reg_w(gspca_dev, 0x101d, v, 2); /* SIF reg0/1 (AGC) */ + break; + } +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 v[2]; + + switch (sd->webcam) { + case P35u: + v[0] = (sd->ctrls[EXPOSURE].val << 3) | 0x01; + reg_w(gspca_dev, 0x1019, v, 1); + break; + case Kr651us: + v[0] = sd->ctrls[EXPOSURE].val; + v[1] = sd->ctrls[EXPOSURE].val >> 8; + reg_w(gspca_dev, 0x101b, v, 2); + break; + } +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int w, h; + + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) + return; + if (!sd->ctrls[AUTOGAIN].val) { + sd->ag_cnt = -1; + return; + } + sd->ag_cnt = AG_CNT_START; + + reg_r(gspca_dev, 0x1004, 1); + if (gspca_dev->usb_buf[0] & 0x04) { /* if AE_FULL_FRM */ + sd->ae_res = gspca_dev->width * gspca_dev->height; + } else { /* get the AE window size */ + reg_r(gspca_dev, 0x1011, 8); + w = (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0] + - (gspca_dev->usb_buf[3] << 8) - gspca_dev->usb_buf[2]; + h = (gspca_dev->usb_buf[5] << 8) + gspca_dev->usb_buf[4] + - (gspca_dev->usb_buf[7] << 8) - gspca_dev->usb_buf[6]; + sd->ae_res = h * w; + if (sd->ae_res == 0) + sd->ae_res = gspca_dev->width * gspca_dev->height; + } +} + +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if ((unsigned) webcam >= NWEBCAMS) + webcam = 0; + sd->webcam = webcam; + gspca_dev->cam.reverse_alts = 1; + gspca_dev->cam.ctrls = sd->ctrls; + sd->ag_cnt = -1; + return 0; +} + +static int nw802_test_reg(struct gspca_dev *gspca_dev, + u16 index, + u8 value) +{ + /* write the value */ + reg_w(gspca_dev, index, &value, 1); + + /* read it */ + reg_r(gspca_dev, index, 1); + + return gspca_dev->usb_buf[0] == value; +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + /* + * Autodetect sequence inspired from some log. + * We try to detect what registers exist or not. + * If 0x0500 does not exist => NW802 + * If it does, test 0x109b. If it doesn't exist, + * then it's a NW801. Else, a NW800 + */ + if (!nw802_test_reg(gspca_dev, 0x0500, 0x55)) { + sd->bridge = BRIDGE_NW802; + if (sd->webcam == Generic800) + sd->webcam = Generic802; + } else if (!nw802_test_reg(gspca_dev, 0x109b, 0xaa)) { + sd->bridge = BRIDGE_NW801; + if (sd->webcam == Generic800) + sd->webcam = P35u; + } + PDEBUG(D_PROBE, "Bridge nw80%d", sd->bridge); + + if (sd->bridge == BRIDGE_NW800) { + gspca_dev->cam.cam_mode = sif_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(sif_mode); + } else { + gspca_dev->cam.cam_mode = vga_mode; + switch (sd->webcam) { + case Generic802: + case Kr651us: + case Proscope: + case P35u: + gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); + break; + default: + gspca_dev->cam.nmodes = 1; /* qvga only */ + break; + } + } + switch (sd->webcam) { + case P35u: +/* sd->ctrls[EXPOSURE].min = 0; + * sd->ctrls[EXPOSURE].max = 9; + * sd->ctrls[EXPOSURE].def = 1; */ + break; + case Kr651us: +/* sd->ctrls[EXPOSURE].min = 0; */ + sd->ctrls[EXPOSURE].max = 315; + sd->ctrls[EXPOSURE].def = 150; + break; + default: + gspca_dev->ctrl_dis = ~(1 << GAIN); + break; + } + + return gspca_dev->usb_err; +} + +/* -- start the camera -- */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + const u8 *cmd; + + cmd = webcam_init[sd->webcam]; + reg_w_buf(gspca_dev, cmd); + switch (sd->webcam) { + case P35u: + if (gspca_dev->width == 320) + reg_w_buf(gspca_dev, nw801_init_qvga); + else + reg_w_buf(gspca_dev, nw801_init_vga); + reg_w_buf(gspca_dev, nw801_init_2); + break; + case Kr651us: + if (gspca_dev->width == 320) + reg_w_buf(gspca_dev, kr651_init_qvga); + else + reg_w_buf(gspca_dev, kr651_init_vga); + reg_w_buf(gspca_dev, kr651_init_2); + break; + case Proscope: + if (gspca_dev->width == 320) + reg_w_buf(gspca_dev, proscope_init_qvga); + else + reg_w_buf(gspca_dev, proscope_init_vga); + reg_w_buf(gspca_dev, proscope_init_2); + break; + } + + setgain(gspca_dev); + setexposure(gspca_dev); + setautogain(gspca_dev); + return gspca_dev->usb_err; +} + +static void sd_stopN(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + u8 value; + + /* 'go' off */ + if (sd->bridge != BRIDGE_NW801) { + value = 0x02; + reg_w(gspca_dev, 0x0406, &value, 1); + } + + /* LED off */ + switch (sd->webcam) { + case Cvideopro: + case Kr651us: + case DvcV6: + case Kritter: + value = 0xff; + break; + case Dlink350c: + value = 0x21; + break; + case SpaceCam: + case SpaceCam2: + case Proscope: + case Twinkle: + value = 0x01; + break; + default: + return; + } + reg_w(gspca_dev, 0x0404, &value, 1); +} + +static void sd_pkt_scan(struct gspca_dev *gspca_dev, + u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + /* + * frame header = '00 00 hh ww ss xx ff ff' + * with: + * - 'hh': height / 4 + * - 'ww': width / 4 + * - 'ss': frame sequence number c0..dd + */ + if (data[0] == 0x00 && data[1] == 0x00 + && data[6] == 0xff && data[7] == 0xff) { + gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); + gspca_frame_add(gspca_dev, FIRST_PACKET, data + 8, len - 8); + } else { + gspca_frame_add(gspca_dev, INTER_PACKET, data, len); + } +} + +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AUTOGAIN].val = val; + if (val) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); + else + gspca_dev->ctrl_inac = 0; + if (gspca_dev->streaming) + setautogain(gspca_dev); + return gspca_dev->usb_err; +} + +static void do_autogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int luma; + int gain, shutter; + + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; + + /* get the average luma */ + reg_r(gspca_dev, sd->bridge == BRIDGE_NW801 ? 0x080d : 0x080c, 4); + luma = (gspca_dev->usb_buf[3] << 24) + (gspca_dev->usb_buf[2] << 16) + + (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; + luma /= sd->ae_res; + + if (sd->webcam == P35u) { + u8 clock; + + if (luma > 92 && luma < 108) + return; /* fine */ + clock = sd->ctrls[EXPOSURE].val; + gain = sd->ctrls[GAIN].val; + if (luma < 100) { + if (luma < 70 && clock > 0) + clock--; + if (gain > 98 && clock > 0) + clock--; + if (gain <= 50) + gain += 3; + } else { + if (luma > 150 && clock < 9) + clock++; + if (gain < 12 && clock < 9) + clock++; + if (gain >= 5) + gain -= 3; + } + if (gain != sd->ctrls[GAIN].val) { + sd->ctrls[GAIN].val = gain; + setgain(gspca_dev); + } + if (clock != sd->ctrls[EXPOSURE].val) { + sd->ctrls[EXPOSURE].val = clock; + setexposure(gspca_dev); + } + return; + } + + /* kr651us */ + if (luma > 95 && luma < 105) + return; /* fine */ + gain = sd->ctrls[GAIN].val; + shutter = sd->ctrls[EXPOSURE].val; + if (luma < 100) { + if (shutter > 0) { + if (luma < 85 && shutter > 50) + shutter -= 50; + else + shutter--; + } else if (gain < 63) { + if (luma < 85 && gain < 53) + gain += 10; + else + gain++; + } + } else { + if (gain > 0) { + if (luma > 115 && gain > 10) + gain -= 10; + else + gain--; + } else if (shutter < 316) { /* max 0x13b */ + if (luma > 115 && shutter < 266) + shutter += 50; + else + shutter++; + } + } + if (gain != sd->ctrls[GAIN].val) { + sd->ctrls[GAIN].val = gain; + setgain(gspca_dev); + } + if (shutter != sd->ctrls[EXPOSURE].val) { + sd->ctrls[EXPOSURE].val = shutter; + setexposure(gspca_dev); + } +} + +/* V4L2 controls supported by the driver */ +static const struct ctrl sd_ctrls[NCTRLS] = { +[GAIN] = { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 63, + .step = 1, + .default_value = 16 + }, + .set_control = setgain + }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, + .maximum = 9, + .step = 1, + .default_value = 1 + }, + .set_control = setexposure + }, +[AUTOGAIN] = { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + .flags = V4L2_CTRL_FLAG_UPDATE + }, + .set = sd_setautogain + }, +}; + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .ctrls = sd_ctrls, + .nctrls = ARRAY_SIZE(sd_ctrls), + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +}; + +/* -- module initialisation -- */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE(0x046d, 0xd001)}, + {USB_DEVICE(0x0502, 0xd001)}, + {USB_DEVICE(0x052b, 0xd001)}, + {USB_DEVICE(0x055f, 0xd001)}, + {USB_DEVICE(0x06a5, 0x0000)}, + {USB_DEVICE(0x06a5, 0xd001)}, + {USB_DEVICE(0x06a5, 0xd800)}, + {USB_DEVICE(0x06be, 0xd001)}, + {USB_DEVICE(0x0728, 0xd001)}, + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + return usb_register(&sd_driver); +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(webcam, int, 0644); +MODULE_PARM_DESC(webcam, + "Webcam type\n" + "0: generic\n" + "1: Trust 120 SpaceCam\n" + "2: other Trust 120 SpaceCam\n" + "3: Conceptronic Video Pro\n" + "4: D-link dru-350c\n" + "5: Plustek Opticam 500U\n" + "6: Panasonic GP-KR651US\n" + "7: iRez Kritter\n" + "8: Mustek Wcam 300 mini\n" + "9: Scalar USB Microscope M2 (Proscope)\n" + "10: Divio Chicony TwinkleCam\n" + "11: DSB-C110\n" + "12: DVC-V6\n"); -- cgit v1.2.2 From c1e13971b19324305b35fafc080b527465214d3c Mon Sep 17 00:00:00 2001 From: Ian Armstrong Date: Fri, 18 Mar 2011 19:23:05 -0300 Subject: [media] af9015: enhance RC Patch from Ian Armstrong. I've encountered a couple of problems with the current af9015 driver as supplied with the 2.6.37 kernel, that the attached patch appears to fix. (I've generated this patch against the current v4l-dvb git). Some key-presses are lost. A key-press is only generated upon 'valid' data (buf[14] == (u8) ~buf[15]), but the buffer is wiped before this check. Sometimes the 15th byte has not been set at the time of read, so the data isn't valid & ignored. On the next poll the 15th byte has been set, but the rest of the data was wiped previously, so the data is still invalid & the key is lost. Weird repeat error, where an old key press is sometimes repeated in error. ie. button sequence '1 (pause) 2 (pause) 3 (pause) 4' generates output like '1 (pause) 2 (pause) 23 (pause) 4'. The current driver zeroes the data for the key pushed, but sometimes this data is already zero but with other bytes set suggesting a repeat code. This results in the last key being incorrectly repeated. This patch attempts to reduce the risk of a missed key-press & also stop the random repeat of an old key-press when a new key is pressed. Signed-off-by: Ian Armstrong Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 39 +++++++++++++++++++++++++++----------- drivers/media/dvb/dvb-usb/af9015.h | 1 + 2 files changed, 29 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 8671ca362c81..6457d042b1a0 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -479,6 +479,9 @@ static int af9015_init_endpoint(struct dvb_usb_device *d) ret = af9015_set_reg_bit(d, 0xd50b, 0); else ret = af9015_clear_reg_bit(d, 0xd50b, 0); + if (ret) + goto error; + ret = af9015_write_reg(d, 0x98e9, 0xff); error: if (ret) err("endpoint init failed:%d", ret); @@ -1016,22 +1019,35 @@ static int af9015_rc_query(struct dvb_usb_device *d) { struct af9015_state *priv = d->priv; int ret; - u8 buf[16]; + u8 buf[17]; /* read registers needed to detect remote controller code */ ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf)); if (ret) goto error; - if (buf[14] || buf[15]) { + /* If any of these are non-zero, assume invalid data */ + if (buf[1] || buf[2] || buf[3]) + return ret; + + /* Check for repeat of previous code */ + if ((priv->rc_repeat != buf[6] || buf[0]) && + !memcmp(&buf[12], priv->rc_last, 4)) { + deb_rc("%s: key repeated\n", __func__); + rc_keydown(d->rc_dev, priv->rc_keycode, 0); + priv->rc_repeat = buf[6]; + return ret; + } + + /* Only process key if canary killed */ + if (buf[16] != 0xff && buf[0] != 0x01) { + /* Reset the canary */ + af9015_write_reg(d, 0x98e9, 0xff); deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__, buf[12], buf[13], buf[14], buf[15]); - /* clean IR code from mem */ - ret = af9015_write_regs(d, 0x98e5, "\x00\x00\x00\x00", 4); - if (ret) - goto error; - + /* Remember this key */ + memcpy(priv->rc_last, &buf[12], 4); if (buf[14] == (u8) ~buf[15]) { if (buf[12] == (u8) ~buf[13]) { /* NEC */ @@ -1041,15 +1057,16 @@ static int af9015_rc_query(struct dvb_usb_device *d) priv->rc_keycode = buf[12] << 16 | buf[13] << 8 | buf[14]; } - rc_keydown(d->rc_dev, priv->rc_keycode, 0); } else { - priv->rc_keycode = 0; /* clear just for sure */ + priv->rc_keycode = buf[12] << 24 | buf[13] << 16 | + buf[14] << 8 | buf[15]; } - } else if (priv->rc_repeat != buf[6] || buf[0]) { - deb_rc("%s: key repeated\n", __func__); rc_keydown(d->rc_dev, priv->rc_keycode, 0); } else { deb_rc("%s: no key press\n", __func__); + /* Invalidate last keypress */ + /* Not really needed, but helps with debug */ + priv->rc_last[2] = priv->rc_last[3]; } priv->rc_repeat = buf[6]; diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h index f20cfa6ed690..beb3004f00ba 100644 --- a/drivers/media/dvb/dvb-usb/af9015.h +++ b/drivers/media/dvb/dvb-usb/af9015.h @@ -102,6 +102,7 @@ struct af9015_state { struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */ u8 rc_repeat; u32 rc_keycode; + u8 rc_last[4]; }; struct af9015_config { -- cgit v1.2.2 From 1e8750c2ac2bcbf2b084d3fa77cbb5eef33b3e7f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 18 Mar 2011 19:36:42 -0300 Subject: [media] af9015: small RC change Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 6457d042b1a0..da2f87efe071 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -479,9 +479,7 @@ static int af9015_init_endpoint(struct dvb_usb_device *d) ret = af9015_set_reg_bit(d, 0xd50b, 0); else ret = af9015_clear_reg_bit(d, 0xd50b, 0); - if (ret) - goto error; - ret = af9015_write_reg(d, 0x98e9, 0xff); + error: if (ret) err("endpoint init failed:%d", ret); @@ -614,6 +612,11 @@ static int af9015_init(struct dvb_usb_device *d) int ret; deb_info("%s:\n", __func__); + /* init RC canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + ret = af9015_init_endpoint(d); if (ret) goto error; @@ -1041,11 +1044,14 @@ static int af9015_rc_query(struct dvb_usb_device *d) /* Only process key if canary killed */ if (buf[16] != 0xff && buf[0] != 0x01) { - /* Reset the canary */ - af9015_write_reg(d, 0x98e9, 0xff); deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__, buf[12], buf[13], buf[14], buf[15]); + /* Reset the canary */ + ret = af9015_write_reg(d, 0x98e9, 0xff); + if (ret) + goto error; + /* Remember this key */ memcpy(priv->rc_last, &buf[12], 4); if (buf[14] == (u8) ~buf[15]) { @@ -1058,6 +1064,7 @@ static int af9015_rc_query(struct dvb_usb_device *d) buf[13] << 8 | buf[14]; } } else { + /* 32 bit NEC */ priv->rc_keycode = buf[12] << 24 | buf[13] << 16 | buf[14] << 8 | buf[15]; } -- cgit v1.2.2 From 638b53f80ceb5a57b5c9b6c4a078f605a8cc2d71 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 19 Mar 2011 14:11:55 -0300 Subject: [media] add TerraTec remote Remote used for TerraTec Cinergy T Stick RC. Keytable from Martin Groszhauser Signed-off-by: Antti Palosaari Cc: Martin Groszhauser Cc: TerraTux Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-terratec-slim-2.c | 72 +++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-terratec-slim-2.c (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index f0c80559b303..cb721216571c 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-technisat-usb2.o \ rc-terratec-cinergy-xs.o \ rc-terratec-slim.o \ + rc-terratec-slim-2.o \ rc-tevii-nec.o \ rc-total-media-in-hand.o \ rc-trekstor.o \ diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c new file mode 100644 index 000000000000..44093918cf03 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c @@ -0,0 +1,72 @@ +/* + * TerraTec remote controller keytable + * + * Copyright (C) 2011 Martin Groszhauser + * Copyright (C) 2011 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +/* + * TerraTec slim remote, 6 rows, 3 columns. + * Keytable from Martin Groszhauser + */ +static struct rc_map_table terratec_slim_2[] = { + { 0x8001, KEY_MUTE }, /* MUTE */ + { 0x8002, KEY_VOLUMEDOWN }, + { 0x8003, KEY_CHANNELDOWN }, + { 0x8004, KEY_1 }, + { 0x8005, KEY_2 }, + { 0x8006, KEY_3 }, + { 0x8007, KEY_4 }, + { 0x8008, KEY_5 }, + { 0x8009, KEY_6 }, + { 0x800a, KEY_7 }, + { 0x800c, KEY_ZOOM }, /* [fullscreen] */ + { 0x800d, KEY_0 }, + { 0x800e, KEY_AGAIN }, /* [two arrows forming a circle] */ + { 0x8012, KEY_POWER2 }, /* [red power button] */ + { 0x801a, KEY_VOLUMEUP }, + { 0x801b, KEY_8 }, + { 0x801e, KEY_CHANNELUP }, + { 0x801f, KEY_9 }, +}; + +static struct rc_map_list terratec_slim_2_map = { + .map = { + .scan = terratec_slim_2, + .size = ARRAY_SIZE(terratec_slim_2), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_TERRATEC_SLIM_2, + } +}; + +static int __init init_rc_map_terratec_slim_2(void) +{ + return rc_map_register(&terratec_slim_2_map); +} + +static void __exit exit_rc_map_terratec_slim_2(void) +{ + rc_map_unregister(&terratec_slim_2_map); +} + +module_init(init_rc_map_terratec_slim_2) +module_exit(exit_rc_map_terratec_slim_2) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); -- cgit v1.2.2 From 04599c2b1ff1eece19b7abaacd97266b8a6b79f2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 19 Mar 2011 14:25:36 -0300 Subject: [media] af9015: map remote for TerraTec Cinergy T Stick RC Map rc-terratec-slim-2 for TerraTec Cinergy T Stick RC device. Signed-off-by: Antti Palosaari Cc: Martin Groszhauser Cc: TerraTux Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index da2f87efe071..0bbc91f50381 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -744,6 +744,8 @@ static const struct af9015_rc_setup af9015_rc_setup_hashes[] = { }; static const struct af9015_rc_setup af9015_rc_setup_usbids[] = { + { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_RC, + RC_MAP_TERRATEC_SLIM_2 }, { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, RC_MAP_TERRATEC_SLIM }, { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700, -- cgit v1.2.2 From 582e565caeaccf145e2256b84d4fde827fede72e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 19 Mar 2011 16:51:43 -0300 Subject: [media] af9015: reimplement firmware download Split FW download packages smarter way and bug free. Implementation is based of Andrea Merello's example he provided for tda18218 driver. Count remaining FW bytes down in loop instead of division and modulo combination used earlier. Thanks-to: Andrea Merello Signed-off-by: Antti Palosaari Cc: Andrea Merello Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9015.c | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index 0bbc91f50381..100ebc37e99e 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -665,9 +665,8 @@ error: static int af9015_download_firmware(struct usb_device *udev, const struct firmware *fw) { - int i, len, packets, remainder, ret; + int i, len, remaining, ret; struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL}; - u16 addr = 0x5100; /* firmware start address */ u16 checksum = 0; deb_info("%s:\n", __func__); @@ -679,24 +678,20 @@ static int af9015_download_firmware(struct usb_device *udev, af9015_config.firmware_size = fw->size; af9015_config.firmware_checksum = checksum; - #define FW_PACKET_MAX_DATA 55 - - packets = fw->size / FW_PACKET_MAX_DATA; - remainder = fw->size % FW_PACKET_MAX_DATA; - len = FW_PACKET_MAX_DATA; - for (i = 0; i <= packets; i++) { - if (i == packets) /* set size of the last packet */ - len = remainder; + #define FW_ADDR 0x5100 /* firmware start address */ + #define LEN_MAX 55 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; req.data_len = len; - req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); - req.addr = addr; - addr += FW_PACKET_MAX_DATA; + req.data = (u8 *) &fw->data[fw->size - remaining]; + req.addr = FW_ADDR + fw->size - remaining; ret = af9015_rw_udev(udev, &req); if (ret) { - err("firmware download failed at packet %d with " \ - "code %d", i, ret); + err("firmware download failed:%d", ret); goto error; } } -- cgit v1.2.2 From 109a29900a36b2b1e7b7f83a561c6af7e343461f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 19 Mar 2011 17:18:18 -0300 Subject: [media] af9013: download FW earlier in attach() Quick test shows that FW must be running before other checks so make it happen earlier. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/af9013.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index ba25fa0b0fc2..6f50f0673994 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -1466,20 +1466,6 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config, state->i2c = i2c; memcpy(&state->config, config, sizeof(struct af9013_config)); - /* chip version */ - ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); - if (ret) - goto error; - - /* ROM version */ - for (i = 0; i < 2; i++) { - ret = af9013_read_reg(state, 0x116b + i, &buf[i]); - if (ret) - goto error; - } - deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, - buf[2], buf[0], buf[1]); - /* download firmware */ if (state->config.output_mode != AF9013_OUTPUT_MODE_USB) { ret = af9013_download_firmware(state); @@ -1495,6 +1481,20 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config, } info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); + /* chip version */ + ret = af9013_read_reg_bits(state, 0xd733, 4, 4, &buf[2]); + if (ret) + goto error; + + /* ROM version */ + for (i = 0; i < 2; i++) { + ret = af9013_read_reg(state, 0x116b + i, &buf[i]); + if (ret) + goto error; + } + deb_info("%s: chip version:%d ROM version:%d.%d\n", __func__, + buf[2], buf[0], buf[1]); + /* settings for mp2if */ if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) { /* AF9015 split PSB to 1.5k + 0.5k */ -- cgit v1.2.2 From 6ed9d56086acb3bb4ec003ff6d2f54313774d72b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 19 Mar 2011 18:02:22 -0300 Subject: [media] af9013: reimplement firmware download Split FW download packages smarter way and bug free. Implementation is based of Andrea Merello's example he provided for tda18218 driver. Count remaining FW bytes down in loop instead of division and modulo combination used earlier. Thanks to: Andrea Merello Signed-off-by: Antti Palosaari Cc: Andrea Merello Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/af9013.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c index 6f50f0673994..345311c33383 100644 --- a/drivers/media/dvb/frontends/af9013.c +++ b/drivers/media/dvb/frontends/af9013.c @@ -1323,13 +1323,11 @@ static struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) { - int i, len, packets, remainder, ret; + int i, len, remaining, ret; const struct firmware *fw; - u16 addr = 0x5100; /* firmware start address */ u16 checksum = 0; u8 val; u8 fw_params[4]; - u8 *data; u8 *fw_file = AF9013_DEFAULT_FIRMWARE; msleep(100); @@ -1373,21 +1371,18 @@ static int af9013_download_firmware(struct af9013_state *state) if (ret) goto error_release; - #define FW_PACKET_MAX_DATA 16 - - packets = fw->size / FW_PACKET_MAX_DATA; - remainder = fw->size % FW_PACKET_MAX_DATA; - len = FW_PACKET_MAX_DATA; - for (i = 0; i <= packets; i++) { - if (i == packets) /* set size of the last packet */ - len = remainder; - - data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA); - ret = af9013_write_ofsm_regs(state, addr, data, len); - addr += FW_PACKET_MAX_DATA; + #define FW_ADDR 0x5100 /* firmware start address */ + #define LEN_MAX 16 /* max packet size */ + for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { + len = remaining; + if (len > LEN_MAX) + len = LEN_MAX; + ret = af9013_write_ofsm_regs(state, + FW_ADDR + fw->size - remaining, + (u8 *) &fw->data[fw->size - remaining], len); if (ret) { - err("firmware download failed at %d with %d", i, ret); + err("firmware download failed:%d", ret); goto error_release; } } -- cgit v1.2.2 From 950720840f392075b19d902e5ca7806a17a562cb Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Sun, 13 Mar 2011 15:23:32 -0300 Subject: [media] Update Pawel Osciak's e-mail address Signed-off-by: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/mem2mem_testdev.c | 4 ++-- drivers/media/video/v4l2-mem2mem.c | 4 ++-- drivers/media/video/videobuf2-core.c | 4 ++-- drivers/media/video/videobuf2-dma-contig.c | 4 ++-- drivers/media/video/videobuf2-memops.c | 4 ++-- drivers/media/video/videobuf2-vmalloc.c | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c index e1f96ea45bcb..b03d74e09a3c 100644 --- a/drivers/media/video/mem2mem_testdev.c +++ b/drivers/media/video/mem2mem_testdev.c @@ -8,7 +8,7 @@ * operation (via the mem2mem framework). * * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * Pawel Osciak, + * Pawel Osciak, * Marek Szyprowski, * * This program is free software; you can redistribute it and/or modify @@ -33,7 +33,7 @@ #define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev" MODULE_DESCRIPTION("Virtual device for mem2mem framework testing"); -MODULE_AUTHOR("Pawel Osciak, "); +MODULE_AUTHOR("Pawel Osciak, "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/video/v4l2-mem2mem.c index a78e5c9be1a2..3b15bf5892a8 100644 --- a/drivers/media/video/v4l2-mem2mem.c +++ b/drivers/media/video/v4l2-mem2mem.c @@ -5,7 +5,7 @@ * source and destination. * * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * Pawel Osciak, + * Pawel Osciak, * Marek Szyprowski, * * This program is free software; you can redistribute it and/or modify @@ -21,7 +21,7 @@ #include MODULE_DESCRIPTION("Mem to mem device framework for videobuf"); -MODULE_AUTHOR("Pawel Osciak, "); +MODULE_AUTHOR("Pawel Osciak, "); MODULE_LICENSE("GPL"); static bool debug; diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 3e9b67bd55b9..ce032255f3ee 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Samsung Electronics * - * Author: Pawel Osciak + * Author: Pawel Osciak * Marek Szyprowski * * This program is free software; you can redistribute it and/or modify @@ -1810,5 +1810,5 @@ size_t vb2_write(struct vb2_queue *q, char __user *data, size_t count, EXPORT_SYMBOL_GPL(vb2_write); MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2"); -MODULE_AUTHOR("Pawel Osciak, Marek Szyprowski"); +MODULE_AUTHOR("Pawel Osciak , Marek Szyprowski"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c index bb6a5602cf94..90495b7b4ddf 100644 --- a/drivers/media/video/videobuf2-dma-contig.c +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Samsung Electronics * - * Author: Pawel Osciak + * Author: Pawel Osciak * * 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 @@ -181,5 +181,5 @@ void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); -MODULE_AUTHOR("Pawel Osciak"); +MODULE_AUTHOR("Pawel Osciak "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/videobuf2-memops.c b/drivers/media/video/videobuf2-memops.c index a3eb6567dea5..5370a3a7ee25 100644 --- a/drivers/media/video/videobuf2-memops.c +++ b/drivers/media/video/videobuf2-memops.c @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Samsung Electronics * - * Author: Pawel Osciak + * Author: Pawel Osciak * Marek Szyprowski * * This program is free software; you can redistribute it and/or modify @@ -231,5 +231,5 @@ const struct vm_operations_struct vb2_common_vm_ops = { EXPORT_SYMBOL_GPL(vb2_common_vm_ops); MODULE_DESCRIPTION("common memory handling routines for videobuf2"); -MODULE_AUTHOR("Pawel Osciak"); +MODULE_AUTHOR("Pawel Osciak "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/videobuf2-vmalloc.c b/drivers/media/video/videobuf2-vmalloc.c index b5e6936fb628..a3a884234059 100644 --- a/drivers/media/video/videobuf2-vmalloc.c +++ b/drivers/media/video/videobuf2-vmalloc.c @@ -3,7 +3,7 @@ * * Copyright (C) 2010 Samsung Electronics * - * Author: Pawel Osciak + * Author: Pawel Osciak * * 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 @@ -128,5 +128,5 @@ const struct vb2_mem_ops vb2_vmalloc_memops = { EXPORT_SYMBOL_GPL(vb2_vmalloc_memops); MODULE_DESCRIPTION("vmalloc memory handling routines for videobuf2"); -MODULE_AUTHOR("Pawel Osciak"); +MODULE_AUTHOR("Pawel Osciak "); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 4ffabdb35ad59fdb8cb6ad3ff4733694ff0dfc35 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Sun, 20 Mar 2011 18:17:34 -0300 Subject: [media] vb2: vb2_poll() fix return values for file I/O mode poll() should be returning poll-specific error values, not E* errors. Signed-off-by: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index ce032255f3ee..8c6f04bc4d89 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -1364,18 +1364,18 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) struct vb2_buffer *vb = NULL; /* - * Start file io emulator if streaming api has not been used yet. + * Start file I/O emulator only if streaming API has not been used yet. */ if (q->num_buffers == 0 && q->fileio == NULL) { if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) { ret = __vb2_init_fileio(q, 1); if (ret) - return ret; + return POLLERR; } if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) { ret = __vb2_init_fileio(q, 0); if (ret) - return ret; + return POLLERR; /* * Write to OUTPUT queue can be done immediately. */ -- cgit v1.2.2 From 5db2c3ba4de8489a7a064bac463bb8af2c7a1ae4 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Sun, 20 Mar 2011 19:26:41 -0300 Subject: [media] vb2: Handle return value from start_streaming callback Fix vb2 not handling return value from start_streaming() callback. Signed-off-by: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 8c6f04bc4d89..6698c77e0f64 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -1111,6 +1111,7 @@ EXPORT_SYMBOL_GPL(vb2_dqbuf); int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) { struct vb2_buffer *vb; + int ret; if (q->fileio) { dprintk(1, "streamon: file io in progress\n"); @@ -1138,12 +1139,16 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type) } } - q->streaming = 1; - /* * Let driver notice that streaming state has been enabled. */ - call_qop(q, start_streaming, q); + ret = call_qop(q, start_streaming, q); + if (ret) { + dprintk(1, "streamon: driver refused to start streaming\n"); + return ret; + } + + q->streaming = 1; /* * If any buffers were queued before streamon, -- cgit v1.2.2 From 3c0f3c605b2572c740f66ea39fe2d125399b20aa Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Fri, 18 Mar 2011 03:53:58 +0000 Subject: NET: smsc95xx: don't use stack for async writes to the device The set_multicast operation performs asynchronous writes to the device, with some addresses pointing to the stack. Bad things may happen, and this is trapped CONFIG_DMA_API_DEBUG: [ 5.237762] WARNING: at /build/buildd/linux-linaro-omap-2.6.38/lib/dma-debug.c:867 check_for_stack+0xd4/0x100() [ 5.237792] ehci-omap ehci-omap.0: DMA-API: device driver maps memory fromstack [addr=d9c77dec] [ 5.237792] Modules linked in: smsc95xx(+) usbnet twl6030_usb twl4030_pwrbutton leds_gpio omap_wdt omap2_mcspi [ 5.237854] [] (unwind_backtrace+0x0/0xf8) from [] (warn_slowpath_common+0x54/0x64) [ 5.237884] [] (warn_slowpath_common+0x54/0x64) from [] (warn_slowpath_fmt+0x30/0x40) [ 5.237915] [] (warn_slowpath_fmt+0x30/0x40) from [] (check_for_stack+0xd4/0x100) [ 5.237915] [] (check_for_stack+0xd4/0x100) from [] (debug_dma_map_page+0xb4/0xdc) [ 5.237976] [] (debug_dma_map_page+0xb4/0xdc) from [] (map_urb_for_dma+0x26c/0x304) [ 5.237976] [] (map_urb_for_dma+0x26c/0x304) from [] (usb_hcd_submit_urb+0x78/0x19c) [ 5.238037] [] (usb_hcd_submit_urb+0x78/0x19c) from [] (smsc95xx_write_reg_async+0xb4/0x130 [smsc95xx]) [ 5.238067] [] (smsc95xx_write_reg_async+0xb4/0x130 [smsc95xx]) from [] (smsc95xx_set_multicast+0xfc/0x148 [smsc95xx]) [ 5.238098] [] (smsc95xx_set_multicast+0xfc/0x148 [smsc95xx]) from [] (smsc95xx_reset+0x2f8/0x68c [smsc95xx]) [ 5.238128] [] (smsc95xx_reset+0x2f8/0x68c [smsc95xx]) from [] (smsc95xx_bind+0xcc/0x188 [smsc95xx]) [ 5.238159] [] (smsc95xx_bind+0xcc/0x188 [smsc95xx]) from [] (usbnet_probe+0x204/0x4c4 [usbnet]) [ 5.238220] [] (usbnet_probe+0x204/0x4c4 [usbnet]) from [] (usb_probe_interface+0xe4/0x1c4) [ 5.238250] [] (usb_probe_interface+0xe4/0x1c4) from [] (really_probe+0x64/0x160) [ 5.238250] [] (really_probe+0x64/0x160) from [] (driver_probe_device+0x48/0x60) [ 5.238281] [] (driver_probe_device+0x48/0x60) from [] (__driver_attach+0x8c/0x90) [ 5.238311] [] (__driver_attach+0x8c/0x90) from [] (bus_for_each_dev+0x50/0x7c) [ 5.238311] [] (bus_for_each_dev+0x50/0x7c) from [] (bus_add_driver+0x190/0x250) [ 5.238311] [] (bus_add_driver+0x190/0x250) from [] (driver_register+0x78/0x13c) [ 5.238433] [] (driver_register+0x78/0x13c) from [] (usb_register_driver+0x78/0x13c) [ 5.238464] [] (usb_register_driver+0x78/0x13c) from [] (do_one_initcall+0x34/0x188) [ 5.238494] [] (do_one_initcall+0x34/0x188) from [] (sys_init_module+0xb0/0x1c0) [ 5.238525] [] (sys_init_module+0xb0/0x1c0) from [] (ret_fast_syscall+0x0/0x30) Move the two offenders to the private structure which is kmalloc-ed, and thus safe. Signed-off-by: Marc Zyngier Cc: Steve Glendinning Signed-off-by: David S. Miller --- drivers/net/usb/smsc95xx.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index bc86f4b6ecc2..727874d9deb6 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -49,6 +49,8 @@ struct smsc95xx_priv { u32 mac_cr; + u32 hash_hi; + u32 hash_lo; spinlock_t mac_cr_lock; bool use_tx_csum; bool use_rx_csum; @@ -370,10 +372,11 @@ static void smsc95xx_set_multicast(struct net_device *netdev) { struct usbnet *dev = netdev_priv(netdev); struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); - u32 hash_hi = 0; - u32 hash_lo = 0; unsigned long flags; + pdata->hash_hi = 0; + pdata->hash_lo = 0; + spin_lock_irqsave(&pdata->mac_cr_lock, flags); if (dev->net->flags & IFF_PROMISC) { @@ -394,13 +397,13 @@ static void smsc95xx_set_multicast(struct net_device *netdev) u32 bitnum = smsc95xx_hash(ha->addr); u32 mask = 0x01 << (bitnum & 0x1F); if (bitnum & 0x20) - hash_hi |= mask; + pdata->hash_hi |= mask; else - hash_lo |= mask; + pdata->hash_lo |= mask; } netif_dbg(dev, drv, dev->net, "HASHH=0x%08X, HASHL=0x%08X\n", - hash_hi, hash_lo); + pdata->hash_hi, pdata->hash_lo); } else { netif_dbg(dev, drv, dev->net, "receive own packets only\n"); pdata->mac_cr &= @@ -410,8 +413,8 @@ static void smsc95xx_set_multicast(struct net_device *netdev) spin_unlock_irqrestore(&pdata->mac_cr_lock, flags); /* Initiate async writes, as we can't wait for completion here */ - smsc95xx_write_reg_async(dev, HASHH, &hash_hi); - smsc95xx_write_reg_async(dev, HASHL, &hash_lo); + smsc95xx_write_reg_async(dev, HASHH, &pdata->hash_hi); + smsc95xx_write_reg_async(dev, HASHL, &pdata->hash_lo); smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); } -- cgit v1.2.2 From bf5f0019046d596d613caf74722ba4994e153899 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Mon, 24 Jan 2011 09:57:20 +0000 Subject: video, sm501: add I/O functions for use on powerpc - add read/write functions for using this driver also on powerpc plattforms Signed-off-by: Heiko Schocher cc: linux-fbdev@vger.kernel.org cc: devicetree-discuss@ozlabs.org cc: Ben Dooks cc: Vincent Sanders cc: Samuel Ortiz cc: linux-kernel@vger.kernel.org cc: Randy Dunlap cc: Paul Mundt Acked-by: Samuel Ortiz Signed-off-by: Paul Mundt --- drivers/mfd/sm501.c | 125 ++++++++++++++++++----------------- drivers/video/sm501fb.c | 172 +++++++++++++++++++++++++----------------------- 2 files changed, 153 insertions(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 5de3a760ea1e..558d5f3f6d02 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -133,10 +133,10 @@ static unsigned long decode_div(unsigned long pll2, unsigned long val, static void sm501_dump_clk(struct sm501_devdata *sm) { - unsigned long misct = readl(sm->regs + SM501_MISC_TIMING); - unsigned long pm0 = readl(sm->regs + SM501_POWER_MODE_0_CLOCK); - unsigned long pm1 = readl(sm->regs + SM501_POWER_MODE_1_CLOCK); - unsigned long pmc = readl(sm->regs + SM501_POWER_MODE_CONTROL); + unsigned long misct = smc501_readl(sm->regs + SM501_MISC_TIMING); + unsigned long pm0 = smc501_readl(sm->regs + SM501_POWER_MODE_0_CLOCK); + unsigned long pm1 = smc501_readl(sm->regs + SM501_POWER_MODE_1_CLOCK); + unsigned long pmc = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); unsigned long sdclk0, sdclk1; unsigned long pll2 = 0; @@ -193,29 +193,29 @@ static void sm501_dump_regs(struct sm501_devdata *sm) void __iomem *regs = sm->regs; dev_info(sm->dev, "System Control %08x\n", - readl(regs + SM501_SYSTEM_CONTROL)); + smc501_readl(regs + SM501_SYSTEM_CONTROL)); dev_info(sm->dev, "Misc Control %08x\n", - readl(regs + SM501_MISC_CONTROL)); + smc501_readl(regs + SM501_MISC_CONTROL)); dev_info(sm->dev, "GPIO Control Low %08x\n", - readl(regs + SM501_GPIO31_0_CONTROL)); + smc501_readl(regs + SM501_GPIO31_0_CONTROL)); dev_info(sm->dev, "GPIO Control Hi %08x\n", - readl(regs + SM501_GPIO63_32_CONTROL)); + smc501_readl(regs + SM501_GPIO63_32_CONTROL)); dev_info(sm->dev, "DRAM Control %08x\n", - readl(regs + SM501_DRAM_CONTROL)); + smc501_readl(regs + SM501_DRAM_CONTROL)); dev_info(sm->dev, "Arbitration Ctrl %08x\n", - readl(regs + SM501_ARBTRTN_CONTROL)); + smc501_readl(regs + SM501_ARBTRTN_CONTROL)); dev_info(sm->dev, "Misc Timing %08x\n", - readl(regs + SM501_MISC_TIMING)); + smc501_readl(regs + SM501_MISC_TIMING)); } static void sm501_dump_gate(struct sm501_devdata *sm) { dev_info(sm->dev, "CurrentGate %08x\n", - readl(sm->regs + SM501_CURRENT_GATE)); + smc501_readl(sm->regs + SM501_CURRENT_GATE)); dev_info(sm->dev, "CurrentClock %08x\n", - readl(sm->regs + SM501_CURRENT_CLOCK)); + smc501_readl(sm->regs + SM501_CURRENT_CLOCK)); dev_info(sm->dev, "PowerModeControl %08x\n", - readl(sm->regs + SM501_POWER_MODE_CONTROL)); + smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL)); } #else @@ -231,7 +231,7 @@ static inline void sm501_dump_clk(struct sm501_devdata *sm) { } static void sm501_sync_regs(struct sm501_devdata *sm) { - readl(sm->regs); + smc501_readl(sm->regs); } static inline void sm501_mdelay(struct sm501_devdata *sm, unsigned int delay) @@ -261,11 +261,11 @@ int sm501_misc_control(struct device *dev, spin_lock_irqsave(&sm->reg_lock, save); - misc = readl(sm->regs + SM501_MISC_CONTROL); + misc = smc501_readl(sm->regs + SM501_MISC_CONTROL); to = (misc & ~clear) | set; if (to != misc) { - writel(to, sm->regs + SM501_MISC_CONTROL); + smc501_writel(to, sm->regs + SM501_MISC_CONTROL); sm501_sync_regs(sm); dev_dbg(sm->dev, "MISC_CONTROL %08lx\n", misc); @@ -294,11 +294,11 @@ unsigned long sm501_modify_reg(struct device *dev, spin_lock_irqsave(&sm->reg_lock, save); - data = readl(sm->regs + reg); + data = smc501_readl(sm->regs + reg); data |= set; data &= ~clear; - writel(data, sm->regs + reg); + smc501_writel(data, sm->regs + reg); sm501_sync_regs(sm); spin_unlock_irqrestore(&sm->reg_lock, save); @@ -322,9 +322,9 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) mutex_lock(&sm->clock_lock); - mode = readl(sm->regs + SM501_POWER_MODE_CONTROL); - gate = readl(sm->regs + SM501_CURRENT_GATE); - clock = readl(sm->regs + SM501_CURRENT_CLOCK); + mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); + gate = smc501_readl(sm->regs + SM501_CURRENT_GATE); + clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); mode &= 3; /* get current power mode */ @@ -356,14 +356,14 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) switch (mode) { case 1: - writel(gate, sm->regs + SM501_POWER_MODE_0_GATE); - writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); + smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE); + smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); mode = 0; break; case 2: case 0: - writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); - writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); + smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); + smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); mode = 1; break; @@ -372,7 +372,7 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) goto already; } - writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); + smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); sm501_sync_regs(sm); dev_dbg(sm->dev, "gate %08lx, clock %08lx, mode %08lx\n", @@ -519,9 +519,9 @@ unsigned long sm501_set_clock(struct device *dev, unsigned long req_freq) { struct sm501_devdata *sm = dev_get_drvdata(dev); - unsigned long mode = readl(sm->regs + SM501_POWER_MODE_CONTROL); - unsigned long gate = readl(sm->regs + SM501_CURRENT_GATE); - unsigned long clock = readl(sm->regs + SM501_CURRENT_CLOCK); + unsigned long mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); + unsigned long gate = smc501_readl(sm->regs + SM501_CURRENT_GATE); + unsigned long clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); unsigned char reg; unsigned int pll_reg = 0; unsigned long sm501_freq; /* the actual frequency achieved */ @@ -592,9 +592,9 @@ unsigned long sm501_set_clock(struct device *dev, mutex_lock(&sm->clock_lock); - mode = readl(sm->regs + SM501_POWER_MODE_CONTROL); - gate = readl(sm->regs + SM501_CURRENT_GATE); - clock = readl(sm->regs + SM501_CURRENT_CLOCK); + mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); + gate = smc501_readl(sm->regs + SM501_CURRENT_GATE); + clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); clock = clock & ~(0xFF << clksrc); clock |= reg<regs + SM501_POWER_MODE_0_GATE); - writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); + smc501_writel(gate, sm->regs + SM501_POWER_MODE_0_GATE); + smc501_writel(clock, sm->regs + SM501_POWER_MODE_0_CLOCK); mode = 0; break; case 2: case 0: - writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); - writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); + smc501_writel(gate, sm->regs + SM501_POWER_MODE_1_GATE); + smc501_writel(clock, sm->regs + SM501_POWER_MODE_1_CLOCK); mode = 1; break; @@ -619,10 +619,11 @@ unsigned long sm501_set_clock(struct device *dev, return -1; } - writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); + smc501_writel(mode, sm->regs + SM501_POWER_MODE_CONTROL); if (pll_reg) - writel(pll_reg, sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL); + smc501_writel(pll_reg, + sm->regs + SM501_PROGRAMMABLE_PLL_CONTROL); sm501_sync_regs(sm); @@ -902,7 +903,7 @@ static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset) struct sm501_gpio_chip *smgpio = to_sm501_gpio(chip); unsigned long result; - result = readl(smgpio->regbase + SM501_GPIO_DATA_LOW); + result = smc501_readl(smgpio->regbase + SM501_GPIO_DATA_LOW); result >>= offset; return result & 1UL; @@ -915,13 +916,13 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip, /* check and modify if this pin is not set as gpio. */ - if (readl(smchip->control) & bit) { + if (smc501_readl(smchip->control) & bit) { dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev, "changing mode of gpio, bit %08lx\n", bit); - ctrl = readl(smchip->control); + ctrl = smc501_readl(smchip->control); ctrl &= ~bit; - writel(ctrl, smchip->control); + smc501_writel(ctrl, smchip->control); sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio)); } @@ -942,10 +943,10 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) spin_lock_irqsave(&smgpio->lock, save); - val = readl(regs + SM501_GPIO_DATA_LOW) & ~bit; + val = smc501_readl(regs + SM501_GPIO_DATA_LOW) & ~bit; if (value) val |= bit; - writel(val, regs); + smc501_writel(val, regs); sm501_sync_regs(sm501_gpio_to_dev(smgpio)); sm501_gpio_ensure_gpio(smchip, bit); @@ -967,8 +968,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) spin_lock_irqsave(&smgpio->lock, save); - ddr = readl(regs + SM501_GPIO_DDR_LOW); - writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW); + ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW); + smc501_writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW); sm501_sync_regs(sm501_gpio_to_dev(smgpio)); sm501_gpio_ensure_gpio(smchip, bit); @@ -994,18 +995,18 @@ static int sm501_gpio_output(struct gpio_chip *chip, spin_lock_irqsave(&smgpio->lock, save); - val = readl(regs + SM501_GPIO_DATA_LOW); + val = smc501_readl(regs + SM501_GPIO_DATA_LOW); if (value) val |= bit; else val &= ~bit; - writel(val, regs); + smc501_writel(val, regs); - ddr = readl(regs + SM501_GPIO_DDR_LOW); - writel(ddr | bit, regs + SM501_GPIO_DDR_LOW); + ddr = smc501_readl(regs + SM501_GPIO_DDR_LOW); + smc501_writel(ddr | bit, regs + SM501_GPIO_DDR_LOW); sm501_sync_regs(sm501_gpio_to_dev(smgpio)); - writel(val, regs + SM501_GPIO_DATA_LOW); + smc501_writel(val, regs + SM501_GPIO_DATA_LOW); sm501_sync_regs(sm501_gpio_to_dev(smgpio)); spin_unlock_irqrestore(&smgpio->lock, save); @@ -1231,7 +1232,7 @@ static ssize_t sm501_dbg_regs(struct device *dev, for (reg = 0x00; reg < 0x70; reg += 4) { ret = sprintf(ptr, "%08x = %08x\n", - reg, readl(sm->regs + reg)); + reg, smc501_readl(sm->regs + reg)); ptr += ret; } @@ -1255,10 +1256,10 @@ static inline void sm501_init_reg(struct sm501_devdata *sm, { unsigned long tmp; - tmp = readl(sm->regs + reg); + tmp = smc501_readl(sm->regs + reg); tmp &= ~r->mask; tmp |= r->set; - writel(tmp, sm->regs + reg); + smc501_writel(tmp, sm->regs + reg); } /* sm501_init_regs @@ -1299,7 +1300,7 @@ static void sm501_init_regs(struct sm501_devdata *sm, static int sm501_check_clocks(struct sm501_devdata *sm) { - unsigned long pwrmode = readl(sm->regs + SM501_CURRENT_CLOCK); + unsigned long pwrmode = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); unsigned long msrc = (pwrmode & SM501_POWERMODE_M_SRC); unsigned long m1src = (pwrmode & SM501_POWERMODE_M1_SRC); @@ -1334,7 +1335,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm) INIT_LIST_HEAD(&sm->devices); - devid = readl(sm->regs + SM501_DEVICEID); + devid = smc501_readl(sm->regs + SM501_DEVICEID); if ((devid & SM501_DEVICEID_IDMASK) != SM501_DEVICEID_SM501) { dev_err(sm->dev, "incorrect device id %08lx\n", devid); @@ -1342,9 +1343,9 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm) } /* disable irqs */ - writel(0, sm->regs + SM501_IRQ_MASK); + smc501_writel(0, sm->regs + SM501_IRQ_MASK); - dramctrl = readl(sm->regs + SM501_DRAM_CONTROL); + dramctrl = smc501_readl(sm->regs + SM501_DRAM_CONTROL); mem_avail = sm501_mem_local[(dramctrl >> 13) & 0x7]; dev_info(sm->dev, "SM501 At %p: Version %08lx, %ld Mb, IRQ %d\n", @@ -1489,7 +1490,7 @@ static int sm501_plat_suspend(struct platform_device *pdev, pm_message_t state) struct sm501_devdata *sm = platform_get_drvdata(pdev); sm->in_suspend = 1; - sm->pm_misc = readl(sm->regs + SM501_MISC_CONTROL); + sm->pm_misc = smc501_readl(sm->regs + SM501_MISC_CONTROL); sm501_dump_regs(sm); @@ -1513,9 +1514,9 @@ static int sm501_plat_resume(struct platform_device *pdev) /* check to see if we are in the same state as when suspended */ - if (readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) { + if (smc501_readl(sm->regs + SM501_MISC_CONTROL) != sm->pm_misc) { dev_info(sm->dev, "SM501_MISC_CONTROL changed over sleep\n"); - writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL); + smc501_writel(sm->pm_misc, sm->regs + SM501_MISC_CONTROL); /* our suspend causes the controller state to change, * either by something attempting setup, power loss, diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index bcb44a594ebc..5df406c87c50 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -117,7 +117,7 @@ static inline int v_total(struct fb_var_screeninfo *var) static inline void sm501fb_sync_regs(struct sm501fb_info *info) { - readl(info->regs); + smc501_readl(info->regs); } /* sm501_alloc_mem @@ -262,7 +262,7 @@ static void sm501fb_setup_gamma(struct sm501fb_info *fbi, /* set gamma values */ for (offset = 0; offset < 256 * 4; offset += 4) { - writel(value, fbi->regs + palette + offset); + smc501_writel(value, fbi->regs + palette + offset); value += 0x010101; /* Advance RGB by 1,1,1.*/ } } @@ -476,7 +476,8 @@ static int sm501fb_set_par_common(struct fb_info *info, /* set start of framebuffer to the screen */ - writel(par->screen.sm_addr | SM501_ADDR_FLIP, fbi->regs + head_addr); + smc501_writel(par->screen.sm_addr | SM501_ADDR_FLIP, + fbi->regs + head_addr); /* program CRT clock */ @@ -519,7 +520,7 @@ static void sm501fb_set_par_geometry(struct fb_info *info, reg = info->fix.line_length; reg |= ((var->xres * var->bits_per_pixel)/8) << 16; - writel(reg, fbi->regs + (par->head == HEAD_CRT ? + smc501_writel(reg, fbi->regs + (par->head == HEAD_CRT ? SM501_DC_CRT_FB_OFFSET : SM501_DC_PANEL_FB_OFFSET)); /* program horizontal total */ @@ -527,27 +528,27 @@ static void sm501fb_set_par_geometry(struct fb_info *info, reg = (h_total(var) - 1) << 16; reg |= (var->xres - 1); - writel(reg, base + SM501_OFF_DC_H_TOT); + smc501_writel(reg, base + SM501_OFF_DC_H_TOT); /* program horizontal sync */ reg = var->hsync_len << 16; reg |= var->xres + var->right_margin - 1; - writel(reg, base + SM501_OFF_DC_H_SYNC); + smc501_writel(reg, base + SM501_OFF_DC_H_SYNC); /* program vertical total */ reg = (v_total(var) - 1) << 16; reg |= (var->yres - 1); - writel(reg, base + SM501_OFF_DC_V_TOT); + smc501_writel(reg, base + SM501_OFF_DC_V_TOT); /* program vertical sync */ reg = var->vsync_len << 16; reg |= var->yres + var->lower_margin - 1; - writel(reg, base + SM501_OFF_DC_V_SYNC); + smc501_writel(reg, base + SM501_OFF_DC_V_SYNC); } /* sm501fb_pan_crt @@ -566,15 +567,15 @@ static int sm501fb_pan_crt(struct fb_var_screeninfo *var, xoffs = var->xoffset * bytes_pixel; - reg = readl(fbi->regs + SM501_DC_CRT_CONTROL); + reg = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL); reg &= ~SM501_DC_CRT_CONTROL_PIXEL_MASK; reg |= ((xoffs & 15) / bytes_pixel) << 4; - writel(reg, fbi->regs + SM501_DC_CRT_CONTROL); + smc501_writel(reg, fbi->regs + SM501_DC_CRT_CONTROL); reg = (par->screen.sm_addr + xoffs + var->yoffset * info->fix.line_length); - writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR); + smc501_writel(reg | SM501_ADDR_FLIP, fbi->regs + SM501_DC_CRT_FB_ADDR); sm501fb_sync_regs(fbi); return 0; @@ -593,10 +594,10 @@ static int sm501fb_pan_pnl(struct fb_var_screeninfo *var, unsigned long reg; reg = var->xoffset | (var->xres_virtual << 16); - writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH); + smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH); reg = var->yoffset | (var->yres_virtual << 16); - writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT); + smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT); sm501fb_sync_regs(fbi); return 0; @@ -622,7 +623,7 @@ static int sm501fb_set_par_crt(struct fb_info *info) /* enable CRT DAC - note 0 is on!*/ sm501_misc_control(fbi->dev->parent, 0, SM501_MISC_DAC_POWER); - control = readl(fbi->regs + SM501_DC_CRT_CONTROL); + control = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL); control &= (SM501_DC_CRT_CONTROL_PIXEL_MASK | SM501_DC_CRT_CONTROL_GAMMA | @@ -684,7 +685,7 @@ static int sm501fb_set_par_crt(struct fb_info *info) out_update: dev_dbg(fbi->dev, "new control is %08lx\n", control); - writel(control, fbi->regs + SM501_DC_CRT_CONTROL); + smc501_writel(control, fbi->regs + SM501_DC_CRT_CONTROL); sm501fb_sync_regs(fbi); return 0; @@ -696,18 +697,18 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL; struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl; - control = readl(ctrl_reg); + control = smc501_readl(ctrl_reg); if (to && (control & SM501_DC_PANEL_CONTROL_VDD) == 0) { /* enable panel power */ control |= SM501_DC_PANEL_CONTROL_VDD; /* FPVDDEN */ - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); control |= SM501_DC_PANEL_CONTROL_DATA; /* DATA */ - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); @@ -719,7 +720,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) else control |= SM501_DC_PANEL_CONTROL_BIAS; - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); } @@ -730,7 +731,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) else control |= SM501_DC_PANEL_CONTROL_FPEN; - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); } @@ -742,7 +743,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) else control &= ~SM501_DC_PANEL_CONTROL_FPEN; - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); } @@ -753,18 +754,18 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) else control &= ~SM501_DC_PANEL_CONTROL_BIAS; - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); } control &= ~SM501_DC_PANEL_CONTROL_DATA; - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); control &= ~SM501_DC_PANEL_CONTROL_VDD; - writel(control, ctrl_reg); + smc501_writel(control, ctrl_reg); sm501fb_sync_regs(fbi); mdelay(10); } @@ -799,7 +800,7 @@ static int sm501fb_set_par_pnl(struct fb_info *info) /* update control register */ - control = readl(fbi->regs + SM501_DC_PANEL_CONTROL); + control = smc501_readl(fbi->regs + SM501_DC_PANEL_CONTROL); control &= (SM501_DC_PANEL_CONTROL_GAMMA | SM501_DC_PANEL_CONTROL_VDD | SM501_DC_PANEL_CONTROL_DATA | @@ -833,16 +834,16 @@ static int sm501fb_set_par_pnl(struct fb_info *info) BUG(); } - writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL); + smc501_writel(0x0, fbi->regs + SM501_DC_PANEL_PANNING_CONTROL); /* panel plane top left and bottom right location */ - writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC); + smc501_writel(0x00, fbi->regs + SM501_DC_PANEL_TL_LOC); reg = var->xres - 1; reg |= (var->yres - 1) << 16; - writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC); + smc501_writel(reg, fbi->regs + SM501_DC_PANEL_BR_LOC); /* program panel control register */ @@ -855,7 +856,7 @@ static int sm501fb_set_par_pnl(struct fb_info *info) if ((var->sync & FB_SYNC_VERT_HIGH_ACT) == 0) control |= SM501_DC_PANEL_CONTROL_VSP; - writel(control, fbi->regs + SM501_DC_PANEL_CONTROL); + smc501_writel(control, fbi->regs + SM501_DC_PANEL_CONTROL); sm501fb_sync_regs(fbi); /* ensure the panel interface is not tristated at this point */ @@ -924,7 +925,7 @@ static int sm501fb_setcolreg(unsigned regno, val |= (green >> 8) << 8; val |= blue >> 8; - writel(val, base + (regno * 4)); + smc501_writel(val, base + (regno * 4)); } break; @@ -980,7 +981,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info) dev_dbg(fbi->dev, "%s(mode=%d, %p)\n", __func__, blank_mode, info); - ctrl = readl(fbi->regs + SM501_DC_CRT_CONTROL); + ctrl = smc501_readl(fbi->regs + SM501_DC_CRT_CONTROL); switch (blank_mode) { case FB_BLANK_POWERDOWN: @@ -1004,7 +1005,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info) } - writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL); + smc501_writel(ctrl, fbi->regs + SM501_DC_CRT_CONTROL); sm501fb_sync_regs(fbi); return 0; @@ -1041,12 +1042,14 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor) if (cursor->image.depth > 1) return -EINVAL; - hwc_addr = readl(base + SM501_OFF_HWC_ADDR); + hwc_addr = smc501_readl(base + SM501_OFF_HWC_ADDR); if (cursor->enable) - writel(hwc_addr | SM501_HWC_EN, base + SM501_OFF_HWC_ADDR); + smc501_writel(hwc_addr | SM501_HWC_EN, + base + SM501_OFF_HWC_ADDR); else - writel(hwc_addr & ~SM501_HWC_EN, base + SM501_OFF_HWC_ADDR); + smc501_writel(hwc_addr & ~SM501_HWC_EN, + base + SM501_OFF_HWC_ADDR); /* set data */ if (cursor->set & FB_CUR_SETPOS) { @@ -1060,7 +1063,7 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor) //y += cursor->image.height; - writel(x | (y << 16), base + SM501_OFF_HWC_LOC); + smc501_writel(x | (y << 16), base + SM501_OFF_HWC_LOC); } if (cursor->set & FB_CUR_SETCMAP) { @@ -1080,8 +1083,8 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor) dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg); - writel(bg, base + SM501_OFF_HWC_COLOR_1_2); - writel(fg, base + SM501_OFF_HWC_COLOR_3); + smc501_writel(bg, base + SM501_OFF_HWC_COLOR_1_2); + smc501_writel(fg, base + SM501_OFF_HWC_COLOR_3); } if (cursor->set & FB_CUR_SETSIZE || @@ -1102,7 +1105,7 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor) __func__, cursor->image.width, cursor->image.height); for (op = 0; op < (64*64*2)/8; op+=4) - writel(0x0, dst + op); + smc501_writel(0x0, dst + op); for (y = 0; y < cursor->image.height; y++) { for (x = 0; x < cursor->image.width; x++) { @@ -1141,7 +1144,7 @@ static ssize_t sm501fb_crtsrc_show(struct device *dev, struct sm501fb_info *info = dev_get_drvdata(dev); unsigned long ctrl; - ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); + ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); ctrl &= SM501_DC_CRT_CONTROL_SEL; return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel"); @@ -1172,7 +1175,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev, dev_info(dev, "setting crt source to head %d\n", head); - ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); + ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); if (head == HEAD_CRT) { ctrl |= SM501_DC_CRT_CONTROL_SEL; @@ -1184,7 +1187,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev, ctrl &= ~SM501_DC_CRT_CONTROL_TE; } - writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); + smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); sm501fb_sync_regs(info); return len; @@ -1205,7 +1208,8 @@ static int sm501fb_show_regs(struct sm501fb_info *info, char *ptr, unsigned int reg; for (reg = start; reg < (len + start); reg += 4) - ptr += sprintf(ptr, "%08x = %08x\n", reg, readl(mem + reg)); + ptr += sprintf(ptr, "%08x = %08x\n", reg, + smc501_readl(mem + reg)); return ptr - buf; } @@ -1257,7 +1261,7 @@ static int sm501fb_sync(struct fb_info *info) /* wait for the 2d engine to be ready */ while ((count > 0) && - (readl(fbi->regs + SM501_SYSTEM_CONTROL) & + (smc501_readl(fbi->regs + SM501_SYSTEM_CONTROL) & SM501_SYSCTRL_2D_ENGINE_STATUS) != 0) count--; @@ -1312,45 +1316,46 @@ static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *are return; /* set the base addresses */ - writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); - writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); + smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); + smc501_writel(par->screen.sm_addr, + fbi->regs2d + SM501_2D_DESTINATION_BASE); /* set the window width */ - writel((info->var.xres << 16) | info->var.xres, + smc501_writel((info->var.xres << 16) | info->var.xres, fbi->regs2d + SM501_2D_WINDOW_WIDTH); /* set window stride */ - writel((info->var.xres_virtual << 16) | info->var.xres_virtual, + smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual, fbi->regs2d + SM501_2D_PITCH); /* set data format */ switch (info->var.bits_per_pixel) { case 8: - writel(0, fbi->regs2d + SM501_2D_STRETCH); + smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH); break; case 16: - writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); + smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); break; case 32: - writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); + smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); break; } /* 2d compare mask */ - writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); + smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); /* 2d mask */ - writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); + smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); /* source and destination x y */ - writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE); - writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION); + smc501_writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE); + smc501_writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION); /* w/h */ - writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); + smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); /* do area move */ - writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL); + smc501_writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL); } static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) @@ -1372,47 +1377,49 @@ static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rec return; /* set the base addresses */ - writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); - writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE); + smc501_writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE); + smc501_writel(par->screen.sm_addr, + fbi->regs2d + SM501_2D_DESTINATION_BASE); /* set the window width */ - writel((info->var.xres << 16) | info->var.xres, + smc501_writel((info->var.xres << 16) | info->var.xres, fbi->regs2d + SM501_2D_WINDOW_WIDTH); /* set window stride */ - writel((info->var.xres_virtual << 16) | info->var.xres_virtual, + smc501_writel((info->var.xres_virtual << 16) | info->var.xres_virtual, fbi->regs2d + SM501_2D_PITCH); /* set data format */ switch (info->var.bits_per_pixel) { case 8: - writel(0, fbi->regs2d + SM501_2D_STRETCH); + smc501_writel(0, fbi->regs2d + SM501_2D_STRETCH); break; case 16: - writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); + smc501_writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH); break; case 32: - writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); + smc501_writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH); break; } /* 2d compare mask */ - writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); + smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK); /* 2d mask */ - writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); + smc501_writel(0xffffffff, fbi->regs2d + SM501_2D_MASK); /* colour */ - writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND); + smc501_writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND); /* x y */ - writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION); + smc501_writel((rect->dx << 16) | rect->dy, + fbi->regs2d + SM501_2D_DESTINATION); /* w/h */ - writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); + smc501_writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION); /* do rectangle fill */ - writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL); + smc501_writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL); } @@ -1470,11 +1477,12 @@ static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) /* initialise the colour registers */ - writel(par->cursor.sm_addr, par->cursor_regs + SM501_OFF_HWC_ADDR); + smc501_writel(par->cursor.sm_addr, + par->cursor_regs + SM501_OFF_HWC_ADDR); - writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC); - writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2); - writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3); + smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_LOC); + smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_1_2); + smc501_writel(0x00, par->cursor_regs + SM501_OFF_HWC_COLOR_3); sm501fb_sync_regs(info); return 0; @@ -1581,7 +1589,7 @@ static int sm501fb_start(struct sm501fb_info *info, /* clear palette ram - undefined at power on */ for (k = 0; k < (256 * 3); k++) - writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4)); + smc501_writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4)); /* enable display controller */ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); @@ -1649,20 +1657,20 @@ static int sm501fb_init_fb(struct fb_info *fb, switch (head) { case HEAD_CRT: pd = info->pdata->fb_crt; - ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); + ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); enable = (ctrl & SM501_DC_CRT_CONTROL_ENABLE) ? 1 : 0; /* ensure we set the correct source register */ if (info->pdata->fb_route != SM501_FB_CRT_PANEL) { ctrl |= SM501_DC_CRT_CONTROL_SEL; - writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); + smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); } break; case HEAD_PANEL: pd = info->pdata->fb_pnl; - ctrl = readl(info->regs + SM501_DC_PANEL_CONTROL); + ctrl = smc501_readl(info->regs + SM501_DC_PANEL_CONTROL); enable = (ctrl & SM501_DC_PANEL_CONTROL_EN) ? 1 : 0; break; @@ -1680,7 +1688,7 @@ static int sm501fb_init_fb(struct fb_info *fb, if (head == HEAD_CRT && info->pdata->fb_route == SM501_FB_CRT_PANEL) { ctrl &= ~SM501_DC_CRT_CONTROL_SEL; - writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); + smc501_writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); enable = 0; } @@ -2085,7 +2093,7 @@ static int sm501fb_suspend(struct platform_device *pdev, pm_message_t state) struct sm501fb_info *info = platform_get_drvdata(pdev); /* store crt control to resume with */ - info->pm_crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); + info->pm_crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); sm501fb_suspend_fb(info, HEAD_CRT); sm501fb_suspend_fb(info, HEAD_PANEL); @@ -2109,10 +2117,10 @@ static int sm501fb_resume(struct platform_device *pdev) /* restore the items we want to be saved for crt control */ - crt_ctrl = readl(info->regs + SM501_DC_CRT_CONTROL); + crt_ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); crt_ctrl &= ~SM501_CRT_CTRL_SAVE; crt_ctrl |= info->pm_crt_ctrl & SM501_CRT_CTRL_SAVE; - writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL); + smc501_writel(crt_ctrl, info->regs + SM501_DC_CRT_CONTROL); sm501fb_resume_fb(info, HEAD_CRT); sm501fb_resume_fb(info, HEAD_PANEL); -- cgit v1.2.2 From e6a049807105decf5aa7f0c510f5e5ec96c3548e Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Wed, 26 Jan 2011 07:21:22 +0000 Subject: video, sm501: add edid and commandline support - add commandline options: sm501fb.mode: Specify resolution as "x[-][@]" sm501fb.bpp: Specify bit-per-pixel if not specified mode - Add support for encoding display mode information in the device tree using verbatim EDID block. If the "edid" entry in the "smi,sm501" node is present, the driver will build mode database using EDID data and allow setting the display modes from this database. Signed-off-by: Heiko Schocher cc: linux-fbdev@vger.kernel.org cc: devicetree-discuss@ozlabs.org cc: Ben Dooks cc: Vincent Sanders cc: Samuel Ortiz cc: linux-kernel@vger.kernel.org cc: Randy Dunlap cc: Paul Mundt Signed-off-by: Paul Mundt --- drivers/video/sm501fb.c | 65 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 5df406c87c50..f31252ce8892 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -41,6 +41,26 @@ #include #include +#include "edid.h" + +static char *fb_mode = "640x480-16@60"; +static unsigned long default_bpp = 16; + +static struct fb_videomode __devinitdata sm501_default_mode = { + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 20833, + .left_margin = 142, + .right_margin = 13, + .upper_margin = 21, + .lower_margin = 1, + .hsync_len = 69, + .vsync_len = 3, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED +}; + #define NR_PALETTE 256 enum sm501_controller { @@ -77,6 +97,7 @@ struct sm501fb_info { void __iomem *regs2d; /* 2d remapped registers */ void __iomem *fbmem; /* remapped framebuffer */ size_t fbmem_len; /* length of remapped region */ + u8 *edid_data; }; /* per-framebuffer private data */ @@ -1725,9 +1746,16 @@ static int sm501fb_init_fb(struct fb_info *fb, fb->var.vmode = FB_VMODE_NONINTERLACED; fb->var.bits_per_pixel = 16; + if (info->edid_data) { + /* Now build modedb from EDID */ + fb_edid_to_monspecs(info->edid_data, &fb->monspecs); + fb_videomode_to_modelist(fb->monspecs.modedb, + fb->monspecs.modedb_len, + &fb->modelist); + } + if (enable && (pd->flags & SM501FB_FLAG_USE_INIT_MODE) && 0) { /* TODO read the mode from the current display */ - } else { if (pd->def_mode) { dev_info(info->dev, "using supplied mode\n"); @@ -1737,12 +1765,34 @@ static int sm501fb_init_fb(struct fb_info *fb, fb->var.xres_virtual = fb->var.xres; fb->var.yres_virtual = fb->var.yres; } else { - ret = fb_find_mode(&fb->var, fb, + if (info->edid_data) + ret = fb_find_mode(&fb->var, fb, fb_mode, + fb->monspecs.modedb, + fb->monspecs.modedb_len, + &sm501_default_mode, default_bpp); + else + ret = fb_find_mode(&fb->var, fb, NULL, NULL, 0, NULL, 8); - if (ret == 0 || ret == 4) { - dev_err(info->dev, - "failed to get initial mode\n"); + switch (ret) { + case 1: + dev_info(info->dev, "using mode specified in " + "@mode\n"); + break; + case 2: + dev_info(info->dev, "using mode specified in " + "@mode with ignored refresh rate\n"); + break; + case 3: + dev_info(info->dev, "using mode default " + "mode\n"); + break; + case 4: + dev_info(info->dev, "using mode from list\n"); + break; + default: + dev_info(info->dev, "ret = %d\n", ret); + dev_info(info->dev, "failed to find mode\n"); return -EINVAL; } } @@ -2157,6 +2207,11 @@ static void __exit sm501fb_cleanup(void) module_init(sm501fb_init); module_exit(sm501fb_cleanup); +module_param_named(mode, fb_mode, charp, 0); +MODULE_PARM_DESC(mode, + "Specify resolution as \"x[-][@]\" "); +module_param_named(bpp, default_bpp, ulong, 0); +MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); MODULE_AUTHOR("Ben Dooks, Vincent Sanders"); MODULE_DESCRIPTION("SM501 Framebuffer driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 4295f9bf74a885da390abc49a3b42a011c1bb890 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Wed, 26 Jan 2011 07:21:30 +0000 Subject: video, sm501: add OF binding to support SM501 - add binding to OF, compatible name "smi,sm501" Signed-off-by: Heiko Schocher cc: linux-fbdev@vger.kernel.org cc: devicetree-discuss@ozlabs.org cc: Ben Dooks cc: Vincent Sanders cc: Samuel Ortiz cc: linux-kernel@vger.kernel.org cc: Randy Dunlap cc: Paul Mundt Signed-off-by: Paul Mundt --- drivers/mfd/sm501.c | 9 ++++++++- drivers/video/sm501fb.c | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 47 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 558d5f3f6d02..df3702c1756d 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1377,7 +1377,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm) sm501_register_gpio(sm); } - if (pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { + if (pdata && pdata->gpio_i2c != NULL && pdata->gpio_i2c_nr > 0) { if (!sm501_gpio_isregistered(sm)) dev_err(sm->dev, "no gpio available for i2c gpio.\n"); else @@ -1422,6 +1422,7 @@ static int __devinit sm501_plat_probe(struct platform_device *dev) sm->io_res = platform_get_resource(dev, IORESOURCE_MEM, 1); sm->mem_res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (sm->io_res == NULL || sm->mem_res == NULL) { dev_err(&dev->dev, "failed to get IO resource\n"); ret = -ENOENT; @@ -1735,10 +1736,16 @@ static struct pci_driver sm501_pci_driver = { MODULE_ALIAS("platform:sm501"); +static struct of_device_id __devinitdata of_sm501_match_tbl[] = { + { .compatible = "smi,sm501", }, + { /* end */ } +}; + static struct platform_driver sm501_plat_driver = { .driver = { .name = "sm501", .owner = THIS_MODULE, + .of_match_table = of_sm501_match_tbl, }, .probe = sm501_plat_probe, .remove = sm501_plat_remove, diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index f31252ce8892..46d1a64fe80d 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -1729,6 +1729,15 @@ static int sm501fb_init_fb(struct fb_info *fb, FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; +#if defined(CONFIG_OF) +#ifdef __BIG_ENDIAN + if (of_get_property(info->dev->parent->of_node, "little-endian", NULL)) + fb->flags |= FBINFO_FOREIGN_ENDIAN; +#else + if (of_get_property(info->dev->parent->of_node, "big-endian", NULL)) + fb->flags |= FBINFO_FOREIGN_ENDIAN; +#endif +#endif /* fixed data */ fb->fix.type = FB_TYPE_PACKED_PIXELS; @@ -1765,14 +1774,17 @@ static int sm501fb_init_fb(struct fb_info *fb, fb->var.xres_virtual = fb->var.xres; fb->var.yres_virtual = fb->var.yres; } else { - if (info->edid_data) + if (info->edid_data) { ret = fb_find_mode(&fb->var, fb, fb_mode, fb->monspecs.modedb, fb->monspecs.modedb_len, &sm501_default_mode, default_bpp); - else + /* edid_data is no longer needed, free it */ + kfree(info->edid_data); + } else { ret = fb_find_mode(&fb->var, fb, NULL, NULL, 0, NULL, 8); + } switch (ret) { case 1: @@ -1933,8 +1945,32 @@ static int __devinit sm501fb_probe(struct platform_device *pdev) } if (info->pdata == NULL) { - dev_info(dev, "using default configuration data\n"); + int found = 0; +#if defined(CONFIG_OF) + struct device_node *np = pdev->dev.parent->of_node; + const u8 *prop; + const char *cp; + int len; + info->pdata = &sm501fb_def_pdata; + if (np) { + /* Get EDID */ + cp = of_get_property(np, "mode", &len); + if (cp) + strcpy(fb_mode, cp); + prop = of_get_property(np, "edid", &len); + if (prop && len == EDID_LENGTH) { + info->edid_data = kmemdup(prop, EDID_LENGTH, + GFP_KERNEL); + if (info->edid_data) + found = 1; + } + } +#endif + if (!found) { + dev_info(dev, "using default configuration data\n"); + info->pdata = &sm501fb_def_pdata; + } } /* probe for the presence of each panel */ -- cgit v1.2.2 From 32b98bf8752c5483481f77d48934aba26c967fcd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 21 Dec 2010 01:41:17 +0000 Subject: fbcon: fix situation where fbcon gets deinitialised and can't reinit. Situation as follow: 2 GPUs + vesafb + kms. GPU 1 is primary, vesafb binds to it as fb0 radeon loads GPU 0 loads as fb1 GPU 1 loads, vesafb gets kicked off which causes fb0 to unbind console, which causes the dummy console to rebind. this means fbcon_deinit gets called, which calls fbcon_exit since the console isn't bound anymore and we set fbcon_has_exited. GPU 1 creates a new fb0 which is primary and we want to be console. fbcon_fb_registered gets called sets the primary up and calls set_con2fb_map, however as fbcon_has_exited is set nothing further ever happens. This patch bypasses the fbcon_has_exited and checks if the console is unbound, if its unbound it calls the fbcon_takeover which calls the vt layer to call the fbcon_startup method and everthing works. Signed-off-by: Dave Airlie Signed-off-by: Paul Mundt --- drivers/video/console/fbcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 9c092b8d64e6..c58393402da2 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -823,10 +823,10 @@ static int set_con2fb_map(int unit, int newidx, int user) if (oldidx == newidx) return 0; - if (!info || fbcon_has_exited) + if (!info) return -EINVAL; - if (!err && !search_for_mapped_con()) { + if (!search_for_mapped_con() || !con_is_bound(&fb_con)) { info_idx = newidx; return fbcon_takeover(0); } -- cgit v1.2.2 From 3d366e28605ebda17d4adf44d524559995157e90 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 22 Mar 2011 02:29:17 -0700 Subject: HID: Fix typo Keyoutch -> Keytouch Signed-off-by: Stephen Boyd Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 111da3c6965b..9de9e97149ec 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -185,7 +185,7 @@ config HID_EZKEY Support for Ezkey BTC 8193 keyboard. config HID_KEYTOUCH - tristate "Keyoutch HID devices" + tristate "Keytouch HID devices" depends on USB_HID ---help--- Support for Keytouch HID devices not fully compliant with -- cgit v1.2.2 From 38a66824d96de8aeeb915e6f46f0d3fe55828eb1 Mon Sep 17 00:00:00 2001 From: Stephan Lachowsky Date: Thu, 27 Jan 2011 23:04:33 -0300 Subject: [media] uvcvideo: Fix uvc_fixup_video_ctrl() format search The scheme used to index format in uvc_fixup_video_ctrl() is not robust: format index is based on descriptor ordering, which does not necessarily match bFormatIndex ordering. Searching for first matching format will prevent uvc_fixup_video_ctrl() from using the wrong format/frame to make adjustments. Signed-off-by: Stephan Lachowsky Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_video.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 5673d673504b..545c0294813d 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -89,15 +89,19 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit, static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, struct uvc_streaming_control *ctrl) { - struct uvc_format *format; + struct uvc_format *format = NULL; struct uvc_frame *frame = NULL; unsigned int i; - if (ctrl->bFormatIndex <= 0 || - ctrl->bFormatIndex > stream->nformats) - return; + for (i = 0; i < stream->nformats; ++i) { + if (stream->format[i].index == ctrl->bFormatIndex) { + format = &stream->format[i]; + break; + } + } - format = &stream->format[ctrl->bFormatIndex - 1]; + if (format == NULL) + return; for (i = 0; i < format->nframes; ++i) { if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) { -- cgit v1.2.2 From 4093a5c4a3f59cba1a085bbf87b6ffdddc5a443d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 23 Feb 2011 11:19:17 -0300 Subject: [media] uvcvideo: Fix descriptor parsing for video output devices Commit 4057ac6ca9a77c4275b34b5925ab5c99557913b1 V4L/DVB (13505): uvcvideo: Refactor chain scan broke output terminals parsing. Fix it. Signed-off-by: Laurent Pinchart Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_driver.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index a1e9dfb52f69..6459b8cba223 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1264,6 +1264,14 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, break; + case UVC_OTT_VENDOR_SPECIFIC: + case UVC_OTT_DISPLAY: + case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: + if (uvc_trace_param & UVC_TRACE_PROBE) + printk(" OT %d", entity->id); + + break; + case UVC_TT_STREAMING: if (UVC_ENTITY_IS_ITERM(entity)) { if (uvc_trace_param & UVC_TRACE_PROBE) -- cgit v1.2.2 From 35d9f510b67b10338161aba6229d4f55b4000f5b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 28 Feb 2011 06:37:02 -0300 Subject: [media] V4L: videobuf, don't use dma addr as physical mem->dma_handle is a dma address obtained by dma_alloc_coherent which needn't be a physical address in presence of IOMMU, as a hardware IOMMU can (and most likely) will return a bus address where physical != bus address. So ensure we are remapping (remap_pfn_range) the right page in __videobuf_mmap_mapper by using virt_to_phys(mem->vaddr) and not mem->dma_handle. While at it, use PFN_DOWN instead of explicit shift. [mchehab@redhat.com: Fix compilation breakage due to the lack of a comma] Signed-off-by: Jiri Slaby Reviewed-by: Konrad Rzeszutek Wilk Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf-dma-contig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index c9691115f2d2..c4742fc15529 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -300,7 +300,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); retval = remap_pfn_range(vma, vma->vm_start, - mem->dma_handle >> PAGE_SHIFT, + PFN_DOWN(virt_to_phys(mem->vaddr)), size, vma->vm_page_prot); if (retval) { dev_err(q->dev, "mmap: remap failed with error %d. ", retval); -- cgit v1.2.2 From 7e270941c8f0a11224e383d3d38946451f66fbbf Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 17 Feb 2011 17:33:56 -0300 Subject: [media] Zarlink zl10036 DVB-S: Fix mem leak in zl10036_attach On Thu, 17 Feb 2011, Matthias Schwarzott wrote: > On Sunday 06 February 2011, Jesper Juhl wrote: > > If the memory allocation to 'state' succeeds but we jump to the 'error' > > label before 'state' is assigned to fe->tuner_priv, then the call to > > 'zl10036_release(fe)' at the 'error:' label will not free 'state', but > > only what was previously assigned to 'tuner_priv', thus leaking the memory > > allocated to 'state'. > > There are may ways to fix this, including assigning the allocated memory > > directly to 'fe->tuner_priv', but I did not go for that since the > > additional pointer derefs are more expensive than the local variable, so I > > just added a 'kfree(state)' call. I guess the call to 'zl10036_release' > > might not even be needed in this case, but I wasn't sure, so I left it in. > > > Yeah, that call to zl10036_release can be completely eleminated. > Another thing is: jumping to the error label only makes sense when memory was > already allocated. So the jump in line 471 can be replaced by "return NULL", > as the other error handling before allocation: > if (NULL == config) { > printk(KERN_ERR "%s: no config specified", __func__); > goto error; > } > > I suggest to improve the patch to clean the code up when changing that. > > But I am fine with commiting this patch also if you do not want to change it. > Thank you for your feedback. It makes a lot of sense. Changing it is not a problem :) How about the updated patch below? If the memory allocation to 'state' succeeds but we jump to the 'error' label before 'state' is assigned to fe->tuner_priv, then the call to 'zl10036_release(fe)' at the 'error:' label will not free 'state', but only what was previously assigned to 'tuner_priv', thus leaking the memory allocated to 'state'. This patch fixes the leak and also does not jump to 'error:' before mem has been allocated but instead just returns. Also some small style cleanups. Signed-off-by: Jesper Juhl Signed-off-by: Matthias Schwarzott Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/zl10036.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/zl10036.c b/drivers/media/dvb/frontends/zl10036.c index 4627f491656b..81aa984c551f 100644 --- a/drivers/media/dvb/frontends/zl10036.c +++ b/drivers/media/dvb/frontends/zl10036.c @@ -463,16 +463,16 @@ struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, const struct zl10036_config *config, struct i2c_adapter *i2c) { - struct zl10036_state *state = NULL; + struct zl10036_state *state; int ret; - if (NULL == config) { + if (!config) { printk(KERN_ERR "%s: no config specified", __func__); - goto error; + return NULL; } state = kzalloc(sizeof(struct zl10036_state), GFP_KERNEL); - if (NULL == state) + if (!state) return NULL; state->config = config; @@ -507,7 +507,7 @@ struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, return fe; error: - zl10036_release(fe); + kfree(state); return NULL; } EXPORT_SYMBOL(zl10036_attach); -- cgit v1.2.2 From 868e90d55c0eb6f3c5949c2a747714072c3e080a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 24 Jan 2011 11:23:15 -0300 Subject: [media] radio-wl1273: remove unused wl1273_device->work wl1273_device->work is unused. Remove it along with the spurious flush_scheduled_work() call in wl1273_fm_module_exit(). Signed-off-by: Tejun Heo Cc: Matti Aaltonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-wl1273.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 9e177dccc673..46cacf845049 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -67,7 +67,6 @@ struct wl1273_device { /* RDS */ unsigned int rds_on; - struct delayed_work work; wait_queue_head_t read_queue; struct mutex lock; /* for serializing fm radio operations */ @@ -967,9 +966,6 @@ static int wl1273_fm_rds_off(struct wl1273_device *radio) if (r) goto out; - /* stop rds reception */ - cancel_delayed_work(&radio->work); - /* Service pending read */ wake_up_interruptible(&radio->read_queue); @@ -2171,7 +2167,6 @@ module_init(wl1273_fm_module_init); static void __exit wl1273_fm_module_exit(void) { - flush_scheduled_work(); platform_driver_unregister(&wl1273_fm_radio_driver); pr_info(DRIVER_DESC ", Exiting.\n"); } -- cgit v1.2.2 From a07500ef690fcbec76e879ee2093d7ca69883825 Mon Sep 17 00:00:00 2001 From: Alexander Strakh Date: Tue, 25 Jan 2011 18:00:13 -0300 Subject: [media] drivers/media/video/tlg2300/pd-video.c: Remove second mutex_unlock in pd_vidioc_s_fmt Error path in file drivers/media/video/tlg2300/pd-video.c: 1. First mutex_unlock on &pd->lock in line 767 (in function that called from line 805) 2. Second in line 806 805 pd_vidioc_s_fmt(pd, &f->fmt.pix); 806 mutex_unlock(&pd->lock); Found by Linux Device Drivers Verification Project Signed-off-by: Alexander Strakh Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/tlg2300/pd-video.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c index df33a1d188bb..a794ae62aebf 100644 --- a/drivers/media/video/tlg2300/pd-video.c +++ b/drivers/media/video/tlg2300/pd-video.c @@ -764,10 +764,8 @@ static int pd_vidioc_s_fmt(struct poseidon *pd, struct v4l2_pix_format *pix) } ret |= send_set_req(pd, VIDEO_ROSOLU_SEL, vid_resol, &cmd_status); - if (ret || cmd_status) { - mutex_unlock(&pd->lock); + if (ret || cmd_status) return -EBUSY; - } pix_def->pixelformat = pix->pixelformat; /* save it */ pix->height = (context->tvnormid & V4L2_STD_525_60) ? 480 : 576; -- cgit v1.2.2 From 09b9cc44c942256026bf7a63fec2155b8f488899 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 22 Mar 2011 00:27:42 -0400 Subject: sd: Fail discard requests when logical block provisioning has been disabled Ensure that we kill discard requests after logical block provisioning has been disabled in sysfs. Signed-off-by: Martin K. Petersen Reported-by: Geert Uytterhoeven Reviewed-by: Jeff Moyer Signed-off-by: Linus Torvalds --- drivers/scsi/sd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3be5db5d6343..7ff61d76b4c5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -597,6 +597,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) break; default: + ret = BLKPREP_KILL; goto out; } -- cgit v1.2.2 From 7f9e5c48c1078507747434d4c182ab10925bf98a Mon Sep 17 00:00:00 2001 From: David Dillow Date: Mon, 17 Jan 2011 02:09:44 +0000 Subject: IB: Increase DMA max_segment_size on Mellanox hardware By default, each device is assumed to be able only handle 64 KB chunks during DMA. By giving the segment size a larger value, the block layer will coalesce more S/G entries together for SRP, allowing larger requests with the same sg_tablesize setting. The block layer is the only direct user of it, though a few IOMMU drivers reference it as well for their *_map_sg coalescing code. pci-gart_64 on x86, and a smattering on on sparc, powerpc, and ia64. Since other IB protocols could potentially see larger segments with this, let's check those: - iSER is fine, because you limit your maximum request size to 512 KB, so we'll never overrun the page vector in struct iser_page_vec (128 entries currently). It is independent of the DMA segment size, and handles multi-page segments already. - IPoIB is fine, as it maps each page individually, and doesn't use ib_dma_map_sg(). - RDS appears to do the right thing and has no dependencies on DMA segment size, but I don't claim to have done a complete audit. - NFSoRDMA and 9p are OK -- they do not use ib_dma_map_sg(), so they doesn't care about the coalescing. - Lustre's ko2iblnd does not care about coalescing -- it properly walks the returned sg list. This patch ups the value on Mellanox hardware to 1 GB, which matches reported firmware limits on mlx4. Signed-off-by: David Dillow Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 3 +++ drivers/net/mlx4/main.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 8a40cd539ab1..f24b79b805f2 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -1043,6 +1043,9 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) } } + /* We can handle large RDMA requests, so allow larger segments. */ + dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); + mdev = (struct mthca_dev *) ib_alloc_device(sizeof *mdev); if (!mdev) { dev_err(&pdev->dev, "Device struct alloc failed, " diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 2765a3ce9c24..c83501122d77 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1109,6 +1109,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } } + /* Allow large DMA segments, up to the firmware limit of 1 GB */ + dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); + priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) { dev_err(&pdev->dev, "Device struct alloc failed, " -- cgit v1.2.2 From 5b9a4f98b2e29fb92a4a54ef12b2e3940f941ed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 22 Mar 2011 10:35:17 +0100 Subject: dma: let IMX_DMA depend on IMX_HAVE_DMA_V1 instead of an explicit list of SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As a side effect this makes IMX_DMA selectable on i.MX21 again, because the symbol ARCH_MX21 doesn't exist (MACH_MX21 would have been more correct). Signed-off-by: Uwe Kleine-König Signed-off-by: Dan Williams --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index d700895cb40f..a572600e44eb 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -221,7 +221,7 @@ config IMX_SDMA config IMX_DMA tristate "i.MX DMA support" - depends on ARCH_MX1 || ARCH_MX21 || MACH_MX27 + depends on IMX_HAVE_DMA_V1 select DMA_ENGINE help Support the i.MX DMA engine. This engine is integrated into -- cgit v1.2.2 From d42efe6bfb4eed8314c8ce3547f21954a4140399 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 22 Mar 2011 17:27:25 +0530 Subject: dmaengine/dmatest: Pass timeout via module params When we try to test all channels present on our controller together, some channels of lower priority may be very slow as compared to others. If number of transfers is unlimited, some channels may timeout and will not finish within 3 seconds. Thus, while doing such regress testing we may need to have higher value of timeouts. This patch adds support for passing timeout value via module parameters. Default value is 3 msec, a negative value means max timeout possible. Signed-off-by: Viresh Kumar Signed-off-by: Dan Williams --- drivers/dma/dmatest.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 7e1b0aa0ca50..e0888cb538d4 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -54,6 +54,11 @@ module_param(pq_sources, uint, S_IRUGO); MODULE_PARM_DESC(pq_sources, "Number of p+q source buffers (default: 3)"); +static int timeout = 3000; +module_param(timeout, uint, S_IRUGO); +MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), \ + Pass -1 for infinite timeout"); + /* * Initialization patterns. All bytes in the source buffer has bit 7 * set, all bytes in the destination buffer has bit 7 cleared. @@ -299,7 +304,7 @@ static int dmatest_func(void *data) dma_addr_t dma_srcs[src_cnt]; dma_addr_t dma_dsts[dst_cnt]; struct completion cmp; - unsigned long tmo = msecs_to_jiffies(3000); + unsigned long tmo = msecs_to_jiffies(timeout); u8 align = 0; total_tests++; -- cgit v1.2.2 From 59c2be1e4d42c0d4949cecdeef3f37070a1fbc13 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Mon, 21 Mar 2011 15:10:11 -0700 Subject: rbd: use watch/notify for changes in rbd header Send notifications when we change the rbd header (e.g. create a snapshot) and wait for such notifications. This allows synchronizing the snapshot creation between different rbd clients/rools. Signed-off-by: Yehuda Sadeh Signed-off-by: Sage Weil --- drivers/block/rbd.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 335 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index e1e38b11f48a..16dc3645291c 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,8 @@ #define DEV_NAME_LEN 32 +#define RBD_NOTIFY_TIMEOUT_DEFAULT 10 + /* * block device image metadata (in-memory version) */ @@ -71,6 +74,12 @@ struct rbd_image_header { char *snap_names; u64 *snap_sizes; + + u64 obj_version; +}; + +struct rbd_options { + int notify_timeout; }; /* @@ -78,6 +87,7 @@ struct rbd_image_header { */ struct rbd_client { struct ceph_client *client; + struct rbd_options *rbd_opts; struct kref kref; struct list_head node; }; @@ -124,6 +134,9 @@ struct rbd_device { char pool_name[RBD_MAX_POOL_NAME_LEN]; int poolid; + struct ceph_osd_event *watch_event; + struct ceph_osd_request *watch_request; + char snap_name[RBD_MAX_SNAP_NAME_LEN]; u32 cur_snap; /* index+1 of current snapshot within snap context 0 - for the head */ @@ -177,6 +190,8 @@ static void rbd_put_dev(struct rbd_device *rbd_dev) put_device(&rbd_dev->dev); } +static int __rbd_update_snaps(struct rbd_device *rbd_dev); + static int rbd_open(struct block_device *bdev, fmode_t mode) { struct gendisk *disk = bdev->bd_disk; @@ -211,7 +226,8 @@ static const struct block_device_operations rbd_bd_ops = { * Initialize an rbd client instance. * We own *opt. */ -static struct rbd_client *rbd_client_create(struct ceph_options *opt) +static struct rbd_client *rbd_client_create(struct ceph_options *opt, + struct rbd_options *rbd_opts) { struct rbd_client *rbdc; int ret = -ENOMEM; @@ -233,6 +249,8 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt) if (ret < 0) goto out_err; + rbdc->rbd_opts = rbd_opts; + spin_lock(&node_lock); list_add_tail(&rbdc->node, &rbd_client_list); spin_unlock(&node_lock); @@ -266,6 +284,59 @@ static struct rbd_client *__rbd_client_find(struct ceph_options *opt) return NULL; } +/* + * mount options + */ +enum { + Opt_notify_timeout, + Opt_last_int, + /* int args above */ + Opt_last_string, + /* string args above */ +}; + +static match_table_t rbdopt_tokens = { + {Opt_notify_timeout, "notify_timeout=%d"}, + /* int args above */ + /* string args above */ + {-1, NULL} +}; + +static int parse_rbd_opts_token(char *c, void *private) +{ + struct rbd_options *rbdopt = private; + substring_t argstr[MAX_OPT_ARGS]; + int token, intval, ret; + + token = match_token((char *)c, rbdopt_tokens, argstr); + if (token < 0) + return -EINVAL; + + if (token < Opt_last_int) { + ret = match_int(&argstr[0], &intval); + if (ret < 0) { + pr_err("bad mount option arg (not int) " + "at '%s'\n", c); + return ret; + } + dout("got int token %d val %d\n", token, intval); + } else if (token > Opt_last_int && token < Opt_last_string) { + dout("got string token %d val %s\n", token, + argstr[0].from); + } else { + dout("got token %d\n", token); + } + + switch (token) { + case Opt_notify_timeout: + rbdopt->notify_timeout = intval; + break; + default: + BUG_ON(token); + } + return 0; +} + /* * Get a ceph client with specific addr and configuration, if one does * not exist create it. @@ -276,11 +347,18 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, struct rbd_client *rbdc; struct ceph_options *opt; int ret; + struct rbd_options *rbd_opts; + + rbd_opts = kzalloc(sizeof(*rbd_opts), GFP_KERNEL); + if (!rbd_opts) + return -ENOMEM; + + rbd_opts->notify_timeout = RBD_NOTIFY_TIMEOUT_DEFAULT; ret = ceph_parse_options(&opt, options, mon_addr, - mon_addr + strlen(mon_addr), NULL, NULL); + mon_addr + strlen(mon_addr), parse_rbd_opts_token, rbd_opts); if (ret < 0) - return ret; + goto done_err; spin_lock(&node_lock); rbdc = __rbd_client_find(opt); @@ -296,13 +374,18 @@ static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr, } spin_unlock(&node_lock); - rbdc = rbd_client_create(opt); - if (IS_ERR(rbdc)) - return PTR_ERR(rbdc); + rbdc = rbd_client_create(opt, rbd_opts); + if (IS_ERR(rbdc)) { + ret = PTR_ERR(rbdc); + goto done_err; + } rbd_dev->rbd_client = rbdc; rbd_dev->client = rbdc->client; return 0; +done_err: + kfree(rbd_opts); + return ret; } /* @@ -318,6 +401,7 @@ static void rbd_client_release(struct kref *kref) spin_unlock(&node_lock); ceph_destroy_client(rbdc->client); + kfree(rbdc->rbd_opts); kfree(rbdc); } @@ -666,7 +750,9 @@ static int rbd_do_request(struct request *rq, struct ceph_osd_req_op *ops, int num_reply, void (*rbd_cb)(struct ceph_osd_request *req, - struct ceph_msg *msg)) + struct ceph_msg *msg), + struct ceph_osd_request **linger_req, + u64 *ver) { struct ceph_osd_request *req; struct ceph_file_layout *layout; @@ -729,12 +815,20 @@ static int rbd_do_request(struct request *rq, req->r_oid, req->r_oid_len); up_read(&header->snap_rwsem); + if (linger_req) { + ceph_osdc_set_request_linger(&dev->client->osdc, req); + *linger_req = req; + } + ret = ceph_osdc_start_request(&dev->client->osdc, req, false); if (ret < 0) goto done_err; if (!rbd_cb) { ret = ceph_osdc_wait_request(&dev->client->osdc, req); + if (ver) + *ver = le64_to_cpu(req->r_reassert_version.version); + dout("reassert_ver=%lld\n", le64_to_cpu(req->r_reassert_version.version)); ceph_osdc_put_request(req); } return ret; @@ -789,6 +883,11 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg) kfree(req_data); } +static void rbd_simple_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg) +{ + ceph_osdc_put_request(req); +} + /* * Do a synchronous ceph osd operation */ @@ -801,7 +900,9 @@ static int rbd_req_sync_op(struct rbd_device *dev, int num_reply, const char *obj, u64 ofs, u64 len, - char *buf) + char *buf, + struct ceph_osd_request **linger_req, + u64 *ver) { int ret; struct page **pages; @@ -833,7 +934,8 @@ static int rbd_req_sync_op(struct rbd_device *dev, flags, ops, 2, - NULL); + NULL, + linger_req, ver); if (ret < 0) goto done_ops; @@ -893,7 +995,7 @@ static int rbd_do_op(struct request *rq, flags, ops, num_reply, - rbd_req_cb); + rbd_req_cb, 0, NULL); done: kfree(seg_name); return ret; @@ -940,18 +1042,174 @@ static int rbd_req_sync_read(struct rbd_device *dev, u64 snapid, const char *obj, u64 ofs, u64 len, - char *buf) + char *buf, + u64 *ver) { return rbd_req_sync_op(dev, NULL, (snapid ? snapid : CEPH_NOSNAP), CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, NULL, - 1, obj, ofs, len, buf); + 1, obj, ofs, len, buf, NULL, ver); } /* - * Request sync osd read + * Request sync osd watch + */ +static int rbd_req_sync_notify_ack(struct rbd_device *dev, + u64 ver, + u64 notify_id, + const char *obj) +{ + struct ceph_osd_req_op *ops; + struct page **pages = NULL; + int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0); + if (ret < 0) + return ret; + + ops[0].watch.ver = cpu_to_le64(dev->header.obj_version); + ops[0].watch.cookie = notify_id; + ops[0].watch.flag = 0; + + ret = rbd_do_request(NULL, dev, NULL, CEPH_NOSNAP, + obj, 0, 0, NULL, + pages, 0, + CEPH_OSD_FLAG_READ, + ops, + 1, + rbd_simple_req_cb, 0, NULL); + + rbd_destroy_ops(ops); + return ret; +} + +static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data) +{ + struct rbd_device *dev = (struct rbd_device *)data; + if (!dev) + return; + + dout("rbd_watch_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name, + notify_id, (int)opcode); + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + __rbd_update_snaps(dev); + mutex_unlock(&ctl_mutex); + + rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name); +} + +/* + * Request sync osd watch + */ +static int rbd_req_sync_watch(struct rbd_device *dev, + const char *obj, + u64 ver) +{ + struct ceph_osd_req_op *ops; + struct ceph_osd_client *osdc = &dev->client->osdc; + + int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_WATCH, 0); + if (ret < 0) + return ret; + + ret = ceph_osdc_create_event(osdc, rbd_watch_cb, 0, + (void *)dev, &dev->watch_event); + if (ret < 0) + goto fail; + + ops[0].watch.ver = cpu_to_le64(ver); + ops[0].watch.cookie = cpu_to_le64(dev->watch_event->cookie); + ops[0].watch.flag = 1; + + ret = rbd_req_sync_op(dev, NULL, + CEPH_NOSNAP, + 0, + CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, + ops, + 1, obj, 0, 0, NULL, + &dev->watch_request, NULL); + + if (ret < 0) + goto fail_event; + + rbd_destroy_ops(ops); + return 0; + +fail_event: + ceph_osdc_cancel_event(dev->watch_event); + dev->watch_event = NULL; +fail: + rbd_destroy_ops(ops); + return ret; +} + +struct rbd_notify_info { + struct rbd_device *dev; +}; + +static void rbd_notify_cb(u64 ver, u64 notify_id, u8 opcode, void *data) +{ + struct rbd_device *dev = (struct rbd_device *)data; + if (!dev) + return; + + dout("rbd_notify_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name, + notify_id, (int)opcode); +} + +/* + * Request sync osd notify + */ +static int rbd_req_sync_notify(struct rbd_device *dev, + const char *obj) +{ + struct ceph_osd_req_op *ops; + struct ceph_osd_client *osdc = &dev->client->osdc; + struct ceph_osd_event *event; + struct rbd_notify_info info; + int payload_len = sizeof(u32) + sizeof(u32); + int ret; + + ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY, payload_len); + if (ret < 0) + return ret; + + info.dev = dev; + + ret = ceph_osdc_create_event(osdc, rbd_notify_cb, 1, + (void *)&info, &event); + if (ret < 0) + goto fail; + + ops[0].watch.ver = 1; + ops[0].watch.flag = 1; + ops[0].watch.cookie = event->cookie; + ops[0].watch.prot_ver = RADOS_NOTIFY_VER; + ops[0].watch.timeout = 12; + + ret = rbd_req_sync_op(dev, NULL, + CEPH_NOSNAP, + 0, + CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, + ops, + 1, obj, 0, 0, NULL, NULL, NULL); + if (ret < 0) + goto fail_event; + + ret = ceph_osdc_wait_event(event, CEPH_OSD_TIMEOUT_DEFAULT); + dout("ceph_osdc_wait_event returned %d\n", ret); + rbd_destroy_ops(ops); + return 0; + +fail_event: + ceph_osdc_cancel_event(event); +fail: + rbd_destroy_ops(ops); + return ret; +} + +/* + * Request sync osd rollback */ static int rbd_req_sync_rollback_obj(struct rbd_device *dev, u64 snapid, @@ -969,13 +1227,10 @@ static int rbd_req_sync_rollback_obj(struct rbd_device *dev, 0, CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, ops, - 1, obj, 0, 0, NULL); + 1, obj, 0, 0, NULL, NULL, NULL); rbd_destroy_ops(ops); - if (ret < 0) - return ret; - return ret; } @@ -987,7 +1242,8 @@ static int rbd_req_sync_exec(struct rbd_device *dev, const char *cls, const char *method, const char *data, - int len) + int len, + u64 *ver) { struct ceph_osd_req_op *ops; int cls_len = strlen(cls); @@ -1010,7 +1266,7 @@ static int rbd_req_sync_exec(struct rbd_device *dev, 0, CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, ops, - 1, obj, 0, 0, NULL); + 1, obj, 0, 0, NULL, NULL, ver); rbd_destroy_ops(ops); @@ -1156,6 +1412,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev, struct rbd_image_header_ondisk *dh; int snap_count = 0; u64 snap_names_len = 0; + u64 ver; while (1) { int len = sizeof(*dh) + @@ -1171,7 +1428,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev, NULL, CEPH_NOSNAP, rbd_dev->obj_md_name, 0, len, - (char *)dh); + (char *)dh, &ver); if (rc < 0) goto out_dh; @@ -1188,6 +1445,7 @@ static int rbd_read_header(struct rbd_device *rbd_dev, } break; } + header->obj_version = ver; out_dh: kfree(dh); @@ -1205,6 +1463,7 @@ static int rbd_header_add_snap(struct rbd_device *dev, u64 new_snapid; int ret; void *data, *data_start, *data_end; + u64 ver; /* we should create a snapshot only if we're pointing at the head */ if (dev->cur_snap) @@ -1227,7 +1486,7 @@ static int rbd_header_add_snap(struct rbd_device *dev, ceph_encode_64_safe(&data, data_end, new_snapid, bad); ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add", - data_start, data - data_start); + data_start, data - data_start, &ver); kfree(data_start); @@ -1259,6 +1518,7 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) int ret; struct rbd_image_header h; u64 snap_seq; + int follow_seq = 0; ret = rbd_read_header(rbd_dev, &h); if (ret < 0) @@ -1267,6 +1527,11 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) down_write(&rbd_dev->header.snap_rwsem); snap_seq = rbd_dev->header.snapc->seq; + if (rbd_dev->header.total_snaps && + rbd_dev->header.snapc->snaps[0] == snap_seq) + /* pointing at the head, will need to follow that + if head moves */ + follow_seq = 1; kfree(rbd_dev->header.snapc); kfree(rbd_dev->header.snap_names); @@ -1277,7 +1542,10 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev) rbd_dev->header.snap_names = h.snap_names; rbd_dev->header.snap_names_len = h.snap_names_len; rbd_dev->header.snap_sizes = h.snap_sizes; - rbd_dev->header.snapc->seq = snap_seq; + if (follow_seq) + rbd_dev->header.snapc->seq = rbd_dev->header.snapc->snaps[0]; + else + rbd_dev->header.snapc->seq = snap_seq; ret = __rbd_init_snaps_header(rbd_dev); @@ -1699,7 +1967,28 @@ static void rbd_bus_del_dev(struct rbd_device *rbd_dev) device_unregister(&rbd_dev->dev); } -static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count) +static int rbd_init_watch_dev(struct rbd_device *rbd_dev) +{ + int ret, rc; + + do { + ret = rbd_req_sync_watch(rbd_dev, rbd_dev->obj_md_name, + rbd_dev->header.obj_version); + if (ret == -ERANGE) { + mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); + rc = __rbd_update_snaps(rbd_dev); + mutex_unlock(&ctl_mutex); + if (rc < 0) + return rc; + } + } while (ret == -ERANGE); + + return ret; +} + +static ssize_t rbd_add(struct bus_type *bus, + const char *buf, + size_t count) { struct ceph_osd_client *osdc; struct rbd_device *rbd_dev; @@ -1797,6 +2086,10 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf, size_t count) if (rc) goto err_out_bus; + rc = rbd_init_watch_dev(rbd_dev); + if (rc) + goto err_out_bus; + return count; err_out_bus: @@ -1849,6 +2142,12 @@ static void rbd_dev_release(struct device *dev) struct rbd_device *rbd_dev = container_of(dev, struct rbd_device, dev); + if (rbd_dev->watch_request) + ceph_osdc_unregister_linger_request(&rbd_dev->client->osdc, + rbd_dev->watch_request); + if (rbd_dev->watch_event) + ceph_osdc_cancel_event(rbd_dev->watch_event); + rbd_put_client(rbd_dev); /* clean up and free blkdev */ @@ -1914,14 +2213,24 @@ static ssize_t rbd_snap_add(struct device *dev, ret = rbd_header_add_snap(rbd_dev, name, GFP_KERNEL); if (ret < 0) - goto done_unlock; + goto err_unlock; ret = __rbd_update_snaps(rbd_dev); if (ret < 0) - goto done_unlock; + goto err_unlock; + + /* shouldn't hold ctl_mutex when notifying.. notify might + trigger a watch callback that would need to get that mutex */ + mutex_unlock(&ctl_mutex); + + /* make a best effort, don't error if failed */ + rbd_req_sync_notify(rbd_dev, rbd_dev->obj_md_name); ret = count; -done_unlock: + kfree(name); + return ret; + +err_unlock: mutex_unlock(&ctl_mutex); kfree(name); return ret; -- cgit v1.2.2 From 9d4540c9395f5f01cdd0cf60d230ec8bee165bb8 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sat, 12 Feb 2011 22:35:08 -0300 Subject: [media] v180 - DM04/QQBOX added support for BS2F7HZ0194 versions Old versions of these boxes have the BS2F7HZ0194 tuner module on both the LME2510 and LME2510C. Firmware dvb-usb-lme2510-s0194.fw and/or dvb-usb-lme2510c-s0194.fw files are required. See Documentation/dvb/lmedm04.txt Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/lmedm04.c | 230 ++++++++++++++++++++++++++---------- 1 file changed, 170 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 46ccd01a7696..fa64b6c15ef9 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -2,7 +2,9 @@ * * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395 * LME2510C + LG TDQY-P001F + * LME2510C + BS2F7HZ0194 * LME2510 + LG TDQY-P001F + * LME2510 + BS2F7HZ0194 * * MVB7395 (LME2510C+SHARP:BS2F7HZ7395) * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V) @@ -12,20 +14,22 @@ * * MVB0001F (LME2510C+LGTDQT-P001F) * + * MV0194 (LME2510+SHARP:BS2F7HZ0194) + * SHARP:BS2F7HZ0194 = (STV0299+IX2410) + * + * MVB0194 (LME2510C+SHARP0194) + * * For firmware see Documentation/dvb/lmedm04.txt * * I2C addresses: * 0xd0 - STV0288 - Demodulator * 0xc0 - Sharp IX2505V - Tuner - * --or-- + * -- * 0x1c - TDA10086 - Demodulator * 0xc0 - TDA8263 - Tuner - * - * ***Please Note*** - * There are other variants of the DM04 - * ***NOT SUPPORTED*** - * MV0194 (LME2510+SHARP0194) - * MVB0194 (LME2510C+SHARP0194) + * -- + * 0xd0 - STV0299 - Demodulator + * 0xc0 - IX2410 - Tuner * * * VID = 3344 PID LME2510=1122 LME2510C=1120 @@ -55,6 +59,9 @@ * * QQbox suffers from noise on LNB voltage. * + * LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system + * with other tuners. After a cold reset streaming will not start. + * * PID functions have been removed from this driver version due to * problems with different firmware and application versions. */ @@ -69,6 +76,9 @@ #include "tda10086.h" #include "stv0288.h" #include "ix2505v.h" +#include "stv0299.h" +#include "dvb-pll.h" +#include "z0194a.h" @@ -96,8 +106,11 @@ MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define TUNER_DEFAULT 0x0 #define TUNER_LG 0x1 #define TUNER_S7395 0x2 +#define TUNER_S0194 0x3 struct lme2510_state { u8 id; @@ -249,6 +262,7 @@ static void lme2510_int_response(struct urb *lme_urb) st->time_key = ibuf[7]; break; case TUNER_S7395: + case TUNER_S0194: /* Tweak for earlier firmware*/ if (ibuf[1] == 0x03) { if (ibuf[2] > 1) @@ -364,6 +378,18 @@ static int lme2510_msg(struct dvb_usb_device *d, msleep(5); } break; + case TUNER_S0194: + if (wbuf[2] == 0xd0) { + if (wbuf[3] == 0x1b) { + st->signal_lock = rbuf[1]; + if ((st->stream_on & 1) && + (st->signal_lock & 0x8)) { + lme2510_stream_restart(d); + st->i2c_talk_onoff = 0; + } + } + } + break; default: break; } @@ -423,6 +449,34 @@ static int lme2510_msg(struct dvb_usb_device *d, break; } break; + case TUNER_S0194: + switch (wbuf[3]) { + case 0x18: + rbuf[0] = 0x55; + rbuf[1] = (st->signal_level & 0x80) + ? 0 : (st->signal_level * 2); + break; + case 0x24: + rbuf[0] = 0x55; + rbuf[1] = st->signal_sn; + break; + case 0x1b: + rbuf[0] = 0x55; + rbuf[1] = st->signal_lock; + break; + case 0x19: + case 0x25: + case 0x1e: + case 0x1d: + rbuf[0] = 0x55; + rbuf[1] = 0x00; + break; + default: + lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); + st->i2c_talk_onoff = 1; + break; + } + break; default: break; } @@ -517,17 +571,14 @@ static int lme2510_identify_state(struct usb_device *udev, struct dvb_usb_device_description **desc, int *cold) { - if (lme2510_return_status(udev) == 0x44) - *cold = 1; - else - *cold = 0; + *cold = 0; return 0; } static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct lme2510_state *st = adap->dev->priv; - static u8 clear_reg_3[] = LME_CLEAR_PID; + static u8 clear_reg_3[] = LME_CLEAR_PID; static u8 rbuf[1]; int ret = 0, rlen = sizeof(rbuf); @@ -658,9 +709,6 @@ static int lme2510_download_firmware(struct usb_device *dev, return (ret < 0) ? -ENODEV : 0; } -/* Default firmware for LME2510C */ -char lme_firmware[50] = "dvb-usb-lme2510c-s7395.fw"; - static void lme_coldreset(struct usb_device *dev) { int ret = 0, len_in; @@ -678,49 +726,83 @@ static void lme_coldreset(struct usb_device *dev) static int lme_firmware_switch(struct usb_device *udev, int cold) { const struct firmware *fw = NULL; - char lme2510c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; - char lme2510c_lg[] = "dvb-usb-lme2510c-lg.fw"; - char *firm_msg[] = {"Loading", "Switching to"}; - int ret; + const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw"; + const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw"; + const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw"; + const char fw_lg[] = "dvb-usb-lme2510-lg.fw"; + const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw"; + const char *fw_lme; + int ret, cold_fw; cold = (cold > 0) ? (cold & 1) : 0; - if (udev->descriptor.idProduct == 0x1122) - return 0; + cold_fw = !cold; - switch (dvb_usb_lme2510_firmware) { - case 0: - default: - memcpy(&lme_firmware, lme2510c_s7395, sizeof(lme2510c_s7395)); - ret = request_firmware(&fw, lme_firmware, &udev->dev); - if (ret == 0) { - info("FRM %s S7395 Firmware", firm_msg[cold]); + if (udev->descriptor.idProduct == 0x1122) { + switch (dvb_usb_lme2510_firmware) { + default: + dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) { + cold = 0;/*lme2510-s0194 cannot cold reset*/ + break; + } + dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + info("FRM No Firmware Found - please install"); + dvb_usb_lme2510_firmware = TUNER_DEFAULT; + cold = 0; + cold_fw = 0; break; } - if (cold == 0) - dvb_usb_lme2510_firmware = 1; - else + } else { + switch (dvb_usb_lme2510_firmware) { + default: + dvb_usb_lme2510_firmware = TUNER_S7395; + case TUNER_S7395: + fw_lme = fw_c_s7395; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + dvb_usb_lme2510_firmware = TUNER_LG; + case TUNER_LG: + fw_lme = fw_c_lg; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + dvb_usb_lme2510_firmware = TUNER_S0194; + case TUNER_S0194: + fw_lme = fw_c_s0194; + ret = request_firmware(&fw, fw_lme, &udev->dev); + if (ret == 0) + break; + info("FRM No Firmware Found - please install"); + dvb_usb_lme2510_firmware = TUNER_DEFAULT; cold = 0; - case 1: - memcpy(&lme_firmware, lme2510c_lg, sizeof(lme2510c_lg)); - ret = request_firmware(&fw, lme_firmware, &udev->dev); - if (ret == 0) { - info("FRM %s LG Firmware", firm_msg[cold]); + cold_fw = 0; break; } - info("FRM No Firmware Found - please install"); - dvb_usb_lme2510_firmware = 0; - cold = 0; - break; } - release_firmware(fw); + if (cold_fw) { + info("FRM Loading %s file", fw_lme); + ret = lme2510_download_firmware(udev, fw); + } if (cold) { + info("FRM Changing to %s firmware", fw_lme); lme_coldreset(udev); return -ENODEV; } + release_firmware(fw); + return ret; } @@ -758,6 +840,18 @@ static struct ix2505v_config lme_tuner = { .tuner_chargepump = 0x3, }; +static struct stv0299_config sharp_z0194_config = { + .demod_address = 0xd0, + .inittab = sharp_z0194a_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .lock_output = STV0299_LOCKOUTPUT_1, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = sharp_z0194a_set_symbol_rate, +}; + static int dm04_lme2510_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) { @@ -793,7 +887,8 @@ static int lme_name(struct dvb_usb_adapter *adap) { struct lme2510_state *st = adap->dev->priv; const char *desc = adap->dev->desc->name; - char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395"}; + char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", + " SHARP:BS2F7HZ0194"}; char *name = adap->fe->ops.info.name; strlcpy(name, desc, 128); @@ -820,26 +915,40 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) st->i2c_tuner_gate_r = 4; st->i2c_tuner_addr = 0xc0; st->tuner_config = TUNER_LG; - if (dvb_usb_lme2510_firmware != 1) { - dvb_usb_lme2510_firmware = 1; + if (dvb_usb_lme2510_firmware != TUNER_LG) { + dvb_usb_lme2510_firmware = TUNER_LG; ret = lme_firmware_switch(adap->dev->udev, 1); - } else /*stops LG/Sharp multi tuner problems*/ - dvb_usb_lme2510_firmware = 0; + } + goto end; + } + + st->i2c_gate = 4; + adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config, + &adap->dev->i2c_adap); + if (adap->fe) { + info("FE Found Stv0299"); + st->i2c_tuner_gate_w = 4; + st->i2c_tuner_gate_r = 5; + st->i2c_tuner_addr = 0xc0; + st->tuner_config = TUNER_S0194; + if (dvb_usb_lme2510_firmware != TUNER_S0194) { + dvb_usb_lme2510_firmware = TUNER_S0194; + ret = lme_firmware_switch(adap->dev->udev, 1); + } goto end; } st->i2c_gate = 5; adap->fe = dvb_attach(stv0288_attach, &lme_config, &adap->dev->i2c_adap); - if (adap->fe) { info("FE Found Stv0288"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; st->i2c_tuner_addr = 0xc0; st->tuner_config = TUNER_S7395; - if (dvb_usb_lme2510_firmware != 0) { - dvb_usb_lme2510_firmware = 0; + if (dvb_usb_lme2510_firmware != TUNER_S7395) { + dvb_usb_lme2510_firmware = TUNER_S7395; ret = lme_firmware_switch(adap->dev->udev, 1); } } else { @@ -847,6 +956,7 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } + end: if (ret) { kfree(adap->fe); adap->fe = NULL; @@ -855,14 +965,13 @@ end: if (ret) { adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; ret = lme_name(adap); - return ret; } static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) { struct lme2510_state *st = adap->dev->priv; - char *tun_msg[] = {"", "TDA8263", "IX2505V"}; + char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA"}; int ret = 0; switch (st->tuner_config) { @@ -876,6 +985,11 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) &adap->dev->i2c_adap)) ret = st->tuner_config; break; + case TUNER_S0194: + if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0, + &adap->dev->i2c_adap, DVB_PLL_OPERA1)) + ret = st->tuner_config; + break; default: break; } @@ -936,7 +1050,10 @@ static int lme2510_probe(struct usb_interface *intf, return -ENODEV; } - lme_firmware_switch(udev, 0); + if (lme2510_return_status(udev) == 0x44) { + lme_firmware_switch(udev, 0); + return -ENODEV; + } if (0 == dvb_usb_device_init(intf, &lme2510_properties, THIS_MODULE, NULL, adapter_nr)) { @@ -964,10 +1081,6 @@ MODULE_DEVICE_TABLE(usb, lme2510_table); static struct dvb_usb_device_properties lme2510_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = lme2510_download_firmware, - .firmware = "dvb-usb-lme2510-lg.fw", - .size_of_priv = sizeof(struct lme2510_state), .num_adapters = 1, .adapter = { @@ -1004,9 +1117,6 @@ static struct dvb_usb_device_properties lme2510_properties = { static struct dvb_usb_device_properties lme2510c_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, - .usb_ctrl = DEVICE_SPECIFIC, - .download_firmware = lme2510_download_firmware, - .firmware = (const char *)&lme_firmware, .size_of_priv = sizeof(struct lme2510_state), .num_adapters = 1, .adapter = { @@ -1109,5 +1219,5 @@ module_exit(lme2510_module_exit); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("1.75"); +MODULE_VERSION("1.80"); MODULE_LICENSE("GPL"); -- cgit v1.2.2 From f8931f56f51a795e030318b95e4a0f8ac453e35e Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 23 Jan 2011 18:22:45 -0300 Subject: [media] DM04/QQBOX Update V1.76 - use 32 bit remote decoding Use 32 bit decoding to add support for more than one variant of remote control. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/lmedm04.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index fa64b6c15ef9..cd26e7c1536a 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -204,7 +204,7 @@ static int lme2510_stream_restart(struct dvb_usb_device *d) rbuff, sizeof(rbuff)); return ret; } -static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress) +static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress) { struct dvb_usb_device *d = adap->dev; @@ -250,7 +250,8 @@ static void lme2510_int_response(struct urb *lme_urb) case 0xaa: debug_data_snipet(1, "INT Remote data snipet in", ibuf); lme2510_remote_keypress(adap, - (u16)(ibuf[4]<<8)+ibuf[5]); + (u32)(ibuf[2] << 24) + (ibuf[3] << 16) + + (ibuf[4] << 8) + ibuf[5]); break; case 0xbb: switch (st->tuner_config) { -- cgit v1.2.2 From 4a1cba5151ccddf4a7071fe4950fb699e8b23bf9 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 23 Jan 2011 18:26:03 -0300 Subject: [media] Change to 32 bit and add other remote controls for lme2510 These bubble button remote controls appear to be generic from China. These are the three variants known to be supplied with DM04/QQBOX DVB-S They could well be supplied with other devices from the region. Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-lme2510.c | 96 +++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 875cd81477c7..3c1913926c1a 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -13,33 +13,75 @@ static struct rc_map_table lme2510_rc[] = { - { 0xba45, KEY_0 }, - { 0xa05f, KEY_1 }, - { 0xaf50, KEY_2 }, - { 0xa25d, KEY_3 }, - { 0xbe41, KEY_4 }, - { 0xf50a, KEY_5 }, - { 0xbd42, KEY_6 }, - { 0xb847, KEY_7 }, - { 0xb649, KEY_8 }, - { 0xfa05, KEY_9 }, - { 0xbc43, KEY_POWER }, - { 0xb946, KEY_SUBTITLE }, - { 0xf906, KEY_PAUSE }, - { 0xfc03, KEY_MEDIA_REPEAT}, - { 0xfd02, KEY_PAUSE }, - { 0xa15e, KEY_VOLUMEUP }, - { 0xa35c, KEY_VOLUMEDOWN }, - { 0xf609, KEY_CHANNELUP }, - { 0xe51a, KEY_CHANNELDOWN }, - { 0xe11e, KEY_PLAY }, - { 0xe41b, KEY_ZOOM }, - { 0xa659, KEY_MUTE }, - { 0xa55a, KEY_TV }, - { 0xe718, KEY_RECORD }, - { 0xf807, KEY_EPG }, - { 0xfe01, KEY_STOP }, - + /* Type 1 - 26 buttons */ + { 0xef12ba45, KEY_0 }, + { 0xef12a05f, KEY_1 }, + { 0xef12af50, KEY_2 }, + { 0xef12a25d, KEY_3 }, + { 0xef12be41, KEY_4 }, + { 0xef12f50a, KEY_5 }, + { 0xef12bd42, KEY_6 }, + { 0xef12b847, KEY_7 }, + { 0xef12b649, KEY_8 }, + { 0xef12fa05, KEY_9 }, + { 0xef12bc43, KEY_POWER }, + { 0xef12b946, KEY_SUBTITLE }, + { 0xef12f906, KEY_PAUSE }, + { 0xef12fc03, KEY_MEDIA_REPEAT}, + { 0xef12fd02, KEY_PAUSE }, + { 0xef12a15e, KEY_VOLUMEUP }, + { 0xef12a35c, KEY_VOLUMEDOWN }, + { 0xef12f609, KEY_CHANNELUP }, + { 0xef12e51a, KEY_CHANNELDOWN }, + { 0xef12e11e, KEY_PLAY }, + { 0xef12e41b, KEY_ZOOM }, + { 0xef12a659, KEY_MUTE }, + { 0xef12a55a, KEY_TV }, + { 0xef12e718, KEY_RECORD }, + { 0xef12f807, KEY_EPG }, + { 0xef12fe01, KEY_STOP }, + /* Type 2 - 20 buttons */ + { 0xff40ea15, KEY_0 }, + { 0xff40f708, KEY_1 }, + { 0xff40f609, KEY_2 }, + { 0xff40f50a, KEY_3 }, + { 0xff40f30c, KEY_4 }, + { 0xff40f20d, KEY_5 }, + { 0xff40f10e, KEY_6 }, + { 0xff40ef10, KEY_7 }, + { 0xff40ee11, KEY_8 }, + { 0xff40ed12, KEY_9 }, + { 0xff40ff00, KEY_POWER }, + { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ + { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff40f906, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/ + { 0xff40fe01, KEY_CHANNELUP }, + { 0xff40fa05, KEY_CHANNELDOWN }, + { 0xff40eb14, KEY_ZOOM }, + { 0xff40e718, KEY_RECORD }, + { 0xff40e916, KEY_STOP }, + /* Type 3 - 20 buttons */ + { 0xff00e31c, KEY_0 }, + { 0xff00f807, KEY_1 }, + { 0xff00ea15, KEY_2 }, + { 0xff00f609, KEY_3 }, + { 0xff00e916, KEY_4 }, + { 0xff00e619, KEY_5 }, + { 0xff00f20d, KEY_6 }, + { 0xff00f30c, KEY_7 }, + { 0xff00e718, KEY_8 }, + { 0xff00a15e, KEY_9 }, + { 0xff00ba45, KEY_POWER }, + { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ + { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/ + { 0xff00b946, KEY_CHANNELUP }, + { 0xff00bf40, KEY_CHANNELDOWN }, + { 0xff00f708, KEY_ZOOM }, + { 0xff00bd42, KEY_RECORD }, + { 0xff00a55a, KEY_STOP }, }; static struct rc_map_list lme2510_map = { -- cgit v1.2.2 From c6384c886dfed806f07ae2f8ba4d3740b57cde9c Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 3 Mar 2011 16:03:31 -0300 Subject: [media] via-camera: Fix OLPC serial check The code that checks the OLPC serial port is never built at the moment, because CONFIG_OLPC_XO_1_5 doesn't exist and probably won't be added. Fix it so that it gets compiled in, only executes on OLPC laptops, and move the check into the probe routine. The compiler is smart enough to eliminate this code when CONFIG_OLPC=n (due to machine_is_olpc() always returning false). Signed-off-by: Daniel Drake Acked-by: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/via-camera.c | 83 ++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c index 3f0146fcf752..8c780c2d937b 100644 --- a/drivers/media/video/via-camera.c +++ b/drivers/media/video/via-camera.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "via-camera.h" @@ -38,14 +39,12 @@ MODULE_PARM_DESC(flip_image, "If set, the sensor will be instructed to flip the image " "vertically."); -#ifdef CONFIG_OLPC_XO_1_5 static int override_serial; module_param(override_serial, bool, 0444); MODULE_PARM_DESC(override_serial, "The camera driver will normally refuse to load if " "the XO 1.5 serial port is enabled. Set this option " - "to force the issue."); -#endif + "to force-enable the camera."); /* * Basic window sizes. @@ -1317,6 +1316,37 @@ static struct video_device viacam_v4l_template = { .release = video_device_release_empty, /* Check this */ }; +/* + * The OLPC folks put the serial port on the same pin as + * the camera. They also get grumpy if we break the + * serial port and keep them from using it. So we have + * to check the serial enable bit and not step on it. + */ +#define VIACAM_SERIAL_DEVFN 0x88 +#define VIACAM_SERIAL_CREG 0x46 +#define VIACAM_SERIAL_BIT 0x40 + +static __devinit bool viacam_serial_is_enabled(void) +{ + struct pci_bus *pbus = pci_find_bus(0, 0); + u8 cbyte; + + pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN, + VIACAM_SERIAL_CREG, &cbyte); + if ((cbyte & VIACAM_SERIAL_BIT) == 0) + return false; /* Not enabled */ + if (override_serial == 0) { + printk(KERN_NOTICE "Via camera: serial port is enabled, " \ + "refusing to load.\n"); + printk(KERN_NOTICE "Specify override_serial=1 to force " \ + "module loading.\n"); + return true; + } + printk(KERN_NOTICE "Via camera: overriding serial port\n"); + pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN, + VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT); + return false; +} static __devinit int viacam_probe(struct platform_device *pdev) { @@ -1348,6 +1378,10 @@ static __devinit int viacam_probe(struct platform_device *pdev) printk(KERN_ERR "viacam: No I/O memory, so no pictures\n"); return -ENOMEM; } + + if (machine_is_olpc() && viacam_serial_is_enabled()) + return -EBUSY; + /* * Basic structure initialization. */ @@ -1459,7 +1493,6 @@ static __devexit int viacam_remove(struct platform_device *pdev) return 0; } - static struct platform_driver viacam_driver = { .driver = { .name = "viafb-camera", @@ -1468,50 +1501,8 @@ static struct platform_driver viacam_driver = { .remove = viacam_remove, }; - -#ifdef CONFIG_OLPC_XO_1_5 -/* - * The OLPC folks put the serial port on the same pin as - * the camera. They also get grumpy if we break the - * serial port and keep them from using it. So we have - * to check the serial enable bit and not step on it. - */ -#define VIACAM_SERIAL_DEVFN 0x88 -#define VIACAM_SERIAL_CREG 0x46 -#define VIACAM_SERIAL_BIT 0x40 - -static __devinit int viacam_check_serial_port(void) -{ - struct pci_bus *pbus = pci_find_bus(0, 0); - u8 cbyte; - - pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN, - VIACAM_SERIAL_CREG, &cbyte); - if ((cbyte & VIACAM_SERIAL_BIT) == 0) - return 0; /* Not enabled */ - if (override_serial == 0) { - printk(KERN_NOTICE "Via camera: serial port is enabled, " \ - "refusing to load.\n"); - printk(KERN_NOTICE "Specify override_serial=1 to force " \ - "module loading.\n"); - return -EBUSY; - } - printk(KERN_NOTICE "Via camera: overriding serial port\n"); - pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN, - VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT); - return 0; -} -#endif - - - - static int viacam_init(void) { -#ifdef CONFIG_OLPC_XO_1_5 - if (viacam_check_serial_port()) - return -EBUSY; -#endif return platform_driver_register(&viacam_driver); } module_init(viacam_init); -- cgit v1.2.2 From bf512b2d9c39af31507f485b15b9b40e2a5c499c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 6 Mar 2011 10:40:11 -0300 Subject: [media] stv0367: signedness bug in stv0367_get_tuner_freq() We use err to store negative error codes so it should be signed. And if we return an error from stv0367_get_tuner_freq() that needs to be handled properly as well. (param->frequency is a u32). Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0367.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index 120fed8229a8..0ddcf7e76704 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -913,7 +913,7 @@ static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe) struct dvb_frontend_ops *frontend_ops = NULL; struct dvb_tuner_ops *tuner_ops = NULL; u32 freq = 0; - u32 err = 0; + int err = 0; dprintk("%s:\n", __func__); @@ -1940,7 +1940,7 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe, int constell = 0,/* snr = 0,*/ Data = 0; param->frequency = stv0367_get_tuner_freq(fe); - if (param->frequency < 0) + if ((int)param->frequency < 0) param->frequency = c->frequency; constell = stv0367_readbits(state, F367TER_TPS_CONST); -- cgit v1.2.2 From bc4b18c6f536de3733e247b07adcc9ea3f5684dd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 6 Mar 2011 10:41:23 -0300 Subject: [media] stv0367: typo in function parameter The CellsCoeffs arrays are [3][6][5] not [2][6][5]. Signed-off-by: Dan Carpenter Cc: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0367.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index 0ddcf7e76704..4e0e6a873b8c 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -1046,7 +1046,7 @@ static u32 stv0367ter_get_mclk(struct stv0367_state *state, u32 ExtClk_Hz) } static int stv0367ter_filt_coeff_init(struct stv0367_state *state, - u16 CellsCoeffs[2][6][5], u32 DemodXtal) + u16 CellsCoeffs[3][6][5], u32 DemodXtal) { int i, j, k, freq; -- cgit v1.2.2 From 8c1476ffc0b820f6ca8cc0b3f50c8a0f57e8d82d Mon Sep 17 00:00:00 2001 From: Vadim Solomin Date: Sun, 6 Mar 2011 13:00:38 -0300 Subject: [media] saa7134-input: key up events not sent after suspend/resume On my AverMedia AverTV Studio 507, key up events are no longer sent after a suspend-to-disk/resume cycle, resulting in "stuck" keys. Apparently, for key up events to be generated, a certain GPIO pin must be set. Currently it's set in saa7134_input_init1(), but that function is not called on device resume. I suggest that code be moved to __saa7134_ir_start(), which is called both on init and resume. Signed-off-by: Vadim Solomin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/saa7134-input.c | 49 +++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index c9eff0336aa6..790d66703fea 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -414,6 +414,41 @@ static int __saa7134_ir_start(void *priv) if (ir->running) return 0; + /* Moved here from saa7134_input_init1() because the latter + * is not called on device resume */ + switch (dev->board) { + case SAA7134_BOARD_MD2819: + case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: + case SAA7134_BOARD_AVERMEDIA_305: + case SAA7134_BOARD_AVERMEDIA_307: + case SAA7134_BOARD_AVERMEDIA_STUDIO_305: + case SAA7134_BOARD_AVERMEDIA_STUDIO_505: + case SAA7134_BOARD_AVERMEDIA_STUDIO_307: + case SAA7134_BOARD_AVERMEDIA_STUDIO_507: + case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA: + case SAA7134_BOARD_AVERMEDIA_GO_007_FM: + case SAA7134_BOARD_AVERMEDIA_M102: + case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS: + /* Without this we won't receive key up events */ + saa_setb(SAA7134_GPIO_GPMODE0, 0x4); + saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); + break; + case SAA7134_BOARD_AVERMEDIA_777: + case SAA7134_BOARD_AVERMEDIA_A16AR: + /* Without this we won't receive key up events */ + saa_setb(SAA7134_GPIO_GPMODE1, 0x1); + saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); + break; + case SAA7134_BOARD_AVERMEDIA_A16D: + /* Without this we won't receive key up events */ + saa_setb(SAA7134_GPIO_GPMODE1, 0x1); + saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); + break; + case SAA7134_BOARD_GOTVIEW_7135: + saa_setb(SAA7134_GPIO_GPMODE1, 0x80); + break; + } + ir->running = true; ir->active = false; @@ -548,9 +583,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keycode = 0x0007C8; mask_keydown = 0x000010; polling = 50; // ms - /* Set GPIO pin2 to high to enable the IR controller */ - saa_setb(SAA7134_GPIO_GPMODE0, 0x4); - saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); + /* GPIO stuff moved to __saa7134_ir_start() */ break; case SAA7134_BOARD_AVERMEDIA_M135A: ir_codes = RC_MAP_AVERMEDIA_M135A; @@ -572,18 +605,14 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keycode = 0x02F200; mask_keydown = 0x000400; polling = 50; // ms - /* Without this we won't receive key up events */ - saa_setb(SAA7134_GPIO_GPMODE1, 0x1); - saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); + /* GPIO stuff moved to __saa7134_ir_start() */ break; case SAA7134_BOARD_AVERMEDIA_A16D: ir_codes = RC_MAP_AVERMEDIA_A16D; mask_keycode = 0x02F200; mask_keydown = 0x000400; polling = 50; /* ms */ - /* Without this we won't receive key up events */ - saa_setb(SAA7134_GPIO_GPMODE1, 0x1); - saa_setb(SAA7134_GPIO_GPSTATUS1, 0x1); + /* GPIO stuff moved to __saa7134_ir_start() */ break; case SAA7134_BOARD_KWORLD_TERMINATOR: ir_codes = RC_MAP_PIXELVIEW; @@ -635,7 +664,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keycode = 0x0003CC; mask_keydown = 0x000010; polling = 5; /* ms */ - saa_setb(SAA7134_GPIO_GPMODE1, 0x80); + /* GPIO stuff moved to __saa7134_ir_start() */ break; case SAA7134_BOARD_VIDEOMATE_TV_PVR: case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: -- cgit v1.2.2 From 022654930891c7ddfdb1ea34d6c4af9d1096bf91 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 29 Dec 2010 10:05:02 -0300 Subject: [media] v4l2_prio: move from v4l2-common to v4l2-dev We are going to move priority handling into the v4l2 core. As a consequence the v4l2_prio helper functions need to be moved into the core videodev module as well to prevent circular dependencies. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-common.c | 63 -------------------------------------- drivers/media/video/v4l2-dev.c | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 940b5db3463e..06b9f9f82013 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -80,69 +80,6 @@ MODULE_LICENSE("GPL"); * Video Standard Operations (contributed by Michael Schimek) */ - -/* ----------------------------------------------------------------- */ -/* priority handling */ - -#define V4L2_PRIO_VALID(val) (val == V4L2_PRIORITY_BACKGROUND || \ - val == V4L2_PRIORITY_INTERACTIVE || \ - val == V4L2_PRIORITY_RECORD) - -void v4l2_prio_init(struct v4l2_prio_state *global) -{ - memset(global, 0, sizeof(*global)); -} -EXPORT_SYMBOL(v4l2_prio_init); - -int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, - enum v4l2_priority new) -{ - if (!V4L2_PRIO_VALID(new)) - return -EINVAL; - if (*local == new) - return 0; - - atomic_inc(&global->prios[new]); - if (V4L2_PRIO_VALID(*local)) - atomic_dec(&global->prios[*local]); - *local = new; - return 0; -} -EXPORT_SYMBOL(v4l2_prio_change); - -void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local) -{ - v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT); -} -EXPORT_SYMBOL(v4l2_prio_open); - -void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local) -{ - if (V4L2_PRIO_VALID(local)) - atomic_dec(&global->prios[local]); -} -EXPORT_SYMBOL(v4l2_prio_close); - -enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) -{ - if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0) - return V4L2_PRIORITY_RECORD; - if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0) - return V4L2_PRIORITY_INTERACTIVE; - if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0) - return V4L2_PRIORITY_BACKGROUND; - return V4L2_PRIORITY_UNSET; -} -EXPORT_SYMBOL(v4l2_prio_max); - -int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local) -{ - return (local < v4l2_prio_max(global)) ? -EBUSY : 0; -} -EXPORT_SYMBOL(v4l2_prio_check); - -/* ----------------------------------------------------------------- */ - /* Helper functions for control handling */ /* Check for correctness of the ctrl's value based on the data from diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index e405b8094b94..65d546f35ef4 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -182,6 +182,70 @@ struct video_device *video_devdata(struct file *file) } EXPORT_SYMBOL(video_devdata); + +/* Priority handling */ + +static inline bool prio_is_valid(enum v4l2_priority prio) +{ + return prio == V4L2_PRIORITY_BACKGROUND || + prio == V4L2_PRIORITY_INTERACTIVE || + prio == V4L2_PRIORITY_RECORD; +} + +void v4l2_prio_init(struct v4l2_prio_state *global) +{ + memset(global, 0, sizeof(*global)); +} +EXPORT_SYMBOL(v4l2_prio_init); + +int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, + enum v4l2_priority new) +{ + if (!prio_is_valid(new)) + return -EINVAL; + if (*local == new) + return 0; + + atomic_inc(&global->prios[new]); + if (prio_is_valid(*local)) + atomic_dec(&global->prios[*local]); + *local = new; + return 0; +} +EXPORT_SYMBOL(v4l2_prio_change); + +void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local) +{ + v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT); +} +EXPORT_SYMBOL(v4l2_prio_open); + +void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local) +{ + if (prio_is_valid(local)) + atomic_dec(&global->prios[local]); +} +EXPORT_SYMBOL(v4l2_prio_close); + +enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) +{ + if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0) + return V4L2_PRIORITY_RECORD; + if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0) + return V4L2_PRIORITY_INTERACTIVE; + if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0) + return V4L2_PRIORITY_BACKGROUND; + return V4L2_PRIORITY_UNSET; +} +EXPORT_SYMBOL(v4l2_prio_max); + +int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local) +{ + return (local < v4l2_prio_max(global)) ? -EBUSY : 0; +} +EXPORT_SYMBOL(v4l2_prio_check); + + static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off) { -- cgit v1.2.2 From 0f62fd6a2fa12d6a63cbb18f9e30b05345f636f6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 24 Feb 2011 10:42:24 -0300 Subject: [media] v4l2: add v4l2_prio_state to v4l2_device and video_device Integrate the v4l2_prio_state into the core, ready for use. One struct v4l2_prio_state is added to v4l2_device and a pointer to a prio state is added to video_device. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-dev.c | 6 ++++++ drivers/media/video/v4l2-device.c | 1 + 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 65d546f35ef4..6b1ef85d8cc8 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -573,6 +573,12 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->parent = vdev->v4l2_dev->dev; if (vdev->ctrl_handler == NULL) vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; + /* If the prio state pointer is NULL, and if the driver doesn't + handle priorities itself, then use the v4l2_device prio + state. */ + if (vdev->prio == NULL && vdev->ioctl_ops && + vdev->ioctl_ops->vidioc_s_priority == NULL) + vdev->prio = &vdev->v4l2_dev->prio; } /* Part 2: find a free minor, device node number and device index. */ diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index a1afda352d08..fd7a445ce34c 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -36,6 +36,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_prio_init(&v4l2_dev->prio); v4l2_dev->dev = dev; if (dev == NULL) { /* If dev == NULL, then name must be filled in by the caller */ -- cgit v1.2.2 From fc5602be7ca5b55174c5d6595089718779b28dfa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 29 Dec 2010 13:36:50 -0300 Subject: [media] v4l2-fh: implement v4l2_priority support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-fh.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c index d78f184f40c5..78a1608a09d6 100644 --- a/drivers/media/video/v4l2-fh.c +++ b/drivers/media/video/v4l2-fh.c @@ -33,6 +33,8 @@ int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) fh->vdev = vdev; INIT_LIST_HEAD(&fh->list); set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags); + fh->prio = V4L2_PRIORITY_UNSET; + BUG_ON(vdev->prio == NULL); /* * fh->events only needs to be initialized if the driver @@ -51,6 +53,7 @@ void v4l2_fh_add(struct v4l2_fh *fh) { unsigned long flags; + v4l2_prio_open(fh->vdev->prio, &fh->prio); spin_lock_irqsave(&fh->vdev->fh_lock, flags); list_add(&fh->list, &fh->vdev->fh_list); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); @@ -64,6 +67,7 @@ void v4l2_fh_del(struct v4l2_fh *fh) spin_lock_irqsave(&fh->vdev->fh_lock, flags); list_del_init(&fh->list); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); + v4l2_prio_close(fh->vdev->prio, fh->prio); } EXPORT_SYMBOL_GPL(v4l2_fh_del); -- cgit v1.2.2 From 73cb42068cff419e72456940c713ceb5efa68c2a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 Jan 2011 09:36:04 -0300 Subject: [media] v4l2-fh: add v4l2_fh_open and v4l2_fh_release helper functions Add two new functions: v4l2_fh_open allocates and initializes a struct v4l2_fh based on a struct file pointer and v4l2_fh_release releases and frees a struct v4l2_fh. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-fh.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c index 78a1608a09d6..27242e5ca431 100644 --- a/drivers/media/video/v4l2-fh.c +++ b/drivers/media/video/v4l2-fh.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -60,6 +61,20 @@ void v4l2_fh_add(struct v4l2_fh *fh) } EXPORT_SYMBOL_GPL(v4l2_fh_add); +int v4l2_fh_open(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct v4l2_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); + + filp->private_data = fh; + if (fh == NULL) + return -ENOMEM; + v4l2_fh_init(fh, vdev); + v4l2_fh_add(fh); + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fh_open); + void v4l2_fh_del(struct v4l2_fh *fh) { unsigned long flags; @@ -81,3 +96,16 @@ void v4l2_fh_exit(struct v4l2_fh *fh) v4l2_event_free(fh); } EXPORT_SYMBOL_GPL(v4l2_fh_exit); + +int v4l2_fh_release(struct file *filp) +{ + struct v4l2_fh *fh = filp->private_data; + + if (fh) { + v4l2_fh_del(fh); + v4l2_fh_exit(fh); + kfree(fh); + } + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fh_release); -- cgit v1.2.2 From dfddb2441f39e8c0254504516be35b854addf6fa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 8 Jan 2011 09:38:02 -0300 Subject: [media] v4l2-fh: add v4l2_fh_is_singular Several drivers need to do something when the first filehandle is opened or the last filehandle is closed. Most implement some use count mechanism, but if they use v4l2_fh, then you can also just check if this is the only filehandle for the device node. A simple helper function can do this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-fh.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c index 27242e5ca431..543b3fe6784e 100644 --- a/drivers/media/video/v4l2-fh.c +++ b/drivers/media/video/v4l2-fh.c @@ -109,3 +109,17 @@ int v4l2_fh_release(struct file *filp) return 0; } EXPORT_SYMBOL_GPL(v4l2_fh_release); + +int v4l2_fh_is_singular(struct v4l2_fh *fh) +{ + unsigned long flags; + int is_singular; + + if (fh == NULL || fh->vdev == NULL) + return 0; + spin_lock_irqsave(&fh->vdev->fh_lock, flags); + is_singular = list_is_singular(&fh->list); + spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); + return is_singular; +} +EXPORT_SYMBOL_GPL(v4l2_fh_is_singular); -- cgit v1.2.2 From 99cd47bc733436da282016e629eef6baa0f6047c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Mar 2011 19:00:56 -0300 Subject: [media] v4l2-ioctl: add priority handling support Drivers that use v4l2_fh can now use the core framework support of g/s_priority. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 3 +- drivers/media/video/cpia2/cpia2_v4l.c | 3 +- drivers/media/video/cx18/cx18-ioctl.c | 3 +- drivers/media/video/davinci/vpfe_capture.c | 2 +- drivers/media/video/ivtv/ivtv-ioctl.c | 3 +- drivers/media/video/meye.c | 3 +- drivers/media/video/mxb.c | 3 +- drivers/media/video/pwc/pwc-v4l.c | 3 +- drivers/media/video/v4l2-ioctl.c | 64 ++++++++++++++++++++++++++---- 9 files changed, 72 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 726d367ad8d0..444b4cf7e65c 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -224,7 +224,8 @@ static int radio_si4713_s_frequency(struct file *file, void *p, s_frequency, vf); } -static long radio_si4713_default(struct file *file, void *p, int cmd, void *arg) +static long radio_si4713_default(struct file *file, void *p, + bool valid_prio, int cmd, void *arg) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, ioctl, cmd, arg); diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 363fe098b748..5111bbcefad5 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -395,7 +395,8 @@ static int sync(struct camera_data *cam, int frame_nr) * *****************************************************************************/ -static long cpia2_default(struct file *file, void *fh, int cmd, void *arg) +static long cpia2_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) { struct camera_data *cam = video_drvdata(file); __u32 gpio_val; diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 36b018c943e5..08ed75de1912 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -1057,7 +1057,8 @@ static int cx18_log_status(struct file *file, void *fh) return 0; } -static long cx18_default(struct file *file, void *fh, int cmd, void *arg) +static long cx18_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) { struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 353eadaa823e..71e961e53a56 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -1719,7 +1719,7 @@ unlock_out: static long vpfe_param_handler(struct file *file, void *priv, - int cmd, void *param) + bool valid_prio, int cmd, void *param) { struct vpfe_device *vpfe_dev = video_drvdata(file); int ret = 0; diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index b686da5e4326..d34a326c0ef0 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1795,7 +1795,8 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) return 0; } -static long ivtv_default(struct file *file, void *fh, int cmd, void *arg) +static long ivtv_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) { struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 48d2c2419c13..b09a3c80a15e 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -1547,7 +1547,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) return 0; } -static long vidioc_default(struct file *file, void *fh, int cmd, void *arg) +static long vidioc_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) { switch (cmd) { case MEYEIOC_G_PARAMS: diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index e8846a09b026..0b3850023505 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -643,7 +643,8 @@ static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_regist } #endif -static long vidioc_default(struct file *file, void *fh, int cmd, void *arg) +static long vidioc_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 68a5313a52d5..aa87e462a958 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c @@ -860,7 +860,8 @@ static int pwc_enum_frameintervals(struct file *file, void *fh, return 0; } -static long pwc_default(struct file *file, void *fh, int cmd, void *arg) +static long pwc_default(struct file *file, void *fh, bool valid_prio, + int cmd, void *arg) { struct pwc_device *pdev = video_drvdata(file); diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index db6ec3868347..3e6b6fa5771a 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #define dbgarg(cmd, fmt, arg...) \ @@ -538,6 +539,7 @@ static long __video_do_ioctl(struct file *file, struct video_device *vfd = video_devdata(file); const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; void *fh = file->private_data; + struct v4l2_fh *vfh = NULL; struct v4l2_format f_copy; long ret = -EINVAL; @@ -553,6 +555,43 @@ static long __video_do_ioctl(struct file *file, printk(KERN_CONT "\n"); } + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) + vfh = file->private_data; + + if (vfh && !ops->vidioc_s_priority) { + switch (cmd) { + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_OUTPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + case VIDIOC_S_FMT: + case VIDIOC_S_CROP: + case VIDIOC_S_AUDIO: + case VIDIOC_S_AUDOUT: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_S_FBUF: + case VIDIOC_S_PRIORITY: + case VIDIOC_S_DV_PRESET: + case VIDIOC_S_DV_TIMINGS: + case VIDIOC_S_JPEGCOMP: + case VIDIOC_S_MODULATOR: + case VIDIOC_S_PARM: + case VIDIOC_S_HW_FREQ_SEEK: + case VIDIOC_ENCODER_CMD: + case VIDIOC_OVERLAY: + case VIDIOC_REQBUFS: + case VIDIOC_STREAMON: + case VIDIOC_STREAMOFF: + ret = v4l2_prio_check(vfd->prio, vfh->prio); + if (ret) + goto exit_prio; + ret = -EINVAL; + break; + } + } + switch (cmd) { /* --- capabilities ------------------------------------------ */ @@ -579,9 +618,12 @@ static long __video_do_ioctl(struct file *file, { enum v4l2_priority *p = arg; - if (!ops->vidioc_g_priority) - break; - ret = ops->vidioc_g_priority(file, fh, p); + if (ops->vidioc_g_priority) { + ret = ops->vidioc_g_priority(file, fh, p); + } else if (vfh) { + *p = v4l2_prio_max(&vfd->v4l2_dev->prio); + ret = 0; + } if (!ret) dbgarg(cmd, "priority is %d\n", *p); break; @@ -590,10 +632,13 @@ static long __video_do_ioctl(struct file *file, { enum v4l2_priority *p = arg; - if (!ops->vidioc_s_priority) - break; + if (!ops->vidioc_s_priority && vfh == NULL) + break; dbgarg(cmd, "setting priority to %d\n", *p); - ret = ops->vidioc_s_priority(file, fh, *p); + if (ops->vidioc_s_priority) + ret = ops->vidioc_s_priority(file, fh, *p); + else + ret = v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p); break; } @@ -2138,13 +2183,18 @@ static long __video_do_ioctl(struct file *file, } default: { + bool valid_prio = true; + if (!ops->vidioc_default) break; - ret = ops->vidioc_default(file, fh, cmd, arg); + if (vfh && !ops->vidioc_s_priority) + valid_prio = v4l2_prio_check(vfd->prio, vfh->prio) >= 0; + ret = ops->vidioc_default(file, fh, valid_prio, cmd, arg); break; } } /* switch */ +exit_prio: if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { if (ret < 0) { v4l_print_ioctl(vfd->name, cmd); -- cgit v1.2.2 From cc0a2d411f158c61af34d056191c7b4669913ddc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Mar 2011 19:03:41 -0300 Subject: [media] ivtv: convert to core priority handling Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-driver.h | 2 -- drivers/media/video/ivtv/ivtv-fileops.c | 2 -- drivers/media/video/ivtv/ivtv-ioctl.c | 56 +++++++++------------------------ 3 files changed, 15 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 04bacdbd10bb..84bdf0f42a8e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -383,7 +383,6 @@ struct ivtv_open_id { u32 open_id; /* unique ID for this file descriptor */ int type; /* stream type */ int yuv_frames; /* 1: started OUT_UDMA_YUV output mode */ - enum v4l2_priority prio; /* priority */ struct ivtv *itv; }; @@ -710,7 +709,6 @@ struct ivtv { /* Miscellaneous */ u32 open_id; /* incremented each time an open occurs, is >= 1 */ - struct v4l2_prio_state prio; /* priority state */ int search_pack_header; /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */ int speed; /* current playback speed setting */ u8 speed_mute_audio; /* 1 if audio should be muted when fast forward */ diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index c57a58523ca8..4463bf4ec4ee 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -856,7 +856,6 @@ int ivtv_v4l2_close(struct file *filp) IVTV_DEBUG_FILE("close %s\n", s->name); - v4l2_prio_close(&itv->prio, id->prio); v4l2_fh_del(fh); v4l2_fh_exit(fh); @@ -973,7 +972,6 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) } item->itv = itv; item->type = s->type; - v4l2_prio_open(&itv->prio, &item->prio); item->open_id = itv->open_id++; filp->private_data = &item->fh; diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index d34a326c0ef0..b443c03d21de 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -750,23 +750,6 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register } #endif -static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p) -{ - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; - - *p = v4l2_prio_max(&itv->prio); - - return 0; -} - -static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio) -{ - struct ivtv_open_id *id = fh; - struct ivtv *itv = id->itv; - - return v4l2_prio_change(&itv->prio, &id->prio, prio); -} - static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; @@ -1800,6 +1783,21 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio, { struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + if (!valid_prio) { + switch (cmd) { + case VIDEO_PLAY: + case VIDEO_STOP: + case VIDEO_FREEZE: + case VIDEO_CONTINUE: + case VIDEO_COMMAND: + case VIDEO_SELECT_SOURCE: + case AUDIO_SET_MUTE: + case AUDIO_CHANNEL_SELECT: + case AUDIO_BILINGUAL_CHANNEL_SELECT: + return -EBUSY; + } + } + switch (cmd) { case VIDIOC_INT_RESET: { u32 val = *(u32 *)arg; @@ -1837,30 +1835,8 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp, unsigned int cmd, unsigned long arg) { struct video_device *vfd = video_devdata(filp); - struct ivtv_open_id *id = fh2id(filp->private_data); long ret; - /* check priority */ - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_OUTPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - case VIDIOC_S_FMT: - case VIDIOC_S_CROP: - case VIDIOC_S_AUDIO: - case VIDIOC_S_AUDOUT: - case VIDIOC_S_EXT_CTRLS: - case VIDIOC_S_FBUF: - case VIDIOC_S_PRIORITY: - case VIDIOC_OVERLAY: - ret = v4l2_prio_check(&itv->prio, id->prio); - if (ret) - return ret; - } - if (ivtv_debug & IVTV_DBGFLG_IOCTL) vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; ret = video_ioctl2(filp, cmd, arg); @@ -1885,8 +1861,6 @@ long ivtv_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { .vidioc_querycap = ivtv_querycap, - .vidioc_g_priority = ivtv_g_priority, - .vidioc_s_priority = ivtv_s_priority, .vidioc_s_audio = ivtv_s_audio, .vidioc_g_audio = ivtv_g_audio, .vidioc_enumaudio = ivtv_enumaudio, -- cgit v1.2.2 From 0b5f265a88d89cbbf8abc42ca3311cb3219162ab Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 12 Mar 2011 06:35:33 -0300 Subject: [media] cx18: use v4l2_fh as preparation for adding core priority support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.h | 12 ++++++ drivers/media/video/cx18/cx18-fileops.c | 18 ++++++--- drivers/media/video/cx18/cx18-ioctl.c | 72 ++++++++++++++++----------------- 3 files changed, 61 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index de2457741e26..30a857473e54 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include "cx18-mailbox.h" @@ -405,12 +406,23 @@ struct cx18_stream { }; struct cx18_open_id { + struct v4l2_fh fh; u32 open_id; int type; enum v4l2_priority prio; struct cx18 *cx; }; +static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) +{ + return container_of(fh, struct cx18_open_id, fh); +} + +static inline struct cx18_open_id *file2id(struct file *file) +{ + return fh2id(file->private_data); +} + /* forward declaration of struct defined in cx18-cards.h */ struct cx18_card; diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 98ef33e4326a..1172d68925c0 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -585,7 +585,7 @@ start_failed: ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { - struct cx18_open_id *id = filp->private_data; + struct cx18_open_id *id = file2id(filp); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; int rc; @@ -602,7 +602,7 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) { - struct cx18_open_id *id = filp->private_data; + struct cx18_open_id *id = file2id(filp); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); @@ -676,13 +676,16 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end) int cx18_v4l2_close(struct file *filp) { - struct cx18_open_id *id = filp->private_data; + struct v4l2_fh *fh = filp->private_data; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; CX18_DEBUG_IOCTL("close() of %s\n", s->name); v4l2_prio_close(&cx->prio, id->prio); + v4l2_fh_del(fh); + v4l2_fh_exit(fh); /* Easy case first: this stream was never claimed by us */ if (s->id != id->open_id) { @@ -728,22 +731,25 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) CX18_DEBUG_FILE("open %s\n", s->name); /* Allocate memory */ - item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL); + item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL); if (NULL == item) { CX18_DEBUG_WARN("nomem on v4l2 open\n"); return -ENOMEM; } + v4l2_fh_init(&item->fh, s->video_dev); + item->cx = cx; item->type = s->type; v4l2_prio_open(&cx->prio, &item->prio); item->open_id = cx->open_id++; - filp->private_data = item; + filp->private_data = &item->fh; if (item->type == CX18_ENC_STREAM_TYPE_RAD) { /* Try to claim this stream */ if (cx18_claim_stream(item, item->type)) { /* No, it's already in use */ + v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; } @@ -753,6 +759,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) /* switching to radio while capture is in progress is not polite */ cx18_release_stream(s); + v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; } @@ -769,6 +776,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) /* Done! Unmute and continue. */ cx18_unmute(cx); } + v4l2_fh_add(&item->fh); return 0; } diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 08ed75de1912..6624ec2419d3 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -148,7 +148,7 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) static int cx18_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -173,7 +173,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; vbifmt->sampling_rate = 27000000; @@ -192,7 +192,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; /* sane, V4L2 spec compliant, defaults */ @@ -221,7 +221,7 @@ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -252,7 +252,7 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; @@ -271,7 +271,7 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; struct v4l2_mbus_framefmt mbus_fmt; int ret; @@ -303,7 +303,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int ret; @@ -337,7 +337,7 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int ret; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; @@ -372,7 +372,7 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; int err = 0; chip->ident = V4L2_IDENT_NONE; @@ -442,7 +442,7 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) static int cx18_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; if (v4l2_chip_match_host(®->match)) return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); @@ -454,7 +454,7 @@ static int cx18_g_register(struct file *file, void *fh, static int cx18_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; if (v4l2_chip_match_host(®->match)) return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); @@ -466,7 +466,7 @@ static int cx18_s_register(struct file *file, void *fh, static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = file2id(file)->cx; *p = v4l2_prio_max(&cx->prio); return 0; @@ -474,7 +474,7 @@ static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p) static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; return v4l2_prio_change(&cx->prio, &id->prio, prio); @@ -483,7 +483,7 @@ static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio) static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); @@ -496,14 +496,14 @@ static int cx18_querycap(struct file *file, void *fh, static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; return cx18_get_audio_input(cx, vin->index, vin); } static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; vin->index = cx->audio_input; return cx18_get_audio_input(cx, vin->index, vin); @@ -511,7 +511,7 @@ static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; if (vout->index >= cx->nof_audio_inputs) return -EINVAL; @@ -522,7 +522,7 @@ static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; /* set it to defaults from our table */ return cx18_get_input(cx, vin->index, vin); @@ -531,7 +531,7 @@ static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) static int cx18_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -546,7 +546,7 @@ static int cx18_cropcap(struct file *file, void *fh, static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int ret; @@ -562,7 +562,7 @@ static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -590,7 +590,7 @@ static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, static int cx18_g_input(struct file *file, void *fh, unsigned int *i) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; *i = cx->active_input; return 0; @@ -598,7 +598,7 @@ static int cx18_g_input(struct file *file, void *fh, unsigned int *i) int cx18_s_input(struct file *file, void *fh, unsigned int inp) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int ret; @@ -633,7 +633,7 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) static int cx18_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; if (vf->tuner != 0) return -EINVAL; @@ -644,7 +644,7 @@ static int cx18_g_frequency(struct file *file, void *fh, int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int ret; @@ -664,7 +664,7 @@ int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; *std = cx->std; return 0; @@ -672,7 +672,7 @@ static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int ret; @@ -713,7 +713,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; int ret; @@ -730,7 +730,7 @@ static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; if (vt->index != 0) return -EINVAL; @@ -751,7 +751,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; int f, l; @@ -872,7 +872,7 @@ static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, static int cx18_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; s32 tmp; struct cx18_mdl *mdl; @@ -919,7 +919,7 @@ static int cx18_g_enc_index(struct file *file, void *fh, static int cx18_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct cx18_open_id *id = fh; + struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; u32 h; @@ -980,7 +980,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh, static int cx18_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; switch (enc->cmd) { case V4L2_ENC_CMD_START: @@ -1012,7 +1012,7 @@ static int cx18_try_encoder_cmd(struct file *file, void *fh, static int cx18_log_status(struct file *file, void *fh) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -1060,7 +1060,7 @@ static int cx18_log_status(struct file *file, void *fh) static long cx18_default(struct file *file, void *fh, bool valid_prio, int cmd, void *arg) { - struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; + struct cx18 *cx = fh2id(fh)->cx; switch (cmd) { case VIDIOC_INT_RESET: { @@ -1082,7 +1082,7 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct video_device *vfd = video_devdata(filp); - struct cx18_open_id *id = filp->private_data; + struct cx18_open_id *id = file2id(filp); struct cx18 *cx = id->cx; long res; -- cgit v1.2.2 From a64bb4b7111e063154f97ff64dab03144cdfb5d9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 12 Mar 2011 06:36:08 -0300 Subject: [media] cx18: use core priority handling VIDIOC_S/G_PRIORITY handling is now done by the v4l2 core framework. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-driver.h | 2 -- drivers/media/video/cx18/cx18-fileops.c | 2 -- drivers/media/video/cx18/cx18-ioctl.c | 57 --------------------------------- 3 files changed, 61 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h index 30a857473e54..b86a740c68df 100644 --- a/drivers/media/video/cx18/cx18-driver.h +++ b/drivers/media/video/cx18/cx18-driver.h @@ -409,7 +409,6 @@ struct cx18_open_id { struct v4l2_fh fh; u32 open_id; int type; - enum v4l2_priority prio; struct cx18 *cx; }; @@ -605,7 +604,6 @@ struct cx18 { uninitialized value in the stream->id. */ u32 base_addr; - struct v4l2_prio_state prio; u8 card_rev; void __iomem *enc_mem, *reg_mem; diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 1172d68925c0..e9802d99439b 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -683,7 +683,6 @@ int cx18_v4l2_close(struct file *filp) CX18_DEBUG_IOCTL("close() of %s\n", s->name); - v4l2_prio_close(&cx->prio, id->prio); v4l2_fh_del(fh); v4l2_fh_exit(fh); @@ -740,7 +739,6 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) item->cx = cx; item->type = s->type; - v4l2_prio_open(&cx->prio, &item->prio); item->open_id = cx->open_id++; filp->private_data = &item->fh; diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 6624ec2419d3..86c30b9963e5 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -277,10 +277,6 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, int ret; int w, h; - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; - ret = cx18_try_fmt_vid_cap(file, fh, fmt); if (ret) return ret; @@ -307,10 +303,6 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, struct cx18 *cx = id->cx; int ret; - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; - /* * Changing the Encoder's Raw VBI parameters won't have any effect * if any analog capture is ongoing @@ -342,10 +334,6 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, int ret; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; - cx18_try_fmt_sliced_vbi_cap(file, fh, fmt); /* @@ -464,22 +452,6 @@ static int cx18_s_register(struct file *file, void *fh, } #endif -static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p) -{ - struct cx18 *cx = file2id(file)->cx; - - *p = v4l2_prio_max(&cx->prio); - return 0; -} - -static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio) -{ - struct cx18_open_id *id = file2id(file); - struct cx18 *cx = id->cx; - - return v4l2_prio_change(&cx->prio, &id->prio, prio); -} - static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { @@ -548,11 +520,6 @@ static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - int ret; - - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -600,11 +567,6 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - int ret; - - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; if (inp >= cx->nof_inputs) return -EINVAL; @@ -646,11 +608,6 @@ int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - int ret; - - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; if (vf->tuner != 0) return -EINVAL; @@ -674,11 +631,6 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - int ret; - - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; if ((*std & V4L2_STD_ALL) == 0) return -EINVAL; @@ -715,11 +667,6 @@ static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - int ret; - - ret = v4l2_prio_check(&cx->prio, id->prio); - if (ret) - return ret; if (vt->index != 0) return -EINVAL; @@ -1088,8 +1035,6 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, mutex_lock(&cx->serialize_lock); - /* FIXME - consolidate v4l2_prio_check()'s here */ - if (cx18_debug & CX18_DBGFLG_IOCTL) vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; res = video_ioctl2(filp, cmd, arg); @@ -1100,8 +1045,6 @@ long cx18_v4l2_ioctl(struct file *filp, unsigned int cmd, static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_querycap = cx18_querycap, - .vidioc_g_priority = cx18_g_priority, - .vidioc_s_priority = cx18_s_priority, .vidioc_s_audio = cx18_s_audio, .vidioc_g_audio = cx18_g_audio, .vidioc_enumaudio = cx18_enumaudio, -- cgit v1.2.2 From bedf8bcf6b4f90a6e31add3721a2e71877289381 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 12 Mar 2011 06:37:19 -0300 Subject: [media] v4l2-device: add kref and a release function The video_device struct has proper ref counting and its release function will be called when the last user releases it. But no such support was available for struct v4l2_device. This made it hard to determine when a USB driver can release the device if it has multiple device nodes. With one device node it is easy of course, since when the device node is released, the whole device can be released. This patch adds refcounting to v4l2_device. When registering device nodes the v4l2_device refcount will be increased, when releasing device nodes it will be decreased. The (optional) release function will be called when the last device node was released. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-dev.c | 10 ++++++++++ drivers/media/video/v4l2-device.c | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 6b1ef85d8cc8..1898099ec65a 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -143,6 +143,7 @@ static inline void video_put(struct video_device *vdev) static void v4l2_device_release(struct device *cd) { struct video_device *vdev = to_video_device(cd); + struct v4l2_device *v4l2_dev = vdev->v4l2_dev; mutex_lock(&videodev_lock); if (video_device[vdev->minor] != vdev) { @@ -169,6 +170,10 @@ static void v4l2_device_release(struct device *cd) /* Release video_device and perform other cleanups as needed. */ vdev->release(vdev); + + /* Decrease v4l2_device refcount */ + if (v4l2_dev) + v4l2_device_put(v4l2_dev); } static struct class video_class = { @@ -676,6 +681,11 @@ int __video_register_device(struct video_device *vdev, int type, int nr, if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, name_base, nr, video_device_node_name(vdev)); + + /* Increase v4l2_device refcount */ + if (vdev->v4l2_dev) + v4l2_device_get(vdev->v4l2_dev); + #if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c index fd7a445ce34c..5aeaf876ba9b 100644 --- a/drivers/media/video/v4l2-device.c +++ b/drivers/media/video/v4l2-device.c @@ -37,6 +37,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) spin_lock_init(&v4l2_dev->lock); mutex_init(&v4l2_dev->ioctl_lock); v4l2_prio_init(&v4l2_dev->prio); + kref_init(&v4l2_dev->ref); v4l2_dev->dev = dev; if (dev == NULL) { /* If dev == NULL, then name must be filled in by the caller */ @@ -54,6 +55,21 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev) } EXPORT_SYMBOL_GPL(v4l2_device_register); +static void v4l2_device_release(struct kref *ref) +{ + struct v4l2_device *v4l2_dev = + container_of(ref, struct v4l2_device, ref); + + if (v4l2_dev->release) + v4l2_dev->release(v4l2_dev); +} + +int v4l2_device_put(struct v4l2_device *v4l2_dev) +{ + return kref_put(&v4l2_dev->ref, v4l2_device_release); +} +EXPORT_SYMBOL_GPL(v4l2_device_put); + int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, atomic_t *instance) { -- cgit v1.2.2 From e64d07c92daa5c7973c1d4433f939a4e0fa3beb9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 19 Dec 2010 18:54:08 -0300 Subject: [media] dsbr100: convert to unlocked_ioctl Use core-assisted locking so .ioctl can be replaced by .unlocked_ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/dsbr100.c | 79 +++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index ed9cd7ad0604..bf2dd6ff042a 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -148,7 +148,7 @@ struct dsbr100_device { struct v4l2_device v4l2_dev; u8 *transfer_buffer; - struct mutex lock; /* buffer locking */ + struct mutex v4l2_lock; int curfreq; int stereo; int removed; @@ -182,8 +182,6 @@ static int dsbr100_start(struct dsbr100_device *radio) int retval; int request; - mutex_lock(&radio->lock); - retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, @@ -207,11 +205,9 @@ static int dsbr100_start(struct dsbr100_device *radio) } radio->status = STARTED; - mutex_unlock(&radio->lock); return (radio->transfer_buffer)[0]; usb_control_msg_failed: - mutex_unlock(&radio->lock); dev_err(&radio->usbdev->dev, "%s - usb_control_msg returned %i, request %i\n", __func__, retval, request); @@ -225,8 +221,6 @@ static int dsbr100_stop(struct dsbr100_device *radio) int retval; int request; - mutex_lock(&radio->lock); - retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, @@ -250,11 +244,9 @@ static int dsbr100_stop(struct dsbr100_device *radio) } radio->status = STOPPED; - mutex_unlock(&radio->lock); return (radio->transfer_buffer)[0]; usb_control_msg_failed: - mutex_unlock(&radio->lock); dev_err(&radio->usbdev->dev, "%s - usb_control_msg returned %i, request %i\n", __func__, retval, request); @@ -269,8 +261,6 @@ static int dsbr100_setfreq(struct dsbr100_device *radio) int request; int freq = (radio->curfreq / 16 * 80) / 1000 + 856; - mutex_lock(&radio->lock); - retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), DSB100_TUNE, @@ -306,12 +296,10 @@ static int dsbr100_setfreq(struct dsbr100_device *radio) } radio->stereo = !((radio->transfer_buffer)[0] & 0x01); - mutex_unlock(&radio->lock); return (radio->transfer_buffer)[0]; usb_control_msg_failed: radio->stereo = -1; - mutex_unlock(&radio->lock); dev_err(&radio->usbdev->dev, "%s - usb_control_msg returned %i, request %i\n", __func__, retval, request); @@ -324,8 +312,6 @@ static void dsbr100_getstat(struct dsbr100_device *radio) { int retval; - mutex_lock(&radio->lock); - retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), USB_REQ_GET_STATUS, @@ -340,33 +326,8 @@ static void dsbr100_getstat(struct dsbr100_device *radio) } else { radio->stereo = !(radio->transfer_buffer[0] & 0x01); } - - mutex_unlock(&radio->lock); -} - -/* USB subsystem interface begins here */ - -/* - * Handle unplugging of the device. - * We call video_unregister_device in any case. - * The last function called in this procedure is - * usb_dsbr100_video_device_release - */ -static void usb_dsbr100_disconnect(struct usb_interface *intf) -{ - struct dsbr100_device *radio = usb_get_intfdata(intf); - - usb_set_intfdata (intf, NULL); - - mutex_lock(&radio->lock); - radio->removed = 1; - mutex_unlock(&radio->lock); - - video_unregister_device(&radio->videodev); - v4l2_device_disconnect(&radio->v4l2_dev); } - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { @@ -432,9 +393,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (radio->removed) return -EIO; - mutex_lock(&radio->lock); radio->curfreq = f->frequency; - mutex_unlock(&radio->lock); retval = dsbr100_setfreq(radio); if (retval < 0) @@ -548,12 +507,36 @@ static int vidioc_s_audio(struct file *file, void *priv, return 0; } +/* USB subsystem interface begins here */ + +/* + * Handle unplugging of the device. + * We call video_unregister_device in any case. + * The last function called in this procedure is + * usb_dsbr100_video_device_release + */ +static void usb_dsbr100_disconnect(struct usb_interface *intf) +{ + struct dsbr100_device *radio = usb_get_intfdata(intf); + + usb_set_intfdata(intf, NULL); + + mutex_lock(&radio->v4l2_lock); + radio->removed = 1; + mutex_unlock(&radio->v4l2_lock); + + video_unregister_device(&radio->videodev); + v4l2_device_disconnect(&radio->v4l2_dev); +} + + /* Suspend device - stop device. */ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) { struct dsbr100_device *radio = usb_get_intfdata(intf); int retval; + mutex_lock(&radio->v4l2_lock); if (radio->status == STARTED) { retval = dsbr100_stop(radio); if (retval < 0) @@ -564,11 +547,9 @@ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message) * we set status equal to STARTED. * On resume we will check status and run radio if needed. */ - - mutex_lock(&radio->lock); radio->status = STARTED; - mutex_unlock(&radio->lock); } + mutex_unlock(&radio->v4l2_lock); dev_info(&intf->dev, "going into suspend..\n"); @@ -581,11 +562,13 @@ static int usb_dsbr100_resume(struct usb_interface *intf) struct dsbr100_device *radio = usb_get_intfdata(intf); int retval; + mutex_lock(&radio->v4l2_lock); if (radio->status == STARTED) { retval = dsbr100_start(radio); if (retval < 0) dev_warn(&intf->dev, "dsbr100_start failed\n"); } + mutex_unlock(&radio->v4l2_lock); dev_info(&intf->dev, "coming out of suspend..\n"); @@ -605,7 +588,7 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev) /* File system interface */ static const struct v4l2_file_operations usb_dsbr100_fops = { .owner = THIS_MODULE, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { @@ -653,13 +636,13 @@ static int usb_dsbr100_probe(struct usb_interface *intf, return retval; } + mutex_init(&radio->v4l2_lock); strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name)); radio->videodev.v4l2_dev = v4l2_dev; radio->videodev.fops = &usb_dsbr100_fops; radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; radio->videodev.release = usb_dsbr100_video_device_release; - - mutex_init(&radio->lock); + radio->videodev.lock = &radio->v4l2_lock; radio->removed = 0; radio->usbdev = interface_to_usbdev(intf); -- cgit v1.2.2 From 13099294973b14f07915d0342af2be8fa0af589b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 17 Jan 2011 20:25:11 -0300 Subject: [media] dsbr100: ensure correct disconnect sequence Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/dsbr100.c | 59 +++++++++---------------------------------- 1 file changed, 12 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index bf2dd6ff042a..3d8cc425fa6b 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -129,7 +129,7 @@ devices, that would be 76 and 91. */ #define STARTED 0 #define STOPPED 1 -#define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev) +#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev) static int usb_dsbr100_probe(struct usb_interface *intf, const struct usb_device_id *id); @@ -151,7 +151,6 @@ struct dsbr100_device { struct mutex v4l2_lock; int curfreq; int stereo; - int removed; int status; }; @@ -346,10 +345,6 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct dsbr100_device *radio = video_drvdata(file); - /* safety check */ - if (radio->removed) - return -EIO; - if (v->index > 0) return -EINVAL; @@ -371,16 +366,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct dsbr100_device *radio = video_drvdata(file); - - /* safety check */ - if (radio->removed) - return -EIO; - - if (v->index > 0) - return -EINVAL; - - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, @@ -389,10 +375,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, struct dsbr100_device *radio = video_drvdata(file); int retval; - /* safety check */ - if (radio->removed) - return -EIO; - radio->curfreq = f->frequency; retval = dsbr100_setfreq(radio); @@ -406,10 +388,6 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct dsbr100_device *radio = video_drvdata(file); - /* safety check */ - if (radio->removed) - return -EIO; - f->type = V4L2_TUNER_RADIO; f->frequency = radio->curfreq; return 0; @@ -431,10 +409,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv, { struct dsbr100_device *radio = video_drvdata(file); - /* safety check */ - if (radio->removed) - return -EIO; - switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = radio->status; @@ -449,10 +423,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, struct dsbr100_device *radio = video_drvdata(file); int retval; - /* safety check */ - if (radio->removed) - return -EIO; - switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) { @@ -494,17 +464,13 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; - return 0; + return a->index ? -EINVAL : 0; } /* USB subsystem interface begins here */ @@ -519,14 +485,13 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf) { struct dsbr100_device *radio = usb_get_intfdata(intf); - usb_set_intfdata(intf, NULL); - + v4l2_device_get(&radio->v4l2_dev); mutex_lock(&radio->v4l2_lock); - radio->removed = 1; - mutex_unlock(&radio->v4l2_lock); - + usb_set_intfdata(intf, NULL); video_unregister_device(&radio->videodev); v4l2_device_disconnect(&radio->v4l2_dev); + mutex_unlock(&radio->v4l2_lock); + v4l2_device_put(&radio->v4l2_dev); } @@ -576,9 +541,9 @@ static int usb_dsbr100_resume(struct usb_interface *intf) } /* free data structures */ -static void usb_dsbr100_video_device_release(struct video_device *videodev) +static void usb_dsbr100_release(struct v4l2_device *v4l2_dev) { - struct dsbr100_device *radio = videodev_to_radio(videodev); + struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev); v4l2_device_unregister(&radio->v4l2_dev); kfree(radio->transfer_buffer); @@ -627,6 +592,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, } v4l2_dev = &radio->v4l2_dev; + v4l2_dev->release = usb_dsbr100_release; retval = v4l2_device_register(&intf->dev, v4l2_dev); if (retval < 0) { @@ -641,10 +607,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf, radio->videodev.v4l2_dev = v4l2_dev; radio->videodev.fops = &usb_dsbr100_fops; radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; - radio->videodev.release = usb_dsbr100_video_device_release; + radio->videodev.release = video_device_release_empty; radio->videodev.lock = &radio->v4l2_lock; - radio->removed = 0; radio->usbdev = interface_to_usbdev(intf); radio->curfreq = FREQ_MIN * FREQ_MUL; radio->status = STOPPED; -- cgit v1.2.2 From 2e4784d0d3a6167e905a49d0dafa40b022fa1a55 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Mar 2011 20:01:54 -0300 Subject: [media] vivi: convert to core priority handling Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/vivi.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index bd104d0ad36c..42500bf03a9c 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #define VIVI_MODULE_NAME "vivi" @@ -199,7 +200,6 @@ struct vivi_dev { enum v4l2_field field; unsigned int field_count; - unsigned int open_count; u8 bars[9][3]; u8 line[MAX_WIDTH * 4]; }; @@ -996,15 +996,6 @@ static int vivi_s_ctrl(struct v4l2_ctrl *ctrl) File operations for the device ------------------------------------------------------------------*/ -static int vivi_open(struct file *file) -{ - struct vivi_dev *dev = video_drvdata(file); - - dprintk(dev, 1, "%s, %p\n", __func__, file); - dev->open_count++; - return 0; -} - static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -1033,9 +1024,9 @@ static int vivi_close(struct file *file) dprintk(dev, 1, "close called (dev=%s), file %p\n", video_device_node_name(vdev), file); - if (--dev->open_count == 0) + if (v4l2_fh_is_singular_file(file)) vb2_queue_release(&dev->vb_vidq); - return 0; + return v4l2_fh_release(file); } static int vivi_mmap(struct file *file, struct vm_area_struct *vma) @@ -1128,7 +1119,7 @@ static const struct v4l2_ctrl_config vivi_ctrl_string = { static const struct v4l2_file_operations vivi_fops = { .owner = THIS_MODULE, - .open = vivi_open, + .open = v4l2_fh_open, .release = vivi_close, .read = vivi_read, .poll = vivi_poll, -- cgit v1.2.2 From 6aff72f6d511bcadbc71358ed17bc87edbf90716 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 12 Mar 2011 06:39:44 -0300 Subject: [media] ivtv: add missing v4l2_fh_exit Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-fileops.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index 4463bf4ec4ee..a7f54b010a5c 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -980,6 +980,7 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) /* Try to claim this stream */ if (ivtv_claim_stream(item, item->type)) { /* No, it's already in use */ + v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; } -- cgit v1.2.2 From 2f82441a8644287e5b647329cc30b590f6fd3714 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 12 Mar 2011 06:43:28 -0300 Subject: [media] ivtv: replace ugly casts with a proper container_of ivtv-ioctl cast the 'void *fh' directly to 'ivtv_open_id *'. This should be done properly with a contained_of since the 'void *fh' is really a 'struct v4l2_fh *'. It worked because the v4l2_fh field is also the first field in the ivtv_open_id struct, but it is not clean code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ivtv/ivtv-ioctl.c | 100 +++++++++++++++++----------------- 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index b443c03d21de..1689783cd19a 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -313,7 +313,7 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; vbifmt->reserved[0] = 0; @@ -334,7 +334,7 @@ static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -358,7 +358,7 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; vbifmt->sampling_rate = 27000000; @@ -377,7 +377,7 @@ static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; vbifmt->reserved[0] = 0; @@ -398,7 +398,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -439,7 +439,7 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; struct v4l2_window *winfmt = &fmt->fmt.win; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) @@ -463,7 +463,7 @@ static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_ static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -492,7 +492,7 @@ static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; if (id->type == IVTV_DEC_STREAM_TYPE_VBI) @@ -512,7 +512,7 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); s32 w = fmt->fmt.pix.width; s32 h = fmt->fmt.pix.height; int field = fmt->fmt.pix.field; @@ -546,7 +546,7 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; u32 chromakey = fmt->fmt.win.chromakey; u8 global_alpha = fmt->fmt.win.global_alpha; @@ -565,7 +565,7 @@ static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct v4l2_mbus_framefmt mbus_fmt; int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); @@ -594,7 +594,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) return -EBUSY; @@ -607,7 +607,7 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); @@ -625,7 +625,7 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; int ret = ivtv_try_fmt_vid_out(file, fh, fmt); @@ -670,7 +670,7 @@ static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); if (ret == 0) { @@ -683,7 +683,7 @@ static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_f static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; chip->ident = V4L2_IDENT_NONE; chip->revision = 0; @@ -727,7 +727,7 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (v4l2_chip_match_host(®->match)) return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg); @@ -739,7 +739,7 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (v4l2_chip_match_host(®->match)) return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg); @@ -752,7 +752,7 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); @@ -764,14 +764,14 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; return ivtv_get_audio_input(itv, vin->index, vin); } static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; vin->index = itv->audio_input; return ivtv_get_audio_input(itv, vin->index, vin); @@ -779,7 +779,7 @@ static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (vout->index >= itv->nof_audio_inputs) return -EINVAL; @@ -792,7 +792,7 @@ static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; /* set it to defaults from our table */ return ivtv_get_audio_output(itv, vin->index, vin); @@ -800,7 +800,7 @@ static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vi static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; vin->index = 0; return ivtv_get_audio_output(itv, vin->index, vin); @@ -808,14 +808,14 @@ static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; return ivtv_get_audio_output(itv, vout->index, vout); } static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; /* set it to defaults from our table */ return ivtv_get_input(itv, vin->index, vin); @@ -823,14 +823,14 @@ static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; return ivtv_get_output(itv, vout->index, vout); } static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; int streamtype; @@ -867,7 +867,7 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; int streamtype; @@ -893,7 +893,7 @@ static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; int streamtype; @@ -935,7 +935,7 @@ static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; static struct v4l2_fmtdesc formats[] = { { 0, 0, 0, @@ -963,7 +963,7 @@ static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdes static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; *i = itv->active_input; @@ -972,7 +972,7 @@ static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) int ivtv_s_input(struct file *file, void *fh, unsigned int inp) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (inp < 0 || inp >= itv->nof_inputs) return -EINVAL; @@ -1006,7 +1006,7 @@ int ivtv_s_input(struct file *file, void *fh, unsigned int inp) static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; @@ -1018,7 +1018,7 @@ static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (outp >= itv->card->nof_outputs) return -EINVAL; @@ -1040,7 +1040,7 @@ static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (vf->tuner != 0) return -EINVAL; @@ -1051,7 +1051,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency * int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (vf->tuner != 0) return -EINVAL; @@ -1065,7 +1065,7 @@ int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; *std = itv->std; return 0; @@ -1074,7 +1074,7 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) { DEFINE_WAIT(wait); - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; struct yuv_playback_info *yi = &itv->yuv_info; int f; @@ -1153,7 +1153,7 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; if (vt->index != 0) @@ -1166,7 +1166,7 @@ static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (vt->index != 0) return -EINVAL; @@ -1186,7 +1186,7 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; int f, l; @@ -1216,7 +1216,7 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; struct v4l2_enc_idx_entry *e = idx->entry; int entries; int i; @@ -1239,7 +1239,7 @@ static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *id static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; @@ -1291,7 +1291,7 @@ static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; switch (enc->cmd) { case V4L2_ENC_CMD_START: @@ -1321,7 +1321,7 @@ static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; u32 data[CX2341X_MBOX_MAX_DATA]; struct yuv_playback_info *yi = &itv->yuv_info; @@ -1408,7 +1408,7 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; @@ -1428,7 +1428,7 @@ static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) static int ivtv_overlay(struct file *file, void *fh, unsigned int on) { - struct ivtv_open_id *id = fh; + struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) @@ -1453,7 +1453,7 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti static int ivtv_log_status(struct file *file, void *fh) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; u32 data[CX2341X_MBOX_MAX_DATA]; int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; @@ -1781,7 +1781,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) static long ivtv_default(struct file *file, void *fh, bool valid_prio, int cmd, void *arg) { - struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv; + struct ivtv *itv = fh2id(fh)->itv; if (!valid_prio) { switch (cmd) { -- cgit v1.2.2 From b1a873a37b6551a214ad37d1eee7654a9d65fd6e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 22 Mar 2011 10:14:07 -0300 Subject: [media] v4l2: use new flag to enable core priority handling Rather than guess which driver supports core priority handling, require drivers that do to explicitly set the V4L2_FL_USE_FH_PRIO flag in video_device. Updated the core prio handling accordingly and set the flag in the three drivers that do. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-streams.c | 1 + drivers/media/video/ivtv/ivtv-streams.c | 1 + drivers/media/video/v4l2-dev.c | 8 +++----- drivers/media/video/v4l2-fh.c | 7 ++++--- drivers/media/video/v4l2-ioctl.c | 13 ++++++++----- drivers/media/video/vivi.c | 1 + 6 files changed, 18 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 2d248560770e..c6e2ca3b1149 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -207,6 +207,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type) s->video_dev->fops = &cx18_v4l2_enc_fops; s->video_dev->release = video_device_release; s->video_dev->tvnorms = V4L2_STD_ALL; + set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags); cx18_set_funcs(s->video_dev); return 0; } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 512607e0cda3..942683336555 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -214,6 +214,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) s->vdev->fops = ivtv_stream_info[type].fops; s->vdev->release = video_device_release; s->vdev->tvnorms = V4L2_STD_ALL; + set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags); ivtv_set_funcs(s->vdev); return 0; } diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 1898099ec65a..498e6742579e 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -578,11 +578,9 @@ int __video_register_device(struct video_device *vdev, int type, int nr, vdev->parent = vdev->v4l2_dev->dev; if (vdev->ctrl_handler == NULL) vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; - /* If the prio state pointer is NULL, and if the driver doesn't - handle priorities itself, then use the v4l2_device prio - state. */ - if (vdev->prio == NULL && vdev->ioctl_ops && - vdev->ioctl_ops->vidioc_s_priority == NULL) + /* If the prio state pointer is NULL, then use the v4l2_device + prio state. */ + if (vdev->prio == NULL) vdev->prio = &vdev->v4l2_dev->prio; } diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c index 543b3fe6784e..717f71e6370e 100644 --- a/drivers/media/video/v4l2-fh.c +++ b/drivers/media/video/v4l2-fh.c @@ -35,7 +35,6 @@ int v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) INIT_LIST_HEAD(&fh->list); set_bit(V4L2_FL_USES_V4L2_FH, &fh->vdev->flags); fh->prio = V4L2_PRIORITY_UNSET; - BUG_ON(vdev->prio == NULL); /* * fh->events only needs to be initialized if the driver @@ -54,7 +53,8 @@ void v4l2_fh_add(struct v4l2_fh *fh) { unsigned long flags; - v4l2_prio_open(fh->vdev->prio, &fh->prio); + if (test_bit(V4L2_FL_USE_FH_PRIO, &fh->vdev->flags)) + v4l2_prio_open(fh->vdev->prio, &fh->prio); spin_lock_irqsave(&fh->vdev->fh_lock, flags); list_add(&fh->list, &fh->vdev->fh_list); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); @@ -82,7 +82,8 @@ void v4l2_fh_del(struct v4l2_fh *fh) spin_lock_irqsave(&fh->vdev->fh_lock, flags); list_del_init(&fh->list); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); - v4l2_prio_close(fh->vdev->prio, fh->prio); + if (test_bit(V4L2_FL_USE_FH_PRIO, &fh->vdev->flags)) + v4l2_prio_close(fh->vdev->prio, fh->prio); } EXPORT_SYMBOL_GPL(v4l2_fh_del); diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 3e6b6fa5771a..a01ed39e6c16 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -541,6 +541,7 @@ static long __video_do_ioctl(struct file *file, void *fh = file->private_data; struct v4l2_fh *vfh = NULL; struct v4l2_format f_copy; + int use_fh_prio = 0; long ret = -EINVAL; if (ops == NULL) { @@ -555,10 +556,12 @@ static long __video_do_ioctl(struct file *file, printk(KERN_CONT "\n"); } - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) + if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { vfh = file->private_data; + use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); + } - if (vfh && !ops->vidioc_s_priority) { + if (use_fh_prio) { switch (cmd) { case VIDIOC_S_CTRL: case VIDIOC_S_STD: @@ -620,7 +623,7 @@ static long __video_do_ioctl(struct file *file, if (ops->vidioc_g_priority) { ret = ops->vidioc_g_priority(file, fh, p); - } else if (vfh) { + } else if (use_fh_prio) { *p = v4l2_prio_max(&vfd->v4l2_dev->prio); ret = 0; } @@ -632,7 +635,7 @@ static long __video_do_ioctl(struct file *file, { enum v4l2_priority *p = arg; - if (!ops->vidioc_s_priority && vfh == NULL) + if (!ops->vidioc_s_priority && !use_fh_prio) break; dbgarg(cmd, "setting priority to %d\n", *p); if (ops->vidioc_s_priority) @@ -2187,7 +2190,7 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_default) break; - if (vfh && !ops->vidioc_s_priority) + if (use_fh_prio) valid_prio = v4l2_prio_check(vfd->prio, vfh->prio) >= 0; ret = ops->vidioc_default(file, fh, valid_prio, cmd, arg); break; diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 42500bf03a9c..2238a613d664 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1254,6 +1254,7 @@ static int __init vivi_create_instance(int inst) *vfd = vivi_template; vfd->debug = debug; vfd->v4l2_dev = &dev->v4l2_dev; + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); /* * Provide a mutex to v4l2 core. It will be used to protect -- cgit v1.2.2 From c3ee142b44c868fb5e0eefe1b9c2df8115f6c69b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 05:16:11 -0300 Subject: [media] gspca - nw80x: Cleanup source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 273 +++++++++----------------------------- 1 file changed, 65 insertions(+), 208 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index 1c9d3c2f6670..831748873884 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -53,7 +53,7 @@ struct sd { }; enum bridges { - BRIDGE_NW800, /* et31x110 */ + BRIDGE_NW800, /* and et31x110 */ BRIDGE_NW801, BRIDGE_NW802, }; @@ -145,7 +145,7 @@ enum webcams { nw801/nw802 320x240 - 640x480 */ -static const struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format cif_mode[] = { {352, 288, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, .bytesperline = 352, .sizeimage = 352 * 288 * 4 / 8, @@ -171,6 +171,7 @@ static const struct v4l2_pix_format vga_mode[] = { * - n bytes: data */ #define I2C0 0xff + static const u8 nw800_init[] = { 0x05, 0x00, 0x01, 0x55, 0x10, 0x9b, 0x01, 0xaa, @@ -333,8 +334,9 @@ static const u8 nw800_init[] = { 0, 0, 0 }; -/* 06a5:d001 - nw801 - p35u */ -static const u8 nw801_init_1[] = { +/* 06a5:d001 - nw801 - Panasonic + * P35u */ +static const u8 nw801_start_1[] = { 0x05, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x0e, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -389,7 +391,7 @@ static const u8 nw801_init_1[] = { 0xf0, 0x00, 0, 0, 0, }; -static const u8 nw801_init_qvga[] = { +static const u8 nw801_start_qvga[] = { 0x02, 0x00, 0x10, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x78, 0x18, 0x0b, 0x06, 0xa2, 0x86, 0x78, 0x02, 0x0f, 0x01, 0x6b, @@ -401,7 +403,7 @@ static const u8 nw801_init_qvga[] = { /* AE window */ 0, 0, 0, }; -static const u8 nw801_init_vga[] = { +static const u8 nw801_start_vga[] = { 0x02, 0x00, 0x10, 0x78, 0xa0, 0x97, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xf0, 0x02, 0x0f, 0x01, 0xd5, @@ -412,7 +414,7 @@ static const u8 nw801_init_vga[] = { 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, 0, 0, 0, }; -static const u8 nw801_init_2[] = { +static const u8 nw801_start_2[] = { 0x10, 0x04, 0x01, 0x1a, 0x10, 0x19, 0x01, 0x09, /* clock */ 0x10, 0x24, 0x06, 0xc0, 0x00, 0x3f, 0x02, 0x00, 0x01, @@ -441,7 +443,7 @@ static const u8 nw801_init_2[] = { }; /* nw802 (sharp IR3Y38M?) */ -static const u8 nw802_init[] = { +static const u8 nw802_start[] = { 0x04, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x4d, 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -524,7 +526,6 @@ static const u8 nw802_init[] = { }; /* et31x110 - Trust 120 SpaceCam */ static const u8 spacecam_init[] = { -/*fixme: at connection time*/ 0x04, 0x05, 0x01, 0x01, 0x04, 0x04, 0x01, 0x01, 0x04, 0x06, 0x01, 0x04, @@ -617,13 +618,8 @@ static const u8 spacecam_init[] = { 0x04, 0x04, 0x01, 0x40, 0, 0, 0 }; -/* et31x110 - other Trust SpaceCam120 */ -static const u8 spacecam2_init[] = { - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x01, - 0x04, 0x06, 0x01, 0x04, - 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, - 0x05, 0x05, 0x01, 0x00, +/* et31x110 - pas106 - other Trust SpaceCam120 */ +static const u8 spacecam2_start[] = { 0x04, 0x06, 0x01, 0x44, 0x04, 0x06, 0x01, 0x00, 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, @@ -682,79 +678,25 @@ static const u8 spacecam2_init[] = { 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x04, 0x04, 0x01, 0x40, 0x04, 0x04, 0x01, 0x00, -#if 1 I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x05, I2C0, 0x40, 0x02, 0x11, 0x06, I2C0, 0x40, 0x02, 0x14, 0x00, - I2C0, 0x40, 0x02, 0x13, 0x01, -#else - 0x06, 0x00, 0x0b, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, - 0x00, 0x05, 0x05, - 0x06, 0x00, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x05, - 0x00, 0x00, 0x05, 0x05, - 0x05, 0x02, 0x02, 0x0c, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x06, - 0x06, 0x00, 0x02, 0x11, 0x06, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x14, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, 0x40, -#if 1 - I2C0, 0x40, 0x02, 0x02, 0x0c, + I2C0, 0x40, 0x02, 0x02, 0x0c, /* pixel clock */ I2C0, 0x40, 0x02, 0x0f, 0x00, - I2C0, 0x40, 0x02, 0x13, 0x01, -#else - 0x06, 0x00, 0x01, 0x0c, - 0x06, 0x00, 0x02, 0x02, 0x0c, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x0f, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ 0x10, 0x00, 0x01, 0x01, 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, 0x01, 0x60, 0x01, -#if 1 - I2C0, 0x40, 0x02, 0x05, 0x0f, - I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x02, 0x05, 0x0f, /* exposure */ + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ I2C0, 0x40, 0x07, 0x09, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, + /* gains */ I2C0, 0x40, 0x03, 0x12, 0x04, 0x01, -#else - 0x06, 0x00, 0x01, 0x0f, - 0x06, 0x00, 0x02, 0x05, 0x0f, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x06, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, - 0x06, 0x00, 0x07, 0x09, 0x0b, 0x0f, 0x05, 0x05, 0x0f, 0x00, - 0x05, 0x02, 0x02, 0x07, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x04, 0x01, - 0x06, 0x00, 0x03, 0x12, 0x04, 0x01, - 0x05, 0x02, 0x02, 0x03, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x10, 0x0e, 0x01, 0x08, 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, @@ -776,7 +718,7 @@ static const u8 spacecam2_init[] = { }; /* nw802 - Conceptronic Video Pro */ -static const u8 cvideopro_init[] = { +static const u8 cvideopro_start[] = { 0x04, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -856,10 +798,9 @@ static const u8 cvideopro_init[] = { }; /* nw802 - D-link dru-350c cam */ -static const u8 dlink_init[] = { +static const u8 dlink_start[] = { 0x04, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, -/* 0xf9, 0x02, = nb pixels per line */ 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, 0x00, 0xce, 0x00, 0xf4, @@ -878,7 +819,6 @@ static const u8 dlink_init[] = { 0x00, 0x80, 0x1f, 0xb4, 0x6f, 0x3f, 0x0f, 0x88, 0x20, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x08, 0x00, 0x11, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x16, 0x00, 0x94, -/* 0x19, v index of clamping pulse */ 0x00, 0x10, 0x06, 0x10, 0x00, 0x36, 0x00, 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, @@ -909,7 +849,6 @@ static const u8 dlink_init[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x82, 0x02, 0xe4, 0x01, 0x40, 0x01, 0xf0, 0x00, 0x40, 0x01, 0xf0, 0x00, -/* 0x00, 0x03, 0x02, 0x92, 0x03, = nb of pixels per line */ 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, 0x40, @@ -938,8 +877,10 @@ static const u8 dlink_init[] = { 0, 0, 0 }; -/* nw801 - Plustek Opticam 500U or ProLink DS3303u (Hitachi HD49322BF) */ -static const u8 ds330_init[] = { +/* 06a5:d001 - nw801 - Sony + * Plustek Opticam 500U or ProLink DS3303u (Hitachi HD49322BF) */ +/*fixme: 320x240 only*/ +static const u8 ds3303_start[] = { 0x05, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x16, 0x00, 0x00, 0xf9, 0x02, 0x11, 0x00, 0x0e, 0x01, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -1021,8 +962,9 @@ static const u8 ds330_init[] = { 0, 0, 0 }; -/* 06a5:d001 - nw802 - Panasonic GP-KR651US (Philips TDA8786) */ -static const u8 kr651_init_1[] = { +/* 06a5:d001 - nw802 - Panasonic + * GP-KR651US (Philips TDA8786) */ +static const u8 kr651_start_1[] = { 0x04, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x48, 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -1075,7 +1017,7 @@ static const u8 kr651_init_1[] = { 0x01, 0xf0, 0x00, 0, 0, 0 }; -static const u8 kr651_init_qvga[] = { +static const u8 kr651_start_qvga[] = { 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, 0x40, @@ -1088,21 +1030,19 @@ static const u8 kr651_init_qvga[] = { 0x10, 0x1d, 0x02, 0x28, 0x01, 0, 0, 0 }; -static const u8 kr651_init_vga[] = { +static const u8 kr651_start_vga[] = { 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0x03, 0x01, 0x82, 0x82, 0x98, 0x80, 0x10, 0x1a, 0x01, 0x03, 0x10, 0x00, 0x01, 0xa0, 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, - 0x10, 0x1b, 0x02, 0x00, 0x00, 0x10, 0x11, 0x08, 0x51, 0x00, 0x30, 0x02, 0x3d, 0x00, 0xa4, 0x01, - 0x10, 0x1d, 0x06, 0xe0, 0x00, 0x0c, 0x00, 0x52, 0x00, 0x10, 0x1d, 0x02, 0x68, 0x00, }; -static const u8 kr651_init_2[] = { +static const u8 kr651_start_2[] = { 0x10, 0x0e, 0x01, 0x08, 0x10, 0x41, 0x11, 0x00, 0x11, 0x3c, 0x5c, 0x74, 0x88, 0x99, 0xa8, 0xb7, 0xc4, 0xd0, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, @@ -1122,7 +1062,7 @@ static const u8 kr651_init_2[] = { }; /* nw802 - iRez Kritter cam */ -static const u8 kritter_init[] = { +static const u8 kritter_start[] = { 0x04, 0x06, 0x01, 0x06, 0x00, 0x00, 0x40, 0x44, 0x96, 0x98, 0x94, 0x03, 0x18, 0x00, 0x48, 0x0f, 0x1e, 0x00, 0x0c, 0x02, 0x01, 0x00, 0x19, @@ -1202,7 +1142,7 @@ static const u8 kritter_init[] = { }; /* nw802 - Mustek Wcam 300 mini */ -static const u8 mustek_init[] = { +static const u8 mustek_start[] = { 0x04, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x92, 0x03, 0x10, 0x00, 0x4d, 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -1337,7 +1277,7 @@ static const u8 proscope_init_1[] = { 0x01, 0xf0, 0x00, 0, 0, 0 }; -static const u8 proscope_init_qvga[] = { +static const u8 proscope_start_qvga[] = { 0x02, 0x00, 0x11, 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x78, 0x3f, 0x10, 0x02, 0xf2, 0x8f, 0x78, 0x40, @@ -1350,7 +1290,7 @@ static const u8 proscope_init_qvga[] = { 0x10, 0x0e, 0x01, 0x10, 0, 0, 0 }; -static const u8 proscope_init_vga[] = { +static const u8 proscope_start_vga[] = { 0x00, 0x03, 0x02, 0xf9, 0x02, 0x10, 0x85, 0x08, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0xdf, 0x01, 0x02, 0x00, 0x11, 0x78, 0xa0, 0x8c, 0x78, 0xa0, 0x00, 0x00, 0x00, @@ -1368,7 +1308,7 @@ static const u8 proscope_init_vga[] = { 0x10, 0x03, 0x01, 0x00, 0, 0, 0 }; -static const u8 proscope_init_2[] = { +static const u8 proscope_start_2[] = { 0x10, 0x0f, 0x02, 0x0c, 0x0c, 0x10, 0x03, 0x01, 0x0c, 0x10, 0x41, 0x11, 0x00, 0x10, 0x51, 0x6e, 0x83, 0x93, 0xa1, 0xae, @@ -1383,14 +1323,8 @@ static const u8 proscope_init_2[] = { 0, 0, 0 }; -/* nw800 - Divio Chicony TwinkleCam */ -static const u8 twinkle_init[] = { - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x01, - 0x04, 0x06, 0x01, 0x04, - 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, - 0x05, 0x05, 0x01, 0x00, - +/* nw800 - hv7121b? (seems pas106) - Divio Chicony TwinkleCam */ +static const u8 twinkle_start[] = { 0x04, 0x06, 0x01, 0x44, 0x04, 0x06, 0x01, 0x00, 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, @@ -1448,107 +1382,32 @@ static const u8 twinkle_init[] = { 0x01, 0x60, 0x01, 0x00, 0x00, 0x10, 0x85, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, -/*320 3f ef, 0x00 */ 0x04, 0x04, 0x01, 0x10, 0x04, 0x04, 0x01, 0x00, 0x04, 0x05, 0x01, 0x61, 0x04, 0x04, 0x01, 0x01, -#if 1 I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, I2C0, 0x40, 0x02, 0x11, 0x06, I2C0, 0x40, 0x02, 0x14, 0x00, - I2C0, 0x40, 0x02, 0x13, 0x01, + I2C0, 0x40, 0x02, 0x13, 0x01, /* i2c end */ I2C0, 0x40, 0x02, 0x07, 0x01, -#else - 0x06, 0x00, 0x0b, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0a, - 0x06, 0x00, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, - 0x05, 0x02, 0x02, 0x0c, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x06, - 0x06, 0x00, 0x02, 0x11, 0x06, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x14, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x07, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif 0x02, 0x00, 0x11, 0x48, 0x58, 0x9e, 0x48, 0x58, 0x00, 0x00, 0x00, -/* 320 0x3c, 0x50, 0x9e, 0x3c, 0x50, 0x00, 0x00, 0x00, */ 0x00, 0x84, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x65, -/* 320 0x00, 0x78, 0x36, 0x05, 0x01, 0xf2, 0x86, 0x5c, */ 0x40, -#if 1 I2C0, 0x40, 0x02, 0x02, 0x0c, I2C0, 0x40, 0x02, 0x13, 0x01, -#else - 0x06, 0x00, 0x01, 0x0c, - 0x06, 0x00, 0x02, 0x02, 0x0c, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif 0x10, 0x00, 0x01, 0x01, 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, 0x01, 0x60, 0x01, -/* 320 0xf0, 0x00, 0x40, 0x01, */ -#if 1 I2C0, 0x40, 0x02, 0x05, 0x0f, I2C0, 0x40, 0x02, 0x13, 0x01, I2C0, 0x40, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, I2C0, 0x40, 0x03, 0x12, 0x00, 0x01, -#else - 0x06, 0x00, 0x01, 0x0f, - 0x06, 0x00, 0x02, 0x05, 0x0f, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x07, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, - 0x06, 0x00, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x17, - 0x05, 0x02, 0x02, 0x08, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x00, 0x01, - 0x06, 0x00, 0x03, 0x12, 0x00, 0x01, - 0x05, 0x02, 0x02, 0x03, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif 0x10, 0x11, 0x08, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x1f, 0x01, -/* 320 3f ef */ -#if 1 I2C0, 0x40, 0x02, 0x12, 0x00, I2C0, 0x40, 0x02, 0x0e, 0x00, I2C0, 0x40, 0x02, 0x11, 0x06, -#else - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x12, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x0e, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x06, - 0x06, 0x00, 0x02, 0x11, 0x06, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, 0xf9, @@ -1745,7 +1604,7 @@ static const u8 dsbc110_init[] = { }; /* nw802 dvc-v6 */ -static const u8 dvcv6_init[] = { +static const u8 dvcv6_start[] = { 0x04, 0x06, 0x01, 0x06, 0x00, 0x00, 0x40, 0x54, 0x96, 0x98, 0xf9, 0x02, 0x18, 0x00, 0x4c, 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -1830,22 +1689,22 @@ static const u8 dvcv6_init[] = { 0x04, 0x04, 0x01, 0x00, }; -static const u8 *webcam_init[] = { +static const u8 *webcam_start[] = { [Generic800] = nw800_init, [SpaceCam] = spacecam_init, - [SpaceCam2] = spacecam2_init, - [Cvideopro] = cvideopro_init, - [Dlink350c] = dlink_init, - [DS3303u] = ds330_init, - [Kr651us] = kr651_init_1, - [Kritter] = kritter_init, - [Mustek300] = mustek_init, + [SpaceCam2] = spacecam2_start, + [Cvideopro] = cvideopro_start, + [Dlink350c] = dlink_start, + [DS3303u] = ds3303_start, + [Kr651us] = kr651_start_1, + [Kritter] = kritter_start, + [Mustek300] = mustek_start, [Proscope] = proscope_init_1, - [Twinkle] = twinkle_init, + [Twinkle] = twinkle_start, [DsbC110] = dsbc110_init, - [DvcV6] = dvcv6_init, - [P35u] = nw801_init_1, - [Generic802] = nw802_init, + [DvcV6] = dvcv6_start, + [P35u] = nw801_start_1, + [Generic802] = nw802_start, }; /* -- write a register -- */ @@ -1949,7 +1808,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, if (cmd[-3] != I2C0) reg_w(gspca_dev, reg, cmd, len); else - i2c_w(gspca_dev, reg & 0xff, cmd, len); + i2c_w(gspca_dev, reg, cmd, len); cmd += len; } } @@ -2092,8 +1951,8 @@ static int sd_init(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "Bridge nw80%d", sd->bridge); if (sd->bridge == BRIDGE_NW800) { - gspca_dev->cam.cam_mode = sif_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(sif_mode); + gspca_dev->cam.cam_mode = cif_mode; + gspca_dev->cam.nmodes = ARRAY_SIZE(cif_mode); } else { gspca_dev->cam.cam_mode = vga_mode; switch (sd->webcam) { @@ -2110,12 +1969,10 @@ static int sd_init(struct gspca_dev *gspca_dev) } switch (sd->webcam) { case P35u: -/* sd->ctrls[EXPOSURE].min = 0; - * sd->ctrls[EXPOSURE].max = 9; +/* sd->ctrls[EXPOSURE].max = 9; * sd->ctrls[EXPOSURE].def = 1; */ break; case Kr651us: -/* sd->ctrls[EXPOSURE].min = 0; */ sd->ctrls[EXPOSURE].max = 315; sd->ctrls[EXPOSURE].def = 150; break; @@ -2133,29 +1990,29 @@ static int sd_start(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; const u8 *cmd; - cmd = webcam_init[sd->webcam]; + cmd = webcam_start[sd->webcam]; reg_w_buf(gspca_dev, cmd); switch (sd->webcam) { case P35u: if (gspca_dev->width == 320) - reg_w_buf(gspca_dev, nw801_init_qvga); + reg_w_buf(gspca_dev, nw801_start_qvga); else - reg_w_buf(gspca_dev, nw801_init_vga); - reg_w_buf(gspca_dev, nw801_init_2); + reg_w_buf(gspca_dev, nw801_start_vga); + reg_w_buf(gspca_dev, nw801_start_2); break; case Kr651us: if (gspca_dev->width == 320) - reg_w_buf(gspca_dev, kr651_init_qvga); + reg_w_buf(gspca_dev, kr651_start_qvga); else - reg_w_buf(gspca_dev, kr651_init_vga); - reg_w_buf(gspca_dev, kr651_init_2); + reg_w_buf(gspca_dev, kr651_start_vga); + reg_w_buf(gspca_dev, kr651_start_2); break; case Proscope: if (gspca_dev->width == 320) - reg_w_buf(gspca_dev, proscope_init_qvga); + reg_w_buf(gspca_dev, proscope_start_qvga); else - reg_w_buf(gspca_dev, proscope_init_vga); - reg_w_buf(gspca_dev, proscope_init_2); + reg_w_buf(gspca_dev, proscope_start_vga); + reg_w_buf(gspca_dev, proscope_start_2); break; } -- cgit v1.2.2 From 94751d4b208281f8447a9baca39963b66dd6983f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 05:37:18 -0300 Subject: [media] gspca - nw80x: The webcam dsb-c110 is the same as the twinkle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 182 +------------------------------------- 1 file changed, 1 insertion(+), 181 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index 831748873884..e5928b1de534 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -69,7 +69,6 @@ enum webcams { Mustek300, Proscope, Twinkle, - DsbC110, DvcV6, P35u, Generic802, @@ -1426,183 +1425,6 @@ static const u8 twinkle_start[] = { 0, 0, 0 }; -/* et31x110 DSB-C110 */ -static const u8 dsbc110_init[] = { - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x01, - 0x04, 0x06, 0x01, 0x04, - 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, - 0x05, 0x05, 0x01, 0x00, - - 0x04, 0x06, 0x01, 0x44, - 0x04, 0x06, 0x01, 0x00, - 0x00, 0x00, 0x40, 0x14, 0x83, 0x00, 0xba, 0x01, 0x10, 0x00, 0x4f, - 0xef, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x01, 0x00, 0x19, - 0x00, 0x01, 0x00, 0x19, 0x00, 0x06, 0x00, 0xfc, - 0x01, 0x3e, 0x00, 0x86, 0x00, 0x3e, 0x00, 0x86, - 0x00, 0x3e, 0x00, 0x86, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x56, 0x00, 0x9e, - 0x00, 0x56, 0x00, 0x9e, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x40, 0x40, 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x6e, 0x00, 0xb6, 0x00, 0x6e, 0x00, 0x78, - 0x04, 0x6e, 0x00, 0xb6, 0x00, 0x01, 0x00, 0x01, - 0x00, 0xca, 0x03, 0x46, 0x04, 0xca, 0x03, 0x46, - 0x04, 0x10, 0x00, 0x36, 0x00, 0xd2, 0x00, 0xee, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0xf0, - 0x00, 0x3e, 0x00, 0xaa, 0x00, 0x88, 0x00, 0x2e, - 0x00, 0x80, 0x1f, 0xb8, 0x48, 0x0f, 0x04, 0x88, 0x14, 0x68, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x03, - 0x00, 0x24, 0x01, 0x01, 0x00, 0x16, 0x00, 0x04, - 0x00, 0x4b, 0x00, 0x76, 0x00, 0x86, 0x00, - 0x02, 0x00, 0x12, 0x78, 0xa0, 0x9e, 0x78, 0xa0, 0x00, 0x00, 0x00, - 0x00, 0xf0, 0x18, 0x0b, 0x06, 0x62, 0x82, 0xa0, - 0x40, 0x20, - 0x03, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x04, 0x00, 0x07, 0x01, 0x10, 0x00, 0x00, 0x00, 0x61, 0x00, - 0x05, 0x00, 0x06, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, - 0x08, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x40, 0x80, 0x02, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x08, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x49, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, - 0x03, 0x00, 0x00, 0x10, 0x00, 0x20, 0x10, 0x06, - 0xf7, 0xee, 0x1c, 0x1c, 0xe9, 0xfc, 0x00, 0x80, - 0x10, 0x40, 0x40, 0x80, 0x00, 0x05, 0x35, 0x5e, 0x78, 0x8b, 0x99, - 0xa4, 0xae, 0xb5, 0xbc, 0xc1, 0xc6, 0xc9, 0xcc, - 0xcf, 0xd0, 0x00, 0x11, 0x22, 0x32, 0x43, 0x54, - 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, 0xd2, - 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, 0x43, - 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, 0xc3, - 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x11, 0x22, 0x32, - 0x43, 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb3, - 0x10, 0x80, 0x1d, 0xc3, 0xd2, 0xe2, 0xf1, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x62, - 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, 0x20, - 0x01, 0x60, 0x01, 0x00, 0x00, - 0x10, 0x85, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, - 0x04, 0x04, 0x01, 0x10, - 0x04, 0x04, 0x01, 0x00, - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x01, -#if 1 - I2C0, 0x40, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, - I2C0, 0x40, 0x02, 0x11, 0x06, - I2C0, 0x40, 0x02, 0x14, 0x00, - I2C0, 0x40, 0x02, 0x13, 0x01, - I2C0, 0x40, 0x02, 0x07, 0x01, -#else - 0x06, 0x00, 0x0b, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0a, - 0x06, 0x00, 0x0c, 0x02, 0x0c, 0x12, 0x07, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, - 0x05, 0x02, 0x02, 0x0c, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x06, - 0x06, 0x00, 0x02, 0x11, 0x06, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x14, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x07, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif - 0x02, 0x00, 0x11, 0x3c, 0x50, 0x8c, 0x3c, 0x50, 0x00, 0x00, 0x00, - 0x00, 0x78, 0x3f, 0x3f, 0x06, 0xf2, 0x8f, 0xe4, - 0x40, -#if 1 - I2C0, 0x40, 0x02, 0x02, 0x0c, - I2C0, 0x40, 0x02, 0x13, 0x01, -#else - 0x06, 0x00, 0x01, 0x1c, - 0x06, 0x00, 0x02, 0x02, 0x1c, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif - 0x10, 0x00, 0x01, 0x01, - 0x10, 0x8f, 0x0c, 0x62, 0x01, 0x24, 0x01, 0x62, 0x01, 0x24, 0x01, - 0xf0, 0x00, 0x40, 0x01, -#if 1 - I2C0, 0x40, 0x02, 0x05, 0x23, - I2C0, 0x40, 0x02, 0x13, 0x01, - I2C0, 0x40, 0x08, 0x08, 0x04, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x00, - I2C0, 0x40, 0x03, 0x12, 0x00, 0x01, -#else - 0x06, 0x00, 0x01, 0x24, - 0x06, 0x00, 0x02, 0x05, 0x24, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x13, 0x01, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x07, 0x06, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x00, - 0x06, 0x00, 0x08, 0x08, 0x06, 0x0b, 0x01, 0x01, 0x02, 0x00, 0x00, - 0x05, 0x02, 0x02, 0x08, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x02, 0x00, 0x01, - 0x06, 0x00, 0x03, 0x12, 0x00, 0x01, - 0x05, 0x02, 0x02, 0x03, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif - 0x10, 0x11, 0x08, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0xef, 0x00, -#if 1 - I2C0, 0x40, 0x02, 0x12, 0x00, - I2C0, 0x40, 0x02, 0x0e, 0x00, - I2C0, 0x40, 0x02, 0x11, 0x06, -#else - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x12, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x00, - 0x06, 0x00, 0x02, 0x0e, 0x00, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, - 0x06, 0x00, 0x01, 0x06, - 0x06, 0x00, 0x02, 0x11, 0x06, - 0x05, 0x02, 0x02, 0x02, 0x40, - 0x05, 0x05, 0x01, 0x01, -#endif - 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, - 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, - 0xf9, - 0x10, 0x03, 0x01, 0x00, - 0x10, 0x0f, 0x02, 0x0c, 0x0c, - 0x10, 0x03, 0x01, 0x06, - 0x10, 0x41, 0x11, 0x00, 0x17, 0x3f, 0x69, 0x7b, 0x8c, 0x9a, 0xa7, - 0xb3, 0xbf, 0xc9, 0xd3, 0xdd, 0xe6, 0xef, 0xf7, - 0xf9, - 0x10, 0x0b, 0x01, 0x14, - 0x10, 0x0d, 0x01, 0x10, - 0x10, 0x0c, 0x01, 0x1d, - 0x04, 0x06, 0x01, 0x03, - 0x04, 0x05, 0x01, 0x61, - 0x04, 0x04, 0x01, 0x41, -}; - /* nw802 dvc-v6 */ static const u8 dvcv6_start[] = { 0x04, 0x06, 0x01, 0x06, @@ -1701,7 +1523,6 @@ static const u8 *webcam_start[] = { [Mustek300] = mustek_start, [Proscope] = proscope_init_1, [Twinkle] = twinkle_start, - [DsbC110] = dsbc110_init, [DvcV6] = dvcv6_start, [P35u] = nw801_start_1, [Generic802] = nw802_start, @@ -2296,5 +2117,4 @@ MODULE_PARM_DESC(webcam, "8: Mustek Wcam 300 mini\n" "9: Scalar USB Microscope M2 (Proscope)\n" "10: Divio Chicony TwinkleCam\n" - "11: DSB-C110\n" - "12: DVC-V6\n"); + "11: DVC-V6\n"); -- cgit v1.2.2 From bad03ff53ae3d336b5ecc5356b4739d9a693fc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 05:46:24 -0300 Subject: [media] gspca - nw80x: Do some initialization at probe time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 85 +++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index e5928b1de534..f4c6f407f56e 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -172,14 +172,14 @@ static const struct v4l2_pix_format vga_mode[] = { #define I2C0 0xff static const u8 nw800_init[] = { - 0x05, 0x00, 0x01, 0x55, - 0x10, 0x9b, 0x01, 0xaa, - 0x05, 0x02, 0x01, 0x02, - 0x06, 0x00, 0x02, 0x04, 0xd9, - 0x05, 0x05, 0x01, 0x00, - 0x05, 0x05, 0x01, 0x01, + 0x04, 0x05, 0x01, 0x61, + 0x04, 0x04, 0x01, 0x01, 0x04, 0x06, 0x01, 0x04, - + 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, + 0x05, 0x05, 0x01, 0x00, + 0, 0, 0 +}; +static const u8 nw800_start[] = { 0x04, 0x06, 0x01, 0xc0, 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, @@ -530,8 +530,9 @@ static const u8 spacecam_init[] = { 0x04, 0x06, 0x01, 0x04, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x05, 0x05, 0x01, 0x00, -/*fixme: add 300ms delay?*/ -/*fixme: at capture start time*/ + 0, 0, 0 +}; +static const u8 spacecam_start[] = { 0x04, 0x06, 0x01, 0x44, 0x00, 0x00, 0x40, 0x10, 0x43, 0x00, 0xb4, 0x01, 0x10, 0x00, 0x4f, 0xef, 0x0e, 0x00, 0x74, 0x01, 0x01, 0x00, 0x19, @@ -1221,9 +1222,12 @@ static const u8 mustek_start[] = { }; /* nw802 - Scope USB Microscope M2 (ProScope) (Hitachi HD49322BF) */ -static const u8 proscope_init_1[] = { +static const u8 proscope_init[] = { 0x04, 0x05, 0x01, 0x21, 0x04, 0x04, 0x01, 0x01, + 0, 0, 0 +}; +static const u8 proscope_start_1[] = { 0x04, 0x06, 0x01, 0x04, 0x00, 0x00, 0x40, 0x10, 0x01, 0x00, 0xf9, 0x02, 0x10, 0x00, 0x04, 0x0f, 0x1f, 0x00, 0x0d, 0x02, 0x01, 0x00, 0x19, @@ -1512,8 +1516,8 @@ static const u8 dvcv6_start[] = { }; static const u8 *webcam_start[] = { - [Generic800] = nw800_init, - [SpaceCam] = spacecam_init, + [Generic800] = nw800_start, + [SpaceCam] = spacecam_start, [SpaceCam2] = spacecam2_start, [Cvideopro] = cvideopro_start, [Dlink350c] = dlink_start, @@ -1521,7 +1525,7 @@ static const u8 *webcam_start[] = { [Kr651us] = kr651_start_1, [Kritter] = kritter_start, [Mustek300] = mustek_start, - [Proscope] = proscope_init_1, + [Proscope] = proscope_start_1, [Twinkle] = twinkle_start, [DvcV6] = dvcv6_start, [P35u] = nw801_start_1, @@ -1720,21 +1724,6 @@ static void setautogain(struct gspca_dev *gspca_dev) } } -/* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, - const struct usb_device_id *id) -{ - struct sd *sd = (struct sd *) gspca_dev; - - if ((unsigned) webcam >= NWEBCAMS) - webcam = 0; - sd->webcam = webcam; - gspca_dev->cam.reverse_alts = 1; - gspca_dev->cam.ctrls = sd->ctrls; - sd->ag_cnt = -1; - return 0; -} - static int nw802_test_reg(struct gspca_dev *gspca_dev, u16 index, u8 value) @@ -1748,11 +1737,19 @@ static int nw802_test_reg(struct gspca_dev *gspca_dev, return gspca_dev->usb_buf[0] == value; } -/* this function is called at probe and resume time */ -static int sd_init(struct gspca_dev *gspca_dev) +/* this function is called at probe time */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; + if ((unsigned) webcam >= NWEBCAMS) + webcam = 0; + sd->webcam = webcam; + gspca_dev->cam.reverse_alts = 1; + gspca_dev->cam.ctrls = sd->ctrls; + sd->ag_cnt = -1; + /* * Autodetect sequence inspired from some log. * We try to detect what registers exist or not. @@ -1801,7 +1798,35 @@ static int sd_init(struct gspca_dev *gspca_dev) gspca_dev->ctrl_dis = ~(1 << GAIN); break; } + return gspca_dev->usb_err; +} +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->bridge) { + case BRIDGE_NW800: + switch (sd->webcam) { + case SpaceCam: + reg_w_buf(gspca_dev, spacecam_init); + break; + default: + reg_w_buf(gspca_dev, nw800_init); + break; + } + break; + default: + switch (sd->webcam) { + case Mustek300: + case P35u: + case Proscope: + reg_w_buf(gspca_dev, proscope_init); + break; + } + break; + } return gspca_dev->usb_err; } -- cgit v1.2.2 From f12b44ff2d5ba8eb41210438589a64490ddfedec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 05:53:21 -0300 Subject: [media] gspca - nw80x: Fix the gain, exposure and autogain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The autogain now uses common functions. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 135 +++++++++++++------------------------- 1 file changed, 46 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index f4c6f407f56e..d2d356e87539 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -38,6 +38,8 @@ enum e_ctrl { NCTRLS /* number of controls */ }; +#define AUTOGAIN_DEF 1 + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ @@ -47,6 +49,8 @@ struct sd { u32 ae_res; s8 ag_cnt; #define AG_CNT_START 13 + u8 exp_too_low_cnt; + u8 exp_too_high_cnt; u8 bridge; u8 webcam; @@ -1638,12 +1642,12 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, } } -static int swap_6bits(int v) +static int swap_bits(int v) { int r, i; r = 0; - for (i = 0; i < 6; i++) { + for (i = 0; i < 8; i++) { r <<= 1; if (v & 1) r++; @@ -1657,20 +1661,17 @@ static void setgain(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; u8 val, v[2]; - val = sd->ctrls[GAIN].val >> 1; /* 0 - 63 -> 0 - 31 */ - reg_w(gspca_dev, 0x100e, &val, 1); /* AE Y gain */ - + val = sd->ctrls[GAIN].val; switch (sd->webcam) { case P35u: /* Note the control goes from 0-255 not 0-127, but anything above 127 just means amplifying noise */ - val = sd->ctrls[GAIN].val << 1; /* 0 - 63 -> 0 - 127 */ + val >>= 1; /* 0 - 255 -> 0 - 127 */ reg_w(gspca_dev, 0x1026, &val, 1); break; case Kr651us: - /* 0 - 63 -> 0 - 0x37 */ - val = (sd->ctrls[GAIN].val * 0x37) / 63; - val = swap_6bits(val); + /* 0 - 253 */ + val = swap_bits(val); v[0] = val << 3; v[1] = val >> 5; reg_w(gspca_dev, 0x101d, v, 2); /* SIF reg0/1 (AGC) */ @@ -1681,16 +1682,18 @@ static void setgain(struct gspca_dev *gspca_dev) static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + s16 val; u8 v[2]; + val = sd->ctrls[EXPOSURE].val; switch (sd->webcam) { case P35u: - v[0] = (sd->ctrls[EXPOSURE].val << 3) | 0x01; + v[0] = ((9 - val) << 3) | 0x01; reg_w(gspca_dev, 0x1019, v, 1); break; case Kr651us: - v[0] = sd->ctrls[EXPOSURE].val; - v[1] = sd->ctrls[EXPOSURE].val >> 8; + v[0] = val; + v[1] = val >> 8; reg_w(gspca_dev, 0x101b, v, 2); break; } @@ -1788,16 +1791,30 @@ static int sd_config(struct gspca_dev *gspca_dev, switch (sd->webcam) { case P35u: /* sd->ctrls[EXPOSURE].max = 9; - * sd->ctrls[EXPOSURE].def = 1; */ + * sd->ctrls[EXPOSURE].def = 9; */ + /* coarse expo auto gain function gain minimum, to avoid + * a large settings jump the first auto adjustment */ + sd->ctrls[GAIN].def = 255 / 5 * 2; break; + case Cvideopro: + case DvcV6: + case Kritter: + gspca_dev->ctrl_dis = (1 << GAIN) | (1 << AUTOGAIN); + /* fall thru */ case Kr651us: sd->ctrls[EXPOSURE].max = 315; sd->ctrls[EXPOSURE].def = 150; break; default: - gspca_dev->ctrl_dis = ~(1 << GAIN); + gspca_dev->ctrl_dis = (1 << GAIN) | (1 << EXPOSURE) + | (1 << AUTOGAIN); break; } + +#if AUTOGAIN_DEF + if (!(gspca_dev->ctrl_dis & (1 << AUTOGAIN))) + gspca_dev->ctrl_inac = (1 << GAIN) | (1 << EXPOSURE); +#endif return gspca_dev->usb_err; } @@ -1865,6 +1882,8 @@ static int sd_start(struct gspca_dev *gspca_dev) setgain(gspca_dev); setexposure(gspca_dev); setautogain(gspca_dev); + sd->exp_too_high_cnt = 0; + sd->exp_too_low_cnt = 0; return gspca_dev->usb_err; } @@ -1936,11 +1955,12 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) return gspca_dev->usb_err; } +#include "autogain_functions.h" + static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int luma; - int gain, shutter; if (sd->ag_cnt < 0) return; @@ -1954,76 +1974,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) + (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; luma /= sd->ae_res; - if (sd->webcam == P35u) { - u8 clock; - - if (luma > 92 && luma < 108) - return; /* fine */ - clock = sd->ctrls[EXPOSURE].val; - gain = sd->ctrls[GAIN].val; - if (luma < 100) { - if (luma < 70 && clock > 0) - clock--; - if (gain > 98 && clock > 0) - clock--; - if (gain <= 50) - gain += 3; - } else { - if (luma > 150 && clock < 9) - clock++; - if (gain < 12 && clock < 9) - clock++; - if (gain >= 5) - gain -= 3; - } - if (gain != sd->ctrls[GAIN].val) { - sd->ctrls[GAIN].val = gain; - setgain(gspca_dev); - } - if (clock != sd->ctrls[EXPOSURE].val) { - sd->ctrls[EXPOSURE].val = clock; - setexposure(gspca_dev); - } - return; - } - - /* kr651us */ - if (luma > 95 && luma < 105) - return; /* fine */ - gain = sd->ctrls[GAIN].val; - shutter = sd->ctrls[EXPOSURE].val; - if (luma < 100) { - if (shutter > 0) { - if (luma < 85 && shutter > 50) - shutter -= 50; - else - shutter--; - } else if (gain < 63) { - if (luma < 85 && gain < 53) - gain += 10; - else - gain++; - } - } else { - if (gain > 0) { - if (luma > 115 && gain > 10) - gain -= 10; - else - gain--; - } else if (shutter < 316) { /* max 0x13b */ - if (luma > 115 && shutter < 266) - shutter += 50; - else - shutter++; - } - } - if (gain != sd->ctrls[GAIN].val) { - sd->ctrls[GAIN].val = gain; - setgain(gspca_dev); - } - if (shutter != sd->ctrls[EXPOSURE].val) { - sd->ctrls[EXPOSURE].val = shutter; - setexposure(gspca_dev); + switch (sd->webcam) { + case P35u: + coarse_grained_expo_autogain(gspca_dev, luma, 100, 5); + break; + default: + auto_gain_n_exposure(gspca_dev, luma, 100, 5, 230, 0); + break; } } @@ -2035,9 +1992,9 @@ static const struct ctrl sd_ctrls[NCTRLS] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Gain", .minimum = 0, - .maximum = 63, + .maximum = 253, .step = 1, - .default_value = 16 + .default_value = 128 }, .set_control = setgain }, @@ -2049,7 +2006,7 @@ static const struct ctrl sd_ctrls[NCTRLS] = { .minimum = 0, .maximum = 9, .step = 1, - .default_value = 1 + .default_value = 9 }, .set_control = setexposure }, @@ -2061,7 +2018,7 @@ static const struct ctrl sd_ctrls[NCTRLS] = { .minimum = 0, .maximum = 1, .step = 1, - .default_value = 1, + .default_value = AUTOGAIN_DEF, .flags = V4L2_CTRL_FLAG_UPDATE }, .set = sd_setautogain -- cgit v1.2.2 From ee32ffbf8e446e9b8c247ae9c9ba032979c3eafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 05:58:19 -0300 Subject: [media] gspca - nw80x: Check the bridge from the webcam type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 146 ++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index d2d356e87539..f2adf6f0426f 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -79,75 +79,80 @@ enum webcams { NWEBCAMS /* number of webcams */ }; +static const u8 webcam_chip[NWEBCAMS] = { + [Generic800] = BRIDGE_NW800, /* 06a5:0000 + * Typhoon Webcam 100 USB */ + + [SpaceCam] = BRIDGE_NW800, /* 06a5:d800 + * Trust SpaceCam120 or SpaceCam100 PORTABLE */ + + [SpaceCam2] = BRIDGE_NW800, /* 06a5:d800 - pas106 + * other Trust SpaceCam120 or SpaceCam100 PORTABLE */ + + [Cvideopro] = BRIDGE_NW802, /* 06a5:d001 + * Conceptronic Video Pro 'CVIDEOPRO USB Webcam CCD' */ + + [Dlink350c] = BRIDGE_NW802, /* 06a5:d001 + * D-Link NetQam Pro 250plus */ + + [DS3303u] = BRIDGE_NW801, /* 06a5:d001 + * Plustek Opticam 500U or ProLink DS3303u */ + + [Kr651us] = BRIDGE_NW802, /* 06a5:d001 + * Panasonic GP-KR651US */ + + [Kritter] = BRIDGE_NW802, /* 06a5:d001 + * iRez Kritter cam */ + + [Mustek300] = BRIDGE_NW802, /* 055f:d001 + * Mustek Wcam 300 mini */ + + [Proscope] = BRIDGE_NW802, /* 06a5:d001 + * Scalar USB Microscope (ProScope) */ + + [Twinkle] = BRIDGE_NW800, /* 06a5:d800 - hv7121b? (seems pas106) + * Divio Chicony TwinkleCam + * DSB-C110 */ + + [DvcV6] = BRIDGE_NW802, /* 0502:d001 + * DVC V6 */ + + [P35u] = BRIDGE_NW801, /* 052b:d001, 06a5:d001 and 06be:d001 + * EZCam Pro p35u */ + + [Generic802] = BRIDGE_NW802, +}; +/* + * other webcams: + * - nw801 046d:d001 + * Logitech QuickCam Pro (dark focus ring) + * - nw801 0728:d001 + * AVerMedia Camguard + * - nw??? 06a5:d001 + * D-Link NetQam Pro 250plus + * - nw800 065a:d800 + * Showcam NGS webcam + * - nw??? ????:???? + * Sceptre svc300 + */ + /* - - webcams: - - Typhoon Webcam 100 USB (06a5:0000) - nw800 - - Trust SpaceCam120 or SpaceCam100 PORTABLE (06a5:d800) - nw801 SpaceCam.init - or trust_space.init if no LED (?) - - Divio Chicony TwinkleCam (06a5:d800) ? - nw800 Twinkle.init - - Plustek Opticam 500U or ProLink DS3303u - nw801 DS3303u.init - - Logitech QuickCam Pro (dark focus ring) (046d:d001) - nw801 - - EZCam Pro p35u (052b:d001, 06a5:d001 and 06be:d001) - nw801 - sensor Sharp IR3Y38M - - AVerMedia Camguard (0728:d001) - nw801 - - Panasonic GP-KR651US (06a5:d001) - nw802 kr651us.init - - iRez Kritter cam - nw802 kritter.init - - D-link dru-350c cam - nw802 d-link-350c.init - - The Scope USB Microscope M2 (ProScope) - = Divio ProLink DS3303u WebCam (06a5:d001) - = Scalar USB Microscope M2 (Proscope) - nw802 proscope.init - - Conceptronic Video Pro 'CVIDEOPRO USB Webcam CCD' (06a5:d001) - nw802 cvideopro.init - - Mustek Wcam 300 mini - nw802 mustek_300_mini.init - - D-Link NetQam Pro 250plus (06a5:d001) - - Showcam NGS webcam (065a:d800) - - sceptre svc300 - - DSB-C110 (06a5:d800) - et31x110 - - DVC V6 (0502:d001) - nw802 - - registers - nw800/et31x110 nw801 nw802 - 0000..009e 0000..00a1 0000..009e - 0200..0211 id id - 0300..0302 id id - 0400..0406 (inex) 0400..0406 - 0500..0505 0500..0506 (inex) - 0600..061a 0600..0601 0600..0601 - 0800..0814 id id - 1000..109c 1000..10a1 1000..109a - - 080c: luma (nw800/nw802) - 080d: luma (nw801) - 1004: LUT (?) - 100b: R gain (0..63) - 100c: B gain - 100d: G gain - 100e: Y gain - 100f: U gain - 1010: V gain - 1019: clock (nw801 - bit 0x08: indoor/outdoor) - 101b: shutter 1 (0..255) - 101c: shutter 2 - 1026: BP = gain (nw801) - 1041, 1052, 1063, 1074: LUT base (nw802) - 1048, 1059, 106a, 107b: LUT base (nw801) - - resolutions - nw800 352x288 - nw801/nw802 320x240 - 640x480 -*/ + * registers + * nw800/et31x110 nw801 nw802 + * 0000..009e 0000..00a1 0000..009e + * 0200..0211 id id + * 0300..0302 id id + * 0400..0406 (inex) 0400..0406 + * 0500..0505 0500..0506 (inex) + * 0600..061a 0600..0601 0600..0601 + * 0800..0814 id id + * 1000..109c 1000..10a1 1000..109a + */ +/* resolutions + * nw800: 320x240, 352x288 + * nw801/802: 320x240, 640x480 + */ static const struct v4l2_pix_format cif_mode[] = { {352, 288, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, .bytesperline = 352, @@ -1769,7 +1774,12 @@ static int sd_config(struct gspca_dev *gspca_dev, if (sd->webcam == Generic800) sd->webcam = P35u; } - PDEBUG(D_PROBE, "Bridge nw80%d", sd->bridge); + if (webcam_chip[sd->webcam] != sd->bridge) { + err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge); + gspca_dev->usb_err = -ENODEV; + return gspca_dev->usb_err; + } + PDEBUG(D_PROBE, "Bridge nw80%d - type: %d", sd->bridge, sd->webcam); if (sd->bridge == BRIDGE_NW800) { gspca_dev->cam.cam_mode = cif_mode; -- cgit v1.2.2 From 152507144a59d74423a25e1ba80f4f7f17449417 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 06:04:09 -0300 Subject: [media] gspca - nw80x: Fix some image resolutions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No 352x288 for Ds3303 and no 320x240 for Generic802. Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index f2adf6f0426f..cfab8973e95c 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -154,6 +154,10 @@ static const u8 webcam_chip[NWEBCAMS] = { * nw801/802: 320x240, 640x480 */ static const struct v4l2_pix_format cif_mode[] = { + {320, 240, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 4 / 8, + .colorspace = V4L2_COLORSPACE_JPEG}, {352, 288, V4L2_PIX_FMT_JPGL, V4L2_FIELD_NONE, .bytesperline = 352, .sizeimage = 352 * 288 * 4 / 8, @@ -1782,12 +1786,18 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Bridge nw80%d - type: %d", sd->bridge, sd->webcam); if (sd->bridge == BRIDGE_NW800) { - gspca_dev->cam.cam_mode = cif_mode; - gspca_dev->cam.nmodes = ARRAY_SIZE(cif_mode); + switch (sd->webcam) { + case DS3303u: + gspca_dev->cam.cam_mode = cif_mode; /* qvga */ + break; + default: + gspca_dev->cam.cam_mode = &cif_mode[1]; /* cif */ + break; + } + gspca_dev->cam.nmodes = 1; } else { gspca_dev->cam.cam_mode = vga_mode; switch (sd->webcam) { - case Generic802: case Kr651us: case Proscope: case P35u: -- cgit v1.2.2 From 088fc390bd2d6af547043b4579bf52d1c163c702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 06:07:40 -0300 Subject: [media] gspca - nw80x: Get the sensor ID when bridge et31x110 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index cfab8973e95c..b6d7c8dbb94f 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -1768,6 +1768,8 @@ static int sd_config(struct gspca_dev *gspca_dev, * If 0x0500 does not exist => NW802 * If it does, test 0x109b. If it doesn't exist, * then it's a NW801. Else, a NW800 + * If a et31x110 (nw800 and 06a5:d800) + * get the sensor ID */ if (!nw802_test_reg(gspca_dev, 0x0500, 0x55)) { sd->bridge = BRIDGE_NW802; @@ -1777,6 +1779,24 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->bridge = BRIDGE_NW801; if (sd->webcam == Generic800) sd->webcam = P35u; + } else if (id->idVendor == 0x06a5 && id->idProduct == 0xd800) { + reg_r(gspca_dev, 0x0403, 1); /* GPIO */ + PDEBUG(D_PROBE, "et31x110 sensor type %02x", + gspca_dev->usb_buf[0]); + switch (gspca_dev->usb_buf[0] >> 1) { + case 0x00: /* ?? */ + if (sd->webcam == Generic800) + sd->webcam = SpaceCam; + break; + case 0x01: /* Hynix? */ + if (sd->webcam == Generic800) + sd->webcam = Twinkle; + break; + case 0x0a: /* Pixart */ + if (sd->webcam == Generic800) + sd->webcam = SpaceCam2; + break; + } } if (webcam_chip[sd->webcam] != sd->bridge) { err("Bad webcam type %d for NW80%d", sd->webcam, sd->bridge); -- cgit v1.2.2 From 8e3c08bb41145bd8507397f63937759500c12a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 06:09:49 -0300 Subject: [media] gspca - nw80x: Fix exposure for some webcams MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/nw80x.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index b6d7c8dbb94f..8e754fd4dc5e 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -1700,6 +1700,9 @@ static void setexposure(struct gspca_dev *gspca_dev) v[0] = ((9 - val) << 3) | 0x01; reg_w(gspca_dev, 0x1019, v, 1); break; + case Cvideopro: + case DvcV6: + case Kritter: case Kr651us: v[0] = val; v[1] = val >> 8; -- cgit v1.2.2 From 7106225a9e7d123ff87a6848972b6d28c8903940 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Mon, 21 Mar 2011 16:58:56 -0300 Subject: [media] gspca - main: Add endpoint direction test in alt_xfer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes a bug in gspca, more precisely in alt_xfer(). This function looks for an input transfer endpoint in an alternate setting. By default it returns the first endpoint corresponding to the transfer type indicated in parameter. But with some USB devices, the first endpoint corresponding to the transfer type is not always an INPUT endpoint but an OUTPUT one. This patch adds the endpoint direction test to be sure to return an INPUT endpoint Signed-off-by: Patrice CHOTARD Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/gspca.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 62881740a0bd..9c6a643caf01 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -630,7 +630,8 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, ep = &alt->endpoint[i]; attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; if (attr == xfer - && ep->desc.wMaxPacketSize != 0) + && ep->desc.wMaxPacketSize != 0 + && usb_endpoint_dir_in(&ep->desc)) return ep; } return NULL; -- cgit v1.2.2 From 590f21680616a78f7d6972b92ceb540e306452c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Moine?= Date: Tue, 22 Mar 2011 06:47:56 -0300 Subject: [media] gspca - zc3xx: Add exposure control for sensor hv7131r MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/zc3xx.c | 76 +++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 6dcb1cf11b5c..fa164e861cde 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -39,6 +39,7 @@ static int force_sensor = -1; enum e_ctrl { BRIGHTNESS, CONTRAST, + EXPOSURE, GAMMA, AUTOGAIN, LIGHTFREQ, @@ -46,6 +47,8 @@ enum e_ctrl { NCTRLS /* number of controls */ }; +#define AUTOGAIN_DEF 1 + /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ @@ -92,7 +95,8 @@ enum sensors { /* V4L2 controls supported by the driver */ static void setcontrast(struct gspca_dev *gspca_dev); -static void setautogain(struct gspca_dev *gspca_dev); +static void setexposure(struct gspca_dev *gspca_dev); +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static void setlightfreq(struct gspca_dev *gspca_dev); static void setsharpness(struct gspca_dev *gspca_dev); @@ -121,6 +125,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = { }, .set_control = setcontrast }, +[EXPOSURE] = { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0x30d, + .maximum = 0x493e, + .step = 1, + .default_value = 0x927 + }, + .set_control = setexposure + }, [GAMMA] = { { .id = V4L2_CID_GAMMA, @@ -141,9 +157,10 @@ static const struct ctrl sd_ctrls[NCTRLS] = { .minimum = 0, .maximum = 1, .step = 1, - .default_value = 1, + .default_value = AUTOGAIN_DEF, + .flags = V4L2_CTRL_FLAG_UPDATE }, - .set_control = setautogain + .set = sd_setautogain }, [LIGHTFREQ] = { { @@ -5926,6 +5943,26 @@ static void setcontrast(struct gspca_dev *gspca_dev) reg_w(gspca_dev, gr[i], 0x0130 + i); /* gradient */ } +static void getexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) + | (i2c_read(gspca_dev, 0x26) << 1) + | (i2c_read(gspca_dev, 0x27) >> 7); +} + +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + + val = sd->ctrls[EXPOSURE].val; + i2c_write(gspca_dev, 0x25, val >> 9, 0x00); + i2c_write(gspca_dev, 0x26, val >> 1, 0x00); + i2c_write(gspca_dev, 0x27, val << 7, 0x00); +} + static void setquality(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -6623,10 +6660,19 @@ static int sd_init(struct gspca_dev *gspca_dev) sd->ctrls[GAMMA].def = gamma[sd->sensor]; switch (sd->sensor) { + case SENSOR_HV7131R: + break; case SENSOR_OV7630C: - gspca_dev->ctrl_dis = (1 << LIGHTFREQ); + gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); + break; + default: + gspca_dev->ctrl_dis = (1 << EXPOSURE); break; } +#if AUTOGAIN_DEF + if (sd->ctrls[AUTOGAIN].val) + gspca_dev->ctrl_inac = (1 << EXPOSURE); +#endif /* switch off the led */ reg_w(gspca_dev, 0x01, 0x0000); @@ -6772,9 +6818,8 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x40, 0x0117); break; case SENSOR_HV7131R: - i2c_write(gspca_dev, 0x25, 0x04, 0x00); /* exposure */ - i2c_write(gspca_dev, 0x26, 0x93, 0x00); - i2c_write(gspca_dev, 0x27, 0xe0, 0x00); + if (!sd->ctrls[AUTOGAIN].val) + setexposure(gspca_dev); reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); break; case SENSOR_GC0305: @@ -6852,6 +6897,23 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } +static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->ctrls[AUTOGAIN].val = val; + if (val) { + gspca_dev->ctrl_inac |= (1 << EXPOSURE); + } else { + gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); + if (gspca_dev->streaming) + getexposure(gspca_dev); + } + if (gspca_dev->streaming) + setautogain(gspca_dev); + return gspca_dev->usb_err; +} + static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { -- cgit v1.2.2 From b50b3a1acd22a07e354a154e5d00a9d338446b77 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Sun, 6 Mar 2011 13:37:00 -0300 Subject: [media] STV0288 added full frontend status status now returns FE_HAS_CARRIER FE_HAS_SIGNAL FE_HAS_VITERBI Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/stv0288.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c index 63db8fd2754c..e3fe17fd96fb 100644 --- a/drivers/media/dvb/frontends/stv0288.c +++ b/drivers/media/dvb/frontends/stv0288.c @@ -367,8 +367,11 @@ static int stv0288_read_status(struct dvb_frontend *fe, fe_status_t *status) dprintk("%s : FE_READ_STATUS : VSTATUS: 0x%02x\n", __func__, sync); *status = 0; - - if ((sync & 0x08) == 0x08) { + if (sync & 0x80) + *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL; + if (sync & 0x10) + *status |= FE_HAS_VITERBI; + if (sync & 0x08) { *status |= FE_HAS_LOCK; dprintk("stv0288 has locked\n"); } -- cgit v1.2.2 From 3e507c55918b51fed30ae5e9a3667c6a5f2e8755 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 10 Mar 2011 19:41:29 -0300 Subject: [media] saa7134: Fix strange kconfig dependency on RC_CORE As the code in saa7134-input is not a module, but the config for it is set as a boolean instead of a tristate, this causes a strange dependency on RC_CORE. VIDEO_SAA7134_RC (which determines if saa7134-input.o is built) depends on RC_CORE and VIDEO_SAA7134. If VIDEO_SAA7134 is compiled as 'y' but RC_CORE is compiled as 'm' VIDEO_SAA7134_RC can still be set to 'y' which causes undefined symbols that it needs from RC_CORE. The simplest solution is to not allow VIDEO_SAA7134_RC be enabled if RC_CORE compiled as a module (m) and VIDEO_SA7134 is compiled into the kernel (y). Suggested-by: Mauro Carvalho Chehab Cc: Michal Marek Cc: linux-kbuild Signed-off-by: Steven Rostedt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/saa7134/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 380f1b28cfcc..39fc0187a747 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -28,6 +28,7 @@ config VIDEO_SAA7134_RC bool "Philips SAA7134 Remote Controller support" depends on RC_CORE depends on VIDEO_SAA7134 + depends on !(RC_CORE=m && VIDEO_SAA7134=y) default y ---help--- Enables Remote Controller support on saa7134 driver. -- cgit v1.2.2 From baf075eca42f217e8d297914ed6fecfd2452a0e4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Mar 2011 15:03:09 -0300 Subject: [media] drivers/media/rc/Kconfig: use tabs, instead of spaces Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 3785162f928e..1143845dd688 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -161,20 +161,20 @@ config IR_STREAMZAP module will be called streamzap. config IR_WINBOND_CIR - tristate "Winbond IR remote control" - depends on X86 && PNP + tristate "Winbond IR remote control" + depends on X86 && PNP depends on RC_CORE - select NEW_LEDS - select LEDS_CLASS - select LEDS_TRIGGERS - select BITREVERSE - ---help--- - Say Y here if you want to use the IR remote functionality found - in some Winbond SuperI/O chips. Currently only the WPCD376I - chip is supported (included in some Intel Media series + select NEW_LEDS + select LEDS_CLASS + select LEDS_TRIGGERS + select BITREVERSE + ---help--- + Say Y here if you want to use the IR remote functionality found + in some Winbond SuperI/O chips. Currently only the WPCD376I + chip is supported (included in some Intel Media series motherboards). - To compile this driver as a module, choose M here: the module will + To compile this driver as a module, choose M here: the module will be called winbond_cir. config RC_LOOPBACK -- cgit v1.2.2 From 620a32bba4a2dd57ccf1d5f87b9e6d2402ffec22 Mon Sep 17 00:00:00 2001 From: "Juan J. Garcia de Soria" Date: Wed, 16 Mar 2011 17:14:52 -0300 Subject: [media] rc: New rc-based ite-cir driver for several ITE CIRs This is a second version of an rc-core based driver for the ITE Tech IT8712F CIR and now for a pair of other variants of the IT8512 CIR too. This driver should replace the lirc_it87 and lirc_ite8709 currently living in the LIRC staging directory. The driver should support the ITE8704, ITE8713, ITE8708 and ITE8709 (this last one yet untested) PNP ID's. The code doesn'te reuse code from the pre-existing LIRC drivers, but has been written from scratch using the nuvoton.cir driver as a skeleton. This new driver shouldn't exhibit timing problems when running under load (or with interrupts disabled for relatively long times). It works OOTB with the RC6 MCE remote bundled with the ASUS EEEBox. TX support is implemented, but I'm unable to test it since my hardware lacks TX capability. Signed-off-by: Juan J. Garcia de Soria Tested-by: Stephan Raue Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 13 + drivers/media/rc/Makefile | 1 + drivers/media/rc/ite-cir.c | 1734 ++++++++++++++++++++++++++++++++++++++++++++ drivers/media/rc/ite-cir.h | 478 ++++++++++++ 4 files changed, 2226 insertions(+) create mode 100644 drivers/media/rc/ite-cir.c create mode 100644 drivers/media/rc/ite-cir.h (limited to 'drivers') diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 1143845dd688..7f03142a329f 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -135,6 +135,19 @@ config IR_MCEUSB To compile this driver as a module, choose M here: the module will be called mceusb. +config IR_ITE_CIR + tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver" + depends on PNP + depends on RC_CORE + ---help--- + Say Y here to enable support for integrated infrared receivers + /transceivers made by ITE Tech Inc. These are found in + several ASUS devices, like the ASUS Digimatrix or the ASUS + EEEBox 1501U. + + To compile this driver as a module, choose M here: the + module will be called ite-cir. + config IR_NUVOTON tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" depends on PNP diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 67b4f7fe2577..c6cfe70d862f 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o # stand-alone IR receivers/transmitters obj-$(CONFIG_IR_IMON) += imon.o +obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o obj-$(CONFIG_IR_ENE) += ene_ir.o diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c new file mode 100644 index 000000000000..10358d5b3189 --- /dev/null +++ b/drivers/media/rc/ite-cir.c @@ -0,0 +1,1734 @@ +/* + * Driver for ITE Tech Inc. IT8712F/IT8512 CIR + * + * Copyright (C) 2010 Juan Jesús García de Soria + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Inspired by the original lirc_it87 and lirc_ite8709 drivers, on top of the + * skeleton provided by the nuvoton-cir driver. + * + * The lirc_it87 driver was originally written by Hans-Gunter Lutke Uphues + * in 2001, with enhancements by Christoph Bartelmus + * , Andrew Calkin and James Edwards + * . + * + * The lirc_ite8709 driver was written by Grégory Lardière + * in 2008. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ite-cir.h" + +/* module parameters */ + +/* debug level */ +static int debug; +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Enable debugging output"); + +/* low limit for RX carrier freq, Hz, 0 for no RX demodulation */ +static int rx_low_carrier_freq; +module_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, " + "0 for no RX demodulation"); + +/* high limit for RX carrier freq, Hz, 0 for no RX demodulation */ +static int rx_high_carrier_freq; +module_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, " + "Hz, 0 for no RX demodulation"); + +/* override tx carrier frequency */ +static int tx_carrier_freq; +module_param(tx_carrier_freq, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(tx_carrier_freq, "Override TX carrier frequency, Hz"); + +/* override tx duty cycle */ +static int tx_duty_cycle; +module_param(tx_duty_cycle, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(tx_duty_cycle, "Override TX duty cycle, 1-100"); + +/* override default sample period */ +static long sample_period; +module_param(sample_period, long, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(sample_period, "Override carrier sample period, us"); + +/* override detected model id */ +static int model_number = -1; +module_param(model_number, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(model_number, "Use this model number, don't autodetect"); + + +/* HW-independent code functions */ + +/* check whether carrier frequency is high frequency */ +static inline bool ite_is_high_carrier_freq(unsigned int freq) +{ + return freq >= ITE_HCF_MIN_CARRIER_FREQ; +} + +/* get the bits required to program the carrier frequency in CFQ bits, + * unshifted */ +static u8 ite_get_carrier_freq_bits(unsigned int freq) +{ + if (ite_is_high_carrier_freq(freq)) { + if (freq < 425000) + return ITE_CFQ_400; + + else if (freq < 465000) + return ITE_CFQ_450; + + else if (freq < 490000) + return ITE_CFQ_480; + + else + return ITE_CFQ_500; + } else { + /* trim to limits */ + if (freq < ITE_LCF_MIN_CARRIER_FREQ) + freq = ITE_LCF_MIN_CARRIER_FREQ; + if (freq > ITE_LCF_MAX_CARRIER_FREQ) + freq = ITE_LCF_MAX_CARRIER_FREQ; + + /* convert to kHz and subtract the base freq */ + freq = + DIV_ROUND_CLOSEST(freq - ITE_LCF_MIN_CARRIER_FREQ, + 1000); + + return (u8) freq; + } +} + +/* get the bits required to program the pulse with in TXMPW */ +static u8 ite_get_pulse_width_bits(unsigned int freq, int duty_cycle) +{ + unsigned long period_ns, on_ns; + + /* sanitize freq into range */ + if (freq < ITE_LCF_MIN_CARRIER_FREQ) + freq = ITE_LCF_MIN_CARRIER_FREQ; + if (freq > ITE_HCF_MAX_CARRIER_FREQ) + freq = ITE_HCF_MAX_CARRIER_FREQ; + + period_ns = 1000000000UL / freq; + on_ns = period_ns * duty_cycle / 100; + + if (ite_is_high_carrier_freq(freq)) { + if (on_ns < 750) + return ITE_TXMPW_A; + + else if (on_ns < 850) + return ITE_TXMPW_B; + + else if (on_ns < 950) + return ITE_TXMPW_C; + + else if (on_ns < 1080) + return ITE_TXMPW_D; + + else + return ITE_TXMPW_E; + } else { + if (on_ns < 6500) + return ITE_TXMPW_A; + + else if (on_ns < 7850) + return ITE_TXMPW_B; + + else if (on_ns < 9650) + return ITE_TXMPW_C; + + else if (on_ns < 11950) + return ITE_TXMPW_D; + + else + return ITE_TXMPW_E; + } +} + +/* decode raw bytes as received by the hardware, and push them to the ir-core + * layer */ +static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int + length) +{ + u32 sample_period; + unsigned long *ldata; + unsigned int next_one, next_zero, size; + DEFINE_IR_RAW_EVENT(ev); + + if (length == 0) + return; + + sample_period = dev->params.sample_period; + ldata = (unsigned long *)data; + size = length << 3; + next_one = generic_find_next_le_bit(ldata, size, 0); + if (next_one > 0) { + ev.pulse = true; + ev.duration = + ITE_BITS_TO_NS(next_one, sample_period); + ir_raw_event_store_with_filter(dev->rdev, &ev); + } + + while (next_one < size) { + next_zero = generic_find_next_zero_le_bit(ldata, size, next_one + 1); + ev.pulse = false; + ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period); + ir_raw_event_store_with_filter(dev->rdev, &ev); + + if (next_zero < size) { + next_one = + generic_find_next_le_bit(ldata, + size, + next_zero + 1); + ev.pulse = true; + ev.duration = + ITE_BITS_TO_NS(next_one - next_zero, + sample_period); + ir_raw_event_store_with_filter + (dev->rdev, &ev); + } else + next_one = size; + } + + ir_raw_event_handle(dev->rdev); + + ite_dbg_verbose("decoded %d bytes.", length); +} + +/* set all the rx/tx carrier parameters; this must be called with the device + * spinlock held */ +static void ite_set_carrier_params(struct ite_dev *dev) +{ + unsigned int freq, low_freq, high_freq; + int allowance; + bool use_demodulator; + bool for_tx = dev->transmitting; + + ite_dbg("%s called", __func__); + + if (for_tx) { + /* we don't need no stinking calculations */ + freq = dev->params.tx_carrier_freq; + allowance = ITE_RXDCR_DEFAULT; + use_demodulator = false; + } else { + low_freq = dev->params.rx_low_carrier_freq; + high_freq = dev->params.rx_high_carrier_freq; + + if (low_freq == 0) { + /* don't demodulate */ + freq = + ITE_DEFAULT_CARRIER_FREQ; + allowance = ITE_RXDCR_DEFAULT; + use_demodulator = false; + } else { + /* calculate the middle freq */ + freq = (low_freq + high_freq) / 2; + + /* calculate the allowance */ + allowance = + DIV_ROUND_CLOSEST(10000 * (high_freq - low_freq), + ITE_RXDCR_PER_10000_STEP + * (high_freq + low_freq)); + + if (allowance < 1) + allowance = 1; + + if (allowance > ITE_RXDCR_MAX) + allowance = ITE_RXDCR_MAX; + } + } + + /* set the carrier parameters in a device-dependent way */ + dev->params.set_carrier_params(dev, ite_is_high_carrier_freq(freq), + use_demodulator, ite_get_carrier_freq_bits(freq), allowance, + ite_get_pulse_width_bits(freq, dev->params.tx_duty_cycle)); +} + +/* interrupt service routine for incoming and outgoing CIR data */ +static irqreturn_t ite_cir_isr(int irq, void *data) +{ + struct ite_dev *dev = data; + unsigned long flags; + irqreturn_t ret = IRQ_RETVAL(IRQ_NONE); + u8 rx_buf[ITE_RX_FIFO_LEN]; + int rx_bytes; + int iflags; + + ite_dbg_verbose("%s firing", __func__); + + /* grab the spinlock */ + spin_lock_irqsave(&dev->lock, flags); + + /* read the interrupt flags */ + iflags = dev->params.get_irq_causes(dev); + + /* check for the receive interrupt */ + if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) { + /* read the FIFO bytes */ + rx_bytes = + dev->params.get_rx_bytes(dev, rx_buf, + ITE_RX_FIFO_LEN); + + if (rx_bytes > 0) { + /* drop the spinlock, since the ir-core layer + * may call us back again through + * ite_s_idle() */ + spin_unlock_irqrestore(&dev-> + lock, + flags); + + /* decode the data we've just received */ + ite_decode_bytes(dev, rx_buf, + rx_bytes); + + /* reacquire the spinlock */ + spin_lock_irqsave(&dev->lock, + flags); + + /* mark the interrupt as serviced */ + ret = IRQ_RETVAL(IRQ_HANDLED); + } + } else if (iflags & ITE_IRQ_TX_FIFO) { + /* FIFO space available interrupt */ + ite_dbg_verbose("got interrupt for TX FIFO"); + + /* wake any sleeping transmitter */ + wake_up_interruptible(&dev->tx_queue); + + /* mark the interrupt as serviced */ + ret = IRQ_RETVAL(IRQ_HANDLED); + } + + /* drop the spinlock */ + spin_unlock_irqrestore(&dev->lock, flags); + + ite_dbg_verbose("%s done returning %d", __func__, (int)ret); + + return ret; +} + +/* set the rx carrier freq range, guess it's in Hz... */ +static int ite_set_rx_carrier_range(struct rc_dev *rcdev, u32 carrier_low, u32 + carrier_high) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + spin_lock_irqsave(&dev->lock, flags); + dev->params.rx_low_carrier_freq = carrier_low; + dev->params.rx_high_carrier_freq = carrier_high; + ite_set_carrier_params(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* set the tx carrier freq, guess it's in Hz... */ +static int ite_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + spin_lock_irqsave(&dev->lock, flags); + dev->params.tx_carrier_freq = carrier; + ite_set_carrier_params(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* set the tx duty cycle by controlling the pulse width */ +static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + spin_lock_irqsave(&dev->lock, flags); + dev->params.tx_duty_cycle = duty_cycle; + ite_set_carrier_params(dev); + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* transmit out IR pulses; what you get here is a batch of alternating + * pulse/space/pulse/space lengths that we should write out completely through + * the FIFO, blocking on a full FIFO */ +static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + bool is_pulse = false; + int remaining_us, fifo_avail, fifo_remaining, last_idx = 0; + int max_rle_us, next_rle_us; + int ret = n; + u8 last_sent[ITE_TX_FIFO_LEN]; + u8 val; + + ite_dbg("%s called", __func__); + + /* clear the array just in case */ + memset(last_sent, 0, ARRAY_SIZE(last_sent)); + + /* n comes in bytes; convert to ints */ + n /= sizeof(int); + + spin_lock_irqsave(&dev->lock, flags); + + /* let everybody know we're now transmitting */ + dev->transmitting = true; + + /* and set the carrier values for transmission */ + ite_set_carrier_params(dev); + + /* calculate how much time we can send in one byte */ + max_rle_us = + (ITE_BAUDRATE_DIVISOR * dev->params.sample_period * + ITE_TX_MAX_RLE) / 1000; + + /* disable the receiver */ + dev->params.disable_rx(dev); + + /* this is where we'll begin filling in the FIFO, until it's full. + * then we'll just activate the interrupt, wait for it to wake us up + * again, disable it, continue filling the FIFO... until everything + * has been pushed out */ + fifo_avail = + ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); + + while (n > 0 && dev->in_use) { + /* transmit the next sample */ + is_pulse = !is_pulse; + remaining_us = *(txbuf++); + n--; + + ite_dbg("%s: %ld", + ((is_pulse) ? "pulse" : "space"), + (long int) + remaining_us); + + /* repeat while the pulse is non-zero length */ + while (remaining_us > 0 && dev->in_use) { + if (remaining_us > max_rle_us) + next_rle_us = max_rle_us; + + else + next_rle_us = remaining_us; + + remaining_us -= next_rle_us; + + /* check what's the length we have to pump out */ + val = (ITE_TX_MAX_RLE * next_rle_us) / max_rle_us; + + /* put it into the sent buffer */ + last_sent[last_idx++] = val; + last_idx &= (ITE_TX_FIFO_LEN); + + /* encode it for 7 bits */ + val = (val - 1) & ITE_TX_RLE_MASK; + + /* take into account pulse/space prefix */ + if (is_pulse) + val |= ITE_TX_PULSE; + + else + val |= ITE_TX_SPACE; + + /* if we get to 0 available, read again, just in case + * some other slot got freed */ + if (fifo_avail <= 0) + fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); + + /* if it's still full */ + if (fifo_avail <= 0) { + /* enable the tx interrupt */ + dev->params. + enable_tx_interrupt(dev); + + /* drop the spinlock */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* wait for the FIFO to empty enough */ + wait_event_interruptible(dev->tx_queue, (fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev)) >= 8); + + /* get the spinlock again */ + spin_lock_irqsave(&dev->lock, flags); + + /* disable the tx interrupt again. */ + dev->params. + disable_tx_interrupt(dev); + } + + /* now send the byte through the FIFO */ + dev->params.put_tx_byte(dev, val); + fifo_avail--; + } + } + + /* wait and don't return until the whole FIFO has been sent out; + * otherwise we could configure the RX carrier params instead of the + * TX ones while the transmission is still being performed! */ + fifo_remaining = dev->params.get_tx_used_slots(dev); + remaining_us = 0; + while (fifo_remaining > 0) { + fifo_remaining--; + last_idx--; + last_idx &= (ITE_TX_FIFO_LEN - 1); + remaining_us += last_sent[last_idx]; + } + remaining_us = (remaining_us * max_rle_us) / (ITE_TX_MAX_RLE); + + /* drop the spinlock while we sleep */ + spin_unlock_irqrestore(&dev->lock, flags); + + /* sleep remaining_us microseconds */ + mdelay(DIV_ROUND_UP(remaining_us, 1000)); + + /* reacquire the spinlock */ + spin_lock_irqsave(&dev->lock, flags); + + /* now we're not transmitting anymore */ + dev->transmitting = false; + + /* and set the carrier values for reception */ + ite_set_carrier_params(dev); + + /* reenable the receiver */ + if (dev->in_use) + dev->params.enable_rx(dev); + + /* notify transmission end */ + wake_up_interruptible(&dev->tx_ended); + + spin_unlock_irqrestore(&dev->lock, flags); + + return ret; +} + +/* idle the receiver if needed */ +static void ite_s_idle(struct rc_dev *rcdev, bool enable) +{ + unsigned long flags; + struct ite_dev *dev = rcdev->priv; + + ite_dbg("%s called", __func__); + + if (enable) { + spin_lock_irqsave(&dev->lock, flags); + dev->params.idle_rx(dev); + spin_unlock_irqrestore(&dev->lock, flags); + } +} + + +/* IT8712F HW-specific functions */ + +/* retrieve a bitmask of the current causes for a pending interrupt; this may + * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN + * */ +static int it87_get_irq_causes(struct ite_dev *dev) +{ + u8 iflags; + int ret = 0; + + ite_dbg("%s called", __func__); + + /* read the interrupt flags */ + iflags = inb(dev->cir_addr + IT87_IIR) & IT87_II; + + switch (iflags) { + case IT87_II_RXDS: + ret = ITE_IRQ_RX_FIFO; + break; + case IT87_II_RXFO: + ret = ITE_IRQ_RX_FIFO_OVERRUN; + break; + case IT87_II_TXLDL: + ret = ITE_IRQ_TX_FIFO; + break; + } + + return ret; +} + +/* set the carrier parameters; to be called with the spinlock held */ +static void it87_set_carrier_params(struct ite_dev *dev, bool high_freq, + bool use_demodulator, + u8 carrier_freq_bits, u8 allowance_bits, + u8 pulse_width_bits) +{ + u8 val; + + ite_dbg("%s called", __func__); + + /* program the RCR register */ + val = inb(dev->cir_addr + IT87_RCR) + & ~(IT87_HCFS | IT87_RXEND | IT87_RXDCR); + + if (high_freq) + val |= IT87_HCFS; + + if (use_demodulator) + val |= IT87_RXEND; + + val |= allowance_bits; + + outb(val, dev->cir_addr + IT87_RCR); + + /* program the TCR2 register */ + outb((carrier_freq_bits << IT87_CFQ_SHIFT) | pulse_width_bits, + dev->cir_addr + IT87_TCR2); +} + +/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock + * held */ +static int it87_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) +{ + int fifo, read = 0; + + ite_dbg("%s called", __func__); + + /* read how many bytes are still in the FIFO */ + fifo = inb(dev->cir_addr + IT87_RSR) & IT87_RXFBC; + + while (fifo > 0 && buf_size > 0) { + *(buf++) = inb(dev->cir_addr + IT87_DR); + fifo--; + read++; + buf_size--; + } + + return read; +} + +/* return how many bytes are still in the FIFO; this will be called + * with the device spinlock NOT HELD while waiting for the TX FIFO to get + * empty; let's expect this won't be a problem */ +static int it87_get_tx_used_slots(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + return inb(dev->cir_addr + IT87_TSR) & IT87_TXFBC; +} + +/* put a byte to the TX fifo; this should be called with the spinlock held */ +static void it87_put_tx_byte(struct ite_dev *dev, u8 value) +{ + outb(value, dev->cir_addr + IT87_DR); +} + +/* idle the receiver so that we won't receive samples until another + pulse is detected; this must be called with the device spinlock held */ +static void it87_idle_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable streaming by clearing RXACT writing it as 1 */ + outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXACT, + dev->cir_addr + IT87_RCR); + + /* clear the FIFO */ + outb(inb(dev->cir_addr + IT87_TCR1) | IT87_FIFOCLR, + dev->cir_addr + IT87_TCR1); +} + +/* disable the receiver; this must be called with the device spinlock held */ +static void it87_disable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the receiver interrupts */ + outb(inb(dev->cir_addr + IT87_IER) & ~(IT87_RDAIE | IT87_RFOIE), + dev->cir_addr + IT87_IER); + + /* disable the receiver */ + outb(inb(dev->cir_addr + IT87_RCR) & ~IT87_RXEN, + dev->cir_addr + IT87_RCR); + + /* clear the FIFO and RXACT (actually RXACT should have been cleared + * in the previous outb() call) */ + it87_idle_rx(dev); +} + +/* enable the receiver; this must be called with the device spinlock held */ +static void it87_enable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the receiver by setting RXEN */ + outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXEN, + dev->cir_addr + IT87_RCR); + + /* just prepare it to idle for the next reception */ + it87_idle_rx(dev); + + /* enable the receiver interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT87_IER) | IT87_RDAIE | IT87_RFOIE | IT87_IEC, + dev->cir_addr + IT87_IER); +} + +/* disable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it87_disable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the transmitter interrupts */ + outb(inb(dev->cir_addr + IT87_IER) & ~IT87_TLDLIE, + dev->cir_addr + IT87_IER); +} + +/* enable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it87_enable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the transmitter interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT87_IER) | IT87_TLDLIE | IT87_IEC, + dev->cir_addr + IT87_IER); +} + +/* disable the device; this must be called with the device spinlock held */ +static void it87_disable(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* clear out all interrupt enable flags */ + outb(inb(dev->cir_addr + IT87_IER) & + ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE), + dev->cir_addr + IT87_IER); + + /* disable the receiver */ + it87_disable_rx(dev); + + /* erase the FIFO */ + outb(IT87_FIFOCLR | inb(dev->cir_addr + IT87_TCR1), + dev->cir_addr + IT87_TCR1); +} + +/* initialize the hardware */ +static void it87_init_hardware(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable just the baud rate divisor register, + disabling all the interrupts at the same time */ + outb((inb(dev->cir_addr + IT87_IER) & + ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE)) | IT87_BR, + dev->cir_addr + IT87_IER); + + /* write out the baud rate divisor */ + outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT87_BDLR); + outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, dev->cir_addr + IT87_BDHR); + + /* disable the baud rate divisor register again */ + outb(inb(dev->cir_addr + IT87_IER) & ~IT87_BR, + dev->cir_addr + IT87_IER); + + /* program the RCR register defaults */ + outb(ITE_RXDCR_DEFAULT, dev->cir_addr + IT87_RCR); + + /* program the TCR1 register */ + outb(IT87_TXMPM_DEFAULT | IT87_TXENDF | IT87_TXRLE + | IT87_FIFOTL_DEFAULT | IT87_FIFOCLR, + dev->cir_addr + IT87_TCR1); + + /* program the carrier parameters */ + ite_set_carrier_params(dev); +} + +/* IT8512F on ITE8708 HW-specific functions */ + +/* retrieve a bitmask of the current causes for a pending interrupt; this may + * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN + * */ +static int it8708_get_irq_causes(struct ite_dev *dev) +{ + u8 iflags; + int ret = 0; + + ite_dbg("%s called", __func__); + + /* read the interrupt flags */ + iflags = inb(dev->cir_addr + IT8708_C0IIR); + + if (iflags & IT85_TLDLI) + ret |= ITE_IRQ_TX_FIFO; + if (iflags & IT85_RDAI) + ret |= ITE_IRQ_RX_FIFO; + if (iflags & IT85_RFOI) + ret |= ITE_IRQ_RX_FIFO_OVERRUN; + + return ret; +} + +/* set the carrier parameters; to be called with the spinlock held */ +static void it8708_set_carrier_params(struct ite_dev *dev, bool high_freq, + bool use_demodulator, + u8 carrier_freq_bits, u8 allowance_bits, + u8 pulse_width_bits) +{ + u8 val; + + ite_dbg("%s called", __func__); + + /* program the C0CFR register, with HRAE=1 */ + outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + val = (inb(dev->cir_addr + IT8708_C0CFR) + & ~(IT85_HCFS | IT85_CFQ)) | carrier_freq_bits; + + if (high_freq) + val |= IT85_HCFS; + + outb(val, dev->cir_addr + IT8708_C0CFR); + + outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + /* program the C0RCR register */ + val = inb(dev->cir_addr + IT8708_C0RCR) + & ~(IT85_RXEND | IT85_RXDCR); + + if (use_demodulator) + val |= IT85_RXEND; + + val |= allowance_bits; + + outb(val, dev->cir_addr + IT8708_C0RCR); + + /* program the C0TCR register */ + val = inb(dev->cir_addr + IT8708_C0TCR) & ~IT85_TXMPW; + val |= pulse_width_bits; + outb(val, dev->cir_addr + IT8708_C0TCR); +} + +/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock + * held */ +static int it8708_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) +{ + int fifo, read = 0; + + ite_dbg("%s called", __func__); + + /* read how many bytes are still in the FIFO */ + fifo = inb(dev->cir_addr + IT8708_C0RFSR) & IT85_RXFBC; + + while (fifo > 0 && buf_size > 0) { + *(buf++) = inb(dev->cir_addr + IT8708_C0DR); + fifo--; + read++; + buf_size--; + } + + return read; +} + +/* return how many bytes are still in the FIFO; this will be called + * with the device spinlock NOT HELD while waiting for the TX FIFO to get + * empty; let's expect this won't be a problem */ +static int it8708_get_tx_used_slots(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + return inb(dev->cir_addr + IT8708_C0TFSR) & IT85_TXFBC; +} + +/* put a byte to the TX fifo; this should be called with the spinlock held */ +static void it8708_put_tx_byte(struct ite_dev *dev, u8 value) +{ + outb(value, dev->cir_addr + IT8708_C0DR); +} + +/* idle the receiver so that we won't receive samples until another + pulse is detected; this must be called with the device spinlock held */ +static void it8708_idle_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable streaming by clearing RXACT writing it as 1 */ + outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXACT, + dev->cir_addr + IT8708_C0RCR); + + /* clear the FIFO */ + outb(inb(dev->cir_addr + IT8708_C0MSTCR) | IT85_FIFOCLR, + dev->cir_addr + IT8708_C0MSTCR); +} + +/* disable the receiver; this must be called with the device spinlock held */ +static void it8708_disable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the receiver interrupts */ + outb(inb(dev->cir_addr + IT8708_C0IER) & + ~(IT85_RDAIE | IT85_RFOIE), + dev->cir_addr + IT8708_C0IER); + + /* disable the receiver */ + outb(inb(dev->cir_addr + IT8708_C0RCR) & ~IT85_RXEN, + dev->cir_addr + IT8708_C0RCR); + + /* clear the FIFO and RXACT (actually RXACT should have been cleared + * in the previous outb() call) */ + it8708_idle_rx(dev); +} + +/* enable the receiver; this must be called with the device spinlock held */ +static void it8708_enable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the receiver by setting RXEN */ + outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXEN, + dev->cir_addr + IT8708_C0RCR); + + /* just prepare it to idle for the next reception */ + it8708_idle_rx(dev); + + /* enable the receiver interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT8708_C0IER) + |IT85_RDAIE | IT85_RFOIE | IT85_IEC, + dev->cir_addr + IT8708_C0IER); +} + +/* disable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8708_disable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the transmitter interrupts */ + outb(inb(dev->cir_addr + IT8708_C0IER) & ~IT85_TLDLIE, + dev->cir_addr + IT8708_C0IER); +} + +/* enable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8708_enable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the transmitter interrupts and master enable flag */ + outb(inb(dev->cir_addr + IT8708_C0IER) + |IT85_TLDLIE | IT85_IEC, + dev->cir_addr + IT8708_C0IER); +} + +/* disable the device; this must be called with the device spinlock held */ +static void it8708_disable(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* clear out all interrupt enable flags */ + outb(inb(dev->cir_addr + IT8708_C0IER) & + ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), + dev->cir_addr + IT8708_C0IER); + + /* disable the receiver */ + it8708_disable_rx(dev); + + /* erase the FIFO */ + outb(IT85_FIFOCLR | inb(dev->cir_addr + IT8708_C0MSTCR), + dev->cir_addr + IT8708_C0MSTCR); +} + +/* initialize the hardware */ +static void it8708_init_hardware(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable all the interrupts */ + outb(inb(dev->cir_addr + IT8708_C0IER) & + ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), + dev->cir_addr + IT8708_C0IER); + + /* program the baud rate divisor */ + outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + outb(ITE_BAUDRATE_DIVISOR & 0xff, dev->cir_addr + IT8708_C0BDLR); + outb((ITE_BAUDRATE_DIVISOR >> 8) & 0xff, + dev->cir_addr + IT8708_C0BDHR); + + outb(inb(dev->cir_addr + IT8708_BANKSEL) & ~IT8708_HRAE, + dev->cir_addr + IT8708_BANKSEL); + + /* program the C0MSTCR register defaults */ + outb((inb(dev->cir_addr + IT8708_C0MSTCR) & + ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL | + IT85_FIFOCLR | IT85_RESET)) | + IT85_FIFOTL_DEFAULT, + dev->cir_addr + IT8708_C0MSTCR); + + /* program the C0RCR register defaults */ + outb((inb(dev->cir_addr + IT8708_C0RCR) & + ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | + IT85_RXACT | IT85_RXDCR)) | + ITE_RXDCR_DEFAULT, + dev->cir_addr + IT8708_C0RCR); + + /* program the C0TCR register defaults */ + outb((inb(dev->cir_addr + IT8708_C0TCR) & + ~(IT85_TXMPM | IT85_TXMPW)) + |IT85_TXRLE | IT85_TXENDF | + IT85_TXMPM_DEFAULT | IT85_TXMPW_DEFAULT, + dev->cir_addr + IT8708_C0TCR); + + /* program the carrier parameters */ + ite_set_carrier_params(dev); +} + +/* IT8512F on ITE8709 HW-specific functions */ + +/* read a byte from the SRAM module */ +static inline u8 it8709_rm(struct ite_dev *dev, int index) +{ + outb(index, dev->cir_addr + IT8709_RAM_IDX); + return inb(dev->cir_addr + IT8709_RAM_VAL); +} + +/* write a byte to the SRAM module */ +static inline void it8709_wm(struct ite_dev *dev, u8 val, int index) +{ + outb(index, dev->cir_addr + IT8709_RAM_IDX); + outb(val, dev->cir_addr + IT8709_RAM_VAL); +} + +static void it8709_wait(struct ite_dev *dev) +{ + int i = 0; + /* + * loop until device tells it's ready to continue + * iterations count is usually ~750 but can sometimes achieve 13000 + */ + for (i = 0; i < 15000; i++) { + udelay(2); + if (it8709_rm(dev, IT8709_MODE) == IT8709_IDLE) + break; + } +} + +/* read the value of a CIR register */ +static u8 it8709_rr(struct ite_dev *dev, int index) +{ + /* just wait in case the previous access was a write */ + it8709_wait(dev); + it8709_wm(dev, index, IT8709_REG_IDX); + it8709_wm(dev, IT8709_READ, IT8709_MODE); + + /* wait for the read data to be available */ + it8709_wait(dev); + + /* return the read value */ + return it8709_rm(dev, IT8709_REG_VAL); +} + +/* write the value of a CIR register */ +static void it8709_wr(struct ite_dev *dev, u8 val, int index) +{ + /* we wait before writing, and not afterwards, since this allows us to + * pipeline the host CPU with the microcontroller */ + it8709_wait(dev); + it8709_wm(dev, val, IT8709_REG_VAL); + it8709_wm(dev, index, IT8709_REG_IDX); + it8709_wm(dev, IT8709_WRITE, IT8709_MODE); +} + +/* retrieve a bitmask of the current causes for a pending interrupt; this may + * be composed of ITE_IRQ_TX_FIFO, ITE_IRQ_RX_FIFO and ITE_IRQ_RX_FIFO_OVERRUN + * */ +static int it8709_get_irq_causes(struct ite_dev *dev) +{ + u8 iflags; + int ret = 0; + + ite_dbg("%s called", __func__); + + /* read the interrupt flags */ + iflags = it8709_rm(dev, IT8709_IIR); + + if (iflags & IT85_TLDLI) + ret |= ITE_IRQ_TX_FIFO; + if (iflags & IT85_RDAI) + ret |= ITE_IRQ_RX_FIFO; + if (iflags & IT85_RFOI) + ret |= ITE_IRQ_RX_FIFO_OVERRUN; + + return ret; +} + +/* set the carrier parameters; to be called with the spinlock held */ +static void it8709_set_carrier_params(struct ite_dev *dev, bool high_freq, + bool use_demodulator, + u8 carrier_freq_bits, u8 allowance_bits, + u8 pulse_width_bits) +{ + u8 val; + + ite_dbg("%s called", __func__); + + val = (it8709_rr(dev, IT85_C0CFR) + &~(IT85_HCFS | IT85_CFQ)) | + carrier_freq_bits; + + if (high_freq) + val |= IT85_HCFS; + + it8709_wr(dev, val, IT85_C0CFR); + + /* program the C0RCR register */ + val = it8709_rr(dev, IT85_C0RCR) + & ~(IT85_RXEND | IT85_RXDCR); + + if (use_demodulator) + val |= IT85_RXEND; + + val |= allowance_bits; + + it8709_wr(dev, val, IT85_C0RCR); + + /* program the C0TCR register */ + val = it8709_rr(dev, IT85_C0TCR) & ~IT85_TXMPW; + val |= pulse_width_bits; + it8709_wr(dev, val, IT85_C0TCR); +} + +/* read up to buf_size bytes from the RX FIFO; to be called with the spinlock + * held */ +static int it8709_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) +{ + int fifo, read = 0; + + ite_dbg("%s called", __func__); + + /* read how many bytes are still in the FIFO */ + fifo = it8709_rm(dev, IT8709_RFSR) & IT85_RXFBC; + + while (fifo > 0 && buf_size > 0) { + *(buf++) = it8709_rm(dev, IT8709_FIFO + read); + fifo--; + read++; + buf_size--; + } + + /* 'clear' the FIFO by setting the writing index to 0; this is + * completely bound to be racy, but we can't help it, since it's a + * limitation of the protocol */ + it8709_wm(dev, 0, IT8709_RFSR); + + return read; +} + +/* return how many bytes are still in the FIFO; this will be called + * with the device spinlock NOT HELD while waiting for the TX FIFO to get + * empty; let's expect this won't be a problem */ +static int it8709_get_tx_used_slots(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + return it8709_rr(dev, IT85_C0TFSR) & IT85_TXFBC; +} + +/* put a byte to the TX fifo; this should be called with the spinlock held */ +static void it8709_put_tx_byte(struct ite_dev *dev, u8 value) +{ + it8709_wr(dev, value, IT85_C0DR); +} + +/* idle the receiver so that we won't receive samples until another + pulse is detected; this must be called with the device spinlock held */ +static void it8709_idle_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable streaming by clearing RXACT writing it as 1 */ + it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXACT, + IT85_C0RCR); + + /* clear the FIFO */ + it8709_wr(dev, it8709_rr(dev, IT85_C0MSTCR) | IT85_FIFOCLR, + IT85_C0MSTCR); +} + +/* disable the receiver; this must be called with the device spinlock held */ +static void it8709_disable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the receiver interrupts */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & + ~(IT85_RDAIE | IT85_RFOIE), + IT85_C0IER); + + /* disable the receiver */ + it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) & ~IT85_RXEN, + IT85_C0RCR); + + /* clear the FIFO and RXACT (actually RXACT should have been cleared + * in the previous it8709_wr(dev, ) call) */ + it8709_idle_rx(dev); +} + +/* enable the receiver; this must be called with the device spinlock held */ +static void it8709_enable_rx(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the receiver by setting RXEN */ + it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXEN, + IT85_C0RCR); + + /* just prepare it to idle for the next reception */ + it8709_idle_rx(dev); + + /* enable the receiver interrupts and master enable flag */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) + |IT85_RDAIE | IT85_RFOIE | IT85_IEC, + IT85_C0IER); +} + +/* disable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8709_disable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable the transmitter interrupts */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~IT85_TLDLIE, + IT85_C0IER); +} + +/* enable the transmitter interrupt; this must be called with the device + * spinlock held */ +static void it8709_enable_tx_interrupt(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* enable the transmitter interrupts and master enable flag */ + it8709_wr(dev, it8709_rr(dev, IT85_C0IER) + |IT85_TLDLIE | IT85_IEC, + IT85_C0IER); +} + +/* disable the device; this must be called with the device spinlock held */ +static void it8709_disable(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* clear out all interrupt enable flags */ + it8709_wr(dev, + it8709_rr(dev, + IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE | + IT85_RDAIE | + IT85_TLDLIE), IT85_C0IER); + + /* disable the receiver */ + it8709_disable_rx(dev); + + /* erase the FIFO */ + it8709_wr(dev, IT85_FIFOCLR | it8709_rr(dev, IT85_C0MSTCR), + IT85_C0MSTCR); +} + +/* initialize the hardware */ +static void it8709_init_hardware(struct ite_dev *dev) +{ + ite_dbg("%s called", __func__); + + /* disable all the interrupts */ + it8709_wr(dev, + it8709_rr(dev, + IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE | + IT85_RDAIE | + IT85_TLDLIE), IT85_C0IER); + + /* program the baud rate divisor */ + it8709_wr(dev, ITE_BAUDRATE_DIVISOR & 0xff, IT85_C0BDLR); + it8709_wr(dev, (ITE_BAUDRATE_DIVISOR >> 8) & 0xff, + IT85_C0BDHR); + + /* program the C0MSTCR register defaults */ + it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) & ~(IT85_ILSEL | + IT85_ILE + | IT85_FIFOTL + | + IT85_FIFOCLR + | + IT85_RESET)) + | IT85_FIFOTL_DEFAULT, IT85_C0MSTCR); + + /* program the C0RCR register defaults */ + it8709_wr(dev, + (it8709_rr(dev, IT85_C0RCR) & + ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND + | IT85_RXACT | IT85_RXDCR)) | + ITE_RXDCR_DEFAULT, IT85_C0RCR); + + /* program the C0TCR register defaults */ + it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR) + &~(IT85_TXMPM | IT85_TXMPW)) + |IT85_TXRLE | IT85_TXENDF | + IT85_TXMPM_DEFAULT | + IT85_TXMPW_DEFAULT, IT85_C0TCR); + + /* program the carrier parameters */ + ite_set_carrier_params(dev); +} + + +/* generic hardware setup/teardown code */ + +/* activate the device for use */ +static int ite_open(struct rc_dev *rcdev) +{ + struct ite_dev *dev = rcdev->priv; + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + dev->in_use = true; + + /* enable the receiver */ + dev->params.enable_rx(dev); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* deactivate the device for use */ +static void ite_close(struct rc_dev *rcdev) +{ + struct ite_dev *dev = rcdev->priv; + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + dev->in_use = false; + + /* wait for any transmission to end */ + spin_unlock_irqrestore(&dev->lock, flags); + wait_event_interruptible(dev->tx_ended, !dev->transmitting); + spin_lock_irqsave(&dev->lock, flags); + + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +/* supported models and their parameters */ +static const struct ite_dev_params ite_dev_descs[] = { + { /* 0: ITE8704 */ + .model = "ITE8704 CIR transceiver", + .io_region_size = IT87_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it87_get_irq_causes, + .enable_rx = it87_enable_rx, + .idle_rx = it87_idle_rx, + .disable_rx = it87_idle_rx, + .get_rx_bytes = it87_get_rx_bytes, + .enable_tx_interrupt = it87_enable_tx_interrupt, + .disable_tx_interrupt = it87_disable_tx_interrupt, + .get_tx_used_slots = it87_get_tx_used_slots, + .put_tx_byte = it87_put_tx_byte, + .disable = it87_disable, + .init_hardware = it87_init_hardware, + .set_carrier_params = it87_set_carrier_params, + }, + { /* 1: ITE8713 */ + .model = "ITE8713 CIR transceiver", + .io_region_size = IT87_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it87_get_irq_causes, + .enable_rx = it87_enable_rx, + .idle_rx = it87_idle_rx, + .disable_rx = it87_idle_rx, + .get_rx_bytes = it87_get_rx_bytes, + .enable_tx_interrupt = it87_enable_tx_interrupt, + .disable_tx_interrupt = it87_disable_tx_interrupt, + .get_tx_used_slots = it87_get_tx_used_slots, + .put_tx_byte = it87_put_tx_byte, + .disable = it87_disable, + .init_hardware = it87_init_hardware, + .set_carrier_params = it87_set_carrier_params, + }, + { /* 2: ITE8708 */ + .model = "ITE8708 CIR transceiver", + .io_region_size = IT8708_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it8708_get_irq_causes, + .enable_rx = it8708_enable_rx, + .idle_rx = it8708_idle_rx, + .disable_rx = it8708_idle_rx, + .get_rx_bytes = it8708_get_rx_bytes, + .enable_tx_interrupt = it8708_enable_tx_interrupt, + .disable_tx_interrupt = + it8708_disable_tx_interrupt, + .get_tx_used_slots = it8708_get_tx_used_slots, + .put_tx_byte = it8708_put_tx_byte, + .disable = it8708_disable, + .init_hardware = it8708_init_hardware, + .set_carrier_params = it8708_set_carrier_params, + }, + { /* 3: ITE8709 */ + .model = "ITE8709 CIR transceiver", + .io_region_size = IT8709_IOREG_LENGTH, + .hw_tx_capable = true, + .sample_period = (u32) (1000000000ULL / 115200), + .tx_carrier_freq = 38000, + .tx_duty_cycle = 33, + .rx_low_carrier_freq = 0, + .rx_high_carrier_freq = 0, + + /* operations */ + .get_irq_causes = it8709_get_irq_causes, + .enable_rx = it8709_enable_rx, + .idle_rx = it8709_idle_rx, + .disable_rx = it8709_idle_rx, + .get_rx_bytes = it8709_get_rx_bytes, + .enable_tx_interrupt = it8709_enable_tx_interrupt, + .disable_tx_interrupt = + it8709_disable_tx_interrupt, + .get_tx_used_slots = it8709_get_tx_used_slots, + .put_tx_byte = it8709_put_tx_byte, + .disable = it8709_disable, + .init_hardware = it8709_init_hardware, + .set_carrier_params = it8709_set_carrier_params, + }, +}; + +static const struct pnp_device_id ite_ids[] = { + {"ITE8704", 0}, /* Default model */ + {"ITE8713", 1}, /* CIR found in EEEBox 1501U */ + {"ITE8708", 2}, /* Bridged IT8512 */ + {"ITE8709", 3}, /* SRAM-Bridged IT8512 */ + {"", 0}, +}; + +/* allocate memory, probe hardware, and initialize everything */ +static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id + *dev_id) +{ + const struct ite_dev_params *dev_desc = NULL; + struct ite_dev *itdev = NULL; + struct rc_dev *rdev = NULL; + int ret = -ENOMEM; + int model_no; + + ite_dbg("%s called", __func__); + + itdev = kzalloc(sizeof(struct ite_dev), GFP_KERNEL); + if (!itdev) + return ret; + + /* input device for IR remote (and tx) */ + rdev = rc_allocate_device(); + if (!rdev) + goto failure; + + ret = -ENODEV; + + /* get the model number */ + model_no = (int)dev_id->driver_data; + ite_pr(KERN_NOTICE, "Auto-detected model: %s\n", + ite_dev_descs[model_no].model); + + if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) { + model_no = model_number; + ite_pr(KERN_NOTICE, "The model has been fixed by a module " + "parameter."); + } + + ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model); + + /* get the description for the device */ + dev_desc = &ite_dev_descs[model_no]; + + /* validate pnp resources */ + if (!pnp_port_valid(pdev, 0) || + pnp_port_len(pdev, 0) != dev_desc->io_region_size) { + dev_err(&pdev->dev, "IR PNP Port not valid!\n"); + goto failure; + } + + if (!pnp_irq_valid(pdev, 0)) { + dev_err(&pdev->dev, "PNP IRQ not valid!\n"); + goto failure; + } + + /* store resource values */ + itdev->cir_addr = pnp_port_start(pdev, 0); + itdev->cir_irq =pnp_irq(pdev, 0); + + /* initialize spinlocks */ + spin_lock_init(&itdev->lock); + + /* initialize raw event */ + init_ir_raw_event(&itdev->rawir); + + ret = -EBUSY; + /* now claim resources */ + if (!request_region(itdev->cir_addr, + dev_desc->io_region_size, ITE_DRIVER_NAME)) + goto failure; + + if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED, + ITE_DRIVER_NAME, (void *)itdev)) + goto failure; + + /* set driver data into the pnp device */ + pnp_set_drvdata(pdev, itdev); + itdev->pdev = pdev; + + /* initialize waitqueues for transmission */ + init_waitqueue_head(&itdev->tx_queue); + init_waitqueue_head(&itdev->tx_ended); + + /* copy model-specific parameters */ + itdev->params = *dev_desc; + + /* apply any overrides */ + if (sample_period > 0) + itdev->params.sample_period = sample_period; + + if (tx_carrier_freq > 0) + itdev->params.tx_carrier_freq = tx_carrier_freq; + + if (tx_duty_cycle > 0 && tx_duty_cycle <= 100) + itdev->params.tx_duty_cycle = tx_duty_cycle; + + if (rx_low_carrier_freq > 0) + itdev->params.rx_low_carrier_freq = rx_low_carrier_freq; + + if (rx_high_carrier_freq > 0) + itdev->params.rx_high_carrier_freq = rx_high_carrier_freq; + + /* print out parameters */ + ite_pr(KERN_NOTICE, "TX-capable: %d\n", (int) + itdev->params.hw_tx_capable); + ite_pr(KERN_NOTICE, "Sample period (ns): %ld\n", (long) + itdev->params.sample_period); + ite_pr(KERN_NOTICE, "TX carrier frequency (Hz): %d\n", (int) + itdev->params.tx_carrier_freq); + ite_pr(KERN_NOTICE, "TX duty cycle (%%): %d\n", (int) + itdev->params.tx_duty_cycle); + ite_pr(KERN_NOTICE, "RX low carrier frequency (Hz): %d\n", (int) + itdev->params.rx_low_carrier_freq); + ite_pr(KERN_NOTICE, "RX high carrier frequency (Hz): %d\n", (int) + itdev->params.rx_high_carrier_freq); + + /* set up hardware initial state */ + itdev->params.init_hardware(itdev); + + /* set up ir-core props */ + rdev->priv = itdev; + rdev->driver_type = RC_DRIVER_IR_RAW; + rdev->allowed_protos = RC_TYPE_ALL; + rdev->open = ite_open; + rdev->close = ite_close; + rdev->s_idle = ite_s_idle; + rdev->s_rx_carrier_range = ite_set_rx_carrier_range; + rdev->min_timeout = ITE_MIN_IDLE_TIMEOUT; + rdev->max_timeout = ITE_MAX_IDLE_TIMEOUT; + rdev->timeout = ITE_IDLE_TIMEOUT; + rdev->rx_resolution = ITE_BAUDRATE_DIVISOR * + itdev->params.sample_period; + rdev->tx_resolution = ITE_BAUDRATE_DIVISOR * + itdev->params.sample_period; + + /* set up transmitter related values if needed */ + if (itdev->params.hw_tx_capable) { + rdev->tx_ir = ite_tx_ir; + rdev->s_tx_carrier = ite_set_tx_carrier; + rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; + } + + rdev->input_name = dev_desc->model; + rdev->input_id.bustype = BUS_HOST; + rdev->input_id.vendor = PCI_VENDOR_ID_ITE; + rdev->input_id.product = 0; + rdev->input_id.version = 0; + rdev->driver_name = ITE_DRIVER_NAME; + rdev->map_name = RC_MAP_RC6_MCE; + + ret = rc_register_device(rdev); + if (ret) + goto failure; + + itdev->rdev = rdev; + ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); + + return 0; + +failure: + if (itdev->cir_irq) + free_irq(itdev->cir_irq, itdev); + + if (itdev->cir_addr) + release_region(itdev->cir_addr, itdev->params.io_region_size); + + rc_free_device(rdev); + kfree(itdev); + + return ret; +} + +static void __devexit ite_remove(struct pnp_dev *pdev) +{ + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + + /* disable hardware */ + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); + + /* free resources */ + free_irq(dev->cir_irq, dev); + release_region(dev->cir_addr, dev->params.io_region_size); + + rc_unregister_device(dev->rdev); + + kfree(dev); +} + +static int ite_suspend(struct pnp_dev *pdev, pm_message_t state) +{ + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + + /* disable all interrupts */ + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +static int ite_resume(struct pnp_dev *pdev) +{ + int ret = 0; + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + + if (dev->transmitting) { + /* wake up the transmitter */ + wake_up_interruptible(&dev->tx_queue); + } else { + /* enable the receiver */ + dev->params.enable_rx(dev); + } + + spin_unlock_irqrestore(&dev->lock, flags); + + return ret; +} + +static void ite_shutdown(struct pnp_dev *pdev) +{ + struct ite_dev *dev = pnp_get_drvdata(pdev); + unsigned long flags; + + ite_dbg("%s called", __func__); + + spin_lock_irqsave(&dev->lock, flags); + + /* disable all interrupts */ + dev->params.disable(dev); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +static struct pnp_driver ite_driver = { + .name = ITE_DRIVER_NAME, + .id_table = ite_ids, + .probe = ite_probe, + .remove = __devexit_p(ite_remove), + .suspend = ite_suspend, + .resume = ite_resume, + .shutdown = ite_shutdown, +}; + +int ite_init(void) +{ + return pnp_register_driver(&ite_driver); +} + +void ite_exit(void) +{ + pnp_unregister_driver(&ite_driver); +} + +MODULE_DEVICE_TABLE(pnp, ite_ids); +MODULE_DESCRIPTION("ITE Tech Inc. IT8712F/ITE8512F CIR driver"); + +MODULE_AUTHOR("Juan J. Garcia de Soria "); +MODULE_LICENSE("GPL"); + +module_init(ite_init); +module_exit(ite_exit); diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h new file mode 100644 index 000000000000..43bac8dc5088 --- /dev/null +++ b/drivers/media/rc/ite-cir.h @@ -0,0 +1,478 @@ +/* + * Driver for ITE Tech Inc. IT8712F/IT8512F CIR + * + * Copyright (C) 2010 Juan Jesús García de Soria + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +/* platform driver name to register */ +#define ITE_DRIVER_NAME "ite-cir" + +/* logging macros */ +#define ite_pr(level, text, ...) \ + printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) +#define ite_dbg(text, ...) \ + if (debug) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) +#define ite_dbg_verbose(text, ...) \ + if (debug > 1) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + +/* FIFO sizes */ +#define ITE_TX_FIFO_LEN 32 +#define ITE_RX_FIFO_LEN 32 + +/* interrupt types */ +#define ITE_IRQ_TX_FIFO 1 +#define ITE_IRQ_RX_FIFO 2 +#define ITE_IRQ_RX_FIFO_OVERRUN 4 + +/* forward declaration */ +struct ite_dev; + +/* struct for storing the parameters of different recognized devices */ +struct ite_dev_params { + /* model of the device */ + const char *model; + + /* size of the I/O region */ + int io_region_size; + + /* true if the hardware supports transmission */ + bool hw_tx_capable; + + /* base sampling period, in ns */ + u32 sample_period; + + /* rx low carrier frequency, in Hz, 0 means no demodulation */ + unsigned int rx_low_carrier_freq; + + /* tx high carrier frequency, in Hz, 0 means no demodulation */ + unsigned int rx_high_carrier_freq; + + /* tx carrier frequency, in Hz */ + unsigned int tx_carrier_freq; + + /* duty cycle, 0-100 */ + int tx_duty_cycle; + + /* hw-specific operation function pointers; most of these must be + * called while holding the spin lock, except for the TX FIFO length + * one */ + /* get pending interrupt causes */ + int (*get_irq_causes) (struct ite_dev * dev); + + /* enable rx */ + void (*enable_rx) (struct ite_dev * dev); + + /* make rx enter the idle state; keep listening for a pulse, but stop + * streaming space bytes */ + void (*idle_rx) (struct ite_dev * dev); + + /* disable rx completely */ + void (*disable_rx) (struct ite_dev * dev); + + /* read bytes from RX FIFO; return read count */ + int (*get_rx_bytes) (struct ite_dev * dev, u8 * buf, int buf_size); + + /* enable tx FIFO space available interrupt */ + void (*enable_tx_interrupt) (struct ite_dev * dev); + + /* disable tx FIFO space available interrupt */ + void (*disable_tx_interrupt) (struct ite_dev * dev); + + /* get number of full TX FIFO slots */ + int (*get_tx_used_slots) (struct ite_dev * dev); + + /* put a byte to the TX FIFO */ + void (*put_tx_byte) (struct ite_dev * dev, u8 value); + + /* disable hardware completely */ + void (*disable) (struct ite_dev * dev); + + /* initialize the hardware */ + void (*init_hardware) (struct ite_dev * dev); + + /* set the carrier parameters */ + void (*set_carrier_params) (struct ite_dev * dev, bool high_freq, + bool use_demodulator, u8 carrier_freq_bits, + u8 allowance_bits, u8 pulse_width_bits); +}; + +/* ITE CIR device structure */ +struct ite_dev { + struct pnp_dev *pdev; + struct rc_dev *rdev; + struct ir_raw_event rawir; + + /* sync data */ + spinlock_t lock; + bool in_use, transmitting; + + /* transmit support */ + int tx_fifo_allowance; + wait_queue_head_t tx_queue, tx_ended; + + /* hardware I/O settings */ + unsigned long cir_addr; + int cir_irq; + + /* overridable copy of model parameters */ + struct ite_dev_params params; +}; + +/* common values for all kinds of hardware */ + +/* baud rate divisor default */ +#define ITE_BAUDRATE_DIVISOR 1 + +/* low-speed carrier frequency limits (Hz) */ +#define ITE_LCF_MIN_CARRIER_FREQ 27000 +#define ITE_LCF_MAX_CARRIER_FREQ 58000 + +/* high-speed carrier frequency limits (Hz) */ +#define ITE_HCF_MIN_CARRIER_FREQ 400000 +#define ITE_HCF_MAX_CARRIER_FREQ 500000 + +/* default carrier freq for when demodulator is off (Hz) */ +#define ITE_DEFAULT_CARRIER_FREQ 38000 + +/* default idling timeout in ns (0.2 seconds) */ +#define ITE_IDLE_TIMEOUT 200000000UL + +/* limit timeout values */ +#define ITE_MIN_IDLE_TIMEOUT 100000000UL +#define ITE_MAX_IDLE_TIMEOUT 1000000000UL + +/* convert bits to us */ +#define ITE_BITS_TO_NS(bits, sample_period) \ +((u32) ((bits) * ITE_BAUDRATE_DIVISOR * sample_period)) + +/* + * n in RDCR produces a tolerance of +/- n * 6.25% around the center + * carrier frequency... + * + * From two limit frequencies, L (low) and H (high), we can get both the + * center frequency F = (L + H) / 2 and the variation from the center + * frequency A = (H - L) / (H + L). We can use this in order to honor the + * s_rx_carrier_range() call in ir-core. We'll suppose that any request + * setting L=0 means we must shut down the demodulator. + */ +#define ITE_RXDCR_PER_10000_STEP 625 + +/* high speed carrier freq values */ +#define ITE_CFQ_400 0x03 +#define ITE_CFQ_450 0x08 +#define ITE_CFQ_480 0x0b +#define ITE_CFQ_500 0x0d + +/* values for pulse widths */ +#define ITE_TXMPW_A 0x02 +#define ITE_TXMPW_B 0x03 +#define ITE_TXMPW_C 0x04 +#define ITE_TXMPW_D 0x05 +#define ITE_TXMPW_E 0x06 + +/* values for demodulator carrier range allowance */ +#define ITE_RXDCR_DEFAULT 0x01 /* default carrier range */ +#define ITE_RXDCR_MAX 0x07 /* default carrier range */ + +/* DR TX bits */ +#define ITE_TX_PULSE 0x00 +#define ITE_TX_SPACE 0x80 +#define ITE_TX_MAX_RLE 0x80 +#define ITE_TX_RLE_MASK 0x7f + +/* + * IT8712F + * + * hardware data obtained from: + * + * IT8712F + * Environment Control – Low Pin Count Input / Output + * (EC - LPC I/O) + * Preliminary Specification V0. 81 + */ + +/* register offsets */ +#define IT87_DR 0x00 /* data register */ +#define IT87_IER 0x01 /* interrupt enable register */ +#define IT87_RCR 0x02 /* receiver control register */ +#define IT87_TCR1 0x03 /* transmitter control register 1 */ +#define IT87_TCR2 0x04 /* transmitter control register 2 */ +#define IT87_TSR 0x05 /* transmitter status register */ +#define IT87_RSR 0x06 /* receiver status register */ +#define IT87_BDLR 0x05 /* baud rate divisor low byte register */ +#define IT87_BDHR 0x06 /* baud rate divisor high byte register */ +#define IT87_IIR 0x07 /* interrupt identification register */ + +#define IT87_IOREG_LENGTH 0x08 /* length of register file */ + +/* IER bits */ +#define IT87_TLDLIE 0x01 /* transmitter low data interrupt enable */ +#define IT87_RDAIE 0x02 /* receiver data available interrupt enable */ +#define IT87_RFOIE 0x04 /* receiver FIFO overrun interrupt enable */ +#define IT87_IEC 0x08 /* interrupt enable control */ +#define IT87_BR 0x10 /* baud rate register enable */ +#define IT87_RESET 0x20 /* reset */ + +/* RCR bits */ +#define IT87_RXDCR 0x07 /* receiver demodulation carrier range mask */ +#define IT87_RXACT 0x08 /* receiver active */ +#define IT87_RXEND 0x10 /* receiver demodulation enable */ +#define IT87_RXEN 0x20 /* receiver enable */ +#define IT87_HCFS 0x40 /* high-speed carrier frequency select */ +#define IT87_RDWOS 0x80 /* receiver data without sync */ + +/* TCR1 bits */ +#define IT87_TXMPM 0x03 /* transmitter modulation pulse mode mask */ +#define IT87_TXMPM_DEFAULT 0x00 /* modulation pulse mode default */ +#define IT87_TXENDF 0x04 /* transmitter deferral */ +#define IT87_TXRLE 0x08 /* transmitter run length enable */ +#define IT87_FIFOTL 0x30 /* FIFO level threshold mask */ +#define IT87_FIFOTL_DEFAULT 0x20 /* FIFO level threshold default + * 0x00 -> 1, 0x10 -> 7, 0x20 -> 17, + * 0x30 -> 25 */ +#define IT87_ILE 0x40 /* internal loopback enable */ +#define IT87_FIFOCLR 0x80 /* FIFO clear bit */ + +/* TCR2 bits */ +#define IT87_TXMPW 0x07 /* transmitter modulation pulse width mask */ +#define IT87_TXMPW_DEFAULT 0x04 /* default modulation pulse width */ +#define IT87_CFQ 0xf8 /* carrier frequency mask */ +#define IT87_CFQ_SHIFT 3 /* carrier frequency bit shift */ + +/* TSR bits */ +#define IT87_TXFBC 0x3f /* transmitter FIFO byte count mask */ + +/* RSR bits */ +#define IT87_RXFBC 0x3f /* receiver FIFO byte count mask */ +#define IT87_RXFTO 0x80 /* receiver FIFO time-out */ + +/* IIR bits */ +#define IT87_IP 0x01 /* interrupt pending */ +#define IT87_II 0x06 /* interrupt identification mask */ +#define IT87_II_NOINT 0x00 /* no interrupt */ +#define IT87_II_TXLDL 0x02 /* transmitter low data level */ +#define IT87_II_RXDS 0x04 /* receiver data stored */ +#define IT87_II_RXFO 0x06 /* receiver FIFO overrun */ + +/* + * IT8512E/F + * + * Hardware data obtained from: + * + * IT8512E/F + * Embedded Controller + * Preliminary Specification V0.4.1 + * + * Note that the CIR registers are not directly available to the host, because + * they only are accessible to the integrated microcontroller. Thus, in order + * use it, some kind of bridging is required. As the bridging may depend on + * the controller firmware in use, we are going to use the PNP ID in order to + * determine the strategy and ports available. See after these generic + * IT8512E/F register definitions for register definitions for those + * strategies. + */ + +/* register offsets */ +#define IT85_C0DR 0x00 /* data register */ +#define IT85_C0MSTCR 0x01 /* master control register */ +#define IT85_C0IER 0x02 /* interrupt enable register */ +#define IT85_C0IIR 0x03 /* interrupt identification register */ +#define IT85_C0CFR 0x04 /* carrier frequency register */ +#define IT85_C0RCR 0x05 /* receiver control register */ +#define IT85_C0TCR 0x06 /* transmitter control register */ +#define IT85_C0SCK 0x07 /* slow clock control register */ +#define IT85_C0BDLR 0x08 /* baud rate divisor low byte register */ +#define IT85_C0BDHR 0x09 /* baud rate divisor high byte register */ +#define IT85_C0TFSR 0x0a /* transmitter FIFO status register */ +#define IT85_C0RFSR 0x0b /* receiver FIFO status register */ +#define IT85_C0WCL 0x0d /* wakeup code length register */ +#define IT85_C0WCR 0x0e /* wakeup code read/write register */ +#define IT85_C0WPS 0x0f /* wakeup power control/status register */ + +#define IT85_IOREG_LENGTH 0x10 /* length of register file */ + +/* C0MSTCR bits */ +#define IT85_RESET 0x01 /* reset */ +#define IT85_FIFOCLR 0x02 /* FIFO clear bit */ +#define IT85_FIFOTL 0x0c /* FIFO level threshold mask */ +#define IT85_FIFOTL_DEFAULT 0x08 /* FIFO level threshold default + * 0x00 -> 1, 0x04 -> 7, 0x08 -> 17, + * 0x0c -> 25 */ +#define IT85_ILE 0x10 /* internal loopback enable */ +#define IT85_ILSEL 0x20 /* internal loopback select */ + +/* C0IER bits */ +#define IT85_TLDLIE 0x01 /* TX low data level interrupt enable */ +#define IT85_RDAIE 0x02 /* RX data available interrupt enable */ +#define IT85_RFOIE 0x04 /* RX FIFO overrun interrupt enable */ +#define IT85_IEC 0x80 /* interrupt enable function control */ + +/* C0IIR bits */ +#define IT85_TLDLI 0x01 /* transmitter low data level interrupt */ +#define IT85_RDAI 0x02 /* receiver data available interrupt */ +#define IT85_RFOI 0x04 /* receiver FIFO overrun interrupt */ +#define IT85_NIP 0x80 /* no interrupt pending */ + +/* C0CFR bits */ +#define IT85_CFQ 0x1f /* carrier frequency mask */ +#define IT85_HCFS 0x20 /* high speed carrier frequency select */ + +/* C0RCR bits */ +#define IT85_RXDCR 0x07 /* receiver demodulation carrier range mask */ +#define IT85_RXACT 0x08 /* receiver active */ +#define IT85_RXEND 0x10 /* receiver demodulation enable */ +#define IT85_RDWOS 0x20 /* receiver data without sync */ +#define IT85_RXEN 0x80 /* receiver enable */ + +/* C0TCR bits */ +#define IT85_TXMPW 0x07 /* transmitter modulation pulse width mask */ +#define IT85_TXMPW_DEFAULT 0x04 /* default modulation pulse width */ +#define IT85_TXMPM 0x18 /* transmitter modulation pulse mode mask */ +#define IT85_TXMPM_DEFAULT 0x00 /* modulation pulse mode default */ +#define IT85_TXENDF 0x20 /* transmitter deferral */ +#define IT85_TXRLE 0x40 /* transmitter run length enable */ + +/* C0SCK bits */ +#define IT85_SCKS 0x01 /* slow clock select */ +#define IT85_TXDCKG 0x02 /* TXD clock gating */ +#define IT85_DLL1P8E 0x04 /* DLL 1.8432M enable */ +#define IT85_DLLTE 0x08 /* DLL test enable */ +#define IT85_BRCM 0x70 /* baud rate count mode */ +#define IT85_DLLOCK 0x80 /* DLL lock */ + +/* C0TFSR bits */ +#define IT85_TXFBC 0x3f /* transmitter FIFO count mask */ + +/* C0RFSR bits */ +#define IT85_RXFBC 0x3f /* receiver FIFO count mask */ +#define IT85_RXFTO 0x80 /* receiver FIFO time-out */ + +/* C0WCL bits */ +#define IT85_WCL 0x3f /* wakeup code length mask */ + +/* C0WPS bits */ +#define IT85_CIRPOSIE 0x01 /* power on/off status interrupt enable */ +#define IT85_CIRPOIS 0x02 /* power on/off interrupt status */ +#define IT85_CIRPOII 0x04 /* power on/off interrupt identification */ +#define IT85_RCRST 0x10 /* wakeup code reading counter reset bit */ +#define IT85_WCRST 0x20 /* wakeup code writing counter reset bit */ + +/* + * ITE8708 + * + * Hardware data obtained from hacked driver for IT8512 in this forum post: + * + * http://ubuntuforums.org/showthread.php?t=1028640 + * + * Although there's no official documentation for that driver, analysis would + * suggest that it maps the 16 registers of IT8512 onto two 8-register banks, + * selectable by a single bank-select bit that's mapped onto both banks. The + * IT8512 registers are mapped in a different order, so that the first bank + * maps the ones that are used more often, and two registers that share a + * reserved high-order bit are placed at the same offset in both banks in + * order to reuse the reserved bit as the bank select bit. + */ + +/* register offsets */ + +/* mapped onto both banks */ +#define IT8708_BANKSEL 0x07 /* bank select register */ +#define IT8708_HRAE 0x80 /* high registers access enable */ + +/* mapped onto the low bank */ +#define IT8708_C0DR 0x00 /* data register */ +#define IT8708_C0MSTCR 0x01 /* master control register */ +#define IT8708_C0IER 0x02 /* interrupt enable register */ +#define IT8708_C0IIR 0x03 /* interrupt identification register */ +#define IT8708_C0RFSR 0x04 /* receiver FIFO status register */ +#define IT8708_C0RCR 0x05 /* receiver control register */ +#define IT8708_C0TFSR 0x06 /* transmitter FIFO status register */ +#define IT8708_C0TCR 0x07 /* transmitter control register */ + +/* mapped onto the high bank */ +#define IT8708_C0BDLR 0x01 /* baud rate divisor low byte register */ +#define IT8708_C0BDHR 0x02 /* baud rate divisor high byte register */ +#define IT8708_C0CFR 0x04 /* carrier frequency register */ + +/* registers whose bank mapping we don't know, since they weren't being used + * in the hacked driver... most probably they belong to the high bank too, + * since they fit in the holes the other registers leave */ +#define IT8708_C0SCK 0x03 /* slow clock control register */ +#define IT8708_C0WCL 0x05 /* wakeup code length register */ +#define IT8708_C0WCR 0x06 /* wakeup code read/write register */ +#define IT8708_C0WPS 0x07 /* wakeup power control/status register */ + +#define IT8708_IOREG_LENGTH 0x08 /* length of register file */ + +/* two more registers that are defined in the hacked driver, but can't be + * found in the data sheets; no idea what they are or how they are accessed, + * since the hacked driver doesn't seem to use them */ +#define IT8708_CSCRR 0x00 +#define IT8708_CGPINTR 0x01 + +/* CSCRR bits */ +#define IT8708_CSCRR_SCRB 0x3f +#define IT8708_CSCRR_PM 0x80 + +/* CGPINTR bits */ +#define IT8708_CGPINT 0x01 + +/* + * ITE8709 + * + * Hardware interfacing data obtained from the original lirc_ite8709 driver. + * Verbatim from its sources: + * + * The ITE8709 device seems to be the combination of IT8512 superIO chip and + * a specific firmware running on the IT8512's embedded micro-controller. + * In addition of the embedded micro-controller, the IT8512 chip contains a + * CIR module and several other modules. A few modules are directly accessible + * by the host CPU, but most of them are only accessible by the + * micro-controller. The CIR module is only accessible by the + * micro-controller. + * + * The battery-backed SRAM module is accessible by the host CPU and the + * micro-controller. So one of the MC's firmware role is to act as a bridge + * between the host CPU and the CIR module. The firmware implements a kind of + * communication protocol using the SRAM module as a shared memory. The IT8512 + * specification is publicly available on ITE's web site, but the + * communication protocol is not, so it was reverse-engineered. + */ + +/* register offsets */ +#define IT8709_RAM_IDX 0x00 /* index into the SRAM module bytes */ +#define IT8709_RAM_VAL 0x01 /* read/write data to the indexed byte */ + +#define IT8709_IOREG_LENGTH 0x02 /* length of register file */ + +/* register offsets inside the SRAM module */ +#define IT8709_MODE 0x1a /* request/ack byte */ +#define IT8709_REG_IDX 0x1b /* index of the CIR register to access */ +#define IT8709_REG_VAL 0x1c /* value read/to be written */ +#define IT8709_IIR 0x1e /* interrupt identification register */ +#define IT8709_RFSR 0x1f /* receiver FIFO status register */ +#define IT8709_FIFO 0x20 /* start of in RAM RX FIFO copy */ + +/* MODE values */ +#define IT8709_IDLE 0x00 +#define IT8709_WRITE 0x01 +#define IT8709_READ 0x02 -- cgit v1.2.2 From 2ccb24ff3b94acb3f405b10a59967d52d95f91e0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Mar 2011 15:12:40 -0300 Subject: [media] ite-cir: Fix some CodingStyle issues Cc: Juan J. Garcia de Soria Cc: Stephan Raue Cc: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ite-cir.c | 8 +++++--- drivers/media/rc/ite-cir.h | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 10358d5b3189..9be6a830f1d2 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -461,8 +461,10 @@ static int ite_tx_ir(struct rc_dev *rcdev, int *txbuf, u32 n) else val |= ITE_TX_SPACE; - /* if we get to 0 available, read again, just in case - * some other slot got freed */ + /* + * if we get to 0 available, read again, just in case + * some other slot got freed + */ if (fifo_avail <= 0) fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); @@ -1511,7 +1513,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* store resource values */ itdev->cir_addr = pnp_port_start(pdev, 0); - itdev->cir_irq =pnp_irq(pdev, 0); + itdev->cir_irq = pnp_irq(pdev, 0); /* initialize spinlocks */ spin_lock_init(&itdev->lock); diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h index 43bac8dc5088..16a19f5fd718 100644 --- a/drivers/media/rc/ite-cir.h +++ b/drivers/media/rc/ite-cir.h @@ -24,15 +24,18 @@ /* logging macros */ #define ite_pr(level, text, ...) \ - printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) -#define ite_dbg(text, ...) \ - if (debug) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) -#define ite_dbg_verbose(text, ...) \ - if (debug > 1) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) + printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) +#define ite_dbg(text, ...) do { \ + if (debug) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ +} while (0) + +#define ite_dbg_verbose(text, ...) do {\ + if (debug > 1) \ + printk(KERN_DEBUG \ + KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ +} while (0) /* FIFO sizes */ #define ITE_TX_FIFO_LEN 32 @@ -76,41 +79,41 @@ struct ite_dev_params { * called while holding the spin lock, except for the TX FIFO length * one */ /* get pending interrupt causes */ - int (*get_irq_causes) (struct ite_dev * dev); + int (*get_irq_causes) (struct ite_dev *dev); /* enable rx */ - void (*enable_rx) (struct ite_dev * dev); + void (*enable_rx) (struct ite_dev *dev); /* make rx enter the idle state; keep listening for a pulse, but stop * streaming space bytes */ - void (*idle_rx) (struct ite_dev * dev); + void (*idle_rx) (struct ite_dev *dev); /* disable rx completely */ - void (*disable_rx) (struct ite_dev * dev); + void (*disable_rx) (struct ite_dev *dev); /* read bytes from RX FIFO; return read count */ - int (*get_rx_bytes) (struct ite_dev * dev, u8 * buf, int buf_size); + int (*get_rx_bytes) (struct ite_dev *dev, u8 *buf, int buf_size); /* enable tx FIFO space available interrupt */ - void (*enable_tx_interrupt) (struct ite_dev * dev); + void (*enable_tx_interrupt) (struct ite_dev *dev); /* disable tx FIFO space available interrupt */ - void (*disable_tx_interrupt) (struct ite_dev * dev); + void (*disable_tx_interrupt) (struct ite_dev *dev); /* get number of full TX FIFO slots */ - int (*get_tx_used_slots) (struct ite_dev * dev); + int (*get_tx_used_slots) (struct ite_dev *dev); /* put a byte to the TX FIFO */ - void (*put_tx_byte) (struct ite_dev * dev, u8 value); + void (*put_tx_byte) (struct ite_dev *dev, u8 value); /* disable hardware completely */ - void (*disable) (struct ite_dev * dev); + void (*disable) (struct ite_dev *dev); /* initialize the hardware */ - void (*init_hardware) (struct ite_dev * dev); + void (*init_hardware) (struct ite_dev *dev); /* set the carrier parameters */ - void (*set_carrier_params) (struct ite_dev * dev, bool high_freq, + void (*set_carrier_params) (struct ite_dev *dev, bool high_freq, bool use_demodulator, u8 carrier_freq_bits, u8 allowance_bits, u8 pulse_width_bits); }; -- cgit v1.2.2 From 812738e11158e9b92c4f0e9278de48377cfa3cc8 Mon Sep 17 00:00:00 2001 From: "Juan J. Garcia de Soria" Date: Wed, 16 Mar 2011 17:14:53 -0300 Subject: [media] lirc: remove staging lirc_it87 and lirc_ite8709 drivers Remove older drivers lirc_it87 and lirc_ite8709 from the LIRC staging area, since they're now superceded by ite-cir. Signed-off-by: Juan J. Garcia de Soria Tested-by: Stephan Raue Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/Kconfig | 12 - drivers/staging/lirc/Makefile | 2 - drivers/staging/lirc/lirc_it87.c | 1027 ----------------------------------- drivers/staging/lirc/lirc_it87.h | 116 ---- drivers/staging/lirc/lirc_ite8709.c | 542 ------------------ 5 files changed, 1699 deletions(-) delete mode 100644 drivers/staging/lirc/lirc_it87.c delete mode 100644 drivers/staging/lirc/lirc_it87.h delete mode 100644 drivers/staging/lirc/lirc_ite8709.c (limited to 'drivers') diff --git a/drivers/staging/lirc/Kconfig b/drivers/staging/lirc/Kconfig index cdaff5903a8f..526ec0fc2f04 100644 --- a/drivers/staging/lirc/Kconfig +++ b/drivers/staging/lirc/Kconfig @@ -32,18 +32,6 @@ config LIRC_IMON Current generation iMON devices use the input layer imon driver. -config LIRC_IT87 - tristate "ITE IT87XX CIR Port Receiver" - depends on LIRC && PNP - help - Driver for the ITE IT87xx IR Receiver - -config LIRC_ITE8709 - tristate "ITE8709 CIR Port Receiver" - depends on LIRC && PNP - help - Driver for the ITE8709 IR Receiver - config LIRC_PARALLEL tristate "Homebrew Parallel Port Receiver" depends on LIRC && PARPORT diff --git a/drivers/staging/lirc/Makefile b/drivers/staging/lirc/Makefile index 94af218d8373..d76b0fa2af53 100644 --- a/drivers/staging/lirc/Makefile +++ b/drivers/staging/lirc/Makefile @@ -6,8 +6,6 @@ obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o obj-$(CONFIG_LIRC_IMON) += lirc_imon.o -obj-$(CONFIG_LIRC_IT87) += lirc_it87.o -obj-$(CONFIG_LIRC_ITE8709) += lirc_ite8709.o obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o diff --git a/drivers/staging/lirc/lirc_it87.c b/drivers/staging/lirc/lirc_it87.c deleted file mode 100644 index 5938616f3e8f..000000000000 --- a/drivers/staging/lirc/lirc_it87.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * LIRC driver for ITE IT8712/IT8705 CIR port - * - * Copyright (C) 2001 Hans-Gunter Lutke Uphues - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - * ITE IT8705 and IT8712(not tested) and IT8720 CIR-port support for lirc based - * via cut and paste from lirc_sir.c (C) 2000 Milan Pikula - * - * Attention: Sendmode only tested with debugging logs - * - * 2001/02/27 Christoph Bartelmus : - * reimplemented read function - * 2005/06/05 Andrew Calkin implemented support for Asus Digimatrix, - * based on work of the following member of the Outertrack Digimatrix - * Forum: Art103 - * 2009/12/24 James Edwards implemeted support - * for ITE8704/ITE8718, on my machine, the DSDT reports 8704, but the - * chip identifies as 18. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "lirc_it87.h" - -#ifdef LIRC_IT87_DIGIMATRIX -static int digimatrix = 1; -static int it87_freq = 36; /* kHz */ -static int irq = 9; -#else -static int digimatrix; -static int it87_freq = 38; /* kHz */ -static int irq = IT87_CIR_DEFAULT_IRQ; -#endif - -static unsigned long it87_bits_in_byte_out; -static unsigned long it87_send_counter; -static unsigned char it87_RXEN_mask = IT87_CIR_RCR_RXEN; - -#define RBUF_LEN 1024 - -#define LIRC_DRIVER_NAME "lirc_it87" - -/* timeout for sequences in jiffies (=5/100s) */ -/* must be longer than TIME_CONST */ -#define IT87_TIMEOUT (HZ*5/100) - -/* module parameters */ -static int debug; -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ - fmt, ## args); \ - } while (0) - -static int io = IT87_CIR_DEFAULT_IOBASE; -/* receiver demodulator default: off */ -static int it87_enable_demodulator; - -static int timer_enabled; -static DEFINE_SPINLOCK(timer_lock); -static struct timer_list timerlist; -/* time of last signal change detected */ -static struct timeval last_tv = {0, 0}; -/* time of last UART data ready interrupt */ -static struct timeval last_intr_tv = {0, 0}; -static int last_value; - -static DECLARE_WAIT_QUEUE_HEAD(lirc_read_queue); - -static DEFINE_SPINLOCK(hardware_lock); -static DEFINE_SPINLOCK(dev_lock); -static bool device_open; - -static int rx_buf[RBUF_LEN]; -unsigned int rx_tail, rx_head; - -static struct pnp_driver it87_pnp_driver; - -/* SECTION: Prototypes */ - -/* Communication with user-space */ -static int lirc_open(struct inode *inode, struct file *file); -static int lirc_close(struct inode *inode, struct file *file); -static unsigned int lirc_poll(struct file *file, poll_table *wait); -static ssize_t lirc_read(struct file *file, char *buf, - size_t count, loff_t *ppos); -static ssize_t lirc_write(struct file *file, const char *buf, - size_t n, loff_t *pos); -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); -static void add_read_queue(int flag, unsigned long val); -static int init_chrdev(void); -static void drop_chrdev(void); -/* Hardware */ -static irqreturn_t it87_interrupt(int irq, void *dev_id); -static void send_space(unsigned long len); -static void send_pulse(unsigned long len); -static void init_send(void); -static void terminate_send(unsigned long len); -static int init_hardware(void); -static void drop_hardware(void); -/* Initialisation */ -static int init_port(void); -static void drop_port(void); - - -/* SECTION: Communication with user-space */ - -static int lirc_open(struct inode *inode, struct file *file) -{ - spin_lock(&dev_lock); - if (device_open) { - spin_unlock(&dev_lock); - return -EBUSY; - } - device_open = true; - spin_unlock(&dev_lock); - return 0; -} - - -static int lirc_close(struct inode *inode, struct file *file) -{ - spin_lock(&dev_lock); - device_open = false; - spin_unlock(&dev_lock); - return 0; -} - - -static unsigned int lirc_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &lirc_read_queue, wait); - if (rx_head != rx_tail) - return POLLIN | POLLRDNORM; - return 0; -} - - -static ssize_t lirc_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - int n = 0; - int retval = 0; - - while (n < count) { - if (file->f_flags & O_NONBLOCK && rx_head == rx_tail) { - retval = -EAGAIN; - break; - } - retval = wait_event_interruptible(lirc_read_queue, - rx_head != rx_tail); - if (retval) - break; - - if (copy_to_user((void *) buf + n, (void *) (rx_buf + rx_head), - sizeof(int))) { - retval = -EFAULT; - break; - } - rx_head = (rx_head + 1) & (RBUF_LEN - 1); - n += sizeof(int); - } - if (n) - return n; - return retval; -} - - -static ssize_t lirc_write(struct file *file, const char *buf, - size_t n, loff_t *pos) -{ - int i = 0; - int *tx_buf; - - if (n % sizeof(int)) - return -EINVAL; - tx_buf = memdup_user(buf, n); - if (IS_ERR(tx_buf)) - return PTR_ERR(tx_buf); - n /= sizeof(int); - init_send(); - while (1) { - if (i >= n) - break; - if (tx_buf[i]) - send_pulse(tx_buf[i]); - i++; - if (i >= n) - break; - if (tx_buf[i]) - send_space(tx_buf[i]); - i++; - } - terminate_send(tx_buf[i - 1]); - kfree(tx_buf); - return n; -} - - -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - int retval = 0; - __u32 value = 0; - unsigned long hw_flags; - - if (cmd == LIRC_GET_FEATURES) - value = LIRC_CAN_SEND_PULSE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_REC_MODE2; - else if (cmd == LIRC_GET_SEND_MODE) - value = LIRC_MODE_PULSE; - else if (cmd == LIRC_GET_REC_MODE) - value = LIRC_MODE_MODE2; - - switch (cmd) { - case LIRC_GET_FEATURES: - case LIRC_GET_SEND_MODE: - case LIRC_GET_REC_MODE: - retval = put_user(value, (__u32 *) arg); - break; - - case LIRC_SET_SEND_MODE: - case LIRC_SET_REC_MODE: - retval = get_user(value, (__u32 *) arg); - break; - - case LIRC_SET_SEND_CARRIER: - retval = get_user(value, (__u32 *) arg); - if (retval) - return retval; - value /= 1000; - if (value > IT87_CIR_FREQ_MAX || - value < IT87_CIR_FREQ_MIN) - return -EINVAL; - - it87_freq = value; - - spin_lock_irqsave(&hardware_lock, hw_flags); - outb(((inb(io + IT87_CIR_TCR2) & IT87_CIR_TCR2_TXMPW) | - (it87_freq - IT87_CIR_FREQ_MIN) << 3), - io + IT87_CIR_TCR2); - spin_unlock_irqrestore(&hardware_lock, hw_flags); - dprintk("demodulation frequency: %d kHz\n", it87_freq); - - break; - - default: - retval = -EINVAL; - } - - if (retval) - return retval; - - if (cmd == LIRC_SET_REC_MODE) { - if (value != LIRC_MODE_MODE2) - retval = -ENOSYS; - } else if (cmd == LIRC_SET_SEND_MODE) { - if (value != LIRC_MODE_PULSE) - retval = -ENOSYS; - } - return retval; -} - -static void add_read_queue(int flag, unsigned long val) -{ - unsigned int new_rx_tail; - int newval; - - dprintk("add flag %d with val %lu\n", flag, val); - - newval = val & PULSE_MASK; - - /* - * statistically, pulses are ~TIME_CONST/2 too long. we could - * maybe make this more exact, but this is good enough - */ - if (flag) { - /* pulse */ - if (newval > TIME_CONST / 2) - newval -= TIME_CONST / 2; - else /* should not ever happen */ - newval = 1; - newval |= PULSE_BIT; - } else - newval += TIME_CONST / 2; - new_rx_tail = (rx_tail + 1) & (RBUF_LEN - 1); - if (new_rx_tail == rx_head) { - dprintk("Buffer overrun.\n"); - return; - } - rx_buf[rx_tail] = newval; - rx_tail = new_rx_tail; - wake_up_interruptible(&lirc_read_queue); -} - - -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .read = lirc_read, - .write = lirc_write, - .poll = lirc_poll, - .unlocked_ioctl = lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_ioctl, -#endif - .open = lirc_open, - .release = lirc_close, - .llseek = noop_llseek, -}; - -static int set_use_inc(void *data) -{ - return 0; -} - -static void set_use_dec(void *data) -{ -} - -static struct lirc_driver driver = { - .name = LIRC_DRIVER_NAME, - .minor = -1, - .code_length = 1, - .sample_rate = 0, - .data = NULL, - .add_to_buf = NULL, - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .fops = &lirc_fops, - .dev = NULL, - .owner = THIS_MODULE, -}; - - -static int init_chrdev(void) -{ - driver.minor = lirc_register_driver(&driver); - - if (driver.minor < 0) { - printk(KERN_ERR LIRC_DRIVER_NAME ": init_chrdev() failed.\n"); - return -EIO; - } - return 0; -} - - -static void drop_chrdev(void) -{ - lirc_unregister_driver(driver.minor); -} - - -/* SECTION: Hardware */ -static long delta(struct timeval *tv1, struct timeval *tv2) -{ - unsigned long deltv; - - deltv = tv2->tv_sec - tv1->tv_sec; - if (deltv > 15) - deltv = 0xFFFFFF; - else - deltv = deltv*1000000 + tv2->tv_usec - tv1->tv_usec; - return deltv; -} - -static void it87_timeout(unsigned long data) -{ - unsigned long flags; - - /* avoid interference with interrupt */ - spin_lock_irqsave(&timer_lock, flags); - - if (digimatrix) { - /* We have timed out. Disable the RX mechanism. */ - - outb((inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN) | - IT87_CIR_RCR_RXACT, io + IT87_CIR_RCR); - if (it87_RXEN_mask) - outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - dprintk(" TIMEOUT\n"); - timer_enabled = 0; - - /* fifo clear */ - outb(inb(io + IT87_CIR_TCR1) | IT87_CIR_TCR1_FIFOCLR, - io+IT87_CIR_TCR1); - - } else { - /* - * if last received signal was a pulse, but receiving stopped - * within the 9 bit frame, we need to finish this pulse and - * simulate a signal change to from pulse to space. Otherwise - * upper layers will receive two sequences next time. - */ - - if (last_value) { - unsigned long pulse_end; - - /* determine 'virtual' pulse end: */ - pulse_end = delta(&last_tv, &last_intr_tv); - dprintk("timeout add %d for %lu usec\n", - last_value, pulse_end); - add_read_queue(last_value, pulse_end); - last_value = 0; - last_tv = last_intr_tv; - } - } - spin_unlock_irqrestore(&timer_lock, flags); -} - -static irqreturn_t it87_interrupt(int irq, void *dev_id) -{ - unsigned char data; - struct timeval curr_tv; - static unsigned long deltv; - unsigned long deltintrtv; - unsigned long flags, hw_flags; - int iir, lsr; - int fifo = 0; - static char lastbit; - char bit; - - /* Bit duration in microseconds */ - const unsigned long bit_duration = 1000000ul / - (115200 / IT87_CIR_BAUDRATE_DIVISOR); - - - iir = inb(io + IT87_CIR_IIR); - - switch (iir & IT87_CIR_IIR_IID) { - case 0x4: - case 0x6: - lsr = inb(io + IT87_CIR_RSR) & (IT87_CIR_RSR_RXFTO | - IT87_CIR_RSR_RXFBC); - fifo = lsr & IT87_CIR_RSR_RXFBC; - dprintk("iir: 0x%x fifo: 0x%x\n", iir, lsr); - - /* avoid interference with timer */ - spin_lock_irqsave(&timer_lock, flags); - spin_lock_irqsave(&hardware_lock, hw_flags); - if (digimatrix) { - static unsigned long acc_pulse; - static unsigned long acc_space; - - do { - data = inb(io + IT87_CIR_DR); - data = ~data; - fifo--; - if (data != 0x00) { - if (timer_enabled) - del_timer(&timerlist); - /* - * start timer for end of - * sequence detection - */ - timerlist.expires = jiffies + - IT87_TIMEOUT; - add_timer(&timerlist); - timer_enabled = 1; - } - /* Loop through */ - for (bit = 0; bit < 8; ++bit) { - if ((data >> bit) & 1) { - ++acc_pulse; - if (lastbit == 0) { - add_read_queue(0, - acc_space * - bit_duration); - acc_space = 0; - } - } else { - ++acc_space; - if (lastbit == 1) { - add_read_queue(1, - acc_pulse * - bit_duration); - acc_pulse = 0; - } - } - lastbit = (data >> bit) & 1; - } - - } while (fifo != 0); - } else { /* Normal Operation */ - do { - del_timer(&timerlist); - data = inb(io + IT87_CIR_DR); - - dprintk("data=%02x\n", data); - do_gettimeofday(&curr_tv); - deltv = delta(&last_tv, &curr_tv); - deltintrtv = delta(&last_intr_tv, &curr_tv); - - dprintk("t %lu , d %d\n", - deltintrtv, (int)data); - - /* - * if nothing came in last 2 cycles, - * it was gap - */ - if (deltintrtv > TIME_CONST * 2) { - if (last_value) { - dprintk("GAP\n"); - - /* simulate signal change */ - add_read_queue(last_value, - deltv - - deltintrtv); - last_value = 0; - last_tv.tv_sec = - last_intr_tv.tv_sec; - last_tv.tv_usec = - last_intr_tv.tv_usec; - deltv = deltintrtv; - } - } - data = 1; - if (data ^ last_value) { - /* - * deltintrtv > 2*TIME_CONST, - * remember ? the other case is - * timeout - */ - add_read_queue(last_value, - deltv-TIME_CONST); - last_value = data; - last_tv = curr_tv; - if (last_tv.tv_usec >= TIME_CONST) - last_tv.tv_usec -= TIME_CONST; - else { - last_tv.tv_sec--; - last_tv.tv_usec += 1000000 - - TIME_CONST; - } - } - last_intr_tv = curr_tv; - if (data) { - /* - * start timer for end of - * sequence detection - */ - timerlist.expires = - jiffies + IT87_TIMEOUT; - add_timer(&timerlist); - } - outb((inb(io + IT87_CIR_RCR) & - ~IT87_CIR_RCR_RXEN) | - IT87_CIR_RCR_RXACT, - io + IT87_CIR_RCR); - if (it87_RXEN_mask) - outb(inb(io + IT87_CIR_RCR) | - IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - fifo--; - } while (fifo != 0); - } - spin_unlock_irqrestore(&hardware_lock, hw_flags); - spin_unlock_irqrestore(&timer_lock, flags); - - return IRQ_RETVAL(IRQ_HANDLED); - - default: - /* not our irq */ - dprintk("unknown IRQ (shouldn't happen) !!\n"); - return IRQ_RETVAL(IRQ_NONE); - } -} - - -static void send_it87(unsigned long len, unsigned long stime, - unsigned char send_byte, unsigned int count_bits) -{ - long count = len / stime; - long time_left = 0; - static unsigned char byte_out; - unsigned long hw_flags; - - dprintk("%s: len=%ld, sb=%d\n", __func__, len, send_byte); - - time_left = (long)len - (long)count * (long)stime; - count += ((2 * time_left) / stime); - while (count) { - long i = 0; - for (i = 0; i < count_bits; i++) { - byte_out = (byte_out << 1) | (send_byte & 1); - it87_bits_in_byte_out++; - } - if (it87_bits_in_byte_out == 8) { - dprintk("out=0x%x, tsr_txfbc: 0x%x\n", - byte_out, - inb(io + IT87_CIR_TSR) & - IT87_CIR_TSR_TXFBC); - - while ((inb(io + IT87_CIR_TSR) & - IT87_CIR_TSR_TXFBC) >= IT87_CIR_FIFO_SIZE) - ; - - spin_lock_irqsave(&hardware_lock, hw_flags); - outb(byte_out, io + IT87_CIR_DR); - spin_unlock_irqrestore(&hardware_lock, hw_flags); - - it87_bits_in_byte_out = 0; - it87_send_counter++; - byte_out = 0; - } - count--; - } -} - - -/*TODO: maybe exchange space and pulse because it8705 only modulates 0-bits */ - -static void send_space(unsigned long len) -{ - send_it87(len, TIME_CONST, IT87_CIR_SPACE, IT87_CIR_BAUDRATE_DIVISOR); -} - -static void send_pulse(unsigned long len) -{ - send_it87(len, TIME_CONST, IT87_CIR_PULSE, IT87_CIR_BAUDRATE_DIVISOR); -} - - -static void init_send() -{ - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - /* RXEN=0: receiver disable */ - it87_RXEN_mask = 0; - outb(inb(io + IT87_CIR_RCR) & ~IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - spin_unlock_irqrestore(&hardware_lock, flags); - it87_bits_in_byte_out = 0; - it87_send_counter = 0; -} - - -static void terminate_send(unsigned long len) -{ - unsigned long flags; - unsigned long last = 0; - - last = it87_send_counter; - /* make sure all necessary data has been sent */ - while (last == it87_send_counter) - send_space(len); - /* wait until all data sent */ - while ((inb(io + IT87_CIR_TSR) & IT87_CIR_TSR_TXFBC) != 0) - ; - /* then re-enable receiver */ - spin_lock_irqsave(&hardware_lock, flags); - it87_RXEN_mask = IT87_CIR_RCR_RXEN; - outb(inb(io + IT87_CIR_RCR) | IT87_CIR_RCR_RXEN, - io + IT87_CIR_RCR); - spin_unlock_irqrestore(&hardware_lock, flags); -} - - -static int init_hardware(void) -{ - unsigned long flags; - unsigned char it87_rcr = 0; - - spin_lock_irqsave(&hardware_lock, flags); - /* init cir-port */ - /* enable r/w-access to Baudrate-Register */ - outb(IT87_CIR_IER_BR, io + IT87_CIR_IER); - outb(IT87_CIR_BAUDRATE_DIVISOR % 0x100, io+IT87_CIR_BDLR); - outb(IT87_CIR_BAUDRATE_DIVISOR / 0x100, io+IT87_CIR_BDHR); - /* Baudrate Register off, define IRQs: Input only */ - if (digimatrix) { - outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RFOIE, io + IT87_CIR_IER); - /* RX: HCFS=0, RXDCR = 001b (33,75..38,25 kHz), RXEN=1 */ - } else { - outb(IT87_CIR_IER_IEC | IT87_CIR_IER_RDAIE, io + IT87_CIR_IER); - /* RX: HCFS=0, RXDCR = 001b (35,6..40,3 kHz), RXEN=1 */ - } - it87_rcr = (IT87_CIR_RCR_RXEN & it87_RXEN_mask) | 0x1; - if (it87_enable_demodulator) - it87_rcr |= IT87_CIR_RCR_RXEND; - outb(it87_rcr, io + IT87_CIR_RCR); - if (digimatrix) { - /* Set FIFO depth to 1 byte, and disable TX */ - outb(inb(io + IT87_CIR_TCR1) | 0x00, - io + IT87_CIR_TCR1); - - /* - * TX: it87_freq (36kHz), 'reserved' sensitivity - * setting (0x00) - */ - outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x00, - io + IT87_CIR_TCR2); - } else { - /* TX: 38kHz, 13,3us (pulse-width) */ - outb(((it87_freq - IT87_CIR_FREQ_MIN) << 3) | 0x06, - io + IT87_CIR_TCR2); - } - spin_unlock_irqrestore(&hardware_lock, flags); - return 0; -} - - -static void drop_hardware(void) -{ - unsigned long flags; - - spin_lock_irqsave(&hardware_lock, flags); - disable_irq(irq); - /* receiver disable */ - it87_RXEN_mask = 0; - outb(0x1, io + IT87_CIR_RCR); - /* turn off irqs */ - outb(0, io + IT87_CIR_IER); - /* fifo clear */ - outb(IT87_CIR_TCR1_FIFOCLR, io+IT87_CIR_TCR1); - /* reset */ - outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); - enable_irq(irq); - spin_unlock_irqrestore(&hardware_lock, flags); -} - - -static unsigned char it87_read(unsigned char port) -{ - outb(port, IT87_ADRPORT); - return inb(IT87_DATAPORT); -} - - -static void it87_write(unsigned char port, unsigned char data) -{ - outb(port, IT87_ADRPORT); - outb(data, IT87_DATAPORT); -} - - -/* SECTION: Initialisation */ - -static int init_port(void) -{ - unsigned long hw_flags; - int retval = 0; - - unsigned char init_bytes[4] = IT87_INIT; - unsigned char it87_chipid = 0; - unsigned char ldn = 0; - unsigned int it87_io = 0; - unsigned int it87_irq = 0; - - /* Enter MB PnP Mode */ - outb(init_bytes[0], IT87_ADRPORT); - outb(init_bytes[1], IT87_ADRPORT); - outb(init_bytes[2], IT87_ADRPORT); - outb(init_bytes[3], IT87_ADRPORT); - - /* 8712 or 8705 ? */ - it87_chipid = it87_read(IT87_CHIP_ID1); - if (it87_chipid != 0x87) { - retval = -ENXIO; - return retval; - } - it87_chipid = it87_read(IT87_CHIP_ID2); - if ((it87_chipid != 0x05) && - (it87_chipid != 0x12) && - (it87_chipid != 0x18) && - (it87_chipid != 0x20)) { - printk(KERN_INFO LIRC_DRIVER_NAME - ": no IT8704/05/12/18/20 found (claimed IT87%02x), " - "exiting..\n", it87_chipid); - retval = -ENXIO; - return retval; - } - printk(KERN_INFO LIRC_DRIVER_NAME - ": found IT87%02x.\n", - it87_chipid); - - /* get I/O-Port and IRQ */ - if (it87_chipid == 0x12 || it87_chipid == 0x18) - ldn = IT8712_CIR_LDN; - else - ldn = IT8705_CIR_LDN; - it87_write(IT87_LDN, ldn); - - it87_io = it87_read(IT87_CIR_BASE_MSB) * 256 + - it87_read(IT87_CIR_BASE_LSB); - if (it87_io == 0) { - if (io == 0) - io = IT87_CIR_DEFAULT_IOBASE; - printk(KERN_INFO LIRC_DRIVER_NAME - ": set default io 0x%x\n", - io); - it87_write(IT87_CIR_BASE_MSB, io / 0x100); - it87_write(IT87_CIR_BASE_LSB, io % 0x100); - } else - io = it87_io; - - it87_irq = it87_read(IT87_CIR_IRQ); - if (digimatrix || it87_irq == 0) { - if (irq == 0) - irq = IT87_CIR_DEFAULT_IRQ; - printk(KERN_INFO LIRC_DRIVER_NAME - ": set default irq 0x%x\n", - irq); - it87_write(IT87_CIR_IRQ, irq); - } else - irq = it87_irq; - - spin_lock_irqsave(&hardware_lock, hw_flags); - /* reset */ - outb(IT87_CIR_IER_RESET, io+IT87_CIR_IER); - /* fifo clear */ - outb(IT87_CIR_TCR1_FIFOCLR | - /* IT87_CIR_TCR1_ILE | */ - IT87_CIR_TCR1_TXRLE | - IT87_CIR_TCR1_TXENDF, io+IT87_CIR_TCR1); - spin_unlock_irqrestore(&hardware_lock, hw_flags); - - /* get I/O port access and IRQ line */ - if (request_region(io, 8, LIRC_DRIVER_NAME) == NULL) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": i/o port 0x%.4x already in use.\n", io); - /* Leaving MB PnP Mode */ - it87_write(IT87_CFGCTRL, 0x2); - return -EBUSY; - } - - /* activate CIR-Device */ - it87_write(IT87_CIR_ACT, 0x1); - - /* Leaving MB PnP Mode */ - it87_write(IT87_CFGCTRL, 0x2); - - retval = request_irq(irq, it87_interrupt, 0 /*IRQF_DISABLED*/, - LIRC_DRIVER_NAME, NULL); - if (retval < 0) { - printk(KERN_ERR LIRC_DRIVER_NAME - ": IRQ %d already in use.\n", - irq); - release_region(io, 8); - return retval; - } - - printk(KERN_INFO LIRC_DRIVER_NAME - ": I/O port 0x%.4x, IRQ %d.\n", io, irq); - - init_timer(&timerlist); - timerlist.function = it87_timeout; - timerlist.data = 0xabadcafe; - - return 0; -} - - -static void drop_port(void) -{ -#if 0 - unsigned char init_bytes[4] = IT87_INIT; - - /* Enter MB PnP Mode */ - outb(init_bytes[0], IT87_ADRPORT); - outb(init_bytes[1], IT87_ADRPORT); - outb(init_bytes[2], IT87_ADRPORT); - outb(init_bytes[3], IT87_ADRPORT); - - /* deactivate CIR-Device */ - it87_write(IT87_CIR_ACT, 0x0); - - /* Leaving MB PnP Mode */ - it87_write(IT87_CFGCTRL, 0x2); -#endif - - del_timer_sync(&timerlist); - free_irq(irq, NULL); - release_region(io, 8); -} - - -static int init_lirc_it87(void) -{ - int retval; - - init_waitqueue_head(&lirc_read_queue); - retval = init_port(); - if (retval < 0) - return retval; - init_hardware(); - printk(KERN_INFO LIRC_DRIVER_NAME ": Installed.\n"); - return 0; -} - -static int it87_probe(struct pnp_dev *pnp_dev, - const struct pnp_device_id *dev_id) -{ - int retval; - - driver.dev = &pnp_dev->dev; - - retval = init_chrdev(); - if (retval < 0) - return retval; - - retval = init_lirc_it87(); - if (retval) - goto init_lirc_it87_failed; - - return 0; - -init_lirc_it87_failed: - drop_chrdev(); - - return retval; -} - -static int __init lirc_it87_init(void) -{ - return pnp_register_driver(&it87_pnp_driver); -} - - -static void __exit lirc_it87_exit(void) -{ - drop_hardware(); - drop_chrdev(); - drop_port(); - pnp_unregister_driver(&it87_pnp_driver); - printk(KERN_INFO LIRC_DRIVER_NAME ": Uninstalled.\n"); -} - -/* SECTION: PNP for ITE8704/13/18 */ - -static const struct pnp_device_id pnp_dev_table[] = { - {"ITE8704", 0}, - {"ITE8713", 0}, - {} -}; - -MODULE_DEVICE_TABLE(pnp, pnp_dev_table); - -static struct pnp_driver it87_pnp_driver = { - .name = LIRC_DRIVER_NAME, - .id_table = pnp_dev_table, - .probe = it87_probe, -}; - -module_init(lirc_it87_init); -module_exit(lirc_it87_exit); - -MODULE_DESCRIPTION("LIRC driver for ITE IT8704/05/12/18/20 CIR port"); -MODULE_AUTHOR("Hans-Gunter Lutke Uphues"); -MODULE_LICENSE("GPL"); - -module_param(io, int, S_IRUGO); -MODULE_PARM_DESC(io, "I/O base address (default: 0x310)"); - -module_param(irq, int, S_IRUGO); -#ifdef LIRC_IT87_DIGIMATRIX -MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 9)"); -#else -MODULE_PARM_DESC(irq, "Interrupt (1,3-12) (default: 7)"); -#endif - -module_param(it87_enable_demodulator, bool, S_IRUGO); -MODULE_PARM_DESC(it87_enable_demodulator, - "Receiver demodulator enable/disable (1/0), default: 0"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); - -module_param(digimatrix, bool, S_IRUGO | S_IWUSR); -#ifdef LIRC_IT87_DIGIMATRIX -MODULE_PARM_DESC(digimatrix, - "Asus Digimatrix it87 compat. enable/disable (1/0), default: 1"); -#else -MODULE_PARM_DESC(digimatrix, - "Asus Digimatrix it87 compat. enable/disable (1/0), default: 0"); -#endif - - -module_param(it87_freq, int, S_IRUGO); -#ifdef LIRC_IT87_DIGIMATRIX -MODULE_PARM_DESC(it87_freq, - "Carrier demodulator frequency (kHz), (default: 36)"); -#else -MODULE_PARM_DESC(it87_freq, - "Carrier demodulator frequency (kHz), (default: 38)"); -#endif diff --git a/drivers/staging/lirc/lirc_it87.h b/drivers/staging/lirc/lirc_it87.h deleted file mode 100644 index cf021c893a35..000000000000 --- a/drivers/staging/lirc/lirc_it87.h +++ /dev/null @@ -1,116 +0,0 @@ -/* lirc_it87.h */ -/* SECTION: Definitions */ - -/********************************* ITE IT87xx ************************/ - -/* based on the following documentation from ITE: - a) IT8712F Preliminary CIR Programming Guide V0.1 - b) IT8705F Simple LPC I/O Preliminary Specification V0.3 - c) IT8712F EC-LPC I/O Preliminary Specification V0.5 -*/ - -/* IT8712/05 Ports: */ -#define IT87_ADRPORT 0x2e -#define IT87_DATAPORT 0x2f -#define IT87_INIT {0x87, 0x01, 0x55, 0x55} - -/* alternate Ports: */ -/* -#define IT87_ADRPORT 0x4e -#define IT87_DATAPORT 0x4f -#define IT87_INIT {0x87, 0x01, 0x55, 0xaa} - */ - -/* IT8712/05 Registers */ -#define IT87_CFGCTRL 0x2 -#define IT87_LDN 0x7 -#define IT87_CHIP_ID1 0x20 -#define IT87_CHIP_ID2 0x21 -#define IT87_CFG_VERSION 0x22 -#define IT87_SWSUSPEND 0x23 - -#define IT8712_CIR_LDN 0xa -#define IT8705_CIR_LDN 0x7 - -/* CIR Configuration Registers: */ -#define IT87_CIR_ACT 0x30 -#define IT87_CIR_BASE_MSB 0x60 -#define IT87_CIR_BASE_LSB 0x61 -#define IT87_CIR_IRQ 0x70 -#define IT87_CIR_CONFIG 0xf0 - -/* List of IT87_CIR registers: offset to BaseAddr */ -#define IT87_CIR_DR 0 -#define IT87_CIR_IER 1 -#define IT87_CIR_RCR 2 -#define IT87_CIR_TCR1 3 -#define IT87_CIR_TCR2 4 -#define IT87_CIR_TSR 5 -#define IT87_CIR_RSR 6 -#define IT87_CIR_BDLR 5 -#define IT87_CIR_BDHR 6 -#define IT87_CIR_IIR 7 - -/* Bit Definition */ -/* IER: */ -#define IT87_CIR_IER_TM_EN 0x80 -#define IT87_CIR_IER_RESEVED 0x40 -#define IT87_CIR_IER_RESET 0x20 -#define IT87_CIR_IER_BR 0x10 -#define IT87_CIR_IER_IEC 0x8 -#define IT87_CIR_IER_RFOIE 0x4 -#define IT87_CIR_IER_RDAIE 0x2 -#define IT87_CIR_IER_TLDLIE 0x1 - -/* RCR: */ -#define IT87_CIR_RCR_RDWOS 0x80 -#define IT87_CIR_RCR_HCFS 0x40 -#define IT87_CIR_RCR_RXEN 0x20 -#define IT87_CIR_RCR_RXEND 0x10 -#define IT87_CIR_RCR_RXACT 0x8 -#define IT87_CIR_RCR_RXDCR 0x7 - -/* TCR1: */ -#define IT87_CIR_TCR1_FIFOCLR 0x80 -#define IT87_CIR_TCR1_ILE 0x40 -#define IT87_CIR_TCR1_FIFOTL 0x30 -#define IT87_CIR_TCR1_TXRLE 0x8 -#define IT87_CIR_TCR1_TXENDF 0x4 -#define IT87_CIR_TCR1_TXMPM 0x3 - -/* TCR2: */ -#define IT87_CIR_TCR2_CFQ 0xf8 -#define IT87_CIR_TCR2_TXMPW 0x7 - -/* TSR: */ -#define IT87_CIR_TSR_RESERVED 0xc0 -#define IT87_CIR_TSR_TXFBC 0x3f - -/* RSR: */ -#define IT87_CIR_RSR_RXFTO 0x80 -#define IT87_CIR_RSR_RESERVED 0x40 -#define IT87_CIR_RSR_RXFBC 0x3f - -/* IIR: */ -#define IT87_CIR_IIR_RESERVED 0xf8 -#define IT87_CIR_IIR_IID 0x6 -#define IT87_CIR_IIR_IIP 0x1 - -/* TM: */ -#define IT87_CIR_TM_IL_SEL 0x80 -#define IT87_CIR_TM_RESERVED 0x40 -#define IT87_CIR_TM_TM_REG 0x3f - -#define IT87_CIR_FIFO_SIZE 32 - -/* Baudratedivisor for IT87: power of 2: only 1,2,4 or 8) */ -#define IT87_CIR_BAUDRATE_DIVISOR 0x1 -#define IT87_CIR_DEFAULT_IOBASE 0x310 -#define IT87_CIR_DEFAULT_IRQ 0x7 -#define IT87_CIR_SPACE 0x00 -#define IT87_CIR_PULSE 0xff -#define IT87_CIR_FREQ_MIN 27 -#define IT87_CIR_FREQ_MAX 58 -#define TIME_CONST (IT87_CIR_BAUDRATE_DIVISOR * 8000000ul / 115200ul) - -/********************************* ITE IT87xx ************************/ diff --git a/drivers/staging/lirc/lirc_ite8709.c b/drivers/staging/lirc/lirc_ite8709.c deleted file mode 100644 index cb20cfdcfadd..000000000000 --- a/drivers/staging/lirc/lirc_ite8709.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * LIRC driver for ITE8709 CIR port - * - * Copyright (C) 2008 Grégory Lardière - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define LIRC_DRIVER_NAME "lirc_ite8709" - -#define BUF_CHUNK_SIZE sizeof(int) -#define BUF_SIZE (128*BUF_CHUNK_SIZE) - -/* - * The ITE8709 device seems to be the combination of IT8512 superIO chip and - * a specific firmware running on the IT8512's embedded micro-controller. - * In addition of the embedded micro-controller, the IT8512 chip contains a - * CIR module and several other modules. A few modules are directly accessible - * by the host CPU, but most of them are only accessible by the - * micro-controller. The CIR module is only accessible by the micro-controller. - * The battery-backed SRAM module is accessible by the host CPU and the - * micro-controller. So one of the MC's firmware role is to act as a bridge - * between the host CPU and the CIR module. The firmware implements a kind of - * communication protocol using the SRAM module as a shared memory. The IT8512 - * specification is publicly available on ITE's web site, but the communication - * protocol is not, so it was reverse-engineered. - */ - -/* ITE8709 Registers addresses and values (reverse-engineered) */ -#define ITE8709_MODE 0x1a -#define ITE8709_REG_ADR 0x1b -#define ITE8709_REG_VAL 0x1c -#define ITE8709_IIR 0x1e /* Interrupt identification register */ -#define ITE8709_RFSR 0x1f /* Receiver FIFO status register */ -#define ITE8709_FIFO_START 0x20 - -#define ITE8709_MODE_READY 0X00 -#define ITE8709_MODE_WRITE 0X01 -#define ITE8709_MODE_READ 0X02 -#define ITE8709_IIR_RDAI 0x02 /* Receiver data available interrupt */ -#define ITE8709_IIR_RFOI 0x04 /* Receiver FIFO overrun interrupt */ -#define ITE8709_RFSR_MASK 0x3f /* FIFO byte count mask */ - -/* - * IT8512 CIR-module registers addresses and values - * (from IT8512 E/F specification v0.4.1) - */ -#define IT8512_REG_MSTCR 0x01 /* Master control register */ -#define IT8512_REG_IER 0x02 /* Interrupt enable register */ -#define IT8512_REG_CFR 0x04 /* Carrier frequency register */ -#define IT8512_REG_RCR 0x05 /* Receive control register */ -#define IT8512_REG_BDLR 0x08 /* Baud rate divisor low byte register */ -#define IT8512_REG_BDHR 0x09 /* Baud rate divisor high byte register */ - -#define IT8512_MSTCR_RESET 0x01 /* Reset registers to default value */ -#define IT8512_MSTCR_FIFOCLR 0x02 /* Clear FIFO */ -#define IT8512_MSTCR_FIFOTL_7 0x04 /* FIFO threshold level : 7 */ -#define IT8512_MSTCR_FIFOTL_25 0x0c /* FIFO threshold level : 25 */ -#define IT8512_IER_RDAIE 0x02 /* Enable data interrupt request */ -#define IT8512_IER_RFOIE 0x04 /* Enable FIFO overrun interrupt req */ -#define IT8512_IER_IEC 0x80 /* Enable interrupt request */ -#define IT8512_CFR_CF_36KHZ 0x09 /* Carrier freq : low speed, 36kHz */ -#define IT8512_RCR_RXDCR_1 0x01 /* Demodulation carrier range : 1 */ -#define IT8512_RCR_RXACT 0x08 /* Receiver active */ -#define IT8512_RCR_RXEN 0x80 /* Receiver enable */ -#define IT8512_BDR_6 6 /* Baud rate divisor : 6 */ - -/* Actual values used by this driver */ -#define CFG_FIFOTL IT8512_MSTCR_FIFOTL_25 -#define CFG_CR_FREQ IT8512_CFR_CF_36KHZ -#define CFG_DCR IT8512_RCR_RXDCR_1 -#define CFG_BDR IT8512_BDR_6 -#define CFG_TIMEOUT 100000 /* Rearm interrupt when a space is > 100 ms */ - -static int debug; - -struct ite8709_device { - int use_count; - int io; - int irq; - spinlock_t hardware_lock; - __u64 acc_pulse; - __u64 acc_space; - char lastbit; - struct timeval last_tv; - struct lirc_driver driver; - struct tasklet_struct tasklet; - char force_rearm; - char rearmed; - char device_busy; -}; - -#define dprintk(fmt, args...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \ - fmt, ## args); \ - } while (0) - - -static unsigned char ite8709_read(struct ite8709_device *dev, - unsigned char port) -{ - outb(port, dev->io); - return inb(dev->io+1); -} - -static void ite8709_write(struct ite8709_device *dev, unsigned char port, - unsigned char data) -{ - outb(port, dev->io); - outb(data, dev->io+1); -} - -static void ite8709_wait_device(struct ite8709_device *dev) -{ - int i = 0; - /* - * loop until device tells it's ready to continue - * iterations count is usually ~750 but can sometimes achieve 13000 - */ - for (i = 0; i < 15000; i++) { - udelay(2); - if (ite8709_read(dev, ITE8709_MODE) == ITE8709_MODE_READY) - break; - } -} - -static void ite8709_write_register(struct ite8709_device *dev, - unsigned char reg_adr, unsigned char reg_value) -{ - ite8709_wait_device(dev); - - ite8709_write(dev, ITE8709_REG_VAL, reg_value); - ite8709_write(dev, ITE8709_REG_ADR, reg_adr); - ite8709_write(dev, ITE8709_MODE, ITE8709_MODE_WRITE); -} - -static void ite8709_init_hardware(struct ite8709_device *dev) -{ - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 1; - spin_unlock_irq(&dev->hardware_lock); - - ite8709_write_register(dev, IT8512_REG_BDHR, (CFG_BDR >> 8) & 0xff); - ite8709_write_register(dev, IT8512_REG_BDLR, CFG_BDR & 0xff); - ite8709_write_register(dev, IT8512_REG_CFR, CFG_CR_FREQ); - ite8709_write_register(dev, IT8512_REG_IER, - IT8512_IER_IEC | IT8512_IER_RFOIE | IT8512_IER_RDAIE); - ite8709_write_register(dev, IT8512_REG_RCR, CFG_DCR); - ite8709_write_register(dev, IT8512_REG_MSTCR, - CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); - ite8709_write_register(dev, IT8512_REG_RCR, - IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); - - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 0; - spin_unlock_irq(&dev->hardware_lock); - - tasklet_enable(&dev->tasklet); -} - -static void ite8709_drop_hardware(struct ite8709_device *dev) -{ - tasklet_disable(&dev->tasklet); - - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 1; - spin_unlock_irq(&dev->hardware_lock); - - ite8709_write_register(dev, IT8512_REG_RCR, 0); - ite8709_write_register(dev, IT8512_REG_MSTCR, - IT8512_MSTCR_RESET | IT8512_MSTCR_FIFOCLR); - - spin_lock_irq(&dev->hardware_lock); - dev->device_busy = 0; - spin_unlock_irq(&dev->hardware_lock); -} - -static int ite8709_set_use_inc(void *data) -{ - struct ite8709_device *dev; - dev = data; - if (dev->use_count == 0) - ite8709_init_hardware(dev); - dev->use_count++; - return 0; -} - -static void ite8709_set_use_dec(void *data) -{ - struct ite8709_device *dev; - dev = data; - dev->use_count--; - if (dev->use_count == 0) - ite8709_drop_hardware(dev); -} - -static void ite8709_add_read_queue(struct ite8709_device *dev, int flag, - __u64 val) -{ - int value; - - dprintk("add a %llu usec %s\n", val, flag ? "pulse" : "space"); - - value = (val > PULSE_MASK) ? PULSE_MASK : val; - if (flag) - value |= PULSE_BIT; - - if (!lirc_buffer_full(dev->driver.rbuf)) { - lirc_buffer_write(dev->driver.rbuf, (void *) &value); - wake_up(&dev->driver.rbuf->wait_poll); - } -} - -static irqreturn_t ite8709_interrupt(int irq, void *dev_id) -{ - unsigned char data; - int iir, rfsr, i; - int fifo = 0; - char bit; - struct timeval curr_tv; - - /* Bit duration in microseconds */ - const unsigned long bit_duration = 1000000ul / (115200 / CFG_BDR); - - struct ite8709_device *dev; - dev = dev_id; - - /* - * If device is busy, we simply discard data because we are in one of - * these two cases : shutting down or rearming the device, so this - * doesn't really matter and this avoids waiting too long in IRQ ctx - */ - spin_lock(&dev->hardware_lock); - if (dev->device_busy) { - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_HANDLED); - } - - iir = ite8709_read(dev, ITE8709_IIR); - - switch (iir) { - case ITE8709_IIR_RFOI: - dprintk("fifo overrun, scheduling forced rearm just in case\n"); - dev->force_rearm = 1; - tasklet_schedule(&dev->tasklet); - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_HANDLED); - - case ITE8709_IIR_RDAI: - rfsr = ite8709_read(dev, ITE8709_RFSR); - fifo = rfsr & ITE8709_RFSR_MASK; - if (fifo > 32) - fifo = 32; - dprintk("iir: 0x%x rfsr: 0x%x fifo: %d\n", iir, rfsr, fifo); - - if (dev->rearmed) { - do_gettimeofday(&curr_tv); - dev->acc_space += 1000000ull - * (curr_tv.tv_sec - dev->last_tv.tv_sec) - + (curr_tv.tv_usec - dev->last_tv.tv_usec); - dev->rearmed = 0; - } - for (i = 0; i < fifo; i++) { - data = ite8709_read(dev, i+ITE8709_FIFO_START); - data = ~data; - /* Loop through */ - for (bit = 0; bit < 8; ++bit) { - if ((data >> bit) & 1) { - dev->acc_pulse += bit_duration; - if (dev->lastbit == 0) { - ite8709_add_read_queue(dev, 0, - dev->acc_space); - dev->acc_space = 0; - } - } else { - dev->acc_space += bit_duration; - if (dev->lastbit == 1) { - ite8709_add_read_queue(dev, 1, - dev->acc_pulse); - dev->acc_pulse = 0; - } - } - dev->lastbit = (data >> bit) & 1; - } - } - ite8709_write(dev, ITE8709_RFSR, 0); - - if (dev->acc_space > CFG_TIMEOUT) { - dprintk("scheduling rearm IRQ\n"); - do_gettimeofday(&dev->last_tv); - dev->force_rearm = 0; - tasklet_schedule(&dev->tasklet); - } - - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_HANDLED); - - default: - /* not our irq */ - dprintk("unknown IRQ (shouldn't happen) !!\n"); - spin_unlock(&dev->hardware_lock); - return IRQ_RETVAL(IRQ_NONE); - } -} - -static void ite8709_rearm_irq(unsigned long data) -{ - struct ite8709_device *dev; - unsigned long flags; - dev = (struct ite8709_device *) data; - - spin_lock_irqsave(&dev->hardware_lock, flags); - dev->device_busy = 1; - spin_unlock_irqrestore(&dev->hardware_lock, flags); - - if (dev->force_rearm || dev->acc_space > CFG_TIMEOUT) { - dprintk("rearming IRQ\n"); - ite8709_write_register(dev, IT8512_REG_RCR, - IT8512_RCR_RXACT | CFG_DCR); - ite8709_write_register(dev, IT8512_REG_MSTCR, - CFG_FIFOTL | IT8512_MSTCR_FIFOCLR); - ite8709_write_register(dev, IT8512_REG_RCR, - IT8512_RCR_RXEN | IT8512_RCR_RXACT | CFG_DCR); - if (!dev->force_rearm) - dev->rearmed = 1; - dev->force_rearm = 0; - } - - spin_lock_irqsave(&dev->hardware_lock, flags); - dev->device_busy = 0; - spin_unlock_irqrestore(&dev->hardware_lock, flags); -} - -static int ite8709_cleanup(struct ite8709_device *dev, int stage, int errno, - char *msg) -{ - if (msg != NULL) - printk(KERN_ERR LIRC_DRIVER_NAME ": %s\n", msg); - - switch (stage) { - case 6: - if (dev->use_count > 0) - ite8709_drop_hardware(dev); - case 5: - free_irq(dev->irq, dev); - case 4: - release_region(dev->io, 2); - case 3: - lirc_unregister_driver(dev->driver.minor); - case 2: - lirc_buffer_free(dev->driver.rbuf); - kfree(dev->driver.rbuf); - case 1: - kfree(dev); - case 0: - ; - } - - return errno; -} - -static int __devinit ite8709_pnp_probe(struct pnp_dev *dev, - const struct pnp_device_id *dev_id) -{ - struct lirc_driver *driver; - struct ite8709_device *ite8709_dev; - int ret; - - /* Check resources validity */ - if (!pnp_irq_valid(dev, 0)) - return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IRQ"); - if (!pnp_port_valid(dev, 2)) - return ite8709_cleanup(NULL, 0, -ENODEV, "invalid IO port"); - - /* Allocate memory for device struct */ - ite8709_dev = kzalloc(sizeof(struct ite8709_device), GFP_KERNEL); - if (ite8709_dev == NULL) - return ite8709_cleanup(NULL, 0, -ENOMEM, "kzalloc failed"); - pnp_set_drvdata(dev, ite8709_dev); - - /* Initialize device struct */ - ite8709_dev->use_count = 0; - ite8709_dev->irq = pnp_irq(dev, 0); - ite8709_dev->io = pnp_port_start(dev, 2); - ite8709_dev->hardware_lock = - __SPIN_LOCK_UNLOCKED(ite8709_dev->hardware_lock); - ite8709_dev->acc_pulse = 0; - ite8709_dev->acc_space = 0; - ite8709_dev->lastbit = 0; - do_gettimeofday(&ite8709_dev->last_tv); - tasklet_init(&ite8709_dev->tasklet, ite8709_rearm_irq, - (long) ite8709_dev); - ite8709_dev->force_rearm = 0; - ite8709_dev->rearmed = 0; - ite8709_dev->device_busy = 0; - - /* Initialize driver struct */ - driver = &ite8709_dev->driver; - strcpy(driver->name, LIRC_DRIVER_NAME); - driver->minor = -1; - driver->code_length = sizeof(int) * 8; - driver->sample_rate = 0; - driver->features = LIRC_CAN_REC_MODE2; - driver->data = ite8709_dev; - driver->add_to_buf = NULL; - driver->set_use_inc = ite8709_set_use_inc; - driver->set_use_dec = ite8709_set_use_dec; - driver->dev = &dev->dev; - driver->owner = THIS_MODULE; - - /* Initialize LIRC buffer */ - driver->rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!driver->rbuf) - return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, - "can't allocate lirc_buffer"); - if (lirc_buffer_init(driver->rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) - return ite8709_cleanup(ite8709_dev, 1, -ENOMEM, - "lirc_buffer_init() failed"); - - /* Register LIRC driver */ - ret = lirc_register_driver(driver); - if (ret < 0) - return ite8709_cleanup(ite8709_dev, 2, ret, - "lirc_register_driver() failed"); - - /* Reserve I/O port access */ - if (!request_region(ite8709_dev->io, 2, LIRC_DRIVER_NAME)) - return ite8709_cleanup(ite8709_dev, 3, -EBUSY, - "i/o port already in use"); - - /* Reserve IRQ line */ - ret = request_irq(ite8709_dev->irq, ite8709_interrupt, 0, - LIRC_DRIVER_NAME, ite8709_dev); - if (ret < 0) - return ite8709_cleanup(ite8709_dev, 4, ret, - "IRQ already in use"); - - /* Initialize hardware */ - ite8709_drop_hardware(ite8709_dev); /* Shutdown hw until first use */ - - printk(KERN_INFO LIRC_DRIVER_NAME ": device found : irq=%d io=0x%x\n", - ite8709_dev->irq, ite8709_dev->io); - - return 0; -} - -static void __devexit ite8709_pnp_remove(struct pnp_dev *dev) -{ - struct ite8709_device *ite8709_dev; - ite8709_dev = pnp_get_drvdata(dev); - - ite8709_cleanup(ite8709_dev, 6, 0, NULL); - - printk(KERN_INFO LIRC_DRIVER_NAME ": device removed\n"); -} - -#ifdef CONFIG_PM -static int ite8709_pnp_suspend(struct pnp_dev *dev, pm_message_t state) -{ - struct ite8709_device *ite8709_dev; - ite8709_dev = pnp_get_drvdata(dev); - - if (ite8709_dev->use_count > 0) - ite8709_drop_hardware(ite8709_dev); - - return 0; -} - -static int ite8709_pnp_resume(struct pnp_dev *dev) -{ - struct ite8709_device *ite8709_dev; - ite8709_dev = pnp_get_drvdata(dev); - - if (ite8709_dev->use_count > 0) - ite8709_init_hardware(ite8709_dev); - - return 0; -} -#else -#define ite8709_pnp_suspend NULL -#define ite8709_pnp_resume NULL -#endif - -static const struct pnp_device_id pnp_dev_table[] = { - {"ITE8709", 0}, - {} -}; - -MODULE_DEVICE_TABLE(pnp, pnp_dev_table); - -static struct pnp_driver ite8709_pnp_driver = { - .name = LIRC_DRIVER_NAME, - .probe = ite8709_pnp_probe, - .remove = __devexit_p(ite8709_pnp_remove), - .suspend = ite8709_pnp_suspend, - .resume = ite8709_pnp_resume, - .id_table = pnp_dev_table, -}; - -static int __init ite8709_init_module(void) -{ - return pnp_register_driver(&ite8709_pnp_driver); -} -module_init(ite8709_init_module); - -static void __exit ite8709_cleanup_module(void) -{ - pnp_unregister_driver(&ite8709_pnp_driver); -} -module_exit(ite8709_cleanup_module); - -MODULE_DESCRIPTION("LIRC driver for ITE8709 CIR port"); -MODULE_AUTHOR("Grégory Lardière"); -MODULE_LICENSE("GPL"); - -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging messages"); -- cgit v1.2.2 From 2aefbc1acb5370b0753d16c9d6e65e01fe586c75 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Thu, 17 Mar 2011 21:08:55 -0300 Subject: [media] tm6000: fix s-video input Add compatibility for composite and s-video inputs. Some TV cards hasn't it. Fix S-Video input, the s-video cable has only video signals no audio. Call the function of audio configure kill chroma in signal. only b/w video. Known bugs: - after s-video the audio for radio didn't work, TV crashed hardly - after composite TV crashed hardly too. P.S. After this patch I'll want to rework the procedure of configure video. Now it has a lot of junk and dubles. With my best regards, Dmitry. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/tm6000/tm6000-cards.c | 46 +++++++++++++++++++++-------------- drivers/staging/tm6000/tm6000-stds.c | 2 -- drivers/staging/tm6000/tm6000-video.c | 17 ++++++++++--- drivers/staging/tm6000/tm6000.h | 2 ++ 4 files changed, 43 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c index 88144a12745d..146c7e86deca 100644 --- a/drivers/staging/tm6000/tm6000-cards.c +++ b/drivers/staging/tm6000/tm6000-cards.c @@ -235,11 +235,13 @@ struct tm6000_board tm6000_boards[] = { .avideo = TM6000_AIP_SIF1, .aradio = TM6000_AIP_LINE1, .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, - .has_remote = 1, + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 1, + .has_input_comp = 1, + .has_input_svid = 1, }, .gpio = { .tuner_reset = TM6010_GPIO_0, @@ -255,11 +257,13 @@ struct tm6000_board tm6000_boards[] = { .avideo = TM6000_AIP_SIF1, .aradio = TM6000_AIP_LINE1, .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, - .has_remote = 1, + .has_tuner = 1, + .has_dvb = 0, + .has_zl10353 = 0, + .has_eeprom = 1, + .has_remote = 1, + .has_input_comp = 1, + .has_input_svid = 1, }, .gpio = { .tuner_reset = TM6010_GPIO_0, @@ -327,10 +331,13 @@ struct tm6000_board tm6000_boards[] = { .avideo = TM6000_AIP_SIF1, .aradio = TM6000_AIP_LINE1, .caps = { - .has_tuner = 1, - .has_dvb = 1, - .has_zl10353 = 1, - .has_eeprom = 1, + .has_tuner = 1, + .has_dvb = 1, + .has_zl10353 = 1, + .has_eeprom = 1, + .has_remote = 0, + .has_input_comp = 0, + .has_input_svid = 0, }, .gpio = { .tuner_reset = TM6010_GPIO_0, @@ -346,10 +353,13 @@ struct tm6000_board tm6000_boards[] = { .avideo = TM6000_AIP_SIF1, .aradio = TM6000_AIP_LINE1, .caps = { - .has_tuner = 1, - .has_dvb = 0, - .has_zl10353 = 0, - .has_eeprom = 1, + .has_tuner = 1, + .has_dvb = 0, + .has_zl10353 = 0, + .has_eeprom = 1, + .has_remote = 0, + .has_input_comp = 0, + .has_input_svid = 0, }, .gpio = { .tuner_reset = TM6010_GPIO_0, diff --git a/drivers/staging/tm6000/tm6000-stds.c b/drivers/staging/tm6000/tm6000-stds.c index a4c07e5a6f1d..da3e51bde109 100644 --- a/drivers/staging/tm6000/tm6000-stds.c +++ b/drivers/staging/tm6000/tm6000-stds.c @@ -1161,8 +1161,6 @@ int tm6000_set_standard(struct tm6000_core *dev, v4l2_std_id * norm) rc = tm6000_load_std(dev, svideo_stds[i].common, sizeof(svideo_stds[i]. common)); - tm6000_set_audio_std(dev, svideo_stds[i].audio_default_std); - goto ret; } } diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index b5503409ca55..c80a316d9d8f 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -1080,18 +1080,27 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *norm) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { + struct tm6000_fh *fh = priv; + struct tm6000_core *dev = fh->dev; + switch (inp->index) { case TM6000_INPUT_TV: inp->type = V4L2_INPUT_TYPE_TUNER; strcpy(inp->name, "Television"); break; case TM6000_INPUT_COMPOSITE: - inp->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(inp->name, "Composite"); + if (dev->caps.has_input_comp) { + inp->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(inp->name, "Composite"); + } else + return -EINVAL; break; case TM6000_INPUT_SVIDEO: - inp->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(inp->name, "S-Video"); + if (dev->caps.has_input_svid) { + inp->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(inp->name, "S-Video"); + } else + return -EINVAL; break; default: return -EINVAL; diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h index ccd120fe1340..99ae50e82b28 100644 --- a/drivers/staging/tm6000/tm6000.h +++ b/drivers/staging/tm6000/tm6000.h @@ -129,6 +129,8 @@ struct tm6000_capabilities { unsigned int has_zl10353:1; unsigned int has_eeprom:1; unsigned int has_remote:1; + unsigned int has_input_comp:1; + unsigned int has_input_svid:1; }; struct tm6000_dvb { -- cgit v1.2.2 From 53a5fd4dede974ba9727cda430e6714293be5e71 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 1 Feb 2011 16:27:05 -0300 Subject: [media] imon: add more panel scancode mappings Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index e7dc6b46fdfa..f714e1a22c92 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -277,12 +277,21 @@ static const struct { u64 hw_code; u32 keycode; } imon_panel_key_table[] = { - { 0x000000000f00ffeell, KEY_PROG1 }, /* Go */ + { 0x000000000f00ffeell, KEY_MEDIA }, /* Go */ + { 0x000000001200ffeell, KEY_UP }, + { 0x000000001300ffeell, KEY_DOWN }, + { 0x000000001400ffeell, KEY_LEFT }, + { 0x000000001500ffeell, KEY_RIGHT }, + { 0x000000001600ffeell, KEY_ENTER }, + { 0x000000001700ffeell, KEY_ESC }, { 0x000000001f00ffeell, KEY_AUDIO }, { 0x000000002000ffeell, KEY_VIDEO }, { 0x000000002100ffeell, KEY_CAMERA }, { 0x000000002700ffeell, KEY_DVD }, { 0x000000002300ffeell, KEY_TV }, + { 0x000000002b00ffeell, KEY_EXIT }, + { 0x000000002c00ffeell, KEY_SELECT }, + { 0x000000002d00ffeell, KEY_MENU }, { 0x000000000500ffeell, KEY_PREVIOUS }, { 0x000000000700ffeell, KEY_REWIND }, { 0x000000000400ffeell, KEY_STOP }, -- cgit v1.2.2 From b443ac5a2836532af2315a4acb95c7a2cf721cbd Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Wed, 2 Mar 2011 13:23:52 -0300 Subject: [media] hdpvr: i2c master enhancements Make the hdpvr's i2c master implementation more closely mirror that of the pvrusb2 driver. Currently makes no significant difference in IR reception behavior with ir-kbd-i2c (i.e., it still sucks). Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/hdpvr/hdpvr-i2c.c | 67 ++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index e53fa55d56a1..3e0658768135 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -62,15 +62,25 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) } static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, - unsigned char addr, char *data, int len) + unsigned char addr, char *wdata, int wlen, + char *data, int len) { int ret; - if (len > sizeof(dev->i2c_buf)) + if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf))) return -EINVAL; - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), + if (wlen) { + memcpy(&dev->i2c_buf, wdata, wlen); + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, + (bus << 8) | addr, 0, &dev->i2c_buf, + wlen, 1000); + if (ret < 0) + return ret; + } + + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), REQTYPE_I2C_READ, CTRL_READ_REQUEST, (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); @@ -92,16 +102,14 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, return -EINVAL; memcpy(&dev->i2c_buf, data, len); - ret = usb_control_msg(dev->udev, - usb_sndctrlpipe(dev->udev, 0), + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); if (ret < 0) return ret; - ret = usb_control_msg(dev->udev, - usb_rcvctrlpipe(dev->udev, 0), + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, 0, 0, &dev->i2c_buf, 2, 1000); @@ -117,24 +125,49 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, int num) { struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter); - int retval = 0, i, addr; + int retval = 0, addr; if (num <= 0) return 0; mutex_lock(&dev->i2c_mutex); - for (i = 0; i < num && !retval; i++) { - addr = msgs[i].addr << 1; + addr = msgs[0].addr << 1; - if (msgs[i].flags & I2C_M_RD) - retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf, - msgs[i].len); + if (num == 1) { + if (msgs[0].flags & I2C_M_RD) + retval = hdpvr_i2c_read(dev, 1, addr, NULL, 0, + msgs[0].buf, msgs[0].len); else - retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf, - msgs[i].len); + retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, + msgs[0].len); + } else if (num == 2) { + if (msgs[0].addr != msgs[1].addr) { + v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer " + "with conflicting target addresses\n"); + retval = -EINVAL; + goto out; + } + + if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { + v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with " + "r0=%d, r1=%d\n", msgs[0].flags & I2C_M_RD, + msgs[1].flags & I2C_M_RD); + retval = -EINVAL; + goto out; + } + + /* + * Write followed by atomic read is the only complex xfer that + * we actually support here. + */ + retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, + msgs[1].buf, msgs[1].len); + } else { + v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num); } +out: mutex_unlock(&dev->i2c_mutex); return retval ? retval : num; @@ -162,7 +195,7 @@ static int hdpvr_activate_ir(struct hdpvr_device *dev) mutex_lock(&dev->i2c_mutex); - hdpvr_i2c_read(dev, 0, 0x54, buffer, 1); + hdpvr_i2c_read(dev, 0, 0x54, NULL, 0, buffer, 1); buffer[0] = 0; buffer[1] = 0x8; -- cgit v1.2.2 From 12d896e1c17978599a98510fdfaff27a4e82c0bf Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 26 Jan 2011 21:06:43 -0300 Subject: [media] lirc_zilog: Restore checks for existence of the IR_tx object This reverts commit 8090232a237ab62e22307fc060097da1a283dd66 and adds an additional check for ir->tx == NULL. The user may need us to handle an RX only unit. Apparently there are TV capture units in existence with Rx only wiring and/or RX only firmware for the on-board Zilog Z8 IR unit. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 0aad0d7a74a3..7389b77ece8c 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -209,7 +209,8 @@ static int add_to_buf(struct IR *ir) return -ENODATA; } schedule_timeout((100 * HZ + 999) / 1000); - ir->tx->need_boot = 1; + if (ir->tx != NULL) + ir->tx->need_boot = 1; ++failures; mutex_unlock(&ir->ir_lock); @@ -1032,9 +1033,10 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) int result; unsigned long mode, features = 0; - features |= LIRC_CAN_SEND_PULSE; if (ir->rx != NULL) features |= LIRC_CAN_REC_LIRCCODE; + if (ir->tx != NULL) + features |= LIRC_CAN_SEND_PULSE; switch (cmd) { case LIRC_GET_LENGTH: @@ -1061,9 +1063,15 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) result = -EINVAL; break; case LIRC_GET_SEND_MODE: + if (!(features&LIRC_CAN_SEND_MASK)) + return -ENOSYS; + result = put_user(LIRC_MODE_PULSE, (unsigned long *) arg); break; case LIRC_SET_SEND_MODE: + if (!(features&LIRC_CAN_SEND_MASK)) + return -ENOSYS; + result = get_user(mode, (unsigned long *) arg); if (!result && mode != LIRC_MODE_PULSE) return -EINVAL; @@ -1242,8 +1250,10 @@ static int ir_remove(struct i2c_client *client) } /* Good-bye Tx */ - i2c_set_clientdata(ir->tx->c, NULL); - kfree(ir->tx); + if (ir->tx != NULL) { + i2c_set_clientdata(ir->tx->c, NULL); + kfree(ir->tx); + } /* Good-bye IR */ del_ir_device(ir); @@ -1393,9 +1403,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) * after registering with lirc as otherwise hotplug seems to take * 10s to create the lirc device. */ - ret = tx_init(ir->tx); - if (ret != 0) - goto out_unregister; + if (ir->tx != NULL) { + /* Special TX init */ + ret = tx_init(ir->tx); + if (ret != 0) + goto out_unregister; + } zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n", tx_probe ? "Tx" : "Rx", adap->name, adap->nr); -- cgit v1.2.2 From 9b28500a59d7ee5da5adb43bcb384391cac401c4 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 26 Jan 2011 21:25:47 -0300 Subject: [media] lirc_zilog: Remove broken, ineffective reference counting The set_use_inc() and set_use_dec() functions tried to lock the underlying bridge driver device instance in memory by changing the use count on the device's i2c_clients. This worked for PCI devices (ivtv, cx18, bttv). It doesn't work for hot-pluggable usb devices (pvrusb2 and hdpvr). With usb device instances, the driver may get locked into memory, but the unplugged hardware is gone. The set_use_inc() set_use_dec() functions also tried to have lirc_zilog change its own module refernce count, which is racy and not guaranteed to work. The lirc_dev module does actually perform proper module ref count manipulation on the lirc_zilog module, so there is need for lirc_zilog to attempt a buggy module get on itself anyway. lirc_zilog also errantly called these functions on itself in open() and close(), but lirc_dev did that already too. So let's just gut the bodies of the set_use_*() functions, and remove the extra calls to them from within lirc_zilog. Proper reference counting of the struct IR, IR_rx, and IR_tx objects -- to handle the case when the underlying bttv, ivtv, cx18, hdpvr, or pvrusb2 bridge driver module or device instance goes away -- will be added in subsequent patches. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 7389b77ece8c..3a912575e12d 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -305,34 +305,12 @@ static int lirc_thread(void *arg) static int set_use_inc(void *data) { - struct IR *ir = data; - - if (ir->l.owner == NULL || try_module_get(ir->l.owner) == 0) - return -ENODEV; - - /* lock bttv in memory while /dev/lirc is in use */ - /* - * this is completely broken code. lirc_unregister_driver() - * must be possible even when the device is open - */ - if (ir->rx != NULL) - i2c_use_client(ir->rx->c); - if (ir->tx != NULL) - i2c_use_client(ir->tx->c); - return 0; } static void set_use_dec(void *data) { - struct IR *ir = data; - - if (ir->rx) - i2c_release_client(ir->rx->c); - if (ir->tx) - i2c_release_client(ir->tx->c); - if (ir->l.owner != NULL) - module_put(ir->l.owner); + return; } /* safe read of a uint32 (always network byte order) */ @@ -1098,7 +1076,6 @@ static struct IR *find_ir_device_by_minor(unsigned int minor) static int open(struct inode *node, struct file *filep) { struct IR *ir; - int ret; unsigned int minor = MINOR(node->i_rdev); /* find our IR struct */ @@ -1112,12 +1089,6 @@ static int open(struct inode *node, struct file *filep) /* increment in use count */ mutex_lock(&ir->ir_lock); ++ir->open; - ret = set_use_inc(ir); - if (ret != 0) { - --ir->open; - mutex_unlock(&ir->ir_lock); - return ret; - } mutex_unlock(&ir->ir_lock); /* stash our IR struct */ @@ -1139,7 +1110,6 @@ static int close(struct inode *node, struct file *filep) /* decrement in use count */ mutex_lock(&ir->ir_lock); --ir->open; - set_use_dec(ir); mutex_unlock(&ir->ir_lock); return 0; -- cgit v1.2.2 From 5c07134fff9e6b1f9a3c75e62bbb827d1faa72eb Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 26 Jan 2011 21:48:32 -0300 Subject: [media] lirc_zilog: Convert ir_device instance array to a linked list Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 59 ++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 3a912575e12d..39f7b53f0785 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -89,6 +89,8 @@ struct IR_tx { }; struct IR { + struct list_head list; + struct lirc_driver l; struct mutex ir_lock; @@ -99,9 +101,9 @@ struct IR { struct IR_tx *tx; }; -/* Minor -> data mapping */ -static struct mutex ir_devices_lock; -static struct IR *ir_devices[MAX_IRCTL_DEVICES]; +/* IR transceiver instance object list */ +static DEFINE_MUTEX(ir_devices_lock); +static LIST_HEAD(ir_devices_list); /* Block size for IR transmitter */ #define TX_BLOCK_SIZE 99 @@ -1063,10 +1065,16 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) /* ir_devices_lock must be held */ static struct IR *find_ir_device_by_minor(unsigned int minor) { - if (minor >= MAX_IRCTL_DEVICES) + struct IR *ir; + + if (list_empty(&ir_devices_list)) return NULL; - return ir_devices[minor]; + list_for_each_entry(ir, &ir_devices_list, list) + if (ir->l.minor == minor) + return ir; + + return NULL; } /* @@ -1172,25 +1180,21 @@ static void destroy_rx_kthread(struct IR_rx *rx) /* ir_devices_lock must be held */ static int add_ir_device(struct IR *ir) { - int i; - - for (i = 0; i < MAX_IRCTL_DEVICES; i++) - if (ir_devices[i] == NULL) { - ir_devices[i] = ir; - break; - } - - return i == MAX_IRCTL_DEVICES ? -ENOMEM : i; + list_add_tail(&ir->list, &ir_devices_list); + return 0; } /* ir_devices_lock must be held */ static void del_ir_device(struct IR *ir) { - int i; + struct IR *p; + + if (list_empty(&ir_devices_list)) + return; - for (i = 0; i < MAX_IRCTL_DEVICES; i++) - if (ir_devices[i] == ir) { - ir_devices[i] = NULL; + list_for_each_entry(p, &ir_devices_list, list) + if (p == ir) { + list_del(&p->list); break; } } @@ -1237,17 +1241,16 @@ static int ir_remove(struct i2c_client *client) /* ir_devices_lock must be held */ static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter) { - int i; - struct IR *ir = NULL; + struct IR *ir; - for (i = 0; i < MAX_IRCTL_DEVICES; i++) - if (ir_devices[i] != NULL && - ir_devices[i]->adapter == adapter) { - ir = ir_devices[i]; - break; - } + if (list_empty(&ir_devices_list)) + return NULL; + + list_for_each_entry(ir, &ir_devices_list, list) + if (ir->adapter == adapter) + return ir; - return ir; + return NULL; } static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -1284,6 +1287,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) goto out_no_ir; } /* store for use in ir_probe() again, and open() later on */ + INIT_LIST_HEAD(&ir->list); ret = add_ir_device(ir); if (ret) goto out_free_ir; @@ -1421,7 +1425,6 @@ static int __init zilog_init(void) zilog_notify("Zilog/Hauppauge IR driver initializing\n"); mutex_init(&tx_data_lock); - mutex_init(&ir_devices_lock); request_module("firmware_class"); -- cgit v1.2.2 From a30648550f2f758c9c00c493c8919f89f65438c4 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 26 Jan 2011 22:04:24 -0300 Subject: [media] lirc_zilog: Convert the instance open count to an atomic_t The open count is simply used for deciding if the Rx polling thread needs to poll the IR chip for userspace. Simplify the manipulation of the open count by using an atomic_t and not requiring a lock The polling thread errantly didn't try to take the lock anyway. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 39f7b53f0785..c857b99e5ace 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -94,7 +94,7 @@ struct IR { struct lirc_driver l; struct mutex ir_lock; - int open; + atomic_t open_count; struct i2c_adapter *adapter; struct IR_rx *rx; @@ -279,7 +279,7 @@ static int lirc_thread(void *arg) set_current_state(TASK_INTERRUPTIBLE); /* if device not opened, we can sleep half a second */ - if (!ir->open) { + if (atomic_read(&ir->open_count) == 0) { schedule_timeout(HZ/2); continue; } @@ -1094,10 +1094,7 @@ static int open(struct inode *node, struct file *filep) if (ir == NULL) return -ENODEV; - /* increment in use count */ - mutex_lock(&ir->ir_lock); - ++ir->open; - mutex_unlock(&ir->ir_lock); + atomic_inc(&ir->open_count); /* stash our IR struct */ filep->private_data = ir; @@ -1115,10 +1112,7 @@ static int close(struct inode *node, struct file *filep) return -ENODEV; } - /* decrement in use count */ - mutex_lock(&ir->ir_lock); - --ir->open; - mutex_unlock(&ir->ir_lock); + atomic_dec(&ir->open_count); return 0; } @@ -1294,6 +1288,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->adapter = adap; mutex_init(&ir->ir_lock); + atomic_set(&ir->open_count, 0); /* set lirc_dev stuff */ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); -- cgit v1.2.2 From 9a55a2b37eb7e4941ef55aadb858b615d229afee Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 27 Jan 2011 00:04:15 -0300 Subject: [media] lirc_zilog: Use kernel standard methods for marking device non-seekable lirc_zilog had its own llseek stub that returned -ESPIPE. Get rid of it and use the kernel's no_llseek() and nonseekable_open() functions instead. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index c857b99e5ace..720ef6739d0e 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -712,12 +712,6 @@ static int tx_init(struct IR_tx *tx) return 0; } -/* do nothing stub to make LIRC happy */ -static loff_t lseek(struct file *filep, loff_t offset, int orig) -{ - return -ESPIPE; -} - /* copied from lirc_dev */ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) { @@ -1099,6 +1093,7 @@ static int open(struct inode *node, struct file *filep) /* stash our IR struct */ filep->private_data = ir; + nonseekable_open(node, filep); return 0; } @@ -1150,7 +1145,7 @@ static struct i2c_driver driver = { static const struct file_operations lirc_fops = { .owner = THIS_MODULE, - .llseek = lseek, + .llseek = no_llseek, .read = read, .write = write, .poll = poll, -- cgit v1.2.2 From 915e54733de4a36742ab78b4768750ce72662f85 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 27 Jan 2011 02:10:42 -0300 Subject: [media] lirc_zilog: Don't acquire the rx->buf_lock in the poll() function There is no need to take the rx->buf_lock in the the poll() function as all the underling calls made on objects in the rx->buf lirc_buffer object are protected by spinlocks. Corrected a bad error return value in poll(): return POLLERR instead of -ENODEV. Added some comments to poll() for when, in the future, I forget what poll() and poll_wait() are supposed to do. [Jarod: minor debug spew fix] Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 720ef6739d0e..695c3df93ca8 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -985,19 +985,26 @@ static unsigned int poll(struct file *filep, poll_table *wait) unsigned int ret; dprintk("poll called\n"); - if (rx == NULL) - return -ENODEV; - mutex_lock(&rx->buf_lock); + if (rx == NULL) { + /* + * Revisit this, if our poll function ever reports writeable + * status for Tx + */ + dprintk("poll result = POLLERR\n"); + return POLLERR; + } + /* + * Add our lirc_buffer's wait_queue to the poll_table. A wake up on + * that buffer's wait queue indicates we may have a new poll status. + */ poll_wait(filep, &rx->buf.wait_poll, wait); - dprintk("poll result = %s\n", - lirc_buffer_empty(&rx->buf) ? "0" : "POLLIN|POLLRDNORM"); - + /* Indicate what ops could happen immediately without blocking */ ret = lirc_buffer_empty(&rx->buf) ? 0 : (POLLIN|POLLRDNORM); - mutex_unlock(&rx->buf_lock); + dprintk("poll result = %s\n", ret ? "POLLIN|POLLRDNORM" : "none"); return ret; } -- cgit v1.2.2 From 8152b760effbff11cb4eef6292ae3b47719ee792 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 27 Jan 2011 02:34:13 -0300 Subject: [media] lirc_zilog: Remove unneeded rx->buf_lock Remove the rx->buf_lock that protected the rx->buf lirc_buffer. The underlying operations on the objects within the lirc_buffer are already protected by spinlocks, or the objects are constant (e.g. chunk_size). Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 695c3df93ca8..a62b94bf6a1a 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -67,9 +67,8 @@ struct IR_rx { /* RX device */ struct i2c_client *c; - /* RX device buffer & lock */ + /* RX device buffer */ struct lirc_buffer buf; - struct mutex buf_lock; /* RX polling thread data */ struct task_struct *task; @@ -718,18 +717,15 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) struct IR *ir = filep->private_data; struct IR_rx *rx = ir->rx; int ret = 0, written = 0; + unsigned int m; DECLARE_WAITQUEUE(wait, current); dprintk("read called\n"); if (rx == NULL) return -ENODEV; - if (mutex_lock_interruptible(&rx->buf_lock)) - return -ERESTARTSYS; - if (n % rx->buf.chunk_size) { dprintk("read result = -EINVAL\n"); - mutex_unlock(&rx->buf_lock); return -EINVAL; } @@ -767,19 +763,19 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) set_current_state(TASK_INTERRUPTIBLE); } else { unsigned char buf[rx->buf.chunk_size]; - lirc_buffer_read(&rx->buf, buf); - ret = copy_to_user((void *)outbuf+written, buf, - rx->buf.chunk_size); - written += rx->buf.chunk_size; + m = lirc_buffer_read(&rx->buf, buf); + if (m == rx->buf.chunk_size) { + ret = copy_to_user((void *)outbuf+written, buf, + rx->buf.chunk_size); + written += rx->buf.chunk_size; + } } } remove_wait_queue(&rx->buf.wait_poll, &wait); set_current_state(TASK_RUNNING); - mutex_unlock(&rx->buf_lock); - dprintk("read result = %s (%d)\n", - ret ? "-EFAULT" : "OK", ret); + dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK"); return ret ? ret : written; } @@ -1327,7 +1323,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) if (ret) goto out_free_xx; - mutex_init(&ir->rx->buf_lock); ir->rx->c = client; ir->rx->hdpvr_data_fmt = (id->driver_data & ID_FLAG_HDPVR) ? true : false; -- cgit v1.2.2 From bcbd165509da05a2317ac7dce3c6b952e98a01ef Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 27 Jan 2011 22:32:44 -0300 Subject: [media] lirc_zilog: Always allocate a Rx lirc_buffer object Always allocate a lirc_buffer object, instead of just upon setup of the Rx i2c_client. If we do not allocate a lirc_buffer object, because we are not handling the Rx i2c_client, lirc_dev will allocate its own lirc_buffer anyway and not tell us about its location. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 62 +++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index a62b94bf6a1a..053fddb8e448 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -67,9 +67,6 @@ struct IR_rx { /* RX device */ struct i2c_client *c; - /* RX device buffer */ - struct lirc_buffer buf; - /* RX polling thread data */ struct task_struct *task; @@ -91,6 +88,7 @@ struct IR { struct list_head list; struct lirc_driver l; + struct lirc_buffer rbuf; struct mutex ir_lock; atomic_t open_count; @@ -157,12 +155,13 @@ static int add_to_buf(struct IR *ir) int ret; int failures = 0; unsigned char sendbuf[1] = { 0 }; + struct lirc_buffer *rbuf = ir->l.rbuf; struct IR_rx *rx = ir->rx; if (rx == NULL) return -ENXIO; - if (lirc_buffer_full(&rx->buf)) { + if (lirc_buffer_full(rbuf)) { dprintk("buffer overflow\n"); return -EOVERFLOW; } @@ -250,9 +249,9 @@ static int add_to_buf(struct IR *ir) codes[1] = code & 0xff; /* return it */ - lirc_buffer_write(&rx->buf, codes); + lirc_buffer_write(rbuf, codes); ++got_data; - } while (!lirc_buffer_full(&rx->buf)); + } while (!lirc_buffer_full(rbuf)); return 0; } @@ -270,7 +269,7 @@ static int add_to_buf(struct IR *ir) static int lirc_thread(void *arg) { struct IR *ir = arg; - struct IR_rx *rx = ir->rx; + struct lirc_buffer *rbuf = ir->l.rbuf; dprintk("poll thread started\n"); @@ -297,7 +296,7 @@ static int lirc_thread(void *arg) if (kthread_should_stop()) break; if (!add_to_buf(ir)) - wake_up_interruptible(&rx->buf.wait_poll); + wake_up_interruptible(&rbuf->wait_poll); } dprintk("poll thread ended\n"); @@ -716,6 +715,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) { struct IR *ir = filep->private_data; struct IR_rx *rx = ir->rx; + struct lirc_buffer *rbuf = ir->l.rbuf; int ret = 0, written = 0; unsigned int m; DECLARE_WAITQUEUE(wait, current); @@ -724,7 +724,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) if (rx == NULL) return -ENODEV; - if (n % rx->buf.chunk_size) { + if (n % rbuf->chunk_size) { dprintk("read result = -EINVAL\n"); return -EINVAL; } @@ -734,7 +734,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) * to avoid losing scan code (in case when queue is awaken somewhere * between while condition checking and scheduling) */ - add_wait_queue(&rx->buf.wait_poll, &wait); + add_wait_queue(&rbuf->wait_poll, &wait); set_current_state(TASK_INTERRUPTIBLE); /* @@ -742,7 +742,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) * mode and 'copy_to_user' is happy, wait for data. */ while (written < n && ret == 0) { - if (lirc_buffer_empty(&rx->buf)) { + if (lirc_buffer_empty(rbuf)) { /* * According to the read(2) man page, 'written' can be * returned as less than 'n', instead of blocking @@ -762,17 +762,17 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) schedule(); set_current_state(TASK_INTERRUPTIBLE); } else { - unsigned char buf[rx->buf.chunk_size]; - m = lirc_buffer_read(&rx->buf, buf); - if (m == rx->buf.chunk_size) { + unsigned char buf[rbuf->chunk_size]; + m = lirc_buffer_read(rbuf, buf); + if (m == rbuf->chunk_size) { ret = copy_to_user((void *)outbuf+written, buf, - rx->buf.chunk_size); - written += rx->buf.chunk_size; + rbuf->chunk_size); + written += rbuf->chunk_size; } } } - remove_wait_queue(&rx->buf.wait_poll, &wait); + remove_wait_queue(&rbuf->wait_poll, &wait); set_current_state(TASK_RUNNING); dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK"); @@ -978,6 +978,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) { struct IR *ir = filep->private_data; struct IR_rx *rx = ir->rx; + struct lirc_buffer *rbuf = ir->l.rbuf; unsigned int ret; dprintk("poll called\n"); @@ -995,10 +996,10 @@ static unsigned int poll(struct file *filep, poll_table *wait) * Add our lirc_buffer's wait_queue to the poll_table. A wake up on * that buffer's wait queue indicates we may have a new poll status. */ - poll_wait(filep, &rx->buf.wait_poll, wait); + poll_wait(filep, &rbuf->wait_poll, wait); /* Indicate what ops could happen immediately without blocking */ - ret = lirc_buffer_empty(&rx->buf) ? 0 : (POLLIN|POLLRDNORM); + ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM); dprintk("poll result = %s\n", ret ? "POLLIN|POLLRDNORM" : "none"); return ret; @@ -1209,8 +1210,6 @@ static int ir_remove(struct i2c_client *client) /* Good-bye Rx */ destroy_rx_kthread(ir->rx); if (ir->rx != NULL) { - if (ir->rx->buf.fifo_initialized) - lirc_buffer_free(&ir->rx->buf); i2c_set_clientdata(ir->rx->c, NULL); kfree(ir->rx); } @@ -1222,6 +1221,8 @@ static int ir_remove(struct i2c_client *client) } /* Good-bye IR */ + if (ir->rbuf.fifo_initialized) + lirc_buffer_free(&ir->rbuf); del_ir_device(ir); kfree(ir); @@ -1292,11 +1293,17 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); ir->l.minor = minor; /* module option */ ir->l.code_length = 13; - ir->l.rbuf = NULL; + ir->l.chunk_size = 2; + ir->l.buffer_size = BUFLEN / 2; + ir->l.rbuf = &ir->rbuf; ir->l.fops = &lirc_fops; ir->l.data = ir; ir->l.dev = &adap->dev; ir->l.sample_rate = 0; + ret = lirc_buffer_init(ir->l.rbuf, + ir->l.chunk_size, ir->l.buffer_size); + if (ret) + goto out_free_ir; } if (tx_probe) { @@ -1319,16 +1326,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) goto out_free_xx; } - ret = lirc_buffer_init(&ir->rx->buf, 2, BUFLEN / 2); - if (ret) - goto out_free_xx; - ir->rx->c = client; ir->rx->hdpvr_data_fmt = (id->driver_data & ID_FLAG_HDPVR) ? true : false; - - /* set lirc_dev stuff */ - ir->l.rbuf = &ir->rx->buf; } i2c_set_clientdata(client, ir); @@ -1388,8 +1388,6 @@ out_free_thread: destroy_rx_kthread(ir->rx); out_free_xx: if (ir->rx != NULL) { - if (ir->rx->buf.fifo_initialized) - lirc_buffer_free(&ir->rx->buf); if (ir->rx->c != NULL) i2c_set_clientdata(ir->rx->c, NULL); kfree(ir->rx); @@ -1399,6 +1397,8 @@ out_free_xx: i2c_set_clientdata(ir->tx->c, NULL); kfree(ir->tx); } + if (ir->rbuf.fifo_initialized) + lirc_buffer_free(&ir->rbuf); out_free_ir: del_ir_device(ir); kfree(ir); -- cgit v1.2.2 From 534c1eab1e2770dca3cf4616cc4059683020114b Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 27 Jan 2011 23:02:20 -0300 Subject: [media] lirc_zilog: Move constants from ir_probe() into the lirc_driver template ir_probe() makes a number of constant assignments into the lirc_driver object after copying in a template. Make better use of the template. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 053fddb8e448..d06788561189 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -1116,13 +1116,6 @@ static int close(struct inode *node, struct file *filep) return 0; } -static struct lirc_driver lirc_template = { - .name = "lirc_zilog", - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .owner = THIS_MODULE -}; - static int ir_remove(struct i2c_client *client); static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id); @@ -1161,6 +1154,19 @@ static const struct file_operations lirc_fops = { .release = close }; +static struct lirc_driver lirc_template = { + .name = "lirc_zilog", + .minor = -1, + .code_length = 13, + .buffer_size = BUFLEN / 2, + .sample_rate = 0, /* tell lirc_dev to not start its own kthread */ + .chunk_size = 2, + .set_use_inc = set_use_inc, + .set_use_dec = set_use_dec, + .fops = &lirc_fops, + .owner = THIS_MODULE, +}; + static void destroy_rx_kthread(struct IR_rx *rx) { /* end up polling thread */ @@ -1292,14 +1298,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* set lirc_dev stuff */ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); ir->l.minor = minor; /* module option */ - ir->l.code_length = 13; - ir->l.chunk_size = 2; - ir->l.buffer_size = BUFLEN / 2; ir->l.rbuf = &ir->rbuf; - ir->l.fops = &lirc_fops; ir->l.data = ir; ir->l.dev = &adap->dev; - ir->l.sample_rate = 0; ret = lirc_buffer_init(ir->l.rbuf, ir->l.chunk_size, ir->l.buffer_size); if (ret) @@ -1314,6 +1315,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) goto out_free_xx; } + ir->l.features |= LIRC_CAN_SEND_PULSE; ir->tx->c = client; ir->tx->need_boot = 1; ir->tx->post_tx_ready_poll = @@ -1326,6 +1328,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) goto out_free_xx; } + ir->l.features |= LIRC_CAN_REC_LIRCCODE; ir->rx->c = client; ir->rx->hdpvr_data_fmt = (id->driver_data & ID_FLAG_HDPVR) ? true : false; -- cgit v1.2.2 From 5bd6b0464b68d429bc8a3fe6595d19c39dfc4d95 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Mon, 7 Feb 2011 22:30:55 -0300 Subject: [media] lirc_zilog: Add ref counting of struct IR, IR_tx, and IR_rx This is a major change to add pointer reference counting for struct IR, struct IR_tx, and struct IR_rx object instances. This ref counting gets lirc_zilog closer to gracefully handling bridge drivers and hot-unplugged USB devices disappearing out from under lirc_zilog when the /dev/lircN node is still open. (mutexes to protect the i2c_client pointers in struct IR_tx and struct IR_rx still need to be added.) This reference counting also helps lirc_zilog clean up properly when the i2c_clients disappear. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 584 +++++++++++++++++++++++++------------- 1 file changed, 380 insertions(+), 204 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index d06788561189..5df90dbba1c6 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -63,8 +63,14 @@ #include #include +struct IR; + struct IR_rx { + struct kref ref; + struct IR *ir; + /* RX device */ + /* FIXME mutex lock access to this pointer */ struct i2c_client *c; /* RX polling thread data */ @@ -76,7 +82,11 @@ struct IR_rx { }; struct IR_tx { + struct kref ref; + struct IR *ir; + /* TX device */ + /* FIXME mutex lock access to this pointer */ struct i2c_client *c; /* TX additional actions needed */ @@ -85,8 +95,10 @@ struct IR_tx { }; struct IR { + struct kref ref; struct list_head list; + /* FIXME spinlock access to l.features */ struct lirc_driver l; struct lirc_buffer rbuf; @@ -94,11 +106,21 @@ struct IR { atomic_t open_count; struct i2c_adapter *adapter; + + spinlock_t rx_ref_lock; /* struct IR_rx kref get()/put() */ struct IR_rx *rx; + + spinlock_t tx_ref_lock; /* struct IR_tx kref get()/put() */ struct IR_tx *tx; }; /* IR transceiver instance object list */ +/* + * This lock is used for the following: + * a. ir_devices_list access, insertions, deletions + * b. struct IR kref get()s and put()s + * c. serialization of ir_probe() for the two i2c_clients for a Z8 + */ static DEFINE_MUTEX(ir_devices_lock); static LIST_HEAD(ir_devices_list); @@ -146,6 +168,157 @@ static int minor = -1; /* minor number */ ## args); \ } while (0) + +/* struct IR reference counting */ +static struct IR *get_ir_device(struct IR *ir, bool ir_devices_lock_held) +{ + if (ir_devices_lock_held) { + kref_get(&ir->ref); + } else { + mutex_lock(&ir_devices_lock); + kref_get(&ir->ref); + mutex_unlock(&ir_devices_lock); + } + return ir; +} + +static void release_ir_device(struct kref *ref) +{ + struct IR *ir = container_of(ref, struct IR, ref); + + /* + * Things should be in this state by now: + * ir->rx set to NULL and deallocated - happens before ir->rx->ir put() + * ir->rx->task kthread stopped - happens before ir->rx->ir put() + * ir->tx set to NULL and deallocated - happens before ir->tx->ir put() + * ir->open_count == 0 - happens on final close() + * ir_lock, tx_ref_lock, rx_ref_lock, all released + */ + if (ir->l.minor >= 0 && ir->l.minor < MAX_IRCTL_DEVICES) { + lirc_unregister_driver(ir->l.minor); + ir->l.minor = MAX_IRCTL_DEVICES; + } + if (ir->rbuf.fifo_initialized) + lirc_buffer_free(&ir->rbuf); + list_del(&ir->list); + kfree(ir); +} + +static int put_ir_device(struct IR *ir, bool ir_devices_lock_held) +{ + int released; + + if (ir_devices_lock_held) + return kref_put(&ir->ref, release_ir_device); + + mutex_lock(&ir_devices_lock); + released = kref_put(&ir->ref, release_ir_device); + mutex_unlock(&ir_devices_lock); + + return released; +} + +/* struct IR_rx reference counting */ +static struct IR_rx *get_ir_rx(struct IR *ir) +{ + struct IR_rx *rx; + + spin_lock(&ir->rx_ref_lock); + rx = ir->rx; + if (rx != NULL) + kref_get(&rx->ref); + spin_unlock(&ir->rx_ref_lock); + return rx; +} + +static void destroy_rx_kthread(struct IR_rx *rx, bool ir_devices_lock_held) +{ + /* end up polling thread */ + if (!IS_ERR_OR_NULL(rx->task)) { + kthread_stop(rx->task); + rx->task = NULL; + /* Put the ir ptr that ir_probe() gave to the rx poll thread */ + put_ir_device(rx->ir, ir_devices_lock_held); + } +} + +static void release_ir_rx(struct kref *ref) +{ + struct IR_rx *rx = container_of(ref, struct IR_rx, ref); + struct IR *ir = rx->ir; + + /* + * This release function can't do all the work, as we want + * to keep the rx_ref_lock a spinlock, and killing the poll thread + * and releasing the ir reference can cause a sleep. That work is + * performed by put_ir_rx() + */ + ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; + /* Don't put_ir_device(rx->ir) here; lock can't be freed yet */ + ir->rx = NULL; + /* Don't do the kfree(rx) here; we still need to kill the poll thread */ + return; +} + +static int put_ir_rx(struct IR_rx *rx, bool ir_devices_lock_held) +{ + int released; + struct IR *ir = rx->ir; + + spin_lock(&ir->rx_ref_lock); + released = kref_put(&rx->ref, release_ir_rx); + spin_unlock(&ir->rx_ref_lock); + /* Destroy the rx kthread while not holding the spinlock */ + if (released) { + destroy_rx_kthread(rx, ir_devices_lock_held); + kfree(rx); + /* Make sure we're not still in a poll_table somewhere */ + wake_up_interruptible(&ir->rbuf.wait_poll); + } + /* Do a reference put() for the rx->ir reference, if we released rx */ + if (released) + put_ir_device(ir, ir_devices_lock_held); + return released; +} + +/* struct IR_tx reference counting */ +static struct IR_tx *get_ir_tx(struct IR *ir) +{ + struct IR_tx *tx; + + spin_lock(&ir->tx_ref_lock); + tx = ir->tx; + if (tx != NULL) + kref_get(&tx->ref); + spin_unlock(&ir->tx_ref_lock); + return tx; +} + +static void release_ir_tx(struct kref *ref) +{ + struct IR_tx *tx = container_of(ref, struct IR_tx, ref); + struct IR *ir = tx->ir; + + ir->l.features &= ~LIRC_CAN_SEND_PULSE; + /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */ + ir->tx = NULL; + kfree(tx); +} + +static int put_ir_tx(struct IR_tx *tx, bool ir_devices_lock_held) +{ + int released; + struct IR *ir = tx->ir; + + spin_lock(&ir->tx_ref_lock); + released = kref_put(&tx->ref, release_ir_tx); + spin_unlock(&ir->tx_ref_lock); + /* Do a reference put() for the tx->ir reference, if we released tx */ + if (released) + put_ir_device(ir, ir_devices_lock_held); + return released; +} + static int add_to_buf(struct IR *ir) { __u16 code; @@ -156,23 +329,29 @@ static int add_to_buf(struct IR *ir) int failures = 0; unsigned char sendbuf[1] = { 0 }; struct lirc_buffer *rbuf = ir->l.rbuf; - struct IR_rx *rx = ir->rx; - - if (rx == NULL) - return -ENXIO; + struct IR_rx *rx; + struct IR_tx *tx; if (lirc_buffer_full(rbuf)) { dprintk("buffer overflow\n"); return -EOVERFLOW; } + rx = get_ir_rx(ir); + if (rx == NULL) + return -ENXIO; + + tx = get_ir_tx(ir); + /* * service the device as long as it is returning * data and we have space */ do { - if (kthread_should_stop()) - return -ENODATA; + if (kthread_should_stop()) { + ret = -ENODATA; + break; + } /* * Lock i2c bus for the duration. RX/TX chips interfere so @@ -182,7 +361,8 @@ static int add_to_buf(struct IR *ir) if (kthread_should_stop()) { mutex_unlock(&ir->ir_lock); - return -ENODATA; + ret = -ENODATA; + break; } /* @@ -196,7 +376,7 @@ static int add_to_buf(struct IR *ir) mutex_unlock(&ir->ir_lock); zilog_error("unable to read from the IR chip " "after 3 resets, giving up\n"); - return ret; + break; } /* Looks like the chip crashed, reset it */ @@ -206,20 +386,23 @@ static int add_to_buf(struct IR *ir) set_current_state(TASK_UNINTERRUPTIBLE); if (kthread_should_stop()) { mutex_unlock(&ir->ir_lock); - return -ENODATA; + ret = -ENODATA; + break; } schedule_timeout((100 * HZ + 999) / 1000); - if (ir->tx != NULL) - ir->tx->need_boot = 1; + if (tx != NULL) + tx->need_boot = 1; ++failures; mutex_unlock(&ir->ir_lock); + ret = 0; continue; } if (kthread_should_stop()) { mutex_unlock(&ir->ir_lock); - return -ENODATA; + ret = -ENODATA; + break; } ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); mutex_unlock(&ir->ir_lock); @@ -235,12 +418,17 @@ static int add_to_buf(struct IR *ir) /* key pressed ? */ if (rx->hdpvr_data_fmt) { - if (got_data && (keybuf[0] == 0x80)) - return 0; - else if (got_data && (keybuf[0] == 0x00)) - return -ENODATA; - } else if ((rx->b[0] & 0x80) == 0) - return got_data ? 0 : -ENODATA; + if (got_data && (keybuf[0] == 0x80)) { + ret = 0; + break; + } else if (got_data && (keybuf[0] == 0x00)) { + ret = -ENODATA; + break; + } + } else if ((rx->b[0] & 0x80) == 0) { + ret = got_data ? 0 : -ENODATA; + break; + } /* look what we have */ code = (((__u16)rx->b[0] & 0x7f) << 6) | (rx->b[1] >> 2); @@ -251,9 +439,13 @@ static int add_to_buf(struct IR *ir) /* return it */ lirc_buffer_write(rbuf, codes); ++got_data; + ret = 0; } while (!lirc_buffer_full(rbuf)); - return 0; + if (tx != NULL) + put_ir_tx(tx, false); + put_ir_rx(rx, false); + return ret; } /* @@ -274,14 +466,14 @@ static int lirc_thread(void *arg) dprintk("poll thread started\n"); while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); - /* if device not opened, we can sleep half a second */ if (atomic_read(&ir->open_count) == 0) { schedule_timeout(HZ/2); continue; } + set_current_state(TASK_INTERRUPTIBLE); + /* * This is ~113*2 + 24 + jitter (2*repeat gap + code length). * We use this interval as the chip resets every time you poll @@ -564,7 +756,7 @@ static int fw_load(struct IR_tx *tx) } /* Request codeset data file */ - ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", &tx->c->dev); + ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev); if (ret != 0) { zilog_error("firmware haup-ir-blaster.bin not available " "(%d)\n", ret); @@ -690,45 +882,26 @@ out: return ret; } -/* initialise the IR TX device */ -static int tx_init(struct IR_tx *tx) -{ - int ret; - - /* Load 'firmware' */ - ret = fw_load(tx); - if (ret != 0) - return ret; - - /* Send boot block */ - ret = send_boot_data(tx); - if (ret != 0) - return ret; - tx->need_boot = 0; - - /* Looks good */ - return 0; -} - /* copied from lirc_dev */ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) { struct IR *ir = filep->private_data; - struct IR_rx *rx = ir->rx; + struct IR_rx *rx; struct lirc_buffer *rbuf = ir->l.rbuf; int ret = 0, written = 0; unsigned int m; DECLARE_WAITQUEUE(wait, current); dprintk("read called\n"); - if (rx == NULL) - return -ENODEV; - if (n % rbuf->chunk_size) { dprintk("read result = -EINVAL\n"); return -EINVAL; } + rx = get_ir_rx(ir); + if (rx == NULL) + return -ENXIO; + /* * we add ourselves to the task queue before buffer check * to avoid losing scan code (in case when queue is awaken somewhere @@ -773,6 +946,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) } remove_wait_queue(&rbuf->wait_poll, &wait); + put_ir_rx(rx, false); set_current_state(TASK_RUNNING); dprintk("read result = %d (%s)\n", ret, ret ? "Error" : "OK"); @@ -902,17 +1076,19 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, loff_t *ppos) { struct IR *ir = filep->private_data; - struct IR_tx *tx = ir->tx; + struct IR_tx *tx; size_t i; int failures = 0; - if (tx == NULL) - return -ENODEV; - /* Validate user parameters */ if (n % sizeof(int)) return -EINVAL; + /* Get a struct IR_tx reference */ + tx = get_ir_tx(ir); + if (tx == NULL) + return -ENXIO; + /* Lock i2c bus for the duration */ mutex_lock(&ir->ir_lock); @@ -923,11 +1099,22 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, if (copy_from_user(&command, buf + i, sizeof(command))) { mutex_unlock(&ir->ir_lock); + put_ir_tx(tx, false); return -EFAULT; } /* Send boot data first if required */ if (tx->need_boot == 1) { + /* Make sure we have the 'firmware' loaded, first */ + ret = fw_load(tx); + if (ret != 0) { + mutex_unlock(&ir->ir_lock); + put_ir_tx(tx, false); + if (ret != -ENOMEM) + ret = -EIO; + return ret; + } + /* Prep the chip for transmitting codes */ ret = send_boot_data(tx); if (ret == 0) tx->need_boot = 0; @@ -939,6 +1126,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, (unsigned)command & 0xFFFF); if (ret == -EPROTO) { mutex_unlock(&ir->ir_lock); + put_ir_tx(tx, false); return ret; } } @@ -956,6 +1144,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, zilog_error("unable to send to the IR chip " "after 3 resets, giving up\n"); mutex_unlock(&ir->ir_lock); + put_ir_tx(tx, false); return ret; } set_current_state(TASK_UNINTERRUPTIBLE); @@ -969,6 +1158,9 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, /* Release i2c bus */ mutex_unlock(&ir->ir_lock); + /* Give back our struct IR_tx reference */ + put_ir_tx(tx, false); + /* All looks good */ return n; } @@ -977,12 +1169,13 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, static unsigned int poll(struct file *filep, poll_table *wait) { struct IR *ir = filep->private_data; - struct IR_rx *rx = ir->rx; + struct IR_rx *rx; struct lirc_buffer *rbuf = ir->l.rbuf; unsigned int ret; dprintk("poll called\n"); + rx = get_ir_rx(ir); if (rx == NULL) { /* * Revisit this, if our poll function ever reports writeable @@ -1009,12 +1202,9 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct IR *ir = filep->private_data; int result; - unsigned long mode, features = 0; + unsigned long mode, features; - if (ir->rx != NULL) - features |= LIRC_CAN_REC_LIRCCODE; - if (ir->tx != NULL) - features |= LIRC_CAN_SEND_PULSE; + features = ir->l.features; switch (cmd) { case LIRC_GET_LENGTH: @@ -1060,19 +1250,24 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) return result; } -/* ir_devices_lock must be held */ -static struct IR *find_ir_device_by_minor(unsigned int minor) +static struct IR *get_ir_device_by_minor(unsigned int minor) { struct IR *ir; + struct IR *ret = NULL; - if (list_empty(&ir_devices_list)) - return NULL; + mutex_lock(&ir_devices_lock); - list_for_each_entry(ir, &ir_devices_list, list) - if (ir->l.minor == minor) - return ir; + if (!list_empty(&ir_devices_list)) { + list_for_each_entry(ir, &ir_devices_list, list) { + if (ir->l.minor == minor) { + ret = get_ir_device(ir, true); + break; + } + } + } - return NULL; + mutex_unlock(&ir_devices_lock); + return ret; } /* @@ -1085,9 +1280,7 @@ static int open(struct inode *node, struct file *filep) unsigned int minor = MINOR(node->i_rdev); /* find our IR struct */ - mutex_lock(&ir_devices_lock); - ir = find_ir_device_by_minor(minor); - mutex_unlock(&ir_devices_lock); + ir = get_ir_device_by_minor(minor); if (ir == NULL) return -ENODEV; @@ -1113,6 +1306,7 @@ static int close(struct inode *node, struct file *filep) atomic_dec(&ir->open_count); + put_ir_device(ir, false); return 0; } @@ -1167,78 +1361,23 @@ static struct lirc_driver lirc_template = { .owner = THIS_MODULE, }; -static void destroy_rx_kthread(struct IR_rx *rx) -{ - /* end up polling thread */ - if (rx != NULL && !IS_ERR_OR_NULL(rx->task)) { - kthread_stop(rx->task); - rx->task = NULL; - } -} - -/* ir_devices_lock must be held */ -static int add_ir_device(struct IR *ir) -{ - list_add_tail(&ir->list, &ir_devices_list); - return 0; -} - -/* ir_devices_lock must be held */ -static void del_ir_device(struct IR *ir) -{ - struct IR *p; - - if (list_empty(&ir_devices_list)) - return; - - list_for_each_entry(p, &ir_devices_list, list) - if (p == ir) { - list_del(&p->list); - break; - } -} - static int ir_remove(struct i2c_client *client) { - struct IR *ir = i2c_get_clientdata(client); - - mutex_lock(&ir_devices_lock); - - if (ir == NULL) { - /* We destroyed everything when the first client came through */ - mutex_unlock(&ir_devices_lock); - return 0; + if (strncmp("ir_tx_z8", client->name, 8) == 0) { + struct IR_tx *tx = i2c_get_clientdata(client); + if (tx != NULL) + put_ir_tx(tx, false); + } else if (strncmp("ir_rx_z8", client->name, 8) == 0) { + struct IR_rx *rx = i2c_get_clientdata(client); + if (rx != NULL) + put_ir_rx(rx, false); } - - /* Good-bye LIRC */ - lirc_unregister_driver(ir->l.minor); - - /* Good-bye Rx */ - destroy_rx_kthread(ir->rx); - if (ir->rx != NULL) { - i2c_set_clientdata(ir->rx->c, NULL); - kfree(ir->rx); - } - - /* Good-bye Tx */ - if (ir->tx != NULL) { - i2c_set_clientdata(ir->tx->c, NULL); - kfree(ir->tx); - } - - /* Good-bye IR */ - if (ir->rbuf.fifo_initialized) - lirc_buffer_free(&ir->rbuf); - del_ir_device(ir); - kfree(ir); - - mutex_unlock(&ir_devices_lock); return 0; } /* ir_devices_lock must be held */ -static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter) +static struct IR *get_ir_device_by_adapter(struct i2c_adapter *adapter) { struct IR *ir; @@ -1246,8 +1385,10 @@ static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter) return NULL; list_for_each_entry(ir, &ir_devices_list, list) - if (ir->adapter == adapter) + if (ir->adapter == adapter) { + get_ir_device(ir, true); return ir; + } return NULL; } @@ -1255,6 +1396,8 @@ static struct IR *find_ir_device_by_adapter(struct i2c_adapter *adapter) static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct IR *ir; + struct IR_tx *tx; + struct IR_rx *rx; struct i2c_adapter *adap = client->adapter; int ret; bool tx_probe = false; @@ -1278,133 +1421,166 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) mutex_lock(&ir_devices_lock); /* Use a single struct IR instance for both the Rx and Tx functions */ - ir = find_ir_device_by_adapter(adap); + ir = get_ir_device_by_adapter(adap); if (ir == NULL) { ir = kzalloc(sizeof(struct IR), GFP_KERNEL); if (ir == NULL) { ret = -ENOMEM; goto out_no_ir; } + kref_init(&ir->ref); + /* store for use in ir_probe() again, and open() later on */ INIT_LIST_HEAD(&ir->list); - ret = add_ir_device(ir); - if (ret) - goto out_free_ir; + list_add_tail(&ir->list, &ir_devices_list); ir->adapter = adap; mutex_init(&ir->ir_lock); atomic_set(&ir->open_count, 0); + spin_lock_init(&ir->tx_ref_lock); + spin_lock_init(&ir->rx_ref_lock); /* set lirc_dev stuff */ memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); - ir->l.minor = minor; /* module option */ - ir->l.rbuf = &ir->rbuf; - ir->l.data = ir; - ir->l.dev = &adap->dev; + /* + * FIXME this is a pointer reference to us, but no refcount. + * + * This OK for now, since lirc_dev currently won't touch this + * buffer as we provide our own lirc_fops. + * + * Currently our own lirc_fops rely on this ir->l.rbuf pointer + */ + ir->l.rbuf = &ir->rbuf; + ir->l.dev = &adap->dev; ret = lirc_buffer_init(ir->l.rbuf, ir->l.chunk_size, ir->l.buffer_size); if (ret) - goto out_free_ir; + goto out_put_ir; } if (tx_probe) { + /* Get the IR_rx instance for later, if already allocated */ + rx = get_ir_rx(ir); + /* Set up a struct IR_tx instance */ - ir->tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); - if (ir->tx == NULL) { + tx = kzalloc(sizeof(struct IR_tx), GFP_KERNEL); + if (tx == NULL) { ret = -ENOMEM; - goto out_free_xx; + goto out_put_xx; } + kref_init(&tx->ref); + ir->tx = tx; ir->l.features |= LIRC_CAN_SEND_PULSE; - ir->tx->c = client; - ir->tx->need_boot = 1; - ir->tx->post_tx_ready_poll = + tx->c = client; + tx->need_boot = 1; + tx->post_tx_ready_poll = (id->driver_data & ID_FLAG_HDPVR) ? false : true; + + /* An ir ref goes to the struct IR_tx instance */ + tx->ir = get_ir_device(ir, true); + + /* A tx ref goes to the i2c_client */ + i2c_set_clientdata(client, get_ir_tx(ir)); + + /* + * Load the 'firmware'. We do this before registering with + * lirc_dev, so the first firmware load attempt does not happen + * after a open() or write() call on the device. + * + * Failure here is not deemed catastrophic, so the receiver will + * still be usable. Firmware load will be retried in write(), + * if it is needed. + */ + fw_load(tx); + + /* Proceed only if the Rx client is also ready or not needed */ + if (rx == NULL && !tx_only) { + zilog_info("probe of IR Tx on %s (i2c-%d) done. Waiting" + " on IR Rx.\n", adap->name, adap->nr); + goto out_ok; + } } else { + /* Get the IR_tx instance for later, if already allocated */ + tx = get_ir_tx(ir); + /* Set up a struct IR_rx instance */ - ir->rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL); - if (ir->rx == NULL) { + rx = kzalloc(sizeof(struct IR_rx), GFP_KERNEL); + if (rx == NULL) { ret = -ENOMEM; - goto out_free_xx; + goto out_put_xx; } + kref_init(&rx->ref); + ir->rx = rx; ir->l.features |= LIRC_CAN_REC_LIRCCODE; - ir->rx->c = client; - ir->rx->hdpvr_data_fmt = + rx->c = client; + rx->hdpvr_data_fmt = (id->driver_data & ID_FLAG_HDPVR) ? true : false; - } - i2c_set_clientdata(client, ir); + /* An ir ref goes to the struct IR_rx instance */ + rx->ir = get_ir_device(ir, true); - /* Proceed only if we have the required Tx and Rx clients ready to go */ - if (ir->tx == NULL || - (ir->rx == NULL && !tx_only)) { - zilog_info("probe of IR %s on %s (i2c-%d) done. Waiting on " - "IR %s.\n", tx_probe ? "Tx" : "Rx", adap->name, - adap->nr, tx_probe ? "Rx" : "Tx"); - goto out_ok; - } + /* An rx ref goes to the i2c_client */ + i2c_set_clientdata(client, get_ir_rx(ir)); - /* initialise RX device */ - if (ir->rx != NULL) { - /* try to fire up polling thread */ - ir->rx->task = kthread_run(lirc_thread, ir, - "zilog-rx-i2c-%d", adap->nr); - if (IS_ERR(ir->rx->task)) { - ret = PTR_ERR(ir->rx->task); + /* + * Start the polling thread. + * It will only perform an empty loop around schedule_timeout() + * until we register with lirc_dev and the first user open() + */ + /* An ir ref goes to the new rx polling kthread */ + rx->task = kthread_run(lirc_thread, get_ir_device(ir, true), + "zilog-rx-i2c-%d", adap->nr); + if (IS_ERR(rx->task)) { + ret = PTR_ERR(rx->task); zilog_error("%s: could not start IR Rx polling thread" "\n", __func__); - goto out_free_xx; + /* Failed kthread, so put back the ir ref */ + put_ir_device(ir, true); + /* Failure exit, so put back rx ref from i2c_client */ + i2c_set_clientdata(client, NULL); + put_ir_rx(rx, true); + ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; + goto out_put_xx; + } + + /* Proceed only if the Tx client is also ready */ + if (tx == NULL) { + zilog_info("probe of IR Rx on %s (i2c-%d) done. Waiting" + " on IR Tx.\n", adap->name, adap->nr); + goto out_ok; } } /* register with lirc */ + ir->l.minor = minor; /* module option: user requested minor number */ ir->l.minor = lirc_register_driver(&ir->l); if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) { zilog_error("%s: \"minor\" must be between 0 and %d (%d)!\n", __func__, MAX_IRCTL_DEVICES-1, ir->l.minor); ret = -EBADRQC; - goto out_free_thread; - } - - /* - * if we have the tx device, load the 'firmware'. We do this - * after registering with lirc as otherwise hotplug seems to take - * 10s to create the lirc device. - */ - if (ir->tx != NULL) { - /* Special TX init */ - ret = tx_init(ir->tx); - if (ret != 0) - goto out_unregister; + goto out_put_xx; } +out_ok: + if (rx != NULL) + put_ir_rx(rx, true); + if (tx != NULL) + put_ir_tx(tx, true); + put_ir_device(ir, true); zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n", tx_probe ? "Tx" : "Rx", adap->name, adap->nr); -out_ok: mutex_unlock(&ir_devices_lock); return 0; -out_unregister: - lirc_unregister_driver(ir->l.minor); -out_free_thread: - destroy_rx_kthread(ir->rx); -out_free_xx: - if (ir->rx != NULL) { - if (ir->rx->c != NULL) - i2c_set_clientdata(ir->rx->c, NULL); - kfree(ir->rx); - } - if (ir->tx != NULL) { - if (ir->tx->c != NULL) - i2c_set_clientdata(ir->tx->c, NULL); - kfree(ir->tx); - } - if (ir->rbuf.fifo_initialized) - lirc_buffer_free(&ir->rbuf); -out_free_ir: - del_ir_device(ir); - kfree(ir); +out_put_xx: + if (rx != NULL) + put_ir_rx(rx, true); + if (tx != NULL) + put_ir_tx(tx, true); +out_put_ir: + put_ir_device(ir, true); out_no_ir: zilog_error("%s: probing IR %s on %s (i2c-%d) failed with %d\n", __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, -- cgit v1.2.2 From d6dbd939b97d271766a58a66d69b27023bc90993 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 17 Feb 2011 20:50:38 -0300 Subject: [media] lirc_zilog: Add locking of the i2c_clients when in use Lock the i2c_client pointers and prevent i2c_client removal when lirc_zilog is perfoming a series of operations that require valid i2c_client pointers. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 41 +++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 5df90dbba1c6..5946a9541c43 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -70,7 +70,7 @@ struct IR_rx { struct IR *ir; /* RX device */ - /* FIXME mutex lock access to this pointer */ + struct mutex client_lock; struct i2c_client *c; /* RX polling thread data */ @@ -86,7 +86,7 @@ struct IR_tx { struct IR *ir; /* TX device */ - /* FIXME mutex lock access to this pointer */ + struct mutex client_lock; struct i2c_client *c; /* TX additional actions needed */ @@ -341,6 +341,14 @@ static int add_to_buf(struct IR *ir) if (rx == NULL) return -ENXIO; + /* Ensure our rx->c i2c_client remains valid for the duration */ + mutex_lock(&rx->client_lock); + if (rx->c == NULL) { + mutex_unlock(&rx->client_lock); + put_ir_rx(rx, false); + return -ENXIO; + } + tx = get_ir_tx(ir); /* @@ -442,6 +450,7 @@ static int add_to_buf(struct IR *ir) ret = 0; } while (!lirc_buffer_full(rbuf)); + mutex_unlock(&rx->client_lock); if (tx != NULL) put_ir_tx(tx, false); put_ir_rx(rx, false); @@ -1089,6 +1098,14 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, if (tx == NULL) return -ENXIO; + /* Ensure our tx->c i2c_client remains valid for the duration */ + mutex_lock(&tx->client_lock); + if (tx->c == NULL) { + mutex_unlock(&tx->client_lock); + put_ir_tx(tx, false); + return -ENXIO; + } + /* Lock i2c bus for the duration */ mutex_lock(&ir->ir_lock); @@ -1099,6 +1116,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, if (copy_from_user(&command, buf + i, sizeof(command))) { mutex_unlock(&ir->ir_lock); + mutex_unlock(&tx->client_lock); put_ir_tx(tx, false); return -EFAULT; } @@ -1109,6 +1127,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, ret = fw_load(tx); if (ret != 0) { mutex_unlock(&ir->ir_lock); + mutex_unlock(&tx->client_lock); put_ir_tx(tx, false); if (ret != -ENOMEM) ret = -EIO; @@ -1126,6 +1145,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, (unsigned)command & 0xFFFF); if (ret == -EPROTO) { mutex_unlock(&ir->ir_lock); + mutex_unlock(&tx->client_lock); put_ir_tx(tx, false); return ret; } @@ -1144,6 +1164,7 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, zilog_error("unable to send to the IR chip " "after 3 resets, giving up\n"); mutex_unlock(&ir->ir_lock); + mutex_unlock(&tx->client_lock); put_ir_tx(tx, false); return ret; } @@ -1158,6 +1179,8 @@ static ssize_t write(struct file *filep, const char *buf, size_t n, /* Release i2c bus */ mutex_unlock(&ir->ir_lock); + mutex_unlock(&tx->client_lock); + /* Give back our struct IR_tx reference */ put_ir_tx(tx, false); @@ -1365,12 +1388,20 @@ static int ir_remove(struct i2c_client *client) { if (strncmp("ir_tx_z8", client->name, 8) == 0) { struct IR_tx *tx = i2c_get_clientdata(client); - if (tx != NULL) + if (tx != NULL) { + mutex_lock(&tx->client_lock); + tx->c = NULL; + mutex_unlock(&tx->client_lock); put_ir_tx(tx, false); + } } else if (strncmp("ir_rx_z8", client->name, 8) == 0) { struct IR_rx *rx = i2c_get_clientdata(client); - if (rx != NULL) + if (rx != NULL) { + mutex_lock(&rx->client_lock); + rx->c = NULL; + mutex_unlock(&rx->client_lock); put_ir_rx(rx, false); + } } return 0; } @@ -1472,6 +1503,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->tx = tx; ir->l.features |= LIRC_CAN_SEND_PULSE; + mutex_init(&tx->client_lock); tx->c = client; tx->need_boot = 1; tx->post_tx_ready_poll = @@ -1514,6 +1546,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->rx = rx; ir->l.features |= LIRC_CAN_REC_LIRCCODE; + mutex_init(&rx->client_lock); rx->c = client; rx->hdpvr_data_fmt = (id->driver_data & ID_FLAG_HDPVR) ? true : false; -- cgit v1.2.2 From 4933fc9d72104d66c54620537eb6f43457a6896f Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 17 Feb 2011 21:14:13 -0300 Subject: [media] lirc_zilog: Fix somewhat confusing information messages in ir_probe() The total sequence of messages emitted by the ir_porbe() calls for a transceiver's two i2c_clients was confusing. Clean it up a bit. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 5946a9541c43..407d4b409a8b 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -1595,6 +1595,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = -EBADRQC; goto out_put_xx; } + zilog_info("IR unit on %s (i2c-%d) registered as lirc%d and ready\n", + adap->name, adap->nr, ir->l.minor); out_ok: if (rx != NULL) @@ -1602,7 +1604,7 @@ out_ok: if (tx != NULL) put_ir_tx(tx, true); put_ir_device(ir, true); - zilog_info("probe of IR %s on %s (i2c-%d) done. IR unit ready.\n", + zilog_info("probe of IR %s on %s (i2c-%d) done\n", tx_probe ? "Tx" : "Rx", adap->name, adap->nr); mutex_unlock(&ir_devices_lock); return 0; -- cgit v1.2.2 From aa3f4e446e784372498f009ea37177857f23331e Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Thu, 17 Feb 2011 21:32:06 -0300 Subject: [media] lirc_zilog: Update TODO list based on work completed and revised plans Update the TODO.lirc_zilog based on what has been completed. Also revised the development plan for lirc_zilog to not try and split Tx/Rx for one IR transceiver unit between lirc_zilog and ir-kbd-i2c, since that would be a ref-counting nightmare. Signed-off-by: Andy Walls Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/TODO.lirc_zilog | 51 ++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/TODO.lirc_zilog b/drivers/staging/lirc/TODO.lirc_zilog index 2d0263f07937..a97800a8e127 100644 --- a/drivers/staging/lirc/TODO.lirc_zilog +++ b/drivers/staging/lirc/TODO.lirc_zilog @@ -1,34 +1,33 @@ -1. Both ir-kbd-i2c and lirc_zilog provide support for RX events. -The 'tx_only' lirc_zilog module parameter will allow ir-kbd-i2c -and lirc_zilog to coexist in the kernel, if the user requires such a set-up. -However the IR unit will not work well without coordination between the -two modules. A shared mutex, for transceiver access locking, needs to be -supplied by bridge drivers, in struct IR_i2_init_data, to both ir-kbd-i2c -and lirc_zilog, before they will coexist usefully. This should be fixed -before moving out of staging. - -2. References and locking need careful examination. For cx18 and ivtv PCI -cards, which are not easily "hot unplugged", the imperfect state of reference -counting and locking is acceptable if not correct. For USB connected units -like HD PVR, PVR USB2, HVR-1900, and HVR1950, the likelyhood of an Ooops on -unplug is probably great. Proper reference counting and locking needs to be -implemented before this module is moved out of staging. - -3. The binding between hdpvr and lirc_zilog is currently disabled, -due to an OOPS reported a few years ago when both the hdpvr and cx18 -drivers were loaded in his system. More details can be seen at: - http://www.mail-archive.com/linux-media@vger.kernel.org/msg09163.html -More tests need to be done, in order to fix the reported issue. - -4. In addition to providing a shared mutex for transceiver access -locking, bridge drivers, if able, should provide a chip reset() callback +1. Both ir-kbd-i2c and lirc_zilog provide support for RX events for +the chips supported by lirc_zilog. Before moving lirc_zilog out of staging: + +a. ir-kbd-i2c needs a module parameter added to allow the user to tell + ir-kbd-i2c to ignore Z8 IR units. + +b. lirc_zilog should provide Rx key presses to the rc core like ir-kbd-i2c + does. + + +2. lirc_zilog module ref-counting need examination. It has not been +verified that cdev and lirc_dev will take the proper module references on +lirc_zilog to prevent removal of lirc_zilog when the /dev/lircN device node +is open. + +(The good news is ref-counting of lirc_zilog internal structures appears to be +complete. Testing has shown the cx18 module can be unloaded out from under +irw + lircd + lirc_dev, with the /dev/lirc0 device node open, with no adverse +effects. The cx18 module could then be reloaded and irw properly began +receiving button presses again and ir_send worked without error.) + + +3. Bridge drivers, if able, should provide a chip reset() callback to lirc_zilog via struct IR_i2c_init_data. cx18 and ivtv already have routines -to perform Z8 chip resets via GPIO manipulations. This will allow lirc_zilog +to perform Z8 chip resets via GPIO manipulations. This would allow lirc_zilog to bring the chip back to normal when it hangs, in the same places the original lirc_pvr150 driver code does. This is not strictly needed, so it is not required to move lirc_zilog out of staging. -5. Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed +Note: Both lirc_zilog and ir-kbd-i2c support the Zilog Z8 for IR, as programmed and installed on Hauppauge products. When working on either module, developers must consider at least the following bridge drivers which mention an IR Rx unit at address 0x71 (indicative of a Z8): -- cgit v1.2.2 From 444cc20b3d6141a5fa9a9774a6b710e16af6110d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:36 -0300 Subject: [media] rc/keymaps: use KEY_CAMERA for snapshots On a few places, KEY_MHP were used for snapshots. However, KEY_CAMERA is used for it on all the other keyboards that have a snapshot/Picture button. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/dvb/dvb-usb/digitv.c | 2 +- drivers/media/rc/keymaps/rc-avermedia-m135a.c | 2 +- drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c | 2 +- drivers/media/rc/keymaps/rc-budget-ci-old.c | 3 ++- drivers/media/rc/keymaps/rc-encore-enltv.c | 2 +- drivers/media/rc/keymaps/rc-hauppauge-new.c | 2 +- drivers/media/rc/keymaps/rc-nebula.c | 2 +- drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c | 2 +- 8 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index f2dbce7edb3b..f6344cdd360f 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -176,7 +176,7 @@ static struct rc_map_table rc_map_digitv_table[] = { { 0xaf59, KEY_AUX }, { 0x5f5a, KEY_DVD }, { 0x6f5a, KEY_POWER }, - { 0x9f5a, KEY_MHP }, /* labelled 'Picture' */ + { 0x9f5a, KEY_CAMERA }, /* labelled 'Picture' */ { 0xaf5a, KEY_AUDIO }, { 0x5f65, KEY_INFO }, { 0x6f65, KEY_F13 }, /* 16:9 */ diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index 357fea58a46e..3d2cbe4e5e46 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -108,7 +108,7 @@ static struct rc_map_table avermedia_m135a[] = { { 0x0414, KEY_TEXT }, { 0x0415, KEY_EPG }, { 0x041a, KEY_TV2 }, /* PIP */ - { 0x041b, KEY_MHP }, /* Snapshot */ + { 0x041b, KEY_CAMERA }, /* Snapshot */ { 0x0417, KEY_RECORD }, { 0x0416, KEY_PLAYPAUSE }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c index e694e6eac37e..8cd7f28808bd 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -56,7 +56,7 @@ static struct rc_map_table avermedia_m733a_rm_k6[] = { { 0x0414, KEY_TEXT }, { 0x0415, KEY_EPG }, { 0x041a, KEY_TV2 }, /* PIP */ - { 0x041b, KEY_MHP }, /* Snapshot */ + { 0x041b, KEY_CAMERA }, /* Snapshot */ { 0x0417, KEY_RECORD }, { 0x0416, KEY_PLAYPAUSE }, diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c index 97fc3862f608..2f66e4310d20 100644 --- a/drivers/media/rc/keymaps/rc-budget-ci-old.c +++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c @@ -12,7 +12,8 @@ #include -/* From reading the following remotes: +/* + * From reading the following remotes: * Zenith Universal 7 / TV Mode 807 / VCR Mode 837 * Hauppauge (from NOVA-CI-s box product) * This is a "middle of the road" approach, differences are noted diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index afa4e92284ef..1a0e590b5d21 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -24,7 +24,7 @@ static struct rc_map_table encore_enltv[] = { { 0x1e, KEY_TV }, { 0x00, KEY_VIDEO }, { 0x01, KEY_AUDIO }, /* music */ - { 0x02, KEY_MHP }, /* picture */ + { 0x02, KEY_CAMERA }, /* picture */ { 0x1f, KEY_1 }, { 0x03, KEY_2 }, diff --git a/drivers/media/rc/keymaps/rc-hauppauge-new.c b/drivers/media/rc/keymaps/rc-hauppauge-new.c index bd11da46e56a..b6a12feb0127 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge-new.c +++ b/drivers/media/rc/keymaps/rc-hauppauge-new.c @@ -48,7 +48,7 @@ static struct rc_map_table hauppauge_new[] = { "Multimedia Home Platform" - no "PICTURES" key in input.h */ - { 0x1a, KEY_MHP }, + { 0x1a, KEY_CAMERA }, { 0x1b, KEY_EPG }, /* Guide */ { 0x1c, KEY_TV }, diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 3e6f077eb700..ddae20e9cd96 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -27,7 +27,7 @@ static struct rc_map_table nebula[] = { { 0x0b, KEY_AUX }, { 0x0c, KEY_DVD }, { 0x0d, KEY_POWER }, - { 0x0e, KEY_MHP }, /* labelled 'Picture' */ + { 0x0e, KEY_CAMERA }, /* labelled 'Picture' */ { 0x0f, KEY_AUDIO }, { 0x10, KEY_INFO }, { 0x11, KEY_F13 }, /* 16:9 */ diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c index dfc9b15f43a9..2ca825b4bef2 100644 --- a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c +++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c @@ -51,7 +51,7 @@ static struct rc_map_table rc5_hauppauge_new[] = { "Multimedia Home Platform" - no "PICTURES" key in input.h */ - { 0x1e1a, KEY_MHP }, + { 0x1e1a, KEY_CAMERA }, { 0x1e1b, KEY_EPG }, /* Guide */ { 0x1e1c, KEY_TV }, -- cgit v1.2.2 From 6f9e46b44785eb9cc59e638970e7aa443ff6fe5e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:37 -0300 Subject: [media] rc/keymaps: Use KEY_VIDEO for Video Source Each keyboard map were using a different definition for the Source/Video Source key. Behold Columbus were the only one using KEY_PROPS. As we want to standardize those keys at X11 and at userspace applications, we need to use just one code for it. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/rc-avermedia-dvbt.c | 4 ++-- drivers/media/rc/keymaps/rc-behold-columbus.c | 2 +- drivers/media/rc/keymaps/rc-behold.c | 2 +- drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c | 2 +- drivers/media/rc/keymaps/rc-encore-enltv2.c | 2 +- drivers/media/rc/keymaps/rc-flydvb.c | 4 ++-- drivers/media/rc/keymaps/rc-hauppauge-new.c | 4 ++-- drivers/media/rc/keymaps/rc-kworld-315u.c | 2 +- drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c | 2 +- drivers/media/rc/keymaps/rc-norwood.c | 2 +- drivers/media/rc/keymaps/rc-pctv-sedna.c | 2 +- drivers/media/rc/keymaps/rc-pixelview-mk12.c | 2 +- drivers/media/rc/keymaps/rc-pixelview-new.c | 2 +- drivers/media/rc/keymaps/rc-pixelview.c | 2 +- drivers/media/rc/keymaps/rc-pv951.c | 4 ++-- drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c | 4 ++-- drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c | 2 +- 17 files changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index 3ddb41bc075e..c25809d4c813 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -26,12 +26,12 @@ static struct rc_map_table avermedia_dvbt[] = { { 0x16, KEY_8 }, /* '8' / 'down arrow' */ { 0x36, KEY_9 }, /* '9' */ - { 0x20, KEY_LIST }, /* 'source' */ + { 0x20, KEY_VIDEO }, /* 'source' */ { 0x10, KEY_TEXT }, /* 'teletext' */ { 0x00, KEY_POWER }, /* 'power' */ { 0x04, KEY_AUDIO }, /* 'audio' */ { 0x06, KEY_ZOOM }, /* 'full screen' */ - { 0x18, KEY_VIDEO }, /* 'display' */ + { 0x18, KEY_SWITCHVIDEOMODE }, /* 'display' */ { 0x38, KEY_SEARCH }, /* 'loop' */ { 0x08, KEY_INFO }, /* 'preview' */ { 0x2a, KEY_REWIND }, /* 'backward <<' */ diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index 4b787fa94f08..8bf058f67f0c 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -28,7 +28,7 @@ static struct rc_map_table behold_columbus[] = { * */ { 0x13, KEY_MUTE }, - { 0x11, KEY_PROPS }, + { 0x11, KEY_VIDEO }, { 0x1C, KEY_TUNER }, /* KEY_TV/KEY_RADIO */ { 0x12, KEY_POWER }, diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index 0ee1f149364c..c909a234c776 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -97,7 +97,7 @@ static struct rc_map_table behold[] = { { 0x6b861a, KEY_STOP }, { 0x6b860e, KEY_TEXT }, { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */ - { 0x6b861e, KEY_YELLOW }, /*XXX KEY_SOURCE */ + { 0x6b861e, KEY_VIDEO }, /* 0x1d 0x13 0x19 * * SLEEP PREVIEW DVB * diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c index 43912bd02a9e..82c0200029af 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -32,7 +32,7 @@ static struct rc_map_table dntv_live_dvb_t[] = { { 0x0c, KEY_SEARCH }, /* scan */ { 0x0d, KEY_STOP }, { 0x0e, KEY_PAUSE }, - { 0x0f, KEY_LIST }, /* source */ + { 0x0f, KEY_VIDEO }, /* source */ { 0x10, KEY_MUTE }, { 0x11, KEY_REWIND }, /* backward << */ diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index 7d5b00ed4ff2..b6264f1bc4c1 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -32,7 +32,7 @@ static struct rc_map_table encore_enltv2[] = { { 0x64, KEY_LAST }, /* +100 */ { 0x4e, KEY_AGAIN }, /* Recall */ - { 0x6c, KEY_SWITCHVIDEOMODE }, /* Video Source */ + { 0x6c, KEY_VIDEO }, /* Video Source */ { 0x5e, KEY_MENU }, { 0x56, KEY_SCREEN }, { 0x7a, KEY_SETUP }, diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index aea2f4acf7d8..a8b0f66edaa9 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -37,8 +37,8 @@ static struct rc_map_table flydvb[] = { { 0x13, KEY_CHANNELDOWN }, /* CH- */ { 0x1d, KEY_ENTER }, /* Enter */ - { 0x1a, KEY_MODE }, /* PIP */ - { 0x18, KEY_TUNER }, /* Source */ + { 0x1a, KEY_TV2 }, /* PIP */ + { 0x18, KEY_VIDEO }, /* Source */ { 0x1e, KEY_RECORD }, /* Record/Pause */ { 0x15, KEY_ANGLE }, /* Swap (no label on key) */ diff --git a/drivers/media/rc/keymaps/rc-hauppauge-new.c b/drivers/media/rc/keymaps/rc-hauppauge-new.c index b6a12feb0127..44f3283e15b5 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge-new.c +++ b/drivers/media/rc/keymaps/rc-hauppauge-new.c @@ -42,7 +42,7 @@ static struct rc_map_table hauppauge_new[] = { { 0x15, KEY_DOWN }, { 0x16, KEY_LEFT }, { 0x17, KEY_RIGHT }, - { 0x18, KEY_VIDEO }, /* Videos */ + { 0x18, KEY_VCR }, /* Videos */ { 0x19, KEY_AUDIO }, /* Music */ /* 0x1a: Pictures - presume this means "Multimedia Home Platform" - @@ -56,7 +56,7 @@ static struct rc_map_table hauppauge_new[] = { { 0x1f, KEY_EXIT }, /* back/exit */ { 0x20, KEY_CHANNELUP }, /* channel / program + */ { 0x21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x22, KEY_CHANNEL }, /* source (old black remote) */ + { 0x22, KEY_VIDEO }, /* source (old black remote) */ { 0x24, KEY_PREVIOUSSONG }, /* replay |< */ { 0x25, KEY_ENTER }, /* OK */ { 0x26, KEY_SLEEP }, /* minimize (old black remote) */ diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index 3ce6ef79fc34..7f33edb47244 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -17,7 +17,7 @@ static struct rc_map_table kworld_315u[] = { { 0x6143, KEY_POWER }, - { 0x6101, KEY_TUNER }, /* source */ + { 0x6101, KEY_VIDEO }, /* source */ { 0x610b, KEY_ZOOM }, { 0x6103, KEY_POWER2 }, /* shutdown */ diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index fa8fd0ab94c7..8e9969d1239b 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -62,7 +62,7 @@ static struct rc_map_table msi_tvanywhere_plus[] = { { 0x13, KEY_AGAIN }, /* Recall */ { 0x1e, KEY_POWER }, /* Power */ - { 0x07, KEY_TUNER }, /* Source */ + { 0x07, KEY_VIDEO }, /* Source */ { 0x1c, KEY_SEARCH }, /* Scan */ { 0x18, KEY_MUTE }, /* Mute */ diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index 629ee9d84537..f1c1281fbc17 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -29,7 +29,7 @@ static struct rc_map_table norwood[] = { { 0x28, KEY_8 }, { 0x29, KEY_9 }, - { 0x78, KEY_TUNER }, /* Video Source */ + { 0x78, KEY_VIDEO }, /* Video Source */ { 0x2c, KEY_EXIT }, /* Open/Close software */ { 0x2a, KEY_SELECT }, /* 2 Digit Select */ { 0x69, KEY_AGAIN }, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c index fa5ae5981eb8..7cdef6e6cc0f 100644 --- a/drivers/media/rc/keymaps/rc-pctv-sedna.c +++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c @@ -36,7 +36,7 @@ static struct rc_map_table pctv_sedna[] = { { 0x0e, KEY_STOP }, { 0x0f, KEY_PREVIOUSSONG }, { 0x10, KEY_ZOOM }, - { 0x11, KEY_TUNER }, /* Source */ + { 0x11, KEY_VIDEO }, /* Source */ { 0x12, KEY_POWER }, { 0x13, KEY_MUTE }, { 0x15, KEY_CHANNELDOWN }, diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c index 8d9f664e0a2d..125fc3949c15 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c +++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c @@ -34,7 +34,7 @@ static struct rc_map_table pixelview_mk12[] = { { 0x866b13, KEY_AGAIN }, /* loop */ { 0x866b10, KEY_DIGITS }, /* +100 */ - { 0x866b00, KEY_MEDIA }, /* source */ + { 0x866b00, KEY_VIDEO }, /* source */ { 0x866b18, KEY_MUTE }, /* mute */ { 0x866b19, KEY_CAMERA }, /* snapshot */ { 0x866b1a, KEY_SEARCH }, /* scan */ diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c index 777a70076be2..bd78d6ac1e16 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-new.c +++ b/drivers/media/rc/keymaps/rc-pixelview-new.c @@ -33,7 +33,7 @@ static struct rc_map_table pixelview_new[] = { { 0x3e, KEY_0 }, { 0x1c, KEY_AGAIN }, /* LOOP */ - { 0x3f, KEY_MEDIA }, /* Source */ + { 0x3f, KEY_VIDEO }, /* Source */ { 0x1f, KEY_LAST }, /* +100 */ { 0x1b, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c index 0ec5988916b9..06187e7db446 100644 --- a/drivers/media/rc/keymaps/rc-pixelview.c +++ b/drivers/media/rc/keymaps/rc-pixelview.c @@ -15,7 +15,7 @@ static struct rc_map_table pixelview[] = { { 0x1e, KEY_POWER }, /* power */ - { 0x07, KEY_MEDIA }, /* source */ + { 0x07, KEY_VIDEO }, /* source */ { 0x1c, KEY_SEARCH }, /* scan */ diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c index 83a418de12c6..5e8beee94de4 100644 --- a/drivers/media/rc/keymaps/rc-pv951.c +++ b/drivers/media/rc/keymaps/rc-pv951.c @@ -46,10 +46,10 @@ static struct rc_map_table pv951[] = { { 0x0c, KEY_SEARCH }, /* AUTOSCAN */ /* Not sure what to do with these ones! */ - { 0x0f, KEY_SELECT }, /* SOURCE */ + { 0x0f, KEY_VIDEO }, /* SOURCE */ { 0x0a, KEY_KPPLUS }, /* +100 */ { 0x14, KEY_EQUAL }, /* SYNC */ - { 0x1c, KEY_MEDIA }, /* PC/TV */ + { 0x1c, KEY_TV }, /* PC/TV */ }; static struct rc_map_list pv951_map = { diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c index 2ca825b4bef2..a581c861c25d 100644 --- a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c +++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c @@ -45,7 +45,7 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1e15, KEY_DOWN }, { 0x1e16, KEY_LEFT }, { 0x1e17, KEY_RIGHT }, - { 0x1e18, KEY_VIDEO }, /* Videos */ + { 0x1e18, KEY_VCR }, /* Videos */ { 0x1e19, KEY_AUDIO }, /* Music */ /* 0x1e1a: Pictures - presume this means "Multimedia Home Platform" - @@ -59,7 +59,7 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1e1f, KEY_EXIT }, /* back/exit */ { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x1e22, KEY_CHANNEL }, /* source (old black remote) */ + { 0x1e22, KEY_VIDEO }, /* source (old black remote) */ { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ { 0x1e25, KEY_ENTER }, /* OK */ { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */ diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c index 2d14598592d8..6813d1102118 100644 --- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c +++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c @@ -35,7 +35,7 @@ static struct rc_map_table real_audio_220_32_keys[] = { { 0x15, KEY_CHANNELDOWN}, { 0x16, KEY_ENTER}, - { 0x11, KEY_LIST}, /* Source */ + { 0x11, KEY_VIDEO}, /* Source */ { 0x0d, KEY_AUDIO}, /* stereo */ { 0x0f, KEY_PREVIOUS}, /* Prev */ -- cgit v1.2.2 From d9e9f41c45536b68b14934949104cb40149e94f1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:38 -0300 Subject: [media] rc/keymaps: Fix most KEY_PROG[n] keycodes Those KEY_PROG[n] keys were used on places where the developer didn't know for sure what key should be used. On several cases, using KEY_RED, KEY_GREEN, KEY_YELLOW would be enough. On others, there are specific keys for that already. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c | 6 +++--- drivers/media/rc/keymaps/rc-avermedia-rm-ks.c | 2 +- drivers/media/rc/keymaps/rc-cinergy.c | 2 +- drivers/media/rc/keymaps/rc-encore-enltv.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c index 136d3952dedc..9a8752fdcca1 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -50,9 +50,9 @@ static struct rc_map_table adstech_dvb_t_pci[] = { { 0x13, KEY_TUNER }, /* Live */ { 0x0a, KEY_A }, { 0x12, KEY_B }, - { 0x03, KEY_PROG1 }, /* 1 */ - { 0x01, KEY_PROG2 }, /* 2 */ - { 0x00, KEY_PROG3 }, /* 3 */ + { 0x03, KEY_RED }, /* 1 */ + { 0x01, KEY_GREEN }, /* 2 */ + { 0x00, KEY_YELLOW }, /* 3 */ { 0x06, KEY_DVD }, { 0x48, KEY_AUX }, /* Photo */ { 0x40, KEY_VIDEO }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index f4ca1fff455d..9d68af217d8b 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -31,7 +31,7 @@ static struct rc_map_table avermedia_rm_ks[] = { { 0x0505, KEY_VOLUMEDOWN }, { 0x0506, KEY_MUTE }, { 0x0507, KEY_RIGHT }, - { 0x0508, KEY_PROG1 }, + { 0x0508, KEY_RED }, { 0x0509, KEY_1 }, { 0x050a, KEY_2 }, { 0x050b, KEY_3 }, diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c index 99520ff65b61..cf3a6bfb190c 100644 --- a/drivers/media/rc/keymaps/rc-cinergy.c +++ b/drivers/media/rc/keymaps/rc-cinergy.c @@ -25,7 +25,7 @@ static struct rc_map_table cinergy[] = { { 0x09, KEY_9 }, { 0x0a, KEY_POWER }, - { 0x0b, KEY_PROG1 }, /* app */ + { 0x0b, KEY_MEDIA }, /* app */ { 0x0c, KEY_ZOOM }, /* zoom/fullscreen */ { 0x0d, KEY_CHANNELUP }, /* channel */ { 0x0e, KEY_CHANNELDOWN }, /* channel- */ diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index 1a0e590b5d21..e56ac6e9670a 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -77,7 +77,7 @@ static struct rc_map_table encore_enltv[] = { { 0x50, KEY_SLEEP }, /* shutdown */ { 0x51, KEY_MODE }, /* stereo > main */ { 0x52, KEY_SELECT }, /* stereo > sap */ - { 0x53, KEY_PROG1 }, /* teletext */ + { 0x53, KEY_TEXT }, /* teletext */ { 0x59, KEY_RED }, /* AP1 */ -- cgit v1.2.2 From 04efa85e03b25c5b519e495485d005a8b69ccdab Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:39 -0300 Subject: [media] rc/keymaps: Use KEY_LEFTMETA were pertinent Using xev and testing the "Windows" key on a normal keyboard, it is mapped as KEY_LEFTMETA. So, as this is the standard code for it, use it, instead of a generic, meaningless KEY_PROG1. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/rc-imon-mce.c | 2 +- drivers/media/rc/keymaps/rc-imon-pad.c | 2 +- drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c | 2 +- drivers/media/rc/keymaps/rc-rc6-mce.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c index cb67184e015c..937a81989f00 100644 --- a/drivers/media/rc/keymaps/rc-imon-mce.c +++ b/drivers/media/rc/keymaps/rc-imon-mce.c @@ -111,7 +111,7 @@ static struct rc_map_table imon_mce[] = { { 0x800ff44d, KEY_TITLE }, { 0x800ff40c, KEY_POWER }, - { 0x800ff40d, KEY_PROG1 }, /* Windows MCE button */ + { 0x800ff40d, KEY_LEFTMETA }, /* Windows MCE button */ }; diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c index eef46b73ca7b..63d42bd24c9e 100644 --- a/drivers/media/rc/keymaps/rc-imon-pad.c +++ b/drivers/media/rc/keymaps/rc-imon-pad.c @@ -125,7 +125,7 @@ static struct rc_map_table imon_pad[] = { { 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/ { 0x02000065, KEY_COMPOSE }, /* RightMenu */ { 0x28b715b7, KEY_COMPOSE }, /* RightMenu */ - { 0x2ab195b7, KEY_PROG1 }, /* Go or MultiMon */ + { 0x2ab195b7, KEY_LEFTMETA }, /* Go or MultiMon */ { 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */ }; diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c index e45f0b8759d0..08d183120e41 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -17,7 +17,7 @@ */ static struct rc_map_table kworld_plus_tv_analog[] = { - { 0x0c, KEY_PROG1 }, /* Kworld key */ + { 0x0c, KEY_LEFTMETA }, /* Kworld key */ { 0x16, KEY_CLOSECD }, /* -> ) */ { 0x1d, KEY_POWER2 }, diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index 2f5dc0622b94..8dd519ecc58e 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -30,7 +30,7 @@ static struct rc_map_table rc6_mce[] = { { 0x800f040a, KEY_DELETE }, { 0x800f040b, KEY_ENTER }, { 0x800f040c, KEY_POWER }, /* PC Power */ - { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */ + { 0x800f040d, KEY_LEFTMETA }, /* Windows MCE button */ { 0x800f040e, KEY_MUTE }, { 0x800f040f, KEY_INFO }, -- cgit v1.2.2 From 991bd3c25e8e07960ecd6bcc7079737f83f17c36 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:40 -0300 Subject: [media] dw2102: Use multimedia keys instead of an app-specific mapping This driver uses an app-specific keymap for one of the tables. This is wrong. Instead, use the standard keycodes. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/dvb/dvb-usb/dw2102.c | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 98cf30270f7d..f5b9da18f611 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -1224,8 +1224,8 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) } static struct rc_map_table rc_map_dw210x_table[] = { - { 0xf80a, KEY_Q }, /*power*/ - { 0xf80c, KEY_M }, /*mute*/ + { 0xf80a, KEY_POWER2 }, /*power*/ + { 0xf80c, KEY_MUTE }, /*mute*/ { 0xf811, KEY_1 }, { 0xf812, KEY_2 }, { 0xf813, KEY_3 }, @@ -1236,25 +1236,25 @@ static struct rc_map_table rc_map_dw210x_table[] = { { 0xf818, KEY_8 }, { 0xf819, KEY_9 }, { 0xf810, KEY_0 }, - { 0xf81c, KEY_PAGEUP }, /*ch+*/ - { 0xf80f, KEY_PAGEDOWN }, /*ch-*/ - { 0xf81a, KEY_O }, /*vol+*/ - { 0xf80e, KEY_Z }, /*vol-*/ - { 0xf804, KEY_R }, /*rec*/ - { 0xf809, KEY_D }, /*fav*/ - { 0xf808, KEY_BACKSPACE }, /*rewind*/ - { 0xf807, KEY_A }, /*fast*/ - { 0xf80b, KEY_P }, /*pause*/ - { 0xf802, KEY_ESC }, /*cancel*/ - { 0xf803, KEY_G }, /*tab*/ + { 0xf81c, KEY_CHANNELUP }, /*ch+*/ + { 0xf80f, KEY_CHANNELDOWN }, /*ch-*/ + { 0xf81a, KEY_VOLUMEUP }, /*vol+*/ + { 0xf80e, KEY_VOLUMEDOWN }, /*vol-*/ + { 0xf804, KEY_RECORD }, /*rec*/ + { 0xf809, KEY_FAVORITES }, /*fav*/ + { 0xf808, KEY_REWIND }, /*rewind*/ + { 0xf807, KEY_FASTFORWARD }, /*fast*/ + { 0xf80b, KEY_PAUSE }, /*pause*/ + { 0xf802, KEY_ESC }, /*cancel*/ + { 0xf803, KEY_TAB }, /*tab*/ { 0xf800, KEY_UP }, /*up*/ - { 0xf81f, KEY_ENTER }, /*ok*/ - { 0xf801, KEY_DOWN }, /*down*/ - { 0xf805, KEY_C }, /*cap*/ - { 0xf806, KEY_S }, /*stop*/ - { 0xf840, KEY_F }, /*full*/ - { 0xf81e, KEY_W }, /*tvmode*/ - { 0xf81b, KEY_B }, /*recall*/ + { 0xf81f, KEY_OK }, /*ok*/ + { 0xf801, KEY_DOWN }, /*down*/ + { 0xf805, KEY_CAMERA }, /*cap*/ + { 0xf806, KEY_STOP }, /*stop*/ + { 0xf840, KEY_ZOOM }, /*full*/ + { 0xf81e, KEY_TV }, /*tvmode*/ + { 0xf81b, KEY_LAST }, /*recall*/ }; static struct rc_map_table rc_map_tevii_table[] = { -- cgit v1.2.2 From 76fd93b62322e5e4bfdf2744efe92f0de9e6ac4a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:41 -0300 Subject: [media] opera1: Use multimedia keys instead of an app-specific mapping This driver uses an app-specific keymap for one of the tables. This is wrong. Instead, use the standard keycodes. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/dvb/dvb-usb/opera1.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index 1f1b7d6980a5..7e569f4dd80b 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -342,23 +342,22 @@ static struct rc_map_table rc_map_opera1_table[] = { {0x49b6, KEY_8}, {0x05fa, KEY_9}, {0x45ba, KEY_0}, - {0x09f6, KEY_UP}, /*chanup */ - {0x1be5, KEY_DOWN}, /*chandown */ - {0x5da3, KEY_LEFT}, /*voldown */ - {0x5fa1, KEY_RIGHT}, /*volup */ - {0x07f8, KEY_SPACE}, /*tab */ - {0x1fe1, KEY_ENTER}, /*play ok */ - {0x1be4, KEY_Z}, /*zoom */ - {0x59a6, KEY_M}, /*mute */ - {0x5ba5, KEY_F}, /*tv/f */ - {0x19e7, KEY_R}, /*rec */ - {0x01fe, KEY_S}, /*Stop */ - {0x03fd, KEY_P}, /*pause */ - {0x03fc, KEY_W}, /*<- -> */ - {0x07f9, KEY_C}, /*capture */ - {0x47b9, KEY_Q}, /*exit */ - {0x43bc, KEY_O}, /*power */ - + {0x09f6, KEY_CHANNELUP}, /*chanup */ + {0x1be5, KEY_CHANNELDOWN}, /*chandown */ + {0x5da3, KEY_VOLUMEDOWN}, /*voldown */ + {0x5fa1, KEY_VOLUMEUP}, /*volup */ + {0x07f8, KEY_SPACE}, /*tab */ + {0x1fe1, KEY_OK}, /*play ok */ + {0x1be4, KEY_ZOOM}, /*zoom */ + {0x59a6, KEY_MUTE}, /*mute */ + {0x5ba5, KEY_RADIO}, /*tv/f */ + {0x19e7, KEY_RECORD}, /*rec */ + {0x01fe, KEY_STOP}, /*Stop */ + {0x03fd, KEY_PAUSE}, /*pause */ + {0x03fc, KEY_SCREEN}, /*<- -> */ + {0x07f9, KEY_CAMERA}, /*capture */ + {0x47b9, KEY_ESC}, /*exit */ + {0x43bc, KEY_POWER2}, /*power */ }; static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) -- cgit v1.2.2 From 898a83e9243e2398e863887b36476c3cc227074a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:42 -0300 Subject: [media] a800: Fix a few wrong IR key assignments Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/dvb/dvb-usb/a800.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c index 53b93a4b6f8a..f8e9bf116f21 100644 --- a/drivers/media/dvb/dvb-usb/a800.c +++ b/drivers/media/dvb/dvb-usb/a800.c @@ -38,8 +38,8 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr } static struct rc_map_table rc_map_a800_table[] = { - { 0x0201, KEY_PROG1 }, /* SOURCE */ - { 0x0200, KEY_POWER }, /* POWER */ + { 0x0201, KEY_MODE }, /* SOURCE */ + { 0x0200, KEY_POWER2 }, /* POWER */ { 0x0205, KEY_1 }, /* 1 */ { 0x0206, KEY_2 }, /* 2 */ { 0x0207, KEY_3 }, /* 3 */ @@ -52,8 +52,8 @@ static struct rc_map_table rc_map_a800_table[] = { { 0x0212, KEY_LEFT }, /* L / DISPLAY */ { 0x0211, KEY_0 }, /* 0 */ { 0x0213, KEY_RIGHT }, /* R / CH RTN */ - { 0x0217, KEY_PROG2 }, /* SNAP SHOT */ - { 0x0210, KEY_PROG3 }, /* 16-CH PREV */ + { 0x0217, KEY_CAMERA }, /* SNAP SHOT */ + { 0x0210, KEY_LAST }, /* 16-CH PREV */ { 0x021e, KEY_VOLUMEDOWN }, /* VOL DOWN */ { 0x020c, KEY_ZOOM }, /* FULL SCREEN */ { 0x021f, KEY_VOLUMEUP }, /* VOL UP */ -- cgit v1.2.2 From 7f961c6989a98c10faea76a39228a63624f10690 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:43 -0300 Subject: [media] rc-winfast: Fix the keycode tables One of the remotes has a picture available at: http://lirc.sourceforge.net/remotes/leadtek/Y04G0004.jpg As there's one variant with a set direction keys plus vol/chann keys, and the same table is used for both models, change it to represent all keys, avoiding the usage of weird function keys. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/rc-winfast.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c index 2747db43b70c..0062ca291959 100644 --- a/drivers/media/rc/keymaps/rc-winfast.c +++ b/drivers/media/rc/keymaps/rc-winfast.c @@ -27,15 +27,15 @@ static struct rc_map_table winfast[] = { { 0x0e, KEY_8 }, { 0x0f, KEY_9 }, - { 0x00, KEY_POWER }, + { 0x00, KEY_POWER2 }, { 0x1b, KEY_AUDIO }, /* Audio Source */ { 0x02, KEY_TUNER }, /* TV/FM, not on Y0400052 */ { 0x1e, KEY_VIDEO }, /* Video Source */ { 0x16, KEY_INFO }, /* Display information */ - { 0x04, KEY_VOLUMEUP }, - { 0x08, KEY_VOLUMEDOWN }, - { 0x0c, KEY_CHANNELUP }, - { 0x10, KEY_CHANNELDOWN }, + { 0x04, KEY_LEFT }, + { 0x08, KEY_RIGHT }, + { 0x0c, KEY_UP }, + { 0x10, KEY_DOWN }, { 0x03, KEY_ZOOM }, /* fullscreen */ { 0x1f, KEY_TEXT }, /* closed caption/teletext */ { 0x20, KEY_SLEEP }, @@ -47,7 +47,7 @@ static struct rc_map_table winfast[] = { { 0x2e, KEY_BLUE }, { 0x18, KEY_KPPLUS }, /* fine tune + , not on Y040052 */ { 0x19, KEY_KPMINUS }, /* fine tune - , not on Y040052 */ - { 0x2a, KEY_MEDIA }, /* PIP (Picture in picture */ + { 0x2a, KEY_TV2 }, /* PIP (Picture in picture */ { 0x21, KEY_DOT }, { 0x13, KEY_ENTER }, { 0x11, KEY_LAST }, /* Recall (last channel */ @@ -57,7 +57,7 @@ static struct rc_map_table winfast[] = { { 0x25, KEY_TIME }, /* Time Shifting */ { 0x26, KEY_STOP }, { 0x27, KEY_RECORD }, - { 0x28, KEY_SAVE }, /* Screenshot */ + { 0x28, KEY_CAMERA }, /* Screenshot */ { 0x2f, KEY_MENU }, { 0x30, KEY_CANCEL }, { 0x31, KEY_CHANNEL }, /* Channel Surf */ @@ -70,10 +70,10 @@ static struct rc_map_table winfast[] = { { 0x38, KEY_DVD }, { 0x1a, KEY_MODE}, /* change to MCE mode on Y04G0051 */ - { 0x3e, KEY_F21 }, /* MCE +VOL, on Y04G0033 */ - { 0x3a, KEY_F22 }, /* MCE -VOL, on Y04G0033 */ - { 0x3b, KEY_F23 }, /* MCE +CH, on Y04G0033 */ - { 0x3f, KEY_F24 } /* MCE -CH, on Y04G0033 */ + { 0x3e, KEY_VOLUMEUP }, /* MCE +VOL, on Y04G0033 */ + { 0x3a, KEY_VOLUMEDOWN }, /* MCE -VOL, on Y04G0033 */ + { 0x3b, KEY_CHANNELUP }, /* MCE +CH, on Y04G0033 */ + { 0x3f, KEY_CHANNELDOWN } /* MCE -CH, on Y04G0033 */ }; static struct rc_map_list winfast_map = { -- cgit v1.2.2 From 0684f5b0fc2b543287abad03fc40e65d5e89d1ef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:43 -0300 Subject: [media] rc-rc5-hauppauge-new: Add the old control to the table Adds the old grey remote controller to Hauppauge table. Hans borrowed me an old gray Hauppauge RC. Thanks to that, we can fix the RC5 table for Hauppauge. Thanks-to: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c | 56 ++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c index a581c861c25d..dcbf3bddc826 100644 --- a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c +++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c @@ -20,6 +20,10 @@ */ static struct rc_map_table rc5_hauppauge_new[] = { + /* + * Remote Controller Hauppauge Gray found on modern devices + * Keycodes start with address = 0x1e + */ /* Keys 0 to 9 */ { 0x1e00, KEY_0 }, { 0x1e01, KEY_1 }, @@ -76,7 +80,57 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1e3c, KEY_ZOOM }, /* full */ { 0x1e3d, KEY_POWER }, /* system power (green button) */ - /* Keycodes for DSR-0112 remote bundled with Haupauge MiniStick */ + /* + * Old Remote Controller Hauppauge Gray with a golden screen + * Keycodes start with address = 0x1d + */ + { 0x1f3d, KEY_POWER2 }, /* system power (green button) */ + { 0x1f3b, KEY_SELECT }, /* GO */ + + /* Keys 0 to 9 */ + { 0x1f00, KEY_0 }, + { 0x1f01, KEY_1 }, + { 0x1f02, KEY_2 }, + { 0x1f03, KEY_3 }, + { 0x1f04, KEY_4 }, + { 0x1f05, KEY_5 }, + { 0x1f06, KEY_6 }, + { 0x1f07, KEY_7 }, + { 0x1f08, KEY_8 }, + { 0x1f09, KEY_9 }, + + { 0x1f1f, KEY_EXIT }, /* back/exit */ + { 0x1f0d, KEY_MENU }, + + { 0x1f10, KEY_VOLUMEUP }, + { 0x1f11, KEY_VOLUMEDOWN }, + { 0x1f20, KEY_CHANNELUP }, /* channel / program + */ + { 0x1f21, KEY_CHANNELDOWN }, /* channel / program - */ + { 0x1f25, KEY_ENTER }, /* OK */ + + { 0x1f0b, KEY_RED }, /* red button */ + { 0x1f2e, KEY_GREEN }, /* green button */ + { 0x1f38, KEY_YELLOW }, /* yellow key */ + { 0x1f29, KEY_BLUE }, /* blue key */ + + { 0x1f0f, KEY_MUTE }, + { 0x1f0c, KEY_RADIO }, /* There's no indicator on this key */ + { 0x1f3c, KEY_ZOOM }, /* full */ + + { 0x1f32, KEY_REWIND }, /* backward << */ + { 0x1f35, KEY_PLAY }, + { 0x1f34, KEY_FASTFORWARD }, /* forward >> */ + + { 0x1f37, KEY_RECORD }, /* recording */ + { 0x1f36, KEY_STOP }, + { 0x1f30, KEY_PAUSE }, /* pause */ + + { 0x1f24, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x1f1e, KEY_NEXTSONG }, /* skip >| */ + + /* + * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick + */ { 0x1d00, KEY_0 }, { 0x1d01, KEY_1 }, { 0x1d02, KEY_2 }, -- cgit v1.2.2 From 9890a9edc8b8bba6d710499afb70e981e0b0dfae Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:44 -0300 Subject: [media] rc-rc5-hauppauge-new: Add support for the old Black RC Hans borrowed me an old Black Hauppauge RC. Thanks to that, we can fix the RC5 table for Hauppauge. Thanks-to: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c | 36 ++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c index dcbf3bddc826..4106008c7f98 100644 --- a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c +++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c @@ -82,7 +82,7 @@ static struct rc_map_table rc5_hauppauge_new[] = { /* * Old Remote Controller Hauppauge Gray with a golden screen - * Keycodes start with address = 0x1d + * Keycodes start with address = 0x1f */ { 0x1f3d, KEY_POWER2 }, /* system power (green button) */ { 0x1f3b, KEY_SELECT }, /* GO */ @@ -130,6 +130,7 @@ static struct rc_map_table rc5_hauppauge_new[] = { /* * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick + * Keycodes start with address = 0x1d */ { 0x1d00, KEY_0 }, { 0x1d01, KEY_1 }, @@ -167,6 +168,39 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1d3b, KEY_GOTO }, { 0x1d3d, KEY_POWER }, { 0x1d3f, KEY_HOME }, + + /* + * Keycodes for the old Black Remote Controller + * This one also uses RC-5 protocol + * Keycodes start with address = 0x00 + */ + { 0x001f, KEY_TV }, + { 0x0020, KEY_CHANNELUP }, + { 0x000c, KEY_RADIO }, + + { 0x0011, KEY_VOLUMEDOWN }, + { 0x002e, KEY_ZOOM }, /* full screen */ + { 0x0010, KEY_VOLUMEUP }, + + { 0x000d, KEY_MUTE }, + { 0x0021, KEY_CHANNELDOWN }, + { 0x0022, KEY_VIDEO }, /* source */ + + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, + { 0x0003, KEY_3 }, + + { 0x0004, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0006, KEY_6 }, + + { 0x0007, KEY_7 }, + { 0x0008, KEY_8 }, + { 0x0009, KEY_9 }, + + { 0x001e, KEY_RED }, /* Reserved */ + { 0x0000, KEY_0 }, + { 0x0026, KEY_SLEEP }, /* Minimize */ }; static struct rc_map_list rc5_hauppauge_new_map = { -- cgit v1.2.2 From 0548757419c974d8c0851c13279b2c89a12b2978 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:45 -0300 Subject: [media] rc-rc5-hauppauge-new: Fix Hauppauge Grey mapping The keys for the old black were messed with the ones for the hauppauge grey. Fix it. Also, fixes some keycodes and order the keys according with the way they appear inside the remote controller. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c | 88 +++++++++++++------------ 1 file changed, 47 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c index 4106008c7f98..cb312dae6fac 100644 --- a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c +++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c @@ -24,61 +24,67 @@ static struct rc_map_table rc5_hauppauge_new[] = { * Remote Controller Hauppauge Gray found on modern devices * Keycodes start with address = 0x1e */ - /* Keys 0 to 9 */ - { 0x1e00, KEY_0 }, + + { 0x1e3b, KEY_SELECT }, /* GO / house symbol */ + { 0x1e3d, KEY_POWER2 }, /* system power (green button) */ + + { 0x1e1c, KEY_TV }, + { 0x1e18, KEY_VIDEO }, /* Videos */ + { 0x1e19, KEY_AUDIO }, /* Music */ + { 0x1e1a, KEY_CAMERA }, /* Pictures */ + + { 0x1e1b, KEY_EPG }, /* Guide */ + { 0x1e0c, KEY_RADIO }, + + { 0x1e14, KEY_UP }, + { 0x1e15, KEY_DOWN }, + { 0x1e16, KEY_LEFT }, + { 0x1e17, KEY_RIGHT }, + { 0x1e25, KEY_OK }, /* OK */ + + { 0x1e1f, KEY_EXIT }, /* back/exit */ + { 0x1e0d, KEY_MENU }, + + { 0x1e10, KEY_VOLUMEUP }, + { 0x1e11, KEY_VOLUMEDOWN }, + + { 0x1e12, KEY_PREVIOUS }, /* previous channel */ + { 0x1e0f, KEY_MUTE }, + + { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ + { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ + + { 0x1e37, KEY_RECORD }, /* recording */ + { 0x1e36, KEY_STOP }, + + { 0x1e32, KEY_REWIND }, /* backward << */ + { 0x1e35, KEY_PLAY }, + { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ + + { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x1e30, KEY_PAUSE }, /* pause */ + { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ + { 0x1e01, KEY_1 }, { 0x1e02, KEY_2 }, { 0x1e03, KEY_3 }, + { 0x1e04, KEY_4 }, { 0x1e05, KEY_5 }, { 0x1e06, KEY_6 }, + { 0x1e07, KEY_7 }, { 0x1e08, KEY_8 }, { 0x1e09, KEY_9 }, { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x1e0b, KEY_RED }, /* red button */ - { 0x1e0c, KEY_RADIO }, - { 0x1e0d, KEY_MENU }, - { 0x1e0e, KEY_SUBTITLE }, /* also the # key */ - { 0x1e0f, KEY_MUTE }, - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - { 0x1e12, KEY_PREVIOUS }, /* previous channel */ - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e18, KEY_VCR }, /* Videos */ - { 0x1e19, KEY_AUDIO }, /* Music */ - /* 0x1e1a: Pictures - presume this means - "Multimedia Home Platform" - - no "PICTURES" key in input.h - */ - { 0x1e1a, KEY_CAMERA }, + { 0x1e00, KEY_0 }, + { 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */ - { 0x1e1b, KEY_EPG }, /* Guide */ - { 0x1e1c, KEY_TV }, - { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ - { 0x1e1f, KEY_EXIT }, /* back/exit */ - { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ - { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x1e22, KEY_VIDEO }, /* source (old black remote) */ - { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x1e25, KEY_ENTER }, /* OK */ - { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */ - { 0x1e29, KEY_BLUE }, /* blue key */ + { 0x1e0b, KEY_RED }, /* red button */ { 0x1e2e, KEY_GREEN }, /* green button */ - { 0x1e30, KEY_PAUSE }, /* pause */ - { 0x1e32, KEY_REWIND }, /* backward << */ - { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ - { 0x1e35, KEY_PLAY }, - { 0x1e36, KEY_STOP }, - { 0x1e37, KEY_RECORD }, /* recording */ { 0x1e38, KEY_YELLOW }, /* yellow key */ - { 0x1e3b, KEY_SELECT }, /* top right button */ - { 0x1e3c, KEY_ZOOM }, /* full */ - { 0x1e3d, KEY_POWER }, /* system power (green button) */ + { 0x1e29, KEY_BLUE }, /* blue key */ /* * Old Remote Controller Hauppauge Gray with a golden screen -- cgit v1.2.2 From 15195d3a83b59f0ca3bed52cbe5524042ce13fd6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:47 -0300 Subject: [media] rc/keymaps: Rename Hauppauge table as rc-hauppauge There are two "hauppauge-new" keymaps, one with protocol unknown, and the other with the protocol marked accordingly. However, both tables are miss-named. Also, the old rc-hauppauge-new is broken, as it mixes three different controllers as if they were just one. This patch solves half of the problem by renaming the correct keycode table as just rc-hauppauge. This table contains the codes for the four different types of remote controllers found on Hauppauge cards, properly mapped with their different addresses. create mode 100644 drivers/media/rc/keymaps/rc-hauppauge.c delete mode 100644 drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c [Jarod: fix up RC_MAP_HAUPPAUGE defines] Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/dvb/siano/sms-cards.c | 2 +- drivers/media/rc/keymaps/Makefile | 2 +- drivers/media/rc/keymaps/rc-hauppauge.c | 241 ++++++++++++++++++++++++ drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c | 235 ----------------------- drivers/media/rc/mceusb.c | 2 +- drivers/media/video/cx23885/cx23885-input.c | 2 +- drivers/media/video/em28xx/em28xx-cards.c | 4 +- 7 files changed, 247 insertions(+), 241 deletions(-) create mode 100644 drivers/media/rc/keymaps/rc-hauppauge.c delete mode 100644 drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c (limited to 'drivers') diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c index 25b43e587fa6..af121db88ea0 100644 --- a/drivers/media/dvb/siano/sms-cards.c +++ b/drivers/media/dvb/siano/sms-cards.c @@ -64,7 +64,7 @@ static struct sms_board sms_boards[] = { .type = SMS_NOVA_B0, .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", - .rc_codes = RC_MAP_RC5_HAUPPAUGE_NEW, + .rc_codes = RC_MAP_HAUPPAUGE, .board_cfg.leds_power = 26, .board_cfg.led0 = 27, .board_cfg.led1 = 28, diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index cb721216571c..1f446f99b61f 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -68,7 +68,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-proteus-2309.o \ rc-purpletv.o \ rc-pv951.o \ - rc-rc5-hauppauge-new.o \ + rc-hauppauge.o \ rc-rc5-tv.o \ rc-rc6-mce.o \ rc-real-audio-220-32-keys.o \ diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c new file mode 100644 index 000000000000..cd3db7779772 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -0,0 +1,241 @@ +/* rc-hauppauge.c - Keytable for Hauppauge Remote Controllers + * + * keymap imported from ir-keymaps.c + * + * This map currently contains the code for four different RCs: + * - New Hauppauge Gray; + * - Old Hauppauge Gray (with a golden screen for media keys); + * - Hauppauge Black; + * - DSR-0112 remote bundled with Haupauge MiniStick. + * + * Copyright (c) 2010-2011 by Mauro Carvalho Chehab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +/* + * Hauppauge:the newer, gray remotes (seems there are multiple + * slightly different versions), shipped with cx88+ivtv cards. + * + * This table contains the complete RC5 code, instead of just the data part + */ + +static struct rc_map_table rc5_hauppauge_new[] = { + /* + * Remote Controller Hauppauge Gray found on modern devices + * Keycodes start with address = 0x1e + */ + + { 0x1e3b, KEY_SELECT }, /* GO / house symbol */ + { 0x1e3d, KEY_POWER2 }, /* system power (green button) */ + + { 0x1e1c, KEY_TV }, + { 0x1e18, KEY_VIDEO }, /* Videos */ + { 0x1e19, KEY_AUDIO }, /* Music */ + { 0x1e1a, KEY_CAMERA }, /* Pictures */ + + { 0x1e1b, KEY_EPG }, /* Guide */ + { 0x1e0c, KEY_RADIO }, + + { 0x1e14, KEY_UP }, + { 0x1e15, KEY_DOWN }, + { 0x1e16, KEY_LEFT }, + { 0x1e17, KEY_RIGHT }, + { 0x1e25, KEY_OK }, /* OK */ + + { 0x1e1f, KEY_EXIT }, /* back/exit */ + { 0x1e0d, KEY_MENU }, + + { 0x1e10, KEY_VOLUMEUP }, + { 0x1e11, KEY_VOLUMEDOWN }, + + { 0x1e12, KEY_PREVIOUS }, /* previous channel */ + { 0x1e0f, KEY_MUTE }, + + { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ + { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ + + { 0x1e37, KEY_RECORD }, /* recording */ + { 0x1e36, KEY_STOP }, + + { 0x1e32, KEY_REWIND }, /* backward << */ + { 0x1e35, KEY_PLAY }, + { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ + + { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x1e30, KEY_PAUSE }, /* pause */ + { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ + + { 0x1e01, KEY_1 }, + { 0x1e02, KEY_2 }, + { 0x1e03, KEY_3 }, + + { 0x1e04, KEY_4 }, + { 0x1e05, KEY_5 }, + { 0x1e06, KEY_6 }, + + { 0x1e07, KEY_7 }, + { 0x1e08, KEY_8 }, + { 0x1e09, KEY_9 }, + + { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ + { 0x1e00, KEY_0 }, + { 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */ + + { 0x1e0b, KEY_RED }, /* red button */ + { 0x1e2e, KEY_GREEN }, /* green button */ + { 0x1e38, KEY_YELLOW }, /* yellow key */ + { 0x1e29, KEY_BLUE }, /* blue key */ + + /* + * Old Remote Controller Hauppauge Gray with a golden screen + * Keycodes start with address = 0x1f + */ + { 0x1f3d, KEY_POWER2 }, /* system power (green button) */ + { 0x1f3b, KEY_SELECT }, /* GO */ + + /* Keys 0 to 9 */ + { 0x1f00, KEY_0 }, + { 0x1f01, KEY_1 }, + { 0x1f02, KEY_2 }, + { 0x1f03, KEY_3 }, + { 0x1f04, KEY_4 }, + { 0x1f05, KEY_5 }, + { 0x1f06, KEY_6 }, + { 0x1f07, KEY_7 }, + { 0x1f08, KEY_8 }, + { 0x1f09, KEY_9 }, + + { 0x1f1f, KEY_EXIT }, /* back/exit */ + { 0x1f0d, KEY_MENU }, + + { 0x1f10, KEY_VOLUMEUP }, + { 0x1f11, KEY_VOLUMEDOWN }, + { 0x1f20, KEY_CHANNELUP }, /* channel / program + */ + { 0x1f21, KEY_CHANNELDOWN }, /* channel / program - */ + { 0x1f25, KEY_ENTER }, /* OK */ + + { 0x1f0b, KEY_RED }, /* red button */ + { 0x1f2e, KEY_GREEN }, /* green button */ + { 0x1f38, KEY_YELLOW }, /* yellow key */ + { 0x1f29, KEY_BLUE }, /* blue key */ + + { 0x1f0f, KEY_MUTE }, + { 0x1f0c, KEY_RADIO }, /* There's no indicator on this key */ + { 0x1f3c, KEY_ZOOM }, /* full */ + + { 0x1f32, KEY_REWIND }, /* backward << */ + { 0x1f35, KEY_PLAY }, + { 0x1f34, KEY_FASTFORWARD }, /* forward >> */ + + { 0x1f37, KEY_RECORD }, /* recording */ + { 0x1f36, KEY_STOP }, + { 0x1f30, KEY_PAUSE }, /* pause */ + + { 0x1f24, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x1f1e, KEY_NEXTSONG }, /* skip >| */ + + /* + * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick + * Keycodes start with address = 0x1d + */ + { 0x1d00, KEY_0 }, + { 0x1d01, KEY_1 }, + { 0x1d02, KEY_2 }, + { 0x1d03, KEY_3 }, + { 0x1d04, KEY_4 }, + { 0x1d05, KEY_5 }, + { 0x1d06, KEY_6 }, + { 0x1d07, KEY_7 }, + { 0x1d08, KEY_8 }, + { 0x1d09, KEY_9 }, + { 0x1d0a, KEY_TEXT }, + { 0x1d0d, KEY_MENU }, + { 0x1d0f, KEY_MUTE }, + { 0x1d10, KEY_VOLUMEUP }, + { 0x1d11, KEY_VOLUMEDOWN }, + { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */ + { 0x1d14, KEY_UP }, + { 0x1d15, KEY_DOWN }, + { 0x1d16, KEY_LEFT }, + { 0x1d17, KEY_RIGHT }, + { 0x1d1c, KEY_TV }, + { 0x1d1e, KEY_NEXT }, /* >| */ + { 0x1d1f, KEY_EXIT }, + { 0x1d20, KEY_CHANNELUP }, + { 0x1d21, KEY_CHANNELDOWN }, + { 0x1d24, KEY_LAST }, /* <| */ + { 0x1d25, KEY_OK }, + { 0x1d30, KEY_PAUSE }, + { 0x1d32, KEY_REWIND }, + { 0x1d34, KEY_FASTFORWARD }, + { 0x1d35, KEY_PLAY }, + { 0x1d36, KEY_STOP }, + { 0x1d37, KEY_RECORD }, + { 0x1d3b, KEY_GOTO }, + { 0x1d3d, KEY_POWER }, + { 0x1d3f, KEY_HOME }, + + /* + * Keycodes for the old Black Remote Controller + * This one also uses RC-5 protocol + * Keycodes start with address = 0x00 + */ + { 0x001f, KEY_TV }, + { 0x0020, KEY_CHANNELUP }, + { 0x000c, KEY_RADIO }, + + { 0x0011, KEY_VOLUMEDOWN }, + { 0x002e, KEY_ZOOM }, /* full screen */ + { 0x0010, KEY_VOLUMEUP }, + + { 0x000d, KEY_MUTE }, + { 0x0021, KEY_CHANNELDOWN }, + { 0x0022, KEY_VIDEO }, /* source */ + + { 0x0001, KEY_1 }, + { 0x0002, KEY_2 }, + { 0x0003, KEY_3 }, + + { 0x0004, KEY_4 }, + { 0x0005, KEY_5 }, + { 0x0006, KEY_6 }, + + { 0x0007, KEY_7 }, + { 0x0008, KEY_8 }, + { 0x0009, KEY_9 }, + + { 0x001e, KEY_RED }, /* Reserved */ + { 0x0000, KEY_0 }, + { 0x0026, KEY_SLEEP }, /* Minimize */ +}; + +static struct rc_map_list rc5_hauppauge_new_map = { + .map = { + .scan = rc5_hauppauge_new, + .size = ARRAY_SIZE(rc5_hauppauge_new), + .rc_type = RC_TYPE_RC5, + .name = RC_MAP_HAUPPAUGE, + } +}; + +static int __init init_rc_map_rc5_hauppauge_new(void) +{ + return rc_map_register(&rc5_hauppauge_new_map); +} + +static void __exit exit_rc_map_rc5_hauppauge_new(void) +{ + rc_map_unregister(&rc5_hauppauge_new_map); +} + +module_init(init_rc_map_rc5_hauppauge_new) +module_exit(exit_rc_map_rc5_hauppauge_new) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); diff --git a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c deleted file mode 100644 index cb312dae6fac..000000000000 --- a/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c +++ /dev/null @@ -1,235 +0,0 @@ -/* rc5-hauppauge-new.h - Keytable for rc5_hauppauge_new Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include - -/* - * Hauppauge:the newer, gray remotes (seems there are multiple - * slightly different versions), shipped with cx88+ivtv cards. - * - * This table contains the complete RC5 code, instead of just the data part - */ - -static struct rc_map_table rc5_hauppauge_new[] = { - /* - * Remote Controller Hauppauge Gray found on modern devices - * Keycodes start with address = 0x1e - */ - - { 0x1e3b, KEY_SELECT }, /* GO / house symbol */ - { 0x1e3d, KEY_POWER2 }, /* system power (green button) */ - - { 0x1e1c, KEY_TV }, - { 0x1e18, KEY_VIDEO }, /* Videos */ - { 0x1e19, KEY_AUDIO }, /* Music */ - { 0x1e1a, KEY_CAMERA }, /* Pictures */ - - { 0x1e1b, KEY_EPG }, /* Guide */ - { 0x1e0c, KEY_RADIO }, - - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e25, KEY_OK }, /* OK */ - - { 0x1e1f, KEY_EXIT }, /* back/exit */ - { 0x1e0d, KEY_MENU }, - - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - - { 0x1e12, KEY_PREVIOUS }, /* previous channel */ - { 0x1e0f, KEY_MUTE }, - - { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ - { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ - - { 0x1e37, KEY_RECORD }, /* recording */ - { 0x1e36, KEY_STOP }, - - { 0x1e32, KEY_REWIND }, /* backward << */ - { 0x1e35, KEY_PLAY }, - { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ - - { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x1e30, KEY_PAUSE }, /* pause */ - { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ - - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, - - { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x1e00, KEY_0 }, - { 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */ - - { 0x1e0b, KEY_RED }, /* red button */ - { 0x1e2e, KEY_GREEN }, /* green button */ - { 0x1e38, KEY_YELLOW }, /* yellow key */ - { 0x1e29, KEY_BLUE }, /* blue key */ - - /* - * Old Remote Controller Hauppauge Gray with a golden screen - * Keycodes start with address = 0x1f - */ - { 0x1f3d, KEY_POWER2 }, /* system power (green button) */ - { 0x1f3b, KEY_SELECT }, /* GO */ - - /* Keys 0 to 9 */ - { 0x1f00, KEY_0 }, - { 0x1f01, KEY_1 }, - { 0x1f02, KEY_2 }, - { 0x1f03, KEY_3 }, - { 0x1f04, KEY_4 }, - { 0x1f05, KEY_5 }, - { 0x1f06, KEY_6 }, - { 0x1f07, KEY_7 }, - { 0x1f08, KEY_8 }, - { 0x1f09, KEY_9 }, - - { 0x1f1f, KEY_EXIT }, /* back/exit */ - { 0x1f0d, KEY_MENU }, - - { 0x1f10, KEY_VOLUMEUP }, - { 0x1f11, KEY_VOLUMEDOWN }, - { 0x1f20, KEY_CHANNELUP }, /* channel / program + */ - { 0x1f21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x1f25, KEY_ENTER }, /* OK */ - - { 0x1f0b, KEY_RED }, /* red button */ - { 0x1f2e, KEY_GREEN }, /* green button */ - { 0x1f38, KEY_YELLOW }, /* yellow key */ - { 0x1f29, KEY_BLUE }, /* blue key */ - - { 0x1f0f, KEY_MUTE }, - { 0x1f0c, KEY_RADIO }, /* There's no indicator on this key */ - { 0x1f3c, KEY_ZOOM }, /* full */ - - { 0x1f32, KEY_REWIND }, /* backward << */ - { 0x1f35, KEY_PLAY }, - { 0x1f34, KEY_FASTFORWARD }, /* forward >> */ - - { 0x1f37, KEY_RECORD }, /* recording */ - { 0x1f36, KEY_STOP }, - { 0x1f30, KEY_PAUSE }, /* pause */ - - { 0x1f24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x1f1e, KEY_NEXTSONG }, /* skip >| */ - - /* - * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick - * Keycodes start with address = 0x1d - */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, - { 0x1d0a, KEY_TEXT }, - { 0x1d0d, KEY_MENU }, - { 0x1d0f, KEY_MUTE }, - { 0x1d10, KEY_VOLUMEUP }, - { 0x1d11, KEY_VOLUMEDOWN }, - { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */ - { 0x1d14, KEY_UP }, - { 0x1d15, KEY_DOWN }, - { 0x1d16, KEY_LEFT }, - { 0x1d17, KEY_RIGHT }, - { 0x1d1c, KEY_TV }, - { 0x1d1e, KEY_NEXT }, /* >| */ - { 0x1d1f, KEY_EXIT }, - { 0x1d20, KEY_CHANNELUP }, - { 0x1d21, KEY_CHANNELDOWN }, - { 0x1d24, KEY_LAST }, /* <| */ - { 0x1d25, KEY_OK }, - { 0x1d30, KEY_PAUSE }, - { 0x1d32, KEY_REWIND }, - { 0x1d34, KEY_FASTFORWARD }, - { 0x1d35, KEY_PLAY }, - { 0x1d36, KEY_STOP }, - { 0x1d37, KEY_RECORD }, - { 0x1d3b, KEY_GOTO }, - { 0x1d3d, KEY_POWER }, - { 0x1d3f, KEY_HOME }, - - /* - * Keycodes for the old Black Remote Controller - * This one also uses RC-5 protocol - * Keycodes start with address = 0x00 - */ - { 0x001f, KEY_TV }, - { 0x0020, KEY_CHANNELUP }, - { 0x000c, KEY_RADIO }, - - { 0x0011, KEY_VOLUMEDOWN }, - { 0x002e, KEY_ZOOM }, /* full screen */ - { 0x0010, KEY_VOLUMEUP }, - - { 0x000d, KEY_MUTE }, - { 0x0021, KEY_CHANNELDOWN }, - { 0x0022, KEY_VIDEO }, /* source */ - - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, - - { 0x001e, KEY_RED }, /* Reserved */ - { 0x0000, KEY_0 }, - { 0x0026, KEY_SLEEP }, /* Minimize */ -}; - -static struct rc_map_list rc5_hauppauge_new_map = { - .map = { - .scan = rc5_hauppauge_new, - .size = ARRAY_SIZE(rc5_hauppauge_new), - .rc_type = RC_TYPE_RC5, - .name = RC_MAP_RC5_HAUPPAUGE_NEW, - } -}; - -static int __init init_rc_map_rc5_hauppauge_new(void) -{ - return rc_map_register(&rc5_hauppauge_new_map); -} - -static void __exit exit_rc_map_rc5_hauppauge_new(void) -{ - rc_map_unregister(&rc5_hauppauge_new_map); -} - -module_init(init_rc_map_rc5_hauppauge_new) -module_exit(exit_rc_map_rc5_hauppauge_new) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index e4f8eac7f717..eedefce86fcf 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -186,7 +186,7 @@ static const struct mceusb_model mceusb_model[] = { * remotes, but we should have something handy, * to allow testing it */ - .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW, + .rc_map = RC_MAP_HAUPPAUGE, .name = "Conexant Hybrid TV (cx231xx) MCE IR", }, [CX_HYBRID_TV] = { diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index 199b9964bbe5..e97cafd83984 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -264,7 +264,7 @@ int cx23885_input_init(struct cx23885_dev *dev) driver_type = RC_DRIVER_IR_RAW; allowed_protos = RC_TYPE_ALL; /* The grey Hauppauge RC-5 remote */ - rc_map = RC_MAP_RC5_HAUPPAUGE_NEW; + rc_map = RC_MAP_HAUPPAUGE; break; case CX23885_BOARD_TEVII_S470: /* Integrated CX23885 IR controller */ diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 87f77a34eeab..aa4f45e692e6 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -911,7 +911,7 @@ struct em28xx_board em28xx_boards[] = { .mts_firmware = 1, .has_dvb = 1, .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW, + .ir_codes = RC_MAP_HAUPPAUGE, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -2430,7 +2430,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev) dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; break; case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - dev->init_data.ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW; + dev->init_data.ir_codes = RC_MAP_HAUPPAUGE; dev->init_data.get_key = em28xx_get_key_em_haup; dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; break; -- cgit v1.2.2 From af86ce79f020a31e4a30661e41471d31face9985 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 12:18:48 -0300 Subject: [media] remove the old RC_MAP_HAUPPAUGE_NEW RC map The rc-hauppauge-new map is a messy thing, as it bundles 3 different remote controllers as if they were just one, discarding the address byte. Also, some key maps are wrong. With the conversion to the new rc-core, it is likely that most of the devices won't be working properly, as the i2c driver and the raw decoders are now providing 16 bits for the remote, instead of just 8. delete mode 100644 drivers/media/rc/keymaps/rc-hauppauge-new.c Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/dvb/ttpci/budget-ci.c | 15 +++- drivers/media/rc/keymaps/Makefile | 1 - drivers/media/rc/keymaps/rc-hauppauge-new.c | 100 ------------------------- drivers/media/video/cx18/cx18-i2c.c | 2 +- drivers/media/video/cx88/cx88-input.c | 4 +- drivers/media/video/em28xx/em28xx-cards.c | 6 +- drivers/media/video/hdpvr/hdpvr-i2c.c | 2 +- drivers/media/video/ir-kbd-i2c.c | 4 +- drivers/media/video/ivtv/ivtv-i2c.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-i2c-core.c | 4 +- drivers/media/video/saa7134/saa7134-input.c | 2 +- 11 files changed, 25 insertions(+), 117 deletions(-) delete mode 100644 drivers/media/rc/keymaps/rc-hauppauge-new.c (limited to 'drivers') diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index b82756db5bd1..1d79ada864d6 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -26,7 +26,7 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * - * the project's page is at http://www.linuxtv.org/ + * the project's page is at http://www.linuxtv.org/ */ #include @@ -102,6 +102,7 @@ struct budget_ci_ir { int rc5_device; u32 ir_key; bool have_command; + bool full_rc5; /* Outputs a full RC5 code */ }; struct budget_ci { @@ -154,11 +155,18 @@ static void msp430_ir_interrupt(unsigned long data) return; budget_ci->ir.have_command = false; - /* FIXME: We should generate complete scancodes with device info */ if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != (command & 0x1f)) return; + if (budget_ci->ir.full_rc5) { + rc_keydown(dev, + budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key, + (command & 0x20) ? 1 : 0); + return; + } + + /* FIXME: We should generate complete scancodes for all devices */ rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0); } @@ -206,7 +214,8 @@ static int msp430_ir_init(struct budget_ci *budget_ci) case 0x1011: case 0x1012: /* The hauppauge keymap is a superset of these remotes */ - dev->map_name = RC_MAP_HAUPPAUGE_NEW; + dev->map_name = RC_MAP_HAUPPAUGE; + budget_ci->ir.full_rc5 = true; if (rc5_device < 0) budget_ci->ir.rc5_device = 0x1f; diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 1f446f99b61f..2fb566bf8ea2 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -37,7 +37,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-gadmei-rm008z.o \ rc-genius-tvgo-a11mce.o \ rc-gotview7135.o \ - rc-hauppauge-new.o \ rc-imon-mce.o \ rc-imon-pad.o \ rc-iodata-bctv7e.o \ diff --git a/drivers/media/rc/keymaps/rc-hauppauge-new.c b/drivers/media/rc/keymaps/rc-hauppauge-new.c deleted file mode 100644 index 44f3283e15b5..000000000000 --- a/drivers/media/rc/keymaps/rc-hauppauge-new.c +++ /dev/null @@ -1,100 +0,0 @@ -/* hauppauge-new.h - Keytable for hauppauge_new Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include - -/* Hauppauge: the newer, gray remotes (seems there are multiple - * slightly different versions), shipped with cx88+ivtv cards. - * almost rc5 coding, but some non-standard keys */ - -static struct rc_map_table hauppauge_new[] = { - /* Keys 0 to 9 */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x0b, KEY_RED }, /* red button */ - { 0x0c, KEY_RADIO }, - { 0x0d, KEY_MENU }, - { 0x0e, KEY_SUBTITLE }, /* also the # key */ - { 0x0f, KEY_MUTE }, - { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_VOLUMEDOWN }, - { 0x12, KEY_PREVIOUS }, /* previous channel */ - { 0x14, KEY_UP }, - { 0x15, KEY_DOWN }, - { 0x16, KEY_LEFT }, - { 0x17, KEY_RIGHT }, - { 0x18, KEY_VCR }, /* Videos */ - { 0x19, KEY_AUDIO }, /* Music */ - /* 0x1a: Pictures - presume this means - "Multimedia Home Platform" - - no "PICTURES" key in input.h - */ - { 0x1a, KEY_CAMERA }, - - { 0x1b, KEY_EPG }, /* Guide */ - { 0x1c, KEY_TV }, - { 0x1e, KEY_NEXTSONG }, /* skip >| */ - { 0x1f, KEY_EXIT }, /* back/exit */ - { 0x20, KEY_CHANNELUP }, /* channel / program + */ - { 0x21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x22, KEY_VIDEO }, /* source (old black remote) */ - { 0x24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x25, KEY_ENTER }, /* OK */ - { 0x26, KEY_SLEEP }, /* minimize (old black remote) */ - { 0x29, KEY_BLUE }, /* blue key */ - { 0x2e, KEY_GREEN }, /* green button */ - { 0x30, KEY_PAUSE }, /* pause */ - { 0x32, KEY_REWIND }, /* backward << */ - { 0x34, KEY_FASTFORWARD }, /* forward >> */ - { 0x35, KEY_PLAY }, - { 0x36, KEY_STOP }, - { 0x37, KEY_RECORD }, /* recording */ - { 0x38, KEY_YELLOW }, /* yellow key */ - { 0x3b, KEY_SELECT }, /* top right button */ - { 0x3c, KEY_ZOOM }, /* full */ - { 0x3d, KEY_POWER }, /* system power (green button) */ -}; - -static struct rc_map_list hauppauge_new_map = { - .map = { - .scan = hauppauge_new, - .size = ARRAY_SIZE(hauppauge_new), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_HAUPPAUGE_NEW, - } -}; - -static int __init init_rc_map_hauppauge_new(void) -{ - return rc_map_register(&hauppauge_new_map); -} - -static void __exit exit_rc_map_hauppauge_new(void) -{ - rc_map_unregister(&hauppauge_new_map); -} - -module_init(init_rc_map_hauppauge_new) -module_exit(exit_rc_map_hauppauge_new) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c index c330fb917b50..040aaa87579d 100644 --- a/drivers/media/video/cx18/cx18-i2c.c +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -96,7 +96,7 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, /* Our default information for ir-kbd-i2c.c to use */ switch (hw) { case CX18_HW_Z8F0811_IR_RX_HAUP: - init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->type = RC_TYPE_RC5; init_data->name = cx->card_name; diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index fbfbba5bec5e..c820e2f53527 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -283,7 +283,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_PCHDTV_HD3000: case CX88_BOARD_PCHDTV_HD5500: case CX88_BOARD_HAUPPAUGE_IRONLY: - ir_codes = RC_MAP_HAUPPAUGE_NEW; + ir_codes = RC_MAP_HAUPPAUGE; ir->sampling = 1; break; case CX88_BOARD_WINFAST_DTV2000H: @@ -604,7 +604,7 @@ void cx88_i2c_init_ir(struct cx88_core *core) if (*addrp == 0x71) { /* Hauppauge XVR */ core->init_data.name = "cx88 Hauppauge XVR remote"; - core->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW; + core->init_data.ir_codes = RC_MAP_HAUPPAUGE; core->init_data.type = RC_TYPE_RC5; core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index aa4f45e692e6..69fcea82d01c 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -834,7 +834,7 @@ struct em28xx_board em28xx_boards[] = { .mts_firmware = 1, .has_dvb = 1, .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_HAUPPAUGE_NEW, + .ir_codes = RC_MAP_HAUPPAUGE, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -859,7 +859,7 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_XC2028, .tuner_gpio = default_tuner_gpio, .mts_firmware = 1, - .ir_codes = RC_MAP_HAUPPAUGE_NEW, + .ir_codes = RC_MAP_HAUPPAUGE, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, @@ -885,7 +885,7 @@ struct em28xx_board em28xx_boards[] = { .mts_firmware = 1, .has_dvb = 1, .dvb_gpio = hauppauge_wintv_hvr_900_digital, - .ir_codes = RC_MAP_HAUPPAUGE_NEW, + .ir_codes = RC_MAP_HAUPPAUGE, .decoder = EM28XX_TVP5150, .input = { { .type = EM28XX_VMUX_TELEVISION, diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index 3e0658768135..de69bae9bac7 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -52,7 +52,7 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) }; /* Our default information for ir-kbd-i2c.c to use */ - init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->type = RC_TYPE_RC5; init_data->name = "HD-PVR"; diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index a221ad68b330..be7064fcdfe4 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -313,7 +313,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->get_key = get_key_haup; rc_type = RC_TYPE_RC5; if (hauppauge == 1) { - ir_codes = RC_MAP_HAUPPAUGE_NEW; + ir_codes = RC_MAP_HAUPPAUGE; } else { ir_codes = RC_MAP_RC5_TV; } @@ -340,7 +340,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) name = "Hauppauge/Zilog Z8"; ir->get_key = get_key_haup_xvr; rc_type = RC_TYPE_RC5; - ir_codes = hauppauge ? RC_MAP_HAUPPAUGE_NEW : RC_MAP_RC5_TV; + ir_codes = hauppauge ? RC_MAP_HAUPPAUGE : RC_MAP_RC5_TV; break; } diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 9fb86a081c0f..3c89d6f28d5f 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -213,7 +213,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) break; case IVTV_HW_Z8F0811_IR_RX_HAUP: /* Default to grey remote */ - init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->type = RC_TYPE_RC5; init_data->name = itv->card_name; diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 451ecd485f97..e72d5103e778 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -578,7 +578,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) switch (hdw->ir_scheme_active) { case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */ case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */ - init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; init_data->type = RC_TYPE_RC5; init_data->name = hdw->hdw_desc->description; @@ -593,7 +593,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) break; case PVR2_IR_SCHEME_ZILOG: /* HVR-1950 style */ case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */ - init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW; + init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->type = RC_TYPE_RC5; init_data->name = hdw->hdw_desc->description; diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 790d66703fea..be1c2a2de27c 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -893,7 +893,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) case SAA7134_BOARD_HAUPPAUGE_HVR1110: dev->init_data.name = "HVR 1110"; dev->init_data.get_key = get_key_hvr1110; - dev->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW; + dev->init_data.ir_codes = RC_MAP_HAUPPAUGE; info.addr = 0x71; break; case SAA7134_BOARD_BEHOLD_607FM_MK3: -- cgit v1.2.2 From 206241069ecfa52c3b8873f8d7e31d434d2fcae1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jan 2011 22:23:08 -0300 Subject: [media] rc/keymaps: Remove the obsolete rc-rc5-tv keymap This keymap were used for the Hauppauge Black remote controller only. It also contains some keycodes not found there. As the Hauppauge Black is now part of the hauppauge keymap, just remove it. Also, remove the modprobe hacks to select between the Gray and the Black versions of the remote controller as: - Both are supported by default by the keymap; - If the user just wants one keyboard supported, it is just a matter of changing the keymap via the userspace tool (ir-keytable), removing the keys that he doesn't desire. As ir-keytable auto-loads the keys via udev, this is better than obscure modprobe parameters. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jarod Wilson --- drivers/media/rc/keymaps/Makefile | 1 - drivers/media/rc/keymaps/rc-rc5-tv.c | 81 ------------------------------------ drivers/media/video/ir-kbd-i2c.c | 16 +------ drivers/media/video/ivtv/ivtv-i2c.c | 3 +- 4 files changed, 3 insertions(+), 98 deletions(-) delete mode 100644 drivers/media/rc/keymaps/rc-rc5-tv.c (limited to 'drivers') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 2fb566bf8ea2..85cac7ddbcec 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -68,7 +68,6 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-purpletv.o \ rc-pv951.o \ rc-hauppauge.o \ - rc-rc5-tv.o \ rc-rc6-mce.o \ rc-real-audio-220-32-keys.o \ rc-streamzap.o \ diff --git a/drivers/media/rc/keymaps/rc-rc5-tv.c b/drivers/media/rc/keymaps/rc-rc5-tv.c deleted file mode 100644 index 4fcef9f1f721..000000000000 --- a/drivers/media/rc/keymaps/rc-rc5-tv.c +++ /dev/null @@ -1,81 +0,0 @@ -/* rc5-tv.h - Keytable for rc5_tv Remote Controller - * - * keymap imported from ir-keymaps.c - * - * Copyright (c) 2010 by Mauro Carvalho Chehab - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include - -/* generic RC5 keytable */ -/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */ -/* used by old (black) Hauppauge remotes */ - -static struct rc_map_table rc5_tv[] = { - /* Keys 0 to 9 */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - - { 0x0b, KEY_CHANNEL }, /* channel / program (japan: 11) */ - { 0x0c, KEY_POWER }, /* standby */ - { 0x0d, KEY_MUTE }, /* mute / demute */ - { 0x0f, KEY_TV }, /* display */ - { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_VOLUMEDOWN }, - { 0x12, KEY_BRIGHTNESSUP }, - { 0x13, KEY_BRIGHTNESSDOWN }, - { 0x1e, KEY_SEARCH }, /* search + */ - { 0x20, KEY_CHANNELUP }, /* channel / program + */ - { 0x21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x22, KEY_CHANNEL }, /* alt / channel */ - { 0x23, KEY_LANGUAGE }, /* 1st / 2nd language */ - { 0x26, KEY_SLEEP }, /* sleeptimer */ - { 0x2e, KEY_MENU }, /* 2nd controls (USA: menu) */ - { 0x30, KEY_PAUSE }, - { 0x32, KEY_REWIND }, - { 0x33, KEY_GOTO }, - { 0x35, KEY_PLAY }, - { 0x36, KEY_STOP }, - { 0x37, KEY_RECORD }, /* recording */ - { 0x3c, KEY_TEXT }, /* teletext submode (Japan: 12) */ - { 0x3d, KEY_SUSPEND }, /* system standby */ - -}; - -static struct rc_map_list rc5_tv_map = { - .map = { - .scan = rc5_tv, - .size = ARRAY_SIZE(rc5_tv), - .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */ - .name = RC_MAP_RC5_TV, - } -}; - -static int __init init_rc_map_rc5_tv(void) -{ - return rc_map_register(&rc5_tv_map); -} - -static void __exit exit_rc_map_rc5_tv(void) -{ - rc_map_unregister(&rc5_tv_map); -} - -module_init(init_rc_map_rc5_tv) -module_exit(exit_rc_map_rc5_tv) - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Mauro Carvalho Chehab "); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index be7064fcdfe4..672935f7aeba 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -55,10 +55,6 @@ static int debug; module_param(debug, int, 0644); /* debug level (0,1,2) */ -static int hauppauge; -module_param(hauppauge, int, 0644); /* Choose Hauppauge remote */ -MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)"); - #define MODULE_NAME "ir-kbd-i2c" #define dprintk(level, fmt, arg...) if (debug >= level) \ @@ -105,10 +101,6 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, /* invalid key press */ return 0; - if (dev!=0x1e && dev!=0x1f) - /* not a hauppauge remote */ - return 0; - if (!range) code += 64; @@ -312,11 +304,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) name = "Hauppauge"; ir->get_key = get_key_haup; rc_type = RC_TYPE_RC5; - if (hauppauge == 1) { - ir_codes = RC_MAP_HAUPPAUGE; - } else { - ir_codes = RC_MAP_RC5_TV; - } + ir_codes = RC_MAP_HAUPPAUGE; break; case 0x30: name = "KNC One"; @@ -340,7 +328,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) name = "Hauppauge/Zilog Z8"; ir->get_key = get_key_haup_xvr; rc_type = RC_TYPE_RC5; - ir_codes = hauppauge ? RC_MAP_HAUPPAUGE : RC_MAP_RC5_TV; + ir_codes = RC_MAP_HAUPPAUGE; break; } diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 3c89d6f28d5f..d47f41a0ef66 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -205,8 +205,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) break; case IVTV_HW_I2C_IR_RX_HAUP_EXT: case IVTV_HW_I2C_IR_RX_HAUP_INT: - /* Default to old black remote */ - init_data->ir_codes = RC_MAP_RC5_TV; + init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; init_data->type = RC_TYPE_RC5; init_data->name = itv->card_name; -- cgit v1.2.2 From 6e5b960176980852187b6f0bafa3db78130be42f Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 4 Mar 2011 17:30:17 -0300 Subject: [media] ir-kbd-i2c: pass device code w/key in hauppauge case The new hauppauge key tables use both device code button code. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/ir-kbd-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 672935f7aeba..3ab875d036e1 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -108,7 +108,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw, start, range, toggle, dev, code); /* return key */ - *ir_key = code; + *ir_key = (dev << 8) | code; *ir_raw = ircode; return 1; } -- cgit v1.2.2 From dc8e2aa3b5a6c13baa77709bcaa2e7e483d9d006 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 4 Mar 2011 17:31:11 -0300 Subject: [media] hdpvr: use same polling interval as other OS The hdpvr's IR part, in short, sucks. As observed with a usb traffic sniffer, the Windows software for it uses a polling interval of 405ms. Its still not behaving as well as I'd like even with this change, but this inches us closer and closer to that point... Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/hdpvr/hdpvr-i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index de69bae9bac7..2a1ac287591d 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c @@ -56,6 +56,7 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; init_data->type = RC_TYPE_RC5; init_data->name = "HD-PVR"; + init_data->polling_interval = 405; /* ms, duplicated from Windows */ hdpvr_ir_rx_i2c_board_info.platform_data = init_data; return i2c_new_device(&dev->i2c_adapter, &hdpvr_ir_rx_i2c_board_info); @@ -191,7 +192,7 @@ static struct i2c_adapter hdpvr_i2c_adapter_template = { static int hdpvr_activate_ir(struct hdpvr_device *dev) { - char buffer[8]; + char buffer[2]; mutex_lock(&dev->i2c_mutex); -- cgit v1.2.2 From 55734785cdaff596be9a5238af54fc0f4ace2e63 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 4 Mar 2011 17:57:24 -0300 Subject: [media] lirc: silence some compile warnings Both lirc_imon and lirc_sasem were causing gcc to complain about the possible use of uninitialized variables. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_imon.c | 2 +- drivers/staging/lirc/lirc_sasem.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_imon.c b/drivers/staging/lirc/lirc_imon.c index 235cab0eb087..4039eda2a15b 100644 --- a/drivers/staging/lirc/lirc_imon.c +++ b/drivers/staging/lirc/lirc_imon.c @@ -379,7 +379,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, struct imon_context *context; const unsigned char vfd_packet6[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; - int *data_buf; + int *data_buf = NULL; context = file->private_data; if (!context) { diff --git a/drivers/staging/lirc/lirc_sasem.c b/drivers/staging/lirc/lirc_sasem.c index 925eabe14854..63a438d1c849 100644 --- a/drivers/staging/lirc/lirc_sasem.c +++ b/drivers/staging/lirc/lirc_sasem.c @@ -364,7 +364,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, int i; int retval = 0; struct sasem_context *context; - int *data_buf; + int *data_buf = NULL; context = (struct sasem_context *) file->private_data; if (!context) { -- cgit v1.2.2 From cc664ae026f1b0f3254564a7d45cc29e735c7fed Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 4 Mar 2011 19:53:05 -0300 Subject: [media] lirc_zilog: error out if buffer read bytes != chunk size Give it a few tries, then exit. Prevents a possible endless loop situation. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/lirc/lirc_zilog.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/lirc/lirc_zilog.c b/drivers/staging/lirc/lirc_zilog.c index 407d4b409a8b..dd6a57c3c3a3 100644 --- a/drivers/staging/lirc/lirc_zilog.c +++ b/drivers/staging/lirc/lirc_zilog.c @@ -897,7 +897,7 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) struct IR *ir = filep->private_data; struct IR_rx *rx; struct lirc_buffer *rbuf = ir->l.rbuf; - int ret = 0, written = 0; + int ret = 0, written = 0, retries = 0; unsigned int m; DECLARE_WAITQUEUE(wait, current); @@ -950,6 +950,12 @@ static ssize_t read(struct file *filep, char *outbuf, size_t n, loff_t *ppos) ret = copy_to_user((void *)outbuf+written, buf, rbuf->chunk_size); written += rbuf->chunk_size; + } else { + retries++; + } + if (retries >= 5) { + zilog_error("Buffer read failed!\n"); + ret = -EIO; } } } -- cgit v1.2.2 From 7d9a46f9d5e0bea8e862143be73df2bbc9acb2a3 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Fri, 4 Mar 2011 20:20:47 -0300 Subject: [media] mceusb: topseed 0x0011 needs gen3 init for tx to work Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index eedefce86fcf..044fb7a382d6 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -261,7 +261,7 @@ static struct usb_device_id mceusb_dev_table[] = { .driver_info = MCE_GEN2_TX_INV }, /* Topseed eHome Infrared Transceiver */ { USB_DEVICE(VENDOR_TOPSEED, 0x0011), - .driver_info = MCE_GEN2_TX_INV }, + .driver_info = MCE_GEN3 }, /* Ricavision internal Infrared Transceiver */ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) }, /* Itron ione Libra Q-11 */ -- cgit v1.2.2 From 4be22b6a7f2f2b7eb6f7aab8902068a367cda8ba Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 22 Mar 2011 17:23:15 -0300 Subject: [media] rc: interim support for 32-bit NEC-ish scancodes The Apple and TiVo remotes I've got use an NEC-ish protocol, but rather than a command/not_command pair, they have what appear to be vendor ID bytes. This change makes the NEC decoder warn if the command/not_command checksum fails, but then passes along a full 32-bit scancode for keymap lookup. This change should make no difference for existing keymaps, since they simply won't have 32-bit scancodes, but allows for a 32-bit keymap. At the moment, that'll have to be uploaded by the user, but I've got Apple and TiVo remote keymaps forthcoming. In the long run (2.6.40, hopefully), we should probably just always use all 32 bits for all NEC keymaps, but this should get us by for 2.6.39. (Note that a few of the TiVo keys actuallly *do* pass the command checksum, so for now, the keymap for this remote will have to be a mix of 24-bit and 32-bit scancodes, but so be it). Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-nec-decoder.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 7b58b4a1729b..63ee722dbd02 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -49,6 +49,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) struct nec_dec *data = &dev->raw->nec; u32 scancode; u8 address, not_address, command, not_command; + bool send_32bits = false; if (!(dev->raw->enabled_protocols & RC_TYPE_NEC)) return 0; @@ -164,10 +165,15 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) if ((command ^ not_command) != 0xff) { IR_dprintk(1, "NEC checksum error: received 0x%08x\n", data->bits); - break; + send_32bits = true; } - if ((address ^ not_address) != 0xff) { + if (send_32bits) { + /* NEC transport, but modified protocol, used by at + * least Apple and TiVo remotes */ + scancode = data->bits; + IR_dprintk(1, "NEC (modified) scancode 0x%08x\n", scancode); + } else if ((address ^ not_address) != 0xff) { /* Extended NEC */ scancode = address << 16 | not_address << 8 | -- cgit v1.2.2 From 0e4c180d3e2cc11e248f29d4c604b6194739d05a Mon Sep 17 00:00:00 2001 From: Sergio Aguirre Date: Mon, 7 Mar 2011 21:49:48 -0300 Subject: [media] v4l: soc-camera: Store negotiated buffer settings This fixes the problem in which a host driver sets a personalized sizeimage or bytesperline field, and gets ignored when doing G_FMT. Signed-off-by: Sergio Aguirre Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index fa80a4a914d4..07525e74c4b4 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -389,6 +389,8 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, icd->user_width = pix->width; icd->user_height = pix->height; + icd->bytesperline = pix->bytesperline; + icd->sizeimage = pix->sizeimage; icd->colorspace = pix->colorspace; icd->field = pix->field; if (ici->ops->init_videobuf) @@ -661,14 +663,11 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, pix->width = icd->user_width; pix->height = icd->user_height; + pix->bytesperline = icd->bytesperline; + pix->sizeimage = icd->sizeimage; pix->field = icd->field; pix->pixelformat = icd->current_fmt->host_fmt->fourcc; - pix->bytesperline = soc_mbus_bytes_per_line(pix->width, - icd->current_fmt->host_fmt); pix->colorspace = icd->colorspace; - if (pix->bytesperline < 0) - return pix->bytesperline; - pix->sizeimage = pix->height * pix->bytesperline; dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", icd->current_fmt->host_fmt->fourcc); return 0; -- cgit v1.2.2 From d366d4a08a4e5e1fddc2cc820302be8e7a8143d4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 21 Mar 2011 06:33:25 -0300 Subject: [media] V4L: soc-camera: explicitly require V4L2_BUF_TYPE_VIDEO_CAPTURE The soc-camera core accesses the "pix" member of the struct v4l2_format::fmt union, which is only valid for V4L2_BUF_TYPE_VIDEO_CAPTURE streams. This patch adds explicit checks for this to {g,s,try}_fmt methods. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 07525e74c4b4..46284489e4eb 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -144,6 +144,10 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, WARN_ON(priv != file->private_data); + /* Only single-plane capture is supported so far */ + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + /* limit format to hardware capabilities */ return ici->ops->try_fmt(icd, f); } @@ -396,10 +400,6 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, if (ici->ops->init_videobuf) icd->vb_vidq.field = pix->field; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", - f->type); - dev_dbg(&icd->dev, "set width: %d height: %d\n", icd->user_width, icd->user_height); @@ -618,6 +618,11 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, WARN_ON(priv != file->private_data); + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_warn(&icd->dev, "Wrong buf-type %d\n", f->type); + return -EINVAL; + } + if (icd->streamer && icd->streamer != file) return -EBUSY; @@ -661,6 +666,9 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, WARN_ON(priv != file->private_data); + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + pix->width = icd->user_width; pix->height = icd->user_height; pix->bytesperline = icd->bytesperline; -- cgit v1.2.2 From d6db5bfe7fd6d4334a1460923ba8175f1a0ece2d Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Mon, 14 Mar 2011 10:38:23 -0300 Subject: [media] sh_mobile_ceu_camera: Do not call vb2's mem_ops directly Use vb2_dma_contig_plane_paddr to retrieve a physical address for a plane instead of calling an internal mem_ops callback. Signed-off-by: Pawel Osciak Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 61f37012b4f8..3fe54bf41142 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -302,9 +302,7 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) bottom2 = CDBCR; } - /* mem_ops->cookie must not be NULL */ - phys_addr_top = (dma_addr_t)icd->vb2_vidq.mem_ops->cookie(pcdev-> - active->planes[0].mem_priv); + phys_addr_top = vb2_dma_contig_plane_paddr(pcdev->active, 0); ceu_write(pcdev, top1, phys_addr_top); if (V4L2_FIELD_NONE != pcdev->field) { -- cgit v1.2.2 From 472af2b05bdefcaee7e754e22cbf131110017ad6 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Mon, 14 Mar 2011 10:38:24 -0300 Subject: [media] videobuf2-dma-contig: make cookie() return a pointer to dma_addr_t dma_addr_t may not fit into void* on some architectures. To be safe, make vb2_dma_contig_cookie() return a pointer to dma_addr_t and dereference it in vb2_dma_contig_plane_paddr() back to dma_addr_t. Signed-off-by: Pawel Osciak Reported-by: Hans Verkuil Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-dma-contig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c index 90495b7b4ddf..58205d596138 100644 --- a/drivers/media/video/videobuf2-dma-contig.c +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -78,7 +78,7 @@ static void *vb2_dma_contig_cookie(void *buf_priv) { struct vb2_dc_buf *buf = buf_priv; - return (void *)buf->paddr; + return &buf->paddr; } static void *vb2_dma_contig_vaddr(void *buf_priv) -- cgit v1.2.2 From f23eb2b2b28547fc70df82dd5049eb39bec5ba12 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 22 Mar 2011 16:17:32 -0700 Subject: tty: stop using "delayed_work" in the tty layer Using delayed-work for tty flip buffers ends up causing us to wait for the next tick to complete some actions. That's usually not all that noticeable, but for certain latency-critical workloads it ends up being totally unacceptable. As an extreme case of this, passing a token back-and-forth over a pty will take two ticks per iteration, so even just a thousand iterations will take 8 seconds assuming a common 250Hz configuration. Avoiding the whole delayed work issue brings that ping-pong test-case down to 0.009s on my machine. In more practical terms, this latency has been a performance problem for things like dive computer simulators (simulating the serial interface using the ptys) and for other environments (Alan mentions a CP/M emulator). Reported-by: Jef Driesen Acked-by: Greg KH Acked-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/tty/tty_buffer.c | 14 +++++++------- drivers/tty/tty_ldisc.c | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index d8210ca00720..b9451219528b 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -322,7 +322,7 @@ void tty_schedule_flip(struct tty_struct *tty) if (tty->buf.tail != NULL) tty->buf.tail->commit = tty->buf.tail->used; spin_unlock_irqrestore(&tty->buf.lock, flags); - schedule_delayed_work(&tty->buf.work, 1); + schedule_work(&tty->buf.work); } EXPORT_SYMBOL(tty_schedule_flip); @@ -402,7 +402,7 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); static void flush_to_ldisc(struct work_struct *work) { struct tty_struct *tty = - container_of(work, struct tty_struct, buf.work.work); + container_of(work, struct tty_struct, buf.work); unsigned long flags; struct tty_ldisc *disc; @@ -443,7 +443,7 @@ static void flush_to_ldisc(struct work_struct *work) if (test_bit(TTY_FLUSHPENDING, &tty->flags)) break; if (!tty->receive_room || seen_tail) { - schedule_delayed_work(&tty->buf.work, 1); + schedule_work(&tty->buf.work); break; } if (count > tty->receive_room) @@ -481,7 +481,7 @@ static void flush_to_ldisc(struct work_struct *work) */ void tty_flush_to_ldisc(struct tty_struct *tty) { - flush_delayed_work(&tty->buf.work); + flush_work(&tty->buf.work); } /** @@ -506,9 +506,9 @@ void tty_flip_buffer_push(struct tty_struct *tty) spin_unlock_irqrestore(&tty->buf.lock, flags); if (tty->low_latency) - flush_to_ldisc(&tty->buf.work.work); + flush_to_ldisc(&tty->buf.work); else - schedule_delayed_work(&tty->buf.work, 1); + schedule_work(&tty->buf.work); } EXPORT_SYMBOL(tty_flip_buffer_push); @@ -529,6 +529,6 @@ void tty_buffer_init(struct tty_struct *tty) tty->buf.tail = NULL; tty->buf.free = NULL; tty->buf.memory_used = 0; - INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); + INIT_WORK(&tty->buf.work, flush_to_ldisc); } diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 0fc564a97706..e19e13647116 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -529,7 +529,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) static int tty_ldisc_halt(struct tty_struct *tty) { clear_bit(TTY_LDISC, &tty->flags); - return cancel_delayed_work_sync(&tty->buf.work); + return cancel_work_sync(&tty->buf.work); } /** @@ -542,7 +542,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) { flush_work_sync(&tty->hangup_work); flush_work_sync(&tty->SAK_work); - flush_delayed_work_sync(&tty->buf.work); + flush_work_sync(&tty->buf.work); } /** @@ -722,9 +722,9 @@ enable: /* Restart the work queue in case no characters kick it off. Safe if already running */ if (work) - schedule_delayed_work(&tty->buf.work, 1); + schedule_work(&tty->buf.work); if (o_work) - schedule_delayed_work(&o_tty->buf.work, 1); + schedule_work(&o_tty->buf.work); mutex_unlock(&tty->ldisc_mutex); tty_unlock(); return retval; @@ -830,12 +830,12 @@ void tty_ldisc_hangup(struct tty_struct *tty) /* * this is like tty_ldisc_halt, but we need to give up - * the BTM before calling cancel_delayed_work_sync, - * which may need to wait for another function taking the BTM + * the BTM before calling cancel_work_sync, which may + * need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); tty_unlock(); - cancel_delayed_work_sync(&tty->buf.work); + cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); tty_lock(); -- cgit v1.2.2 From 551ea73838c5eba18d673bd4e7fb0fec77cdcb8a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Mar 2011 16:30:14 -0700 Subject: leds: convert bd2802 driver to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitiate updates to the PM core. Do this move for the bs2802 driver. [akpm@linux-foundation.org: fix warnings] Signed-off-by: Mark Brown Cc: Kim Kyuwon Cc: Kim Kyuwon Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-bd2802.c | 47 +++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 19dc4b61a105..3ebe3824662d 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -19,7 +19,7 @@ #include #include #include - +#include #define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0)) @@ -319,20 +319,6 @@ static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id, bd2802_update_state(led, id, color, BD2802_OFF); } -static void bd2802_restore_state(struct bd2802_led *led) -{ - int i; - - for (i = 0; i < LED_NUM; i++) { - if (led->led[i].r) - bd2802_turn_on(led, i, RED, led->led[i].r); - if (led->led[i].g) - bd2802_turn_on(led, i, GREEN, led->led[i].g); - if (led->led[i].b) - bd2802_turn_on(led, i, BLUE, led->led[i].b); - } -} - #define BD2802_SET_REGISTER(reg_addr, reg_name) \ static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \ struct device_attribute *attr, const char *buf, size_t count) \ @@ -761,8 +747,25 @@ static int __exit bd2802_remove(struct i2c_client *client) return 0; } -static int bd2802_suspend(struct i2c_client *client, pm_message_t mesg) +#ifdef CONFIG_PM + +static void bd2802_restore_state(struct bd2802_led *led) { + int i; + + for (i = 0; i < LED_NUM; i++) { + if (led->led[i].r) + bd2802_turn_on(led, i, RED, led->led[i].r); + if (led->led[i].g) + bd2802_turn_on(led, i, GREEN, led->led[i].g); + if (led->led[i].b) + bd2802_turn_on(led, i, BLUE, led->led[i].b); + } +} + +static int bd2802_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); struct bd2802_led *led = i2c_get_clientdata(client); gpio_set_value(led->pdata->reset_gpio, 0); @@ -770,8 +773,9 @@ static int bd2802_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int bd2802_resume(struct i2c_client *client) +static int bd2802_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct bd2802_led *led = i2c_get_clientdata(client); if (!bd2802_is_all_off(led) || led->adf_on) { @@ -782,6 +786,12 @@ static int bd2802_resume(struct i2c_client *client) return 0; } +static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume); +#define BD2802_PM (&bd2802_pm) +#else /* CONFIG_PM */ +#define BD2802_PM NULL +#endif + static const struct i2c_device_id bd2802_id[] = { { "BD2802", 0 }, { } @@ -791,11 +801,10 @@ MODULE_DEVICE_TABLE(i2c, bd2802_id); static struct i2c_driver bd2802_i2c_driver = { .driver = { .name = "BD2802", + .pm = BD2802_PM, }, .probe = bd2802_probe, .remove = __exit_p(bd2802_remove), - .suspend = bd2802_suspend, - .resume = bd2802_resume, .id_table = bd2802_id, }; -- cgit v1.2.2 From b1e6b7068f026e88257c20522555c78122e5a14d Mon Sep 17 00:00:00 2001 From: Shreshtha Kumar Sahu Date: Tue, 22 Mar 2011 16:30:16 -0700 Subject: leds: add driver for LM3530 ALS Simple backlight driver for National Semiconductor LM3530. Presently only manual mode is supported, PWM and ALS support to be added. Signed-off-by: Shreshtha Kumar Sahu Cc: Linus Walleij Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/Kconfig | 10 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-lm3530.c | 378 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 389 insertions(+) create mode 100644 drivers/leds/leds-lm3530.c (limited to 'drivers') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6f190f4cdbc0..9bec8699b8a3 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -34,6 +34,16 @@ config LEDS_ATMEL_PWM This option enables support for LEDs driven using outputs of the dedicated PWM controller found on newer Atmel SOCs. +config LEDS_LM3530 + tristate "LCD Backlight driver for LM3530" + depends on LEDS_CLASS + depends on I2C + help + This option enables support for the LCD backlight using + LM3530 ambient light sensor chip. This ALS chip can be + controlled manually or using PWM input or using ambient + light automatically. + config LEDS_LOCOMO tristate "LED Support for Locomo device" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index aae6989ff6b6..39c80fca84d2 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o +obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o obj-$(CONFIG_LEDS_MIKROTIK_RB532) += leds-rb532.o obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c new file mode 100644 index 000000000000..e7089a1f6cb6 --- /dev/null +++ b/drivers/leds/leds-lm3530.c @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2011 ST-Ericsson SA. + * Copyright (C) 2009 Motorola, Inc. + * + * License Terms: GNU General Public License v2 + * + * Simple driver for National Semiconductor LM3530 Backlight driver chip + * + * Author: Shreshtha Kumar SAHU + * based on leds-lm3530.c by Dan Murphy + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LM3530_LED_DEV "lcd-backlight" +#define LM3530_NAME "lm3530-led" + +#define LM3530_GEN_CONFIG 0x10 +#define LM3530_ALS_CONFIG 0x20 +#define LM3530_BRT_RAMP_RATE 0x30 +#define LM3530_ALS_ZONE_REG 0x40 +#define LM3530_ALS_IMP_SELECT 0x41 +#define LM3530_BRT_CTRL_REG 0xA0 +#define LM3530_ALS_ZB0_REG 0x60 +#define LM3530_ALS_ZB1_REG 0x61 +#define LM3530_ALS_ZB2_REG 0x62 +#define LM3530_ALS_ZB3_REG 0x63 +#define LM3530_ALS_Z0T_REG 0x70 +#define LM3530_ALS_Z1T_REG 0x71 +#define LM3530_ALS_Z2T_REG 0x72 +#define LM3530_ALS_Z3T_REG 0x73 +#define LM3530_ALS_Z4T_REG 0x74 +#define LM3530_REG_MAX 15 + +/* General Control Register */ +#define LM3530_EN_I2C_SHIFT (0) +#define LM3530_RAMP_LAW_SHIFT (1) +#define LM3530_MAX_CURR_SHIFT (2) +#define LM3530_EN_PWM_SHIFT (5) +#define LM3530_PWM_POL_SHIFT (6) +#define LM3530_EN_PWM_SIMPLE_SHIFT (7) + +#define LM3530_ENABLE_I2C (1 << LM3530_EN_I2C_SHIFT) +#define LM3530_ENABLE_PWM (1 << LM3530_EN_PWM_SHIFT) +#define LM3530_POL_LOW (1 << LM3530_PWM_POL_SHIFT) +#define LM3530_ENABLE_PWM_SIMPLE (1 << LM3530_EN_PWM_SIMPLE_SHIFT) + +/* ALS Config Register Options */ +#define LM3530_ALS_AVG_TIME_SHIFT (0) +#define LM3530_EN_ALS_SHIFT (3) +#define LM3530_ALS_SEL_SHIFT (5) + +#define LM3530_ENABLE_ALS (3 << LM3530_EN_ALS_SHIFT) + +/* Brightness Ramp Rate Register */ +#define LM3530_BRT_RAMP_FALL_SHIFT (0) +#define LM3530_BRT_RAMP_RISE_SHIFT (3) + +/* ALS Resistor Select */ +#define LM3530_ALS1_IMP_SHIFT (0) +#define LM3530_ALS2_IMP_SHIFT (4) + +/* Zone Boundary Register defaults */ +#define LM3530_DEF_ZB_0 (0x33) +#define LM3530_DEF_ZB_1 (0x66) +#define LM3530_DEF_ZB_2 (0x99) +#define LM3530_DEF_ZB_3 (0xCC) + +/* Zone Target Register defaults */ +#define LM3530_DEF_ZT_0 (0x19) +#define LM3530_DEF_ZT_1 (0x33) +#define LM3530_DEF_ZT_2 (0x4C) +#define LM3530_DEF_ZT_3 (0x66) +#define LM3530_DEF_ZT_4 (0x7F) + +struct lm3530_mode_map { + const char *mode; + enum lm3530_mode mode_val; +}; + +static struct lm3530_mode_map mode_map[] = { + { "man", LM3530_BL_MODE_MANUAL }, + { "als", LM3530_BL_MODE_ALS }, + { "pwm", LM3530_BL_MODE_PWM }, +}; + +/** + * struct lm3530_data + * @led_dev: led class device + * @client: i2c client + * @pdata: LM3530 platform data + * @mode: mode of operation - manual, ALS, PWM + */ +struct lm3530_data { + struct led_classdev led_dev; + struct i2c_client *client; + struct lm3530_platform_data *pdata; + enum lm3530_mode mode; +}; + +static const u8 lm3530_reg[LM3530_REG_MAX] = { + LM3530_GEN_CONFIG, + LM3530_ALS_CONFIG, + LM3530_BRT_RAMP_RATE, + LM3530_ALS_ZONE_REG, + LM3530_ALS_IMP_SELECT, + LM3530_BRT_CTRL_REG, + LM3530_ALS_ZB0_REG, + LM3530_ALS_ZB1_REG, + LM3530_ALS_ZB2_REG, + LM3530_ALS_ZB3_REG, + LM3530_ALS_Z0T_REG, + LM3530_ALS_Z1T_REG, + LM3530_ALS_Z2T_REG, + LM3530_ALS_Z3T_REG, + LM3530_ALS_Z4T_REG, +}; + +static int lm3530_get_mode_from_str(const char *str) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mode_map); i++) + if (sysfs_streq(str, mode_map[i].mode)) + return mode_map[i].mode_val; + + return -1; +} + +static int lm3530_init_registers(struct lm3530_data *drvdata) +{ + int ret = 0; + int i; + u8 gen_config; + u8 als_config = 0; + u8 brt_ramp; + u8 als_imp_sel = 0; + u8 brightness; + u8 reg_val[LM3530_REG_MAX]; + struct lm3530_platform_data *pltfm = drvdata->pdata; + struct i2c_client *client = drvdata->client; + + gen_config = (pltfm->brt_ramp_law << LM3530_RAMP_LAW_SHIFT) | + ((pltfm->max_current & 7) << LM3530_MAX_CURR_SHIFT); + + if (drvdata->mode == LM3530_BL_MODE_MANUAL || + drvdata->mode == LM3530_BL_MODE_ALS) + gen_config |= (LM3530_ENABLE_I2C); + + if (drvdata->mode == LM3530_BL_MODE_ALS) { + als_config = + (pltfm->als_avrg_time << LM3530_ALS_AVG_TIME_SHIFT) | + (LM3530_ENABLE_ALS) | + (pltfm->als_input_mode << LM3530_ALS_SEL_SHIFT); + + als_imp_sel = + (pltfm->als1_resistor_sel << LM3530_ALS1_IMP_SHIFT) | + (pltfm->als2_resistor_sel << LM3530_ALS2_IMP_SHIFT); + } + + if (drvdata->mode == LM3530_BL_MODE_PWM) + gen_config |= (LM3530_ENABLE_PWM) | + (pltfm->pwm_pol_hi << LM3530_PWM_POL_SHIFT) | + (LM3530_ENABLE_PWM_SIMPLE); + + brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) | + (pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT); + + brightness = pltfm->brt_val; + + reg_val[0] = gen_config; /* LM3530_GEN_CONFIG */ + reg_val[1] = als_config; /* LM3530_ALS_CONFIG */ + reg_val[2] = brt_ramp; /* LM3530_BRT_RAMP_RATE */ + reg_val[3] = 0x00; /* LM3530_ALS_ZONE_REG */ + reg_val[4] = als_imp_sel; /* LM3530_ALS_IMP_SELECT */ + reg_val[5] = brightness; /* LM3530_BRT_CTRL_REG */ + reg_val[6] = LM3530_DEF_ZB_0; /* LM3530_ALS_ZB0_REG */ + reg_val[7] = LM3530_DEF_ZB_1; /* LM3530_ALS_ZB1_REG */ + reg_val[8] = LM3530_DEF_ZB_2; /* LM3530_ALS_ZB2_REG */ + reg_val[9] = LM3530_DEF_ZB_3; /* LM3530_ALS_ZB3_REG */ + reg_val[10] = LM3530_DEF_ZT_0; /* LM3530_ALS_Z0T_REG */ + reg_val[11] = LM3530_DEF_ZT_1; /* LM3530_ALS_Z1T_REG */ + reg_val[12] = LM3530_DEF_ZT_2; /* LM3530_ALS_Z2T_REG */ + reg_val[13] = LM3530_DEF_ZT_3; /* LM3530_ALS_Z3T_REG */ + reg_val[14] = LM3530_DEF_ZT_4; /* LM3530_ALS_Z4T_REG */ + + for (i = 0; i < LM3530_REG_MAX; i++) { + ret = i2c_smbus_write_byte_data(client, + lm3530_reg[i], reg_val[i]); + if (ret) + break; + } + + return ret; +} + +static void lm3530_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brt_val) +{ + int err; + struct lm3530_data *drvdata = + container_of(led_cdev, struct lm3530_data, led_dev); + + switch (drvdata->mode) { + case LM3530_BL_MODE_MANUAL: + + /* set the brightness in brightness control register*/ + err = i2c_smbus_write_byte_data(drvdata->client, + LM3530_BRT_CTRL_REG, brt_val / 2); + if (err) + dev_err(&drvdata->client->dev, + "Unable to set brightness: %d\n", err); + break; + case LM3530_BL_MODE_ALS: + break; + case LM3530_BL_MODE_PWM: + break; + default: + break; + } +} + + +static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute + *attr, const char *buf, size_t size) +{ + int err; + struct i2c_client *client = container_of( + dev->parent, struct i2c_client, dev); + struct lm3530_data *drvdata = i2c_get_clientdata(client); + int mode; + + mode = lm3530_get_mode_from_str(buf); + if (mode < 0) { + dev_err(dev, "Invalid mode\n"); + return -EINVAL; + } + + if (mode == LM3530_BL_MODE_MANUAL) + drvdata->mode = LM3530_BL_MODE_MANUAL; + else if (mode == LM3530_BL_MODE_ALS) + drvdata->mode = LM3530_BL_MODE_ALS; + else if (mode == LM3530_BL_MODE_PWM) { + dev_err(dev, "PWM mode not supported\n"); + return -EINVAL; + } + + err = lm3530_init_registers(drvdata); + if (err) { + dev_err(dev, "Setting %s Mode failed :%d\n", buf, err); + return err; + } + + return sizeof(drvdata->mode); +} + +static DEVICE_ATTR(mode, 0644, NULL, lm3530_mode_set); + +static int __devinit lm3530_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm3530_platform_data *pdata = client->dev.platform_data; + struct lm3530_data *drvdata; + int err = 0; + + if (pdata == NULL) { + dev_err(&client->dev, "platform data required\n"); + err = -ENODEV; + goto err_out; + } + + /* BL mode */ + if (pdata->mode > LM3530_BL_MODE_PWM) { + dev_err(&client->dev, "Illegal Mode request\n"); + err = -EINVAL; + goto err_out; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "I2C_FUNC_I2C not supported\n"); + err = -EIO; + goto err_out; + } + + drvdata = kzalloc(sizeof(struct lm3530_data), GFP_KERNEL); + if (drvdata == NULL) { + err = -ENOMEM; + goto err_out; + } + + drvdata->mode = pdata->mode; + drvdata->client = client; + drvdata->pdata = pdata; + drvdata->led_dev.name = LM3530_LED_DEV; + drvdata->led_dev.brightness_set = lm3530_brightness_set; + + i2c_set_clientdata(client, drvdata); + + err = lm3530_init_registers(drvdata); + if (err < 0) { + dev_err(&client->dev, "Register Init failed: %d\n", err); + err = -ENODEV; + goto err_reg_init; + } + + err = led_classdev_register((struct device *) + &client->dev, &drvdata->led_dev); + if (err < 0) { + dev_err(&client->dev, "Register led class failed: %d\n", err); + err = -ENODEV; + goto err_class_register; + } + + err = device_create_file(drvdata->led_dev.dev, &dev_attr_mode); + if (err < 0) { + dev_err(&client->dev, "File device creation failed: %d\n", err); + err = -ENODEV; + goto err_create_file; + } + + return 0; + +err_create_file: + led_classdev_unregister(&drvdata->led_dev); +err_class_register: +err_reg_init: + kfree(drvdata); +err_out: + return err; +} + +static int __devexit lm3530_remove(struct i2c_client *client) +{ + struct lm3530_data *drvdata = i2c_get_clientdata(client); + + device_remove_file(drvdata->led_dev.dev, &dev_attr_mode); + led_classdev_unregister(&drvdata->led_dev); + kfree(drvdata); + return 0; +} + +static const struct i2c_device_id lm3530_id[] = { + {LM3530_NAME, 0}, + {} +}; + +static struct i2c_driver lm3530_i2c_driver = { + .probe = lm3530_probe, + .remove = lm3530_remove, + .id_table = lm3530_id, + .driver = { + .name = LM3530_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init lm3530_init(void) +{ + return i2c_add_driver(&lm3530_i2c_driver); +} + +static void __exit lm3530_exit(void) +{ + i2c_del_driver(&lm3530_i2c_driver); +} + +module_init(lm3530_init); +module_exit(lm3530_exit); + +MODULE_DESCRIPTION("Back Light driver for LM3530"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Shreshtha Kumar SAHU "); -- cgit v1.2.2 From 9517f925f2eb9ffca78b3f0f9389fc675bcb572c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 22 Mar 2011 16:30:17 -0700 Subject: leds: make *struct gpio_led_platform_data.leds const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And fix a typo. Signed-off-by: Uwe Kleine-König Cc: Lars-Peter Clausen Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-net5501.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/leds/leds-net5501.c b/drivers/leds/leds-net5501.c index 1739557a9038..7e764b8365e6 100644 --- a/drivers/leds/leds-net5501.c +++ b/drivers/leds/leds-net5501.c @@ -19,7 +19,7 @@ #include -static struct gpio_led net5501_leds[] = { +static const struct gpio_led net5501_leds[] = { { .name = "error", .gpio = 6, -- cgit v1.2.2 From 1baf0eb3975ab56e29d57984b7bd6c9cd360dbf3 Mon Sep 17 00:00:00 2001 From: Donghwa Lee Date: Tue, 22 Mar 2011 16:30:18 -0700 Subject: drivers/vidfeo/backlight: ld9040 amoled driver support Add a ld9040 amoled panel driver. Signed-off-by: Donghwa Lee Signed-off-by: Kyungmin Park Signed-off-by: Inki Dae Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 8 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/ld9040.c | 819 +++++++++++++++++++++++++++++++++ drivers/video/backlight/ld9040_gamma.h | 200 ++++++++ 4 files changed, 1028 insertions(+) create mode 100644 drivers/video/backlight/ld9040.c create mode 100644 drivers/video/backlight/ld9040_gamma.h (limited to 'drivers') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index e54a337227ea..39a4cd258d5b 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -109,6 +109,14 @@ config LCD_S6E63M0 If you have an S6E63M0 LCD Panel, say Y to enable its LCD control driver. +config LCD_LD9040 + tristate "LD9040 AMOLED LCD Driver" + depends on SPI && BACKLIGHT_CLASS_DEVICE + default n + help + If you have an LD9040 Panel, say Y to enable its + control driver. + endif # LCD_CLASS_DEVICE # diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 44c0f81ad85d..457996c97f5f 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o +obj-$(CONFIG_LCD_LD9040) += ld9040.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c new file mode 100644 index 000000000000..7281b2506a67 --- /dev/null +++ b/drivers/video/backlight/ld9040.c @@ -0,0 +1,819 @@ +/* + * ld9040 AMOLED LCD panel driver. + * + * Copyright (c) 2011 Samsung Electronics + * Author: Donghwa Lee + * Derived from drivers/video/backlight/s6e63m0.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ld9040_gamma.h" + +#define SLEEPMSEC 0x1000 +#define ENDDEF 0x2000 +#define DEFMASK 0xFF00 +#define COMMAND_ONLY 0xFE +#define DATA_ONLY 0xFF + +#define MIN_BRIGHTNESS 0 +#define MAX_BRIGHTNESS 24 +#define power_is_on(pwr) ((pwr) <= FB_BLANK_NORMAL) + +struct ld9040 { + struct device *dev; + struct spi_device *spi; + unsigned int power; + unsigned int current_brightness; + + struct lcd_device *ld; + struct backlight_device *bd; + struct lcd_platform_data *lcd_pd; +}; + +static const unsigned short seq_swreset[] = { + 0x01, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_user_setting[] = { + 0xF0, 0x5A, + + DATA_ONLY, 0x5A, + ENDDEF, 0x00 +}; + +static const unsigned short seq_elvss_on[] = { + 0xB1, 0x0D, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x16, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gtcon[] = { + 0xF7, 0x09, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + ENDDEF, 0x00 +}; + +static const unsigned short seq_panel_condition[] = { + 0xF8, 0x05, + + DATA_ONLY, 0x65, + DATA_ONLY, 0x96, + DATA_ONLY, 0x71, + DATA_ONLY, 0x7D, + DATA_ONLY, 0x19, + DATA_ONLY, 0x3B, + DATA_ONLY, 0x0D, + DATA_ONLY, 0x19, + DATA_ONLY, 0x7E, + DATA_ONLY, 0x0D, + DATA_ONLY, 0xE2, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x7E, + DATA_ONLY, 0x7D, + DATA_ONLY, 0x07, + DATA_ONLY, 0x07, + DATA_ONLY, 0x20, + DATA_ONLY, 0x20, + DATA_ONLY, 0x20, + DATA_ONLY, 0x02, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gamma_set1[] = { + 0xF9, 0x00, + + DATA_ONLY, 0xA7, + DATA_ONLY, 0xB4, + DATA_ONLY, 0xAE, + DATA_ONLY, 0xBF, + DATA_ONLY, 0x00, + DATA_ONLY, 0x91, + DATA_ONLY, 0x00, + DATA_ONLY, 0xB2, + DATA_ONLY, 0xB4, + DATA_ONLY, 0xAA, + DATA_ONLY, 0xBB, + DATA_ONLY, 0x00, + DATA_ONLY, 0xAC, + DATA_ONLY, 0x00, + DATA_ONLY, 0xB3, + DATA_ONLY, 0xB1, + DATA_ONLY, 0xAA, + DATA_ONLY, 0xBC, + DATA_ONLY, 0x00, + DATA_ONLY, 0xB3, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gamma_ctrl[] = { + 0xFB, 0x02, + + DATA_ONLY, 0x5A, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gamma_start[] = { + 0xF9, COMMAND_ONLY, + + ENDDEF, 0x00 +}; + +static const unsigned short seq_apon[] = { + 0xF3, 0x00, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x0A, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_display_ctrl[] = { + 0xF2, 0x02, + + DATA_ONLY, 0x08, + DATA_ONLY, 0x08, + DATA_ONLY, 0x10, + DATA_ONLY, 0x10, + ENDDEF, 0x00 +}; + +static const unsigned short seq_manual_pwr[] = { + 0xB0, 0x04, + ENDDEF, 0x00 +}; + +static const unsigned short seq_pwr_ctrl[] = { + 0xF4, 0x0A, + + DATA_ONLY, 0x87, + DATA_ONLY, 0x25, + DATA_ONLY, 0x6A, + DATA_ONLY, 0x44, + DATA_ONLY, 0x02, + DATA_ONLY, 0x88, + ENDDEF, 0x00 +}; + +static const unsigned short seq_sleep_out[] = { + 0x11, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_sleep_in[] = { + 0x10, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_display_on[] = { + 0x29, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_display_off[] = { + 0x28, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vci1_1st_en[] = { + 0xF3, 0x10, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vl1_en[] = { + 0xF3, 0x11, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vl2_en[] = { + 0xF3, 0x13, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vci1_2nd_en[] = { + 0xF3, 0x33, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vl3_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vreg1_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x01, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vgh_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x11, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vgl_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x31, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vmos_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xB1, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vint_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xF1, + /* DATA_ONLY, 0x71, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_vbh_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xF9, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vbl_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFD, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gam_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_sd_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x80, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_gls_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x81, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_els_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x83, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_el_on[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x87, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data) +{ + u16 buf[1]; + struct spi_message msg; + + struct spi_transfer xfer = { + .len = 2, + .tx_buf = buf, + }; + + buf[0] = (addr << 8) | data; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(lcd->spi, &msg); +} + +static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address, + unsigned char command) +{ + int ret = 0; + + if (address != DATA_ONLY) + ret = ld9040_spi_write_byte(lcd, 0x0, address); + if (command != COMMAND_ONLY) + ret = ld9040_spi_write_byte(lcd, 0x1, command); + + return ret; +} + +static int ld9040_panel_send_sequence(struct ld9040 *lcd, + const unsigned short *wbuf) +{ + int ret = 0, i = 0; + + while ((wbuf[i] & DEFMASK) != ENDDEF) { + if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { + ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]); + if (ret) + break; + } else + udelay(wbuf[i+1]*1000); + i += 2; + } + + return ret; +} + +static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma) +{ + unsigned int i = 0; + int ret = 0; + + /* start gamma table updating. */ + ret = ld9040_panel_send_sequence(lcd, seq_gamma_start); + if (ret) { + dev_err(lcd->dev, "failed to disable gamma table updating.\n"); + goto gamma_err; + } + + for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) { + ret = ld9040_spi_write(lcd, DATA_ONLY, gamma[i]); + if (ret) { + dev_err(lcd->dev, "failed to set gamma table.\n"); + goto gamma_err; + } + } + + /* update gamma table. */ + ret = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl); + if (ret) + dev_err(lcd->dev, "failed to update gamma table.\n"); + +gamma_err: + return ret; +} + +static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma) +{ + int ret = 0; + + ret = _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); + + return ret; +} + + +static int ld9040_ldi_init(struct ld9040 *lcd) +{ + int ret, i; + static const unsigned short *init_seq[] = { + seq_user_setting, + seq_panel_condition, + seq_display_ctrl, + seq_manual_pwr, + seq_elvss_on, + seq_gtcon, + seq_gamma_set1, + seq_gamma_ctrl, + seq_sleep_out, + }; + + for (i = 0; i < ARRAY_SIZE(init_seq); i++) { + ret = ld9040_panel_send_sequence(lcd, init_seq[i]); + /* workaround: minimum delay time for transferring CMD */ + udelay(300); + if (ret) + break; + } + + return ret; +} + +static int ld9040_ldi_enable(struct ld9040 *lcd) +{ + int ret = 0; + + ret = ld9040_panel_send_sequence(lcd, seq_display_on); + + return ret; +} + +static int ld9040_ldi_disable(struct ld9040 *lcd) +{ + int ret; + + ret = ld9040_panel_send_sequence(lcd, seq_display_off); + ret = ld9040_panel_send_sequence(lcd, seq_sleep_in); + + return ret; +} + +static int ld9040_power_on(struct ld9040 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd = NULL; + pd = lcd->lcd_pd; + if (!pd) { + dev_err(lcd->dev, "platform data is NULL.\n"); + return -EFAULT; + } + + if (!pd->power_on) { + dev_err(lcd->dev, "power_on is NULL.\n"); + return -EFAULT; + } else { + pd->power_on(lcd->ld, 1); + mdelay(pd->power_on_delay); + } + + if (!pd->reset) { + dev_err(lcd->dev, "reset is NULL.\n"); + return -EFAULT; + } else { + pd->reset(lcd->ld); + mdelay(pd->reset_delay); + } + + ret = ld9040_ldi_init(lcd); + if (ret) { + dev_err(lcd->dev, "failed to initialize ldi.\n"); + return ret; + } + + ret = ld9040_ldi_enable(lcd); + if (ret) { + dev_err(lcd->dev, "failed to enable ldi.\n"); + return ret; + } + + return 0; +} + +static int ld9040_power_off(struct ld9040 *lcd) +{ + int ret = 0; + struct lcd_platform_data *pd = NULL; + + pd = lcd->lcd_pd; + if (!pd) { + dev_err(lcd->dev, "platform data is NULL.\n"); + return -EFAULT; + } + + ret = ld9040_ldi_disable(lcd); + if (ret) { + dev_err(lcd->dev, "lcd setting failed.\n"); + return -EIO; + } + + mdelay(pd->power_off_delay); + + if (!pd->power_on) { + dev_err(lcd->dev, "power_on is NULL.\n"); + return -EFAULT; + } else + pd->power_on(lcd->ld, 0); + + return 0; +} + +static int ld9040_power(struct ld9040 *lcd, int power) +{ + int ret = 0; + + if (power_is_on(power) && !power_is_on(lcd->power)) + ret = ld9040_power_on(lcd); + else if (!power_is_on(power) && power_is_on(lcd->power)) + ret = ld9040_power_off(lcd); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int ld9040_set_power(struct lcd_device *ld, int power) +{ + struct ld9040 *lcd = lcd_get_data(ld); + + if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN && + power != FB_BLANK_NORMAL) { + dev_err(lcd->dev, "power value should be 0, 1 or 4.\n"); + return -EINVAL; + } + + return ld9040_power(lcd, power); +} + +static int ld9040_get_power(struct lcd_device *ld) +{ + struct ld9040 *lcd = lcd_get_data(ld); + + return lcd->power; +} + +static int ld9040_get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + +static int ld9040_set_brightness(struct backlight_device *bd) +{ + int ret = 0, brightness = bd->props.brightness; + struct ld9040 *lcd = bl_get_data(bd); + + if (brightness < MIN_BRIGHTNESS || + brightness > bd->props.max_brightness) { + dev_err(&bd->dev, "lcd brightness should be %d to %d.\n", + MIN_BRIGHTNESS, MAX_BRIGHTNESS); + return -EINVAL; + } + + ret = ld9040_gamma_ctl(lcd, bd->props.brightness); + if (ret) { + dev_err(&bd->dev, "lcd brightness setting failed.\n"); + return -EIO; + } + + return ret; +} + +static struct lcd_ops ld9040_lcd_ops = { + .set_power = ld9040_set_power, + .get_power = ld9040_get_power, +}; + +static const struct backlight_ops ld9040_backlight_ops = { + .get_brightness = ld9040_get_brightness, + .update_status = ld9040_set_brightness, +}; + + +static int ld9040_probe(struct spi_device *spi) +{ + int ret = 0; + struct ld9040 *lcd = NULL; + struct lcd_device *ld = NULL; + struct backlight_device *bd = NULL; + + lcd = kzalloc(sizeof(struct ld9040), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + /* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */ + spi->bits_per_word = 9; + + ret = spi_setup(spi); + if (ret < 0) { + dev_err(&spi->dev, "spi setup failed.\n"); + goto out_free_lcd; + } + + lcd->spi = spi; + lcd->dev = &spi->dev; + + lcd->lcd_pd = spi->dev.platform_data; + if (!lcd->lcd_pd) { + dev_err(&spi->dev, "platform data is NULL.\n"); + goto out_free_lcd; + } + + ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + + lcd->ld = ld; + + bd = backlight_device_register("ld9040-bl", &spi->dev, + lcd, &ld9040_backlight_ops, NULL); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + + bd->props.max_brightness = MAX_BRIGHTNESS; + bd->props.brightness = MAX_BRIGHTNESS; + lcd->bd = bd; + + /* + * if lcd panel was on from bootloader like u-boot then + * do not lcd on. + */ + if (!lcd->lcd_pd->lcd_enabled) { + /* + * if lcd panel was off from bootloader then + * current lcd status is powerdown and then + * it enables lcd panel. + */ + lcd->power = FB_BLANK_POWERDOWN; + + ld9040_power(lcd, FB_BLANK_UNBLANK); + } else + lcd->power = FB_BLANK_UNBLANK; + + dev_set_drvdata(&spi->dev, lcd); + + dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); + return 0; + +out_free_lcd: + kfree(lcd); + return ret; +} + +static int __devexit ld9040_remove(struct spi_device *spi) +{ + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + ld9040_power(lcd, FB_BLANK_POWERDOWN); + lcd_device_unregister(lcd->ld); + kfree(lcd); + + return 0; +} + +#if defined(CONFIG_PM) +static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg) +{ + int ret = 0; + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); + + /* + * when lcd panel is suspend, lcd panel becomes off + * regardless of status. + */ + ret = ld9040_power(lcd, FB_BLANK_POWERDOWN); + + return ret; +} + +static int ld9040_resume(struct spi_device *spi) +{ + int ret = 0; + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + lcd->power = FB_BLANK_POWERDOWN; + + ret = ld9040_power(lcd, FB_BLANK_UNBLANK); + + return ret; +} +#else +#define ld9040_suspend NULL +#define ld9040_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt. */ +static void ld9040_shutdown(struct spi_device *spi) +{ + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + ld9040_power(lcd, FB_BLANK_POWERDOWN); +} + +static struct spi_driver ld9040_driver = { + .driver = { + .name = "ld9040", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ld9040_probe, + .remove = __devexit_p(ld9040_remove), + .shutdown = ld9040_shutdown, + .suspend = ld9040_suspend, + .resume = ld9040_resume, +}; + +static int __init ld9040_init(void) +{ + return spi_register_driver(&ld9040_driver); +} + +static void __exit ld9040_exit(void) +{ + spi_unregister_driver(&ld9040_driver); +} + +module_init(ld9040_init); +module_exit(ld9040_exit); + +MODULE_AUTHOR("Donghwa Lee "); +MODULE_DESCRIPTION("ld9040 LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h new file mode 100644 index 000000000000..038d9c86ec03 --- /dev/null +++ b/drivers/video/backlight/ld9040_gamma.h @@ -0,0 +1,200 @@ +/* + * Gamma level definitions. + * + * Copyright (c) 2011 Samsung Electronics + * InKi Dae + * Donghwa Lee + * + * 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. +*/ + +#ifndef _LD9040_BRIGHTNESS_H +#define _LD9040_BRIGHTNESS_H + +#define MAX_GAMMA_LEVEL 25 +#define GAMMA_TABLE_COUNT 21 + +/* gamma value: 2.2 */ +static const unsigned int ld9040_22_300[] = { + 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91, + 0x00, 0xb2, 0xb4, 0xaa, 0xbb, 0x00, 0xac, + 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3 +}; + +static const unsigned int ld9040_22_290[] = { + 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89, + 0x00, 0xb7, 0xb6, 0xa8, 0xba, 0x00, 0xa4, + 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa +}; + +static const unsigned int ld9040_22_280[] = { + 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86, + 0x00, 0xb8, 0xb5, 0xa8, 0xbc, 0x00, 0xa0, + 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7 +}; + +static const unsigned int ld9040_22_270[] = { + 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84, + 0x00, 0xb9, 0xb7, 0xa8, 0xbc, 0x00, 0x9d, + 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4 + +}; +static const unsigned int ld9040_22_260[] = { + 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80, + 0x00, 0xb8, 0xb6, 0xaa, 0xbc, 0x00, 0x9a, + 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0 +}; + +static const unsigned int ld9040_22_250[] = { + 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d, + 0x00, 0xb9, 0xb6, 0xaa, 0xbb, 0x00, 0x97, + 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d +}; + +static const unsigned int ld9040_22_240[] = { + 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a, + 0x00, 0xb9, 0xb7, 0xaa, 0xbd, 0x00, 0x94, + 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a +}; + +static const unsigned int ld9040_22_230[] = { + 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77, + 0x00, 0xb9, 0xb7, 0xab, 0xbe, 0x00, 0x90, + 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97 +}; + +static const unsigned int ld9040_22_220[] = { + 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75, + 0x00, 0xb9, 0xb8, 0xab, 0xbe, 0x00, 0x8e, + 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94 +}; + +static const unsigned int ld9040_22_210[] = { + 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72, + 0x00, 0xb8, 0xb8, 0xac, 0xbf, 0x00, 0x8a, + 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91 +}; + +static const unsigned int ld9040_22_200[] = { + 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f, + 0x00, 0xb8, 0xb8, 0xad, 0xc0, 0x00, 0x86, + 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d +}; + +static const unsigned int ld9040_22_190[] = { + 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c, + 0x00, 0xb8, 0xb8, 0xae, 0xc1, 0x00, 0x82, + 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89 +}; + +static const unsigned int ld9040_22_180[] = { + 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69, + 0x00, 0xb8, 0xb9, 0xae, 0xc1, 0x00, 0x7f, + 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85 +}; + +static const unsigned int ld9040_22_170[] = { + 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65, + 0x00, 0xb7, 0xb8, 0xaf, 0xc3, 0x00, 0x7a, + 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81 +}; + +static const unsigned int ld9040_22_160[] = { + 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62, + 0x00, 0xb6, 0xba, 0xaf, 0xc3, 0x00, 0x76, + 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e +}; + +static const unsigned int ld9040_22_150[] = { + 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f, + 0x00, 0xb5, 0xba, 0xb0, 0xc3, 0x00, 0x72, + 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a +}; + +static const unsigned int ld9040_22_140[] = { + 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b, + 0x00, 0xb5, 0xba, 0xb1, 0xc4, 0x00, 0x6e, + 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75 +}; + +static const unsigned int ld9040_22_130[] = { + 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57, + 0x00, 0xb5, 0xbb, 0xb0, 0xc5, 0x00, 0x6a, + 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70 +}; + +static const unsigned int ld9040_22_120[] = { + 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53, + 0x00, 0xb5, 0xbb, 0xb3, 0xc6, 0x00, 0x65, + 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c +}; + +static const unsigned int ld9040_22_110[] = { + 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f, + 0x00, 0xb4, 0xbb, 0xb3, 0xc7, 0x00, 0x60, + 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67 +}; + +static const unsigned int ld9040_22_100[] = { + 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b, + 0x00, 0xb3, 0xbc, 0xb4, 0xc7, 0x00, 0x5c, + 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62 +}; + +static const unsigned int ld9040_22_90[] = { + 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46, + 0x00, 0xb1, 0xbc, 0xb5, 0xc8, 0x00, 0x56, + 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d +}; + +static const unsigned int ld9040_22_80[] = { + 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41, + 0x00, 0xb0, 0xbe, 0xb5, 0xc9, 0x00, 0x51, + 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57 +}; + +static const unsigned int ld9040_22_70[] = { + 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c, + 0x00, 0xaf, 0xbf, 0xb6, 0xcb, 0x00, 0x4b, + 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52 +}; + +static const unsigned int ld9040_22_50[] = { + 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30, + 0x00, 0xaf, 0xc0, 0xb8, 0xcd, 0x00, 0x3d, + 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44 +}; + +struct ld9040_gamma { + unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; +} gamma_table = { + .gamma_22_table[0] = (unsigned int *)&ld9040_22_50, + .gamma_22_table[1] = (unsigned int *)&ld9040_22_70, + .gamma_22_table[2] = (unsigned int *)&ld9040_22_80, + .gamma_22_table[3] = (unsigned int *)&ld9040_22_90, + .gamma_22_table[4] = (unsigned int *)&ld9040_22_100, + .gamma_22_table[5] = (unsigned int *)&ld9040_22_110, + .gamma_22_table[6] = (unsigned int *)&ld9040_22_120, + .gamma_22_table[7] = (unsigned int *)&ld9040_22_130, + .gamma_22_table[8] = (unsigned int *)&ld9040_22_140, + .gamma_22_table[9] = (unsigned int *)&ld9040_22_150, + .gamma_22_table[10] = (unsigned int *)&ld9040_22_160, + .gamma_22_table[11] = (unsigned int *)&ld9040_22_170, + .gamma_22_table[12] = (unsigned int *)&ld9040_22_180, + .gamma_22_table[13] = (unsigned int *)&ld9040_22_190, + .gamma_22_table[14] = (unsigned int *)&ld9040_22_200, + .gamma_22_table[15] = (unsigned int *)&ld9040_22_210, + .gamma_22_table[16] = (unsigned int *)&ld9040_22_220, + .gamma_22_table[17] = (unsigned int *)&ld9040_22_230, + .gamma_22_table[18] = (unsigned int *)&ld9040_22_240, + .gamma_22_table[19] = (unsigned int *)&ld9040_22_250, + .gamma_22_table[20] = (unsigned int *)&ld9040_22_260, + .gamma_22_table[21] = (unsigned int *)&ld9040_22_270, + .gamma_22_table[22] = (unsigned int *)&ld9040_22_280, + .gamma_22_table[23] = (unsigned int *)&ld9040_22_290, + .gamma_22_table[24] = (unsigned int *)&ld9040_22_300, +}; + +#endif -- cgit v1.2.2 From 67d1da79b25c05d9a38b820bb5b5d89c91070ab2 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Tue, 22 Mar 2011 16:30:19 -0700 Subject: drivers/leds/leds-lp5521.c: world-writable sysfs engine* files Don't allow everybody to change LED settings. Signed-off-by: Vasiliy Kulikov Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-lp5521.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 80a3ae3c00b9..c0cff64a1ae6 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -534,7 +534,7 @@ static ssize_t lp5521_selftest(struct device *dev, } /* led class device attributes */ -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); +static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current); static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL); static struct attribute *lp5521_led_attributes[] = { @@ -548,15 +548,15 @@ static struct attribute_group lp5521_led_attribute_group = { }; /* device attributes */ -static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR, show_engine1_mode, store_engine1_mode); -static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR, show_engine2_mode, store_engine2_mode); -static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR, show_engine3_mode, store_engine3_mode); -static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load); -static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load); -static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load); +static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load); +static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load); +static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load); static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL); static struct attribute *lp5521_attributes[] = { -- cgit v1.2.2 From ccd7510fd8dea5b4b2af87fb2aef2ebd6b23b76b Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Tue, 22 Mar 2011 16:30:20 -0700 Subject: drivers/leds/leds-lp5523.c: world-writable engine* sysfs files Don't allow everybody to change LED settings. Signed-off-by: Vasiliy Kulikov Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-lp5523.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index d0c4068ecddd..e19fed25f137 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -713,7 +713,7 @@ static ssize_t store_current(struct device *dev, } /* led class device attributes */ -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); +static DEVICE_ATTR(led_current, S_IRUGO | S_IWUSR, show_current, store_current); static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL); static struct attribute *lp5523_led_attributes[] = { @@ -727,21 +727,21 @@ static struct attribute_group lp5523_led_attribute_group = { }; /* device attributes */ -static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUSR, show_engine1_mode, store_engine1_mode); -static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUSR, show_engine2_mode, store_engine2_mode); -static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUSR, show_engine3_mode, store_engine3_mode); -static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUSR, show_engine1_leds, store_engine1_leds); -static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUSR, show_engine2_leds, store_engine2_leds); -static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUSR, show_engine3_leds, store_engine3_leds); -static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load); -static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load); -static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load); +static DEVICE_ATTR(engine1_load, S_IWUSR, NULL, store_engine1_load); +static DEVICE_ATTR(engine2_load, S_IWUSR, NULL, store_engine2_load); +static DEVICE_ATTR(engine3_load, S_IWUSR, NULL, store_engine3_load); static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL); static struct attribute *lp5523_attributes[] = { -- cgit v1.2.2 From bb7ca747f8d6243b3943c5b133048652020f4a50 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 22 Mar 2011 16:30:21 -0700 Subject: backlight: add backlight type There may be multiple ways of controlling the backlight on a given machine. Allow drivers to expose the type of interface they are providing, making it possible for userspace to make appropriate policy decisions. Signed-off-by: Matthew Garrett Cc: Richard Purdie Cc: Chris Wilson Cc: David Airlie Cc: Alex Deucher Cc: Ben Skeggs Cc: Zhang Rui Cc: Len Brown Cc: Jesse Barnes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/video.c | 1 + drivers/gpu/drm/nouveau/nouveau_backlight.c | 2 ++ drivers/hid/hid-picolcd.c | 1 + drivers/macintosh/via-pmu-backlight.c | 1 + drivers/platform/x86/acer-wmi.c | 1 + drivers/platform/x86/asus-laptop.c | 1 + drivers/platform/x86/asus_acpi.c | 1 + drivers/platform/x86/classmate-laptop.c | 1 + drivers/platform/x86/compal-laptop.c | 1 + drivers/platform/x86/dell-laptop.c | 1 + drivers/platform/x86/eeepc-laptop.c | 1 + drivers/platform/x86/fujitsu-laptop.c | 1 + drivers/platform/x86/msi-laptop.c | 1 + drivers/platform/x86/msi-wmi.c | 1 + drivers/platform/x86/panasonic-laptop.c | 1 + drivers/platform/x86/sony-laptop.c | 3 ++- drivers/platform/x86/thinkpad_acpi.c | 1 + drivers/platform/x86/toshiba_acpi.c | 1 + drivers/staging/olpc_dcon/olpc_dcon.c | 1 + drivers/staging/samsung-laptop/samsung-laptop.c | 1 + drivers/usb/misc/appledisplay.c | 1 + drivers/video/atmel_lcdfb.c | 1 + drivers/video/aty/aty128fb.c | 1 + drivers/video/aty/atyfb_base.c | 1 + drivers/video/aty/radeon_backlight.c | 1 + drivers/video/backlight/88pm860x_bl.c | 1 + drivers/video/backlight/adp5520_bl.c | 1 + drivers/video/backlight/adp8860_bl.c | 1 + drivers/video/backlight/adx_bl.c | 1 + drivers/video/backlight/atmel-pwm-bl.c | 1 + drivers/video/backlight/backlight.c | 24 +++++++++++++++++++++- drivers/video/backlight/corgi_lcd.c | 1 + drivers/video/backlight/cr_bllcd.c | 1 + drivers/video/backlight/da903x_bl.c | 1 + drivers/video/backlight/ep93xx_bl.c | 1 + drivers/video/backlight/generic_bl.c | 1 + drivers/video/backlight/hp680_bl.c | 1 + drivers/video/backlight/jornada720_bl.c | 1 + drivers/video/backlight/kb3886_bl.c | 1 + drivers/video/backlight/locomolcd.c | 1 + drivers/video/backlight/max8925_bl.c | 1 + drivers/video/backlight/mbp_nvidia_bl.c | 1 + drivers/video/backlight/omap1_bl.c | 1 + drivers/video/backlight/pcf50633-backlight.c | 1 + drivers/video/backlight/progear_bl.c | 1 + drivers/video/backlight/pwm_bl.c | 1 + drivers/video/backlight/s6e63m0.c | 1 + drivers/video/backlight/tosa_bl.c | 1 + drivers/video/backlight/wm831x_bl.c | 1 + drivers/video/bf54x-lq043fb.c | 1 + drivers/video/bfin-t350mcqb-fb.c | 1 + drivers/video/imxfb.c | 1 + drivers/video/nvidia/nv_backlight.c | 1 + drivers/video/omap2/displays/panel-acx565akm.c | 1 + .../video/omap2/displays/panel-sharp-ls037v7dw01.c | 1 + drivers/video/omap2/displays/panel-taal.c | 2 ++ drivers/video/riva/fbdev.c | 1 + 57 files changed, 82 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 90f8f7676d1f..a9eec8c95a1f 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -795,6 +795,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) count++; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_FIRMWARE; props.max_brightness = device->brightness->count - 3; device->backlight = backlight_device_register(name, NULL, device, &acpi_backlight_ops, diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index d3a9c6e02477..18d7bcc54ce0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -98,6 +98,7 @@ static int nouveau_nv40_backlight_init(struct drm_device *dev) return 0; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 31; bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev, &nv40_bl_ops, &props); @@ -121,6 +122,7 @@ static int nouveau_nv50_backlight_init(struct drm_device *dev) return 0; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 1025; bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev, &nv50_bl_ops, &props); diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index de9cf21b3494..657da5a3d5c6 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -944,6 +944,7 @@ static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report * } memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; bdev = backlight_device_register(dev_name(dev), dev, data, &picolcd_blops, &props); diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index ade1e656bfb2..b1d91170ded0 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -163,6 +163,7 @@ void __init pmu_backlight_init() snprintf(name, sizeof(name), "pmubl"); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, NULL, NULL, &pmu_backlight_data, &props); diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index ad3d099bf5c1..c9784705f6ac 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1031,6 +1031,7 @@ static int __devinit acer_backlight_init(struct device *dev) struct backlight_device *bd; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = max_brightness; bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, &props); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index f3aa6a7fdab6..5a6f7d7575d6 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -667,6 +667,7 @@ static int asus_backlight_init(struct asus_laptop *asus) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 15; + props.type = BACKLIGHT_PLATFORM; bd = backlight_device_register(ASUS_LAPTOP_FILE, &asus->platform_device->dev, asus, diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index fe495939c307..f503607c0645 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c @@ -1507,6 +1507,7 @@ static int __init asus_acpi_init(void) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = 15; asus_backlight_device = backlight_device_register("asus", NULL, NULL, &asus_backlight_data, diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 911135425224..94f93b621d7b 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -564,6 +564,7 @@ static int cmpc_ipml_add(struct acpi_device *acpi) return -ENOMEM; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = 7; ipml->bd = backlight_device_register("cmpc_bl", &acpi->dev, acpi->handle, &cmpc_bl_ops, diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 034572b980c9..eb95878fa583 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -970,6 +970,7 @@ static int __init compal_init(void) if (!acpi_video_backlight_support()) { struct backlight_properties props; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = BACKLIGHT_LEVEL_MAX; compalbl_device = backlight_device_register(DRIVER_NAME, NULL, NULL, diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index ad24ef36f9f7..de301aa8e5c3 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -671,6 +671,7 @@ static int __init dell_init(void) if (max_intensity) { struct backlight_properties props; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = max_intensity; dell_backlight_device = backlight_device_register("dell_backlight", &platform_device->dev, diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 49d9ad708f89..6605beac0d0e 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1147,6 +1147,7 @@ static int eeepc_backlight_init(struct eeepc_laptop *eeepc) struct backlight_device *bd; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = 15; bd = backlight_device_register(EEEPC_LAPTOP_FILE, &eeepc->platform_device->dev, eeepc, diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 95e3b0948e9c..493054c2dbe1 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -1128,6 +1128,7 @@ static int __init fujitsu_init(void) memset(&props, 0, sizeof(struct backlight_properties)); max_brightness = fujitsu->max_brightness; + props.type = BACKLIGHT_PLATFORM; props.max_brightness = max_brightness - 1; fujitsu->bl_device = backlight_device_register("fujitsu-laptop", NULL, NULL, diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 7e9bb6df9d39..142d38579314 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -804,6 +804,7 @@ static int __init msi_init(void) } else { struct backlight_properties props; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = MSI_LCD_LEVEL_MAX - 1; msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL, &msibl_ops, diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c index 35278ad7e628..d5419c9ec07a 100644 --- a/drivers/platform/x86/msi-wmi.c +++ b/drivers/platform/x86/msi-wmi.c @@ -254,6 +254,7 @@ static int __init msi_wmi_init(void) if (!acpi_video_backlight_support()) { struct backlight_properties props; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = ARRAY_SIZE(backlight_map) - 1; backlight = backlight_device_register(DRV_NAME, NULL, NULL, &msi_backlight_ops, diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index cc1e0ba104d7..05be30ee158b 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -602,6 +602,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) } /* initialize backlight */ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT]; pcc->backlight = backlight_device_register("panasonic", NULL, pcc, &pcc_backlight_ops, &props); diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 5e83370b0812..13d8d63bcca9 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1305,8 +1305,9 @@ static int sony_nc_add(struct acpi_device *device) "controlled by ACPI video driver\n"); } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) { - struct backlight_properties props; + struct backlight_properties props; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = SONY_MAX_BRIGHTNESS - 1; sony_backlight_device = backlight_device_register("sony", NULL, NULL, diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index eb9922385ef8..947bdcaa0ce9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6307,6 +6307,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) return 1; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = bright_maxlvl; props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; ibm_backlight_device = backlight_device_register(TPACPI_BACKLIGHT_DEV_NAME, diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 209cced786c6..63f42a22e102 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1018,6 +1018,7 @@ static int __init toshiba_acpi_init(void) create_toshiba_proc_entries(); } + props.type = BACKLIGHT_PLATFORM; props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; toshiba_backlight_device = backlight_device_register("toshiba", &toshiba_acpi.p_dev->dev, diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index b90c2cf3e247..750fe5045efa 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -574,6 +574,7 @@ static const struct backlight_ops dcon_bl_ops = { static struct backlight_properties dcon_bl_props = { .max_brightness = 15, + .type = BACKLIGHT_RAW, .power = FB_BLANK_UNBLANK, }; diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c index 6607a89ccb4b..25294462b8b6 100644 --- a/drivers/staging/samsung-laptop/samsung-laptop.c +++ b/drivers/staging/samsung-laptop/samsung-laptop.c @@ -781,6 +781,7 @@ static int __init samsung_init(void) /* create a backlight device to talk to this one */ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = sabi_config->max_brightness; backlight_device = backlight_device_register("samsung", &sdev->dev, NULL, &backlight_ops, diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 1fa6ce3e4a23..68ab460a735c 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -282,6 +282,7 @@ static int appledisplay_probe(struct usb_interface *iface, snprintf(bl_name, sizeof(bl_name), "appledisplay%d", atomic_inc_return(&count_displays) - 1); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; pdata->bd = backlight_device_register(bl_name, NULL, pdata, &appledisplay_bl_data, &props); diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index bac163450216..4b4e8dadd6b2 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -127,6 +127,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) return; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo, &atmel_lcdc_bl_ops, &props); diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 4cb6a576c567..b0b2ac335347 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1818,6 +1818,7 @@ static void aty128_bl_init(struct aty128fb_par *par) snprintf(name, sizeof(name), "aty128bl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &aty128_bl_data, &props); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 94e293fce1d2..d437b3daf1f5 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2241,6 +2241,7 @@ static void aty_bl_init(struct atyfb_par *par) snprintf(name, sizeof(name), "atybl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &aty_bl_data, &props); diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 9b811ddbce83..db572df7e1ef 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -158,6 +158,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data, &props); diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index b224396b86d5..e59623a15f3f 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -227,6 +227,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; bl = backlight_device_register(name, &pdev->dev, data, &pm860x_backlight_ops, &props); diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index 9f436e014f85..af3119707dbf 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -303,6 +303,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) mutex_init(&data->lock); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = ADP5020_MAX_BRIGHTNESS; bl = backlight_device_register(pdev->name, data->master, data, &adp5520_bl_ops, &props); diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 734c650a47c4..d2a96a421ffd 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -709,6 +709,7 @@ static int __devinit adp8860_probe(struct i2c_client *client, i2c_set_clientdata(client, data); memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; props.max_brightness = ADP8860_MAX_BRIGHTNESS; mutex_init(&data->lock); diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c index fe9af129c5dd..c861c41af442 100644 --- a/drivers/video/backlight/adx_bl.c +++ b/drivers/video/backlight/adx_bl.c @@ -104,6 +104,7 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bl, &adx_backlight_ops, &props); diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index e6a66dab088c..0443a4f71858 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -168,6 +168,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min; bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl, &atmel_pwm_bl_ops, &props); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 08703299ef61..80d292fb92d8 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -19,6 +19,12 @@ #include #endif +static const char const *backlight_types[] = { + [BACKLIGHT_RAW] = "raw", + [BACKLIGHT_PLATFORM] = "platform", + [BACKLIGHT_FIRMWARE] = "firmware", +}; + #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) /* This callback gets called when something important happens inside a @@ -169,6 +175,14 @@ static ssize_t backlight_store_brightness(struct device *dev, return rc; } +static ssize_t backlight_show_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct backlight_device *bd = to_backlight_device(dev); + + return sprintf(buf, "%s\n", backlight_types[bd->props.type]); +} + static ssize_t backlight_show_max_brightness(struct device *dev, struct device_attribute *attr, char *buf) { @@ -234,6 +248,7 @@ static struct device_attribute bl_device_attributes[] = { __ATTR(actual_brightness, 0444, backlight_show_actual_brightness, NULL), __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), + __ATTR(type, 0444, backlight_show_type, NULL), __ATTR_NULL, }; @@ -292,9 +307,16 @@ struct backlight_device *backlight_device_register(const char *name, dev_set_drvdata(&new_bd->dev, devdata); /* Set default properties */ - if (props) + if (props) { memcpy(&new_bd->props, props, sizeof(struct backlight_properties)); + if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) { + WARN(1, "%s: invalid backlight type", name); + new_bd->props.type = BACKLIGHT_RAW; + } + } else { + new_bd->props.type = BACKLIGHT_RAW; + } rc = device_register(&new_bd->dev); if (rc) { diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index 1e71c35083bb..af6098396fe6 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -562,6 +562,7 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi) lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = pdata->max_intensity; lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd, &corgi_bl_ops, &props); diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 397d15eb1ea8..6c8c54041fae 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -193,6 +193,7 @@ static int cr_backlight_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL, &cr_backlight_ops, &props); if (IS_ERR(bdp)) { diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index 87659ed79bd7..62043f12a5a4 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -136,6 +136,7 @@ static int da903x_backlight_probe(struct platform_device *pdev) da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2, DA9034_WLED_ISET(pdata->output_current)); + props.type = BACKLIGHT_RAW; props.max_brightness = max_brightness; bl = backlight_device_register(pdev->name, data->da903x_dev, data, &da903x_backlight_ops, &props); diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index b0cc49184803..9f1e389d51d2 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -87,6 +87,7 @@ static int __init ep93xxbl_probe(struct platform_device *dev) ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = EP93XX_MAX_BRIGHT; bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl, &ep93xxbl_ops, &props); diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 312ca619735d..8c6befd65a33 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -91,6 +91,7 @@ static int genericbl_probe(struct platform_device *pdev) name = machinfo->name; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops, &props); diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 267d23f8d645..38aa00272141 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -109,6 +109,7 @@ static int __devinit hp680bl_probe(struct platform_device *pdev) struct backlight_device *bd; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = HP680_MAX_INTENSITY; bd = backlight_device_register("hp680-bl", &pdev->dev, NULL, &hp680bl_ops, &props); diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c index 2f177b3a4885..40e4fa8fcf92 100644 --- a/drivers/video/backlight/jornada720_bl.c +++ b/drivers/video/backlight/jornada720_bl.c @@ -106,6 +106,7 @@ static int jornada_bl_probe(struct platform_device *pdev) struct backlight_device *bd; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = BL_MAX_BRIGHT; bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_bl_ops, &props); diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index f439a8632287..72dd5556a35b 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -149,6 +149,7 @@ static int kb3886bl_probe(struct platform_device *pdev) machinfo->limit_mask = -1; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; kb3886_backlight_device = backlight_device_register("kb3886-bl", &pdev->dev, NULL, diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index d2f59015d517..bbca3127071e 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -184,6 +184,7 @@ static int locomolcd_probe(struct locomo_dev *ldev) local_irq_restore(flags); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 4; locomolcd_bl_device = backlight_device_register("locomo-bl", &ldev->dev, NULL, diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 209acc105cbc..07e8e273ced0 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -136,6 +136,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) data->current_brightness = 0; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; bl = backlight_device_register(name, &pdev->dev, data, &max8925_backlight_ops, &props); diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 1485f7345f49..74c33944aa86 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -367,6 +367,7 @@ static int __init mbp_init(void) return -ENXIO; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = 15; mbp_backlight_device = backlight_device_register("mbp_backlight", NULL, NULL, diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index d3bc56296c8d..08d26a72394c 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -146,6 +146,7 @@ static int omapbl_probe(struct platform_device *pdev) return -ENOMEM; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = OMAPBL_MAX_INTENSITY; dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops, &props); diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index 3c424f7efdcc..ef5628d60563 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -112,6 +112,7 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) if (!pcf_bl) return -ENOMEM; + bl_props.type = BACKLIGHT_RAW; bl_props.max_brightness = 0x3f; bl_props.power = FB_BLANK_UNBLANK; diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 809278c90738..6af183d6465e 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -84,6 +84,7 @@ static int progearbl_probe(struct platform_device *pdev) pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; progear_backlight_device = backlight_device_register("progear-bl", &pdev->dev, NULL, diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 21866ec69656..2c2a2c703c14 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -108,6 +108,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "got pwm for backlight\n"); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = data->max_brightness; bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb, &pwm_backlight_ops, &props); diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 5927db0da999..322040f686c2 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -778,6 +778,7 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) bd->props.max_brightness = MAX_BRIGHTNESS; bd->props.brightness = MAX_BRIGHTNESS; + bd->props.type = BACKLIGHT_RAW; lcd->bd = bd; /* diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 2a04b382ec48..425a7365470b 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -102,6 +102,7 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, data->i2c = client; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 512 - 1; data->bl = backlight_device_register("tosa-bl", &client->dev, data, &bl_ops, &props); diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 08fd87f3aecc..d4c6eb248ff9 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -193,6 +193,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev) data->current_brightness = 0; data->isink_reg = isink_reg; + props.type = BACKLIGHT_RAW; props.max_brightness = max_isel; bl = backlight_device_register("wm831x", &pdev->dev, data, &wm831x_backlight_ops, &props); diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index e7d0f525041e..2464b910b590 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -649,6 +649,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) } #ifndef NO_BL_SUPPORT memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 255; bl_dev = backlight_device_register("bf54x-bl", NULL, NULL, &bfin_lq043fb_bl_ops, &props); diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 3cf77676947c..d8de29f0dd8d 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -545,6 +545,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) } #ifndef NO_BL_SUPPORT memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 255; bl_dev = backlight_device_register("bf52x-bl", NULL, NULL, &bfin_lq043fb_bl_ops, &props); diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 69bd4a581d4a..ef72cb483834 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -499,6 +499,7 @@ static void imxfb_init_backlight(struct imxfb_info *fbi) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 0xff; + props.type = BACKLIGHT_RAW; writel(fbi->pwmr, fbi->regs + LCDC_PWMR); bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi, diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 6aac6d1b937b..8471008aa6ff 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -111,6 +111,7 @@ void nvidia_bl_init(struct nvidia_par *par) snprintf(name, sizeof(name), "nvidiabl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops, &props); diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index e77310653207..7e04c921aa2a 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -534,6 +534,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) props.fb_blank = FB_BLANK_UNBLANK; props.power = FB_BLANK_UNBLANK; + props.type = BACKLIGHT_RAW; bldev = backlight_device_register("acx565akm", &md->spi->dev, md, &acx565akm_bl_ops, &props); diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index 9a138f650e05..d2b35d2df2a6 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -99,6 +99,7 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = dssdev->max_backlight_level; + props.type = BACKLIGHT_RAW; bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev, &sharp_ls_bl_ops, &props); diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 61026f96ad20..c74e8b778ba1 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -729,6 +729,8 @@ static int taal_probe(struct omap_dss_device *dssdev) props.max_brightness = 255; else props.max_brightness = 127; + + props.type = BACKLIGHT_RAW; bldev = backlight_device_register("taal", &dssdev->dev, dssdev, &taal_bl_ops, &props); if (IS_ERR(bldev)) { diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index da388186d617..d8ab7be4fd6b 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -355,6 +355,7 @@ static void riva_bl_init(struct riva_par *par) snprintf(name, sizeof(name), "rivabl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &riva_bl_ops, &props); -- cgit v1.2.2 From 63ec0119d3720034dfd626c9785aefa5a6f972ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 22 Mar 2011 16:30:23 -0700 Subject: radeon: expose backlight class device for legacy LVDS encoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows e.g. power management daemons to control the backlight level. Inspired by the corresponding code in radeonfb. [mjg@redhat.com: updated to add backlight type and make the connector the parent device] Signed-off-by: Michel Dänzer Signed-off-by: Matthew Garrett Cc: Richard Purdie Cc: Chris Wilson Cc: David Airlie Acked-by: Alex Deucher Cc: Ben Skeggs Cc: Zhang Rui Cc: Len Brown Cc: Jesse Barnes Tested-by: Sedat Dilek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpu/drm/radeon/Kconfig | 1 + drivers/gpu/drm/radeon/radeon_connectors.c | 15 ++ drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 257 +++++++++++++++++++++++- drivers/gpu/drm/radeon/radeon_mode.h | 6 + 4 files changed, 273 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig index 1c02d23f6fcc..9746fee59f56 100644 --- a/drivers/gpu/drm/radeon/Kconfig +++ b/drivers/gpu/drm/radeon/Kconfig @@ -1,6 +1,7 @@ config DRM_RADEON_KMS bool "Enable modesetting on radeon by default - NEW DRIVER" depends on DRM_RADEON + select BACKLIGHT_CLASS_DEVICE help Choose this option if you want kernel modesetting enabled by default. diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 3f3c9aac46cc..28c7961cd19b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -40,6 +40,10 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, struct drm_encoder *encoder, bool connected); +extern void +radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, + struct drm_connector *drm_connector); + void radeon_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -1526,6 +1530,17 @@ radeon_add_legacy_connector(struct drm_device *dev, connector->polled = DRM_CONNECTOR_POLL_HPD; connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); + if (connector_type == DRM_MODE_CONNECTOR_LVDS) { + struct drm_encoder *drm_encoder; + + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_encoder; + + radeon_encoder = to_radeon_encoder(drm_encoder); + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_LVDS) + radeon_legacy_backlight_init(radeon_encoder, connector); + } + } return; failed: diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 59f834ba283d..5b54268ed6b2 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -28,6 +28,10 @@ #include "radeon_drm.h" #include "radeon.h" #include "atom.h" +#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif static void radeon_legacy_encoder_disable(struct drm_encoder *encoder) { @@ -39,7 +43,7 @@ static void radeon_legacy_encoder_disable(struct drm_encoder *encoder) radeon_encoder->active_device = 0; } -static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) +static void radeon_legacy_lvds_update(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; @@ -47,15 +51,23 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; int panel_pwr_delay = 2000; bool is_mac = false; + uint8_t backlight_level; DRM_DEBUG_KMS("\n"); + lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); + backlight_level = (lvds_gen_cntl >> RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; + if (radeon_encoder->enc_priv) { if (rdev->is_atom_bios) { struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; panel_pwr_delay = lvds->panel_pwr_delay; + if (lvds->bl_dev) + backlight_level = lvds->backlight_level; } else { struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; panel_pwr_delay = lvds->panel_pwr_delay; + if (lvds->bl_dev) + backlight_level = lvds->backlight_level; } } @@ -82,11 +94,13 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET; WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl); - lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); - lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON); + lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS | + RADEON_LVDS_BL_MOD_LEVEL_MASK); + lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | + RADEON_LVDS_DIGON | RADEON_LVDS_BLON | + (backlight_level << RADEON_LVDS_BL_MOD_LEVEL_SHIFT)); if (is_mac) lvds_gen_cntl |= RADEON_LVDS_BL_MOD_EN; - lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS); udelay(panel_pwr_delay * 1000); WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl); break; @@ -95,7 +109,6 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) case DRM_MODE_DPMS_OFF: pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL); WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); - lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS; if (is_mac) { lvds_gen_cntl &= ~RADEON_LVDS_BL_MOD_EN; @@ -119,6 +132,25 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) } +static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) +{ + struct radeon_device *rdev = encoder->dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DRM_DEBUG("\n"); + + if (radeon_encoder->enc_priv) { + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; + lvds->dpms_mode = mode; + } else { + struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; + lvds->dpms_mode = mode; + } + } + + radeon_legacy_lvds_update(encoder, mode); +} + static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder) { struct radeon_device *rdev = encoder->dev->dev_private; @@ -237,9 +269,222 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { .disable = radeon_legacy_encoder_disable, }; +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + +#define MAX_RADEON_LEVEL 0xFF + +struct radeon_backlight_privdata { + struct radeon_encoder *encoder; + uint8_t negative; +}; + +static uint8_t radeon_legacy_lvds_level(struct backlight_device *bd) +{ + struct radeon_backlight_privdata *pdata = bl_get_data(bd); + uint8_t level; + + /* Convert brightness to hardware level */ + if (bd->props.brightness < 0) + level = 0; + else if (bd->props.brightness > MAX_RADEON_LEVEL) + level = MAX_RADEON_LEVEL; + else + level = bd->props.brightness; + + if (pdata->negative) + level = MAX_RADEON_LEVEL - level; + + return level; +} + +static int radeon_legacy_backlight_update_status(struct backlight_device *bd) +{ + struct radeon_backlight_privdata *pdata = bl_get_data(bd); + struct radeon_encoder *radeon_encoder = pdata->encoder; + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + int dpms_mode = DRM_MODE_DPMS_ON; + + if (radeon_encoder->enc_priv) { + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; + dpms_mode = lvds->dpms_mode; + lvds->backlight_level = radeon_legacy_lvds_level(bd); + } else { + struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; + dpms_mode = lvds->dpms_mode; + lvds->backlight_level = radeon_legacy_lvds_level(bd); + } + } + + if (bd->props.brightness > 0) + radeon_legacy_lvds_update(&radeon_encoder->base, dpms_mode); + else + radeon_legacy_lvds_update(&radeon_encoder->base, DRM_MODE_DPMS_OFF); + + return 0; +} + +static int radeon_legacy_backlight_get_brightness(struct backlight_device *bd) +{ + struct radeon_backlight_privdata *pdata = bl_get_data(bd); + struct radeon_encoder *radeon_encoder = pdata->encoder; + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + uint8_t backlight_level; + + backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >> + RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; + + return pdata->negative ? MAX_RADEON_LEVEL - backlight_level : backlight_level; +} + +static const struct backlight_ops radeon_backlight_ops = { + .get_brightness = radeon_legacy_backlight_get_brightness, + .update_status = radeon_legacy_backlight_update_status, +}; + +void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, + struct drm_connector *drm_connector) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct backlight_device *bd; + struct backlight_properties props; + struct radeon_backlight_privdata *pdata; + uint8_t backlight_level; + + if (!radeon_encoder->enc_priv) + return; + +#ifdef CONFIG_PMAC_BACKLIGHT + if (!pmac_has_backlight_type("ati") && + !pmac_has_backlight_type("mnca")) + return; +#endif + + pdata = kmalloc(sizeof(struct radeon_backlight_privdata), GFP_KERNEL); + if (!pdata) { + DRM_ERROR("Memory allocation failed\n"); + goto error; + } + + props.max_brightness = MAX_RADEON_LEVEL; + props.type = BACKLIGHT_RAW; + bd = backlight_device_register("radeon_bl", &drm_connector->kdev, + pdata, &radeon_backlight_ops, &props); + if (IS_ERR(bd)) { + DRM_ERROR("Backlight registration failed\n"); + goto error; + } + + pdata->encoder = radeon_encoder; + + backlight_level = (RREG32(RADEON_LVDS_GEN_CNTL) >> + RADEON_LVDS_BL_MOD_LEVEL_SHIFT) & 0xff; + + /* First, try to detect backlight level sense based on the assumption + * that firmware set it up at full brightness + */ + if (backlight_level == 0) + pdata->negative = true; + else if (backlight_level == 0xff) + pdata->negative = false; + else { + /* XXX hack... maybe some day we can figure out in what direction + * backlight should work on a given panel? + */ + pdata->negative = (rdev->family != CHIP_RV200 && + rdev->family != CHIP_RV250 && + rdev->family != CHIP_RV280 && + rdev->family != CHIP_RV350); + +#ifdef CONFIG_PMAC_BACKLIGHT + pdata->negative = (pdata->negative || + of_machine_is_compatible("PowerBook4,3") || + of_machine_is_compatible("PowerBook6,3") || + of_machine_is_compatible("PowerBook6,5")); +#endif + } + + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; + lvds->bl_dev = bd; + } else { + struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; + lvds->bl_dev = bd; + } + + bd->props.brightness = radeon_legacy_backlight_get_brightness(bd); + bd->props.power = FB_BLANK_UNBLANK; + backlight_update_status(bd); + + DRM_INFO("radeon legacy LVDS backlight initialized\n"); + + return; + +error: + kfree(pdata); + return; +} + +static void radeon_legacy_backlight_exit(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct backlight_device *bd = NULL; + + if (!radeon_encoder->enc_priv) + return; + + if (rdev->is_atom_bios) { + struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv; + bd = lvds->bl_dev; + lvds->bl_dev = NULL; + } else { + struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv; + bd = lvds->bl_dev; + lvds->bl_dev = NULL; + } + + if (bd) { + struct radeon_legacy_backlight_privdata *pdata; + + pdata = bl_get_data(bd); + backlight_device_unregister(bd); + kfree(pdata); + + DRM_INFO("radeon legacy LVDS backlight unloaded\n"); + } +} + +#else /* !CONFIG_BACKLIGHT_CLASS_DEVICE */ + +void radeon_legacy_backlight_init(struct radeon_encoder *encoder) +{ +} + +static void radeon_legacy_backlight_exit(struct radeon_encoder *encoder) +{ +} + +#endif + + +static void radeon_lvds_enc_destroy(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->enc_priv) { + radeon_legacy_backlight_exit(radeon_encoder); + kfree(radeon_encoder->enc_priv); + } + drm_encoder_cleanup(encoder); + kfree(radeon_encoder); +} static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = { - .destroy = radeon_enc_destroy, + .destroy = radeon_lvds_enc_destroy, }; static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5067d18d0009..e4582814bb78 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -302,6 +302,9 @@ struct radeon_encoder_lvds { uint32_t lvds_gen_cntl; /* panel mode */ struct drm_display_mode native_mode; + struct backlight_device *bl_dev; + int dpms_mode; + uint8_t backlight_level; }; struct radeon_encoder_tv_dac { @@ -355,6 +358,9 @@ struct radeon_encoder_atom_dig { uint32_t lcd_ss_id; /* panel mode */ struct drm_display_mode native_mode; + struct backlight_device *bl_dev; + int dpms_mode; + uint8_t backlight_level; }; struct radeon_encoder_atom_dac { -- cgit v1.2.2 From 7eae3efa13c5d1c8e7d8dd0504ad524963b8add1 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 22 Mar 2011 16:30:24 -0700 Subject: nouveau: change the backlight parent device to the connector, not the PCI dev We may eventually end up with per-connector backlights, especially with ddcci devices. Make sure that the parent node for the backlight device is the connector rather than the PCI device. Signed-off-by: Matthew Garrett Cc: Richard Purdie Cc: Chris Wilson Cc: David Airlie Cc: Alex Deucher Acked-by: Ben Skeggs Cc: Zhang Rui Cc: Len Brown Cc: Jesse Barnes Tested-by: Sedat Dilek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpu/drm/nouveau/nouveau_backlight.c | 24 ++++++++++++++---------- drivers/gpu/drm/nouveau/nouveau_connector.c | 9 +++++++++ drivers/gpu/drm/nouveau/nouveau_drv.h | 8 ++++---- drivers/gpu/drm/nouveau/nouveau_state.c | 6 ------ 4 files changed, 27 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index 18d7bcc54ce0..00a55dfdba82 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -88,10 +88,11 @@ static const struct backlight_ops nv50_bl_ops = { .update_status = nv50_set_intensity, }; -static int nouveau_nv40_backlight_init(struct drm_device *dev) +static int nouveau_nv40_backlight_init(struct drm_connector *connector) { - struct backlight_properties props; + struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct backlight_properties props; struct backlight_device *bd; if (!(nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK)) @@ -100,7 +101,7 @@ static int nouveau_nv40_backlight_init(struct drm_device *dev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = 31; - bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev, + bd = backlight_device_register("nv_backlight", &connector->kdev, dev, &nv40_bl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -112,10 +113,11 @@ static int nouveau_nv40_backlight_init(struct drm_device *dev) return 0; } -static int nouveau_nv50_backlight_init(struct drm_device *dev) +static int nouveau_nv50_backlight_init(struct drm_connector *connector) { - struct backlight_properties props; + struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct backlight_properties props; struct backlight_device *bd; if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT)) @@ -124,7 +126,7 @@ static int nouveau_nv50_backlight_init(struct drm_device *dev) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = 1025; - bd = backlight_device_register("nv_backlight", &dev->pdev->dev, dev, + bd = backlight_device_register("nv_backlight", &connector->kdev, dev, &nv50_bl_ops, &props); if (IS_ERR(bd)) return PTR_ERR(bd); @@ -135,8 +137,9 @@ static int nouveau_nv50_backlight_init(struct drm_device *dev) return 0; } -int nouveau_backlight_init(struct drm_device *dev) +int nouveau_backlight_init(struct drm_connector *connector) { + struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; #ifdef CONFIG_ACPI @@ -149,9 +152,9 @@ int nouveau_backlight_init(struct drm_device *dev) switch (dev_priv->card_type) { case NV_40: - return nouveau_nv40_backlight_init(dev); + return nouveau_nv40_backlight_init(connector); case NV_50: - return nouveau_nv50_backlight_init(dev); + return nouveau_nv50_backlight_init(connector); default: break; } @@ -159,8 +162,9 @@ int nouveau_backlight_init(struct drm_device *dev) return 0; } -void nouveau_backlight_exit(struct drm_device *dev) +void nouveau_backlight_exit(struct drm_connector *connector) { + struct drm_device *dev = connector->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; if (dev_priv->backlight) { diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 390d82c3c4b0..7ae151109a66 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -116,6 +116,10 @@ nouveau_connector_destroy(struct drm_connector *connector) nouveau_connector_hotplug, connector); } + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || + connector->connector_type == DRM_MODE_CONNECTOR_eDP) + nouveau_backlight_exit(connector); + kfree(nv_connector->edid); drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); @@ -894,6 +898,11 @@ nouveau_connector_create(struct drm_device *dev, int index) } drm_sysfs_connector_add(connector); + + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || + connector->connector_type == DRM_MODE_CONNECTOR_eDP) + nouveau_backlight_init(connector); + dcb->drm = connector; return dcb->drm; diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 06111887b789..fff180a99867 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -999,15 +999,15 @@ static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector /* nouveau_backlight.c */ #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT -extern int nouveau_backlight_init(struct drm_device *); -extern void nouveau_backlight_exit(struct drm_device *); +extern int nouveau_backlight_init(struct drm_connector *); +extern void nouveau_backlight_exit(struct drm_connector *); #else -static inline int nouveau_backlight_init(struct drm_device *dev) +static inline int nouveau_backlight_init(struct drm_connector *dev) { return 0; } -static inline void nouveau_backlight_exit(struct drm_device *dev) { } +static inline void nouveau_backlight_exit(struct drm_connector *dev) { } #endif /* nouveau_bios.c */ diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 05294910e135..4fcbd091a117 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -704,10 +704,6 @@ nouveau_card_init(struct drm_device *dev) goto out_fence; } - ret = nouveau_backlight_init(dev); - if (ret) - NV_ERROR(dev, "Error %d registering backlight\n", ret); - nouveau_fbcon_init(dev); drm_kms_helper_poll_init(dev); return 0; @@ -759,8 +755,6 @@ static void nouveau_card_takedown(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; - nouveau_backlight_exit(dev); - if (!engine->graph.accel_blocked) { nouveau_fence_fini(dev); nouveau_channel_put_unlocked(&dev_priv->channel); -- cgit v1.2.2 From 9661e92c10a9775243c1ecb73373528ed8725a10 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 22 Mar 2011 16:30:25 -0700 Subject: acpi: tie ACPI backlight devices to PCI devices if possible Dual-GPU machines may provide more than one ACPI backlight interface. Tie the backlight device to the GPU in order to allow userspace to identify the correct interface. Signed-off-by: Matthew Garrett Cc: Richard Purdie Cc: Chris Wilson Cc: David Airlie Cc: Alex Deucher Cc: Ben Skeggs Cc: Zhang Rui Cc: Len Brown Cc: Jesse Barnes Tested-by: Sedat Dilek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/acpi/video.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a9eec8c95a1f..a18e497f1c3c 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -782,6 +782,9 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) if (acpi_video_backlight_support()) { struct backlight_properties props; + struct pci_dev *pdev; + acpi_handle acpi_parent; + struct device *parent = NULL; int result; static int count = 0; char *name; @@ -794,10 +797,20 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) return; count++; + acpi_get_parent(device->dev->handle, &acpi_parent); + + pdev = acpi_get_pci_dev(acpi_parent); + if (pdev) { + parent = &pdev->dev; + pci_dev_put(pdev); + } + memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_FIRMWARE; props.max_brightness = device->brightness->count - 3; - device->backlight = backlight_device_register(name, NULL, device, + device->backlight = backlight_device_register(name, + parent, + device, &acpi_backlight_ops, &props); kfree(name); -- cgit v1.2.2 From 23a9847f0d5252872c4fecb5d4f803c523bd9283 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 22 Mar 2011 16:30:26 -0700 Subject: mbp_nvidia_bl: remove DMI dependency This driver only has to deal with two different classes of hardware, but right now it needs new DMI entries for every new machine. It turns out that there's an ACPI device that uniquely identifies Apples with backlights, so this patch reworks the driver into an ACPI one, identifies the hardware by checking the PCI vendor of the root bridge and strips out all the DMI code. It also changes the config text to clarify that it works on devices other than Macbook Pros and GPUs other than nvidia. Signed-off-by: Matthew Garrett Acked-by: Richard Purdie Cc: Mourad De Clerck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 8 +- drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/mbp_nvidia_bl.c | 366 +++++++++----------------------- 3 files changed, 101 insertions(+), 275 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 39a4cd258d5b..aa8cf9d2e34f 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -244,12 +244,12 @@ config BACKLIGHT_MAX8925 If you have a LCD backlight connected to the WLED output of MAX8925 WLED output, say Y here to enable this driver. -config BACKLIGHT_MBP_NVIDIA - tristate "MacBook Pro Nvidia Backlight Driver" +config BACKLIGHT_MACBOOK + tristate "MacBook Backlight Driver" depends on X86 help - If you have an Apple Macbook Pro with Nvidia graphics hardware say Y - to enable a driver for its backlight + If you have an Apple Macbook say Y to enable a driver for its + backlight config BACKLIGHT_TOSA tristate "Sharp SL-6000 Backlight Driver" diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 457996c97f5f..988d7cd159ea 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o -obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o +obj-$(CONFIG_BACKLIGHT_MACBOOK) += mbp_nvidia_bl.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 74c33944aa86..b22cfb24bd55 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -1,5 +1,5 @@ /* - * Backlight Driver for Nvidia 8600 in Macbook Pro + * Backlight Driver for Macbooks * * Copyright (c) Red Hat * Based on code from Pommed: @@ -19,23 +19,27 @@ #include #include #include -#include #include #include -#include #include +#include +#include -static struct backlight_device *mbp_backlight_device; +static struct backlight_device *mb_backlight_device; -/* Structure to be passed to the DMI_MATCH function. */ -struct dmi_match_data { +struct hw_data { /* I/O resource to allocate. */ unsigned long iostart; unsigned long iolen; /* Backlight operations structure. */ const struct backlight_ops backlight_ops; + void (*set_brightness)(int); }; +static const struct hw_data *hw_data; + +#define DRIVER "mb_backlight: " + /* Module parameters. */ static int debug; module_param_named(debug, debug, int, 0644); @@ -44,16 +48,21 @@ MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); /* * Implementation for MacBooks with Intel chipset. */ +static void intel_chipset_set_brightness(int intensity) +{ + outb(0x04 | (intensity << 4), 0xb3); + outb(0xbf, 0xb2); +} + static int intel_chipset_send_intensity(struct backlight_device *bd) { int intensity = bd->props.brightness; if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", + printk(KERN_DEBUG DRIVER "setting brightness to %d\n", intensity); - outb(0x04 | (intensity << 4), 0xb3); - outb(0xbf, 0xb2); + intel_chipset_set_brightness(intensity); return 0; } @@ -66,35 +75,41 @@ static int intel_chipset_get_intensity(struct backlight_device *bd) intensity = inb(0xb3) >> 4; if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", + printk(KERN_DEBUG DRIVER "read brightness of %d\n", intensity); return intensity; } -static const struct dmi_match_data intel_chipset_data = { +static const struct hw_data intel_chipset_data = { .iostart = 0xb2, .iolen = 2, .backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = intel_chipset_get_intensity, .update_status = intel_chipset_send_intensity, - } + }, + .set_brightness = intel_chipset_set_brightness, }; /* * Implementation for MacBooks with Nvidia chipset. */ +static void nvidia_chipset_set_brightness(int intensity) +{ + outb(0x04 | (intensity << 4), 0x52f); + outb(0xbf, 0x52e); +} + static int nvidia_chipset_send_intensity(struct backlight_device *bd) { int intensity = bd->props.brightness; if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", + printk(KERN_DEBUG DRIVER "setting brightness to %d\n", intensity); - outb(0x04 | (intensity << 4), 0x52f); - outb(0xbf, 0x52e); + nvidia_chipset_set_brightness(intensity); return 0; } @@ -107,295 +122,106 @@ static int nvidia_chipset_get_intensity(struct backlight_device *bd) intensity = inb(0x52f) >> 4; if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", + printk(KERN_DEBUG DRIVER "read brightness of %d\n", intensity); return intensity; } -static const struct dmi_match_data nvidia_chipset_data = { +static const struct hw_data nvidia_chipset_data = { .iostart = 0x52e, .iolen = 2, .backlight_ops = { .options = BL_CORE_SUSPENDRESUME, .get_brightness = nvidia_chipset_get_intensity, .update_status = nvidia_chipset_send_intensity - } + }, + .set_brightness = nvidia_chipset_set_brightness, }; -/* - * DMI matching. - */ -static /* const */ struct dmi_match_data *driver_data; - -static int mbp_dmi_match(const struct dmi_system_id *id) +static int __devinit mb_bl_add(struct acpi_device *dev) { - driver_data = id->driver_data; + struct backlight_properties props; + struct pci_dev *host; - printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident); - return 1; -} + host = pci_get_bus_and_slot(0, 0); -static const struct dmi_system_id __initdata mbp_device_table[] = { - { - .callback = mbp_dmi_match, - .ident = "MacBook 1,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 2,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 3,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook3,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 4,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 4,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,2"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 1,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 1,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 2,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 2,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 3,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 3,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 4,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 1,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir1,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 5,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 5,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 6,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 2,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,2"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,4", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,5", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,5"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 3,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 3,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { } -}; + if (!host) { + printk(KERN_ERR DRIVER "unable to find PCI host\n"); + return -ENODEV; + } -static int __init mbp_init(void) -{ - struct backlight_properties props; - if (!dmi_check_system(mbp_device_table)) + if (host->vendor == PCI_VENDOR_ID_INTEL) + hw_data = &intel_chipset_data; + else if (host->vendor == PCI_VENDOR_ID_NVIDIA) + hw_data = &nvidia_chipset_data; + + pci_dev_put(host); + + if (!hw_data) { + printk(KERN_ERR DRIVER "unknown hardware\n"); return -ENODEV; + } - if (!request_region(driver_data->iostart, driver_data->iolen, - "Macbook Pro backlight")) + if (!request_region(hw_data->iostart, hw_data->iolen, + "Macbook backlight")) return -ENXIO; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; props.max_brightness = 15; - mbp_backlight_device = backlight_device_register("mbp_backlight", NULL, - NULL, - &driver_data->backlight_ops, - &props); - if (IS_ERR(mbp_backlight_device)) { - release_region(driver_data->iostart, driver_data->iolen); - return PTR_ERR(mbp_backlight_device); + mb_backlight_device = backlight_device_register("mb_backlight", NULL, + NULL, &hw_data->backlight_ops, &props); + + if (IS_ERR(mb_backlight_device)) { + release_region(hw_data->iostart, hw_data->iolen); + return PTR_ERR(mb_backlight_device); } - mbp_backlight_device->props.brightness = - driver_data->backlight_ops.get_brightness(mbp_backlight_device); - backlight_update_status(mbp_backlight_device); + mb_backlight_device->props.brightness = + hw_data->backlight_ops.get_brightness(mb_backlight_device); + backlight_update_status(mb_backlight_device); return 0; } -static void __exit mbp_exit(void) +static int __devexit mb_bl_remove(struct acpi_device *dev, int type) { - backlight_device_unregister(mbp_backlight_device); + backlight_device_unregister(mb_backlight_device); - release_region(driver_data->iostart, driver_data->iolen); + release_region(hw_data->iostart, hw_data->iolen); + hw_data = NULL; + return 0; +} + +static const struct acpi_device_id mb_bl_ids[] = { + {"APP0002", 0}, + {"", 0}, +}; + +static struct acpi_driver mb_bl_driver = { + .name = "Macbook backlight", + .ids = mb_bl_ids, + .ops = { + .add = mb_bl_add, + .remove = mb_bl_remove, + }, +}; + +static int __init mb_init(void) +{ + return acpi_bus_register_driver(&mb_bl_driver); +} + +static void __exit mb_exit(void) +{ + acpi_bus_unregister_driver(&mb_bl_driver); } -module_init(mbp_init); -module_exit(mbp_exit); +module_init(mb_init); +module_exit(mb_exit); MODULE_AUTHOR("Matthew Garrett "); -MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver"); +MODULE_DESCRIPTION("Macbook Backlight Driver"); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(dmi, mbp_device_table); +MODULE_DEVICE_TABLE(acpi, mb_bl_ids); -- cgit v1.2.2 From 99fd28e19429f5212f0758adc1b2f08c6e63b6db Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 22 Mar 2011 16:30:27 -0700 Subject: mbp_nvidia_bl: check that the backlight control functions The SMI-based backlight control functionality may fail to work if the system is running under EFI rather than BIOS. Check that the hardware responds as expected, and exit if it doesn't. Signed-off-by: Matthew Garrett Acked-by: Richard Purdie Cc: Mourad De Clerck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/mbp_nvidia_bl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index b22cfb24bd55..dd0e145170b7 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -143,6 +143,7 @@ static int __devinit mb_bl_add(struct acpi_device *dev) { struct backlight_properties props; struct pci_dev *host; + int intensity; host = pci_get_bus_and_slot(0, 0); @@ -163,6 +164,18 @@ static int __devinit mb_bl_add(struct acpi_device *dev) return -ENODEV; } + /* Check that the hardware responds - this may not work under EFI */ + + intensity = hw_data->backlight_ops.get_brightness(NULL); + + if (!intensity) { + hw_data->set_brightness(1); + if (!hw_data->backlight_ops.get_brightness(NULL)) + return -ENODEV; + + hw_data->set_brightness(0); + } + if (!request_region(hw_data->iostart, hw_data->iolen, "Macbook backlight")) return -ENXIO; -- cgit v1.2.2 From 39b3dee76fa1f1ac8310ea5898ba7c07280bdd9f Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 22 Mar 2011 16:30:28 -0700 Subject: mbp_nvidia_bl: rename to apple_bl It works on hardware other than Macbook Pros, and it works on GPUs other than Nvidia. It should even work on iMacs, so change the name to match reality more precisely and include an alias so existing users don't get confused. Signed-off-by: Matthew Garrett Acked-by: Richard Purdie Cc: Mourad De Clerck Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 6 +- drivers/video/backlight/Makefile | 2 +- drivers/video/backlight/apple_bl.c | 241 ++++++++++++++++++++++++++++++++ drivers/video/backlight/mbp_nvidia_bl.c | 240 ------------------------------- 4 files changed, 245 insertions(+), 244 deletions(-) create mode 100644 drivers/video/backlight/apple_bl.c delete mode 100644 drivers/video/backlight/mbp_nvidia_bl.c (limited to 'drivers') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index aa8cf9d2e34f..39fff49da19d 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -244,11 +244,11 @@ config BACKLIGHT_MAX8925 If you have a LCD backlight connected to the WLED output of MAX8925 WLED output, say Y here to enable this driver. -config BACKLIGHT_MACBOOK - tristate "MacBook Backlight Driver" +config BACKLIGHT_APPLE + tristate "Apple Backlight Driver" depends on X86 help - If you have an Apple Macbook say Y to enable a driver for its + If you have an Intel-based Apple say Y to enable a driver for its backlight config BACKLIGHT_TOSA diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 988d7cd159ea..b9ca8490df87 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o -obj-$(CONFIG_BACKLIGHT_MACBOOK) += mbp_nvidia_bl.o +obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c new file mode 100644 index 000000000000..be98d152b7fd --- /dev/null +++ b/drivers/video/backlight/apple_bl.c @@ -0,0 +1,241 @@ +/* + * Backlight Driver for Intel-based Apples + * + * Copyright (c) Red Hat + * Based on code from Pommed: + * Copyright (C) 2006 Nicolas Boichat + * Copyright (C) 2006 Felipe Alfaro Solana + * Copyright (C) 2007 Julien BLACHE + * + * 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. + * + * This driver triggers SMIs which cause the firmware to change the + * backlight brightness. This is icky in many ways, but it's impractical to + * get at the firmware code in order to figure out what it's actually doing. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct backlight_device *apple_backlight_device; + +struct hw_data { + /* I/O resource to allocate. */ + unsigned long iostart; + unsigned long iolen; + /* Backlight operations structure. */ + const struct backlight_ops backlight_ops; + void (*set_brightness)(int); +}; + +static const struct hw_data *hw_data; + +#define DRIVER "apple_backlight: " + +/* Module parameters. */ +static int debug; +module_param_named(debug, debug, int, 0644); +MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); + +/* + * Implementation for machines with Intel chipset. + */ +static void intel_chipset_set_brightness(int intensity) +{ + outb(0x04 | (intensity << 4), 0xb3); + outb(0xbf, 0xb2); +} + +static int intel_chipset_send_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + + if (debug) + printk(KERN_DEBUG DRIVER "setting brightness to %d\n", + intensity); + + intel_chipset_set_brightness(intensity); + return 0; +} + +static int intel_chipset_get_intensity(struct backlight_device *bd) +{ + int intensity; + + outb(0x03, 0xb3); + outb(0xbf, 0xb2); + intensity = inb(0xb3) >> 4; + + if (debug) + printk(KERN_DEBUG DRIVER "read brightness of %d\n", + intensity); + + return intensity; +} + +static const struct hw_data intel_chipset_data = { + .iostart = 0xb2, + .iolen = 2, + .backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = intel_chipset_get_intensity, + .update_status = intel_chipset_send_intensity, + }, + .set_brightness = intel_chipset_set_brightness, +}; + +/* + * Implementation for machines with Nvidia chipset. + */ +static void nvidia_chipset_set_brightness(int intensity) +{ + outb(0x04 | (intensity << 4), 0x52f); + outb(0xbf, 0x52e); +} + +static int nvidia_chipset_send_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + + if (debug) + printk(KERN_DEBUG DRIVER "setting brightness to %d\n", + intensity); + + nvidia_chipset_set_brightness(intensity); + return 0; +} + +static int nvidia_chipset_get_intensity(struct backlight_device *bd) +{ + int intensity; + + outb(0x03, 0x52f); + outb(0xbf, 0x52e); + intensity = inb(0x52f) >> 4; + + if (debug) + printk(KERN_DEBUG DRIVER "read brightness of %d\n", + intensity); + + return intensity; +} + +static const struct hw_data nvidia_chipset_data = { + .iostart = 0x52e, + .iolen = 2, + .backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = nvidia_chipset_get_intensity, + .update_status = nvidia_chipset_send_intensity + }, + .set_brightness = nvidia_chipset_set_brightness, +}; + +static int __devinit apple_bl_add(struct acpi_device *dev) +{ + struct backlight_properties props; + struct pci_dev *host; + int intensity; + + host = pci_get_bus_and_slot(0, 0); + + if (!host) { + printk(KERN_ERR DRIVER "unable to find PCI host\n"); + return -ENODEV; + } + + if (host->vendor == PCI_VENDOR_ID_INTEL) + hw_data = &intel_chipset_data; + else if (host->vendor == PCI_VENDOR_ID_NVIDIA) + hw_data = &nvidia_chipset_data; + + pci_dev_put(host); + + if (!hw_data) { + printk(KERN_ERR DRIVER "unknown hardware\n"); + return -ENODEV; + } + + /* Check that the hardware responds - this may not work under EFI */ + + intensity = hw_data->backlight_ops.get_brightness(NULL); + + if (!intensity) { + hw_data->set_brightness(1); + if (!hw_data->backlight_ops.get_brightness(NULL)) + return -ENODEV; + + hw_data->set_brightness(0); + } + + if (!request_region(hw_data->iostart, hw_data->iolen, + "Apple backlight")) + return -ENXIO; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = 15; + apple_backlight_device = backlight_device_register("apple_backlight", + NULL, NULL, &hw_data->backlight_ops, &props); + + if (IS_ERR(apple_backlight_device)) { + release_region(hw_data->iostart, hw_data->iolen); + return PTR_ERR(apple_backlight_device); + } + + apple_backlight_device->props.brightness = + hw_data->backlight_ops.get_brightness(apple_backlight_device); + backlight_update_status(apple_backlight_device); + + return 0; +} + +static int __devexit apple_bl_remove(struct acpi_device *dev, int type) +{ + backlight_device_unregister(apple_backlight_device); + + release_region(hw_data->iostart, hw_data->iolen); + hw_data = NULL; + return 0; +} + +static const struct acpi_device_id apple_bl_ids[] = { + {"APP0002", 0}, + {"", 0}, +}; + +static struct acpi_driver apple_bl_driver = { + .name = "Apple backlight", + .ids = apple_bl_ids, + .ops = { + .add = apple_bl_add, + .remove = apple_bl_remove, + }, +}; + +static int __init apple_bl_init(void) +{ + return acpi_bus_register_driver(&apple_bl_driver); +} + +static void __exit apple_bl_exit(void) +{ + acpi_bus_unregister_driver(&apple_bl_driver); +} + +module_init(apple_bl_init); +module_exit(apple_bl_exit); + +MODULE_AUTHOR("Matthew Garrett "); +MODULE_DESCRIPTION("Apple Backlight Driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(acpi, apple_bl_ids); +MODULE_ALIAS("mbp_nvidia_bl"); diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c deleted file mode 100644 index dd0e145170b7..000000000000 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Backlight Driver for Macbooks - * - * Copyright (c) Red Hat - * Based on code from Pommed: - * Copyright (C) 2006 Nicolas Boichat - * Copyright (C) 2006 Felipe Alfaro Solana - * Copyright (C) 2007 Julien BLACHE - * - * 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. - * - * This driver triggers SMIs which cause the firmware to change the - * backlight brightness. This is icky in many ways, but it's impractical to - * get at the firmware code in order to figure out what it's actually doing. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct backlight_device *mb_backlight_device; - -struct hw_data { - /* I/O resource to allocate. */ - unsigned long iostart; - unsigned long iolen; - /* Backlight operations structure. */ - const struct backlight_ops backlight_ops; - void (*set_brightness)(int); -}; - -static const struct hw_data *hw_data; - -#define DRIVER "mb_backlight: " - -/* Module parameters. */ -static int debug; -module_param_named(debug, debug, int, 0644); -MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); - -/* - * Implementation for MacBooks with Intel chipset. - */ -static void intel_chipset_set_brightness(int intensity) -{ - outb(0x04 | (intensity << 4), 0xb3); - outb(0xbf, 0xb2); -} - -static int intel_chipset_send_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (debug) - printk(KERN_DEBUG DRIVER "setting brightness to %d\n", - intensity); - - intel_chipset_set_brightness(intensity); - return 0; -} - -static int intel_chipset_get_intensity(struct backlight_device *bd) -{ - int intensity; - - outb(0x03, 0xb3); - outb(0xbf, 0xb2); - intensity = inb(0xb3) >> 4; - - if (debug) - printk(KERN_DEBUG DRIVER "read brightness of %d\n", - intensity); - - return intensity; -} - -static const struct hw_data intel_chipset_data = { - .iostart = 0xb2, - .iolen = 2, - .backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = intel_chipset_get_intensity, - .update_status = intel_chipset_send_intensity, - }, - .set_brightness = intel_chipset_set_brightness, -}; - -/* - * Implementation for MacBooks with Nvidia chipset. - */ -static void nvidia_chipset_set_brightness(int intensity) -{ - outb(0x04 | (intensity << 4), 0x52f); - outb(0xbf, 0x52e); -} - -static int nvidia_chipset_send_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (debug) - printk(KERN_DEBUG DRIVER "setting brightness to %d\n", - intensity); - - nvidia_chipset_set_brightness(intensity); - return 0; -} - -static int nvidia_chipset_get_intensity(struct backlight_device *bd) -{ - int intensity; - - outb(0x03, 0x52f); - outb(0xbf, 0x52e); - intensity = inb(0x52f) >> 4; - - if (debug) - printk(KERN_DEBUG DRIVER "read brightness of %d\n", - intensity); - - return intensity; -} - -static const struct hw_data nvidia_chipset_data = { - .iostart = 0x52e, - .iolen = 2, - .backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = nvidia_chipset_get_intensity, - .update_status = nvidia_chipset_send_intensity - }, - .set_brightness = nvidia_chipset_set_brightness, -}; - -static int __devinit mb_bl_add(struct acpi_device *dev) -{ - struct backlight_properties props; - struct pci_dev *host; - int intensity; - - host = pci_get_bus_and_slot(0, 0); - - if (!host) { - printk(KERN_ERR DRIVER "unable to find PCI host\n"); - return -ENODEV; - } - - if (host->vendor == PCI_VENDOR_ID_INTEL) - hw_data = &intel_chipset_data; - else if (host->vendor == PCI_VENDOR_ID_NVIDIA) - hw_data = &nvidia_chipset_data; - - pci_dev_put(host); - - if (!hw_data) { - printk(KERN_ERR DRIVER "unknown hardware\n"); - return -ENODEV; - } - - /* Check that the hardware responds - this may not work under EFI */ - - intensity = hw_data->backlight_ops.get_brightness(NULL); - - if (!intensity) { - hw_data->set_brightness(1); - if (!hw_data->backlight_ops.get_brightness(NULL)) - return -ENODEV; - - hw_data->set_brightness(0); - } - - if (!request_region(hw_data->iostart, hw_data->iolen, - "Macbook backlight")) - return -ENXIO; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = 15; - mb_backlight_device = backlight_device_register("mb_backlight", NULL, - NULL, &hw_data->backlight_ops, &props); - - if (IS_ERR(mb_backlight_device)) { - release_region(hw_data->iostart, hw_data->iolen); - return PTR_ERR(mb_backlight_device); - } - - mb_backlight_device->props.brightness = - hw_data->backlight_ops.get_brightness(mb_backlight_device); - backlight_update_status(mb_backlight_device); - - return 0; -} - -static int __devexit mb_bl_remove(struct acpi_device *dev, int type) -{ - backlight_device_unregister(mb_backlight_device); - - release_region(hw_data->iostart, hw_data->iolen); - hw_data = NULL; - return 0; -} - -static const struct acpi_device_id mb_bl_ids[] = { - {"APP0002", 0}, - {"", 0}, -}; - -static struct acpi_driver mb_bl_driver = { - .name = "Macbook backlight", - .ids = mb_bl_ids, - .ops = { - .add = mb_bl_add, - .remove = mb_bl_remove, - }, -}; - -static int __init mb_init(void) -{ - return acpi_bus_register_driver(&mb_bl_driver); -} - -static void __exit mb_exit(void) -{ - acpi_bus_unregister_driver(&mb_bl_driver); -} - -module_init(mb_init); -module_exit(mb_exit); - -MODULE_AUTHOR("Matthew Garrett "); -MODULE_DESCRIPTION("Macbook Backlight Driver"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(acpi, mb_bl_ids); -- cgit v1.2.2 From b372412e159897c20ce2ad100f51c5d94ae98845 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 22 Mar 2011 16:30:29 -0700 Subject: backlight: apple_bl depends on ACPI apple_bl uses ACPI interfaces (data & code), so it should depend on ACPI. drivers/video/backlight/apple_bl.c:142: warning: 'struct acpi_device' declared inside parameter list drivers/video/backlight/apple_bl.c:142: warning: its scope is only this definition or declaration, which is probably not what you want drivers/video/backlight/apple_bl.c:201: warning: 'struct acpi_device' declared inside parameter list drivers/video/backlight/apple_bl.c:215: error: variable 'apple_bl_driver' has initializer but incomplete type drivers/video/backlight/apple_bl.c:216: error: unknown field 'name' specified in initializer ... Signed-off-by: Randy Dunlap Acked-by: Matthew Garrett Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 39fff49da19d..0c9373bedd1f 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -246,10 +246,10 @@ config BACKLIGHT_MAX8925 config BACKLIGHT_APPLE tristate "Apple Backlight Driver" - depends on X86 + depends on X86 && ACPI help If you have an Intel-based Apple say Y to enable a driver for its - backlight + backlight. config BACKLIGHT_TOSA tristate "Sharp SL-6000 Backlight Driver" -- cgit v1.2.2 From 0508e04e05cdf9b819210f5d5a12264e5eeff1f3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 22 Mar 2011 16:30:30 -0700 Subject: drivers/video/backlight/jornada720_*.c: make needlessly global symbols static The following symbols are needlessly defined global: jornada_bl_init, jornada_bl_exit, jornada_lcd_init, jornada_lcd_exit. Make them static. Signed-off-by: Axel Lin Acked-by: Kristoffer Ericson Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/jornada720_bl.c | 4 ++-- drivers/video/backlight/jornada720_lcd.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c index 40e4fa8fcf92..de65d80159be 100644 --- a/drivers/video/backlight/jornada720_bl.c +++ b/drivers/video/backlight/jornada720_bl.c @@ -147,12 +147,12 @@ static struct platform_driver jornada_bl_driver = { }, }; -int __init jornada_bl_init(void) +static int __init jornada_bl_init(void) { return platform_driver_register(&jornada_bl_driver); } -void __exit jornada_bl_exit(void) +static void __exit jornada_bl_exit(void) { platform_driver_unregister(&jornada_bl_driver); } diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c index cbbb167fd268..d2ff658b4144 100644 --- a/drivers/video/backlight/jornada720_lcd.c +++ b/drivers/video/backlight/jornada720_lcd.c @@ -135,12 +135,12 @@ static struct platform_driver jornada_lcd_driver = { }, }; -int __init jornada_lcd_init(void) +static int __init jornada_lcd_init(void) { return platform_driver_register(&jornada_lcd_driver); } -void __exit jornada_lcd_exit(void) +static void __exit jornada_lcd_exit(void) { platform_driver_unregister(&jornada_lcd_driver); } -- cgit v1.2.2 From ef0a5e80f56f6409e957e7117da9551c3d3ff239 Mon Sep 17 00:00:00 2001 From: Robert Morell Date: Tue, 22 Mar 2011 16:30:31 -0700 Subject: pwm_backlight: add check_fb() hook In systems with multiple framebuffer devices, one of the devices might be blanked while another is unblanked. In order for the backlight blanking logic to know whether to turn off the backlight for a particular framebuffer's blanking notification, it needs to be able to check if a given framebuffer device corresponds to the backlight. This plumbs the check_fb hook from core backlight through the pwm_backlight helper to allow platform code to plug in a check_fb hook. Signed-off-by: Robert Morell Cc: Richard Purdie Cc: Arun Murthy Cc: Linus Walleij Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/backlight/pwm_bl.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 2c2a2c703c14..b8f38ec6eb18 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -28,6 +28,7 @@ struct pwm_bl_data { unsigned int lth_brightness; int (*notify)(struct device *, int brightness); + int (*check_fb)(struct device *, struct fb_info *); }; static int pwm_backlight_update_status(struct backlight_device *bl) @@ -62,9 +63,18 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl) return bl->props.brightness; } +static int pwm_backlight_check_fb(struct backlight_device *bl, + struct fb_info *info) +{ + struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); + + return !pb->check_fb || pb->check_fb(pb->dev, info); +} + static const struct backlight_ops pwm_backlight_ops = { .update_status = pwm_backlight_update_status, .get_brightness = pwm_backlight_get_brightness, + .check_fb = pwm_backlight_check_fb, }; static int pwm_backlight_probe(struct platform_device *pdev) @@ -95,6 +105,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->period = data->pwm_period_ns; pb->notify = data->notify; + pb->check_fb = data->check_fb; pb->lth_brightness = data->lth_brightness * (data->pwm_period_ns / data->max_brightness); pb->dev = &pdev->dev; -- cgit v1.2.2 From 4a7de634f0316080cae5dd4a994112049a7d8462 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Tue, 22 Mar 2011 16:33:57 -0700 Subject: bh1780gli: convert to dev pm ops Signed-off-by: Shubhrajyoti Datta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/bh1780gli.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index d5f3a3fd2319..d07cd67c951c 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c @@ -196,10 +196,11 @@ static int __devexit bh1780_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg) +static int bh1780_suspend(struct device *dev) { struct bh1780_data *ddata; int state, ret; + struct i2c_client *client = to_i2c_client(dev); ddata = i2c_get_clientdata(client); state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); @@ -217,14 +218,14 @@ static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg) return 0; } -static int bh1780_resume(struct i2c_client *client) +static int bh1780_resume(struct device *dev) { struct bh1780_data *ddata; int state, ret; + struct i2c_client *client = to_i2c_client(dev); ddata = i2c_get_clientdata(client); state = ddata->power_state; - ret = bh1780_write(ddata, BH1780_REG_CONTROL, state, "CONTROL"); @@ -233,9 +234,10 @@ static int bh1780_resume(struct i2c_client *client) return 0; } +static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume); +#define BH1780_PMOPS (&bh1780_pm) #else -#define bh1780_suspend NULL -#define bh1780_resume NULL +#define BH1780_PMOPS NULL #endif /* CONFIG_PM */ static const struct i2c_device_id bh1780_id[] = { @@ -247,11 +249,10 @@ static struct i2c_driver bh1780_driver = { .probe = bh1780_probe, .remove = bh1780_remove, .id_table = bh1780_id, - .suspend = bh1780_suspend, - .resume = bh1780_resume, .driver = { - .name = "bh1780" - }, + .name = "bh1780", + .pm = BH1780_PMOPS, +}, }; static int __init bh1780_init(void) -- cgit v1.2.2 From 45bff2ea4285cac5b4438c65216e114d3619f123 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Tue, 22 Mar 2011 16:33:57 -0700 Subject: drivers/misc/bmp085.c: free initmem memory Free the memory that is used only at init Signed-off-by: Shubhrajyoti Datta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/bmp085.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index b6e1c9a6679e..ecd276ad6b19 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c @@ -402,7 +402,7 @@ exit: return status; } -static int bmp085_probe(struct i2c_client *client, +static int __devinit bmp085_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bmp085_data *data; @@ -438,7 +438,7 @@ exit: return err; } -static int bmp085_remove(struct i2c_client *client) +static int __devexit bmp085_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group); kfree(i2c_get_clientdata(client)); @@ -458,7 +458,7 @@ static struct i2c_driver bmp085_driver = { }, .id_table = bmp085_id, .probe = bmp085_probe, - .remove = bmp085_remove, + .remove = __devexit_p(bmp085_remove), .detect = bmp085_detect, .address_list = normal_i2c -- cgit v1.2.2 From b9500546d5f85b56359657e1f78334db8de851fd Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Tue, 22 Mar 2011 16:33:58 -0700 Subject: ST SPEAr: PCIE gadget suppport This is a configurable gadget. can be configured by configfs interface. Any IP available at PCIE bus can be programmed to be used by host controller.It supoorts both INTX and MSI. By default, the gadget is configured for INTX and SYSRAM1 is mapped to BAR0 with size 0x1000 Signed-off-by: Pratyush Anand Cc: Randy Dunlap Cc: Jesse Barnes Cc: Viresh Kumar Cc: Shiraz Hashim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/Kconfig | 10 + drivers/misc/Makefile | 1 + drivers/misc/spear13xx_pcie_gadget.c | 908 +++++++++++++++++++++++++++++++++++ 3 files changed, 919 insertions(+) create mode 100644 drivers/misc/spear13xx_pcie_gadget.c (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 203500d9b848..4e007c6a4b44 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -402,6 +402,16 @@ config DS1682 This driver can also be built as a module. If so, the module will be called ds1682. +config SPEAR13XX_PCIE_GADGET + bool "PCIe gadget support for SPEAr13XX platform" + depends on ARCH_SPEAR13XX + default n + help + This option enables gadget support for PCIe controller. If + board file defines any controller as PCIe endpoint then a sysfs + entry will be created for that controller. User can use these + sysfs node to configure PCIe EP as per his requirements. + config TI_DAC7512 tristate "Texas Instruments DAC7512" depends on SPI && SYSFS diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 804f421bc079..f5468602961f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ obj-$(CONFIG_HMC6352) += hmc6352.o obj-y += eeprom/ obj-y += cb710/ +obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o obj-$(CONFIG_PCH_PHUB) += pch_phub.o diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c new file mode 100644 index 000000000000..ec3b8c911833 --- /dev/null +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -0,0 +1,908 @@ +/* + * drivers/misc/spear13xx_pcie_gadget.c + * + * Copyright (C) 2010 ST Microelectronics + * Pratyush Anand + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IN0_MEM_SIZE (200 * 1024 * 1024 - 1) +/* In current implementation address translation is done using IN0 only. + * So IN1 start address and IN0 end address has been kept same +*/ +#define IN1_MEM_SIZE (0 * 1024 * 1024 - 1) +#define IN_IO_SIZE (20 * 1024 * 1024 - 1) +#define IN_CFG0_SIZE (12 * 1024 * 1024 - 1) +#define IN_CFG1_SIZE (12 * 1024 * 1024 - 1) +#define IN_MSG_SIZE (12 * 1024 * 1024 - 1) +/* Keep default BAR size as 4K*/ +/* AORAM would be mapped by default*/ +#define INBOUND_ADDR_MASK (SPEAR13XX_SYSRAM1_SIZE - 1) + +#define INT_TYPE_NO_INT 0 +#define INT_TYPE_INTX 1 +#define INT_TYPE_MSI 2 +struct spear_pcie_gadget_config { + void __iomem *base; + void __iomem *va_app_base; + void __iomem *va_dbi_base; + char int_type[10]; + ulong requested_msi; + ulong configured_msi; + ulong bar0_size; + ulong bar0_rw_offset; + void __iomem *va_bar0_address; +}; + +struct pcie_gadget_target { + struct configfs_subsystem subsys; + struct spear_pcie_gadget_config config; +}; + +struct pcie_gadget_target_attr { + struct configfs_attribute attr; + ssize_t (*show)(struct spear_pcie_gadget_config *config, + char *buf); + ssize_t (*store)(struct spear_pcie_gadget_config *config, + const char *buf, + size_t count); +}; + +static void enable_dbi_access(struct pcie_app_reg __iomem *app_reg) +{ + /* Enable DBI access */ + writel(readl(&app_reg->slv_armisc) | (1 << AXI_OP_DBI_ACCESS_ID), + &app_reg->slv_armisc); + writel(readl(&app_reg->slv_awmisc) | (1 << AXI_OP_DBI_ACCESS_ID), + &app_reg->slv_awmisc); + +} + +static void disable_dbi_access(struct pcie_app_reg __iomem *app_reg) +{ + /* disable DBI access */ + writel(readl(&app_reg->slv_armisc) & ~(1 << AXI_OP_DBI_ACCESS_ID), + &app_reg->slv_armisc); + writel(readl(&app_reg->slv_awmisc) & ~(1 << AXI_OP_DBI_ACCESS_ID), + &app_reg->slv_awmisc); + +} + +static void spear_dbi_read_reg(struct spear_pcie_gadget_config *config, + int where, int size, u32 *val) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + ulong va_address; + + /* Enable DBI access */ + enable_dbi_access(app_reg); + + va_address = (ulong)config->va_dbi_base + (where & ~0x3); + + *val = readl(va_address); + + if (size == 1) + *val = (*val >> (8 * (where & 3))) & 0xff; + else if (size == 2) + *val = (*val >> (8 * (where & 3))) & 0xffff; + + /* Disable DBI access */ + disable_dbi_access(app_reg); +} + +static void spear_dbi_write_reg(struct spear_pcie_gadget_config *config, + int where, int size, u32 val) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + ulong va_address; + + /* Enable DBI access */ + enable_dbi_access(app_reg); + + va_address = (ulong)config->va_dbi_base + (where & ~0x3); + + if (size == 4) + writel(val, va_address); + else if (size == 2) + writew(val, va_address + (where & 2)); + else if (size == 1) + writeb(val, va_address + (where & 3)); + + /* Disable DBI access */ + disable_dbi_access(app_reg); +} + +#define PCI_FIND_CAP_TTL 48 + +static int pci_find_own_next_cap_ttl(struct spear_pcie_gadget_config *config, + u32 pos, int cap, int *ttl) +{ + u32 id; + + while ((*ttl)--) { + spear_dbi_read_reg(config, pos, 1, &pos); + if (pos < 0x40) + break; + pos &= ~3; + spear_dbi_read_reg(config, pos + PCI_CAP_LIST_ID, 1, &id); + if (id == 0xff) + break; + if (id == cap) + return pos; + pos += PCI_CAP_LIST_NEXT; + } + return 0; +} + +static int pci_find_own_next_cap(struct spear_pcie_gadget_config *config, + u32 pos, int cap) +{ + int ttl = PCI_FIND_CAP_TTL; + + return pci_find_own_next_cap_ttl(config, pos, cap, &ttl); +} + +static int pci_find_own_cap_start(struct spear_pcie_gadget_config *config, + u8 hdr_type) +{ + u32 status; + + spear_dbi_read_reg(config, PCI_STATUS, 2, &status); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + return PCI_CAPABILITY_LIST; + case PCI_HEADER_TYPE_CARDBUS: + return PCI_CB_CAPABILITY_LIST; + default: + return 0; + } + + return 0; +} + +/* + * Tell if a device supports a given PCI capability. + * Returns the address of the requested capability structure within the + * device's PCI configuration space or 0 in case the device does not + * support it. Possible values for @cap: + * + * %PCI_CAP_ID_PM Power Management + * %PCI_CAP_ID_AGP Accelerated Graphics Port + * %PCI_CAP_ID_VPD Vital Product Data + * %PCI_CAP_ID_SLOTID Slot Identification + * %PCI_CAP_ID_MSI Message Signalled Interrupts + * %PCI_CAP_ID_CHSWP CompactPCI HotSwap + * %PCI_CAP_ID_PCIX PCI-X + * %PCI_CAP_ID_EXP PCI Express + */ +static int pci_find_own_capability(struct spear_pcie_gadget_config *config, + int cap) +{ + u32 pos; + u32 hdr_type; + + spear_dbi_read_reg(config, PCI_HEADER_TYPE, 1, &hdr_type); + + pos = pci_find_own_cap_start(config, hdr_type); + if (pos) + pos = pci_find_own_next_cap(config, pos, cap); + + return pos; +} + +static irqreturn_t spear_pcie_gadget_irq(int irq, void *dev_id) +{ + return 0; +} + +/* + * configfs interfaces show/store functions + */ +static ssize_t pcie_gadget_show_link( + struct spear_pcie_gadget_config *config, + char *buf) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + + if (readl(&app_reg->app_status_1) & ((u32)1 << XMLH_LINK_UP_ID)) + return sprintf(buf, "UP"); + else + return sprintf(buf, "DOWN"); +} + +static ssize_t pcie_gadget_store_link( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + + if (sysfs_streq(buf, "UP")) + writel(readl(&app_reg->app_ctrl_0) | (1 << APP_LTSSM_ENABLE_ID), + &app_reg->app_ctrl_0); + else if (sysfs_streq(buf, "DOWN")) + writel(readl(&app_reg->app_ctrl_0) + & ~(1 << APP_LTSSM_ENABLE_ID), + &app_reg->app_ctrl_0); + else + return -EINVAL; + return count; +} + +static ssize_t pcie_gadget_show_int_type( + struct spear_pcie_gadget_config *config, + char *buf) +{ + return sprintf(buf, "%s", config->int_type); +} + +static ssize_t pcie_gadget_store_int_type( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + u32 cap, vec, flags; + ulong vector; + + if (sysfs_streq(buf, "INTA")) + spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); + + else if (sysfs_streq(buf, "MSI")) { + vector = config->requested_msi; + vec = 0; + while (vector > 1) { + vector /= 2; + vec++; + } + spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 0); + cap = pci_find_own_capability(config, PCI_CAP_ID_MSI); + spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags); + flags &= ~PCI_MSI_FLAGS_QMASK; + flags |= vec << 1; + spear_dbi_write_reg(config, cap + PCI_MSI_FLAGS, 1, flags); + } else + return -EINVAL; + + strcpy(config->int_type, buf); + + return count; +} + +static ssize_t pcie_gadget_show_no_of_msi( + struct spear_pcie_gadget_config *config, + char *buf) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + u32 cap, vec, flags; + ulong vector; + + if ((readl(&app_reg->msg_status) & (1 << CFG_MSI_EN_ID)) + != (1 << CFG_MSI_EN_ID)) + vector = 0; + else { + cap = pci_find_own_capability(config, PCI_CAP_ID_MSI); + spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags); + flags &= ~PCI_MSI_FLAGS_QSIZE; + vec = flags >> 4; + vector = 1; + while (vec--) + vector *= 2; + } + config->configured_msi = vector; + + return sprintf(buf, "%lu", vector); +} + +static ssize_t pcie_gadget_store_no_of_msi( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + if (strict_strtoul(buf, 0, &config->requested_msi)) + return -EINVAL; + if (config->requested_msi > 32) + config->requested_msi = 32; + + return count; +} + +static ssize_t pcie_gadget_store_inta( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + ulong en; + + if (strict_strtoul(buf, 0, &en)) + return -EINVAL; + + if (en) + writel(readl(&app_reg->app_ctrl_0) | (1 << SYS_INT_ID), + &app_reg->app_ctrl_0); + else + writel(readl(&app_reg->app_ctrl_0) & ~(1 << SYS_INT_ID), + &app_reg->app_ctrl_0); + + return count; +} + +static ssize_t pcie_gadget_store_send_msi( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + ulong vector; + u32 ven_msi; + + if (strict_strtoul(buf, 0, &vector)) + return -EINVAL; + + if (!config->configured_msi) + return -EINVAL; + + if (vector >= config->configured_msi) + return -EINVAL; + + ven_msi = readl(&app_reg->ven_msi_1); + ven_msi &= ~VEN_MSI_FUN_NUM_MASK; + ven_msi |= 0 << VEN_MSI_FUN_NUM_ID; + ven_msi &= ~VEN_MSI_TC_MASK; + ven_msi |= 0 << VEN_MSI_TC_ID; + ven_msi &= ~VEN_MSI_VECTOR_MASK; + ven_msi |= vector << VEN_MSI_VECTOR_ID; + + /* generating interrupt for msi vector */ + ven_msi |= VEN_MSI_REQ_EN; + writel(ven_msi, &app_reg->ven_msi_1); + udelay(1); + ven_msi &= ~VEN_MSI_REQ_EN; + writel(ven_msi, &app_reg->ven_msi_1); + + return count; +} + +static ssize_t pcie_gadget_show_vendor_id( + struct spear_pcie_gadget_config *config, + char *buf) +{ + u32 id; + + spear_dbi_read_reg(config, PCI_VENDOR_ID, 2, &id); + + return sprintf(buf, "%x", id); +} + +static ssize_t pcie_gadget_store_vendor_id( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + ulong id; + + if (strict_strtoul(buf, 0, &id)) + return -EINVAL; + + spear_dbi_write_reg(config, PCI_VENDOR_ID, 2, id); + + return count; +} + +static ssize_t pcie_gadget_show_device_id( + struct spear_pcie_gadget_config *config, + char *buf) +{ + u32 id; + + spear_dbi_read_reg(config, PCI_DEVICE_ID, 2, &id); + + return sprintf(buf, "%x", id); +} + +static ssize_t pcie_gadget_store_device_id( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + ulong id; + + if (strict_strtoul(buf, 0, &id)) + return -EINVAL; + + spear_dbi_write_reg(config, PCI_DEVICE_ID, 2, id); + + return count; +} + +static ssize_t pcie_gadget_show_bar0_size( + struct spear_pcie_gadget_config *config, + char *buf) +{ + return sprintf(buf, "%lx", config->bar0_size); +} + +static ssize_t pcie_gadget_store_bar0_size( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + ulong size; + u32 pos, pos1; + u32 no_of_bit = 0; + + if (strict_strtoul(buf, 0, &size)) + return -EINVAL; + /* min bar size is 256 */ + if (size <= 0x100) + size = 0x100; + /* max bar size is 1MB*/ + else if (size >= 0x100000) + size = 0x100000; + else { + pos = 0; + pos1 = 0; + while (pos < 21) { + pos = find_next_bit((ulong *)&size, 21, pos); + if (pos != 21) + pos1 = pos + 1; + pos++; + no_of_bit++; + } + if (no_of_bit == 2) + pos1--; + + size = 1 << pos1; + } + config->bar0_size = size; + spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, size - 1); + + return count; +} + +static ssize_t pcie_gadget_show_bar0_address( + struct spear_pcie_gadget_config *config, + char *buf) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + + u32 address = readl(&app_reg->pim0_mem_addr_start); + + return sprintf(buf, "%x", address); +} + +static ssize_t pcie_gadget_store_bar0_address( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + ulong address; + + if (strict_strtoul(buf, 0, &address)) + return -EINVAL; + + address &= ~(config->bar0_size - 1); + if (config->va_bar0_address) + iounmap(config->va_bar0_address); + config->va_bar0_address = ioremap(address, config->bar0_size); + if (!config->va_bar0_address) + return -ENOMEM; + + writel(address, &app_reg->pim0_mem_addr_start); + + return count; +} + +static ssize_t pcie_gadget_show_bar0_rw_offset( + struct spear_pcie_gadget_config *config, + char *buf) +{ + return sprintf(buf, "%lx", config->bar0_rw_offset); +} + +static ssize_t pcie_gadget_store_bar0_rw_offset( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + ulong offset; + + if (strict_strtoul(buf, 0, &offset)) + return -EINVAL; + + if (offset % 4) + return -EINVAL; + + config->bar0_rw_offset = offset; + + return count; +} + +static ssize_t pcie_gadget_show_bar0_data( + struct spear_pcie_gadget_config *config, + char *buf) +{ + ulong data; + + if (!config->va_bar0_address) + return -ENOMEM; + + data = readl((ulong)config->va_bar0_address + config->bar0_rw_offset); + + return sprintf(buf, "%lx", data); +} + +static ssize_t pcie_gadget_store_bar0_data( + struct spear_pcie_gadget_config *config, + const char *buf, size_t count) +{ + ulong data; + + if (strict_strtoul(buf, 0, &data)) + return -EINVAL; + + if (!config->va_bar0_address) + return -ENOMEM; + + writel(data, (ulong)config->va_bar0_address + config->bar0_rw_offset); + + return count; +} + +/* + * Attribute definitions. + */ + +#define PCIE_GADGET_TARGET_ATTR_RO(_name) \ +static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ + __CONFIGFS_ATTR(_name, S_IRUGO, pcie_gadget_show_##_name, NULL) + +#define PCIE_GADGET_TARGET_ATTR_WO(_name) \ +static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ + __CONFIGFS_ATTR(_name, S_IWUSR, NULL, pcie_gadget_store_##_name) + +#define PCIE_GADGET_TARGET_ATTR_RW(_name) \ +static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ + __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, pcie_gadget_show_##_name, \ + pcie_gadget_store_##_name) +PCIE_GADGET_TARGET_ATTR_RW(link); +PCIE_GADGET_TARGET_ATTR_RW(int_type); +PCIE_GADGET_TARGET_ATTR_RW(no_of_msi); +PCIE_GADGET_TARGET_ATTR_WO(inta); +PCIE_GADGET_TARGET_ATTR_WO(send_msi); +PCIE_GADGET_TARGET_ATTR_RW(vendor_id); +PCIE_GADGET_TARGET_ATTR_RW(device_id); +PCIE_GADGET_TARGET_ATTR_RW(bar0_size); +PCIE_GADGET_TARGET_ATTR_RW(bar0_address); +PCIE_GADGET_TARGET_ATTR_RW(bar0_rw_offset); +PCIE_GADGET_TARGET_ATTR_RW(bar0_data); + +static struct configfs_attribute *pcie_gadget_target_attrs[] = { + &pcie_gadget_target_link.attr, + &pcie_gadget_target_int_type.attr, + &pcie_gadget_target_no_of_msi.attr, + &pcie_gadget_target_inta.attr, + &pcie_gadget_target_send_msi.attr, + &pcie_gadget_target_vendor_id.attr, + &pcie_gadget_target_device_id.attr, + &pcie_gadget_target_bar0_size.attr, + &pcie_gadget_target_bar0_address.attr, + &pcie_gadget_target_bar0_rw_offset.attr, + &pcie_gadget_target_bar0_data.attr, + NULL, +}; + +static struct pcie_gadget_target *to_target(struct config_item *item) +{ + return item ? + container_of(to_configfs_subsystem(to_config_group(item)), + struct pcie_gadget_target, subsys) : NULL; +} + +/* + * Item operations and type for pcie_gadget_target. + */ + +static ssize_t pcie_gadget_target_attr_show(struct config_item *item, + struct configfs_attribute *attr, + char *buf) +{ + ssize_t ret = -EINVAL; + struct pcie_gadget_target *target = to_target(item); + struct pcie_gadget_target_attr *t_attr = + container_of(attr, struct pcie_gadget_target_attr, attr); + + if (t_attr->show) + ret = t_attr->show(&target->config, buf); + return ret; +} + +static ssize_t pcie_gadget_target_attr_store(struct config_item *item, + struct configfs_attribute *attr, + const char *buf, + size_t count) +{ + ssize_t ret = -EINVAL; + struct pcie_gadget_target *target = to_target(item); + struct pcie_gadget_target_attr *t_attr = + container_of(attr, struct pcie_gadget_target_attr, attr); + + if (t_attr->store) + ret = t_attr->store(&target->config, buf, count); + return ret; +} + +static struct configfs_item_operations pcie_gadget_target_item_ops = { + .show_attribute = pcie_gadget_target_attr_show, + .store_attribute = pcie_gadget_target_attr_store, +}; + +static struct config_item_type pcie_gadget_target_type = { + .ct_attrs = pcie_gadget_target_attrs, + .ct_item_ops = &pcie_gadget_target_item_ops, + .ct_owner = THIS_MODULE, +}; + +static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config) +{ + struct pcie_app_reg __iomem *app_reg = config->va_app_base; + + /*setup registers for outbound translation */ + + writel(config->base, &app_reg->in0_mem_addr_start); + writel(app_reg->in0_mem_addr_start + IN0_MEM_SIZE, + &app_reg->in0_mem_addr_limit); + writel(app_reg->in0_mem_addr_limit + 1, &app_reg->in1_mem_addr_start); + writel(app_reg->in1_mem_addr_start + IN1_MEM_SIZE, + &app_reg->in1_mem_addr_limit); + writel(app_reg->in1_mem_addr_limit + 1, &app_reg->in_io_addr_start); + writel(app_reg->in_io_addr_start + IN_IO_SIZE, + &app_reg->in_io_addr_limit); + writel(app_reg->in_io_addr_limit + 1, &app_reg->in_cfg0_addr_start); + writel(app_reg->in_cfg0_addr_start + IN_CFG0_SIZE, + &app_reg->in_cfg0_addr_limit); + writel(app_reg->in_cfg0_addr_limit + 1, &app_reg->in_cfg1_addr_start); + writel(app_reg->in_cfg1_addr_start + IN_CFG1_SIZE, + &app_reg->in_cfg1_addr_limit); + writel(app_reg->in_cfg1_addr_limit + 1, &app_reg->in_msg_addr_start); + writel(app_reg->in_msg_addr_start + IN_MSG_SIZE, + &app_reg->in_msg_addr_limit); + + writel(app_reg->in0_mem_addr_start, &app_reg->pom0_mem_addr_start); + writel(app_reg->in1_mem_addr_start, &app_reg->pom1_mem_addr_start); + writel(app_reg->in_io_addr_start, &app_reg->pom_io_addr_start); + + /*setup registers for inbound translation */ + + /* Keep AORAM mapped at BAR0 as default */ + config->bar0_size = INBOUND_ADDR_MASK + 1; + spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, INBOUND_ADDR_MASK); + spear_dbi_write_reg(config, PCI_BASE_ADDRESS_0, 4, 0xC); + config->va_bar0_address = ioremap(SPEAR13XX_SYSRAM1_BASE, + config->bar0_size); + + writel(SPEAR13XX_SYSRAM1_BASE, &app_reg->pim0_mem_addr_start); + writel(0, &app_reg->pim1_mem_addr_start); + writel(INBOUND_ADDR_MASK + 1, &app_reg->mem0_addr_offset_limit); + + writel(0x0, &app_reg->pim_io_addr_start); + writel(0x0, &app_reg->pim_io_addr_start); + writel(0x0, &app_reg->pim_rom_addr_start); + + writel(DEVICE_TYPE_EP | (1 << MISCTRL_EN_ID) + | ((u32)1 << REG_TRANSLATION_ENABLE), + &app_reg->app_ctrl_0); + /* disable all rx interrupts */ + writel(0, &app_reg->int_mask); + + /* Select INTA as default*/ + spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); +} + +static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev) +{ + struct resource *res0, *res1; + unsigned int status = 0; + int irq; + struct clk *clk; + static struct pcie_gadget_target *target; + struct spear_pcie_gadget_config *config; + struct config_item *cg_item; + struct configfs_subsystem *subsys; + + /* get resource for application registers*/ + + res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res0) { + dev_err(&pdev->dev, "no resource defined\n"); + return -EBUSY; + } + if (!request_mem_region(res0->start, resource_size(res0), + pdev->name)) { + dev_err(&pdev->dev, "pcie gadget region already claimed\n"); + return -EBUSY; + } + /* get resource for dbi registers*/ + + res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res1) { + dev_err(&pdev->dev, "no resource defined\n"); + goto err_rel_res0; + } + if (!request_mem_region(res1->start, resource_size(res1), + pdev->name)) { + dev_err(&pdev->dev, "pcie gadget region already claimed\n"); + goto err_rel_res0; + } + + target = kzalloc(sizeof(*target), GFP_KERNEL); + if (!target) { + dev_err(&pdev->dev, "out of memory\n"); + status = -ENOMEM; + goto err_rel_res; + } + + cg_item = &target->subsys.su_group.cg_item; + sprintf(cg_item->ci_namebuf, "pcie_gadget.%d", pdev->id); + cg_item->ci_type = &pcie_gadget_target_type; + config = &target->config; + config->va_app_base = (void __iomem *)ioremap(res0->start, + resource_size(res0)); + if (!config->va_app_base) { + dev_err(&pdev->dev, "ioremap fail\n"); + status = -ENOMEM; + goto err_kzalloc; + } + + config->base = (void __iomem *)res1->start; + + config->va_dbi_base = (void __iomem *)ioremap(res1->start, + resource_size(res1)); + if (!config->va_dbi_base) { + dev_err(&pdev->dev, "ioremap fail\n"); + status = -ENOMEM; + goto err_iounmap_app; + } + + dev_set_drvdata(&pdev->dev, target); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no update irq?\n"); + status = irq; + goto err_iounmap; + } + + status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL); + if (status) { + dev_err(&pdev->dev, "pcie gadget interrupt IRQ%d already \ + claimed\n", irq); + goto err_iounmap; + } + + /* Register configfs hooks */ + subsys = &target->subsys; + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + status = configfs_register_subsystem(subsys); + if (status) + goto err_irq; + + /* + * init basic pcie application registers + * do not enable clock if it is PCIE0.Ideally , all controller should + * have been independent from others with respect to clock. But PCIE1 + * and 2 depends on PCIE0.So PCIE0 clk is provided during board init. + */ + if (pdev->id == 1) { + /* + * Ideally CFG Clock should have been also enabled here. But + * it is done currently during board init routne + */ + clk = clk_get_sys("pcie1", NULL); + if (IS_ERR(clk)) { + pr_err("%s:couldn't get clk for pcie1\n", __func__); + goto err_irq; + } + if (clk_enable(clk)) { + pr_err("%s:couldn't enable clk for pcie1\n", __func__); + goto err_irq; + } + } else if (pdev->id == 2) { + /* + * Ideally CFG Clock should have been also enabled here. But + * it is done currently during board init routne + */ + clk = clk_get_sys("pcie2", NULL); + if (IS_ERR(clk)) { + pr_err("%s:couldn't get clk for pcie2\n", __func__); + goto err_irq; + } + if (clk_enable(clk)) { + pr_err("%s:couldn't enable clk for pcie2\n", __func__); + goto err_irq; + } + } + spear13xx_pcie_device_init(config); + + return 0; +err_irq: + free_irq(irq, NULL); +err_iounmap: + iounmap(config->va_dbi_base); +err_iounmap_app: + iounmap(config->va_app_base); +err_kzalloc: + kfree(config); +err_rel_res: + release_mem_region(res1->start, resource_size(res1)); +err_rel_res0: + release_mem_region(res0->start, resource_size(res0)); + return status; +} + +static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev) +{ + struct resource *res0, *res1; + static struct pcie_gadget_target *target; + struct spear_pcie_gadget_config *config; + int irq; + + res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); + irq = platform_get_irq(pdev, 0); + target = dev_get_drvdata(&pdev->dev); + config = &target->config; + + free_irq(irq, NULL); + iounmap(config->va_dbi_base); + iounmap(config->va_app_base); + release_mem_region(res1->start, resource_size(res1)); + release_mem_region(res0->start, resource_size(res0)); + configfs_unregister_subsystem(&target->subsys); + kfree(target); + + return 0; +} + +static void spear_pcie_gadget_shutdown(struct platform_device *pdev) +{ +} + +static struct platform_driver spear_pcie_gadget_driver = { + .probe = spear_pcie_gadget_probe, + .remove = spear_pcie_gadget_remove, + .shutdown = spear_pcie_gadget_shutdown, + .driver = { + .name = "pcie-gadget-spear", + .bus = &platform_bus_type + }, +}; + +static int __init spear_pcie_gadget_init(void) +{ + return platform_driver_register(&spear_pcie_gadget_driver); +} +module_init(spear_pcie_gadget_init); + +static void __exit spear_pcie_gadget_exit(void) +{ + platform_driver_unregister(&spear_pcie_gadget_driver); +} +module_exit(spear_pcie_gadget_exit); + +MODULE_ALIAS("pcie-gadget-spear"); +MODULE_AUTHOR("Pratyush Anand"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 4e6735992392ecd393674119aef9ec7bff9be5b0 Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Tue, 22 Mar 2011 16:33:59 -0700 Subject: drivers/misc/apds9802als.c: put the device into runtime suspend after resume()/probe() is handled Put the device into runtime suspend after resume()/probe() is handled by the PM core and the device core code. No need to manually add them in each single driver. And correct the runtime state in remove(). Signed-off-by: Hong Liu Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/apds9802als.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 644d4cd071cc..81db7811cf68 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c @@ -245,9 +245,8 @@ static int apds9802als_probe(struct i2c_client *client, als_set_default_config(client); mutex_init(&data->mutex); + pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); - pm_runtime_get(&client->dev); - pm_runtime_put(&client->dev); return res; als_error1: @@ -255,12 +254,19 @@ als_error1: return res; } -static int apds9802als_remove(struct i2c_client *client) +static int __devexit apds9802als_remove(struct i2c_client *client) { struct als_data *data = i2c_get_clientdata(client); + pm_runtime_get_sync(&client->dev); + als_set_power_state(client, false); sysfs_remove_group(&client->dev.kobj, &m_als_gr); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + kfree(data); return 0; } @@ -275,9 +281,6 @@ static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg) static int apds9802als_resume(struct i2c_client *client) { als_set_default_config(client); - - pm_runtime_get(&client->dev); - pm_runtime_put(&client->dev); return 0; } @@ -323,7 +326,7 @@ static struct i2c_driver apds9802als_driver = { .pm = APDS9802ALS_PM_OPS, }, .probe = apds9802als_probe, - .remove = apds9802als_remove, + .remove = __devexit_p(apds9802als_remove), .suspend = apds9802als_suspend, .resume = apds9802als_resume, .id_table = apds9802als_id, -- cgit v1.2.2 From 6f7d485e13c6c07348cf9cfd1b735fe1bcf3caa9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 22 Mar 2011 16:34:00 -0700 Subject: drivers/misc/hmc6352.c: fix wrong return value checking for i2c_master_recv() i2c_master_recv() returns negative errno, or else the number of bytes read. Thus i2c_master_recv(client, i2c_data, 2) returns 2 instead of 1 in success case. [akpm@linux-foundation.org: make `ret' signed] Signed-off-by: Axel Lin Cc: Kalhan Trisal Cc: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/hmc6352.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c index 234bfcaf2099..ca938fc8a8d6 100644 --- a/drivers/misc/hmc6352.c +++ b/drivers/misc/hmc6352.c @@ -75,7 +75,7 @@ static ssize_t compass_heading_data_show(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); unsigned char i2c_data[2]; - unsigned int ret; + int ret; mutex_lock(&compass_mutex); ret = compass_command(client, 'A'); @@ -86,7 +86,7 @@ static ssize_t compass_heading_data_show(struct device *dev, msleep(10); /* sending 'A' cmd we need to wait for 7-10 millisecs */ ret = i2c_master_recv(client, i2c_data, 2); mutex_unlock(&compass_mutex); - if (ret != 1) { + if (ret < 0) { dev_warn(dev, "i2c read data cmd failed\n"); return ret; } -- cgit v1.2.2 From a844b43ca078d7dd8f0cd13c6f030ec62a996975 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 22 Mar 2011 16:34:01 -0700 Subject: drivers/misc/atmel_tclib.c: fix a memory leak request_mem_region() will call kzalloc to allocate memory for struct resource. release_resource() unregisters the resource but does not free the allocated memory, thus use release_mem_region() instead to fix the memory leak. Signed-off-by: Axel Lin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/atmel_tclib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index 3891124001f2..a844810b50f6 100644 --- a/drivers/misc/atmel_tclib.c +++ b/drivers/misc/atmel_tclib.c @@ -75,7 +75,7 @@ out: return tc; fail_ioremap: - release_resource(r); + release_mem_region(r->start, ATMEL_TC_IOMEM_SIZE); fail: tc = NULL; goto out; @@ -95,7 +95,7 @@ void atmel_tc_free(struct atmel_tc *tc) spin_lock(&tc_list_lock); if (tc->regs) { iounmap(tc->regs); - release_resource(tc->iomem); + release_mem_region(tc->iomem->start, ATMEL_TC_IOMEM_SIZE); tc->regs = NULL; tc->iomem = NULL; } -- cgit v1.2.2 From deb187e72470b0382d4f0cb859e76e1ebc3a1082 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Tue, 22 Mar 2011 16:34:01 -0700 Subject: drivers/misc/ep93xx_pwm.c: world-writable sysfs files Don't allow everybody to change device settings. Signed-off-by: Vasiliy Kulikov Acked-by: Hartley Sweeten Cc: Matthieu Crapet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/ep93xx_pwm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/ep93xx_pwm.c b/drivers/misc/ep93xx_pwm.c index 46b3439673e9..16d7179e2f9b 100644 --- a/drivers/misc/ep93xx_pwm.c +++ b/drivers/misc/ep93xx_pwm.c @@ -249,11 +249,11 @@ static ssize_t ep93xx_pwm_set_invert(struct device *dev, static DEVICE_ATTR(min_freq, S_IRUGO, ep93xx_pwm_get_min_freq, NULL); static DEVICE_ATTR(max_freq, S_IRUGO, ep93xx_pwm_get_max_freq, NULL); -static DEVICE_ATTR(freq, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(freq, S_IWUSR | S_IRUGO, ep93xx_pwm_get_freq, ep93xx_pwm_set_freq); -static DEVICE_ATTR(duty_percent, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(duty_percent, S_IWUSR | S_IRUGO, ep93xx_pwm_get_duty_percent, ep93xx_pwm_set_duty_percent); -static DEVICE_ATTR(invert, S_IWUGO | S_IRUGO, +static DEVICE_ATTR(invert, S_IWUSR | S_IRUGO, ep93xx_pwm_get_invert, ep93xx_pwm_set_invert); static struct attribute *ep93xx_pwm_attrs[] = { -- cgit v1.2.2 From b259514282d54323aaadead3dac4823ea01f9b89 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 22 Mar 2011 16:34:02 -0700 Subject: drivers/misc/pch_phub.c: add MODULE_DEVICE_TABLE The device table is required to load modules based on modaliases. Signed-off-by: Axel Lin Cc: Masayuki Ohtak Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/pch_phub.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 380ba806495d..a19cb710a246 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -735,6 +735,7 @@ static struct pci_device_id pch_phub_pcidev_id[] = { { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, }, { } }; +MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id); static struct pci_driver pch_phub_driver = { .name = "pch_phub", -- cgit v1.2.2 From 3bb598fb23b6040e67b5e6db9a00b28cd26e5809 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 22 Mar 2011 16:34:18 -0700 Subject: drivers/dca/dca-core.c: use list_move() instead of list_del()/list_add() combination Signed-off-by: Kirill A. Shutemov Cc: Maciej Sosnowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/dca/dca-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index c461eda62411..4abd089a094f 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -111,10 +111,8 @@ static void unregister_dca_providers(void) /* at this point only one domain in the list is expected */ domain = list_first_entry(&dca_domains, struct dca_domain, node); - list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) { - list_del(&dca->node); - list_add(&dca->node, &unregistered_providers); - } + list_for_each_entry_safe(dca, _dca, &domain->dca_providers, node) + list_move(&dca->node, &unregistered_providers); dca_free_domain(domain); -- cgit v1.2.2 From 33ee3b2e2eb9b4b6c64dcf9ed66e2ac3124e748c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 22 Mar 2011 16:34:40 -0700 Subject: kstrto*: converting strings to integers done (hopefully) right 1. simple_strto*() do not contain overflow checks and crufty, libc way to indicate failure. 2. strict_strto*() also do not have overflow checks but the name and comments pretend they do. 3. Both families have only "long long" and "long" variants, but users want strtou8() 4. Both "simple" and "strict" prefixes are wrong: Simple doesn't exactly say what's so simple, strict should not exist because conversion should be strict by default. The solution is to use "k" prefix and add convertors for more types. Enter kstrtoull() kstrtoll() kstrtoul() kstrtol() kstrtouint() kstrtoint() kstrtou64() kstrtos64() kstrtou32() kstrtos32() kstrtou16() kstrtos16() kstrtou8() kstrtos8() Include runtime testsuite (somewhat incomplete) as well. strict_strto*() become deprecated, stubbed to kstrto*() and eventually will be removed altogether. Use kstrto*() in code today! Note: on some archs _kstrtoul() and _kstrtol() are left in tree, even if they'll be unused at runtime. This is temporarily solution, because I don't want to hardcode list of archs where these functions aren't needed. Current solution with sizeof() and __alignof__ at least always works. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/via/viafbdev.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index d66f963e930e..137996dc547e 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -94,9 +94,6 @@ extern int viafb_LCD_ON; extern int viafb_DVI_ON; extern int viafb_hotplug; -extern int strict_strtoul(const char *cp, unsigned int base, - unsigned long *res); - u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, u8 index); -- cgit v1.2.2 From e359dc24d32e58c795fc339cb3e89ea6330fceae Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 22 Mar 2011 16:34:40 -0700 Subject: sigma-firmware: loader for Analog Devices' SigmaStudio Analog Devices' SigmaStudio can produce firmware blobs for devices with these DSPs embedded (like some audio codecs). Allow these device drivers to easily parse and load them. Signed-off-by: Mike Frysinger Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/Kconfig | 12 +++++ drivers/firmware/Makefile | 1 + drivers/firmware/sigma.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 drivers/firmware/sigma.c (limited to 'drivers') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 3c56afc5eb1b..b3a25a55ba23 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -145,4 +145,16 @@ config ISCSI_IBFT detect iSCSI boot parameters dynamically during system boot, say Y. Otherwise, say N. +config SIGMA + tristate "SigmaStudio firmware loader" + depends on I2C + select CRC32 + default n + help + Enable helper functions for working with Analog Devices SigmaDSP + parts and binary firmwares produced by Analog Devices SigmaStudio. + + If unsure, say N here. Drivers that need these helpers will select + this option automatically. + endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 20c17fca1232..00bb0b80a79f 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_DMIID) += dmi-id.o obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o +obj-$(CONFIG_SIGMA) += sigma.o diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c new file mode 100644 index 000000000000..c19cd2c39fa6 --- /dev/null +++ b/drivers/firmware/sigma.c @@ -0,0 +1,115 @@ +/* + * Load Analog Devices SigmaStudio firmware files + * + * Copyright 2009-2011 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include + +/* Return: 0==OK, <0==error, =1 ==no more actions */ +static int +process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw) +{ + struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos); + size_t len = sigma_action_len(sa); + int ret = 0; + + pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, + sa->instr, sa->addr, len); + + switch (sa->instr) { + case SIGMA_ACTION_WRITEXBYTES: + case SIGMA_ACTION_WRITESINGLE: + case SIGMA_ACTION_WRITESAFELOAD: + if (ssfw->fw->size < ssfw->pos + len) + return -EINVAL; + ret = i2c_master_send(client, (void *)&sa->addr, len); + if (ret < 0) + return -EINVAL; + break; + + case SIGMA_ACTION_DELAY: + ret = 0; + udelay(len); + len = 0; + break; + + case SIGMA_ACTION_END: + return 1; + + default: + return -EINVAL; + } + + /* when arrive here ret=0 or sent data */ + ssfw->pos += sigma_action_size(sa, len); + return ssfw->pos == ssfw->fw->size; +} + +static int +process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw) +{ + pr_debug("%s: processing %p\n", __func__, ssfw); + + while (1) { + int ret = process_sigma_action(client, ssfw); + pr_debug("%s: action returned %i\n", __func__, ret); + if (ret == 1) + return 0; + else if (ret) + return ret; + } +} + +int process_sigma_firmware(struct i2c_client *client, const char *name) +{ + int ret; + struct sigma_firmware_header *ssfw_head; + struct sigma_firmware ssfw; + const struct firmware *fw; + u32 crc; + + pr_debug("%s: loading firmware %s\n", __func__, name); + + /* first load the blob */ + ret = request_firmware(&fw, name, &client->dev); + if (ret) { + pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); + return ret; + } + ssfw.fw = fw; + + /* then verify the header */ + ret = -EINVAL; + if (fw->size < sizeof(*ssfw_head)) + goto done; + + ssfw_head = (void *)fw->data; + if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) + goto done; + + crc = crc32(0, fw->data, fw->size); + pr_debug("%s: crc=%x\n", __func__, crc); + if (crc != ssfw_head->crc) + goto done; + + ssfw.pos = sizeof(*ssfw_head); + + /* finally process all of the actions */ + ret = process_sigma_actions(client, &ssfw); + + done: + release_firmware(fw); + + pr_debug("%s: loaded %s\n", __func__, name); + + return ret; +} +EXPORT_SYMBOL(process_sigma_firmware); -- cgit v1.2.2 From 2092014df6e62b3ddfe8b6199da98cacfc055e23 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 22 Mar 2011 16:34:41 -0700 Subject: drivers/mmc/host/omap.c: use resource_size() Signed-off-by: Chris Ball Cc: Jarkko Lavinen Cc: Tony Lindgren Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/omap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 379d2ffe4c87..2e032f0e8cf4 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1417,7 +1417,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev) if (res == NULL || irq < 0) return -ENXIO; - res = request_mem_region(res->start, res->end - res->start + 1, + res = request_mem_region(res->start, resource_size(res), pdev->name); if (res == NULL) return -EBUSY; @@ -1457,7 +1457,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev) host->irq = irq; host->phys_base = host->mem_res->start; - host->virt_base = ioremap(res->start, res->end - res->start + 1); + host->virt_base = ioremap(res->start, resource_size(res)); if (!host->virt_base) goto err_ioremap; @@ -1514,7 +1514,7 @@ err_free_mmc_host: err_ioremap: kfree(host); err_free_mem_region: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); return ret; } -- cgit v1.2.2 From 984b203a7237d8d32090b48113c18eb8f824a2be Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 22 Mar 2011 16:34:42 -0700 Subject: drivers/mmc/host/omap_hsmmc.c: use resource_size() Use resource_size(). Signed-off-by: Chris Ball Cc: Madhusudhan Chikkature Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/omap_hsmmc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 158c0ee53b2c..259ece047afc 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2047,8 +2047,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) res->start += pdata->reg_offset; res->end += pdata->reg_offset; - res = request_mem_region(res->start, res->end - res->start + 1, - pdev->name); + res = request_mem_region(res->start, resource_size(res), pdev->name); if (res == NULL) return -EBUSY; @@ -2287,7 +2286,7 @@ err1: err_alloc: omap_hsmmc_gpio_free(pdata); err: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); return ret; } @@ -2324,7 +2323,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); return 0; -- cgit v1.2.2 From bc96ba7414ca4456661d0873856e0f363d32ba67 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 22 Mar 2011 16:34:52 -0700 Subject: rtc: convert DS1374 to dev_pm_ops There is a general move to replace bus-specific PM ops with dev_pm_ops in order to facilitate core improvements. Do this conversion for DS1374. Signed-off-by: Mark Brown Cc: Alessandro Zummo Cc: john stultz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds1374.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index d834a63ec4b0..e6e71deb188f 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -25,6 +25,7 @@ #include #include #include +#include #define DS1374_REG_TOD0 0x00 /* Time of Day */ #define DS1374_REG_TOD1 0x01 @@ -409,32 +410,38 @@ static int __devexit ds1374_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int ds1374_suspend(struct i2c_client *client, pm_message_t state) +static int ds1374_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + if (client->irq >= 0 && device_may_wakeup(&client->dev)) enable_irq_wake(client->irq); return 0; } -static int ds1374_resume(struct i2c_client *client) +static int ds1374_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + if (client->irq >= 0 && device_may_wakeup(&client->dev)) disable_irq_wake(client->irq); return 0; } + +static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume); + +#define DS1374_PM (&ds1374_pm) #else -#define ds1374_suspend NULL -#define ds1374_resume NULL +#define DS1374_PM NULL #endif static struct i2c_driver ds1374_driver = { .driver = { .name = "rtc-ds1374", .owner = THIS_MODULE, + .pm = DS1374_PM, }, .probe = ds1374_probe, - .suspend = ds1374_suspend, - .resume = ds1374_resume, .remove = __devexit_p(ds1374_remove), .id_table = ds1374_id, }; -- cgit v1.2.2 From cf044f0ed526752b8c2aaae748220759608b3fc8 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Tue, 22 Mar 2011 16:34:53 -0700 Subject: drivers/rtc/rtc-isl1208.c: add alarm support Add alarm/wakeup support to rtc isl1208 driver Signed-off-by: Ryan Mallon Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-isl1208.c | 176 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 468200c38ecb..da8beb8cae51 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -39,6 +39,8 @@ #define ISL1208_REG_SR_BAT (1<<1) /* battery */ #define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */ #define ISL1208_REG_INT 0x08 +#define ISL1208_REG_INT_ALME (1<<6) /* alarm enable */ +#define ISL1208_REG_INT_IM (1<<7) /* interrupt/alarm mode */ #define ISL1208_REG_09 0x09 /* reserved */ #define ISL1208_REG_ATR 0x0a #define ISL1208_REG_DTR 0x0b @@ -201,6 +203,30 @@ isl1208_i2c_set_usr(struct i2c_client *client, u16 usr) ISL1208_USR_SECTION_LEN); } +static int +isl1208_rtc_toggle_alarm(struct i2c_client *client, int enable) +{ + int icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT); + + if (icr < 0) { + dev_err(&client->dev, "%s: reading INT failed\n", __func__); + return icr; + } + + if (enable) + icr |= ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM; + else + icr &= ~(ISL1208_REG_INT_ALME | ISL1208_REG_INT_IM); + + icr = i2c_smbus_write_byte_data(client, ISL1208_REG_INT, icr); + if (icr < 0) { + dev_err(&client->dev, "%s: writing INT failed\n", __func__); + return icr; + } + + return 0; +} + static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq) { @@ -288,9 +314,8 @@ isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) { struct rtc_time *const tm = &alarm->time; u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; - int sr; + int icr, yr, sr = isl1208_i2c_get_sr(client); - sr = isl1208_i2c_get_sr(client); if (sr < 0) { dev_err(&client->dev, "%s: reading SR failed\n", __func__); return sr; @@ -313,6 +338,73 @@ isl1208_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) bcd2bin(regs[ISL1208_REG_MOA - ISL1208_REG_SCA] & 0x1f) - 1; tm->tm_wday = bcd2bin(regs[ISL1208_REG_DWA - ISL1208_REG_SCA] & 0x03); + /* The alarm doesn't store the year so get it from the rtc section */ + yr = i2c_smbus_read_byte_data(client, ISL1208_REG_YR); + if (yr < 0) { + dev_err(&client->dev, "%s: reading RTC YR failed\n", __func__); + return yr; + } + tm->tm_year = bcd2bin(yr) + 100; + + icr = i2c_smbus_read_byte_data(client, ISL1208_REG_INT); + if (icr < 0) { + dev_err(&client->dev, "%s: reading INT failed\n", __func__); + return icr; + } + alarm->enabled = !!(icr & ISL1208_REG_INT_ALME); + + return 0; +} + +static int +isl1208_i2c_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm) +{ + struct rtc_time *alarm_tm = &alarm->time; + u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, }; + const int offs = ISL1208_REG_SCA; + unsigned long rtc_secs, alarm_secs; + struct rtc_time rtc_tm; + int err, enable; + + err = isl1208_i2c_read_time(client, &rtc_tm); + if (err) + return err; + err = rtc_tm_to_time(&rtc_tm, &rtc_secs); + if (err) + return err; + err = rtc_tm_to_time(alarm_tm, &alarm_secs); + if (err) + return err; + + /* If the alarm time is before the current time disable the alarm */ + if (!alarm->enabled || alarm_secs <= rtc_secs) + enable = 0x00; + else + enable = 0x80; + + /* Program the alarm and enable it for each setting */ + regs[ISL1208_REG_SCA - offs] = bin2bcd(alarm_tm->tm_sec) | enable; + regs[ISL1208_REG_MNA - offs] = bin2bcd(alarm_tm->tm_min) | enable; + regs[ISL1208_REG_HRA - offs] = bin2bcd(alarm_tm->tm_hour) | + ISL1208_REG_HR_MIL | enable; + + regs[ISL1208_REG_DTA - offs] = bin2bcd(alarm_tm->tm_mday) | enable; + regs[ISL1208_REG_MOA - offs] = bin2bcd(alarm_tm->tm_mon + 1) | enable; + regs[ISL1208_REG_DWA - offs] = bin2bcd(alarm_tm->tm_wday & 7) | enable; + + /* write ALARM registers */ + err = isl1208_i2c_set_regs(client, offs, regs, + ISL1208_ALARM_SECTION_LEN); + if (err < 0) { + dev_err(&client->dev, "%s: writing ALARM section failed\n", + __func__); + return err; + } + + err = isl1208_rtc_toggle_alarm(client, enable); + if (err) + return err; + return 0; } @@ -391,12 +483,63 @@ isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm); } +static int +isl1208_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + return isl1208_i2c_set_alarm(to_i2c_client(dev), alarm); +} + +static irqreturn_t +isl1208_rtc_interrupt(int irq, void *data) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + struct i2c_client *client = data; + int handled = 0, sr, err; + + /* + * I2C reads get NAK'ed if we read straight away after an interrupt? + * Using a mdelay/msleep didn't seem to help either, so we work around + * this by continually trying to read the register for a short time. + */ + while (1) { + sr = isl1208_i2c_get_sr(client); + if (sr >= 0) + break; + + if (time_after(jiffies, timeout)) { + dev_err(&client->dev, "%s: reading SR failed\n", + __func__); + return sr; + } + } + + if (sr & ISL1208_REG_SR_ALM) { + dev_dbg(&client->dev, "alarm!\n"); + + /* Clear the alarm */ + sr &= ~ISL1208_REG_SR_ALM; + sr = i2c_smbus_write_byte_data(client, ISL1208_REG_SR, sr); + if (sr < 0) + dev_err(&client->dev, "%s: writing SR failed\n", + __func__); + else + handled = 1; + + /* Disable the alarm */ + err = isl1208_rtc_toggle_alarm(client, 0); + if (err) + return err; + } + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + static const struct rtc_class_ops isl1208_rtc_ops = { .proc = isl1208_rtc_proc, .read_time = isl1208_rtc_read_time, .set_time = isl1208_rtc_set_time, .read_alarm = isl1208_rtc_read_alarm, - /*.set_alarm = isl1208_rtc_set_alarm, */ + .set_alarm = isl1208_rtc_set_alarm, }; /* sysfs interface */ @@ -488,11 +631,29 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + if (client->irq > 0) { + rc = request_threaded_irq(client->irq, NULL, + isl1208_rtc_interrupt, + IRQF_SHARED, + isl1208_driver.driver.name, client); + if (!rc) { + device_init_wakeup(&client->dev, 1); + enable_irq_wake(client->irq); + } else { + dev_err(&client->dev, + "Unable to request irq %d, no alarm support\n", + client->irq); + client->irq = 0; + } + } + rtc = rtc_device_register(isl1208_driver.driver.name, &client->dev, &isl1208_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (IS_ERR(rtc)) { + rc = PTR_ERR(rtc); + goto exit_free_irq; + } i2c_set_clientdata(client, rtc); @@ -514,6 +675,9 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) exit_unregister: rtc_device_unregister(rtc); +exit_free_irq: + if (client->irq) + free_irq(client->irq, client); return rc; } @@ -525,6 +689,8 @@ isl1208_remove(struct i2c_client *client) sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); rtc_device_unregister(rtc); + if (client->irq) + free_irq(client->irq, client); return 0; } -- cgit v1.2.2 From 49d50fb1c28738ef6bad0c2b87d5355a1653fed5 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Tue, 22 Mar 2011 16:34:53 -0700 Subject: drivers/rtc/rtc-ds1511.c: world-writable sysfs nvram file Don't allow everybogy to write to NVRAM. Signed-off-by: Vasiliy Kulikov Cc: Andy Sharp Cc: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-ds1511.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 3fffd708711f..fbabc773dded 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -468,7 +468,7 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj, static struct bin_attribute ds1511_nvram_attr = { .attr = { .name = "nvram", - .mode = S_IRUGO | S_IWUGO, + .mode = S_IRUGO | S_IWUSR, }, .size = DS1511_RAM_MAX, .read = ds1511_nvram_read, -- cgit v1.2.2 From ff859ba6d166202d6fd8d6344a41be54e4c8a2b6 Mon Sep 17 00:00:00 2001 From: Andrew Chew Date: Tue, 22 Mar 2011 16:34:55 -0700 Subject: rtc: add real-time clock driver for NVIDIA Tegra This is a platform driver that supports the built-in real-time clock on Tegra SOCs. Signed-off-by: Andrew Chew Acked-by: Alessandro Zummo Acked-by: Wan ZongShun Acked-by: Jon Mayo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 10 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-tegra.c | 488 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 499 insertions(+) create mode 100644 drivers/rtc/rtc-tegra.c (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4941cade319f..e1878877399c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -985,4 +985,14 @@ config RTC_DRV_LPC32XX This driver can also be buillt as a module. If so, the module will be called rtc-lpc32xx. +config RTC_DRV_TEGRA + tristate "NVIDIA Tegra Internal RTC driver" + depends on RTC_CLASS && ARCH_TEGRA + help + If you say yes here you get support for the + Tegra 200 series internal RTC module. + + This drive can also be built as a module. If so, the module + will be called rtc-tegra. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 5f6c3838dcf6..ca91c3c42e98 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o +obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c new file mode 100644 index 000000000000..2fc31aac3f4e --- /dev/null +++ b/drivers/rtc/rtc-tegra.c @@ -0,0 +1,488 @@ +/* + * An RTC driver for the NVIDIA Tegra 200 series internal RTC. + * + * Copyright (c) 2010, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */ +#define TEGRA_RTC_REG_BUSY 0x004 +#define TEGRA_RTC_REG_SECONDS 0x008 +/* when msec is read, the seconds are buffered into shadow seconds. */ +#define TEGRA_RTC_REG_SHADOW_SECONDS 0x00c +#define TEGRA_RTC_REG_MILLI_SECONDS 0x010 +#define TEGRA_RTC_REG_SECONDS_ALARM0 0x014 +#define TEGRA_RTC_REG_SECONDS_ALARM1 0x018 +#define TEGRA_RTC_REG_MILLI_SECONDS_ALARM0 0x01c +#define TEGRA_RTC_REG_INTR_MASK 0x028 +/* write 1 bits to clear status bits */ +#define TEGRA_RTC_REG_INTR_STATUS 0x02c + +/* bits in INTR_MASK */ +#define TEGRA_RTC_INTR_MASK_MSEC_CDN_ALARM (1<<4) +#define TEGRA_RTC_INTR_MASK_SEC_CDN_ALARM (1<<3) +#define TEGRA_RTC_INTR_MASK_MSEC_ALARM (1<<2) +#define TEGRA_RTC_INTR_MASK_SEC_ALARM1 (1<<1) +#define TEGRA_RTC_INTR_MASK_SEC_ALARM0 (1<<0) + +/* bits in INTR_STATUS */ +#define TEGRA_RTC_INTR_STATUS_MSEC_CDN_ALARM (1<<4) +#define TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM (1<<3) +#define TEGRA_RTC_INTR_STATUS_MSEC_ALARM (1<<2) +#define TEGRA_RTC_INTR_STATUS_SEC_ALARM1 (1<<1) +#define TEGRA_RTC_INTR_STATUS_SEC_ALARM0 (1<<0) + +struct tegra_rtc_info { + struct platform_device *pdev; + struct rtc_device *rtc_dev; + void __iomem *rtc_base; /* NULL if not initialized. */ + int tegra_rtc_irq; /* alarm and periodic irq */ + spinlock_t tegra_rtc_lock; +}; + +/* RTC hardware is busy when it is updating its values over AHB once + * every eight 32kHz clocks (~250uS). + * outside of these updates the CPU is free to write. + * CPU is always free to read. + */ +static inline u32 tegra_rtc_check_busy(struct tegra_rtc_info *info) +{ + return readl(info->rtc_base + TEGRA_RTC_REG_BUSY) & 1; +} + +/* Wait for hardware to be ready for writing. + * This function tries to maximize the amount of time before the next update. + * It does this by waiting for the RTC to become busy with its periodic update, + * then returning once the RTC first becomes not busy. + * This periodic update (where the seconds and milliseconds are copied to the + * AHB side) occurs every eight 32kHz clocks (~250uS). + * The behavior of this function allows us to make some assumptions without + * introducing a race, because 250uS is plenty of time to read/write a value. + */ +static int tegra_rtc_wait_while_busy(struct device *dev) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + + int retries = 500; /* ~490 us is the worst case, ~250 us is best. */ + + /* first wait for the RTC to become busy. this is when it + * posts its updated seconds+msec registers to AHB side. */ + while (tegra_rtc_check_busy(info)) { + if (!retries--) + goto retry_failed; + udelay(1); + } + + /* now we have about 250 us to manipulate registers */ + return 0; + +retry_failed: + dev_err(dev, "write failed:retry count exceeded.\n"); + return -ETIMEDOUT; +} + +static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec, msec; + unsigned long sl_irq_flags; + + /* RTC hardware copies seconds to shadow seconds when a read + * of milliseconds occurs. use a lock to keep other threads out. */ + spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + + msec = readl(info->rtc_base + TEGRA_RTC_REG_MILLI_SECONDS); + sec = readl(info->rtc_base + TEGRA_RTC_REG_SHADOW_SECONDS); + + spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + + rtc_time_to_tm(sec, tm); + + dev_vdbg(dev, "time read as %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_year + 1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec + ); + + return 0; +} + +static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec; + int ret; + + /* convert tm to seconds. */ + ret = rtc_valid_tm(tm); + if (ret) + return ret; + + rtc_tm_to_time(tm, &sec); + + dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + tm->tm_mon+1, + tm->tm_mday, + tm->tm_year+1900, + tm->tm_hour, + tm->tm_min, + tm->tm_sec + ); + + /* seconds only written if wait succeeded. */ + ret = tegra_rtc_wait_while_busy(dev); + if (!ret) + writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS); + + dev_vdbg(dev, "time read back as %d\n", + readl(info->rtc_base + TEGRA_RTC_REG_SECONDS)); + + return ret; +} + +static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec; + unsigned tmp; + + sec = readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + + if (sec == 0) { + /* alarm is disabled. */ + alarm->enabled = 0; + alarm->time.tm_mon = -1; + alarm->time.tm_mday = -1; + alarm->time.tm_year = -1; + alarm->time.tm_hour = -1; + alarm->time.tm_min = -1; + alarm->time.tm_sec = -1; + } else { + /* alarm is enabled. */ + alarm->enabled = 1; + rtc_time_to_tm(sec, &alarm->time); + } + + tmp = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + alarm->pending = (tmp & TEGRA_RTC_INTR_STATUS_SEC_ALARM0) != 0; + + return 0; +} + +static int tegra_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned status; + unsigned long sl_irq_flags; + + tegra_rtc_wait_while_busy(dev); + spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + + /* read the original value, and OR in the flag. */ + status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + if (enabled) + status |= TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* set it */ + else + status &= ~TEGRA_RTC_INTR_MASK_SEC_ALARM0; /* clear it */ + + writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + + spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + + return 0; +} + +static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long sec; + + if (alarm->enabled) + rtc_tm_to_time(&alarm->time, &sec); + else + sec = 0; + + tegra_rtc_wait_while_busy(dev); + writel(sec, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + dev_vdbg(dev, "alarm read back as %d\n", + readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); + + /* if successfully written and alarm is enabled ... */ + if (sec) { + tegra_rtc_alarm_irq_enable(dev, 1); + + dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n", + sec, + alarm->time.tm_mon+1, + alarm->time.tm_mday, + alarm->time.tm_year+1900, + alarm->time.tm_hour, + alarm->time.tm_min, + alarm->time.tm_sec); + } else { + /* disable alarm if 0 or write error. */ + dev_vdbg(dev, "alarm disabled\n"); + tegra_rtc_alarm_irq_enable(dev, 0); + } + + return 0; +} + +static int tegra_rtc_proc(struct device *dev, struct seq_file *seq) +{ + if (!dev || !dev->driver) + return 0; + + return seq_printf(seq, "name\t\t: %s\n", dev_name(dev)); +} + +static irqreturn_t tegra_rtc_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct tegra_rtc_info *info = dev_get_drvdata(dev); + unsigned long events = 0; + unsigned status; + unsigned long sl_irq_flags; + + status = readl(info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + if (status) { + /* clear the interrupt masks and status on any irq. */ + tegra_rtc_wait_while_busy(dev); + spin_lock_irqsave(&info->tegra_rtc_lock, sl_irq_flags); + writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + writel(status, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + spin_unlock_irqrestore(&info->tegra_rtc_lock, sl_irq_flags); + } + + /* check if Alarm */ + if ((status & TEGRA_RTC_INTR_STATUS_SEC_ALARM0)) + events |= RTC_IRQF | RTC_AF; + + /* check if Periodic */ + if ((status & TEGRA_RTC_INTR_STATUS_SEC_CDN_ALARM)) + events |= RTC_IRQF | RTC_PF; + + rtc_update_irq(info->rtc_dev, 1, events); + + return IRQ_HANDLED; +} + +static struct rtc_class_ops tegra_rtc_ops = { + .read_time = tegra_rtc_read_time, + .set_time = tegra_rtc_set_time, + .read_alarm = tegra_rtc_read_alarm, + .set_alarm = tegra_rtc_set_alarm, + .proc = tegra_rtc_proc, + .alarm_irq_enable = tegra_rtc_alarm_irq_enable, +}; + +static int __devinit tegra_rtc_probe(struct platform_device *pdev) +{ + struct tegra_rtc_info *info; + struct resource *res; + int ret; + + info = kzalloc(sizeof(struct tegra_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, + "Unable to allocate resources for device.\n"); + ret = -EBUSY; + goto err_free_info; + } + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) { + dev_err(&pdev->dev, + "Unable to request mem region for device.\n"); + ret = -EBUSY; + goto err_free_info; + } + + info->tegra_rtc_irq = platform_get_irq(pdev, 0); + if (info->tegra_rtc_irq <= 0) { + ret = -EBUSY; + goto err_release_mem_region; + } + + info->rtc_base = ioremap_nocache(res->start, resource_size(res)); + if (!info->rtc_base) { + dev_err(&pdev->dev, "Unable to grab IOs for device.\n"); + ret = -EBUSY; + goto err_release_mem_region; + } + + /* set context info. */ + info->pdev = pdev; + info->tegra_rtc_lock = __SPIN_LOCK_UNLOCKED(info->tegra_rtc_lock); + + platform_set_drvdata(pdev, info); + + /* clear out the hardware. */ + writel(0, info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0); + writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + writel(0, info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + + device_init_wakeup(&pdev->dev, 1); + + info->rtc_dev = rtc_device_register( + pdev->name, &pdev->dev, &tegra_rtc_ops, THIS_MODULE); + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + info->rtc_dev = NULL; + dev_err(&pdev->dev, + "Unable to register device (err=%d).\n", + ret); + goto err_iounmap; + } + + ret = request_irq(info->tegra_rtc_irq, tegra_rtc_irq_handler, + IRQF_TRIGGER_HIGH, "rtc alarm", &pdev->dev); + if (ret) { + dev_err(&pdev->dev, + "Unable to request interrupt for device (err=%d).\n", + ret); + goto err_dev_unreg; + } + + dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n"); + + return 0; + +err_dev_unreg: + rtc_device_unregister(info->rtc_dev); +err_iounmap: + iounmap(info->rtc_base); +err_release_mem_region: + release_mem_region(res->start, resource_size(res)); +err_free_info: + kfree(info); + + return ret; +} + +static int __devexit tegra_rtc_remove(struct platform_device *pdev) +{ + struct tegra_rtc_info *info = platform_get_drvdata(pdev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EBUSY; + + free_irq(info->tegra_rtc_irq, &pdev->dev); + rtc_device_unregister(info->rtc_dev); + iounmap(info->rtc_base); + release_mem_region(res->start, resource_size(res)); + kfree(info); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int tegra_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct device *dev = &pdev->dev; + struct tegra_rtc_info *info = platform_get_drvdata(pdev); + + tegra_rtc_wait_while_busy(dev); + + /* only use ALARM0 as a wake source. */ + writel(0xffffffff, info->rtc_base + TEGRA_RTC_REG_INTR_STATUS); + writel(TEGRA_RTC_INTR_STATUS_SEC_ALARM0, + info->rtc_base + TEGRA_RTC_REG_INTR_MASK); + + dev_vdbg(dev, "alarm sec = %d\n", + readl(info->rtc_base + TEGRA_RTC_REG_SECONDS_ALARM0)); + + dev_vdbg(dev, "Suspend (device_may_wakeup=%d) irq:%d\n", + device_may_wakeup(dev), info->tegra_rtc_irq); + + /* leave the alarms on as a wake source. */ + if (device_may_wakeup(dev)) + enable_irq_wake(info->tegra_rtc_irq); + + return 0; +} + +static int tegra_rtc_resume(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_rtc_info *info = platform_get_drvdata(pdev); + + dev_vdbg(dev, "Resume (device_may_wakeup=%d)\n", + device_may_wakeup(dev)); + /* alarms were left on as a wake source, turn them off. */ + if (device_may_wakeup(dev)) + disable_irq_wake(info->tegra_rtc_irq); + + return 0; +} +#endif + +static void tegra_rtc_shutdown(struct platform_device *pdev) +{ + dev_vdbg(&pdev->dev, "disabling interrupts.\n"); + tegra_rtc_alarm_irq_enable(&pdev->dev, 0); +} + +MODULE_ALIAS("platform:tegra_rtc"); +static struct platform_driver tegra_rtc_driver = { + .remove = __devexit_p(tegra_rtc_remove), + .shutdown = tegra_rtc_shutdown, + .driver = { + .name = "tegra_rtc", + .owner = THIS_MODULE, + }, +#ifdef CONFIG_PM + .suspend = tegra_rtc_suspend, + .resume = tegra_rtc_resume, +#endif +}; + +static int __init tegra_rtc_init(void) +{ + return platform_driver_probe(&tegra_rtc_driver, tegra_rtc_probe); +} +module_init(tegra_rtc_init); + +static void __exit tegra_rtc_exit(void) +{ + platform_driver_unregister(&tegra_rtc_driver); +} +module_exit(tegra_rtc_exit); + +MODULE_AUTHOR("Jon Mayo "); +MODULE_DESCRIPTION("driver for Tegra internal RTC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 586f83e2b4c080073b115c1a0fcc2757f52839b8 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 22 Mar 2011 16:34:56 -0700 Subject: pnp: only assign IORESOURCE_DMA if CONFIG_ISA_DMA_API is enabled IORESOURCE_DMA cannot be assigned without utilizing the interface provided by CONFIG_ISA_DMA_API, specifically request_dma() and free_dma(). Thus, there's a strict dependency on the config option and limits IORESOURCE_DMA only to architectures that support ISA-style DMA. ia64 is not one of those architectures, so pnp_check_dma() no longer needs to be special-cased for that architecture. pnp_assign_resources() will now return -EINVAL if IORESOURCE_DMA is attempted on such a kernel. Signed-off-by: David Rientjes Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Bjorn Helgaas Cc: Russell King Cc: "Luck, Tony" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pnp/base.h | 2 ++ drivers/pnp/manager.c | 7 ++++++- drivers/pnp/resource.c | 7 ++----- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 19bc73695475..fa4e0a5db3f8 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -142,7 +142,9 @@ void __pnp_remove_device(struct pnp_dev *dev); int pnp_check_port(struct pnp_dev *dev, struct resource *res); int pnp_check_mem(struct pnp_dev *dev, struct resource *res); int pnp_check_irq(struct pnp_dev *dev, struct resource *res); +#ifdef CONFIG_ISA_DMA_API int pnp_check_dma(struct pnp_dev *dev, struct resource *res); +#endif char *pnp_resource_type_name(struct resource *res); void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc); diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index 0a15664eef1c..ed9ce507149a 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -171,6 +171,7 @@ __add: return 0; } +#ifdef CONFIG_ISA_DMA_API static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx) { struct resource *res, local_res; @@ -210,6 +211,7 @@ __add: pnp_add_dma_resource(dev, res->start, res->flags); return 0; } +#endif /* CONFIG_ISA_DMA_API */ void pnp_init_resources(struct pnp_dev *dev) { @@ -234,7 +236,8 @@ static void pnp_clean_resource_table(struct pnp_dev *dev) static int pnp_assign_resources(struct pnp_dev *dev, int set) { struct pnp_option *option; - int nport = 0, nmem = 0, nirq = 0, ndma = 0; + int nport = 0, nmem = 0, nirq = 0; + int ndma __maybe_unused = 0; int ret = 0; pnp_dbg(&dev->dev, "pnp_assign_resources, try dependent set %d\n", set); @@ -256,9 +259,11 @@ static int pnp_assign_resources(struct pnp_dev *dev, int set) case IORESOURCE_IRQ: ret = pnp_assign_irq(dev, &option->u.irq, nirq++); break; +#ifdef CONFIG_ISA_DMA_API case IORESOURCE_DMA: ret = pnp_assign_dma(dev, &option->u.dma, ndma++); break; +#endif default: ret = -EINVAL; break; diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index a925e6b63d72..b0ecacbe53b1 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -409,9 +409,9 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res) return 1; } +#ifdef CONFIG_ISA_DMA_API int pnp_check_dma(struct pnp_dev *dev, struct resource *res) { -#ifndef CONFIG_IA64 int i; struct pnp_dev *tdev; struct resource *tres; @@ -466,11 +466,8 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res) } return 1; -#else - /* IA64 does not have legacy DMA */ - return 0; -#endif } +#endif /* CONFIG_ISA_DMA_API */ unsigned long pnp_resource_type(struct resource *res) { -- cgit v1.2.2 From 77d1c8eb8a8e0989f4c46e9a40bbd4185d34974e Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 22 Mar 2011 16:35:06 -0700 Subject: pps: remove unreachable code Remove code enabled only when CONFIG_PREEMPT_RT is turned on because it is not used in the vanilla kernel. Signed-off-by: Alexander Gordeev Cc: john stultz Cc: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/generators/pps_gen_parport.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c index b93af3ebb5ba..dcd39fba6ddd 100644 --- a/drivers/pps/generators/pps_gen_parport.c +++ b/drivers/pps/generators/pps_gen_parport.c @@ -216,11 +216,6 @@ static void parport_attach(struct parport *port) hrtimer_init(&device.timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); device.timer.function = hrtimer_event; -#ifdef CONFIG_PREEMPT_RT - /* hrtimer interrupt will run in the interrupt context with this */ - device.timer.irqsafe = 1; -#endif - hrtimer_start(&device.timer, next_intr_time(&device), HRTIMER_MODE_ABS); return; -- cgit v1.2.2 From 565d76cb7d5fd7cb010fd690602280a69ab116ef Mon Sep 17 00:00:00 2001 From: Jim Keniston Date: Tue, 22 Mar 2011 16:35:12 -0700 Subject: zlib: slim down zlib_deflate() workspace when possible Instead of always creating a huge (268K) deflate_workspace with the maximum compression parameters (windowBits=15, memLevel=8), allow the caller to obtain a smaller workspace by specifying smaller parameter values. For example, when capturing oops and panic reports to a medium with limited capacity, such as NVRAM, compression may be the only way to capture the whole report. In this case, a small workspace (24K works fine) is a win, whether you allocate the workspace when you need it (i.e., during an oops or panic) or at boot time. I've verified that this patch works with all accepted values of windowBits (positive and negative), memLevel, and compression level. Signed-off-by: Jim Keniston Cc: Herbert Xu Cc: David Miller Cc: Chris Mason Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/ppp_deflate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index 43583309a65d..31e9407a0739 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c @@ -129,7 +129,7 @@ static void *z_comp_alloc(unsigned char *options, int opt_len) state->strm.next_in = NULL; state->w_size = w_size; - state->strm.workspace = vmalloc(zlib_deflate_workspacesize()); + state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8)); if (state->strm.workspace == NULL) goto out_free; -- cgit v1.2.2 From d88d6b05fee3cc78e5b0273eb58c31201dcc6b76 Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Tue, 22 Mar 2011 19:46:43 +0000 Subject: sfc: Siena: Disable write-combining when SR-IOV is enabled If SR-IOV is enabled by firmware, even if it is not enabled in the PCI capability, TX pushes using write-combining may be corrupted. We want to know whether it is enabled before mapping the NIC registers, and even if PCI extended capabilities are not accessible. Therefore, we look for the MSI capability, which is removed if SR-IOV is enabled. Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 18 ++++++++++++++++-- drivers/net/sfc/workarounds.h | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index b8bd936374f2..d890679e4c4d 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1054,6 +1054,7 @@ static int efx_init_io(struct efx_nic *efx) { struct pci_dev *pci_dev = efx->pci_dev; dma_addr_t dma_mask = efx->type->max_dma_mask; + bool use_wc; int rc; netif_dbg(efx, probe, efx->net_dev, "initialising I/O\n"); @@ -1104,8 +1105,21 @@ static int efx_init_io(struct efx_nic *efx) rc = -EIO; goto fail3; } - efx->membase = ioremap_wc(efx->membase_phys, - efx->type->mem_map_size); + + /* bug22643: If SR-IOV is enabled then tx push over a write combined + * mapping is unsafe. We need to disable write combining in this case. + * MSI is unsupported when SR-IOV is enabled, and the firmware will + * have removed the MSI capability. So write combining is safe if + * there is an MSI capability. + */ + use_wc = (!EFX_WORKAROUND_22643(efx) || + pci_find_capability(pci_dev, PCI_CAP_ID_MSI)); + if (use_wc) + efx->membase = ioremap_wc(efx->membase_phys, + efx->type->mem_map_size); + else + efx->membase = ioremap_nocache(efx->membase_phys, + efx->type->mem_map_size); if (!efx->membase) { netif_err(efx, probe, efx->net_dev, "could not map memory BAR at %llx+%x\n", diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index e4dd3a7f304b..99ff11400cef 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -38,6 +38,8 @@ #define EFX_WORKAROUND_15783 EFX_WORKAROUND_ALWAYS /* Legacy interrupt storm when interrupt fifo fills */ #define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA +/* Write combining and sriov=enabled are incompatible */ +#define EFX_WORKAROUND_22643 EFX_WORKAROUND_SIENA /* Spurious parity errors in TSORT buffers */ #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A -- cgit v1.2.2 From 6a1fef6d000944911df0f160f366111daa10740a Mon Sep 17 00:00:00 2001 From: Sriram Date: Tue, 22 Mar 2011 02:31:03 +0000 Subject: net: davinci_emac:Fix translation logic for buffer descriptor With recent changes to the driver(switch to new cpdma layer), the support for buffer descriptor address translation logic is broken. This affects platforms where the physical address of the descriptors as seen by the DMA engine is different from the physical address. Original Patch adding translation logic support: Commit: ad021ae8862209864dc8ebd3b7d3a55ce84b9ea2 Signed-off-by: Sriramakrishnan A G Tested-By: Sekhar Nori Signed-off-by: David S. Miller --- drivers/net/davinci_cpdma.c | 11 ++++++++--- drivers/net/davinci_cpdma.h | 1 + drivers/net/davinci_emac.c | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/davinci_cpdma.c b/drivers/net/davinci_cpdma.c index e92b2b6cd8c4..ae47f23ba930 100644 --- a/drivers/net/davinci_cpdma.c +++ b/drivers/net/davinci_cpdma.c @@ -76,6 +76,7 @@ struct cpdma_desc { struct cpdma_desc_pool { u32 phys; + u32 hw_addr; void __iomem *iomap; /* ioremap map */ void *cpumap; /* dma_alloc map */ int desc_size, mem_size; @@ -137,7 +138,8 @@ struct cpdma_chan { * abstract out these details */ static struct cpdma_desc_pool * -cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align) +cpdma_desc_pool_create(struct device *dev, u32 phys, u32 hw_addr, + int size, int align) { int bitmap_size; struct cpdma_desc_pool *pool; @@ -161,10 +163,12 @@ cpdma_desc_pool_create(struct device *dev, u32 phys, int size, int align) if (phys) { pool->phys = phys; pool->iomap = ioremap(phys, size); + pool->hw_addr = hw_addr; } else { pool->cpumap = dma_alloc_coherent(dev, size, &pool->phys, GFP_KERNEL); pool->iomap = (void __force __iomem *)pool->cpumap; + pool->hw_addr = pool->phys; } if (pool->iomap) @@ -201,14 +205,14 @@ static inline dma_addr_t desc_phys(struct cpdma_desc_pool *pool, { if (!desc) return 0; - return pool->phys + (__force dma_addr_t)desc - + return pool->hw_addr + (__force dma_addr_t)desc - (__force dma_addr_t)pool->iomap; } static inline struct cpdma_desc __iomem * desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma) { - return dma ? pool->iomap + dma - pool->phys : NULL; + return dma ? pool->iomap + dma - pool->hw_addr : NULL; } static struct cpdma_desc __iomem * @@ -260,6 +264,7 @@ struct cpdma_ctlr *cpdma_ctlr_create(struct cpdma_params *params) ctlr->pool = cpdma_desc_pool_create(ctlr->dev, ctlr->params.desc_mem_phys, + ctlr->params.desc_hw_addr, ctlr->params.desc_mem_size, ctlr->params.desc_align); if (!ctlr->pool) { diff --git a/drivers/net/davinci_cpdma.h b/drivers/net/davinci_cpdma.h index 868e50ebde45..afa19a0c0d81 100644 --- a/drivers/net/davinci_cpdma.h +++ b/drivers/net/davinci_cpdma.h @@ -33,6 +33,7 @@ struct cpdma_params { bool has_soft_reset; int min_packet_size; u32 desc_mem_phys; + u32 desc_hw_addr; int desc_mem_size; int desc_align; diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 082d6ea69920..baca6bfcb089 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1854,10 +1854,13 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) dma_params.rxcp = priv->emac_base + 0x660; dma_params.num_chan = EMAC_MAX_TXRX_CHANNELS; dma_params.min_packet_size = EMAC_DEF_MIN_ETHPKTSIZE; - dma_params.desc_mem_phys = hw_ram_addr; + dma_params.desc_hw_addr = hw_ram_addr; dma_params.desc_mem_size = pdata->ctrl_ram_size; dma_params.desc_align = 16; + dma_params.desc_mem_phys = pdata->no_bd_ram ? 0 : + (u32 __force)res->start + pdata->ctrl_ram_offset; + priv->dma = cpdma_ctlr_create(&dma_params); if (!priv->dma) { dev_err(emac_dev, "DaVinci EMAC: Error initializing DMA\n"); -- cgit v1.2.2 From 912b7427fc13467bac042cc72f2eccbdbc39d773 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Wed, 23 Mar 2011 10:21:40 +0800 Subject: ACPI button: remove unused procfs I/F Remove unused ACPI button procfs interface. Only /proc/acpi/button/lid/LID/state remains. Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/button.c | 163 +++++++++++++++++++------------------------------- 1 file changed, 60 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 12c28f4adb67..d27d072472f9 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -78,8 +78,6 @@ static int acpi_button_add(struct acpi_device *device); static int acpi_button_remove(struct acpi_device *device, int type); static int acpi_button_resume(struct acpi_device *device); static void acpi_button_notify(struct acpi_device *device, u32 event); -static int acpi_button_info_open_fs(struct inode *inode, struct file *file); -static int acpi_button_state_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_button_driver = { .name = "button", @@ -101,22 +99,6 @@ struct acpi_button { bool wakeup_enabled; }; -static const struct file_operations acpi_button_info_fops = { - .owner = THIS_MODULE, - .open = acpi_button_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations acpi_button_state_fops = { - .owner = THIS_MODULE, - .open = acpi_button_state_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); static struct acpi_device *lid_device; @@ -125,20 +107,7 @@ static struct acpi_device *lid_device; -------------------------------------------------------------------------- */ static struct proc_dir_entry *acpi_button_dir; - -static int acpi_button_info_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_device *device = seq->private; - - seq_printf(seq, "type: %s\n", - acpi_device_name(device)); - return 0; -} - -static int acpi_button_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, acpi_button_info_seq_show, PDE(inode)->data); -} +static struct proc_dir_entry *acpi_lid_dir; static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) { @@ -158,77 +127,85 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_button_state_seq_show, PDE(inode)->data); } -static struct proc_dir_entry *acpi_power_dir; -static struct proc_dir_entry *acpi_sleep_dir; -static struct proc_dir_entry *acpi_lid_dir; +static const struct file_operations acpi_button_state_fops = { + .owner = THIS_MODULE, + .open = acpi_button_state_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; static int acpi_button_add_fs(struct acpi_device *device) { struct acpi_button *button = acpi_driver_data(device); struct proc_dir_entry *entry = NULL; + int ret = 0; - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - if (!acpi_power_dir) - acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, - acpi_button_dir); - entry = acpi_power_dir; - break; - case ACPI_BUTTON_TYPE_SLEEP: - if (!acpi_sleep_dir) - acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, - acpi_button_dir); - entry = acpi_sleep_dir; - break; - case ACPI_BUTTON_TYPE_LID: - if (!acpi_lid_dir) - acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, - acpi_button_dir); - entry = acpi_lid_dir; - break; + /* procfs I/F for ACPI lid device only */ + if (button->type != ACPI_BUTTON_TYPE_LID) + return 0; + + if (acpi_button_dir || acpi_lid_dir) { + printk(KERN_ERR PREFIX "More than one Lid device found!\n"); + return -EEXIST; } - if (!entry) + /* create /proc/acpi/button */ + acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); + if (!acpi_button_dir) return -ENODEV; - acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry); - if (!acpi_device_dir(device)) - return -ENODEV; + /* create /proc/acpi/button/lid */ + acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); + if (!acpi_lid_dir) { + ret = -ENODEV; + goto remove_button_dir; + } - /* 'info' [R] */ - entry = proc_create_data(ACPI_BUTTON_FILE_INFO, - S_IRUGO, acpi_device_dir(device), - &acpi_button_info_fops, device); - if (!entry) - return -ENODEV; + /* create /proc/acpi/button/lid/LID/ */ + acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir); + if (!acpi_device_dir(device)) { + ret = -ENODEV; + goto remove_lid_dir; + } - /* show lid state [R] */ - if (button->type == ACPI_BUTTON_TYPE_LID) { - entry = proc_create_data(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device), - &acpi_button_state_fops, device); - if (!entry) - return -ENODEV; + /* create /proc/acpi/button/lid/LID/state */ + entry = proc_create_data(ACPI_BUTTON_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_button_state_fops, device); + if (!entry) { + ret = -ENODEV; + goto remove_dev_dir; } - return 0; +done: + return ret; + +remove_dev_dir: + remove_proc_entry(acpi_device_bid(device), + acpi_lid_dir); + acpi_device_dir(device) = NULL; +remove_lid_dir: + remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); +remove_button_dir: + remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); + goto done; } static int acpi_button_remove_fs(struct acpi_device *device) { struct acpi_button *button = acpi_driver_data(device); - if (acpi_device_dir(device)) { - if (button->type == ACPI_BUTTON_TYPE_LID) - remove_proc_entry(ACPI_BUTTON_FILE_STATE, - acpi_device_dir(device)); - remove_proc_entry(ACPI_BUTTON_FILE_INFO, - acpi_device_dir(device)); + if (button->type != ACPI_BUTTON_TYPE_LID) + return 0; - remove_proc_entry(acpi_device_bid(device), - acpi_device_dir(device)->parent); - acpi_device_dir(device) = NULL; - } + remove_proc_entry(ACPI_BUTTON_FILE_STATE, + acpi_device_dir(device)); + remove_proc_entry(acpi_device_bid(device), + acpi_lid_dir); + acpi_device_dir(device) = NULL; + remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); + remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); return 0; } @@ -468,32 +445,12 @@ static int acpi_button_remove(struct acpi_device *device, int type) static int __init acpi_button_init(void) { - int result; - - acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); - if (!acpi_button_dir) - return -ENODEV; - - result = acpi_bus_register_driver(&acpi_button_driver); - if (result < 0) { - remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); - return -ENODEV; - } - - return 0; + return acpi_bus_register_driver(&acpi_button_driver); } static void __exit acpi_button_exit(void) { acpi_bus_unregister_driver(&acpi_button_driver); - - if (acpi_power_dir) - remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir); - if (acpi_sleep_dir) - remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir); - if (acpi_lid_dir) - remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); - remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); } module_init(acpi_button_init); -- cgit v1.2.2 From 25be5821521640eb00b7eb219ffe59664510d073 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 22 Mar 2011 16:19:50 -0400 Subject: ACPI battery: fribble sysfs files from a resume notifier Commit da8aeb92 re-poked the battery on resume, but Linus reports that it broke his eee and partially reverted it in b23fffd7. Unfortunately this also results in my x201s giving crack values until the sysfs files are poked again. In the revert message, it was suggested that we poke it from a PM notifier, so let's do that. With this in place, I haven't noticed the units going nutty on my gnome-power-manager across a dozen suspends or so... Signed-off-by: Kyle McMartin Acked-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/battery.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index ac1a599f5147..fcc13ac0aa18 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI_PROCFS_POWER #include @@ -102,6 +103,7 @@ struct acpi_battery { struct mutex lock; struct power_supply bat; struct acpi_device *device; + struct notifier_block pm_nb; unsigned long update_time; int rate_now; int capacity_now; @@ -940,6 +942,21 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) power_supply_changed(&battery->bat); } +static int battery_notify(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + struct acpi_battery *battery = container_of(nb, struct acpi_battery, + pm_nb); + switch (mode) { + case PM_POST_SUSPEND: + sysfs_remove_battery(battery); + sysfs_add_battery(battery); + break; + } + + return 0; +} + static int acpi_battery_add(struct acpi_device *device) { int result = 0; @@ -972,6 +989,10 @@ static int acpi_battery_add(struct acpi_device *device) #endif kfree(battery); } + + battery->pm_nb.notifier_call = battery_notify; + register_pm_notifier(&battery->pm_nb); + return result; } @@ -982,6 +1003,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type) if (!device || !acpi_driver_data(device)) return -EINVAL; battery = acpi_driver_data(device); + unregister_pm_notifier(&battery->pm_nb); #ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device); #endif -- cgit v1.2.2 From f17d9cbf20c4734c4199caa6dee87047f2f8278f Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 11 Mar 2011 16:12:18 -0500 Subject: ACPICA: Fix access width for reset vector Section 4.7.3.6 of the ACPI specification requires that the register width of the reset vector be 8 bits. Windows simply hardcodes the access to be a byte and ignores the width provided in the FADT, so make sure that we do the same. Signed-off-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/acpi/acpica/hwxface.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 6f98d210e71c..f75f81ad15c9 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -80,14 +80,14 @@ acpi_status acpi_reset(void) if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { /* - * For I/O space, write directly to the OSL. This bypasses the port - * validation mechanism, which may block a valid write to the reset - * register. + * For I/O space, write directly to the OSL. This + * bypasses the port validation mechanism, which may + * block a valid write to the reset register. Spec + * section 4.7.3.6 requires register width to be 8. */ status = acpi_os_write_port((acpi_io_address) reset_reg->address, - acpi_gbl_FADT.reset_value, - reset_reg->bit_width); + acpi_gbl_FADT.reset_value, 8); } else { /* Write the reset value to the reset register */ -- cgit v1.2.2 From 6734fe57a07b2dd23ef1ef2ac1f790747e53eefc Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 11 Mar 2011 16:12:19 -0500 Subject: ACPI: Bug compatibility for Windows on the ACPI reboot vector Windows ignores the bit_offset and bit_width, despite the spec requiring that they be validated. Drop the checks so that we match this behaviour. Windows also goes straight for the keyboard controller if the ACPI reboot fails, so we shouldn't sleep if we're still alive. Signed-off-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/acpi/reboot.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index 93f91142d7ad..4870aaaa2ae1 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -15,9 +15,10 @@ void acpi_reboot(void) rr = &acpi_gbl_FADT.reset_register; - /* Is the reset register supported? */ - if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || - rr->bit_width != 8 || rr->bit_offset != 0) + /* Is the reset register supported? The spec says we should be + * checking the bit width and bit offset, but Windows ignores + * these fields */ + if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)) return; reset_value = acpi_gbl_FADT.reset_value; @@ -45,6 +46,4 @@ void acpi_reboot(void) acpi_reset(); break; } - /* Wait ten seconds */ - acpi_os_stall(10000000); } -- cgit v1.2.2 From 95cf3e12e7f659e536215b37c67d46f3e2ce95cc Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 11 Mar 2011 16:12:20 -0500 Subject: ACPI: Make sure the FADT is at least rev 2 before using the reset register The reset register was only introduced with version 2 of the FADT, so we should check that the FADT revision before trusting its contents. Signed-off-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/acpi/reboot.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index 4870aaaa2ae1..a6c77e8b37bd 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -15,6 +15,11 @@ void acpi_reboot(void) rr = &acpi_gbl_FADT.reset_register; + /* ACPI reset register was only introduced with v2 of the FADT */ + + if (acpi_gbl_FADT.header.revision < 2) + return; + /* Is the reset register supported? The spec says we should be * checking the bit width and bit offset, but Windows ignores * these fields */ -- cgit v1.2.2 From 64146f8b2af1ba77fe3c21d9d6d7213b9bb72b40 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 22 Mar 2011 01:46:12 -0400 Subject: drm/radeon/kms: prefer legacy pll algo for tv-out ntsc seems to work fine with either algo, some pal TVs seem pickier. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=30832 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 3cd3234ba0af..10e41af6b026 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -957,7 +957,11 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode /* adjust pixel clock as needed */ adjusted_clock = atombios_adjust_pll(crtc, mode, pll, ss_enabled, &ss); - if (ASIC_IS_AVIVO(rdev)) + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + /* TV seems to prefer the legacy algo on some boards */ + radeon_compute_pll_legacy(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, + &ref_div, &post_div); + else if (ASIC_IS_AVIVO(rdev)) radeon_compute_pll_avivo(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, &ref_div, &post_div); else -- cgit v1.2.2 From 32297abd90a5d181e8e026c8b8e65ef41e9ffc07 Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Wed, 2 Feb 2011 23:26:58 +0000 Subject: ACPI: make acpi_pad /sys output more readable Make /sys output from acpi_pad more readable. Before the fix: # cat idlecpus idlepct rrtime 00000000510 After the fix: # cat idlecpus idlepct rrtime 00000000 5 10 Signed-off-by: Naga Chumbalkar Signed-off-by: Len Brown --- drivers/acpi/acpi_pad.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 6afceb3d4034..474be3a198ed 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -298,7 +298,7 @@ static ssize_t acpi_pad_rrtime_store(struct device *dev, static ssize_t acpi_pad_rrtime_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d", round_robin_time); + return scnprintf(buf, PAGE_SIZE, "%d\n", round_robin_time); } static DEVICE_ATTR(rrtime, S_IRUGO|S_IWUSR, acpi_pad_rrtime_show, @@ -321,7 +321,7 @@ static ssize_t acpi_pad_idlepct_store(struct device *dev, static ssize_t acpi_pad_idlepct_show(struct device *dev, struct device_attribute *attr, char *buf) { - return scnprintf(buf, PAGE_SIZE, "%d", idle_pct); + return scnprintf(buf, PAGE_SIZE, "%d\n", idle_pct); } static DEVICE_ATTR(idlepct, S_IRUGO|S_IWUSR, acpi_pad_idlepct_show, @@ -342,8 +342,11 @@ static ssize_t acpi_pad_idlecpus_store(struct device *dev, static ssize_t acpi_pad_idlecpus_show(struct device *dev, struct device_attribute *attr, char *buf) { - return cpumask_scnprintf(buf, PAGE_SIZE, - to_cpumask(pad_busy_cpus_bits)); + int n = 0; + n = cpumask_scnprintf(buf, PAGE_SIZE-2, to_cpumask(pad_busy_cpus_bits)); + buf[n++] = '\n'; + buf[n] = '\0'; + return n; } static DEVICE_ATTR(idlecpus, S_IRUGO|S_IWUSR, acpi_pad_idlecpus_show, -- cgit v1.2.2 From cdf2a4eeded69f66ec8c5098c375fe49e0820127 Mon Sep 17 00:00:00 2001 From: Naga Chumbalkar Date: Wed, 2 Feb 2011 23:27:04 +0000 Subject: ACPI: minor printk format change in acpi_pad Minor format change. Signed-off-by: Naga Chumbalkar Signed-off-by: Len Brown --- drivers/acpi/acpi_pad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 474be3a198ed..a43fa1a57d57 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -456,7 +456,7 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, dev_name(&device->dev), event, 0); break; default: - printk(KERN_WARNING"Unsupported event [0x%x]\n", event); + printk(KERN_WARNING "Unsupported event [0x%x]\n", event); break; } } -- cgit v1.2.2 From 762237bb714b0cd93ce2405ccc891fadb405c26e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 17 Mar 2011 07:20:20 +0000 Subject: drm/i915: Remove surplus POSTING_READs before wait_for_vblank ... as wait_for_vblank (and friends) will do a flush of the MMIO writes anyway. References: https://bugs.freedesktop.org/show_bug.cgi?id=34601 Cc: Jesse Barnes Signed-off-by: Chris Wilson Reviewed-by: Keith Packard Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_display.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3106c0dc8389..3bc6ab56cf8b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1518,7 +1518,6 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, val = I915_READ(reg); val |= PIPECONF_ENABLE; I915_WRITE(reg, val); - POSTING_READ(reg); intel_wait_for_vblank(dev_priv->dev, pipe); } @@ -1554,7 +1553,6 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, val = I915_READ(reg); val &= ~PIPECONF_ENABLE; I915_WRITE(reg, val); - POSTING_READ(reg); intel_wait_for_pipe_off(dev_priv->dev, pipe); } @@ -1579,7 +1577,6 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, val = I915_READ(reg); val |= DISPLAY_PLANE_ENABLE; I915_WRITE(reg, val); - POSTING_READ(reg); intel_wait_for_vblank(dev_priv->dev, pipe); } @@ -1612,7 +1609,6 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, val = I915_READ(reg); val &= ~DISPLAY_PLANE_ENABLE; I915_WRITE(reg, val); - POSTING_READ(reg); intel_flush_display_plane(dev_priv, plane); intel_wait_for_vblank(dev_priv->dev, pipe); } @@ -1769,7 +1765,6 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) return; I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); - POSTING_READ(DPFC_CONTROL); intel_wait_for_vblank(dev, intel_crtc->pipe); } @@ -1861,7 +1856,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) return; I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN); - POSTING_READ(ILK_DPFC_CONTROL); intel_wait_for_vblank(dev, intel_crtc->pipe); } @@ -5777,7 +5771,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc) dpll &= ~DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); - POSTING_READ(dpll_reg); intel_wait_for_vblank(dev, pipe); dpll = I915_READ(dpll_reg); @@ -5821,7 +5814,6 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc) dpll |= DISPLAY_RATE_SELECT_FPA1; I915_WRITE(dpll_reg, dpll); - dpll = I915_READ(dpll_reg); intel_wait_for_vblank(dev, pipe); dpll = I915_READ(dpll_reg); if (!(dpll & DISPLAY_RATE_SELECT_FPA1)) -- cgit v1.2.2 From 00d70b15125030391d17baab2c2f70f93b3339a6 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 17 Mar 2011 07:18:29 +0000 Subject: drm/i915: skip redundant operations whilst enabling pipes and planes If the pipe or plane is already enabled, then we do not need to enable it again and can skip the delay. Similarly if it is already disabled when we want to disable it, we can also skip it. This fixes a regression from b24e717988, which caused the LVDS output on one PineView machine to become corrupt after changing orientation several times. References: https://bugs.freedesktop.org/show_bug.cgi?id=34601 Cc: Jesse Barnes Signed-off-by: Chris Wilson Reviewed-by: Keith Packard Tested-by: mengmeng.meng@intel.com --- drivers/gpu/drm/i915/intel_display.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3bc6ab56cf8b..841f0397288b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1516,8 +1516,10 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, reg = PIPECONF(pipe); val = I915_READ(reg); - val |= PIPECONF_ENABLE; - I915_WRITE(reg, val); + if (val & PIPECONF_ENABLE) + return; + + I915_WRITE(reg, val | PIPECONF_ENABLE); intel_wait_for_vblank(dev_priv->dev, pipe); } @@ -1551,8 +1553,10 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, reg = PIPECONF(pipe); val = I915_READ(reg); - val &= ~PIPECONF_ENABLE; - I915_WRITE(reg, val); + if ((val & PIPECONF_ENABLE) == 0) + return; + + I915_WRITE(reg, val & ~PIPECONF_ENABLE); intel_wait_for_pipe_off(dev_priv->dev, pipe); } @@ -1575,8 +1579,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, reg = DSPCNTR(plane); val = I915_READ(reg); - val |= DISPLAY_PLANE_ENABLE; - I915_WRITE(reg, val); + if (val & DISPLAY_PLANE_ENABLE) + return; + + I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); intel_wait_for_vblank(dev_priv->dev, pipe); } @@ -1607,8 +1613,10 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, reg = DSPCNTR(plane); val = I915_READ(reg); - val &= ~DISPLAY_PLANE_ENABLE; - I915_WRITE(reg, val); + if ((val & DISPLAY_PLANE_ENABLE) == 0) + return; + + I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE); intel_flush_display_plane(dev_priv, plane); intel_wait_for_vblank(dev_priv->dev, pipe); } -- cgit v1.2.2 From 09bfa51773c1e90f13000dc2fc0c4b84047009bc Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Thu, 17 Mar 2011 13:45:12 +0000 Subject: drm/i915: Prevent racy removal of request from client list When i915_gem_retire_requests_ring calls i915_gem_request_remove_from_client, the client_list for that request may already be removed in i915_gem_release. So we may call twice list_del(&request->client_list), resulting in an oops like this report: [126167.230394] BUG: unable to handle kernel paging request at 00100104 [126167.230699] IP: [] i915_gem_retire_requests_ring+0xd4/0x240 [i915] [126167.231042] *pdpt = 00000000314c1001 *pde = 0000000000000000 [126167.231314] Oops: 0002 [#1] SMP [126167.231471] last sysfs file: /sys/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1/current_now [126167.231901] Modules linked in: snd_seq_dummy nls_utf8 isofs btrfs zlib_deflate libcrc32c ufs qnx4 hfsplus hfs minix ntfs vfat msdos fat jfs xfs exportfs reiserfs cryptd aes_i586 aes_generic binfmt_misc vboxnetadp vboxnetflt vboxdrv parport_pc ppdev snd_hda_codec_hdmi snd_hda_codec_conexant snd_hda_intel snd_hda_codec snd_hwdep arc4 snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq uvcvideo videodev snd_timer snd_seq_device joydev iwlagn iwlcore mac80211 snd cfg80211 soundcore i915 drm_kms_helper snd_page_alloc psmouse drm serio_raw i2c_algo_bit video lp parport usbhid hid sky2 sdhci_pci ahci sdhci libahci [126167.232018] [126167.232018] Pid: 1101, comm: Xorg Not tainted 2.6.38-6-generic-pae #34-Ubuntu Gateway MC7833U / [126167.232018] EIP: 0060:[] EFLAGS: 00213246 CPU: 0 [126167.232018] EIP is at i915_gem_retire_requests_ring+0xd4/0x240 [i915] [126167.232018] EAX: 00200200 EBX: f1ac25b0 ECX: 00000040 EDX: 00100100 [126167.232018] ESI: f1a2801c EDI: e87fc060 EBP: ef4d7dd8 ESP: ef4d7db0 [126167.232018] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 [126167.232018] Process Xorg (pid: 1101, ti=ef4d6000 task=f1ba6500 task.ti=ef4d6000) [126167.232018] Stack: [126167.232018] f1a28000 f1a2809c f1a28094 0058bd97 f1aa2400 f1a2801c 0058bd7b 0058bd85 [126167.232018] f1a2801c f1a28000 ef4d7e38 f8c2e995 ef4d7e30 ef4d7e60 c14d1ebc f6b3a040 [126167.232018] f1522cc0 000000db 00000000 f1ba6500 ffffffa1 00000000 00000001 f1a29214 [126167.232018] Call Trace: Unfortunately the call trace reported was cut, but looking at debug symbols the crash is at __list_del, when probably list_del is called twice on the same request->client_list, as the dereferenced value is LIST_POISON1 + 4, and by looking more at the debug symbols before list_del call it should have being called by i915_gem_request_remove_from_client And as I can see in the code, it seems we indeed have the possibility to remove a request->client_list twice, which would cause the above, because we do list_del(&request->client_list) on both i915_gem_request_remove_from_client and i915_gem_release As Chris Wilson pointed out, it's indeed the case: "(...) I had thought that the actual insertion/deletion was serialised under the struct mutex and the intention of the spinlock was to protect the unlocked list traversal during throttling. However, I missed that i915_gem_release() is also called without struct mutex and so we do need the double check for i915_gem_request_remove_from_client()." This change does the required check to avoid the duplicate remove of request->client_list. Bugzilla: http://bugs.launchpad.net/bugs/733780 Cc: stable@kernel.org # 2.6.38 Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c4c2855d002d..d4bf061dbaf1 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1796,8 +1796,10 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) return; spin_lock(&file_priv->mm.lock); - list_del(&request->client_list); - request->file_priv = NULL; + if (request->file_priv) { + list_del(&request->client_list); + request->file_priv = NULL; + } spin_unlock(&file_priv->mm.lock); } -- cgit v1.2.2 From 7ccb4a53eb03c9196646ca0c2a97558313e886f1 Mon Sep 17 00:00:00 2001 From: Yuanhan Liu Date: Fri, 18 Mar 2011 07:37:35 +0000 Subject: drm/i915: Re-enable self-refresh A broken implementation of is_pot() prevented the detection of when a singular pipe was enabled. Eric Anholt pointed out the existence of is_power_of_2() so use that instead of our broken code! Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35402 Signed-off-by: Yuanhan Liu Tested-by: xunx.fang@intel.com Reviewed-by: Keith Packard Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 841f0397288b..49c07231302c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3885,10 +3885,7 @@ static bool g4x_compute_srwm(struct drm_device *dev, display, cursor); } -static inline bool single_plane_enabled(unsigned int mask) -{ - return mask && (mask & -mask) == 0; -} +#define single_plane_enabled(mask) is_power_of_2(mask) static void g4x_update_wm(struct drm_device *dev) { -- cgit v1.2.2 From 29c5a587284195278e233eec5c2234c24fb2c204 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 17 Mar 2011 15:23:22 +0000 Subject: drm/i915: Fix tiling corruption from pipelined fencing ... even though it was disabled. A mistake in the handling of fence reuse caused us to skip the vital delay of waiting for the object to finish rendering before changing the register. This resulted in us changing the fence register whilst the bo was active and so causing the blits to complete using the wrong stride or even the wrong tiling. (Visually the effect is that small blocks of the screen look like they have been interlaced). The fix is to wait for the GPU to finish using the memory region pointed to by the fence before changing it. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=34584 Cc: Andy Whitcroft Cc: Daniel Vetter Reviewed-by: Daniel Vetter [Note for 2.6.38-stable, we need to reintroduce the interruptible passing] Signed-off-by: Chris Wilson Tested-by: Dave Airlie --- drivers/gpu/drm/i915/i915_gem.c | 44 ++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d4bf061dbaf1..c5dfb59e13d3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2581,8 +2581,23 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, reg = &dev_priv->fence_regs[obj->fence_reg]; list_move_tail(®->lru_list, &dev_priv->mm.fence_list); - if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) - pipelined = NULL; + if (obj->tiling_changed) { + ret = i915_gem_object_flush_fence(obj, pipelined); + if (ret) + return ret; + + if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) + pipelined = NULL; + + if (pipelined) { + reg->setup_seqno = + i915_gem_next_request_seqno(pipelined); + obj->last_fenced_seqno = reg->setup_seqno; + obj->last_fenced_ring = pipelined; + } + + goto update; + } if (!pipelined) { if (reg->setup_seqno) { @@ -2601,31 +2616,6 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj, ret = i915_gem_object_flush_fence(obj, pipelined); if (ret) return ret; - } else if (obj->tiling_changed) { - if (obj->fenced_gpu_access) { - if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) { - ret = i915_gem_flush_ring(obj->ring, - 0, obj->base.write_domain); - if (ret) - return ret; - } - - obj->fenced_gpu_access = false; - } - } - - if (!obj->fenced_gpu_access && !obj->last_fenced_seqno) - pipelined = NULL; - BUG_ON(!pipelined && reg->setup_seqno); - - if (obj->tiling_changed) { - if (pipelined) { - reg->setup_seqno = - i915_gem_next_request_seqno(pipelined); - obj->last_fenced_seqno = reg->setup_seqno; - obj->last_fenced_ring = pipelined; - } - goto update; } return 0; -- cgit v1.2.2 From 9a26513eb67ec4b2cb1744834076afad21b68aac Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 23 Mar 2011 10:16:01 +0100 Subject: [S390] qdio: prevent handling of buffers if count is zero Exit do_QDIO early if the buffer count is zero to prevent side effects in the following functions. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 5640c89cd9de..479c665e9e7c 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1508,7 +1508,8 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) return -EBUSY; - + if (!count) + return 0; if (callflags & QDIO_FLAG_SYNC_INPUT) return handle_inbound(irq_ptr->input_qs[q_nr], callflags, bufnr, count); -- cgit v1.2.2 From 3bda058b0c39fc72188116d2fd71af08dd0fe5b0 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 23 Mar 2011 10:16:02 +0100 Subject: [S390] ccw_driver: remove duplicate members Remove the owner and name members of struct ccw_driver and convert all drivers to store this data in the embedded struct device_driver. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 6 ++++-- drivers/s390/block/dasd_fba.c | 6 ++++-- drivers/s390/char/con3215.c | 6 ++++-- drivers/s390/char/raw3270.c | 6 ++++-- drivers/s390/char/tape_34xx.c | 6 ++++-- drivers/s390/char/tape_3590.c | 6 ++++-- drivers/s390/char/vmur.c | 6 ++++-- drivers/s390/cio/device.c | 6 ++---- drivers/s390/net/claw.c | 6 ++++-- drivers/s390/net/ctcm_main.c | 6 ++++-- drivers/s390/net/lcs.c | 6 ++++-- drivers/s390/net/qeth_core_main.c | 4 +++- drivers/s390/scsi/zfcp_ccw.c | 6 ++++-- 13 files changed, 49 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 379d8592bc6e..459f2cbe80fc 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -3982,8 +3982,10 @@ out_err: } static struct ccw_driver dasd_eckd_driver = { - .name = "dasd-eckd", - .owner = THIS_MODULE, + .driver = { + .name = "dasd-eckd", + .owner = THIS_MODULE, + }, .ids = dasd_eckd_ids, .probe = dasd_eckd_probe, .remove = dasd_generic_remove, diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index be89b3a893da..4b71b1164868 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -65,8 +65,10 @@ dasd_fba_set_online(struct ccw_device *cdev) } static struct ccw_driver dasd_fba_driver = { - .name = "dasd-fba", - .owner = THIS_MODULE, + .driver = { + .name = "dasd-fba", + .owner = THIS_MODULE, + }, .ids = dasd_fba_ids, .probe = dasd_fba_probe, .remove = dasd_generic_remove, diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 3fb4335d491d..694464c65fcd 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -764,8 +764,10 @@ static struct ccw_device_id raw3215_id[] = { }; static struct ccw_driver raw3215_ccw_driver = { - .name = "3215", - .owner = THIS_MODULE, + .driver = { + .name = "3215", + .owner = THIS_MODULE, + }, .ids = raw3215_id, .probe = &raw3215_probe, .remove = &raw3215_remove, diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 96ba2fd1c8ad..4c023761946f 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -1388,8 +1388,10 @@ static struct ccw_device_id raw3270_id[] = { }; static struct ccw_driver raw3270_ccw_driver = { - .name = "3270", - .owner = THIS_MODULE, + .driver = { + .name = "3270", + .owner = THIS_MODULE, + }, .ids = raw3270_id, .probe = &raw3270_probe, .remove = &raw3270_remove, diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index c26511171ffe..9eff2df70ddb 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c @@ -1320,8 +1320,10 @@ tape_34xx_online(struct ccw_device *cdev) } static struct ccw_driver tape_34xx_driver = { - .name = "tape_34xx", - .owner = THIS_MODULE, + .driver = { + .name = "tape_34xx", + .owner = THIS_MODULE, + }, .ids = tape_34xx_ids, .probe = tape_generic_probe, .remove = tape_generic_remove, diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index de2e99e0a71b..b98dcbd16711 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -1761,8 +1761,10 @@ tape_3590_online(struct ccw_device *cdev) } static struct ccw_driver tape_3590_driver = { - .name = "tape_3590", - .owner = THIS_MODULE, + .driver = { + .name = "tape_3590", + .owner = THIS_MODULE, + }, .ids = tape_3590_ids, .probe = tape_generic_probe, .remove = tape_generic_remove, diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index caef1757341d..f6b00c3df425 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -64,8 +64,10 @@ static int ur_set_offline(struct ccw_device *cdev); static int ur_pm_suspend(struct ccw_device *cdev); static struct ccw_driver ur_driver = { - .name = "vmur", - .owner = THIS_MODULE, + .driver = { + .name = "vmur", + .owner = THIS_MODULE, + }, .ids = ur_ids, .probe = ur_probe, .remove = ur_remove, diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e50b12163afe..334459eb23c8 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -547,7 +547,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) return -EAGAIN; - if (cdev->drv && !try_module_get(cdev->drv->owner)) { + if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) { atomic_set(&cdev->private->onoff, 0); return -EINVAL; } @@ -573,7 +573,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, } out: if (cdev->drv) - module_put(cdev->drv->owner); + module_put(cdev->drv->driver.owner); atomic_set(&cdev->private->onoff, 0); return (ret < 0) ? ret : count; } @@ -1993,8 +1993,6 @@ int ccw_driver_register(struct ccw_driver *cdriver) struct device_driver *drv = &cdriver->driver; drv->bus = &ccw_bus_type; - drv->name = cdriver->name; - drv->owner = cdriver->owner; return driver_register(drv); } diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index ce3a5c13ce0b..2e2d2dfe78db 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -282,8 +282,10 @@ static struct ccw_device_id claw_ids[] = { MODULE_DEVICE_TABLE(ccw, claw_ids); static struct ccw_driver claw_ccw_driver = { - .owner = THIS_MODULE, - .name = "claw", + .driver = { + .owner = THIS_MODULE, + .name = "claw", + }, .ids = claw_ids, .probe = ccwgroup_probe_ccwdev, .remove = ccwgroup_remove_ccwdev, diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 4c2845985927..97fd4800ab12 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1764,8 +1764,10 @@ static struct ccw_device_id ctcm_ids[] = { MODULE_DEVICE_TABLE(ccw, ctcm_ids); static struct ccw_driver ctcm_ccw_driver = { - .owner = THIS_MODULE, - .name = "ctcm", + .driver = { + .owner = THIS_MODULE, + .name = "ctcm", + }, .ids = ctcm_ids, .probe = ccwgroup_probe_ccwdev, .remove = ccwgroup_remove_ccwdev, diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 30b2a820e670..f59429c3bc30 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -2396,8 +2396,10 @@ static struct ccw_device_id lcs_ids[] = { MODULE_DEVICE_TABLE(ccw, lcs_ids); static struct ccw_driver lcs_ccw_driver = { - .owner = THIS_MODULE, - .name = "lcs", + .driver = { + .owner = THIS_MODULE, + .name = "lcs", + }, .ids = lcs_ids, .probe = ccwgroup_probe_ccwdev, .remove = ccwgroup_remove_ccwdev, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 25eef304bd47..150b2cd99ba8 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3902,7 +3902,9 @@ static struct ccw_device_id qeth_ids[] = { MODULE_DEVICE_TABLE(ccw, qeth_ids); static struct ccw_driver qeth_ccw_driver = { - .name = "qeth", + .driver = { + .name = "qeth", + }, .ids = qeth_ids, .probe = ccwgroup_probe_ccwdev, .remove = ccwgroup_remove_ccwdev, diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index 4f7852dd30c7..e8b7cee62046 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -251,8 +251,10 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev) } struct ccw_driver zfcp_ccw_driver = { - .owner = THIS_MODULE, - .name = "zfcp", + .driver = { + .owner = THIS_MODULE, + .name = "zfcp", + }, .ids = zfcp_ccw_device_id, .probe = zfcp_ccw_probe, .remove = zfcp_ccw_remove, -- cgit v1.2.2 From d5ab5276baf9fd8b581cfbf41b10b6d4eae55960 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 23 Mar 2011 10:16:03 +0100 Subject: [S390] ccw_bus_type: make it static Make ccw_bus_type static. ccw_device drivers have to use ccw_driver_register. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 5 ++--- drivers/s390/cio/device.h | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 334459eb23c8..df14c51f6532 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -127,7 +127,7 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } -struct bus_type ccw_bus_type; +static struct bus_type ccw_bus_type; static void io_subchannel_irq(struct subchannel *); static int io_subchannel_probe(struct subchannel *); @@ -1970,7 +1970,7 @@ static const struct dev_pm_ops ccw_pm_ops = { .restore = ccw_device_pm_restore, }; -struct bus_type ccw_bus_type = { +static struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, .uevent = ccw_uevent, @@ -2110,5 +2110,4 @@ EXPORT_SYMBOL(ccw_device_set_offline); EXPORT_SYMBOL(ccw_driver_register); EXPORT_SYMBOL(ccw_driver_unregister); EXPORT_SYMBOL(get_ccwdev_by_busid); -EXPORT_SYMBOL(ccw_bus_type); EXPORT_SYMBOL_GPL(ccw_device_get_subchannel_id); diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 379de2d1ec49..7e297c7bb5ff 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -133,7 +133,6 @@ void ccw_device_set_notoper(struct ccw_device *cdev); /* qdio needs this. */ void ccw_device_set_timeout(struct ccw_device *, int); extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); -extern struct bus_type ccw_bus_type; /* Channel measurement facility related */ void retry_set_schib(struct ccw_device *cdev); -- cgit v1.2.2 From 3c190c51f55eab691e5d096747262d2653e67de1 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Wed, 23 Mar 2011 10:16:04 +0100 Subject: [S390] ccwgroup_driver: remove duplicate members Remove the owner and name members of struct ccwgroup_driver and convert all drivers to store this data in the embedded struct device_driver. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/ccwgroup.c | 6 ++---- drivers/s390/net/claw.c | 6 ++++-- drivers/s390/net/ctcm_main.c | 6 ++++-- drivers/s390/net/lcs.c | 6 ++++-- drivers/s390/net/qeth_core_main.c | 6 ++++-- 5 files changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 2864581d8ecb..5c567414c4bb 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -428,7 +428,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); - if (!try_module_get(gdrv->owner)) + if (!try_module_get(gdrv->driver.owner)) return -EINVAL; ret = strict_strtoul(buf, 0, &value); @@ -442,7 +442,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const else ret = -EINVAL; out: - module_put(gdrv->owner); + module_put(gdrv->driver.owner); return (ret == 0) ? count : ret; } @@ -616,8 +616,6 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) { /* register our new driver with the core */ cdriver->driver.bus = &ccwgroup_bus_type; - cdriver->driver.name = cdriver->name; - cdriver->driver.owner = cdriver->owner; return driver_register(&cdriver->driver); } diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 2e2d2dfe78db..9feb62febb3d 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -264,8 +264,10 @@ static struct device *claw_root_dev; /* ccwgroup table */ static struct ccwgroup_driver claw_group_driver = { - .owner = THIS_MODULE, - .name = "claw", + .driver = { + .owner = THIS_MODULE, + .name = "claw", + }, .max_slaves = 2, .driver_id = 0xC3D3C1E6, .probe = claw_probe, diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 97fd4800ab12..c189296763a4 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1774,8 +1774,10 @@ static struct ccw_driver ctcm_ccw_driver = { }; static struct ccwgroup_driver ctcm_group_driver = { - .owner = THIS_MODULE, - .name = CTC_DRIVER_NAME, + .driver = { + .owner = THIS_MODULE, + .name = CTC_DRIVER_NAME, + }, .max_slaves = 2, .driver_id = 0xC3E3C3D4, /* CTCM */ .probe = ctcm_probe_device, diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index f59429c3bc30..7fbc4adbb6d5 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -2409,8 +2409,10 @@ static struct ccw_driver lcs_ccw_driver = { * LCS ccwgroup driver registration */ static struct ccwgroup_driver lcs_group_driver = { - .owner = THIS_MODULE, - .name = "lcs", + .driver = { + .owner = THIS_MODULE, + .name = "lcs", + }, .max_slaves = 2, .driver_id = 0xD3C3E2, .probe = lcs_probe_device, diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 150b2cd99ba8..10a3a3b4dd3e 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4430,8 +4430,10 @@ static int qeth_core_restore(struct ccwgroup_device *gdev) } static struct ccwgroup_driver qeth_core_ccwgroup_driver = { - .owner = THIS_MODULE, - .name = "qeth", + .driver = { + .owner = THIS_MODULE, + .name = "qeth", + }, .driver_id = 0xD8C5E3C8, .probe = qeth_core_probe_device, .remove = qeth_core_remove_device, -- cgit v1.2.2 From 48898b038b69ef4801f0e059026c8f6920684677 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 18 Mar 2011 09:06:49 +0000 Subject: drm/i915/dp: Correct the order of deletion for ghost eDP devices The order of the calls does matter indeed. Swapping the call order of intel_dp_destroy() and intel_dp_encoder_destroy() fixes the problem. This is because i2c_del_adapter unregisters the device which parent is intel_connector, and connectors are removed in intel_dp_destroy(). Thus intel_dp_encoder_destroy() must be called before intel_dp_destroy(). Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=24822 Signed-off-by: Takashi Iwai Signed-off-by: Chris Wilson Reviewed-by: Keith Packard --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d29e33f815d7..0daefca5cbb8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1957,9 +1957,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) DP_NO_AUX_HANDSHAKE_LINK_TRAINING; } else { /* if this fails, presume the device is a ghost */ - DRM_ERROR("failed to retrieve link info\n"); - intel_dp_destroy(&intel_connector->base); + DRM_INFO("failed to retrieve link info, disabling eDP\n"); intel_dp_encoder_destroy(&intel_dp->base.base); + intel_dp_destroy(&intel_connector->base); return; } } -- cgit v1.2.2 From e281fcaa287fb39ce26d9aa33a716c2a7bb8484e Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Fri, 18 Mar 2011 10:32:07 -0700 Subject: drm/i915: report correct render clock frequencies on SNB Fix up the debug file to report the right frequencies. On SNB, we program the PCU with a frequency ratio, which is multiplied by 100MHz on the CPU side. But GFX only runs at half that, so report it as such to avoid confusion. Signed-off-by: Jesse Barnes Signed-off-by: Chris Wilson Reviewed-by: Keith Packard --- drivers/gpu/drm/i915/i915_debugfs.c | 8 ++++---- drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 09e0327fc6ce..87c8e29465e3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -892,7 +892,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_printf(m, "Render p-state limit: %d\n", rp_state_limits & 0xff); seq_printf(m, "CAGF: %dMHz\n", ((rpstat & GEN6_CAGF_MASK) >> - GEN6_CAGF_SHIFT) * 100); + GEN6_CAGF_SHIFT) * 50); seq_printf(m, "RP CUR UP EI: %dus\n", rpupei & GEN6_CURICONT_MASK); seq_printf(m, "RP CUR UP: %dus\n", rpcurup & @@ -908,15 +908,15 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) max_freq = (rp_state_cap & 0xff0000) >> 16; seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", - max_freq * 100); + max_freq * 50); max_freq = (rp_state_cap & 0xff00) >> 8; seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", - max_freq * 100); + max_freq * 50); max_freq = rp_state_cap & 0xff; seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", - max_freq * 100); + max_freq * 50); __gen6_gt_force_wake_put(dev_priv); } else { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 49c07231302c..432fc04c6bff 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6930,7 +6930,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) DRM_ERROR("timeout waiting for pcode mailbox to finish\n"); if (pcu_mbox & (1<<31)) { /* OC supported */ max_freq = pcu_mbox & 0xff; - DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 100); + DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50); } /* In units of 100MHz */ -- cgit v1.2.2 From ed0291fd16f6349ef43d3f25a4626c2f7baf568b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 19 Mar 2011 08:21:45 +0000 Subject: drm/i915: Fix computation of pitch for dumb bo creator Cc: Dave Airlie Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c5dfb59e13d3..0b99c30bb19c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -224,7 +224,7 @@ i915_gem_dumb_create(struct drm_file *file, struct drm_mode_create_dumb *args) { /* have to work out size/pitch and return them */ - args->pitch = ALIGN(args->width & ((args->bpp + 1) / 8), 64); + args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64); args->size = args->pitch * args->height; return i915_gem_create(file, dev, args->size, &args->handle); -- cgit v1.2.2 From d4aeee776017b6da6dcd12f453cd82a3c951a0dc Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 14 Mar 2011 15:11:24 +0000 Subject: drm/i915: Disable pagefaults along execbuffer relocation fast path Along the fast path for relocation handling, we attempt to copy directly from the user data structures whilst holding our mutex. This causes lockdep to warn about circular lock dependencies if we need to pagefault the user pages. [Since when handling a page fault on a mmapped bo, we need to acquire the struct mutex whilst already holding the mm semaphore, it is then verboten to acquire the mm semaphore when already holding the struct mutex. The likelihood of the user passing in the relocations contained in a GTT mmaped bo is low, but conceivable for extreme pathology.] In order to force the mm to return EFAULT rather than handle the pagefault, we therefore need to disable pagefaults across the relocation fast path. Signed-off-by: Chris Wilson Cc: stable@kernel.org Reviewed-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7ff7f933ddf1..20a4cc5b818f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -367,6 +367,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj, uint32_t __iomem *reloc_entry; void __iomem *reloc_page; + /* We can't wait for rendering with pagefaults disabled */ + if (obj->active && in_atomic()) + return -EFAULT; + ret = i915_gem_object_set_to_gtt_domain(obj, 1); if (ret) return ret; @@ -440,15 +444,24 @@ i915_gem_execbuffer_relocate(struct drm_device *dev, struct list_head *objects) { struct drm_i915_gem_object *obj; - int ret; - + int ret = 0; + + /* This is the fast path and we cannot handle a pagefault whilst + * holding the struct mutex lest the user pass in the relocations + * contained within a mmaped bo. For in such a case we, the page + * fault handler would call i915_gem_fault() and we would try to + * acquire the struct mutex again. Obviously this is bad and so + * lockdep complains vehemently. + */ + pagefault_disable(); list_for_each_entry(obj, objects, exec_list) { ret = i915_gem_execbuffer_relocate_object(obj, eb); if (ret) - return ret; + break; } + pagefault_enable(); - return 0; + return ret; } static int -- cgit v1.2.2 From 36d527deadf7d0c302e3452dde39465e74a65a08 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 19 Mar 2011 22:26:49 +0000 Subject: drm/i915: Restore missing command flush before interrupt on BLT ring We always skipped flushing the BLT ring if the request flush did not include the RENDER domain. However, this neglects that we try to flush the COMMAND domain after every batch and before the breadcrumb interrupt (to make sure the batch is indeed completed prior to the interrupt firing and so insuring CPU coherency). As a result of the missing flush, incoherency did indeed creep in, most notable when using lots of command buffers and so potentially rewritting an active command buffer (i.e. the GPU was still executing from it even though the following interrupt had already fired and the request/buffer retired). As all ring->flush routines now have the same preconditions, de-duplicate and move those checks up into i915_gem_flush_ring(). Fixes gem_linear_blit. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35284 Signed-off-by: Chris Wilson Reviewed-by: Daniel Vetter Tested-by: mengmeng.meng@intel.com --- drivers/gpu/drm/i915/i915_gem.c | 7 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 109 ++++++++++++++------------------ 2 files changed, 55 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0b99c30bb19c..edd6098743b2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2219,13 +2219,18 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring, { int ret; + if (((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) == 0) + return 0; + trace_i915_gem_ring_flush(ring, invalidate_domains, flush_domains); ret = ring->flush(ring, invalidate_domains, flush_domains); if (ret) return ret; - i915_gem_process_flushing_list(ring, flush_domains); + if (flush_domains & I915_GEM_GPU_DOMAINS) + i915_gem_process_flushing_list(ring, flush_domains); + return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 789c47801ba8..e9e6f71418a4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -65,62 +65,60 @@ render_ring_flush(struct intel_ring_buffer *ring, u32 cmd; int ret; - if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) { + /* + * read/write caches: + * + * I915_GEM_DOMAIN_RENDER is always invalidated, but is + * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is + * also flushed at 2d versus 3d pipeline switches. + * + * read-only caches: + * + * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if + * MI_READ_FLUSH is set, and is always flushed on 965. + * + * I915_GEM_DOMAIN_COMMAND may not exist? + * + * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is + * invalidated when MI_EXE_FLUSH is set. + * + * I915_GEM_DOMAIN_VERTEX, which exists on 965, is + * invalidated with every MI_FLUSH. + * + * TLBs: + * + * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND + * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and + * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER + * are flushed at any MI_FLUSH. + */ + + cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; + if ((invalidate_domains|flush_domains) & + I915_GEM_DOMAIN_RENDER) + cmd &= ~MI_NO_WRITE_FLUSH; + if (INTEL_INFO(dev)->gen < 4) { /* - * read/write caches: - * - * I915_GEM_DOMAIN_RENDER is always invalidated, but is - * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is - * also flushed at 2d versus 3d pipeline switches. - * - * read-only caches: - * - * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if - * MI_READ_FLUSH is set, and is always flushed on 965. - * - * I915_GEM_DOMAIN_COMMAND may not exist? - * - * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is - * invalidated when MI_EXE_FLUSH is set. - * - * I915_GEM_DOMAIN_VERTEX, which exists on 965, is - * invalidated with every MI_FLUSH. - * - * TLBs: - * - * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND - * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and - * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER - * are flushed at any MI_FLUSH. + * On the 965, the sampler cache always gets flushed + * and this bit is reserved. */ + if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) + cmd |= MI_READ_FLUSH; + } + if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) + cmd |= MI_EXE_FLUSH; - cmd = MI_FLUSH | MI_NO_WRITE_FLUSH; - if ((invalidate_domains|flush_domains) & - I915_GEM_DOMAIN_RENDER) - cmd &= ~MI_NO_WRITE_FLUSH; - if (INTEL_INFO(dev)->gen < 4) { - /* - * On the 965, the sampler cache always gets flushed - * and this bit is reserved. - */ - if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) - cmd |= MI_READ_FLUSH; - } - if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION) - cmd |= MI_EXE_FLUSH; - - if (invalidate_domains & I915_GEM_DOMAIN_COMMAND && - (IS_G4X(dev) || IS_GEN5(dev))) - cmd |= MI_INVALIDATE_ISP; + if (invalidate_domains & I915_GEM_DOMAIN_COMMAND && + (IS_G4X(dev) || IS_GEN5(dev))) + cmd |= MI_INVALIDATE_ISP; - ret = intel_ring_begin(ring, 2); - if (ret) - return ret; + ret = intel_ring_begin(ring, 2); + if (ret) + return ret; - intel_ring_emit(ring, cmd); - intel_ring_emit(ring, MI_NOOP); - intel_ring_advance(ring); - } + intel_ring_emit(ring, cmd); + intel_ring_emit(ring, MI_NOOP); + intel_ring_advance(ring); return 0; } @@ -568,9 +566,6 @@ bsd_ring_flush(struct intel_ring_buffer *ring, { int ret; - if ((flush_domains & I915_GEM_DOMAIN_RENDER) == 0) - return 0; - ret = intel_ring_begin(ring, 2); if (ret) return ret; @@ -1056,9 +1051,6 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring, uint32_t cmd; int ret; - if (((invalidate | flush) & I915_GEM_GPU_DOMAINS) == 0) - return 0; - ret = intel_ring_begin(ring, 4); if (ret) return ret; @@ -1230,9 +1222,6 @@ static int blt_ring_flush(struct intel_ring_buffer *ring, uint32_t cmd; int ret; - if (((invalidate | flush) & I915_GEM_DOMAIN_RENDER) == 0) - return 0; - ret = blt_ring_begin(ring, 4); if (ret) return ret; -- cgit v1.2.2 From 26e12f894317bf0221fed40bef6f937538a78c0b Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Mar 2011 11:20:19 +0000 Subject: drm/i915: Fix use after free within tracepoint Detected by scripts/coccinelle/free/kfree.cocci. Signed-off-by: Chris Wilson Reviewed-by: Keith Packard --- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index edd6098743b2..c9bdaf208a91 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3603,6 +3603,8 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj) return; } + trace_i915_gem_object_destroy(obj); + if (obj->base.map_list.map) i915_gem_free_mmap_offset(obj); @@ -3612,8 +3614,6 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj) kfree(obj->page_cpu_valid); kfree(obj->bit_17); kfree(obj); - - trace_i915_gem_object_destroy(obj); } void i915_gem_free_object(struct drm_gem_object *gem_obj) -- cgit v1.2.2 From f6e47884e7f588094bf7b824c839a9ee33f2aa55 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 20 Mar 2011 21:09:12 +0000 Subject: drm/i915: Avoid unmapping pages from a NULL address space Found by gem_stress. As we perform retirement from a workqueue, it is possible for us to free and unbind objects after the last close on the device, and so after the address space has been torn down and reset to NULL: BUG: unable to handle kernel NULL pointer dereference at 00000054 IP: [] mutex_lock+0xf/0x27 *pde = 00000000 Oops: 0002 [#1] SMP last sysfs file: /sys/module/vt/parameters/default_utf8 Pid: 5, comm: kworker/u:0 Not tainted 2.6.38+ #214 EIP: 0060:[] EFLAGS: 00010206 CPU: 1 EIP is at mutex_lock+0xf/0x27 EAX: 00000054 EBX: 00000054 ECX: 00000000 EDX: 00012fff ESI: 00000028 EDI: 00000000 EBP: f706fe20 ESP: f706fe18 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process kworker/u:0 (pid: 5, ti=f706e000 task=f7060d00 task.ti=f706e000) Stack: f5aa3c60 00000000 f706fe74 c107e7df 00000246 dea55380 00000054 f5aa3c60 f706fe44 00000061 f70b4000 c13fff84 00000008 f706fe54 00000000 00000000 00012f00 00012fff 00000028 c109e575 f6b36700 00100000 00000000 f706fe90 Call Trace: [] unmap_mapping_range+0x7d/0x1e6 [] ? mntput_no_expire+0x52/0xb6 [] i915_gem_release_mmap+0x49/0x58 [] i915_gem_object_unbind+0x4c/0x125 [] i915_gem_free_object_tail+0x1d/0xdb [] i915_gem_free_object+0x3d/0x41 [] ? drm_gem_object_free+0x0/0x27 [] drm_gem_object_free+0x25/0x27 [] kref_put+0x39/0x42 [] drm_gem_object_unreference+0x16/0x18 [] i915_gem_object_move_to_inactive+0xba/0xbe [] i915_gem_retire_requests_ring+0x16e/0x1a5 [] i915_gem_retire_requests+0x48/0x63 [] i915_gem_retire_work_handler+0x4c/0x117 [] process_one_work+0x140/0x21b [] ? __need_more_worker+0x13/0x2a [] ? need_to_create_worker+0x1c/0x35 [] ? i915_gem_retire_work_handler+0x0/0x117 [] worker_thread+0xd4/0x14b [] ? worker_thread+0x0/0x14b [] kthread+0x68/0x6d [] ? kthread+0x0/0x6d [] kernel_thread_helper+0x6/0x10 Code: 00 e8 98 fe ff ff 5d c3 55 89 e5 3e 8d 74 26 00 ba 01 00 00 00 e8 84 fe ff ff 5d c3 55 89 e5 53 8d 64 24 fc 3e 8d 74 26 00 89 c3 ff 08 79 05 e8 ab ff ff ff 89 e0 25 00 e0 ff ff 89 43 10 58 EIP: [] mutex_lock+0xf/0x27 SS:ESP 0068:f706fe18 CR2: 0000000000000054 Signed-off-by: Chris Wilson Reviewed-by: Keith Packard --- drivers/gpu/drm/i915/i915_gem.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c9bdaf208a91..7ce3f353af33 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1356,9 +1356,10 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj) if (!obj->fault_mappable) return; - unmap_mapping_range(obj->base.dev->dev_mapping, - (loff_t)obj->base.map_list.hash.key<base.size, 1); + if (obj->base.dev->dev_mapping) + unmap_mapping_range(obj->base.dev->dev_mapping, + (loff_t)obj->base.map_list.hash.key<base.size, 1); obj->fault_mappable = false; } -- cgit v1.2.2 From df508450870cd5b4478156dcde8e68e6bf0d6661 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 14 Jan 2011 13:38:16 +0000 Subject: mfd: Leave acknowledgement of WM831x touchscreen IRQs to the driver The WM831x touchscreen interrupts need acknowledgement even when using direct signals to the CPU (which don't go through the core) so leave the acknowledgement up to the touchscreen driver for simplicity. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index f7192d438aab..2691648e607e 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -481,6 +481,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) } out: + /* Touchscreen interrupts are handled specially in the driver */ + status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); + for (i = 0; i < ARRAY_SIZE(status_regs); i++) { if (status_regs[i]) wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, -- cgit v1.2.2 From dc781454690d7e5857afd84845b6402e03493ee1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 21:45:46 +0000 Subject: mfd: Convert adp5520 to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitiate updates to the PM core. Do this move for the adp5520 driver. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/adp5520.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 3122139b4300..f1d88483112c 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -321,27 +321,27 @@ static int __devexit adp5520_remove(struct i2c_client *client) } #ifdef CONFIG_PM -static int adp5520_suspend(struct i2c_client *client, - pm_message_t state) +static int adp5520_suspend(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct adp5520_chip *chip = dev_get_drvdata(&client->dev); adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); return 0; } -static int adp5520_resume(struct i2c_client *client) +static int adp5520_resume(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); struct adp5520_chip *chip = dev_get_drvdata(&client->dev); adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); return 0; } -#else -#define adp5520_suspend NULL -#define adp5520_resume NULL #endif +static SIMPLE_DEV_PM_OPS(adp5520_pm, adp5520_suspend, adp5520_resume); + static const struct i2c_device_id adp5520_id[] = { { "pmic-adp5520", ID_ADP5520 }, { "pmic-adp5501", ID_ADP5501 }, @@ -353,11 +353,10 @@ static struct i2c_driver adp5520_driver = { .driver = { .name = "adp5520", .owner = THIS_MODULE, + .pm = &adp5520_pm, }, .probe = adp5520_probe, .remove = __devexit_p(adp5520_remove), - .suspend = adp5520_suspend, - .resume = adp5520_resume, .id_table = adp5520_id, }; -- cgit v1.2.2 From 44be0a40d8666d9f3acee2a329e50f925e32d8b0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 21:47:31 +0000 Subject: mfd: Staticise non-exported symbols in MAX8998 driver No need to have them in the global namespace and sparse complains. Signed-off-by: Mark Brown Acked-by: Kyungmin Park Signed-off-by: Samuel Ortiz --- drivers/mfd/max8998.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index bbfe86732602..c00214257da2 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -233,7 +233,7 @@ struct max8998_reg_dump { u8 val; }; #define SAVE_ITEM(x) { .addr = (x), .val = 0x0, } -struct max8998_reg_dump max8998_dump[] = { +static struct max8998_reg_dump max8998_dump[] = { SAVE_ITEM(MAX8998_REG_IRQM1), SAVE_ITEM(MAX8998_REG_IRQM2), SAVE_ITEM(MAX8998_REG_IRQM3), @@ -298,7 +298,7 @@ static int max8998_restore(struct device *dev) return 0; } -const struct dev_pm_ops max8998_pm = { +static const struct dev_pm_ops max8998_pm = { .suspend = max8998_suspend, .resume = max8998_resume, .freeze = max8998_freeze, -- cgit v1.2.2 From 939941d44dcaa138241d2182bd9e10f2b5d52665 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Jan 2011 21:52:42 +0000 Subject: mfd: Convert pcf50633 to dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitiate updates to the PM core. Do this move for the pcf50633 driver. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/pcf50633-core.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 501ce13b693e..2640e4dcd078 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -230,27 +231,26 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, } } -#ifdef CONFIG_PM -static int pcf50633_suspend(struct i2c_client *client, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pcf50633_suspend(struct device *dev) { - struct pcf50633 *pcf; - pcf = i2c_get_clientdata(client); + struct i2c_client *client = to_i2c_client(dev); + struct pcf50633 *pcf = i2c_get_clientdata(client); return pcf50633_irq_suspend(pcf); } -static int pcf50633_resume(struct i2c_client *client) +static int pcf50633_resume(struct device *dev) { - struct pcf50633 *pcf; - pcf = i2c_get_clientdata(client); + struct i2c_client *client = to_i2c_client(dev); + struct pcf50633 *pcf = i2c_get_clientdata(client); return pcf50633_irq_resume(pcf); } -#else -#define pcf50633_suspend NULL -#define pcf50633_resume NULL #endif +static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume); + static int __devinit pcf50633_probe(struct i2c_client *client, const struct i2c_device_id *ids) { @@ -364,12 +364,11 @@ static struct i2c_device_id pcf50633_id_table[] = { static struct i2c_driver pcf50633_driver = { .driver = { .name = "pcf50633", + .pm = &pcf50633_pm, }, .id_table = pcf50633_id_table, .probe = pcf50633_probe, .remove = __devexit_p(pcf50633_remove), - .suspend = pcf50633_suspend, - .resume = pcf50633_resume, }; static int __init pcf50633_init(void) -- cgit v1.2.2 From b103e0b3c52e6edb4839ccc961cf335ca6b88918 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Jan 2011 13:26:46 +0000 Subject: mfd: Support configuration of WM831x /IRQ output in CMOS mode Provide platform data allowing the system to set the /IRQ pin into CMOS mode rather than the default open drain. The default value of this platform data reflects the default hardware configuration so there should be no change to existing users. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 2691648e607e..90ad3fa91329 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -520,6 +520,14 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) return 0; } + if (pdata->irq_cmos) + i = 0; + else + i = WM831X_IRQ_OD; + + wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, + WM831X_IRQ_OD, i); + /* Try to flag /IRQ as a wake source; there are a number of * unconditional wake sources in the PMIC so this isn't * conditional but we don't actually care *too* much if it -- cgit v1.2.2 From ce5d4a435af2839771210aeda2b649f5a183b63c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 24 Jan 2011 11:44:27 +0100 Subject: mfd: Remove obsolete cleanup for wl1273 clientdata A few new i2c-drivers came into the kernel which clear the clientdata-pointer on exit or error. This is obsolete meanwhile, the core will do it. Signed-off-by: Wolfram Sang Signed-off-by: Samuel Ortiz --- drivers/mfd/wl1273-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index d2ecc2435736..6bb51364dcb4 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -38,7 +38,6 @@ static int wl1273_core_remove(struct i2c_client *client) dev_dbg(&client->dev, "%s\n", __func__); mfd_remove_devices(&client->dev); - i2c_set_clientdata(client, NULL); kfree(core); return 0; @@ -104,7 +103,6 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, return 0; err: - i2c_set_clientdata(client, NULL); pdata->free_resources(); kfree(core); -- cgit v1.2.2 From de8c8b0683043e81d2001e446f2bcb143affb0b2 Mon Sep 17 00:00:00 2001 From: Jochen Friedrich Date: Sun, 30 Jan 2011 13:40:56 +0100 Subject: mfd: Add BTN_TOUCH event to ucb1x00-ts Add BTN_TOUCH event reporting to ucb1x00_ts touchscreen driver. This will make this touchscreen driver behave consistently wrt. BTN_TOUCH. Signed-off-by: Jochen Friedrich Acked-by: Dmitry Torokhov Signed-off-by: Samuel Ortiz --- drivers/mfd/ucb1x00-ts.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 92b85e28a15e..38ffbd50a0d2 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -60,6 +60,7 @@ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x input_report_abs(idev, ABS_X, x); input_report_abs(idev, ABS_Y, y); input_report_abs(idev, ABS_PRESSURE, pressure); + input_report_key(idev, BTN_TOUCH, 1); input_sync(idev); } @@ -68,6 +69,7 @@ static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) struct input_dev *idev = ts->idev; input_report_abs(idev, ABS_PRESSURE, 0); + input_report_key(idev, BTN_TOUCH, 0); input_sync(idev); } @@ -384,7 +386,8 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) idev->open = ucb1x00_ts_open; idev->close = ucb1x00_ts_close; - __set_bit(EV_ABS, idev->evbit); + idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY); + idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); input_set_drvdata(idev, ts); -- cgit v1.2.2 From 6f9f13bf9b9fabf2da2028cb7c1e732ef2efa26d Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Mon, 31 Jan 2011 11:31:49 -0500 Subject: mfd: Invert tps6586x GPIO and subdevices initialization When using a fixed voltage regulator triggered by a TPS6586x GPIO, this allows to declare and initialize it conveniently from the "subdev" list. Signed-off-by: Vincent Palatin Signed-off-by: Samuel Ortiz --- drivers/mfd/tps6586x.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index e9018d1394ee..0aa9186aec19 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -288,12 +288,10 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask); } -static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) +static int tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) { - int ret; - if (!gpio_base) - return; + return 0; tps6586x->gpio.owner = THIS_MODULE; tps6586x->gpio.label = tps6586x->client->name; @@ -307,9 +305,7 @@ static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base) tps6586x->gpio.set = tps6586x_gpio_set; tps6586x->gpio.get = tps6586x_gpio_get; - ret = gpiochip_add(&tps6586x->gpio); - if (ret) - dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret); + return gpiochip_add(&tps6586x->gpio); } static int __remove_subdev(struct device *dev, void *unused) @@ -517,17 +513,28 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, } } + ret = tps6586x_gpio_init(tps6586x, pdata->gpio_base); + if (ret) { + dev_err(&client->dev, "GPIO registration failed: %d\n", ret); + goto err_gpio_init; + } + ret = tps6586x_add_subdevs(tps6586x, pdata); if (ret) { dev_err(&client->dev, "add devices failed: %d\n", ret); goto err_add_devs; } - tps6586x_gpio_init(tps6586x, pdata->gpio_base); - return 0; err_add_devs: + if (pdata->gpio_base) { + ret = gpiochip_remove(&tps6586x->gpio); + if (ret) + dev_err(&client->dev, "Can't remove gpio chip: %d\n", + ret); + } +err_gpio_init: if (client->irq) free_irq(client->irq, tps6586x); err_irq_init: @@ -587,4 +594,3 @@ module_exit(tps6586x_exit); MODULE_DESCRIPTION("TPS6586X core driver"); MODULE_AUTHOR("Mike Rapoport "); MODULE_LICENSE("GPL"); - -- cgit v1.2.2 From 87d1906df4ecf6df0832e78e5189a39c7ea09a29 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 1 Feb 2011 11:46:12 +0000 Subject: mfd: Convert WM831x SPI to use dev_pm_ops There is a move to deprecate bus-specific PM operations and move to using dev_pm_ops instead in order to reduce the amount of boilerplate code in buses and facilitiate updates to the PM core. Do this move for the WM831x SPI driver. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-spi.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 0a8f772be88c..eed8e4f7a5a1 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -113,22 +114,27 @@ static int __devexit wm831x_spi_remove(struct spi_device *spi) return 0; } -static int wm831x_spi_suspend(struct spi_device *spi, pm_message_t m) +static int wm831x_spi_suspend(struct device *dev) { - struct wm831x *wm831x = dev_get_drvdata(&spi->dev); + struct wm831x *wm831x = dev_get_drvdata(dev); return wm831x_device_suspend(wm831x); } +static const struct dev_pm_ops wm831x_spi_pm = { + .freeze = wm831x_spi_suspend, + .suspend = wm831x_spi_suspend, +}; + static struct spi_driver wm8310_spi_driver = { .driver = { .name = "wm8310", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), - .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8311_spi_driver = { @@ -136,10 +142,10 @@ static struct spi_driver wm8311_spi_driver = { .name = "wm8311", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), - .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8312_spi_driver = { @@ -147,10 +153,10 @@ static struct spi_driver wm8312_spi_driver = { .name = "wm8312", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), - .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8320_spi_driver = { @@ -158,10 +164,10 @@ static struct spi_driver wm8320_spi_driver = { .name = "wm8320", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), - .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8321_spi_driver = { @@ -169,10 +175,10 @@ static struct spi_driver wm8321_spi_driver = { .name = "wm8321", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), - .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8325_spi_driver = { @@ -180,10 +186,10 @@ static struct spi_driver wm8325_spi_driver = { .name = "wm8325", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), - .suspend = wm831x_spi_suspend, }; static struct spi_driver wm8326_spi_driver = { @@ -191,10 +197,10 @@ static struct spi_driver wm8326_spi_driver = { .name = "wm8326", .bus = &spi_bus_type, .owner = THIS_MODULE, + .pm = &wm831x_spi_pm, }, .probe = wm831x_spi_probe, .remove = __devexit_p(wm831x_spi_remove), - .suspend = wm831x_spi_suspend, }; static int __init wm831x_spi_init(void) -- cgit v1.2.2 From 8546bd4af1251d17d16b0ef682d84fd23c8beaca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 1 Feb 2011 11:46:13 +0000 Subject: mfd: Add fast path for WM831x touchscreen interrupts The WM831x interrupt controller provides reporting of the touchscreen related interrupts in the primary interrupt status register as a performance optimisation - use this to avoid reading the secondary status registers for those interrupts. For code simplicity and to avoid iterating over all interrupts we open code for the two affected interrupt sources. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 90ad3fa91329..03eb61dd0965 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -449,6 +449,18 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) goto out; } + /* The touch interrupts are visible in the primary register as + * an optimisation; open code this to avoid complicating the + * main handling loop and so we can also skip iterating the + * descriptors. + */ + if (primary & WM831X_TCHPD_INT) + handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); + if (primary & WM831X_TCHDATA_INT) + handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); + if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT)) + goto out; + for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { int offset = wm831x_irqs[i].reg - 1; -- cgit v1.2.2 From 90550d1903da8dac851d220b794e44c90a11c6ce Mon Sep 17 00:00:00 2001 From: Mattias Nilsson Date: Mon, 14 Feb 2011 11:17:12 +0100 Subject: mfd: AB8500 system control driver This adds a pretty straight-forward system control driver for the AB8500. This driver will be used from the core platform, e.g the clock tree implementation in the machine code, and is by nature singleton. There are a few simple functions to read, write, set and clear registers so that the machine code can control its own foundation. Cc: Mattias Wallin Signed-off-by: Mattias Nilsson Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/Makefile | 2 +- drivers/mfd/ab8500-sysctrl.c | 80 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 drivers/mfd/ab8500-sysctrl.c (limited to 'drivers') diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f0e25cad762e..61a0b0f901a2 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -71,7 +71,7 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_AB3100_CORE) += ab3100-core.o obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB3550_CORE) += ab3550-core.o -obj-$(CONFIG_AB8500_CORE) += ab8500-core.o +obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c new file mode 100644 index 000000000000..392185965b39 --- /dev/null +++ b/drivers/mfd/ab8500-sysctrl.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Author: Mattias Nilsson for ST Ericsson. + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include + +static struct device *sysctrl_dev; + +static inline bool valid_bank(u8 bank) +{ + return ((bank == AB8500_SYS_CTRL1_BLOCK) || + (bank == AB8500_SYS_CTRL2_BLOCK)); +} + +int ab8500_sysctrl_read(u16 reg, u8 *value) +{ + u8 bank; + + if (sysctrl_dev == NULL) + return -EAGAIN; + + bank = (reg >> 8); + if (!valid_bank(bank)) + return -EINVAL; + + return abx500_get_register_interruptible(sysctrl_dev, bank, + (u8)(reg & 0xFF), value); +} + +int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value) +{ + u8 bank; + + if (sysctrl_dev == NULL) + return -EAGAIN; + + bank = (reg >> 8); + if (!valid_bank(bank)) + return -EINVAL; + + return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank, + (u8)(reg & 0xFF), mask, value); +} + +static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev) +{ + sysctrl_dev = &pdev->dev; + return 0; +} + +static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev) +{ + sysctrl_dev = NULL; + return 0; +} + +static struct platform_driver ab8500_sysctrl_driver = { + .driver = { + .name = "ab8500-sysctrl", + .owner = THIS_MODULE, + }, + .probe = ab8500_sysctrl_probe, + .remove = __devexit_p(ab8500_sysctrl_remove), +}; + +static int __init ab8500_sysctrl_init(void) +{ + return platform_driver_register(&ab8500_sysctrl_driver); +} +subsys_initcall(ab8500_sysctrl_init); + +MODULE_AUTHOR("Mattias Nilsson Date: Fri, 4 Feb 2011 15:23:36 +0300 Subject: mfd: ab3100: world-writable debugfs *_priv files Don't allow everybody to change device hardware registers. Signed-off-by: Vasiliy Kulikov Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3100-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 4193af5f2743..1707d224232d 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -613,7 +613,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100) ab3100_get_priv.ab3100 = ab3100; ab3100_get_priv.mode = false; ab3100_get_reg_file = debugfs_create_file("get_reg", - S_IWUGO, ab3100_dir, &ab3100_get_priv, + S_IWUSR, ab3100_dir, &ab3100_get_priv, &ab3100_get_set_reg_fops); if (!ab3100_get_reg_file) { err = -ENOMEM; @@ -623,7 +623,7 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100) ab3100_set_priv.ab3100 = ab3100; ab3100_set_priv.mode = true; ab3100_set_reg_file = debugfs_create_file("set_reg", - S_IWUGO, ab3100_dir, &ab3100_set_priv, + S_IWUSR, ab3100_dir, &ab3100_set_priv, &ab3100_get_set_reg_fops); if (!ab3100_set_reg_file) { err = -ENOMEM; -- cgit v1.2.2 From 90c861c2a83d974684974441093ff8a50e6b430b Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Fri, 4 Feb 2011 15:23:39 +0300 Subject: mfd: ab3500: world-writable debugfs register-* files Don't allow everybody to interact with hardware registers. Signed-off-by: Vasiliy Kulikov Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3550-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index 5fbca346b998..681984df1c28 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -1053,17 +1053,17 @@ static inline void ab3550_setup_debugfs(struct ab3550 *ab) goto exit_destroy_dir; ab3550_bank_file = debugfs_create_file("register-bank", - (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_bank_fops); + (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_bank_fops); if (!ab3550_bank_file) goto exit_destroy_reg; ab3550_address_file = debugfs_create_file("register-address", - (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_address_fops); + (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_address_fops); if (!ab3550_address_file) goto exit_destroy_bank; ab3550_val_file = debugfs_create_file("register-value", - (S_IRUGO | S_IWUGO), ab3550_dir, ab, &ab3550_val_fops); + (S_IRUGO | S_IWUSR), ab3550_dir, ab, &ab3550_val_fops); if (!ab3550_val_file) goto exit_destroy_address; -- cgit v1.2.2 From 44bdcb54df2714da18c4a0c6f711a350ab4ed93c Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Fri, 4 Feb 2011 15:23:43 +0300 Subject: mfd: ab8500: world-writable debugfs register-* files Don't allow everybody to interact with hardware registers. Signed-off-by: Vasiliy Kulikov Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 3c1541ae7223..64748e42ac03 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -585,18 +585,18 @@ static int __devinit ab8500_debug_probe(struct platform_device *plf) goto exit_destroy_dir; ab8500_bank_file = debugfs_create_file("register-bank", - (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_bank_fops); + (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_bank_fops); if (!ab8500_bank_file) goto exit_destroy_reg; ab8500_address_file = debugfs_create_file("register-address", - (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, + (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_address_fops); if (!ab8500_address_file) goto exit_destroy_bank; ab8500_val_file = debugfs_create_file("register-value", - (S_IRUGO | S_IWUGO), ab8500_dir, &plf->dev, &ab8500_val_fops); + (S_IRUGO | S_IWUSR), ab8500_dir, &plf->dev, &ab8500_val_fops); if (!ab8500_val_file) goto exit_destroy_address; -- cgit v1.2.2 From dae2db30c114cd0dec59b4130c315c9cce351741 Mon Sep 17 00:00:00 2001 From: Arun Murthy Date: Tue, 22 Feb 2011 10:11:13 +0100 Subject: mfd: Add new ab8500 GPADC driver AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage Signed-off-by: Arun Murthy Acked-by: Linus Walleij Acked-by: Mattias Wallin Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 7 ++ drivers/mfd/Makefile | 1 + drivers/mfd/ab8500-gpadc.c | 296 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 drivers/mfd/ab8500-gpadc.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fdca643249e1..d71af4531b14 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -534,6 +534,13 @@ config AB8500_DEBUG Select this option if you want debug information using the debug filesystem, debugfs. +config AB8500_GPADC + bool "AB8500 GPADC driver" + depends on AB8500_CORE && REGULATOR_AB8500 + default y + help + AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage + config AB3550_CORE bool "ST-Ericsson AB3550 Mixed Signal Circuit core functions" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 61a0b0f901a2..ad71bd59345f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_AB3550_CORE) += ab3550-core.o obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o +obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o obj-$(CONFIG_LPC_SCH) += lpc_sch.o diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c new file mode 100644 index 000000000000..19339bc439ca --- /dev/null +++ b/drivers/mfd/ab8500-gpadc.c @@ -0,0 +1,296 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * Author: Arun R Murthy + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * GPADC register offsets + * Bank : 0x0A + */ +#define AB8500_GPADC_CTRL1_REG 0x00 +#define AB8500_GPADC_CTRL2_REG 0x01 +#define AB8500_GPADC_CTRL3_REG 0x02 +#define AB8500_GPADC_AUTO_TIMER_REG 0x03 +#define AB8500_GPADC_STAT_REG 0x04 +#define AB8500_GPADC_MANDATAL_REG 0x05 +#define AB8500_GPADC_MANDATAH_REG 0x06 +#define AB8500_GPADC_AUTODATAL_REG 0x07 +#define AB8500_GPADC_AUTODATAH_REG 0x08 +#define AB8500_GPADC_MUX_CTRL_REG 0x09 + +/* gpadc constants */ +#define EN_VINTCORE12 0x04 +#define EN_VTVOUT 0x02 +#define EN_GPADC 0x01 +#define DIS_GPADC 0x00 +#define SW_AVG_16 0x60 +#define ADC_SW_CONV 0x04 +#define EN_BUF 0x40 +#define DIS_ZERO 0x00 +#define GPADC_BUSY 0x01 + +/** + * struct ab8500_gpadc - ab8500 GPADC device information + * @dev: pointer to the struct device + * @parent: pointer to the parent device structure ab8500 + * @ab8500_gpadc_complete: pointer to the struct completion, to indicate + * the completion of gpadc conversion + * @ab8500_gpadc_lock: structure of type mutex + * @regu: pointer to the struct regulator + * @irq: interrupt number that is used by gpadc + */ +static struct ab8500_gpadc { + struct device *dev; + struct ab8500 *parent; + struct completion ab8500_gpadc_complete; + struct mutex ab8500_gpadc_lock; + struct regulator *regu; + int irq; +} *di; + +/** + * ab8500_gpadc_convert() - gpadc conversion + * @input: analog input to be converted to digital data + * + * This function converts the selected analog i/p to digital + * data. Thereafter calibration has to be made to obtain the + * data in the required quantity measurement. + */ +int ab8500_gpadc_convert(u8 input) +{ + int ret; + u16 data = 0; + int looplimit = 0; + u8 val, low_data, high_data; + + if (!di) + return -ENODEV; + + mutex_lock(&di->ab8500_gpadc_lock); + /* Enable VTVout LDO this is required for GPADC */ + regulator_enable(di->regu); + + /* Check if ADC is not busy, lock and proceed */ + do { + ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_STAT_REG, &val); + if (ret < 0) + goto out; + if (!(val & GPADC_BUSY)) + break; + msleep(10); + } while (++looplimit < 10); + if (looplimit >= 10 && (val & GPADC_BUSY)) { + dev_err(di->dev, "gpadc_conversion: GPADC busy"); + ret = -EINVAL; + goto out; + } + + /* Enable GPADC */ + ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC); + if (ret < 0) { + dev_err(di->dev, "gpadc_conversion: enable gpadc failed\n"); + goto out; + } + /* Select the input source and set average samples to 16 */ + ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16)); + if (ret < 0) { + dev_err(di->dev, + "gpadc_conversion: set avg samples failed\n"); + goto out; + } + /* Enable ADC, Buffering and select rising edge, start Conversion */ + ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); + if (ret < 0) { + dev_err(di->dev, + "gpadc_conversion: select falling edge failed\n"); + goto out; + } + ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); + if (ret < 0) { + dev_err(di->dev, + "gpadc_conversion: start s/w conversion failed\n"); + goto out; + } + /* wait for completion of conversion */ + if (!wait_for_completion_timeout(&di->ab8500_gpadc_complete, 2*HZ)) { + dev_err(di->dev, + "timeout: didnt recieve GPADC conversion interrupt\n"); + ret = -EINVAL; + goto out; + } + + /* Read the converted RAW data */ + ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_MANDATAL_REG, &low_data); + if (ret < 0) { + dev_err(di->dev, "gpadc_conversion: read low data failed\n"); + goto out; + } + + ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_MANDATAH_REG, &high_data); + if (ret < 0) { + dev_err(di->dev, "gpadc_conversion: read high data failed\n"); + goto out; + } + + data = (high_data << 8) | low_data; + /* Disable GPADC */ + ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_CTRL1_REG, DIS_GPADC); + if (ret < 0) { + dev_err(di->dev, "gpadc_conversion: disable gpadc failed\n"); + goto out; + } + /* Disable VTVout LDO this is required for GPADC */ + regulator_disable(di->regu); + mutex_unlock(&di->ab8500_gpadc_lock); + return data; + +out: + /* + * It has shown to be needed to turn off the GPADC if an error occurs, + * otherwise we might have problem when waiting for the busy bit in the + * GPADC status register to go low. In V1.1 there wait_for_completion + * seems to timeout when waiting for an interrupt.. Not seen in V2.0 + */ + (void) abx500_set_register_interruptible(di->dev, AB8500_GPADC, + AB8500_GPADC_CTRL1_REG, DIS_GPADC); + regulator_disable(di->regu); + mutex_unlock(&di->ab8500_gpadc_lock); + dev_err(di->dev, "gpadc_conversion: Failed to AD convert channel %d\n", + input); + return ret; +} +EXPORT_SYMBOL(ab8500_gpadc_convert); + +/** + * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion + * @irq: irq number + * @data: pointer to the data passed during request irq + * + * This is a interrupt service routine for s/w gpadc conversion completion. + * Notifies the gpadc completion is completed and the converted raw value + * can be read from the registers. + * Returns IRQ status(IRQ_HANDLED) + */ +static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_di) +{ + struct ab8500_gpadc *gpadc = _di; + + complete(&gpadc->ab8500_gpadc_complete); + + return IRQ_HANDLED; +} + +static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct ab8500_gpadc *gpadc; + + gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL); + if (!gpadc) { + dev_err(&pdev->dev, "Error: No memory\n"); + return -ENOMEM; + } + + gpadc->parent = dev_get_drvdata(pdev->dev.parent); + gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END"); + if (gpadc->irq < 0) { + dev_err(gpadc->dev, "failed to get platform irq-%d\n", di->irq); + ret = gpadc->irq; + goto fail; + } + + gpadc->dev = &pdev->dev; + mutex_init(&di->ab8500_gpadc_lock); + + /* Initialize completion used to notify completion of conversion */ + init_completion(&gpadc->ab8500_gpadc_complete); + + /* Register interrupt - SwAdcComplete */ + ret = request_threaded_irq(gpadc->irq, NULL, + ab8500_bm_gpswadcconvend_handler, + IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc", gpadc); + if (ret < 0) { + dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n", + gpadc->irq); + goto fail; + } + + /* VTVout LDO used to power up ab8500-GPADC */ + gpadc->regu = regulator_get(&pdev->dev, "vddadc"); + if (IS_ERR(gpadc->regu)) { + ret = PTR_ERR(gpadc->regu); + dev_err(gpadc->dev, "failed to get vtvout LDO\n"); + goto fail; + } + di = gpadc; + dev_dbg(gpadc->dev, "probe success\n"); + return 0; +fail: + kfree(gpadc); + gpadc = NULL; + return ret; +} + +static int __devexit ab8500_gpadc_remove(struct platform_device *pdev) +{ + struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); + + /* remove interrupt - completion of Sw ADC conversion */ + free_irq(gpadc->irq, di); + /* disable VTVout LDO that is being used by GPADC */ + regulator_put(gpadc->regu); + kfree(gpadc); + gpadc = NULL; + return 0; +} + +static struct platform_driver ab8500_gpadc_driver = { + .probe = ab8500_gpadc_probe, + .remove = __devexit_p(ab8500_gpadc_remove), + .driver = { + .name = "ab8500-gpadc", + .owner = THIS_MODULE, + }, +}; + +static int __init ab8500_gpadc_init(void) +{ + return platform_driver_register(&ab8500_gpadc_driver); +} + +static void __exit ab8500_gpadc_exit(void) +{ + platform_driver_unregister(&ab8500_gpadc_driver); +} + +subsys_initcall_sync(ab8500_gpadc_init); +module_exit(ab8500_gpadc_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Arun R Murthy"); +MODULE_ALIAS("platform:ab8500_gpadc"); +MODULE_DESCRIPTION("AB8500 GPADC driver"); -- cgit v1.2.2 From 8e6de4a30294809420ac9a974b4f28b38ebdb38f Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Thu, 10 Feb 2011 18:44:50 +0530 Subject: regulator: twl: add clk32kg to twl-regulator In OMAP4 Blaze and Panda, 32KHz clock to WLAN is supplied from Phoenix TWL6030. The 32KHz clock state (ON/OFF) is configured in CLK32KG_CFG_[GRP, TRANS, STATE] register. This follows the same register programming model as other regulators in TWL6030. So add CLK32KG as pseudo regulator. Signed-off-by: Balaji T K Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/twl-core.c | 4 ++++ drivers/regulator/twl-regulator.c | 24 +++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index a35fa7dcbf53..7d909cc8670d 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -864,6 +864,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3); if (IS_ERR(child)) return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg); + if (IS_ERR(child)) + return PTR_ERR(child); } if (twl_has_bci() && pdata->bci && diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index bd332cf1cc3f..6a292852a358 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -475,6 +475,13 @@ static struct regulator_ops twlfixed_ops = { .get_status = twlreg_get_status, }; +static struct regulator_ops twl6030_fixed_resource = { + .enable = twlreg_enable, + .disable = twlreg_disable, + .is_enabled = twlreg_is_enabled, + .get_status = twlreg_get_status, +}; + /*----------------------------------------------------------------------*/ #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ @@ -538,6 +545,20 @@ static struct regulator_ops twlfixed_ops = { }, \ } +#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay, remap_conf) { \ + .base = offset, \ + .id = num, \ + .delay = turnon_delay, \ + .remap = remap_conf, \ + .desc = { \ + .name = #label, \ + .id = TWL6030_REG_##label, \ + .ops = &twl6030_fixed_resource, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + /* * We list regulators here if systems need some level of * software control over them after boot. @@ -577,7 +598,8 @@ static struct twlreg_info twl_regs[] = { TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21), TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21), TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21), - TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21) + TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21), + TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0, 0x21), }; static int __devinit twlreg_probe(struct platform_device *pdev) -- cgit v1.2.2 From f66ea457f616258777cb3349f33745b0240e54fd Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 13 Feb 2011 20:06:06 +0000 Subject: mfd: Remove bitrotted genirq comment from wm831x IRQ code Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 03eb61dd0965..2e45f60d01a7 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -26,15 +26,6 @@ #include -/* - * Since generic IRQs don't currently support interrupt controllers on - * interrupt driven buses we don't use genirq but instead provide an - * interface that looks very much like the standard ones. This leads - * to some bodges, including storing interrupt handler information in - * the static irq_data table we use to look up the data for individual - * interrupts, but hopefully won't last too long. - */ - struct wm831x_irq_data { int primary; int reg; -- cgit v1.2.2 From f40dff9edbf1daa14068542d60ae22df78e8c74a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 21 Feb 2011 18:30:31 +0000 Subject: mfd: Put WM8994 into reset when suspending Ensure that the chip is in the lowest power mode possible when suspended by performing a soft reset on it. On early silicon revisions the lowest power modes can't be entered without using reset so we can't achieve equivalent results within the individual drivers. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index f4016a075fd6..e673bda21f5d 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -271,6 +271,11 @@ static int wm8994_suspend(struct device *dev) if (ret < 0) dev_err(dev, "Failed to save LDO registers: %d\n", ret); + /* Explicitly put the device into reset in case regulators + * don't get disabled in order to ensure consistent restart. + */ + wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994); + wm8994->suspended = true; ret = regulator_bulk_disable(wm8994->num_supplies, -- cgit v1.2.2 From 153617fdd3e88fc9f8ea0bcd664671054645180f Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 23 Feb 2011 16:26:54 +0530 Subject: mfd: Enabling twl4030_wdt and pwrbutton only for Triton Enabling twl4030_wdt and twl4030_pwrbutton only for Triton i.e for TWL4030 and TWL5030. This is to be excluded for Phoenix TWL6030. Tested OMAP4 blaze, OMAP2430, OMAP3630 boot up. Signed-off-by: Keerthy Reviewed-by: Balaji T K Signed-off-by: Samuel Ortiz --- drivers/mfd/twl-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 7d909cc8670d..960b5bed7f52 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -721,13 +721,13 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) } - if (twl_has_watchdog()) { + if (twl_has_watchdog() && twl_class_is_4030()) { child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_pwrbutton()) { + if (twl_has_pwrbutton() && twl_class_is_4030()) { child = add_child(1, "twl4030_pwrbutton", NULL, 0, true, pdata->irq_base + 8 + 0, 0); if (IS_ERR(child)) -- cgit v1.2.2 From fe891a008f3310be47786e87c158edebdb71e265 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:09 -0800 Subject: mfd-core: Unconditionally add mfd_cell to every platform_device Previously, one would set the mfd_cell's platform_data/data_size to point to the current mfd_cell in order to pass that information along to drivers. This causes the current mfd_cell to always be available to drivers. It also adds a wrapper function for fetching the mfd cell from a platform device, similar to what originally existed for mfd devices. Drivers who previously used platform_data for other purposes can still use it; the difference is that mfd_get_data() must be used to access it (and the pdata structure is no longer allocated in mfd_add_devices). Note that mfd_get_data is intentionally vague (in name) about where the data is stored; variable name changes can come later without having to touch brazillions of drivers. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index d83ad0f141af..21a39dc64ea0 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -39,12 +39,9 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; platform_set_drvdata(pdev, cell->driver_data); - if (cell->data_size) { - ret = platform_device_add_data(pdev, - cell->platform_data, cell->data_size); - if (ret) - goto fail_res; - } + ret = platform_device_add_data(pdev, cell, sizeof(*cell)); + if (ret) + goto fail_res; for (r = 0; r < cell->num_resources; r++) { res[r].name = cell->resources[r].name; -- cgit v1.2.2 From 6a54ac2149ab5b8972bb4f77bd42b43dbeabb56f Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:10 -0800 Subject: mfd: mfd_cell is now implicitly available to jz4740 drivers No need to explicitly set the cell's platform_data/data_size. Modify clients to use mfd_get_cell helper function instead of accessing platform_data directly. Signed-off-by: Andres Salomon Acked-by: Jean Delvare Signed-off-by: Samuel Ortiz --- drivers/hwmon/jz4740-hwmon.c | 2 +- drivers/mfd/jz4740-adc.c | 4 ---- drivers/power/jz4740-battery.c | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index 1c8b3d9e2051..40f106d95afe 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -112,7 +112,7 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev) return -ENOMEM; } - hwmon->cell = pdev->dev.platform_data; + hwmon->cell = mfd_get_cell(pdev); hwmon->irq = platform_get_irq(pdev, 0); if (hwmon->irq < 0) { diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 0cc59795f600..aa518b9beaf5 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -232,8 +232,6 @@ const struct mfd_cell jz4740_adc_cells[] = { .name = "jz4740-hwmon", .num_resources = ARRAY_SIZE(jz4740_hwmon_resources), .resources = jz4740_hwmon_resources, - .platform_data = (void *)&jz4740_adc_cells[0], - .data_size = sizeof(struct mfd_cell), .enable = jz4740_adc_cell_enable, .disable = jz4740_adc_cell_disable, @@ -243,8 +241,6 @@ const struct mfd_cell jz4740_adc_cells[] = { .name = "jz4740-battery", .num_resources = ARRAY_SIZE(jz4740_battery_resources), .resources = jz4740_battery_resources, - .platform_data = (void *)&jz4740_adc_cells[1], - .data_size = sizeof(struct mfd_cell), .enable = jz4740_adc_cell_enable, .disable = jz4740_adc_cell_disable, diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index 02414db6a94c..0938650a466c 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c @@ -258,7 +258,7 @@ static int __devinit jz_battery_probe(struct platform_device *pdev) return -ENOMEM; } - jz_battery->cell = pdev->dev.platform_data; + jz_battery->cell = mfd_get_cell(pdev); jz_battery->irq = platform_get_irq(pdev, 0); if (jz_battery->irq < 0) { -- cgit v1.2.2 From 0ce5fabe59d7c4f51b5ad51ed178ba92531ec04d Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:11 -0800 Subject: mfd: mfd_cell is now implicitly available to ab3550 driver No clients (in mainline kernel, I'm told that drivers exist in external trees that are planned for mainline inclusion) make use of this, nor do they make use of platform_data, so nothing really had to change here. The .data_size field is unused, so its usage gets removed. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3550-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index 681984df1c28..c8e555a9ee6c 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -1320,10 +1320,8 @@ static int __init ab3550_probe(struct i2c_client *client, goto exit_no_ops; /* Set up and register the platform devices. */ - for (i = 0; i < AB3550_NUM_DEVICES; i++) { + for (i = 0; i < AB3550_NUM_DEVICES; i++) ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i]; - ab3550_devs[i].data_size = ab3550_plf_data->dev_data_sz[i]; - } err = mfd_add_devices(&client->dev, 0, ab3550_devs, ARRAY_SIZE(ab3550_devs), NULL, -- cgit v1.2.2 From 5528e40f973ac427c857593ea0f636b6f65058b0 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:12 -0800 Subject: mfd: mfd_cell is now implicitly available to ab3100 drivers The cell's platform_data is now accessed with a helper function; change clients to use that, and remove the now-unused data_size. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3100-core.c | 4 +--- drivers/regulator/ab3100.c | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 1707d224232d..2dcab8643e71 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -949,10 +949,8 @@ static int __devinit ab3100_probe(struct i2c_client *client, goto exit_no_ops; /* Set up and register the platform devices. */ - for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { + for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) ab3100_devs[i].platform_data = ab3100_plf_data; - ab3100_devs[i].data_size = sizeof(struct ab3100_platform_data); - } err = mfd_add_devices(&client->dev, 0, ab3100_devs, ARRAY_SIZE(ab3100_devs), NULL, 0); diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index ed6feaf9398d..2dec589a8908 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -17,6 +17,7 @@ #include #include #include +#include /* LDO registers and some handy masking definitions for AB3100 */ #define AB3100_LDO_A 0x40 @@ -576,7 +577,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { static int __devinit ab3100_regulators_probe(struct platform_device *pdev) { - struct ab3100_platform_data *plfdata = pdev->dev.platform_data; + struct ab3100_platform_data *plfdata = mfd_get_data(pdev); int err = 0; u8 data; int i; -- cgit v1.2.2 From d24f36d352bb9fb72b6611bdca41adbb41cb13ba Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:13 -0800 Subject: mfd: mfd_cell is now implicitly available to asic3 drivers No need to explicitly set the cell's platform_data/data_size. Modify clients to use mfd_get_cell helper function instead of accessing platform_data directly. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 6 ------ drivers/mmc/host/tmio_mmc.c | 24 ++++++++++++------------ drivers/w1/masters/ds1wm.c | 2 +- 3 files changed, 13 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index c45e6305b26f..bd97639cd83a 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -810,9 +810,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, ds1wm_resources[0].start >>= asic->bus_shift; ds1wm_resources[0].end >>= asic->bus_shift; - asic3_cell_ds1wm.platform_data = &asic3_cell_ds1wm; - asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); - /* MMC */ asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + mem_sdio->start, 0x400 >> asic->bus_shift); @@ -824,9 +821,6 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, asic3_mmc_resources[0].start >>= asic->bus_shift; asic3_mmc_resources[0].end >>= asic->bus_shift; - asic3_cell_mmc.platform_data = &asic3_cell_mmc; - asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); - ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_ds1wm, 1, mem, asic->irq_base); if (ret < 0) diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index ac52eb65395e..67c9d0f595ef 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -303,7 +303,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) { - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; /* @@ -327,7 +327,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | @@ -669,7 +669,7 @@ out: static irqreturn_t tmio_mmc_irq(int irq, void *devid) { struct tmio_mmc_host *host = devid; - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; unsigned int ireg, irq_mask, status; unsigned int sdio_ireg, sdio_irq_mask, sdio_status; @@ -799,7 +799,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; dma_cookie_t cookie; int ret, i; @@ -869,7 +869,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; dma_cookie_t cookie; int ret, i; @@ -1063,7 +1063,7 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host) static int tmio_mmc_start_data(struct tmio_mmc_host *host, struct mmc_data *data) { - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", @@ -1169,7 +1169,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static int tmio_mmc_get_ro(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || @@ -1179,7 +1179,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) static int tmio_mmc_get_cd(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct mfd_cell *cell = host->pdev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(host->pdev); struct tmio_mmc_data *pdata = cell->driver_data; if (!pdata->get_cd) @@ -1199,7 +1199,7 @@ static const struct mmc_host_ops tmio_mmc_ops = { #ifdef CONFIG_PM static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) { - struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct mmc_host *mmc = platform_get_drvdata(dev); int ret; @@ -1214,7 +1214,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) static int tmio_mmc_resume(struct platform_device *dev) { - struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct mmc_host *mmc = platform_get_drvdata(dev); int ret = 0; @@ -1237,7 +1237,7 @@ out: static int __devinit tmio_mmc_probe(struct platform_device *dev) { - struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_mmc_data *pdata; struct resource *res_ctl; struct tmio_mmc_host *host; @@ -1352,7 +1352,7 @@ out: static int __devexit tmio_mmc_remove(struct platform_device *dev) { - struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct mmc_host *mmc = platform_get_drvdata(dev); platform_set_drvdata(dev, NULL); diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 6b85e7fefa43..94f55d80f9ac 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -336,7 +336,7 @@ static int ds1wm_probe(struct platform_device *pdev) if (!pdev) return -ENODEV; - cell = pdev->dev.platform_data; + cell = mfd_get_cell(pdev); if (!cell) return -ENODEV; -- cgit v1.2.2 From 07ae2a08deb141f22d7974615bd3006e8dce3883 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:14 -0800 Subject: mfd: mfd_cell is now implicitly available to htc-pasic3 drivers No need to explicitly set the cell's platform_data/data_size. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/htc-pasic3.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 7bc752272dc1..079d39665549 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -165,8 +165,6 @@ static int __init pasic3_probe(struct platform_device *pdev) ds1wm_pdata.clock_rate = pdata->clock_rate; /* the first 5 PASIC3 registers control the DS1WM */ ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; - ds1wm_cell.platform_data = &ds1wm_cell; - ds1wm_cell.data_size = sizeof(ds1wm_cell); ret = mfd_add_devices(&pdev->dev, pdev->id, &ds1wm_cell, 1, r, irq); if (ret < 0) @@ -175,8 +173,6 @@ static int __init pasic3_probe(struct platform_device *pdev) if (pdata && pdata->led_pdata) { led_cell.driver_data = pdata->led_pdata; - led_cell.platform_data = &led_cell; - led_cell.data_size = sizeof(ds1wm_cell); ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); if (ret < 0) dev_warn(dev, "failed to register LED device\n"); -- cgit v1.2.2 From e46dccff341068d8530610a822965794f70b998f Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:15 -0800 Subject: mfd: mfd_cell is now implicitly available to timberdale drivers The cell's platform_data is now accessed with a helper function; change clients to use that, and remove the now-unused data_size. Note that the mfd's platform_data is marked __devinitdata. This is still correct in all cases except for the timbgpio driver, whose remove hook has been changed to no longer reference the pdata. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/dma/timb_dma.c | 3 ++- drivers/gpio/timbgpio.c | 6 +++--- drivers/i2c/busses/i2c-ocores.c | 3 ++- drivers/i2c/busses/i2c-xiic.c | 3 ++- drivers/media/radio/radio-timb.c | 3 ++- drivers/media/video/timblogiw.c | 3 ++- drivers/mfd/timberdale.c | 27 --------------------------- drivers/net/ks8842.c | 3 ++- drivers/spi/xilinx_spi.c | 3 ++- 9 files changed, 17 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index f69f90a61873..d2c75feff7df 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -684,7 +685,7 @@ static irqreturn_t td_irq(int irq, void *devid) static int __devinit td_probe(struct platform_device *pdev) { - struct timb_dma_platform_data *pdata = pdev->dev.platform_data; + struct timb_dma_platform_data *pdata = mfd_get_data(pdev); struct timb_dma *td; struct resource *iomem; int irq; diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index 58c8f30352dd..ffcd815b8b8b 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -228,7 +229,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev) struct gpio_chip *gc; struct timbgpio *tgpio; struct resource *iomem; - struct timbgpio_platform_data *pdata = pdev->dev.platform_data; + struct timbgpio_platform_data *pdata = mfd_get_data(pdev); int irq = platform_get_irq(pdev, 0); if (!pdata || pdata->nr_pins > 32) { @@ -319,14 +320,13 @@ err_mem: static int __devexit timbgpio_remove(struct platform_device *pdev) { int err; - struct timbgpio_platform_data *pdata = pdev->dev.platform_data; struct timbgpio *tgpio = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); if (irq >= 0 && tgpio->irq_base > 0) { int i; - for (i = 0; i < pdata->nr_pins; i++) { + for (i = 0; i < tgpio->gpio.ngpio; i++) { set_irq_chip(tgpio->irq_base + i, NULL); set_irq_chip_data(tgpio->irq_base + i, NULL); } diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1b46a9d9f907..fee1a2613861 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -305,7 +306,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return -EIO; } - pdata = pdev->dev.platform_data; + pdata = mfd_get_data(pdev); if (pdata) { i2c->regstep = pdata->regstep; i2c->clock_khz = pdata->clock_khz; diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index a9c419e075a5..9fbd7e6fe32e 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -704,7 +705,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev) if (irq < 0) goto resource_missing; - pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data; + pdata = mfd_get_data(pdev); if (!pdata) return -EINVAL; diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index a185610b376b..1e3a8dd820a4 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -148,7 +149,7 @@ static const struct v4l2_file_operations timbradio_fops = { static int __devinit timbradio_probe(struct platform_device *pdev) { - struct timb_radio_platform_data *pdata = pdev->dev.platform_data; + struct timb_radio_platform_data *pdata = mfd_get_data(pdev); struct timbradio *tr; int err; diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c index fc611ebeb82c..84d4c7c83435 100644 --- a/drivers/media/video/timblogiw.c +++ b/drivers/media/video/timblogiw.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -790,7 +791,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev) { int err; struct timblogiw *lw = NULL; - struct timb_video_platform_data *pdata = pdev->dev.platform_data; + struct timb_video_platform_data *pdata = mfd_get_data(pdev); if (!pdata) { dev_err(&pdev->dev, "No platform data\n"); diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 6ad8a7f8d390..6353921c1729 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -385,7 +385,6 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, .platform_data = &timb_dma_platform_data, - .data_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -397,42 +396,36 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, .platform_data = &timberdale_xiic_platform_data, - .data_size = sizeof(timberdale_xiic_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, .platform_data = &timberdale_gpio_platform_data, - .data_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, .platform_data = &timberdale_video_platform_data, - .data_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, .platform_data = &timberdale_radio_platform_data, - .data_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .platform_data = &timberdale_xspi_platform_data, - .data_size = sizeof(timberdale_xspi_platform_data), }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, .platform_data = &timberdale_ks8842_platform_data, - .data_size = sizeof(timberdale_ks8842_platform_data) }, }; @@ -442,7 +435,6 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, .platform_data = &timb_dma_platform_data, - .data_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -459,14 +451,12 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, .platform_data = &timberdale_xiic_platform_data, - .data_size = sizeof(timberdale_xiic_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, .platform_data = &timberdale_gpio_platform_data, - .data_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-mlogicore", @@ -478,28 +468,24 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, .platform_data = &timberdale_video_platform_data, - .data_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, .platform_data = &timberdale_radio_platform_data, - .data_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .platform_data = &timberdale_xspi_platform_data, - .data_size = sizeof(timberdale_xspi_platform_data), }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, .platform_data = &timberdale_ks8842_platform_data, - .data_size = sizeof(timberdale_ks8842_platform_data) }, }; @@ -509,7 +495,6 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, .platform_data = &timb_dma_platform_data, - .data_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -521,35 +506,30 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, .platform_data = &timberdale_xiic_platform_data, - .data_size = sizeof(timberdale_xiic_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, .platform_data = &timberdale_gpio_platform_data, - .data_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, .platform_data = &timberdale_video_platform_data, - .data_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, .platform_data = &timberdale_radio_platform_data, - .data_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .platform_data = &timberdale_xspi_platform_data, - .data_size = sizeof(timberdale_xspi_platform_data), }, }; @@ -559,7 +539,6 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, .platform_data = &timb_dma_platform_data, - .data_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -571,42 +550,36 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .num_resources = ARRAY_SIZE(timberdale_ocores_resources), .resources = timberdale_ocores_resources, .platform_data = &timberdale_ocores_platform_data, - .data_size = sizeof(timberdale_ocores_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, .platform_data = &timberdale_gpio_platform_data, - .data_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, .platform_data = &timberdale_video_platform_data, - .data_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, .platform_data = &timberdale_radio_platform_data, - .data_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, .platform_data = &timberdale_xspi_platform_data, - .data_size = sizeof(timberdale_xspi_platform_data), }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, .platform_data = &timberdale_ks8842_platform_data, - .data_size = sizeof(timberdale_ks8842_platform_data) }, }; diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index 928b2b83cef5..efd44afeae83 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1145,7 +1146,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev) struct resource *iomem; struct net_device *netdev; struct ks8842_adapter *adapter; - struct ks8842_platform_data *pdata = pdev->dev.platform_data; + struct ks8842_platform_data *pdata = mfd_get_data(pdev); u16 id; unsigned i; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 4d2c75df886c..c69c6f2c2c5c 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -470,7 +471,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev) struct spi_master *master; u8 i; - pdata = dev->dev.platform_data; + pdata = mfd_get_data(dev); if (pdata) { num_cs = pdata->num_chipselect; little_endian = pdata->little_endian; -- cgit v1.2.2 From a23090ada44889322fe39142fb58ebc5794f709c Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:16 -0800 Subject: mfd: mfd_cell is now implicitly available to t7166xb drivers No need to explicitly set the cell's platform_data/data_size. Modify clients to use mfd_get_cell helper function instead of accessing platform_data directly. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/t7l66xb.c | 9 --------- drivers/mtd/nand/tmio_nand.c | 10 +++++----- 2 files changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 9caeb4ac6ea6..b9c1e4c630a8 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -384,15 +384,6 @@ static int t7l66xb_probe(struct platform_device *dev) t7l66xb_attach_irq(dev); t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; - t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = - &t7l66xb_cells[T7L66XB_CELL_NAND]; - t7l66xb_cells[T7L66XB_CELL_NAND].data_size = - sizeof(t7l66xb_cells[T7L66XB_CELL_NAND]); - - t7l66xb_cells[T7L66XB_CELL_MMC].platform_data = - &t7l66xb_cells[T7L66XB_CELL_MMC]; - t7l66xb_cells[T7L66XB_CELL_MMC].data_size = - sizeof(t7l66xb_cells[T7L66XB_CELL_MMC]); ret = mfd_add_devices(&dev->dev, dev->id, t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 3041d1f7ae3f..5bf63e31e5d0 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -319,7 +319,7 @@ static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) { - struct mfd_cell *cell = dev_get_platdata(&dev->dev); + struct mfd_cell *cell = mfd_get_cell(dev); int ret; if (cell->enable) { @@ -363,7 +363,7 @@ static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) { - struct mfd_cell *cell = dev_get_platdata(&dev->dev); + struct mfd_cell *cell = mfd_get_cell(dev); tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE); if (cell->disable) @@ -372,7 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) static int tmio_probe(struct platform_device *dev) { - struct mfd_cell *cell = dev_get_platdata(&dev->dev); + struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_nand_data *data = cell->driver_data; struct resource *fcr = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -516,7 +516,7 @@ static int tmio_remove(struct platform_device *dev) #ifdef CONFIG_PM static int tmio_suspend(struct platform_device *dev, pm_message_t state) { - struct mfd_cell *cell = dev_get_platdata(&dev->dev); + struct mfd_cell *cell = mfd_get_cell(dev); if (cell->suspend) cell->suspend(dev); @@ -527,7 +527,7 @@ static int tmio_suspend(struct platform_device *dev, pm_message_t state) static int tmio_resume(struct platform_device *dev) { - struct mfd_cell *cell = dev_get_platdata(&dev->dev); + struct mfd_cell *cell = mfd_get_cell(dev); /* FIXME - is this required or merely another attack of the broken * SHARP platform? Looks suspicious. -- cgit v1.2.2 From 15de7a41d30cfe8090efdc5fd6a92ed7a2d80ce7 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:17 -0800 Subject: mfd: mfd_cell is now implicitly available to wl1273 drivers The cell's platform_data is now accessed with a helper function; change clients to use that, and remove the now-unused data_size. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/media/radio/radio-wl1273.c | 2 +- drivers/mfd/wl1273-core.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 7ecc8e657663..4698eb00b59f 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -2138,7 +2138,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev) static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev) { - struct wl1273_core **core = pdev->dev.platform_data; + struct wl1273_core **core = mfd_get_data(pdev); struct wl1273_device *radio; struct v4l2_ctrl *ctrl; int r = 0; diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index 6bb51364dcb4..b4823bf9523b 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -79,7 +79,6 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, cell = &core->cells[children]; cell->name = "wl1273_fm_radio"; cell->platform_data = &core; - cell->data_size = sizeof(core); children++; if (pdata->children & WL1273_CODEC_CHILD) { @@ -88,7 +87,6 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, dev_dbg(&client->dev, "%s: Have codec.\n", __func__); cell->name = "wl1273-codec"; cell->platform_data = &core; - cell->data_size = sizeof(core); children++; } -- cgit v1.2.2 From 410b09172787a930753fa5ed904d820e3a9d7a1f Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:18 -0800 Subject: mfd: mfd_cell is now implicitly available to sh_mobile_sdhi drivers No need to explicitly set the cell's platform_data/data_size. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/sh_mobile_sdhi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index 0a7df44a93c0..b511e744e526 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c @@ -147,8 +147,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); priv->cell_mmc.driver_data = mmc_data; - priv->cell_mmc.platform_data = &priv->cell_mmc; - priv->cell_mmc.data_size = sizeof(priv->cell_mmc); platform_set_drvdata(pdev, priv); -- cgit v1.2.2 From 7d76ac15ad1a8d8b1a7b7b4f6be7a9d8dfd225bf Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:19 -0800 Subject: mfd: mfd_cell is now implicitly available to tc6393xb drivers No need to explicitly set the cell's platform_data/data_size. Modify clients to use mfd_get_cell helper function instead of accessing platform_data directly. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/tc6393xb.c | 19 ------------------- drivers/usb/host/ohci-tmio.c | 8 ++++---- drivers/video/tmiofb.c | 20 +++++++++----------- 3 files changed, 13 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 9a238633a54d..a71ff5c88b59 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -694,26 +694,7 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) } tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; - tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = - &tc6393xb_cells[TC6393XB_CELL_NAND]; - tc6393xb_cells[TC6393XB_CELL_NAND].data_size = - sizeof(tc6393xb_cells[TC6393XB_CELL_NAND]); - - tc6393xb_cells[TC6393XB_CELL_MMC].platform_data = - &tc6393xb_cells[TC6393XB_CELL_MMC]; - tc6393xb_cells[TC6393XB_CELL_MMC].data_size = - sizeof(tc6393xb_cells[TC6393XB_CELL_MMC]); - - tc6393xb_cells[TC6393XB_CELL_OHCI].platform_data = - &tc6393xb_cells[TC6393XB_CELL_OHCI]; - tc6393xb_cells[TC6393XB_CELL_OHCI].data_size = - sizeof(tc6393xb_cells[TC6393XB_CELL_OHCI]); - tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data; - tc6393xb_cells[TC6393XB_CELL_FB].platform_data = - &tc6393xb_cells[TC6393XB_CELL_FB]; - tc6393xb_cells[TC6393XB_CELL_FB].data_size = - sizeof(tc6393xb_cells[TC6393XB_CELL_FB]); ret = mfd_add_devices(&dev->dev, dev->id, tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index 8dabe8e31d8c..eeed16461e0d 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -185,7 +185,7 @@ static struct platform_driver ohci_hcd_tmio_driver; static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0); struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1); struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2); @@ -274,7 +274,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct tmio_hcd *tmio = hcd_to_tmio(hcd); - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); usb_remove_hcd(hcd); tmio_stop_hc(dev); @@ -293,7 +293,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev) #ifdef CONFIG_PM static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct tmio_hcd *tmio = hcd_to_tmio(hcd); @@ -326,7 +326,7 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct tmio_hcd *tmio = hcd_to_tmio(hcd); diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index dfef88c803d4..630288212656 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c @@ -250,7 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info) */ static int tmiofb_hw_stop(struct platform_device *dev) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_fb_data *data = cell->driver_data; struct fb_info *info = platform_get_drvdata(dev); struct tmiofb_par *par = info->par; @@ -268,7 +268,7 @@ static int tmiofb_hw_stop(struct platform_device *dev) */ static int tmiofb_hw_init(struct platform_device *dev) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct fb_info *info = platform_get_drvdata(dev); struct tmiofb_par *par = info->par; const struct resource *nlcr = &cell->resources[0]; @@ -312,7 +312,7 @@ static int tmiofb_hw_init(struct platform_device *dev) */ static void tmiofb_hw_mode(struct platform_device *dev) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_fb_data *data = cell->driver_data; struct fb_info *info = platform_get_drvdata(dev); struct fb_videomode *mode = info->mode; @@ -559,8 +559,7 @@ static int tmiofb_ioctl(struct fb_info *fbi, static struct fb_videomode * tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var) { - struct mfd_cell *cell = - info->device->platform_data; + struct mfd_cell *cell = mfd_get_cell(to_platform_device(info->device)); struct tmio_fb_data *data = cell->driver_data; struct fb_videomode *best = NULL; int i; @@ -581,8 +580,7 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct fb_videomode *mode; - struct mfd_cell *cell = - info->device->platform_data; + struct mfd_cell *cell = mfd_get_cell(to_platform_device(info->device)); struct tmio_fb_data *data = cell->driver_data; mode = tmiofb_find_mode(info, var); @@ -683,7 +681,7 @@ static struct fb_ops tmiofb_ops = { static int __devinit tmiofb_probe(struct platform_device *dev) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_fb_data *data = cell->driver_data; struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1); struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -811,7 +809,7 @@ err_ioremap_ccr: static int __devexit tmiofb_remove(struct platform_device *dev) { - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); struct fb_info *info = platform_get_drvdata(dev); int irq = platform_get_irq(dev, 0); struct tmiofb_par *par; @@ -941,7 +939,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) #ifdef CONFIG_FB_TMIO_ACCELL struct tmiofb_par *par = info->par; #endif - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); int retval = 0; console_lock(); @@ -973,7 +971,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) static int tmiofb_resume(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); - struct mfd_cell *cell = dev->dev.platform_data; + struct mfd_cell *cell = mfd_get_cell(dev); int retval = 0; console_lock(); -- cgit v1.2.2 From 0638d56fbb6cf8367fcf01a1febf6a191b0e0704 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:20 -0800 Subject: mfd: mfd_cell is now implicitly available to twl4030 drivers The cell's platform_data is now accessed with a helper function; change clients to use that, and remove the now-unused data_size. Signed-off-by: Andres Salomon Acked-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/input/misc/twl4030-vibra.c | 3 ++- drivers/mfd/twl4030-codec.c | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 014dd4ad0d4f..6a11694e3fc7 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -196,7 +197,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, static int __devinit twl4030_vibra_probe(struct platform_device *pdev) { - struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data; + struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev); struct vibra_info *info; int ret; diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c index 9a4b196d6deb..0f5742655b46 100644 --- a/drivers/mfd/twl4030-codec.c +++ b/drivers/mfd/twl4030-codec.c @@ -209,14 +209,12 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) cell = &codec->cells[childs]; cell->name = "twl4030-codec"; cell->platform_data = pdata->audio; - cell->data_size = sizeof(*pdata->audio); childs++; } if (pdata->vibra) { cell = &codec->cells[childs]; cell->name = "twl4030-vibra"; cell->platform_data = pdata->vibra; - cell->data_size = sizeof(*pdata->vibra); childs++; } -- cgit v1.2.2 From 6a3521ad3db45066d4ca38652dd0b57ea2fd0a30 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:21 -0800 Subject: mfd: mfd_cell is now implicitly available to tc6387xb drivers No need to explicitly set the cell's platform_data/data_size. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/tc6387xb.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 6315f63f017d..6bf177536870 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -190,11 +190,6 @@ static int __devinit tc6387xb_probe(struct platform_device *dev) printk(KERN_INFO "Toshiba tc6387xb initialised\n"); - tc6387xb_cells[TC6387XB_CELL_MMC].platform_data = - &tc6387xb_cells[TC6387XB_CELL_MMC]; - tc6387xb_cells[TC6387XB_CELL_MMC].data_size = - sizeof(tc6387xb_cells[TC6387XB_CELL_MMC]); - ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, ARRAY_SIZE(tc6387xb_cells), iomem, irq); -- cgit v1.2.2 From 8615e4cba1d3a0f15b9a4da9f32f8fbc3488fa54 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:22 -0800 Subject: mfd: mfd_cell is now implicitly available to janz drivers The cell's platform_data is now accessed with a helper function; change clients to use that, and remove the now-unused data_size. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/gpio/janz-ttl.c | 3 ++- drivers/mfd/janz-cmodio.c | 1 - drivers/net/can/janz-ican3.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/janz-ttl.c b/drivers/gpio/janz-ttl.c index 813ac077e5d7..2514fb075f4a 100644 --- a/drivers/gpio/janz-ttl.c +++ b/drivers/gpio/janz-ttl.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -149,7 +150,7 @@ static int __devinit ttl_probe(struct platform_device *pdev) struct resource *res; int ret; - pdata = pdev->dev.platform_data; + pdata = mfd_get_data(pdev); if (!pdata) { dev_err(dev, "no platform data\n"); ret = -ENXIO; diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 36a166bcdb08..58de1e28788e 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -87,7 +87,6 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv, /* Add platform data */ pdata->modno = modno; cell->platform_data = pdata; - cell->data_size = sizeof(*pdata); /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */ res->flags = IORESOURCE_MEM; diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 366f5cc050ae..102b16c6cc97 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -1643,7 +1644,7 @@ static int __devinit ican3_probe(struct platform_device *pdev) struct device *dev; int ret; - pdata = pdev->dev.platform_data; + pdata = mfd_get_data(pdev); if (!pdata) return -ENXIO; -- cgit v1.2.2 From 4ec1b54c4d082d4bad19b55ca709da7e7138d542 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:23 -0800 Subject: mfd: mfd_cell is now implicitly available to mc13xxx drivers The cell's platform_data is now accessed with a helper function; change clients to use that, and remove the now-unused data_size. Note that mfd-core no longer makes a copy of platform_data, but the mc13xxx-core driver creates the pdata structures on the stack. In order to get around that, the various ARM mach types that set the pdata have been changed to hold the variable in static (global) memory. Also note that __initdata references in aforementioned pdata structs have been dropped. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/leds/leds-mc13783.c | 7 ++++--- drivers/mfd/mc13xxx-core.c | 18 +++++------------- drivers/regulator/mc13783-regulator.c | 7 +++---- drivers/regulator/mc13892-regulator.c | 7 +++---- 4 files changed, 15 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index f05bb08d0f09..06a5bb484707 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -22,6 +22,7 @@ #include #include #include +#include #include struct mc13783_led { @@ -183,7 +184,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current) static int __devinit mc13783_leds_prepare(struct platform_device *pdev) { - struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev); struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent); int ret = 0; int reg = 0; @@ -264,7 +265,7 @@ out: static int __devinit mc13783_led_probe(struct platform_device *pdev) { - struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev); struct mc13783_led_platform_data *led_cur; struct mc13783_led *led, *led_dat; int ret, i; @@ -351,7 +352,7 @@ err_free: static int __devexit mc13783_led_remove(struct platform_device *pdev) { - struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev); struct mc13783_led *led = platform_get_drvdata(pdev); struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent); int i; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index b9fcaf0004da..30807d3a6539 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -683,14 +683,13 @@ out: EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, - const char *format, void *pdata, size_t pdata_size) + const char *format, void *pdata) { char buf[30]; const char *name = mc13xxx_get_chipname(mc13xxx); struct mfd_cell cell = { .platform_data = pdata, - .data_size = pdata_size, }; /* there is no asnprintf in the kernel :-( */ @@ -706,7 +705,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) { - return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); + return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL); } static int mc13xxx_probe(struct spi_device *spi) @@ -764,13 +763,8 @@ err_revision: mc13xxx_add_subdevice(mc13xxx, "%s-codec"); if (pdata->flags & MC13XXX_USE_REGULATOR) { - struct mc13xxx_regulator_platform_data regulator_pdata = { - .num_regulators = pdata->num_regulators, - .regulators = pdata->regulators, - }; - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", - ®ulator_pdata, sizeof(regulator_pdata)); + &pdata->regulators); } if (pdata->flags & MC13XXX_USE_RTC) @@ -779,10 +773,8 @@ err_revision: if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) mc13xxx_add_subdevice(mc13xxx, "%s-ts"); - if (pdata->flags & MC13XXX_USE_LED) { - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", - pdata->leds, sizeof(*pdata->leds)); - } + if (pdata->flags & MC13XXX_USE_LED) + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds); return 0; } diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 3e5d0c3b4e53..23249cb0a8bd 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -336,8 +337,7 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); - struct mc13783_regulator_platform_data *pdata = - dev_get_platdata(&pdev->dev); + struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev); struct mc13783_regulator_init_data *init_data; int i, ret; @@ -381,8 +381,7 @@ err: static int __devexit mc13783_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - struct mc13783_regulator_platform_data *pdata = - dev_get_platdata(&pdev->dev); + struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev); int i; platform_set_drvdata(pdev, NULL); diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 1b8f7398a4a8..6f15168e5ed4 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -520,8 +521,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); - struct mc13xxx_regulator_platform_data *pdata = - dev_get_platdata(&pdev->dev); + struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev); struct mc13xxx_regulator_init_data *init_data; int i, ret; u32 val; @@ -595,8 +595,7 @@ err_free: static int __devexit mc13892_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - struct mc13xxx_regulator_platform_data *pdata = - dev_get_platdata(&pdev->dev); + struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev); int i; platform_set_drvdata(pdev, NULL); -- cgit v1.2.2 From 65e523595a31813c0f20ffd249792c60e253438e Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:25 -0800 Subject: mfd: Rename platform_data field of mfd_cell to mfd_data Rename the platform_data variable to imply a distinction between common platform_data driver usage (typically accessed via pdev->dev.platform_data) and the way MFD passes data down to clients (using a wrapper named mfd_get_data). All clients have already been changed to use the wrapper function, so this can be a quick single-commit change that only touches things in drivers/mfd. Signed-off-by: Andres Salomon Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3100-core.c | 2 +- drivers/mfd/ab3550-core.c | 2 +- drivers/mfd/janz-cmodio.c | 2 +- drivers/mfd/mc13xxx-core.c | 2 +- drivers/mfd/timberdale.c | 54 ++++++++++++++++++++++----------------------- drivers/mfd/twl4030-codec.c | 4 ++-- drivers/mfd/wl1273-core.c | 4 ++-- 7 files changed, 35 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 2dcab8643e71..a751927047ac 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -950,7 +950,7 @@ static int __devinit ab3100_probe(struct i2c_client *client, /* Set up and register the platform devices. */ for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) - ab3100_devs[i].platform_data = ab3100_plf_data; + ab3100_devs[i].mfd_data = ab3100_plf_data; err = mfd_add_devices(&client->dev, 0, ab3100_devs, ARRAY_SIZE(ab3100_devs), NULL, 0); diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index c8e555a9ee6c..c12d04285226 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -1321,7 +1321,7 @@ static int __init ab3550_probe(struct i2c_client *client, /* Set up and register the platform devices. */ for (i = 0; i < AB3550_NUM_DEVICES; i++) - ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i]; + ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i]; err = mfd_add_devices(&client->dev, 0, ab3550_devs, ARRAY_SIZE(ab3550_devs), NULL, diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 58de1e28788e..fc4191137e90 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -86,7 +86,7 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv, /* Add platform data */ pdata->modno = modno; - cell->platform_data = pdata; + cell->mfd_data = pdata; /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */ res->flags = IORESOURCE_MEM; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 30807d3a6539..97a3b400ed4f 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -689,7 +689,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, const char *name = mc13xxx_get_chipname(mc13xxx); struct mfd_cell cell = { - .platform_data = pdata, + .mfd_data = pdata, }; /* there is no asnprintf in the kernel :-( */ diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 6353921c1729..94c6c8afad12 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -384,7 +384,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .platform_data = &timb_dma_platform_data, + .mfd_data = &timb_dma_platform_data, }, { .name = "timb-uart", @@ -395,37 +395,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .name = "xiic-i2c", .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, - .platform_data = &timberdale_xiic_platform_data, + .mfd_data = &timberdale_xiic_platform_data, }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .platform_data = &timberdale_gpio_platform_data, + .mfd_data = &timberdale_gpio_platform_data, }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .platform_data = &timberdale_video_platform_data, + .mfd_data = &timberdale_video_platform_data, }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .platform_data = &timberdale_radio_platform_data, + .mfd_data = &timberdale_radio_platform_data, }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .platform_data = &timberdale_xspi_platform_data, + .mfd_data = &timberdale_xspi_platform_data, }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, - .platform_data = &timberdale_ks8842_platform_data, + .mfd_data = &timberdale_ks8842_platform_data, }, }; @@ -434,7 +434,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .platform_data = &timb_dma_platform_data, + .mfd_data = &timb_dma_platform_data, }, { .name = "timb-uart", @@ -450,13 +450,13 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .name = "xiic-i2c", .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, - .platform_data = &timberdale_xiic_platform_data, + .mfd_data = &timberdale_xiic_platform_data, }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .platform_data = &timberdale_gpio_platform_data, + .mfd_data = &timberdale_gpio_platform_data, }, { .name = "timb-mlogicore", @@ -467,25 +467,25 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .platform_data = &timberdale_video_platform_data, + .mfd_data = &timberdale_video_platform_data, }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .platform_data = &timberdale_radio_platform_data, + .mfd_data = &timberdale_radio_platform_data, }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .platform_data = &timberdale_xspi_platform_data, + .mfd_data = &timberdale_xspi_platform_data, }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, - .platform_data = &timberdale_ks8842_platform_data, + .mfd_data = &timberdale_ks8842_platform_data, }, }; @@ -494,7 +494,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .platform_data = &timb_dma_platform_data, + .mfd_data = &timb_dma_platform_data, }, { .name = "timb-uart", @@ -505,31 +505,31 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .name = "xiic-i2c", .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, - .platform_data = &timberdale_xiic_platform_data, + .mfd_data = &timberdale_xiic_platform_data, }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .platform_data = &timberdale_gpio_platform_data, + .mfd_data = &timberdale_gpio_platform_data, }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .platform_data = &timberdale_video_platform_data, + .mfd_data = &timberdale_video_platform_data, }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .platform_data = &timberdale_radio_platform_data, + .mfd_data = &timberdale_radio_platform_data, }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .platform_data = &timberdale_xspi_platform_data, + .mfd_data = &timberdale_xspi_platform_data, }, }; @@ -538,7 +538,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .platform_data = &timb_dma_platform_data, + .mfd_data = &timb_dma_platform_data, }, { .name = "timb-uart", @@ -549,37 +549,37 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .name = "ocores-i2c", .num_resources = ARRAY_SIZE(timberdale_ocores_resources), .resources = timberdale_ocores_resources, - .platform_data = &timberdale_ocores_platform_data, + .mfd_data = &timberdale_ocores_platform_data, }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .platform_data = &timberdale_gpio_platform_data, + .mfd_data = &timberdale_gpio_platform_data, }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .platform_data = &timberdale_video_platform_data, + .mfd_data = &timberdale_video_platform_data, }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .platform_data = &timberdale_radio_platform_data, + .mfd_data = &timberdale_radio_platform_data, }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .platform_data = &timberdale_xspi_platform_data, + .mfd_data = &timberdale_xspi_platform_data, }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, - .platform_data = &timberdale_ks8842_platform_data, + .mfd_data = &timberdale_ks8842_platform_data, }, }; diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c index 0f5742655b46..c02fded316c9 100644 --- a/drivers/mfd/twl4030-codec.c +++ b/drivers/mfd/twl4030-codec.c @@ -208,13 +208,13 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) if (pdata->audio) { cell = &codec->cells[childs]; cell->name = "twl4030-codec"; - cell->platform_data = pdata->audio; + cell->mfd_data = pdata->audio; childs++; } if (pdata->vibra) { cell = &codec->cells[childs]; cell->name = "twl4030-vibra"; - cell->platform_data = pdata->vibra; + cell->mfd_data = pdata->vibra; childs++; } diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index b4823bf9523b..529d65ba5353 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -78,7 +78,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, cell = &core->cells[children]; cell->name = "wl1273_fm_radio"; - cell->platform_data = &core; + cell->mfd_data = &core; children++; if (pdata->children & WL1273_CODEC_CHILD) { @@ -86,7 +86,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, dev_dbg(&client->dev, "%s: Have codec.\n", __func__); cell->name = "wl1273-codec"; - cell->platform_data = &core; + cell->mfd_data = &core; children++; } -- cgit v1.2.2 From d57763370e1e12dd72e5a7bc6d6a7644e0003593 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 28 Feb 2011 17:24:03 +0100 Subject: asoc: davinci_voicecodec: use mfd_data instead of driver_data Use mfd_data for passing information from mfd drivers to soc clients. The mfd_cell's driver_data field is being phased out. Clients that were using driver_data now access .mfd_data via mfd_get_data(). Signed-off-by: Andres Salomon Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/davinci_voicecodec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index fdd8a1b8bc67..414783b04849 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -119,12 +119,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev) /* Voice codec interface client */ cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; cell->name = "davinci-vcif"; - cell->driver_data = davinci_vc; + cell->mfd_data = davinci_vc; /* Voice codec CQ93VC client */ cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; cell->name = "cq93vc-codec"; - cell->driver_data = davinci_vc; + cell->mfd_data = davinci_vc; ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, DAVINCI_VC_CELLS, NULL, 0); -- cgit v1.2.2 From dab1547a011b221308b6e991405677c78e1a8956 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:27 -0800 Subject: asoc: wm8400-codec: Use mfd_data instead of driver_data Use mfd_data for passing information from mfd drivers to soc clients. The mfd_cell's driver_data field is being phased out. Clients that were using driver_data now access .mfd_data via mfd_get_data(). Signed-off-by: Andres Salomon Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8400-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 1bfef4846b07..3a6e78cb0384 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -245,7 +245,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400) { struct mfd_cell cell = { .name = "wm8400-codec", - .driver_data = wm8400, + .mfd_data = wm8400, }; return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); -- cgit v1.2.2 From fcd67979d3808afbe357048d928470ef9b37cd4b Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:28 -0800 Subject: w1: Use mfd_data instead of driver_data for dsw1wm.c Use mfd_data for passing information from mfd drivers to mfd clients. The mfd_cell's driver_data field is being phased out. Clients that were using driver_data now access .mfd_data via mfd_get_data(). This changes ds1wm only; mfd drivers with other cells are not modified, with the exception of led_cell. The led_cell.driver_data line is dropped from htc-pasic3.c in this patch as well. It's not used in mainline (there's no leds-pasic3 platform driver), so it should be safe to take care of that here. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 2 +- drivers/mfd/htc-pasic3.c | 3 +-- drivers/w1/masters/ds1wm.c | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index bd97639cd83a..388938ce3c92 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -682,7 +682,7 @@ static struct mfd_cell asic3_cell_ds1wm = { .name = "ds1wm", .enable = ds1wm_enable, .disable = ds1wm_disable, - .driver_data = &ds1wm_pdata, + .mfd_data = &ds1wm_pdata, .num_resources = ARRAY_SIZE(ds1wm_resources), .resources = ds1wm_resources, }; diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 079d39665549..fb9770b39a32 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -117,7 +117,7 @@ static struct mfd_cell ds1wm_cell __initdata = { .name = "ds1wm", .enable = ds1wm_enable, .disable = ds1wm_disable, - .driver_data = &ds1wm_pdata, + .mfd_data = &ds1wm_pdata, .num_resources = 2, .resources = ds1wm_resources, }; @@ -172,7 +172,6 @@ static int __init pasic3_probe(struct platform_device *pdev) } if (pdata && pdata->led_pdata) { - led_cell.driver_data = pdata->led_pdata; ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); if (ret < 0) dev_warn(dev, "failed to register LED device\n"); diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 94f55d80f9ac..22fc726feb9b 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -216,7 +216,7 @@ static int ds1wm_find_divisor(int gclk) static void ds1wm_up(struct ds1wm_data *ds1wm_data) { int divisor; - struct ds1wm_driver_data *plat = ds1wm_data->cell->driver_data; + struct ds1wm_driver_data *plat = mfd_get_data(ds1wm_data->pdev); if (ds1wm_data->cell->enable) ds1wm_data->cell->enable(ds1wm_data->pdev); @@ -356,7 +356,7 @@ static int ds1wm_probe(struct platform_device *pdev) ret = -ENOMEM; goto err0; } - plat = cell->driver_data; + plat = mfd_get_data(pdev); /* calculate bus shift from mem resource */ ds1wm_data->bus_shift = resource_size(res) >> 3; -- cgit v1.2.2 From 4f95bf404870cccb08ff6d59e1986d43aee5efb6 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:29 -0800 Subject: mmc: Use mfd_data instead of driver_data for tmio-mmc Use mfd_data for passing information from mfd drivers to mfd clients. The mfd_cell's driver_data field is being phased out. Clients that were using driver_data now access .mfd_data via mfd_get_data(). This changes tmio-mmc only; mfd drivers with other cells are not modified. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 2 +- drivers/mfd/sh_mobile_sdhi.c | 2 +- drivers/mfd/t7l66xb.c | 2 +- drivers/mfd/tc6387xb.c | 2 +- drivers/mfd/tc6393xb.c | 2 +- drivers/mmc/host/tmio_mmc.c | 26 +++++++++----------------- 6 files changed, 14 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 388938ce3c92..0241f08fc00d 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -783,7 +783,7 @@ static struct mfd_cell asic3_cell_mmc = { .name = "tmio-mmc", .enable = asic3_mmc_enable, .disable = asic3_mmc_disable, - .driver_data = &asic3_mmc_data, + .mfd_data = &asic3_mmc_data, .num_resources = ARRAY_SIZE(asic3_mmc_resources), .resources = asic3_mmc_resources, }; diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c index b511e744e526..53a63024bf11 100644 --- a/drivers/mfd/sh_mobile_sdhi.c +++ b/drivers/mfd/sh_mobile_sdhi.c @@ -146,7 +146,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) } memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); - priv->cell_mmc.driver_data = mmc_data; + priv->cell_mmc.mfd_data = mmc_data; platform_set_drvdata(pdev, priv); diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index b9c1e4c630a8..3c9e38940dbe 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -170,7 +170,7 @@ static struct mfd_cell t7l66xb_cells[] = { .name = "tmio-mmc", .enable = t7l66xb_mmc_enable, .disable = t7l66xb_mmc_disable, - .driver_data = &t7166xb_mmc_data, + .mfd_data = &t7166xb_mmc_data, .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), .resources = t7l66xb_mmc_resources, }, diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 6bf177536870..b006f7cee952 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -131,7 +131,7 @@ static struct mfd_cell tc6387xb_cells[] = { .name = "tmio-mmc", .enable = tc6387xb_mmc_enable, .disable = tc6387xb_mmc_disable, - .driver_data = &tc6387xb_mmc_data, + .mfd_data = &tc6387xb_mmc_data, .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), .resources = tc6387xb_mmc_resources, }, diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index a71ff5c88b59..7f7b9fadea5d 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -393,7 +393,7 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { .name = "tmio-mmc", .enable = tc6393xb_mmc_enable, .resume = tc6393xb_mmc_resume, - .driver_data = &tc6393xb_mmc_data, + .mfd_data = &tc6393xb_mmc_data, .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), .resources = tc6393xb_mmc_resources, }, diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 67c9d0f595ef..f8cb06b8ed65 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -303,8 +303,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) { - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); /* * Testing on sh-mobile showed that SDIO IRQs are unmasked when @@ -327,8 +326,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); @@ -669,8 +667,7 @@ out: static irqreturn_t tmio_mmc_irq(int irq, void *devid) { struct tmio_mmc_host *host = devid; - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); unsigned int ireg, irq_mask, status; unsigned int sdio_ireg, sdio_irq_mask, sdio_status; @@ -799,8 +796,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_rx; - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; @@ -869,8 +865,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) struct scatterlist *sg = host->sg_ptr, *sg_tmp; struct dma_async_tx_descriptor *desc = NULL; struct dma_chan *chan = host->chan_tx; - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); dma_cookie_t cookie; int ret, i; bool aligned = true, multiple = true; @@ -1063,8 +1058,7 @@ static void tmio_mmc_release_dma(struct tmio_mmc_host *host) static int tmio_mmc_start_data(struct tmio_mmc_host *host, struct mmc_data *data) { - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", data->blksz, data->blocks); @@ -1169,8 +1163,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static int tmio_mmc_get_ro(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1; @@ -1179,8 +1172,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) static int tmio_mmc_get_cd(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct mfd_cell *cell = mfd_get_cell(host->pdev); - struct tmio_mmc_data *pdata = cell->driver_data; + struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); if (!pdata->get_cd) return -ENOSYS; @@ -1252,7 +1244,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *dev) if (!res_ctl) goto out; - pdata = cell->driver_data; + pdata = mfd_get_data(dev); if (!pdata || !pdata->hclk) goto out; -- cgit v1.2.2 From d9d01f4b2697b410625fce288bd1196927994093 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:30 -0800 Subject: mtd: Use mfd_data instead of driver_data for tmio_nand Use mfd_data for passing information from mfd drivers to mfd clients. The mfd_cell's driver_data field is being phased out. Clients that were using driver_data now access .mfd_data via mfd_get_data(). This changes tmio-nand only; mfd drivers with other cells are not modified. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/t7l66xb.c | 2 +- drivers/mfd/tc6393xb.c | 2 +- drivers/mtd/nand/tmio_nand.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 3c9e38940dbe..af57fc706a4c 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -383,7 +383,7 @@ static int t7l66xb_probe(struct platform_device *dev) t7l66xb_attach_irq(dev); - t7l66xb_cells[T7L66XB_CELL_NAND].driver_data = pdata->nand_data; + t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data; ret = mfd_add_devices(&dev->dev, dev->id, t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 7f7b9fadea5d..ecb045b5dd5d 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -693,7 +693,7 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) goto err_setup; } - tc6393xb_cells[TC6393XB_CELL_NAND].driver_data = tcpd->nand_data; + tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data; tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data; ret = mfd_add_devices(&dev->dev, dev->id, diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 5bf63e31e5d0..2383b8f2306b 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -372,8 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) static int tmio_probe(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); - struct tmio_nand_data *data = cell->driver_data; + struct tmio_nand_data *data = mfd_get_data(dev); struct resource *fcr = platform_get_resource(dev, IORESOURCE_MEM, 0); struct resource *ccr = platform_get_resource(dev, -- cgit v1.2.2 From 6d90bdde4b7b8e0f403bc3641fcddea733bddf77 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:31 -0800 Subject: fb: Use mfd_data instead of driver_data for tmio-fb Use mfd_data for passing information from mfd drivers to mfd clients. The mfd_cell's driver_data field is being phased out. Clients that were using driver_data now access .mfd_data via mfd_get_data(). This changes tmio-fb only; mfd drivers with other cells are not modified. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/tc6393xb.c | 2 +- drivers/video/tmiofb.c | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index ecb045b5dd5d..3d62ded86a8f 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -694,7 +694,7 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) } tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data; - tc6393xb_cells[TC6393XB_CELL_FB].driver_data = tcpd->fb_data; + tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data; ret = mfd_add_devices(&dev->dev, dev->id, tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index 630288212656..7e57d3baab23 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c @@ -250,8 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info) */ static int tmiofb_hw_stop(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); - struct tmio_fb_data *data = cell->driver_data; + struct tmio_fb_data *data = mfd_get_data(dev); struct fb_info *info = platform_get_drvdata(dev); struct tmiofb_par *par = info->par; @@ -313,7 +312,7 @@ static int tmiofb_hw_init(struct platform_device *dev) static void tmiofb_hw_mode(struct platform_device *dev) { struct mfd_cell *cell = mfd_get_cell(dev); - struct tmio_fb_data *data = cell->driver_data; + struct tmio_fb_data *data = mfd_get_data(dev); struct fb_info *info = platform_get_drvdata(dev); struct fb_videomode *mode = info->mode; struct tmiofb_par *par = info->par; @@ -559,8 +558,8 @@ static int tmiofb_ioctl(struct fb_info *fbi, static struct fb_videomode * tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var) { - struct mfd_cell *cell = mfd_get_cell(to_platform_device(info->device)); - struct tmio_fb_data *data = cell->driver_data; + struct tmio_fb_data *data = + mfd_get_data(to_platform_device(info->device)); struct fb_videomode *best = NULL; int i; @@ -580,8 +579,8 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct fb_videomode *mode; - struct mfd_cell *cell = mfd_get_cell(to_platform_device(info->device)); - struct tmio_fb_data *data = cell->driver_data; + struct tmio_fb_data *data = + mfd_get_data(to_platform_device(info->device)); mode = tmiofb_find_mode(info, var); if (!mode || var->bits_per_pixel > 16) @@ -682,7 +681,7 @@ static struct fb_ops tmiofb_ops = { static int __devinit tmiofb_probe(struct platform_device *dev) { struct mfd_cell *cell = mfd_get_cell(dev); - struct tmio_fb_data *data = cell->driver_data; + struct tmio_fb_data *data = mfd_get_data(dev); struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1); struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0); struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2); -- cgit v1.2.2 From 46673ed2cdca85afa7c69d126e3778bba2dbd2d5 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:32 -0800 Subject: rdc321x-southbridge: Use mfd_data instead of driver_data Use mfd_data for passing information from mfd drivers to soc clients. The mfd_cell's driver_data field is being phased out. Clients that were using driver_data now access .mfd_data via mfd_get_data(). Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/gpio/rdc321x-gpio.c | 3 ++- drivers/mfd/rdc321x-southbridge.c | 4 ++-- drivers/watchdog/rdc321x_wdt.c | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/rdc321x-gpio.c b/drivers/gpio/rdc321x-gpio.c index 897e0577e65e..a9bda881935a 100644 --- a/drivers/gpio/rdc321x-gpio.c +++ b/drivers/gpio/rdc321x-gpio.c @@ -27,6 +27,7 @@ #include #include #include +#include #include struct rdc321x_gpio { @@ -135,7 +136,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) struct rdc321x_gpio *rdc321x_gpio_dev; struct rdc321x_gpio_pdata *pdata; - pdata = platform_get_drvdata(pdev); + pdata = mfd_get_data(pdev); if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 50922975bda3..193c940225b5 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -61,12 +61,12 @@ static struct mfd_cell rdc321x_sb_cells[] = { .name = "rdc321x-wdt", .resources = rdc321x_wdt_resource, .num_resources = ARRAY_SIZE(rdc321x_wdt_resource), - .driver_data = &rdc321x_wdt_pdata, + .mfd_data = &rdc321x_wdt_pdata, }, { .name = "rdc321x-gpio", .resources = rdc321x_gpio_resources, .num_resources = ARRAY_SIZE(rdc321x_gpio_resources), - .driver_data = &rdc321x_gpio_pdata, + .mfd_data = &rdc321x_gpio_pdata, }, }; diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c index 3939e53f5f98..d8e725082fdc 100644 --- a/drivers/watchdog/rdc321x_wdt.c +++ b/drivers/watchdog/rdc321x_wdt.c @@ -37,6 +37,7 @@ #include #include #include +#include #define RDC_WDT_MASK 0x80000000 /* Mask */ #define RDC_WDT_EN 0x00800000 /* Enable bit */ @@ -231,7 +232,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) struct resource *r; struct rdc321x_wdt_pdata *pdata; - pdata = platform_get_drvdata(pdev); + pdata = mfd_get_data(pdev); if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; -- cgit v1.2.2 From dcb50e83bb86d66d3554ba9c365488669c84d037 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:33 -0800 Subject: mfd: Remove driver_data field from mfd_cell All users of this have now been switched over to using mfd_data; it can go away now. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 21a39dc64ea0..01115f686dfa 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -37,7 +37,6 @@ static int mfd_add_device(struct device *parent, int id, goto fail_device; pdev->dev.parent = parent; - platform_set_drvdata(pdev, cell->driver_data); ret = platform_device_add_data(pdev, cell, sizeof(*cell)); if (ret) -- cgit v1.2.2 From 1e29af62f2b285bd18685da93c3ce8c33ca2d1db Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:34 -0800 Subject: mfd: Add refcounting support to mfd_cells This provides convenience functions for sharing of cells across multiple mfd clients. Mfd drivers can provide enable/disable hooks to actually tweak the hardware, and clients can call mfd_shared_cell_{en,dis}able without having to worry about whether or not another client happens to have enabled or disabled the cell/hardware. Note that this is purely optional; drivers can continue to use the mfd_cell's enable/disable hooks for their own purposes, if desired. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 01115f686dfa..ca789f882305 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -18,6 +18,43 @@ #include #include +int mfd_shared_cell_enable(struct platform_device *pdev) +{ + const struct mfd_cell *cell = mfd_get_cell(pdev); + int err = 0; + + /* only call enable hook if the cell wasn't previously enabled */ + if (atomic_inc_return(cell->usage_count) == 1) + err = cell->enable(pdev); + + /* if the enable hook failed, decrement counter to allow retries */ + if (err) + atomic_dec(cell->usage_count); + + return err; +} +EXPORT_SYMBOL(mfd_shared_cell_enable); + +int mfd_shared_cell_disable(struct platform_device *pdev) +{ + const struct mfd_cell *cell = mfd_get_cell(pdev); + int err = 0; + + /* only disable if no other clients are using it */ + if (atomic_dec_return(cell->usage_count) == 0) + err = cell->disable(pdev); + + /* if the disable hook failed, increment to allow retries */ + if (err) + atomic_inc(cell->usage_count); + + /* sanity check; did someone call disable too many times? */ + WARN_ON(atomic_read(cell->usage_count) < 0); + + return err; +} +EXPORT_SYMBOL(mfd_shared_cell_disable); + static int mfd_add_device(struct device *parent, int id, const struct mfd_cell *cell, struct resource *mem_base, @@ -96,14 +133,22 @@ fail_alloc: } int mfd_add_devices(struct device *parent, int id, - const struct mfd_cell *cells, int n_devs, + struct mfd_cell *cells, int n_devs, struct resource *mem_base, int irq_base) { int i; int ret = 0; + atomic_t *cnts; + + /* initialize reference counting for all cells */ + cnts = kcalloc(sizeof(*cnts), n_devs, GFP_KERNEL); + if (!cnts) + return -ENOMEM; for (i = 0; i < n_devs; i++) { + atomic_set(&cnts[i], 0); + cells[i].usage_count = &cnts[i]; ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); if (ret) break; @@ -116,15 +161,26 @@ int mfd_add_devices(struct device *parent, int id, } EXPORT_SYMBOL(mfd_add_devices); -static int mfd_remove_devices_fn(struct device *dev, void *unused) +static int mfd_remove_devices_fn(struct device *dev, void *c) { - platform_device_unregister(to_platform_device(dev)); + struct platform_device *pdev = to_platform_device(dev); + const struct mfd_cell *cell = mfd_get_cell(pdev); + atomic_t **usage_count = c; + + /* find the base address of usage_count pointers (for freeing) */ + if (!*usage_count || (cell->usage_count < *usage_count)) + *usage_count = cell->usage_count; + + platform_device_unregister(pdev); return 0; } void mfd_remove_devices(struct device *parent) { - device_for_each_child(parent, NULL, mfd_remove_devices_fn); + atomic_t *cnts = NULL; + + device_for_each_child(parent, &cnts, mfd_remove_devices_fn); + kfree(cnts); } EXPORT_SYMBOL(mfd_remove_devices); -- cgit v1.2.2 From a9bbba996302344b1fac7773cf8198f6fee35ac1 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:35 -0800 Subject: mfd: add platform_device sharing support for mfd This adds functions to enable platform_device sharing for mfd clients. Each platform driver (mfd client) that wants to share an mfd_cell's platform_device uses the mfd_shared_platform_driver_{un,}register() functions instead of platform_driver_{un,}register(). Along with registering the platform driver, these also register a new platform device with the same characteristics as the original cell, but a different name. Given an mfd_cell with the name "foo", drivers that want to share access to its resources can call mfd_shared_platform_driver_register with platform drivers named (for example) "bar" and "baz". This will register two platform devices and drivers named "bar" and "baz" that share the same cell as the platform device "foo". The drivers can then call "foo" cell's enable hooks (or mfd_shared_cell_enable) to enable resources, and obtain platform resources as they normally would. This deals with platform handling only; mfd driver-specific details, hardware handling, refcounting, etc are all dealt with separately. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index ca789f882305..bb2264cc410b 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -184,5 +184,66 @@ void mfd_remove_devices(struct device *parent) } EXPORT_SYMBOL(mfd_remove_devices); +static int add_shared_platform_device(const char *cell, const char *name) +{ + struct mfd_cell cell_entry; + struct device *dev; + struct platform_device *pdev; + int err; + + /* check if we've already registered a device (don't fail if we have) */ + if (bus_find_device_by_name(&platform_bus_type, NULL, name)) + return 0; + + /* fetch the parent cell's device (should already be registered!) */ + dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); + if (!dev) { + printk(KERN_ERR "failed to find device for cell %s\n", cell); + return -ENODEV; + } + pdev = to_platform_device(dev); + memcpy(&cell_entry, mfd_get_cell(pdev), sizeof(cell_entry)); + + WARN_ON(!cell_entry.enable); + + cell_entry.name = name; + err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0); + if (err) + dev_err(dev, "MFD add devices failed: %d\n", err); + return err; +} + +int mfd_shared_platform_driver_register(struct platform_driver *drv, + const char *cellname) +{ + int err; + + err = add_shared_platform_device(cellname, drv->driver.name); + if (err) + printk(KERN_ERR "failed to add platform device %s\n", + drv->driver.name); + + err = platform_driver_register(drv); + if (err) + printk(KERN_ERR "failed to add platform driver %s\n", + drv->driver.name); + + return err; +} +EXPORT_SYMBOL(mfd_shared_platform_driver_register); + +void mfd_shared_platform_driver_unregister(struct platform_driver *drv) +{ + struct device *dev; + + dev = bus_find_device_by_name(&platform_bus_type, NULL, + drv->driver.name); + if (dev) + platform_device_unregister(to_platform_device(dev)); + + platform_driver_unregister(drv); +} +EXPORT_SYMBOL(mfd_shared_platform_driver_unregister); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); -- cgit v1.2.2 From 1310e6d638b302bd9cd064f8de7dcd546bb7f597 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Feb 2011 19:07:36 -0800 Subject: mfd: Add sharing for cs5535 acpi/pms cells This enables sharing of cs5535-mfd cells via the new mfd_shared_* API. Hooks for enable/disble of resources are added, with refcounting of resources being automatically handled so that cs5535_mfd_res_enable/disable are only called when necessary. Clients of cs5535-mfd (in this case, olpc-xo1.c) are also modified to use the mfd_shared API. The platform drivers are also renamed to olpc-xo1-{pms,acpi}, and resource enabling/disabling is replaced with mfd_shared API calls. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/cs5535-mfd.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 59ca6f151e78..886a06871065 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -39,6 +39,37 @@ enum cs5535_mfd_bars { NR_BARS, }; +static int cs5535_mfd_res_enable(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(&pdev->dev, "can't fetch device resource info\n"); + return -EIO; + } + + if (!request_region(res->start, resource_size(res), DRV_NAME)) { + dev_err(&pdev->dev, "can't request region\n"); + return -EIO; + } + + return 0; +} + +static int cs5535_mfd_res_disable(struct platform_device *pdev) +{ + struct resource *res; + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) { + dev_err(&pdev->dev, "can't fetch device resource info\n"); + return -EIO; + } + + release_region(res->start, resource_size(res)); + return 0; +} + static __devinitdata struct resource cs5535_mfd_resources[NR_BARS]; static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { @@ -65,12 +96,18 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { .name = "cs5535-pms", .num_resources = 1, .resources = &cs5535_mfd_resources[PMS_BAR], + + .enable = cs5535_mfd_res_enable, + .disable = cs5535_mfd_res_disable, }, { .id = ACPI_BAR, .name = "cs5535-acpi", .num_resources = 1, .resources = &cs5535_mfd_resources[ACPI_BAR], + + .enable = cs5535_mfd_res_enable, + .disable = cs5535_mfd_res_disable, }, }; -- cgit v1.2.2 From 6991ec255af960e1349a21ec2782ea67408b7eb6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 28 Feb 2011 14:32:15 +0800 Subject: mfd: Add MODULE_DEVICE_TABLE to mc13xxx-core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The device table is required to load modules based on modaliases. After adding the MODULE_DEVICE_TABLE, below entries will be added to modules.alias: alias spi:mc13892 mc13xxx_core alias spi:mc13783 mc13xxx_core Signed-off-by: Axel Lin Acked-by: Uwe Kleine-König Signed-off-by: Samuel Ortiz --- drivers/mfd/mc13xxx-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 97a3b400ed4f..668634e89e81 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -803,6 +803,7 @@ static const struct spi_device_id mc13xxx_device_id[] = { /* sentinel */ } }; +MODULE_DEVICE_TABLE(spi, mc13xxx_device_id); static struct spi_driver mc13xxx_driver = { .id_table = mc13xxx_device_id, -- cgit v1.2.2 From 7679089debfbffc9243b41664e348412f9df1639 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 28 Feb 2011 14:33:12 +0800 Subject: mfd: Add MODULE_DEVICE_TABLE to pcf50633-core The device table is required to load modules based on modaliases. After adding the MODULE_DEVICE_TABLE, below entries will be added to modules.alias: alias i2c:pcf50633 pcf50633 Signed-off-by: Axel Lin Acked-by: Harald Welte Signed-off-by: Samuel Ortiz --- drivers/mfd/pcf50633-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 2640e4dcd078..c1306ed43e3c 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -360,6 +360,7 @@ static struct i2c_device_id pcf50633_id_table[] = { {"pcf50633", 0x73}, {/* end of list */} }; +MODULE_DEVICE_TABLE(i2c, pcf50633_id_table); static struct i2c_driver pcf50633_driver = { .driver = { -- cgit v1.2.2 From bcd2f639629b58fbc702bb8be348a03e75472021 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 28 Feb 2011 14:34:27 +0800 Subject: mfd: Add MODULE_DEVICE_TABLE to vx855 The device table is required to load modules based on modaliases. After adding the MODULE_DEVICE_TABLE, below entries will be added to modules.pcimap: vx855 0x00001106 0x00008409 0xffffffff 0xffffffff 0x00000000 0x00000000 0x0 Signed-off-by: Axel Lin Acked-by: Harald Welte Signed-off-by: Samuel Ortiz --- drivers/mfd/vx855.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index 348052aa5dbf..d698703dbd46 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c @@ -122,6 +122,7 @@ static struct pci_device_id vx855_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, { 0, } }; +MODULE_DEVICE_TABLE(pci, vx855_pci_tbl); static struct pci_driver vx855_pci_driver = { .name = "vx855", -- cgit v1.2.2 From f99c1d4f94f91fd3a20bd2eaa3be9c5e7d2668eb Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 1 Mar 2011 19:12:26 +0530 Subject: mfd: Add twl4030 madc driver Introducing a driver for MADC on TWL4030 powerIC. MADC stands for monitoring ADC. This driver monitors the real time conversion of analog signals like battery temperature, battery cuurent etc. Signed-off-by: Keerthy Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/twl4030-madc.c | 802 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 813 insertions(+) create mode 100644 drivers/mfd/twl4030-madc.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d71af4531b14..50c476964e48 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -178,6 +178,16 @@ config TWL4030_CORE high speed USB OTG transceiver, an audio codec (on most versions) and many other features. +config TWL4030_MADC + tristate "Texas Instruments TWL4030 MADC" + depends on TWL4030_CORE + help + This driver provides support for triton TWL4030-MADC. The + driver supports both RT and SW conversion methods. + + This driver can be built as a module. If so it will be + named twl4030-madc + config TWL4030_POWER bool "Support power resources on TWL4030 family chips" depends on TWL4030_CORE && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ad71bd59345f..25f3c7551489 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_TPS6507X) += tps6507x.o obj-$(CONFIG_MENELAUS) += menelaus.o obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o +obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c new file mode 100644 index 000000000000..e9884e2583bf --- /dev/null +++ b/drivers/mfd/twl4030-madc.c @@ -0,0 +1,802 @@ +/* + * + * TWL4030 MADC module driver-This driver monitors the real time + * conversion of analog signals like battery temperature, + * battery type, battery level etc. + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * J Keerthy + * + * Based on twl4030-madc.c + * Copyright (C) 2008 Nokia Corporation + * Mikko Ylinen + * + * Amit Kucheria + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * struct twl4030_madc_data - a container for madc info + * @dev - pointer to device structure for madc + * @lock - mutex protecting this data structure + * @requests - Array of request struct corresponding to SW1, SW2 and RT + * @imr - Interrupt mask register of MADC + * @isr - Interrupt status register of MADC + */ +struct twl4030_madc_data { + struct device *dev; + struct mutex lock; /* mutex protecting this data structure */ + struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; + int imr; + int isr; +}; + +static struct twl4030_madc_data *twl4030_madc; + +struct twl4030_prescale_divider_ratios { + s16 numerator; + s16 denominator; +}; + +static const struct twl4030_prescale_divider_ratios +twl4030_divider_ratios[16] = { + {1, 1}, /* CHANNEL 0 No Prescaler */ + {1, 1}, /* CHANNEL 1 No Prescaler */ + {6, 10}, /* CHANNEL 2 */ + {6, 10}, /* CHANNEL 3 */ + {6, 10}, /* CHANNEL 4 */ + {6, 10}, /* CHANNEL 5 */ + {6, 10}, /* CHANNEL 6 */ + {6, 10}, /* CHANNEL 7 */ + {3, 14}, /* CHANNEL 8 */ + {1, 3}, /* CHANNEL 9 */ + {1, 1}, /* CHANNEL 10 No Prescaler */ + {15, 100}, /* CHANNEL 11 */ + {1, 4}, /* CHANNEL 12 */ + {1, 1}, /* CHANNEL 13 Reserved channels */ + {1, 1}, /* CHANNEL 14 Reseved channels */ + {5, 11}, /* CHANNEL 15 */ +}; + + +/* + * Conversion table from -3 to 55 degree Celcius + */ +static int therm_tbl[] = { +30800, 29500, 28300, 27100, +26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900, +17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100, +11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310, +8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830, +5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170, +4040, 3910, 3790, 3670, 3550 +}; + +/* + * Structure containing the registers + * of different conversion methods supported by MADC. + * Hardware or RT real time conversion request initiated by external host + * processor for RT Signal conversions. + * External host processors can also request for non RT conversions + * SW1 and SW2 software conversions also called asynchronous or GPC request. + */ +static +const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = { + [TWL4030_MADC_RT] = { + .sel = TWL4030_MADC_RTSELECT_LSB, + .avg = TWL4030_MADC_RTAVERAGE_LSB, + .rbase = TWL4030_MADC_RTCH0_LSB, + }, + [TWL4030_MADC_SW1] = { + .sel = TWL4030_MADC_SW1SELECT_LSB, + .avg = TWL4030_MADC_SW1AVERAGE_LSB, + .rbase = TWL4030_MADC_GPCH0_LSB, + .ctrl = TWL4030_MADC_CTRL_SW1, + }, + [TWL4030_MADC_SW2] = { + .sel = TWL4030_MADC_SW2SELECT_LSB, + .avg = TWL4030_MADC_SW2AVERAGE_LSB, + .rbase = TWL4030_MADC_GPCH0_LSB, + .ctrl = TWL4030_MADC_CTRL_SW2, + }, +}; + +/* + * Function to read a particular channel value. + * @madc - pointer to struct twl4030_madc_data + * @reg - lsb of ADC Channel + * If the i2c read fails it returns an error else returns 0. + */ +static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg) +{ + u8 msb, lsb; + int ret; + /* + * For each ADC channel, we have MSB and LSB register pair. MSB address + * is always LSB address+1. reg parameter is the address of LSB register + */ + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1); + if (ret) { + dev_err(madc->dev, "unable to read MSB register 0x%X\n", + reg + 1); + return ret; + } + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg); + if (ret) { + dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg); + return ret; + } + + return (int)(((msb << 8) | lsb) >> 6); +} + +/* + * Return battery temperature + * Or < 0 on failure. + */ +static int twl4030battery_temperature(int raw_volt) +{ + u8 val; + int temp, curr, volt, res, ret; + + volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R; + /* Getting and calculating the supply current in micro ampers */ + ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, + REG_BCICTL2); + if (ret < 0) + return ret; + curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10; + /* Getting and calculating the thermistor resistance in ohms */ + res = volt * 1000 / curr; + /* calculating temperature */ + for (temp = 58; temp >= 0; temp--) { + int actual = therm_tbl[temp]; + + if ((actual - res) >= 0) + break; + } + + return temp + 1; +} + +static int twl4030battery_current(int raw_volt) +{ + int ret; + u8 val; + + ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val, + TWL4030_BCI_BCICTL1); + if (ret) + return ret; + if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */ + return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1; + else /* slope of 0.88 mV/mA */ + return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2; +} +/* + * Function to read channel values + * @madc - pointer to twl4030_madc_data struct + * @reg_base - Base address of the first channel + * @Channels - 16 bit bitmap. If the bit is set, channel value is read + * @buf - The channel values are stored here. if read fails error + * value is stored + * Returns the number of successfully read channels. + */ +static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, + u8 reg_base, unsigned + long channels, int *buf) +{ + int count = 0, count_req = 0, i; + u8 reg; + + for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) { + reg = reg_base + 2 * i; + buf[i] = twl4030_madc_channel_raw_read(madc, reg); + if (buf[i] < 0) { + dev_err(madc->dev, + "Unable to read register 0x%X\n", reg); + count_req++; + continue; + } + switch (i) { + case 10: + buf[i] = twl4030battery_current(buf[i]); + if (buf[i] < 0) { + dev_err(madc->dev, "err reading current\n"); + count_req++; + } else { + count++; + buf[i] = buf[i] - 750; + } + break; + case 1: + buf[i] = twl4030battery_temperature(buf[i]); + if (buf[i] < 0) { + dev_err(madc->dev, "err reading temperature\n"); + count_req++; + } else { + buf[i] -= 3; + count++; + } + break; + default: + count++; + /* Analog Input (V) = conv_result * step_size / R + * conv_result = decimal value of 10-bit conversion + * result + * step size = 1.5 / (2 ^ 10 -1) + * R = Prescaler ratio for input channels. + * Result given in mV hence multiplied by 1000. + */ + buf[i] = (buf[i] * 3 * 1000 * + twl4030_divider_ratios[i].denominator) + / (2 * 1023 * + twl4030_divider_ratios[i].numerator); + } + } + if (count_req) + dev_err(madc->dev, "%d channel conversion failed\n", count_req); + + return count; +} + +/* + * Enables irq. + * @madc - pointer to twl4030_madc_data struct + * @id - irq number to be enabled + * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 + * corresponding to RT, SW1, SW2 conversion requests. + * If the i2c read fails it returns an error else returns 0. + */ +static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id) +{ + u8 val; + int ret; + + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); + if (ret) { + dev_err(madc->dev, "unable to read imr register 0x%X\n", + madc->imr); + return ret; + } + val &= ~(1 << id); + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); + if (ret) { + dev_err(madc->dev, + "unable to write imr register 0x%X\n", madc->imr); + return ret; + + } + + return 0; +} + +/* + * Disables irq. + * @madc - pointer to twl4030_madc_data struct + * @id - irq number to be disabled + * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 + * corresponding to RT, SW1, SW2 conversion requests. + * Returns error if i2c read/write fails. + */ +static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id) +{ + u8 val; + int ret; + + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); + if (ret) { + dev_err(madc->dev, "unable to read imr register 0x%X\n", + madc->imr); + return ret; + } + val |= (1 << id); + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); + if (ret) { + dev_err(madc->dev, + "unable to write imr register 0x%X\n", madc->imr); + return ret; + } + + return 0; +} + +static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) +{ + struct twl4030_madc_data *madc = _madc; + const struct twl4030_madc_conversion_method *method; + u8 isr_val, imr_val; + int i, len, ret; + struct twl4030_madc_request *r; + + mutex_lock(&madc->lock); + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr); + if (ret) { + dev_err(madc->dev, "unable to read isr register 0x%X\n", + madc->isr); + goto err_i2c; + } + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr); + if (ret) { + dev_err(madc->dev, "unable to read imr register 0x%X\n", + madc->imr); + goto err_i2c; + } + isr_val &= ~imr_val; + for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { + if (!(isr_val & (1 << i))) + continue; + ret = twl4030_madc_disable_irq(madc, i); + if (ret < 0) + dev_dbg(madc->dev, "Disable interrupt failed%d\n", i); + madc->requests[i].result_pending = 1; + } + for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { + r = &madc->requests[i]; + /* No pending results for this method, move to next one */ + if (!r->result_pending) + continue; + method = &twl4030_conversion_methods[r->method]; + /* Read results */ + len = twl4030_madc_read_channels(madc, method->rbase, + r->channels, r->rbuf); + /* Return results to caller */ + if (r->func_cb != NULL) { + r->func_cb(len, r->channels, r->rbuf); + r->func_cb = NULL; + } + /* Free request */ + r->result_pending = 0; + r->active = 0; + } + mutex_unlock(&madc->lock); + + return IRQ_HANDLED; + +err_i2c: + /* + * In case of error check whichever request is active + * and service the same. + */ + for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { + r = &madc->requests[i]; + if (r->active == 0) + continue; + method = &twl4030_conversion_methods[r->method]; + /* Read results */ + len = twl4030_madc_read_channels(madc, method->rbase, + r->channels, r->rbuf); + /* Return results to caller */ + if (r->func_cb != NULL) { + r->func_cb(len, r->channels, r->rbuf); + r->func_cb = NULL; + } + /* Free request */ + r->result_pending = 0; + r->active = 0; + } + mutex_unlock(&madc->lock); + + return IRQ_HANDLED; +} + +static int twl4030_madc_set_irq(struct twl4030_madc_data *madc, + struct twl4030_madc_request *req) +{ + struct twl4030_madc_request *p; + int ret; + + p = &madc->requests[req->method]; + memcpy(p, req, sizeof(*req)); + ret = twl4030_madc_enable_irq(madc, req->method); + if (ret < 0) { + dev_err(madc->dev, "enable irq failed!!\n"); + return ret; + } + + return 0; +} + +/* + * Function which enables the madc conversion + * by writing to the control register. + * @madc - pointer to twl4030_madc_data struct + * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1 + * corresponding to RT SW1 or SW2 conversion methods. + * Returns 0 if succeeds else a negative error value + */ +static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc, + int conv_method) +{ + const struct twl4030_madc_conversion_method *method; + int ret = 0; + method = &twl4030_conversion_methods[conv_method]; + switch (conv_method) { + case TWL4030_MADC_SW1: + case TWL4030_MADC_SW2: + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, + TWL4030_MADC_SW_START, method->ctrl); + if (ret) { + dev_err(madc->dev, + "unable to write ctrl register 0x%X\n", + method->ctrl); + return ret; + } + break; + default: + break; + } + + return 0; +} + +/* + * Function that waits for conversion to be ready + * @madc - pointer to twl4030_madc_data struct + * @timeout_ms - timeout value in milliseconds + * @status_reg - ctrl register + * returns 0 if succeeds else a negative error value + */ +static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc, + unsigned int timeout_ms, + u8 status_reg) +{ + unsigned long timeout; + int ret; + + timeout = jiffies + msecs_to_jiffies(timeout_ms); + do { + u8 reg; + + ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, ®, status_reg); + if (ret) { + dev_err(madc->dev, + "unable to read status register 0x%X\n", + status_reg); + return ret; + } + if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW)) + return 0; + usleep_range(500, 2000); + } while (!time_after(jiffies, timeout)); + dev_err(madc->dev, "conversion timeout!\n"); + + return -EAGAIN; +} + +/* + * An exported function which can be called from other kernel drivers. + * @req twl4030_madc_request structure + * req->rbuf will be filled with read values of channels based on the + * channel index. If a particular channel reading fails there will + * be a negative error value in the corresponding array element. + * returns 0 if succeeds else error value + */ +int twl4030_madc_conversion(struct twl4030_madc_request *req) +{ + const struct twl4030_madc_conversion_method *method; + u8 ch_msb, ch_lsb; + int ret; + + if (!req) + return -EINVAL; + mutex_lock(&twl4030_madc->lock); + if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) { + ret = -EINVAL; + goto out; + } + /* Do we have a conversion request ongoing */ + if (twl4030_madc->requests[req->method].active) { + ret = -EBUSY; + goto out; + } + ch_msb = (req->channels >> 8) & 0xff; + ch_lsb = req->channels & 0xff; + method = &twl4030_conversion_methods[req->method]; + /* Select channels to be converted */ + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1); + if (ret) { + dev_err(twl4030_madc->dev, + "unable to write sel register 0x%X\n", method->sel + 1); + return ret; + } + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel); + if (ret) { + dev_err(twl4030_madc->dev, + "unable to write sel register 0x%X\n", method->sel + 1); + return ret; + } + /* Select averaging for all channels if do_avg is set */ + if (req->do_avg) { + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, + ch_msb, method->avg + 1); + if (ret) { + dev_err(twl4030_madc->dev, + "unable to write avg register 0x%X\n", + method->avg + 1); + return ret; + } + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, + ch_lsb, method->avg); + if (ret) { + dev_err(twl4030_madc->dev, + "unable to write sel reg 0x%X\n", + method->sel + 1); + return ret; + } + } + if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) { + ret = twl4030_madc_set_irq(twl4030_madc, req); + if (ret < 0) + goto out; + ret = twl4030_madc_start_conversion(twl4030_madc, req->method); + if (ret < 0) + goto out; + twl4030_madc->requests[req->method].active = 1; + ret = 0; + goto out; + } + /* With RT method we should not be here anymore */ + if (req->method == TWL4030_MADC_RT) { + ret = -EINVAL; + goto out; + } + ret = twl4030_madc_start_conversion(twl4030_madc, req->method); + if (ret < 0) + goto out; + twl4030_madc->requests[req->method].active = 1; + /* Wait until conversion is ready (ctrl register returns EOC) */ + ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl); + if (ret) { + twl4030_madc->requests[req->method].active = 0; + goto out; + } + ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, + req->channels, req->rbuf); + twl4030_madc->requests[req->method].active = 0; + +out: + mutex_unlock(&twl4030_madc->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(twl4030_madc_conversion); + +/* + * Return channel value + * Or < 0 on failure. + */ +int twl4030_get_madc_conversion(int channel_no) +{ + struct twl4030_madc_request req; + int temp = 0; + int ret; + + req.channels = (1 << channel_no); + req.method = TWL4030_MADC_SW2; + req.active = 0; + req.func_cb = NULL; + ret = twl4030_madc_conversion(&req); + if (ret < 0) + return ret; + if (req.rbuf[channel_no] > 0) + temp = req.rbuf[channel_no]; + + return temp; +} +EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion); + +/* + * Function to enable or disable bias current for + * main battery type reading or temperature sensing + * @madc - pointer to twl4030_madc_data struct + * @chan - can be one of the two values + * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading + * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature + * sensing + * @on - enable or disable chan. + */ +static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc, + int chan, int on) +{ + int ret; + u8 regval; + + ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, + ®val, TWL4030_BCI_BCICTL1); + if (ret) { + dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X", + TWL4030_BCI_BCICTL1); + return ret; + } + if (on) + regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN; + else + regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN; + ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, + regval, TWL4030_BCI_BCICTL1); + if (ret) { + dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n", + TWL4030_BCI_BCICTL1); + return ret; + } + + return 0; +} + +/* + * Function that sets MADC software power on bit to enable MADC + * @madc - pointer to twl4030_madc_data struct + * @on - Enable or disable MADC software powen on bit. + * returns error if i2c read/write fails else 0 + */ +static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) +{ + u8 regval; + int ret; + + ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, + ®val, TWL4030_MADC_CTRL1); + if (ret) { + dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n", + TWL4030_MADC_CTRL1); + return ret; + } + if (on) + regval |= TWL4030_MADC_MADCON; + else + regval &= ~TWL4030_MADC_MADCON; + ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1); + if (ret) { + dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n", + TWL4030_MADC_CTRL1); + return ret; + } + + return 0; +} + +/* + * Initialize MADC and request for threaded irq + */ +static int __devinit twl4030_madc_probe(struct platform_device *pdev) +{ + struct twl4030_madc_data *madc; + struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data; + int ret; + u8 regval; + + if (!pdata) { + dev_err(&pdev->dev, "platform_data not available\n"); + return -EINVAL; + } + madc = kzalloc(sizeof(*madc), GFP_KERNEL); + if (!madc) + return -ENOMEM; + + /* + * Phoenix provides 2 interrupt lines. The first one is connected to + * the OMAP. The other one can be connected to the other processor such + * as modem. Hence two separate ISR and IMR registers. + */ + madc->imr = (pdata->irq_line == 1) ? + TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; + madc->isr = (pdata->irq_line == 1) ? + TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2; + ret = twl4030_madc_set_power(madc, 1); + if (ret < 0) + goto err_power; + ret = twl4030_madc_set_current_generator(madc, 0, 1); + if (ret < 0) + goto err_current_generator; + + ret = twl_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, + ®val, TWL4030_BCI_BCICTL1); + if (ret) { + dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n", + TWL4030_BCI_BCICTL1); + goto err_i2c; + } + regval |= TWL4030_BCI_MESBAT; + ret = twl_i2c_write_u8(TWL4030_MODULE_MAIN_CHARGE, + regval, TWL4030_BCI_BCICTL1); + if (ret) { + dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n", + TWL4030_BCI_BCICTL1); + goto err_i2c; + } + platform_set_drvdata(pdev, madc); + mutex_init(&madc->lock); + ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL, + twl4030_madc_threaded_irq_handler, + IRQF_TRIGGER_RISING, "twl4030_madc", madc); + if (ret) { + dev_dbg(&pdev->dev, "could not request irq\n"); + goto err_irq; + } + twl4030_madc = madc; + return 0; +err_irq: + platform_set_drvdata(pdev, NULL); +err_i2c: + twl4030_madc_set_current_generator(madc, 0, 0); +err_current_generator: + twl4030_madc_set_power(madc, 0); +err_power: + kfree(madc); + + return ret; +} + +static int __devexit twl4030_madc_remove(struct platform_device *pdev) +{ + struct twl4030_madc_data *madc = platform_get_drvdata(pdev); + + free_irq(platform_get_irq(pdev, 0), madc); + platform_set_drvdata(pdev, NULL); + twl4030_madc_set_current_generator(madc, 0, 0); + twl4030_madc_set_power(madc, 0); + kfree(madc); + + return 0; +} + +static struct platform_driver twl4030_madc_driver = { + .probe = twl4030_madc_probe, + .remove = __exit_p(twl4030_madc_remove), + .driver = { + .name = "twl4030_madc", + .owner = THIS_MODULE, + }, +}; + +static int __init twl4030_madc_init(void) +{ + return platform_driver_register(&twl4030_madc_driver); +} + +module_init(twl4030_madc_init); + +static void __exit twl4030_madc_exit(void) +{ + platform_driver_unregister(&twl4030_madc_driver); +} + +module_exit(twl4030_madc_exit); + +MODULE_DESCRIPTION("TWL4030 ADC driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("J Keerthy"); +MODULE_ALIAS("twl4030_madc"); -- cgit v1.2.2 From 0070bddfe7275e5bc763884a8ac59651f4e79eab Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 1 Mar 2011 19:12:36 +0530 Subject: hwmon: twl4030: Hwmon Driver for TWL4030 MADC This driver exposes the sysfs nodes of the TWL4030 MADC module. All the voltage channel values are expressed in terms of mV. Channel 13 and channel 14 are reserved. There are channels which represent temperature and current the output is represented by celcius and mA respectively. Signed-off-by: Keerthy Acked-by: Guenter Roeck Signed-off-by: Samuel Ortiz --- drivers/hwmon/Kconfig | 10 +++ drivers/hwmon/Makefile | 1 + drivers/hwmon/twl4030-madc-hwmon.c | 157 +++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 drivers/hwmon/twl4030-madc-hwmon.c (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e4bd13b3cd8b..81131eda5544 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1047,6 +1047,16 @@ config SENSORS_TMP421 This driver can also be built as a module. If so, the module will be called tmp421. +config SENSORS_TWL4030_MADC + tristate "Texas Instruments TWL4030 MADC Hwmon" + depends on TWL4030_MADC + help + If you say yes here you get hwmon support for triton + TWL4030-MADC. + + This driver can also be built as a module. If so it will be called + twl4030-madc-hwmon. + config SENSORS_VIA_CPUTEMP tristate "VIA CPU temperature sensor" depends on X86 diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 54ca5939d028..967d0ea9447f 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -104,6 +104,7 @@ obj-$(CONFIG_SENSORS_THMC50) += thmc50.o obj-$(CONFIG_SENSORS_TMP102) += tmp102.o obj-$(CONFIG_SENSORS_TMP401) += tmp401.o obj-$(CONFIG_SENSORS_TMP421) += tmp421.o +obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c new file mode 100644 index 000000000000..97e22bef85ab --- /dev/null +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -0,0 +1,157 @@ +/* + * + * TWL4030 MADC Hwmon driver-This driver monitors the real time + * conversion of analog signals like battery temperature, + * battery type, battery level etc. User can ask for the conversion on a + * particular channel using the sysfs nodes. + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * J Keerthy + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * sysfs hook function + */ +static ssize_t madc_read(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct twl4030_madc_request req; + long val; + + req.channels = (1 << attr->index); + req.method = TWL4030_MADC_SW2; + req.func_cb = NULL; + val = twl4030_madc_conversion(&req); + if (val < 0) + return val; + + return sprintf(buf, "%d\n", req.rbuf[attr->index]); +} + +/* sysfs nodes to read individual channels from user side */ +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, madc_read, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, madc_read, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, madc_read, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, madc_read, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, madc_read, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, madc_read, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, madc_read, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, madc_read, NULL, 7); +static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, madc_read, NULL, 8); +static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, madc_read, NULL, 9); +static SENSOR_DEVICE_ATTR(curr10_input, S_IRUGO, madc_read, NULL, 10); +static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, madc_read, NULL, 11); +static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, madc_read, NULL, 12); +static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, madc_read, NULL, 15); + +static struct attribute *twl4030_madc_attributes[] = { + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in8_input.dev_attr.attr, + &sensor_dev_attr_in9_input.dev_attr.attr, + &sensor_dev_attr_curr10_input.dev_attr.attr, + &sensor_dev_attr_in11_input.dev_attr.attr, + &sensor_dev_attr_in12_input.dev_attr.attr, + &sensor_dev_attr_in15_input.dev_attr.attr, + NULL +}; + +static const struct attribute_group twl4030_madc_group = { + .attrs = twl4030_madc_attributes, +}; + +static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) +{ + int ret; + int status; + struct device *hwmon; + + ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group); + if (ret) + goto err_sysfs; + hwmon = hwmon_device_register(&pdev->dev); + if (IS_ERR(hwmon)) { + dev_err(&pdev->dev, "hwmon_device_register failed.\n"); + status = PTR_ERR(hwmon); + goto err_reg; + } + + return 0; + +err_reg: + sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group); +err_sysfs: + + return ret; +} + +static int __devexit twl4030_madc_hwmon_remove(struct platform_device *pdev) +{ + hwmon_device_unregister(&pdev->dev); + sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group); + + return 0; +} + +static struct platform_driver twl4030_madc_hwmon_driver = { + .probe = twl4030_madc_hwmon_probe, + .remove = __exit_p(twl4030_madc_hwmon_remove), + .driver = { + .name = "twl4030_madc_hwmon", + .owner = THIS_MODULE, + }, +}; + +static int __init twl4030_madc_hwmon_init(void) +{ + return platform_driver_register(&twl4030_madc_hwmon_driver); +} + +module_init(twl4030_madc_hwmon_init); + +static void __exit twl4030_madc_hwmon_exit(void) +{ + platform_driver_unregister(&twl4030_madc_hwmon_driver); +} + +module_exit(twl4030_madc_hwmon_exit); + +MODULE_DESCRIPTION("TWL4030 ADC Hwmon driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("J Keerthy"); +MODULE_ALIAS("twl4030_madc_hwmon"); -- cgit v1.2.2 From f624effb7354814d062f149c8a1e2c46a44acb1f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 1 Mar 2011 20:12:44 +0000 Subject: mfd: Convert WM831x interrupt masking to enable/disable operations The WM831x interrupt masking support is a much better match for the genirq enable and disable operations than for the mask and unmask operations. The latter are intended to used during interrupt handling for temporary changes which isn't really practical on a slow bus. Convert the operations over to match this. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 2e45f60d01a7..a5cd17e18d09 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -352,6 +352,10 @@ static void wm831x_irq_sync_unlock(struct irq_data *data) /* If there's been a change in the mask write it back * to the hardware. */ if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { + dev_dbg(wm831x->dev, "IRQ mask sync: %x = %x\n", + WM831X_INTERRUPT_STATUS_1_MASK + i, + wm831x->irq_masks_cur[i]); + wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1_MASK + i, @@ -362,7 +366,7 @@ static void wm831x_irq_sync_unlock(struct irq_data *data) mutex_unlock(&wm831x->irq_lock); } -static void wm831x_irq_unmask(struct irq_data *data) +static void wm831x_irq_enable(struct irq_data *data) { struct wm831x *wm831x = irq_data_get_irq_chip_data(data); struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, @@ -371,7 +375,7 @@ static void wm831x_irq_unmask(struct irq_data *data) wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; } -static void wm831x_irq_mask(struct irq_data *data) +static void wm831x_irq_disable(struct irq_data *data) { struct wm831x *wm831x = irq_data_get_irq_chip_data(data); struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, @@ -417,8 +421,8 @@ static struct irq_chip wm831x_irq_chip = { .name = "wm831x", .irq_bus_lock = wm831x_irq_lock, .irq_bus_sync_unlock = wm831x_irq_sync_unlock, - .irq_mask = wm831x_irq_mask, - .irq_unmask = wm831x_irq_unmask, + .irq_disable = wm831x_irq_disable, + .irq_enable = wm831x_irq_enable, .irq_set_type = wm831x_irq_set_type, }; -- cgit v1.2.2 From d664f20020e0a3564d7aaba6625aa58d24283b7d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 1 Mar 2011 20:12:45 +0000 Subject: mfd: Convert WM8994/58 interrupt masking to enable/disable operations The WM8994/58 interrupt masking support is a much better match for the genirq enable and disable operations than for the mask and unmask operations. The latter are intended to used during interrupt handling for temporary changes which isn't really practical on a slow bus. Convert the operations over to match this. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-irq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 29e8faf9c01c..f5e439a37dc5 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -182,7 +182,7 @@ static void wm8994_irq_sync_unlock(struct irq_data *data) mutex_unlock(&wm8994->irq_lock); } -static void wm8994_irq_unmask(struct irq_data *data) +static void wm8994_irq_enable(struct irq_data *data) { struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, @@ -191,7 +191,7 @@ static void wm8994_irq_unmask(struct irq_data *data) wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; } -static void wm8994_irq_mask(struct irq_data *data) +static void wm8994_irq_disable(struct irq_data *data) { struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data); struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, @@ -204,8 +204,8 @@ static struct irq_chip wm8994_irq_chip = { .name = "wm8994", .irq_bus_lock = wm8994_irq_lock, .irq_bus_sync_unlock = wm8994_irq_sync_unlock, - .irq_mask = wm8994_irq_mask, - .irq_unmask = wm8994_irq_unmask, + .irq_disable = wm8994_irq_disable, + .irq_enable = wm8994_irq_enable, }; /* The processing of the primary interrupt occurs in a thread so that -- cgit v1.2.2 From 944dc03551f6e812c00e586edba84b28c52ffe8c Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 1 Mar 2011 12:32:20 -0800 Subject: tmio: Silence warnings introduced by mfd changes This silences warnings such as drivers/video/tmiofb.c: In function 'tmiofb_hw_init': drivers/video/tmiofb.c:270: warning: initialization discards qualifiers from pointer target type These were added by me in commit 2a79bb1d. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mmc/host/tmio_mmc.c | 8 ++++---- drivers/mtd/nand/tmio_nand.c | 8 ++++---- drivers/usb/host/ohci-tmio.c | 8 ++++---- drivers/video/tmiofb.c | 11 +++++------ 4 files changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index f8cb06b8ed65..ab1adeabdd22 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -1191,7 +1191,7 @@ static const struct mmc_host_ops tmio_mmc_ops = { #ifdef CONFIG_PM static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct mmc_host *mmc = platform_get_drvdata(dev); int ret; @@ -1206,7 +1206,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) static int tmio_mmc_resume(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct mmc_host *mmc = platform_get_drvdata(dev); int ret = 0; @@ -1229,7 +1229,7 @@ out: static int __devinit tmio_mmc_probe(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_mmc_data *pdata; struct resource *res_ctl; struct tmio_mmc_host *host; @@ -1344,7 +1344,7 @@ out: static int __devexit tmio_mmc_remove(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct mmc_host *mmc = platform_get_drvdata(dev); platform_set_drvdata(dev, NULL); diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 2383b8f2306b..38fb16771f85 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -319,7 +319,7 @@ static int tmio_nand_correct_data(struct mtd_info *mtd, unsigned char *buf, static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); int ret; if (cell->enable) { @@ -363,7 +363,7 @@ static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio) static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); tmio_iowrite8(FCR_MODE_POWER_OFF, tmio->fcr + FCR_MODE); if (cell->disable) @@ -515,7 +515,7 @@ static int tmio_remove(struct platform_device *dev) #ifdef CONFIG_PM static int tmio_suspend(struct platform_device *dev, pm_message_t state) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); if (cell->suspend) cell->suspend(dev); @@ -526,7 +526,7 @@ static int tmio_suspend(struct platform_device *dev, pm_message_t state) static int tmio_resume(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); /* FIXME - is this required or merely another attack of the broken * SHARP platform? Looks suspicious. diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index eeed16461e0d..3558491dd87d 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -185,7 +185,7 @@ static struct platform_driver ohci_hcd_tmio_driver; static int __devinit ohci_hcd_tmio_drv_probe(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct resource *regs = platform_get_resource(dev, IORESOURCE_MEM, 0); struct resource *config = platform_get_resource(dev, IORESOURCE_MEM, 1); struct resource *sram = platform_get_resource(dev, IORESOURCE_MEM, 2); @@ -274,7 +274,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct tmio_hcd *tmio = hcd_to_tmio(hcd); - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); usb_remove_hcd(hcd); tmio_stop_hc(dev); @@ -293,7 +293,7 @@ static int __devexit ohci_hcd_tmio_drv_remove(struct platform_device *dev) #ifdef CONFIG_PM static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct tmio_hcd *tmio = hcd_to_tmio(hcd); @@ -326,7 +326,7 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s static int ohci_hcd_tmio_drv_resume(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct tmio_hcd *tmio = hcd_to_tmio(hcd); diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index 7e57d3baab23..9710bf8caeae 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c @@ -267,7 +267,7 @@ static int tmiofb_hw_stop(struct platform_device *dev) */ static int tmiofb_hw_init(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct fb_info *info = platform_get_drvdata(dev); struct tmiofb_par *par = info->par; const struct resource *nlcr = &cell->resources[0]; @@ -311,7 +311,6 @@ static int tmiofb_hw_init(struct platform_device *dev) */ static void tmiofb_hw_mode(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_fb_data *data = mfd_get_data(dev); struct fb_info *info = platform_get_drvdata(dev); struct fb_videomode *mode = info->mode; @@ -680,7 +679,7 @@ static struct fb_ops tmiofb_ops = { static int __devinit tmiofb_probe(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct tmio_fb_data *data = mfd_get_data(dev); struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1); struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -808,7 +807,7 @@ err_ioremap_ccr: static int __devexit tmiofb_remove(struct platform_device *dev) { - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); struct fb_info *info = platform_get_drvdata(dev); int irq = platform_get_irq(dev, 0); struct tmiofb_par *par; @@ -938,7 +937,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) #ifdef CONFIG_FB_TMIO_ACCELL struct tmiofb_par *par = info->par; #endif - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); int retval = 0; console_lock(); @@ -970,7 +969,7 @@ static int tmiofb_suspend(struct platform_device *dev, pm_message_t state) static int tmiofb_resume(struct platform_device *dev) { struct fb_info *info = platform_get_drvdata(dev); - struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(dev); int retval = 0; console_lock(); -- cgit v1.2.2 From e9300066bbd21c4fba3c8c5475c6a21d9c97694e Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 1 Mar 2011 13:35:48 -0800 Subject: jz4740: silence warnings related to mfd_get_cell changes mfd_get_cell returns a const, so change the jz4740 clients to store a const mfd cell. This silences type mismatch warnings. Signed-off-by: Andres Salomon Acked-by: Anton Vorontsov Signed-off-by: Samuel Ortiz --- drivers/hwmon/jz4740-hwmon.c | 2 +- drivers/power/jz4740-battery.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index 40f106d95afe..fea292d43407 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -32,7 +32,7 @@ struct jz4740_hwmon { int irq; - struct mfd_cell *cell; + const struct mfd_cell *cell; struct device *hwmon; struct completion read_completion; diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index 0938650a466c..763f894ed188 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c @@ -39,7 +39,7 @@ struct jz_battery { int irq; int charge_irq; - struct mfd_cell *cell; + const struct mfd_cell *cell; int status; long voltage; -- cgit v1.2.2 From adceed6263887e04721b477e6504aa24789f827d Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Wed, 2 Mar 2011 11:51:11 +0100 Subject: mfd: ab8500 chip revision 3.0 support This patch adds support for ab8500 chip revision cut 3.0. Also rephrased from Changes to Author in the header. Signed-off-by: Mattias Wallin Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index b6887014d687..8d6c29251dcd 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -4,7 +4,7 @@ * License Terms: GNU General Public License v2 * Author: Srinidhi Kasagar * Author: Rabin Vincent - * Changes: Mattias Wallin + * Author: Mattias Wallin */ #include @@ -686,9 +686,10 @@ int __devinit ab8500_init(struct ab8500 *ab8500) * 0x10 - Cut 1.0 * 0x11 - Cut 1.1 * 0x20 - Cut 2.0 + * 0x30 - Cut 3.0 */ - if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20) { - ab8500->revision = value; + if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 || + value == 0x30) { dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); } else { dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); @@ -764,6 +765,6 @@ int __devexit ab8500_exit(struct ab8500 *ab8500) return 0; } -MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent"); +MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); MODULE_DESCRIPTION("AB8500 MFD core"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From e5c238c3fde93afdddef36aec2642155c709d93a Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Wed, 2 Mar 2011 11:52:36 +0100 Subject: mfd: ab8500-core switch off status added This patch adds a sysfs file with the ab8500 switch off status. The switch off status contains information of what caused the ab8500 chip to power off. A print during boot is also added. Signed-off-by: Mattias Wallin Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 8d6c29251dcd..6e185b272d00 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -90,6 +90,7 @@ #define AB8500_IT_MASK24_REG 0x57 #define AB8500_REV_REG 0x80 +#define AB8500_SWITCH_OFF_STATUS 0x00 /* * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt @@ -652,10 +653,38 @@ static ssize_t show_chip_id(struct device *dev, return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL); } +/* + * ab8500 has switched off due to (SWITCH_OFF_STATUS): + * 0x01 Swoff bit programming + * 0x02 Thermal protection activation + * 0x04 Vbat lower then BattOk falling threshold + * 0x08 Watchdog expired + * 0x10 Non presence of 32kHz clock + * 0x20 Battery level lower than power on reset threshold + * 0x40 Power on key 1 pressed longer than 10 seconds + * 0x80 DB8500 thermal shutdown + */ +static ssize_t show_switch_off_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + u8 value; + struct ab8500 *ab8500; + + ab8500 = dev_get_drvdata(dev); + ret = get_register_interruptible(ab8500, AB8500_RTC, + AB8500_SWITCH_OFF_STATUS, &value); + if (ret < 0) + return ret; + return sprintf(buf, "%#x\n", value); +} + static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL); +static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL); static struct attribute *ab8500_sysfs_entries[] = { &dev_attr_chip_id.attr, + &dev_attr_switch_off_status.attr, NULL, }; @@ -697,6 +726,24 @@ int __devinit ab8500_init(struct ab8500 *ab8500) } ab8500->chip_id = value; + /* + * ab8500 has switched off due to (SWITCH_OFF_STATUS): + * 0x01 Swoff bit programming + * 0x02 Thermal protection activation + * 0x04 Vbat lower then BattOk falling threshold + * 0x08 Watchdog expired + * 0x10 Non presence of 32kHz clock + * 0x20 Battery level lower than power on reset threshold + * 0x40 Power on key 1 pressed longer than 10 seconds + * 0x80 DB8500 thermal shutdown + */ + + ret = get_register_interruptible(ab8500, AB8500_RTC, + AB8500_SWITCH_OFF_STATUS, &value); + if (ret < 0) + return ret; + dev_info(ab8500->dev, "switch off status: %#x", value); + if (plat && plat->init) plat->init(ab8500); -- cgit v1.2.2 From 7e5dc1f7004832f797999dfb3498a68a6c16ef73 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 1 Mar 2011 13:55:07 -0800 Subject: w1: Silence ds1wm warnings related to mfd_get_cell changes mfd_get_cell returns a const, so change the ds1wm client to store a const mfd cell. This silences type mismatch warnings. Since we're guaranteed to have the mfd_cell, we can also simplify the code a bit to get rid of a temporary variable and NULL check. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/w1/masters/ds1wm.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 22fc726feb9b..95921b77cf86 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -90,7 +90,7 @@ struct ds1wm_data { void __iomem *map; int bus_shift; /* # of shifts to calc register offsets */ struct platform_device *pdev; - struct mfd_cell *cell; + const struct mfd_cell *cell; int irq; int active_high; int slave_present; @@ -330,16 +330,11 @@ static int ds1wm_probe(struct platform_device *pdev) struct ds1wm_data *ds1wm_data; struct ds1wm_driver_data *plat; struct resource *res; - struct mfd_cell *cell; int ret; if (!pdev) return -ENODEV; - cell = mfd_get_cell(pdev); - if (!cell) - return -ENODEV; - ds1wm_data = kzalloc(sizeof(*ds1wm_data), GFP_KERNEL); if (!ds1wm_data) return -ENOMEM; @@ -362,7 +357,7 @@ static int ds1wm_probe(struct platform_device *pdev) ds1wm_data->bus_shift = resource_size(res) >> 3; ds1wm_data->pdev = pdev; - ds1wm_data->cell = cell; + ds1wm_data->cell = mfd_get_cell(pdev); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { -- cgit v1.2.2 From f77289ac25b0c81acbed6f9c17cb14809a04e18b Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 3 Mar 2011 09:51:58 -0800 Subject: mfd: Rename mfd_shared_cell_{en,dis}able to drop the "shared" part As requested by Samuel, there's not really any reason to have "shared" in the name. This also modifies the only user of the function, as well. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index bb2264cc410b..79eda0264fb2 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -18,7 +18,7 @@ #include #include -int mfd_shared_cell_enable(struct platform_device *pdev) +int mfd_cell_enable(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); int err = 0; @@ -33,9 +33,9 @@ int mfd_shared_cell_enable(struct platform_device *pdev) return err; } -EXPORT_SYMBOL(mfd_shared_cell_enable); +EXPORT_SYMBOL(mfd_cell_enable); -int mfd_shared_cell_disable(struct platform_device *pdev) +int mfd_cell_disable(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); int err = 0; @@ -53,7 +53,7 @@ int mfd_shared_cell_disable(struct platform_device *pdev) return err; } -EXPORT_SYMBOL(mfd_shared_cell_disable); +EXPORT_SYMBOL(mfd_cell_disable); static int mfd_add_device(struct device *parent, int id, const struct mfd_cell *cell, -- cgit v1.2.2 From 527e7e9a82ec95cdb8f694855004b3d262efd09f Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Fri, 4 Mar 2011 15:50:26 +0900 Subject: mfd: MAX8997/8966 support MAX8997/MAX8966 chip is a multi-function device with I2C bussses. The chip includes PMIC, RTC, Fuel Gauge, MUIC, Haptic, Flash control, and Battery (charging) control. This patch is an initial release of a MAX8997/8966 driver that supports to enable the chip with its primary I2C bus that connects every device mentioned above except for Fuel Gauge, which uses another I2C bus. The fuel gauge is not supported by this mfd driver and is supported by a seperated driver of MAX17042 Fuel Gauge (yes, the fuel gauge part is compatible with MAX17042). Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 12 ++ drivers/mfd/Makefile | 1 + drivers/mfd/max8997.c | 427 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 440 insertions(+) create mode 100644 drivers/mfd/max8997.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 50c476964e48..642168c8d3b1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -314,6 +314,18 @@ config MFD_MAX8925 accessing the device, additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX8997 + bool "Maxim Semiconductor MAX8997/8966 PMIC Support" + depends on I2C=y && GENERIC_HARDIRQS + select MFD_CORE + help + Say yes here to support for Maxim Semiconductor MAX8998/8966. + This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, + MUIC controls on chip. + This driver provies common support for accessing the device, + additional drivers must be enabled in order to use the functionality + of the device. + config MFD_MAX8998 bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" depends on I2C=y && GENERIC_HARDIRQS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 25f3c7551489..0e9f0c51449d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o +obj-$(CONFIG_MFD_MAX8997) += max8997.o obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c new file mode 100644 index 000000000000..5d1fca0277ef --- /dev/null +++ b/drivers/mfd/max8997.c @@ -0,0 +1,427 @@ +/* + * max8997.c - mfd core driver for the Maxim 8966 and 8997 + * + * Copyright (C) 2011 Samsung Electronics + * MyungJoo Ham + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max8998.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#define I2C_ADDR_PMIC (0xCC >> 1) +#define I2C_ADDR_MUIC (0x4A >> 1) +#define I2C_ADDR_BATTERY (0x6C >> 1) +#define I2C_ADDR_RTC (0x0C >> 1) +#define I2C_ADDR_HAPTIC (0x90 >> 1) + +static struct mfd_cell max8997_devs[] = { + { .name = "max8997-pmic", }, + { .name = "max8997-rtc", }, + { .name = "max8997-battery", }, + { .name = "max8997-haptic", }, + { .name = "max8997-muic", }, + { .name = "max8997-flash", }, +}; + +int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) +{ + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&max8997->iolock); + ret = i2c_smbus_read_byte_data(i2c, reg); + mutex_unlock(&max8997->iolock); + if (ret < 0) + return ret; + + ret &= 0xff; + *dest = ret; + return 0; +} +EXPORT_SYMBOL_GPL(max8997_read_reg); + +int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf) +{ + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&max8997->iolock); + ret = i2c_smbus_read_i2c_block_data(i2c, reg, count, buf); + mutex_unlock(&max8997->iolock); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(max8997_bulk_read); + +int max8997_write_reg(struct i2c_client *i2c, u8 reg, u8 value) +{ + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&max8997->iolock); + ret = i2c_smbus_write_byte_data(i2c, reg, value); + mutex_unlock(&max8997->iolock); + return ret; +} +EXPORT_SYMBOL_GPL(max8997_write_reg); + +int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf) +{ + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&max8997->iolock); + ret = i2c_smbus_write_i2c_block_data(i2c, reg, count, buf); + mutex_unlock(&max8997->iolock); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(max8997_bulk_write); + +int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) +{ + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + int ret; + + mutex_lock(&max8997->iolock); + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret >= 0) { + u8 old_val = ret & 0xff; + u8 new_val = (val & mask) | (old_val & (~mask)); + ret = i2c_smbus_write_byte_data(i2c, reg, new_val); + } + mutex_unlock(&max8997->iolock); + return ret; +} +EXPORT_SYMBOL_GPL(max8997_update_reg); + +static int max8997_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max8997_dev *max8997; + struct max8997_platform_data *pdata = i2c->dev.platform_data; + int ret = 0; + + max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL); + if (max8997 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, max8997); + max8997->dev = &i2c->dev; + max8997->i2c = i2c; + max8997->type = id->driver_data; + + if (!pdata) + goto err; + + max8997->wakeup = pdata->wakeup; + + mutex_init(&max8997->iolock); + + max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC); + i2c_set_clientdata(max8997->rtc, max8997); + max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); + i2c_set_clientdata(max8997->haptic, max8997); + max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC); + i2c_set_clientdata(max8997->muic, max8997); + + pm_runtime_set_active(max8997->dev); + + mfd_add_devices(max8997->dev, -1, max8997_devs, + ARRAY_SIZE(max8997_devs), + NULL, 0); + + /* + * TODO: enable others (flash, muic, rtc, battery, ...) and + * check the return value + */ + + if (ret < 0) + goto err_mfd; + + return ret; + +err_mfd: + mfd_remove_devices(max8997->dev); + i2c_unregister_device(max8997->muic); + i2c_unregister_device(max8997->haptic); + i2c_unregister_device(max8997->rtc); +err: + kfree(max8997); + return ret; +} + +static int max8997_i2c_remove(struct i2c_client *i2c) +{ + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + + mfd_remove_devices(max8997->dev); + i2c_unregister_device(max8997->muic); + i2c_unregister_device(max8997->haptic); + i2c_unregister_device(max8997->rtc); + kfree(max8997); + + return 0; +} + +static const struct i2c_device_id max8997_i2c_id[] = { + { "max8997", TYPE_MAX8997 }, + { "max8966", TYPE_MAX8966 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max8998_i2c_id); + +u8 max8997_dumpaddr_pmic[] = { + MAX8997_REG_INT1MSK, + MAX8997_REG_INT2MSK, + MAX8997_REG_INT3MSK, + MAX8997_REG_INT4MSK, + MAX8997_REG_MAINCON1, + MAX8997_REG_MAINCON2, + MAX8997_REG_BUCKRAMP, + MAX8997_REG_BUCK1CTRL, + MAX8997_REG_BUCK1DVS1, + MAX8997_REG_BUCK1DVS2, + MAX8997_REG_BUCK1DVS3, + MAX8997_REG_BUCK1DVS4, + MAX8997_REG_BUCK1DVS5, + MAX8997_REG_BUCK1DVS6, + MAX8997_REG_BUCK1DVS7, + MAX8997_REG_BUCK1DVS8, + MAX8997_REG_BUCK2CTRL, + MAX8997_REG_BUCK2DVS1, + MAX8997_REG_BUCK2DVS2, + MAX8997_REG_BUCK2DVS3, + MAX8997_REG_BUCK2DVS4, + MAX8997_REG_BUCK2DVS5, + MAX8997_REG_BUCK2DVS6, + MAX8997_REG_BUCK2DVS7, + MAX8997_REG_BUCK2DVS8, + MAX8997_REG_BUCK3CTRL, + MAX8997_REG_BUCK3DVS, + MAX8997_REG_BUCK4CTRL, + MAX8997_REG_BUCK4DVS, + MAX8997_REG_BUCK5CTRL, + MAX8997_REG_BUCK5DVS1, + MAX8997_REG_BUCK5DVS2, + MAX8997_REG_BUCK5DVS3, + MAX8997_REG_BUCK5DVS4, + MAX8997_REG_BUCK5DVS5, + MAX8997_REG_BUCK5DVS6, + MAX8997_REG_BUCK5DVS7, + MAX8997_REG_BUCK5DVS8, + MAX8997_REG_BUCK6CTRL, + MAX8997_REG_BUCK6BPSKIPCTRL, + MAX8997_REG_BUCK7CTRL, + MAX8997_REG_BUCK7DVS, + MAX8997_REG_LDO1CTRL, + MAX8997_REG_LDO2CTRL, + MAX8997_REG_LDO3CTRL, + MAX8997_REG_LDO4CTRL, + MAX8997_REG_LDO5CTRL, + MAX8997_REG_LDO6CTRL, + MAX8997_REG_LDO7CTRL, + MAX8997_REG_LDO8CTRL, + MAX8997_REG_LDO9CTRL, + MAX8997_REG_LDO10CTRL, + MAX8997_REG_LDO11CTRL, + MAX8997_REG_LDO12CTRL, + MAX8997_REG_LDO13CTRL, + MAX8997_REG_LDO14CTRL, + MAX8997_REG_LDO15CTRL, + MAX8997_REG_LDO16CTRL, + MAX8997_REG_LDO17CTRL, + MAX8997_REG_LDO18CTRL, + MAX8997_REG_LDO21CTRL, + MAX8997_REG_MBCCTRL1, + MAX8997_REG_MBCCTRL2, + MAX8997_REG_MBCCTRL3, + MAX8997_REG_MBCCTRL4, + MAX8997_REG_MBCCTRL5, + MAX8997_REG_MBCCTRL6, + MAX8997_REG_OTPCGHCVS, + MAX8997_REG_SAFEOUTCTRL, + MAX8997_REG_LBCNFG1, + MAX8997_REG_LBCNFG2, + MAX8997_REG_BBCCTRL, + + MAX8997_REG_FLASH1_CUR, + MAX8997_REG_FLASH2_CUR, + MAX8997_REG_MOVIE_CUR, + MAX8997_REG_GSMB_CUR, + MAX8997_REG_BOOST_CNTL, + MAX8997_REG_LEN_CNTL, + MAX8997_REG_FLASH_CNTL, + MAX8997_REG_WDT_CNTL, + MAX8997_REG_MAXFLASH1, + MAX8997_REG_MAXFLASH2, + MAX8997_REG_FLASHSTATUSMASK, + + MAX8997_REG_GPIOCNTL1, + MAX8997_REG_GPIOCNTL2, + MAX8997_REG_GPIOCNTL3, + MAX8997_REG_GPIOCNTL4, + MAX8997_REG_GPIOCNTL5, + MAX8997_REG_GPIOCNTL6, + MAX8997_REG_GPIOCNTL7, + MAX8997_REG_GPIOCNTL8, + MAX8997_REG_GPIOCNTL9, + MAX8997_REG_GPIOCNTL10, + MAX8997_REG_GPIOCNTL11, + MAX8997_REG_GPIOCNTL12, + + MAX8997_REG_LDO1CONFIG, + MAX8997_REG_LDO2CONFIG, + MAX8997_REG_LDO3CONFIG, + MAX8997_REG_LDO4CONFIG, + MAX8997_REG_LDO5CONFIG, + MAX8997_REG_LDO6CONFIG, + MAX8997_REG_LDO7CONFIG, + MAX8997_REG_LDO8CONFIG, + MAX8997_REG_LDO9CONFIG, + MAX8997_REG_LDO10CONFIG, + MAX8997_REG_LDO11CONFIG, + MAX8997_REG_LDO12CONFIG, + MAX8997_REG_LDO13CONFIG, + MAX8997_REG_LDO14CONFIG, + MAX8997_REG_LDO15CONFIG, + MAX8997_REG_LDO16CONFIG, + MAX8997_REG_LDO17CONFIG, + MAX8997_REG_LDO18CONFIG, + MAX8997_REG_LDO21CONFIG, + + MAX8997_REG_DVSOKTIMER1, + MAX8997_REG_DVSOKTIMER2, + MAX8997_REG_DVSOKTIMER4, + MAX8997_REG_DVSOKTIMER5, +}; + +u8 max8997_dumpaddr_muic[] = { + MAX8997_MUIC_REG_INTMASK1, + MAX8997_MUIC_REG_INTMASK2, + MAX8997_MUIC_REG_INTMASK3, + MAX8997_MUIC_REG_CDETCTRL, + MAX8997_MUIC_REG_CONTROL1, + MAX8997_MUIC_REG_CONTROL2, + MAX8997_MUIC_REG_CONTROL3, +}; + +u8 max8997_dumpaddr_haptic[] = { + MAX8997_HAPTIC_REG_CONF1, + MAX8997_HAPTIC_REG_CONF2, + MAX8997_HAPTIC_REG_DRVCONF, + MAX8997_HAPTIC_REG_CYCLECONF1, + MAX8997_HAPTIC_REG_CYCLECONF2, + MAX8997_HAPTIC_REG_SIGCONF1, + MAX8997_HAPTIC_REG_SIGCONF2, + MAX8997_HAPTIC_REG_SIGCONF3, + MAX8997_HAPTIC_REG_SIGCONF4, + MAX8997_HAPTIC_REG_SIGDC1, + MAX8997_HAPTIC_REG_SIGDC2, + MAX8997_HAPTIC_REG_SIGPWMDC1, + MAX8997_HAPTIC_REG_SIGPWMDC2, + MAX8997_HAPTIC_REG_SIGPWMDC3, + MAX8997_HAPTIC_REG_SIGPWMDC4, +}; + +static int max8997_freeze(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + int i; + + for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++) + max8997_read_reg(i2c, max8997_dumpaddr_pmic[i], + &max8997->reg_dump[i]); + + for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++) + max8997_read_reg(i2c, max8997_dumpaddr_muic[i], + &max8997->reg_dump[i + MAX8997_REG_PMIC_END]); + + for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++) + max8997_read_reg(i2c, max8997_dumpaddr_haptic[i], + &max8997->reg_dump[i + MAX8997_REG_PMIC_END + + MAX8997_MUIC_REG_END]); + + return 0; +} + +static int max8997_restore(struct device *dev) +{ + struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); + struct max8997_dev *max8997 = i2c_get_clientdata(i2c); + int i; + + for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++) + max8997_write_reg(i2c, max8997_dumpaddr_pmic[i], + max8997->reg_dump[i]); + + for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++) + max8997_write_reg(i2c, max8997_dumpaddr_muic[i], + max8997->reg_dump[i + MAX8997_REG_PMIC_END]); + + for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++) + max8997_write_reg(i2c, max8997_dumpaddr_haptic[i], + max8997->reg_dump[i + MAX8997_REG_PMIC_END + + MAX8997_MUIC_REG_END]); + + return 0; +} + +const struct dev_pm_ops max8997_pm = { + .freeze = max8997_freeze, + .restore = max8997_restore, +}; + +static struct i2c_driver max8997_i2c_driver = { + .driver = { + .name = "max8997", + .owner = THIS_MODULE, + .pm = &max8997_pm, + }, + .probe = max8997_i2c_probe, + .remove = max8997_i2c_remove, + .id_table = max8997_i2c_id, +}; + +static int __init max8997_i2c_init(void) +{ + return i2c_add_driver(&max8997_i2c_driver); +} +/* init early so consumer devices can complete system boot */ +subsys_initcall(max8997_i2c_init); + +static void __exit max8997_i2c_exit(void) +{ + i2c_del_driver(&max8997_i2c_driver); +} +module_exit(max8997_i2c_exit); + +MODULE_DESCRIPTION("MAXIM 8997 multi-function core driver"); +MODULE_AUTHOR("MyungJoo Ham "); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From cf16943947cef089c564d2be0ae9d96a285f495e Mon Sep 17 00:00:00 2001 From: Daniel Willerud Date: Sat, 5 Mar 2011 11:46:01 +0100 Subject: mfd: Move ab8500 gpadc header to subdir This moves the ab8500-gpadc.h header down into the ab8500/ subdir in include/linux/mfd and fixes some whitespace in the header in the process. Signed-off-by: Daniel Willerud Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 19339bc439ca..f60f71f4b473 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include /* * GPADC register offsets -- cgit v1.2.2 From 6321992cd3c56bab6cc52e3384951e12616805a1 Mon Sep 17 00:00:00 2001 From: Daniel Willerud Date: Sat, 5 Mar 2011 11:46:13 +0100 Subject: mfd: Reentrance and revamp ab8500 gpadc fetching interface This revamps the interface so that AB8500 GPADCs are fetched by name. Probed GPADCs are added to a list and this list is searched for a matching GPADC. This makes it possible to have multiple AB8500 GPADC instances instead of it being a singleton, and rids the need to keep a GPADC pointer around in the core AB8500 MFD struct. Currently the match is made to the device name which is by default numbered from the device instance such as "ab8500-gpadc.0" but by using the .init_name field of the device a more intiutive naming for the GPADC blocks can be achieved if desired. Signed-off-by: Daniel Willerud Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 115 +++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index f60f71f4b473..178cbc55caea 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -3,6 +3,7 @@ * * License Terms: GNU General Public License v2 * Author: Arun R Murthy + * Author: Daniel Willerud */ #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -48,21 +50,41 @@ /** * struct ab8500_gpadc - ab8500 GPADC device information * @dev: pointer to the struct device - * @parent: pointer to the parent device structure ab8500 + * @node: a list of AB8500 GPADCs, hence prepared for + reentrance * @ab8500_gpadc_complete: pointer to the struct completion, to indicate * the completion of gpadc conversion * @ab8500_gpadc_lock: structure of type mutex * @regu: pointer to the struct regulator * @irq: interrupt number that is used by gpadc */ -static struct ab8500_gpadc { +struct ab8500_gpadc { struct device *dev; - struct ab8500 *parent; + struct list_head node; struct completion ab8500_gpadc_complete; struct mutex ab8500_gpadc_lock; struct regulator *regu; int irq; -} *di; +}; + +static LIST_HEAD(ab8500_gpadc_list); + +/** + * ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC + * (i.e. the first GPADC in the instance list) + */ +struct ab8500_gpadc *ab8500_gpadc_get(char *name) +{ + struct ab8500_gpadc *gpadc; + + list_for_each_entry(gpadc, &ab8500_gpadc_list, node) { + if (!strcmp(name, dev_name(gpadc->dev))) + return gpadc; + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(ab8500_gpadc_get); /** * ab8500_gpadc_convert() - gpadc conversion @@ -72,24 +94,24 @@ static struct ab8500_gpadc { * data. Thereafter calibration has to be made to obtain the * data in the required quantity measurement. */ -int ab8500_gpadc_convert(u8 input) +int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) { int ret; u16 data = 0; int looplimit = 0; u8 val, low_data, high_data; - if (!di) + if (!gpadc) return -ENODEV; - mutex_lock(&di->ab8500_gpadc_lock); + mutex_lock(&gpadc->ab8500_gpadc_lock); /* Enable VTVout LDO this is required for GPADC */ - regulator_enable(di->regu); + regulator_enable(gpadc->regu); /* Check if ADC is not busy, lock and proceed */ do { - ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, - AB8500_GPADC_STAT_REG, &val); + ret = abx500_get_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_STAT_REG, &val); if (ret < 0) goto out; if (!(val & GPADC_BUSY)) @@ -97,75 +119,76 @@ int ab8500_gpadc_convert(u8 input) msleep(10); } while (++looplimit < 10); if (looplimit >= 10 && (val & GPADC_BUSY)) { - dev_err(di->dev, "gpadc_conversion: GPADC busy"); + dev_err(gpadc->dev, "gpadc_conversion: GPADC busy"); ret = -EINVAL; goto out; } /* Enable GPADC */ - ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, - AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC); + ret = abx500_mask_and_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC); if (ret < 0) { - dev_err(di->dev, "gpadc_conversion: enable gpadc failed\n"); + dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n"); goto out; } /* Select the input source and set average samples to 16 */ - ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, + ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16)); if (ret < 0) { - dev_err(di->dev, + dev_err(gpadc->dev, "gpadc_conversion: set avg samples failed\n"); goto out; } /* Enable ADC, Buffering and select rising edge, start Conversion */ - ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, - AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); + ret = abx500_mask_and_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); if (ret < 0) { - dev_err(di->dev, + dev_err(gpadc->dev, "gpadc_conversion: select falling edge failed\n"); goto out; } - ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_GPADC, - AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); + ret = abx500_mask_and_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); if (ret < 0) { - dev_err(di->dev, + dev_err(gpadc->dev, "gpadc_conversion: start s/w conversion failed\n"); goto out; } /* wait for completion of conversion */ - if (!wait_for_completion_timeout(&di->ab8500_gpadc_complete, 2*HZ)) { - dev_err(di->dev, + if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) { + dev_err(gpadc->dev, "timeout: didnt recieve GPADC conversion interrupt\n"); ret = -EINVAL; goto out; } /* Read the converted RAW data */ - ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, + ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_MANDATAL_REG, &low_data); if (ret < 0) { - dev_err(di->dev, "gpadc_conversion: read low data failed\n"); + dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n"); goto out; } - ret = abx500_get_register_interruptible(di->dev, AB8500_GPADC, + ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_MANDATAH_REG, &high_data); if (ret < 0) { - dev_err(di->dev, "gpadc_conversion: read high data failed\n"); + dev_err(gpadc->dev, + "gpadc_conversion: read high data failed\n"); goto out; } data = (high_data << 8) | low_data; /* Disable GPADC */ - ret = abx500_set_register_interruptible(di->dev, AB8500_GPADC, + ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_CTRL1_REG, DIS_GPADC); if (ret < 0) { - dev_err(di->dev, "gpadc_conversion: disable gpadc failed\n"); + dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n"); goto out; } /* Disable VTVout LDO this is required for GPADC */ - regulator_disable(di->regu); - mutex_unlock(&di->ab8500_gpadc_lock); + regulator_disable(gpadc->regu); + mutex_unlock(&gpadc->ab8500_gpadc_lock); return data; out: @@ -175,12 +198,12 @@ out: * GPADC status register to go low. In V1.1 there wait_for_completion * seems to timeout when waiting for an interrupt.. Not seen in V2.0 */ - (void) abx500_set_register_interruptible(di->dev, AB8500_GPADC, + (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_CTRL1_REG, DIS_GPADC); - regulator_disable(di->regu); - mutex_unlock(&di->ab8500_gpadc_lock); - dev_err(di->dev, "gpadc_conversion: Failed to AD convert channel %d\n", - input); + regulator_disable(gpadc->regu); + mutex_unlock(&gpadc->ab8500_gpadc_lock); + dev_err(gpadc->dev, + "gpadc_conversion: Failed to AD convert channel %d\n", input); return ret; } EXPORT_SYMBOL(ab8500_gpadc_convert); @@ -195,9 +218,9 @@ EXPORT_SYMBOL(ab8500_gpadc_convert); * can be read from the registers. * Returns IRQ status(IRQ_HANDLED) */ -static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_di) +static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc) { - struct ab8500_gpadc *gpadc = _di; + struct ab8500_gpadc *gpadc = _gpadc; complete(&gpadc->ab8500_gpadc_complete); @@ -215,16 +238,16 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) return -ENOMEM; } - gpadc->parent = dev_get_drvdata(pdev->dev.parent); gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END"); if (gpadc->irq < 0) { - dev_err(gpadc->dev, "failed to get platform irq-%d\n", di->irq); + dev_err(gpadc->dev, "failed to get platform irq-%d\n", + gpadc->irq); ret = gpadc->irq; goto fail; } gpadc->dev = &pdev->dev; - mutex_init(&di->ab8500_gpadc_lock); + mutex_init(&gpadc->ab8500_gpadc_lock); /* Initialize completion used to notify completion of conversion */ init_completion(&gpadc->ab8500_gpadc_complete); @@ -246,7 +269,7 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) dev_err(gpadc->dev, "failed to get vtvout LDO\n"); goto fail; } - di = gpadc; + list_add_tail(&gpadc->node, &ab8500_gpadc_list); dev_dbg(gpadc->dev, "probe success\n"); return 0; fail: @@ -259,8 +282,10 @@ static int __devexit ab8500_gpadc_remove(struct platform_device *pdev) { struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); + /* remove this gpadc entry from the list */ + list_del(&gpadc->node); /* remove interrupt - completion of Sw ADC conversion */ - free_irq(gpadc->irq, di); + free_irq(gpadc->irq, gpadc); /* disable VTVout LDO that is being used by GPADC */ regulator_put(gpadc->regu); kfree(gpadc); @@ -291,6 +316,6 @@ subsys_initcall_sync(ab8500_gpadc_init); module_exit(ab8500_gpadc_exit); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Arun R Murthy"); +MODULE_AUTHOR("Arun R Murthy, Daniel Willerud"); MODULE_ALIAS("platform:ab8500_gpadc"); MODULE_DESCRIPTION("AB8500 GPADC driver"); -- cgit v1.2.2 From 633e0fa59072f5d78227191b212cb12ad3d21902 Mon Sep 17 00:00:00 2001 From: Daniel Willerud Date: Sat, 5 Mar 2011 11:46:27 +0100 Subject: mfd: Free dangling irq in ab8500 gpadc probe error path Signed-off-by: Daniel Willerud Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 178cbc55caea..b5b75b74e86c 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -267,11 +267,13 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) if (IS_ERR(gpadc->regu)) { ret = PTR_ERR(gpadc->regu); dev_err(gpadc->dev, "failed to get vtvout LDO\n"); - goto fail; + goto fail_irq; } list_add_tail(&gpadc->node, &ab8500_gpadc_list); dev_dbg(gpadc->dev, "probe success\n"); return 0; +fail_irq: + free_irq(gpadc->irq, gpadc); fail: kfree(gpadc); gpadc = NULL; -- cgit v1.2.2 From 586f3318adceee4857e82cafc3610070368754e3 Mon Sep 17 00:00:00 2001 From: Johan Palsson Date: Sat, 5 Mar 2011 11:46:37 +0100 Subject: mfd: Calibrate ab8500 gpadc using OTP values The GPADC found in the AB8500 needs to be calibrated to work properly. This is done by writing a number of special OTP (one-time-programmable) registers at production. This patch makes sure that these values are used to calibrate the returned value from the GPADC so that it is correct. Signed-off-by: Johan Palsson Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 286 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 281 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index b5b75b74e86c..a70201a74729 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -4,6 +4,7 @@ * License Terms: GNU General Public License v2 * Author: Arun R Murthy * Author: Daniel Willerud + * Author: Johan Palsson */ #include #include @@ -36,6 +37,18 @@ #define AB8500_GPADC_AUTODATAH_REG 0x08 #define AB8500_GPADC_MUX_CTRL_REG 0x09 +/* + * OTP register offsets + * Bank : 0x15 + */ +#define AB8500_GPADC_CAL_1 0x0F +#define AB8500_GPADC_CAL_2 0x10 +#define AB8500_GPADC_CAL_3 0x11 +#define AB8500_GPADC_CAL_4 0x12 +#define AB8500_GPADC_CAL_5 0x13 +#define AB8500_GPADC_CAL_6 0x14 +#define AB8500_GPADC_CAL_7 0x15 + /* gpadc constants */ #define EN_VINTCORE12 0x04 #define EN_VTVOUT 0x02 @@ -47,8 +60,46 @@ #define DIS_ZERO 0x00 #define GPADC_BUSY 0x01 +/* GPADC constants from AB8500 spec, UM0836 */ +#define ADC_RESOLUTION 1024 +#define ADC_CH_BTEMP_MIN 0 +#define ADC_CH_BTEMP_MAX 1350 +#define ADC_CH_DIETEMP_MIN 0 +#define ADC_CH_DIETEMP_MAX 1350 +#define ADC_CH_CHG_V_MIN 0 +#define ADC_CH_CHG_V_MAX 20030 +#define ADC_CH_ACCDET2_MIN 0 +#define ADC_CH_ACCDET2_MAX 2500 +#define ADC_CH_VBAT_MIN 2300 +#define ADC_CH_VBAT_MAX 4800 +#define ADC_CH_CHG_I_MIN 0 +#define ADC_CH_CHG_I_MAX 1500 +#define ADC_CH_BKBAT_MIN 0 +#define ADC_CH_BKBAT_MAX 3200 + +/* This is used to not lose precision when dividing to get gain and offset */ +#define CALIB_SCALE 1000 + +enum cal_channels { + ADC_INPUT_VMAIN = 0, + ADC_INPUT_BTEMP, + ADC_INPUT_VBAT, + NBR_CAL_INPUTS, +}; + +/** + * struct adc_cal_data - Table for storing gain and offset for the calibrated + * ADC channels + * @gain: Gain of the ADC channel + * @offset: Offset of the ADC channel + */ +struct adc_cal_data { + u64 gain; + u64 offset; +}; + /** - * struct ab8500_gpadc - ab8500 GPADC device information + * struct ab8500_gpadc - AB8500 GPADC device information * @dev: pointer to the struct device * @node: a list of AB8500 GPADCs, hence prepared for reentrance @@ -57,6 +108,7 @@ * @ab8500_gpadc_lock: structure of type mutex * @regu: pointer to the struct regulator * @irq: interrupt number that is used by gpadc + * @cal_data array of ADC calibration data structs */ struct ab8500_gpadc { struct device *dev; @@ -65,6 +117,7 @@ struct ab8500_gpadc { struct mutex ab8500_gpadc_lock; struct regulator *regu; int irq; + struct adc_cal_data cal_data[NBR_CAL_INPUTS]; }; static LIST_HEAD(ab8500_gpadc_list); @@ -86,13 +139,102 @@ struct ab8500_gpadc *ab8500_gpadc_get(char *name) } EXPORT_SYMBOL(ab8500_gpadc_get); +static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 input, + int ad_value) +{ + int res; + + switch (input) { + case MAIN_CHARGER_V: + /* For some reason we don't have calibrated data */ + if (!gpadc->cal_data[ADC_INPUT_VMAIN].gain) { + res = ADC_CH_CHG_V_MIN + (ADC_CH_CHG_V_MAX - + ADC_CH_CHG_V_MIN) * ad_value / + ADC_RESOLUTION; + break; + } + /* Here we can use the calibrated data */ + res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VMAIN].gain + + gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE; + break; + + case BAT_CTRL: + case BTEMP_BALL: + case ACC_DETECT1: + case ADC_AUX1: + case ADC_AUX2: + /* For some reason we don't have calibrated data */ + if (!gpadc->cal_data[ADC_INPUT_BTEMP].gain) { + res = ADC_CH_BTEMP_MIN + (ADC_CH_BTEMP_MAX - + ADC_CH_BTEMP_MIN) * ad_value / + ADC_RESOLUTION; + break; + } + /* Here we can use the calibrated data */ + res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_BTEMP].gain + + gpadc->cal_data[ADC_INPUT_BTEMP].offset) / CALIB_SCALE; + break; + + case MAIN_BAT_V: + /* For some reason we don't have calibrated data */ + if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) { + res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX - + ADC_CH_VBAT_MIN) * ad_value / + ADC_RESOLUTION; + break; + } + /* Here we can use the calibrated data */ + res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VBAT].gain + + gpadc->cal_data[ADC_INPUT_VBAT].offset) / CALIB_SCALE; + break; + + case DIE_TEMP: + res = ADC_CH_DIETEMP_MIN + + (ADC_CH_DIETEMP_MAX - ADC_CH_DIETEMP_MIN) * ad_value / + ADC_RESOLUTION; + break; + + case ACC_DETECT2: + res = ADC_CH_ACCDET2_MIN + + (ADC_CH_ACCDET2_MAX - ADC_CH_ACCDET2_MIN) * ad_value / + ADC_RESOLUTION; + break; + + case VBUS_V: + res = ADC_CH_CHG_V_MIN + + (ADC_CH_CHG_V_MAX - ADC_CH_CHG_V_MIN) * ad_value / + ADC_RESOLUTION; + break; + + case MAIN_CHARGER_C: + case USB_CHARGER_C: + res = ADC_CH_CHG_I_MIN + + (ADC_CH_CHG_I_MAX - ADC_CH_CHG_I_MIN) * ad_value / + ADC_RESOLUTION; + break; + + case BK_BAT_V: + res = ADC_CH_BKBAT_MIN + + (ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * ad_value / + ADC_RESOLUTION; + break; + + default: + dev_err(gpadc->dev, + "unknown channel, not possible to convert\n"); + res = -EINVAL; + break; + + } + return res; +} + /** * ab8500_gpadc_convert() - gpadc conversion * @input: analog input to be converted to digital data * * This function converts the selected analog i/p to digital - * data. Thereafter calibration has to be made to obtain the - * data in the required quantity measurement. + * data. */ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) { @@ -189,7 +331,8 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) /* Disable VTVout LDO this is required for GPADC */ regulator_disable(gpadc->regu); mutex_unlock(&gpadc->ab8500_gpadc_lock); - return data; + ret = ab8500_gpadc_ad_to_voltage(gpadc, input, data); + return ret; out: /* @@ -227,6 +370,138 @@ static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc) return IRQ_HANDLED; } +static int otp_cal_regs[] = { + AB8500_GPADC_CAL_1, + AB8500_GPADC_CAL_2, + AB8500_GPADC_CAL_3, + AB8500_GPADC_CAL_4, + AB8500_GPADC_CAL_5, + AB8500_GPADC_CAL_6, + AB8500_GPADC_CAL_7, +}; + +static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) +{ + int i; + int ret[ARRAY_SIZE(otp_cal_regs)]; + u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)]; + + int vmain_high, vmain_low; + int btemp_high, btemp_low; + int vbat_high, vbat_low; + + /* First we read all OTP registers and store the error code */ + for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) { + ret[i] = abx500_get_register_interruptible(gpadc->dev, + AB8500_OTP_EMUL, otp_cal_regs[i], &gpadc_cal[i]); + if (ret[i] < 0) + dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n", + __func__, otp_cal_regs[i]); + } + + /* + * The ADC calibration data is stored in OTP registers. + * The layout of the calibration data is outlined below and a more + * detailed description can be found in UM0836 + * + * vm_h/l = vmain_high/low + * bt_h/l = btemp_high/low + * vb_h/l = vbat_high/low + * + * Data bits: + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | | vm_h9 | vm_h8 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | + * |.......|.......|.......|.......|.......|.......|.......|....... + * + * + * Ideal output ADC codes corresponding to injected input voltages + * during manufacturing is: + * + * vmain_high: Vin = 19500mV / ADC ideal code = 997 + * vmain_low: Vin = 315mV / ADC ideal code = 16 + * btemp_high: Vin = 1300mV / ADC ideal code = 985 + * btemp_low: Vin = 21mV / ADC ideal code = 16 + * vbat_high: Vin = 4700mV / ADC ideal code = 982 + * vbat_low: Vin = 2380mV / ADC ideal code = 33 + */ + + /* Calculate gain and offset for VMAIN if all reads succeeded */ + if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) { + vmain_high = (((gpadc_cal[0] & 0x03) << 8) | + ((gpadc_cal[1] & 0x3F) << 2) | + ((gpadc_cal[2] & 0xC0) >> 6)); + + vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); + + gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE * + (19500 - 315) / (vmain_high - vmain_low); + + gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 - + (CALIB_SCALE * (19500 - 315) / + (vmain_high - vmain_low)) * vmain_high; + } else { + gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0; + } + + /* Calculate gain and offset for BTEMP if all reads succeeded */ + if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) { + btemp_high = (((gpadc_cal[2] & 0x01) << 9) | + (gpadc_cal[3] << 1) | + ((gpadc_cal[4] & 0x80) >> 7)); + + btemp_low = ((gpadc_cal[4] & 0x7C) >> 2); + + gpadc->cal_data[ADC_INPUT_BTEMP].gain = + CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low); + + gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 - + (CALIB_SCALE * (1300 - 21) / + (btemp_high - btemp_low)) * btemp_high; + } else { + gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0; + } + + /* Calculate gain and offset for VBAT if all reads succeeded */ + if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) { + vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]); + vbat_low = ((gpadc_cal[6] & 0xFC) >> 2); + + gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE * + (4700 - 2380) / (vbat_high - vbat_low); + + gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 - + (CALIB_SCALE * (4700 - 2380) / + (vbat_high - vbat_low)) * vbat_high; + } else { + gpadc->cal_data[ADC_INPUT_VBAT].gain = 0; + } + + dev_dbg(gpadc->dev, "VMAIN gain %llu offset %llu\n", + gpadc->cal_data[ADC_INPUT_VMAIN].gain, + gpadc->cal_data[ADC_INPUT_VMAIN].offset); + + dev_dbg(gpadc->dev, "BTEMP gain %llu offset %llu\n", + gpadc->cal_data[ADC_INPUT_BTEMP].gain, + gpadc->cal_data[ADC_INPUT_BTEMP].offset); + + dev_dbg(gpadc->dev, "VBAT gain %llu offset %llu\n", + gpadc->cal_data[ADC_INPUT_VBAT].gain, + gpadc->cal_data[ADC_INPUT_VBAT].offset); +} + static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) { int ret = 0; @@ -269,6 +544,7 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) dev_err(gpadc->dev, "failed to get vtvout LDO\n"); goto fail_irq; } + ab8500_gpadc_read_calibration_data(gpadc); list_add_tail(&gpadc->node, &ab8500_gpadc_list); dev_dbg(gpadc->dev, "probe success\n"); return 0; @@ -318,6 +594,6 @@ subsys_initcall_sync(ab8500_gpadc_init); module_exit(ab8500_gpadc_exit); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Arun R Murthy, Daniel Willerud"); +MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson"); MODULE_ALIAS("platform:ab8500_gpadc"); MODULE_DESCRIPTION("AB8500 GPADC driver"); -- cgit v1.2.2 From 4aad5a918c919c04b6c3136f3c4dcafada3b6319 Mon Sep 17 00:00:00 2001 From: Karl Komierowski Date: Sat, 5 Mar 2011 11:46:45 +0100 Subject: mfd: Fix ab8500-gpadc to measure charger current The GPADC in the AB8500 was incorrectly configured when a charger current channel was selected. Signed-off-by: Karl Komierowski Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index a70201a74729..2ad3115f7772 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -56,6 +56,7 @@ #define DIS_GPADC 0x00 #define SW_AVG_16 0x60 #define ADC_SW_CONV 0x04 +#define EN_ICHAR 0x80 #define EN_BUF 0x40 #define DIS_ZERO 0x00 #define GPADC_BUSY 0x01 @@ -281,9 +282,23 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) "gpadc_conversion: set avg samples failed\n"); goto out; } - /* Enable ADC, Buffering and select rising edge, start Conversion */ - ret = abx500_mask_and_set_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); + /* + * Enable ADC, buffering, select rising edge and enable ADC path + * charging current sense if it needed + */ + switch (input) { + case MAIN_CHARGER_C: + case USB_CHARGER_C: + ret = abx500_mask_and_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, + EN_BUF | EN_ICHAR, + EN_BUF | EN_ICHAR); + break; + default: + ret = abx500_mask_and_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); + break; + } if (ret < 0) { dev_err(gpadc->dev, "gpadc_conversion: select falling edge failed\n"); -- cgit v1.2.2 From 0ea3e83bd8d198f2a18e0066542f8670b2883890 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 7 Mar 2011 11:02:29 +0800 Subject: mfd: Add "platform:" prefix for twl4030-madc platform modalias Since 43cc71eed1250755986da4c0f9898f9a635cb3bf (platform: prefix MODALIAS with "platform:"), the platform modalias is prefixed with "platform:". Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-madc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index e9884e2583bf..3941ddcf15fe 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -799,4 +799,4 @@ module_exit(twl4030_madc_exit); MODULE_DESCRIPTION("TWL4030 ADC driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("J Keerthy"); -MODULE_ALIAS("twl4030_madc"); +MODULE_ALIAS("platform:twl4030_madc"); -- cgit v1.2.2 From d7e8c01a97429101cb0ca2c09380e683c3814af8 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 14 Mar 2011 11:28:37 +0100 Subject: mfd: Fix MAX8997 Kconfig entry typos Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 642168c8d3b1..500a130857d8 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -322,7 +322,7 @@ config MFD_MAX8997 Say yes here to support for Maxim Semiconductor MAX8998/8966. This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, MUIC controls on chip. - This driver provies common support for accessing the device, + This driver provides common support for accessing the device; additional drivers must be enabled in order to use the functionality of the device. -- cgit v1.2.2 From adb70483f4d560323db9aaca5f066fde4d96f339 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 7 Mar 2011 23:43:09 +0800 Subject: mfd: Adopt mfd_data in 88pm860x backlight Copy 88pm860x platform data into different mfd_data structure for backlight driver. So move the identification of device node from backlight driver to mfd driver. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 96 +++++++++++++++++++---------------- drivers/video/backlight/88pm860x_bl.c | 34 +++---------- 2 files changed, 59 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 793300c554b4..a88967a466cb 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -20,12 +20,19 @@ #define INT_STATUS_NUM 3 -char pm860x_backlight_name[][MFD_NAME_SIZE] = { - "backlight-0", - "backlight-1", - "backlight-2", +static struct resource bk_resources[] __initdata = { + {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,}, + {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,}, + {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, }; -EXPORT_SYMBOL(pm860x_backlight_name); + +static struct mfd_cell bk_devs[] __initdata = { + {"88pm860x-backlight", 0,}, + {"88pm860x-backlight", 1,}, + {"88pm860x-backlight", 2,}, +}; + +static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; char pm860x_led_name[][MFD_NAME_SIZE] = { "led0-red", @@ -37,34 +44,6 @@ char pm860x_led_name[][MFD_NAME_SIZE] = { }; EXPORT_SYMBOL(pm860x_led_name); -#define PM8606_BACKLIGHT_RESOURCE(_i, _x) \ -{ \ - .name = pm860x_backlight_name[_i], \ - .start = PM8606_##_x, \ - .end = PM8606_##_x, \ - .flags = IORESOURCE_IO, \ -} - -static struct resource backlight_resources[] = { - PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A), - PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A), - PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A), -}; - -#define PM8606_BACKLIGHT_DEVS(_i) \ -{ \ - .name = "88pm860x-backlight", \ - .num_resources = 1, \ - .resources = &backlight_resources[_i], \ - .id = _i, \ -} - -static struct mfd_cell backlight_devs[] = { - PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1), - PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2), - PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3), -}; - #define PM8606_LED_RESOURCE(_i, _x) \ { \ .name = pm860x_led_name[_i], \ @@ -595,23 +574,49 @@ static void device_irq_exit(struct pm860x_chip *chip) free_irq(chip->core_irq, chip); } +static void __devinit device_bk_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + int ret; + int i, j, id; + + if ((pdata == NULL) || (pdata->backlight == NULL)) + return; + + if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) + pdata->num_backlights = ARRAY_SIZE(bk_devs); + + for (i = 0; i < pdata->num_backlights; i++) { + memcpy(&bk_pdata[i], &pdata->backlight[i], + sizeof(struct pm860x_backlight_pdata)); + bk_devs[i].mfd_data = &bk_pdata[i]; + + for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { + id = bk_resources[j].start; + if (bk_pdata[i].flags != id) + continue; + + bk_devs[i].num_resources = 1; + bk_devs[i].resources = &bk_resources[j]; + ret = mfd_add_devices(chip->dev, 0, + &bk_devs[i], 1, + &bk_resources[j], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add " + "backlight subdev\n"); + return; + } + } + } +} + static void __devinit device_8606_init(struct pm860x_chip *chip, struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; - if (pdata && pdata->backlight) { - ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], - ARRAY_SIZE(backlight_devs), - &backlight_resources[0], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add backlight " - "subdev\n"); - goto out_dev; - } - } - if (pdata && pdata->led) { ret = mfd_add_devices(chip->dev, 0, &led_devs[0], ARRAY_SIZE(led_devs), @@ -624,7 +629,6 @@ static void __devinit device_8606_init(struct pm860x_chip *chip, } return; out_dev: - mfd_remove_devices(chip->dev); device_irq_exit(chip); } @@ -743,6 +747,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, switch (chip->id) { case CHIP_PM8606: + device_bk_init(chip, chip->client, pdata); device_8606_init(chip, chip->client, pdata); break; case CHIP_PM8607: @@ -753,6 +758,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, if (chip->companion) { switch (chip->id) { case CHIP_PM8607: + device_bk_init(chip, chip->companion, pdata); device_8606_init(chip, chip->companion, pdata); break; case CHIP_PM8606: diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index e59623a15f3f..c8b520e9a11a 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -12,11 +12,12 @@ #include #include #include +#include #include #include #include +#include #include -#include #define MAX_BRIGHTNESS (0xFF) #define MIN_BRIGHTNESS (0) @@ -161,32 +162,13 @@ static const struct backlight_ops pm860x_backlight_ops = { .get_brightness = pm860x_backlight_get_brightness, }; -static int __check_device(struct pm860x_backlight_pdata *pdata, char *name) -{ - struct pm860x_backlight_pdata *p = pdata; - int ret = -EINVAL; - - while (p && p->id) { - if ((p->id != PM8606_ID_BACKLIGHT) || (p->flags < 0)) - break; - - if (!strncmp(name, pm860x_backlight_name[p->flags], - MFD_NAME_SIZE)) { - ret = (int)p->flags; - break; - } - p++; - } - return ret; -} - static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_platform_data *pm860x_pdata; struct pm860x_backlight_pdata *pdata = NULL; struct pm860x_backlight_data *data; struct backlight_device *bl; + struct mfd_cell *cell; struct resource *res; struct backlight_properties props; unsigned char value; @@ -199,10 +181,10 @@ static int pm860x_backlight_probe(struct platform_device *pdev) return -EINVAL; } - if (pdev->dev.parent->platform_data) { - pm860x_pdata = pdev->dev.parent->platform_data; - pdata = pm860x_pdata->backlight; - } + cell = pdev->dev.platform_data; + if (cell == NULL) + return -ENODEV; + pdata = cell->mfd_data; if (pdata == NULL) { dev_err(&pdev->dev, "platform data isn't assigned to " "backlight\n"); @@ -219,7 +201,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) data->current_brightness = MAX_BRIGHTNESS; data->pwm = pdata->pwm; data->iset = pdata->iset; - data->port = __check_device(pdata, name); + data->port = pdata->flags; if (data->port < 0) { dev_err(&pdev->dev, "wrong platform data is assigned"); kfree(data); -- cgit v1.2.2 From 3154c344696e58b7e15317cd624816dbe3832ad1 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 7 Mar 2011 23:43:10 +0800 Subject: mfd: Adopt mfd_data in 88pm860x led Copy 88pm860x platform data into different mfd_data structure for led driver. So move the identification of device node from led driver to mfd driver. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/leds/leds-88pm860x.c | 60 +++++++++++------------- drivers/mfd/88pm860x-core.c | 109 ++++++++++++++++++++----------------------- 2 files changed, 78 insertions(+), 91 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index e672b44ee172..416def84d045 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define LED_PWM_SHIFT (3) @@ -118,7 +119,8 @@ static void pm860x_led_work(struct work_struct *work) struct pm860x_led *led; struct pm860x_chip *chip; - int mask; + unsigned char buf[3]; + int mask, ret; led = container_of(work, struct pm860x_led, work); chip = led->chip; @@ -128,16 +130,27 @@ static void pm860x_led_work(struct work_struct *work) pm860x_set_bits(led->i2c, __led_off(led->port), LED_CURRENT_MASK, led->iset); } + pm860x_set_bits(led->i2c, __blink_off(led->port), + LED_BLINK_MASK, LED_ON_CONTINUOUS); mask = __blink_ctl_mask(led->port); pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); - } else if (led->brightness == 0) { - pm860x_set_bits(led->i2c, __led_off(led->port), - LED_CURRENT_MASK, 0); - mask = __blink_ctl_mask(led->port); - pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); } pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, led->brightness); + + if (led->brightness == 0) { + pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf); + ret = buf[0] & LED_PWM_MASK; + ret |= buf[1] & LED_PWM_MASK; + ret |= buf[2] & LED_PWM_MASK; + if (ret == 0) { + /* unset current since no led is lighting */ + pm860x_set_bits(led->i2c, __led_off(led->port), + LED_CURRENT_MASK, 0); + mask = __blink_ctl_mask(led->port); + pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); + } + } led->current_brightness = led->brightness; dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", __led_off(led->port), led->brightness); @@ -153,31 +166,12 @@ static void pm860x_led_set(struct led_classdev *cdev, schedule_work(&data->work); } -static int __check_device(struct pm860x_led_pdata *pdata, char *name) -{ - struct pm860x_led_pdata *p = pdata; - int ret = -EINVAL; - - while (p && p->id) { - if ((p->id != PM8606_ID_LED) || (p->flags < 0)) - break; - - if (!strncmp(name, pm860x_led_name[p->flags], - MFD_NAME_SIZE)) { - ret = (int)p->flags; - break; - } - p++; - } - return ret; -} - static int pm860x_led_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_platform_data *pm860x_pdata; struct pm860x_led_pdata *pdata; struct pm860x_led *data; + struct mfd_cell *cell; struct resource *res; int ret; @@ -187,10 +181,11 @@ static int pm860x_led_probe(struct platform_device *pdev) return -EINVAL; } - if (pdev->dev.parent->platform_data) { - pm860x_pdata = pdev->dev.parent->platform_data; - pdata = pm860x_pdata->led; - } else { + cell = pdev->dev.platform_data; + if (cell == NULL) + return -ENODEV; + pdata = cell->mfd_data; + if (pdata == NULL) { dev_err(&pdev->dev, "No platform data!\n"); return -EINVAL; } @@ -198,12 +193,12 @@ static int pm860x_led_probe(struct platform_device *pdev) data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(data->name, res->name, MFD_NAME_SIZE); + strncpy(data->name, res->name, MFD_NAME_SIZE - 1); dev_set_drvdata(&pdev->dev, data); data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; data->iset = pdata->iset; - data->port = __check_device(pdata, data->name); + data->port = pdata->flags; if (data->port < 0) { dev_err(&pdev->dev, "check device failed\n"); kfree(data); @@ -221,6 +216,7 @@ static int pm860x_led_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to register LED: %d\n", ret); goto out; } + pm860x_led_set(&data->cdev, 0); return 0; out: kfree(data); diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index a88967a466cb..cec375c534b8 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -26,57 +26,32 @@ static struct resource bk_resources[] __initdata = { {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, }; +static struct resource led_resources[] __initdata = { + {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,}, + {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,}, + {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,}, + {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,}, + {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,}, + {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, +}; + static struct mfd_cell bk_devs[] __initdata = { {"88pm860x-backlight", 0,}, {"88pm860x-backlight", 1,}, {"88pm860x-backlight", 2,}, }; -static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; - -char pm860x_led_name[][MFD_NAME_SIZE] = { - "led0-red", - "led0-green", - "led0-blue", - "led1-red", - "led1-green", - "led1-blue", -}; -EXPORT_SYMBOL(pm860x_led_name); - -#define PM8606_LED_RESOURCE(_i, _x) \ -{ \ - .name = pm860x_led_name[_i], \ - .start = PM8606_##_x, \ - .end = PM8606_##_x, \ - .flags = IORESOURCE_IO, \ -} - -static struct resource led_resources[] = { - PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B), - PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C), - PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D), - PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B), - PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C), - PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D), +static struct mfd_cell led_devs[] __initdata = { + {"88pm860x-led", 0,}, + {"88pm860x-led", 1,}, + {"88pm860x-led", 2,}, + {"88pm860x-led", 3,}, + {"88pm860x-led", 4,}, + {"88pm860x-led", 5,}, }; -#define PM8606_LED_DEVS(_i) \ -{ \ - .name = "88pm860x-led", \ - .num_resources = 1, \ - .resources = &led_resources[_i], \ - .id = _i, \ -} - -static struct mfd_cell led_devs[] = { - PM8606_LED_DEVS(PM8606_LED1_RED), - PM8606_LED_DEVS(PM8606_LED1_GREEN), - PM8606_LED_DEVS(PM8606_LED1_BLUE), - PM8606_LED_DEVS(PM8606_LED2_RED), - PM8606_LED_DEVS(PM8606_LED2_GREEN), - PM8606_LED_DEVS(PM8606_LED2_BLUE), -}; +static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; +static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)]; static struct resource touch_resources[] = { { @@ -611,25 +586,41 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, } } -static void __devinit device_8606_init(struct pm860x_chip *chip, - struct i2c_client *i2c, - struct pm860x_platform_data *pdata) +static void __devinit device_led_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) { int ret; + int i, j, id; - if (pdata && pdata->led) { - ret = mfd_add_devices(chip->dev, 0, &led_devs[0], - ARRAY_SIZE(led_devs), - &led_resources[0], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add led " - "subdev\n"); - goto out_dev; + if ((pdata == NULL) || (pdata->led == NULL)) + return; + + if (pdata->num_leds > ARRAY_SIZE(led_devs)) + pdata->num_leds = ARRAY_SIZE(led_devs); + + for (i = 0; i < pdata->num_leds; i++) { + memcpy(&led_pdata[i], &pdata->led[i], + sizeof(struct pm860x_led_pdata)); + led_devs[i].mfd_data = &led_pdata[i]; + + for (j = 0; j < ARRAY_SIZE(led_devs); j++) { + id = led_resources[j].start; + if (led_pdata[i].flags != id) + continue; + + led_devs[i].num_resources = 1; + led_devs[i].resources = &led_resources[j], + ret = mfd_add_devices(chip->dev, 0, + &led_devs[i], 1, + &led_resources[j], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add " + "led subdev\n"); + return; + } } } - return; -out_dev: - device_irq_exit(chip); } static void __devinit device_8607_init(struct pm860x_chip *chip, @@ -748,7 +739,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, switch (chip->id) { case CHIP_PM8606: device_bk_init(chip, chip->client, pdata); - device_8606_init(chip, chip->client, pdata); + device_led_init(chip, chip->client, pdata); break; case CHIP_PM8607: device_8607_init(chip, chip->client, pdata); @@ -759,7 +750,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, switch (chip->id) { case CHIP_PM8607: device_bk_init(chip, chip->companion, pdata); - device_8606_init(chip, chip->companion, pdata); + device_led_init(chip, chip->companion, pdata); break; case CHIP_PM8606: device_8607_init(chip, chip->companion, pdata); -- cgit v1.2.2 From 22aad0011e4728a29bf3775b6f5e2f9677abd8c0 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 7 Mar 2011 23:43:11 +0800 Subject: mfd: Adopt mfd_data in 88pm860x regulator Copy 88pm860x platform data into different mfd_data structure for regulator driver. So move the identification of device node from regulator driver to mfd driver. Signed-off-by: Haojian Zhuang Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 165 +++++++++++++++++++++++++++---------------- drivers/regulator/88pm8607.c | 46 ++++++------ 2 files changed, 128 insertions(+), 83 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index cec375c534b8..96ea0c64bbbc 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -17,6 +17,7 @@ #include #include #include +#include #define INT_STATUS_NUM 3 @@ -35,6 +36,27 @@ static struct resource led_resources[] __initdata = { {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, }; +static struct resource regulator_resources[] __initdata = { + {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,}, + {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,}, + {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,}, + {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,}, + {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,}, + {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,}, + {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,}, + {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,}, + {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,}, + {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,}, + {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,}, + {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,}, + {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,}, + {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,}, + {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,}, + {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,}, + {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,}, + {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, +}; + static struct mfd_cell bk_devs[] __initdata = { {"88pm860x-backlight", 0,}, {"88pm860x-backlight", 1,}, @@ -50,8 +72,30 @@ static struct mfd_cell led_devs[] __initdata = { {"88pm860x-led", 5,}, }; +static struct mfd_cell regulator_devs[] __initdata = { + {"88pm860x-regulator", 0,}, + {"88pm860x-regulator", 1,}, + {"88pm860x-regulator", 2,}, + {"88pm860x-regulator", 3,}, + {"88pm860x-regulator", 4,}, + {"88pm860x-regulator", 5,}, + {"88pm860x-regulator", 6,}, + {"88pm860x-regulator", 7,}, + {"88pm860x-regulator", 8,}, + {"88pm860x-regulator", 9,}, + {"88pm860x-regulator", 10,}, + {"88pm860x-regulator", 11,}, + {"88pm860x-regulator", 12,}, + {"88pm860x-regulator", 13,}, + {"88pm860x-regulator", 14,}, + {"88pm860x-regulator", 15,}, + {"88pm860x-regulator", 16,}, + {"88pm860x-regulator", 17,}, +}; + static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)]; +static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)]; static struct resource touch_resources[] = { { @@ -69,13 +113,6 @@ static struct mfd_cell touch_devs[] = { }, }; -#define PM8607_REG_RESOURCE(_start, _end) \ -{ \ - .start = PM8607_##_start, \ - .end = PM8607_##_end, \ - .flags = IORESOURCE_IO, \ -} - static struct resource power_supply_resources[] = { { .name = "88pm860x-power", @@ -149,52 +186,6 @@ static struct mfd_cell codec_devs[] = { }, }; -static struct resource regulator_resources[] = { - PM8607_REG_RESOURCE(BUCK1, BUCK1), - PM8607_REG_RESOURCE(BUCK2, BUCK2), - PM8607_REG_RESOURCE(BUCK3, BUCK3), - PM8607_REG_RESOURCE(LDO1, LDO1), - PM8607_REG_RESOURCE(LDO2, LDO2), - PM8607_REG_RESOURCE(LDO3, LDO3), - PM8607_REG_RESOURCE(LDO4, LDO4), - PM8607_REG_RESOURCE(LDO5, LDO5), - PM8607_REG_RESOURCE(LDO6, LDO6), - PM8607_REG_RESOURCE(LDO7, LDO7), - PM8607_REG_RESOURCE(LDO8, LDO8), - PM8607_REG_RESOURCE(LDO9, LDO9), - PM8607_REG_RESOURCE(LDO10, LDO10), - PM8607_REG_RESOURCE(LDO12, LDO12), - PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET), - PM8607_REG_RESOURCE(LDO14, LDO14), -}; - -#define PM8607_REG_DEVS(_id) \ -{ \ - .name = "88pm860x-regulator", \ - .num_resources = 1, \ - .resources = ®ulator_resources[PM8607_ID_##_id], \ - .id = PM8607_ID_##_id, \ -} - -static struct mfd_cell regulator_devs[] = { - PM8607_REG_DEVS(BUCK1), - PM8607_REG_DEVS(BUCK2), - PM8607_REG_DEVS(BUCK3), - PM8607_REG_DEVS(LDO1), - PM8607_REG_DEVS(LDO2), - PM8607_REG_DEVS(LDO3), - PM8607_REG_DEVS(LDO4), - PM8607_REG_DEVS(LDO5), - PM8607_REG_DEVS(LDO6), - PM8607_REG_DEVS(LDO7), - PM8607_REG_DEVS(LDO8), - PM8607_REG_DEVS(LDO9), - PM8607_REG_DEVS(LDO10), - PM8607_REG_DEVS(LDO12), - PM8607_REG_DEVS(LDO13), - PM8607_REG_DEVS(LDO14), -}; - struct pm860x_irq_data { int reg; int mask_reg; @@ -623,6 +614,64 @@ static void __devinit device_led_init(struct pm860x_chip *chip, } } +static void __devinit device_regulator_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + struct regulator_init_data *initdata; + int ret; + int i, j; + + if ((pdata == NULL) || (pdata->regulator == NULL)) + return; + + if (pdata->num_regulators > ARRAY_SIZE(regulator_devs)) + pdata->num_regulators = ARRAY_SIZE(regulator_devs); + + for (i = 0, j = -1; i < pdata->num_regulators; i++) { + initdata = &pdata->regulator[i]; + if (strstr(initdata->constraints.name, "BUCK")) { + sscanf(initdata->constraints.name, "BUCK%d", &j); + /* BUCK1 ~ BUCK3 */ + if ((j < 1) || (j > 3)) { + dev_err(chip->dev, "Failed to add constraint " + "(%s)\n", initdata->constraints.name); + goto out; + } + j = (j - 1) + PM8607_ID_BUCK1; + } + if (strstr(initdata->constraints.name, "LDO")) { + sscanf(initdata->constraints.name, "LDO%d", &j); + /* LDO1 ~ LDO15 */ + if ((j < 1) || (j > 15)) { + dev_err(chip->dev, "Failed to add constraint " + "(%s)\n", initdata->constraints.name); + goto out; + } + j = (j - 1) + PM8607_ID_LDO1; + } + if (j == -1) { + dev_err(chip->dev, "Failed to add constraint (%s)\n", + initdata->constraints.name); + goto out; + } + memcpy(®ulator_pdata[i], &pdata->regulator[i], + sizeof(struct regulator_init_data)); + regulator_devs[i].mfd_data = ®ulator_pdata[i]; + regulator_devs[i].num_resources = 1; + regulator_devs[i].resources = ®ulator_resources[j]; + + ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, + ®ulator_resources[j], 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); + goto out; + } + } +out: + return; +} + static void __devinit device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, struct pm860x_platform_data *pdata) @@ -678,14 +727,6 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, if (ret < 0) goto out; - ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], - ARRAY_SIZE(regulator_devs), - ®ulator_resources[0], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add regulator subdev\n"); - goto out_dev; - } - if (pdata && pdata->touch) { ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], ARRAY_SIZE(touch_devs), @@ -723,6 +764,8 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, dev_err(chip->dev, "Failed to add codec subdev\n"); goto out_dev; } + + device_regulator_init(chip, i2c, pdata); return; out_dev: mfd_remove_devices(chip->dev); diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index dd6308499bd4..859251250b55 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -15,6 +15,7 @@ #include #include #include +#include #include struct pm8607_regulator_info { @@ -394,47 +395,48 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = { PM8607_LDO(14, LDO14, 0, 4, SUPPLIES_EN12, 6), }; -static inline struct pm8607_regulator_info *find_regulator_info(int id) +static int __devinit pm8607_regulator_probe(struct platform_device *pdev) { - struct pm8607_regulator_info *info; + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm8607_regulator_info *info = NULL; + struct regulator_init_data *pdata; + struct mfd_cell *cell; int i; + cell = pdev->dev.platform_data; + if (cell == NULL) + return -ENODEV; + pdata = cell->mfd_data; + if (pdata == NULL) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { info = &pm8607_regulator_info[i]; - if (info->desc.id == id) - return info; + if (!strcmp(info->desc.name, pdata->constraints.name)) + break; } - return NULL; -} - -static int __devinit pm8607_regulator_probe(struct platform_device *pdev) -{ - struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_platform_data *pdata = chip->dev->platform_data; - struct pm8607_regulator_info *info = NULL; - - info = find_regulator_info(pdev->id); - if (info == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); + if (i > ARRAY_SIZE(pm8607_regulator_info)) { + dev_err(&pdev->dev, "Failed to find regulator %s\n", + pdata->constraints.name); return -EINVAL; } info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; info->chip = chip; + /* check DVC ramp slope double */ + if (!strcmp(info->desc.name, "BUCK3")) + if (info->chip->buck3_double) + info->slope_double = 1; + info->regulator = regulator_register(&info->desc, &pdev->dev, - pdata->regulator[pdev->id], info); + pdata, info); if (IS_ERR(info->regulator)) { dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); return PTR_ERR(info->regulator); } - /* check DVC ramp slope double */ - if (info->desc.id == PM8607_ID_BUCK3) - if (info->chip->buck3_double) - info->slope_double = 1; - platform_set_drvdata(pdev, info); return 0; } -- cgit v1.2.2 From c9f560b3d0222f6a6e3faeda324e786e230e4f20 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 7 Mar 2011 23:43:12 +0800 Subject: mfd: Adopt mfd_data in 88pm860x input driver Copy 88pm860x platform data into different mfd_data structure for onkey/touch/codec/power driver. So move the identification of device node from those drivers to mfd driver. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/input/misc/88pm860x_onkey.c | 2 +- drivers/mfd/88pm860x-core.c | 251 ++++++++++++++++++------------------ 2 files changed, 127 insertions(+), 126 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c index 4cc82826ea6b..3dca3c14510e 100644 --- a/drivers/input/misc/88pm860x_onkey.c +++ b/drivers/input/misc/88pm860x_onkey.c @@ -74,7 +74,7 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev) info->chip = chip; info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; info->dev = &pdev->dev; - info->irq = irq + chip->irq_base; + info->irq = irq; info->idev = input_allocate_device(); if (!info->idev) { diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 96ea0c64bbbc..9c511c1604a5 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -57,6 +57,39 @@ static struct resource regulator_resources[] __initdata = { {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, }; +static struct resource touch_resources[] __initdata = { + {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,}, +}; + +static struct resource onkey_resources[] __initdata = { + {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,}, +}; + +static struct resource codec_resources[] __initdata = { + /* Headset microphone insertion or removal */ + {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,}, + /* Hook-switch press or release */ + {PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,}, + /* Headset insertion or removal */ + {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,}, + /* Audio short */ + {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,}, +}; + +static struct resource battery_resources[] __initdata = { + {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,}, + {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,}, +}; + +static struct resource charger_resources[] __initdata = { + {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,}, + {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,}, + {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,}, + {PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature", IORESOURCE_IRQ,}, + {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,}, + {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, +}; + static struct mfd_cell bk_devs[] __initdata = { {"88pm860x-backlight", 0,}, {"88pm860x-backlight", 1,}, @@ -93,98 +126,28 @@ static struct mfd_cell regulator_devs[] __initdata = { {"88pm860x-regulator", 17,}, }; -static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; -static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)]; -static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)]; - -static struct resource touch_resources[] = { - { - .start = PM8607_IRQ_PEN, - .end = PM8607_IRQ_PEN, - .flags = IORESOURCE_IRQ, - }, +static struct mfd_cell touch_devs[] __initdata = { + {"88pm860x-touch", -1,}, }; -static struct mfd_cell touch_devs[] = { - { - .name = "88pm860x-touch", - .num_resources = 1, - .resources = &touch_resources[0], - }, +static struct mfd_cell onkey_devs[] __initdata = { + {"88pm860x-onkey", -1,}, }; -static struct resource power_supply_resources[] = { - { - .name = "88pm860x-power", - .start = PM8607_IRQ_CHG, - .end = PM8607_IRQ_CHG, - .flags = IORESOURCE_IRQ, - }, +static struct mfd_cell codec_devs[] __initdata = { + {"88pm860x-codec", -1,}, }; static struct mfd_cell power_devs[] = { - { - .name = "88pm860x-power", - .num_resources = 1, - .resources = &power_supply_resources[0], - .id = -1, - }, -}; - -static struct resource onkey_resources[] = { - { - .name = "88pm860x-onkey", - .start = PM8607_IRQ_ONKEY, - .end = PM8607_IRQ_ONKEY, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct mfd_cell onkey_devs[] = { - { - .name = "88pm860x-onkey", - .num_resources = 1, - .resources = &onkey_resources[0], - .id = -1, - }, -}; - -static struct resource codec_resources[] = { - { - /* Headset microphone insertion or removal */ - .name = "micin", - .start = PM8607_IRQ_MICIN, - .end = PM8607_IRQ_MICIN, - .flags = IORESOURCE_IRQ, - }, { - /* Hook-switch press or release */ - .name = "hook", - .start = PM8607_IRQ_HOOK, - .end = PM8607_IRQ_HOOK, - .flags = IORESOURCE_IRQ, - }, { - /* Headset insertion or removal */ - .name = "headset", - .start = PM8607_IRQ_HEADSET, - .end = PM8607_IRQ_HEADSET, - .flags = IORESOURCE_IRQ, - }, { - /* Audio short */ - .name = "audio-short", - .start = PM8607_IRQ_AUDIO_SHORT, - .end = PM8607_IRQ_AUDIO_SHORT, - .flags = IORESOURCE_IRQ, - }, + {"88pm860x-battery", -1,}, + {"88pm860x-charger", -1,}, }; -static struct mfd_cell codec_devs[] = { - { - .name = "88pm860x-codec", - .num_resources = ARRAY_SIZE(codec_resources), - .resources = &codec_resources[0], - .id = -1, - }, -}; +static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)]; +static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)]; +static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)]; +static struct pm860x_touch_pdata touch_pdata; +static struct pm860x_power_pdata power_pdata; struct pm860x_irq_data { int reg; @@ -672,6 +635,82 @@ out: return; } +static void __devinit device_touch_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + int ret; + + if ((pdata == NULL) || (pdata->touch == NULL)) + return; + + memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata)); + touch_devs[0].mfd_data = &touch_pdata; + touch_devs[0].num_resources = ARRAY_SIZE(touch_resources); + touch_devs[0].resources = &touch_resources[0]; + ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], + ARRAY_SIZE(touch_devs), &touch_resources[0], + chip->irq_base); + if (ret < 0) + dev_err(chip->dev, "Failed to add touch subdev\n"); +} + +static void __devinit device_power_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + int ret; + + if ((pdata == NULL) || (pdata->power == NULL)) + return; + + memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata)); + power_devs[0].mfd_data = &power_pdata; + power_devs[0].num_resources = ARRAY_SIZE(battery_resources); + power_devs[0].resources = &battery_resources[0], + ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, + &battery_resources[0], chip->irq_base); + if (ret < 0) + dev_err(chip->dev, "Failed to add battery subdev\n"); + + power_devs[1].mfd_data = &power_pdata; + power_devs[1].num_resources = ARRAY_SIZE(charger_resources); + power_devs[1].resources = &charger_resources[0], + ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, + &charger_resources[0], chip->irq_base); + if (ret < 0) + dev_err(chip->dev, "Failed to add charger subdev\n"); +} + +static void __devinit device_onkey_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + int ret; + + onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources); + onkey_devs[0].resources = &onkey_resources[0], + ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], + ARRAY_SIZE(onkey_devs), &onkey_resources[0], + chip->irq_base); + if (ret < 0) + dev_err(chip->dev, "Failed to add onkey subdev\n"); +} + +static void __devinit device_codec_init(struct pm860x_chip *chip, + struct i2c_client *i2c, + struct pm860x_platform_data *pdata) +{ + int ret; + + codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); + codec_devs[0].resources = &codec_resources[0], + ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], + ARRAY_SIZE(codec_devs), &codec_resources[0], 0); + if (ret < 0) + dev_err(chip->dev, "Failed to add codec subdev\n"); +} + static void __devinit device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, struct pm860x_platform_data *pdata) @@ -727,49 +766,11 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, if (ret < 0) goto out; - if (pdata && pdata->touch) { - ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], - ARRAY_SIZE(touch_devs), - &touch_resources[0], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add touch " - "subdev\n"); - goto out_dev; - } - } - - if (pdata && pdata->power) { - ret = mfd_add_devices(chip->dev, 0, &power_devs[0], - ARRAY_SIZE(power_devs), - &power_supply_resources[0], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add power supply " - "subdev\n"); - goto out_dev; - } - } - - ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], - ARRAY_SIZE(onkey_devs), - &onkey_resources[0], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add onkey subdev\n"); - goto out_dev; - } - - ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], - ARRAY_SIZE(codec_devs), - &codec_resources[0], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add codec subdev\n"); - goto out_dev; - } - device_regulator_init(chip, i2c, pdata); - return; -out_dev: - mfd_remove_devices(chip->dev); - device_irq_exit(chip); + device_onkey_init(chip, i2c, pdata); + device_touch_init(chip, i2c, pdata); + device_power_init(chip, i2c, pdata); + device_codec_init(chip, i2c, pdata); out: return; } -- cgit v1.2.2 From 09b034191acd1f95a749630fe366a84d3029930c Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 7 Mar 2011 23:43:16 +0800 Subject: mfd: Append additional read write on 88pm860x Append the additional read/write operation on 88pm860x for accessing test page in 88PM860x. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-i2c.c | 103 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index bc02e6b21608..e017dc88622a 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -126,6 +126,109 @@ out: } EXPORT_SYMBOL(pm860x_set_bits); +int pm860x_page_reg_read(struct i2c_client *i2c, int reg) +{ + struct pm860x_chip *chip = i2c_get_clientdata(i2c); + unsigned char zero = 0; + unsigned char data; + int ret; + + mutex_lock(&chip->io_lock); + pm860x_write_device(i2c, 0xFA, 0, &zero); + pm860x_write_device(i2c, 0xFB, 0, &zero); + pm860x_write_device(i2c, 0xFF, 0, &zero); + ret = pm860x_read_device(i2c, reg, 1, &data); + if (ret >= 0) + ret = (int)data; + pm860x_write_device(i2c, 0xFE, 0, &zero); + pm860x_write_device(i2c, 0xFC, 0, &zero); + mutex_unlock(&chip->io_lock); + return ret; +} +EXPORT_SYMBOL(pm860x_page_reg_read); + +int pm860x_page_reg_write(struct i2c_client *i2c, int reg, + unsigned char data) +{ + struct pm860x_chip *chip = i2c_get_clientdata(i2c); + unsigned char zero; + int ret; + + mutex_lock(&chip->io_lock); + pm860x_write_device(i2c, 0xFA, 0, &zero); + pm860x_write_device(i2c, 0xFB, 0, &zero); + pm860x_write_device(i2c, 0xFF, 0, &zero); + ret = pm860x_write_device(i2c, reg, 1, &data); + pm860x_write_device(i2c, 0xFE, 0, &zero); + pm860x_write_device(i2c, 0xFC, 0, &zero); + mutex_unlock(&chip->io_lock); + return ret; +} +EXPORT_SYMBOL(pm860x_page_reg_write); + +int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, + int count, unsigned char *buf) +{ + struct pm860x_chip *chip = i2c_get_clientdata(i2c); + unsigned char zero = 0; + int ret; + + mutex_lock(&chip->io_lock); + pm860x_write_device(i2c, 0xFA, 0, &zero); + pm860x_write_device(i2c, 0xFB, 0, &zero); + pm860x_write_device(i2c, 0xFF, 0, &zero); + ret = pm860x_read_device(i2c, reg, count, buf); + pm860x_write_device(i2c, 0xFE, 0, &zero); + pm860x_write_device(i2c, 0xFC, 0, &zero); + mutex_unlock(&chip->io_lock); + return ret; +} +EXPORT_SYMBOL(pm860x_page_bulk_read); + +int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, + int count, unsigned char *buf) +{ + struct pm860x_chip *chip = i2c_get_clientdata(i2c); + unsigned char zero = 0; + int ret; + + mutex_lock(&chip->io_lock); + pm860x_write_device(i2c, 0xFA, 0, &zero); + pm860x_write_device(i2c, 0xFB, 0, &zero); + pm860x_write_device(i2c, 0xFF, 0, &zero); + ret = pm860x_write_device(i2c, reg, count, buf); + pm860x_write_device(i2c, 0xFE, 0, &zero); + pm860x_write_device(i2c, 0xFC, 0, &zero); + mutex_unlock(&chip->io_lock); + return ret; +} +EXPORT_SYMBOL(pm860x_page_bulk_write); + +int pm860x_page_set_bits(struct i2c_client *i2c, int reg, + unsigned char mask, unsigned char data) +{ + struct pm860x_chip *chip = i2c_get_clientdata(i2c); + unsigned char zero; + unsigned char value; + int ret; + + mutex_lock(&chip->io_lock); + pm860x_write_device(i2c, 0xFA, 0, &zero); + pm860x_write_device(i2c, 0xFB, 0, &zero); + pm860x_write_device(i2c, 0xFF, 0, &zero); + ret = pm860x_read_device(i2c, reg, 1, &value); + if (ret < 0) + goto out; + value &= ~mask; + value |= data; + ret = pm860x_write_device(i2c, reg, 1, &value); +out: + pm860x_write_device(i2c, 0xFE, 0, &zero); + pm860x_write_device(i2c, 0xFC, 0, &zero); + mutex_unlock(&chip->io_lock); + return ret; +} +EXPORT_SYMBOL(pm860x_page_set_bits); static const struct i2c_device_id pm860x_id_table[] = { { "88PM860x", 0 }, -- cgit v1.2.2 From e93c53870c6d77c40de8981da238af947d6aa084 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 10 Mar 2011 13:54:07 +0000 Subject: mfd: Add WM8994 bulk register write operation Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index e673bda21f5d..5220af26419e 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -137,6 +137,29 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, } EXPORT_SYMBOL_GPL(wm8994_reg_write); +/** + * wm8994_bulk_write: Write multiple WM8994 registers + * + * @wm8994: Device to write to + * @reg: First register + * @count: Number of registers + * @buf: Buffer to write from. + */ +int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, + int count, u16 *buf) +{ + int ret; + + mutex_lock(&wm8994->io_lock); + + ret = wm8994_write(wm8994, reg, count * 2, buf); + + mutex_unlock(&wm8994->io_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm8994_bulk_write); + /** * wm8994_set_bits: Set the value of a bitfield in a WM8994 register * -- cgit v1.2.2 From bd6ca2cf50fbe3cc63513d026343035c3bd2e352 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Fri, 11 Mar 2011 11:34:44 +0900 Subject: regulator: MAX8997/8966 support This patch supports PMIC/Regulator part of MAX8997/MAX8966 MFD. In this initial release, selecting voltages or current-limit and switching on/off the regulators are supported. Controlling voltages for DVS with GPIOs is not implemented fully and requires more considerations: it controls multiple bucks (selection of 1, 2, and 5) at the same time with SET1~3 gpios. Thus, when DVS-GPIO is activated, we lose the ability to control the voltage of a single buck regulator independently; i.e., contolling a buck affects other two bucks. Therefore, using the conventional regulator framework directly might be problematic. However, in this driver, we try to choose a setting without such side effect of affecting other regulators and then try to choose a setting with the minimum side effect (the sum of voltage changes in other regulators). On the other hand, controlling all the three bucks simultenously based on the voltage set table may help build cpufreq and similar system more robust; i.e., all the three voltages are consistent every time without glitches during transition. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/max8997.c | 1213 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1223 insertions(+) create mode 100644 drivers/regulator/max8997.c (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e1d943619ab8..395d35941b84 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -108,6 +108,15 @@ config REGULATOR_MAX8952 via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS modes ranging from 0.77V to 1.40V by 0.01V steps. +config REGULATOR_MAX8997 + tristate "Maxim 8997/8966 regulator" + depends on MFD_MAX8997 + help + This driver controls a Maxim 8997/8966 regulator + via I2C bus. The provided regulator is suitable for S5PC110, + S5PV210, and Exynos-4 chips to control VCC_CORE and + VCC_USIM voltages. + config REGULATOR_MAX8998 tristate "Maxim 8998 voltage regulator" depends on MFD_MAX8998 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 0b5e88c2b8d7..e43b8524871e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o +obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c new file mode 100644 index 000000000000..01ef7e9903bb --- /dev/null +++ b/drivers/regulator/max8997.c @@ -0,0 +1,1213 @@ +/* + * max8997.c - Regulator driver for the Maxim 8997/8966 + * + * Copyright (C) 2011 Samsung Electronics + * MyungJoo Ham + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max8998.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct max8997_data { + struct device *dev; + struct max8997_dev *iodev; + int num_regulators; + struct regulator_dev **rdev; + int ramp_delay; /* in mV/us */ + + u8 buck1_vol[8]; + u8 buck2_vol[8]; + u8 buck5_vol[8]; + int buck125_gpioindex; + + u8 saved_states[MAX8997_REG_MAX]; +}; + +static inline void max8997_set_gpio(struct max8997_data *max8997) +{ + struct max8997_platform_data *pdata = + dev_get_platdata(max8997->iodev->dev); + int set3 = (max8997->buck125_gpioindex) & 0x1; + int set2 = ((max8997->buck125_gpioindex) >> 1) & 0x1; + int set1 = ((max8997->buck125_gpioindex) >> 2) & 0x1; + + gpio_set_value(pdata->buck125_gpios[0], set1); + gpio_set_value(pdata->buck125_gpios[1], set2); + gpio_set_value(pdata->buck125_gpios[2], set3); +} + +struct voltage_map_desc { + int min; + int max; + int step; + unsigned int n_bits; +}; + +/* Voltage maps in mV */ +static const struct voltage_map_desc ldo_voltage_map_desc = { + .min = 800, .max = 3950, .step = 50, .n_bits = 6, +}; /* LDO1 ~ 18, 21 all */ + +static const struct voltage_map_desc buck1245_voltage_map_desc = { + .min = 650, .max = 2225, .step = 25, .n_bits = 6, +}; /* Buck1, 2, 4, 5 */ + +static const struct voltage_map_desc buck37_voltage_map_desc = { + .min = 750, .max = 3900, .step = 50, .n_bits = 6, +}; /* Buck3, 7 */ + +/* current map in mA */ +static const struct voltage_map_desc charger_current_map_desc = { + .min = 200, .max = 950, .step = 50, .n_bits = 4, +}; + +static const struct voltage_map_desc topoff_current_map_desc = { + .min = 50, .max = 200, .step = 10, .n_bits = 4, +}; + +static const struct voltage_map_desc *reg_voltage_map[] = { + [MAX8997_LDO1] = &ldo_voltage_map_desc, + [MAX8997_LDO2] = &ldo_voltage_map_desc, + [MAX8997_LDO3] = &ldo_voltage_map_desc, + [MAX8997_LDO4] = &ldo_voltage_map_desc, + [MAX8997_LDO5] = &ldo_voltage_map_desc, + [MAX8997_LDO6] = &ldo_voltage_map_desc, + [MAX8997_LDO7] = &ldo_voltage_map_desc, + [MAX8997_LDO8] = &ldo_voltage_map_desc, + [MAX8997_LDO9] = &ldo_voltage_map_desc, + [MAX8997_LDO10] = &ldo_voltage_map_desc, + [MAX8997_LDO11] = &ldo_voltage_map_desc, + [MAX8997_LDO12] = &ldo_voltage_map_desc, + [MAX8997_LDO13] = &ldo_voltage_map_desc, + [MAX8997_LDO14] = &ldo_voltage_map_desc, + [MAX8997_LDO15] = &ldo_voltage_map_desc, + [MAX8997_LDO16] = &ldo_voltage_map_desc, + [MAX8997_LDO17] = &ldo_voltage_map_desc, + [MAX8997_LDO18] = &ldo_voltage_map_desc, + [MAX8997_LDO21] = &ldo_voltage_map_desc, + [MAX8997_BUCK1] = &buck1245_voltage_map_desc, + [MAX8997_BUCK2] = &buck1245_voltage_map_desc, + [MAX8997_BUCK3] = &buck37_voltage_map_desc, + [MAX8997_BUCK4] = &buck1245_voltage_map_desc, + [MAX8997_BUCK5] = &buck1245_voltage_map_desc, + [MAX8997_BUCK6] = NULL, + [MAX8997_BUCK7] = &buck37_voltage_map_desc, + [MAX8997_EN32KHZ_AP] = NULL, + [MAX8997_EN32KHZ_CP] = NULL, + [MAX8997_ENVICHG] = NULL, + [MAX8997_ESAFEOUT1] = NULL, + [MAX8997_ESAFEOUT2] = NULL, + [MAX8997_CHARGER_CV] = NULL, + [MAX8997_CHARGER] = &charger_current_map_desc, + [MAX8997_CHARGER_TOPOFF] = &topoff_current_map_desc, +}; + +static inline int max8997_get_rid(struct regulator_dev *rdev) +{ + return rdev_get_id(rdev); +} + +static int max8997_list_voltage_safeout(struct regulator_dev *rdev, + unsigned int selector) +{ + int rid = max8997_get_rid(rdev); + + if (rid == MAX8997_ESAFEOUT1 || rid == MAX8997_ESAFEOUT2) { + switch (selector) { + case 0: + return 4850000; + case 1: + return 4900000; + case 2: + return 4950000; + case 3: + return 3300000; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +static int max8997_list_voltage_charger_cv(struct regulator_dev *rdev, + unsigned int selector) +{ + int rid = max8997_get_rid(rdev); + + if (rid != MAX8997_CHARGER_CV) + goto err; + + switch (selector) { + case 0x00: + return 4200000; + case 0x01 ... 0x0E: + return 4000000 + 20000 * (selector - 0x01); + case 0x0F: + return 4350000; + default: + return -EINVAL; + } +err: + return -EINVAL; +} + +static int max8997_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + const struct voltage_map_desc *desc; + int rid = max8997_get_rid(rdev); + int val; + + if (rid >= ARRAY_SIZE(reg_voltage_map) || + rid < 0) + return -EINVAL; + + desc = reg_voltage_map[rid]; + if (desc == NULL) + return -EINVAL; + + val = desc->min + desc->step * selector; + if (val > desc->max) + return -EINVAL; + + return val * 1000; +} + +static int max8997_get_enable_register(struct regulator_dev *rdev, + int *reg, int *mask, int *pattern) +{ + int rid = max8997_get_rid(rdev); + + switch (rid) { + case MAX8997_LDO1 ... MAX8997_LDO21: + *reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); + *mask = 0xC0; + *pattern = 0xC0; + break; + case MAX8997_BUCK1: + *reg = MAX8997_REG_BUCK1CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK2: + *reg = MAX8997_REG_BUCK2CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK3: + *reg = MAX8997_REG_BUCK3CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK4: + *reg = MAX8997_REG_BUCK4CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK5: + *reg = MAX8997_REG_BUCK5CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK6: + *reg = MAX8997_REG_BUCK6CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_BUCK7: + *reg = MAX8997_REG_BUCK7CTRL; + *mask = 0x01; + *pattern = 0x01; + break; + case MAX8997_EN32KHZ_AP ... MAX8997_EN32KHZ_CP: + *reg = MAX8997_REG_MAINCON1; + *mask = 0x01 << (rid - MAX8997_EN32KHZ_AP); + *pattern = 0x01 << (rid - MAX8997_EN32KHZ_AP); + break; + case MAX8997_ENVICHG: + *reg = MAX8997_REG_MBCCTRL1; + *mask = 0x80; + *pattern = 0x80; + break; + case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: + *reg = MAX8997_REG_SAFEOUTCTRL; + *mask = 0x40 << (rid - MAX8997_ESAFEOUT1); + *pattern = 0x40 << (rid - MAX8997_ESAFEOUT1); + break; + case MAX8997_CHARGER: + *reg = MAX8997_REG_MBCCTRL2; + *mask = 0x40; + *pattern = 0x40; + break; + default: + /* Not controllable or not exists */ + return -EINVAL; + break; + } + + return 0; +} + +static int max8997_reg_is_enabled(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + u8 val; + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret == -EINVAL) + return 1; /* "not controllable" */ + else if (ret) + return ret; + + ret = max8997_read_reg(i2c, reg, &val); + if (ret) + return ret; + + return (val & mask) == pattern; +} + +static int max8997_reg_enable(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret) + return ret; + + return max8997_update_reg(i2c, reg, pattern, mask); +} + +static int max8997_reg_disable(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret) + return ret; + + return max8997_update_reg(i2c, reg, ~pattern, mask); +} + +static int max8997_get_voltage_register(struct regulator_dev *rdev, + int *_reg, int *_shift, int *_mask) +{ + int rid = max8997_get_rid(rdev); + int reg, shift = 0, mask = 0x3f; + + switch (rid) { + case MAX8997_LDO1 ... MAX8997_LDO21: + reg = MAX8997_REG_LDO1CTRL + (rid - MAX8997_LDO1); + break; + case MAX8997_BUCK1: + reg = MAX8997_REG_BUCK1DVS1; + break; + case MAX8997_BUCK2: + reg = MAX8997_REG_BUCK2DVS1; + break; + case MAX8997_BUCK3: + reg = MAX8997_REG_BUCK3DVS; + break; + case MAX8997_BUCK4: + reg = MAX8997_REG_BUCK4DVS; + break; + case MAX8997_BUCK5: + reg = MAX8997_REG_BUCK5DVS1; + break; + case MAX8997_BUCK7: + reg = MAX8997_REG_BUCK7DVS; + break; + case MAX8997_ESAFEOUT1 ... MAX8997_ESAFEOUT2: + reg = MAX8997_REG_SAFEOUTCTRL; + shift = (rid == MAX8997_ESAFEOUT2) ? 2 : 0; + mask = 0x3; + break; + case MAX8997_CHARGER_CV: + reg = MAX8997_REG_MBCCTRL3; + shift = 0; + mask = 0xf; + break; + case MAX8997_CHARGER: + reg = MAX8997_REG_MBCCTRL4; + shift = 0; + mask = 0xf; + break; + case MAX8997_CHARGER_TOPOFF: + reg = MAX8997_REG_MBCCTRL5; + shift = 0; + mask = 0xf; + break; + default: + return -EINVAL; + } + + *_reg = reg; + *_shift = shift; + *_mask = mask; + + return 0; +} + +static int max8997_get_voltage(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct max8997_platform_data *pdata = + dev_get_platdata(max8997->iodev->dev); + struct i2c_client *i2c = max8997->iodev->i2c; + int reg, shift, mask, ret; + int rid = max8997_get_rid(rdev); + u8 val; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + if ((rid == MAX8997_BUCK1 && pdata->buck1_gpiodvs) || + (rid == MAX8997_BUCK2 && pdata->buck2_gpiodvs) || + (rid == MAX8997_BUCK5 && pdata->buck5_gpiodvs)) + reg += max8997->buck125_gpioindex; + + ret = max8997_read_reg(i2c, reg, &val); + if (ret) + return ret; + + val >>= shift; + val &= mask; + + if (rdev->desc && rdev->desc->ops && rdev->desc->ops->list_voltage) + return rdev->desc->ops->list_voltage(rdev, val); + + /* + * max8997_list_voltage returns value for any rdev with voltage_map, + * which works for "CHARGER" and "CHARGER TOPOFF" that do not have + * list_voltage ops (they are current regulators). + */ + return max8997_list_voltage(rdev, val); +} + +static inline int max8997_get_voltage_proper_val( + const struct voltage_map_desc *desc, + int min_vol, int max_vol) +{ + int i = 0; + + if (desc == NULL) + return -EINVAL; + + if (max_vol < desc->min || min_vol > desc->max) + return -EINVAL; + + while (desc->min + desc->step * i < min_vol && + desc->min + desc->step * i < desc->max) + i++; + + if (desc->min + desc->step * i > max_vol) + return -EINVAL; + + if (i >= (1 << desc->n_bits)) + return -EINVAL; + + return i; +} + +static int max8997_set_voltage_charger_cv(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int rid = max8997_get_rid(rdev); + int lb, ub; + int reg, shift = 0, mask, ret = 0; + u8 val = 0x0; + + if (rid != MAX8997_CHARGER_CV) + return -EINVAL; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + if (max_uV < 4000000 || min_uV > 4350000) + return -EINVAL; + + if (min_uV <= 4000000) { + if (max_uV >= 4000000) + return -EINVAL; + else + val = 0x1; + } else if (min_uV <= 4200000 && max_uV >= 4200000) + val = 0x0; + else { + lb = (min_uV - 4000001) / 20000 + 2; + ub = (max_uV - 4000000) / 20000 + 1; + + if (lb > ub) + return -EINVAL; + + if (lb < 0xf) + val = lb; + else { + if (ub >= 0xf) + val = 0xf; + else + return -EINVAL; + } + } + + *selector = val; + + ret = max8997_update_reg(i2c, reg, val << shift, mask); + + return ret; +} + +/* + * For LDO1 ~ LDO21, BUCK1~5, BUCK7, CHARGER, CHARGER_TOPOFF + * BUCK1, 2, and 5 are available if they are not controlled by gpio + */ +static int max8997_set_voltage_ldobuck(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const struct voltage_map_desc *desc; + int rid = max8997_get_rid(rdev); + int reg, shift = 0, mask, ret; + int i; + u8 org; + + switch (rid) { + case MAX8997_LDO1 ... MAX8997_LDO21: + break; + case MAX8997_BUCK1 ... MAX8997_BUCK5: + break; + case MAX8997_BUCK6: + return -EINVAL; + case MAX8997_BUCK7: + break; + case MAX8997_CHARGER: + break; + case MAX8997_CHARGER_TOPOFF: + break; + default: + return -EINVAL; + } + + desc = reg_voltage_map[rid]; + + i = max8997_get_voltage_proper_val(desc, min_vol, max_vol); + if (i < 0) + return i; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + max8997_read_reg(i2c, reg, &org); + org = (org & mask) >> shift; + + ret = max8997_update_reg(i2c, reg, i << shift, mask << shift); + *selector = i; + + if (rid == MAX8997_BUCK1 || rid == MAX8997_BUCK2 || + rid == MAX8997_BUCK4 || rid == MAX8997_BUCK5) { + /* If the voltage is increasing */ + if (org < i) + udelay(desc->step * (i - org) / max8997->ramp_delay); + } + + return ret; +} + +/* + * Assess the damage on the voltage setting of BUCK1,2,5 by the change. + * + * When GPIO-DVS mode is used for multiple bucks, changing the voltage value + * of one of the bucks may affect that of another buck, which is the side + * effect of the change (set_voltage). This function examines the GPIO-DVS + * configurations and checks whether such side-effect exists. + */ +static int max8997_assess_side_effect(struct regulator_dev *rdev, + u8 new_val, int *best) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct max8997_platform_data *pdata = + dev_get_platdata(max8997->iodev->dev); + int rid = max8997_get_rid(rdev); + u8 *buckx_val[3]; + bool buckx_gpiodvs[3]; + int side_effect[8]; + int min_side_effect = INT_MAX; + int i; + + *best = -1; + + switch (rid) { + case MAX8997_BUCK1: + rid = 0; + break; + case MAX8997_BUCK2: + rid = 1; + break; + case MAX8997_BUCK5: + rid = 2; + break; + default: + return -EINVAL; + } + + buckx_val[0] = max8997->buck1_vol; + buckx_val[1] = max8997->buck2_vol; + buckx_val[2] = max8997->buck5_vol; + buckx_gpiodvs[0] = pdata->buck1_gpiodvs; + buckx_gpiodvs[1] = pdata->buck2_gpiodvs; + buckx_gpiodvs[2] = pdata->buck5_gpiodvs; + + for (i = 0; i < 8; i++) { + int others; + + if (new_val != (buckx_val[rid])[i]) { + side_effect[i] = -1; + continue; + } + + side_effect[i] = 0; + for (others = 0; others < 3; others++) { + int diff; + + if (others == rid) + continue; + if (buckx_gpiodvs[others] == false) + continue; /* Not affected */ + diff = (buckx_val[others])[i] - + (buckx_val[others])[max8997->buck125_gpioindex]; + if (diff > 0) + side_effect[i] += diff; + else if (diff < 0) + side_effect[i] -= diff; + } + if (side_effect[i] == 0) { + *best = i; + return 0; /* NO SIDE EFFECT! Use This! */ + } + if (side_effect[i] < min_side_effect) { + min_side_effect = side_effect[i]; + *best = i; + } + } + + if (*best == -1) + return -EINVAL; + + return side_effect[*best]; +} + +/* + * For Buck 1 ~ 5 and 7. If it is not controlled by GPIO, this calls + * max8997_set_voltage_ldobuck to do the job. + */ +static int max8997_set_voltage_buck(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct max8997_platform_data *pdata = + dev_get_platdata(max8997->iodev->dev); + int rid = max8997_get_rid(rdev); + const struct voltage_map_desc *desc; + int new_val, new_idx, damage, tmp_val, tmp_idx, tmp_dmg; + bool gpio_dvs_mode = false; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + + if (rid < MAX8997_BUCK1 || rid > MAX8997_BUCK7) + return -EINVAL; + + switch (rid) { + case MAX8997_BUCK1: + if (pdata->buck1_gpiodvs) + gpio_dvs_mode = true; + break; + case MAX8997_BUCK2: + if (pdata->buck2_gpiodvs) + gpio_dvs_mode = true; + break; + case MAX8997_BUCK5: + if (pdata->buck5_gpiodvs) + gpio_dvs_mode = true; + break; + } + + if (!gpio_dvs_mode) + return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, + selector); + + desc = reg_voltage_map[rid]; + new_val = max8997_get_voltage_proper_val(desc, min_vol, max_vol); + if (new_val < 0) + return new_val; + + tmp_dmg = INT_MAX; + tmp_idx = -1; + tmp_val = -1; + do { + damage = max8997_assess_side_effect(rdev, new_val, &new_idx); + if (damage == 0) + goto out; + + if (tmp_dmg > damage) { + tmp_idx = new_idx; + tmp_val = new_val; + tmp_dmg = damage; + } + + new_val++; + } while (desc->min + desc->step + new_val <= desc->max); + + new_idx = tmp_idx; + new_val = tmp_val; + + if (pdata->ignore_gpiodvs_side_effect == false) + return -EINVAL; + + dev_warn(&rdev->dev, "MAX8997 GPIO-DVS Side Effect Warning: GPIO SET:" + " %d -> %d\n", max8997->buck125_gpioindex, tmp_idx); + +out: + if (new_idx < 0 || new_val < 0) + return -EINVAL; + + max8997->buck125_gpioindex = new_idx; + max8997_set_gpio(max8997); + *selector = new_val; + + return 0; +} + +static const int safeoutvolt[] = { + 3300000, + 4850000, + 4900000, + 4950000, +}; + +/* For SAFEOUT1 and SAFEOUT2 */ +static int max8997_set_voltage_safeout(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int rid = max8997_get_rid(rdev); + int reg, shift = 0, mask, ret; + int i = 0; + u8 val; + + if (rid != MAX8997_ESAFEOUT1 && rid != MAX8997_ESAFEOUT2) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(safeoutvolt); i++) { + if (min_uV <= safeoutvolt[i] && + max_uV >= safeoutvolt[i]) + break; + } + + if (i >= ARRAY_SIZE(safeoutvolt)) + return -EINVAL; + + if (i == 0) + val = 0x3; + else + val = i - 1; + + ret = max8997_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + ret = max8997_update_reg(i2c, reg, val << shift, mask << shift); + *selector = val; + + return ret; +} + +static int max8997_reg_enable_suspend(struct regulator_dev *rdev) +{ + return 0; +} + +static int max8997_reg_disable_suspend(struct regulator_dev *rdev) +{ + struct max8997_data *max8997 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8997->iodev->i2c; + int ret, reg, mask, pattern; + int rid = max8997_get_rid(rdev); + + ret = max8997_get_enable_register(rdev, ®, &mask, &pattern); + if (ret) + return ret; + + max8997_read_reg(i2c, reg, &max8997->saved_states[rid]); + + if (rid == MAX8997_LDO1 || + rid == MAX8997_LDO10 || + rid == MAX8997_LDO21) { + dev_dbg(&rdev->dev, "Conditional Power-Off for %s\n", + rdev->desc->name); + return max8997_update_reg(i2c, reg, 0x40, mask); + } + + dev_dbg(&rdev->dev, "Full Power-Off for %s (%xh -> %xh)\n", + rdev->desc->name, max8997->saved_states[rid] & mask, + (~pattern) & mask); + return max8997_update_reg(i2c, reg, ~pattern, mask); +} + +static struct regulator_ops max8997_ldo_ops = { + .list_voltage = max8997_list_voltage, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_voltage = max8997_get_voltage, + .set_voltage = max8997_set_voltage_ldobuck, + .set_suspend_enable = max8997_reg_enable_suspend, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_buck_ops = { + .list_voltage = max8997_list_voltage, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_voltage = max8997_get_voltage, + .set_voltage = max8997_set_voltage_buck, + .set_suspend_enable = max8997_reg_enable_suspend, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_fixedvolt_ops = { + .list_voltage = max8997_list_voltage, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .set_suspend_enable = max8997_reg_enable_suspend, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_safeout_ops = { + .list_voltage = max8997_list_voltage_safeout, + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_voltage = max8997_get_voltage, + .set_voltage = max8997_set_voltage_safeout, + .set_suspend_enable = max8997_reg_enable_suspend, + .set_suspend_disable = max8997_reg_disable_suspend, +}; + +static struct regulator_ops max8997_fixedstate_ops = { + .list_voltage = max8997_list_voltage_charger_cv, + .get_voltage = max8997_get_voltage, + .set_voltage = max8997_set_voltage_charger_cv, +}; + +static int max8997_set_voltage_ldobuck_wrap(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + unsigned dummy; + + return max8997_set_voltage_ldobuck(rdev, min_uV, max_uV, &dummy); +} + + +static struct regulator_ops max8997_charger_ops = { + .is_enabled = max8997_reg_is_enabled, + .enable = max8997_reg_enable, + .disable = max8997_reg_disable, + .get_current_limit = max8997_get_voltage, + .set_current_limit = max8997_set_voltage_ldobuck_wrap, +}; + +static struct regulator_ops max8997_charger_fixedstate_ops = { + .is_enabled = max8997_reg_is_enabled, + .get_current_limit = max8997_get_voltage, + .set_current_limit = max8997_set_voltage_ldobuck_wrap, +}; + +#define regulator_desc_ldo(num) { \ + .name = "LDO"#num, \ + .id = MAX8997_LDO##num, \ + .ops = &max8997_ldo_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ +} +#define regulator_desc_buck(num) { \ + .name = "BUCK"#num, \ + .id = MAX8997_BUCK##num, \ + .ops = &max8997_buck_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ +} + +static struct regulator_desc regulators[] = { + regulator_desc_ldo(1), + regulator_desc_ldo(2), + regulator_desc_ldo(3), + regulator_desc_ldo(4), + regulator_desc_ldo(5), + regulator_desc_ldo(6), + regulator_desc_ldo(7), + regulator_desc_ldo(8), + regulator_desc_ldo(9), + regulator_desc_ldo(10), + regulator_desc_ldo(11), + regulator_desc_ldo(12), + regulator_desc_ldo(13), + regulator_desc_ldo(14), + regulator_desc_ldo(15), + regulator_desc_ldo(16), + regulator_desc_ldo(17), + regulator_desc_ldo(18), + regulator_desc_ldo(21), + regulator_desc_buck(1), + regulator_desc_buck(2), + regulator_desc_buck(3), + regulator_desc_buck(4), + regulator_desc_buck(5), + { + .name = "BUCK6", + .id = MAX8997_BUCK6, + .ops = &max8997_fixedvolt_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + regulator_desc_buck(7), + { + .name = "EN32KHz AP", + .id = MAX8997_EN32KHZ_AP, + .ops = &max8997_fixedvolt_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, { + .name = "EN32KHz CP", + .id = MAX8997_EN32KHZ_CP, + .ops = &max8997_fixedvolt_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, { + .name = "ENVICHG", + .id = MAX8997_ENVICHG, + .ops = &max8997_fixedvolt_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, { + .name = "ESAFEOUT1", + .id = MAX8997_ESAFEOUT1, + .ops = &max8997_safeout_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, { + .name = "ESAFEOUT2", + .id = MAX8997_ESAFEOUT2, + .ops = &max8997_safeout_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, { + .name = "CHARGER CV", + .id = MAX8997_CHARGER_CV, + .ops = &max8997_fixedstate_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, { + .name = "CHARGER", + .id = MAX8997_CHARGER, + .ops = &max8997_charger_ops, + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + }, { + .name = "CHARGER TOPOFF", + .id = MAX8997_CHARGER_TOPOFF, + .ops = &max8997_charger_fixedstate_ops, + .type = REGULATOR_CURRENT, + .owner = THIS_MODULE, + }, +}; + +static __devinit int max8997_pmic_probe(struct platform_device *pdev) +{ + struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); + struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); + struct regulator_dev **rdev; + struct max8997_data *max8997; + struct i2c_client *i2c; + int i, ret, size; + u8 max_buck1 = 0, max_buck2 = 0, max_buck5 = 0; + + if (!pdata) { + dev_err(pdev->dev.parent, "No platform init data supplied.\n"); + return -ENODEV; + } + + max8997 = kzalloc(sizeof(struct max8997_data), GFP_KERNEL); + if (!max8997) + return -ENOMEM; + + size = sizeof(struct regulator_dev *) * pdata->num_regulators; + max8997->rdev = kzalloc(size, GFP_KERNEL); + if (!max8997->rdev) { + kfree(max8997); + return -ENOMEM; + } + + rdev = max8997->rdev; + max8997->dev = &pdev->dev; + max8997->iodev = iodev; + max8997->num_regulators = pdata->num_regulators; + platform_set_drvdata(pdev, max8997); + i2c = max8997->iodev->i2c; + + max8997->buck125_gpioindex = pdata->buck125_default_idx; + + for (i = 0; i < 8; i++) { + max8997->buck1_vol[i] = ret = + max8997_get_voltage_proper_val( + &buck1245_voltage_map_desc, + pdata->buck1_voltage[i] / 1000, + pdata->buck1_voltage[i] / 1000 + + buck1245_voltage_map_desc.step); + if (ret < 0) + goto err_alloc; + + max8997->buck2_vol[i] = ret = + max8997_get_voltage_proper_val( + &buck1245_voltage_map_desc, + pdata->buck2_voltage[i] / 1000, + pdata->buck2_voltage[i] / 1000 + + buck1245_voltage_map_desc.step); + if (ret < 0) + goto err_alloc; + + max8997->buck5_vol[i] = ret = + max8997_get_voltage_proper_val( + &buck1245_voltage_map_desc, + pdata->buck5_voltage[i] / 1000, + pdata->buck5_voltage[i] / 1000 + + buck1245_voltage_map_desc.step); + if (ret < 0) + goto err_alloc; + + if (max_buck1 < max8997->buck1_vol[i]) + max_buck1 = max8997->buck1_vol[i]; + if (max_buck2 < max8997->buck2_vol[i]) + max_buck2 = max8997->buck2_vol[i]; + if (max_buck5 < max8997->buck5_vol[i]) + max_buck5 = max8997->buck5_vol[i]; + } + + /* For the safety, set max voltage before setting up */ + for (i = 0; i < 8; i++) { + max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1), + max_buck1, 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1), + max_buck2, 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1), + max_buck5, 0x3f); + } + + /* + * If buck 1, 2, and 5 do not care DVS GPIO settings, ignore them. + * If at least one of them cares, set gpios. + */ + if (pdata->buck1_gpiodvs || pdata->buck2_gpiodvs || + pdata->buck5_gpiodvs) { + bool gpio1set = false, gpio2set = false; + + if (!gpio_is_valid(pdata->buck125_gpios[0]) || + !gpio_is_valid(pdata->buck125_gpios[1]) || + !gpio_is_valid(pdata->buck125_gpios[2])) { + dev_err(&pdev->dev, "GPIO NOT VALID\n"); + ret = -EINVAL; + goto err_alloc; + } + + ret = gpio_request(pdata->buck125_gpios[0], + "MAX8997 SET1"); + if (ret == -EBUSY) + dev_warn(&pdev->dev, "Duplicated gpio request" + " on SET1\n"); + else if (ret) + goto err_alloc; + else + gpio1set = true; + + ret = gpio_request(pdata->buck125_gpios[1], + "MAX8997 SET2"); + if (ret == -EBUSY) + dev_warn(&pdev->dev, "Duplicated gpio request" + " on SET2\n"); + else if (ret) { + if (gpio1set) + gpio_free(pdata->buck125_gpios[0]); + goto err_alloc; + } else + gpio2set = true; + + ret = gpio_request(pdata->buck125_gpios[2], + "MAX8997 SET3"); + if (ret == -EBUSY) + dev_warn(&pdev->dev, "Duplicated gpio request" + " on SET3\n"); + else if (ret) { + if (gpio1set) + gpio_free(pdata->buck125_gpios[0]); + if (gpio2set) + gpio_free(pdata->buck125_gpios[1]); + goto err_alloc; + } + + gpio_direction_output(pdata->buck125_gpios[0], + (max8997->buck125_gpioindex >> 2) + & 0x1); /* SET1 */ + gpio_direction_output(pdata->buck125_gpios[1], + (max8997->buck125_gpioindex >> 1) + & 0x1); /* SET2 */ + gpio_direction_output(pdata->buck125_gpios[2], + (max8997->buck125_gpioindex >> 0) + & 0x1); /* SET3 */ + ret = 0; + } + + /* DVS-GPIO disabled */ + max8997_update_reg(i2c, MAX8997_REG_BUCK1CTRL, (pdata->buck1_gpiodvs) ? + (1 << 1) : (0 << 1), 1 << 1); + max8997_update_reg(i2c, MAX8997_REG_BUCK2CTRL, (pdata->buck2_gpiodvs) ? + (1 << 1) : (0 << 1), 1 << 1); + max8997_update_reg(i2c, MAX8997_REG_BUCK5CTRL, (pdata->buck5_gpiodvs) ? + (1 << 1) : (0 << 1), 1 << 1); + + /* Initialize all the DVS related BUCK registers */ + for (i = 0; i < 8; i++) { + max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1), + max8997->buck1_vol[i], + 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1), + max8997->buck2_vol[i], + 0x3f); + max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1), + max8997->buck5_vol[i], + 0x3f); + } + + for (i = 0; i < pdata->num_regulators; i++) { + const struct voltage_map_desc *desc; + int id = pdata->regulators[i].id; + + desc = reg_voltage_map[id]; + if (desc) + regulators[id].n_voltages = + (desc->max - desc->min) / desc->step + 1; + else if (id == MAX8997_ESAFEOUT1 || id == MAX8997_ESAFEOUT2) + regulators[id].n_voltages = 4; + else if (id == MAX8997_CHARGER_CV) + regulators[id].n_voltages = 16; + + rdev[i] = regulator_register(®ulators[id], max8997->dev, + pdata->regulators[i].initdata, max8997); + if (IS_ERR(rdev[i])) { + ret = PTR_ERR(rdev[i]); + dev_err(max8997->dev, "regulator init failed for %d\n", + id); + rdev[i] = NULL; + goto err; + } + } + + /* Misc Settings */ + max8997->ramp_delay = 10; /* set 10mV/us, which is the default */ + max8997_write_reg(i2c, MAX8997_REG_BUCKRAMP, (0xf << 4) | 0x9); + + return 0; +err: + for (i = 0; i < max8997->num_regulators; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); +err_alloc: + kfree(max8997->rdev); + kfree(max8997); + + return ret; +} + +static int __devexit max8997_pmic_remove(struct platform_device *pdev) +{ + struct max8997_data *max8997 = platform_get_drvdata(pdev); + struct regulator_dev **rdev = max8997->rdev; + int i; + + for (i = 0; i < max8997->num_regulators; i++) + if (rdev[i]) + regulator_unregister(rdev[i]); + + kfree(max8997->rdev); + kfree(max8997); + + return 0; +} + +static const struct platform_device_id max8997_pmic_id[] = { + { "max8997-pmic", 0}, + { }, +}; + +static struct platform_driver max8997_pmic_driver = { + .driver = { + .name = "max8997-pmic", + .owner = THIS_MODULE, + }, + .probe = max8997_pmic_probe, + .remove = __devexit_p(max8997_pmic_remove), + .id_table = max8997_pmic_id, +}; + +static int __init max8997_pmic_init(void) +{ + return platform_driver_register(&max8997_pmic_driver); +} +subsys_initcall(max8997_pmic_init); + +static void __exit max8997_pmic_cleanup(void) +{ + platform_driver_unregister(&max8997_pmic_driver); +} +module_exit(max8997_pmic_cleanup); + +MODULE_DESCRIPTION("MAXIM 8997/8966 Regulator Driver"); +MODULE_AUTHOR("MyungJoo Ham "); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From e967f77d9818df884bdffb3e801eb12e0fd52b1c Mon Sep 17 00:00:00 2001 From: Denis Turischev Date: Sun, 13 Mar 2011 17:28:59 +0200 Subject: mfd: Add Tunnel Creek support to lpc_sch Intel Poulsbo SCH and Tunnel Creek provide almost the same LPC interface. Use the same driver for both devices while storing PCI ID to distinguish between platforms to apply plarform related quirks. Signed-off-by: Denis Turischev Signed-off-by: Samuel Ortiz --- drivers/mfd/lpc_sch.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 51b2f6065a0b..ea3f52c07ef7 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -61,6 +61,7 @@ static struct mfd_cell lpc_sch_cells[] = { static struct pci_device_id lpc_sch_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) }, { 0, } }; MODULE_DEVICE_TABLE(pci, lpc_sch_ids); @@ -70,6 +71,7 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, { unsigned int base_addr_cfg; unsigned short base_addr; + int i; pci_read_config_dword(dev, SMBASE, &base_addr_cfg); if (!(base_addr_cfg & (1 << 31))) { @@ -99,7 +101,10 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, gpio_sch_resource.start = base_addr; gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; - return mfd_add_devices(&dev->dev, -1, + for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++) + lpc_sch_cells[i].id = id->device; + + return mfd_add_devices(&dev->dev, 0, lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); } -- cgit v1.2.2 From f04ddfcd24bf3c1f987eaf634a84998044e616d3 Mon Sep 17 00:00:00 2001 From: Denis Turischev Date: Mon, 14 Mar 2011 12:53:05 +0200 Subject: gpio: Add Tunnel Creek support to sch_gpio Almost the same driver for both Poulsbo and Tunnel Creek. The difference is in quantity of GPIOs powered by the core power rail and by suspend power supply, default values for some GPIOs, etc. Detect actual hardware by platform device ID assigned in lpc_sch and set configuration accordingly. Signed-off-by: Denis Turischev Acked-by: Grant Likely Signed-off-by: Samuel Ortiz --- drivers/gpio/Kconfig | 7 ++++-- drivers/gpio/sch_gpio.c | 57 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b46442d7d66e..d8d0cda2641d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -100,18 +100,21 @@ config GPIO_VR41XX Say yes here to support the NEC VR4100 series General-purpose I/O Uint config GPIO_SCH - tristate "Intel SCH GPIO" + tristate "Intel SCH/TunnelCreek GPIO" depends on GPIOLIB && PCI && X86 select MFD_CORE select LPC_SCH help - Say yes here to support GPIO interface on Intel Poulsbo SCH. + Say yes here to support GPIO interface on Intel Poulsbo SCH + or Intel Tunnel Creek processor. The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are powered by the core power rail and are turned off during sleep modes (S3 and higher). The remaining four GPIOs are powered by the Intel SCH suspend power supply. These GPIOs remain active during S3. The suspend powered GPIOs can be used to wake the system from the Suspend-to-RAM state. + The Intel Tunnel Creek processor has 5 GPIOs powered by the + core power rail and 9 from suspend power supply. This driver can also be built as a module. If so, the module will be called sch-gpio. diff --git a/drivers/gpio/sch_gpio.c b/drivers/gpio/sch_gpio.c index 583521352c16..56060421cdff 100644 --- a/drivers/gpio/sch_gpio.c +++ b/drivers/gpio/sch_gpio.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -187,7 +188,11 @@ static struct gpio_chip sch_gpio_resume = { static int __devinit sch_gpio_probe(struct platform_device *pdev) { struct resource *res; - int err; + int err, id; + + id = pdev->id; + if (!id) + return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) @@ -198,12 +203,40 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev) gpio_ba = res->start; - sch_gpio_core.base = 0; - sch_gpio_core.ngpio = 10; - sch_gpio_core.dev = &pdev->dev; + switch (id) { + case PCI_DEVICE_ID_INTEL_SCH_LPC: + sch_gpio_core.base = 0; + sch_gpio_core.ngpio = 10; + + sch_gpio_resume.base = 10; + sch_gpio_resume.ngpio = 4; + + /* + * GPIO[6:0] enabled by default + * GPIO7 is configured by the CMC as SLPIOVR + * Enable GPIO[9:8] core powered gpios explicitly + */ + outb(0x3, gpio_ba + CGEN + 1); + /* + * SUS_GPIO[2:0] enabled by default + * Enable SUS_GPIO3 resume powered gpio explicitly + */ + outb(0x8, gpio_ba + RGEN); + break; + + case PCI_DEVICE_ID_INTEL_ITC_LPC: + sch_gpio_core.base = 0; + sch_gpio_core.ngpio = 5; + + sch_gpio_resume.base = 5; + sch_gpio_resume.ngpio = 9; + break; + + default: + return -ENODEV; + } - sch_gpio_resume.base = 10; - sch_gpio_resume.ngpio = 4; + sch_gpio_core.dev = &pdev->dev; sch_gpio_resume.dev = &pdev->dev; err = gpiochip_add(&sch_gpio_core); @@ -214,18 +247,6 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev) if (err < 0) goto err_sch_gpio_resume; - /* - * GPIO[6:0] enabled by default - * GPIO7 is configured by the CMC as SLPIOVR - * Enable GPIO[9:8] core powered gpios explicitly - */ - outb(0x3, gpio_ba + CGEN + 1); - /* - * SUS_GPIO[2:0] enabled by default - * Enable SUS_GPIO3 resume powered gpio explicitly - */ - outb(0x8, gpio_ba + RGEN); - return 0; err_sch_gpio_resume: -- cgit v1.2.2 From 798a8eee44da56b4f2e000ff81dfb49d09c65b71 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 9 Mar 2011 13:02:38 +0100 Subject: mfd: Add a core driver for TI TPS61050/TPS61052 chips v2 The TPS61050/TPS61052 are boost converters, LED drivers, LED flash drivers and a simple GPIO pin chips. Cc: Liam Girdwood Cc: Mark Brown Cc: Jonas Aberg Cc: Ola Lilja Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 9 ++ drivers/mfd/Makefile | 1 + drivers/mfd/tps6105x.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 drivers/mfd/tps6105x.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 500a130857d8..bc99288f8f39 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -129,6 +129,15 @@ config UCB1400_CORE To compile this driver as a module, choose M here: the module will be called ucb1400_core. +config TPS6105X + tristate "TPS61050/61052 Boost Converters" + depends on I2C + help + This option enables a driver for the TP61050/TPS61052 + high-power "white LED driver". This boost converter is + sometimes used for other things than white LEDs, and + also contains a GPIO pin. + config TPS65010 tristate "TPS6501x Power Management chips" depends on I2C && GPIOLIB diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0e9f0c51449d..47f5709f3828 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o +obj-$(CONFIG_TPS6105X) += tps6105x.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS6507X) += tps6507x.o obj-$(CONFIG_MENELAUS) += menelaus.o diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c new file mode 100644 index 000000000000..46d8205646b6 --- /dev/null +++ b/drivers/mfd/tps6105x.c @@ -0,0 +1,246 @@ +/* + * Core driver for TPS61050/61052 boost converters, used for while LED + * driving, audio power amplification, white LED flash, and generic + * boost conversion. Additionally it provides a 1-bit GPIO pin (out or in) + * and a flash synchronization pin to synchronize flash events when used as + * flashgun. + * + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int tps6105x_set(struct tps6105x *tps6105x, u8 reg, u8 value) +{ + int ret; + + ret = mutex_lock_interruptible(&tps6105x->lock); + if (ret) + return ret; + ret = i2c_smbus_write_byte_data(tps6105x->client, reg, value); + mutex_unlock(&tps6105x->lock); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(tps6105x_set); + +int tps6105x_get(struct tps6105x *tps6105x, u8 reg, u8 *buf) +{ + int ret; + + ret = mutex_lock_interruptible(&tps6105x->lock); + if (ret) + return ret; + ret = i2c_smbus_read_byte_data(tps6105x->client, reg); + mutex_unlock(&tps6105x->lock); + if (ret < 0) + return ret; + + *buf = ret; + return 0; +} +EXPORT_SYMBOL(tps6105x_get); + +/* + * Masks off the bits in the mask and sets the bits in the bitvalues + * parameter in one atomic operation + */ +int tps6105x_mask_and_set(struct tps6105x *tps6105x, u8 reg, + u8 bitmask, u8 bitvalues) +{ + int ret; + u8 regval; + + ret = mutex_lock_interruptible(&tps6105x->lock); + if (ret) + return ret; + ret = i2c_smbus_read_byte_data(tps6105x->client, reg); + if (ret < 0) + goto fail; + regval = ret; + regval = (~bitmask & regval) | (bitmask & bitvalues); + ret = i2c_smbus_write_byte_data(tps6105x->client, reg, regval); +fail: + mutex_unlock(&tps6105x->lock); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(tps6105x_mask_and_set); + +static int __devinit tps6105x_startup(struct tps6105x *tps6105x) +{ + int ret; + u8 regval; + + ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); + if (ret) + return ret; + switch (regval >> TPS6105X_REG0_MODE_SHIFT) { + case TPS6105X_REG0_MODE_SHUTDOWN: + dev_info(&tps6105x->client->dev, + "TPS6105x found in SHUTDOWN mode\n"); + break; + case TPS6105X_REG0_MODE_TORCH: + dev_info(&tps6105x->client->dev, + "TPS6105x found in TORCH mode\n"); + break; + case TPS6105X_REG0_MODE_TORCH_FLASH: + dev_info(&tps6105x->client->dev, + "TPS6105x found in FLASH mode\n"); + break; + case TPS6105X_REG0_MODE_VOLTAGE: + dev_info(&tps6105x->client->dev, + "TPS6105x found in VOLTAGE mode\n"); + break; + default: + break; + } + + return ret; +} + +/* + * MFD cells - we have one cell which is selected operation + * mode, and we always have a GPIO cell. + */ +static struct mfd_cell tps6105x_cells[] = { + { + /* name will be runtime assigned */ + .id = -1, + }, + { + .name = "tps6105x-gpio", + .id = -1, + }, +}; + +static int __devinit tps6105x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tps6105x *tps6105x; + struct tps6105x_platform_data *pdata; + int ret; + int i; + + tps6105x = kmalloc(sizeof(*tps6105x), GFP_KERNEL); + if (!tps6105x) + return -ENOMEM; + + i2c_set_clientdata(client, tps6105x); + tps6105x->client = client; + pdata = client->dev.platform_data; + tps6105x->pdata = pdata; + mutex_init(&tps6105x->lock); + + ret = tps6105x_startup(tps6105x); + if (ret) { + dev_err(&client->dev, "chip initialization failed\n"); + goto fail; + } + + /* Remove warning texts when you implement new cell drivers */ + switch (pdata->mode) { + case TPS6105X_MODE_SHUTDOWN: + dev_info(&client->dev, + "present, not used for anything, only GPIO\n"); + break; + case TPS6105X_MODE_TORCH: + tps6105x_cells[0].name = "tps6105x-leds"; + dev_warn(&client->dev, + "torch mode is unsupported\n"); + break; + case TPS6105X_MODE_TORCH_FLASH: + tps6105x_cells[0].name = "tps6105x-flash"; + dev_warn(&client->dev, + "flash mode is unsupported\n"); + break; + case TPS6105X_MODE_VOLTAGE: + tps6105x_cells[0].name ="tps6105x-regulator"; + break; + default: + break; + } + + /* Set up and register the platform devices. */ + for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) { + /* One state holder for all drivers, this is simple */ + tps6105x_cells[i].mfd_data = tps6105x; + } + + ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, + ARRAY_SIZE(tps6105x_cells), NULL, 0); + if (ret) + goto fail; + + return 0; + +fail: + kfree(tps6105x); + return ret; +} + +static int __devexit tps6105x_remove(struct i2c_client *client) +{ + struct tps6105x *tps6105x = i2c_get_clientdata(client); + + mfd_remove_devices(&client->dev); + + /* Put chip in shutdown mode */ + tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + TPS6105X_REG0_MODE_MASK, + TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); + + kfree(tps6105x); + return 0; +} + +static const struct i2c_device_id tps6105x_id[] = { + { "tps61050", 0 }, + { "tps61052", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tps6105x_id); + +static struct i2c_driver tps6105x_driver = { + .driver = { + .name = "tps6105x", + }, + .probe = tps6105x_probe, + .remove = __devexit_p(tps6105x_remove), + .id_table = tps6105x_id, +}; + +static int __init tps6105x_init(void) +{ + return i2c_add_driver(&tps6105x_driver); +} +subsys_initcall(tps6105x_init); + +static void __exit tps6105x_exit(void) +{ + i2c_del_driver(&tps6105x_driver); +} +module_exit(tps6105x_exit); + +MODULE_AUTHOR("Linus Walleij"); +MODULE_DESCRIPTION("TPS6105x White LED Boost Converter Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 2edd3b692404efc2d3915175a2ed553e783de763 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 9 Mar 2011 12:02:55 +0000 Subject: regulator: Add a subdriver for TI TPS6105x regulator portions v2 This adds a subdriver for the regulator found inside the TPS61050 and TPS61052 chips. Cc: Samuel Ortiz Cc: Ola Lilja Cc: Jonas Aberg Signed-off-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 2 + drivers/regulator/Kconfig | 9 ++ drivers/regulator/Makefile | 2 +- drivers/regulator/tps6105x-regulator.c | 196 +++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 drivers/regulator/tps6105x-regulator.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index bc99288f8f39..8d7d098f7a03 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -132,6 +132,8 @@ config UCB1400_CORE config TPS6105X tristate "TPS61050/61052 Boost Converters" depends on I2C + select REGULATOR + select REGULATOR_FIXED_VOLTAGE help This option enables a driver for the TP61050/TPS61052 high-power "white LED driver". This boost converter is diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 395d35941b84..de75f67f4cc3 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -223,6 +223,15 @@ config REGULATOR_AB3100 AB3100 analog baseband dealing with power regulators for the system. +config REGULATOR_TPS6105X + tristate "TI TPS6105X Power regulators" + depends on TPS6105X + default y if TPS6105X + help + This driver supports TPS61050/TPS61052 voltage regulator chips. + It is a single boost converter primarily for white LEDs and + audio amplifiers. + config REGULATOR_TPS65023 tristate "TI TPS65023 Power regulators" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index e43b8524871e..d72a42756778 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o - +obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c new file mode 100644 index 000000000000..1661499feda4 --- /dev/null +++ b/drivers/regulator/tps6105x-regulator.c @@ -0,0 +1,196 @@ +/* + * Driver for TPS61050/61052 boost converters, typically used for white LEDs + * or audio amplifiers. + * + * Copyright (C) 2011 ST-Ericsson SA + * Written on behalf of Linaro for ST-Ericsson + * + * Author: Linus Walleij + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const int tps6105x_voltages[] = { + 4500000, + 5000000, + 5250000, + 5000000, /* There is an additional 5V */ +}; + +static int tps6105x_regulator_enable(struct regulator_dev *rdev) +{ + struct tps6105x *tps6105x = rdev_get_drvdata(rdev); + int ret; + + /* Activate voltage mode */ + ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + TPS6105X_REG0_MODE_MASK, + TPS6105X_REG0_MODE_VOLTAGE << TPS6105X_REG0_MODE_SHIFT); + if (ret) + return ret; + + return 0; +} + +static int tps6105x_regulator_disable(struct regulator_dev *rdev) +{ + struct tps6105x *tps6105x = rdev_get_drvdata(rdev); + int ret; + + /* Set into shutdown mode */ + ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + TPS6105X_REG0_MODE_MASK, + TPS6105X_REG0_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); + if (ret) + return ret; + + return 0; +} + +static int tps6105x_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct tps6105x *tps6105x = rdev_get_drvdata(rdev); + u8 regval; + int ret; + + ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); + if (ret) + return ret; + regval &= TPS6105X_REG0_MODE_MASK; + regval >>= TPS6105X_REG0_MODE_SHIFT; + + if (regval == TPS6105X_REG0_MODE_VOLTAGE) + return 1; + + return 0; +} + +static int tps6105x_regulator_get_voltage_sel(struct regulator_dev *rdev) +{ + struct tps6105x *tps6105x = rdev_get_drvdata(rdev); + u8 regval; + int ret; + + ret = tps6105x_get(tps6105x, TPS6105X_REG_0, ®val); + if (ret) + return ret; + + regval &= TPS6105X_REG0_VOLTAGE_MASK; + regval >>= TPS6105X_REG0_VOLTAGE_SHIFT; + return (int) regval; +} + +static int tps6105x_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned selector) +{ + struct tps6105x *tps6105x = rdev_get_drvdata(rdev); + int ret; + + ret = tps6105x_mask_and_set(tps6105x, TPS6105X_REG_0, + TPS6105X_REG0_VOLTAGE_MASK, + selector << TPS6105X_REG0_VOLTAGE_SHIFT); + if (ret) + return ret; + + return 0; +} + +static int tps6105x_regulator_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + if (selector >= ARRAY_SIZE(tps6105x_voltages)) + return -EINVAL; + + return tps6105x_voltages[selector]; +} + +static struct regulator_ops tps6105x_regulator_ops = { + .enable = tps6105x_regulator_enable, + .disable = tps6105x_regulator_disable, + .is_enabled = tps6105x_regulator_is_enabled, + .get_voltage_sel = tps6105x_regulator_get_voltage_sel, + .set_voltage_sel = tps6105x_regulator_set_voltage_sel, + .list_voltage = tps6105x_regulator_list_voltage, +}; + +static struct regulator_desc tps6105x_regulator_desc = { + .name = "tps6105x-boost", + .ops = &tps6105x_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = 0, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(tps6105x_voltages), +}; + +/* + * Registers the chip as a voltage regulator + */ +static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) +{ + struct tps6105x *tps6105x = mfd_get_data(pdev); + struct tps6105x_platform_data *pdata = tps6105x->pdata; + int ret; + + /* This instance is not set for regulator mode so bail out */ + if (pdata->mode != TPS6105X_MODE_VOLTAGE) { + dev_info(&pdev->dev, + "chip not in voltage mode mode, exit probe \n"); + return 0; + } + + /* Register regulator with framework */ + tps6105x->regulator = regulator_register(&tps6105x_regulator_desc, + &tps6105x->client->dev, + pdata->regulator_data, tps6105x); + if (IS_ERR(tps6105x->regulator)) { + ret = PTR_ERR(tps6105x->regulator); + dev_err(&tps6105x->client->dev, + "failed to register regulator\n"); + return ret; + } + + return 0; +} + +static int __devexit tps6105x_regulator_remove(struct platform_device *pdev) +{ + struct tps6105x *tps6105x = platform_get_drvdata(pdev); + regulator_unregister(tps6105x->regulator); + return 0; +} + +static struct platform_driver tps6105x_regulator_driver = { + .driver = { + .name = "tps6105x-regulator", + .owner = THIS_MODULE, + }, + .probe = tps6105x_regulator_probe, + .remove = __devexit_p(tps6105x_regulator_remove), +}; + +static __init int tps6105x_regulator_init(void) +{ + return platform_driver_register(&tps6105x_regulator_driver); +} +subsys_initcall(tps6105x_regulator_init); + +static __exit void tps6105x_regulator_exit(void) +{ + platform_driver_unregister(&tps6105x_regulator_driver); +} +module_exit(tps6105x_regulator_exit); + +MODULE_AUTHOR("Linus Walleij "); +MODULE_DESCRIPTION("TPS6105x regulator driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:tps6105x-regulator"); -- cgit v1.2.2 From aad343107b4c153dd9f3ffc3d0f32558a25438e9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Mar 2011 16:33:49 +0000 Subject: mfd: Staticise WM8994 PM ops They're not exported. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 5220af26419e..749c31d29b09 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -640,7 +640,8 @@ static const struct i2c_device_id wm8994_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); -UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, NULL); +static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, + NULL); static struct i2c_driver wm8994_i2c_driver = { .driver = { -- cgit v1.2.2 From 4c4d887822070410e3be519e1a4ff933fb899ba8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Mar 2011 21:40:51 +0000 Subject: mfd: Remove copy from WM831x I2C write function This saves us allocating an array on the stack, giving a meaningless performance improvement and ensuring that if drivers ever do large writes we'll not allocate large arrays on the stack. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-i2c.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c index 3853fa8e7cc2..a06cbc739716 100644 --- a/drivers/mfd/wm831x-i2c.c +++ b/drivers/mfd/wm831x-i2c.c @@ -51,17 +51,25 @@ static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg, int bytes, void *src) { struct i2c_client *i2c = wm831x->control_data; - unsigned char msg[bytes + 2]; + struct i2c_msg xfer[2]; int ret; reg = cpu_to_be16(reg); - memcpy(&msg[0], ®, 2); - memcpy(&msg[2], src, bytes); - ret = i2c_master_send(i2c, msg, bytes + 2); + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = 2; + xfer[0].buf = (char *)® + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_NOSTART; + xfer[1].len = bytes; + xfer[1].buf = (char *)src; + + ret = i2c_transfer(i2c->adapter, xfer, 2); if (ret < 0) return ret; - if (ret < bytes + 2) + if (ret != 2) return -EIO; return 0; -- cgit v1.2.2 From 334e9ab8f9bb90ddf1eff0b07609961a628064b6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Mar 2011 21:42:28 +0000 Subject: mfd: Avoid copying data in WM8994 I2C write As well as providing a trivial performance optimisation this also avoids allocating a copy of the message on the stack which is beneficial when doing large transfers. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 749c31d29b09..ce93796e7f57 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -580,25 +580,29 @@ static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg, return 0; } -/* Currently we allocate the write buffer on the stack; this is OK for - * small writes - if we need to do large writes this will need to be - * revised. - */ static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, int bytes, void *src) { struct i2c_client *i2c = wm8994->control_data; - unsigned char msg[bytes + 2]; + struct i2c_msg xfer[2]; int ret; reg = cpu_to_be16(reg); - memcpy(&msg[0], ®, 2); - memcpy(&msg[2], src, bytes); - ret = i2c_master_send(i2c, msg, bytes + 2); + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = 2; + xfer[0].buf = (char *)® + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_NOSTART; + xfer[1].len = bytes; + xfer[1].buf = (char *)src; + + ret = i2c_transfer(i2c->adapter, xfer, 2); if (ret < 0) return ret; - if (ret < bytes + 2) + if (ret != 2) return -EIO; return 0; -- cgit v1.2.2 From 4277163c2a451fd8db0883cde5e55cf61a70fe85 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Mar 2011 21:42:29 +0000 Subject: mfd: Push byte swap out of WM8994 bulk I/O For bulk I/O it is both convenient and more sensible to pre-swap the data rather than doing the swap as part of the I/O operation so move the byte swaps we're currently doing into the core write function into the register based functions, giving the bulk write function a straight pass through to the chip. This leaves reads inconsistent, this will be addressed as a followup patch. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index ce93796e7f57..475bd50d5528 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -107,9 +107,7 @@ static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, for (i = 0; i < bytes / 2; i++) { dev_vdbg(wm8994->dev, "Write %04x to R%d(0x%x)\n", - buf[i], reg + i, reg + i); - - buf[i] = cpu_to_be16(buf[i]); + be16_to_cpu(buf[i]), reg + i, reg + i); } return wm8994->write_dev(wm8994, reg, bytes, src); @@ -127,6 +125,8 @@ int wm8994_reg_write(struct wm8994 *wm8994, unsigned short reg, { int ret; + val = cpu_to_be16(val); + mutex_lock(&wm8994->io_lock); ret = wm8994_write(wm8994, reg, 2, &val); @@ -143,7 +143,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_write); * @wm8994: Device to write to * @reg: First register * @count: Number of registers - * @buf: Buffer to write from. + * @buf: Buffer to write from. Data must be big-endian formatted. */ int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, int count, u16 *buf) @@ -183,6 +183,8 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, r &= ~mask; r |= val; + r = cpu_to_be16(r); + ret = wm8994_write(wm8994, reg, 2, &r); out: -- cgit v1.2.2 From 07e73fbb2d52434e6b61019326f35040357e8efb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 17 Mar 2011 21:42:30 +0000 Subject: mfd: Constify WM8994 write path Allow const buffers to be passed in without type safety issues. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 475bd50d5528..3f5b7cc85f1d 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -97,9 +97,9 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, EXPORT_SYMBOL_GPL(wm8994_bulk_read); static int wm8994_write(struct wm8994 *wm8994, unsigned short reg, - int bytes, void *src) + int bytes, const void *src) { - u16 *buf = src; + const u16 *buf = src; int i; BUG_ON(bytes % 2); @@ -146,7 +146,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_write); * @buf: Buffer to write from. Data must be big-endian formatted. */ int wm8994_bulk_write(struct wm8994 *wm8994, unsigned short reg, - int count, u16 *buf) + int count, const u16 *buf) { int ret; @@ -583,7 +583,7 @@ static int wm8994_i2c_read_device(struct wm8994 *wm8994, unsigned short reg, } static int wm8994_i2c_write_device(struct wm8994 *wm8994, unsigned short reg, - int bytes, void *src) + int bytes, const void *src) { struct i2c_client *i2c = wm8994->control_data; struct i2c_msg xfer[2]; -- cgit v1.2.2 From 8bd4d7c4c500e88bff975bbcb7fe0d89da319cdd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 15 Mar 2011 14:26:37 +0100 Subject: mfd: Rename ab8500 gpadc header Rename AB8500 GPADC header so as not to be redunantly named. Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 2ad3115f7772..bc93b2e8230c 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include /* * GPADC register offsets -- cgit v1.2.2 From 316b6cc081b112546842d44ded21512bd8454a85 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 18 Mar 2011 12:50:10 +0000 Subject: mfd: Push byte swaps out of wm8994 bulk read path For consistency with the write path push byte swaps of the WM8994 register data out of the bulk read data path into the per-register APIs. The only user of the bulk register read is the interrupt code which is updated to do the swaps itself part of this patch. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 10 +++++----- drivers/mfd/wm8994-irq.c | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 3f5b7cc85f1d..e198d40292e7 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -40,10 +40,8 @@ static int wm8994_read(struct wm8994 *wm8994, unsigned short reg, return ret; for (i = 0; i < bytes / 2; i++) { - buf[i] = be16_to_cpu(buf[i]); - dev_vdbg(wm8994->dev, "Read %04x from R%d(0x%x)\n", - buf[i], reg + i, reg + i); + be16_to_cpu(buf[i]), reg + i, reg + i); } return 0; @@ -69,7 +67,7 @@ int wm8994_reg_read(struct wm8994 *wm8994, unsigned short reg) if (ret < 0) return ret; else - return val; + return be16_to_cpu(val); } EXPORT_SYMBOL_GPL(wm8994_reg_read); @@ -79,7 +77,7 @@ EXPORT_SYMBOL_GPL(wm8994_reg_read); * @wm8994: Device to read from * @reg: First register * @count: Number of registers - * @buf: Buffer to fill. + * @buf: Buffer to fill. The data will be returned big endian. */ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg, int count, u16 *buf) @@ -180,6 +178,8 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg, if (ret < 0) goto out; + r = be16_to_cpu(r); + r &= ~mask; r |= val; diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index f5e439a37dc5..1e3bf4a2ff8e 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -225,9 +225,11 @@ static irqreturn_t wm8994_irq_thread(int irq, void *data) return IRQ_NONE; } - /* Apply masking */ - for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) + /* Bit swap and apply masking */ + for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) { + status[i] = be16_to_cpu(status[i]); status[i] &= ~wm8994->irq_masks_cur[i]; + } /* Report */ for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) { -- cgit v1.2.2 From a696b89c582e3201ef10bfb0d0b3594e29b75e0f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 22 Mar 2011 20:19:28 +0000 Subject: sh: Use struct syscore_ops instead of sysdevs Convert the SuperH clocks framework and shared interrupt handling code to using struct syscore_ops instead of a sysdev classes and sysdevs for power managment. This reduces the code size significantly and simplifies it. The optimizations causing things not to be restored after creating a hibernation image are removed, but they might lead to undesirable effects during resume from hibernation (e.g. the clocks would be left as the boot kernel set them, which might be not the same way as the hibernated kernel had seen them before the hibernation). This also is necessary for removing sysdevs from the kernel entirely in the future. Signed-off-by: Rafael J. Wysocki Signed-off-by: Paul Mundt --- drivers/sh/clk/core.c | 68 +++++++++----------------------- drivers/sh/intc/core.c | 95 ++++++++++++++++++++++----------------------- drivers/sh/intc/internals.h | 1 - 3 files changed, 65 insertions(+), 99 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index 5f63c3b83828..4f64183b27fa 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -630,68 +630,36 @@ long clk_round_parent(struct clk *clk, unsigned long target, EXPORT_SYMBOL_GPL(clk_round_parent); #ifdef CONFIG_PM -static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) +static void clks_core_resume(void) { - static pm_message_t prev_state; struct clk *clkp; - switch (state.event) { - case PM_EVENT_ON: - /* Resumeing from hibernation */ - if (prev_state.event != PM_EVENT_FREEZE) - break; - - list_for_each_entry(clkp, &clock_list, node) { - if (likely(clkp->ops)) { - unsigned long rate = clkp->rate; - - if (likely(clkp->ops->set_parent)) - clkp->ops->set_parent(clkp, - clkp->parent); - if (likely(clkp->ops->set_rate)) - clkp->ops->set_rate(clkp, rate); - else if (likely(clkp->ops->recalc)) - clkp->rate = clkp->ops->recalc(clkp); - } + list_for_each_entry(clkp, &clock_list, node) { + if (likely(clkp->ops)) { + unsigned long rate = clkp->rate; + + if (likely(clkp->ops->set_parent)) + clkp->ops->set_parent(clkp, + clkp->parent); + if (likely(clkp->ops->set_rate)) + clkp->ops->set_rate(clkp, rate); + else if (likely(clkp->ops->recalc)) + clkp->rate = clkp->ops->recalc(clkp); } - break; - case PM_EVENT_FREEZE: - break; - case PM_EVENT_SUSPEND: - break; } - - prev_state = state; - return 0; -} - -static int clks_sysdev_resume(struct sys_device *dev) -{ - return clks_sysdev_suspend(dev, PMSG_ON); } -static struct sysdev_class clks_sysdev_class = { - .name = "clks", -}; - -static struct sysdev_driver clks_sysdev_driver = { - .suspend = clks_sysdev_suspend, - .resume = clks_sysdev_resume, -}; - -static struct sys_device clks_sysdev_dev = { - .cls = &clks_sysdev_class, +static struct syscore_ops clks_syscore_ops = { + .resume = clks_core_resume, }; -static int __init clk_sysdev_init(void) +static int __init clk_syscore_init(void) { - sysdev_class_register(&clks_sysdev_class); - sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver); - sysdev_register(&clks_sysdev_dev); + register_syscore_ops(&clks_syscore_ops); return 0; } -subsys_initcall(clk_sysdev_init); +subsys_initcall(clk_syscore_init); #endif /* diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 9739431092d1..5833afbf08d7 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -376,91 +377,89 @@ err0: return -ENOMEM; } -static ssize_t -show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) +static int intc_suspend(void) { struct intc_desc_int *d; - d = container_of(dev, struct intc_desc_int, sysdev); + list_for_each_entry(d, &intc_list, list) { + int irq; - return sprintf(buf, "%s\n", d->chip.name); -} + /* enable wakeup irqs belonging to this intc controller */ + for_each_active_irq(irq) { + struct irq_data *data; + struct irq_desc *desc; + struct irq_chip *chip; -static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL); + data = irq_get_irq_data(irq); + chip = irq_data_get_irq_chip(data); + if (chip != &d->chip) + continue; + desc = irq_to_desc(irq); + if ((desc->status & IRQ_WAKEUP)) + chip->irq_enable(data); + } + } + + return 0; +} -static int intc_suspend(struct sys_device *dev, pm_message_t state) +static void intc_resume(void) { struct intc_desc_int *d; - struct irq_data *data; - struct irq_desc *desc; - struct irq_chip *chip; - int irq; - - /* get intc controller associated with this sysdev */ - d = container_of(dev, struct intc_desc_int, sysdev); - switch (state.event) { - case PM_EVENT_ON: - if (d->state.event != PM_EVENT_FREEZE) - break; + list_for_each_entry(d, &intc_list, list) { + int irq; for_each_active_irq(irq) { - desc = irq_to_desc(irq); + struct irq_data *data; + struct irq_desc *desc; + struct irq_chip *chip; + data = irq_get_irq_data(irq); chip = irq_data_get_irq_chip(data); - /* * This will catch the redirect and VIRQ cases * due to the dummy_irq_chip being inserted. */ if (chip != &d->chip) continue; + desc = irq_to_desc(irq); if (desc->status & IRQ_DISABLED) chip->irq_disable(data); else chip->irq_enable(data); } - break; - case PM_EVENT_FREEZE: - /* nothing has to be done */ - break; - case PM_EVENT_SUSPEND: - /* enable wakeup irqs belonging to this intc controller */ - for_each_active_irq(irq) { - desc = irq_to_desc(irq); - data = irq_get_irq_data(irq); - chip = irq_data_get_irq_chip(data); - - if (chip != &d->chip) - continue; - if ((desc->status & IRQ_WAKEUP)) - chip->irq_enable(data); - } - break; } - - d->state = state; - - return 0; } -static int intc_resume(struct sys_device *dev) -{ - return intc_suspend(dev, PMSG_ON); -} +struct syscore_ops intc_syscore_ops = { + .suspend = intc_suspend, + .resume = intc_resume, +}; struct sysdev_class intc_sysdev_class = { .name = "intc", - .suspend = intc_suspend, - .resume = intc_resume, }; -/* register this intc as sysdev to allow suspend/resume */ +static ssize_t +show_intc_name(struct sys_device *dev, struct sysdev_attribute *attr, char *buf) +{ + struct intc_desc_int *d; + + d = container_of(dev, struct intc_desc_int, sysdev); + + return sprintf(buf, "%s\n", d->chip.name); +} + +static SYSDEV_ATTR(name, S_IRUGO, show_intc_name, NULL); + static int __init register_intc_sysdevs(void) { struct intc_desc_int *d; int error; + register_syscore_ops(&intc_syscore_ops); + error = sysdev_class_register(&intc_sysdev_class); if (!error) { list_for_each_entry(d, &intc_list, list) { diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h index 0cf8260971d4..df36a421e675 100644 --- a/drivers/sh/intc/internals.h +++ b/drivers/sh/intc/internals.h @@ -53,7 +53,6 @@ struct intc_desc_int { struct list_head list; struct sys_device sysdev; struct radix_tree_root tree; - pm_message_t state; raw_spinlock_t lock; unsigned int index; unsigned long *reg; -- cgit v1.2.2 From 877a55979c189c590e819a61cbbe2b7947875f17 Mon Sep 17 00:00:00 2001 From: John Hughes Date: Wed, 4 Nov 2009 19:01:22 +0100 Subject: [SCSI] ses: show devices for enclosures with no page 7 enclosure page 7 gives us the "pretty" names of the enclosure slots. Without a page 7, we can still use the enclosure code as long as we make up numeric names for the slots. Unfortunately, the current code fails to add any devices because the check for page 10 is in the wrong place if we have no page 7. Fix it so that devices show up even if the enclosure has no page 7. Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/ses.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 7f5a6a86f820..3b00e907b917 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -390,9 +390,9 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, len = (desc_ptr[2] << 8) + desc_ptr[3]; /* skip past overall descriptor */ desc_ptr += len + 4; - if (ses_dev->page10) - addl_desc_ptr = ses_dev->page10 + 8; } + if (ses_dev->page10) + addl_desc_ptr = ses_dev->page10 + 8; type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; components = 0; for (i = 0; i < types; i++, type_ptr += 4) { -- cgit v1.2.2 From 523f3c80bc41d663d5b35c0cd6ce0fad7f3e7188 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Fri, 4 Feb 2011 15:24:14 +0300 Subject: [SCSI] scsi_transport_iscsi: make priv_sess file writeable only by root Signed-off-by: Vasiliy Kulikov Acked-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index b4218390941e..3fd16d7212de 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1917,7 +1917,7 @@ store_priv_session_##field(struct device *dev, \ #define iscsi_priv_session_rw_attr(field, format) \ iscsi_priv_session_attr_show(field, format) \ iscsi_priv_session_attr_store(field) \ -static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUGO, \ +static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUSR, \ show_priv_session_##field, \ store_priv_session_##field) iscsi_priv_session_rw_attr(recovery_tmo, "%d"); -- cgit v1.2.2 From 463b8977ecebf8cf590c33191d43ea0b059381c6 Mon Sep 17 00:00:00 2001 From: HighPoint Linux Team Date: Wed, 23 Feb 2011 16:28:44 +0800 Subject: [SCSI] mvsas: Add support for HighPoint RR27xx series HBA This patch is to add support for HighPoint RR27xx SAS/SATA HBA which is based on Marvell 88SE9480 chipset. Signed-off-by: HighPoint Linux Team Signed-off-by: James Bottomley --- drivers/scsi/mvsas/mv_init.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index 19ad34f381a5..938d045e4180 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -663,6 +663,13 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = { { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, + { PCI_VDEVICE(TTI, 0x2710), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2720), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2721), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2722), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, + { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, { } /* terminate list */ }; -- cgit v1.2.2 From 5a6f133eea2d0b4f8f75367b803fef0f03acf268 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 11 Mar 2011 16:05:35 -0500 Subject: [SCSI] lpfc 8.3.22: Add new mailbox command and new BSG fix - Add new Queue Create Mailbox version support - Make lpfc_bsg_wake_mbox_wait routine check the mailboxes job reference before using it. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_bsg.c | 18 ++-- drivers/scsi/lpfc/lpfc_hw4.h | 101 +++++++++++++------ drivers/scsi/lpfc/lpfc_sli.c | 228 ++++++++++++++++++++++++++++--------------- 3 files changed, 229 insertions(+), 118 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 0dd43bb91618..5a4a2f36ae6d 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -2479,16 +2479,18 @@ lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) from = (uint8_t *)dd_data->context_un.mbox.mb; job = dd_data->context_un.mbox.set_job; - size = job->reply_payload.payload_len; - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - from, size); - job->reply->result = 0; + if (job) { + size = job->reply_payload.payload_len; + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + from, size); + job->reply->result = 0; + job->dd_data = NULL; + job->job_done(job); + } dd_data->context_un.mbox.set_job = NULL; - job->dd_data = NULL; - job->job_done(job); /* need to hold the lock until we call job done to hold off * the timeout handler returning to the midlayer while * we are stillprocessing the job diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index c7178d60c7bf..b42b6994fd94 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -711,21 +711,27 @@ struct lpfc_sli4_cfg_mhdr { union lpfc_sli4_cfg_shdr { struct { uint32_t word6; -#define lpfc_mbox_hdr_opcode_SHIFT 0 -#define lpfc_mbox_hdr_opcode_MASK 0x000000FF -#define lpfc_mbox_hdr_opcode_WORD word6 -#define lpfc_mbox_hdr_subsystem_SHIFT 8 -#define lpfc_mbox_hdr_subsystem_MASK 0x000000FF -#define lpfc_mbox_hdr_subsystem_WORD word6 -#define lpfc_mbox_hdr_port_number_SHIFT 16 -#define lpfc_mbox_hdr_port_number_MASK 0x000000FF -#define lpfc_mbox_hdr_port_number_WORD word6 -#define lpfc_mbox_hdr_domain_SHIFT 24 -#define lpfc_mbox_hdr_domain_MASK 0x000000FF -#define lpfc_mbox_hdr_domain_WORD word6 +#define lpfc_mbox_hdr_opcode_SHIFT 0 +#define lpfc_mbox_hdr_opcode_MASK 0x000000FF +#define lpfc_mbox_hdr_opcode_WORD word6 +#define lpfc_mbox_hdr_subsystem_SHIFT 8 +#define lpfc_mbox_hdr_subsystem_MASK 0x000000FF +#define lpfc_mbox_hdr_subsystem_WORD word6 +#define lpfc_mbox_hdr_port_number_SHIFT 16 +#define lpfc_mbox_hdr_port_number_MASK 0x000000FF +#define lpfc_mbox_hdr_port_number_WORD word6 +#define lpfc_mbox_hdr_domain_SHIFT 24 +#define lpfc_mbox_hdr_domain_MASK 0x000000FF +#define lpfc_mbox_hdr_domain_WORD word6 uint32_t timeout; uint32_t request_length; - uint32_t reserved9; + uint32_t word9; +#define lpfc_mbox_hdr_version_SHIFT 0 +#define lpfc_mbox_hdr_version_MASK 0x000000FF +#define lpfc_mbox_hdr_version_WORD word9 +#define LPFC_Q_CREATE_VERSION_2 2 +#define LPFC_Q_CREATE_VERSION_1 1 +#define LPFC_Q_CREATE_VERSION_0 0 } request; struct { uint32_t word6; @@ -917,9 +923,12 @@ struct cq_context { #define LPFC_CQ_CNT_512 0x1 #define LPFC_CQ_CNT_1024 0x2 uint32_t word1; -#define lpfc_cq_eq_id_SHIFT 22 +#define lpfc_cq_eq_id_SHIFT 22 /* Version 0 Only */ #define lpfc_cq_eq_id_MASK 0x000000FF #define lpfc_cq_eq_id_WORD word1 +#define lpfc_cq_eq_id_2_SHIFT 0 /* Version 2 Only */ +#define lpfc_cq_eq_id_2_MASK 0x0000FFFF +#define lpfc_cq_eq_id_2_WORD word1 uint32_t reserved0; uint32_t reserved1; }; @@ -929,6 +938,9 @@ struct lpfc_mbx_cq_create { union { struct { uint32_t word0; +#define lpfc_mbx_cq_create_page_size_SHIFT 16 /* Version 2 Only */ +#define lpfc_mbx_cq_create_page_size_MASK 0x000000FF +#define lpfc_mbx_cq_create_page_size_WORD word0 #define lpfc_mbx_cq_create_num_pages_SHIFT 0 #define lpfc_mbx_cq_create_num_pages_MASK 0x0000FFFF #define lpfc_mbx_cq_create_num_pages_WORD word0 @@ -969,7 +981,7 @@ struct wq_context { struct lpfc_mbx_wq_create { struct mbox_header header; union { - struct { + struct { /* Version 0 Request */ uint32_t word0; #define lpfc_mbx_wq_create_num_pages_SHIFT 0 #define lpfc_mbx_wq_create_num_pages_MASK 0x0000FFFF @@ -979,6 +991,23 @@ struct lpfc_mbx_wq_create { #define lpfc_mbx_wq_create_cq_id_WORD word0 struct dma_address page[LPFC_MAX_WQ_PAGE]; } request; + struct { /* Version 1 Request */ + uint32_t word0; /* Word 0 is the same as in v0 */ + uint32_t word1; +#define lpfc_mbx_wq_create_page_size_SHIFT 0 +#define lpfc_mbx_wq_create_page_size_MASK 0x000000FF +#define lpfc_mbx_wq_create_page_size_WORD word1 +#define lpfc_mbx_wq_create_wqe_size_SHIFT 8 +#define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F +#define lpfc_mbx_wq_create_wqe_size_WORD word1 +#define LPFC_WQ_WQE_SIZE_64 0x5 +#define LPFC_WQ_WQE_SIZE_128 0x6 +#define lpfc_mbx_wq_create_wqe_count_SHIFT 16 +#define lpfc_mbx_wq_create_wqe_count_MASK 0x0000FFFF +#define lpfc_mbx_wq_create_wqe_count_WORD word1 + uint32_t word2; + struct dma_address page[LPFC_MAX_WQ_PAGE-1]; + } request_1; struct { uint32_t word0; #define lpfc_mbx_wq_create_q_id_SHIFT 0 @@ -1007,13 +1036,22 @@ struct lpfc_mbx_wq_destroy { #define LPFC_DATA_BUF_SIZE 2048 struct rq_context { uint32_t word0; -#define lpfc_rq_context_rq_size_SHIFT 16 -#define lpfc_rq_context_rq_size_MASK 0x0000000F -#define lpfc_rq_context_rq_size_WORD word0 +#define lpfc_rq_context_rqe_count_SHIFT 16 /* Version 0 Only */ +#define lpfc_rq_context_rqe_count_MASK 0x0000000F +#define lpfc_rq_context_rqe_count_WORD word0 #define LPFC_RQ_RING_SIZE_512 9 /* 512 entries */ #define LPFC_RQ_RING_SIZE_1024 10 /* 1024 entries */ #define LPFC_RQ_RING_SIZE_2048 11 /* 2048 entries */ #define LPFC_RQ_RING_SIZE_4096 12 /* 4096 entries */ +#define lpfc_rq_context_rqe_count_1_SHIFT 16 /* Version 1 Only */ +#define lpfc_rq_context_rqe_count_1_MASK 0x0000FFFF +#define lpfc_rq_context_rqe_count_1_WORD word0 +#define lpfc_rq_context_rqe_size_SHIFT 8 /* Version 1 Only */ +#define lpfc_rq_context_rqe_size_MASK 0x0000000F +#define lpfc_rq_context_rqe_size_WORD word0 +#define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */ +#define lpfc_rq_context_page_size_MASK 0x000000FF +#define lpfc_rq_context_page_size_WORD word0 uint32_t reserved1; uint32_t word2; #define lpfc_rq_context_cq_id_SHIFT 16 @@ -1022,7 +1060,7 @@ struct rq_context { #define lpfc_rq_context_buf_size_SHIFT 0 #define lpfc_rq_context_buf_size_MASK 0x0000FFFF #define lpfc_rq_context_buf_size_WORD word2 - uint32_t reserved3; + uint32_t buffer_size; /* Version 1 Only */ }; struct lpfc_mbx_rq_create { @@ -1062,16 +1100,16 @@ struct lpfc_mbx_rq_destroy { struct mq_context { uint32_t word0; -#define lpfc_mq_context_cq_id_SHIFT 22 +#define lpfc_mq_context_cq_id_SHIFT 22 /* Version 0 Only */ #define lpfc_mq_context_cq_id_MASK 0x000003FF #define lpfc_mq_context_cq_id_WORD word0 -#define lpfc_mq_context_count_SHIFT 16 -#define lpfc_mq_context_count_MASK 0x0000000F -#define lpfc_mq_context_count_WORD word0 -#define LPFC_MQ_CNT_16 0x5 -#define LPFC_MQ_CNT_32 0x6 -#define LPFC_MQ_CNT_64 0x7 -#define LPFC_MQ_CNT_128 0x8 +#define lpfc_mq_context_ring_size_SHIFT 16 +#define lpfc_mq_context_ring_size_MASK 0x0000000F +#define lpfc_mq_context_ring_size_WORD word0 +#define LPFC_MQ_RING_SIZE_16 0x5 +#define LPFC_MQ_RING_SIZE_32 0x6 +#define LPFC_MQ_RING_SIZE_64 0x7 +#define LPFC_MQ_RING_SIZE_128 0x8 uint32_t word1; #define lpfc_mq_context_valid_SHIFT 31 #define lpfc_mq_context_valid_MASK 0x00000001 @@ -1105,9 +1143,12 @@ struct lpfc_mbx_mq_create_ext { union { struct { uint32_t word0; -#define lpfc_mbx_mq_create_ext_num_pages_SHIFT 0 -#define lpfc_mbx_mq_create_ext_num_pages_MASK 0x0000FFFF -#define lpfc_mbx_mq_create_ext_num_pages_WORD word0 +#define lpfc_mbx_mq_create_ext_num_pages_SHIFT 0 +#define lpfc_mbx_mq_create_ext_num_pages_MASK 0x0000FFFF +#define lpfc_mbx_mq_create_ext_num_pages_WORD word0 +#define lpfc_mbx_mq_create_ext_cq_id_SHIFT 16 /* Version 1 Only */ +#define lpfc_mbx_mq_create_ext_cq_id_MASK 0x0000FFFF +#define lpfc_mbx_mq_create_ext_cq_id_WORD word0 uint32_t async_evt_bmap; #define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK #define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001 diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 2ee0374a9908..84234a4c54ce 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -10403,7 +10403,6 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; @@ -10413,11 +10412,22 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, LPFC_MBOX_OPCODE_CQ_CREATE, length, LPFC_SLI4_MBX_EMBED); cq_create = &mbox->u.mqe.un.cq_create; + shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr; bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request, cq->page_count); bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1); bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1); - bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, eq->queue_id); + bf_set(lpfc_mbox_hdr_version, &shdr->request, + phba->sli4_hba.pc_sli4_params.cqv); + if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { + bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, + (PAGE_SIZE/SLI4_PAGE_SIZE)); + bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context, + eq->queue_id); + } else { + bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, + eq->queue_id); + } switch (cq->entry_count) { default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -10449,7 +10459,6 @@ lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { @@ -10515,20 +10524,20 @@ lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq, bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1); switch (mq->entry_count) { case 16: - bf_set(lpfc_mq_context_count, &mq_create->u.request.context, - LPFC_MQ_CNT_16); + bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, + LPFC_MQ_RING_SIZE_16); break; case 32: - bf_set(lpfc_mq_context_count, &mq_create->u.request.context, - LPFC_MQ_CNT_32); + bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, + LPFC_MQ_RING_SIZE_32); break; case 64: - bf_set(lpfc_mq_context_count, &mq_create->u.request.context, - LPFC_MQ_CNT_64); + bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, + LPFC_MQ_RING_SIZE_64); break; case 128: - bf_set(lpfc_mq_context_count, &mq_create->u.request.context, - LPFC_MQ_CNT_128); + bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, + LPFC_MQ_RING_SIZE_128); break; } list_for_each_entry(dmabuf, &mq->page_list, list) { @@ -10586,6 +10595,7 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, length, LPFC_SLI4_MBX_EMBED); mq_create_ext = &mbox->u.mqe.un.mq_create_ext; + shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr; bf_set(lpfc_mbx_mq_create_ext_num_pages, &mq_create_ext->u.request, mq->page_count); bf_set(lpfc_mbx_mq_create_ext_async_evt_link, @@ -10598,9 +10608,15 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, &mq_create_ext->u.request, 1); bf_set(lpfc_mbx_mq_create_ext_async_evt_sli, &mq_create_ext->u.request, 1); - bf_set(lpfc_mq_context_cq_id, - &mq_create_ext->u.request.context, cq->queue_id); bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1); + bf_set(lpfc_mbox_hdr_version, &shdr->request, + phba->sli4_hba.pc_sli4_params.mqv); + if (phba->sli4_hba.pc_sli4_params.mqv == LPFC_Q_CREATE_VERSION_1) + bf_set(lpfc_mbx_mq_create_ext_cq_id, &mq_create_ext->u.request, + cq->queue_id); + else + bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context, + cq->queue_id); switch (mq->entry_count) { default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, @@ -10610,20 +10626,24 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, return -EINVAL; /* otherwise default to smallest count (drop through) */ case 16: - bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, - LPFC_MQ_CNT_16); + bf_set(lpfc_mq_context_ring_size, + &mq_create_ext->u.request.context, + LPFC_MQ_RING_SIZE_16); break; case 32: - bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, - LPFC_MQ_CNT_32); + bf_set(lpfc_mq_context_ring_size, + &mq_create_ext->u.request.context, + LPFC_MQ_RING_SIZE_32); break; case 64: - bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, - LPFC_MQ_CNT_64); + bf_set(lpfc_mq_context_ring_size, + &mq_create_ext->u.request.context, + LPFC_MQ_RING_SIZE_64); break; case 128: - bf_set(lpfc_mq_context_count, &mq_create_ext->u.request.context, - LPFC_MQ_CNT_128); + bf_set(lpfc_mq_context_ring_size, + &mq_create_ext->u.request.context, + LPFC_MQ_RING_SIZE_128); break; } list_for_each_entry(dmabuf, &mq->page_list, list) { @@ -10634,7 +10654,6 @@ lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, putPaddrHigh(dmabuf->phys); } rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr; mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, &mq_create_ext->u.response); if (rc != MBX_SUCCESS) { @@ -10711,6 +10730,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; + struct dma_address *page; if (!phba->sli4_hba.pc_sli4_params.supported) hw_page_size = SLI4_PAGE_SIZE; @@ -10724,20 +10744,42 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, LPFC_MBOX_OPCODE_FCOE_WQ_CREATE, length, LPFC_SLI4_MBX_EMBED); wq_create = &mbox->u.mqe.un.wq_create; + shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr; bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request, wq->page_count); bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request, cq->queue_id); + bf_set(lpfc_mbox_hdr_version, &shdr->request, + phba->sli4_hba.pc_sli4_params.wqv); + if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) { + bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, + wq->entry_count); + switch (wq->entry_size) { + default: + case 64: + bf_set(lpfc_mbx_wq_create_wqe_size, + &wq_create->u.request_1, + LPFC_WQ_WQE_SIZE_64); + break; + case 128: + bf_set(lpfc_mbx_wq_create_wqe_size, + &wq_create->u.request_1, + LPFC_WQ_WQE_SIZE_128); + break; + } + bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, + (PAGE_SIZE/SLI4_PAGE_SIZE)); + page = wq_create->u.request_1.page; + } else { + page = wq_create->u.request.page; + } list_for_each_entry(dmabuf, &wq->page_list, list) { memset(dmabuf->virt, 0, hw_page_size); - wq_create->u.request.page[dmabuf->buffer_tag].addr_lo = - putPaddrLow(dmabuf->phys); - wq_create->u.request.page[dmabuf->buffer_tag].addr_hi = - putPaddrHigh(dmabuf->phys); + page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys); + page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys); } rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { @@ -10815,37 +10857,51 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, length, LPFC_SLI4_MBX_EMBED); rq_create = &mbox->u.mqe.un.rq_create; - switch (hrq->entry_count) { - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2535 Unsupported RQ count. (%d)\n", - hrq->entry_count); - if (hrq->entry_count < 512) - return -EINVAL; - /* otherwise default to smallest count (drop through) */ - case 512: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_512); - break; - case 1024: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_1024); - break; - case 2048: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_2048); - break; - case 4096: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_4096); - break; + shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; + bf_set(lpfc_mbox_hdr_version, &shdr->request, + phba->sli4_hba.pc_sli4_params.rqv); + if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { + bf_set(lpfc_rq_context_rqe_count_1, + &rq_create->u.request.context, + hrq->entry_count); + rq_create->u.request.context.buffer_size = LPFC_HDR_BUF_SIZE; + } else { + switch (hrq->entry_count) { + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2535 Unsupported RQ count. (%d)\n", + hrq->entry_count); + if (hrq->entry_count < 512) + return -EINVAL; + /* otherwise default to smallest count (drop through) */ + case 512: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_512); + break; + case 1024: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_1024); + break; + case 2048: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_2048); + break; + case 4096: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_4096); + break; + } + bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, + LPFC_HDR_BUF_SIZE); } bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, cq->queue_id); bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, hrq->page_count); - bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, - LPFC_HDR_BUF_SIZE); list_for_each_entry(dmabuf, &hrq->page_list, list) { memset(dmabuf->virt, 0, hw_page_size); rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = @@ -10855,7 +10911,6 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, } rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); if (shdr_status || shdr_add_status || rc) { @@ -10881,37 +10936,50 @@ lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, length, LPFC_SLI4_MBX_EMBED); - switch (drq->entry_count) { - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2536 Unsupported RQ count. (%d)\n", - drq->entry_count); - if (drq->entry_count < 512) - return -EINVAL; - /* otherwise default to smallest count (drop through) */ - case 512: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_512); - break; - case 1024: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_1024); - break; - case 2048: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_2048); - break; - case 4096: - bf_set(lpfc_rq_context_rq_size, &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_4096); - break; + bf_set(lpfc_mbox_hdr_version, &shdr->request, + phba->sli4_hba.pc_sli4_params.rqv); + if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { + bf_set(lpfc_rq_context_rqe_count_1, + &rq_create->u.request.context, + hrq->entry_count); + rq_create->u.request.context.buffer_size = LPFC_DATA_BUF_SIZE; + } else { + switch (drq->entry_count) { + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2536 Unsupported RQ count. (%d)\n", + drq->entry_count); + if (drq->entry_count < 512) + return -EINVAL; + /* otherwise default to smallest count (drop through) */ + case 512: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_512); + break; + case 1024: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_1024); + break; + case 2048: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_2048); + break; + case 4096: + bf_set(lpfc_rq_context_rqe_count, + &rq_create->u.request.context, + LPFC_RQ_RING_SIZE_4096); + break; + } + bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, + LPFC_DATA_BUF_SIZE); } bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, cq->queue_id); bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, drq->page_count); - bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, - LPFC_DATA_BUF_SIZE); list_for_each_entry(dmabuf, &drq->page_list, list) { rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys); -- cgit v1.2.2 From 7f86059ac016d8662e5fbfab4875529510977b47 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 11 Mar 2011 16:05:52 -0500 Subject: [SCSI] lpfc 8.3.22: T10-DIF corrections T10-DIF corrections - Add selective reset jump table entry - Split T10-DIF BDEs that cross 4K boundary Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 2 ++ drivers/scsi/lpfc/lpfc_attr.c | 4 ++-- drivers/scsi/lpfc/lpfc_crtn.h | 4 ++-- drivers/scsi/lpfc/lpfc_hw.h | 11 +++++++++++ drivers/scsi/lpfc/lpfc_init.c | 1 + drivers/scsi/lpfc/lpfc_scsi.c | 41 ++++++++++++++++++++++++++++++----------- 6 files changed, 48 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index b64c6da870d3..d9869f417d4f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -539,6 +539,8 @@ struct lpfc_hba { (struct lpfc_hba *, uint32_t); int (*lpfc_hba_down_link) (struct lpfc_hba *, uint32_t); + int (*lpfc_selective_reset) + (struct lpfc_hba *); /* SLI4 specific HBA data structure */ struct lpfc_sli4_hba sli4_hba; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e7c020df12fa..427c046e8209 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -685,7 +685,7 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) * -EIO reset not configured or error posting the event * zero for success **/ -static int +int lpfc_selective_reset(struct lpfc_hba *phba) { struct completion online_compl; @@ -746,7 +746,7 @@ lpfc_issue_reset(struct device *dev, struct device_attribute *attr, int status = -EINVAL; if (strncmp(buf, "selective", sizeof("selective") - 1) == 0) - status = lpfc_selective_reset(phba); + status = phba->lpfc_selective_reset(phba); if (status == 0) return strlen(buf); diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 3d40023f4804..60281d875184 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -254,8 +254,8 @@ uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); void lpfc_sli_cancel_iocbs(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t); void lpfc_sli_wake_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *); - -void lpfc_reset_barrier(struct lpfc_hba * phba); +int lpfc_selective_reset(struct lpfc_hba *); +void lpfc_reset_barrier(struct lpfc_hba *); int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); int lpfc_sli_brdkill(struct lpfc_hba *); int lpfc_sli_brdreset(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 94ae37c5111a..057ab82bf399 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1713,6 +1713,17 @@ struct lpfc_pde6 { #define pde6_apptagval_WORD word2 }; +struct lpfc_pde7 { + uint32_t word0; +#define pde7_type_SHIFT 24 +#define pde7_type_MASK 0x000000ff +#define pde7_type_WORD word0 +#define pde7_rsvd0_SHIFT 0 +#define pde7_rsvd0_MASK 0x00ffffff +#define pde7_rsvd0_WORD word0 + uint32_t addrHigh; + uint32_t addrLow; +}; /* Structure for MB Command LOAD_SM and DOWN_LOAD */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 35665cfb5689..29aab9432af9 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4474,6 +4474,7 @@ lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) { phba->lpfc_hba_init_link = lpfc_hba_init_link; phba->lpfc_hba_down_link = lpfc_hba_down_link; + phba->lpfc_selective_reset = lpfc_selective_reset; switch (dev_grp) { case LPFC_PCI_DEV_LP: phba->lpfc_hba_down_post = lpfc_hba_down_post_s3; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index bf34178b80bf..e3a1d295e4dc 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1514,10 +1514,11 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, struct scatterlist *sgpe = NULL; /* s/g prot entry */ struct lpfc_pde5 *pde5 = NULL; struct lpfc_pde6 *pde6 = NULL; - struct ulp_bde64 *prot_bde = NULL; + struct lpfc_pde7 *pde7 = NULL; dma_addr_t dataphysaddr, protphysaddr; unsigned short curr_data = 0, curr_prot = 0; - unsigned int split_offset, protgroup_len; + unsigned int split_offset; + unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder; unsigned int protgrp_blks, protgrp_bytes; unsigned int remainder, subtotal; int status; @@ -1585,23 +1586,33 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, bpl++; /* setup the first BDE that points to protection buffer */ - prot_bde = (struct ulp_bde64 *) bpl; - protphysaddr = sg_dma_address(sgpe); - prot_bde->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr)); - prot_bde->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr)); - protgroup_len = sg_dma_len(sgpe); + protphysaddr = sg_dma_address(sgpe) + protgroup_offset; + protgroup_len = sg_dma_len(sgpe) - protgroup_offset; /* must be integer multiple of the DIF block length */ BUG_ON(protgroup_len % 8); + pde7 = (struct lpfc_pde7 *) bpl; + memset(pde7, 0, sizeof(struct lpfc_pde7)); + bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR); + + pde7->addrHigh = le32_to_cpu(putPaddrLow(protphysaddr)); + pde7->addrLow = le32_to_cpu(putPaddrHigh(protphysaddr)); + protgrp_blks = protgroup_len / 8; protgrp_bytes = protgrp_blks * blksize; - prot_bde->tus.f.bdeSize = protgroup_len; - prot_bde->tus.f.bdeFlags = LPFC_PDE7_DESCRIPTOR; - prot_bde->tus.w = le32_to_cpu(bpl->tus.w); + /* check if this pde is crossing the 4K boundary; if so split */ + if ((pde7->addrLow & 0xfff) + protgroup_len > 0x1000) { + protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff); + protgroup_offset += protgroup_remainder; + protgrp_blks = protgroup_remainder / 8; + protgrp_bytes = protgroup_remainder * blksize; + } else { + protgroup_offset = 0; + curr_prot++; + } - curr_prot++; num_bde++; /* setup BDE's for data blocks associated with DIF data */ @@ -1653,6 +1664,13 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, } + if (protgroup_offset) { + /* update the reference tag */ + reftag += protgrp_blks; + bpl++; + continue; + } + /* are we done ? */ if (curr_prot == protcnt) { alldone = 1; @@ -1675,6 +1693,7 @@ out: return num_bde; } + /* * Given a SCSI command that supports DIF, determine composition of protection * groups involved in setting up buffer lists -- cgit v1.2.2 From 9940b97bb30d7435c881418c809ed652eb329583 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 11 Mar 2011 16:06:12 -0500 Subject: [SCSI] lpfc 8.3.22: Add support for PCI Adapter Failure Periodically poll adapter registers to detect pci adapter failure (reads return -1). On failure, take port offline, set error indicators and wake up worker threads. Threads will take adapter offline. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 25 ++++-- drivers/scsi/lpfc/lpfc_attr.c | 10 ++- drivers/scsi/lpfc/lpfc_bsg.c | 16 +++- drivers/scsi/lpfc/lpfc_els.c | 3 +- drivers/scsi/lpfc/lpfc_hw.h | 2 +- drivers/scsi/lpfc/lpfc_init.c | 38 ++++++--- drivers/scsi/lpfc/lpfc_sli.c | 184 +++++++++++++++++++++++++++++++----------- 7 files changed, 207 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index d9869f417d4f..60e98a62f308 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -897,7 +897,18 @@ lpfc_worker_wake_up(struct lpfc_hba *phba) return; } -static inline void +static inline int +lpfc_readl(void __iomem *addr, uint32_t *data) +{ + uint32_t temp; + temp = readl(addr); + if (temp == 0xffffffff) + return -EIO; + *data = temp; + return 0; +} + +static inline int lpfc_sli_read_hs(struct lpfc_hba *phba) { /* @@ -906,15 +917,17 @@ lpfc_sli_read_hs(struct lpfc_hba *phba) */ phba->sli.slistat.err_attn_event++; - /* Save status info */ - phba->work_hs = readl(phba->HSregaddr); - phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); - phba->work_status[1] = readl(phba->MBslimaddr + 0xac); + /* Save status info and check for unplug error */ + if (lpfc_readl(phba->HSregaddr, &phba->work_hs) || + lpfc_readl(phba->MBslimaddr + 0xa8, &phba->work_status[0]) || + lpfc_readl(phba->MBslimaddr + 0xac, &phba->work_status[1])) { + return -EIO; + } /* Clear chip Host Attention error bit */ writel(HA_ERATT, phba->HAregaddr); readl(phba->HAregaddr); /* flush */ phba->pport->stopped = 1; - return; + return 0; } diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 427c046e8209..4e0faa00b96f 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1224,7 +1224,10 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, if (val & ENABLE_FCP_RING_POLLING) { if ((val & DISABLE_FCP_RING_INT) && !(old_val & DISABLE_FCP_RING_INT)) { - creg_val = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &creg_val)) { + spin_unlock_irq(&phba->hbalock); + return -EINVAL; + } creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); writel(creg_val, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -1242,7 +1245,10 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, spin_unlock_irq(&phba->hbalock); del_timer(&phba->fcp_poll_timer); spin_lock_irq(&phba->hbalock); - creg_val = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &creg_val)) { + spin_unlock_irq(&phba->hbalock); + return -EINVAL; + } creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); writel(creg_val, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 5a4a2f36ae6d..d9b91b3f942f 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -348,7 +348,10 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) dd_data->context_un.iocb.bmp = bmp; if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - creg_val = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &creg_val)) { + rc = -EIO ; + goto free_cmdiocbq; + } creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); writel(creg_val, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -599,7 +602,10 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) dd_data->context_un.iocb.ndlp = ndlp; if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - creg_val = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &creg_val)) { + rc = -EIO; + goto linkdown_err; + } creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); writel(creg_val, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -613,6 +619,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) else rc = -EIO; +linkdown_err: pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, job->request_payload.sg_cnt, DMA_TO_DEVICE); pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, @@ -1357,7 +1364,10 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, dd_data->context_un.iocb.ndlp = ndlp; if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - creg_val = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &creg_val)) { + rc = -IOCB_ERROR; + goto issue_ct_rsp_exit; + } creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); writel(creg_val, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8e28edf9801e..735028fedda5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -89,7 +89,8 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) return 0; /* Read the HBA Host Attention Register */ - ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + return 1; if (!(ha_copy & HA_LATT)) return 0; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 057ab82bf399..c3a0e62de491 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1344,7 +1344,7 @@ typedef struct { /* FireFly BIU registers */ #define HS_FFER1 0x80000000 /* Bit 31 */ #define HS_CRIT_TEMP 0x00000100 /* Bit 8 */ #define HS_FFERM 0xFF000100 /* Mask for error bits 31:24 and 8 */ - +#define UNPLUG_ERR 0x00000001 /* Indicate pci hot unplug */ /* Host Control Register */ #define HC_REG_OFFSET 12 /* Byte offset from register base address */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 29aab9432af9..d5d07a890b67 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -507,7 +507,10 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->hba_flag &= ~HBA_ERATT_HANDLED; /* Enable appropriate host interrupts */ - status = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &status)) { + spin_unlock_irq(&phba->hbalock); + return -EIO; + } status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA; if (psli->num_rings > 0) status |= HC_R0INT_ENA; @@ -1222,7 +1225,10 @@ lpfc_handle_deferred_eratt(struct lpfc_hba *phba) /* Wait for the ER1 bit to clear.*/ while (phba->work_hs & HS_FFER1) { msleep(100); - phba->work_hs = readl(phba->HSregaddr); + if (lpfc_readl(phba->HSregaddr, &phba->work_hs)) { + phba->work_hs = UNPLUG_ERR ; + break; + } /* If driver is unloading let the worker thread continue */ if (phba->pport->load_flag & FC_UNLOADING) { phba->work_hs = 0; @@ -5386,13 +5392,16 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) int i, port_error = 0; uint32_t if_type; + memset(&portsmphr_reg, 0, sizeof(portsmphr_reg)); + memset(®_data, 0, sizeof(reg_data)); if (!phba->sli4_hba.PSMPHRregaddr) return -ENODEV; /* Wait up to 30 seconds for the SLI Port POST done and ready */ for (i = 0; i < 3000; i++) { - portsmphr_reg.word0 = readl(phba->sli4_hba.PSMPHRregaddr); - if (bf_get(lpfc_port_smphr_perr, &portsmphr_reg)) { + if (lpfc_readl(phba->sli4_hba.PSMPHRregaddr, + &portsmphr_reg.word0) || + (bf_get(lpfc_port_smphr_perr, &portsmphr_reg))) { /* Port has a fatal POST error, break out */ port_error = -ENODEV; break; @@ -5473,9 +5482,9 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) break; case LPFC_SLI_INTF_IF_TYPE_2: /* Final checks. The port status should be clean. */ - reg_data.word0 = - readl(phba->sli4_hba.u.if_type2.STATUSregaddr); - if (bf_get(lpfc_sliport_status_err, ®_data)) { + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + ®_data.word0) || + bf_get(lpfc_sliport_status_err, ®_data)) { phba->work_status[0] = readl(phba->sli4_hba.u.if_type2. ERR1regaddr); @@ -6761,9 +6770,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) * the loop again. */ for (rdy_chk = 0; rdy_chk < 1000; rdy_chk++) { - reg_data.word0 = - readl(phba->sli4_hba.u.if_type2. - STATUSregaddr); + if (lpfc_readl(phba->sli4_hba.u.if_type2. + STATUSregaddr, ®_data.word0)) { + rc = -ENODEV; + break; + } if (bf_get(lpfc_sliport_status_rdy, ®_data)) break; if (bf_get(lpfc_sliport_status_rn, ®_data)) { @@ -6784,8 +6795,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) } /* Detect any port errors. */ - reg_data.word0 = readl(phba->sli4_hba.u.if_type2. - STATUSregaddr); + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + ®_data.word0)) { + rc = -ENODEV; + break; + } if ((bf_get(lpfc_sliport_status_err, ®_data)) || (rdy_chk >= 1000)) { phba->work_status[0] = readl( diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 84234a4c54ce..3218c184be6f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -3477,7 +3477,8 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) int retval = 0; /* Read the HBA Host Status Register */ - status = readl(phba->HSregaddr); + if (lpfc_readl(phba->HSregaddr, &status)) + return 1; /* * Check status register every 100ms for 5 retries, then every @@ -3502,7 +3503,10 @@ lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) lpfc_sli_brdrestart(phba); } /* Read the HBA Host Status Register */ - status = readl(phba->HSregaddr); + if (lpfc_readl(phba->HSregaddr, &status)) { + retval = 1; + break; + } } /* Check to see if any errors occurred during init */ @@ -3584,7 +3588,7 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) uint32_t __iomem *resp_buf; uint32_t __iomem *mbox_buf; volatile uint32_t mbox; - uint32_t hc_copy; + uint32_t hc_copy, ha_copy, resp_data; int i; uint8_t hdrtype; @@ -3601,12 +3605,15 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) resp_buf = phba->MBslimaddr; /* Disable the error attention */ - hc_copy = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &hc_copy)) + return; writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr); readl(phba->HCregaddr); /* flush */ phba->link_flag |= LS_IGNORE_ERATT; - if (readl(phba->HAregaddr) & HA_ERATT) { + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + return; + if (ha_copy & HA_ERATT) { /* Clear Chip error bit */ writel(HA_ERATT, phba->HAregaddr); phba->pport->stopped = 1; @@ -3620,11 +3627,18 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) mbox_buf = phba->MBslimaddr; writel(mbox, mbox_buf); - for (i = 0; - readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN) && i < 50; i++) - mdelay(1); - - if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) { + for (i = 0; i < 50; i++) { + if (lpfc_readl((resp_buf + 1), &resp_data)) + return; + if (resp_data != ~(BARRIER_TEST_PATTERN)) + mdelay(1); + else + break; + } + resp_data = 0; + if (lpfc_readl((resp_buf + 1), &resp_data)) + return; + if (resp_data != ~(BARRIER_TEST_PATTERN)) { if (phba->sli.sli_flag & LPFC_SLI_ACTIVE || phba->pport->stopped) goto restore_hc; @@ -3633,13 +3647,26 @@ void lpfc_reset_barrier(struct lpfc_hba *phba) } ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST; - for (i = 0; readl(resp_buf) != mbox && i < 500; i++) - mdelay(1); + resp_data = 0; + for (i = 0; i < 500; i++) { + if (lpfc_readl(resp_buf, &resp_data)) + return; + if (resp_data != mbox) + mdelay(1); + else + break; + } clear_errat: - while (!(readl(phba->HAregaddr) & HA_ERATT) && ++i < 500) - mdelay(1); + while (++i < 500) { + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + return; + if (!(ha_copy & HA_ERATT)) + mdelay(1); + else + break; + } if (readl(phba->HAregaddr) & HA_ERATT) { writel(HA_ERATT, phba->HAregaddr); @@ -3686,7 +3713,11 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) /* Disable the error attention */ spin_lock_irq(&phba->hbalock); - status = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &status)) { + spin_unlock_irq(&phba->hbalock); + mempool_free(pmb, phba->mbox_mem_pool); + return 1; + } status &= ~HC_ERINT_ENA; writel(status, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -3720,11 +3751,12 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) * 3 seconds we still set HBA_ERROR state because the status of the * board is now undefined. */ - ha_copy = readl(phba->HAregaddr); - + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + return 1; while ((i++ < 30) && !(ha_copy & HA_ERATT)) { mdelay(100); - ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + return 1; } del_timer_sync(&psli->mbox_tmo); @@ -4018,7 +4050,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) uint32_t status, i = 0; /* Read the HBA Host Status Register */ - status = readl(phba->HSregaddr); + if (lpfc_readl(phba->HSregaddr, &status)) + return -EIO; /* Check status register to see what current state is */ i = 0; @@ -4073,7 +4106,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) lpfc_sli_brdrestart(phba); } /* Read the HBA Host Status Register */ - status = readl(phba->HSregaddr); + if (lpfc_readl(phba->HSregaddr, &status)) + return -EIO; } /* Check to see if any errors occurred during init */ @@ -5136,7 +5170,7 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, MAILBOX_t *mb; struct lpfc_sli *psli = &phba->sli; uint32_t status, evtctr; - uint32_t ha_copy; + uint32_t ha_copy, hc_copy; int i; unsigned long timeout; unsigned long drvr_flag = 0; @@ -5202,15 +5236,17 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, goto out_not_finished; } - if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT && - !(readl(phba->HCregaddr) & HC_MBINT_ENA)) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT) { + if (lpfc_readl(phba->HCregaddr, &hc_copy) || + !(hc_copy & HC_MBINT_ENA)) { + spin_unlock_irqrestore(&phba->hbalock, drvr_flag); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "(%d):2528 Mailbox command x%x cannot " "issue Data: x%x x%x\n", pmbox->vport ? pmbox->vport->vpi : 0, pmbox->u.mb.mbxCommand, psli->sli_flag, flag); - goto out_not_finished; + goto out_not_finished; + } } if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { @@ -5408,11 +5444,19 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, word0 = le32_to_cpu(word0); } else { /* First read mbox status word */ - word0 = readl(phba->MBslimaddr); + if (lpfc_readl(phba->MBslimaddr, &word0)) { + spin_unlock_irqrestore(&phba->hbalock, + drvr_flag); + goto out_not_finished; + } } /* Read the HBA Host Attention Register */ - ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &ha_copy)) { + spin_unlock_irqrestore(&phba->hbalock, + drvr_flag); + goto out_not_finished; + } timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mb->mbxCommand) * 1000) + jiffies; @@ -5463,7 +5507,11 @@ lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, word0 = readl(phba->MBslimaddr); } /* Read the HBA Host Attention Register */ - ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &ha_copy)) { + spin_unlock_irqrestore(&phba->hbalock, + drvr_flag); + goto out_not_finished; + } } if (psli->sli_flag & LPFC_SLI_ACTIVE) { @@ -8194,7 +8242,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, piocb->iocb_flag &= ~LPFC_IO_WAKE; if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - creg_val = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &creg_val)) + return IOCB_ERROR; creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); writel(creg_val, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -8236,7 +8285,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, } if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - creg_val = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &creg_val)) + return IOCB_ERROR; creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); writel(creg_val, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -8387,10 +8437,13 @@ lpfc_sli_eratt_read(struct lpfc_hba *phba) uint32_t ha_copy; /* Read chip Host Attention (HA) register */ - ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + goto unplug_err; + if (ha_copy & HA_ERATT) { /* Read host status register to retrieve error event */ - lpfc_sli_read_hs(phba); + if (lpfc_sli_read_hs(phba)) + goto unplug_err; /* Check if there is a deferred error condition is active */ if ((HS_FFER1 & phba->work_hs) && @@ -8409,6 +8462,15 @@ lpfc_sli_eratt_read(struct lpfc_hba *phba) return 1; } return 0; + +unplug_err: + /* Set the driver HS work bitmap */ + phba->work_hs |= UNPLUG_ERR; + /* Set the driver HA work bitmap */ + phba->work_ha |= HA_ERATT; + /* Indicate polling handles this ERATT */ + phba->hba_flag |= HBA_ERATT_HANDLED; + return 1; } /** @@ -8436,8 +8498,15 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); switch (if_type) { case LPFC_SLI_INTF_IF_TYPE_0: - uerr_sta_lo = readl(phba->sli4_hba.u.if_type0.UERRLOregaddr); - uerr_sta_hi = readl(phba->sli4_hba.u.if_type0.UERRHIregaddr); + if (lpfc_readl(phba->sli4_hba.u.if_type0.UERRLOregaddr, + &uerr_sta_lo) || + lpfc_readl(phba->sli4_hba.u.if_type0.UERRHIregaddr, + &uerr_sta_hi)) { + phba->work_hs |= UNPLUG_ERR; + phba->work_ha |= HA_ERATT; + phba->hba_flag |= HBA_ERATT_HANDLED; + return 1; + } if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) || (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -8456,9 +8525,15 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) } break; case LPFC_SLI_INTF_IF_TYPE_2: - portstat_reg.word0 = - readl(phba->sli4_hba.u.if_type2.STATUSregaddr); - portsmphr = readl(phba->sli4_hba.PSMPHRregaddr); + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + &portstat_reg.word0) || + lpfc_readl(phba->sli4_hba.PSMPHRregaddr, + &portsmphr)){ + phba->work_hs |= UNPLUG_ERR; + phba->work_ha |= HA_ERATT; + phba->hba_flag |= HBA_ERATT_HANDLED; + return 1; + } if (bf_get(lpfc_sliport_status_err, &portstat_reg)) { phba->work_status[0] = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); @@ -8639,7 +8714,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) return IRQ_NONE; /* Need to read HA REG for slow-path events */ spin_lock_irqsave(&phba->hbalock, iflag); - ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + goto unplug_error; /* If somebody is waiting to handle an eratt don't process it * here. The brdkill function will do this. */ @@ -8665,7 +8741,9 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) } /* Clear up only attention source related to slow-path */ - hc_copy = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &hc_copy)) + goto unplug_error; + writel(hc_copy & ~(HC_MBINT_ENA | HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA), phba->HCregaddr); @@ -8688,7 +8766,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) */ spin_lock_irqsave(&phba->hbalock, iflag); phba->sli.sli_flag &= ~LPFC_PROCESS_LA; - control = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &control)) + goto unplug_error; control &= ~HC_LAINT_ENA; writel(control, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ @@ -8708,7 +8787,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) status >>= (4*LPFC_ELS_RING); if (status & HA_RXMASK) { spin_lock_irqsave(&phba->hbalock, iflag); - control = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &control)) + goto unplug_error; lpfc_debugfs_slow_ring_trc(phba, "ISR slow ring: ctl:x%x stat:x%x isrcnt:x%x", @@ -8741,7 +8821,8 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) } spin_lock_irqsave(&phba->hbalock, iflag); if (work_ha_copy & HA_ERATT) { - lpfc_sli_read_hs(phba); + if (lpfc_sli_read_hs(phba)) + goto unplug_error; /* * Check if there is a deferred error condition * is active @@ -8872,6 +8953,9 @@ send_current_mbox: lpfc_worker_wake_up(phba); } return IRQ_HANDLED; +unplug_error: + spin_unlock_irqrestore(&phba->hbalock, iflag); + return IRQ_HANDLED; } /* lpfc_sli_sp_intr_handler */ @@ -8919,7 +9003,8 @@ lpfc_sli_fp_intr_handler(int irq, void *dev_id) if (lpfc_intr_state_check(phba)) return IRQ_NONE; /* Need to read HA REG for FCP ring and other ring events */ - ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &ha_copy)) + return IRQ_HANDLED; /* Clear up only attention source related to fast-path */ spin_lock_irqsave(&phba->hbalock, iflag); /* @@ -9004,7 +9089,11 @@ lpfc_sli_intr_handler(int irq, void *dev_id) return IRQ_NONE; spin_lock(&phba->hbalock); - phba->ha_copy = readl(phba->HAregaddr); + if (lpfc_readl(phba->HAregaddr, &phba->ha_copy)) { + spin_unlock(&phba->hbalock); + return IRQ_HANDLED; + } + if (unlikely(!phba->ha_copy)) { spin_unlock(&phba->hbalock); return IRQ_NONE; @@ -9026,7 +9115,10 @@ lpfc_sli_intr_handler(int irq, void *dev_id) } /* Clear attention sources except link and error attentions */ - hc_copy = readl(phba->HCregaddr); + if (lpfc_readl(phba->HCregaddr, &hc_copy)) { + spin_unlock(&phba->hbalock); + return IRQ_HANDLED; + } writel(hc_copy & ~(HC_MBINT_ENA | HC_R0INT_ENA | HC_R1INT_ENA | HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA), phba->HCregaddr); -- cgit v1.2.2 From 546fc854d0faa76358d1deffd2c4f6b8598bf5f2 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 11 Mar 2011 16:06:29 -0500 Subject: [SCSI] lpfc 8.3.22: FC Discovery fixes FC Discovery fixes - In lpfc_sli4_bpl2sgl byte swapping the SGL in word2. - In lpfc_sli4_iocb2wqe byteswap the data for CMD_GEN_REQUEST64_CR type WQE. - In lpfc_sli4_seq_abort_acc do not set the oxid into the iocb's xritag field. - In lpfc_sli4_seq_abort_acc check the return value of lpfc_sli_issue_iocb. - Inprove messages in this area. Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hw.h | 2 +- drivers/scsi/lpfc/lpfc_hw4.h | 12 +++++- drivers/scsi/lpfc/lpfc_sli.c | 99 ++++++++++++++++++++++++++++++-------------- 3 files changed, 81 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index c3a0e62de491..95f11ed79463 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -3632,7 +3632,7 @@ typedef struct _IOCB { /* IOCB structure */ ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */ - struct sli4_bls_acc bls_acc; /* UNSOL ABTS BLS_ACC params */ + struct sli4_bls_rsp bls_rsp; /* UNSOL ABTS BLS_RSP params */ uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ } un; union { diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index b42b6994fd94..8433ac0d9fb4 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -215,7 +215,7 @@ struct lpfc_sli4_flags { #define lpfc_fip_flag_WORD word0 }; -struct sli4_bls_acc { +struct sli4_bls_rsp { uint32_t word0_rsvd; /* Word0 must be reserved */ uint32_t word1; #define lpfc_abts_orig_SHIFT 0 @@ -231,6 +231,16 @@ struct sli4_bls_acc { #define lpfc_abts_oxid_MASK 0x0000FFFF #define lpfc_abts_oxid_WORD word2 uint32_t word3; +#define lpfc_vndr_code_SHIFT 0 +#define lpfc_vndr_code_MASK 0x000000FF +#define lpfc_vndr_code_WORD word3 +#define lpfc_rsn_expln_SHIFT 8 +#define lpfc_rsn_expln_MASK 0x000000FF +#define lpfc_rsn_expln_WORD word3 +#define lpfc_rsn_code_SHIFT 16 +#define lpfc_rsn_code_MASK 0x000000FF +#define lpfc_rsn_code_WORD word3 + uint32_t word4; uint32_t word5_rsvd; /* Word5 must be reserved */ }; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 3218c184be6f..cca5f2d78a54 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -6311,7 +6311,6 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, bf_set(lpfc_sli4_sge_last, sgl, 1); else bf_set(lpfc_sli4_sge_last, sgl, 0); - sgl->word2 = cpu_to_le32(sgl->word2); /* swap the size field back to the cpu so we * can assign it to the sgl. */ @@ -6331,6 +6330,7 @@ lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, bf_set(lpfc_sli4_sge_offset, sgl, offset); offset += bde.tus.f.bdeSize; } + sgl->word2 = cpu_to_le32(sgl->word2); bpl++; sgl++; } @@ -6576,9 +6576,9 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / sizeof(struct ulp_bde64); for (i = 0; i < numBdes; i++) { - if (bpl[i].tus.f.bdeFlags != BUFF_TYPE_BDE_64) - break; bde.tus.w = le32_to_cpu(bpl[i].tus.w); + if (bde.tus.f.bdeFlags != BUFF_TYPE_BDE_64) + break; xmit_len += bde.tus.f.bdeSize; } /* word3 iocb=IO_TAG wqe=request_payload_len */ @@ -6668,15 +6668,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, xritag = 0; break; case CMD_XMIT_BLS_RSP64_CX: - /* As BLS ABTS-ACC WQE is very different from other WQEs, + /* As BLS ABTS RSP WQE is very different from other WQEs, * we re-construct this WQE here based on information in * iocbq from scratch. */ memset(wqe, 0, sizeof(union lpfc_wqe)); /* OX_ID is invariable to who sent ABTS to CT exchange */ bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp, - bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_acc)); - if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_acc) == + bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_rsp)); + if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_rsp) == LPFC_ABTS_UNSOL_INT) { /* ABTS sent by initiator to CT exchange, the * RX_ID field will be filled with the newly @@ -6690,7 +6690,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, * RX_ID from ABTS. */ bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, - bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_acc)); + bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_rsp)); } bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); @@ -6701,6 +6701,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, LPFC_WQE_LENLOC_NONE); /* Overwrite the pre-set comnd type with OTHER_COMMAND */ command_type = OTHER_COMMAND; + if (iocbq->iocb.un.xseq64.w5.hcsw.Rctl == FC_RCTL_BA_RJT) { + bf_set(xmit_bls_rsp64_rjt_vspec, &wqe->xmit_bls_rsp, + bf_get(lpfc_vndr_code, &iocbq->iocb.un.bls_rsp)); + bf_set(xmit_bls_rsp64_rjt_expc, &wqe->xmit_bls_rsp, + bf_get(lpfc_rsn_expln, &iocbq->iocb.un.bls_rsp)); + bf_set(xmit_bls_rsp64_rjt_rsnc, &wqe->xmit_bls_rsp, + bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp)); + } + break; case CMD_XRI_ABORTED_CX: case CMD_CREATE_XRI_CR: /* Do we expect to use this? */ @@ -6749,7 +6758,8 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, if (piocb->sli4_xritag == NO_XRI) { if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) + piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN || + piocb->iocb.ulpCommand == CMD_XMIT_BLS_RSP64_CX) sglq = NULL; else { if (pring->txq_cnt) { @@ -11740,6 +11750,7 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) static char *rctl_names[] = FC_RCTL_NAMES_INIT; char *type_names[] = FC_TYPE_NAMES_INIT; struct fc_vft_header *fc_vft_hdr; + uint32_t *header = (uint32_t *) fc_hdr; switch (fc_hdr->fh_r_ctl) { case FC_RCTL_DD_UNCAT: /* uncategorized information */ @@ -11788,10 +11799,15 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) default: goto drop; } + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "2538 Received frame rctl:%s type:%s\n", + "2538 Received frame rctl:%s type:%s " + "Frame Data:%08x %08x %08x %08x %08x %08x\n", rctl_names[fc_hdr->fh_r_ctl], - type_names[fc_hdr->fh_type]); + type_names[fc_hdr->fh_type], + be32_to_cpu(header[0]), be32_to_cpu(header[1]), + be32_to_cpu(header[2]), be32_to_cpu(header[3]), + be32_to_cpu(header[4]), be32_to_cpu(header[5])); return 0; drop: lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, @@ -12088,17 +12104,17 @@ lpfc_sli4_abort_partial_seq(struct lpfc_vport *vport, } /** - * lpfc_sli4_seq_abort_acc_cmpl - Accept seq abort iocb complete handler + * lpfc_sli4_seq_abort_rsp_cmpl - BLS ABORT RSP seq abort iocb complete handler * @phba: Pointer to HBA context object. * @cmd_iocbq: pointer to the command iocbq structure. * @rsp_iocbq: pointer to the response iocbq structure. * - * This function handles the sequence abort accept iocb command complete + * This function handles the sequence abort response iocb command complete * event. It properly releases the memory allocated to the sequence abort * accept iocb. **/ static void -lpfc_sli4_seq_abort_acc_cmpl(struct lpfc_hba *phba, +lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmd_iocbq, struct lpfc_iocbq *rsp_iocbq) { @@ -12107,15 +12123,15 @@ lpfc_sli4_seq_abort_acc_cmpl(struct lpfc_hba *phba, } /** - * lpfc_sli4_seq_abort_acc - Accept sequence abort + * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort * @phba: Pointer to HBA context object. * @fc_hdr: pointer to a FC frame header. * - * This function sends a basic accept to a previous unsol sequence abort + * This function sends a basic response to a previous unsol sequence abort * event after aborting the sequence handling. **/ static void -lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, +lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) { struct lpfc_iocbq *ctiocb = NULL; @@ -12123,6 +12139,7 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, uint16_t oxid, rxid; uint32_t sid, fctl; IOCB_t *icmd; + int rc; if (!lpfc_is_link_up(phba)) return; @@ -12143,7 +12160,7 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, + phba->sli4_hba.max_cfg_param.xri_base)) lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); - /* Allocate buffer for acc iocb */ + /* Allocate buffer for rsp iocb */ ctiocb = lpfc_sli_get_iocbq(phba); if (!ctiocb) return; @@ -12168,32 +12185,54 @@ lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, ctiocb->iocb_cmpl = NULL; ctiocb->vport = phba->pport; - ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_acc_cmpl; + ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; + ctiocb->sli4_xritag = NO_XRI; + + /* If the oxid maps to the FCP XRI range or if it is out of range, + * send a BLS_RJT. The driver no longer has that exchange. + * Override the IOCB for a BA_RJT. + */ + if (oxid > (phba->sli4_hba.max_cfg_param.max_xri + + phba->sli4_hba.max_cfg_param.xri_base) || + oxid > (lpfc_sli4_get_els_iocb_cnt(phba) + + phba->sli4_hba.max_cfg_param.xri_base)) { + icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; + bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); + bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID); + bf_set(lpfc_rsn_code, &icmd->un.bls_rsp, FC_BA_RJT_UNABLE); + } if (fctl & FC_FC_EX_CTX) { /* ABTS sent by responder to CT exchange, construction * of BA_ACC will use OX_ID from ABTS for the XRI_TAG * field and RX_ID from ABTS for RX_ID field. */ - bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_RSP); - bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, rxid); - ctiocb->sli4_xritag = oxid; + bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_RSP); + bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); } else { /* ABTS sent by initiator to CT exchange, construction * of BA_ACC will need to allocate a new XRI as for the * XRI_TAG and RX_ID fields. */ - bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_INT); - bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, NO_XRI); - ctiocb->sli4_xritag = NO_XRI; + bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_INT); + bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, NO_XRI); } - bf_set(lpfc_abts_oxid, &icmd->un.bls_acc, oxid); + bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid); - /* Xmit CT abts accept on exchange */ + /* Xmit CT abts response on exchange */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "1200 Xmit CT ABTS ACC on exchange x%x Data: x%x\n", - CMD_XMIT_BLS_RSP64_CX, phba->link_state); - lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); + "1200 Send BLS cmd x%x on oxid x%x Data: x%x\n", + icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state); + + rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); + if (rc == IOCB_ERROR) { + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "2925 Failed to issue CT ABTS RSP x%x on " + "xri x%x, Data x%x\n", + icmd->un.xseq64.w5.hcsw.Rctl, oxid, + phba->link_state); + lpfc_sli_release_iocbq(phba, ctiocb); + } } /** @@ -12241,7 +12280,7 @@ lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport, lpfc_in_buf_free(phba, &dmabuf->dbuf); } /* Send basic accept (BA_ACC) to the abort requester */ - lpfc_sli4_seq_abort_acc(phba, &fc_hdr); + lpfc_sli4_seq_abort_rsp(phba, &fc_hdr); } /** -- cgit v1.2.2 From 792581de597c78ee353b6e2a06490f0ef576032e Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 11 Mar 2011 16:06:44 -0500 Subject: [SCSI] lpfc 8.3.22: Update Copyright Dates Update Copyright Dates Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/Makefile | 2 +- drivers/scsi/lpfc/lpfc_bsg.c | 2 +- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_init.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 2 +- drivers/scsi/lpfc/lpfc_sli4.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile index 14de249917f8..88928f00aa2d 100644 --- a/drivers/scsi/lpfc/Makefile +++ b/drivers/scsi/lpfc/Makefile @@ -1,7 +1,7 @@ #/******************************************************************* # * This file is part of the Emulex Linux Device Driver for * # * Fibre Channel Host Bus Adapters. * -# * Copyright (C) 2004-2006 Emulex. All rights reserved. * +# * Copyright (C) 2004-2011 Emulex. All rights reserved. * # * EMULEX and SLI are trademarks of Emulex. * # * www.emulex.com * # * * diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index d9b91b3f942f..793b9f1131fb 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2010 Emulex. All rights reserved. * + * Copyright (C) 2009-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 60281d875184..f0b332f4eedb 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2010 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index d5d07a890b67..e6ebe516cfbb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2010 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index e3a1d295e4dc..2b962b020cfb 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index cca5f2d78a54..4746dcd756dd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * + * Copyright (C) 2004-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 595056b89608..1a3cbf88f2ce 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009 Emulex. All rights reserved. * + * Copyright (C) 2009-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * -- cgit v1.2.2 From 4b3203052494ea7b0a445ace676cd2013917c807 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 11 Mar 2011 16:06:58 -0500 Subject: [SCSI] lpfc 8.3.22: Update driver version to 8.3.22 Update driver version to 8.3.22 Signed-off-by: Alex Iannicelli Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 0a4d376dbca5..2404d1d65563 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.21" +#define LPFC_DRIVER_VERSION "8.3.22" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" -- cgit v1.2.2 From 8fc1858a42663248d5b362edc313786e0be7a639 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 14 Mar 2011 04:05:55 -0700 Subject: [SCSI] target: Fix memory leak on error path in pscsi_alloc_task If allocation of pt->pscsi_cdb fails, we need to free the just-allocated pt or else it will be leaked. Signed-off-by: Roland Dreier Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_pscsi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 5a9d2ba4b609..3031ef8261ef 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -816,6 +816,7 @@ pscsi_alloc_task(struct se_cmd *cmd) if (!(pt->pscsi_cdb)) { printk(KERN_ERR "pSCSI: Unable to allocate extended" " pt->pscsi_cdb\n"); + kfree(pt); return NULL; } } else -- cgit v1.2.2 From 6d1802539d218e24492c651bd0687ebfe7e14831 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 14 Mar 2011 04:05:56 -0700 Subject: [SCSI] target: Fix match_strdup() memory leaks match_strdup() dynamically allocates memory and it is the responsabillity of the caller to free that memory. The following three cases: drivers/target/target_core_file.c:fd_set_configfs_dev_params() drivers/target/target_core_iblock.c:iblock_set_configfs_dev_params() drivers/target/target_core_configfs.c:target_core_dev_pr_store_attr_res_aptpl_metadata() should be kfree()'ing the allocated memory once it is no longer needed. It also makes sure to return -ENOMEM if the memory allocation in match_strdup() should fail. For target_core_configfs.c, this patch adds kfree()'s around Opt_initiator_fabric, Opt_initiator_node, Opt_initiator_sid, Opt_sa_res_key, Opt_target_fabric, and Opt_target_node for the Persistent Reservations Activate Persistence across Target Power Loss (APTPL=1) token parsing. Signed-off-by: Jesper Juhl Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_configfs.c | 33 +++++++++++++++++++++++++++++++-- drivers/target/target_core_file.c | 13 ++++++++++++- drivers/target/target_core_iblock.c | 13 +++++++++---- 3 files changed, 52 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index caf8dc18ee0a..c9254d7ad18a 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1451,8 +1451,8 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( size_t count) { struct se_device *dev; - unsigned char *i_fabric, *t_fabric, *i_port = NULL, *t_port = NULL; - unsigned char *isid = NULL; + unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL; + unsigned char *t_fabric = NULL, *t_port = NULL; char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; unsigned long long tmp_ll; @@ -1488,9 +1488,17 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( switch (token) { case Opt_initiator_fabric: i_fabric = match_strdup(&args[0]); + if (!i_fabric) { + ret = -ENOMEM; + goto out; + } break; case Opt_initiator_node: i_port = match_strdup(&args[0]); + if (!i_port) { + ret = -ENOMEM; + goto out; + } if (strlen(i_port) > PR_APTPL_MAX_IPORT_LEN) { printk(KERN_ERR "APTPL metadata initiator_node=" " exceeds PR_APTPL_MAX_IPORT_LEN: %d\n", @@ -1501,6 +1509,10 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_initiator_sid: isid = match_strdup(&args[0]); + if (!isid) { + ret = -ENOMEM; + goto out; + } if (strlen(isid) > PR_REG_ISID_LEN) { printk(KERN_ERR "APTPL metadata initiator_isid" "= exceeds PR_REG_ISID_LEN: %d\n", @@ -1511,6 +1523,10 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( break; case Opt_sa_res_key: arg_p = match_strdup(&args[0]); + if (!arg_p) { + ret = -ENOMEM; + goto out; + } ret = strict_strtoull(arg_p, 0, &tmp_ll); if (ret < 0) { printk(KERN_ERR "strict_strtoull() failed for" @@ -1547,9 +1563,17 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( */ case Opt_target_fabric: t_fabric = match_strdup(&args[0]); + if (!t_fabric) { + ret = -ENOMEM; + goto out; + } break; case Opt_target_node: t_port = match_strdup(&args[0]); + if (!t_port) { + ret = -ENOMEM; + goto out; + } if (strlen(t_port) > PR_APTPL_MAX_TPORT_LEN) { printk(KERN_ERR "APTPL metadata target_node=" " exceeds PR_APTPL_MAX_TPORT_LEN: %d\n", @@ -1592,6 +1616,11 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( i_port, isid, mapped_lun, t_port, tpgt, target_lun, res_holder, all_tg_pt, type); out: + kfree(i_fabric); + kfree(i_port); + kfree(isid); + kfree(t_fabric); + kfree(t_port); kfree(orig); return (ret == 0) ? count : ret; } diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 190ca8ac2498..7850c6ae06e4 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -536,15 +536,26 @@ static ssize_t fd_set_configfs_dev_params( token = match_token(ptr, tokens, args); switch (token) { case Opt_fd_dev_name: + arg_p = match_strdup(&args[0]); + if (!arg_p) { + ret = -ENOMEM; + break; + } snprintf(fd_dev->fd_dev_name, FD_MAX_DEV_NAME, - "%s", match_strdup(&args[0])); + "%s", arg_p); + kfree(arg_p); printk(KERN_INFO "FILEIO: Referencing Path: %s\n", fd_dev->fd_dev_name); fd_dev->fbd_flags |= FBDF_HAS_PATH; break; case Opt_fd_dev_size: arg_p = match_strdup(&args[0]); + if (!arg_p) { + ret = -ENOMEM; + break; + } ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size); + kfree(arg_p); if (ret < 0) { printk(KERN_ERR "strict_strtoull() failed for" " fd_dev_size=\n"); diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 3df570db0e4f..96d98cc8f85b 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -468,7 +468,7 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, const char *page, ssize_t count) { struct iblock_dev *ib_dev = se_dev->se_dev_su_ptr; - char *orig, *ptr, *opts; + char *orig, *ptr, *arg_p, *opts; substring_t args[MAX_OPT_ARGS]; int ret = 0, arg, token; @@ -491,9 +491,14 @@ static ssize_t iblock_set_configfs_dev_params(struct se_hba *hba, ret = -EEXIST; goto out; } - - ret = snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN, - "%s", match_strdup(&args[0])); + arg_p = match_strdup(&args[0]); + if (!arg_p) { + ret = -ENOMEM; + break; + } + snprintf(ib_dev->ibd_udev_path, SE_UDEV_PATH_LEN, + "%s", arg_p); + kfree(arg_p); printk(KERN_INFO "IBLOCK: Referencing UDEV path: %s\n", ib_dev->ibd_udev_path); ib_dev->ibd_flags |= IBDF_HAS_UDEV_PATH; -- cgit v1.2.2 From 5e8de4f3199446f5eeb371312da20534ebfe9979 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 14 Mar 2011 04:05:58 -0700 Subject: [SCSI] target: remove EXTRA_CFLAGS Add the current directory is superflous in general, and no includes in drivers/scsi are needed either. Signed-off-by: Christoph Hellwig Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 973bb190ef57..050ee6569b2b 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -1,4 +1,3 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/target/ -I$(srctree)/drivers/scsi/ target_core_mod-y := target_core_configfs.o \ target_core_device.o \ -- cgit v1.2.2 From 613640e4e1b5358ce880d16f10ecc2550b32b250 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:05:59 -0700 Subject: [SCSI] target: Convert backend ->create_virtdevice() call to return ERR_PTR This patch converts the target_core_store_dev_enable() -> struct se_subsystem_api->create_virtdevice() call to return proper ERR_PTR values back up to configfs logic during backend dependent struct se_device ENABLE exception conditions. Along with the change to target_core_configfs.c, this includes converting IBLOCK, FILEIO, pSCSI, and RAMDISK_* backend subsystem plugins to obtain upper level PTR_ERR return codes (where available), and return via ERR_PTR during a *_create_virtdev() failure. Reported-by: Fubo Chen Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_configfs.c | 4 +++- drivers/target/target_core_file.c | 13 +++++++++---- drivers/target/target_core_iblock.c | 15 ++++++++------- drivers/target/target_core_pscsi.c | 18 +++++++++--------- drivers/target/target_core_rd.c | 8 +++++--- 5 files changed, 34 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index c9254d7ad18a..9721ef28335c 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1827,7 +1827,9 @@ static ssize_t target_core_store_dev_enable( return -EINVAL; dev = t->create_virtdevice(hba, se_dev, se_dev->se_dev_su_ptr); - if (!(dev) || IS_ERR(dev)) + if (IS_ERR(dev)) + return PTR_ERR(dev); + else if (!dev) return -EINVAL; se_dev->se_dev_ptr = dev; diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 7850c6ae06e4..03fa40f72ef7 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -134,7 +134,7 @@ static struct se_device *fd_create_virtdevice( mm_segment_t old_fs; struct file *file; struct inode *inode = NULL; - int dev_flags = 0, flags; + int dev_flags = 0, flags, ret = -EINVAL; memset(&dev_limits, 0, sizeof(struct se_dev_limits)); @@ -146,6 +146,7 @@ static struct se_device *fd_create_virtdevice( if (IS_ERR(dev_p)) { printk(KERN_ERR "getname(%s) failed: %lu\n", fd_dev->fd_dev_name, IS_ERR(dev_p)); + ret = PTR_ERR(dev_p); goto fail; } #if 0 @@ -165,8 +166,12 @@ static struct se_device *fd_create_virtdevice( flags |= O_SYNC; file = filp_open(dev_p, flags, 0600); - - if (IS_ERR(file) || !file || !file->f_dentry) { + if (IS_ERR(file)) { + printk(KERN_ERR "filp_open(%s) failed\n", dev_p); + ret = PTR_ERR(file); + goto fail; + } + if (!file || !file->f_dentry) { printk(KERN_ERR "filp_open(%s) failed\n", dev_p); goto fail; } @@ -241,7 +246,7 @@ fail: fd_dev->fd_file = NULL; } putname(dev_p); - return NULL; + return ERR_PTR(ret); } /* fd_free_device(): (Part of se_subsystem_api_t template) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 96d98cc8f85b..0f4a50935a86 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -129,10 +129,11 @@ static struct se_device *iblock_create_virtdevice( struct request_queue *q; struct queue_limits *limits; u32 dev_flags = 0; + int ret = -EINVAL; if (!(ib_dev)) { printk(KERN_ERR "Unable to locate struct iblock_dev parameter\n"); - return 0; + return ERR_PTR(ret); } memset(&dev_limits, 0, sizeof(struct se_dev_limits)); /* @@ -141,7 +142,7 @@ static struct se_device *iblock_create_virtdevice( ib_dev->ibd_bio_set = bioset_create(32, 64); if (!(ib_dev->ibd_bio_set)) { printk(KERN_ERR "IBLOCK: Unable to create bioset()\n"); - return 0; + return ERR_PTR(-ENOMEM); } printk(KERN_INFO "IBLOCK: Created bio_set()\n"); /* @@ -153,8 +154,10 @@ static struct se_device *iblock_create_virtdevice( bd = blkdev_get_by_path(ib_dev->ibd_udev_path, FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); - if (IS_ERR(bd)) + if (IS_ERR(bd)) { + ret = PTR_ERR(bd); goto failed; + } /* * Setup the local scope queue_limits from struct request_queue->limits * to pass into transport_add_device_to_core_hba() as struct se_dev_limits. @@ -184,9 +187,7 @@ static struct se_device *iblock_create_virtdevice( * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM * in ATA and we need to set TPE=1 */ - if (blk_queue_discard(bdev_get_queue(bd))) { - struct request_queue *q = bdev_get_queue(bd); - + if (blk_queue_discard(q)) { DEV_ATTRIB(dev)->max_unmap_lba_count = q->limits.max_discard_sectors; /* @@ -212,7 +213,7 @@ failed: ib_dev->ibd_bd = NULL; ib_dev->ibd_major = 0; ib_dev->ibd_minor = 0; - return NULL; + return ERR_PTR(ret); } static void iblock_free_device(void *p) diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 3031ef8261ef..51fd309388fc 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -555,7 +555,7 @@ static struct se_device *pscsi_create_virtdevice( if (!(pdv)) { printk(KERN_ERR "Unable to locate struct pscsi_dev_virt" " parameter\n"); - return NULL; + return ERR_PTR(-EINVAL); } /* * If not running in PHV_LLD_SCSI_HOST_NO mode, locate the @@ -565,7 +565,7 @@ static struct se_device *pscsi_create_virtdevice( if (phv->phv_mode == PHV_LLD_SCSI_HOST_NO) { printk(KERN_ERR "pSCSI: Unable to locate struct" " Scsi_Host for PHV_LLD_SCSI_HOST_NO\n"); - return NULL; + return ERR_PTR(-ENODEV); } /* * For the newer PHV_VIRUTAL_HOST_ID struct scsi_device @@ -574,7 +574,7 @@ static struct se_device *pscsi_create_virtdevice( if (!(se_dev->su_dev_flags & SDF_USING_UDEV_PATH)) { printk(KERN_ERR "pSCSI: udev_path attribute has not" " been set before ENABLE=1\n"); - return NULL; + return ERR_PTR(-EINVAL); } /* * If no scsi_host_id= was passed for PHV_VIRUTAL_HOST_ID, @@ -587,12 +587,12 @@ static struct se_device *pscsi_create_virtdevice( printk(KERN_ERR "pSCSI: Unable to set hba_mode" " with active devices\n"); spin_unlock(&hba->device_lock); - return NULL; + return ERR_PTR(-EEXIST); } spin_unlock(&hba->device_lock); if (pscsi_pmode_enable_hba(hba, 1) != 1) - return NULL; + return ERR_PTR(-ENODEV); legacy_mode_enable = 1; hba->hba_flags |= HBA_FLAGS_PSCSI_MODE; @@ -602,14 +602,14 @@ static struct se_device *pscsi_create_virtdevice( if (!(sh)) { printk(KERN_ERR "pSCSI: Unable to locate" " pdv_host_id: %d\n", pdv->pdv_host_id); - return NULL; + return ERR_PTR(-ENODEV); } } } else { if (phv->phv_mode == PHV_VIRUTAL_HOST_ID) { printk(KERN_ERR "pSCSI: PHV_VIRUTAL_HOST_ID set while" " struct Scsi_Host exists\n"); - return NULL; + return ERR_PTR(-EEXIST); } } @@ -644,7 +644,7 @@ static struct se_device *pscsi_create_virtdevice( hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; } pdv->pdv_sd = NULL; - return NULL; + return ERR_PTR(-ENODEV); } return dev; } @@ -660,7 +660,7 @@ static struct se_device *pscsi_create_virtdevice( hba->hba_flags &= ~HBA_FLAGS_PSCSI_MODE; } - return NULL; + return ERR_PTR(-ENODEV); } /* pscsi_free_device(): (Part of se_subsystem_api_t template) diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 8dc6d74c1d40..f36094f0596a 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -253,13 +253,15 @@ static struct se_device *rd_create_virtdevice( struct se_dev_limits dev_limits; struct rd_dev *rd_dev = p; struct rd_host *rd_host = hba->hba_ptr; - int dev_flags = 0; + int dev_flags = 0, ret = -EINVAL; char prod[16], rev[4]; memset(&dev_limits, 0, sizeof(struct se_dev_limits)); - if (rd_build_device_space(rd_dev) < 0) + if (rd_build_device_space(rd_dev) < 0) { + ret = -ENOMEM; goto fail; + } snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); snprintf(rev, 4, "%s", (rd_dev->rd_direct) ? RD_DR_VERSION : @@ -292,7 +294,7 @@ static struct se_device *rd_create_virtdevice( fail: rd_release_device_space(rd_dev); - return NULL; + return ERR_PTR(ret); } static struct se_device *rd_DIRECT_create_virtdevice( -- cgit v1.2.2 From 05aea6e7e497ab418239ae54fe5966d52cbd8550 Mon Sep 17 00:00:00 2001 From: Fubo Chen Date: Mon, 14 Mar 2011 04:06:00 -0700 Subject: [SCSI] target: Remove unnecessary hba_dev_list walk and se_clear_dev_ports legacy code This patch removes a legacy struct se_hba->hba_dev_list -> se_release_device_for_hba() list walk in core_delete_hba(), which is no longer required while using configfs VFS level parent/child struct config_group dependency referencing. The reason is because any struct se_hba->hba_dev_list-> struct se_device members are going to have to be released via: rmdir /sys/kernel/config/target/core/$HBA/* before rmdir release of struct se_hba via target_core_configfs.c: target_core_call_delhbafromtarget() -> core_delete_hba() rmdir /sys/kernel/config/target/core/$HBA to release struct se_hba in core_delete_hba(). This patch also removes the legacy se_clear_dev_ports() function, which is left-over pre-configfs shutdown logic for when se_free_virtual_device() was responsible for walking struct se_device->dev_sep_list and calling core_dev_del_lun() for each individual active struct se_port->se_lun. The reason this can be removed is because all struct se_device->dev_sep_list -> struct se_port communication is done via configfs symlinks, which means that an target fabric module's endpoints containg active struct se_port(s) will have to be released via target_core_fabric_configfs.c: target_fabric_port_unlink() via: unlink /sys/kernel/config/target/$FABRIC_MOD/$ENDPOINT/tpgt_$TPGT/lun/lun_$LUN_ID/ before rmdir release of struct se_device in target_core_configfs.c: target_core_drop_subdev() -> se_free_virtual_device() can happen via: rmdir /sys/kernel/config/target/core/$HBA/* to release struct se_subsystem_dev in target_core_drop_subdev() Reported-by: Stefan Richter Reported-by: Fubo Chen Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_device.c | 39 ++----------------------------------- drivers/target/target_core_hba.c | 15 ++------------ 2 files changed, 4 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 350ed401544e..9e182bd245f0 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -779,49 +779,14 @@ void se_release_vpd_for_dev(struct se_device *dev) return; } -/* - * Called with struct se_hba->device_lock held. - */ -void se_clear_dev_ports(struct se_device *dev) -{ - struct se_hba *hba = dev->se_hba; - struct se_lun *lun; - struct se_portal_group *tpg; - struct se_port *sep, *sep_tmp; - - spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { - spin_unlock(&dev->se_port_lock); - spin_unlock(&hba->device_lock); - - lun = sep->sep_lun; - tpg = sep->sep_tpg; - spin_lock(&lun->lun_sep_lock); - if (lun->lun_se_dev == NULL) { - spin_unlock(&lun->lun_sep_lock); - continue; - } - spin_unlock(&lun->lun_sep_lock); - - core_dev_del_lun(tpg, lun->unpacked_lun); - - spin_lock(&hba->device_lock); - spin_lock(&dev->se_port_lock); - } - spin_unlock(&dev->se_port_lock); - - return; -} - /* se_free_virtual_device(): * * Used for IBLOCK, RAMDISK, and FILEIO Transport Drivers. */ int se_free_virtual_device(struct se_device *dev, struct se_hba *hba) { - spin_lock(&hba->device_lock); - se_clear_dev_ports(dev); - spin_unlock(&hba->device_lock); + if (!list_empty(&dev->dev_sep_list)) + dump_stack(); core_alua_free_lu_gp_mem(dev); se_release_device_for_hba(dev); diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 6ec51cbc018e..0b8f8da89019 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -151,19 +151,8 @@ out_free_hba: int core_delete_hba(struct se_hba *hba) { - struct se_device *dev, *dev_tmp; - - spin_lock(&hba->device_lock); - list_for_each_entry_safe(dev, dev_tmp, &hba->hba_dev_list, dev_list) { - - se_clear_dev_ports(dev); - spin_unlock(&hba->device_lock); - - se_release_device_for_hba(dev); - - spin_lock(&hba->device_lock); - } - spin_unlock(&hba->device_lock); + if (!list_empty(&hba->hba_dev_list)) + dump_stack(); hba->transport->detach_hba(hba); -- cgit v1.2.2 From 5dd7ed2e811d5cd12f31fb7f0c5ad0107d494a12 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 14 Mar 2011 04:06:01 -0700 Subject: [SCSI] target: Minor sparse warning fixes and annotations This patch addresses the majority of sparse warnings and adds proper locking annotations. It also fixes the dubious one-bit signed bitfield, for which the signed one-bit types can be 0 or -1 which can cause a problem if someone ever checks if (foo->lu_gp_assoc == 1). The current code is fine because everyone just checks zero vs non-zero. But Sparse complains about it so lets change it. The warnings look like this: include/target/target_core_base.h:228:26: error: dubious one-bit signed bitfield Signed-off-by: Dan Carpenter Signed-off-by: Fubo Chen Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_device.c | 1 + drivers/target/target_core_fabric_lib.c | 1 + drivers/target/target_core_pscsi.c | 3 +++ drivers/target/target_core_rd.h | 2 -- drivers/target/target_core_transport.c | 4 +--- 5 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 9e182bd245f0..3fb8e32506ed 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -589,6 +589,7 @@ static void core_export_port( * Called with struct se_device->se_port_lock spinlock held. */ static void core_release_port(struct se_device *dev, struct se_port *port) + __releases(&dev->se_port_lock) __acquires(&dev->se_port_lock) { /* * Wait for any port reference for PR ALL_TG_PT=1 operation diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index a3c695adabec..d57ad672677f 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 51fd309388fc..7ff6a35f26ac 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -441,6 +441,7 @@ static struct se_device *pscsi_create_type_disk( struct pscsi_dev_virt *pdv, struct se_subsystem_dev *se_dev, struct se_hba *hba) + __releases(sh->host_lock) { struct se_device *dev; struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; @@ -488,6 +489,7 @@ static struct se_device *pscsi_create_type_rom( struct pscsi_dev_virt *pdv, struct se_subsystem_dev *se_dev, struct se_hba *hba) + __releases(sh->host_lock) { struct se_device *dev; struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; @@ -522,6 +524,7 @@ static struct se_device *pscsi_create_type_other( struct pscsi_dev_virt *pdv, struct se_subsystem_dev *se_dev, struct se_hba *hba) + __releases(sh->host_lock) { struct se_device *dev; struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index 13badfbaf9c0..3ea19e29d8ec 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h @@ -14,8 +14,6 @@ #define RD_BLOCKSIZE 512 #define RD_MAX_SECTORS 1024 -extern struct kmem_cache *se_mem_cache; - /* Used in target_core_init_configfs() for virtual LUN 0 access */ int __init rd_module_init(void); void rd_module_exit(void); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ff9ace01e27a..80df4056f9f1 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -227,8 +227,6 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd, static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); static void transport_stop_all_task_timers(struct se_cmd *cmd); -int transport_emulate_control_cdb(struct se_task *task); - int init_se_global(void) { struct se_global *global; @@ -4395,7 +4393,7 @@ out: return -1; } -extern u32 transport_calc_sg_num( +u32 transport_calc_sg_num( struct se_task *task, struct se_mem *in_se_mem, u32 task_offset) -- cgit v1.2.2 From 065f97161b2da30b13000b1d9f64adff7e01e270 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 14 Mar 2011 04:06:03 -0700 Subject: [SCSI] target: Convert rd_build_device_space() to use errno This patch converts rd_build_device_space() to return errno usage for failures in rd_create_virtdevice(). Signed-off-by: Dan Carpenter Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_rd.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index f36094f0596a..7837dd365a9d 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -150,7 +150,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) if (rd_dev->rd_page_count <= 0) { printk(KERN_ERR "Illegal page count: %u for Ramdisk device\n", rd_dev->rd_page_count); - return -1; + return -EINVAL; } total_sg_needed = rd_dev->rd_page_count; @@ -160,7 +160,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) if (!(sg_table)) { printk(KERN_ERR "Unable to allocate memory for Ramdisk" " scatterlist tables\n"); - return -1; + return -ENOMEM; } rd_dev->sg_table_array = sg_table; @@ -175,7 +175,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) if (!(sg)) { printk(KERN_ERR "Unable to allocate scatterlist array" " for struct rd_dev\n"); - return -1; + return -ENOMEM; } sg_init_table((struct scatterlist *)&sg[0], sg_per_table); @@ -191,7 +191,7 @@ static int rd_build_device_space(struct rd_dev *rd_dev) if (!(pg)) { printk(KERN_ERR "Unable to allocate scatterlist" " pages for struct rd_dev_sg_table\n"); - return -1; + return -ENOMEM; } sg_assign_page(&sg[j], pg); sg[j].length = PAGE_SIZE; @@ -253,15 +253,14 @@ static struct se_device *rd_create_virtdevice( struct se_dev_limits dev_limits; struct rd_dev *rd_dev = p; struct rd_host *rd_host = hba->hba_ptr; - int dev_flags = 0, ret = -EINVAL; + int dev_flags = 0, ret; char prod[16], rev[4]; memset(&dev_limits, 0, sizeof(struct se_dev_limits)); - if (rd_build_device_space(rd_dev) < 0) { - ret = -ENOMEM; + ret = rd_build_device_space(rd_dev); + if (ret < 0) goto fail; - } snprintf(prod, 16, "RAMDISK-%s", (rd_dev->rd_direct) ? "DR" : "MCP"); snprintf(rev, 4, "%s", (rd_dev->rd_direct) ? RD_DR_VERSION : -- cgit v1.2.2 From 5c6cd613196558ba50ba97268b6d225c8d2f56d6 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:04 -0700 Subject: [SCSI] target: Convert TMR REQ/RSP definitions to target namespace This patch changes include/target/target_core_tmr.h code to use target specific 'TMR_*' prefixed definitions for fabric independent SCSI Task Management Request/Request naming in include/scsi/scsi.h definitions for mainline target code. Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_transport.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 80df4056f9f1..20ab27cb3e45 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -5832,31 +5832,26 @@ int transport_generic_do_tmr(struct se_cmd *cmd) int ret; switch (tmr->function) { - case ABORT_TASK: + case TMR_ABORT_TASK: ref_cmd = tmr->ref_cmd; tmr->response = TMR_FUNCTION_REJECTED; break; - case ABORT_TASK_SET: - case CLEAR_ACA: - case CLEAR_TASK_SET: + case TMR_ABORT_TASK_SET: + case TMR_CLEAR_ACA: + case TMR_CLEAR_TASK_SET: tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; break; - case LUN_RESET: + case TMR_LUN_RESET: ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : TMR_FUNCTION_REJECTED; break; -#if 0 - case TARGET_WARM_RESET: - transport_generic_host_reset(dev->se_hba); + case TMR_TARGET_WARM_RESET: tmr->response = TMR_FUNCTION_REJECTED; break; - case TARGET_COLD_RESET: - transport_generic_host_reset(dev->se_hba); - transport_generic_cold_reset(dev->se_hba); + case TMR_TARGET_COLD_RESET: tmr->response = TMR_FUNCTION_REJECTED; break; -#endif default: printk(KERN_ERR "Uknown TMR function: 0x%02x.\n", tmr->function); -- cgit v1.2.2 From 872105689eeccbcd77377d6a29f69bba3b0cbe3b Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Mon, 14 Mar 2011 04:06:05 -0700 Subject: [SCSI] target: Avoid mem leak and needless work in transport_generic_get_mem In drivers/target/target_core_transport.c::transport_generic_get_mem() there are a few potential memory leaks in the error paths. This patch makes sure that we free previously allocated memory when other allocations fail. It also moves some work (INIT_LIST_HEAD() and assignment to se_mem->se_len) below all the allocations so that if something fails we don't do the work at all. Signed-off-by: Jesper Juhl Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_transport.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 20ab27cb3e45..67d4286cf244 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -4357,11 +4357,9 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) printk(KERN_ERR "Unable to allocate struct se_mem\n"); goto out; } - INIT_LIST_HEAD(&se_mem->se_list); - se_mem->se_len = (length > dma_size) ? dma_size : length; /* #warning FIXME Allocate contigous pages for struct se_mem elements */ - se_mem->se_page = (struct page *) alloc_pages(GFP_KERNEL, 0); + se_mem->se_page = alloc_pages(GFP_KERNEL, 0); if (!(se_mem->se_page)) { printk(KERN_ERR "alloc_pages() failed\n"); goto out; @@ -4372,6 +4370,8 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) printk(KERN_ERR "kmap_atomic() failed\n"); goto out; } + INIT_LIST_HEAD(&se_mem->se_list); + se_mem->se_len = (length > dma_size) ? dma_size : length; memset(buf, 0, se_mem->se_len); kunmap_atomic(buf, KM_IRQ0); @@ -4390,6 +4390,9 @@ transport_generic_get_mem(struct se_cmd *cmd, u32 length, u32 dma_size) return 0; out: + if (se_mem) + __free_pages(se_mem->se_page, 0); + kmem_cache_free(se_mem_cache, se_mem); return -1; } -- cgit v1.2.2 From 12a18bdc27f81ba9d0a08a2462a49d339fff8b2d Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:06 -0700 Subject: [SCSI] target: Fix bogus return in transport_add_device_to_core_hba failure path This patch removes a bogus conditional+return check within the failure path of transport_add_device_to_core_hba(). This breakage was introduced during the v4 conversion to remove struct se_cmd passthrough ops for INQUIRY / READ_CAPCITY during struct se_device creation and registration process. Reported-by: Julia Lawall Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_transport.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 67d4286cf244..bf6aa8a9f1d8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1620,7 +1620,7 @@ struct se_device *transport_add_device_to_core_hba( const char *inquiry_prod, const char *inquiry_rev) { - int ret = 0, force_pt; + int force_pt; struct se_device *dev; dev = kzalloc(sizeof(struct se_device), GFP_KERNEL); @@ -1737,9 +1737,8 @@ struct se_device *transport_add_device_to_core_hba( } scsi_dump_inquiry(dev); + return dev; out: - if (!ret) - return dev; kthread_stop(dev->process_thread); spin_lock(&hba->device_lock); -- cgit v1.2.2 From 58c3e6477f3840df7d9b346627420bc7b246cdc8 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:08 -0700 Subject: [SCSI] target: Fix FILEIO fd_buffered_io= token typo This patch fixes a token typo for the TCM/FILEIO match_table_t used for toggling O_SYNC usage for individual struct file backend access. Reported-by: Christophe Fergeau Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 03fa40f72ef7..02f553aef43d 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -514,7 +514,7 @@ enum { static match_table_t tokens = { {Opt_fd_dev_name, "fd_dev_name=%s"}, {Opt_fd_dev_size, "fd_dev_size=%s"}, - {Opt_fd_buffered_io, "fd_buffered_id=%d"}, + {Opt_fd_buffered_io, "fd_buffered_io=%d"}, {Opt_err, NULL} }; -- cgit v1.2.2 From 54550fabfecdb71e0deb51999cca7d28bb4299ed Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 14 Mar 2011 04:06:09 -0700 Subject: [SCSI] target: Add __init/__exit annotation for target_core_[init,exit]_configfs This patch fixes the follownig section mismatch warning: WARNING: vmlinux.o(.text+0x21617a): Section mismatch in reference from the function target_core_init_configfs() to the function .init.text:rd_module_init() The function target_core_init_configfs() references the function __init rd_module_init(). This is often because target_core_init_configfs() lacks a __init annotation or the annotation of rd_module_init is wrong. Signed-off-by: Axel Lin Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_configfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 9721ef28335c..a38fec4acceb 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3075,7 +3075,7 @@ static struct config_item_type target_core_cit = { /* Stop functions for struct config_item_type target_core_hba_cit */ -static int target_core_init_configfs(void) +static int __init target_core_init_configfs(void) { struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; struct config_group *lu_gp_cg = NULL; @@ -3207,7 +3207,7 @@ out_global: return -1; } -static void target_core_exit_configfs(void) +static void __exit target_core_exit_configfs(void) { struct configfs_subsystem *subsys; struct config_group *hba_cg, *alua_cg, *lu_gp_cg; -- cgit v1.2.2 From 12d233842987d9972957419e427987b94f7bd7b4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:11 -0700 Subject: [SCSI] target: add initial statistics This patch adds a target_core_mib.c statistics conversion for backend context struct se_subsystem_dev + struct se_device config_group based statistics in target_core_device.c using CONFIGFS_EATTR() based struct config_item_types from target_core_stat.c code. The conversion from backend /proc/scsi_target/mib/ context output to configfs default groups+attributes include scsi_dev, scsi_lu, and scsi_tgt_dev output from within individual: /sys/kernel/config/target/core/$HBA/DEV/ The legacy procfs output now appear as individual configfs attributes under: *) $HBA/$DEV/statistics/scsi_dev: |-- indx |-- inst |-- ports `-- role *) $HBA/$DEV/statistics/scsi_lu: |-- creation_time |-- dev |-- dev_type |-- full_stat |-- hs_num_cmds |-- indx |-- inst |-- lu_name |-- lun |-- num_cmds |-- prod |-- read_mbytes |-- resets |-- rev |-- state_bit |-- status |-- vend `-- write_mbytes *) $HBA/$DEV/statistics/scsi_tgt_dev: |-- indx |-- inst |-- non_access_lus |-- num_lus |-- resets `-- status The conversion from backend /proc/scsi_target/mib/ context output to configfs default groups+attributes include scsi_port, scsi_tgt_port and scsi_transport output from within individual: /sys/kernel/config/target/fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/ The legacy procfs output now appear as individual configfs attributes under: *) fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/scsi_port |-- busy_count |-- dev |-- indx |-- inst `-- role *) fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/scsi_tgt_port |-- dev |-- hs_in_cmds |-- in_cmds |-- indx |-- inst |-- name |-- port_index |-- read_mbytes `-- write_mbytes *) fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/scsi_transport |-- dev_name |-- device |-- indx `-- inst The conversion from backend /proc/scsi_target/mib/ context output to configfs default groups+attributes include scsi_att_intr_port and scsi_auth_intr output from within individual: /sys/kernel/config/target/fabric/$WWN/tpgt_$TPGT/acls/$INITIATOR_WWN/lun_$LUN_ID/statistics/ The legacy procfs output now appear as individual configfs attributes under: *) acls/$INITIATOR_WWN/lun_$LUN_ID/statistics/scsi_att_intr_port |-- dev |-- indx |-- inst |-- port |-- port_auth_indx `-- port_ident *) acls/$INITIATOR_WWN/lun_$LUN_ID/statistics/scsi_auth_intr |-- att_count |-- creation_time |-- dev |-- dev_or_port |-- hs_num_cmds |-- indx |-- inst |-- intr_name |-- map_indx |-- num_cmds |-- port |-- read_mbytes |-- row_status `-- write_mbytes Also, this includes adding struct target_fabric_configfs_template-> tfc_wwn_fabric_stats_cit and ->tfc_tpg_nacl_stat_cit respectively for use during target_core_fabric_configfs.c:target_fabric_setup_cits() Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/Makefile | 3 +- drivers/target/target_core_configfs.c | 76 +- drivers/target/target_core_fabric_configfs.c | 209 ++- drivers/target/target_core_stat.c | 1810 ++++++++++++++++++++++++++ drivers/target/target_core_stat.h | 8 + 5 files changed, 2090 insertions(+), 16 deletions(-) create mode 100644 drivers/target/target_core_stat.c create mode 100644 drivers/target/target_core_stat.h (limited to 'drivers') diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 050ee6569b2b..4f3cb788f06a 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -12,7 +12,8 @@ target_core_mod-y := target_core_configfs.o \ target_core_transport.o \ target_core_cdb.o \ target_core_ua.o \ - target_core_rd.o + target_core_rd.o \ + target_core_stat.o obj-$(CONFIG_TARGET_CORE) += target_core_mod.o diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index a38fec4acceb..a5f44a6e6e1d 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3,8 +3,8 @@ * * This file contains ConfigFS logic for the Generic Target Engine project. * - * Copyright (c) 2008-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * Copyright (c) 2008-2011 Rising Tide Systems + * Copyright (c) 2008-2011 Linux-iSCSI.org * * Nicholas A. Bellinger * @@ -50,6 +50,7 @@ #include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_rd.h" +#include "target_core_stat.h" static struct list_head g_tf_list; static struct mutex g_tf_lock; @@ -2709,6 +2710,34 @@ static struct config_item_type target_core_alua_cit = { /* End functions for struct config_item_type target_core_alua_cit */ +/* Start functions for struct config_item_type target_core_stat_cit */ + +static struct config_group *target_core_stat_mkdir( + struct config_group *group, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static void target_core_stat_rmdir( + struct config_group *group, + struct config_item *item) +{ + return; +} + +static struct configfs_group_operations target_core_stat_group_ops = { + .make_group = &target_core_stat_mkdir, + .drop_item = &target_core_stat_rmdir, +}; + +static struct config_item_type target_core_stat_cit = { + .ct_group_ops = &target_core_stat_group_ops, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_stat_cit */ + /* Start functions for struct config_item_type target_core_hba_cit */ static struct config_group *target_core_make_subdev( @@ -2721,10 +2750,12 @@ static struct config_group *target_core_make_subdev( struct config_item *hba_ci = &group->cg_item; struct se_hba *hba = item_to_hba(hba_ci); struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; + struct config_group *dev_stat_grp = NULL; + int errno = -ENOMEM, ret; - if (mutex_lock_interruptible(&hba->hba_access_mutex)) - return NULL; - + ret = mutex_lock_interruptible(&hba->hba_access_mutex); + if (ret) + return ERR_PTR(ret); /* * Locate the struct se_subsystem_api from parent's struct se_hba. */ @@ -2754,7 +2785,7 @@ static struct config_group *target_core_make_subdev( se_dev->se_dev_hba = hba; dev_cg = &se_dev->se_dev_group; - dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, + dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, GFP_KERNEL); if (!(dev_cg->default_groups)) goto out; @@ -2786,13 +2817,17 @@ static struct config_group *target_core_make_subdev( &target_core_dev_wwn_cit); config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, "alua", &target_core_alua_tg_pt_gps_cit); + config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, + "statistics", &target_core_stat_cit); + dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; - dev_cg->default_groups[4] = NULL; + dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; + dev_cg->default_groups[5] = NULL; /* - * Add core/$HBA/$DEV/alua/tg_pt_gps/default_tg_pt_gp + * Add core/$HBA/$DEV/alua/default_tg_pt_gp */ tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); if (!(tg_pt_gp)) @@ -2812,6 +2847,17 @@ static struct config_group *target_core_make_subdev( tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; tg_pt_gp_cg->default_groups[1] = NULL; T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp; + /* + * Add core/$HBA/$DEV/statistics/ default groups + */ + dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; + dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, + GFP_KERNEL); + if (!dev_stat_grp->default_groups) { + printk(KERN_ERR "Unable to allocate dev_stat_grp->default_groups\n"); + goto out; + } + target_stat_setup_dev_default_groups(se_dev); printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); @@ -2823,6 +2869,8 @@ out: core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); T10_ALUA(se_dev)->default_tg_pt_gp = NULL; } + if (dev_stat_grp) + kfree(dev_stat_grp->default_groups); if (tg_pt_gp_cg) kfree(tg_pt_gp_cg->default_groups); if (dev_cg) @@ -2832,7 +2880,7 @@ out: kfree(se_dev); unlock: mutex_unlock(&hba->hba_access_mutex); - return NULL; + return ERR_PTR(errno); } static void target_core_drop_subdev( @@ -2844,7 +2892,7 @@ static void target_core_drop_subdev( struct se_hba *hba; struct se_subsystem_api *t; struct config_item *df_item; - struct config_group *dev_cg, *tg_pt_gp_cg; + struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; int i; hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); @@ -2856,6 +2904,14 @@ static void target_core_drop_subdev( list_del(&se_dev->g_se_dev_list); spin_unlock(&se_global->g_device_lock); + dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; + for (i = 0; dev_stat_grp->default_groups[i]; i++) { + df_item = &dev_stat_grp->default_groups[i]->cg_item; + dev_stat_grp->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(dev_stat_grp->default_groups); + tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index b65d1c8e7740..07ab5a3bb8e8 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -4,10 +4,10 @@ * This file contains generic fabric module configfs infrastructure for * TCM v4.x code * - * Copyright (c) 2010 Rising Tide Systems - * Copyright (c) 2010 Linux-iSCSI.org + * Copyright (c) 2010,2011 Rising Tide Systems + * Copyright (c) 2010,2011 Linux-iSCSI.org * - * Copyright (c) 2010 Nicholas A. Bellinger + * Copyright (c) Nicholas A. Bellinger * * 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 +48,7 @@ #include "target_core_alua.h" #include "target_core_hba.h" #include "target_core_pr.h" +#include "target_core_stat.h" #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ @@ -241,6 +242,32 @@ TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL, /* End of tfc_tpg_mappedlun_cit */ +/* Start of tfc_tpg_mappedlun_port_cit */ + +static struct config_group *target_core_mappedlun_stat_mkdir( + struct config_group *group, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static void target_core_mappedlun_stat_rmdir( + struct config_group *group, + struct config_item *item) +{ + return; +} + +static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { + .make_group = target_core_mappedlun_stat_mkdir, + .drop_item = target_core_mappedlun_stat_rmdir, +}; + +TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops, + NULL); + +/* End of tfc_tpg_mappedlun_port_cit */ + /* Start of tfc_tpg_nacl_attrib_cit */ CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); @@ -294,6 +321,7 @@ static struct config_group *target_fabric_make_mappedlun( struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_lun_acl *lacl; struct config_item *acl_ci; + struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; char *buf; unsigned long mapped_lun; int ret = 0; @@ -330,15 +358,42 @@ static struct config_group *target_fabric_make_mappedlun( lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, config_item_name(acl_ci), &ret); - if (!(lacl)) + if (!(lacl)) { + ret = -EINVAL; goto out; + } + + lacl_cg = &lacl->se_lun_group; + lacl_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!lacl_cg->default_groups) { + printk(KERN_ERR "Unable to allocate lacl_cg->default_groups\n"); + ret = -ENOMEM; + goto out; + } config_group_init_type_name(&lacl->se_lun_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit); + config_group_init_type_name(&lacl->ml_stat_grps.stat_group, + "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_stat_cit); + lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group; + lacl_cg->default_groups[1] = NULL; + + ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; + ml_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, + GFP_KERNEL); + if (!ml_stat_grp->default_groups) { + printk(KERN_ERR "Unable to allocate ml_stat_grp->default_groups\n"); + ret = -ENOMEM; + goto out; + } + target_stat_setup_mappedlun_default_groups(lacl); kfree(buf); return &lacl->se_lun_group; out: + if (lacl_cg) + kfree(lacl_cg->default_groups); kfree(buf); return ERR_PTR(ret); } @@ -347,6 +402,28 @@ static void target_fabric_drop_mappedlun( struct config_group *group, struct config_item *item) { + struct se_lun_acl *lacl = container_of(to_config_group(item), + struct se_lun_acl, se_lun_group); + struct config_item *df_item; + struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; + int i; + + ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; + for (i = 0; ml_stat_grp->default_groups[i]; i++) { + df_item = &ml_stat_grp->default_groups[i]->cg_item; + ml_stat_grp->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(ml_stat_grp->default_groups); + + lacl_cg = &lacl->se_lun_group; + for (i = 0; lacl_cg->default_groups[i]; i++) { + df_item = &lacl_cg->default_groups[i]->cg_item; + lacl_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(lacl_cg->default_groups); + config_item_put(item); } @@ -376,6 +453,15 @@ TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops, /* End of tfc_tpg_nacl_base_cit */ +/* Start of tfc_node_fabric_stats_cit */ +/* + * This is used as a placeholder for struct se_node_acl->acl_fabric_stat_group + * to allow fabrics access to ->acl_fabric_stat_group->default_groups[] + */ +TF_CIT_SETUP(tpg_nacl_stat, NULL, NULL, NULL); + +/* End of tfc_wwn_fabric_stats_cit */ + /* Start of tfc_tpg_nacl_cit */ static struct config_group *target_fabric_make_nodeacl( @@ -402,7 +488,8 @@ static struct config_group *target_fabric_make_nodeacl( nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; nacl_cg->default_groups[2] = &se_nacl->acl_param_group; - nacl_cg->default_groups[3] = NULL; + nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group; + nacl_cg->default_groups[4] = NULL; config_group_init_type_name(&se_nacl->acl_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit); @@ -412,6 +499,9 @@ static struct config_group *target_fabric_make_nodeacl( &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit); config_group_init_type_name(&se_nacl->acl_param_group, "param", &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit); + config_group_init_type_name(&se_nacl->acl_fabric_stat_group, + "fabric_statistics", + &TF_CIT_TMPL(tf)->tfc_tpg_nacl_stat_cit); return &se_nacl->acl_group; } @@ -758,6 +848,31 @@ TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_at /* End of tfc_tpg_port_cit */ +/* Start of tfc_tpg_port_stat_cit */ + +static struct config_group *target_core_port_stat_mkdir( + struct config_group *group, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static void target_core_port_stat_rmdir( + struct config_group *group, + struct config_item *item) +{ + return; +} + +static struct configfs_group_operations target_fabric_port_stat_group_ops = { + .make_group = target_core_port_stat_mkdir, + .drop_item = target_core_port_stat_rmdir, +}; + +TF_CIT_SETUP(tpg_port_stat, NULL, &target_fabric_port_stat_group_ops, NULL); + +/* End of tfc_tpg_port_stat_cit */ + /* Start of tfc_tpg_lun_cit */ static struct config_group *target_fabric_make_lun( @@ -768,7 +883,9 @@ static struct config_group *target_fabric_make_lun( struct se_portal_group *se_tpg = container_of(group, struct se_portal_group, tpg_lun_group); struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct config_group *lun_cg = NULL, *port_stat_grp = NULL; unsigned long unpacked_lun; + int errno; if (strstr(name, "lun_") != name) { printk(KERN_ERR "Unable to locate \'_\" in" @@ -782,16 +899,64 @@ static struct config_group *target_fabric_make_lun( if (!(lun)) return ERR_PTR(-EINVAL); + lun_cg = &lun->lun_group; + lun_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!lun_cg->default_groups) { + printk(KERN_ERR "Unable to allocate lun_cg->default_groups\n"); + return ERR_PTR(-ENOMEM); + } + config_group_init_type_name(&lun->lun_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_port_cit); + config_group_init_type_name(&lun->port_stat_grps.stat_group, + "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_port_stat_cit); + lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group; + lun_cg->default_groups[1] = NULL; + + port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; + port_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, + GFP_KERNEL); + if (!port_stat_grp->default_groups) { + printk(KERN_ERR "Unable to allocate port_stat_grp->default_groups\n"); + errno = -ENOMEM; + goto out; + } + target_stat_setup_port_default_groups(lun); return &lun->lun_group; +out: + if (lun_cg) + kfree(lun_cg->default_groups); + return ERR_PTR(errno); } static void target_fabric_drop_lun( struct config_group *group, struct config_item *item) { + struct se_lun *lun = container_of(to_config_group(item), + struct se_lun, lun_group); + struct config_item *df_item; + struct config_group *lun_cg, *port_stat_grp; + int i; + + port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; + for (i = 0; port_stat_grp->default_groups[i]; i++) { + df_item = &port_stat_grp->default_groups[i]->cg_item; + port_stat_grp->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(port_stat_grp->default_groups); + + lun_cg = &lun->lun_group; + for (i = 0; lun_cg->default_groups[i]; i++) { + df_item = &lun_cg->default_groups[i]->cg_item; + lun_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(lun_cg->default_groups); + config_item_put(item); } @@ -946,6 +1111,15 @@ TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops, /* End of tfc_tpg_cit */ +/* Start of tfc_wwn_fabric_stats_cit */ +/* + * This is used as a placeholder for struct se_wwn->fabric_stat_group + * to allow fabrics access to ->fabric_stat_group->default_groups[] + */ +TF_CIT_SETUP(wwn_fabric_stats, NULL, NULL, NULL); + +/* End of tfc_wwn_fabric_stats_cit */ + /* Start of tfc_wwn_cit */ static struct config_group *target_fabric_make_wwn( @@ -966,8 +1140,17 @@ static struct config_group *target_fabric_make_wwn( return ERR_PTR(-EINVAL); wwn->wwn_tf = tf; + /* + * Setup default groups from pre-allocated wwn->wwn_default_groups + */ + wwn->wwn_group.default_groups = wwn->wwn_default_groups; + wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group; + wwn->wwn_group.default_groups[1] = NULL; + config_group_init_type_name(&wwn->wwn_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_cit); + config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", + &TF_CIT_TMPL(tf)->tfc_wwn_fabric_stats_cit); return &wwn->wwn_group; } @@ -976,6 +1159,18 @@ static void target_fabric_drop_wwn( struct config_group *group, struct config_item *item) { + struct se_wwn *wwn = container_of(to_config_group(item), + struct se_wwn, wwn_group); + struct config_item *df_item; + struct config_group *cg = &wwn->wwn_group; + int i; + + for (i = 0; cg->default_groups[i]; i++) { + df_item = &cg->default_groups[i]->cg_item; + cg->default_groups[i] = NULL; + config_item_put(df_item); + } + config_item_put(item); } @@ -1015,9 +1210,11 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) { target_fabric_setup_discovery_cit(tf); target_fabric_setup_wwn_cit(tf); + target_fabric_setup_wwn_fabric_stats_cit(tf); target_fabric_setup_tpg_cit(tf); target_fabric_setup_tpg_base_cit(tf); target_fabric_setup_tpg_port_cit(tf); + target_fabric_setup_tpg_port_stat_cit(tf); target_fabric_setup_tpg_lun_cit(tf); target_fabric_setup_tpg_np_cit(tf); target_fabric_setup_tpg_np_base_cit(tf); @@ -1028,7 +1225,9 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) target_fabric_setup_tpg_nacl_attrib_cit(tf); target_fabric_setup_tpg_nacl_auth_cit(tf); target_fabric_setup_tpg_nacl_param_cit(tf); + target_fabric_setup_tpg_nacl_stat_cit(tf); target_fabric_setup_tpg_mappedlun_cit(tf); + target_fabric_setup_tpg_mappedlun_stat_cit(tf); return 0; } diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c new file mode 100644 index 000000000000..5e3a067a7475 --- /dev/null +++ b/drivers/target/target_core_stat.c @@ -0,0 +1,1810 @@ +/******************************************************************************* + * Filename: target_core_stat.c + * + * Copyright (c) 2011 Rising Tide Systems + * Copyright (c) 2011 Linux-iSCSI.org + * + * Modern ConfigFS group context specific statistics based on original + * target_core_mib.c code + * + * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. + * + * Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "target_core_hba.h" + +#ifndef INITIAL_JIFFIES +#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) +#endif + +#define NONE "None" +#define ISPRINT(a) ((a >= ' ') && (a <= '~')) + +#define SCSI_LU_INDEX 1 +#define LU_COUNT 1 + +/* + * SCSI Device Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_dev, se_dev_stat_grps); +#define DEV_STAT_SCSI_DEV_ATTR(_name, _mode) \ +static struct target_stat_scsi_dev_attribute \ + target_stat_scsi_dev_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_dev_show_attr_##_name, \ + target_stat_scsi_dev_store_attr_##_name); + +#define DEV_STAT_SCSI_DEV_ATTR_RO(_name) \ +static struct target_stat_scsi_dev_attribute \ + target_stat_scsi_dev_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_dev_show_attr_##_name); + +static ssize_t target_stat_scsi_dev_show_attr_inst( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_hba *hba = se_subdev->se_dev_hba; + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); +} +DEV_STAT_SCSI_DEV_ATTR_RO(inst); + +static ssize_t target_stat_scsi_dev_show_attr_indx( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); +} +DEV_STAT_SCSI_DEV_ATTR_RO(indx); + +static ssize_t target_stat_scsi_dev_show_attr_role( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "Target\n"); +} +DEV_STAT_SCSI_DEV_ATTR_RO(role); + +static ssize_t target_stat_scsi_dev_show_attr_ports( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count); +} +DEV_STAT_SCSI_DEV_ATTR_RO(ports); + +CONFIGFS_EATTR_OPS(target_stat_scsi_dev, se_dev_stat_grps, scsi_dev_group); + +static struct configfs_attribute *target_stat_scsi_dev_attrs[] = { + &target_stat_scsi_dev_inst.attr, + &target_stat_scsi_dev_indx.attr, + &target_stat_scsi_dev_role.attr, + &target_stat_scsi_dev_ports.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_dev_attrib_ops = { + .show_attribute = target_stat_scsi_dev_attr_show, + .store_attribute = target_stat_scsi_dev_attr_store, +}; + +static struct config_item_type target_stat_scsi_dev_cit = { + .ct_item_ops = &target_stat_scsi_dev_attrib_ops, + .ct_attrs = target_stat_scsi_dev_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Target Device Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_dev, se_dev_stat_grps); +#define DEV_STAT_SCSI_TGT_DEV_ATTR(_name, _mode) \ +static struct target_stat_scsi_tgt_dev_attribute \ + target_stat_scsi_tgt_dev_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_tgt_dev_show_attr_##_name, \ + target_stat_scsi_tgt_dev_store_attr_##_name); + +#define DEV_STAT_SCSI_TGT_DEV_ATTR_RO(_name) \ +static struct target_stat_scsi_tgt_dev_attribute \ + target_stat_scsi_tgt_dev_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_tgt_dev_show_attr_##_name); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_inst( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_hba *hba = se_subdev->se_dev_hba; + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_indx( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_status( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + char status[16]; + + if (!dev) + return -ENODEV; + + switch (dev->dev_status) { + case TRANSPORT_DEVICE_ACTIVATED: + strcpy(status, "activated"); + break; + case TRANSPORT_DEVICE_DEACTIVATED: + strcpy(status, "deactivated"); + break; + case TRANSPORT_DEVICE_SHUTDOWN: + strcpy(status, "shutdown"); + break; + case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: + case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: + strcpy(status, "offline"); + break; + default: + sprintf(status, "unknown(%d)", dev->dev_status); + break; + } + + return snprintf(page, PAGE_SIZE, "%s\n", status); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int non_accessible_lus; + + if (!dev) + return -ENODEV; + + switch (dev->dev_status) { + case TRANSPORT_DEVICE_ACTIVATED: + non_accessible_lus = 0; + break; + case TRANSPORT_DEVICE_DEACTIVATED: + case TRANSPORT_DEVICE_SHUTDOWN: + case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: + case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: + default: + non_accessible_lus = 1; + break; + } + + return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_resets( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(resets); + + +CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_dev, se_dev_stat_grps, scsi_tgt_dev_group); + +static struct configfs_attribute *target_stat_scsi_tgt_dev_attrs[] = { + &target_stat_scsi_tgt_dev_inst.attr, + &target_stat_scsi_tgt_dev_indx.attr, + &target_stat_scsi_tgt_dev_num_lus.attr, + &target_stat_scsi_tgt_dev_status.attr, + &target_stat_scsi_tgt_dev_non_access_lus.attr, + &target_stat_scsi_tgt_dev_resets.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_tgt_dev_attrib_ops = { + .show_attribute = target_stat_scsi_tgt_dev_attr_show, + .store_attribute = target_stat_scsi_tgt_dev_attr_store, +}; + +static struct config_item_type target_stat_scsi_tgt_dev_cit = { + .ct_item_ops = &target_stat_scsi_tgt_dev_attrib_ops, + .ct_attrs = target_stat_scsi_tgt_dev_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Logical Unit Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_lu, se_dev_stat_grps); +#define DEV_STAT_SCSI_LU_ATTR(_name, _mode) \ +static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_lu_show_attr_##_name, \ + target_stat_scsi_lu_store_attr_##_name); + +#define DEV_STAT_SCSI_LU_ATTR_RO(_name) \ +static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_lu_show_attr_##_name); + +static ssize_t target_stat_scsi_lu_show_attr_inst( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_hba *hba = se_subdev->se_dev_hba; + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); +} +DEV_STAT_SCSI_LU_ATTR_RO(inst); + +static ssize_t target_stat_scsi_lu_show_attr_dev( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); +} +DEV_STAT_SCSI_LU_ATTR_RO(dev); + +static ssize_t target_stat_scsi_lu_show_attr_indx( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX); +} +DEV_STAT_SCSI_LU_ATTR_RO(indx); + +static ssize_t target_stat_scsi_lu_show_attr_lun( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + /* FIXME: scsiLuDefaultLun */ + return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0); +} +DEV_STAT_SCSI_LU_ATTR_RO(lun); + +static ssize_t target_stat_scsi_lu_show_attr_lu_name( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + /* scsiLuWwnName */ + return snprintf(page, PAGE_SIZE, "%s\n", + (strlen(DEV_T10_WWN(dev)->unit_serial)) ? + (char *)&DEV_T10_WWN(dev)->unit_serial[0] : "None"); +} +DEV_STAT_SCSI_LU_ATTR_RO(lu_name); + +static ssize_t target_stat_scsi_lu_show_attr_vend( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int j; + char str[28]; + + if (!dev) + return -ENODEV; + /* scsiLuVendorId */ + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + for (j = 0; j < 8; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ? + DEV_T10_WWN(dev)->vendor[j] : 0x20; + str[8] = 0; + return snprintf(page, PAGE_SIZE, "%s\n", str); +} +DEV_STAT_SCSI_LU_ATTR_RO(vend); + +static ssize_t target_stat_scsi_lu_show_attr_prod( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int j; + char str[28]; + + if (!dev) + return -ENODEV; + + /* scsiLuProductId */ + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + for (j = 0; j < 16; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ? + DEV_T10_WWN(dev)->model[j] : 0x20; + str[16] = 0; + return snprintf(page, PAGE_SIZE, "%s\n", str); +} +DEV_STAT_SCSI_LU_ATTR_RO(prod); + +static ssize_t target_stat_scsi_lu_show_attr_rev( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int j; + char str[28]; + + if (!dev) + return -ENODEV; + + /* scsiLuRevisionId */ + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + for (j = 0; j < 4; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ? + DEV_T10_WWN(dev)->revision[j] : 0x20; + str[4] = 0; + return snprintf(page, PAGE_SIZE, "%s\n", str); +} +DEV_STAT_SCSI_LU_ATTR_RO(rev); + +static ssize_t target_stat_scsi_lu_show_attr_dev_type( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuPeripheralType */ + return snprintf(page, PAGE_SIZE, "%u\n", + TRANSPORT(dev)->get_device_type(dev)); +} +DEV_STAT_SCSI_LU_ATTR_RO(dev_type); + +static ssize_t target_stat_scsi_lu_show_attr_status( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuStatus */ + return snprintf(page, PAGE_SIZE, "%s\n", + (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? + "available" : "notavailable"); +} +DEV_STAT_SCSI_LU_ATTR_RO(status); + +static ssize_t target_stat_scsi_lu_show_attr_state_bit( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuState */ + return snprintf(page, PAGE_SIZE, "exposed\n"); +} +DEV_STAT_SCSI_LU_ATTR_RO(state_bit); + +static ssize_t target_stat_scsi_lu_show_attr_num_cmds( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuNumCommands */ + return snprintf(page, PAGE_SIZE, "%llu\n", + (unsigned long long)dev->num_cmds); +} +DEV_STAT_SCSI_LU_ATTR_RO(num_cmds); + +static ssize_t target_stat_scsi_lu_show_attr_read_mbytes( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuReadMegaBytes */ + return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->read_bytes >> 20)); +} +DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes); + +static ssize_t target_stat_scsi_lu_show_attr_write_mbytes( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuWrittenMegaBytes */ + return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->write_bytes >> 20)); +} +DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes); + +static ssize_t target_stat_scsi_lu_show_attr_resets( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuInResets */ + return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); +} +DEV_STAT_SCSI_LU_ATTR_RO(resets); + +static ssize_t target_stat_scsi_lu_show_attr_full_stat( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* FIXME: scsiLuOutTaskSetFullStatus */ + return snprintf(page, PAGE_SIZE, "%u\n", 0); +} +DEV_STAT_SCSI_LU_ATTR_RO(full_stat); + +static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* FIXME: scsiLuHSInCommands */ + return snprintf(page, PAGE_SIZE, "%u\n", 0); +} +DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds); + +static ssize_t target_stat_scsi_lu_show_attr_creation_time( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuCreationTime */ + return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time - + INITIAL_JIFFIES) * 100 / HZ)); +} +DEV_STAT_SCSI_LU_ATTR_RO(creation_time); + +CONFIGFS_EATTR_OPS(target_stat_scsi_lu, se_dev_stat_grps, scsi_lu_group); + +static struct configfs_attribute *target_stat_scsi_lu_attrs[] = { + &target_stat_scsi_lu_inst.attr, + &target_stat_scsi_lu_dev.attr, + &target_stat_scsi_lu_indx.attr, + &target_stat_scsi_lu_lun.attr, + &target_stat_scsi_lu_lu_name.attr, + &target_stat_scsi_lu_vend.attr, + &target_stat_scsi_lu_prod.attr, + &target_stat_scsi_lu_rev.attr, + &target_stat_scsi_lu_dev_type.attr, + &target_stat_scsi_lu_status.attr, + &target_stat_scsi_lu_state_bit.attr, + &target_stat_scsi_lu_num_cmds.attr, + &target_stat_scsi_lu_read_mbytes.attr, + &target_stat_scsi_lu_write_mbytes.attr, + &target_stat_scsi_lu_resets.attr, + &target_stat_scsi_lu_full_stat.attr, + &target_stat_scsi_lu_hs_num_cmds.attr, + &target_stat_scsi_lu_creation_time.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_lu_attrib_ops = { + .show_attribute = target_stat_scsi_lu_attr_show, + .store_attribute = target_stat_scsi_lu_attr_store, +}; + +static struct config_item_type target_stat_scsi_lu_cit = { + .ct_item_ops = &target_stat_scsi_lu_attrib_ops, + .ct_attrs = target_stat_scsi_lu_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * Called from target_core_configfs.c:target_core_make_subdev() to setup + * the target statistics groups + configfs CITs located in target_core_stat.c + */ +void target_stat_setup_dev_default_groups(struct se_subsystem_dev *se_subdev) +{ + struct config_group *dev_stat_grp = &DEV_STAT_GRP(se_subdev)->stat_group; + + config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_dev_group, + "scsi_dev", &target_stat_scsi_dev_cit); + config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group, + "scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit); + config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_lu_group, + "scsi_lu", &target_stat_scsi_lu_cit); + + dev_stat_grp->default_groups[0] = &DEV_STAT_GRP(se_subdev)->scsi_dev_group; + dev_stat_grp->default_groups[1] = &DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group; + dev_stat_grp->default_groups[2] = &DEV_STAT_GRP(se_subdev)->scsi_lu_group; + dev_stat_grp->default_groups[3] = NULL; +} + +/* + * SCSI Port Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_port, se_port_stat_grps); +#define DEV_STAT_SCSI_PORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_port_attribute \ + target_stat_scsi_port_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_port_show_attr_##_name, \ + target_stat_scsi_port_store_attr_##_name); + +#define DEV_STAT_SCSI_PORT_ATTR_RO(_name) \ +static struct target_stat_scsi_port_attribute \ + target_stat_scsi_port_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_port_show_attr_##_name); + +static ssize_t target_stat_scsi_port_show_attr_inst( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_device *dev = lun->lun_se_dev; + struct se_hba *hba; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + hba = dev->se_hba; + ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_port_show_attr_dev( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_device *dev = lun->lun_se_dev; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(dev); + +static ssize_t target_stat_scsi_port_show_attr_indx( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_port_show_attr_role( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + ssize_t ret; + + if (!dev) + return -ENODEV; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(role); + +static ssize_t target_stat_scsi_port_show_attr_busy_count( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + /* FIXME: scsiPortBusyStatuses */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); + +CONFIGFS_EATTR_OPS(target_stat_scsi_port, se_port_stat_grps, scsi_port_group); + +static struct configfs_attribute *target_stat_scsi_port_attrs[] = { + &target_stat_scsi_port_inst.attr, + &target_stat_scsi_port_dev.attr, + &target_stat_scsi_port_indx.attr, + &target_stat_scsi_port_role.attr, + &target_stat_scsi_port_busy_count.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_port_attrib_ops = { + .show_attribute = target_stat_scsi_port_attr_show, + .store_attribute = target_stat_scsi_port_attr_store, +}; + +static struct config_item_type target_stat_scsi_port_cit = { + .ct_item_ops = &target_stat_scsi_port_attrib_ops, + .ct_attrs = target_stat_scsi_port_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Target Port Table + */ +CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_port, se_port_stat_grps); +#define DEV_STAT_SCSI_TGT_PORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_tgt_port_attribute \ + target_stat_scsi_tgt_port_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_tgt_port_show_attr_##_name, \ + target_stat_scsi_tgt_port_store_attr_##_name); + +#define DEV_STAT_SCSI_TGT_PORT_ATTR_RO(_name) \ +static struct target_stat_scsi_tgt_port_attribute \ + target_stat_scsi_tgt_port_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_tgt_port_show_attr_##_name); + +static ssize_t target_stat_scsi_tgt_port_show_attr_inst( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + struct se_hba *hba; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + hba = dev->se_hba; + ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_tgt_port_show_attr_dev( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); + +static ssize_t target_stat_scsi_tgt_port_show_attr_indx( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_tgt_port_show_attr_name( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", + TPG_TFO(tpg)->get_fabric_name(), sep->sep_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); + +static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", + TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); + +static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); + +static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(sep->sep_stats.rx_data_octets >> 20)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); + +static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(sep->sep_stats.tx_data_octets >> 20)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); + +static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + /* FIXME: scsiTgtPortHsInCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); + +CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_port, se_port_stat_grps, + scsi_tgt_port_group); + +static struct configfs_attribute *target_stat_scsi_tgt_port_attrs[] = { + &target_stat_scsi_tgt_port_inst.attr, + &target_stat_scsi_tgt_port_dev.attr, + &target_stat_scsi_tgt_port_indx.attr, + &target_stat_scsi_tgt_port_name.attr, + &target_stat_scsi_tgt_port_port_index.attr, + &target_stat_scsi_tgt_port_in_cmds.attr, + &target_stat_scsi_tgt_port_write_mbytes.attr, + &target_stat_scsi_tgt_port_read_mbytes.attr, + &target_stat_scsi_tgt_port_hs_in_cmds.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_tgt_port_attrib_ops = { + .show_attribute = target_stat_scsi_tgt_port_attr_show, + .store_attribute = target_stat_scsi_tgt_port_attr_store, +}; + +static struct config_item_type target_stat_scsi_tgt_port_cit = { + .ct_item_ops = &target_stat_scsi_tgt_port_attrib_ops, + .ct_attrs = target_stat_scsi_tgt_port_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Transport Table +o */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_transport, se_port_stat_grps); +#define DEV_STAT_SCSI_TRANSPORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_transport_attribute \ + target_stat_scsi_transport_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_transport_show_attr_##_name, \ + target_stat_scsi_transport_store_attr_##_name); + +#define DEV_STAT_SCSI_TRANSPORT_ATTR_RO(_name) \ +static struct target_stat_scsi_transport_attribute \ + target_stat_scsi_transport_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_transport_show_attr_##_name); + +static ssize_t target_stat_scsi_transport_show_attr_inst( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + struct se_hba *hba; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + + hba = dev->se_hba; + ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_transport_show_attr_device( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + /* scsiTransportType */ + ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", + TPG_TFO(tpg)->get_fabric_name()); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); + +static ssize_t target_stat_scsi_transport_show_attr_indx( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->tpg_get_inst_index(tpg)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_transport_show_attr_dev_name( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + struct se_portal_group *tpg; + struct t10_wwn *wwn; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + wwn = DEV_T10_WWN(dev); + /* scsiTransportDevName */ + ret = snprintf(page, PAGE_SIZE, "%s+%s\n", + TPG_TFO(tpg)->tpg_get_wwn(tpg), + (strlen(wwn->unit_serial)) ? wwn->unit_serial : + wwn->vendor); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); + +CONFIGFS_EATTR_OPS(target_stat_scsi_transport, se_port_stat_grps, + scsi_transport_group); + +static struct configfs_attribute *target_stat_scsi_transport_attrs[] = { + &target_stat_scsi_transport_inst.attr, + &target_stat_scsi_transport_device.attr, + &target_stat_scsi_transport_indx.attr, + &target_stat_scsi_transport_dev_name.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_transport_attrib_ops = { + .show_attribute = target_stat_scsi_transport_attr_show, + .store_attribute = target_stat_scsi_transport_attr_store, +}; + +static struct config_item_type target_stat_scsi_transport_cit = { + .ct_item_ops = &target_stat_scsi_transport_attrib_ops, + .ct_attrs = target_stat_scsi_transport_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * Called from target_core_fabric_configfs.c:target_fabric_make_lun() to setup + * the target port statistics groups + configfs CITs located in target_core_stat.c + */ +void target_stat_setup_port_default_groups(struct se_lun *lun) +{ + struct config_group *port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; + + config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_port_group, + "scsi_port", &target_stat_scsi_port_cit); + config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_tgt_port_group, + "scsi_tgt_port", &target_stat_scsi_tgt_port_cit); + config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_transport_group, + "scsi_transport", &target_stat_scsi_transport_cit); + + port_stat_grp->default_groups[0] = &PORT_STAT_GRP(lun)->scsi_port_group; + port_stat_grp->default_groups[1] = &PORT_STAT_GRP(lun)->scsi_tgt_port_group; + port_stat_grp->default_groups[2] = &PORT_STAT_GRP(lun)->scsi_transport_group; + port_stat_grp->default_groups[3] = NULL; +} + +/* + * SCSI Authorized Initiator Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_auth_intr, se_ml_stat_grps); +#define DEV_STAT_SCSI_AUTH_INTR_ATTR(_name, _mode) \ +static struct target_stat_scsi_auth_intr_attribute \ + target_stat_scsi_auth_intr_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_auth_intr_show_attr_##_name, \ + target_stat_scsi_auth_intr_store_attr_##_name); + +#define DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(_name) \ +static struct target_stat_scsi_auth_intr_attribute \ + target_stat_scsi_auth_intr_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_auth_intr_show_attr_##_name); + +static ssize_t target_stat_scsi_auth_intr_show_attr_inst( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiInstIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->tpg_get_inst_index(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst); + +static ssize_t target_stat_scsi_auth_intr_show_attr_dev( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + lun = deve->se_lun; + /* scsiDeviceIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev); + +static ssize_t target_stat_scsi_auth_intr_show_attr_port( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiAuthIntrTgtPortIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port); + +static ssize_t target_stat_scsi_auth_intr_show_attr_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx); + +static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrDevOrPort */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 1); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port); + +static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrName */ + ret = snprintf(page, PAGE_SIZE, "%s\n", nacl->initiatorname); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name); + +static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* FIXME: scsiAuthIntrLunMapIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx); + +static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrAttachedTimes */ + ret = snprintf(page, PAGE_SIZE, "%u\n", deve->attach_count); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count); + +static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrOutCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", deve->total_cmds); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds); + +static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrReadMegaBytes */ + ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->read_bytes >> 20)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes); + +static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrWrittenMegaBytes */ + ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->write_bytes >> 20)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes); + +static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* FIXME: scsiAuthIntrHSOutCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds); + +static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrLastCreation */ + ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)deve->creation_time - + INITIAL_JIFFIES) * 100 / HZ)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time); + +static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* FIXME: scsiAuthIntrRowStatus */ + ret = snprintf(page, PAGE_SIZE, "Ready\n"); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status); + +CONFIGFS_EATTR_OPS(target_stat_scsi_auth_intr, se_ml_stat_grps, + scsi_auth_intr_group); + +static struct configfs_attribute *target_stat_scsi_auth_intr_attrs[] = { + &target_stat_scsi_auth_intr_inst.attr, + &target_stat_scsi_auth_intr_dev.attr, + &target_stat_scsi_auth_intr_port.attr, + &target_stat_scsi_auth_intr_indx.attr, + &target_stat_scsi_auth_intr_dev_or_port.attr, + &target_stat_scsi_auth_intr_intr_name.attr, + &target_stat_scsi_auth_intr_map_indx.attr, + &target_stat_scsi_auth_intr_att_count.attr, + &target_stat_scsi_auth_intr_num_cmds.attr, + &target_stat_scsi_auth_intr_read_mbytes.attr, + &target_stat_scsi_auth_intr_write_mbytes.attr, + &target_stat_scsi_auth_intr_hs_num_cmds.attr, + &target_stat_scsi_auth_intr_creation_time.attr, + &target_stat_scsi_auth_intr_row_status.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_auth_intr_attrib_ops = { + .show_attribute = target_stat_scsi_auth_intr_attr_show, + .store_attribute = target_stat_scsi_auth_intr_attr_store, +}; + +static struct config_item_type target_stat_scsi_auth_intr_cit = { + .ct_item_ops = &target_stat_scsi_auth_intr_attrib_ops, + .ct_attrs = target_stat_scsi_auth_intr_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Attached Initiator Port Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_att_intr_port, se_ml_stat_grps); +#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_att_intr_port_attribute \ + target_stat_scsi_att_intr_port_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_att_intr_port_show_attr_##_name, \ + target_stat_scsi_att_intr_port_store_attr_##_name); + +#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(_name) \ +static struct target_stat_scsi_att_intr_port_attribute \ + target_stat_scsi_att_intr_port_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_att_intr_port_show_attr_##_name); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiInstIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->tpg_get_inst_index(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + lun = deve->se_lun; + /* scsiDeviceIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_port( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiPortIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_session *se_sess; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->nacl_sess_lock); + se_sess = nacl->nacl_sess; + if (!se_sess) { + spin_unlock_irq(&nacl->nacl_sess_lock); + return -ENODEV; + } + + tpg = nacl->se_tpg; + /* scsiAttIntrPortIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->sess_get_index(se_sess)); + spin_unlock_irq(&nacl->nacl_sess_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAttIntrPortAuthIntrIdx */ + ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_session *se_sess; + struct se_portal_group *tpg; + ssize_t ret; + unsigned char buf[64]; + + spin_lock_irq(&nacl->nacl_sess_lock); + se_sess = nacl->nacl_sess; + if (!se_sess) { + spin_unlock_irq(&nacl->nacl_sess_lock); + return -ENODEV; + } + + tpg = nacl->se_tpg; + /* scsiAttIntrPortName+scsiAttIntrPortIdentifier */ + memset(buf, 0, 64); + if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) + TPG_TFO(tpg)->sess_get_initiator_sid(se_sess, + (unsigned char *)&buf[0], 64); + + ret = snprintf(page, PAGE_SIZE, "%s+i+%s\n", nacl->initiatorname, buf); + spin_unlock_irq(&nacl->nacl_sess_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_ident); + +CONFIGFS_EATTR_OPS(target_stat_scsi_att_intr_port, se_ml_stat_grps, + scsi_att_intr_port_group); + +static struct configfs_attribute *target_stat_scsi_ath_intr_port_attrs[] = { + &target_stat_scsi_att_intr_port_inst.attr, + &target_stat_scsi_att_intr_port_dev.attr, + &target_stat_scsi_att_intr_port_port.attr, + &target_stat_scsi_att_intr_port_indx.attr, + &target_stat_scsi_att_intr_port_port_auth_indx.attr, + &target_stat_scsi_att_intr_port_port_ident.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_att_intr_port_attrib_ops = { + .show_attribute = target_stat_scsi_att_intr_port_attr_show, + .store_attribute = target_stat_scsi_att_intr_port_attr_store, +}; + +static struct config_item_type target_stat_scsi_att_intr_port_cit = { + .ct_item_ops = &target_stat_scsi_att_intr_port_attrib_ops, + .ct_attrs = target_stat_scsi_ath_intr_port_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * Called from target_core_fabric_configfs.c:target_fabric_make_mappedlun() to setup + * the target MappedLUN statistics groups + configfs CITs located in target_core_stat.c + */ +void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl) +{ + struct config_group *ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; + + config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_auth_intr_group, + "scsi_auth_intr", &target_stat_scsi_auth_intr_cit); + config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_att_intr_port_group, + "scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit); + + ml_stat_grp->default_groups[0] = &ML_STAT_GRPS(lacl)->scsi_auth_intr_group; + ml_stat_grp->default_groups[1] = &ML_STAT_GRPS(lacl)->scsi_att_intr_port_group; + ml_stat_grp->default_groups[2] = NULL; +} diff --git a/drivers/target/target_core_stat.h b/drivers/target/target_core_stat.h new file mode 100644 index 000000000000..86c252f9ea47 --- /dev/null +++ b/drivers/target/target_core_stat.h @@ -0,0 +1,8 @@ +#ifndef TARGET_CORE_STAT_H +#define TARGET_CORE_STAT_H + +extern void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); +extern void target_stat_setup_port_default_groups(struct se_lun *); +extern void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); + +#endif /*** TARGET_CORE_STAT_H ***/ -- cgit v1.2.2 From 0a2385cea9a715e11df10fce1f1442d933008a40 Mon Sep 17 00:00:00 2001 From: "Kashyap, Desai" Date: Tue, 15 Mar 2011 20:04:26 +0530 Subject: [SCSI] mpt2sas : Added customer specific display support Added Vendor specific branding message support. Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 49 +++++++++++++++++++++++++++++++++++++ drivers/scsi/mpt2sas/mpt2sas_base.h | 20 +++++++++++++++ 2 files changed, 69 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index e8a6f1cf1e4b..5e001ffd4c13 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1747,6 +1747,54 @@ _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) } } +/** + * _base_display_hp_branding - Display branding string + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc) +{ + if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID) + return; + + switch (ioc->pdev->device) { + case MPI2_MFGPAGE_DEVID_SAS2004: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); + break; + default: + break; + } + case MPI2_MFGPAGE_DEVID_SAS2308_2: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_HP_2_4_INTERNAL_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_HP_2_4_INTERNAL_BRANDING); + break; + case MPT2SAS_HP_2_4_EXTERNAL_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_HP_2_4_EXTERNAL_BRANDING); + break; + case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); + break; + case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: + printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, + MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); + break; + default: + break; + } + default: + break; + } +} + /** * _base_display_ioc_capabilities - Disply IOC's capabilities. * @ioc: per adapter object @@ -1778,6 +1826,7 @@ _base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) _base_display_dell_branding(ioc); _base_display_intel_branding(ioc); + _base_display_hp_branding(ioc); printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index a3f8aa9baea4..500328245f61 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -168,6 +168,26 @@ #define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E #define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F + +/* + * HP HBA branding + */ +#define MPT2SAS_HP_3PAR_SSVID 0x1590 +#define MPT2SAS_HP_2_4_INTERNAL_BRANDING "HP H220 Host Bus Adapter" +#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING "HP H221 Host Bus Adapter" +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter" +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING "HP H220i Host Bus Adapter" +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING "HP H210i Host Bus Adapter" + +/* + * HO HBA SSDIDs + */ +#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 +#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 + /* * per target private data */ -- cgit v1.2.2 From e8b12f0fb8352237525961f14ec933e915848840 Mon Sep 17 00:00:00 2001 From: Mahesh Rajashekhara Date: Thu, 17 Mar 2011 02:10:32 -0700 Subject: [SCSI] aacraid: Add new code for PMC-Sierra's SRC based controller family Added new hardware device 0x28b interface for PMC-Sierra's SRC based controller family. - new src.c file for 0x28b specific functions - new XPORT header required - sync. command interface: doorbell bits shifted (SRC_ODR_SHIFT, SRC_IDR_SHIFT) - async. Interface: different inbound queue handling, no outbound I2O queue available, using doorbell ("PmDoorBellResponseSent") and response buffer on the host ("host_rrq") for status - changed AIF (adapter initiated FIBs) interface: "DoorBellAifPending" bit to inform about pending AIF, "AifRequest" command to read AIF, "NoMoreAifDataAvailable" to mark the end of the AIFs Signed-off-by: Mahesh Rajashekhara Signed-off-by: James Bottomley --- drivers/scsi/aacraid/Makefile | 2 +- drivers/scsi/aacraid/aachba.c | 7 +- drivers/scsi/aacraid/aacraid.h | 106 ++++++- drivers/scsi/aacraid/commctrl.c | 3 +- drivers/scsi/aacraid/comminit.c | 58 +++- drivers/scsi/aacraid/commsup.c | 41 ++- drivers/scsi/aacraid/dpcsup.c | 85 +++++- drivers/scsi/aacraid/linit.c | 15 +- drivers/scsi/aacraid/nark.c | 3 +- drivers/scsi/aacraid/rkt.c | 3 +- drivers/scsi/aacraid/rx.c | 33 ++- drivers/scsi/aacraid/sa.c | 7 +- drivers/scsi/aacraid/src.c | 594 ++++++++++++++++++++++++++++++++++++++++ 13 files changed, 898 insertions(+), 59 deletions(-) create mode 100644 drivers/scsi/aacraid/src.c (limited to 'drivers') diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile index 92df4d6b6147..1bd9fd18f7f3 100644 --- a/drivers/scsi/aacraid/Makefile +++ b/drivers/scsi/aacraid/Makefile @@ -3,6 +3,6 @@ obj-$(CONFIG_SCSI_AACRAID) := aacraid.o aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ - dpcsup.o rx.o sa.o rkt.o nark.o + dpcsup.o rx.o sa.o rkt.o nark.o src.o ccflags-y := -Idrivers/scsi diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 7df2dd1d2c6f..118ce83a737c 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1486,7 +1487,9 @@ int aac_get_adapter_info(struct aac_dev* dev) dev->a_ops.adapter_write = aac_write_block; } dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; - if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { + if (dev->adapter_info.options & AAC_OPT_NEW_COMM_TYPE1) + dev->adapter_info.options |= AAC_OPT_NEW_COMM; + if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { /* * Worst case size that could cause sg overflow when * we break up SG elements that are larger than 64KB. diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 4dbcc055ac78..29ab00016b78 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -12,7 +12,7 @@ *----------------------------------------------------------------------------*/ #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 26400 +# define AAC_DRIVER_BUILD 28000 # define AAC_DRIVER_BRANCH "-ms" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -277,6 +277,16 @@ enum aac_queue_types { #define FsaNormal 1 +/* transport FIB header (PMC) */ +struct aac_fib_xporthdr { + u64 HostAddress; /* FIB host address w/o xport header */ + u32 Size; /* FIB size excluding xport header */ + u32 Handle; /* driver handle to reference the FIB */ + u64 Reserved[2]; +}; + +#define ALIGN32 32 + /* * Define the FIB. The FIB is the where all the requested data and * command information are put to the application on the FSA adapter. @@ -394,7 +404,9 @@ enum fib_xfer_state { AdapterMicroFib = (1<<17), BIOSFibPath = (1<<18), FastResponseCapable = (1<<19), - ApiFib = (1<<20) // Its an API Fib. + ApiFib = (1<<20), /* Its an API Fib */ + /* PMC NEW COMM: There is no more AIF data pending */ + NoMoreAifDataAvailable = (1<<21) }; /* @@ -404,6 +416,7 @@ enum fib_xfer_state { #define ADAPTER_INIT_STRUCT_REVISION 3 #define ADAPTER_INIT_STRUCT_REVISION_4 4 // rocket science +#define ADAPTER_INIT_STRUCT_REVISION_6 6 /* PMC src */ struct aac_init { @@ -428,9 +441,15 @@ struct aac_init #define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001 #define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010 #define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020 +#define INITFLAGS_NEW_COMM_TYPE1_SUPPORTED 0x00000041 __le32 MaxIoCommands; /* max outstanding commands */ __le32 MaxIoSize; /* largest I/O command */ __le32 MaxFibSize; /* largest FIB to adapter */ + /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */ + __le32 MaxNumAif; /* max number of aif */ + /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */ + __le32 HostRRQ_AddrLow; + __le32 HostRRQ_AddrHigh; /* Host RRQ (response queue) for SRC */ }; enum aac_log_level { @@ -685,7 +704,7 @@ struct rx_inbound { #define OutboundDoorbellReg MUnit.ODR struct rx_registers { - struct rx_mu_registers MUnit; /* 1300h - 1344h */ + struct rx_mu_registers MUnit; /* 1300h - 1347h */ __le32 reserved1[2]; /* 1348h - 134ch */ struct rx_inbound IndexRegs; }; @@ -703,7 +722,7 @@ struct rx_registers { #define rkt_inbound rx_inbound struct rkt_registers { - struct rkt_mu_registers MUnit; /* 1300h - 1344h */ + struct rkt_mu_registers MUnit; /* 1300h - 1347h */ __le32 reserved1[1006]; /* 1348h - 22fch */ struct rkt_inbound IndexRegs; /* 2300h - */ }; @@ -713,6 +732,44 @@ struct rkt_registers { #define rkt_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rkt->CSR)) #define rkt_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rkt->CSR)) +/* + * PMC SRC message unit registers + */ + +#define src_inbound rx_inbound + +struct src_mu_registers { + /* PCI*| Name */ + __le32 reserved0[8]; /* 00h | Reserved */ + __le32 IDR; /* 20h | Inbound Doorbell Register */ + __le32 IISR; /* 24h | Inbound Int. Status Register */ + __le32 reserved1[3]; /* 28h | Reserved */ + __le32 OIMR; /* 34h | Outbound Int. Mask Register */ + __le32 reserved2[25]; /* 38h | Reserved */ + __le32 ODR_R; /* 9ch | Outbound Doorbell Read */ + __le32 ODR_C; /* a0h | Outbound Doorbell Clear */ + __le32 reserved3[6]; /* a4h | Reserved */ + __le32 OMR; /* bch | Outbound Message Register */ + __le32 IQ_L; /* c0h | Inbound Queue (Low address) */ + __le32 IQ_H; /* c4h | Inbound Queue (High address) */ +}; + +struct src_registers { + struct src_mu_registers MUnit; /* 00h - c7h */ + __le32 reserved1[130790]; /* c8h - 7fc5fh */ + struct src_inbound IndexRegs; /* 7fc60h */ +}; + +#define src_readb(AEP, CSR) readb(&((AEP)->regs.src.bar0->CSR)) +#define src_readl(AEP, CSR) readl(&((AEP)->regs.src.bar0->CSR)) +#define src_writeb(AEP, CSR, value) writeb(value, \ + &((AEP)->regs.src.bar0->CSR)) +#define src_writel(AEP, CSR, value) writel(value, \ + &((AEP)->regs.src.bar0->CSR)) + +#define SRC_ODR_SHIFT 12 +#define SRC_IDR_SHIFT 9 + typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); struct aac_fib_context { @@ -879,6 +936,7 @@ struct aac_supplement_adapter_info #define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001) #define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002) #define AAC_OPTION_POWER_MANAGEMENT cpu_to_le32(0x00000004) +#define AAC_OPTION_DOORBELL_RESET cpu_to_le32(0x00004000) #define AAC_SIS_VERSION_V3 3 #define AAC_SIS_SLOT_UNKNOWN 0xFF @@ -940,6 +998,7 @@ struct aac_bus_info_response { #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO cpu_to_le32(1<<16) #define AAC_OPT_NEW_COMM cpu_to_le32(1<<17) #define AAC_OPT_NEW_COMM_64 cpu_to_le32(1<<18) +#define AAC_OPT_NEW_COMM_TYPE1 cpu_to_le32(1<<28) struct aac_dev { @@ -952,6 +1011,7 @@ struct aac_dev */ unsigned max_fib_size; unsigned sg_tablesize; + unsigned max_num_aif; /* * Map for 128 fib objects (64k) @@ -980,10 +1040,21 @@ struct aac_dev struct adapter_ops a_ops; unsigned long fsrev; /* Main driver's revision number */ - unsigned base_size; /* Size of mapped in region */ + unsigned long dbg_base; /* address of UART + * debug buffer */ + + unsigned base_size, dbg_size; /* Size of + * mapped in region */ + struct aac_init *init; /* Holds initialization info to communicate with adapter */ dma_addr_t init_pa; /* Holds physical address of the init struct */ + u32 *host_rrq; /* response queue + * if AAC_COMM_MESSAGE_TYPE1 */ + + dma_addr_t host_rrq_pa; /* phys. address */ + u32 host_rrq_idx; /* index into rrq buffer */ + struct pci_dev *pdev; /* Our PCI interface */ void * printfbuf; /* pointer to buffer used for printf's from the adapter */ void * comm_addr; /* Base address of Comm area */ @@ -1003,14 +1074,20 @@ struct aac_dev */ #ifndef AAC_MIN_FOOTPRINT_SIZE # define AAC_MIN_FOOTPRINT_SIZE 8192 +# define AAC_MIN_SRC_BAR0_SIZE 0x400000 +# define AAC_MIN_SRC_BAR1_SIZE 0x800 #endif union { struct sa_registers __iomem *sa; struct rx_registers __iomem *rx; struct rkt_registers __iomem *rkt; + struct { + struct src_registers __iomem *bar0; + char __iomem *bar1; + } src; } regs; - volatile void __iomem *base; + volatile void __iomem *base, *dbg_base_mapped; volatile struct rx_inbound __iomem *IndexRegs; u32 OIMR; /* Mask Register Cache */ /* @@ -1031,9 +1108,8 @@ struct aac_dev u8 comm_interface; # define AAC_COMM_PRODUCER 0 # define AAC_COMM_MESSAGE 1 - /* macro side-effects BEWARE */ -# define raw_io_interface \ - init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4) +# define AAC_COMM_MESSAGE_TYPE1 3 + u8 raw_io_interface; u8 raw_io_64; u8 printf_enabled; u8 in_reset; @@ -1789,6 +1865,10 @@ extern struct aac_common aac_config; #define DoorBellAdapterNormCmdNotFull (1<<3) /* Adapter -> Host */ #define DoorBellAdapterNormRespNotFull (1<<4) /* Adapter -> Host */ #define DoorBellPrintfReady (1<<5) /* Adapter -> Host */ +#define DoorBellAifPending (1<<6) /* Adapter -> Host */ + +/* PMC specific outbound doorbell bits */ +#define PmDoorBellResponseSent (1<<1) /* Adapter -> Host */ /* * For FIB communication, we need all of the following things @@ -1831,6 +1911,9 @@ extern struct aac_common aac_config; #define AifReqAPIJobUpdate 109 /* Update a job report from the API */ #define AifReqAPIJobFinish 110 /* Finish a job from the API */ +/* PMC NEW COMM: Request the event data */ +#define AifReqEvent 200 + /* * Adapter Initiated FIB command structures. Start with the adapter * initiated FIBs that really come from the adapter, and get responded @@ -1886,10 +1969,13 @@ int aac_rx_init(struct aac_dev *dev); int aac_rkt_init(struct aac_dev *dev); int aac_nark_init(struct aac_dev *dev); int aac_sa_init(struct aac_dev *dev); +int aac_src_init(struct aac_dev *dev); int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); unsigned int aac_response_normal(struct aac_queue * q); unsigned int aac_command_normal(struct aac_queue * q); -unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index); +unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, + int isAif, int isFastResponse, + struct hw_fib *aif_fib); int aac_reset_adapter(struct aac_dev * dev, int forced); int aac_check_health(struct aac_dev * dev); int aac_command_thread(void *data); diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 645ddd9d9b9e..8a0b33033177 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index a7261486ccd4..7ac8fdb5577b 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,12 +53,16 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co unsigned long size, align; const unsigned long fibsize = 4096; const unsigned long printfbufsiz = 256; + unsigned long host_rrq_size = 0; struct aac_init *init; dma_addr_t phys; unsigned long aac_max_hostphysmempages; - size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz; - + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) + host_rrq_size = (dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB) * sizeof(u32); + size = fibsize + sizeof(struct aac_init) + commsize + + commalign + printfbufsiz + host_rrq_size; base = pci_alloc_consistent(dev->pdev, size, &phys); @@ -70,8 +75,14 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co dev->comm_phys = phys; dev->comm_size = size; - dev->init = (struct aac_init *)(base + fibsize); - dev->init_pa = phys + fibsize; + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { + dev->host_rrq = (u32 *)(base + fibsize); + dev->host_rrq_pa = phys + fibsize; + memset(dev->host_rrq, 0, host_rrq_size); + } + + dev->init = (struct aac_init *)(base + fibsize + host_rrq_size); + dev->init_pa = phys + fibsize + host_rrq_size; init = dev->init; @@ -106,8 +117,13 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co init->InitFlags = 0; if (dev->comm_interface == AAC_COMM_MESSAGE) { - init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); + init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n")); + } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { + init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6); + init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_TYPE1_SUPPORTED); + dprintk((KERN_WARNING + "aacraid: New Comm Interface type1 enabled\n")); } init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME | INITFLAGS_DRIVER_SUPPORTS_PM); @@ -115,11 +131,18 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9); init->MaxFibSize = cpu_to_le32(dev->max_fib_size); + init->MaxNumAif = cpu_to_le32(dev->max_num_aif); + init->HostRRQ_AddrHigh = (u32)((u64)dev->host_rrq_pa >> 32); + init->HostRRQ_AddrLow = (u32)(dev->host_rrq_pa & 0xffffffff); + + /* * Increment the base address by the amount already used */ - base = base + fibsize + sizeof(struct aac_init); - phys = (dma_addr_t)((ulong)phys + fibsize + sizeof(struct aac_init)); + base = base + fibsize + host_rrq_size + sizeof(struct aac_init); + phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size + + sizeof(struct aac_init)); + /* * Align the beginning of Headers to commalign */ @@ -314,15 +337,22 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) - sizeof(struct aac_write) + sizeof(struct sgentry)) / sizeof(struct sgentry); dev->comm_interface = AAC_COMM_PRODUCER; - dev->raw_io_64 = 0; + dev->raw_io_interface = dev->raw_io_64 = 0; + if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) && (status[0] == 0x00000001)) { if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64)) dev->raw_io_64 = 1; - if (dev->a_ops.adapter_comm && - (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) - dev->comm_interface = AAC_COMM_MESSAGE; + if (dev->a_ops.adapter_comm) { + if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1)) { + dev->comm_interface = AAC_COMM_MESSAGE_TYPE1; + dev->raw_io_interface = 1; + } else if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)) { + dev->comm_interface = AAC_COMM_MESSAGE; + dev->raw_io_interface = 1; + } + } if ((dev->comm_interface == AAC_COMM_MESSAGE) && (status[2] > dev->base_size)) { aac_adapter_ioremap(dev, 0); @@ -350,10 +380,12 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) * status[3] & 0xFFFF maximum number FIBs outstanding */ host->max_sectors = (status[1] >> 16) << 1; - dev->max_fib_size = status[1] & 0xFFFF; + /* Multiple of 32 for PMC */ + dev->max_fib_size = status[1] & 0xFFE0; host->sg_tablesize = status[2] >> 16; dev->sg_tablesize = status[2] & 0xFFFF; host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB; + dev->max_num_aif = status[4] & 0xFFFF; /* * NOTE: * All these overrides are based on a fixed internal diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 060ac4bd5a14..dd7ad3ba2dad 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,9 +64,11 @@ static int fib_map_alloc(struct aac_dev *dev) "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n", dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue, AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); - if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, dev->max_fib_size - * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), - &dev->hw_fib_pa))==NULL) + dev->hw_fib_va = pci_alloc_consistent(dev->pdev, + (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) + * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1), + &dev->hw_fib_pa); + if (dev->hw_fib_va == NULL) return -ENOMEM; return 0; } @@ -110,9 +113,22 @@ int aac_fib_setup(struct aac_dev * dev) if (i<0) return -ENOMEM; + /* 32 byte alignment for PMC */ + hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1); + dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + + (hw_fib_pa - dev->hw_fib_pa)); + dev->hw_fib_pa = hw_fib_pa; + memset(dev->hw_fib_va, 0, + (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) * + (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); + + /* add Xport header */ + dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + + sizeof(struct aac_fib_xporthdr)); + dev->hw_fib_pa += sizeof(struct aac_fib_xporthdr); + hw_fib = dev->hw_fib_va; hw_fib_pa = dev->hw_fib_pa; - memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); /* * Initialise the fibs */ @@ -129,8 +145,10 @@ int aac_fib_setup(struct aac_dev * dev) hw_fib->header.XferState = cpu_to_le32(0xffffffff); hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); fibptr->hw_fib_pa = hw_fib_pa; - hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size); - hw_fib_pa = hw_fib_pa + dev->max_fib_size; + hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + + dev->max_fib_size + sizeof(struct aac_fib_xporthdr)); + hw_fib_pa = hw_fib_pa + + dev->max_fib_size + sizeof(struct aac_fib_xporthdr); } /* * Add the fib chain to the free list @@ -664,9 +682,14 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) unsigned long nointr = 0; unsigned long qflags; + if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { + kfree(hw_fib); + return 0; + } + if (hw_fib->header.XferState == 0) { if (dev->comm_interface == AAC_COMM_MESSAGE) - kfree (hw_fib); + kfree(hw_fib); return 0; } /* @@ -674,7 +697,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) */ if (hw_fib->header.StructType != FIB_MAGIC) { if (dev->comm_interface == AAC_COMM_MESSAGE) - kfree (hw_fib); + kfree(hw_fib); return -EINVAL; } /* diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index 9c7408fe8c7d..f0c66a80ad13 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -228,6 +229,48 @@ unsigned int aac_command_normal(struct aac_queue *q) return 0; } +/* + * + * aac_aif_callback + * @context: the context set in the fib - here it is scsi cmd + * @fibptr: pointer to the fib + * + * Handles the AIFs - new method (SRC) + * + */ + +static void aac_aif_callback(void *context, struct fib * fibptr) +{ + struct fib *fibctx; + struct aac_dev *dev; + struct aac_aifcmd *cmd; + int status; + + fibctx = (struct fib *)context; + BUG_ON(fibptr == NULL); + dev = fibptr->dev; + + if (fibptr->hw_fib_va->header.XferState & + cpu_to_le32(NoMoreAifDataAvailable)) { + aac_fib_complete(fibptr); + aac_fib_free(fibptr); + return; + } + + aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va); + + aac_fib_init(fibctx); + cmd = (struct aac_aifcmd *) fib_data(fibctx); + cmd->command = cpu_to_le32(AifReqEvent); + + status = aac_fib_send(AifRequest, + fibctx, + sizeof(struct hw_fib)-sizeof(struct aac_fibhdr), + FsaNormal, + 0, 1, + (fib_callback)aac_aif_callback, fibctx); +} + /** * aac_intr_normal - Handle command replies @@ -238,19 +281,17 @@ unsigned int aac_command_normal(struct aac_queue *q) * know there is a response on our normal priority queue. We will pull off * all QE there are and wake up all the waiters before exiting. */ - -unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) +unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, + int isAif, int isFastResponse, struct hw_fib *aif_fib) { unsigned long mflags; dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index)); - if ((index & 0x00000002L)) { + if (isAif == 1) { /* AIF - common */ struct hw_fib * hw_fib; struct fib * fib; struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue]; unsigned long flags; - if (index == 0xFFFFFFFEL) /* Special Case */ - return 0; /* Do nothing */ /* * Allocate a FIB. For non queued stuff we can just use * the stack so we are happy. We need a fib object in order to @@ -263,8 +304,13 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) kfree (fib); return 1; } - memcpy(hw_fib, (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) + - (index & ~0x00000002L)), sizeof(struct hw_fib)); + if (aif_fib != NULL) { + memcpy(hw_fib, aif_fib, sizeof(struct hw_fib)); + } else { + memcpy(hw_fib, + (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) + + index), sizeof(struct hw_fib)); + } INIT_LIST_HEAD(&fib->fiblink); fib->type = FSAFS_NTC_FIB_CONTEXT; fib->size = sizeof(struct fib); @@ -277,9 +323,26 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) wake_up_interruptible(&q->cmdready); spin_unlock_irqrestore(q->lock, flags); return 1; + } else if (isAif == 2) { /* AIF - new (SRC) */ + struct fib *fibctx; + struct aac_aifcmd *cmd; + + fibctx = aac_fib_alloc(dev); + if (!fibctx) + return 1; + aac_fib_init(fibctx); + + cmd = (struct aac_aifcmd *) fib_data(fibctx); + cmd->command = cpu_to_le32(AifReqEvent); + + return aac_fib_send(AifRequest, + fibctx, + sizeof(struct hw_fib)-sizeof(struct aac_fibhdr), + FsaNormal, + 0, 1, + (fib_callback)aac_aif_callback, fibctx); } else { - int fast = index & 0x01; - struct fib * fib = &dev->fibs[index >> 2]; + struct fib *fib = &dev->fibs[index]; struct hw_fib * hwfib = fib->hw_fib_va; /* @@ -298,7 +361,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) return 0; } - if (fast) { + if (isFastResponse) { /* * Doctor the fib */ diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 2c93d9496d62..4ff26521d75f 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -54,7 +55,7 @@ #include "aacraid.h" -#define AAC_DRIVER_VERSION "1.1-5" +#define AAC_DRIVER_VERSION "1.1-7" #ifndef AAC_DRIVER_BRANCH #define AAC_DRIVER_BRANCH "" #endif @@ -161,6 +162,7 @@ static const struct pci_device_id aac_pci_tbl[] __devinitdata = { { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */ { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */ { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */ + { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Catch All */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -235,7 +237,8 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */ { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ - { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */ + { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec NEMER/ARK Catch All */ + { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec PMC Catch All */ }; /** @@ -653,8 +656,10 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) * This adapter needs a blind reset, only do so for Adapters that * support a register, instead of a commanded, reset. */ - if ((aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_MU_RESET) && + if (((aac->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_MU_RESET) || + (aac->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_DOORBELL_RESET)) && aac_check_reset && ((aac_check_reset != 1) || !(aac->supplement_adapter_info.SupportedOptions2 & diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c index c55f7c862f0e..f397d21a0c06 100644 --- a/drivers/scsi/aacraid/nark.c +++ b/drivers/scsi/aacraid/nark.c @@ -4,7 +4,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2006-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index 16d8db550027..be44de92429a 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 84d77fd86e5b..ce530f113fdb 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -84,15 +85,35 @@ static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) static irqreturn_t aac_rx_intr_message(int irq, void *dev_id) { + int isAif, isFastResponse, isSpecial; struct aac_dev *dev = dev_id; u32 Index = rx_readl(dev, MUnit.OutboundQueue); if (unlikely(Index == 0xFFFFFFFFL)) Index = rx_readl(dev, MUnit.OutboundQueue); if (likely(Index != 0xFFFFFFFFL)) { do { - if (unlikely(aac_intr_normal(dev, Index))) { - rx_writel(dev, MUnit.OutboundQueue, Index); - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady); + isAif = isFastResponse = isSpecial = 0; + if (Index & 0x00000002L) { + isAif = 1; + if (Index == 0xFFFFFFFEL) + isSpecial = 1; + Index &= ~0x00000002L; + } else { + if (Index & 0x00000001L) + isFastResponse = 1; + Index >>= 2; + } + if (!isSpecial) { + if (unlikely(aac_intr_normal(dev, + Index, isAif, + isFastResponse, NULL))) { + rx_writel(dev, + MUnit.OutboundQueue, + Index); + rx_writel(dev, + MUnit.ODR, + DoorBellAdapterNormRespReady); + } } Index = rx_readl(dev, MUnit.OutboundQueue); } while (Index != 0xFFFFFFFFL); @@ -631,6 +652,10 @@ int _aac_rx_init(struct aac_dev *dev) name, instance); goto error_iounmap; } + dev->dbg_base = dev->scsi_host_ptr->base; + dev->dbg_base_mapped = dev->base; + dev->dbg_size = dev->base_size; + aac_adapter_enable_int(dev); /* * Tell the adapter that all is configured, and it can diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 622c21c68e65..e5d4457121ea 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -5,7 +5,8 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -391,6 +392,10 @@ int aac_sa_init(struct aac_dev *dev) name, instance); goto error_iounmap; } + dev->dbg_base = dev->scsi_host_ptr->base; + dev->dbg_base_mapped = dev->base; + dev->dbg_size = dev->base_size; + aac_adapter_enable_int(dev); /* diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c new file mode 100644 index 000000000000..c20494660603 --- /dev/null +++ b/drivers/scsi/aacraid/src.c @@ -0,0 +1,594 @@ +/* + * Adaptec AAC series RAID controller driver + * (c) Copyright 2001 Red Hat Inc. + * + * based on the old aacraid driver that is.. + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000-2010 Adaptec, Inc. + * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * src.c + * + * Abstract: Hardware Device Interface for PMC SRC based controllers + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aacraid.h" + +static irqreturn_t aac_src_intr_message(int irq, void *dev_id) +{ + struct aac_dev *dev = dev_id; + unsigned long bellbits, bellbits_shifted; + int our_interrupt = 0; + int isFastResponse; + u32 index, handle; + + bellbits = src_readl(dev, MUnit.ODR_R); + if (bellbits & PmDoorBellResponseSent) { + bellbits = PmDoorBellResponseSent; + /* handle async. status */ + our_interrupt = 1; + index = dev->host_rrq_idx; + if (dev->host_rrq[index] == 0) { + u32 old_index = index; + /* adjust index */ + do { + index++; + if (index == dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB) + index = 0; + if (dev->host_rrq[index] != 0) + break; + } while (index != old_index); + dev->host_rrq_idx = index; + } + for (;;) { + isFastResponse = 0; + /* remove toggle bit (31) */ + handle = (dev->host_rrq[index] & 0x7fffffff); + /* check fast response bit (30) */ + if (handle & 0x40000000) + isFastResponse = 1; + handle &= 0x0000ffff; + if (handle == 0) + break; + + aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL); + + dev->host_rrq[index++] = 0; + if (index == dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB) + index = 0; + dev->host_rrq_idx = index; + } + } else { + bellbits_shifted = (bellbits >> SRC_ODR_SHIFT); + if (bellbits_shifted & DoorBellAifPending) { + our_interrupt = 1; + /* handle AIF */ + aac_intr_normal(dev, 0, 2, 0, NULL); + } + } + + if (our_interrupt) { + src_writel(dev, MUnit.ODR_C, bellbits); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +/** + * aac_src_disable_interrupt - Disable interrupts + * @dev: Adapter + */ + +static void aac_src_disable_interrupt(struct aac_dev *dev) +{ + src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); +} + +/** + * aac_src_enable_interrupt_message - Enable interrupts + * @dev: Adapter + */ + +static void aac_src_enable_interrupt_message(struct aac_dev *dev) +{ + src_writel(dev, MUnit.OIMR, dev->OIMR = 0xfffffff8); +} + +/** + * src_sync_cmd - send a command and wait + * @dev: Adapter + * @command: Command to execute + * @p1: first parameter + * @ret: adapter status + * + * This routine will send a synchronous command to the adapter and wait + * for its completion. + */ + +static int src_sync_cmd(struct aac_dev *dev, u32 command, + u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, + u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) +{ + unsigned long start; + int ok; + + /* + * Write the command into Mailbox 0 + */ + writel(command, &dev->IndexRegs->Mailbox[0]); + /* + * Write the parameters into Mailboxes 1 - 6 + */ + writel(p1, &dev->IndexRegs->Mailbox[1]); + writel(p2, &dev->IndexRegs->Mailbox[2]); + writel(p3, &dev->IndexRegs->Mailbox[3]); + writel(p4, &dev->IndexRegs->Mailbox[4]); + + /* + * Clear the synch command doorbell to start on a clean slate. + */ + src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); + + /* + * Disable doorbell interrupts + */ + src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); + + /* + * Force the completion of the mask register write before issuing + * the interrupt. + */ + src_readl(dev, MUnit.OIMR); + + /* + * Signal that there is a new synch command + */ + src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); + + ok = 0; + start = jiffies; + + /* + * Wait up to 30 seconds + */ + while (time_before(jiffies, start+30*HZ)) { + /* Delay 5 microseconds to let Mon960 get info. */ + udelay(5); + + /* Mon960 will set doorbell0 bit + * when it has completed the command + */ + if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) { + /* Clear the doorbell */ + src_writel(dev, + MUnit.ODR_C, + OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); + ok = 1; + break; + } + + /* Yield the processor in case we are slow */ + msleep(1); + } + if (unlikely(ok != 1)) { + /* Restore interrupt mask even though we timed out */ + aac_adapter_enable_int(dev); + return -ETIMEDOUT; + } + + /* Pull the synch status from Mailbox 0 */ + if (status) + *status = readl(&dev->IndexRegs->Mailbox[0]); + if (r1) + *r1 = readl(&dev->IndexRegs->Mailbox[1]); + if (r2) + *r2 = readl(&dev->IndexRegs->Mailbox[2]); + if (r3) + *r3 = readl(&dev->IndexRegs->Mailbox[3]); + if (r4) + *r4 = readl(&dev->IndexRegs->Mailbox[4]); + + /* Clear the synch command doorbell */ + src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); + + /* Restore interrupt mask */ + aac_adapter_enable_int(dev); + return 0; + +} + +/** + * aac_src_interrupt_adapter - interrupt adapter + * @dev: Adapter + * + * Send an interrupt to the i960 and breakpoint it. + */ + +static void aac_src_interrupt_adapter(struct aac_dev *dev) +{ + src_sync_cmd(dev, BREAKPOINT_REQUEST, + 0, 0, 0, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL); +} + +/** + * aac_src_notify_adapter - send an event to the adapter + * @dev: Adapter + * @event: Event to send + * + * Notify the i960 that something it probably cares about has + * happened. + */ + +static void aac_src_notify_adapter(struct aac_dev *dev, u32 event) +{ + switch (event) { + + case AdapNormCmdQue: + src_writel(dev, MUnit.ODR_C, + INBOUNDDOORBELL_1 << SRC_ODR_SHIFT); + break; + case HostNormRespNotFull: + src_writel(dev, MUnit.ODR_C, + INBOUNDDOORBELL_4 << SRC_ODR_SHIFT); + break; + case AdapNormRespQue: + src_writel(dev, MUnit.ODR_C, + INBOUNDDOORBELL_2 << SRC_ODR_SHIFT); + break; + case HostNormCmdNotFull: + src_writel(dev, MUnit.ODR_C, + INBOUNDDOORBELL_3 << SRC_ODR_SHIFT); + break; + case FastIo: + src_writel(dev, MUnit.ODR_C, + INBOUNDDOORBELL_6 << SRC_ODR_SHIFT); + break; + case AdapPrintfDone: + src_writel(dev, MUnit.ODR_C, + INBOUNDDOORBELL_5 << SRC_ODR_SHIFT); + break; + default: + BUG(); + break; + } +} + +/** + * aac_src_start_adapter - activate adapter + * @dev: Adapter + * + * Start up processing on an i960 based AAC adapter + */ + +static void aac_src_start_adapter(struct aac_dev *dev) +{ + struct aac_init *init; + + init = dev->init; + init->HostElapsedSeconds = cpu_to_le32(get_seconds()); + + /* We can only use a 32 bit address here */ + src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, + 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); +} + +/** + * aac_src_check_health + * @dev: device to check if healthy + * + * Will attempt to determine if the specified adapter is alive and + * capable of handling requests, returning 0 if alive. + */ +static int aac_src_check_health(struct aac_dev *dev) +{ + u32 status = src_readl(dev, MUnit.OMR); + + /* + * Check to see if the board failed any self tests. + */ + if (unlikely(status & SELF_TEST_FAILED)) + return -1; + + /* + * Check to see if the board panic'd. + */ + if (unlikely(status & KERNEL_PANIC)) + return (status >> 16) & 0xFF; + /* + * Wait for the adapter to be up and running. + */ + if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) + return -3; + /* + * Everything is OK + */ + return 0; +} + +/** + * aac_src_deliver_message + * @fib: fib to issue + * + * Will send a fib, returning 0 if successful. + */ +static int aac_src_deliver_message(struct fib *fib) +{ + struct aac_dev *dev = fib->dev; + struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; + unsigned long qflags; + u32 fibsize; + u64 address; + struct aac_fib_xporthdr *pFibX; + + spin_lock_irqsave(q->lock, qflags); + q->numpending++; + spin_unlock_irqrestore(q->lock, qflags); + + /* Calculate the amount to the fibsize bits */ + fibsize = (sizeof(struct aac_fib_xporthdr) + + fib->hw_fib_va->header.Size + 127) / 128 - 1; + if (fibsize > (ALIGN32 - 1)) + fibsize = ALIGN32 - 1; + + /* Fill XPORT header */ + pFibX = (struct aac_fib_xporthdr *) + ((unsigned char *)fib->hw_fib_va - + sizeof(struct aac_fib_xporthdr)); + pFibX->Handle = fib->hw_fib_va->header.SenderData + 1; + pFibX->HostAddress = fib->hw_fib_pa; + pFibX->Size = fib->hw_fib_va->header.Size; + address = fib->hw_fib_pa - (u64)sizeof(struct aac_fib_xporthdr); + + src_writel(dev, MUnit.IQ_H, (u32)(address >> 32)); + src_writel(dev, MUnit.IQ_L, (u32)(address & 0xffffffff) + fibsize); + return 0; +} + +/** + * aac_src_ioremap + * @size: mapping resize request + * + */ +static int aac_src_ioremap(struct aac_dev *dev, u32 size) +{ + if (!size) { + iounmap(dev->regs.src.bar0); + dev->regs.src.bar0 = NULL; + iounmap(dev->base); + dev->base = NULL; + return 0; + } + dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2), + AAC_MIN_SRC_BAR1_SIZE); + dev->base = NULL; + if (dev->regs.src.bar1 == NULL) + return -1; + dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, + size); + if (dev->base == NULL) { + iounmap(dev->regs.src.bar1); + dev->regs.src.bar1 = NULL; + return -1; + } + dev->IndexRegs = &((struct src_registers __iomem *) + dev->base)->IndexRegs; + return 0; +} + +static int aac_src_restart_adapter(struct aac_dev *dev, int bled) +{ + u32 var, reset_mask; + + if (bled >= 0) { + if (bled) + printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", + dev->name, dev->id, bled); + bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, + 0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL); + if (bled || (var != 0x00000001)) + bled = -EINVAL; + if (dev->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_DOORBELL_RESET) { + src_writel(dev, MUnit.IDR, reset_mask); + msleep(5000); /* Delay 5 seconds */ + } + } + + if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC) + return -ENODEV; + + if (startup_timeout < 300) + startup_timeout = 300; + + return 0; +} + +/** + * aac_src_select_comm - Select communications method + * @dev: Adapter + * @comm: communications method + */ +int aac_src_select_comm(struct aac_dev *dev, int comm) +{ + switch (comm) { + case AAC_COMM_MESSAGE: + dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; + dev->a_ops.adapter_intr = aac_src_intr_message; + dev->a_ops.adapter_deliver = aac_src_deliver_message; + break; + default: + return 1; + } + return 0; +} + +/** + * aac_src_init - initialize an Cardinal Frey Bar card + * @dev: device to configure + * + */ + +int aac_src_init(struct aac_dev *dev) +{ + unsigned long start; + unsigned long status; + int restart = 0; + int instance = dev->id; + const char *name = dev->name; + + dev->a_ops.adapter_ioremap = aac_src_ioremap; + dev->a_ops.adapter_comm = aac_src_select_comm; + + dev->base_size = AAC_MIN_SRC_BAR0_SIZE; + if (aac_adapter_ioremap(dev, dev->base_size)) { + printk(KERN_WARNING "%s: unable to map adapter.\n", name); + goto error_iounmap; + } + + /* Failure to reset here is an option ... */ + dev->a_ops.adapter_sync_cmd = src_sync_cmd; + dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; + if ((aac_reset_devices || reset_devices) && + !aac_src_restart_adapter(dev, 0)) + ++restart; + /* + * Check to see if the board panic'd while booting. + */ + status = src_readl(dev, MUnit.OMR); + if (status & KERNEL_PANIC) { + if (aac_src_restart_adapter(dev, aac_src_check_health(dev))) + goto error_iounmap; + ++restart; + } + /* + * Check to see if the board failed any self tests. + */ + status = src_readl(dev, MUnit.OMR); + if (status & SELF_TEST_FAILED) { + printk(KERN_ERR "%s%d: adapter self-test failed.\n", + dev->name, instance); + goto error_iounmap; + } + /* + * Check to see if the monitor panic'd while booting. + */ + if (status & MONITOR_PANIC) { + printk(KERN_ERR "%s%d: adapter monitor panic.\n", + dev->name, instance); + goto error_iounmap; + } + start = jiffies; + /* + * Wait for the adapter to be up and running. Wait up to 3 minutes + */ + while (!((status = src_readl(dev, MUnit.OMR)) & + KERNEL_UP_AND_RUNNING)) { + if ((restart && + (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || + time_after(jiffies, start+HZ*startup_timeout)) { + printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", + dev->name, instance, status); + goto error_iounmap; + } + if (!restart && + ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || + time_after(jiffies, start + HZ * + ((startup_timeout > 60) + ? (startup_timeout - 60) + : (startup_timeout / 2))))) { + if (likely(!aac_src_restart_adapter(dev, + aac_src_check_health(dev)))) + start = jiffies; + ++restart; + } + msleep(1); + } + if (restart && aac_commit) + aac_commit = 1; + /* + * Fill in the common function dispatch table. + */ + dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; + dev->a_ops.adapter_notify = aac_src_notify_adapter; + dev->a_ops.adapter_sync_cmd = src_sync_cmd; + dev->a_ops.adapter_check_health = aac_src_check_health; + dev->a_ops.adapter_restart = aac_src_restart_adapter; + + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + aac_adapter_comm(dev, AAC_COMM_MESSAGE); + aac_adapter_disable_int(dev); + src_writel(dev, MUnit.ODR_C, 0xffffffff); + aac_adapter_enable_int(dev); + + if (aac_init_adapter(dev) == NULL) + goto error_iounmap; + if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) + goto error_iounmap; + + dev->msi = aac_msi && !pci_enable_msi(dev->pdev); + + if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, + IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { + + if (dev->msi) + pci_disable_msi(dev->pdev); + + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", + name, instance); + goto error_iounmap; + } + dev->dbg_base = pci_resource_start(dev->pdev, 2); + dev->dbg_base_mapped = dev->regs.src.bar1; + dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE; + + aac_adapter_enable_int(dev); + /* + * Tell the adapter that all is configured, and it can + * start accepting requests + */ + aac_src_start_adapter(dev); + + return 0; + +error_iounmap: + + return -1; +} -- cgit v1.2.2 From 70c7c88a1a65ca683eb7f3fe3ce79c72f29d845e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 17 Mar 2011 16:22:17 -0500 Subject: [SCSI] libiscsi_tcp: use kmap in xmit path The xmit path can sleep with a page kmapped in the network xmit code while it waits for space to open up, so we have to use kmap instead of kmap atomic in that path. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi_tcp.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 8eeb39ffa37f..e98ae33f1295 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -132,14 +132,25 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) if (page_count(sg_page(sg)) >= 1 && !recv) return; - segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + if (recv) { + segment->atomic_mapped = true; + segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + } else { + segment->atomic_mapped = false; + /* the xmit path can sleep with the page mapped so use kmap */ + segment->sg_mapped = kmap(sg_page(sg)); + } + segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; } void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) { if (segment->sg_mapped) { - kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); + if (segment->atomic_mapped) + kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); + else + kunmap(sg_page(segment->sg)); segment->sg_mapped = NULL; segment->data = NULL; } -- cgit v1.2.2 From 839900c69d5b8a07a4df8e9bd9d1e59a5c556811 Mon Sep 17 00:00:00 2001 From: Bhanu Gollapudi Date: Thu, 17 Mar 2011 17:13:26 -0700 Subject: [SCSI] bnx2fc: Avoid holding cq_lock when iounmap() is called With kernel debugging enabled, holding cq_lock when calling bnx2fc_free_session_resc() which calls iounmap() leads to a warning stack trace [INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected]. iounmap() grabs a HARDIRQ-unsafe vmlist lock, so holding spin_lock_bh(cq_lock) when calling iounmap() will trigger the LOCKDEP warning. Since cq_lock is required only to guard against deletion, hold the lock just before freeing the cq. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc_tgt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index 7ea93af60260..7cc05e4e82d5 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -304,10 +304,8 @@ static void bnx2fc_upload_session(struct fcoe_port *port, " not sent to FW\n"); /* Free session resources */ - spin_lock_bh(&tgt->cq_lock); bnx2fc_free_session_resc(hba, tgt); bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); - spin_unlock_bh(&tgt->cq_lock); } static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt, @@ -830,11 +828,13 @@ static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, tgt->rq = NULL; } /* Free CQ */ + spin_lock_bh(&tgt->cq_lock); if (tgt->cq) { dma_free_coherent(&hba->pcidev->dev, tgt->cq_mem_size, tgt->cq, tgt->cq_dma); tgt->cq = NULL; } + spin_unlock_bh(&tgt->cq_lock); /* Free SQ */ if (tgt->sq) { dma_free_coherent(&hba->pcidev->dev, tgt->sq_mem_size, -- cgit v1.2.2 From 6702ca1dffbc864497b6f2c68543aad9bbf0bcee Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Thu, 17 Mar 2011 17:13:27 -0700 Subject: [SCSI] bnx2fc: Remove rtnl_trylock/restart_syscall checks Call rtnl_lock instead of rtnl_trylock & restart_syscall. This is bnx2fc counterpart of fcoe fixes, here is the reference: https://lists.open-fcoe.org/pipermail/devel/2011-March/011199.html Signed-off-by: Nithin Nayak Sujir Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index e476e8753079..13271a43cd35 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1432,8 +1432,7 @@ static int bnx2fc_destroy(struct net_device *netdev) struct net_device *phys_dev; int rc = 0; - if (!rtnl_trylock()) - return restart_syscall(); + rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); #ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE @@ -1805,10 +1804,7 @@ static int bnx2fc_disable(struct net_device *netdev) struct ethtool_drvinfo drvinfo; int rc = 0; - if (!rtnl_trylock()) { - printk(KERN_ERR PFX "retrying for rtnl_lock\n"); - return -EIO; - } + rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); @@ -1867,10 +1863,7 @@ static int bnx2fc_enable(struct net_device *netdev) struct ethtool_drvinfo drvinfo; int rc = 0; - if (!rtnl_trylock()) { - printk(KERN_ERR PFX "retrying for rtnl_lock\n"); - return -EIO; - } + rtnl_lock(); BNX2FC_MISC_DBG("Entered %s\n", __func__); mutex_lock(&bnx2fc_dev_lock); @@ -1942,10 +1935,8 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) return -EIO; } - if (!rtnl_trylock()) { - printk(KERN_ERR "trying for rtnl_lock\n"); - return -EIO; - } + rtnl_lock(); + mutex_lock(&bnx2fc_dev_lock); #ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE -- cgit v1.2.2 From 0ea5c27583e1cc164bba7ca29fe48a225f52d19b Mon Sep 17 00:00:00 2001 From: Bhanu Gollapudi Date: Thu, 17 Mar 2011 17:13:29 -0700 Subject: [SCSI] bnx2fc: common free list for cleanup commands Cleanup commands are issued to the firmware to cleanup any stuck ios that are supposed to be implicitly aborted. In the worst case we can have all scsi ios filling up the free_list and we may not be able to allocate cleanup tasks. So the driver has to reserve free_list entries to be able to allocate the cleanup tasks. This reserve free_list common to all cpus is allocated as one additional entry in the per cpu free_lists. In bnx2fc_cmd_alloc(), there is a related fix to use get_cpu() for the free_list_index. This will prevent using the wrong index if the CPU is preempted. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc.h | 15 ++++---- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 2 +- drivers/scsi/bnx2fc/bnx2fc_io.c | 73 +++++++++++++++++++++++++-------------- 3 files changed, 58 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index df2fc09ba479..464d71ea31aa 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -84,7 +84,9 @@ #define BNX2FC_NUM_MAX_SESS 128 #define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS)) -#define BNX2FC_MAX_OUTSTANDING_CMNDS 4096 +#define BNX2FC_MAX_OUTSTANDING_CMNDS 2048 +#define BNX2FC_CAN_QUEUE BNX2FC_MAX_OUTSTANDING_CMNDS +#define BNX2FC_ELSTM_XIDS BNX2FC_CAN_QUEUE #define BNX2FC_MIN_PAYLOAD 256 #define BNX2FC_MAX_PAYLOAD 2048 @@ -98,7 +100,8 @@ #define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe)) #define BNX2FC_5771X_DB_PAGE_SIZE 128 -#define BNX2FC_MAX_TASKS BNX2FC_MAX_OUTSTANDING_CMNDS +#define BNX2FC_MAX_TASKS \ + (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS) #define BNX2FC_TASK_SIZE 128 #define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE) #define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE) @@ -112,10 +115,10 @@ #define BNX2FC_WRITE (1 << 0) #define BNX2FC_MIN_XID 0 -#define BNX2FC_MAX_XID (BNX2FC_MAX_OUTSTANDING_CMNDS - 1) -#define FCOE_MIN_XID (BNX2FC_MAX_OUTSTANDING_CMNDS) -#define FCOE_MAX_XID \ - (BNX2FC_MAX_OUTSTANDING_CMNDS + (nr_cpu_ids * 256)) +#define BNX2FC_MAX_XID \ + (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1) +#define FCOE_MIN_XID (BNX2FC_MAX_XID + 1) +#define FCOE_MAX_XID (FCOE_MIN_XID + 4095) #define BNX2FC_MAX_LUN 0xFFFF #define BNX2FC_MAX_FCP_TGT 256 #define BNX2FC_MAX_CMD_LEN 16 diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 13271a43cd35..90cd632eed91 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -2497,7 +2497,7 @@ static struct scsi_host_template bnx2fc_shost_template = { .change_queue_type = fc_change_queue_type, .this_id = -1, .cmd_per_lun = 3, - .can_queue = (BNX2FC_MAX_OUTSTANDING_CMNDS/2), + .can_queue = BNX2FC_CAN_QUEUE, .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, .max_sectors = 512, diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 0f1dd23730db..d3fc302c241a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -11,6 +11,9 @@ */ #include "bnx2fc.h" + +#define RESERVE_FREE_LIST_INDEX num_possible_cpus() + static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, int bd_index); static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req); @@ -242,8 +245,9 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, u32 mem_size; u16 xid; int i; - int num_ios; + int num_ios, num_pri_ios; size_t bd_tbl_sz; + int arr_sz = num_possible_cpus() + 1; if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \ @@ -263,14 +267,14 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, } cmgr->free_list = kzalloc(sizeof(*cmgr->free_list) * - num_possible_cpus(), GFP_KERNEL); + arr_sz, GFP_KERNEL); if (!cmgr->free_list) { printk(KERN_ERR PFX "failed to alloc free_list\n"); goto mem_err; } cmgr->free_list_lock = kzalloc(sizeof(*cmgr->free_list_lock) * - num_possible_cpus(), GFP_KERNEL); + arr_sz, GFP_KERNEL); if (!cmgr->free_list_lock) { printk(KERN_ERR PFX "failed to alloc free_list_lock\n"); goto mem_err; @@ -279,13 +283,18 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, cmgr->hba = hba; cmgr->cmds = (struct bnx2fc_cmd **)(cmgr + 1); - for (i = 0; i < num_possible_cpus(); i++) { + for (i = 0; i < arr_sz; i++) { INIT_LIST_HEAD(&cmgr->free_list[i]); spin_lock_init(&cmgr->free_list_lock[i]); } - /* Pre-allocated pool of bnx2fc_cmds */ + /* + * Pre-allocated pool of bnx2fc_cmds. + * Last entry in the free list array is the free list + * of slow path requests. + */ xid = BNX2FC_MIN_XID; + num_pri_ios = num_ios - BNX2FC_ELSTM_XIDS; for (i = 0; i < num_ios; i++) { io_req = kzalloc(sizeof(*io_req), GFP_KERNEL); @@ -298,11 +307,13 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, INIT_DELAYED_WORK(&io_req->timeout_work, bnx2fc_cmd_timeout); io_req->xid = xid++; - if (io_req->xid >= BNX2FC_MAX_OUTSTANDING_CMNDS) - printk(KERN_ERR PFX "ERROR allocating xids - 0x%x\n", - io_req->xid); - list_add_tail(&io_req->link, - &cmgr->free_list[io_req->xid % num_possible_cpus()]); + if (i < num_pri_ios) + list_add_tail(&io_req->link, + &cmgr->free_list[io_req->xid % + num_possible_cpus()]); + else + list_add_tail(&io_req->link, + &cmgr->free_list[num_possible_cpus()]); io_req++; } @@ -389,7 +400,7 @@ free_cmd_pool: if (!cmgr->free_list) goto free_cmgr; - for (i = 0; i < num_possible_cpus(); i++) { + for (i = 0; i < num_possible_cpus() + 1; i++) { struct list_head *list; struct list_head *tmp; @@ -413,6 +424,7 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) struct bnx2fc_cmd *io_req; struct list_head *listp; struct io_bdt *bd_tbl; + int index = RESERVE_FREE_LIST_INDEX; u32 max_sqes; u16 xid; @@ -432,26 +444,26 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) * NOTE: Free list insertions and deletions are protected with * cmgr lock */ - spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); - if ((list_empty(&(cmd_mgr->free_list[smp_processor_id()]))) || + spin_lock_bh(&cmd_mgr->free_list_lock[index]); + if ((list_empty(&(cmd_mgr->free_list[index]))) || (tgt->num_active_ios.counter >= max_sqes)) { BNX2FC_TGT_DBG(tgt, "No free els_tm cmds available " "ios(%d):sqes(%d)\n", tgt->num_active_ios.counter, tgt->max_sqes); - if (list_empty(&(cmd_mgr->free_list[smp_processor_id()]))) + if (list_empty(&(cmd_mgr->free_list[index]))) printk(KERN_ERR PFX "elstm_alloc: list_empty\n"); - spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); + spin_unlock_bh(&cmd_mgr->free_list_lock[index]); return NULL; } listp = (struct list_head *) - cmd_mgr->free_list[smp_processor_id()].next; + cmd_mgr->free_list[index].next; list_del_init(listp); io_req = (struct bnx2fc_cmd *) listp; xid = io_req->xid; cmd_mgr->cmds[xid] = io_req; atomic_inc(&tgt->num_active_ios); - spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); + spin_unlock_bh(&cmd_mgr->free_list_lock[index]); INIT_LIST_HEAD(&io_req->link); @@ -479,27 +491,30 @@ static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) struct io_bdt *bd_tbl; u32 max_sqes; u16 xid; + int index = get_cpu(); max_sqes = BNX2FC_SCSI_MAX_SQES; /* * NOTE: Free list insertions and deletions are protected with * cmgr lock */ - spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); - if ((list_empty(&cmd_mgr->free_list[smp_processor_id()])) || + spin_lock_bh(&cmd_mgr->free_list_lock[index]); + if ((list_empty(&cmd_mgr->free_list[index])) || (tgt->num_active_ios.counter >= max_sqes)) { - spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); + spin_unlock_bh(&cmd_mgr->free_list_lock[index]); + put_cpu(); return NULL; } listp = (struct list_head *) - cmd_mgr->free_list[smp_processor_id()].next; + cmd_mgr->free_list[index].next; list_del_init(listp); io_req = (struct bnx2fc_cmd *) listp; xid = io_req->xid; cmd_mgr->cmds[xid] = io_req; atomic_inc(&tgt->num_active_ios); - spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); + spin_unlock_bh(&cmd_mgr->free_list_lock[index]); + put_cpu(); INIT_LIST_HEAD(&io_req->link); @@ -522,8 +537,15 @@ void bnx2fc_cmd_release(struct kref *ref) struct bnx2fc_cmd *io_req = container_of(ref, struct bnx2fc_cmd, refcount); struct bnx2fc_cmd_mgr *cmd_mgr = io_req->cmd_mgr; + int index; + + if (io_req->cmd_type == BNX2FC_SCSI_CMD) + index = io_req->xid % num_possible_cpus(); + else + index = RESERVE_FREE_LIST_INDEX; - spin_lock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); + + spin_lock_bh(&cmd_mgr->free_list_lock[index]); if (io_req->cmd_type != BNX2FC_SCSI_CMD) bnx2fc_free_mp_resc(io_req); cmd_mgr->cmds[io_req->xid] = NULL; @@ -531,9 +553,10 @@ void bnx2fc_cmd_release(struct kref *ref) list_del_init(&io_req->link); /* Add it to the free list */ list_add(&io_req->link, - &cmd_mgr->free_list[smp_processor_id()]); + &cmd_mgr->free_list[index]); atomic_dec(&io_req->tgt->num_active_ios); - spin_unlock_bh(&cmd_mgr->free_list_lock[smp_processor_id()]); + spin_unlock_bh(&cmd_mgr->free_list_lock[index]); + } static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req) -- cgit v1.2.2 From 686959736a8543265930c8d777a73b052bc57f87 Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Thu, 17 Mar 2011 17:13:31 -0700 Subject: [SCSI] bnx2fc: Call bnx2fc_return_rqe and bnx2fc_get_next_rqe with tgt lock held tgt lock is needed during - bnx2fc_return_rqe to protect the rq_prod_idx. bnx2fc_get_next_rqe to protect rq_cons_idx Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc_hwi.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 4f4096836742..3de1ce73bdd3 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -590,7 +590,10 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) num_rq = (frame_len + BNX2FC_RQ_BUF_SZ - 1) / BNX2FC_RQ_BUF_SZ; + spin_lock_bh(&tgt->tgt_lock); rq_data = (unsigned char *)bnx2fc_get_next_rqe(tgt, num_rq); + spin_unlock_bh(&tgt->tgt_lock); + if (rq_data) { buf = rq_data; } else { @@ -603,8 +606,10 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) } for (i = 0; i < num_rq; i++) { + spin_lock_bh(&tgt->tgt_lock); rq_data = (unsigned char *) bnx2fc_get_next_rqe(tgt, 1); + spin_unlock_bh(&tgt->tgt_lock); len = BNX2FC_RQ_BUF_SZ; memcpy(buf1, rq_data, len); buf1 += len; @@ -615,13 +620,15 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) if (buf != rq_data) kfree(buf); + spin_lock_bh(&tgt->tgt_lock); bnx2fc_return_rqe(tgt, num_rq); + spin_unlock_bh(&tgt->tgt_lock); break; case FCOE_ERROR_DETECTION_CQE_TYPE: /* - *In case of error reporting CQE a single RQ entry - * is consumes. + * In case of error reporting CQE a single RQ entry + * is consumed. */ spin_lock_bh(&tgt->tgt_lock); num_rq = 1; @@ -705,6 +712,7 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) *In case of warning reporting CQE a single RQ entry * is consumes. */ + spin_lock_bh(&tgt->tgt_lock); num_rq = 1; err_entry = (struct fcoe_err_report_entry *) bnx2fc_get_next_rqe(tgt, 1); @@ -717,6 +725,7 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) err_entry->tx_buf_off, err_entry->rx_buf_off); bnx2fc_return_rqe(tgt, 1); + spin_unlock_bh(&tgt->tgt_lock); break; default: -- cgit v1.2.2 From 26ce67c3df46a8253e3bbf3eb87cc6782f6a6c91 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 17 Mar 2011 17:13:32 -0700 Subject: [SCSI] bnx2fc: Remove network bonding checking bnx2fc only operates on bnx2x hardware devices and not master bonding devices, so there is no need to check for bonding. Even if the bnx2x device is "enslaved" into a bonding device, FCoE is unaffected as it has its own MAC address and queues. Signed-off-by: Michael Chan Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 90cd632eed91..0eec4e092554 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1095,13 +1095,6 @@ static int bnx2fc_netdev_setup(struct bnx2fc_hba *hba) struct netdev_hw_addr *ha; int sel_san_mac = 0; - /* Do not support for bonding device */ - if ((netdev->priv_flags & IFF_MASTER_ALB) || - (netdev->priv_flags & IFF_SLAVE_INACTIVE) || - (netdev->priv_flags & IFF_MASTER_8023AD)) { - return -EOPNOTSUPP; - } - /* setup Source MAC Address */ rcu_read_lock(); for_each_dev_addr(physdev, ha) { -- cgit v1.2.2 From 1294bfe60960c89a0c875cffb90c3bacf1d675d2 Mon Sep 17 00:00:00 2001 From: Bhanu Gollapudi Date: Thu, 17 Mar 2011 17:13:34 -0700 Subject: [SCSI] bnx2fc: Fix MTU issue by using static MTU bnx2x now uses seperate MTUs for networking and FCoE. FCoE MTU is fixed to 2500 and bnx2fc now needs to match this logic by using FCOE_MTU instead of netdev->mtu. Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc.h | 5 ++++- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 35 +---------------------------------- drivers/scsi/bnx2fc/bnx2fc_hwi.c | 2 +- 3 files changed, 6 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 464d71ea31aa..d869a4ce7eac 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -89,6 +89,10 @@ #define BNX2FC_ELSTM_XIDS BNX2FC_CAN_QUEUE #define BNX2FC_MIN_PAYLOAD 256 #define BNX2FC_MAX_PAYLOAD 2048 +#define BNX2FC_MFS \ + (BNX2FC_MAX_PAYLOAD + sizeof(struct fc_frame_header)) +#define BNX2FC_MINI_JUMBO_MTU 2500 + #define BNX2FC_RQ_BUF_SZ 256 #define BNX2FC_RQ_BUF_LOG_SZ (ilog2(BNX2FC_RQ_BUF_SZ)) @@ -128,7 +132,6 @@ #define BNX2FC_WAIT_CNT 120 #define BNX2FC_FW_TIMEOUT (3 * HZ) - #define PORT_MAX 2 #define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 0eec4e092554..aab55e24cb7b 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -661,31 +661,6 @@ static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev) return 0; } -static int bnx2fc_mfs_update(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_hba *hba = port->priv; - struct net_device *netdev = hba->netdev; - u32 mfs; - u32 max_mfs; - - mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + - sizeof(struct fcoe_crc_eof)); - max_mfs = BNX2FC_MAX_PAYLOAD + sizeof(struct fc_frame_header); - BNX2FC_HBA_DBG(lport, "mfs = %d, max_mfs = %d\n", mfs, max_mfs); - if (mfs > max_mfs) - mfs = max_mfs; - - /* Adjust mfs to be a multiple of 256 bytes */ - mfs = (((mfs - sizeof(struct fc_frame_header)) / BNX2FC_MIN_PAYLOAD) * - BNX2FC_MIN_PAYLOAD); - mfs = mfs + sizeof(struct fc_frame_header); - - BNX2FC_HBA_DBG(lport, "Set MFS = %d\n", mfs); - if (fc_set_mfs(lport, mfs)) - return -EINVAL; - return 0; -} static void bnx2fc_link_speed_update(struct fc_lport *lport) { struct fcoe_port *port = lport_priv(lport); @@ -754,7 +729,7 @@ static int bnx2fc_net_config(struct fc_lport *lport) !hba->phys_dev->ethtool_ops->get_pauseparam) return -EOPNOTSUPP; - if (bnx2fc_mfs_update(lport)) + if (fc_set_mfs(lport, BNX2FC_MFS)) return -EINVAL; skb_queue_head_init(&port->fcoe_pending_queue); @@ -825,14 +800,6 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event) if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) printk(KERN_ERR "indicate_netevent: "\ "adapter is not UP!!\n"); - /* fall thru to update mfs if MTU has changed */ - case NETDEV_CHANGEMTU: - BNX2FC_HBA_DBG(lport, "NETDEV_CHANGEMTU event\n"); - bnx2fc_mfs_update(lport); - mutex_lock(&lport->lp_mutex); - list_for_each_entry(vport, &lport->vports, list) - bnx2fc_mfs_update(vport); - mutex_unlock(&lport->lp_mutex); break; case NETDEV_DOWN: diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 3de1ce73bdd3..1b680e288c56 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -87,7 +87,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba) fcoe_init1.task_list_pbl_addr_lo = (u32) hba->task_ctx_bd_dma; fcoe_init1.task_list_pbl_addr_hi = (u32) ((u64) hba->task_ctx_bd_dma >> 32); - fcoe_init1.mtu = hba->netdev->mtu; + fcoe_init1.mtu = BNX2FC_MINI_JUMBO_MTU; fcoe_init1.flags = (PAGE_SHIFT << FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT); -- cgit v1.2.2 From c94460fd29a9893eb677d2e0831a247a185c7a22 Mon Sep 17 00:00:00 2001 From: Bhanu Gollapudi Date: Thu, 17 Mar 2011 17:13:35 -0700 Subject: [SCSI] bnx2fc: Remove unnecessary module state checks The check for module state MODULE_STATE_LIVE is no longer required for LLDs, as libfcoe transport takes care of it. Reference: http://marc.info/?l=linux-scsi&m=129989565903046&w=2 Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index aab55e24cb7b..38a00fe10bd7 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1395,12 +1395,6 @@ static int bnx2fc_destroy(struct net_device *netdev) rtnl_lock(); mutex_lock(&bnx2fc_dev_lock); -#ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto netdev_err; - } -#endif /* obtain physical netdev */ if (netdev->priv_flags & IFF_802_1Q_VLAN) phys_dev = vlan_dev_real_dev(netdev); @@ -1768,11 +1762,6 @@ static int bnx2fc_disable(struct net_device *netdev) mutex_lock(&bnx2fc_dev_lock); - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto nodev; - } - /* obtain physical netdev */ if (netdev->priv_flags & IFF_802_1Q_VLAN) phys_dev = vlan_dev_real_dev(netdev); @@ -1828,11 +1817,6 @@ static int bnx2fc_enable(struct net_device *netdev) BNX2FC_MISC_DBG("Entered %s\n", __func__); mutex_lock(&bnx2fc_dev_lock); - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto nodev; - } - /* obtain physical netdev */ if (netdev->priv_flags & IFF_802_1Q_VLAN) phys_dev = vlan_dev_real_dev(netdev); @@ -1899,13 +1883,6 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) mutex_lock(&bnx2fc_dev_lock); -#ifdef CONFIG_SCSI_BNX2X_FCOE_MODULE - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto mod_err; - } -#endif - if (!try_module_get(THIS_MODULE)) { rc = -EINVAL; goto mod_err; -- cgit v1.2.2 From d9f7f37b90e7b0180961cb6567ae423ac3757db8 Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Thu, 17 Mar 2011 17:13:37 -0700 Subject: [SCSI] bnx2fc: Bump version to 1.0.1 Signed-off-by: Nithin Nayak Sujir Signed-off-by: Michael Chan Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc.h | 2 +- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index d869a4ce7eac..b6d350ac4288 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -62,7 +62,7 @@ #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "1.0.0" +#define BNX2FC_VERSION "1.0.1" #define PFX "bnx2fc: " diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 38a00fe10bd7..2056890b437a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -21,7 +21,7 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); #define DRV_MODULE_NAME "bnx2fc" #define DRV_MODULE_VERSION BNX2FC_VERSION -#define DRV_MODULE_RELDATE "Jan 25, 2011" +#define DRV_MODULE_RELDATE "Mar 17, 2011" static char version[] __devinitdata = -- cgit v1.2.2 From 8c3adc796f32fa4878ec843f8960717ba377e024 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 18 Mar 2011 11:24:23 -0400 Subject: [SCSI] ses: add subenclosure support There have been many complaints that an enclosure with subenclosures isn't attached to by the ses driver. Until now, though, no-one had been willing to provide access to one. Subenclosures are added simply by flattening the tree (i.e. all subenclosure devices show up under the one main device). This may have consequences if the naming is only unique per subenclosure, but that's a bug for another day. The tested array had no page 7, so no device naming at all. It also only had the disk devices on one of its subenclosures (all the others had power, fans, temperature and various sensors), so testing of this is fairly rudimentary. Signed-off-by: James Bottomley --- drivers/scsi/ses.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 3b00e907b917..eb7a3e85304f 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -35,9 +35,11 @@ struct ses_device { unsigned char *page1; + unsigned char *page1_types; unsigned char *page2; unsigned char *page10; short page1_len; + short page1_num_types; short page2_len; short page10_len; }; @@ -110,12 +112,12 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev, int i, j, count = 0, descriptor = ecomp->number; struct scsi_device *sdev = to_scsi_device(edev->edev.parent); struct ses_device *ses_dev = edev->scratch; - unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; + unsigned char *type_ptr = ses_dev->page1_types; unsigned char *desc_ptr = ses_dev->page2 + 8; /* Clear everything */ memset(desc_ptr, 0, ses_dev->page2_len - 8); - for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { + for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { for (j = 0; j < type_ptr[1]; j++) { desc_ptr += 4; if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && @@ -140,12 +142,12 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, int i, j, count = 0, descriptor = ecomp->number; struct scsi_device *sdev = to_scsi_device(edev->edev.parent); struct ses_device *ses_dev = edev->scratch; - unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; + unsigned char *type_ptr = ses_dev->page1_types; unsigned char *desc_ptr = ses_dev->page2 + 8; ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); - for (i = 0; i < ses_dev->page1[10]; i++, type_ptr += 4) { + for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { for (j = 0; j < type_ptr[1]; j++) { desc_ptr += 4; if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && @@ -358,7 +360,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; int i, j, page7_len, len, components; struct ses_device *ses_dev = edev->scratch; - int types = ses_dev->page1[10]; + int types = ses_dev->page1_num_types; unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); if (!hdr_buf) @@ -393,7 +395,7 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, } if (ses_dev->page10) addl_desc_ptr = ses_dev->page10 + 8; - type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; + type_ptr = ses_dev->page1_types; components = 0; for (i = 0; i < types; i++, type_ptr += 4) { for (j = 0; j < type_ptr[1]; j++) { @@ -503,6 +505,7 @@ static int ses_intf_add(struct device *cdev, u32 result; int i, types, len, components = 0; int err = -ENOMEM; + int num_enclosures; struct enclosure_device *edev; struct ses_component *scomp = NULL; @@ -530,16 +533,6 @@ static int ses_intf_add(struct device *cdev, if (result) goto recv_failed; - if (hdr_buf[1] != 0) { - /* FIXME: need subenclosure support; I've just never - * seen a device with subenclosures and it makes the - * traversal routines more complex */ - sdev_printk(KERN_ERR, sdev, - "FIXME driver has no support for subenclosures (%d)\n", - hdr_buf[1]); - goto err_free; - } - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; buf = kzalloc(len, GFP_KERNEL); if (!buf) @@ -549,11 +542,24 @@ static int ses_intf_add(struct device *cdev, if (result) goto recv_failed; - types = buf[10]; + types = 0; - type_ptr = buf + 12 + buf[11]; + /* we always have one main enclosure and the rest are referred + * to as secondary subenclosures */ + num_enclosures = buf[1] + 1; - for (i = 0; i < types; i++, type_ptr += 4) { + /* begin at the enclosure descriptor */ + type_ptr = buf + 8; + /* skip all the enclosure descriptors */ + for (i = 0; i < num_enclosures && type_ptr < buf + len; i++) { + types += type_ptr[2]; + type_ptr += type_ptr[3] + 4; + } + + ses_dev->page1_types = type_ptr; + ses_dev->page1_num_types = types; + + for (i = 0; i < types && type_ptr < buf + len; i++, type_ptr += 4) { if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) components += type_ptr[1]; -- cgit v1.2.2 From 9640de2099a3c7936b65bf3a45e67a324de950c8 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 21 Mar 2011 03:34:24 -0700 Subject: [SCSI] qla4xxx: cleanup qla4xxx_initialize_ddb_list() Remove process all aen code from qla4xxx_initialize_ddb_list() as DPC activities should be done in DPC only. Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 1629c48c35ef..22fc57e2bc05 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1013,13 +1013,6 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR) return status; - /* - * Targets can come online after the inital discovery, so processing - * the aens here will catch them. - */ - if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) - qla4xxx_process_aen(ha, PROCESS_ALL_AENS); - return status; } -- cgit v1.2.2 From 99b53bf50cc4711a3c82dfc704911ff738a41758 Mon Sep 17 00:00:00 2001 From: Prasanna Mumbai Date: Mon, 21 Mar 2011 03:34:25 -0700 Subject: [SCSI] qla4xxx: Do not send mbox command if FW is in failed state FW is not able to process mbox command if FW state is failed. This will cause mbox command to timeout and adapter reset. We have separate function to detect FW failed state and do adapter reset. So to avoid mbox command timeout, do not process mbox command in case of FW state failed. Signed-off-by: Vikas Chaudhary Signed-off-by: Prasanna Mumbai Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_mbx.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index f65626aec7c1..47b259190b5a 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -32,6 +32,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, u_long wait_count; uint32_t intr_status; unsigned long flags = 0; + uint32_t dev_state; /* Make sure that pointers are valid */ if (!mbx_cmd || !mbx_sts) { @@ -40,12 +41,23 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, return status; } - if (is_qla8022(ha) && - test_bit(AF_FW_RECOVERY, &ha->flags)) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: prematurely " - "completing mbx cmd as firmware recovery detected\n", - ha->host_no, __func__)); - return status; + if (is_qla8022(ha)) { + if (test_bit(AF_FW_RECOVERY, &ha->flags)) { + DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " + "prematurely completing mbx cmd as firmware " + "recovery detected\n", ha->host_no, __func__)); + return status; + } + /* Do not send any mbx cmd if h/w is in failed state*/ + qla4_8xxx_idc_lock(ha); + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + qla4_8xxx_idc_unlock(ha); + if (dev_state == QLA82XX_DEV_FAILED) { + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: H/W is in " + "failed state, do not send any mailbox commands\n", + ha->host_no, __func__); + return status; + } } if ((is_aer_supported(ha)) && -- cgit v1.2.2 From f9880e76fd15795b5917b20f54eeca764b0f3ccb Mon Sep 17 00:00:00 2001 From: Prasanna Mumbai Date: Mon, 21 Mar 2011 03:34:26 -0700 Subject: [SCSI] qla4xxx: Do not retry ISP82XX initialization if H/W state is failed Signed-off-by: Vikas Chaudhary Signed-off-by: Prasanna Mumbai Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 967836ef5ab2..409b20d62ef5 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1630,6 +1630,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, uint8_t init_retry_count = 0; char buf[34]; struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; + uint32_t dev_state; if (pci_enable_device(pdev)) return -1; @@ -1713,6 +1714,18 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST); while ((!test_bit(AF_ONLINE, &ha->flags)) && init_retry_count++ < MAX_INIT_RETRIES) { + + if (is_qla8022(ha)) { + qla4_8xxx_idc_lock(ha); + dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); + qla4_8xxx_idc_unlock(ha); + if (dev_state == QLA82XX_DEV_FAILED) { + ql4_printk(KERN_WARNING, ha, "%s: don't retry " + "initialize adapter. H/W is in failed state\n", + __func__); + break; + } + } DEBUG2(printk("scsi: %s: retrying adapter initialization " "(%d)\n", __func__, init_retry_count)); -- cgit v1.2.2 From 7edd9a7b28f57d8a5bcdb1a0def2aa09d1dd49d4 Mon Sep 17 00:00:00 2001 From: Karen Higgins Date: Mon, 21 Mar 2011 03:34:27 -0700 Subject: [SCSI] qla4xxx: cleanup DDB relogin logic during initialization Driver has capability to add device dynamically and present them to OS, driver no longer need to wait for DDBs to come online during driver initialization. Driver still issues a relogin for DDBs that are not online, but no longer wait for DDB to come online. Signed-off-by: Vikas Chaudhary Signed-off-by: Karen Higgins Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 5 -- drivers/scsi/qla4xxx/ql4_glbl.h | 1 - drivers/scsi/qla4xxx/ql4_init.c | 183 +++++++--------------------------------- drivers/scsi/qla4xxx/ql4_isr.c | 29 +------ drivers/scsi/qla4xxx/ql4_mbx.c | 3 - drivers/scsi/qla4xxx/ql4_os.c | 4 - 6 files changed, 33 insertions(+), 192 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 2fc0045b1a52..b46d0dc9a48e 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -233,9 +233,6 @@ struct ddb_entry { unsigned long flags; /* DDB Flags */ - unsigned long dev_scan_wait_to_start_relogin; - unsigned long dev_scan_wait_to_complete_relogin; - uint16_t fw_ddb_index; /* DDB firmware index */ uint16_t options; uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ @@ -479,7 +476,6 @@ struct scsi_qla_host { uint32_t timer_active; /* Recovery Timers */ - uint32_t discovery_wait; atomic_t check_relogin_timeouts; uint32_t retry_reset_ha_cnt; uint32_t isp_reset_timer; /* reset test timer */ @@ -765,6 +761,5 @@ static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a) /* Defines for process_aen() */ #define PROCESS_ALL_AENS 0 #define FLUSH_DDB_CHANGED_AENS 1 -#define RELOGIN_DDB_CHANGED_AENS 2 #endif /*_QLA4XXX_H */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 8fad99b7eef4..cc53e3fbd78c 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -136,7 +136,6 @@ void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); extern int ql4xextended_error_logging; -extern int ql4xdiscoverywait; extern int ql4xdontresethba; extern int ql4xenablemsix; diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 22fc57e2bc05..bf1c30b17a82 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -723,13 +723,38 @@ int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err) return relogin; } +static void qla4xxx_flush_AENS(struct scsi_qla_host *ha) +{ + unsigned long wtime; + + /* Flush the 0x8014 AEN from the firmware as a result of + * Auto connect. We are basically doing get_firmware_ddb() + * to determine whether we need to log back in or not. + * Trying to do a set ddb before we have processed 0x8014 + * will result in another set_ddb() for the same ddb. In other + * words there will be stale entries in the aen_q. + */ + wtime = jiffies + (2 * HZ); + do { + if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) + if (ha->firmware_state & (BIT_2 | BIT_0)) + return; + + if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) + qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); + + msleep(1000); + } while (!time_after_eq(jiffies, wtime)); +} + /** - * qla4xxx_configure_ddbs - builds driver ddb list + * qla4xxx_build_ddb_list - builds driver ddb list * @ha: Pointer to host adapter structure. * * This routine searches for all valid firmware ddb entries and builds * an internal ddb list. Ddbs that are considered valid are those with * a device state of SESSION_ACTIVE. + * A relogin (set_ddb) is issued for DDBs that are not online. **/ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) { @@ -744,6 +769,8 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha) uint32_t ipv6_device; uint32_t new_tgt; + qla4xxx_flush_AENS(ha); + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, GFP_KERNEL); if (fw_ddb_entry == NULL) { @@ -847,144 +874,6 @@ exit_build_ddb_list_no_free: return status; } -struct qla4_relog_scan { - int halt_wait; - uint32_t conn_err; - uint32_t fw_ddb_index; - uint32_t next_fw_ddb_index; - uint32_t fw_ddb_device_state; -}; - -static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs) -{ - struct ddb_entry *ddb_entry; - - if (qla4_is_relogin_allowed(ha, rs->conn_err)) { - /* We either have a device that is in - * the process of relogging in or a - * device that is waiting to be - * relogged in */ - rs->halt_wait = 0; - - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, - rs->fw_ddb_index); - if (ddb_entry == NULL) - return QLA_ERROR; - - if (ddb_entry->dev_scan_wait_to_start_relogin != 0 - && time_after_eq(jiffies, - ddb_entry-> - dev_scan_wait_to_start_relogin)) - { - ddb_entry->dev_scan_wait_to_start_relogin = 0; - qla4xxx_set_ddb_entry(ha, rs->fw_ddb_index, 0); - } - } - return QLA_SUCCESS; -} - -static int qla4_scan_for_relogin(struct scsi_qla_host *ha, - struct qla4_relog_scan *rs) -{ - int error; - - /* scan for relogins - * ----------------- */ - for (rs->fw_ddb_index = 0; rs->fw_ddb_index < MAX_DDB_ENTRIES; - rs->fw_ddb_index = rs->next_fw_ddb_index) { - if (qla4xxx_get_fwddb_entry(ha, rs->fw_ddb_index, NULL, 0, - NULL, &rs->next_fw_ddb_index, - &rs->fw_ddb_device_state, - &rs->conn_err, NULL, NULL) - == QLA_ERROR) - return QLA_ERROR; - - if (rs->fw_ddb_device_state == DDB_DS_LOGIN_IN_PROCESS) - rs->halt_wait = 0; - - if (rs->fw_ddb_device_state == DDB_DS_SESSION_FAILED || - rs->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) { - error = qla4_test_rdy(ha, rs); - if (error) - return error; - } - - /* We know we've reached the last device when - * next_fw_ddb_index is 0 */ - if (rs->next_fw_ddb_index == 0) - break; - } - return QLA_SUCCESS; -} - -/** - * qla4xxx_devices_ready - wait for target devices to be logged in - * @ha: pointer to adapter structure - * - * This routine waits up to ql4xdiscoverywait seconds - * F/W database during driver load time. - **/ -static int qla4xxx_devices_ready(struct scsi_qla_host *ha) -{ - int error; - unsigned long discovery_wtime; - struct qla4_relog_scan rs; - - discovery_wtime = jiffies + (ql4xdiscoverywait * HZ); - - DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait)); - do { - /* poll for AEN. */ - qla4xxx_get_firmware_state(ha); - if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) { - /* Set time-between-relogin timer */ - qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS); - } - - /* if no relogins active or needed, halt discvery wait */ - rs.halt_wait = 1; - - error = qla4_scan_for_relogin(ha, &rs); - - if (rs.halt_wait) { - DEBUG2(printk("scsi%ld: %s: Delay halted. Devices " - "Ready.\n", ha->host_no, __func__)); - return QLA_SUCCESS; - } - - msleep(2000); - } while (!time_after_eq(jiffies, discovery_wtime)); - - DEBUG3(qla4xxx_get_conn_event_log(ha)); - - return QLA_SUCCESS; -} - -static void qla4xxx_flush_AENS(struct scsi_qla_host *ha) -{ - unsigned long wtime; - - /* Flush the 0x8014 AEN from the firmware as a result of - * Auto connect. We are basically doing get_firmware_ddb() - * to determine whether we need to log back in or not. - * Trying to do a set ddb before we have processed 0x8014 - * will result in another set_ddb() for the same ddb. In other - * words there will be stale entries in the aen_q. - */ - wtime = jiffies + (2 * HZ); - do { - if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) - if (ha->firmware_state & (BIT_2 | BIT_0)) - return; - - if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) - qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - - msleep(1000); - } while (!time_after_eq(jiffies, wtime)); - -} - static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) { uint16_t fw_ddb_index; @@ -996,22 +885,12 @@ static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha) for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++) ha->fw_ddb_index_map[fw_ddb_index] = - (struct ddb_entry *)INVALID_ENTRY; + (struct ddb_entry *)INVALID_ENTRY; ha->tot_ddbs = 0; - qla4xxx_flush_AENS(ha); - - /* Wait for an AEN */ - qla4xxx_devices_ready(ha); - - /* - * First perform device discovery for active - * fw ddb indexes and build - * ddb list. - */ - if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR) - return status; + /* Perform device discovery and build ddb list. */ + status = qla4xxx_build_ddb_list(ha); return status; } diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 03e028e6e809..2ef1a986f5c0 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -1008,34 +1008,9 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) mbox_sts[0], mbox_sts[2], mbox_sts[3])); break; - } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) { - /* for use during init time, we only want to - * relogin non-active ddbs */ - struct ddb_entry *ddb_entry; - - ddb_entry = - /* FIXME: name length? */ - qla4xxx_lookup_ddb_by_fw_index(ha, - mbox_sts[2]); - if (!ddb_entry) - break; - - ddb_entry->dev_scan_wait_to_complete_relogin = - 0; - ddb_entry->dev_scan_wait_to_start_relogin = - jiffies + - ((ddb_entry->default_time2wait + - 4) * HZ); - - DEBUG2(printk("scsi%ld: ddb [%d] initiate" - " RELOGIN after %d seconds\n", - ha->host_no, - ddb_entry->fw_ddb_index, - ddb_entry->default_time2wait + - 4)); - break; } - + case PROCESS_ALL_AENS: + default: if (mbox_sts[1] == 0) { /* Global DB change. */ qla4xxx_reinitialize_ddb_list(ha); } else if (mbox_sts[1] == 1) { /* Specific device. */ diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 47b259190b5a..379df2bde9db 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -407,9 +407,6 @@ qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, /*memcpy(ha->alias, init_fw_cb->Alias, min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ - /* Save Command Line Paramater info */ - ha->discovery_wait = ql4xdiscoverywait; - if (ha->acb_version == ACB_SUPPORTED) { ha->ipv6_options = init_fw_cb->ipv6_opts; ha->ipv6_addl_options = init_fw_cb->ipv6_addtl_opts; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 409b20d62ef5..1d5c6fbbfaae 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -29,10 +29,6 @@ static struct kmem_cache *srb_cachep; /* * Module parameter information and variables */ -int ql4xdiscoverywait = 60; -module_param(ql4xdiscoverywait, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time"); - int ql4xdontresethba = 0; module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdontresethba, -- cgit v1.2.2 From 58da51dcfc13b2222ce8565e308852aef001f5d2 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 21 Mar 2011 03:34:28 -0700 Subject: [SCSI] qla4xxx: remove unused ddb flag DF_NO_RELOGIN Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 2 -- drivers/scsi/qla4xxx/ql4_init.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index b46d0dc9a48e..7aa60ee485e1 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -286,8 +286,6 @@ struct ddb_entry { * DDB flags. */ #define DF_RELOGIN 0 /* Relogin to device */ -#define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL - * logged it out */ #define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ #define DF_FO_MASKED 3 diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index bf1c30b17a82..8b5453a60444 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1445,7 +1445,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); - clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); iscsi_unblock_session(ddb_entry->sess); iscsi_session_event(ddb_entry->sess, ISCSI_KEVENT_CREATE_SESSION); @@ -1470,7 +1469,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, */ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED && !test_bit(DF_RELOGIN, &ddb_entry->flags) && - !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) && qla4_is_relogin_allowed(ha, conn_err)) { /* * This triggers a relogin. After the relogin_timer -- cgit v1.2.2 From 7eece5a084264c1bff908b0d6a1b176b39dd272f Mon Sep 17 00:00:00 2001 From: Karen Higgins Date: Mon, 21 Mar 2011 03:34:29 -0700 Subject: [SCSI] qla4xxx: Prevent other port reinitialization during remove_adapter remove ha flag AF_HBA_GOING_AWAY and added flag AF_HA_REMOVAL to mark the other ISP-4xxx port to indicate that the driver is being removed, so that the other port will not re-initialize while in the process of removing the ha due to driver unload or hba hotplug. Signed-off-by: Karen Higgins Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_def.h | 5 +++- drivers/scsi/qla4xxx/ql4_isr.c | 2 +- drivers/scsi/qla4xxx/ql4_mbx.c | 2 +- drivers/scsi/qla4xxx/ql4_os.c | 53 +++++++++++++++++++++++++++++++----------- 4 files changed, 46 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index 7aa60ee485e1..c1f8d1b150f7 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -53,6 +53,9 @@ #define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022 #endif +#define ISP4XXX_PCI_FN_1 0x1 +#define ISP4XXX_PCI_FN_2 0x3 + #define QLA_SUCCESS 0 #define QLA_ERROR 1 @@ -371,7 +374,7 @@ struct scsi_qla_host { #define AF_LINK_UP 8 /* 0x00000100 */ #define AF_IRQ_ATTACHED 10 /* 0x00000400 */ #define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ -#define AF_HBA_GOING_AWAY 12 /* 0x00001000 */ +#define AF_HA_REMOVAL 12 /* 0x00001000 */ #define AF_INTx_ENABLED 15 /* 0x00008000 */ #define AF_MSI_ENABLED 16 /* 0x00010000 */ #define AF_MSIX_ENABLED 17 /* 0x00020000 */ diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 2ef1a986f5c0..2f40ac761cd4 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -801,7 +801,7 @@ irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) &ha->reg->ctrl_status); readl(&ha->reg->ctrl_status); - if (!test_bit(AF_HBA_GOING_AWAY, &ha->flags)) + if (!test_bit(AF_HA_REMOVAL, &ha->flags)) set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); break; diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 379df2bde9db..199fa643cdad 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -151,7 +151,7 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, if (test_bit(AF_IRQ_ATTACHED, &ha->flags) && test_bit(AF_INTERRUPTS_ON, &ha->flags) && test_bit(AF_ONLINE, &ha->flags) && - !test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { + !test_bit(AF_HA_REMOVAL, &ha->flags)) { /* Do not poll for completion. Use completion queue */ set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ); diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 1d5c6fbbfaae..f80b702730ad 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -749,12 +749,6 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) if (!pci_channel_offline(ha->pdev)) pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); - if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s exited. HBA GOING AWAY\n", - __func__)); - return; - } - if (is_qla8022(ha)) { qla4_8xxx_watchdog(ha); } @@ -1063,7 +1057,6 @@ void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) /* Disable the board */ ql4_printk(KERN_INFO, ha, "Disabling the board\n"); - set_bit(AF_HBA_GOING_AWAY, &ha->flags); qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); qla4xxx_mark_all_devices_missing(ha); @@ -1255,11 +1248,6 @@ static void qla4xxx_do_dpc(struct work_struct *work) goto do_dpc_exit; } - /* HBA is in the process of being permanently disabled. - * Don't process anything */ - if (test_bit(AF_HBA_GOING_AWAY, &ha->flags)) - return; - if (is_qla8022(ha)) { if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { qla4_8xxx_idc_lock(ha); @@ -1823,6 +1811,44 @@ probe_disable_device: return ret; } +/** + * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize + * @ha: pointer to adapter structure + * + * Mark the other ISP-4xxx port to indicate that the driver is being removed, + * so that the other port will not re-initialize while in the process of + * removing the ha due to driver unload or hba hotplug. + **/ +static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) +{ + struct scsi_qla_host *other_ha = NULL; + struct pci_dev *other_pdev = NULL; + int fn = ISP4XXX_PCI_FN_2; + + /*iscsi function numbers for ISP4xxx is 1 and 3*/ + if (PCI_FUNC(ha->pdev->devfn) & BIT_1) + fn = ISP4XXX_PCI_FN_1; + + other_pdev = + pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), + ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), + fn)); + + /* Get other_ha if other_pdev is valid and state is enable*/ + if (other_pdev) { + if (atomic_read(&other_pdev->enable_cnt)) { + other_ha = pci_get_drvdata(other_pdev); + if (other_ha) { + set_bit(AF_HA_REMOVAL, &other_ha->flags); + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " + "Prevent %s reinit\n", __func__, + dev_name(&other_ha->pdev->dev))); + } + } + pci_dev_put(other_pdev); + } +} + /** * qla4xxx_remove_adapter - calback function to remove adapter. * @pci_dev: PCI device pointer @@ -1833,7 +1859,8 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) ha = pci_get_drvdata(pdev); - set_bit(AF_HBA_GOING_AWAY, &ha->flags); + if (!is_qla8022(ha)) + qla4xxx_prevent_other_port_reinit(ha); /* remove devs from iscsi_sessions to scsi_devices */ qla4xxx_free_ddb_list(ha); -- cgit v1.2.2 From fc7657c9d98c250c9fd212348e6e156c73885cc4 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 21 Mar 2011 03:34:30 -0700 Subject: [SCSI] qla4xxx: cleanup function qla4xxx_process_ddb_changed We don't need to check ddb old state we can take action based on ddb new state. Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_init.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 8b5453a60444..bbb2e903d38a 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1409,7 +1409,6 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, uint32_t state, uint32_t conn_err) { struct ddb_entry * ddb_entry; - uint32_t old_fw_ddb_device_state; /* check for out of range index */ if (fw_ddb_index >= MAX_DDB_ENTRIES) @@ -1425,22 +1424,14 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, } /* Device already exists in our database. */ - old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for " "index [%d]\n", ha->host_no, __func__, ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); - if (old_fw_ddb_device_state == state && - state == DDB_DS_SESSION_ACTIVE) { - if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) { - atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); - iscsi_unblock_session(ddb_entry->sess); - } - return QLA_SUCCESS; - } ddb_entry->fw_ddb_device_state = state; /* Device is back online. */ - if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { + if ((ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) && + (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)) { atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); atomic_set(&ddb_entry->relogin_retry_count, 0); atomic_set(&ddb_entry->relogin_timer, 0); @@ -1452,7 +1443,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, * Change the lun state to READY in case the lun TIMEOUT before * the device came back. */ - } else { + } else if (ddb_entry->fw_ddb_device_state != DDB_DS_SESSION_ACTIVE) { /* Device went away, mark device missing */ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE) { DEBUG2(ql4_printk(KERN_INFO, ha, "%s mark missing " -- cgit v1.2.2 From 8bb4033d2b91e055a32e905e10a7034a4b077b7a Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 21 Mar 2011 03:34:31 -0700 Subject: [SCSI] qla4xxx: Add support for ql4xmaxqdepth command line parameter This provides the flexibility to modify the qdepth based on different target devices to make the best use of system resources. Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index f80b702730ad..df46e5d8f74e 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -51,6 +51,11 @@ MODULE_PARM_DESC(ql4xenablemsix, " 2 = enable MSI interrupt mechanism."); #define QL4_DEF_QDEPTH 32 +static int ql4xmaxqdepth = QL4_DEF_QDEPTH; +module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ql4xmaxqdepth, + "Maximum queue depth to report for target devices.\n" + " Default: 32."); /* * SCSI host template entry points @@ -1904,10 +1909,15 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev) { struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target); struct ddb_entry *ddb = sess->dd_data; + int queue_depth = QL4_DEF_QDEPTH; sdev->hostdata = ddb; sdev->tagged_supported = 1; - scsi_activate_tcq(sdev, QL4_DEF_QDEPTH); + + if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) + queue_depth = ql4xmaxqdepth; + + scsi_activate_tcq(sdev, queue_depth); return 0; } -- cgit v1.2.2 From 3038727c8391ab1f3e5f5cf764f9f74164e6b47a Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 21 Mar 2011 03:34:32 -0700 Subject: [SCSI] qla4xxx: add support for ql4xsess_recovery_tmo cmd line param Target Session Recovery Timeout Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index df46e5d8f74e..b7bc69900de8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -57,6 +57,12 @@ MODULE_PARM_DESC(ql4xmaxqdepth, "Maximum queue depth to report for target devices.\n" " Default: 32."); +static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; +module_param(ql4xsess_recovery_tmo, int, S_IRUGO); +MODULE_PARM_DESC(ql4xsess_recovery_tmo, + "Target Session Recovery Timeout.\n" + " Default: 30 sec."); + /* * SCSI host template entry points */ @@ -166,7 +172,7 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session) DEBUG2(printk("scsi%ld: %s: ddb [%d] session recovery timeout " "of (%d) secs exhausted, marking device DEAD.\n", ha->host_no, __func__, ddb_entry->fw_ddb_index, - QL4_SESS_RECOVERY_TMO)); + ddb_entry->sess->recovery_tmo)); } } @@ -296,7 +302,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) { int err; - ddb_entry->sess->recovery_tmo = QL4_SESS_RECOVERY_TMO; + ddb_entry->sess->recovery_tmo = ql4xsess_recovery_tmo; err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); if (err) { -- cgit v1.2.2 From 2d7924e6be8b994f718429001457e677a2159445 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 21 Mar 2011 03:34:33 -0700 Subject: [SCSI] qla4xxx: added new function qla4xxx_relogin_all_devices Move relogin to all devices code from do_dpc to new fuction qla4xxx_relogin_all_devices() Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_os.c | 54 ++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index b7bc69900de8..a4acb0dd7beb 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1218,6 +1218,27 @@ recover_ha_init_adapter: return status; } +static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry, *dtemp; + + list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) { + if ((atomic_read(&ddb_entry->state) == DDB_STATE_MISSING) || + (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD)) { + if (ddb_entry->fw_ddb_device_state == + DDB_DS_SESSION_ACTIVE) { + atomic_set(&ddb_entry->state, DDB_STATE_ONLINE); + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " marked ONLINE\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + + iscsi_unblock_session(ddb_entry->sess); + } else + qla4xxx_relogin_device(ha, ddb_entry); + } + } +} + void qla4xxx_wake_dpc(struct scsi_qla_host *ha) { if (ha->dpc_thread && @@ -1326,13 +1347,7 @@ dpc_post_reset_ha: if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { if (!test_bit(AF_LINK_UP, &ha->flags)) { /* ---- link down? --- */ - list_for_each_entry_safe(ddb_entry, dtemp, - &ha->ddb_list, list) { - if (atomic_read(&ddb_entry->state) == - DDB_STATE_ONLINE) - qla4xxx_mark_device_missing(ha, - ddb_entry); - } + qla4xxx_mark_all_devices_missing(ha); } else { /* ---- link up? --- * * F/W will auto login to all devices ONLY ONCE after @@ -1341,30 +1356,7 @@ dpc_post_reset_ha: * manually relogin to devices when recovering from * connection failures, logouts, expired KATO, etc. */ - list_for_each_entry_safe(ddb_entry, dtemp, - &ha->ddb_list, list) { - if ((atomic_read(&ddb_entry->state) == - DDB_STATE_MISSING) || - (atomic_read(&ddb_entry->state) == - DDB_STATE_DEAD)) { - if (ddb_entry->fw_ddb_device_state == - DDB_DS_SESSION_ACTIVE) { - atomic_set(&ddb_entry->state, - DDB_STATE_ONLINE); - ql4_printk(KERN_INFO, ha, - "scsi%ld: %s: ddb[%d]" - " marked ONLINE\n", - ha->host_no, __func__, - ddb_entry->fw_ddb_index); - - iscsi_unblock_session( - ddb_entry->sess); - } else - qla4xxx_relogin_device( - ha, ddb_entry); - } - - } + qla4xxx_relogin_all_devices(ha); } } -- cgit v1.2.2 From d32cee3c2d742784ec6ac0b4ca5732e98b17bc5c Mon Sep 17 00:00:00 2001 From: Prasanna Mumbai Date: Mon, 21 Mar 2011 03:34:35 -0700 Subject: [SCSI] qla4xxx: masking required bits of add_fw_options during initialization Signed-off-by: Vikas Chaudhary Signed-off-by: Prasanna Mumbai Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_fw.h | 1 + drivers/scsi/qla4xxx/ql4_mbx.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index c1985792f034..31e2bf97198c 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -455,6 +455,7 @@ struct addr_ctrl_blk { uint8_t res0; /* 07 */ uint16_t eth_mtu_size; /* 08-09 */ uint16_t add_fw_options; /* 0A-0B */ +#define SERIALIZE_TASK_MGMT 0x0400 uint8_t hb_interval; /* 0C */ uint8_t inst_num; /* 0D */ diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 199fa643cdad..f9d81c8372c3 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -476,6 +476,11 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); + /* Set bit for "serialize task mgmt" all other bits need to be zero */ + init_fw_cb->add_fw_options = 0; + init_fw_cb->add_fw_options |= + __constant_cpu_to_le16(SERIALIZE_TASK_MGMT); + if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != QLA_SUCCESS) { DEBUG2(printk(KERN_WARNING -- cgit v1.2.2 From 2dcb0a61041a003f439bbd38005b6e454c368be0 Mon Sep 17 00:00:00 2001 From: Vikas Chaudhary Date: Mon, 21 Mar 2011 03:34:36 -0700 Subject: [SCSI] qla4xxx: Update driver version to 5.02.00-k6 Signed-off-by: Vikas Chaudhary Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index 8475b308e01b..603155769407 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k5" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k6" -- cgit v1.2.2 From fee787129d4d6a5e967a69ea3dea3e38ba556b3d Mon Sep 17 00:00:00 2001 From: Bhanu Gollapudi Date: Mon, 21 Mar 2011 18:51:13 -0700 Subject: [SCSI] bnx2fc: IO completion not processed due to missed wakeup Driver does not detect a new CQE (completion queue entry) if a thread receives the wakup when it is in TASK_RUNNING state. Fix is to set the state to TASK_INTERRUPTIBLE while holding the fp_work_lock. Also, Use __set_current_task() since it is now set inside a spinlock with synchronization. Two other related optimizations: 1. After we exit the while (!kthread_should_stop()) loop, use __set_current_state() since synchronization is no longer needed. 2. Remove set_current_state(TASK_RUNNING) after schedule() since it should always be TASK_RUNNING after schedule(). Reviewed-by: Michael Chan Signed-off-by: Bhanu Prakash Gollapudi Signed-off-by: James Bottomley --- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 2056890b437a..e2e647509a73 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -437,17 +437,16 @@ static int bnx2fc_l2_rcv_thread(void *arg) set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); - set_current_state(TASK_RUNNING); spin_lock_bh(&bg->fcoe_rx_list.lock); while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) { spin_unlock_bh(&bg->fcoe_rx_list.lock); bnx2fc_recv_frame(skb); spin_lock_bh(&bg->fcoe_rx_list.lock); } + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_bh(&bg->fcoe_rx_list.lock); - set_current_state(TASK_INTERRUPTIBLE); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); return 0; } @@ -569,7 +568,6 @@ int bnx2fc_percpu_io_thread(void *arg) set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); - set_current_state(TASK_RUNNING); spin_lock_bh(&p->fp_work_lock); while (!list_empty(&p->work_list)) { list_splice_init(&p->work_list, &work_list); @@ -583,10 +581,10 @@ int bnx2fc_percpu_io_thread(void *arg) spin_lock_bh(&p->fp_work_lock); } + __set_current_state(TASK_INTERRUPTIBLE); spin_unlock_bh(&p->fp_work_lock); - set_current_state(TASK_INTERRUPTIBLE); } - set_current_state(TASK_RUNNING); + __set_current_state(TASK_RUNNING); return 0; } -- cgit v1.2.2 From 3dea642afd9187728d119fce5c82a7ed9faa9b6a Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 23 Mar 2011 09:58:28 -0500 Subject: [SCSI] Revert "[SCSI] Retrieve the Caching mode page" This reverts commit 24d720b726c1a85f1962831ac30ad4d2ef8276b1. Previously we thought there was little possibility that devices would crash with this, but some have been found. Reported-by: Alan Stern Cc: Luben Tuikov Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 63 ++++++++++++++----------------------------------------- 1 file changed, 16 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 7ff61d76b4c5..b61ebec6bca7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2027,14 +2027,10 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) int old_rcd = sdkp->RCD; int old_dpofua = sdkp->DPOFUA; - if (sdp->skip_ms_page_8) { - if (sdp->type == TYPE_RBC) - goto defaults; - else { - modepage = 0x3F; - dbd = 0; - } - } else if (sdp->type == TYPE_RBC) { + if (sdp->skip_ms_page_8) + goto defaults; + + if (sdp->type == TYPE_RBC) { modepage = 6; dbd = 8; } else { @@ -2062,11 +2058,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) */ if (len < 3) goto bad_sense; - else if (len > SD_BUF_SIZE) { - sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " - "data from %d to %d bytes\n", len, SD_BUF_SIZE); - len = SD_BUF_SIZE; - } + if (len > 20) + len = 20; + + /* Take headers and block descriptors into account */ + len += data.header_length + data.block_descriptor_length; + if (len > SD_BUF_SIZE) + goto bad_sense; /* Get the data */ res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); @@ -2074,45 +2072,16 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (scsi_status_is_good(res)) { int offset = data.header_length + data.block_descriptor_length; - while (offset < len) { - u8 page_code = buffer[offset] & 0x3F; - u8 spf = buffer[offset] & 0x40; - - if (page_code == 8 || page_code == 6) { - /* We're interested only in the first 3 bytes. - */ - if (len - offset <= 2) { - sd_printk(KERN_ERR, sdkp, "Incomplete " - "mode parameter data\n"); - goto defaults; - } else { - modepage = page_code; - goto Page_found; - } - } else { - /* Go to the next page */ - if (spf && len - offset > 3) - offset += 4 + (buffer[offset+2] << 8) + - buffer[offset+3]; - else if (!spf && len - offset > 1) - offset += 2 + buffer[offset+1]; - else { - sd_printk(KERN_ERR, sdkp, "Incomplete " - "mode parameter data\n"); - goto defaults; - } - } + if (offset >= SD_BUF_SIZE - 2) { + sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n"); + goto defaults; } - if (modepage == 0x3F) { - sd_printk(KERN_ERR, sdkp, "No Caching mode page " - "present\n"); - goto defaults; - } else if ((buffer[offset] & 0x3f) != modepage) { + if ((buffer[offset] & 0x3f) != modepage) { sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); goto defaults; } - Page_found: + if (modepage == 8) { sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0); sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0); -- cgit v1.2.2 From 5fa8b573134108a333a317378998a9f1299c4dd6 Mon Sep 17 00:00:00 2001 From: Sarang Radke Date: Wed, 23 Mar 2011 08:07:33 -0700 Subject: [SCSI] qla4xxx: Use polling mode for disable interrupt mailbox completion Disable Interrupt MBX completion will disable the interrupt on successful completion. Fixed the bug where driver was waiting for Interrupt to come in for its completion. Now driver will poll for disable interrupt MBX completion. Signed-off-by: Sarang Radke Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/qla4xxx/ql4_nx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 3d5ef2df4134..35381cb0936e 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -2304,14 +2304,13 @@ qla4_8xxx_enable_intrs(struct scsi_qla_host *ha) void qla4_8xxx_disable_intrs(struct scsi_qla_host *ha) { - if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) + if (test_and_clear_bit(AF_INTERRUPTS_ON, &ha->flags)) qla4_8xxx_mbx_intr_disable(ha); spin_lock_irq(&ha->hardware_lock); /* BIT 10 - set */ qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400); spin_unlock_irq(&ha->hardware_lock); - clear_bit(AF_INTERRUPTS_ON, &ha->flags); } struct ql4_init_msix_entry { -- cgit v1.2.2 From 3703b2c5d041a68095cdd22380c23ce27d449ad7 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Fri, 18 Mar 2011 15:39:17 -0700 Subject: [SCSI] tcm_loop: Add multi-fabric Linux/SCSI LLD fabric module This patch adds the TCM_Loop Linux/SCSI LLD fabric module for accessing TCM device backstores as locally accessable SCSI LUNs in virtual SAS, FC, and iSCSI Target ports using the generic fabric TransportID and Target Port WWN naming handlers from TCM's target_core_fabric_lib.c The TCM_Loop module uses the generic fabric configfs infratructure provided by target_core_fabric_configfs.c and adds a module dependent attribute for the creation/release of the virtual I_T Nexus connected the TCM_Loop Target and Initiator Ports. TCM_Loop can also be used with scsi-generic and BSG drivers so that STGT userspace fabric modules, QEMU-KVM and other hypervisor SCSI passthrough support can access TCM device backstore and control CDB emulation. For more information please see: http://linux-iscsi.org/wiki/Tcm_loop [jejb: fixed up checkpatch stuff] Signed-off-by: Nicholas A. Bellinger Reviewed-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/target/Kconfig | 2 + drivers/target/Makefile | 3 + drivers/target/loopback/Kconfig | 11 + drivers/target/loopback/Makefile | 1 + drivers/target/loopback/tcm_loop.c | 1579 ++++++++++++++++++++++++++++++++++++ drivers/target/loopback/tcm_loop.h | 77 ++ 6 files changed, 1673 insertions(+) create mode 100644 drivers/target/loopback/Kconfig create mode 100644 drivers/target/loopback/Makefile create mode 100644 drivers/target/loopback/tcm_loop.c create mode 100644 drivers/target/loopback/tcm_loop.h (limited to 'drivers') diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 2fac3be209ac..9ef2dbbfa62b 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig @@ -29,4 +29,6 @@ config TCM_PSCSI Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered passthrough access to Linux/SCSI device +source "drivers/target/loopback/Kconfig" + endif diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 4f3cb788f06a..1178bbfc68fe 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -21,3 +21,6 @@ obj-$(CONFIG_TARGET_CORE) += target_core_mod.o obj-$(CONFIG_TCM_IBLOCK) += target_core_iblock.o obj-$(CONFIG_TCM_FILEIO) += target_core_file.o obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o + +# Fabric modules +obj-$(CONFIG_LOOPBACK_TARGET) += loopback/ diff --git a/drivers/target/loopback/Kconfig b/drivers/target/loopback/Kconfig new file mode 100644 index 000000000000..57dcbc2d711b --- /dev/null +++ b/drivers/target/loopback/Kconfig @@ -0,0 +1,11 @@ +config LOOPBACK_TARGET + tristate "TCM Virtual SAS target and Linux/SCSI LDD fabric loopback module" + help + Say Y here to enable the TCM Virtual SAS target and Linux/SCSI LLD + fabric loopback module. + +config LOOPBACK_TARGET_CDB_DEBUG + bool "TCM loopback fabric module CDB debug code" + depends on LOOPBACK_TARGET + help + Say Y here to enable the TCM loopback fabric module CDB debug code diff --git a/drivers/target/loopback/Makefile b/drivers/target/loopback/Makefile new file mode 100644 index 000000000000..6abebdf95659 --- /dev/null +++ b/drivers/target/loopback/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_LOOPBACK_TARGET) += tcm_loop.o diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c new file mode 100644 index 000000000000..aed4e464d31c --- /dev/null +++ b/drivers/target/loopback/tcm_loop.c @@ -0,0 +1,1579 @@ +/******************************************************************************* + * + * This file contains the Linux/SCSI LLD virtual SCSI initiator driver + * for emulated SAS initiator ports + * + * © Copyright 2011 RisingTide Systems LLC. + * + * Licensed to the Linux Foundation under the General Public License (GPL) version 2. + * + * Author: Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For TASK_ATTR_* */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcm_loop.h" + +#define to_tcm_loop_hba(hba) container_of(hba, struct tcm_loop_hba, dev) + +/* Local pointer to allocated TCM configfs fabric module */ +static struct target_fabric_configfs *tcm_loop_fabric_configfs; + +static struct kmem_cache *tcm_loop_cmd_cache; + +static int tcm_loop_hba_no_cnt; + +/* + * Allocate a tcm_loop cmd descriptor from target_core_mod code + * + * Can be called from interrupt context in tcm_loop_queuecommand() below + */ +static struct se_cmd *tcm_loop_allocate_core_cmd( + struct tcm_loop_hba *tl_hba, + struct se_portal_group *se_tpg, + struct scsi_cmnd *sc) +{ + struct se_cmd *se_cmd; + struct se_session *se_sess; + struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus; + struct tcm_loop_cmd *tl_cmd; + int sam_task_attr; + + if (!tl_nexus) { + scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" + " does not exist\n"); + set_host_byte(sc, DID_ERROR); + return NULL; + } + se_sess = tl_nexus->se_sess; + + tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC); + if (!tl_cmd) { + printk(KERN_ERR "Unable to allocate struct tcm_loop_cmd\n"); + set_host_byte(sc, DID_ERROR); + return NULL; + } + se_cmd = &tl_cmd->tl_se_cmd; + /* + * Save the pointer to struct scsi_cmnd *sc + */ + tl_cmd->sc = sc; + /* + * Locate the SAM Task Attr from struct scsi_cmnd * + */ + if (sc->device->tagged_supported) { + switch (sc->tag) { + case HEAD_OF_QUEUE_TAG: + sam_task_attr = TASK_ATTR_HOQ; + break; + case ORDERED_QUEUE_TAG: + sam_task_attr = TASK_ATTR_ORDERED; + break; + default: + sam_task_attr = TASK_ATTR_SIMPLE; + break; + } + } else + sam_task_attr = TASK_ATTR_SIMPLE; + + /* + * Initialize struct se_cmd descriptor from target_core_mod infrastructure + */ + transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, + scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr, + &tl_cmd->tl_sense_buf[0]); + + /* + * Signal BIDI usage with T_TASK(cmd)->t_tasks_bidi + */ + if (scsi_bidi_cmnd(sc)) + T_TASK(se_cmd)->t_tasks_bidi = 1; + /* + * Locate the struct se_lun pointer and attach it to struct se_cmd + */ + if (transport_get_lun_for_cmd(se_cmd, NULL, tl_cmd->sc->device->lun) < 0) { + kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); + set_host_byte(sc, DID_NO_CONNECT); + return NULL; + } + + transport_device_setup_cmd(se_cmd); + return se_cmd; +} + +/* + * Called by struct target_core_fabric_ops->new_cmd_map() + * + * Always called in process context. A non zero return value + * here will signal to handle an exception based on the return code. + */ +static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) +{ + struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, + struct tcm_loop_cmd, tl_se_cmd); + struct scsi_cmnd *sc = tl_cmd->sc; + void *mem_ptr, *mem_bidi_ptr = NULL; + u32 sg_no_bidi = 0; + int ret; + /* + * Allocate the necessary tasks to complete the received CDB+data + */ + ret = transport_generic_allocate_tasks(se_cmd, tl_cmd->sc->cmnd); + if (ret == -1) { + /* Out of Resources */ + return PYX_TRANSPORT_LU_COMM_FAILURE; + } else if (ret == -2) { + /* + * Handle case for SAM_STAT_RESERVATION_CONFLICT + */ + if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) + return PYX_TRANSPORT_RESERVATION_CONFLICT; + /* + * Otherwise, return SAM_STAT_CHECK_CONDITION and return + * sense data. + */ + return PYX_TRANSPORT_USE_SENSE_REASON; + } + /* + * Setup the struct scatterlist memory from the received + * struct scsi_cmnd. + */ + if (scsi_sg_count(sc)) { + se_cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM; + mem_ptr = (void *)scsi_sglist(sc); + /* + * For BIDI commands, pass in the extra READ buffer + * to transport_generic_map_mem_to_cmd() below.. + */ + if (T_TASK(se_cmd)->t_tasks_bidi) { + struct scsi_data_buffer *sdb = scsi_in(sc); + + mem_bidi_ptr = (void *)sdb->table.sgl; + sg_no_bidi = sdb->table.nents; + } + } else { + /* + * Used for DMA_NONE + */ + mem_ptr = NULL; + } + /* + * Map the SG memory into struct se_mem->page linked list using the same + * physical memory at sg->page_link. + */ + ret = transport_generic_map_mem_to_cmd(se_cmd, mem_ptr, + scsi_sg_count(sc), mem_bidi_ptr, sg_no_bidi); + if (ret < 0) + return PYX_TRANSPORT_LU_COMM_FAILURE; + + return 0; +} + +/* + * Called from struct target_core_fabric_ops->check_stop_free() + */ +static void tcm_loop_check_stop_free(struct se_cmd *se_cmd) +{ + /* + * Do not release struct se_cmd's containing a valid TMR + * pointer. These will be released directly in tcm_loop_device_reset() + * with transport_generic_free_cmd(). + */ + if (se_cmd->se_tmr_req) + return; + /* + * Release the struct se_cmd, which will make a callback to release + * struct tcm_loop_cmd * in tcm_loop_deallocate_core_cmd() + */ + transport_generic_free_cmd(se_cmd, 0, 1, 0); +} + +/* + * Called from struct target_core_fabric_ops->release_cmd_to_pool() + */ +static void tcm_loop_deallocate_core_cmd(struct se_cmd *se_cmd) +{ + struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, + struct tcm_loop_cmd, tl_se_cmd); + + kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); +} + +static int tcm_loop_proc_info(struct Scsi_Host *host, char *buffer, + char **start, off_t offset, + int length, int inout) +{ + return sprintf(buffer, "tcm_loop_proc_info()\n"); +} + +static int tcm_loop_driver_probe(struct device *); +static int tcm_loop_driver_remove(struct device *); + +static int pseudo_lld_bus_match(struct device *dev, + struct device_driver *dev_driver) +{ + return 1; +} + +static struct bus_type tcm_loop_lld_bus = { + .name = "tcm_loop_bus", + .match = pseudo_lld_bus_match, + .probe = tcm_loop_driver_probe, + .remove = tcm_loop_driver_remove, +}; + +static struct device_driver tcm_loop_driverfs = { + .name = "tcm_loop", + .bus = &tcm_loop_lld_bus, +}; +/* + * Used with root_device_register() in tcm_loop_alloc_core_bus() below + */ +struct device *tcm_loop_primary; + +/* + * Copied from drivers/scsi/libfc/fc_fcp.c:fc_change_queue_depth() and + * drivers/scsi/libiscsi.c:iscsi_change_queue_depth() + */ +static int tcm_loop_change_queue_depth( + struct scsi_device *sdev, + int depth, + int reason) +{ + switch (reason) { + case SCSI_QDEPTH_DEFAULT: + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + break; + case SCSI_QDEPTH_QFULL: + scsi_track_queue_full(sdev, depth); + break; + case SCSI_QDEPTH_RAMP_UP: + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); + break; + default: + return -EOPNOTSUPP; + } + return sdev->queue_depth; +} + +/* + * Main entry point from struct scsi_host_template for incoming SCSI CDB+Data + * from Linux/SCSI subsystem for SCSI low level device drivers (LLDs) + */ +static int tcm_loop_queuecommand( + struct Scsi_Host *sh, + struct scsi_cmnd *sc) +{ + struct se_cmd *se_cmd; + struct se_portal_group *se_tpg; + struct tcm_loop_hba *tl_hba; + struct tcm_loop_tpg *tl_tpg; + + TL_CDB_DEBUG("tcm_loop_queuecommand() %d:%d:%d:%d got CDB: 0x%02x" + " scsi_buf_len: %u\n", sc->device->host->host_no, + sc->device->id, sc->device->channel, sc->device->lun, + sc->cmnd[0], scsi_bufflen(sc)); + /* + * Locate the tcm_loop_hba_t pointer + */ + tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); + tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; + se_tpg = &tl_tpg->tl_se_tpg; + /* + * Determine the SAM Task Attribute and allocate tl_cmd and + * tl_cmd->tl_se_cmd from TCM infrastructure + */ + se_cmd = tcm_loop_allocate_core_cmd(tl_hba, se_tpg, sc); + if (!se_cmd) { + sc->scsi_done(sc); + return 0; + } + /* + * Queue up the newly allocated to be processed in TCM thread context. + */ + transport_generic_handle_cdb_map(se_cmd); + return 0; +} + +/* + * Called from SCSI EH process context to issue a LUN_RESET TMR + * to struct scsi_device + */ +static int tcm_loop_device_reset(struct scsi_cmnd *sc) +{ + struct se_cmd *se_cmd = NULL; + struct se_portal_group *se_tpg; + struct se_session *se_sess; + struct tcm_loop_cmd *tl_cmd = NULL; + struct tcm_loop_hba *tl_hba; + struct tcm_loop_nexus *tl_nexus; + struct tcm_loop_tmr *tl_tmr = NULL; + struct tcm_loop_tpg *tl_tpg; + int ret = FAILED; + /* + * Locate the tcm_loop_hba_t pointer + */ + tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); + /* + * Locate the tl_nexus and se_sess pointers + */ + tl_nexus = tl_hba->tl_nexus; + if (!tl_nexus) { + printk(KERN_ERR "Unable to perform device reset without" + " active I_T Nexus\n"); + return FAILED; + } + se_sess = tl_nexus->se_sess; + /* + * Locate the tl_tpg and se_tpg pointers from TargetID in sc->device->id + */ + tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; + se_tpg = &tl_tpg->tl_se_tpg; + + tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_KERNEL); + if (!tl_cmd) { + printk(KERN_ERR "Unable to allocate memory for tl_cmd\n"); + return FAILED; + } + + tl_tmr = kzalloc(sizeof(struct tcm_loop_tmr), GFP_KERNEL); + if (!tl_tmr) { + printk(KERN_ERR "Unable to allocate memory for tl_tmr\n"); + goto release; + } + init_waitqueue_head(&tl_tmr->tl_tmr_wait); + + se_cmd = &tl_cmd->tl_se_cmd; + /* + * Initialize struct se_cmd descriptor from target_core_mod infrastructure + */ + transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, 0, + DMA_NONE, TASK_ATTR_SIMPLE, + &tl_cmd->tl_sense_buf[0]); + /* + * Allocate the LUN_RESET TMR + */ + se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, (void *)tl_tmr, + TMR_LUN_RESET); + if (!se_cmd->se_tmr_req) + goto release; + /* + * Locate the underlying TCM struct se_lun from sc->device->lun + */ + if (transport_get_lun_for_tmr(se_cmd, sc->device->lun) < 0) + goto release; + /* + * Queue the TMR to TCM Core and sleep waiting for tcm_loop_queue_tm_rsp() + * to wake us up. + */ + transport_generic_handle_tmr(se_cmd); + wait_event(tl_tmr->tl_tmr_wait, atomic_read(&tl_tmr->tmr_complete)); + /* + * The TMR LUN_RESET has completed, check the response status and + * then release allocations. + */ + ret = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? + SUCCESS : FAILED; +release: + if (se_cmd) + transport_generic_free_cmd(se_cmd, 1, 1, 0); + else + kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); + kfree(tl_tmr); + return ret; +} + +static int tcm_loop_slave_alloc(struct scsi_device *sd) +{ + set_bit(QUEUE_FLAG_BIDI, &sd->request_queue->queue_flags); + return 0; +} + +static int tcm_loop_slave_configure(struct scsi_device *sd) +{ + return 0; +} + +static struct scsi_host_template tcm_loop_driver_template = { + .proc_info = tcm_loop_proc_info, + .proc_name = "tcm_loopback", + .name = "TCM_Loopback", + .queuecommand = tcm_loop_queuecommand, + .change_queue_depth = tcm_loop_change_queue_depth, + .eh_device_reset_handler = tcm_loop_device_reset, + .can_queue = TL_SCSI_CAN_QUEUE, + .this_id = -1, + .sg_tablesize = TL_SCSI_SG_TABLESIZE, + .cmd_per_lun = TL_SCSI_CMD_PER_LUN, + .max_sectors = TL_SCSI_MAX_SECTORS, + .use_clustering = DISABLE_CLUSTERING, + .slave_alloc = tcm_loop_slave_alloc, + .slave_configure = tcm_loop_slave_configure, + .module = THIS_MODULE, +}; + +static int tcm_loop_driver_probe(struct device *dev) +{ + struct tcm_loop_hba *tl_hba; + struct Scsi_Host *sh; + int error; + + tl_hba = to_tcm_loop_hba(dev); + + sh = scsi_host_alloc(&tcm_loop_driver_template, + sizeof(struct tcm_loop_hba)); + if (!sh) { + printk(KERN_ERR "Unable to allocate struct scsi_host\n"); + return -ENODEV; + } + tl_hba->sh = sh; + + /* + * Assign the struct tcm_loop_hba pointer to struct Scsi_Host->hostdata + */ + *((struct tcm_loop_hba **)sh->hostdata) = tl_hba; + /* + * Setup single ID, Channel and LUN for now.. + */ + sh->max_id = 2; + sh->max_lun = 0; + sh->max_channel = 0; + sh->max_cmd_len = TL_SCSI_MAX_CMD_LEN; + + error = scsi_add_host(sh, &tl_hba->dev); + if (error) { + printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); + scsi_host_put(sh); + return -ENODEV; + } + return 0; +} + +static int tcm_loop_driver_remove(struct device *dev) +{ + struct tcm_loop_hba *tl_hba; + struct Scsi_Host *sh; + + tl_hba = to_tcm_loop_hba(dev); + sh = tl_hba->sh; + + scsi_remove_host(sh); + scsi_host_put(sh); + return 0; +} + +static void tcm_loop_release_adapter(struct device *dev) +{ + struct tcm_loop_hba *tl_hba = to_tcm_loop_hba(dev); + + kfree(tl_hba); +} + +/* + * Called from tcm_loop_make_scsi_hba() in tcm_loop_configfs.c + */ +static int tcm_loop_setup_hba_bus(struct tcm_loop_hba *tl_hba, int tcm_loop_host_id) +{ + int ret; + + tl_hba->dev.bus = &tcm_loop_lld_bus; + tl_hba->dev.parent = tcm_loop_primary; + tl_hba->dev.release = &tcm_loop_release_adapter; + dev_set_name(&tl_hba->dev, "tcm_loop_adapter_%d", tcm_loop_host_id); + + ret = device_register(&tl_hba->dev); + if (ret) { + printk(KERN_ERR "device_register() failed for" + " tl_hba->dev: %d\n", ret); + return -ENODEV; + } + + return 0; +} + +/* + * Called from tcm_loop_fabric_init() in tcl_loop_fabric.c to load the emulated + * tcm_loop SCSI bus. + */ +static int tcm_loop_alloc_core_bus(void) +{ + int ret; + + tcm_loop_primary = root_device_register("tcm_loop_0"); + if (IS_ERR(tcm_loop_primary)) { + printk(KERN_ERR "Unable to allocate tcm_loop_primary\n"); + return PTR_ERR(tcm_loop_primary); + } + + ret = bus_register(&tcm_loop_lld_bus); + if (ret) { + printk(KERN_ERR "bus_register() failed for tcm_loop_lld_bus\n"); + goto dev_unreg; + } + + ret = driver_register(&tcm_loop_driverfs); + if (ret) { + printk(KERN_ERR "driver_register() failed for" + "tcm_loop_driverfs\n"); + goto bus_unreg; + } + + printk(KERN_INFO "Initialized TCM Loop Core Bus\n"); + return ret; + +bus_unreg: + bus_unregister(&tcm_loop_lld_bus); +dev_unreg: + root_device_unregister(tcm_loop_primary); + return ret; +} + +static void tcm_loop_release_core_bus(void) +{ + driver_unregister(&tcm_loop_driverfs); + bus_unregister(&tcm_loop_lld_bus); + root_device_unregister(tcm_loop_primary); + + printk(KERN_INFO "Releasing TCM Loop Core BUS\n"); +} + +static char *tcm_loop_get_fabric_name(void) +{ + return "loopback"; +} + +static u8 tcm_loop_get_fabric_proto_ident(struct se_portal_group *se_tpg) +{ + struct tcm_loop_tpg *tl_tpg = + (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + /* + * tl_proto_id is set at tcm_loop_configfs.c:tcm_loop_make_scsi_hba() + * time based on the protocol dependent prefix of the passed configfs group. + * + * Based upon tl_proto_id, TCM_Loop emulates the requested fabric + * ProtocolID using target_core_fabric_lib.c symbols. + */ + switch (tl_hba->tl_proto_id) { + case SCSI_PROTOCOL_SAS: + return sas_get_fabric_proto_ident(se_tpg); + case SCSI_PROTOCOL_FCP: + return fc_get_fabric_proto_ident(se_tpg); + case SCSI_PROTOCOL_ISCSI: + return iscsi_get_fabric_proto_ident(se_tpg); + default: + printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" + " SAS emulation\n", tl_hba->tl_proto_id); + break; + } + + return sas_get_fabric_proto_ident(se_tpg); +} + +static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) +{ + struct tcm_loop_tpg *tl_tpg = + (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + /* + * Return the passed NAA identifier for the SAS Target Port + */ + return &tl_tpg->tl_hba->tl_wwn_address[0]; +} + +static u16 tcm_loop_get_tag(struct se_portal_group *se_tpg) +{ + struct tcm_loop_tpg *tl_tpg = + (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + /* + * This Tag is used when forming SCSI Name identifier in EVPD=1 0x83 + * to represent the SCSI Target Port. + */ + return tl_tpg->tl_tpgt; +} + +static u32 tcm_loop_get_default_depth(struct se_portal_group *se_tpg) +{ + return 1; +} + +static u32 tcm_loop_get_pr_transport_id( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code, + unsigned char *buf) +{ + struct tcm_loop_tpg *tl_tpg = + (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + + switch (tl_hba->tl_proto_id) { + case SCSI_PROTOCOL_SAS: + return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, + format_code, buf); + case SCSI_PROTOCOL_FCP: + return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg, + format_code, buf); + case SCSI_PROTOCOL_ISCSI: + return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg, + format_code, buf); + default: + printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" + " SAS emulation\n", tl_hba->tl_proto_id); + break; + } + + return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, + format_code, buf); +} + +static u32 tcm_loop_get_pr_transport_id_len( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code) +{ + struct tcm_loop_tpg *tl_tpg = + (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + + switch (tl_hba->tl_proto_id) { + case SCSI_PROTOCOL_SAS: + return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, + format_code); + case SCSI_PROTOCOL_FCP: + return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, + format_code); + case SCSI_PROTOCOL_ISCSI: + return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, + format_code); + default: + printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" + " SAS emulation\n", tl_hba->tl_proto_id); + break; + } + + return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, + format_code); +} + +/* + * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above + * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations. + */ +static char *tcm_loop_parse_pr_out_transport_id( + struct se_portal_group *se_tpg, + const char *buf, + u32 *out_tid_len, + char **port_nexus_ptr) +{ + struct tcm_loop_tpg *tl_tpg = + (struct tcm_loop_tpg *)se_tpg->se_tpg_fabric_ptr; + struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + + switch (tl_hba->tl_proto_id) { + case SCSI_PROTOCOL_SAS: + return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, + port_nexus_ptr); + case SCSI_PROTOCOL_FCP: + return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, + port_nexus_ptr); + case SCSI_PROTOCOL_ISCSI: + return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, + port_nexus_ptr); + default: + printk(KERN_ERR "Unknown tl_proto_id: 0x%02x, using" + " SAS emulation\n", tl_hba->tl_proto_id); + break; + } + + return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, + port_nexus_ptr); +} + +/* + * Returning (1) here allows for target_core_mod struct se_node_acl to be generated + * based upon the incoming fabric dependent SCSI Initiator Port + */ +static int tcm_loop_check_demo_mode(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int tcm_loop_check_demo_mode_cache(struct se_portal_group *se_tpg) +{ + return 0; +} + +/* + * Allow I_T Nexus full READ-WRITE access without explict Initiator Node ACLs for + * local virtual Linux/SCSI LLD passthrough into VM hypervisor guest + */ +static int tcm_loop_check_demo_mode_write_protect(struct se_portal_group *se_tpg) +{ + return 0; +} + +/* + * Because TCM_Loop does not use explict ACLs and MappedLUNs, this will + * never be called for TCM_Loop by target_core_fabric_configfs.c code. + * It has been added here as a nop for target_fabric_tf_ops_check() + */ +static int tcm_loop_check_prod_mode_write_protect(struct se_portal_group *se_tpg) +{ + return 0; +} + +static struct se_node_acl *tcm_loop_tpg_alloc_fabric_acl( + struct se_portal_group *se_tpg) +{ + struct tcm_loop_nacl *tl_nacl; + + tl_nacl = kzalloc(sizeof(struct tcm_loop_nacl), GFP_KERNEL); + if (!tl_nacl) { + printk(KERN_ERR "Unable to allocate struct tcm_loop_nacl\n"); + return NULL; + } + + return &tl_nacl->se_node_acl; +} + +static void tcm_loop_tpg_release_fabric_acl( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl) +{ + struct tcm_loop_nacl *tl_nacl = container_of(se_nacl, + struct tcm_loop_nacl, se_node_acl); + + kfree(tl_nacl); +} + +static u32 tcm_loop_get_inst_index(struct se_portal_group *se_tpg) +{ + return 1; +} + +static void tcm_loop_new_cmd_failure(struct se_cmd *se_cmd) +{ + /* + * Since TCM_loop is already passing struct scatterlist data from + * struct scsi_cmnd, no more Linux/SCSI failure dependent state need + * to be handled here. + */ + return; +} + +static int tcm_loop_is_state_remove(struct se_cmd *se_cmd) +{ + /* + * Assume struct scsi_cmnd is not in remove state.. + */ + return 0; +} + +static int tcm_loop_sess_logged_in(struct se_session *se_sess) +{ + /* + * Assume that TL Nexus is always active + */ + return 1; +} + +static u32 tcm_loop_sess_get_index(struct se_session *se_sess) +{ + return 1; +} + +static void tcm_loop_set_default_node_attributes(struct se_node_acl *se_acl) +{ + return; +} + +static u32 tcm_loop_get_task_tag(struct se_cmd *se_cmd) +{ + return 1; +} + +static int tcm_loop_get_cmd_state(struct se_cmd *se_cmd) +{ + struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, + struct tcm_loop_cmd, tl_se_cmd); + + return tl_cmd->sc_cmd_state; +} + +static int tcm_loop_shutdown_session(struct se_session *se_sess) +{ + return 0; +} + +static void tcm_loop_close_session(struct se_session *se_sess) +{ + return; +}; + +static void tcm_loop_stop_session( + struct se_session *se_sess, + int sess_sleep, + int conn_sleep) +{ + return; +} + +static void tcm_loop_fall_back_to_erl0(struct se_session *se_sess) +{ + return; +} + +static int tcm_loop_write_pending(struct se_cmd *se_cmd) +{ + /* + * Since Linux/SCSI has already sent down a struct scsi_cmnd + * sc->sc_data_direction of DMA_TO_DEVICE with struct scatterlist array + * memory, and memory has already been mapped to struct se_cmd->t_mem_list + * format with transport_generic_map_mem_to_cmd(). + * + * We now tell TCM to add this WRITE CDB directly into the TCM storage + * object execution queue. + */ + transport_generic_process_write(se_cmd); + return 0; +} + +static int tcm_loop_write_pending_status(struct se_cmd *se_cmd) +{ + return 0; +} + +static int tcm_loop_queue_data_in(struct se_cmd *se_cmd) +{ + struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, + struct tcm_loop_cmd, tl_se_cmd); + struct scsi_cmnd *sc = tl_cmd->sc; + + TL_CDB_DEBUG("tcm_loop_queue_data_in() called for scsi_cmnd: %p" + " cdb: 0x%02x\n", sc, sc->cmnd[0]); + + sc->result = SAM_STAT_GOOD; + set_host_byte(sc, DID_OK); + sc->scsi_done(sc); + return 0; +} + +static int tcm_loop_queue_status(struct se_cmd *se_cmd) +{ + struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, + struct tcm_loop_cmd, tl_se_cmd); + struct scsi_cmnd *sc = tl_cmd->sc; + + TL_CDB_DEBUG("tcm_loop_queue_status() called for scsi_cmnd: %p" + " cdb: 0x%02x\n", sc, sc->cmnd[0]); + + if (se_cmd->sense_buffer && + ((se_cmd->se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || + (se_cmd->se_cmd_flags & SCF_EMULATED_TASK_SENSE))) { + + memcpy((void *)sc->sense_buffer, (void *)se_cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE); + sc->result = SAM_STAT_CHECK_CONDITION; + set_driver_byte(sc, DRIVER_SENSE); + } else + sc->result = se_cmd->scsi_status; + + set_host_byte(sc, DID_OK); + sc->scsi_done(sc); + return 0; +} + +static int tcm_loop_queue_tm_rsp(struct se_cmd *se_cmd) +{ + struct se_tmr_req *se_tmr = se_cmd->se_tmr_req; + struct tcm_loop_tmr *tl_tmr = se_tmr->fabric_tmr_ptr; + /* + * The SCSI EH thread will be sleeping on se_tmr->tl_tmr_wait, go ahead + * and wake up the wait_queue_head_t in tcm_loop_device_reset() + */ + atomic_set(&tl_tmr->tmr_complete, 1); + wake_up(&tl_tmr->tl_tmr_wait); + return 0; +} + +static u16 tcm_loop_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length) +{ + return 0; +} + +static u16 tcm_loop_get_fabric_sense_len(void) +{ + return 0; +} + +static u64 tcm_loop_pack_lun(unsigned int lun) +{ + u64 result; + + /* LSB of lun into byte 1 big-endian */ + result = ((lun & 0xff) << 8); + /* use flat space addressing method */ + result |= 0x40 | ((lun >> 8) & 0x3f); + + return cpu_to_le64(result); +} + +static char *tcm_loop_dump_proto_id(struct tcm_loop_hba *tl_hba) +{ + switch (tl_hba->tl_proto_id) { + case SCSI_PROTOCOL_SAS: + return "SAS"; + case SCSI_PROTOCOL_FCP: + return "FCP"; + case SCSI_PROTOCOL_ISCSI: + return "iSCSI"; + default: + break; + } + + return "Unknown"; +} + +/* Start items for tcm_loop_port_cit */ + +static int tcm_loop_port_link( + struct se_portal_group *se_tpg, + struct se_lun *lun) +{ + struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, + struct tcm_loop_tpg, tl_se_tpg); + struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + + atomic_inc(&tl_tpg->tl_tpg_port_count); + smp_mb__after_atomic_inc(); + /* + * Add Linux/SCSI struct scsi_device by HCTL + */ + scsi_add_device(tl_hba->sh, 0, tl_tpg->tl_tpgt, lun->unpacked_lun); + + printk(KERN_INFO "TCM_Loop_ConfigFS: Port Link Successful\n"); + return 0; +} + +static void tcm_loop_port_unlink( + struct se_portal_group *se_tpg, + struct se_lun *se_lun) +{ + struct scsi_device *sd; + struct tcm_loop_hba *tl_hba; + struct tcm_loop_tpg *tl_tpg; + + tl_tpg = container_of(se_tpg, struct tcm_loop_tpg, tl_se_tpg); + tl_hba = tl_tpg->tl_hba; + + sd = scsi_device_lookup(tl_hba->sh, 0, tl_tpg->tl_tpgt, + se_lun->unpacked_lun); + if (!sd) { + printk(KERN_ERR "Unable to locate struct scsi_device for %d:%d:" + "%d\n", 0, tl_tpg->tl_tpgt, se_lun->unpacked_lun); + return; + } + /* + * Remove Linux/SCSI struct scsi_device by HCTL + */ + scsi_remove_device(sd); + scsi_device_put(sd); + + atomic_dec(&tl_tpg->tl_tpg_port_count); + smp_mb__after_atomic_dec(); + + printk(KERN_INFO "TCM_Loop_ConfigFS: Port Unlink Successful\n"); +} + +/* End items for tcm_loop_port_cit */ + +/* Start items for tcm_loop_nexus_cit */ + +static int tcm_loop_make_nexus( + struct tcm_loop_tpg *tl_tpg, + const char *name) +{ + struct se_portal_group *se_tpg; + struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + struct tcm_loop_nexus *tl_nexus; + + if (tl_tpg->tl_hba->tl_nexus) { + printk(KERN_INFO "tl_tpg->tl_hba->tl_nexus already exists\n"); + return -EEXIST; + } + se_tpg = &tl_tpg->tl_se_tpg; + + tl_nexus = kzalloc(sizeof(struct tcm_loop_nexus), GFP_KERNEL); + if (!tl_nexus) { + printk(KERN_ERR "Unable to allocate struct tcm_loop_nexus\n"); + return -ENOMEM; + } + /* + * Initialize the struct se_session pointer + */ + tl_nexus->se_sess = transport_init_session(); + if (!tl_nexus->se_sess) + goto out; + /* + * Since we are running in 'demo mode' this call with generate a + * struct se_node_acl for the tcm_loop struct se_portal_group with the SCSI + * Initiator port name of the passed configfs group 'name'. + */ + tl_nexus->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( + se_tpg, (unsigned char *)name); + if (!tl_nexus->se_sess->se_node_acl) { + transport_free_session(tl_nexus->se_sess); + goto out; + } + /* + * Now, register the SAS I_T Nexus as active with the call to + * transport_register_session() + */ + __transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, + tl_nexus->se_sess, (void *)tl_nexus); + tl_tpg->tl_hba->tl_nexus = tl_nexus; + printk(KERN_INFO "TCM_Loop_ConfigFS: Established I_T Nexus to emulated" + " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), + name); + return 0; + +out: + kfree(tl_nexus); + return -ENOMEM; +} + +static int tcm_loop_drop_nexus( + struct tcm_loop_tpg *tpg) +{ + struct se_session *se_sess; + struct tcm_loop_nexus *tl_nexus; + struct tcm_loop_hba *tl_hba = tpg->tl_hba; + + tl_nexus = tpg->tl_hba->tl_nexus; + if (!tl_nexus) + return -ENODEV; + + se_sess = tl_nexus->se_sess; + if (!se_sess) + return -ENODEV; + + if (atomic_read(&tpg->tl_tpg_port_count)) { + printk(KERN_ERR "Unable to remove TCM_Loop I_T Nexus with" + " active TPG port count: %d\n", + atomic_read(&tpg->tl_tpg_port_count)); + return -EPERM; + } + + printk(KERN_INFO "TCM_Loop_ConfigFS: Removing I_T Nexus to emulated" + " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tl_hba), + tl_nexus->se_sess->se_node_acl->initiatorname); + /* + * Release the SCSI I_T Nexus to the emulated SAS Target Port + */ + transport_deregister_session(tl_nexus->se_sess); + tpg->tl_hba->tl_nexus = NULL; + kfree(tl_nexus); + return 0; +} + +/* End items for tcm_loop_nexus_cit */ + +static ssize_t tcm_loop_tpg_show_nexus( + struct se_portal_group *se_tpg, + char *page) +{ + struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, + struct tcm_loop_tpg, tl_se_tpg); + struct tcm_loop_nexus *tl_nexus; + ssize_t ret; + + tl_nexus = tl_tpg->tl_hba->tl_nexus; + if (!tl_nexus) + return -ENODEV; + + ret = snprintf(page, PAGE_SIZE, "%s\n", + tl_nexus->se_sess->se_node_acl->initiatorname); + + return ret; +} + +static ssize_t tcm_loop_tpg_store_nexus( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, + struct tcm_loop_tpg, tl_se_tpg); + struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba; + unsigned char i_port[TL_WWN_ADDR_LEN], *ptr, *port_ptr; + int ret; + /* + * Shutdown the active I_T nexus if 'NULL' is passed.. + */ + if (!strncmp(page, "NULL", 4)) { + ret = tcm_loop_drop_nexus(tl_tpg); + return (!ret) ? count : ret; + } + /* + * Otherwise make sure the passed virtual Initiator port WWN matches + * the fabric protocol_id set in tcm_loop_make_scsi_hba(), and call + * tcm_loop_make_nexus() + */ + if (strlen(page) > TL_WWN_ADDR_LEN) { + printk(KERN_ERR "Emulated NAA Sas Address: %s, exceeds" + " max: %d\n", page, TL_WWN_ADDR_LEN); + return -EINVAL; + } + snprintf(&i_port[0], TL_WWN_ADDR_LEN, "%s", page); + + ptr = strstr(i_port, "naa."); + if (ptr) { + if (tl_hba->tl_proto_id != SCSI_PROTOCOL_SAS) { + printk(KERN_ERR "Passed SAS Initiator Port %s does not" + " match target port protoid: %s\n", i_port, + tcm_loop_dump_proto_id(tl_hba)); + return -EINVAL; + } + port_ptr = &i_port[0]; + goto check_newline; + } + ptr = strstr(i_port, "fc."); + if (ptr) { + if (tl_hba->tl_proto_id != SCSI_PROTOCOL_FCP) { + printk(KERN_ERR "Passed FCP Initiator Port %s does not" + " match target port protoid: %s\n", i_port, + tcm_loop_dump_proto_id(tl_hba)); + return -EINVAL; + } + port_ptr = &i_port[3]; /* Skip over "fc." */ + goto check_newline; + } + ptr = strstr(i_port, "iqn."); + if (ptr) { + if (tl_hba->tl_proto_id != SCSI_PROTOCOL_ISCSI) { + printk(KERN_ERR "Passed iSCSI Initiator Port %s does not" + " match target port protoid: %s\n", i_port, + tcm_loop_dump_proto_id(tl_hba)); + return -EINVAL; + } + port_ptr = &i_port[0]; + goto check_newline; + } + printk(KERN_ERR "Unable to locate prefix for emulated Initiator Port:" + " %s\n", i_port); + return -EINVAL; + /* + * Clear any trailing newline for the NAA WWN + */ +check_newline: + if (i_port[strlen(i_port)-1] == '\n') + i_port[strlen(i_port)-1] = '\0'; + + ret = tcm_loop_make_nexus(tl_tpg, port_ptr); + if (ret < 0) + return ret; + + return count; +} + +TF_TPG_BASE_ATTR(tcm_loop, nexus, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *tcm_loop_tpg_attrs[] = { + &tcm_loop_tpg_nexus.attr, + NULL, +}; + +/* Start items for tcm_loop_naa_cit */ + +struct se_portal_group *tcm_loop_make_naa_tpg( + struct se_wwn *wwn, + struct config_group *group, + const char *name) +{ + struct tcm_loop_hba *tl_hba = container_of(wwn, + struct tcm_loop_hba, tl_hba_wwn); + struct tcm_loop_tpg *tl_tpg; + char *tpgt_str, *end_ptr; + int ret; + unsigned short int tpgt; + + tpgt_str = strstr(name, "tpgt_"); + if (!tpgt_str) { + printk(KERN_ERR "Unable to locate \"tpgt_#\" directory" + " group\n"); + return ERR_PTR(-EINVAL); + } + tpgt_str += 5; /* Skip ahead of "tpgt_" */ + tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0); + + if (tpgt > TL_TPGS_PER_HBA) { + printk(KERN_ERR "Passed tpgt: %hu exceeds TL_TPGS_PER_HBA:" + " %u\n", tpgt, TL_TPGS_PER_HBA); + return ERR_PTR(-EINVAL); + } + tl_tpg = &tl_hba->tl_hba_tpgs[tpgt]; + tl_tpg->tl_hba = tl_hba; + tl_tpg->tl_tpgt = tpgt; + /* + * Register the tl_tpg as a emulated SAS TCM Target Endpoint + */ + ret = core_tpg_register(&tcm_loop_fabric_configfs->tf_ops, + wwn, &tl_tpg->tl_se_tpg, (void *)tl_tpg, + TRANSPORT_TPG_TYPE_NORMAL); + if (ret < 0) + return ERR_PTR(-ENOMEM); + + printk(KERN_INFO "TCM_Loop_ConfigFS: Allocated Emulated %s" + " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), + config_item_name(&wwn->wwn_group.cg_item), tpgt); + + return &tl_tpg->tl_se_tpg; +} + +void tcm_loop_drop_naa_tpg( + struct se_portal_group *se_tpg) +{ + struct se_wwn *wwn = se_tpg->se_tpg_wwn; + struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, + struct tcm_loop_tpg, tl_se_tpg); + struct tcm_loop_hba *tl_hba; + unsigned short tpgt; + + tl_hba = tl_tpg->tl_hba; + tpgt = tl_tpg->tl_tpgt; + /* + * Release the I_T Nexus for the Virtual SAS link if present + */ + tcm_loop_drop_nexus(tl_tpg); + /* + * Deregister the tl_tpg as a emulated SAS TCM Target Endpoint + */ + core_tpg_deregister(se_tpg); + + printk(KERN_INFO "TCM_Loop_ConfigFS: Deallocated Emulated %s" + " Target Port %s,t,0x%04x\n", tcm_loop_dump_proto_id(tl_hba), + config_item_name(&wwn->wwn_group.cg_item), tpgt); +} + +/* End items for tcm_loop_naa_cit */ + +/* Start items for tcm_loop_cit */ + +struct se_wwn *tcm_loop_make_scsi_hba( + struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct tcm_loop_hba *tl_hba; + struct Scsi_Host *sh; + char *ptr; + int ret, off = 0; + + tl_hba = kzalloc(sizeof(struct tcm_loop_hba), GFP_KERNEL); + if (!tl_hba) { + printk(KERN_ERR "Unable to allocate struct tcm_loop_hba\n"); + return ERR_PTR(-ENOMEM); + } + /* + * Determine the emulated Protocol Identifier and Target Port Name + * based on the incoming configfs directory name. + */ + ptr = strstr(name, "naa."); + if (ptr) { + tl_hba->tl_proto_id = SCSI_PROTOCOL_SAS; + goto check_len; + } + ptr = strstr(name, "fc."); + if (ptr) { + tl_hba->tl_proto_id = SCSI_PROTOCOL_FCP; + off = 3; /* Skip over "fc." */ + goto check_len; + } + ptr = strstr(name, "iqn."); + if (ptr) { + tl_hba->tl_proto_id = SCSI_PROTOCOL_ISCSI; + goto check_len; + } + + printk(KERN_ERR "Unable to locate prefix for emulated Target Port:" + " %s\n", name); + return ERR_PTR(-EINVAL); + +check_len: + if (strlen(name) > TL_WWN_ADDR_LEN) { + printk(KERN_ERR "Emulated NAA %s Address: %s, exceeds" + " max: %d\n", name, tcm_loop_dump_proto_id(tl_hba), + TL_WWN_ADDR_LEN); + kfree(tl_hba); + return ERR_PTR(-EINVAL); + } + snprintf(&tl_hba->tl_wwn_address[0], TL_WWN_ADDR_LEN, "%s", &name[off]); + + /* + * Call device_register(tl_hba->dev) to register the emulated + * Linux/SCSI LLD of type struct Scsi_Host at tl_hba->sh after + * device_register() callbacks in tcm_loop_driver_probe() + */ + ret = tcm_loop_setup_hba_bus(tl_hba, tcm_loop_hba_no_cnt); + if (ret) + goto out; + + sh = tl_hba->sh; + tcm_loop_hba_no_cnt++; + printk(KERN_INFO "TCM_Loop_ConfigFS: Allocated emulated Target" + " %s Address: %s at Linux/SCSI Host ID: %d\n", + tcm_loop_dump_proto_id(tl_hba), name, sh->host_no); + + return &tl_hba->tl_hba_wwn; +out: + kfree(tl_hba); + return ERR_PTR(ret); +} + +void tcm_loop_drop_scsi_hba( + struct se_wwn *wwn) +{ + struct tcm_loop_hba *tl_hba = container_of(wwn, + struct tcm_loop_hba, tl_hba_wwn); + int host_no = tl_hba->sh->host_no; + /* + * Call device_unregister() on the original tl_hba->dev. + * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will + * release *tl_hba; + */ + device_unregister(&tl_hba->dev); + + printk(KERN_INFO "TCM_Loop_ConfigFS: Deallocated emulated Target" + " SAS Address: %s at Linux/SCSI Host ID: %d\n", + config_item_name(&wwn->wwn_group.cg_item), host_no); +} + +/* Start items for tcm_loop_cit */ +static ssize_t tcm_loop_wwn_show_attr_version( + struct target_fabric_configfs *tf, + char *page) +{ + return sprintf(page, "TCM Loopback Fabric module %s\n", TCM_LOOP_VERSION); +} + +TF_WWN_ATTR_RO(tcm_loop, version); + +static struct configfs_attribute *tcm_loop_wwn_attrs[] = { + &tcm_loop_wwn_version.attr, + NULL, +}; + +/* End items for tcm_loop_cit */ + +static int tcm_loop_register_configfs(void) +{ + struct target_fabric_configfs *fabric; + struct config_group *tf_cg; + int ret; + /* + * Set the TCM Loop HBA counter to zero + */ + tcm_loop_hba_no_cnt = 0; + /* + * Register the top level struct config_item_type with TCM core + */ + fabric = target_fabric_configfs_init(THIS_MODULE, "loopback"); + if (!fabric) { + printk(KERN_ERR "tcm_loop_register_configfs() failed!\n"); + return -1; + } + /* + * Setup the fabric API of function pointers used by target_core_mod + */ + fabric->tf_ops.get_fabric_name = &tcm_loop_get_fabric_name; + fabric->tf_ops.get_fabric_proto_ident = &tcm_loop_get_fabric_proto_ident; + fabric->tf_ops.tpg_get_wwn = &tcm_loop_get_endpoint_wwn; + fabric->tf_ops.tpg_get_tag = &tcm_loop_get_tag; + fabric->tf_ops.tpg_get_default_depth = &tcm_loop_get_default_depth; + fabric->tf_ops.tpg_get_pr_transport_id = &tcm_loop_get_pr_transport_id; + fabric->tf_ops.tpg_get_pr_transport_id_len = + &tcm_loop_get_pr_transport_id_len; + fabric->tf_ops.tpg_parse_pr_out_transport_id = + &tcm_loop_parse_pr_out_transport_id; + fabric->tf_ops.tpg_check_demo_mode = &tcm_loop_check_demo_mode; + fabric->tf_ops.tpg_check_demo_mode_cache = + &tcm_loop_check_demo_mode_cache; + fabric->tf_ops.tpg_check_demo_mode_write_protect = + &tcm_loop_check_demo_mode_write_protect; + fabric->tf_ops.tpg_check_prod_mode_write_protect = + &tcm_loop_check_prod_mode_write_protect; + /* + * The TCM loopback fabric module runs in demo-mode to a local + * virtual SCSI device, so fabric dependent initator ACLs are + * not required. + */ + fabric->tf_ops.tpg_alloc_fabric_acl = &tcm_loop_tpg_alloc_fabric_acl; + fabric->tf_ops.tpg_release_fabric_acl = + &tcm_loop_tpg_release_fabric_acl; + fabric->tf_ops.tpg_get_inst_index = &tcm_loop_get_inst_index; + /* + * Since tcm_loop is mapping physical memory from Linux/SCSI + * struct scatterlist arrays for each struct scsi_cmnd I/O, + * we do not need TCM to allocate a iovec array for + * virtual memory address mappings + */ + fabric->tf_ops.alloc_cmd_iovecs = NULL; + /* + * Used for setting up remaining TCM resources in process context + */ + fabric->tf_ops.new_cmd_map = &tcm_loop_new_cmd_map; + fabric->tf_ops.check_stop_free = &tcm_loop_check_stop_free; + fabric->tf_ops.release_cmd_to_pool = &tcm_loop_deallocate_core_cmd; + fabric->tf_ops.release_cmd_direct = &tcm_loop_deallocate_core_cmd; + fabric->tf_ops.shutdown_session = &tcm_loop_shutdown_session; + fabric->tf_ops.close_session = &tcm_loop_close_session; + fabric->tf_ops.stop_session = &tcm_loop_stop_session; + fabric->tf_ops.fall_back_to_erl0 = &tcm_loop_fall_back_to_erl0; + fabric->tf_ops.sess_logged_in = &tcm_loop_sess_logged_in; + fabric->tf_ops.sess_get_index = &tcm_loop_sess_get_index; + fabric->tf_ops.sess_get_initiator_sid = NULL; + fabric->tf_ops.write_pending = &tcm_loop_write_pending; + fabric->tf_ops.write_pending_status = &tcm_loop_write_pending_status; + /* + * Not used for TCM loopback + */ + fabric->tf_ops.set_default_node_attributes = + &tcm_loop_set_default_node_attributes; + fabric->tf_ops.get_task_tag = &tcm_loop_get_task_tag; + fabric->tf_ops.get_cmd_state = &tcm_loop_get_cmd_state; + fabric->tf_ops.new_cmd_failure = &tcm_loop_new_cmd_failure; + fabric->tf_ops.queue_data_in = &tcm_loop_queue_data_in; + fabric->tf_ops.queue_status = &tcm_loop_queue_status; + fabric->tf_ops.queue_tm_rsp = &tcm_loop_queue_tm_rsp; + fabric->tf_ops.set_fabric_sense_len = &tcm_loop_set_fabric_sense_len; + fabric->tf_ops.get_fabric_sense_len = &tcm_loop_get_fabric_sense_len; + fabric->tf_ops.is_state_remove = &tcm_loop_is_state_remove; + fabric->tf_ops.pack_lun = &tcm_loop_pack_lun; + + tf_cg = &fabric->tf_group; + /* + * Setup function pointers for generic logic in target_core_fabric_configfs.c + */ + fabric->tf_ops.fabric_make_wwn = &tcm_loop_make_scsi_hba; + fabric->tf_ops.fabric_drop_wwn = &tcm_loop_drop_scsi_hba; + fabric->tf_ops.fabric_make_tpg = &tcm_loop_make_naa_tpg; + fabric->tf_ops.fabric_drop_tpg = &tcm_loop_drop_naa_tpg; + /* + * fabric_post_link() and fabric_pre_unlink() are used for + * registration and release of TCM Loop Virtual SCSI LUNs. + */ + fabric->tf_ops.fabric_post_link = &tcm_loop_port_link; + fabric->tf_ops.fabric_pre_unlink = &tcm_loop_port_unlink; + fabric->tf_ops.fabric_make_np = NULL; + fabric->tf_ops.fabric_drop_np = NULL; + /* + * Setup default attribute lists for various fabric->tf_cit_tmpl + */ + TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_loop_wwn_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_loop_tpg_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; + /* + * Once fabric->tf_ops has been setup, now register the fabric for + * use within TCM + */ + ret = target_fabric_configfs_register(fabric); + if (ret < 0) { + printk(KERN_ERR "target_fabric_configfs_register() for" + " TCM_Loop failed!\n"); + target_fabric_configfs_free(fabric); + return -1; + } + /* + * Setup our local pointer to *fabric. + */ + tcm_loop_fabric_configfs = fabric; + printk(KERN_INFO "TCM_LOOP[0] - Set fabric ->" + " tcm_loop_fabric_configfs\n"); + return 0; +} + +static void tcm_loop_deregister_configfs(void) +{ + if (!tcm_loop_fabric_configfs) + return; + + target_fabric_configfs_deregister(tcm_loop_fabric_configfs); + tcm_loop_fabric_configfs = NULL; + printk(KERN_INFO "TCM_LOOP[0] - Cleared" + " tcm_loop_fabric_configfs\n"); +} + +static int __init tcm_loop_fabric_init(void) +{ + int ret; + + tcm_loop_cmd_cache = kmem_cache_create("tcm_loop_cmd_cache", + sizeof(struct tcm_loop_cmd), + __alignof__(struct tcm_loop_cmd), + 0, NULL); + if (!tcm_loop_cmd_cache) { + printk(KERN_ERR "kmem_cache_create() for" + " tcm_loop_cmd_cache failed\n"); + return -ENOMEM; + } + + ret = tcm_loop_alloc_core_bus(); + if (ret) + return ret; + + ret = tcm_loop_register_configfs(); + if (ret) { + tcm_loop_release_core_bus(); + return ret; + } + + return 0; +} + +static void __exit tcm_loop_fabric_exit(void) +{ + tcm_loop_deregister_configfs(); + tcm_loop_release_core_bus(); + kmem_cache_destroy(tcm_loop_cmd_cache); +} + +MODULE_DESCRIPTION("TCM loopback virtual Linux/SCSI fabric module"); +MODULE_AUTHOR("Nicholas A. Bellinger "); +MODULE_LICENSE("GPL"); +module_init(tcm_loop_fabric_init); +module_exit(tcm_loop_fabric_exit); diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h new file mode 100644 index 000000000000..7e9f7ab45548 --- /dev/null +++ b/drivers/target/loopback/tcm_loop.h @@ -0,0 +1,77 @@ +#define TCM_LOOP_VERSION "v2.1-rc1" +#define TL_WWN_ADDR_LEN 256 +#define TL_TPGS_PER_HBA 32 +/* + * Defaults for struct scsi_host_template tcm_loop_driver_template + * + * We use large can_queue and cmd_per_lun here and let TCM enforce + * the underlying se_device_t->queue_depth. + */ +#define TL_SCSI_CAN_QUEUE 1024 +#define TL_SCSI_CMD_PER_LUN 1024 +#define TL_SCSI_MAX_SECTORS 1024 +#define TL_SCSI_SG_TABLESIZE 256 +/* + * Used in tcm_loop_driver_probe() for struct Scsi_Host->max_cmd_len + */ +#define TL_SCSI_MAX_CMD_LEN 32 + +#ifdef CONFIG_LOOPBACK_TARGET_CDB_DEBUG +# define TL_CDB_DEBUG(x...) printk(KERN_INFO x) +#else +# define TL_CDB_DEBUG(x...) +#endif + +struct tcm_loop_cmd { + /* State of Linux/SCSI CDB+Data descriptor */ + u32 sc_cmd_state; + /* Pointer to the CDB+Data descriptor from Linux/SCSI subsystem */ + struct scsi_cmnd *sc; + struct list_head *tl_cmd_list; + /* The TCM I/O descriptor that is accessed via container_of() */ + struct se_cmd tl_se_cmd; + /* Sense buffer that will be mapped into outgoing status */ + unsigned char tl_sense_buf[TRANSPORT_SENSE_BUFFER]; +}; + +struct tcm_loop_tmr { + atomic_t tmr_complete; + wait_queue_head_t tl_tmr_wait; +}; + +struct tcm_loop_nexus { + int it_nexus_active; + /* + * Pointer to Linux/SCSI HBA from linux/include/scsi_host.h + */ + struct scsi_host *sh; + /* + * Pointer to TCM session for I_T Nexus + */ + struct se_session *se_sess; +}; + +struct tcm_loop_nacl { + struct se_node_acl se_node_acl; +}; + +struct tcm_loop_tpg { + unsigned short tl_tpgt; + atomic_t tl_tpg_port_count; + struct se_portal_group tl_se_tpg; + struct tcm_loop_hba *tl_hba; +}; + +struct tcm_loop_hba { + u8 tl_proto_id; + unsigned char tl_wwn_address[TL_WWN_ADDR_LEN]; + struct se_hba_s *se_hba; + struct se_lun *tl_hba_lun; + struct se_port *tl_hba_lun_sep; + struct se_device_s *se_dev_hba_ptr; + struct tcm_loop_nexus *tl_nexus; + struct device dev; + struct Scsi_Host *sh; + struct tcm_loop_tpg tl_hba_tpgs[TL_TPGS_PER_HBA]; + struct se_wwn tl_hba_wwn; +}; -- cgit v1.2.2 From be36cacdddcc119ef7b33ae0b91631c3535a75ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 22 Mar 2011 11:00:37 +0100 Subject: iwlagn: fix error in command waiting Clearly a mistake, since pointers won't suddenly change their value... Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 2003c1d4295f..08ccb9496f76 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2265,7 +2265,7 @@ signed long iwlagn_wait_notification(struct iwl_priv *priv, int ret; ret = wait_event_timeout(priv->_agn.notif_waitq, - &wait_entry->triggered, + wait_entry->triggered, timeout); spin_lock_bh(&priv->_agn.notif_wait_lock); -- cgit v1.2.2 From a3ad38e87eead6ce748c6e4eec0571ce53b5a0c2 Mon Sep 17 00:00:00 2001 From: "armadefuego@gmail.com" Date: Tue, 22 Mar 2011 09:49:15 -0700 Subject: orinoco: Clear dangling pointer on hardware busy On hardware busy the scan request pointer should be cleared, as higher levels will release. This avoids a crash when that pointer is erroneously used later. Signed-off-by: Joseph J. Gunn Signed-off-by: John W. Linville --- drivers/net/wireless/orinoco/cfg.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index 09fae2f0ea08..736bbb9bd1d0 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -153,6 +153,9 @@ static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, priv->scan_request = request; err = orinoco_hw_trigger_scan(priv, request->ssids); + /* On error the we aren't processing the request */ + if (err) + priv->scan_request = NULL; return err; } -- cgit v1.2.2 From 19b9675069cb06ae17d1595ac517d475d75e6bb9 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 23 Mar 2011 23:07:21 +0530 Subject: ath9k: Fix kernel panic caused by invalid rate index access. With the recent tx status optimization in mac80211, we bail out as and and when invalid rate index is found. So the behavior of resetting rate idx to -1 and count to 0 has changed for the rate indexes that were not part of the driver's retry series. This has resulted in ath9k using incorrect rate table index which caused the system to panic. Ideally ath9k need to loop only for the indexes that were part of the retry series and so simply use hw->max_rates as the loop counter. Pasted the stack trace of the panic issue for reference. [ 754.093192] BUG: unable to handle kernel paging request at ffff88046a9025b0 [ 754.093256] IP: [] ath_tx_status+0x209/0x2f0 [ath9k] [ 754.094888] Call Trace: [ 754.094903] [ 754.094928] [] ieee80211_tx_status+0x203/0x9e0 [mac80211] [ 754.094975] [] ? __ieee80211_wake_queue+0x125/0x140 [mac80211] [ 754.095017] [] ath_tx_complete_buf+0x1b9/0x370 [ath9k] [ 754.095054] [] ath_tx_complete_aggr+0x51f/0xb50 [ath9k] [ 754.095098] [] ? ieee80211_prepare_and_rx_handle+0x173/0xab0 [mac80211] [ 754.095148] [] ? _raw_spin_unlock_irqrestore+0x32/0x40 [ 754.095186] [] ath_tx_tasklet+0x365/0x4b0 [ath9k] [ 754.095224] [] ? clockevents_program_event+0x62/0xa0 [ 754.095261] [] ath9k_tasklet+0x168/0x1c0 [ath9k] [ 754.095298] [] tasklet_action+0x6b/0xe0 [ 754.095331] [] __do_softirq+0x98/0x120 [ 754.095361] [] call_softirq+0x1c/0x30 [ 754.095393] [] do_softirq+0x65/0xa0 [ 754.095423] [] irq_exit+0x8d/0x90 [ 754.095453] [] do_IRQ+0x61/0xe0 [ 754.095482] [] ret_from_intr+0x0/0x15 [ 754.095513] [ 754.095531] [] ? native_sched_clock+0x15/0x70 [ 754.096475] [] ? acpi_idle_enter_bm+0x24d/0x285 [processor] [ 754.096475] [] ? acpi_idle_enter_bm+0x246/0x285 [processor] [ 754.096475] [] cpuidle_idle_call+0x82/0x100 [ 754.096475] [] cpu_idle+0xa6/0xf0 [ 754.096475] [] rest_init+0x91/0xa0 [ 754.096475] [] start_kernel+0x3fd/0x408 [ 754.096475] [] x86_64_start_reservations+0x132/0x136 [ 754.096475] [] x86_64_start_kernel+0x106/0x115 [ 754.096475] RIP [] ath_tx_status+0x209/0x2f0 [ath9k] Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 960d717ca7c2..a3241cd089b1 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1328,7 +1328,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + for (i = 0; i < sc->hw->max_rates; i++) { struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; if (!rate->count) break; -- cgit v1.2.2 From d78f4b3e2c4dfb9487624f7157af04ab4260e189 Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Wed, 23 Mar 2011 23:07:22 +0530 Subject: ath9k: Fix TX queue stuck issue. commit 86271e460a66003dc1f4cbfd845adafb790b7587 introduced a regression that caused mac80211 queues in stopped state. ath_drain_all_txq is called in driver flush which would reset the stopped flag and the mac80211 queues were never started after that. iperf traffic is completely stalled due to this issue. Restart the mac80211 queues in driver flush only if the txqs were drained. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 115f162c617a..524825720a09 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2160,6 +2160,8 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) if (!ath_drain_all_txq(sc, false)) ath_reset(sc, false); + ieee80211_wake_queues(hw); + out: ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0); mutex_unlock(&sc->mutex); -- cgit v1.2.2 From b6055006b26de15aaa66870809b3d63b334737ce Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:37:23 +0000 Subject: mlx4_en: going out of range of TX rings when reporting stats Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c index 7f5a3221e0c1..a2b0bc4ada5d 100644 --- a/drivers/net/mlx4/en_port.c +++ b/drivers/net/mlx4/en_port.c @@ -206,7 +206,7 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) } stats->tx_packets = 0; stats->tx_bytes = 0; - for (i = 0; i <= priv->tx_ring_num; i++) { + for (i = 0; i < priv->tx_ring_num; i++) { stats->tx_packets += priv->tx_ring[i].packets; stats->tx_bytes += priv->tx_ring[i].bytes; } -- cgit v1.2.2 From 39f17b44aaaa6bc47ded0bbb17fc617ec6cf08bb Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:37:28 +0000 Subject: mlx4_en: moderation parameters are not reseted. Instead of reseting the module parameters each ifup or mtu change, they are being set once at device initialization Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 897f576b8b17..56627c26d918 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -801,7 +801,6 @@ static int mlx4_en_open(struct net_device *dev) priv->rx_ring[i].packets = 0; } - mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) en_err(priv, "Failed starting port:%d\n", priv->port); @@ -932,7 +931,6 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) en_dbg(DRV, priv, "Change MTU called with card down!?\n"); } else { mlx4_en_stop_port(dev); - mlx4_en_set_default_moderation(priv); err = mlx4_en_start_port(dev); if (err) { en_err(priv, "Failed restarting port:%d\n", @@ -1080,6 +1078,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); priv->registered = 1; + mlx4_en_set_default_moderation(priv); queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); return 0; -- cgit v1.2.2 From 46afd0fb01d62ee217f142ab9c26054304ab7454 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:37:36 +0000 Subject: mlx4_en: optimize adaptive moderation algorithm for better latency Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 18 +++++------------- drivers/net/mlx4/mlx4_en.h | 1 + 2 files changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 56627c26d918..b1180dd5e173 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -417,7 +417,6 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) unsigned long avg_pkt_size; unsigned long rx_packets; unsigned long rx_bytes; - unsigned long rx_byte_diff; unsigned long tx_packets; unsigned long tx_pkt_diff; unsigned long rx_pkt_diff; @@ -441,25 +440,20 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) rx_pkt_diff = ((unsigned long) (rx_packets - priv->last_moder_packets)); packets = max(tx_pkt_diff, rx_pkt_diff); - rx_byte_diff = rx_bytes - priv->last_moder_bytes; - rx_byte_diff = rx_byte_diff ? rx_byte_diff : 1; rate = packets * HZ / period; avg_pkt_size = packets ? ((unsigned long) (rx_bytes - priv->last_moder_bytes)) / packets : 0; /* Apply auto-moderation only when packet rate exceeds a rate that * it matters */ - if (rate > MLX4_EN_RX_RATE_THRESH) { + if (rate > MLX4_EN_RX_RATE_THRESH && avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { /* If tx and rx packet rates are not balanced, assume that * traffic is mainly BW bound and apply maximum moderation. * Otherwise, moderate according to packet rate */ - if (2 * tx_pkt_diff > 3 * rx_pkt_diff && - rx_pkt_diff / rx_byte_diff < - MLX4_EN_SMALL_PKT_SIZE) - moder_time = priv->rx_usecs_low; - else if (2 * rx_pkt_diff > 3 * tx_pkt_diff) + if (2 * tx_pkt_diff > 3 * rx_pkt_diff || + 2 * rx_pkt_diff > 3 * tx_pkt_diff) { moder_time = priv->rx_usecs_high; - else { + } else { if (rate < priv->pkt_rate_low) moder_time = priv->rx_usecs_low; else if (rate > priv->pkt_rate_high) @@ -471,9 +465,7 @@ static void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) priv->rx_usecs_low; } } else { - /* When packet rate is low, use default moderation rather than - * 0 to prevent interrupt storms if traffic suddenly increases */ - moder_time = priv->rx_usecs; + moder_time = priv->rx_usecs_low; } en_dbg(INTR, priv, "tx rate:%lu rx_rate:%lu\n", diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index dfed6a07c2d7..5387c4e9f295 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -124,6 +124,7 @@ enum { #define MLX4_EN_RX_SIZE_THRESH 1024 #define MLX4_EN_RX_RATE_THRESH (1000000 / MLX4_EN_RX_COAL_TIME_HIGH) #define MLX4_EN_SAMPLE_INTERVAL 0 +#define MLX4_EN_AVG_PKT_SMALL 256 #define MLX4_EN_AUTO_CONF 0xffff -- cgit v1.2.2 From 908222655b38005483d64385e06341a38647fdf1 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:37:41 +0000 Subject: mlx4_en: bringing link up when registering netdevice Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index b1180dd5e173..5727bf5ad452 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -1069,6 +1069,23 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num); en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); + /* Configure port */ + err = mlx4_SET_PORT_general(mdev->dev, priv->port, + MLX4_EN_MIN_MTU, + 0, 0, 0, 0); + if (err) { + en_err(priv, "Failed setting port general configurations " + "for port %d, with error %d\n", priv->port, err); + goto out; + } + + /* Init port */ + en_warn(priv, "Initializing port\n"); + err = mlx4_INIT_PORT(mdev->dev, priv->port); + if (err) { + en_err(priv, "Failed Initializing port\n"); + goto out; + } priv->registered = 1; mlx4_en_set_default_moderation(priv); queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); -- cgit v1.2.2 From 0b7ca5a928e2271bbc225e9e1ac1f22e9fbee54f Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:37:47 +0000 Subject: mlx4: Changing interrupt scheme Adding a pool of MSI-X vectors and EQs that can be used explicitly by mlx4_core customers (mlx4_ib, mlx4_en). The consumers will assign their own names to the interrupt vectors. Those vectors are not opened at mlx4 device initialization, opened by demand. Changed the max number of possible EQs according to the new scheme, no longer relies on on number of cores. The new functionality is exposed through mlx4_assign_eq() and mlx4_release_eq(). Customers that do not use the new API will get completion vectors as before. Signed-off-by: Markuze Alex Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/cq.c | 2 +- drivers/net/mlx4/eq.c | 107 ++++++++++++++++++++++++++++++++++++++++++--- drivers/net/mlx4/main.c | 20 +++++++-- drivers/net/mlx4/mlx4.h | 6 +++ drivers/net/mlx4/profile.c | 4 +- 5 files changed, 126 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 7cd34e9c7c7e..bd8ef9f2fa71 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -198,7 +198,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, u64 mtt_addr; int err; - if (vector >= dev->caps.num_comp_vectors) + if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool) return -EINVAL; cq->vector = vector; diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 552d0fce6f67..506cfd0372ec 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -42,7 +42,7 @@ #include "fw.h" enum { - MLX4_IRQNAME_SIZE = 64 + MLX4_IRQNAME_SIZE = 32 }; enum { @@ -317,8 +317,8 @@ static int mlx4_num_eq_uar(struct mlx4_dev *dev) * we need to map, take the difference of highest index and * the lowest index we'll use and add 1. */ - return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs) / 4 - - dev->caps.reserved_eqs / 4 + 1; + return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + + dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; } static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) @@ -496,16 +496,32 @@ static void mlx4_free_eq(struct mlx4_dev *dev, static void mlx4_free_irqs(struct mlx4_dev *dev) { struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; - int i; + struct mlx4_priv *priv = mlx4_priv(dev); + int i, vec; if (eq_table->have_irq) free_irq(dev->pdev->irq, dev); + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) if (eq_table->eq[i].have_irq) { free_irq(eq_table->eq[i].irq, eq_table->eq + i); eq_table->eq[i].have_irq = 0; } + for (i = 0; i < dev->caps.comp_pool; i++) { + /* + * Freeing the assigned irq's + * all bits should be 0, but we need to validate + */ + if (priv->msix_ctl.pool_bm & 1ULL << i) { + /* NO need protecting*/ + vec = dev->caps.num_comp_vectors + 1 + i; + free_irq(priv->eq_table.eq[vec].irq, + &priv->eq_table.eq[vec]); + } + } + + kfree(eq_table->irq_names); } @@ -578,7 +594,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) (priv->eq_table.inta_pin < 32 ? 4 : 0); priv->eq_table.irq_names = - kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1), + kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + + dev->caps.comp_pool), GFP_KERNEL); if (!priv->eq_table.irq_names) { err = -ENOMEM; @@ -601,6 +618,22 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) if (err) goto err_out_comp; + /*if additional completion vectors poolsize is 0 this loop will not run*/ + for (i = dev->caps.num_comp_vectors + 1; + i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { + + err = mlx4_create_eq(dev, dev->caps.num_cqs - + dev->caps.reserved_cqs + + MLX4_NUM_SPARE_EQE, + (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, + &priv->eq_table.eq[i]); + if (err) { + --i; + goto err_out_unmap; + } + } + + if (dev->flags & MLX4_FLAG_MSI_X) { const char *eq_name; @@ -686,7 +719,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) mlx4_free_irqs(dev); - for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) + for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) mlx4_free_eq(dev, &priv->eq_table.eq[i]); mlx4_unmap_clr_int(dev); @@ -743,3 +776,65 @@ int mlx4_test_interrupts(struct mlx4_dev *dev) return err; } EXPORT_SYMBOL(mlx4_test_interrupts); + +int mlx4_assign_eq(struct mlx4_dev *dev, char* name, int * vector) +{ + + struct mlx4_priv *priv = mlx4_priv(dev); + int vec = 0, err = 0, i; + + spin_lock(&priv->msix_ctl.pool_lock); + for (i = 0; !vec && i < dev->caps.comp_pool; i++) { + if (~priv->msix_ctl.pool_bm & 1ULL << i) { + priv->msix_ctl.pool_bm |= 1ULL << i; + vec = dev->caps.num_comp_vectors + 1 + i; + snprintf(priv->eq_table.irq_names + + vec * MLX4_IRQNAME_SIZE, + MLX4_IRQNAME_SIZE, "%s", name); + err = request_irq(priv->eq_table.eq[vec].irq, + mlx4_msi_x_interrupt, 0, + &priv->eq_table.irq_names[vec<<5], + priv->eq_table.eq + vec); + if (err) { + /*zero out bit by fliping it*/ + priv->msix_ctl.pool_bm ^= 1 << i; + vec = 0; + continue; + /*we dont want to break here*/ + } + eq_set_ci(&priv->eq_table.eq[vec], 1); + } + } + spin_unlock(&priv->msix_ctl.pool_lock); + + if (vec) { + *vector = vec; + } else { + *vector = 0; + err = (i == dev->caps.comp_pool) ? -ENOSPC : err; + } + return err; +} +EXPORT_SYMBOL(mlx4_assign_eq); + +void mlx4_release_eq(struct mlx4_dev *dev, int vec) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + /*bm index*/ + int i = vec - dev->caps.num_comp_vectors - 1; + + if (likely(i >= 0)) { + /*sanity check , making sure were not trying to free irq's + Belonging to a legacy EQ*/ + spin_lock(&priv->msix_ctl.pool_lock); + if (priv->msix_ctl.pool_bm & 1ULL << i) { + free_irq(priv->eq_table.eq[vec].irq, + &priv->eq_table.eq[vec]); + priv->msix_ctl.pool_bm &= ~(1ULL << i); + } + spin_unlock(&priv->msix_ctl.pool_lock); + } + +} +EXPORT_SYMBOL(mlx4_release_eq); + diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 2765a3ce9c24..517ca34f5b37 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -969,13 +969,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); struct msix_entry *entries; - int nreq; + int nreq = min_t(int, dev->caps.num_ports * + min_t(int, num_online_cpus() + 1, MAX_MSIX_P_PORT) + + MSIX_LEGACY_SZ, MAX_MSIX); int err; int i; if (msi_x) { nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, - num_possible_cpus() + 1); + nreq); entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); if (!entries) goto no_msi; @@ -998,7 +1000,15 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) goto no_msi; } - dev->caps.num_comp_vectors = nreq - 1; + if (nreq < + MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) { + /*Working in legacy mode , all EQ's shared*/ + dev->caps.comp_pool = 0; + dev->caps.num_comp_vectors = nreq - 1; + } else { + dev->caps.comp_pool = nreq - MSIX_LEGACY_SZ; + dev->caps.num_comp_vectors = MSIX_LEGACY_SZ - 1; + } for (i = 0; i < nreq; ++i) priv->eq_table.eq[i].irq = entries[i].vector; @@ -1010,6 +1020,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) no_msi: dev->caps.num_comp_vectors = 1; + dev->caps.comp_pool = 0; for (i = 0; i < 2; ++i) priv->eq_table.eq[i].irq = dev->pdev->irq; @@ -1151,6 +1162,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto err_close; + priv->msix_ctl.pool_bm = 0; + spin_lock_init(&priv->msix_ctl.pool_lock); + mlx4_enable_msi_x(dev); err = mlx4_setup_hca(dev); diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 0da5bb7285b4..67ee8dacae79 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -282,6 +282,11 @@ struct mlx4_sense { struct delayed_work sense_poll; }; +struct mlx4_msix_ctl { + u64 pool_bm; + spinlock_t pool_lock; +}; + struct mlx4_priv { struct mlx4_dev dev; @@ -313,6 +318,7 @@ struct mlx4_priv { struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; struct mlx4_sense sense; struct mutex port_mutex; + struct mlx4_msix_ctl msix_ctl; }; static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) diff --git a/drivers/net/mlx4/profile.c b/drivers/net/mlx4/profile.c index e749f82865fe..b967647d0c76 100644 --- a/drivers/net/mlx4/profile.c +++ b/drivers/net/mlx4/profile.c @@ -107,9 +107,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, profile[MLX4_RES_AUXC].num = request->num_qp; profile[MLX4_RES_SRQ].num = request->num_srq; profile[MLX4_RES_CQ].num = request->num_cq; - profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, - dev_cap->reserved_eqs + - num_possible_cpus() + 1); + profile[MLX4_RES_EQ].num = min_t(unsigned, dev_cap->max_eqs, MAX_MSIX); profile[MLX4_RES_DMPT].num = request->num_mpt; profile[MLX4_RES_CMPT].num = MLX4_NUM_CMPTS; profile[MLX4_RES_MTT].num = request->num_mtt; -- cgit v1.2.2 From 1fb9876e9bf895ea4127ff17180f1b2ab37771b6 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:37:52 +0000 Subject: mlx4_en: using new mlx4 interrupt scheme Each RX ring will have its own interrupt vector, and TX rings will share one (we mostly use polling for TX completions). The vectors are assigned first time device is opened, and its name includes the interface name and ring number. Signed-off-by: Markuze Alex Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_cq.c | 38 +++++++++++++++++++++++++++++++------- drivers/net/mlx4/en_ethtool.c | 2 +- drivers/net/mlx4/en_main.c | 20 +++++++++++--------- drivers/net/mlx4/en_netdev.c | 18 ++++++++++++++---- drivers/net/mlx4/mlx4_en.h | 7 +++++-- 5 files changed, 62 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c index 21786ad4455e..ec4b6d047fe0 100644 --- a/drivers/net/mlx4/en_cq.c +++ b/drivers/net/mlx4/en_cq.c @@ -51,13 +51,10 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, int err; cq->size = entries; - if (mode == RX) { + if (mode == RX) cq->buf_size = cq->size * sizeof(struct mlx4_cqe); - cq->vector = ring % mdev->dev->caps.num_comp_vectors; - } else { + else cq->buf_size = sizeof(struct mlx4_cqe); - cq->vector = 0; - } cq->ring = ring; cq->is_tx = mode; @@ -80,7 +77,8 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) { struct mlx4_en_dev *mdev = priv->mdev; - int err; + int err = 0; + char name[25]; cq->dev = mdev->pndev[priv->port]; cq->mcq.set_ci_db = cq->wqres.db.db; @@ -89,6 +87,29 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) *cq->mcq.arm_db = 0; memset(cq->buf, 0, cq->buf_size); + if (cq->is_tx == RX) { + if (mdev->dev->caps.comp_pool) { + if (!cq->vector) { + sprintf(name , "%s-rx-%d", priv->dev->name, cq->ring); + if (mlx4_assign_eq(mdev->dev, name, &cq->vector)) { + cq->vector = (cq->ring + 1 + priv->port) % + mdev->dev->caps.num_comp_vectors; + mlx4_warn(mdev, "Failed Assigning an EQ to " + "%s_rx-%d ,Falling back to legacy EQ's\n", + priv->dev->name, cq->ring); + } + } + } else { + cq->vector = (cq->ring + 1 + priv->port) % + mdev->dev->caps.num_comp_vectors; + } + } else { + if (!cq->vector || !mdev->dev->caps.comp_pool) { + /*Fallback to legacy pool in case of error*/ + cq->vector = 0; + } + } + if (!cq->is_tx) cq->size = priv->rx_ring[cq->ring].actual_size; @@ -112,12 +133,15 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) return 0; } -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) +void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, + bool reserve_vectors) { struct mlx4_en_dev *mdev = priv->mdev; mlx4_en_unmap_buffer(&cq->wqres.buf); mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); + if (priv->mdev->dev->caps.comp_pool && cq->vector && !reserve_vectors) + mlx4_release_eq(priv->mdev->dev, cq->vector); cq->buf_size = 0; cq->buf = NULL; } diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index 056152b3ff58..8cfe8586ed2d 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -388,7 +388,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev, mlx4_en_stop_port(dev); } - mlx4_en_free_resources(priv); + mlx4_en_free_resources(priv, true); priv->prof->tx_ring_size = tx_size; priv->prof->rx_ring_size = rx_size; diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 1ff6ca6466ed..29aaa4303991 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -241,16 +241,18 @@ static void *mlx4_en_add(struct mlx4_dev *dev) mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) mdev->port_cnt++; - /* If we did not receive an explicit number of Rx rings, default to - * the number of completion vectors populated by the mlx4_core */ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - mlx4_info(mdev, "Using %d tx rings for port:%d\n", - mdev->profile.prof[i].tx_ring_num, i); - mdev->profile.prof[i].rx_ring_num = min_t(int, - roundup_pow_of_two(dev->caps.num_comp_vectors), - MAX_RX_RINGS); - mlx4_info(mdev, "Defaulting to %d rx rings for port:%d\n", - mdev->profile.prof[i].rx_ring_num, i); + if (!dev->caps.comp_pool) { + mdev->profile.prof[i].rx_ring_num = + rounddown_pow_of_two(max_t(int, MIN_RX_RINGS, + min_t(int, + dev->caps.num_comp_vectors, + MAX_RX_RINGS))); + } else { + mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two( + min_t(int, dev->caps.comp_pool/ + dev->caps.num_ports - 1 , MAX_MSIX_P_PORT - 1)); + } } /* Create our own workqueue for reset/multicast tasks diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 5727bf5ad452..f6ed315b4b89 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -557,6 +557,7 @@ int mlx4_en_start_port(struct net_device *dev) int err = 0; int i; int j; + char name[32]; if (priv->port_up) { en_dbg(DRV, priv, "start port called while port already up\n"); @@ -601,10 +602,19 @@ int mlx4_en_start_port(struct net_device *dev) goto cq_err; } + if (mdev->dev->caps.comp_pool && !priv->tx_vector) { + sprintf(name , "%s-tx", priv->dev->name); + if (mlx4_assign_eq(mdev->dev , name, &priv->tx_vector)) { + mlx4_warn(mdev, "Failed Assigning an EQ to " + "%s_tx ,Falling back to legacy " + "EQ's\n", priv->dev->name); + } + } /* Configure tx cq's and rings */ for (i = 0; i < priv->tx_ring_num; i++) { /* Configure cq */ cq = &priv->tx_cq[i]; + cq->vector = priv->tx_vector; err = mlx4_en_activate_cq(priv, cq); if (err) { en_err(priv, "Failed allocating Tx CQ\n"); @@ -819,7 +829,7 @@ static int mlx4_en_close(struct net_device *dev) return 0; } -void mlx4_en_free_resources(struct mlx4_en_priv *priv) +void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors) { int i; @@ -827,14 +837,14 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) if (priv->tx_ring[i].tx_info) mlx4_en_destroy_tx_ring(priv, &priv->tx_ring[i]); if (priv->tx_cq[i].buf) - mlx4_en_destroy_cq(priv, &priv->tx_cq[i]); + mlx4_en_destroy_cq(priv, &priv->tx_cq[i], reserve_vectors); } for (i = 0; i < priv->rx_ring_num; i++) { if (priv->rx_ring[i].rx_info) mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i]); if (priv->rx_cq[i].buf) - mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); + mlx4_en_destroy_cq(priv, &priv->rx_cq[i], reserve_vectors); } } @@ -896,7 +906,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev) mdev->pndev[priv->port] = NULL; mutex_unlock(&mdev->state_lock); - mlx4_en_free_resources(priv); + mlx4_en_free_resources(priv, false); free_netdev(dev); } diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 5387c4e9f295..2db245fcd84b 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -62,6 +62,7 @@ #define MLX4_EN_PAGE_SHIFT 12 #define MLX4_EN_PAGE_SIZE (1 << MLX4_EN_PAGE_SHIFT) #define MAX_RX_RINGS 16 +#define MIN_RX_RINGS 4 #define TXBB_SIZE 64 #define HEADROOM (2048 / TXBB_SIZE + 1) #define STAMP_STRIDE 64 @@ -462,6 +463,7 @@ struct mlx4_en_priv { u16 log_rx_info; struct mlx4_en_tx_ring tx_ring[MAX_TX_RINGS]; + int tx_vector; struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS]; struct mlx4_en_cq tx_cq[MAX_TX_RINGS]; struct mlx4_en_cq rx_cq[MAX_RX_RINGS]; @@ -487,12 +489,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, int mlx4_en_start_port(struct net_device *dev); void mlx4_en_stop_port(struct net_device *dev); -void mlx4_en_free_resources(struct mlx4_en_priv *priv); +void mlx4_en_free_resources(struct mlx4_en_priv *priv, bool reserve_vectors); int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, int entries, int ring, enum cq_type mode); -void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); +void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, + bool reserve_vectors); int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); -- cgit v1.2.2 From 14c07b1358ede1664652bb9b28d9ace5fe6f7f92 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:37:59 +0000 Subject: mlx4: Wake on LAN support The driver queries the FW for WOL support. Ethtool get/set_wol is implemented accordingly. Only magic packets are supported at the time. Signed-off-by: Igor Yarovinsky Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_ethtool.c | 62 +++++++++++++++++++++++++++++++++++++++++-- drivers/net/mlx4/fw.c | 20 ++++++++++++++ drivers/net/mlx4/fw.h | 1 + drivers/net/mlx4/main.c | 1 + drivers/net/mlx4/mlx4_en.h | 7 +++++ 5 files changed, 89 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index 8cfe8586ed2d..c1f351f6ae57 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -131,8 +131,65 @@ static void mlx4_en_set_msglevel(struct net_device *dev, u32 val) static void mlx4_en_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { - wol->supported = 0; - wol->wolopts = 0; + struct mlx4_en_priv *priv = netdev_priv(netdev); + int err = 0; + u64 config = 0; + + if (!priv->mdev->dev->caps.wol) { + wol->supported = 0; + wol->wolopts = 0; + return; + } + + err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); + if (err) { + en_err(priv, "Failed to get WoL information\n"); + return; + } + + if (config & MLX4_EN_WOL_MAGIC) + wol->supported = WAKE_MAGIC; + else + wol->supported = 0; + + if (config & MLX4_EN_WOL_ENABLED) + wol->wolopts = WAKE_MAGIC; + else + wol->wolopts = 0; +} + +static int mlx4_en_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct mlx4_en_priv *priv = netdev_priv(netdev); + u64 config = 0; + int err = 0; + + if (!priv->mdev->dev->caps.wol) + return -EOPNOTSUPP; + + if (wol->supported & ~WAKE_MAGIC) + return -EINVAL; + + err = mlx4_wol_read(priv->mdev->dev, &config, priv->port); + if (err) { + en_err(priv, "Failed to get WoL info, unable to modify\n"); + return err; + } + + if (wol->wolopts & WAKE_MAGIC) { + config |= MLX4_EN_WOL_DO_MODIFY | MLX4_EN_WOL_ENABLED | + MLX4_EN_WOL_MAGIC; + } else { + config &= ~(MLX4_EN_WOL_ENABLED | MLX4_EN_WOL_MAGIC); + config |= MLX4_EN_WOL_DO_MODIFY; + } + + err = mlx4_wol_write(priv->mdev->dev, config, priv->port); + if (err) + en_err(priv, "Failed to set WoL information\n"); + + return err; } static int mlx4_en_get_sset_count(struct net_device *dev, int sset) @@ -442,6 +499,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { .get_ethtool_stats = mlx4_en_get_ethtool_stats, .self_test = mlx4_en_self_test, .get_wol = mlx4_en_get_wol, + .set_wol = mlx4_en_set_wol, .get_msglevel = mlx4_en_get_msglevel, .set_msglevel = mlx4_en_set_msglevel, .get_coalesce = mlx4_en_get_coalesce, diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 5de1db897835..fd1c51b6197a 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -276,6 +276,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->udp_rss = field & 0x1; MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); dev_cap->loopback_support = field & 0x1; + dev_cap->wol = field & 0x40; MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET); MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_UAR_OFFSET); dev_cap->reserved_uars = field >> 4; @@ -908,3 +909,22 @@ int mlx4_NOP(struct mlx4_dev *dev) /* Input modifier of 0x1f means "finish as soon as possible." */ return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100); } + +#define MLX4_WOL_SETUP_MODE (5 << 28) +int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) +{ + u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; + + return mlx4_cmd_imm(dev, 0, config, in_mod, 0x3, + MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A); +} +EXPORT_SYMBOL_GPL(mlx4_wol_read); + +int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port) +{ + u32 in_mod = MLX4_WOL_SETUP_MODE | port << 8; + + return mlx4_cmd(dev, config, in_mod, 0x1, MLX4_CMD_MOD_STAT_CFG, + MLX4_CMD_TIME_CLASS_A); +} +EXPORT_SYMBOL_GPL(mlx4_wol_write); diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index 65cc72eb899d..f7b9cc2d1b2a 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h @@ -80,6 +80,7 @@ struct mlx4_dev_cap { u16 stat_rate_support; int udp_rss; int loopback_support; + int wol; u32 flags; int reserved_uars; int uar_size; diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 517ca34f5b37..42d4fb477870 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -227,6 +227,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.stat_rate_support = dev_cap->stat_rate_support; dev->caps.udp_rss = dev_cap->udp_rss; dev->caps.loopback_support = dev_cap->loopback_support; + dev->caps.wol = dev_cap->wol; dev->caps.max_gso_sz = dev_cap->max_gso_sz; dev->caps.log_num_macs = log_num_mac; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 2db245fcd84b..07aea8d0beeb 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -479,6 +479,13 @@ struct mlx4_en_priv { int mc_addrs_cnt; struct mlx4_en_stat_out_mbox hw_stats; int vids[128]; + bool wol; +}; + +enum mlx4_en_wol { + MLX4_EN_WOL_MAGIC = (1ULL << 61), + MLX4_EN_WOL_ENABLED = (1ULL << 62), + MLX4_EN_WOL_DO_MODIFY = (1ULL << 63), }; -- cgit v1.2.2 From 725c89997e03d71b09ea3c17c997da0712b9d835 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:38:07 +0000 Subject: mlx4_en: Reporting HW revision in ethtool -i HW revision is derived from device ID and rev id. Signed-off-by: Eugenia Emantayev Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/main.c | 1 - drivers/net/mlx4/en_ethtool.c | 15 ++++++++++++++- drivers/net/mlx4/main.c | 2 ++ drivers/net/mlx4/mlx4_en.h | 3 +++ 4 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index c7a6213c6996..66e3eecfd0db 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -721,7 +721,6 @@ static int init_node_data(struct mlx4_ib_dev *dev) if (err) goto out; - dev->dev->rev_id = be32_to_cpup((__be32 *) (out_mad->data + 32)); memcpy(&dev->ib_dev.node_guid, out_mad->data + 12, 8); out: diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index c1f351f6ae57..62ace6c72b42 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -45,7 +45,20 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); + switch (mdev->dev->rev_id) { + case 0xa0: + if (dev->dev_id >= MLX4_EN_CX3_LOW_ID && dev->dev_id <= MLX4_EN_CX3_HIGH_ID) + sprintf(drvinfo->driver, DRV_NAME " (%s_CX-3)", mdev->dev->board_id); + else + sprintf(drvinfo->driver, DRV_NAME " (%s_CX)", mdev->dev->board_id); + break; + case 0xb0: + sprintf(drvinfo->driver, DRV_NAME " (%s_CX-2)", mdev->dev->board_id); + break; + default: + sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); + break; + } strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); sprintf(drvinfo->fw_version, "%d.%d.%d", (u16) (mdev->dev->caps.fw_ver >> 32), diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 42d4fb477870..5bebb8800ab2 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1139,6 +1139,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&priv->pgdir_list); mutex_init(&priv->pgdir_mutex); + pci_read_config_byte(pdev, PCI_REVISION_ID, &dev->rev_id); + /* * Now reset the HCA before we touch the PCI capabilities or * attempt a firmware command, since a boot ROM may have left diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 07aea8d0beeb..ad4df66750bc 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -216,6 +216,9 @@ struct mlx4_en_tx_desc { #define MLX4_EN_USE_SRQ 0x01000000 +#define MLX4_EN_CX3_LOW_ID 0x1000 +#define MLX4_EN_CX3_HIGH_ID 0x1005 + struct mlx4_en_rx_alloc { struct page *page; u16 offset; -- cgit v1.2.2 From 0345584e0b8be3735a950d17c7e463db20c6ce27 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:38:17 +0000 Subject: mlx4: generalization of multicast steering. The same packet steering mechanism would be used both for IB and Ethernet, Both multicasts and unicasts. This commit prepares the general infrastructure for this. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/main.c | 10 ++-- drivers/net/mlx4/en_main.c | 2 +- drivers/net/mlx4/fw.c | 2 + drivers/net/mlx4/fw.h | 2 + drivers/net/mlx4/main.c | 2 + drivers/net/mlx4/mcg.c | 113 ++++++++++++++++++++++++++------------ 6 files changed, 90 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 66e3eecfd0db..fbe1973f77b0 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -625,7 +625,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, !!(mqp->flags & MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK), - MLX4_PROTOCOL_IB); + MLX4_PROT_IB_IPV6); if (err) return err; @@ -636,7 +636,7 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) return 0; err_add: - mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); + mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6); return err; } @@ -666,7 +666,7 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) struct mlx4_ib_gid_entry *ge; err = mlx4_multicast_detach(mdev->dev, - &mqp->mqp, gid->raw, MLX4_PROTOCOL_IB); + &mqp->mqp, gid->raw, MLX4_PROT_IB_IPV6); if (err) return err; @@ -953,7 +953,7 @@ static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event mlx4_foreach_ib_transport_port(port, ibdev->dev) { oldnd = iboe->netdevs[port - 1]; iboe->netdevs[port - 1] = - mlx4_get_protocol_dev(ibdev->dev, MLX4_PROTOCOL_EN, port); + mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port); if (oldnd != iboe->netdevs[port - 1]) { if (iboe->netdevs[port - 1]) netdev_added(ibdev, port); @@ -1206,7 +1206,7 @@ static struct mlx4_interface mlx4_ib_interface = { .add = mlx4_ib_add, .remove = mlx4_ib_remove, .event = mlx4_ib_event, - .protocol = MLX4_PROTOCOL_IB + .protocol = MLX4_PROT_IB_IPV6 }; static int __init mlx4_ib_init(void) diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 29aaa4303991..9317b61a75b8 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -296,7 +296,7 @@ static struct mlx4_interface mlx4_en_interface = { .remove = mlx4_en_remove, .event = mlx4_en_event, .get_dev = mlx4_en_get_netdev, - .protocol = MLX4_PROTOCOL_EN, + .protocol = MLX4_PROT_ETH, }; static int __init mlx4_en_init(void) diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index fd1c51b6197a..7813913b6d0f 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -274,6 +274,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->stat_rate_support = stat_rate; MLX4_GET(field, outbox, QUERY_DEV_CAP_UDP_RSS_OFFSET); dev_cap->udp_rss = field & 0x1; + dev_cap->vep_uc_steering = field & 0x2; + dev_cap->vep_mc_steering = field & 0x4; MLX4_GET(field, outbox, QUERY_DEV_CAP_ETH_UC_LOOPBACK_OFFSET); dev_cap->loopback_support = field & 0x1; dev_cap->wol = field & 0x40; diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h index f7b9cc2d1b2a..88003ebc6185 100644 --- a/drivers/net/mlx4/fw.h +++ b/drivers/net/mlx4/fw.h @@ -80,6 +80,8 @@ struct mlx4_dev_cap { u16 stat_rate_support; int udp_rss; int loopback_support; + int vep_uc_steering; + int vep_mc_steering; int wol; u32 flags; int reserved_uars; diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 5bebb8800ab2..da0da281d830 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -227,6 +227,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.stat_rate_support = dev_cap->stat_rate_support; dev->caps.udp_rss = dev_cap->udp_rss; dev->caps.loopback_support = dev_cap->loopback_support; + dev->caps.vep_uc_steering = dev_cap->vep_uc_steering; + dev->caps.vep_mc_steering = dev_cap->vep_mc_steering; dev->caps.wol = dev_cap->wol; dev->caps.max_gso_sz = dev_cap->max_gso_sz; diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 79cf42db2ea9..b103ad23bd84 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -32,6 +32,7 @@ */ #include +#include #include @@ -50,28 +51,28 @@ struct mlx4_mgm { static const u8 zero_gid[16]; /* automatically initialized to 0 */ -static int mlx4_READ_MCG(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) +static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) { return mlx4_cmd_box(dev, 0, mailbox->dma, index, 0, MLX4_CMD_READ_MCG, MLX4_CMD_TIME_CLASS_A); } -static int mlx4_WRITE_MCG(struct mlx4_dev *dev, int index, - struct mlx4_cmd_mailbox *mailbox) +static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, + struct mlx4_cmd_mailbox *mailbox) { return mlx4_cmd(dev, mailbox->dma, index, 0, MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A); } -static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, - u16 *hash) +static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, + u16 *hash, u8 op_mod) { u64 imm; int err; - err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, 0, MLX4_CMD_MGID_HASH, - MLX4_CMD_TIME_CLASS_A); + err = mlx4_cmd_imm(dev, mailbox->dma, &imm, 0, op_mod, + MLX4_CMD_MGID_HASH, MLX4_CMD_TIME_CLASS_A); if (!err) *hash = imm; @@ -94,15 +95,17 @@ static int mlx4_MGID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox * If no AMGM exists for given gid, *index = -1, *prev = index of last * entry in hash chain and *mgm holds end of hash chain. */ -static int find_mgm(struct mlx4_dev *dev, - u8 *gid, enum mlx4_protocol protocol, - struct mlx4_cmd_mailbox *mgm_mailbox, - u16 *hash, int *prev, int *index) +static int find_entry(struct mlx4_dev *dev, u8 port, + u8 *gid, enum mlx4_protocol prot, + enum mlx4_steer_type steer, + struct mlx4_cmd_mailbox *mgm_mailbox, + u16 *hash, int *prev, int *index) { struct mlx4_cmd_mailbox *mailbox; struct mlx4_mgm *mgm = mgm_mailbox->buf; u8 *mgid; int err; + u8 op_mod = (prot == MLX4_PROT_ETH) ? !!(dev->caps.vep_mc_steering) : 0; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -111,7 +114,7 @@ static int find_mgm(struct mlx4_dev *dev, memcpy(mgid, gid, 16); - err = mlx4_MGID_HASH(dev, mailbox, hash); + err = mlx4_GID_HASH(dev, mailbox, hash, op_mod); mlx4_free_cmd_mailbox(dev, mailbox); if (err) return err; @@ -123,11 +126,11 @@ static int find_mgm(struct mlx4_dev *dev, *prev = -1; do { - err = mlx4_READ_MCG(dev, *index, mgm_mailbox); + err = mlx4_READ_ENTRY(dev, *index, mgm_mailbox); if (err) return err; - if (!memcmp(mgm->gid, zero_gid, 16)) { + if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { if (*index != *hash) { mlx4_err(dev, "Found zero MGID in AMGM.\n"); err = -EINVAL; @@ -136,7 +139,7 @@ static int find_mgm(struct mlx4_dev *dev, } if (!memcmp(mgm->gid, gid, 16) && - be32_to_cpu(mgm->members_count) >> 30 == protocol) + be32_to_cpu(mgm->members_count) >> 30 == prot) return err; *prev = *index; @@ -147,8 +150,9 @@ static int find_mgm(struct mlx4_dev *dev, return err; } -int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - int block_mcast_loopback, enum mlx4_protocol protocol) +int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_protocol prot, + enum mlx4_steer_type steer) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -159,6 +163,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], int link = 0; int i; int err; + u8 port = gid[5]; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -166,13 +171,13 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mgm = mailbox->buf; mutex_lock(&priv->mcg_table.mutex); - - err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); + err = find_entry(dev, port, gid, prot, steer, + mailbox, &hash, &prev, &index); if (err) goto out; if (index != -1) { - if (!memcmp(mgm->gid, zero_gid, 16)) + if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) memcpy(mgm->gid, gid, 16); } else { link = 1; @@ -209,22 +214,22 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], else mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); - mgm->members_count = cpu_to_be32(members_count | (u32) protocol << 30); + mgm->members_count = cpu_to_be32(members_count | (u32) prot << 30); - err = mlx4_WRITE_MCG(dev, index, mailbox); + err = mlx4_WRITE_ENTRY(dev, index, mailbox); if (err) goto out; if (!link) goto out; - err = mlx4_READ_MCG(dev, prev, mailbox); + err = mlx4_READ_ENTRY(dev, prev, mailbox); if (err) goto out; mgm->next_gid_index = cpu_to_be32(index << 6); - err = mlx4_WRITE_MCG(dev, prev, mailbox); + err = mlx4_WRITE_ENTRY(dev, prev, mailbox); if (err) goto out; @@ -242,10 +247,9 @@ out: mlx4_free_cmd_mailbox(dev, mailbox); return err; } -EXPORT_SYMBOL_GPL(mlx4_multicast_attach); -int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], - enum mlx4_protocol protocol) +int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol prot, enum mlx4_steer_type steer) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cmd_mailbox *mailbox; @@ -255,6 +259,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], int prev, index; int i, loc; int err; + u8 port = gid[5]; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -263,7 +268,8 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mutex_lock(&priv->mcg_table.mutex); - err = find_mgm(dev, gid, protocol, mailbox, &hash, &prev, &index); + err = find_entry(dev, port, gid, prot, steer, + mailbox, &hash, &prev, &index); if (err) goto out; @@ -285,12 +291,12 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], } - mgm->members_count = cpu_to_be32(--members_count | (u32) protocol << 30); + mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30); mgm->qp[loc] = mgm->qp[i - 1]; mgm->qp[i - 1] = 0; if (i != 1) { - err = mlx4_WRITE_MCG(dev, index, mailbox); + err = mlx4_WRITE_ENTRY(dev, index, mailbox); goto out; } @@ -298,13 +304,13 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], /* Remove entry from MGM */ int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; if (amgm_index) { - err = mlx4_READ_MCG(dev, amgm_index, mailbox); + err = mlx4_READ_ENTRY(dev, amgm_index, mailbox); if (err) goto out; } else memset(mgm->gid, 0, 16); - err = mlx4_WRITE_MCG(dev, index, mailbox); + err = mlx4_WRITE_ENTRY(dev, index, mailbox); if (err) goto out; @@ -319,13 +325,13 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], } else { /* Remove entry from AMGM */ int cur_next_index = be32_to_cpu(mgm->next_gid_index) >> 6; - err = mlx4_READ_MCG(dev, prev, mailbox); + err = mlx4_READ_ENTRY(dev, prev, mailbox); if (err) goto out; mgm->next_gid_index = cpu_to_be32(cur_next_index << 6); - err = mlx4_WRITE_MCG(dev, prev, mailbox); + err = mlx4_WRITE_ENTRY(dev, prev, mailbox); if (err) goto out; @@ -343,6 +349,43 @@ out: mlx4_free_cmd_mailbox(dev, mailbox); return err; } + + +int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_protocol prot) +{ + enum mlx4_steer_type steer; + + steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; + + if (prot == MLX4_PROT_ETH && !dev->caps.vep_mc_steering) + return 0; + + if (prot == MLX4_PROT_ETH) + gid[7] |= (steer << 1); + + return mlx4_qp_attach_common(dev, qp, gid, + block_mcast_loopback, prot, + steer); +} +EXPORT_SYMBOL_GPL(mlx4_multicast_attach); + +int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol prot) +{ + enum mlx4_steer_type steer; + + steer = (is_valid_ether_addr(&gid[10])) ? MLX4_UC_STEER : MLX4_MC_STEER; + + if (prot == MLX4_PROT_ETH && !dev->caps.vep_mc_steering) + return 0; + + if (prot == MLX4_PROT_ETH) { + gid[7] |= (steer << 1); + } + + return mlx4_qp_detach_common(dev, qp, gid, prot, steer); +} EXPORT_SYMBOL_GPL(mlx4_multicast_detach); int mlx4_init_mcg_table(struct mlx4_dev *dev) -- cgit v1.2.2 From b12d93d63c3217f0ec923ff938b12a744e242ffa Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:38:24 +0000 Subject: mlx4: Add support for promiscuous mode in the new steering model. For Ethernet mode only, When we want to register QP as promiscuous, it must be added to all the existing steering entries and also to the default one. The promiscuous QP might also be on of "real" QPs, which means we need to monitor every entry to avoid duplicates and ensure we close an entry when all it has is promiscuous QPs. Same mechanism both for unicast and multicast. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/main.c | 63 +++++- drivers/net/mlx4/mcg.c | 535 +++++++++++++++++++++++++++++++++++++++++++++++- drivers/net/mlx4/mlx4.h | 33 +++ 3 files changed, 620 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index da0da281d830..c8e276138f81 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1063,6 +1063,59 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info) device_remove_file(&info->dev->pdev->dev, &info->port_attr); } +static int mlx4_init_steering(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int num_entries = dev->caps.num_ports; + int i, j; + + priv->steer = kzalloc(sizeof(struct mlx4_steer) * num_entries, GFP_KERNEL); + if (!priv->steer) + return -ENOMEM; + + for (i = 0; i < num_entries; i++) { + for (j = 0; j < MLX4_NUM_STEERS; j++) { + INIT_LIST_HEAD(&priv->steer[i].promisc_qps[j]); + INIT_LIST_HEAD(&priv->steer[i].steer_entries[j]); + } + INIT_LIST_HEAD(&priv->steer[i].high_prios); + } + return 0; +} + +static void mlx4_clear_steering(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_steer_index *entry, *tmp_entry; + struct mlx4_promisc_qp *pqp, *tmp_pqp; + int num_entries = dev->caps.num_ports; + int i, j; + + for (i = 0; i < num_entries; i++) { + for (j = 0; j < MLX4_NUM_STEERS; j++) { + list_for_each_entry_safe(pqp, tmp_pqp, + &priv->steer[i].promisc_qps[j], + list) { + list_del(&pqp->list); + kfree(pqp); + } + list_for_each_entry_safe(entry, tmp_entry, + &priv->steer[i].steer_entries[j], + list) { + list_del(&entry->list); + list_for_each_entry_safe(pqp, tmp_pqp, + &entry->duplicates, + list) { + list_del(&pqp->list); + kfree(pqp); + } + kfree(entry); + } + } + } + kfree(priv->steer); +} + static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { struct mlx4_priv *priv; @@ -1172,6 +1225,10 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) mlx4_enable_msi_x(dev); + err = mlx4_init_steering(dev); + if (err) + goto err_free_eq; + err = mlx4_setup_hca(dev); if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) { dev->flags &= ~MLX4_FLAG_MSI_X; @@ -1180,7 +1237,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } if (err) - goto err_free_eq; + goto err_steer; for (port = 1; port <= dev->caps.num_ports; port++) { err = mlx4_init_port_info(dev, port); @@ -1213,6 +1270,9 @@ err_port: mlx4_cleanup_pd_table(dev); mlx4_cleanup_uar_table(dev); +err_steer: + mlx4_clear_steering(dev); + err_free_eq: mlx4_free_eq_table(dev); @@ -1272,6 +1332,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) iounmap(priv->kar); mlx4_uar_free(dev, &priv->driver_uar); mlx4_cleanup_uar_table(dev); + mlx4_clear_steering(dev); mlx4_free_eq_table(dev); mlx4_close_hca(dev); mlx4_cmd_cleanup(dev); diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index b103ad23bd84..e71372aa9cc4 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -41,14 +41,6 @@ #define MGM_QPN_MASK 0x00FFFFFF #define MGM_BLCK_LB_BIT 30 -struct mlx4_mgm { - __be32 next_gid_index; - __be32 members_count; - u32 reserved[2]; - u8 gid[16]; - __be32 qp[MLX4_QP_PER_MGM]; -}; - static const u8 zero_gid[16]; /* automatically initialized to 0 */ static int mlx4_READ_ENTRY(struct mlx4_dev *dev, int index, @@ -65,6 +57,16 @@ static int mlx4_WRITE_ENTRY(struct mlx4_dev *dev, int index, MLX4_CMD_TIME_CLASS_A); } +static int mlx4_WRITE_PROMISC(struct mlx4_dev *dev, u8 vep_num, u8 port, u8 steer, + struct mlx4_cmd_mailbox *mailbox) +{ + u32 in_mod; + + in_mod = (u32) vep_num << 24 | (u32) port << 16 | steer << 1; + return mlx4_cmd(dev, mailbox->dma, in_mod, 0x1, + MLX4_CMD_WRITE_MCG, MLX4_CMD_TIME_CLASS_A); +} + static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, u16 *hash, u8 op_mod) { @@ -80,6 +82,457 @@ static int mlx4_GID_HASH(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, return err; } +static struct mlx4_promisc_qp *get_promisc_qp(struct mlx4_dev *dev, u8 pf_num, + enum mlx4_steer_type steer, + u32 qpn) +{ + struct mlx4_steer *s_steer = &mlx4_priv(dev)->steer[pf_num]; + struct mlx4_promisc_qp *pqp; + + list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { + if (pqp->qpn == qpn) + return pqp; + } + /* not found */ + return NULL; +} + +/* + * Add new entry to steering data structure. + * All promisc QPs should be added as well + */ +static int new_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + u32 members_count; + struct mlx4_steer_index *new_entry; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp; + u32 prot; + int err; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + new_entry = kzalloc(sizeof *new_entry, GFP_KERNEL); + if (!new_entry) + return -ENOMEM; + + INIT_LIST_HEAD(&new_entry->duplicates); + new_entry->index = index; + list_add_tail(&new_entry->list, &s_steer->steer_entries[steer]); + + /* If the given qpn is also a promisc qp, + * it should be inserted to duplicates list + */ + pqp = get_promisc_qp(dev, pf_num, steer, qpn); + if (pqp) { + dqp = kmalloc(sizeof *dqp, GFP_KERNEL); + if (!dqp) { + err = -ENOMEM; + goto out_alloc; + } + dqp->qpn = qpn; + list_add_tail(&dqp->list, &new_entry->duplicates); + } + + /* if no promisc qps for this vep, we are done */ + if (list_empty(&s_steer->promisc_qps[steer])) + return 0; + + /* now need to add all the promisc qps to the new + * steering entry, as they should also receive the packets + * destined to this address */ + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = -ENOMEM; + goto out_alloc; + } + mgm = mailbox->buf; + + err = mlx4_READ_ENTRY(dev, index, mailbox); + if (err) + goto out_mailbox; + + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + prot = be32_to_cpu(mgm->members_count) >> 30; + list_for_each_entry(pqp, &s_steer->promisc_qps[steer], list) { + /* don't add already existing qpn */ + if (pqp->qpn == qpn) + continue; + if (members_count == MLX4_QP_PER_MGM) { + /* out of space */ + err = -ENOMEM; + goto out_mailbox; + } + + /* add the qpn */ + mgm->qp[members_count++] = cpu_to_be32(pqp->qpn & MGM_QPN_MASK); + } + /* update the qps count and update the entry with all the promisc qps*/ + mgm->members_count = cpu_to_be32(members_count | (prot << 30)); + err = mlx4_WRITE_ENTRY(dev, index, mailbox); + +out_mailbox: + mlx4_free_cmd_mailbox(dev, mailbox); + if (!err) + return 0; +out_alloc: + if (dqp) { + list_del(&dqp->list); + kfree(&dqp); + } + list_del(&new_entry->list); + kfree(new_entry); + return err; +} + +/* update the data structures with existing steering entry */ +static int existing_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_steer_index *tmp_entry, *entry = NULL; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + pqp = get_promisc_qp(dev, pf_num, steer, qpn); + if (!pqp) + return 0; /* nothing to do */ + + list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { + if (tmp_entry->index == index) { + entry = tmp_entry; + break; + } + } + if (unlikely(!entry)) { + mlx4_warn(dev, "Steering entry at index %x is not registered\n", index); + return -EINVAL; + } + + /* the given qpn is listed as a promisc qpn + * we need to add it as a duplicate to this entry + * for future refernce */ + list_for_each_entry(dqp, &entry->duplicates, list) { + if (qpn == dqp->qpn) + return 0; /* qp is already duplicated */ + } + + /* add the qp as a duplicate on this index */ + dqp = kmalloc(sizeof *dqp, GFP_KERNEL); + if (!dqp) + return -ENOMEM; + dqp->qpn = qpn; + list_add_tail(&dqp->list, &entry->duplicates); + + return 0; +} + +/* Check whether a qpn is a duplicate on steering entry + * If so, it should not be removed from mgm */ +static bool check_duplicate_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_steer_index *tmp_entry, *entry = NULL; + struct mlx4_promisc_qp *dqp, *tmp_dqp; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + /* if qp is not promisc, it cannot be duplicated */ + if (!get_promisc_qp(dev, pf_num, steer, qpn)) + return false; + + /* The qp is promisc qp so it is a duplicate on this index + * Find the index entry, and remove the duplicate */ + list_for_each_entry(tmp_entry, &s_steer->steer_entries[steer], list) { + if (tmp_entry->index == index) { + entry = tmp_entry; + break; + } + } + if (unlikely(!entry)) { + mlx4_warn(dev, "Steering entry for index %x is not registered\n", index); + return false; + } + list_for_each_entry_safe(dqp, tmp_dqp, &entry->duplicates, list) { + if (dqp->qpn == qpn) { + list_del(&dqp->list); + kfree(dqp); + } + } + return true; +} + +/* I a steering entry contains only promisc QPs, it can be removed. */ +static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, + unsigned int index, u32 tqpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + struct mlx4_steer_index *entry = NULL, *tmp_entry; + u32 qpn; + u32 members_count; + bool ret = false; + int i; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return false; + mgm = mailbox->buf; + + if (mlx4_READ_ENTRY(dev, index, mailbox)) + goto out; + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + for (i = 0; i < members_count; i++) { + qpn = be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK; + if (!get_promisc_qp(dev, pf_num, steer, qpn) && qpn != tqpn) { + /* the qp is not promisc, the entry can't be removed */ + goto out; + } + } + /* All the qps currently registered for this entry are promiscuous, + * Checking for duplicates */ + ret = true; + list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) { + if (entry->index == index) { + if (list_empty(&entry->duplicates)) { + list_del(&entry->list); + kfree(entry); + } else { + /* This entry contains duplicates so it shouldn't be removed */ + ret = false; + goto out; + } + } + } + +out: + mlx4_free_cmd_mailbox(dev, mailbox); + return ret; +} + +static int add_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, u32 qpn) +{ + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + struct mlx4_steer_index *entry; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp; + u32 members_count; + u32 prot; + int i; + bool found; + int last_index; + int err; + u8 pf_num; + struct mlx4_priv *priv = mlx4_priv(dev); + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + + mutex_lock(&priv->mcg_table.mutex); + + if (get_promisc_qp(dev, pf_num, steer, qpn)) { + err = 0; /* Noting to do, already exists */ + goto out_mutex; + } + + pqp = kmalloc(sizeof *pqp, GFP_KERNEL); + if (!pqp) { + err = -ENOMEM; + goto out_mutex; + } + pqp->qpn = qpn; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = -ENOMEM; + goto out_alloc; + } + mgm = mailbox->buf; + + /* the promisc qp needs to be added for each one of the steering + * entries, if it already exists, needs to be added as a duplicate + * for this entry */ + list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { + err = mlx4_READ_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + prot = be32_to_cpu(mgm->members_count) >> 30; + found = false; + for (i = 0; i < members_count; i++) { + if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) { + /* Entry already exists, add to duplicates */ + dqp = kmalloc(sizeof *dqp, GFP_KERNEL); + if (!dqp) + goto out_mailbox; + dqp->qpn = qpn; + list_add_tail(&dqp->list, &entry->duplicates); + found = true; + } + } + if (!found) { + /* Need to add the qpn to mgm */ + if (members_count == MLX4_QP_PER_MGM) { + /* entry is full */ + err = -ENOMEM; + goto out_mailbox; + } + mgm->qp[members_count++] = cpu_to_be32(qpn & MGM_QPN_MASK); + mgm->members_count = cpu_to_be32(members_count | (prot << 30)); + err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + } + last_index = entry->index; + } + + /* add the new qpn to list of promisc qps */ + list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); + /* now need to add all the promisc qps to default entry */ + memset(mgm, 0, sizeof *mgm); + members_count = 0; + list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) + mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); + mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); + + err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox); + if (err) + goto out_list; + + mlx4_free_cmd_mailbox(dev, mailbox); + mutex_unlock(&priv->mcg_table.mutex); + return 0; + +out_list: + list_del(&pqp->list); +out_mailbox: + mlx4_free_cmd_mailbox(dev, mailbox); +out_alloc: + kfree(pqp); +out_mutex: + mutex_unlock(&priv->mcg_table.mutex); + return err; +} + +static int remove_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port, + enum mlx4_steer_type steer, u32 qpn) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_steer *s_steer; + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_mgm *mgm; + struct mlx4_steer_index *entry; + struct mlx4_promisc_qp *pqp; + struct mlx4_promisc_qp *dqp; + u32 members_count; + bool found; + bool back_to_list = false; + int loc, i; + int err; + u8 pf_num; + + pf_num = (dev->caps.num_ports == 1) ? vep_num : (vep_num << 1) | (port - 1); + s_steer = &mlx4_priv(dev)->steer[pf_num]; + mutex_lock(&priv->mcg_table.mutex); + + pqp = get_promisc_qp(dev, pf_num, steer, qpn); + if (unlikely(!pqp)) { + mlx4_warn(dev, "QP %x is not promiscuous QP\n", qpn); + /* nothing to do */ + err = 0; + goto out_mutex; + } + + /*remove from list of promisc qps */ + list_del(&pqp->list); + kfree(pqp); + + /* set the default entry not to include the removed one */ + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) { + err = -ENOMEM; + back_to_list = true; + goto out_list; + } + mgm = mailbox->buf; + members_count = 0; + list_for_each_entry(dqp, &s_steer->promisc_qps[steer], list) + mgm->qp[members_count++] = cpu_to_be32(dqp->qpn & MGM_QPN_MASK); + mgm->members_count = cpu_to_be32(members_count | MLX4_PROT_ETH << 30); + + err = mlx4_WRITE_PROMISC(dev, vep_num, port, steer, mailbox); + if (err) + goto out_mailbox; + + /* remove the qp from all the steering entries*/ + list_for_each_entry(entry, &s_steer->steer_entries[steer], list) { + found = false; + list_for_each_entry(dqp, &entry->duplicates, list) { + if (dqp->qpn == qpn) { + found = true; + break; + } + } + if (found) { + /* a duplicate, no need to change the mgm, + * only update the duplicates list */ + list_del(&dqp->list); + kfree(dqp); + } else { + err = mlx4_READ_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; + for (loc = -1, i = 0; i < members_count; ++i) + if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) + loc = i; + + mgm->members_count = cpu_to_be32(--members_count | + (MLX4_PROT_ETH << 30)); + mgm->qp[loc] = mgm->qp[i - 1]; + mgm->qp[i - 1] = 0; + + err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox); + if (err) + goto out_mailbox; + } + + } + +out_mailbox: + mlx4_free_cmd_mailbox(dev, mailbox); +out_list: + if (back_to_list) + list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); +out_mutex: + mutex_unlock(&priv->mcg_table.mutex); + return err; +} + /* * Caller must hold MCG table semaphore. gid and mgm parameters must * be properly aligned for command interface. @@ -164,6 +617,7 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], int i; int err; u8 port = gid[5]; + u8 new_entry = 0; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -177,8 +631,10 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; if (index != -1) { - if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) + if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) { + new_entry = 1; memcpy(mgm->gid, gid, 16); + } } else { link = 1; @@ -234,6 +690,14 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; out: + if (prot == MLX4_PROT_ETH) { + /* manage the steering entry for promisc mode */ + if (new_entry) + new_steering_entry(dev, 0, port, steer, index, qp->qpn); + else + existing_steering_entry(dev, 0, port, steer, + index, qp->qpn); + } if (err && link && index != -1) { if (index < dev->caps.num_mgms) mlx4_warn(dev, "Got AMGM index %d < %d", @@ -260,6 +724,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], int i, loc; int err; u8 port = gid[5]; + bool removed_entry = false; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -279,6 +744,11 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], goto out; } + /* if this pq is also a promisc qp, it shouldn't be removed */ + if (prot == MLX4_PROT_ETH && + check_duplicate_entry(dev, 0, port, steer, index, qp->qpn)) + goto out; + members_count = be32_to_cpu(mgm->members_count) & 0xffffff; for (loc = -1, i = 0; i < members_count; ++i) if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) @@ -295,11 +765,16 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], mgm->qp[loc] = mgm->qp[i - 1]; mgm->qp[i - 1] = 0; - if (i != 1) { + if (prot == MLX4_PROT_ETH) + removed_entry = can_remove_steering_entry(dev, 0, port, steer, index, qp->qpn); + if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) { err = mlx4_WRITE_ENTRY(dev, index, mailbox); goto out; } + /* We are going to delete the entry, members count should be 0 */ + mgm->members_count = cpu_to_be32((u32) prot << 30); + if (prev == -1) { /* Remove entry from MGM */ int amgm_index = be32_to_cpu(mgm->next_gid_index) >> 6; @@ -388,6 +863,46 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], } EXPORT_SYMBOL_GPL(mlx4_multicast_detach); + +int mlx4_multicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + + return add_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_add); + +int mlx4_multicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + + return remove_promisc_qp(dev, 0, port, MLX4_MC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_multicast_promisc_remove); + +int mlx4_unicast_promisc_add(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + + return add_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_add); + +int mlx4_unicast_promisc_remove(struct mlx4_dev *dev, u32 qpn, u8 port) +{ + if (!dev->caps.vep_mc_steering) + return 0; + + return remove_promisc_qp(dev, 0, port, MLX4_UC_STEER, qpn); +} +EXPORT_SYMBOL_GPL(mlx4_unicast_promisc_remove); + int mlx4_init_mcg_table(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 67ee8dacae79..1513a91b4bd4 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -162,6 +162,27 @@ struct mlx4_fw { u8 catas_bar; }; +#define MGM_QPN_MASK 0x00FFFFFF +#define MGM_BLCK_LB_BIT 30 + +struct mlx4_promisc_qp { + struct list_head list; + u32 qpn; +}; + +struct mlx4_steer_index { + struct list_head list; + unsigned int index; + struct list_head duplicates; +}; + +struct mlx4_mgm { + __be32 next_gid_index; + __be32 members_count; + u32 reserved[2]; + u8 gid[16]; + __be32 qp[MLX4_QP_PER_MGM]; +}; struct mlx4_cmd { struct pci_pool *pool; void __iomem *hcr; @@ -287,6 +308,12 @@ struct mlx4_msix_ctl { spinlock_t pool_lock; }; +struct mlx4_steer { + struct list_head promisc_qps[MLX4_NUM_STEERS]; + struct list_head steer_entries[MLX4_NUM_STEERS]; + struct list_head high_prios; +}; + struct mlx4_priv { struct mlx4_dev dev; @@ -319,6 +346,7 @@ struct mlx4_priv { struct mlx4_sense sense; struct mutex port_mutex; struct mlx4_msix_ctl msix_ctl; + struct mlx4_steer *steer; }; static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) @@ -409,4 +437,9 @@ void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port); int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps); +int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + enum mlx4_protocol prot, enum mlx4_steer_type steer); +int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], + int block_mcast_loopback, enum mlx4_protocol prot, + enum mlx4_steer_type steer); #endif /* MLX4_H */ -- cgit v1.2.2 From 1679200f91da6a054b06954c9bd3eeed29b6731f Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:38:31 +0000 Subject: mlx4_en: Enabling new steering The mlx4_en module now uses the new steering mechanism. The RX packets are now steered through the MCG table instead of Mac table for unicast, and default entry for multicast. The feature is enabled through INIT_HCA Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 133 +++++++++++++++++++++++++++------- drivers/net/mlx4/en_port.c | 11 ++- drivers/net/mlx4/en_port.h | 19 +++-- drivers/net/mlx4/en_rx.c | 11 +-- drivers/net/mlx4/fw.c | 3 + drivers/net/mlx4/mlx4.h | 6 ++ drivers/net/mlx4/mlx4_en.h | 1 + drivers/net/mlx4/port.c | 165 +++++++++++++++++++++++++++++++++++++++---- 8 files changed, 291 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index f6ed315b4b89..08e680100db8 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -156,9 +156,8 @@ static void mlx4_en_do_set_mac(struct work_struct *work) mutex_lock(&mdev->state_lock); if (priv->port_up) { /* Remove old MAC and insert the new one */ - mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); - err = mlx4_register_mac(mdev->dev, priv->port, - priv->mac, &priv->mac_index); + err = mlx4_replace_mac(mdev->dev, priv->port, + priv->base_qpn, priv->mac, 0); if (err) en_err(priv, "Failed changing HW MAC address\n"); } else @@ -214,6 +213,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) struct mlx4_en_dev *mdev = priv->mdev; struct net_device *dev = priv->dev; u64 mcast_addr = 0; + u8 mc_list[16] = {0}; int err; mutex_lock(&mdev->state_lock); @@ -239,8 +239,12 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) priv->flags |= MLX4_EN_FLAG_PROMISC; /* Enable promiscouos mode */ - err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, - priv->base_qpn, 1); + if (!mdev->dev->caps.vep_uc_steering) + err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, + priv->base_qpn, 1); + else + err = mlx4_unicast_promisc_add(mdev->dev, priv->base_qpn, + priv->port); if (err) en_err(priv, "Failed enabling " "promiscous mode\n"); @@ -252,10 +256,21 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) en_err(priv, "Failed disabling " "multicast filter\n"); - /* Disable port VLAN filter */ - err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); - if (err) - en_err(priv, "Failed disabling VLAN filter\n"); + /* Add the default qp number as multicast promisc */ + if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { + err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed entering multicast promisc mode\n"); + priv->flags |= MLX4_EN_FLAG_MC_PROMISC; + } + + if (priv->vlgrp) { + /* Disable port VLAN filter */ + err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, NULL); + if (err) + en_err(priv, "Failed disabling VLAN filter\n"); + } } goto out; } @@ -270,11 +285,24 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) priv->flags &= ~MLX4_EN_FLAG_PROMISC; /* Disable promiscouos mode */ - err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, - priv->base_qpn, 0); + if (!mdev->dev->caps.vep_uc_steering) + err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, + priv->base_qpn, 0); + else + err = mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, + priv->port); if (err) en_err(priv, "Failed disabling promiscous mode\n"); + /* Disable Multicast promisc */ + if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { + err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed disabling multicast promiscous mode\n"); + priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; + } + /* Enable port VLAN filter */ err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp); if (err) @@ -287,14 +315,38 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) 0, MLX4_MCAST_DISABLE); if (err) en_err(priv, "Failed disabling multicast filter\n"); + + /* Add the default qp number as multicast promisc */ + if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { + err = mlx4_multicast_promisc_add(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed entering multicast promisc mode\n"); + priv->flags |= MLX4_EN_FLAG_MC_PROMISC; + } } else { int i; + /* Disable Multicast promisc */ + if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { + err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, + priv->port); + if (err) + en_err(priv, "Failed disabling multicast promiscous mode\n"); + priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; + } err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 0, MLX4_MCAST_DISABLE); if (err) en_err(priv, "Failed disabling multicast filter\n"); + /* Detach our qp from all the multicast addresses */ + for (i = 0; i < priv->mc_addrs_cnt; i++) { + memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, + mc_list, MLX4_PROT_ETH); + } /* Flush mcast filter and init it with broadcast address */ mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, 1, MLX4_MCAST_CONFIG); @@ -307,6 +359,10 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) for (i = 0; i < priv->mc_addrs_cnt; i++) { mcast_addr = mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN); + memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, + mc_list, 0, MLX4_PROT_ETH); mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, mcast_addr, 0, MLX4_MCAST_CONFIG); } @@ -314,8 +370,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) 0, MLX4_MCAST_ENABLE); if (err) en_err(priv, "Failed enabling multicast filter\n"); - - mlx4_en_clear_list(dev); } out: mutex_unlock(&mdev->state_lock); @@ -557,6 +611,7 @@ int mlx4_en_start_port(struct net_device *dev) int err = 0; int i; int j; + u8 mc_list[16] = {0}; char name[32]; if (priv->port_up) { @@ -596,10 +651,20 @@ int mlx4_en_start_port(struct net_device *dev) ++rx_index; } + /* Set port mac number */ + en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); + err = mlx4_register_mac(mdev->dev, priv->port, + priv->mac, &priv->base_qpn, 0); + if (err) { + en_err(priv, "Failed setting port mac\n"); + goto cq_err; + } + mdev->mac_removed[priv->port] = 0; + err = mlx4_en_config_rss_steer(priv); if (err) { en_err(priv, "Failed configuring rss steering\n"); - goto cq_err; + goto mac_err; } if (mdev->dev->caps.comp_pool && !priv->tx_vector) { @@ -661,24 +726,22 @@ int mlx4_en_start_port(struct net_device *dev) en_err(priv, "Failed setting default qp numbers\n"); goto tx_err; } - /* Set port mac number */ - en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port); - err = mlx4_register_mac(mdev->dev, priv->port, - priv->mac, &priv->mac_index); - if (err) { - en_err(priv, "Failed setting port mac\n"); - goto tx_err; - } - mdev->mac_removed[priv->port] = 0; /* Init port */ en_dbg(HW, priv, "Initializing port\n"); err = mlx4_INIT_PORT(mdev->dev, priv->port); if (err) { en_err(priv, "Failed Initializing port\n"); - goto mac_err; + goto tx_err; } + /* Attach rx QP to bradcast address */ + memset(&mc_list[10], 0xff, ETH_ALEN); + mc_list[5] = priv->port; + if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list, + 0, MLX4_PROT_ETH)) + mlx4_warn(mdev, "Failed Attaching Broadcast\n"); + /* Schedule multicast task to populate multicast list */ queue_work(mdev->workqueue, &priv->mcast_task); @@ -686,8 +749,6 @@ int mlx4_en_start_port(struct net_device *dev) netif_tx_start_all_queues(dev); return 0; -mac_err: - mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); tx_err: while (tx_index--) { mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]); @@ -695,6 +756,8 @@ tx_err: } mlx4_en_release_rss_steer(priv); +mac_err: + mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn); cq_err: while (rx_index--) mlx4_en_deactivate_cq(priv, &priv->rx_cq[rx_index]); @@ -710,6 +773,7 @@ void mlx4_en_stop_port(struct net_device *dev) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; int i; + u8 mc_list[16] = {0}; if (!priv->port_up) { en_dbg(DRV, priv, "stop port called while port already down\n"); @@ -724,8 +788,23 @@ void mlx4_en_stop_port(struct net_device *dev) /* Set port as not active */ priv->port_up = false; + /* Detach All multicasts */ + memset(&mc_list[10], 0xff, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list, + MLX4_PROT_ETH); + for (i = 0; i < priv->mc_addrs_cnt; i++) { + memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN); + mc_list[5] = priv->port; + mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, + mc_list, MLX4_PROT_ETH); + } + mlx4_en_clear_list(dev); + /* Flush multicast filter */ + mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); + /* Unregister Mac address for the port */ - mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index); + mlx4_unregister_mac(mdev->dev, priv->port, priv->base_qpn); mdev->mac_removed[priv->port] = 1; /* Free TX Rings */ diff --git a/drivers/net/mlx4/en_port.c b/drivers/net/mlx4/en_port.c index a2b0bc4ada5d..f2a4f5dd313d 100644 --- a/drivers/net/mlx4/en_port.c +++ b/drivers/net/mlx4/en_port.c @@ -119,6 +119,10 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, struct mlx4_set_port_rqp_calc_context *context; int err; u32 in_mod; + u32 m_promisc = (dev->caps.vep_mc_steering) ? MCAST_DIRECT : MCAST_DEFAULT; + + if (dev->caps.vep_mc_steering && dev->caps.vep_uc_steering) + return 0; mailbox = mlx4_alloc_cmd_mailbox(dev); if (IS_ERR(mailbox)) @@ -127,8 +131,11 @@ int mlx4_SET_PORT_qpn_calc(struct mlx4_dev *dev, u8 port, u32 base_qpn, memset(context, 0, sizeof *context); context->base_qpn = cpu_to_be32(base_qpn); - context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_EN_SHIFT | base_qpn); - context->mcast = cpu_to_be32(1 << SET_PORT_PROMISC_MODE_SHIFT | base_qpn); + context->n_mac = 0x7; + context->promisc = cpu_to_be32(promisc << SET_PORT_PROMISC_SHIFT | + base_qpn); + context->mcast = cpu_to_be32(m_promisc << SET_PORT_MC_PROMISC_SHIFT | + base_qpn); context->intra_no_vlan = 0; context->no_vlan = MLX4_NO_VLAN_IDX; context->intra_vlan_miss = 0; diff --git a/drivers/net/mlx4/en_port.h b/drivers/net/mlx4/en_port.h index 092e814b1981..e3d73e41c567 100644 --- a/drivers/net/mlx4/en_port.h +++ b/drivers/net/mlx4/en_port.h @@ -36,8 +36,8 @@ #define SET_PORT_GEN_ALL_VALID 0x7 -#define SET_PORT_PROMISC_EN_SHIFT 31 -#define SET_PORT_PROMISC_MODE_SHIFT 30 +#define SET_PORT_PROMISC_SHIFT 31 +#define SET_PORT_MC_PROMISC_SHIFT 30 enum { MLX4_CMD_SET_VLAN_FLTR = 0x47, @@ -45,6 +45,12 @@ enum { MLX4_CMD_DUMP_ETH_STATS = 0x49, }; +enum { + MCAST_DIRECT_ONLY = 0, + MCAST_DIRECT = 1, + MCAST_DEFAULT = 2 +}; + struct mlx4_set_port_general_context { u8 reserved[3]; u8 flags; @@ -60,14 +66,17 @@ struct mlx4_set_port_general_context { struct mlx4_set_port_rqp_calc_context { __be32 base_qpn; - __be32 flags; - u8 reserved[3]; + u8 rererved; + u8 n_mac; + u8 n_vlan; + u8 n_prio; + u8 reserved2[3]; u8 mac_miss; u8 intra_no_vlan; u8 no_vlan; u8 intra_vlan_miss; u8 vlan_miss; - u8 reserved2[3]; + u8 reserved3[3]; u8 no_vlan_prio; __be32 promisc; __be32 mcast; diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 570f2508fb30..05998ee297c9 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -845,16 +845,10 @@ int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv) } /* Configure RSS indirection qp */ - err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &priv->base_qpn); - if (err) { - en_err(priv, "Failed to reserve range for RSS " - "indirection qp\n"); - goto rss_err; - } err = mlx4_qp_alloc(mdev->dev, priv->base_qpn, &rss_map->indir_qp); if (err) { en_err(priv, "Failed to allocate RSS indirection QP\n"); - goto reserve_err; + goto rss_err; } rss_map->indir_qp.event = mlx4_en_sqp_event; mlx4_en_fill_qp_context(priv, 0, 0, 0, 1, priv->base_qpn, @@ -881,8 +875,6 @@ indir_err: MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); mlx4_qp_free(mdev->dev, &rss_map->indir_qp); -reserve_err: - mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); rss_err: for (i = 0; i < good_qps; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], @@ -904,7 +896,6 @@ void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv) MLX4_QP_STATE_RST, NULL, 0, 0, &rss_map->indir_qp); mlx4_qp_remove(mdev->dev, &rss_map->indir_qp); mlx4_qp_free(mdev->dev, &rss_map->indir_qp); - mlx4_qp_release_range(mdev->dev, priv->base_qpn, 1); for (i = 0; i < priv->rx_ring_num; i++) { mlx4_qp_modify(mdev->dev, NULL, rss_map->state[i], diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 7813913b6d0f..67a209ba939d 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -740,6 +740,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) #define INIT_HCA_MC_BASE_OFFSET (INIT_HCA_MCAST_OFFSET + 0x00) #define INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x12) #define INIT_HCA_LOG_MC_HASH_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x16) +#define INIT_HCA_UC_STEERING_OFFSET (INIT_HCA_MCAST_OFFSET + 0x18) #define INIT_HCA_LOG_MC_TABLE_SZ_OFFSET (INIT_HCA_MCAST_OFFSET + 0x1b) #define INIT_HCA_TPT_OFFSET 0x0f0 #define INIT_HCA_DMPT_BASE_OFFSET (INIT_HCA_TPT_OFFSET + 0x00) @@ -800,6 +801,8 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param) MLX4_PUT(inbox, param->mc_base, INIT_HCA_MC_BASE_OFFSET); MLX4_PUT(inbox, param->log_mc_entry_sz, INIT_HCA_LOG_MC_ENTRY_SZ_OFFSET); MLX4_PUT(inbox, param->log_mc_hash_sz, INIT_HCA_LOG_MC_HASH_SZ_OFFSET); + if (dev->caps.vep_mc_steering) + MLX4_PUT(inbox, (u8) (1 << 3), INIT_HCA_UC_STEERING_OFFSET); MLX4_PUT(inbox, param->log_mc_table_sz, INIT_HCA_LOG_MC_TABLE_SZ_OFFSET); /* TPT attributes */ diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 1513a91b4bd4..d8bb4418581b 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -286,6 +286,10 @@ struct mlx4_vlan_table { int max; }; +struct mlx4_mac_entry { + u64 mac; +}; + struct mlx4_port_info { struct mlx4_dev *dev; int port; @@ -293,7 +297,9 @@ struct mlx4_port_info { struct device_attribute port_attr; enum mlx4_port_type tmp_type; struct mlx4_mac_table mac_table; + struct radix_tree_root mac_tree; struct mlx4_vlan_table vlan_table; + int base_qpn; }; struct mlx4_sense { diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index ad4df66750bc..5a2c56023668 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -458,6 +458,7 @@ struct mlx4_en_priv { struct mlx4_en_rss_map rss_map; u32 flags; #define MLX4_EN_FLAG_PROMISC 0x1 +#define MLX4_EN_FLAG_MC_PROMISC 0x2 u32 tx_ring_num; u32 rx_ring_num; u32 rx_skb_size; diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c index 451339559bdc..eca7d8596f87 100644 --- a/drivers/net/mlx4/port.c +++ b/drivers/net/mlx4/port.c @@ -90,12 +90,79 @@ static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port, return err; } -int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) +static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port, + u64 mac, int *qpn, u8 reserve) { - struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; + struct mlx4_qp qp; + u8 gid[16] = {0}; + int err; + + if (reserve) { + err = mlx4_qp_reserve_range(dev, 1, 1, qpn); + if (err) { + mlx4_err(dev, "Failed to reserve qp for mac registration\n"); + return err; + } + } + qp.qpn = *qpn; + + mac &= 0xffffffffffffULL; + mac = cpu_to_be64(mac << 16); + memcpy(&gid[10], &mac, ETH_ALEN); + gid[5] = port; + gid[7] = MLX4_UC_STEER << 1; + + err = mlx4_qp_attach_common(dev, &qp, gid, 0, + MLX4_PROT_ETH, MLX4_UC_STEER); + if (err && reserve) + mlx4_qp_release_range(dev, *qpn, 1); + + return err; +} + +static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port, + u64 mac, int qpn, u8 free) +{ + struct mlx4_qp qp; + u8 gid[16] = {0}; + + qp.qpn = qpn; + mac &= 0xffffffffffffULL; + mac = cpu_to_be64(mac << 16); + memcpy(&gid[10], &mac, ETH_ALEN); + gid[5] = port; + gid[7] = MLX4_UC_STEER << 1; + + mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER); + if (free) + mlx4_qp_release_range(dev, qpn, 1); +} + +int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap) +{ + struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; + struct mlx4_mac_table *table = &info->mac_table; + struct mlx4_mac_entry *entry; int i, err = 0; int free = -1; + if (dev->caps.vep_uc_steering) { + err = mlx4_uc_steer_add(dev, port, mac, qpn, 1); + if (!err) { + entry = kmalloc(sizeof *entry, GFP_KERNEL); + if (!entry) { + mlx4_uc_steer_release(dev, port, mac, *qpn, 1); + return -ENOMEM; + } + entry->mac = mac; + err = radix_tree_insert(&info->mac_tree, *qpn, entry); + if (err) { + mlx4_uc_steer_release(dev, port, mac, *qpn, 1); + return err; + } + } else + return err; + } mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac); mutex_lock(&table->mutex); for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) { @@ -106,7 +173,6 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { /* MAC already registered, increase refernce count */ - *index = i; ++table->refs[i]; goto out; } @@ -137,7 +203,8 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) goto out; } - *index = free; + if (!dev->caps.vep_uc_steering) + *qpn = info->base_qpn + free; ++table->total; out: mutex_unlock(&table->mutex); @@ -145,20 +212,52 @@ out: } EXPORT_SYMBOL_GPL(mlx4_register_mac); -void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index) +static int validate_index(struct mlx4_dev *dev, + struct mlx4_mac_table *table, int index) { - struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; + int err = 0; - mutex_lock(&table->mutex); - if (!table->refs[index]) { - mlx4_warn(dev, "No MAC entry for index %d\n", index); - goto out; + if (index < 0 || index >= table->max || !table->entries[index]) { + mlx4_warn(dev, "No valid Mac entry for the given index\n"); + err = -EINVAL; } - if (--table->refs[index]) { - mlx4_warn(dev, "Have more references for index %d," - "no need to modify MAC table\n", index); - goto out; + return err; +} + +static int find_index(struct mlx4_dev *dev, + struct mlx4_mac_table *table, u64 mac) +{ + int i; + for (i = 0; i < MLX4_MAX_MAC_NUM; i++) { + if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) + return i; } + /* Mac not found */ + return -EINVAL; +} + +void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn) +{ + struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; + struct mlx4_mac_table *table = &info->mac_table; + int index = qpn - info->base_qpn; + struct mlx4_mac_entry *entry; + + if (dev->caps.vep_uc_steering) { + entry = radix_tree_lookup(&info->mac_tree, qpn); + if (entry) { + mlx4_uc_steer_release(dev, port, entry->mac, qpn, 1); + radix_tree_delete(&info->mac_tree, qpn); + index = find_index(dev, table, entry->mac); + kfree(entry); + } + } + + mutex_lock(&table->mutex); + + if (validate_index(dev, table, index)) + goto out; + table->entries[index] = 0; mlx4_set_port_mac_table(dev, port, table->entries); --table->total; @@ -167,6 +266,44 @@ out: } EXPORT_SYMBOL_GPL(mlx4_unregister_mac); +int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac, u8 wrap) +{ + struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; + struct mlx4_mac_table *table = &info->mac_table; + int index = qpn - info->base_qpn; + struct mlx4_mac_entry *entry; + int err; + + if (dev->caps.vep_uc_steering) { + entry = radix_tree_lookup(&info->mac_tree, qpn); + if (!entry) + return -EINVAL; + index = find_index(dev, table, entry->mac); + mlx4_uc_steer_release(dev, port, entry->mac, qpn, 0); + entry->mac = new_mac; + err = mlx4_uc_steer_add(dev, port, entry->mac, &qpn, 0); + if (err || index < 0) + return err; + } + + mutex_lock(&table->mutex); + + err = validate_index(dev, table, index); + if (err) + goto out; + + table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID); + + err = mlx4_set_port_mac_table(dev, port, table->entries); + if (unlikely(err)) { + mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) new_mac); + table->entries[index] = 0; + } +out: + mutex_unlock(&table->mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_replace_mac); static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, __be32 *entries) { -- cgit v1.2.2 From c1b43dca137f2154845122417fba86d4bae67182 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 22 Mar 2011 22:38:41 +0000 Subject: mlx4: Add blue flame support for kernel consumers Using blue flame can improve latency by allowing the HW to more efficiently access the WQE. This patch presents two functions that are used to allocate or release HW resources for using blue flame; the caller need to supply a struct mlx4_bf object when allocating resources. Consumers that make use of this API should post doorbells to the UAR object pointed by the initialized struct mlx4_bf; Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/mlx4/main.c | 31 ++++++++++++++++ drivers/net/mlx4/mlx4.h | 3 ++ drivers/net/mlx4/pd.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index c8e276138f81..05c5671749aa 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -721,8 +722,31 @@ static void mlx4_free_icms(struct mlx4_dev *dev) mlx4_free_icm(dev, priv->fw.aux_icm, 0); } +static int map_bf_area(struct mlx4_dev *dev) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + resource_size_t bf_start; + resource_size_t bf_len; + int err = 0; + + bf_start = pci_resource_start(dev->pdev, 2) + (dev->caps.num_uars << PAGE_SHIFT); + bf_len = pci_resource_len(dev->pdev, 2) - (dev->caps.num_uars << PAGE_SHIFT); + priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len); + if (!priv->bf_mapping) + err = -ENOMEM; + + return err; +} + +static void unmap_bf_area(struct mlx4_dev *dev) +{ + if (mlx4_priv(dev)->bf_mapping) + io_mapping_free(mlx4_priv(dev)->bf_mapping); +} + static void mlx4_close_hca(struct mlx4_dev *dev) { + unmap_bf_area(dev); mlx4_CLOSE_HCA(dev, 0); mlx4_free_icms(dev); mlx4_UNMAP_FA(dev); @@ -775,6 +799,9 @@ static int mlx4_init_hca(struct mlx4_dev *dev) goto err_stop_fw; } + if (map_bf_area(dev)) + mlx4_dbg(dev, "Failed to map blue flame area\n"); + init_hca.log_uar_sz = ilog2(dev->caps.num_uars); err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size); @@ -805,6 +832,7 @@ err_free_icm: mlx4_free_icms(dev); err_stop_fw: + unmap_bf_area(dev); mlx4_UNMAP_FA(dev); mlx4_free_icm(dev, priv->fw.fw_icm, 0); @@ -1196,6 +1224,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_read_config_byte(pdev, PCI_REVISION_ID, &dev->rev_id); + INIT_LIST_HEAD(&priv->bf_list); + mutex_init(&priv->bf_mutex); + /* * Now reset the HCA before we touch the PCI capabilities or * attempt a firmware command, since a boot ROM may have left diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index d8bb4418581b..bc9a21657a4f 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -353,6 +353,9 @@ struct mlx4_priv { struct mutex port_mutex; struct mlx4_msix_ctl msix_ctl; struct mlx4_steer *steer; + struct list_head bf_list; + struct mutex bf_mutex; + struct io_mapping *bf_mapping; }; static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index c4988d6bd5b2..5210a0f31413 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c @@ -32,6 +32,7 @@ */ #include +#include #include @@ -77,6 +78,7 @@ int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar) return -ENOMEM; uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + uar->index; + uar->map = NULL; return 0; } @@ -88,6 +90,98 @@ void mlx4_uar_free(struct mlx4_dev *dev, struct mlx4_uar *uar) } EXPORT_SYMBOL_GPL(mlx4_uar_free); +int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_uar *uar; + int err = 0; + int idx; + + if (!priv->bf_mapping) + return -ENOMEM; + + mutex_lock(&priv->bf_mutex); + if (!list_empty(&priv->bf_list)) + uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); + else { + uar = kmalloc(sizeof *uar, GFP_KERNEL); + if (!uar) { + err = -ENOMEM; + goto out; + } + err = mlx4_uar_alloc(dev, uar); + if (err) + goto free_kmalloc; + + uar->map = ioremap(uar->pfn << PAGE_SHIFT, PAGE_SIZE); + if (!uar->map) { + err = -ENOMEM; + goto free_uar; + } + + uar->bf_map = io_mapping_map_wc(priv->bf_mapping, uar->index << PAGE_SHIFT); + if (!uar->bf_map) { + err = -ENOMEM; + goto unamp_uar; + } + uar->free_bf_bmap = 0; + list_add(&uar->bf_list, &priv->bf_list); + } + + bf->uar = uar; + idx = ffz(uar->free_bf_bmap); + uar->free_bf_bmap |= 1 << idx; + bf->uar = uar; + bf->offset = 0; + bf->buf_size = dev->caps.bf_reg_size / 2; + bf->reg = uar->bf_map + idx * dev->caps.bf_reg_size; + if (uar->free_bf_bmap == (1 << dev->caps.bf_regs_per_page) - 1) + list_del_init(&uar->bf_list); + + goto out; + +unamp_uar: + bf->uar = NULL; + iounmap(uar->map); + +free_uar: + mlx4_uar_free(dev, uar); + +free_kmalloc: + kfree(uar); + +out: + mutex_unlock(&priv->bf_mutex); + return err; +} +EXPORT_SYMBOL_GPL(mlx4_bf_alloc); + +void mlx4_bf_free(struct mlx4_dev *dev, struct mlx4_bf *bf) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int idx; + + if (!bf->uar || !bf->uar->bf_map) + return; + + mutex_lock(&priv->bf_mutex); + idx = (bf->reg - bf->uar->bf_map) / dev->caps.bf_reg_size; + bf->uar->free_bf_bmap &= ~(1 << idx); + if (!bf->uar->free_bf_bmap) { + if (!list_empty(&bf->uar->bf_list)) + list_del(&bf->uar->bf_list); + + io_mapping_unmap(bf->uar->bf_map); + iounmap(bf->uar->map); + mlx4_uar_free(dev, bf->uar); + kfree(bf->uar); + } else if (list_empty(&bf->uar->bf_list)) + list_add(&bf->uar->bf_list, &priv->bf_list); + + mutex_unlock(&priv->bf_mutex); +} +EXPORT_SYMBOL_GPL(mlx4_bf_free); + int mlx4_init_uar_table(struct mlx4_dev *dev) { if (dev->caps.num_uars <= 128) { -- cgit v1.2.2 From 42d1e017e2f040c3e3d62b6cfa3a26351a865d04 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 22 Mar 2011 22:38:45 +0000 Subject: mlx4_core: maintain available field in bitmap allocator Add mlx4_bitmap_avail() to give the number of available resources. We want to use this as a hint to whether to allocate a resources or not. This patch is introduced to be used with allocation blue flame registers. Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/mlx4/alloc.c | 13 +++++++++++++ drivers/net/mlx4/mlx4.h | 2 ++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mlx4/alloc.c b/drivers/net/mlx4/alloc.c index 3a4277f6fac4..116cae334dad 100644 --- a/drivers/net/mlx4/alloc.c +++ b/drivers/net/mlx4/alloc.c @@ -62,6 +62,9 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap) } else obj = -1; + if (obj != -1) + --bitmap->avail; + spin_unlock(&bitmap->lock); return obj; @@ -101,11 +104,19 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) } else obj = -1; + if (obj != -1) + bitmap->avail -= cnt; + spin_unlock(&bitmap->lock); return obj; } +u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap) +{ + return bitmap->avail; +} + void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) { obj &= bitmap->max + bitmap->reserved_top - 1; @@ -115,6 +126,7 @@ void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt) bitmap->last = min(bitmap->last, obj); bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) & bitmap->mask; + bitmap->avail += cnt; spin_unlock(&bitmap->lock); } @@ -130,6 +142,7 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, bitmap->max = num - reserved_top; bitmap->mask = mask; bitmap->reserved_top = reserved_top; + bitmap->avail = num - reserved_top - reserved_bot; spin_lock_init(&bitmap->lock); bitmap->table = kzalloc(BITS_TO_LONGS(bitmap->max) * sizeof (long), GFP_KERNEL); diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index bc9a21657a4f..c1e0e5f1bcdb 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -105,6 +105,7 @@ struct mlx4_bitmap { u32 max; u32 reserved_top; u32 mask; + u32 avail; spinlock_t lock; unsigned long *table; }; @@ -371,6 +372,7 @@ u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); void mlx4_bitmap_free_range(struct mlx4_bitmap *bitmap, u32 obj, int cnt); +u32 mlx4_bitmap_avail(struct mlx4_bitmap *bitmap); int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, u32 mask, u32 reserved_bot, u32 resetrved_top); void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap); -- cgit v1.2.2 From 9ace5e0176f165f04537497143506621d33a0139 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Tue, 22 Mar 2011 22:38:48 +0000 Subject: mlx4_core: reserve UARs for userspace consumers Do not allow a kernel consumer to allocate a UAR to serve for blue flame if the number of available UARs gets below MLX4_NUM_RESERVED_UARS (currently 8). This will allow userspace apps to open a device file and run things like ibv_devinfo. Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/mlx4/pd.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c index 5210a0f31413..1286b886dcea 100644 --- a/drivers/net/mlx4/pd.c +++ b/drivers/net/mlx4/pd.c @@ -39,6 +39,10 @@ #include "mlx4.h" #include "icm.h" +enum { + MLX4_NUM_RESERVED_UARS = 8 +}; + int mlx4_pd_alloc(struct mlx4_dev *dev, u32 *pdn) { struct mlx4_priv *priv = mlx4_priv(dev); @@ -104,6 +108,10 @@ int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf) if (!list_empty(&priv->bf_list)) uar = list_entry(priv->bf_list.next, struct mlx4_uar, bf_list); else { + if (mlx4_bitmap_avail(&priv->uar_table.bitmap) < MLX4_NUM_RESERVED_UARS) { + err = -ENOMEM; + goto out; + } uar = kmalloc(sizeof *uar, GFP_KERNEL); if (!uar) { err = -ENOMEM; -- cgit v1.2.2 From 87a5c3896f9cf3b7f374af95b342d1089989327a Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:38:52 +0000 Subject: mlx4_en: Using blue flame support Doorbell is used according to usage of BlueFlame. For Blue Flame to work in Ethernet mode QP number should have 0 at bits 6,7. Allocating range of QPs accordingly. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 10 +++++- drivers/net/mlx4/en_tx.c | 72 ++++++++++++++++++++++++++++++++------------ drivers/net/mlx4/mlx4_en.h | 4 ++- 3 files changed, 64 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 08e680100db8..5762ebde4455 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -931,6 +931,13 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) { struct mlx4_en_port_profile *prof = priv->prof; int i; + int base_tx_qpn, err; + + err = mlx4_qp_reserve_range(priv->mdev->dev, priv->tx_ring_num, 256, &base_tx_qpn); + if (err) { + en_err(priv, "failed reserving range for TX rings\n"); + return err; + } /* Create tx Rings */ for (i = 0; i < priv->tx_ring_num; i++) { @@ -938,7 +945,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) prof->tx_ring_size, i, TX)) goto err; - if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], + if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[i], base_tx_qpn + i, prof->tx_ring_size, TXBB_SIZE)) goto err; } @@ -958,6 +965,7 @@ int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) err: en_err(priv, "Failed to allocate NIC resources\n"); + mlx4_qp_release_range(priv->mdev->dev, base_tx_qpn, priv->tx_ring_num); return -ENOMEM; } diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index a680cd4a5ab6..01feb8fd42ad 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -44,6 +44,7 @@ enum { MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ + MAX_BF = 256, }; static int inline_thold __read_mostly = MAX_INLINE; @@ -52,7 +53,7 @@ module_param_named(inline_thold, inline_thold, int, 0444); MODULE_PARM_DESC(inline_thold, "threshold for using inline data"); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, - struct mlx4_en_tx_ring *ring, u32 size, + struct mlx4_en_tx_ring *ring, int qpn, u32 size, u16 stride) { struct mlx4_en_dev *mdev = priv->mdev; @@ -103,23 +104,25 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, "buf_size:%d dma:%llx\n", ring, ring->buf, ring->size, ring->buf_size, (unsigned long long) ring->wqres.buf.direct.map); - err = mlx4_qp_reserve_range(mdev->dev, 1, 1, &ring->qpn); - if (err) { - en_err(priv, "Failed reserving qp for tx ring.\n"); - goto err_map; - } - + ring->qpn = qpn; err = mlx4_qp_alloc(mdev->dev, ring->qpn, &ring->qp); if (err) { en_err(priv, "Failed allocating qp %d\n", ring->qpn); - goto err_reserve; + goto err_map; } ring->qp.event = mlx4_en_sqp_event; + err = mlx4_bf_alloc(mdev->dev, &ring->bf); + if (err) { + en_dbg(DRV, priv, "working without blueflame (%d)", err); + ring->bf.uar = &mdev->priv_uar; + ring->bf.uar->map = mdev->uar_map; + ring->bf_enabled = false; + } else + ring->bf_enabled = true; + return 0; -err_reserve: - mlx4_qp_release_range(mdev->dev, ring->qpn, 1); err_map: mlx4_en_unmap_buffer(&ring->wqres.buf); err_hwq_res: @@ -139,6 +142,8 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_dev *mdev = priv->mdev; en_dbg(DRV, priv, "Destroying tx ring, qpn: %d\n", ring->qpn); + if (ring->bf_enabled) + mlx4_bf_free(mdev->dev, &ring->bf); mlx4_qp_remove(mdev->dev, &ring->qp); mlx4_qp_free(mdev->dev, &ring->qp); mlx4_qp_release_range(mdev->dev, ring->qpn, 1); @@ -171,6 +176,8 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, mlx4_en_fill_qp_context(priv, ring->size, ring->stride, 1, 0, ring->qpn, ring->cqn, &ring->context); + if (ring->bf_enabled) + ring->context.usr_page = cpu_to_be32(ring->bf.uar->index); err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, &ring->context, &ring->qp, &ring->qp_state); @@ -591,6 +598,11 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) return skb_tx_hash(dev, skb); } +static void mlx4_bf_copy(unsigned long *dst, unsigned long *src, unsigned bytecnt) +{ + __iowrite64_copy(dst, src, bytecnt / 8); +} + netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); @@ -609,12 +621,13 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) int desc_size; int real_size; dma_addr_t dma; - u32 index; + u32 index, bf_index; __be32 op_own; u16 vlan_tag = 0; int i; int lso_header_size; void *fragptr; + bool bounce = false; if (!priv->port_up) goto tx_drop; @@ -657,13 +670,16 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) /* Packet is good - grab an index and transmit it */ index = ring->prod & ring->size_mask; + bf_index = ring->prod; /* See if we have enough space for whole descriptor TXBB for setting * SW ownership on next descriptor; if not, use a bounce buffer. */ if (likely(index + nr_txbb <= ring->size)) tx_desc = ring->buf + index * TXBB_SIZE; - else + else { tx_desc = (struct mlx4_en_tx_desc *) ring->bounce_buf; + bounce = true; + } /* Save skb in tx_info ring */ tx_info = &ring->tx_info[index]; @@ -768,21 +784,37 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->prod += nr_txbb; /* If we used a bounce buffer then copy descriptor back into place */ - if (tx_desc == (struct mlx4_en_tx_desc *) ring->bounce_buf) + if (bounce) tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size); /* Run destructor before passing skb to HW */ if (likely(!skb_shared(skb))) skb_orphan(skb); - /* Ensure new descirptor hits memory - * before setting ownership of this descriptor to HW */ - wmb(); - tx_desc->ctrl.owner_opcode = op_own; + if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) { + *(u32 *) (&tx_desc->ctrl.vlan_tag) |= ring->doorbell_qpn; + op_own |= htonl((bf_index & 0xffff) << 8); + /* Ensure new descirptor hits memory + * before setting ownership of this descriptor to HW */ + wmb(); + tx_desc->ctrl.owner_opcode = op_own; - /* Ring doorbell! */ - wmb(); - writel(ring->doorbell_qpn, mdev->uar_map + MLX4_SEND_DOORBELL); + wmb(); + + mlx4_bf_copy(ring->bf.reg + ring->bf.offset, (unsigned long *) &tx_desc->ctrl, + desc_size); + + wmb(); + + ring->bf.offset ^= ring->bf.buf_size; + } else { + /* Ensure new descirptor hits memory + * before setting ownership of this descriptor to HW */ + wmb(); + tx_desc->ctrl.owner_opcode = op_own; + wmb(); + writel(ring->doorbell_qpn, ring->bf.uar->map + MLX4_SEND_DOORBELL); + } /* Poll CQ here */ mlx4_en_xmit_poll(priv, tx_ind); diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 5a2c56023668..edcb53562c10 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -248,6 +248,8 @@ struct mlx4_en_tx_ring { unsigned long bytes; unsigned long packets; spinlock_t comp_lock; + struct mlx4_bf bf; + bool bf_enabled; }; struct mlx4_en_rx_desc { @@ -518,7 +520,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, - u32 size, u16 stride); + int qpn, u32 size, u16 stride); void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring, -- cgit v1.2.2 From 61b85bf6060bfd205c218f5aeb71c19a24abb0cd Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Tue, 22 Mar 2011 22:39:05 +0000 Subject: mlx4_en: updated driver version to 1.5.4.1 Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/mlx4_en.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index edcb53562c10..e30f6099c0de 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -49,8 +49,8 @@ #include "en_port.h" #define DRV_NAME "mlx4_en" -#define DRV_VERSION "1.5.1.6" -#define DRV_RELDATE "August 2010" +#define DRV_VERSION "1.5.4.1" +#define DRV_RELDATE "March 2011" #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) -- cgit v1.2.2 From cda6587c21a887254c8ed4b58da8fcc4040ab557 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 23 Mar 2011 02:44:30 +0000 Subject: myri10ge: fix rmmod crash Rmmod myri10ge crash at free_netdev() -> netif_napi_del(), because napi structures are already deallocated. To fix call netif_napi_del() before kfree() at myri10ge_free_slices(). Cc: stable@kernel.org Signed-off-by: Stanislaw Gruszka Signed-off-by: David S. Miller --- drivers/net/myri10ge/myri10ge.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index a7f2eed9a08a..1f4e8680a96a 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -3645,6 +3645,7 @@ static void myri10ge_free_slices(struct myri10ge_priv *mgp) dma_free_coherent(&pdev->dev, bytes, ss->fw_stats, ss->fw_stats_bus); ss->fw_stats = NULL; + netif_napi_del(&ss->napi); } } kfree(mgp->ss); -- cgit v1.2.2 From 35d48903e9781975e823b359ee85c257c9ff5c1c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 22 Mar 2011 02:38:12 +0000 Subject: bonding: fix rx_handler locking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prevents possible race between bond_enslave and bond_handle_frame as reported by Nicolas by moving rx_handler register/unregister. slave->bond is added to hold pointer to master bonding sructure. That way dev->master is no longer used in bond_handler_frame. Also, this removes "BUG: scheduling while atomic" message Reported-by: Nicolas de Pesloüan Signed-off-by: Jiri Pirko Signed-off-by: Andy Gospodarek Tested-by: Nicolas de Pesloüan Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 56 +++++++++++++++++++++++------------------ drivers/net/bonding/bonding.h | 1 + 2 files changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 338bea147c64..16d6fe954695 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1482,21 +1482,16 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; struct slave *slave; - struct net_device *bond_dev; struct bonding *bond; - slave = bond_slave_get_rcu(skb->dev); - bond_dev = ACCESS_ONCE(slave->dev->master); - if (unlikely(!bond_dev)) - return RX_HANDLER_PASS; - skb = skb_share_check(skb, GFP_ATOMIC); if (unlikely(!skb)) return RX_HANDLER_CONSUMED; *pskb = skb; - bond = netdev_priv(bond_dev); + slave = bond_slave_get_rcu(skb->dev); + bond = slave->bond; if (bond->params.arp_interval) slave->dev->last_rx = jiffies; @@ -1505,10 +1500,10 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) return RX_HANDLER_EXACT; } - skb->dev = bond_dev; + skb->dev = bond->dev; if (bond->params.mode == BOND_MODE_ALB && - bond_dev->priv_flags & IFF_BRIDGE_PORT && + bond->dev->priv_flags & IFF_BRIDGE_PORT && skb->pkt_type == PACKET_HOST) { if (unlikely(skb_cow_head(skb, @@ -1516,7 +1511,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) kfree_skb(skb); return RX_HANDLER_CONSUMED; } - memcpy(eth_hdr(skb)->h_dest, bond_dev->dev_addr, ETH_ALEN); + memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN); } return RX_HANDLER_ANOTHER; @@ -1698,20 +1693,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) pr_debug("Error %d calling netdev_set_bond_master\n", res); goto err_restore_mac; } - res = netdev_rx_handler_register(slave_dev, bond_handle_frame, - new_slave); - if (res) { - pr_debug("Error %d calling netdev_rx_handler_register\n", res); - goto err_unset_master; - } /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { pr_debug("Opening slave %s failed\n", slave_dev->name); - goto err_unreg_rxhandler; + goto err_unset_master; } + new_slave->bond = bond; new_slave->dev = slave_dev; slave_dev->priv_flags |= IFF_BONDING; @@ -1907,6 +1897,13 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (res) goto err_close; + res = netdev_rx_handler_register(slave_dev, bond_handle_frame, + new_slave); + if (res) { + pr_debug("Error %d calling netdev_rx_handler_register\n", res); + goto err_dest_symlinks; + } + pr_info("%s: enslaving %s as a%s interface with a%s link.\n", bond_dev->name, slave_dev->name, bond_is_active_slave(new_slave) ? "n active" : " backup", @@ -1916,13 +1913,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) return 0; /* Undo stages on error */ +err_dest_symlinks: + bond_destroy_slave_symlinks(bond_dev, slave_dev); + err_close: dev_close(slave_dev); -err_unreg_rxhandler: - netdev_rx_handler_unregister(slave_dev); - synchronize_net(); - err_unset_master: netdev_set_bond_master(slave_dev, NULL); @@ -1988,6 +1984,14 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) return -EINVAL; } + /* unregister rx_handler early so bond_handle_frame wouldn't be called + * for this slave anymore. + */ + netdev_rx_handler_unregister(slave_dev); + write_unlock_bh(&bond->lock); + synchronize_net(); + write_lock_bh(&bond->lock); + if (!bond->params.fail_over_mac) { if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) && bond->slave_cnt > 1) @@ -2104,8 +2108,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) netif_addr_unlock_bh(bond_dev); } - netdev_rx_handler_unregister(slave_dev); - synchronize_net(); netdev_set_bond_master(slave_dev, NULL); slave_disable_netpoll(slave); @@ -2186,6 +2188,12 @@ static int bond_release_all(struct net_device *bond_dev) */ write_unlock_bh(&bond->lock); + /* unregister rx_handler early so bond_handle_frame wouldn't + * be called for this slave anymore. + */ + netdev_rx_handler_unregister(slave_dev); + synchronize_net(); + if (bond_is_lb(bond)) { /* must be called only after the slave * has been detached from the list @@ -2217,8 +2225,6 @@ static int bond_release_all(struct net_device *bond_dev) netif_addr_unlock_bh(bond_dev); } - netdev_rx_handler_unregister(slave_dev); - synchronize_net(); netdev_set_bond_master(slave_dev, NULL); slave_disable_netpoll(slave); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 6b26962fd0ec..90736cb4d975 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -187,6 +187,7 @@ struct slave { struct net_device *dev; /* first - useful for panic debug */ struct slave *next; struct slave *prev; + struct bonding *bond; /* our master */ int delay; unsigned long jiffies; unsigned long last_arp_rx; -- cgit v1.2.2 From 1ddd5049545e0aa1a0ed19bca4d9c9c3ce1ac8a2 Mon Sep 17 00:00:00 2001 From: Bud Brown Date: Wed, 23 Mar 2011 20:47:11 +0100 Subject: cciss: fix lost command issue Under certain workloads a command may seem to get lost. IOW, the Smart Array thinks all commands have been completed but we still have commands in our completion queue. This may lead to system instability, filesystems going read-only, or even panics depending on the affected filesystem. We add an extra read to force the write to complete. Testing shows this extra read avoids the problem. Signed-off-by: Mike Miller Cc: stable@kernel.org Signed-off-by: Jens Axboe --- drivers/block/cciss.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 579f74918493..554bbd907d14 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -222,6 +222,7 @@ static void SA5_submit_command( ctlr_info_t *h, CommandList_struct *c) h->ctlr, c->busaddr); #endif /* CCISS_DEBUG */ writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + readl(h->vaddr + SA5_REQUEST_PORT_OFFSET); h->commands_outstanding++; if ( h->commands_outstanding > h->max_outstanding) h->max_outstanding = h->commands_outstanding; -- cgit v1.2.2 From 9d02b42614149ebccf12c9c580601ed01bd83070 Mon Sep 17 00:00:00 2001 From: Michal Sojka Date: Tue, 15 Mar 2011 16:41:47 +0100 Subject: USB: Do not pass negative length to snoop_urb() When `echo Y > /sys/module/usbcore/parameters/usbfs_snoop` and usb_control_msg() returns error, a lot of kernel memory is dumped to dmesg until unhandled kernel paging request occurs. Signed-off-by: Michal Sojka Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index a7131ad630f9..37518dfdeb98 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -802,7 +802,7 @@ static int proc_control(struct dev_state *ps, void __user *arg) tbuf, ctrl.wLength, tmo); usb_lock_device(dev); snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, - tbuf, i); + tbuf, max(i, 0)); if ((i > 0) && ctrl.wLength) { if (copy_to_user(ctrl.data, tbuf, i)) { free_page((unsigned long)tbuf); -- cgit v1.2.2 From b5a3b3d985493c173925907adfebf3edab236fe7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 16 Mar 2011 10:57:15 -0400 Subject: ehci-hcd: Bug fix: don't set a QH's Halt bit This patch (as1453) fixes a long-standing bug in the ehci-hcd driver. There is no need to set the Halt bit in the overlay region for an unlinked or blocked QH. Contrary to what the comment says, setting the Halt bit does not cause the QH to be patched later; that decision (made in qh_refresh()) depends only on whether the QH is currently pointing to a valid qTD. Likewise, setting the Halt bit does not prevent completions from activating the QH while it is "stopped"; they are prevented by the fact that qh_completions() temporarily changes qh->qh_state to QH_STATE_COMPLETING. On the other hand, there are circumstances in which the QH will be reactivated _without_ being patched; this happens after an URB beyond the head of the queue is unlinked. Setting the Halt bit will then cause the hardware to see the QH with both the Active and Halt bits set, an invalid combination that will prevent the queue from advancing and may even crash some controllers. Apparently the only reason this hasn't been reported before is that unlinking URBs from the middle of a running queue is quite uncommon. However Test 17, recently added to the usbtest driver, does exactly this, and it confirms the presence of the bug. In short, there is no reason to set the Halt bit for an unlinked or blocked QH, and there is a very good reason not to set it. Therefore the code that sets it is removed. Signed-off-by: Alan Stern Tested-by: Andiry Xu CC: David Brownell CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index fe99895fb098..98ded66e8d3f 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -315,7 +315,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) int stopped; unsigned count = 0; u8 state; - const __le32 halt = HALT_BIT(ehci); struct ehci_qh_hw *hw = qh->hw; if (unlikely (list_empty (&qh->qtd_list))) @@ -422,7 +421,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) && !(qtd->hw_alt_next & EHCI_LIST_END(ehci))) { stopped = 1; - goto halt; } /* stop scanning when we reach qtds the hc is using */ @@ -456,16 +454,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) */ ehci_clear_tt_buffer(ehci, qh, urb, token); } - - /* force halt for unlinked or blocked qh, so we'll - * patch the qh later and so that completions can't - * activate it while we "know" it's stopped. - */ - if ((halt & hw->hw_token) == 0) { -halt: - hw->hw_token |= halt; - wmb (); - } } /* unless we already know the urb's status, collect qtd status -- cgit v1.2.2 From 5f1e8ce75c19b0433aba6e0ea28937f1ee5d849e Mon Sep 17 00:00:00 2001 From: Hema HK Date: Thu, 17 Mar 2011 16:11:58 +0530 Subject: usb: musb: Fix for merge issue There was conflict while merging 2 patches. Enabling vbus code is wrongly moved to error check if loop. This is a fix to resolve the merge issue. Signed-off-by: Hema HK Cc: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 5c7b321d3959..98519c5d8b5c 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1880,12 +1880,12 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, if (retval < 0) { DBG(1, "add_hcd failed, %d\n", retval); goto err2; - - if ((musb->xceiv->last_event == USB_EVENT_ID) - && musb->xceiv->set_vbus) - otg_set_vbus(musb->xceiv, 1); } + if ((musb->xceiv->last_event == USB_EVENT_ID) + && musb->xceiv->set_vbus) + otg_set_vbus(musb->xceiv, 1); + hcd->self.uses_pio_for_control = 1; if (musb->xceiv->last_event == USB_EVENT_NONE) -- cgit v1.2.2 From 417ddf86c8c499fada439b8ee89bb4c6f282ed6c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 22 Mar 2011 14:43:37 -0400 Subject: usb: musb: blackfin: fix typo in platform driver name The modularization of the Blackfin driver set the name to "musb-blackfin" in all the boards, but "musb-bfin" in the driver itself. Since the driver file name uses "blackfin", change the driver to "musb-blackfin". This is also easier as it's only one file to change. Cc: stable@kernel.org Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/blackfin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 9d49d1cd7ce2..5da9ef8ff311 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -548,7 +548,7 @@ static struct dev_pm_ops bfin_pm_ops = { static struct platform_driver bfin_driver = { .remove = __exit_p(bfin_remove), .driver = { - .name = "musb-bfin", + .name = "musb-blackfin", .pm = DEV_PM_OPS, }, }; -- cgit v1.2.2 From 8f7e7b87ec7c3202941ef2770bacd353ab93368b Mon Sep 17 00:00:00 2001 From: Bob Liu Date: Mon, 21 Mar 2011 14:06:31 -0400 Subject: usb: musb: blackfin: fix typo in new dev_pm_ops struct Cc: stable@kernel.org Signed-off-by: Bob Liu Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/blackfin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 5da9ef8ff311..7843333b6199 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -540,7 +540,7 @@ static struct dev_pm_ops bfin_pm_ops = { .resume = bfin_resume, }; -#define DEV_PM_OPS &bfin_pm_op, +#define DEV_PM_OPS &bfin_pm_ops #else #define DEV_PM_OPS NULL #endif -- cgit v1.2.2 From 45567c28d29a8766a67c53f898d502aef71b7ef0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 21 Mar 2011 14:06:32 -0400 Subject: usb: musb: blackfin: fix typo in new bfin_musb_vbus_status func The common code has a "get" in the middle, but each implementation does not have it. Cc: stable@kernel.org Signed-off-by: Mike Frysinger Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/blackfin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 7843333b6199..52312e8af213 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -322,7 +322,7 @@ static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout) mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); } -static int bfin_musb_get_vbus_status(struct musb *musb) +static int bfin_musb_vbus_status(struct musb *musb) { return 0; } -- cgit v1.2.2 From adaa3c6342b249548ea830fe8e02aa5b45be8688 Mon Sep 17 00:00:00 2001 From: Peter Holik Date: Fri, 18 Mar 2011 18:47:44 +0100 Subject: USB: uss720 fixup refcount position My testprog do a lot of bitbang - after hours i got following warning and my machine lockups: WARNING: at /build/buildd/linux-2.6.38/lib/kref.c:34 After debugging uss720 driver i discovered that the completion callback was called before usb_submit_urb returns. The callback frees the request structure that is krefed on return by usb_submit_urb. Signed-off-by: Peter Holik Acked-by: Thomas Sailer Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/uss720.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index f7a205738032..8b1d94a76914 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -177,12 +177,11 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p spin_lock_irqsave(&priv->asynclock, flags); list_add_tail(&rq->asynclist, &priv->asynclist); spin_unlock_irqrestore(&priv->asynclock, flags); + kref_get(&rq->ref_count); ret = usb_submit_urb(rq->urb, mem_flags); - if (!ret) { - kref_get(&rq->ref_count); + if (!ret) return rq; - } - kref_put(&rq->ref_count, destroy_async); + destroy_async(&rq->ref_count); err("submit_async_request submit_urb failed with %d", ret); return NULL; } -- cgit v1.2.2 From 97ac01d8f1b8d1c9e5af32c2813ba771835961f9 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 18 Mar 2011 12:44:17 +0100 Subject: usb: wwan: fix compilation without CONFIG_PM_RUNTIME The pm usage counter must be accessed with the proper wrappers to allow compilation under all configurations. Signed-off-by: Oliver Neukum Reported-by: Eric Dumazet Reported-by: Tao Ma Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb_wwan.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index a65ddd543869..e4fad5e643d7 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -698,8 +698,7 @@ static void play_delayed(struct usb_serial_port *port) /* we have to throw away the rest */ do { unbusy_queued_urb(urb, portdata); - //extremely dirty - atomic_dec(&port->serial->interface->dev.power.usage_count); + usb_autopm_put_interface_no_suspend(port->serial->interface); } while ((urb = usb_get_from_anchor(&portdata->delayed))); break; } -- cgit v1.2.2 From 878b753e32ca765cd346a5d3038d630178ec78ff Mon Sep 17 00:00:00 2001 From: Robert Lukassen Date: Wed, 16 Mar 2011 12:13:34 +0100 Subject: USB: Fix 'bad dma' problem on WDM device disconnect In the WDM class driver a disconnect event leads to calls to usb_free_coherent to put back two USB DMA buffers allocated earlier. The call to usb_free_coherent uses a different size parameter (desc->wMaxCommand) than the corresponding call to usb_alloc_coherent (desc->bMaxPacketSize0). When a disconnect event occurs, this leads to 'bad dma' complaints from usb core because the USB DMA buffer is being pushed back to the 'buffer-2048' pool from which it has not been allocated. This patch against the most recent linux-2.6 kernel ensures that the parameters used by usb_alloc_coherent & usb_free_coherent calls in cdc-wdm.c match. Signed-off-by: Robert Lukassen Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 47085e5879ab..a97c018dd419 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -281,7 +281,7 @@ static void cleanup(struct wdm_device *desc) desc->sbuf, desc->validity->transfer_dma); usb_free_coherent(interface_to_usbdev(desc->intf), - desc->wMaxCommand, + desc->bMaxPacketSize0, desc->inbuf, desc->response->transfer_dma); kfree(desc->orq); -- cgit v1.2.2 From 23b80550e2aa61d0ba3af98b831b9195be0db9ee Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 22 Mar 2011 11:12:09 +0100 Subject: USB: cdc-acm: fix memory corruption / panic Prevent read urbs from being resubmitted from tasklet after port close. The receive tasklet was not disabled on port close, which could lead to corruption of receive lists on consecutive port open. In particular, read urbs could be re-submitted before port open, added to free list in open, and then added a second time to the free list in the completion handler. cdc-acm.c: Entering acm_tty_open. cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x3 len: 0x0 result: 0 cdc-acm.c: Entering acm_rx_tasklet cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da280, rcv 0xf57fbc24, buf 0xf57fbd64 cdc-acm.c: set line: 115200 0 0 8 cdc-acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7 cdc-acm.c: acm_tty_close cdc-acm.c: acm_port_down cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0 cdc-acm.c: acm_ctrl_irq - urb shutting down with status: -2 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da300, rcv 0xf57fbc10, buf 0xf57fbd50 cdc-acm.c: Entering acm_read_bulk with status -2 cdc_acm 4-1:1.1: Aborting, acm not ready cdc-acm.c: Entering acm_read_bulk with status -2 cdc_acm 4-1:1.1: Aborting, acm not ready cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da380, rcv 0xf57fbbfc, buf 0xf57fbd3c cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da400, rcv 0xf57fbbe8, buf 0xf57fbd28 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da480, rcv 0xf57fbbd4, buf 0xf57fbd14 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da900, rcv 0xf57fbbc0, buf 0xf57fbd00 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da980, rcv 0xf57fbbac, buf 0xf57fbcec cdc-acm.c: acm_rx_tasklet: sending urb 0xf50daa00, rcv 0xf57fbb98, buf 0xf57fbcd8 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50daa80, rcv 0xf57fbb84, buf 0xf57fbcc4 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50dab00, rcv 0xf57fbb70, buf 0xf57fbcb0 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50dab80, rcv 0xf57fbb5c, buf 0xf57fbc9c cdc-acm.c: acm_rx_tasklet: sending urb 0xf50dac00, rcv 0xf57fbb48, buf 0xf57fbc88 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50dac80, rcv 0xf57fbb34, buf 0xf57fbc74 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50dad00, rcv 0xf57fbb20, buf 0xf57fbc60 cdc-acm.c: acm_rx_tasklet: sending urb 0xf50dad80, rcv 0xf57fbb0c, buf 0xf57fbc4c cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da880, rcv 0xf57fbaf8, buf 0xf57fbc38 cdc-acm.c: Entering acm_tty_open. cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x3 len: 0x0 result: 0 cdc-acm.c: Entering acm_rx_tasklet cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da280, rcv 0xf57fbc24, buf 0xf57fbd64 cdc-acm.c: Entering acm_tty_write to write 3 bytes, cdc-acm.c: Get 3 bytes... cdc-acm.c: acm_write_start susp_count: 0 cdc-acm.c: Entering acm_read_bulk with status 0 ------------[ cut here ]------------ WARNING: at /home/johan/src/linux/linux-2.6/lib/list_debug.c:57 list_del+0x10c/0x120() Hardware name: Vostro 1520 list_del corruption. next->prev should be f57fbc10, but was f57fbaf8 Modules linked in: cdc_acm Pid: 3, comm: ksoftirqd/0 Not tainted 2.6.37+ #39 Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? list_del+0x10c/0x120 [] ? list_del+0x10c/0x120 [] warn_slowpath_fmt+0x33/0x40 [] list_del+0x10c/0x120 [] acm_rx_tasklet+0xef/0x3e0 [cdc_acm] [] ? net_rps_action_and_irq_enable+0x6d/0x80 [] tasklet_action+0xe6/0x140 [] __do_softirq+0xaf/0x210 [] ? __do_softirq+0x0/0x210 [] ? run_ksoftirqd+0x8a/0x1c0 [] ? run_ksoftirqd+0x0/0x1c0 [] ? kthread+0x74/0x80 [] ? kthread+0x0/0x80 [] ? kernel_thread_helper+0x6/0x10 ---[ end trace efd9a11434f0082e ]--- ------------[ cut here ]------------ WARNING: at /home/johan/src/linux/linux-2.6/lib/list_debug.c:57 list_del+0x10c/0x120() Hardware name: Vostro 1520 list_del corruption. next->prev should be f57fbd50, but was f57fbdb0 Modules linked in: cdc_acm Pid: 3, comm: ksoftirqd/0 Tainted: G W 2.6.37+ #39 Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? list_del+0x10c/0x120 [] ? list_del+0x10c/0x120 [] warn_slowpath_fmt+0x33/0x40 [] list_del+0x10c/0x120 [] acm_rx_tasklet+0x106/0x3e0 [cdc_acm] [] ? net_rps_action_and_irq_enable+0x6d/0x80 [] tasklet_action+0xe6/0x140 [] __do_softirq+0xaf/0x210 [] ? __do_softirq+0x0/0x210 [] ? run_ksoftirqd+0x8a/0x1c0 [] ? run_ksoftirqd+0x0/0x1c0 [] ? kthread+0x74/0x80 [] ? kthread+0x0/0x80 [] ? kernel_thread_helper+0x6/0x10 ---[ end trace efd9a11434f0082f ]--- cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da300, rcv 0xf57fbc10, buf 0xf57fbd50 cdc-acm.c: disconnected from network cdc-acm.c: acm_rx_tasklet: sending urb 0xf50da380, rcv 0xf57fbbfc, buf 0xf57fbd3c cdc-acm.c: Entering acm_rx_tasklet ------------[ cut here ]------------ WARNING: at /home/johan/src/linux/linux-2.6/lib/list_debug.c:48 list_del+0xd5/0x120() Hardware name: Vostro 1520 list_del corruption, next is LIST_POISON1 (00100100) Modules linked in: cdc_acm Pid: 3, comm: ksoftirqd/0 Tainted: G W 2.6.37+ #39 Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? list_del+0xd5/0x120 [] ? list_del+0xd5/0x120 [] warn_slowpath_fmt+0x33/0x40 [] list_del+0xd5/0x120 [] acm_rx_tasklet+0x2dc/0x3e0 [cdc_acm] [] ? trace_hardirqs_on+0xb/0x10 [] ? tasklet_action+0x60/0x140 [] tasklet_action+0xe6/0x140 [] __do_softirq+0xaf/0x210 [] ? __do_softirq+0x0/0x210 [] ? run_ksoftirqd+0x8a/0x1c0 [] ? run_ksoftirqd+0x0/0x1c0 [] ? kthread+0x74/0x80 [] ? kthread+0x0/0x80 [] ? kernel_thread_helper+0x6/0x10 ---[ end trace efd9a11434f00830 ]--- BUG: unable to handle kernel paging request at 00200200 IP: [] list_del+0x1d/0x120 *pde = 00000000 Oops: 0000 [#1] PREEMPT SMP last sysfs file: /sys/devices/pci0000:00/0000:00:1a.1/usb4/4-1/4-1:1.0/tty/ttyACM0/uevent Modules linked in: cdc_acm Pid: 3, comm: ksoftirqd/0 Tainted: G W 2.6.37+ #39 0T816J/Vostro 1520 EIP: 0060:[] EFLAGS: 00010046 CPU: 0 EIP is at list_del+0x1d/0x120 EAX: f57fbd3c EBX: f57fb800 ECX: ffff8000 EDX: 00200200 ESI: f57fbe90 EDI: f57fbd3c EBP: f600bf54 ESP: f600bf3c DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process ksoftirqd/0 (pid: 3, ti=f600a000 task=f60791c0 task.ti=f6082000) Stack: c1527e84 00000030 c1527e54 00100100 f57fb800 f57fbd3c f600bf98 f8051fac f8053104 f8052b94 f600bf6c c106dbab f600bf80 00000286 f60791c0 c1042b30 f57fbda8 f57f5800 f57fbdb0 f57fbd80 f57fbe7c c1656b04 00000000 f600bfb0 Call Trace: [] ? acm_rx_tasklet+0x2dc/0x3e0 [cdc_acm] [] ? trace_hardirqs_on+0xb/0x10 [] ? tasklet_action+0x60/0x140 [] ? tasklet_action+0xe6/0x140 [] ? __do_softirq+0xaf/0x210 [] ? __do_softirq+0x0/0x210 [] ? run_ksoftirqd+0x8a/0x1c0 [] ? run_ksoftirqd+0x0/0x1c0 [] ? kthread+0x74/0x80 [] ? kthread+0x0/0x80 [] ? kernel_thread_helper+0x6/0x10 Code: ff 48 14 e9 57 ff ff ff 90 90 90 90 90 90 55 89 e5 83 ec 18 81 38 00 01 10 00 0f 84 9c 00 00 00 8b 50 04 81 fa 00 02 20 00 74 33 <8b> 12 39 d0 75 5c 8b 10 8b 4a 04 39 c8 0f 85 b5 00 00 00 8b 48 EIP: [] list_del+0x1d/0x120 SS:ESP 0068:f600bf3c CR2: 0000000000200200 ---[ end trace efd9a11434f00831 ]--- Kernel panic - not syncing: Fatal exception in interrupt Pid: 3, comm: ksoftirqd/0 Tainted: G D W 2.6.37+ #39 Call Trace: [] ? printk+0x1d/0x24 [] panic+0x66/0x15c [] oops_end+0x8f/0x90 [] no_context+0xc6/0x160 [] __bad_area_nosemaphore+0x98/0x140 [] ? release_console_sem+0x1d8/0x210 [] bad_area_nosemaphore+0x17/0x20 [] do_page_fault+0x279/0x420 [] ? show_trace+0x1f/0x30 [] ? printk+0x1d/0x24 [] ? do_page_fault+0x0/0x420 [] error_code+0x5f/0x64 [] ? select_task_rq_fair+0x37b/0x6a0 [] ? do_page_fault+0x0/0x420 [] ? list_del+0x1d/0x120 [] acm_rx_tasklet+0x2dc/0x3e0 [cdc_acm] [] ? trace_hardirqs_on+0xb/0x10 [] ? tasklet_action+0x60/0x140 [] tasklet_action+0xe6/0x140 [] __do_softirq+0xaf/0x210 [] ? __do_softirq+0x0/0x210 [] ? run_ksoftirqd+0x8a/0x1c0 [] ? run_ksoftirqd+0x0/0x1c0 [] ? kthread+0x74/0x80 [] ? kthread+0x0/0x80 [] ? kernel_thread_helper+0x6/0x10 panic occurred, switching back to text console ------------[ cut here ]------------ Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index f492a7f2b6ee..00d809dfe84d 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -646,8 +646,10 @@ static void acm_port_down(struct acm *acm) usb_kill_urb(acm->ctrlurb); for (i = 0; i < ACM_NW; i++) usb_kill_urb(acm->wb[i].urb); + tasklet_disable(&acm->urb_task); for (i = 0; i < nr; i++) usb_kill_urb(acm->ru[i].urb); + tasklet_enable(&acm->urb_task); acm->control->needs_remote_wakeup = 0; usb_autopm_put_interface(acm->control); } -- cgit v1.2.2 From 15e5bee33ffc11d0e5c6f819a65e7881c5c407be Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 22 Mar 2011 11:12:10 +0100 Subject: USB: cdc-acm: fix potential null-pointer dereference Must check return value of tty_port_tty_get. Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 00d809dfe84d..175637148962 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -533,6 +533,8 @@ static void acm_softint(struct work_struct *work) if (!ACM_READY(acm)) return; tty = tty_port_tty_get(&acm->port); + if (!tty) + return; tty_wakeup(tty); tty_kref_put(tty); } -- cgit v1.2.2 From 7e7797e7f6f7bfab73fca02c65e40eaa5bb9000c Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 22 Mar 2011 11:12:11 +0100 Subject: USB: cdc-acm: fix potential null-pointer dereference on disconnect Fix potential null-pointer exception on disconnect introduced by commit 11ea859d64b69a747d6b060b9ed1520eab1161fe (USB: additional power savings for cdc-acm devices that support remote wakeup). Only access acm->dev after making sure it is non-null in control urb completion handler. Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 175637148962..e057e5381465 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -297,6 +297,8 @@ static void acm_ctrl_irq(struct urb *urb) if (!ACM_READY(acm)) goto exit; + usb_mark_last_busy(acm->dev); + data = (unsigned char *)(dr + 1); switch (dr->bNotificationType) { case USB_CDC_NOTIFY_NETWORK_CONNECTION: @@ -336,7 +338,6 @@ static void acm_ctrl_irq(struct urb *urb) break; } exit: - usb_mark_last_busy(acm->dev); retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with " -- cgit v1.2.2 From 38e9e21dac33082f0440d24aefb3466bb18bfed6 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 18 Mar 2011 10:21:28 -0600 Subject: dt: Refactor of_platform_bus_probe() The current implementation uses three copies of of basically identical code. This patch consolidates them to make the code simpler. Signed-off-by: Grant Likely --- drivers/of/platform.c | 55 +++++++++++++++++---------------------------------- 1 file changed, 18 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 1ce4c45c4ab2..f489e36af892 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -210,13 +210,16 @@ struct platform_device *of_platform_device_create(struct device_node *np, EXPORT_SYMBOL(of_platform_device_create); /** - * of_platform_bus_create - Create an OF device for a bus node and all its - * children. Optionally recursively instantiate matching busses. + * of_platform_bus_create() - Create a device for a node and its children. * @bus: device node of the bus to instantiate * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to - * disallow recursive creation of child busses + * disallow recursive creation of child buses + * @parent: parent for new device, or NULL for top level. + * + * Creates a platform_device for the provided device_node, and optionally + * recursively create devices for all the child nodes. */ -static int of_platform_bus_create(const struct device_node *bus, +static int of_platform_bus_create(struct device_node *bus, const struct of_device_id *matches, struct device *parent) { @@ -224,18 +227,13 @@ static int of_platform_bus_create(const struct device_node *bus, struct platform_device *dev; int rc = 0; + dev = of_platform_device_create(bus, NULL, parent); + if (!dev || !of_match_node(matches, bus)) + return 0; + for_each_child_of_node(bus, child) { pr_debug(" create child: %s\n", child->full_name); - dev = of_platform_device_create(child, NULL, parent); - if (dev == NULL) - continue; - - if (!of_match_node(matches, child)) - continue; - if (rc == 0) { - pr_debug(" and sub busses\n"); - rc = of_platform_bus_create(child, matches, &dev->dev); - } + rc = of_platform_bus_create(child, matches, &dev->dev); if (rc) { of_node_put(child); break; @@ -245,7 +243,7 @@ static int of_platform_bus_create(const struct device_node *bus, } /** - * of_platform_bus_probe - Probe the device-tree for platform busses + * of_platform_bus_probe() - Probe the device-tree for platform buses * @root: parent of the first level to probe or NULL for the root of the tree * @matches: match table, NULL to use the default * @parent: parent to hook devices from, NULL for toplevel @@ -258,7 +256,6 @@ int of_platform_bus_probe(struct device_node *root, struct device *parent) { struct device_node *child; - struct platform_device *dev; int rc = 0; if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE)) @@ -277,31 +274,15 @@ int of_platform_bus_probe(struct device_node *root, * children */ if (of_match_node(matches, root)) { - pr_debug(" root match, create all sub devices\n"); - dev = of_platform_device_create(root, NULL, parent); - if (dev == NULL) - goto bail; - - pr_debug(" create all sub busses\n"); - rc = of_platform_bus_create(root, matches, &dev->dev); - goto bail; - } - for_each_child_of_node(root, child) { + rc = of_platform_bus_create(root, matches, parent); + } else for_each_child_of_node(root, child) { if (!of_match_node(matches, child)) continue; - - pr_debug(" match: %s\n", child->full_name); - dev = of_platform_device_create(child, NULL, parent); - if (dev == NULL) - continue; - - rc = of_platform_bus_create(child, matches, &dev->dev); - if (rc) { - of_node_put(child); + rc = of_platform_bus_create(child, matches, parent); + if (rc) break; - } } - bail: + of_node_put(root); return rc; } -- cgit v1.2.2 From a52f07ecd143baee51623b063be5007585748a4f Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 18 Mar 2011 10:21:29 -0600 Subject: dt: protect against NULL matches passed to of_match_node() There are a few use cases where it is convenient to pass NULL to of_match_node() and have it fail gracefully. The patch adds a null check to the beginning so taht it does so. Signed-off-by: Grant Likely --- drivers/of/base.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 710b53bfac6d..632ebae7f17a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -496,6 +496,9 @@ EXPORT_SYMBOL(of_find_node_with_property); const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node) { + if (!matches) + return NULL; + while (matches->name[0] || matches->type[0] || matches->compatible[0]) { int match = 1; if (matches->name[0]) -- cgit v1.2.2 From 1eed4c077c31450bfcd0249aebb21d96fc5d5d3c Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Fri, 18 Mar 2011 10:21:29 -0600 Subject: dt: eliminate OF_NO_DEEP_PROBE and test for NULL match table There are no users of OF_NO_DEEP_PROBE, and of_match_node() now gracefully handles being passed a NULL pointer, so the checks at the top of of_platform_bus_probe can be dropped. While at it, consolidate the root node pointer check to be easier to read and tidy up related comments. Signed-off-by: Grant Likely --- drivers/of/platform.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/of/platform.c b/drivers/of/platform.c index f489e36af892..63d3cb73bdb9 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -212,7 +212,7 @@ EXPORT_SYMBOL(of_platform_device_create); /** * of_platform_bus_create() - Create a device for a node and its children. * @bus: device node of the bus to instantiate - * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to + * @matches: match table for bus nodes * disallow recursive creation of child buses * @parent: parent for new device, or NULL for top level. * @@ -245,7 +245,7 @@ static int of_platform_bus_create(struct device_node *bus, /** * of_platform_bus_probe() - Probe the device-tree for platform buses * @root: parent of the first level to probe or NULL for the root of the tree - * @matches: match table, NULL to use the default + * @matches: match table for bus nodes * @parent: parent to hook devices from, NULL for toplevel * * Note that children of the provided root are not instantiated as devices @@ -258,21 +258,14 @@ int of_platform_bus_probe(struct device_node *root, struct device_node *child; int rc = 0; - if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE)) - return -EINVAL; - if (root == NULL) - root = of_find_node_by_path("/"); - else - of_node_get(root); - if (root == NULL) + root = root ? of_node_get(root) : of_find_node_by_path("/"); + if (!root) return -EINVAL; pr_debug("of_platform_bus_probe()\n"); pr_debug(" starting at: %s\n", root->full_name); - /* Do a self check of bus type, if there's a match, create - * children - */ + /* Do a self check of bus type, if there's a match, create children */ if (of_match_node(matches, root)) { rc = of_platform_bus_create(root, matches, parent); } else for_each_child_of_node(root, child) { -- cgit v1.2.2 From a7006c9747ef225ab070d96c054e85682a09a13e Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Thu, 17 Mar 2011 17:32:35 -0700 Subject: of/flattree: minor cleanups - static-ize some functions - add some additional comments Signed-off-by: Andres Salomon Signed-off-by: Grant Likely --- drivers/of/fdt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index af824e7e0367..c9db49c10f45 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -139,12 +139,13 @@ static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size, /** * unflatten_dt_node - Alloc and populate a device_node from the flat tree * @blob: The parent device tree blob + * @mem: Memory chunk to use for allocating device nodes and properties * @p: pointer to node in flat tree * @dad: Parent struct device_node * @allnextpp: pointer to ->allnext from last allocated device_node * @fpsize: Size of the node path up at the current depth. */ -unsigned long unflatten_dt_node(struct boot_param_header *blob, +static unsigned long unflatten_dt_node(struct boot_param_header *blob, unsigned long mem, unsigned long *p, struct device_node *dad, @@ -230,6 +231,7 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob, } kref_init(&np->kref); } + /* process properties */ while (1) { u32 sz, noff; char *pname; @@ -351,7 +353,7 @@ unsigned long unflatten_dt_node(struct boot_param_header *blob, * @dt_alloc: An allocator that provides a virtual address to memory * for the resulting tree */ -void __unflatten_device_tree(struct boot_param_header *blob, +static void __unflatten_device_tree(struct boot_param_header *blob, struct device_node **mynodes, void * (*dt_alloc)(u64 size, u64 align)) { -- cgit v1.2.2 From 95c5c3ab7db0dcaeebeb771b90152cd47aa27243 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Mon, 21 Mar 2011 16:27:30 +0200 Subject: spi/omap_mcspi: Fix broken last word xfer Commit adef658 "spi/omap_mcspi: catch xfers of non-multiple SPI word size" broke the transmission of last word in cases where access is multiple of word size and word size is 16 or 32 bits. Fix this by replacing the test "c > (word_len>>3)" in do-while loops with "c >= 'pointer increment size'". This ensures that the last word is transmitted in above case and still allow to break the loop and prevent variable c underflow in cases where word size != 'pointer increment size'. Signed-off-by: Jarkko Nikula Tested-by: Sourav Poddar Acked-by: Michael Jones Signed-off-by: Grant Likely --- drivers/spi/omap2_mcspi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index 3a5ed06d3d2f..6f86ba0175ac 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -517,7 +517,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) dev_vdbg(&spi->dev, "read-%d %02x\n", word_len, *(rx - 1)); } - } while (c > (word_len>>3)); + } while (c); } else if (word_len <= 16) { u16 *rx; const u16 *tx; @@ -564,7 +564,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) dev_vdbg(&spi->dev, "read-%d %04x\n", word_len, *(rx - 1)); } - } while (c > (word_len>>3)); + } while (c >= 2); } else if (word_len <= 32) { u32 *rx; const u32 *tx; @@ -611,7 +611,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) dev_vdbg(&spi->dev, "read-%d %08x\n", word_len, *(rx - 1)); } - } while (c > (word_len>>3)); + } while (c >= 4); } /* for TX_ONLY mode, be sure all words have shifted out */ -- cgit v1.2.2 From 88e87be6ba528bd73522ecf0468fe32f1ee199e6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 22 Mar 2011 07:15:21 +0000 Subject: drivers/net/ariadne.c: Convert release_resource to release_region/release_mem_region Request_mem_region should be used with release_mem_region, not release_resource. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,E; @@ *x = request_mem_region(...) ... when != release_mem_region(x) when != x = E * release_resource(x); // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ariadne.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 7ca0eded2561..b7f45cd756a2 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -182,14 +182,14 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, return -EBUSY; r2 = request_mem_region(mem_start, ARIADNE_RAM_SIZE, "RAM"); if (!r2) { - release_resource(r1); + release_mem_region(base_addr, sizeof(struct Am79C960)); return -EBUSY; } dev = alloc_etherdev(sizeof(struct ariadne_private)); if (dev == NULL) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct Am79C960)); + release_mem_region(mem_start, ARIADNE_RAM_SIZE); return -ENOMEM; } @@ -213,8 +213,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, err = register_netdev(dev); if (err) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct Am79C960)); + release_mem_region(mem_start, ARIADNE_RAM_SIZE); free_netdev(dev); return err; } -- cgit v1.2.2 From e6937ee626dee9c66ae820f5cca11efca2933845 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 22 Mar 2011 07:15:23 +0000 Subject: drivers/net/a2065.c: Convert release_resource to release_region/release_mem_region Request_mem_region should be used with release_mem_region, not release_resource. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,E; @@ *x = request_mem_region(...) ... when != release_mem_region(x) when != x = E * release_resource(x); // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/a2065.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index f142cc21e453..deaa8bc16cf8 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -711,14 +711,14 @@ static int __devinit a2065_init_one(struct zorro_dev *z, return -EBUSY; r2 = request_mem_region(mem_start, A2065_RAM_SIZE, "RAM"); if (!r2) { - release_resource(r1); + release_mem_region(base_addr, sizeof(struct lance_regs)); return -EBUSY; } dev = alloc_etherdev(sizeof(struct lance_private)); if (dev == NULL) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct lance_regs)); + release_mem_region(mem_start, A2065_RAM_SIZE); return -ENOMEM; } @@ -764,8 +764,8 @@ static int __devinit a2065_init_one(struct zorro_dev *z, err = register_netdev(dev); if (err) { - release_resource(r1); - release_resource(r2); + release_mem_region(base_addr, sizeof(struct lance_regs)); + release_mem_region(mem_start, A2065_RAM_SIZE); free_netdev(dev); return err; } -- cgit v1.2.2 From 134fac3f457f3dd753ecdb25e6da3e5f6629f696 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 23 Mar 2011 22:16:14 +0100 Subject: PCI / Intel IOMMU: Use syscore_ops instead of sysdev class and sysdev The Intel IOMMU subsystem uses a sysdev class and a sysdev for executing iommu_suspend() after interrupts have been turned off on the boot CPU (during system suspend) and for executing iommu_resume() before turning on interrupts on the boot CPU (during system resume). However, since both of these functions ignore their arguments, the entire mechanism may be replaced with a struct syscore_ops object which is simpler. Signed-off-by: Rafael J. Wysocki Acked-by: Joerg Roedel --- drivers/pci/intel-iommu.c | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4789f8e8bf7a..a4115f1afe1f 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -3135,7 +3135,7 @@ static void iommu_flush_all(void) } } -static int iommu_suspend(struct sys_device *dev, pm_message_t state) +static int iommu_suspend(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu = NULL; @@ -3175,7 +3175,7 @@ nomem: return -ENOMEM; } -static int iommu_resume(struct sys_device *dev) +static void iommu_resume(void) { struct dmar_drhd_unit *drhd; struct intel_iommu *iommu = NULL; @@ -3183,7 +3183,7 @@ static int iommu_resume(struct sys_device *dev) if (init_iommu_hw()) { WARN(1, "IOMMU setup failed, DMAR can not resume!\n"); - return -EIO; + return; } for_each_active_iommu(iommu, drhd) { @@ -3204,40 +3204,20 @@ static int iommu_resume(struct sys_device *dev) for_each_active_iommu(iommu, drhd) kfree(iommu->iommu_state); - - return 0; } -static struct sysdev_class iommu_sysclass = { - .name = "iommu", +static struct syscore_ops iommu_syscore_ops = { .resume = iommu_resume, .suspend = iommu_suspend, }; -static struct sys_device device_iommu = { - .cls = &iommu_sysclass, -}; - -static int __init init_iommu_sysfs(void) +static void __init init_iommu_pm_ops(void) { - int error; - - error = sysdev_class_register(&iommu_sysclass); - if (error) - return error; - - error = sysdev_register(&device_iommu); - if (error) - sysdev_class_unregister(&iommu_sysclass); - - return error; + register_syscore_ops(&iommu_syscore_ops); } #else -static int __init init_iommu_sysfs(void) -{ - return 0; -} +static inline int init_iommu_pm_ops(void) { } #endif /* CONFIG_PM */ /* @@ -3320,7 +3300,7 @@ int __init intel_iommu_init(void) #endif dma_ops = &intel_dma_ops; - init_iommu_sysfs(); + init_iommu_pm_ops(); register_iommu(&intel_iommu_ops); -- cgit v1.2.2 From e00e56dfd3cf1d209ce630a2b440c91e4a30bbd3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 23 Mar 2011 22:16:32 +0100 Subject: cpufreq: Use syscore_ops for boot CPU suspend/resume (v2) The cpufreq subsystem uses sysdev suspend and resume for executing cpufreq_suspend() and cpufreq_resume(), respectively, during system suspend, after interrupts have been switched off on the boot CPU, and during system resume, while interrupts are still off on the boot CPU. In both cases the other CPUs are off-line at the relevant point (either they have been switched off via CPU hotplug during suspend, or they haven't been switched on yet during resume). For this reason, although it may seem that cpufreq_suspend() and cpufreq_resume() are executed for all CPUs in the system, they are only called for the boot CPU in fact, which is quite confusing. To remove the confusion and to prepare for elimiating sysdev suspend and resume operations from the kernel enirely, convernt cpufreq to using a struct syscore_ops object for the boot CPU suspend and resume and rename the callbacks so that their names reflect their purpose. In addition, put some explanatory remarks into their kerneldoc comments. Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 66 +++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0f17ad8585d7..b03771d4787c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -1340,35 +1341,31 @@ out: } EXPORT_SYMBOL(cpufreq_get); +static struct sysdev_driver cpufreq_sysdev_driver = { + .add = cpufreq_add_dev, + .remove = cpufreq_remove_dev, +}; + /** - * cpufreq_suspend - let the low level driver prepare for suspend + * cpufreq_bp_suspend - Prepare the boot CPU for system suspend. + * + * This function is only executed for the boot processor. The other CPUs + * have been put offline by means of CPU hotplug. */ - -static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) +static int cpufreq_bp_suspend(void) { int ret = 0; - int cpu = sysdev->id; + int cpu = smp_processor_id(); struct cpufreq_policy *cpu_policy; dprintk("suspending cpu %u\n", cpu); - if (!cpu_online(cpu)) - return 0; - - /* we may be lax here as interrupts are off. Nonetheless - * we need to grab the correct cpu policy, as to check - * whether we really run on this CPU. - */ - + /* If there's no policy for the boot CPU, we have nothing to do. */ cpu_policy = cpufreq_cpu_get(cpu); if (!cpu_policy) - return -EINVAL; - - /* only handle each CPU group once */ - if (unlikely(cpu_policy->cpu != cpu)) - goto out; + return 0; if (cpufreq_driver->suspend) { ret = cpufreq_driver->suspend(cpu_policy); @@ -1377,13 +1374,12 @@ static int cpufreq_suspend(struct sys_device *sysdev, pm_message_t pmsg) "step on CPU %u\n", cpu_policy->cpu); } -out: cpufreq_cpu_put(cpu_policy); return ret; } /** - * cpufreq_resume - restore proper CPU frequency handling after resume + * cpufreq_bp_resume - Restore proper frequency handling of the boot CPU. * * 1.) resume CPUfreq hardware support (cpufreq_driver->resume()) * 2.) schedule call cpufreq_update_policy() ASAP as interrupts are @@ -1391,31 +1387,23 @@ out: * what we believe it to be. This is a bit later than when it * should be, but nonethteless it's better than calling * cpufreq_driver->get() here which might re-enable interrupts... + * + * This function is only executed for the boot CPU. The other CPUs have not + * been turned on yet. */ -static int cpufreq_resume(struct sys_device *sysdev) +static void cpufreq_bp_resume(void) { int ret = 0; - int cpu = sysdev->id; + int cpu = smp_processor_id(); struct cpufreq_policy *cpu_policy; dprintk("resuming cpu %u\n", cpu); - if (!cpu_online(cpu)) - return 0; - - /* we may be lax here as interrupts are off. Nonetheless - * we need to grab the correct cpu policy, as to check - * whether we really run on this CPU. - */ - + /* If there's no policy for the boot CPU, we have nothing to do. */ cpu_policy = cpufreq_cpu_get(cpu); if (!cpu_policy) - return -EINVAL; - - /* only handle each CPU group once */ - if (unlikely(cpu_policy->cpu != cpu)) - goto fail; + return; if (cpufreq_driver->resume) { ret = cpufreq_driver->resume(cpu_policy); @@ -1430,14 +1418,11 @@ static int cpufreq_resume(struct sys_device *sysdev) fail: cpufreq_cpu_put(cpu_policy); - return ret; } -static struct sysdev_driver cpufreq_sysdev_driver = { - .add = cpufreq_add_dev, - .remove = cpufreq_remove_dev, - .suspend = cpufreq_suspend, - .resume = cpufreq_resume, +static struct syscore_ops cpufreq_syscore_ops = { + .suspend = cpufreq_bp_suspend, + .resume = cpufreq_bp_resume, }; @@ -2002,6 +1987,7 @@ static int __init cpufreq_core_init(void) cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_sysdev_class.kset.kobj); BUG_ON(!cpufreq_global_kobject); + register_syscore_ops(&cpufreq_syscore_ops); return 0; } -- cgit v1.2.2 From d47d81c0e9abdc3c88653fabff5beae82c949b09 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 23 Mar 2011 22:16:41 +0100 Subject: Introduce ARCH_NO_SYSDEV_OPS config option (v2) Introduce Kconfig option allowing architectures where sysdev operations used during system suspend, resume and shutdown have been completely replaced with struct sycore_ops operations to avoid building sysdev code that will never be used. Make callbacks in struct sys_device and struct sysdev_driver depend on ARCH_NO_SYSDEV_OPS to allows us to verify if all of the references have been actually removed from the code the given architecture depends on. Make x86 select ARCH_NO_SYSDEV_OPS. Signed-off-by: Rafael J. Wysocki --- drivers/base/Kconfig | 7 +++++++ drivers/base/sys.c | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index d57e8d0fb823..e9e5238f3106 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -168,4 +168,11 @@ config SYS_HYPERVISOR bool default n +config ARCH_NO_SYSDEV_OPS + bool + ---help--- + To be selected by architectures that don't use sysdev class or + sysdev driver power management (suspend/resume) and shutdown + operations. + endmenu diff --git a/drivers/base/sys.c b/drivers/base/sys.c index f6fb54741602..fbe72da6c414 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -329,7 +329,7 @@ void sysdev_unregister(struct sys_device *sysdev) } - +#ifndef CONFIG_ARCH_NO_SYSDEV_OPS /** * sysdev_shutdown - Shut down all system devices. * @@ -524,6 +524,7 @@ int sysdev_resume(void) return 0; } EXPORT_SYMBOL_GPL(sysdev_resume); +#endif /* CONFIG_ARCH_NO_SYSDEV_OPS */ int __init system_bus_init(void) { -- cgit v1.2.2 From 968b503e69a6b90aa4a3b9162960f605b6abd821 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 23 Mar 2011 18:16:55 +0000 Subject: Revert "drm/i915: Don't save/restore hardware status page address register" This reverts commit a7a75c8f70d6f6a2f16c9f627f938bbee2d32718. There are two different variations on how Intel hardware addresses the "Hardware Status Page". One as a location in physical memory and the other as an offset into the virtual memory of the GPU, used in more recent chipsets. (The HWS itself is a cacheable region of memory which the GPU can write to without requiring CPU synchronisation, used for updating various details of hardware state, such as the position of the GPU head in the ringbuffer, the last breadcrumb seqno, etc). These two types of addresses were updated in different locations of code - one inline with the ringbuffer initialisation, and the other during device initialisation. (The HWS page is logically associated with the rings, and there is one HWS page per ring.) During resume, only the ringbuffers were being re-initialised along with the virtual HWS page, leaving the older physical address HWS untouched. This then caused a hang on the older gen3/4 (915GM, 945GM, 965GM) the first time we tried to synchronise the GPU as the breadcrumbs were never being updated. Reported-and-tested-by: Linus Torvalds Reported-by: Jan Niehusmann Reported-by: Justin P. Mattock Reported-and-tested-by: Michael "brot" Groh Cc: Zhenyu Wang Signed-off-by: Chris Wilson Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_suspend.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 449650545bb4..5004724ea57e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -383,6 +383,7 @@ typedef struct drm_i915_private { u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; + u32 saveHWS; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 7e992a8e9098..da474153a0a2 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -796,6 +796,9 @@ int i915_save_state(struct drm_device *dev) pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + /* Hardware status page */ + dev_priv->saveHWS = I915_READ(HWS_PGA); + i915_save_display(dev); /* Interrupt state */ @@ -842,6 +845,9 @@ int i915_restore_state(struct drm_device *dev) pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); + /* Hardware status page */ + I915_WRITE(HWS_PGA, dev_priv->saveHWS); + i915_restore_display(dev); /* Interrupt state */ -- cgit v1.2.2 From 6b33aff368def952be78102c0935ebd219f9a748 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 23 Mar 2011 16:42:13 -0700 Subject: md: use little-endian bitops As a preparation for removing ext2 non-atomic bit operations from asm/bitops.h. This converts ext2 non-atomic bit operations to little-endian bit operations. Signed-off-by: Akinobu Mita Acked-by: NeilBrown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/bitmap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 9a35320fb59f..a2ce0b2da281 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -854,7 +854,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block) if (bitmap->flags & BITMAP_HOSTENDIAN) set_bit(bit, kaddr); else - ext2_set_bit(bit, kaddr); + __test_and_set_bit_le(bit, kaddr); kunmap_atomic(kaddr, KM_USER0); PRINTK("set file bit %lu page %lu\n", bit, page->index); } @@ -1050,7 +1050,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) if (bitmap->flags & BITMAP_HOSTENDIAN) b = test_bit(bit, paddr); else - b = ext2_test_bit(bit, paddr); + b = test_bit_le(bit, paddr); kunmap_atomic(paddr, KM_USER0); if (b) { /* if the disk bit is set, set the memory bit */ @@ -1226,7 +1226,7 @@ void bitmap_daemon_work(mddev_t *mddev) clear_bit(file_page_offset(bitmap, j), paddr); else - ext2_clear_bit(file_page_offset(bitmap, j), + __test_and_clear_bit_le(file_page_offset(bitmap, j), paddr); kunmap_atomic(paddr, KM_USER0); } else -- cgit v1.2.2 From bb5cda3d706f44e5696533c9a7353c458f2871e0 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 23 Mar 2011 16:42:13 -0700 Subject: dm: use little-endian bitops As a preparation for removing ext2 non-atomic bit operations from asm/bitops.h. This converts ext2 non-atomic bit operations to little-endian bit operations. Signed-off-by: Akinobu Mita Cc: Alasdair Kergon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/md/dm-log.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 6951536ea29c..57968eb382c1 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -251,20 +251,20 @@ struct log_c { */ static inline int log_test_bit(uint32_t *bs, unsigned bit) { - return ext2_test_bit(bit, (unsigned long *) bs) ? 1 : 0; + return test_bit_le(bit, (unsigned long *) bs) ? 1 : 0; } static inline void log_set_bit(struct log_c *l, uint32_t *bs, unsigned bit) { - ext2_set_bit(bit, (unsigned long *) bs); + __test_and_set_bit_le(bit, (unsigned long *) bs); l->touched_cleaned = 1; } static inline void log_clear_bit(struct log_c *l, uint32_t *bs, unsigned bit) { - ext2_clear_bit(bit, (unsigned long *) bs); + __test_and_clear_bit_le(bit, (unsigned long *) bs); l->touched_dirtied = 1; } @@ -740,7 +740,7 @@ static int core_get_resync_work(struct dm_dirty_log *log, region_t *region) return 0; do { - *region = ext2_find_next_zero_bit( + *region = find_next_zero_bit_le( (unsigned long *) lc->sync_bits, lc->region_count, lc->sync_search); -- cgit v1.2.2 From 0dcf334c44d99cd08515f4fc5cc9075abd92b2ff Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Wed, 23 Mar 2011 16:42:54 -0700 Subject: drivers/char/ipmi/ipmi_si_intf.c: fix cleanup_one_si section mismatch commit d2478521afc2022 ("char/ipmi: fix OOPS caused by pnp_unregister_driver on unregistered driver") introduced a section mismatch by calling __exit cleanup_ipmi_si from __devinit init_ipmi_si. Remove __exit annotation from cleanup_ipmi_si. Signed-off-by: Sergey Senozhatsky Acked-by: Corey Minyard Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/ipmi/ipmi_si_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index c86d43b88e1e..d28b484aee45 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -3521,7 +3521,7 @@ static void cleanup_one_si(struct smi_info *to_clean) kfree(to_clean); } -static void __exit cleanup_ipmi_si(void) +static void cleanup_ipmi_si(void) { struct smi_info *e, *tmp_e; -- cgit v1.2.2 From 73210a135b9dd53ba59beb4ced5a55633ae65b2f Mon Sep 17 00:00:00 2001 From: Niranjana Vishwanathapura Date: Wed, 23 Mar 2011 16:42:55 -0700 Subject: drivers/char: add MSM smd_pkt driver Add smd_pkt driver which provides device interface to smd packet ports. Signed-off-by: Niranjana Vishwanathapura Cc: Brian Swetland Cc: Greg KH Cc: Alan Cox Cc: David Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 8 + drivers/char/Makefile | 1 + drivers/char/msm_smd_pkt.c | 466 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 475 insertions(+) create mode 100644 drivers/char/msm_smd_pkt.c (limited to 'drivers') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 04f8b2d083c6..ad59b4e0a9b5 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -608,5 +608,13 @@ config RAMOOPS This enables panic and oops messages to be logged to a circular buffer in RAM where it can be read back at some later point. +config MSM_SMD_PKT + bool "Enable device interface for some SMD packet ports" + default n + depends on MSM_SMD + help + Enables userspace clients to read and write to some packet SMD + ports via device interface for MSM chipset. + endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 057f65452e7b..7a00672bd85d 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o +obj-$(CONFIG_MSM_SMD_PKT) += msm_smd_pkt.o obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c new file mode 100644 index 000000000000..b6f8a65c9960 --- /dev/null +++ b/drivers/char/msm_smd_pkt.c @@ -0,0 +1,466 @@ +/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +/* + * SMD Packet Driver -- Provides userspace interface to SMD packet ports. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NUM_SMD_PKT_PORTS 9 +#define DEVICE_NAME "smdpkt" +#define MAX_BUF_SIZE 2048 + +struct smd_pkt_dev { + struct cdev cdev; + struct device *devicep; + + struct smd_channel *ch; + int open_count; + struct mutex ch_lock; + struct mutex rx_lock; + struct mutex tx_lock; + wait_queue_head_t ch_read_wait_queue; + wait_queue_head_t ch_opened_wait_queue; + + int i; + + unsigned char tx_buf[MAX_BUF_SIZE]; + unsigned char rx_buf[MAX_BUF_SIZE]; + int remote_open; + +} *smd_pkt_devp[NUM_SMD_PKT_PORTS]; + +struct class *smd_pkt_classp; +static dev_t smd_pkt_number; + +static int msm_smd_pkt_debug_enable; +module_param_named(debug_enable, msm_smd_pkt_debug_enable, + int, S_IRUGO | S_IWUSR | S_IWGRP); + +#ifdef DEBUG +#define D_DUMP_BUFFER(prestr, cnt, buf) do { \ + int i; \ + if (msm_smd_pkt_debug_enable) { \ + pr_debug("%s", prestr); \ + for (i = 0; i < cnt; i++) \ + pr_debug("%.2x", buf[i]); \ + pr_debug("\n"); \ + } \ + } while (0) +#else +#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0) +#endif + +#ifdef DEBUG +#define DBG(x...) do { \ + if (msm_smd_pkt_debug_enable) \ + pr_debug(x); \ + } while (0) +#else +#define DBG(x...) do {} while (0) +#endif + +static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp) +{ + int sz; + + if (!smd_pkt_devp || !smd_pkt_devp->ch) + return; + + sz = smd_cur_packet_size(smd_pkt_devp->ch); + if (sz == 0) { + DBG("no packet\n"); + return; + } + if (sz > smd_read_avail(smd_pkt_devp->ch)) { + DBG("incomplete packet\n"); + return; + } + + DBG("waking up reader\n"); + wake_up_interruptible(&smd_pkt_devp->ch_read_wait_queue); +} + +static int smd_pkt_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int r, bytes_read; + struct smd_pkt_dev *smd_pkt_devp; + struct smd_channel *chl; + + DBG("read %d bytes\n", count); + if (count > MAX_BUF_SIZE) + return -EINVAL; + + smd_pkt_devp = file->private_data; + if (!smd_pkt_devp || !smd_pkt_devp->ch) + return -EINVAL; + + chl = smd_pkt_devp->ch; +wait_for_packet: + r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue, + (smd_cur_packet_size(chl) > 0 && + smd_read_avail(chl) >= + smd_cur_packet_size(chl))); + + if (r < 0) { + if (r != -ERESTARTSYS) + pr_err("wait returned %d\n", r); + return r; + } + + mutex_lock(&smd_pkt_devp->rx_lock); + + bytes_read = smd_cur_packet_size(smd_pkt_devp->ch); + if (bytes_read == 0 || + bytes_read < smd_read_avail(smd_pkt_devp->ch)) { + mutex_unlock(&smd_pkt_devp->rx_lock); + DBG("Nothing to read\n"); + goto wait_for_packet; + } + + if (bytes_read > count) { + mutex_unlock(&smd_pkt_devp->rx_lock); + pr_info("packet size %d > buffer size %d", bytes_read, count); + return -EINVAL; + } + + r = smd_read(smd_pkt_devp->ch, smd_pkt_devp->rx_buf, bytes_read); + if (r != bytes_read) { + mutex_unlock(&smd_pkt_devp->rx_lock); + pr_err("smd_read failed to read %d bytes: %d\n", bytes_read, r); + return -EIO; + } + + D_DUMP_BUFFER("read: ", bytes_read, smd_pkt_devp->rx_buf); + r = copy_to_user(buf, smd_pkt_devp->rx_buf, bytes_read); + mutex_unlock(&smd_pkt_devp->rx_lock); + if (r) { + pr_err("copy_to_user failed %d\n", r); + return -EFAULT; + } + + DBG("read complete %d bytes\n", bytes_read); + check_and_wakeup_reader(smd_pkt_devp); + + return bytes_read; +} + +static int smd_pkt_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + int r; + struct smd_pkt_dev *smd_pkt_devp; + + if (count > MAX_BUF_SIZE) + return -EINVAL; + + DBG("writting %d bytes\n", count); + + smd_pkt_devp = file->private_data; + if (!smd_pkt_devp || !smd_pkt_devp->ch) + return -EINVAL; + + mutex_lock(&smd_pkt_devp->tx_lock); + if (smd_write_avail(smd_pkt_devp->ch) < count) { + mutex_unlock(&smd_pkt_devp->tx_lock); + DBG("Not enough space to write\n"); + return -ENOMEM; + } + + D_DUMP_BUFFER("write: ", count, buf); + r = copy_from_user(smd_pkt_devp->tx_buf, buf, count); + if (r) { + mutex_unlock(&smd_pkt_devp->tx_lock); + pr_err("copy_from_user failed %d\n", r); + return -EFAULT; + } + + r = smd_write(smd_pkt_devp->ch, smd_pkt_devp->tx_buf, count); + if (r != count) { + mutex_unlock(&smd_pkt_devp->tx_lock); + pr_err("smd_write failed to write %d bytes: %d.\n", count, r); + return -EIO; + } + mutex_unlock(&smd_pkt_devp->tx_lock); + + DBG("wrote %d bytes\n", count); + return count; +} + +static unsigned int smd_pkt_poll(struct file *file, poll_table *wait) +{ + struct smd_pkt_dev *smd_pkt_devp; + unsigned int mask = 0; + + smd_pkt_devp = file->private_data; + if (!smd_pkt_devp) + return POLLERR; + + DBG("poll waiting\n"); + poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait); + if (smd_read_avail(smd_pkt_devp->ch)) + mask |= POLLIN | POLLRDNORM; + + DBG("poll return\n"); + return mask; +} + +static void smd_pkt_ch_notify(void *priv, unsigned event) +{ + struct smd_pkt_dev *smd_pkt_devp = priv; + + if (smd_pkt_devp->ch == 0) + return; + + switch (event) { + case SMD_EVENT_DATA: + DBG("data\n"); + check_and_wakeup_reader(smd_pkt_devp); + break; + + case SMD_EVENT_OPEN: + DBG("remote open\n"); + smd_pkt_devp->remote_open = 1; + wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue); + break; + + case SMD_EVENT_CLOSE: + smd_pkt_devp->remote_open = 0; + pr_info("remote closed\n"); + break; + + default: + pr_err("unknown event %d\n", event); + break; + } +} + +static char *smd_pkt_dev_name[] = { + "smdcntl0", + "smdcntl1", + "smdcntl2", + "smdcntl3", + "smdcntl4", + "smdcntl5", + "smdcntl6", + "smdcntl7", + "smd22", +}; + +static char *smd_ch_name[] = { + "DATA5_CNTL", + "DATA6_CNTL", + "DATA7_CNTL", + "DATA8_CNTL", + "DATA9_CNTL", + "DATA12_CNTL", + "DATA13_CNTL", + "DATA14_CNTL", + "DATA22", +}; + +static int smd_pkt_open(struct inode *inode, struct file *file) +{ + int r = 0; + struct smd_pkt_dev *smd_pkt_devp; + + smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev); + if (!smd_pkt_devp) + return -EINVAL; + + file->private_data = smd_pkt_devp; + + mutex_lock(&smd_pkt_devp->ch_lock); + if (smd_pkt_devp->open_count == 0) { + r = smd_open(smd_ch_name[smd_pkt_devp->i], + &smd_pkt_devp->ch, smd_pkt_devp, + smd_pkt_ch_notify); + if (r < 0) { + pr_err("smd_open failed for %s, %d\n", + smd_ch_name[smd_pkt_devp->i], r); + goto out; + } + + r = wait_event_interruptible_timeout( + smd_pkt_devp->ch_opened_wait_queue, + smd_pkt_devp->remote_open, + msecs_to_jiffies(2 * HZ)); + if (r == 0) + r = -ETIMEDOUT; + + if (r < 0) { + pr_err("wait returned %d\n", r); + smd_close(smd_pkt_devp->ch); + smd_pkt_devp->ch = 0; + } else { + smd_pkt_devp->open_count++; + r = 0; + } + } +out: + mutex_unlock(&smd_pkt_devp->ch_lock); + return r; +} + +static int smd_pkt_release(struct inode *inode, struct file *file) +{ + int r = 0; + struct smd_pkt_dev *smd_pkt_devp = file->private_data; + + if (!smd_pkt_devp) + return -EINVAL; + + mutex_lock(&smd_pkt_devp->ch_lock); + if (--smd_pkt_devp->open_count == 0) { + r = smd_close(smd_pkt_devp->ch); + smd_pkt_devp->ch = 0; + } + mutex_unlock(&smd_pkt_devp->ch_lock); + + return r; +} + +static const struct file_operations smd_pkt_fops = { + .owner = THIS_MODULE, + .open = smd_pkt_open, + .release = smd_pkt_release, + .read = smd_pkt_read, + .write = smd_pkt_write, + .poll = smd_pkt_poll, +}; + +static int __init smd_pkt_init(void) +{ + int i; + int r; + + r = alloc_chrdev_region(&smd_pkt_number, 0, + NUM_SMD_PKT_PORTS, DEVICE_NAME); + if (r) { + pr_err("alloc_chrdev_region() failed %d\n", r); + return r; + } + + smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(smd_pkt_classp)) { + r = PTR_ERR(smd_pkt_classp); + pr_err("class_create() failed %d\n", r); + goto unreg_chardev; + } + + for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) { + smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev), + GFP_KERNEL); + if (IS_ERR(smd_pkt_devp[i])) { + r = PTR_ERR(smd_pkt_devp[i]); + pr_err("kmalloc() failed %d\n", r); + goto clean_cdevs; + } + + smd_pkt_devp[i]->i = i; + + init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue); + smd_pkt_devp[i]->remote_open = 0; + init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue); + + mutex_init(&smd_pkt_devp[i]->ch_lock); + mutex_init(&smd_pkt_devp[i]->rx_lock); + mutex_init(&smd_pkt_devp[i]->tx_lock); + + cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops); + smd_pkt_devp[i]->cdev.owner = THIS_MODULE; + + r = cdev_add(&smd_pkt_devp[i]->cdev, + (smd_pkt_number + i), 1); + if (r) { + pr_err("cdev_add() failed %d\n", r); + kfree(smd_pkt_devp[i]); + goto clean_cdevs; + } + + smd_pkt_devp[i]->devicep = + device_create(smd_pkt_classp, NULL, + (smd_pkt_number + i), NULL, + smd_pkt_dev_name[i]); + if (IS_ERR(smd_pkt_devp[i]->devicep)) { + r = PTR_ERR(smd_pkt_devp[i]->devicep); + pr_err("device_create() failed %d\n", r); + cdev_del(&smd_pkt_devp[i]->cdev); + kfree(smd_pkt_devp[i]); + goto clean_cdevs; + } + + } + + pr_info("SMD Packet Port Driver Initialized.\n"); + return 0; + +clean_cdevs: + if (i > 0) { + while (--i >= 0) { + mutex_destroy(&smd_pkt_devp[i]->ch_lock); + mutex_destroy(&smd_pkt_devp[i]->rx_lock); + mutex_destroy(&smd_pkt_devp[i]->tx_lock); + cdev_del(&smd_pkt_devp[i]->cdev); + kfree(smd_pkt_devp[i]); + device_destroy(smd_pkt_classp, + MKDEV(MAJOR(smd_pkt_number), i)); + } + } + + class_destroy(smd_pkt_classp); +unreg_chardev: + unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS); + return r; +} +module_init(smd_pkt_init); + +static void __exit smd_pkt_cleanup(void) +{ + int i; + + for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) { + mutex_destroy(&smd_pkt_devp[i]->ch_lock); + mutex_destroy(&smd_pkt_devp[i]->rx_lock); + mutex_destroy(&smd_pkt_devp[i]->tx_lock); + cdev_del(&smd_pkt_devp[i]->cdev); + kfree(smd_pkt_devp[i]); + device_destroy(smd_pkt_classp, + MKDEV(MAJOR(smd_pkt_number), i)); + } + + class_destroy(smd_pkt_classp); + unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS); +} +module_exit(smd_pkt_cleanup); + +MODULE_DESCRIPTION("MSM Shared Memory Packet Port"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From d9d691f584bd012d235c35279c043a2ccd23d7d7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 23 Mar 2011 16:42:56 -0700 Subject: drivers/tty/bfin_jtag_comm.c: avoid calling put_tty_driver on NULL put_tty_driver calls tty_driver_kref_put on its argument, and then tty_driver_kref_put calls kref_put on the address of a field of this argument. kref_put checks for NULL, but in this case the field is likely to have some offset and so the result of taking its address will not be NULL. Labels are added to be able to skip over the call to put_tty_driver when the argument will be NULL. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression *x; @@ *if (x == NULL) { ... * put_tty_driver(x); ... return ...; } // Signed-off-by: Julia Lawall Cc: Torben Hohn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/tty/bfin_jtag_comm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 16402445f2b2..03c285bb2f18 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -251,11 +251,11 @@ static int __init bfin_jc_init(void) bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0; bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL); if (!bfin_jc_write_buf.buf) - goto err; + goto err_buf; bfin_jc_driver = alloc_tty_driver(1); if (!bfin_jc_driver) - goto err; + goto err_driver; bfin_jc_driver->owner = THIS_MODULE; bfin_jc_driver->driver_name = DRV_NAME; @@ -275,7 +275,9 @@ static int __init bfin_jc_init(void) err: put_tty_driver(bfin_jc_driver); + err_driver: kfree(bfin_jc_write_buf.buf); + err_buf: kthread_stop(bfin_jc_kthread); return ret; } -- cgit v1.2.2 From 115bcd156a7c4b4dad950f3bd2e4d023688c2ee7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 23 Mar 2011 16:42:57 -0700 Subject: drivers/staging/tty/specialix.c: convert func_enter to func_exit Convert calls to func_enter on leaving a function to func_exit. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ @@ - func_enter(); + func_exit(); return...; // Signed-off-by: Julia Lawall Cc: Roger Wolff Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/staging/tty/specialix.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/tty/specialix.c b/drivers/staging/tty/specialix.c index 47e5753f732a..17a1be536a46 100644 --- a/drivers/staging/tty/specialix.c +++ b/drivers/staging/tty/specialix.c @@ -1416,7 +1416,7 @@ static int sx_open(struct tty_struct *tty, struct file *filp) board, bp, port, SX_PORT(tty->index)); if (sx_paranoia_check(port, tty->name, "sx_open")) { - func_enter(); + func_exit(); return -ENODEV; } @@ -1435,13 +1435,13 @@ static int sx_open(struct tty_struct *tty, struct file *filp) error = sx_setup_port(bp, port); if (error) { - func_enter(); + func_exit(); return error; } error = block_til_ready(tty, filp, port); if (error) { - func_enter(); + func_exit(); return error; } @@ -1860,7 +1860,7 @@ static int sx_set_serial_info(struct specialix_port *port, func_enter(); if (copy_from_user(&tmp, newinfo, sizeof(tmp))) { - func_enter(); + func_exit(); return -EFAULT; } -- cgit v1.2.2 From cfaf346cb2741ca648d83527df173b759381e607 Mon Sep 17 00:00:00 2001 From: Changli Gao Date: Wed, 23 Mar 2011 16:42:58 -0700 Subject: drivers/char/mem.c: clean up the code Reduce the lines of code and simplify the logic. Signed-off-by: Changli Gao Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/mem.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 1256454b2d43..436a99017998 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -47,10 +47,7 @@ static inline unsigned long size_inside_page(unsigned long start, #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE static inline int valid_phys_addr_range(unsigned long addr, size_t count) { - if (addr + count > __pa(high_memory)) - return 0; - - return 1; + return addr + count <= __pa(high_memory); } static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) -- cgit v1.2.2 From cd8b974fad4f993bde74d820f83bd0a88ad82491 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 23 Mar 2011 16:42:59 -0700 Subject: rapidio: add new sysfs attributes Add new sysfs attributes. 1. Routing information required to to reach the RIO device: destid - device destination ID (real for for endpoint, route for switch) hopcount - hopcount for maintenance requests (switches only) 2. device linking information: lprev - name of device that precedes the given device in the enumeration or discovery order (displayed along with of the port to which it is attached). lnext - names of devices (with corresponding port numbers) that are attached to the given device as next in the enumeration or discovery order (switches only) Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-sysfs.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 1269fbd2deca..0d894320e227 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -33,6 +33,8 @@ rio_config_attr(device_rev, "0x%08x\n"); rio_config_attr(asm_did, "0x%04x\n"); rio_config_attr(asm_vid, "0x%04x\n"); rio_config_attr(asm_rev, "0x%04x\n"); +rio_config_attr(destid, "0x%04x\n"); +rio_config_attr(hopcount, "0x%02x\n"); static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -52,6 +54,35 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch return (str - buf); } +static ssize_t lprev_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rio_dev *rdev = to_rio_dev(dev); + + return sprintf(buf, "%s\n", + (rdev->prev) ? rio_name(rdev->prev) : "root"); +} + +static ssize_t lnext_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rio_dev *rdev = to_rio_dev(dev); + char *str = buf; + int i; + + if (rdev->pef & RIO_PEF_SWITCH) { + for (i = 0; i < RIO_GET_TOTAL_PORTS(rdev->swpinfo); i++) { + if (rdev->rswitch->nextdev[i]) + str += sprintf(str, "%s\n", + rio_name(rdev->rswitch->nextdev[i])); + else + str += sprintf(str, "null\n"); + } + } + + return str - buf; +} + struct device_attribute rio_dev_attrs[] = { __ATTR_RO(did), __ATTR_RO(vid), @@ -59,10 +90,14 @@ struct device_attribute rio_dev_attrs[] = { __ATTR_RO(asm_did), __ATTR_RO(asm_vid), __ATTR_RO(asm_rev), + __ATTR_RO(lprev), + __ATTR_RO(destid), __ATTR_NULL, }; static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL); +static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL); +static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL); static ssize_t rio_read_config(struct file *filp, struct kobject *kobj, @@ -218,7 +253,9 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev) err = device_create_bin_file(&rdev->dev, &rio_config_attr); if (!err && (rdev->pef & RIO_PEF_SWITCH)) { - err = device_create_file(&rdev->dev, &dev_attr_routes); + err |= device_create_file(&rdev->dev, &dev_attr_routes); + err |= device_create_file(&rdev->dev, &dev_attr_lnext); + err |= device_create_file(&rdev->dev, &dev_attr_hopcount); if (!err && rdev->rswitch->sw_sysfs) err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE); } @@ -241,6 +278,8 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev) device_remove_bin_file(&rdev->dev, &rio_config_attr); if (rdev->pef & RIO_PEF_SWITCH) { device_remove_file(&rdev->dev, &dev_attr_routes); + device_remove_file(&rdev->dev, &dev_attr_lnext); + device_remove_file(&rdev->dev, &dev_attr_hopcount); if (rdev->rswitch->sw_sysfs) rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE); } -- cgit v1.2.2 From f8f0626989c85b3d8bd67eff29d9dd3d14a5e71f Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 23 Mar 2011 16:43:02 -0700 Subject: rapidio: add architecture specific callbacks This set of patches eliminates RapidIO dependency on PowerPC architecture and makes it available to other architectures (x86 and MIPS). It also enables support of new platform independent RapidIO controllers such as PCI-to-SRIO and PCI Express-to-SRIO. This patch: Extend number of mport callback functions to eliminate direct linking of architecture specific mport operations. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index cc2a3b74d0f0..d520dbaede80 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -68,9 +68,13 @@ int rio_request_inb_mbox(struct rio_mport *mport, void (*minb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) { - int rc = 0; + int rc = -ENOSYS; + struct resource *res; - struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); + if (mport->ops->open_inb_mbox == NULL) + goto out; + + res = kmalloc(sizeof(struct resource), GFP_KERNEL); if (res) { rio_init_mbox_res(res, mbox, mbox); @@ -88,7 +92,7 @@ int rio_request_inb_mbox(struct rio_mport *mport, /* Hook the inbound message callback */ mport->inb_msg[mbox].mcback = minb; - rc = rio_open_inb_mbox(mport, dev_id, mbox, entries); + rc = mport->ops->open_inb_mbox(mport, dev_id, mbox, entries); } else rc = -ENOMEM; @@ -106,10 +110,13 @@ int rio_request_inb_mbox(struct rio_mport *mport, */ int rio_release_inb_mbox(struct rio_mport *mport, int mbox) { - rio_close_inb_mbox(mport, mbox); + if (mport->ops->close_inb_mbox) { + mport->ops->close_inb_mbox(mport, mbox); - /* Release the mailbox resource */ - return release_resource(mport->inb_msg[mbox].res); + /* Release the mailbox resource */ + return release_resource(mport->inb_msg[mbox].res); + } else + return -ENOSYS; } /** @@ -129,9 +136,13 @@ int rio_request_outb_mbox(struct rio_mport *mport, int entries, void (*moutb) (struct rio_mport * mport, void *dev_id, int mbox, int slot)) { - int rc = 0; + int rc = -ENOSYS; + struct resource *res; - struct resource *res = kmalloc(sizeof(struct resource), GFP_KERNEL); + if (mport->ops->open_outb_mbox == NULL) + goto out; + + res = kmalloc(sizeof(struct resource), GFP_KERNEL); if (res) { rio_init_mbox_res(res, mbox, mbox); @@ -149,7 +160,7 @@ int rio_request_outb_mbox(struct rio_mport *mport, /* Hook the inbound message callback */ mport->outb_msg[mbox].mcback = moutb; - rc = rio_open_outb_mbox(mport, dev_id, mbox, entries); + rc = mport->ops->open_outb_mbox(mport, dev_id, mbox, entries); } else rc = -ENOMEM; @@ -167,10 +178,13 @@ int rio_request_outb_mbox(struct rio_mport *mport, */ int rio_release_outb_mbox(struct rio_mport *mport, int mbox) { - rio_close_outb_mbox(mport, mbox); + if (mport->ops->close_outb_mbox) { + mport->ops->close_outb_mbox(mport, mbox); - /* Release the mailbox resource */ - return release_resource(mport->outb_msg[mbox].res); + /* Release the mailbox resource */ + return release_resource(mport->outb_msg[mbox].res); + } else + return -ENOSYS; } /** -- cgit v1.2.2 From 388b78adc9899f0299128610f566051d0b1a57f6 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 23 Mar 2011 16:43:03 -0700 Subject: rapidio: modify configuration to support PCI-SRIO controller 1. Add an option to include RapidIO support if the PCI is available. 2. Add FSL_RIO configuration option to enable controller selection. 3. Add RapidIO support option into x86 and MIPS architectures. Signed-off-by: Alexandre Bounine Acked-by: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/rionet.c | 4 ++-- drivers/rapidio/rio-sysfs.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 44150f2f7bfd..678e5777da81 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -382,7 +382,7 @@ static void rionet_remove(struct rio_dev *rdev) struct rionet_peer *peer, *tmp; free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ? - __ilog2(sizeof(void *)) + 4 : 0); + __fls(sizeof(void *)) + 4 : 0); unregister_netdev(ndev); free_netdev(ndev); @@ -450,7 +450,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) } rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, - mport->sys_size ? __ilog2(sizeof(void *)) + 4 : 0); + mport->sys_size ? __fls(sizeof(void *)) + 4 : 0); if (!rionet_active) { rc = -ENOMEM; goto out; diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c index 0d894320e227..4dbe360989be 100644 --- a/drivers/rapidio/rio-sysfs.c +++ b/drivers/rapidio/rio-sysfs.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "rio.h" -- cgit v1.2.2 From 2f809985d2cbc78078b8da1cbed1f1ce1f4a0d5f Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 23 Mar 2011 16:43:04 -0700 Subject: rapidio: modify subsystem and driver initialization sequence Subsystem initialization sequence modified to support presence of multiple RapidIO controllers in the system. The new sequence is compatible with initialization of PCI devices. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/rionet.c | 2 +- drivers/rapidio/rio.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 678e5777da81..26afbaae23f0 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -571,5 +571,5 @@ static void __exit rionet_exit(void) rio_unregister_driver(&rionet_driver); } -module_init(rionet_init); +late_initcall(rionet_init); module_exit(rionet_exit); diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index d520dbaede80..f861b728f80e 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1134,8 +1134,6 @@ static int __devinit rio_init(void) return 0; } -device_initcall(rio_init); - int __devinit rio_init_mports(void) { int rc = 0; @@ -1158,10 +1156,14 @@ int __devinit rio_init_mports(void) rio_disc_mport(port); } + rio_init(); + out: return rc; } +device_initcall_sync(rio_init_mports); + void rio_register_mport(struct rio_mport *port) { list_add_tail(&port->node, &rio_mports); -- cgit v1.2.2 From 569fccb6b48878d654310e1ffaf9a5a6e46b3144 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 23 Mar 2011 16:43:05 -0700 Subject: rapidio: modify mport ID assignment Changes mport ID and host destination ID assignment to implement unified method common to all mport drivers. Makes "riohdid=" kernel command line parameter common for all architectures with support for more that one host destination ID assignment. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index f861b728f80e..9a7b2168d1d5 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -32,6 +32,7 @@ #include "rio.h" static LIST_HEAD(rio_mports); +static unsigned char next_portid; /** * rio_local_get_device_id - Get the base/extended device id for a port @@ -1164,8 +1165,33 @@ int __devinit rio_init_mports(void) device_initcall_sync(rio_init_mports); +static int hdids[RIO_MAX_MPORTS + 1]; + +static int rio_get_hdid(int index) +{ + if (!hdids[0] || hdids[0] <= index || index >= RIO_MAX_MPORTS) + return -1; + + return hdids[index + 1]; +} + +static int rio_hdid_setup(char *str) +{ + (void)get_options(str, ARRAY_SIZE(hdids), hdids); + return 1; +} + +__setup("riohdid=", rio_hdid_setup); + void rio_register_mport(struct rio_mport *port) { + if (next_portid >= RIO_MAX_MPORTS) { + pr_err("RIO: reached specified max number of mports\n"); + return; + } + + port->id = next_portid++; + port->host_deviceid = rio_get_hdid(port->id); list_add_tail(&port->node, &rio_mports); } -- cgit v1.2.2 From c1256ebe6a10bb3e104ecb2d1a458f9907ee49fb Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 23 Mar 2011 16:43:06 -0700 Subject: rapidio: remove mport resource reservation from common RIO code Removes resource reservation from the common sybsystem initialization code and make it part of mport driver initialization. This resolves conflict with resource reservation by device specific mport drivers. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Cc: Micha Nelissen Cc: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 9a7b2168d1d5..c29719cacbca 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1137,20 +1137,9 @@ static int __devinit rio_init(void) int __devinit rio_init_mports(void) { - int rc = 0; struct rio_mport *port; list_for_each_entry(port, &rio_mports, node) { - if (!request_mem_region(port->iores.start, - resource_size(&port->iores), - port->name)) { - printk(KERN_ERR - "RIO: Error requesting master port region 0x%016llx-0x%016llx\n", - (u64)port->iores.start, (u64)port->iores.end); - rc = -ENOMEM; - goto out; - } - if (port->host_deviceid >= 0) rio_enum_mport(port); else @@ -1159,8 +1148,7 @@ int __devinit rio_init_mports(void) rio_init(); - out: - return rc; + return 0; } device_initcall_sync(rio_init_mports); -- cgit v1.2.2 From ad4ac17ad1e2f0bd0ce38b2585c5d7fa2b0780dc Mon Sep 17 00:00:00 2001 From: Dan Carpenter <[error27@gmail.com]> Date: Wed, 23 Mar 2011 16:43:07 -0700 Subject: rapidio: fix potential null deref on failure path If rio is not a switch then "rswitch" is null. Signed-off-by: Dan Carpenter Cc: Matt Porter Cc: Kumar Gala Signed-off-by: Alexandre Bounine Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio-scan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index a50391b6ba2a..3a59d5f018d3 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -517,7 +517,7 @@ static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, return rdev; cleanup: - if (rswitch->route_table) + if (rio_is_switch(rdev)) kfree(rswitch->route_table); kfree(rdev); -- cgit v1.2.2 From 3486740a4f32a6a466f5ac931654d154790ba648 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Wed, 23 Mar 2011 16:43:17 -0700 Subject: userns: security: make capabilities relative to the user namespace - Introduce ns_capable to test for a capability in a non-default user namespace. - Teach cap_capable to handle capabilities in a non-default user namespace. The motivation is to get to the unprivileged creation of new namespaces. It looks like this gets us 90% of the way there, with only potential uid confusion issues left. I still need to handle getting all caps after creation but otherwise I think I have a good starter patch that achieves all of your goals. Changelog: 11/05/2010: [serge] add apparmor 12/14/2010: [serge] fix capabilities to created user namespaces Without this, if user serge creates a user_ns, he won't have capabilities to the user_ns he created. THis is because we were first checking whether his effective caps had the caps he needed and returning -EPERM if not, and THEN checking whether he was the creator. Reverse those checks. 12/16/2010: [serge] security_real_capable needs ns argument in !security case 01/11/2011: [serge] add task_ns_capable helper 01/11/2011: [serge] add nsown_capable() helper per Bastian Blank suggestion 02/16/2011: [serge] fix a logic bug: the root user is always creator of init_user_ns, but should not always have capabilities to it! Fix the check in cap_capable(). 02/21/2011: Add the required user_ns parameter to security_capable, fixing a compile failure. 02/23/2011: Convert some macros to functions as per akpm comments. Some couldn't be converted because we can't easily forward-declare them (they are inline if !SECURITY, extern if SECURITY). Add a current_user_ns function so we can use it in capability.h without #including cred.h. Move all forward declarations together to the top of the #ifdef __KERNEL__ section, and use kernel-doc format. 02/23/2011: Per dhowells, clean up comment in cap_capable(). 02/23/2011: Per akpm, remove unreachable 'return -EPERM' in cap_capable. (Original written and signed off by Eric; latest, modified version acked by him) [akpm@linux-foundation.org: fix build] [akpm@linux-foundation.org: export current_user_ns() for ecryptfs] [serge.hallyn@canonical.com: remove unneeded extra argument in selinux's task_has_capability] Signed-off-by: Eric W. Biederman Signed-off-by: Serge E. Hallyn Acked-by: "Eric W. Biederman" Acked-by: Daniel Lezcano Acked-by: David Howells Cc: James Morris Signed-off-by: Serge E. Hallyn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pci/pci-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c85438a367d5..a8a277a2e0d0 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -369,7 +369,7 @@ pci_read_config(struct file *filp, struct kobject *kobj, u8 *data = (u8*) buf; /* Several chips lock up trying to read undefined config space */ - if (security_capable(filp->f_cred, CAP_SYS_ADMIN) == 0) { + if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) { size = dev->cfg_size; } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { size = 128; -- cgit v1.2.2 From 06fb01fd1dc624d891cbe039a88a44bc8a8a9ec1 Mon Sep 17 00:00:00 2001 From: Philippe Langlais Date: Wed, 23 Mar 2011 11:05:16 +0100 Subject: spi/pl022: Add loopback support for the SPI on 5500 Extend the vendor data with a loopback field, and add new amba-pl022 vendor data for the DB5500 pl023, as the pl023 on db8500 and db5500 vary. Signed-off-by: Prajadevi H Signed-off-by: Philippe Langlais Signed-off-by: Linus Walleij Signed-off-by: Grant Likely --- drivers/spi/amba-pl022.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 5c2b092a915e..5a4e0afb9ad6 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -324,6 +324,7 @@ struct vendor_data { bool unidir; bool extended_cr; bool pl023; + bool loopback; }; /** @@ -1983,7 +1984,7 @@ static int pl022_setup(struct spi_device *spi) SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8); /* Loopback is available on all versions except PL023 */ - if (!pl022->vendor->pl023) { + if (pl022->vendor->loopback) { if (spi->mode & SPI_LOOP) tmp = LOOPBACK_ENABLED; else @@ -2233,6 +2234,7 @@ static struct vendor_data vendor_arm = { .unidir = false, .extended_cr = false, .pl023 = false, + .loopback = true, }; @@ -2242,6 +2244,7 @@ static struct vendor_data vendor_st = { .unidir = false, .extended_cr = true, .pl023 = false, + .loopback = true, }; static struct vendor_data vendor_st_pl023 = { @@ -2250,6 +2253,16 @@ static struct vendor_data vendor_st_pl023 = { .unidir = false, .extended_cr = true, .pl023 = true, + .loopback = false, +}; + +static struct vendor_data vendor_db5500_pl023 = { + .fifodepth = 32, + .max_bpw = 32, + .unidir = false, + .extended_cr = true, + .pl023 = true, + .loopback = true, }; static struct amba_id pl022_ids[] = { @@ -2283,6 +2296,11 @@ static struct amba_id pl022_ids[] = { .mask = 0xffffffff, .data = &vendor_st_pl023, }, + { + .id = 0x10080023, + .mask = 0xffffffff, + .data = &vendor_db5500_pl023, + }, { 0, 0 }, }; -- cgit v1.2.2 From ddca6a31345cbea8c7c907e6b7e016339cbb6342 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 21 Mar 2011 02:37:07 -0700 Subject: Input: tsc2005 - driver should depend on GENERIC_HARDIRQS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/input/touchscreen/tsc2005.c: In function ‘tsc2005_probe’: drivers/input/touchscreen/tsc2005.c:666: error: implicit declaration of function ‘set_irq_wake’ In addition, migrate from set_irq_wake() (marked "do not use" as of commit a0cd9ca2b907d7ee26575e7b63ac92dad768a75e ("genirq: Namespace cleanup")) to irq_set_irq_wake(). Signed-off-by: Geert Uytterhoeven Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 2 +- drivers/input/touchscreen/tsc2005.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 112ec55f2939..434fd800cd24 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -641,7 +641,7 @@ config TOUCHSCREEN_TOUCHIT213 config TOUCHSCREEN_TSC2005 tristate "TSC2005 based touchscreens" - depends on SPI_MASTER + depends on SPI_MASTER && GENERIC_HARDIRQS help Say Y here if you have a TSC2005 based touchscreen. diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 87420616efa4..437b9cdddf82 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -663,7 +663,7 @@ static int __devinit tsc2005_probe(struct spi_device *spi) goto err_remove_sysfs; } - set_irq_wake(spi->irq, 1); + irq_set_irq_wake(spi->irq, 1); return 0; err_remove_sysfs: -- cgit v1.2.2 From 903427955b9ffe1ca4b76c510089774c3b7a4a8a Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 23 Mar 2011 23:45:11 -0700 Subject: Input: tsc2005 - use relative jiffies to schedule the watchdog Use relative jiffies to schedule the watchdog. Otherwise it will run like a mad one. Signed-off-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 437b9cdddf82..2a9a7260fe8e 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -358,7 +358,7 @@ static void __tsc2005_enable(struct tsc2005 *ts) if (ts->esd_timeout && ts->set_reset) { ts->last_valid_interrupt = jiffies; schedule_delayed_work(&ts->esd_work, - round_jiffies(jiffies + + round_jiffies_relative( msecs_to_jiffies(ts->esd_timeout))); } @@ -512,7 +512,7 @@ static void tsc2005_esd_work(struct work_struct *work) out: /* re-arm the watchdog */ schedule_delayed_work(&ts->esd_work, - round_jiffies(jiffies + + round_jiffies_relative( msecs_to_jiffies(ts->esd_timeout))); mutex_unlock(&ts->mutex); } -- cgit v1.2.2 From a0fa2206f550066d6948d43c5401e973e5f7d320 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Wed, 23 Mar 2011 23:48:19 -0700 Subject: Input: tsc2005 - fix locking issue Commit 0b950d3 (Input: tsc2005 - add open/close) introduced a locking issue with the ESD watchdog: __tsc2005_disable() is calling cancel_delayed_work_sync() with mutex held, and the work also needs the same mutex. Fix the problem by using mutex_trylock() in tsc2005_esd_work(). If the mutex is taken, we know we are in the middle of disable or enable and the watchdog check can be skipped. Signed-off-by: Aaro Koskinen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 2a9a7260fe8e..cbf0ff322676 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -477,7 +477,14 @@ static void tsc2005_esd_work(struct work_struct *work) int error; u16 r; - mutex_lock(&ts->mutex); + if (!mutex_trylock(&ts->mutex)) { + /* + * If the mutex is taken, it means that disable or enable is in + * progress. In that case just reschedule the work. If the work + * is not needed, it will be canceled by disable. + */ + goto reschedule; + } if (time_is_after_jiffies(ts->last_valid_interrupt + msecs_to_jiffies(ts->esd_timeout))) @@ -510,11 +517,12 @@ static void tsc2005_esd_work(struct work_struct *work) tsc2005_start_scan(ts); out: + mutex_unlock(&ts->mutex); +reschedule: /* re-arm the watchdog */ schedule_delayed_work(&ts->esd_work, round_jiffies_relative( msecs_to_jiffies(ts->esd_timeout))); - mutex_unlock(&ts->mutex); } static int tsc2005_open(struct input_dev *input) -- cgit v1.2.2 From f0c860246472248a534656d6cdbed5a36d1feb2e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 23 Mar 2011 17:53:28 +0000 Subject: Revert "drm/i915: Don't save/restore hardware status page address register" This reverts commit a7a75c8f70d6f6a2f16c9f627f938bbee2d32718. There are two different variations on how Intel hardware addresses the "Hardware Status Page". One as a location in physical memory and the other as an offset into the virtual memory of the GPU, used in more recent chipsets. (The HWS itself is a cacheable region of memory which the GPU can write to without requiring CPU synchronisation, used for updating various details of hardware state, such as the position of the GPU head in the ringbuffer, the last breadcrumb seqno, etc). These two types of addresses were updated in different locations of code - one inline with the ringbuffer initialisation, and the other during device initialisation. (The HWS page is logically associated with the rings, and there is one HWS page per ring.) During resume, only the ringbuffers were being re-initialised along with the virtual HWS page, leaving the older physical address HWS untouched. This then caused a hang on the older gen3/4 (915GM, 945GM, 965GM) the first time we tried to synchronise the GPU as the breadcrumbs were never being updated. Reported-and-tested-by: Linus Torvalds Reported-by: Jan Niehusmann Reported-and-tested-by: Justin P. Mattock Reported-and-tested-by: Michael "brot" Groh Cc: Zhenyu Wang Signed-off-by: Chris Wilson Acked-by: Zhenyu Wang --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_suspend.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 449650545bb4..5004724ea57e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -383,6 +383,7 @@ typedef struct drm_i915_private { u32 saveDSPACNTR; u32 saveDSPBCNTR; u32 saveDSPARB; + u32 saveHWS; u32 savePIPEACONF; u32 savePIPEBCONF; u32 savePIPEASRC; diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 7e992a8e9098..da474153a0a2 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -796,6 +796,9 @@ int i915_save_state(struct drm_device *dev) pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB); + /* Hardware status page */ + dev_priv->saveHWS = I915_READ(HWS_PGA); + i915_save_display(dev); /* Interrupt state */ @@ -842,6 +845,9 @@ int i915_restore_state(struct drm_device *dev) pci_write_config_byte(dev->pdev, LBB, dev_priv->saveLBB); + /* Hardware status page */ + I915_WRITE(HWS_PGA, dev_priv->saveHWS); + i915_restore_display(dev); /* Interrupt state */ -- cgit v1.2.2 From fafcf94e2b5732d1e13b440291c53115d2b172e9 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 23 Mar 2011 08:10:10 +0000 Subject: drm/radeon/kms: fix hardcoded EDID handling On some servers there is a hardcoded EDID provided in the vbios so that the driver will always see a display connected even if something like a KVM prevents traditional means like DDC or load detection from working properly. Also most server boards with DVI are not actually DVI, but DVO connected to a virtual KVM service processor. If we fail to detect a monitor via DDC or load detection and a hardcoded EDID is available, use it. Additionally, when using the hardcoded EDID, use a copy of it rather than the actual one stored in the driver as the detect() and get_modes() functions may free it if DDC is successful. This fixes the virtual KVM on several internal servers. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 21 ++++++++++++++++----- drivers/gpu/drm/radeon/radeon_connectors.c | 30 ++++++++++++++++++++++++++++-- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 3 files changed, 45 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index cf7c8d5b4ec2..cf602e2d0718 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -448,7 +448,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev, bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) { - int edid_info; + int edid_info, size; struct edid *edid; unsigned char *raw; edid_info = combios_get_table_offset(rdev->ddev, COMBIOS_HARDCODED_EDID_TABLE); @@ -456,11 +456,12 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) return false; raw = rdev->bios + edid_info; - edid = kmalloc(EDID_LENGTH * (raw[0x7e] + 1), GFP_KERNEL); + size = EDID_LENGTH * (raw[0x7e] + 1); + edid = kmalloc(size, GFP_KERNEL); if (edid == NULL) return false; - memcpy((unsigned char *)edid, raw, EDID_LENGTH * (raw[0x7e] + 1)); + memcpy((unsigned char *)edid, raw, size); if (!drm_edid_is_valid(edid)) { kfree(edid); @@ -468,6 +469,7 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) } rdev->mode_info.bios_hardcoded_edid = edid; + rdev->mode_info.bios_hardcoded_edid_size = size; return true; } @@ -475,8 +477,17 @@ bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev) struct edid * radeon_bios_get_hardcoded_edid(struct radeon_device *rdev) { - if (rdev->mode_info.bios_hardcoded_edid) - return rdev->mode_info.bios_hardcoded_edid; + struct edid *edid; + + if (rdev->mode_info.bios_hardcoded_edid) { + edid = kmalloc(rdev->mode_info.bios_hardcoded_edid_size, GFP_KERNEL); + if (edid) { + memcpy((unsigned char *)edid, + (unsigned char *)rdev->mode_info.bios_hardcoded_edid, + rdev->mode_info.bios_hardcoded_edid_size); + return edid; + } + } return NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 3f3c9aac46cc..a1866738a657 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -629,6 +629,8 @@ static int radeon_vga_mode_valid(struct drm_connector *connector, static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector, bool force) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder; struct drm_encoder_helper_funcs *encoder_funcs; @@ -679,6 +681,17 @@ radeon_vga_detect(struct drm_connector *connector, bool force) if (ret == connector_status_connected) ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); + + /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the + * vbios to deal with KVMs. If we have one and are not able to detect a monitor + * by other means, assume the CRT is connected and use that EDID. + */ + if ((!rdev->is_atom_bios) && + (ret == connector_status_disconnected) && + rdev->mode_info.bios_hardcoded_edid_size) { + ret = connector_status_connected; + } + radeon_connector_update_scratch_regs(connector, ret); return ret; } @@ -790,6 +803,8 @@ static int radeon_dvi_get_modes(struct drm_connector *connector) static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector, bool force) { + struct drm_device *dev = connector->dev; + struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct drm_encoder *encoder = NULL; struct drm_encoder_helper_funcs *encoder_funcs; @@ -829,8 +844,6 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) * you don't really know what's connected to which port as both are digital. */ if (radeon_connector->shared_ddc && (ret == connector_status_connected)) { - struct drm_device *dev = connector->dev; - struct radeon_device *rdev = dev->dev_private; struct drm_connector *list_connector; struct radeon_connector *list_radeon_connector; list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) { @@ -895,6 +908,19 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, true); } + /* RN50 and some RV100 asics in servers often have a hardcoded EDID in the + * vbios to deal with KVMs. If we have one and are not able to detect a monitor + * by other means, assume the DFP is connected and use that EDID. In most + * cases the DVI port is actually a virtual KVM port connected to the service + * processor. + */ + if ((!rdev->is_atom_bios) && + (ret == connector_status_disconnected) && + rdev->mode_info.bios_hardcoded_edid_size) { + radeon_connector->use_digital = true; + ret = connector_status_connected; + } + out: /* updated in get modes as well since we need to know if it's analog or digital */ radeon_connector_update_scratch_regs(connector, ret); diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 5067d18d0009..1ae6846de827 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -239,6 +239,7 @@ struct radeon_mode_info { struct drm_property *underscan_vborder_property; /* hardcoded DFP edid from BIOS */ struct edid *bios_hardcoded_edid; + int bios_hardcoded_edid_size; /* pointer to fbdev info structure */ struct radeon_fbdev *rfbdev; -- cgit v1.2.2 From 1783e4bf6f4e5c3b13c09aff24da7dcc69fb3e2f Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Wed, 23 Mar 2011 15:14:09 +0000 Subject: drm radeon: Return -EINVAL on wrong pm sysfs access Throw an error if someone tries to fill this with wrong data, instead of simply ignoring the input. Now you get: echo hello >/sys/../power_method -bash: echo: write error: Invalid argument Signed-off-by: Thomas Renninger CC: Alexander.Deucher@amd.com CC: dri-devel@lists.freedesktop.org Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_pm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 2aed03bde4b2..08de669e025a 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -365,12 +365,14 @@ static ssize_t radeon_set_pm_profile(struct device *dev, else if (strncmp("high", buf, strlen("high")) == 0) rdev->pm.profile = PM_PROFILE_HIGH; else { - DRM_ERROR("invalid power profile!\n"); + count = -EINVAL; goto fail; } radeon_pm_update_profile(rdev); radeon_pm_set_clocks(rdev); - } + } else + count = -EINVAL; + fail: mutex_unlock(&rdev->pm.mutex); @@ -413,7 +415,7 @@ static ssize_t radeon_set_pm_method(struct device *dev, mutex_unlock(&rdev->pm.mutex); cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work); } else { - DRM_ERROR("invalid power method!\n"); + count = -EINVAL; goto fail; } radeon_pm_compute_clocks(rdev); -- cgit v1.2.2 From 51eab416c9b4b3ed16553d405ec4a5f67daa34cf Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 24 Mar 2011 20:54:35 +1000 Subject: drm/vblank: update recently added vbl interface to be more future proof. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the interface a bit cleaner by leaving a single gap in the vblank bit space instead of creating two gaps. Suggestions from Michel on mailing list/irc. Reviewed-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 3617b4c4bb57..904d7e9c8e47 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -280,7 +280,7 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) if (dev->driver->dumb_create) req->value = 1; break; - case DRM_CAP_HIGH_CRTC: + case DRM_CAP_VBLANK_HIGH_CRTC: req->value = 1; break; default: -- cgit v1.2.2 From f786bba4499cf3de20da345ce090457ebcef03b0 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 22 Mar 2011 17:34:01 +0100 Subject: HID: hid-multitouch: migrate 3M PCT touch screens to hid-multitouch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch merges the hid-3m-pct driver into hid-multitouch. To keep devices working the same way they used to with hid-3m-pct, we need to add two signal/noise ratios for width and height. We also need to work on width/height to send proper ABS_MT_ORIENTATION flag. Importing 3M into hid-multitouch also solved the bug in which devices handling width and height in their report descriptors did not show ABS_MT_TOUCH_MAJOR and ABS_MT_TOUCH_MINOR. Signed-off-by: Benjamin Tissoires Reviewed-by: Stéphane Chatty Reviewed-and-tested-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +- drivers/hid/Makefile | 1 - drivers/hid/hid-3m-pct.c | 305 ------------------------------------------- drivers/hid/hid-multitouch.c | 47 ++++++- 4 files changed, 46 insertions(+), 314 deletions(-) delete mode 100644 drivers/hid/hid-3m-pct.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 1edb0bd72a60..996ae3ac3244 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -55,12 +55,6 @@ source "drivers/hid/usbhid/Kconfig" menu "Special HID drivers" depends on HID -config HID_3M_PCT - tristate "3M PCT touchscreen" - depends on USB_HID - ---help--- - Support for 3M PCT touch screens. - config HID_A4TECH tristate "A4 tech mice" if EXPERT depends on USB_HID @@ -314,6 +308,7 @@ config HID_MULTITOUCH Generic support for HID multitouch panels. Say Y here if you have one of the following devices: + - 3M PCT touch screens - Cando dual touch panel - Cypress TrueTouch panels - Hanvon dual touch panels diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index f8b90e4e4841..11c9f0b127e1 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -25,7 +25,6 @@ ifdef CONFIG_LOGIWII_FF hid-logitech-y += hid-lg4ff.o endif -obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_APPLE) += hid-apple.o diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c deleted file mode 100644 index 5243ae2d3730..000000000000 --- a/drivers/hid/hid-3m-pct.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * HID driver for 3M PCT multitouch panels - * - * Copyright (c) 2009-2010 Stephane Chatty - * Copyright (c) 2010 Henrik Rydberg - * Copyright (c) 2010 Canonical, Ltd. - * - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Stephane Chatty "); -MODULE_DESCRIPTION("3M PCT multitouch panels"); -MODULE_LICENSE("GPL"); - -#include "hid-ids.h" - -#define MAX_SLOTS 60 - -/* estimated signal-to-noise ratios */ -#define SN_MOVE 2048 -#define SN_WIDTH 128 - -struct mmm_finger { - __s32 x, y, w, h; - bool touch, valid; -}; - -struct mmm_data { - struct mmm_finger f[MAX_SLOTS]; - __u8 curid; - __u8 nexp, nreal; - bool touch, valid; -}; - -static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - int f1 = field->logical_minimum; - int f2 = field->logical_maximum; - int df = f2 - f1; - - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_BUTTON: - return -1; - - case HID_UP_GENDESK: - switch (usage->hid) { - case HID_GD_X: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_X); - input_set_abs_params(hi->input, ABS_MT_POSITION_X, - f1, f2, df / SN_MOVE, 0); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_X, - f1, f2, df / SN_MOVE, 0); - return 1; - case HID_GD_Y: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_Y); - input_set_abs_params(hi->input, ABS_MT_POSITION_Y, - f1, f2, df / SN_MOVE, 0); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_Y, - f1, f2, df / SN_MOVE, 0); - return 1; - } - return 0; - - case HID_UP_DIGITIZER: - switch (usage->hid) { - /* we do not want to map these: no input-oriented meaning */ - case 0x14: - case 0x23: - case HID_DG_INPUTMODE: - case HID_DG_DEVICEINDEX: - case HID_DG_CONTACTCOUNT: - case HID_DG_CONTACTMAX: - case HID_DG_INRANGE: - case HID_DG_CONFIDENCE: - return -1; - case HID_DG_TIPSWITCH: - /* touchscreen emulation */ - hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); - input_set_capability(hi->input, EV_KEY, BTN_TOUCH); - return 1; - case HID_DG_WIDTH: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MAJOR); - input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR, - f1, f2, df / SN_WIDTH, 0); - return 1; - case HID_DG_HEIGHT: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TOUCH_MINOR); - input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR, - f1, f2, df / SN_WIDTH, 0); - input_set_abs_params(hi->input, ABS_MT_ORIENTATION, - 0, 1, 0, 0); - return 1; - case HID_DG_CONTACTID: - input_mt_init_slots(hi->input, MAX_SLOTS); - return 1; - } - /* let hid-input decide for the others */ - return 0; - - case 0xff000000: - /* we do not want to map these: no input-oriented meaning */ - return -1; - } - - return 0; -} - -static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - /* tell hid-input to skip setup of these event types */ - if (usage->type == EV_KEY || usage->type == EV_ABS) - set_bit(usage->type, hi->input->evbit); - return -1; -} - -/* - * this function is called when a whole packet has been received and processed, - * so that it can decide what to send to the input layer. - */ -static void mmm_filter_event(struct mmm_data *md, struct input_dev *input) -{ - int i; - for (i = 0; i < MAX_SLOTS; ++i) { - struct mmm_finger *f = &md->f[i]; - if (!f->valid) { - /* this finger is just placeholder data, ignore */ - continue; - } - input_mt_slot(input, i); - input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch); - if (f->touch) { - /* this finger is on the screen */ - int wide = (f->w > f->h); - /* divided by two to match visual scale of touch */ - int major = max(f->w, f->h) >> 1; - int minor = min(f->w, f->h) >> 1; - - input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y); - input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); - input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); - input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); - } - f->valid = 0; - } - - input_mt_report_pointer_emulation(input, true); - input_sync(input); -} - -/* - * this function is called upon all reports - * so that we can accumulate contact point information, - * and call input_mt_sync after each point. - */ -static int mmm_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct mmm_data *md = hid_get_drvdata(hid); - /* - * strangely, this function can be called before - * field->hidinput is initialized! - */ - if (hid->claimed & HID_CLAIMED_INPUT) { - struct input_dev *input = field->hidinput->input; - switch (usage->hid) { - case HID_DG_TIPSWITCH: - md->touch = value; - break; - case HID_DG_CONFIDENCE: - md->valid = value; - break; - case HID_DG_WIDTH: - if (md->valid) - md->f[md->curid].w = value; - break; - case HID_DG_HEIGHT: - if (md->valid) - md->f[md->curid].h = value; - break; - case HID_DG_CONTACTID: - value = clamp_val(value, 0, MAX_SLOTS - 1); - if (md->valid) { - md->curid = value; - md->f[value].touch = md->touch; - md->f[value].valid = 1; - md->nreal++; - } - break; - case HID_GD_X: - if (md->valid) - md->f[md->curid].x = value; - break; - case HID_GD_Y: - if (md->valid) - md->f[md->curid].y = value; - break; - case HID_DG_CONTACTCOUNT: - if (value) - md->nexp = value; - if (md->nreal >= md->nexp) { - mmm_filter_event(md, input); - md->nreal = 0; - } - break; - } - } - - /* we have handled the hidinput part, now remains hiddev */ - if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) - hid->hiddev_hid_event(hid, field, usage, value); - - return 1; -} - -static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - int ret; - struct mmm_data *md; - - hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; - - md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL); - if (!md) { - hid_err(hdev, "cannot allocate 3M data\n"); - return -ENOMEM; - } - hid_set_drvdata(hdev, md); - - ret = hid_parse(hdev); - if (!ret) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - - if (ret) - kfree(md); - return ret; -} - -static void mmm_remove(struct hid_device *hdev) -{ - hid_hw_stop(hdev); - kfree(hid_get_drvdata(hdev)); - hid_set_drvdata(hdev, NULL); -} - -static const struct hid_device_id mmm_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) }, - { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, - { } -}; -MODULE_DEVICE_TABLE(hid, mmm_devices); - -static const struct hid_usage_id mmm_grabbed_usages[] = { - { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, - { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} -}; - -static struct hid_driver mmm_driver = { - .name = "3m-pct", - .id_table = mmm_devices, - .probe = mmm_probe, - .remove = mmm_remove, - .input_mapping = mmm_input_mapping, - .input_mapped = mmm_input_mapped, - .usage_table = mmm_grabbed_usages, - .event = mmm_event, -}; - -static int __init mmm_init(void) -{ - return hid_register_driver(&mmm_driver); -} - -static void __exit mmm_exit(void) -{ - hid_unregister_driver(&mmm_driver); -} - -module_init(mmm_init); -module_exit(mmm_exit); - diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index d31301e85c56..0175f8583095 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -11,6 +11,12 @@ * Copyright (c) 2010 Henrik Rydberg * Copyright (c) 2010 Canonical, Ltd. * + * This code is partly based on hid-3m-pct.c: + * + * Copyright (c) 2009-2010 Stephane Chatty + * Copyright (c) 2010 Henrik Rydberg + * Copyright (c) 2010 Canonical, Ltd. + * */ /* @@ -69,6 +75,8 @@ struct mt_class { __s32 name; /* MT_CLS */ __s32 quirks; __s32 sn_move; /* Signal/noise ratio for move events */ + __s32 sn_width; /* Signal/noise ratio for width events */ + __s32 sn_height; /* Signal/noise ratio for height events */ __s32 sn_pressure; /* Signal/noise ratio for pressure events */ __u8 maxcontacts; }; @@ -80,6 +88,7 @@ struct mt_class { #define MT_CLS_CYPRESS 4 #define MT_CLS_EGALAX 5 #define MT_CLS_STANTUM 6 +#define MT_CLS_3M 7 #define MT_DEFAULT_MAXCONTACT 10 @@ -141,6 +150,12 @@ struct mt_class mt_classes[] = { }, { .name = MT_CLS_STANTUM, .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, + { .name = MT_CLS_3M, + .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | + MT_QUIRK_SLOT_IS_CONTACTID, + .sn_move = 2048, + .sn_width = 128, + .sn_height = 128 }, { } }; @@ -230,11 +245,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); + set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, + cls->sn_width); td->last_slot_field = usage->hid; return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); + set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, + cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); td->last_slot_field = usage->hid; @@ -332,11 +351,18 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) input_mt_report_slot_state(input, MT_TOOL_FINGER, s->touch_state); if (s->touch_state) { + /* this finger is on the screen */ + int wide = (s->w > s->h); + /* divided by two to match visual scale of touch */ + int major = max(s->w, s->h) >> 1; + int minor = min(s->w, s->h) >> 1; + input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x); input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y); + input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); - input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w); - input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h); + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); + input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); } s->seen_in_this_frame = false; @@ -398,6 +424,15 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, break; default: + if (td->last_field_index + && field->index == td->last_field_index) + /* we reach here when the last field in the + * report is not related to multitouch. + * This is not good. As a temporary solution, + * we trigger our mt event completion and + * ignore the field. + */ + break; /* fallback to the generic hidinput handling */ return 0; } @@ -513,6 +548,14 @@ static void mt_remove(struct hid_device *hdev) static const struct hid_device_id mt_devices[] = { + /* 3M panels */ + { .driver_data = MT_CLS_3M, + HID_USB_DEVICE(USB_VENDOR_ID_3M, + USB_DEVICE_ID_3M1968) }, + { .driver_data = MT_CLS_3M, + HID_USB_DEVICE(USB_VENDOR_ID_3M, + USB_DEVICE_ID_3M2256) }, + /* Cando panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, HID_USB_DEVICE(USB_VENDOR_ID_CANDO, -- cgit v1.2.2 From 3fce224608f38eac6d6b032b0619c1655acaf61d Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 23 Mar 2011 18:11:36 +0100 Subject: HID: roccat: Add support for wireless variant of Pyra Wireless variant of Roccat Pyra finally has been tested with existing driver. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-roccat-pyra.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9809b58e3c7d..3876b6aff503 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1446,6 +1446,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c index 160f481344f6..38280c055a19 100644 --- a/drivers/hid/hid-roccat-pyra.c +++ b/drivers/hid/hid-roccat-pyra.c @@ -652,7 +652,8 @@ static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report, static const struct hid_device_id pyra_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, - /* TODO add USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS after testing */ + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, + USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, { } }; -- cgit v1.2.2 From 024d37e95ec4a7ccc256973ab2feab01f4fbdd2d Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 24 Mar 2011 13:52:14 +0000 Subject: dm: fix opening log and cow devices for read only tables If a table is read-only, also open any log and cow devices it uses read-only. Previously, even read-only devices were opened read-write internally. After patch 75f1dc0d076d1c1168f2115f1941ea627d38bd5a block: check bdev_read_only() from blkdev_get() was applied, loading such tables began to fail. The patch was reverted by e51900f7d38cbcfb481d84567fd92540e7e1d23a block: revert block_dev read-only check but this patch fixes this part of the code to work with the original patch. Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-log.c | 2 +- drivers/md/dm-snap.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c index 6951536ea29c..8e8a868ca857 100644 --- a/drivers/md/dm-log.c +++ b/drivers/md/dm-log.c @@ -543,7 +543,7 @@ static int disk_ctr(struct dm_dirty_log *log, struct dm_target *ti, return -EINVAL; } - r = dm_get_device(ti, argv[0], FMODE_READ | FMODE_WRITE, &dev); + r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &dev); if (r) return r; diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index fdde53cd12b7..a2d330942cb2 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1080,7 +1080,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv) argv++; argc--; - r = dm_get_device(ti, cow_path, FMODE_READ | FMODE_WRITE, &s->cow); + r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow); if (r) { ti->error = "Cannot get COW device"; goto bad_cow; -- cgit v1.2.2 From 3407ef5262b55ca5d7139d2b555ef792fe531eec Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Thu, 24 Mar 2011 13:54:24 +0000 Subject: dm: add flakey target This target is the same as the linear target except that it returns I/O errors periodically. It's been found useful in simulating failing devices for testing purposes. I needed a dm target to do some failure testing on btrfs's raid code, and Mike pointed me at this. Signed-off-by: Josef Bacik Signed-off-by: Alasdair G Kergon --- drivers/md/Kconfig | 6 ++ drivers/md/Makefile | 1 + drivers/md/dm-flakey.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 drivers/md/dm-flakey.c (limited to 'drivers') diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 98d9ec85e0eb..8420129fc5ee 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -327,4 +327,10 @@ config DM_UEVENT ---help--- Generate udev events for DM events. +config DM_FLAKEY + tristate "Flakey target (EXPERIMENTAL)" + depends on BLK_DEV_DM && EXPERIMENTAL + ---help--- + A target that intermittently fails I/O for debugging purposes. + endif # MD diff --git a/drivers/md/Makefile b/drivers/md/Makefile index d0138606c2e8..448838b1f92a 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o obj-$(CONFIG_DM_CRYPT) += dm-crypt.o obj-$(CONFIG_DM_DELAY) += dm-delay.o +obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c new file mode 100644 index 000000000000..ea790623c30b --- /dev/null +++ b/drivers/md/dm-flakey.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2003 Sistina Software (UK) Limited. + * Copyright (C) 2004, 2010 Red Hat, Inc. All rights reserved. + * + * This file is released under the GPL. + */ + +#include + +#include +#include +#include +#include +#include + +#define DM_MSG_PREFIX "flakey" + +/* + * Flakey: Used for testing only, simulates intermittent, + * catastrophic device failure. + */ +struct flakey_c { + struct dm_dev *dev; + unsigned long start_time; + sector_t start; + unsigned up_interval; + unsigned down_interval; +}; + +/* + * Construct a flakey mapping: + */ +static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + struct flakey_c *fc; + unsigned long long tmp; + + if (argc != 4) { + ti->error = "dm-flakey: Invalid argument count"; + return -EINVAL; + } + + fc = kmalloc(sizeof(*fc), GFP_KERNEL); + if (!fc) { + ti->error = "dm-flakey: Cannot allocate linear context"; + return -ENOMEM; + } + fc->start_time = jiffies; + + if (sscanf(argv[1], "%llu", &tmp) != 1) { + ti->error = "dm-flakey: Invalid device sector"; + goto bad; + } + fc->start = tmp; + + if (sscanf(argv[2], "%u", &fc->up_interval) != 1) { + ti->error = "dm-flakey: Invalid up interval"; + goto bad; + } + + if (sscanf(argv[3], "%u", &fc->down_interval) != 1) { + ti->error = "dm-flakey: Invalid down interval"; + goto bad; + } + + if (!(fc->up_interval + fc->down_interval)) { + ti->error = "dm-flakey: Total (up + down) interval is zero"; + goto bad; + } + + if (fc->up_interval + fc->down_interval < fc->up_interval) { + ti->error = "dm-flakey: Interval overflow"; + goto bad; + } + + if (dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &fc->dev)) { + ti->error = "dm-flakey: Device lookup failed"; + goto bad; + } + + ti->num_flush_requests = 1; + ti->private = fc; + return 0; + +bad: + kfree(fc); + return -EINVAL; +} + +static void flakey_dtr(struct dm_target *ti) +{ + struct flakey_c *fc = ti->private; + + dm_put_device(ti, fc->dev); + kfree(fc); +} + +static sector_t flakey_map_sector(struct dm_target *ti, sector_t bi_sector) +{ + struct flakey_c *fc = ti->private; + + return fc->start + (bi_sector - ti->begin); +} + +static void flakey_map_bio(struct dm_target *ti, struct bio *bio) +{ + struct flakey_c *fc = ti->private; + + bio->bi_bdev = fc->dev->bdev; + if (bio_sectors(bio)) + bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); +} + +static int flakey_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) +{ + struct flakey_c *fc = ti->private; + unsigned elapsed; + + /* Are we alive ? */ + elapsed = (jiffies - fc->start_time) / HZ; + if (elapsed % (fc->up_interval + fc->down_interval) >= fc->up_interval) + return -EIO; + + flakey_map_bio(ti, bio); + + return DM_MAPIO_REMAPPED; +} + +static int flakey_status(struct dm_target *ti, status_type_t type, + char *result, unsigned int maxlen) +{ + struct flakey_c *fc = ti->private; + + switch (type) { + case STATUSTYPE_INFO: + result[0] = '\0'; + break; + + case STATUSTYPE_TABLE: + snprintf(result, maxlen, "%s %llu %u %u", fc->dev->name, + (unsigned long long)fc->start, fc->up_interval, + fc->down_interval); + break; + } + return 0; +} + +static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) +{ + struct flakey_c *fc = ti->private; + + return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); +} + +static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, + struct bio_vec *biovec, int max_size) +{ + struct flakey_c *fc = ti->private; + struct request_queue *q = bdev_get_queue(fc->dev->bdev); + + if (!q->merge_bvec_fn) + return max_size; + + bvm->bi_bdev = fc->dev->bdev; + bvm->bi_sector = flakey_map_sector(ti, bvm->bi_sector); + + return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); +} + +static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) +{ + struct flakey_c *fc = ti->private; + + return fn(ti, fc->dev, fc->start, ti->len, data); +} + +static struct target_type flakey_target = { + .name = "flakey", + .version = {1, 1, 0}, + .module = THIS_MODULE, + .ctr = flakey_ctr, + .dtr = flakey_dtr, + .map = flakey_map, + .status = flakey_status, + .ioctl = flakey_ioctl, + .merge = flakey_merge, + .iterate_devices = flakey_iterate_devices, +}; + +static int __init dm_flakey_init(void) +{ + int r = dm_register_target(&flakey_target); + + if (r < 0) + DMERR("register failed %d", r); + + return r; +} + +static void __exit dm_flakey_exit(void) +{ + dm_unregister_target(&flakey_target); +} + +/* Module hooks */ +module_init(dm_flakey_init); +module_exit(dm_flakey_exit); + +MODULE_DESCRIPTION(DM_NAME " flakey target"); +MODULE_AUTHOR("Joe Thornber "); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From de8be5ac70f50a2340f24fd769a1aafa5a51ae34 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 24 Mar 2011 13:54:27 +0000 Subject: dm crypt: wipe keys string immediately after key is set Always wipe the original copy of the key after processing it in crypt_set_key(). Signed-off-by: Milan Broz Acked-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-crypt.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 4e054bd91664..7dcae0d74db7 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1331,20 +1331,29 @@ static int crypt_setkey_allcpus(struct crypt_config *cc) static int crypt_set_key(struct crypt_config *cc, char *key) { + int r = -EINVAL; + int key_string_len = strlen(key); + /* The key size may not be changed. */ - if (cc->key_size != (strlen(key) >> 1)) - return -EINVAL; + if (cc->key_size != (key_string_len >> 1)) + goto out; /* Hyphen (which gives a key_size of zero) means there is no key. */ if (!cc->key_size && strcmp(key, "-")) - return -EINVAL; + goto out; if (cc->key_size && crypt_decode_key(cc->key, key, cc->key_size) < 0) - return -EINVAL; + goto out; set_bit(DM_CRYPT_KEY_VALID, &cc->flags); - return crypt_setkey_allcpus(cc); + r = crypt_setkey_allcpus(cc); + +out: + /* Hex key string not needed after here, so wipe it. */ + memset(key, '0', key_string_len); + + return r; } static int crypt_wipe_key(struct crypt_config *cc) -- cgit v1.2.2 From 6bb43b5d1f54fb44c0408d86d5e71e4405a3ebe1 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 24 Mar 2011 13:54:28 +0000 Subject: dm ioctl: prepare for crypt key wiping Prepare code for implementing buffer wipe flag. No functional change in this patch. Signed-off-by: Milan Broz Acked-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-ioctl.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 6d12775a1061..3a8f6a0e6eb5 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1501,11 +1501,6 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) return r; } -static void free_params(struct dm_ioctl *param) -{ - vfree(param); -} - static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) { struct dm_ioctl tmp, *dmi; @@ -1520,13 +1515,15 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) if (!dmi) return -ENOMEM; - if (copy_from_user(dmi, user, tmp.data_size)) { - vfree(dmi); - return -EFAULT; - } + if (copy_from_user(dmi, user, tmp.data_size)) + goto bad; *param = dmi; return 0; + +bad: + vfree(dmi); + return -EFAULT; } static int validate_params(uint cmd, struct dm_ioctl *param) @@ -1564,7 +1561,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) unsigned int cmd; struct dm_ioctl *uninitialized_var(param); ioctl_fn fn = NULL; - size_t param_size; + size_t input_param_size; /* only root can play with this */ if (!capable(CAP_SYS_ADMIN)) @@ -1605,6 +1602,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) * Copy the parameters into kernel space. */ r = copy_params(user, ¶m); + input_param_size = param->data_size; current->flags &= ~PF_MEMALLOC; @@ -1615,9 +1613,8 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) if (r) goto out; - param_size = param->data_size; param->data_size = sizeof(*param); - r = fn(param, param_size); + r = fn(param, input_param_size); /* * Copy the results back to userland. @@ -1625,8 +1622,8 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) if (!r && copy_to_user(user, param, param->data_size)) r = -EFAULT; - out: - free_params(param); +out: + vfree(param); return r; } -- cgit v1.2.2 From f868120549fc1664b2c451d4b9882a363928c698 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 24 Mar 2011 13:54:30 +0000 Subject: dm ioctl: add flag to wipe buffers for secure data Add DM_SECURE_DATA_FLAG which userspace can use to ensure that all buffers allocated for dm-ioctl are wiped immediately after use. The user buffer is wiped as well (we do not want to keep and return sensitive data back to userspace if the flag is set). Wiping is useful for cryptsetup to ensure that the key is present in memory only in defined places and only for the time needed. (For crypt, key can be present in table during load or table status, wait and message commands). Signed-off-by: Milan Broz Signed-off-by: Alasdair G Kergon --- drivers/md/dm-ioctl.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 3a8f6a0e6eb5..4cacdad2270a 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1504,6 +1504,7 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) { struct dm_ioctl tmp, *dmi; + int secure_data; if (copy_from_user(&tmp, user, sizeof(tmp) - sizeof(tmp.data))) return -EFAULT; @@ -1511,17 +1512,28 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) if (tmp.data_size < (sizeof(tmp) - sizeof(tmp.data))) return -EINVAL; + secure_data = tmp.flags & DM_SECURE_DATA_FLAG; + dmi = vmalloc(tmp.data_size); - if (!dmi) + if (!dmi) { + if (secure_data && clear_user(user, tmp.data_size)) + return -EFAULT; return -ENOMEM; + } if (copy_from_user(dmi, user, tmp.data_size)) goto bad; + /* Wipe the user buffer so we do not return it to userspace */ + if (secure_data && clear_user(user, tmp.data_size)) + goto bad; + *param = dmi; return 0; bad: + if (secure_data) + memset(dmi, 0, tmp.data_size); vfree(dmi); return -EFAULT; } @@ -1531,6 +1543,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) /* Always clear this flag */ param->flags &= ~DM_BUFFER_FULL_FLAG; param->flags &= ~DM_UEVENT_GENERATED_FLAG; + param->flags &= ~DM_SECURE_DATA_FLAG; /* Ignores parameters */ if (cmd == DM_REMOVE_ALL_CMD || @@ -1558,6 +1571,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) static int ctl_ioctl(uint command, struct dm_ioctl __user *user) { int r = 0; + int wipe_buffer; unsigned int cmd; struct dm_ioctl *uninitialized_var(param); ioctl_fn fn = NULL; @@ -1602,13 +1616,15 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) * Copy the parameters into kernel space. */ r = copy_params(user, ¶m); - input_param_size = param->data_size; current->flags &= ~PF_MEMALLOC; if (r) return r; + input_param_size = param->data_size; + wipe_buffer = param->flags & DM_SECURE_DATA_FLAG; + r = validate_params(cmd, param); if (r) goto out; @@ -1623,6 +1639,9 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) r = -EFAULT; out: + if (wipe_buffer) + memset(param, 0, input_param_size); + vfree(param); return r; } -- cgit v1.2.2 From 19040c0bc8efcb767221d8ef7bb9c32ff0586179 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 24 Mar 2011 13:54:31 +0000 Subject: dm mpath: fail message ioctl if specified path is not valid Fail the reinstate_path and fail_path message ioctl if the specified path is not valid. The message ioctl would succeed for the 'reinistate_path' and 'fail_path' messages even if action was not taken because the specified device was not a valid path of the multipath device. Before, when /dev/vdb is not a path of mpathb: $ dmsetup message mpathb 0 reinstate_path /dev/vdb $ echo $? 0 After: $ dmsetup message mpathb 0 reinstate_path /dev/vdb device-mapper: message ioctl failed: Invalid argument Command failed $ echo $? 1 Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-mpath.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 4b0b63c290a6..52f0de394632 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1065,7 +1065,7 @@ out: static int action_dev(struct multipath *m, struct dm_dev *dev, action_fn action) { - int r = 0; + int r = -EINVAL; struct pgpath *pgpath; struct priority_group *pg; @@ -1669,7 +1669,7 @@ out: *---------------------------------------------------------------*/ static struct target_type multipath_target = { .name = "multipath", - .version = {1, 2, 0}, + .version = {1, 3, 0}, .module = THIS_MODULE, .ctr = multipath_ctr, .dtr = multipath_dtr, -- cgit v1.2.2 From a490a07a67b7a37f588021410e06b721a752fc34 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Thu, 24 Mar 2011 13:54:33 +0000 Subject: dm mpath: allow table load with no priority groups This patch adjusts the multipath target to allow a table with both 0 priority groups and 0 for the initial priority group number. If any mpath device is held open when all paths in the last priority group have failed, userspace multipathd will attempt to reload the associated DM table to reflect the fact that the device no longer has any priority groups. But the reload attempt always failed because the multipath target did not allow 0 priority groups. All multipath target messages related to priority group (enable_group, disable_group, switch_group) will handle a priority group of 0 (will cause error). When reloading a multipath table with 0 priority groups, userspace multipathd must be updated to specify an initial priority group number of 0 (rather than 1). Signed-off-by: Mike Snitzer Cc: Babu Moger Acked-by: Hannes Reinecke Signed-off-by: Alasdair G Kergon --- drivers/md/dm-mpath.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 52f0de394632..a550a057d991 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -844,8 +844,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, { /* target parameters */ static struct param _params[] = { - {1, 1024, "invalid number of priority groups"}, - {1, 1024, "invalid initial priority group number"}, + {0, 1024, "invalid number of priority groups"}, + {0, 1024, "invalid initial priority group number"}, }; int r; @@ -879,6 +879,13 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc, if (r) goto bad; + if ((!m->nr_priority_groups && next_pg_num) || + (m->nr_priority_groups && !next_pg_num)) { + ti->error = "invalid initial priority group"; + r = -EINVAL; + goto bad; + } + /* parse the priority groups */ while (as.argc) { struct priority_group *pg; @@ -1415,7 +1422,7 @@ static int multipath_status(struct dm_target *ti, status_type_t type, else if (m->current_pg) pg_num = m->current_pg->pg_num; else - pg_num = 1; + pg_num = (m->nr_priority_groups ? 1 : 0); DMEMIT("%u ", pg_num); -- cgit v1.2.2 From 29915202006c2e7bafe81348eb498ff9a724ac61 Mon Sep 17 00:00:00 2001 From: Mustafa Mesanovic Date: Thu, 24 Mar 2011 13:54:35 +0000 Subject: dm stripe: implement merge method Implement a merge function in the striped target. When the striped target's underlying devices provide a merge_bvec_fn (like all DM devices do via dm_merge_bvec) it is important to call down to them when building a biovec that doesn't span a stripe boundary. Without the merge method, a striped DM device stacked on DM devices causes bios with a single page to be submitted which results in unnecessary overhead that hurts performance. This change really helps filesystems (e.g. XFS and now ext4) which take care to assemble larger bios. By implementing stripe_merge(), DM and the stripe target no longer undermine the filesystem's work by only allowing a single page per bio. Buffered IO sees the biggest improvement (particularly uncached reads, buffered writes to a lesser degree). This is especially so for more capable "enterprise" storage LUNs. The performance improvement has been measured to be ~12-35% -- when a reasonable chunk_size is used (e.g. 64K) in conjunction with a stripe count that is a power of 2. In contrast, the performance penalty is ~5-7% for the pathological worst case stripe configuration (small chunk_size with a stripe count that is not a power of 2). The reason for this is that stripe_map_sector() is now called once for every call to dm_merge_bvec(). stripe_map_sector() will use slower division if stripe count isn't a power of 2. Signed-off-by: Mustafa Mesanovic Signed-off-by: Mike Snitzer Signed-off-by: Alasdair G Kergon --- drivers/md/dm-stripe.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index dddfa14f2982..3d80cf0c152d 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -396,9 +396,29 @@ static void stripe_io_hints(struct dm_target *ti, blk_limits_io_opt(limits, chunk_size * sc->stripes); } +static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm, + struct bio_vec *biovec, int max_size) +{ + struct stripe_c *sc = ti->private; + sector_t bvm_sector = bvm->bi_sector; + uint32_t stripe; + struct request_queue *q; + + stripe_map_sector(sc, bvm_sector, &stripe, &bvm_sector); + + q = bdev_get_queue(sc->stripe[stripe].dev->bdev); + if (!q->merge_bvec_fn) + return max_size; + + bvm->bi_bdev = sc->stripe[stripe].dev->bdev; + bvm->bi_sector = sc->stripe[stripe].physical_start + bvm_sector; + + return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); +} + static struct target_type stripe_target = { .name = "striped", - .version = {1, 3, 1}, + .version = {1, 4, 0}, .module = THIS_MODULE, .ctr = stripe_ctr, .dtr = stripe_dtr, @@ -407,6 +427,7 @@ static struct target_type stripe_target = { .status = stripe_status, .iterate_devices = stripe_iterate_devices, .io_hints = stripe_io_hints, + .merge = stripe_merge, }; int __init dm_stripe_init(void) -- cgit v1.2.2 From 3d46b316bcc1ecb17f8e7874a8ec620c64864898 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 24 Mar 2011 16:09:56 +0200 Subject: UBI: use GFP_NOFS properly This patch fixes a brown-paperbag bug which was introduced by me: I used incorrect "GFP_KERNEL | GFP_NOFS" allocation flags to make sure my allocations do not cause write-back. But the correct form is "GFP_NOFS". Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index aaa6e1e83b29..eededf94f5a6 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -1345,7 +1345,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum, if (!(ubi_chk_flags & UBI_CHK_IO)) return 0; - buf1 = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL); + buf1 = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); if (!buf1) { ubi_err("cannot allocate memory to check writes"); return 0; @@ -1409,7 +1409,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) if (!(ubi_chk_flags & UBI_CHK_IO)) return 0; - buf = __vmalloc(len, GFP_KERNEL | GFP_NOFS, PAGE_KERNEL); + buf = __vmalloc(len, GFP_NOFS, PAGE_KERNEL); if (!buf) { ubi_err("cannot allocate memory to check for 0xFFs"); return 0; -- cgit v1.2.2 From 12f0258d5b44b3b5a9442ec461bbac1f7edab8c6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 19 Mar 2011 08:44:34 +0300 Subject: xen-gntdev: return -EFAULT on copy_to_user failure copy_to_user() returns the amount of data remaining to be copied. We want to return a negative error code here. The upper layers just call WARN_ON() if we return non-zero so this doesn't change the behavior. But returning -EFAULT is still cleaner. Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 017ce600fbc6..00b3accc43ee 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -273,7 +273,7 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages) map->vma->vm_start + map->notify.addr; err = copy_to_user(tmp, &err, 1); if (err) - return err; + return -EFAULT; map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; } else if (pgno >= offset && pgno < offset + pages) { uint8_t *tmp = kmap(map->pages[pgno]); -- cgit v1.2.2 From a93e20a83077f57638f8574b1c072ce6712e95ec Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 19 Mar 2011 08:45:43 +0300 Subject: xen-gntdev: unlock on error path in gntdev_mmap() We should unlock here and also decrement the number of &map->users. Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 00b3accc43ee..b0f9e8fb0052 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -662,7 +662,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) if (map->flags) { if ((vma->vm_flags & VM_WRITE) && (map->flags & GNTMAP_readonly)) - return -EINVAL; + goto out_unlock_put; } else { map->flags = GNTMAP_host_map; if (!(vma->vm_flags & VM_WRITE)) @@ -700,6 +700,8 @@ unlock_out: spin_unlock(&priv->lock); return err; +out_unlock_put: + spin_unlock(&priv->lock); out_put_map: if (use_ptemod) map->vma = NULL; -- cgit v1.2.2 From 6ee3b5a12740eddc5a76e130b6cc7cc64468d1f7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 24 Mar 2011 13:26:43 +0000 Subject: drm/i915/lvds: Always return connected in the absence of better information The LVDS connector should default to connected. We tried our best to verify the claims of the BIOS that the hardware exists during init(), and then during detect() we then try to verify that the panel is open. In the event of an unsuccessful query, we should then always report that the LVDS panel is connected. This was only the case for gen2/3, later generations leaked the return value from the panel probe instead. Reported-and-tested-by: Alessandro Suardi Signed-off-by: Chris Wilson Reviewed-by: Keith Packard --- drivers/gpu/drm/i915/intel_lvds.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 1a311ad01116..86cd30bcb619 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -473,19 +473,13 @@ static enum drm_connector_status intel_lvds_detect(struct drm_connector *connector, bool force) { struct drm_device *dev = connector->dev; - enum drm_connector_status status = connector_status_connected; + enum drm_connector_status status; status = intel_panel_detect(dev); if (status != connector_status_unknown) return status; - /* ACPI lid methods were generally unreliable in this generation, so - * don't even bother. - */ - if (IS_GEN2(dev) || IS_GEN3(dev)) - return connector_status_connected; - - return status; + return connector_status_connected; } /** -- cgit v1.2.2 From 6f71d7927c9a9efb7d7e9e6d227d5e246a9c5bd7 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Thu, 24 Mar 2011 11:47:51 -0700 Subject: mlx4_en: Removing HW info from ethtool -i report. Avoiding abuse of ethtool_drvinfo.driver field. HW specific info can be retrieved using lspci. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_ethtool.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c index 62ace6c72b42..d54b7abf0225 100644 --- a/drivers/net/mlx4/en_ethtool.c +++ b/drivers/net/mlx4/en_ethtool.c @@ -45,20 +45,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - switch (mdev->dev->rev_id) { - case 0xa0: - if (dev->dev_id >= MLX4_EN_CX3_LOW_ID && dev->dev_id <= MLX4_EN_CX3_HIGH_ID) - sprintf(drvinfo->driver, DRV_NAME " (%s_CX-3)", mdev->dev->board_id); - else - sprintf(drvinfo->driver, DRV_NAME " (%s_CX)", mdev->dev->board_id); - break; - case 0xb0: - sprintf(drvinfo->driver, DRV_NAME " (%s_CX-2)", mdev->dev->board_id); - break; - default: - sprintf(drvinfo->driver, DRV_NAME " (%s)", mdev->dev->board_id); - break; - } + strncpy(drvinfo->driver, DRV_NAME, 32); strncpy(drvinfo->version, DRV_VERSION " (" DRV_RELDATE ")", 32); sprintf(drvinfo->fw_version, "%d.%d.%d", (u16) (mdev->dev->caps.fw_ver >> 32), -- cgit v1.2.2 From 63a8588debd4dc72becb9e27add9343c76301c7d Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Thu, 24 Mar 2011 14:51:21 -0300 Subject: Bluetooth: add support for Apple MacBook Pro 8,2 Just adding the vendor details makes it work fine. Signed-off-by: Marc-Antoine Perennou Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 866811428e20..2af2e770f4bd 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -71,6 +71,9 @@ static struct usb_device_id btusb_table[] = { /* Apple MacBookAir3,1, MacBookAir3,2 */ { USB_DEVICE(0x05ac, 0x821b) }, + /* Apple MacBookPro8,2 */ + { USB_DEVICE(0x05ac, 0x821a) }, + /* AVM BlueFRITZ! USB v2.0 */ { USB_DEVICE(0x057c, 0x3800) }, -- cgit v1.2.2 From 8763b4da41132e2d5a896cd5e629c3c0a652205e Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Mon, 14 Mar 2011 18:20:33 -0300 Subject: Bluetooth: Fix sending LE data over USB Now that we have support for LE connections, before discarding a frame we must check if there's a LE connection over that transport. Signed-off-by: Vinicius Costa Gomes Acked-by: Ville Tervo Signed-off-by: Gustavo F. Padovan --- drivers/bluetooth/btusb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 2af2e770f4bd..762a5109c68a 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -693,7 +693,8 @@ static int btusb_send_frame(struct sk_buff *skb) break; case HCI_ACLDATA_PKT: - if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1) + if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 && + hdev->conn_hash.le_num < 1)) return -ENODEV; urb = usb_alloc_urb(0, GFP_ATOMIC); -- cgit v1.2.2 From b15f052cb8c1ba2a55998707f29dc8a8e5cc40ca Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 21:27:35 +0000 Subject: arm/gpio: Remove three copies of broken and racy debug code gpiolib plus two gpio implementations in arm fiddle in the guts of irq_desc in a racy and buggy way. Remove the stuff. I already told the gpio folks that we can provide that information in a proper way if necessary. Signed-off-by: Thomas Gleixner Acked-by: Grant Likely LKML-Reference: <20110324212508.931638262@linutronix.de> --- drivers/gpio/gpiolib.c | 45 --------------------------------------------- 1 file changed, 45 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 649550e2cae9..36a2974815b7 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1656,51 +1656,6 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) chip->get ? (chip->get(chip, i) ? "hi" : "lo") : "? "); - - if (!is_out) { - int irq = gpio_to_irq(gpio); - struct irq_desc *desc = irq_to_desc(irq); - - /* This races with request_irq(), set_irq_type(), - * and set_irq_wake() ... but those are "rare". - * - * More significantly, trigger type flags aren't - * currently maintained by genirq. - */ - if (irq >= 0 && desc->action) { - char *trigger; - - switch (desc->status & IRQ_TYPE_SENSE_MASK) { - case IRQ_TYPE_NONE: - trigger = "(default)"; - break; - case IRQ_TYPE_EDGE_FALLING: - trigger = "edge-falling"; - break; - case IRQ_TYPE_EDGE_RISING: - trigger = "edge-rising"; - break; - case IRQ_TYPE_EDGE_BOTH: - trigger = "edge-both"; - break; - case IRQ_TYPE_LEVEL_HIGH: - trigger = "level-high"; - break; - case IRQ_TYPE_LEVEL_LOW: - trigger = "level-low"; - break; - default: - trigger = "?trigger?"; - break; - } - - seq_printf(s, " irq-%d %s%s", - irq, trigger, - (desc->status & IRQ_WAKEUP) - ? " wakeup" : ""); - } - } - seq_printf(s, "\n"); } } -- cgit v1.2.2 From b51804bcf0774a8bc6af1e8bb6ae818f4b71173a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 21:27:36 +0000 Subject: gpio: Cleanup genirq namespace Converted with coccinelle. Signed-off-by: Thomas Gleixner Acked-by: Grant Likely LKML-Reference: <20110324212509.025730689@linutronix.de> Signed-off-by: Thomas Gleixner --- drivers/gpio/adp5588-gpio.c | 8 ++++---- drivers/gpio/max732x.c | 8 ++++---- drivers/gpio/pca953x.c | 6 +++--- drivers/gpio/pl061.c | 14 +++++++------- drivers/gpio/stmpe-gpio.c | 12 ++++++------ drivers/gpio/sx150x.c | 10 +++++----- drivers/gpio/tc3589x-gpio.c | 12 ++++++------ drivers/gpio/timbgpio.c | 18 +++++++++--------- drivers/gpio/vr41xx_giu.c | 12 ++++++------ 9 files changed, 50 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/adp5588-gpio.c b/drivers/gpio/adp5588-gpio.c index 33fc685cb385..3525ad918771 100644 --- a/drivers/gpio/adp5588-gpio.c +++ b/drivers/gpio/adp5588-gpio.c @@ -289,10 +289,10 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev) for (gpio = 0; gpio < dev->gpio_chip.ngpio; gpio++) { int irq = gpio + dev->irq_base; - set_irq_chip_data(irq, dev); - set_irq_chip_and_handler(irq, &adp5588_irq_chip, + irq_set_chip_data(irq, dev); + irq_set_chip_and_handler(irq, &adp5588_irq_chip, handle_level_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM /* * ARM needs us to explicitly flag the IRQ as VALID, @@ -300,7 +300,7 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev) */ set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c index 9e1d01f0071a..ad6951edc16c 100644 --- a/drivers/gpio/max732x.c +++ b/drivers/gpio/max732x.c @@ -470,14 +470,14 @@ static int max732x_irq_setup(struct max732x_chip *chip, if (!(chip->dir_input & (1 << lvl))) continue; - set_irq_chip_data(irq, chip); - set_irq_chip_and_handler(irq, &max732x_irq_chip, + irq_set_chip_data(irq, chip); + irq_set_chip_and_handler(irq, &max732x_irq_chip, handle_edge_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 2fc25dec7cf5..583e92592073 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -395,13 +395,13 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { int irq = lvl + chip->irq_base; - set_irq_chip_data(irq, chip); - set_irq_chip_and_handler(irq, &pca953x_irq_chip, + irq_set_chip_data(irq, chip); + irq_set_chip_and_handler(irq, &pca953x_irq_chip, handle_edge_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index 838ddbdf90cc..901e4e06b377 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c @@ -210,7 +210,7 @@ static struct irq_chip pl061_irqchip = { static void pl061_irq_handler(unsigned irq, struct irq_desc *desc) { - struct list_head *chip_list = get_irq_data(irq); + struct list_head *chip_list = irq_get_handler_data(irq); struct list_head *ptr; struct pl061_gpio *chip; @@ -294,7 +294,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) ret = -ENODEV; goto iounmap; } - set_irq_chained_handler(irq, pl061_irq_handler); + irq_set_chained_handler(irq, pl061_irq_handler); if (!test_and_set_bit(irq, init_irq)) { /* list initialized? */ chip_list = kmalloc(sizeof(*chip_list), GFP_KERNEL); if (chip_list == NULL) { @@ -303,9 +303,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) goto iounmap; } INIT_LIST_HEAD(chip_list); - set_irq_data(irq, chip_list); + irq_set_handler_data(irq, chip_list); } else - chip_list = get_irq_data(irq); + chip_list = irq_get_handler_data(irq); list_add(&chip->list, chip_list); for (i = 0; i < PL061_GPIO_NR; i++) { @@ -315,10 +315,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) else pl061_direction_input(&chip->gc, i); - set_irq_chip(i+chip->irq_base, &pl061_irqchip); - set_irq_handler(i+chip->irq_base, handle_simple_irq); + irq_set_chip(i + chip->irq_base, &pl061_irqchip); + irq_set_handler(i + chip->irq_base, handle_simple_irq); set_irq_flags(i+chip->irq_base, IRQF_VALID); - set_irq_chip_data(i+chip->irq_base, chip); + irq_set_chip_data(i + chip->irq_base, chip); } return 0; diff --git a/drivers/gpio/stmpe-gpio.c b/drivers/gpio/stmpe-gpio.c index eb2901f8ab5e..4c980b573328 100644 --- a/drivers/gpio/stmpe-gpio.c +++ b/drivers/gpio/stmpe-gpio.c @@ -254,14 +254,14 @@ static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio) int irq; for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) { - set_irq_chip_data(irq, stmpe_gpio); - set_irq_chip_and_handler(irq, &stmpe_gpio_irq_chip, + irq_set_chip_data(irq, stmpe_gpio); + irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, handle_simple_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -277,8 +277,8 @@ static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c index d2f874c3d3d5..0370ecf63edf 100644 --- a/drivers/gpio/sx150x.c +++ b/drivers/gpio/sx150x.c @@ -551,12 +551,12 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip, for (n = 0; n < chip->dev_cfg->ngpios; ++n) { irq = irq_base + n; - set_irq_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); - set_irq_nested_thread(irq, 1); + irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -583,8 +583,8 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip) for (n = 0; n < chip->dev_cfg->ngpios; ++n) { irq = chip->irq_base + n; - set_irq_handler(irq, NULL); - set_irq_chip(irq, NULL); + irq_set_handler(irq, NULL); + irq_set_chip(irq, NULL); } } diff --git a/drivers/gpio/tc3589x-gpio.c b/drivers/gpio/tc3589x-gpio.c index 27200af1a595..2a82e8999a42 100644 --- a/drivers/gpio/tc3589x-gpio.c +++ b/drivers/gpio/tc3589x-gpio.c @@ -239,14 +239,14 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio) int irq; for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) { - set_irq_chip_data(irq, tc3589x_gpio); - set_irq_chip_and_handler(irq, &tc3589x_gpio_irq_chip, + irq_set_chip_data(irq, tc3589x_gpio); + irq_set_chip_and_handler(irq, &tc3589x_gpio_irq_chip, handle_simple_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -262,8 +262,8 @@ static void tc3589x_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index 58c8f30352dd..0265872e57d1 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c @@ -195,7 +195,7 @@ out: static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) { - struct timbgpio *tgpio = get_irq_data(irq); + struct timbgpio *tgpio = irq_get_handler_data(irq); unsigned long ipr; int offset; @@ -291,16 +291,16 @@ static int __devinit timbgpio_probe(struct platform_device *pdev) return 0; for (i = 0; i < pdata->nr_pins; i++) { - set_irq_chip_and_handler_name(tgpio->irq_base + i, + irq_set_chip_and_handler_name(tgpio->irq_base + i, &timbgpio_irqchip, handle_simple_irq, "mux"); - set_irq_chip_data(tgpio->irq_base + i, tgpio); + irq_set_chip_data(tgpio->irq_base + i, tgpio); #ifdef CONFIG_ARM set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); #endif } - set_irq_data(irq, tgpio); - set_irq_chained_handler(irq, timbgpio_irq); + irq_set_handler_data(irq, tgpio); + irq_set_chained_handler(irq, timbgpio_irq); return 0; @@ -327,12 +327,12 @@ static int __devexit timbgpio_remove(struct platform_device *pdev) if (irq >= 0 && tgpio->irq_base > 0) { int i; for (i = 0; i < pdata->nr_pins; i++) { - set_irq_chip(tgpio->irq_base + i, NULL); - set_irq_chip_data(tgpio->irq_base + i, NULL); + irq_set_chip(tgpio->irq_base + i, NULL); + irq_set_chip_data(tgpio->irq_base + i, NULL); } - set_irq_handler(irq, NULL); - set_irq_data(irq, NULL); + irq_set_handler(irq, NULL); + irq_set_handler_data(irq, NULL); } err = gpiochip_remove(&tgpio->gpio); diff --git a/drivers/gpio/vr41xx_giu.c b/drivers/gpio/vr41xx_giu.c index cffa3bd7ad3b..a365be040b36 100644 --- a/drivers/gpio/vr41xx_giu.c +++ b/drivers/gpio/vr41xx_giu.c @@ -238,13 +238,13 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, break; } } - set_irq_chip_and_handler(GIU_IRQ(pin), + irq_set_chip_and_handler(GIU_IRQ(pin), &giuint_low_irq_chip, handle_edge_irq); } else { giu_clear(GIUINTTYPL, mask); giu_clear(GIUINTHTSELL, mask); - set_irq_chip_and_handler(GIU_IRQ(pin), + irq_set_chip_and_handler(GIU_IRQ(pin), &giuint_low_irq_chip, handle_level_irq); } @@ -273,13 +273,13 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, break; } } - set_irq_chip_and_handler(GIU_IRQ(pin), + irq_set_chip_and_handler(GIU_IRQ(pin), &giuint_high_irq_chip, handle_edge_irq); } else { giu_clear(GIUINTTYPH, mask); giu_clear(GIUINTHTSELH, mask); - set_irq_chip_and_handler(GIU_IRQ(pin), + irq_set_chip_and_handler(GIU_IRQ(pin), &giuint_high_irq_chip, handle_level_irq); } @@ -539,9 +539,9 @@ static int __devinit giu_probe(struct platform_device *pdev) chip = &giuint_high_irq_chip; if (trigger & (1 << pin)) - set_irq_chip_and_handler(i, chip, handle_edge_irq); + irq_set_chip_and_handler(i, chip, handle_edge_irq); else - set_irq_chip_and_handler(i, chip, handle_level_irq); + irq_set_chip_and_handler(i, chip, handle_level_irq); } -- cgit v1.2.2 From 08f1b807355c8d355885a71e7fd462fe9d499411 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 21:27:37 +0000 Subject: gpio: Fold irq_set_chip/irq_set_handler to irq_set_chip_and_handler Converted with coccinelle. Signed-off-by: Thomas Gleixner Acked-by: Grant Likely LKML-Reference: <20110324212509.118888535@linutronix.de> --- drivers/gpio/pl061.c | 4 ++-- drivers/gpio/sx150x.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/pl061.c b/drivers/gpio/pl061.c index 901e4e06b377..6fcb28cdd862 100644 --- a/drivers/gpio/pl061.c +++ b/drivers/gpio/pl061.c @@ -315,8 +315,8 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) else pl061_direction_input(&chip->gc, i); - irq_set_chip(i + chip->irq_base, &pl061_irqchip); - irq_set_handler(i + chip->irq_base, handle_simple_irq); + irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip, + handle_simple_irq); set_irq_flags(i+chip->irq_base, IRQF_VALID); irq_set_chip_data(i + chip->irq_base, chip); } diff --git a/drivers/gpio/sx150x.c b/drivers/gpio/sx150x.c index 0370ecf63edf..a4f73534394e 100644 --- a/drivers/gpio/sx150x.c +++ b/drivers/gpio/sx150x.c @@ -583,8 +583,7 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip) for (n = 0; n < chip->dev_cfg->ngpios; ++n) { irq = chip->irq_base + n; - irq_set_handler(irq, NULL); - irq_set_chip(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); } } -- cgit v1.2.2 From f7594d42944c0dfca90318f50978a4bdf8504086 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 24 Mar 2011 16:16:02 -0700 Subject: net: fix pch_gbe section mismatch warning Fix section mismatch warning by renaming the pci_driver variable to a recognized (whitelisted) name. WARNING: drivers/net/pch_gbe/pch_gbe.o(.data+0x1f8): Section mismatch in reference from the variable pch_gbe_pcidev to the variable .devinit.rodata:pch_gbe_pcidev_id The variable pch_gbe_pcidev references the variable __devinitconst pch_gbe_pcidev_id If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/net/pch_gbe/pch_gbe_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 8c66e22c3a0a..50986840c99c 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -2441,7 +2441,7 @@ static struct pci_error_handlers pch_gbe_err_handler = { .resume = pch_gbe_io_resume }; -static struct pci_driver pch_gbe_pcidev = { +static struct pci_driver pch_gbe_driver = { .name = KBUILD_MODNAME, .id_table = pch_gbe_pcidev_id, .probe = pch_gbe_probe, @@ -2458,7 +2458,7 @@ static int __init pch_gbe_init_module(void) { int ret; - ret = pci_register_driver(&pch_gbe_pcidev); + ret = pci_register_driver(&pch_gbe_driver); if (copybreak != PCH_GBE_COPYBREAK_DEFAULT) { if (copybreak == 0) { pr_info("copybreak disabled\n"); @@ -2472,7 +2472,7 @@ static int __init pch_gbe_init_module(void) static void __exit pch_gbe_exit_module(void) { - pci_unregister_driver(&pch_gbe_pcidev); + pci_unregister_driver(&pch_gbe_driver); } module_init(pch_gbe_init_module); -- cgit v1.2.2 From cf55bb2439d2a7080fae6edf84919fd81f891574 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Thu, 24 Mar 2011 17:13:20 -0700 Subject: RDMA/nes: Fix test of uninitialized netdev Commit 1765a575334f ("net: make dev->master general") introduced a test of an uninitialized netdev. Fix the code so the intended netdev is tested. Signed-off-by: Roland Dreier --- drivers/infiniband/hw/nes/nes_cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index ef3291551bc6..cfa3a2b22232 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1116,7 +1116,7 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi return rc; } - if (netif_is_bond_slave(netdev)) + if (netif_is_bond_slave(nesvnic->netdev)) netdev = nesvnic->netdev->master; else netdev = nesvnic->netdev; -- cgit v1.2.2 From b2b755b5f10eb32fbdc73a9907c07006b17f714b Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Thu, 24 Mar 2011 15:18:15 -0700 Subject: lib, arch: add filter argument to show_mem and fix private implementations Commit ddd588b5dd55 ("oom: suppress nodes that are not allowed from meminfo on oom kill") moved lib/show_mem.o out of lib/lib.a, which resulted in build warnings on all architectures that implement their own versions of show_mem(): lib/lib.a(show_mem.o): In function `show_mem': show_mem.c:(.text+0x1f4): multiple definition of `show_mem' arch/sparc/mm/built-in.o:(.text+0xd70): first defined here The fix is to remove __show_mem() and add its argument to show_mem() in all implementations to prevent this breakage. Architectures that implement their own show_mem() actually don't do anything with the argument yet, but they could be made to filter nodes that aren't allowed in the current context in the future just like the generic implementation. Reported-by: Stephen Rothwell Reported-by: James Bottomley Suggested-by: Andrew Morton Signed-off-by: David Rientjes Signed-off-by: Linus Torvalds --- drivers/tty/sysrq.c | 2 +- drivers/tty/vt/keyboard.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 81f13958e751..43db715f1502 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -306,7 +306,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = { static void sysrq_handle_showmem(int key) { - show_mem(); + show_mem(0); } static struct sysrq_key_op sysrq_showmem_op = { .handler = sysrq_handle_showmem, diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 6dd3c68c13ad..d6b342b5b423 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -600,7 +600,7 @@ static void fn_scroll_back(struct vc_data *vc) static void fn_show_mem(struct vc_data *vc) { - show_mem(); + show_mem(0); } static void fn_show_state(struct vc_data *vc) -- cgit v1.2.2 From 30f5b28e7f937608e0407edaa459cc8161de81d9 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 25 Mar 2011 12:30:05 +1100 Subject: [media] rc: update for bitop name changes Fix the following compile failure: drivers/media/rc/ite-cir.c: In function 'ite_decode_bytes': drivers/media/rc/ite-cir.c:190: error: implicit declaration of function 'generic_find_next_le_bit' drivers/media/rc/ite-cir.c:199: error: implicit declaration of function 'generic_find_next_zero_le_bit' Caused by commit 620a32bba4a2 ("[media] rc: New rc-based ite-cir driver for several ITE CIRs") interacting with commit c4945b9ed472 ("asm-generic: rename generic little-endian bitops functions"). Signed-off-by: Stephen Rothwell Signed-off-by: Linus Torvalds --- drivers/media/rc/ite-cir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 9be6a830f1d2..ac0e42b47b2a 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -187,7 +187,7 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int sample_period = dev->params.sample_period; ldata = (unsigned long *)data; size = length << 3; - next_one = generic_find_next_le_bit(ldata, size, 0); + next_one = find_next_bit_le(ldata, size, 0); if (next_one > 0) { ev.pulse = true; ev.duration = @@ -196,14 +196,14 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int } while (next_one < size) { - next_zero = generic_find_next_zero_le_bit(ldata, size, next_one + 1); + next_zero = find_next_zero_bit_le(ldata, size, next_one + 1); ev.pulse = false; ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period); ir_raw_event_store_with_filter(dev->rdev, &ev); if (next_zero < size) { next_one = - generic_find_next_le_bit(ldata, + find_next_bit_le(ldata, size, next_zero + 1); ev.pulse = true; -- cgit v1.2.2 From 5a8fba524c2063cb297bdbacda535448ee365dc4 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Wed, 16 Mar 2011 17:46:45 -0400 Subject: mmc: mmc_test: Remove set-but-unused variable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: drivers/mmc/card/mmc_test.c: In function ‘mmc_test_seq_perf’: drivers/mmc/card/mmc_test.c:1878:28: warning: variable ‘ts’ set but not used [-Wunused-but-set-variable] There's no reason to be calling timespec_sub() here, because mmc_test_print_avg_rate() is going to do that itself. Signed-off-by: Chris Ball Cc: Adrian Hunter --- drivers/mmc/card/mmc_test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 5ec8eddfcf6e..f5cedeccad42 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -1875,7 +1875,7 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write, unsigned int tot_sz, int max_scatter) { unsigned int dev_addr, i, cnt, sz, ssz; - struct timespec ts1, ts2, ts; + struct timespec ts1, ts2; int ret; sz = test->area.max_tfr; @@ -1912,7 +1912,6 @@ static int mmc_test_seq_perf(struct mmc_test_card *test, int write, } getnstimeofday(&ts2); - ts = timespec_sub(ts2, ts1); mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2); return 0; -- cgit v1.2.2 From cf5e23e1c27af4291cf90020c295756ba4dcf326 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 17 Mar 2011 16:46:17 -0400 Subject: mmc: use pci_dev->revision The SDHCI driver uses PCI_CLASS_REVISION instead of PCI_REVISION_ID, so it was not converted by commit 44c10138fd4bbc4b6d6bff0873c24902f2a9da65 (PCI: Change all drivers to use pci_device->revision). The newer VIA driver has similar code too. This patch converts both drivers to use the 'revision' field of 'struct pci_dev'. Signed-off-by: Sergei Shtylyov Acked-by: Harald Welte Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 6 ++---- drivers/mmc/host/via-sdmmc.c | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 2f8d46854acd..a136be706347 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1016,16 +1016,14 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; - u8 slots, rev, first_bar; + u8 slots, first_bar; int ret, i; BUG_ON(pdev == NULL); BUG_ON(ent == NULL); - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); - dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n", - (int)pdev->vendor, (int)pdev->device, (int)rev); + (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots); if (ret) diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 8c5b4881ccd6..4dfe2c02ea91 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -1087,14 +1087,13 @@ static int __devinit via_sd_probe(struct pci_dev *pcidev, struct mmc_host *mmc; struct via_crdr_mmc_host *sdhost; u32 base, len; - u8 rev, gatt; + u8 gatt; int ret; - pci_read_config_byte(pcidev, PCI_CLASS_REVISION, &rev); pr_info(DRV_NAME ": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n", pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, - (int)rev); + (int)pcidev->revision); ret = pci_enable_device(pcidev); if (ret) -- cgit v1.2.2 From a5289a433dd7b15df248d1f0272f52be38fe6971 Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Fri, 25 Feb 2011 11:08:13 +0900 Subject: mmc: dw_mmc: set fixed burst in BMOD register This patch uses the fixed burst bit when using an internal DMA controller. I found increased performance with IDMAC when this bit is set. Signed-off-by: Jaehoon Chung Signed-off-by: Kyungmin Park Signed-off-by: Chris Ball --- drivers/mmc/host/dw_mmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 5a614069cb00..87e1f57ec9ba 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -316,7 +316,7 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host) /* Stop the IDMAC running */ temp = mci_readl(host, BMOD); - temp &= ~SDMMC_IDMAC_ENABLE; + temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB); mci_writel(host, BMOD, temp); } @@ -385,7 +385,7 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len) /* Enable the IDMAC */ temp = mci_readl(host, BMOD); - temp |= SDMMC_IDMAC_ENABLE; + temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB; mci_writel(host, BMOD, temp); /* Start it running */ -- cgit v1.2.2 From 768fbc1876b3239f4c463c00ea1e78725554cf21 Mon Sep 17 00:00:00 2001 From: Pawel Moll Date: Fri, 11 Mar 2011 17:18:07 +0000 Subject: mmc: mmci: Add ARM variant with extended FIFO New IO FPGA implementation for Versatile Express boards contain MMCI (PL180) cell with FIFO extended to 128 words (512 bytes). Matt Waddel reports that this patch improves MMC performance on his vexpress system, and also fixes "mmcblk0: error -5 transferring data" errors. Signed-off-by: Pawel Moll Tested-by: Matt Waddel Signed-off-by: Chris Ball --- drivers/mmc/host/mmci.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5bbb87d10251..b4a7e4fba90f 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -68,6 +68,12 @@ static struct variant_data variant_arm = { .datalength_bits = 16, }; +static struct variant_data variant_arm_extended_fifo = { + .fifosize = 128 * 4, + .fifohalfsize = 64 * 4, + .datalength_bits = 16, +}; + static struct variant_data variant_u300 = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, @@ -1277,9 +1283,14 @@ static int mmci_resume(struct amba_device *dev) static struct amba_id mmci_ids[] = { { .id = 0x00041180, - .mask = 0x000fffff, + .mask = 0xff0fffff, .data = &variant_arm, }, + { + .id = 0x01041180, + .mask = 0xff0fffff, + .data = &variant_arm_extended_fifo, + }, { .id = 0x00041181, .mask = 0x000fffff, -- cgit v1.2.2 From b2fce6ad9f0f01cc06745298148a4941ccc4d3ec Mon Sep 17 00:00:00 2001 From: David Miller Date: Fri, 18 Mar 2011 15:00:23 -0700 Subject: mmc: of_mmc_spi: Need to include irq.h and of_irq.h Since these are the headers that provide irq_of_parse_and_map() and NO_IRQ. Signed-off-by: David S. Miller Acked-by: Grant Likely Signed-off-by: Chris Ball --- drivers/mmc/host/of_mmc_spi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index 5530def54e5b..e2aecb7f1d5c 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -15,9 +15,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include -- cgit v1.2.2 From e481e45df754cbb01630e308f9baeb1c066ef1f9 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Mon, 21 Mar 2011 13:22:13 +0800 Subject: mmc: sdhci-esdhc: remove SDHCI_QUIRK_NO_CARD_NO_RESET from esdhc sdhci-esdhc-imx does not need SDHCI_QUIRK_NO_CARD_NO_RESET. Make it OF-specific. Signed-off-by: Richard Zhu Tested-by: Wolfram Sang Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-esdhc.h | 3 +-- drivers/mmc/host/sdhci-of-esdhc.c | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h index c55aae828aac..c3b08f111942 100644 --- a/drivers/mmc/host/sdhci-esdhc.h +++ b/drivers/mmc/host/sdhci-esdhc.h @@ -23,8 +23,7 @@ SDHCI_QUIRK_NONSTANDARD_CLOCK | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ SDHCI_QUIRK_PIO_NEEDS_DELAY | \ - SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | \ - SDHCI_QUIRK_NO_CARD_NO_RESET) + SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET) #define ESDHC_SYSTEM_CONTROL 0x2c #define ESDHC_CLOCK_MASK 0x0000fff0 diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 08161f690ae8..ba40d6d035c7 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -74,7 +74,8 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) struct sdhci_of_data sdhci_esdhc = { /* card detection could be handled via GPIO */ - .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION, + .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION + | SDHCI_QUIRK_NO_CARD_NO_RESET, .ops = { .read_l = sdhci_be32bs_readl, .read_w = esdhc_readw, -- cgit v1.2.2 From 574e3f5602d930a962f50dcc7124941c60c44084 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Mon, 21 Mar 2011 13:22:14 +0800 Subject: mmc: sdhci: add the abort CMDTYPE bits definition Add the abort CMDTYPE bits definition of command register (offset 0xE) Signed-off-by: Richard Zhu Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 6e0969e40650..25e8bde600d1 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -45,6 +45,7 @@ #define SDHCI_CMD_CRC 0x08 #define SDHCI_CMD_INDEX 0x10 #define SDHCI_CMD_DATA 0x20 +#define SDHCI_CMD_ABORTCMD 0xC0 #define SDHCI_CMD_RESP_NONE 0x00 #define SDHCI_CMD_RESP_LONG 0x01 -- cgit v1.2.2 From e149860d16d96aef1a8eb7dc1d0b9d4313479e61 Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Fri, 25 Mar 2011 09:18:27 -0400 Subject: mmc: sdhci-esdhc: use writel/readl as general APIs Add one flag to indicate the GPIO CD/WP is enabled or not on imx platforms, and reuse the writel/readl as the general APIs for imx SOCs. Signed-off-by: Richard Zhu Reviewed-by: Wolfram Sang Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-esdhc-imx.c | 44 ++++++++++++++++++++++++++++++++------ drivers/mmc/host/sdhci-pltfm.h | 2 +- 2 files changed, 38 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 3b5248567973..67a2da961bb5 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,13 @@ #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" +#define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0) + +struct pltfm_imx_data { + int flags; + u32 scratchpad; +}; + static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) { void __iomem *base = host->ioaddr + (reg & ~0x3); @@ -34,10 +42,14 @@ static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, i static u32 esdhc_readl_le(struct sdhci_host *host, int reg) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; + /* fake CARD_PRESENT flag on mx25/35 */ u32 val = readl(host->ioaddr + reg); - if (unlikely(reg == SDHCI_PRESENT_STATE)) { + if (unlikely((reg == SDHCI_PRESENT_STATE) + && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) { struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; @@ -55,7 +67,11 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) { - if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; + + if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE) + && (imx_data->flags & ESDHC_FLAG_GPIO_FOR_CD_WP))) /* * these interrupts won't work with a custom card_detect gpio * (only applied to mx25/35) @@ -76,6 +92,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg) static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = pltfm_host->priv; switch (reg) { case SDHCI_TRANSFER_MODE: @@ -83,10 +100,10 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) * Postpone this write, we must do it together with a * command write that is down below. */ - pltfm_host->scratchpad = val; + imx_data->scratchpad = val; return; case SDHCI_COMMAND: - writel(val << 16 | pltfm_host->scratchpad, + writel(val << 16 | imx_data->scratchpad, host->ioaddr + SDHCI_TRANSFER_MODE); return; case SDHCI_BLOCK_SIZE: @@ -146,7 +163,9 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) } static struct sdhci_ops sdhci_esdhc_ops = { + .read_l = esdhc_readl_le, .read_w = esdhc_readw_le, + .write_l = esdhc_writel_le, .write_w = esdhc_writew_le, .write_b = esdhc_writeb_le, .set_clock = esdhc_set_clock, @@ -168,6 +187,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; struct clk *clk; int err; + struct pltfm_imx_data *imx_data; clk = clk_get(mmc_dev(host->mmc), NULL); if (IS_ERR(clk)) { @@ -177,7 +197,15 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd clk_enable(clk); pltfm_host->clk = clk; - if (cpu_is_mx35() || cpu_is_mx51()) + imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); + if (!imx_data) { + clk_disable(pltfm_host->clk); + clk_put(pltfm_host->clk); + return -ENOMEM; + } + pltfm_host->priv = imx_data; + + if (!cpu_is_mx25()) host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; if (cpu_is_mx25() || cpu_is_mx35()) { @@ -214,8 +242,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd goto no_card_detect_irq; } - sdhci_esdhc_ops.write_l = esdhc_writel_le; - sdhci_esdhc_ops.read_l = esdhc_readl_le; + imx_data->flags |= ESDHC_FLAG_GPIO_FOR_CD_WP; /* Now we have a working card_detect again */ host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; } @@ -227,6 +254,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd no_card_detect_pin: boarddata->cd_gpio = err; not_supported: + kfree(imx_data); return 0; } @@ -234,6 +262,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; + struct pltfm_imx_data *imx_data = pltfm_host->priv; if (boarddata && gpio_is_valid(boarddata->wp_gpio)) gpio_free(boarddata->wp_gpio); @@ -247,6 +276,7 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) clk_disable(pltfm_host->clk); clk_put(pltfm_host->clk); + kfree(imx_data); } struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index ea2e44d9be5e..2b37016ad0ac 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -17,7 +17,7 @@ struct sdhci_pltfm_host { struct clk *clk; - u32 scratchpad; /* to handle quirks across io-accessor calls */ + void *priv; /* to handle quirks across io-accessor calls */ }; extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata; -- cgit v1.2.2 From 58ac8177cebb890ba980cdace36457e0fe1e62af Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Mon, 21 Mar 2011 13:22:16 +0800 Subject: mmc: sdhci-esdhc: enable esdhc on imx53 Fix the NO INT in the Multi-BLK IO in SD/MMC, and Multi-BLK read in SDIO on imx53. The CMDTYPE of the CMD register (offset 0xE) should be set to "11" when the STOP CMD12 is issued on imx53 to abort one open ended multi-blk IO. Otherwise the TC INT wouldn't be generated. In exact block transfer, the controller doesn't complete the operations automatically as required at the end of the transfer and remains on hold if the abort command is not sent on imx53. As a result, the TC flag is not asserted and SW receives timeout exception. Set bit1 of Vendor Spec register to fix it. Signed-off-by: Richard Zhu Signed-off-by: Richard Zhao Reviewed-by: Wolfram Sang Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-esdhc-imx.c | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 67a2da961bb5..a19967d0bfc4 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -19,13 +19,31 @@ #include #include #include +#include +#include #include #include #include "sdhci.h" #include "sdhci-pltfm.h" #include "sdhci-esdhc.h" +/* VENDOR SPEC register */ +#define SDHCI_VENDOR_SPEC 0xC0 +#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 + #define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0) +/* + * The CMDTYPE of the CMD register (offset 0xE) should be set to + * "11" when the STOP CMD12 is issued on imx53 to abort one + * open ended multi-blk IO. Otherwise the TC INT wouldn't + * be generated. + * In exact block transfer, the controller doesn't complete the + * operations automatically as required at the end of the + * transfer and remains on hold if the abort command is not sent. + * As a result, the TC flag is not asserted and SW received timeout + * exeception. Bit1 of Vendor Spec registor is used to fix it. + */ +#define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) struct pltfm_imx_data { int flags; @@ -78,6 +96,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) */ val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); + if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) + && (reg == SDHCI_INT_STATUS) + && (val & SDHCI_INT_DATA_END))) { + u32 v; + v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); + v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; + writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); + } + writel(val, host->ioaddr + reg); } @@ -100,9 +127,21 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) * Postpone this write, we must do it together with a * command write that is down below. */ + if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) + && (host->cmd->opcode == SD_IO_RW_EXTENDED) + && (host->cmd->data->blocks > 1) + && (host->cmd->data->flags & MMC_DATA_READ)) { + u32 v; + v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); + v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; + writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); + } imx_data->scratchpad = val; return; case SDHCI_COMMAND: + if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) + && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) + val |= SDHCI_CMD_ABORTCMD; writel(val << 16 | imx_data->scratchpad, host->ioaddr + SDHCI_TRANSFER_MODE); return; @@ -215,6 +254,9 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; } + if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())) + imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; + if (boarddata) { err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); if (err) { -- cgit v1.2.2 From 4f665cb614b8a258b507cc47753dd3f7dd45aac6 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Fri, 25 Mar 2011 15:06:19 +0900 Subject: mmc: fix mmc_app_send_scr() for dma transfer This patch is based on the commit "af51715079e7fb6b290e1881d63d815dc4de5011": * Bugfix to that mmc_send_cxd_data() code: dma-to-stack is unsafe/nonportable, so kmalloc a bounce buffer instead. The driver may invalidate the mmc_card->csd when host driver uses dma. So this subroutine also needs a kmalloc buffer. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Chris Ball --- drivers/mmc/core/sd_ops.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c index 797cdb5887fd..76af349c14b4 100644 --- a/drivers/mmc/core/sd_ops.c +++ b/drivers/mmc/core/sd_ops.c @@ -9,6 +9,7 @@ * your option) any later version. */ +#include #include #include @@ -252,6 +253,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) struct mmc_command cmd; struct mmc_data data; struct scatterlist sg; + void *data_buf; BUG_ON(!card); BUG_ON(!card->host); @@ -263,6 +265,13 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) if (err) return err; + /* dma onto stack is unsafe/nonportable, but callers to this + * routine normally provide temporary on-stack buffers ... + */ + data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL); + if (data_buf == NULL) + return -ENOMEM; + memset(&mrq, 0, sizeof(struct mmc_request)); memset(&cmd, 0, sizeof(struct mmc_command)); memset(&data, 0, sizeof(struct mmc_data)); @@ -280,12 +289,15 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) data.sg = &sg; data.sg_len = 1; - sg_init_one(&sg, scr, 8); + sg_init_one(&sg, data_buf, 8); mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); + memcpy(scr, data_buf, sizeof(card->raw_scr)); + kfree(data_buf); + if (cmd.error) return cmd.error; if (data.error) -- cgit v1.2.2 From 51fc7b2ce74d31b7d9a6bd3c57bf6c1cc77e837d Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 4 Mar 2011 09:56:21 +0100 Subject: mmc: tmio-mmc: Improve DMA stability on sh-mobile On some SDHI tmio implementations the order of DMA and command completion interrupts swaps, which leads to malfunction. This patch postpones DMA activation until the MMC command completion IRQ time. Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 63 ++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index ab1adeabdd22..e88627b33377 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -485,7 +485,10 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) unsigned int count; unsigned long flags; - if (!data) { + if (host->chan_tx || host->chan_rx) { + pr_err("PIO IRQ in DMA mode!\n"); + return; + } else if (!data) { pr_debug("Spurious PIO IRQ\n"); return; } @@ -648,6 +651,8 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, if (host->data->flags & MMC_DATA_READ) { if (!host->chan_rx) enable_mmc_irqs(host, TMIO_MASK_READOP); + else + tasklet_schedule(&host->dma_issue); } else { if (!host->chan_tx) enable_mmc_irqs(host, TMIO_MASK_WRITEOP); @@ -779,18 +784,6 @@ static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) #endif } -static void tmio_dma_complete(void *arg) -{ - struct tmio_mmc_host *host = arg; - - dev_dbg(&host->pdev->dev, "Command completed\n"); - - if (!host->data) - dev_warn(&host->pdev->dev, "NULL data in DMA completion!\n"); - else - enable_mmc_irqs(host, TMIO_STAT_DATAEND); -} - static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) { struct scatterlist *sg = host->sg_ptr, *sg_tmp; @@ -817,6 +810,8 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) goto pio; } + disable_mmc_irqs(host, TMIO_STAT_RXRDY); + /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); @@ -827,14 +822,11 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); if (ret > 0) desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_FROM_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_FROM_DEVICE, DMA_CTRL_ACK); - if (desc) { - desc->callback = tmio_dma_complete; - desc->callback_param = host; + if (desc) cookie = dmaengine_submit(desc); - dma_async_issue_pending(chan); - } + dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", __func__, host->sg_len, ret, cookie, host->mrq); @@ -886,6 +878,8 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) goto pio; } + disable_mmc_irqs(host, TMIO_STAT_TXRQ); + /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { unsigned long flags; @@ -900,13 +894,11 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); if (ret > 0) desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + DMA_TO_DEVICE, DMA_CTRL_ACK); - if (desc) { - desc->callback = tmio_dma_complete; - desc->callback_param = host; + if (desc) cookie = dmaengine_submit(desc); - } + dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", __func__, host->sg_len, ret, cookie, host->mrq); @@ -947,17 +939,30 @@ static void tmio_mmc_start_dma(struct tmio_mmc_host *host, static void tmio_issue_tasklet_fn(unsigned long priv) { struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; - struct dma_chan *chan = host->chan_tx; + struct dma_chan *chan = NULL; + + spin_lock_irq(&host->lock); + + if (host && host->data) { + if (host->data->flags & MMC_DATA_READ) + chan = host->chan_rx; + else + chan = host->chan_tx; + } + + spin_unlock_irq(&host->lock); - dma_async_issue_pending(chan); + enable_mmc_irqs(host, TMIO_STAT_DATAEND); + + if (chan) + dma_async_issue_pending(chan); } static void tmio_tasklet_fn(unsigned long arg) { struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; - unsigned long flags; - spin_lock_irqsave(&host->lock, flags); + spin_lock_irq(&host->lock); if (!host->data) goto out; @@ -973,7 +978,7 @@ static void tmio_tasklet_fn(unsigned long arg) tmio_mmc_do_data_irq(host); out: - spin_unlock_irqrestore(&host->lock, flags); + spin_unlock_irq(&host->lock); } /* It might be necessary to make filter MFD specific */ -- cgit v1.2.2 From 5f52c3552946eafa13f89c949449d16ce2b58b24 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 7 Mar 2011 11:33:11 +0100 Subject: mmc: tmio: use PIO for short transfers This patch allows transferring of some requests in PIO and some in DMA mode and defaults to using DMA only for transfers longer than 8 bytes. This is especially useful with SDIO, which can have lots of 2- and 4-byte transfers, creating unnecessary high overhead, when executed in DMA. Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index e88627b33377..32ab1452d97d 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -100,6 +100,8 @@ TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) #define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) +#define TMIO_MIN_DMA_LEN 8 + #define enable_mmc_irqs(host, i) \ do { \ u32 mask;\ @@ -147,6 +149,7 @@ struct tmio_mmc_host { struct platform_device *pdev; /* DMA support */ + bool force_pio; struct dma_chan *chan_rx; struct dma_chan *chan_tx; struct tasklet_struct dma_complete; @@ -385,6 +388,7 @@ static void tmio_mmc_reset_work(struct work_struct *work) host->cmd = NULL; host->data = NULL; host->mrq = NULL; + host->force_pio = false; spin_unlock_irqrestore(&host->lock, flags); @@ -404,6 +408,7 @@ tmio_mmc_finish_request(struct tmio_mmc_host *host) host->mrq = NULL; host->cmd = NULL; host->data = NULL; + host->force_pio = false; cancel_delayed_work(&host->delayed_reset_work); @@ -485,7 +490,7 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) unsigned int count; unsigned long flags; - if (host->chan_tx || host->chan_rx) { + if ((host->chan_tx || host->chan_rx) && !host->force_pio) { pr_err("PIO IRQ in DMA mode!\n"); return; } else if (!data) { @@ -551,15 +556,11 @@ static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) */ if (data->flags & MMC_DATA_READ) { - if (!host->chan_rx) - disable_mmc_irqs(host, TMIO_MASK_READOP); - else + if (host->chan_rx && !host->force_pio) tmio_check_bounce_buffer(host); dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", host->mrq); } else { - if (!host->chan_tx) - disable_mmc_irqs(host, TMIO_MASK_WRITEOP); dev_dbg(&host->pdev->dev, "Complete Tx request %p\n", host->mrq); } @@ -583,7 +584,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host) if (!data) goto out; - if (host->chan_tx && (data->flags & MMC_DATA_WRITE)) { + if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) { /* * Has all data been written out yet? Testing on SuperH showed, * that in most cases the first interrupt comes already with the @@ -596,11 +597,12 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host) disable_mmc_irqs(host, TMIO_STAT_DATAEND); tasklet_schedule(&host->dma_complete); } - } else if (host->chan_rx && (data->flags & MMC_DATA_READ)) { + } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) { disable_mmc_irqs(host, TMIO_STAT_DATAEND); tasklet_schedule(&host->dma_complete); } else { tmio_mmc_do_data_irq(host); + disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP); } out: spin_unlock(&host->lock); @@ -649,12 +651,12 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, */ if (host->data && !cmd->error) { if (host->data->flags & MMC_DATA_READ) { - if (!host->chan_rx) + if (host->force_pio || !host->chan_rx) enable_mmc_irqs(host, TMIO_MASK_READOP); else tasklet_schedule(&host->dma_issue); } else { - if (!host->chan_tx) + if (host->force_pio || !host->chan_tx) enable_mmc_irqs(host, TMIO_MASK_WRITEOP); else tasklet_schedule(&host->dma_issue); @@ -810,6 +812,11 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) goto pio; } + if (sg->length < TMIO_MIN_DMA_LEN) { + host->force_pio = true; + return; + } + disable_mmc_irqs(host, TMIO_STAT_RXRDY); /* The only sg element can be unaligned, use our bounce buffer then */ @@ -878,6 +885,11 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) goto pio; } + if (sg->length < TMIO_MIN_DMA_LEN) { + host->force_pio = true; + return; + } + disable_mmc_irqs(host, TMIO_STAT_TXRQ); /* The only sg element can be unaligned, use our bounce buffer then */ @@ -1119,6 +1131,7 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) fail: host->mrq = NULL; + host->force_pio = false; mrq->cmd->error = ret; mmc_request_done(mmc, mrq); } -- cgit v1.2.2 From b6147490e6aac82fa2f4b9d7fce925d9891ebe8f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 12:42:44 +0100 Subject: mmc: tmio: split core functionality, DMA and MFD glue TMIO MMC chips contain an SD / SDIO IP core from Panasonic, similar to the one, used in MN5774 and other MN57xx controllers. These IP cores are included in many multifunction devices, in sh-mobile chips from Renesas, in the latter case they can also use DMA. Some sh-mobile implementations also have some other specialities, that MFD-based solutions don't have. This makes supporting all these features in a monolithic driver inconveniet and error-prone. This patch splits the driver into 3 parts: the core, the MFD glue and the DMA support. In case of a modular build, two modules will be built: mmc_tmio_core and mmc_tmio. Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 4 + drivers/mmc/host/Makefile | 3 + drivers/mmc/host/tmio_mmc.c | 1303 +-------------------------------------- drivers/mmc/host/tmio_mmc.h | 145 +++++ drivers/mmc/host/tmio_mmc_dma.c | 316 ++++++++++ drivers/mmc/host/tmio_mmc_pio.c | 923 +++++++++++++++++++++++++++ 6 files changed, 1409 insertions(+), 1285 deletions(-) create mode 100644 drivers/mmc/host/tmio_mmc.h create mode 100644 drivers/mmc/host/tmio_mmc_dma.c create mode 100644 drivers/mmc/host/tmio_mmc_pio.c (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 1a21c6427a19..4d16166386ca 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -439,9 +439,13 @@ config MMC_SDRICOH_CS To compile this driver as a module, choose M here: the module will be called sdricoh_cs. +config MMC_TMIO_CORE + tristate + config MMC_TMIO tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI + select MMC_TMIO_CORE help This provides support for the SD/MMC cell found in TC6393XB, T7L66XB and also HTC ASIC3 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 30aa6867745f..79c42dd23c0e 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -29,6 +29,9 @@ endif obj-$(CONFIG_MMC_S3C) += s3cmci.o obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o +obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o +tmio_mmc_core-y := tmio_mmc_pio.o +tmio_mmc_core-$(CONFIG_TMIO_MMC_DMA) += tmio_mmc_dma.o obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 32ab1452d97d..79c568461d59 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -1,8 +1,8 @@ /* - * linux/drivers/mmc/tmio_mmc.c + * linux/drivers/mmc/host/tmio_mmc.c * - * Copyright (C) 2004 Ian Molton - * Copyright (C) 2007 Ian Molton + * Copyright (C) 2007 Ian Molton + * Copyright (C) 2004 Ian Molton * * 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 @@ -11,1200 +11,17 @@ * Driver for the MMC / SD / SDIO cell found in: * * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 - * - * This driver draws mainly on scattered spec sheets, Reverse engineering - * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit - * support). (Further 4 bit support from a later datasheet). - * - * TODO: - * Investigate using a workqueue for PIO transfers - * Eliminate FIXMEs - * SDIO support - * Better Power management - * Handle MMC errors better - * double buffer support - * */ -#include #include -#include -#include -#include -#include -#include #include #include #include #include #include #include -#include -#include - -#define CTL_SD_CMD 0x00 -#define CTL_ARG_REG 0x04 -#define CTL_STOP_INTERNAL_ACTION 0x08 -#define CTL_XFER_BLK_COUNT 0xa -#define CTL_RESPONSE 0x0c -#define CTL_STATUS 0x1c -#define CTL_IRQ_MASK 0x20 -#define CTL_SD_CARD_CLK_CTL 0x24 -#define CTL_SD_XFER_LEN 0x26 -#define CTL_SD_MEM_CARD_OPT 0x28 -#define CTL_SD_ERROR_DETAIL_STATUS 0x2c -#define CTL_SD_DATA_PORT 0x30 -#define CTL_TRANSACTION_CTL 0x34 -#define CTL_SDIO_STATUS 0x36 -#define CTL_SDIO_IRQ_MASK 0x38 -#define CTL_RESET_SD 0xe0 -#define CTL_SDIO_REGS 0x100 -#define CTL_CLK_AND_WAIT_CTL 0x138 -#define CTL_RESET_SDIO 0x1e0 - -/* Definitions for values the CTRL_STATUS register can take. */ -#define TMIO_STAT_CMDRESPEND 0x00000001 -#define TMIO_STAT_DATAEND 0x00000004 -#define TMIO_STAT_CARD_REMOVE 0x00000008 -#define TMIO_STAT_CARD_INSERT 0x00000010 -#define TMIO_STAT_SIGSTATE 0x00000020 -#define TMIO_STAT_WRPROTECT 0x00000080 -#define TMIO_STAT_CARD_REMOVE_A 0x00000100 -#define TMIO_STAT_CARD_INSERT_A 0x00000200 -#define TMIO_STAT_SIGSTATE_A 0x00000400 -#define TMIO_STAT_CMD_IDX_ERR 0x00010000 -#define TMIO_STAT_CRCFAIL 0x00020000 -#define TMIO_STAT_STOPBIT_ERR 0x00040000 -#define TMIO_STAT_DATATIMEOUT 0x00080000 -#define TMIO_STAT_RXOVERFLOW 0x00100000 -#define TMIO_STAT_TXUNDERRUN 0x00200000 -#define TMIO_STAT_CMDTIMEOUT 0x00400000 -#define TMIO_STAT_RXRDY 0x01000000 -#define TMIO_STAT_TXRQ 0x02000000 -#define TMIO_STAT_ILL_FUNC 0x20000000 -#define TMIO_STAT_CMD_BUSY 0x40000000 -#define TMIO_STAT_ILL_ACCESS 0x80000000 - -/* Definitions for values the CTRL_SDIO_STATUS register can take. */ -#define TMIO_SDIO_STAT_IOIRQ 0x0001 -#define TMIO_SDIO_STAT_EXPUB52 0x4000 -#define TMIO_SDIO_STAT_EXWT 0x8000 -#define TMIO_SDIO_MASK_ALL 0xc007 - -/* Define some IRQ masks */ -/* This is the mask used at reset by the chip */ -#define TMIO_MASK_ALL 0x837f031d -#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) -#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) -#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ - TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) -#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) - -#define TMIO_MIN_DMA_LEN 8 - -#define enable_mmc_irqs(host, i) \ - do { \ - u32 mask;\ - mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ - mask &= ~((i) & TMIO_MASK_IRQ); \ - sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ - } while (0) - -#define disable_mmc_irqs(host, i) \ - do { \ - u32 mask;\ - mask = sd_ctrl_read32((host), CTL_IRQ_MASK); \ - mask |= ((i) & TMIO_MASK_IRQ); \ - sd_ctrl_write32((host), CTL_IRQ_MASK, mask); \ - } while (0) - -#define ack_mmc_irqs(host, i) \ - do { \ - sd_ctrl_write32((host), CTL_STATUS, ~(i)); \ - } while (0) - -/* This is arbitrary, just noone needed any higher alignment yet */ -#define MAX_ALIGN 4 - -struct tmio_mmc_host { - void __iomem *ctl; - unsigned long bus_shift; - struct mmc_command *cmd; - struct mmc_request *mrq; - struct mmc_data *data; - struct mmc_host *mmc; - int irq; - unsigned int sdio_irq_enabled; - - /* Callbacks for clock / power control */ - void (*set_pwr)(struct platform_device *host, int state); - void (*set_clk_div)(struct platform_device *host, int state); - - /* pio related stuff */ - struct scatterlist *sg_ptr; - struct scatterlist *sg_orig; - unsigned int sg_len; - unsigned int sg_off; - - struct platform_device *pdev; - - /* DMA support */ - bool force_pio; - struct dma_chan *chan_rx; - struct dma_chan *chan_tx; - struct tasklet_struct dma_complete; - struct tasklet_struct dma_issue; -#ifdef CONFIG_TMIO_MMC_DMA - u8 bounce_buf[PAGE_CACHE_SIZE] __attribute__((aligned(MAX_ALIGN))); - struct scatterlist bounce_sg; -#endif - - /* Track lost interrupts */ - struct delayed_work delayed_reset_work; - spinlock_t lock; - unsigned long last_req_ts; -}; - -static void tmio_check_bounce_buffer(struct tmio_mmc_host *host); - -static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) -{ - return readw(host->ctl + (addr << host->bus_shift)); -} - -static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, - u16 *buf, int count) -{ - readsw(host->ctl + (addr << host->bus_shift), buf, count); -} - -static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) -{ - return readw(host->ctl + (addr << host->bus_shift)) | - readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; -} - -static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) -{ - writew(val, host->ctl + (addr << host->bus_shift)); -} - -static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, - u16 *buf, int count) -{ - writesw(host->ctl + (addr << host->bus_shift), buf, count); -} - -static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) -{ - writew(val, host->ctl + (addr << host->bus_shift)); - writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); -} - -static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) -{ - host->sg_len = data->sg_len; - host->sg_ptr = data->sg; - host->sg_orig = data->sg; - host->sg_off = 0; -} - -static int tmio_mmc_next_sg(struct tmio_mmc_host *host) -{ - host->sg_ptr = sg_next(host->sg_ptr); - host->sg_off = 0; - return --host->sg_len; -} - -static char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) -{ - local_irq_save(*flags); - return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; -} - -static void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) -{ - kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); - local_irq_restore(*flags); -} - -#ifdef CONFIG_MMC_DEBUG - -#define STATUS_TO_TEXT(a, status, i) \ - do { \ - if (status & TMIO_STAT_##a) { \ - if (i++) \ - printk(" | "); \ - printk(#a); \ - } \ - } while (0) - -void pr_debug_status(u32 status) -{ - int i = 0; - printk(KERN_DEBUG "status: %08x = ", status); - STATUS_TO_TEXT(CARD_REMOVE, status, i); - STATUS_TO_TEXT(CARD_INSERT, status, i); - STATUS_TO_TEXT(SIGSTATE, status, i); - STATUS_TO_TEXT(WRPROTECT, status, i); - STATUS_TO_TEXT(CARD_REMOVE_A, status, i); - STATUS_TO_TEXT(CARD_INSERT_A, status, i); - STATUS_TO_TEXT(SIGSTATE_A, status, i); - STATUS_TO_TEXT(CMD_IDX_ERR, status, i); - STATUS_TO_TEXT(STOPBIT_ERR, status, i); - STATUS_TO_TEXT(ILL_FUNC, status, i); - STATUS_TO_TEXT(CMD_BUSY, status, i); - STATUS_TO_TEXT(CMDRESPEND, status, i); - STATUS_TO_TEXT(DATAEND, status, i); - STATUS_TO_TEXT(CRCFAIL, status, i); - STATUS_TO_TEXT(DATATIMEOUT, status, i); - STATUS_TO_TEXT(CMDTIMEOUT, status, i); - STATUS_TO_TEXT(RXOVERFLOW, status, i); - STATUS_TO_TEXT(TXUNDERRUN, status, i); - STATUS_TO_TEXT(RXRDY, status, i); - STATUS_TO_TEXT(TXRQ, status, i); - STATUS_TO_TEXT(ILL_ACCESS, status, i); - printk("\n"); -} - -#else -#define pr_debug_status(s) do { } while (0) -#endif - -static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - - if (enable) { - host->sdio_irq_enabled = 1; - sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, - (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); - } else { - sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); - sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); - host->sdio_irq_enabled = 0; - } -} - -static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) -{ - u32 clk = 0, clock; - - if (new_clock) { - for (clock = host->mmc->f_min, clk = 0x80000080; - new_clock >= (clock<<1); clk >>= 1) - clock <<= 1; - clk |= 0x100; - } - - if (host->set_clk_div) - host->set_clk_div(host->pdev, (clk>>22) & 1); - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); -} - -static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) -{ - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - - /* - * Testing on sh-mobile showed that SDIO IRQs are unmasked when - * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the - * device IRQ here and restore the SDIO IRQ mask before - * re-enabling the device IRQ. - */ - if (pdata->flags & TMIO_MMC_SDIO_IRQ) - disable_irq(host->irq); - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); - msleep(10); - if (pdata->flags & TMIO_MMC_SDIO_IRQ) { - tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); - enable_irq(host->irq); - } - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(10); -} - -static void tmio_mmc_clk_start(struct tmio_mmc_host *host) -{ - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(10); - /* see comment in tmio_mmc_clk_stop above */ - if (pdata->flags & TMIO_MMC_SDIO_IRQ) - disable_irq(host->irq); - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); - msleep(10); - if (pdata->flags & TMIO_MMC_SDIO_IRQ) { - tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); - enable_irq(host->irq); - } -} - -static void reset(struct tmio_mmc_host *host) -{ - /* FIXME - should we set stop clock reg here */ - sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); - msleep(10); - sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); - msleep(10); -} - -static void tmio_mmc_reset_work(struct work_struct *work) -{ - struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, - delayed_reset_work.work); - struct mmc_request *mrq; - unsigned long flags; - - spin_lock_irqsave(&host->lock, flags); - mrq = host->mrq; - - /* request already finished */ - if (!mrq - || time_is_after_jiffies(host->last_req_ts + - msecs_to_jiffies(2000))) { - spin_unlock_irqrestore(&host->lock, flags); - return; - } - - dev_warn(&host->pdev->dev, - "timeout waiting for hardware interrupt (CMD%u)\n", - mrq->cmd->opcode); - - if (host->data) - host->data->error = -ETIMEDOUT; - else if (host->cmd) - host->cmd->error = -ETIMEDOUT; - else - mrq->cmd->error = -ETIMEDOUT; - - host->cmd = NULL; - host->data = NULL; - host->mrq = NULL; - host->force_pio = false; - - spin_unlock_irqrestore(&host->lock, flags); - reset(host); - - mmc_request_done(host->mmc, mrq); -} - -static void -tmio_mmc_finish_request(struct tmio_mmc_host *host) -{ - struct mmc_request *mrq = host->mrq; - - if (!mrq) - return; - - host->mrq = NULL; - host->cmd = NULL; - host->data = NULL; - host->force_pio = false; - - cancel_delayed_work(&host->delayed_reset_work); - - mmc_request_done(host->mmc, mrq); -} - -/* These are the bitmasks the tmio chip requires to implement the MMC response - * types. Note that R1 and R6 are the same in this scheme. */ -#define APP_CMD 0x0040 -#define RESP_NONE 0x0300 -#define RESP_R1 0x0400 -#define RESP_R1B 0x0500 -#define RESP_R2 0x0600 -#define RESP_R3 0x0700 -#define DATA_PRESENT 0x0800 -#define TRANSFER_READ 0x1000 -#define TRANSFER_MULTI 0x2000 -#define SECURITY_CMD 0x4000 - -static int -tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) -{ - struct mmc_data *data = host->data; - int c = cmd->opcode; - - /* Command 12 is handled by hardware */ - if (cmd->opcode == 12 && !cmd->arg) { - sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); - return 0; - } - - switch (mmc_resp_type(cmd)) { - case MMC_RSP_NONE: c |= RESP_NONE; break; - case MMC_RSP_R1: c |= RESP_R1; break; - case MMC_RSP_R1B: c |= RESP_R1B; break; - case MMC_RSP_R2: c |= RESP_R2; break; - case MMC_RSP_R3: c |= RESP_R3; break; - default: - pr_debug("Unknown response type %d\n", mmc_resp_type(cmd)); - return -EINVAL; - } - - host->cmd = cmd; - -/* FIXME - this seems to be ok commented out but the spec suggest this bit - * should be set when issuing app commands. - * if(cmd->flags & MMC_FLAG_ACMD) - * c |= APP_CMD; - */ - if (data) { - c |= DATA_PRESENT; - if (data->blocks > 1) { - sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100); - c |= TRANSFER_MULTI; - } - if (data->flags & MMC_DATA_READ) - c |= TRANSFER_READ; - } - - enable_mmc_irqs(host, TMIO_MASK_CMD); - - /* Fire off the command */ - sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); - sd_ctrl_write16(host, CTL_SD_CMD, c); - - return 0; -} - -/* - * This chip always returns (at least?) as much data as you ask for. - * I'm unsure what happens if you ask for less than a block. This should be - * looked into to ensure that a funny length read doesnt hose the controller. - */ -static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) -{ - struct mmc_data *data = host->data; - void *sg_virt; - unsigned short *buf; - unsigned int count; - unsigned long flags; - - if ((host->chan_tx || host->chan_rx) && !host->force_pio) { - pr_err("PIO IRQ in DMA mode!\n"); - return; - } else if (!data) { - pr_debug("Spurious PIO IRQ\n"); - return; - } - - sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); - buf = (unsigned short *)(sg_virt + host->sg_off); - - count = host->sg_ptr->length - host->sg_off; - if (count > data->blksz) - count = data->blksz; - - pr_debug("count: %08x offset: %08x flags %08x\n", - count, host->sg_off, data->flags); - - /* Transfer the data */ - if (data->flags & MMC_DATA_READ) - sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); - else - sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); - - host->sg_off += count; - - tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt); - - if (host->sg_off == host->sg_ptr->length) - tmio_mmc_next_sg(host); - - return; -} - -/* needs to be called with host->lock held */ -static void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) -{ - struct mmc_data *data = host->data; - struct mmc_command *stop; - - host->data = NULL; - - if (!data) { - dev_warn(&host->pdev->dev, "Spurious data end IRQ\n"); - return; - } - stop = data->stop; - - /* FIXME - return correct transfer count on errors */ - if (!data->error) - data->bytes_xfered = data->blocks * data->blksz; - else - data->bytes_xfered = 0; - - pr_debug("Completed data request\n"); - - /* - * FIXME: other drivers allow an optional stop command of any given type - * which we dont do, as the chip can auto generate them. - * Perhaps we can be smarter about when to use auto CMD12 and - * only issue the auto request when we know this is the desired - * stop command, allowing fallback to the stop command the - * upper layers expect. For now, we do what works. - */ - - if (data->flags & MMC_DATA_READ) { - if (host->chan_rx && !host->force_pio) - tmio_check_bounce_buffer(host); - dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", - host->mrq); - } else { - dev_dbg(&host->pdev->dev, "Complete Tx request %p\n", - host->mrq); - } - - if (stop) { - if (stop->opcode == 12 && !stop->arg) - sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); - else - BUG(); - } - - tmio_mmc_finish_request(host); -} - -static void tmio_mmc_data_irq(struct tmio_mmc_host *host) -{ - struct mmc_data *data; - spin_lock(&host->lock); - data = host->data; - - if (!data) - goto out; - - if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) { - /* - * Has all data been written out yet? Testing on SuperH showed, - * that in most cases the first interrupt comes already with the - * BUSY status bit clear, but on some operations, like mount or - * in the beginning of a write / sync / umount, there is one - * DATAEND interrupt with the BUSY bit set, in this cases - * waiting for one more interrupt fixes the problem. - */ - if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) { - disable_mmc_irqs(host, TMIO_STAT_DATAEND); - tasklet_schedule(&host->dma_complete); - } - } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) { - disable_mmc_irqs(host, TMIO_STAT_DATAEND); - tasklet_schedule(&host->dma_complete); - } else { - tmio_mmc_do_data_irq(host); - disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP); - } -out: - spin_unlock(&host->lock); -} - -static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, - unsigned int stat) -{ - struct mmc_command *cmd = host->cmd; - int i, addr; - - spin_lock(&host->lock); - - if (!host->cmd) { - pr_debug("Spurious CMD irq\n"); - goto out; - } - - host->cmd = NULL; - - /* This controller is sicker than the PXA one. Not only do we need to - * drop the top 8 bits of the first response word, we also need to - * modify the order of the response for short response command types. - */ - - for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4) - cmd->resp[i] = sd_ctrl_read32(host, addr); - - if (cmd->flags & MMC_RSP_136) { - cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); - cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24); - cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24); - cmd->resp[3] <<= 8; - } else if (cmd->flags & MMC_RSP_R3) { - cmd->resp[0] = cmd->resp[3]; - } - - if (stat & TMIO_STAT_CMDTIMEOUT) - cmd->error = -ETIMEDOUT; - else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) - cmd->error = -EILSEQ; - - /* If there is data to handle we enable data IRQs here, and - * we will ultimatley finish the request in the data_end handler. - * If theres no data or we encountered an error, finish now. - */ - if (host->data && !cmd->error) { - if (host->data->flags & MMC_DATA_READ) { - if (host->force_pio || !host->chan_rx) - enable_mmc_irqs(host, TMIO_MASK_READOP); - else - tasklet_schedule(&host->dma_issue); - } else { - if (host->force_pio || !host->chan_tx) - enable_mmc_irqs(host, TMIO_MASK_WRITEOP); - else - tasklet_schedule(&host->dma_issue); - } - } else { - tmio_mmc_finish_request(host); - } - -out: - spin_unlock(&host->lock); - - return; -} - -static irqreturn_t tmio_mmc_irq(int irq, void *devid) -{ - struct tmio_mmc_host *host = devid; - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - unsigned int ireg, irq_mask, status; - unsigned int sdio_ireg, sdio_irq_mask, sdio_status; - - pr_debug("MMC IRQ begin\n"); - - status = sd_ctrl_read32(host, CTL_STATUS); - irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); - ireg = status & TMIO_MASK_IRQ & ~irq_mask; - - sdio_ireg = 0; - if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { - sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); - sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); - sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; - - sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); - - if (sdio_ireg && !host->sdio_irq_enabled) { - pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", - sdio_status, sdio_irq_mask, sdio_ireg); - tmio_mmc_enable_sdio_irq(host->mmc, 0); - goto out; - } - - if (host->mmc->caps & MMC_CAP_SDIO_IRQ && - sdio_ireg & TMIO_SDIO_STAT_IOIRQ) - mmc_signal_sdio_irq(host->mmc); - - if (sdio_ireg) - goto out; - } - - pr_debug_status(status); - pr_debug_status(ireg); - - if (!ireg) { - disable_mmc_irqs(host, status & ~irq_mask); - - pr_warning("tmio_mmc: Spurious irq, disabling! " - "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); - pr_debug_status(status); - - goto out; - } - - while (ireg) { - /* Card insert / remove attempts */ - if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { - ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | - TMIO_STAT_CARD_REMOVE); - mmc_detect_change(host->mmc, msecs_to_jiffies(100)); - } - - /* CRC and other errors */ -/* if (ireg & TMIO_STAT_ERR_IRQ) - * handled |= tmio_error_irq(host, irq, stat); - */ - - /* Command completion */ - if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { - ack_mmc_irqs(host, - TMIO_STAT_CMDRESPEND | - TMIO_STAT_CMDTIMEOUT); - tmio_mmc_cmd_irq(host, status); - } - - /* Data transfer */ - if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { - ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); - tmio_mmc_pio_irq(host); - } - - /* Data transfer completion */ - if (ireg & TMIO_STAT_DATAEND) { - ack_mmc_irqs(host, TMIO_STAT_DATAEND); - tmio_mmc_data_irq(host); - } - - /* Check status - keep going until we've handled it all */ - status = sd_ctrl_read32(host, CTL_STATUS); - irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); - ireg = status & TMIO_MASK_IRQ & ~irq_mask; - - pr_debug("Status at end of loop: %08x\n", status); - pr_debug_status(status); - } - pr_debug("MMC IRQ end\n"); - -out: - return IRQ_HANDLED; -} - -#ifdef CONFIG_TMIO_MMC_DMA -static void tmio_check_bounce_buffer(struct tmio_mmc_host *host) -{ - if (host->sg_ptr == &host->bounce_sg) { - unsigned long flags; - void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); - memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); - } -} - -static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) -{ -#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE) - /* Switch DMA mode on or off - SuperH specific? */ - sd_ctrl_write16(host, 0xd8, enable ? 2 : 0); -#endif -} - -static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) -{ - struct scatterlist *sg = host->sg_ptr, *sg_tmp; - struct dma_async_tx_descriptor *desc = NULL; - struct dma_chan *chan = host->chan_rx; - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - dma_cookie_t cookie; - int ret, i; - bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; - - for_each_sg(sg, sg_tmp, host->sg_len, i) { - if (sg_tmp->offset & align) - aligned = false; - if (sg_tmp->length & align) { - multiple = false; - break; - } - } - - if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || - align >= MAX_ALIGN)) || !multiple) { - ret = -EINVAL; - goto pio; - } - - if (sg->length < TMIO_MIN_DMA_LEN) { - host->force_pio = true; - return; - } - - disable_mmc_irqs(host, TMIO_STAT_RXRDY); - - /* The only sg element can be unaligned, use our bounce buffer then */ - if (!aligned) { - sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); - host->sg_ptr = &host->bounce_sg; - sg = host->sg_ptr; - } - - ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); - if (ret > 0) - desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_FROM_DEVICE, DMA_CTRL_ACK); - - if (desc) - cookie = dmaengine_submit(desc); - - dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, cookie, host->mrq); - -pio: - if (!desc) { - /* DMA failed, fall back to PIO */ - if (ret >= 0) - ret = -EIO; - host->chan_rx = NULL; - dma_release_channel(chan); - /* Free the Tx channel too */ - chan = host->chan_tx; - if (chan) { - host->chan_tx = NULL; - dma_release_channel(chan); - } - dev_warn(&host->pdev->dev, - "DMA failed: %d, falling back to PIO\n", ret); - tmio_mmc_enable_dma(host, false); - } - - dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, - desc, cookie, host->sg_len); -} - -static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) -{ - struct scatterlist *sg = host->sg_ptr, *sg_tmp; - struct dma_async_tx_descriptor *desc = NULL; - struct dma_chan *chan = host->chan_tx; - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - dma_cookie_t cookie; - int ret, i; - bool aligned = true, multiple = true; - unsigned int align = (1 << pdata->dma->alignment_shift) - 1; - - for_each_sg(sg, sg_tmp, host->sg_len, i) { - if (sg_tmp->offset & align) - aligned = false; - if (sg_tmp->length & align) { - multiple = false; - break; - } - } - - if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || - align >= MAX_ALIGN)) || !multiple) { - ret = -EINVAL; - goto pio; - } - - if (sg->length < TMIO_MIN_DMA_LEN) { - host->force_pio = true; - return; - } - - disable_mmc_irqs(host, TMIO_STAT_TXRQ); - - /* The only sg element can be unaligned, use our bounce buffer then */ - if (!aligned) { - unsigned long flags; - void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); - sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); - memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); - tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); - host->sg_ptr = &host->bounce_sg; - sg = host->sg_ptr; - } - - ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); - if (ret > 0) - desc = chan->device->device_prep_slave_sg(chan, sg, ret, - DMA_TO_DEVICE, DMA_CTRL_ACK); - - if (desc) - cookie = dmaengine_submit(desc); - - dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", - __func__, host->sg_len, ret, cookie, host->mrq); - -pio: - if (!desc) { - /* DMA failed, fall back to PIO */ - if (ret >= 0) - ret = -EIO; - host->chan_tx = NULL; - dma_release_channel(chan); - /* Free the Rx channel too */ - chan = host->chan_rx; - if (chan) { - host->chan_rx = NULL; - dma_release_channel(chan); - } - dev_warn(&host->pdev->dev, - "DMA failed: %d, falling back to PIO\n", ret); - tmio_mmc_enable_dma(host, false); - } - - dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__, - desc, cookie); -} - -static void tmio_mmc_start_dma(struct tmio_mmc_host *host, - struct mmc_data *data) -{ - if (data->flags & MMC_DATA_READ) { - if (host->chan_rx) - tmio_mmc_start_dma_rx(host); - } else { - if (host->chan_tx) - tmio_mmc_start_dma_tx(host); - } -} - -static void tmio_issue_tasklet_fn(unsigned long priv) -{ - struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; - struct dma_chan *chan = NULL; - - spin_lock_irq(&host->lock); - - if (host && host->data) { - if (host->data->flags & MMC_DATA_READ) - chan = host->chan_rx; - else - chan = host->chan_tx; - } - - spin_unlock_irq(&host->lock); - - enable_mmc_irqs(host, TMIO_STAT_DATAEND); - - if (chan) - dma_async_issue_pending(chan); -} - -static void tmio_tasklet_fn(unsigned long arg) -{ - struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; - - spin_lock_irq(&host->lock); - - if (!host->data) - goto out; - - if (host->data->flags & MMC_DATA_READ) - dma_unmap_sg(host->chan_rx->device->dev, - host->sg_ptr, host->sg_len, - DMA_FROM_DEVICE); - else - dma_unmap_sg(host->chan_tx->device->dev, - host->sg_ptr, host->sg_len, - DMA_TO_DEVICE); - - tmio_mmc_do_data_irq(host); -out: - spin_unlock_irq(&host->lock); -} - -/* It might be necessary to make filter MFD specific */ -static bool tmio_mmc_filter(struct dma_chan *chan, void *arg) -{ - dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); - chan->private = arg; - return true; -} - -static void tmio_mmc_request_dma(struct tmio_mmc_host *host, - struct tmio_mmc_data *pdata) -{ - /* We can only either use DMA for both Tx and Rx or not use it at all */ - if (pdata->dma) { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->chan_tx = dma_request_channel(mask, tmio_mmc_filter, - pdata->dma->chan_priv_tx); - dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, - host->chan_tx); - - if (!host->chan_tx) - return; - - host->chan_rx = dma_request_channel(mask, tmio_mmc_filter, - pdata->dma->chan_priv_rx); - dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, - host->chan_rx); - - if (!host->chan_rx) { - dma_release_channel(host->chan_tx); - host->chan_tx = NULL; - return; - } - - tasklet_init(&host->dma_complete, tmio_tasklet_fn, (unsigned long)host); - tasklet_init(&host->dma_issue, tmio_issue_tasklet_fn, (unsigned long)host); - - tmio_mmc_enable_dma(host, true); - } -} - -static void tmio_mmc_release_dma(struct tmio_mmc_host *host) -{ - if (host->chan_tx) { - struct dma_chan *chan = host->chan_tx; - host->chan_tx = NULL; - dma_release_channel(chan); - } - if (host->chan_rx) { - struct dma_chan *chan = host->chan_rx; - host->chan_rx = NULL; - dma_release_channel(chan); - } -} -#else -static void tmio_check_bounce_buffer(struct tmio_mmc_host *host) -{ -} - -static void tmio_mmc_start_dma(struct tmio_mmc_host *host, - struct mmc_data *data) -{ -} - -static void tmio_mmc_request_dma(struct tmio_mmc_host *host, - struct tmio_mmc_data *pdata) -{ - host->chan_tx = NULL; - host->chan_rx = NULL; -} - -static void tmio_mmc_release_dma(struct tmio_mmc_host *host) -{ -} -#endif - -static int tmio_mmc_start_data(struct tmio_mmc_host *host, - struct mmc_data *data) -{ - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - - pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", - data->blksz, data->blocks); - - /* Some hardware cannot perform 2 byte requests in 4 bit mode */ - if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { - int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES; - - if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) { - pr_err("%s: %d byte block unsupported in 4 bit mode\n", - mmc_hostname(host->mmc), data->blksz); - return -EINVAL; - } - } - - tmio_mmc_init_sg(host, data); - host->data = data; - - /* Set transfer length / blocksize */ - sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); - sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); - - tmio_mmc_start_dma(host, data); - - return 0; -} - -/* Process requests from the MMC layer */ -static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - int ret; - - if (host->mrq) - pr_debug("request not null\n"); - - host->last_req_ts = jiffies; - wmb(); - host->mrq = mrq; - - if (mrq->data) { - ret = tmio_mmc_start_data(host, mrq->data); - if (ret) - goto fail; - } - - ret = tmio_mmc_start_command(host, mrq->cmd); - if (!ret) { - schedule_delayed_work(&host->delayed_reset_work, - msecs_to_jiffies(2000)); - return; - } - -fail: - host->mrq = NULL; - host->force_pio = false; - mrq->cmd->error = ret; - mmc_request_done(mmc, mrq); -} - -/* Set MMC clock / power. - * Note: This controller uses a simple divider scheme therefore it cannot - * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as - * MMC wont run that fast, it has to be clocked at 12MHz which is the next - * slowest setting. - */ -static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - - if (ios->clock) - tmio_mmc_set_clock(host, ios->clock); - - /* Power sequence - OFF -> ON -> UP */ - switch (ios->power_mode) { - case MMC_POWER_OFF: /* power down SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 0); - tmio_mmc_clk_stop(host); - break; - case MMC_POWER_ON: /* power up SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 1); - break; - case MMC_POWER_UP: /* start bus clock */ - tmio_mmc_clk_start(host); - break; - } - - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); - break; - case MMC_BUS_WIDTH_4: - sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); - break; - } - - /* Let things settle. delay taken from winCE driver */ - udelay(140); -} - -static int tmio_mmc_get_ro(struct mmc_host *mmc) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - - return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || - (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)) ? 0 : 1; -} - -static int tmio_mmc_get_cd(struct mmc_host *mmc) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = mfd_get_data(host->pdev); - - if (!pdata->get_cd) - return -ENOSYS; - else - return pdata->get_cd(host->pdev); -} - -static const struct mmc_host_ops tmio_mmc_ops = { - .request = tmio_mmc_request, - .set_ios = tmio_mmc_set_ios, - .get_ro = tmio_mmc_get_ro, - .get_cd = tmio_mmc_get_cd, - .enable_sdio_irq = tmio_mmc_enable_sdio_irq, -}; +#include "tmio_mmc.h" #ifdef CONFIG_PM static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) @@ -1245,138 +62,54 @@ out: #define tmio_mmc_resume NULL #endif -static int __devinit tmio_mmc_probe(struct platform_device *dev) +static int __devinit tmio_mmc_probe(struct platform_device *pdev) { - const struct mfd_cell *cell = mfd_get_cell(dev); + const struct mfd_cell *cell = mfd_get_cell(pdev); struct tmio_mmc_data *pdata; - struct resource *res_ctl; struct tmio_mmc_host *host; - struct mmc_host *mmc; int ret = -EINVAL; - u32 irq_mask = TMIO_MASK_CMD; - if (dev->num_resources != 2) + if (pdev->num_resources != 2) goto out; - res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res_ctl) - goto out; - - pdata = mfd_get_data(dev); + pdata = mfd_get_data(pdev); if (!pdata || !pdata->hclk) goto out; - ret = -ENOMEM; - - mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev); - if (!mmc) - goto out; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->pdev = dev; - platform_set_drvdata(dev, mmc); - - host->set_pwr = pdata->set_pwr; - host->set_clk_div = pdata->set_clk_div; - - /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ - host->bus_shift = resource_size(res_ctl) >> 10; - - host->ctl = ioremap(res_ctl->start, resource_size(res_ctl)); - if (!host->ctl) - goto host_free; - - mmc->ops = &tmio_mmc_ops; - mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; - mmc->f_max = pdata->hclk; - mmc->f_min = mmc->f_max / 512; - mmc->max_segs = 32; - mmc->max_blk_size = 512; - mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * - mmc->max_segs; - mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; - mmc->max_seg_size = mmc->max_req_size; - if (pdata->ocr_mask) - mmc->ocr_avail = pdata->ocr_mask; - else - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - /* Tell the MFD core we are ready to be enabled */ if (cell->enable) { - ret = cell->enable(dev); + ret = cell->enable(pdev); if (ret) - goto unmap_ctl; + goto out; } - tmio_mmc_clk_stop(host); - reset(host); - - ret = platform_get_irq(dev, 0); - if (ret >= 0) - host->irq = ret; - else - goto cell_disable; - - disable_mmc_irqs(host, TMIO_MASK_ALL); - if (pdata->flags & TMIO_MMC_SDIO_IRQ) - tmio_mmc_enable_sdio_irq(mmc, 0); - - ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | - IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); + ret = tmio_mmc_host_probe(&host, pdev, pdata); if (ret) goto cell_disable; - spin_lock_init(&host->lock); - - /* Init delayed work for request timeouts */ - INIT_DELAYED_WORK(&host->delayed_reset_work, tmio_mmc_reset_work); - - /* See if we also get DMA */ - tmio_mmc_request_dma(host, pdata); - - mmc_add_host(mmc); - pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), (unsigned long)host->ctl, host->irq); - /* Unmask the IRQs we want to know about */ - if (!host->chan_rx) - irq_mask |= TMIO_MASK_READOP; - if (!host->chan_tx) - irq_mask |= TMIO_MASK_WRITEOP; - enable_mmc_irqs(host, irq_mask); - return 0; cell_disable: if (cell->disable) - cell->disable(dev); -unmap_ctl: - iounmap(host->ctl); -host_free: - mmc_free_host(mmc); + cell->disable(pdev); out: return ret; } -static int __devexit tmio_mmc_remove(struct platform_device *dev) +static int __devexit tmio_mmc_remove(struct platform_device *pdev) { - const struct mfd_cell *cell = mfd_get_cell(dev); - struct mmc_host *mmc = platform_get_drvdata(dev); + const struct mfd_cell *cell = mfd_get_cell(pdev); + struct mmc_host *mmc = platform_get_drvdata(pdev); - platform_set_drvdata(dev, NULL); + platform_set_drvdata(pdev, NULL); if (mmc) { - struct tmio_mmc_host *host = mmc_priv(mmc); - mmc_remove_host(mmc); - cancel_delayed_work_sync(&host->delayed_reset_work); - tmio_mmc_release_dma(host); - free_irq(host->irq, host); + tmio_mmc_host_remove(mmc_priv(mmc)); if (cell->disable) - cell->disable(dev); - iounmap(host->ctl); - mmc_free_host(mmc); + cell->disable(pdev); } return 0; diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h new file mode 100644 index 000000000000..8dedf0a69348 --- /dev/null +++ b/drivers/mmc/host/tmio_mmc.h @@ -0,0 +1,145 @@ +/* + * linux/drivers/mmc/host/tmio_mmc.h + * + * Copyright (C) 2007 Ian Molton + * Copyright (C) 2004 Ian Molton + * + * 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. + * + * Driver for the MMC / SD / SDIO cell found in: + * + * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 + */ + +#ifndef TMIO_MMC_H +#define TMIO_MMC_H + +#include +#include + +/* Definitions for values the CTRL_STATUS register can take. */ +#define TMIO_STAT_CMDRESPEND 0x00000001 +#define TMIO_STAT_DATAEND 0x00000004 +#define TMIO_STAT_CARD_REMOVE 0x00000008 +#define TMIO_STAT_CARD_INSERT 0x00000010 +#define TMIO_STAT_SIGSTATE 0x00000020 +#define TMIO_STAT_WRPROTECT 0x00000080 +#define TMIO_STAT_CARD_REMOVE_A 0x00000100 +#define TMIO_STAT_CARD_INSERT_A 0x00000200 +#define TMIO_STAT_SIGSTATE_A 0x00000400 +#define TMIO_STAT_CMD_IDX_ERR 0x00010000 +#define TMIO_STAT_CRCFAIL 0x00020000 +#define TMIO_STAT_STOPBIT_ERR 0x00040000 +#define TMIO_STAT_DATATIMEOUT 0x00080000 +#define TMIO_STAT_RXOVERFLOW 0x00100000 +#define TMIO_STAT_TXUNDERRUN 0x00200000 +#define TMIO_STAT_CMDTIMEOUT 0x00400000 +#define TMIO_STAT_RXRDY 0x01000000 +#define TMIO_STAT_TXRQ 0x02000000 +#define TMIO_STAT_ILL_FUNC 0x20000000 +#define TMIO_STAT_CMD_BUSY 0x40000000 +#define TMIO_STAT_ILL_ACCESS 0x80000000 + +/* Definitions for values the CTRL_SDIO_STATUS register can take. */ +#define TMIO_SDIO_STAT_IOIRQ 0x0001 +#define TMIO_SDIO_STAT_EXPUB52 0x4000 +#define TMIO_SDIO_STAT_EXWT 0x8000 +#define TMIO_SDIO_MASK_ALL 0xc007 + +/* Define some IRQ masks */ +/* This is the mask used at reset by the chip */ +#define TMIO_MASK_ALL 0x837f031d +#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND) +#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND) +#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \ + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT) +#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD) + +struct tmio_mmc_data; + +struct tmio_mmc_host { + void __iomem *ctl; + unsigned long bus_shift; + struct mmc_command *cmd; + struct mmc_request *mrq; + struct mmc_data *data; + struct mmc_host *mmc; + int irq; + unsigned int sdio_irq_enabled; + + /* Callbacks for clock / power control */ + void (*set_pwr)(struct platform_device *host, int state); + void (*set_clk_div)(struct platform_device *host, int state); + + /* pio related stuff */ + struct scatterlist *sg_ptr; + struct scatterlist *sg_orig; + unsigned int sg_len; + unsigned int sg_off; + + struct platform_device *pdev; + struct tmio_mmc_data *pdata; + + /* DMA support */ + bool force_pio; + struct dma_chan *chan_rx; + struct dma_chan *chan_tx; + struct tasklet_struct dma_complete; + struct tasklet_struct dma_issue; + struct scatterlist bounce_sg; + u8 *bounce_buf; + + /* Track lost interrupts */ + struct delayed_work delayed_reset_work; + spinlock_t lock; + unsigned long last_req_ts; +}; + +int tmio_mmc_host_probe(struct tmio_mmc_host **host, + struct platform_device *pdev, + struct tmio_mmc_data *pdata); +void tmio_mmc_host_remove(struct tmio_mmc_host *host); +void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); + +void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); +void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); + +static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, + unsigned long *flags) +{ + local_irq_save(*flags); + return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset; +} + +static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, + unsigned long *flags, void *virt) +{ + kunmap_atomic(virt - sg->offset, KM_BIO_SRC_IRQ); + local_irq_restore(*flags); +} + +#ifdef CONFIG_TMIO_MMC_DMA +void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); +void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); +void tmio_mmc_release_dma(struct tmio_mmc_host *host); +#else +static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host, + struct mmc_data *data) +{ +} + +static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host, + struct tmio_mmc_data *pdata) +{ + host->chan_tx = NULL; + host->chan_rx = NULL; +} + +static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host) +{ +} +#endif + +#endif diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c new file mode 100644 index 000000000000..c505278be43f --- /dev/null +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -0,0 +1,316 @@ +/* + * linux/drivers/mmc/tmio_mmc_dma.c + * + * Copyright (C) 2010-2011 Guennadi Liakhovetski + * + * 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. + * + * DMA function for TMIO MMC implementations + */ + +#include +#include +#include +#include +#include +#include + +#include "tmio_mmc.h" + +#define TMIO_MMC_MIN_DMA_LEN 8 + +static void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable) +{ +#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE) + /* Switch DMA mode on or off - SuperH specific? */ + writew(enable ? 2 : 0, host->ctl + (0xd8 << host->bus_shift)); +#endif +} + +static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) +{ + struct scatterlist *sg = host->sg_ptr, *sg_tmp; + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *chan = host->chan_rx; + struct tmio_mmc_data *pdata = host->pdata; + dma_cookie_t cookie; + int ret, i; + bool aligned = true, multiple = true; + unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + + for_each_sg(sg, sg_tmp, host->sg_len, i) { + if (sg_tmp->offset & align) + aligned = false; + if (sg_tmp->length & align) { + multiple = false; + break; + } + } + + if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || + (align & PAGE_MASK))) || !multiple) { + ret = -EINVAL; + goto pio; + } + + if (sg->length < TMIO_MMC_MIN_DMA_LEN) { + host->force_pio = true; + return; + } + + tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY); + + /* The only sg element can be unaligned, use our bounce buffer then */ + if (!aligned) { + sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); + host->sg_ptr = &host->bounce_sg; + sg = host->sg_ptr; + } + + ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE); + if (ret > 0) + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_FROM_DEVICE, DMA_CTRL_ACK); + + if (desc) { + cookie = dmaengine_submit(desc); + if (cookie < 0) { + desc = NULL; + ret = cookie; + } + } + dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", + __func__, host->sg_len, ret, cookie, host->mrq); + +pio: + if (!desc) { + /* DMA failed, fall back to PIO */ + if (ret >= 0) + ret = -EIO; + host->chan_rx = NULL; + dma_release_channel(chan); + /* Free the Tx channel too */ + chan = host->chan_tx; + if (chan) { + host->chan_tx = NULL; + dma_release_channel(chan); + } + dev_warn(&host->pdev->dev, + "DMA failed: %d, falling back to PIO\n", ret); + tmio_mmc_enable_dma(host, false); + } + + dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, + desc, cookie, host->sg_len); +} + +static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) +{ + struct scatterlist *sg = host->sg_ptr, *sg_tmp; + struct dma_async_tx_descriptor *desc = NULL; + struct dma_chan *chan = host->chan_tx; + struct tmio_mmc_data *pdata = host->pdata; + dma_cookie_t cookie; + int ret, i; + bool aligned = true, multiple = true; + unsigned int align = (1 << pdata->dma->alignment_shift) - 1; + + for_each_sg(sg, sg_tmp, host->sg_len, i) { + if (sg_tmp->offset & align) + aligned = false; + if (sg_tmp->length & align) { + multiple = false; + break; + } + } + + if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE || + (align & PAGE_MASK))) || !multiple) { + ret = -EINVAL; + goto pio; + } + + if (sg->length < TMIO_MMC_MIN_DMA_LEN) { + host->force_pio = true; + return; + } + + tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ); + + /* The only sg element can be unaligned, use our bounce buffer then */ + if (!aligned) { + unsigned long flags; + void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); + sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); + memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); + tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); + host->sg_ptr = &host->bounce_sg; + sg = host->sg_ptr; + } + + ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE); + if (ret > 0) + desc = chan->device->device_prep_slave_sg(chan, sg, ret, + DMA_TO_DEVICE, DMA_CTRL_ACK); + + if (desc) { + cookie = dmaengine_submit(desc); + if (cookie < 0) { + desc = NULL; + ret = cookie; + } + } + dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n", + __func__, host->sg_len, ret, cookie, host->mrq); + +pio: + if (!desc) { + /* DMA failed, fall back to PIO */ + if (ret >= 0) + ret = -EIO; + host->chan_tx = NULL; + dma_release_channel(chan); + /* Free the Rx channel too */ + chan = host->chan_rx; + if (chan) { + host->chan_rx = NULL; + dma_release_channel(chan); + } + dev_warn(&host->pdev->dev, + "DMA failed: %d, falling back to PIO\n", ret); + tmio_mmc_enable_dma(host, false); + } + + dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__, + desc, cookie); +} + +void tmio_mmc_start_dma(struct tmio_mmc_host *host, + struct mmc_data *data) +{ + if (data->flags & MMC_DATA_READ) { + if (host->chan_rx) + tmio_mmc_start_dma_rx(host); + } else { + if (host->chan_tx) + tmio_mmc_start_dma_tx(host); + } +} + +static void tmio_mmc_issue_tasklet_fn(unsigned long priv) +{ + struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv; + struct dma_chan *chan = NULL; + + spin_lock_irq(&host->lock); + + if (host && host->data) { + if (host->data->flags & MMC_DATA_READ) + chan = host->chan_rx; + else + chan = host->chan_tx; + } + + spin_unlock_irq(&host->lock); + + tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND); + + if (chan) + dma_async_issue_pending(chan); +} + +static void tmio_mmc_tasklet_fn(unsigned long arg) +{ + struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg; + + spin_lock_irq(&host->lock); + + if (!host->data) + goto out; + + if (host->data->flags & MMC_DATA_READ) + dma_unmap_sg(host->chan_rx->device->dev, + host->sg_ptr, host->sg_len, + DMA_FROM_DEVICE); + else + dma_unmap_sg(host->chan_tx->device->dev, + host->sg_ptr, host->sg_len, + DMA_TO_DEVICE); + + tmio_mmc_do_data_irq(host); +out: + spin_unlock_irq(&host->lock); +} + +/* It might be necessary to make filter MFD specific */ +static bool tmio_mmc_filter(struct dma_chan *chan, void *arg) +{ + dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg); + chan->private = arg; + return true; +} + +void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata) +{ + /* We can only either use DMA for both Tx and Rx or not use it at all */ + if (pdata->dma) { + dma_cap_mask_t mask; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + host->chan_tx = dma_request_channel(mask, tmio_mmc_filter, + pdata->dma->chan_priv_tx); + dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__, + host->chan_tx); + + if (!host->chan_tx) + return; + + host->chan_rx = dma_request_channel(mask, tmio_mmc_filter, + pdata->dma->chan_priv_rx); + dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__, + host->chan_rx); + + if (!host->chan_rx) + goto ereqrx; + + host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA); + if (!host->bounce_buf) + goto ebouncebuf; + + tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host); + tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host); + + tmio_mmc_enable_dma(host, true); + + return; +ebouncebuf: + dma_release_channel(host->chan_rx); + host->chan_rx = NULL; +ereqrx: + dma_release_channel(host->chan_tx); + host->chan_tx = NULL; + return; + } +} + +void tmio_mmc_release_dma(struct tmio_mmc_host *host) +{ + if (host->chan_tx) { + struct dma_chan *chan = host->chan_tx; + host->chan_tx = NULL; + dma_release_channel(chan); + } + if (host->chan_rx) { + struct dma_chan *chan = host->chan_rx; + host->chan_rx = NULL; + dma_release_channel(chan); + } + if (host->bounce_buf) { + free_pages((unsigned long)host->bounce_buf, 0); + host->bounce_buf = NULL; + } +} diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c new file mode 100644 index 000000000000..a7406e3701c9 --- /dev/null +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -0,0 +1,923 @@ +/* + * linux/drivers/mmc/host/tmio_mmc_pio.c + * + * Copyright (C) 2011 Guennadi Liakhovetski + * Copyright (C) 2007 Ian Molton + * Copyright (C) 2004 Ian Molton + * + * 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. + * + * Driver for the MMC / SD / SDIO IP found in: + * + * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs + * + * This driver draws mainly on scattered spec sheets, Reverse engineering + * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit + * support). (Further 4 bit support from a later datasheet). + * + * TODO: + * Investigate using a workqueue for PIO transfers + * Eliminate FIXMEs + * SDIO support + * Better Power management + * Handle MMC errors better + * double buffer support + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tmio_mmc.h" + +#define CTL_SD_CMD 0x00 +#define CTL_ARG_REG 0x04 +#define CTL_STOP_INTERNAL_ACTION 0x08 +#define CTL_XFER_BLK_COUNT 0xa +#define CTL_RESPONSE 0x0c +#define CTL_STATUS 0x1c +#define CTL_IRQ_MASK 0x20 +#define CTL_SD_CARD_CLK_CTL 0x24 +#define CTL_SD_XFER_LEN 0x26 +#define CTL_SD_MEM_CARD_OPT 0x28 +#define CTL_SD_ERROR_DETAIL_STATUS 0x2c +#define CTL_SD_DATA_PORT 0x30 +#define CTL_TRANSACTION_CTL 0x34 +#define CTL_SDIO_STATUS 0x36 +#define CTL_SDIO_IRQ_MASK 0x38 +#define CTL_RESET_SD 0xe0 +#define CTL_SDIO_REGS 0x100 +#define CTL_CLK_AND_WAIT_CTL 0x138 +#define CTL_RESET_SDIO 0x1e0 + +static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) +{ + return readw(host->ctl + (addr << host->bus_shift)); +} + +static void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, + u16 *buf, int count) +{ + readsw(host->ctl + (addr << host->bus_shift), buf, count); +} + +static u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) +{ + return readw(host->ctl + (addr << host->bus_shift)) | + readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; +} + +static void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val) +{ + writew(val, host->ctl + (addr << host->bus_shift)); +} + +static void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, + u16 *buf, int count) +{ + writesw(host->ctl + (addr << host->bus_shift), buf, count); +} + +static void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) +{ + writew(val, host->ctl + (addr << host->bus_shift)); + writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); +} + +void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) +{ + u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) & ~(i & TMIO_MASK_IRQ); + sd_ctrl_write32(host, CTL_IRQ_MASK, mask); +} + +void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) +{ + u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) | (i & TMIO_MASK_IRQ); + sd_ctrl_write32(host, CTL_IRQ_MASK, mask); +} + +static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) +{ + sd_ctrl_write32(host, CTL_STATUS, ~i); +} + +static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) +{ + host->sg_len = data->sg_len; + host->sg_ptr = data->sg; + host->sg_orig = data->sg; + host->sg_off = 0; +} + +static int tmio_mmc_next_sg(struct tmio_mmc_host *host) +{ + host->sg_ptr = sg_next(host->sg_ptr); + host->sg_off = 0; + return --host->sg_len; +} + +#ifdef CONFIG_MMC_DEBUG + +#define STATUS_TO_TEXT(a, status, i) \ + do { \ + if (status & TMIO_STAT_##a) { \ + if (i++) \ + printk(" | "); \ + printk(#a); \ + } \ + } while (0) + +static void pr_debug_status(u32 status) +{ + int i = 0; + printk(KERN_DEBUG "status: %08x = ", status); + STATUS_TO_TEXT(CARD_REMOVE, status, i); + STATUS_TO_TEXT(CARD_INSERT, status, i); + STATUS_TO_TEXT(SIGSTATE, status, i); + STATUS_TO_TEXT(WRPROTECT, status, i); + STATUS_TO_TEXT(CARD_REMOVE_A, status, i); + STATUS_TO_TEXT(CARD_INSERT_A, status, i); + STATUS_TO_TEXT(SIGSTATE_A, status, i); + STATUS_TO_TEXT(CMD_IDX_ERR, status, i); + STATUS_TO_TEXT(STOPBIT_ERR, status, i); + STATUS_TO_TEXT(ILL_FUNC, status, i); + STATUS_TO_TEXT(CMD_BUSY, status, i); + STATUS_TO_TEXT(CMDRESPEND, status, i); + STATUS_TO_TEXT(DATAEND, status, i); + STATUS_TO_TEXT(CRCFAIL, status, i); + STATUS_TO_TEXT(DATATIMEOUT, status, i); + STATUS_TO_TEXT(CMDTIMEOUT, status, i); + STATUS_TO_TEXT(RXOVERFLOW, status, i); + STATUS_TO_TEXT(TXUNDERRUN, status, i); + STATUS_TO_TEXT(RXRDY, status, i); + STATUS_TO_TEXT(TXRQ, status, i); + STATUS_TO_TEXT(ILL_ACCESS, status, i); + printk("\n"); +} + +#else +#define pr_debug_status(s) do { } while (0) +#endif + +static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + + if (enable) { + host->sdio_irq_enabled = 1; + sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, + (TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); + } else { + sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); + sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); + host->sdio_irq_enabled = 0; + } +} + +static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) +{ + u32 clk = 0, clock; + + if (new_clock) { + for (clock = host->mmc->f_min, clk = 0x80000080; + new_clock >= (clock<<1); clk >>= 1) + clock <<= 1; + clk |= 0x100; + } + + if (host->set_clk_div) + host->set_clk_div(host->pdev, (clk>>22) & 1); + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); +} + +static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) +{ + struct tmio_mmc_data *pdata = host->pdata; + + /* + * Testing on sh-mobile showed that SDIO IRQs are unmasked when + * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the + * device IRQ here and restore the SDIO IRQ mask before + * re-enabling the device IRQ. + */ + if (pdata->flags & TMIO_MMC_SDIO_IRQ) + disable_irq(host->irq); + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); + msleep(10); + if (pdata->flags & TMIO_MMC_SDIO_IRQ) { + tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); + enable_irq(host->irq); + } + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + msleep(10); +} + +static void tmio_mmc_clk_start(struct tmio_mmc_host *host) +{ + struct tmio_mmc_data *pdata = host->pdata; + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + msleep(10); + /* see comment in tmio_mmc_clk_stop above */ + if (pdata->flags & TMIO_MMC_SDIO_IRQ) + disable_irq(host->irq); + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); + msleep(10); + if (pdata->flags & TMIO_MMC_SDIO_IRQ) { + tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); + enable_irq(host->irq); + } +} + +static void tmio_mmc_reset(struct tmio_mmc_host *host) +{ + /* FIXME - should we set stop clock reg here */ + sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); + msleep(10); + sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); + msleep(10); +} + +static void tmio_mmc_reset_work(struct work_struct *work) +{ + struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host, + delayed_reset_work.work); + struct mmc_request *mrq; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + mrq = host->mrq; + + /* request already finished */ + if (!mrq + || time_is_after_jiffies(host->last_req_ts + + msecs_to_jiffies(2000))) { + spin_unlock_irqrestore(&host->lock, flags); + return; + } + + dev_warn(&host->pdev->dev, + "timeout waiting for hardware interrupt (CMD%u)\n", + mrq->cmd->opcode); + + if (host->data) + host->data->error = -ETIMEDOUT; + else if (host->cmd) + host->cmd->error = -ETIMEDOUT; + else + mrq->cmd->error = -ETIMEDOUT; + + host->cmd = NULL; + host->data = NULL; + host->mrq = NULL; + host->force_pio = false; + + spin_unlock_irqrestore(&host->lock, flags); + + tmio_mmc_reset(host); + + mmc_request_done(host->mmc, mrq); +} + +static void tmio_mmc_finish_request(struct tmio_mmc_host *host) +{ + struct mmc_request *mrq = host->mrq; + + if (!mrq) + return; + + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + host->force_pio = false; + + cancel_delayed_work(&host->delayed_reset_work); + + mmc_request_done(host->mmc, mrq); +} + +/* These are the bitmasks the tmio chip requires to implement the MMC response + * types. Note that R1 and R6 are the same in this scheme. */ +#define APP_CMD 0x0040 +#define RESP_NONE 0x0300 +#define RESP_R1 0x0400 +#define RESP_R1B 0x0500 +#define RESP_R2 0x0600 +#define RESP_R3 0x0700 +#define DATA_PRESENT 0x0800 +#define TRANSFER_READ 0x1000 +#define TRANSFER_MULTI 0x2000 +#define SECURITY_CMD 0x4000 + +static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd) +{ + struct mmc_data *data = host->data; + int c = cmd->opcode; + + /* Command 12 is handled by hardware */ + if (cmd->opcode == 12 && !cmd->arg) { + sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001); + return 0; + } + + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: c |= RESP_NONE; break; + case MMC_RSP_R1: c |= RESP_R1; break; + case MMC_RSP_R1B: c |= RESP_R1B; break; + case MMC_RSP_R2: c |= RESP_R2; break; + case MMC_RSP_R3: c |= RESP_R3; break; + default: + pr_debug("Unknown response type %d\n", mmc_resp_type(cmd)); + return -EINVAL; + } + + host->cmd = cmd; + +/* FIXME - this seems to be ok commented out but the spec suggest this bit + * should be set when issuing app commands. + * if(cmd->flags & MMC_FLAG_ACMD) + * c |= APP_CMD; + */ + if (data) { + c |= DATA_PRESENT; + if (data->blocks > 1) { + sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100); + c |= TRANSFER_MULTI; + } + if (data->flags & MMC_DATA_READ) + c |= TRANSFER_READ; + } + + tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_CMD); + + /* Fire off the command */ + sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); + sd_ctrl_write16(host, CTL_SD_CMD, c); + + return 0; +} + +/* + * This chip always returns (at least?) as much data as you ask for. + * I'm unsure what happens if you ask for less than a block. This should be + * looked into to ensure that a funny length read doesnt hose the controller. + */ +static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) +{ + struct mmc_data *data = host->data; + void *sg_virt; + unsigned short *buf; + unsigned int count; + unsigned long flags; + + if ((host->chan_tx || host->chan_rx) && !host->force_pio) { + pr_err("PIO IRQ in DMA mode!\n"); + return; + } else if (!data) { + pr_debug("Spurious PIO IRQ\n"); + return; + } + + sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); + buf = (unsigned short *)(sg_virt + host->sg_off); + + count = host->sg_ptr->length - host->sg_off; + if (count > data->blksz) + count = data->blksz; + + pr_debug("count: %08x offset: %08x flags %08x\n", + count, host->sg_off, data->flags); + + /* Transfer the data */ + if (data->flags & MMC_DATA_READ) + sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); + else + sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1); + + host->sg_off += count; + + tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt); + + if (host->sg_off == host->sg_ptr->length) + tmio_mmc_next_sg(host); + + return; +} + +static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host) +{ + if (host->sg_ptr == &host->bounce_sg) { + unsigned long flags; + void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); + memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); + tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); + } +} + +/* needs to be called with host->lock held */ +void tmio_mmc_do_data_irq(struct tmio_mmc_host *host) +{ + struct mmc_data *data = host->data; + struct mmc_command *stop; + + host->data = NULL; + + if (!data) { + dev_warn(&host->pdev->dev, "Spurious data end IRQ\n"); + return; + } + stop = data->stop; + + /* FIXME - return correct transfer count on errors */ + if (!data->error) + data->bytes_xfered = data->blocks * data->blksz; + else + data->bytes_xfered = 0; + + pr_debug("Completed data request\n"); + + /* + * FIXME: other drivers allow an optional stop command of any given type + * which we dont do, as the chip can auto generate them. + * Perhaps we can be smarter about when to use auto CMD12 and + * only issue the auto request when we know this is the desired + * stop command, allowing fallback to the stop command the + * upper layers expect. For now, we do what works. + */ + + if (data->flags & MMC_DATA_READ) { + if (host->chan_rx && !host->force_pio) + tmio_mmc_check_bounce_buffer(host); + dev_dbg(&host->pdev->dev, "Complete Rx request %p\n", + host->mrq); + } else { + dev_dbg(&host->pdev->dev, "Complete Tx request %p\n", + host->mrq); + } + + if (stop) { + if (stop->opcode == 12 && !stop->arg) + sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000); + else + BUG(); + } + + tmio_mmc_finish_request(host); +} + +static void tmio_mmc_data_irq(struct tmio_mmc_host *host) +{ + struct mmc_data *data; + spin_lock(&host->lock); + data = host->data; + + if (!data) + goto out; + + if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) { + /* + * Has all data been written out yet? Testing on SuperH showed, + * that in most cases the first interrupt comes already with the + * BUSY status bit clear, but on some operations, like mount or + * in the beginning of a write / sync / umount, there is one + * DATAEND interrupt with the BUSY bit set, in this cases + * waiting for one more interrupt fixes the problem. + */ + if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) { + tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); + tasklet_schedule(&host->dma_complete); + } + } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) { + tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND); + tasklet_schedule(&host->dma_complete); + } else { + tmio_mmc_do_data_irq(host); + tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP); + } +out: + spin_unlock(&host->lock); +} + +static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, + unsigned int stat) +{ + struct mmc_command *cmd = host->cmd; + int i, addr; + + spin_lock(&host->lock); + + if (!host->cmd) { + pr_debug("Spurious CMD irq\n"); + goto out; + } + + host->cmd = NULL; + + /* This controller is sicker than the PXA one. Not only do we need to + * drop the top 8 bits of the first response word, we also need to + * modify the order of the response for short response command types. + */ + + for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4) + cmd->resp[i] = sd_ctrl_read32(host, addr); + + if (cmd->flags & MMC_RSP_136) { + cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); + cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24); + cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24); + cmd->resp[3] <<= 8; + } else if (cmd->flags & MMC_RSP_R3) { + cmd->resp[0] = cmd->resp[3]; + } + + if (stat & TMIO_STAT_CMDTIMEOUT) + cmd->error = -ETIMEDOUT; + else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC) + cmd->error = -EILSEQ; + + /* If there is data to handle we enable data IRQs here, and + * we will ultimatley finish the request in the data_end handler. + * If theres no data or we encountered an error, finish now. + */ + if (host->data && !cmd->error) { + if (host->data->flags & MMC_DATA_READ) { + if (host->force_pio || !host->chan_rx) + tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP); + else + tasklet_schedule(&host->dma_issue); + } else { + if (host->force_pio || !host->chan_tx) + tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP); + else + tasklet_schedule(&host->dma_issue); + } + } else { + tmio_mmc_finish_request(host); + } + +out: + spin_unlock(&host->lock); +} + +static irqreturn_t tmio_mmc_irq(int irq, void *devid) +{ + struct tmio_mmc_host *host = devid; + struct tmio_mmc_data *pdata = host->pdata; + unsigned int ireg, irq_mask, status; + unsigned int sdio_ireg, sdio_irq_mask, sdio_status; + + pr_debug("MMC IRQ begin\n"); + + status = sd_ctrl_read32(host, CTL_STATUS); + irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); + ireg = status & TMIO_MASK_IRQ & ~irq_mask; + + sdio_ireg = 0; + if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { + sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); + sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); + sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; + + sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); + + if (sdio_ireg && !host->sdio_irq_enabled) { + pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", + sdio_status, sdio_irq_mask, sdio_ireg); + tmio_mmc_enable_sdio_irq(host->mmc, 0); + goto out; + } + + if (host->mmc->caps & MMC_CAP_SDIO_IRQ && + sdio_ireg & TMIO_SDIO_STAT_IOIRQ) + mmc_signal_sdio_irq(host->mmc); + + if (sdio_ireg) + goto out; + } + + pr_debug_status(status); + pr_debug_status(ireg); + + if (!ireg) { + tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask); + + pr_warning("tmio_mmc: Spurious irq, disabling! " + "0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); + pr_debug_status(status); + + goto out; + } + + while (ireg) { + /* Card insert / remove attempts */ + if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { + tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | + TMIO_STAT_CARD_REMOVE); + mmc_detect_change(host->mmc, msecs_to_jiffies(100)); + } + + /* CRC and other errors */ +/* if (ireg & TMIO_STAT_ERR_IRQ) + * handled |= tmio_error_irq(host, irq, stat); + */ + + /* Command completion */ + if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { + tmio_mmc_ack_mmc_irqs(host, + TMIO_STAT_CMDRESPEND | + TMIO_STAT_CMDTIMEOUT); + tmio_mmc_cmd_irq(host, status); + } + + /* Data transfer */ + if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { + tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); + tmio_mmc_pio_irq(host); + } + + /* Data transfer completion */ + if (ireg & TMIO_STAT_DATAEND) { + tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND); + tmio_mmc_data_irq(host); + } + + /* Check status - keep going until we've handled it all */ + status = sd_ctrl_read32(host, CTL_STATUS); + irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); + ireg = status & TMIO_MASK_IRQ & ~irq_mask; + + pr_debug("Status at end of loop: %08x\n", status); + pr_debug_status(status); + } + pr_debug("MMC IRQ end\n"); + +out: + return IRQ_HANDLED; +} + +static int tmio_mmc_start_data(struct tmio_mmc_host *host, + struct mmc_data *data) +{ + struct tmio_mmc_data *pdata = host->pdata; + + pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n", + data->blksz, data->blocks); + + /* Some hardware cannot perform 2 byte requests in 4 bit mode */ + if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) { + int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES; + + if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) { + pr_err("%s: %d byte block unsupported in 4 bit mode\n", + mmc_hostname(host->mmc), data->blksz); + return -EINVAL; + } + } + + tmio_mmc_init_sg(host, data); + host->data = data; + + /* Set transfer length / blocksize */ + sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); + sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks); + + tmio_mmc_start_dma(host, data); + + return 0; +} + +/* Process requests from the MMC layer */ +static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + int ret; + + if (host->mrq) + pr_debug("request not null\n"); + + host->last_req_ts = jiffies; + wmb(); + host->mrq = mrq; + + if (mrq->data) { + ret = tmio_mmc_start_data(host, mrq->data); + if (ret) + goto fail; + } + + ret = tmio_mmc_start_command(host, mrq->cmd); + if (!ret) { + schedule_delayed_work(&host->delayed_reset_work, + msecs_to_jiffies(2000)); + return; + } + +fail: + host->mrq = NULL; + host->force_pio = false; + mrq->cmd->error = ret; + mmc_request_done(mmc, mrq); +} + +/* Set MMC clock / power. + * Note: This controller uses a simple divider scheme therefore it cannot + * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as + * MMC wont run that fast, it has to be clocked at 12MHz which is the next + * slowest setting. + */ +static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + + if (ios->clock) + tmio_mmc_set_clock(host, ios->clock); + + /* Power sequence - OFF -> ON -> UP */ + switch (ios->power_mode) { + case MMC_POWER_OFF: /* power down SD bus */ + if (host->set_pwr) + host->set_pwr(host->pdev, 0); + tmio_mmc_clk_stop(host); + break; + case MMC_POWER_ON: /* power up SD bus */ + if (host->set_pwr) + host->set_pwr(host->pdev, 1); + break; + case MMC_POWER_UP: /* start bus clock */ + tmio_mmc_clk_start(host); + break; + } + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_1: + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); + break; + case MMC_BUS_WIDTH_4: + sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0); + break; + } + + /* Let things settle. delay taken from winCE driver */ + udelay(140); +} + +static int tmio_mmc_get_ro(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct tmio_mmc_data *pdata = host->pdata; + + return ((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || + !(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); +} + +static int tmio_mmc_get_cd(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct tmio_mmc_data *pdata = host->pdata; + + if (!pdata->get_cd) + return -ENOSYS; + else + return pdata->get_cd(host->pdev); +} + +static const struct mmc_host_ops tmio_mmc_ops = { + .request = tmio_mmc_request, + .set_ios = tmio_mmc_set_ios, + .get_ro = tmio_mmc_get_ro, + .get_cd = tmio_mmc_get_cd, + .enable_sdio_irq = tmio_mmc_enable_sdio_irq, +}; + +int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, + struct platform_device *pdev, + struct tmio_mmc_data *pdata) +{ + struct tmio_mmc_host *_host; + struct mmc_host *mmc; + struct resource *res_ctl; + int ret; + u32 irq_mask = TMIO_MASK_CMD; + + res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_ctl) + return -EINVAL; + + mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); + if (!mmc) + return -ENOMEM; + + _host = mmc_priv(mmc); + _host->pdata = pdata; + _host->mmc = mmc; + _host->pdev = pdev; + platform_set_drvdata(pdev, mmc); + + _host->set_pwr = pdata->set_pwr; + _host->set_clk_div = pdata->set_clk_div; + + /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ + _host->bus_shift = resource_size(res_ctl) >> 10; + + _host->ctl = ioremap(res_ctl->start, resource_size(res_ctl)); + if (!_host->ctl) { + ret = -ENOMEM; + goto host_free; + } + + mmc->ops = &tmio_mmc_ops; + mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities; + mmc->f_max = pdata->hclk; + mmc->f_min = mmc->f_max / 512; + mmc->max_segs = 32; + mmc->max_blk_size = 512; + mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) * + mmc->max_segs; + mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; + mmc->max_seg_size = mmc->max_req_size; + if (pdata->ocr_mask) + mmc->ocr_avail = pdata->ocr_mask; + else + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + + tmio_mmc_clk_stop(_host); + tmio_mmc_reset(_host); + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + goto unmap_ctl; + + _host->irq = ret; + + tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); + if (pdata->flags & TMIO_MMC_SDIO_IRQ) + tmio_mmc_enable_sdio_irq(mmc, 0); + + ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED | + IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host); + if (ret) + goto unmap_ctl; + + spin_lock_init(&_host->lock); + + /* Init delayed work for request timeouts */ + INIT_DELAYED_WORK(&_host->delayed_reset_work, tmio_mmc_reset_work); + + /* See if we also get DMA */ + tmio_mmc_request_dma(_host, pdata); + + mmc_add_host(mmc); + + /* Unmask the IRQs we want to know about */ + if (!_host->chan_rx) + irq_mask |= TMIO_MASK_READOP; + if (!_host->chan_tx) + irq_mask |= TMIO_MASK_WRITEOP; + + tmio_mmc_enable_mmc_irqs(_host, irq_mask); + + *host = _host; + + return 0; + +unmap_ctl: + iounmap(_host->ctl); +host_free: + mmc_free_host(mmc); + + return ret; +} +EXPORT_SYMBOL(tmio_mmc_host_probe); + +void tmio_mmc_host_remove(struct tmio_mmc_host *host) +{ + mmc_remove_host(host->mmc); + cancel_delayed_work_sync(&host->delayed_reset_work); + tmio_mmc_release_dma(host); + free_irq(host->irq, host); + iounmap(host->ctl); + mmc_free_host(host->mmc); +} +EXPORT_SYMBOL(tmio_mmc_host_remove); + +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 42051e8a7bce76ebd3cd201704ee2427120636e1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 14 Mar 2011 09:52:33 +0100 Subject: mmc: tmio: convert the SDHI MMC driver from MFD to a platform driver On sh-mobile platforms the SDHI driver was using the tmio_mmc SD/SDIO MFD cell driver. Now that the tmio_mmc driver has been split into a core and a separate MFD glue, we can support SDHI natively without the need to emulate an MFD controller. This also allows to support systems with an on-SoC SDHI controller and a separate MFD with a TMIO core. Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mfd/Kconfig | 14 --- drivers/mfd/Makefile | 1 - drivers/mfd/sh_mobile_sdhi.c | 200 -------------------------------------- drivers/mmc/host/Kconfig | 9 +- drivers/mmc/host/Makefile | 7 +- drivers/mmc/host/sh_mobile_sdhi.c | 171 ++++++++++++++++++++++++++++++++ drivers/mmc/host/tmio_mmc.h | 2 +- 7 files changed, 185 insertions(+), 219 deletions(-) delete mode 100644 drivers/mfd/sh_mobile_sdhi.c create mode 100644 drivers/mmc/host/sh_mobile_sdhi.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a9a1af49281e..38cb1d4d6843 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -60,15 +60,6 @@ config MFD_ASIC3 This driver supports the ASIC3 multifunction chip found on many PDAs (mainly iPAQ and HTC based ones) -config MFD_SH_MOBILE_SDHI - bool "Support for SuperH Mobile SDHI" - depends on SUPERH || ARCH_SHMOBILE - select MFD_CORE - select TMIO_MMC_DMA - ---help--- - This driver supports the SDHI hardware block found in many - SuperH Mobile SoCs. - config MFD_DAVINCI_VOICECODEC tristate select MFD_CORE @@ -265,11 +256,6 @@ config MFD_TMIO bool default n -config TMIO_MMC_DMA - bool - select DMA_ENGINE - select DMADEVICES - config MFD_T7L66XB bool "Support Toshiba T7L66XB" depends on ARM && HAVE_CLK diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 47f5709f3828..ad6c44321873 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o -obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o diff --git a/drivers/mfd/sh_mobile_sdhi.c b/drivers/mfd/sh_mobile_sdhi.c deleted file mode 100644 index 53a63024bf11..000000000000 --- a/drivers/mfd/sh_mobile_sdhi.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * SuperH Mobile SDHI - * - * Copyright (C) 2009 Magnus Damm - * - * 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. - * - * Based on "Compaq ASIC3 support": - * - * Copyright 2001 Compaq Computer Corporation. - * Copyright 2004-2005 Phil Blundell - * Copyright 2007-2008 OpenedHand Ltd. - * - * Authors: Phil Blundell , - * Samuel Ortiz - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct sh_mobile_sdhi { - struct clk *clk; - struct tmio_mmc_data mmc_data; - struct mfd_cell cell_mmc; - struct sh_dmae_slave param_tx; - struct sh_dmae_slave param_rx; - struct tmio_mmc_dma dma_priv; -}; - -static struct resource sh_mobile_sdhi_resources[] = { - { - .start = 0x000, - .end = 0x1ff, - .flags = IORESOURCE_MEM, - }, - { - .start = 0, - .end = 0, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct mfd_cell sh_mobile_sdhi_cell = { - .name = "tmio-mmc", - .num_resources = ARRAY_SIZE(sh_mobile_sdhi_resources), - .resources = sh_mobile_sdhi_resources, -}; - -static void sh_mobile_sdhi_set_pwr(struct platform_device *tmio, int state) -{ - struct platform_device *pdev = to_platform_device(tmio->dev.parent); - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - - if (p && p->set_pwr) - p->set_pwr(pdev, state); -} - -static int sh_mobile_sdhi_get_cd(struct platform_device *tmio) -{ - struct platform_device *pdev = to_platform_device(tmio->dev.parent); - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - - if (p && p->get_cd) - return p->get_cd(pdev); - else - return -ENOSYS; -} - -static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) -{ - struct sh_mobile_sdhi *priv; - struct tmio_mmc_data *mmc_data; - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - struct resource *mem; - char clk_name[8]; - int ret, irq; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) - dev_err(&pdev->dev, "missing MEM resource\n"); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - dev_err(&pdev->dev, "missing IRQ resource\n"); - - if (!mem || (irq < 0)) - return -EINVAL; - - priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); - if (priv == NULL) { - dev_err(&pdev->dev, "kzalloc failed\n"); - return -ENOMEM; - } - - mmc_data = &priv->mmc_data; - - snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); - priv->clk = clk_get(&pdev->dev, clk_name); - if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); - ret = PTR_ERR(priv->clk); - kfree(priv); - return ret; - } - - clk_enable(priv->clk); - - mmc_data->hclk = clk_get_rate(priv->clk); - mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; - mmc_data->get_cd = sh_mobile_sdhi_get_cd; - mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; - if (p) { - mmc_data->flags = p->tmio_flags; - mmc_data->ocr_mask = p->tmio_ocr_mask; - mmc_data->capabilities |= p->tmio_caps; - } - - /* - * All SDHI blocks support 2-byte and larger block sizes in 4-bit - * bus width mode. - */ - mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; - - /* - * All SDHI blocks support SDIO IRQ signalling. - */ - mmc_data->flags |= TMIO_MMC_SDIO_IRQ; - - if (p && p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { - priv->param_tx.slave_id = p->dma_slave_tx; - priv->param_rx.slave_id = p->dma_slave_rx; - priv->dma_priv.chan_priv_tx = &priv->param_tx; - priv->dma_priv.chan_priv_rx = &priv->param_rx; - priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ - mmc_data->dma = &priv->dma_priv; - } - - memcpy(&priv->cell_mmc, &sh_mobile_sdhi_cell, sizeof(priv->cell_mmc)); - priv->cell_mmc.mfd_data = mmc_data; - - platform_set_drvdata(pdev, priv); - - ret = mfd_add_devices(&pdev->dev, pdev->id, - &priv->cell_mmc, 1, mem, irq); - if (ret) { - clk_disable(priv->clk); - clk_put(priv->clk); - kfree(priv); - } - - return ret; -} - -static int sh_mobile_sdhi_remove(struct platform_device *pdev) -{ - struct sh_mobile_sdhi *priv = platform_get_drvdata(pdev); - - mfd_remove_devices(&pdev->dev); - clk_disable(priv->clk); - clk_put(priv->clk); - kfree(priv); - - return 0; -} - -static struct platform_driver sh_mobile_sdhi_driver = { - .driver = { - .name = "sh_mobile_sdhi", - .owner = THIS_MODULE, - }, - .probe = sh_mobile_sdhi_probe, - .remove = __devexit_p(sh_mobile_sdhi_remove), -}; - -static int __init sh_mobile_sdhi_init(void) -{ - return platform_driver_register(&sh_mobile_sdhi_driver); -} - -static void __exit sh_mobile_sdhi_exit(void) -{ - platform_driver_unregister(&sh_mobile_sdhi_driver); -} - -module_init(sh_mobile_sdhi_init); -module_exit(sh_mobile_sdhi_exit); - -MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); -MODULE_AUTHOR("Magnus Damm"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 4d16166386ca..0b03cee91451 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -444,12 +444,19 @@ config MMC_TMIO_CORE config MMC_TMIO tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO || MFD_ASIC3 || MFD_SH_MOBILE_SDHI + depends on MFD_TMIO || MFD_ASIC3 select MMC_TMIO_CORE help This provides support for the SD/MMC cell found in TC6393XB, T7L66XB and also HTC ASIC3 +config MMC_SDHI + tristate "SH-Mobile SDHI SD/SDIO controller support" + select MMC_TMIO_CORE + help + This provides support for the SDHI SD/SDIO controller found in + SuperH and ARM SH-Mobile SoCs + config MMC_CB710 tristate "ENE CB710 MMC/SD Interface support" depends on PCI diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 79c42dd23c0e..4f1df0aae574 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -31,8 +31,11 @@ obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o tmio_mmc_core-y := tmio_mmc_pio.o -tmio_mmc_core-$(CONFIG_TMIO_MMC_DMA) += tmio_mmc_dma.o -obj-$(CONFIG_MMC_CB710) += cb710-mmc.o +ifneq ($(CONFIG_MMC_SDHI),n) +tmio_mmc_core-y += tmio_mmc_dma.o +endif +obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o +obj-$(CONFIG_MMC_CB710) += cb710-mmc.o obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o obj-$(CONFIG_MMC_DW) += dw_mmc.o diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c new file mode 100644 index 000000000000..cc701236d16f --- /dev/null +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -0,0 +1,171 @@ +/* + * SuperH Mobile SDHI + * + * Copyright (C) 2009 Magnus Damm + * + * 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. + * + * Based on "Compaq ASIC3 support": + * + * Copyright 2001 Compaq Computer Corporation. + * Copyright 2004-2005 Phil Blundell + * Copyright 2007-2008 OpenedHand Ltd. + * + * Authors: Phil Blundell , + * Samuel Ortiz + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tmio_mmc.h" + +struct sh_mobile_sdhi { + struct clk *clk; + struct tmio_mmc_data mmc_data; + struct sh_dmae_slave param_tx; + struct sh_dmae_slave param_rx; + struct tmio_mmc_dma dma_priv; +}; + +static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state) +{ + struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; + + if (p && p->set_pwr) + p->set_pwr(pdev, state); +} + +static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) +{ + struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; + + if (p && p->get_cd) + return p->get_cd(pdev); + else + return -ENOSYS; +} + +static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) +{ + struct sh_mobile_sdhi *priv; + struct tmio_mmc_data *mmc_data; + struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; + struct tmio_mmc_host *host; + char clk_name[8]; + int ret; + + priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); + if (priv == NULL) { + dev_err(&pdev->dev, "kzalloc failed\n"); + return -ENOMEM; + } + + mmc_data = &priv->mmc_data; + + snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); + priv->clk = clk_get(&pdev->dev, clk_name); + if (IS_ERR(priv->clk)) { + dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); + ret = PTR_ERR(priv->clk); + goto eclkget; + } + + clk_enable(priv->clk); + + mmc_data->hclk = clk_get_rate(priv->clk); + mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; + mmc_data->get_cd = sh_mobile_sdhi_get_cd; + mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED; + if (p) { + mmc_data->flags = p->tmio_flags; + mmc_data->ocr_mask = p->tmio_ocr_mask; + mmc_data->capabilities |= p->tmio_caps; + + if (p->dma_slave_tx >= 0 && p->dma_slave_rx >= 0) { + priv->param_tx.slave_id = p->dma_slave_tx; + priv->param_rx.slave_id = p->dma_slave_rx; + priv->dma_priv.chan_priv_tx = &priv->param_tx; + priv->dma_priv.chan_priv_rx = &priv->param_rx; + priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */ + mmc_data->dma = &priv->dma_priv; + } + } + + /* + * All SDHI blocks support 2-byte and larger block sizes in 4-bit + * bus width mode. + */ + mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES; + + /* + * All SDHI blocks support SDIO IRQ signalling. + */ + mmc_data->flags |= TMIO_MMC_SDIO_IRQ; + + ret = tmio_mmc_host_probe(&host, pdev, mmc_data); + if (ret < 0) + goto eprobe; + + pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc), + (unsigned long)host->ctl, host->irq); + + return ret; + +eprobe: + clk_disable(priv->clk); + clk_put(priv->clk); +eclkget: + kfree(priv); + return ret; +} + +static int sh_mobile_sdhi_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct tmio_mmc_host *host = mmc_priv(mmc); + struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); + + tmio_mmc_host_remove(host); + clk_disable(priv->clk); + clk_put(priv->clk); + kfree(priv); + + return 0; +} + +static struct platform_driver sh_mobile_sdhi_driver = { + .driver = { + .name = "sh_mobile_sdhi", + .owner = THIS_MODULE, + }, + .probe = sh_mobile_sdhi_probe, + .remove = __devexit_p(sh_mobile_sdhi_remove), +}; + +static int __init sh_mobile_sdhi_init(void) +{ + return platform_driver_register(&sh_mobile_sdhi_driver); +} + +static void __exit sh_mobile_sdhi_exit(void) +{ + platform_driver_unregister(&sh_mobile_sdhi_driver); +} + +module_init(sh_mobile_sdhi_init); +module_exit(sh_mobile_sdhi_exit); + +MODULE_DESCRIPTION("SuperH Mobile SDHI driver"); +MODULE_AUTHOR("Magnus Damm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:sh_mobile_sdhi"); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 8dedf0a69348..7d79b14d56aa 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -120,7 +120,7 @@ static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, local_irq_restore(*flags); } -#ifdef CONFIG_TMIO_MMC_DMA +#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data); void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata); void tmio_mmc_release_dma(struct tmio_mmc_host *host); -- cgit v1.2.2 From 69d1fe18e92afb4687605a1ab2ec73fbc3bae344 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 9 Mar 2011 17:28:55 +0100 Subject: mmc: tmio: only access registers above 0xff, if available Not all tmio implementations have registers above oxff. Accessing them on thise platforms is dangerous. In some cases it leads to address wrapping to addresses below 0x100, which corrupts random unrelated registers. Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc_pio.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index a7406e3701c9..28e14c7a2540 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -209,6 +209,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) { struct tmio_mmc_data *pdata = host->pdata; + struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); /* * Testing on sh-mobile showed that SDIO IRQs are unmasked when @@ -218,8 +219,11 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) */ if (pdata->flags & TMIO_MMC_SDIO_IRQ) disable_irq(host->irq); - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); - msleep(10); + /* implicit BUG_ON(!res) */ + if (resource_size(res) > 0x100) { + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); + msleep(10); + } if (pdata->flags & TMIO_MMC_SDIO_IRQ) { tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); enable_irq(host->irq); @@ -232,6 +236,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { struct tmio_mmc_data *pdata = host->pdata; + struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); @@ -239,8 +244,11 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host) /* see comment in tmio_mmc_clk_stop above */ if (pdata->flags & TMIO_MMC_SDIO_IRQ) disable_irq(host->irq); - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); - msleep(10); + /* implicit BUG_ON(!res) */ + if (resource_size(res) > 0x100) { + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); + msleep(10); + } if (pdata->flags & TMIO_MMC_SDIO_IRQ) { tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); enable_irq(host->irq); @@ -249,12 +257,17 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host) static void tmio_mmc_reset(struct tmio_mmc_host *host) { + struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); + /* FIXME - should we set stop clock reg here */ sd_ctrl_write16(host, CTL_RESET_SD, 0x0000); - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); + /* implicit BUG_ON(!res) */ + if (resource_size(res) > 0x100) + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000); msleep(10); sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); - sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); + if (resource_size(res) > 0x100) + sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001); msleep(10); } -- cgit v1.2.2 From d9b03421775d5cf8b4d5518a3e80b28cf3f999ce Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 10 Mar 2011 18:43:07 +0100 Subject: mmc: tmio: remove work-around for unmasked SDIO interrupts SDIO IRQs got unmasked on sh-mobile while writing to the CTL_CLK_AND_WAIT_CTL register, because that register at address 0x138 is not implemented on those SoCs and writes to it overwrite the register at address 0x38: CTL_SDIO_IRQ_MASK. Previous patches eliminated access to register above 0xff on sh-mobile, so that this work-around isn't needed anymore. Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc_pio.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 28e14c7a2540..e1aed2555126 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -208,26 +208,14 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock) static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) { - struct tmio_mmc_data *pdata = host->pdata; struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); - /* - * Testing on sh-mobile showed that SDIO IRQs are unmasked when - * CTL_CLK_AND_WAIT_CTL gets written, so we have to disable the - * device IRQ here and restore the SDIO IRQ mask before - * re-enabling the device IRQ. - */ - if (pdata->flags & TMIO_MMC_SDIO_IRQ) - disable_irq(host->irq); /* implicit BUG_ON(!res) */ if (resource_size(res) > 0x100) { sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); msleep(10); } - if (pdata->flags & TMIO_MMC_SDIO_IRQ) { - tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); - enable_irq(host->irq); - } + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(10); @@ -235,24 +223,17 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { - struct tmio_mmc_data *pdata = host->pdata; struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); msleep(10); - /* see comment in tmio_mmc_clk_stop above */ - if (pdata->flags & TMIO_MMC_SDIO_IRQ) - disable_irq(host->irq); + /* implicit BUG_ON(!res) */ if (resource_size(res) > 0x100) { sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); msleep(10); } - if (pdata->flags & TMIO_MMC_SDIO_IRQ) { - tmio_mmc_enable_sdio_irq(host->mmc, host->sdio_irq_enabled); - enable_irq(host->irq); - } } static void tmio_mmc_reset(struct tmio_mmc_host *host) -- cgit v1.2.2 From a7edbe399b40fb82ccd11216fd88d24e428025c5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 9 Mar 2011 14:38:58 +0100 Subject: mmc: tmio: fix power-mode interpretation The power-mode sequence on MMC is MMC_POWER_OFF -> MMC_POWER_UP -> MMC_POWER_ON and not MMC_POWER_ON -> MMC_POWER_UP, as the driver currently is implying. Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc_pio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index e1aed2555126..69772ab3ca22 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -746,20 +746,20 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->clock) tmio_mmc_set_clock(host, ios->clock); - /* Power sequence - OFF -> ON -> UP */ + /* Power sequence - OFF -> UP -> ON */ switch (ios->power_mode) { case MMC_POWER_OFF: /* power down SD bus */ if (host->set_pwr) host->set_pwr(host->pdev, 0); tmio_mmc_clk_stop(host); break; - case MMC_POWER_ON: /* power up SD bus */ + case MMC_POWER_ON: /* start bus clock */ + tmio_mmc_clk_start(host); + break; + case MMC_POWER_UP: /* power up SD bus */ if (host->set_pwr) host->set_pwr(host->pdev, 1); break; - case MMC_POWER_UP: /* start bus clock */ - tmio_mmc_clk_start(host); - break; } switch (ios->bus_width) { -- cgit v1.2.2 From 5fd0157901d5a8f497f3d3b95cb4beebf1641d1b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 9 Mar 2011 14:45:44 +0100 Subject: mmc: tmio: support aggressive clock gating Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc_pio.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 69772ab3ca22..e35e17992e38 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -747,19 +747,18 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmio_mmc_set_clock(host, ios->clock); /* Power sequence - OFF -> UP -> ON */ - switch (ios->power_mode) { - case MMC_POWER_OFF: /* power down SD bus */ - if (host->set_pwr) + if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { + /* power down SD bus */ + if (ios->power_mode == MMC_POWER_OFF && host->set_pwr) host->set_pwr(host->pdev, 0); tmio_mmc_clk_stop(host); - break; - case MMC_POWER_ON: /* start bus clock */ - tmio_mmc_clk_start(host); - break; - case MMC_POWER_UP: /* power up SD bus */ + } else if (ios->power_mode == MMC_POWER_UP) { + /* power up SD bus */ if (host->set_pwr) host->set_pwr(host->pdev, 1); - break; + } else { + /* start bus clock */ + tmio_mmc_clk_start(host); } switch (ios->bus_width) { -- cgit v1.2.2 From e21fa86ad0ffa2c292b104ea19bdaa46ceab7105 Mon Sep 17 00:00:00 2001 From: Yang Ruirui Date: Mon, 14 Mar 2011 09:50:56 +0800 Subject: mtdswap: kill strict error handling option As Artem Bityutskiy suggested: this option is controversial, as we do not really have any prove it is useful. And it is too much to have it as a config parameter. So, better kill it and let the real mtdswap users decide whether it is needed or not. Signed-off-by: Yang Ruirui Signed-off-by: Artem Bityutskiy --- drivers/mtd/Kconfig | 8 -------- drivers/mtd/mtdswap.c | 8 +------- 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 5fe01d556657..b4567c35a322 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -335,14 +335,6 @@ config MTD_SWAP The driver provides wear leveling by storing erase counter into the OOB. -config MTD_SWAP_STRICT - bool "Strict erase error handling" - depends on MTD_SWAP - help - Enables strict tolerance on failed erasures, marking erase blocks bad - right after the first failed operation. With non-strict mode the - erase operation is retried. - source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index a65594fee4a3..dc4b136800b8 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -156,12 +156,6 @@ struct mtdswap_oobdata { #define MTDSWAP_ERASE_RETRIES 3 /* Before marking erase block bad */ #define MTDSWAP_IO_RETRIES 3 -#ifdef CONFIG_MTD_SWAP_STRICT -#define MTDSWAP_STRICT 1 -#else -#define MTDSWAP_STRICT 0 -#endif - enum { MTDSWAP_SCANNED_CLEAN, MTDSWAP_SCANNED_DIRTY, @@ -575,7 +569,7 @@ retry: ret = mtd->erase(mtd, &erase); if (ret) { - if (retries++ < MTDSWAP_ERASE_RETRIES && !MTDSWAP_STRICT) { + if (retries++ < MTDSWAP_ERASE_RETRIES) { dev_warn(d->dev, "erase of erase block %#llx on %s failed", erase.addr, mtd->name); -- cgit v1.2.2 From 68b1a1e786f29c900fa1c516a402e24f0ece622a Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 25 Mar 2011 17:10:16 +0200 Subject: mtd: mtdswap: fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following compilation warning: drivers/mtd/mtdswap.c: In function ‘mtdswap_pick_gc_eblk’: drivers/mtd/mtdswap.c:859: warning: ‘idx’ may be used uninitialized in this function drivers/mtd/mtdswap.c:859: note: ‘idx’ was declared here Initialize idx to -1 because this value means "no tree choosen". Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdswap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index dc4b136800b8..237913c5c92c 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -850,7 +850,7 @@ static int mtdswap_wlfreq(unsigned int maxdiff) static int mtdswap_choose_wl_tree(struct mtdswap_dev *d) { static unsigned int pick_cnt; - unsigned int i, idx, wear, max; + unsigned int i, idx = -1, wear, max; struct rb_root *root; max = 0; -- cgit v1.2.2 From 6a03513825db4db57fa93821a0c04dbbb39a68e6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 12:21:38 +0100 Subject: dma: Ipu: Convert interupt code Convert to the new irq chip functions and cleanup the name space. [ Guennadi reported: irq_data_get_chip_data is undefined. Yes, I screwed up. it needs to be irq_data_get_irq_chip_data ] Signed-off-by: Thomas Gleixner Tested-by: Guennadi Liakhovetski Cc: Dan Williams LKML-Reference: --- drivers/dma/ipu/ipu_irq.c | 58 +++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index dd8ebc75b667..ab8a4eff072a 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -94,9 +94,9 @@ static struct ipu_irq_map *src2map(unsigned int src) return NULL; } -static void ipu_irq_unmask(unsigned int irq) +static void ipu_irq_unmask(struct irq_data *d) { - struct ipu_irq_map *map = get_irq_chip_data(irq); + struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); struct ipu_irq_bank *bank; uint32_t reg; unsigned long lock_flags; @@ -106,7 +106,7 @@ static void ipu_irq_unmask(unsigned int irq) bank = map->bank; if (!bank) { spin_unlock_irqrestore(&bank_lock, lock_flags); - pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq); + pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); return; } @@ -117,9 +117,9 @@ static void ipu_irq_unmask(unsigned int irq) spin_unlock_irqrestore(&bank_lock, lock_flags); } -static void ipu_irq_mask(unsigned int irq) +static void ipu_irq_mask(struct irq_data *d) { - struct ipu_irq_map *map = get_irq_chip_data(irq); + struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); struct ipu_irq_bank *bank; uint32_t reg; unsigned long lock_flags; @@ -129,7 +129,7 @@ static void ipu_irq_mask(unsigned int irq) bank = map->bank; if (!bank) { spin_unlock_irqrestore(&bank_lock, lock_flags); - pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq); + pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); return; } @@ -140,9 +140,9 @@ static void ipu_irq_mask(unsigned int irq) spin_unlock_irqrestore(&bank_lock, lock_flags); } -static void ipu_irq_ack(unsigned int irq) +static void ipu_irq_ack(struct irq_data *d) { - struct ipu_irq_map *map = get_irq_chip_data(irq); + struct ipu_irq_map *map = irq_data_get_irq_chip_data(d); struct ipu_irq_bank *bank; unsigned long lock_flags; @@ -151,7 +151,7 @@ static void ipu_irq_ack(unsigned int irq) bank = map->bank; if (!bank) { spin_unlock_irqrestore(&bank_lock, lock_flags); - pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq); + pr_err("IPU: %s(%u) - unmapped!\n", __func__, d->irq); return; } @@ -167,7 +167,7 @@ static void ipu_irq_ack(unsigned int irq) */ bool ipu_irq_status(unsigned int irq) { - struct ipu_irq_map *map = get_irq_chip_data(irq); + struct ipu_irq_map *map = irq_get_chip_data(irq); struct ipu_irq_bank *bank; unsigned long lock_flags; bool ret; @@ -269,7 +269,7 @@ int ipu_irq_unmap(unsigned int source) /* Chained IRQ handler for IPU error interrupt */ static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) { - struct ipu *ipu = get_irq_data(irq); + struct ipu *ipu = irq_get_handler_data(irq); u32 status; int i, line; @@ -310,7 +310,7 @@ static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) /* Chained IRQ handler for IPU function interrupt */ static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc) { - struct ipu *ipu = get_irq_data(irq); + struct ipu *ipu = irq_desc_get_handler_data(desc); u32 status; int i, line; @@ -345,10 +345,10 @@ static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc) } static struct irq_chip ipu_irq_chip = { - .name = "ipu_irq", - .ack = ipu_irq_ack, - .mask = ipu_irq_mask, - .unmask = ipu_irq_unmask, + .name = "ipu_irq", + .irq_ack = ipu_irq_ack, + .irq_mask = ipu_irq_mask, + .irq_unmask = ipu_irq_unmask, }; /* Install the IRQ handler */ @@ -366,26 +366,26 @@ int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev) int ret; irq = irq_base + i; - ret = set_irq_chip(irq, &ipu_irq_chip); + ret = irq_set_chip(irq, &ipu_irq_chip); if (ret < 0) return ret; - ret = set_irq_chip_data(irq, irq_map + i); + ret = irq_set_chip_data(irq, irq_map + i); if (ret < 0) return ret; irq_map[i].ipu = ipu; irq_map[i].irq = irq; irq_map[i].source = -EINVAL; - set_irq_handler(irq, handle_level_irq); + irq_set_handler(irq, handle_level_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); #endif } - set_irq_data(ipu->irq_fn, ipu); - set_irq_chained_handler(ipu->irq_fn, ipu_irq_fn); + irq_set_handler_data(ipu->irq_fn, ipu); + irq_set_chained_handler(ipu->irq_fn, ipu_irq_fn); - set_irq_data(ipu->irq_err, ipu); - set_irq_chained_handler(ipu->irq_err, ipu_irq_err); + irq_set_handler_data(ipu->irq_err, ipu); + irq_set_chained_handler(ipu->irq_err, ipu_irq_err); return 0; } @@ -397,17 +397,17 @@ void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev) irq_base = pdata->irq_base; - set_irq_chained_handler(ipu->irq_fn, NULL); - set_irq_data(ipu->irq_fn, NULL); + irq_set_chained_handler(ipu->irq_fn, NULL); + irq_set_handler_data(ipu->irq_fn, NULL); - set_irq_chained_handler(ipu->irq_err, NULL); - set_irq_data(ipu->irq_err, NULL); + irq_set_chained_handler(ipu->irq_err, NULL); + irq_set_handler_data(ipu->irq_err, NULL); for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) { #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip(irq, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip(irq, NULL); + irq_set_chip_data(irq, NULL); } } -- cgit v1.2.2 From adb4b83c12f9d966ea3478aa14c60511467c9916 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 15 Mar 2010 07:28:00 -0500 Subject: kgdboc,kgdbts: strlen() doesn't count the terminator This is an off by one because strlen() doesn't count the null terminator. We strcpy() these strings into an array of size MAX_CONFIG_LEN. Signed-off-by: Dan Carpenter Signed-off-by: Jason Wessel --- drivers/misc/kgdbts.c | 2 +- drivers/tty/serial/kgdboc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 59c118c19a91..27dc463097f3 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -988,7 +988,7 @@ static void kgdbts_run_tests(void) static int kgdbts_option_setup(char *opt) { - if (strlen(opt) > MAX_CONFIG_LEN) { + if (strlen(opt) >= MAX_CONFIG_LEN) { printk(KERN_ERR "kgdbts: config string too long\n"); return -ENOSPC; } diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 25a8bc565f40..87e7e6c876d4 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -131,7 +131,7 @@ static void kgdboc_unregister_kbd(void) static int kgdboc_option_setup(char *opt) { - if (strlen(opt) > MAX_CONFIG_LEN) { + if (strlen(opt) >= MAX_CONFIG_LEN) { printk(KERN_ERR "kgdboc: config string too long\n"); return -ENOSPC; } -- cgit v1.2.2 From 9263412501022fecef844907129ee2513b5a89de Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Fri, 25 Mar 2011 01:56:59 -0700 Subject: memstick: add driver for Ricoh R5C592 card reader Signed-off-by: Maxim Levitsky Acked-by: Alex Dubov Cc: FUJITA Tomonori Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/memstick/host/Kconfig | 12 + drivers/memstick/host/Makefile | 1 + drivers/memstick/host/r592.c | 908 +++++++++++++++++++++++++++++++++++++++++ drivers/memstick/host/r592.h | 175 ++++++++ 4 files changed, 1096 insertions(+) create mode 100644 drivers/memstick/host/r592.c create mode 100644 drivers/memstick/host/r592.h (limited to 'drivers') diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index 4ce5c8dffb68..cc0997a05171 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig @@ -30,3 +30,15 @@ config MEMSTICK_JMICRON_38X To compile this driver as a module, choose M here: the module will be called jmb38x_ms. + +config MEMSTICK_R592 + tristate "Ricoh R5C592 MemoryStick interface support (EXPERIMENTAL)" + depends on EXPERIMENTAL && PCI + + help + Say Y here if you want to be able to access MemoryStick cards with + the Ricoh R5C592 MemoryStick card reader (which is part of 5 in one + multifunction reader) + + To compile this driver as a module, choose M here: the module will + be called r592. diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index a1815e9dd019..31ba8d378e46 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o +obj-$(CONFIG_MEMSTICK_R592) += r592.o diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c new file mode 100644 index 000000000000..767406c95291 --- /dev/null +++ b/drivers/memstick/host/r592.c @@ -0,0 +1,908 @@ +/* + * Copyright (C) 2010 - Maxim Levitsky + * driver for Ricoh memstick readers + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "r592.h" + +static int enable_dma = 1; +static int debug; + +static const char *tpc_names[] = { + "MS_TPC_READ_MG_STATUS", + "MS_TPC_READ_LONG_DATA", + "MS_TPC_READ_SHORT_DATA", + "MS_TPC_READ_REG", + "MS_TPC_READ_QUAD_DATA", + "INVALID", + "MS_TPC_GET_INT", + "MS_TPC_SET_RW_REG_ADRS", + "MS_TPC_EX_SET_CMD", + "MS_TPC_WRITE_QUAD_DATA", + "MS_TPC_WRITE_REG", + "MS_TPC_WRITE_SHORT_DATA", + "MS_TPC_WRITE_LONG_DATA", + "MS_TPC_SET_CMD", +}; + +/** + * memstick_debug_get_tpc_name - debug helper that returns string for + * a TPC number + */ +const char *memstick_debug_get_tpc_name(int tpc) +{ + return tpc_names[tpc-1]; +} +EXPORT_SYMBOL(memstick_debug_get_tpc_name); + + +/* Read a register*/ +static inline u32 r592_read_reg(struct r592_device *dev, int address) +{ + u32 value = readl(dev->mmio + address); + dbg_reg("reg #%02d == 0x%08x", address, value); + return value; +} + +/* Write a register */ +static inline void r592_write_reg(struct r592_device *dev, + int address, u32 value) +{ + dbg_reg("reg #%02d <- 0x%08x", address, value); + writel(value, dev->mmio + address); +} + +/* Reads a big endian DWORD register */ +static inline u32 r592_read_reg_raw_be(struct r592_device *dev, int address) +{ + u32 value = __raw_readl(dev->mmio + address); + dbg_reg("reg #%02d == 0x%08x", address, value); + return be32_to_cpu(value); +} + +/* Writes a big endian DWORD register */ +static inline void r592_write_reg_raw_be(struct r592_device *dev, + int address, u32 value) +{ + dbg_reg("reg #%02d <- 0x%08x", address, value); + __raw_writel(cpu_to_be32(value), dev->mmio + address); +} + +/* Set specific bits in a register (little endian) */ +static inline void r592_set_reg_mask(struct r592_device *dev, + int address, u32 mask) +{ + u32 reg = readl(dev->mmio + address); + dbg_reg("reg #%02d |= 0x%08x (old =0x%08x)", address, mask, reg); + writel(reg | mask , dev->mmio + address); +} + +/* Clear specific bits in a register (little endian) */ +static inline void r592_clear_reg_mask(struct r592_device *dev, + int address, u32 mask) +{ + u32 reg = readl(dev->mmio + address); + dbg_reg("reg #%02d &= 0x%08x (old = 0x%08x, mask = 0x%08x)", + address, ~mask, reg, mask); + writel(reg & ~mask, dev->mmio + address); +} + + +/* Wait for status bits while checking for errors */ +static int r592_wait_status(struct r592_device *dev, u32 mask, u32 wanted_mask) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + u32 reg = r592_read_reg(dev, R592_STATUS); + + if ((reg & mask) == wanted_mask) + return 0; + + while (time_before(jiffies, timeout)) { + + reg = r592_read_reg(dev, R592_STATUS); + + if ((reg & mask) == wanted_mask) + return 0; + + if (reg & (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR)) + return -EIO; + + cpu_relax(); + } + return -ETIME; +} + + +/* Enable/disable device */ +static int r592_enable_device(struct r592_device *dev, bool enable) +{ + dbg("%sabling the device", enable ? "en" : "dis"); + + if (enable) { + + /* Power up the card */ + r592_write_reg(dev, R592_POWER, R592_POWER_0 | R592_POWER_1); + + /* Perform a reset */ + r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); + + msleep(100); + } else + /* Power down the card */ + r592_write_reg(dev, R592_POWER, 0); + + return 0; +} + +/* Set serial/parallel mode */ +static int r592_set_mode(struct r592_device *dev, bool parallel_mode) +{ + if (!parallel_mode) { + dbg("switching to serial mode"); + + /* Set serial mode */ + r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_SERIAL); + + r592_clear_reg_mask(dev, R592_POWER, R592_POWER_20); + + } else { + dbg("switching to parallel mode"); + + /* This setting should be set _before_ switch TPC */ + r592_set_reg_mask(dev, R592_POWER, R592_POWER_20); + + r592_clear_reg_mask(dev, R592_IO, + R592_IO_SERIAL1 | R592_IO_SERIAL2); + + /* Set the parallel mode now */ + r592_write_reg(dev, R592_IO_MODE, R592_IO_MODE_PARALLEL); + } + + dev->parallel_mode = parallel_mode; + return 0; +} + +/* Perform a controller reset without powering down the card */ +static void r592_host_reset(struct r592_device *dev) +{ + r592_set_reg_mask(dev, R592_IO, R592_IO_RESET); + msleep(100); + r592_set_mode(dev, dev->parallel_mode); +} + +/* Disable all hardware interrupts */ +static void r592_clear_interrupts(struct r592_device *dev) +{ + /* Disable & ACK all interrupts */ + r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_ACK_MASK); + r592_clear_reg_mask(dev, R592_REG_MSC, IRQ_ALL_EN_MASK); +} + +/* Tests if there is an CRC error */ +static int r592_test_io_error(struct r592_device *dev) +{ + if (!(r592_read_reg(dev, R592_STATUS) & + (R592_STATUS_SEND_ERR | R592_STATUS_RECV_ERR))) + return 0; + + return -EIO; +} + +/* Ensure that FIFO is ready for use */ +static int r592_test_fifo_empty(struct r592_device *dev) +{ + if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) + return 0; + + dbg("FIFO not ready, trying to reset the device"); + r592_host_reset(dev); + + if (r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_FIFO_EMPTY) + return 0; + + message("FIFO still not ready, giving up"); + return -EIO; +} + +/* Activates the DMA transfer from to FIFO */ +static void r592_start_dma(struct r592_device *dev, bool is_write) +{ + unsigned long flags; + u32 reg; + spin_lock_irqsave(&dev->irq_lock, flags); + + /* Ack interrupts (just in case) + enable them */ + r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); + r592_set_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); + + /* Set DMA address */ + r592_write_reg(dev, R592_FIFO_DMA, sg_dma_address(&dev->req->sg)); + + /* Enable the DMA */ + reg = r592_read_reg(dev, R592_FIFO_DMA_SETTINGS); + reg |= R592_FIFO_DMA_SETTINGS_EN; + + if (!is_write) + reg |= R592_FIFO_DMA_SETTINGS_DIR; + else + reg &= ~R592_FIFO_DMA_SETTINGS_DIR; + r592_write_reg(dev, R592_FIFO_DMA_SETTINGS, reg); + + spin_unlock_irqrestore(&dev->irq_lock, flags); +} + +/* Cleanups DMA related settings */ +static void r592_stop_dma(struct r592_device *dev, int error) +{ + r592_clear_reg_mask(dev, R592_FIFO_DMA_SETTINGS, + R592_FIFO_DMA_SETTINGS_EN); + + /* This is only a precation */ + r592_write_reg(dev, R592_FIFO_DMA, + dev->dummy_dma_page_physical_address); + + r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_EN_MASK); + r592_clear_reg_mask(dev, R592_REG_MSC, DMA_IRQ_ACK_MASK); + dev->dma_error = error; +} + +/* Test if hardware supports DMA */ +static void r592_check_dma(struct r592_device *dev) +{ + dev->dma_capable = enable_dma && + (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & + R592_FIFO_DMA_SETTINGS_CAP); +} + +/* Transfers fifo contents in/out using DMA */ +static int r592_transfer_fifo_dma(struct r592_device *dev) +{ + int len, sg_count; + bool is_write; + + if (!dev->dma_capable || !dev->req->long_data) + return -EINVAL; + + len = dev->req->sg.length; + is_write = dev->req->data_dir == WRITE; + + if (len != R592_LFIFO_SIZE) + return -EINVAL; + + dbg_verbose("doing dma transfer"); + + dev->dma_error = 0; + INIT_COMPLETION(dev->dma_done); + + /* TODO: hidden assumption about nenth beeing always 1 */ + sg_count = dma_map_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? + PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + + if (sg_count != 1 || + (sg_dma_len(&dev->req->sg) < dev->req->sg.length)) { + message("problem in dma_map_sg"); + return -EIO; + } + + r592_start_dma(dev, is_write); + + /* Wait for DMA completion */ + if (!wait_for_completion_timeout( + &dev->dma_done, msecs_to_jiffies(1000))) { + message("DMA timeout"); + r592_stop_dma(dev, -ETIMEDOUT); + } + + dma_unmap_sg(&dev->pci_dev->dev, &dev->req->sg, 1, is_write ? + PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + + + return dev->dma_error; +} + +/* + * Writes the FIFO in 4 byte chunks. + * If length isn't 4 byte aligned, rest of the data if put to a fifo + * to be written later + * Use r592_flush_fifo_write to flush that fifo when writing for the + * last time + */ +static void r592_write_fifo_pio(struct r592_device *dev, + unsigned char *buffer, int len) +{ + /* flush spill from former write */ + if (!kfifo_is_empty(&dev->pio_fifo)) { + + u8 tmp[4] = {0}; + int copy_len = kfifo_in(&dev->pio_fifo, buffer, len); + + if (!kfifo_is_full(&dev->pio_fifo)) + return; + len -= copy_len; + buffer += copy_len; + + copy_len = kfifo_out(&dev->pio_fifo, tmp, 4); + WARN_ON(copy_len != 4); + r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)tmp); + } + + WARN_ON(!kfifo_is_empty(&dev->pio_fifo)); + + /* write full dwords */ + while (len >= 4) { + r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); + buffer += 4; + len -= 4; + } + + /* put remaining bytes to the spill */ + if (len) + kfifo_in(&dev->pio_fifo, buffer, len); +} + +/* Flushes the temporary FIFO used to make aligned DWORD writes */ +static void r592_flush_fifo_write(struct r592_device *dev) +{ + u8 buffer[4] = { 0 }; + int len; + + if (kfifo_is_empty(&dev->pio_fifo)) + return; + + len = kfifo_out(&dev->pio_fifo, buffer, 4); + r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer); +} + +/* + * Read a fifo in 4 bytes chunks. + * If input doesn't fit the buffer, it places bytes of last dword in spill + * buffer, so that they don't get lost on last read, just throw these away. + */ +static void r592_read_fifo_pio(struct r592_device *dev, + unsigned char *buffer, int len) +{ + u8 tmp[4]; + + /* Read from last spill */ + if (!kfifo_is_empty(&dev->pio_fifo)) { + int bytes_copied = + kfifo_out(&dev->pio_fifo, buffer, min(4, len)); + buffer += bytes_copied; + len -= bytes_copied; + + if (!kfifo_is_empty(&dev->pio_fifo)) + return; + } + + /* Reads dwords from FIFO */ + while (len >= 4) { + *(u32 *)buffer = r592_read_reg_raw_be(dev, R592_FIFO_PIO); + buffer += 4; + len -= 4; + } + + if (len) { + *(u32 *)tmp = r592_read_reg_raw_be(dev, R592_FIFO_PIO); + kfifo_in(&dev->pio_fifo, tmp, 4); + len -= kfifo_out(&dev->pio_fifo, buffer, len); + } + + WARN_ON(len); + return; +} + +/* Transfers actual data using PIO. */ +static int r592_transfer_fifo_pio(struct r592_device *dev) +{ + unsigned long flags; + + bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; + struct sg_mapping_iter miter; + + kfifo_reset(&dev->pio_fifo); + + if (!dev->req->long_data) { + if (is_write) { + r592_write_fifo_pio(dev, dev->req->data, + dev->req->data_len); + r592_flush_fifo_write(dev); + } else + r592_read_fifo_pio(dev, dev->req->data, + dev->req->data_len); + return 0; + } + + local_irq_save(flags); + sg_miter_start(&miter, &dev->req->sg, 1, SG_MITER_ATOMIC | + (is_write ? SG_MITER_FROM_SG : SG_MITER_TO_SG)); + + /* Do the transfer fifo<->memory*/ + while (sg_miter_next(&miter)) + if (is_write) + r592_write_fifo_pio(dev, miter.addr, miter.length); + else + r592_read_fifo_pio(dev, miter.addr, miter.length); + + + /* Write last few non aligned bytes*/ + if (is_write) + r592_flush_fifo_write(dev); + + sg_miter_stop(&miter); + local_irq_restore(flags); + return 0; +} + +/* Executes one TPC (data is read/written from small or large fifo) */ +static void r592_execute_tpc(struct r592_device *dev) +{ + bool is_write = dev->req->tpc >= MS_TPC_SET_RW_REG_ADRS; + int len, error; + u32 status, reg; + + if (!dev->req) { + message("BUG: tpc execution without request!"); + return; + } + + len = dev->req->long_data ? + dev->req->sg.length : dev->req->data_len; + + /* Ensure that FIFO can hold the input data */ + if (len > R592_LFIFO_SIZE) { + message("IO: hardware doesn't support TPCs longer that 512"); + error = -ENOSYS; + goto out; + } + + if (!(r592_read_reg(dev, R592_REG_MSC) & R592_REG_MSC_PRSNT)) { + dbg("IO: refusing to send TPC because card is absent"); + error = -ENODEV; + goto out; + } + + dbg("IO: executing %s LEN=%d", + memstick_debug_get_tpc_name(dev->req->tpc), len); + + /* Set IO direction */ + if (is_write) + r592_set_reg_mask(dev, R592_IO, R592_IO_DIRECTION); + else + r592_clear_reg_mask(dev, R592_IO, R592_IO_DIRECTION); + + + error = r592_test_fifo_empty(dev); + if (error) + goto out; + + /* Transfer write data */ + if (is_write) { + error = r592_transfer_fifo_dma(dev); + if (error == -EINVAL) + error = r592_transfer_fifo_pio(dev); + } + + if (error) + goto out; + + /* Trigger the TPC */ + reg = (len << R592_TPC_EXEC_LEN_SHIFT) | + (dev->req->tpc << R592_TPC_EXEC_TPC_SHIFT) | + R592_TPC_EXEC_BIG_FIFO; + + r592_write_reg(dev, R592_TPC_EXEC, reg); + + /* Wait for TPC completion */ + status = R592_STATUS_RDY; + if (dev->req->need_card_int) + status |= R592_STATUS_CED; + + error = r592_wait_status(dev, status, status); + if (error) { + message("card didn't respond"); + goto out; + } + + /* Test IO errors */ + error = r592_test_io_error(dev); + if (error) { + dbg("IO error"); + goto out; + } + + /* Read data from FIFO */ + if (!is_write) { + error = r592_transfer_fifo_dma(dev); + if (error == -EINVAL) + error = r592_transfer_fifo_pio(dev); + } + + /* read INT reg. This can be shortened with shifts, but that way + its more readable */ + if (dev->parallel_mode && dev->req->need_card_int) { + + dev->req->int_reg = 0; + status = r592_read_reg(dev, R592_STATUS); + + if (status & R592_STATUS_P_CMDNACK) + dev->req->int_reg |= MEMSTICK_INT_CMDNAK; + if (status & R592_STATUS_P_BREQ) + dev->req->int_reg |= MEMSTICK_INT_BREQ; + if (status & R592_STATUS_P_INTERR) + dev->req->int_reg |= MEMSTICK_INT_ERR; + if (status & R592_STATUS_P_CED) + dev->req->int_reg |= MEMSTICK_INT_CED; + } + + if (error) + dbg("FIFO read error"); +out: + dev->req->error = error; + r592_clear_reg_mask(dev, R592_REG_MSC, R592_REG_MSC_LED); + return; +} + +/* Main request processing thread */ +static int r592_process_thread(void *data) +{ + int error; + struct r592_device *dev = (struct r592_device *)data; + unsigned long flags; + + while (!kthread_should_stop()) { + spin_lock_irqsave(&dev->io_thread_lock, flags); + set_current_state(TASK_INTERRUPTIBLE); + error = memstick_next_req(dev->host, &dev->req); + spin_unlock_irqrestore(&dev->io_thread_lock, flags); + + if (error) { + if (error == -ENXIO || error == -EAGAIN) { + dbg_verbose("IO: done IO, sleeping"); + } else { + dbg("IO: unknown error from " + "memstick_next_req %d", error); + } + + if (kthread_should_stop()) + set_current_state(TASK_RUNNING); + + schedule(); + } else { + set_current_state(TASK_RUNNING); + r592_execute_tpc(dev); + } + } + return 0; +} + +/* Reprogram chip to detect change in card state */ +/* eg, if card is detected, arm it to detect removal, and vice versa */ +static void r592_update_card_detect(struct r592_device *dev) +{ + u32 reg = r592_read_reg(dev, R592_REG_MSC); + bool card_detected = reg & R592_REG_MSC_PRSNT; + + dbg("update card detect. card state: %s", card_detected ? + "present" : "absent"); + + reg &= ~((R592_REG_MSC_IRQ_REMOVE | R592_REG_MSC_IRQ_INSERT) << 16); + + if (card_detected) + reg |= (R592_REG_MSC_IRQ_REMOVE << 16); + else + reg |= (R592_REG_MSC_IRQ_INSERT << 16); + + r592_write_reg(dev, R592_REG_MSC, reg); +} + +/* Timer routine that fires 1 second after last card detection event, */ +static void r592_detect_timer(long unsigned int data) +{ + struct r592_device *dev = (struct r592_device *)data; + r592_update_card_detect(dev); + memstick_detect_change(dev->host); +} + +/* Interrupt handler */ +static irqreturn_t r592_irq(int irq, void *data) +{ + struct r592_device *dev = (struct r592_device *)data; + irqreturn_t ret = IRQ_NONE; + u32 reg; + u16 irq_enable, irq_status; + unsigned long flags; + int error; + + spin_lock_irqsave(&dev->irq_lock, flags); + + reg = r592_read_reg(dev, R592_REG_MSC); + irq_enable = reg >> 16; + irq_status = reg & 0xFFFF; + + /* Ack the interrupts */ + reg &= ~irq_status; + r592_write_reg(dev, R592_REG_MSC, reg); + + /* Get the IRQ status minus bits that aren't enabled */ + irq_status &= (irq_enable); + + /* Due to limitation of memstick core, we don't look at bits that + indicate that card was removed/inserted and/or present */ + if (irq_status & (R592_REG_MSC_IRQ_INSERT | R592_REG_MSC_IRQ_REMOVE)) { + + bool card_was_added = irq_status & R592_REG_MSC_IRQ_INSERT; + ret = IRQ_HANDLED; + + message("IRQ: card %s", card_was_added ? "added" : "removed"); + + mod_timer(&dev->detect_timer, + jiffies + msecs_to_jiffies(card_was_added ? 500 : 50)); + } + + if (irq_status & + (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR)) { + ret = IRQ_HANDLED; + + if (irq_status & R592_REG_MSC_FIFO_DMA_ERR) { + message("IRQ: DMA error"); + error = -EIO; + } else { + dbg_verbose("IRQ: dma done"); + error = 0; + } + + r592_stop_dma(dev, error); + complete(&dev->dma_done); + } + + spin_unlock_irqrestore(&dev->irq_lock, flags); + return ret; +} + +/* External inteface: set settings */ +static int r592_set_param(struct memstick_host *host, + enum memstick_param param, int value) +{ + struct r592_device *dev = memstick_priv(host); + + switch (param) { + case MEMSTICK_POWER: + switch (value) { + case MEMSTICK_POWER_ON: + return r592_enable_device(dev, true); + case MEMSTICK_POWER_OFF: + return r592_enable_device(dev, false); + default: + return -EINVAL; + } + case MEMSTICK_INTERFACE: + switch (value) { + case MEMSTICK_SERIAL: + return r592_set_mode(dev, 0); + case MEMSTICK_PAR4: + return r592_set_mode(dev, 1); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + +/* External interface: submit requests */ +static void r592_submit_req(struct memstick_host *host) +{ + struct r592_device *dev = memstick_priv(host); + unsigned long flags; + + if (dev->req) + return; + + spin_lock_irqsave(&dev->io_thread_lock, flags); + if (wake_up_process(dev->io_thread)) + dbg_verbose("IO thread woken to process requests"); + spin_unlock_irqrestore(&dev->io_thread_lock, flags); +} + +static const struct pci_device_id r592_pci_id_tbl[] = { + + { PCI_VDEVICE(RICOH, 0x0592), }, + { }, +}; + +/* Main entry */ +static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int error = -ENOMEM; + struct memstick_host *host; + struct r592_device *dev; + + /* Allocate memory */ + host = memstick_alloc_host(sizeof(struct r592_device), &pdev->dev); + if (!host) + goto error1; + + dev = memstick_priv(host); + dev->host = host; + dev->pci_dev = pdev; + pci_set_drvdata(pdev, dev); + + /* pci initialization */ + error = pci_enable_device(pdev); + if (error) + goto error2; + + pci_set_master(pdev); + error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (error) + goto error3; + + error = pci_request_regions(pdev, DRV_NAME); + if (error) + goto error3; + + dev->mmio = pci_ioremap_bar(pdev, 0); + if (!dev->mmio) + goto error4; + + dev->irq = pdev->irq; + spin_lock_init(&dev->irq_lock); + spin_lock_init(&dev->io_thread_lock); + init_completion(&dev->dma_done); + INIT_KFIFO(dev->pio_fifo); + setup_timer(&dev->detect_timer, + r592_detect_timer, (long unsigned int)dev); + + /* Host initialization */ + host->caps = MEMSTICK_CAP_PAR4; + host->request = r592_submit_req; + host->set_param = r592_set_param; + r592_check_dma(dev); + + dev->io_thread = kthread_run(r592_process_thread, dev, "r592_io"); + if (IS_ERR(dev->io_thread)) { + error = PTR_ERR(dev->io_thread); + goto error5; + } + + /* This is just a precation, so don't fail */ + dev->dummy_dma_page = pci_alloc_consistent(pdev, PAGE_SIZE, + &dev->dummy_dma_page_physical_address); + r592_stop_dma(dev , 0); + + if (request_irq(dev->irq, &r592_irq, IRQF_SHARED, + DRV_NAME, dev)) + goto error6; + + r592_update_card_detect(dev); + if (memstick_add_host(host)) + goto error7; + + message("driver succesfully loaded"); + return 0; +error7: + free_irq(dev->irq, dev); +error6: + if (dev->dummy_dma_page) + pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page, + dev->dummy_dma_page_physical_address); + + kthread_stop(dev->io_thread); +error5: + iounmap(dev->mmio); +error4: + pci_release_regions(pdev); +error3: + pci_disable_device(pdev); +error2: + memstick_free_host(host); +error1: + return error; +} + +static void r592_remove(struct pci_dev *pdev) +{ + int error = 0; + struct r592_device *dev = pci_get_drvdata(pdev); + + /* Stop the processing thread. + That ensures that we won't take any more requests */ + kthread_stop(dev->io_thread); + + r592_enable_device(dev, false); + + while (!error && dev->req) { + dev->req->error = -ETIME; + error = memstick_next_req(dev->host, &dev->req); + } + memstick_remove_host(dev->host); + + free_irq(dev->irq, dev); + iounmap(dev->mmio); + pci_release_regions(pdev); + pci_disable_device(pdev); + memstick_free_host(dev->host); + + if (dev->dummy_dma_page) + pci_free_consistent(pdev, PAGE_SIZE, dev->dummy_dma_page, + dev->dummy_dma_page_physical_address); +} + +#ifdef CONFIG_PM +static int r592_suspend(struct device *core_dev) +{ + struct pci_dev *pdev = to_pci_dev(core_dev); + struct r592_device *dev = pci_get_drvdata(pdev); + + r592_clear_interrupts(dev); + memstick_suspend_host(dev->host); + del_timer_sync(&dev->detect_timer); + return 0; +} + +static int r592_resume(struct device *core_dev) +{ + struct pci_dev *pdev = to_pci_dev(core_dev); + struct r592_device *dev = pci_get_drvdata(pdev); + + r592_clear_interrupts(dev); + r592_enable_device(dev, false); + memstick_resume_host(dev->host); + r592_update_card_detect(dev); + return 0; +} + +SIMPLE_DEV_PM_OPS(r592_pm_ops, r592_suspend, r592_resume); +#endif + +MODULE_DEVICE_TABLE(pci, r592_pci_id_tbl); + +static struct pci_driver r852_pci_driver = { + .name = DRV_NAME, + .id_table = r592_pci_id_tbl, + .probe = r592_probe, + .remove = r592_remove, +#ifdef CONFIG_PM + .driver.pm = &r592_pm_ops, +#endif +}; + +static __init int r592_module_init(void) +{ + return pci_register_driver(&r852_pci_driver); +} + +static void __exit r592_module_exit(void) +{ + pci_unregister_driver(&r852_pci_driver); +} + +module_init(r592_module_init); +module_exit(r592_module_exit); + +module_param(enable_dma, bool, S_IRUGO); +MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); +module_param(debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug level (0-3)"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Maxim Levitsky "); +MODULE_DESCRIPTION("Ricoh R5C592 Memstick/Memstick PRO card reader driver"); diff --git a/drivers/memstick/host/r592.h b/drivers/memstick/host/r592.h new file mode 100644 index 000000000000..eee264e6028f --- /dev/null +++ b/drivers/memstick/host/r592.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2010 - Maxim Levitsky + * driver for Ricoh memstick readers + * + * 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. + */ + +#ifndef R592_H + +#include +#include +#include +#include +#include +#include + +/* write to this reg (number,len) triggers TPC execution */ +#define R592_TPC_EXEC 0x00 +#define R592_TPC_EXEC_LEN_SHIFT 16 /* Bits 16..25 are TPC len */ +#define R592_TPC_EXEC_BIG_FIFO (1 << 26) /* If bit 26 is set, large fifo is used (reg 48) */ +#define R592_TPC_EXEC_TPC_SHIFT 28 /* Bits 28..31 are the TPC number */ + + +/* Window for small TPC fifo (big endian)*/ +/* reads and writes always are done in 8 byte chunks */ +/* Not used in driver, because large fifo does better job */ +#define R592_SFIFO 0x08 + + +/* Status register (ms int, small fifo, IO)*/ +#define R592_STATUS 0x10 + /* Parallel INT bits */ +#define R592_STATUS_P_CMDNACK (1 << 16) /* INT reg: NACK (parallel mode) */ +#define R592_STATUS_P_BREQ (1 << 17) /* INT reg: card ready (parallel mode)*/ +#define R592_STATUS_P_INTERR (1 << 18) /* INT reg: int error (parallel mode)*/ +#define R592_STATUS_P_CED (1 << 19) /* INT reg: command done (parallel mode) */ + + /* Fifo status */ +#define R592_STATUS_SFIFO_FULL (1 << 20) /* Small Fifo almost full (last chunk is written) */ +#define R592_STATUS_SFIFO_EMPTY (1 << 21) /* Small Fifo empty */ + + /* Error detection via CRC */ +#define R592_STATUS_SEND_ERR (1 << 24) /* Send failed */ +#define R592_STATUS_RECV_ERR (1 << 25) /* Recieve failed */ + + /* Card state */ +#define R592_STATUS_RDY (1 << 28) /* RDY signal recieved */ +#define R592_STATUS_CED (1 << 29) /* INT: Command done (serial mode)*/ +#define R592_STATUS_SFIFO_INPUT (1 << 30) /* Small fifo recieved data*/ + +#define R592_SFIFO_SIZE 32 /* total size of small fifo is 32 bytes */ +#define R592_SFIFO_PACKET 8 /* packet size of small fifo */ + +/* IO control */ +#define R592_IO 0x18 +#define R592_IO_16 (1 << 16) /* Set by default, can be cleared */ +#define R592_IO_18 (1 << 18) /* Set by default, can be cleared */ +#define R592_IO_SERIAL1 (1 << 20) /* Set by default, can be cleared, (cleared on parallel) */ +#define R592_IO_22 (1 << 22) /* Set by default, can be cleared */ +#define R592_IO_DIRECTION (1 << 24) /* TPC direction (1 write 0 read) */ +#define R592_IO_26 (1 << 26) /* Set by default, can be cleared */ +#define R592_IO_SERIAL2 (1 << 30) /* Set by default, can be cleared (cleared on parallel), serial doesn't work if unset */ +#define R592_IO_RESET (1 << 31) /* Reset, sets defaults*/ + + +/* Turns hardware on/off */ +#define R592_POWER 0x20 /* bits 0-7 writeable */ +#define R592_POWER_0 (1 << 0) /* set on start, cleared on stop - must be set*/ +#define R592_POWER_1 (1 << 1) /* set on start, cleared on stop - must be set*/ +#define R592_POWER_3 (1 << 3) /* must be clear */ +#define R592_POWER_20 (1 << 5) /* set before switch to parallel */ + +/* IO mode*/ +#define R592_IO_MODE 0x24 +#define R592_IO_MODE_SERIAL 1 +#define R592_IO_MODE_PARALLEL 3 + + +/* IRQ,card detection,large fifo (first word irq status, second enable) */ +/* IRQs are ACKed by clearing the bits */ +#define R592_REG_MSC 0x28 +#define R592_REG_MSC_PRSNT (1 << 1) /* card present (only status)*/ +#define R592_REG_MSC_IRQ_INSERT (1 << 8) /* detect insert / card insered */ +#define R592_REG_MSC_IRQ_REMOVE (1 << 9) /* detect removal / card removed */ +#define R592_REG_MSC_FIFO_EMPTY (1 << 10) /* fifo is empty */ +#define R592_REG_MSC_FIFO_DMA_DONE (1 << 11) /* dma enable / dma done */ + +#define R592_REG_MSC_FIFO_USER_ORN (1 << 12) /* set if software reads empty fifo (if R592_REG_MSC_FIFO_EMPTY is set) */ +#define R592_REG_MSC_FIFO_MISMATH (1 << 13) /* set if amount of data in fifo doesn't match amount in TPC */ +#define R592_REG_MSC_FIFO_DMA_ERR (1 << 14) /* IO failure */ +#define R592_REG_MSC_LED (1 << 15) /* clear to turn led off (only status)*/ + +#define DMA_IRQ_ACK_MASK \ + (R592_REG_MSC_FIFO_DMA_DONE | R592_REG_MSC_FIFO_DMA_ERR) + +#define DMA_IRQ_EN_MASK (DMA_IRQ_ACK_MASK << 16) + +#define IRQ_ALL_ACK_MASK 0x00007F00 +#define IRQ_ALL_EN_MASK (IRQ_ALL_ACK_MASK << 16) + +/* DMA address for large FIFO read/writes*/ +#define R592_FIFO_DMA 0x2C + +/* PIO access to large FIFO (512 bytes) (big endian)*/ +#define R592_FIFO_PIO 0x30 +#define R592_LFIFO_SIZE 512 /* large fifo size */ + + +/* large FIFO DMA settings */ +#define R592_FIFO_DMA_SETTINGS 0x34 +#define R592_FIFO_DMA_SETTINGS_EN (1 << 0) /* DMA enabled */ +#define R592_FIFO_DMA_SETTINGS_DIR (1 << 1) /* Dma direction (1 read, 0 write) */ +#define R592_FIFO_DMA_SETTINGS_CAP (1 << 24) /* Dma is aviable */ + +/* Maybe just an delay */ +/* Bits 17..19 are just number */ +/* bit 16 is set, then bit 20 is waited */ +/* time to wait is about 50 spins * 2 ^ (bits 17..19) */ +/* seems to be possible just to ignore */ +/* Probably debug register */ +#define R592_REG38 0x38 +#define R592_REG38_CHANGE (1 << 16) /* Start bit */ +#define R592_REG38_DONE (1 << 20) /* HW set this after the delay */ +#define R592_REG38_SHIFT 17 + +/* Debug register, written (0xABCDEF00) when error happens - not used*/ +#define R592_REG_3C 0x3C + +struct r592_device { + struct pci_dev *pci_dev; + struct memstick_host *host; /* host backpointer */ + struct memstick_request *req; /* current request */ + + /* Registers, IRQ */ + void __iomem *mmio; + int irq; + spinlock_t irq_lock; + spinlock_t io_thread_lock; + struct timer_list detect_timer; + + struct task_struct *io_thread; + bool parallel_mode; + + DECLARE_KFIFO(pio_fifo, u8, sizeof(u32)); + + /* DMA area */ + int dma_capable; + int dma_error; + struct completion dma_done; + void *dummy_dma_page; + dma_addr_t dummy_dma_page_physical_address; + +}; + +#define DRV_NAME "r592" + + +#define message(format, ...) \ + printk(KERN_INFO DRV_NAME ": " format "\n", ## __VA_ARGS__) + +#define __dbg(level, format, ...) \ + do { \ + if (debug >= level) \ + printk(KERN_DEBUG DRV_NAME \ + ": " format "\n", ## __VA_ARGS__); \ + } while (0) + + +#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__) +#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__) +#define dbg_reg(format, ...) __dbg(3, format, ## __VA_ARGS__) + +#endif -- cgit v1.2.2 From 2740c60c4ab9a8c6169d7925014f57440361f698 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 26 Mar 2011 10:45:01 +0100 Subject: hwmon: (f71882fg) Secure chip property definition arrays Using C99-style array initialization will ensure definitions won't drift if the chips enum gets new values added. Signed-off-by: Jean Delvare Acked-by: Hans de Goede Acked-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 54 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index a4d430ee7e20..0f60b058ff9d 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -119,37 +119,37 @@ static const char *f71882fg_names[] = { "f8000", }; -static const char f71882fg_has_in[8][F71882FG_MAX_INS] = { - { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, /* f71808e */ - { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f71858fg */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71862fg */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71869 */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71882fg */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889fg */ - { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889ed */ - { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f8000 */ +static const char f71882fg_has_in[][F71882FG_MAX_INS] = { + [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 }, + [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, + [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, }; -static const char f71882fg_has_in1_alarm[8] = { - 0, /* f71808e */ - 0, /* f71858fg */ - 0, /* f71862fg */ - 0, /* f71869 */ - 1, /* f71882fg */ - 1, /* f71889fg */ - 1, /* f71889ed */ - 0, /* f8000 */ +static const char f71882fg_has_in1_alarm[] = { + [f71808e] = 0, + [f71858fg] = 0, + [f71862fg] = 0, + [f71869] = 0, + [f71882fg] = 1, + [f71889fg] = 1, + [f71889ed] = 1, + [f8000] = 0, }; -static const char f71882fg_has_beep[8] = { - 0, /* f71808e */ - 0, /* f71858fg */ - 1, /* f71862fg */ - 1, /* f71869 */ - 1, /* f71882fg */ - 1, /* f71889fg */ - 1, /* f71889ed */ - 0, /* f8000 */ +static const char f71882fg_has_beep[] = { + [f71808e] = 0, + [f71858fg] = 0, + [f71862fg] = 1, + [f71869] = 1, + [f71882fg] = 1, + [f71889fg] = 1, + [f71889ed] = 1, + [f8000] = 0, }; static struct platform_device *f71882fg_pdev; -- cgit v1.2.2 From f27def07bfb296d5eb441cd5777d351c7afcb4a1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 26 Mar 2011 10:45:01 +0100 Subject: hwmon: (f71882fg) Per-chip fan/temperature input count tables Use tables to list the count of fan and temperature inputs for all supported chips, almost similar to (but more simple than) what is already done for voltage inputs. This avoids repeating the same tests in different functions, and will make it easier to add support for chips with a different count of fan or temperature inputs. Signed-off-by: Jean Delvare Acked-by: Hans de Goede Acked-by: Guenter Roeck --- drivers/hwmon/f71882fg.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 0f60b058ff9d..222c7f4a1e3f 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -152,6 +152,28 @@ static const char f71882fg_has_beep[] = { [f8000] = 0, }; +static const char f71882fg_nr_fans[] = { + [f71808e] = 3, + [f71858fg] = 3, + [f71862fg] = 3, + [f71869] = 3, + [f71882fg] = 4, + [f71889fg] = 3, + [f71889ed] = 3, + [f8000] = 3, +}; + +static const char f71882fg_nr_temps[] = { + [f71808e] = 2, + [f71858fg] = 3, + [f71862fg] = 3, + [f71869] = 3, + [f71882fg] = 3, + [f71889fg] = 3, + [f71889ed] = 3, + [f8000] = 3, +}; + static struct platform_device *f71882fg_pdev; /* Super-I/O Function prototypes */ @@ -1071,9 +1093,9 @@ static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) static struct f71882fg_data *f71882fg_update_device(struct device *dev) { struct f71882fg_data *data = dev_get_drvdata(dev); + int nr_fans = f71882fg_nr_fans[data->type]; + int nr_temps = f71882fg_nr_temps[data->type]; int nr, reg, point; - int nr_fans = (data->type == f71882fg) ? 4 : 3; - int nr_temps = (data->type == f71808e) ? 2 : 3; mutex_lock(&data->update_lock); @@ -2042,8 +2064,9 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) { struct f71882fg_data *data; struct f71882fg_sio_data *sio_data = pdev->dev.platform_data; - int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3; - int nr_temps = (sio_data->type == f71808e) ? 2 : 3; + int nr_fans = f71882fg_nr_fans[sio_data->type]; + int nr_temps = f71882fg_nr_temps[sio_data->type]; + int err, i; u8 start_reg, reg; data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL); @@ -2276,8 +2299,9 @@ exit_free: static int f71882fg_remove(struct platform_device *pdev) { struct f71882fg_data *data = platform_get_drvdata(pdev); - int i, nr_fans = (data->type == f71882fg) ? 4 : 3; - int nr_temps = (data->type == f71808e) ? 2 : 3; + int nr_fans = f71882fg_nr_fans[data->type]; + int nr_temps = f71882fg_nr_temps[data->type]; + int i; u8 start_reg = f71882fg_read8(data, F71882FG_REG_START); if (data->hwmon_dev) -- cgit v1.2.2 From 5d7f77bf66bfa986754b3e12073bef0ab8cd61bd Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 26 Mar 2011 10:45:02 +0100 Subject: hwmon: (f71882fg) Document all supported devices The list of supported devices was not always well documented in all places. Clarify and list all devices in documentation, Kconfig and the driver itself. Signed-off-by: Jean Delvare Acked-by: Hans de Goede Acked-by: Guenter Roeck --- drivers/hwmon/Kconfig | 16 +++++++++++++--- drivers/hwmon/f71882fg.c | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 81131eda5544..51255b366d09 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -315,11 +315,21 @@ config SENSORS_F71805F will be called f71805f. config SENSORS_F71882FG - tristate "Fintek F71858FG, F71862FG, F71882FG, F71889FG and F8000" + tristate "Fintek F71882FG and compatibles" help If you say yes here you get support for hardware monitoring - features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG, - F71889FG and F8000 Super-I/O chips. + features of many Fintek Super-I/O (LPC) chips. The currently + supported chips are: + F71808E + F71858FG + F71862FG + F71863FG + F71869F/E + F71882FG + F71883FG + F71889FG/ED + F8000 + F81801U This driver can also be built as a module. If so, the module will be called f71882fg. diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 222c7f4a1e3f..29879046fe53 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -114,7 +114,7 @@ static const char *f71882fg_names[] = { "f71862fg", "f71869", /* Both f71869f and f71869e, reg. compatible and same id */ "f71882fg", - "f71889fg", + "f71889fg", /* f81801u too, same id */ "f71889ed", "f8000", }; -- cgit v1.2.2 From 383586b12d89ba4297c49898645658cdb324b918 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 26 Mar 2011 10:45:02 +0100 Subject: hwmon: (f71882fg) Add support for the F81865F Add support for the Fintek F81865F. It's essentially compatible with the F71882FG, but has fewer inputs: 7 voltage, 2 temperature and 2 fan inputs only. Signed-off-by: Jean Delvare Acked-by: Hans de Goede Acked-by: Guenter Roeck --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/f71882fg.c | 22 ++++++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 51255b366d09..df9944bd47c4 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -330,6 +330,7 @@ config SENSORS_F71882FG F71889FG/ED F8000 F81801U + F81865F This driver can also be built as a module. If so, the module will be called f71882fg. diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 29879046fe53..aa8cf5d5c22e 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -55,6 +55,7 @@ #define SIO_F71889_ID 0x0723 /* Chipset ID */ #define SIO_F71889E_ID 0x0909 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ +#define SIO_F81865_ID 0x0704 /* Chipset ID */ #define REGION_LENGTH 8 #define ADDR_REG_OFFSET 5 @@ -106,7 +107,7 @@ module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg, - f71889ed, f8000 }; + f71889ed, f8000, f81865f }; static const char *f71882fg_names[] = { "f71808e", @@ -117,6 +118,7 @@ static const char *f71882fg_names[] = { "f71889fg", /* f81801u too, same id */ "f71889ed", "f8000", + "f81865f", }; static const char f71882fg_has_in[][F71882FG_MAX_INS] = { @@ -128,6 +130,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = { [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, + [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 }, }; static const char f71882fg_has_in1_alarm[] = { @@ -139,6 +142,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71889fg] = 1, [f71889ed] = 1, [f8000] = 0, + [f81865f] = 1, }; static const char f71882fg_has_beep[] = { @@ -150,6 +154,7 @@ static const char f71882fg_has_beep[] = { [f71889fg] = 1, [f71889ed] = 1, [f8000] = 0, + [f81865f] = 1, }; static const char f71882fg_nr_fans[] = { @@ -161,6 +166,7 @@ static const char f71882fg_nr_fans[] = { [f71889fg] = 3, [f71889ed] = 3, [f8000] = 3, + [f81865f] = 2, }; static const char f71882fg_nr_temps[] = { @@ -172,6 +178,7 @@ static const char f71882fg_nr_temps[] = { [f71889fg] = 3, [f71889ed] = 3, [f8000] = 3, + [f81865f] = 2, }; static struct platform_device *f71882fg_pdev; @@ -2186,16 +2193,12 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) case f71862fg: err = (data->pwm_enable & 0x15) != 0x15; break; - case f71808e: - case f71869: - case f71882fg: - case f71889fg: - case f71889ed: - err = 0; - break; case f8000: err = data->pwm_enable & 0x20; break; + default: + err = 0; + break; } if (err) { dev_err(&pdev->dev, @@ -2433,6 +2436,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, case SIO_F8000_ID: sio_data->type = f8000; break; + case SIO_F81865_ID: + sio_data->type = f81865f; + break; default: pr_info("Unsupported Fintek device: %04x\n", (unsigned int)devid); -- cgit v1.2.2 From a66c10887ad2a99e172111cc94087ba4bed8fa92 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 26 Mar 2011 10:45:02 +0100 Subject: hwmon: (f71882fg) Add support for the F71889A Signed-off-by: Hans de Goede Acked-by: Guenter Roeck Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 2 +- drivers/hwmon/f71882fg.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index df9944bd47c4..060ef6327876 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -327,7 +327,7 @@ config SENSORS_F71882FG F71869F/E F71882FG F71883FG - F71889FG/ED + F71889FG/ED/A F8000 F81801U F81865F diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index aa8cf5d5c22e..ca07a32447c2 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -54,6 +54,7 @@ #define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F71889_ID 0x0723 /* Chipset ID */ #define SIO_F71889E_ID 0x0909 /* Chipset ID */ +#define SIO_F71889A_ID 0x1005 /* Chipset ID */ #define SIO_F8000_ID 0x0581 /* Chipset ID */ #define SIO_F81865_ID 0x0704 /* Chipset ID */ @@ -107,7 +108,7 @@ module_param(force_id, ushort, 0); MODULE_PARM_DESC(force_id, "Override the detected device ID"); enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg, - f71889ed, f8000, f81865f }; + f71889ed, f71889a, f8000, f81865f }; static const char *f71882fg_names[] = { "f71808e", @@ -117,6 +118,7 @@ static const char *f71882fg_names[] = { "f71882fg", "f71889fg", /* f81801u too, same id */ "f71889ed", + "f71889a", "f8000", "f81865f", }; @@ -129,6 +131,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = { [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 }, }; @@ -141,6 +144,7 @@ static const char f71882fg_has_in1_alarm[] = { [f71882fg] = 1, [f71889fg] = 1, [f71889ed] = 1, + [f71889a] = 1, [f8000] = 0, [f81865f] = 1, }; @@ -153,6 +157,7 @@ static const char f71882fg_has_beep[] = { [f71882fg] = 1, [f71889fg] = 1, [f71889ed] = 1, + [f71889a] = 1, [f8000] = 0, [f81865f] = 1, }; @@ -165,6 +170,7 @@ static const char f71882fg_nr_fans[] = { [f71882fg] = 4, [f71889fg] = 3, [f71889ed] = 3, + [f71889a] = 3, [f8000] = 3, [f81865f] = 2, }; @@ -177,6 +183,7 @@ static const char f71882fg_nr_temps[] = { [f71882fg] = 3, [f71889fg] = 3, [f71889ed] = 3, + [f71889a] = 3, [f8000] = 3, [f81865f] = 2, }; @@ -2168,6 +2175,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) /* Fall through to select correct fan/pwm reg bank! */ case f71889fg: case f71889ed: + case f71889a: reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T); if (reg & F71882FG_FAN_NEG_TEMP_EN) data->auto_point_temp_signed = 1; @@ -2225,6 +2233,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) case f71869: case f71889fg: case f71889ed: + case f71889a: for (i = 0; i < nr_fans; i++) { data->pwm_auto_point_mapping[i] = f71882fg_read8(data, @@ -2433,6 +2442,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, case SIO_F71889E_ID: sio_data->type = f71889ed; break; + case SIO_F71889A_ID: + sio_data->type = f71889a; + break; case SIO_F8000_ID: sio_data->type = f8000; break; -- cgit v1.2.2 From 23c2f041efa891e6ec0706dc9ad4f776a9aa8c14 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 24 Feb 2011 17:39:09 +0000 Subject: regulator: If we fail when setting up a supply say which supply Makes it a bit easier to identify if it's a problem with the supplies, the usual error would be omitting the supply name entirely. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9fa20957847d..a2dc6223e8d2 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2565,8 +2565,11 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, init_data->consumer_supplies[i].dev, init_data->consumer_supplies[i].dev_name, init_data->consumer_supplies[i].supply); - if (ret < 0) + if (ret < 0) { + dev_err(dev, "Failed to set supply %s\n", + init_data->consumer_supplies[i].supply); goto unset_supplies; + } } list_add(&rdev->list, ®ulator_list); -- cgit v1.2.2 From dfda9c27ba15330f37453c389d775ecf9e981d05 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 1 Mar 2011 16:50:43 +0000 Subject: regulator: Convert WM831x regulators to genirq Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm831x-dcdc.c | 26 +++++++++++--------------- drivers/regulator/wm831x-isink.c | 8 +++----- drivers/regulator/wm831x-ldo.c | 17 +++++++---------- 3 files changed, 21 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 06df898842c0..857d741539da 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -565,9 +565,8 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "UV"); - ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq, - IRQF_TRIGGER_RISING, dcdc->name, - dcdc); + ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, + IRQF_TRIGGER_RISING, dcdc->name, dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); @@ -575,9 +574,8 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "HC"); - ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_oc_irq, - IRQF_TRIGGER_RISING, dcdc->name, - dcdc); + ret = request_threaded_irq(irq, NULL, wm831x_dcdc_oc_irq, + IRQF_TRIGGER_RISING, dcdc->name, dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d\n", irq, ret); @@ -589,7 +587,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) return 0; err_uv: - wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); + free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); err_regulator: regulator_unregister(dcdc->regulator); err: @@ -756,9 +754,8 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "UV"); - ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq, - IRQF_TRIGGER_RISING, dcdc->name, - dcdc); + ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, + IRQF_TRIGGER_RISING, dcdc->name, dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); @@ -885,9 +882,9 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "UV"); - ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq, - IRQF_TRIGGER_RISING, dcdc->name, - dcdc); + ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq, + IRQF_TRIGGER_RISING, dcdc->name, + dcdc); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); @@ -908,11 +905,10 @@ err: static __devexit int wm831x_boostp_remove(struct platform_device *pdev) { struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); - struct wm831x *wm831x = dcdc->wm831x; platform_set_drvdata(pdev, NULL); - wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); + free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); regulator_unregister(dcdc->regulator); kfree(dcdc); diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 6c446cd6ad54..01f27c7f4236 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -198,9 +198,8 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - ret = wm831x_request_irq(wm831x, irq, wm831x_isink_irq, - IRQF_TRIGGER_RISING, isink->name, - isink); + ret = request_threaded_irq(irq, NULL, wm831x_isink_irq, + IRQF_TRIGGER_RISING, isink->name, isink); if (ret != 0) { dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n", irq, ret); @@ -221,11 +220,10 @@ err: static __devexit int wm831x_isink_remove(struct platform_device *pdev) { struct wm831x_isink *isink = platform_get_drvdata(pdev); - struct wm831x *wm831x = isink->wm831x; platform_set_drvdata(pdev, NULL); - wm831x_free_irq(wm831x, platform_get_irq(pdev, 0), isink); + free_irq(platform_get_irq(pdev, 0), isink); regulator_unregister(isink->regulator); kfree(isink); diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index c94fc5b7cd5b..2220cf8defb1 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -354,9 +354,9 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "UV"); - ret = wm831x_request_irq(wm831x, irq, wm831x_ldo_uv_irq, - IRQF_TRIGGER_RISING, ldo->name, - ldo); + ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, + IRQF_TRIGGER_RISING, ldo->name, + ldo); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); @@ -377,11 +377,10 @@ err: static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - struct wm831x *wm831x = ldo->wm831x; platform_set_drvdata(pdev, NULL); - wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo); + free_irq(platform_get_irq_byname(pdev, "UV"), ldo); regulator_unregister(ldo->regulator); kfree(ldo); @@ -619,9 +618,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) } irq = platform_get_irq_byname(pdev, "UV"); - ret = wm831x_request_irq(wm831x, irq, wm831x_ldo_uv_irq, - IRQF_TRIGGER_RISING, ldo->name, - ldo); + ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq, + IRQF_TRIGGER_RISING, ldo->name, ldo); if (ret != 0) { dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n", irq, ret); @@ -642,9 +640,8 @@ err: static __devexit int wm831x_aldo_remove(struct platform_device *pdev) { struct wm831x_ldo *ldo = platform_get_drvdata(pdev); - struct wm831x *wm831x = ldo->wm831x; - wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo); + free_irq(platform_get_irq_byname(pdev, "UV"), ldo); regulator_unregister(ldo->regulator); kfree(ldo); -- cgit v1.2.2 From fb7c18cac8608983168a7f4f55193cea190c83c8 Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Tue, 1 Mar 2011 11:54:44 +0200 Subject: regulator: fix typo in Kconfig Fix typo: s/TPS695x0/TPS659x0/ Signed-off-by: Igor Grinberg Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index de75f67f4cc3..b9f29e0d4295 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -126,7 +126,7 @@ config REGULATOR_MAX8998 and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. config REGULATOR_TWL4030 - bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC" + bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" depends on TWL4030_CORE help This driver supports the voltage regulators provided by -- cgit v1.2.2 From 7a32b589a9c856493bccb02db55047edc04eee7b Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Fri, 11 Mar 2011 10:13:59 +0900 Subject: Regulator: add suspend-finish API for regulator core. The regulator core had suspend-prepare that turns off the regulators when entering a system-wide suspend. However, it did not have suspend-finish that pairs with suspend-prepare and the regulator core has assumed that the regulator devices and their drivers support autonomous recover at resume. This patch adds regulator_suspend_finish that pairs with the previously-existed regulator_suspend_prepare. The function regulator_suspend_finish turns on the regulators that have always_on set or positive use_count so that we can reset the regulator states appropriately at resume. In regulator_suspend_finish, if has_full_constraints, it disables unnecessary regulators. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Acked-by: Mark Brown -- Updates v3 comments corrected (Thanks to Igor) v2 disable unnecessary regulators (Thanks to Mark) Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a2dc6223e8d2..e611f6797e6a 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2655,6 +2655,47 @@ out: } EXPORT_SYMBOL_GPL(regulator_suspend_prepare); +/** + * regulator_suspend_finish - resume regulators from system wide suspend + * + * Turn on regulators that might be turned off by regulator_suspend_prepare + * and that should be turned on according to the regulators properties. + */ +int regulator_suspend_finish(void) +{ + struct regulator_dev *rdev; + int ret = 0, error; + + mutex_lock(®ulator_list_mutex); + list_for_each_entry(rdev, ®ulator_list, list) { + struct regulator_ops *ops = rdev->desc->ops; + + mutex_lock(&rdev->mutex); + if ((rdev->use_count > 0 || rdev->constraints->always_on) && + ops->enable) { + error = ops->enable(rdev); + if (error) + ret = error; + } else { + if (!has_full_constraints) + goto unlock; + if (!ops->disable) + goto unlock; + if (ops->is_enabled && !ops->is_enabled(rdev)) + goto unlock; + + error = ops->disable(rdev); + if (error) + ret = error; + } +unlock: + mutex_unlock(&rdev->mutex); + } + mutex_unlock(®ulator_list_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_suspend_finish); + /** * regulator_has_full_constraints - the system has fully specified constraints * -- cgit v1.2.2 From 19c98825941cb10b59c9953665fc4495bc82c0ae Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 11 Mar 2011 16:26:18 +0100 Subject: regulator: switch the ab3100 to use enable_time() Acked-by: Mark Brown This switches the ab3100 core to use the enable_time() infrastructure from the regulator core. Cc: Mattias Wallin Signed-off-by: Linus Walleij Signed-off-by: Liam Girdwood --- drivers/regulator/ab3100.c | 51 +++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 2dec589a8908..b1d77946e9c6 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -206,29 +206,6 @@ static int ab3100_enable_regulator(struct regulator_dev *reg) return err; } - /* Per-regulator power on delay from spec */ - switch (abreg->regreg) { - case AB3100_LDO_A: /* Fallthrough */ - case AB3100_LDO_C: /* Fallthrough */ - case AB3100_LDO_D: /* Fallthrough */ - case AB3100_LDO_E: /* Fallthrough */ - case AB3100_LDO_H: /* Fallthrough */ - case AB3100_LDO_K: - udelay(200); - break; - case AB3100_LDO_F: - udelay(600); - break; - case AB3100_LDO_G: - udelay(400); - break; - case AB3100_BUCK: - mdelay(1); - break; - default: - break; - } - return 0; } @@ -450,11 +427,37 @@ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg) return abreg->plfdata->external_voltage; } +static int ab3100_enable_time_regulator(struct regulator_dev *reg) +{ + struct ab3100_regulator *abreg = reg->reg_data; + + /* Per-regulator power on delay from spec */ + switch (abreg->regreg) { + case AB3100_LDO_A: /* Fallthrough */ + case AB3100_LDO_C: /* Fallthrough */ + case AB3100_LDO_D: /* Fallthrough */ + case AB3100_LDO_E: /* Fallthrough */ + case AB3100_LDO_H: /* Fallthrough */ + case AB3100_LDO_K: + return 200; + case AB3100_LDO_F: + return 600; + case AB3100_LDO_G: + return 400; + case AB3100_BUCK: + return 1000; + default: + break; + } + return 0; +} + static struct regulator_ops regulator_ops_fixed = { .enable = ab3100_enable_regulator, .disable = ab3100_disable_regulator, .is_enabled = ab3100_is_enabled_regulator, .get_voltage = ab3100_get_voltage_regulator, + .enable_time = ab3100_enable_time_regulator, }; static struct regulator_ops regulator_ops_variable = { @@ -464,6 +467,7 @@ static struct regulator_ops regulator_ops_variable = { .get_voltage = ab3100_get_voltage_regulator, .set_voltage = ab3100_set_voltage_regulator, .list_voltage = ab3100_list_voltage_regulator, + .enable_time = ab3100_enable_time_regulator, }; static struct regulator_ops regulator_ops_variable_sleepable = { @@ -474,6 +478,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = { .set_voltage = ab3100_set_voltage_regulator, .set_suspend_voltage = ab3100_set_suspend_voltage_regulator, .list_voltage = ab3100_list_voltage_regulator, + .enable_time = ab3100_enable_time_regulator, }; /* -- cgit v1.2.2 From ea05ef31f2aa98b25d14222300dc9c1d1eb59e41 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Thu, 10 Mar 2011 14:43:31 +0100 Subject: regulator: add support for USB voltage regulator Signed-off-by: Bengt Jonsson Signed-off-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index d9a052c53aec..5a77630095d9 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -9,7 +9,7 @@ * AB8500 peripheral regulators * * AB8500 supports the following regulators: - * VAUX1/2/3, VINTCORE, VTVOUT, VAUDIO, VAMIC1/2, VDMIC, VANA + * VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA */ #include #include @@ -432,6 +432,21 @@ static struct ab8500_regulator_info .update_mask = 0x82, .update_val_enable = 0x02, }, + [AB8500_LDO_USB] = { + .desc = { + .name = "LDO-USB", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_USB, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 3300000, + .update_bank = 0x03, + .update_reg = 0x82, + .update_mask = 0x03, + .update_val_enable = 0x01, + }, [AB8500_LDO_AUDIO] = { .desc = { .name = "LDO-AUDIO", -- cgit v1.2.2 From 79568b941277b5986a8a7f0fb8578b2ccfc3e87e Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 11 Mar 2011 11:54:46 +0100 Subject: regulator: initialization for ab8500 regulators The regulators on the AB8500 have a lot of custom hardware control settings pertaining to 8 external signals, settings which are board-specific and need be provided from the platform at startup. Initialization added for regulators Vana, VextSupply1, VextSupply2, VextSupply3, Vaux1, Vaux2, Vaux3, VTVout, Vintcore12, Vaudio, Vdmic, Vamic1, Vamic2, VrefDDR. Signed-off-by: Bengt Jonsson Reviewed-by: Rickard Andersson Reviewed-by: Jonas Aberg Signed-off-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 223 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 222 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 5a77630095d9..d157146c8655 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -526,6 +526,186 @@ static struct ab8500_regulator_info }; +struct ab8500_reg_init { + u8 bank; + u8 addr; + u8 mask; +}; + +#define REG_INIT(_id, _bank, _addr, _mask) \ + [_id] = { \ + .bank = _bank, \ + .addr = _addr, \ + .mask = _mask, \ + } + +static struct ab8500_reg_init ab8500_reg_init[] = { + /* + * 0x30, VanaRequestCtrl + * 0x0C, VpllRequestCtrl + * 0xc0, VextSupply1RequestCtrl + */ + REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc), + /* + * 0x03, VextSupply2RequestCtrl + * 0x0c, VextSupply3RequestCtrl + * 0x30, Vaux1RequestCtrl + * 0xc0, Vaux2RequestCtrl + */ + REG_INIT(AB8500_REGUREQUESTCTRL3, 0x03, 0x05, 0xff), + /* + * 0x03, Vaux3RequestCtrl + * 0x04, SwHPReq + */ + REG_INIT(AB8500_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), + /* + * 0x08, VanaSysClkReq1HPValid + * 0x20, Vaux1SysClkReq1HPValid + * 0x40, Vaux2SysClkReq1HPValid + * 0x80, Vaux3SysClkReq1HPValid + */ + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xe8), + /* + * 0x10, VextSupply1SysClkReq1HPValid + * 0x20, VextSupply2SysClkReq1HPValid + * 0x40, VextSupply3SysClkReq1HPValid + */ + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x70), + /* + * 0x08, VanaHwHPReq1Valid + * 0x20, Vaux1HwHPReq1Valid + * 0x40, Vaux2HwHPReq1Valid + * 0x80, Vaux3HwHPReq1Valid + */ + REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xe8), + /* + * 0x01, VextSupply1HwHPReq1Valid + * 0x02, VextSupply2HwHPReq1Valid + * 0x04, VextSupply3HwHPReq1Valid + */ + REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), + /* + * 0x08, VanaHwHPReq2Valid + * 0x20, Vaux1HwHPReq2Valid + * 0x40, Vaux2HwHPReq2Valid + * 0x80, Vaux3HwHPReq2Valid + */ + REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xe8), + /* + * 0x01, VextSupply1HwHPReq2Valid + * 0x02, VextSupply2HwHPReq2Valid + * 0x04, VextSupply3HwHPReq2Valid + */ + REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), + /* + * 0x20, VanaSwHPReqValid + * 0x80, Vaux1SwHPReqValid + */ + REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xa0), + /* + * 0x01, Vaux2SwHPReqValid + * 0x02, Vaux3SwHPReqValid + * 0x04, VextSupply1SwHPReqValid + * 0x08, VextSupply2SwHPReqValid + * 0x10, VextSupply3SwHPReqValid + */ + REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), + /* + * 0x02, SysClkReq2Valid1 + * ... + * 0x80, SysClkReq8Valid1 + */ + REG_INIT(AB8500_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe), + /* + * 0x02, SysClkReq2Valid2 + * ... + * 0x80, SysClkReq8Valid2 + */ + REG_INIT(AB8500_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe), + /* + * 0x02, VTVoutEna + * 0x04, Vintcore12Ena + * 0x38, Vintcore12Sel + * 0x40, Vintcore12LP + * 0x80, VTVoutLP + */ + REG_INIT(AB8500_REGUMISC1, 0x03, 0x80, 0xfe), + /* + * 0x02, VaudioEna + * 0x04, VdmicEna + * 0x08, Vamic1Ena + * 0x10, Vamic2Ena + */ + REG_INIT(AB8500_VAUDIOSUPPLY, 0x03, 0x83, 0x1e), + /* + * 0x01, Vamic1_dzout + * 0x02, Vamic2_dzout + */ + REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), + /* + * 0x0c, VanaRegu + * 0x03, VpllRegu + */ + REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f), + /* + * 0x01, VrefDDREna + * 0x02, VrefDDRSleepMode + */ + REG_INIT(AB8500_VREFDDR, 0x04, 0x07, 0x03), + /* + * 0x03, VextSupply1Regu + * 0x0c, VextSupply2Regu + * 0x30, VextSupply3Regu + * 0x40, ExtSupply2Bypass + * 0x80, ExtSupply3Bypass + */ + REG_INIT(AB8500_EXTSUPPLYREGU, 0x04, 0x08, 0xff), + /* + * 0x03, Vaux1Regu + * 0x0c, Vaux2Regu + */ + REG_INIT(AB8500_VAUX12REGU, 0x04, 0x09, 0x0f), + /* + * 0x03, Vaux3Regu + */ + REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03), + /* + * 0x3f, Vsmps1Sel1 + */ + REG_INIT(AB8500_VSMPS1SEL1, 0x04, 0x13, 0x3f), + /* + * 0x0f, Vaux1Sel + */ + REG_INIT(AB8500_VAUX1SEL, 0x04, 0x1f, 0x0f), + /* + * 0x0f, Vaux2Sel + */ + REG_INIT(AB8500_VAUX2SEL, 0x04, 0x20, 0x0f), + /* + * 0x07, Vaux3Sel + */ + REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x07), + /* + * 0x01, VextSupply12LP + */ + REG_INIT(AB8500_REGUCTRL2SPARE, 0x04, 0x22, 0x01), + /* + * 0x04, Vaux1Disch + * 0x08, Vaux2Disch + * 0x10, Vaux3Disch + * 0x20, Vintcore12Disch + * 0x40, VTVoutDisch + * 0x80, VaudioDisch + */ + REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xfc), + /* + * 0x02, VanaDisch + * 0x04, VdmicPullDownEna + * 0x10, VdmicDisch + */ + REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), +}; + static __devinit int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); @@ -544,10 +724,51 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) /* make sure the platform data has the correct size */ if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { - dev_err(&pdev->dev, "platform configuration error\n"); + dev_err(&pdev->dev, "Configuration error: size mismatch.\n"); return -EINVAL; } + /* initialize registers */ + for (i = 0; i < pdata->num_regulator_reg_init; i++) { + int id; + u8 value; + + id = pdata->regulator_reg_init[i].id; + value = pdata->regulator_reg_init[i].value; + + /* check for configuration errors */ + if (id >= AB8500_NUM_REGULATOR_REGISTERS) { + dev_err(&pdev->dev, + "Configuration error: id outside range.\n"); + return -EINVAL; + } + if (value & ~ab8500_reg_init[id].mask) { + dev_err(&pdev->dev, + "Configuration error: value outside mask.\n"); + return -EINVAL; + } + + /* initialize register */ + err = abx500_mask_and_set_register_interruptible(&pdev->dev, + ab8500_reg_init[id].bank, + ab8500_reg_init[id].addr, + ab8500_reg_init[id].mask, + value); + if (err < 0) { + dev_err(&pdev->dev, + "Failed to initialize 0x%02x, 0x%02x.\n", + ab8500_reg_init[id].bank, + ab8500_reg_init[id].addr); + return err; + } + dev_vdbg(&pdev->dev, + " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", + ab8500_reg_init[id].bank, + ab8500_reg_init[id].addr, + ab8500_reg_init[id].mask, + value); + } + /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; -- cgit v1.2.2 From 77af1b2641faf45788a0d480db94082ebee931dc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Mar 2011 13:24:36 +0100 Subject: regulator: add set_voltage_time_sel infrastructure This makes it possible to set the stabilization time for voltage regulators in the same manner as enable_time(). The interface only supports regulators that implements fixed selectors. Cc: Bengt Jonsson Signed-off-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e611f6797e6a..e7e4460dcb92 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1629,6 +1629,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) { int ret; + int delay = 0; unsigned int selector; trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); @@ -1662,6 +1663,22 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, } } + /* + * If we can't obtain the old selector there is not enough + * info to call set_voltage_time_sel(). + */ + if (rdev->desc->ops->set_voltage_time_sel && + rdev->desc->ops->get_voltage_sel) { + unsigned int old_selector = 0; + + ret = rdev->desc->ops->get_voltage_sel(rdev); + if (ret < 0) + return ret; + old_selector = ret; + delay = rdev->desc->ops->set_voltage_time_sel(rdev, + old_selector, selector); + } + if (best_val != INT_MAX) { ret = rdev->desc->ops->set_voltage_sel(rdev, selector); selector = best_val; @@ -1672,6 +1689,14 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, ret = -EINVAL; } + /* Insert any necessary delays */ + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } + if (ret == 0) _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); -- cgit v1.2.2 From 88cd222b259d62148ab8c82398498b1a01314476 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Mar 2011 13:24:52 +0100 Subject: regulator: provide consumer interface for fall/rise time This exposes the functionality for rise/fall fime when setting voltage to the consumers. Cc: Bengt Jonsson Signed-off-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/core.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e7e4460dcb92..3ffc6979d164 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1764,6 +1764,51 @@ out: } EXPORT_SYMBOL_GPL(regulator_set_voltage); +/** + * regulator_set_voltage_time - get raise/fall time + * @regulator: regulator source + * @old_uV: starting voltage in microvolts + * @new_uV: target voltage in microvolts + * + * Provided with the starting and ending voltage, this function attempts to + * calculate the time in microseconds required to rise or fall to this new + * voltage. + */ +int regulator_set_voltage_time(struct regulator *regulator, + int old_uV, int new_uV) +{ + struct regulator_dev *rdev = regulator->rdev; + struct regulator_ops *ops = rdev->desc->ops; + int old_sel = -1; + int new_sel = -1; + int voltage; + int i; + + /* Currently requires operations to do this */ + if (!ops->list_voltage || !ops->set_voltage_time_sel + || !rdev->desc->n_voltages) + return -EINVAL; + + for (i = 0; i < rdev->desc->n_voltages; i++) { + /* We only look for exact voltage matches here */ + voltage = regulator_list_voltage(regulator, i); + if (voltage < 0) + return -EINVAL; + if (voltage == 0) + continue; + if (voltage == old_uV) + old_sel = i; + if (voltage == new_uV) + new_sel = i; + } + + if (old_sel < 0 || new_sel < 0) + return -EINVAL; + + return ops->set_voltage_time_sel(rdev, old_sel, new_sel); +} +EXPORT_SYMBOL_GPL(regulator_set_voltage_time); + /** * regulator_sync_voltage - re-apply last regulator output voltage * @regulator: regulator source -- cgit v1.2.2 From 42ab616afe8844261828395cc2e4708c867412c2 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 17 Mar 2011 13:25:02 +0100 Subject: regulator: add ab8500 enable and raise time delays This uses the new infrastructure to provide proper delays when enabling or setting the voltage of one specific regulator. Cc: Bengt Jonsson Signed-off-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/ab8500.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index d157146c8655..02f3c2333c83 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -38,6 +38,7 @@ * @voltage_mask: mask to control regulator voltage * @voltages: supported voltage table * @voltages_len: number of supported voltages for the regulator + * @delay: startup/set voltage delay in us */ struct ab8500_regulator_info { struct device *dev; @@ -55,6 +56,7 @@ struct ab8500_regulator_info { u8 voltage_mask; int const *voltages; int voltages_len; + unsigned int delay; }; /* voltage tables for the vauxn/vintcore supplies */ @@ -290,6 +292,29 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, return ret; } +static int ab8500_regulator_enable_time(struct regulator_dev *rdev) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + + return info->delay; +} + +static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_sel, + unsigned int new_sel) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + /* If the regulator isn't on, it won't take time here */ + ret = ab8500_regulator_is_enabled(rdev); + if (ret < 0) + return ret; + if (!ret) + return 0; + return info->delay; +} + static struct regulator_ops ab8500_regulator_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, @@ -297,6 +322,8 @@ static struct regulator_ops ab8500_regulator_ops = { .get_voltage = ab8500_regulator_get_voltage, .set_voltage = ab8500_regulator_set_voltage, .list_voltage = ab8500_list_voltage, + .enable_time = ab8500_regulator_enable_time, + .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, }; static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) @@ -317,6 +344,8 @@ static struct regulator_ops ab8500_regulator_fixed_ops = { .is_enabled = ab8500_regulator_is_enabled, .get_voltage = ab8500_fixed_get_voltage, .list_voltage = ab8500_list_voltage, + .enable_time = ab8500_regulator_enable_time, + .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, }; static struct ab8500_regulator_info @@ -426,6 +455,7 @@ static struct ab8500_regulator_info .owner = THIS_MODULE, .n_voltages = 1, }, + .delay = 10000, .fixed_uV = 2000000, .update_bank = 0x03, .update_reg = 0x80, -- cgit v1.2.2 From 69952369ed2367bae0ae207a6e380ed40cdbc414 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 18 Mar 2011 12:43:35 +0000 Subject: regulator: Remove more wm831x-specific IRQ operations These are the last users in the tree. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/wm831x-dcdc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 857d741539da..e93453b1b978 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -604,8 +604,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc); - wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); + free_irq(platform_get_irq_byname(pdev, "HC"), dcdc); + free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); regulator_unregister(dcdc->regulator); if (dcdc->dvs_gpio) gpio_free(dcdc->dvs_gpio); @@ -780,7 +780,7 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); - wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); + free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); regulator_unregister(dcdc->regulator); kfree(dcdc); -- cgit v1.2.2 From 5362b09849508db94a15f3f6996427aab248320a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 24 Mar 2011 13:30:59 -0700 Subject: regulator: fix tps6524x section mismatch Acked-by: Mark Brown Fix section mismatch that is caused by init code calling exit code: pmic_remove() cannot be marked as __devexit. WARNING: drivers/regulator/tps6524x-regulator.o(.devinit.text+0x205): Section mismatch in reference from the function pmic_probe() to the function .devexit.text:pmic_remove() The function __devinit pmic_probe() references a function __devexit pmic_remove(). This is often seen when error handling in the init function uses functionality in the exit path. The fix is often to remove the __devexit annotation of pmic_remove() so it may be used outside an exit section. Signed-off-by: Randy Dunlap Cc: Liam Girdwood Cc: Mark Brown Cc: Cyril Chemparathy Signed-off-by: Liam Girdwood --- drivers/regulator/tps6524x-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 176a6be5a8ce..9166aa0a9df7 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -596,7 +596,7 @@ static struct regulator_ops regulator_ops = { .get_current_limit = get_current_limit, }; -static int __devexit pmic_remove(struct spi_device *spi) +static int pmic_remove(struct spi_device *spi) { struct tps6524x *hw = spi_get_drvdata(spi); int i; -- cgit v1.2.2 From 3506999e2fd1eb7ed7375eaa67dcc1d1d60e8ccd Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 21 Mar 2011 21:31:00 -0700 Subject: hwmon: (pmbus) Fix temperature limit register access Commit 8677011 added auto-update to temperature limit registers. Unfortunately, the update flag is also used to determine if an attribute is writable, which results in read-only temperature limit registers. To fix the problem, pass 'readonly' as separate flag to the function used to add sensor attributes. Signed-off-by: Guenter Roeck --- drivers/hwmon/pmbus_core.c | 70 ++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c index 6474512f49b0..edfb92e41735 100644 --- a/drivers/hwmon/pmbus_core.c +++ b/drivers/hwmon/pmbus_core.c @@ -752,7 +752,7 @@ static void pmbus_add_boolean_cmp(struct pmbus_data *data, static void pmbus_add_sensor(struct pmbus_data *data, const char *name, const char *type, int seq, int page, int reg, enum pmbus_sensor_classes class, - bool update) + bool update, bool readonly) { struct pmbus_sensor *sensor; @@ -765,7 +765,7 @@ static void pmbus_add_sensor(struct pmbus_data *data, sensor->reg = reg; sensor->class = class; sensor->update = update; - if (update) + if (readonly) PMBUS_ADD_GET_ATTR(data, sensor->name, sensor, data->num_sensors); else @@ -916,14 +916,14 @@ static void pmbus_find_attributes(struct i2c_client *client, i0 = data->num_sensors; pmbus_add_label(data, "in", in_index, "vin", 0); - pmbus_add_sensor(data, "in", "input", in_index, - 0, PMBUS_READ_VIN, PSC_VOLTAGE_IN, true); + pmbus_add_sensor(data, "in", "input", in_index, 0, + PMBUS_READ_VIN, PSC_VOLTAGE_IN, true, true); if (pmbus_check_word_register(client, 0, PMBUS_VIN_UV_WARN_LIMIT)) { i1 = data->num_sensors; pmbus_add_sensor(data, "in", "min", in_index, 0, PMBUS_VIN_UV_WARN_LIMIT, - PSC_VOLTAGE_IN, false); + PSC_VOLTAGE_IN, false, false); if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { pmbus_add_boolean_reg(data, "in", "min_alarm", in_index, @@ -937,7 +937,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "in", "lcrit", in_index, 0, PMBUS_VIN_UV_FAULT_LIMIT, - PSC_VOLTAGE_IN, false); + PSC_VOLTAGE_IN, false, false); if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { pmbus_add_boolean_reg(data, "in", "lcrit_alarm", in_index, @@ -951,7 +951,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "in", "max", in_index, 0, PMBUS_VIN_OV_WARN_LIMIT, - PSC_VOLTAGE_IN, false); + PSC_VOLTAGE_IN, false, false); if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { pmbus_add_boolean_reg(data, "in", "max_alarm", in_index, @@ -965,7 +965,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "in", "crit", in_index, 0, PMBUS_VIN_OV_FAULT_LIMIT, - PSC_VOLTAGE_IN, false); + PSC_VOLTAGE_IN, false, false); if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { pmbus_add_boolean_reg(data, "in", "crit_alarm", in_index, @@ -988,7 +988,7 @@ static void pmbus_find_attributes(struct i2c_client *client, if (info->func[0] & PMBUS_HAVE_VCAP) { pmbus_add_label(data, "in", in_index, "vcap", 0); pmbus_add_sensor(data, "in", "input", in_index, 0, - PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true); + PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true, true); in_index++; } @@ -1004,13 +1004,13 @@ static void pmbus_find_attributes(struct i2c_client *client, i0 = data->num_sensors; pmbus_add_label(data, "in", in_index, "vout", page + 1); pmbus_add_sensor(data, "in", "input", in_index, page, - PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true); + PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true, true); if (pmbus_check_word_register(client, page, PMBUS_VOUT_UV_WARN_LIMIT)) { i1 = data->num_sensors; pmbus_add_sensor(data, "in", "min", in_index, page, PMBUS_VOUT_UV_WARN_LIMIT, - PSC_VOLTAGE_OUT, false); + PSC_VOLTAGE_OUT, false, false); if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { pmbus_add_boolean_reg(data, "in", "min_alarm", in_index, @@ -1025,7 +1025,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "in", "lcrit", in_index, page, PMBUS_VOUT_UV_FAULT_LIMIT, - PSC_VOLTAGE_OUT, false); + PSC_VOLTAGE_OUT, false, false); if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { pmbus_add_boolean_reg(data, "in", "lcrit_alarm", in_index, @@ -1040,7 +1040,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "in", "max", in_index, page, PMBUS_VOUT_OV_WARN_LIMIT, - PSC_VOLTAGE_OUT, false); + PSC_VOLTAGE_OUT, false, false); if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { pmbus_add_boolean_reg(data, "in", "max_alarm", in_index, @@ -1055,7 +1055,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "in", "crit", in_index, page, PMBUS_VOUT_OV_FAULT_LIMIT, - PSC_VOLTAGE_OUT, false); + PSC_VOLTAGE_OUT, false, false); if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) { pmbus_add_boolean_reg(data, "in", "crit_alarm", in_index, @@ -1088,14 +1088,14 @@ static void pmbus_find_attributes(struct i2c_client *client, if (info->func[0] & PMBUS_HAVE_IIN) { i0 = data->num_sensors; pmbus_add_label(data, "curr", in_index, "iin", 0); - pmbus_add_sensor(data, "curr", "input", in_index, - 0, PMBUS_READ_IIN, PSC_CURRENT_IN, true); + pmbus_add_sensor(data, "curr", "input", in_index, 0, + PMBUS_READ_IIN, PSC_CURRENT_IN, true, true); if (pmbus_check_word_register(client, 0, PMBUS_IIN_OC_WARN_LIMIT)) { i1 = data->num_sensors; pmbus_add_sensor(data, "curr", "max", in_index, 0, PMBUS_IIN_OC_WARN_LIMIT, - PSC_CURRENT_IN, false); + PSC_CURRENT_IN, false, false); if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) { pmbus_add_boolean_reg(data, "curr", "max_alarm", in_index, @@ -1108,7 +1108,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "curr", "crit", in_index, 0, PMBUS_IIN_OC_FAULT_LIMIT, - PSC_CURRENT_IN, false); + PSC_CURRENT_IN, false, false); if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) pmbus_add_boolean_reg(data, "curr", "crit_alarm", @@ -1131,13 +1131,13 @@ static void pmbus_find_attributes(struct i2c_client *client, i0 = data->num_sensors; pmbus_add_label(data, "curr", in_index, "iout", page + 1); pmbus_add_sensor(data, "curr", "input", in_index, page, - PMBUS_READ_IOUT, PSC_CURRENT_OUT, true); + PMBUS_READ_IOUT, PSC_CURRENT_OUT, true, true); if (pmbus_check_word_register(client, page, PMBUS_IOUT_OC_WARN_LIMIT)) { i1 = data->num_sensors; pmbus_add_sensor(data, "curr", "max", in_index, page, PMBUS_IOUT_OC_WARN_LIMIT, - PSC_CURRENT_OUT, false); + PSC_CURRENT_OUT, false, false); if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { pmbus_add_boolean_reg(data, "curr", "max_alarm", in_index, @@ -1151,7 +1151,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "curr", "lcrit", in_index, page, PMBUS_IOUT_UC_FAULT_LIMIT, - PSC_CURRENT_OUT, false); + PSC_CURRENT_OUT, false, false); if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { pmbus_add_boolean_reg(data, "curr", "lcrit_alarm", @@ -1166,7 +1166,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "curr", "crit", in_index, page, PMBUS_IOUT_OC_FAULT_LIMIT, - PSC_CURRENT_OUT, false); + PSC_CURRENT_OUT, false, false); if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) { pmbus_add_boolean_reg(data, "curr", "crit_alarm", @@ -1199,13 +1199,13 @@ static void pmbus_find_attributes(struct i2c_client *client, i0 = data->num_sensors; pmbus_add_label(data, "power", in_index, "pin", 0); pmbus_add_sensor(data, "power", "input", in_index, - 0, PMBUS_READ_PIN, PSC_POWER, true); + 0, PMBUS_READ_PIN, PSC_POWER, true, true); if (pmbus_check_word_register(client, 0, PMBUS_PIN_OP_WARN_LIMIT)) { i1 = data->num_sensors; pmbus_add_sensor(data, "power", "max", in_index, 0, PMBUS_PIN_OP_WARN_LIMIT, PSC_POWER, - false); + false, false); if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) pmbus_add_boolean_reg(data, "power", "alarm", @@ -1228,7 +1228,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i0 = data->num_sensors; pmbus_add_label(data, "power", in_index, "pout", page + 1); pmbus_add_sensor(data, "power", "input", in_index, page, - PMBUS_READ_POUT, PSC_POWER, true); + PMBUS_READ_POUT, PSC_POWER, true, true); /* * Per hwmon sysfs API, power_cap is to be used to limit output * power. @@ -1241,7 +1241,8 @@ static void pmbus_find_attributes(struct i2c_client *client, if (pmbus_check_word_register(client, page, PMBUS_POUT_MAX)) { i1 = data->num_sensors; pmbus_add_sensor(data, "power", "cap", in_index, page, - PMBUS_POUT_MAX, PSC_POWER, false); + PMBUS_POUT_MAX, PSC_POWER, + false, false); need_alarm = true; } if (pmbus_check_word_register(client, page, @@ -1249,7 +1250,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "power", "max", in_index, page, PMBUS_POUT_OP_WARN_LIMIT, PSC_POWER, - false); + false, false); need_alarm = true; } if (need_alarm && (info->func[page] & PMBUS_HAVE_STATUS_IOUT)) @@ -1264,7 +1265,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "power", "crit", in_index, page, PMBUS_POUT_OP_FAULT_LIMIT, PSC_POWER, - false); + false, false); if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) pmbus_add_boolean_reg(data, "power", "crit_alarm", @@ -1302,7 +1303,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i0 = data->num_sensors; pmbus_add_sensor(data, "temp", "input", in_index, page, pmbus_temp_registers[t], - PSC_TEMPERATURE, true); + PSC_TEMPERATURE, true, true); /* * PMBus provides only one status register for TEMP1-3. @@ -1323,7 +1324,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "temp", "min", in_index, page, PMBUS_UT_WARN_LIMIT, - PSC_TEMPERATURE, true); + PSC_TEMPERATURE, true, false); if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { pmbus_add_boolean_cmp(data, "temp", "min_alarm", in_index, i1, i0, @@ -1338,7 +1339,7 @@ static void pmbus_find_attributes(struct i2c_client *client, pmbus_add_sensor(data, "temp", "lcrit", in_index, page, PMBUS_UT_FAULT_LIMIT, - PSC_TEMPERATURE, true); + PSC_TEMPERATURE, true, false); if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { pmbus_add_boolean_cmp(data, "temp", "lcrit_alarm", in_index, i1, i0, @@ -1352,7 +1353,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "temp", "max", in_index, page, PMBUS_OT_WARN_LIMIT, - PSC_TEMPERATURE, true); + PSC_TEMPERATURE, true, false); if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { pmbus_add_boolean_cmp(data, "temp", "max_alarm", in_index, i0, i1, @@ -1366,7 +1367,7 @@ static void pmbus_find_attributes(struct i2c_client *client, i1 = data->num_sensors; pmbus_add_sensor(data, "temp", "crit", in_index, page, PMBUS_OT_FAULT_LIMIT, - PSC_TEMPERATURE, true); + PSC_TEMPERATURE, true, false); if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) { pmbus_add_boolean_cmp(data, "temp", "crit_alarm", in_index, i0, i1, @@ -1421,7 +1422,8 @@ static void pmbus_find_attributes(struct i2c_client *client, i0 = data->num_sensors; pmbus_add_sensor(data, "fan", "input", in_index, page, - pmbus_fan_registers[f], PSC_FAN, true); + pmbus_fan_registers[f], PSC_FAN, true, + true); /* * Each fan status register covers multiple fans, -- cgit v1.2.2 From 9ced0b95b3993660e7990cf6bf68c1a80f31544e Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Sat, 26 Mar 2011 19:49:54 +0100 Subject: ide: ensure that we re-run the queue handler The conversion to blk_delay_queue() missed parts of IDE. Add a blk_delay_queue() to ensure that the request handler gets reinvoked when it needs to. Note that in all but one place the old plug re-run delay of 3 msecs is used, even though it probably could be shorter for performance reasons in some of those cases. Reported-by: Geert Uytterhoeven Signed-off-by: Jens Axboe --- drivers/ide/ide-io.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index f4077840d3ab..0e406d73b2c8 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -440,6 +440,7 @@ void do_ide_request(struct request_queue *q) struct ide_host *host = hwif->host; struct request *rq = NULL; ide_startstop_t startstop; + unsigned long queue_run_ms = 3; /* old plug delay */ spin_unlock_irq(q->queue_lock); @@ -459,6 +460,9 @@ repeat: prev_port = hwif->host->cur_port; if (drive->dev_flags & IDE_DFLAG_SLEEPING && time_after(drive->sleep, jiffies)) { + unsigned long left = jiffies - drive->sleep; + + queue_run_ms = jiffies_to_msecs(left + 1); ide_unlock_port(hwif); goto plug_device; } @@ -547,8 +551,10 @@ plug_device: plug_device_2: spin_lock_irq(q->queue_lock); - if (rq) + if (rq) { blk_requeue_request(q, rq); + blk_delay_queue(q, queue_run_ms); + } } void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) @@ -562,6 +568,10 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) blk_requeue_request(q, rq); spin_unlock_irqrestore(q->queue_lock, flags); + + /* Use 3ms as that was the old plug delay */ + if (rq) + blk_delay_queue(q, 3); } static int drive_is_ready(ide_drive_t *drive) -- cgit v1.2.2 From 0b58b4e3e711aed17aa26fafd01be137f6a1ab2e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 26 Mar 2011 19:52:59 +0100 Subject: staging: Fix bdops->check_events() misconversion in cyasblkdev_block.c Commit cafb0bfca1 (staging: Convert to bdops->check_events()) incorrectly set bd->user_disk_0->events while initializing bd->user_disk_1. Fix it. The problem was spotted by Milton's suspect code pattern detector. Signed-off-by: Tejun Heo Reported-by: Milton Miller Signed-off-by: Jens Axboe --- drivers/staging/westbridge/astoria/block/cyasblkdev_block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c index 842cd9214a5e..289729daba80 100644 --- a/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c +++ b/drivers/staging/westbridge/astoria/block/cyasblkdev_block.c @@ -1191,7 +1191,7 @@ static int cyasblkdev_add_disks(int bus_num, bd->user_disk_1->first_minor = (devidx + 1) << CYASBLKDEV_SHIFT; bd->user_disk_1->minors = 8; bd->user_disk_1->fops = &cyasblkdev_bdops; - bd->user_disk_0->events = DISK_EVENT_MEDIA_CHANGE; + bd->user_disk_1->events = DISK_EVENT_MEDIA_CHANGE; bd->user_disk_1->private_data = bd; bd->user_disk_1->queue = bd->queue.queue; bd->dbgprn_flags = DBGPRN_RD_RQ; -- cgit v1.2.2 From cba179aec779b364a683906b99e23014c7652e8e Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 24 Mar 2011 09:48:36 +0100 Subject: mmc: tmio_mmc: Move some defines into a shared header Also add TMIO_BBS. This allows these defines to also be used by zboot. Cc: Guennadi Liakhovetski Signed-off-by: Simon Horman Signed-off-by: Guennadi Liakhovetski Acked-by: Paul Mundt Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc.h | 30 ++++-------------------------- drivers/mmc/host/tmio_mmc_dma.c | 1 + drivers/mmc/host/tmio_mmc_pio.c | 21 +-------------------- 3 files changed, 6 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 7d79b14d56aa..099ed49a259b 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -17,36 +17,14 @@ #define TMIO_MMC_H #include +#include #include -/* Definitions for values the CTRL_STATUS register can take. */ -#define TMIO_STAT_CMDRESPEND 0x00000001 -#define TMIO_STAT_DATAEND 0x00000004 -#define TMIO_STAT_CARD_REMOVE 0x00000008 -#define TMIO_STAT_CARD_INSERT 0x00000010 -#define TMIO_STAT_SIGSTATE 0x00000020 -#define TMIO_STAT_WRPROTECT 0x00000080 -#define TMIO_STAT_CARD_REMOVE_A 0x00000100 -#define TMIO_STAT_CARD_INSERT_A 0x00000200 -#define TMIO_STAT_SIGSTATE_A 0x00000400 -#define TMIO_STAT_CMD_IDX_ERR 0x00010000 -#define TMIO_STAT_CRCFAIL 0x00020000 -#define TMIO_STAT_STOPBIT_ERR 0x00040000 -#define TMIO_STAT_DATATIMEOUT 0x00080000 -#define TMIO_STAT_RXOVERFLOW 0x00100000 -#define TMIO_STAT_TXUNDERRUN 0x00200000 -#define TMIO_STAT_CMDTIMEOUT 0x00400000 -#define TMIO_STAT_RXRDY 0x01000000 -#define TMIO_STAT_TXRQ 0x02000000 -#define TMIO_STAT_ILL_FUNC 0x20000000 -#define TMIO_STAT_CMD_BUSY 0x40000000 -#define TMIO_STAT_ILL_ACCESS 0x80000000 - /* Definitions for values the CTRL_SDIO_STATUS register can take. */ -#define TMIO_SDIO_STAT_IOIRQ 0x0001 +#define TMIO_SDIO_STAT_IOIRQ 0x0001 #define TMIO_SDIO_STAT_EXPUB52 0x4000 -#define TMIO_SDIO_STAT_EXWT 0x8000 -#define TMIO_SDIO_MASK_ALL 0xc007 +#define TMIO_SDIO_STAT_EXWT 0x8000 +#define TMIO_SDIO_MASK_ALL 0xc007 /* Define some IRQ masks */ /* This is the mask used at reset by the chip */ diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index c505278be43f..d3de74ab633e 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index e35e17992e38..6ae8d2f00ec7 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -44,26 +45,6 @@ #include "tmio_mmc.h" -#define CTL_SD_CMD 0x00 -#define CTL_ARG_REG 0x04 -#define CTL_STOP_INTERNAL_ACTION 0x08 -#define CTL_XFER_BLK_COUNT 0xa -#define CTL_RESPONSE 0x0c -#define CTL_STATUS 0x1c -#define CTL_IRQ_MASK 0x20 -#define CTL_SD_CARD_CLK_CTL 0x24 -#define CTL_SD_XFER_LEN 0x26 -#define CTL_SD_MEM_CARD_OPT 0x28 -#define CTL_SD_ERROR_DETAIL_STATUS 0x2c -#define CTL_SD_DATA_PORT 0x30 -#define CTL_TRANSACTION_CTL 0x34 -#define CTL_SDIO_STATUS 0x36 -#define CTL_SDIO_IRQ_MASK 0x38 -#define CTL_RESET_SD 0xe0 -#define CTL_SDIO_REGS 0x100 -#define CTL_CLK_AND_WAIT_CTL 0x138 -#define CTL_RESET_SDIO 0x1e0 - static u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr) { return readw(host->ctl + (addr << host->bus_shift)); -- cgit v1.2.2 From fa1df691688f34cbcd5bf77bd084bbe47e9d6bfe Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 21 Mar 2011 19:19:35 -0700 Subject: mfd: Add mfd_clone_cell(), convert cs5535-mfd/olpc-xo1 to it Replace mfd_shared_platform_driver_register with mfd_clone_cell. The former was called by an mfd client, and registered both a platform driver and device. The latter is called by an mfd driver, and registers only a platform device. The downside of this is that mfd drivers need to be modified whenever new clients are added that share a cell; the upside is that it fits Linux's driver model better. It's also simpler. This also converts cs5535-mfd/olpc-xo1 from the old API. cs5535-mfd now creates the olpc-xo1-{acpi,pms} devices, while olpc-xo1 binds to them via platform drivers. Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/cs5535-mfd.c | 18 ++++++++++++++++ drivers/mfd/mfd-core.c | 53 ++++++++++-------------------------------------- 2 files changed, 29 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 886a06871065..24959ddd9324 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -27,6 +27,7 @@ #include #include #include +#include #define DRV_NAME "cs5535-mfd" @@ -111,6 +112,22 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { }, }; +#ifdef CONFIG_OLPC +static void __devinit cs5535_clone_olpc_cells(void) +{ + const char *acpi_clones[] = { "olpc-xo1-acpi" }; + const char *pms_clones[] = { "olpc-xo1-pms" }; + + if (!machine_is_olpc()) + return; + + mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones)); + mfd_clone_cell("cs5535-pms", pms_clones, ARRAY_SIZE(pms_clones)); +} +#else +static void cs5535_clone_olpc_cells(void) { } +#endif + static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -139,6 +156,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); goto err_disable; } + cs5535_clone_olpc_cells(); dev_info(&pdev->dev, "%zu devices registered.\n", ARRAY_SIZE(cs5535_mfd_cells)); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 79eda0264fb2..d01574d98870 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -184,16 +184,12 @@ void mfd_remove_devices(struct device *parent) } EXPORT_SYMBOL(mfd_remove_devices); -static int add_shared_platform_device(const char *cell, const char *name) +int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) { struct mfd_cell cell_entry; struct device *dev; struct platform_device *pdev; - int err; - - /* check if we've already registered a device (don't fail if we have) */ - if (bus_find_device_by_name(&platform_bus_type, NULL, name)) - return 0; + int i; /* fetch the parent cell's device (should already be registered!) */ dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); @@ -206,44 +202,17 @@ static int add_shared_platform_device(const char *cell, const char *name) WARN_ON(!cell_entry.enable); - cell_entry.name = name; - err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0); - if (err) - dev_err(dev, "MFD add devices failed: %d\n", err); - return err; -} - -int mfd_shared_platform_driver_register(struct platform_driver *drv, - const char *cellname) -{ - int err; - - err = add_shared_platform_device(cellname, drv->driver.name); - if (err) - printk(KERN_ERR "failed to add platform device %s\n", - drv->driver.name); - - err = platform_driver_register(drv); - if (err) - printk(KERN_ERR "failed to add platform driver %s\n", - drv->driver.name); - - return err; -} -EXPORT_SYMBOL(mfd_shared_platform_driver_register); - -void mfd_shared_platform_driver_unregister(struct platform_driver *drv) -{ - struct device *dev; - - dev = bus_find_device_by_name(&platform_bus_type, NULL, - drv->driver.name); - if (dev) - platform_device_unregister(to_platform_device(dev)); + for (i = 0; i < n_clones; i++) { + cell_entry.name = clones[i]; + /* don't give up if a single call fails; just report error */ + if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0)) + dev_err(dev, "failed to create platform device '%s'\n", + clones[i]); + } - platform_driver_unregister(drv); + return 0; } -EXPORT_SYMBOL(mfd_shared_platform_driver_unregister); +EXPORT_SYMBOL(mfd_clone_cell); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); -- cgit v1.2.2 From adfa4bd4a8bfc53ca7370c57be240d35c2ec28e2 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 22 Mar 2011 13:50:39 -0700 Subject: mfd: OLPC: Clean up names to match what OLPC actually uses The cs5535-pms cell doesn't actually need to be cloned, so we can drop that and simply have the olpc-xo1.c driver use "cs5535-pms" directly. Also, rename the cs5535-acpi clones to what we actually use for the (currently out-of-tree) SCI driver. In the process, that fixes a subtle bug in olpc-xo1.c which broke powerdown on XO-1s.. olpc-xo1-ac-acpi was a typo, not something that actually existed. Signed-off-by: Daniel Drake Signed-off-by: Andres Salomon Signed-off-by: Samuel Ortiz --- drivers/mfd/cs5535-mfd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 24959ddd9324..155fa0407882 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -115,14 +115,12 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { #ifdef CONFIG_OLPC static void __devinit cs5535_clone_olpc_cells(void) { - const char *acpi_clones[] = { "olpc-xo1-acpi" }; - const char *pms_clones[] = { "olpc-xo1-pms" }; + const char *acpi_clones[] = { "olpc-xo1-pm-acpi", "olpc-xo1-sci-acpi" }; if (!machine_is_olpc()) return; mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones)); - mfd_clone_cell("cs5535-pms", pms_clones, ARRAY_SIZE(pms_clones)); } #else static void cs5535_clone_olpc_cells(void) { } -- cgit v1.2.2 From 1206552b02f725bdc603e3153b4a32403d7da9e4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 23 Mar 2011 20:54:17 +0800 Subject: mfd: Constify i2c_device_id tables Signed-off-by: Axel Lin Acked-by: Harald Welte Cc: Matti Aaltonen Signed-off-by: Samuel Ortiz --- drivers/mfd/pcf50633-core.c | 2 +- drivers/mfd/wl1273-core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index c1306ed43e3c..c7687f6a78a0 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -356,7 +356,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id pcf50633_id_table[] = { +static const struct i2c_device_id pcf50633_id_table[] = { {"pcf50633", 0x73}, {/* end of list */} }; diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index f76f6c798046..04914f2836c0 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -25,7 +25,7 @@ #define DRIVER_DESC "WL1273 FM Radio Core" -static struct i2c_device_id wl1273_driver_id_table[] = { +static const struct i2c_device_id wl1273_driver_id_table[] = { { WL1273_FM_DRIVER_NAME, 0 }, { } }; -- cgit v1.2.2 From 8de6bc7f6ba58dd717e4a65e3bf4a746116fb874 Mon Sep 17 00:00:00 2001 From: MyungJoo Ham Date: Thu, 24 Mar 2011 15:54:45 +0900 Subject: mfd: Add MAX8997/8966 IRQ control This patch enables IRQ handling for MAX8997/8966 chips. Please note that Fuel-Gauge-related IRQs are not implemented in this initial release. The fuel gauge module in MAX8997 is identical to MAX17042, which is already in Linux kernel. In order to use the already-existing MAX17042 driver for fuel gauge module in MAX8997, the main interrupt handler of MAX8997 should relay related interrupts to MAX17042 driver. However, in order to do this, we need to modify MAX17042 driver as well because MAX17042 driver does not have any interrupt handlers for now. We are not going to implement this in this initial release as it is not crucial in basic operations of MAX8997. Signed-off-by: MyungJoo Ham Signed-off-by: Kyungmin Park Signed-off-by: Samuel Ortiz --- drivers/mfd/Makefile | 2 +- drivers/mfd/max8997-irq.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 drivers/mfd/max8997-irq.c (limited to 'drivers') diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 47f5709f3828..ef489f253402 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -63,7 +63,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o -obj-$(CONFIG_MFD_MAX8997) += max8997.o +obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c new file mode 100644 index 000000000000..e85c874133c4 --- /dev/null +++ b/drivers/mfd/max8997-irq.c @@ -0,0 +1,377 @@ +/* + * max8997-irq.c - Interrupt controller support for MAX8997 + * + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * MyungJoo Ham + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max8998-irq.c + */ + +#include +#include +#include +#include +#include + +static const u8 max8997_mask_reg[] = { + [PMIC_INT1] = MAX8997_REG_INT1MSK, + [PMIC_INT2] = MAX8997_REG_INT2MSK, + [PMIC_INT3] = MAX8997_REG_INT3MSK, + [PMIC_INT4] = MAX8997_REG_INT4MSK, + [FUEL_GAUGE] = MAX8997_REG_INVALID, + [MUIC_INT1] = MAX8997_MUIC_REG_INTMASK1, + [MUIC_INT2] = MAX8997_MUIC_REG_INTMASK2, + [MUIC_INT3] = MAX8997_MUIC_REG_INTMASK3, + [GPIO_LOW] = MAX8997_REG_INVALID, + [GPIO_HI] = MAX8997_REG_INVALID, + [FLASH_STATUS] = MAX8997_REG_INVALID, +}; + +static struct i2c_client *get_i2c(struct max8997_dev *max8997, + enum max8997_irq_source src) +{ + switch (src) { + case PMIC_INT1 ... PMIC_INT4: + return max8997->i2c; + case FUEL_GAUGE: + return NULL; + case MUIC_INT1 ... MUIC_INT3: + return max8997->muic; + case GPIO_LOW ... GPIO_HI: + return max8997->i2c; + case FLASH_STATUS: + return max8997->i2c; + default: + return ERR_PTR(-EINVAL); + } + + return ERR_PTR(-EINVAL); +} + +struct max8997_irq_data { + int mask; + enum max8997_irq_source group; +}; + +#define DECLARE_IRQ(idx, _group, _mask) \ + [(idx)] = { .group = (_group), .mask = (_mask) } +static const struct max8997_irq_data max8997_irqs[] = { + DECLARE_IRQ(MAX8997_PMICIRQ_PWRONR, PMIC_INT1, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_PWRONF, PMIC_INT1, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_PWRON1SEC, PMIC_INT1, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_JIGONR, PMIC_INT1, 1 << 4), + DECLARE_IRQ(MAX8997_PMICIRQ_JIGONF, PMIC_INT1, 1 << 5), + DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT2, PMIC_INT1, 1 << 6), + DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT1, PMIC_INT1, 1 << 7), + + DECLARE_IRQ(MAX8997_PMICIRQ_JIGR, PMIC_INT2, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_JIGF, PMIC_INT2, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_MR, PMIC_INT2, 1 << 2), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS1OK, PMIC_INT2, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS2OK, PMIC_INT2, 1 << 4), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS3OK, PMIC_INT2, 1 << 5), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS4OK, PMIC_INT2, 1 << 6), + + DECLARE_IRQ(MAX8997_PMICIRQ_CHGINS, PMIC_INT3, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_CHGRM, PMIC_INT3, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_DCINOVP, PMIC_INT3, 1 << 2), + DECLARE_IRQ(MAX8997_PMICIRQ_TOPOFFR, PMIC_INT3, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_CHGRSTF, PMIC_INT3, 1 << 5), + DECLARE_IRQ(MAX8997_PMICIRQ_MBCHGTMEXPD, PMIC_INT3, 1 << 7), + + DECLARE_IRQ(MAX8997_PMICIRQ_RTC60S, PMIC_INT4, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_RTCA1, PMIC_INT4, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_RTCA2, PMIC_INT4, 1 << 2), + DECLARE_IRQ(MAX8997_PMICIRQ_SMPL_INT, PMIC_INT4, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_RTC1S, PMIC_INT4, 1 << 4), + DECLARE_IRQ(MAX8997_PMICIRQ_WTSR, PMIC_INT4, 1 << 5), + + DECLARE_IRQ(MAX8997_MUICIRQ_ADCError, MUIC_INT1, 1 << 2), + DECLARE_IRQ(MAX8997_MUICIRQ_ADCLow, MUIC_INT1, 1 << 1), + DECLARE_IRQ(MAX8997_MUICIRQ_ADC, MUIC_INT1, 1 << 0), + + DECLARE_IRQ(MAX8997_MUICIRQ_VBVolt, MUIC_INT2, 1 << 4), + DECLARE_IRQ(MAX8997_MUICIRQ_DBChg, MUIC_INT2, 1 << 3), + DECLARE_IRQ(MAX8997_MUICIRQ_DCDTmr, MUIC_INT2, 1 << 2), + DECLARE_IRQ(MAX8997_MUICIRQ_ChgDetRun, MUIC_INT2, 1 << 1), + DECLARE_IRQ(MAX8997_MUICIRQ_ChgTyp, MUIC_INT2, 1 << 0), + + DECLARE_IRQ(MAX8997_MUICIRQ_OVP, MUIC_INT3, 1 << 2), +}; + +static void max8997_irq_lock(struct irq_data *data) +{ + struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + + mutex_lock(&max8997->irqlock); +} + +static void max8997_irq_sync_unlock(struct irq_data *data) +{ + struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + int i; + + for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { + u8 mask_reg = max8997_mask_reg[i]; + struct i2c_client *i2c = get_i2c(max8997, i); + + if (mask_reg == MAX8997_REG_INVALID || + IS_ERR_OR_NULL(i2c)) + continue; + max8997->irq_masks_cache[i] = max8997->irq_masks_cur[i]; + + max8997_write_reg(i2c, max8997_mask_reg[i], + max8997->irq_masks_cur[i]); + } + + mutex_unlock(&max8997->irqlock); +} + +static const inline struct max8997_irq_data * +irq_to_max8997_irq(struct max8997_dev *max8997, int irq) +{ + return &max8997_irqs[irq - max8997->irq_base]; +} + +static void max8997_irq_mask(struct irq_data *data) +{ + struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, + data->irq); + + max8997->irq_masks_cur[irq_data->group] |= irq_data->mask; +} + +static void max8997_irq_unmask(struct irq_data *data) +{ + struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, + data->irq); + + max8997->irq_masks_cur[irq_data->group] &= ~irq_data->mask; +} + +static struct irq_chip max8997_irq_chip = { + .name = "max8997", + .irq_bus_lock = max8997_irq_lock, + .irq_bus_sync_unlock = max8997_irq_sync_unlock, + .irq_mask = max8997_irq_mask, + .irq_unmask = max8997_irq_unmask, +}; + +#define MAX8997_IRQSRC_PMIC (1 << 1) +#define MAX8997_IRQSRC_FUELGAUGE (1 << 2) +#define MAX8997_IRQSRC_MUIC (1 << 3) +#define MAX8997_IRQSRC_GPIO (1 << 4) +#define MAX8997_IRQSRC_FLASH (1 << 5) +static irqreturn_t max8997_irq_thread(int irq, void *data) +{ + struct max8997_dev *max8997 = data; + u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {}; + u8 irq_src; + int ret; + int i; + + ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src); + if (ret < 0) { + dev_err(max8997->dev, "Failed to read interrupt source: %d\n", + ret); + return IRQ_NONE; + } + + if (irq_src & MAX8997_IRQSRC_PMIC) { + /* PMIC INT1 ~ INT4 */ + max8997_bulk_read(max8997->i2c, MAX8997_REG_INT1, 4, + &irq_reg[PMIC_INT1]); + } + if (irq_src & MAX8997_IRQSRC_FUELGAUGE) { + /* + * TODO: FUEL GAUGE + * + * This is to be supported by Max17042 driver. When + * an interrupt incurs here, it should be relayed to a + * Max17042 device that is connected (probably by + * platform-data). However, we do not have interrupt + * handling in Max17042 driver currently. The Max17042 IRQ + * driver should be ready to be used as a stand-alone device and + * a Max8997-dependent device. Because it is not ready in + * Max17042-side and it is not too critical in operating + * Max8997, we do not implement this in initial releases. + */ + irq_reg[FUEL_GAUGE] = 0; + } + if (irq_src & MAX8997_IRQSRC_MUIC) { + /* MUIC INT1 ~ INT3 */ + max8997_bulk_read(max8997->muic, MAX8997_MUIC_REG_INT1, 3, + &irq_reg[MUIC_INT1]); + } + if (irq_src & MAX8997_IRQSRC_GPIO) { + /* GPIO Interrupt */ + u8 gpio_info[MAX8997_NUM_GPIO]; + + irq_reg[GPIO_LOW] = 0; + irq_reg[GPIO_HI] = 0; + + max8997_bulk_read(max8997->i2c, MAX8997_REG_GPIOCNTL1, + MAX8997_NUM_GPIO, gpio_info); + for (i = 0; i < MAX8997_NUM_GPIO; i++) { + bool interrupt = false; + + switch (gpio_info[i] & MAX8997_GPIO_INT_MASK) { + case MAX8997_GPIO_INT_BOTH: + if (max8997->gpio_status[i] != gpio_info[i]) + interrupt = true; + break; + case MAX8997_GPIO_INT_RISE: + if ((max8997->gpio_status[i] != gpio_info[i]) && + (gpio_info[i] & MAX8997_GPIO_DATA_MASK)) + interrupt = true; + break; + case MAX8997_GPIO_INT_FALL: + if ((max8997->gpio_status[i] != gpio_info[i]) && + !(gpio_info[i] & MAX8997_GPIO_DATA_MASK)) + interrupt = true; + break; + default: + break; + } + + if (interrupt) { + if (i < 8) + irq_reg[GPIO_LOW] |= (1 << i); + else + irq_reg[GPIO_HI] |= (1 << (i - 8)); + } + + } + } + if (irq_src & MAX8997_IRQSRC_FLASH) { + /* Flash Status Interrupt */ + ret = max8997_read_reg(max8997->i2c, MAX8997_REG_FLASHSTATUS, + &irq_reg[FLASH_STATUS]); + } + + /* Apply masking */ + for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) + irq_reg[i] &= ~max8997->irq_masks_cur[i]; + + /* Report */ + for (i = 0; i < MAX8997_IRQ_NR; i++) { + if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) + handle_nested_irq(max8997->irq_base + i); + } + + return IRQ_HANDLED; +} + +int max8997_irq_resume(struct max8997_dev *max8997) +{ + if (max8997->irq && max8997->irq_base) + max8997_irq_thread(max8997->irq_base, max8997); + return 0; +} + +int max8997_irq_init(struct max8997_dev *max8997) +{ + int i; + int cur_irq; + int ret; + u8 val; + + if (!max8997->irq) { + dev_warn(max8997->dev, "No interrupt specified.\n"); + max8997->irq_base = 0; + return 0; + } + + if (!max8997->irq_base) { + dev_err(max8997->dev, "No interrupt base specified.\n"); + return 0; + } + + mutex_init(&max8997->irqlock); + + /* Mask individual interrupt sources */ + for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { + struct i2c_client *i2c; + + max8997->irq_masks_cur[i] = 0xff; + max8997->irq_masks_cache[i] = 0xff; + i2c = get_i2c(max8997, i); + + if (IS_ERR_OR_NULL(i2c)) + continue; + if (max8997_mask_reg[i] == MAX8997_REG_INVALID) + continue; + + max8997_write_reg(i2c, max8997_mask_reg[i], 0xff); + } + + for (i = 0; i < MAX8997_NUM_GPIO; i++) { + max8997->gpio_status[i] = (max8997_read_reg(max8997->i2c, + MAX8997_REG_GPIOCNTL1 + i, + &val) + & MAX8997_GPIO_DATA_MASK) ? + true : false; + } + + /* Register with genirq */ + for (i = 0; i < MAX8997_IRQ_NR; i++) { + cur_irq = i + max8997->irq_base; + set_irq_chip_data(cur_irq, max8997); + set_irq_chip_and_handler(cur_irq, &max8997_irq_chip, + handle_edge_irq); + set_irq_nested_thread(cur_irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + set_irq_noprobe(cur_irq); +#endif + } + + ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "max8997-irq", max8997); + + if (ret) { + dev_err(max8997->dev, "Failed to request IRQ %d: %d\n", + max8997->irq, ret); + return ret; + } + + if (!max8997->ono) + return 0; + + ret = request_threaded_irq(max8997->ono, NULL, max8997_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "max8997-ono", max8997); + + if (ret) + dev_err(max8997->dev, "Failed to request ono-IRQ %d: %d\n", + max8997->ono, ret); + + return 0; +} + +void max8997_irq_exit(struct max8997_dev *max8997) +{ + if (max8997->ono) + free_irq(max8997->ono, max8997); + + if (max8997->irq) + free_irq(max8997->irq, max8997); +} -- cgit v1.2.2 From 8537548645231424b457dd277900054c59096920 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 24 Mar 2011 15:04:53 +0800 Subject: mfd: Add MODULE_DEVICE_TABLE to rdc321x-southbridge The device table is required to load modules based on modaliases. After adding MODULE_DEVICE_TABLE, below entry will be added to modules.pcimap: rdc321x-southbridge 0x000017f3 0x00006030 0xffffffff 0xffffffff 0x00000000 0x00000000 0x0 Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/mfd/rdc321x-southbridge.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 193c940225b5..10dbe6374a89 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -97,6 +97,7 @@ static DEFINE_PCI_DEVICE_TABLE(rdc321x_sb_table) = { { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, {} }; +MODULE_DEVICE_TABLE(pci, rdc321x_sb_table); static struct pci_driver rdc321x_sb_driver = { .name = "RDC321x Southbridge", -- cgit v1.2.2 From fc498fa29c725a0f0fc5ed359db0e3ed33f4ed52 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 24 Mar 2011 12:12:47 -0700 Subject: mfd: Select MFD_CORE if TPS6105X driver is configured The TPS61050/61052 driver uses MFD core code, yet does not specify the dependency in Kconfig. If it is the only MFD driver configured, compilation fails with ERROR: "mfd_add_devices" [drivers/mfd/tps6105x.ko] undefined! ERROR: "mfd_remove_devices" [drivers/mfd/tps6105x.ko] undefined! Fix the problem by adding "select MFD_CORE" to the respective Kconfig entry. Signed-off-by: Guenter Roeck Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a9a1af49281e..e986f91fff9c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -133,6 +133,7 @@ config TPS6105X tristate "TPS61050/61052 Boost Converters" depends on I2C select REGULATOR + select MFD_CORE select REGULATOR_FIXED_VOLTAGE help This option enables a driver for the TP61050/TPS61052 -- cgit v1.2.2 From 52a7d60775aa447b3a3dc685b7006f7cdc7835dd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:26 +0000 Subject: mfd: asic3: Cleanup irq handling Remove the open coded access to irq_desc and use the proper wrappers. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 0241f08fc00d..652bde5a5adc 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -139,13 +139,12 @@ static void asic3_irq_flip_edge(struct asic3 *asic, static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) { + struct asic3 *asic = irq_desc_get_handler_data(desc); + struct irq_data *data = irq_desc_get_irq_data(desc); int iter, i; unsigned long flags; - struct asic3 *asic; - - desc->irq_data.chip->irq_ack(&desc->irq_data); - asic = get_irq_data(irq); + data->chip->irq_ack(irq_data); for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { u32 status; @@ -188,8 +187,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) irqnr = asic->irq_base + (ASIC3_GPIOS_PER_BANK * bank) + i; - desc = irq_to_desc(irqnr); - desc->handle_irq(irqnr, desc); + generic_handle_irq(irqnr); if (asic->irq_bothedge[bank] & bit) asic3_irq_flip_edge(asic, base, bit); @@ -200,11 +198,8 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) /* Handle remaining IRQs in the status register */ for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { /* They start at bit 4 and go up */ - if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) { - desc = irq_to_desc(asic->irq_base + i); - desc->handle_irq(asic->irq_base + i, - desc); - } + if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) + generic_handle_irq(asic->irq_base + i); } } -- cgit v1.2.2 From 256d0e2e4553417466ca8213b446954ff1778c2c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:27 +0000 Subject: mfd: 88pm860x: Remove unused irq_desc leftovers Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 9c511c1604a5..e13e9f0f6d70 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -416,7 +416,6 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, : chip->companion; unsigned char status_buf[INT_STATUS_NUM]; unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; - struct irq_desc *desc; int i, data, mask, ret = -EINVAL; int __irq; @@ -468,8 +467,6 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, if (!chip->core_irq) goto out; - desc = irq_to_desc(chip->core_irq); - /* register IRQ by genirq */ for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { __irq = i + chip->irq_base; -- cgit v1.2.2 From 73a6839fdb7f3f5ac7bfaee0796dd7647b9c9376 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:27 +0000 Subject: mfd: ezx-pcap: Remvove open coded irq handling There is no point in checking irq_desc here, as it _is_ available. The driver configured those lines, so they cannot go away. The home brewn disabled/note_interrupt magic can be removed as well by adding a irq_disable callback which avoids the lazy disable. That driver needs to be converted to threaded interrupts. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/ezx-pcap.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 9e2d8dd5f9e5..92e6fbc43a14 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -162,6 +162,7 @@ static void pcap_unmask_irq(struct irq_data *d) static struct irq_chip pcap_irq_chip = { .name = "pcap", + .irq_disable = pcap_mask_irq, .irq_mask = pcap_mask_irq, .irq_unmask = pcap_unmask_irq, }; @@ -196,17 +197,8 @@ static void pcap_isr_work(struct work_struct *work) local_irq_disable(); service = isr & ~msr; for (irq = pcap->irq_base; service; service >>= 1, irq++) { - if (service & 1) { - struct irq_desc *desc = irq_to_desc(irq); - - if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq)) - break; - - if (desc->status & IRQ_DISABLED) - note_interrupt(irq, desc, IRQ_NONE); - else - desc->handle_irq(irq, desc); - } + if (service & 1) + generic_handle_irq(irq); } local_irq_enable(); ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); -- cgit v1.2.2 From 77eda96691f5e39973f2f2667a28e57e852f559d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:28 +0000 Subject: mfd: htc-egpio: Cleanup interrupt handling Replace the open coded handler call with the prober accessor. Retrieve the handler data from desc. That avoids a redundant lookup in the sparse irq case. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/htc-egpio.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index d00b6d1a69e5..0ca68860c0d0 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -100,7 +100,7 @@ static struct irq_chip egpio_muxed_chip = { static void egpio_handler(unsigned int irq, struct irq_desc *desc) { - struct egpio_info *ei = get_irq_data(irq); + struct egpio_info *ei = irq_desc_get_handler_data(desc); int irqpin; /* Read current pins. */ @@ -113,9 +113,7 @@ static void egpio_handler(unsigned int irq, struct irq_desc *desc) for_each_set_bit(irqpin, &readval, ei->nirqs) { /* Run irq handler */ pr_debug("got IRQ %d\n", irqpin); - irq = ei->irq_start + irqpin; - desc = irq_to_desc(irq); - desc->handle_irq(irq, desc); + generic_handle_irq(ei->irq_start + irqpin); } } -- cgit v1.2.2 From 9eaee99e5a9cedcc4acb3b5507c0878352222bce Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:29 +0000 Subject: mfd: htc-i2cpld: Cleanup interrupt handling Remove the pointless irq_desc check in set_type. This function is called with that irq descriptor locked. Also remove the write back of the flow type as the core code does this already when the return value is 0. Also store the flow type in the chip data structure, so there is no need to fiddle in the irq descriptor. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/htc-i2cpld.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 296ad1562f69..b3aa82339993 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -58,6 +58,7 @@ struct htcpld_chip { uint irq_start; int nirqs; + unsigned int flow_type; /* * Work structure to allow for setting values outside of any * possible interrupt context @@ -97,12 +98,7 @@ static void htcpld_unmask(struct irq_data *data) static int htcpld_set_type(struct irq_data *data, unsigned int flags) { - struct irq_desc *d = irq_to_desc(data->irq); - - if (!d) { - pr_err("HTCPLD invalid IRQ: %d\n", data->irq); - return -EINVAL; - } + struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); if (flags & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -111,9 +107,7 @@ static int htcpld_set_type(struct irq_data *data, unsigned int flags) if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)) return -EINVAL; - d->status &= ~IRQ_TYPE_SENSE_MASK; - d->status |= flags; - + chip->flow_type = flags; return 0; } @@ -135,7 +129,6 @@ static irqreturn_t htcpld_handler(int irq, void *dev) unsigned int i; unsigned long flags; int irqpin; - struct irq_desc *desc; if (!htcpld) { pr_debug("htcpld is null in ISR\n"); @@ -195,23 +188,19 @@ static irqreturn_t htcpld_handler(int irq, void *dev) * associated interrupts. */ for (irqpin = 0; irqpin < chip->nirqs; irqpin++) { - unsigned oldb, newb; - int flags; + unsigned oldb, newb, type = chip->flow_type; irq = chip->irq_start + irqpin; - desc = irq_to_desc(irq); - flags = desc->status; /* Run the IRQ handler, but only if the bit value * changed, and the proper flags are set */ oldb = (old_val >> irqpin) & 1; newb = (uval >> irqpin) & 1; - if ((!oldb && newb && (flags & IRQ_TYPE_EDGE_RISING)) || - (oldb && !newb && - (flags & IRQ_TYPE_EDGE_FALLING))) { + if ((!oldb && newb && (type & IRQ_TYPE_EDGE_RISING)) || + (oldb && !newb && (type & IRQ_TYPE_EDGE_FALLING))) { pr_debug("fire IRQ %d\n", irqpin); - desc->handle_irq(irq, desc); + generic_handle_irq(irq); } } } -- cgit v1.2.2 From 9d8fd10aa5843e018d456644fc1a58896d8eeaf5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:30 +0000 Subject: mfd: mx8925: Remove irq_desc leftovers Remove unused code. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 0e998dc4e7d8..a92ea9bb83fa 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -517,7 +517,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, struct max8925_platform_data *pdata) { unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; - struct irq_desc *desc; int i, ret; int __irq; @@ -544,7 +543,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, mutex_init(&chip->irq_lock); chip->core_irq = irq; chip->irq_base = pdata->irq_base; - desc = irq_to_desc(chip->core_irq); /* register with genirq */ for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { -- cgit v1.2.2 From d740f4523bb4aea24bece704c726c69094e20d00 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:31 +0000 Subject: mfd: twl4030: Cleanup interrupt handling irq_desc checking in a function which is called with that irq descriptor locked, is pointless. Equally pointless as the irq desc check in the interrupt service routine. The driver sets those lines up, so that cant go away magically. Remove the open coded handler magic and use the proper accessor. No need to fiddle with irq_desc in the type setting function. The original value is in irq_data and the core code stores the new setting when the return value is 0. This driver needs to be converted to threaded interrupts and buslock. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-irq.c | 46 ++++++++-------------------------------------- 1 file changed, 8 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 63a30e88908f..47e8de0f3366 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -320,24 +320,8 @@ static int twl4030_irq_thread(void *data) for (module_irq = twl4030_irq_base; pih_isr; pih_isr >>= 1, module_irq++) { - if (pih_isr & 0x1) { - struct irq_desc *d = irq_to_desc(module_irq); - - if (!d) { - pr_err("twl4030: Invalid SIH IRQ: %d\n", - module_irq); - return -EINVAL; - } - - /* These can't be masked ... always warn - * if we get any surprises. - */ - if (d->status & IRQ_DISABLED) - note_interrupt(module_irq, d, - IRQ_NONE); - else - d->handle_irq(module_irq, d); - } + if (pih_isr & 0x1) + generic_handle_irq(module_irq); } local_irq_enable(); @@ -560,24 +544,18 @@ static void twl4030_sih_do_edge(struct work_struct *work) /* Modify only the bits we know must change */ while (edge_change) { int i = fls(edge_change) - 1; - struct irq_desc *d = irq_to_desc(i + agent->irq_base); + struct irq_data *idata = irq_get_irq_data(i + agent->irq_base); int byte = 1 + (i >> 2); int off = (i & 0x3) * 2; - - if (!d) { - pr_err("twl4030: Invalid IRQ: %d\n", - i + agent->irq_base); - return; - } + unsigned int type; bytes[byte] &= ~(0x03 << off); - raw_spin_lock_irq(&d->lock); - if (d->status & IRQ_TYPE_EDGE_RISING) + type = irqd_get_trigger_type(idata); + if (type & IRQ_TYPE_EDGE_RISING) bytes[byte] |= BIT(off + 1); - if (d->status & IRQ_TYPE_EDGE_FALLING) + if (type & IRQ_TYPE_EDGE_FALLING) bytes[byte] |= BIT(off + 0); - raw_spin_unlock_irq(&d->lock); edge_change &= ~BIT(i); } @@ -626,21 +604,13 @@ static void twl4030_sih_unmask(struct irq_data *data) static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger) { struct sih_agent *sih = irq_data_get_irq_chip_data(data); - struct irq_desc *desc = irq_to_desc(data->irq); unsigned long flags; - if (!desc) { - pr_err("twl4030: Invalid IRQ: %d\n", data->irq); - return -EINVAL; - } - if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; spin_lock_irqsave(&sih_agent_lock, flags); - if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) { - desc->status &= ~IRQ_TYPE_SENSE_MASK; - desc->status |= trigger; + if (irqd_get_trigger_type(data) != trigger) { sih->edge_change |= BIT(data->irq - sih->irq_base); queue_work(wq, &sih->edge_work); } -- cgit v1.2.2 From c22435a307e00b8ae947b79a8c0d94ab0bef404c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:31 +0000 Subject: mfd: twl6030: Cleanup interrupt handling irq_desc checking in the interrupt demux routine is totally pointless. The driver sets those lines up, so that cant go away magically. Remove the open coded handler magic and use the proper accessor. This driver needs to be converted to threaded interrupts and buslock. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 4082ed73613f..3b9c7756cb6d 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -140,22 +140,7 @@ static int twl6030_irq_thread(void *data) if (sts.int_sts & 0x1) { int module_irq = twl6030_irq_base + twl6030_interrupt_mapping[i]; - struct irq_desc *d = irq_to_desc(module_irq); - - if (!d) { - pr_err("twl6030: Invalid SIH IRQ: %d\n", - module_irq); - return -EINVAL; - } - - /* These can't be masked ... always warn - * if we get any surprises. - */ - if (d->status & IRQ_DISABLED) - note_interrupt(module_irq, d, - IRQ_NONE); - else - d->handle_irq(module_irq, d); + generic_handle_irq(module_irq); } local_irq_enable(); -- cgit v1.2.2 From d5bb122165981aed327845c32a9916d1b8ae0e4b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:32 +0000 Subject: mfd: Cleanup irq namespace Converted with coccinelle. Signed-off-by: Thomas Gleixner Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 8 ++++---- drivers/mfd/ab3550-core.c | 12 ++++++------ drivers/mfd/ab8500-core.c | 12 ++++++------ drivers/mfd/asic3.c | 22 +++++++++++----------- drivers/mfd/ezx-pcap.c | 20 ++++++++++---------- drivers/mfd/htc-egpio.c | 18 +++++++++--------- drivers/mfd/htc-i2cpld.c | 8 ++++---- drivers/mfd/jz4740-adc.c | 16 ++++++++-------- drivers/mfd/max8925-core.c | 8 ++++---- drivers/mfd/max8998-irq.c | 8 ++++---- drivers/mfd/max8998.c | 4 ++-- drivers/mfd/stmpe.c | 12 ++++++------ drivers/mfd/t7l66xb.c | 22 +++++++++++----------- drivers/mfd/tc3589x.c | 12 ++++++------ drivers/mfd/tc6393xb.c | 22 +++++++++++----------- drivers/mfd/tps6586x.c | 6 +++--- drivers/mfd/twl4030-irq.c | 20 ++++++++++---------- drivers/mfd/twl6030-irq.c | 8 ++++---- drivers/mfd/wm831x-irq.c | 8 ++++---- drivers/mfd/wm8350-irq.c | 8 ++++---- drivers/mfd/wm8994-irq.c | 8 ++++---- 21 files changed, 131 insertions(+), 131 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index e13e9f0f6d70..011cb6ce861b 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -470,14 +470,14 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, /* register IRQ by genirq */ for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { __irq = i + chip->irq_base; - set_irq_chip_data(__irq, chip); - set_irq_chip_and_handler(__irq, &pm860x_irq_chip, + irq_set_chip_data(__irq, chip); + irq_set_chip_and_handler(__irq, &pm860x_irq_chip, handle_edge_irq); - set_irq_nested_thread(__irq, 1); + irq_set_nested_thread(__irq, 1); #ifdef CONFIG_ARM set_irq_flags(__irq, IRQF_VALID); #else - set_irq_noprobe(__irq); + irq_set_noprobe(__irq); #endif } diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index c12d04285226..ff86acf3e6bd 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -668,7 +668,7 @@ static int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq) struct ab3550_platform_data *plf_data; bool val; - ab = get_irq_chip_data(irq); + ab = irq_get_chip_data(irq); plf_data = ab->i2c_client[0]->dev.platform_data; irq -= plf_data->irq.base; val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0); @@ -1296,14 +1296,14 @@ static int __init ab3550_probe(struct i2c_client *client, unsigned int irq; irq = ab3550_plf_data->irq.base + i; - set_irq_chip_data(irq, ab); - set_irq_chip_and_handler(irq, &ab3550_irq_chip, - handle_simple_irq); - set_irq_nested_thread(irq, 1); + irq_set_chip_data(irq, ab); + irq_set_chip_and_handler(irq, &ab3550_irq_chip, + handle_simple_irq); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6e185b272d00..62e33e2258d4 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -334,14 +334,14 @@ static int ab8500_irq_init(struct ab8500 *ab8500) int irq; for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { - set_irq_chip_data(irq, ab8500); - set_irq_chip_and_handler(irq, &ab8500_irq_chip, + irq_set_chip_data(irq, ab8500); + irq_set_chip_and_handler(irq, &ab8500_irq_chip, handle_simple_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -357,8 +357,8 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 652bde5a5adc..22b5a78bbfdb 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -388,21 +388,21 @@ static int __init asic3_irq_probe(struct platform_device *pdev) for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { if (irq < asic->irq_base + ASIC3_NUM_GPIOS) - set_irq_chip(irq, &asic3_gpio_irq_chip); + irq_set_chip(irq, &asic3_gpio_irq_chip); else - set_irq_chip(irq, &asic3_irq_chip); + irq_set_chip(irq, &asic3_irq_chip); - set_irq_chip_data(irq, asic); - set_irq_handler(irq, handle_level_irq); + irq_set_chip_data(irq, asic); + irq_set_handler(irq, handle_level_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), ASIC3_INTMASK_GINTMASK); - set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); - set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); - set_irq_data(asic->irq_nr, asic); + irq_set_chained_handler(asic->irq_nr, asic3_irq_demux); + irq_set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(asic->irq_nr, asic); return 0; } @@ -416,11 +416,11 @@ static void asic3_irq_remove(struct platform_device *pdev) for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { set_irq_flags(irq, 0); - set_irq_handler(irq, NULL); - set_irq_chip(irq, NULL); - set_irq_chip_data(irq, NULL); + irq_set_handler(irq, NULL); + irq_set_chip(irq, NULL); + irq_set_chip_data(irq, NULL); } - set_irq_chained_handler(asic->irq_nr, NULL); + irq_set_chained_handler(asic->irq_nr, NULL); } /* GPIOs */ diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 92e6fbc43a14..f2f4029e21a0 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -207,7 +207,7 @@ static void pcap_isr_work(struct work_struct *work) static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct pcap_chip *pcap = get_irq_data(irq); + struct pcap_chip *pcap = irq_get_handler_data(irq); desc->irq_data.chip->irq_ack(&desc->irq_data); queue_work(pcap->workqueue, &pcap->isr_work); @@ -411,7 +411,7 @@ static int __devexit ezx_pcap_remove(struct spi_device *spi) /* cleanup irqchip */ for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); destroy_workqueue(pcap->workqueue); @@ -468,12 +468,12 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) /* setup irq chip */ for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { - set_irq_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); - set_irq_chip_data(i, pcap); + irq_set_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); + irq_set_chip_data(i, pcap); #ifdef CONFIG_ARM set_irq_flags(i, IRQF_VALID); #else - set_irq_noprobe(i); + irq_set_noprobe(i); #endif } @@ -482,10 +482,10 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); pcap->msr = PCAP_MASK_ALL_INTERRUPT; - set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); - set_irq_data(spi->irq, pcap); - set_irq_chained_handler(spi->irq, pcap_irq_handler); - set_irq_wake(spi->irq, 1); + irq_set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(spi->irq, pcap); + irq_set_chained_handler(spi->irq, pcap_irq_handler); + irq_set_irq_wake(spi->irq, 1); /* ADC */ adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? @@ -514,7 +514,7 @@ remove_subdevs: free_irq(adc_irq, pcap); free_irqchip: for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); /* destroy_workqueue: */ destroy_workqueue(pcap->workqueue); free_pcap: diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index 0ca68860c0d0..fcd89e604ab1 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -344,14 +344,14 @@ static int __init egpio_probe(struct platform_device *pdev) ei->ack_write = 0; irq_end = ei->irq_start + ei->nirqs; for (irq = ei->irq_start; irq < irq_end; irq++) { - set_irq_chip(irq, &egpio_muxed_chip); - set_irq_chip_data(irq, ei); - set_irq_handler(irq, handle_simple_irq); + irq_set_chip(irq, &egpio_muxed_chip); + irq_set_chip_data(irq, ei); + irq_set_handler(irq, handle_simple_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); - set_irq_data(ei->chained_irq, ei); - set_irq_chained_handler(ei->chained_irq, egpio_handler); + irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(ei->chained_irq, ei); + irq_set_chained_handler(ei->chained_irq, egpio_handler); ack_irqs(ei); device_init_wakeup(&pdev->dev, 1); @@ -373,11 +373,11 @@ static int __exit egpio_remove(struct platform_device *pdev) if (ei->chained_irq) { irq_end = ei->irq_start + ei->nirqs; for (irq = ei->irq_start; irq < irq_end; irq++) { - set_irq_chip(irq, NULL); - set_irq_handler(irq, NULL); + irq_set_chip(irq, NULL); + irq_set_handler(irq, NULL); set_irq_flags(irq, 0); } - set_irq_chained_handler(ei->chained_irq, NULL); + irq_set_chained_handler(ei->chained_irq, NULL); device_init_wakeup(&pdev->dev, 0); } iounmap(ei->base_addr); diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index b3aa82339993..9ba2a2a15dcb 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -348,13 +348,13 @@ static int __devinit htcpld_setup_chip_irq( /* Setup irq handlers */ irq_end = chip->irq_start + chip->nirqs; for (irq = chip->irq_start; irq < irq_end; irq++) { - set_irq_chip(irq, &htcpld_muxed_chip); - set_irq_chip_data(irq, chip); - set_irq_handler(irq, handle_simple_irq); + irq_set_chip(irq, &htcpld_muxed_chip); + irq_set_chip_data(irq, chip); + irq_set_handler(irq, handle_simple_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); #else - set_irq_probe(irq); + irq_set_probe(irq); #endif } diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index aa518b9beaf5..a0bd0cf05af3 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -112,7 +112,7 @@ static struct irq_chip jz4740_adc_irq_chip = { static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct jz4740_adc *adc = get_irq_desc_data(desc); + struct jz4740_adc *adc = irq_desc_get_handler_data(desc); uint8_t status; unsigned int i; @@ -310,13 +310,13 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adc); for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { - set_irq_chip_data(irq, adc); - set_irq_chip_and_handler(irq, &jz4740_adc_irq_chip, - handle_level_irq); + irq_set_chip_data(irq, adc); + irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip, + handle_level_irq); } - set_irq_data(adc->irq, adc); - set_irq_chained_handler(adc->irq, jz4740_adc_irq_demux); + irq_set_handler_data(adc->irq, adc); + irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux); writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); writeb(0xff, adc->base + JZ_REG_ADC_CTRL); @@ -347,8 +347,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev) mfd_remove_devices(&pdev->dev); - set_irq_data(adc->irq, NULL); - set_irq_chained_handler(adc->irq, NULL); + irq_set_handler_data(adc->irq, NULL); + irq_set_chained_handler(adc->irq, NULL); iounmap(adc->base); release_mem_region(adc->mem->start, resource_size(adc->mem)); diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index a92ea9bb83fa..58cc5fdde016 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -547,14 +547,14 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, /* register with genirq */ for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { __irq = i + chip->irq_base; - set_irq_chip_data(__irq, chip); - set_irq_chip_and_handler(__irq, &max8925_irq_chip, + irq_set_chip_data(__irq, chip); + irq_set_chip_and_handler(__irq, &max8925_irq_chip, handle_edge_irq); - set_irq_nested_thread(__irq, 1); + irq_set_nested_thread(__irq, 1); #ifdef CONFIG_ARM set_irq_flags(__irq, IRQF_VALID); #else - set_irq_noprobe(__irq); + irq_set_noprobe(__irq); #endif } if (!irq) { diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index 3903e1fbb334..5919710dc9ed 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c @@ -224,14 +224,14 @@ int max8998_irq_init(struct max8998_dev *max8998) /* register with genirq */ for (i = 0; i < MAX8998_IRQ_NR; i++) { cur_irq = i + max8998->irq_base; - set_irq_chip_data(cur_irq, max8998); - set_irq_chip_and_handler(cur_irq, &max8998_irq_chip, + irq_set_chip_data(cur_irq, max8998); + irq_set_chip_and_handler(cur_irq, &max8998_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index c00214257da2..9ec7570f5b81 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -209,7 +209,7 @@ static int max8998_suspend(struct device *dev) struct max8998_dev *max8998 = i2c_get_clientdata(i2c); if (max8998->wakeup) - set_irq_wake(max8998->irq, 1); + irq_set_irq_wake(max8998->irq, 1); return 0; } @@ -219,7 +219,7 @@ static int max8998_resume(struct device *dev) struct max8998_dev *max8998 = i2c_get_clientdata(i2c); if (max8998->wakeup) - set_irq_wake(max8998->irq, 0); + irq_set_irq_wake(max8998->irq, 0); /* * In LP3974, if IRQ registers are not "read & clear" * when it's set during sleep, the interrupt becomes diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 3e5732b58c49..7ab7746631d4 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -762,14 +762,14 @@ static int __devinit stmpe_irq_init(struct stmpe *stmpe) int irq; for (irq = base; irq < base + num_irqs; irq++) { - set_irq_chip_data(irq, stmpe); - set_irq_chip_and_handler(irq, &stmpe_irq_chip, + irq_set_chip_data(irq, stmpe); + irq_set_chip_and_handler(irq, &stmpe_irq_chip, handle_edge_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -786,8 +786,8 @@ static void stmpe_irq_remove(struct stmpe *stmpe) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index af57fc706a4c..2e1fca4715ed 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -186,7 +186,7 @@ static struct mfd_cell t7l66xb_cells[] = { /* Handle the T7L66XB interrupt mux */ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) { - struct t7l66xb *t7l66xb = get_irq_data(irq); + struct t7l66xb *t7l66xb = irq_get_handler_data(irq); unsigned int isr; unsigned int i, irq_base; @@ -243,17 +243,17 @@ static void t7l66xb_attach_irq(struct platform_device *dev) irq_base = t7l66xb->irq_base; for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { - set_irq_chip(irq, &t7l66xb_chip); - set_irq_chip_data(irq, t7l66xb); - set_irq_handler(irq, handle_level_irq); + irq_set_chip(irq, &t7l66xb_chip); + irq_set_chip_data(irq, t7l66xb); + irq_set_handler(irq, handle_level_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); #endif } - set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); - set_irq_data(t7l66xb->irq, t7l66xb); - set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); + irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); + irq_set_handler_data(t7l66xb->irq, t7l66xb); + irq_set_chained_handler(t7l66xb->irq, t7l66xb_irq); } static void t7l66xb_detach_irq(struct platform_device *dev) @@ -263,15 +263,15 @@ static void t7l66xb_detach_irq(struct platform_device *dev) irq_base = t7l66xb->irq_base; - set_irq_chained_handler(t7l66xb->irq, NULL); - set_irq_data(t7l66xb->irq, NULL); + irq_set_chained_handler(t7l66xb->irq, NULL); + irq_set_handler_data(t7l66xb->irq, NULL); for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip(irq, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip(irq, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 729dbeed2ce0..c27e515b0722 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -192,14 +192,14 @@ static int tc3589x_irq_init(struct tc3589x *tc3589x) int irq; for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { - set_irq_chip_data(irq, tc3589x); - set_irq_chip_and_handler(irq, &dummy_irq_chip, + irq_set_chip_data(irq, tc3589x); + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_edge_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -215,8 +215,8 @@ static void tc3589x_irq_remove(struct tc3589x *tc3589x) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 3d62ded86a8f..06112c8628bf 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -513,7 +513,7 @@ static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) static void tc6393xb_irq(unsigned int irq, struct irq_desc *desc) { - struct tc6393xb *tc6393xb = get_irq_data(irq); + struct tc6393xb *tc6393xb = irq_get_handler_data(irq); unsigned int isr; unsigned int i, irq_base; @@ -572,15 +572,15 @@ static void tc6393xb_attach_irq(struct platform_device *dev) irq_base = tc6393xb->irq_base; for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { - set_irq_chip(irq, &tc6393xb_chip); - set_irq_chip_data(irq, tc6393xb); - set_irq_handler(irq, handle_edge_irq); + irq_set_chip(irq, &tc6393xb_chip); + irq_set_chip_data(irq, tc6393xb); + irq_set_handler(irq, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); - set_irq_data(tc6393xb->irq, tc6393xb); - set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq); + irq_set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); + irq_set_handler_data(tc6393xb->irq, tc6393xb); + irq_set_chained_handler(tc6393xb->irq, tc6393xb_irq); } static void tc6393xb_detach_irq(struct platform_device *dev) @@ -588,15 +588,15 @@ static void tc6393xb_detach_irq(struct platform_device *dev) struct tc6393xb *tc6393xb = platform_get_drvdata(dev); unsigned int irq, irq_base; - set_irq_chained_handler(tc6393xb->irq, NULL); - set_irq_data(tc6393xb->irq, NULL); + irq_set_chained_handler(tc6393xb->irq, NULL); + irq_set_handler_data(tc6393xb->irq, NULL); irq_base = tc6393xb->irq_base; for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { set_irq_flags(irq, 0); - set_irq_chip(irq, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip(irq, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 0aa9186aec19..b600808690c1 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -422,10 +422,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { int __irq = i + tps6586x->irq_base; - set_irq_chip_data(__irq, tps6586x); - set_irq_chip_and_handler(__irq, &tps6586x->irq_chip, + irq_set_chip_data(__irq, tps6586x); + irq_set_chip_and_handler(__irq, &tps6586x->irq_chip, handle_simple_irq); - set_irq_nested_thread(__irq, 1); + irq_set_nested_thread(__irq, 1); #ifdef CONFIG_ARM set_irq_flags(__irq, IRQF_VALID); #endif diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 47e8de0f3366..8a7ee3139b86 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -454,7 +454,7 @@ static inline void activate_irq(int irq) set_irq_flags(irq, IRQF_VALID); #else /* same effect on other architectures */ - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -650,7 +650,7 @@ static inline int sih_read_isr(const struct sih *sih) */ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) { - struct sih_agent *agent = get_irq_data(irq); + struct sih_agent *agent = irq_get_handler_data(irq); const struct sih *sih = agent->sih; int isr; @@ -724,9 +724,9 @@ int twl4030_sih_setup(int module) for (i = 0; i < sih->bits; i++) { irq = irq_base + i; - set_irq_chip_and_handler(irq, &twl4030_sih_irq_chip, - handle_edge_irq); - set_irq_chip_data(irq, agent); + irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip, + handle_edge_irq); + irq_set_chip_data(irq, agent); activate_irq(irq); } @@ -735,8 +735,8 @@ int twl4030_sih_setup(int module) /* replace generic PIH handler (handle_simple_irq) */ irq = sih_mod + twl4030_irq_base; - set_irq_data(irq, agent); - set_irq_chained_handler(irq, handle_twl4030_sih); + irq_set_handler_data(irq, agent); + irq_set_chained_handler(irq, handle_twl4030_sih); pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, irq, irq_base, twl4030_irq_next - 1); @@ -785,8 +785,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; for (i = irq_base; i < irq_end; i++) { - set_irq_chip_and_handler(i, &twl4030_irq_chip, - handle_simple_irq); + irq_set_chip_and_handler(i, &twl4030_irq_chip, + handle_simple_irq); activate_irq(i); } twl4030_irq_next = i; @@ -826,7 +826,7 @@ fail_rqirq: /* clean up twl4030_sih_setup */ fail: for (i = irq_base; i < irq_end; i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); destroy_workqueue(wq); wq = NULL; return status; diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 3b9c7756cb6d..fa937052fbab 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -183,7 +183,7 @@ static inline void activate_irq(int irq) set_irq_flags(irq, IRQF_VALID); #else /* same effect on other architectures */ - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -320,8 +320,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) twl6030_irq_chip.irq_set_type = NULL; for (i = irq_base; i < irq_end; i++) { - set_irq_chip_and_handler(i, &twl6030_irq_chip, - handle_simple_irq); + irq_set_chip_and_handler(i, &twl6030_irq_chip, + handle_simple_irq); activate_irq(i); } @@ -350,7 +350,7 @@ fail_irq: fail_kthread: for (i = irq_base; i < irq_end; i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); return status; } diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index a5cd17e18d09..23e66af89dea 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -553,17 +553,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) for (cur_irq = wm831x->irq_base; cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; cur_irq++) { - set_irq_chip_data(cur_irq, wm831x); - set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip, + irq_set_chip_data(cur_irq, wm831x); + irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); /* ARM needs us to explicitly flag the IRQ as valid * and will set them noprobe when we do so. */ #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 5839966ebd85..ed4b22a167b3 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -518,17 +518,17 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq, for (cur_irq = wm8350->irq_base; cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; cur_irq++) { - set_irq_chip_data(cur_irq, wm8350); - set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip, + irq_set_chip_data(cur_irq, wm8350); + irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); /* ARM needs us to explicitly flag the IRQ as valid * and will set them noprobe when we do so. */ #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 1e3bf4a2ff8e..71c6e8f9aedb 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -278,17 +278,17 @@ int wm8994_irq_init(struct wm8994 *wm8994) for (cur_irq = wm8994->irq_base; cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; cur_irq++) { - set_irq_chip_data(cur_irq, wm8994); - set_irq_chip_and_handler(cur_irq, &wm8994_irq_chip, + irq_set_chip_data(cur_irq, wm8994); + irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); /* ARM needs us to explicitly flag the IRQ as valid * and will set them noprobe when we do so. */ #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } -- cgit v1.2.2 From d6f7ce9f7fde069424e6400c31717ef34aab7e5f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:12:35 +0000 Subject: mfd: Fold irq_set_chip/irq_set_handler Use the combined irq_set_chip_and_handler() function instead. Converted with coccinelle. Signed-off-by: Thomas Gleixner Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 3 +-- drivers/mfd/htc-egpio.c | 7 +++---- drivers/mfd/htc-i2cpld.c | 4 ++-- drivers/mfd/t7l66xb.c | 3 +-- drivers/mfd/tc6393xb.c | 3 +-- 5 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 22b5a78bbfdb..d4a851c6b5bf 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -416,8 +416,7 @@ static void asic3_irq_remove(struct platform_device *pdev) for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { set_irq_flags(irq, 0); - irq_set_handler(irq, NULL); - irq_set_chip(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_data(irq, NULL); } irq_set_chained_handler(asic->irq_nr, NULL); diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index fcd89e604ab1..bbaec0ccba8f 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -344,9 +344,9 @@ static int __init egpio_probe(struct platform_device *pdev) ei->ack_write = 0; irq_end = ei->irq_start + ei->nirqs; for (irq = ei->irq_start; irq < irq_end; irq++) { - irq_set_chip(irq, &egpio_muxed_chip); + irq_set_chip_and_handler(irq, &egpio_muxed_chip, + handle_simple_irq); irq_set_chip_data(irq, ei); - irq_set_handler(irq, handle_simple_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); @@ -373,8 +373,7 @@ static int __exit egpio_remove(struct platform_device *pdev) if (ei->chained_irq) { irq_end = ei->irq_start + ei->nirqs; for (irq = ei->irq_start; irq < irq_end; irq++) { - irq_set_chip(irq, NULL); - irq_set_handler(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); set_irq_flags(irq, 0); } irq_set_chained_handler(ei->chained_irq, NULL); diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 9ba2a2a15dcb..d55065cc324c 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -348,9 +348,9 @@ static int __devinit htcpld_setup_chip_irq( /* Setup irq handlers */ irq_end = chip->irq_start + chip->nirqs; for (irq = chip->irq_start; irq < irq_end; irq++) { - irq_set_chip(irq, &htcpld_muxed_chip); + irq_set_chip_and_handler(irq, &htcpld_muxed_chip, + handle_simple_irq); irq_set_chip_data(irq, chip); - irq_set_handler(irq, handle_simple_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); #else diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 2e1fca4715ed..42830e692964 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -243,9 +243,8 @@ static void t7l66xb_attach_irq(struct platform_device *dev) irq_base = t7l66xb->irq_base; for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { - irq_set_chip(irq, &t7l66xb_chip); + irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq); irq_set_chip_data(irq, t7l66xb); - irq_set_handler(irq, handle_level_irq); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); #endif diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 06112c8628bf..fc53ce287601 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -572,9 +572,8 @@ static void tc6393xb_attach_irq(struct platform_device *dev) irq_base = tc6393xb->irq_base; for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { - irq_set_chip(irq, &tc6393xb_chip); + irq_set_chip_and_handler(irq, &tc6393xb_chip, handle_edge_irq); irq_set_chip_data(irq, tc6393xb); - irq_set_handler(irq, handle_edge_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } -- cgit v1.2.2 From 8317d5178e7491589693693e5a7f64442cf46ca2 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 25 Mar 2011 17:56:02 +0100 Subject: mfd: Clean up max8997 IRQ namespace Signed-off-by: Samuel Ortiz --- drivers/mfd/max8997-irq.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c index e85c874133c4..638bf7e4d3b3 100644 --- a/drivers/mfd/max8997-irq.c +++ b/drivers/mfd/max8997-irq.c @@ -115,14 +115,14 @@ static const struct max8997_irq_data max8997_irqs[] = { static void max8997_irq_lock(struct irq_data *data) { - struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); mutex_lock(&max8997->irqlock); } static void max8997_irq_sync_unlock(struct irq_data *data) { - struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); int i; for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { @@ -149,7 +149,7 @@ irq_to_max8997_irq(struct max8997_dev *max8997, int irq) static void max8997_irq_mask(struct irq_data *data) { - struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, data->irq); @@ -158,7 +158,7 @@ static void max8997_irq_mask(struct irq_data *data) static void max8997_irq_unmask(struct irq_data *data) { - struct max8997_dev *max8997 = get_irq_chip_data(data->irq); + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, data->irq); @@ -332,14 +332,14 @@ int max8997_irq_init(struct max8997_dev *max8997) /* Register with genirq */ for (i = 0; i < MAX8997_IRQ_NR; i++) { cur_irq = i + max8997->irq_base; - set_irq_chip_data(cur_irq, max8997); - set_irq_chip_and_handler(cur_irq, &max8997_irq_chip, + irq_set_chip_data(cur_irq, max8997); + irq_set_chip_and_handler(cur_irq, &max8997_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } -- cgit v1.2.2 From 7b824bbdd6210155bac9e1a1d795f94f8f2927b2 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 26 Mar 2011 21:16:04 -0700 Subject: Input: wacom - constify wacom_features for a new missed Bamboo models Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 5597637cfd41..ba6e17c5e254 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1366,23 +1366,23 @@ static const struct wacom_features wacom_features_0xE3 = { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; -static struct wacom_features wacom_features_0xD0 = +static const struct wacom_features wacom_features_0xD0 = { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD1 = +static const struct wacom_features wacom_features_0xD1 = { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD2 = +static const 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 = +static const 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_0xD6 = +static const struct wacom_features wacom_features_0xD6 = { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD7 = +static const struct wacom_features wacom_features_0xD7 = { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; -static struct wacom_features wacom_features_0xD8 = +static const 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 = +static const struct wacom_features wacom_features_0xDA = { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; static struct wacom_features wacom_features_0xDB = { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; -- cgit v1.2.2 From e35fb8c1db2d6fc92783d492e458d19b06502742 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Sat, 26 Mar 2011 21:16:05 -0700 Subject: Input: wacom - report resolution for pen devices Touch resolution is reported to the userland by retrieving the value from the HID descriptor. But pen resolution is not since it can not be retrieved. The current Wacom X driver has a resolution table. To centralize the source of these values, the resolution entries are added in the wacom_features struct for x and y coordinates respectively. The values are then reported to the userland. Signed-off-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 271 ++++++++++++++++++++++++++------------- drivers/input/tablet/wacom_wac.h | 2 + 2 files changed, 181 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index ba6e17c5e254..c87d94ff6ae4 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -16,6 +16,14 @@ #include "wacom.h" #include +/* resolution for penabled devices */ +#define WACOM_PL_RES 20 +#define WACOM_PENPRTN_RES 40 +#define WACOM_VOLITO_RES 50 +#define WACOM_GRAPHIRE_RES 80 +#define WACOM_INTUOS_RES 100 +#define WACOM_INTUOS3_RES 200 + static int wacom_penpartner_irq(struct wacom_wac *wacom) { unsigned char *data = wacom->data; @@ -1055,6 +1063,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max, features->pressure_fuzz, 0); + if (features->device_type == BTN_TOOL_PEN) { + /* penabled devices have fixed resolution for each model */ + input_abs_set_res(input_dev, ABS_X, features->x_resolution); + input_abs_set_res(input_dev, ABS_Y, features->y_resolution); + } else { + input_abs_set_res(input_dev, ABS_X, + wacom_calculate_touch_res(features->x_max, + features->x_phy)); + input_abs_set_res(input_dev, ABS_Y, + wacom_calculate_touch_res(features->y_max, + features->y_phy)); + } + __set_bit(ABS_MISC, input_dev->absbit); switch (wacom_wac->features.type) { @@ -1171,15 +1192,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case TABLETPC: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type != BTN_TOOL_PEN) { - input_abs_set_res(input_dev, ABS_X, - wacom_calculate_touch_res(features->x_max, - features->x_phy)); - input_abs_set_res(input_dev, ABS_Y, - wacom_calculate_touch_res(features->y_max, - features->y_phy)); + if (features->device_type != BTN_TOOL_PEN) break; /* no need to process stylus stuff */ - } + /* fall through */ case PL: @@ -1216,12 +1231,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, features->pressure_max, features->pressure_fuzz, 0); - input_abs_set_res(input_dev, ABS_X, - wacom_calculate_touch_res(features->x_max, - features->x_phy)); - input_abs_set_res(input_dev, ABS_Y, - wacom_calculate_touch_res(features->y_max, - features->y_phy)); } else if (features->device_type == BTN_TOOL_PEN) { __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); @@ -1233,161 +1242,239 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, } static const struct wacom_features wacom_features_0x00 = - { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, 0, PENPARTNER }; + { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255, + 0, PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; static const struct wacom_features wacom_features_0x10 = - { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }; + { "Wacom Graphire", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x11 = - { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, 63, GRAPHIRE }; + { "Wacom Graphire2 4x5", WACOM_PKGLEN_GRAPHIRE, 10206, 7422, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x12 = - { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, 63, GRAPHIRE }; + { "Wacom Graphire2 5x7", WACOM_PKGLEN_GRAPHIRE, 13918, 10206, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x13 = - { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, GRAPHIRE }; + { "Wacom Graphire3", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x14 = - { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }; + { "Wacom Graphire3 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x15 = - { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, 63, WACOM_G4 }; + { "Wacom Graphire4 4x5", WACOM_PKGLEN_GRAPHIRE, 10208, 7424, 511, + 63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x16 = - { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, WACOM_G4 }; + { "Wacom Graphire4 6x8", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, + 63, WACOM_G4, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x17 = - { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }; + { "Wacom BambooFun 4x5", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, + 63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x18 = - { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, 63, WACOM_MO }; + { "Wacom BambooFun 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 511, + 63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x19 = - { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, 63, GRAPHIRE }; + { "Wacom Bamboo1 Medium", WACOM_PKGLEN_GRAPHIRE, 16704, 12064, 511, + 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x60 = - { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; + { "Wacom Volito", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x61 = - { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, 63, GRAPHIRE }; + { "Wacom PenStation2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 255, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x62 = - { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; + { "Wacom Volito2 4x5", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x63 = - { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, 63, GRAPHIRE }; + { "Wacom Volito2 2x3", WACOM_PKGLEN_GRAPHIRE, 3248, 2320, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x64 = - { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, 63, GRAPHIRE }; + { "Wacom PenPartner2", WACOM_PKGLEN_GRAPHIRE, 3250, 2320, 511, + 63, GRAPHIRE, WACOM_VOLITO_RES, WACOM_VOLITO_RES }; static const struct wacom_features wacom_features_0x65 = - { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, 63, WACOM_MO }; + { "Wacom Bamboo", WACOM_PKGLEN_BBFUN, 14760, 9225, 511, + 63, WACOM_MO, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x69 = - { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE }; + { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, + 63, GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; static const struct wacom_features wacom_features_0x20 = - { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }; + { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x21 = - { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; + { "Wacom Intuos 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x22 = - { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }; + { "Wacom Intuos 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x23 = - { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x24 = - { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x30 = - { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, 0, PL }; + { "Wacom PL400", WACOM_PKGLEN_GRAPHIRE, 5408, 4056, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x31 = - { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, 0, PL }; + { "Wacom PL500", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x32 = - { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, 0, PL }; + { "Wacom PL600", WACOM_PKGLEN_GRAPHIRE, 6126, 4604, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x33 = - { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, 0, PL }; + { "Wacom PL600SX", WACOM_PKGLEN_GRAPHIRE, 6260, 5016, 255, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x34 = - { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, 0, PL }; + { "Wacom PL550", WACOM_PKGLEN_GRAPHIRE, 6144, 4608, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x35 = - { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, 0, PL }; + { "Wacom PL800", WACOM_PKGLEN_GRAPHIRE, 7220, 5780, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x37 = - { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, 0, PL }; + { "Wacom PL700", WACOM_PKGLEN_GRAPHIRE, 6758, 5406, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x38 = - { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }; + { "Wacom PL510", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x39 = - { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, 0, PL }; + { "Wacom DTU710", WACOM_PKGLEN_GRAPHIRE, 34080, 27660, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0xC4 = - { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, 0, PL }; + { "Wacom DTF521", WACOM_PKGLEN_GRAPHIRE, 6282, 4762, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0xC0 = - { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }; + { "Wacom DTF720", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0xC2 = - { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, 0, PL }; + { "Wacom DTF720a", WACOM_PKGLEN_GRAPHIRE, 6858, 5506, 511, + 0, PL, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x03 = - { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, 0, PTU }; + { "Wacom Cintiq Partner", WACOM_PKGLEN_GRAPHIRE, 20480, 15360, 511, + 0, PTU, WACOM_PL_RES, WACOM_PL_RES }; static const struct wacom_features wacom_features_0x41 = - { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS }; + { "Wacom Intuos2 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x42 = - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x43 = - { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, 31, INTUOS }; + { "Wacom Intuos2 9x12", WACOM_PKGLEN_INTUOS, 30480, 24060, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x44 = - { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos2 12x12", WACOM_PKGLEN_INTUOS, 30480, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x45 = - { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, 31, INTUOS }; + { "Wacom Intuos2 12x18", WACOM_PKGLEN_INTUOS, 45720, 31680, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xB0 = - { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, 63, INTUOS3S }; + { "Wacom Intuos3 4x5", WACOM_PKGLEN_INTUOS, 25400, 20320, 1023, + 63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB1 = - { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, 63, INTUOS3 }; + { "Wacom Intuos3 6x8", WACOM_PKGLEN_INTUOS, 40640, 30480, 1023, + 63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB2 = - { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, 63, INTUOS3 }; + { "Wacom Intuos3 9x12", WACOM_PKGLEN_INTUOS, 60960, 45720, 1023, + 63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB3 = - { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, 63, INTUOS3L }; + { "Wacom Intuos3 12x12", WACOM_PKGLEN_INTUOS, 60960, 60960, 1023, + 63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB4 = - { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, 63, INTUOS3L }; + { "Wacom Intuos3 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 1023, + 63, INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB5 = - { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, 63, INTUOS3 }; + { "Wacom Intuos3 6x11", WACOM_PKGLEN_INTUOS, 54204, 31750, 1023, + 63, INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB7 = - { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, 63, INTUOS3S }; + { "Wacom Intuos3 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 1023, + 63, INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB8 = - { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, 63, INTUOS4S }; + { "Wacom Intuos4 4x6", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047, + 63, INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xB9 = - { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, 63, INTUOS4 }; + { "Wacom Intuos4 6x9", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047, + 63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xBA = - { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L }; + { "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, + 63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xBB = - { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L }; + { "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, + 63, INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xBC = - { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047, 63, INTUOS4 }; + { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047, + 63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0x3F = - { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ }; + { "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, + 63, CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC5 = - { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, 63, WACOM_BEE }; + { "Wacom Cintiq 20WSX", WACOM_PKGLEN_INTUOS, 86680, 54180, 1023, + 63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC6 = - { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE }; + { "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, + 63, WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0xC7 = - { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL }; + { "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, + 0, PL, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xCE = - { "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, 0, DTU }; + { "Wacom DTU2231", WACOM_PKGLEN_GRAPHIRE, 47864, 27011, 511, + 0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xF0 = - { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, 0, DTU }; + { "Wacom DTU1631", WACOM_PKGLEN_GRAPHIRE, 34623, 19553, 511, + 0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xCC = - { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, 63, WACOM_21UX2 }; + { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, + 63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; static const struct wacom_features wacom_features_0x90 = - { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x93 = - { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x9A = - { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x9F = - { "Wacom ISDv4 9F", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC }; + { "Wacom ISDv4 9F", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xE2 = - { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; + { "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xE3 = - { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG }; + { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = - { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS }; + { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, + 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD0 = - { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD1 = - { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD2 = - { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD3 = - { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD4 = - { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT }; + { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD6 = - { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD7 = - { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD8 = - { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xDA = - { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static struct wacom_features wacom_features_0xDB = - { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT }; + { "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, + 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x6004 = - { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, 0, TABLETPC }; + { "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; #define USB_DEVICE_WACOM(prod) \ USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index 835f756b150c..53eb71b68330 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -74,6 +74,8 @@ struct wacom_features { int pressure_max; int distance_max; int type; + int x_resolution; + int y_resolution; int device_type; int x_phy; int y_phy; -- cgit v1.2.2 From d51ca07634b8a441f731e087e93775a67d629a8c Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sat, 26 Mar 2011 22:52:25 -0700 Subject: Input: h3600_ts_input - fix a spelling error Signed-off-by: Sylvestre Ledru Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/h3600_ts_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index b4d7f63deff1..efa06882de00 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -62,7 +62,7 @@ MODULE_LICENSE("GPL"); Programmer has no control over these numbers. TODO there are holes - specifically 1,7,0x0a */ -#define VERSION_ID 0 /* Get Version (request/respose) */ +#define VERSION_ID 0 /* Get Version (request/response) */ #define KEYBD_ID 2 /* Keyboard (event) */ #define TOUCHS_ID 3 /* Touch Screen (event)*/ #define EEPROM_READ_ID 4 /* (request/response) */ -- cgit v1.2.2 From ac065bf214bb6a7fb7536f2dde686d4694342801 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 26 Mar 2011 04:47:35 +0300 Subject: HID: hiddev: fix brace indent There was an extra tab so the close curly brace didn't match up with the right if statement. Signed-off-by: Dan Carpenter Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index af0a7c1002af..527003188bfe 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -509,7 +509,7 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, (uref_multi->num_values > HID_MAX_MULTI_USAGES || uref->usage_index + uref_multi->num_values > field->report_count)) goto inval; - } + } switch (cmd) { case HIDIOCGUSAGE: -- cgit v1.2.2 From a51b907b2ecdfd3830576733810233f00dcfb2af Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 26 Mar 2011 23:28:42 +0800 Subject: regulator: Add MODULE_DEVICE_TABLE to max8997 and max8998 The device table is required to load modules based on modaliases. Signed-off-by: Axel Lin Cc: MyungJoo Ham Cc: Kyungmin Park Cc: Marek Szyprowski Acked-by: Mark Brown Signed-off-by: Liam Girdwood --- drivers/regulator/max8997.c | 1 + drivers/regulator/max8998.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 01ef7e9903bb..77e0cfb30b23 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -1185,6 +1185,7 @@ static const struct platform_device_id max8997_pmic_id[] = { { "max8997-pmic", 0}, { }, }; +MODULE_DEVICE_TABLE(platform, max8997_pmic_id); static struct platform_driver max8997_pmic_driver = { .driver = { diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 0ec49ca527a8..43410266f993 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -887,6 +887,7 @@ static const struct platform_device_id max8998_pmic_id[] = { { "lp3974-pmic", TYPE_LP3974 }, { } }; +MODULE_DEVICE_TABLE(platform, max8998_pmic_id); static struct platform_driver max8998_pmic_driver = { .driver = { -- cgit v1.2.2 From d2a1cfebe38edc0bbac8f5cfbce062fe3d146d7a Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Sun, 27 Mar 2011 20:29:02 +0200 Subject: HID: hidraw: fix comments Adjust the comments a little bit. Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 54409cba018c..93c72e593701 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -101,8 +101,8 @@ out: return ret; } -/* the first byte is expected to be a report number */ -/* This function is to be called with the minors_lock mutex held */ +/* The first byte is expected to be a report number. + * This function is to be called with the minors_lock mutex held */ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type) { unsigned int minor = iminor(file->f_path.dentry->d_inode); @@ -166,11 +166,11 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t /* This function performs a Get_Report transfer over the control endpoint - per section 7.2.1 of the HID specification, version 1.1. The first byte - of buffer is the report number to request, or 0x0 if the defice does not - use numbered reports. The report_type parameter can be HID_FEATURE_REPORT - or HID_INPUT_REPORT. This function is to be called with the minors_lock - mutex held. */ + * per section 7.2.1 of the HID specification, version 1.1. The first byte + * of buffer is the report number to request, or 0x0 if the defice does not + * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT + * or HID_INPUT_REPORT. This function is to be called with the minors_lock + * mutex held. */ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type) { unsigned int minor = iminor(file->f_path.dentry->d_inode); @@ -207,7 +207,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t } /* Read the first byte from the user. This is the report number, - which is passed to dev->hid_get_raw_report(). */ + * which is passed to dev->hid_get_raw_report(). */ if (copy_from_user(&report_number, buffer, 1)) { ret = -EFAULT; goto out_free; -- cgit v1.2.2 From ee6f0988a69b3a81bcea0871418ecf5db332149c Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 24 Mar 2011 02:34:32 +0000 Subject: can: c_can: disable one shot mode until driver is fixed This patch disables the one shot mode, until the driver has been fixed and tested to support it. > I'm quite sure I've seen a situation where msg_obj 17 "seemed" to be > pending, while msg_obj 18 and 19 already have been transmitted. But > in that case, I enabled ONESHOT for the can interface, which enables > the DA mode (automatic retransmission is disabled). Reported-by: Jan Altenberg Signed-off-by: Marc Kleine-Budde Signed-off-by: Kurt Van Dijck Cc: Bhupesh Sharma Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/c_can/c_can.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 110eda01843c..d0bffb08aef5 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -588,14 +588,9 @@ static void c_can_chip_config(struct net_device *dev) { struct c_can_priv *priv = netdev_priv(dev); - if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) - /* disable automatic retransmission */ - priv->write_reg(priv, &priv->regs->control, - CONTROL_DISABLE_AR); - else - /* enable automatic retransmission */ - priv->write_reg(priv, &priv->regs->control, - CONTROL_ENABLE_AR); + /* enable automatic retransmission */ + priv->write_reg(priv, &priv->regs->control, + CONTROL_ENABLE_AR); if (priv->can.ctrlmode & (CAN_CTRLMODE_LISTENONLY & CAN_CTRLMODE_LOOPBACK)) { @@ -1112,8 +1107,7 @@ struct net_device *alloc_c_can_dev(void) priv->can.bittiming_const = &c_can_bittiming_const; priv->can.do_set_mode = c_can_set_mode; priv->can.do_get_berr_counter = c_can_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT | - CAN_CTRLMODE_LOOPBACK | + priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING; -- cgit v1.2.2 From b0052b088cf0cb688b4630c1d520c57276da71a5 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 24 Mar 2011 02:34:33 +0000 Subject: can: c_can_platform: fix irq check in probe This patch fixes the check in the probe function whether a IRQ was supplied to the driver. The original driver check the irq "struct resource *" against <= 0. Use "platform_get_irq" instead. Signed-off-by: Marc Kleine-Budde Cc: Bhupesh Sharma Signed-off-by: David S. Miller --- drivers/net/can/c_can/c_can_platform.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c index e629b961ae2d..cc90824f2c9c 100644 --- a/drivers/net/can/c_can/c_can_platform.c +++ b/drivers/net/can/c_can/c_can_platform.c @@ -73,7 +73,8 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) void __iomem *addr; struct net_device *dev; struct c_can_priv *priv; - struct resource *mem, *irq; + struct resource *mem; + int irq; #ifdef CONFIG_HAVE_CLK struct clk *clk; @@ -88,8 +89,8 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) /* get the platform data */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!mem || (irq <= 0)) { + irq = platform_get_irq(pdev, 0); + if (!mem || irq <= 0) { ret = -ENODEV; goto exit_free_clk; } @@ -117,7 +118,7 @@ static int __devinit c_can_plat_probe(struct platform_device *pdev) priv = netdev_priv(dev); - dev->irq = irq->start; + dev->irq = irq; priv->regs = addr; #ifdef CONFIG_HAVE_CLK priv->can.clock.freq = clk_get_rate(clk); -- cgit v1.2.2 From dc760b375e50a47847d4942811bd9679beeb5535 Mon Sep 17 00:00:00 2001 From: Jan Altenberg Date: Sun, 27 Mar 2011 18:24:10 -0700 Subject: can: c_can: Fix tx_bytes accounting The current SocketCAN implementation for the Bosch c_can cell doesn't account the TX bytes correctly, because it calls c_can_inval_msg_object() (which clears the msg ctrl register) before reading the DLC value: for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { msg_obj_no = get_tx_echo_msg_obj(priv); c_can_inval_msg_object(dev, 0, msg_obj_no); val = c_can_read_reg32(priv, &priv->regs->txrqst1); if (!(val & (1 << msg_obj_no))) { can_get_echo_skb(dev, msg_obj_no - C_CAN_MSG_OBJ_TX_FIRST); stats->tx_bytes += priv->read_reg(priv, &priv->regs->ifregs[0].msg_cntrl) & IF_MCONT_DLC_MASK; stats->tx_packets++; } } So, we will always read 0 for the DLC value and "ifconfig" will report *0* TX Bytes. The fix is quite easy: Just move c_can_inval_msg_object() to the end of the if() statement. So: * We only call c_can_inval_msg_object() if the message was actually transmitted * We read out the DLC value _before_ clearing the msg ctrl register Signed-off-by: Jan Altenberg Acked-by: Kurt Van Dijck Acked-by: Wolfgang Grandegger Signed-off-by: David S. Miller --- drivers/net/can/c_can/c_can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index d0bffb08aef5..31552959aed7 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -699,7 +699,6 @@ static void c_can_do_tx(struct net_device *dev) for (/* nix */; (priv->tx_next - priv->tx_echo) > 0; priv->tx_echo++) { msg_obj_no = get_tx_echo_msg_obj(priv); - c_can_inval_msg_object(dev, 0, msg_obj_no); val = c_can_read_reg32(priv, &priv->regs->txrqst1); if (!(val & (1 << msg_obj_no))) { can_get_echo_skb(dev, @@ -708,6 +707,7 @@ static void c_can_do_tx(struct net_device *dev) &priv->regs->ifregs[0].msg_cntrl) & IF_MCONT_DLC_MASK; stats->tx_packets++; + c_can_inval_msg_object(dev, 0, msg_obj_no); } } -- cgit v1.2.2 From b3cd965739b8677f6e04913aa535fa156b09e73d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 25 Mar 2011 01:21:51 +0000 Subject: myri10ge: small rx_done refactoring Avoid theoretical race condition regarding accessing dev->features NETIF_F_LRO flag, which is illustrated below. CPU1 CPU2 myri10ge_clean_rx_done(): myri10ge_set_flags(): or myri10ge_set_rx_csum(): if (dev->features & NETIF_F_LRO) setup lro dev->features |= NETIF_F_LRO or dev->features &= ~NETIF_F_LRO; if (dev->features & NETIF_F_LRO) flush lro On the way reduce myri10ge_rx_done() number of arguments and calls by moving mgp->small_bytes check into that function. That reduce code size from: text data bss dec hex filename 36644 248 100 36992 9080 drivers/net/myri10ge/myri10ge.o to: text data bss dec hex filename 36037 247 100 36384 8e20 drivers/net/myri10ge/myri10ge.o on my i686 system, what should also make myri10ge_clean_rx_done() being faster. Signed-off-by: Stanislaw Gruszka Signed-off-by: David S. Miller --- drivers/net/myri10ge/myri10ge.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 1f4e8680a96a..673dc600c891 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1312,17 +1312,26 @@ myri10ge_unmap_rx_page(struct pci_dev *pdev, * page into an skb */ static inline int -myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, - int bytes, int len, __wsum csum) +myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum, + int lro_enabled) { struct myri10ge_priv *mgp = ss->mgp; struct sk_buff *skb; struct skb_frag_struct rx_frags[MYRI10GE_MAX_FRAGS_PER_FRAME]; - int i, idx, hlen, remainder; + struct myri10ge_rx_buf *rx; + int i, idx, hlen, remainder, bytes; struct pci_dev *pdev = mgp->pdev; struct net_device *dev = mgp->dev; u8 *va; + if (len <= mgp->small_bytes) { + rx = &ss->rx_small; + bytes = mgp->small_bytes; + } else { + rx = &ss->rx_big; + bytes = mgp->big_bytes; + } + len += MXGEFW_PAD; idx = rx->cnt & rx->mask; va = page_address(rx->info[idx].page) + rx->info[idx].page_offset; @@ -1341,7 +1350,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, remainder -= MYRI10GE_ALLOC_SIZE; } - if (dev->features & NETIF_F_LRO) { + if (lro_enabled) { rx_frags[0].page_offset += MXGEFW_PAD; rx_frags[0].size -= MXGEFW_PAD; len -= MXGEFW_PAD; @@ -1463,7 +1472,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) { struct myri10ge_rx_done *rx_done = &ss->rx_done; struct myri10ge_priv *mgp = ss->mgp; - struct net_device *netdev = mgp->dev; + unsigned long rx_bytes = 0; unsigned long rx_packets = 0; unsigned long rx_ok; @@ -1474,18 +1483,18 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) u16 length; __wsum checksum; + /* + * Prevent compiler from generating more than one ->features memory + * access to avoid theoretical race condition with functions that + * change NETIF_F_LRO flag at runtime. + */ + bool lro_enabled = ACCESS_ONCE(mgp->dev->features) & NETIF_F_LRO; + while (rx_done->entry[idx].length != 0 && work_done < budget) { length = ntohs(rx_done->entry[idx].length); rx_done->entry[idx].length = 0; checksum = csum_unfold(rx_done->entry[idx].checksum); - if (length <= mgp->small_bytes) - rx_ok = myri10ge_rx_done(ss, &ss->rx_small, - mgp->small_bytes, - length, checksum); - else - rx_ok = myri10ge_rx_done(ss, &ss->rx_big, - mgp->big_bytes, - length, checksum); + rx_ok = myri10ge_rx_done(ss, length, checksum, lro_enabled); rx_packets += rx_ok; rx_bytes += rx_ok * (unsigned long)length; cnt++; @@ -1497,7 +1506,7 @@ myri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) ss->stats.rx_packets += rx_packets; ss->stats.rx_bytes += rx_bytes; - if (netdev->features & NETIF_F_LRO) + if (lro_enabled) lro_flush_all(&rx_done->lro_mgr); /* restock receive rings if needed */ -- cgit v1.2.2 From f4e5bd4f5784c0608078805f29d4a4897ee482f7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 26 Mar 2011 01:34:06 +0000 Subject: Net / jme: Do not use legacy PCI power management The jme driver uses the legacy PCI power management, so it has to do some PCI-specific things in its ->suspend() and ->resume() callbacks, which isn't necessary and should better be done by the PCI sybsystem-level power management code. It also doesn't use device wakeup flags correctly. Convert jme to the new PCI power management framework and make it let the PCI subsystem take care of all the PCI-specific aspects of device handling during system power transitions. Signed-off-by: Rafael J. Wysocki Signed-off-by: David S. Miller --- drivers/net/jme.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/jme.c b/drivers/net/jme.c index f690474f4409..994c80939c7a 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -273,7 +273,7 @@ jme_clear_pm(struct jme_adapter *jme) { jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); pci_set_power_state(jme->pdev, PCI_D0); - pci_enable_wake(jme->pdev, PCI_D0, false); + device_set_wakeup_enable(&jme->pdev->dev, false); } static int @@ -2538,6 +2538,8 @@ jme_set_wol(struct net_device *netdev, jwrite32(jme, JME_PMCS, jme->reg_pmcs); + device_set_wakeup_enable(&jme->pdev->dev, jme->reg_pmcs); + return 0; } @@ -3172,9 +3174,9 @@ jme_shutdown(struct pci_dev *pdev) } #ifdef CONFIG_PM -static int -jme_suspend(struct pci_dev *pdev, pm_message_t state) +static int jme_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct jme_adapter *jme = netdev_priv(netdev); @@ -3206,22 +3208,18 @@ jme_suspend(struct pci_dev *pdev, pm_message_t state) tasklet_hi_enable(&jme->rxclean_task); tasklet_hi_enable(&jme->rxempty_task); - pci_save_state(pdev); jme_powersave_phy(jme); - pci_enable_wake(jme->pdev, PCI_D3hot, true); - pci_set_power_state(pdev, PCI_D3hot); return 0; } -static int -jme_resume(struct pci_dev *pdev) +static int jme_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct jme_adapter *jme = netdev_priv(netdev); - jme_clear_pm(jme); - pci_restore_state(pdev); + jwrite32(jme, JME_PMCS, 0xFFFF0000 | jme->reg_pmcs); jme_phy_on(jme); if (test_bit(JME_FLAG_SSET, &jme->flags)) @@ -3238,6 +3236,13 @@ jme_resume(struct pci_dev *pdev) return 0; } + +static SIMPLE_DEV_PM_OPS(jme_pm_ops, jme_suspend, jme_resume); +#define JME_PM_OPS (&jme_pm_ops) + +#else + +#define JME_PM_OPS NULL #endif static DEFINE_PCI_DEVICE_TABLE(jme_pci_tbl) = { @@ -3251,11 +3256,8 @@ static struct pci_driver jme_driver = { .id_table = jme_pci_tbl, .probe = jme_init_one, .remove = __devexit_p(jme_remove_one), -#ifdef CONFIG_PM - .suspend = jme_suspend, - .resume = jme_resume, -#endif /* CONFIG_PM */ .shutdown = jme_shutdown, + .driver.pm = JME_PM_OPS, }; static int __init -- cgit v1.2.2 From 3e49e6d520401e1d25ec8d366520aad2c01adc1c Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Sat, 26 Mar 2011 05:10:30 +0000 Subject: net: use CHECKSUM_NONE instead of magic number Two places in the kernel were doing skb->ip_summed = 0. Change both to skb->ip_summed = CHECKSUM_NONE, which is more readable. Signed-off-by: Cesar Eduardo Barros Signed-off-by: David S. Miller --- drivers/net/ksz884x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 540a8dcbcc46..7f7d5708a658 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -4898,7 +4898,7 @@ static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev) goto unlock; } skb_copy_and_csum_dev(org_skb, skb->data); - org_skb->ip_summed = 0; + org_skb->ip_summed = CHECKSUM_NONE; skb->len = org_skb->len; copy_old_skb(org_skb, skb); } -- cgit v1.2.2 From 27fd9de8eb9bf48e4a09c8f02d13f56e9a074a1e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 26 Mar 2011 16:42:31 +0000 Subject: tg3: use and instead and It is proper style to include linux/foo.h instead asm/foo.h if both exist Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ebec88882c3b..513565503f90 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -48,9 +48,9 @@ #include #include -#include +#include #include -#include +#include #ifdef CONFIG_SPARC #include -- cgit v1.2.2 From 6303e6e8da770e62a4d38f7206fe046514276d14 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 26 Mar 2011 16:42:33 +0000 Subject: tg3: Fix inline keyword usage The correct usage is "static inline void" not "static void inline". Signed-off-by: Javier Martinez Canillas Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 513565503f90..73c942d85f07 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -13118,7 +13118,7 @@ done: static struct pci_dev * __devinit tg3_find_peer(struct tg3 *); -static void inline vlan_features_add(struct net_device *dev, unsigned long flags) +static inline void vlan_features_add(struct net_device *dev, unsigned long flags) { dev->vlan_features |= flags; } -- cgit v1.2.2 From b5845f9834d8f4c79d324bc59b99dbcf0a40f428 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 27 Mar 2011 01:01:26 +0000 Subject: mlx4_en: Fix loss of promiscuity The mlx4_en driver uses the combination stop_port/start_port in a number of places. Unfortunately that causes any promiscuous mode settings on the hardware to be lost. This patch fixes that problem. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/mlx4/en_netdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 5762ebde4455..4f158baa0246 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -742,6 +742,9 @@ int mlx4_en_start_port(struct net_device *dev) 0, MLX4_PROT_ETH)) mlx4_warn(mdev, "Failed Attaching Broadcast\n"); + /* Must redo promiscuous mode setup. */ + priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); + /* Schedule multicast task to populate multicast list */ queue_work(mdev->workqueue, &priv->mcast_task); -- cgit v1.2.2 From 673e63c688f43104c73aad8ea4237f7ad41fa14d Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 22 Mar 2011 23:54:49 +0000 Subject: net: fix ethtool->set_flags not intended -EINVAL return value After commit d5dbda23804156ae6f35025ade5307a49d1db6d7 "ethtool: Add support for vlan accleration.", drivers that have NETIF_F_HW_VLAN_TX, and/or NETIF_F_HW_VLAN_RX feature, but do not allow enable/disable vlan acceleration via ethtool set_flags, always return -EINVAL from that function. Fix by returning -EINVAL only if requested features do not match current settings and can not be changed by driver. Change any driver that define ethtool->set_flags to use ethtool_invalid_flags() to avoid similar problems in the future (also on drivers that do not have the problem). Tested with modified (to reproduce this bug) myri10ge driver. Cc: stable@kernel.org # 2.6.37+ Signed-off-by: Stanislaw Gruszka Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic_ethtool.c | 2 +- drivers/net/qlcnic/qlcnic_ethtool.c | 2 +- drivers/net/s2io.c | 2 +- drivers/net/vmxnet3/vmxnet3_ethtool.c | 4 ++-- drivers/net/vxge/vxge-ethtool.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 653d308e0f5d..3bdcc803ec68 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -871,7 +871,7 @@ static int netxen_nic_set_flags(struct net_device *netdev, u32 data) struct netxen_adapter *adapter = netdev_priv(netdev); int hw_lro; - if (data & ~ETH_FLAG_LRO) + if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) return -EINVAL; if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)) diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c index 4c14510e2a87..45b2755d6cba 100644 --- a/drivers/net/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/qlcnic/qlcnic_ethtool.c @@ -1003,7 +1003,7 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data) struct qlcnic_adapter *adapter = netdev_priv(netdev); int hw_lro; - if (data & ~ETH_FLAG_LRO) + if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) return -EINVAL; if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2ad6364103ea..356e74d20b80 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -6726,7 +6726,7 @@ static int s2io_ethtool_set_flags(struct net_device *dev, u32 data) int rc = 0; int changed = 0; - if (data & ~ETH_FLAG_LRO) + if (ethtool_invalid_flags(dev, data, ETH_FLAG_LRO)) return -EINVAL; if (data & ETH_FLAG_LRO) { diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 81254be85b92..51f2ef142a5b 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -304,8 +304,8 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data) u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1; unsigned long flags; - if (data & ~ETH_FLAG_LRO) - return -EOPNOTSUPP; + if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO)) + return -EINVAL; if (lro_requested ^ lro_present) { /* toggle the LRO feature*/ diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c index 1dd3a21b3a43..c5eb034107fd 100644 --- a/drivers/net/vxge/vxge-ethtool.c +++ b/drivers/net/vxge/vxge-ethtool.c @@ -1117,8 +1117,8 @@ static int vxge_set_flags(struct net_device *dev, u32 data) struct vxgedev *vdev = netdev_priv(dev); enum vxge_hw_status status; - if (data & ~ETH_FLAG_RXHASH) - return -EOPNOTSUPP; + if (ethtool_invalid_flags(dev, data, ETH_FLAG_RXHASH)) + return -EINVAL; if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en) return 0; -- cgit v1.2.2 From 0cb3fcd72cc3e6dd88f0e769746d294e5e6bafa9 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Wed, 9 Feb 2011 11:02:35 +0530 Subject: gpio: driver for 42 AB8500 GPIO pins To get rid of port expanders, the free GPIOs of ab8500 can be used. There are 42 GPIO pins. Out of which 16 are interrupt capable.This patch implements 16 virtual IRQ mapped to 16 interrupt capable AB8500 GPIOs. Signed-off-by: Bibek Basu Acked-by: Grant Likely [Renamed header file as per MFD structure] Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 5 + drivers/gpio/Makefile | 1 + drivers/gpio/ab8500-gpio.c | 522 +++++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/ab8500-core.c | 14 ++ drivers/mfd/ab8500-i2c.c | 2 +- 5 files changed, 543 insertions(+), 1 deletion(-) create mode 100644 drivers/gpio/ab8500-gpio.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d8d0cda2641d..d3743204a7e9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -414,4 +414,9 @@ config GPIO_JANZ_TTL This driver provides support for driving the pins in output mode only. Input mode is not supported. +config AB8500_GPIO + bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" + depends on AB8500_CORE + help + Select this to enable the AB8500 IC GPIO driver endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 3351cf87b0ed..becef5954356 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += janz-ttl.o obj-$(CONFIG_GPIO_SX150X) += sx150x.o obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o +obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o diff --git a/drivers/gpio/ab8500-gpio.c b/drivers/gpio/ab8500-gpio.c new file mode 100644 index 000000000000..e7b834d054b7 --- /dev/null +++ b/drivers/gpio/ab8500-gpio.c @@ -0,0 +1,522 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Author: BIBEK BASU + * License terms: GNU General Public License (GPL) version 2 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * GPIO registers offset + * Bank: 0x10 + */ +#define AB8500_GPIO_SEL1_REG 0x00 +#define AB8500_GPIO_SEL2_REG 0x01 +#define AB8500_GPIO_SEL3_REG 0x02 +#define AB8500_GPIO_SEL4_REG 0x03 +#define AB8500_GPIO_SEL5_REG 0x04 +#define AB8500_GPIO_SEL6_REG 0x05 + +#define AB8500_GPIO_DIR1_REG 0x10 +#define AB8500_GPIO_DIR2_REG 0x11 +#define AB8500_GPIO_DIR3_REG 0x12 +#define AB8500_GPIO_DIR4_REG 0x13 +#define AB8500_GPIO_DIR5_REG 0x14 +#define AB8500_GPIO_DIR6_REG 0x15 + +#define AB8500_GPIO_OUT1_REG 0x20 +#define AB8500_GPIO_OUT2_REG 0x21 +#define AB8500_GPIO_OUT3_REG 0x22 +#define AB8500_GPIO_OUT4_REG 0x23 +#define AB8500_GPIO_OUT5_REG 0x24 +#define AB8500_GPIO_OUT6_REG 0x25 + +#define AB8500_GPIO_PUD1_REG 0x30 +#define AB8500_GPIO_PUD2_REG 0x31 +#define AB8500_GPIO_PUD3_REG 0x32 +#define AB8500_GPIO_PUD4_REG 0x33 +#define AB8500_GPIO_PUD5_REG 0x34 +#define AB8500_GPIO_PUD6_REG 0x35 + +#define AB8500_GPIO_IN1_REG 0x40 +#define AB8500_GPIO_IN2_REG 0x41 +#define AB8500_GPIO_IN3_REG 0x42 +#define AB8500_GPIO_IN4_REG 0x43 +#define AB8500_GPIO_IN5_REG 0x44 +#define AB8500_GPIO_IN6_REG 0x45 +#define AB8500_GPIO_ALTFUN_REG 0x45 +#define ALTFUN_REG_INDEX 6 +#define AB8500_NUM_GPIO 42 +#define AB8500_NUM_VIR_GPIO_IRQ 16 + +enum ab8500_gpio_action { + NONE, + STARTUP, + SHUTDOWN, + MASK, + UNMASK +}; + +struct ab8500_gpio { + struct gpio_chip chip; + struct ab8500 *parent; + struct device *dev; + struct mutex lock; + u32 irq_base; + enum ab8500_gpio_action irq_action; + u16 rising; + u16 falling; +}; +/** + * to_ab8500_gpio() - get the pointer to ab8500_gpio + * @chip: Member of the structure ab8500_gpio + */ +static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct ab8500_gpio, chip); +} + +static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg, + unsigned offset, int val) +{ + struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); + u8 pos = offset % 8; + int ret; + + reg = reg + (offset / 8); + ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev, + AB8500_MISC, reg, 1 << pos, val << pos); + if (ret < 0) + dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); + return ret; +} +/** + * ab8500_gpio_get() - Get the particular GPIO value + * @chip: Gpio device + * @offset: GPIO number to read + */ +static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); + u8 mask = 1 << (offset % 8); + u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8); + int ret; + u8 data; + ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC, + reg, &data); + if (ret < 0) { + dev_err(ab8500_gpio->dev, "%s read failed\n", __func__); + return ret; + } + return (data & mask) >> (offset % 8); +} + +static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); + int ret; + /* Write the data */ + ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1); + if (ret < 0) + dev_err(ab8500_gpio->dev, "%s write failed\n", __func__); +} + +static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + int ret; + /* set direction as output */ + ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1); + if (ret < 0) + return ret; + /* disable pull down */ + ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1); + if (ret < 0) + return ret; + /* set the output as 1 or 0 */ + return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val); + +} + +static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + /* set the register as input */ + return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0); +} + +static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + /* + * Only some GPIOs are interrupt capable, and they are + * organized in discontiguous clusters: + * + * GPIO6 to GPIO13 + * GPIO24 and GPIO25 + * GPIO36 to GPIO41 + */ + static struct ab8500_gpio_irq_cluster { + int start; + int end; + } clusters[] = { + {.start = 6, .end = 13}, + {.start = 24, .end = 25}, + {.start = 36, .end = 41}, + }; + struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip); + int base = ab8500_gpio->irq_base; + int i; + + for (i = 0; i < ARRAY_SIZE(clusters); i++) { + struct ab8500_gpio_irq_cluster *cluster = &clusters[i]; + + if (offset >= cluster->start && offset <= cluster->end) + return base + offset - cluster->start; + + /* Advance by the number of gpios in this cluster */ + base += cluster->end - cluster->start + 1; + } + + return -EINVAL; +} + +static struct gpio_chip ab8500gpio_chip = { + .label = "ab8500_gpio", + .owner = THIS_MODULE, + .direction_input = ab8500_gpio_direction_input, + .get = ab8500_gpio_get, + .direction_output = ab8500_gpio_direction_output, + .set = ab8500_gpio_set, + .to_irq = ab8500_gpio_to_irq, +}; + +static unsigned int irq_to_rising(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + int offset = irq - ab8500_gpio->irq_base; + int new_irq = offset + AB8500_INT_GPIO6R + + ab8500_gpio->parent->irq_base; + return new_irq; +} + +static unsigned int irq_to_falling(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + int offset = irq - ab8500_gpio->irq_base; + int new_irq = offset + AB8500_INT_GPIO6F + + ab8500_gpio->parent->irq_base; + return new_irq; + +} + +static unsigned int rising_to_irq(unsigned int irq, void *dev) +{ + struct ab8500_gpio *ab8500_gpio = dev; + int offset = irq - AB8500_INT_GPIO6R + - ab8500_gpio->parent->irq_base ; + int new_irq = offset + ab8500_gpio->irq_base; + return new_irq; +} + +static unsigned int falling_to_irq(unsigned int irq, void *dev) +{ + struct ab8500_gpio *ab8500_gpio = dev; + int offset = irq - AB8500_INT_GPIO6F + - ab8500_gpio->parent->irq_base ; + int new_irq = offset + ab8500_gpio->irq_base; + return new_irq; + +} + +/* + * IRQ handler + */ + +static irqreturn_t handle_rising(int irq, void *dev) +{ + + handle_nested_irq(rising_to_irq(irq , dev)); + return IRQ_HANDLED; +} + +static irqreturn_t handle_falling(int irq, void *dev) +{ + + handle_nested_irq(falling_to_irq(irq, dev)); + return IRQ_HANDLED; +} + +static void ab8500_gpio_irq_lock(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + mutex_lock(&ab8500_gpio->lock); +} + +static void ab8500_gpio_irq_sync_unlock(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + int offset = irq - ab8500_gpio->irq_base; + bool rising = ab8500_gpio->rising & BIT(offset); + bool falling = ab8500_gpio->falling & BIT(offset); + int ret; + + switch (ab8500_gpio->irq_action) { + case STARTUP: + if (rising) + ret = request_threaded_irq(irq_to_rising(irq), + NULL, handle_rising, + IRQF_TRIGGER_RISING, + "ab8500-gpio-r", ab8500_gpio); + if (falling) + ret = request_threaded_irq(irq_to_falling(irq), + NULL, handle_falling, + IRQF_TRIGGER_FALLING, + "ab8500-gpio-f", ab8500_gpio); + break; + case SHUTDOWN: + if (rising) + free_irq(irq_to_rising(irq), ab8500_gpio); + if (falling) + free_irq(irq_to_falling(irq), ab8500_gpio); + break; + case MASK: + if (rising) + disable_irq(irq_to_rising(irq)); + if (falling) + disable_irq(irq_to_falling(irq)); + break; + case UNMASK: + if (rising) + enable_irq(irq_to_rising(irq)); + if (falling) + enable_irq(irq_to_falling(irq)); + break; + case NONE: + break; + } + ab8500_gpio->irq_action = NONE; + ab8500_gpio->rising &= ~(BIT(offset)); + ab8500_gpio->falling &= ~(BIT(offset)); + mutex_unlock(&ab8500_gpio->lock); +} + + +static void ab8500_gpio_irq_mask(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + ab8500_gpio->irq_action = MASK; +} + +static void ab8500_gpio_irq_unmask(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + ab8500_gpio->irq_action = UNMASK; +} + +static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + int offset = irq - ab8500_gpio->irq_base; + + if (type == IRQ_TYPE_EDGE_BOTH) { + ab8500_gpio->rising = BIT(offset); + ab8500_gpio->falling = BIT(offset); + } else if (type == IRQ_TYPE_EDGE_RISING) { + ab8500_gpio->rising = BIT(offset); + } else { + ab8500_gpio->falling = BIT(offset); + } + return 0; +} + +unsigned int ab8500_gpio_irq_startup(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + ab8500_gpio->irq_action = STARTUP; + return 0; +} + +void ab8500_gpio_irq_shutdown(unsigned int irq) +{ + struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq); + ab8500_gpio->irq_action = SHUTDOWN; +} + +static struct irq_chip ab8500_gpio_irq_chip = { + .name = "ab8500-gpio", + .startup = ab8500_gpio_irq_startup, + .shutdown = ab8500_gpio_irq_shutdown, + .bus_lock = ab8500_gpio_irq_lock, + .bus_sync_unlock = ab8500_gpio_irq_sync_unlock, + .mask = ab8500_gpio_irq_mask, + .unmask = ab8500_gpio_irq_unmask, + .set_type = ab8500_gpio_irq_set_type, +}; + +static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio) +{ + u32 base = ab8500_gpio->irq_base; + int irq; + + for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) { + set_irq_chip_data(irq, ab8500_gpio); + set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip, + handle_simple_irq); + set_irq_nested_thread(irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(irq, IRQF_VALID); +#else + set_irq_noprobe(irq); +#endif + } + + return 0; +} + +static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio) +{ + int base = ab8500_gpio->irq_base; + int irq; + + for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) { +#ifdef CONFIG_ARM + set_irq_flags(irq, 0); +#endif + set_irq_chip_and_handler(irq, NULL, NULL); + set_irq_chip_data(irq, NULL); + } +} + +static int __devinit ab8500_gpio_probe(struct platform_device *pdev) +{ + struct ab8500_platform_data *ab8500_pdata = + dev_get_platdata(pdev->dev.parent); + struct ab8500_gpio_platform_data *pdata; + struct ab8500_gpio *ab8500_gpio; + int ret; + int i; + + pdata = ab8500_pdata->gpio; + if (!pdata) { + dev_err(&pdev->dev, "gpio platform data missing\n"); + return -ENODEV; + } + + ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL); + if (ab8500_gpio == NULL) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + ab8500_gpio->dev = &pdev->dev; + ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent); + ab8500_gpio->chip = ab8500gpio_chip; + ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO; + ab8500_gpio->chip.dev = &pdev->dev; + ab8500_gpio->chip.base = pdata->gpio_base; + ab8500_gpio->irq_base = pdata->irq_base; + /* initialize the lock */ + mutex_init(&ab8500_gpio->lock); + /* + * AB8500 core will handle and clear the IRQ + * configre GPIO based on config-reg value. + * These values are for selecting the PINs as + * GPIO or alternate function + */ + for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++) { + ret = abx500_set_register_interruptible(ab8500_gpio->dev, + AB8500_MISC, i, + pdata->config_reg[i]); + if (ret < 0) + goto out_free; + } + ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC, + AB8500_GPIO_ALTFUN_REG, + pdata->config_reg[ALTFUN_REG_INDEX]); + if (ret < 0) + goto out_free; + + ret = ab8500_gpio_irq_init(ab8500_gpio); + if (ret) + goto out_free; + ret = gpiochip_add(&ab8500_gpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpiochip: %d\n", + ret); + goto out_rem_irq; + } + platform_set_drvdata(pdev, ab8500_gpio); + return 0; + +out_rem_irq: + ab8500_gpio_irq_remove(ab8500_gpio); +out_free: + mutex_destroy(&ab8500_gpio->lock); + kfree(ab8500_gpio); + return ret; +} + +/* + * ab8500_gpio_remove() - remove Ab8500-gpio driver + * @pdev : Platform device registered + */ +static int __devexit ab8500_gpio_remove(struct platform_device *pdev) +{ + struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev); + int ret; + + ret = gpiochip_remove(&ab8500_gpio->chip); + if (ret < 0) { + dev_err(ab8500_gpio->dev, "unable to remove gpiochip:\ + %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, NULL); + mutex_destroy(&ab8500_gpio->lock); + kfree(ab8500_gpio); + + return 0; +} + +static struct platform_driver ab8500_gpio_driver = { + .driver = { + .name = "ab8500-gpio", + .owner = THIS_MODULE, + }, + .probe = ab8500_gpio_probe, + .remove = __devexit_p(ab8500_gpio_remove), +}; + +static int __init ab8500_gpio_init(void) +{ + return platform_driver_register(&ab8500_gpio_driver); +} +arch_initcall(ab8500_gpio_init); + +static void __exit ab8500_gpio_exit(void) +{ + platform_driver_unregister(&ab8500_gpio_driver); +} +module_exit(ab8500_gpio_exit); + +MODULE_AUTHOR("BIBEK BASU "); +MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins\ + to be used as GPIO"); +MODULE_ALIAS("AB8500 GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 62e33e2258d4..67d01c938284 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -362,6 +362,15 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) } } +static struct resource ab8500_gpio_resources[] = { + { + .name = "GPIO_INT6", + .start = AB8500_INT_GPIO6R, + .end = AB8500_INT_GPIO41F, + .flags = IORESOURCE_IRQ, + } +}; + static struct resource ab8500_gpadc_resources[] = { { .name = "HW_CONV_END", @@ -595,6 +604,11 @@ static struct mfd_cell ab8500_devs[] = { { .name = "ab8500-regulator", }, + { + .name = "ab8500-gpio", + .num_resources = ARRAY_SIZE(ab8500_gpio_resources), + .resources = ab8500_gpio_resources, + }, { .name = "ab8500-gpadc", .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c index 6820327adf4a..821e6b86afd2 100644 --- a/drivers/mfd/ab8500-i2c.c +++ b/drivers/mfd/ab8500-i2c.c @@ -97,7 +97,7 @@ static void __exit ab8500_i2c_exit(void) { platform_driver_unregister(&ab8500_i2c_driver); } -subsys_initcall(ab8500_i2c_init); +arch_initcall(ab8500_i2c_init); module_exit(ab8500_i2c_exit); MODULE_AUTHOR("Mattias WALLIN Date: Thu, 3 Feb 2011 16:27:55 +0000 Subject: OLPC XO-1.5 ebook switch driver The OLPC XO-1.5 has an ebook switch, triggered when the laptop screen is rotated then folding down, converting the device into ebook form. This switch is exposed through ACPI. Add a driver that exposes it to userspace as an input device. Signed-off-by: Daniel Drake Acked-by: Dmitry Torokhov Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 9 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/xo15-ebook.c | 181 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 drivers/platform/x86/xo15-ebook.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 222dfb737b11..2f6a37a1d2e6 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -672,4 +672,13 @@ config XO1_RFKILL Support for enabling/disabling the WLAN interface on the OLPC XO-1 laptop. +config XO15_EBOOK + tristate "OLPC XO-1.5 ebook switch" + depends on ACPI && INPUT + ---help--- + Support for the ebook switch on the OLPC XO-1.5 laptop. + + This switch is triggered as the screen is rotated and folded down to + convert the device into ebook form. + endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 299aefb3e74c..daa286c9d53a 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -34,4 +34,5 @@ obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o obj-$(CONFIG_INTEL_IPS) += intel_ips.o obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o +obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o obj-$(CONFIG_IBM_RTL) += ibm_rtl.o diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c new file mode 100644 index 000000000000..2343bb36e563 --- /dev/null +++ b/drivers/platform/x86/xo15-ebook.c @@ -0,0 +1,181 @@ +/* + * OLPC XO-1.5 ebook switch driver + * (based on generic ACPI button driver) + * + * Copyright (C) 2009 Paul Fox + * Copyright (C) 2010 One Laptop per Child + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MODULE_NAME "xo15-ebook" +#define PREFIX MODULE_NAME ": " + +#define XO15_EBOOK_CLASS MODULE_NAME +#define XO15_EBOOK_TYPE_UNKNOWN 0x00 +#define XO15_EBOOK_NOTIFY_STATUS 0x80 + +#define XO15_EBOOK_SUBCLASS "ebook" +#define XO15_EBOOK_HID "XO15EBK" +#define XO15_EBOOK_DEVICE_NAME "EBook Switch" + +ACPI_MODULE_NAME(MODULE_NAME); + +MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver"); +MODULE_LICENSE("GPL"); + +static const struct acpi_device_id ebook_device_ids[] = { + { XO15_EBOOK_HID, 0 }, + { "", 0 }, +}; +MODULE_DEVICE_TABLE(acpi, ebook_device_ids); + +struct ebook_switch { + struct input_dev *input; + char phys[32]; /* for input device */ +}; + +static int ebook_send_state(struct acpi_device *device) +{ + struct ebook_switch *button = acpi_driver_data(device); + unsigned long long state; + acpi_status status; + + status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state); + if (ACPI_FAILURE(status)) + return -EIO; + + /* input layer checks if event is redundant */ + input_report_switch(button->input, SW_TABLET_MODE, !state); + input_sync(button->input); + return 0; +} + +static void ebook_switch_notify(struct acpi_device *device, u32 event) +{ + switch (event) { + case ACPI_FIXED_HARDWARE_EVENT: + case XO15_EBOOK_NOTIFY_STATUS: + ebook_send_state(device); + break; + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } +} + +static int ebook_switch_resume(struct acpi_device *device) +{ + return ebook_send_state(device); +} + +static int ebook_switch_add(struct acpi_device *device) +{ + struct ebook_switch *button; + struct input_dev *input; + const char *hid = acpi_device_hid(device); + char *name, *class; + int error; + + button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL); + if (!button) + return -ENOMEM; + + device->driver_data = button; + + button->input = input = input_allocate_device(); + if (!input) { + error = -ENOMEM; + goto err_free_button; + } + + name = acpi_device_name(device); + class = acpi_device_class(device); + + if (strcmp(hid, XO15_EBOOK_HID)) { + printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); + error = -ENODEV; + goto err_free_input; + } + + strcpy(name, XO15_EBOOK_DEVICE_NAME); + sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS); + + snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); + + input->name = name; + input->phys = button->phys; + input->id.bustype = BUS_HOST; + input->dev.parent = &device->dev; + + input->evbit[0] = BIT_MASK(EV_SW); + set_bit(SW_TABLET_MODE, input->swbit); + + error = input_register_device(input); + if (error) + goto err_free_input; + + ebook_send_state(device); + + if (device->wakeup.flags.valid) { + /* Button's GPE is run-wake GPE */ + acpi_enable_gpe(device->wakeup.gpe_device, + device->wakeup.gpe_number); + device->wakeup.run_wake_count++; + device_set_wakeup_enable(&device->dev, true); + } + + return 0; + + err_free_input: + input_free_device(input); + err_free_button: + kfree(button); + return error; +} + +static int ebook_switch_remove(struct acpi_device *device, int type) +{ + struct ebook_switch *button = acpi_driver_data(device); + + input_unregister_device(button->input); + kfree(button); + return 0; +} + +static struct acpi_driver xo15_ebook_driver = { + .name = MODULE_NAME, + .class = XO15_EBOOK_CLASS, + .ids = ebook_device_ids, + .ops = { + .add = ebook_switch_add, + .resume = ebook_switch_resume, + .remove = ebook_switch_remove, + .notify = ebook_switch_notify, + }, +}; + +static int __init xo15_ebook_init(void) +{ + return acpi_bus_register_driver(&xo15_ebook_driver); +} + +static void __exit xo15_ebook_exit(void) +{ + acpi_bus_unregister_driver(&xo15_ebook_driver); +} + +module_init(xo15_ebook_init); +module_exit(xo15_ebook_exit); -- cgit v1.2.2 From 5628e5aa12d6147f4174ed7c42da146ef57fd125 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:26 +0100 Subject: eeepc-wmi: reorder keymap Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 4d38f98aa976..350b7bcfc326 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -74,18 +74,18 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); static const struct key_entry eeepc_wmi_keymap[] = { /* Sleep already handled via generic ACPI code */ - { KE_KEY, 0x5d, { KEY_WLAN } }, - { KE_KEY, 0x32, { KEY_MUTE } }, - { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, - { KE_KEY, 0x30, { KEY_VOLUMEUP } }, { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x30, { KEY_VOLUMEUP } }, + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x32, { KEY_MUTE } }, + { KE_KEY, 0x5c, { KEY_F15 } }, + { KE_KEY, 0x5d, { KEY_WLAN } }, { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ + { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0xe0, { KEY_PROG1 } }, { KE_KEY, 0xe1, { KEY_F14 } }, { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } }, - { KE_KEY, 0xe0, { KEY_PROG1 } }, - { KE_KEY, 0x5c, { KEY_F15 } }, { KE_END, 0}, }; -- cgit v1.2.2 From bc40cce201b69ab25178565e298d9482a5876306 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:27 +0100 Subject: eeepc-wmi: add wlan key found on 1015P Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 350b7bcfc326..0d8217d14780 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -82,6 +82,7 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0x5c, { KEY_F15 } }, { KE_KEY, 0x5d, { KEY_WLAN } }, { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ + { KE_KEY, 0x88, { KEY_WLAN } }, { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, { KE_KEY, 0xe1, { KEY_F14 } }, -- cgit v1.2.2 From afa7c886578ce264d9b66d4bcb1fea51fac47925 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:28 +0100 Subject: eeepc-wmi: add hotplug code for Eeepc 1000H Implement wireless like hotplug handling (code stolen from eeepc-laptop). Reminder: on some models rfkill is implemented by logically unplugging the wireless card from the PCI bus. Despite sending ACPI notifications, this does not appear to be implemented using standard ACPI hotplug - nor does the firmware provide the _OSC method required to support native PCIe hotplug. The only sensible choice appears to be to handle the hotplugging directly in the platform driver. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 274 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 273 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 0d8217d14780..01bc2b3da98a 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -37,9 +37,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include @@ -72,6 +75,14 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 +static bool hotplug_wireless; + +module_param(hotplug_wireless, bool, 0444); +MODULE_PARM_DESC(hotplug_wireless, + "Enable hotplug for wireless device. " + "If your laptop needs that, please report to " + "acpi4asus-user@lists.sourceforge.net."); + static const struct key_entry eeepc_wmi_keymap[] = { /* Sleep already handled via generic ACPI code */ { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, @@ -109,6 +120,8 @@ struct eeepc_wmi_debug { }; struct eeepc_wmi { + bool hotplug_wireless; + struct input_dev *inputdev; struct backlight_device *backlight_device; struct platform_device *platform_device; @@ -122,6 +135,9 @@ struct eeepc_wmi { struct rfkill *bluetooth_rfkill; struct rfkill *wwan3g_rfkill; + struct hotplug_slot *hotplug_slot; + struct mutex hotplug_lock; + struct eeepc_wmi_debug debug; }; @@ -177,7 +193,8 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) u32 tmp; status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, - 1, EEEPC_WMI_METHODID_DSTS, &input, &output); + 1, EEEPC_WMI_METHODID_DSTS, + &input, &output); if (ACPI_FAILURE(status)) return status; @@ -333,6 +350,206 @@ static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) destroy_workqueue(eeepc->led_workqueue); } +/* + * PCI hotplug (for wlan rfkill) + */ +static bool eeepc_wlan_rfkill_blocked(struct eeepc_wmi *eeepc) +{ + u32 retval; + acpi_status status; + + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_WLAN, &retval); + + if (ACPI_FAILURE(status)) + return false; + + return !(retval & 0x1); +} + +static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) +{ + struct pci_dev *dev; + struct pci_bus *bus; + bool blocked = eeepc_wlan_rfkill_blocked(eeepc); + bool absent; + u32 l; + + if (eeepc->wlan_rfkill) + rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); + + mutex_lock(&eeepc->hotplug_lock); + + if (eeepc->hotplug_slot) { + bus = pci_find_bus(0, 1); + if (!bus) { + pr_warning("Unable to find PCI bus 1?\n"); + goto out_unlock; + } + + if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { + pr_err("Unable to read PCI config space?\n"); + goto out_unlock; + } + absent = (l == 0xffffffff); + + if (blocked != absent) { + pr_warning("BIOS says wireless lan is %s, " + "but the pci device is %s\n", + blocked ? "blocked" : "unblocked", + absent ? "absent" : "present"); + pr_warning("skipped wireless hotplug as probably " + "inappropriate for this model\n"); + goto out_unlock; + } + + if (!blocked) { + dev = pci_get_slot(bus, 0); + if (dev) { + /* Device already present */ + pci_dev_put(dev); + goto out_unlock; + } + dev = pci_scan_single_device(bus, 0); + if (dev) { + pci_bus_assign_resources(bus); + if (pci_bus_add_device(dev)) + pr_err("Unable to hotplug wifi\n"); + } + } else { + dev = pci_get_slot(bus, 0); + if (dev) { + pci_remove_bus_device(dev); + pci_dev_put(dev); + } + } + } + +out_unlock: + mutex_unlock(&eeepc->hotplug_lock); +} + +static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) +{ + struct eeepc_wmi *eeepc = data; + + if (event != ACPI_NOTIFY_BUS_CHECK) + return; + + eeepc_rfkill_hotplug(eeepc); +} + +static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, + char *node) +{ + acpi_status status; + acpi_handle handle; + + status = acpi_get_handle(NULL, node, &handle); + + if (ACPI_SUCCESS(status)) { + status = acpi_install_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + eeepc_rfkill_notify, + eeepc); + if (ACPI_FAILURE(status)) + pr_warning("Failed to register notify on %s\n", node); + } else + return -ENODEV; + + return 0; +} + +static void eeepc_unregister_rfkill_notifier(struct eeepc_wmi *eeepc, + char *node) +{ + acpi_status status = AE_OK; + acpi_handle handle; + + status = acpi_get_handle(NULL, node, &handle); + + if (ACPI_SUCCESS(status)) { + status = acpi_remove_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + eeepc_rfkill_notify); + if (ACPI_FAILURE(status)) + pr_err("Error removing rfkill notify handler %s\n", + node); + } +} + +static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, + u8 *value) +{ + u32 retval; + acpi_status status; + + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_WLAN, &retval); + + if (ACPI_FAILURE(status)) + return -EIO; + + if (!retval || retval == 0x00060000) + return -ENODEV; + else + *value = (retval & 0x1); + + return 0; +} + +static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) +{ + kfree(hotplug_slot->info); + kfree(hotplug_slot); +} + +static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { + .owner = THIS_MODULE, + .get_adapter_status = eeepc_get_adapter_status, + .get_power_status = eeepc_get_adapter_status, +}; + +static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) +{ + int ret = -ENOMEM; + struct pci_bus *bus = pci_find_bus(0, 1); + + if (!bus) { + pr_err("Unable to find wifi PCI bus\n"); + return -ENODEV; + } + + eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!eeepc->hotplug_slot) + goto error_slot; + + eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), + GFP_KERNEL); + if (!eeepc->hotplug_slot->info) + goto error_info; + + eeepc->hotplug_slot->private = eeepc; + eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; + eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; + eeepc_get_adapter_status(eeepc->hotplug_slot, + &eeepc->hotplug_slot->info->adapter_status); + + ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); + if (ret) { + pr_err("Unable to register hotplug slot - %d\n", ret); + goto error_register; + } + + return 0; + +error_register: + kfree(eeepc->hotplug_slot->info); +error_info: + kfree(eeepc->hotplug_slot); + eeepc->hotplug_slot = NULL; +error_slot: + return ret; +} + /* * Rfkill devices */ @@ -404,11 +621,22 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) { + eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); + eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); + eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); if (eeepc->wlan_rfkill) { rfkill_unregister(eeepc->wlan_rfkill); rfkill_destroy(eeepc->wlan_rfkill); eeepc->wlan_rfkill = NULL; } + /* + * Refresh pci hotplug in case the rfkill state was changed after + * eeepc_unregister_rfkill_notifier() + */ + eeepc_rfkill_hotplug(eeepc); + if (eeepc->hotplug_slot) + pci_hp_deregister(eeepc->hotplug_slot); + if (eeepc->bluetooth_rfkill) { rfkill_unregister(eeepc->bluetooth_rfkill); rfkill_destroy(eeepc->bluetooth_rfkill); @@ -425,6 +653,8 @@ static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) { int result = 0; + mutex_init(&eeepc->hotplug_lock); + result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, "eeepc-wlan", RFKILL_TYPE_WLAN, EEEPC_WMI_DEVID_WLAN); @@ -446,6 +676,23 @@ static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) if (result && result != -ENODEV) goto exit; + result = eeepc_setup_pci_hotplug(eeepc); + /* + * If we get -EBUSY then something else is handling the PCI hotplug - + * don't fail in this case + */ + if (result == -EBUSY) + result = 0; + + eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); + eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); + eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); + /* + * Refresh pci hotplug in case the rfkill state was changed during + * setup. + */ + eeepc_rfkill_hotplug(eeepc); + exit: if (result && result != -ENODEV) eeepc_wmi_rfkill_exit(eeepc); @@ -771,6 +1018,28 @@ error_debugfs: /* * WMI Driver */ +static void eeepc_dmi_check(struct eeepc_wmi *eeepc) +{ + const char *model; + + model = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!model) + return; + + /* + * Whitelist for wlan hotplug + * + * Eeepc 1000H needs the current hotplug code to handle + * Fn+F2 correctly. We may add other Eeepc here later, but + * it seems that most of the laptops supported by eeepc-wmi + * don't need to be on this list + */ + if (strcmp(model, "1000H") == 0) { + eeepc->hotplug_wireless = true; + pr_info("wlan hotplug enabled\n"); + } +} + static struct platform_device * __init eeepc_wmi_add(void) { struct eeepc_wmi *eeepc; @@ -781,6 +1050,9 @@ static struct platform_device * __init eeepc_wmi_add(void) if (!eeepc) return ERR_PTR(-ENOMEM); + eeepc->hotplug_wireless = hotplug_wireless; + eeepc_dmi_check(eeepc); + /* * Register the platform device first. It is used as a parent for the * sub-devices below. -- cgit v1.2.2 From 279f8f95493c9aaa0a85520c863ccba87c4bf930 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:29 +0100 Subject: eeepc-wmi: serialize access to wmi method \AMW0.WMBC, which is the main method that we use, is not reentrant. When wireless hotpluging is enabled, toggling the status of the wireless device using WMBC will trigger a notification and the notification handler need to call WMBC again to get the new status of the device, this will trigger the following error: ACPI Error (dswload-0802): [_T_0] Namespace lookup failure, AE_ALREADY_EXISTS ACPI Exception: AE_ALREADY_EXISTS, During name lookup/catalog (20100428/psloop-231) ACPI Error (psparse-0537): Method parse/execution failed [\AMW0.WMBC] (Node f7023b88), AE_ALREADY_EXISTS ACPI: Marking method WMBC as Serialized because of AE_ALREADY_EXISTS error Since there is currently no way to tell the acpi subsystem to mark a method as serialized, we do it in eeepc-wmi. Of course, we could let the first call fail, and then it would work, but it doesn't seems really clean, and it will make the first WMBC call return a random value. This patch was tested on EeePc 1000H with a RaLink RT2860 wireless card using the rt2800pci driver. rt2860sta driver seems to deadlock when we remove the pci device... Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 78 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 01bc2b3da98a..eb4c0ce88ac1 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -137,6 +137,9 @@ struct eeepc_wmi { struct hotplug_slot *hotplug_slot; struct mutex hotplug_lock; + struct mutex wmi_lock; + struct workqueue_struct *hotplug_workqueue; + struct work_struct hotplug_work; struct eeepc_wmi_debug debug; }; @@ -370,15 +373,19 @@ static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) { struct pci_dev *dev; struct pci_bus *bus; - bool blocked = eeepc_wlan_rfkill_blocked(eeepc); + bool blocked; bool absent; u32 l; - if (eeepc->wlan_rfkill) - rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); + mutex_lock(&eeepc->wmi_lock); + blocked = eeepc_wlan_rfkill_blocked(eeepc); + mutex_unlock(&eeepc->wmi_lock); mutex_lock(&eeepc->hotplug_lock); + if (eeepc->wlan_rfkill) + rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); + if (eeepc->hotplug_slot) { bus = pci_find_bus(0, 1); if (!bus) { @@ -435,7 +442,14 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) if (event != ACPI_NOTIFY_BUS_CHECK) return; - eeepc_rfkill_hotplug(eeepc); + /* + * We can't call directly eeepc_rfkill_hotplug because most + * of the time WMBC is still being executed and not reetrant. + * There is currently no way to tell ACPICA that we want this + * method to be serialized, we schedule a eeepc_rfkill_hotplug + * call later, in a safer context. + */ + queue_work(eeepc->hotplug_workqueue, &eeepc->hotplug_work); } static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, @@ -508,6 +522,14 @@ static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { .get_power_status = eeepc_get_adapter_status, }; +static void eeepc_hotplug_work(struct work_struct *work) +{ + struct eeepc_wmi *eeepc; + + eeepc = container_of(work, struct eeepc_wmi, hotplug_work); + eeepc_rfkill_hotplug(eeepc); +} + static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) { int ret = -ENOMEM; @@ -518,6 +540,13 @@ static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) return -ENODEV; } + eeepc->hotplug_workqueue = + create_singlethread_workqueue("hotplug_workqueue"); + if (!eeepc->hotplug_workqueue) + goto error_workqueue; + + INIT_WORK(&eeepc->hotplug_work, eeepc_hotplug_work); + eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); if (!eeepc->hotplug_slot) goto error_slot; @@ -547,6 +576,8 @@ error_info: kfree(eeepc->hotplug_slot); eeepc->hotplug_slot = NULL; error_slot: + destroy_workqueue(eeepc->hotplug_workqueue); +error_workqueue: return ret; } @@ -575,6 +606,34 @@ static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) rfkill_set_sw_state(rfkill, !(retval & 0x1)); } +static int eeepc_rfkill_wlan_set(void *data, bool blocked) +{ + struct eeepc_wmi *eeepc = data; + int ret; + + /* + * This handler is enabled only if hotplug is enabled. + * In this case, the eeepc_wmi_set_devstate() will + * trigger a wmi notification and we need to wait + * this call to finish before being able to call + * any wmi method + */ + mutex_lock(&eeepc->wmi_lock); + ret = eeepc_rfkill_set((void *)(long)EEEPC_WMI_DEVID_WLAN, blocked); + mutex_unlock(&eeepc->wmi_lock); + return ret; +} + +static void eeepc_rfkill_wlan_query(struct rfkill *rfkill, void *data) +{ + eeepc_rfkill_query(rfkill, (void *)(long)EEEPC_WMI_DEVID_WLAN); +} + +static const struct rfkill_ops eeepc_rfkill_wlan_ops = { + .set_block = eeepc_rfkill_wlan_set, + .query = eeepc_rfkill_wlan_query, +}; + static const struct rfkill_ops eeepc_rfkill_ops = { .set_block = eeepc_rfkill_set, .query = eeepc_rfkill_query, @@ -603,8 +662,12 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, if (!retval || retval == 0x00060000) return -ENODEV; - *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, - &eeepc_rfkill_ops, (void *)(long)dev_id); + if (dev_id == EEEPC_WMI_DEVID_WLAN && eeepc->hotplug_wireless) + *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, + &eeepc_rfkill_wlan_ops, eeepc); + else + *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, + &eeepc_rfkill_ops, (void *)(long)dev_id); if (!*rfkill) return -EINVAL; @@ -636,6 +699,8 @@ static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) eeepc_rfkill_hotplug(eeepc); if (eeepc->hotplug_slot) pci_hp_deregister(eeepc->hotplug_slot); + if (eeepc->hotplug_workqueue) + destroy_workqueue(eeepc->hotplug_workqueue); if (eeepc->bluetooth_rfkill) { rfkill_unregister(eeepc->bluetooth_rfkill); @@ -654,6 +719,7 @@ static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) int result = 0; mutex_init(&eeepc->hotplug_lock); + mutex_init(&eeepc->wmi_lock); result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, "eeepc-wlan", RFKILL_TYPE_WLAN, -- cgit v1.2.2 From 7898cf1a3665d22c4d16308f73e981c6464be81b Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:30 +0100 Subject: eeepc-wmi: return proper error code in eeepc_rfkill_set() Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index eb4c0ce88ac1..d8234582b541 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -588,8 +588,14 @@ static int eeepc_rfkill_set(void *data, bool blocked) { int dev_id = (unsigned long)data; u32 ctrl_param = !blocked; + acpi_status status; + + status = eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); + + if (ACPI_FAILURE(status)) + return -EIO; - return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); + return 0; } static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) -- cgit v1.2.2 From 5c95638d115f9c6661fff254b3beb14b19f88e41 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:31 +0100 Subject: eeepc-wmi: add an helper using simple return codes eeepc_wmi_get_devstate returns an acpi_status, so each call need extra logic to handle the return code. This patch add a simple getter, returning a boolean (or a negative error code). Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 96 ++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index d8234582b541..de501fb3d1bb 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -257,6 +257,29 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, return status; } +/* Helper for special devices with magic return codes */ +static int eeepc_wmi_get_devstate_simple(u32 dev_id) +{ + u32 retval = 0; + acpi_status status; + + status = eeepc_wmi_get_devstate(dev_id, &retval); + + if (ACPI_FAILURE(status)) + return -EINVAL; + + /* If the device is present, DSTS will always set some bits + * 0x00070000 - 1110000000000000000 - device supported + * 0x00060000 - 1100000000000000000 - not supported + * 0x00020000 - 0100000000000000000 - device supported + * 0x00010000 - 0010000000000000000 - not supported / special mode ? + */ + if (!retval || retval == 0x00060000) + return -ENODEV; + + return retval & 0x1; +} + /* * LEDs */ @@ -290,23 +313,7 @@ static void tpd_led_set(struct led_classdev *led_cdev, static int read_tpd_state(struct eeepc_wmi *eeepc) { - u32 retval; - acpi_status status; - - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval); - - if (ACPI_FAILURE(status)) - return -1; - else if (!retval || retval == 0x00060000) - /* - * if touchpad led is present, DSTS will set some bits, - * usually 0x00020000. - * 0x00060000 means that the device is not supported - */ - return -ENODEV; - else - /* Status is stored in the first bit */ - return retval & 0x1; + return eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_TPDLED); } static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) @@ -358,15 +365,11 @@ static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) */ static bool eeepc_wlan_rfkill_blocked(struct eeepc_wmi *eeepc) { - u32 retval; - acpi_status status; - - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_WLAN, &retval); + int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); - if (ACPI_FAILURE(status)) + if (result < 0) return false; - - return !(retval & 0x1); + return !result; } static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) @@ -494,19 +497,12 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_wmi *eeepc, static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - u32 retval; - acpi_status status; - - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_WLAN, &retval); - - if (ACPI_FAILURE(status)) - return -EIO; + int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); - if (!retval || retval == 0x00060000) - return -ENODEV; - else - *value = (retval & 0x1); + if (result < 0) + return result; + *value = !!result; return 0; } @@ -601,15 +597,14 @@ static int eeepc_rfkill_set(void *data, bool blocked) static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) { int dev_id = (unsigned long)data; - u32 retval; - acpi_status status; + int result; - status = eeepc_wmi_get_devstate(dev_id, &retval); + result = eeepc_wmi_get_devstate_simple(dev_id); - if (ACPI_FAILURE(status)) + if (result < 0) return ; - rfkill_set_sw_state(rfkill, !(retval & 0x1)); + rfkill_set_sw_state(rfkill, !result); } static int eeepc_rfkill_wlan_set(void *data, bool blocked) @@ -650,23 +645,10 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, const char *name, enum rfkill_type type, int dev_id) { - int result; - u32 retval; - acpi_status status; - - status = eeepc_wmi_get_devstate(dev_id, &retval); + int result = eeepc_wmi_get_devstate_simple(dev_id); - if (ACPI_FAILURE(status)) - return -1; - - /* If the device is present, DSTS will always set some bits - * 0x00070000 - 1110000000000000000 - device supported - * 0x00060000 - 1100000000000000000 - not supported - * 0x00020000 - 0100000000000000000 - device supported - * 0x00010000 - 0010000000000000000 - not supported / special mode ? - */ - if (!retval || retval == 0x00060000) - return -ENODEV; + if (result < 0) + return result; if (dev_id == EEEPC_WMI_DEVID_WLAN && eeepc->hotplug_wireless) *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, @@ -678,7 +660,7 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, if (!*rfkill) return -EINVAL; - rfkill_init_sw_state(*rfkill, !(retval & 0x1)); + rfkill_init_sw_state(*rfkill, !result); result = rfkill_register(*rfkill); if (result) { rfkill_destroy(*rfkill); -- cgit v1.2.2 From 0773d7f9f1c0ad5fb86d23ad7e4ef5bfd2f48b5e Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:32 +0100 Subject: eeepc-wmi: add hibernate/resume callbacks Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index de501fb3d1bb..583ba78a7f7d 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -1183,10 +1183,59 @@ static int eeepc_wmi_remove(struct platform_device *device) return 0; } +/* + * Platform driver - hibernate/resume callbacks + */ +static int eeepc_hotk_thaw(struct device *device) +{ + struct eeepc_wmi *eeepc = dev_get_drvdata(device); + + if (eeepc->wlan_rfkill) { + bool wlan; + + /* + * Work around bios bug - acpi _PTS turns off the wireless led + * during suspend. Normally it restores it on resume, but + * we should kick it ourselves in case hibernation is aborted. + */ + wlan = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); + eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_WLAN, wlan, NULL); + } + + return 0; +} + +static int eeepc_hotk_restore(struct device *device) +{ + struct eeepc_wmi *eeepc = dev_get_drvdata(device); + int bl; + + /* Refresh both wlan rfkill state and pci hotplug */ + if (eeepc->wlan_rfkill) + eeepc_rfkill_hotplug(eeepc); + + if (eeepc->bluetooth_rfkill) { + bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BLUETOOTH); + rfkill_set_sw_state(eeepc->bluetooth_rfkill, bl); +} + if (eeepc->wwan3g_rfkill) { + bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WWAN3G); + rfkill_set_sw_state(eeepc->wwan3g_rfkill, bl); + } + + return 0; +} + +static const struct dev_pm_ops eeepc_pm_ops = { + .thaw = eeepc_hotk_thaw, + .restore = eeepc_hotk_restore, +}; + static struct platform_driver platform_driver = { .driver = { .name = EEEPC_WMI_FILE, .owner = THIS_MODULE, + .pm = &eeepc_pm_ops, }, }; -- cgit v1.2.2 From a04ce290bffe6b39edf18bac0fdb302503a53a4e Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:33 +0100 Subject: eeepc-wmi: switch to platform_create_bundle() This allow to remove ~30 lines of code. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 75 ++++++++++++---------------------------- 1 file changed, 22 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 583ba78a7f7d..1fc191bc0a3f 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -144,9 +144,6 @@ struct eeepc_wmi { struct eeepc_wmi_debug debug; }; -/* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ -static struct platform_device *platform_device; - static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) { int err; @@ -932,33 +929,12 @@ static int eeepc_wmi_sysfs_init(struct platform_device *device) */ static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) { - int err; - - eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); - if (!eeepc->platform_device) - return -ENOMEM; - platform_set_drvdata(eeepc->platform_device, eeepc); - - err = platform_device_add(eeepc->platform_device); - if (err) - goto fail_platform_device; - - err = eeepc_wmi_sysfs_init(eeepc->platform_device); - if (err) - goto fail_sysfs; - return 0; - -fail_sysfs: - platform_device_del(eeepc->platform_device); -fail_platform_device: - platform_device_put(eeepc->platform_device); - return err; + return eeepc_wmi_sysfs_init(eeepc->platform_device); } static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) { eeepc_wmi_sysfs_exit(eeepc->platform_device); - platform_device_unregister(eeepc->platform_device); } /* @@ -1094,7 +1070,7 @@ static void eeepc_dmi_check(struct eeepc_wmi *eeepc) } } -static struct platform_device * __init eeepc_wmi_add(void) +static int __init eeepc_wmi_add(struct platform_device *pdev) { struct eeepc_wmi *eeepc; acpi_status status; @@ -1102,15 +1078,14 @@ static struct platform_device * __init eeepc_wmi_add(void) eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); if (!eeepc) - return ERR_PTR(-ENOMEM); + return -ENOMEM; + + eeepc->platform_device = pdev; + platform_set_drvdata(eeepc->platform_device, eeepc); eeepc->hotplug_wireless = hotplug_wireless; eeepc_dmi_check(eeepc); - /* - * Register the platform device first. It is used as a parent for the - * sub-devices below. - */ err = eeepc_wmi_platform_init(eeepc); if (err) goto fail_platform; @@ -1147,7 +1122,7 @@ static struct platform_device * __init eeepc_wmi_add(void) if (err) goto fail_debugfs; - return eeepc->platform_device; + return 0; fail_debugfs: wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); @@ -1163,10 +1138,10 @@ fail_input: eeepc_wmi_platform_exit(eeepc); fail_platform: kfree(eeepc); - return ERR_PTR(err); + return err; } -static int eeepc_wmi_remove(struct platform_device *device) +static int __exit eeepc_wmi_remove(struct platform_device *device) { struct eeepc_wmi *eeepc; @@ -1232,6 +1207,7 @@ static const struct dev_pm_ops eeepc_pm_ops = { }; static struct platform_driver platform_driver = { + .remove = __exit_p(eeepc_wmi_remove), .driver = { .name = EEEPC_WMI_FILE, .owner = THIS_MODULE, @@ -1260,10 +1236,8 @@ static int __init eeepc_wmi_check_atkd(void) return -1; } -static int __init eeepc_wmi_init(void) +static int __init eeepc_wmi_probe(struct platform_device *pdev) { - int err; - if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { pr_warning("No known WMI GUID found\n"); @@ -1280,29 +1254,24 @@ static int __init eeepc_wmi_init(void) return -ENODEV; } - platform_device = eeepc_wmi_add(); - if (IS_ERR(platform_device)) { - err = PTR_ERR(platform_device); - goto fail_eeepc_wmi; - } + return eeepc_wmi_add(pdev); +} - err = platform_driver_register(&platform_driver); - if (err) { - pr_warning("Unable to register platform driver\n"); - goto fail_platform_driver; - } +static struct platform_device *platform_device; +static int __init eeepc_wmi_init(void) +{ + platform_device = platform_create_bundle(&platform_driver, + eeepc_wmi_probe, + NULL, 0, NULL, 0); + if (IS_ERR(platform_device)) + return PTR_ERR(platform_device); return 0; - -fail_platform_driver: - eeepc_wmi_remove(platform_device); -fail_eeepc_wmi: - return err; } static void __exit eeepc_wmi_exit(void) { - eeepc_wmi_remove(platform_device); + platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); } -- cgit v1.2.2 From 33e0e6fed04dc6067562c65e3e6d551dc0eb11fc Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:34 +0100 Subject: eeepc-wmi: reorder defines Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 1fc191bc0a3f..aa9e1d1719da 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -60,20 +60,20 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); -#define NOTIFY_BRNUP_MIN 0x11 -#define NOTIFY_BRNUP_MAX 0x1f -#define NOTIFY_BRNDOWN_MIN 0x20 -#define NOTIFY_BRNDOWN_MAX 0x2e +#define NOTIFY_BRNUP_MIN 0x11 +#define NOTIFY_BRNUP_MAX 0x1f +#define NOTIFY_BRNDOWN_MIN 0x20 +#define NOTIFY_BRNDOWN_MAX 0x2e -#define EEEPC_WMI_METHODID_DEVS 0x53564544 -#define EEEPC_WMI_METHODID_DSTS 0x53544344 -#define EEEPC_WMI_METHODID_CFVS 0x53564643 +#define EEEPC_WMI_METHODID_DSTS 0x53544344 +#define EEEPC_WMI_METHODID_DEVS 0x53564544 +#define EEEPC_WMI_METHODID_CFVS 0x53564643 -#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 -#define EEEPC_WMI_DEVID_TPDLED 0x00100011 #define EEEPC_WMI_DEVID_WLAN 0x00010011 #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 +#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 +#define EEEPC_WMI_DEVID_TPDLED 0x00100011 static bool hotplug_wireless; -- cgit v1.2.2 From aafa719dcd0cb0c05bb0690c816b13263c8b36e6 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:35 +0100 Subject: eeepc-wmi: use the presence bit correctly I checked some more DSDT, and it seems that I wasn't totally right about the meaning of DSTS return value. Bit 0 is clearly the status of the device, and I discovered that bit 16 is set when the device is present. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index aa9e1d1719da..391c32bd703e 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -75,6 +75,9 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 #define EEEPC_WMI_DEVID_TPDLED 0x00100011 +#define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 +#define EEEPC_WMI_DSTS_PRESENCE_BIT 0x00010000 + static bool hotplug_wireless; module_param(hotplug_wireless, bool, 0444); @@ -265,16 +268,10 @@ static int eeepc_wmi_get_devstate_simple(u32 dev_id) if (ACPI_FAILURE(status)) return -EINVAL; - /* If the device is present, DSTS will always set some bits - * 0x00070000 - 1110000000000000000 - device supported - * 0x00060000 - 1100000000000000000 - not supported - * 0x00020000 - 0100000000000000000 - device supported - * 0x00010000 - 0010000000000000000 - not supported / special mode ? - */ - if (!retval || retval == 0x00060000) + if (!(retval & EEEPC_WMI_DSTS_PRESENCE_BIT)) return -ENODEV; - return retval & 0x1; + return retval & EEEPC_WMI_DSTS_STATUS_BIT; } /* -- cgit v1.2.2 From 9e1565bc390123d3c74b940ba3466faf196970ec Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:36 +0100 Subject: eeepc-wmi: add camera and card reader support Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 89 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 391c32bd703e..83415dd42d0d 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -73,6 +73,8 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 +#define EEEPC_WMI_DEVID_CAMERA 0x00060013 +#define EEEPC_WMI_DEVID_CARDREADER 0x00080013 #define EEEPC_WMI_DEVID_TPDLED 0x00100011 #define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 @@ -879,6 +881,70 @@ static void eeepc_wmi_notify(u32 value, void *context) kfree(obj); } +/* + * Sys helpers + */ +static int parse_arg(const char *buf, unsigned long count, int *val) +{ + if (!count) + return 0; + if (sscanf(buf, "%i", val) != 1) + return -EINVAL; + return count; +} + +static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) +{ + acpi_status status; + u32 retval; + int rv, value; + + value = eeepc_wmi_get_devstate_simple(devid); + if (value == -ENODEV) /* Check device presence */ + return value; + + rv = parse_arg(buf, count, &value); + status = eeepc_wmi_set_devstate(devid, value, &retval); + + if (ACPI_FAILURE(status)) + return -EIO; + return rv; +} + +static ssize_t show_sys_wmi(int devid, char *buf) +{ + int value = eeepc_wmi_get_devstate_simple(devid); + + if (value < 0) + return value; + + return sprintf(buf, "%d\n", value); +} + +#define EEEPC_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ + static ssize_t show_##_name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return show_sys_wmi(_cm, buf); \ + } \ + static ssize_t store_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + return store_sys_wmi(_cm, buf, count); \ + } \ + static struct device_attribute dev_attr_##_name = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = _mode }, \ + .show = show_##_name, \ + .store = store_##_name, \ + } + +EEEPC_WMI_CREATE_DEVICE_ATTR(camera, 0644, EEEPC_WMI_DEVID_CAMERA); +EEEPC_WMI_CREATE_DEVICE_ATTR(cardr, 0644, EEEPC_WMI_DEVID_CARDREADER); + static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -904,11 +970,32 @@ static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); static struct attribute *platform_attributes[] = { &dev_attr_cpufv.attr, + &dev_attr_camera.attr, + &dev_attr_cardr.attr, NULL }; +static mode_t eeepc_sysfs_is_visible(struct kobject *kobj, + struct attribute *attr, + int idx) +{ + bool supported = true; + int devid = -1; + + if (attr == &dev_attr_camera.attr) + devid = EEEPC_WMI_DEVID_CAMERA; + else if (attr == &dev_attr_cardr.attr) + devid = EEEPC_WMI_DEVID_CARDREADER; + + if (devid != -1) + supported = eeepc_wmi_get_devstate_simple(devid) != -ENODEV; + + return supported ? attr->mode : 0; +} + static struct attribute_group platform_attribute_group = { - .attrs = platform_attributes + .is_visible = eeepc_sysfs_is_visible, + .attrs = platform_attributes }; static void eeepc_wmi_sysfs_exit(struct platform_device *device) -- cgit v1.2.2 From 2e9e159d8e18c37d60a7d5040314f579a40f4c63 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:37 +0100 Subject: eeepc-wmi: add wimax support Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 83415dd42d0d..0db700939433 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -71,6 +71,7 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_WLAN 0x00010011 #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 +#define EEEPC_WMI_DEVID_WIMAX 0x00010017 #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 #define EEEPC_WMI_DEVID_CAMERA 0x00060013 @@ -138,6 +139,7 @@ struct eeepc_wmi { struct rfkill *wlan_rfkill; struct rfkill *bluetooth_rfkill; + struct rfkill *wimax_rfkill; struct rfkill *wwan3g_rfkill; struct hotplug_slot *hotplug_slot; @@ -691,6 +693,11 @@ static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) rfkill_destroy(eeepc->bluetooth_rfkill); eeepc->bluetooth_rfkill = NULL; } + if (eeepc->wimax_rfkill) { + rfkill_unregister(eeepc->wimax_rfkill); + rfkill_destroy(eeepc->wimax_rfkill); + eeepc->wimax_rfkill = NULL; + } if (eeepc->wwan3g_rfkill) { rfkill_unregister(eeepc->wwan3g_rfkill); rfkill_destroy(eeepc->wwan3g_rfkill); @@ -719,6 +726,13 @@ static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) if (result && result != -ENODEV) goto exit; + result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill, + "eeepc-wimax", RFKILL_TYPE_WIMAX, + EEEPC_WMI_DEVID_WIMAX); + + if (result && result != -ENODEV) + goto exit; + result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, "eeepc-wwan3g", RFKILL_TYPE_WWAN, EEEPC_WMI_DEVID_WWAN3G); @@ -1276,7 +1290,11 @@ static int eeepc_hotk_restore(struct device *device) if (eeepc->bluetooth_rfkill) { bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BLUETOOTH); rfkill_set_sw_state(eeepc->bluetooth_rfkill, bl); -} + } + if (eeepc->wimax_rfkill) { + bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WIMAX); + rfkill_set_sw_state(eeepc->wimax_rfkill, bl); + } if (eeepc->wwan3g_rfkill) { bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WWAN3G); rfkill_set_sw_state(eeepc->wwan3g_rfkill, bl); -- cgit v1.2.2 From 54c799a50f58285f5f6a93d87470cba1847943a3 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:38 +0100 Subject: eeepc-wmi: set the right key code for 0xe9 This key should power off the backlight, not the display, it is also used in acpi/video.c to do the same thing. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 0db700939433..75dd692d31ee 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -103,7 +103,7 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, { KE_KEY, 0xe1, { KEY_F14 } }, - { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } }, + { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, { KE_END, 0}, }; -- cgit v1.2.2 From b71872650fe967eb0a38aa0d7dcbe9c60d160032 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:39 +0100 Subject: eeepc-wmi: support backlight power (bl_power) attribute Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 75 ++++++++++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 75dd692d31ee..910eb00fb13e 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -73,13 +73,16 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 #define EEEPC_WMI_DEVID_WIMAX 0x00010017 #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 -#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 +#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050011 +#define EEEPC_WMI_DEVID_BRIGHTNESS 0x00050012 #define EEEPC_WMI_DEVID_CAMERA 0x00060013 #define EEEPC_WMI_DEVID_CARDREADER 0x00080013 #define EEEPC_WMI_DEVID_TPDLED 0x00100011 #define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 #define EEEPC_WMI_DSTS_PRESENCE_BIT 0x00010000 +#define EEEPC_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF +#define EEEPC_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 static bool hotplug_wireless; @@ -262,7 +265,7 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, } /* Helper for special devices with magic return codes */ -static int eeepc_wmi_get_devstate_simple(u32 dev_id) +static int eeepc_wmi_get_devstate_bits(u32 dev_id, u32 mask) { u32 retval = 0; acpi_status status; @@ -275,7 +278,12 @@ static int eeepc_wmi_get_devstate_simple(u32 dev_id) if (!(retval & EEEPC_WMI_DSTS_PRESENCE_BIT)) return -ENODEV; - return retval & EEEPC_WMI_DSTS_STATUS_BIT; + return retval & mask; +} + +static int eeepc_wmi_get_devstate_simple(u32 dev_id) +{ + return eeepc_wmi_get_devstate_bits(dev_id, EEEPC_WMI_DSTS_STATUS_BIT); } /* @@ -770,34 +778,53 @@ exit: /* * Backlight */ +static int read_backlight_power(void) +{ + int ret = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BACKLIGHT); + + if (ret < 0) + return ret; + + return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; +} + static int read_brightness(struct backlight_device *bd) { u32 retval; acpi_status status; - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval); + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, &retval); if (ACPI_FAILURE(status)) - return -1; + return -EIO; else - return retval & 0xFF; + return retval & EEEPC_WMI_DSTS_BRIGHTNESS_MASK; } static int update_bl_status(struct backlight_device *bd) { - u32 ctrl_param; acpi_status status; + int power; ctrl_param = bd->props.brightness; - status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, + status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, ctrl_param, NULL); if (ACPI_FAILURE(status)) - return -1; - else - return 0; + return -EIO; + + power = read_backlight_power(); + if (power != -ENODEV && bd->props.power != power) { + ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); + status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, + ctrl_param, NULL); + + if (ACPI_FAILURE(status)) + return -EIO; + } + return 0; } static const struct backlight_ops eeepc_wmi_bl_ops = { @@ -827,9 +854,29 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) { struct backlight_device *bd; struct backlight_properties props; + int max; + int power; + + max = eeepc_wmi_get_devstate_bits(EEEPC_WMI_DEVID_BRIGHTNESS, + EEEPC_WMI_DSTS_MAX_BRIGTH_MASK); + power = read_backlight_power(); + + if (max < 0 && power < 0) { + /* Try to keep the original error */ + if (max == -ENODEV && power == -ENODEV) + return -ENODEV; + if (max != -ENODEV) + return max; + else + return power; + } + if (max == -ENODEV) + max = 0; + if (power == -ENODEV) + power = FB_BLANK_UNBLANK; memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 15; + props.max_brightness = max; bd = backlight_device_register(EEEPC_WMI_FILE, &eeepc->platform_device->dev, eeepc, &eeepc_wmi_bl_ops, &props); @@ -841,7 +888,7 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) eeepc->backlight_device = bd; bd->props.brightness = read_brightness(bd); - bd->props.power = FB_BLANK_UNBLANK; + bd->props.power = power; backlight_update_status(bd); return 0; @@ -1202,7 +1249,7 @@ static int __init eeepc_wmi_add(struct platform_device *pdev) if (!acpi_video_backlight_support()) { err = eeepc_wmi_backlight_init(eeepc); - if (err) + if (err && err != -ENODEV) goto fail_backlight; } else pr_info("Backlight controlled by ACPI video driver\n"); -- cgit v1.2.2 From c14d4b8ea799515cd44134b8eddd8f789f0b6286 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:40 +0100 Subject: eeepc-wmi: respect wireless_hotplug setting Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 910eb00fb13e..bc7133345674 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -748,6 +748,9 @@ static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) if (result && result != -ENODEV) goto exit; + if (!eeepc->hotplug_wireless) + goto exit; + result = eeepc_setup_pci_hotplug(eeepc); /* * If we get -EBUSY then something else is handling the PCI hotplug - -- cgit v1.2.2 From 8571d75d614702e3e0278c92892012dbf7c2e65b Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:41 +0100 Subject: eeepc-wmi: real touchpad led device id is 0x001000012 Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index bc7133345674..898476716246 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -77,7 +77,7 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_BRIGHTNESS 0x00050012 #define EEEPC_WMI_DEVID_CAMERA 0x00060013 #define EEEPC_WMI_DEVID_CARDREADER 0x00080013 -#define EEEPC_WMI_DEVID_TPDLED 0x00100011 +#define EEEPC_WMI_DEVID_TOUCHPAD_LED 0x00100012 #define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 #define EEEPC_WMI_DSTS_PRESENCE_BIT 0x00010000 @@ -303,7 +303,7 @@ static void tpd_led_update(struct work_struct *work) eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); ctrl_param = eeepc->tpd_led_wk; - eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL); + eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); } static void tpd_led_set(struct led_classdev *led_cdev, @@ -317,9 +317,9 @@ static void tpd_led_set(struct led_classdev *led_cdev, queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); } -static int read_tpd_state(struct eeepc_wmi *eeepc) +static int read_tpd_led_state(struct eeepc_wmi *eeepc) { - return eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_TPDLED); + return eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_TOUCHPAD_LED); } static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) @@ -328,14 +328,14 @@ static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); - return read_tpd_state(eeepc); + return read_tpd_led_state(eeepc); } static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) { int rv; - if (read_tpd_state(eeepc) < 0) + if (read_tpd_led_state(eeepc) < 0) return 0; eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); -- cgit v1.2.2 From 77ca5b0197138db1260bbbb95ce3fd015dd10437 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:30:48 +0100 Subject: eeepc-wmi: comments keymap to clarify the meaning of some keys Found while checking PDF manuals... Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 898476716246..a78a90d886da 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -99,13 +99,13 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0x30, { KEY_VOLUMEUP } }, { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, { KE_KEY, 0x32, { KEY_MUTE } }, - { KE_KEY, 0x5c, { KEY_F15 } }, + { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ { KE_KEY, 0x5d, { KEY_WLAN } }, { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ { KE_KEY, 0x88, { KEY_WLAN } }, { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, - { KE_KEY, 0xe0, { KEY_PROG1 } }, - { KE_KEY, 0xe1, { KEY_F14 } }, + { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ + { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, { KE_END, 0}, }; -- cgit v1.2.2 From af96f87703f33a4dba4b51c7b3f0d6f874aa4853 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:27:30 +0100 Subject: asus-laptop: let WLED alone on L1400B Asus took the DSDT from another model (L84F), made some change to make it work, but forgot to remove WLED method (the laptop doesn't have a wireless card). They even didn't change the model name. ref: https://bugzilla.kernel.org/show_bug.cgi?id=25712 Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 5a6f7d7575d6..2b9d7b8636e3 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -1557,6 +1558,20 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) return result; } +static void __devinit asus_dmi_check(void) +{ + const char *model; + + model = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!model) + return; + + /* On L1400B WLED control the sound card, don't mess with it ... */ + if (strncmp(model, "L1400B", 6) == 0) { + wlan_status = -1; + } +} + static bool asus_device_present; static int __devinit asus_acpi_add(struct acpi_device *device) @@ -1575,6 +1590,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device) device->driver_data = asus; asus->device = device; + asus_dmi_check(); + result = asus_acpi_init(asus); if (result) goto fail_platform; -- cgit v1.2.2 From 3b81cf9d558c57406b4ed9b0d2639113d1d428b6 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:27:31 +0100 Subject: asus-laptop: remove deprecated interfaces (lcd_switch and display_get) I should have done that one year ago, so it's more than time to do it. These two features use non-standard interfaces. There are the only features that really need multiple path to guess what's the right method name on a specific laptop. Removing them allow to remove a lot of code an significantly clean the driver. This will affect the backlight code which won't be able to know if the backlight is on or off. The platform display file will also be write only (like the one in eeepc-laptop). Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 163 +------------------------------------ 1 file changed, 3 insertions(+), 160 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 2b9d7b8636e3..62ef43ef06d2 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -158,46 +158,9 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " #define METHOD_BRIGHTNESS_SET "SPLV" #define METHOD_BRIGHTNESS_GET "GPLV" -/* Backlight */ -static acpi_handle lcd_switch_handle; -static char *lcd_switch_paths[] = { - "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ - "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ - "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ - "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ - "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ - "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ - "\\_SB.PCI0.PX40.Q10", /* S1x */ - "\\Q10"}; /* A2x, L2D, L3D, M2E */ - /* Display */ #define METHOD_SWITCH_DISPLAY "SDSP" -static acpi_handle display_get_handle; -static char *display_get_paths[] = { - /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ - "\\_SB.PCI0.P0P1.VGA.GETD", - /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ - "\\_SB.PCI0.P0P2.VGA.GETD", - /* A6V A6Q */ - "\\_SB.PCI0.P0P3.VGA.GETD", - /* A6T, A6M */ - "\\_SB.PCI0.P0PA.VGA.GETD", - /* L3C */ - "\\_SB.PCI0.PCI1.VGAC.NMAP", - /* Z96F */ - "\\_SB.PCI0.VGA.GETD", - /* A2D */ - "\\ACTD", - /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ - "\\ADVG", - /* P30 */ - "\\DNXT", - /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ - "\\INFB", - /* A3F A6F A3N A3L M6N W3N W6A */ - "\\SSTE"}; - #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ @@ -247,7 +210,6 @@ struct asus_laptop { int wireless_status; bool have_rsts; - int lcd_state; struct rfkill *gps_rfkill; @@ -560,48 +522,6 @@ error: /* * Backlight device */ -static int asus_lcd_status(struct asus_laptop *asus) -{ - return asus->lcd_state; -} - -static int asus_lcd_set(struct asus_laptop *asus, int value) -{ - int lcd = 0; - acpi_status status = 0; - - lcd = !!value; - - if (lcd == asus_lcd_status(asus)) - return 0; - - if (!lcd_switch_handle) - return -ENODEV; - - status = acpi_evaluate_object(lcd_switch_handle, - NULL, NULL, NULL); - - if (ACPI_FAILURE(status)) { - pr_warning("Error switching LCD\n"); - return -ENODEV; - } - - asus->lcd_state = lcd; - return 0; -} - -static void lcd_blank(struct asus_laptop *asus, int blank) -{ - struct backlight_device *bd = asus->backlight_device; - - asus->lcd_state = (blank == FB_BLANK_UNBLANK); - - if (bd) { - bd->props.power = blank; - backlight_update_status(bd); - } -} - static int asus_read_brightness(struct backlight_device *bd) { struct asus_laptop *asus = bl_get_data(bd); @@ -629,16 +549,9 @@ static int asus_set_brightness(struct backlight_device *bd, int value) static int update_bl_status(struct backlight_device *bd) { - struct asus_laptop *asus = bl_get_data(bd); - int rv; int value = bd->props.brightness; - rv = asus_set_brightness(bd, value); - if (rv) - return rv; - - value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; - return asus_lcd_set(asus, value); + return asus_set_brightness(bd, value); } static const struct backlight_ops asusbl_ops = { @@ -662,8 +575,7 @@ static int asus_backlight_init(struct asus_laptop *asus) struct backlight_properties props; if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || - acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) || - !lcd_switch_handle) + acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL)) return 0; memset(&props, 0, sizeof(struct backlight_properties)); @@ -972,41 +884,6 @@ static void asus_set_display(struct asus_laptop *asus, int value) return; } -static int read_display(struct asus_laptop *asus) -{ - unsigned long long value = 0; - acpi_status rv = AE_OK; - - /* - * In most of the case, we know how to set the display, but sometime - * we can't read it - */ - if (display_get_handle) { - rv = acpi_evaluate_integer(display_get_handle, NULL, - NULL, &value); - if (ACPI_FAILURE(rv)) - pr_warning("Error reading display status\n"); - } - - value &= 0x0F; /* needed for some models, shouldn't hurt others */ - - return value; -} - -/* - * Now, *this* one could be more user-friendly, but so far, no-one has - * complained. The significance of bits is the same as in store_disp() - */ -static ssize_t show_disp(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct asus_laptop *asus = dev_get_drvdata(dev); - - if (!display_get_handle) - return -ENODEV; - return sprintf(buf, "%d\n", read_display(asus)); -} - /* * Experimental support for display switching. As of now: 1 should activate * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. @@ -1248,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) struct asus_laptop *asus = acpi_driver_data(device); u16 count; - /* - * We need to tell the backlight device when the backlight power is - * switched - */ - if (event == ATKD_LCD_ON) - lcd_blank(asus, FB_BLANK_UNBLANK); - else if (event == ATKD_LCD_OFF) - lcd_blank(asus, FB_BLANK_POWERDOWN); - /* TODO Find a better way to handle events count. */ count = asus->event_count[event % 128]++; acpi_bus_generate_proc_event(asus->device, event, count); @@ -1283,7 +1151,7 @@ static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth, store_bluetooth); static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); -static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); +static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp); static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); @@ -1394,26 +1262,6 @@ static struct platform_driver platform_driver = { } }; -static int asus_handle_init(char *name, acpi_handle * handle, - char **paths, int num_paths) -{ - int i; - acpi_status status; - - for (i = 0; i < num_paths; i++) { - status = acpi_get_handle(NULL, paths[i], handle); - if (ACPI_SUCCESS(status)) - return 0; - } - - *handle = NULL; - return -ENODEV; -} - -#define ASUS_HANDLE_INIT(object) \ - asus_handle_init(#object, &object##_handle, object##_paths, \ - ARRAY_SIZE(object##_paths)) - /* * This function is used to initialize the context with right values. In this * method, we can make all the detection we want, and modify the asus_laptop @@ -1499,10 +1347,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus) if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) asus->have_rsts = true; - /* Scheduled for removal */ - ASUS_HANDLE_INIT(lcd_switch); - ASUS_HANDLE_INIT(display_get); - kfree(model); return AE_OK; @@ -1554,7 +1398,6 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus_als_level(asus, asus->light_level); } - asus->lcd_state = 1; /* LCD should be on when the module load */ return result; } -- cgit v1.2.2 From 4615bb661352acb7032796185c8c5573e47dfa1d Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:42 +0100 Subject: eeepc-wmi: add touchpad sysfs file Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index a78a90d886da..16c7f2d62515 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -77,6 +77,7 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define EEEPC_WMI_DEVID_BRIGHTNESS 0x00050012 #define EEEPC_WMI_DEVID_CAMERA 0x00060013 #define EEEPC_WMI_DEVID_CARDREADER 0x00080013 +#define EEEPC_WMI_DEVID_TOUCHPAD 0x00100011 #define EEEPC_WMI_DEVID_TOUCHPAD_LED 0x00100012 #define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 @@ -1006,6 +1007,7 @@ static ssize_t show_sys_wmi(int devid, char *buf) .store = store_##_name, \ } +EEEPC_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, EEEPC_WMI_DEVID_TOUCHPAD); EEEPC_WMI_CREATE_DEVICE_ATTR(camera, 0644, EEEPC_WMI_DEVID_CAMERA); EEEPC_WMI_CREATE_DEVICE_ATTR(cardr, 0644, EEEPC_WMI_DEVID_CARDREADER); @@ -1036,6 +1038,7 @@ static struct attribute *platform_attributes[] = { &dev_attr_cpufv.attr, &dev_attr_camera.attr, &dev_attr_cardr.attr, + &dev_attr_touchpad.attr, NULL }; @@ -1050,6 +1053,8 @@ static mode_t eeepc_sysfs_is_visible(struct kobject *kobj, devid = EEEPC_WMI_DEVID_CAMERA; else if (attr == &dev_attr_cardr.attr) devid = EEEPC_WMI_DEVID_CARDREADER; + else if (attr == &dev_attr_touchpad.attr) + devid = EEEPC_WMI_DEVID_TOUCHPAD; if (devid != -1) supported = eeepc_wmi_get_devstate_simple(devid) != -ENODEV; -- cgit v1.2.2 From 43815941efb1374c2f71eb1fb0a2814b049030eb Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:28:43 +0100 Subject: eeepc-wmi: reorder device ids Each device seems to be in a "group" (devid >> 16 & 0xFF). Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 16c7f2d62515..eea8c942653b 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -65,21 +65,32 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define NOTIFY_BRNDOWN_MIN 0x20 #define NOTIFY_BRNDOWN_MAX 0x2e +/* WMI Methods */ #define EEEPC_WMI_METHODID_DSTS 0x53544344 #define EEEPC_WMI_METHODID_DEVS 0x53564544 #define EEEPC_WMI_METHODID_CFVS 0x53564643 +/* Wireless */ #define EEEPC_WMI_DEVID_WLAN 0x00010011 #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 #define EEEPC_WMI_DEVID_WIMAX 0x00010017 #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 + +/* Backlight and Brightness */ #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050011 #define EEEPC_WMI_DEVID_BRIGHTNESS 0x00050012 + +/* Misc */ #define EEEPC_WMI_DEVID_CAMERA 0x00060013 + +/* Storage */ #define EEEPC_WMI_DEVID_CARDREADER 0x00080013 + +/* Input */ #define EEEPC_WMI_DEVID_TOUCHPAD 0x00100011 #define EEEPC_WMI_DEVID_TOUCHPAD_LED 0x00100012 +/* DSTS masks */ #define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 #define EEEPC_WMI_DSTS_PRESENCE_BIT 0x00010000 #define EEEPC_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF -- cgit v1.2.2 From e2d3d44b9a6efe4f3968252d4b680397a9640268 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sun, 6 Feb 2011 13:30:47 +0100 Subject: eeepc-wmi: add camera keys These keys are supposed to be handled by any software using the camera (like webKam or cheese...). They can also be used to actually move the camera when possible. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index eea8c942653b..d3997757e790 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -114,11 +114,18 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ { KE_KEY, 0x5d, { KEY_WLAN } }, { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ + { KE_KEY, 0x82, { KEY_CAMERA } }, + { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, { KE_KEY, 0x88, { KEY_WLAN } }, { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, + { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, + { KE_KEY, 0xec, { KEY_CAMERA_UP } }, + { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, + { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, + { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, { KE_END, 0}, }; -- cgit v1.2.2 From 8eec8a1167b5912c19fec2cdad5b968dd0f8690d Mon Sep 17 00:00:00 2001 From: Hong Liu Date: Mon, 7 Feb 2011 14:45:55 -0500 Subject: intel_mid_powerbtn: add power button driver for Medfield platform (#3) The power button is connected to MSIC on Medfield, we will get two interrupts from IOAPIC when pressing or releasing the power button. Signed-off-by: Hong Liu [Minor fixes as noted by Dmitry] Signed-off-by: Alan Cox Acked-by: Dmitry Torokhov Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 8 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_mid_powerbtn.c | 148 ++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 drivers/platform/x86/intel_mid_powerbtn.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2f6a37a1d2e6..2822d8a8cdd2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -616,6 +616,14 @@ config GPIO_INTEL_PMIC Say Y here to support GPIO via the SCU IPC interface on Intel MID platforms. +config INTEL_MID_POWER_BUTTON + tristate "power button driver for Intel MID platforms" + depends on INTEL_SCU_IPC + help + This driver handles the power button on the Intel MID platforms. + + If unsure, say N. + config RAR_REGISTER bool "Restricted Access Region Register Driver" depends on PCI && X86_MRST diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index daa286c9d53a..3e14b18403e0 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -36,3 +36,4 @@ obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o obj-$(CONFIG_IBM_RTL) += ibm_rtl.o +obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c new file mode 100644 index 000000000000..213e79ba68d5 --- /dev/null +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -0,0 +1,148 @@ +/* + * Power button driver for Medfield. + * + * Copyright (C) 2010 Intel Corp + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "msic_power_btn" + +#define MSIC_IRQ_STAT 0x02 + #define MSIC_IRQ_PB (1 << 0) +#define MSIC_PB_CONFIG 0x3e +#define MSIC_PB_STATUS 0x3f + #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ + +struct mfld_pb_priv { + struct input_dev *input; + unsigned int irq; +}; + +static irqreturn_t mfld_pb_isr(int irq, void *dev_id) +{ + struct mfld_pb_priv *priv = dev_id; + int ret; + u8 pbstat; + + ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat); + if (ret < 0) + return IRQ_HANDLED; + + input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL)); + input_sync(priv->input); + + return IRQ_HANDLED; +} + +static int __devinit mfld_pb_probe(struct platform_device *pdev) +{ + struct mfld_pb_priv *priv; + struct input_dev *input; + int irq; + int error; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL); + input = input_allocate_device(); + if (!priv || !input) { + error = -ENOMEM; + goto err_free_mem; + } + + priv->input = input; + priv->irq = irq; + + input->name = pdev->name; + input->phys = "power-button/input0"; + input->id.bustype = BUS_HOST; + input->dev.parent = &pdev->dev; + + input_set_capability(input, EV_KEY, KEY_POWER); + + error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr, + 0, DRIVER_NAME, priv); + if (error) { + dev_err(&pdev->dev, + "unable to request irq %d for mfld power button\n", + irq); + goto err_free_mem; + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, + "unable to register input dev, error %d\n", error); + goto err_free_irq; + } + + platform_set_drvdata(pdev, priv); + return 0; + +err_free_irq: + free_irq(priv->irq, priv); +err_free_mem: + input_free_device(input); + kfree(priv); + return error; +} + +static int __devexit mfld_pb_remove(struct platform_device *pdev) +{ + struct mfld_pb_priv *priv = platform_get_drvdata(pdev); + + free_irq(priv->irq, priv); + input_unregister_device(priv->input); + kfree(priv); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +static struct platform_driver mfld_pb_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = mfld_pb_probe, + .remove = __devexit_p(mfld_pb_remove), +}; + +static int __init mfld_pb_init(void) +{ + return platform_driver_register(&mfld_pb_driver); +} +module_init(mfld_pb_init); + +static void __exit mfld_pb_exit(void) +{ + platform_driver_unregister(&mfld_pb_driver); +} +module_exit(mfld_pb_exit); + +MODULE_AUTHOR("Hong Liu "); +MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.2 From 820787fceb3e62c29a36423eb30e2f9f198547f7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 17 Feb 2011 18:44:09 +0000 Subject: Enable Dell All-In-One volume up/down keys Enable volume up and down hotkeys on WMI events GUID 284A0E6B-380E-472A-921F-E52786257FB4 and GUID 02314822-307C-4F66-bf0E-48AEAEB26CC8. Also works around a firmware bug where the _WED method should return an integer containing the key code and in fact the method returns the key code in element zero of a buffer. BugLink: http://bugs.launchpad.net/bugs/701530 BugLink: http://bugs.launchpad.net/bugs/676997 Signed-off-by: Colin Ian King Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 13 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/dell-wmi-aio.c | 171 ++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/platform/x86/dell-wmi-aio.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2822d8a8cdd2..f0ef757d9fde 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -101,6 +101,19 @@ config DELL_WMI To compile this driver as a module, choose M here: the module will be called dell-wmi. +config DELL_WMI_AIO + tristate "WMI Hotkeys for Dell All-In-One series" + depends on ACPI_WMI + depends on INPUT + select INPUT_SPARSEKMAP + ---help--- + Say Y here if you want to support WMI-based hotkeys on Dell + All-In-One machines. + + To compile this driver as a module, choose M here: the module will + be called dell-wmi. + + config FUJITSU_LAPTOP tristate "Fujitsu Laptop Extras" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 3e14b18403e0..46f3fd2c8856 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o +obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ACERHDF) += acerhdf.o obj-$(CONFIG_HP_ACCEL) += hp_accel.o diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c new file mode 100644 index 000000000000..0ed84573ae1f --- /dev/null +++ b/drivers/platform/x86/dell-wmi-aio.c @@ -0,0 +1,171 @@ +/* + * WMI hotkeys support for Dell All-In-One series + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series"); +MODULE_LICENSE("GPL"); + +#define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4" +#define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8" + +static const char *dell_wmi_aio_guids[] = { + EVENT_GUID1, + EVENT_GUID2, + NULL +}; + +MODULE_ALIAS("wmi:"EVENT_GUID1); +MODULE_ALIAS("wmi:"EVENT_GUID2); + +static const struct key_entry dell_wmi_aio_keymap[] = { + { KE_KEY, 0xc0, { KEY_VOLUMEUP } }, + { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } }, + { KE_END, 0 } +}; + +static struct input_dev *dell_wmi_aio_input_dev; + +static void dell_wmi_aio_notify(u32 value, void *context) +{ + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + + status = wmi_get_event_data(value, &response); + if (status != AE_OK) { + pr_info("bad event status 0x%x\n", status); + return; + } + + obj = (union acpi_object *)response.pointer; + if (obj) { + unsigned int scancode; + + switch (obj->type) { + case ACPI_TYPE_INTEGER: + /* Most All-In-One correctly return integer scancode */ + scancode = obj->integer.value; + sparse_keymap_report_event(dell_wmi_aio_input_dev, + scancode, 1, true); + break; + case ACPI_TYPE_BUFFER: + /* Broken machines return the scancode in a buffer */ + if (obj->buffer.pointer && obj->buffer.length > 0) { + scancode = obj->buffer.pointer[0]; + sparse_keymap_report_event( + dell_wmi_aio_input_dev, + scancode, 1, true); + } + break; + } + } + kfree(obj); +} + +static int __init dell_wmi_aio_input_setup(void) +{ + int err; + + dell_wmi_aio_input_dev = input_allocate_device(); + + if (!dell_wmi_aio_input_dev) + return -ENOMEM; + + dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys"; + dell_wmi_aio_input_dev->phys = "wmi/input0"; + dell_wmi_aio_input_dev->id.bustype = BUS_HOST; + + err = sparse_keymap_setup(dell_wmi_aio_input_dev, + dell_wmi_aio_keymap, NULL); + if (err) { + pr_err("Unable to setup input device keymap\n"); + goto err_free_dev; + } + err = input_register_device(dell_wmi_aio_input_dev); + if (err) { + pr_info("Unable to register input device\n"); + goto err_free_keymap; + } + return 0; + +err_free_keymap: + sparse_keymap_free(dell_wmi_aio_input_dev); +err_free_dev: + input_free_device(dell_wmi_aio_input_dev); + return err; +} + +static const char *dell_wmi_aio_find(void) +{ + int i; + + for (i = 0; dell_wmi_aio_guids[i] != NULL; i++) + if (wmi_has_guid(dell_wmi_aio_guids[i])) + return dell_wmi_aio_guids[i]; + + return NULL; +} + +static int __init dell_wmi_aio_init(void) +{ + int err; + const char *guid; + + guid = dell_wmi_aio_find(); + if (!guid) { + pr_warning("No known WMI GUID found\n"); + return -ENXIO; + } + + err = dell_wmi_aio_input_setup(); + if (err) + return err; + + err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL); + if (err) { + pr_err("Unable to register notify handler - %d\n", err); + sparse_keymap_free(dell_wmi_aio_input_dev); + input_unregister_device(dell_wmi_aio_input_dev); + return err; + } + + return 0; +} + +static void __exit dell_wmi_aio_exit(void) +{ + const char *guid; + + guid = dell_wmi_aio_find(); + wmi_remove_notify_handler(guid); + sparse_keymap_free(dell_wmi_aio_input_dev); + input_unregister_device(dell_wmi_aio_input_dev); +} + +module_init(dell_wmi_aio_init); +module_exit(dell_wmi_aio_exit); -- cgit v1.2.2 From 80887757e304d1f973330d9398024cffcd82d00d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 16 Feb 2011 14:31:02 -0800 Subject: platform/x86: intel_mid_powerbutton needs INPUT intel_mid_powerbtn.c uses input interfaces, so it should depend on INPUT to fix build errors when CONFIG_INPUT is not enabled: intel_mid_powerbtn.c:(.text+0x56ca8f): undefined reference to `input_event' intel_mid_powerbtn.c:(.devinit.text+0x2e7b4): undefined reference to `input_allocate_device' intel_mid_powerbtn.c:(.devinit.text+0x2e7ff): undefined reference to `input_set_capability' intel_mid_powerbtn.c:(.devinit.text+0x2e84a): undefined reference to `input_register_device' intel_mid_powerbtn.c:(.devinit.text+0x2e88b): undefined reference to `input_free_device' intel_mid_powerbtn.c:(.devexit.text+0x42f0): undefined reference to `input_unregister_device' Signed-off-by: Randy Dunlap Cc: Hong Liu Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f0ef757d9fde..53f818d23edb 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -631,7 +631,7 @@ config GPIO_INTEL_PMIC config INTEL_MID_POWER_BUTTON tristate "power button driver for Intel MID platforms" - depends on INTEL_SCU_IPC + depends on INTEL_SCU_IPC && INPUT help This driver handles the power button on the Intel MID platforms. -- cgit v1.2.2 From 56e6e716b5211f4cda8db63b9a16d083ee193480 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 19 Feb 2011 11:52:25 +0900 Subject: sony-laptop: add some debug printk useful for bug reports Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 13d8d63bcca9..5cd39af376d9 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -733,22 +733,30 @@ static int sony_find_snc_handle(int handle) for (i = 0x20; i < 0x30; i++) { acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); - if (result == handle) + if (result == handle) { + dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", + handle, i - 0x20); return i-0x20; + } } + dprintk("handle 0x%.4x not found\n", handle); return -1; } static int sony_call_snc_handle(int handle, int argument, int *result) { + int ret = 0; int offset = sony_find_snc_handle(handle); if (offset < 0) return -1; - return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, - result); + ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, + result); + dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, + *result); + return ret; } /* -- cgit v1.2.2 From 4eeb50220a4efd8c33598a228d03aff203a7ad07 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 19 Feb 2011 11:52:27 +0900 Subject: sony-laptop: ignore hard switch rfkill events (SPIC) There is not much use for these events in userspace and handling the events themselves seems to get in the way of the actual activation of the rf devices. The SNC device doesn't expose them already. https://bugzilla.kernel.org/show_bug.cgi?id=15303 Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 5cd39af376d9..5fa93cb6f337 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1592,8 +1592,8 @@ static struct sonypi_event sonypi_blueev[] = { /* The set of possible wireless events */ static struct sonypi_event sonypi_wlessev[] = { - { 0x59, SONYPI_EVENT_WIRELESS_ON }, - { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, + { 0x59, SONYPI_EVENT_IGNORE }, + { 0x5a, SONYPI_EVENT_IGNORE }, { 0, 0 } }; @@ -2733,6 +2733,9 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) if (ev == dev->event_types[i].events[j].data) { device_event = dev->event_types[i].events[j].event; + /* some events may require ignoring */ + if (!device_event) + return IRQ_HANDLED; goto found; } } @@ -2752,7 +2755,6 @@ found: sony_laptop_report_input_event(device_event); acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); sonypi_compat_report_event(device_event); - return IRQ_HANDLED; } -- cgit v1.2.2 From d669793802be5ac105d8ecbab00404ae886d3ebe Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 19 Feb 2011 11:52:28 +0900 Subject: sony-laptop: use pr_ for messages Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 100 +++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 5fa93cb6f337..89d66c70d828 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -71,8 +71,9 @@ #endif #define DRV_PFX "sony-laptop: " -#define dprintk(msg...) do { \ - if (debug) printk(KERN_WARNING DRV_PFX msg); \ +#define dprintk(msg...) do { \ + if (debug) \ + pr_warn(DRV_PFX msg); \ } while (0) #define SONY_LAPTOP_DRIVER_VERSION "0.6" @@ -402,7 +403,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device) error = kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); if (error) { - printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); + pr_err(DRV_PFX "kfifo_alloc failed\n"); goto err_dec_users; } @@ -686,7 +687,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) return 0; } - printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); + pr_warn(DRV_PFX "acpi_callreadfunc failed\n"); return -1; } @@ -712,7 +713,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, if (status == AE_OK) { if (result != NULL) { if (out_obj.type != ACPI_TYPE_INTEGER) { - printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " + pr_warn(DRV_PFX "acpi_evaluate_object bad " "return type\n"); return -1; } @@ -721,7 +722,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, return 0; } - printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); + pr_warn(DRV_PFX "acpi_evaluate_object failed\n"); return -1; } @@ -980,7 +981,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event) } if (!key_event->data) - printk(KERN_INFO DRV_PFX + pr_info(DRV_PFX "Unknown event: 0x%x 0x%x\n", key_handle, ev); @@ -1004,7 +1005,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level, struct acpi_device_info *info; if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { - printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", + pr_warn(DRV_PFX "method: name: %4.4s, args %X\n", (char *)&info->name, info->param_count); kfree(info); @@ -1045,7 +1046,7 @@ static int sony_nc_resume(struct acpi_device *device) ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, item->value, NULL); if (ret < 0) { - printk("%s: %d\n", __func__, ret); + pr_err(DRV_PFX "%s: %d\n", __func__, ret); break; } } @@ -1065,7 +1066,7 @@ static int sony_nc_resume(struct acpi_device *device) /* set the last requested brightness level */ if (sony_backlight_device && sony_backlight_update_status(sony_backlight_device) < 0) - printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n"); + pr_warn(DRV_PFX "unable to restore brightness level\n"); /* re-read rfkill state */ sony_nc_rfkill_update(); @@ -1213,13 +1214,9 @@ static void sony_nc_rfkill_setup(struct acpi_device *device) } device_enum = (union acpi_object *) buffer.pointer; - if (!device_enum) { - pr_err("Invalid SN06 return object\n"); - goto out_no_enum; - } - if (device_enum->type != ACPI_TYPE_BUFFER) { - pr_err("Invalid SN06 return object type 0x%.2x\n", - device_enum->type); + if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) { + pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n", + device_enum->type); goto out_no_enum; } @@ -1260,8 +1257,8 @@ static int sony_nc_add(struct acpi_device *device) acpi_handle handle; struct sony_nc_value *item; - printk(KERN_INFO DRV_PFX "%s v%s.\n", - SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); + pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME, + SONY_LAPTOP_DRIVER_VERSION); sony_nc_acpi_device = device; strcpy(acpi_device_class(device), "sony/hotkey"); @@ -1278,10 +1275,11 @@ static int sony_nc_add(struct acpi_device *device) } if (debug) { - status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, - 1, sony_walk_callback, NULL, NULL, NULL); + status = acpi_walk_namespace(ACPI_TYPE_METHOD, + sony_nc_acpi_handle, 1, sony_walk_callback, + NULL, NULL, NULL); if (ACPI_FAILURE(status)) { - printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); + pr_warn(DRV_PFX "unable to walk acpi resources\n"); result = -ENODEV; goto outwalk; } @@ -1303,13 +1301,12 @@ static int sony_nc_add(struct acpi_device *device) /* setup input devices and helper fifo */ result = sony_laptop_setup_input(device); if (result) { - printk(KERN_ERR DRV_PFX - "Unable to create input devices.\n"); + pr_err(DRV_PFX "Unable to create input devices.\n"); goto outwalk; } if (acpi_video_backlight_support()) { - printk(KERN_INFO DRV_PFX "brightness ignored, must be " + pr_info(DRV_PFX "brightness ignored, must be " "controlled by ACPI video driver\n"); } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) { @@ -1323,7 +1320,7 @@ static int sony_nc_add(struct acpi_device *device) &props); if (IS_ERR(sony_backlight_device)) { - printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); + pr_warning(DRV_PFX "unable to register backlight device\n"); sony_backlight_device = NULL; } else { sony_backlight_device->props.brightness = @@ -1850,7 +1847,7 @@ out: if (pcidev) pci_dev_put(pcidev); - printk(KERN_INFO DRV_PFX "detected Type%d model\n", + pr_info(DRV_PFX "detected Type%d model\n", dev->model == SONYPI_DEVICE_TYPE1 ? 1 : dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); } @@ -1898,7 +1895,7 @@ static int __sony_pic_camera_ready(void) static int __sony_pic_camera_off(void) { if (!camera) { - printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); + pr_warn(DRV_PFX "camera control not enabled\n"); return -ENODEV; } @@ -1918,7 +1915,7 @@ static int __sony_pic_camera_on(void) int i, j, x; if (!camera) { - printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); + pr_warn(DRV_PFX "camera control not enabled\n"); return -ENODEV; } @@ -1941,7 +1938,7 @@ static int __sony_pic_camera_on(void) } if (j == 0) { - printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); + pr_warn(DRV_PFX "failed to power on camera\n"); return -ENODEV; } @@ -1997,7 +1994,7 @@ int sony_pic_camera_command(int command, u8 value) ITERATIONS_SHORT); break; default: - printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", + pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n", command); break; } @@ -2404,7 +2401,7 @@ static int sonypi_compat_init(void) error = kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); if (error) { - printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); + pr_err(DRV_PFX "kfifo_alloc failed\n"); return error; } @@ -2414,11 +2411,11 @@ static int sonypi_compat_init(void) sonypi_misc_device.minor = minor; error = misc_register(&sonypi_misc_device); if (error) { - printk(KERN_ERR DRV_PFX "misc_register failed\n"); + pr_err(DRV_PFX "misc_register failed\n"); goto err_free_kfifo; } if (minor == -1) - printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", + pr_info(DRV_PFX "device allocated minor is %d\n", sonypi_misc_device.minor); return 0; @@ -2478,8 +2475,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) } for (i = 0; i < p->interrupt_count; i++) { if (!p->interrupts[i]) { - printk(KERN_WARNING DRV_PFX - "Invalid IRQ %d\n", + pr_warn(DRV_PFX "Invalid IRQ %d\n", p->interrupts[i]); continue; } @@ -2518,7 +2514,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) ioport->io2.address_length); } else { - printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); + pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); return AE_ERROR; } return AE_OK; @@ -2546,7 +2542,7 @@ static int sony_pic_possible_resources(struct acpi_device *device) dprintk("Evaluating _STA\n"); result = acpi_bus_get_status(device); if (result) { - printk(KERN_WARNING DRV_PFX "Unable to read status\n"); + pr_warn(DRV_PFX "Unable to read status\n"); goto end; } @@ -2562,8 +2558,7 @@ static int sony_pic_possible_resources(struct acpi_device *device) status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, sony_pic_read_possible_resource, &spic_dev); if (ACPI_FAILURE(status)) { - printk(KERN_WARNING DRV_PFX - "Failure evaluating %s\n", + pr_warn(DRV_PFX "Failure evaluating %s\n", METHOD_NAME__PRS); result = -ENODEV; } @@ -2677,7 +2672,7 @@ static int sony_pic_enable(struct acpi_device *device, /* check for total failure */ if (ACPI_FAILURE(status)) { - printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); + pr_err(DRV_PFX "Error evaluating _SRS\n"); result = -ENODEV; goto end; } @@ -2769,7 +2764,7 @@ static int sony_pic_remove(struct acpi_device *device, int type) struct sony_pic_irq *irq, *tmp_irq; if (sony_pic_disable(device)) { - printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); + pr_err(DRV_PFX "Couldn't disable device.\n"); return -ENXIO; } @@ -2809,8 +2804,8 @@ static int sony_pic_add(struct acpi_device *device) struct sony_pic_ioport *io, *tmp_io; struct sony_pic_irq *irq, *tmp_irq; - printk(KERN_INFO DRV_PFX "%s v%s.\n", - SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); + pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME, + SONY_LAPTOP_DRIVER_VERSION); spic_dev.acpi_dev = device; strcpy(acpi_device_class(device), "sony/hotkey"); @@ -2820,16 +2815,14 @@ static int sony_pic_add(struct acpi_device *device) /* read _PRS resources */ result = sony_pic_possible_resources(device); if (result) { - printk(KERN_ERR DRV_PFX - "Unable to read possible resources.\n"); + pr_err(DRV_PFX "Unable to read possible resources.\n"); goto err_free_resources; } /* setup input devices and helper fifo */ result = sony_laptop_setup_input(device); if (result) { - printk(KERN_ERR DRV_PFX - "Unable to create input devices.\n"); + pr_err(DRV_PFX "Unable to create input devices.\n"); goto err_free_resources; } @@ -2870,7 +2863,7 @@ static int sony_pic_add(struct acpi_device *device) } } if (!spic_dev.cur_ioport) { - printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); + pr_err(DRV_PFX "Failed to request_region.\n"); result = -ENODEV; goto err_remove_compat; } @@ -2890,7 +2883,7 @@ static int sony_pic_add(struct acpi_device *device) } } if (!spic_dev.cur_irq) { - printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); + pr_err(DRV_PFX "Failed to request_irq.\n"); result = -ENODEV; goto err_release_region; } @@ -2898,7 +2891,7 @@ static int sony_pic_add(struct acpi_device *device) /* set resource status _SRS */ result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); if (result) { - printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); + pr_err(DRV_PFX "Couldn't enable device.\n"); goto err_free_irq; } @@ -3007,8 +3000,7 @@ static int __init sony_laptop_init(void) if (!no_spic && dmi_check_system(sonypi_dmi_table)) { result = acpi_bus_register_driver(&sony_pic_driver); if (result) { - printk(KERN_ERR DRV_PFX - "Unable to register SPIC driver."); + pr_err(DRV_PFX "Unable to register SPIC driver."); goto out; } spic_drv_registered = 1; @@ -3016,7 +3008,7 @@ static int __init sony_laptop_init(void) result = acpi_bus_register_driver(&sony_nc_driver); if (result) { - printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); + pr_err(DRV_PFX "Unable to register SNC driver."); goto out_unregister_pic; } -- cgit v1.2.2 From 3672329c3642033286984313d05f4a5b57bd2da7 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 19 Feb 2011 11:52:29 +0900 Subject: sony-laptop: remove unused Type4 define Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 89d66c70d828..6db1661a5625 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1443,7 +1443,6 @@ static struct acpi_driver sony_nc_driver = { #define SONYPI_DEVICE_TYPE1 0x00000001 #define SONYPI_DEVICE_TYPE2 0x00000002 #define SONYPI_DEVICE_TYPE3 0x00000004 -#define SONYPI_DEVICE_TYPE4 0x00000008 #define SONYPI_TYPE1_OFFSET 0x04 #define SONYPI_TYPE2_OFFSET 0x12 -- cgit v1.2.2 From 2a4f0c81adcd1f812a63bc9106be2fd26f437730 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 19 Feb 2011 11:52:30 +0900 Subject: sony-laptop: cache handles and report them via sysfs Avoid calling into acpi each time we need to lookup a method handle and report the available handles to ease collection of information when debugging issues. Also move initialization of the platform driver earlier to allow adding files from other setup functions. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 97 +++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 6db1661a5625..516dd22bbb26 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -727,20 +727,79 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, return -1; } -static int sony_find_snc_handle(int handle) +struct sony_nc_handles { + u16 cap[0x10]; + struct device_attribute devattr; +}; + +struct sony_nc_handles *handles; + +static ssize_t sony_nc_handles_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + ssize_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { + len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ", + handles->cap[i]); + } + len += snprintf(buffer + len, PAGE_SIZE - len, "\n"); + + return len; +} + +static int sony_nc_handles_setup(struct platform_device *pd) { int i; int result; - for (i = 0x20; i < 0x30; i++) { - acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); - if (result == handle) { - dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", - handle, i - 0x20); - return i-0x20; + handles = kzalloc(sizeof(*handles), GFP_KERNEL); + + sysfs_attr_init(&handles->devattr.attr); + handles->devattr.attr.name = "handles"; + handles->devattr.attr.mode = S_IRUGO; + handles->devattr.show = sony_nc_handles_show; + + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { + if (!acpi_callsetfunc(sony_nc_acpi_handle, + "SN00", i + 0x20, &result)) { + dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", + result, i); + handles->cap[i] = result; } } + /* allow reading capabilities via sysfs */ + if (device_create_file(&pd->dev, &handles->devattr)) { + kfree(handles); + handles = NULL; + return -1; + } + + return 0; +} + +static int sony_nc_handles_cleanup(struct platform_device *pd) +{ + if (handles) { + device_remove_file(&pd->dev, &handles->devattr); + kfree(handles); + handles = NULL; + } + return 0; +} + +static int sony_find_snc_handle(int handle) +{ + int i; + for (i = 0; i < 0x10; i++) { + if (handles->cap[i] == handle) { + dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", + handle, i); + return i; + } + } dprintk("handle 0x%.4x not found\n", handle); return -1; } @@ -1274,6 +1333,10 @@ static int sony_nc_add(struct acpi_device *device) goto outwalk; } + result = sony_pf_add(); + if (result) + goto outpresent; + if (debug) { status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, 1, sony_walk_callback, @@ -1281,7 +1344,7 @@ static int sony_nc_add(struct acpi_device *device) if (ACPI_FAILURE(status)) { pr_warn(DRV_PFX "unable to walk acpi resources\n"); result = -ENODEV; - goto outwalk; + goto outpresent; } } @@ -1294,6 +1357,8 @@ static int sony_nc_add(struct acpi_device *device) if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", &handle))) { dprintk("Doing SNC setup\n"); + if (sony_nc_handles_setup(sony_pf_device)) + goto outpresent; sony_nc_function_setup(device); sony_nc_rfkill_setup(device); } @@ -1302,7 +1367,7 @@ static int sony_nc_add(struct acpi_device *device) result = sony_laptop_setup_input(device); if (result) { pr_err(DRV_PFX "Unable to create input devices.\n"); - goto outwalk; + goto outsnc; } if (acpi_video_backlight_support()) { @@ -1330,10 +1395,6 @@ static int sony_nc_add(struct acpi_device *device) } - result = sony_pf_add(); - if (result) - goto outbacklight; - /* create sony_pf sysfs attributes related to the SNC device */ for (item = sony_nc_values; item->name; ++item) { @@ -1379,14 +1440,17 @@ static int sony_nc_add(struct acpi_device *device) for (item = sony_nc_values; item->name; ++item) { device_remove_file(&sony_pf_device->dev, &item->devattr); } - sony_pf_remove(); - - outbacklight: if (sony_backlight_device) backlight_device_unregister(sony_backlight_device); sony_laptop_remove_input(); + outsnc: + sony_nc_handles_cleanup(sony_pf_device); + + outpresent: + sony_pf_remove(); + outwalk: sony_nc_rfkill_cleanup(); return result; @@ -1405,6 +1469,7 @@ static int sony_nc_remove(struct acpi_device *device, int type) device_remove_file(&sony_pf_device->dev, &item->devattr); } + sony_nc_handles_cleanup(sony_pf_device); sony_pf_remove(); sony_laptop_remove_input(); sony_nc_rfkill_cleanup(); -- cgit v1.2.2 From bf155714013e59c299e378055d60a4adf92e79db Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 19 Feb 2011 11:52:31 +0900 Subject: sony-laptop: implement keyboard backlight support Recent Vaios have the opportunity to control the keyboard backlight via ACPI calls to the SNC device. Introduce two module parameters to control how keyboard backlight should be set at module loading (default to on and with 10 seconds timeout). Tested-by: Marco Chiappero Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 176 ++++++++++++++++++++++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 516dd22bbb26..326a4600fad1 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -125,6 +125,19 @@ MODULE_PARM_DESC(minor, "default is -1 (automatic)"); #endif +static int kbd_backlight; /* = 1 */ +module_param(kbd_backlight, int, 0444); +MODULE_PARM_DESC(kbd_backlight, + "set this to 0 to disable keyboard backlight, " + "1 to enable it (default: 0)"); + +static int kbd_backlight_timeout; /* = 0 */ +module_param(kbd_backlight_timeout, int, 0444); +MODULE_PARM_DESC(kbd_backlight_timeout, + "set this to 0 to set the default 10 seconds timeout, " + "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " + "(default: 0)"); + enum sony_nc_rfkill { SONY_WIFI, SONY_BLUETOOTH, @@ -1309,6 +1322,161 @@ out_no_enum: return; } +/* Keyboard backlight feature */ +#define KBDBL_HANDLER 0x137 +#define KBDBL_PRESENT 0xB00 +#define SET_MODE 0xC00 +#define SET_TIMEOUT 0xE00 + +struct kbd_backlight { + int mode; + int timeout; + struct device_attribute mode_attr; + struct device_attribute timeout_attr; +}; + +struct kbd_backlight *kbdbl_handle; + +static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) +{ + int result; + + if (value > 1) + return -EINVAL; + + if (sony_call_snc_handle(KBDBL_HANDLER, + (value << 0x10) | SET_MODE, &result)) + return -EIO; + + kbdbl_handle->mode = value; + + return 0; +} + +static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + int ret = 0; + unsigned long value; + + if (count > 31) + return -EINVAL; + + if (strict_strtoul(buffer, 10, &value)) + return -EINVAL; + + ret = __sony_nc_kbd_backlight_mode_set(value); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + ssize_t count = 0; + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); + return count; +} + +static int __sony_nc_kbd_backlight_timeout_set(u8 value) +{ + int result; + + if (value > 3) + return -EINVAL; + + if (sony_call_snc_handle(KBDBL_HANDLER, + (value << 0x10) | SET_TIMEOUT, &result)) + return -EIO; + + kbdbl_handle->timeout = value; + + return 0; +} + +static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + int ret = 0; + unsigned long value; + + if (count > 31) + return -EINVAL; + + if (strict_strtoul(buffer, 10, &value)) + return -EINVAL; + + ret = __sony_nc_kbd_backlight_timeout_set(value); + if (ret < 0) + return ret; + + return count; +} + +static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + ssize_t count = 0; + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); + return count; +} + +static int sony_nc_kbd_backlight_setup(struct platform_device *pd) +{ + int result; + + if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) + return 0; + if (!(result & 0x02)) + return 0; + + kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); + + sysfs_attr_init(&kbdbl_handle->mode_attr.attr); + kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; + kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; + kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; + kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; + + sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); + kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; + kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; + kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; + kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; + + if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) + goto outkzalloc; + + if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) + goto outmode; + + __sony_nc_kbd_backlight_mode_set(kbd_backlight); + __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout); + + return 0; + +outmode: + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); +outkzalloc: + kfree(kbdbl_handle); + kbdbl_handle = NULL; + return -1; +} + +static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) +{ + if (kbdbl_handle) { + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); + device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); + kfree(kbdbl_handle); + } + return 0; +} + static int sony_nc_add(struct acpi_device *device) { acpi_status status; @@ -1359,6 +1527,8 @@ static int sony_nc_add(struct acpi_device *device) dprintk("Doing SNC setup\n"); if (sony_nc_handles_setup(sony_pf_device)) goto outpresent; + if (sony_nc_kbd_backlight_setup(sony_pf_device)) + goto outsnc; sony_nc_function_setup(device); sony_nc_rfkill_setup(device); } @@ -1367,7 +1537,7 @@ static int sony_nc_add(struct acpi_device *device) result = sony_laptop_setup_input(device); if (result) { pr_err(DRV_PFX "Unable to create input devices.\n"); - goto outsnc; + goto outkbdbacklight; } if (acpi_video_backlight_support()) { @@ -1445,6 +1615,9 @@ static int sony_nc_add(struct acpi_device *device) sony_laptop_remove_input(); + outkbdbacklight: + sony_nc_kbd_backlight_cleanup(sony_pf_device); + outsnc: sony_nc_handles_cleanup(sony_pf_device); @@ -1469,6 +1642,7 @@ static int sony_nc_remove(struct acpi_device *device, int type) device_remove_file(&sony_pf_device->dev, &item->devattr); } + sony_nc_kbd_backlight_cleanup(sony_pf_device); sony_nc_handles_cleanup(sony_pf_device); sony_pf_remove(); sony_laptop_remove_input(); -- cgit v1.2.2 From 7751ab8e600f26e10c2ba12a92d48a4852a51da8 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 19 Feb 2011 11:52:32 +0900 Subject: sony-laptop: implement new backlight control method Reasonably recent Vaios have a 0x12f or 0x137 handler that exposes a fine lid backlight regulation with values ranging from 0 to 255. The patch is based on findings and code from Javier Achirica and Marco Chiappero Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 109 +++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 326a4600fad1..d28a4a58a497 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -938,11 +938,39 @@ static int sony_backlight_get_brightness(struct backlight_device *bd) return value - 1; } -static struct backlight_device *sony_backlight_device; +static int sony_nc_get_brightness_ng(struct backlight_device *bd) +{ + int result; + int *handle = (int *)bl_get_data(bd); + + sony_call_snc_handle(*handle, 0x0200, &result); + + return result & 0xff; +} + +static int sony_nc_update_status_ng(struct backlight_device *bd) +{ + int value, result; + int *handle = (int *)bl_get_data(bd); + + value = bd->props.brightness; + sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result); + + return sony_nc_get_brightness_ng(bd); +} + static const struct backlight_ops sony_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, .update_status = sony_backlight_update_status, .get_brightness = sony_backlight_get_brightness, }; +static const struct backlight_ops sony_backlight_ng_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = sony_nc_update_status_ng, + .get_brightness = sony_nc_get_brightness_ng, +}; +static int backlight_ng_handle; +static struct backlight_device *sony_backlight_device; /* * New SNC-only Vaios event mapping to driver known keys @@ -1135,11 +1163,6 @@ static int sony_nc_resume(struct acpi_device *device) sony_nc_function_setup(device); } - /* set the last requested brightness level */ - if (sony_backlight_device && - sony_backlight_update_status(sony_backlight_device) < 0) - pr_warn(DRV_PFX "unable to restore brightness level\n"); - /* re-read rfkill state */ sony_nc_rfkill_update(); @@ -1477,6 +1500,52 @@ static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) return 0; } +static void sony_nc_backlight_setup(void) +{ + acpi_handle unused; + int max_brightness = 0; + const struct backlight_ops *ops = NULL; + struct backlight_properties props; + + if (sony_find_snc_handle(0x12f) != -1) { + backlight_ng_handle = 0x12f; + ops = &sony_backlight_ng_ops; + max_brightness = 0xff; + + } else if (sony_find_snc_handle(0x137) != -1) { + backlight_ng_handle = 0x137; + ops = &sony_backlight_ng_ops; + max_brightness = 0xff; + + } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", + &unused))) { + ops = &sony_backlight_ops; + max_brightness = SONY_MAX_BRIGHTNESS - 1; + + } else + return; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = max_brightness; + sony_backlight_device = backlight_device_register("sony", NULL, + &backlight_ng_handle, + ops, &props); + + if (IS_ERR(sony_backlight_device)) { + pr_warning(DRV_PFX "unable to register backlight device\n"); + sony_backlight_device = NULL; + } else + sony_backlight_device->props.brightness = + ops->get_brightness(sony_backlight_device); +} + +static void sony_nc_backlight_cleanup(void) +{ + if (sony_backlight_device) + backlight_device_unregister(sony_backlight_device); +} + static int sony_nc_add(struct acpi_device *device) { acpi_status status; @@ -1543,26 +1612,8 @@ static int sony_nc_add(struct acpi_device *device) if (acpi_video_backlight_support()) { pr_info(DRV_PFX "brightness ignored, must be " "controlled by ACPI video driver\n"); - } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", - &handle))) { - struct backlight_properties props; - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = SONY_MAX_BRIGHTNESS - 1; - sony_backlight_device = backlight_device_register("sony", NULL, - NULL, - &sony_backlight_ops, - &props); - - if (IS_ERR(sony_backlight_device)) { - pr_warning(DRV_PFX "unable to register backlight device\n"); - sony_backlight_device = NULL; - } else { - sony_backlight_device->props.brightness = - sony_backlight_get_brightness - (sony_backlight_device); - } - + } else { + sony_nc_backlight_setup(); } /* create sony_pf sysfs attributes related to the SNC device */ @@ -1610,8 +1661,7 @@ static int sony_nc_add(struct acpi_device *device) for (item = sony_nc_values; item->name; ++item) { device_remove_file(&sony_pf_device->dev, &item->devattr); } - if (sony_backlight_device) - backlight_device_unregister(sony_backlight_device); + sony_nc_backlight_cleanup(); sony_laptop_remove_input(); @@ -1633,8 +1683,7 @@ static int sony_nc_remove(struct acpi_device *device, int type) { struct sony_nc_value *item; - if (sony_backlight_device) - backlight_device_unregister(sony_backlight_device); + sony_nc_backlight_cleanup(); sony_nc_acpi_device = NULL; -- cgit v1.2.2 From 9af0e0fb70ed8e2387323c19496a7e174363f7b6 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 20 Feb 2011 20:07:20 +0200 Subject: hp-wmi: check query return value in hp_wmi_perform_query Check BIOS provided return value code in hp_wmi_perform_query and print a warning on error. Printing is suppressed for HPWMI_RET_UNKNOWN_CMDTYPE which is returned when the command type is unsupported. Signed-off-by: Anssi Hannula Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 9e05af9c41cb..87dfb2489762 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -89,6 +89,13 @@ struct bios_return { u32 value; }; +enum hp_return_value { + HPWMI_RET_WRONG_SIGNATURE = 0x02, + HPWMI_RET_UNKNOWN_COMMAND = 0x03, + HPWMI_RET_UNKNOWN_CMDTYPE = 0x04, + HPWMI_RET_INVALID_PARAMETERS = 0x05, +}; + static const struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, @@ -171,6 +178,15 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, bios_return = *((struct bios_return *)obj->buffer.pointer); + if (bios_return.return_code) { + if (bios_return.return_code != HPWMI_RET_UNKNOWN_CMDTYPE) + printk(KERN_WARNING PREFIX "query 0x%x returned " + "error 0x%x\n", + query, bios_return.return_code); + kfree(obj); + return bios_return.return_code; + } + memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); kfree(obj); -- cgit v1.2.2 From 25bb067a08c5db70cd8bcf9e160ac81718ea075c Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 20 Feb 2011 20:07:21 +0200 Subject: hp-wmi: remove a variable that is never read Remove the status variable from hp_wmi_perform_query which holds the return value from wmi_evaluate_method(). It is never checked as the function bails out if the output buffer hasn't been allocated which indicates the call failed. Signed-off-by: Anssi Hannula Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 87dfb2489762..8e27c27900a3 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -153,7 +153,6 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, int buffersize) { struct bios_return bios_return; - acpi_status status; union acpi_object *obj; struct bios_args args = { .signature = 0x55434553, @@ -165,7 +164,7 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, struct acpi_buffer input = { sizeof(struct bios_args), &args }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); + wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); obj = output.pointer; -- cgit v1.2.2 From c3021ea1beeeb1aa8a92fa6946a6e25fc55f171d Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 20 Feb 2011 20:07:22 +0200 Subject: hp-wmi: allow setting input and output buffer sizes separately Split buffersize parameter of hp_wmi_perform_query to insize and outsize. Existing callers are changed to use the same value for insize and outsize to avoid any regressions, with the exception of hp_wmi_set_block where the output buffer is unused and therefore outsize is set to 0 (this change is not seen by BIOS code). The maximum input buffer size is kept at 4 bytes as per struct bios_args. Some commands exist that take longer buffers, but they haven't been implemented. The data portion of bios_args can be trivially made dynamically allocated later when such larger buffers become needed. Signed-off-by: Anssi Hannula Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 63 ++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 8e27c27900a3..5c8ae65950d4 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -86,7 +86,6 @@ struct bios_args { struct bios_return { u32 sigpass; u32 return_code; - u32 value; }; enum hp_return_value { @@ -136,7 +135,8 @@ static struct platform_driver hp_wmi_driver = { * query: The commandtype -> What should be queried * write: The command -> 0 read, 1 write, 3 ODM specific * buffer: Buffer used as input and/or output - * buffersize: Size of buffer + * insize: Size of input buffer + * outsize: Size of output buffer * * returns zero on success * an HP WMI query specific error code (which is positive) @@ -147,23 +147,28 @@ static struct platform_driver hp_wmi_driver = { * size. E.g. Battery info query (0x7) is defined to have 1 byte input * and 128 byte output. The caller would do: * buffer = kzalloc(128, GFP_KERNEL); - * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) + * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128) */ -static int hp_wmi_perform_query(int query, int write, u32 *buffer, - int buffersize) +static int hp_wmi_perform_query(int query, int write, void *buffer, + int insize, int outsize) { - struct bios_return bios_return; + struct bios_return *bios_return; + int actual_outsize; union acpi_object *obj; struct bios_args args = { .signature = 0x55434553, .command = write ? 0x2 : 0x1, .commandtype = query, - .datasize = buffersize, - .data = *buffer, + .datasize = insize, + .data = 0, }; struct acpi_buffer input = { sizeof(struct bios_args), &args }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + if (WARN_ON(insize > sizeof(args.data))) + return -EINVAL; + memcpy(&args.data, buffer, insize); + wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); obj = output.pointer; @@ -175,19 +180,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer, return -EINVAL; } - bios_return = *((struct bios_return *)obj->buffer.pointer); + bios_return = (struct bios_return *)obj->buffer.pointer; - if (bios_return.return_code) { - if (bios_return.return_code != HPWMI_RET_UNKNOWN_CMDTYPE) + if (bios_return->return_code) { + if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE) printk(KERN_WARNING PREFIX "query 0x%x returned " "error 0x%x\n", - query, bios_return.return_code); + query, bios_return->return_code); kfree(obj); - return bios_return.return_code; + return bios_return->return_code; } - memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); + if (!outsize) { + /* ignore output data */ + kfree(obj); + return 0; + } + actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); + memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); + memset(buffer + actual_outsize, 0, outsize - actual_outsize); kfree(obj); return 0; } @@ -196,7 +208,7 @@ static int hp_wmi_display_state(void) { int state = 0; int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, - sizeof(state)); + sizeof(state), sizeof(state)); if (ret) return -EINVAL; return state; @@ -206,7 +218,7 @@ static int hp_wmi_hddtemp_state(void) { int state = 0; int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, - sizeof(state)); + sizeof(state), sizeof(state)); if (ret) return -EINVAL; return state; @@ -216,7 +228,7 @@ static int hp_wmi_als_state(void) { int state = 0; int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, - sizeof(state)); + sizeof(state), sizeof(state)); if (ret) return -EINVAL; return state; @@ -226,7 +238,7 @@ static int hp_wmi_dock_state(void) { int state = 0; int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, - sizeof(state)); + sizeof(state), sizeof(state)); if (ret) return -EINVAL; @@ -238,7 +250,7 @@ static int hp_wmi_tablet_state(void) { int state = 0; int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, - sizeof(state)); + sizeof(state), sizeof(state)); if (ret) return ret; @@ -252,7 +264,7 @@ static int hp_wmi_set_block(void *data, bool blocked) int ret; ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, - &query, sizeof(query)); + &query, sizeof(query), 0); if (ret) return -EINVAL; return 0; @@ -267,7 +279,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) int wireless = 0; int mask; hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, - &wireless, sizeof(wireless)); + &wireless, sizeof(wireless), + sizeof(wireless)); /* TBD: Pass error */ mask = 0x200 << (r * 8); @@ -283,7 +296,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) int wireless = 0; int mask; hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, - &wireless, sizeof(wireless)); + &wireless, sizeof(wireless), + sizeof(wireless)); /* TBD: Pass error */ mask = 0x800 << (r * 8); @@ -344,7 +358,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr, { u32 tmp = simple_strtoul(buf, NULL, 10); int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, - sizeof(tmp)); + sizeof(tmp), sizeof(tmp)); if (ret) return -EINVAL; @@ -417,6 +431,7 @@ static void hp_wmi_notify(u32 value, void *context) case HPWMI_BEZEL_BUTTON: ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, &key_code, + sizeof(key_code), sizeof(key_code)); if (ret) break; @@ -523,7 +538,7 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device) int wireless = 0; err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, - sizeof(wireless)); + sizeof(wireless), sizeof(wireless)); if (err) return err; -- cgit v1.2.2 From eceb7bdf644b418175aab1c998137e692ac98a4c Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 20 Feb 2011 20:07:23 +0200 Subject: hp-wmi: split rfkill initialization out of hp_wmi_bios_setup Split initialization of rfkill devices from hp_wmi_bios_setup() to hp_wmi_rfkill_setup(). This makes the code somewhat cleaner, especially with the future command 0x1b rfkill support. Signed-off-by: Anssi Hannula Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 46 +++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 5c8ae65950d4..f6a1c37af9cc 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -532,7 +532,7 @@ static void cleanup_sysfs(struct platform_device *device) device_remove_file(&device->dev, &dev_attr_tablet); } -static int __devinit hp_wmi_bios_setup(struct platform_device *device) +static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) { int err; int wireless = 0; @@ -542,22 +542,6 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device) if (err) return err; - err = device_create_file(&device->dev, &dev_attr_display); - if (err) - goto add_sysfs_error; - err = device_create_file(&device->dev, &dev_attr_hddtemp); - if (err) - goto add_sysfs_error; - err = device_create_file(&device->dev, &dev_attr_als); - if (err) - goto add_sysfs_error; - err = device_create_file(&device->dev, &dev_attr_dock); - if (err) - goto add_sysfs_error; - err = device_create_file(&device->dev, &dev_attr_tablet); - if (err) - goto add_sysfs_error; - if (wireless & 0x1) { wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, RFKILL_TYPE_WLAN, @@ -611,6 +595,34 @@ register_bluetooth_error: rfkill_unregister(wifi_rfkill); register_wifi_error: rfkill_destroy(wifi_rfkill); + return err; +} + +static int __devinit hp_wmi_bios_setup(struct platform_device *device) +{ + int err; + + err = hp_wmi_rfkill_setup(device); + if (err) + return err; + + err = device_create_file(&device->dev, &dev_attr_display); + if (err) + goto add_sysfs_error; + err = device_create_file(&device->dev, &dev_attr_hddtemp); + if (err) + goto add_sysfs_error; + err = device_create_file(&device->dev, &dev_attr_als); + if (err) + goto add_sysfs_error; + err = device_create_file(&device->dev, &dev_attr_dock); + if (err) + goto add_sysfs_error; + err = device_create_file(&device->dev, &dev_attr_tablet); + if (err) + goto add_sysfs_error; + return 0; + add_sysfs_error: cleanup_sysfs(device); return err; -- cgit v1.2.2 From 6d97db590ca2787c202cf35e76f5d24b3007bc7c Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 20 Feb 2011 20:07:24 +0200 Subject: hp-wmi: clear rfkill device pointers when appropriate NULLify rfkill pointers during initialization. This prevents dereference of invalid pointer in case the driver is rebound and some rfkill device isn't detected anymore. Clear them also in hp_wmi_rfkill_setup failure path so that an rfkill initialization failure doesn't need to be fatal for the whole driver. Signed-off-by: Anssi Hannula Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f6a1c37af9cc..45b2bbe6d835 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -587,14 +587,17 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) return 0; register_wwan_err: rfkill_destroy(wwan_rfkill); + wwan_rfkill = NULL; if (bluetooth_rfkill) rfkill_unregister(bluetooth_rfkill); register_bluetooth_error: rfkill_destroy(bluetooth_rfkill); + bluetooth_rfkill = NULL; if (wifi_rfkill) rfkill_unregister(wifi_rfkill); register_wifi_error: rfkill_destroy(wifi_rfkill); + wifi_rfkill = NULL; return err; } @@ -602,6 +605,11 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device) { int err; + /* clear detected rfkill devices */ + wifi_rfkill = NULL; + bluetooth_rfkill = NULL; + wwan_rfkill = NULL; + err = hp_wmi_rfkill_setup(device); if (err) return err; -- cgit v1.2.2 From 7cd635da42fda9272fd200121e565d116c0c65c9 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 20 Feb 2011 20:07:25 +0200 Subject: hp-wmi: make rfkill initialization failure non-fatal hp_wmi_rfkill_setup cleans up after itself now, so failing completely is no longer necessary. Signed-off-by: Anssi Hannula Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 45b2bbe6d835..524ffabc2866 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -610,9 +610,7 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device) bluetooth_rfkill = NULL; wwan_rfkill = NULL; - err = hp_wmi_rfkill_setup(device); - if (err) - return err; + hp_wmi_rfkill_setup(device); err = device_create_file(&device->dev, &dev_attr_display); if (err) -- cgit v1.2.2 From c0b9c6494498014f28dbec37fe327bf016a91356 Mon Sep 17 00:00:00 2001 From: Anssi Hannula Date: Sun, 20 Feb 2011 20:07:26 +0200 Subject: hp-wmi: add rfkill support for wireless query 0x1b Some recent HP laptops use a new wireless query command type 0x1b. Add support for it. Tested on HP Mini 5102. Signed-off-by: Anssi Hannula Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 188 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 524ffabc2866..1bc4a7539ba9 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -2,6 +2,7 @@ * HP WMI hotkeys * * Copyright (C) 2008 Red Hat + * Copyright (C) 2010, 2011 Anssi Hannula * * Portions based on wistron_btns.c: * Copyright (C) 2005 Miloslav Trmac @@ -51,6 +52,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_HARDWARE_QUERY 0x4 #define HPWMI_WIRELESS_QUERY 0x5 #define HPWMI_HOTKEY_QUERY 0xc +#define HPWMI_WIRELESS2_QUERY 0x1b #define PREFIX "HP WMI: " #define UNIMP "Unimplemented " @@ -95,6 +97,39 @@ enum hp_return_value { HPWMI_RET_INVALID_PARAMETERS = 0x05, }; +enum hp_wireless2_bits { + HPWMI_POWER_STATE = 0x01, + HPWMI_POWER_SOFT = 0x02, + HPWMI_POWER_BIOS = 0x04, + HPWMI_POWER_HARD = 0x08, +}; + +#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \ + != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) +#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) + +struct bios_rfkill2_device_state { + u8 radio_type; + u8 bus_type; + u16 vendor_id; + u16 product_id; + u16 subsys_vendor_id; + u16 subsys_product_id; + u8 rfkill_id; + u8 power; + u8 unknown[4]; +}; + +/* 7 devices fit into the 128 byte buffer */ +#define HPWMI_MAX_RFKILL2_DEVICES 7 + +struct bios_rfkill2_state { + u8 unknown[7]; + u8 count; + u8 pad[8]; + struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES]; +}; + static const struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, @@ -114,6 +149,15 @@ static struct rfkill *wifi_rfkill; static struct rfkill *bluetooth_rfkill; static struct rfkill *wwan_rfkill; +struct rfkill2_device { + u8 id; + int num; + struct rfkill *rfkill; +}; + +static int rfkill2_count; +static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; + static const struct dev_pm_ops hp_wmi_pm_ops = { .resume = hp_wmi_resume_handler, .restore = hp_wmi_resume_handler, @@ -308,6 +352,51 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) return true; } +static int hp_wmi_rfkill2_set_block(void *data, bool blocked) +{ + int rfkill_id = (int)(long)data; + char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; + + if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1, + buffer, sizeof(buffer), 0)) + return -EINVAL; + return 0; +} + +static const struct rfkill_ops hp_wmi_rfkill2_ops = { + .set_block = hp_wmi_rfkill2_set_block, +}; + +static int hp_wmi_rfkill2_refresh(void) +{ + int err, i; + struct bios_rfkill2_state state; + + err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, + 0, sizeof(state)); + if (err) + return err; + + for (i = 0; i < rfkill2_count; i++) { + int num = rfkill2[i].num; + struct bios_rfkill2_device_state *devstate; + devstate = &state.device[num]; + + if (num >= state.count || + devstate->rfkill_id != rfkill2[i].id) { + printk(KERN_WARNING PREFIX "power configuration of " + "the wireless devices unexpectedly changed\n"); + continue; + } + + rfkill_set_states(rfkill2[i].rfkill, + IS_SWBLOCKED(devstate->power), + IS_HWBLOCKED(devstate->power)); + } + + return 0; +} + static ssize_t show_display(struct device *dev, struct device_attribute *attr, char *buf) { @@ -442,6 +531,11 @@ static void hp_wmi_notify(u32 value, void *context) key_code); break; case HPWMI_WIRELESS: + if (rfkill2_count) { + hp_wmi_rfkill2_refresh(); + break; + } + if (wifi_rfkill) rfkill_set_states(wifi_rfkill, hp_wmi_get_sw_state(HPWMI_WIFI), @@ -601,6 +695,87 @@ register_wifi_error: return err; } +static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device) +{ + int err, i; + struct bios_rfkill2_state state; + err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, + 0, sizeof(state)); + if (err) + return err; + + if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { + printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n"); + return -EINVAL; + } + + for (i = 0; i < state.count; i++) { + struct rfkill *rfkill; + enum rfkill_type type; + char *name; + switch (state.device[i].radio_type) { + case HPWMI_WIFI: + type = RFKILL_TYPE_WLAN; + name = "hp-wifi"; + break; + case HPWMI_BLUETOOTH: + type = RFKILL_TYPE_BLUETOOTH; + name = "hp-bluetooth"; + break; + case HPWMI_WWAN: + type = RFKILL_TYPE_WWAN; + name = "hp-wwan"; + break; + default: + printk(KERN_WARNING PREFIX "unknown device type 0x%x\n", + state.device[i].radio_type); + continue; + } + + if (!state.device[i].vendor_id) { + printk(KERN_WARNING PREFIX "zero device %d while %d " + "reported\n", i, state.count); + continue; + } + + rfkill = rfkill_alloc(name, &device->dev, type, + &hp_wmi_rfkill2_ops, (void *)(long)i); + if (!rfkill) { + err = -ENOMEM; + goto fail; + } + + rfkill2[rfkill2_count].id = state.device[i].rfkill_id; + rfkill2[rfkill2_count].num = i; + rfkill2[rfkill2_count].rfkill = rfkill; + + rfkill_init_sw_state(rfkill, + IS_SWBLOCKED(state.device[i].power)); + rfkill_set_hw_state(rfkill, + IS_HWBLOCKED(state.device[i].power)); + + if (!(state.device[i].power & HPWMI_POWER_BIOS)) + printk(KERN_INFO PREFIX "device %s blocked by BIOS\n", + name); + + err = rfkill_register(rfkill); + if (err) { + rfkill_destroy(rfkill); + goto fail; + } + + rfkill2_count++; + } + + return 0; +fail: + for (; rfkill2_count > 0; rfkill2_count--) { + rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill); + rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill); + } + return err; +} + static int __devinit hp_wmi_bios_setup(struct platform_device *device) { int err; @@ -609,8 +784,10 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device) wifi_rfkill = NULL; bluetooth_rfkill = NULL; wwan_rfkill = NULL; + rfkill2_count = 0; - hp_wmi_rfkill_setup(device); + if (hp_wmi_rfkill_setup(device)) + hp_wmi_rfkill2_setup(device); err = device_create_file(&device->dev, &dev_attr_display); if (err) @@ -636,8 +813,14 @@ add_sysfs_error: static int __exit hp_wmi_bios_remove(struct platform_device *device) { + int i; cleanup_sysfs(device); + for (i = 0; i < rfkill2_count; i++) { + rfkill_unregister(rfkill2[i].rfkill); + rfkill_destroy(rfkill2[i].rfkill); + } + if (wifi_rfkill) { rfkill_unregister(wifi_rfkill); rfkill_destroy(wifi_rfkill); @@ -670,6 +853,9 @@ static int hp_wmi_resume_handler(struct device *device) input_sync(hp_wmi_input_dev); } + if (rfkill2_count) + hp_wmi_rfkill2_refresh(); + if (wifi_rfkill) rfkill_set_states(wifi_rfkill, hp_wmi_get_sw_state(HPWMI_WIFI), -- cgit v1.2.2 From f017fbe7993d8416824aaf079fa1e6dc88d1ba55 Mon Sep 17 00:00:00 2001 From: Durgadoss R Date: Sun, 20 Feb 2011 23:05:43 +0530 Subject: medfield: Add Thermal Driver This is the basic thermal sensor driver for Intel MID platform using the Medfield chipset. It plugs in via the thermal drivers and provides sensor readings for the device sensors. Signed-off-by: Durgadoss R Signed-off-by: Alan Cox Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 7 + drivers/platform/x86/Makefile | 3 +- drivers/platform/x86/intel_mid_thermal.c | 575 +++++++++++++++++++++++++++++++ 3 files changed, 584 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/x86/intel_mid_thermal.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 53f818d23edb..b039d6a93f17 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -637,6 +637,13 @@ config INTEL_MID_POWER_BUTTON If unsure, say N. +config INTEL_MFLD_THERMAL + tristate "Thermal driver for Intel Medfield platform" + depends on INTEL_SCU_IPC && THERMAL + help + Say Y here to enable thermal driver support for the Intel Medfield + platform. + config RAR_REGISTER bool "Restricted Access Region Register Driver" depends on PCI && X86_MRST diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 46f3fd2c8856..a9877711b3f1 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -30,7 +30,8 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o -obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o +obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o +obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o obj-$(CONFIG_INTEL_IPS) += intel_ips.o obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c new file mode 100644 index 000000000000..1215c3096868 --- /dev/null +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -0,0 +1,575 @@ +/* + * intel_mid_thermal.c - Intel MID platform thermal driver + * + * Copyright (C) 2011 Intel Corporation + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Author: Durgadoss R + */ + +#define pr_fmt(fmt) "intel_mid_thermal: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Number of thermal sensors */ +#define MSIC_THERMAL_SENSORS 4 + +/* ADC1 - thermal registers */ +#define MSIC_THERM_ADC1CNTL1 0x1C0 +#define MSIC_ADC_ENBL 0x10 +#define MSIC_ADC_START 0x08 + +#define MSIC_THERM_ADC1CNTL3 0x1C2 +#define MSIC_ADCTHERM_ENBL 0x04 +#define MSIC_ADCRRDATA_ENBL 0x05 +#define MSIC_CHANL_MASK_VAL 0x0F + +#define MSIC_STOPBIT_MASK 16 +#define MSIC_ADCTHERM_MASK 4 +#define ADC_CHANLS_MAX 15 /* Number of ADC channels */ +#define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS) + +/* ADC channel code values */ +#define SKIN_SENSOR0_CODE 0x08 +#define SKIN_SENSOR1_CODE 0x09 +#define SYS_SENSOR_CODE 0x0A +#define MSIC_DIE_SENSOR_CODE 0x03 + +#define SKIN_THERM_SENSOR0 0 +#define SKIN_THERM_SENSOR1 1 +#define SYS_THERM_SENSOR2 2 +#define MSIC_DIE_THERM_SENSOR3 3 + +/* ADC code range */ +#define ADC_MAX 977 +#define ADC_MIN 162 +#define ADC_VAL0C 887 +#define ADC_VAL20C 720 +#define ADC_VAL40C 508 +#define ADC_VAL60C 315 + +/* ADC base addresses */ +#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ +#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ + +/* MSIC die attributes */ +#define MSIC_DIE_ADC_MIN 488 +#define MSIC_DIE_ADC_MAX 1004 + +/* This holds the address of the first free ADC channel, + * among the 15 channels + */ +static int channel_index; + +struct platform_info { + struct platform_device *pdev; + struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS]; +}; + +struct thermal_device_info { + unsigned int chnl_addr; + int direct; + /* This holds the current temperature in millidegree celsius */ + long curr_temp; +}; + +/** + * to_msic_die_temp - converts adc_val to msic_die temperature + * @adc_val: ADC value to be converted + * + * Can sleep + */ +static int to_msic_die_temp(uint16_t adc_val) +{ + return (368 * (adc_val) / 1000) - 220; +} + +/** + * is_valid_adc - checks whether the adc code is within the defined range + * @min: minimum value for the sensor + * @max: maximum value for the sensor + * + * Can sleep + */ +static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max) +{ + return (adc_val >= min) && (adc_val <= max); +} + +/** + * adc_to_temp - converts the ADC code to temperature in C + * @direct: true if ths channel is direct index + * @adc_val: the adc_val that needs to be converted + * @tp: temperature return value + * + * Linear approximation is used to covert the skin adc value into temperature. + * This technique is used to avoid very long look-up table to get + * the appropriate temp value from ADC value. + * The adc code vs sensor temp curve is split into five parts + * to achieve very close approximate temp value with less than + * 0.5C error + */ +static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp) +{ + int temp; + + /* Direct conversion for die temperature */ + if (direct) { + if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) { + *tp = to_msic_die_temp(adc_val) * 1000; + return 0; + } + return -ERANGE; + } + + if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX)) + return -ERANGE; + + /* Linear approximation for skin temperature */ + if (adc_val > ADC_VAL0C) + temp = 177 - (adc_val/5); + else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C)) + temp = 111 - (adc_val/8); + else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C)) + temp = 92 - (adc_val/10); + else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C)) + temp = 91 - (adc_val/10); + else + temp = 112 - (adc_val/6); + + /* Convert temperature in celsius to milli degree celsius */ + *tp = temp * 1000; + return 0; +} + +/** + * mid_read_temp - read sensors for temperature + * @temp: holds the current temperature for the sensor after reading + * + * reads the adc_code from the channel and converts it to real + * temperature. The converted value is stored in temp. + * + * Can sleep + */ +static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) +{ + struct thermal_device_info *td_info = tzd->devdata; + uint16_t adc_val, addr; + uint8_t data = 0; + int ret; + unsigned long curr_temp; + + + addr = td_info->chnl_addr; + + /* Enable the msic for conversion before reading */ + ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); + if (ret) + return ret; + + /* Re-toggle the RRDATARD bit (temporary workaround) */ + ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL); + if (ret) + return ret; + + /* Read the higher bits of data */ + ret = intel_scu_ipc_ioread8(addr, &data); + if (ret) + return ret; + + /* Shift bits to accomodate the lower two data bits */ + adc_val = (data << 2); + addr++; + + ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */ + if (ret) + return ret; + + /* Adding lower two bits to the higher bits */ + data &= 03; + adc_val += data; + + /* Convert ADC value to temperature */ + ret = adc_to_temp(td_info->direct, adc_val, &curr_temp); + if (ret == 0) + *temp = td_info->curr_temp = curr_temp; + return ret; +} + +/** + * configure_adc - enables/disables the ADC for conversion + * @val: zero: disables the ADC non-zero:enables the ADC + * + * Enable/Disable the ADC depending on the argument + * + * Can sleep + */ +static int configure_adc(int val) +{ + int ret; + uint8_t data; + + ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); + if (ret) + return ret; + + if (val) { + /* Enable and start the ADC */ + data |= (MSIC_ADC_ENBL | MSIC_ADC_START); + } else { + /* Just stop the ADC */ + data &= (~MSIC_ADC_START); + } + + return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data); +} + +/** + * set_up_therm_channel - enable thermal channel for conversion + * @base_addr: index of free msic ADC channel + * + * Enable all the three channels for conversion + * + * Can sleep + */ +static int set_up_therm_channel(u16 base_addr) +{ + int ret; + + /* Enable all the sensor channels */ + ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE); + if (ret) + return ret; + + ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE); + if (ret) + return ret; + + ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE); + if (ret) + return ret; + + /* Since this is the last channel, set the stop bit + to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ + ret = intel_scu_ipc_iowrite8(base_addr + 3, + (MSIC_DIE_SENSOR_CODE | 0x10)); + if (ret) + return ret; + + /* Enable ADC and start it */ + return configure_adc(1); +} + +/** + * reset_stopbit - sets the stop bit to 0 on the given channel + * @addr: address of the channel + * + * Can sleep + */ +static int reset_stopbit(uint16_t addr) +{ + int ret; + uint8_t data; + ret = intel_scu_ipc_ioread8(addr, &data); + if (ret) + return ret; + /* Set the stop bit to zero */ + return intel_scu_ipc_iowrite8(addr, (data & 0xEF)); +} + +/** + * find_free_channel - finds an empty channel for conversion + * + * If the ADC is not enabled then start using 0th channel + * itself. Otherwise find an empty channel by looking for a + * channel in which the stopbit is set to 1. returns the index + * of the first free channel if succeeds or an error code. + * + * Context: can sleep + * + * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc + * code. + */ +static int find_free_channel(void) +{ + int ret; + int i; + uint8_t data; + + /* check whether ADC is enabled */ + ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); + if (ret) + return ret; + + if ((data & MSIC_ADC_ENBL) == 0) + return 0; + + /* ADC is already enabled; Looking for an empty channel */ + for (i = 0; i < ADC_CHANLS_MAX; i++) { + ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data); + if (ret) + return ret; + + if (data & MSIC_STOPBIT_MASK) { + ret = i; + break; + } + } + return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; +} + +/** + * mid_initialize_adc - initializing the ADC + * @dev: our device structure + * + * Initialize the ADC for reading thermistor values. Can sleep. + */ +static int mid_initialize_adc(struct device *dev) +{ + u8 data; + u16 base_addr; + int ret; + + /* + * Ensure that adctherm is disabled before we + * initialize the ADC + */ + ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data); + if (ret) + return ret; + + if (data & MSIC_ADCTHERM_MASK) + dev_warn(dev, "ADCTHERM already set"); + + /* Index of the first channel in which the stop bit is set */ + channel_index = find_free_channel(); + if (channel_index < 0) { + dev_err(dev, "No free ADC channels"); + return channel_index; + } + + base_addr = ADC_CHNL_START_ADDR + channel_index; + + if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { + /* Reset stop bit for channels other than 0 and 12 */ + ret = reset_stopbit(base_addr); + if (ret) + return ret; + + /* Index of the first free channel */ + base_addr++; + channel_index++; + } + + ret = set_up_therm_channel(base_addr); + if (ret) { + dev_err(dev, "unable to enable ADC"); + return ret; + } + dev_dbg(dev, "ADC initialization successful"); + return ret; +} + +/** + * initialize_sensor - sets default temp and timer ranges + * @index: index of the sensor + * + * Context: can sleep + */ +static struct thermal_device_info *initialize_sensor(int index) +{ + struct thermal_device_info *td_info = + kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL); + + if (!td_info) + return NULL; + + /* Set the base addr of the channel for this sensor */ + td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index); + /* Sensor 3 is direct conversion */ + if (index == 3) + td_info->direct = 1; + return td_info; +} + +/** + * mid_thermal_resume - resume routine + * @pdev: platform device structure + * + * mid thermal resume: re-initializes the adc. Can sleep. + */ +static int mid_thermal_resume(struct platform_device *pdev) +{ + return mid_initialize_adc(&pdev->dev); +} + +/** + * mid_thermal_suspend - suspend routine + * @pdev: platform device structure + * + * mid thermal suspend implements the suspend functionality + * by stopping the ADC. Can sleep. + */ +static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + /* + * This just stops the ADC and does not disable it. + * temporary workaround until we have a generic ADC driver. + * If 0 is passed, it disables the ADC. + */ + return configure_adc(0); +} + +/** + * read_curr_temp - reads the current temperature and stores in temp + * @temp: holds the current temperature value after reading + * + * Can sleep + */ +static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp) +{ + WARN_ON(tzd == NULL); + return mid_read_temp(tzd, temp); +} + +/* Can't be const */ +static struct thermal_zone_device_ops tzd_ops = { + .get_temp = read_curr_temp, +}; + + +/** + * mid_thermal_probe - mfld thermal initialize + * @pdev: platform device structure + * + * mid thermal probe initializes the hardware and registers + * all the sensors with the generic thermal framework. Can sleep. + */ +static int mid_thermal_probe(struct platform_device *pdev) +{ + static char *name[MSIC_THERMAL_SENSORS] = { + "skin0", "skin1", "sys", "msicdie" + }; + + int ret; + int i; + struct platform_info *pinfo; + + pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + /* Initializing the hardware */ + ret = mid_initialize_adc(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "ADC init failed"); + kfree(pinfo); + return ret; + } + + /* Register each sensor with the generic thermal framework*/ + for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { + pinfo->tzd[i] = thermal_zone_device_register(name[i], + 0, initialize_sensor(i), + &tzd_ops, 0, 0, 0, 0); + if (IS_ERR(pinfo->tzd[i])) + goto reg_fail; + } + + pinfo->pdev = pdev; + platform_set_drvdata(pdev, pinfo); + return 0; + +reg_fail: + ret = PTR_ERR(pinfo->tzd[i]); + while (--i >= 0) + thermal_zone_device_unregister(pinfo->tzd[i]); + configure_adc(0); + kfree(pinfo); + return ret; +} + +/** + * mid_thermal_remove - mfld thermal finalize + * @dev: platform device structure + * + * MLFD thermal remove unregisters all the sensors from the generic + * thermal framework. Can sleep. + */ +static int mid_thermal_remove(struct platform_device *pdev) +{ + int i; + struct platform_info *pinfo = platform_get_drvdata(pdev); + + for (i = 0; i < MSIC_THERMAL_SENSORS; i++) + thermal_zone_device_unregister(pinfo->tzd[i]); + + platform_set_drvdata(pdev, NULL); + + /* Stop the ADC */ + return configure_adc(0); +} + +/********************************************************************* + * Driver initialisation and finalization + *********************************************************************/ + +#define DRIVER_NAME "msic_sensor" + +static const struct platform_device_id therm_id_table[] = { + { DRIVER_NAME, 1 }, +}; + +static struct platform_driver mid_thermal_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = mid_thermal_probe, + .suspend = mid_thermal_suspend, + .resume = mid_thermal_resume, + .remove = __devexit_p(mid_thermal_remove), + .id_table = therm_id_table, +}; + +static int __init mid_thermal_module_init(void) +{ + return platform_driver_register(&mid_thermal_driver); +} + +static void __exit mid_thermal_module_exit(void) +{ + platform_driver_unregister(&mid_thermal_driver); +} + +module_init(mid_thermal_module_init); +module_exit(mid_thermal_module_exit); + +MODULE_AUTHOR("Durgadoss R "); +MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 5b799d4fb787bb94f1068352220ab033ac7969f8 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:30 +0100 Subject: asus-wmi: move generic code to asus-wmi New Asus notebooks are using a WMI device similar to the one used in Eee PCs. Since we don't want to load a module named eeepc-laptop on Asus Notebooks, start by copying all the code to asus-wmi.c. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Makefile | 2 +- drivers/platform/x86/asus-wmi.c | 1454 ++++++++++++++++++++++++++++++++++++++ drivers/platform/x86/eeepc-wmi.c | 1454 -------------------------------------- 3 files changed, 1455 insertions(+), 1455 deletions(-) create mode 100644 drivers/platform/x86/asus-wmi.c delete mode 100644 drivers/platform/x86/eeepc-wmi.c (limited to 'drivers') diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index a9877711b3f1..443257617b20 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o -obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o +obj-$(CONFIG_EEEPC_WMI) += asus-wmi.o eeepc-wmi.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c new file mode 100644 index 000000000000..d3997757e790 --- /dev/null +++ b/drivers/platform/x86/asus-wmi.c @@ -0,0 +1,1454 @@ +/* + * Eee PC WMI hotkey driver + * + * Copyright(C) 2010 Intel Corporation. + * Copyright(C) 2010 Corentin Chary + * + * Portions based on wistron_btns.c: + * Copyright (C) 2005 Miloslav Trmac + * Copyright (C) 2005 Bernhard Rosenkraenzer + * Copyright (C) 2005 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EEEPC_WMI_FILE "eeepc-wmi" + +MODULE_AUTHOR("Yong Wang "); +MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); +MODULE_LICENSE("GPL"); + +#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ + +#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" +#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" + +MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); +MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); + +#define NOTIFY_BRNUP_MIN 0x11 +#define NOTIFY_BRNUP_MAX 0x1f +#define NOTIFY_BRNDOWN_MIN 0x20 +#define NOTIFY_BRNDOWN_MAX 0x2e + +/* WMI Methods */ +#define EEEPC_WMI_METHODID_DSTS 0x53544344 +#define EEEPC_WMI_METHODID_DEVS 0x53564544 +#define EEEPC_WMI_METHODID_CFVS 0x53564643 + +/* Wireless */ +#define EEEPC_WMI_DEVID_WLAN 0x00010011 +#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 +#define EEEPC_WMI_DEVID_WIMAX 0x00010017 +#define EEEPC_WMI_DEVID_WWAN3G 0x00010019 + +/* Backlight and Brightness */ +#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050011 +#define EEEPC_WMI_DEVID_BRIGHTNESS 0x00050012 + +/* Misc */ +#define EEEPC_WMI_DEVID_CAMERA 0x00060013 + +/* Storage */ +#define EEEPC_WMI_DEVID_CARDREADER 0x00080013 + +/* Input */ +#define EEEPC_WMI_DEVID_TOUCHPAD 0x00100011 +#define EEEPC_WMI_DEVID_TOUCHPAD_LED 0x00100012 + +/* DSTS masks */ +#define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 +#define EEEPC_WMI_DSTS_PRESENCE_BIT 0x00010000 +#define EEEPC_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF +#define EEEPC_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 + +static bool hotplug_wireless; + +module_param(hotplug_wireless, bool, 0444); +MODULE_PARM_DESC(hotplug_wireless, + "Enable hotplug for wireless device. " + "If your laptop needs that, please report to " + "acpi4asus-user@lists.sourceforge.net."); + +static const struct key_entry eeepc_wmi_keymap[] = { + /* Sleep already handled via generic ACPI code */ + { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, + { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0x30, { KEY_VOLUMEUP } }, + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x32, { KEY_MUTE } }, + { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ + { KE_KEY, 0x5d, { KEY_WLAN } }, + { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ + { KE_KEY, 0x82, { KEY_CAMERA } }, + { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, + { KE_KEY, 0x88, { KEY_WLAN } }, + { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ + { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ + { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, + { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, + { KE_KEY, 0xec, { KEY_CAMERA_UP } }, + { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, + { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, + { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, + { KE_END, 0}, +}; + +struct bios_args { + u32 dev_id; + u32 ctrl_param; +}; + +/* + * eeepc-wmi/ - debugfs root directory + * dev_id - current dev_id + * ctrl_param - current ctrl_param + * devs - call DEVS(dev_id, ctrl_param) and print result + * dsts - call DSTS(dev_id) and print result + */ +struct eeepc_wmi_debug { + struct dentry *root; + u32 dev_id; + u32 ctrl_param; +}; + +struct eeepc_wmi { + bool hotplug_wireless; + + struct input_dev *inputdev; + struct backlight_device *backlight_device; + struct platform_device *platform_device; + + struct led_classdev tpd_led; + int tpd_led_wk; + struct workqueue_struct *led_workqueue; + struct work_struct tpd_led_work; + + struct rfkill *wlan_rfkill; + struct rfkill *bluetooth_rfkill; + struct rfkill *wimax_rfkill; + struct rfkill *wwan3g_rfkill; + + struct hotplug_slot *hotplug_slot; + struct mutex hotplug_lock; + struct mutex wmi_lock; + struct workqueue_struct *hotplug_workqueue; + struct work_struct hotplug_work; + + struct eeepc_wmi_debug debug; +}; + +static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) +{ + int err; + + eeepc->inputdev = input_allocate_device(); + if (!eeepc->inputdev) + return -ENOMEM; + + eeepc->inputdev->name = "Eee PC WMI hotkeys"; + eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; + eeepc->inputdev->id.bustype = BUS_HOST; + eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; + + err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); + if (err) + goto err_free_dev; + + err = input_register_device(eeepc->inputdev); + if (err) + goto err_free_keymap; + + return 0; + +err_free_keymap: + sparse_keymap_free(eeepc->inputdev); +err_free_dev: + input_free_device(eeepc->inputdev); + return err; +} + +static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) +{ + if (eeepc->inputdev) { + sparse_keymap_free(eeepc->inputdev); + input_unregister_device(eeepc->inputdev); + } + + eeepc->inputdev = NULL; +} + +static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) +{ + struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + u32 tmp; + + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, + 1, EEEPC_WMI_METHODID_DSTS, + &input, &output); + + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32)obj->integer.value; + else + tmp = 0; + + if (retval) + *retval = tmp; + + kfree(obj); + + return status; + +} + +static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, + u32 *retval) +{ + struct bios_args args = { + .dev_id = dev_id, + .ctrl_param = ctrl_param, + }; + struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; + acpi_status status; + + if (!retval) { + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, + EEEPC_WMI_METHODID_DEVS, + &input, NULL); + } else { + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + u32 tmp; + + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, + EEEPC_WMI_METHODID_DEVS, + &input, &output); + + if (ACPI_FAILURE(status)) + return status; + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + tmp = (u32)obj->integer.value; + else + tmp = 0; + + *retval = tmp; + + kfree(obj); + } + + return status; +} + +/* Helper for special devices with magic return codes */ +static int eeepc_wmi_get_devstate_bits(u32 dev_id, u32 mask) +{ + u32 retval = 0; + acpi_status status; + + status = eeepc_wmi_get_devstate(dev_id, &retval); + + if (ACPI_FAILURE(status)) + return -EINVAL; + + if (!(retval & EEEPC_WMI_DSTS_PRESENCE_BIT)) + return -ENODEV; + + return retval & mask; +} + +static int eeepc_wmi_get_devstate_simple(u32 dev_id) +{ + return eeepc_wmi_get_devstate_bits(dev_id, EEEPC_WMI_DSTS_STATUS_BIT); +} + +/* + * LEDs + */ +/* + * These functions actually update the LED's, and are called from a + * workqueue. By doing this as separate work rather than when the LED + * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a + * potentially bad time, such as a timer interrupt. + */ +static void tpd_led_update(struct work_struct *work) +{ + int ctrl_param; + struct eeepc_wmi *eeepc; + + eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); + + ctrl_param = eeepc->tpd_led_wk; + eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); +} + +static void tpd_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct eeepc_wmi *eeepc; + + eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); + + eeepc->tpd_led_wk = !!value; + queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); +} + +static int read_tpd_led_state(struct eeepc_wmi *eeepc) +{ + return eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_TOUCHPAD_LED); +} + +static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) +{ + struct eeepc_wmi *eeepc; + + eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); + + return read_tpd_led_state(eeepc); +} + +static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) +{ + int rv; + + if (read_tpd_led_state(eeepc) < 0) + return 0; + + eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!eeepc->led_workqueue) + return -ENOMEM; + INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); + + eeepc->tpd_led.name = "eeepc::touchpad"; + eeepc->tpd_led.brightness_set = tpd_led_set; + eeepc->tpd_led.brightness_get = tpd_led_get; + eeepc->tpd_led.max_brightness = 1; + + rv = led_classdev_register(&eeepc->platform_device->dev, + &eeepc->tpd_led); + if (rv) { + destroy_workqueue(eeepc->led_workqueue); + return rv; + } + + return 0; +} + +static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) +{ + if (eeepc->tpd_led.dev) + led_classdev_unregister(&eeepc->tpd_led); + if (eeepc->led_workqueue) + destroy_workqueue(eeepc->led_workqueue); +} + +/* + * PCI hotplug (for wlan rfkill) + */ +static bool eeepc_wlan_rfkill_blocked(struct eeepc_wmi *eeepc) +{ + int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); + + if (result < 0) + return false; + return !result; +} + +static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) +{ + struct pci_dev *dev; + struct pci_bus *bus; + bool blocked; + bool absent; + u32 l; + + mutex_lock(&eeepc->wmi_lock); + blocked = eeepc_wlan_rfkill_blocked(eeepc); + mutex_unlock(&eeepc->wmi_lock); + + mutex_lock(&eeepc->hotplug_lock); + + if (eeepc->wlan_rfkill) + rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); + + if (eeepc->hotplug_slot) { + bus = pci_find_bus(0, 1); + if (!bus) { + pr_warning("Unable to find PCI bus 1?\n"); + goto out_unlock; + } + + if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { + pr_err("Unable to read PCI config space?\n"); + goto out_unlock; + } + absent = (l == 0xffffffff); + + if (blocked != absent) { + pr_warning("BIOS says wireless lan is %s, " + "but the pci device is %s\n", + blocked ? "blocked" : "unblocked", + absent ? "absent" : "present"); + pr_warning("skipped wireless hotplug as probably " + "inappropriate for this model\n"); + goto out_unlock; + } + + if (!blocked) { + dev = pci_get_slot(bus, 0); + if (dev) { + /* Device already present */ + pci_dev_put(dev); + goto out_unlock; + } + dev = pci_scan_single_device(bus, 0); + if (dev) { + pci_bus_assign_resources(bus); + if (pci_bus_add_device(dev)) + pr_err("Unable to hotplug wifi\n"); + } + } else { + dev = pci_get_slot(bus, 0); + if (dev) { + pci_remove_bus_device(dev); + pci_dev_put(dev); + } + } + } + +out_unlock: + mutex_unlock(&eeepc->hotplug_lock); +} + +static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) +{ + struct eeepc_wmi *eeepc = data; + + if (event != ACPI_NOTIFY_BUS_CHECK) + return; + + /* + * We can't call directly eeepc_rfkill_hotplug because most + * of the time WMBC is still being executed and not reetrant. + * There is currently no way to tell ACPICA that we want this + * method to be serialized, we schedule a eeepc_rfkill_hotplug + * call later, in a safer context. + */ + queue_work(eeepc->hotplug_workqueue, &eeepc->hotplug_work); +} + +static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, + char *node) +{ + acpi_status status; + acpi_handle handle; + + status = acpi_get_handle(NULL, node, &handle); + + if (ACPI_SUCCESS(status)) { + status = acpi_install_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + eeepc_rfkill_notify, + eeepc); + if (ACPI_FAILURE(status)) + pr_warning("Failed to register notify on %s\n", node); + } else + return -ENODEV; + + return 0; +} + +static void eeepc_unregister_rfkill_notifier(struct eeepc_wmi *eeepc, + char *node) +{ + acpi_status status = AE_OK; + acpi_handle handle; + + status = acpi_get_handle(NULL, node, &handle); + + if (ACPI_SUCCESS(status)) { + status = acpi_remove_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + eeepc_rfkill_notify); + if (ACPI_FAILURE(status)) + pr_err("Error removing rfkill notify handler %s\n", + node); + } +} + +static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, + u8 *value) +{ + int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); + + if (result < 0) + return result; + + *value = !!result; + return 0; +} + +static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) +{ + kfree(hotplug_slot->info); + kfree(hotplug_slot); +} + +static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { + .owner = THIS_MODULE, + .get_adapter_status = eeepc_get_adapter_status, + .get_power_status = eeepc_get_adapter_status, +}; + +static void eeepc_hotplug_work(struct work_struct *work) +{ + struct eeepc_wmi *eeepc; + + eeepc = container_of(work, struct eeepc_wmi, hotplug_work); + eeepc_rfkill_hotplug(eeepc); +} + +static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) +{ + int ret = -ENOMEM; + struct pci_bus *bus = pci_find_bus(0, 1); + + if (!bus) { + pr_err("Unable to find wifi PCI bus\n"); + return -ENODEV; + } + + eeepc->hotplug_workqueue = + create_singlethread_workqueue("hotplug_workqueue"); + if (!eeepc->hotplug_workqueue) + goto error_workqueue; + + INIT_WORK(&eeepc->hotplug_work, eeepc_hotplug_work); + + eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!eeepc->hotplug_slot) + goto error_slot; + + eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), + GFP_KERNEL); + if (!eeepc->hotplug_slot->info) + goto error_info; + + eeepc->hotplug_slot->private = eeepc; + eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; + eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; + eeepc_get_adapter_status(eeepc->hotplug_slot, + &eeepc->hotplug_slot->info->adapter_status); + + ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); + if (ret) { + pr_err("Unable to register hotplug slot - %d\n", ret); + goto error_register; + } + + return 0; + +error_register: + kfree(eeepc->hotplug_slot->info); +error_info: + kfree(eeepc->hotplug_slot); + eeepc->hotplug_slot = NULL; +error_slot: + destroy_workqueue(eeepc->hotplug_workqueue); +error_workqueue: + return ret; +} + +/* + * Rfkill devices + */ +static int eeepc_rfkill_set(void *data, bool blocked) +{ + int dev_id = (unsigned long)data; + u32 ctrl_param = !blocked; + acpi_status status; + + status = eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); + + if (ACPI_FAILURE(status)) + return -EIO; + + return 0; +} + +static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) +{ + int dev_id = (unsigned long)data; + int result; + + result = eeepc_wmi_get_devstate_simple(dev_id); + + if (result < 0) + return ; + + rfkill_set_sw_state(rfkill, !result); +} + +static int eeepc_rfkill_wlan_set(void *data, bool blocked) +{ + struct eeepc_wmi *eeepc = data; + int ret; + + /* + * This handler is enabled only if hotplug is enabled. + * In this case, the eeepc_wmi_set_devstate() will + * trigger a wmi notification and we need to wait + * this call to finish before being able to call + * any wmi method + */ + mutex_lock(&eeepc->wmi_lock); + ret = eeepc_rfkill_set((void *)(long)EEEPC_WMI_DEVID_WLAN, blocked); + mutex_unlock(&eeepc->wmi_lock); + return ret; +} + +static void eeepc_rfkill_wlan_query(struct rfkill *rfkill, void *data) +{ + eeepc_rfkill_query(rfkill, (void *)(long)EEEPC_WMI_DEVID_WLAN); +} + +static const struct rfkill_ops eeepc_rfkill_wlan_ops = { + .set_block = eeepc_rfkill_wlan_set, + .query = eeepc_rfkill_wlan_query, +}; + +static const struct rfkill_ops eeepc_rfkill_ops = { + .set_block = eeepc_rfkill_set, + .query = eeepc_rfkill_query, +}; + +static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, + struct rfkill **rfkill, + const char *name, + enum rfkill_type type, int dev_id) +{ + int result = eeepc_wmi_get_devstate_simple(dev_id); + + if (result < 0) + return result; + + if (dev_id == EEEPC_WMI_DEVID_WLAN && eeepc->hotplug_wireless) + *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, + &eeepc_rfkill_wlan_ops, eeepc); + else + *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, + &eeepc_rfkill_ops, (void *)(long)dev_id); + + if (!*rfkill) + return -EINVAL; + + rfkill_init_sw_state(*rfkill, !result); + result = rfkill_register(*rfkill); + if (result) { + rfkill_destroy(*rfkill); + *rfkill = NULL; + return result; + } + return 0; +} + +static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) +{ + eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); + eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); + eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); + if (eeepc->wlan_rfkill) { + rfkill_unregister(eeepc->wlan_rfkill); + rfkill_destroy(eeepc->wlan_rfkill); + eeepc->wlan_rfkill = NULL; + } + /* + * Refresh pci hotplug in case the rfkill state was changed after + * eeepc_unregister_rfkill_notifier() + */ + eeepc_rfkill_hotplug(eeepc); + if (eeepc->hotplug_slot) + pci_hp_deregister(eeepc->hotplug_slot); + if (eeepc->hotplug_workqueue) + destroy_workqueue(eeepc->hotplug_workqueue); + + if (eeepc->bluetooth_rfkill) { + rfkill_unregister(eeepc->bluetooth_rfkill); + rfkill_destroy(eeepc->bluetooth_rfkill); + eeepc->bluetooth_rfkill = NULL; + } + if (eeepc->wimax_rfkill) { + rfkill_unregister(eeepc->wimax_rfkill); + rfkill_destroy(eeepc->wimax_rfkill); + eeepc->wimax_rfkill = NULL; + } + if (eeepc->wwan3g_rfkill) { + rfkill_unregister(eeepc->wwan3g_rfkill); + rfkill_destroy(eeepc->wwan3g_rfkill); + eeepc->wwan3g_rfkill = NULL; + } +} + +static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) +{ + int result = 0; + + mutex_init(&eeepc->hotplug_lock); + mutex_init(&eeepc->wmi_lock); + + result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, + "eeepc-wlan", RFKILL_TYPE_WLAN, + EEEPC_WMI_DEVID_WLAN); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, + "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, + EEEPC_WMI_DEVID_BLUETOOTH); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill, + "eeepc-wimax", RFKILL_TYPE_WIMAX, + EEEPC_WMI_DEVID_WIMAX); + + if (result && result != -ENODEV) + goto exit; + + result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, + "eeepc-wwan3g", RFKILL_TYPE_WWAN, + EEEPC_WMI_DEVID_WWAN3G); + + if (result && result != -ENODEV) + goto exit; + + if (!eeepc->hotplug_wireless) + goto exit; + + result = eeepc_setup_pci_hotplug(eeepc); + /* + * If we get -EBUSY then something else is handling the PCI hotplug - + * don't fail in this case + */ + if (result == -EBUSY) + result = 0; + + eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); + eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); + eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); + /* + * Refresh pci hotplug in case the rfkill state was changed during + * setup. + */ + eeepc_rfkill_hotplug(eeepc); + +exit: + if (result && result != -ENODEV) + eeepc_wmi_rfkill_exit(eeepc); + + if (result == -ENODEV) + result = 0; + + return result; +} + +/* + * Backlight + */ +static int read_backlight_power(void) +{ + int ret = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BACKLIGHT); + + if (ret < 0) + return ret; + + return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; +} + +static int read_brightness(struct backlight_device *bd) +{ + u32 retval; + acpi_status status; + + status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, &retval); + + if (ACPI_FAILURE(status)) + return -EIO; + else + return retval & EEEPC_WMI_DSTS_BRIGHTNESS_MASK; +} + +static int update_bl_status(struct backlight_device *bd) +{ + u32 ctrl_param; + acpi_status status; + int power; + + ctrl_param = bd->props.brightness; + + status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, + ctrl_param, NULL); + + if (ACPI_FAILURE(status)) + return -EIO; + + power = read_backlight_power(); + if (power != -ENODEV && bd->props.power != power) { + ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); + status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, + ctrl_param, NULL); + + if (ACPI_FAILURE(status)) + return -EIO; + } + return 0; +} + +static const struct backlight_ops eeepc_wmi_bl_ops = { + .get_brightness = read_brightness, + .update_status = update_bl_status, +}; + +static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) +{ + struct backlight_device *bd = eeepc->backlight_device; + int old = bd->props.brightness; + int new = old; + + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) + new = code - NOTIFY_BRNUP_MIN + 1; + else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) + new = code - NOTIFY_BRNDOWN_MIN; + + bd->props.brightness = new; + backlight_update_status(bd); + backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); + + return old; +} + +static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) +{ + struct backlight_device *bd; + struct backlight_properties props; + int max; + int power; + + max = eeepc_wmi_get_devstate_bits(EEEPC_WMI_DEVID_BRIGHTNESS, + EEEPC_WMI_DSTS_MAX_BRIGTH_MASK); + power = read_backlight_power(); + + if (max < 0 && power < 0) { + /* Try to keep the original error */ + if (max == -ENODEV && power == -ENODEV) + return -ENODEV; + if (max != -ENODEV) + return max; + else + return power; + } + if (max == -ENODEV) + max = 0; + if (power == -ENODEV) + power = FB_BLANK_UNBLANK; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = max; + bd = backlight_device_register(EEEPC_WMI_FILE, + &eeepc->platform_device->dev, eeepc, + &eeepc_wmi_bl_ops, &props); + if (IS_ERR(bd)) { + pr_err("Could not register backlight device\n"); + return PTR_ERR(bd); + } + + eeepc->backlight_device = bd; + + bd->props.brightness = read_brightness(bd); + bd->props.power = power; + backlight_update_status(bd); + + return 0; +} + +static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc) +{ + if (eeepc->backlight_device) + backlight_device_unregister(eeepc->backlight_device); + + eeepc->backlight_device = NULL; +} + +static void eeepc_wmi_notify(u32 value, void *context) +{ + struct eeepc_wmi *eeepc = context; + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + int code; + int orig_code; + + status = wmi_get_event_data(value, &response); + if (status != AE_OK) { + pr_err("bad event status 0x%x\n", status); + return; + } + + obj = (union acpi_object *)response.pointer; + + if (obj && obj->type == ACPI_TYPE_INTEGER) { + code = obj->integer.value; + orig_code = code; + + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) + code = NOTIFY_BRNUP_MIN; + else if (code >= NOTIFY_BRNDOWN_MIN && + code <= NOTIFY_BRNDOWN_MAX) + code = NOTIFY_BRNDOWN_MIN; + + if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { + if (!acpi_video_backlight_support()) + eeepc_wmi_backlight_notify(eeepc, orig_code); + } + + if (!sparse_keymap_report_event(eeepc->inputdev, + code, 1, true)) + pr_info("Unknown key %x pressed\n", code); + } + + kfree(obj); +} + +/* + * Sys helpers + */ +static int parse_arg(const char *buf, unsigned long count, int *val) +{ + if (!count) + return 0; + if (sscanf(buf, "%i", val) != 1) + return -EINVAL; + return count; +} + +static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) +{ + acpi_status status; + u32 retval; + int rv, value; + + value = eeepc_wmi_get_devstate_simple(devid); + if (value == -ENODEV) /* Check device presence */ + return value; + + rv = parse_arg(buf, count, &value); + status = eeepc_wmi_set_devstate(devid, value, &retval); + + if (ACPI_FAILURE(status)) + return -EIO; + return rv; +} + +static ssize_t show_sys_wmi(int devid, char *buf) +{ + int value = eeepc_wmi_get_devstate_simple(devid); + + if (value < 0) + return value; + + return sprintf(buf, "%d\n", value); +} + +#define EEEPC_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ + static ssize_t show_##_name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return show_sys_wmi(_cm, buf); \ + } \ + static ssize_t store_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + return store_sys_wmi(_cm, buf, count); \ + } \ + static struct device_attribute dev_attr_##_name = { \ + .attr = { \ + .name = __stringify(_name), \ + .mode = _mode }, \ + .show = show_##_name, \ + .store = store_##_name, \ + } + +EEEPC_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, EEEPC_WMI_DEVID_TOUCHPAD); +EEEPC_WMI_CREATE_DEVICE_ATTR(camera, 0644, EEEPC_WMI_DEVID_CAMERA); +EEEPC_WMI_CREATE_DEVICE_ATTR(cardr, 0644, EEEPC_WMI_DEVID_CARDREADER); + +static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int value; + struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; + acpi_status status; + + if (!count || sscanf(buf, "%i", &value) != 1) + return -EINVAL; + if (value < 0 || value > 2) + return -EINVAL; + + status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, + 1, EEEPC_WMI_METHODID_CFVS, &input, NULL); + + if (ACPI_FAILURE(status)) + return -EIO; + else + return count; +} + +static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); + +static struct attribute *platform_attributes[] = { + &dev_attr_cpufv.attr, + &dev_attr_camera.attr, + &dev_attr_cardr.attr, + &dev_attr_touchpad.attr, + NULL +}; + +static mode_t eeepc_sysfs_is_visible(struct kobject *kobj, + struct attribute *attr, + int idx) +{ + bool supported = true; + int devid = -1; + + if (attr == &dev_attr_camera.attr) + devid = EEEPC_WMI_DEVID_CAMERA; + else if (attr == &dev_attr_cardr.attr) + devid = EEEPC_WMI_DEVID_CARDREADER; + else if (attr == &dev_attr_touchpad.attr) + devid = EEEPC_WMI_DEVID_TOUCHPAD; + + if (devid != -1) + supported = eeepc_wmi_get_devstate_simple(devid) != -ENODEV; + + return supported ? attr->mode : 0; +} + +static struct attribute_group platform_attribute_group = { + .is_visible = eeepc_sysfs_is_visible, + .attrs = platform_attributes +}; + +static void eeepc_wmi_sysfs_exit(struct platform_device *device) +{ + sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); +} + +static int eeepc_wmi_sysfs_init(struct platform_device *device) +{ + return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); +} + +/* + * Platform device + */ +static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) +{ + return eeepc_wmi_sysfs_init(eeepc->platform_device); +} + +static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) +{ + eeepc_wmi_sysfs_exit(eeepc->platform_device); +} + +/* + * debugfs + */ +struct eeepc_wmi_debugfs_node { + struct eeepc_wmi *eeepc; + char *name; + int (*show)(struct seq_file *m, void *data); +}; + +static int show_dsts(struct seq_file *m, void *data) +{ + struct eeepc_wmi *eeepc = m->private; + acpi_status status; + u32 retval = -1; + + status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); + + if (ACPI_FAILURE(status)) + return -EIO; + + seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); + + return 0; +} + +static int show_devs(struct seq_file *m, void *data) +{ + struct eeepc_wmi *eeepc = m->private; + acpi_status status; + u32 retval = -1; + + status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, + eeepc->debug.ctrl_param, &retval); + if (ACPI_FAILURE(status)) + return -EIO; + + seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, + eeepc->debug.ctrl_param, retval); + + return 0; +} + +static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { + { NULL, "devs", show_devs }, + { NULL, "dsts", show_dsts }, +}; + +static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) +{ + struct eeepc_wmi_debugfs_node *node = inode->i_private; + + return single_open(file, node->show, node->eeepc); +} + +static const struct file_operations eeepc_wmi_debugfs_io_ops = { + .owner = THIS_MODULE, + .open = eeepc_wmi_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) +{ + debugfs_remove_recursive(eeepc->debug.root); +} + +static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) +{ + struct dentry *dent; + int i; + + eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); + if (!eeepc->debug.root) { + pr_err("failed to create debugfs directory"); + goto error_debugfs; + } + + dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, + eeepc->debug.root, &eeepc->debug.dev_id); + if (!dent) + goto error_debugfs; + + dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, + eeepc->debug.root, &eeepc->debug.ctrl_param); + if (!dent) + goto error_debugfs; + + for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { + struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; + + node->eeepc = eeepc; + dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, + eeepc->debug.root, node, + &eeepc_wmi_debugfs_io_ops); + if (!dent) { + pr_err("failed to create debug file: %s\n", node->name); + goto error_debugfs; + } + } + + return 0; + +error_debugfs: + eeepc_wmi_debugfs_exit(eeepc); + return -ENOMEM; +} + +/* + * WMI Driver + */ +static void eeepc_dmi_check(struct eeepc_wmi *eeepc) +{ + const char *model; + + model = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!model) + return; + + /* + * Whitelist for wlan hotplug + * + * Eeepc 1000H needs the current hotplug code to handle + * Fn+F2 correctly. We may add other Eeepc here later, but + * it seems that most of the laptops supported by eeepc-wmi + * don't need to be on this list + */ + if (strcmp(model, "1000H") == 0) { + eeepc->hotplug_wireless = true; + pr_info("wlan hotplug enabled\n"); + } +} + +static int __init eeepc_wmi_add(struct platform_device *pdev) +{ + struct eeepc_wmi *eeepc; + acpi_status status; + int err; + + eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); + if (!eeepc) + return -ENOMEM; + + eeepc->platform_device = pdev; + platform_set_drvdata(eeepc->platform_device, eeepc); + + eeepc->hotplug_wireless = hotplug_wireless; + eeepc_dmi_check(eeepc); + + err = eeepc_wmi_platform_init(eeepc); + if (err) + goto fail_platform; + + err = eeepc_wmi_input_init(eeepc); + if (err) + goto fail_input; + + err = eeepc_wmi_led_init(eeepc); + if (err) + goto fail_leds; + + err = eeepc_wmi_rfkill_init(eeepc); + if (err) + goto fail_rfkill; + + if (!acpi_video_backlight_support()) { + err = eeepc_wmi_backlight_init(eeepc); + if (err && err != -ENODEV) + goto fail_backlight; + } else + pr_info("Backlight controlled by ACPI video driver\n"); + + status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, + eeepc_wmi_notify, eeepc); + if (ACPI_FAILURE(status)) { + pr_err("Unable to register notify handler - %d\n", + status); + err = -ENODEV; + goto fail_wmi_handler; + } + + err = eeepc_wmi_debugfs_init(eeepc); + if (err) + goto fail_debugfs; + + return 0; + +fail_debugfs: + wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); +fail_wmi_handler: + eeepc_wmi_backlight_exit(eeepc); +fail_backlight: + eeepc_wmi_rfkill_exit(eeepc); +fail_rfkill: + eeepc_wmi_led_exit(eeepc); +fail_leds: + eeepc_wmi_input_exit(eeepc); +fail_input: + eeepc_wmi_platform_exit(eeepc); +fail_platform: + kfree(eeepc); + return err; +} + +static int __exit eeepc_wmi_remove(struct platform_device *device) +{ + struct eeepc_wmi *eeepc; + + eeepc = platform_get_drvdata(device); + wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); + eeepc_wmi_backlight_exit(eeepc); + eeepc_wmi_input_exit(eeepc); + eeepc_wmi_led_exit(eeepc); + eeepc_wmi_rfkill_exit(eeepc); + eeepc_wmi_debugfs_exit(eeepc); + eeepc_wmi_platform_exit(eeepc); + + kfree(eeepc); + return 0; +} + +/* + * Platform driver - hibernate/resume callbacks + */ +static int eeepc_hotk_thaw(struct device *device) +{ + struct eeepc_wmi *eeepc = dev_get_drvdata(device); + + if (eeepc->wlan_rfkill) { + bool wlan; + + /* + * Work around bios bug - acpi _PTS turns off the wireless led + * during suspend. Normally it restores it on resume, but + * we should kick it ourselves in case hibernation is aborted. + */ + wlan = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); + eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_WLAN, wlan, NULL); + } + + return 0; +} + +static int eeepc_hotk_restore(struct device *device) +{ + struct eeepc_wmi *eeepc = dev_get_drvdata(device); + int bl; + + /* Refresh both wlan rfkill state and pci hotplug */ + if (eeepc->wlan_rfkill) + eeepc_rfkill_hotplug(eeepc); + + if (eeepc->bluetooth_rfkill) { + bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BLUETOOTH); + rfkill_set_sw_state(eeepc->bluetooth_rfkill, bl); + } + if (eeepc->wimax_rfkill) { + bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WIMAX); + rfkill_set_sw_state(eeepc->wimax_rfkill, bl); + } + if (eeepc->wwan3g_rfkill) { + bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WWAN3G); + rfkill_set_sw_state(eeepc->wwan3g_rfkill, bl); + } + + return 0; +} + +static const struct dev_pm_ops eeepc_pm_ops = { + .thaw = eeepc_hotk_thaw, + .restore = eeepc_hotk_restore, +}; + +static struct platform_driver platform_driver = { + .remove = __exit_p(eeepc_wmi_remove), + .driver = { + .name = EEEPC_WMI_FILE, + .owner = THIS_MODULE, + .pm = &eeepc_pm_ops, + }, +}; + +static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, + void *context, void **retval) +{ + pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); + *(bool *)context = true; + return AE_CTRL_TERMINATE; +} + +static int __init eeepc_wmi_check_atkd(void) +{ + acpi_status status; + bool found = false; + + status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device, + &found, NULL); + + if (ACPI_FAILURE(status) || !found) + return 0; + return -1; +} + +static int __init eeepc_wmi_probe(struct platform_device *pdev) +{ + if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || + !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { + pr_warning("No known WMI GUID found\n"); + return -ENODEV; + } + + if (eeepc_wmi_check_atkd()) { + pr_warning("WMI device present, but legacy ATKD device is also " + "present and enabled."); + pr_warning("You probably booted with acpi_osi=\"Linux\" or " + "acpi_osi=\"!Windows 2009\""); + pr_warning("Can't load eeepc-wmi, use default acpi_osi " + "(preferred) or eeepc-laptop"); + return -ENODEV; + } + + return eeepc_wmi_add(pdev); +} + +static struct platform_device *platform_device; + +static int __init eeepc_wmi_init(void) +{ + platform_device = platform_create_bundle(&platform_driver, + eeepc_wmi_probe, + NULL, 0, NULL, 0); + if (IS_ERR(platform_device)) + return PTR_ERR(platform_device); + return 0; +} + +static void __exit eeepc_wmi_exit(void) +{ + platform_device_unregister(platform_device); + platform_driver_unregister(&platform_driver); +} + +module_init(eeepc_wmi_init); +module_exit(eeepc_wmi_exit); diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c deleted file mode 100644 index d3997757e790..000000000000 --- a/drivers/platform/x86/eeepc-wmi.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * Eee PC WMI hotkey driver - * - * Copyright(C) 2010 Intel Corporation. - * Copyright(C) 2010 Corentin Chary - * - * Portions based on wistron_btns.c: - * Copyright (C) 2005 Miloslav Trmac - * Copyright (C) 2005 Bernhard Rosenkraenzer - * Copyright (C) 2005 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define EEEPC_WMI_FILE "eeepc-wmi" - -MODULE_AUTHOR("Yong Wang "); -MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); -MODULE_LICENSE("GPL"); - -#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ - -#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" -#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" - -MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); -MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); - -#define NOTIFY_BRNUP_MIN 0x11 -#define NOTIFY_BRNUP_MAX 0x1f -#define NOTIFY_BRNDOWN_MIN 0x20 -#define NOTIFY_BRNDOWN_MAX 0x2e - -/* WMI Methods */ -#define EEEPC_WMI_METHODID_DSTS 0x53544344 -#define EEEPC_WMI_METHODID_DEVS 0x53564544 -#define EEEPC_WMI_METHODID_CFVS 0x53564643 - -/* Wireless */ -#define EEEPC_WMI_DEVID_WLAN 0x00010011 -#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 -#define EEEPC_WMI_DEVID_WIMAX 0x00010017 -#define EEEPC_WMI_DEVID_WWAN3G 0x00010019 - -/* Backlight and Brightness */ -#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050011 -#define EEEPC_WMI_DEVID_BRIGHTNESS 0x00050012 - -/* Misc */ -#define EEEPC_WMI_DEVID_CAMERA 0x00060013 - -/* Storage */ -#define EEEPC_WMI_DEVID_CARDREADER 0x00080013 - -/* Input */ -#define EEEPC_WMI_DEVID_TOUCHPAD 0x00100011 -#define EEEPC_WMI_DEVID_TOUCHPAD_LED 0x00100012 - -/* DSTS masks */ -#define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 -#define EEEPC_WMI_DSTS_PRESENCE_BIT 0x00010000 -#define EEEPC_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF -#define EEEPC_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 - -static bool hotplug_wireless; - -module_param(hotplug_wireless, bool, 0444); -MODULE_PARM_DESC(hotplug_wireless, - "Enable hotplug for wireless device. " - "If your laptop needs that, please report to " - "acpi4asus-user@lists.sourceforge.net."); - -static const struct key_entry eeepc_wmi_keymap[] = { - /* Sleep already handled via generic ACPI code */ - { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, - { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0x30, { KEY_VOLUMEUP } }, - { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, - { KE_KEY, 0x32, { KEY_MUTE } }, - { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ - { KE_KEY, 0x5d, { KEY_WLAN } }, - { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ - { KE_KEY, 0x82, { KEY_CAMERA } }, - { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, - { KE_KEY, 0x88, { KEY_WLAN } }, - { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, - { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ - { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ - { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, - { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, - { KE_KEY, 0xec, { KEY_CAMERA_UP } }, - { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, - { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, - { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, - { KE_END, 0}, -}; - -struct bios_args { - u32 dev_id; - u32 ctrl_param; -}; - -/* - * eeepc-wmi/ - debugfs root directory - * dev_id - current dev_id - * ctrl_param - current ctrl_param - * devs - call DEVS(dev_id, ctrl_param) and print result - * dsts - call DSTS(dev_id) and print result - */ -struct eeepc_wmi_debug { - struct dentry *root; - u32 dev_id; - u32 ctrl_param; -}; - -struct eeepc_wmi { - bool hotplug_wireless; - - struct input_dev *inputdev; - struct backlight_device *backlight_device; - struct platform_device *platform_device; - - struct led_classdev tpd_led; - int tpd_led_wk; - struct workqueue_struct *led_workqueue; - struct work_struct tpd_led_work; - - struct rfkill *wlan_rfkill; - struct rfkill *bluetooth_rfkill; - struct rfkill *wimax_rfkill; - struct rfkill *wwan3g_rfkill; - - struct hotplug_slot *hotplug_slot; - struct mutex hotplug_lock; - struct mutex wmi_lock; - struct workqueue_struct *hotplug_workqueue; - struct work_struct hotplug_work; - - struct eeepc_wmi_debug debug; -}; - -static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) -{ - int err; - - eeepc->inputdev = input_allocate_device(); - if (!eeepc->inputdev) - return -ENOMEM; - - eeepc->inputdev->name = "Eee PC WMI hotkeys"; - eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; - eeepc->inputdev->id.bustype = BUS_HOST; - eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; - - err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); - if (err) - goto err_free_dev; - - err = input_register_device(eeepc->inputdev); - if (err) - goto err_free_keymap; - - return 0; - -err_free_keymap: - sparse_keymap_free(eeepc->inputdev); -err_free_dev: - input_free_device(eeepc->inputdev); - return err; -} - -static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) -{ - if (eeepc->inputdev) { - sparse_keymap_free(eeepc->inputdev); - input_unregister_device(eeepc->inputdev); - } - - eeepc->inputdev = NULL; -} - -static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) -{ - struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - acpi_status status; - u32 tmp; - - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, - 1, EEEPC_WMI_METHODID_DSTS, - &input, &output); - - if (ACPI_FAILURE(status)) - return status; - - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32)obj->integer.value; - else - tmp = 0; - - if (retval) - *retval = tmp; - - kfree(obj); - - return status; - -} - -static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, - u32 *retval) -{ - struct bios_args args = { - .dev_id = dev_id, - .ctrl_param = ctrl_param, - }; - struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; - acpi_status status; - - if (!retval) { - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, - EEEPC_WMI_METHODID_DEVS, - &input, NULL); - } else { - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - u32 tmp; - - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, - EEEPC_WMI_METHODID_DEVS, - &input, &output); - - if (ACPI_FAILURE(status)) - return status; - - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32)obj->integer.value; - else - tmp = 0; - - *retval = tmp; - - kfree(obj); - } - - return status; -} - -/* Helper for special devices with magic return codes */ -static int eeepc_wmi_get_devstate_bits(u32 dev_id, u32 mask) -{ - u32 retval = 0; - acpi_status status; - - status = eeepc_wmi_get_devstate(dev_id, &retval); - - if (ACPI_FAILURE(status)) - return -EINVAL; - - if (!(retval & EEEPC_WMI_DSTS_PRESENCE_BIT)) - return -ENODEV; - - return retval & mask; -} - -static int eeepc_wmi_get_devstate_simple(u32 dev_id) -{ - return eeepc_wmi_get_devstate_bits(dev_id, EEEPC_WMI_DSTS_STATUS_BIT); -} - -/* - * LEDs - */ -/* - * These functions actually update the LED's, and are called from a - * workqueue. By doing this as separate work rather than when the LED - * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a - * potentially bad time, such as a timer interrupt. - */ -static void tpd_led_update(struct work_struct *work) -{ - int ctrl_param; - struct eeepc_wmi *eeepc; - - eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); - - ctrl_param = eeepc->tpd_led_wk; - eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); -} - -static void tpd_led_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - struct eeepc_wmi *eeepc; - - eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); - - eeepc->tpd_led_wk = !!value; - queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); -} - -static int read_tpd_led_state(struct eeepc_wmi *eeepc) -{ - return eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_TOUCHPAD_LED); -} - -static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) -{ - struct eeepc_wmi *eeepc; - - eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); - - return read_tpd_led_state(eeepc); -} - -static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) -{ - int rv; - - if (read_tpd_led_state(eeepc) < 0) - return 0; - - eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); - if (!eeepc->led_workqueue) - return -ENOMEM; - INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); - - eeepc->tpd_led.name = "eeepc::touchpad"; - eeepc->tpd_led.brightness_set = tpd_led_set; - eeepc->tpd_led.brightness_get = tpd_led_get; - eeepc->tpd_led.max_brightness = 1; - - rv = led_classdev_register(&eeepc->platform_device->dev, - &eeepc->tpd_led); - if (rv) { - destroy_workqueue(eeepc->led_workqueue); - return rv; - } - - return 0; -} - -static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) -{ - if (eeepc->tpd_led.dev) - led_classdev_unregister(&eeepc->tpd_led); - if (eeepc->led_workqueue) - destroy_workqueue(eeepc->led_workqueue); -} - -/* - * PCI hotplug (for wlan rfkill) - */ -static bool eeepc_wlan_rfkill_blocked(struct eeepc_wmi *eeepc) -{ - int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); - - if (result < 0) - return false; - return !result; -} - -static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) -{ - struct pci_dev *dev; - struct pci_bus *bus; - bool blocked; - bool absent; - u32 l; - - mutex_lock(&eeepc->wmi_lock); - blocked = eeepc_wlan_rfkill_blocked(eeepc); - mutex_unlock(&eeepc->wmi_lock); - - mutex_lock(&eeepc->hotplug_lock); - - if (eeepc->wlan_rfkill) - rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); - - if (eeepc->hotplug_slot) { - bus = pci_find_bus(0, 1); - if (!bus) { - pr_warning("Unable to find PCI bus 1?\n"); - goto out_unlock; - } - - if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { - pr_err("Unable to read PCI config space?\n"); - goto out_unlock; - } - absent = (l == 0xffffffff); - - if (blocked != absent) { - pr_warning("BIOS says wireless lan is %s, " - "but the pci device is %s\n", - blocked ? "blocked" : "unblocked", - absent ? "absent" : "present"); - pr_warning("skipped wireless hotplug as probably " - "inappropriate for this model\n"); - goto out_unlock; - } - - if (!blocked) { - dev = pci_get_slot(bus, 0); - if (dev) { - /* Device already present */ - pci_dev_put(dev); - goto out_unlock; - } - dev = pci_scan_single_device(bus, 0); - if (dev) { - pci_bus_assign_resources(bus); - if (pci_bus_add_device(dev)) - pr_err("Unable to hotplug wifi\n"); - } - } else { - dev = pci_get_slot(bus, 0); - if (dev) { - pci_remove_bus_device(dev); - pci_dev_put(dev); - } - } - } - -out_unlock: - mutex_unlock(&eeepc->hotplug_lock); -} - -static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) -{ - struct eeepc_wmi *eeepc = data; - - if (event != ACPI_NOTIFY_BUS_CHECK) - return; - - /* - * We can't call directly eeepc_rfkill_hotplug because most - * of the time WMBC is still being executed and not reetrant. - * There is currently no way to tell ACPICA that we want this - * method to be serialized, we schedule a eeepc_rfkill_hotplug - * call later, in a safer context. - */ - queue_work(eeepc->hotplug_workqueue, &eeepc->hotplug_work); -} - -static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, - char *node) -{ - acpi_status status; - acpi_handle handle; - - status = acpi_get_handle(NULL, node, &handle); - - if (ACPI_SUCCESS(status)) { - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - eeepc_rfkill_notify, - eeepc); - if (ACPI_FAILURE(status)) - pr_warning("Failed to register notify on %s\n", node); - } else - return -ENODEV; - - return 0; -} - -static void eeepc_unregister_rfkill_notifier(struct eeepc_wmi *eeepc, - char *node) -{ - acpi_status status = AE_OK; - acpi_handle handle; - - status = acpi_get_handle(NULL, node, &handle); - - if (ACPI_SUCCESS(status)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - eeepc_rfkill_notify); - if (ACPI_FAILURE(status)) - pr_err("Error removing rfkill notify handler %s\n", - node); - } -} - -static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, - u8 *value) -{ - int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); - - if (result < 0) - return result; - - *value = !!result; - return 0; -} - -static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) -{ - kfree(hotplug_slot->info); - kfree(hotplug_slot); -} - -static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { - .owner = THIS_MODULE, - .get_adapter_status = eeepc_get_adapter_status, - .get_power_status = eeepc_get_adapter_status, -}; - -static void eeepc_hotplug_work(struct work_struct *work) -{ - struct eeepc_wmi *eeepc; - - eeepc = container_of(work, struct eeepc_wmi, hotplug_work); - eeepc_rfkill_hotplug(eeepc); -} - -static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) -{ - int ret = -ENOMEM; - struct pci_bus *bus = pci_find_bus(0, 1); - - if (!bus) { - pr_err("Unable to find wifi PCI bus\n"); - return -ENODEV; - } - - eeepc->hotplug_workqueue = - create_singlethread_workqueue("hotplug_workqueue"); - if (!eeepc->hotplug_workqueue) - goto error_workqueue; - - INIT_WORK(&eeepc->hotplug_work, eeepc_hotplug_work); - - eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!eeepc->hotplug_slot) - goto error_slot; - - eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), - GFP_KERNEL); - if (!eeepc->hotplug_slot->info) - goto error_info; - - eeepc->hotplug_slot->private = eeepc; - eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; - eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; - eeepc_get_adapter_status(eeepc->hotplug_slot, - &eeepc->hotplug_slot->info->adapter_status); - - ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); - if (ret) { - pr_err("Unable to register hotplug slot - %d\n", ret); - goto error_register; - } - - return 0; - -error_register: - kfree(eeepc->hotplug_slot->info); -error_info: - kfree(eeepc->hotplug_slot); - eeepc->hotplug_slot = NULL; -error_slot: - destroy_workqueue(eeepc->hotplug_workqueue); -error_workqueue: - return ret; -} - -/* - * Rfkill devices - */ -static int eeepc_rfkill_set(void *data, bool blocked) -{ - int dev_id = (unsigned long)data; - u32 ctrl_param = !blocked; - acpi_status status; - - status = eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); - - if (ACPI_FAILURE(status)) - return -EIO; - - return 0; -} - -static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) -{ - int dev_id = (unsigned long)data; - int result; - - result = eeepc_wmi_get_devstate_simple(dev_id); - - if (result < 0) - return ; - - rfkill_set_sw_state(rfkill, !result); -} - -static int eeepc_rfkill_wlan_set(void *data, bool blocked) -{ - struct eeepc_wmi *eeepc = data; - int ret; - - /* - * This handler is enabled only if hotplug is enabled. - * In this case, the eeepc_wmi_set_devstate() will - * trigger a wmi notification and we need to wait - * this call to finish before being able to call - * any wmi method - */ - mutex_lock(&eeepc->wmi_lock); - ret = eeepc_rfkill_set((void *)(long)EEEPC_WMI_DEVID_WLAN, blocked); - mutex_unlock(&eeepc->wmi_lock); - return ret; -} - -static void eeepc_rfkill_wlan_query(struct rfkill *rfkill, void *data) -{ - eeepc_rfkill_query(rfkill, (void *)(long)EEEPC_WMI_DEVID_WLAN); -} - -static const struct rfkill_ops eeepc_rfkill_wlan_ops = { - .set_block = eeepc_rfkill_wlan_set, - .query = eeepc_rfkill_wlan_query, -}; - -static const struct rfkill_ops eeepc_rfkill_ops = { - .set_block = eeepc_rfkill_set, - .query = eeepc_rfkill_query, -}; - -static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, - struct rfkill **rfkill, - const char *name, - enum rfkill_type type, int dev_id) -{ - int result = eeepc_wmi_get_devstate_simple(dev_id); - - if (result < 0) - return result; - - if (dev_id == EEEPC_WMI_DEVID_WLAN && eeepc->hotplug_wireless) - *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, - &eeepc_rfkill_wlan_ops, eeepc); - else - *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, - &eeepc_rfkill_ops, (void *)(long)dev_id); - - if (!*rfkill) - return -EINVAL; - - rfkill_init_sw_state(*rfkill, !result); - result = rfkill_register(*rfkill); - if (result) { - rfkill_destroy(*rfkill); - *rfkill = NULL; - return result; - } - return 0; -} - -static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) -{ - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); - if (eeepc->wlan_rfkill) { - rfkill_unregister(eeepc->wlan_rfkill); - rfkill_destroy(eeepc->wlan_rfkill); - eeepc->wlan_rfkill = NULL; - } - /* - * Refresh pci hotplug in case the rfkill state was changed after - * eeepc_unregister_rfkill_notifier() - */ - eeepc_rfkill_hotplug(eeepc); - if (eeepc->hotplug_slot) - pci_hp_deregister(eeepc->hotplug_slot); - if (eeepc->hotplug_workqueue) - destroy_workqueue(eeepc->hotplug_workqueue); - - if (eeepc->bluetooth_rfkill) { - rfkill_unregister(eeepc->bluetooth_rfkill); - rfkill_destroy(eeepc->bluetooth_rfkill); - eeepc->bluetooth_rfkill = NULL; - } - if (eeepc->wimax_rfkill) { - rfkill_unregister(eeepc->wimax_rfkill); - rfkill_destroy(eeepc->wimax_rfkill); - eeepc->wimax_rfkill = NULL; - } - if (eeepc->wwan3g_rfkill) { - rfkill_unregister(eeepc->wwan3g_rfkill); - rfkill_destroy(eeepc->wwan3g_rfkill); - eeepc->wwan3g_rfkill = NULL; - } -} - -static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) -{ - int result = 0; - - mutex_init(&eeepc->hotplug_lock); - mutex_init(&eeepc->wmi_lock); - - result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, - "eeepc-wlan", RFKILL_TYPE_WLAN, - EEEPC_WMI_DEVID_WLAN); - - if (result && result != -ENODEV) - goto exit; - - result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, - "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, - EEEPC_WMI_DEVID_BLUETOOTH); - - if (result && result != -ENODEV) - goto exit; - - result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill, - "eeepc-wimax", RFKILL_TYPE_WIMAX, - EEEPC_WMI_DEVID_WIMAX); - - if (result && result != -ENODEV) - goto exit; - - result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, - "eeepc-wwan3g", RFKILL_TYPE_WWAN, - EEEPC_WMI_DEVID_WWAN3G); - - if (result && result != -ENODEV) - goto exit; - - if (!eeepc->hotplug_wireless) - goto exit; - - result = eeepc_setup_pci_hotplug(eeepc); - /* - * If we get -EBUSY then something else is handling the PCI hotplug - - * don't fail in this case - */ - if (result == -EBUSY) - result = 0; - - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); - /* - * Refresh pci hotplug in case the rfkill state was changed during - * setup. - */ - eeepc_rfkill_hotplug(eeepc); - -exit: - if (result && result != -ENODEV) - eeepc_wmi_rfkill_exit(eeepc); - - if (result == -ENODEV) - result = 0; - - return result; -} - -/* - * Backlight - */ -static int read_backlight_power(void) -{ - int ret = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BACKLIGHT); - - if (ret < 0) - return ret; - - return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; -} - -static int read_brightness(struct backlight_device *bd) -{ - u32 retval; - acpi_status status; - - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, &retval); - - if (ACPI_FAILURE(status)) - return -EIO; - else - return retval & EEEPC_WMI_DSTS_BRIGHTNESS_MASK; -} - -static int update_bl_status(struct backlight_device *bd) -{ - u32 ctrl_param; - acpi_status status; - int power; - - ctrl_param = bd->props.brightness; - - status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, - ctrl_param, NULL); - - if (ACPI_FAILURE(status)) - return -EIO; - - power = read_backlight_power(); - if (power != -ENODEV && bd->props.power != power) { - ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); - status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, - ctrl_param, NULL); - - if (ACPI_FAILURE(status)) - return -EIO; - } - return 0; -} - -static const struct backlight_ops eeepc_wmi_bl_ops = { - .get_brightness = read_brightness, - .update_status = update_bl_status, -}; - -static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) -{ - struct backlight_device *bd = eeepc->backlight_device; - int old = bd->props.brightness; - int new = old; - - if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) - new = code - NOTIFY_BRNUP_MIN + 1; - else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) - new = code - NOTIFY_BRNDOWN_MIN; - - bd->props.brightness = new; - backlight_update_status(bd); - backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); - - return old; -} - -static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) -{ - struct backlight_device *bd; - struct backlight_properties props; - int max; - int power; - - max = eeepc_wmi_get_devstate_bits(EEEPC_WMI_DEVID_BRIGHTNESS, - EEEPC_WMI_DSTS_MAX_BRIGTH_MASK); - power = read_backlight_power(); - - if (max < 0 && power < 0) { - /* Try to keep the original error */ - if (max == -ENODEV && power == -ENODEV) - return -ENODEV; - if (max != -ENODEV) - return max; - else - return power; - } - if (max == -ENODEV) - max = 0; - if (power == -ENODEV) - power = FB_BLANK_UNBLANK; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = max; - bd = backlight_device_register(EEEPC_WMI_FILE, - &eeepc->platform_device->dev, eeepc, - &eeepc_wmi_bl_ops, &props); - if (IS_ERR(bd)) { - pr_err("Could not register backlight device\n"); - return PTR_ERR(bd); - } - - eeepc->backlight_device = bd; - - bd->props.brightness = read_brightness(bd); - bd->props.power = power; - backlight_update_status(bd); - - return 0; -} - -static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc) -{ - if (eeepc->backlight_device) - backlight_device_unregister(eeepc->backlight_device); - - eeepc->backlight_device = NULL; -} - -static void eeepc_wmi_notify(u32 value, void *context) -{ - struct eeepc_wmi *eeepc = context; - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - acpi_status status; - int code; - int orig_code; - - status = wmi_get_event_data(value, &response); - if (status != AE_OK) { - pr_err("bad event status 0x%x\n", status); - return; - } - - obj = (union acpi_object *)response.pointer; - - if (obj && obj->type == ACPI_TYPE_INTEGER) { - code = obj->integer.value; - orig_code = code; - - if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) - code = NOTIFY_BRNUP_MIN; - else if (code >= NOTIFY_BRNDOWN_MIN && - code <= NOTIFY_BRNDOWN_MAX) - code = NOTIFY_BRNDOWN_MIN; - - if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { - if (!acpi_video_backlight_support()) - eeepc_wmi_backlight_notify(eeepc, orig_code); - } - - if (!sparse_keymap_report_event(eeepc->inputdev, - code, 1, true)) - pr_info("Unknown key %x pressed\n", code); - } - - kfree(obj); -} - -/* - * Sys helpers - */ -static int parse_arg(const char *buf, unsigned long count, int *val) -{ - if (!count) - return 0; - if (sscanf(buf, "%i", val) != 1) - return -EINVAL; - return count; -} - -static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) -{ - acpi_status status; - u32 retval; - int rv, value; - - value = eeepc_wmi_get_devstate_simple(devid); - if (value == -ENODEV) /* Check device presence */ - return value; - - rv = parse_arg(buf, count, &value); - status = eeepc_wmi_set_devstate(devid, value, &retval); - - if (ACPI_FAILURE(status)) - return -EIO; - return rv; -} - -static ssize_t show_sys_wmi(int devid, char *buf) -{ - int value = eeepc_wmi_get_devstate_simple(devid); - - if (value < 0) - return value; - - return sprintf(buf, "%d\n", value); -} - -#define EEEPC_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ - static ssize_t show_##_name(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ - { \ - return show_sys_wmi(_cm, buf); \ - } \ - static ssize_t store_##_name(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ - { \ - return store_sys_wmi(_cm, buf, count); \ - } \ - static struct device_attribute dev_attr_##_name = { \ - .attr = { \ - .name = __stringify(_name), \ - .mode = _mode }, \ - .show = show_##_name, \ - .store = store_##_name, \ - } - -EEEPC_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, EEEPC_WMI_DEVID_TOUCHPAD); -EEEPC_WMI_CREATE_DEVICE_ATTR(camera, 0644, EEEPC_WMI_DEVID_CAMERA); -EEEPC_WMI_CREATE_DEVICE_ATTR(cardr, 0644, EEEPC_WMI_DEVID_CARDREADER); - -static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int value; - struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; - acpi_status status; - - if (!count || sscanf(buf, "%i", &value) != 1) - return -EINVAL; - if (value < 0 || value > 2) - return -EINVAL; - - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, - 1, EEEPC_WMI_METHODID_CFVS, &input, NULL); - - if (ACPI_FAILURE(status)) - return -EIO; - else - return count; -} - -static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); - -static struct attribute *platform_attributes[] = { - &dev_attr_cpufv.attr, - &dev_attr_camera.attr, - &dev_attr_cardr.attr, - &dev_attr_touchpad.attr, - NULL -}; - -static mode_t eeepc_sysfs_is_visible(struct kobject *kobj, - struct attribute *attr, - int idx) -{ - bool supported = true; - int devid = -1; - - if (attr == &dev_attr_camera.attr) - devid = EEEPC_WMI_DEVID_CAMERA; - else if (attr == &dev_attr_cardr.attr) - devid = EEEPC_WMI_DEVID_CARDREADER; - else if (attr == &dev_attr_touchpad.attr) - devid = EEEPC_WMI_DEVID_TOUCHPAD; - - if (devid != -1) - supported = eeepc_wmi_get_devstate_simple(devid) != -ENODEV; - - return supported ? attr->mode : 0; -} - -static struct attribute_group platform_attribute_group = { - .is_visible = eeepc_sysfs_is_visible, - .attrs = platform_attributes -}; - -static void eeepc_wmi_sysfs_exit(struct platform_device *device) -{ - sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); -} - -static int eeepc_wmi_sysfs_init(struct platform_device *device) -{ - return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); -} - -/* - * Platform device - */ -static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) -{ - return eeepc_wmi_sysfs_init(eeepc->platform_device); -} - -static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) -{ - eeepc_wmi_sysfs_exit(eeepc->platform_device); -} - -/* - * debugfs - */ -struct eeepc_wmi_debugfs_node { - struct eeepc_wmi *eeepc; - char *name; - int (*show)(struct seq_file *m, void *data); -}; - -static int show_dsts(struct seq_file *m, void *data) -{ - struct eeepc_wmi *eeepc = m->private; - acpi_status status; - u32 retval = -1; - - status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); - - if (ACPI_FAILURE(status)) - return -EIO; - - seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); - - return 0; -} - -static int show_devs(struct seq_file *m, void *data) -{ - struct eeepc_wmi *eeepc = m->private; - acpi_status status; - u32 retval = -1; - - status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, - eeepc->debug.ctrl_param, &retval); - if (ACPI_FAILURE(status)) - return -EIO; - - seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, - eeepc->debug.ctrl_param, retval); - - return 0; -} - -static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { - { NULL, "devs", show_devs }, - { NULL, "dsts", show_dsts }, -}; - -static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) -{ - struct eeepc_wmi_debugfs_node *node = inode->i_private; - - return single_open(file, node->show, node->eeepc); -} - -static const struct file_operations eeepc_wmi_debugfs_io_ops = { - .owner = THIS_MODULE, - .open = eeepc_wmi_debugfs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) -{ - debugfs_remove_recursive(eeepc->debug.root); -} - -static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) -{ - struct dentry *dent; - int i; - - eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); - if (!eeepc->debug.root) { - pr_err("failed to create debugfs directory"); - goto error_debugfs; - } - - dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, - eeepc->debug.root, &eeepc->debug.dev_id); - if (!dent) - goto error_debugfs; - - dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, - eeepc->debug.root, &eeepc->debug.ctrl_param); - if (!dent) - goto error_debugfs; - - for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { - struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; - - node->eeepc = eeepc; - dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, - eeepc->debug.root, node, - &eeepc_wmi_debugfs_io_ops); - if (!dent) { - pr_err("failed to create debug file: %s\n", node->name); - goto error_debugfs; - } - } - - return 0; - -error_debugfs: - eeepc_wmi_debugfs_exit(eeepc); - return -ENOMEM; -} - -/* - * WMI Driver - */ -static void eeepc_dmi_check(struct eeepc_wmi *eeepc) -{ - const char *model; - - model = dmi_get_system_info(DMI_PRODUCT_NAME); - if (!model) - return; - - /* - * Whitelist for wlan hotplug - * - * Eeepc 1000H needs the current hotplug code to handle - * Fn+F2 correctly. We may add other Eeepc here later, but - * it seems that most of the laptops supported by eeepc-wmi - * don't need to be on this list - */ - if (strcmp(model, "1000H") == 0) { - eeepc->hotplug_wireless = true; - pr_info("wlan hotplug enabled\n"); - } -} - -static int __init eeepc_wmi_add(struct platform_device *pdev) -{ - struct eeepc_wmi *eeepc; - acpi_status status; - int err; - - eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); - if (!eeepc) - return -ENOMEM; - - eeepc->platform_device = pdev; - platform_set_drvdata(eeepc->platform_device, eeepc); - - eeepc->hotplug_wireless = hotplug_wireless; - eeepc_dmi_check(eeepc); - - err = eeepc_wmi_platform_init(eeepc); - if (err) - goto fail_platform; - - err = eeepc_wmi_input_init(eeepc); - if (err) - goto fail_input; - - err = eeepc_wmi_led_init(eeepc); - if (err) - goto fail_leds; - - err = eeepc_wmi_rfkill_init(eeepc); - if (err) - goto fail_rfkill; - - if (!acpi_video_backlight_support()) { - err = eeepc_wmi_backlight_init(eeepc); - if (err && err != -ENODEV) - goto fail_backlight; - } else - pr_info("Backlight controlled by ACPI video driver\n"); - - status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, - eeepc_wmi_notify, eeepc); - if (ACPI_FAILURE(status)) { - pr_err("Unable to register notify handler - %d\n", - status); - err = -ENODEV; - goto fail_wmi_handler; - } - - err = eeepc_wmi_debugfs_init(eeepc); - if (err) - goto fail_debugfs; - - return 0; - -fail_debugfs: - wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); -fail_wmi_handler: - eeepc_wmi_backlight_exit(eeepc); -fail_backlight: - eeepc_wmi_rfkill_exit(eeepc); -fail_rfkill: - eeepc_wmi_led_exit(eeepc); -fail_leds: - eeepc_wmi_input_exit(eeepc); -fail_input: - eeepc_wmi_platform_exit(eeepc); -fail_platform: - kfree(eeepc); - return err; -} - -static int __exit eeepc_wmi_remove(struct platform_device *device) -{ - struct eeepc_wmi *eeepc; - - eeepc = platform_get_drvdata(device); - wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); - eeepc_wmi_backlight_exit(eeepc); - eeepc_wmi_input_exit(eeepc); - eeepc_wmi_led_exit(eeepc); - eeepc_wmi_rfkill_exit(eeepc); - eeepc_wmi_debugfs_exit(eeepc); - eeepc_wmi_platform_exit(eeepc); - - kfree(eeepc); - return 0; -} - -/* - * Platform driver - hibernate/resume callbacks - */ -static int eeepc_hotk_thaw(struct device *device) -{ - struct eeepc_wmi *eeepc = dev_get_drvdata(device); - - if (eeepc->wlan_rfkill) { - bool wlan; - - /* - * Work around bios bug - acpi _PTS turns off the wireless led - * during suspend. Normally it restores it on resume, but - * we should kick it ourselves in case hibernation is aborted. - */ - wlan = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); - eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_WLAN, wlan, NULL); - } - - return 0; -} - -static int eeepc_hotk_restore(struct device *device) -{ - struct eeepc_wmi *eeepc = dev_get_drvdata(device); - int bl; - - /* Refresh both wlan rfkill state and pci hotplug */ - if (eeepc->wlan_rfkill) - eeepc_rfkill_hotplug(eeepc); - - if (eeepc->bluetooth_rfkill) { - bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BLUETOOTH); - rfkill_set_sw_state(eeepc->bluetooth_rfkill, bl); - } - if (eeepc->wimax_rfkill) { - bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WIMAX); - rfkill_set_sw_state(eeepc->wimax_rfkill, bl); - } - if (eeepc->wwan3g_rfkill) { - bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WWAN3G); - rfkill_set_sw_state(eeepc->wwan3g_rfkill, bl); - } - - return 0; -} - -static const struct dev_pm_ops eeepc_pm_ops = { - .thaw = eeepc_hotk_thaw, - .restore = eeepc_hotk_restore, -}; - -static struct platform_driver platform_driver = { - .remove = __exit_p(eeepc_wmi_remove), - .driver = { - .name = EEEPC_WMI_FILE, - .owner = THIS_MODULE, - .pm = &eeepc_pm_ops, - }, -}; - -static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, - void *context, void **retval) -{ - pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); - *(bool *)context = true; - return AE_CTRL_TERMINATE; -} - -static int __init eeepc_wmi_check_atkd(void) -{ - acpi_status status; - bool found = false; - - status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device, - &found, NULL); - - if (ACPI_FAILURE(status) || !found) - return 0; - return -1; -} - -static int __init eeepc_wmi_probe(struct platform_device *pdev) -{ - if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || - !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { - pr_warning("No known WMI GUID found\n"); - return -ENODEV; - } - - if (eeepc_wmi_check_atkd()) { - pr_warning("WMI device present, but legacy ATKD device is also " - "present and enabled."); - pr_warning("You probably booted with acpi_osi=\"Linux\" or " - "acpi_osi=\"!Windows 2009\""); - pr_warning("Can't load eeepc-wmi, use default acpi_osi " - "(preferred) or eeepc-laptop"); - return -ENODEV; - } - - return eeepc_wmi_add(pdev); -} - -static struct platform_device *platform_device; - -static int __init eeepc_wmi_init(void) -{ - platform_device = platform_create_bundle(&platform_driver, - eeepc_wmi_probe, - NULL, 0, NULL, 0); - if (IS_ERR(platform_device)) - return PTR_ERR(platform_device); - return 0; -} - -static void __exit eeepc_wmi_exit(void) -{ - platform_device_unregister(platform_device); - platform_driver_unregister(&platform_driver); -} - -module_init(eeepc_wmi_init); -module_exit(eeepc_wmi_exit); -- cgit v1.2.2 From e12e6d94db24e9050821965aa75c95e8d2c65f10 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:31 +0100 Subject: eeepc-wmi: asus generic asus-wmi.ko module New Asus notebooks are using a WMI device similar to the one used in Eee PCs. Since we don't want to load eeepc-wmi module on Asus notebooks, and we want to keep the eeepc-wmi module for backward compatibility, this patch introduce a new module, named asus-wmi, that will be used by eeepc-wmi and the new Asus Notebook WMI Driver. eeepc-wmi's input device strings (device name and phys) are kept, but rfkill and led names are changed (s/eeepc/asus/). This should not break anything since rfkill are used by type or index, not by name, and the eeepc::touchpad led wasn't working correctly before 2.6.39 anyway. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 24 +- drivers/platform/x86/Makefile | 3 +- drivers/platform/x86/asus-wmi.c | 924 ++++++++++++++++++--------------------- drivers/platform/x86/asus-wmi.h | 58 +++ drivers/platform/x86/eeepc-wmi.c | 162 +++++++ 5 files changed, 677 insertions(+), 494 deletions(-) create mode 100644 drivers/platform/x86/asus-wmi.h create mode 100644 drivers/platform/x86/eeepc-wmi.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b039d6a93f17..7fde7ba01ab0 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -451,10 +451,11 @@ config EEEPC_LAPTOP Bluetooth, backlight and allows powering on/off some other devices. - If you have an Eee PC laptop, say Y or M here. + If you have an Eee PC laptop, say Y or M here. If this driver + doesn't work on your Eee PC, try eeepc-wmi instead. -config EEEPC_WMI - tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)" +config ASUS_WMI + tristate "ASUS WMI Driver (EXPERIMENTAL)" depends on ACPI_WMI depends on INPUT depends on EXPERIMENTAL @@ -464,10 +465,23 @@ config EEEPC_WMI select LEDS_CLASS select NEW_LEDS ---help--- - Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. + Say Y here if you have a WMI aware Asus laptop (like Eee PCs). To compile this driver as a module, choose M here: the module will - be called eeepc-wmi. + be called asus-wmi. + +config EEEPC_WMI + tristate "Eee PC WMI Driver (EXPERIMENTAL)" + depends on ASUS_WMI + ---help--- + This is a driver for newer Eee PC laptops. It adds extra features + like wireless radio and bluetooth control, leds, hotkeys, backlight... + + For more informations, see + + + If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M + here. config ACPI_WMI tristate "WMI" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 443257617b20..f9c83f48c922 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -3,8 +3,9 @@ # x86 Platform-Specific Drivers # obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o +obj-$(CONFIG_ASUS_WMI) += asus-wmi.o obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o -obj-$(CONFIG_EEEPC_WMI) += asus-wmi.o eeepc-wmi.o +obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d3997757e790..35e6bb6c266d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1,5 +1,5 @@ /* - * Eee PC WMI hotkey driver + * Asus PC WMI hotkey driver * * Copyright(C) 2010 Intel Corporation. * Copyright(C) 2010 Corentin Chary @@ -42,23 +42,23 @@ #include #include #include -#include #include #include -#define EEEPC_WMI_FILE "eeepc-wmi" +#include "asus-wmi.h" -MODULE_AUTHOR("Yong Wang "); -MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); +MODULE_AUTHOR("Corentin Chary , " + "Yong Wang "); +MODULE_DESCRIPTION("Asus Generic WMI Driver"); MODULE_LICENSE("GPL"); -#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ +#define to_platform_driver(drv) \ + (container_of((drv), struct platform_driver, driver)) -#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" -#define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" +#define to_asus_wmi_driver(pdrv) \ + (container_of((pdrv), struct asus_wmi_driver, platform_driver)) -MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); -MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); +#define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" #define NOTIFY_BRNUP_MIN 0x11 #define NOTIFY_BRNUP_MAX 0x1f @@ -66,90 +66,55 @@ MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); #define NOTIFY_BRNDOWN_MAX 0x2e /* WMI Methods */ -#define EEEPC_WMI_METHODID_DSTS 0x53544344 -#define EEEPC_WMI_METHODID_DEVS 0x53564544 -#define EEEPC_WMI_METHODID_CFVS 0x53564643 +#define ASUS_WMI_METHODID_DSTS 0x53544344 +#define ASUS_WMI_METHODID_DEVS 0x53564544 +#define ASUS_WMI_METHODID_CFVS 0x53564643 /* Wireless */ -#define EEEPC_WMI_DEVID_WLAN 0x00010011 -#define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 -#define EEEPC_WMI_DEVID_WIMAX 0x00010017 -#define EEEPC_WMI_DEVID_WWAN3G 0x00010019 +#define ASUS_WMI_DEVID_WLAN 0x00010011 +#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 +#define ASUS_WMI_DEVID_WIMAX 0x00010017 +#define ASUS_WMI_DEVID_WWAN3G 0x00010019 /* Backlight and Brightness */ -#define EEEPC_WMI_DEVID_BACKLIGHT 0x00050011 -#define EEEPC_WMI_DEVID_BRIGHTNESS 0x00050012 +#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 +#define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 /* Misc */ -#define EEEPC_WMI_DEVID_CAMERA 0x00060013 +#define ASUS_WMI_DEVID_CAMERA 0x00060013 /* Storage */ -#define EEEPC_WMI_DEVID_CARDREADER 0x00080013 +#define ASUS_WMI_DEVID_CARDREADER 0x00080013 /* Input */ -#define EEEPC_WMI_DEVID_TOUCHPAD 0x00100011 -#define EEEPC_WMI_DEVID_TOUCHPAD_LED 0x00100012 +#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 +#define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 /* DSTS masks */ -#define EEEPC_WMI_DSTS_STATUS_BIT 0x00000001 -#define EEEPC_WMI_DSTS_PRESENCE_BIT 0x00010000 -#define EEEPC_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF -#define EEEPC_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 - -static bool hotplug_wireless; - -module_param(hotplug_wireless, bool, 0444); -MODULE_PARM_DESC(hotplug_wireless, - "Enable hotplug for wireless device. " - "If your laptop needs that, please report to " - "acpi4asus-user@lists.sourceforge.net."); - -static const struct key_entry eeepc_wmi_keymap[] = { - /* Sleep already handled via generic ACPI code */ - { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, - { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0x30, { KEY_VOLUMEUP } }, - { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, - { KE_KEY, 0x32, { KEY_MUTE } }, - { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ - { KE_KEY, 0x5d, { KEY_WLAN } }, - { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ - { KE_KEY, 0x82, { KEY_CAMERA } }, - { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, - { KE_KEY, 0x88, { KEY_WLAN } }, - { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, - { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ - { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ - { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, - { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, - { KE_KEY, 0xec, { KEY_CAMERA_UP } }, - { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, - { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, - { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, - { KE_END, 0}, -}; +#define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 +#define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000 +#define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF +#define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 struct bios_args { - u32 dev_id; - u32 ctrl_param; + u32 dev_id; + u32 ctrl_param; }; /* - * eeepc-wmi/ - debugfs root directory + * / - debugfs root directory * dev_id - current dev_id * ctrl_param - current ctrl_param * devs - call DEVS(dev_id, ctrl_param) and print result * dsts - call DSTS(dev_id) and print result */ -struct eeepc_wmi_debug { +struct asus_wmi_debug { struct dentry *root; u32 dev_id; u32 ctrl_param; }; -struct eeepc_wmi { - bool hotplug_wireless; - +struct asus_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; struct platform_device *platform_device; @@ -170,59 +135,61 @@ struct eeepc_wmi { struct workqueue_struct *hotplug_workqueue; struct work_struct hotplug_work; - struct eeepc_wmi_debug debug; + struct asus_wmi_debug debug; + + struct asus_wmi_driver *driver; }; -static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) +static int asus_wmi_input_init(struct asus_wmi *asus) { int err; - eeepc->inputdev = input_allocate_device(); - if (!eeepc->inputdev) + asus->inputdev = input_allocate_device(); + if (!asus->inputdev) return -ENOMEM; - eeepc->inputdev->name = "Eee PC WMI hotkeys"; - eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; - eeepc->inputdev->id.bustype = BUS_HOST; - eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; + asus->inputdev->name = asus->driver->input_phys; + asus->inputdev->phys = asus->driver->input_name; + asus->inputdev->id.bustype = BUS_HOST; + asus->inputdev->dev.parent = &asus->platform_device->dev; - err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); + err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); if (err) goto err_free_dev; - err = input_register_device(eeepc->inputdev); + err = input_register_device(asus->inputdev); if (err) goto err_free_keymap; return 0; err_free_keymap: - sparse_keymap_free(eeepc->inputdev); + sparse_keymap_free(asus->inputdev); err_free_dev: - input_free_device(eeepc->inputdev); + input_free_device(asus->inputdev); return err; } -static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) +static void asus_wmi_input_exit(struct asus_wmi *asus) { - if (eeepc->inputdev) { - sparse_keymap_free(eeepc->inputdev); - input_unregister_device(eeepc->inputdev); + if (asus->inputdev) { + sparse_keymap_free(asus->inputdev); + input_unregister_device(asus->inputdev); } - eeepc->inputdev = NULL; + asus->inputdev = NULL; } -static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) +static acpi_status asus_wmi_get_devstate(u32 dev_id, u32 *retval) { - struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; + struct acpi_buffer input = { (acpi_size) sizeof(u32), &dev_id }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_status status; u32 tmp; - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, - 1, EEEPC_WMI_METHODID_DSTS, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, + 1, ASUS_WMI_METHODID_DSTS, &input, &output); if (ACPI_FAILURE(status)) @@ -230,7 +197,7 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) obj = (union acpi_object *)output.pointer; if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32)obj->integer.value; + tmp = (u32) obj->integer.value; else tmp = 0; @@ -243,27 +210,27 @@ static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) } -static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, - u32 *retval) +static acpi_status asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, + u32 *retval) { struct bios_args args = { .dev_id = dev_id, .ctrl_param = ctrl_param, }; - struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; acpi_status status; if (!retval) { - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, - EEEPC_WMI_METHODID_DEVS, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, + ASUS_WMI_METHODID_DEVS, &input, NULL); } else { struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; u32 tmp; - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, - EEEPC_WMI_METHODID_DEVS, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, + ASUS_WMI_METHODID_DEVS, &input, &output); if (ACPI_FAILURE(status)) @@ -271,7 +238,7 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, obj = (union acpi_object *)output.pointer; if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32)obj->integer.value; + tmp = (u32) obj->integer.value; else tmp = 0; @@ -284,25 +251,25 @@ static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, } /* Helper for special devices with magic return codes */ -static int eeepc_wmi_get_devstate_bits(u32 dev_id, u32 mask) +static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) { u32 retval = 0; acpi_status status; - status = eeepc_wmi_get_devstate(dev_id, &retval); + status = asus_wmi_get_devstate(dev_id, &retval); if (ACPI_FAILURE(status)) return -EINVAL; - if (!(retval & EEEPC_WMI_DSTS_PRESENCE_BIT)) + if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) return -ENODEV; return retval & mask; } -static int eeepc_wmi_get_devstate_simple(u32 dev_id) +static int asus_wmi_get_devstate_simple(u32 dev_id) { - return eeepc_wmi_get_devstate_bits(dev_id, EEEPC_WMI_DSTS_STATUS_BIT); + return asus_wmi_get_devstate_bits(dev_id, ASUS_WMI_DSTS_STATUS_BIT); } /* @@ -311,93 +278,92 @@ static int eeepc_wmi_get_devstate_simple(u32 dev_id) /* * These functions actually update the LED's, and are called from a * workqueue. By doing this as separate work rather than when the LED - * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a + * subsystem asks, we avoid messing with the Asus ACPI stuff during a * potentially bad time, such as a timer interrupt. */ static void tpd_led_update(struct work_struct *work) { int ctrl_param; - struct eeepc_wmi *eeepc; + struct asus_wmi *asus; - eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); + asus = container_of(work, struct asus_wmi, tpd_led_work); - ctrl_param = eeepc->tpd_led_wk; - eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); + ctrl_param = asus->tpd_led_wk; + asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); } static void tpd_led_set(struct led_classdev *led_cdev, enum led_brightness value) { - struct eeepc_wmi *eeepc; + struct asus_wmi *asus; - eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); + asus = container_of(led_cdev, struct asus_wmi, tpd_led); - eeepc->tpd_led_wk = !!value; - queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); + asus->tpd_led_wk = !!value; + queue_work(asus->led_workqueue, &asus->tpd_led_work); } -static int read_tpd_led_state(struct eeepc_wmi *eeepc) +static int read_tpd_led_state(struct asus_wmi *asus) { - return eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_TOUCHPAD_LED); + return asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_TOUCHPAD_LED); } static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) { - struct eeepc_wmi *eeepc; + struct asus_wmi *asus; - eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); + asus = container_of(led_cdev, struct asus_wmi, tpd_led); - return read_tpd_led_state(eeepc); + return read_tpd_led_state(asus); } -static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) +static int asus_wmi_led_init(struct asus_wmi *asus) { int rv; - if (read_tpd_led_state(eeepc) < 0) + if (read_tpd_led_state(asus) < 0) return 0; - eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); - if (!eeepc->led_workqueue) + asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); + if (!asus->led_workqueue) return -ENOMEM; - INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); + INIT_WORK(&asus->tpd_led_work, tpd_led_update); - eeepc->tpd_led.name = "eeepc::touchpad"; - eeepc->tpd_led.brightness_set = tpd_led_set; - eeepc->tpd_led.brightness_get = tpd_led_get; - eeepc->tpd_led.max_brightness = 1; + asus->tpd_led.name = "asus::touchpad"; + asus->tpd_led.brightness_set = tpd_led_set; + asus->tpd_led.brightness_get = tpd_led_get; + asus->tpd_led.max_brightness = 1; - rv = led_classdev_register(&eeepc->platform_device->dev, - &eeepc->tpd_led); + rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led); if (rv) { - destroy_workqueue(eeepc->led_workqueue); + destroy_workqueue(asus->led_workqueue); return rv; } return 0; } -static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) +static void asus_wmi_led_exit(struct asus_wmi *asus) { - if (eeepc->tpd_led.dev) - led_classdev_unregister(&eeepc->tpd_led); - if (eeepc->led_workqueue) - destroy_workqueue(eeepc->led_workqueue); + if (asus->tpd_led.dev) + led_classdev_unregister(&asus->tpd_led); + if (asus->led_workqueue) + destroy_workqueue(asus->led_workqueue); } /* * PCI hotplug (for wlan rfkill) */ -static bool eeepc_wlan_rfkill_blocked(struct eeepc_wmi *eeepc) +static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) { - int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); + int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); if (result < 0) return false; return !result; } -static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) +static void asus_rfkill_hotplug(struct asus_wmi *asus) { struct pci_dev *dev; struct pci_bus *bus; @@ -405,16 +371,16 @@ static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) bool absent; u32 l; - mutex_lock(&eeepc->wmi_lock); - blocked = eeepc_wlan_rfkill_blocked(eeepc); - mutex_unlock(&eeepc->wmi_lock); + mutex_lock(&asus->wmi_lock); + blocked = asus_wlan_rfkill_blocked(asus); + mutex_unlock(&asus->wmi_lock); - mutex_lock(&eeepc->hotplug_lock); + mutex_lock(&asus->hotplug_lock); - if (eeepc->wlan_rfkill) - rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); + if (asus->wlan_rfkill) + rfkill_set_sw_state(asus->wlan_rfkill, blocked); - if (eeepc->hotplug_slot) { + if (asus->hotplug_slot) { bus = pci_find_bus(0, 1); if (!bus) { pr_warning("Unable to find PCI bus 1?\n"); @@ -429,11 +395,11 @@ static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) if (blocked != absent) { pr_warning("BIOS says wireless lan is %s, " - "but the pci device is %s\n", - blocked ? "blocked" : "unblocked", - absent ? "absent" : "present"); + "but the pci device is %s\n", + blocked ? "blocked" : "unblocked", + absent ? "absent" : "present"); pr_warning("skipped wireless hotplug as probably " - "inappropriate for this model\n"); + "inappropriate for this model\n"); goto out_unlock; } @@ -460,28 +426,27 @@ static void eeepc_rfkill_hotplug(struct eeepc_wmi *eeepc) } out_unlock: - mutex_unlock(&eeepc->hotplug_lock); + mutex_unlock(&asus->hotplug_lock); } -static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) +static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data) { - struct eeepc_wmi *eeepc = data; + struct asus_wmi *asus = data; if (event != ACPI_NOTIFY_BUS_CHECK) return; /* - * We can't call directly eeepc_rfkill_hotplug because most + * We can't call directly asus_rfkill_hotplug because most * of the time WMBC is still being executed and not reetrant. * There is currently no way to tell ACPICA that we want this - * method to be serialized, we schedule a eeepc_rfkill_hotplug + * method to be serialized, we schedule a asus_rfkill_hotplug * call later, in a safer context. */ - queue_work(eeepc->hotplug_workqueue, &eeepc->hotplug_work); + queue_work(asus->hotplug_workqueue, &asus->hotplug_work); } -static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, - char *node) +static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node) { acpi_status status; acpi_handle handle; @@ -491,8 +456,7 @@ static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, if (ACPI_SUCCESS(status)) { status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - eeepc_rfkill_notify, - eeepc); + asus_rfkill_notify, asus); if (ACPI_FAILURE(status)) pr_warning("Failed to register notify on %s\n", node); } else @@ -501,8 +465,7 @@ static int eeepc_register_rfkill_notifier(struct eeepc_wmi *eeepc, return 0; } -static void eeepc_unregister_rfkill_notifier(struct eeepc_wmi *eeepc, - char *node) +static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) { acpi_status status = AE_OK; acpi_handle handle; @@ -511,18 +474,18 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_wmi *eeepc, if (ACPI_SUCCESS(status)) { status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - eeepc_rfkill_notify); + ACPI_SYSTEM_NOTIFY, + asus_rfkill_notify); if (ACPI_FAILURE(status)) pr_err("Error removing rfkill notify handler %s\n", - node); + node); } } -static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, - u8 *value) +static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, + u8 *value) { - int result = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); + int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); if (result < 0) return result; @@ -531,27 +494,27 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, return 0; } -static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) +static void asus_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) { kfree(hotplug_slot->info); kfree(hotplug_slot); } -static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { +static struct hotplug_slot_ops asus_hotplug_slot_ops = { .owner = THIS_MODULE, - .get_adapter_status = eeepc_get_adapter_status, - .get_power_status = eeepc_get_adapter_status, + .get_adapter_status = asus_get_adapter_status, + .get_power_status = asus_get_adapter_status, }; -static void eeepc_hotplug_work(struct work_struct *work) +static void asus_hotplug_work(struct work_struct *work) { - struct eeepc_wmi *eeepc; + struct asus_wmi *asus; - eeepc = container_of(work, struct eeepc_wmi, hotplug_work); - eeepc_rfkill_hotplug(eeepc); + asus = container_of(work, struct asus_wmi, hotplug_work); + asus_rfkill_hotplug(asus); } -static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) +static int asus_setup_pci_hotplug(struct asus_wmi *asus) { int ret = -ENOMEM; struct pci_bus *bus = pci_find_bus(0, 1); @@ -561,29 +524,29 @@ static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) return -ENODEV; } - eeepc->hotplug_workqueue = - create_singlethread_workqueue("hotplug_workqueue"); - if (!eeepc->hotplug_workqueue) + asus->hotplug_workqueue = + create_singlethread_workqueue("hotplug_workqueue"); + if (!asus->hotplug_workqueue) goto error_workqueue; - INIT_WORK(&eeepc->hotplug_work, eeepc_hotplug_work); + INIT_WORK(&asus->hotplug_work, asus_hotplug_work); - eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!eeepc->hotplug_slot) + asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!asus->hotplug_slot) goto error_slot; - eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), - GFP_KERNEL); - if (!eeepc->hotplug_slot->info) + asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), + GFP_KERNEL); + if (!asus->hotplug_slot->info) goto error_info; - eeepc->hotplug_slot->private = eeepc; - eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; - eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; - eeepc_get_adapter_status(eeepc->hotplug_slot, - &eeepc->hotplug_slot->info->adapter_status); + asus->hotplug_slot->private = asus; + asus->hotplug_slot->release = &asus_cleanup_pci_hotplug; + asus->hotplug_slot->ops = &asus_hotplug_slot_ops; + asus_get_adapter_status(asus->hotplug_slot, + &asus->hotplug_slot->info->adapter_status); - ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); + ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi"); if (ret) { pr_err("Unable to register hotplug slot - %d\n", ret); goto error_register; @@ -592,12 +555,12 @@ static int eeepc_setup_pci_hotplug(struct eeepc_wmi *eeepc) return 0; error_register: - kfree(eeepc->hotplug_slot->info); + kfree(asus->hotplug_slot->info); error_info: - kfree(eeepc->hotplug_slot); - eeepc->hotplug_slot = NULL; + kfree(asus->hotplug_slot); + asus->hotplug_slot = NULL; error_slot: - destroy_workqueue(eeepc->hotplug_workqueue); + destroy_workqueue(asus->hotplug_workqueue); error_workqueue: return ret; } @@ -605,13 +568,13 @@ error_workqueue: /* * Rfkill devices */ -static int eeepc_rfkill_set(void *data, bool blocked) +static int asus_rfkill_set(void *data, bool blocked) { int dev_id = (unsigned long)data; u32 ctrl_param = !blocked; acpi_status status; - status = eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); + status = asus_wmi_set_devstate(dev_id, ctrl_param, NULL); if (ACPI_FAILURE(status)) return -EIO; @@ -619,68 +582,67 @@ static int eeepc_rfkill_set(void *data, bool blocked) return 0; } -static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) +static void asus_rfkill_query(struct rfkill *rfkill, void *data) { int dev_id = (unsigned long)data; int result; - result = eeepc_wmi_get_devstate_simple(dev_id); + result = asus_wmi_get_devstate_simple(dev_id); if (result < 0) - return ; + return; rfkill_set_sw_state(rfkill, !result); } -static int eeepc_rfkill_wlan_set(void *data, bool blocked) +static int asus_rfkill_wlan_set(void *data, bool blocked) { - struct eeepc_wmi *eeepc = data; + struct asus_wmi *asus = data; int ret; /* * This handler is enabled only if hotplug is enabled. - * In this case, the eeepc_wmi_set_devstate() will + * In this case, the asus_wmi_set_devstate() will * trigger a wmi notification and we need to wait * this call to finish before being able to call * any wmi method */ - mutex_lock(&eeepc->wmi_lock); - ret = eeepc_rfkill_set((void *)(long)EEEPC_WMI_DEVID_WLAN, blocked); - mutex_unlock(&eeepc->wmi_lock); + mutex_lock(&asus->wmi_lock); + ret = asus_rfkill_set((void *)(long)ASUS_WMI_DEVID_WLAN, blocked); + mutex_unlock(&asus->wmi_lock); return ret; } -static void eeepc_rfkill_wlan_query(struct rfkill *rfkill, void *data) +static void asus_rfkill_wlan_query(struct rfkill *rfkill, void *data) { - eeepc_rfkill_query(rfkill, (void *)(long)EEEPC_WMI_DEVID_WLAN); + asus_rfkill_query(rfkill, (void *)(long)ASUS_WMI_DEVID_WLAN); } -static const struct rfkill_ops eeepc_rfkill_wlan_ops = { - .set_block = eeepc_rfkill_wlan_set, - .query = eeepc_rfkill_wlan_query, +static const struct rfkill_ops asus_rfkill_wlan_ops = { + .set_block = asus_rfkill_wlan_set, + .query = asus_rfkill_wlan_query, }; -static const struct rfkill_ops eeepc_rfkill_ops = { - .set_block = eeepc_rfkill_set, - .query = eeepc_rfkill_query, +static const struct rfkill_ops asus_rfkill_ops = { + .set_block = asus_rfkill_set, + .query = asus_rfkill_query, }; -static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, - struct rfkill **rfkill, - const char *name, - enum rfkill_type type, int dev_id) +static int asus_new_rfkill(struct asus_wmi *asus, + struct rfkill **rfkill, + const char *name, enum rfkill_type type, int dev_id) { - int result = eeepc_wmi_get_devstate_simple(dev_id); + int result = asus_wmi_get_devstate_simple(dev_id); if (result < 0) return result; - if (dev_id == EEEPC_WMI_DEVID_WLAN && eeepc->hotplug_wireless) - *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, - &eeepc_rfkill_wlan_ops, eeepc); + if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless) + *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, + &asus_rfkill_wlan_ops, asus); else - *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, - &eeepc_rfkill_ops, (void *)(long)dev_id); + *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, + &asus_rfkill_ops, (void *)(long)dev_id); if (!*rfkill) return -EINVAL; @@ -695,82 +657,82 @@ static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, return 0; } -static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) +static void asus_wmi_rfkill_exit(struct asus_wmi *asus) { - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); - eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); - if (eeepc->wlan_rfkill) { - rfkill_unregister(eeepc->wlan_rfkill); - rfkill_destroy(eeepc->wlan_rfkill); - eeepc->wlan_rfkill = NULL; + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); + if (asus->wlan_rfkill) { + rfkill_unregister(asus->wlan_rfkill); + rfkill_destroy(asus->wlan_rfkill); + asus->wlan_rfkill = NULL; } /* * Refresh pci hotplug in case the rfkill state was changed after - * eeepc_unregister_rfkill_notifier() + * asus_unregister_rfkill_notifier() */ - eeepc_rfkill_hotplug(eeepc); - if (eeepc->hotplug_slot) - pci_hp_deregister(eeepc->hotplug_slot); - if (eeepc->hotplug_workqueue) - destroy_workqueue(eeepc->hotplug_workqueue); - - if (eeepc->bluetooth_rfkill) { - rfkill_unregister(eeepc->bluetooth_rfkill); - rfkill_destroy(eeepc->bluetooth_rfkill); - eeepc->bluetooth_rfkill = NULL; + asus_rfkill_hotplug(asus); + if (asus->hotplug_slot) + pci_hp_deregister(asus->hotplug_slot); + if (asus->hotplug_workqueue) + destroy_workqueue(asus->hotplug_workqueue); + + if (asus->bluetooth_rfkill) { + rfkill_unregister(asus->bluetooth_rfkill); + rfkill_destroy(asus->bluetooth_rfkill); + asus->bluetooth_rfkill = NULL; } - if (eeepc->wimax_rfkill) { - rfkill_unregister(eeepc->wimax_rfkill); - rfkill_destroy(eeepc->wimax_rfkill); - eeepc->wimax_rfkill = NULL; + if (asus->wimax_rfkill) { + rfkill_unregister(asus->wimax_rfkill); + rfkill_destroy(asus->wimax_rfkill); + asus->wimax_rfkill = NULL; } - if (eeepc->wwan3g_rfkill) { - rfkill_unregister(eeepc->wwan3g_rfkill); - rfkill_destroy(eeepc->wwan3g_rfkill); - eeepc->wwan3g_rfkill = NULL; + if (asus->wwan3g_rfkill) { + rfkill_unregister(asus->wwan3g_rfkill); + rfkill_destroy(asus->wwan3g_rfkill); + asus->wwan3g_rfkill = NULL; } } -static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) +static int asus_wmi_rfkill_init(struct asus_wmi *asus) { int result = 0; - mutex_init(&eeepc->hotplug_lock); - mutex_init(&eeepc->wmi_lock); + mutex_init(&asus->hotplug_lock); + mutex_init(&asus->wmi_lock); - result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, - "eeepc-wlan", RFKILL_TYPE_WLAN, - EEEPC_WMI_DEVID_WLAN); + result = asus_new_rfkill(asus, &asus->wlan_rfkill, + "asus-wlan", RFKILL_TYPE_WLAN, + ASUS_WMI_DEVID_WLAN); if (result && result != -ENODEV) goto exit; - result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, - "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, - EEEPC_WMI_DEVID_BLUETOOTH); + result = asus_new_rfkill(asus, &asus->bluetooth_rfkill, + "asus-bluetooth", RFKILL_TYPE_BLUETOOTH, + ASUS_WMI_DEVID_BLUETOOTH); if (result && result != -ENODEV) goto exit; - result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill, - "eeepc-wimax", RFKILL_TYPE_WIMAX, - EEEPC_WMI_DEVID_WIMAX); + result = asus_new_rfkill(asus, &asus->wimax_rfkill, + "asus-wimax", RFKILL_TYPE_WIMAX, + ASUS_WMI_DEVID_WIMAX); if (result && result != -ENODEV) goto exit; - result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, - "eeepc-wwan3g", RFKILL_TYPE_WWAN, - EEEPC_WMI_DEVID_WWAN3G); + result = asus_new_rfkill(asus, &asus->wwan3g_rfkill, + "asus-wwan3g", RFKILL_TYPE_WWAN, + ASUS_WMI_DEVID_WWAN3G); if (result && result != -ENODEV) goto exit; - if (!eeepc->hotplug_wireless) + if (!asus->driver->hotplug_wireless) goto exit; - result = eeepc_setup_pci_hotplug(eeepc); + result = asus_setup_pci_hotplug(asus); /* * If we get -EBUSY then something else is handling the PCI hotplug - * don't fail in this case @@ -778,18 +740,18 @@ static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) if (result == -EBUSY) result = 0; - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); - eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); + asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); + asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); + asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); /* * Refresh pci hotplug in case the rfkill state was changed during * setup. */ - eeepc_rfkill_hotplug(eeepc); + asus_rfkill_hotplug(asus); exit: if (result && result != -ENODEV) - eeepc_wmi_rfkill_exit(eeepc); + asus_wmi_rfkill_exit(asus); if (result == -ENODEV) result = 0; @@ -802,7 +764,7 @@ exit: */ static int read_backlight_power(void) { - int ret = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BACKLIGHT); + int ret = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BACKLIGHT); if (ret < 0) return ret; @@ -815,12 +777,12 @@ static int read_brightness(struct backlight_device *bd) u32 retval; acpi_status status; - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, &retval); + status = asus_wmi_get_devstate(ASUS_WMI_DEVID_BRIGHTNESS, &retval); if (ACPI_FAILURE(status)) return -EIO; else - return retval & EEEPC_WMI_DSTS_BRIGHTNESS_MASK; + return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; } static int update_bl_status(struct backlight_device *bd) @@ -831,8 +793,8 @@ static int update_bl_status(struct backlight_device *bd) ctrl_param = bd->props.brightness; - status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BRIGHTNESS, - ctrl_param, NULL); + status = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, + ctrl_param, NULL); if (ACPI_FAILURE(status)) return -EIO; @@ -840,8 +802,8 @@ static int update_bl_status(struct backlight_device *bd) power = read_backlight_power(); if (power != -ENODEV && bd->props.power != power) { ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); - status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, - ctrl_param, NULL); + status = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, + ctrl_param, NULL); if (ACPI_FAILURE(status)) return -EIO; @@ -849,14 +811,14 @@ static int update_bl_status(struct backlight_device *bd) return 0; } -static const struct backlight_ops eeepc_wmi_bl_ops = { +static const struct backlight_ops asus_wmi_bl_ops = { .get_brightness = read_brightness, .update_status = update_bl_status, }; -static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) +static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code) { - struct backlight_device *bd = eeepc->backlight_device; + struct backlight_device *bd = asus->backlight_device; int old = bd->props.brightness; int new = old; @@ -872,15 +834,15 @@ static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) return old; } -static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) +static int asus_wmi_backlight_init(struct asus_wmi *asus) { struct backlight_device *bd; struct backlight_properties props; int max; int power; - max = eeepc_wmi_get_devstate_bits(EEEPC_WMI_DEVID_BRIGHTNESS, - EEEPC_WMI_DSTS_MAX_BRIGTH_MASK); + max = asus_wmi_get_devstate_bits(ASUS_WMI_DEVID_BRIGHTNESS, + ASUS_WMI_DSTS_MAX_BRIGTH_MASK); power = read_backlight_power(); if (max < 0 && power < 0) { @@ -899,15 +861,15 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = max; - bd = backlight_device_register(EEEPC_WMI_FILE, - &eeepc->platform_device->dev, eeepc, - &eeepc_wmi_bl_ops, &props); + bd = backlight_device_register(asus->driver->name, + &asus->platform_device->dev, asus, + &asus_wmi_bl_ops, &props); if (IS_ERR(bd)) { pr_err("Could not register backlight device\n"); return PTR_ERR(bd); } - eeepc->backlight_device = bd; + asus->backlight_device = bd; bd->props.brightness = read_brightness(bd); bd->props.power = power; @@ -916,17 +878,17 @@ static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) return 0; } -static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc) +static void asus_wmi_backlight_exit(struct asus_wmi *asus) { - if (eeepc->backlight_device) - backlight_device_unregister(eeepc->backlight_device); + if (asus->backlight_device) + backlight_device_unregister(asus->backlight_device); - eeepc->backlight_device = NULL; + asus->backlight_device = NULL; } -static void eeepc_wmi_notify(u32 value, void *context) +static void asus_wmi_notify(u32 value, void *context) { - struct eeepc_wmi *eeepc = context; + struct asus_wmi *asus = context; struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_status status; @@ -953,11 +915,10 @@ static void eeepc_wmi_notify(u32 value, void *context) if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { if (!acpi_video_backlight_support()) - eeepc_wmi_backlight_notify(eeepc, orig_code); + asus_wmi_backlight_notify(asus, orig_code); } - if (!sparse_keymap_report_event(eeepc->inputdev, - code, 1, true)) + if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) pr_info("Unknown key %x pressed\n", code); } @@ -982,12 +943,12 @@ static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) u32 retval; int rv, value; - value = eeepc_wmi_get_devstate_simple(devid); - if (value == -ENODEV) /* Check device presence */ + value = asus_wmi_get_devstate_simple(devid); + if (value == -ENODEV) /* Check device presence */ return value; rv = parse_arg(buf, count, &value); - status = eeepc_wmi_set_devstate(devid, value, &retval); + status = asus_wmi_set_devstate(devid, value, &retval); if (ACPI_FAILURE(status)) return -EIO; @@ -996,7 +957,7 @@ static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) static ssize_t show_sys_wmi(int devid, char *buf) { - int value = eeepc_wmi_get_devstate_simple(devid); + int value = asus_wmi_get_devstate_simple(devid); if (value < 0) return value; @@ -1004,7 +965,7 @@ static ssize_t show_sys_wmi(int devid, char *buf) return sprintf(buf, "%d\n", value); } -#define EEEPC_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ +#define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ static ssize_t show_##_name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ @@ -1025,15 +986,15 @@ static ssize_t show_sys_wmi(int devid, char *buf) .store = store_##_name, \ } -EEEPC_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, EEEPC_WMI_DEVID_TOUCHPAD); -EEEPC_WMI_CREATE_DEVICE_ATTR(camera, 0644, EEEPC_WMI_DEVID_CAMERA); -EEEPC_WMI_CREATE_DEVICE_ATTR(cardr, 0644, EEEPC_WMI_DEVID_CARDREADER); +ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); +ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); +ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; - struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; + struct acpi_buffer input = { (acpi_size) sizeof(value), &value }; acpi_status status; if (!count || sscanf(buf, "%i", &value) != 1) @@ -1041,8 +1002,8 @@ static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, if (value < 0 || value > 2) return -EINVAL; - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, - 1, EEEPC_WMI_METHODID_CFVS, &input, NULL); + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, + 1, ASUS_WMI_METHODID_CFVS, &input, NULL); if (ACPI_FAILURE(status)) return -EIO; @@ -1060,37 +1021,36 @@ static struct attribute *platform_attributes[] = { NULL }; -static mode_t eeepc_sysfs_is_visible(struct kobject *kobj, - struct attribute *attr, - int idx) +static mode_t asus_sysfs_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) { bool supported = true; int devid = -1; if (attr == &dev_attr_camera.attr) - devid = EEEPC_WMI_DEVID_CAMERA; + devid = ASUS_WMI_DEVID_CAMERA; else if (attr == &dev_attr_cardr.attr) - devid = EEEPC_WMI_DEVID_CARDREADER; + devid = ASUS_WMI_DEVID_CARDREADER; else if (attr == &dev_attr_touchpad.attr) - devid = EEEPC_WMI_DEVID_TOUCHPAD; + devid = ASUS_WMI_DEVID_TOUCHPAD; if (devid != -1) - supported = eeepc_wmi_get_devstate_simple(devid) != -ENODEV; + supported = asus_wmi_get_devstate_simple(devid) != -ENODEV; return supported ? attr->mode : 0; } static struct attribute_group platform_attribute_group = { - .is_visible = eeepc_sysfs_is_visible, - .attrs = platform_attributes + .is_visible = asus_sysfs_is_visible, + .attrs = platform_attributes }; -static void eeepc_wmi_sysfs_exit(struct platform_device *device) +static void asus_wmi_sysfs_exit(struct platform_device *device) { sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); } -static int eeepc_wmi_sysfs_init(struct platform_device *device) +static int asus_wmi_sysfs_init(struct platform_device *device) { return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); } @@ -1098,111 +1058,111 @@ static int eeepc_wmi_sysfs_init(struct platform_device *device) /* * Platform device */ -static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) +static int __init asus_wmi_platform_init(struct asus_wmi *asus) { - return eeepc_wmi_sysfs_init(eeepc->platform_device); + return asus_wmi_sysfs_init(asus->platform_device); } -static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) +static void asus_wmi_platform_exit(struct asus_wmi *asus) { - eeepc_wmi_sysfs_exit(eeepc->platform_device); + asus_wmi_sysfs_exit(asus->platform_device); } /* * debugfs */ -struct eeepc_wmi_debugfs_node { - struct eeepc_wmi *eeepc; +struct asus_wmi_debugfs_node { + struct asus_wmi *asus; char *name; - int (*show)(struct seq_file *m, void *data); + int (*show) (struct seq_file *m, void *data); }; static int show_dsts(struct seq_file *m, void *data) { - struct eeepc_wmi *eeepc = m->private; + struct asus_wmi *asus = m->private; acpi_status status; u32 retval = -1; - status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); + status = asus_wmi_get_devstate(asus->debug.dev_id, &retval); if (ACPI_FAILURE(status)) return -EIO; - seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); + seq_printf(m, "DSTS(%x) = %x\n", asus->debug.dev_id, retval); return 0; } static int show_devs(struct seq_file *m, void *data) { - struct eeepc_wmi *eeepc = m->private; + struct asus_wmi *asus = m->private; acpi_status status; u32 retval = -1; - status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, - eeepc->debug.ctrl_param, &retval); + status = asus_wmi_set_devstate(asus->debug.dev_id, + asus->debug.ctrl_param, &retval); if (ACPI_FAILURE(status)) return -EIO; - seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, - eeepc->debug.ctrl_param, retval); + seq_printf(m, "DEVS(%x, %x) = %x\n", asus->debug.dev_id, + asus->debug.ctrl_param, retval); return 0; } -static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { - { NULL, "devs", show_devs }, - { NULL, "dsts", show_dsts }, +static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = { + {NULL, "devs", show_devs}, + {NULL, "dsts", show_dsts}, }; -static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) +static int asus_wmi_debugfs_open(struct inode *inode, struct file *file) { - struct eeepc_wmi_debugfs_node *node = inode->i_private; + struct asus_wmi_debugfs_node *node = inode->i_private; - return single_open(file, node->show, node->eeepc); + return single_open(file, node->show, node->asus); } -static const struct file_operations eeepc_wmi_debugfs_io_ops = { +static const struct file_operations asus_wmi_debugfs_io_ops = { .owner = THIS_MODULE, - .open = eeepc_wmi_debugfs_open, + .open = asus_wmi_debugfs_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) +static void asus_wmi_debugfs_exit(struct asus_wmi *asus) { - debugfs_remove_recursive(eeepc->debug.root); + debugfs_remove_recursive(asus->debug.root); } -static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) +static int asus_wmi_debugfs_init(struct asus_wmi *asus) { struct dentry *dent; int i; - eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); - if (!eeepc->debug.root) { + asus->debug.root = debugfs_create_dir(asus->driver->name, NULL); + if (!asus->debug.root) { pr_err("failed to create debugfs directory"); goto error_debugfs; } - dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, - eeepc->debug.root, &eeepc->debug.dev_id); + dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, + asus->debug.root, &asus->debug.dev_id); if (!dent) goto error_debugfs; - dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, - eeepc->debug.root, &eeepc->debug.ctrl_param); + dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, + asus->debug.root, &asus->debug.ctrl_param); if (!dent) goto error_debugfs; - for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { - struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; + for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) { + struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i]; - node->eeepc = eeepc; + node->asus = asus; dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, - eeepc->debug.root, node, - &eeepc_wmi_debugfs_io_ops); + asus->debug.root, node, + &asus_wmi_debugfs_io_ops); if (!dent) { pr_err("failed to create debug file: %s\n", node->name); goto error_debugfs; @@ -1212,131 +1172,112 @@ static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) return 0; error_debugfs: - eeepc_wmi_debugfs_exit(eeepc); + asus_wmi_debugfs_exit(asus); return -ENOMEM; } /* * WMI Driver */ -static void eeepc_dmi_check(struct eeepc_wmi *eeepc) +static int asus_wmi_add(struct platform_device *pdev) { - const char *model; - - model = dmi_get_system_info(DMI_PRODUCT_NAME); - if (!model) - return; - - /* - * Whitelist for wlan hotplug - * - * Eeepc 1000H needs the current hotplug code to handle - * Fn+F2 correctly. We may add other Eeepc here later, but - * it seems that most of the laptops supported by eeepc-wmi - * don't need to be on this list - */ - if (strcmp(model, "1000H") == 0) { - eeepc->hotplug_wireless = true; - pr_info("wlan hotplug enabled\n"); - } -} - -static int __init eeepc_wmi_add(struct platform_device *pdev) -{ - struct eeepc_wmi *eeepc; + struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); + struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); + struct asus_wmi *asus; acpi_status status; int err; - eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); - if (!eeepc) + asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL); + if (!asus) return -ENOMEM; - eeepc->platform_device = pdev; - platform_set_drvdata(eeepc->platform_device, eeepc); + asus->driver = wdrv; + asus->platform_device = pdev; + wdrv->platform_device = pdev; + platform_set_drvdata(asus->platform_device, asus); - eeepc->hotplug_wireless = hotplug_wireless; - eeepc_dmi_check(eeepc); + if (wdrv->quirks) + wdrv->quirks(asus->driver); - err = eeepc_wmi_platform_init(eeepc); + err = asus_wmi_platform_init(asus); if (err) goto fail_platform; - err = eeepc_wmi_input_init(eeepc); + err = asus_wmi_input_init(asus); if (err) goto fail_input; - err = eeepc_wmi_led_init(eeepc); + err = asus_wmi_led_init(asus); if (err) goto fail_leds; - err = eeepc_wmi_rfkill_init(eeepc); + err = asus_wmi_rfkill_init(asus); if (err) goto fail_rfkill; if (!acpi_video_backlight_support()) { - err = eeepc_wmi_backlight_init(eeepc); + err = asus_wmi_backlight_init(asus); if (err && err != -ENODEV) goto fail_backlight; } else pr_info("Backlight controlled by ACPI video driver\n"); - status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, - eeepc_wmi_notify, eeepc); + status = wmi_install_notify_handler(asus->driver->event_guid, + asus_wmi_notify, asus); if (ACPI_FAILURE(status)) { - pr_err("Unable to register notify handler - %d\n", - status); + pr_err("Unable to register notify handler - %d\n", status); err = -ENODEV; goto fail_wmi_handler; } - err = eeepc_wmi_debugfs_init(eeepc); + err = asus_wmi_debugfs_init(asus); if (err) goto fail_debugfs; return 0; fail_debugfs: - wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); + wmi_remove_notify_handler(asus->driver->event_guid); fail_wmi_handler: - eeepc_wmi_backlight_exit(eeepc); + asus_wmi_backlight_exit(asus); fail_backlight: - eeepc_wmi_rfkill_exit(eeepc); + asus_wmi_rfkill_exit(asus); fail_rfkill: - eeepc_wmi_led_exit(eeepc); + asus_wmi_led_exit(asus); fail_leds: - eeepc_wmi_input_exit(eeepc); + asus_wmi_input_exit(asus); fail_input: - eeepc_wmi_platform_exit(eeepc); + asus_wmi_platform_exit(asus); fail_platform: - kfree(eeepc); + kfree(asus); return err; } -static int __exit eeepc_wmi_remove(struct platform_device *device) +static int asus_wmi_remove(struct platform_device *device) { - struct eeepc_wmi *eeepc; - - eeepc = platform_get_drvdata(device); - wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); - eeepc_wmi_backlight_exit(eeepc); - eeepc_wmi_input_exit(eeepc); - eeepc_wmi_led_exit(eeepc); - eeepc_wmi_rfkill_exit(eeepc); - eeepc_wmi_debugfs_exit(eeepc); - eeepc_wmi_platform_exit(eeepc); - - kfree(eeepc); + struct asus_wmi *asus; + + asus = platform_get_drvdata(device); + wmi_remove_notify_handler(asus->driver->event_guid); + asus_wmi_backlight_exit(asus); + asus_wmi_input_exit(asus); + asus_wmi_led_exit(asus); + asus_wmi_rfkill_exit(asus); + asus_wmi_debugfs_exit(asus); + asus_wmi_platform_exit(asus); + + kfree(asus); return 0; } /* * Platform driver - hibernate/resume callbacks */ -static int eeepc_hotk_thaw(struct device *device) +static int asus_hotk_thaw(struct device *device) { - struct eeepc_wmi *eeepc = dev_get_drvdata(device); + struct asus_wmi *asus = dev_get_drvdata(device); - if (eeepc->wlan_rfkill) { + if (asus->wlan_rfkill) { bool wlan; /* @@ -1344,111 +1285,118 @@ static int eeepc_hotk_thaw(struct device *device) * during suspend. Normally it restores it on resume, but * we should kick it ourselves in case hibernation is aborted. */ - wlan = eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WLAN); - eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_WLAN, wlan, NULL); + wlan = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); + asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); } return 0; } -static int eeepc_hotk_restore(struct device *device) +static int asus_hotk_restore(struct device *device) { - struct eeepc_wmi *eeepc = dev_get_drvdata(device); + struct asus_wmi *asus = dev_get_drvdata(device); int bl; /* Refresh both wlan rfkill state and pci hotplug */ - if (eeepc->wlan_rfkill) - eeepc_rfkill_hotplug(eeepc); + if (asus->wlan_rfkill) + asus_rfkill_hotplug(asus); - if (eeepc->bluetooth_rfkill) { - bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_BLUETOOTH); - rfkill_set_sw_state(eeepc->bluetooth_rfkill, bl); + if (asus->bluetooth_rfkill) { + bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BLUETOOTH); + rfkill_set_sw_state(asus->bluetooth_rfkill, bl); } - if (eeepc->wimax_rfkill) { - bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WIMAX); - rfkill_set_sw_state(eeepc->wimax_rfkill, bl); + if (asus->wimax_rfkill) { + bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WIMAX); + rfkill_set_sw_state(asus->wimax_rfkill, bl); } - if (eeepc->wwan3g_rfkill) { - bl = !eeepc_wmi_get_devstate_simple(EEEPC_WMI_DEVID_WWAN3G); - rfkill_set_sw_state(eeepc->wwan3g_rfkill, bl); + if (asus->wwan3g_rfkill) { + bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WWAN3G); + rfkill_set_sw_state(asus->wwan3g_rfkill, bl); } return 0; } -static const struct dev_pm_ops eeepc_pm_ops = { - .thaw = eeepc_hotk_thaw, - .restore = eeepc_hotk_restore, -}; - -static struct platform_driver platform_driver = { - .remove = __exit_p(eeepc_wmi_remove), - .driver = { - .name = EEEPC_WMI_FILE, - .owner = THIS_MODULE, - .pm = &eeepc_pm_ops, - }, +static const struct dev_pm_ops asus_pm_ops = { + .thaw = asus_hotk_thaw, + .restore = asus_hotk_restore, }; -static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, - void *context, void **retval) +static int asus_wmi_probe(struct platform_device *pdev) { - pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); - *(bool *)context = true; - return AE_CTRL_TERMINATE; -} - -static int __init eeepc_wmi_check_atkd(void) -{ - acpi_status status; - bool found = false; - - status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device, - &found, NULL); - - if (ACPI_FAILURE(status) || !found) - return 0; - return -1; -} + struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); + struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); + int ret; -static int __init eeepc_wmi_probe(struct platform_device *pdev) -{ - if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || - !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { - pr_warning("No known WMI GUID found\n"); + if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { + pr_warning("Management GUID not found\n"); return -ENODEV; } - if (eeepc_wmi_check_atkd()) { - pr_warning("WMI device present, but legacy ATKD device is also " - "present and enabled."); - pr_warning("You probably booted with acpi_osi=\"Linux\" or " - "acpi_osi=\"!Windows 2009\""); - pr_warning("Can't load eeepc-wmi, use default acpi_osi " - "(preferred) or eeepc-laptop"); + if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) { + pr_warning("Event GUID not found\n"); return -ENODEV; } - return eeepc_wmi_add(pdev); + if (wdrv->probe) { + ret = wdrv->probe(pdev); + if (ret) + return ret; + } + + return asus_wmi_add(pdev); } -static struct platform_device *platform_device; +static bool used; -static int __init eeepc_wmi_init(void) +int asus_wmi_register_driver(struct asus_wmi_driver *driver) { - platform_device = platform_create_bundle(&platform_driver, - eeepc_wmi_probe, + struct platform_driver *platform_driver; + struct platform_device *platform_device; + + if (used) + return -EBUSY; + + platform_driver = &driver->platform_driver; + platform_driver->remove = asus_wmi_remove; + platform_driver->driver.owner = driver->owner; + platform_driver->driver.name = driver->name; + platform_driver->driver.pm = &asus_pm_ops; + + platform_device = platform_create_bundle(platform_driver, + asus_wmi_probe, NULL, 0, NULL, 0); if (IS_ERR(platform_device)) return PTR_ERR(platform_device); + + used = true; + return 0; +} +EXPORT_SYMBOL_GPL(asus_wmi_register_driver); + +void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) +{ + platform_device_unregister(driver->platform_device); + platform_driver_unregister(&driver->platform_driver); + used = false; +} +EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver); + +static int __init asus_wmi_init(void) +{ + if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { + pr_info("Asus Management GUID not found"); + return -ENODEV; + } + + pr_info("ASUS WMI generic driver loaded"); return 0; } -static void __exit eeepc_wmi_exit(void) +static void __exit asus_wmi_exit(void) { - platform_device_unregister(platform_device); - platform_driver_unregister(&platform_driver); + pr_info("ASUS WMI generic driver unloaded"); } -module_init(eeepc_wmi_init); -module_exit(eeepc_wmi_exit); +module_init(asus_wmi_init); +module_exit(asus_wmi_exit); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h new file mode 100644 index 000000000000..c044522c8766 --- /dev/null +++ b/drivers/platform/x86/asus-wmi.h @@ -0,0 +1,58 @@ +/* + * Asus PC WMI hotkey driver + * + * Copyright(C) 2010 Intel Corporation. + * Copyright(C) 2010-2011 Corentin Chary + * + * Portions based on wistron_btns.c: + * Copyright (C) 2005 Miloslav Trmac + * Copyright (C) 2005 Bernhard Rosenkraenzer + * Copyright (C) 2005 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ASUS_WMI_H_ +#define _ASUS_WMI_H_ + +#include + +struct module; +struct key_entry; +struct asus_wmi; + +struct asus_wmi_driver { + bool hotplug_wireless; + + const char *name; + struct module *owner; + + const char *event_guid; + + const struct key_entry *keymap; + const char *input_name; + const char *input_phys; + + int (*probe) (struct platform_device *device); + void (*quirks) (struct asus_wmi_driver *driver); + + struct platform_driver platform_driver; + struct platform_device *platform_device; +}; + +int asus_wmi_register_driver(struct asus_wmi_driver *driver); +void asus_wmi_unregister_driver(struct asus_wmi_driver *driver); + +#endif /* !_ASUS_WMI_H_ */ diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c new file mode 100644 index 000000000000..3a060aefc5f3 --- /dev/null +++ b/drivers/platform/x86/eeepc-wmi.c @@ -0,0 +1,162 @@ +/* + * Eee PC WMI hotkey driver + * + * Copyright(C) 2010 Intel Corporation. + * Copyright(C) 2010 Corentin Chary + * + * Portions based on wistron_btns.c: + * Copyright (C) 2005 Miloslav Trmac + * Copyright (C) 2005 Bernhard Rosenkraenzer + * Copyright (C) 2005 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "asus-wmi.h" + +#define EEEPC_WMI_FILE "eeepc-wmi" + +MODULE_AUTHOR("Corentin Chary "); +MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); +MODULE_LICENSE("GPL"); + +#define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ + +#define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" + +MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); + +static bool hotplug_wireless; + +module_param(hotplug_wireless, bool, 0444); +MODULE_PARM_DESC(hotplug_wireless, + "Enable hotplug for wireless device. " + "If your laptop needs that, please report to " + "acpi4asus-user@lists.sourceforge.net."); + +static const struct key_entry eeepc_wmi_keymap[] = { + /* Sleep already handled via generic ACPI code */ + { KE_KEY, 0x30, { KEY_VOLUMEUP } }, + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x32, { KEY_MUTE } }, + { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ + { KE_KEY, 0x5d, { KEY_WLAN } }, + { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ + { KE_KEY, 0x82, { KEY_CAMERA } }, + { KE_KEY, 0x88, { KEY_WLAN } }, + { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ + { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ + { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, + { KE_END, 0}, +}; + +static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level, + void *context, void **retval) +{ + pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); + *(bool *)context = true; + return AE_CTRL_TERMINATE; +} + +static int eeepc_wmi_check_atkd(void) +{ + acpi_status status; + bool found = false; + + status = acpi_get_devices(EEEPC_ACPI_HID, eeepc_wmi_parse_device, + &found, NULL); + + if (ACPI_FAILURE(status) || !found) + return 0; + return -1; +} + +static int eeepc_wmi_probe(struct platform_device *pdev) +{ + if (eeepc_wmi_check_atkd()) { + pr_warning("WMI device present, but legacy ATKD device is also " + "present and enabled."); + pr_warning("You probably booted with acpi_osi=\"Linux\" or " + "acpi_osi=\"!Windows 2009\""); + pr_warning("Can't load eeepc-wmi, use default acpi_osi " + "(preferred) or eeepc-laptop"); + return -EBUSY; + } + return 0; +} + +static void eeepc_dmi_check(struct asus_wmi_driver *driver) +{ + const char *model; + + model = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!model) + return; + + /* + * Whitelist for wlan hotplug + * + * Asus 1000H needs the current hotplug code to handle + * Fn+F2 correctly. We may add other Asus here later, but + * it seems that most of the laptops supported by asus-wmi + * don't need to be on this list + */ + if (strcmp(model, "1000H") == 0) { + driver->hotplug_wireless = true; + pr_info("wlan hotplug enabled\n"); + } +} + +static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) +{ + driver->hotplug_wireless = hotplug_wireless; + eeepc_dmi_check(driver); +} + +static struct asus_wmi_driver asus_wmi_driver = { + .name = EEEPC_WMI_FILE, + .owner = THIS_MODULE, + .event_guid = EEEPC_WMI_EVENT_GUID, + .keymap = eeepc_wmi_keymap, + .input_name = "Eee PC WMI hotkeys", + .input_phys = EEEPC_WMI_FILE "/input0", + .probe = eeepc_wmi_probe, + .quirks = eeepc_wmi_quirks, +}; + + +static int __init eeepc_wmi_init(void) +{ + return asus_wmi_register_driver(&asus_wmi_driver); +} + +static void __exit eeepc_wmi_exit(void) +{ + asus_wmi_unregister_driver(&asus_wmi_driver); +} + +module_init(eeepc_wmi_init); +module_exit(eeepc_wmi_exit); -- cgit v1.2.2 From 57ab7dae27fae6a492ec968dc543106685adcad5 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:32 +0100 Subject: asus-wmi: minor cleanups Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 34 +++++++++++++++++----------------- drivers/platform/x86/eeepc-wmi.c | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 35e6bb6c266d..4c3f68a495d7 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -2,7 +2,7 @@ * Asus PC WMI hotkey driver * * Copyright(C) 2010 Intel Corporation. - * Copyright(C) 2010 Corentin Chary + * Copyright(C) 2010-2011 Corentin Chary * * Portions based on wistron_btns.c: * Copyright (C) 2005 Miloslav Trmac @@ -87,7 +87,7 @@ MODULE_LICENSE("GPL"); #define ASUS_WMI_DEVID_CARDREADER 0x00080013 /* Input */ -#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 +#define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 /* DSTS masks */ @@ -903,25 +903,25 @@ static void asus_wmi_notify(u32 value, void *context) obj = (union acpi_object *)response.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) { - code = obj->integer.value; - orig_code = code; + if (!obj || obj->type != ACPI_TYPE_INTEGER) + goto exit; - if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) - code = NOTIFY_BRNUP_MIN; - else if (code >= NOTIFY_BRNDOWN_MIN && - code <= NOTIFY_BRNDOWN_MAX) - code = NOTIFY_BRNDOWN_MIN; + code = obj->integer.value; + orig_code = code; - if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { - if (!acpi_video_backlight_support()) - asus_wmi_backlight_notify(asus, orig_code); - } + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) + code = NOTIFY_BRNUP_MIN; + else if (code >= NOTIFY_BRNDOWN_MIN && + code <= NOTIFY_BRNDOWN_MAX) + code = NOTIFY_BRNDOWN_MIN; - if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) - pr_info("Unknown key %x pressed\n", code); - } + if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { + if (!acpi_video_backlight_support()) + asus_wmi_backlight_notify(asus, orig_code); + } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) + pr_info("Unknown key %x pressed\n", code); +exit: kfree(obj); } diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 3a060aefc5f3..e69701fc422b 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -2,7 +2,7 @@ * Eee PC WMI hotkey driver * * Copyright(C) 2010 Intel Corporation. - * Copyright(C) 2010 Corentin Chary + * Copyright(C) 2010-2011 Corentin Chary * * Portions based on wistron_btns.c: * Copyright (C) 2005 Miloslav Trmac -- cgit v1.2.2 From a7ce3f041e640daf96e227d8f7ffa6b988f33025 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:33 +0100 Subject: asus-wmi: introduce struct asus_rfkill First, this allow use to remove the custom asusrfkill_wlan_query, but this will also allow us to give struct asus_wmi * to get_devstate/set_devstate later. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 115 +++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 4c3f68a495d7..d0f0931ea5eb 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -114,6 +114,12 @@ struct asus_wmi_debug { u32 ctrl_param; }; +struct asus_rfkill { + struct asus_wmi *asus; + struct rfkill *rfkill; + u32 dev_id; +}; + struct asus_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; @@ -124,10 +130,10 @@ struct asus_wmi { struct workqueue_struct *led_workqueue; struct work_struct tpd_led_work; - struct rfkill *wlan_rfkill; - struct rfkill *bluetooth_rfkill; - struct rfkill *wimax_rfkill; - struct rfkill *wwan3g_rfkill; + struct asus_rfkill wlan; + struct asus_rfkill bluetooth; + struct asus_rfkill wimax; + struct asus_rfkill wwan3g; struct hotplug_slot *hotplug_slot; struct mutex hotplug_lock; @@ -377,8 +383,8 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus) mutex_lock(&asus->hotplug_lock); - if (asus->wlan_rfkill) - rfkill_set_sw_state(asus->wlan_rfkill, blocked); + if (asus->wlan.rfkill) + rfkill_set_sw_state(asus->wlan.rfkill, blocked); if (asus->hotplug_slot) { bus = pci_find_bus(0, 1); @@ -570,11 +576,11 @@ error_workqueue: */ static int asus_rfkill_set(void *data, bool blocked) { - int dev_id = (unsigned long)data; + struct asus_rfkill *priv = data; u32 ctrl_param = !blocked; acpi_status status; - status = asus_wmi_set_devstate(dev_id, ctrl_param, NULL); + status = asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL); if (ACPI_FAILURE(status)) return -EIO; @@ -584,20 +590,21 @@ static int asus_rfkill_set(void *data, bool blocked) static void asus_rfkill_query(struct rfkill *rfkill, void *data) { - int dev_id = (unsigned long)data; + struct asus_rfkill *priv = data; int result; - result = asus_wmi_get_devstate_simple(dev_id); + result = asus_wmi_get_devstate_simple(priv->dev_id); if (result < 0) return; - rfkill_set_sw_state(rfkill, !result); + rfkill_set_sw_state(priv->rfkill, !result); } static int asus_rfkill_wlan_set(void *data, bool blocked) { - struct asus_wmi *asus = data; + struct asus_rfkill *priv = data; + struct asus_wmi *asus = priv->asus; int ret; /* @@ -608,19 +615,14 @@ static int asus_rfkill_wlan_set(void *data, bool blocked) * any wmi method */ mutex_lock(&asus->wmi_lock); - ret = asus_rfkill_set((void *)(long)ASUS_WMI_DEVID_WLAN, blocked); + ret = asus_rfkill_set(data, blocked); mutex_unlock(&asus->wmi_lock); return ret; } -static void asus_rfkill_wlan_query(struct rfkill *rfkill, void *data) -{ - asus_rfkill_query(rfkill, (void *)(long)ASUS_WMI_DEVID_WLAN); -} - static const struct rfkill_ops asus_rfkill_wlan_ops = { .set_block = asus_rfkill_wlan_set, - .query = asus_rfkill_wlan_query, + .query = asus_rfkill_query, }; static const struct rfkill_ops asus_rfkill_ops = { @@ -629,20 +631,24 @@ static const struct rfkill_ops asus_rfkill_ops = { }; static int asus_new_rfkill(struct asus_wmi *asus, - struct rfkill **rfkill, + struct asus_rfkill *arfkill, const char *name, enum rfkill_type type, int dev_id) { int result = asus_wmi_get_devstate_simple(dev_id); + struct rfkill **rfkill = &arfkill->rfkill; if (result < 0) return result; + arfkill->dev_id = dev_id; + arfkill->asus = asus; + if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless) *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, - &asus_rfkill_wlan_ops, asus); + &asus_rfkill_wlan_ops, arfkill); else *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, - &asus_rfkill_ops, (void *)(long)dev_id); + &asus_rfkill_ops, arfkill); if (!*rfkill) return -EINVAL; @@ -662,10 +668,10 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus) asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); - if (asus->wlan_rfkill) { - rfkill_unregister(asus->wlan_rfkill); - rfkill_destroy(asus->wlan_rfkill); - asus->wlan_rfkill = NULL; + if (asus->wlan.rfkill) { + rfkill_unregister(asus->wlan.rfkill); + rfkill_destroy(asus->wlan.rfkill); + asus->wlan.rfkill = NULL; } /* * Refresh pci hotplug in case the rfkill state was changed after @@ -677,20 +683,20 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus) if (asus->hotplug_workqueue) destroy_workqueue(asus->hotplug_workqueue); - if (asus->bluetooth_rfkill) { - rfkill_unregister(asus->bluetooth_rfkill); - rfkill_destroy(asus->bluetooth_rfkill); - asus->bluetooth_rfkill = NULL; + if (asus->bluetooth.rfkill) { + rfkill_unregister(asus->bluetooth.rfkill); + rfkill_destroy(asus->bluetooth.rfkill); + asus->bluetooth.rfkill = NULL; } - if (asus->wimax_rfkill) { - rfkill_unregister(asus->wimax_rfkill); - rfkill_destroy(asus->wimax_rfkill); - asus->wimax_rfkill = NULL; + if (asus->wimax.rfkill) { + rfkill_unregister(asus->wimax.rfkill); + rfkill_destroy(asus->wimax.rfkill); + asus->wimax.rfkill = NULL; } - if (asus->wwan3g_rfkill) { - rfkill_unregister(asus->wwan3g_rfkill); - rfkill_destroy(asus->wwan3g_rfkill); - asus->wwan3g_rfkill = NULL; + if (asus->wwan3g.rfkill) { + rfkill_unregister(asus->wwan3g.rfkill); + rfkill_destroy(asus->wwan3g.rfkill); + asus->wwan3g.rfkill = NULL; } } @@ -701,30 +707,27 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus) mutex_init(&asus->hotplug_lock); mutex_init(&asus->wmi_lock); - result = asus_new_rfkill(asus, &asus->wlan_rfkill, - "asus-wlan", RFKILL_TYPE_WLAN, - ASUS_WMI_DEVID_WLAN); + result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan", + RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN); if (result && result != -ENODEV) goto exit; - result = asus_new_rfkill(asus, &asus->bluetooth_rfkill, + result = asus_new_rfkill(asus, &asus->bluetooth, "asus-bluetooth", RFKILL_TYPE_BLUETOOTH, ASUS_WMI_DEVID_BLUETOOTH); if (result && result != -ENODEV) goto exit; - result = asus_new_rfkill(asus, &asus->wimax_rfkill, - "asus-wimax", RFKILL_TYPE_WIMAX, - ASUS_WMI_DEVID_WIMAX); + result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax", + RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX); if (result && result != -ENODEV) goto exit; - result = asus_new_rfkill(asus, &asus->wwan3g_rfkill, - "asus-wwan3g", RFKILL_TYPE_WWAN, - ASUS_WMI_DEVID_WWAN3G); + result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g", + RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G); if (result && result != -ENODEV) goto exit; @@ -1277,7 +1280,7 @@ static int asus_hotk_thaw(struct device *device) { struct asus_wmi *asus = dev_get_drvdata(device); - if (asus->wlan_rfkill) { + if (asus->wlan.rfkill) { bool wlan; /* @@ -1298,20 +1301,20 @@ static int asus_hotk_restore(struct device *device) int bl; /* Refresh both wlan rfkill state and pci hotplug */ - if (asus->wlan_rfkill) + if (asus->wlan.rfkill) asus_rfkill_hotplug(asus); - if (asus->bluetooth_rfkill) { + if (asus->bluetooth.rfkill) { bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BLUETOOTH); - rfkill_set_sw_state(asus->bluetooth_rfkill, bl); + rfkill_set_sw_state(asus->bluetooth.rfkill, bl); } - if (asus->wimax_rfkill) { + if (asus->wimax.rfkill) { bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WIMAX); - rfkill_set_sw_state(asus->wimax_rfkill, bl); + rfkill_set_sw_state(asus->wimax.rfkill, bl); } - if (asus->wwan3g_rfkill) { + if (asus->wwan3g.rfkill) { bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WWAN3G); - rfkill_set_sw_state(asus->wwan3g_rfkill, bl); + rfkill_set_sw_state(asus->wwan3g.rfkill, bl); } return 0; -- cgit v1.2.2 From a75fe0d78ec00d3d5b2c42b1ee76b22e99f213d1 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:34 +0100 Subject: asus-wmi: handle "unknown status" bit Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d0f0931ea5eb..39ce3c1a7712 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -92,6 +92,7 @@ MODULE_LICENSE("GPL"); /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 +#define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 #define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000 #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 @@ -270,6 +271,11 @@ static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) return -ENODEV; + if (mask == ASUS_WMI_DSTS_STATUS_BIT) { + if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT) + return -ENODEV; + } + return retval & mask; } -- cgit v1.2.2 From d33da3b6866975b17fbec67540f6153f5dcdcec7 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:35 +0100 Subject: asus-wmi: factorise wmi_evaluate_method call This patch create a single function to call the WMI methods. This function handle inexistent methods (when implemented by the WMI devices, and this is not the case on Eee PCs), ACPI errors, etc.. Also pack struct bios_arg, and make sure that we always send a 64bit buffer when calling a WMI method, because this is needed on Asus notebooks. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 162 ++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 39ce3c1a7712..34e6b4d83a93 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -70,6 +70,8 @@ MODULE_LICENSE("GPL"); #define ASUS_WMI_METHODID_DEVS 0x53564544 #define ASUS_WMI_METHODID_CFVS 0x53564643 +#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE + /* Wireless */ #define ASUS_WMI_DEVID_WLAN 0x00010011 #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 @@ -98,9 +100,9 @@ MODULE_LICENSE("GPL"); #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 struct bios_args { - u32 dev_id; - u32 ctrl_param; -}; + u32 arg0; + u32 arg1; +} __packed; /* * / - debugfs root directory @@ -187,20 +189,24 @@ static void asus_wmi_input_exit(struct asus_wmi *asus) asus->inputdev = NULL; } -static acpi_status asus_wmi_get_devstate(u32 dev_id, u32 *retval) +static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, + u32 *retval) { - struct acpi_buffer input = { (acpi_size) sizeof(u32), &dev_id }; + struct bios_args args = { + .arg0 = arg0, + .arg1 = arg1, + }; + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; acpi_status status; + union acpi_object *obj; u32 tmp; - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, - 1, ASUS_WMI_METHODID_DSTS, + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, &input, &output); if (ACPI_FAILURE(status)) - return status; + goto exit; obj = (union acpi_object *)output.pointer; if (obj && obj->type == ACPI_TYPE_INTEGER) @@ -213,60 +219,39 @@ static acpi_status asus_wmi_get_devstate(u32 dev_id, u32 *retval) kfree(obj); - return status; +exit: + if (ACPI_FAILURE(status)) + return -EIO; + + if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) + return -ENODEV; + return 0; } -static acpi_status asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, - u32 *retval) +static int asus_wmi_get_devstate(u32 dev_id, u32 *retval) { - struct bios_args args = { - .dev_id = dev_id, - .ctrl_param = ctrl_param, - }; - struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; - acpi_status status; - - if (!retval) { - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, - ASUS_WMI_METHODID_DEVS, - &input, NULL); - } else { - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - u32 tmp; - - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, - ASUS_WMI_METHODID_DEVS, - &input, &output); - - if (ACPI_FAILURE(status)) - return status; - - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32) obj->integer.value; - else - tmp = 0; - - *retval = tmp; - - kfree(obj); - } + return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, + 0, retval); +} - return status; +static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, + u32 *retval) +{ + return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, + ctrl_param, retval); } /* Helper for special devices with magic return codes */ static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) { u32 retval = 0; - acpi_status status; + int err; - status = asus_wmi_get_devstate(dev_id, &retval); + err = asus_wmi_get_devstate(dev_id, &retval); - if (ACPI_FAILURE(status)) - return -EINVAL; + if (err < 0) + return err; if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) return -ENODEV; @@ -584,14 +569,8 @@ static int asus_rfkill_set(void *data, bool blocked) { struct asus_rfkill *priv = data; u32 ctrl_param = !blocked; - acpi_status status; - - status = asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL); - - if (ACPI_FAILURE(status)) - return -EIO; - return 0; + return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL); } static void asus_rfkill_query(struct rfkill *rfkill, void *data) @@ -784,38 +763,34 @@ static int read_backlight_power(void) static int read_brightness(struct backlight_device *bd) { u32 retval; - acpi_status status; + int err; - status = asus_wmi_get_devstate(ASUS_WMI_DEVID_BRIGHTNESS, &retval); + err = asus_wmi_get_devstate(ASUS_WMI_DEVID_BRIGHTNESS, &retval); - if (ACPI_FAILURE(status)) - return -EIO; - else - return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; + if (err < 0) + return err; + + return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; } static int update_bl_status(struct backlight_device *bd) { u32 ctrl_param; - acpi_status status; - int power; + int power, err; ctrl_param = bd->props.brightness; - status = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, - ctrl_param, NULL); + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, + ctrl_param, NULL); - if (ACPI_FAILURE(status)) - return -EIO; + if (err < 0) + return err; power = read_backlight_power(); if (power != -ENODEV && bd->props.power != power) { ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); - status = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, - ctrl_param, NULL); - - if (ACPI_FAILURE(status)) - return -EIO; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, + ctrl_param, NULL); } return 0; } @@ -948,19 +923,19 @@ static int parse_arg(const char *buf, unsigned long count, int *val) static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) { - acpi_status status; u32 retval; - int rv, value; + int rv, err, value; value = asus_wmi_get_devstate_simple(devid); if (value == -ENODEV) /* Check device presence */ return value; rv = parse_arg(buf, count, &value); - status = asus_wmi_set_devstate(devid, value, &retval); + err = asus_wmi_set_devstate(devid, value, &retval); + + if (err < 0) + return err; - if (ACPI_FAILURE(status)) - return -EIO; return rv; } @@ -1003,21 +978,13 @@ static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int value; - struct acpi_buffer input = { (acpi_size) sizeof(value), &value }; - acpi_status status; if (!count || sscanf(buf, "%i", &value) != 1) return -EINVAL; if (value < 0 || value > 2) return -EINVAL; - status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, - 1, ASUS_WMI_METHODID_CFVS, &input, NULL); - - if (ACPI_FAILURE(status)) - return -EIO; - else - return count; + return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); } static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); @@ -1089,13 +1056,13 @@ struct asus_wmi_debugfs_node { static int show_dsts(struct seq_file *m, void *data) { struct asus_wmi *asus = m->private; - acpi_status status; + int err; u32 retval = -1; - status = asus_wmi_get_devstate(asus->debug.dev_id, &retval); + err = asus_wmi_get_devstate(asus->debug.dev_id, &retval); - if (ACPI_FAILURE(status)) - return -EIO; + if (err < 0) + return err; seq_printf(m, "DSTS(%x) = %x\n", asus->debug.dev_id, retval); @@ -1105,13 +1072,14 @@ static int show_dsts(struct seq_file *m, void *data) static int show_devs(struct seq_file *m, void *data) { struct asus_wmi *asus = m->private; - acpi_status status; + int err; u32 retval = -1; - status = asus_wmi_set_devstate(asus->debug.dev_id, - asus->debug.ctrl_param, &retval); - if (ACPI_FAILURE(status)) - return -EIO; + err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, + &retval); + + if (err < 0) + return err; seq_printf(m, "DEVS(%x, %x) = %x\n", asus->debug.dev_id, asus->debug.ctrl_param, retval); -- cgit v1.2.2 From 1d070f89a723bd296865dd7eb61c8050763e6e3b Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:36 +0100 Subject: asus-wmi: try to guess the right DSTS methods This is tricky, new WMI aware notebooks seems to use 0x53545344 while Eee PCs are using 0x53544344. But there is no way to know if there is an Eee PC in that wild that is using 0x53545344 or a notebook using 0x53544344. So the driver try to guess the available DSTS method ... But most Eee PCs never return 0xFFFFFFFE when a method is not available, they return 0 instead (and that's useless). So, first, try 0x53544344 then 0x53545344. We will find a better way when we got more data. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 99 +++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 34e6b4d83a93..fd5b08eecf1e 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -67,6 +67,7 @@ MODULE_LICENSE("GPL"); /* WMI Methods */ #define ASUS_WMI_METHODID_DSTS 0x53544344 +#define ASUS_WMI_METHODID_DSTS2 0x53545344 #define ASUS_WMI_METHODID_DEVS 0x53564544 #define ASUS_WMI_METHODID_CFVS 0x53564643 @@ -124,6 +125,8 @@ struct asus_rfkill { }; struct asus_wmi { + int dsts_id; + struct input_dev *inputdev; struct backlight_device *backlight_device; struct platform_device *platform_device; @@ -229,26 +232,26 @@ exit: return 0; } -static int asus_wmi_get_devstate(u32 dev_id, u32 *retval) +static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) { - return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, - 0, retval); + return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval); } static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, - u32 *retval) + u32 *retval) { return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval); } /* Helper for special devices with magic return codes */ -static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) +static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, + u32 dev_id, u32 mask) { u32 retval = 0; int err; - err = asus_wmi_get_devstate(dev_id, &retval); + err = asus_wmi_get_devstate(asus, dev_id, &retval); if (err < 0) return err; @@ -264,9 +267,10 @@ static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask) return retval & mask; } -static int asus_wmi_get_devstate_simple(u32 dev_id) +static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) { - return asus_wmi_get_devstate_bits(dev_id, ASUS_WMI_DSTS_STATUS_BIT); + return asus_wmi_get_devstate_bits(asus, dev_id, + ASUS_WMI_DSTS_STATUS_BIT); } /* @@ -302,7 +306,7 @@ static void tpd_led_set(struct led_classdev *led_cdev, static int read_tpd_led_state(struct asus_wmi *asus) { - return asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_TOUCHPAD_LED); + return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED); } static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) @@ -353,7 +357,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) */ static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) { - int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); + int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); if (result < 0) return false; @@ -482,7 +486,8 @@ static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { - int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); + struct asus_wmi *asus = hotplug_slot->private; + int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); if (result < 0) return result; @@ -578,7 +583,7 @@ static void asus_rfkill_query(struct rfkill *rfkill, void *data) struct asus_rfkill *priv = data; int result; - result = asus_wmi_get_devstate_simple(priv->dev_id); + result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id); if (result < 0) return; @@ -619,7 +624,7 @@ static int asus_new_rfkill(struct asus_wmi *asus, struct asus_rfkill *arfkill, const char *name, enum rfkill_type type, int dev_id) { - int result = asus_wmi_get_devstate_simple(dev_id); + int result = asus_wmi_get_devstate_simple(asus, dev_id); struct rfkill **rfkill = &arfkill->rfkill; if (result < 0) @@ -750,9 +755,9 @@ exit: /* * Backlight */ -static int read_backlight_power(void) +static int read_backlight_power(struct asus_wmi *asus) { - int ret = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BACKLIGHT); + int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT); if (ret < 0) return ret; @@ -762,10 +767,11 @@ static int read_backlight_power(void) static int read_brightness(struct backlight_device *bd) { + struct asus_wmi *asus = bl_get_data(bd); u32 retval; int err; - err = asus_wmi_get_devstate(ASUS_WMI_DEVID_BRIGHTNESS, &retval); + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); if (err < 0) return err; @@ -775,6 +781,7 @@ static int read_brightness(struct backlight_device *bd) static int update_bl_status(struct backlight_device *bd) { + struct asus_wmi *asus = bl_get_data(bd); u32 ctrl_param; int power, err; @@ -786,7 +793,7 @@ static int update_bl_status(struct backlight_device *bd) if (err < 0) return err; - power = read_backlight_power(); + power = read_backlight_power(asus); if (power != -ENODEV && bd->props.power != power) { ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, @@ -825,9 +832,9 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus) int max; int power; - max = asus_wmi_get_devstate_bits(ASUS_WMI_DEVID_BRIGHTNESS, + max = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_BRIGHTNESS, ASUS_WMI_DSTS_MAX_BRIGTH_MASK); - power = read_backlight_power(); + power = read_backlight_power(asus); if (max < 0 && power < 0) { /* Try to keep the original error */ @@ -921,12 +928,13 @@ static int parse_arg(const char *buf, unsigned long count, int *val) return count; } -static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) +static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, + const char *buf, size_t count) { u32 retval; int rv, err, value; - value = asus_wmi_get_devstate_simple(devid); + value = asus_wmi_get_devstate_simple(asus, devid); if (value == -ENODEV) /* Check device presence */ return value; @@ -939,9 +947,9 @@ static ssize_t store_sys_wmi(int devid, const char *buf, size_t count) return rv; } -static ssize_t show_sys_wmi(int devid, char *buf) +static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) { - int value = asus_wmi_get_devstate_simple(devid); + int value = asus_wmi_get_devstate_simple(asus, devid); if (value < 0) return value; @@ -954,13 +962,17 @@ static ssize_t show_sys_wmi(int devid, char *buf) struct device_attribute *attr, \ char *buf) \ { \ - return show_sys_wmi(_cm, buf); \ + struct asus_wmi *asus = dev_get_drvdata(dev); \ + \ + return show_sys_wmi(asus, _cm, buf); \ } \ static ssize_t store_##_name(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ - return store_sys_wmi(_cm, buf, count); \ + struct asus_wmi *asus = dev_get_drvdata(dev); \ + \ + return store_sys_wmi(asus, _cm, buf, count); \ } \ static struct device_attribute dev_attr_##_name = { \ .attr = { \ @@ -1000,7 +1012,10 @@ static struct attribute *platform_attributes[] = { static mode_t asus_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx) { - bool supported = true; + struct device *dev = container_of(kobj, struct device, kobj); + struct platform_device *pdev = to_platform_device(dev); + struct asus_wmi *asus = platform_get_drvdata(pdev); + bool ok = true; int devid = -1; if (attr == &dev_attr_camera.attr) @@ -1011,9 +1026,9 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj, devid = ASUS_WMI_DEVID_TOUCHPAD; if (devid != -1) - supported = asus_wmi_get_devstate_simple(devid) != -ENODEV; + ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); - return supported ? attr->mode : 0; + return ok ? attr->mode : 0; } static struct attribute_group platform_attribute_group = { @@ -1036,6 +1051,23 @@ static int asus_wmi_sysfs_init(struct platform_device *device) */ static int __init asus_wmi_platform_init(struct asus_wmi *asus) { + /* + * Eee PC and Notebooks seems to have different method_id for DSTS, + * but it may also be related to the BIOS's SPEC. + * Note, on most Eeepc, there is no way to check if a method exist + * or note, while on notebooks, they returns 0xFFFFFFFE on failure, + * but once again, SPEC may probably be used for that kind of things. + */ + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) + asus->dsts_id = ASUS_WMI_METHODID_DSTS; + else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL)) + asus->dsts_id = ASUS_WMI_METHODID_DSTS2; + + if (!asus->dsts_id) { + pr_err("Can't find DSTS"); + return -ENODEV; + } + return asus_wmi_sysfs_init(asus->platform_device); } @@ -1059,7 +1091,7 @@ static int show_dsts(struct seq_file *m, void *data) int err; u32 retval = -1; - err = asus_wmi_get_devstate(asus->debug.dev_id, &retval); + err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); if (err < 0) return err; @@ -1262,7 +1294,7 @@ static int asus_hotk_thaw(struct device *device) * during suspend. Normally it restores it on resume, but * we should kick it ourselves in case hibernation is aborted. */ - wlan = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN); + wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); } @@ -1279,15 +1311,16 @@ static int asus_hotk_restore(struct device *device) asus_rfkill_hotplug(asus); if (asus->bluetooth.rfkill) { - bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BLUETOOTH); + bl = !asus_wmi_get_devstate_simple(asus, + ASUS_WMI_DEVID_BLUETOOTH); rfkill_set_sw_state(asus->bluetooth.rfkill, bl); } if (asus->wimax.rfkill) { - bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WIMAX); + bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX); rfkill_set_sw_state(asus->wimax.rfkill, bl); } if (asus->wwan3g.rfkill) { - bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WWAN3G); + bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); rfkill_set_sw_state(asus->wwan3g.rfkill, bl); } -- cgit v1.2.2 From 8fbea019a1a70e0fb01e0f98c963e6042fbe94ab Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:37 +0100 Subject: asus-wmi: fix and clean backlight code Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 44 +++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index fd5b08eecf1e..adf7b05c9aef 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -765,14 +765,32 @@ static int read_backlight_power(struct asus_wmi *asus) return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; } -static int read_brightness(struct backlight_device *bd) +static int read_brightness_max(struct asus_wmi *asus) { - struct asus_wmi *asus = bl_get_data(bd); u32 retval; int err; err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); + if (err < 0) + return err; + + retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK; + retval >>= 8; + + if (!retval) + return -ENODEV; + + return retval; +} + +static int read_brightness(struct backlight_device *bd) +{ + struct asus_wmi *asus = bl_get_data(bd); + u32 retval, err; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); + if (err < 0) return err; @@ -799,7 +817,7 @@ static int update_bl_status(struct backlight_device *bd) err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, ctrl_param, NULL); } - return 0; + return err; } static const struct backlight_ops asus_wmi_bl_ops = { @@ -832,23 +850,19 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus) int max; int power; - max = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_BRIGHTNESS, - ASUS_WMI_DSTS_MAX_BRIGTH_MASK); - power = read_backlight_power(asus); + max = read_brightness_max(asus); - if (max < 0 && power < 0) { - /* Try to keep the original error */ - if (max == -ENODEV && power == -ENODEV) - return -ENODEV; - if (max != -ENODEV) - return max; - else - return power; - } if (max == -ENODEV) max = 0; + else if (max < 0) + return max; + + power = read_backlight_power(asus); + if (power == -ENODEV) power = FB_BLANK_UNBLANK; + else if (power < 0) + return power; memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = max; -- cgit v1.2.2 From 46dbca871df753ce92c321a41a8a38eba7487680 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:38 +0100 Subject: asus-wmi: add calls to INIT, SPEC and SFUN on init INIT() call is needed to enable hotkeys on G73 SPEC() and SFUN() allow us to know more about available features. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index adf7b05c9aef..88596ea0f74e 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -66,10 +66,13 @@ MODULE_LICENSE("GPL"); #define NOTIFY_BRNDOWN_MAX 0x2e /* WMI Methods */ +#define ASUS_WMI_METHODID_SPEC 0x43455053 +#define ASUS_WMI_METHODID_SFUN 0x4E554653 #define ASUS_WMI_METHODID_DSTS 0x53544344 #define ASUS_WMI_METHODID_DSTS2 0x53545344 #define ASUS_WMI_METHODID_DEVS 0x53564544 #define ASUS_WMI_METHODID_CFVS 0x53564643 +#define ASUS_WMI_METHODID_INIT 0x54494E49 #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE @@ -126,6 +129,8 @@ struct asus_rfkill { struct asus_wmi { int dsts_id; + int spec; + int sfun; struct input_dev *inputdev; struct backlight_device *backlight_device; @@ -1065,6 +1070,29 @@ static int asus_wmi_sysfs_init(struct platform_device *device) */ static int __init asus_wmi_platform_init(struct asus_wmi *asus) { + int rv; + + /* INIT enable hotkeys on some models */ + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv)) + pr_info("Initialization: %#x", rv); + + /* We don't know yet what to do with this version... */ + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { + pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF); + asus->spec = rv; + } + + /* + * The SFUN method probably allows the original driver to get the list + * of features supported by a given model. For now, 0x0100 or 0x0800 + * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. + * The significance of others is yet to be found. + */ + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) { + pr_info("SFUN value: %#x", rv); + asus->sfun = rv; + } + /* * Eee PC and Notebooks seems to have different method_id for DSTS, * but it may also be related to the BIOS's SPEC. -- cgit v1.2.2 From ef343491db1770a3af5010ba007167c348cdbe1a Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:39 +0100 Subject: asus-wmi: allow debugfs interface to call arbitrary method Also add some # format flags to debugfs output. Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 47 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 88596ea0f74e..9095c28340cd 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -112,11 +112,14 @@ struct bios_args { * / - debugfs root directory * dev_id - current dev_id * ctrl_param - current ctrl_param + * method_id - current method_id * devs - call DEVS(dev_id, ctrl_param) and print result * dsts - call DSTS(dev_id) and print result + * call - call method_id(dev_id, ctrl_param) and print result */ struct asus_wmi_debug { struct dentry *root; + u32 method_id; u32 dev_id; u32 ctrl_param; }; @@ -1138,7 +1141,7 @@ static int show_dsts(struct seq_file *m, void *data) if (err < 0) return err; - seq_printf(m, "DSTS(%x) = %x\n", asus->debug.dev_id, retval); + seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval); return 0; } @@ -1155,15 +1158,50 @@ static int show_devs(struct seq_file *m, void *data) if (err < 0) return err; - seq_printf(m, "DEVS(%x, %x) = %x\n", asus->debug.dev_id, + seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id, asus->debug.ctrl_param, retval); return 0; } +static int show_call(struct seq_file *m, void *data) +{ + struct asus_wmi *asus = m->private; + struct bios_args args = { + .arg0 = asus->debug.dev_id, + .arg1 = asus->debug.ctrl_param, + }; + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, + 1, asus->debug.method_id, + &input, &output); + + if (ACPI_FAILURE(status)) + return -EIO; + + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id, + asus->debug.dev_id, asus->debug.ctrl_param, + (u32) obj->integer.value); + else + seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id, + asus->debug.dev_id, asus->debug.ctrl_param, + obj->type); + + kfree(obj); + + return 0; +} + static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = { {NULL, "devs", show_devs}, {NULL, "dsts", show_dsts}, + {NULL, "call", show_call}, }; static int asus_wmi_debugfs_open(struct inode *inode, struct file *file) @@ -1197,6 +1235,11 @@ static int asus_wmi_debugfs_init(struct asus_wmi *asus) goto error_debugfs; } + dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, + asus->debug.root, &asus->debug.method_id); + if (!dent) + goto error_debugfs; + dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, asus->debug.root, &asus->debug.dev_id); if (!dent) -- cgit v1.2.2 From b229ece9911cc0b2415d3ffd55d7b2a28d30b614 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:40 +0100 Subject: asus-nb-wmi: Asus Notebooks WMI Driver Introduce a new driver for Asus Notebooks shipped with a WMI device instead of the old ACPI device. The WMI device is almost the same as the one present in Eee PC, but the event guid and the keymap are different. The keymap comes from asus-laptop module. On Asus notebooks, when you call the WMI device, you always need a 64bit buffer, even if you only want to get the state of a device (tested on a G73). Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 16 ++++++- drivers/platform/x86/Makefile | 1 + drivers/platform/x86/asus-nb-wmi.c | 98 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 drivers/platform/x86/asus-nb-wmi.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7fde7ba01ab0..45f4d63c7939 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -465,11 +465,25 @@ config ASUS_WMI select LEDS_CLASS select NEW_LEDS ---help--- - Say Y here if you have a WMI aware Asus laptop (like Eee PCs). + Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new + Asus Notebooks). To compile this driver as a module, choose M here: the module will be called asus-wmi. +config ASUS_NB_WMI + tristate "Asus Notebook WMI Driver (EXPERIMENTAL)" + depends on ASUS_WMI + ---help--- + This is a driver for newer Asus notebooks. It adds extra features + like wireless radio and bluetooth control, leds, hotkeys, backlight... + + For more informations, see + + + If you have an ACPI-WMI compatible Asus Notebook, say Y or M + here. + config EEEPC_WMI tristate "Eee PC WMI Driver (EXPERIMENTAL)" depends on ASUS_WMI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index f9c83f48c922..0f7b23c0714b 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ASUS_WMI) += asus-wmi.o +obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c new file mode 100644 index 000000000000..0580d99b0798 --- /dev/null +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -0,0 +1,98 @@ +/* + * Asus Notebooks WMI hotkey driver + * + * Copyright(C) 2010 Corentin Chary + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#include "asus-wmi.h" + +#define ASUS_NB_WMI_FILE "asus-nb-wmi" + +MODULE_AUTHOR("Corentin Chary "); +MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver"); +MODULE_LICENSE("GPL"); + +#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" + +MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); + +static const struct key_entry asus_nb_wmi_keymap[] = { + { KE_KEY, 0x30, { KEY_VOLUMEUP } }, + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, + { KE_KEY, 0x32, { KEY_MUTE } }, + { KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */ + { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */ + { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, + { KE_KEY, 0x41, { KEY_NEXTSONG } }, + { KE_KEY, 0x43, { KEY_STOPCD } }, + { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, + { KE_KEY, 0x4c, { KEY_MEDIA } }, + { KE_KEY, 0x50, { KEY_EMAIL } }, + { KE_KEY, 0x51, { KEY_WWW } }, + { KE_KEY, 0x55, { KEY_CALC } }, + { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ + { KE_KEY, 0x5D, { KEY_WLAN } }, + { KE_KEY, 0x5E, { KEY_WLAN } }, + { KE_KEY, 0x5F, { KEY_WLAN } }, + { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, + { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, + { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, + { KE_KEY, 0x82, { KEY_CAMERA } }, + { KE_KEY, 0x88, { KEY_RFKILL } }, + { KE_KEY, 0x8A, { KEY_PROG1 } }, + { KE_KEY, 0x95, { KEY_MEDIA } }, + { KE_KEY, 0x99, { KEY_PHONE } }, + { KE_KEY, 0xb5, { KEY_CALC } }, + { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, + { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, + { KE_END, 0}, +}; + +static struct asus_wmi_driver asus_nb_wmi_driver = { + .name = ASUS_NB_WMI_FILE, + .owner = THIS_MODULE, + .event_guid = ASUS_NB_WMI_EVENT_GUID, + .keymap = asus_nb_wmi_keymap, + .input_name = "Asus WMI hotkeys", + .input_phys = ASUS_NB_WMI_FILE "/input0", +}; + + +static int __init asus_nb_wmi_init(void) +{ + return asus_wmi_register_driver(&asus_nb_wmi_driver); +} + +static void __exit asus_nb_wmi_exit(void) +{ + asus_wmi_unregister_driver(&asus_nb_wmi_driver); +} + +module_init(asus_nb_wmi_init); +module_exit(asus_nb_wmi_exit); -- cgit v1.2.2 From 2f686b54fbfcd82ebfb650a5c628c1b9ba8b9863 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:41 +0100 Subject: asus-wmi: add some common device ids and method ids I also found some leds ids (0x00020011-0x00020016 and 0x00040015), but since they are not really present on the notebook, I can't guess their name . Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 44 ++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 9095c28340cd..05db6b2067b5 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -66,25 +66,46 @@ MODULE_LICENSE("GPL"); #define NOTIFY_BRNDOWN_MAX 0x2e /* WMI Methods */ -#define ASUS_WMI_METHODID_SPEC 0x43455053 -#define ASUS_WMI_METHODID_SFUN 0x4E554653 -#define ASUS_WMI_METHODID_DSTS 0x53544344 -#define ASUS_WMI_METHODID_DSTS2 0x53545344 -#define ASUS_WMI_METHODID_DEVS 0x53564544 -#define ASUS_WMI_METHODID_CFVS 0x53564643 -#define ASUS_WMI_METHODID_INIT 0x54494E49 +#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ +#define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */ +#define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */ +#define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */ +#define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */ +#define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */ +#define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */ +#define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */ +#define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */ +#define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */ +#define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */ +#define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */ +#define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/ +#define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */ +#define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */ +#define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */ +#define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */ +#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */ +#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */ #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE /* Wireless */ +#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001 +#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 #define ASUS_WMI_DEVID_WLAN 0x00010011 #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 +#define ASUS_WMI_DEVID_GPS 0x00010015 #define ASUS_WMI_DEVID_WIMAX 0x00010017 #define ASUS_WMI_DEVID_WWAN3G 0x00010019 +#define ASUS_WMI_DEVID_UWB 0x00010021 + +/* Leds */ +/* 0x000200XX and 0x000400XX */ /* Backlight and Brightness */ #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 #define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 +#define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 +#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */ /* Misc */ #define ASUS_WMI_DEVID_CAMERA 0x00060013 @@ -96,10 +117,19 @@ MODULE_LICENSE("GPL"); #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 +/* Fan, Thermal */ +#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 +#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 + +/* Power */ +#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 + /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 #define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000 +#define ASUS_WMI_DSTS_USER_BIT 0x00020000 +#define ASUS_WMI_DSTS_BIOS_BIT 0x00040000 #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 -- cgit v1.2.2 From e07babde13460d7b03842a6de8f22fbef93709e1 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:42 +0100 Subject: asus-wmi: add hwmon interface and pwm1 Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/asus-wmi.c | 128 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 45f4d63c7939..0c7cf666a1bc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -458,6 +458,7 @@ config ASUS_WMI tristate "ASUS WMI Driver (EXPERIMENTAL)" depends on ACPI_WMI depends on INPUT + depends on HWMON depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL || RFKILL = n diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 05db6b2067b5..5b779a9443d6 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -167,6 +169,7 @@ struct asus_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; + struct device *hwmon_device; struct platform_device *platform_device; struct led_classdev tpd_led; @@ -790,6 +793,124 @@ exit: return result; } +/* + * Hwmon device + */ +static ssize_t asus_hwmon_pwm1(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct asus_wmi *asus = dev_get_drvdata(dev); + u32 value; + int err; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); + + if (err < 0) + return err; + + value |= 0xFF; + + if (value == 1) /* Low Speed */ + value = 85; + else if (value == 2) + value = 170; + else if (value == 3) + value = 255; + else if (value != 0) { + pr_err("Unknown fan speed %#x", value); + value = -1; + } + + return sprintf(buf, "%d\n", value); +} + +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); + +static ssize_t +show_name(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "asus\n"); +} +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); + +static struct attribute *hwmon_attributes[] = { + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_name.dev_attr.attr, + NULL +}; + +static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct platform_device *pdev = to_platform_device(dev->parent); + struct asus_wmi *asus = platform_get_drvdata(pdev); + bool ok = true; + int dev_id = -1; + u32 value = ASUS_WMI_UNSUPPORTED_METHOD; + + if (attr == &sensor_dev_attr_pwm1.dev_attr.attr) + dev_id = ASUS_WMI_DEVID_FAN_CTRL; + + if (dev_id != -1) { + int err = asus_wmi_get_devstate(asus, dev_id, &value); + + if (err < 0) + return err; + } + + if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) { + /* + * We need to find a better way, probably using sfun, + * bits or spec ... + * Currently we disable it if: + * - ASUS_WMI_UNSUPPORTED_METHOD is returned + * - reverved bits are non-zero + * - sfun and presence bit are not set + */ + if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 + || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) + ok = false; + } + + return ok ? attr->mode : 0; +} + +static struct attribute_group hwmon_attribute_group = { + .is_visible = asus_hwmon_sysfs_is_visible, + .attrs = hwmon_attributes +}; + +static void asus_wmi_hwmon_exit(struct asus_wmi *asus) +{ + struct device *hwmon; + + hwmon = asus->hwmon_device; + if (!hwmon) + return; + sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group); + hwmon_device_unregister(hwmon); + asus->hwmon_device = NULL; +} + +static int asus_wmi_hwmon_init(struct asus_wmi *asus) +{ + struct device *hwmon; + int result; + + hwmon = hwmon_device_register(&asus->platform_device->dev); + if (IS_ERR(hwmon)) { + pr_err("Could not register asus hwmon device\n"); + return PTR_ERR(hwmon); + } + asus->hwmon_device = hwmon; + result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group); + if (result) + asus_wmi_hwmon_exit(asus); + return result; +} + /* * Backlight */ @@ -1331,6 +1452,10 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_input; + err = asus_wmi_hwmon_init(asus); + if (err) + goto fail_hwmon; + err = asus_wmi_led_init(asus); if (err) goto fail_leds; @@ -1369,6 +1494,8 @@ fail_backlight: fail_rfkill: asus_wmi_led_exit(asus); fail_leds: + asus_wmi_hwmon_exit(asus); +fail_hwmon: asus_wmi_input_exit(asus); fail_input: asus_wmi_platform_exit(asus); @@ -1385,6 +1512,7 @@ static int asus_wmi_remove(struct platform_device *device) wmi_remove_notify_handler(asus->driver->event_guid); asus_wmi_backlight_exit(asus); asus_wmi_input_exit(asus); + asus_wmi_hwmon_exit(asus); asus_wmi_led_exit(asus); asus_wmi_rfkill_exit(asus); asus_wmi_debugfs_exit(asus); -- cgit v1.2.2 From 5f8540094d23b8886d671ff1faf875b698e2f299 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Sat, 26 Feb 2011 10:20:43 +0100 Subject: eeepc-wmi: restore KEY_CAMERA_* keys lost in 190ca27 Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index e69701fc422b..64e36de2285c 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -65,11 +65,17 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0x5d, { KEY_WLAN } }, { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ { KE_KEY, 0x82, { KEY_CAMERA } }, + { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, { KE_KEY, 0x88, { KEY_WLAN } }, { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, + { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, + { KE_KEY, 0xec, { KEY_CAMERA_UP } }, + { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, + { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, + { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, { KE_END, 0}, }; -- cgit v1.2.2 From 90ba4b1bfcf71bfe5c3844ddeb474aae4453cabd Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 22 Feb 2011 13:47:35 -0800 Subject: eeepc-wmi: kconfig changes to fix build errors Fix eeepc-wmi build when CONFIG_HOTPLUG_PCI is not enabled: eeepc-wmi.c:(.text+0x3bc5e9): undefined reference to `pci_hp_deregister' eeepc-wmi.c:(.text+0x3bcca4): undefined reference to `__pci_hp_register' Signed-off-by: Randy Dunlap Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0c7cf666a1bc..0253157085d3 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -462,6 +462,7 @@ config ASUS_WMI depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL || RFKILL = n + depends on HOTPLUG_PCI select INPUT_SPARSEKMAP select LEDS_CLASS select NEW_LEDS -- cgit v1.2.2 From 2165136585b5c7d6f118f1d90fbde550bb7de212 Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Wed, 23 Feb 2011 21:39:59 +0800 Subject: ideapad: read brightness setting on brightness key notify BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=25922 On ideapad Y530, the brightness key notify will be blocked if the last notify is not responsed by getting the brightness value. Read value when we get the notify shall fix the problem and will not have any difference on other ideapads. Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 114d95247cdf..21b101899bae 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -459,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event) if (test_bit(vpc_bit, &vpc1)) { if (vpc_bit == 9) ideapad_sync_rfk_state(adevice); + else if (vpc_bit == 4) + read_ec_data(handle, 0x12, &vpc2); else ideapad_input_report(priv, vpc_bit); } -- cgit v1.2.2 From 3b3e73f7d879f914f25605f74a71c2dad34bc329 Mon Sep 17 00:00:00 2001 From: Keng-Yu Lin Date: Tue, 1 Mar 2011 12:56:13 +0800 Subject: eeepc-wmi: set the touchpad toggle key code to KEY_TOUCHPAD_TOGGLE Signed-off-by: Keng-Yu Lin Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 64e36de2285c..0ddc434fb93b 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -63,7 +63,7 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0x32, { KEY_MUTE } }, { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ { KE_KEY, 0x5d, { KEY_WLAN } }, - { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ + { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */ { KE_KEY, 0x82, { KEY_CAMERA } }, { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, { KE_KEY, 0x88, { KEY_WLAN } }, -- cgit v1.2.2 From f11113b22cd84b0adc355eaaa80be433005f5f45 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 26 Feb 2011 15:54:27 +0300 Subject: sony-laptop: make a couple variables static Sparse complains that these variables should be static. Signed-off-by: Dan Carpenter Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index d28a4a58a497..60d83343fb01 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -745,7 +745,7 @@ struct sony_nc_handles { struct device_attribute devattr; }; -struct sony_nc_handles *handles; +static struct sony_nc_handles *handles; static ssize_t sony_nc_handles_show(struct device *dev, struct device_attribute *attr, char *buffer) @@ -1358,7 +1358,7 @@ struct kbd_backlight { struct device_attribute timeout_attr; }; -struct kbd_backlight *kbdbl_handle; +static struct kbd_backlight *kbdbl_handle; static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) { -- cgit v1.2.2 From 7227dedbc22f66f1bd310c866053b08de0496e38 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 26 Feb 2011 15:54:57 +0300 Subject: sony-laptop: return negative on failure in sony_nc_add() There were two places in sony_nc_add() where we returned zero on failure instead of a negative error code. Signed-off-by: Dan Carpenter Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 60d83343fb01..363b89ef61cc 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1594,9 +1594,11 @@ static int sony_nc_add(struct acpi_device *device) if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", &handle))) { dprintk("Doing SNC setup\n"); - if (sony_nc_handles_setup(sony_pf_device)) + result = sony_nc_handles_setup(sony_pf_device); + if (result) goto outpresent; - if (sony_nc_kbd_backlight_setup(sony_pf_device)) + result = sony_nc_kbd_backlight_setup(sony_pf_device); + if (result) goto outsnc; sony_nc_function_setup(device); sony_nc_rfkill_setup(device); -- cgit v1.2.2 From 31f007598cc547ba3239524470386af8ae5f1c13 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 26 Feb 2011 15:55:24 +0300 Subject: sony-laptop: handle allocation failures Return -ENOMEM if kzalloc() fails. The callers already handle error returns. Signed-off-by: Dan Carpenter Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 363b89ef61cc..bd1b9adfbaf9 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -768,6 +768,8 @@ static int sony_nc_handles_setup(struct platform_device *pd) int result; handles = kzalloc(sizeof(*handles), GFP_KERNEL); + if (!handles) + return -ENOMEM; sysfs_attr_init(&handles->devattr.attr); handles->devattr.attr.name = "handles"; @@ -1458,6 +1460,8 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd) return 0; kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); + if (!kbdbl_handle) + return -ENOMEM; sysfs_attr_init(&kbdbl_handle->mode_attr.attr); kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; -- cgit v1.2.2 From 200140bdb52b259380e9082e2a4f25a4ddbb5d68 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 27 Feb 2011 17:13:25 +0300 Subject: sony-laptop: potential null dereference In the original code, if "device_enum" was NULL then it would dereference it when it printed the error message. Signed-off-by: Dan Carpenter Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index bd1b9adfbaf9..4ab898a39fea 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -1311,7 +1311,11 @@ static void sony_nc_rfkill_setup(struct acpi_device *device) } device_enum = (union acpi_object *) buffer.pointer; - if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) { + if (!device_enum) { + pr_err(DRV_PFX "No SN06 return object."); + goto out_no_enum; + } + if (device_enum->type != ACPI_TYPE_BUFFER) { pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n", device_enum->type); goto out_no_enum; -- cgit v1.2.2 From 47ae4352bece7b617a084770495b993fcd1a2be5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 26 Feb 2011 23:03:34 +0800 Subject: platform-driver-x86: intel_mid_thermal: fix unterminated platform_device_id table The platform_device_id table is supposed to be zero-terminated. Signed-off-by: Axel Lin Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_mid_thermal.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 1215c3096868..6c12db503161 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -543,6 +543,7 @@ static int mid_thermal_remove(struct platform_device *pdev) static const struct platform_device_id therm_id_table[] = { { DRIVER_NAME, 1 }, + { } }; static struct platform_driver mid_thermal_driver = { -- cgit v1.2.2 From 8941178efad900e48e44000208513a6426c74368 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Wed, 2 Mar 2011 01:07:11 +0800 Subject: acer-wmi: set the touchpad toggle key code to KEY_TOUCHPAD_TOGGLE Set the touchpad toggle key code from F22 to KEY_TOUCHPAD_TOGGLE, and userspace should use udev's key re-mapping facilities while X is unable to process keycodes above 255 to adjust to the keycode. Cc: Matthew Garrett Cc: Dmitry Torokhov Cc: Corentin Chary Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c9784705f6ac..a8acf35d7475 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -108,7 +108,7 @@ static const struct key_entry acer_wmi_keymap[] = { {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ - {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ + {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */ {KE_END, 0} }; -- cgit v1.2.2 From 143a4c0284dc2378b3ce78866b3548d90121d843 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Mon, 7 Mar 2011 15:46:28 +0800 Subject: msi-laptop: send out touchpad on/off key MSI BIOS's raw behavior is send out KEY_TOUCHPAD_TOGGLE key when user pressed touchpad hotkey. Actually, we can capture the real touchpad status by read 0xE4 EC address on MSI netbook/notebook. So, add msi-laptop input device for send out KEY_TOUCHPAD_ON or KEY_TOUCHPAD_OFF key when user pressed Fn+F3 touchpad hotkey. It leave userland applications to know the real touchpad status. Tested on MSI netbook U-100, U-115, U160(N051), U160DX, N014, N034 Tested on MSI notebook CR620 Cc: Carlos Corbacho Cc: Matthew Garrett Cc: Dmitry Torokhov Cc: Corentin Chary Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett --- drivers/platform/x86/msi-laptop.c | 81 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 142d38579314..fb4da28f5906 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -60,6 +60,8 @@ #include #include #include +#include +#include #define MSI_DRIVER_VERSION "0.5" @@ -78,6 +80,9 @@ #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) +#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4 +#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4) + static int msi_laptop_resume(struct platform_device *device); #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f @@ -90,6 +95,14 @@ static int auto_brightness; module_param(auto_brightness, int, 0); MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); +static const struct key_entry msi_laptop_keymap[] = { + {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */ + {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */ + {KE_END, 0} +}; + +static struct input_dev *msi_laptop_input_dev; + static bool old_ec_model; static int wlan_s, bluetooth_s, threeg_s; static int threeg_exists; @@ -605,6 +618,21 @@ static void msi_update_rfkill(struct work_struct *ignored) } static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); +static void msi_send_touchpad_key(struct work_struct *ignored) +{ + u8 rdata; + int result; + + result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata); + if (result < 0) + return; + + sparse_keymap_report_event(msi_laptop_input_dev, + (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? + KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); +} +static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); + static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, struct serio *port) { @@ -613,12 +641,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, if (str & 0x20) return false; - /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ + /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/ if (unlikely(data == 0xe0)) { extended = true; return false; } else if (unlikely(extended)) { + extended = false; switch (data) { + case 0xE4: + schedule_delayed_work(&msi_touchpad_work, + round_jiffies_relative(0.5 * HZ)); + break; case 0x54: case 0x62: case 0x76: @@ -626,7 +659,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, round_jiffies_relative(0.5 * HZ)); break; } - extended = false; } return false; @@ -731,6 +763,42 @@ static int msi_laptop_resume(struct platform_device *device) return 0; } +static int __init msi_laptop_input_setup(void) +{ + int err; + + msi_laptop_input_dev = input_allocate_device(); + if (!msi_laptop_input_dev) + return -ENOMEM; + + msi_laptop_input_dev->name = "MSI Laptop hotkeys"; + msi_laptop_input_dev->phys = "msi-laptop/input0"; + msi_laptop_input_dev->id.bustype = BUS_HOST; + + err = sparse_keymap_setup(msi_laptop_input_dev, + msi_laptop_keymap, NULL); + if (err) + goto err_free_dev; + + err = input_register_device(msi_laptop_input_dev); + if (err) + goto err_free_keymap; + + return 0; + +err_free_keymap: + sparse_keymap_free(msi_laptop_input_dev); +err_free_dev: + input_free_device(msi_laptop_input_dev); + return err; +} + +static void msi_laptop_input_destroy(void) +{ + sparse_keymap_free(msi_laptop_input_dev); + input_unregister_device(msi_laptop_input_dev); +} + static int load_scm_model_init(struct platform_device *sdev) { u8 data; @@ -759,6 +827,11 @@ static int load_scm_model_init(struct platform_device *sdev) if (result < 0) goto fail_rfkill; + /* setup input device */ + result = msi_laptop_input_setup(); + if (result) + goto fail_input; + result = i8042_install_filter(msi_laptop_i8042_filter); if (result) { printk(KERN_ERR @@ -769,6 +842,9 @@ static int load_scm_model_init(struct platform_device *sdev) return 0; fail_filter: + msi_laptop_input_destroy(); + +fail_input: rfkill_cleanup(); fail_rfkill: @@ -886,6 +962,7 @@ static void __exit msi_cleanup(void) { if (load_scm_model) { i8042_remove_filter(msi_laptop_i8042_filter); + msi_laptop_input_destroy(); cancel_delayed_work_sync(&msi_rfkill_work); rfkill_cleanup(); } -- cgit v1.2.2 From 9a0b74fd873005122145364d3dfe4e1c9da1dad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Sat, 26 Feb 2011 21:18:58 +0100 Subject: acer-wmi: deactive mail led when power off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch deactive mail led when laptop is going to hibernete/suspend or power off. After resume from hibernate/suspend correctly restore mail led state. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index a8acf35d7475..4c8209376985 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -991,6 +991,7 @@ static int __devinit acer_led_init(struct device *dev) static void acer_led_exit(void) { + set_u32(LED_OFF, ACER_CAP_MAILLED); led_classdev_unregister(&mail_led); } @@ -1553,6 +1554,7 @@ pm_message_t state) if (has_cap(ACER_CAP_MAILLED)) { get_u32(&value, ACER_CAP_MAILLED); + set_u32(LED_OFF, ACER_CAP_MAILLED); data->mailled = value; } @@ -1580,6 +1582,17 @@ static int acer_platform_resume(struct platform_device *device) return 0; } +static void acer_platform_shutdown(struct platform_device *device) +{ + struct acer_data *data = &interface->data; + + if (!data) + return; + + if (has_cap(ACER_CAP_MAILLED)) + set_u32(LED_OFF, ACER_CAP_MAILLED); +} + static struct platform_driver acer_platform_driver = { .driver = { .name = "acer-wmi", @@ -1589,6 +1602,7 @@ static struct platform_driver acer_platform_driver = { .remove = acer_platform_remove, .suspend = acer_platform_suspend, .resume = acer_platform_resume, + .shutdown = acer_platform_shutdown, }; static struct platform_device *acer_platform_device; -- cgit v1.2.2 From 298f19b2547ba11a577a15ca329daa6f4bbf5ad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Fri, 11 Mar 2011 12:36:43 -0500 Subject: acer-wmi: Fix WMI ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch change WMI ID to upper characters. With this patch module acer-wmi is automatically loaded when WMI ID is detected. Signed-off-by: Pali Rohár Tested-by: Pali Rohár Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 4c8209376985..c1036d288f19 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -84,7 +84,7 @@ MODULE_LICENSE("GPL"); #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" #define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" -#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" +#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A" #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" /* @@ -93,7 +93,7 @@ MODULE_LICENSE("GPL"); #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); -MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); +MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); enum acer_wmi_event_ids { -- cgit v1.2.2 From 2d70b73ae5b85c9d13f5dfbb8fc4fd5edae633dc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 11 Mar 2011 12:41:19 -0500 Subject: Platform: add Samsung Laptop platform driver This adds the samsung-laptop driver to the kernel. It now supports all known Samsung laptops that use the SABI interface. Signed-off-by: Greg Kroah-Hartman Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 13 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/samsung-laptop.c | 832 ++++++++++++++++++++++++++++++++++ 3 files changed, 846 insertions(+) create mode 100644 drivers/platform/x86/samsung-laptop.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0253157085d3..2ee442c2a5db 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -739,4 +739,17 @@ config XO15_EBOOK This switch is triggered as the screen is rotated and folded down to convert the device into ebook form. +config SAMSUNG_LAPTOP + tristate "Samsung Laptop driver" + depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 + ---help--- + This module implements a driver for a wide range of different + Samsung laptops. It offers control over the different + function keys, wireless LED, LCD backlight level, and + sometimes provides a "performance_control" sysfs file to allow + the performance level of the laptop to be changed. + + To compile this driver as a module, choose M here: the module + will be called samsung-laptop. + endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 0f7b23c0714b..029e8861d086 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -40,4 +40,5 @@ obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o obj-$(CONFIG_IBM_RTL) += ibm_rtl.o +obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c new file mode 100644 index 000000000000..e0b390d45d8d --- /dev/null +++ b/drivers/platform/x86/samsung-laptop.c @@ -0,0 +1,832 @@ +/* + * Samsung Laptop driver + * + * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) + * Copyright (C) 2009,2011 Novell Inc. + * + * 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. + * + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This driver is needed because a number of Samsung laptops do not hook + * their control settings through ACPI. So we have to poke around in the + * BIOS to do things like brightness values, and "special" key controls. + */ + +/* + * We have 0 - 8 as valid brightness levels. The specs say that level 0 should + * be reserved by the BIOS (which really doesn't make much sense), we tell + * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8 + */ +#define MAX_BRIGHT 0x07 + + +#define SABI_IFACE_MAIN 0x00 +#define SABI_IFACE_SUB 0x02 +#define SABI_IFACE_COMPLETE 0x04 +#define SABI_IFACE_DATA 0x05 + +/* Structure to get data back to the calling function */ +struct sabi_retval { + u8 retval[20]; +}; + +struct sabi_header_offsets { + u8 port; + u8 re_mem; + u8 iface_func; + u8 en_mem; + u8 data_offset; + u8 data_segment; +}; + +struct sabi_commands { + /* + * Brightness is 0 - 8, as described above. + * Value 0 is for the BIOS to use + */ + u8 get_brightness; + u8 set_brightness; + + /* + * first byte: + * 0x00 - wireless is off + * 0x01 - wireless is on + * second byte: + * 0x02 - 3G is off + * 0x03 - 3G is on + * TODO, verify 3G is correct, that doesn't seem right... + */ + u8 get_wireless_button; + u8 set_wireless_button; + + /* 0 is off, 1 is on */ + u8 get_backlight; + u8 set_backlight; + + /* + * 0x80 or 0x00 - no action + * 0x81 - recovery key pressed + */ + u8 get_recovery_mode; + u8 set_recovery_mode; + + /* + * on seclinux: 0 is low, 1 is high, + * on swsmi: 0 is normal, 1 is silent, 2 is turbo + */ + u8 get_performance_level; + u8 set_performance_level; + + /* + * Tell the BIOS that Linux is running on this machine. + * 81 is on, 80 is off + */ + u8 set_linux; +}; + +struct sabi_performance_level { + const char *name; + u8 value; +}; + +struct sabi_config { + const char *test_string; + u16 main_function; + const struct sabi_header_offsets header_offsets; + const struct sabi_commands commands; + const struct sabi_performance_level performance_levels[4]; + u8 min_brightness; + u8 max_brightness; +}; + +static const struct sabi_config sabi_configs[] = { + { + .test_string = "SECLINUX", + + .main_function = 0x4c49, + + .header_offsets = { + .port = 0x00, + .re_mem = 0x02, + .iface_func = 0x03, + .en_mem = 0x04, + .data_offset = 0x05, + .data_segment = 0x07, + }, + + .commands = { + .get_brightness = 0x00, + .set_brightness = 0x01, + + .get_wireless_button = 0x02, + .set_wireless_button = 0x03, + + .get_backlight = 0x04, + .set_backlight = 0x05, + + .get_recovery_mode = 0x06, + .set_recovery_mode = 0x07, + + .get_performance_level = 0x08, + .set_performance_level = 0x09, + + .set_linux = 0x0a, + }, + + .performance_levels = { + { + .name = "silent", + .value = 0, + }, + { + .name = "normal", + .value = 1, + }, + { }, + }, + .min_brightness = 1, + .max_brightness = 8, + }, + { + .test_string = "SwSmi@", + + .main_function = 0x5843, + + .header_offsets = { + .port = 0x00, + .re_mem = 0x04, + .iface_func = 0x02, + .en_mem = 0x03, + .data_offset = 0x05, + .data_segment = 0x07, + }, + + .commands = { + .get_brightness = 0x10, + .set_brightness = 0x11, + + .get_wireless_button = 0x12, + .set_wireless_button = 0x13, + + .get_backlight = 0x2d, + .set_backlight = 0x2e, + + .get_recovery_mode = 0xff, + .set_recovery_mode = 0xff, + + .get_performance_level = 0x31, + .set_performance_level = 0x32, + + .set_linux = 0xff, + }, + + .performance_levels = { + { + .name = "normal", + .value = 0, + }, + { + .name = "silent", + .value = 1, + }, + { + .name = "overclock", + .value = 2, + }, + { }, + }, + .min_brightness = 0, + .max_brightness = 8, + }, + { }, +}; + +static const struct sabi_config *sabi_config; + +static void __iomem *sabi; +static void __iomem *sabi_iface; +static void __iomem *f0000_segment; +static struct backlight_device *backlight_device; +static struct mutex sabi_mutex; +static struct platform_device *sdev; +static struct rfkill *rfk; + +static int force; +module_param(force, bool, 0); +MODULE_PARM_DESC(force, + "Disable the DMI check and forces the driver to be loaded"); + +static int debug; +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); + +static int sabi_get_command(u8 command, struct sabi_retval *sretval) +{ + int retval = 0; + u16 port = readw(sabi + sabi_config->header_offsets.port); + u8 complete, iface_data; + + mutex_lock(&sabi_mutex); + + /* enable memory to be able to write to it */ + outb(readb(sabi + sabi_config->header_offsets.en_mem), port); + + /* write out the command */ + writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); + writew(command, sabi_iface + SABI_IFACE_SUB); + writeb(0, sabi_iface + SABI_IFACE_COMPLETE); + outb(readb(sabi + sabi_config->header_offsets.iface_func), port); + + /* write protect memory to make it safe */ + outb(readb(sabi + sabi_config->header_offsets.re_mem), port); + + /* see if the command actually succeeded */ + complete = readb(sabi_iface + SABI_IFACE_COMPLETE); + iface_data = readb(sabi_iface + SABI_IFACE_DATA); + if (complete != 0xaa || iface_data == 0xff) { + pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", + command, complete, iface_data); + retval = -EINVAL; + goto exit; + } + /* + * Save off the data into a structure so the caller use it. + * Right now we only want the first 4 bytes, + * There are commands that need more, but not for the ones we + * currently care about. + */ + sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA); + sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1); + sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2); + sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3); + +exit: + mutex_unlock(&sabi_mutex); + return retval; + +} + +static int sabi_set_command(u8 command, u8 data) +{ + int retval = 0; + u16 port = readw(sabi + sabi_config->header_offsets.port); + u8 complete, iface_data; + + mutex_lock(&sabi_mutex); + + /* enable memory to be able to write to it */ + outb(readb(sabi + sabi_config->header_offsets.en_mem), port); + + /* write out the command */ + writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); + writew(command, sabi_iface + SABI_IFACE_SUB); + writeb(0, sabi_iface + SABI_IFACE_COMPLETE); + writeb(data, sabi_iface + SABI_IFACE_DATA); + outb(readb(sabi + sabi_config->header_offsets.iface_func), port); + + /* write protect memory to make it safe */ + outb(readb(sabi + sabi_config->header_offsets.re_mem), port); + + /* see if the command actually succeeded */ + complete = readb(sabi_iface + SABI_IFACE_COMPLETE); + iface_data = readb(sabi_iface + SABI_IFACE_DATA); + if (complete != 0xaa || iface_data == 0xff) { + pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", + command, complete, iface_data); + retval = -EINVAL; + } + + mutex_unlock(&sabi_mutex); + return retval; +} + +static void test_backlight(void) +{ + struct sabi_retval sretval; + + sabi_get_command(sabi_config->commands.get_backlight, &sretval); + printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); + + sabi_set_command(sabi_config->commands.set_backlight, 0); + printk(KERN_DEBUG "backlight should be off\n"); + + sabi_get_command(sabi_config->commands.get_backlight, &sretval); + printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); + + msleep(1000); + + sabi_set_command(sabi_config->commands.set_backlight, 1); + printk(KERN_DEBUG "backlight should be on\n"); + + sabi_get_command(sabi_config->commands.get_backlight, &sretval); + printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); +} + +static void test_wireless(void) +{ + struct sabi_retval sretval; + + sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); + printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); + + sabi_set_command(sabi_config->commands.set_wireless_button, 0); + printk(KERN_DEBUG "wireless led should be off\n"); + + sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); + printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); + + msleep(1000); + + sabi_set_command(sabi_config->commands.set_wireless_button, 1); + printk(KERN_DEBUG "wireless led should be on\n"); + + sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); + printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); +} + +static u8 read_brightness(void) +{ + struct sabi_retval sretval; + int user_brightness = 0; + int retval; + + retval = sabi_get_command(sabi_config->commands.get_brightness, + &sretval); + if (!retval) { + user_brightness = sretval.retval[0]; + if (user_brightness != 0) + user_brightness -= sabi_config->min_brightness; + } + return user_brightness; +} + +static void set_brightness(u8 user_brightness) +{ + u8 user_level = user_brightness - sabi_config->min_brightness; + + sabi_set_command(sabi_config->commands.set_brightness, user_level); +} + +static int get_brightness(struct backlight_device *bd) +{ + return (int)read_brightness(); +} + +static int update_status(struct backlight_device *bd) +{ + set_brightness(bd->props.brightness); + + if (bd->props.power == FB_BLANK_UNBLANK) + sabi_set_command(sabi_config->commands.set_backlight, 1); + else + sabi_set_command(sabi_config->commands.set_backlight, 0); + return 0; +} + +static const struct backlight_ops backlight_ops = { + .get_brightness = get_brightness, + .update_status = update_status, +}; + +static int rfkill_set(void *data, bool blocked) +{ + /* Do something with blocked...*/ + /* + * blocked == false is on + * blocked == true is off + */ + if (blocked) + sabi_set_command(sabi_config->commands.set_wireless_button, 0); + else + sabi_set_command(sabi_config->commands.set_wireless_button, 1); + + return 0; +} + +static struct rfkill_ops rfkill_ops = { + .set_block = rfkill_set, +}; + +static int init_wireless(struct platform_device *sdev) +{ + int retval; + + rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, + &rfkill_ops, NULL); + if (!rfk) + return -ENOMEM; + + retval = rfkill_register(rfk); + if (retval) { + rfkill_destroy(rfk); + return -ENODEV; + } + + return 0; +} + +static void destroy_wireless(void) +{ + rfkill_unregister(rfk); + rfkill_destroy(rfk); +} + +static ssize_t get_performance_level(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sabi_retval sretval; + int retval; + int i; + + /* Read the state */ + retval = sabi_get_command(sabi_config->commands.get_performance_level, + &sretval); + if (retval) + return retval; + + /* The logic is backwards, yeah, lots of fun... */ + for (i = 0; sabi_config->performance_levels[i].name; ++i) { + if (sretval.retval[0] == sabi_config->performance_levels[i].value) + return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); + } + return sprintf(buf, "%s\n", "unknown"); +} + +static ssize_t set_performance_level(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + if (count >= 1) { + int i; + for (i = 0; sabi_config->performance_levels[i].name; ++i) { + const struct sabi_performance_level *level = + &sabi_config->performance_levels[i]; + if (!strncasecmp(level->name, buf, strlen(level->name))) { + sabi_set_command(sabi_config->commands.set_performance_level, + level->value); + break; + } + } + if (!sabi_config->performance_levels[i].name) + return -EINVAL; + } + return count; +} +static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, + get_performance_level, set_performance_level); + + +static int __init dmi_check_cb(const struct dmi_system_id *id) +{ + pr_info("found laptop model '%s'\n", + id->ident); + return 0; +} + +static struct dmi_system_id __initdata samsung_dmi_table[] = { + { + .ident = "N128", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N128"), + DMI_MATCH(DMI_BOARD_NAME, "N128"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "N130", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N130"), + DMI_MATCH(DMI_BOARD_NAME, "N130"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "X125", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "X125"), + DMI_MATCH(DMI_BOARD_NAME, "X125"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "X120/X170", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), + DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "NC10", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), + DMI_MATCH(DMI_BOARD_NAME, "NC10"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "NP-Q45", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), + DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "X360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "X360"), + DMI_MATCH(DMI_BOARD_NAME, "X360"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "R518", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R518"), + DMI_MATCH(DMI_BOARD_NAME, "R518"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "R519/R719", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), + DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "N150/N210/N220", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "N150P/N210P/N220P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), + DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "R530/R730", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), + DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "NF110/NF210/NF310", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), + DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "N145P/N250P/N260P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), + DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "R70/R71", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), + DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), + }, + .callback = dmi_check_cb, + }, + { + .ident = "P460", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "P460"), + DMI_MATCH(DMI_BOARD_NAME, "P460"), + }, + .callback = dmi_check_cb, + }, + { }, +}; +MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); + +static int find_signature(void __iomem *memcheck, const char *testStr) +{ + int i = 0; + int loca; + + for (loca = 0; loca < 0xffff; loca++) { + char temp = readb(memcheck + loca); + + if (temp == testStr[i]) { + if (i == strlen(testStr)-1) + break; + ++i; + } else { + i = 0; + } + } + return loca; +} + +static int __init samsung_init(void) +{ + struct backlight_properties props; + struct sabi_retval sretval; + unsigned int ifaceP; + int i; + int loca; + int retval; + + mutex_init(&sabi_mutex); + + if (!force && !dmi_check_system(samsung_dmi_table)) + return -ENODEV; + + f0000_segment = ioremap_nocache(0xf0000, 0xffff); + if (!f0000_segment) { + pr_err("Can't map the segment at 0xf0000\n"); + return -EINVAL; + } + + /* Try to find one of the signatures in memory to find the header */ + for (i = 0; sabi_configs[i].test_string != 0; ++i) { + sabi_config = &sabi_configs[i]; + loca = find_signature(f0000_segment, sabi_config->test_string); + if (loca != 0xffff) + break; + } + + if (loca == 0xffff) { + pr_err("This computer does not support SABI\n"); + goto error_no_signature; + } + + /* point to the SMI port Number */ + loca += 1; + sabi = (f0000_segment + loca); + + if (debug) { + printk(KERN_DEBUG "This computer supports SABI==%x\n", + loca + 0xf0000 - 6); + printk(KERN_DEBUG "SABI header:\n"); + printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", + readw(sabi + sabi_config->header_offsets.port)); + printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", + readb(sabi + sabi_config->header_offsets.iface_func)); + printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", + readb(sabi + sabi_config->header_offsets.en_mem)); + printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", + readb(sabi + sabi_config->header_offsets.re_mem)); + printk(KERN_DEBUG " SABI data offset = 0x%04x\n", + readw(sabi + sabi_config->header_offsets.data_offset)); + printk(KERN_DEBUG " SABI data segment = 0x%04x\n", + readw(sabi + sabi_config->header_offsets.data_segment)); + } + + /* Get a pointer to the SABI Interface */ + ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; + ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; + sabi_iface = ioremap_nocache(ifaceP, 16); + if (!sabi_iface) { + pr_err("Can't remap %x\n", ifaceP); + goto exit; + } + if (debug) { + printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); + printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); + + test_backlight(); + test_wireless(); + + retval = sabi_get_command(sabi_config->commands.get_brightness, + &sretval); + printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); + } + + /* Turn on "Linux" mode in the BIOS */ + if (sabi_config->commands.set_linux != 0xff) { + retval = sabi_set_command(sabi_config->commands.set_linux, + 0x81); + if (retval) { + pr_warn("Linux mode was not set!\n"); + goto error_no_platform; + } + } + + /* knock up a platform device to hang stuff off of */ + sdev = platform_device_register_simple("samsung", -1, NULL, 0); + if (IS_ERR(sdev)) + goto error_no_platform; + + /* create a backlight device to talk to this one */ + memset(&props, 0, sizeof(struct backlight_properties)); + props.max_brightness = sabi_config->max_brightness; + backlight_device = backlight_device_register("samsung", &sdev->dev, + NULL, &backlight_ops, + &props); + if (IS_ERR(backlight_device)) + goto error_no_backlight; + + backlight_device->props.brightness = read_brightness(); + backlight_device->props.power = FB_BLANK_UNBLANK; + backlight_update_status(backlight_device); + + retval = init_wireless(sdev); + if (retval) + goto error_no_rfk; + + retval = device_create_file(&sdev->dev, &dev_attr_performance_level); + if (retval) + goto error_file_create; + +exit: + return 0; + +error_file_create: + destroy_wireless(); + +error_no_rfk: + backlight_device_unregister(backlight_device); + +error_no_backlight: + platform_device_unregister(sdev); + +error_no_platform: + iounmap(sabi_iface); + +error_no_signature: + iounmap(f0000_segment); + return -EINVAL; +} + +static void __exit samsung_exit(void) +{ + /* Turn off "Linux" mode in the BIOS */ + if (sabi_config->commands.set_linux != 0xff) + sabi_set_command(sabi_config->commands.set_linux, 0x80); + + device_remove_file(&sdev->dev, &dev_attr_performance_level); + backlight_device_unregister(backlight_device); + destroy_wireless(); + iounmap(sabi_iface); + iounmap(f0000_segment); + platform_device_unregister(sdev); +} + +module_init(samsung_init); +module_exit(samsung_exit); + +MODULE_AUTHOR("Greg Kroah-Hartman "); +MODULE_DESCRIPTION("Samsung Backlight driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From bbe24fee22fa045a07ff7e926589ac722c7ee78d Mon Sep 17 00:00:00 2001 From: Joey Lee Date: Wed, 16 Mar 2011 01:55:19 -0600 Subject: msi-laptop: use pr_ for messages msi-laptop: use pr_ for messages Cc: Carlos Corbacho Cc: Matthew Garrett Cc: Dmitry Torokhov Cc: Corentin Chary Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett --- drivers/platform/x86/msi-laptop.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index fb4da28f5906..23fb2afda00b 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -51,6 +51,8 @@ * laptop as MSI S270. YMMV. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -445,8 +447,7 @@ static struct platform_device *msipf_device; static int dmi_check_cb(const struct dmi_system_id *id) { - printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", - id->ident); + pr_info("Identified laptop model '%s'.\n", id->ident); return 1; } @@ -834,8 +835,7 @@ static int load_scm_model_init(struct platform_device *sdev) result = i8042_install_filter(msi_laptop_i8042_filter); if (result) { - printk(KERN_ERR - "msi-laptop: Unable to install key filter\n"); + pr_err("Unable to install key filter\n"); goto fail_filter; } @@ -875,7 +875,7 @@ static int __init msi_init(void) /* Register backlight stuff */ if (acpi_video_backlight_support()) { - printk(KERN_INFO "MSI: Brightness ignored, must be controlled " + pr_info("Brightness ignored, must be controlled " "by ACPI video driver\n"); } else { struct backlight_properties props; @@ -930,7 +930,7 @@ static int __init msi_init(void) if (auto_brightness != 2) set_auto_brightness(auto_brightness); - printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); + pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n"); return 0; @@ -978,7 +978,7 @@ static void __exit msi_cleanup(void) if (auto_brightness != 2) set_auto_brightness(1); - printk(KERN_INFO "msi-laptop: driver unloaded.\n"); + pr_info("driver unloaded.\n"); } module_init(msi_init); -- cgit v1.2.2 From 0e4510f7c9708304104c07e87b7e5e78fb1716d1 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 14 Mar 2011 18:53:14 +0800 Subject: platform-driver-x86: fix wrong merge for compal-laptop.c I found the commit 80183a4b "compal-laptop/fujitsu-laptop/msi-laptop: make dmi_check_cb to return 1 instead of 0" has wrong patch merge. The original patch change the return value for dmi_check_cb(): https://lkml.org/lkml/2010/7/2/88 But commit 80183a4b changed the return value for set_backlight_level. Signed-off-by: Axel Lin Signed-off-by: Matthew Garrett --- drivers/platform/x86/compal-laptop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index eb95878fa583..3994c80549fb 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -275,7 +275,7 @@ static int set_backlight_level(int level) ec_write(BACKLIGHT_LEVEL_ADDR, level); - return 1; + return 0; } static int get_backlight_level(void) @@ -763,7 +763,7 @@ static int dmi_check_cb(const struct dmi_system_id *id) printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", id->ident); extra_features = false; - return 0; + return 1; } static int dmi_check_cb_extra(const struct dmi_system_id *id) @@ -772,7 +772,7 @@ static int dmi_check_cb_extra(const struct dmi_system_id *id) "enabling extra features\n", id->ident); extra_features = true; - return 0; + return 1; } static struct dmi_system_id __initdata compal_dmi_table[] = { -- cgit v1.2.2 From 2783658477205b0cf31e5c02d69214e36fe59aae Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 14 Mar 2011 18:56:18 +0800 Subject: platform-driver-x86: samsung-laptop: make dmi_check_cb to return 1 instead of 0 dmi_check_system() walks the table running matching functions until someone returns non zero or we hit the end. This patch makes dmi_check_cb to return 1 so dmi_check_system() return immediately when a match is found. Signed-off-by: Axel Lin Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index e0b390d45d8d..de434c6dc2d6 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -496,7 +496,7 @@ static int __init dmi_check_cb(const struct dmi_system_id *id) { pr_info("found laptop model '%s'\n", id->ident); - return 0; + return 1; } static struct dmi_system_id __initdata samsung_dmi_table[] = { -- cgit v1.2.2 From 0986f25fbba8827762b35222bb45d2fbb2d72fa4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 Mar 2011 10:06:23 +0300 Subject: asus-wmi: signedness bug in read_brightness() "err" needs to be signed for the error handling to work. Signed-off-by: Dan Carpenter Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 5b779a9443d6..a038595200ee 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -946,7 +946,8 @@ static int read_brightness_max(struct asus_wmi *asus) static int read_brightness(struct backlight_device *bd) { struct asus_wmi *asus = bl_get_data(bd); - u32 retval, err; + u32 retval; + int err; err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); -- cgit v1.2.2 From a1d6086739c5b8f23a48e02e62b0e495321a2122 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 15 Mar 2011 10:07:37 +0300 Subject: asus-wmi: potential NULL dereference in show_call() In the earlier check we assumed that "obj" could be NULL. I looked at some of the other places that call evaluate_object() and they check for NULL as well. Signed-off-by: Dan Carpenter Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index a038595200ee..efc776cb0c66 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1343,7 +1343,7 @@ static int show_call(struct seq_file *m, void *data) else seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id, asus->debug.dev_id, asus->debug.ctrl_param, - obj->type); + obj ? obj->type : -1); kfree(obj); -- cgit v1.2.2 From cae157026491d2e9a789b876a367dee7b17235cb Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Wed, 16 Mar 2011 18:52:36 +0800 Subject: acer-wmi: use pr_ for messages acer-wmi: use pr_ for messages Cc: Carlos Corbacho Cc: Matthew Garrett Cc: Corentin Chary Cc: Dmitry Torokhov Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 68 +++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c1036d288f19..d798314b81fe 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -22,6 +22,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -46,12 +48,6 @@ MODULE_AUTHOR("Carlos Corbacho"); MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); MODULE_LICENSE("GPL"); -#define ACER_LOGPREFIX "acer-wmi: " -#define ACER_ERR KERN_ERR ACER_LOGPREFIX -#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX -#define ACER_INFO KERN_INFO ACER_LOGPREFIX -#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX - /* * Magic Number * Meaning is unknown - this number is required for writing to ACPI for AMW0 @@ -845,7 +841,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy) has_type_aa = true; type_aa = (struct hotkey_function_type_aa *) header; - printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n", + pr_info("Function bitmap for Communication Button: 0x%x\n", type_aa->commun_func_bitmap); if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) @@ -1037,7 +1033,7 @@ static int __devinit acer_backlight_init(struct device *dev) bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, &props); if (IS_ERR(bd)) { - printk(ACER_ERR "Could not register Acer backlight device\n"); + pr_err("Could not register Acer backlight device\n"); acer_backlight_device = NULL; return PTR_ERR(bd); } @@ -1084,8 +1080,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device) return AE_ERROR; } if (obj->buffer.length != 8) { - printk(ACER_WARNING "Unknown buffer length %d\n", - obj->buffer.length); + pr_warning("Unknown buffer length %d\n", obj->buffer.length); kfree(obj); return AE_ERROR; } @@ -1094,7 +1089,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device) kfree(obj); if (return_value.error_code || return_value.ec_return_value) - printk(ACER_WARNING "Get Device Status failed: " + pr_warning("Get Device Status failed: " "0x%x - 0x%x\n", return_value.error_code, return_value.ec_return_value); else @@ -1310,7 +1305,7 @@ static void acer_wmi_notify(u32 value, void *context) status = wmi_get_event_data(value, &response); if (status != AE_OK) { - printk(ACER_WARNING "bad event status 0x%x\n", status); + pr_warning("bad event status 0x%x\n", status); return; } @@ -1319,14 +1314,12 @@ static void acer_wmi_notify(u32 value, void *context) if (!obj) return; if (obj->type != ACPI_TYPE_BUFFER) { - printk(ACER_WARNING "Unknown response received %d\n", - obj->type); + pr_warning("Unknown response received %d\n", obj->type); kfree(obj); return; } if (obj->buffer.length != 8) { - printk(ACER_WARNING "Unknown buffer length %d\n", - obj->buffer.length); + pr_warning("Unknown buffer length %d\n", obj->buffer.length); kfree(obj); return; } @@ -1338,11 +1331,11 @@ static void acer_wmi_notify(u32 value, void *context) case WMID_HOTKEY_EVENT: if (!sparse_keymap_report_event(acer_wmi_input_dev, return_value.key_num, 1, true)) - printk(ACER_WARNING "Unknown key number - 0x%x\n", + pr_warning("Unknown key number - 0x%x\n", return_value.key_num); break; default: - printk(ACER_WARNING "Unknown function number - %d - %d\n", + pr_warning("Unknown function number - %d - %d\n", return_value.function, return_value.key_num); break; } @@ -1371,8 +1364,7 @@ wmid3_set_lm_mode(struct lm_input_params *params, return AE_ERROR; } if (obj->buffer.length != 4) { - printk(ACER_WARNING "Unknown buffer length %d\n", - obj->buffer.length); + pr_warning("Unknown buffer length %d\n", obj->buffer.length); kfree(obj); return AE_ERROR; } @@ -1397,11 +1389,11 @@ static int acer_wmi_enable_ec_raw(void) status = wmid3_set_lm_mode(¶ms, &return_value); if (return_value.error_code || return_value.ec_return_value) - printk(ACER_WARNING "Enabling EC raw mode failed: " + pr_warning("Enabling EC raw mode failed: " "0x%x - 0x%x\n", return_value.error_code, return_value.ec_return_value); else - printk(ACER_INFO "Enabled EC raw mode"); + pr_info("Enabled EC raw mode"); return status; } @@ -1420,7 +1412,7 @@ static int acer_wmi_enable_lm(void) status = wmid3_set_lm_mode(¶ms, &return_value); if (return_value.error_code || return_value.ec_return_value) - printk(ACER_WARNING "Enabling Launch Manager failed: " + pr_warning("Enabling Launch Manager failed: " "0x%x - 0x%x\n", return_value.error_code, return_value.ec_return_value); @@ -1650,7 +1642,7 @@ static int create_debugfs(void) { interface->debug.root = debugfs_create_dir("acer-wmi", NULL); if (!interface->debug.root) { - printk(ACER_ERR "Failed to create debugfs directory"); + pr_err("Failed to create debugfs directory"); return -ENOMEM; } @@ -1671,11 +1663,10 @@ static int __init acer_wmi_init(void) { int err; - printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); + pr_info("Acer Laptop ACPI-WMI Extras\n"); if (dmi_check_system(acer_blacklist)) { - printk(ACER_INFO "Blacklisted hardware detected - " - "not loading\n"); + pr_info("Blacklisted hardware detected - not loading\n"); return -ENODEV; } @@ -1692,12 +1683,11 @@ static int __init acer_wmi_init(void) if (wmi_has_guid(WMID_GUID2) && interface) { if (ACPI_FAILURE(WMID_set_capabilities())) { - printk(ACER_ERR "Unable to detect available WMID " - "devices\n"); + pr_err("Unable to detect available WMID devices\n"); return -ENODEV; } } else if (!wmi_has_guid(WMID_GUID2) && interface) { - printk(ACER_ERR "No WMID device detection method found\n"); + pr_err("No WMID device detection method found\n"); return -ENODEV; } @@ -1705,8 +1695,7 @@ static int __init acer_wmi_init(void) interface = &AMW0_interface; if (ACPI_FAILURE(AMW0_set_capabilities())) { - printk(ACER_ERR "Unable to detect available AMW0 " - "devices\n"); + pr_err("Unable to detect available AMW0 devices\n"); return -ENODEV; } } @@ -1715,8 +1704,7 @@ static int __init acer_wmi_init(void) AMW0_find_mailled(); if (!interface) { - printk(ACER_INFO "No or unsupported WMI interface, unable to " - "load\n"); + pr_err("No or unsupported WMI interface, unable to load\n"); return -ENODEV; } @@ -1724,22 +1712,22 @@ static int __init acer_wmi_init(void) if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { interface->capability &= ~ACER_CAP_BRIGHTNESS; - printk(ACER_INFO "Brightness must be controlled by " + pr_info("Brightness must be controlled by " "generic video driver\n"); } if (wmi_has_guid(WMID_GUID3)) { if (ec_raw_mode) { if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { - printk(ACER_ERR "Cannot enable EC raw mode\n"); + pr_err("Cannot enable EC raw mode\n"); return -ENODEV; } } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { - printk(ACER_ERR "Cannot enable Launch Manager mode\n"); + pr_err("Cannot enable Launch Manager mode\n"); return -ENODEV; } } else if (ec_raw_mode) { - printk(ACER_INFO "No WMID EC raw mode enable method\n"); + pr_info("No WMID EC raw mode enable method\n"); } if (wmi_has_guid(ACERWMID_EVENT_GUID)) { @@ -1750,7 +1738,7 @@ static int __init acer_wmi_init(void) err = platform_driver_register(&acer_platform_driver); if (err) { - printk(ACER_ERR "Unable to register platform driver.\n"); + pr_err("Unable to register platform driver.\n"); goto error_platform_register; } @@ -1805,7 +1793,7 @@ static void __exit acer_wmi_exit(void) platform_device_unregister(acer_platform_device); platform_driver_unregister(&acer_platform_driver); - printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); + pr_info("Acer Laptop WMI Extras unloaded\n"); return; } -- cgit v1.2.2 From c8440336fe376036e473554c30f7266987961734 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 17 Mar 2011 17:18:22 -0300 Subject: platform-drivers: x86: fix common misspellings Signed-off-by: Lucas De Marchi Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 2 +- drivers/platform/x86/compal-laptop.c | 2 +- drivers/platform/x86/eeepc-laptop.c | 2 +- drivers/platform/x86/intel_rar_register.c | 2 +- drivers/platform/x86/intel_scu_ipc.c | 2 +- drivers/platform/x86/sony-laptop.c | 6 +++--- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 62ef43ef06d2..c53b3ff7978a 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -29,7 +29,7 @@ * John Belmonte - ACPI code for Toshiba laptop was a good starting point. * Eric Burghard - LED display support for W1N * Josh Green - Light Sens support - * Thomas Tuttle - His first patch for led support was very helpfull + * Thomas Tuttle - His first patch for led support was very helpful * Sam Lin - GPS support */ diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 3994c80549fb..c16a27641ced 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -201,7 +201,7 @@ static bool extra_features; * into 0x4F and read a few bytes from the output, like so: * u8 writeData = 0x33; * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); - * That address is labled "fan1 table information" in the service manual. + * That address is labelled "fan1 table information" in the service manual. * It should be clear which value in 'buffer' changes). This seems to be * related to fan speed. It isn't a proper 'realtime' fan speed value * though, because physically stopping or speeding up the fan doesn't diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 6605beac0d0e..5f2dd386152b 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -1322,7 +1322,7 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) { int dummy; - /* Some BIOSes do not report cm although it is avaliable. + /* Some BIOSes do not report cm although it is available. Check if cm_getv[cm] works and, if yes, assume cm should be set. */ if (!(eeepc->cm_supported & (1 << cm)) && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c index 2b11a33325e6..bde47e9080cd 100644 --- a/drivers/platform/x86/intel_rar_register.c +++ b/drivers/platform/x86/intel_rar_register.c @@ -485,7 +485,7 @@ EXPORT_SYMBOL(rar_lock); * * The register_rar function is to used by other device drivers * to ensure that this driver is ready. As we cannot be sure of - * the compile/execute order of drivers in ther kernel, it is + * the compile/execute order of drivers in the kernel, it is * best to give this driver a callback function to call when * it is ready to give out addresses. The callback function * would have those steps that continue the initialization of diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index a91d510a798b..940accbe28d3 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; version 2 * of the License. * - * SCU runing in ARC processor communicates with other entity running in IA + * SCU running in ARC processor communicates with other entity running in IA * core through IPC mechanism which in turn messaging between IA core ad SCU. * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 4ab898a39fea..e642f5f29504 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -605,7 +605,7 @@ struct sony_nc_value { int value; /* current setting */ int valid; /* Has ever been set */ int debug; /* active only in debug mode ? */ - struct device_attribute devattr; /* sysfs atribute */ + struct device_attribute devattr; /* sysfs attribute */ }; #define SNC_HANDLE_NAMES(_name, _values...) \ @@ -3129,7 +3129,7 @@ static int sony_pic_add(struct acpi_device *device) /* request io port */ list_for_each_entry_reverse(io, &spic_dev.ioports, list) { if (request_region(io->io1.minimum, io->io1.address_length, - "Sony Programable I/O Device")) { + "Sony Programmable I/O Device")) { dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", io->io1.minimum, io->io1.maximum, io->io1.address_length); @@ -3137,7 +3137,7 @@ static int sony_pic_add(struct acpi_device *device) if (io->io2.minimum) { if (request_region(io->io2.minimum, io->io2.address_length, - "Sony Programable I/O Device")) { + "Sony Programmable I/O Device")) { dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", io->io2.minimum, io->io2.maximum, io->io2.address_length); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 947bdcaa0ce9..a08561f5349e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -2407,7 +2407,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn, * This code is supposed to duplicate the IBM firmware behaviour: * - Pressing MUTE issues mute hotkey message, even when already mute * - Pressing Volume up/down issues volume up/down hotkey messages, - * even when already at maximum or minumum volume + * even when already at maximum or minimum volume * - The act of unmuting issues volume up/down notification, * depending which key was used to unmute * @@ -2990,7 +2990,7 @@ static void tpacpi_send_radiosw_update(void) * rfkill input events, or we will race the rfkill core input * handler. * - * tpacpi_inputdev_send_mutex works as a syncronization point + * tpacpi_inputdev_send_mutex works as a synchronization point * for the above. * * We optimize to avoid numerous calls to hotkey_get_wlsw. -- cgit v1.2.2 From 8215af019040ce9182728afee9642d8fdeb17f59 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Mon, 28 Mar 2011 16:52:02 +0800 Subject: acer-wmi: does not set persistence state by rfkill_init_sw_state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Acer BIOS keeps devices state when system reboot, but reset to default device states (Wlan on, Bluetooth off, wwan on) if system cold boot. That means BIOS's initial state is not always real persistence. So, removed rfkill_init_sw_state because it sets initial state to persistence then replicate to other new killswitch when rfkill-input enabled. After removed it, acer-wmi set initial soft-block state after rfkill register, and doesn't allow set_block until rfkill initial finished. Reference: bko#31002 https://bugzilla.kernel.org/show_bug.cgi?id=31002 Cc: Carlos Corbacho Cc: Matthew Garrett Cc: Dmitry Torokhov Cc: Corentin Chary Cc: Oldřich JedliÄÂka Cc: Johannes Berg Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index d798314b81fe..652a84ec36cf 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -217,6 +217,7 @@ struct acer_debug { static struct rfkill *wireless_rfkill; static struct rfkill *bluetooth_rfkill; static struct rfkill *threeg_rfkill; +static bool rfkill_inited; /* Each low-level interface must define at least some of the following */ struct wmi_interface { @@ -1157,9 +1158,13 @@ static int acer_rfkill_set(void *data, bool blocked) { acpi_status status; u32 cap = (unsigned long)data; - status = set_u32(!blocked, cap); - if (ACPI_FAILURE(status)) - return -ENODEV; + + if (rfkill_inited) { + status = set_u32(!blocked, cap); + if (ACPI_FAILURE(status)) + return -ENODEV; + } + return 0; } @@ -1183,14 +1188,16 @@ static struct rfkill *acer_rfkill_register(struct device *dev, return ERR_PTR(-ENOMEM); status = get_device_status(&state, cap); - if (ACPI_SUCCESS(status)) - rfkill_init_sw_state(rfkill_dev, !state); err = rfkill_register(rfkill_dev); if (err) { rfkill_destroy(rfkill_dev); return ERR_PTR(err); } + + if (ACPI_SUCCESS(status)) + rfkill_set_sw_state(rfkill_dev, !state); + return rfkill_dev; } @@ -1225,6 +1232,8 @@ static int acer_rfkill_init(struct device *dev) } } + rfkill_inited = true; + schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); return 0; -- cgit v1.2.2 From 70a9b9047aebd53ac38837a1046da52a2f8d9636 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Mon, 28 Mar 2011 06:34:13 -0400 Subject: acer-wmi: does not poll device status when WMI event is available Acer WMI hotkey event's result include current device status, just need sync the status to killswitch after acer-wmi driver receive hotkey event but not always poll device status. This is good for performance. But, if use EC raw mode, Acer BIOS will not emit wmi event and leave EC to control device status. So, still startup polling job when doesn't detect WMI event GUID or user choice to use ec_raw_mode. Tested on Acer TravelMate 8572 notebook. Cc: Carlos Corbacho Cc: Matthew Garrett Cc: Dmitry Torokhov Cc: Corentin Chary Cc: Thomas Renninger Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 652a84ec36cf..5ea6c3477d17 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1234,14 +1234,17 @@ static int acer_rfkill_init(struct device *dev) rfkill_inited = true; - schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); + if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) + schedule_delayed_work(&acer_rfkill_work, + round_jiffies_relative(HZ)); return 0; } static void acer_rfkill_exit(void) { - cancel_delayed_work_sync(&acer_rfkill_work); + if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) + cancel_delayed_work_sync(&acer_rfkill_work); rfkill_unregister(wireless_rfkill); rfkill_destroy(wireless_rfkill); @@ -1338,6 +1341,19 @@ static void acer_wmi_notify(u32 value, void *context) switch (return_value.function) { case WMID_HOTKEY_EVENT: + if (return_value.device_state) { + u16 device_state = return_value.device_state; + pr_debug("deivces states: 0x%x\n", device_state); + if (has_cap(ACER_CAP_WIRELESS)) + rfkill_set_sw_state(wireless_rfkill, + !(device_state & ACER_WMID3_GDS_WIRELESS)); + if (has_cap(ACER_CAP_BLUETOOTH)) + rfkill_set_sw_state(bluetooth_rfkill, + !(device_state & ACER_WMID3_GDS_BLUETOOTH)); + if (has_cap(ACER_CAP_THREEG)) + rfkill_set_sw_state(threeg_rfkill, + !(device_state & ACER_WMID3_GDS_THREEG)); + } if (!sparse_keymap_report_event(acer_wmi_input_dev, return_value.key_num, 1, true)) pr_warning("Unknown key number - 0x%x\n", -- cgit v1.2.2 From a3424216e4935221fdaa5ca3c26e024f11297164 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 28 Mar 2011 06:36:30 -0400 Subject: ips: use interruptible waits in ips-monitor This is what I intended to do since: 1) the driver handles variable waits just fine, and 2) interruptible waits aren't reported as load in the load avg. Reported-and-tested-by: Andreas Hartmann Signed-off-by: Jesse Barnes Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_ips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 1294a39373ba..85c8ad43c0c5 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -1111,7 +1111,7 @@ static int ips_monitor(void *data) last_msecs = jiffies_to_msecs(jiffies); expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); - __set_current_state(TASK_UNINTERRUPTIBLE); + __set_current_state(TASK_INTERRUPTIBLE); mod_timer(&timer, expire); schedule(); -- cgit v1.2.2 From bd1573a5546b4351b5d042f1e4cd631ea67cc6b0 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 28 Mar 2011 06:40:23 -0400 Subject: xo15-ebook: Remove device.wakeup_count This is handled automatically now. Signed-off-by: Matthew Garrett --- drivers/platform/x86/xo15-ebook.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c index 2343bb36e563..c1372ed9d2e9 100644 --- a/drivers/platform/x86/xo15-ebook.c +++ b/drivers/platform/x86/xo15-ebook.c @@ -133,7 +133,6 @@ static int ebook_switch_add(struct acpi_device *device) /* Button's GPE is run-wake GPE */ acpi_enable_gpe(device->wakeup.gpe_device, device->wakeup.gpe_number); - device->wakeup.run_wake_count++; device_set_wakeup_enable(&device->dev, true); } -- cgit v1.2.2 From 022b483596fabb5d1320aa4b76f43a754063f37e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 28 Mar 2011 09:16:33 +0200 Subject: mmc: SDHI should depend on SUPERH || ARCH_SHMOBILE Fix build breakage on platforms, not providing readsw and writesw functions, e.g., on x86(_64). Reported-by: Stephen Rothwell Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 0b03cee91451..94df40531c38 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -452,6 +452,7 @@ config MMC_TMIO config MMC_SDHI tristate "SH-Mobile SDHI SD/SDIO controller support" + depends on SUPERH || ARCH_SHMOBILE select MMC_TMIO_CORE help This provides support for the SDHI SD/SDIO controller found in -- cgit v1.2.2 From 7e599e6e62759e057e902fcf9a05ba24f6155bcd Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 28 Mar 2011 07:42:58 -0700 Subject: drbd: fix up merge error In commit 95a0f10cddbf ("drbd: store in-core bitmap little endian, regardless of architecture") drbd had made the sane choice to use little-endian bitmap functions everywhere. However, it used the horrible old functions names from , that were never really meant to be exported. In the meantime, things got cleaned up, and in commit c4945b9ed472 ("asm-generic: rename generic little-endian bitops functions") we renamed the LE bitops to something sane, exactly so that they could be used in random code without people gouging their eyes out when seeing the crazy jumble of letters that were the old internal names. As a result the drbd thing merged cleanly (commit 8d49a77568d1: "Merge branch 'for-2.6.39/drivers' of git://git.kernel.dk/linux-2.6-block"), since there was no data conflict - but the end result obviously doesn't actually compile. Reported-and-tested-by: Ingo Molnar Cc: Jens Axboe Cc: Stephen Rothwell Signed-off-by: Linus Torvalds --- drivers/block/drbd/drbd_bitmap.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index f0ae63d2df65..76210ba401ac 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -29,8 +29,6 @@ #include #include -#include - #include "drbd_int.h" @@ -1184,10 +1182,10 @@ static unsigned long __bm_find_next(struct drbd_conf *mdev, unsigned long bm_fo, p_addr = __bm_map_pidx(b, bm_bit_to_page_idx(b, bm_fo), km); if (find_zero_bit) - i = generic_find_next_zero_le_bit(p_addr, + i = find_next_zero_bit_le(p_addr, PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); else - i = generic_find_next_le_bit(p_addr, + i = find_next_bit_le(p_addr, PAGE_SIZE*8, bm_fo & BITS_PER_PAGE_MASK); __bm_unmap(p_addr, km); @@ -1287,9 +1285,9 @@ static int __bm_change_bits_to(struct drbd_conf *mdev, const unsigned long s, last_page_nr = page_nr; } if (val) - c += (0 == generic___test_and_set_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); + c += (0 == __test_and_set_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr)); else - c -= (0 != generic___test_and_clear_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr)); + c -= (0 != __test_and_clear_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr)); } if (p_addr) __bm_unmap(p_addr, km); @@ -1438,7 +1436,7 @@ int drbd_bm_test_bit(struct drbd_conf *mdev, const unsigned long bitnr) bm_print_lock_info(mdev); if (bitnr < b->bm_bits) { p_addr = bm_map_pidx(b, bm_bit_to_page_idx(b, bitnr)); - i = generic_test_le_bit(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0; + i = test_bit_le(bitnr & BITS_PER_PAGE_MASK, p_addr) ? 1 : 0; bm_unmap(p_addr); } else if (bitnr == b->bm_bits) { i = -1; @@ -1482,7 +1480,7 @@ int drbd_bm_count_bits(struct drbd_conf *mdev, const unsigned long s, const unsi ERR_IF (bitnr >= b->bm_bits) { dev_err(DEV, "bitnr=%lu bm_bits=%lu\n", bitnr, b->bm_bits); } else { - c += (0 != generic_test_le_bit(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); + c += (0 != test_bit_le(bitnr - (page_nr << (PAGE_SHIFT+3)), p_addr)); } } if (p_addr) -- cgit v1.2.2 From 15b7cf1416c0e3ae6163ade3349d717fe2729952 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Sun, 27 Mar 2011 21:26:03 -0700 Subject: MFD: allow cs5535-mfd to build on X86 only Stephen ran into the following build error: drivers/mfd/cs5535-mfd.c:30:22: error: asm/olpc.h: No such file or directory olpc.h exists only on x86 (and in the future, ARM). Rather than wrapping the include in an #ifdef, just change cs5535-mfd to only build on x86. Reported-by: Stephen Rothwell Signed-off-by: Andres Salomon Signed-off-by: Linus Torvalds --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e986f91fff9c..9a46d64996a9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -592,7 +592,7 @@ config AB3550_CORE config MFD_CS5535 tristate "Support for CS5535 and CS5536 southbridge core functions" select MFD_CORE - depends on PCI + depends on PCI && X86 ---help--- This is the core driver for CS5535/CS5536 MFD functions. This is necessary for using the board's GPIO and MFGPT functionality. -- cgit v1.2.2 From 8ec4ad2bebd1dd7e782bd1a1ac4c5e17ceb2ff81 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 21:56:37 +0100 Subject: vlynq: Convert irq functions Convert to the new irq_chip functions and the new namespace. Signed-off-by: Thomas Gleixner Acked-by: Florian Fainelli LKML-Reference: --- drivers/vlynq/vlynq.c | 64 +++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/vlynq/vlynq.c b/drivers/vlynq/vlynq.c index f885c868a04d..aa250cebecd2 100644 --- a/drivers/vlynq/vlynq.c +++ b/drivers/vlynq/vlynq.c @@ -135,40 +135,40 @@ static void vlynq_reset(struct vlynq_device *dev) msleep(5); } -static void vlynq_irq_unmask(unsigned int irq) +static void vlynq_irq_unmask(struct irq_data *d) { - u32 val; - struct vlynq_device *dev = get_irq_chip_data(irq); + struct vlynq_device *dev = irq_data_get_irq_chip_data(d); int virq; + u32 val; BUG_ON(!dev); - virq = irq - dev->irq_start; + virq = d->irq - dev->irq_start; val = readl(&dev->remote->int_device[virq >> 2]); val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq); writel(val, &dev->remote->int_device[virq >> 2]); } -static void vlynq_irq_mask(unsigned int irq) +static void vlynq_irq_mask(struct irq_data *d) { - u32 val; - struct vlynq_device *dev = get_irq_chip_data(irq); + struct vlynq_device *dev = irq_data_get_irq_chip_data(d); int virq; + u32 val; BUG_ON(!dev); - virq = irq - dev->irq_start; + virq = d->irq - dev->irq_start; val = readl(&dev->remote->int_device[virq >> 2]); val &= ~(VINT_ENABLE << VINT_OFFSET(virq)); writel(val, &dev->remote->int_device[virq >> 2]); } -static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) +static int vlynq_irq_type(struct irq_data *d, unsigned int flow_type) { - u32 val; - struct vlynq_device *dev = get_irq_chip_data(irq); + struct vlynq_device *dev = irq_data_get_irq_chip_data(d); int virq; + u32 val; BUG_ON(!dev); - virq = irq - dev->irq_start; + virq = d->irq - dev->irq_start; val = readl(&dev->remote->int_device[virq >> 2]); switch (flow_type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: @@ -192,10 +192,9 @@ static int vlynq_irq_type(unsigned int irq, unsigned int flow_type) return 0; } -static void vlynq_local_ack(unsigned int irq) +static void vlynq_local_ack(struct irq_data *d) { - struct vlynq_device *dev = get_irq_chip_data(irq); - + struct vlynq_device *dev = irq_data_get_irq_chip_data(d); u32 status = readl(&dev->local->status); pr_debug("%s: local status: 0x%08x\n", @@ -203,10 +202,9 @@ static void vlynq_local_ack(unsigned int irq) writel(status, &dev->local->status); } -static void vlynq_remote_ack(unsigned int irq) +static void vlynq_remote_ack(struct irq_data *d) { - struct vlynq_device *dev = get_irq_chip_data(irq); - + struct vlynq_device *dev = irq_data_get_irq_chip_data(d); u32 status = readl(&dev->remote->status); pr_debug("%s: remote status: 0x%08x\n", @@ -238,23 +236,23 @@ static irqreturn_t vlynq_irq(int irq, void *dev_id) static struct irq_chip vlynq_irq_chip = { .name = "vlynq", - .unmask = vlynq_irq_unmask, - .mask = vlynq_irq_mask, - .set_type = vlynq_irq_type, + .irq_unmask = vlynq_irq_unmask, + .irq_mask = vlynq_irq_mask, + .irq_set_type = vlynq_irq_type, }; static struct irq_chip vlynq_local_chip = { .name = "vlynq local error", - .unmask = vlynq_irq_unmask, - .mask = vlynq_irq_mask, - .ack = vlynq_local_ack, + .irq_unmask = vlynq_irq_unmask, + .irq_mask = vlynq_irq_mask, + .irq_ack = vlynq_local_ack, }; static struct irq_chip vlynq_remote_chip = { .name = "vlynq local error", - .unmask = vlynq_irq_unmask, - .mask = vlynq_irq_mask, - .ack = vlynq_remote_ack, + .irq_unmask = vlynq_irq_unmask, + .irq_mask = vlynq_irq_mask, + .irq_ack = vlynq_remote_ack, }; static int vlynq_setup_irq(struct vlynq_device *dev) @@ -291,17 +289,17 @@ static int vlynq_setup_irq(struct vlynq_device *dev) for (i = dev->irq_start; i <= dev->irq_end; i++) { virq = i - dev->irq_start; if (virq == dev->local_irq) { - set_irq_chip_and_handler(i, &vlynq_local_chip, + irq_set_chip_and_handler(i, &vlynq_local_chip, handle_level_irq); - set_irq_chip_data(i, dev); + irq_set_chip_data(i, dev); } else if (virq == dev->remote_irq) { - set_irq_chip_and_handler(i, &vlynq_remote_chip, + irq_set_chip_and_handler(i, &vlynq_remote_chip, handle_level_irq); - set_irq_chip_data(i, dev); + irq_set_chip_data(i, dev); } else { - set_irq_chip_and_handler(i, &vlynq_irq_chip, + irq_set_chip_and_handler(i, &vlynq_irq_chip, handle_simple_irq); - set_irq_chip_data(i, dev); + irq_set_chip_data(i, dev); writel(0, &dev->remote->int_device[virq >> 2]); } } -- cgit v1.2.2 From f62d816fc4324afbb7cf90110c70b6a14139b225 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 25 Mar 2011 17:43:41 +0100 Subject: ath9k: fix a chip wakeup related crash in ath9k_start When the chip is still asleep when ath9k_start is called, ath9k_hw_configpcipowersave can trigger a data bus error. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 524825720a09..dddb85de622d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1048,6 +1048,8 @@ static int ath9k_start(struct ieee80211_hw *hw) "Starting driver with initial channel: %d MHz\n", curchan->center_freq); + ath9k_ps_wakeup(sc); + mutex_lock(&sc->mutex); /* setup initial channel */ @@ -1143,6 +1145,8 @@ static int ath9k_start(struct ieee80211_hw *hw) mutex_unlock: mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); + return r; } -- cgit v1.2.2 From 445aef374594207b278477dfd98fc5d1498d353a Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 28 Mar 2011 12:46:02 +0000 Subject: acpi: Remove sysfs_create_link from video driver The acpi video driver attempts to explicitly create a sysfs link between the acpi device and the associated PCI device. However, we're now also doing this from the backlight core, which means that we get a backtrace caused by a duplicate file. Remove the code and leave it up to the backlight core. Reported-by: Jeff Chua Signed-off-by: Matthew Garrett Acked-by: Rafael J. Wysocki Tested-by: Alessandro Suardi Signed-off-by: Linus Torvalds --- drivers/acpi/video.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index a18e497f1c3c..31e9e10f657e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -824,11 +824,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->backlight->props.brightness = acpi_video_get_brightness(device->backlight); - result = sysfs_create_link(&device->backlight->dev.kobj, - &device->dev->dev.kobj, "device"); - if (result) - printk(KERN_ERR PREFIX "Create sysfs link\n"); - device->cooling_dev = thermal_cooling_device_register("LCD", device->dev, &video_cooling_ops); if (IS_ERR(device->cooling_dev)) { @@ -1381,7 +1376,6 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) "Cant remove video notify handler\n"); } if (device->backlight) { - sysfs_remove_link(&device->backlight->dev.kobj, "device"); backlight_device_unregister(device->backlight); device->backlight = NULL; } -- cgit v1.2.2 From 5ede9ddfba424b5dad96e7ccd55607875a64ff6c Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 28 Mar 2011 16:24:29 -0700 Subject: memstick: make enable_dma less generic in r592 Fixes this build error: drivers/memstick/host/r592.c:26: error: 'enable_dma' redeclared as different kind of symbol arch/powerpc/include/asm/dma.h:189: note: previous definition of 'enable_dma' was here Signed-off-by: Stephen Rothwell Cc: Andrew Morton Cc: FUJITA Tomonori Cc: Alex Dubov Acked-by: Maxim Levitsky Signed-off-by: Linus Torvalds --- drivers/memstick/host/r592.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 767406c95291..700d420a59ac 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -23,7 +23,7 @@ #include #include "r592.h" -static int enable_dma = 1; +static int r592_enable_dma = 1; static int debug; static const char *tpc_names[] = { @@ -267,7 +267,7 @@ static void r592_stop_dma(struct r592_device *dev, int error) /* Test if hardware supports DMA */ static void r592_check_dma(struct r592_device *dev) { - dev->dma_capable = enable_dma && + dev->dma_capable = r592_enable_dma && (r592_read_reg(dev, R592_FIFO_DMA_SETTINGS) & R592_FIFO_DMA_SETTINGS_CAP); } @@ -898,7 +898,7 @@ static void __exit r592_module_exit(void) module_init(r592_module_init); module_exit(r592_module_exit); -module_param(enable_dma, bool, S_IRUGO); +module_param_named(enable_dma, r592_enable_dma, bool, S_IRUGO); MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)"); module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level (0-3)"); -- cgit v1.2.2 From 89078d572eb9ce8d4c04264b8b0ba86de0d74c8f Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 28 Mar 2011 20:09:12 -0400 Subject: md: Fix integrity registration error when no devices are capable We incorrectly returned -EINVAL when none of the devices in the array had an integrity profile. This in turn prevented mdadm from starting the metadevice. Fix this so we only return errors on mismatched profiles and memory allocation failures. Reported-by: Giacomo Catenazzi Reported-by: Thomas Gleixner Signed-off-by: Martin K. Petersen Signed-off-by: Linus Torvalds --- drivers/md/md.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 06ecea751a39..8b66e04c2ea6 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1777,12 +1777,6 @@ int md_integrity_register(mddev_t *mddev) continue; if (rdev->raid_disk < 0) continue; - /* - * If at least one rdev is not integrity capable, we can not - * enable data integrity for the md device. - */ - if (!bdev_get_integrity(rdev->bdev)) - return -EINVAL; if (!reference) { /* Use the first rdev as the reference */ reference = rdev; @@ -1793,6 +1787,8 @@ int md_integrity_register(mddev_t *mddev) rdev->bdev->bd_disk) < 0) return -EINVAL; } + if (!reference || !bdev_get_integrity(reference->bdev)) + return 0; /* * All component devices are integrity capable and have matching * profiles, register the common profile for the md device. -- cgit v1.2.2 From c211c9698920d2b114bd8fbf913c8bdab3918461 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 27 Mar 2011 16:50:41 +0000 Subject: cxgb3: Apply interrupt coalescing settings to all queues While testing the performance of different receive interrupt coalescing settings on a single stream TCP benchmark, I noticed two very different results. With rx-usecs=50, most of the time a connection would hit 8280 Mbps but once in a while it would hit 9330 Mbps. It turns out we are only applying the interrupt coalescing settings to the first queue and whenever the rx hash would direct us onto that queue we ran faster. With this patch applied and rx-usecs=50, I get 9330 Mbps consistently. Signed-off-by: Anton Blanchard Acked-by: Divy Le Ray Signed-off-by: David S. Miller --- drivers/net/cxgb3/cxgb3_main.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 4d538a4e9d55..910893143295 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -1983,14 +1983,20 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - struct qset_params *qsp = &adapter->params.sge.qset[0]; - struct sge_qset *qs = &adapter->sge.qs[0]; + struct qset_params *qsp; + struct sge_qset *qs; + int i; if (c->rx_coalesce_usecs * 10 > M_NEWTIMER) return -EINVAL; - qsp->coalesce_usecs = c->rx_coalesce_usecs; - t3_update_qset_coalesce(qs, qsp); + for (i = 0; i < pi->nqsets; i++) { + qsp = &adapter->params.sge.qset[i]; + qs = &adapter->sge.qs[i]; + qsp->coalesce_usecs = c->rx_coalesce_usecs; + t3_update_qset_coalesce(qs, qsp); + } + return 0; } -- cgit v1.2.2 From bc8d7da3f19191f86dcc8274cf1a3f2d6aeb0aaa Mon Sep 17 00:00:00 2001 From: Balaji G Date: Sun, 27 Mar 2011 17:15:19 +0000 Subject: drivers net: Fix declaration ordering in inline functions. The correct usage should be "static inline void" instead of "static void inline" Signed-off-by: G.Balaji Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index d1865cc97313..8e6d618b5305 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8317,7 +8317,7 @@ static const struct net_device_ops bnx2_netdev_ops = { #endif }; -static void inline vlan_features_add(struct net_device *dev, u32 flags) +static inline void vlan_features_add(struct net_device *dev, u32 flags) { dev->vlan_features |= flags; } -- cgit v1.2.2 From 72f49050ba18959472aac723cd9d094bc3547e89 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 27 Mar 2011 22:33:13 +0000 Subject: netdev: bfin_mac: document TE setting in RMII modes The current code sometimes generates build warnings due to how it checks the silicon revision, so clean it up and properly document things. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller --- drivers/net/bfin_mac.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 22abfb39d813..68d45ba2d9b9 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -1237,8 +1237,17 @@ static int bfin_mac_enable(struct phy_device *phydev) if (phydev->interface == PHY_INTERFACE_MODE_RMII) { opmode |= RMII; /* For Now only 100MBit are supported */ -#if (defined(CONFIG_BF537) || defined(CONFIG_BF536)) && CONFIG_BF_REV_0_2 - opmode |= TE; +#if defined(CONFIG_BF537) || defined(CONFIG_BF536) + if (__SILICON_REVISION__ < 3) { + /* + * This isn't publicly documented (fun times!), but in + * silicon <=0.2, the RX and TX pins are clocked together. + * So in order to recv, we must enable the transmit side + * as well. This will cause a spurious TX interrupt too, + * but we can easily consume that. + */ + opmode |= TE; + } #endif } -- cgit v1.2.2 From f3cf5c4fedbe13880cd80a9fa1aebae79ebef20e Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Sat, 26 Mar 2011 22:53:34 -0700 Subject: Input: sparse-keymap - report scancodes with key events Scancodes are useful debugging aids when incorrect keycodes are being sent, as is common with laptop hotkeys. Signed-off-by: Seth Forshee Signed-off-by: Dmitry Torokhov --- drivers/input/sparse-keymap.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 337bf51bc984..74bca5d2f6dc 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -208,6 +208,11 @@ int sparse_keymap_setup(struct input_dev *dev, } } + if (test_bit(EV_KEY, dev->evbit)) { + __set_bit(EV_MSC, dev->evbit); + __set_bit(MSC_SCAN, dev->mscbit); + } + dev->keycode = map; dev->keycodemax = map_size; dev->getkeycode = sparse_keymap_getkeycode; @@ -268,6 +273,7 @@ void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *k { switch (ke->type) { case KE_KEY: + input_event(dev, EV_MSC, MSC_SCAN, ke->code); input_report_key(dev, ke->keycode, value); input_sync(dev); if (value && autorelease) { -- cgit v1.2.2 From 170531bae648c0ef8d56b44dc5bd8d67717b0db9 Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Sat, 26 Mar 2011 22:53:34 -0700 Subject: Input: sparse-keymap - report KEY_UNKNOWN for unknown scan codes This allows for debugging non-functional keys easily from userspace. Signed-off-by: Seth Forshee Signed-off-by: Dmitry Torokhov --- drivers/input/sparse-keymap.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 74bca5d2f6dc..fdb6a3976f94 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -209,6 +209,7 @@ int sparse_keymap_setup(struct input_dev *dev, } if (test_bit(EV_KEY, dev->evbit)) { + __set_bit(KEY_UNKNOWN, dev->keybit); __set_bit(EV_MSC, dev->evbit); __set_bit(MSC_SCAN, dev->mscbit); } @@ -311,12 +312,19 @@ bool sparse_keymap_report_event(struct input_dev *dev, unsigned int code, { const struct key_entry *ke = sparse_keymap_entry_from_scancode(dev, code); + struct key_entry unknown_ke; if (ke) { sparse_keymap_report_entry(dev, ke, value, autorelease); return true; } + /* Report an unknown key event as a debugging aid */ + unknown_ke.type = KE_KEY; + unknown_ke.code = code; + unknown_ke.keycode = KEY_UNKNOWN; + sparse_keymap_report_entry(dev, &unknown_ke, value, true); + return false; } EXPORT_SYMBOL(sparse_keymap_report_event); -- cgit v1.2.2 From ff7690b48ae8571d930a2621e21f6e5a41e42b6d Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 9 Feb 2011 07:46:47 +0000 Subject: dma: shdma: add checking the DMAOR_AE in sh_dmae_err The irq numbers of tranfer end and address error are assigned same number on some CPU. So the sh_dmae_err() should check the AE flag in DMAOR. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Paul Mundt --- drivers/dma/shdma.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index 6451b581a70b..d50da41ac328 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c @@ -865,7 +865,12 @@ static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev) static irqreturn_t sh_dmae_err(int irq, void *data) { - return IRQ_RETVAL(sh_dmae_reset(data)); + struct sh_dmae_device *shdev = data; + + if (dmaor_read(shdev) & DMAOR_AE) + return IRQ_RETVAL(sh_dmae_reset(data)); + else + return IRQ_NONE; } static void dmae_do_tasklet(unsigned long data) -- cgit v1.2.2 From 8857b9aa7e64a70852545ee01fa638481cb08a76 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 23 Feb 2011 08:36:30 +0000 Subject: fbdev: sh_mobile_lcdcfb: add blanking support Add a blanking callback to the LCDC driver in order to support both FBIOBLANK and TIOCLINUX blanking ioctls. LCDC clocks are also released if the requested blanking level is superior to FB_BLANK_NORMAL, to allow runtime PM to disable the clocks if possible. Signed-off-by: Alexandre Courbot Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 44 ++++++++++++++++++++++++++++++++++++++++ drivers/video/sh_mobile_lcdcfb.h | 1 + 2 files changed, 45 insertions(+) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e040e46d7d91..65c4ee3628c4 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -977,6 +977,49 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in return 0; } +/* + * Screen blanking. Behavior is as follows: + * FB_BLANK_UNBLANK: screen unblanked, clocks enabled + * FB_BLANK_NORMAL: screen blanked, clocks enabled + * FB_BLANK_VSYNC, + * FB_BLANK_HSYNC, + * FB_BLANK_POWEROFF: screen blanked, clocks disabled + */ +static int sh_mobile_lcdc_blank(int blank, struct fb_info *info) +{ + struct sh_mobile_lcdc_chan *ch = info->par; + struct sh_mobile_lcdc_priv *p = ch->lcdc; + + /* blank the screen? */ + if (blank > FB_BLANK_UNBLANK && ch->blank_status == FB_BLANK_UNBLANK) { + struct fb_fillrect rect = { + .width = info->var.xres, + .height = info->var.yres, + }; + sh_mobile_lcdc_fillrect(info, &rect); + } + /* turn clocks on? */ + if (blank <= FB_BLANK_NORMAL && ch->blank_status > FB_BLANK_NORMAL) { + sh_mobile_lcdc_clk_on(p); + } + /* turn clocks off? */ + if (blank > FB_BLANK_NORMAL && ch->blank_status <= FB_BLANK_NORMAL) { + /* make sure the screen is updated with the black fill before + * switching the clocks off. one vsync is not enough since + * blanking may occur in the middle of a refresh. deferred io + * mode will reenable the clocks and update the screen in time, + * so it does not need this. */ + if (!info->fbdefio) { + sh_mobile_wait_for_vsync(info); + sh_mobile_wait_for_vsync(info); + } + sh_mobile_lcdc_clk_off(p); + } + + ch->blank_status = blank; + return 0; +} + static struct fb_ops sh_mobile_lcdc_ops = { .owner = THIS_MODULE, .fb_setcolreg = sh_mobile_lcdc_setcolreg, @@ -985,6 +1028,7 @@ static struct fb_ops sh_mobile_lcdc_ops = { .fb_fillrect = sh_mobile_lcdc_fillrect, .fb_copyarea = sh_mobile_lcdc_copyarea, .fb_imageblit = sh_mobile_lcdc_imageblit, + .fb_blank = sh_mobile_lcdc_blank, .fb_pan_display = sh_mobile_fb_pan_display, .fb_ioctl = sh_mobile_ioctl, .fb_open = sh_mobile_open, diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index 03a22dcbcc59..fad353a7e44c 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h @@ -37,6 +37,7 @@ struct sh_mobile_lcdc_chan { struct completion vsync_completion; struct fb_var_screeninfo display_var; int use_count; + int blank_status; struct mutex open_lock; /* protects the use counter */ }; -- cgit v1.2.2 From 247f99386100d1d1c369ba98120d2edebf5426fc Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 23 Feb 2011 08:41:50 +0000 Subject: fbdev: sh_mobile_lcdcfb: fix module lock acquisition Whenever the LCDC is to be started or stopped, a board callback is checked for existence and invoked. Prior to the invokation, the callback's module lock is also acquired, to be released once the callback returns. However, the order of testing makes it possible for the lock to be acquired and not released in case the callback does not exist. This patch reorders the tests to prevent this particular case. Signed-off-by: Alexandre Courbot Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 65c4ee3628c4..69e2833bd460 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -616,7 +616,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) continue; board_cfg = &ch->cfg.board_cfg; - if (try_module_get(board_cfg->owner) && board_cfg->display_on) { + if (board_cfg->display_on && try_module_get(board_cfg->owner)) { board_cfg->display_on(board_cfg->board_data, ch->info); module_put(board_cfg->owner); } @@ -661,7 +661,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) } board_cfg = &ch->cfg.board_cfg; - if (try_module_get(board_cfg->owner) && board_cfg->display_off) { + if (board_cfg->display_off && try_module_get(board_cfg->owner)) { board_cfg->display_off(board_cfg->board_data); module_put(board_cfg->owner); } @@ -1228,7 +1228,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, switch(action) { case FB_EVENT_SUSPEND: - if (try_module_get(board_cfg->owner) && board_cfg->display_off) { + if (board_cfg->display_off && try_module_get(board_cfg->owner)) { board_cfg->display_off(board_cfg->board_data); module_put(board_cfg->owner); } @@ -1241,7 +1241,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, mutex_unlock(&ch->open_lock); /* HDMI must be enabled before LCDC configuration */ - if (try_module_get(board_cfg->owner) && board_cfg->display_on) { + if (board_cfg->display_on && try_module_get(board_cfg->owner)) { board_cfg->display_on(board_cfg->board_data, info); module_put(board_cfg->owner); } -- cgit v1.2.2 From ca444564a947034557a85357b3911d067cac4b8f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 25 Mar 2011 15:20:14 +0100 Subject: x86: Stop including in two asm header files Stop including in x86 header files which don't need it. This will let the compiler complain when this header is not included by source files when it should, so that contributors can fix the problem before building on other architectures starts to fail. Credits go to Geert for the idea. Signed-off-by: Jean Delvare Cc: James E.J. Bottomley Cc: Geert Uytterhoeven Cc: Stephen Rothwell LKML-Reference: <20110325152014.297890ec@endymion.delvare> [ this also fixes an upstream build bug in drivers/media/rc/ite-cir.c ] Signed-off-by: Ingo Molnar --- drivers/media/rc/ite-cir.c | 1 + drivers/scsi/ultrastor.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index ac0e42b47b2a..accaf6c9789a 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "ite-cir.h" diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 0571ef9639cb..9f4b58b7daad 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -138,6 +138,7 @@ #include #include #include +#include #include #include -- cgit v1.2.2 From f72401e94d159bc4b2beab51d74e956da2c32e0a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 26 Feb 2011 17:34:38 +0100 Subject: watchdog: s3c2410_wdt.c: Convert release_resource to release_region/release_mem_region Request_mem_region should be used with release_mem_region, not release_resource. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,E; @@ *x = request_mem_region(...) ... when != release_mem_region(x) when != x = E * release_resource(x); // Signed-off-by: Julia Lawall Signed-off-by: Wim Van Sebroeck Cc: stable --- drivers/watchdog/s3c2410_wdt.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 25b39bf35925..f7f5aa00df60 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -402,7 +402,6 @@ static inline void s3c2410wdt_cpufreq_deregister(void) static int __devinit s3c2410wdt_probe(struct platform_device *pdev) { - struct resource *res; struct device *dev; unsigned int wtcon; int started = 0; @@ -416,20 +415,19 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) /* get the memory region for the watchdog timer */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { + wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (wdt_mem == NULL) { dev_err(dev, "no memory resource specified\n"); return -ENOENT; } - size = resource_size(res); - wdt_mem = request_mem_region(res->start, size, pdev->name); - if (wdt_mem == NULL) { + size = resource_size(wdt_mem); + if (!request_mem_region(wdt_mem->start, size, pdev->name)) { dev_err(dev, "failed to get memory region\n"); return -EBUSY; } - wdt_base = ioremap(res->start, size); + wdt_base = ioremap(wdt_mem->start, size); if (wdt_base == NULL) { dev_err(dev, "failed to ioremap() region\n"); ret = -EINVAL; @@ -524,8 +522,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) iounmap(wdt_base); err_req: - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, size); + wdt_mem = NULL; return ret; } @@ -545,8 +543,7 @@ static int __devexit s3c2410wdt_remove(struct platform_device *dev) iounmap(wdt_base); - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, resource_size(wdt_mem)); wdt_mem = NULL; return 0; } -- cgit v1.2.2 From f712eacf02ecfbf4f1686addb8c569841549b0b7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 26 Feb 2011 17:34:39 +0100 Subject: watchdog: Convert release_resource to release_region/release_mem_region Request_mem_region should be used with release_mem_region, not release_resource. In pnx4008_wdt.c, a missing clk_put is added as well. The semantic match that finds the first problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x,E; @@ *x = request_mem_region(...) ... when != release_mem_region(x) when != x = E * release_resource(x); // Signed-off-by: Julia Lawall Signed-off-by: Wim Van Sebroeck Cc: stable --- drivers/watchdog/davinci_wdt.c | 22 ++++++++++------------ drivers/watchdog/max63xx_wdt.c | 20 ++++++++------------ drivers/watchdog/pnx4008_wdt.c | 28 +++++++++++++--------------- 3 files changed, 31 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 596ba604e78d..51b5551b4e3f 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -202,7 +202,6 @@ static struct miscdevice davinci_wdt_miscdev = { static int __devinit davinci_wdt_probe(struct platform_device *pdev) { int ret = 0, size; - struct resource *res; struct device *dev = &pdev->dev; wdt_clk = clk_get(dev, NULL); @@ -216,31 +215,31 @@ static int __devinit davinci_wdt_probe(struct platform_device *pdev) dev_info(dev, "heartbeat %d sec\n", heartbeat); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { + wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (wdt_mem == NULL) { dev_err(dev, "failed to get memory region resource\n"); return -ENOENT; } - size = resource_size(res); - wdt_mem = request_mem_region(res->start, size, pdev->name); - - if (wdt_mem == NULL) { + size = resource_size(wdt_mem); + if (!request_mem_region(wdt_mem->start, size, pdev->name)) { dev_err(dev, "failed to get memory region\n"); return -ENOENT; } - wdt_base = ioremap(res->start, size); + wdt_base = ioremap(wdt_mem->start, size); if (!wdt_base) { dev_err(dev, "failed to map memory region\n"); + release_mem_region(wdt_mem->start, size); + wdt_mem = NULL; return -ENOMEM; } ret = misc_register(&davinci_wdt_miscdev); if (ret < 0) { dev_err(dev, "cannot register misc device\n"); - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, size); + wdt_mem = NULL; } else { set_bit(WDT_DEVICE_INITED, &wdt_status); } @@ -253,8 +252,7 @@ static int __devexit davinci_wdt_remove(struct platform_device *pdev) { misc_deregister(&davinci_wdt_miscdev); if (wdt_mem) { - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, resource_size(wdt_mem)); wdt_mem = NULL; } diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c index 7a82ce5a6337..73ba2fd8e591 100644 --- a/drivers/watchdog/max63xx_wdt.c +++ b/drivers/watchdog/max63xx_wdt.c @@ -270,7 +270,6 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev) { int ret = 0; int size; - struct resource *res; struct device *dev = &pdev->dev; struct max63xx_timeout *table; @@ -294,21 +293,19 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev) max63xx_pdev = pdev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { + wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (wdt_mem == NULL) { dev_err(dev, "failed to get memory region resource\n"); return -ENOENT; } - size = resource_size(res); - wdt_mem = request_mem_region(res->start, size, pdev->name); - - if (wdt_mem == NULL) { + size = resource_size(wdt_mem); + if (!request_mem_region(wdt_mem->start, size, pdev->name)) { dev_err(dev, "failed to get memory region\n"); return -ENOENT; } - wdt_base = ioremap(res->start, size); + wdt_base = ioremap(wdt_mem->start, size); if (!wdt_base) { dev_err(dev, "failed to map memory region\n"); ret = -ENOMEM; @@ -326,8 +323,8 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev) out_unmap: iounmap(wdt_base); out_request: - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, size); + wdt_mem = NULL; return ret; } @@ -336,8 +333,7 @@ static int __devexit max63xx_wdt_remove(struct platform_device *pdev) { misc_deregister(&max63xx_wdt_miscdev); if (wdt_mem) { - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, resource_size(wdt_mem)); wdt_mem = NULL; } diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index c7cf4cbf8ab3..614933225560 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c @@ -254,7 +254,6 @@ static struct miscdevice pnx4008_wdt_miscdev = { static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) { int ret = 0, size; - struct resource *res; if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) heartbeat = DEFAULT_HEARTBEAT; @@ -262,42 +261,42 @@ static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) printk(KERN_INFO MODULE_NAME "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { + wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (wdt_mem == NULL) { printk(KERN_INFO MODULE_NAME "failed to get memory region resouce\n"); return -ENOENT; } - size = resource_size(res); - wdt_mem = request_mem_region(res->start, size, pdev->name); + size = resource_size(wdt_mem); - if (wdt_mem == NULL) { + if (!request_mem_region(wdt_mem->start, size, pdev->name)) { printk(KERN_INFO MODULE_NAME "failed to get memory region\n"); return -ENOENT; } - wdt_base = (void __iomem *)IO_ADDRESS(res->start); + wdt_base = (void __iomem *)IO_ADDRESS(wdt_mem->start); wdt_clk = clk_get(&pdev->dev, NULL); if (IS_ERR(wdt_clk)) { ret = PTR_ERR(wdt_clk); - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, size); + wdt_mem = NULL; goto out; } ret = clk_enable(wdt_clk); if (ret) { - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, size); + wdt_mem = NULL; + clk_put(wdt_clk); goto out; } ret = misc_register(&pnx4008_wdt_miscdev); if (ret < 0) { printk(KERN_ERR MODULE_NAME "cannot register misc device\n"); - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, size); + wdt_mem = NULL; clk_disable(wdt_clk); clk_put(wdt_clk); } else { @@ -320,8 +319,7 @@ static int __devexit pnx4008_wdt_remove(struct platform_device *pdev) clk_put(wdt_clk); if (wdt_mem) { - release_resource(wdt_mem); - kfree(wdt_mem); + release_mem_region(wdt_mem->start, resource_size(wdt_mem)); wdt_mem = NULL; } return 0; -- cgit v1.2.2 From 90d241edd13bdeef70f264b569f7e150bf23621e Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 16 Mar 2011 20:01:07 -0700 Subject: watchdog: sp5100_tco.c: Check if firmware has set correct value in tcobase. Stefano found SP5100 TCO watchdog driver using wrong address. [ 9.148536] SP5100 TCO timer: SP5100 TCO WatchDog Timer Driver v0.01 [ 9.148628] DEBUG __ioremap_caller WARNING address=b8fe00 size=8 valid=1 reserved=1 and e820 said that range is RAM. We should check if we can use that reading out. BIOS could just program wrong address there. Reported-by: Stefano Stabellini Signed-off-by:Yinghai Lu Acked-by: Mike Waychison Tested-by: Konrad Rzeszutek Wilk Signed-off-by: Wim Van Sebroeck Cc: stable --- drivers/watchdog/sp5100_tco.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index 1bc493848ed4..87e0527669d8 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c @@ -42,6 +42,7 @@ #define PFX TCO_MODULE_NAME ": " /* internal variables */ +static u32 tcobase_phys; static void __iomem *tcobase; static unsigned int pm_iobase; static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ @@ -305,10 +306,18 @@ static unsigned char __devinit sp5100_tco_setupdevice(void) /* Low three bits of BASE0 are reserved. */ val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); + if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, + "SP5100 TCO")) { + printk(KERN_ERR PFX "mmio address 0x%04x already in use\n", + val); + goto unreg_region; + } + tcobase_phys = val; + tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); if (tcobase == 0) { printk(KERN_ERR PFX "failed to get tcobase address\n"); - goto unreg_region; + goto unreg_mem_region; } /* Enable watchdog decode bit */ @@ -346,7 +355,8 @@ static unsigned char __devinit sp5100_tco_setupdevice(void) /* Done */ return 1; - iounmap(tcobase); +unreg_mem_region: + release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); unreg_region: release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); exit: @@ -401,6 +411,7 @@ static int __devinit sp5100_tco_init(struct platform_device *dev) exit: iounmap(tcobase); + release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); return ret; } @@ -414,6 +425,7 @@ static void __devexit sp5100_tco_cleanup(void) /* Deregister */ misc_deregister(&sp5100_tco_miscdev); iounmap(tcobase); + release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); } -- cgit v1.2.2 From 708d42472fba9a661a85ce12006c87ba3172a37e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 24 Mar 2011 13:32:44 -0700 Subject: watchdog: fix nv_tco section mismatch Fix section mismatch warning: Mark the called nv_tco_getdevice() as __devinit, just like its caller. WARNING: drivers/watchdog/nv_tco.o(.devinit.text+0x16): Section mismatch in reference from the function nv_tco_init() to the function .init.text:nv_tco_getdevice() The function __devinit nv_tco_init() references a function __init nv_tco_getdevice(). If nv_tco_getdevice is only used by nv_tco_init then annotate nv_tco_getdevice with a matching annotation. Signed-off-by: Randy Dunlap Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/nv_tco.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c index 267377a5a83e..afa78a54711e 100644 --- a/drivers/watchdog/nv_tco.c +++ b/drivers/watchdog/nv_tco.c @@ -302,7 +302,7 @@ MODULE_DEVICE_TABLE(pci, tco_pci_tbl); * Init & exit routines */ -static unsigned char __init nv_tco_getdevice(void) +static unsigned char __devinit nv_tco_getdevice(void) { struct pci_dev *dev = NULL; u32 val; -- cgit v1.2.2 From 7fff4beb311dfab4f18ff2cd64f78ec89296a39a Mon Sep 17 00:00:00 2001 From: Anithra P Janakiraman Date: Mon, 28 Mar 2011 14:29:19 -0700 Subject: watchdog: softdog.c: enhancement to optionally invoke panic instead of reboot on timer expiry This is needed for determining the reason for failure when a softdog timeout occurs. We use softdog to watch for critical application failures and at the minimum a snapshot of the system would help to determine the cause. In such a scenario the application could fail but there isn't a softlockup as such, hence the detect softlockup feature does not help. The patch adds a module parameter soft_panic which when set to 1 causes softdog to invoke panic instead of reboot when the softdog timer expires. By invoking panic we execute kdump if it is configured and the vmcore generated by kdump should provide atleast a minimal idea of the reason for failure. Based on an original patch by Ken Sugawara Signed-off-by: Anithra P J Reviewed-by: WANG Cong Acked-by: Alan Cox Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/watchdog/softdog.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index 100b114e3c3c..bf16ffb4d21e 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c @@ -48,6 +48,7 @@ #include #include #include +#include #define PFX "SoftDog: " @@ -75,6 +76,11 @@ MODULE_PARM_DESC(soft_noboot, "Softdog action, set to 1 to ignore reboots, 0 to reboot " "(default depends on ONLY_TESTING)"); +static int soft_panic; +module_param(soft_panic, int, 0); +MODULE_PARM_DESC(soft_panic, + "Softdog action, set to 1 to panic, 0 to reboot (default=0)"); + /* * Our timer */ @@ -98,7 +104,10 @@ static void watchdog_fire(unsigned long data) if (soft_noboot) printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n"); - else { + else if (soft_panic) { + printk(KERN_CRIT PFX "Initiating panic.\n"); + panic("Software Watchdog Timer expired."); + } else { printk(KERN_CRIT PFX "Initiating system reboot.\n"); emergency_restart(); printk(KERN_CRIT PFX "Reboot didn't ?????\n"); @@ -267,7 +276,8 @@ static struct notifier_block softdog_notifier = { }; static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 " - "initialized. soft_noboot=%d soft_margin=%d sec (nowayout= %d)\n"; + "initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d " + "(nowayout= %d)\n"; static int __init watchdog_init(void) { @@ -298,7 +308,7 @@ static int __init watchdog_init(void) return ret; } - printk(banner, soft_noboot, soft_margin, nowayout); + printk(banner, soft_noboot, soft_margin, soft_panic, nowayout); return 0; } -- cgit v1.2.2 From e2f571d294cc5f944539088bed46abae375b75f6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 17:41:44 +0100 Subject: parisc: Convert irq namespace Convert to the new function names. Scripted with coccinelle. Signed-off-by: Thomas Gleixner Cc: Kyle McMartin Cc: linux-parisc@vger.kernel.org --- drivers/parisc/eisa.c | 2 +- drivers/parisc/gsc.c | 4 ++-- drivers/parisc/superio.c | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c index deeec32a5803..103095bbe8c0 100644 --- a/drivers/parisc/eisa.c +++ b/drivers/parisc/eisa.c @@ -340,7 +340,7 @@ static int __init eisa_probe(struct parisc_device *dev) /* Reserve IRQ2 */ setup_irq(2, &irq2_action); for (i = 0; i < 16; i++) { - set_irq_chip_and_handler(i, &eisa_interrupt_type, + irq_set_chip_and_handler(i, &eisa_interrupt_type, handle_simple_irq); } diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c index ef31080cf591..1bab5a2cd359 100644 --- a/drivers/parisc/gsc.c +++ b/drivers/parisc/gsc.c @@ -152,8 +152,8 @@ int gsc_assign_irq(struct irq_chip *type, void *data) if (irq > GSC_IRQ_MAX) return NO_IRQ; - set_irq_chip_and_handler(irq, type, handle_simple_irq); - set_irq_chip_data(irq, data); + irq_set_chip_and_handler(irq, type, handle_simple_irq); + irq_set_chip_data(irq, data); return irq++; } diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index a4d8ff66a639..e3b76d409dee 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -355,7 +355,8 @@ int superio_fixup_irq(struct pci_dev *pcidev) #endif for (i = 0; i < 16; i++) { - set_irq_chip_and_handler(i, &superio_interrupt_type, handle_simple_irq); + irq_set_chip_and_handler(i, &superio_interrupt_type, + handle_simple_irq); } /* -- cgit v1.2.2 From a821b2793ea958038687c481c1ea7f74c8fcccfd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 14:47:46 +0100 Subject: sh: Use the proper accessor functions Signed-off-by: Thomas Gleixner --- drivers/sh/intc/core.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 5833afbf08d7..2578db524036 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -387,19 +387,16 @@ static int intc_suspend(void) /* enable wakeup irqs belonging to this intc controller */ for_each_active_irq(irq) { struct irq_data *data; - struct irq_desc *desc; struct irq_chip *chip; data = irq_get_irq_data(irq); chip = irq_data_get_irq_chip(data); if (chip != &d->chip) continue; - desc = irq_to_desc(irq); - if ((desc->status & IRQ_WAKEUP)) + if (irqd_is_wakeup_set(data)) chip->irq_enable(data); } } - return 0; } @@ -412,7 +409,6 @@ static void intc_resume(void) for_each_active_irq(irq) { struct irq_data *data; - struct irq_desc *desc; struct irq_chip *chip; data = irq_get_irq_data(irq); @@ -423,8 +419,7 @@ static void intc_resume(void) */ if (chip != &d->chip) continue; - desc = irq_to_desc(irq); - if (desc->status & IRQ_DISABLED) + if (irqd_irq_disabled(data)) chip->irq_disable(data); else chip->irq_enable(data); -- cgit v1.2.2 From fcb8918fd242f39496090dbbd6789ab24098295b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 16:31:17 +0100 Subject: sh: Convert to new function names Scripted with coccinelle. Signed-off-by: Thomas Gleixner --- drivers/sh/intc/core.c | 14 +++++++------- drivers/sh/intc/virq.c | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 2578db524036..c6ca115c71df 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -63,7 +63,7 @@ void intc_set_prio_level(unsigned int irq, unsigned int level) static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) { - generic_handle_irq((unsigned int)get_irq_data(irq)); + generic_handle_irq((unsigned int)irq_get_handler_data(irq)); } static void __init intc_register_irq(struct intc_desc *desc, @@ -116,9 +116,9 @@ static void __init intc_register_irq(struct intc_desc *desc, irq_data = irq_get_irq_data(irq); disable_irq_nosync(irq); - set_irq_chip_and_handler_name(irq, &d->chip, - handle_level_irq, "level"); - set_irq_chip_data(irq, (void *)data[primary]); + irq_set_chip_and_handler_name(irq, &d->chip, handle_level_irq, + "level"); + irq_set_chip_data(irq, (void *)data[primary]); /* * set priority level @@ -340,9 +340,9 @@ int __init register_intc_controller(struct intc_desc *desc) vect2->enum_id = 0; /* redirect this interrupts to the first one */ - set_irq_chip(irq2, &dummy_irq_chip); - set_irq_chained_handler(irq2, intc_redirect_irq); - set_irq_data(irq2, (void *)irq); + irq_set_chip(irq2, &dummy_irq_chip); + irq_set_chained_handler(irq2, intc_redirect_irq); + irq_set_handler_data(irq2, (void *)irq); } } diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index 4e0ff7181164..ce5f81d7cc6b 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -110,7 +110,7 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) { struct irq_data *data = irq_get_irq_data(irq); struct irq_chip *chip = irq_data_get_irq_chip(data); - struct intc_virq_list *entry, *vlist = irq_data_get_irq_data(data); + struct intc_virq_list *entry, *vlist = irq_data_get_irq_handler_data(data); struct intc_desc_int *d = get_intc_desc(irq); chip->irq_mask_ack(data); @@ -118,7 +118,7 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) for_each_virq(entry, vlist) { unsigned long addr, handle; - handle = (unsigned long)get_irq_data(entry->irq); + handle = (unsigned long)irq_get_handler_data(entry->irq); addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) @@ -229,13 +229,13 @@ restart: intc_irq_xlate_set(irq, entry->enum_id, d); - set_irq_chip_and_handler_name(irq, get_irq_chip(entry->pirq), + irq_set_chip_and_handler_name(irq, irq_get_chip(entry->pirq), handle_simple_irq, "virq"); - set_irq_chip_data(irq, get_irq_chip_data(entry->pirq)); + irq_set_chip_data(irq, irq_get_chip_data(entry->pirq)); - set_irq_data(irq, (void *)entry->handle); + irq_set_handler_data(irq, (void *)entry->handle); - set_irq_chained_handler(entry->pirq, intc_virq_handler); + irq_set_chained_handler(entry->pirq, intc_virq_handler); add_virq_to_pirq(entry->pirq, irq); radix_tree_tag_clear(&d->tree, entry->enum_id, -- cgit v1.2.2 From c442b8068f7c53c40a73a82bbfd96d3f41f6778c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 10:58:06 +0100 Subject: xen: Cleanup genirq namespace Converted with coccinelle. Signed-off-by: Thomas Gleixner --- drivers/xen/events.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 02b5a9c05cfa..0e7e394e42f2 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -122,7 +122,7 @@ static struct irq_chip xen_pirq_chip; /* Get info for IRQ */ static struct irq_info *info_for_irq(unsigned irq) { - return get_irq_data(irq); + return irq_get_handler_data(irq); } /* Constructors for packed IRQ information. */ @@ -403,7 +403,7 @@ static void xen_irq_init(unsigned irq) info->type = IRQT_UNBOUND; - set_irq_data(irq, info); + irq_set_handler_data(irq, info); list_add_tail(&info->list, &xen_irq_list_head); } @@ -458,11 +458,11 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi) static void xen_free_irq(unsigned irq) { - struct irq_info *info = get_irq_data(irq); + struct irq_info *info = irq_get_handler_data(irq); list_del(&info->list); - set_irq_data(irq, NULL); + irq_set_handler_data(irq, NULL); kfree(info); @@ -639,8 +639,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, if (irq < 0) goto out; - set_irq_chip_and_handler_name(irq, &xen_pirq_chip, - handle_level_irq, name); + irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, + name); irq_op.irq = irq; irq_op.vector = 0; @@ -690,8 +690,8 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, if (irq == -1) goto out; - set_irq_chip_and_handler_name(irq, &xen_pirq_chip, - handle_level_irq, name); + irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, + name); xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); ret = irq_set_msi_desc(irq, msidesc); @@ -772,7 +772,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) if (irq == -1) goto out; - set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, + irq_set_chip_and_handler_name(irq, &xen_dynamic_chip, handle_fasteoi_irq, "event"); xen_irq_info_evtchn_init(irq, evtchn); @@ -799,7 +799,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) if (irq < 0) goto out; - set_irq_chip_and_handler_name(irq, &xen_percpu_chip, + irq_set_chip_and_handler_name(irq, &xen_percpu_chip, handle_percpu_irq, "ipi"); bind_ipi.vcpu = cpu; @@ -848,7 +848,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) if (irq == -1) goto out; - set_irq_chip_and_handler_name(irq, &xen_percpu_chip, + irq_set_chip_and_handler_name(irq, &xen_percpu_chip, handle_percpu_irq, "virq"); bind_virq.virq = virq; -- cgit v1.2.2 From a3b975c49e3e21864268892760f630433d96e01a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 21:31:25 +0100 Subject: xen: Use new irq_move functions These functions take irq_data as an argument and avoid a redundant lookup in the sparse irq case. Signed-off-by: Thomas Gleixner Cc: Ian Campbell Cc: Jeremy Fitzhardinge Cc: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0e7e394e42f2..036343ba204e 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -585,7 +585,7 @@ static void ack_pirq(struct irq_data *data) { int evtchn = evtchn_from_irq(data->irq); - move_native_irq(data->irq); + irq_move_irq(data); if (VALID_EVTCHN(evtchn)) { mask_evtchn(evtchn); @@ -1339,7 +1339,7 @@ static void ack_dynirq(struct irq_data *data) { int evtchn = evtchn_from_irq(data->irq); - move_masked_irq(data->irq); + irq_move_masked_irq(data); if (VALID_EVTCHN(evtchn)) unmask_evtchn(evtchn); -- cgit v1.2.2 From dced35aeb0367dda2636ee9ee914bda14510dcc9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 28 Mar 2011 17:49:12 +0200 Subject: drivers: Final irq namespace conversion Scripted with coccinelle. Signed-off-by: Thomas Gleixner --- drivers/ata/pata_ixp4xx_cf.c | 2 +- drivers/ata/pata_rb532_cf.c | 4 ++-- drivers/hwmon/gpio-fan.c | 2 +- drivers/input/keyboard/lm8323.c | 4 ++-- drivers/input/serio/ams_delta_serio.c | 2 +- drivers/input/touchscreen/mainstone-wm97xx.c | 2 +- drivers/input/touchscreen/zylonite-wm97xx.c | 2 +- drivers/misc/sgi-gru/grufile.c | 2 +- drivers/mmc/host/sdhci-spear.c | 2 +- drivers/net/dm9000.c | 8 ++++---- drivers/net/wireless/p54/p54spi.c | 3 +-- drivers/net/wireless/wl1251/sdio.c | 2 +- drivers/net/wireless/wl1251/spi.c | 2 +- drivers/pci/dmar.c | 12 ++++++------ drivers/pci/htirq.c | 16 ++++++++-------- drivers/pci/intel-iommu.c | 2 +- drivers/pci/intr_remapping.c | 2 +- drivers/pci/msi.c | 10 +++++----- drivers/pcmcia/bfin_cf_pcmcia.c | 2 +- drivers/pcmcia/db1xxx_ss.c | 2 +- drivers/pcmcia/sa1100_nanoengine.c | 2 +- drivers/pcmcia/soc_common.c | 14 +++++++------- drivers/pcmcia/xxs1500_ss.c | 2 +- drivers/platform/x86/intel_pmic_gpio.c | 8 +++++--- drivers/power/z2_battery.c | 4 ++-- drivers/rtc/rtc-sh.c | 6 +++--- drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c | 4 ++-- .../astoria/arch/arm/mach-omap2/cyashalomap_kernel.c | 2 +- drivers/tty/hvc/hvc_xen.c | 2 +- drivers/tty/serial/msm_serial_hs.c | 4 ++-- drivers/usb/host/oxu210hp-hcd.c | 2 +- drivers/usb/musb/tusb6010.c | 2 +- drivers/w1/masters/ds1wm.c | 4 ++-- 33 files changed, 70 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 5253b271b3fe..f6b3f995f58a 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -167,7 +167,7 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq) - set_irq_type(irq, IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); /* Setup expansion bus chip selects */ *data->cs0_cfg = data->cs0_bits; diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index baeaf938d55b..1b9d10d9c5d9 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -60,10 +60,10 @@ static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance) struct rb532_cf_info *info = ah->private_data; if (gpio_get_value(info->gpio_line)) { - set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); ata_sff_interrupt(info->irq, dev_instance); } else { - set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); + irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); } return IRQ_HANDLED; diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index f141a1de519c..89aa9fb743af 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -116,7 +116,7 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data, return 0; INIT_WORK(&fan_data->alarm_work, fan_alarm_notify); - set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH); err = request_irq(alarm_irq, fan_alarm_irq_handler, IRQF_SHARED, "GPIO fan alarm", fan_data); if (err) diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index b732870ecc89..71f744a8e686 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -809,7 +809,7 @@ static int lm8323_suspend(struct device *dev) struct lm8323_chip *lm = i2c_get_clientdata(client); int i; - set_irq_wake(client->irq, 0); + irq_set_irq_wake(client->irq, 0); disable_irq(client->irq); mutex_lock(&lm->lock); @@ -838,7 +838,7 @@ static int lm8323_resume(struct device *dev) led_classdev_resume(&lm->pwm[i].cdev); enable_irq(client->irq); - set_irq_wake(client->irq, 1); + irq_set_irq_wake(client->irq, 1); return 0; } diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index ebe955325677..4b2a42f9f0bb 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -149,7 +149,7 @@ static int __init ams_delta_serio_init(void) * at FIQ level, switch back from edge to simple interrupt handler * to avoid bad interaction. */ - set_irq_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), + irq_set_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), handle_simple_irq); serio_register_port(ams_delta_serio); diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c index b6b8b1c7ecea..3242e7076258 100644 --- a/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/drivers/input/touchscreen/mainstone-wm97xx.c @@ -219,7 +219,7 @@ static int wm97xx_acc_startup(struct wm97xx *wm) } wm->pen_irq = gpio_to_irq(irq); - set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH); } else /* pen irq not supported */ pen_int = 0; diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c index 048849867643..5b0f15ec874a 100644 --- a/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/drivers/input/touchscreen/zylonite-wm97xx.c @@ -193,7 +193,7 @@ static int zylonite_wm97xx_probe(struct platform_device *pdev) gpio_touch_irq = mfp_to_gpio(MFP_PIN_GPIO26); wm->pen_irq = IRQ_GPIO(gpio_touch_irq); - set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(IRQ_GPIO(gpio_touch_irq), IRQ_TYPE_EDGE_BOTH); wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, WM97XX_GPIO_POL_HIGH, diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index 28852dfa310d..20e4e9395b61 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -373,7 +373,7 @@ static int gru_chiplet_setup_tlb_irq(int chiplet, char *irq_name, if (gru_irq_count[chiplet] == 0) { gru_chip[chiplet].name = irq_name; - ret = set_irq_chip(irq, &gru_chip[chiplet]); + ret = irq_set_chip(irq, &gru_chip[chiplet]); if (ret) { printk(KERN_ERR "%s: set_irq_chip failed, errno=%d\n", GRU_DRIVER_ID_STR, -ret); diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index d70c54c7b70a..60a4c97d3d18 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -50,7 +50,7 @@ static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) /* val == 1 -> card removed, val == 0 -> card inserted */ /* if card removed - set irq for low level, else vice versa */ gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; - set_irq_type(irq, gpio_irq_type); + irq_set_irq_type(irq, gpio_irq_type); if (sdhci->data->card_power_gpio >= 0) { if (!sdhci->data->power_always_enb) { diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 317708113601..b7af5bab9937 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -621,9 +621,9 @@ static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) /* change in wol state, update IRQ state */ if (!dm->wake_state) - set_irq_wake(dm->irq_wake, 1); + irq_set_irq_wake(dm->irq_wake, 1); else if (dm->wake_state & !opts) - set_irq_wake(dm->irq_wake, 0); + irq_set_irq_wake(dm->irq_wake, 0); } dm->wake_state = opts; @@ -1424,13 +1424,13 @@ dm9000_probe(struct platform_device *pdev) } else { /* test to see if irq is really wakeup capable */ - ret = set_irq_wake(db->irq_wake, 1); + ret = irq_set_irq_wake(db->irq_wake, 1); if (ret) { dev_err(db->dev, "irq %d cannot set wakeup (%d)\n", db->irq_wake, ret); ret = 0; } else { - set_irq_wake(db->irq_wake, 0); + irq_set_irq_wake(db->irq_wake, 0); db->wake_supported = 1; } } diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 18d24b7b1e34..7ecc0bda57b3 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -649,8 +649,7 @@ static int __devinit p54spi_probe(struct spi_device *spi) goto err_free_common; } - set_irq_type(gpio_to_irq(p54spi_gpio_irq), - IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING); disable_irq(gpio_to_irq(p54spi_gpio_irq)); diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index d550b5e68d3c..f51a0241a440 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -265,7 +265,7 @@ static int wl1251_sdio_probe(struct sdio_func *func, goto disable; } - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); disable_irq(wl->irq); wl1251_sdio_ops.enable_irq = wl1251_enable_line_irq; diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c index ac872b38960f..af6448c4d3e2 100644 --- a/drivers/net/wireless/wl1251/spi.c +++ b/drivers/net/wireless/wl1251/spi.c @@ -286,7 +286,7 @@ static int __devinit wl1251_spi_probe(struct spi_device *spi) goto out_free; } - set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(wl->irq, IRQ_TYPE_EDGE_RISING); disable_irq(wl->irq); diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 09933eb9126b..12e02bf92c4a 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -1226,7 +1226,7 @@ const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type) void dmar_msi_unmask(struct irq_data *data) { - struct intel_iommu *iommu = irq_data_get_irq_data(data); + struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); unsigned long flag; /* unmask it */ @@ -1240,7 +1240,7 @@ void dmar_msi_unmask(struct irq_data *data) void dmar_msi_mask(struct irq_data *data) { unsigned long flag; - struct intel_iommu *iommu = irq_data_get_irq_data(data); + struct intel_iommu *iommu = irq_data_get_irq_handler_data(data); /* mask it */ spin_lock_irqsave(&iommu->register_lock, flag); @@ -1252,7 +1252,7 @@ void dmar_msi_mask(struct irq_data *data) void dmar_msi_write(int irq, struct msi_msg *msg) { - struct intel_iommu *iommu = get_irq_data(irq); + struct intel_iommu *iommu = irq_get_handler_data(irq); unsigned long flag; spin_lock_irqsave(&iommu->register_lock, flag); @@ -1264,7 +1264,7 @@ void dmar_msi_write(int irq, struct msi_msg *msg) void dmar_msi_read(int irq, struct msi_msg *msg) { - struct intel_iommu *iommu = get_irq_data(irq); + struct intel_iommu *iommu = irq_get_handler_data(irq); unsigned long flag; spin_lock_irqsave(&iommu->register_lock, flag); @@ -1382,12 +1382,12 @@ int dmar_set_interrupt(struct intel_iommu *iommu) return -EINVAL; } - set_irq_data(irq, iommu); + irq_set_handler_data(irq, iommu); iommu->irq = irq; ret = arch_setup_dmar_msi(irq); if (ret) { - set_irq_data(irq, NULL); + irq_set_handler_data(irq, NULL); iommu->irq = 0; destroy_irq(irq); return ret; diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c index 834842aa5bbf..db057b6fe0c8 100644 --- a/drivers/pci/htirq.c +++ b/drivers/pci/htirq.c @@ -34,7 +34,7 @@ struct ht_irq_cfg { void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { - struct ht_irq_cfg *cfg = get_irq_data(irq); + struct ht_irq_cfg *cfg = irq_get_handler_data(irq); unsigned long flags; spin_lock_irqsave(&ht_irq_lock, flags); if (cfg->msg.address_lo != msg->address_lo) { @@ -53,13 +53,13 @@ void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg) { - struct ht_irq_cfg *cfg = get_irq_data(irq); + struct ht_irq_cfg *cfg = irq_get_handler_data(irq); *msg = cfg->msg; } void mask_ht_irq(struct irq_data *data) { - struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); + struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); struct ht_irq_msg msg = cfg->msg; msg.address_lo |= 1; @@ -68,7 +68,7 @@ void mask_ht_irq(struct irq_data *data) void unmask_ht_irq(struct irq_data *data) { - struct ht_irq_cfg *cfg = irq_data_get_irq_data(data); + struct ht_irq_cfg *cfg = irq_data_get_irq_handler_data(data); struct ht_irq_msg msg = cfg->msg; msg.address_lo &= ~1; @@ -126,7 +126,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update) kfree(cfg); return -EBUSY; } - set_irq_data(irq, cfg); + irq_set_handler_data(irq, cfg); if (arch_setup_ht_irq(irq, dev) < 0) { ht_destroy_irq(irq); @@ -162,9 +162,9 @@ void ht_destroy_irq(unsigned int irq) { struct ht_irq_cfg *cfg; - cfg = get_irq_data(irq); - set_irq_chip(irq, NULL); - set_irq_data(irq, NULL); + cfg = irq_get_handler_data(irq); + irq_set_chip(irq, NULL); + irq_set_handler_data(irq, NULL); destroy_irq(irq); kfree(cfg); diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index a4115f1afe1f..7da3bef60d87 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1206,7 +1206,7 @@ void free_dmar_iommu(struct intel_iommu *iommu) iommu_disable_translation(iommu); if (iommu->irq) { - set_irq_data(iommu->irq, NULL); + irq_set_handler_data(iommu->irq, NULL); /* This will mask the irq */ free_irq(iommu->irq, iommu); destroy_irq(iommu->irq); diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index ec87cd66f3eb..a22557b20283 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(irq_2_ir_lock); static struct irq_2_iommu *irq_2_iommu(unsigned int irq) { - struct irq_cfg *cfg = get_irq_chip_data(irq); + struct irq_cfg *cfg = irq_get_chip_data(irq); return cfg ? &cfg->irq_2_iommu : NULL; } diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 44b0aeee83e5..2f10328bf661 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -236,7 +236,7 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void read_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct msi_desc *entry = irq_get_msi_desc(irq); __read_msi_msg(entry, msg); } @@ -253,7 +253,7 @@ void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct msi_desc *entry = irq_get_msi_desc(irq); __get_cached_msi_msg(entry, msg); } @@ -297,7 +297,7 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void write_msi_msg(unsigned int irq, struct msi_msg *msg) { - struct msi_desc *entry = get_irq_msi(irq); + struct msi_desc *entry = irq_get_msi_desc(irq); __write_msi_msg(entry, msg); } @@ -354,7 +354,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) if (!dev->msi_enabled) return; - entry = get_irq_msi(dev->irq); + entry = irq_get_msi_desc(dev->irq); pos = entry->msi_attrib.pos; pci_intx_for_msi(dev, 0); @@ -519,7 +519,7 @@ static void msix_program_entries(struct pci_dev *dev, PCI_MSIX_ENTRY_VECTOR_CTRL; entries[i].vector = entry->irq; - set_irq_msi(entry->irq, entry); + irq_set_msi_desc(entry->irq, entry); entry->masked = readl(entry->mask_base + offset); msix_mask_irq(entry, 1); i++; diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c index eae9cbe37a3e..49221395101e 100644 --- a/drivers/pcmcia/bfin_cf_pcmcia.c +++ b/drivers/pcmcia/bfin_cf_pcmcia.c @@ -235,7 +235,7 @@ static int __devinit bfin_cf_probe(struct platform_device *pdev) cf->irq = irq; cf->socket.pci_irq = irq; - set_irq_type(irq, IRQF_TRIGGER_LOW); + irq_set_irq_type(irq, IRQF_TRIGGER_LOW); io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index 27575e6378a1..01757f18a208 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -181,7 +181,7 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock) /* all other (older) Db1x00 boards use a GPIO to show * card detection status: use both-edge triggers. */ - set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH); ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq, 0, "pcmcia_carddetect", sock); diff --git a/drivers/pcmcia/sa1100_nanoengine.c b/drivers/pcmcia/sa1100_nanoengine.c index 3d2652e2f5ae..93b9c9ba57c3 100644 --- a/drivers/pcmcia/sa1100_nanoengine.c +++ b/drivers/pcmcia/sa1100_nanoengine.c @@ -86,7 +86,7 @@ static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt) 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); + irq_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, diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 5a9a392eacdf..768f9572a8c8 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -155,11 +155,11 @@ static int soc_common_pcmcia_config_skt( */ if (skt->irq_state != 1 && state->io_irq) { skt->irq_state = 1; - set_irq_type(skt->socket.pci_irq, - IRQ_TYPE_EDGE_FALLING); + irq_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); + irq_set_irq_type(skt->socket.pci_irq, IRQ_TYPE_NONE); } skt->cs_state = *state; @@ -537,7 +537,7 @@ int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt, IRQF_DISABLED, irqs[i].str, skt); if (res) break; - set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); + irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); } if (res) { @@ -570,7 +570,7 @@ void soc_pcmcia_disable_irqs(struct soc_pcmcia_socket *skt, for (i = 0; i < nr; i++) if (irqs[i].sock == skt->nr) - set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); + irq_set_irq_type(irqs[i].irq, IRQ_TYPE_NONE); } EXPORT_SYMBOL(soc_pcmcia_disable_irqs); @@ -581,8 +581,8 @@ void soc_pcmcia_enable_irqs(struct soc_pcmcia_socket *skt, for (i = 0; i < nr; i++) if (irqs[i].sock == skt->nr) { - set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING); - set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(irqs[i].irq, IRQ_TYPE_EDGE_BOTH); } } EXPORT_SYMBOL(soc_pcmcia_enable_irqs); diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c index 3b67a1b6a197..379f4218857d 100644 --- a/drivers/pcmcia/xxs1500_ss.c +++ b/drivers/pcmcia/xxs1500_ss.c @@ -274,7 +274,7 @@ static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev) * edge detector. */ irq = gpio_to_irq(GPIO_CDA); - set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock); if (ret) { dev_err(&pdev->dev, "cannot setup cd irq\n"); diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 61433d492862..d653104b59cb 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -257,9 +257,11 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) } for (i = 0; i < 8; i++) { - set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip, - handle_simple_irq, "demux"); - set_irq_chip_data(i + pg->irq_base, pg); + irq_set_chip_and_handler_name(i + pg->irq_base, + &pmic_irqchip, + handle_simple_irq, + "demux"); + irq_set_chip_data(i + pg->irq_base, pg); } return 0; err: diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index 2a9ab89f83b8..e5ced3a4c1ed 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c @@ -215,8 +215,8 @@ static int __devinit z2_batt_probe(struct i2c_client *client, if (ret) goto err2; - set_irq_type(gpio_to_irq(info->charge_gpio), - IRQ_TYPE_EDGE_BOTH); + irq_set_irq_type(gpio_to_irq(info->charge_gpio), + IRQ_TYPE_EDGE_BOTH); ret = request_irq(gpio_to_irq(info->charge_gpio), z2_charge_switch_irq, IRQF_DISABLED, "AC Detect", charger); diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index e55dc1ac83ab..6ac55fd48413 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -782,11 +782,11 @@ static void sh_rtc_set_irq_wake(struct device *dev, int enabled) struct platform_device *pdev = to_platform_device(dev); struct sh_rtc *rtc = platform_get_drvdata(pdev); - set_irq_wake(rtc->periodic_irq, enabled); + irq_set_irq_wake(rtc->periodic_irq, enabled); if (rtc->carry_irq > 0) { - set_irq_wake(rtc->carry_irq, enabled); - set_irq_wake(rtc->alarm_irq, enabled); + irq_set_irq_wake(rtc->carry_irq, enabled); + irq_set_irq_wake(rtc->alarm_irq, enabled); } } diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c index e3556ff43bb9..ac5bbc8722e5 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c @@ -341,7 +341,7 @@ int bcmsdh_register_oob_intr(void *dhdp) if (error) return -ENODEV; - set_irq_wake(sdhcinfo->oob_irq, 1); + irq_set_irq_wake(sdhcinfo->oob_irq, 1); sdhcinfo->oob_irq_registered = true; } @@ -352,7 +352,7 @@ void bcmsdh_unregister_oob_intr(void) { SDLX_MSG(("%s: Enter\n", __func__)); - set_irq_wake(sdhcinfo->oob_irq, 0); + irq_set_irq_wake(sdhcinfo->oob_irq, 0); disable_irq(sdhcinfo->oob_irq); /* just in case.. */ free_irq(sdhcinfo->oob_irq, NULL); sdhcinfo->oob_irq_registered = false; diff --git a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c index ea9b733c3926..21cdb0637beb 100644 --- a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c +++ b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c @@ -597,7 +597,7 @@ static int cy_as_hal_configure_interrupts(void *dev_p) int result; int irq_pin = AST_INT; - set_irq_type(OMAP_GPIO_IRQ(irq_pin), IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(OMAP_GPIO_IRQ(irq_pin), IRQ_TYPE_LEVEL_LOW); /* * for shared IRQS must provide non NULL device ptr diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index c35f1a73bc8b..52fdf60bdbe2 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -178,7 +178,7 @@ static int __init xen_hvc_init(void) if (xencons_irq < 0) xencons_irq = 0; /* NO_IRQ */ else - set_irq_noprobe(xencons_irq); + irq_set_noprobe(xencons_irq); hp = hvc_alloc(HVC_COOKIE, xencons_irq, ops, 256); if (IS_ERR(hp)) diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index 2e7fc9cee9cc..b906f11f7c1a 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -1644,7 +1644,7 @@ static int __devinit msm_hs_probe(struct platform_device *pdev) if (unlikely(uport->irq < 0)) return -ENXIO; - if (unlikely(set_irq_wake(uport->irq, 1))) + if (unlikely(irq_set_irq_wake(uport->irq, 1))) return -ENXIO; if (pdata == NULL || pdata->rx_wakeup_irq < 0) @@ -1658,7 +1658,7 @@ static int __devinit msm_hs_probe(struct platform_device *pdev) if (unlikely(msm_uport->rx_wakeup.irq < 0)) return -ENXIO; - if (unlikely(set_irq_wake(msm_uport->rx_wakeup.irq, 1))) + if (unlikely(irq_set_irq_wake(msm_uport->rx_wakeup.irq, 1))) return -ENXIO; } diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 38193f4e980e..44e4deb362e1 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -3832,7 +3832,7 @@ static int oxu_drv_probe(struct platform_device *pdev) return -EBUSY; } - ret = set_irq_type(irq, IRQF_TRIGGER_FALLING); + ret = irq_set_irq_type(irq, IRQF_TRIGGER_FALLING); if (ret) { dev_err(&pdev->dev, "error setting irq type\n"); ret = -EFAULT; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 2ba3b070ed0b..c47aac4a1f98 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -943,7 +943,7 @@ static void tusb_musb_enable(struct musb *musb) musb_writel(tbase, TUSB_INT_CTRL_CONF, TUSB_INT_CTRL_CONF_INT_RELCYC(0)); - set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW); + irq_set_irq_type(musb->nIrq, IRQ_TYPE_LEVEL_LOW); /* maybe force into the Default-A OTG state machine */ if (!(musb_readl(tbase, TUSB_DEV_OTG_STAT) diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 95921b77cf86..2f4fa02744a5 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -368,9 +368,9 @@ static int ds1wm_probe(struct platform_device *pdev) ds1wm_data->active_high = plat->active_high; if (res->flags & IORESOURCE_IRQ_HIGHEDGE) - set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); + irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); if (res->flags & IORESOURCE_IRQ_LOWEDGE) - set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); + irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED, "ds1wm", ds1wm_data); -- cgit v1.2.2 From 9ad198cba2a8177eea6a7f2f0202b910abdef96b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 29 Mar 2011 04:02:50 +0200 Subject: gpio: ab8500: Mark broken This driver is broken in several aspects. 1) old style irq_chip functions. Sigh 2) Abuse of the unlock callback. That's not supposed to be a state machine for evrything and some more. Signed-off-by: Thomas Gleixner --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d3743204a7e9..d3b295305542 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -416,7 +416,7 @@ config GPIO_JANZ_TTL config AB8500_GPIO bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions" - depends on AB8500_CORE + depends on AB8500_CORE && BROKEN help Select this to enable the AB8500 IC GPIO driver endif -- cgit v1.2.2 From 3b3af761669ae59530a8be763b83c937c6096772 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 25 Mar 2011 11:01:39 +0100 Subject: xen: Convert genirq namespace Converted with coccinelle. Signed-off-by: Thomas Gleixner Acked-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 02b5a9c05cfa..0e7e394e42f2 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -122,7 +122,7 @@ static struct irq_chip xen_pirq_chip; /* Get info for IRQ */ static struct irq_info *info_for_irq(unsigned irq) { - return get_irq_data(irq); + return irq_get_handler_data(irq); } /* Constructors for packed IRQ information. */ @@ -403,7 +403,7 @@ static void xen_irq_init(unsigned irq) info->type = IRQT_UNBOUND; - set_irq_data(irq, info); + irq_set_handler_data(irq, info); list_add_tail(&info->list, &xen_irq_list_head); } @@ -458,11 +458,11 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi) static void xen_free_irq(unsigned irq) { - struct irq_info *info = get_irq_data(irq); + struct irq_info *info = irq_get_handler_data(irq); list_del(&info->list); - set_irq_data(irq, NULL); + irq_set_handler_data(irq, NULL); kfree(info); @@ -639,8 +639,8 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, if (irq < 0) goto out; - set_irq_chip_and_handler_name(irq, &xen_pirq_chip, - handle_level_irq, name); + irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, + name); irq_op.irq = irq; irq_op.vector = 0; @@ -690,8 +690,8 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, if (irq == -1) goto out; - set_irq_chip_and_handler_name(irq, &xen_pirq_chip, - handle_level_irq, name); + irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_level_irq, + name); xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); ret = irq_set_msi_desc(irq, msidesc); @@ -772,7 +772,7 @@ int bind_evtchn_to_irq(unsigned int evtchn) if (irq == -1) goto out; - set_irq_chip_and_handler_name(irq, &xen_dynamic_chip, + irq_set_chip_and_handler_name(irq, &xen_dynamic_chip, handle_fasteoi_irq, "event"); xen_irq_info_evtchn_init(irq, evtchn); @@ -799,7 +799,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) if (irq < 0) goto out; - set_irq_chip_and_handler_name(irq, &xen_percpu_chip, + irq_set_chip_and_handler_name(irq, &xen_percpu_chip, handle_percpu_irq, "ipi"); bind_ipi.vcpu = cpu; @@ -848,7 +848,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu) if (irq == -1) goto out; - set_irq_chip_and_handler_name(irq, &xen_percpu_chip, + irq_set_chip_and_handler_name(irq, &xen_percpu_chip, handle_percpu_irq, "virq"); bind_virq.virq = virq; -- cgit v1.2.2 From e240ae4aad9c5c0da189cb6c956cca58abd428d0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 21:37:31 +0100 Subject: xen: Use new irq_move functions These functions take irq_data as an argument and avoid a redundant lookup in the sparse irq case. Signed-off-by: Thomas Gleixner Cc: Ian Campbell Cc: Jeremy Fitzhardinge Cc: Konrad Rzeszutek Wilk Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0e7e394e42f2..036343ba204e 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -585,7 +585,7 @@ static void ack_pirq(struct irq_data *data) { int evtchn = evtchn_from_irq(data->irq); - move_native_irq(data->irq); + irq_move_irq(data); if (VALID_EVTCHN(evtchn)) { mask_evtchn(evtchn); @@ -1339,7 +1339,7 @@ static void ack_dynirq(struct irq_data *data) { int evtchn = evtchn_from_irq(data->irq); - move_masked_irq(data->irq); + irq_move_masked_irq(data); if (VALID_EVTCHN(evtchn)) unmask_evtchn(evtchn); -- cgit v1.2.2 From a9f0fbe2bbf328f869fc5ee5a12c6a4118c32689 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 29 Mar 2011 18:10:53 +0200 Subject: amd64_edac: Fix potential memleak We check the pointers together but at least one of them could be invalid due to failed allocation. Since we cannot continue if either of the two allocations has failed, exit early by freeing them both. Cc: # 38.x Reported-by: Mauro Carvalho Chehab Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 0be30e978c85..31e71c4fc831 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -2679,7 +2679,7 @@ static int __init amd64_edac_init(void) mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL); ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL); if (!(mcis && ecc_stngs)) - goto err_ret; + goto err_free; msrs = msrs_alloc(); if (!msrs) -- cgit v1.2.2 From 1309d7afbed112f0e8e90be9af975550caa0076b Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 29 Mar 2011 13:31:25 +0200 Subject: char/tpm: Fix unitialized usage of data buffer This patch fixes information leakage to the userspace by initializing the data buffer to zero. Reported-by: Peter Huewe Signed-off-by: Peter Huewe Signed-off-by: Marcel Selhorst [ Also removed the silly "* sizeof(u8)". If that isn't 1, we have way deeper problems than a simple multiplication can fix. - Linus ] Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 1f46f1cd9225..7beb0e25f1e1 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -980,7 +980,7 @@ int tpm_open(struct inode *inode, struct file *file) return -EBUSY; } - chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); + chip->data_buffer = kzalloc(TPM_BUFSIZE, GFP_KERNEL); if (chip->data_buffer == NULL) { clear_bit(0, &chip->is_open); put_device(chip->dev); -- cgit v1.2.2 From 3bda50e3eaf58a4b9c4ce34204e5faa15c8b1b97 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 14 Mar 2011 14:15:06 +0100 Subject: iwl3945: do not deprecate software scan Software scanning can be used for workaround some performance problems, so do not deprecate it. Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl3945-base.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index ab87e1b73529..b6c52095bc1a 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -3960,8 +3960,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * "the hard way", rather than using device's scan. */ if (iwl3945_mod_params.disable_hw_scan) { - dev_printk(KERN_DEBUG, &(pdev->dev), - "sw scan support is deprecated\n"); + IWL_DEBUG_INFO(priv, "Disabling hw_scan\n"); iwl3945_hw_ops.hw_scan = NULL; } @@ -4280,8 +4279,7 @@ MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])"); module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, - "disable hardware scanning (default 0) (deprecated)"); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG module_param_named(debug, iwlegacy_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); -- cgit v1.2.2 From 8d4ca61a10feea9583dc62ec1514722e99bdcd3d Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Sun, 27 Mar 2011 20:33:06 +0200 Subject: wireless: rt2x00: rt2800usb.c add and identify ids taken from staging/rt2860 0x0411,0x016f de37cd49b5a54facef174cf34496919857436e8f MelCo(Buffalo) WLI-UC-G301N 0x050d,0x825b 12840c63b0679f7fab88ea1cc26b52db8b574ce7 Belkin F5D8055 0x050d,0x935a 705059a670f3af2b37695e82de0ee58e75e656ed Belkin F6D4050 v1 0x050d,0x935b 5d92fe3387d086fc2f10426fbdb6b86d6cce5a47 Belkin F6D4050 v2 identifed from ralink driverss 0x0930,0x0a07 RT35xx TOSHIBA 2010_1215_RT3572_Linux_STA_v2.5.0.0.DPO 0x1d4d,0x0011 3072 Pegatron 2011_0107_RT3070_RT3370_Linux_STA_v2.5.0.1_DPO Signed-off-by: Xose Vazquez Perez Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2800usb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 4e368657a83c..37509d019910 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -730,8 +730,12 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x825b), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x935a), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x050d, 0x935b), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Conceptronic */ { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -818,6 +822,7 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Pegatron */ { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) }, + { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Philips */ { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ @@ -899,6 +904,8 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Sitecom */ { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) }, + /* Toshiba */ + { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zinwell */ { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) }, #endif @@ -961,7 +968,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) }, - { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Planex */ { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) }, @@ -975,8 +981,6 @@ static struct usb_device_id rt2800usb_device_table[] = { /* Sweex */ { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) }, { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) }, - /* Toshiba */ - { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) }, /* Zyxel */ { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) }, #endif -- cgit v1.2.2 From 0263aa45293838b514b8af674a03faf040991a90 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 29 Mar 2011 11:24:21 +0200 Subject: iwl3945: disable hw scan by default After new NetworkManager 0.8.996 changes, hardware scanning is causing microcode errors as reported here: https://bugzilla.redhat.com/show_bug.cgi?id=683571 and sometimes kernel crashes: https://bugzilla.redhat.com/show_bug.cgi?id=688252 Also with hw scan there are very bad performance on some systems as reported here: https://bugzilla.redhat.com/show_bug.cgi?id=671366 Since Intel no longer supports 3945, there is no chance to get proper firmware fixes, we need workaround problems by disable hardware scanning by default. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl3945-base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index b6c52095bc1a..28eb3d885ba1 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -93,6 +93,7 @@ MODULE_LICENSE("GPL"); struct iwl_mod_params iwl3945_mod_params = { .sw_crypto = 1, .restart_fw = 1, + .disable_hw_scan = 1, /* the rest are 0 by default */ }; @@ -4279,7 +4280,7 @@ MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])"); module_param_named(disable_hw_scan, iwl3945_mod_params.disable_hw_scan, int, S_IRUGO); -MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); +MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 1)"); #ifdef CONFIG_IWLWIFI_LEGACY_DEBUG module_param_named(debug, iwlegacy_debug_level, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); -- cgit v1.2.2 From 24047e2c4feb8c126e92cc5bb7a863115c89bd72 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 29 Mar 2011 13:43:14 +0200 Subject: carl9170: Fix tx aggregation problems with some clients Some clients seem to rely upon the reception of BlockAckReqs to flush their rx reorder buffer. In order to fix aggregation for these clients carl9170 should set IEEE80211_TX_STAT_AMPDU_NO_BACK to generate a BlockAckReq if the transmission of an AMPDU subframe fails. This fixes aggregation problems with Intel 5100 Windows STAs (and maybe others as well). Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/carl9170/carl9170.h | 1 + drivers/net/wireless/ath/carl9170/main.c | 1 + drivers/net/wireless/ath/carl9170/tx.c | 7 +++++++ 3 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index c6a5fae634a0..9cad061cc1d2 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -443,6 +443,7 @@ struct carl9170_ba_stats { u8 ampdu_len; u8 ampdu_ack_len; bool clear; + bool req; }; struct carl9170_sta_info { diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index ede3d7e5a048..89fe60accf85 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -1355,6 +1355,7 @@ static int carl9170_op_ampdu_action(struct ieee80211_hw *hw, tid_info = rcu_dereference(sta_info->agg[tid]); sta_info->stats[tid].clear = true; + sta_info->stats[tid].req = false; if (tid_info) { bitmap_zero(tid_info->bitmap, CARL9170_BAW_SIZE); diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index 0ef70b6fc512..cb70ed7ec5cc 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -383,6 +383,7 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, if (sta_info->stats[tid].clear) { sta_info->stats[tid].clear = false; + sta_info->stats[tid].req = false; sta_info->stats[tid].ampdu_len = 0; sta_info->stats[tid].ampdu_ack_len = 0; } @@ -391,10 +392,16 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar, if (txinfo->status.rates[0].count == 1) sta_info->stats[tid].ampdu_ack_len++; + if (!(txinfo->flags & IEEE80211_TX_STAT_ACK)) + sta_info->stats[tid].req = true; + if (super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_IMM_BA)) { super->s.rix = sta_info->stats[tid].ampdu_len; super->s.cnt = sta_info->stats[tid].ampdu_ack_len; txinfo->flags |= IEEE80211_TX_STAT_AMPDU; + if (sta_info->stats[tid].req) + txinfo->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + sta_info->stats[tid].clear = true; } spin_unlock_bh(&tid_info->lock); -- cgit v1.2.2 From ffd8c746fbef50cf12df239f9d23c2afe1a2c3cb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Mar 2011 15:28:11 +0200 Subject: iwlegacy: fix bugs in change_interface If change_interface gets invoked during a firmware restart, it may crash; prevent that from happening by checking if ctx->vif is assigned. Additionally, in my initial commit I forgot to set the vif->p2p variable correctly, so fix that too. Cc: stable@kernel.org [2.6.38+] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index d418b647be80..a209a0e76bf0 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -1805,6 +1805,15 @@ iwl_legacy_mac_change_interface(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); + if (!ctx->vif || !iwl_legacy_is_ready_rf(priv)) { + /* + * Huh? But wait ... this can maybe happen when + * we're in the middle of a firmware restart! + */ + err = -EBUSY; + goto out; + } + interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes; if (!(interface_modes & BIT(newtype))) { @@ -1832,6 +1841,7 @@ iwl_legacy_mac_change_interface(struct ieee80211_hw *hw, /* success */ iwl_legacy_teardown_interface(priv, vif, true); vif->type = newtype; + vif->p2p = newp2p; err = iwl_legacy_setup_interface(priv, ctx); WARN_ON(err); /* -- cgit v1.2.2 From 286b9bfe8ef6d97213c86bbaf30c250fd1f67568 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 30 Mar 2011 00:15:49 +0200 Subject: sh: Fix irq cleanup fallout I missed that coccinelle does not fix up header files by default. Reported-by: Rafael J. Wysocki Signed-off-by: Thomas Gleixner Cc: Paul Mundt Cc: --- drivers/sh/intc/internals.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h index df36a421e675..5b934851efa8 100644 --- a/drivers/sh/intc/internals.h +++ b/drivers/sh/intc/internals.h @@ -86,7 +86,7 @@ enum { MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */ static inline struct intc_desc_int *get_intc_desc(unsigned int irq) { - struct irq_chip *chip = get_irq_chip(irq); + struct irq_chip *chip = irq_get_chip(irq); return container_of(chip, struct intc_desc_int, chip); } @@ -103,7 +103,7 @@ static inline void activate_irq(int irq) set_irq_flags(irq, IRQF_VALID); #else /* same effect on other architectures */ - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } -- cgit v1.2.2 From c4757ee58ae08fa6eb4df6d5e0f417e11d40bc0e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 7 Mar 2011 11:05:33 +0800 Subject: hwmon: twl4030-madc-hwmon: add "platform:" prefix for platform modalias Since 43cc71eed1250755986da4c0f9898f9a635cb3bf (platform: prefix MODALIAS with "platform:"), the platform modalias is prefixed with "platform:". Signed-off-by: Axel Lin Cc: J Keerthy Cc: Samuel Ortiz Signed-off-by: Guenter Roeck --- drivers/hwmon/twl4030-madc-hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index 97e22bef85ab..de5819199e2e 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -154,4 +154,4 @@ module_exit(twl4030_madc_hwmon_exit); MODULE_DESCRIPTION("TWL4030 ADC Hwmon driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("J Keerthy"); -MODULE_ALIAS("twl4030_madc_hwmon"); +MODULE_ALIAS("platform:twl4030_madc_hwmon"); -- cgit v1.2.2 From f6d5b33125c4fa63c16f7f54c533338c9695d82c Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 29 Mar 2011 18:00:27 -0700 Subject: RTC: Fix early irqs caused by calling rtc_set_alarm too early When we register an rtc device at boot, we read the alarm value in hardware and set the rtc device's aie_timer to that value. The initial method to do this was to simply call rtc_set_alarm() with the value read from hardware. However, this may cause problems as rtc_set_alarm may enable interupts, and the RTC alarm might fire, which can cause invalid pointer dereferencing since the RTC registration is not complete. This patch solves the issue by initializing the rtc_device.aie_timer y hand via rtc_initialize_alarm(). This avoids any calls to the RTC hardware which might enable interrupts too early. CC: Thomas Gleixner CC: Alessandro Zummo Reported-by: Konrad Rzeszutek Wilk Tested-by: Konrad Rzeszutek Wilk Signed-off-by: John Stultz --- drivers/rtc/class.c | 2 +- drivers/rtc/interface.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 09b4437b3e61..39013867cbd6 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -171,7 +171,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, err = __rtc_read_alarm(rtc, &alrm); if (!err && !rtc_valid_tm(&alrm.time)) - rtc_set_alarm(rtc, &alrm); + rtc_initialize_alarm(rtc, &alrm); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); dev_set_name(&rtc->dev, "rtc%d", id); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8ec6b069a7f5..b2fea80dfb65 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -375,6 +375,32 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_set_alarm); +/* Called once per device from rtc_device_register */ +int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +{ + int err; + + err = rtc_valid_tm(&alarm->time); + if (err != 0) + return err; + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return err; + + rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); + rtc->aie_timer.period = ktime_set(0, 0); + if (alarm->enabled) { + rtc->aie_timer.enabled = 1; + timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); + } + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_initialize_alarm); + + + int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) { int err = mutex_lock_interruptible(&rtc->ops_lock); -- cgit v1.2.2 From a54aba87bb8e90f9e39bcfe151717b86abbbdd79 Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Thu, 24 Mar 2011 22:09:33 +0200 Subject: RTC: Fix s3c compile error due to missing s3c_rtc_setpie s3c_rtc_setpie was removed, and it resulted in compiler error: drivers/rtc/rtc-s3c.c: In function s3c_rtc_release drivers/rtc/rtc-s3c.c:339:2: error: implicit declaration of function s3c_rtc_setpie Fix it by removing s3c_rtc_release calls. [jstultz: An identical fix was also sent in by Jiri Pinkava ] CC: Thomas Gleixner CC: Alessandro Zummo Signed-off-by: Vasily Khoruzhick Signed-off-by: John Stultz --- drivers/rtc/rtc-s3c.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 714964913e5e..b3466c491cd3 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -336,7 +336,6 @@ static void s3c_rtc_release(struct device *dev) /* do not clear AIE here, it may be needed for wake */ - s3c_rtc_setpie(dev, 0); free_irq(s3c_rtc_alarmno, rtc_dev); free_irq(s3c_rtc_tickno, rtc_dev); } @@ -408,7 +407,6 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); rtc_device_unregister(rtc); - s3c_rtc_setpie(&dev->dev, 0); s3c_rtc_setaie(&dev->dev, 0); clk_disable(rtc_clk); -- cgit v1.2.2 From 8c122b96866580c99e44f3f07ac93a993d964ec3 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 18 Mar 2011 04:26:24 -0400 Subject: RTC: add missing "return 0" in new alarm func for rtc-bfin.c The new bfin_rtc_alarm_irq_enable function forgot to add a "return 0" to the end leading to the build warning: drivers/rtc/rtc-bfin.c: In function 'bfin_rtc_alarm_irq_enable': drivers/rtc/rtc-bfin.c:253: warning: control reaches end of non-void function CC: stable@kernel.org CC: Thomas Gleixner CC: Alessandro Zummo Signed-off-by: Mike Frysinger Signed-off-by: John Stultz --- drivers/rtc/rtc-bfin.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index ca9cff85ab8a..f2496440d076 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -250,6 +250,8 @@ static int bfin_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) bfin_rtc_int_set_alarm(rtc); else bfin_rtc_int_clear(~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); + + return 0; } static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm) -- cgit v1.2.2 From abc45592bce8267a8e651c12ce94a1f83eaac7a6 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 28 Mar 2011 17:10:43 +0000 Subject: via-ircc: Use pci_{get, set}_drvdata() instead of static pointer variable via-ircc still maintains its own array of device pointers in Linux 2.4 style. Worse, it always uses index 0, so it will crash if there are multiple suitable devices in the system. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/irda/via-ircc.c | 82 +++++++++------------------------------------ 1 file changed, 15 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 67c0ad42d818..cc6faca35160 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -75,15 +75,9 @@ static int dongle_id = 0; /* default: probe */ /* We can't guess the type of connected dongle, user *must* supply it. */ module_param(dongle_id, int, 0); -/* FIXME : we should not need this, because instances should be automatically - * managed by the PCI layer. Especially that we seem to only be using the - * first entry. Jean II */ -/* Max 4 instances for now */ -static struct via_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; - /* Some prototypes */ -static int via_ircc_open(int i, chipio_t * info, unsigned int id); -static int via_ircc_close(struct via_ircc_cb *self); +static int via_ircc_open(struct pci_dev *pdev, chipio_t * info, + unsigned int id); static int via_ircc_dma_receive(struct via_ircc_cb *self); static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, int iobase); @@ -215,7 +209,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0)); pci_write_config_byte(pcidev,0x5a,0xc0); WriteLPCReg(0x28, 0x70 ); - if (via_ircc_open(0, &info,0x3076) == 0) + if (via_ircc_open(pcidev, &info, 0x3076) == 0) rc=0; } else rc = -ENODEV; //IR not turn on @@ -254,7 +248,7 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi info.irq=FirIRQ; info.dma=FirDRQ1; info.dma2=FirDRQ0; - if (via_ircc_open(0, &info,0x3096) == 0) + if (via_ircc_open(pcidev, &info, 0x3096) == 0) rc=0; } else rc = -ENODEV; //IR not turn on !!!!! @@ -264,48 +258,10 @@ static int __devinit via_init_one (struct pci_dev *pcidev, const struct pci_devi return rc; } -/* - * Function via_ircc_clean () - * - * Close all configured chips - * - */ -static void via_ircc_clean(void) -{ - int i; - - IRDA_DEBUG(3, "%s()\n", __func__); - - for (i=0; i < ARRAY_SIZE(dev_self); i++) { - if (dev_self[i]) - via_ircc_close(dev_self[i]); - } -} - -static void __devexit via_remove_one (struct pci_dev *pdev) -{ - IRDA_DEBUG(3, "%s()\n", __func__); - - /* FIXME : This is ugly. We should use pci_get_drvdata(pdev); - * to get our driver instance and call directly via_ircc_close(). - * See vlsi_ir for details... - * Jean II */ - via_ircc_clean(); - - /* FIXME : This should be in via_ircc_close(), because here we may - * theoritically disable still configured devices :-( - Jean II */ - pci_disable_device(pdev); -} - static void __exit via_ircc_cleanup(void) { IRDA_DEBUG(3, "%s()\n", __func__); - /* FIXME : This should be redundant, as pci_unregister_driver() - * should call via_remove_one() on each device. - * Jean II */ - via_ircc_clean(); - /* Cleanup all instances of the driver */ pci_unregister_driver (&via_driver); } @@ -324,12 +280,13 @@ static const struct net_device_ops via_ircc_fir_ops = { }; /* - * Function via_ircc_open (iobase, irq) + * Function via_ircc_open(pdev, iobase, irq) * * Open driver instance * */ -static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) +static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info, + unsigned int id) { struct net_device *dev; struct via_ircc_cb *self; @@ -337,9 +294,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) IRDA_DEBUG(3, "%s()\n", __func__); - if (i >= ARRAY_SIZE(dev_self)) - return -ENOMEM; - /* Allocate new instance of the driver */ dev = alloc_irdadev(sizeof(struct via_ircc_cb)); if (dev == NULL) @@ -349,13 +303,8 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) self->netdev = dev; spin_lock_init(&self->lock); - /* FIXME : We should store our driver instance in the PCI layer, - * using pci_set_drvdata(), not in this array. - * See vlsi_ir for details... - Jean II */ - /* FIXME : 'i' is always 0 (see via_init_one()) :-( - Jean II */ - /* Need to store self somewhere */ - dev_self[i] = self; - self->index = i; + pci_set_drvdata(pdev, self); + /* Initialize Resource */ self->io.cfg_base = info->cfg_base; self->io.fir_base = info->fir_base; @@ -463,25 +412,24 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) err_out2: release_region(self->io.fir_base, self->io.fir_ext); err_out1: + pci_set_drvdata(pdev, NULL); free_netdev(dev); - dev_self[i] = NULL; return err; } /* - * Function via_ircc_close (self) + * Function via_remove_one(pdev) * * Close driver instance * */ -static int via_ircc_close(struct via_ircc_cb *self) +static void __devexit via_remove_one(struct pci_dev *pdev) { + struct via_ircc_cb *self = pci_get_drvdata(pdev); int iobase; IRDA_DEBUG(3, "%s()\n", __func__); - IRDA_ASSERT(self != NULL, return -1;); - iobase = self->io.fir_base; ResetChip(iobase, 5); //hardware reset. @@ -498,11 +446,11 @@ static int via_ircc_close(struct via_ircc_cb *self) if (self->rx_buff.head) dma_free_coherent(NULL, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); - dev_self[self->index] = NULL; + pci_set_drvdata(pdev, NULL); free_netdev(self->netdev); - return 0; + pci_disable_device(pdev); } /* -- cgit v1.2.2 From fd1d9188f2cb81fe63c789d9f5463dca402ade12 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 28 Mar 2011 17:12:52 +0000 Subject: via-ircc: Pass PCI device pointer to dma_{alloc, free}_coherent() via-ircc has been passing a NULL pointer to DMA allocation functions, which is completely invalid and results in a BUG on PowerPC. Now that we always have the device pointer available, pass it in. Reference: http://bugs.debian.org/619450 Reported-by: Andrew Buckeridge Signed-off-by: Ben Hutchings Tested-by: Andrew Buckeridge [against 2.6.32] Signed-off-by: David S. Miller --- drivers/net/irda/via-ircc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index cc6faca35160..186cd28a61cc 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -363,7 +363,7 @@ static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info, /* Allocate memory if needed */ self->rx_buff.head = - dma_alloc_coherent(NULL, self->rx_buff.truesize, + dma_alloc_coherent(&pdev->dev, self->rx_buff.truesize, &self->rx_buff_dma, GFP_KERNEL); if (self->rx_buff.head == NULL) { err = -ENOMEM; @@ -372,7 +372,7 @@ static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info, memset(self->rx_buff.head, 0, self->rx_buff.truesize); self->tx_buff.head = - dma_alloc_coherent(NULL, self->tx_buff.truesize, + dma_alloc_coherent(&pdev->dev, self->tx_buff.truesize, &self->tx_buff_dma, GFP_KERNEL); if (self->tx_buff.head == NULL) { err = -ENOMEM; @@ -404,10 +404,10 @@ static __devinit int via_ircc_open(struct pci_dev *pdev, chipio_t * info, via_hw_init(self); return 0; err_out4: - dma_free_coherent(NULL, self->tx_buff.truesize, + dma_free_coherent(&pdev->dev, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); err_out3: - dma_free_coherent(NULL, self->rx_buff.truesize, + dma_free_coherent(&pdev->dev, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); err_out2: release_region(self->io.fir_base, self->io.fir_ext); @@ -441,10 +441,10 @@ static void __devexit via_remove_one(struct pci_dev *pdev) __func__, self->io.fir_base); release_region(self->io.fir_base, self->io.fir_ext); if (self->tx_buff.head) - dma_free_coherent(NULL, self->tx_buff.truesize, + dma_free_coherent(&pdev->dev, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); if (self->rx_buff.head) - dma_free_coherent(NULL, self->rx_buff.truesize, + dma_free_coherent(&pdev->dev, self->rx_buff.truesize, self->rx_buff.head, self->rx_buff_dma); pci_set_drvdata(pdev, NULL); -- cgit v1.2.2 From d005a09edf8b12dd1bec651b2cf94caa0e7bb1be Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Mon, 28 Mar 2011 14:54:08 +0000 Subject: phylib: phy_attach_direct: phy_init_hw can fail, add cleanup The function phy_attach_direct attaches the phy and calls phy_init_hw. phy_init_hw can fail, but the phy is still marked as attached. Successive calls to phy_attach_direct will fail because the phy is busy. [ 1.020000] eth0: Freescale FEC PHY driver [Generic PHY] (mii_bus:phy_addr=1:00, irq=-1) [ 1.030000] eth1: Freescale FEC PHY driver [Generic PHY] (mii_bus:phy_addr=1:01, irq=-1) [ 2.050000] Sending DHCP requests . [ 3.020000] PHY: 1:00 - Link is Up - 100/Full [ 5.110000] ..... timed out! [ 87.660000] IP-Config: Reopening network devices... [ 88.190000] FEC: MDIO read timeout [ 88.190000] eth0: could not attach to PHY [ 88.190000] IP-Config: Failed to open eth0 [ 88.210000] FEC: MDIO read timeout [ 88.210000] eth1: could not attach to PHY [ 88.210000] IP-Config: Failed to open eth1 [ 88.220000] IP-Config: No network devices available. [ 88.220000] Freeing init memory: 6968K [...] starting network interfaces... ip: RTNETLINK answers: File exists [ 94.000000] net eth0: PHY already attached [ 94.010000] eth0: could not attach to PHY ip: SIOCSIFFLAGS: Device or resource busy This patch adds phy_detach to clean up if phy_init_hw fails. Signed-off-by: Marc Kleine-Budde Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 993c52c82aeb..e870c0698bbe 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -442,11 +442,11 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, u32 flags, phy_interface_t interface) { struct device *d = &phydev->dev; + int err; /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ if (NULL == d->driver) { - int err; d->driver = &genphy_driver.driver; err = d->driver->probe(d); @@ -474,7 +474,11 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, /* Do initial configuration here, now that * we have certain key parameters * (dev_flags and interface) */ - return phy_init_hw(phydev); + err = phy_init_hw(phydev); + if (err) + phy_detach(phydev); + + return err; } /** -- cgit v1.2.2 From 7a635ea989991d7f12d57a12f2ba7cb6d211e083 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Mon, 28 Mar 2011 12:56:33 +0000 Subject: net/usb: Ethernet quirks for the LG-VL600 4G modem This adds a driver for the CDC Ethernet part of this modem. The device's ID is blacklisted in cdc_ether.c and is white-listed in this new driver because of the quirks needed to make it useful. The modem's firmware exposes a CDC ACM port for modem control and a CDC Ethernet port for network data. The descriptors look fine but both ports actually are some sort of multiplexers requiring non- standard headers added/removed from every packet or they get ignored. All information is based on a usb traffic log from a Windows machine. On the Verizon 4G network I've seen speeds up to 1.1MB/s so far with this driver, a speed-o-meter site reports 16.2Mbps/10.5Mbps. Userspace scripts are required to talk to the CDC ACM port. Signed-off-by: Andrzej Zaborowski Signed-off-by: David S. Miller --- drivers/net/usb/Kconfig | 15 ++ drivers/net/usb/Makefile | 1 + drivers/net/usb/cdc_ether.c | 21 ++- drivers/net/usb/lg-vl600.c | 346 ++++++++++++++++++++++++++++++++++++++++++++ drivers/net/usb/usbnet.c | 10 +- 5 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 drivers/net/usb/lg-vl600.c (limited to 'drivers') diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 6f600cced6e1..3ec22c307797 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -433,4 +433,19 @@ config USB_SIERRA_NET To compile this driver as a module, choose M here: the module will be called sierra_net. +config USB_VL600 + tristate "LG VL600 modem dongle" + depends on USB_NET_CDCETHER + select USB_ACM + help + Select this if you want to use an LG Electronics 4G/LTE usb modem + called VL600. This driver only handles the ethernet + interface exposed by the modem firmware. To establish a connection + you will first need a userspace program that sends the right + command to the modem through its CDC ACM port, and most + likely also a DHCP client. See this thread about using the + 4G modem from Verizon: + + http://ubuntuforums.org/showpost.php?p=10589647&postcount=17 + endmenu diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index cac170301187..c7ec8a5f0a90 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -27,4 +27,5 @@ obj-$(CONFIG_USB_IPHETH) += ipheth.o obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o +obj-$(CONFIG_USB_VL600) += lg-vl600.o diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 9a60e415d76b..51c259b69278 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -378,7 +378,7 @@ static void dumpspeed(struct usbnet *dev, __le32 *speeds) __le32_to_cpu(speeds[1]) / 1000); } -static void cdc_status(struct usbnet *dev, struct urb *urb) +void usbnet_cdc_status(struct usbnet *dev, struct urb *urb) { struct usb_cdc_notification *event; @@ -418,8 +418,9 @@ static void cdc_status(struct usbnet *dev, struct urb *urb) break; } } +EXPORT_SYMBOL_GPL(usbnet_cdc_status); -static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) +int usbnet_cdc_bind(struct usbnet *dev, struct usb_interface *intf) { int status; struct cdc_state *info = (void *) &dev->data; @@ -441,6 +442,7 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) */ return 0; } +EXPORT_SYMBOL_GPL(usbnet_cdc_bind); static int cdc_manage_power(struct usbnet *dev, int on) { @@ -452,18 +454,18 @@ static const struct driver_info cdc_info = { .description = "CDC Ethernet Device", .flags = FLAG_ETHER, // .check_connect = cdc_check_connect, - .bind = cdc_bind, + .bind = usbnet_cdc_bind, .unbind = usbnet_cdc_unbind, - .status = cdc_status, + .status = usbnet_cdc_status, .manage_power = cdc_manage_power, }; static const struct driver_info mbm_info = { .description = "Mobile Broadband Network Device", .flags = FLAG_WWAN, - .bind = cdc_bind, + .bind = usbnet_cdc_bind, .unbind = usbnet_cdc_unbind, - .status = cdc_status, + .status = usbnet_cdc_status, .manage_power = cdc_manage_power, }; @@ -560,6 +562,13 @@ static const struct usb_device_id products [] = { .driver_info = 0, }, +/* LG Electronics VL600 wants additional headers on every frame */ +{ + USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* * WHITELIST!!! * diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c new file mode 100644 index 000000000000..1d83ccfd7277 --- /dev/null +++ b/drivers/net/usb/lg-vl600.c @@ -0,0 +1,346 @@ +/* + * Ethernet interface part of the LG VL600 LTE modem (4G dongle) + * + * Copyright (C) 2011 Intel Corporation + * Author: Andrzej Zaborowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * The device has a CDC ACM port for modem control (it claims to be + * CDC ACM anyway) and a CDC Ethernet port for actual network data. + * It will however ignore data on both ports that is not encapsulated + * in a specific way, any data returned is also encapsulated the same + * way. The headers don't seem to follow any popular standard. + * + * This driver adds and strips these headers from the ethernet frames + * sent/received from the CDC Ethernet port. The proprietary header + * replaces the standard ethernet header in a packet so only actual + * ethernet frames are allowed. The headers allow some form of + * multiplexing by using non standard values of the .h_proto field. + * Windows/Mac drivers do send a couple of such frames to the device + * during initialisation, with protocol set to 0x0906 or 0x0b06 and (what + * seems to be) a flag in the .dummy_flags. This doesn't seem necessary + * for modem operation but can possibly be used for GPS or other funcitons. + */ + +struct vl600_frame_hdr { + __le32 len; + __le32 serial; + __le32 pkt_cnt; + __le32 dummy_flags; + __le32 dummy; + __le32 magic; +} __attribute__((packed)); + +struct vl600_pkt_hdr { + __le32 dummy[2]; + __le32 len; + __be16 h_proto; +} __attribute__((packed)); + +struct vl600_state { + struct sk_buff *current_rx_buf; +}; + +static int vl600_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int ret; + struct vl600_state *s = kzalloc(sizeof(struct vl600_state), GFP_KERNEL); + + if (!s) + return -ENOMEM; + + ret = usbnet_cdc_bind(dev, intf); + if (ret) { + kfree(s); + return ret; + } + + dev->driver_priv = s; + + /* ARP packets don't go through, but they're also of no use. The + * subnet has only two hosts anyway: us and the gateway / DHCP + * server (probably simulated by modem firmware or network operator) + * whose address changes everytime we connect to the intarwebz and + * who doesn't bother answering ARP requests either. So hardware + * addresses have no meaning, the destination and the source of every + * packet depend only on whether it is on the IN or OUT endpoint. */ + dev->net->flags |= IFF_NOARP; + + return ret; +} + +static void vl600_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct vl600_state *s = dev->driver_priv; + + if (s->current_rx_buf) + dev_kfree_skb(s->current_rx_buf); + + kfree(s); + + return usbnet_cdc_unbind(dev, intf); +} + +static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct vl600_frame_hdr *frame; + struct vl600_pkt_hdr *packet; + struct ethhdr *ethhdr; + int packet_len, count; + struct sk_buff *buf = skb; + struct sk_buff *clone; + struct vl600_state *s = dev->driver_priv; + + /* Frame lengths are generally 4B multiplies but every couple of + * hours there's an odd number of bytes sized yet correct frame, + * so don't require this. */ + + /* Allow a packet (or multiple packets batched together) to be + * split across many frames. We don't allow a new batch to + * begin in the same frame another one is ending however, and no + * leading or trailing pad bytes. */ + if (s->current_rx_buf) { + frame = (struct vl600_frame_hdr *) s->current_rx_buf->data; + if (skb->len + s->current_rx_buf->len > + le32_to_cpup(&frame->len)) { + netif_err(dev, ifup, dev->net, "Fragment too long\n"); + dev->net->stats.rx_length_errors++; + goto error; + } + + buf = s->current_rx_buf; + memcpy(skb_put(buf, skb->len), skb->data, skb->len); + } else if (skb->len < 4) { + netif_err(dev, ifup, dev->net, "Frame too short\n"); + dev->net->stats.rx_length_errors++; + goto error; + } + + frame = (struct vl600_frame_hdr *) buf->data; + /* NOTE: Should check that frame->magic == 0x53544448? + * Otherwise if we receive garbage at the beginning of the frame + * we may end up allocating a huge buffer and saving all the + * future incoming data into it. */ + + if (buf->len < sizeof(*frame) || + buf->len != le32_to_cpup(&frame->len)) { + /* Save this fragment for later assembly */ + if (s->current_rx_buf) + return 0; + + s->current_rx_buf = skb_copy_expand(skb, 0, + le32_to_cpup(&frame->len), GFP_ATOMIC); + if (!s->current_rx_buf) { + netif_err(dev, ifup, dev->net, "Reserving %i bytes " + "for packet assembly failed.\n", + le32_to_cpup(&frame->len)); + dev->net->stats.rx_errors++; + } + + return 0; + } + + count = le32_to_cpup(&frame->pkt_cnt); + + skb_pull(buf, sizeof(*frame)); + + while (count--) { + if (buf->len < sizeof(*packet)) { + netif_err(dev, ifup, dev->net, "Packet too short\n"); + goto error; + } + + packet = (struct vl600_pkt_hdr *) buf->data; + packet_len = sizeof(*packet) + le32_to_cpup(&packet->len); + if (packet_len > buf->len) { + netif_err(dev, ifup, dev->net, + "Bad packet length stored in header\n"); + goto error; + } + + /* Packet header is same size as the ethernet header + * (sizeof(*packet) == sizeof(*ethhdr)), additionally + * the h_proto field is in the same place so we just leave it + * alone and fill in the remaining fields. + */ + ethhdr = (struct ethhdr *) skb->data; + if (be16_to_cpup(ðhdr->h_proto) == ETH_P_ARP && + buf->len > 0x26) { + /* Copy the addresses from packet contents */ + memcpy(ethhdr->h_source, + &buf->data[sizeof(*ethhdr) + 0x8], + ETH_ALEN); + memcpy(ethhdr->h_dest, + &buf->data[sizeof(*ethhdr) + 0x12], + ETH_ALEN); + } else { + memset(ethhdr->h_source, 0, ETH_ALEN); + memcpy(ethhdr->h_dest, dev->net->dev_addr, ETH_ALEN); + } + + if (count) { + /* Not the last packet in this batch */ + clone = skb_clone(buf, GFP_ATOMIC); + if (!clone) + goto error; + + skb_trim(clone, packet_len); + usbnet_skb_return(dev, clone); + + skb_pull(buf, (packet_len + 3) & ~3); + } else { + skb_trim(buf, packet_len); + + if (s->current_rx_buf) { + usbnet_skb_return(dev, buf); + s->current_rx_buf = NULL; + return 0; + } + + return 1; + } + } + +error: + if (s->current_rx_buf) { + dev_kfree_skb_any(s->current_rx_buf); + s->current_rx_buf = NULL; + } + dev->net->stats.rx_errors++; + return 0; +} + +static struct sk_buff *vl600_tx_fixup(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags) +{ + struct sk_buff *ret; + struct vl600_frame_hdr *frame; + struct vl600_pkt_hdr *packet; + static uint32_t serial = 1; + int orig_len = skb->len - sizeof(struct ethhdr); + int full_len = (skb->len + sizeof(struct vl600_frame_hdr) + 3) & ~3; + + frame = (struct vl600_frame_hdr *) skb->data; + if (skb->len > sizeof(*frame) && skb->len == le32_to_cpup(&frame->len)) + return skb; /* Already encapsulated? */ + + if (skb->len < sizeof(struct ethhdr)) + /* Drop, device can only deal with ethernet packets */ + return NULL; + + if (!skb_cloned(skb)) { + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + + if (tailroom >= full_len - skb->len - sizeof(*frame) && + headroom >= sizeof(*frame)) + /* There's enough head and tail room */ + goto encapsulate; + + if (headroom + tailroom + skb->len >= full_len) { + /* There's enough total room, just readjust */ + skb->data = memmove(skb->head + sizeof(*frame), + skb->data, skb->len); + skb_set_tail_pointer(skb, skb->len); + goto encapsulate; + } + } + + /* Alloc a new skb with the required size */ + ret = skb_copy_expand(skb, sizeof(struct vl600_frame_hdr), full_len - + skb->len - sizeof(struct vl600_frame_hdr), flags); + dev_kfree_skb_any(skb); + if (!ret) + return ret; + skb = ret; + +encapsulate: + /* Packet header is same size as ethernet packet header + * (sizeof(*packet) == sizeof(struct ethhdr)), additionally the + * h_proto field is in the same place so we just leave it alone and + * overwrite the remaining fields. + */ + packet = (struct vl600_pkt_hdr *) skb->data; + memset(&packet->dummy, 0, sizeof(packet->dummy)); + packet->len = cpu_to_le32(orig_len); + + frame = (struct vl600_frame_hdr *) skb_push(skb, sizeof(*frame)); + memset(frame, 0, sizeof(*frame)); + frame->len = cpu_to_le32(full_len); + frame->serial = cpu_to_le32(serial++); + frame->pkt_cnt = cpu_to_le32(1); + + if (skb->len < full_len) /* Pad */ + skb_put(skb, full_len - skb->len); + + return skb; +} + +static const struct driver_info vl600_info = { + .description = "LG VL600 modem", + .flags = FLAG_ETHER | FLAG_RX_ASSEMBLE, + .bind = vl600_bind, + .unbind = vl600_unbind, + .status = usbnet_cdc_status, + .rx_fixup = vl600_rx_fixup, + .tx_fixup = vl600_tx_fixup, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &vl600_info, + }, + {}, /* End */ +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver lg_vl600_driver = { + .name = "lg-vl600", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init vl600_init(void) +{ + return usb_register(&lg_vl600_driver); +} +module_init(vl600_init); + +static void __exit vl600_exit(void) +{ + usb_deregister(&lg_vl600_driver); +} +module_exit(vl600_exit); + +MODULE_AUTHOR("Anrzej Zaborowski"); +MODULE_DESCRIPTION("LG-VL600 modem's ethernet link"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 95c41d56631c..cf58b7682565 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -387,8 +387,12 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) { if (dev->driver_info->rx_fixup && - !dev->driver_info->rx_fixup (dev, skb)) - goto error; + !dev->driver_info->rx_fixup (dev, skb)) { + /* With RX_ASSEMBLE, rx_fixup() must update counters */ + if (!(dev->driver_info->flags & FLAG_RX_ASSEMBLE)) + dev->net->stats.rx_errors++; + goto done; + } // else network stack removes extra byte if we forced a short packet if (skb->len) { @@ -401,8 +405,8 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) } netif_dbg(dev, rx_err, dev->net, "drop\n"); -error: dev->net->stats.rx_errors++; +done: skb_queue_tail(&dev->done, skb); } -- cgit v1.2.2 From ad19031b5f6ede5b2df057e3e1b4f82a2ef7f75f Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 27 Mar 2011 09:16:12 +0000 Subject: Atheros, atl2: Fix mem leaks in error paths of atl2_set_eeprom We leak in some error paths of drivers/net/atlx/atl2.c:atl2_set_eeprom(). The memory allocated to 'eeprom_buff' is not freed when we return -EIO. This patch fixes that up and also removes a pointless explicit cast. Signed-off-by: Jesper Juhl Signed-off-by: David S. Miller --- drivers/net/atlx/atl2.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index e637e9f28fd4..937ef1afa5db 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -1996,13 +1996,15 @@ static int atl2_set_eeprom(struct net_device *netdev, if (!eeprom_buff) return -ENOMEM; - ptr = (u32 *)eeprom_buff; + ptr = eeprom_buff; if (eeprom->offset & 3) { /* need read/modify/write of first changed EEPROM word */ /* only the second byte of the word is being modified */ - if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) - return -EIO; + if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) { + ret_val = -EIO; + goto out; + } ptr++; } if (((eeprom->offset + eeprom->len) & 3)) { @@ -2011,18 +2013,22 @@ static int atl2_set_eeprom(struct net_device *netdev, * only the first byte of the word is being modified */ if (!atl2_read_eeprom(hw, last_dword * 4, - &(eeprom_buff[last_dword - first_dword]))) - return -EIO; + &(eeprom_buff[last_dword - first_dword]))) { + ret_val = -EIO; + goto out; + } } /* Device's eeprom is always little-endian, word addressable */ memcpy(ptr, bytes, eeprom->len); for (i = 0; i < last_dword - first_dword + 1; i++) { - if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) - return -EIO; + if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) { + ret_val = -EIO; + goto out; + } } - + out: kfree(eeprom_buff); return ret_val; } -- cgit v1.2.2 From 10544f128c338aeb7f63c002ad7eee67aa0e6acf Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Wed, 30 Mar 2011 01:12:40 +0000 Subject: sparc32, leon: APBUART driver must use archdata to get IRQ number See Commit id 1636f8ac2b08410df4766449f7c86b912443cd99 (sparc/of: Move of_device fields into struct pdev_archdata), this patch is similar to 19e4875fb21a69fbf620e84769a74d189c69c58d (of/sparc: fix build regression from of_device changes) Signed-off-by: Daniel Hellstrom Acked-by: Sam Ravnborg Signed-off-by: David S. Miller --- drivers/tty/serial/apbuart.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 1ab999b04ef3..12d4e7ca53ca 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -555,10 +555,9 @@ static struct uart_driver grlib_apbuart_driver = { static int __devinit apbuart_probe(struct platform_device *op) { - int i = -1; + int i; struct uart_port *port = NULL; - i = 0; for (i = 0; i < grlib_apbuart_port_nr; i++) { if (op->dev.of_node == grlib_apbuart_nodes[i]) break; @@ -566,6 +565,7 @@ static int __devinit apbuart_probe(struct platform_device *op) port = &grlib_apbuart_ports[i]; port->dev = &op->dev; + port->irq = op->archdata.irqs[0]; uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port); @@ -615,7 +615,7 @@ static int grlib_apbuart_configure(void) freq_khz = *prop; for_each_matching_node(np, apbuart_match) { - const int *irqs, *ampopts; + const int *ampopts; const struct amba_prom_registers *regs; struct uart_port *port; unsigned long addr; @@ -623,11 +623,9 @@ static int grlib_apbuart_configure(void) ampopts = of_get_property(np, "ampopts", NULL); if (ampopts && (*ampopts == 0)) continue; /* Ignore if used by another OS instance */ - - irqs = of_get_property(np, "interrupts", NULL); regs = of_get_property(np, "reg", NULL); - if (!irqs || !regs) + if (!regs) continue; grlib_apbuart_nodes[line] = np; @@ -638,7 +636,7 @@ static int grlib_apbuart_configure(void) port->mapbase = addr; port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map)); - port->irq = *irqs; + port->irq = 0; port->iotype = UPIO_MEM; port->ops = &grlib_apbuart_ops; port->flags = UPF_BOOT_AUTOCONF; -- cgit v1.2.2 From c897dcf6311ea9c8d24e96cc7f7fe9de58a0a6a2 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Wed, 30 Mar 2011 01:12:41 +0000 Subject: sparc32,leon: Fixed APBUART frequency detection The UARTs may be located on different APB buses, thus have different UART clock frequency. The system frequency is not the same (but often) as the UART frequency, rather the APB bus frequency that the APBUART is located at has the same frequency, so this looks at the "freq" property instead. Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- drivers/tty/serial/apbuart.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 12d4e7ca53ca..19a943693e4c 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -598,24 +598,12 @@ static struct platform_driver grlib_apbuart_of_driver = { static int grlib_apbuart_configure(void) { - struct device_node *np, *rp; - const u32 *prop; - int freq_khz, line = 0; - - /* Get bus frequency */ - rp = of_find_node_by_path("/"); - if (!rp) - return -ENODEV; - rp = of_get_next_child(rp, NULL); - if (!rp) - return -ENODEV; - prop = of_get_property(rp, "clock-frequency", NULL); - if (!prop) - return -ENODEV; - freq_khz = *prop; + struct device_node *np; + int line = 0; for_each_matching_node(np, apbuart_match) { const int *ampopts; + const u32 *freq_hz; const struct amba_prom_registers *regs; struct uart_port *port; unsigned long addr; @@ -624,8 +612,10 @@ static int grlib_apbuart_configure(void) if (ampopts && (*ampopts == 0)) continue; /* Ignore if used by another OS instance */ regs = of_get_property(np, "reg", NULL); + /* Frequency of APB Bus is frequency of UART */ + freq_hz = of_get_property(np, "freq", NULL); - if (!regs) + if (!regs || !freq_hz || (*freq_hz == 0)) continue; grlib_apbuart_nodes[line] = np; @@ -641,7 +631,7 @@ static int grlib_apbuart_configure(void) port->ops = &grlib_apbuart_ops; port->flags = UPF_BOOT_AUTOCONF; port->line = line; - port->uartclk = freq_khz * 1000; + port->uartclk = *freq_hz; port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line); line++; -- cgit v1.2.2 From 361ae8cb57ec35ace2fa5f9695dba14eca9893e0 Mon Sep 17 00:00:00 2001 From: Nicolas Kaiser Date: Wed, 30 Mar 2011 21:14:26 +0200 Subject: xen: events: fix error checks in bind_*_to_irqhandler() Checking 'irq < 0' doesn't work when 'irq' is unsigned. The assigned bind_evtchn_to_irq() and bind_virq_to_irq() return int, so using int appears appropriate. Signed-off-by: Nicolas Kaiser Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 036343ba204e..589f0a53a604 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -912,8 +912,7 @@ int bind_evtchn_to_irqhandler(unsigned int evtchn, unsigned long irqflags, const char *devname, void *dev_id) { - unsigned int irq; - int retval; + int irq, retval; irq = bind_evtchn_to_irq(evtchn); if (irq < 0) @@ -955,8 +954,7 @@ int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id) { - unsigned int irq; - int retval; + int irq, retval; irq = bind_virq_to_irq(virq, cpu); if (irq < 0) -- cgit v1.2.2 From 1e19e658567472c46c9b4d27acdb804de04dfdac Mon Sep 17 00:00:00 2001 From: "Philip A. Prindeville" Date: Wed, 30 Mar 2011 13:22:45 +0000 Subject: atm/solos-pci: Use VPI.VCI notation uniformly. Use VPI.VCI notation consistently throughout the module. This is the one remaining place where the VCI is used before the VPI in any output. Signed-off-by: Philip Prindeville Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 25ef1a4556e6..2c4146afd84a 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -710,8 +710,8 @@ void solos_bh(unsigned long card_arg) le16_to_cpu(header->vci)); if (!vcc) { if (net_ratelimit()) - dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n", - le16_to_cpu(header->vci), le16_to_cpu(header->vpi), + dev_warn(&card->dev->dev, "Received packet for unknown VPI.VCI %d.%d on port %d\n", + le16_to_cpu(header->vpi), le16_to_cpu(header->vci), port); continue; } -- cgit v1.2.2 From 18b429e74eeafe42e947b1b0f9a760c7153a0b5c Mon Sep 17 00:00:00 2001 From: "Philip A. Prindeville" Date: Wed, 30 Mar 2011 12:59:26 +0000 Subject: atm/solos-pci: Don't include frame pseudo-header on transmit hex-dump Omit pkt_hdr preamble when dumping transmitted packet as hex-dump; we can pull this up because the frame has already been sent, and dumping it is the last thing we do with it before freeing it. Also include the size, vpi, and vci in the debug as is done on receive. Use "port" consistently instead of "device" intermittently. Signed-off-by: Philip Prindeville Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 2c4146afd84a..968f022d141a 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -697,7 +697,7 @@ void solos_bh(unsigned long card_arg) size); } if (atmdebug) { - dev_info(&card->dev->dev, "Received: device %d\n", port); + dev_info(&card->dev->dev, "Received: port %d\n", port); dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", size, le16_to_cpu(header->vpi), le16_to_cpu(header->vci)); @@ -1018,8 +1018,15 @@ static uint32_t fpga_tx(struct solos_card *card) /* Clean up and free oldskb now it's gone */ if (atmdebug) { + struct pkt_hdr *header = (void *)oldskb->data; + int size = le16_to_cpu(header->size); + + skb_pull(oldskb, sizeof(*header)); dev_info(&card->dev->dev, "Transmitted: port %d\n", port); + dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", + size, le16_to_cpu(header->vpi), + le16_to_cpu(header->vci)); print_buffer(oldskb); } -- cgit v1.2.2 From c031235b395433350f25943b7580a5e343c7b7b2 Mon Sep 17 00:00:00 2001 From: "Philip A. Prindeville" Date: Wed, 30 Mar 2011 13:17:04 +0000 Subject: atm/solos-pci: Don't flap VCs when carrier state changes Don't flap VCs when carrier state changes; higher-level protocols can detect loss of connectivity and act accordingly. This is more consistent with how other network interfaces work. We no longer use release_vccs() so we can delete it. release_vccs() was duplicated from net/atm/common.c; make the corresponding function exported, since other code duplicates it and could leverage it if it were public. Signed-off-by: Philip A. Prindeville Signed-off-by: David S. Miller --- drivers/atm/solos-pci.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 968f022d141a..cd0ff66469b2 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -165,7 +165,6 @@ static uint32_t fpga_tx(struct solos_card *); static irqreturn_t solos_irq(int irq, void *dev_id); static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); static int list_vccs(int vci); -static void release_vccs(struct atm_dev *dev); static int atm_init(struct solos_card *, struct device *); static void atm_remove(struct solos_card *); static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); @@ -384,7 +383,6 @@ static int process_status(struct solos_card *card, int port, struct sk_buff *skb /* Anything but 'Showtime' is down */ if (strcmp(state_str, "Showtime")) { atm_dev_signal_change(card->atmdev[port], ATM_PHY_SIG_LOST); - release_vccs(card->atmdev[port]); dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str); return 0; } @@ -830,28 +828,6 @@ static int list_vccs(int vci) return num_found; } -static void release_vccs(struct atm_dev *dev) -{ - int i; - - write_lock_irq(&vcc_sklist_lock); - for (i = 0; i < VCC_HTABLE_SIZE; i++) { - struct hlist_head *head = &vcc_hash[i]; - struct hlist_node *node, *tmp; - struct sock *s; - struct atm_vcc *vcc; - - sk_for_each_safe(s, node, tmp, head) { - vcc = atm_sk(s); - if (vcc->dev == dev) { - vcc_release_async(vcc, -EPIPE); - sk_del_node_init(s); - } - } - } - write_unlock_irq(&vcc_sklist_lock); -} - static int popen(struct atm_vcc *vcc) { @@ -1269,7 +1245,7 @@ static int atm_init(struct solos_card *card, struct device *parent) card->atmdev[i]->ci_range.vci_bits = 16; card->atmdev[i]->dev_data = card; card->atmdev[i]->phy_data = (void *)(unsigned long)i; - atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_UNKNOWN); + atm_dev_signal_change(card->atmdev[i], ATM_PHY_SIG_FOUND); skb = alloc_skb(sizeof(*header), GFP_ATOMIC); if (!skb) { -- cgit v1.2.2 From 04f482faf50535229a5a5c8d629cf963899f857c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 28 Mar 2011 08:39:36 +0000 Subject: connector: convert to synchronous netlink message processing Commits 01a16b21 (netlink: kill eff_cap from struct netlink_skb_parms) and c53fa1ed (netlink: kill loginuid/sessionid/sid members from struct netlink_skb_parms) removed some members from struct netlink_skb_parms that depend on the current context, all netlink users are now required to do synchronous message processing. connector however queues received messages and processes them in a work queue, which is not valid anymore. This patch converts connector to do synchronous message processing by invoking the registered callback handler directly from the netlink receive function. In order to avoid invoking the callback with connector locks held, a reference count is added to struct cn_callback_entry, the reference is taken when finding a matching callback entry on the device's queue_list and released after the callback handler has been invoked. Signed-off-by: Patrick McHardy Acked-by: Evgeniy Polyakov Signed-off-by: David S. Miller --- drivers/connector/cn_queue.c | 58 +++++++++++++------------------------------ drivers/connector/connector.c | 47 +++++++++-------------------------- 2 files changed, 29 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 55653aba6735..c42c9d517790 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -31,24 +31,9 @@ #include #include -void cn_queue_wrapper(struct work_struct *work) -{ - struct cn_callback_entry *cbq = - container_of(work, struct cn_callback_entry, work); - struct cn_callback_data *d = &cbq->data; - struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(d->skb)); - struct netlink_skb_parms *nsp = &NETLINK_CB(d->skb); - - d->callback(msg, nsp); - - kfree_skb(d->skb); - d->skb = NULL; - - kfree(d->free); -} - static struct cn_callback_entry * -cn_queue_alloc_callback_entry(const char *name, struct cb_id *id, +cn_queue_alloc_callback_entry(struct cn_queue_dev *dev, const char *name, + struct cb_id *id, void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) { struct cn_callback_entry *cbq; @@ -59,17 +44,23 @@ cn_queue_alloc_callback_entry(const char *name, struct cb_id *id, return NULL; } + atomic_set(&cbq->refcnt, 1); + + atomic_inc(&dev->refcnt); + cbq->pdev = dev; + snprintf(cbq->id.name, sizeof(cbq->id.name), "%s", name); memcpy(&cbq->id.id, id, sizeof(struct cb_id)); - cbq->data.callback = callback; - - INIT_WORK(&cbq->work, &cn_queue_wrapper); + cbq->callback = callback; return cbq; } -static void cn_queue_free_callback(struct cn_callback_entry *cbq) +void cn_queue_release_callback(struct cn_callback_entry *cbq) { - flush_workqueue(cbq->pdev->cn_queue); + if (!atomic_dec_and_test(&cbq->refcnt)) + return; + + atomic_dec(&cbq->pdev->refcnt); kfree(cbq); } @@ -85,13 +76,10 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name, struct cn_callback_entry *cbq, *__cbq; int found = 0; - cbq = cn_queue_alloc_callback_entry(name, id, callback); + cbq = cn_queue_alloc_callback_entry(dev, name, id, callback); if (!cbq) return -ENOMEM; - atomic_inc(&dev->refcnt); - cbq->pdev = dev; - spin_lock_bh(&dev->queue_lock); list_for_each_entry(__cbq, &dev->queue_list, callback_entry) { if (cn_cb_equal(&__cbq->id.id, id)) { @@ -104,8 +92,7 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, const char *name, spin_unlock_bh(&dev->queue_lock); if (found) { - cn_queue_free_callback(cbq); - atomic_dec(&dev->refcnt); + cn_queue_release_callback(cbq); return -EINVAL; } @@ -130,10 +117,8 @@ void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id) } spin_unlock_bh(&dev->queue_lock); - if (found) { - cn_queue_free_callback(cbq); - atomic_dec(&dev->refcnt); - } + if (found) + cn_queue_release_callback(cbq); } struct cn_queue_dev *cn_queue_alloc_dev(const char *name, struct sock *nls) @@ -151,12 +136,6 @@ struct cn_queue_dev *cn_queue_alloc_dev(const char *name, struct sock *nls) dev->nls = nls; - dev->cn_queue = alloc_ordered_workqueue(dev->name, 0); - if (!dev->cn_queue) { - kfree(dev); - return NULL; - } - return dev; } @@ -164,9 +143,6 @@ void cn_queue_free_dev(struct cn_queue_dev *dev) { struct cn_callback_entry *cbq, *n; - flush_workqueue(dev->cn_queue); - destroy_workqueue(dev->cn_queue); - spin_lock_bh(&dev->queue_lock); list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) list_del(&cbq->callback_entry); diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index f7554de3be5e..d77005849af8 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -122,51 +122,28 @@ EXPORT_SYMBOL_GPL(cn_netlink_send); */ static int cn_call_callback(struct sk_buff *skb) { - struct cn_callback_entry *__cbq, *__new_cbq; + struct cn_callback_entry *i, *cbq = NULL; struct cn_dev *dev = &cdev; struct cn_msg *msg = NLMSG_DATA(nlmsg_hdr(skb)); + struct netlink_skb_parms *nsp = &NETLINK_CB(skb); int err = -ENODEV; spin_lock_bh(&dev->cbdev->queue_lock); - list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { - if (cn_cb_equal(&__cbq->id.id, &msg->id)) { - if (likely(!work_pending(&__cbq->work) && - __cbq->data.skb == NULL)) { - __cbq->data.skb = skb; - - if (queue_work(dev->cbdev->cn_queue, - &__cbq->work)) - err = 0; - else - err = -EINVAL; - } else { - struct cn_callback_data *d; - - err = -ENOMEM; - __new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC); - if (__new_cbq) { - d = &__new_cbq->data; - d->skb = skb; - d->callback = __cbq->data.callback; - d->free = __new_cbq; - - INIT_WORK(&__new_cbq->work, - &cn_queue_wrapper); - - if (queue_work(dev->cbdev->cn_queue, - &__new_cbq->work)) - err = 0; - else { - kfree(__new_cbq); - err = -EINVAL; - } - } - } + list_for_each_entry(i, &dev->cbdev->queue_list, callback_entry) { + if (cn_cb_equal(&i->id.id, &msg->id)) { + atomic_inc(&i->refcnt); + cbq = i; break; } } spin_unlock_bh(&dev->cbdev->queue_lock); + if (cbq != NULL) { + cbq->callback(msg, nsp); + kfree_skb(skb); + cn_queue_release_callback(cbq); + } + return err; } -- cgit v1.2.2 From 272df502bcd1fbb1b95facc92bd861d604be8871 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 31 Mar 2011 07:18:46 +0900 Subject: gpio/pca953x: fix error handling path in probe() call If the device fails to respond, then the error path tries to remove an interrupt that never got registered, which causes an backtrace from the interrupt handling code. Fix this by ensuring that the cleanup path has two labels and use the correct path as needed. fixes the following error: WARNING: at kernel/irq/manage.c:908 __free_irq+0x80/0x160() Trying to free already-free IRQ 0 Signed-off-by: Ben Dooks Signed-off-by: Mark Brown Signed-off-by: Grant Likely --- drivers/gpio/pca953x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 583e92592073..7630ab7b9bec 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -558,7 +558,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, ret = gpiochip_add(&chip->gpio_chip); if (ret) - goto out_failed; + goto out_failed_irq; if (pdata->setup) { ret = pdata->setup(client, chip->gpio_chip.base, @@ -570,8 +570,9 @@ static int __devinit pca953x_probe(struct i2c_client *client, i2c_set_clientdata(client, chip); return 0; -out_failed: +out_failed_irq: pca953x_irq_teardown(chip); +out_failed: kfree(chip->dyn_pdata); kfree(chip); return ret; -- cgit v1.2.2 From 6cd7a63756a68ad5e718b42aa108e27c19425743 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 30 Mar 2011 21:11:35 -0700 Subject: apbuart: Depend upon sparc. It absolutely needs to be able to get at pdev_archdata members which are sparc specific. Signed-off-by: David S. Miller Reported-by: Stephen Rothwell --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index e1aee37270f5..80484af781e1 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1506,7 +1506,7 @@ config SERIAL_BCM63XX_CONSOLE config SERIAL_GRLIB_GAISLER_APBUART tristate "GRLIB APBUART serial support" - depends on OF + depends on OF && SPARC select SERIAL_CORE ---help--- Add support for the GRLIB APBUART serial port. -- cgit v1.2.2 From 62e0ff1ef2d8ea0814487f73a7de431396a1e914 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Thu, 24 Mar 2011 20:50:52 +0000 Subject: fbcon: Remove unused 'display *p' variable from fb_flashcursor() Signed-off-by: Sergey Senozhatsky Signed-off-by: Paul Mundt --- drivers/video/console/fbcon.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index c58393402da2..8745637e4b7e 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -370,7 +370,6 @@ static void fb_flashcursor(struct work_struct *work) { struct fb_info *info = container_of(work, struct fb_info, queue); struct fbcon_ops *ops = info->fbcon_par; - struct display *p; struct vc_data *vc = NULL; int c; int mode; @@ -386,7 +385,6 @@ static void fb_flashcursor(struct work_struct *work) return; } - p = &fb_display[vc->vc_num]; c = scr_readw((u16 *) vc->vc_pos); mode = (!ops->cursor_flash || ops->cursor_state.enable) ? CM_ERASE : CM_DRAW; -- cgit v1.2.2 From 94e948e6e43cd34e0e2ca496d5e90e4ff0d884f9 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 29 Mar 2011 19:07:08 +0000 Subject: s3fb: fix Virge/GX2 Fix Virge/GX2 support in s3fb: - fix IDs: 86C357 is GX2, 86C359 is GX2+, 86C356 probably does not exist - add memory size detection - drive it the same way as Trio3D/2X The original IDs most likely came from S3 website which claims that: - 356 is Virge/GX2 with ID=8A10, driver included in Windows 2K, XP - 357 is Virge/GX2+ with ID=8A11, driver included in Windows ME - 359 is Virge/GX2+ with ID=8A12, driver included in Windows ME but: - google search for 86C356 only reveals references to Trio3D (probably because of a typo - Trio3D is 86C365) - my card is clearly marked as 86C357, Virge/GX2 and has ID=8A10 - there is no driver for IDs 8A11 and 8A12 in Windows ME - there is a driver for ID 8A10 in Windows ME that says it's GX2 (357) Tested with #9 Reality 334 (86C357 Virge/GX2, ID=0x8A10). Signed-off-by: Ondrej Zary Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index ddedad9cd069..c4482f2e5799 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -71,9 +71,9 @@ static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512}; static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", "S3 Trio64V+", "S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX", - "S3 Plato/PX", "S3 Aurora64VP", "S3 Virge", + "S3 Plato/PX", "S3 Aurora64V+", "S3 Virge", "S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX", - "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P", + "S3 Virge/GX2", "S3 Virge/GX2+", "", "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X", "S3 Trio3D"}; @@ -90,9 +90,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", #define CHIP_988_VIRGE_VX 0x0A #define CHIP_375_VIRGE_DX 0x0B #define CHIP_385_VIRGE_GX 0x0C -#define CHIP_356_VIRGE_GX2 0x0D -#define CHIP_357_VIRGE_GX2P 0x0E -#define CHIP_359_VIRGE_GX2P 0x0F +#define CHIP_357_VIRGE_GX2 0x0D +#define CHIP_359_VIRGE_GX2P 0x0E #define CHIP_360_TRIO3D_1X 0x10 #define CHIP_362_TRIO3D_2X 0x11 #define CHIP_368_TRIO3D_2X 0x12 @@ -359,7 +358,9 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD); /* Set S3 clock registers */ - if (par->chip == CHIP_360_TRIO3D_1X || + if (par->chip == CHIP_357_VIRGE_GX2 || + par->chip == CHIP_359_VIRGE_GX2P || + par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) { vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */ @@ -560,7 +561,9 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: offset register : %d\n", info->node, offset_value); svga_wcrt_multi(par->state.vgabase, s3_offset_regs, offset_value); - if (par->chip != CHIP_360_TRIO3D_1X && + if (par->chip != CHIP_357_VIRGE_GX2 && + par->chip != CHIP_359_VIRGE_GX2P && + par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) { vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */ @@ -604,7 +607,9 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(par->state.vgabase, 0x66, 0x90); } - if (par->chip == CHIP_360_TRIO3D_1X || + if (par->chip == CHIP_357_VIRGE_GX2 || + par->chip == CHIP_359_VIRGE_GX2P || + par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X || par->chip == CHIP_365_TRIO3D || @@ -617,8 +622,7 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(par->state.vgabase, 0x66, 0x81); } - if (par->chip == CHIP_356_VIRGE_GX2 || - par->chip == CHIP_357_VIRGE_GX2P || + if (par->chip == CHIP_357_VIRGE_GX2 || par->chip == CHIP_359_VIRGE_GX2P || par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || @@ -674,6 +678,8 @@ static int s3fb_set_par(struct fb_info *info) pr_debug("fb%d: 8 bit pseudocolor\n", info->node); svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); if (info->var.pixclock > 20000 || + par->chip == CHIP_357_VIRGE_GX2 || + par->chip == CHIP_359_VIRGE_GX2P || par->chip == CHIP_360_TRIO3D_1X || par->chip == CHIP_362_TRIO3D_2X || par->chip == CHIP_368_TRIO3D_2X) @@ -702,7 +708,9 @@ static int s3fb_set_par(struct fb_info *info) } else { svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0); - if (par->chip != CHIP_360_TRIO3D_1X && + if (par->chip != CHIP_357_VIRGE_GX2 && + par->chip != CHIP_359_VIRGE_GX2P && + par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) hmul = 2; @@ -727,7 +735,9 @@ static int s3fb_set_par(struct fb_info *info) } else { svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30); svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0); - if (par->chip != CHIP_360_TRIO3D_1X && + if (par->chip != CHIP_357_VIRGE_GX2 && + par->chip != CHIP_359_VIRGE_GX2P && + par->chip != CHIP_360_TRIO3D_1X && par->chip != CHIP_362_TRIO3D_2X && par->chip != CHIP_368_TRIO3D_2X) hmul = 2; @@ -1069,6 +1079,16 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i info->screen_size = 2 << 20; break; } + } else if (par->chip == CHIP_357_VIRGE_GX2 || + par->chip == CHIP_359_VIRGE_GX2P) { + switch ((regval & 0xC0) >> 6) { + case 1: /* 4MB */ + info->screen_size = 4 << 20; + break; + case 3: /* 2MB */ + info->screen_size = 2 << 20; + break; + } } else info->screen_size = s3_memsizes[regval >> 5] << 10; info->fix.smem_len = info->screen_size; @@ -1268,8 +1288,8 @@ static struct pci_device_id s3_devices[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x5631), .driver_data = CHIP_325_VIRGE}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x883D), .driver_data = CHIP_988_VIRGE_VX}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A01), .driver_data = CHIP_XXX_VIRGE_DXGX}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2}, - {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_357_VIRGE_GX2}, + {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_359_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X}, {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D}, -- cgit v1.2.2 From e9c5db0b8dce1bcdc99ad26e718230810d6b5cff Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Thu, 31 Mar 2011 00:12:22 +0000 Subject: efifb: support AMD Radeon HD 6490 This patch enables the framebuffer for the AMD Radeon 6490 found in the new MacBook Pro 8,2 generation. The framebuffer's base is located at 0x90010000, the method for obtaining it was found in the same way mentioned in https://patchwork.kernel.org/patch/91704/ Signed-off-by: Davidlohr Bueso Signed-off-by: Jonathan Gonzalez Signed-off-by: Paul Mundt --- drivers/video/efifb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 70477c2e4b61..a9645b86a623 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -64,6 +64,7 @@ enum { M_MBP_6_1, /* MacBook Pro, 6,1th gen */ M_MBP_6_2, /* MacBook Pro, 6,2th gen */ M_MBP_7_1, /* MacBook Pro, 7,1th gen */ + M_MBP_8_2, /* MacBook Pro, 8,2nd gen */ M_UNKNOWN /* placeholder */ }; @@ -100,6 +101,7 @@ static struct efifb_dmi_info { [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200 }, [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050 }, [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800 }, + [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900 }, [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } }; @@ -151,6 +153,7 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,1", M_MBP_6_1), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro6,2", M_MBP_6_2), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro7,1", M_MBP_7_1), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro8,2", M_MBP_8_2), {}, }; -- cgit v1.2.2 From b2267a6b095afb84b5766d6646e581b9054704d9 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Wed, 9 Feb 2011 03:18:46 +0000 Subject: serial: sh-sci: prevent setup of uninitialized serial console Commit 906b17dc089f7fa87e37a9cfe6ee185efc90e0da introduced a condition where the kernel will crash unless a earlyprintk parameter is specified. Without this parameter, sci_console_init is called during early console setup without any port being initialized, and the kernel crashes a little bit later when uart_set_options attemps to invoke set_termios on a port with an ops member equal to NULL. This patch just checks in sci_console_init that the port is properly initialized, and aborts the early console setup if it is not. Signed-off-by: Alexandre Courbot Signed-off-by: Paul Mundt --- drivers/tty/serial/sh-sci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index eb7958c675a8..264209c32675 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1836,6 +1836,12 @@ static int __devinit serial_console_setup(struct console *co, char *options) sci_port = &sci_ports[co->index]; port = &sci_port->port; + /* + * Refuse to handle uninitialized ports. + */ + if (!port->ops) + return -ENODEV; + ret = sci_remap_port(port); if (unlikely(ret != 0)) return ret; -- cgit v1.2.2 From 6a8c979935f1955707fe79909cb3baf9575282f4 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 24 Mar 2011 02:20:56 +0000 Subject: sh: sh-sci: Fix double initialization by serial_console_setup The driver is initialized in a state with an unknown value by serial_console_setup. And initialization fails. This is caused by the initialization by sci_console_init. This function does not seem to be necessary for the present sh-sci driver. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Paul Mundt --- drivers/tty/serial/sh-sci.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 264209c32675..4e530a58bb1d 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1872,13 +1872,6 @@ static struct console serial_console = { .data = &sci_uart_driver, }; -static int __init sci_console_init(void) -{ - register_console(&serial_console); - return 0; -} -console_initcall(sci_console_init); - static struct console early_serial_console = { .name = "early_ttySC", .write = serial_console_write, @@ -1907,18 +1900,18 @@ static int __devinit sci_probe_earlyprintk(struct platform_device *pdev) register_console(&early_serial_console); return 0; } + +#define SCI_CONSOLE (&serial_console) + #else static inline int __devinit sci_probe_earlyprintk(struct platform_device *pdev) { return -EINVAL; } -#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ -#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) -#define SCI_CONSOLE (&serial_console) -#else -#define SCI_CONSOLE 0 -#endif +#define SCI_CONSOLE NULL + +#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */ static char banner[] __initdata = KERN_INFO "SuperH SCI(F) driver initialized\n"; -- cgit v1.2.2 From a718d79cc0e0c2f0aa82ba2c54383a18f15b7738 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 30 Mar 2011 22:25:34 -0700 Subject: Input: uinput - allow for 0/0 min/max on absolute axes. Some devices provide absolute axes with min/max of 0/0 (e.g. wacom's ABS_MISC axis). Current uinput restrictions do not allow duplication of these devices and require hacks in userspace to work around this. If the kernel accepts physical devices with a min/max of 0/0, uinput shouldn't disallow the same range. Signed-off-by: Peter Hutterer Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 364bdf43a381..736056897e50 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -302,10 +302,14 @@ static int uinput_validate_absbits(struct input_dev *dev) int retval = 0; for (cnt = 0; cnt < ABS_CNT; cnt++) { + int min, max; if (!test_bit(cnt, dev->absbit)) continue; - if (input_abs_get_max(dev, cnt) <= input_abs_get_min(dev, cnt)) { + min = input_abs_get_min(dev, cnt); + max = input_abs_get_max(dev, cnt); + + if ((min != 0 || max != 0) && max <= min) { printk(KERN_DEBUG "%s: invalid abs[%02x] min:%d max:%d\n", UINPUT_NAME, cnt, -- cgit v1.2.2 From 799a2a215ed7f9398a8d528767e64b8e39904105 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Wed, 30 Mar 2011 22:33:42 -0700 Subject: Input: spear-keyboard - fix inverted condition in interrupt handler We should return IRQ_NONE from interrupt handler in case keyboard does not report DATA_AVAIL condition. Signed-off-by: Rajeev Kumar Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/spear-keyboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index bee03d64c453..d712dffd2157 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -69,7 +69,7 @@ static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) u8 sts, val; sts = readb(kbd->io_base + STATUS_REG); - if (sts & DATA_AVAIL) + if (!(sts & DATA_AVAIL)) return IRQ_NONE; if (kbd->last_key != KEY_RESERVED) { -- cgit v1.2.2 From 708748670c7c6dd5bd3b141473086e6937e72737 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 31 Mar 2011 00:01:58 -0700 Subject: Input: synaptics - fix crash in synaptics_module_init() 'struct dmi_system_id' arrays must always have a terminator to keep dmi_check_system() from looking at data (and possibly crashing) it isn't supposed to look at. The issue went unnoticed until ef8313bb1a22e7d2125d9d758aa8a81f1de91d81, but was introduced about a year earlier with 7705d548cbe33f18ea7713b9a07aa11047aaeca4 (which also similarly changed lifebook.c, but the problem there got eliminated shortly afterwards). The first hunk therefore is a stable candidate back to 2.6.33, while the full change is needed only on 2.6.38. Signed-off-by: Jan Beulich Cc: stable@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index aa186cf6c514..e06e045bf907 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -836,8 +836,8 @@ static const struct dmi_system_id __initconst toshiba_dmi_table[] = { }, }, - { } #endif + { } }; static bool broken_olpc_ec; @@ -851,8 +851,8 @@ static const struct dmi_system_id __initconst olpc_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "XO"), }, }, - { } #endif + { } }; void __init synaptics_module_init(void) -- cgit v1.2.2 From a2a94e7323dad972f23b9000cab150026c929b9f Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 31 Mar 2011 00:11:48 -0700 Subject: Input: i8042 - downgrade selftest error message to dbg() On a "really fragile" laptop I noticed a single i8042.c: i8042 controller selftest failed. (0x1 != 0x55) error in the log. But there's no reason to print this message at KERN_ERR level each time that loop fails, especially since the message telling about the overall selftest failure is printed at KERN_INFO level (on X86). Add an actual error message for non-X86 systems, where a selftest failure is (apparently) more serious. Remove a space in an another error message. Signed-off-by: Paul Bolle Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index ac4c93689ab9..d37a48e099d0 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -869,15 +869,15 @@ static int i8042_controller_selftest(void) do { if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { - pr_err("i8042 controller self test timeout\n"); + pr_err("i8042 controller selftest timeout\n"); return -ENODEV; } if (param == I8042_RET_CTL_TEST) return 0; - pr_err("i8042 controller selftest failed. (%#x != %#x)\n", - param, I8042_RET_CTL_TEST); + dbg("i8042 controller selftest: %#x != %#x\n", + param, I8042_RET_CTL_TEST); msleep(50); } while (i++ < 5); @@ -891,6 +891,7 @@ static int i8042_controller_selftest(void) pr_info("giving up on controller selftest, continuing anyway...\n"); return 0; #else + pr_err("i8042 controller selftest failed\n"); return -EIO; #endif } -- cgit v1.2.2 From 9f01b25048ad12b5d71f4f7d3b62ef737639a08d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 24 Mar 2011 11:37:03 +0000 Subject: drm/i915: Busy-spin wait_for condition in atomic contexts During modesetting, we need to wait for the hardware to report readiness by polling the registers. Normally, we call msleep() between reads, because some state changes may take a whole vblank or more to complete. However during a panic, we are in an atomic context and cannot sleep. Instead, busy spin polling the termination condition. References: https://bugzilla.kernel.org/show_bug.cgi?id=31772 Signed-off-by: Chris Wilson Reviewed-by: Keith Packard Reviewed-by: Jesse Barnes --- drivers/gpu/drm/i915/intel_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5daa991cb287..f5b0d8306d83 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -39,7 +39,7 @@ ret__ = -ETIMEDOUT; \ break; \ } \ - if (W && !in_dbg_master()) msleep(W); \ + if (W && !(in_atomic() || in_dbg_master())) msleep(W); \ } \ ret__; \ }) -- cgit v1.2.2 From 7f58aabc369014fda3a4a33604ba0a1b63b941ac Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 30 Mar 2011 16:20:43 +0100 Subject: drm/i915: Reset GMBUS controller after NAK Once a NAK has been asserted by the slave, we need to reset the GMBUS controller in order to continue. This is done by asserting the Software Clear Interrupt bit and then clearing it again to restore operations. If we don't clear the NAK, then all future GMBUS xfers will fail, including DDC probes and EDID retrieval. v2: Add some comments as suggested by Keith Packard. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35781 Signed-off-by: Chris Wilson Reviewed-by: Keith Packard Tested-by: Jesse Barnes Tested-by: "Mengmeng Meng" --- drivers/gpu/drm/i915/intel_i2c.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 82d04c5899d2..d3b903bce7c5 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -259,7 +259,7 @@ gmbus_xfer(struct i2c_adapter *adapter, if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) goto timeout; if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) - return 0; + goto clear_err; val = I915_READ(GMBUS3 + reg_offset); do { @@ -287,7 +287,7 @@ gmbus_xfer(struct i2c_adapter *adapter, if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50)) goto timeout; if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) - return 0; + goto clear_err; val = loop = 0; do { @@ -302,14 +302,31 @@ gmbus_xfer(struct i2c_adapter *adapter, if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50)) goto timeout; if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER) - return 0; + goto clear_err; } - return num; + goto done; + +clear_err: + /* Toggle the Software Clear Interrupt bit. This has the effect + * of resetting the GMBUS controller and so clearing the + * BUS_ERROR raised by the slave's NAK. + */ + I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT); + I915_WRITE(GMBUS1 + reg_offset, 0); + +done: + /* Mark the GMBUS interface as disabled. We will re-enable it at the + * start of the next xfer, till then let it sleep. + */ + I915_WRITE(GMBUS0 + reg_offset, 0); + return i; timeout: DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n", bus->reg0 & 0xff, bus->adapter.name); + I915_WRITE(GMBUS0 + reg_offset, 0); + /* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */ bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff); if (!bus->force_bit) -- cgit v1.2.2 From 5e8996e72899847269ca36061ea33ea24bf6cb90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Wed, 30 Mar 2011 20:46:19 +0000 Subject: bonding:typo in comment use accumulates instead of acumulates. Signed-off-by: Pan Weiping Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 118c28aa471e..4b3e35878406 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -74,7 +74,7 @@ struct tlb_client_info { * packets to a Client that the Hash function * gave this entry index. */ - u32 tx_bytes; /* Each Client acumulates the BytesTx that + u32 tx_bytes; /* Each Client accumulates the BytesTx that * were tranmitted to it, and after each * CallBack the LoadHistory is devided * by the balance interval -- cgit v1.2.2 From 53020092bd89b0d4ccc5368a3956f43cb43e5665 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 30 Mar 2011 23:28:52 +0000 Subject: mlx4: Fixing use after free In case of allocation failure, tried to use the promiscuous QP entry that was previously freed. Now freeing this entry only in case we will not put it back to the list of promiscuous entries. Reported-by: Dan Carpenter Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/mcg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index e71372aa9cc4..37150b2f6425 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -469,7 +469,6 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 vep_num, u8 port, /*remove from list of promisc qps */ list_del(&pqp->list); - kfree(pqp); /* set the default entry not to include the removed one */ mailbox = mlx4_alloc_cmd_mailbox(dev); @@ -528,6 +527,8 @@ out_mailbox: out_list: if (back_to_list) list_add_tail(&pqp->list, &s_steer->promisc_qps[steer]); + else + kfree(pqp); out_mutex: mutex_unlock(&priv->mcg_table.mutex); return err; -- cgit v1.2.2 From c37947459172a02691ccd48cb967e8b605d38c56 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 30 Mar 2011 23:30:17 +0000 Subject: mlx4: Fixing bad size of event queue buffer We should reduce the number of reserved completion queues from the total number of entries. Since the queue size is power of two, not reducing the reserved entries, caused a double queue size, which may lead to allocation failures in some cases. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/eq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 506cfd0372ec..1ad1f6029af8 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -603,7 +603,9 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) } for (i = 0; i < dev->caps.num_comp_vectors; ++i) { - err = mlx4_create_eq(dev, dev->caps.num_cqs + MLX4_NUM_SPARE_EQE, + err = mlx4_create_eq(dev, dev->caps.num_cqs - + dev->caps.reserved_cqs + + MLX4_NUM_SPARE_EQE, (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, &priv->eq_table.eq[i]); if (err) { -- cgit v1.2.2 From 25985edcedea6396277003854657b5f3cb31a628 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 30 Mar 2011 22:57:33 -0300 Subject: Fix common misspellings Fixes generated by 'codespell' and manually reviewed. Signed-off-by: Lucas De Marchi --- drivers/acpi/apei/ghes.c | 2 +- drivers/acpi/processor_throttling.c | 2 +- drivers/acpi/video.c | 4 +- drivers/amba/bus.c | 2 +- drivers/ata/ahci.c | 2 +- drivers/ata/ahci.h | 4 +- drivers/ata/ata_piix.c | 10 ++-- drivers/ata/libata-core.c | 2 +- drivers/ata/libata-eh.c | 10 ++-- drivers/ata/libata-scsi.c | 2 +- drivers/ata/libata-sff.c | 4 +- drivers/ata/pata_amd.c | 2 +- drivers/ata/pata_arasan_cf.c | 8 ++-- drivers/ata/pata_bf54x.c | 2 +- drivers/ata/pata_cs5520.c | 2 +- drivers/ata/pata_mpiix.c | 2 +- drivers/ata/pata_rz1000.c | 2 +- drivers/ata/pata_sil680.c | 4 +- drivers/ata/pata_sis.c | 4 +- drivers/ata/pata_triflex.c | 2 +- drivers/ata/sata_fsl.c | 4 +- drivers/ata/sata_mv.c | 4 +- drivers/ata/sata_nv.c | 2 +- drivers/ata/sata_via.c | 2 +- drivers/atm/ambassador.c | 2 +- drivers/atm/firestream.c | 2 +- drivers/atm/fore200e.h | 4 +- drivers/atm/horizon.c | 10 ++-- drivers/atm/idt77252.c | 2 +- drivers/atm/idt77252.h | 2 +- drivers/atm/iphase.c | 6 +-- drivers/atm/lanai.c | 4 +- drivers/auxdisplay/cfag12864b.c | 4 +- drivers/base/power/runtime.c | 2 +- drivers/base/sys.c | 14 +++--- drivers/block/DAC960.c | 2 +- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_int.h | 10 ++-- drivers/block/drbd/drbd_main.c | 4 +- drivers/block/drbd/drbd_receiver.c | 2 +- drivers/block/drbd/drbd_vli.h | 2 +- drivers/block/hd.c | 2 +- drivers/block/viodasd.c | 2 +- drivers/block/xsysace.c | 8 ++-- drivers/bluetooth/hci_ll.c | 2 +- drivers/cdrom/cdrom.c | 4 +- drivers/char/agp/agp.h | 2 +- drivers/char/agp/amd-k7-agp.c | 2 +- drivers/char/agp/sworks-agp.c | 2 +- drivers/char/agp/via-agp.c | 2 +- drivers/char/ipmi/ipmi_poweroff.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 4 +- drivers/char/mbcs.h | 4 +- drivers/char/mwave/3780i.h | 2 +- drivers/char/nwbutton.c | 2 +- drivers/char/pcmcia/cm4000_cs.c | 2 +- drivers/char/pcmcia/synclink_cs.c | 4 +- drivers/char/random.c | 2 +- drivers/char/sonypi.c | 4 +- drivers/char/xilinx_hwicap/xilinx_hwicap.c | 2 +- drivers/cpufreq/cpufreq.c | 2 +- drivers/crypto/amcc/crypto4xx_sa.c | 2 +- drivers/crypto/amcc/crypto4xx_sa.h | 2 +- drivers/crypto/ixp4xx_crypto.c | 2 +- drivers/dma/at_hdmac.c | 2 +- drivers/dma/coh901318.c | 2 +- drivers/dma/intel_mid_dma.c | 8 ++-- drivers/dma/intel_mid_dma_regs.h | 4 +- drivers/dma/mpc512x_dma.c | 2 +- drivers/dma/ste_dma40.c | 4 +- drivers/edac/Kconfig | 2 +- drivers/edac/cpc925_edac.c | 2 +- drivers/edac/edac_core.h | 8 ++-- drivers/edac/edac_device.c | 4 +- drivers/edac/edac_device_sysfs.c | 4 +- drivers/edac/edac_mc.c | 2 +- drivers/edac/edac_mc_sysfs.c | 2 +- drivers/edac/edac_pci_sysfs.c | 4 +- drivers/edac/i5000_edac.c | 2 +- drivers/edac/i5100_edac.c | 2 +- drivers/edac/i5400_edac.c | 4 +- drivers/edac/i7300_edac.c | 2 +- drivers/edac/i7core_edac.c | 2 +- drivers/edac/i82443bxgx_edac.c | 4 +- drivers/edac/mce_amd_inj.c | 2 +- drivers/edac/r82600_edac.c | 6 +-- drivers/firewire/net.c | 2 +- drivers/gpio/mc33880.c | 2 +- drivers/gpu/drm/drm_crtc.c | 4 +- drivers/gpu/drm/drm_mm.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_sdvo_regs.h | 2 +- drivers/gpu/drm/mga/mga_dma.c | 2 +- drivers/gpu/drm/nouveau/nouveau_channel.c | 4 +- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 +- drivers/gpu/drm/nouveau/nouveau_state.c | 2 +- drivers/gpu/drm/nouveau/nv04_crtc.c | 4 +- drivers/gpu/drm/nouveau/nv40_graph.c | 2 +- drivers/gpu/drm/radeon/atombios.h | 34 +++++++------- drivers/gpu/drm/radeon/evergreen_cs.c | 2 +- drivers/gpu/drm/radeon/r300.c | 2 +- drivers/gpu/drm/radeon/r300_reg.h | 4 +- drivers/gpu/drm/radeon/r600_cs.c | 2 +- drivers/gpu/drm/radeon/r600_hdmi.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 4 +- drivers/gpu/drm/radeon/radeon_cp.c | 2 +- drivers/gpu/drm/radeon/radeon_cursor.c | 2 +- drivers/gpu/drm/radeon/radeon_device.c | 2 +- drivers/gpu/drm/radeon/radeon_display.c | 2 +- drivers/gpu/drm/radeon/radeon_drv.h | 2 +- drivers/gpu/drm/radeon/radeon_object.h | 2 +- drivers/gpu/drm/radeon/radeon_state.c | 2 +- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- drivers/gpu/vga/vgaarb.c | 4 +- drivers/hid/hid-core.c | 4 +- drivers/hid/hid-debug.c | 2 +- drivers/hid/hid-magicmouse.c | 2 +- drivers/hid/hid-picolcd.c | 4 +- drivers/hid/hid-roccat-kone.h | 2 +- drivers/hwmon/abituguru.c | 2 +- drivers/hwmon/abituguru3.c | 2 +- drivers/hwmon/adm1026.c | 2 +- drivers/hwmon/lm85.c | 2 +- drivers/hwmon/lm90.c | 2 +- drivers/hwmon/sht15.c | 6 +-- drivers/hwmon/tmp102.c | 2 +- drivers/hwmon/w83791d.c | 2 +- drivers/hwmon/w83792d.c | 2 +- drivers/hwmon/w83793.c | 2 +- drivers/i2c/algos/i2c-algo-pca.c | 2 +- drivers/i2c/busses/i2c-ali1535.c | 2 +- drivers/i2c/busses/i2c-ali15x3.c | 2 +- drivers/i2c/busses/i2c-davinci.c | 2 +- drivers/i2c/busses/i2c-designware.c | 2 +- drivers/i2c/busses/i2c-elektor.c | 2 +- drivers/i2c/busses/i2c-i801.c | 2 +- drivers/i2c/busses/i2c-ibm_iic.c | 4 +- drivers/i2c/busses/i2c-intel-mid.c | 14 +++--- drivers/i2c/busses/i2c-isch.c | 2 +- drivers/i2c/busses/i2c-mxs.c | 2 +- drivers/i2c/busses/i2c-nomadik.c | 8 ++-- drivers/i2c/busses/i2c-s6000.c | 2 +- drivers/i2c/busses/i2c-stu300.c | 4 +- drivers/i2c/busses/i2c-tegra.c | 2 +- drivers/i2c/busses/i2c-xiic.c | 2 +- drivers/i2c/i2c-core.c | 2 +- drivers/ide/cy82c693.c | 2 +- drivers/ide/ide-floppy.c | 2 +- drivers/ide/ide-taskfile.c | 2 +- drivers/ide/piix.c | 4 +- drivers/ide/sis5513.c | 4 +- drivers/ide/triflex.c | 2 +- drivers/ide/via82cxxx.c | 2 +- drivers/infiniband/hw/amso1100/c2_ae.c | 2 +- drivers/infiniband/hw/amso1100/c2_qp.c | 2 +- drivers/infiniband/hw/amso1100/c2_wr.h | 4 +- drivers/infiniband/hw/ipath/ipath_driver.c | 2 +- drivers/infiniband/hw/ipath/ipath_file_ops.c | 2 +- drivers/infiniband/hw/ipath/ipath_init_chip.c | 2 +- drivers/infiniband/hw/ipath/ipath_ud.c | 4 +- drivers/infiniband/hw/ipath/ipath_user_sdma.c | 2 +- drivers/infiniband/hw/nes/nes_cm.c | 2 +- drivers/infiniband/hw/nes/nes_hw.c | 4 +- drivers/infiniband/hw/nes/nes_nic.c | 2 +- drivers/infiniband/hw/qib/qib.h | 2 +- drivers/infiniband/hw/qib/qib_file_ops.c | 4 +- drivers/infiniband/hw/qib/qib_iba6120.c | 4 +- drivers/infiniband/hw/qib/qib_iba7220.c | 6 +-- drivers/infiniband/hw/qib/qib_iba7322.c | 8 ++-- drivers/infiniband/hw/qib/qib_init.c | 2 +- drivers/infiniband/hw/qib/qib_mad.h | 2 +- drivers/infiniband/hw/qib/qib_twsi.c | 2 +- drivers/infiniband/hw/qib/qib_ud.c | 4 +- drivers/infiniband/hw/qib/qib_user_sdma.c | 2 +- drivers/infiniband/ulp/iser/iscsi_iser.h | 2 +- drivers/input/joydev.c | 4 +- drivers/input/joystick/a3d.c | 4 +- drivers/input/keyboard/davinci_keyscan.c | 2 +- drivers/input/misc/adxl34x.c | 2 +- drivers/input/misc/keyspan_remote.c | 2 +- drivers/input/misc/wistron_btns.c | 2 +- drivers/input/mouse/bcm5974.c | 2 +- drivers/input/mouse/synaptics_i2c.c | 2 +- drivers/input/mouse/vsxxxaa.c | 2 +- drivers/input/serio/hp_sdc.c | 2 +- drivers/input/serio/xilinx_ps2.c | 2 +- drivers/input/touchscreen/intel-mid-touch.c | 2 +- drivers/input/touchscreen/ucb1400_ts.c | 2 +- drivers/input/touchscreen/wm9705.c | 2 +- drivers/input/touchscreen/wm9712.c | 2 +- drivers/input/touchscreen/wm9713.c | 2 +- drivers/input/touchscreen/wm97xx-core.c | 4 +- drivers/isdn/hardware/eicon/divacapi.h | 2 +- drivers/isdn/hardware/eicon/io.h | 2 +- drivers/isdn/hardware/eicon/message.c | 4 +- drivers/isdn/hardware/eicon/pc.h | 2 +- drivers/isdn/hardware/eicon/um_idi.c | 2 +- drivers/isdn/hardware/mISDN/hfcmulti.c | 4 +- drivers/isdn/hardware/mISDN/hfcpci.c | 2 +- drivers/isdn/hisax/hfc_pci.c | 2 +- drivers/isdn/hisax/hfc_sx.c | 2 +- drivers/isdn/hisax/hfc_usb.h | 2 +- drivers/isdn/hisax/l3dss1.c | 4 +- drivers/isdn/hisax/l3ni1.c | 4 +- drivers/isdn/hisax/nj_s.c | 2 +- drivers/isdn/hisax/st5481_b.c | 2 +- drivers/isdn/hisax/st5481_usb.c | 2 +- drivers/isdn/hisax/teles_cs.c | 2 +- drivers/isdn/hysdn/hysdn_sched.c | 2 +- drivers/isdn/i4l/isdn_net.c | 4 +- drivers/isdn/i4l/isdn_ppp.c | 4 +- drivers/isdn/i4l/isdn_tty.c | 2 +- drivers/isdn/isdnloop/isdnloop.c | 2 +- drivers/isdn/mISDN/dsp.h | 2 +- drivers/isdn/mISDN/dsp_cmx.c | 4 +- drivers/isdn/mISDN/dsp_core.c | 8 ++-- drivers/isdn/mISDN/dsp_dtmf.c | 4 +- drivers/isdn/mISDN/dsp_tones.c | 2 +- drivers/isdn/mISDN/l1oip_core.c | 6 +-- drivers/isdn/mISDN/layer2.c | 4 +- drivers/leds/leds-pca9532.c | 2 +- drivers/leds/leds-wm8350.c | 4 +- drivers/lguest/lguest_user.c | 2 +- drivers/macintosh/adbhid.c | 2 +- drivers/macintosh/macio-adb.c | 2 +- drivers/macintosh/therm_adt746x.c | 2 +- drivers/macintosh/therm_pm72.c | 6 +-- drivers/macintosh/therm_windtunnel.c | 2 +- drivers/md/bitmap.h | 2 +- drivers/md/dm-region-hash.c | 2 +- drivers/md/faulty.c | 2 +- drivers/md/md.c | 2 +- drivers/md/md.h | 2 +- drivers/md/raid10.c | 6 +-- drivers/md/raid10.h | 4 +- drivers/media/common/saa7146_i2c.c | 8 ++-- drivers/media/common/tuners/mxl5005s.c | 2 +- drivers/media/common/tuners/tda18271.h | 2 +- drivers/media/dvb/b2c2/flexcop-pci.c | 2 +- drivers/media/dvb/bt8xx/dvb-bt8xx.c | 4 +- drivers/media/dvb/dvb-core/dvb_frontend.c | 4 +- drivers/media/dvb/dvb-usb/af9005-fe.c | 8 ++-- drivers/media/dvb/dvb-usb/friio.h | 2 +- drivers/media/dvb/dvb-usb/lmedm04.c | 12 ++--- drivers/media/dvb/frontends/atbm8830.h | 2 +- drivers/media/dvb/frontends/au8522_dig.c | 6 +-- drivers/media/dvb/frontends/bcm3510.c | 6 +-- drivers/media/dvb/frontends/cx22700.c | 2 +- drivers/media/dvb/frontends/cx22702.c | 6 +-- drivers/media/dvb/frontends/cx24110.c | 2 +- drivers/media/dvb/frontends/cx24113.h | 2 +- drivers/media/dvb/frontends/cx24123.c | 2 +- drivers/media/dvb/frontends/drx397xD.c | 2 +- drivers/media/dvb/frontends/mb86a16.c | 2 +- drivers/media/dvb/frontends/mb86a20s.c | 2 +- drivers/media/dvb/frontends/mt312.c | 2 +- drivers/media/dvb/frontends/s5h1420.c | 2 +- drivers/media/dvb/frontends/stb6100.c | 2 +- drivers/media/dvb/frontends/stv0297.c | 2 +- drivers/media/dvb/frontends/stv0367.c | 2 +- drivers/media/dvb/frontends/stv0900_priv.h | 2 +- drivers/media/dvb/frontends/stv090x.c | 12 ++--- drivers/media/dvb/mantis/mantis_uart.c | 2 +- drivers/media/dvb/ngene/ngene-core.c | 4 +- drivers/media/dvb/pluto2/pluto2.c | 10 ++-- drivers/media/dvb/siano/smsdvb.c | 2 +- drivers/media/dvb/ttpci/av7110.c | 2 +- drivers/media/dvb/ttpci/budget-patch.c | 2 +- drivers/media/dvb/ttusb-dec/ttusb_dec.c | 2 +- drivers/media/radio/radio-mr800.c | 2 +- drivers/media/radio/si4713-i2c.c | 2 +- drivers/media/radio/wl128x/fmdrv_common.c | 6 +-- drivers/media/radio/wl128x/fmdrv_common.h | 2 +- drivers/media/rc/ene_ir.c | 4 +- drivers/media/rc/imon.c | 2 +- drivers/media/rc/ir-raw.c | 2 +- drivers/media/rc/keymaps/rc-lme2510.c | 4 +- drivers/media/rc/keymaps/rc-msi-tvanywhere.c | 2 +- drivers/media/rc/keymaps/rc-norwood.c | 2 +- drivers/media/rc/rc-main.c | 4 +- drivers/media/video/au0828/au0828-video.c | 2 +- drivers/media/video/bt8xx/bttv-cards.c | 6 +-- drivers/media/video/bt8xx/bttv-gpio.c | 2 +- drivers/media/video/cafe_ccic.c | 2 +- drivers/media/video/cx18/cx18-av-core.h | 2 +- drivers/media/video/cx18/cx18-ioctl.c | 2 +- drivers/media/video/cx18/cx18-vbi.c | 2 +- drivers/media/video/cx231xx/cx231xx-avcore.c | 2 +- drivers/media/video/cx231xx/cx231xx-vbi.c | 2 +- drivers/media/video/cx231xx/cx231xx-video.c | 2 +- drivers/media/video/cx23885/cimax2.c | 2 +- drivers/media/video/cx23885/cx23885.h | 2 +- drivers/media/video/cx25840/cx25840-core.c | 10 ++-- drivers/media/video/davinci/dm644x_ccdc.c | 4 +- drivers/media/video/davinci/vpfe_capture.c | 2 +- drivers/media/video/em28xx/em28xx-video.c | 4 +- drivers/media/video/gspca/gl860/gl860-mi1320.c | 2 +- drivers/media/video/gspca/gspca.c | 4 +- drivers/media/video/gspca/mars.c | 2 +- drivers/media/video/gspca/mr97310a.c | 2 +- drivers/media/video/gspca/ov519.c | 4 +- drivers/media/video/gspca/sonixb.c | 2 +- drivers/media/video/gspca/spca500.c | 4 +- drivers/media/video/gspca/spca508.c | 2 +- drivers/media/video/gspca/sq905.c | 2 +- drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c | 2 +- drivers/media/video/hexium_gemini.c | 2 +- drivers/media/video/ivtv/ivtv-firmware.c | 4 +- drivers/media/video/ivtv/ivtvfb.c | 2 +- drivers/media/video/msp3400-driver.c | 4 +- drivers/media/video/msp3400-kthreads.c | 2 +- drivers/media/video/omap/omap_vout.c | 4 +- drivers/media/video/omap/omap_voutlib.c | 6 +-- drivers/media/video/omap1_camera.c | 4 +- drivers/media/video/omap3isp/isp.c | 8 ++-- drivers/media/video/omap3isp/ispccdc.h | 4 +- drivers/media/video/omap3isp/ispccp2.c | 2 +- drivers/media/video/omap3isp/ispcsi2.c | 2 +- drivers/media/video/omap3isp/isppreview.c | 20 ++++---- drivers/media/video/omap3isp/isppreview.h | 2 +- drivers/media/video/omap3isp/ispqueue.h | 4 +- drivers/media/video/omap3isp/ispresizer.c | 4 +- drivers/media/video/omap3isp/ispvideo.c | 6 +-- drivers/media/video/ov6650.c | 2 +- drivers/media/video/ov9640.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-eeprom.c | 2 +- drivers/media/video/pvrusb2/pvrusb2-hdw.h | 2 +- drivers/media/video/pxa_camera.c | 2 +- drivers/media/video/s5p-fimc/fimc-reg.c | 2 +- drivers/media/video/saa7134/saa7134-cards.c | 4 +- drivers/media/video/saa7164/saa7164-cmd.c | 2 +- drivers/media/video/saa7164/saa7164-fw.c | 2 +- drivers/media/video/saa7164/saa7164-types.h | 2 +- drivers/media/video/sn9c102/sn9c102_core.c | 2 +- drivers/media/video/sn9c102/sn9c102_sensor.h | 2 +- drivers/media/video/tcm825x.c | 4 +- drivers/media/video/tvaudio.c | 10 ++-- drivers/media/video/uvc/uvc_video.c | 8 ++-- drivers/media/video/v4l2-ioctl.c | 2 +- drivers/media/video/vpx3220.c | 2 +- drivers/media/video/zoran/videocodec.h | 2 +- drivers/media/video/zoran/zoran.h | 2 +- drivers/media/video/zoran/zoran_driver.c | 2 +- drivers/memstick/core/mspro_block.c | 2 +- drivers/memstick/host/r592.c | 2 +- drivers/memstick/host/r592.h | 6 +-- drivers/message/fusion/lsi/mpi_log_fc.h | 4 +- drivers/message/fusion/lsi/mpi_log_sas.h | 14 +++--- drivers/message/fusion/mptbase.c | 6 +-- drivers/message/fusion/mptctl.c | 4 +- drivers/message/fusion/mptsas.c | 8 ++-- drivers/message/i2o/README | 2 +- drivers/message/i2o/device.c | 8 ++-- drivers/message/i2o/i2o_block.c | 4 +- drivers/message/i2o/i2o_block.h | 2 +- drivers/message/i2o/i2o_scsi.c | 2 +- drivers/mfd/Kconfig | 2 +- drivers/mfd/ab8500-gpadc.c | 2 +- drivers/mfd/ezx-pcap.c | 4 +- drivers/mfd/omap-usb-host.c | 2 +- drivers/mfd/pcf50633-core.c | 4 +- drivers/mfd/twl6030-irq.c | 4 +- drivers/mfd/ucb1400_core.c | 2 +- drivers/misc/bmp085.c | 4 +- drivers/misc/c2port/c2port-duramar2150.c | 2 +- drivers/misc/ibmasm/remote.h | 2 +- drivers/misc/iwmc3200top/main.c | 2 +- drivers/misc/kgdbts.c | 2 +- drivers/misc/sgi-gru/grukservices.c | 2 +- drivers/misc/sgi-gru/grutables.h | 2 +- drivers/misc/ti-st/st_kim.c | 2 +- drivers/mmc/card/mmc_test.c | 2 +- drivers/mmc/core/mmc.c | 2 +- drivers/mmc/core/mmc_ops.c | 2 +- drivers/mmc/core/sdio_irq.c | 2 +- drivers/mmc/host/atmel-mci.c | 4 +- drivers/mmc/host/mmc_spi.c | 2 +- drivers/mmc/host/s3cmci.c | 6 +-- drivers/mmc/host/tmio_mmc_pio.c | 2 +- drivers/mmc/host/wbsd.c | 6 +-- drivers/mtd/chips/Kconfig | 2 +- drivers/mtd/chips/cfi_cmdset_0001.c | 4 +- drivers/mtd/chips/cfi_cmdset_0002.c | 10 ++-- drivers/mtd/chips/cfi_util.c | 2 +- drivers/mtd/chips/jedec_probe.c | 2 +- drivers/mtd/devices/block2mtd.c | 2 +- drivers/mtd/devices/doc2001plus.c | 2 +- drivers/mtd/devices/docecc.c | 4 +- drivers/mtd/devices/lart.c | 4 +- drivers/mtd/devices/pmc551.c | 4 +- drivers/mtd/lpddr/lpddr_cmds.c | 4 +- drivers/mtd/maps/ceiva.c | 4 +- drivers/mtd/maps/cfi_flagadm.c | 2 +- drivers/mtd/maps/pcmciamtd.c | 2 +- drivers/mtd/maps/pmcmsp-flash.c | 2 +- drivers/mtd/maps/sc520cdp.c | 2 +- drivers/mtd/maps/tqm8xxl.c | 2 +- drivers/mtd/mtdblock.c | 2 +- drivers/mtd/mtdchar.c | 2 +- drivers/mtd/nand/Kconfig | 2 +- drivers/mtd/nand/ams-delta.c | 2 +- drivers/mtd/nand/autcpu12.c | 2 +- drivers/mtd/nand/cs553x_nand.c | 2 +- drivers/mtd/nand/denali.c | 6 +-- drivers/mtd/nand/diskonchip.c | 8 ++-- drivers/mtd/nand/fsl_elbc_nand.c | 2 +- drivers/mtd/nand/fsmc_nand.c | 10 ++-- drivers/mtd/nand/nand_base.c | 2 +- drivers/mtd/nand/nand_bbt.c | 2 +- drivers/mtd/nand/nandsim.c | 2 +- drivers/mtd/nand/nomadik_nand.c | 2 +- drivers/mtd/nand/pasemi_nand.c | 2 +- drivers/mtd/nand/plat_nand.c | 2 +- drivers/mtd/nand/pxa3xx_nand.c | 2 +- drivers/mtd/nand/r852.c | 10 ++-- drivers/mtd/nand/sh_flctl.c | 2 +- drivers/mtd/nand/sm_common.c | 2 +- drivers/mtd/nand/tmio_nand.c | 2 +- drivers/mtd/onenand/omap2.c | 4 +- drivers/mtd/onenand/onenand_sim.c | 4 +- drivers/mtd/sm_ftl.c | 4 +- drivers/mtd/ubi/scan.c | 2 +- drivers/net/3c501.c | 6 +-- drivers/net/3c523.c | 2 +- drivers/net/3c527.c | 4 +- drivers/net/3c59x.c | 2 +- drivers/net/acenic.c | 4 +- drivers/net/amd8111e.c | 2 +- drivers/net/at1700.c | 2 +- drivers/net/atl1e/atl1e_main.c | 2 +- drivers/net/atlx/atl2.c | 2 +- drivers/net/bcm63xx_enet.c | 2 +- drivers/net/benet/be_cmds.c | 2 +- drivers/net/benet/be_main.c | 2 +- drivers/net/bna/bna_hw.h | 2 +- drivers/net/bnx2x/bnx2x.h | 2 +- drivers/net/bnx2x/bnx2x_hsi.h | 2 +- drivers/net/bnx2x/bnx2x_link.c | 14 +++--- drivers/net/bnx2x/bnx2x_main.c | 10 ++-- drivers/net/bnx2x/bnx2x_reg.h | 44 +++++++++--------- drivers/net/bonding/bond_alb.h | 2 +- drivers/net/caif/caif_shmcore.c | 2 +- drivers/net/caif/caif_spi.c | 2 +- drivers/net/caif/caif_spi_slave.c | 4 +- drivers/net/can/at91_can.c | 4 +- drivers/net/can/c_can/c_can.c | 4 +- drivers/net/can/janz-ican3.c | 8 ++-- drivers/net/can/mscan/mscan.c | 2 +- drivers/net/can/sja1000/sja1000.c | 2 +- drivers/net/can/softing/softing.h | 2 +- drivers/net/can/softing/softing_main.c | 2 +- drivers/net/can/ti_hecc.c | 2 +- drivers/net/can/usb/ems_usb.c | 2 +- drivers/net/can/usb/esd_usb2.c | 2 +- drivers/net/cassini.c | 4 +- drivers/net/cassini.h | 2 +- drivers/net/chelsio/mv88e1xxx.c | 2 +- drivers/net/chelsio/pm3393.c | 2 +- drivers/net/chelsio/sge.c | 2 +- drivers/net/chelsio/vsc7326.c | 2 +- drivers/net/cris/eth_v10.c | 2 +- drivers/net/cxgb3/sge.c | 2 +- drivers/net/cxgb3/t3_hw.c | 6 +-- drivers/net/cxgb4/t4_hw.c | 2 +- drivers/net/cxgb4vf/cxgb4vf_main.c | 2 +- drivers/net/cxgb4vf/sge.c | 8 ++-- drivers/net/davinci_emac.c | 8 ++-- drivers/net/e1000/e1000_ethtool.c | 2 +- drivers/net/e1000/e1000_hw.h | 2 +- drivers/net/e1000/e1000_main.c | 2 +- drivers/net/e1000e/netdev.c | 2 +- drivers/net/enc28j60_hw.h | 2 +- drivers/net/eth16i.c | 2 +- drivers/net/ethoc.c | 2 +- drivers/net/fec.h | 4 +- drivers/net/forcedeth.c | 14 +++--- drivers/net/gianfar.h | 2 +- drivers/net/hamradio/Makefile | 2 +- drivers/net/hamradio/yam.c | 2 +- drivers/net/hp100.c | 16 +++---- drivers/net/hp100.h | 2 +- drivers/net/ibm_newemac/tah.c | 2 +- drivers/net/ibmlana.c | 4 +- drivers/net/ibmlana.h | 2 +- drivers/net/igb/e1000_mac.c | 4 +- drivers/net/igb/e1000_phy.c | 2 +- drivers/net/igb/igb_main.c | 14 +++--- drivers/net/igbvf/netdev.c | 2 +- drivers/net/ipg.c | 28 +++++------ drivers/net/irda/ali-ircc.c | 4 +- drivers/net/irda/donauboe.c | 2 +- drivers/net/irda/donauboe.h | 2 +- drivers/net/irda/girbil-sir.c | 2 +- drivers/net/irda/irda-usb.c | 4 +- drivers/net/irda/mcs7780.c | 6 +-- drivers/net/irda/nsc-ircc.c | 2 +- drivers/net/irda/nsc-ircc.h | 2 +- drivers/net/irda/pxaficp_ir.c | 4 +- drivers/net/irda/smsc-ircc2.c | 2 +- drivers/net/irda/via-ircc.c | 4 +- drivers/net/irda/vlsi_ir.h | 4 +- drivers/net/ixgbe/ixgbe_dcb.c | 2 +- drivers/net/ixgbe/ixgbe_dcb_nl.c | 4 +- drivers/net/ixgbe/ixgbe_main.c | 8 ++-- drivers/net/ixgbe/ixgbe_phy.c | 2 +- drivers/net/ixgbe/ixgbe_x540.c | 2 +- drivers/net/ixgbevf/ixgbevf_main.c | 2 +- drivers/net/ks8842.c | 2 +- drivers/net/ks8851.c | 8 ++-- drivers/net/ks8851_mll.c | 4 +- drivers/net/lib8390.c | 4 +- drivers/net/lp486e.c | 2 +- drivers/net/meth.h | 4 +- drivers/net/mlx4/en_main.c | 2 +- drivers/net/mlx4/en_netdev.c | 10 ++-- drivers/net/mlx4/en_rx.c | 2 +- drivers/net/mlx4/en_selftest.c | 2 +- drivers/net/mlx4/en_tx.c | 2 +- drivers/net/mlx4/mcg.c | 2 +- drivers/net/mlx4/port.c | 4 +- drivers/net/myri10ge/myri10ge.c | 2 +- drivers/net/myri_sbus.c | 2 +- drivers/net/natsemi.c | 6 +-- drivers/net/netxen/netxen_nic_hdr.h | 2 +- drivers/net/ns83820.c | 4 +- drivers/net/pch_gbe/pch_gbe.h | 14 +++--- drivers/net/pch_gbe/pch_gbe_ethtool.c | 2 +- drivers/net/pch_gbe/pch_gbe_main.c | 4 +- drivers/net/pci-skeleton.c | 2 +- drivers/net/pcmcia/3c574_cs.c | 2 +- drivers/net/pcmcia/axnet_cs.c | 4 +- drivers/net/pcmcia/smc91c92_cs.c | 2 +- drivers/net/pcnet32.c | 2 +- drivers/net/phy/phy_device.c | 4 +- drivers/net/ppp_generic.c | 2 +- drivers/net/ppp_synctty.c | 2 +- drivers/net/pppoe.c | 2 +- drivers/net/ps3_gelic_net.c | 4 +- drivers/net/ps3_gelic_net.h | 2 +- drivers/net/ps3_gelic_wireless.c | 2 +- drivers/net/pxa168_eth.c | 2 +- drivers/net/qla3xxx.h | 2 +- drivers/net/qlge/qlge_main.c | 10 ++-- drivers/net/r6040.c | 2 +- drivers/net/s2io.c | 6 +-- drivers/net/s2io.h | 2 +- drivers/net/sfc/falcon.c | 4 +- drivers/net/sfc/mcdi.c | 2 +- drivers/net/sfc/mcdi_pcol.h | 6 +-- drivers/net/sfc/mcdi_phy.c | 2 +- drivers/net/sfc/net_driver.h | 2 +- drivers/net/sgiseeq.c | 4 +- drivers/net/sh_eth.c | 2 +- drivers/net/sis190.c | 4 +- drivers/net/sis900.c | 6 +-- drivers/net/skfp/ess.c | 8 ++-- drivers/net/skfp/fplustm.c | 6 +-- drivers/net/skfp/h/cmtdef.h | 4 +- drivers/net/skfp/h/fplustm.h | 4 +- drivers/net/skfp/h/smc.h | 2 +- drivers/net/skfp/h/smt.h | 2 +- drivers/net/skfp/h/supern_2.h | 4 +- drivers/net/skfp/hwmtm.c | 2 +- drivers/net/skfp/pcmplc.c | 6 +-- drivers/net/skfp/smt.c | 2 +- drivers/net/skge.h | 8 ++-- drivers/net/sky2.c | 4 +- drivers/net/sky2.h | 6 +-- drivers/net/smc91x.h | 2 +- drivers/net/smsc911x.c | 2 +- drivers/net/smsc9420.c | 2 +- drivers/net/stmmac/norm_desc.c | 2 +- drivers/net/sunbmac.h | 2 +- drivers/net/sungem.c | 2 +- drivers/net/sunhme.h | 2 +- drivers/net/tc35815.c | 38 +++++++-------- drivers/net/tehuti.c | 12 ++--- drivers/net/tehuti.h | 2 +- drivers/net/tg3.c | 2 +- drivers/net/tg3.h | 4 +- drivers/net/tokenring/3c359.c | 2 +- drivers/net/tokenring/madgemc.c | 6 +-- drivers/net/tokenring/smctr.c | 12 ++--- drivers/net/tokenring/tms380tr.h | 2 +- drivers/net/tsi108_eth.h | 8 ++-- drivers/net/tulip/de4x5.c | 6 +-- drivers/net/tulip/dmfe.c | 2 +- drivers/net/tulip/eeprom.c | 2 +- drivers/net/typhoon.c | 2 +- drivers/net/ucc_geth.h | 4 +- drivers/net/usb/cdc_eem.c | 2 +- drivers/net/usb/kaweth.c | 2 +- drivers/net/via-rhine.c | 4 +- drivers/net/via-velocity.c | 4 +- drivers/net/vmxnet3/vmxnet3_drv.c | 4 +- drivers/net/vxge/vxge-config.c | 2 +- drivers/net/vxge/vxge-main.c | 8 ++-- drivers/net/vxge/vxge-traffic.c | 4 +- drivers/net/vxge/vxge-traffic.h | 2 +- drivers/net/wan/cosa.c | 2 +- drivers/net/wan/dscc4.c | 8 ++-- drivers/net/wan/hostess_sv11.c | 2 +- drivers/net/wan/ixp4xx_hss.c | 4 +- drivers/net/wan/lmc/lmc_main.c | 2 +- drivers/net/wan/lmc/lmc_var.h | 6 +-- drivers/net/wan/z85230.c | 8 ++-- drivers/net/wimax/i2400m/control.c | 4 +- drivers/net/wimax/i2400m/driver.c | 4 +- drivers/net/wimax/i2400m/fw.c | 4 +- drivers/net/wimax/i2400m/i2400m-usb.h | 6 +-- drivers/net/wimax/i2400m/i2400m.h | 4 +- drivers/net/wimax/i2400m/netdev.c | 2 +- drivers/net/wimax/i2400m/op-rfkill.c | 4 +- drivers/net/wimax/i2400m/rx.c | 4 +- drivers/net/wimax/i2400m/tx.c | 4 +- drivers/net/wimax/i2400m/usb-fw.c | 2 +- drivers/net/wimax/i2400m/usb-rx.c | 2 +- drivers/net/wimax/i2400m/usb-tx.c | 2 +- drivers/net/wireless/airo.c | 14 +++--- drivers/net/wireless/ath/ar9170/main.c | 2 +- drivers/net/wireless/ath/ar9170/phy.c | 2 +- drivers/net/wireless/ath/ath5k/ani.h | 2 +- drivers/net/wireless/ath/ath5k/base.c | 6 +-- drivers/net/wireless/ath/ath5k/desc.c | 14 +++--- drivers/net/wireless/ath/ath5k/eeprom.c | 4 +- drivers/net/wireless/ath/ath5k/pci.c | 2 +- drivers/net/wireless/ath/ath5k/pcu.c | 6 +-- drivers/net/wireless/ath/ath5k/phy.c | 22 ++++----- drivers/net/wireless/ath/ath5k/reg.h | 12 ++--- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 2 +- drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 2 +- drivers/net/wireless/ath/ath9k/htc_hst.c | 2 +- drivers/net/wireless/ath/ath9k/pci.c | 2 +- drivers/net/wireless/ath/ath9k/rc.c | 2 +- drivers/net/wireless/ath/ath9k/xmit.c | 4 +- drivers/net/wireless/ath/carl9170/carl9170.h | 2 +- drivers/net/wireless/ath/carl9170/phy.c | 2 +- drivers/net/wireless/ath/carl9170/rx.c | 2 +- drivers/net/wireless/ath/carl9170/usb.c | 2 +- drivers/net/wireless/ath/hw.c | 2 +- drivers/net/wireless/ath/regd.c | 4 +- drivers/net/wireless/atmel.c | 4 +- drivers/net/wireless/atmel_cs.c | 2 +- drivers/net/wireless/b43/b43.h | 2 +- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43/phy_g.h | 2 +- drivers/net/wireless/b43/phy_n.h | 2 +- drivers/net/wireless/b43legacy/b43legacy.h | 2 +- drivers/net/wireless/hostap/hostap_ap.c | 2 +- drivers/net/wireless/hostap/hostap_ap.h | 2 +- drivers/net/wireless/hostap/hostap_ioctl.c | 4 +- drivers/net/wireless/hostap/hostap_wlan.h | 2 +- drivers/net/wireless/ipw2x00/ipw2100.c | 2 +- drivers/net/wireless/ipw2x00/ipw2200.c | 18 ++++---- drivers/net/wireless/ipw2x00/libipw_rx.c | 2 +- drivers/net/wireless/iwlegacy/iwl-core.c | 2 +- drivers/net/wireless/iwlegacy/iwl-fh.h | 2 +- drivers/net/wireless/iwlegacy/iwl-scan.c | 2 +- drivers/net/wireless/iwlegacy/iwl-sta.c | 2 +- drivers/net/wireless/iwlwifi/iwl-agn-ict.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 2 +- drivers/net/wireless/iwlwifi/iwl-fh.h | 2 +- drivers/net/wireless/iwlwifi/iwl-scan.c | 2 +- drivers/net/wireless/iwmc3200wifi/hal.c | 4 +- drivers/net/wireless/iwmc3200wifi/tx.c | 2 +- drivers/net/wireless/libertas/README | 4 +- drivers/net/wireless/libertas/cfg.c | 2 +- drivers/net/wireless/libertas/if_cs.c | 2 +- drivers/net/wireless/libertas/if_spi.h | 2 +- drivers/net/wireless/mac80211_hwsim.c | 2 +- drivers/net/wireless/orinoco/hw.c | 2 +- drivers/net/wireless/p54/main.c | 2 +- drivers/net/wireless/p54/p54spi.c | 2 +- drivers/net/wireless/prism54/islpci_eth.c | 4 +- drivers/net/wireless/rayctl.h | 2 +- drivers/net/wireless/rt2x00/rt2800.h | 2 +- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- drivers/net/wireless/rt2x00/rt2x00.h | 8 ++-- drivers/net/wireless/rt2x00/rt2x00config.c | 2 +- drivers/net/wireless/rt2x00/rt2x00crypto.c | 2 +- drivers/net/wireless/rt2x00/rt2x00dump.h | 2 +- drivers/net/wireless/rt2x00/rt2x00link.c | 2 +- drivers/net/wireless/rt2x00/rt2x00queue.c | 6 +-- drivers/net/wireless/rt2x00/rt2x00queue.h | 12 ++--- drivers/net/wireless/rt2x00/rt2x00usb.c | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.h | 2 +- drivers/net/wireless/rtlwifi/base.c | 2 +- drivers/net/wireless/rtlwifi/pci.c | 2 +- drivers/net/wireless/rtlwifi/regd.c | 2 +- drivers/net/wireless/rtlwifi/wifi.h | 2 +- drivers/net/wireless/wl1251/cmd.c | 2 +- drivers/net/wireless/wl1251/rx.c | 2 +- drivers/net/wireless/wl12xx/cmd.c | 2 +- drivers/net/wireless/wl12xx/conf.h | 8 ++-- drivers/net/wireless/wl12xx/io.h | 2 +- drivers/net/wireless/wl3501_cs.c | 4 +- drivers/net/wireless/zd1211rw/zd_rf_rf2959.c | 2 +- drivers/net/wireless/zd1211rw/zd_rf_uw2453.c | 2 +- drivers/net/xilinx_emaclite.c | 2 +- drivers/net/znet.c | 2 +- drivers/of/fdt.c | 2 +- drivers/of/of_mdio.c | 2 +- drivers/parisc/pdc_stable.c | 4 +- drivers/parport/Kconfig | 2 +- drivers/parport/ieee1284.c | 2 +- drivers/parport/parport_pc.c | 6 +-- drivers/pci/hotplug/acpi_pcihp.c | 2 +- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/pci/hotplug/rpaphp_core.c | 2 +- drivers/pci/intel-iommu.c | 2 +- drivers/pci/intr_remapping.c | 2 +- drivers/pci/iova.c | 2 +- drivers/pci/pci-sysfs.c | 2 +- drivers/pci/quirks.c | 4 +- drivers/pcmcia/i82092.c | 2 +- drivers/pcmcia/pcmcia_resource.c | 2 +- drivers/pcmcia/pxa2xx_lubbock.c | 2 +- drivers/pcmcia/ti113x.h | 2 +- drivers/platform/x86/intel_mid_thermal.c | 2 +- drivers/pnp/card.c | 4 +- drivers/pnp/pnpbios/bioscalls.c | 2 +- drivers/pps/Kconfig | 2 +- drivers/ps3/ps3-lpm.c | 6 +-- drivers/ps3/ps3-sys-manager.c | 2 +- drivers/rapidio/rio-scan.c | 2 +- drivers/regulator/core.c | 2 +- drivers/regulator/max8952.c | 2 +- drivers/rtc/interface.c | 2 +- drivers/rtc/rtc-at91rm9200.c | 2 +- drivers/rtc/rtc-bfin.c | 4 +- drivers/rtc/rtc-lpc32xx.c | 2 +- drivers/rtc/rtc-x1205.c | 2 +- drivers/s390/block/dasd_3990_erp.c | 6 +-- drivers/s390/block/dasd_devmap.c | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/char/raw3270.c | 2 +- drivers/s390/char/tape_char.c | 2 +- drivers/s390/char/tty3270.c | 2 +- drivers/s390/cio/device_fsm.c | 4 +- drivers/s390/crypto/zcrypt_api.h | 2 +- drivers/s390/net/claw.c | 2 +- drivers/s390/net/ctcm_fsms.c | 2 +- drivers/s390/net/lcs.c | 2 +- drivers/s390/net/qeth_core_main.c | 2 +- drivers/s390/scsi/zfcp_fsf.c | 2 +- drivers/s390/scsi/zfcp_qdio.c | 2 +- drivers/sbus/char/jsflash.c | 2 +- drivers/sbus/char/max1617.h | 2 +- drivers/scsi/3w-9xxx.h | 2 +- drivers/scsi/3w-xxxx.h | 2 +- drivers/scsi/53c700.scr | 2 +- drivers/scsi/53c700_d.h_shipped | 2 +- drivers/scsi/FlashPoint.c | 4 +- drivers/scsi/NCR5380.c | 8 ++-- drivers/scsi/aacraid/aachba.c | 4 +- drivers/scsi/aacraid/aacraid.h | 2 +- drivers/scsi/aacraid/commsup.c | 2 +- drivers/scsi/advansys.c | 2 +- drivers/scsi/aha1740.c | 2 +- drivers/scsi/aic7xxx/aic79xx.h | 4 +- drivers/scsi/aic7xxx/aic79xx.reg | 24 +++++----- drivers/scsi/aic7xxx/aic79xx.seq | 18 ++++---- drivers/scsi/aic7xxx/aic79xx_core.c | 24 +++++----- drivers/scsi/aic7xxx/aic79xx_osm.c | 2 +- drivers/scsi/aic7xxx/aic7xxx.h | 4 +- drivers/scsi/aic7xxx/aic7xxx.reg | 2 +- drivers/scsi/aic7xxx/aic7xxx.seq | 10 ++-- drivers/scsi/aic7xxx/aic7xxx_core.c | 18 ++++---- drivers/scsi/aic7xxx/aic7xxx_osm.c | 4 +- drivers/scsi/aic7xxx/aic7xxx_pci.c | 6 +-- drivers/scsi/aic7xxx/aicasm/aicasm_gram.y | 8 ++-- drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y | 2 +- drivers/scsi/aic7xxx_old.c | 12 ++--- drivers/scsi/aic7xxx_old/aic7xxx.seq | 8 ++-- drivers/scsi/aic94xx/aic94xx_reg_def.h | 2 +- drivers/scsi/arm/acornscsi.c | 4 +- drivers/scsi/arm/acornscsi.h | 6 +-- drivers/scsi/arm/arxescsi.c | 2 +- drivers/scsi/arm/cumana_2.c | 2 +- drivers/scsi/arm/eesox.c | 2 +- drivers/scsi/arm/fas216.c | 4 +- drivers/scsi/arm/fas216.h | 10 ++-- drivers/scsi/arm/powertec.c | 2 +- drivers/scsi/atari_NCR5380.c | 6 +-- drivers/scsi/atp870u.c | 2 +- drivers/scsi/be2iscsi/be_cmds.h | 18 ++++---- drivers/scsi/bfa/bfa_core.c | 2 +- drivers/scsi/bfa/bfa_defs_svc.h | 6 +-- drivers/scsi/bfa/bfa_fc.h | 2 +- drivers/scsi/bfa/bfa_fcs.c | 2 +- drivers/scsi/bfa/bfa_fcs.h | 2 +- drivers/scsi/bfa/bfa_fcs_lport.c | 2 +- drivers/scsi/bfa/bfa_svc.c | 4 +- drivers/scsi/bfa/bfa_svc.h | 2 +- drivers/scsi/bfa/bfad.c | 2 +- drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h | 2 +- drivers/scsi/bnx2fc/bnx2fc_els.c | 2 +- drivers/scsi/bnx2fc/bnx2fc_io.c | 4 +- drivers/scsi/bnx2fc/bnx2fc_tgt.c | 2 +- drivers/scsi/bnx2i/bnx2i_hwi.c | 2 +- drivers/scsi/cxgbi/libcxgbi.h | 6 +-- drivers/scsi/dc395x.c | 14 +++--- drivers/scsi/dc395x.h | 2 +- drivers/scsi/device_handler/scsi_dh_alua.c | 4 +- drivers/scsi/dpt/sys_info.h | 6 +-- drivers/scsi/eata.c | 2 +- drivers/scsi/fcoe/fcoe_ctlr.c | 4 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/fnic/fnic_fcs.c | 2 +- drivers/scsi/fnic/fnic_scsi.c | 4 +- drivers/scsi/g_NCR5380.c | 4 +- drivers/scsi/gdth.h | 2 +- drivers/scsi/gvp11.c | 2 +- drivers/scsi/imm.c | 2 +- drivers/scsi/initio.c | 4 +- drivers/scsi/initio.h | 4 +- drivers/scsi/ips.c | 4 +- drivers/scsi/ips.h | 2 +- drivers/scsi/iscsi_tcp.c | 2 +- drivers/scsi/libfc/fc_exch.c | 4 +- drivers/scsi/libfc/fc_fcp.c | 4 +- drivers/scsi/libfc/fc_lport.c | 18 ++++---- drivers/scsi/libsas/sas_expander.c | 2 +- drivers/scsi/lpfc/lpfc_attr.c | 2 +- drivers/scsi/lpfc/lpfc_bsg.c | 2 +- drivers/scsi/lpfc/lpfc_debugfs.c | 8 ++-- drivers/scsi/lpfc/lpfc_els.c | 4 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 16 +++---- drivers/scsi/lpfc/lpfc_init.c | 20 ++++---- drivers/scsi/lpfc/lpfc_mbox.c | 2 +- drivers/scsi/lpfc/lpfc_nl.h | 2 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 10 ++-- drivers/scsi/lpfc/lpfc_scsi.h | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 26 +++++------ drivers/scsi/megaraid.c | 4 +- drivers/scsi/megaraid.h | 6 +-- drivers/scsi/megaraid/mbox_defs.h | 8 ++-- drivers/scsi/megaraid/megaraid_mbox.c | 6 +-- drivers/scsi/megaraid/megaraid_sas.h | 2 +- drivers/scsi/megaraid/megaraid_sas_base.c | 2 +- drivers/scsi/mpt2sas/mpi/mpi2_init.h | 2 +- drivers/scsi/mpt2sas/mpt2sas_base.c | 12 ++--- drivers/scsi/mpt2sas/mpt2sas_config.c | 2 +- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 2 +- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 20 ++++---- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/nsp32.c | 6 +-- drivers/scsi/nsp32.h | 2 +- drivers/scsi/osst.c | 6 +-- drivers/scsi/osst.h | 2 +- drivers/scsi/pcmcia/nsp_cs.c | 2 +- drivers/scsi/pm8001/pm8001_hwi.c | 2 +- drivers/scsi/pm8001/pm8001_hwi.h | 4 +- drivers/scsi/pm8001/pm8001_sas.h | 2 +- drivers/scsi/pmcraid.c | 10 ++-- drivers/scsi/pmcraid.h | 2 +- drivers/scsi/qla1280.c | 2 +- drivers/scsi/qla2xxx/qla_def.h | 2 +- drivers/scsi/qla2xxx/qla_fw.h | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 6 +-- drivers/scsi/qla2xxx/qla_nx.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 6 +-- drivers/scsi/qla4xxx/ql4_def.h | 2 +- drivers/scsi/qla4xxx/ql4_init.c | 2 +- drivers/scsi/qla4xxx/ql4_nvram.h | 2 +- drivers/scsi/qla4xxx/ql4_os.c | 8 ++-- drivers/scsi/scsi_debug.c | 2 +- drivers/scsi/scsi_netlink.c | 2 +- drivers/scsi/scsi_tgt_lib.c | 2 +- drivers/scsi/scsi_transport_fc.c | 4 +- drivers/scsi/sd.c | 2 +- drivers/scsi/sr.c | 2 +- drivers/scsi/sun3_NCR5380.c | 6 +-- drivers/scsi/sym53c416.c | 2 +- drivers/scsi/sym53c8xx_2/sym_fw1.h | 2 +- drivers/scsi/sym53c8xx_2/sym_fw2.h | 2 +- drivers/scsi/sym53c8xx_2/sym_hipd.c | 4 +- drivers/scsi/sym53c8xx_2/sym_malloc.c | 2 +- drivers/scsi/wd33c93.c | 2 +- drivers/scsi/wd7000.c | 2 +- drivers/sfi/sfi_core.c | 2 +- drivers/spi/amba-pl022.c | 16 +++---- drivers/spi/au1550_spi.c | 2 +- drivers/spi/dw_spi.c | 2 +- drivers/spi/dw_spi.h | 2 +- drivers/spi/ep93xx_spi.c | 2 +- drivers/spi/pxa2xx_spi.c | 4 +- drivers/spi/spi.c | 2 +- drivers/spi/spi_bfin5xx.c | 2 +- drivers/spi/spi_fsl_espi.c | 2 +- drivers/ssb/pci.c | 2 +- drivers/ssb/sprom.c | 2 +- .../ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c | 6 +-- drivers/staging/ath6kl/include/aggr_recv_api.h | 2 +- drivers/staging/ath6kl/include/common/a_hci.h | 4 +- drivers/staging/ath6kl/include/common/dbglog.h | 2 +- .../staging/ath6kl/include/common/epping_test.h | 2 +- drivers/staging/ath6kl/include/common/ini_dset.h | 2 +- drivers/staging/ath6kl/include/common/testcmd.h | 4 +- drivers/staging/ath6kl/include/common/wmi.h | 8 ++-- drivers/staging/ath6kl/include/common/wmix.h | 2 +- drivers/staging/ath6kl/include/htc_api.h | 6 +-- drivers/staging/ath6kl/miscdrv/credit_dist.c | 6 +-- drivers/staging/ath6kl/os/linux/ar6000_android.c | 2 +- drivers/staging/ath6kl/os/linux/ar6000_drv.c | 8 ++-- drivers/staging/ath6kl/wmi/wmi.c | 2 +- drivers/staging/bcm/Adapter.h | 10 ++-- drivers/staging/bcm/CmHost.c | 16 +++---- drivers/staging/bcm/HostMIBSInterface.h | 2 +- drivers/staging/bcm/IPv6Protocol.c | 4 +- drivers/staging/bcm/InterfaceIdleMode.c | 4 +- drivers/staging/bcm/InterfaceIsr.c | 4 +- drivers/staging/bcm/InterfaceRx.c | 10 ++-- drivers/staging/bcm/Ioctl.h | 2 +- drivers/staging/bcm/LeakyBucket.c | 2 +- drivers/staging/bcm/Misc.c | 6 +-- drivers/staging/bcm/Qos.c | 2 +- drivers/staging/bcm/cntrl_SignalingInterface.h | 6 +-- drivers/staging/bcm/nvm.c | 54 +++++++++++----------- drivers/staging/brcm80211/README | 2 +- drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c | 2 +- .../staging/brcm80211/brcmfmac/dhd_custom_gpio.c | 2 +- drivers/staging/brcm80211/brcmfmac/dhd_linux.c | 2 +- drivers/staging/brcm80211/brcmfmac/dhd_sdio.c | 4 +- drivers/staging/brcm80211/brcmsmac/wl_mac80211.c | 2 +- drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c | 6 +-- drivers/staging/brcm80211/brcmsmac/wlc_bmac.c | 2 +- drivers/staging/brcm80211/brcmsmac/wlc_main.c | 4 +- drivers/staging/brcm80211/brcmsmac/wlc_rate.c | 2 +- drivers/staging/brcm80211/include/bcmsrom_fmt.h | 2 +- drivers/staging/brcm80211/include/hndsoc.h | 2 +- drivers/staging/brcm80211/util/bcmotp.c | 4 +- drivers/staging/brcm80211/util/bcmsrom.c | 2 +- drivers/staging/brcm80211/util/hnddma.c | 6 +-- drivers/staging/brcm80211/util/sbpcmcia.h | 2 +- drivers/staging/brcm80211/util/siutils.c | 2 +- drivers/staging/comedi/comedi_fops.c | 2 +- .../comedi/drivers/addi-data/APCI1710_Chrono.c | 8 ++-- .../comedi/drivers/addi-data/addi_amcc_S5920.c | 2 +- .../comedi/drivers/addi-data/hwdrv_apci2032.c | 2 +- .../comedi/drivers/addi-data/hwdrv_apci3120.c | 18 ++++---- .../comedi/drivers/addi-data/hwdrv_apci3120.h | 2 +- .../comedi/drivers/addi-data/hwdrv_apci3200.c | 4 +- drivers/staging/comedi/drivers/adl_pci9118.c | 6 +-- drivers/staging/comedi/drivers/adq12b.c | 4 +- drivers/staging/comedi/drivers/adv_pci1710.c | 8 ++-- drivers/staging/comedi/drivers/cb_pcidas.c | 6 +-- drivers/staging/comedi/drivers/cb_pcidas64.c | 14 +++--- drivers/staging/comedi/drivers/comedi_test.c | 2 +- drivers/staging/comedi/drivers/das1800.c | 2 +- drivers/staging/comedi/drivers/das800.c | 2 +- drivers/staging/comedi/drivers/dmm32at.c | 2 +- drivers/staging/comedi/drivers/dt2811.c | 2 +- drivers/staging/comedi/drivers/dt9812.c | 2 +- drivers/staging/comedi/drivers/gsc_hpdi.c | 4 +- drivers/staging/comedi/drivers/icp_multi.c | 6 +-- drivers/staging/comedi/drivers/me4000.c | 4 +- drivers/staging/comedi/drivers/mpc624.c | 14 +++--- drivers/staging/comedi/drivers/ni_at_a2150.c | 12 ++--- drivers/staging/comedi/drivers/ni_labpc.c | 14 +++--- drivers/staging/comedi/drivers/ni_pcidio.c | 2 +- drivers/staging/comedi/drivers/pcl812.c | 2 +- drivers/staging/comedi/drivers/pcl816.c | 6 +-- drivers/staging/comedi/drivers/pcl818.c | 6 +-- drivers/staging/comedi/drivers/pcmmio.c | 4 +- drivers/staging/comedi/drivers/pcmuio.c | 2 +- drivers/staging/comedi/drivers/quatech_daqp_cs.c | 4 +- drivers/staging/comedi/drivers/rtd520.c | 12 ++--- drivers/staging/comedi/drivers/s626.c | 18 ++++---- drivers/staging/comedi/drivers/usbdux.c | 22 ++++----- drivers/staging/comedi/drivers/usbduxfast.c | 8 ++-- drivers/staging/cptm1217/clearpad_tm1217.c | 2 +- drivers/staging/crystalhd/crystalhd_cmds.c | 2 +- drivers/staging/crystalhd/crystalhd_hw.c | 6 +-- drivers/staging/cxt1e1/musycc.c | 2 +- drivers/staging/cxt1e1/musycc.h | 4 +- drivers/staging/cxt1e1/pmcc4_defs.h | 4 +- drivers/staging/cxt1e1/sbecrc.c | 2 +- drivers/staging/cxt1e1/sbeproc.c | 2 +- drivers/staging/et131x/et1310_address_map.h | 4 +- drivers/staging/et131x/et1310_phy.h | 2 +- drivers/staging/et131x/et1310_rx.c | 2 +- drivers/staging/et131x/et131x_isr.c | 2 +- drivers/staging/et131x/et131x_netdev.c | 2 +- drivers/staging/ft1000/ft1000-pcmcia/ft1000_dev.h | 4 +- drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c | 44 +++++++++--------- .../staging/ft1000/ft1000-usb/ft1000_download.c | 8 ++-- drivers/staging/ft1000/ft1000-usb/ft1000_hw.c | 16 +++---- drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h | 2 +- drivers/staging/ft1000/ft1000-usb/ft1000_usb.h | 2 +- drivers/staging/generic_serial/generic_serial.c | 2 +- drivers/staging/generic_serial/rio/map.h | 2 +- drivers/staging/generic_serial/rio/rioboot.c | 8 ++-- drivers/staging/generic_serial/rio/riocmd.c | 2 +- drivers/staging/generic_serial/rio/rioroute.c | 4 +- drivers/staging/generic_serial/rio/riotty.c | 4 +- drivers/staging/generic_serial/sx.c | 8 ++-- drivers/staging/gma500/psb_drm.h | 2 +- drivers/staging/gma500/psb_drv.c | 2 +- drivers/staging/gma500/psb_intel_bios.c | 2 +- drivers/staging/gma500/psb_intel_sdvo.c | 2 +- drivers/staging/gma500/psb_intel_sdvo_regs.h | 2 +- drivers/staging/gma500/psb_ttm_fence_user.h | 2 +- drivers/staging/go7007/go7007.txt | 2 +- drivers/staging/hv/blkvsc_drv.c | 2 +- drivers/staging/hv/channel_mgmt.c | 2 +- drivers/staging/hv/hv.c | 2 +- drivers/staging/hv/hv_api.h | 4 +- drivers/staging/hv/hv_kvp.h | 2 +- drivers/staging/hv/hv_util.c | 2 +- drivers/staging/hv/rndis_filter.c | 2 +- drivers/staging/hv/tools/hv_kvp_daemon.c | 2 +- drivers/staging/iio/Documentation/iio_utils.h | 2 +- drivers/staging/iio/accel/adis16201.h | 2 +- drivers/staging/iio/accel/adis16203.h | 2 +- drivers/staging/iio/accel/adis16204.h | 2 +- drivers/staging/iio/accel/adis16209.h | 2 +- drivers/staging/iio/accel/adis16220.h | 2 +- drivers/staging/iio/accel/adis16240.h | 2 +- drivers/staging/iio/accel/lis3l02dq.h | 26 +++++------ drivers/staging/iio/accel/lis3l02dq_core.c | 2 +- drivers/staging/iio/accel/lis3l02dq_ring.c | 4 +- drivers/staging/iio/accel/sca3000.h | 4 +- drivers/staging/iio/accel/sca3000_ring.c | 2 +- drivers/staging/iio/adc/ad7298_ring.c | 2 +- drivers/staging/iio/adc/ad7476_ring.c | 2 +- drivers/staging/iio/adc/ad7887_ring.c | 2 +- drivers/staging/iio/adc/ad799x_core.c | 2 +- drivers/staging/iio/adc/ad799x_ring.c | 2 +- drivers/staging/iio/adc/max1363_core.c | 4 +- drivers/staging/iio/adc/max1363_ring.c | 2 +- drivers/staging/iio/chrdev.h | 6 +-- drivers/staging/iio/gyro/adis16060_core.c | 2 +- drivers/staging/iio/gyro/adis16080_core.c | 2 +- drivers/staging/iio/gyro/adis16260.h | 2 +- drivers/staging/iio/iio.h | 2 +- drivers/staging/iio/imu/adis16300.h | 2 +- drivers/staging/iio/imu/adis16350.h | 2 +- drivers/staging/iio/imu/adis16400.h | 2 +- drivers/staging/iio/industrialio-core.c | 2 +- drivers/staging/iio/meter/ade7753.h | 2 +- drivers/staging/iio/meter/ade7754.h | 2 +- drivers/staging/iio/meter/ade7758.h | 2 +- drivers/staging/iio/meter/ade7759.h | 2 +- drivers/staging/iio/meter/ade7854.h | 2 +- drivers/staging/iio/ring_generic.h | 2 +- drivers/staging/intel_sst/TODO | 2 +- drivers/staging/intel_sst/intel_sst.c | 4 +- .../staging/intel_sst/intel_sst_app_interface.c | 16 +++---- .../staging/intel_sst/intel_sst_drv_interface.c | 2 +- drivers/staging/intel_sst/intel_sst_dsp.c | 4 +- drivers/staging/intel_sst/intel_sst_fw_ipc.h | 2 +- drivers/staging/intel_sst/intel_sst_stream.c | 2 +- .../staging/intel_sst/intel_sst_stream_encoded.c | 2 +- drivers/staging/intel_sst/intelmid.c | 2 +- drivers/staging/intel_sst/intelmid.h | 2 +- drivers/staging/keucr/init.c | 4 +- drivers/staging/keucr/smilmain.c | 8 ++-- drivers/staging/keucr/smilsub.c | 6 +-- drivers/staging/lirc/lirc_ene0100.h | 4 +- drivers/staging/memrar/memrar_handler.c | 2 +- drivers/staging/msm/mdp4_overlay.c | 2 +- drivers/staging/msm/mdp_ppp_dq.c | 2 +- drivers/staging/msm/msm_fb.c | 6 +-- drivers/staging/octeon/cvmx-cmd-queue.h | 2 +- drivers/staging/octeon/cvmx-fpa.h | 2 +- drivers/staging/octeon/cvmx-helper-board.h | 2 +- drivers/staging/octeon/cvmx-helper-util.c | 2 +- drivers/staging/octeon/cvmx-helper.c | 2 +- drivers/staging/octeon/cvmx-mdio.h | 2 +- drivers/staging/octeon/cvmx-pko.h | 4 +- drivers/staging/octeon/cvmx-pow.h | 12 ++--- drivers/staging/octeon/ethernet-util.h | 2 +- drivers/staging/olpc_dcon/olpc_dcon_xo_1.c | 2 +- drivers/staging/pohmelfs/crypto.c | 2 +- drivers/staging/quatech_usb2/quatech_usb2.c | 12 ++--- drivers/staging/rt2860/chip/rtmp_phy.h | 2 +- drivers/staging/rt2860/common/ba_action.c | 4 +- drivers/staging/rt2860/common/cmm_aes.c | 2 +- drivers/staging/rt2860/common/cmm_cfg.c | 2 +- drivers/staging/rt2860/common/cmm_data.c | 4 +- drivers/staging/rt2860/common/cmm_data_pci.c | 6 +-- drivers/staging/rt2860/common/cmm_data_usb.c | 6 +-- drivers/staging/rt2860/common/cmm_mac_pci.c | 2 +- drivers/staging/rt2860/common/cmm_sanity.c | 4 +- drivers/staging/rt2860/common/cmm_sync.c | 2 +- drivers/staging/rt2860/common/cmm_wpa.c | 4 +- drivers/staging/rt2860/common/mlme.c | 16 +++---- drivers/staging/rt2860/common/rtmp_init.c | 14 +++--- drivers/staging/rt2860/common/spectrum.c | 12 ++--- drivers/staging/rt2860/mlme.h | 8 ++-- drivers/staging/rt2860/rt_linux.c | 2 +- drivers/staging/rt2860/rt_pci_rbus.c | 2 +- drivers/staging/rt2860/rtmp.h | 4 +- drivers/staging/rt2860/sta_ioctl.c | 2 +- drivers/staging/rt2870/common/rtusb_bulk.c | 6 +-- drivers/staging/rt2870/common/rtusb_data.c | 2 +- drivers/staging/rtl8187se/ieee80211/ieee80211.h | 6 +-- .../rtl8187se/ieee80211/ieee80211_softmac.c | 2 +- drivers/staging/rtl8187se/r8180_core.c | 4 +- drivers/staging/rtl8187se/r8180_dm.c | 4 +- drivers/staging/rtl8187se/r8180_rtl8225z2.c | 2 +- drivers/staging/rtl8187se/r8185b_init.c | 2 +- drivers/staging/rtl8192e/ieee80211/ieee80211.h | 8 ++-- drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c | 2 +- .../staging/rtl8192e/ieee80211/ieee80211_softmac.c | 4 +- drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h | 2 +- .../staging/rtl8192e/ieee80211/rtl819x_HTProc.c | 8 ++-- drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h | 2 +- .../staging/rtl8192e/ieee80211/rtl819x_TSProc.c | 2 +- drivers/staging/rtl8192e/r819xE_phy.c | 6 +-- drivers/staging/rtl8192u/ieee80211/ieee80211.h | 8 ++-- drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c | 2 +- .../staging/rtl8192u/ieee80211/ieee80211_softmac.c | 4 +- drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h | 2 +- .../staging/rtl8192u/ieee80211/rtl819x_HTProc.c | 8 ++-- drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h | 2 +- .../staging/rtl8192u/ieee80211/rtl819x_TSProc.c | 2 +- drivers/staging/rtl8192u/ieee80211/scatterwalk.c | 2 +- drivers/staging/rtl8192u/r8192U_core.c | 6 +-- drivers/staging/rtl8192u/r819xU_HTType.h | 2 +- drivers/staging/rtl8192u/r819xU_phy.c | 6 +-- drivers/staging/rtl8712/rtl871x_cmd.h | 2 +- drivers/staging/rtl8712/rtl871x_led.h | 4 +- drivers/staging/rtl8712/rtl871x_mlme.c | 6 +-- drivers/staging/rtl8712/rtl871x_mlme.h | 2 +- drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h | 2 +- drivers/staging/rtl8712/usb_halinit.c | 2 +- drivers/staging/rts_pstor/rtsx_chip.h | 10 ++-- drivers/staging/rts_pstor/rtsx_scsi.h | 2 +- drivers/staging/rts_pstor/sd.c | 2 +- drivers/staging/sep/sep_driver.c | 10 ++-- drivers/staging/sep/sep_driver_config.h | 4 +- drivers/staging/slicoss/README | 2 +- drivers/staging/sm7xx/smtcfb.c | 4 +- drivers/staging/speakup/keyhelp.c | 2 +- drivers/staging/speakup/spkguide.txt | 2 +- drivers/staging/spectra/ffsport.c | 4 +- drivers/staging/spectra/flash.c | 6 +-- drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c | 20 ++++---- drivers/staging/tidspbridge/core/_tiomap.h | 2 +- drivers/staging/tidspbridge/core/chnl_sm.c | 2 +- drivers/staging/tidspbridge/dynload/cload.c | 2 +- drivers/staging/tidspbridge/hw/hw_mmu.c | 6 +-- .../tidspbridge/include/dspbridge/_chnl_sm.h | 4 +- .../staging/tidspbridge/include/dspbridge/clk.h | 6 +-- .../staging/tidspbridge/include/dspbridge/cmm.h | 2 +- .../staging/tidspbridge/include/dspbridge/cod.h | 2 +- .../staging/tidspbridge/include/dspbridge/dev.h | 2 +- .../staging/tidspbridge/include/dspbridge/drv.h | 6 +-- .../tidspbridge/include/dspbridge/dspdefs.h | 14 +++--- .../staging/tidspbridge/include/dspbridge/mgr.h | 4 +- .../staging/tidspbridge/include/dspbridge/node.h | 2 +- .../staging/tidspbridge/include/dspbridge/proc.h | 6 +-- .../staging/tidspbridge/include/dspbridge/pwr.h | 8 ++-- drivers/staging/tidspbridge/pmgr/dev.c | 6 +-- drivers/staging/tidspbridge/rmgr/drv.c | 2 +- drivers/staging/tidspbridge/rmgr/nldr.c | 6 +-- drivers/staging/tidspbridge/rmgr/proc.c | 4 +- drivers/staging/tm6000/tm6000-video.c | 2 +- drivers/staging/tty/cd1865.h | 2 +- drivers/staging/tty/epca.c | 16 +++---- drivers/staging/tty/ip2/i2hw.h | 4 +- drivers/staging/tty/ip2/i2lib.c | 8 ++-- drivers/staging/tty/ip2/ip2main.c | 2 +- drivers/staging/tty/specialix.c | 4 +- drivers/staging/tty/specialix_io8.h | 4 +- drivers/staging/usbip/vhci_hcd.c | 2 +- drivers/staging/vme/bridges/vme_ca91cx42.c | 6 +-- drivers/staging/vme/bridges/vme_tsi148.c | 4 +- drivers/staging/vme/bridges/vme_tsi148.h | 8 ++-- drivers/staging/vme/vme_api.txt | 6 +-- drivers/staging/vt6655/card.c | 2 +- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6655/wcmd.c | 2 +- drivers/staging/vt6655/wmgr.h | 4 +- drivers/staging/vt6656/rxtx.c | 2 +- drivers/staging/vt6656/wcmd.c | 4 +- drivers/staging/vt6656/wmgr.h | 4 +- .../staging/westbridge/astoria/api/src/cyasdma.c | 2 +- .../westbridge/astoria/api/src/cyaslep2pep.c | 2 +- .../westbridge/astoria/api/src/cyaslowlevel.c | 2 +- .../staging/westbridge/astoria/api/src/cyasmisc.c | 6 +-- .../staging/westbridge/astoria/api/src/cyasmtp.c | 4 +- .../westbridge/astoria/api/src/cyasstorage.c | 6 +-- .../staging/westbridge/astoria/api/src/cyasusb.c | 4 +- .../arch/arm/mach-omap2/cyashalomap_kernel.c | 12 ++--- .../cyashalomap_kernel.h | 2 +- .../westbridge-omap3-pnand-hal/cyasmemmap.h | 4 +- .../westbridge/astoria/block/cyasblkdev_queue.c | 2 +- .../astoria/include/linux/westbridge/cyasdevice.h | 6 +-- .../astoria/include/linux/westbridge/cyasdma.h | 10 ++-- .../astoria/include/linux/westbridge/cyaserr.h | 4 +- .../astoria/include/linux/westbridge/cyashaldoc.h | 2 +- .../astoria/include/linux/westbridge/cyasintr.h | 2 +- .../astoria/include/linux/westbridge/cyasmisc.h | 8 ++-- .../include/linux/westbridge/cyasprotocol.h | 4 +- .../astoria/include/linux/westbridge/cyasstorage.h | 34 +++++++------- .../astoria/include/linux/westbridge/cyasusb.h | 40 ++++++++-------- drivers/staging/winbond/mds.c | 2 +- drivers/staging/wlags49_h2/README.ubuntu | 2 +- drivers/staging/wlags49_h2/TODO | 4 +- drivers/staging/wlags49_h2/hcf.c | 24 +++++----- drivers/staging/wlags49_h2/hcfdef.h | 2 +- drivers/staging/wlags49_h2/wl_wext.c | 6 +-- drivers/staging/wlags49_h25/TODO | 4 +- drivers/staging/wlan-ng/prism2sta.c | 2 +- drivers/staging/xgifb/vb_setmode.c | 2 +- drivers/staging/xgifb/vgatypes.h | 2 +- drivers/target/target_core_alua.c | 10 ++-- drivers/target/target_core_device.c | 2 +- drivers/target/target_core_fabric_lib.c | 2 +- drivers/target/target_core_file.c | 2 +- drivers/target/target_core_pr.c | 6 +-- drivers/target/target_core_transport.c | 14 +++--- drivers/target/target_core_ua.c | 4 +- drivers/telephony/ixj.c | 8 ++-- drivers/telephony/ixj.h | 2 +- drivers/tty/hvc/hvc_iucv.c | 4 +- drivers/tty/hvc/hvc_vio.c | 2 +- drivers/tty/hvc/hvcs.c | 8 ++-- drivers/tty/mxser.h | 2 +- drivers/tty/n_gsm.c | 10 ++-- drivers/tty/nozomi.c | 2 +- drivers/tty/rocket.c | 4 +- drivers/tty/serial/8250.c | 2 +- drivers/tty/serial/8250_pci.c | 2 +- drivers/tty/serial/amba-pl011.c | 2 +- drivers/tty/serial/icom.c | 2 +- drivers/tty/serial/imx.c | 2 +- drivers/tty/serial/ip22zilog.c | 2 +- drivers/tty/serial/jsm/jsm.h | 2 +- drivers/tty/serial/jsm/jsm_neo.c | 4 +- drivers/tty/serial/max3107.h | 2 +- drivers/tty/serial/mrst_max3110.c | 2 +- drivers/tty/serial/mrst_max3110.h | 2 +- drivers/tty/serial/msm_serial_hs.c | 4 +- drivers/tty/serial/omap-serial.c | 2 +- drivers/tty/serial/pmac_zilog.c | 6 +-- drivers/tty/serial/samsung.c | 4 +- drivers/tty/serial/sh-sci.c | 2 +- drivers/tty/serial/sn_console.c | 4 +- drivers/tty/serial/sunzilog.c | 2 +- drivers/tty/synclink.c | 10 ++-- drivers/tty/synclink_gt.c | 2 +- drivers/tty/synclinkmp.c | 10 ++-- drivers/tty/tty_io.c | 8 ++-- drivers/tty/tty_ioctl.c | 6 +-- drivers/tty/vt/vt.c | 2 +- drivers/uio/uio_pruss.c | 2 +- drivers/usb/atm/ueagle-atm.c | 8 ++-- drivers/usb/c67x00/c67x00-drv.c | 2 +- drivers/usb/c67x00/c67x00-hcd.h | 2 +- drivers/usb/c67x00/c67x00-sched.c | 2 +- drivers/usb/class/cdc-acm.h | 2 +- drivers/usb/class/usbtmc.c | 2 +- drivers/usb/core/hcd.c | 2 +- drivers/usb/core/hub.c | 2 +- drivers/usb/early/ehci-dbgp.c | 2 +- drivers/usb/gadget/amd5536udc.c | 14 +++--- drivers/usb/gadget/amd5536udc.h | 2 +- drivers/usb/gadget/at91_udc.c | 2 +- drivers/usb/gadget/composite.c | 6 +-- drivers/usb/gadget/f_audio.c | 2 +- drivers/usb/gadget/f_ncm.c | 2 +- drivers/usb/gadget/fsl_qe_udc.h | 6 +-- drivers/usb/gadget/fsl_udc_core.c | 6 +-- drivers/usb/gadget/fsl_usb2_udc.h | 4 +- drivers/usb/gadget/gmidi.c | 2 +- drivers/usb/gadget/langwell_udc.c | 2 +- drivers/usb/gadget/mv_udc_core.c | 6 +-- drivers/usb/gadget/net2280.c | 2 +- drivers/usb/gadget/nokia.c | 2 +- drivers/usb/gadget/printer.c | 2 +- drivers/usb/gadget/pxa27x_udc.c | 12 ++--- drivers/usb/gadget/s3c-hsotg.c | 18 ++++---- drivers/usb/host/Kconfig | 2 +- drivers/usb/host/ehci.h | 2 +- drivers/usb/host/fhci-hcd.c | 2 +- drivers/usb/host/fhci-tds.c | 8 ++-- drivers/usb/host/fhci.h | 4 +- drivers/usb/host/imx21-hcd.c | 2 +- drivers/usb/host/isp116x.h | 2 +- drivers/usb/host/isp1362-hcd.c | 2 +- drivers/usb/host/ohci-hcd.c | 2 +- drivers/usb/host/oxu210hp-hcd.c | 4 +- drivers/usb/host/whci/qset.c | 2 +- drivers/usb/host/xhci.c | 4 +- drivers/usb/host/xhci.h | 2 +- drivers/usb/image/microtek.c | 8 ++-- drivers/usb/misc/iowarrior.c | 2 +- drivers/usb/otg/isp1301_omap.c | 2 +- drivers/usb/otg/langwell_otg.c | 4 +- drivers/usb/serial/aircable.c | 4 +- drivers/usb/serial/cp210x.c | 2 +- drivers/usb/serial/cypress_m8.c | 2 +- drivers/usb/serial/ftdi_sio.c | 2 +- drivers/usb/serial/io_edgeport.c | 2 +- drivers/usb/serial/io_edgeport.h | 2 +- drivers/usb/serial/io_ti.c | 2 +- drivers/usb/serial/opticon.c | 2 +- drivers/usb/storage/ene_ub6250.c | 4 +- drivers/usb/storage/isd200.c | 2 +- drivers/usb/storage/scsiglue.c | 2 +- drivers/usb/storage/shuttle_usbat.c | 2 +- drivers/usb/wusbcore/crypto.c | 4 +- drivers/usb/wusbcore/reservation.c | 2 +- drivers/usb/wusbcore/rh.c | 2 +- drivers/usb/wusbcore/wa-rpipe.c | 2 +- drivers/usb/wusbcore/wa-xfer.c | 8 ++-- drivers/usb/wusbcore/wusbhc.h | 2 +- drivers/uwb/driver.c | 2 +- drivers/uwb/drp.c | 6 +-- drivers/uwb/lc-rc.c | 2 +- drivers/uwb/reset.c | 2 +- drivers/uwb/umc-dev.c | 2 +- drivers/video/atmel_lcdfb.c | 2 +- drivers/video/aty/atyfb_base.c | 4 +- drivers/video/aty/mach64_cursor.c | 2 +- drivers/video/au1200fb.c | 2 +- drivers/video/backlight/corgi_lcd.c | 2 +- drivers/video/backlight/locomolcd.c | 2 +- drivers/video/bfin_adv7393fb.h | 24 +++++----- drivers/video/console/font_mini_4x6.c | 2 +- drivers/video/da8xx-fb.c | 2 +- drivers/video/display/display-sysfs.c | 2 +- drivers/video/ep93xx-fb.c | 2 +- drivers/video/fbsysfs.c | 2 +- drivers/video/fm2fb.c | 2 +- drivers/video/fsl-diu-fb.c | 2 +- drivers/video/gbefb.c | 2 +- drivers/video/geode/lxfb.h | 2 +- drivers/video/i810/i810_accel.c | 2 +- drivers/video/kyro/STG4000OverlayDevice.c | 2 +- drivers/video/kyro/STG4000Reg.h | 2 +- drivers/video/matrox/matroxfb_DAC1064.h | 2 +- drivers/video/matrox/matroxfb_Ti3026.c | 4 +- drivers/video/matrox/matroxfb_base.c | 2 +- drivers/video/matrox/matroxfb_base.h | 2 +- drivers/video/nuc900fb.h | 2 +- drivers/video/omap/Kconfig | 2 +- drivers/video/omap2/dss/hdmi.c | 2 +- drivers/video/pxa3xx-gcu.c | 2 +- drivers/video/savage/savagefb.h | 2 +- drivers/video/savage/savagefb_driver.c | 4 +- drivers/video/sm501fb.c | 4 +- drivers/video/sstfb.c | 8 ++-- drivers/video/sticore.h | 2 +- drivers/video/tdfxfb.c | 18 ++++---- drivers/video/tmiofb.c | 2 +- drivers/video/udlfb.c | 2 +- drivers/video/vga16fb.c | 2 +- drivers/video/via/via_utility.c | 2 +- drivers/video/via/via_utility.h | 2 +- drivers/video/via/viafbdev.c | 2 +- drivers/video/w100fb.c | 2 +- drivers/w1/masters/omap_hdq.c | 2 +- drivers/watchdog/Kconfig | 2 +- drivers/watchdog/Makefile | 4 +- drivers/watchdog/acquirewdt.c | 2 +- drivers/watchdog/pc87413_wdt.c | 2 +- drivers/watchdog/sbc7240_wdt.c | 2 +- drivers/watchdog/sch311x_wdt.c | 2 +- drivers/watchdog/shwdt.c | 2 +- drivers/watchdog/smsc37b787_wdt.c | 2 +- drivers/watchdog/sp805_wdt.c | 2 +- drivers/xen/events.c | 4 +- 1370 files changed, 2679 insertions(+), 2679 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index d1d484d4a06a..f703b2881153 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -241,7 +241,7 @@ static inline int ghes_severity(int severity) case CPER_SEV_FATAL: return GHES_SEV_PANIC; default: - /* Unkown, go panic */ + /* Unknown, go panic */ return GHES_SEV_PANIC; } } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index fa84e9744330..ad3501739563 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -1164,7 +1164,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, */ if (!match_pr->flags.throttling) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Throttling Controll is unsupported " + "Throttling Control is unsupported " "on CPU %d\n", i)); continue; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 31e9e10f657e..ec574fc8fbc6 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -1354,7 +1354,7 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video, status = acpi_video_bus_get_one_device(dev, video); if (ACPI_FAILURE(status)) { printk(KERN_WARNING PREFIX - "Cant attach device\n"); + "Can't attach device\n"); continue; } } @@ -1373,7 +1373,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) acpi_video_device_notify); if (ACPI_FAILURE(status)) { printk(KERN_WARNING PREFIX - "Cant remove video notify handler\n"); + "Can't remove video notify handler\n"); } if (device->backlight) { backlight_device_unregister(device->backlight); diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 6d2bb2524b6e..821040503154 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -760,7 +760,7 @@ int amba_request_regions(struct amba_device *dev, const char *name) } /** - * amba_release_regions - release mem regions assoicated with device + * amba_release_regions - release mem regions associated with device * @dev: amba_device structure for device * * Release regions claimed by a successful call to amba_request_regions. diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e62f693be8ea..39d829cd82dd 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -926,7 +926,7 @@ static bool ahci_broken_suspend(struct pci_dev *pdev) /* * Acer eMachines G725 has the same problem. BIOS * V1.03 is known to be broken. V3.04 is known to - * work. Inbetween, there are V1.06, V2.06 and V3.03 + * work. Between, there are V1.06, V2.06 and V3.03 * that we don't have much idea about. For now, * blacklist anything older than V3.04. * diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index ccaf08122058..39865009c251 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -225,7 +225,7 @@ enum { /* em_ctl bits */ EM_CTL_RST = (1 << 9), /* Reset */ EM_CTL_TM = (1 << 8), /* Transmit Message */ - EM_CTL_MR = (1 << 0), /* Message Recieved */ + EM_CTL_MR = (1 << 0), /* Message Received */ EM_CTL_ALHD = (1 << 26), /* Activity LED */ EM_CTL_XMT = (1 << 25), /* Transmit Only */ EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ @@ -281,7 +281,7 @@ struct ahci_port_priv { }; struct ahci_host_priv { - void __iomem * mmio; /* bus-independant mem map */ + void __iomem * mmio; /* bus-independent mem map */ unsigned int flags; /* AHCI_HFLAG_* */ u32 cap; /* cap to use */ u32 cap2; /* cap2 to use */ diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index cdec4ab3b159..0bc3fd6c3fdb 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -38,16 +38,16 @@ * Hardware documentation available at http://developer.intel.com/ * * Documentation - * Publically available from Intel web site. Errata documentation - * is also publically available. As an aide to anyone hacking on this + * Publicly available from Intel web site. Errata documentation + * is also publicly available. As an aide to anyone hacking on this * driver the list of errata that are relevant is below, going back to * PIIX4. Older device documentation is now a bit tricky to find. * * The chipsets all follow very much the same design. The original Triton - * series chipsets do _not_ support independant device timings, but this + * series chipsets do _not_ support independent device timings, but this * is fixed in Triton II. With the odd mobile exception the chips then * change little except in gaining more modes until SATA arrives. This - * driver supports only the chips with independant timing (that is those + * driver supports only the chips with independent timing (that is those * with SITRE and the 0x44 timing register). See pata_oldpiix and pata_mpiix * for the early chip drivers. * @@ -122,7 +122,7 @@ enum { P2 = 2, /* port 2 */ P3 = 3, /* port 3 */ IDE = -1, /* IDE */ - NA = -2, /* not avaliable */ + NA = -2, /* not available */ RV = -3, /* reserved */ PIIX_AHCI_DEVICE = 6, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b91e19cab102..423c0a6952b2 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5340,7 +5340,7 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg) * * Resume @host. Actual operation is performed by EH. This * function requests EH to perform PM operations and returns. - * Note that all resume operations are performed parallely. + * Note that all resume operations are performed parallelly. * * LOCKING: * Kernel thread context (may sleep). diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index df3f3140c9c7..88cd22fa65cd 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -771,7 +771,7 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) /* process port suspend request */ ata_eh_handle_port_suspend(ap); - /* Exception might have happend after ->error_handler + /* Exception might have happened after ->error_handler * recovered the port but before this point. Repeat * EH in such case. */ @@ -1742,7 +1742,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) * * Analyze taskfile of @qc and further determine cause of * failure. This function also requests ATAPI sense data if - * avaliable. + * available. * * LOCKING: * Kernel thread context (may sleep). @@ -1893,7 +1893,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) * occurred during last 5 mins, NCQ_OFF. * * 3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors - * ocurred during last 5 mins, FALLBACK_TO_PIO + * occurred during last 5 mins, FALLBACK_TO_PIO * * 4. If more than 3 TOUT_HSM or UNK_DEV errors occurred * during last 10 mins, NCQ_OFF. @@ -2577,7 +2577,7 @@ int ata_eh_reset(struct ata_link *link, int classify, if (link->flags & ATA_LFLAG_NO_SRST) softreset = NULL; - /* make sure each reset attemp is at least COOL_DOWN apart */ + /* make sure each reset attempt is at least COOL_DOWN apart */ if (ehc->i.flags & ATA_EHI_DID_RESET) { now = jiffies; WARN_ON(time_after(ehc->last_reset, now)); @@ -2736,7 +2736,7 @@ int ata_eh_reset(struct ata_link *link, int classify, if (!reset) { ata_link_printk(link, KERN_ERR, "follow-up softreset required " - "but no softreset avaliable\n"); + "but no softreset available\n"); failed_link = link; rc = -EINVAL; goto fail; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a83419991357..e2f57e9e12f0 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -999,7 +999,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) * @qc: Command that we are erroring out * * Generate sense block for a failed ATA command @qc. Descriptor - * format is used to accomodate LBA48 block address. + * format is used to accommodate LBA48 block address. * * LOCKING: * None. diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index cf7acbc0cfcb..f8380ce0f4d1 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2839,7 +2839,7 @@ unsigned int ata_bmdma_port_intr(struct ata_port *ap, struct ata_queued_cmd *qc) bmdma_stopped = true; if (unlikely(host_stat & ATA_DMA_ERR)) { - /* error when transfering data to/from memory */ + /* error when transferring data to/from memory */ qc->err_mask |= AC_ERR_HOST_BUS; ap->hsm_task_state = HSM_ST_ERR; } @@ -3032,7 +3032,7 @@ void ata_bmdma_start(struct ata_queued_cmd *qc) * Or maybe I'm just being paranoid. * * FIXME: The posting of this write means I/O starts are - * unneccessarily delayed for MMIO + * unnecessarily delayed for MMIO */ } EXPORT_SYMBOL_GPL(ata_bmdma_start); diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 620a07cabe31..b0975a5ad8c4 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -11,7 +11,7 @@ * Power management on ports * * - * Documentation publically available. + * Documentation publicly available. */ #include diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 65cee74605b4..719bb73a73e0 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -385,7 +385,7 @@ static inline int wait4buf(struct arasan_cf_dev *acdev) return -ETIMEDOUT; } - /* Check if PIO Error interrupt has occured */ + /* Check if PIO Error interrupt has occurred */ if (acdev->dma_status & ATA_DMA_ERR) return -EAGAIN; @@ -450,7 +450,7 @@ static int sg_xfer(struct arasan_cf_dev *acdev, struct scatterlist *sg) /* * For each sg: * MAX_XFER_COUNT data will be transferred before we get transfer - * complete interrupt. Inbetween after FIFO_SIZE data + * complete interrupt. Between after FIFO_SIZE data * buffer available interrupt will be generated. At this time we will * fill FIFO again: max FIFO_SIZE data. */ @@ -463,7 +463,7 @@ static int sg_xfer(struct arasan_cf_dev *acdev, struct scatterlist *sg) acdev->vbase + XFER_CTR); spin_unlock_irqrestore(&acdev->host->lock, flags); - /* continue dma xfers untill current sg is completed */ + /* continue dma xfers until current sg is completed */ while (xfer_cnt) { /* wait for read to complete */ if (!write) { @@ -563,7 +563,7 @@ static void data_xfer(struct work_struct *work) chan_request_fail: spin_lock_irqsave(&acdev->host->lock, flags); - /* error when transfering data to/from memory */ + /* error when transferring data to/from memory */ qc->err_mask |= AC_ERR_HOST_BUS; qc->ap->hsm_task_state = HSM_ST_ERR; diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index e0b58b8dfe6f..ea64967000ff 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1342,7 +1342,7 @@ static unsigned int bfin_ata_host_intr(struct ata_port *ap, ap->ops->bmdma_stop(qc); if (unlikely(host_stat & ATA_DMA_ERR)) { - /* error when transfering data to/from memory */ + /* error when transferring data to/from memory */ qc->err_mask |= AC_ERR_HOST_BUS; ap->hsm_task_state = HSM_ST_ERR; } diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 030952f1f97c..e3254fcff0f1 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -29,7 +29,7 @@ * General Public License for more details. * * Documentation: - * Not publically available. + * Not publicly available. */ #include #include diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index b21f0021f54a..d8d9c5807740 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -15,7 +15,7 @@ * with PCI IDE and also that we do not disable the device when our driver is * unloaded (as it has many other functions). * - * The driver conciously keeps this logic internally to avoid pushing quirky + * The driver consciously keeps this logic internally to avoid pushing quirky * PATA history into the clean libata layer. * * Thinkpad specific note: If you boot an MPIIX using a thinkpad with a PCMCIA diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 4a454a88aa9d..4d04471794b6 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -112,7 +112,7 @@ static int rz1000_reinit_one(struct pci_dev *pdev) if (rc) return rc; - /* If this fails on resume (which is a "cant happen" case), we + /* If this fails on resume (which is a "can't happen" case), we must stop as any progress risks data loss */ if (rz1000_fifo_disable(pdev)) panic("rz1000 fifo"); diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 00eefbd84b33..118787caa93f 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -11,7 +11,7 @@ * * May be copied or modified under the terms of the GNU General Public License * - * Documentation publically available. + * Documentation publicly available. * * If you have strange problems with nVidia chipset systems please * see the SI support documentation and update your system BIOS @@ -43,7 +43,7 @@ * * Turn a config register offset into the right address in either * PCI space or MMIO space to access the control register in question - * Thankfully this is a configuration operation so isnt performance + * Thankfully this is a configuration operation so isn't performance * criticial. */ diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index c04abc393fc5..be08ff92db17 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -331,7 +331,7 @@ static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev) if (adev->dma_mode < XFER_UDMA_0) { /* bits 3-0 hold recovery timing bits 8-10 active timing and - the higher bits are dependant on the device */ + the higher bits are dependent on the device */ timing &= ~0x870F; timing |= mwdma_bits[speed]; } else { @@ -371,7 +371,7 @@ static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev) if (adev->dma_mode < XFER_UDMA_0) { /* bits 3-0 hold recovery timing bits 8-10 active timing and - the higher bits are dependant on the device, bit 15 udma */ + the higher bits are dependent on the device, bit 15 udma */ timing &= ~0x870F; timing |= mwdma_bits[speed]; } else { diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 0d1f89e571dd..03b6d69d6197 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -30,7 +30,7 @@ * Loosely based on the piix & svwks drivers. * * Documentation: - * Not publically available. + * Not publicly available. */ #include diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 0f91e583892e..35a71d875d0e 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -42,7 +42,7 @@ enum { /* * SATA-FSL host controller supports a max. of (15+1) direct PRDEs, and - * chained indirect PRDEs upto a max count of 63. + * chained indirect PRDEs up to a max count of 63. * We are allocating an array of 63 PRDEs contiguously, but PRDE#15 will * be setup as an indirect descriptor, pointing to it's next * (contiguous) PRDE. Though chained indirect PRDE arrays are @@ -907,7 +907,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class, ata_msleep(ap, 1); /* - * SATA device enters reset state after receving a Control register + * SATA device enters reset state after receiving a Control register * FIS with SRST bit asserted and it awaits another H2D Control reg. * FIS with SRST bit cleared, then the device does internal diags & * initialization, followed by indicating it's initialization status diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index cd40651e9b72..b52c0519ad0b 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1352,7 +1352,7 @@ static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val) /* * Workaround for 88SX60x1 FEr SATA#26: * - * COMRESETs have to take care not to accidently + * COMRESETs have to take care not to accidentally * put the drive to sleep when writing SCR_CONTROL. * Setting bits 12..15 prevents this problem. * @@ -2044,7 +2044,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc) cw = &pp->crqb[in_index].ata_cmd[0]; - /* Sadly, the CRQB cannot accomodate all registers--there are + /* Sadly, the CRQB cannot accommodate all registers--there are * only 11 bytes...so we must pick and choose required * registers based on the command. So, we drop feature and * hob_feature for [RW] DMA commands, but they are needed for diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 42344e3c686d..f173ef3bfc10 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -2121,7 +2121,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap) host_stat = ap->ops->bmdma_status(ap); if (unlikely(host_stat & ATA_DMA_ERR)) { - /* error when transfering data to/from memory */ + /* error when transferring data to/from memory */ ata_ehi_clear_desc(ehi); ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); ehi->err_mask |= AC_ERR_HOST_BUS; diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 21242c5709a0..54434db15b12 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -582,7 +582,7 @@ static void svia_configure(struct pci_dev *pdev, int board_id) * When host issues HOLD, device may send up to 20DW of data * before acknowledging it with HOLDA and the host should be * able to buffer them in FIFO. Unfortunately, some WD drives - * send upto 40DW before acknowledging HOLD and, in the + * send up to 40DW before acknowledging HOLD and, in the * default configuration, this ends up overflowing vt6421's * FIFO, making the controller abort the transaction with * R_ERR. diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 9f47e8625266..a5fcb1eb862f 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -497,7 +497,7 @@ static void rx_complete (amb_dev * dev, rx_out * rx) { // VC layer stats atomic_inc(&atm_vcc->stats->rx); __net_timestamp(skb); - // end of our responsability + // end of our responsibility atm_vcc->push (atm_vcc, skb); return; diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 049650d42c88..ef7a658312a6 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -1782,7 +1782,7 @@ static int __devinit fs_init (struct fs_dev *dev) write_fs (dev, RAS0, RAS0_DCD_XHLT | (((1 << FS155_VPI_BITS) - 1) * RAS0_VPSEL) | (((1 << FS155_VCI_BITS) - 1) * RAS0_VCSEL)); - /* We can chose the split arbitarily. We might be able to + /* We can chose the split arbitrarily. We might be able to support more. Whatever. This should do for now. */ dev->atm_dev->ci_range.vpi_bits = FS155_VPI_BITS; dev->atm_dev->ci_range.vci_bits = FS155_VCI_BITS; diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h index 7f97c09aaea5..ba34a02b717d 100644 --- a/drivers/atm/fore200e.h +++ b/drivers/atm/fore200e.h @@ -263,7 +263,7 @@ typedef enum opcode { } opcode_t; -/* virtual path / virtual channel identifers */ +/* virtual path / virtual channel identifiers */ typedef struct vpvc { BITFIELD3( @@ -926,7 +926,7 @@ typedef struct fore200e_vcc { #define PCA200E_PCI_LATENCY 0x40 /* maximum slave latenty */ #define PCA200E_PCI_MASTER_CTRL 0x41 /* master control */ -#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continous req threshold */ +#define PCA200E_PCI_THRESHOLD 0x42 /* burst / continuous req threshold */ /* PBI master control register */ diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 24761e1d6642..d58e3fcb9db3 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -169,13 +169,13 @@ static inline void __init show_version (void) { Real Time (cdv and max CDT given) CBR(pcr) pcr bandwidth always available - rtVBR(pcr,scr,mbs) scr bandwidth always available, upto pcr at mbs too + rtVBR(pcr,scr,mbs) scr bandwidth always available, up to pcr at mbs too Non Real Time - nrtVBR(pcr,scr,mbs) scr bandwidth always available, upto pcr at mbs too + nrtVBR(pcr,scr,mbs) scr bandwidth always available, up to pcr at mbs too UBR() - ABR(mcr,pcr) mcr bandwidth always available, upto pcr (depending) too + ABR(mcr,pcr) mcr bandwidth always available, up to pcr (depending) too mbs is max burst size (bucket) pcr and scr have associated cdvt values @@ -944,7 +944,7 @@ static void hrz_close_rx (hrz_dev * dev, u16 vc) { // to be fixed soon, so do not define TAILRECUSRIONWORKS unless you // are sure it does as you may otherwise overflow the kernel stack. -// giving this fn a return value would help GCC, alledgedly +// giving this fn a return value would help GCC, allegedly static void rx_schedule (hrz_dev * dev, int irq) { unsigned int rx_bytes; @@ -1036,7 +1036,7 @@ static void rx_schedule (hrz_dev * dev, int irq) { // VC layer stats atomic_inc(&vcc->stats->rx); __net_timestamp(skb); - // end of our responsability + // end of our responsibility vcc->push (vcc, skb); } } diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index bfb7feee0400..048f99fe6f83 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -3495,7 +3495,7 @@ init_card(struct atm_dev *dev) return -1; } if (dev->phy->ioctl == NULL) { - printk("%s: LT had no IOCTL funtion defined.\n", card->name); + printk("%s: LT had no IOCTL function defined.\n", card->name); deinit_card(card); return -1; } diff --git a/drivers/atm/idt77252.h b/drivers/atm/idt77252.h index f53a43ae2bbe..3a82cc23a053 100644 --- a/drivers/atm/idt77252.h +++ b/drivers/atm/idt77252.h @@ -766,7 +766,7 @@ struct idt77252_dev #define SAR_RCTE_BUFFSTAT_MASK 0x00003000 /* buffer status */ #define SAR_RCTE_EFCI 0x00000800 /* EFCI Congestion flag */ #define SAR_RCTE_CLP 0x00000400 /* Cell Loss Priority flag */ -#define SAR_RCTE_CRC 0x00000200 /* Recieved CRC Error */ +#define SAR_RCTE_CRC 0x00000200 /* Received CRC Error */ #define SAR_RCTE_CELLCNT_MASK 0x000001FF /* cell Count */ #define SAR_RCTE_AAL0 0x00000000 /* AAL types for ALL field */ diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index d80d51b62a1a..1c674a91f146 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -1025,7 +1025,7 @@ static void desc_dbg(IADEV *iadev) { } -/*----------------------------- Recieving side stuff --------------------------*/ +/*----------------------------- Receiving side stuff --------------------------*/ static void rx_excp_rcvd(struct atm_dev *dev) { @@ -1195,7 +1195,7 @@ static void rx_intr(struct atm_dev *dev) if (status & RX_PKT_RCVD) { /* do something */ - /* Basically recvd an interrupt for receving a packet. + /* Basically recvd an interrupt for receiving a packet. A descriptor would have been written to the packet complete queue. Get all the descriptors and set up dma to move the packets till the packet complete queue is empty.. @@ -1855,7 +1855,7 @@ static int open_tx(struct atm_vcc *vcc) return -EINVAL; } if (vcc->qos.txtp.max_pcr > iadev->LineRate) { - IF_CBR(printk("PCR is not availble\n");) + IF_CBR(printk("PCR is not available\n");) return -1; } vc->type = CBR; diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c index 52880c8387d8..4e8ba56f75d3 100644 --- a/drivers/atm/lanai.c +++ b/drivers/atm/lanai.c @@ -1255,7 +1255,7 @@ static inline void lanai_endtx(struct lanai_dev *lanai, /* * Since the "butt register" is a shared resounce on the card we * serialize all accesses to it through this spinlock. This is - * mostly just paranoia sicne the register is rarely "busy" anyway + * mostly just paranoia since the register is rarely "busy" anyway * but is needed for correctness. */ spin_lock(&lanai->endtxlock); @@ -1990,7 +1990,7 @@ static int __devinit lanai_pci_start(struct lanai_dev *lanai) /* * We _can_ use VCI==0 for normal traffic, but only for UBR (or we'll - * get a CBRZERO interrupt), and we can use it only if noone is receiving + * get a CBRZERO interrupt), and we can use it only if no one is receiving * AAL0 traffic (since they will use the same queue) - according to the * docs we shouldn't even use it for AAL0 traffic */ diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c index 49758593a5ba..41ce4bd96813 100644 --- a/drivers/auxdisplay/cfag12864b.c +++ b/drivers/auxdisplay/cfag12864b.c @@ -49,7 +49,7 @@ static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE; module_param(cfag12864b_rate, uint, S_IRUGO); MODULE_PARM_DESC(cfag12864b_rate, - "Refresh rate (hertzs)"); + "Refresh rate (hertz)"); unsigned int cfag12864b_getrate(void) { @@ -60,7 +60,7 @@ unsigned int cfag12864b_getrate(void) * cfag12864b Commands * * E = Enable signal - * Everytime E switch from low to high, + * Every time E switch from low to high, * cfag12864b/ks0108 reads the command/data. * * CS1 = First ks0108controller. diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 54597c859ecb..3172c60d23a9 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -443,7 +443,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) * * Check if the device's run-time PM status allows it to be resumed. Cancel * any scheduled or pending requests. If another resume has been started - * earlier, either return imediately or wait for it to finish, depending on the + * earlier, either return immediately or wait for it to finish, depending on the * RPM_NOWAIT and RPM_ASYNC flags. Similarly, if there's a suspend running in * parallel with this function, either tell the other process to resume after * suspending (deferred_resume) or wait for it to finish. If the RPM_ASYNC diff --git a/drivers/base/sys.c b/drivers/base/sys.c index fbe72da6c414..acde9b5ee131 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -197,7 +197,7 @@ kset_put: } /** - * sysdev_driver_register - Register auxillary driver + * sysdev_driver_register - Register auxiliary driver * @cls: Device class driver belongs to. * @drv: Driver. * @@ -250,7 +250,7 @@ unlock: } /** - * sysdev_driver_unregister - Remove an auxillary driver. + * sysdev_driver_unregister - Remove an auxiliary driver. * @cls: Class driver belongs to. * @drv: Driver. */ @@ -302,7 +302,7 @@ int sysdev_register(struct sys_device *sysdev) * code that should have called us. */ - /* Notify class auxillary drivers */ + /* Notify class auxiliary drivers */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->add) drv->add(sysdev); @@ -335,7 +335,7 @@ void sysdev_unregister(struct sys_device *sysdev) * * Loop over each class of system devices, and the devices in each * of those classes. For each device, we call the shutdown method for - * each driver registered for the device - the auxillaries, + * each driver registered for the device - the auxiliaries, * and the class driver. * * Note: The list is iterated in reverse order, so that we shut down @@ -360,7 +360,7 @@ void sysdev_shutdown(void) struct sysdev_driver *drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call auxillary drivers first */ + /* Call auxiliary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->shutdown) drv->shutdown(sysdev); @@ -385,7 +385,7 @@ static void __sysdev_resume(struct sys_device *dev) WARN_ONCE(!irqs_disabled(), "Interrupts enabled after %pF\n", cls->resume); - /* Call auxillary drivers next. */ + /* Call auxiliary drivers next. */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->resume) drv->resume(dev); @@ -432,7 +432,7 @@ int sysdev_suspend(pm_message_t state) list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* Call auxillary drivers first */ + /* Call auxiliary drivers first */ list_for_each_entry(drv, &cls->drivers, entry) { if (drv->suspend) { ret = drv->suspend(sysdev, state); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 79882104e431..8066d086578a 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -1790,7 +1790,7 @@ static bool DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T unsigned short LogicalDeviceNumber = 0; int ModelNameLength; - /* Get data into dma-able area, then copy into permanant location */ + /* Get data into dma-able area, then copy into permanent location */ if (!DAC960_V2_NewControllerInfo(Controller)) return DAC960_Failure(Controller, "GET CONTROLLER INFO"); memcpy(ControllerInfo, Controller->V2.NewControllerInformation, diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 2a1642bc451d..c6828b68d77b 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -30,7 +30,7 @@ /* We maintain a trivial check sum in our on disk activity log. * With that we can ensure correct operation even when the storage - * device might do a partial (last) sector write while loosing power. + * device might do a partial (last) sector write while losing power. */ struct __packed al_transaction { u32 magic; diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 81030d8d654b..b2699bb2e530 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -622,7 +622,7 @@ DCBP_set_pad_bits(struct p_compressed_bm *p, int n) /* one bitmap packet, including the p_header, * should fit within one _architecture independend_ page. * so we need to use the fixed size 4KiB page size - * most architechtures have used for a long time. + * most architectures have used for a long time. */ #define BM_PACKET_PAYLOAD_BYTES (4096 - sizeof(struct p_header80)) #define BM_PACKET_WORDS (BM_PACKET_PAYLOAD_BYTES/sizeof(long)) @@ -810,7 +810,7 @@ enum { /* global flag bits */ enum { - CREATE_BARRIER, /* next P_DATA is preceeded by a P_BARRIER */ + CREATE_BARRIER, /* next P_DATA is preceded by a P_BARRIER */ SIGNAL_ASENDER, /* whether asender wants to be interrupted */ SEND_PING, /* whether asender should send a ping asap */ @@ -1126,7 +1126,7 @@ struct drbd_conf { int c_sync_rate; /* current resync rate after syncer throttle magic */ struct fifo_buffer rs_plan_s; /* correction values of resync planer */ int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */ - int rs_planed; /* resync sectors already planed */ + int rs_planed; /* resync sectors already planned */ atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */ }; @@ -1144,7 +1144,7 @@ static inline unsigned int mdev_to_minor(struct drbd_conf *mdev) return mdev->minor; } -/* returns 1 if it was successfull, +/* returns 1 if it was successful, * returns 0 if there was no data socket. * so wherever you are going to use the data.socket, e.g. do * if (!drbd_get_data_sock(mdev)) @@ -2079,7 +2079,7 @@ static inline void inc_ap_pending(struct drbd_conf *mdev) /* counts how many resync-related answers we still expect from the peer * increase decrease * C_SYNC_TARGET sends P_RS_DATA_REQUEST (and expects P_RS_DATA_REPLY) - * C_SYNC_SOURCE sends P_RS_DATA_REPLY (and expects P_WRITE_ACK whith ID_SYNCER) + * C_SYNC_SOURCE sends P_RS_DATA_REPLY (and expects P_WRITE_ACK with ID_SYNCER) * (or P_NEG_ACK with ID_SYNCER) */ static inline void inc_rs_pending(struct drbd_conf *mdev) diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index dfc85f32d317..5b525c179f39 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1561,7 +1561,7 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, if (drbd_send_state(mdev)) dev_warn(DEV, "Notified peer that I'm now diskless.\n"); /* corresponding get_ldev in __drbd_set_state - * this may finaly trigger drbd_ldev_destroy. */ + * this may finally trigger drbd_ldev_destroy. */ put_ldev(mdev); } @@ -3706,7 +3706,7 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev) buffer = (struct meta_data_on_disk *)page_address(mdev->md_io_page); if (!drbd_md_sync_page_io(mdev, bdev, bdev->md.md_offset, READ)) { - /* NOTE: cant do normal error processing here as this is + /* NOTE: can't do normal error processing here as this is called BEFORE disk is attached */ dev_err(DEV, "Error while reading metadata.\n"); rv = ERR_IO_MD_DISK; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index fe1564c7d8b6..fd26666c0b08 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -862,7 +862,7 @@ retry: msock->sk->sk_rcvtimeo = mdev->net_conf->ping_int*HZ; /* we don't want delays. - * we use TCP_CORK where apropriate, though */ + * we use TCP_CORK where appropriate, though */ drbd_tcp_nodelay(sock); drbd_tcp_nodelay(msock); diff --git a/drivers/block/drbd/drbd_vli.h b/drivers/block/drbd/drbd_vli.h index fc824006e721..8cb1532a3816 100644 --- a/drivers/block/drbd/drbd_vli.h +++ b/drivers/block/drbd/drbd_vli.h @@ -32,7 +32,7 @@ * the bitmap transfer time can take much too long, * if transmitted in plain text. * - * We try to reduce the transfered bitmap information + * We try to reduce the transferred bitmap information * by encoding runlengths of bit polarity. * * We never actually need to encode a "zero" (runlengths are positive). diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 30ec6b37424e..007c630904c1 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -733,7 +733,7 @@ static int __init hd_init(void) * the BIOS or CMOS. This doesn't work all that well, * since this assumes that this is a primary or secondary * drive, and if we're using this legacy driver, it's - * probably an auxilliary controller added to recover + * probably an auxiliary controller added to recover * legacy data off an ST-506 drive. Either way, it's * definitely safest to have the user explicitly specify * the information. diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index e2ff697697c2..9a5b2a2d616d 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -94,7 +94,7 @@ static const struct vio_error_entry viodasd_err_table[] = { { 0x0204, EIO, "Use Error" }, { 0x0205, EIO, "Release Error" }, { 0x0206, EINVAL, "Invalid Disk" }, - { 0x0207, EBUSY, "Cant Lock" }, + { 0x0207, EBUSY, "Can't Lock" }, { 0x0208, EIO, "Already Locked" }, { 0x0209, EIO, "Already Unlocked" }, { 0x020A, EIO, "Invalid Arg" }, diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 73354b081ed3..645ff765cd12 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -621,7 +621,7 @@ static void ace_fsm_dostate(struct ace_device *ace) ace_dump_mem(ace->cf_id, 512); /* Debug: Dump out disk ID */ if (ace->data_result) { - /* Error occured, disable the disk */ + /* Error occurred, disable the disk */ ace->media_change = 1; set_capacity(ace->gd, 0); dev_err(ace->dev, "error fetching CF id (%i)\n", @@ -801,7 +801,7 @@ static int ace_interrupt_checkstate(struct ace_device *ace) u32 sreg = ace_in32(ace, ACE_STATUS); u16 creg = ace_in(ace, ACE_CTRL); - /* Check for error occurance */ + /* Check for error occurrence */ if ((sreg & (ACE_STATUS_CFGERROR | ACE_STATUS_CFCERROR)) && (creg & ACE_CTRL_ERRORIRQ)) { dev_err(ace->dev, "transfer failure\n"); @@ -1169,7 +1169,7 @@ static int __devinit ace_probe(struct platform_device *dev) irq = dev->resource[i].start; } - /* Call the bus-independant setup code */ + /* Call the bus-independent setup code */ return ace_alloc(&dev->dev, id, physaddr, irq, bus_width); } @@ -1222,7 +1222,7 @@ static int __devinit ace_of_probe(struct platform_device *op) if (of_find_property(op->dev.of_node, "8-bit", NULL)) bus_width = ACE_BUS_WIDTH_8; - /* Call the bus-independant setup code */ + /* Call the bus-independent setup code */ return ace_alloc(&op->dev, id ? be32_to_cpup(id) : 0, physaddr, irq, bus_width); } diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 38595e782d02..7e4b435f79f0 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -207,7 +207,7 @@ static void ll_device_want_to_wakeup(struct hci_uart *hu) /* * This state means that both the host and the BRF chip * have simultaneously sent a wake-up-indication packet. - * Traditionaly, in this case, receiving a wake-up-indication + * Traditionally, in this case, receiving a wake-up-indication * was enough and an additional wake-up-ack wasn't needed. * This has changed with the BRF6350, which does require an * explicit wake-up-ack. Other BRF versions, which do not diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index e2c48a7eccff..514dd8efaf73 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -30,7 +30,7 @@ changelog for the 1.x series, David? 2.00 Dec 2, 1997 -- Erik Andersen - -- New maintainer! As David A. van Leeuwen has been too busy to activly + -- New maintainer! As David A. van Leeuwen has been too busy to actively maintain and improve this driver, I am now carrying on the torch. If you have a problem with this driver, please feel free to contact me. @@ -2520,7 +2520,7 @@ static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi, /* * Ok, this is where problems start. The current interface for the * CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption that - * CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly, while this + * CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunately, while this * is often the case, it is also very common for CDs to have some tracks * with data, and some tracks with audio. Just because I feel like it, * I declare the following to be the best way to cope. If the CD has ANY diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 3e67ddde9e16..923f99df4f1c 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -237,7 +237,7 @@ extern int agp_try_unsupported_boot; long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -/* Chipset independant registers (from AGP Spec) */ +/* Chipset independent registers (from AGP Spec) */ #define AGP_APBASE 0x10 #define AGPSTAT 0x4 diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 45681c0ff3b6..f7e88787af97 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -272,7 +272,7 @@ static void amd_irongate_cleanup(void) * This routine could be implemented by taking the addresses * written to the GATT, and flushing them individually. However * currently it just flushes the whole table. Which is probably - * more efficent, since agp_memory blocks can be a large number of + * more efficient, since agp_memory blocks can be a large number of * entries. */ diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 13acaaf64edb..f02f9b07fd4c 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -229,7 +229,7 @@ static int serverworks_fetch_size(void) * This routine could be implemented by taking the addresses * written to the GATT, and flushing them individually. However * currently it just flushes the whole table. Which is probably - * more efficent, since agp_memory blocks can be a large number of + * more efficient, since agp_memory blocks can be a large number of * entries. */ static void serverworks_tlbflush(struct agp_memory *temp) diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index df67e80019d2..8bc384937401 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -400,7 +400,7 @@ static struct agp_device_ids via_agp_device_ids[] __devinitdata = * the traditional AGP which resides only in chipset. AGP is used * by 3D driver which wasn't available for the VT3336 and VT3364 * generation until now. Unfortunately, by testing, VT3364 works - * but VT3336 doesn't. - explaination from via, just leave this as + * but VT3336 doesn't. - explanation from via, just leave this as * as a placeholder to avoid future patches adding it back in. */ #if 0 diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 0dec5da000ef..2efa176beab0 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -122,7 +122,7 @@ static struct ipmi_recv_msg halt_recv_msg = { /* - * Code to send a message and wait for the reponse. + * Code to send a message and wait for the response. */ static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index d28b484aee45..cc6c9b2546a3 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -339,7 +339,7 @@ static void return_hosed_msg(struct smi_info *smi_info, int cCode) cCode = IPMI_ERR_UNSPECIFIED; /* else use it as is */ - /* Make it a reponse */ + /* Make it a response */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; msg->rsp[2] = cCode; @@ -2927,7 +2927,7 @@ static void return_hosed_msg_badsize(struct smi_info *smi_info) { struct ipmi_smi_msg *msg = smi_info->curr_msg; - /* Make it a reponse */ + /* Make it a response */ msg->rsp[0] = msg->data[0] | 4; msg->rsp[1] = msg->data[1]; msg->rsp[2] = CANNOT_RETURN_REQUESTED_LENGTH; diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h index ba671589f4cb..1a36884c48b5 100644 --- a/drivers/char/mbcs.h +++ b/drivers/char/mbcs.h @@ -36,13 +36,13 @@ #define MBCS_RD_DMA_CTRL 0x0110 /* Read DMA Control */ #define MBCS_RD_DMA_AMO_DEST 0x0118 /* Read DMA AMO Destination */ #define MBCS_RD_DMA_INT_DEST 0x0120 /* Read DMA Interrupt Destination */ -#define MBCS_RD_DMA_AUX_STAT 0x0130 /* Read DMA Auxillary Status */ +#define MBCS_RD_DMA_AUX_STAT 0x0130 /* Read DMA Auxiliary Status */ #define MBCS_WR_DMA_SYS_ADDR 0x0200 /* Write DMA System Address */ #define MBCS_WR_DMA_LOC_ADDR 0x0208 /* Write DMA Local Address */ #define MBCS_WR_DMA_CTRL 0x0210 /* Write DMA Control */ #define MBCS_WR_DMA_AMO_DEST 0x0218 /* Write DMA AMO Destination */ #define MBCS_WR_DMA_INT_DEST 0x0220 /* Write DMA Interrupt Destination */ -#define MBCS_WR_DMA_AUX_STAT 0x0230 /* Write DMA Auxillary Status */ +#define MBCS_WR_DMA_AUX_STAT 0x0230 /* Write DMA Auxiliary Status */ #define MBCS_ALG_AMO_DEST 0x0300 /* Algorithm AMO Destination */ #define MBCS_ALG_INT_DEST 0x0308 /* Algorithm Interrupt Destination */ #define MBCS_ALG_OFFSETS 0x0310 diff --git a/drivers/char/mwave/3780i.h b/drivers/char/mwave/3780i.h index 270431ca7dae..fba6ab1160ce 100644 --- a/drivers/char/mwave/3780i.h +++ b/drivers/char/mwave/3780i.h @@ -122,7 +122,7 @@ typedef struct { typedef struct { unsigned char Dma:3; /* RW: DMA channel selection */ unsigned char NumTransfers:2; /* RW: Maximum # of transfers once being granted the ISA bus */ - unsigned char ReRequest:2; /* RW: Minumum delay between releasing the ISA bus and requesting it again */ + unsigned char ReRequest:2; /* RW: Minimum delay between releasing the ISA bus and requesting it again */ unsigned char MEMCS16:1; /* RW: ISA signal MEMCS16: 0=disabled, 1=enabled */ } DSP_BUSMASTER_CFG_1; diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 8994ce32e6c7..04a480f86c6c 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -75,7 +75,7 @@ int button_add_callback (void (*callback) (void), int count) * with -EINVAL. If there is more than one entry with the same address, * because it searches the list from end to beginning, it will unregister the * last one to be registered first (FILO- First In Last Out). - * Note that this is not neccessarily true if the entries are not submitted + * Note that this is not necessarily true if the entries are not submitted * at the same time, because another driver could have unregistered a callback * between the submissions creating a gap earlier in the list, which would * be filled first at submission time. diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index bcbbc71febb7..90bd01671c70 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -806,7 +806,7 @@ static void monitor_card(unsigned long p) dev->flags1 = 0x01; xoutb(dev->flags1, REG_FLAGS1(iobase)); - /* atr is present (which doesnt mean it's valid) */ + /* atr is present (which doesn't mean it's valid) */ set_bit(IS_ATR_PRESENT, &dev->flags); if (dev->atr[0] == 0x03) str_invert_revert(dev->atr, dev->atr_len); diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index beca80bb9bdb..b575411c69b2 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1290,7 +1290,7 @@ static int startup(MGSLPC_INFO * info, struct tty_struct *tty) /* Allocate and claim adapter resources */ retval = claim_resources(info); - /* perform existance check and diagnostics */ + /* perform existence check and diagnostics */ if ( !retval ) retval = adapter_test(info); @@ -2680,7 +2680,7 @@ static void rx_free_buffers(MGSLPC_INFO *info) static int claim_resources(MGSLPC_INFO *info) { if (rx_alloc_buffers(info) < 0 ) { - printk( "Cant allocate rx buffer %s\n", info->device_name); + printk( "Can't allocate rx buffer %s\n", info->device_name); release_resources(info); return -ENODEV; } diff --git a/drivers/char/random.c b/drivers/char/random.c index 5e29e8031bbc..d4ddeba56682 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -732,7 +732,7 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, size_t nbytes, int min, int rsvd); /* - * This utility inline function is responsible for transfering entropy + * This utility inline function is responsible for transferring entropy * from the primary pool to the secondary extraction pool. We make * sure we pull enough for a 'catastrophic reseed'. */ diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 79e36c878a4c..1ee8ce7d2762 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1241,7 +1241,7 @@ static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, while (check_ioport && check->port1) { if (!request_region(check->port1, sonypi_device.region_size, - "Sony Programable I/O Device Check")) { + "Sony Programmable I/O Device Check")) { printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? " "if not use check_ioport=0\n", check->port1); @@ -1255,7 +1255,7 @@ static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, if (request_region(ioport_list->port1, sonypi_device.region_size, - "Sony Programable I/O Device")) { + "Sony Programmable I/O Device")) { dev->ioport1 = ioport_list->port1; dev->ioport2 = ioport_list->port2; return 0; diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index d3c9d755ed98..d6412c16385f 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -67,7 +67,7 @@ * cp foo.bit /dev/icap0 * * Note that unless foo.bit is an appropriately constructed partial - * bitstream, this has a high likelyhood of overwriting the design + * bitstream, this has a high likelihood of overwriting the design * currently programmed in the FPGA. */ diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b03771d4787c..2dafc5c38ae7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1782,7 +1782,7 @@ error_out: * cpufreq_update_policy - re-evaluate an existing cpufreq policy * @cpu: CPU which shall be re-evaluated * - * Usefull for policy notifiers which have different necessities + * Useful for policy notifiers which have different necessities * at different times. */ int cpufreq_update_policy(unsigned int cpu) diff --git a/drivers/crypto/amcc/crypto4xx_sa.c b/drivers/crypto/amcc/crypto4xx_sa.c index 466fd94cd4a3..de8a7a48775a 100644 --- a/drivers/crypto/amcc/crypto4xx_sa.c +++ b/drivers/crypto/amcc/crypto4xx_sa.c @@ -17,7 +17,7 @@ * @file crypto4xx_sa.c * * This file implements the security context - * assoicate format. + * associate format. */ #include #include diff --git a/drivers/crypto/amcc/crypto4xx_sa.h b/drivers/crypto/amcc/crypto4xx_sa.h index 4b83ed7e5570..1352d58d4e34 100644 --- a/drivers/crypto/amcc/crypto4xx_sa.h +++ b/drivers/crypto/amcc/crypto4xx_sa.h @@ -15,7 +15,7 @@ * GNU General Public License for more details. * * This file defines the security context - * assoicate format. + * associate format. */ #ifndef __CRYPTO4XX_SA_H__ diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 0d662213c066..4c20c5bf6058 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -1044,7 +1044,7 @@ static int aead_perform(struct aead_request *req, int encrypt, memcpy(crypt->iv, req->iv, ivsize); if (req->src != req->dst) { - BUG(); /* -ENOTSUP because of my lazyness */ + BUG(); /* -ENOTSUP because of my laziness */ } /* ASSOC data */ diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 3d7d705f026f..235f53bf494e 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -167,7 +167,7 @@ static void atc_desc_put(struct at_dma_chan *atchan, struct at_desc *desc) /** * atc_assign_cookie - compute and assign new cookie * @atchan: channel we work on - * @desc: descriptor to asign cookie for + * @desc: descriptor to assign cookie for * * Called with atchan->lock held and bh disabled */ diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index 00deabd9a04b..f48e54006518 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -529,7 +529,7 @@ static void coh901318_pause(struct dma_chan *chan) val = readl(virtbase + COH901318_CX_CFG + COH901318_CX_CFG_SPACING * channel); - /* Stopping infinit transfer */ + /* Stopping infinite transfer */ if ((val & COH901318_CX_CTRL_TC_ENABLE) == 0 && (val & COH901318_CX_CFG_CH_ENABLE)) cohc->stopped = 1; diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 798f46a4590d..3d4ec38b9b62 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -911,8 +911,8 @@ static int intel_mid_dma_alloc_chan_resources(struct dma_chan *chan) /** * midc_handle_error - Handle DMA txn error - * @mid: controller where error occured - * @midc: chan where error occured + * @mid: controller where error occurred + * @midc: chan where error occurred * * Scan the descriptor for error */ @@ -1099,7 +1099,7 @@ static int mid_setup_dma(struct pci_dev *pdev) dma->mask_reg = ioremap(LNW_PERIPHRAL_MASK_BASE, LNW_PERIPHRAL_MASK_SIZE); if (dma->mask_reg == NULL) { - pr_err("ERR_MDMA:Cant map periphral intr space !!\n"); + pr_err("ERR_MDMA:Can't map periphral intr space !!\n"); return -ENOMEM; } } else @@ -1373,7 +1373,7 @@ int dma_resume(struct pci_dev *pci) pci_restore_state(pci); ret = pci_enable_device(pci); if (ret) { - pr_err("MDMA: device cant be enabled for %x\n", pci->device); + pr_err("MDMA: device can't be enabled for %x\n", pci->device); return ret; } device->state = RUNNING; diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h index 709fecbdde79..aea5ee88ce03 100644 --- a/drivers/dma/intel_mid_dma_regs.h +++ b/drivers/dma/intel_mid_dma_regs.h @@ -174,8 +174,8 @@ union intel_mid_dma_cfg_hi { * @dma: dma device struture pointer * @busy: bool representing if ch is busy (active txn) or not * @in_use: bool representing if ch is in use or not - * @raw_tfr: raw trf interrupt recieved - * @raw_block: raw block interrupt recieved + * @raw_tfr: raw trf interrupt received + * @raw_block: raw block interrupt received */ struct intel_mid_dma_chan { struct dma_chan chan; diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 4f95d31f5a20..b9bae94f2015 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -328,7 +328,7 @@ static irqreturn_t mpc_dma_irq(int irq, void *data) return IRQ_HANDLED; } -/* proccess completed descriptors */ +/* process completed descriptors */ static void mpc_dma_process_completed(struct mpc_dma *mdma) { dma_cookie_t last_cookie = 0; diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index af955de035f4..94ee15dd3aed 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -90,7 +90,7 @@ struct d40_lli_pool { * @lli_log: Same as above but for logical channels. * @lli_pool: The pool with two entries pre-allocated. * @lli_len: Number of llis of current descriptor. - * @lli_current: Number of transfered llis. + * @lli_current: Number of transferred llis. * @lcla_alloc: Number of LCLA entries allocated. * @txd: DMA engine struct. Used for among other things for communication * during a transfer. @@ -1214,7 +1214,7 @@ static void dma_tasklet(unsigned long data) return; err: - /* Rescue manouver if receiving double interrupts */ + /* Rescue manoeuvre if receiving double interrupts */ if (d40c->pending_tx > 0) d40c->pending_tx--; spin_unlock_irqrestore(&d40c->lock, flags); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index fac1a2002e67..af1a17d42bd7 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -45,7 +45,7 @@ config EDAC_DECODE_MCE default y ---help--- Enable this option if you want to decode Machine Check Exceptions - occuring on your machine in human-readable form. + occurring on your machine in human-readable form. You should definitely say Y here in case you want to decode MCEs which occur really early upon boot, before the module infrastructure diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index b9a781c47e3c..837ad8f85b48 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -817,7 +817,7 @@ static void cpc925_del_edac_devices(void) } } -/* Convert current back-ground scrub rate into byte/sec bandwith */ +/* Convert current back-ground scrub rate into byte/sec bandwidth */ static int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci) { struct cpc925_mc_pdata *pdata = mci->pvt_info; diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 3d965347a673..eefa3501916b 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -164,7 +164,7 @@ enum mem_type { /* chipset Error Detection and Correction capabilities and mode */ enum edac_type { EDAC_UNKNOWN = 0, /* Unknown if ECC is available */ - EDAC_NONE, /* Doesnt support ECC */ + EDAC_NONE, /* Doesn't support ECC */ EDAC_RESERVED, /* Reserved ECC type */ EDAC_PARITY, /* Detects parity errors */ EDAC_EC, /* Error Checking - no correction */ @@ -233,7 +233,7 @@ enum scrub_type { * of these in parallel provides 64 bits which is common * for a memory stick. * - * Memory Stick: A printed circuit board that agregates multiple + * Memory Stick: A printed circuit board that aggregates multiple * memory devices in parallel. This is the atomic * memory component that is purchaseable by Joe consumer * and loaded into a memory socket. @@ -385,7 +385,7 @@ struct mem_ctl_info { /* Get the current sdram memory scrub rate from the internal representation and converts it to the closest matching - bandwith in bytes/sec. + bandwidth in bytes/sec. */ int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci); @@ -823,7 +823,7 @@ extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, * There are a limited number of error logging registers that can * be exausted. When all registers are exhausted and an additional * error occurs then an error overflow register records that an - * error occured and the type of error, but doesn't have any + * error occurred and the type of error, but doesn't have any * further information. The ce/ue versions make for cleaner * reporting logic and function interface - reduces conditional * statement clutter and extra function arguments. diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index d5e13c94714f..a7408cf86f37 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -672,7 +672,7 @@ void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, block->counters.ce_count++; } - /* Propogate the count up the 'totals' tree */ + /* Propagate the count up the 'totals' tree */ instance->counters.ce_count++; edac_dev->counters.ce_count++; @@ -718,7 +718,7 @@ void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, block->counters.ue_count++; } - /* Propogate the count up the 'totals' tree */ + /* Propagate the count up the 'totals' tree */ instance->counters.ue_count++; edac_dev->counters.ue_count++; diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 400de071cabc..86649df00285 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -533,7 +533,7 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, memset(&block->kobj, 0, sizeof(struct kobject)); /* bump the main kobject's reference count for this controller - * and this instance is dependant on the main + * and this instance is dependent on the main */ main_kobj = kobject_get(&edac_dev->kobj); if (!main_kobj) { @@ -635,7 +635,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, instance->ctl = edac_dev; /* bump the main kobject's reference count for this controller - * and this instance is dependant on the main + * and this instance is dependent on the main */ main_kobj = kobject_get(&edac_dev->kobj); if (!main_kobj) { diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index a4e9db2d6524..1d8056049072 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -724,7 +724,7 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci, * Some MC's can remap memory so that it is still available * at a different address when PCI devices map into memory. * MC's that can't do this lose the memory where PCI devices - * are mapped. This mapping is MC dependant and so we call + * are mapped. This mapping is MC dependent and so we call * back into the MC driver for it to map the MC page to * a physical (CPU) page which can then be mapped to a virtual * page - which can then be scrubbed. diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 73196f7b7229..26343fd46596 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -850,7 +850,7 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, /* * loop if there are attributes and until we hit a NULL entry - * Remove first all the atributes + * Remove first all the attributes */ while (sysfs_attrib) { debugf4("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 023b01cb5175..495198ad059c 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -352,7 +352,7 @@ static int edac_pci_main_kobj_setup(void) return 0; /* First time, so create the main kobject and its - * controls and atributes + * controls and attributes */ edac_class = edac_get_sysfs_class(); if (edac_class == NULL) { @@ -551,7 +551,7 @@ static void edac_pci_dev_parity_clear(struct pci_dev *dev) /* * PCI Parity polling * - * Fucntion to retrieve the current parity status + * Function to retrieve the current parity status * and decode it * */ diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index a5cefab8d65d..87f427c2ce5c 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -1372,7 +1372,7 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx) * actual number of slots/dimms per channel, we thus utilize the * resource as specified by the chipset. Thus, we might have * have more DIMMs per channel than actually on the mobo, but this - * allows the driver to support upto the chipset max, without + * allows the driver to support up to the chipset max, without * some fancy mobo determination. */ i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel, diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index 0448da0af75d..bcbdeeca48b8 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -11,7 +11,7 @@ * * The intel 5100 has two independent channels. EDAC core currently * can not reflect this configuration so instead the chip-select - * rows for each respective channel are layed out one after another, + * rows for each respective channel are laid out one after another, * the first half belonging to channel 0, the second half belonging * to channel 1. */ diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index 38a9be9e1c7c..80a465efbae8 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -648,7 +648,7 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci, return; } - /* Miscelaneous errors */ + /* Miscellaneous errors */ errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); branch = extract_fbdchan_indx(info->ferr_nf_fbd); @@ -1240,7 +1240,7 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx) * actual number of slots/dimms per channel, we thus utilize the * resource as specified by the chipset. Thus, we might have * have more DIMMs per channel than actually on the mobo, but this - * allows the driver to support upto the chipset max, without + * allows the driver to support up to the chipset max, without * some fancy mobo determination. */ num_dimms_per_channel = MAX_DIMMS_PER_CHANNEL; diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index 76d1f576cdc8..363cc1602944 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -1065,7 +1065,7 @@ static int __devinit i7300_init_one(struct pci_dev *pdev, * actual number of slots/dimms per channel, we thus utilize the * resource as specified by the chipset. Thus, we might have * have more DIMMs per channel than actually on the mobo, but this - * allows the driver to support upto the chipset max, without + * allows the driver to support up to the chipset max, without * some fancy mobo determination. */ num_dimms_per_channel = MAX_SLOTS; diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 81154ab296b6..465cbc25149f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1772,7 +1772,7 @@ static void i7core_check_error(struct mem_ctl_info *mci) /* * MCE first step: Copy all mce errors into a temporary buffer * We use a double buffering here, to reduce the risk of - * loosing an error. + * losing an error. */ smp_rmb(); count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in) diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 678405ab04e4..4329d39f902c 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -203,7 +203,7 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci, row_high_limit = ((u32) drbar << 23); /* find the DRAM Chip Select Base address and mask */ debugf1("MC%d: %s: %s() Row=%d, " - "Boundry Address=%#0x, Last = %#0x\n", + "Boundary Address=%#0x, Last = %#0x\n", mci->mc_idx, __FILE__, __func__, index, row_high_limit, row_high_limit_last); @@ -305,7 +305,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx) i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype); /* Many BIOSes don't clear error flags on boot, so do this - * here, or we get "phantom" errors occuring at module-load + * here, or we get "phantom" errors occurring at module-load * time. */ pci_write_bits32(pdev, I82443BXGX_EAP, (I82443BXGX_EAP_OFFSET_SBE | diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 733a7e7a8d6f..a4987e03f59e 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -90,7 +90,7 @@ static ssize_t edac_inject_bank_store(struct kobject *kobj, if (value > 5) if (boot_cpu_data.x86 != 0x15 || value > 6) { - printk(KERN_ERR "Non-existant MCE bank: %lu\n", value); + printk(KERN_ERR "Non-existent MCE bank: %lu\n", value); return -EINVAL; } diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index 6a822c631ef5..678513738c33 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -120,7 +120,7 @@ * write 0=NOP */ -#define R82600_DRBA 0x60 /* + 0x60..0x63 SDRAM Row Boundry Address +#define R82600_DRBA 0x60 /* + 0x60..0x63 SDRAM Row Boundary Address * Registers * * 7:0 Address lines 30:24 - upper limit of @@ -217,7 +217,7 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, { struct csrow_info *csrow; int index; - u8 drbar; /* SDRAM Row Boundry Address Register */ + u8 drbar; /* SDRAM Row Boundary Address Register */ u32 row_high_limit, row_high_limit_last; u32 reg_sdram, ecc_on, row_base; @@ -236,7 +236,7 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, row_high_limit = ((u32) drbar << 24); /* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ - debugf1("%s() Row=%d, Boundry Address=%#0x, Last = %#0x\n", + debugf1("%s() Row=%d, Boundary Address=%#0x, Last = %#0x\n", __func__, index, row_high_limit, row_high_limit_last); /* Empty row [p.57] */ diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 7ed08fd1214e..3f04dd3681cf 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -453,7 +453,7 @@ static bool fwnet_pd_update(struct fwnet_peer *peer, memcpy(pd->pbuf + frag_off, frag_buf, frag_len); /* - * Move list entry to beginnig of list so that oldest partial + * Move list entry to beginning of list so that oldest partial * datagrams percolate to the end of the list */ list_move_tail(&pd->pd_link, &peer->pd_list); diff --git a/drivers/gpio/mc33880.c b/drivers/gpio/mc33880.c index 00f6d24c669d..4ec797593bdb 100644 --- a/drivers/gpio/mc33880.c +++ b/drivers/gpio/mc33880.c @@ -45,7 +45,7 @@ * To save time we cache them here in memory */ struct mc33880 { - struct mutex lock; /* protect from simultanous accesses */ + struct mutex lock; /* protect from simultaneous accesses */ u8 port_config; struct gpio_chip chip; struct spi_device *spi; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 799e1490cf24..872747c5a544 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1699,7 +1699,7 @@ int drm_mode_addfb(struct drm_device *dev, mutex_lock(&dev->mode_config.mutex); - /* TODO check buffer is sufficently large */ + /* TODO check buffer is sufficiently large */ /* TODO setup destructor callback */ fb = dev->mode_config.funcs->fb_create(dev, file_priv, r); @@ -1750,7 +1750,7 @@ int drm_mode_rmfb(struct drm_device *dev, mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB); - /* TODO check that we realy get a framebuffer back. */ + /* TODO check that we really get a framebuffer back. */ if (!obj) { DRM_ERROR("mode invalid framebuffer id\n"); ret = -EINVAL; diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index add1737dae0d..5d00b0fc0d91 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -551,7 +551,7 @@ EXPORT_SYMBOL(drm_mm_scan_add_block); * corrupted. * * When the scan list is empty, the selected memory nodes can be freed. An - * immediatly following drm_mm_search_free with best_match = 0 will then return + * immediately following drm_mm_search_free with best_match = 0 will then return * the just freed block (because its at the top of the free_stack list). * * Returns one if this block should be evicted, zero otherwise. Will always diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5004724ea57e..1c1b27c97e5c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -630,7 +630,7 @@ typedef struct drm_i915_private { * Flag if the hardware appears to be wedged. * * This is set when attempts to idle the device timeout. - * It prevents command submission from occuring and makes + * It prevents command submission from occurring and makes * every pending request fail */ atomic_t wedged; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0daefca5cbb8..cb8578b7e443 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -213,7 +213,7 @@ intel_dp_mode_valid(struct drm_connector *connector, return MODE_PANEL; } - /* only refuse the mode on non eDP since we have seen some wierd eDP panels + /* only refuse the mode on non eDP since we have seen some weird eDP panels which are outside spec tolerances but somehow work by magic */ if (!is_edp(intel_dp) && (intel_dp_link_required(connector->dev, intel_dp, mode->clock) diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index a386b022e538..4f4e23bc2d16 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -230,7 +230,7 @@ struct intel_sdvo_set_target_input_args { } __attribute__((packed)); /** - * Takes a struct intel_sdvo_output_flags of which outputs are targetted by + * Takes a struct intel_sdvo_output_flags of which outputs are targeted by * future output commands. * * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c index 1e1eb1d7e971..5ccb65deb83c 100644 --- a/drivers/gpu/drm/mga/mga_dma.c +++ b/drivers/gpu/drm/mga/mga_dma.c @@ -426,7 +426,7 @@ int mga_driver_load(struct drm_device *dev, unsigned long flags) * Bootstrap the driver for AGP DMA. * * \todo - * Investigate whether there is any benifit to storing the WARP microcode in + * Investigate whether there is any benefit to storing the WARP microcode in * AGP memory. If not, the microcode may as well always be put in PCI * memory. * diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 3837090d66af..4cea35c57d15 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -200,7 +200,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, /* disable the fifo caches */ pfifo->reassign(dev, false); - /* Construct inital RAMFC for new channel */ + /* Construct initial RAMFC for new channel */ ret = pfifo->create_context(chan); if (ret) { nouveau_channel_put(&chan); @@ -278,7 +278,7 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan) return; } - /* noone wants the channel anymore */ + /* no one wants the channel anymore */ NV_DEBUG(dev, "freeing channel %d\n", chan->id); nouveau_debugfs_channel_fini(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index fff180a99867..57e5302503db 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -216,7 +216,7 @@ struct nouveau_channel { /* mapping of the fifo itself */ struct drm_local_map *map; - /* mapping of the regs controling the fifo */ + /* mapping of the regs controlling the fifo */ void __iomem *user; uint32_t user_get; uint32_t user_put; diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 4fcbd091a117..5bb2859001e2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -963,7 +963,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) if (ret) goto err_mmio; - /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ + /* Map PRAMIN BAR, or on older cards, the aperture within BAR0 */ if (dev_priv->card_type >= NV_40) { int ramin_bar = 2; if (pci_resource_len(dev->pdev, ramin_bar) == 0) diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index a260fbbe3d9b..748b9d9c2949 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -164,7 +164,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) NV_DEBUG_KMS(dev, "Setting dpms mode %d on CRTC %d\n", mode, nv_crtc->index); - if (nv_crtc->last_dpms == mode) /* Don't do unnecesary mode changes. */ + if (nv_crtc->last_dpms == mode) /* Don't do unnecessary mode changes. */ return; nv_crtc->last_dpms = mode; @@ -677,7 +677,7 @@ static void nv_crtc_prepare(struct drm_crtc *crtc) NVBlankScreen(dev, nv_crtc->index, true); - /* Some more preperation. */ + /* Some more preparation. */ NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_CONFIG, NV_PCRTC_CONFIG_START_ADDRESS_NON_VGA); if (dev_priv->card_type == NV_40) { uint32_t reg900 = NVReadRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_900); diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 18d30c2c1aa6..fceb44c0ec74 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -181,7 +181,7 @@ nv40_graph_load_context(struct nouveau_channel *chan) NV40_PGRAPH_CTXCTL_CUR_LOADED); /* 0x32E0 records the instance address of the active FIFO's PGRAPH * context. If at any time this doesn't match 0x40032C, you will - * recieve PGRAPH_INTR_CONTEXT_SWITCH + * receive PGRAPH_INTR_CONTEXT_SWITCH */ nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst); return 0; diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h index 04b269d14a59..7fd88497b930 100644 --- a/drivers/gpu/drm/radeon/atombios.h +++ b/drivers/gpu/drm/radeon/atombios.h @@ -738,13 +738,13 @@ typedef struct _ATOM_DIG_ENCODER_CONFIG_V3 { #if ATOM_BIG_ENDIAN UCHAR ucReserved1:1; - UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F) UCHAR ucReserved:3; UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz #else UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz UCHAR ucReserved:3; - UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F) UCHAR ucReserved1:1; #endif }ATOM_DIG_ENCODER_CONFIG_V3; @@ -785,13 +785,13 @@ typedef struct _ATOM_DIG_ENCODER_CONFIG_V4 { #if ATOM_BIG_ENDIAN UCHAR ucReserved1:1; - UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F) UCHAR ucReserved:2; UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version #else UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version UCHAR ucReserved:2; - UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) + UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also referred as DIGA/B/C/D/E/F) UCHAR ucReserved1:1; #endif }ATOM_DIG_ENCODER_CONFIG_V4; @@ -2126,7 +2126,7 @@ typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO // Structures used in FirmwareInfoTable /****************************************************************************/ -// usBIOSCapability Defintion: +// usBIOSCapability Definition: // Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; // Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; // Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; @@ -3341,7 +3341,7 @@ typedef struct _ATOM_SPREAD_SPECTRUM_INFO /****************************************************************************/ // Structure used in AnalogTV_InfoTable (Top level) /****************************************************************************/ -//ucTVBootUpDefaultStd definiton: +//ucTVBootUpDefaultStd definition: //ATOM_TV_NTSC 1 //ATOM_TV_NTSCJ 2 @@ -3816,7 +3816,7 @@ typedef struct _ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO UCHAR Reserved [6]; // for potential expansion }ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO; -//Related definitions, all records are differnt but they have a commond header +//Related definitions, all records are different but they have a commond header typedef struct _ATOM_COMMON_RECORD_HEADER { UCHAR ucRecordType; //An emun to indicate the record type @@ -4365,14 +4365,14 @@ ucUMAChannelNumber: System memory channel numbers. ulCSR_M3_ARB_CNTL_DEFAULT[10]: Arrays with values for CSR M3 arbiter for default ulCSR_M3_ARB_CNTL_UVD[10]: Arrays with values for CSR M3 arbiter for UVD playback. ulCSR_M3_ARB_CNTL_FS3D[10]: Arrays with values for CSR M3 arbiter for Full Screen 3D applications. -sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high +sAvail_SCLK[5]: Arrays to provide available list of SLCK and corresponding voltage, order from low to high ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. ulMinimumNClk: Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz. ulIdleNClk: NCLK speed while memory runs in self-refresh state. Unit in 10kHz. ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns. ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns. -usPCIEClkSSPercentage: PCIE Clock Spred Spectrum Percentage in unit 0.01%; 100 mean 1%. -usPCIEClkSSType: PCIE Clock Spred Spectrum Type. 0 for Down spread(default); 1 for Center spread. +usPCIEClkSSPercentage: PCIE Clock Spread Spectrum Percentage in unit 0.01%; 100 mean 1%. +usPCIEClkSSType: PCIE Clock Spread Spectrum Type. 0 for Down spread(default); 1 for Center spread. usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting. usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting. @@ -4555,7 +4555,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3 #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LIT2AC 4 -//Byte aligned defintion for BIOS usage +//Byte aligned definition for BIOS usage #define ATOM_S0_CRT1_MONOb0 0x01 #define ATOM_S0_CRT1_COLORb0 0x02 #define ATOM_S0_CRT1_MASKb0 (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0) @@ -4621,7 +4621,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 #define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK 0xC0000000L -//Byte aligned defintion for BIOS usage +//Byte aligned definition for BIOS usage #define ATOM_S2_TV1_STANDARD_MASKb0 0x0F #define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF #define ATOM_S2_DEVICE_DPMS_STATEb2 0x01 @@ -4671,7 +4671,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 #define ATOM_S3_ALLOW_FAST_PWR_SWITCH 0x40000000L #define ATOM_S3_RQST_GPU_USE_MIN_PWR 0x80000000L -//Byte aligned defintion for BIOS usage +//Byte aligned definition for BIOS usage #define ATOM_S3_CRT1_ACTIVEb0 0x01 #define ATOM_S3_LCD1_ACTIVEb0 0x02 #define ATOM_S3_TV1_ACTIVEb0 0x04 @@ -4707,7 +4707,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 #define ATOM_S4_LCD1_REFRESH_MASK 0x0000FF00L #define ATOM_S4_LCD1_REFRESH_SHIFT 8 -//Byte aligned defintion for BIOS usage +//Byte aligned definition for BIOS usage #define ATOM_S4_LCD1_PANEL_ID_MASKb0 0x0FF #define ATOM_S4_LCD1_REFRESH_MASKb1 ATOM_S4_LCD1_PANEL_ID_MASKb0 #define ATOM_S4_VRAM_INFO_MASKb2 ATOM_S4_LCD1_PANEL_ID_MASKb0 @@ -4786,7 +4786,7 @@ typedef struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 #define ATOM_S6_VRI_BRIGHTNESS_CHANGE 0x40000000L #define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK 0x80000000L -//Byte aligned defintion for BIOS usage +//Byte aligned definition for BIOS usage #define ATOM_S6_DEVICE_CHANGEb0 0x01 #define ATOM_S6_SCALER_CHANGEb0 0x02 #define ATOM_S6_LID_CHANGEb0 0x04 @@ -5027,7 +5027,7 @@ typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION typedef struct _MEMORY_CLEAN_UP_PARAMETERS { - USHORT usMemoryStart; //in 8Kb boundry, offset from memory base address + USHORT usMemoryStart; //in 8Kb boundary, offset from memory base address USHORT usMemorySize; //8Kb blocks aligned }MEMORY_CLEAN_UP_PARAMETERS; #define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS @@ -6855,7 +6855,7 @@ typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table /**************************************************************************/ -// Following definitions are for compatiblity issue in different SW components. +// Following definitions are for compatibility issue in different SW components. #define ATOM_MASTER_DATA_TABLE_REVISION 0x01 #define Object_Info Object_Header #define AdjustARB_SEQ MC_InitParameter diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index edde90b37554..23d36417158d 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -442,7 +442,7 @@ static inline int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u3 } ib = p->ib->ptr; switch (reg) { - /* force following reg to 0 in an attemp to disable out buffer + /* force following reg to 0 in an attempt to disable out buffer * which will need us to better understand how it works to perform * security check on it (Jerome) */ diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 8713731fa014..55a7f190027e 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -437,7 +437,7 @@ int r300_asic_reset(struct radeon_device *rdev) status = RREG32(R_000E40_RBBM_STATUS); dev_info(rdev->dev, "(%s:%d) RBBM_STATUS=0x%08X\n", __func__, __LINE__, status); /* resetting the CP seems to be problematic sometimes it end up - * hard locking the computer, but it's necessary for successfull + * hard locking the computer, but it's necessary for successful * reset more test & playing is needed on R3XX/R4XX to find a * reliable (if any solution) */ diff --git a/drivers/gpu/drm/radeon/r300_reg.h b/drivers/gpu/drm/radeon/r300_reg.h index f0bce399c9f3..00c0d2ba22d3 100644 --- a/drivers/gpu/drm/radeon/r300_reg.h +++ b/drivers/gpu/drm/radeon/r300_reg.h @@ -608,7 +608,7 @@ * My guess is that there are two bits for each zbias primitive * (FILL, LINE, POINT). * One to enable depth test and one for depth write. - * Yet this doesnt explain why depth writes work ... + * Yet this doesn't explain why depth writes work ... */ #define R300_RE_OCCLUSION_CNTL 0x42B4 # define R300_OCCLUSION_ON (1<<1) @@ -817,7 +817,7 @@ # define R300_TX_MIN_FILTER_LINEAR_MIP_NEAREST (6 << 11) # define R300_TX_MIN_FILTER_LINEAR_MIP_LINEAR (10 << 11) -/* NOTE: NEAREST doesnt seem to exist. +/* NOTE: NEAREST doesn't seem to exist. * Im not seting MAG_FILTER_MASK and (3 << 11) on for all * anisotropy modes because that would void selected mag filter */ diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 3324620b2db6..fd18be9871ab 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -921,7 +921,7 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx return 0; ib = p->ib->ptr; switch (reg) { - /* force following reg to 0 in an attemp to disable out buffer + /* force following reg to 0 in an attempt to disable out buffer * which will need us to better understand how it works to perform * security check on it (Jerome) */ diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 50db6d62eec2..f5ac7e788d81 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -334,7 +334,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - /* it's unknown what these bits do excatly, but it's indeed quite usefull for debugging */ + /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */ WREG32(offset+R600_HDMI_AUDIO_DEBUG_0, 0x00FFFFFF); WREG32(offset+R600_HDMI_AUDIO_DEBUG_1, 0x007FFFFF); WREG32(offset+R600_HDMI_AUDIO_DEBUG_2, 0x00000001); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index cfe3af1a7935..93f536594c73 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -679,11 +679,11 @@ struct radeon_wb { * @sideport_bandwidth: sideport bandwidth the gpu has (MByte/s) (IGP) * @ht_bandwidth: ht bandwidth the gpu has (MByte/s) (IGP) * @core_bandwidth: core GPU bandwidth the gpu has (MByte/s) (IGP) - * @sclk: GPU clock Mhz (core bandwith depends of this clock) + * @sclk: GPU clock Mhz (core bandwidth depends of this clock) * @needed_bandwidth: current bandwidth needs * * It keeps track of various data needed to take powermanagement decision. - * Bandwith need is used to determine minimun clock of the GPU and memory. + * Bandwidth need is used to determine minimun clock of the GPU and memory. * Equation between gpu/memory clock and available bandwidth is hw dependent * (type of memory, bus size, efficiency, ...) */ diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 3d599e33b9cc..75867792a4e2 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -244,7 +244,7 @@ void radeon_write_agp_base(drm_radeon_private_t *dev_priv, u64 agp_base) u32 agp_base_lo = agp_base & 0xffffffff; u32 r6xx_agp_base = (agp_base >> 22) & 0x3ffff; - /* R6xx/R7xx must be aligned to a 4MB boundry */ + /* R6xx/R7xx must be aligned to a 4MB boundary */ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) RADEON_WRITE(R700_MC_VM_AGP_BASE, r6xx_agp_base); else if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index 017ac54920fb..bdf2fa1189ae 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -226,7 +226,7 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc, y += crtc->y; DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y); - /* avivo cursor image can't end on 128 pixel boundry or + /* avivo cursor image can't end on 128 pixel boundary or * go past the end of the frame if both crtcs are enabled */ list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index f0209be7a34b..890217e678d3 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -262,7 +262,7 @@ int radeon_wb_init(struct radeon_device *rdev) * Note: GTT start, end, size should be initialized before calling this * function on AGP platform. * - * Note: We don't explictly enforce VRAM start to be aligned on VRAM size, + * Note: We don't explicitly enforce VRAM start to be aligned on VRAM size, * this shouldn't be a problem as we are using the PCI aperture as a reference. * Otherwise this would be needed for rv280, all r3xx, and all r4xx, but * not IGP. diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 4be58793dc17..bdbab5c43bdc 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1492,7 +1492,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, * * \return Flags, or'ed together as follows: * - * DRM_SCANOUTPOS_VALID = Query successfull. + * DRM_SCANOUTPOS_VALID = Query successful. * DRM_SCANOUTPOS_INVBL = Inside vblank. * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of * this flag means that returned position may be offset by a constant but diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h index 5cba46b9779a..a1b59ca96d01 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.h +++ b/drivers/gpu/drm/radeon/radeon_drv.h @@ -271,7 +271,7 @@ typedef struct drm_radeon_private { int have_z_offset; - /* starting from here on, data is preserved accross an open */ + /* starting from here on, data is preserved across an open */ uint32_t flags; /* see radeon_chip_flags */ resource_size_t fb_aper_offset; diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 7f8e778dba46..ede6c13628f2 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h @@ -87,7 +87,7 @@ static inline void radeon_bo_unreserve(struct radeon_bo *bo) * Returns current GPU offset of the object. * * Note: object should either be pinned or reserved when calling this - * function, it might be usefull to add check for this for debugging. + * function, it might be useful to add check for this for debugging. */ static inline u64 radeon_bo_gpu_offset(struct radeon_bo *bo) { diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index 4ae5a3d1074e..92e7ea73b7c5 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -980,7 +980,7 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev, } /* hyper z clear */ - /* no docs available, based on reverse engeneering by Stephane Marchesin */ + /* no docs available, based on reverse engineering by Stephane Marchesin */ if ((flags & (RADEON_DEPTH | RADEON_STENCIL)) && (flags & RADEON_CLEAR_FASTZ)) { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index cceeb42789b6..dfe32e62bd90 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -245,7 +245,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, /* TODO handle none page aligned offsets */ /* TODO handle partial uploads and pitch != 256 */ /* TODO handle more then one copy (size != 64) */ - DRM_ERROR("lazy programer, cant handle wierd stuff\n"); + DRM_ERROR("lazy programmer, can't handle weird stuff\n"); return; } diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index ace2b1623b21..be8d4cb5861c 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -151,7 +151,7 @@ static inline void vga_irq_set_state(struct vga_device *vgadev, bool state) static void vga_check_first_use(void) { /* we should inform all GPUs in the system that - * VGA arb has occured and to try and disable resources + * VGA arb has occurred and to try and disable resources * if they can */ if (!vga_arbiter_used) { vga_arbiter_used = true; @@ -774,7 +774,7 @@ static ssize_t vga_arb_read(struct file *file, char __user * buf, */ spin_lock_irqsave(&vga_lock, flags); - /* If we are targetting the default, use it */ + /* If we are targeting the default, use it */ pdev = priv->target; if (pdev == NULL || pdev == PCI_INVALID_CARD) { spin_unlock_irqrestore(&vga_lock, flags); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e9687768a335..453e7e6da0c2 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -306,7 +306,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) case HID_GLOBAL_ITEM_TAG_PUSH: if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { - dbg_hid("global enviroment stack overflow\n"); + dbg_hid("global environment stack overflow\n"); return -1; } @@ -317,7 +317,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) case HID_GLOBAL_ITEM_TAG_POP: if (!parser->global_stack_ptr) { - dbg_hid("global enviroment stack underflow\n"); + dbg_hid("global environment stack underflow\n"); return -1; } diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 555382fc7417..bae48745bb42 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -341,7 +341,7 @@ static const struct hid_usage_entry hid_usage_table[] = { { 0x85, 0x83, "DesignCapacity" }, { 0x85, 0x85, "ManufacturerDate" }, { 0x85, 0x89, "iDeviceChemistry" }, - { 0x85, 0x8b, "Rechargable" }, + { 0x85, 0x8b, "Rechargeable" }, { 0x85, 0x8f, "iOEMInformation" }, { 0x85, 0x8d, "CapacityGranularity1" }, { 0x85, 0xd0, "ACPresent" }, diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 318cc40df92d..7a6137346097 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -76,7 +76,7 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie * This is true when single_touch_id is equal to NO_TOUCHES. If multiple touches * are down and the touch providing for single touch emulation is lifted, * single_touch_id is equal to SINGLE_TOUCH_UP. While single touch emulation is - * occuring, single_touch_id corresponds with the tracking id of the touch used. + * occurring, single_touch_id corresponds with the tracking id of the touch used. */ #define NO_TOUCHES -1 #define SINGLE_TOUCH_UP -2 diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 657da5a3d5c6..b2f56a13bcf5 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -1806,13 +1806,13 @@ static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u, /* * Notes: * - concurrent writing is prevented by mutex and all writes must be - * n*64 bytes and 64-byte aligned, each write being preceeded by an + * n*64 bytes and 64-byte aligned, each write being preceded by an * ERASE which erases a 64byte block. * If less than requested was written or an error is returned for an * otherwise correct write request the next 64-byte block which should * have been written is in undefined state (mostly: original, erased, * (half-)written with write error) - * - reading can happend without special restriction + * - reading can happen without special restriction */ static const struct file_operations picolcd_debug_flash_fops = { .owner = THIS_MODULE, diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h index 64abb5b8a59a..4109a028e138 100644 --- a/drivers/hid/hid-roccat-kone.h +++ b/drivers/hid/hid-roccat-kone.h @@ -166,7 +166,7 @@ enum kone_mouse_events { /* osd events are thought to be display on screen */ kone_mouse_event_osd_dpi = 0xa0, kone_mouse_event_osd_profile = 0xb0, - /* TODO clarify meaning and occurence of kone_mouse_event_calibration */ + /* TODO clarify meaning and occurrence of kone_mouse_event_calibration */ kone_mouse_event_calibration = 0xc0, kone_mouse_event_call_overlong_macro = 0xe0, /* switch events notify if user changed values with mousebutton click */ diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 0e05aa179eaa..e7d4c4687f02 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -1422,7 +1422,7 @@ static int __init abituguru_detect(void) at DATA and 0xAC, when this driver has already been loaded once DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either scenario but some will hold 0x00. - Some uGuru's initally hold 0x09 at DATA and will only hold 0x08 + Some uGuru's initially hold 0x09 at DATA and will only hold 0x08 after reading CMD first, so CMD must be read first! */ u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD); u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA); diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 034cebfcd273..e89d572e3320 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -151,7 +151,7 @@ struct abituguru3_data { /* Pointer to the sensors info for the detected motherboard */ const struct abituguru3_sensor_info *sensors; - /* The abituguru3 supports upto 48 sensors, and thus has registers + /* The abituguru3 supports up to 48 sensors, and thus has registers sets for 48 sensors, for convienence reasons / simplicity of the code we always read and store all registers for all 48 sensors */ diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index be0fdd58aa29..0531867484f4 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -175,7 +175,7 @@ static u16 ADM1026_REG_TEMP_OFFSET[] = { 0x1e, 0x6e, 0x6f }; * these macros are called: arguments may be evaluated more than once. */ -/* IN are scaled acording to built-in resistors. These are the +/* IN are scaled according to built-in resistors. These are the * voltages corresponding to 3/4 of full scale (192 or 0xc0) * NOTE: The -12V input needs an additional factor to account * for the Vref pullup resistor. diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index cf47e6e476ed..250d099ca398 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -130,7 +130,7 @@ enum chips { these macros are called: arguments may be evaluated more than once. */ -/* IN are scaled acording to built-in resistors */ +/* IN are scaled according to built-in resistors */ static const int lm85_scaling[] = { /* .001 Volts */ 2500, 2250, 3300, 5000, 12000, 3300, 1500, 1800 /*EMC6D100*/ diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 812781c655a7..c43b4e9f96a9 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -356,7 +356,7 @@ static int lm90_read16(struct i2c_client *client, u8 regh, u8 regl, u16 *value) /* * There is a trick here. We have to read two registers to have the * sensor temperature, but we have to beware a conversion could occur - * inbetween the readings. The datasheet says we should either use + * between the readings. The datasheet says we should either use * the one-shot conversion register, which we don't want to do * (disables hardware monitoring) or monitor the busy bit, which is * impossible (we can't read the values and monitor that bit at the diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 1a9c32d6893a..f4e617adb220 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -52,7 +52,7 @@ #define SHT15_TSU 150 /* data setup time */ /** - * struct sht15_temppair - elements of voltage dependant temp calc + * struct sht15_temppair - elements of voltage dependent temp calc * @vdd: supply voltage in microvolts * @d1: see data sheet */ @@ -251,7 +251,7 @@ static inline int sht15_update_single_val(struct sht15_data *data, enable_irq(gpio_to_irq(data->pdata->gpio_data)); if (gpio_get_value(data->pdata->gpio_data) == 0) { disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data)); - /* Only relevant if the interrupt hasn't occured. */ + /* Only relevant if the interrupt hasn't occurred. */ if (!atomic_read(&data->interrupt_handled)) schedule_work(&data->read_work); } @@ -452,7 +452,7 @@ static void sht15_bh_read_data(struct work_struct *work_s) */ atomic_set(&data->interrupt_handled, 0); enable_irq(gpio_to_irq(data->pdata->gpio_data)); - /* If still not occured or another handler has been scheduled */ + /* If still not occurred or another handler has been scheduled */ if (gpio_get_value(data->pdata->gpio_data) || atomic_read(&data->interrupt_handled)) return; diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 93187c3cb5e7..5bd194968801 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -166,7 +166,7 @@ static int __devinit tmp102_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { - dev_err(&client->dev, "adapter doesnt support SMBus word " + dev_err(&client->dev, "adapter doesn't support SMBus word " "transactions\n"); return -ENODEV; } diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 400a88bde278..17cf1ab95521 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -556,7 +556,7 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of - least suprise; the user doesn't expect the fan minimum to change just + least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 63841f8cec07..f3e7130c4cda 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -244,7 +244,7 @@ FAN_TO_REG(long rpm, int div) #define TEMP1_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ : (val)) / 1000, 0, 0xff)) #define TEMP1_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) -/* for temp2 and temp3, because they need addtional resolution */ +/* for temp2 and temp3, because they need additional resolution */ #define TEMP_ADD_FROM_REG(val1, val2) \ ((((val1) & 0x80 ? (val1)-0x100 \ : (val1)) * 1000) + ((val2 & 0x80) ? 500 : 0)) diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index e3bdedfb5347..854f9117f1aa 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1921,7 +1921,7 @@ static void w83793_update_nonvolatile(struct device *dev) struct w83793_data *data = i2c_get_clientdata(client); int i, j; /* - They are somewhat "stable" registers, and to update them everytime + They are somewhat "stable" registers, and to update them every time takes so much time, it's just not worthy. Update them in a long interval to avoid exception. */ diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 2b9a8f54bb2c..4ca9cf9cde73 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -343,7 +343,7 @@ static int pca_xfer(struct i2c_adapter *i2c_adap, ret = curmsg; out: - DEB1("}}} transfered %d/%d messages. " + DEB1("}}} transferred %d/%d messages. " "status is %#04x. control is %#04x\n", curmsg, num, pca_status(adap), pca_get_con(adap)); diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 906a3ca50db6..dd364171f9c5 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -295,7 +295,7 @@ static int ali1535_transaction(struct i2c_adapter *adap) } /* Unfortunately the ALI SMB controller maps "no response" and "bus - * collision" into a single bit. No reponse is the usual case so don't + * collision" into a single bit. No response is the usual case so don't * do a printk. This means that bus collisions go unreported. */ if (temp & ALI1535_STS_BUSERR) { diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index b14f6d68221d..83e8a60cdc86 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -318,7 +318,7 @@ static int ali15x3_transaction(struct i2c_adapter *adap) /* Unfortunately the ALI SMB controller maps "no response" and "bus - collision" into a single bit. No reponse is the usual case so don't + collision" into a single bit. No response is the usual case so don't do a printk. This means that bus collisions go unreported. */ diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 5795c8398c7c..a76d85fa3ad7 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -355,7 +355,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) /* * Write mode register first as needed for correct behaviour * on OMAP-L138, but don't set STT yet to avoid a race with XRDY - * occuring before we have loaded DXR + * occurring before we have loaded DXR */ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); diff --git a/drivers/i2c/busses/i2c-designware.c b/drivers/i2c/busses/i2c-designware.c index b664ed8bbdb3..b7a51c43b185 100644 --- a/drivers/i2c/busses/i2c-designware.c +++ b/drivers/i2c/busses/i2c-designware.c @@ -178,7 +178,7 @@ static char *abort_sources[] = { * @lock: protect this struct and IO registers * @clk: input reference clock * @cmd_err: run time hadware error code - * @msgs: points to an array of messages currently being transfered + * @msgs: points to an array of messages currently being transferred * @msgs_num: the number of elements in msgs * @msg_write_idx: the element index of the current tx message in the msgs * array diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index e5b1a3bf5b80..37e2e82a9c88 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -22,7 +22,7 @@ /* With some changes from Kyösti Mälkki and even Frodo Looijaard */ -/* Partialy rewriten by Oleg I. Vdovikin for mmapped support of +/* Partially rewriten by Oleg I. Vdovikin for mmapped support of for Alpha Processor Inc. UP-2000(+) boards */ #include diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ed2e0c5ea37c..72c0415f6f94 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -96,7 +96,7 @@ #define SMBHSTCFG_SMB_SMI_EN 2 #define SMBHSTCFG_I2C_EN 4 -/* Auxillary control register bits, ICH4+ only */ +/* Auxiliary control register bits, ICH4+ only */ #define SMBAUXCTL_CRC 1 #define SMBAUXCTL_E32B 2 diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index e4f88dca99b5..3c110fbc409b 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -494,7 +494,7 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, if (unlikely(ret < 0)) break; else if (unlikely(ret != count)){ - DBG("%d: xfer_bytes, requested %d, transfered %d\n", + DBG("%d: xfer_bytes, requested %d, transferred %d\n", dev->idx, count, ret); /* If it's not a last part of xfer, abort it */ @@ -593,7 +593,7 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){ DBG("%d: iic_xfer, bus is not free\n", dev->idx); - /* Usually it means something serious has happend. + /* Usually it means something serious has happened. * We *cannot* have unfinished previous transfer * so it doesn't make any sense to try to stop it. * Probably we were not able to recover from the diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c index c71492782bbd..e828ac85cfa7 100644 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -170,8 +170,8 @@ struct intel_mid_i2c_private { /* Raw Interrupt Status Register */ #define IC_RAW_INTR_STAT 0x34 /* Read Only */ #define GEN_CALL (1 << 11) /* General call */ -#define START_DET (1 << 10) /* (RE)START occured */ -#define STOP_DET (1 << 9) /* STOP occured */ +#define START_DET (1 << 10) /* (RE)START occurred */ +#define STOP_DET (1 << 9) /* STOP occurred */ #define ACTIVITY (1 << 8) /* Bus busy */ #define RX_DONE (1 << 7) /* Not used in Master mode */ #define TX_ABRT (1 << 6) /* Transmit Abort */ @@ -375,7 +375,7 @@ static int intel_mid_i2c_disable(struct i2c_adapter *adap) * I2C should be disabled prior to other register operation. If failed, an * errno is returned. Mask and Clear all interrpts, this should be done at * first. Set common registers which will not be modified during normal - * transfers, including: controll register, FIFO threshold and clock freq. + * transfers, including: control register, FIFO threshold and clock freq. * Check APB data width at last. */ static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c) @@ -455,7 +455,7 @@ static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1, * * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be * distingushed. At present, no circumstances have been found out that - * multiple errors would be occured simutaneously, so we simply use the + * multiple errors would be occurred simutaneously, so we simply use the * register value directly. * * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need @@ -469,7 +469,7 @@ static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c) /* Single transfer error check: * According to databook, TX/RX FIFOs would be flushed when - * the abort interrupt occured. + * the abort interrupt occurred. */ if (abort & ABRT_MASTER_DIS) dev_err(&adap->dev, @@ -569,7 +569,7 @@ static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) * Return Values: * 0 if the read transfer succeeds * -ETIMEDOUT if we cannot read the "raw" interrupt register - * -EINVAL if a transfer abort occured + * -EINVAL if a transfer abort occurred * * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to * data transfer. The actual "write" operation will be performed when the @@ -697,7 +697,7 @@ static int intel_mid_i2c_setup(struct i2c_adapter *adap, struct i2c_msg *pmsg) * @num: number of i2c_msg * * Return Values: - * + number of messages transfered + * + number of messages transferred * -ETIMEDOUT If cannot disable I2C controller or read IC_STATUS * -EINVAL If the address in i2c_msg is invalid * diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index ddc258edb34f..0682f8f277b0 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -141,7 +141,7 @@ static int sch_transaction(void) * This is the main access entry for i2c-sch access * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write * (0 for read and 1 for write), size is i2c transaction type and data is the - * union of transaction for data to be transfered or data read from bus. + * union of transaction for data to be transferred or data read from bus. * return 0 for success and others for failure. */ static s32 sch_access(struct i2c_adapter *adap, u16 addr, diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index caf96dc8ca1b..7e78f7c87857 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -149,7 +149,7 @@ static void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c, * We have to copy the slave address (u8) and buffer (arbitrary number * of u8) into the data register (u32). To achieve that, the u8 are put * into the MSBs of 'data' which is then shifted for the next u8. When - * apropriate, 'data' is written to MXS_I2C_DATA. So, the first u32 + * appropriate, 'data' is written to MXS_I2C_DATA. So, the first u32 * looks like this: * * 3 2 1 0 diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 594ed5059c4a..e10e5cf3751a 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -126,9 +126,9 @@ enum i2c_operation { /** * struct i2c_nmk_client - client specific data * @slave_adr: 7-bit slave address - * @count: no. bytes to be transfered + * @count: no. bytes to be transferred * @buffer: client data buffer - * @xfer_bytes: bytes transfered till now + * @xfer_bytes: bytes transferred till now * @operation: current I2C operation */ struct i2c_nmk_client { @@ -330,7 +330,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * slsu defines the data setup time after SCL clock * stretching in terms of i2c clk cycles. The * needed setup time for the three modes are 250ns, - * 100ns, 10ns repectively thus leading to the values + * 100ns, 10ns respectively thus leading to the values * of 14, 6, 2 for a 48 MHz i2c clk. */ writel(dev->cfg.slsu << 16, dev->virtbase + I2C_SCR); @@ -364,7 +364,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) /* * set the speed mode. Currently we support * only standard and fast mode of operation - * TODO - support for fast mode plus (upto 1Mb/s) + * TODO - support for fast mode plus (up to 1Mb/s) * and high speed (up to 3.4 Mb/s) */ if (dev->cfg.sm > I2C_FREQ_MODE_FAST) { diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c index cadc0216e02f..cb5d01e279c6 100644 --- a/drivers/i2c/busses/i2c-s6000.c +++ b/drivers/i2c/busses/i2c-s6000.c @@ -318,7 +318,7 @@ static int __devinit s6i2c_probe(struct platform_device *dev) rc = request_irq(iface->irq, s6i2c_interrupt_entry, IRQF_SHARED, dev->name, iface); if (rc) { - dev_err(&p_adap->dev, "s6i2c: cant get IRQ %d\n", iface->irq); + dev_err(&p_adap->dev, "s6i2c: can't get IRQ %d\n", iface->irq); goto err_clk_dis; } diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 266135ddf7fa..99879617e686 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -497,7 +497,7 @@ static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate) u32 val; int i = 0; - /* Locate the apropriate clock setting */ + /* Locate the appropriate clock setting */ while (i < ARRAY_SIZE(stu300_clktable) - 1 && stu300_clktable[i].rate < clkrate) i++; @@ -644,7 +644,7 @@ static int stu300_send_address(struct stu300_dev *dev, ret = stu300_await_event(dev, STU300_EVENT_6); /* - * Clear any pending EVENT 6 no matter what happend during + * Clear any pending EVENT 6 no matter what happened during * await_event. */ val = stu300_r8(dev->virtbase + I2C_CR); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 3921f664c9c3..b4ab39b741eb 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -386,7 +386,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); return IRQ_HANDLED; err: - /* An error occured, mask all interrupts */ + /* An error occurred, mask all interrupts */ tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ | I2C_INT_RX_FIFO_DATA_REQ); diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 9fbd7e6fe32e..e9d5ff4d1496 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -21,7 +21,7 @@ * to the automotive development board Russellville. The copyright holder * as seen in the header is Intel corporation. * Mocean Laboratories forked off the GNU/Linux platform work into a - * separate company called Pelagicore AB, which commited the code to the + * separate company called Pelagicore AB, which committed the code to the * kernel. */ diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e5f76a0372fd..70c30e6bce0b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -348,7 +348,7 @@ EXPORT_SYMBOL(i2c_verify_client); /* This is a permissive address validity check, I2C address map constraints - * are purposedly not enforced, except for the general call address. */ + * are purposely not enforced, except for the general call address. */ static int i2c_check_client_addr_validity(const struct i2c_client *client) { if (client->flags & I2C_CLIENT_TEN) { diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c index 9383f67deae1..3be60da52123 100644 --- a/drivers/ide/cy82c693.c +++ b/drivers/ide/cy82c693.c @@ -67,7 +67,7 @@ static void cy82c693_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) /* * note: below we set the value for Bus Master IDE TimeOut Register - * I'm not absolutly sure what this does, but it solved my problem + * I'm not absolutely sure what this does, but it solved my problem * with IDE DMA and sound, so I now can play sound and work with * my IDE driver at the same time :-) * diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 5406b6ea3ad1..5a702d02c848 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -107,7 +107,7 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc) static void ide_floppy_report_error(struct ide_disk_obj *floppy, struct ide_atapi_pc *pc) { - /* supress error messages resulting from Medium not present */ + /* suppress error messages resulting from Medium not present */ if (floppy->sense_key == 0x02 && floppy->asc == 0x3a && floppy->ascq == 0x00) diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 34b9872f35d1..600c89a3d137 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -201,7 +201,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) u8 stat; /* - * Last sector was transfered, wait until device is ready. This can + * Last sector was transferred, wait until device is ready. This can * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms. */ for (retries = 0; retries < 1000; retries++) { diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index 1bdca49e5a03..b59d04c72051 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -8,8 +8,8 @@ * * Documentation: * - * Publically available from Intel web site. Errata documentation - * is also publically available. As an aide to anyone hacking on this + * Publicly available from Intel web site. Errata documentation + * is also publicly available. As an aide to anyone hacking on this * driver the list of errata that are relevant is below.going back to * PIIX4. Older device documentation is now a bit tricky to find. * diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c index db7f4e761dbc..4a0022567758 100644 --- a/drivers/ide/sis5513.c +++ b/drivers/ide/sis5513.c @@ -53,7 +53,7 @@ #define DRV_NAME "sis5513" -/* registers layout and init values are chipset family dependant */ +/* registers layout and init values are chipset family dependent */ #define ATA_16 0x01 #define ATA_33 0x02 @@ -406,7 +406,7 @@ static int __devinit sis_find_family(struct pci_dev *dev) pci_name(dev)); chipset_family = ATA_133; - /* Check for 5513 compability mapping + /* Check for 5513 compatibility mapping * We must use this, else the port enabled code will fail, * as it expects the enablebits at 0x4a. */ diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c index 7953447eae0f..e53a1b78378b 100644 --- a/drivers/ide/triflex.c +++ b/drivers/ide/triflex.c @@ -22,7 +22,7 @@ * Loosely based on the piix & svwks drivers. * * Documentation: - * Not publically available. + * Not publicly available. */ #include diff --git a/drivers/ide/via82cxxx.c b/drivers/ide/via82cxxx.c index d2a0997b78f8..f46f49cfcc28 100644 --- a/drivers/ide/via82cxxx.c +++ b/drivers/ide/via82cxxx.c @@ -14,7 +14,7 @@ * Andre Hedrick * * Documentation: - * Obsolete device documentation publically available from via.com.tw + * Obsolete device documentation publicly available from via.com.tw * Current device documentation available under NDA only */ diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c index 62af74295dbe..24f9e3a90e8e 100644 --- a/drivers/infiniband/hw/amso1100/c2_ae.c +++ b/drivers/infiniband/hw/amso1100/c2_ae.c @@ -157,7 +157,7 @@ void c2_ae_event(struct c2_dev *c2dev, u32 mq_index) int status; /* - * retreive the message + * retrieve the message */ wr = c2_mq_consume(mq); if (!wr) diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c index d8f4bb8bf42e..0d7b6f23caff 100644 --- a/drivers/infiniband/hw/amso1100/c2_qp.c +++ b/drivers/infiniband/hw/amso1100/c2_qp.c @@ -612,7 +612,7 @@ void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp) c2_unlock_cqs(send_cq, recv_cq); /* - * Destory qp in the rnic... + * Destroy qp in the rnic... */ destroy_qp(c2dev, qp); diff --git a/drivers/infiniband/hw/amso1100/c2_wr.h b/drivers/infiniband/hw/amso1100/c2_wr.h index c65fbdd6e469..8d4b4ca463ca 100644 --- a/drivers/infiniband/hw/amso1100/c2_wr.h +++ b/drivers/infiniband/hw/amso1100/c2_wr.h @@ -131,7 +131,7 @@ enum c2wr_ids { * All the preceding IDs are fixed, and must not change. * You can add new IDs, but must not remove or reorder * any IDs. If you do, YOU will ruin any hope of - * compatability between versions. + * compatibility between versions. */ CCWR_LAST, @@ -242,7 +242,7 @@ enum c2_acf { /* * to fix bug 1815 we define the max size allowable of the * terminate message (per the IETF spec).Refer to the IETF - * protocal specification, section 12.1.6, page 64) + * protocol specification, section 12.1.6, page 64) * The message is prefixed by 20 types of DDP info. * * Then the message has 6 bytes for the terminate control diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 47db4bf34628..58c0e417bc30 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -2392,7 +2392,7 @@ void ipath_shutdown_device(struct ipath_devdata *dd) /* * clear SerdesEnable and turn the leds off; do this here because * we are unloading, so don't count on interrupts to move along - * Turn the LEDs off explictly for the same reason. + * Turn the LEDs off explicitly for the same reason. */ dd->ipath_f_quiet_serdes(dd); diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 6d4b29c4cd89..ee79a2d97b14 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -1972,7 +1972,7 @@ static int ipath_do_user_init(struct file *fp, * 0 to 1. So for those chips, we turn it off and then back on. * This will (very briefly) affect any other open ports, but the * duration is very short, and therefore isn't an issue. We - * explictly set the in-memory tail copy to 0 beforehand, so we + * explicitly set the in-memory tail copy to 0 beforehand, so we * don't have to wait to be sure the DMA update has happened * (chip resets head/tail to 0 on transition to enable). */ diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index fef0f4201257..7c1eebe8c7c9 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -335,7 +335,7 @@ done: * @dd: the infinipath device * * sanity check at least some of the values after reset, and - * ensure no receive or transmit (explictly, in case reset + * ensure no receive or transmit (explicitly, in case reset * failed */ static int init_chip_reset(struct ipath_devdata *dd) diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index 7420715256a9..e8a2a915251e 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -86,7 +86,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe) } /* - * A GRH is expected to preceed the data even if not + * A GRH is expected to precede the data even if not * present on the wire. */ length = swqe->length; @@ -515,7 +515,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, } /* - * A GRH is expected to preceed the data even if not + * A GRH is expected to precede the data even if not * present on the wire. */ wc.byte_len = tlen + sizeof(struct ib_grh); diff --git a/drivers/infiniband/hw/ipath/ipath_user_sdma.c b/drivers/infiniband/hw/ipath/ipath_user_sdma.c index be78f6643c06..f5cb13b21445 100644 --- a/drivers/infiniband/hw/ipath/ipath_user_sdma.c +++ b/drivers/infiniband/hw/ipath/ipath_user_sdma.c @@ -236,7 +236,7 @@ static int ipath_user_sdma_num_pages(const struct iovec *iov) return 1 + ((epage - spage) >> PAGE_SHIFT); } -/* truncate length to page boundry */ +/* truncate length to page boundary */ static int ipath_user_sdma_page_length(unsigned long addr, unsigned long len) { const unsigned long offset = addr & ~PAGE_MASK; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index cfa3a2b22232..33c7eedaba6c 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1397,7 +1397,7 @@ static void handle_fin_pkt(struct nes_cm_node *cm_node) cleanup_retrans_entry(cm_node); cm_node->state = NES_CM_STATE_CLOSING; send_ack(cm_node, NULL); - /* Wait for ACK as this is simultanous close.. + /* Wait for ACK as this is simultaneous close.. * After we receive ACK, do not send anything.. * Just rm the node.. Done.. */ break; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 08c194861af5..10d0a5ec9add 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -80,7 +80,7 @@ static void nes_terminate_start_timer(struct nes_qp *nesqp); #ifdef CONFIG_INFINIBAND_NES_DEBUG static unsigned char *nes_iwarp_state_str[] = { - "Non-Existant", + "Non-Existent", "Idle", "RTS", "Closing", @@ -91,7 +91,7 @@ static unsigned char *nes_iwarp_state_str[] = { }; static unsigned char *nes_tcp_state_str[] = { - "Non-Existant", + "Non-Existent", "Closed", "Listen", "SYN Sent", diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 2c9c1933bbe3..e96b8fb5d44c 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -902,7 +902,7 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) nes_write_indexed(nesdev, NES_IDX_NIC_UNICAST_ALL, nic_active); } - nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscous = %d, All Multicast = %d.\n", + nes_debug(NES_DBG_NIC_RX, "Number of MC entries = %d, Promiscuous = %d, All Multicast = %d.\n", mc_count, !!(netdev->flags & IFF_PROMISC), !!(netdev->flags & IFF_ALLMULTI)); if (!mc_all_on) { diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index 73225eee3cc6..769a1d9da4b7 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -653,7 +653,7 @@ struct diag_observer_list_elt; /* device data struct now contains only "general per-device" info. * fields related to a physical IB port are in a qib_pportdata struct, - * described above) while fields only used by a particualr chip-type are in + * described above) while fields only used by a particular chip-type are in * a qib_chipdata struct, whose contents are opaque to this file. */ struct qib_devdata { diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 75bfad16c114..406fca50d036 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1539,7 +1539,7 @@ done_chk_sdma: /* * If process has NOT already set it's affinity, select and - * reserve a processor for it, as a rendevous for all + * reserve a processor for it, as a rendezvous for all * users of the driver. If they don't actually later * set affinity to this cpu, or set it to some other cpu, * it just means that sooner or later we don't recommend @@ -1657,7 +1657,7 @@ static int qib_do_user_init(struct file *fp, * 0 to 1. So for those chips, we turn it off and then back on. * This will (very briefly) affect any other open ctxts, but the * duration is very short, and therefore isn't an issue. We - * explictly set the in-memory tail copy to 0 beforehand, so we + * explicitly set the in-memory tail copy to 0 beforehand, so we * don't have to wait to be sure the DMA update has happened * (chip resets head/tail to 0 on transition to enable). */ diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 774dea897e9c..7de4b7ebffc5 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1799,7 +1799,7 @@ static int qib_6120_setup_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isnt' set. + * isn't' set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ @@ -2171,7 +2171,7 @@ static void rcvctrl_6120_mod(struct qib_pportdata *ppd, unsigned int op, * Init the context registers also; if we were * disabled, tail and head should both be zero * already from the enable, but since we don't - * know, we have to do it explictly. + * know, we have to do it explicitly. */ val = qib_read_ureg32(dd, ur_rcvegrindextail, ctxt); qib_write_ureg(dd, ur_rcvegrindexhead, val, ctxt); diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index de799f17cb9e..74fe0360bec7 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2111,7 +2111,7 @@ static int qib_setup_7220_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isnt' set. + * isn't' set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ @@ -2479,7 +2479,7 @@ static int qib_7220_set_ib_cfg(struct qib_pportdata *ppd, int which, u32 val) * we command the link down. As with width, only write the * actual register if the link is currently down, otherwise * takes effect on next link change. Since setting is being - * explictly requested (via MAD or sysfs), clear autoneg + * explicitly requested (via MAD or sysfs), clear autoneg * failure status if speed autoneg is enabled. */ ppd->link_speed_enabled = val; @@ -2778,7 +2778,7 @@ static void rcvctrl_7220_mod(struct qib_pportdata *ppd, unsigned int op, * Init the context registers also; if we were * disabled, tail and head should both be zero * already from the enable, but since we don't - * know, we have to do it explictly. + * know, we have to do it explicitly. */ val = qib_read_ureg32(dd, ur_rcvegrindextail, ctxt); qib_write_ureg(dd, ur_rcvegrindexhead, val, ctxt); diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 4a2d21e15a70..55de3cf3441c 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3299,7 +3299,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isnt' set. + * isn't' set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT | QIB_BADINTR); dd->flags |= QIB_DOING_RESET; @@ -3727,7 +3727,7 @@ static int qib_7322_set_ib_cfg(struct qib_pportdata *ppd, int which, u32 val) /* * As with width, only write the actual register if the * link is currently down, otherwise takes effect on next - * link change. Since setting is being explictly requested + * link change. Since setting is being explicitly requested * (via MAD or sysfs), clear autoneg failure status if speed * autoneg is enabled. */ @@ -4163,7 +4163,7 @@ static void rcvctrl_7322_mod(struct qib_pportdata *ppd, unsigned int op, * Init the context registers also; if we were * disabled, tail and head should both be zero * already from the enable, but since we don't - * know, we have to do it explictly. + * know, we have to do it explicitly. */ val = qib_read_ureg32(dd, ur_rcvegrindextail, ctxt); qib_write_ureg(dd, ur_rcvegrindexhead, val, ctxt); @@ -7483,7 +7483,7 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd) /* Baseline Wander Correction Gain [13:4-0] (leave as default) */ /* Baseline Wander Correction Gain [3:7-5] (leave as default) */ /* Data Rate Select [5:7-6] (leave as default) */ - /* RX Parralel Word Width [3:10-8] (leave as default) */ + /* RX Parallel Word Width [3:10-8] (leave as default) */ /* RX REST */ /* Single- or Multi-channel reset */ diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index ffefb78b8949..a01f3fce8eb3 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -346,7 +346,7 @@ done: * @dd: the qlogic_ib device * * sanity check at least some of the values after reset, and - * ensure no receive or transmit (explictly, in case reset + * ensure no receive or transmit (explicitly, in case reset * failed */ static int init_after_reset(struct qib_devdata *dd) diff --git a/drivers/infiniband/hw/qib/qib_mad.h b/drivers/infiniband/hw/qib/qib_mad.h index 147aff9117d7..7840ab593bcf 100644 --- a/drivers/infiniband/hw/qib/qib_mad.h +++ b/drivers/infiniband/hw/qib/qib_mad.h @@ -73,7 +73,7 @@ struct ib_mad_notice_attr { struct { __be16 reserved; - __be16 lid; /* LID where change occured */ + __be16 lid; /* LID where change occurred */ u8 reserved2; u8 local_changes; /* low bit - local changes */ __be32 new_cap_mask; /* new capability mask */ diff --git a/drivers/infiniband/hw/qib/qib_twsi.c b/drivers/infiniband/hw/qib/qib_twsi.c index 6f31ca5039db..ddde72e11edb 100644 --- a/drivers/infiniband/hw/qib/qib_twsi.c +++ b/drivers/infiniband/hw/qib/qib_twsi.c @@ -41,7 +41,7 @@ * QLogic_IB "Two Wire Serial Interface" driver. * Originally written for a not-quite-i2c serial eeprom, which is * still used on some supported boards. Later boards have added a - * variety of other uses, most board-specific, so teh bit-boffing + * variety of other uses, most board-specific, so the bit-boffing * part has been split off to this file, while the other parts * have been moved to chip-specific files. * diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c index 4a51fd1e9cb7..828609fa4d28 100644 --- a/drivers/infiniband/hw/qib/qib_ud.c +++ b/drivers/infiniband/hw/qib/qib_ud.c @@ -116,7 +116,7 @@ static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe) } /* - * A GRH is expected to preceed the data even if not + * A GRH is expected to precede the data even if not * present on the wire. */ length = swqe->length; @@ -520,7 +520,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct qib_ib_header *hdr, goto drop; /* - * A GRH is expected to preceed the data even if not + * A GRH is expected to precede the data even if not * present on the wire. */ wc.byte_len = tlen + sizeof(struct ib_grh); diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c index 66208bcd7c13..82442085cbe6 100644 --- a/drivers/infiniband/hw/qib/qib_user_sdma.c +++ b/drivers/infiniband/hw/qib/qib_user_sdma.c @@ -239,7 +239,7 @@ static int qib_user_sdma_num_pages(const struct iovec *iov) } /* - * Truncate length to page boundry. + * Truncate length to page boundary. */ static int qib_user_sdma_page_length(unsigned long addr, unsigned long len) { diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index f1df01567bb6..2f02ab0ccc1e 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -91,7 +91,7 @@ #define SIZE_4K (1UL << SHIFT_4K) #define MASK_4K (~(SIZE_4K-1)) - /* support upto 512KB in one RDMA */ + /* support up to 512KB in one RDMA */ #define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K) #define ISER_DEF_CMD_PER_LUN 128 diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 3182c9cd1b0e..5688b5c88f24 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -758,7 +758,7 @@ static void joydev_remove_chrdev(struct joydev *joydev) } /* - * Mark device non-existant. This disables writes, ioctls and + * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted * blocking reads will stay, however new ones will fail. */ @@ -777,7 +777,7 @@ static void joydev_cleanup(struct joydev *joydev) joydev_hangup(joydev); joydev_remove_chrdev(joydev); - /* joydev is marked dead so noone else accesses joydev->open */ + /* joydev is marked dead so no one else accesses joydev->open */ if (joydev->open) input_close_device(handle); } diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index d259b41354b8..1639ab2b94b7 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -3,7 +3,7 @@ */ /* - * FP-Gaming Assasin 3D joystick driver for Linux + * FP-Gaming Assassin 3D joystick driver for Linux */ /* @@ -34,7 +34,7 @@ #include #include -#define DRIVER_DESC "FP-Gaming Assasin 3D joystick driver" +#define DRIVER_DESC "FP-Gaming Assassin 3D joystick driver" MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c index a91ee941b5c1..cd89d17162a3 100644 --- a/drivers/input/keyboard/davinci_keyscan.c +++ b/drivers/input/keyboard/davinci_keyscan.c @@ -5,7 +5,7 @@ * * Author: Miguel Aguilar * - * Intial Code: Sandeep Paulraj + * Initial Code: Sandeep Paulraj * * 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 diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index de5900d50788..144ddbdeb9b3 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -716,7 +716,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, pdata = dev->platform_data; if (!pdata) { dev_dbg(dev, - "No platfrom data: Using default initialization\n"); + "No platform data: Using default initialization\n"); pdata = &adxl34x_default_init; } diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index a93c525475c6..fc62256c963f 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -312,7 +312,7 @@ static void keyspan_check_data(struct usb_keyspan *remote) remote->data.tester = remote->data.tester >> 5; remote->data.bits_left -= 5; } else { - err("Bad message recieved, no stop bit found.\n"); + err("Bad message received, no stop bit found.\n"); } dev_dbg(&remote->udev->dev, diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 12501de0c5cd..52b419348983 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -274,7 +274,7 @@ static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = { { KE_BLUETOOTH, 0x30 }, /* Fn+F10 */ { KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */ { KE_KEY, 0x36, {KEY_WWW} }, /* www button */ - { KE_WIFI, 0x78 }, /* satelite dish button */ + { KE_WIFI, 0x78 }, /* satellite dish button */ { KE_END, 0 } }; diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 3aead91bacc8..3126983c004a 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -639,7 +639,7 @@ exit: * device, resulting in trackpad malfunction under certain * circumstances. To get around this problem, there is at least one * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to - * recieve a reset_resume request rather than the normal resume. + * receive a reset_resume request rather than the normal resume. * Since the implementation of reset_resume is equal to mode switch * plus start_traffic, it seems easier to always do the switch when * starting traffic on the device. diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index f6aa26d305ed..cba3c84d2f21 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -462,7 +462,7 @@ static void synaptics_i2c_work_handler(struct work_struct *work) * While interrupt driven, there is no real need to poll the device. * But touchpads are very sensitive, so there could be errors * related to physical environment and the attention line isn't - * neccesarily asserted. In such case we can lose the touchpad. + * necessarily asserted. In such case we can lose the touchpad. * We poll the device once in THREAD_IRQ_SLEEP_SECS and * if error is detected, we try to reset and reconfigure the touchpad. */ diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index bf2c0c80d6cc..eb9a3cfbeefa 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -334,7 +334,7 @@ static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse) * M: manufacturer location code * R: revision code * E: Error code. If it's in the range of 0x00..0x1f, only some - * minor problem occured. Errors >= 0x20 are considered bad + * minor problem occurred. Errors >= 0x20 are considered bad * and the device may not work properly... * D: <0010> == mouse, <0100> == tablet */ diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 8c0b51c31424..42206205e4f5 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -955,7 +955,7 @@ static int __init hp_sdc_init_hppa(struct parisc_device *d) INIT_DELAYED_WORK(&moduleloader_work, request_module_delayed); ret = hp_sdc_init(); - /* after successfull initialization give SDC some time to settle + /* after successful initialization give SDC some time to settle * and then load the hp_sdc_mlc upper layer driver */ if (!ret) schedule_delayed_work(&moduleloader_work, diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 7540bafc95cf..80baa53da5b1 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -225,7 +225,7 @@ static void sxps2_close(struct serio *pserio) /** * xps2_of_probe - probe method for the PS/2 device. * @of_dev: pointer to OF device structure - * @match: pointer to the stucture used for matching a device + * @match: pointer to the structure used for matching a device * * This function probes the PS/2 device in the device tree. * It initializes the driver data structure and the hardware. diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c index c0307b22d86f..66c96bfc5522 100644 --- a/drivers/input/touchscreen/intel-mid-touch.c +++ b/drivers/input/touchscreen/intel-mid-touch.c @@ -542,7 +542,7 @@ static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev) * ADC power on, start, enable PENDET and set loop delay * ADC loop delay is set to 4.5 ms approximately * Loop delay more than this results in jitter in adc readings - * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET + * Setting loop delay to 0 (continuous loop) in MAXIM stops PENDET * interrupt generation sometimes. */ diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 028a5363eea1..3b5b5df04dd6 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -6,7 +6,7 @@ * Copyright: MontaVista Software, Inc. * * Spliting done by: Marek Vasut - * If something doesnt work and it worked before spliting, e-mail me, + * If something doesn't work and it worked before spliting, e-mail me, * dont bother Nicolas please ;-) * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c index 6b5be742c27d..98e61175d3f5 100644 --- a/drivers/input/touchscreen/wm9705.c +++ b/drivers/input/touchscreen/wm9705.c @@ -306,7 +306,7 @@ static int wm9705_acc_enable(struct wm97xx *wm, int enable) dig2 = wm->dig[2]; if (enable) { - /* continous mode */ + /* continuous mode */ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0) return ret; diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c index 7490b05c3566..2bc2fb801009 100644 --- a/drivers/input/touchscreen/wm9712.c +++ b/drivers/input/touchscreen/wm9712.c @@ -419,7 +419,7 @@ static int wm9712_acc_enable(struct wm97xx *wm, int enable) dig2 = wm->dig[2]; if (enable) { - /* continous mode */ + /* continuous mode */ if (wm->mach_ops->acc_startup) { ret = wm->mach_ops->acc_startup(wm); if (ret < 0) diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c index 238b5132712e..73ec99568f12 100644 --- a/drivers/input/touchscreen/wm9713.c +++ b/drivers/input/touchscreen/wm9713.c @@ -431,7 +431,7 @@ static int wm9713_acc_enable(struct wm97xx *wm, int enable) dig3 = wm->dig[2]; if (enable) { - /* continous mode */ + /* continuous mode */ if (wm->mach_ops->acc_startup && (ret = wm->mach_ops->acc_startup(wm)) < 0) return ret; diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 6b75c9f660ae..5dbe73af2f8f 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -335,7 +335,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) */ if (!wm->mach_ops->acc_enabled || wm->mach_ops->acc_pen_down) { if (wm->pen_is_down && !pen_was_down) { - /* Data is not availiable immediately on pen down */ + /* Data is not available immediately on pen down */ queue_delayed_work(wm->ts_workq, &wm->ts_reader, 1); } @@ -354,7 +354,7 @@ static void wm97xx_pen_irq_worker(struct work_struct *work) * Codec PENDOWN irq handler * * We have to disable the codec interrupt in the handler because it - * can take upto 1ms to clear the interrupt source. We schedule a task + * can take up to 1ms to clear the interrupt source. We schedule a task * in a work queue to do the actual interaction with the chip. The * interrupt is then enabled again in the slow handler when the source * has been cleared. diff --git a/drivers/isdn/hardware/eicon/divacapi.h b/drivers/isdn/hardware/eicon/divacapi.h index 9f5b68037a26..e330da0c5fc0 100644 --- a/drivers/isdn/hardware/eicon/divacapi.h +++ b/drivers/isdn/hardware/eicon/divacapi.h @@ -673,7 +673,7 @@ struct async_s { /*------------------------------------------------------------------*/ -/* auxilliary states for supplementary services */ +/* auxiliary states for supplementary services */ /*------------------------------------------------------------------*/ #define IDLE 0 diff --git a/drivers/isdn/hardware/eicon/io.h b/drivers/isdn/hardware/eicon/io.h index 0c6c650d76bb..a6f175596364 100644 --- a/drivers/isdn/hardware/eicon/io.h +++ b/drivers/isdn/hardware/eicon/io.h @@ -60,7 +60,7 @@ typedef struct _diva_xdi_capi_cfg { -------------------------------------------------------------------------- */ struct _ISDN_ADAPTER { void (* DIRequest)(PISDN_ADAPTER, ENTITY *) ; - int State ; /* from NT4 1.srv, a good idea, but a poor achievment */ + int State ; /* from NT4 1.srv, a good idea, but a poor achievement */ int Initialized ; int RegisteredWithDidd ; int Unavailable ; /* callback function possible? */ diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 341ef17c22ac..8c5c563c4f12 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -2639,7 +2639,7 @@ static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, } else { - /* local reply if assign unsuccessfull + /* local reply if assign unsuccessful or B3 protocol allows only one layer 3 connection and already connected or B2 protocol not any LAPD @@ -8189,7 +8189,7 @@ static word add_b23(PLCI *plci, API_PARSE *bp) dlc[ 0] = 15; if(b2_config->length >= 8) { /* PIAFS control abilities */ dlc[ 7] = 10; - dlc[16] = 2; /* Length of PIAFS extention */ + dlc[16] = 2; /* Length of PIAFS extension */ dlc[17] = PIAFS_UDATA_ABILITIES; /* control (UDATA) ability */ dlc[18] = b2_config_parms[4].info[0]; /* value */ dlc[ 0] = 18; diff --git a/drivers/isdn/hardware/eicon/pc.h b/drivers/isdn/hardware/eicon/pc.h index 1c6945768a35..bf6b01812400 100644 --- a/drivers/isdn/hardware/eicon/pc.h +++ b/drivers/isdn/hardware/eicon/pc.h @@ -701,7 +701,7 @@ Byte | 8 7 6 5 4 3 2 1 #define PROTCAP_FREE12 0x1000 /* not used */ #define PROTCAP_FREE13 0x2000 /* not used */ #define PROTCAP_FREE14 0x4000 /* not used */ -#define PROTCAP_EXTENSION 0x8000 /* used for future extentions */ +#define PROTCAP_EXTENSION 0x8000 /* used for future extensions */ /* -----------------------------------------------------------* */ /* Onhook data transmission ETS30065901 */ /* Message Type */ diff --git a/drivers/isdn/hardware/eicon/um_idi.c b/drivers/isdn/hardware/eicon/um_idi.c index 6563db998d06..ac0bdd1f23fa 100644 --- a/drivers/isdn/hardware/eicon/um_idi.c +++ b/drivers/isdn/hardware/eicon/um_idi.c @@ -363,7 +363,7 @@ int diva_um_idi_read(void *entity, if ((ret = (*cp_fn) (os_handle, dst, data, length)) >= 0) { /* - Acknowledge only if read was successfull + Acknowledge only if read was successful */ diva_data_q_ack_segment4read(q); } diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 4e3780d78ac7..f6f3c87cc7c2 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -118,7 +118,7 @@ * -> See hfc_multi.h for HFC_IO_MODE_* values * By default, the IO mode is pci memory IO (MEMIO). * Some cards require specific IO mode, so it cannot be changed. - * It may be usefull to set IO mode to register io (REGIO) to solve + * It may be useful to set IO mode to register io (REGIO) to solve * PCI bridge problems. * If unsure, don't give this parameter. * @@ -903,7 +903,7 @@ vpm_echocan_off(struct hfc_multi *hc, int ch) /* * Speech Design resync feature * NOTE: This is called sometimes outside interrupt handler. - * We must lock irqsave, so no other interrupt (other card) will occurr! + * We must lock irqsave, so no other interrupt (other card) will occur! * Also multiple interrupts may nest, so must lock each access (lists, card)! */ static inline void diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index 15d323b8be60..4343abac0b13 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -272,7 +272,7 @@ reset_hfcpci(struct hfc_pci *hc) * D- and monitor/CI channel are not enabled * STIO1 is used as output for data, B1+B2 from ST->IOM+HFC * STIO2 is used as data input, B1+B2 from IOM->ST - * ST B-channel send disabled -> continous 1s + * ST B-channel send disabled -> continuous 1s * The IOM slots are always enabled */ if (test_bit(HFC_CFG_PCM, &hc->cfg)) { diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 3147020d188b..0cb0546ead88 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -146,7 +146,7 @@ reset_hfcpci(struct IsdnCardState *cs) /* D- and monitor/CI channel are not enabled */ /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ /* STIO2 is used as data input, B1+B2 from IOM->ST */ - /* ST B-channel send disabled -> continous 1s */ + /* ST B-channel send disabled -> continuous 1s */ /* The IOM slots are always enabled */ cs->hw.hfcpci.conn = 0x36; /* set data flow directions */ Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c index 1235b7131ae1..156d7c63d944 100644 --- a/drivers/isdn/hisax/hfc_sx.c +++ b/drivers/isdn/hisax/hfc_sx.c @@ -399,7 +399,7 @@ reset_hfcsx(struct IsdnCardState *cs) /* D- and monitor/CI channel are not enabled */ /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ /* STIO2 is used as data input, B1+B2 from IOM->ST */ - /* ST B-channel send disabled -> continous 1s */ + /* ST B-channel send disabled -> continuous 1s */ /* The IOM slots are always enabled */ cs->hw.hfcsx.conn = 0x36; /* set data flow directions */ Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h index e79f56568d30..2f581c0b4693 100644 --- a/drivers/isdn/hisax/hfc_usb.h +++ b/drivers/isdn/hisax/hfc_usb.h @@ -126,7 +126,7 @@ static struct hfcusb_symbolic_list urb_errlist[] = { /* - * device dependant information to support different + * device dependent information to support different * ISDN Ta's using the HFC-S USB chip */ diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index cc6ee2d39880..8e2fd02ecce0 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -1595,7 +1595,7 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) * Bearer Capabilities */ p = skb->data; - /* only the first occurence 'll be detected ! */ + /* only the first occurrence 'll be detected ! */ if ((p = findie(p, skb->len, 0x04, 0))) { if ((p[1] < 2) || (p[1] > 11)) err = 1; @@ -2161,7 +2161,7 @@ static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) /***********************************************/ /* handle special commands for this protocol. */ -/* Examples are call independant services like */ +/* Examples are call independent services like */ /* remote operations with dummy callref. */ /***********************************************/ static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic) diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c index f9584491fe8e..7b229c0ce115 100644 --- a/drivers/isdn/hisax/l3ni1.c +++ b/drivers/isdn/hisax/l3ni1.c @@ -1449,7 +1449,7 @@ l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) * Bearer Capabilities */ p = skb->data; - /* only the first occurence 'll be detected ! */ + /* only the first occurrence 'll be detected ! */ if ((p = findie(p, skb->len, 0x04, 0))) { if ((p[1] < 2) || (p[1] > 11)) err = 1; @@ -2017,7 +2017,7 @@ static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) /***********************************************/ /* handle special commands for this protocol. */ -/* Examples are call independant services like */ +/* Examples are call independent services like */ /* remote operations with dummy callref. */ /***********************************************/ static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c index 2344e7b33448..a1b89524b505 100644 --- a/drivers/isdn/hisax/nj_s.c +++ b/drivers/isdn/hisax/nj_s.c @@ -167,7 +167,7 @@ static int __devinit njs_pci_probe(struct pci_dev *dev_netjet, return(0); } /* the TJ300 and TJ320 must be detected, the IRQ handling is different - * unfortunatly the chips use the same device ID, but the TJ320 has + * unfortunately the chips use the same device ID, but the TJ320 has * the bit20 in status PCI cfg register set */ pci_read_config_dword(dev_netjet, 0x04, &cfg); diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index e56e5af889b6..ed4bc564dc63 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -124,7 +124,7 @@ static void usb_b_out(struct st5481_bcs *bcs,int buf_nr) } /* - * Start transfering (flags or data) on the B channel, since + * Start transferring (flags or data) on the B channel, since * FIFO counters has been set to a non-zero value. */ static void st5481B_start_xfer(void *context) diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index 10d41c5d73ed..159e8fa00fd6 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -470,7 +470,7 @@ void st5481_release_isocpipes(struct urb* urb[2]) /* * Decode frames received on the B/D channel. - * Note that this function will be called continously + * Note that this function will be called continuously * with 64Kbit/s / 16Kbit/s of data and hence it will be * called 50 times per second with 20 ISOC descriptors. * Called at interrupt. diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 282a4467ef19..aa25e183bf79 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c @@ -9,7 +9,7 @@ Also inspired by ELSA PCMCIA driver by Klaus Lichtenwalder - Extentions to new hisax_pcmcia by Karsten Keil + Extensions to new hisax_pcmcia by Karsten Keil minor changes to be compatible with kernel 2.4.x by Jan.Schubert@GMX.li diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c index 81db4a190d41..3674d30d6a03 100644 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ b/drivers/isdn/hysdn/hysdn_sched.c @@ -143,7 +143,7 @@ hysdn_sched_tx(hysdn_card *card, unsigned char *buf, /* send one config line to the card and return 0 if successful, otherwise a */ /* negative error code. */ /* The function works with timeouts perhaps not giving the greatest speed */ -/* sending the line, but this should be meaningless beacuse only some lines */ +/* sending the line, but this should be meaningless because only some lines */ /* are to be sent and this happens very seldom. */ /*****************************************************************************/ int diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index afeede7ee295..2a7d17c19489 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1530,7 +1530,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) printk (KERN_WARNING "UPDOWN: Line protocol on Interface %s," " changed state to down\n", lp->netdev->dev->name); - /* should stop routing higher-level data accross */ + /* should stop routing higher-level data across */ } else if ((!lp->cisco_line_state) && (myseq_diff >= 0) && (myseq_diff <= 2)) { /* line down -> up */ @@ -1538,7 +1538,7 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) printk (KERN_WARNING "UPDOWN: Line protocol on Interface %s," " changed state to up\n", lp->netdev->dev->name); - /* restart routing higher-level data accross */ + /* restart routing higher-level data across */ } if (lp->cisco_debserint) diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 9e8162c80bb0..1b002b0002a4 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1514,7 +1514,7 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) #define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1) #define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1) -/* sequence-wrap safe comparisions (for long sequence)*/ +/* sequence-wrap safe comparisons (for long sequence)*/ #define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT) #define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT) #define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT) @@ -1746,7 +1746,7 @@ static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, * then next fragment should be the start of new reassembly * if sequence is contiguous, but we haven't reassembled yet, * keep going. - * if sequence is not contiguous, either clear everyting + * if sequence is not contiguous, either clear everything * below low watermark and set start to the next frag or * clear start ptr. */ diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 3d88f15aa218..607d846ae063 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -792,7 +792,7 @@ isdn_tty_suspend(char *id, modem_info * info, atemu * m) } /* isdn_tty_resume() tries to resume a suspended call - * setup of the lower levels before that. unfortunatly here is no + * setup of the lower levels before that. unfortunately here is no * checking for compatibility of used protocols implemented by Q931 * It does the same things like isdn_tty_dial, the last command * is different, may be we can merge it. diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index b8a1098b66ed..d497db0a26d0 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -954,7 +954,7 @@ isdnloop_parse_cmd(isdnloop_card * card) /* * Put command-strings into the of the 'card'. In reality, execute them * right in place by calling isdnloop_parse_cmd(). Also copy every - * command to the read message ringbuffer, preceeding it with a '>'. + * command to the read message ringbuffer, preceding it with a '>'. * These mesagges can be read at /dev/isdnctrl. * * Parameter: diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 18af86879c05..8549431430f0 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -21,7 +21,7 @@ /* options may be: * * bit 0 = use ulaw instead of alaw - * bit 1 = enable hfc hardware accelleration for all channels + * bit 1 = enable hfc hardware acceleration for all channels * */ #define DSP_OPT_ULAW (1<<0) diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 309bacf1fadc..4d395dea32f3 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1513,7 +1513,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) /* -> if echo is NOT enabled */ if (!dsp->echo.software) { /* - * -> substract rx-data from conf-data, + * -> subtract rx-data from conf-data, * if tx-data is available, mix */ while (r != rr && t != tt) { @@ -1572,7 +1572,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) send_packet: /* * send tx-data if enabled - don't filter, - * becuase we want what we send, not what we filtered + * because we want what we send, not what we filtered */ if (dsp->tx_data) { if (tx_data_only) { diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 6f5b54864283..2877291a9ed8 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -115,7 +115,7 @@ * * The CMX has special functions for conferences with one, two and more * members. It will allow different types of data flow. Receive and transmit - * data to/form upper layer may be swithed on/off individually without loosing + * data to/form upper layer may be swithed on/off individually without losing * features of CMX, Tones and DTMF. * * Echo Cancellation: Sometimes we like to cancel echo from the interface. @@ -127,9 +127,9 @@ * * If all used features can be realized in hardware, and if transmit and/or * receive data ist disabled, the card may not send/receive any data at all. - * Not receiving is usefull if only announcements are played. Not sending is - * usefull if an answering machine records audio. Not sending and receiving is - * usefull during most states of the call. If supported by hardware, tones + * Not receiving is useful if only announcements are played. Not sending is + * useful if an answering machine records audio. Not sending and receiving is + * useful during most states of the call. If supported by hardware, tones * will be played without cpu load. Small PBXs and NT-Mode applications will * not need expensive hardware when processing calls. * diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c index 9ae2d33b06f7..5b484c3f4af6 100644 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ b/drivers/isdn/mISDN/dsp_dtmf.c @@ -106,7 +106,7 @@ void dsp_dtmf_hardware(struct dsp *dsp) * tested it allot. it even works with very short tones (40ms). the only * disadvantage is, that it doesn't work good with different volumes of both * tones. this will happen, if accoustically coupled dialers are used. - * it sometimes detects tones during speach, which is normal for decoders. + * it sometimes detects tones during speech, which is normal for decoders. * use sequences to given commands during calls. * * dtmf - points to a structure of the current dtmf state @@ -244,7 +244,7 @@ coefficients: if (result[i] < tresh) { lowgroup = -1; highgroup = -1; - break; /* noise inbetween */ + break; /* noise in between */ } /* good level found. This is allowed only one time per group */ if (i < NCOEFF/2) { diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c index 7dbe54ed1deb..4e4440e8bae5 100644 --- a/drivers/isdn/mISDN/dsp_tones.c +++ b/drivers/isdn/mISDN/dsp_tones.c @@ -394,7 +394,7 @@ void dsp_tone_copy(struct dsp *dsp, u8 *data, int len) while (len) { /* find sample to start with */ while (42) { - /* warp arround */ + /* wrap around */ if (!pat->seq[index]) { count = 0; index = 0; diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index bd526f664a39..22f8ec8b9247 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -179,7 +179,7 @@ NOTE: A value of 0 equals 256 bytes of data. - Time Base = Timestamp of first sample in frame The "Time Base" is used to rearange packets and to detect packet loss. The 16 bits are sent in network order (MSB first) and count 1/8000 th of a -second. This causes a wrap arround each 8,192 seconds. There is no requirement +second. This causes a wrap around each 8,192 seconds. There is no requirement for the initial "Time Base", but 0 should be used for the first packet. In case of HDLC data, this timestamp counts the packet or byte number. @@ -205,7 +205,7 @@ On Demand: If the ondemand parameter is given, the remote IP is set to 0 on timeout. This will stop keepalive traffic to remote. If the remote is online again, -traffic will continue to the remote address. This is usefull for road warriors. +traffic will continue to the remote address. This is useful for road warriors. This feature only works with ID set, otherwhise it is highly unsecure. @@ -590,7 +590,7 @@ multiframe: return; } } else - mlen = len-2; /* single frame, substract timebase */ + mlen = len-2; /* single frame, subtract timebase */ if (len < 2) { printk(KERN_WARNING "%s: packet error - packet too short, time " diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 4ae75053c9d2..d0aeb44ee7c0 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -1864,7 +1864,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) psapi >>= 2; ptei >>= 1; if (psapi != l2->sapi) { - /* not our bussiness */ + /* not our business */ if (*debug & DEBUG_L2) printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n", __func__, psapi, l2->sapi); @@ -1872,7 +1872,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) return 0; } if ((ptei != l2->tei) && (ptei != GROUP_TEI)) { - /* not our bussiness */ + /* not our business */ if (*debug & DEBUG_L2) printk(KERN_DEBUG "%s: tei %d/%d mismatch\n", __func__, ptei, l2->tei); diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index afac338d5025..5bf63af09ddf 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -58,7 +58,7 @@ static struct i2c_driver pca9532_driver = { .id_table = pca9532_id, }; -/* We have two pwm/blinkers, but 16 possible leds to drive. Additionaly, +/* We have two pwm/blinkers, but 16 possible leds to drive. Additionally, * the clever Thecus people are using one pwm to drive the beeper. So, * as a compromise we average one pwm to the values requested by all * leds that are not ON/OFF. diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c index a04523273282..f14edd82cb00 100644 --- a/drivers/leds/leds-wm8350.c +++ b/drivers/leds/leds-wm8350.c @@ -215,13 +215,13 @@ static int wm8350_led_probe(struct platform_device *pdev) isink = regulator_get(&pdev->dev, "led_isink"); if (IS_ERR(isink)) { - printk(KERN_ERR "%s: cant get ISINK\n", __func__); + printk(KERN_ERR "%s: can't get ISINK\n", __func__); return PTR_ERR(isink); } dcdc = regulator_get(&pdev->dev, "led_vcc"); if (IS_ERR(dcdc)) { - printk(KERN_ERR "%s: cant get DCDC\n", __func__); + printk(KERN_ERR "%s: can't get DCDC\n", __func__); ret = PTR_ERR(dcdc); goto err_isink; } diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 3c781cdddda9..948c547b8e9e 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -130,7 +130,7 @@ static int add_eventfd(struct lguest *lg, unsigned long addr, int fd) rcu_assign_pointer(lg->eventfds, new); /* - * We're not in a big hurry. Wait until noone's looking at old + * We're not in a big hurry. Wait until no one's looking at old * version, then free it. */ synchronize_rcu(); diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 5396c67ba0a4..09d72bb00d12 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c @@ -328,7 +328,7 @@ adbhid_input_keycode(int id, int scancode, int repeat) switch (keycode) { case ADB_KEY_CAPSLOCK: if (!restore_capslock_events) { - /* Generate down/up events for CapsLock everytime. */ + /* Generate down/up events for CapsLock every time. */ input_report_key(ahid->input, KEY_CAPSLOCK, 1); input_sync(ahid->input); input_report_key(ahid->input, KEY_CAPSLOCK, 0); diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c index bd6da7a9c55b..b6ef8f590764 100644 --- a/drivers/macintosh/macio-adb.c +++ b/drivers/macintosh/macio-adb.c @@ -147,7 +147,7 @@ static int macio_adb_reset_bus(void) /* Hrm... we may want to not lock interrupts for so * long ... oh well, who uses that chip anyway ? :) - * That function will be seldomly used during boot + * That function will be seldom used during boot * on rare machines, so... */ spin_lock_irqsave(&macio_lock, flags); diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 9e3e2c566598..02367308ff2e 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -662,7 +662,7 @@ static void thermostat_create_files(void) err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); if (err) printk(KERN_WARNING - "Failed to create tempertaure attribute file(s).\n"); + "Failed to create temperature attribute file(s).\n"); } static void thermostat_remove_files(void) diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index bca2af2e3760..d25df48b437b 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -91,7 +91,7 @@ * * Mar. 10, 2005 : 1.2 * - Add basic support for Xserve G5 - * - Retreive pumps min/max from EEPROM image in device-tree (broken) + * - Retrieve pumps min/max from EEPROM image in device-tree (broken) * - Use min/max macros here or there * - Latest darwin updated U3H min fan speed to 20% PWM * @@ -375,7 +375,7 @@ static int read_smon_adc(struct cpu_pid_state *state, int chan) rc = i2c_master_send(state->monitor, buf, 2); if (rc <= 0) goto error; - /* Wait for convertion */ + /* Wait for conversion */ msleep(1); /* Switch to data register */ buf[0] = 4; @@ -1192,7 +1192,7 @@ static int init_cpu_state(struct cpu_pid_state *state, int index) err |= device_create_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm); } if (err) - printk(KERN_WARNING "Failed to create some of the atribute" + printk(KERN_WARNING "Failed to create some of the attribute" "files for CPU %d\n", index); return 0; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index d37819fd5ad3..46c4e95f10d6 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -45,7 +45,7 @@ #include #include -#define LOG_TEMP 0 /* continously log temperature */ +#define LOG_TEMP 0 /* continuously log temperature */ static struct { volatile int running; diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index 931a7a7c3796..d0aeaf46d932 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -45,7 +45,7 @@ * * The counter counts pending write requests, plus the on-disk bit. * When the counter is '1' and the resync bits are clear, the on-disk - * bit can be cleared aswell, thus setting the counter to 0. + * bit can be cleared as well, thus setting the counter to 0. * When we set a bit, or in the counter (to start a write), if the fields is * 0, we first set the disk bit and set the counter to 1. * diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index dad011aed0c9..7771ed212182 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -419,7 +419,7 @@ void dm_rh_mark_nosync(struct dm_region_hash *rh, struct bio *bio) /* * Possible cases: * 1) DM_RH_DIRTY - * 2) DM_RH_NOSYNC: was dirty, other preceeding writes failed + * 2) DM_RH_NOSYNC: was dirty, other preceding writes failed * 3) DM_RH_RECOVERING: flushing pending writes * Either case, the region should have not been connected to list. */ diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 339fdc670751..23078dabb6df 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -30,7 +30,7 @@ * * Different modes can be active at a time, but only * one can be set at array creation. Others can be added later. - * A mode can be one-shot or recurrent with the recurrance being + * A mode can be one-shot or recurrent with the recurrence being * once in every N requests. * The bottom 5 bits of the "layout" indicate the mode. The * remainder indicate a period, or 0 for one-shot. diff --git a/drivers/md/md.c b/drivers/md/md.c index 8b66e04c2ea6..b12b3776c0c0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -6266,7 +6266,7 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev) * rt is a sector_t, so could be 32bit or 64bit. * So we divide before multiply in case it is 32bit and close * to the limit. - * We scale the divisor (db) by 32 to avoid loosing precision + * We scale the divisor (db) by 32 to avoid losing precision * near the end of resync when the number of remaining sectors * is close to 'db'. * We then divide rt by 32 after multiplying by db to compensate. diff --git a/drivers/md/md.h b/drivers/md/md.h index 12215d437fcc..52b407369e13 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -94,7 +94,7 @@ struct mdk_rdev_s #define In_sync 2 /* device is in_sync with rest of array */ #define WriteMostly 4 /* Avoid reading if at all possible */ #define AutoDetected 7 /* added by auto-detect */ -#define Blocked 8 /* An error occured on an externally +#define Blocked 8 /* An error occurred on an externally * managed array, don't allow writes * until it is cleared */ wait_queue_head_t blocked_wait; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index f7b62370b374..2da83d566592 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -5,7 +5,7 @@ * * RAID-10 support for md. * - * Base on code in raid1.c. See raid1.c for futher copyright information. + * Base on code in raid1.c. See raid1.c for further copyright information. * * * This program is free software; you can redistribute it and/or modify @@ -340,14 +340,14 @@ static void raid10_end_write_request(struct bio *bio, int error) /* * RAID10 layout manager - * Aswell as the chunksize and raid_disks count, there are two + * As well as the chunksize and raid_disks count, there are two * parameters: near_copies and far_copies. * near_copies * far_copies must be <= raid_disks. * Normally one of these will be 1. * If both are 1, we get raid0. * If near_copies == raid_disks, we get raid1. * - * Chunks are layed out in raid0 style with near_copies copies of the + * Chunks are laid out in raid0 style with near_copies copies of the * first chunk, followed by near_copies copies of the next chunk and * so on. * If far_copies > 1, then after 1/far_copies of the array has been assigned diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index 2316ac2e8e21..944b1104d3b4 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -17,8 +17,8 @@ struct r10_private_data_s { spinlock_t device_lock; /* geometry */ - int near_copies; /* number of copies layed out raid0 style */ - int far_copies; /* number of copies layed out + int near_copies; /* number of copies laid out raid0 style */ + int far_copies; /* number of copies laid out * at large strides across drives */ int far_offset; /* far_copies are offset by 1 stripe diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c index 74ee172b5bc9..b2ba9dc0dd6d 100644 --- a/drivers/media/common/saa7146_i2c.c +++ b/drivers/media/common/saa7146_i2c.c @@ -161,7 +161,7 @@ static int saa7146_i2c_reset(struct saa7146_dev *dev) msleep(SAA7146_I2C_DELAY); } - /* if any error is still present, a fatal error has occured ... */ + /* if any error is still present, a fatal error has occurred ... */ status = saa7146_i2c_status(dev); if ( dev->i2c_bitrate != status ) { DEB_I2C(("fatal error. status:0x%08x\n",status)); @@ -326,9 +326,9 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m if ( 0 != err) { /* this one is unsatisfying: some i2c slaves on some dvb cards don't acknowledge correctly, so the saa7146 - thinks that an address error occured. in that case, the + thinks that an address error occurred. in that case, the transaction should be retrying, even if an address error - occured. analog saa7146 based cards extensively rely on + occurred. analog saa7146 based cards extensively rely on i2c address probing, however, and address errors indicate that a device is really *not* there. retrying in that case increases the time the device needs to probe greatly, so @@ -365,7 +365,7 @@ static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *m DEB_I2C(("transmission successful. (msg:%d).\n",err)); out: /* another bug in revision 0: the i2c-registers get uploaded randomly by other - uploads, so we better clear them out before continueing */ + uploads, so we better clear them out before continuing */ if( 0 == dev->revision ) { __le32 zero = 0; saa7146_i2c_reset(dev); diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c index 605e28b73263..0d6e09419044 100644 --- a/drivers/media/common/tuners/mxl5005s.c +++ b/drivers/media/common/tuners/mxl5005s.c @@ -106,7 +106,7 @@ enum { /* MXL5005 Tuner Register Struct */ struct TunerReg { u16 Reg_Num; /* Tuner Register Address */ - u16 Reg_Val; /* Current sw programmed value waiting to be writen */ + u16 Reg_Val; /* Current sw programmed value waiting to be written */ }; enum { diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h index 3abb221f3d07..50cfa8cebb93 100644 --- a/drivers/media/common/tuners/tda18271.h +++ b/drivers/media/common/tuners/tda18271.h @@ -98,7 +98,7 @@ struct tda18271_config { /* output options that can be disabled */ enum tda18271_output_options output_opt; - /* some i2c providers cant write all 39 registers at once */ + /* some i2c providers can't write all 39 registers at once */ enum tda18271_small_i2c small_i2c; /* force rf tracking filter calibration on startup */ diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 227c0200b70a..955254090a0e 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -58,7 +58,7 @@ struct flexcop_pci { int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */ u32 last_dma1_cur_pos; - /* position of the pointer last time the timer/packet irq occured */ + /* position of the pointer last time the timer/packet irq occurred */ int count; int count_prev; int stream_problem; diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 78fc469f0f69..1e1106dcd063 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -427,10 +427,10 @@ static void or51211_reset(struct dvb_frontend * fe) struct dvb_bt8xx_card *bt = fe->dvb->priv; /* RESET DEVICE - * reset is controled by GPIO-0 + * reset is controlled by GPIO-0 * when set to 0 causes reset and when to 1 for normal op * must remain reset for 128 clock cycles on a 50Mhz clock - * also PRM1 PRM2 & PRM4 are controled by GPIO-1,GPIO-2 & GPIO-4 + * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4 * We assume that the reset has be held low long enough or we * have been reset by a power on. When the driver is unloaded * reset set to 0 so if reloaded we have been reset. diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index cad6634610ea..31e2c0d45db3 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1638,7 +1638,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, case FE_READ_STATUS: { fe_status_t* status = parg; - /* if retune was requested but hasn't occured yet, prevent + /* if retune was requested but hasn't occurred yet, prevent * that user get signal state from previous tuning */ if (fepriv->state == FESTATE_RETUNE || fepriv->state == FESTATE_ERROR) { @@ -1729,7 +1729,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, * Dish network legacy switches (as used by Dish500) * are controlled by sending 9-bit command words * spaced 8msec apart. - * the actual command word is switch/port dependant + * the actual command word is switch/port dependent * so it is up to the userspace application to send * the right command. * The command must always start with a '0' after diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c index 199ece0d4883..6ad94745bbdd 100644 --- a/drivers/media/dvb/dvb-usb/af9005-fe.c +++ b/drivers/media/dvb/dvb-usb/af9005-fe.c @@ -580,7 +580,7 @@ static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw) NS_coeff2_8k = 0x724925; break; default: - err("Invalid bandwith %d.", bw); + err("Invalid bandwidth %d.", bw); return -EINVAL; } @@ -789,7 +789,7 @@ static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw) temp = 2; break; default: - err("Invalid bandwith %d.", bw); + err("Invalid bandwidth %d.", bw); return -EINVAL; } return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos, @@ -930,7 +930,7 @@ static int af9005_fe_init(struct dvb_frontend *fe) if (ret) return ret; - /* init other parameters: program cfoe and select bandwith */ + /* init other parameters: program cfoe and select bandwidth */ deb_info("program cfoe\n"); if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ))) return ret; @@ -1167,7 +1167,7 @@ static int af9005_fe_set_frontend(struct dvb_frontend *fe, if (ret) return ret; - /* select bandwith */ + /* select bandwidth */ deb_info("select bandwidth"); ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth); if (ret) diff --git a/drivers/media/dvb/dvb-usb/friio.h b/drivers/media/dvb/dvb-usb/friio.h index af8d55e390fb..0f461ca10cb9 100644 --- a/drivers/media/dvb/dvb-usb/friio.h +++ b/drivers/media/dvb/dvb-usb/friio.h @@ -20,7 +20,7 @@ * Frontend: comtech JDVBT-90502 * (tuner PLL: tua6034, I2C addr:(0xC0 >> 1)) * (OFDM demodulator: TC90502, I2C addr:(0x30 >> 1)) - * LED x3 (+LNB) controll: PIC 16F676 + * LED x3 (+LNB) control: PIC 16F676 * EEPROM: 24C08 * * (USB smart card reader: AU9522) diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index cd26e7c1536a..f2db01212ca1 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -321,7 +321,7 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap) lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC); - info("INT Interupt Service Started"); + info("INT Interrupt Service Started"); return 0; } @@ -482,7 +482,7 @@ static int lme2510_msg(struct dvb_usb_device *d, break; } - deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)", + deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)", wbuf[3], rbuf[1]); } @@ -632,11 +632,11 @@ static int lme2510_int_service(struct dvb_usb_adapter *adap) } d->rc_dev = rc; - /* Start the Interupt */ + /* Start the Interrupt */ ret = lme2510_int_read(adap); if (ret < 0) { rc_unregister_device(rc); - info("INT Unable to start Interupt Service"); + info("INT Unable to start Interrupt Service"); return -ENODEV; } @@ -1003,7 +1003,7 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) return -ENODEV; } - /* Start the Interupt & Remote*/ + /* Start the Interrupt & Remote*/ ret = lme2510_int_service(adap); return ret; @@ -1171,7 +1171,7 @@ void *lme2510_exit_int(struct dvb_usb_device *d) usb_kill_urb(st->lme_urb); usb_free_coherent(d->udev, 5000, st->buffer, st->lme_urb->transfer_dma); - info("Interupt Service Stopped"); + info("Interrupt Service Stopped"); rc_unregister_device(d->rc_dev); info("Remote Stopped"); } diff --git a/drivers/media/dvb/frontends/atbm8830.h b/drivers/media/dvb/frontends/atbm8830.h index e8149f393300..024273374bd8 100644 --- a/drivers/media/dvb/frontends/atbm8830.h +++ b/drivers/media/dvb/frontends/atbm8830.h @@ -39,7 +39,7 @@ struct atbm8830_config { /* parallel or serial transport stream */ u8 serial_ts; - /* transport stream clock output only when receving valid stream */ + /* transport stream clock output only when receiving valid stream */ u8 ts_clk_gated; /* Decoder sample TS data at rising edge of clock */ diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c index 65f6a36dfb21..1d572940e243 100644 --- a/drivers/media/dvb/frontends/au8522_dig.c +++ b/drivers/media/dvb/frontends/au8522_dig.c @@ -635,7 +635,7 @@ static int au8522_led_gpio_enable(struct au8522_state *state, int onoff) struct au8522_led_config *led_config = state->config->led_cfg; u8 val; - /* bail out if we cant control an LED */ + /* bail out if we can't control an LED */ if (!led_config || !led_config->gpio_output || !led_config->gpio_output_enable || !led_config->gpio_output_disable) return 0; @@ -665,7 +665,7 @@ static int au8522_led_ctrl(struct au8522_state *state, int led) struct au8522_led_config *led_config = state->config->led_cfg; int i, ret = 0; - /* bail out if we cant control an LED */ + /* bail out if we can't control an LED */ if (!led_config || !led_config->gpio_leds || !led_config->num_led_states || !led_config->led_states) return 0; @@ -803,7 +803,7 @@ static int au8522_led_status(struct au8522_state *state, const u16 *snr) int led; u16 strong; - /* bail out if we cant control an LED */ + /* bail out if we can't control an LED */ if (!led_config) return 0; diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index cf5e576dfdcf..8aff5868a5e1 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -155,7 +155,7 @@ static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len) unsigned long t; /* Check if any previous HAB request still needs to be serviced by the - * Aquisition Processor before sending new request */ + * Acquisition Processor before sending new request */ if ((ret = bcm3510_readB(st,0xa8,&v)) < 0) return ret; if (v.HABSTAT_a8.HABR) { @@ -361,7 +361,7 @@ static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a) /* Set duration of the initial state of TUNCTL = 3.34 micro Sec */ c.TUNCTL_state = 0x40; -/* PRESCALER DEVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */ +/* PRESCALER DIVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */ c.ctl_dat[0].ctrl.size = BITS_8; c.ctl_dat[0].data = 0x80 | bc; @@ -397,7 +397,7 @@ static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a) c.ctl_dat[7].ctrl.cs0 = 1; c.ctl_dat[7].data = 0x40; -/* PRESCALER DEVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */ +/* PRESCALER DIVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */ c.ctl_dat[8].ctrl.size = BITS_8; c.ctl_dat[8].data = 0x80; diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 5fbc0fc37ecd..0142214b0133 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -179,7 +179,7 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet cx22700_writereg (state, 0x06, val); cx22700_writereg (state, 0x08, 0x04 | 0x02); /* use user tps parameters */ - cx22700_writereg (state, 0x08, 0x04); /* restart aquisition */ + cx22700_writereg (state, 0x08, 0x04); /* restart acquisition */ return 0; } diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index ff6c4983051c..3139558148ba 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -55,7 +55,7 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages"); /* Register values to initialise the demod */ static const u8 init_tab[] = { - 0x00, 0x00, /* Stop aquisition */ + 0x00, 0x00, /* Stop acquisition */ 0x0B, 0x06, 0x09, 0x01, 0x0D, 0x41, @@ -310,7 +310,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, & 0xfc); cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); - cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */ + cx22702_writereg(state, 0x00, 0x01); /* Begin acquisition */ dprintk("%s: Autodetecting\n", __func__); return 0; } @@ -424,7 +424,7 @@ static int cx22702_set_tps(struct dvb_frontend *fe, cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40); - /* Begin channel aquisition */ + /* Begin channel acquisition */ cx22702_writereg(state, 0x00, 0x01); return 0; diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index 7a1a5bc337d8..bf9c999aa470 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -544,7 +544,7 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par cx24110_set_inversion (state, p->inversion); cx24110_set_fec (state, p->u.qpsk.fec_inner); cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); - cx24110_writereg(state,0x04,0x05); /* start aquisition */ + cx24110_writereg(state,0x04,0x05); /* start acquisition */ return 0; } diff --git a/drivers/media/dvb/frontends/cx24113.h b/drivers/media/dvb/frontends/cx24113.h index 5de0f7ffd8d2..01eb7b9c28f4 100644 --- a/drivers/media/dvb/frontends/cx24113.h +++ b/drivers/media/dvb/frontends/cx24113.h @@ -1,5 +1,5 @@ /* - * Driver for Conexant CX24113/CX24128 Tuner (Satelite) + * Driver for Conexant CX24113/CX24128 Tuner (Satellite) * * Copyright (C) 2007-8 Patrick Boettcher * diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index fad6a990a39b..b1dd8acc607a 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -949,7 +949,7 @@ static int cx24123_set_frontend(struct dvb_frontend *fe, else err("it seems I don't have a tuner..."); - /* Enable automatic aquisition and reset cycle */ + /* Enable automatic acquisition and reset cycle */ cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07)); cx24123_writereg(state, 0x00, 0x10); cx24123_writereg(state, 0x00, 0); diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c index a05007c80985..536f02b17338 100644 --- a/drivers/media/dvb/frontends/drx397xD.c +++ b/drivers/media/dvb/frontends/drx397xD.c @@ -1097,7 +1097,7 @@ static int drx397x_init(struct dvb_frontend *fe) s->config.ifagc.w0A = 0x3ff; s->config.ifagc.w0C = 0x388; - /* for signal strenght calculations */ + /* for signal strength calculations */ s->config.ss76 = 820; s->config.ss78 = 2200; s->config.ss7A = 150; diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c index 33b63235b86e..c283112051b1 100644 --- a/drivers/media/dvb/frontends/mb86a16.c +++ b/drivers/media/dvb/frontends/mb86a16.c @@ -1630,7 +1630,7 @@ static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe, state->srate = p->u.qpsk.symbol_rate / 1000; if (!mb86a16_set_fe(state)) { - dprintk(verbose, MB86A16_ERROR, 1, "Succesfully acquired LOCK"); + dprintk(verbose, MB86A16_ERROR, 1, "Successfully acquired LOCK"); return DVBFE_ALGO_SEARCH_SUCCESS; } diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c index cc4acd2f920d..0f867a5055fb 100644 --- a/drivers/media/dvb/frontends/mb86a20s.c +++ b/drivers/media/dvb/frontends/mb86a20s.c @@ -406,7 +406,7 @@ err: printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n"); } else { state->need_init = false; - dprintk("Initialization succeded.\n"); + dprintk("Initialization succeeded.\n"); } return rc; } diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 472907d43460..83e6f1a1b700 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -670,7 +670,7 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) if (ret < 0) goto error; - /* preserve this bit to not accidently shutdown ADC */ + /* preserve this bit to not accidentally shutdown ADC */ val &= 0x80; break; } diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index e87b747ea99c..17f8cdf8afef 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -225,7 +225,7 @@ static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, unsigned long timeout; int result = 0; - /* setup for DISEQC recieve */ + /* setup for DISEQC receive */ val = s5h1420_readreg(state, 0x3b); s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */ msleep(15); diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c index 64673b8b64a2..bc1a8af4f6e1 100644 --- a/drivers/media/dvb/frontends/stb6100.c +++ b/drivers/media/dvb/frontends/stb6100.c @@ -360,7 +360,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency) else odiv = 0; - /* VCO enabled, seach clock off as per LL3.7, 3.4.1 */ + /* VCO enabled, search clock off as per LL3.7, 3.4.1 */ regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT); /* OSM */ diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index 4fd7479bb62b..84d88f33275e 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -435,7 +435,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par return -EINVAL; } - // determine inversion dependant parameters + // determine inversion dependent parameters inversion = p->inversion; if (state->config->invert) inversion = (inversion == INVERSION_ON) ? INVERSION_OFF : INVERSION_ON; diff --git a/drivers/media/dvb/frontends/stv0367.c b/drivers/media/dvb/frontends/stv0367.c index 4e0e6a873b8c..e57ab53e2e27 100644 --- a/drivers/media/dvb/frontends/stv0367.c +++ b/drivers/media/dvb/frontends/stv0367.c @@ -1328,7 +1328,7 @@ stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state) /*guard=stv0367_readbits(state,F367TER_SYR_GUARD); */ - /*supress EPQ auto for SYR_GARD 1/16 or 1/32 + /*suppress EPQ auto for SYR_GARD 1/16 or 1/32 and set channel predictor in automatic */ #if 0 switch (guard) { diff --git a/drivers/media/dvb/frontends/stv0900_priv.h b/drivers/media/dvb/frontends/stv0900_priv.h index b62b0f0a4fef..e0ea74c8e093 100644 --- a/drivers/media/dvb/frontends/stv0900_priv.h +++ b/drivers/media/dvb/frontends/stv0900_priv.h @@ -238,7 +238,7 @@ enum fe_stv0900_demod_mode { }; struct stv0900_init_params{ - u32 dmd_ref_clk;/* Refrence,Input clock for the demod in Hz */ + u32 dmd_ref_clk;/* Reference,Input clock for the demod in Hz */ /* Demodulator Type (single demod or dual demod) */ enum fe_stv0900_demod_mode demod_mode; diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 41d0f0a6655d..52d8712411e5 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -1424,7 +1424,7 @@ static int stv090x_start_search(struct stv090x_state *state) if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0) goto err; - /*enlarge the timing bandwith for Low SR*/ + /*enlarge the timing bandwidth for Low SR*/ if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) goto err; } else { @@ -1432,17 +1432,17 @@ static int stv090x_start_search(struct stv090x_state *state) Set The carrier search up and low to auto mode */ if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0) goto err; - /*reduce the timing bandwith for high SR*/ + /*reduce the timing bandwidth for high SR*/ if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0) goto err; } } else { /* >= Cut 3 */ if (state->srate <= 5000000) { - /* enlarge the timing bandwith for Low SR */ + /* enlarge the timing bandwidth for Low SR */ STV090x_WRITE_DEMOD(state, RTCS2, 0x68); } else { - /* reduce timing bandwith for high SR */ + /* reduce timing bandwidth for high SR */ STV090x_WRITE_DEMOD(state, RTCS2, 0x44); } @@ -2482,7 +2482,7 @@ static int stv090x_sw_algo(struct stv090x_state *state) dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD); } if (dvbs2_fly_wheel < 0xd) { - /*FALSE lock, The demod is loosing lock */ + /*FALSE lock, The demod is losing lock */ lock = 0; if (trials < 2) { if (state->internal->dev_ver >= 0x20) { @@ -3202,7 +3202,7 @@ static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state) goto err; if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0) goto err; - if (stv090x_set_srate(state, 1000000) < 0) /* inital srate = 1Msps */ + if (stv090x_set_srate(state, 1000000) < 0) /* initial srate = 1Msps */ goto err; } else { /* known srate */ diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c index 97b889e8a341..f807c8ba26e4 100644 --- a/drivers/media/dvb/mantis/mantis_uart.c +++ b/drivers/media/dvb/mantis/mantis_uart.c @@ -172,7 +172,7 @@ int mantis_uart_init(struct mantis_pci *mantis) mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); schedule_work(&mantis->uart_work); - dprintk(MANTIS_DEBUG, 1, "UART succesfully initialized"); + dprintk(MANTIS_DEBUG, 1, "UART successfully initialized"); return 0; } diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 175a0f6c2a4c..ccc2d1af49d4 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -122,7 +122,7 @@ static void demux_tasklet(unsigned long data) Cur->ngeneBuffer.SR.Flags &= ~0x40; break; - /* Stop proccessing stream */ + /* Stop processing stream */ } } else { /* We got a valid buffer, @@ -133,7 +133,7 @@ static void demux_tasklet(unsigned long data) printk(KERN_ERR DEVICE_NAME ": OOPS\n"); if (chan->HWState == HWSTATE_RUN) { Cur->ngeneBuffer.SR.Flags &= ~0x40; - break; /* Stop proccessing stream */ + break; /* Stop processing stream */ } } if (chan->AudioDTOUpdated) { diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 6ca6713d527a..7cb79ec685f0 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -294,13 +294,13 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets) /* Workaround for broken hardware: * [1] On startup NBPACKETS seems to contain an uninitialized value, - * but no packets have been transfered. + * but no packets have been transferred. * [2] Sometimes (actually very often) NBPACKETS stays at zero - * although one packet has been transfered. + * although one packet has been transferred. * [3] Sometimes (actually rarely), the card gets into an erroneous * mode where it continuously generates interrupts, claiming it - * has recieved nbpackets>TS_DMA_PACKETS packets, but no packet - * has been transfered. Only a reset seems to solve this + * has received nbpackets>TS_DMA_PACKETS packets, but no packet + * has been transferred. Only a reset seems to solve this */ if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) { unsigned int i = 0; @@ -332,7 +332,7 @@ static irqreturn_t pluto_irq(int irq, void *dev_id) struct pluto *pluto = dev_id; u32 tscr; - /* check whether an interrupt occured on this device */ + /* check whether an interrupt occurred on this device */ tscr = pluto_readreg(pluto, REG_TSCR); if (!(tscr & (TSCR_DE | TSCR_OVR))) return IRQ_NONE; diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index b80d09b035a1..37c594f82782 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -650,7 +650,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe, if (status & FE_HAS_LOCK) return ret; - /* previous tune didnt lock - enable LNA and tune again */ + /* previous tune didn't lock - enable LNA and tune again */ sms_board_lna_control(client->coredev, 1); } diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index fc0a60f8a1e1..3d20719fce1a 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2332,7 +2332,7 @@ static int frontend_init(struct av7110 *av7110) * increment. That's how the 7146 is programmed to do event * counting in this budget-patch.c * I *think* HPS setting has something to do with the phase - * of HS but I cant be 100% sure in that. + * of HS but I can't be 100% sure in that. * * hardware debug note: a working budget card (including budget patch) * with vpeirq() interrupt setup in mode "0x90" (every 64K) will diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 579835590690..3395d1a90516 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -539,7 +539,7 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte ** increment. That's how the 7146 is programmed to do event ** counting in this budget-patch.c ** I *think* HPS setting has something to do with the phase -** of HS but I cant be 100% sure in that. +** of HS but I can't be 100% sure in that. ** hardware debug note: a working budget card (including budget patch) ** with vpeirq() interrupt setup in mode "0x90" (every 64K) will diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index fe1b8037b247..f893bffa08a3 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -234,7 +234,7 @@ static void ttusb_dec_handle_irq( struct urb *urb) * (with buffer[3] == 0x40) in an intervall of ~100ms. * But to handle this correctly we had to imlemenent some * kind of timer which signals a 'key up' event if no - * keyrepeat signal is recieved for lets say 200ms. + * keyrepeat signal is received for lets say 200ms. * this should/could be added later ... * for now lets report each signal as a key down and up*/ dprintk("%s:rc signal:%d\n", __func__, buffer[4]); diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index e6b2d085a449..b3a635b95820 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -99,7 +99,7 @@ devices, that would be 76 and 91. */ /* * Commands that device should understand - * List isnt full and will be updated with implementation of new functions + * List isn't full and will be updated with implementation of new functions */ #define AMRADIO_SET_FREQ 0xa4 #define AMRADIO_SET_MUTE 0xab diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index 0fab6f8f7e24..deca2e06ff22 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -481,7 +481,7 @@ unlock: } /* - * si4713_wait_stc - Waits STC interrupt and clears status bits. Usefull + * si4713_wait_stc - Waits STC interrupt and clears status bits. Useful * for TX_TUNE_POWER, TX_TUNE_FREQ and TX_TUNE_MEAS * @sdev: si4713_device structure for the device we are communicating * @usecs: timeout to wait for STC interrupt signal diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 64454d39c0ca..26fb9cbd7530 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -352,7 +352,7 @@ static void send_tasklet(unsigned long arg) if (!atomic_read(&fmdev->tx_cnt)) return; - /* Check, is there any timeout happenned to last transmitted packet */ + /* Check, is there any timeout happened to last transmitted packet */ if ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT) { fmerr("TX timeout occurred\n"); atomic_set(&fmdev->tx_cnt, 1); @@ -478,7 +478,7 @@ u32 fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, return -ETIMEDOUT; } if (!fmdev->resp_skb) { - fmerr("Reponse SKB is missing\n"); + fmerr("Response SKB is missing\n"); return -EFAULT; } spin_lock_irqsave(&fmdev->resp_skb_lock, flags); @@ -1592,7 +1592,7 @@ u32 fmc_release(struct fmdev *fmdev) fmdbg("FM Core is already down\n"); return 0; } - /* Sevice pending read */ + /* Service pending read */ wake_up_interruptible(&fmdev->rx.rds.read_queue); tasklet_kill(&fmdev->tx_task); diff --git a/drivers/media/radio/wl128x/fmdrv_common.h b/drivers/media/radio/wl128x/fmdrv_common.h index 427c4164cece..aee243bb6630 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.h +++ b/drivers/media/radio/wl128x/fmdrv_common.h @@ -362,7 +362,7 @@ struct fm_event_msg_hdr { #define FM_TX_PREEMPH_50US 0 #define FM_TX_PREEMPH_75US 2 -/* FM TX antenna impedence values */ +/* FM TX antenna impedance values */ #define FM_TX_ANT_IMP_50 0 #define FM_TX_ANT_IMP_200 1 #define FM_TX_ANT_IMP_500 2 diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 1ac49139158d..a43ed6c41bfc 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -520,7 +520,7 @@ static void ene_rx_disable(struct ene_device *dev) dev->rx_enabled = false; } -/* This resets the receiver. Usefull to stop stream of spaces at end of +/* This resets the receiver. Useful to stop stream of spaces at end of * transmission */ static void ene_rx_reset(struct ene_device *dev) @@ -1089,7 +1089,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (error < 0) goto error; - ene_notice("driver has been succesfully loaded"); + ene_notice("driver has been successfully loaded"); return 0; error: if (dev && dev->irq >= 0) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index f714e1a22c92..ebd68edf5b24 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1293,7 +1293,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) * contain a position coordinate (x,y), with each component ranging * from -14 to 14. We want to down-sample this to only 4 discrete values * for up/down/left/right arrow keys. Also, when you get too close to - * diagonals, it has a tendancy to jump back and forth, so lets try to + * diagonals, it has a tendency to jump back and forth, so lets try to * ignore when they get too close. */ if (ictx->product != 0xffdc) { diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 01f258a2a57a..11c19d8d0ee0 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -153,7 +153,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_store_edge); * @type: the type of the event that has occurred * * This routine (which may be called from an interrupt context) works - * in similiar manner to ir_raw_event_store_edge. + * in similar manner to ir_raw_event_store_edge. * This routine is intended for devices with limited internal buffer * It automerges samples of same type, and handles timeouts */ diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 3c1913926c1a..afae14fd152e 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -55,7 +55,7 @@ static struct rc_map_table lme2510_rc[] = { { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0xff40f906, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/ + { 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ { 0xff40fe01, KEY_CHANNELUP }, { 0xff40fa05, KEY_CHANNELDOWN }, { 0xff40eb14, KEY_ZOOM }, @@ -76,7 +76,7 @@ static struct rc_map_table lme2510_rc[] = { { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volumne defined as right hand*/ + { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ { 0xff00b946, KEY_CHANNELUP }, { 0xff00bf40, KEY_CHANNELDOWN }, { 0xff00f708, KEY_ZOOM }, diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index 18b37facb0dd..fdd213ff1adf 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -29,7 +29,7 @@ static struct rc_map_table msi_tvanywhere[] = { { 0x0c, KEY_MUTE }, { 0x0f, KEY_SCREEN }, /* Full Screen */ - { 0x10, KEY_FN }, /* Funtion */ + { 0x10, KEY_FN }, /* Function */ { 0x11, KEY_TIME }, /* Time shift */ { 0x12, KEY_POWER }, { 0x13, KEY_MEDIA }, /* MTS */ diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index f1c1281fbc17..f9f2fa2819b8 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -49,7 +49,7 @@ static struct rc_map_table norwood[] = { { 0x37, KEY_PLAY }, /* Play */ { 0x36, KEY_PAUSE }, /* Pause */ { 0x2b, KEY_STOP }, /* Stop */ - { 0x67, KEY_FASTFORWARD }, /* Foward */ + { 0x67, KEY_FASTFORWARD }, /* Forward */ { 0x66, KEY_REWIND }, /* Rewind */ { 0x3e, KEY_SEARCH }, /* Auto Scan */ { 0x2e, KEY_CAMERA }, /* Capture Video */ diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 5ac1baf45c8e..f53f9c68d38d 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -255,7 +255,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, * @rc_map: scancode table to be searched * @scancode: the desired scancode * @resize: controls whether we allowed to resize the table to - * accomodate not yet present scancodes + * accommodate not yet present scancodes * @return: index of the mapping containing scancode in question * or -1U in case of failure. * @@ -1037,7 +1037,7 @@ int rc_register_device(struct rc_dev *dev) goto out_table; /* - * Default delay of 250ms is too short for some protocols, expecially + * Default delay of 250ms is too short for some protocols, especially * since the timeout is currently set to 250ms. Increase it to 500ms, * to avoid wrong repetition of the keycodes. Note that this must be * set after the call to input_register_device(). diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 6ad83a15d073..c03eb29a9ee6 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c @@ -502,7 +502,7 @@ static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q, /* Get the next buffer */ *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue); - /* Cleans up buffer - Usefull for testing for frame/URB loss */ + /* Cleans up buffer - Useful for testing for frame/URB loss */ outp = videobuf_to_vmalloc(&(*buf)->vb); memset(outp, 0x00, (*buf)->vb.size); diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 242f0d512238..3c9e6c7e7b52 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -2244,8 +2244,8 @@ struct tvcard bttv_tvcards[] = { }, [BTTV_BOARD_PICOLO_TETRA_CHIP] = { /*Eric DEBIEF */ - /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controled*/ - /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the folowing declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/ + /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controlled*/ + /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/ /*0x79 in bttv.h*/ .name = "Euresys Picolo Tetra", .video_inputs = 4, @@ -4567,7 +4567,7 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) * at one input while the monitor is looking at another. * * Since I've couldn't be bothered figuring out how to add an - * independant muxsel for the monitor bus, I've just set it to + * independent muxsel for the monitor bus, I've just set it to * whatever the card is looking at. * * OUT0 of the TDA8540's is connected to MUX0 (0x03) diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c index fd604d32bbb9..13ce72c04b33 100644 --- a/drivers/media/video/bt8xx/bttv-gpio.c +++ b/drivers/media/video/bt8xx/bttv-gpio.c @@ -3,7 +3,7 @@ bttv-gpio.c -- gpio sub drivers sysfs-based sub driver interface for bttv - mainly intented for gpio access + mainly intended for gpio access Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 55ffd60ffa7f..664703398493 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -383,7 +383,7 @@ static int cafe_smbus_write_data(struct cafe_camera *cam, * causes the device to die. * Use a busy-wait because we often send a large quantity of small * commands at-once; using msleep() would cause a lot of context - * switches which take longer than 2ms, resulting in a noticable + * switches which take longer than 2ms, resulting in a noticeable * boot-time and capture-start delays. */ mdelay(2); diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h index 188c9c3d2db1..e9c69d9c9e4a 100644 --- a/drivers/media/video/cx18/cx18-av-core.h +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -109,7 +109,7 @@ struct cx18_av_state { int is_initialized; /* - * The VBI slicer starts operating and counting lines, begining at + * The VBI slicer starts operating and counting lines, beginning at * slicer line count of 1, at D lines after the deassertion of VRESET. * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525 * line systems respectively. Sliced ancillary data captured on VBI diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 86c30b9963e5..4f041c033c54 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -312,7 +312,7 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, /* * Set the digitizer registers for raw active VBI. - * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid + * Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid * calling conditions */ ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi); diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c index 582227522cf0..6d3121ff45a2 100644 --- a/drivers/media/video/cx18/cx18-vbi.c +++ b/drivers/media/video/cx18/cx18-vbi.c @@ -29,7 +29,7 @@ /* * Raster Reference/Protection (RP) bytes, used in Start/End Active * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start - * of VBI sample or VBI ancilliary data regions in the digitial ratser line. + * of VBI sample or VBI ancillary data regions in the digitial ratser line. * * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0 */ diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c index 62843d39817c..280df43ca446 100644 --- a/drivers/media/video/cx231xx/cx231xx-avcore.c +++ b/drivers/media/video/cx231xx/cx231xx-avcore.c @@ -2577,7 +2577,7 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type) break; case 6: /* ts1 parallel mode */ - cx231xx_info("%s: set ts1 parrallel mode registers\n", + cx231xx_info("%s: set ts1 parallel mode registers\n", __func__); status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100); status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400); diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c index 1d914488dbb3..1c7a4daafecf 100644 --- a/drivers/media/video/cx231xx/cx231xx-vbi.c +++ b/drivers/media/video/cx231xx/cx231xx-vbi.c @@ -631,7 +631,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, /* Get the next buffer */ *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); - /* Cleans up buffer - Usefull for testing for frame/URB loss */ + /* Cleans up buffer - Useful for testing for frame/URB loss */ outp = videobuf_to_vmalloc(&(*buf)->vb); memset(outp, 0, (*buf)->vb.size); diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index ffd5af914c44..a69c24d8db06 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -309,7 +309,7 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q, /* Get the next buffer */ *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); - /* Cleans up buffer - Usefull for testing for frame/URB loss */ + /* Cleans up buffer - Useful for testing for frame/URB loss */ outp = videobuf_to_vmalloc(&(*buf)->vb); memset(outp, 0, (*buf)->vb.size); diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c index 209b971bd267..c9f15d6dec40 100644 --- a/drivers/media/video/cx23885/cimax2.c +++ b/drivers/media/video/cx23885/cimax2.c @@ -449,7 +449,7 @@ int netup_ci_init(struct cx23885_tsport *port) 0x04, /* ack active low */ 0x00, /* LOCK = 0 */ 0x33, /* serial mode, rising in, rising out, MSB first*/ - 0x31, /* syncronization */ + 0x31, /* synchronization */ }; int ret; diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 8db2797bc7c3..c186473fc570 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -214,7 +214,7 @@ struct cx23885_board { /* Vendors can and do run the PCIe bridge at different * clock rates, driven physically by crystals on the PCBs. - * The core has to accomodate this. This allows the user + * The core has to accommodate this. This allows the user * to add new boards with new frequencys. The value is * expressed in Hz. * diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 35796e035247..b7ee2ae70583 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -2,7 +2,7 @@ * * Copyright (C) 2004 Ulf Eklund * - * Based on the saa7115 driver and on the first verison of Chris Kennedy's + * Based on the saa7115 driver and on the first version of Chris Kennedy's * cx25840 driver. * * Changes by Tyler Trafford @@ -445,7 +445,7 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_write(client, 0x918, 0xa0); cx25840_write(client, 0x919, 0x01); - /* stereo prefered */ + /* stereo preferred */ cx25840_write(client, 0x809, 0x04); /* AC97 shift */ cx25840_write(client, 0x8cf, 0x0f); @@ -546,7 +546,7 @@ static void cx23885_initialize(struct i2c_client *client) * Aux PLL * Initial setup for audio sample clock: * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz - * Intial I2S output/master clock(?): + * Initial I2S output/master clock(?): * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz */ switch (state->id) { @@ -903,7 +903,7 @@ static void input_change(struct i2c_client *client) } else if (std & V4L2_STD_PAL) { /* Autodetect audio standard and audio system */ cx25840_write(client, 0x808, 0xff); - /* Since system PAL-L is pretty much non-existant and + /* Since system PAL-L is pretty much non-existent and not used by any public broadcast network, force 6.5 MHz carrier to be interpreted as System DK, this avoids DK audio detection instability */ @@ -1851,7 +1851,7 @@ static u32 get_cx2388x_ident(struct i2c_client *client) ret = V4L2_IDENT_CX23885_AV; } else { /* CX23887 has a broken DIF, but the registers - * appear valid (but unsed), good enough to detect. */ + * appear valid (but unused), good enough to detect. */ ret = V4L2_IDENT_CX23887_AV; } } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { diff --git a/drivers/media/video/davinci/dm644x_ccdc.c b/drivers/media/video/davinci/dm644x_ccdc.c index 490aafb34e2f..c8b32c1c7386 100644 --- a/drivers/media/video/davinci/dm644x_ccdc.c +++ b/drivers/media/video/davinci/dm644x_ccdc.c @@ -258,7 +258,7 @@ static int ccdc_update_raw_params(struct ccdc_config_params_raw *raw_params) /* * Allocate memory for FPC table if current * FPC table buffer is not big enough to - * accomodate FPC Number requested + * accommodate FPC Number requested */ if (raw_params->fault_pxl.fp_num != config_params->fault_pxl.fp_num) { if (fpc_physaddr != NULL) { @@ -436,7 +436,7 @@ void ccdc_config_ycbcr(void) /* * configure the horizontal line offset. This should be a - * on 32 byte bondary. So clear LSB 5 bits + * on 32 byte boundary. So clear LSB 5 bits */ regw(((params->win.width * 2 + 31) & ~0x1f), CCDC_HSIZE_OFF); diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 71e961e53a56..5b38fc93ff28 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -1691,7 +1691,7 @@ static int vpfe_s_crop(struct file *file, void *priv, goto unlock_out; } - /* adjust the width to 16 pixel boundry */ + /* adjust the width to 16 pixel boundary */ crop->c.width = ((crop->c.width + 15) & ~0xf); /* make sure parameters are valid */ diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index a83131bd00b2..7b6461d2d1ff 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -377,7 +377,7 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, /* Get the next buffer */ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); - /* Cleans up buffer - Usefull for testing for frame/URB loss */ + /* Cleans up buffer - Useful for testing for frame/URB loss */ outp = videobuf_to_vmalloc(&(*buf)->vb); memset(outp, 0, (*buf)->vb.size); @@ -404,7 +404,7 @@ static inline void vbi_get_next_buf(struct em28xx_dmaqueue *dma_q, /* Get the next buffer */ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); - /* Cleans up buffer - Usefull for testing for frame/URB loss */ + /* Cleans up buffer - Useful for testing for frame/URB loss */ outp = videobuf_to_vmalloc(&(*buf)->vb); memset(outp, 0x00, (*buf)->vb.size); diff --git a/drivers/media/video/gspca/gl860/gl860-mi1320.c b/drivers/media/video/gspca/gl860/gl860-mi1320.c index c276a7debdec..b57160e04866 100644 --- a/drivers/media/video/gspca/gl860/gl860-mi1320.c +++ b/drivers/media/video/gspca/gl860/gl860-mi1320.c @@ -201,7 +201,7 @@ void mi1320_init_settings(struct gspca_dev *gspca_dev) sd->vmax.backlight = 2; sd->vmax.brightness = 8; sd->vmax.sharpness = 7; - sd->vmax.contrast = 0; /* 10 but not working with tihs driver */ + sd->vmax.contrast = 0; /* 10 but not working with this driver */ sd->vmax.gamma = 40; sd->vmax.hue = 5 + 1; sd->vmax.saturation = 8; diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 9c6a643caf01..e526aa3dedaf 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -857,7 +857,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) } /* the bandwidth is not wide enough - * negociate or try a lower alternate setting */ + * negotiate or try a lower alternate setting */ PDEBUG(D_ERR|D_STREAM, "bandwidth not wide enough - trying again"); msleep(20); /* wait for kill complete */ @@ -2346,7 +2346,7 @@ void gspca_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); /* release the device */ - /* (this will call gspca_release() immediatly or on last close) */ + /* (this will call gspca_release() immediately or on last close) */ video_unregister_device(&gspca_dev->vdev); /* PDEBUG(D_PROBE, "disconnect complete"); */ diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index cb4d0bf0d784..0196209a948a 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -361,7 +361,7 @@ static int sd_start(struct gspca_dev *gspca_dev) mi_w(gspca_dev, i + 1, mi_data[i]); data[0] = 0x00; - data[1] = 0x4d; /* ISOC transfering enable... */ + data[1] = 0x4d; /* ISOC transferring enable... */ reg_w(gspca_dev, 2); gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */ diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index 3884c9d300c5..97e507967434 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c @@ -469,7 +469,7 @@ static void lcd_stop(struct gspca_dev *gspca_dev) static int isoc_enable(struct gspca_dev *gspca_dev) { gspca_dev->usb_buf[0] = 0x00; - gspca_dev->usb_buf[1] = 0x4d; /* ISOC transfering enable... */ + gspca_dev->usb_buf[1] = 0x4d; /* ISOC transferring enable... */ return mr_write(gspca_dev, 2); } diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index fd1b6082c96d..36a46fc78734 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -381,7 +381,7 @@ static const struct v4l2_pix_format ov519_sif_mode[] = { larger then necessary, however they need to be this big as the ov511 / ov518 always fills the entire isoc frame, using 0 padding bytes when it doesn't have any data. So with low framerates the amount of data - transfered can become quite large (libv4l will remove all the 0 padding + transferred can become quite large (libv4l will remove all the 0 padding in userspace). */ static const struct v4l2_pix_format ov518_vga_mode[] = { {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE, @@ -4368,7 +4368,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev, gspca_dev->last_packet_type = DISCARD_PACKET; return; } - /* Add 11 byte footer to frame, might be usefull */ + /* Add 11 byte footer to frame, might be useful */ gspca_frame_add(gspca_dev, LAST_PACKET, in, 11); return; } else { diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 5a08738fba30..146b459b08d5 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -827,7 +827,7 @@ static void setexposure(struct gspca_dev *gspca_dev) possible to use less exposure then what the fps maximum allows by setting register 10. register 10 configures the actual exposure as quotient of the full exposure, with 0 - being no exposure at all (not very usefull) and reg10_max + being no exposure at all (not very useful) and reg10_max being max exposure possible at that framerate. The code maps our 0 - 510 ms exposure ctrl to these 2 diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c index 45552c3ff8d9..3e76951e3c19 100644 --- a/drivers/media/video/gspca/spca500.c +++ b/drivers/media/video/gspca/spca500.c @@ -607,7 +607,7 @@ static void spca500_reinit(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x00, 0x8880, 2); /* family cam Quicksmart stuff */ reg_w(gspca_dev, 0x00, 0x800a, 0x00); - /* Set agc transfer: synced inbetween frames */ + /* Set agc transfer: synced between frames */ reg_w(gspca_dev, 0x00, 0x820f, 0x01); /* Init SDRAM - needed for SDRAM access */ reg_w(gspca_dev, 0x00, 0x870a, 0x04); @@ -831,7 +831,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* familycam Quicksmart pocketDV stuff */ reg_w(gspca_dev, 0x00, 0x800a, 0x00); - /* Set agc transfer: synced inbetween frames */ + /* Set agc transfer: synced between frames */ reg_w(gspca_dev, 0x00, 0x820f, 0x01); /* Init SDRAM - needed for SDRAM access */ reg_w(gspca_dev, 0x00, 0x870a, 0x04); diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c index 348319371523..41dce49fb43d 100644 --- a/drivers/media/video/gspca/spca508.c +++ b/drivers/media/video/gspca/spca508.c @@ -592,7 +592,7 @@ static const u16 spca508_sightcam_init_data[][2] = { /* This line seems to setup the frame/canvas */ {0x000f, 0x8402}, -/* Theese 6 lines are needed to startup the webcam */ +/* These 6 lines are needed to startup the webcam */ {0x0090, 0x8110}, {0x0001, 0x8114}, {0x0001, 0x8114}, diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 2e9c06175192..5ba96aff2252 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c @@ -22,7 +22,7 @@ * History and Acknowledgments * * The original Linux driver for SQ905 based cameras was written by - * Marcell Lengyel and furter developed by many other contributers + * Marcell Lengyel and furter developed by many other contributors * and is available from http://sourceforge.net/projects/sqcam/ * * This driver takes advantage of the reverse engineering work done for diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index 17531b41a073..b8156855f2b7 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -569,7 +569,7 @@ static int hdcs_init(struct sd *sd) if (err < 0) return err; - /* Enable continous frame capture, bit 2: stop when frame complete */ + /* Enable continuous frame capture, bit 2: stop when frame complete */ err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3)); if (err < 0) return err; diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c index cdf8b191f710..cbc505a2fc29 100644 --- a/drivers/media/video/hexium_gemini.c +++ b/drivers/media/video/hexium_gemini.c @@ -261,7 +261,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input) /* the saa7146 provides some controls (brightness, contrast, saturation) which gets registered *after* this function. because of this we have - to return with a value != 0 even if the function succeded.. */ + to return with a value != 0 even if the function succeeded.. */ static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c index 4df01947a7df..14a1cea1d70d 100644 --- a/drivers/media/video/ivtv/ivtv-firmware.c +++ b/drivers/media/video/ivtv/ivtv-firmware.c @@ -179,7 +179,7 @@ static volatile struct ivtv_mailbox __iomem *ivtv_search_mailbox(const volatile { int i; - /* mailbox is preceeded by a 16 byte 'magic cookie' starting at a 256-byte + /* mailbox is preceded by a 16 byte 'magic cookie' starting at a 256-byte address boundary */ for (i = 0; i < size; i += 0x100) { if (readl(mem + i) == 0x12345678 && @@ -377,7 +377,7 @@ int ivtv_firmware_check(struct ivtv *itv, char *where) "Reloading\n", where); res = ivtv_firmware_restart(itv); /* - * Even if restarted ok, still signal a problem had occured. + * Even if restarted ok, still signal a problem had occurred. * The caller can come through this function again to check * if things are really ok after the restart. */ diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index f0316d02f09f..17247451c693 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -1080,7 +1080,7 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) kmalloc(sizeof(u32) * 16, GFP_KERNEL|__GFP_NOWARN); if (!oi->ivtvfb_info.pseudo_palette) { - IVTVFB_ERR("abort, unable to alloc pseudo pallete\n"); + IVTVFB_ERR("abort, unable to alloc pseudo palette\n"); return -ENOMEM; } diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index b1763ac93ab3..8126622fb4f5 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -69,7 +69,7 @@ MODULE_LICENSE("GPL"); /* module parameters */ static int opmode = OPMODE_AUTO; int msp_debug; /* msp_debug output */ -int msp_once; /* no continous stereo monitoring */ +int msp_once; /* no continuous stereo monitoring */ int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ int msp_standard = 1; /* Override auto detect of audio msp_standard, @@ -551,7 +551,7 @@ static int msp_log_status(struct v4l2_subdev *sd) switch (state->mode) { case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; case MSP_MODE_FM_RADIO: p = "FM Radio"; break; - case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; + case MSP_MODE_FM_TERRA: p = "Terrestrial FM-mono/stereo"; break; case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index b376fcdee652..80387e2c3eca 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -87,7 +87,7 @@ static struct msp3400c_init_data_dem { {-8, -8, 4, 6, 78, 107}, MSP_CARRIER(10.7), MSP_CARRIER(10.7), 0x00d0, 0x0480, 0x0020, 0x3000 - }, { /* Terrestial FM-mono + FM-stereo */ + }, { /* Terrestrial FM-mono + FM-stereo */ {3, 18, 27, 48, 66, 72}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 029a4babfd61..d4fe7bc92a1d 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -473,7 +473,7 @@ static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout, /* * Convert V4L2 rotation to DSS rotation * V4L2 understand 0, 90, 180, 270. - * Convert to 0, 1, 2 and 3 repsectively for DSS + * Convert to 0, 1, 2 and 3 respectively for DSS */ static int v4l2_rot_to_dss_rot(int v4l2_rotation, enum dss_rotation *rotation, bool mirror) @@ -1142,7 +1142,7 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, } /* - * Buffer queue funtion will be called from the videobuf layer when _QBUF + * Buffer queue function will be called from the videobuf layer when _QBUF * ioctl is called. It is used to enqueue buffer, which is ready to be * displayed. */ diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c index b941c761eef9..2aa6a76c5e59 100644 --- a/drivers/media/video/omap/omap_voutlib.c +++ b/drivers/media/video/omap/omap_voutlib.c @@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(omap_vout_default_crop); /* Given a new render window in new_win, adjust the window to the * nearest supported configuration. The adjusted window parameters are * returned in new_win. - * Returns zero if succesful, or -EINVAL if the requested window is + * Returns zero if successful, or -EINVAL if the requested window is * impossible and cannot reasonably be adjusted. */ int omap_vout_try_window(struct v4l2_framebuffer *fbuf, @@ -101,7 +101,7 @@ EXPORT_SYMBOL_GPL(omap_vout_try_window); * will also be adjusted if necessary. Preference is given to keeping the * the window as close to the requested configuration as possible. If * successful, new_win, vout->win, and crop are updated. - * Returns zero if succesful, or -EINVAL if the requested preview window is + * Returns zero if successful, or -EINVAL if the requested preview window is * impossible and cannot reasonably be adjusted. */ int omap_vout_new_window(struct v4l2_rect *crop, @@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(omap_vout_new_window); * window would fall outside the display boundaries, the cropping rectangle * will also be adjusted to maintain the rescaling ratios. If successful, crop * and win are updated. - * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is + * Returns zero if successful, or -EINVAL if the requested cropping rectangle is * impossible and cannot reasonably be adjusted. */ int omap_vout_new_crop(struct v4l2_pix_format *pix, diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index eab31cbd68eb..5954b9306630 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -687,7 +687,7 @@ static void videobuf_done(struct omap1_cam_dev *pcdev, * In CONTIG mode, the current buffer parameters had already * been entered into the DMA programming register set while the * buffer was fetched with prepare_next_vb(), they may have also - * been transfered into the runtime set and already active if + * been transferred into the runtime set and already active if * the DMA still running. */ } else { @@ -835,7 +835,7 @@ static irqreturn_t cam_isr(int irq, void *data) /* * If exactly 2 sgbufs from the next sglist have * been programmed into the DMA engine (the - * frist one already transfered into the DMA + * first one already transferred into the DMA * runtime register set, the second one still * in the programming set), then we are in sync. */ diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 1a9963bd6d40..503bd7922bd6 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -715,7 +715,7 @@ static int isp_pipeline_link_notify(struct media_pad *source, * Walk the entities chain starting at the pipeline output video node and start * all modules in the chain in the given mode. * - * Return 0 if successfull, or the return value of the failed video::s_stream + * Return 0 if successful, or the return value of the failed video::s_stream * operation otherwise. */ static int isp_pipeline_enable(struct isp_pipeline *pipe, @@ -883,7 +883,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) * Set the pipeline to the given stream state. Pipelines can be started in * single-shot or continuous mode. * - * Return 0 if successfull, or the return value of the failed video::s_stream + * Return 0 if successful, or the return value of the failed video::s_stream * operation otherwise. */ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, @@ -1283,7 +1283,7 @@ static void __isp_subclk_update(struct isp_device *isp) clk |= ISPCTRL_RSZ_CLK_EN; /* NOTE: For CCDC & Preview submodules, we need to affect internal - * RAM aswell. + * RAM as well. */ if (isp->subclk_resources & OMAP3_ISP_SUBCLK_CCDC) clk |= ISPCTRL_CCDC_CLK_EN | ISPCTRL_CCDC_RAM_EN; @@ -1431,7 +1431,7 @@ static int isp_get_clocks(struct isp_device *isp) * Increment the reference count on the ISP. If the first reference is taken, * enable clocks and power-up all submodules. * - * Return a pointer to the ISP device structure, or NULL if an error occured. + * Return a pointer to the ISP device structure, or NULL if an error occurred. */ struct isp_device *omap3isp_get(struct isp_device *isp) { diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h index d403af5d31d2..483a19cac1ad 100644 --- a/drivers/media/video/omap3isp/ispccdc.h +++ b/drivers/media/video/omap3isp/ispccdc.h @@ -150,7 +150,7 @@ struct ispccdc_lsc { * @input: Active input * @output: Active outputs * @video_out: Output video node - * @error: A hardware error occured during capture + * @error: A hardware error occurred during capture * @alaw: A-law compression enabled (1) or disabled (0) * @lpf: Low pass filter enabled (1) or disabled (0) * @obclamp: Optical-black clamp enabled (1) or disabled (0) @@ -163,7 +163,7 @@ struct ispccdc_lsc { * @shadow_update: Controls update in progress by userspace * @syncif: Interface synchronization configuration * @vpcfg: Video port configuration - * @underrun: A buffer underrun occured and a new buffer has been queued + * @underrun: A buffer underrun occurred and a new buffer has been queued * @state: Streaming state * @lock: Serializes shadow_update with interrupt handler * @wait: Wait queue used to stop the module diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c index 0efef2e78d93..0e16cab8e089 100644 --- a/drivers/media/video/omap3isp/ispccp2.c +++ b/drivers/media/video/omap3isp/ispccp2.c @@ -772,7 +772,7 @@ static int ccp2_enum_frame_size(struct v4l2_subdev *sd, * @sd : pointer to v4l2 subdev structure * @fh : V4L2 subdev file handle * @fmt : pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess + * return -EINVAL or zero on success */ static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c index fb503f3db3be..69161a682b3d 100644 --- a/drivers/media/video/omap3isp/ispcsi2.c +++ b/drivers/media/video/omap3isp/ispcsi2.c @@ -969,7 +969,7 @@ static int csi2_enum_frame_size(struct v4l2_subdev *sd, * @sd : pointer to v4l2 subdev structure * @fh : V4L2 subdev file handle * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess + * return -EINVAL or zero on success */ static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index baf9374201dc..2b16988a501d 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -34,7 +34,7 @@ #include "ispreg.h" #include "isppreview.h" -/* Default values in Office Flourescent Light for RGBtoRGB Blending */ +/* Default values in Office Fluorescent Light for RGBtoRGB Blending */ static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { { /* RGB-RGB Matrix */ {0x01E2, 0x0F30, 0x0FEE}, @@ -44,7 +44,7 @@ static struct omap3isp_prev_rgbtorgb flr_rgb2rgb = { {0x0000, 0x0000, 0x0000} }; -/* Default values in Office Flourescent Light for RGB to YUV Conversion*/ +/* Default values in Office Fluorescent Light for RGB to YUV Conversion*/ static struct omap3isp_prev_csc flr_prev_csc = { { /* CSC Coef Matrix */ {66, 129, 25}, @@ -54,22 +54,22 @@ static struct omap3isp_prev_csc flr_prev_csc = { {0x0, 0x0, 0x0} }; -/* Default values in Office Flourescent Light for CFA Gradient*/ +/* Default values in Office Fluorescent Light for CFA Gradient*/ #define FLR_CFA_GRADTHRS_HORZ 0x28 #define FLR_CFA_GRADTHRS_VERT 0x28 -/* Default values in Office Flourescent Light for Chroma Suppression*/ +/* Default values in Office Fluorescent Light for Chroma Suppression*/ #define FLR_CSUP_GAIN 0x0D #define FLR_CSUP_THRES 0xEB -/* Default values in Office Flourescent Light for Noise Filter*/ +/* Default values in Office Fluorescent Light for Noise Filter*/ #define FLR_NF_STRGTH 0x03 /* Default values for White Balance */ #define FLR_WBAL_DGAIN 0x100 #define FLR_WBAL_COEF 0x20 -/* Default values in Office Flourescent Light for Black Adjustment*/ +/* Default values in Office Fluorescent Light for Black Adjustment*/ #define FLR_BLKADJ_BLUE 0x0 #define FLR_BLKADJ_GREEN 0x0 #define FLR_BLKADJ_RED 0x0 @@ -137,7 +137,7 @@ preview_enable_invalaw(struct isp_prev_device *prev, u8 enable) * @enable: 1 - Enable, 0 - Disable * * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also - * The proccess is applied for each captured frame. + * The process is applied for each captured frame. */ static void preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable) @@ -157,7 +157,7 @@ preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable) * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is * subtracted with the pixels in the current frame. * - * The proccess is applied for each captured frame. + * The process is applied for each captured frame. */ static void preview_enable_drkframe(struct isp_prev_device *prev, u8 enable) @@ -1528,7 +1528,7 @@ static long preview_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) * preview_set_stream - Enable/Disable streaming on preview subdev * @sd : pointer to v4l2 subdev structure * @enable: 1 == Enable, 0 == Disable - * return -EINVAL or zero on sucess + * return -EINVAL or zero on success */ static int preview_set_stream(struct v4l2_subdev *sd, int enable) { @@ -1780,7 +1780,7 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd, * @sd : pointer to v4l2 subdev structure * @fh : V4L2 subdev file handle * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess + * return -EINVAL or zero on success */ static int preview_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h index f2d63ca4bd6f..fa943bd05c7f 100644 --- a/drivers/media/video/omap3isp/isppreview.h +++ b/drivers/media/video/omap3isp/isppreview.h @@ -163,7 +163,7 @@ struct isptables_update { * @output: Bitmask of the active output * @video_in: Input video entity * @video_out: Output video entity - * @error: A hardware error occured during capture + * @error: A hardware error occurred during capture * @params: Module configuration data * @shadow_update: If set, update the hardware configured in the next interrupt * @underrun: Whether the preview entity has queued buffers on the output diff --git a/drivers/media/video/omap3isp/ispqueue.h b/drivers/media/video/omap3isp/ispqueue.h index 251de3e1679d..92c5a12157d5 100644 --- a/drivers/media/video/omap3isp/ispqueue.h +++ b/drivers/media/video/omap3isp/ispqueue.h @@ -46,9 +46,9 @@ struct scatterlist; * device yet. * @ISP_BUF_STATE_ACTIVE: The buffer is in use for an active video transfer. * @ISP_BUF_STATE_ERROR: The device is done with the buffer and an error - * occured. For capture device the buffer likely contains corrupted data or + * occurred. For capture device the buffer likely contains corrupted data or * no data at all. - * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occured. + * @ISP_BUF_STATE_DONE: The device is done with the buffer and no error occurred. * For capture devices the buffer contains valid data. */ enum isp_video_buffer_state { diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 75d39b115d42..653f88ba56db 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -751,7 +751,7 @@ static void resizer_print_status(struct isp_res_device *res) * ratio will thus result in a resizing factor slightly larger than the * requested value. * - * To accomodate that, and make sure the TRM equations are satisfied exactly, we + * To accommodate that, and make sure the TRM equations are satisfied exactly, we * compute the input crop rectangle as the last step. * * As if the situation wasn't complex enough, the maximum output width depends @@ -1386,7 +1386,7 @@ static int resizer_enum_frame_size(struct v4l2_subdev *sd, * @sd : pointer to v4l2 subdev structure * @fh : V4L2 subdev file handle * @fmt : pointer to v4l2 subdev format structure - * return -EINVAL or zero on sucess + * return -EINVAL or zero on success */ static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_format *fmt) diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index a0bb5db9cb8a..208a7ec739d7 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -494,12 +494,12 @@ static const struct isp_video_queue_operations isp_video_queue_ops = { /* * omap3isp_video_buffer_next - Complete the current buffer and return the next * @video: ISP video object - * @error: Whether an error occured during capture + * @error: Whether an error occurred during capture * * Remove the current video buffer from the DMA queue and fill its timestamp, * field count and state fields before waking up its completion handler. * - * The buffer state is set to VIDEOBUF_DONE if no error occured (@error is 0) + * The buffer state is set to VIDEOBUF_DONE if no error occurred (@error is 0) * or VIDEOBUF_ERROR otherwise (@error is non-zero). * * The DMA queue is expected to contain at least one buffer. @@ -578,7 +578,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video, /* * omap3isp_video_resume - Perform resume operation on the buffers * @video: ISP video object - * @continuous: Pipeline is in single shot mode if 0 or continous mode otherwise + * @continuous: Pipeline is in single shot mode if 0 or continuous mode otherwise * * This function is intended to be used on suspend/resume scenario. It * requests video queue layer to discard buffers marked as DONE if it's in diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index fe8e3ebd9ce4..456d9ad9ae5a 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -1038,7 +1038,7 @@ static int ov6650_reset(struct i2c_client *client) ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0); if (ret) dev_err(&client->dev, - "An error occured while entering soft reset!\n"); + "An error occurred while entering soft reset!\n"); return ret; } diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index 53d88a2ab920..5173ac449dd8 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -273,7 +273,7 @@ static int ov9640_reset(struct i2c_client *client) ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET); if (ret) dev_err(&client->dev, - "An error occured while entering soft reset!\n"); + "An error occurred while entering soft reset!\n"); return ret; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c index aeed1c2945fb..9515f3a68f8f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c @@ -32,7 +32,7 @@ Read and analyze data in the eeprom. Use tveeprom to figure out the packet structure, since this is another Hauppauge device and - internally it has a family resemblence to ivtv-type devices + internally it has a family resemblance to ivtv-type devices */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 51d3009ab57f..d7753ae9ff46 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -75,7 +75,7 @@ enum pvr2_v4l_type { * (but it might still on the bus). In this state there's nothing we can * do; it must be replugged in order to recover. * - * COLD - Device is in an unusuable state, needs microcontroller firmware. + * COLD - Device is in an unusable state, needs microcontroller firmware. * * WARM - We can communicate with the device and the proper * microcontroller firmware is running, but other device initialization is diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 02686771740d..c1ee09a043ba 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -714,7 +714,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, * * The DMA chaining is done with DMA running. This means a tiny temporal window * remains, where a buffer is queued on the chain, while the chain is already - * stopped. This means the tailed buffer would never be transfered by DMA. + * stopped. This means the tailed buffer would never be transferred by DMA. * This function restarts the capture for this corner case, where : * - DADR() == DADDR_STOP * - a videobuffer is queued on the pcdev->capture list diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 4d929a394521..4893b2d91d84 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -356,7 +356,7 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx) /* one shot mode */ cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN; } else { - /* Continous frame capture mode (freerun). */ + /* Continuous frame capture mode (freerun). */ cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_CPT_FRMOD_CNT); cfg |= S5P_CIIMGCPT_IMGCPTEN; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 61c6007c8ea6..50f1be05ebd3 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -7460,7 +7460,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; break; default: - printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); + printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t); } } else if ((data[1] != 0) && (data[1] != 0xff)) { /* new config structure */ @@ -7480,7 +7480,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) printk(KERN_INFO "%s Board has DVB-T\n", dev->name); break; default: - printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t); + printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t); } } else { printk(KERN_ERR "%s unexpected config structure\n", dev->name); diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/video/saa7164/saa7164-cmd.c index 6a4c217ed3a7..62fac7f9d04e 100644 --- a/drivers/media/video/saa7164/saa7164-cmd.c +++ b/drivers/media/video/saa7164/saa7164-cmd.c @@ -257,7 +257,7 @@ out: } /* Wait for a signal event, without holding a mutex. Either return TIMEOUT if - * the event never occured, or SAA_OK if it was signaled during the wait. + * the event never occurred, or SAA_OK if it was signaled during the wait. */ int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) { diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/video/saa7164/saa7164-fw.c index b369300cce06..a266bf0169e6 100644 --- a/drivers/media/video/saa7164/saa7164-fw.c +++ b/drivers/media/video/saa7164/saa7164-fw.c @@ -444,7 +444,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) printk(KERN_INFO " .Reserved = 0x%x\n", hdr->reserved); printk(KERN_INFO " .Version = 0x%x\n", hdr->version); - /* Retreive bootloader if reqd */ + /* Retrieve bootloader if reqd */ if ((hdr->firmwaresize == 0) && (hdr->bslsize == 0)) /* Second bootloader in the firmware file */ filesize = hdr->reserved * 16; diff --git a/drivers/media/video/saa7164/saa7164-types.h b/drivers/media/video/saa7164/saa7164-types.h index df1d2997fa6c..1d2140a3eb38 100644 --- a/drivers/media/video/saa7164/saa7164-types.h +++ b/drivers/media/video/saa7164/saa7164-types.h @@ -412,7 +412,7 @@ struct tmComResVBIFormatDescrHeader { u8 StartLine; /* NTSC Start = 10 */ u8 EndLine; /* NTSC = 21 */ u8 FieldRate; /* 60 for NTSC */ - u8 bNumLines; /* Unsed - scheduled for removal */ + u8 bNumLines; /* Unused - scheduled for removal */ } __attribute__((packed)); struct tmComResProbeCommit { diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index ce56a1cdbf0a..0e07c493e6f0 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1810,7 +1810,7 @@ static int sn9c102_open(struct file *filp) /* We will not release the "open_mutex" lock, so that only one process can be in the wait queue below. This way the process - will be sleeping while holding the lock, without loosing its + will be sleeping while holding the lock, without losing its priority after any wake_up(). */ err = wait_event_interruptible_exclusive(cam->wait_open, diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h index 7f38549715b6..3679970dba2c 100644 --- a/drivers/media/video/sn9c102/sn9c102_sensor.h +++ b/drivers/media/video/sn9c102/sn9c102_sensor.h @@ -180,7 +180,7 @@ struct sn9c102_sensor { It should be used to initialize the sensor only, but may also configure part of the SN9C1XX chip if necessary. You don't need to setup picture settings like brightness, contrast, etc.. here, if - the corrisponding controls are implemented (see below), since + the corresponding controls are implemented (see below), since they are adjusted in the core driver by calling the set_ctrl() method after init(), where the arguments are the default values specified in the v4l2_queryctrl list of supported controls; diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 54681a535822..b6ee1bd342dc 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -493,7 +493,7 @@ static int ioctl_g_ctrl(struct v4l2_int_device *s, int val, r; struct vcontrol *lvc; - /* exposure time is special, spread accross 2 registers */ + /* exposure time is special, spread across 2 registers */ if (vc->id == V4L2_CID_EXPOSURE) { int val_lower, val_upper; @@ -538,7 +538,7 @@ static int ioctl_s_ctrl(struct v4l2_int_device *s, struct vcontrol *lvc; int val = vc->value; - /* exposure time is special, spread accross 2 registers */ + /* exposure time is special, spread across 2 registers */ if (vc->id == V4L2_CID_EXPOSURE) { int val_lower, val_upper; val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L); diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index a25e2b5e1944..c46a3bb95852 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1058,11 +1058,11 @@ static int tda9874a_initialize(struct CHIPSTATE *chip) #define TDA9875_MVR 0x1b /* Main volume droite */ #define TDA9875_MBA 0x1d /* Main Basse */ #define TDA9875_MTR 0x1e /* Main treble */ -#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/ -#define TDA9875_AVL 0x20 /* Auxilary volume gauche */ -#define TDA9875_AVR 0x21 /* Auxilary volume droite */ -#define TDA9875_ABA 0x22 /* Auxilary Basse */ -#define TDA9875_ATR 0x23 /* Auxilary treble */ +#define TDA9875_ACS 0x1f /* Auxiliary channel select (FM) 0b0000000*/ +#define TDA9875_AVL 0x20 /* Auxiliary volume gauche */ +#define TDA9875_AVR 0x21 /* Auxiliary volume droite */ +#define TDA9875_ABA 0x22 /* Auxiliary Basse */ +#define TDA9875_ATR 0x23 /* Auxiliary treble */ #define TDA9875_MSR 0x02 /* Monitor select register */ #define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */ diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 545c0294813d..fc766b9f24c5 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -394,11 +394,11 @@ int uvc_commit_video(struct uvc_streaming *stream, * * uvc_video_decode_end is called with header data at the end of a bulk or * isochronous payload. It performs any additional header data processing and - * returns 0 or a negative error code if an error occured. As header data have + * returns 0 or a negative error code if an error occurred. As header data have * already been processed by uvc_video_decode_start, this functions isn't * required to perform sanity checks a second time. * - * For isochronous transfers where a payload is always transfered in a single + * For isochronous transfers where a payload is always transferred in a single * URB, the three functions will be called in a row. * * To let the decoder process header data and update its internal state even @@ -658,7 +658,7 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream, buf); } while (ret == -EAGAIN); - /* If an error occured skip the rest of the payload. */ + /* If an error occurred skip the rest of the payload. */ if (ret < 0 || buf == NULL) { stream->bulk.skip_payload = 1; } else { @@ -821,7 +821,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, return stream->urb_size / psize; /* Compute the number of packets. Bulk endpoints might transfer UVC - * payloads accross multiple URBs. + * payloads across multiple URBs. */ npackets = DIV_ROUND_UP(size, psize); if (npackets > UVC_MAX_PACKETS) diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index a01ed39e6c16..506edcc2ddeb 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -48,7 +48,7 @@ printk(KERN_CONT "%s: " fmt, vfd->name, ## arg);\ } while (0) -/* Zero out the end of the struct pointed to by p. Everthing after, but +/* Zero out the end of the struct pointed to by p. Everything after, but * not including, the specified field is cleared. */ #define CLEAR_AFTER_FIELD(p, field) \ memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \ diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c index 75301d10a838..ca372eb911d0 100644 --- a/drivers/media/video/vpx3220.c +++ b/drivers/media/video/vpx3220.c @@ -354,7 +354,7 @@ static int vpx3220_s_std(struct v4l2_subdev *sd, v4l2_std_id std) /* Here we back up the input selection because it gets overwritten when we fill the registers with the - choosen video norm */ + chosen video norm */ temp_input = vpx3220_fp_read(sd, 0xf2); v4l2_dbg(1, debug, sd, "s_std %llx\n", (unsigned long long)std); diff --git a/drivers/media/video/zoran/videocodec.h b/drivers/media/video/zoran/videocodec.h index b654bfff8740..def55585ad23 100644 --- a/drivers/media/video/zoran/videocodec.h +++ b/drivers/media/video/zoran/videocodec.h @@ -57,7 +57,7 @@ therfor they may not be initialized. The other functions are just for convenience, as they are for sure used by - most/all of the codecs. The last ones may be ommited, too. + most/all of the codecs. The last ones may be omitted, too. See the structure declaration below for more information and which data has to be set up for the master and the slave. diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h index 4bb368e6fd47..f3f640014928 100644 --- a/drivers/media/video/zoran/zoran.h +++ b/drivers/media/video/zoran/zoran.h @@ -259,7 +259,7 @@ struct card_info { struct vfe_polarity vfe_pol; u8 gpio_pol[ZR_GPIO_MAX]; - /* is the /GWS line conected? */ + /* is the /GWS line connected? */ u8 gws_not_connected; /* avs6eyes mux setting */ diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index 7c3921de9589..2771d818406e 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -1254,7 +1254,7 @@ static int setup_overlay(struct zoran_fh *fh, int on) { struct zoran *zr = fh->zr; - /* If there is nothing to do, return immediatly */ + /* If there is nothing to do, return immediately */ if ((on && fh->overlay_active != ZORAN_FREE) || (!on && fh->overlay_active == ZORAN_FREE)) return 0; diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 57b42bfc7d23..4a1909a32b60 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -973,7 +973,7 @@ try_again: } /* Memory allocated for attributes by this function should be freed by - * mspro_block_data_clear, no matter if the initialization process succeded + * mspro_block_data_clear, no matter if the initialization process succeeded * or failed. */ static int mspro_block_read_attributes(struct memstick_dev *card) diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c index 700d420a59ac..668f5c6a0399 100644 --- a/drivers/memstick/host/r592.c +++ b/drivers/memstick/host/r592.c @@ -796,7 +796,7 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (memstick_add_host(host)) goto error7; - message("driver succesfully loaded"); + message("driver successfully loaded"); return 0; error7: free_irq(dev->irq, dev); diff --git a/drivers/memstick/host/r592.h b/drivers/memstick/host/r592.h index eee264e6028f..c5726c1e8832 100644 --- a/drivers/memstick/host/r592.h +++ b/drivers/memstick/host/r592.h @@ -43,12 +43,12 @@ /* Error detection via CRC */ #define R592_STATUS_SEND_ERR (1 << 24) /* Send failed */ -#define R592_STATUS_RECV_ERR (1 << 25) /* Recieve failed */ +#define R592_STATUS_RECV_ERR (1 << 25) /* Receive failed */ /* Card state */ -#define R592_STATUS_RDY (1 << 28) /* RDY signal recieved */ +#define R592_STATUS_RDY (1 << 28) /* RDY signal received */ #define R592_STATUS_CED (1 << 29) /* INT: Command done (serial mode)*/ -#define R592_STATUS_SFIFO_INPUT (1 << 30) /* Small fifo recieved data*/ +#define R592_STATUS_SFIFO_INPUT (1 << 30) /* Small fifo received data*/ #define R592_SFIFO_SIZE 32 /* total size of small fifo is 32 bytes */ #define R592_SFIFO_PACKET 8 /* packet size of small fifo */ diff --git a/drivers/message/fusion/lsi/mpi_log_fc.h b/drivers/message/fusion/lsi/mpi_log_fc.h index face6e7acc72..03be8b217709 100644 --- a/drivers/message/fusion/lsi/mpi_log_fc.h +++ b/drivers/message/fusion/lsi/mpi_log_fc.h @@ -38,8 +38,8 @@ typedef enum _MpiIocLogInfoFc { MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000, MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* Bad Rx Frame, bad end of frame primative */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primitive */ + MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* Bad Rx Frame, bad end of frame primitive */ MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Bad Rx Frame, overrun */ MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */ MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */ diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index 8b04810df469..f62960b5d527 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -56,9 +56,9 @@ #define IOP_LOGINFO_CODE_FWUPLOAD_NO_FLASH_AVAILABLE (0x0003E000) /* Tried to upload from flash, but there is none */ #define IOP_LOGINFO_CODE_FWUPLOAD_UNKNOWN_IMAGE_TYPE (0x0003E001) /* ImageType field contents were invalid */ #define IOP_LOGINFO_CODE_FWUPLOAD_WRONG_IMAGE_SIZE (0x0003E002) /* ImageSize field in TCSGE was bad/offset in MfgPg 4 was wrong */ -#define IOP_LOGINFO_CODE_FWUPLOAD_ENTIRE_FLASH_UPLOAD_FAILED (0x0003E003) /* Error occured while attempting to upload the entire flash */ -#define IOP_LOGINFO_CODE_FWUPLOAD_REGION_UPLOAD_FAILED (0x0003E004) /* Error occured while attempting to upload single flash region */ -#define IOP_LOGINFO_CODE_FWUPLOAD_DMA_FAILURE (0x0003E005) /* Problem occured while DMAing FW to host memory */ +#define IOP_LOGINFO_CODE_FWUPLOAD_ENTIRE_FLASH_UPLOAD_FAILED (0x0003E003) /* Error occurred while attempting to upload the entire flash */ +#define IOP_LOGINFO_CODE_FWUPLOAD_REGION_UPLOAD_FAILED (0x0003E004) /* Error occurred while attempting to upload single flash region */ +#define IOP_LOGINFO_CODE_FWUPLOAD_DMA_FAILURE (0x0003E005) /* Problem occurred while DMAing FW to host memory */ #define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ @@ -187,8 +187,8 @@ #define PL_LOGINFO_SUB_CODE_BREAK_ON_INCOMPLETE_BREAK_RCVD (0x00005000) #define PL_LOGINFO_CODE_ENCL_MGMT_SMP_FRAME_FAILURE (0x00200000) /* Can't get SMP Frame */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occured on SMP Read */ -#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occured on SMP Write */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_READ_ERROR (0x00200010) /* Error occurred on SMP Read */ +#define PL_LOGINFO_CODE_ENCL_MGMT_SMP_WRITE_ERROR (0x00200020) /* Error occurred on SMP Write */ #define PL_LOGINFO_CODE_ENCL_MGMT_NOT_SUPPORTED_ON_ENCL (0x00200040) /* Encl Mgmt services not available for this WWID */ #define PL_LOGINFO_CODE_ENCL_MGMT_ADDR_MODE_NOT_SUPPORTED (0x00200050) /* Address Mode not suppored */ #define PL_LOGINFO_CODE_ENCL_MGMT_BAD_SLOT_NUM (0x00200060) /* Invalid Slot Number in SEP Msg */ @@ -207,8 +207,8 @@ #define PL_LOGINFO_DA_SEP_RECEIVED_NACK_FROM_SLAVE (0x00200103) /* SEP NACK'd, it is busy */ #define PL_LOGINFO_DA_SEP_DID_NOT_RECEIVE_ACK (0x00200104) /* SEP didn't rcv. ACK (Last Rcvd Bit = 1) */ #define PL_LOGINFO_DA_SEP_BAD_STATUS_HDR_CHKSUM (0x00200105) /* SEP stopped or sent bad chksum in Hdr */ -#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transfering data */ -#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transfering sense data */ +#define PL_LOGINFO_DA_SEP_STOP_ON_DATA (0x00200106) /* SEP stopped while transferring data */ +#define PL_LOGINFO_DA_SEP_STOP_ON_SENSE_DATA (0x00200107) /* SEP stopped while transferring sense data */ #define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_1 (0x00200108) /* SEP returned unknown scsi status */ #define PL_LOGINFO_DA_SEP_UNSUPPORTED_SCSI_STATUS_2 (0x00200109) /* SEP returned unknown scsi status */ #define PL_LOGINFO_DA_SEP_CHKSUM_ERROR_AFTER_STOP (0x0020010A) /* SEP returned bad chksum after STOP */ diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index ec8080c98081..fa15e853d4e8 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -3435,7 +3435,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) * If memory has already been allocated, the same (cached) value * is returned. * - * Return 0 if successfull, or non-zero for failure + * Return 0 if successful, or non-zero for failure **/ int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) @@ -6932,7 +6932,7 @@ EXPORT_SYMBOL(mpt_halt_firmware); * Message Unit Reset - instructs the IOC to reset the Reply Post and * Free FIFO's. All the Message Frames on Reply Free FIFO are discarded. * All posted buffers are freed, and event notification is turned off. - * IOC doesnt reply to any outstanding request. This will transfer IOC + * IOC doesn't reply to any outstanding request. This will transfer IOC * to READY state. **/ int @@ -7905,7 +7905,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info) "Owner", /* 15h */ "Open Transmit DMA Abort", /* 16h */ "IO Device Missing Delay Retry", /* 17h */ - "IO Cancelled Due to Recieve Error", /* 18h */ + "IO Cancelled Due to Receive Error", /* 18h */ NULL, /* 19h */ NULL, /* 1Ah */ NULL, /* 1Bh */ diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 878bda0cce70..6e6e16aab9da 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -985,7 +985,7 @@ retry_wait: ReplyMsg = (pFWDownloadReply_t)iocp->ioctl_cmds.reply; iocstat = le16_to_cpu(ReplyMsg->IOCStatus) & MPI_IOCSTATUS_MASK; if (iocstat == MPI_IOCSTATUS_SUCCESS) { - printk(MYIOC_s_INFO_FMT "F/W update successfull!\n", iocp->name); + printk(MYIOC_s_INFO_FMT "F/W update successful!\n", iocp->name); return 0; } else if (iocstat == MPI_IOCSTATUS_INVALID_FUNCTION) { printk(MYIOC_s_WARN_FMT "Hmmm... F/W download not supported!?!\n", @@ -2407,7 +2407,7 @@ done_free_mem: } /* mf is null if command issued successfully - * otherwise, failure occured after mf acquired. + * otherwise, failure occurred after mf acquired. */ if (mf) mpt_free_msg_frame(ioc, mf); diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index f5a14afad2cd..66f94125de4e 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -307,7 +307,7 @@ mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } -/* free memory assoicated to a sas firmware event */ +/* free memory associated to a sas firmware event */ static void mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) { @@ -1094,7 +1094,7 @@ mptsas_block_io_starget(struct scsi_target *starget) /** * mptsas_target_reset_queue * - * Receive request for TARGET_RESET after recieving an firmware + * Receive request for TARGET_RESET after receiving an firmware * event NOT_RESPONDING_EVENT, then put command in link list * and queue if task_queue already in use. * @@ -1403,7 +1403,7 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, /** * mptsas_add_end_device - report a new end device to sas transport layer * @ioc: Pointer to MPT_ADAPTER structure - * @phy_info: decribes attached device + * @phy_info: describes attached device * * return (0) success (1) failure * @@ -1481,7 +1481,7 @@ mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info) /** * mptsas_del_end_device - report a deleted end device to sas transport layer * @ioc: Pointer to MPT_ADAPTER structure - * @phy_info: decribes attached device + * @phy_info: describes attached device * **/ static void diff --git a/drivers/message/i2o/README b/drivers/message/i2o/README index 911fc3021e3b..f072a8eb3041 100644 --- a/drivers/message/i2o/README +++ b/drivers/message/i2o/README @@ -53,7 +53,7 @@ Symbios Logic (Now LSI) BoxHill Corporation Loan of initial FibreChannel disk array used for development work. -European Comission +European Commission Funding the work done by the University of Helsinki SysKonnect diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 0ee4264f5db7..4547db99f7da 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -65,7 +65,7 @@ int i2o_device_claim(struct i2o_device *dev) rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY); if (!rc) - pr_debug("i2o: claim of device %d succeded\n", + pr_debug("i2o: claim of device %d succeeded\n", dev->lct_data.tid); else pr_debug("i2o: claim of device %d failed %d\n", @@ -110,7 +110,7 @@ int i2o_device_claim_release(struct i2o_device *dev) } if (!rc) - pr_debug("i2o: claim release of device %d succeded\n", + pr_debug("i2o: claim release of device %d succeeded\n", dev->lct_data.tid); else pr_debug("i2o: claim release of device %d failed %d\n", @@ -248,7 +248,7 @@ static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry) goto unreg_dev; } - /* create user entries refering to this device */ + /* create user entries referring to this device */ list_for_each_entry(tmp, &c->devices, list) if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid) && (tmp != i2o_dev)) { @@ -267,7 +267,7 @@ static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry) goto rmlink1; } - /* create parent entries refering to this device */ + /* create parent entries referring to this device */ list_for_each_entry(tmp, &c->devices, list) if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid) && (tmp != i2o_dev)) { diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index 47ec5bc0ed21..643ad52e3ca2 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -610,7 +610,7 @@ static int i2o_block_release(struct gendisk *disk, fmode_t mode) /* * This is to deail with the case of an application - * opening a device and then the device dissapears while + * opening a device and then the device disappears while * it's in use, and then the application tries to release * it. ex: Unmounting a deleted RAID volume at reboot. * If we send messages, it will just cause FAILs since @@ -717,7 +717,7 @@ static unsigned int i2o_block_check_events(struct gendisk *disk, /** * i2o_block_transfer - Transfer a request to/from the I2O controller - * @req: the request which should be transfered + * @req: the request which should be transferred * * This function converts the request into a I2O message. The necessary * DMA buffers are allocated and after everything is setup post the message diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h index 67f921b4419b..cf8873cbca3f 100644 --- a/drivers/message/i2o/i2o_block.h +++ b/drivers/message/i2o/i2o_block.h @@ -73,7 +73,7 @@ struct i2o_block_device { struct i2o_device *i2o_dev; /* pointer to I2O device */ struct gendisk *gd; spinlock_t lock; /* queue lock */ - struct list_head open_queue; /* list of transfered, but unfinished + struct list_head open_queue; /* list of transferred, but unfinished requests */ unsigned int open_queue_depth; /* number of requests in the queue */ diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index 97bdf82ec905..f003957e8e1c 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -204,7 +204,7 @@ static int i2o_scsi_remove(struct device *dev) * i2o_scsi_probe - verify if dev is a I2O SCSI device and install it * @dev: device to verify if it is a I2O SCSI device * - * Retrieve channel, id and lun for I2O device. If everthing goes well + * Retrieve channel, id and lun for I2O device. If everything goes well * register the I2O device as SCSI device on the I2O SCSI controller. * * Returns 0 on success or negative error code on failure. diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e2fea580585a..3ed3ff06be5d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -201,7 +201,7 @@ config TWL4030_POWER as clock request handshaking. This driver uses board-specific data to initialize the resources - and load scripts controling which resources are switched off/on + and load scripts controlling which resources are switched off/on or reset when a sleep, wakeup or warm reset event occurs. config TWL4030_CODEC diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index bc93b2e8230c..6421ad1160de 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -314,7 +314,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) /* wait for completion of conversion */ if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, 2*HZ)) { dev_err(gpadc->dev, - "timeout: didnt recieve GPADC conversion interrupt\n"); + "timeout: didn't receive GPADC conversion interrupt\n"); ret = -EINVAL; goto out; } diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index f2f4029e21a0..43a76c41cfcc 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -185,7 +185,7 @@ static void pcap_isr_work(struct work_struct *work) ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); - /* We cant service/ack irqs that are assigned to port 2 */ + /* We can't service/ack irqs that are assigned to port 2 */ if (!(pdata->config & PCAP_SECOND_PORT)) { ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); isr &= ~int_sel; @@ -457,7 +457,7 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) pcap->workqueue = create_singlethread_workqueue("pcapd"); if (!pcap->workqueue) { ret = -ENOMEM; - dev_err(&spi->dev, "cant create pcap thread\n"); + dev_err(&spi->dev, "can't create pcap thread\n"); goto free_pcap; } diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index cb01209754e0..53450f433f10 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -332,7 +332,7 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) int i; if (!pdata) { - dev_err(dev, "Missing platfrom data\n"); + dev_err(dev, "Missing platform data\n"); ret = -ENOMEM; goto end_probe; } diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index c7687f6a78a0..57868416c760 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -51,7 +51,7 @@ static int __pcf50633_write(struct pcf50633 *pcf, u8 reg, int num, u8 *data) } -/* Read a block of upto 32 regs */ +/* Read a block of up to 32 regs */ int pcf50633_read_block(struct pcf50633 *pcf, u8 reg, int nr_regs, u8 *data) { @@ -65,7 +65,7 @@ int pcf50633_read_block(struct pcf50633 *pcf, u8 reg, } EXPORT_SYMBOL_GPL(pcf50633_read_block); -/* Write a block of upto 32 regs */ +/* Write a block of up to 32 regs */ int pcf50633_write_block(struct pcf50633 *pcf , u8 reg, int nr_regs, u8 *data) { diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index fa937052fbab..dfbae34e1804 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -229,7 +229,7 @@ int twl6030_mmc_card_detect_config(void) twl6030_interrupt_unmask(TWL6030_MMCDETECT_INT_MASK, REG_INT_MSK_STS_B); /* - * Intially Configuring MMC_CTRL for receving interrupts & + * Initially Configuring MMC_CTRL for receiving interrupts & * Card status on TWL6030 for MMC1 */ ret = twl_i2c_read_u8(TWL6030_MODULE_ID0, ®_val, TWL6030_MMCCTRL); @@ -275,7 +275,7 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) /* TWL6030 provide's Card detect support for * only MMC1 controller. */ - pr_err("Unkown MMC controller %d in %s\n", pdev->id, __func__); + pr_err("Unknown MMC controller %d in %s\n", pdev->id, __func__); return ret; } /* diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index d73f84ba0f08..daf69527ed83 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -8,7 +8,7 @@ * Copyright: MontaVista Software, Inc. * * Spliting done by: Marek Vasut - * If something doesnt work and it worked before spliting, e-mail me, + * If something doesn't work and it worked before spliting, e-mail me, * dont bother Nicolas please ;-) * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index ecd276ad6b19..5f898cb706a6 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c @@ -2,7 +2,7 @@ This driver supports the bmp085 digital barometric pressure and temperature sensor from Bosch Sensortec. The datasheet - is avaliable from their website: + is available from their website: http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf A pressure measurement is issued by reading from pressure0_input. @@ -429,7 +429,7 @@ static int __devinit bmp085_probe(struct i2c_client *client, if (err) goto exit_free; - dev_info(&data->client->dev, "Succesfully initialized bmp085!\n"); + dev_info(&data->client->dev, "Successfully initialized bmp085!\n"); goto exit; exit_free: diff --git a/drivers/misc/c2port/c2port-duramar2150.c b/drivers/misc/c2port/c2port-duramar2150.c index 338dcc121507..778fc3fdfb9b 100644 --- a/drivers/misc/c2port/c2port-duramar2150.c +++ b/drivers/misc/c2port/c2port-duramar2150.c @@ -41,7 +41,7 @@ static void duramar2150_c2port_access(struct c2port_device *dev, int status) outb(v | (C2D | C2CK), DIR_PORT); else /* When access is "off" is important that both lines are set - * as inputs or hi-impedence */ + * as inputs or hi-impedance */ outb(v & ~(C2D | C2CK), DIR_PORT); mutex_unlock(&update_lock); diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h index 72acf5af7a2a..00dbf1d4373a 100644 --- a/drivers/misc/ibmasm/remote.h +++ b/drivers/misc/ibmasm/remote.h @@ -20,7 +20,7 @@ * * Author: Max Asböck * - * Orignally written by Pete Reynolds + * Originally written by Pete Reynolds */ #ifndef _IBMASM_REMOTE_H_ diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index 727af07f1fbd..b1f4563be9ae 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c @@ -268,7 +268,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws) LOG_INFO(priv, IRQ, "ACK barker arrived " "- starting FW download\n"); } else { /* REBOOT barker */ - LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker); + LOG_INFO(priv, IRQ, "Received reboot barker: %x\n", barker); priv->barker = barker; if (barker & BARKER_DNLOAD_SYNC_MSK) { diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 27dc463097f3..74f16f167b8e 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -645,7 +645,7 @@ static int validate_simple_test(char *put_str) while (*chk_str != '\0' && *put_str != '\0') { /* If someone does a * to match the rest of the string, allow - * it, or stop if the recieved string is complete. + * it, or stop if the received string is complete. */ if (*put_str == '#' || *chk_str == '*') return 0; diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 34749ee88dfa..9e9bddaa95ae 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c @@ -229,7 +229,7 @@ again: bid = blade_id < 0 ? uv_numa_blade_id() : blade_id; bs = gru_base[bid]; - /* Handle the case where migration occured while waiting for the sema */ + /* Handle the case where migration occurred while waiting for the sema */ down_read(&bs->bs_kgts_sema); if (blade_id < 0 && bid != uv_numa_blade_id()) { up_read(&bs->bs_kgts_sema); diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index 7a8b9068ea03..5c3ce2459675 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -379,7 +379,7 @@ struct gru_thread_state { required for contest */ char ts_cch_req_slice;/* CCH packet slice */ char ts_blade; /* If >= 0, migrate context if - ref from diferent blade */ + ref from different blade */ char ts_force_cch_reload; char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each allocated CB */ diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 9ee4c788aa69..b4488c8f6b23 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -649,7 +649,7 @@ static int kim_probe(struct platform_device *pdev) /* multiple devices could exist */ st_kim_devices[pdev->id] = pdev; } else { - /* platform's sure about existance of 1 device */ + /* platform's sure about existence of 1 device */ st_kim_devices[0] = pdev; } diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index f5cedeccad42..abc1a63bcc5e 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -292,7 +292,7 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem) } /* - * Allocate a lot of memory, preferrably max_sz but at least min_sz. In case + * Allocate a lot of memory, preferably max_sz but at least min_sz. In case * there isn't much memory do not exceed 1/16th total lowmem pages. Also do * not exceed a maximum number of segments and try not to make segments much * bigger than maximum segment size. diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 14e95f39a7bf..772d0d0a541b 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -538,7 +538,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, /* * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF - * bit. This bit will be lost everytime after a reset or power off. + * bit. This bit will be lost every time after a reset or power off. */ if (card->ext_csd.enhanced_area_en) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 60842f878ded..f3b22bf89cc9 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -105,7 +105,7 @@ int mmc_go_idle(struct mmc_host *host) * that in case of hardware that won't pull up DAT3/nCS otherwise. * * SPI hosts ignore ios.chip_select; it's managed according to - * rules that must accomodate non-MMC slaves which this layer + * rules that must accommodate non-MMC slaves which this layer * won't even know about. */ if (!mmc_host_is_spi(host)) { diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index bb192f90e8e9..b3001617e67d 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -45,7 +45,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) struct sdio_func *func = card->sdio_func[i - 1]; if (!func) { printk(KERN_WARNING "%s: pending IRQ for " - "non-existant function\n", + "non-existent function\n", mmc_card_id(card)); ret = -EINVAL; } else if (func->irq_handler) { diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 80bc9a5c25cc..ea3888b65d5d 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -127,7 +127,7 @@ struct atmel_mci_dma { * EVENT_DATA_COMPLETE is set in @pending_events, all data-related * interrupts must be disabled and @data_status updated with a * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the - * CMDRDY interupt must be disabled and @cmd_status updated with a + * CMDRDY interrupt must be disabled and @cmd_status updated with a * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the * bytes_xfered field of @data must be written. This is ensured by * using barriers. @@ -1082,7 +1082,7 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) /* * Update the MMC clock rate if necessary. This may be * necessary if set_ios() is called when a different slot is - * busy transfering data. + * busy transferring data. */ if (host->need_clock_update) { mci_writel(host, MR, host->mode_reg); diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 2f7fc0c5146f..7c1e16aaf17f 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -99,7 +99,7 @@ #define r1b_timeout (HZ * 3) /* One of the critical speed parameters is the amount of data which may - * be transfered in one command. If this value is too low, the SD card + * be transferred in one command. If this value is too low, the SD card * controller has to do multiple partial block writes (argggh!). With * today (2008) SD cards there is little speed gain if we transfer more * than 64 KBytes at a time. So use this value until there is any indication diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 1ccd4b256cee..a04f87d7ee3d 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -874,7 +874,7 @@ static void finalize_request(struct s3cmci_host *host) if (!mrq->data) goto request_done; - /* Calulate the amout of bytes transfer if there was no error */ + /* Calculate the amout of bytes transfer if there was no error */ if (mrq->data->error == 0) { mrq->data->bytes_xfered = (mrq->data->blocks * mrq->data->blksz); @@ -882,7 +882,7 @@ static void finalize_request(struct s3cmci_host *host) mrq->data->bytes_xfered = 0; } - /* If we had an error while transfering data we flush the + /* If we had an error while transferring data we flush the * DMA channel and the fifo to clear out any garbage. */ if (mrq->data->error != 0) { if (s3cmci_host_usedma(host)) @@ -980,7 +980,7 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) if ((data->blksz & 3) != 0) { /* We cannot deal with unaligned blocks with more than - * one block being transfered. */ + * one block being transferred. */ if (data->blocks > 1) { pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 6ae8d2f00ec7..62d37de6de76 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -355,7 +355,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command /* * This chip always returns (at least?) as much data as you ask for. * I'm unsure what happens if you ask for less than a block. This should be - * looked into to ensure that a funny length read doesnt hose the controller. + * looked into to ensure that a funny length read doesn't hose the controller. */ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) { diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 7fca0a386ba0..62e5a4d171e1 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -484,7 +484,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host) /* * Check that we aren't being called after the - * entire buffer has been transfered. + * entire buffer has been transferred. */ if (host->num_sg == 0) return; @@ -828,7 +828,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) /* * If this is a data transfer the request * will be finished after the data has - * transfered. + * transferred. */ if (cmd->data && !cmd->error) { /* @@ -904,7 +904,7 @@ static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) setup &= ~WBSD_DAT3_H; /* - * We cannot resume card detection immediatly + * We cannot resume card detection immediately * because of capacitance and delays in the chip. */ mod_timer(&host->ignore_timer, jiffies + HZ / 100); diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index 35c6a23b183b..b1e3c26edd6d 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -19,7 +19,7 @@ config MTD_JEDECPROBE help This option enables JEDEC-style probing of flash chips which are not compatible with the Common Flash Interface, but will use the common - CFI-targetted flash drivers for any chips which are identified which + CFI-targeted flash drivers for any chips which are identified which are in fact compatible in all but the probe method. This actually covers most AMD/Fujitsu-compatible chips and also non-CFI Intel chips. diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 092aef11120c..09cb7c8d93b4 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -1247,12 +1247,12 @@ static int inval_cache_and_wait_for_operation( break; if (chip->erase_suspended && chip_state == FL_ERASING) { - /* Erase suspend occured while sleep: reset timeout */ + /* Erase suspend occurred while sleep: reset timeout */ timeo = reset_timeo; chip->erase_suspended = 0; } if (chip->write_suspended && chip_state == FL_WRITING) { - /* Write suspend occured while sleep: reset timeout */ + /* Write suspend occurred while sleep: reset timeout */ timeo = reset_timeo; chip->write_suspended = 0; } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index f9a5331e9445..0b49266840b9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -263,7 +263,7 @@ static void fixup_old_sst_eraseregion(struct mtd_info *mtd) struct cfi_private *cfi = map->fldrv_priv; /* - * These flashes report two seperate eraseblock regions based on the + * These flashes report two separate eraseblock regions based on the * sector_erase-size and block_erase-size, although they both operate on the * same memory. This is not allowed according to CFI, so we just pick the * sector_erase-size. @@ -611,8 +611,8 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) * * Note that anything more complicated than checking if no bits are toggling * (including checking DQ5 for an error status) is tricky to get working - * correctly and is therefore not done (particulary with interleaved chips - * as each chip must be checked independantly of the others). + * correctly and is therefore not done (particularly with interleaved chips + * as each chip must be checked independently of the others). */ static int __xipram chip_ready(struct map_info *map, unsigned long addr) { @@ -635,8 +635,8 @@ static int __xipram chip_ready(struct map_info *map, unsigned long addr) * * Note that anything more complicated than checking if no bits are toggling * (including checking DQ5 for an error status) is tricky to get working - * correctly and is therefore not done (particulary with interleaved chips - * as each chip must be checked independantly of the others). + * correctly and is therefore not done (particularly with interleaved chips + * as each chip must be checked independently of the others). * */ static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected) diff --git a/drivers/mtd/chips/cfi_util.c b/drivers/mtd/chips/cfi_util.c index 6ae3d111e1e7..8e464054a631 100644 --- a/drivers/mtd/chips/cfi_util.c +++ b/drivers/mtd/chips/cfi_util.c @@ -1,6 +1,6 @@ /* * Common Flash Interface support: - * Generic utility functions not dependant on command set + * Generic utility functions not dependent on command set * * Copyright (C) 2002 Red Hat * Copyright (C) 2003 STMicroelectronics Limited diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 4e1be51cc122..ea832ea0e4aa 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -2075,7 +2075,7 @@ static inline int jedec_match( uint32_t base, } /* - * Make sure the ID's dissappear when the device is taken out of + * Make sure the ID's disappear when the device is taken out of * ID mode. The only time this should fail when it should succeed * is when the ID's are written as data to the same * addresses. For this rare and unfortunate case the chip diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index f29a6f9df6e7..97183c8c9e33 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -295,7 +295,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) dev->mtd.owner = THIS_MODULE; if (add_mtd_device(&dev->mtd)) { - /* Device didnt get added, so free the entry */ + /* Device didn't get added, so free the entry */ goto devinit_err; } list_add(&dev->list, &blkmtd_device_list); diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 719b2915dc3a..8b36fa77a195 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -90,7 +90,7 @@ static inline int DoC_WaitReady(void __iomem * docptr) return ret; } -/* For some reason the Millennium Plus seems to occassionally put itself +/* For some reason the Millennium Plus seems to occasionally put itself * into reset mode. For me this happens randomly, with no pattern that I * can detect. M-systems suggest always check this on any block level * operation and setting to normal mode if in reset mode. diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index a99838bb2dc0..37ef29a73ee4 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -109,7 +109,7 @@ for(ci=(n)-1;ci >=0;ci--)\ of the integer "alpha_to[i]" with a(0) being the LSB and a(m-1) the MSB. Thus for example the polynomial representation of @^5 would be given by the binary representation of the integer "alpha_to[5]". - Similarily, index_of[] can be used as follows: + Similarly, index_of[] can be used as follows: As above, let @ represent the primitive element of GF(2^m) that is the root of the primitive polynomial p(x). In order to find the power of @ (alpha) that has the polynomial representation @@ -121,7 +121,7 @@ for(ci=(n)-1;ci >=0;ci--)\ NOTE: The element alpha_to[2^m-1] = 0 always signifying that the representation of "@^infinity" = 0 is (0,0,0,...,0). - Similarily, the element index_of[0] = A0 always signifying + Similarly, the element index_of[0] = A0 always signifying that the power of alpha which has the polynomial representation (0,0,...,0) is "infinity". diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index caf604167f03..4b829f97d56c 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -353,7 +353,7 @@ static inline int erase_block (__u32 offset) /* put the flash back into command mode */ write32 (DATA_TO_FLASH (READ_ARRAY),offset); - /* was the erase successfull? */ + /* was the erase successful? */ if ((status & STATUS_ERASE_ERR)) { printk (KERN_WARNING "%s: erase error at address 0x%.8x.\n",module_name,offset); @@ -508,7 +508,7 @@ static inline int write_dword (__u32 offset,__u32 x) /* put the flash back into command mode */ write32 (DATA_TO_FLASH (READ_ARRAY),offset); - /* was the write successfull? */ + /* was the write successful? */ if ((status & STATUS_PGM_ERR) || read32 (offset) != x) { printk (KERN_WARNING "%s: write error at address 0x%.8x.\n",module_name,offset); diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index ef0aba0ce58f..41b8cdcc64cb 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -351,7 +351,7 @@ static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len, * Fixup routines for the V370PDC * PCI device ID 0x020011b0 * - * This function basicly kick starts the DRAM oboard the card and gets it + * This function basically kick starts the DRAM oboard the card and gets it * ready to be used. Before this is done the device reads VERY erratic, so * much that it can crash the Linux 2.2.x series kernels when a user cat's * /proc/pci .. though that is mainly a kernel bug in handling the PCI DEVSEL @@ -540,7 +540,7 @@ static u32 fixup_pmc551(struct pci_dev *dev) /* * Check to make certain the DEVSEL is set correctly, this device - * has a tendancy to assert DEVSEL and TRDY when a write is performed + * has a tendency to assert DEVSEL and TRDY when a write is performed * to the memory when memory is read-only */ if ((cmd & PCI_STATUS_DEVSEL_MASK) != 0x0) { diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 04fdfcca93f7..12679925b420 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -3,7 +3,7 @@ * erase, lock/unlock support for LPDDR flash memories * (C) 2008 Korolev Alexey * (C) 2008 Vasiliy Leonenko - * Many thanks to Roman Borisov for intial enabling + * Many thanks to Roman Borisov for initial enabling * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -171,7 +171,7 @@ static int wait_for_ready(struct map_info *map, struct flchip *chip, mutex_lock(&chip->mutex); } if (chip->erase_suspended || chip->write_suspended) { - /* Suspend has occured while sleep: reset timeout */ + /* Suspend has occurred while sleep: reset timeout */ timeo = reset_timeo; chip->erase_suspended = chip->write_suspended = 0; } diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index e5f645b775ad..23f551dc8ca8 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -42,7 +42,7 @@ * * Please note: * 1. The flash size given should be the largest flash size that can - * be accomodated. + * be accommodated. * * 2. The bus width must defined in clps_setup_flash. * @@ -58,7 +58,7 @@ #define BOOT_PARTITION_SIZE_KiB (16) #define PARAMS_PARTITION_SIZE_KiB (8) #define KERNEL_PARTITION_SIZE_KiB (4*128) -/* Use both remaing portion of first flash, and all of second flash */ +/* Use both remaining portion of first flash, and all of second flash */ #define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128) static struct mtd_partition ceiva_partitions[] = { diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index b4ed81611918..f71343cd77cc 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -33,7 +33,7 @@ /* We split the flash chip up into four parts. - * 1: bootloader firts 128k (0x00000000 - 0x0001FFFF) size 0x020000 + * 1: bootloader first 128k (0x00000000 - 0x0001FFFF) size 0x020000 * 2: kernel 640k (0x00020000 - 0x000BFFFF) size 0x0A0000 * 3: compressed 1536k root ramdisk (0x000C0000 - 0x0023FFFF) size 0x180000 * 4: writeable diskpartition (jffs)(0x00240000 - 0x003FFFFF) size 0x1C0000 diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index 917022948399..6799e75d74e0 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -497,7 +497,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp; /* Request a memory window for PCMCIA. Some architeures can map windows - * upto the maximum that PCMCIA can support (64MiB) - this is ideal and + * up to the maximum that PCMCIA can support (64MiB) - this is ideal and * we aim for a window the size of the whole card - otherwise we try * smaller windows until we succeed */ diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index acb13fa5001c..64aea6acd48e 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c @@ -3,7 +3,7 @@ * Config with both CFI and JEDEC device support. * * Basically physmap.c with the addition of partitions and - * an array of mapping info to accomodate more than one flash type per board. + * an array of mapping info to accommodate more than one flash type per board. * * Copyright 2005-2007 PMC-Sierra, Inc. * diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index 85c1e56309ec..4d8aaaf4bb76 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -197,7 +197,7 @@ static void sc520cdp_setup_par(void) } /* - ** Find the PARxx registers that are reponsible for activating + ** Find the PARxx registers that are responsible for activating ** ROMCS0, ROMCS1 and BOOTCS. Reprogram each of these with a ** new value from the table. */ diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index c08e140d40ed..0718dfb3ee64 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -63,7 +63,7 @@ static void __iomem *start_scan_addr; */ #ifdef CONFIG_MTD_PARTITIONS -/* Currently, TQM8xxL has upto 8MiB flash */ +/* Currently, TQM8xxL has up to 8MiB flash */ static unsigned long tqm8xxl_max_flash_size = 0x00800000; /* partition definition for first flash bank diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 1e74ad961040..3326615ad66b 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -129,7 +129,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) return ret; /* - * Here we could argubly set the cache state to STATE_CLEAN. + * Here we could arguably set the cache state to STATE_CLEAN. * However this could lead to inconsistency since we will not * be notified if this content is altered on the flash by other * means. Let's declare it empty and leave buffering tasks to diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 145b3d0dc0db..4c36ef66a46b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -234,7 +234,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t * the data. For our userspace tools it is important * to dump areas with ecc errors ! * For kernel internal usage it also might return -EUCLEAN - * to signal the caller that a bitflip has occured and has + * to signal the caller that a bitflip has occurred and has * been corrected by the ECC algorithm. * Userspace software which accesses NAND this way * must be aware of the fact that it deals with NAND diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index a92054e945e1..edec457d361d 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -239,7 +239,7 @@ config MTD_NAND_BCM_UMI help This enables the NAND flash controller on the BCM UMI block. - No board specfic support is done by this driver, each board + No board specific support is done by this driver, each board must advertise a platform_device for the driver to attach. config MTD_NAND_BCM_UMI_HWCS diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index a067d090cb31..bc65bf71e1a2 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -228,7 +228,7 @@ static int __devinit ams_delta_init(struct platform_device *pdev) AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP); - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan(ams_delta_mtd, 1)) { err = -ENXIO; goto out_mtd; diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 7c95da1f612c..0911cf03db80 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -176,7 +176,7 @@ static int __init autcpu12_init(void) */ this->options = NAND_USE_FLASH_BBT; - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan(autcpu12_mtd, 1)) { err = -ENXIO; goto out_ior; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index 9f1b451005ca..71c35a0b9826 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -241,7 +241,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) /* Enable the following for a flash based bad block table */ this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan(new_mtd, 1)) { err = -ENXIO; goto out_ior; diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 8c8d3c86c0e8..4633f094c510 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -724,7 +724,7 @@ static uint32_t wait_for_irq(struct denali_nand_info *denali, uint32_t irq_mask) } /* This helper function setups the registers for ECC and whether or not - * the spare area will be transfered. */ + * the spare area will be transferred. */ static void setup_ecc_for_xfer(struct denali_nand_info *denali, bool ecc_en, bool transfer_spare) { @@ -965,7 +965,7 @@ static bool handle_ecc(struct denali_nand_info *denali, uint8_t *buf, if (ECC_ERROR_CORRECTABLE(err_correction_info)) { /* If err_byte is larger than ECC_SECTOR_SIZE, - * means error happend in OOB, so we ignore + * means error happened in OOB, so we ignore * it. It's no need for us to correct it * err_device is represented the NAND error * bits are happened in if there are more @@ -1109,7 +1109,7 @@ static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip, } /* This is the callback that the NAND core calls to write a page without ECC. - * raw access is similiar to ECC page writes, so all the work is done in the + * raw access is similar to ECC page writes, so all the work is done in the * write_page() function above. */ static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index b7f8de7b2780..96c0b34ba8db 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -137,7 +137,7 @@ static struct rs_control *rs_decoder; * * Fabrice Bellard figured this out in the old docecc code. I added * some comments, improved a minor bit and converted it to make use - * of the generic Reed-Solomon libary. tglx + * of the generic Reed-Solomon library. tglx */ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) { @@ -400,7 +400,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* We cant' use dev_ready here, but at least we wait for the + /* We can't' use dev_ready here, but at least we wait for the * command to complete */ udelay(50); @@ -986,7 +986,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, dummy = ReadDOC(docptr, ECCConf); } - /* Error occured ? */ + /* Error occurred ? */ if (dummy & 0x80) { for (i = 0; i < 6; i++) { if (DoC_is_MillenniumPlus(doc)) @@ -1160,7 +1160,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio /* NOTE: The lines below modify internal variables of the NAND and MTD layers; variables with have already been configured by nand_scan. Unfortunately, we didn't know before this point what these values - should be. Thus, this code is somewhat dependant on the exact + should be. Thus, this code is somewhat dependent on the exact implementation of the NAND layer. */ if (mh->UnitSizeFactor != 0xff) { this->bbt_erase_shift += (0xff - mh->UnitSizeFactor); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 7a13d42cbabd..537e380b8dcb 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -59,7 +59,7 @@ struct fsl_elbc_mtd { unsigned int fmr; /* FCM Flash Mode Register value */ }; -/* Freescale eLBC FCM controller infomation */ +/* Freescale eLBC FCM controller information */ struct fsl_elbc_fcm_ctrl { struct nand_hw_control controller; diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 205b10b9f9b9..0d45ef3883e8 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -335,7 +335,7 @@ static void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) /* * fsmc_read_hwecc_ecc4 - Hardware ECC calculator for ecc4 option supported by - * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction upto + * FSMC. ECC is 13 bytes for 512 bytes of data (supports error correction up to * max of 8-bits) */ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, @@ -381,7 +381,7 @@ static int fsmc_read_hwecc_ecc4(struct mtd_info *mtd, const uint8_t *data, /* * fsmc_read_hwecc_ecc1 - Hardware ECC calculator for ecc1 option supported by - * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction upto + * FSMC. ECC is 3 bytes for 512 bytes of data (supports error correction up to * max of 1-bit) */ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, @@ -408,10 +408,10 @@ static int fsmc_read_hwecc_ecc1(struct mtd_info *mtd, const uint8_t *data, * @buf: buffer to store read data * @page: page number to read * - * This routine is needed for fsmc verison 8 as reading from NAND chip has to be + * This routine is needed for fsmc version 8 as reading from NAND chip has to be * performed in a strict sequence as follows: * data(512 byte) -> ecc(13 byte) - * After this read, fsmc hardware generates and reports error data bits(upto a + * After this read, fsmc hardware generates and reports error data bits(up to a * max of 8 bits) */ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, @@ -686,7 +686,7 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) } /* - * Scan to find existance of the device + * Scan to find existence of the device */ if (nand_scan_ident(&host->mtd, 1, NULL)) { ret = -ENXIO; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 85cfc061d41c..c54a4cbac6bc 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1582,7 +1582,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } /** - * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc + * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index a1e8b30078d9..af46428286fe 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -945,7 +945,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc rd2 = NULL; /* Per chip or per device ? */ chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table avilable ? */ + /* Mirrored table available ? */ if (md) { if (td->pages[i] == -1 && md->pages[i] == -1) { writeops = 0x03; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 213181be0d9a..893d95bfea48 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -162,7 +162,7 @@ MODULE_PARM_DESC(bitflips, "Maximum number of random bit flips per page (z MODULE_PARM_DESC(gravepages, "Pages that lose data [: maximum reads (defaults to 3)]" " separated by commas e.g. 1401:2 means page 1401" " can be read only twice before failing"); -MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if not zero"); +MODULE_PARM_DESC(rptwear, "Number of erases between reporting wear, if not zero"); MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " "The size is specified in erase blocks and as the exponent of a power of two" " e.g. 5 means a size of 32 erase blocks"); diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index 8c0b69375224..a045a4a581b6 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -151,7 +151,7 @@ static int nomadik_nand_probe(struct platform_device *pdev) nand->options = pdata->options; /* - * Scan to find existance of the device + * Scan to find existence of the device */ if (nand_scan(&host->mtd, 1)) { ret = -ENXIO; diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 59efa829ef24..20bfe5f15afd 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -157,7 +157,7 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) /* Enable the following for a flash based bad block table */ chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan(pasemi_nand_mtd, 1)) { err = -ENXIO; goto out_lpc; diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 317aff428e42..caf5a736340a 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -95,7 +95,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) goto out; } - /* Scan to find existance of the device */ + /* Scan to find existence of the device */ if (nand_scan(&data->mtd, pdata->chip.nr_chips)) { err = -ENXIO; goto out; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index ab7f4c33ced6..ff0701276d65 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -184,7 +184,7 @@ struct pxa3xx_nand_info { static int use_dma = 1; module_param(use_dma, bool, 0444); -MODULE_PARM_DESC(use_dma, "enable DMA for data transfering to/from NAND HW"); +MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW"); /* * Default NAND flash controller configuration setup by the diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 6322d1fb5d62..cae2e013c986 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -185,7 +185,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read) dbg_verbose("doing dma %s ", do_read ? "read" : "write"); - /* Set intial dma state: for reading first fill on board buffer, + /* Set initial dma state: for reading first fill on board buffer, from device, for writes first fill the buffer from memory*/ dev->dma_state = do_read ? DMA_INTERNAL : DMA_MEMORY; @@ -766,7 +766,7 @@ static irqreturn_t r852_irq(int irq, void *data) ret = IRQ_HANDLED; dev->card_detected = !!(card_status & R852_CARD_IRQ_INSERT); - /* we shouldn't recieve any interrupts if we wait for card + /* we shouldn't receive any interrupts if we wait for card to settle */ WARN_ON(dev->card_unstable); @@ -794,13 +794,13 @@ static irqreturn_t r852_irq(int irq, void *data) ret = IRQ_HANDLED; if (dma_status & R852_DMA_IRQ_ERROR) { - dbg("recieved dma error IRQ"); + dbg("received dma error IRQ"); r852_dma_done(dev, -EIO); complete(&dev->dma_done); goto out; } - /* recieved DMA interrupt out of nowhere? */ + /* received DMA interrupt out of nowhere? */ WARN_ON_ONCE(dev->dma_stage == 0); if (dev->dma_stage == 0) @@ -960,7 +960,7 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) &dev->card_detect_work, 0); - printk(KERN_NOTICE DRV_NAME ": driver loaded succesfully\n"); + printk(KERN_NOTICE DRV_NAME ": driver loaded successfully\n"); return 0; error10: diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 546c2f0eb2e8..81bbb5ee148d 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -78,7 +78,7 @@ static void start_translation(struct sh_flctl *flctl) static void timeout_error(struct sh_flctl *flctl, const char *str) { - dev_err(&flctl->pdev->dev, "Timeout occured in %s\n", str); + dev_err(&flctl->pdev->dev, "Timeout occurred in %s\n", str); } static void wait_completion(struct sh_flctl *flctl) diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index 4a8f367c295c..57cc80cd01a3 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -121,7 +121,7 @@ int sm_register_device(struct mtd_info *mtd, int smartmedia) if (ret) return ret; - /* Bad block marker postion */ + /* Bad block marker position */ chip->badblockpos = 0x05; chip->badblockbits = 7; chip->block_markbad = sm_block_markbad; diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 38fb16771f85..14c578707824 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -4,7 +4,7 @@ * Slightly murky pre-git history of the driver: * * Copyright (c) Ian Molton 2004, 2005, 2008 - * Original work, independant of sharps code. Included hardware ECC support. + * Original work, independent of sharps code. Included hardware ECC support. * Hard ECC did not work for writes in the early revisions. * Copyright (c) Dirk Opfer 2005. * Modifications developed from sharps code but diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index f591f615d3f6..1fcb41adab07 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -608,7 +608,7 @@ static int omap2_onenand_enable(struct mtd_info *mtd) ret = regulator_enable(c->regulator); if (ret != 0) - dev_err(&c->pdev->dev, "cant enable regulator\n"); + dev_err(&c->pdev->dev, "can't enable regulator\n"); return ret; } @@ -620,7 +620,7 @@ static int omap2_onenand_disable(struct mtd_info *mtd) ret = regulator_disable(c->regulator); if (ret != 0) - dev_err(&c->pdev->dev, "cant disable regulator\n"); + dev_err(&c->pdev->dev, "can't disable regulator\n"); return ret; } diff --git a/drivers/mtd/onenand/onenand_sim.c b/drivers/mtd/onenand/onenand_sim.c index 8b246061d511..5ef3bd547772 100644 --- a/drivers/mtd/onenand/onenand_sim.c +++ b/drivers/mtd/onenand/onenand_sim.c @@ -321,7 +321,7 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, continue; if (memcmp(dest + off, ffchars, this->subpagesize) && onenand_check_overwrite(dest + off, src + off, this->subpagesize)) - printk(KERN_ERR "over-write happend at 0x%08x\n", offset); + printk(KERN_ERR "over-write happened at 0x%08x\n", offset); memcpy(dest + off, src + off, this->subpagesize); } /* Fall through */ @@ -335,7 +335,7 @@ static void onenand_data_handle(struct onenand_chip *this, int cmd, dest = ONENAND_CORE_SPARE(flash, this, offset); if (memcmp(dest, ffchars, mtd->oobsize) && onenand_check_overwrite(dest, src, mtd->oobsize)) - printk(KERN_ERR "OOB: over-write happend at 0x%08x\n", + printk(KERN_ERR "OOB: over-write happened at 0x%08x\n", offset); memcpy(dest, src, mtd->oobsize); break; diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index 2b0daae4018d..ed3d6cd2c6dc 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -540,7 +540,7 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) return -EIO; } - /* If the block is sliced (partialy erased usually) erase it */ + /* If the block is sliced (partially erased usually) erase it */ if (i == 2) { sm_erase_block(ftl, zone, block, 1); return 1; @@ -878,7 +878,7 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num) return 0; } -/* Get and automaticly initialize an FTL mapping for one zone */ +/* Get and automatically initialize an FTL mapping for one zone */ struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num) { struct ftl_zone *zone; diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index 11eb8ef12485..d2d12ab7def4 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -968,7 +968,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, * contains garbage because of a power cut during erase * operation. So we just schedule this PEB for erasure. * - * Besides, in case of NOR flash, we deliberatly + * Besides, in case of NOR flash, we deliberately * corrupt both headers because NOR flash erasure is * slow and can start from the end. */ diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 9e1c03eb97ae..5420f6de27df 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -399,7 +399,7 @@ static void el_timeout(struct net_device *dev) * as we may still be attempting to retrieve the last RX packet buffer. * * When a transmit times out we dump the card into control mode and just - * start again. It happens enough that it isnt worth logging. + * start again. It happens enough that it isn't worth logging. * * We avoid holding the spin locks when doing the packet load to the board. * The device is very slow, and its DMA mode is even slower. If we held the @@ -499,7 +499,7 @@ static netdev_tx_t el_start_xmit(struct sk_buff *skb, struct net_device *dev) * * Handle the ether interface interrupts. The 3c501 needs a lot more * hand holding than most cards. In particular we get a transmit interrupt - * with a collision error because the board firmware isnt capable of rewinding + * with a collision error because the board firmware isn't capable of rewinding * its own transmit buffer pointers. It can however count to 16 for us. * * On the receive side the card is also very dumb. It has no buffering to @@ -732,7 +732,7 @@ static void el_receive(struct net_device *dev) * el_reset: Reset a 3c501 card * @dev: The 3c501 card about to get zapped * - * Even resetting a 3c501 isnt simple. When you activate reset it loses all + * Even resetting a 3c501 isn't simple. When you activate reset it loses all * its configuration. You must hold the lock when doing this. The function * cannot take the lock itself as it is callable from the irq handler. */ diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index de579d043169..bc0d1a1c2e28 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -44,7 +44,7 @@ this for the 64K version would require a lot of heinous bank switching, which I'm sure not interested in doing. If you try to implement a bank switching version, you'll basically have to remember - what bank is enabled and do a switch everytime you access a memory + what bank is enabled and do a switch every time you access a memory location that's not current. You'll also have to remap pointers on the driver side, because it only knows about 16K of the memory. Anyone desperate or masochistic enough to try? diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 8c094bae8bf3..d9d056d207f3 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -51,7 +51,7 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter tx_csm != ap->tx_ret_csm) { printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n", @@ -2564,7 +2564,7 @@ restart: /* * A TX-descriptor producer (an IRQ) might have gotten - * inbetween, making the ring free again. Since xmit is + * between, making the ring free again. Since xmit is * serialized, this is the only situation we have to * re-test. */ diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 2ca880b4c0db..88495c48a81d 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1398,7 +1398,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) mc_filter[1] = mc_filter[0] = 0; lp->options &= ~OPTION_MULTICAST_ENABLE; amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF); - /* disable promiscous mode */ + /* disable promiscuous mode */ writel(PROM, lp->mmio + CMD2); return; } diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index f4744fc89768..65a78f965dd2 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -133,7 +133,7 @@ struct net_local { /* Run-time register bank 2 definitions. */ #define DATAPORT 8 /* Word-wide DMA or programmed-I/O dataport. */ #define TX_START 10 -#define COL16CNTL 11 /* Controll Reg for 16 collisions */ +#define COL16CNTL 11 /* Control Reg for 16 collisions */ #define MODE13 13 #define RX_CTRL 14 /* Configuration registers only on the '865A/B chips. */ diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 1ff001a8270c..b0a71e2f28a9 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -2509,7 +2509,7 @@ static struct pci_driver atl1e_driver = { .id_table = atl1e_pci_tbl, .probe = atl1e_probe, .remove = __devexit_p(atl1e_remove), - /* Power Managment Hooks */ + /* Power Management Hooks */ #ifdef CONFIG_PM .suspend = atl1e_suspend, .resume = atl1e_resume, diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index e637e9f28fd4..f46ee4546fdc 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -1701,7 +1701,7 @@ static struct pci_driver atl2_driver = { .id_table = atl2_pci_tbl, .probe = atl2_probe, .remove = __devexit_p(atl2_remove), - /* Power Managment Hooks */ + /* Power Management Hooks */ .suspend = atl2_suspend, #ifdef CONFIG_PM .resume = atl2_resume, diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c index e94a966af418..c48104b08861 100644 --- a/drivers/net/bcm63xx_enet.c +++ b/drivers/net/bcm63xx_enet.c @@ -597,7 +597,7 @@ static int bcm_enet_set_mac_address(struct net_device *dev, void *p) } /* - * Change rx mode (promiscous/allmulti) and update multicast list + * Change rx mode (promiscuous/allmulti) and update multicast list */ static void bcm_enet_set_multicast_list(struct net_device *dev) { diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 5a4a87e7c5ea..1e2d825bb94a 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -1331,7 +1331,7 @@ err: /* * Uses MCC for this command as it may be called in BH context - * (mc == NULL) => multicast promiscous + * (mc == NULL) => multicast promiscuous */ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, struct net_device *netdev, struct be_dma_mem *mem) diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a71163f1e34b..9a54c8b24ff9 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -708,7 +708,7 @@ static void be_set_multicast_list(struct net_device *netdev) goto done; } - /* BE was previously in promiscous mode; disable it */ + /* BE was previously in promiscuous mode; disable it */ if (adapter->promiscuous) { adapter->promiscuous = false; be_cmd_promiscuous_config(adapter, adapter->port_num, 0); diff --git a/drivers/net/bna/bna_hw.h b/drivers/net/bna/bna_hw.h index 806b224a4c63..6cb89692f5c1 100644 --- a/drivers/net/bna/bna_hw.h +++ b/drivers/net/bna/bna_hw.h @@ -897,7 +897,7 @@ static struct bna_ritseg_pool_cfg name[BFI_RIT_SEG_TOTAL_POOLS] = \ * Catapult RSS Table Base Offset Address * * Exists in RAD memory space. - * Each entry is 352 bits, but alligned on + * Each entry is 352 bits, but aligned on * 64 byte (512 bit) boundary. Accessed * 4 byte words, the whole entry can be * broken into 11 word accesses. diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index b7ff87b35fbb..e0fca701d2f3 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -1220,7 +1220,7 @@ struct bnx2x { struct bnx2x_dcbx_port_params dcbx_port_params; int dcb_version; - /* DCBX Negotation results */ + /* DCBX Negotiation results */ struct dcbx_features dcbx_local_feat; u32 dcbx_error; u32 pending_max; diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index be503cc0a50b..dac1bf9cbbfa 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -3019,7 +3019,7 @@ struct tstorm_eth_mac_filter_config { /* - * common flag to indicate existance of TPA. + * common flag to indicate existence of TPA. */ struct tstorm_eth_tpa_exist { #if defined(__BIG_ENDIAN) diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index f2f367d4e74d..974ef2be36a5 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -2823,7 +2823,7 @@ static u16 bnx2x_wait_reset_complete(struct bnx2x *bp, struct link_params *params) { u16 cnt, ctrl; - /* Wait for soft reset to get cleared upto 1 sec */ + /* Wait for soft reset to get cleared up to 1 sec */ for (cnt = 0; cnt < 1000; cnt++) { bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, &ctrl); @@ -4141,7 +4141,7 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, val = (1<<5); /* * Note that 2.5G works only when used with 1G - * advertisment + * advertisement */ } else val = (1<<5); @@ -4151,7 +4151,7 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) val |= (1<<7); - /* Note that 2.5G works only when used with 1G advertisment */ + /* Note that 2.5G works only when used with 1G advertisement */ if (phy->speed_cap_mask & (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G | PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) @@ -5232,14 +5232,14 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1); } else { - /* Force 1Gbps using autoneg with 1G advertisment */ + /* Force 1Gbps using autoneg with 1G advertisement */ /* Allow CL37 through CL73 */ DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n"); bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c); - /* Enable Full-Duplex advertisment on CL37 */ + /* Enable Full-Duplex advertisement on CL37 */ bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020); /* Enable CL37 AN */ @@ -6269,7 +6269,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, switch (actual_phy_selection) { case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: - /* Do nothing. Essentialy this is like the priority copper */ + /* Do nothing. Essentially this is like the priority copper */ break; case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER; @@ -7765,7 +7765,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); msleep(10); - /* The PHY reset is controled by GPIO 1 + /* The PHY reset is controlled by GPIO 1 * Hold it as vars low */ /* clear link led */ diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 32e64cc85d2c..a97a4a1c344f 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -3702,7 +3702,7 @@ static void bnx2x_eq_int(struct bnx2x *bp) if ((hw_cons & EQ_DESC_MAX_PAGE) == EQ_DESC_MAX_PAGE) hw_cons++; - /* This function may never run in parralel with itself for a + /* This function may never run in parallel with itself for a * specific bp, thus there is no need in "paired" read memory * barrier here. */ @@ -5089,7 +5089,7 @@ static int bnx2x_init_hw_common(struct bnx2x *bp, u32 load_code) /* Step 1: set zeroes to all ilt page entries with valid bit on * Step 2: set the timers first/last ilt entry to point * to the entire range to prevent ILT range error for 3rd/4th - * vnic (this code assumes existance of the vnic) + * vnic (this code assumes existence of the vnic) * * both steps performed by call to bnx2x_ilt_client_init_op() * with dummy TM client @@ -8685,7 +8685,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) E1H_FUNC_MAX * sizeof(struct drv_func_mb); /* * get mf configuration: - * 1. existance of MF configuration + * 1. existence of MF configuration * 2. MAC address must be legal (check only upper bytes) * for Switch-Independent mode; * OVLAN must be legal for Switch-Dependent mode @@ -8727,7 +8727,7 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) default: /* Unknown configuration: reset mf_config */ bp->mf_config[vn] = 0; - DP(NETIF_MSG_PROBE, "Unkown MF mode 0x%x\n", + DP(NETIF_MSG_PROBE, "Unknown MF mode 0x%x\n", val); } } @@ -9777,7 +9777,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, #endif - /* Configure interupt mode: try to enable MSI-X/MSI if + /* Configure interrupt mode: try to enable MSI-X/MSI if * needed, set bp->num_queues appropriately. */ bnx2x_set_int_mode(bp); diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 1c89f19a4425..1509a2318af9 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -175,9 +175,9 @@ the initial credit value; read returns the current value of the credit counter. Must be initialized to 1 at start-up. */ #define CCM_REG_CFC_INIT_CRD 0xd0204 -/* [RW 2] Auxillary counter flag Q number 1. */ +/* [RW 2] Auxiliary counter flag Q number 1. */ #define CCM_REG_CNT_AUX1_Q 0xd00c8 -/* [RW 2] Auxillary counter flag Q number 2. */ +/* [RW 2] Auxiliary counter flag Q number 2. */ #define CCM_REG_CNT_AUX2_Q 0xd00cc /* [RW 28] The CM header value for QM request (primary). */ #define CCM_REG_CQM_CCM_HDR_P 0xd008c @@ -457,13 +457,13 @@ #define CSDM_REG_AGG_INT_MODE_9 0xc21dc /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define CSDM_REG_CFC_RSP_START_ADDR 0xc2008 -/* [RW 16] The maximum value of the competion counter #0 */ +/* [RW 16] The maximum value of the completion counter #0 */ #define CSDM_REG_CMP_COUNTER_MAX0 0xc201c -/* [RW 16] The maximum value of the competion counter #1 */ +/* [RW 16] The maximum value of the completion counter #1 */ #define CSDM_REG_CMP_COUNTER_MAX1 0xc2020 -/* [RW 16] The maximum value of the competion counter #2 */ +/* [RW 16] The maximum value of the completion counter #2 */ #define CSDM_REG_CMP_COUNTER_MAX2 0xc2024 -/* [RW 16] The maximum value of the competion counter #3 */ +/* [RW 16] The maximum value of the completion counter #3 */ #define CSDM_REG_CMP_COUNTER_MAX3 0xc2028 /* [RW 13] The start address in the internal RAM for the completion counters. */ @@ -851,7 +851,7 @@ #define IGU_REG_ATTN_MSG_ADDR_L 0x130120 /* [R 4] Debug: [3] - attention write done message is pending (0-no pending; * 1-pending). [2:0] = PFID. Pending means attention message was sent; but - * write done didnt receive. */ + * write done didn't receive. */ #define IGU_REG_ATTN_WRITE_DONE_PENDING 0x130030 #define IGU_REG_BLOCK_CONFIGURATION 0x130000 #define IGU_REG_COMMAND_REG_32LSB_DATA 0x130124 @@ -862,7 +862,7 @@ #define IGU_REG_CSTORM_TYPE_0_SB_CLEANUP 0x130200 /* [R 5] Debug: ctrl_fsm */ #define IGU_REG_CTRL_FSM 0x130064 -/* [R 1] data availble for error memory. If this bit is clear do not red +/* [R 1] data available for error memory. If this bit is clear do not red * from error_handling_memory. */ #define IGU_REG_ERROR_HANDLING_DATA_VALID 0x130130 /* [RW 11] Parity mask register #0 read/write */ @@ -3015,7 +3015,7 @@ block. Should be used for close the gates. */ #define PXP_REG_HST_DISCARD_DOORBELLS 0x1030a4 /* [R 1] debug only: '1' means this PSWHST is discarding doorbells. This bit - should update accoring to 'hst_discard_doorbells' register when the state + should update according to 'hst_discard_doorbells' register when the state machine is idle */ #define PXP_REG_HST_DISCARD_DOORBELLS_STATUS 0x1030a0 /* [RW 1] When 1; new internal writes arriving to the block are discarded. @@ -3023,7 +3023,7 @@ #define PXP_REG_HST_DISCARD_INTERNAL_WRITES 0x1030a8 /* [R 6] debug only: A bit mask for all PSWHST internal write clients. '1' means this PSWHST is discarding inputs from this client. Each bit should - update accoring to 'hst_discard_internal_writes' register when the state + update according to 'hst_discard_internal_writes' register when the state machine is idle. */ #define PXP_REG_HST_DISCARD_INTERNAL_WRITES_STATUS 0x10309c /* [WB 160] Used for initialization of the inbound interrupts memory */ @@ -3822,13 +3822,13 @@ #define TSDM_REG_AGG_INT_T_1 0x420bc /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define TSDM_REG_CFC_RSP_START_ADDR 0x42008 -/* [RW 16] The maximum value of the competion counter #0 */ +/* [RW 16] The maximum value of the completion counter #0 */ #define TSDM_REG_CMP_COUNTER_MAX0 0x4201c -/* [RW 16] The maximum value of the competion counter #1 */ +/* [RW 16] The maximum value of the completion counter #1 */ #define TSDM_REG_CMP_COUNTER_MAX1 0x42020 -/* [RW 16] The maximum value of the competion counter #2 */ +/* [RW 16] The maximum value of the completion counter #2 */ #define TSDM_REG_CMP_COUNTER_MAX2 0x42024 -/* [RW 16] The maximum value of the competion counter #3 */ +/* [RW 16] The maximum value of the completion counter #3 */ #define TSDM_REG_CMP_COUNTER_MAX3 0x42028 /* [RW 13] The start address in the internal RAM for the completion counters. */ @@ -4284,13 +4284,13 @@ #define USDM_REG_AGG_INT_T_6 0xc40d0 /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define USDM_REG_CFC_RSP_START_ADDR 0xc4008 -/* [RW 16] The maximum value of the competion counter #0 */ +/* [RW 16] The maximum value of the completion counter #0 */ #define USDM_REG_CMP_COUNTER_MAX0 0xc401c -/* [RW 16] The maximum value of the competion counter #1 */ +/* [RW 16] The maximum value of the completion counter #1 */ #define USDM_REG_CMP_COUNTER_MAX1 0xc4020 -/* [RW 16] The maximum value of the competion counter #2 */ +/* [RW 16] The maximum value of the completion counter #2 */ #define USDM_REG_CMP_COUNTER_MAX2 0xc4024 -/* [RW 16] The maximum value of the competion counter #3 */ +/* [RW 16] The maximum value of the completion counter #3 */ #define USDM_REG_CMP_COUNTER_MAX3 0xc4028 /* [RW 13] The start address in the internal RAM for the completion counters. */ @@ -4798,13 +4798,13 @@ #define XSDM_REG_AGG_INT_MODE_1 0x1661bc /* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ #define XSDM_REG_CFC_RSP_START_ADDR 0x166008 -/* [RW 16] The maximum value of the competion counter #0 */ +/* [RW 16] The maximum value of the completion counter #0 */ #define XSDM_REG_CMP_COUNTER_MAX0 0x16601c -/* [RW 16] The maximum value of the competion counter #1 */ +/* [RW 16] The maximum value of the completion counter #1 */ #define XSDM_REG_CMP_COUNTER_MAX1 0x166020 -/* [RW 16] The maximum value of the competion counter #2 */ +/* [RW 16] The maximum value of the completion counter #2 */ #define XSDM_REG_CMP_COUNTER_MAX2 0x166024 -/* [RW 16] The maximum value of the competion counter #3 */ +/* [RW 16] The maximum value of the completion counter #3 */ #define XSDM_REG_CMP_COUNTER_MAX3 0x166028 /* [RW 13] The start address in the internal RAM for the completion counters. */ diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 118c28aa471e..b3bc7502868f 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -76,7 +76,7 @@ struct tlb_client_info { */ u32 tx_bytes; /* Each Client acumulates the BytesTx that * were tranmitted to it, and after each - * CallBack the LoadHistory is devided + * CallBack the LoadHistory is divided * by the balance interval */ u32 load_history; /* This field contains the amount of Bytes diff --git a/drivers/net/caif/caif_shmcore.c b/drivers/net/caif/caif_shmcore.c index 80511167f35b..731aa1193770 100644 --- a/drivers/net/caif/caif_shmcore.c +++ b/drivers/net/caif/caif_shmcore.c @@ -591,7 +591,7 @@ int caif_shmcore_probe(struct shmdev_layer *pshm_dev) (NR_TX_BUF * TX_BUF_SZ + NR_RX_BUF * RX_BUF_SZ)) { pr_warn("ERROR, Amount of available" - " Phys. SHM cannot accomodate current SHM " + " Phys. SHM cannot accommodate current SHM " "driver configuration, Bailing out ...\n"); free_netdev(pshm_dev->pshm_netdev); return -ENOMEM; diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 20da1996d354..57e639373815 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -397,7 +397,7 @@ int cfspi_xmitlen(struct cfspi *cfspi) int pkts = 0; /* - * Decommit previously commited frames. + * Decommit previously committed frames. * skb_queue_splice_tail(&cfspi->chead,&cfspi->qhead) */ while (skb_peek(&cfspi->chead)) { diff --git a/drivers/net/caif/caif_spi_slave.c b/drivers/net/caif/caif_spi_slave.c index 1b9943a4edab..b009e03cda9e 100644 --- a/drivers/net/caif/caif_spi_slave.c +++ b/drivers/net/caif/caif_spi_slave.c @@ -98,7 +98,7 @@ void cfspi_xfer(struct work_struct *work) cfspi_dbg_state(cfspi, CFSPI_STATE_FETCH_PKT); - /* Copy commited SPI frames after the SPI indication. */ + /* Copy committed SPI frames after the SPI indication. */ ptr = (u8 *) cfspi->xfer.va_tx; ptr += SPI_IND_SZ; len = cfspi_xmitfrm(cfspi, ptr, cfspi->tx_cpck_len); @@ -158,7 +158,7 @@ void cfspi_xfer(struct work_struct *work) cfspi_dbg_state(cfspi, CFSPI_STATE_SIG_ACTIVE); - /* Signal that we are ready to recieve data. */ + /* Signal that we are ready to receive data. */ cfspi->dev->sig_xfer(true, cfspi->dev); cfspi_dbg_state(cfspi, CFSPI_STATE_WAIT_XFER_DONE); diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 57d2ffbbb433..74efb5a2ad41 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -416,7 +416,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_bytes += cf->can_dlc; - /* _NOTE_: substract AT91_MB_TX_FIRST offset from mb! */ + /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ can_put_echo_skb(skb, dev, mb - AT91_MB_TX_FIRST); /* @@ -782,7 +782,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) reg_msr = at91_read(priv, AT91_MSR(mb)); if (likely(reg_msr & AT91_MSR_MRDY && ~reg_msr & AT91_MSR_MABT)) { - /* _NOTE_: substract AT91_MB_TX_FIRST offset from mb! */ + /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ can_get_echo_skb(dev, mb - AT91_MB_TX_FIRST); dev->stats.tx_packets++; } diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c index 31552959aed7..7e5cc0bd913d 100644 --- a/drivers/net/can/c_can/c_can.c +++ b/drivers/net/can/c_can/c_can.c @@ -813,7 +813,7 @@ static int c_can_handle_state_change(struct net_device *dev, struct sk_buff *skb; struct can_berr_counter bec; - /* propogate the error condition to the CAN stack */ + /* propagate the error condition to the CAN stack */ skb = alloc_can_err_skb(dev, &cf); if (unlikely(!skb)) return 0; @@ -887,7 +887,7 @@ static int c_can_handle_bus_err(struct net_device *dev, if (lec_type == LEC_UNUSED || lec_type == LEC_NO_ERROR) return 0; - /* propogate the error condition to the CAN stack */ + /* propagate the error condition to the CAN stack */ skb = alloc_can_err_skb(dev, &cf); if (unlikely(!skb)) return 0; diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 102b16c6cc97..587fba48cdd9 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -274,7 +274,7 @@ static inline void ican3_set_page(struct ican3_dev *mod, unsigned int page) */ /* - * Recieve a message from the ICAN3 "old-style" firmware interface + * Receive a message from the ICAN3 "old-style" firmware interface * * LOCKING: must hold mod->lock * @@ -1050,7 +1050,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) complete(&mod->termination_comp); break; default: - dev_err(mod->dev, "recieved an unknown inquiry response\n"); + dev_err(mod->dev, "received an unknown inquiry response\n"); break; } } @@ -1058,7 +1058,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) static void ican3_handle_unknown_message(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_warn(mod->dev, "recieved unknown message: spec 0x%.2x length %d\n", + dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n", msg->spec, le16_to_cpu(msg->len)); } @@ -1113,7 +1113,7 @@ static bool ican3_txok(struct ican3_dev *mod) } /* - * Recieve one CAN frame from the hardware + * Receive one CAN frame from the hardware * * CONTEXT: must be called from user context */ diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c index 74cd880c7e06..92feac68b66e 100644 --- a/drivers/net/can/mscan/mscan.c +++ b/drivers/net/can/mscan/mscan.c @@ -246,7 +246,7 @@ static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev) out_be16(®s->tx.idr3_2, can_id); can_id >>= 16; - /* EFF_FLAGS are inbetween the IDs :( */ + /* EFF_FLAGS are between the IDs :( */ can_id = (can_id & 0x7) | ((can_id << 2) & 0xffe0) | MSCAN_EFF_FLAGS; } else { diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index 0a8de01d52f7..a358ea9445a2 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -425,7 +425,7 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status) cf->data[3] = ecc & ECC_SEG; break; } - /* Error occured during transmission? */ + /* Error occurred during transmission? */ if ((ecc & ECC_DIR) == 0) cf->data[2] |= CAN_ERR_PROT_TX; } diff --git a/drivers/net/can/softing/softing.h b/drivers/net/can/softing/softing.h index 7ec9f4db3d52..afd7d85b6915 100644 --- a/drivers/net/can/softing/softing.h +++ b/drivers/net/can/softing/softing.h @@ -22,7 +22,7 @@ struct softing_priv { struct softing *card; struct { int pending; - /* variables wich hold the circular buffer */ + /* variables which hold the circular buffer */ int echo_put; int echo_get; } tx; diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c index aeea9f9ff6e8..7a70709d5608 100644 --- a/drivers/net/can/softing/softing_main.c +++ b/drivers/net/can/softing/softing_main.c @@ -218,7 +218,7 @@ static int softing_handle_1(struct softing *card) ptr = buf; cmd = *ptr++; if (cmd == 0xff) - /* not quite usefull, probably the card has got out */ + /* not quite useful, probably the card has got out */ return 0; netdev = card->net[0]; if (cmd & CMD_BUS2) diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 4d07f1ee7168..f7bbde9eb2cb 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -663,7 +663,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status, struct can_frame *cf; struct sk_buff *skb; - /* propogate the error condition to the can stack */ + /* propagate the error condition to the can stack */ skb = alloc_can_err_skb(ndev, &cf); if (!skb) { if (printk_ratelimit()) diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index e75f1a876972..a72c7bfb4090 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -386,7 +386,7 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg) break; } - /* Error occured during transmission? */ + /* Error occurred during transmission? */ if ((ecc & SJA1000_ECC_DIR) == 0) cf->data[2] |= CAN_ERR_PROT_TX; diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index dc53c831ea95..eb8b0e600282 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -284,7 +284,7 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv, break; } - /* Error occured during transmission? */ + /* Error occurred during transmission? */ if (!(ecc & SJA1000_ECC_DIR)) cf->data[2] |= CAN_ERR_PROT_TX; diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 3437613f0454..143a28c666af 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -51,7 +51,7 @@ * TX has 4 queues. currently these queues are used in a round-robin * fashion for load balancing. They can also be used for QoS. for that * to work, however, QoS information needs to be exposed down to the driver - * level so that subqueues get targetted to particular transmit rings. + * level so that subqueues get targeted to particular transmit rings. * alternatively, the queues can be configured via use of the all-purpose * ioctl. * @@ -5165,7 +5165,7 @@ err_out_free_res: pci_release_regions(pdev); err_write_cacheline: - /* Try to restore it in case the error occured after we + /* Try to restore it in case the error occurred after we * set it. */ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, orig_cacheline_size); diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h index faf4746a0f3e..b361424d5f57 100644 --- a/drivers/net/cassini.h +++ b/drivers/net/cassini.h @@ -772,7 +772,7 @@ #define RX_DEBUG_INTR_WRITE_PTR_MASK 0xC0000000 /* interrupt write pointer of the interrupt queue */ -/* flow control frames are emmitted using two PAUSE thresholds: +/* flow control frames are emitted using two PAUSE thresholds: * XOFF PAUSE uses pause time value pre-programmed in the Send PAUSE MAC reg * XON PAUSE uses a pause time of 0. granularity of threshold is 64bytes. * PAUSE thresholds defined in terms of FIFO occupancy and may be translated diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c index 809047a99e96..71018a4fdf15 100644 --- a/drivers/net/chelsio/mv88e1xxx.c +++ b/drivers/net/chelsio/mv88e1xxx.c @@ -41,7 +41,7 @@ static void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval) * * PARAMS: cphy - Pointer to PHY instance data. * - * RETURN: 0 - Successfull reset. + * RETURN: 0 - Successful reset. * -1 - Timeout. */ static int mv88e1xxx_reset(struct cphy *cphy, int wait) diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c index 7dbb16d36fff..40c7b93ababc 100644 --- a/drivers/net/chelsio/pm3393.c +++ b/drivers/net/chelsio/pm3393.c @@ -293,7 +293,7 @@ static int pm3393_enable_port(struct cmac *cmac, int which) pm3393_enable(cmac, which); /* - * XXX This should be done by the PHY and preferrably not at all. + * XXX This should be done by the PHY and preferably not at all. * The PHY doesn't give us link status indication on its own so have * the link management code query it instead. */ diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index f778b15ad3fd..8754d4473042 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1662,7 +1662,7 @@ irqreturn_t t1_interrupt(int irq, void *data) * The code figures out how many entries the sk_buff will require in the * cmdQ and updates the cmdQ data structure with the state once the enqueue * has complete. Then, it doesn't access the global structure anymore, but - * uses the corresponding fields on the stack. In conjuction with a spinlock + * uses the corresponding fields on the stack. In conjunction with a spinlock * around that code, we can make the function reentrant without holding the * lock when we actually enqueue (which might be expensive, especially on * architectures with IO MMUs). diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c index 106a590f0d9a..b0cb388f5e12 100644 --- a/drivers/net/chelsio/vsc7326.c +++ b/drivers/net/chelsio/vsc7326.c @@ -566,7 +566,7 @@ static int mac_disable(struct cmac *mac, int which) for (i = 0; i <= 0x3a; ++i) vsc_write(mac->adapter, CRA(4, port, i), 0); - /* Clear sofware counters */ + /* Clear software counters */ memset(&mac->stats, 0, sizeof(struct cmac_statistics)); return 0; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 80c2feeefec5..9d267d3a6892 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -1383,7 +1383,7 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) spin_lock(&np->lock); /* Preempt protection */ switch (cmd) { /* The ioctls below should be considered obsolete but are */ - /* still present for compatability with old scripts/apps */ + /* still present for compatibility with old scripts/apps */ case SET_ETH_SPEED_10: /* 10 Mbps */ e100_set_speed(dev, 10); break; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index f9f6645b2e61..bfa2d56af1ee 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -199,7 +199,7 @@ static inline void refill_rspq(struct adapter *adapter, * need_skb_unmap - does the platform need unmapping of sk_buffs? * * Returns true if the platform needs sk_buff unmapping. The compiler - * optimizes away unecessary code if this returns true. + * optimizes away unnecessary code if this returns true. */ static inline int need_skb_unmap(void) { diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index d55db6b38e7b..c688421da9c7 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -1386,11 +1386,11 @@ struct intr_info { * @reg: the interrupt status register to process * @mask: a mask to apply to the interrupt status * @acts: table of interrupt actions - * @stats: statistics counters tracking interrupt occurences + * @stats: statistics counters tracking interrupt occurrences * * A table driven interrupt handler that applies a set of masks to an * interrupt status word and performs the corresponding actions if the - * interrupts described by the mask have occured. The actions include + * interrupts described by the mask have occurred. The actions include * optionally printing a warning or alert message, and optionally * incrementing a stat counter. The table is terminated by an entry * specifying mask 0. Returns the number of fatal interrupt conditions. @@ -2783,7 +2783,7 @@ static void init_mtus(unsigned short mtus[]) { /* * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so - * it can accomodate max size TCP/IP headers when SACK and timestamps + * it can accommodate max size TCP/IP headers when SACK and timestamps * are enabled and still have at least 8 bytes of payload. */ mtus[0] = 88; diff --git a/drivers/net/cxgb4/t4_hw.c b/drivers/net/cxgb4/t4_hw.c index b9fd8a6f2cc4..d1ec111aebd8 100644 --- a/drivers/net/cxgb4/t4_hw.c +++ b/drivers/net/cxgb4/t4_hw.c @@ -883,7 +883,7 @@ struct intr_info { * * A table driven interrupt handler that applies a set of masks to an * interrupt status word and performs the corresponding actions if the - * interrupts described by the mask have occured. The actions include + * interrupts described by the mask have occurred. The actions include * optionally emitting a warning or alert message. The table is terminated * by an entry specifying mask 0. Returns the number of fatal interrupt * conditions. diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c index 6aad64df4dcb..4661cbbd9bd9 100644 --- a/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -2738,7 +2738,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, cfg_queues(adapter); /* - * Print a short notice on the existance and configuration of the new + * Print a short notice on the existence and configuration of the new * VF network device ... */ for_each_port(adapter, pidx) { diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c index e0b3d1bc2fdf..bb65121f581c 100644 --- a/drivers/net/cxgb4vf/sge.c +++ b/drivers/net/cxgb4vf/sge.c @@ -224,8 +224,8 @@ static inline bool is_buf_mapped(const struct rx_sw_desc *sdesc) /** * need_skb_unmap - does the platform need unmapping of sk_buffs? * - * Returns true if the platfrom needs sk_buff unmapping. The compiler - * optimizes away unecessary code if this returns true. + * Returns true if the platform needs sk_buff unmapping. The compiler + * optimizes away unnecessary code if this returns true. */ static inline int need_skb_unmap(void) { @@ -267,7 +267,7 @@ static inline unsigned int fl_cap(const struct sge_fl *fl) * * Tests specified Free List to see whether the number of buffers * available to the hardware has falled below our "starvation" - * threshhold. + * threshold. */ static inline bool fl_starving(const struct sge_fl *fl) { @@ -1149,7 +1149,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(credits < ETHTXQ_STOP_THRES)) { /* * After we're done injecting the Work Request for this - * packet, we'll be below our "stop threshhold" so stop the TX + * packet, we'll be below our "stop threshold" so stop the TX * Queue now and schedule a request for an SGE Egress Queue * Update message. The queue will get started later on when * the firmware processes this Work Request and sends us an diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index baca6bfcb089..807b6bb200eb 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -94,14 +94,14 @@ MODULE_VERSION(EMAC_MODULE_VERSION); static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; /* Configuration items */ -#define EMAC_DEF_PASS_CRC (0) /* Do not pass CRC upto frames */ +#define EMAC_DEF_PASS_CRC (0) /* Do not pass CRC up to frames */ #define EMAC_DEF_QOS_EN (0) /* EMAC proprietary QoS disabled */ #define EMAC_DEF_NO_BUFF_CHAIN (0) /* No buffer chain */ #define EMAC_DEF_MACCTRL_FRAME_EN (0) /* Discard Maccontrol frames */ #define EMAC_DEF_SHORT_FRAME_EN (0) /* Discard short frames */ #define EMAC_DEF_ERROR_FRAME_EN (0) /* Discard error frames */ -#define EMAC_DEF_PROM_EN (0) /* Promiscous disabled */ -#define EMAC_DEF_PROM_CH (0) /* Promiscous channel is 0 */ +#define EMAC_DEF_PROM_EN (0) /* Promiscuous disabled */ +#define EMAC_DEF_PROM_CH (0) /* Promiscuous channel is 0 */ #define EMAC_DEF_BCAST_EN (1) /* Broadcast enabled */ #define EMAC_DEF_BCAST_CH (0) /* Broadcast channel is 0 */ #define EMAC_DEF_MCAST_EN (1) /* Multicast enabled */ @@ -1013,7 +1013,7 @@ static void emac_rx_handler(void *token, int len, int status) return; } - /* recycle on recieve error */ + /* recycle on receive error */ if (status < 0) { ndev->stats.rx_errors++; goto recycle; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index f4d0922ec65b..dd70738eb2f4 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -160,7 +160,7 @@ static int e1000_get_settings(struct net_device *netdev, &adapter->link_duplex); ecmd->speed = adapter->link_speed; - /* unfortunatly FULL_DUPLEX != DUPLEX_FULL + /* unfortunately FULL_DUPLEX != DUPLEX_FULL * and HALF_DUPLEX != DUPLEX_HALF */ if (adapter->link_duplex == FULL_DUPLEX) diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index c70b23d52284..5c9a8403668b 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1026,7 +1026,7 @@ extern void __iomem *ce4100_gbe_mdio_base_virt; #define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */ #define E1000_MDPHYA 0x0003C /* PHY address - RW */ -#define E1000_MANC2H 0x05860 /* Managment Control To Host - RW */ +#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ #define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ #define E1000_GCR 0x05B00 /* PCI-Ex Control */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index bfab14092d2c..477e066a1cf0 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -205,7 +205,7 @@ static struct pci_driver e1000_driver = { .probe = e1000_probe, .remove = __devexit_p(e1000_remove), #ifdef CONFIG_PM - /* Power Managment Hooks */ + /* Power Management Hooks */ .suspend = e1000_suspend, .resume = e1000_resume, #endif diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index a39d4a4d871c..506a0a0043b3 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -4886,7 +4886,7 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb, if (skb->protocol == htons(ETH_P_IP)) tx_flags |= E1000_TX_FLAGS_IPV4; - /* if count is 0 then mapping error has occured */ + /* if count is 0 then mapping error has occurred */ count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss); if (count) { e1000_tx_queue(adapter, tx_flags, count); diff --git a/drivers/net/enc28j60_hw.h b/drivers/net/enc28j60_hw.h index 1a0b20969f80..25b41de49f0e 100644 --- a/drivers/net/enc28j60_hw.h +++ b/drivers/net/enc28j60_hw.h @@ -303,7 +303,7 @@ /* maximum ethernet frame length */ #define MAX_FRAMELEN 1518 -/* Prefered half duplex: LEDA: Link status LEDB: Rx/Tx activity */ +/* Preferred half duplex: LEDA: Link status LEDB: Rx/Tx activity */ #define ENC28J60_LAMPS_MODE 0x3476 #endif diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index fb717be511f6..12d28e9d0cb7 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -13,7 +13,7 @@ This driver supports following cards : - ICL EtherTeam 16i - ICL EtherTeam 32 EISA - (Uses true 32 bit transfers rather than 16i compability mode) + (Uses true 32 bit transfers rather than 16i compatibility mode) Example Module usage: insmod eth16i.o io=0x2a0 mediatype=bnc diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index db0290f05bdf..a83dd312c3ac 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -542,7 +542,7 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id) /* Figure out what triggered the interrupt... * The tricky bit here is that the interrupt source bits get - * set in INT_SOURCE for an event irregardless of whether that + * set in INT_SOURCE for an event regardless of whether that * event is masked or not. Thus, in order to figure out what * triggered the interrupt, we need to remove the sources * for all events that are currently masked. This behaviour diff --git a/drivers/net/fec.h b/drivers/net/fec.h index ace318df4c8d..8b2c6d797e6d 100644 --- a/drivers/net/fec.h +++ b/drivers/net/fec.h @@ -97,11 +97,11 @@ struct bufdesc { * The following definitions courtesy of commproc.h, which where * Copyright (c) 1997 Dan Malek (dmalek@jlc.net). */ -#define BD_SC_EMPTY ((ushort)0x8000) /* Recieve is empty */ +#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */ #define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */ #define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */ #define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */ -#define BD_SC_CM ((ushort)0x0200) /* Continous mode */ +#define BD_SC_CM ((ushort)0x0200) /* Continuous mode */ #define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */ #define BD_SC_P ((ushort)0x0100) /* xmt preamble */ #define BD_SC_BR ((ushort)0x0020) /* Break received */ diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 7b92897ca66b..d5ab4dad5051 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -440,7 +440,7 @@ union ring_type { #define NV_RX3_VLAN_TAG_PRESENT (1<<16) #define NV_RX3_VLAN_TAG_MASK (0x0000FFFF) -/* Miscelaneous hardware related defines: */ +/* Miscellaneous hardware related defines: */ #define NV_PCI_REGSZ_VER1 0x270 #define NV_PCI_REGSZ_VER2 0x2d4 #define NV_PCI_REGSZ_VER3 0x604 @@ -1488,7 +1488,7 @@ static int phy_init(struct net_device *dev) } } - /* some phys clear out pause advertisment on reset, set it back */ + /* some phys clear out pause advertisement on reset, set it back */ mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg); /* restart auto negotiation, power down phy */ @@ -2535,7 +2535,7 @@ static void nv_tx_timeout(struct net_device *dev) else nv_tx_done_optimized(dev, np->tx_ring_size); - /* save current HW postion */ + /* save current HW position */ if (np->tx_change_owner) put_tx.ex = np->tx_change_owner->first_tx_desc; else @@ -4053,7 +4053,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else if (ecmd->autoneg == AUTONEG_DISABLE) { /* Note: autonegotiation disable, speed 1000 intentionally - * forbidden - noone should need that. */ + * forbidden - no one should need that. */ if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) return -EINVAL; @@ -4103,7 +4103,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) adv |= ADVERTISE_100HALF; if (ecmd->advertising & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; - if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ + if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisements but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) adv |= ADVERTISE_PAUSE_ASYM; @@ -4148,7 +4148,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) adv |= ADVERTISE_100FULL; np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE); - if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisments but disable tx pause */ + if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisements but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; np->pause_flags |= NV_PAUSEFRAME_RX_ENABLE; } @@ -4449,7 +4449,7 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam* adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); adv &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisments but disable tx pause */ + if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) /* for rx we set both advertisements but disable tx pause */ adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; if (np->pause_flags & NV_PAUSEFRAME_TX_REQ) adv |= ADVERTISE_PAUSE_ASYM; diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index ec5d595ce2e2..b2fe7edefad9 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -1043,7 +1043,7 @@ enum gfar_errata { }; /* Struct stolen almost completely (and shamelessly) from the FCC enet source - * (Ok, that's not so true anymore, but there is a family resemblence) + * (Ok, that's not so true anymore, but there is a family resemblance) * The GFAR buffer descriptors track the ring buffers. The rx_bd_base * and tx_bd_base always point to the currently available buffer. * The dirty_tx tracks the current buffer that is being sent by the diff --git a/drivers/net/hamradio/Makefile b/drivers/net/hamradio/Makefile index 9def86704a91..104096070026 100644 --- a/drivers/net/hamradio/Makefile +++ b/drivers/net/hamradio/Makefile @@ -3,7 +3,7 @@ # # # 19971130 Moved the amateur radio related network drivers from -# drivers/net/ to drivers/hamradio for easier maintainance. +# drivers/net/ to drivers/hamradio for easier maintenance. # Joerg Reuter DL1BKE # # 20000806 Rewritten to use lists instead of if-statements. diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 7d9ced0738c5..96a98d2ff151 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -30,7 +30,7 @@ * 0.1 F1OAT 07.06.98 Add timer polling routine for channel arbitration * 0.2 F6FBB 08.06.98 Added delay after FPGA programming * 0.3 F6FBB 29.07.98 Delayed PTT implementation for dupmode=2 - * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistance + * 0.4 F6FBB 30.07.98 Added TxTail, Slottime and Persistence * 0.5 F6FBB 01.08.98 Shared IRQs, /proc/net and network statistics * 0.6 F6FBB 25.08.98 Added 1200Bds format * 0.7 F6FBB 12.09.98 Added to the kernel configuration diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 8e2c4601b5f5..8e10d2f6a5ad 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -180,8 +180,8 @@ struct hp100_private { u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ u_long whatever_offset; /* Offset to bus/phys/dma address */ - int rxrcommit; /* # Rx PDLs commited to adapter */ - int txrcommit; /* # Tx PDLs commited to adapter */ + int rxrcommit; /* # Rx PDLs committed to adapter */ + int txrcommit; /* # Tx PDLs committed to adapter */ }; /* @@ -716,7 +716,7 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr, * implemented/tested only with the lassen chip anyway... */ if (lp->mode == 1) { /* busmaster */ dma_addr_t page_baddr; - /* Get physically continous memory for TX & RX PDLs */ + /* Get physically continuous memory for TX & RX PDLs */ /* Conversion to new PCI API : * Pages are always aligned and zeroed, no need to it ourself. * Doc says should be OK for EISA bus as well - Jean II */ @@ -1596,7 +1596,7 @@ drop: /* clean_txring checks if packets have been sent by the card by reading * the TX_PDL register from the performance page and comparing it to the - * number of commited packets. It then frees the skb's of the packets that + * number of committed packets. It then frees the skb's of the packets that * obviously have been sent to the network. * * Needs the PERFORMANCE page selected. @@ -1617,7 +1617,7 @@ static void hp100_clean_txring(struct net_device *dev) #ifdef HP100_DEBUG if (donecount > MAX_TX_PDL) - printk("hp100: %s: Warning: More PDLs transmitted than commited to card???\n", dev->name); + printk("hp100: %s: Warning: More PDLs transmitted than committed to card???\n", dev->name); #endif for (; 0 != donecount; donecount--) { @@ -1765,7 +1765,7 @@ drop: * Receive Function (Non-Busmaster mode) * Called when an "Receive Packet" interrupt occurs, i.e. the receive * packet counter is non-zero. - * For non-busmaster, this function does the whole work of transfering + * For non-busmaster, this function does the whole work of transferring * the packet to the host memory and then up to higher layers via skb * and netif_rx. */ @@ -1892,7 +1892,7 @@ static void hp100_rx_bm(struct net_device *dev) /* RX_PKT_CNT states how many PDLs are currently formatted and available to * the cards BM engine */ if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) { - printk("hp100: %s: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", + printk("hp100: %s: More packets received than committed? RX_PKT_CNT=0x%x, commit=0x%x\n", dev->name, hp100_inw(RX_PKT_CNT) & 0x00ff, lp->rxrcommit); return; @@ -2256,7 +2256,7 @@ static irqreturn_t hp100_interrupt(int irq, void *dev_id) if (lp->mode != 1) /* non busmaster */ hp100_rx(dev); else if (!(val & HP100_RX_PDL_FILL_COMPL)) { - /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ + /* Shouldn't happen - maybe we missed a RX_PDL_FILL Interrupt? */ hp100_rx_bm(dev); } } diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h index e6ca128a5564..b60e96fe38b4 100644 --- a/drivers/net/hp100.h +++ b/drivers/net/hp100.h @@ -109,7 +109,7 @@ #define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */ #define HP100_REG_MAC_CFG_3 0x0e /* RW: (8) Misc MAC functions */ #define HP100_REG_MAC_CFG_4 0x0f /* R: (8) Misc MAC states */ -#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts cant fit in mem */ +#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts can't fit in mem */ #define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */ #define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */ #define HP100_REG_TRAIN_REQUEST 0x14 /* RW: (16) Endnode MAC register. */ diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c index 8ead6a96abaa..5f51bf7c9dc5 100644 --- a/drivers/net/ibm_newemac/tah.c +++ b/drivers/net/ibm_newemac/tah.c @@ -60,7 +60,7 @@ void tah_reset(struct platform_device *ofdev) printk(KERN_ERR "%s: reset timeout\n", ofdev->dev.of_node->full_name); - /* 10KB TAH TX FIFO accomodates the max MTU of 9000 */ + /* 10KB TAH TX FIFO accommodates the max MTU of 9000 */ out_be32(&p->mr, TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | TAH_MR_DIG); diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 94d9969ec0bb..8ff68ae6b520 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -53,7 +53,7 @@ History: still work with 2.0.x.... Jan 28th, 2000 in Linux 2.2.13, the version.h file mysteriously didn't get - included. Added a workaround for this. Futhermore, it now + included. Added a workaround for this. Furthermore, it now not only compiles as a modules ;-) Jan 30th, 2000 newer kernels automatically probe more than one board, so the @@ -481,7 +481,7 @@ static void InitBoard(struct net_device *dev) if ((dev->flags & IFF_ALLMULTI) || netdev_mc_count(dev) > camcnt) rcrval |= RCREG_AMC; - /* promiscous mode ? */ + /* promiscuous mode ? */ if (dev->flags & IFF_PROMISC) rcrval |= RCREG_PRO; diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h index aa3ddbdee4bb..accd5efc9c8a 100644 --- a/drivers/net/ibmlana.h +++ b/drivers/net/ibmlana.h @@ -90,7 +90,7 @@ typedef struct { #define RCREG_ERR 0x8000 /* accept damaged and collided pkts */ #define RCREG_RNT 0x4000 /* accept packets that are < 64 */ #define RCREG_BRD 0x2000 /* accept broadcasts */ -#define RCREG_PRO 0x1000 /* promiscous mode */ +#define RCREG_PRO 0x1000 /* promiscuous mode */ #define RCREG_AMC 0x0800 /* accept all multicasts */ #define RCREG_LB_NONE 0x0000 /* no loopback */ #define RCREG_LB_MAC 0x0200 /* MAC loopback */ diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index 90c5e01e9235..ce8255fc3c52 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -181,7 +181,7 @@ s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add) * address and must override the actual permanent MAC address. If an * alternate MAC address is fopund it is saved in the hw struct and * prgrammed into RAR0 and the cuntion returns success, otherwise the - * fucntion returns an error. + * function returns an error. **/ s32 igb_check_alt_mac_addr(struct e1000_hw *hw) { @@ -982,7 +982,7 @@ out: } /** - * igb_get_speed_and_duplex_copper - Retreive current speed/duplex + * igb_get_speed_and_duplex_copper - Retrieve current speed/duplex * @hw: pointer to the HW structure * @speed: stores the current speed * @duplex: stores the current duplex diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c index 6694bf3e5ad9..d639706eb3f6 100644 --- a/drivers/net/igb/e1000_phy.c +++ b/drivers/net/igb/e1000_phy.c @@ -1421,7 +1421,7 @@ out: } /** - * igb_check_downshift - Checks whether a downshift in speed occured + * igb_check_downshift - Checks whether a downshift in speed occurred * @hw: pointer to the HW structure * * Success returns 0, Failure returns 1 diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 3d850af0cdda..0dfd1b93829e 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -200,7 +200,7 @@ static struct pci_driver igb_driver = { .probe = igb_probe, .remove = __devexit_p(igb_remove), #ifdef CONFIG_PM - /* Power Managment Hooks */ + /* Power Management Hooks */ .suspend = igb_suspend, .resume = igb_resume, #endif @@ -2292,7 +2292,7 @@ static void igb_init_hw_timer(struct igb_adapter *adapter) /** * Scale the NIC clock cycle by a large factor so that * relatively small clock corrections can be added or - * substracted at each clock tick. The drawbacks of a large + * subtracted at each clock tick. The drawbacks of a large * factor are a) that the clock register overflows more quickly * (not such a big deal) and b) that the increment per tick has * to fit into 24 bits. As a result we need to use a shift of @@ -3409,7 +3409,7 @@ static void igb_set_rx_mode(struct net_device *netdev) } else { /* * Write addresses to the MTA, if the attempt fails - * then we should just turn on promiscous mode so + * then we should just turn on promiscuous mode so * that we can at least receive multicast traffic */ count = igb_write_mc_addr_list(netdev); @@ -3423,7 +3423,7 @@ static void igb_set_rx_mode(struct net_device *netdev) /* * Write addresses to available RAR registers, if there is not * sufficient space to store all the addresses then enable - * unicast promiscous mode + * unicast promiscuous mode */ count = igb_write_uc_addr_list(netdev); if (count < 0) { @@ -4317,7 +4317,7 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, /* * count reflects descriptors mapped, if 0 or less then mapping error - * has occured and we need to rewind the descriptor queue + * has occurred and we need to rewind the descriptor queue */ count = igb_tx_map_adv(tx_ring, skb, first); if (!count) { @@ -5352,8 +5352,8 @@ static void igb_msg_task(struct igb_adapter *adapter) * The unicast table address is a register array of 32-bit registers. * The table is meant to be used in a way similar to how the MTA is used * however due to certain limitations in the hardware it is necessary to - * set all the hash bits to 1 and use the VMOLR ROPE bit as a promiscous - * enable bit to allow vlan tag stripping when promiscous mode is enabled + * set all the hash bits to 1 and use the VMOLR ROPE bit as a promiscuous + * enable bit to allow vlan tag stripping when promiscuous mode is enabled **/ static void igb_set_uta(struct igb_adapter *adapter) { diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index 6ccc32fd7338..1d04ca6fdaea 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -2227,7 +2227,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb, /* * count reflects descriptors mapped, if 0 then mapping error - * has occured and we need to rewind the descriptor queue + * has occurred and we need to rewind the descriptor queue */ count = igbvf_tx_map_adv(adapter, tx_ring, skb, first); diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index a5b0f0e194bb..58cd3202b48c 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -486,14 +486,14 @@ static int ipg_config_autoneg(struct net_device *dev) phyctrl = ipg_r8(PHY_CTRL); mac_ctrl_val = ipg_r32(MAC_CTRL); - /* Set flags for use in resolving auto-negotation, assuming + /* Set flags for use in resolving auto-negotiation, assuming * non-1000Mbps, half duplex, no flow control. */ fullduplex = 0; txflowcontrol = 0; rxflowcontrol = 0; - /* To accomodate a problem in 10Mbps operation, + /* To accommodate a problem in 10Mbps operation, * set a global flag if PHY running in 10Mbps mode. */ sp->tenmbpsmode = 0; @@ -846,7 +846,7 @@ static void init_tfdlist(struct net_device *dev) } /* - * Free all transmit buffers which have already been transfered + * Free all transmit buffers which have already been transferred * via DMA to the IPG. */ static void ipg_nic_txfree(struct net_device *dev) @@ -920,7 +920,7 @@ static void ipg_tx_timeout(struct net_device *dev) /* * For TxComplete interrupts, free all transmit - * buffers which have already been transfered via DMA + * buffers which have already been transferred via DMA * to the IPG. */ static void ipg_nic_txcleanup(struct net_device *dev) @@ -1141,13 +1141,13 @@ static int ipg_nic_rx_check_error(struct net_device *dev) /* Increment detailed receive error statistics. */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { - IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); + IPG_DEBUG_MSG("RX FIFO overrun occurred.\n"); sp->stats.rx_fifo_errors++; } if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { - IPG_DEBUG_MSG("RX runt occured.\n"); + IPG_DEBUG_MSG("RX runt occurred.\n"); sp->stats.rx_length_errors++; } @@ -1156,7 +1156,7 @@ static int ipg_nic_rx_check_error(struct net_device *dev) */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { - IPG_DEBUG_MSG("RX alignment error occured.\n"); + IPG_DEBUG_MSG("RX alignment error occurred.\n"); sp->stats.rx_frame_errors++; } @@ -1421,12 +1421,12 @@ static int ipg_nic_rx(struct net_device *dev) /* Increment detailed receive error statistics. */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) { - IPG_DEBUG_MSG("RX FIFO overrun occured.\n"); + IPG_DEBUG_MSG("RX FIFO overrun occurred.\n"); sp->stats.rx_fifo_errors++; } if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) { - IPG_DEBUG_MSG("RX runt occured.\n"); + IPG_DEBUG_MSG("RX runt occurred.\n"); sp->stats.rx_length_errors++; } @@ -1436,7 +1436,7 @@ static int ipg_nic_rx(struct net_device *dev) */ if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) { - IPG_DEBUG_MSG("RX alignment error occured.\n"); + IPG_DEBUG_MSG("RX alignment error occurred.\n"); sp->stats.rx_frame_errors++; } @@ -1460,7 +1460,7 @@ static int ipg_nic_rx(struct net_device *dev) } } else { - /* Adjust the new buffer length to accomodate the size + /* Adjust the new buffer length to accommodate the size * of the received frame. */ skb_put(skb, framelen); @@ -1488,7 +1488,7 @@ static int ipg_nic_rx(struct net_device *dev) } /* - * If there are more RFDs to proces and the allocated amount of RFD + * If there are more RFDs to process and the allocated amount of RFD * processing time has expired, assert Interrupt Requested to make * sure we come back to process the remaining RFDs. */ @@ -1886,7 +1886,7 @@ static netdev_tx_t ipg_nic_hard_start_xmit(struct sk_buff *skb, /* Request TxComplete interrupts at an interval defined * by the constant IPG_FRAMESBETWEENTXCOMPLETES. * Request TxComplete interrupt for every frame - * if in 10Mbps mode to accomodate problem with 10Mbps + * if in 10Mbps mode to accommodate problem with 10Mbps * processing. */ if (sp->tenmbpsmode) @@ -2098,7 +2098,7 @@ static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu) struct ipg_nic_private *sp = netdev_priv(dev); int err; - /* Function to accomodate changes to Maximum Transfer Unit + /* Function to accommodate changes to Maximum Transfer Unit * (or MTU) of IPG NIC. Cannot use default function since * the default will not allow for MTU > 1500 bytes. */ diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 92631eb6f6a3..872183f29ec4 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -76,7 +76,7 @@ static int ali_ircc_probe_53(ali_chip_t *chip, chipio_t *info); static int ali_ircc_init_43(ali_chip_t *chip, chipio_t *info); static int ali_ircc_init_53(ali_chip_t *chip, chipio_t *info); -/* These are the currently known ALi sourth-bridge chipsets, the only one difference +/* These are the currently known ALi south-bridge chipsets, the only one difference * is that M1543C doesn't support HP HDSL-3600 */ static ali_chip_t chips[] = @@ -1108,7 +1108,7 @@ static void ali_ircc_sir_change_speed(struct ali_ircc_cb *priv, __u32 speed) outb(lcr, iobase+UART_LCR); /* Set 8N1 */ outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ - /* without this, the conection will be broken after come back from FIR speed, + /* without this, the connection will be broken after come back from FIR speed, but with this, the SIR connection is harder to established */ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index f81d944fc360..174cafad2c1a 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -56,7 +56,7 @@ /* do_probe module parameter Enable this code */ /* Probe code is very useful for understanding how the hardware works */ /* Use it with various combinations of TT_LEN, RX_LEN */ -/* Strongly recomended, disable if the probe fails on your machine */ +/* Strongly recommended, disable if the probe fails on your machine */ /* and send me the output of dmesg */ #define USE_PROBE 1 #undef USE_PROBE diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h index 77fcf4459161..d92d54e839b9 100644 --- a/drivers/net/irda/donauboe.h +++ b/drivers/net/irda/donauboe.h @@ -51,7 +51,7 @@ /* The documentation for this chip is allegedly released */ /* However I have not seen it, not have I managed to contact */ -/* anyone who has. HOWEVER the chip bears a striking resemblence */ +/* anyone who has. HOWEVER the chip bears a striking resemblance */ /* to the IrDA controller in the Toshiba RISC TMPR3922 chip */ /* the documentation for this is freely available at */ /* http://www.madingley.org/james/resources/toshoboe/TMPR3922.pdf */ diff --git a/drivers/net/irda/girbil-sir.c b/drivers/net/irda/girbil-sir.c index a31b8fa8aaa9..96cdecff349d 100644 --- a/drivers/net/irda/girbil-sir.c +++ b/drivers/net/irda/girbil-sir.c @@ -38,7 +38,7 @@ static int girbil_change_speed(struct sir_dev *dev, unsigned speed); /* Control register 1 */ #define GIRBIL_TXEN 0x01 /* Enable transmitter */ #define GIRBIL_RXEN 0x02 /* Enable receiver */ -#define GIRBIL_ECAN 0x04 /* Cancel self emmited data */ +#define GIRBIL_ECAN 0x04 /* Cancel self emitted data */ #define GIRBIL_ECHO 0x08 /* Echo control characters */ /* LED Current Register (0x2) */ diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index e4ea61944c22..d9267cb98a23 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -370,7 +370,7 @@ static void speed_bulk_callback(struct urb *urb) /* urb is now available */ //urb->status = 0; -> tested above - /* New speed and xbof is now commited in hardware */ + /* New speed and xbof is now committed in hardware */ self->new_speed = -1; self->new_xbofs = -1; @@ -602,7 +602,7 @@ static void write_bulk_callback(struct urb *urb) IRDA_DEBUG(1, "%s(), Changing speed now...\n", __func__); irda_usb_change_speed_xbofs(self); } else { - /* New speed and xbof is now commited in hardware */ + /* New speed and xbof is now committed in hardware */ self->new_speed = -1; self->new_xbofs = -1; /* Done, waiting for next packet */ diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index cc821de2c966..be52bfed66a9 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -588,7 +588,7 @@ static int mcs_speed_change(struct mcs_cb *mcs) mcs_get_reg(mcs, MCS_MODE_REG, &rval); - /* MINRXPW values recomended by MosChip */ + /* MINRXPW values recommended by MosChip */ if (mcs->new_speed <= 115200) { rval &= ~MCS_FIR; @@ -799,7 +799,7 @@ static void mcs_receive_irq(struct urb *urb) ret = usb_submit_urb(urb, GFP_ATOMIC); } -/* Transmit callback funtion. */ +/* Transmit callback function. */ static void mcs_send_irq(struct urb *urb) { struct mcs_cb *mcs = urb->context; @@ -811,7 +811,7 @@ static void mcs_send_irq(struct urb *urb) netif_wake_queue(ndev); } -/* Transmit callback funtion. */ +/* Transmit callback function. */ static netdev_tx_t mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) { diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 559fe854d76d..7a963d4e6d06 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -716,7 +716,7 @@ static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info) int reg, com = 0; int pnp; - /* Read funtion enable register (FER) */ + /* Read function enable register (FER) */ outb(CFG_338_FER, cfg_base); reg = inb(cfg_base+1); diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h index 7ba7738759b9..32fa58211fad 100644 --- a/drivers/net/irda/nsc-ircc.h +++ b/drivers/net/irda/nsc-ircc.h @@ -135,7 +135,7 @@ #define LSR_TXRDY 0x20 /* Transmitter ready */ #define LSR_TXEMP 0x40 /* Transmitter empty */ -#define ASCR 0x07 /* Auxillary Status and Control Register */ +#define ASCR 0x07 /* Auxiliary Status and Control Register */ #define ASCR_RXF_TOUT 0x01 /* Rx FIFO timeout */ #define ASCR_FEND_INF 0x02 /* Frame end bytes in rx FIFO */ #define ASCR_S_EOT 0x04 /* Set end of transmission */ diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index c192c31e4c5c..001ed0a255f6 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -40,7 +40,7 @@ #define ICCR0_AME (1 << 7) /* Address match enable */ #define ICCR0_TIE (1 << 6) /* Transmit FIFO interrupt enable */ -#define ICCR0_RIE (1 << 5) /* Recieve FIFO interrupt enable */ +#define ICCR0_RIE (1 << 5) /* Receive FIFO interrupt enable */ #define ICCR0_RXE (1 << 4) /* Receive enable */ #define ICCR0_TXE (1 << 3) /* Transmit enable */ #define ICCR0_TUS (1 << 2) /* Transmit FIFO underrun select */ @@ -483,7 +483,7 @@ static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) } if (icsr0 & ICSR0_EIF) { - /* An error in FIFO occured, or there is a end of frame */ + /* An error in FIFO occurred, or there is a end of frame */ pxa_irda_fir_irq_eif(si, dev, icsr0); } diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 1c1677cfea29..8800e1fe4129 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -1582,7 +1582,7 @@ static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev) int iobase; int iir, lsr; - /* Already locked comming here in smsc_ircc_interrupt() */ + /* Already locked coming here in smsc_ircc_interrupt() */ /*spin_lock(&self->lock);*/ iobase = self->io.sir_base; diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 67c0ad42d818..fc896854e282 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -29,7 +29,7 @@ F02 Oct/28/02: Add SB device ID for 3147 and 3177. 2004-02-16: - Removed unneeded 'legacy' pci stuff. -- Make sure SIR mode is set (hw_init()) before calling mode-dependant stuff. +- Make sure SIR mode is set (hw_init()) before calling mode-dependent stuff. - On speed change from core, don't send SIR frame with new speed. Use current speed and change speeds later. - Make module-param dongle_id actually work. @@ -385,7 +385,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) self->io.dongle_id = dongle_id; /* The only value we must override it the baudrate */ - /* Maximum speeds and capabilities are dongle-dependant. */ + /* Maximum speeds and capabilities are dongle-dependent. */ switch( self->io.dongle_id ){ case 0x0d: self->qos.baud_rate.bits = diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index d66fab854bf1..a076eb125349 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -209,7 +209,7 @@ enum vlsi_pio_irintr { IRINTR_ACTEN = 0x80, /* activity interrupt enable */ IRINTR_ACTIVITY = 0x40, /* activity monitor (traffic detected) */ IRINTR_RPKTEN = 0x20, /* receive packet interrupt enable*/ - IRINTR_RPKTINT = 0x10, /* rx-packet transfered from fifo to memory finished */ + IRINTR_RPKTINT = 0x10, /* rx-packet transferred from fifo to memory finished */ IRINTR_TPKTEN = 0x08, /* transmit packet interrupt enable */ IRINTR_TPKTINT = 0x04, /* last bit of tx-packet+crc shifted to ir-pulser */ IRINTR_OE_EN = 0x02, /* UART rx fifo overrun error interrupt enable */ @@ -739,7 +739,7 @@ typedef struct vlsi_irda_dev { /* the remapped error flags we use for returning from frame * post-processing in vlsi_process_tx/rx() after it was completed * by the hardware. These functions either return the >=0 number - * of transfered bytes in case of success or the negative (-) + * of transferred bytes in case of success or the negative (-) * of the or'ed error flags. */ diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c index 41c529fac0ab..686a17aadef3 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.c +++ b/drivers/net/ixgbe/ixgbe_dcb.c @@ -36,7 +36,7 @@ /** * ixgbe_ieee_credits - This calculates the ieee traffic class * credits from the configured bandwidth percentages. Credits - * are the smallest unit programable into the underlying + * are the smallest unit programmable into the underlying * hardware. The IEEE 802.1Qaz specification do not use bandwidth * groups so this is much simplified from the CEE case. */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index fec4c724c37a..327c8614198c 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -360,7 +360,7 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) return DCB_NO_HW_CHG; /* - * Only take down the adapter if an app change occured. FCoE + * Only take down the adapter if an app change occurred. FCoE * may shuffle tx rings in this case and this can not be done * without a reset currently. */ @@ -599,7 +599,7 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, break; /* The FCoE application priority may be changed multiple - * times in quick sucession with switches that build up + * times in quick succession with switches that build up * TLVs. To avoid creating uneeded device resets this * checks the actual HW configuration and clears * BIT_APP_UPCHG if a HW configuration change is not diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index f17e4a7ee731..6f8adc7f5d7c 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -644,7 +644,7 @@ void ixgbe_unmap_and_free_tx_resource(struct ixgbe_ring *tx_ring, * @adapter: driver private struct * @index: reg idx of queue to query (0-127) * - * Helper function to determine the traffic index for a paticular + * Helper function to determine the traffic index for a particular * register index. * * Returns : a tc index for use in range 0-7, or 0-3 @@ -3556,7 +3556,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev) } else { /* * Write addresses to the MTA, if the attempt fails - * then we should just turn on promiscous mode so + * then we should just turn on promiscuous mode so * that we can at least receive multicast traffic */ hw->mac.ops.update_mc_addr_list(hw, netdev); @@ -3567,7 +3567,7 @@ void ixgbe_set_rx_mode(struct net_device *netdev) /* * Write addresses to available RAR registers, if there is not * sufficient space to store all the addresses then enable - * unicast promiscous mode + * unicast promiscuous mode */ count = ixgbe_write_uc_addr_list(netdev); if (count < 0) { @@ -4443,7 +4443,7 @@ static inline bool ixgbe_set_sriov_queues(struct ixgbe_adapter *adapter) } /* - * ixgbe_set_num_queues: Allocate queues for device, feature dependant + * ixgbe_set_num_queues: Allocate queues for device, feature dependent * @adapter: board private structure to initialize * * This is the top level queue allocation routine. The order here is very diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index f72f705f6183..df5b8aa4795d 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -1694,7 +1694,7 @@ static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) } /** - * ixgbe_tn_check_overtemp - Checks if an overtemp occured. + * ixgbe_tn_check_overtemp - Checks if an overtemp occurred. * @hw: pointer to hardware structure * * Checks if the LASI temp alarm status was triggered due to overtemp diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c index f47e93fe32be..d9323c08f5c7 100644 --- a/drivers/net/ixgbe/ixgbe_x540.c +++ b/drivers/net/ixgbe/ixgbe_x540.c @@ -573,7 +573,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) * @hw: pointer to hardware structure * @mask: Mask to specify which semaphore to release * - * Releases the SWFW semaphore throught the SW_FW_SYNC register + * Releases the SWFW semaphore through the SW_FW_SYNC register * for the specified function (CSR, PHY0, PHY1, EVM, Flash) **/ static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index 054ab05b7c6a..05fa7c85deed 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -1925,7 +1925,7 @@ static void ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter, } /* - * ixgbevf_set_num_queues: Allocate queues for device, feature dependant + * ixgbevf_set_num_queues: Allocate queues for device, feature dependent * @adapter: board private structure to initialize * * This is the top level queue allocation routine. The order here is very diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index efd44afeae83..f0d8346d0fa5 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -321,7 +321,7 @@ static void ks8842_reset_hw(struct ks8842_adapter *adapter) /* RX 2 kb high watermark */ ks8842_write16(adapter, 0, 0x1000, REG_QRFCR); - /* aggresive back off in half duplex */ + /* aggressive back off in half duplex */ ks8842_enable_bits(adapter, 32, 1 << 8, REG_SGCR1); /* enable no excessive collison drop */ diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 0fa4a9887ba2..bcd9ba68c9f2 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -141,7 +141,7 @@ static int msg_enable; * * All these calls issue SPI transactions to access the chip's registers. They * all require that the necessary lock is held to prevent accesses when the - * chip is busy transfering packet data (RX/TX FIFO accesses). + * chip is busy transferring packet data (RX/TX FIFO accesses). */ /** @@ -483,7 +483,7 @@ static void ks8851_rx_pkts(struct ks8851_net *ks) * * This form of operation would require us to hold the SPI bus' * chipselect low during the entie transaction to avoid any - * reset to the data stream comming from the chip. + * reset to the data stream coming from the chip. */ for (; rxfc != 0; rxfc--) { @@ -634,7 +634,7 @@ static void ks8851_irq_work(struct work_struct *work) /** * calc_txlen - calculate size of message to send packet - * @len: Lenght of data + * @len: Length of data * * Returns the size of the TXFIFO message needed to send * this packet. @@ -1472,7 +1472,7 @@ static int ks8851_phy_reg(int reg) * @reg: The register to read. * * This call reads data from the PHY register specified in @reg. Since the - * device does not support all the MII registers, the non-existant values + * device does not support all the MII registers, the non-existent values * are always returned as zero. * * We return zero for unsupported registers as the MII code does not check diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 2e2c69b24062..61631cace913 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -470,7 +470,7 @@ static int msg_enable; * * All these calls issue transactions to access the chip's registers. They * all require that the necessary lock is held to prevent accesses when the - * chip is busy transfering packet data (RX/TX FIFO accesses). + * chip is busy transferring packet data (RX/TX FIFO accesses). */ /** @@ -1364,7 +1364,7 @@ static int ks_phy_reg(int reg) * @reg: The register to read. * * This call reads data from the PHY register specified in @reg. Since the - * device does not support all the MII registers, the non-existant values + * device does not support all the MII registers, the non-existent values * are always returned as zero. * * We return zero for unsupported registers as the MII code does not check diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index da74db4a03d4..17b75e5f1b0a 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -35,7 +35,7 @@ Alexey Kuznetsov : use the 8390's six bit hash multicast filter. Paul Gortmaker : tweak ANK's above multicast changes a bit. Paul Gortmaker : update packet statistics for v2.1.x - Alan Cox : support arbitary stupid port mappings on the + Alan Cox : support arbitrary stupid port mappings on the 68K Macintosh. Support >16bit I/O spaces Paul Gortmaker : add kmod support for auto-loading of the 8390 module by all drivers that require it. @@ -121,7 +121,7 @@ static void __NS8390_init(struct net_device *dev, int startp); /* * SMP and the 8390 setup. * - * The 8390 isnt exactly designed to be multithreaded on RX/TX. There is + * The 8390 isn't exactly designed to be multithreaded on RX/TX. There is * a page register that controls bank and packet buffer access. We guard * this with ei_local->page_lock. Nobody should assume or set the page other * than zero when the lock is not held. Lock holders must restore page 0 diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 3698824744cb..385a95311cd2 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -27,7 +27,7 @@ Credits: Thanks to Murphy Software BV for letting me write this in their time. - Well, actually, I get payed doing this... + Well, actually, I get paid doing this... (Also: see http://www.murphy.nl for murphy, and my homepage ~ard for more information on the Professional Workstation) diff --git a/drivers/net/meth.h b/drivers/net/meth.h index a78dc1ca8c29..5b145c6bad60 100644 --- a/drivers/net/meth.h +++ b/drivers/net/meth.h @@ -144,7 +144,7 @@ typedef struct rx_packet { /* Bits 22 through 28 are used to determine IPGR2 */ #define METH_REV_SHIFT 29 /* Bits 29 through 31 are used to determine the revision */ - /* 000: Inital revision */ + /* 000: Initial revision */ /* 001: First revision, Improved TX concatenation */ @@ -193,7 +193,7 @@ typedef struct rx_packet { /* 1: A TX message had the INT request bit set, the packet has been sent. */ #define METH_INT_TX_LINK_FAIL BIT(2) /* 0: No interrupt pending, 1: PHY has reported a link failure */ #define METH_INT_MEM_ERROR BIT(3) /* 0: No interrupt pending */ - /* 1: A memory error occurred durring DMA, DMA stopped, Fatal */ + /* 1: A memory error occurred during DMA, DMA stopped, Fatal */ #define METH_INT_TX_ABORT BIT(4) /* 0: No interrupt pending, 1: The TX aborted operation, DMA stopped, FATAL */ #define METH_INT_RX_THRESHOLD BIT(5) /* 0: No interrupt pending, 1: Selected receive threshold condition Valid */ #define METH_INT_RX_UNDERFLOW BIT(6) /* 0: No interrupt pending, 1: FIFO was empty, packet could not be queued */ diff --git a/drivers/net/mlx4/en_main.c b/drivers/net/mlx4/en_main.c index 9317b61a75b8..9276b1b25586 100644 --- a/drivers/net/mlx4/en_main.c +++ b/drivers/net/mlx4/en_main.c @@ -236,7 +236,7 @@ static void *mlx4_en_add(struct mlx4_dev *dev) goto err_mr; } - /* Configure wich ports to start according to module parameters */ + /* Configure which ports to start according to module parameters */ mdev->port_cnt = 0; mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) mdev->port_cnt++; diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 4f158baa0246..77063f91c564 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -247,7 +247,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) priv->port); if (err) en_err(priv, "Failed enabling " - "promiscous mode\n"); + "promiscuous mode\n"); /* Disable port multicast filter (unconditionally) */ err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, @@ -276,7 +276,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) } /* - * Not in promiscous mode + * Not in promiscuous mode */ if (priv->flags & MLX4_EN_FLAG_PROMISC) { @@ -292,14 +292,14 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, priv->port); if (err) - en_err(priv, "Failed disabling promiscous mode\n"); + en_err(priv, "Failed disabling promiscuous mode\n"); /* Disable Multicast promisc */ if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, priv->port); if (err) - en_err(priv, "Failed disabling multicast promiscous mode\n"); + en_err(priv, "Failed disabling multicast promiscuous mode\n"); priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; } @@ -331,7 +331,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work) err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, priv->port); if (err) - en_err(priv, "Failed disabling multicast promiscous mode\n"); + en_err(priv, "Failed disabling multicast promiscuous mode\n"); priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; } diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 05998ee297c9..cfd50bc49169 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -706,7 +706,7 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget) } -/* Calculate the last offset position that accomodates a full fragment +/* Calculate the last offset position that accommodates a full fragment * (assuming fagment size = stride-align) */ static int mlx4_en_last_alloc_offset(struct mlx4_en_priv *priv, u16 stride, u16 align) { diff --git a/drivers/net/mlx4/en_selftest.c b/drivers/net/mlx4/en_selftest.c index 9c91a92da705..191a8dcd8a93 100644 --- a/drivers/net/mlx4/en_selftest.c +++ b/drivers/net/mlx4/en_selftest.c @@ -149,7 +149,7 @@ void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf) netif_carrier_off(dev); retry_tx: - /* Wait untill all tx queues are empty. + /* Wait until all tx queues are empty. * there should not be any additional incoming traffic * since we turned the carrier off */ msleep(200); diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 01feb8fd42ad..b229acf1855f 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -636,7 +636,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(!real_size)) goto tx_drop; - /* Allign descriptor to TXBB size */ + /* Align descriptor to TXBB size */ desc_size = ALIGN(real_size, TXBB_SIZE); nr_txbb = desc_size / TXBB_SIZE; if (unlikely(nr_txbb > MAX_DESC_TXBBS)) { diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index e71372aa9cc4..279521aed826 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -222,7 +222,7 @@ static int existing_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, /* the given qpn is listed as a promisc qpn * we need to add it as a duplicate to this entry - * for future refernce */ + * for future references */ list_for_each_entry(dqp, &entry->duplicates, list) { if (qpn == dqp->qpn) return 0; /* qp is already duplicated */ diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c index eca7d8596f87..8856659fb43c 100644 --- a/drivers/net/mlx4/port.c +++ b/drivers/net/mlx4/port.c @@ -172,7 +172,7 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap) } if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { - /* MAC already registered, increase refernce count */ + /* MAC already registered, increase references count */ ++table->refs[i]; goto out; } @@ -360,7 +360,7 @@ int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index) if (table->refs[i] && (vlan == (MLX4_VLAN_MASK & be32_to_cpu(table->entries[i])))) { - /* Vlan already registered, increase refernce count */ + /* Vlan already registered, increase references count */ *index = i; ++table->refs[i]; goto out; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 673dc600c891..1446de59ae53 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -3702,7 +3702,7 @@ abort: /* * This function determines the number of slices supported. - * The number slices is the minumum of the number of CPUS, + * The number slices is the minimum of the number of CPUS, * the number of MSI-X irqs supported, the number of slices * supported by the firmware */ diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index a761076b69c3..53aeea4b536e 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1009,7 +1009,7 @@ static int __devinit myri_sbus_probe(struct platform_device *op) /* Map in the MyriCOM register/localram set. */ if (mp->eeprom.cpuvers < CPUVERS_4_0) { - /* XXX Makes no sense, if control reg is non-existant this + /* XXX Makes no sense, if control reg is non-existent this * XXX driver cannot function at all... maybe pre-4.0 is * XXX only a valid version for PCI cards? Ask feldy... */ diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 2fd39630b1e5..aa2813e06d00 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -203,7 +203,7 @@ skbuff at an offset of "+2", 16-byte aligning the IP header. IIId. Synchronization Most operations are synchronized on the np->lock irq spinlock, except the -recieve and transmit paths which are synchronised using a combination of +receive and transmit paths which are synchronised using a combination of hardware descriptor ownership, disabling interrupts and NAPI poll scheduling. IVb. References @@ -726,7 +726,7 @@ static void move_int_phy(struct net_device *dev, int addr) * There are two addresses we must avoid: * - the address on the external phy that is used for transmission. * - the address that we want to access. User space can access phys - * on the mii bus with SIOCGMIIREG/SIOCSMIIREG, independant from the + * on the mii bus with SIOCGMIIREG/SIOCSMIIREG, independent from the * phy that is used for transmission. */ @@ -1982,7 +1982,7 @@ static void init_ring(struct net_device *dev) np->rx_head_desc = &np->rx_ring[0]; - /* Please be carefull before changing this loop - at least gcc-2.95.1 + /* Please be careful before changing this loop - at least gcc-2.95.1 * miscompiles it otherwise. */ /* Initialize all Rx descriptors. */ diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index d8bd73d7e296..dc1967c1f312 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -780,7 +780,7 @@ enum { /* * capabilities register, can be used to selectively enable/disable features - * for backward compability + * for backward compatibility */ #define CRB_NIC_CAPABILITIES_HOST NETXEN_NIC_REG(0x1a8) #define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index a41b2cf4d917..6667e0667a88 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -512,7 +512,7 @@ static void ns83820_vlan_rx_register(struct net_device *ndev, struct vlan_group /* Packet Receiver * * The hardware supports linked lists of receive descriptors for - * which ownership is transfered back and forth by means of an + * which ownership is transferred back and forth by means of an * ownership bit. While the hardware does support the use of a * ring for receive descriptors, we only make use of a chain in * an attempt to reduce bus traffic under heavy load scenarios. @@ -1147,7 +1147,7 @@ again: #ifdef NS83820_VLAN_ACCEL_SUPPORT if(vlan_tx_tag_present(skb)) { /* fetch the vlan tag info out of the - * ancilliary data if the vlan code + * ancillary data if the vlan code * is using hw vlan acceleration */ short tag = vlan_tx_tag_get(skb); diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h index e1e33c80fb25..bf126e76fabf 100644 --- a/drivers/net/pch_gbe/pch_gbe.h +++ b/drivers/net/pch_gbe/pch_gbe.h @@ -351,7 +351,7 @@ struct pch_gbe_functions { }; /** - * struct pch_gbe_mac_info - MAC infomation + * struct pch_gbe_mac_info - MAC information * @addr[6]: Store the MAC address * @fc: Mode of flow control * @fc_autoneg: Auto negotiation enable for flow control setting @@ -375,7 +375,7 @@ struct pch_gbe_mac_info { }; /** - * struct pch_gbe_phy_info - PHY infomation + * struct pch_gbe_phy_info - PHY information * @addr: PHY address * @id: PHY's identifier * @revision: PHY's revision @@ -393,7 +393,7 @@ struct pch_gbe_phy_info { /*! * @ingroup Gigabit Ether driver Layer * @struct pch_gbe_bus_info - * @brief Bus infomation + * @brief Bus information */ struct pch_gbe_bus_info { u8 type; @@ -404,7 +404,7 @@ struct pch_gbe_bus_info { /*! * @ingroup Gigabit Ether driver Layer * @struct pch_gbe_hw - * @brief Hardware infomation + * @brief Hardware information */ struct pch_gbe_hw { void *back; @@ -462,7 +462,7 @@ struct pch_gbe_tx_desc { /** - * struct pch_gbe_buffer - Buffer infomation + * struct pch_gbe_buffer - Buffer information * @skb: pointer to a socket buffer * @dma: DMA address * @time_stamp: time stamp @@ -477,7 +477,7 @@ struct pch_gbe_buffer { }; /** - * struct pch_gbe_tx_ring - tx ring infomation + * struct pch_gbe_tx_ring - tx ring information * @tx_lock: spinlock structs * @desc: pointer to the descriptor ring memory * @dma: physical address of the descriptor ring @@ -499,7 +499,7 @@ struct pch_gbe_tx_ring { }; /** - * struct pch_gbe_rx_ring - rx ring infomation + * struct pch_gbe_rx_ring - rx ring information * @desc: pointer to the descriptor ring memory * @dma: physical address of the descriptor ring * @size: length of descriptor ring in bytes diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c index c8c873b31a89..d2174a40d708 100644 --- a/drivers/net/pch_gbe/pch_gbe_ethtool.c +++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c @@ -21,7 +21,7 @@ #include "pch_gbe_api.h" /** - * pch_gbe_stats - Stats item infomation + * pch_gbe_stats - Stats item information */ struct pch_gbe_stats { char string[ETH_GSTRING_LEN]; diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 50986840c99c..2ef2f9cdefa6 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -1011,7 +1011,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, tmp_skb->len = skb->len; memcpy(&tmp_skb->data[ETH_HLEN + 2], &skb->data[ETH_HLEN], (skb->len - ETH_HLEN)); - /*-- Set Buffer infomation --*/ + /*-- Set Buffer information --*/ buffer_info->length = tmp_skb->len; buffer_info->dma = dma_map_single(&adapter->pdev->dev, tmp_skb->data, buffer_info->length, @@ -1540,7 +1540,7 @@ int pch_gbe_setup_tx_resources(struct pch_gbe_adapter *adapter, size = (int)sizeof(struct pch_gbe_buffer) * tx_ring->count; tx_ring->buffer_info = vzalloc(size); if (!tx_ring->buffer_info) { - pr_err("Unable to allocate memory for the buffer infomation\n"); + pr_err("Unable to allocate memory for the buffer information\n"); return -ENOMEM; } diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 1766dc4f07e1..c0f23376a462 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -214,7 +214,7 @@ static struct { { "SMC1211TX EZCard 10/100 (RealTek RTL8139)" }, /* { MPX5030, "Accton MPX5030 (RealTek RTL8139)" },*/ { "Delta Electronics 8139 10/100BaseTX" }, - { "Addtron Technolgy 8139 10/100BaseTX" }, + { "Addtron Technology 8139 10/100BaseTX" }, }; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 321b12f82645..81ac330f931d 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -950,7 +950,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) } /* Update statistics. - Suprisingly this need not be run single-threaded, but it effectively is. + Surprisingly this need not be run single-threaded, but it effectively is. The counters clear when read, so the adds must merely be atomic. */ static void update_stats(struct net_device *dev) diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index d3cb77205863..3077d72e8222 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -780,7 +780,7 @@ module_exit(exit_axnet_cs); Alexey Kuznetsov : use the 8390's six bit hash multicast filter. Paul Gortmaker : tweak ANK's above multicast changes a bit. Paul Gortmaker : update packet statistics for v2.1.x - Alan Cox : support arbitary stupid port mappings on the + Alan Cox : support arbitrary stupid port mappings on the 68K Macintosh. Support >16bit I/O spaces Paul Gortmaker : add kmod support for auto-loading of the 8390 module by all drivers that require it. @@ -842,7 +842,7 @@ static void do_set_multicast_list(struct net_device *dev); /* * SMP and the 8390 setup. * - * The 8390 isnt exactly designed to be multithreaded on RX/TX. There is + * The 8390 isn't exactly designed to be multithreaded on RX/TX. There is * a page register that controls bank and packet buffer access. We guard * this with ei_local->page_lock. Nobody should assume or set the page other * than zero when the lock is not held. Lock holders must restore page 0 diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 8a9ff5318923..108591756440 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -1264,7 +1264,7 @@ static netdev_tx_t smc_start_xmit(struct sk_buff *skb, /*====================================================================== - Handle a Tx anomolous event. Entered while in Window 2. + Handle a Tx anomalous event. Entered while in Window 2. ======================================================================*/ diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index aee3bb0358bf..768037602dff 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1651,7 +1651,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) /* * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit * starting until the packet is loaded. Strike one for reliability, lose - * one for latency - although on PCI this isnt a big loss. Older chips + * one for latency - although on PCI this isn't a big loss. Older chips * have FIFO's smaller than a packet, so you can't do this. * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn. */ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 993c52c82aeb..ff6129319b89 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -534,7 +534,7 @@ EXPORT_SYMBOL(phy_detach); /* Generic PHY support and helper functions */ /** - * genphy_config_advert - sanitize and advertise auto-negotation parameters + * genphy_config_advert - sanitize and advertise auto-negotiation parameters * @phydev: target phy_device struct * * Description: Writes MII_ADVERTISE with the appropriate values, @@ -683,7 +683,7 @@ int genphy_config_aneg(struct phy_device *phydev) return result; if (result == 0) { - /* Advertisment hasn't changed, but maybe aneg was never on to + /* Advertisement hasn't changed, but maybe aneg was never on to * begin with? Or maybe phy was isolated? */ int ctl = phy_read(phydev, MII_BMCR); diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 9f6d670748d1..4609bc0e2f56 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1448,7 +1448,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb) /* *check if we are on the last channel or - *we exceded the lenght of the data to + *we exceded the length of the data to *fragment */ if ((nfree <= 0) || (flen > len)) diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 4e6b72f57de8..2573f525f11c 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -178,7 +178,7 @@ ppp_print_buffer (const char *name, const __u8 *buf, int count) * way to fix this is to use a rwlock in the tty struct, but for now * we use a single global rwlock for all ttys in ppp line discipline. * - * FIXME: Fixed in tty_io nowdays. + * FIXME: Fixed in tty_io nowadays. */ static DEFINE_RWLOCK(disc_data_lock); diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 78c0e3c9b2b5..693aaef4e3ce 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -115,7 +115,7 @@ struct pppoe_net { * 2) Session stage (MAC and SID are known) * * Ethernet frames have a special tag for this but - * we use simplier approach based on session id + * we use simpler approach based on session id */ static inline bool stage_session(__be16 sid) { diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 5ecfa4b1e758..ffdf7349ef7a 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -632,7 +632,7 @@ static inline void gelic_card_enable_rxdmac(struct gelic_card *card) * @card: card structure * * gelic_card_disable_rxdmac terminates processing on the DMA controller by - * turing off DMA and issueing a force end + * turing off DMA and issuing a force end */ static inline void gelic_card_disable_rxdmac(struct gelic_card *card) { @@ -650,7 +650,7 @@ static inline void gelic_card_disable_rxdmac(struct gelic_card *card) * @card: card structure * * gelic_card_disable_txdmac terminates processing on the DMA controller by - * turing off DMA and issueing a force end + * turing off DMA and issuing a force end */ static inline void gelic_card_disable_txdmac(struct gelic_card *card) { diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index 32521ae5e824..fadadf9097a3 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -117,7 +117,7 @@ enum gelic_descr_rx_error { GELIC_DESCR_RXDATAERR = 0x00020000, /* IP packet format error */ GELIC_DESCR_RXCALERR = 0x00010000, /* cariier extension length * error */ - GELIC_DESCR_RXCREXERR = 0x00008000, /* carrier extention error */ + GELIC_DESCR_RXCREXERR = 0x00008000, /* carrier extension error */ GELIC_DESCR_RXMLTCST = 0x00004000, /* multicast address frame */ /* bit 13..0 reserved */ }; diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index 4a624a29393f..b5ae29d20f2e 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -814,7 +814,7 @@ static int gelic_wl_set_auth(struct net_device *netdev, * you will not decide suitable cipher from * its beacon. * You should have knowledge about the AP's - * cipher infomation in other method prior to + * cipher information in other method prior to * the association. */ if (!precise_ie()) diff --git a/drivers/net/pxa168_eth.c b/drivers/net/pxa168_eth.c index 1b63c8aef121..89f7540d90f9 100644 --- a/drivers/net/pxa168_eth.c +++ b/drivers/net/pxa168_eth.c @@ -462,7 +462,7 @@ static u32 hash_function(unsigned char *mac_addr_orig) * pep - ETHERNET . * mac_addr - MAC address. * skip - if 1, skip this address.Used in case of deleting an entry which is a - * part of chain in the hash table.We cant just delete the entry since + * part of chain in the hash table.We can't just delete the entry since * that will break the chain.We need to defragment the tables time to * time. * rd - 0 Discard packet upon match. diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index 3362a661248c..73e234366a82 100644 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -770,7 +770,7 @@ enum { FM93C56A_WDS = 0x0, FM93C56A_ERASE = 0x3, FM93C56A_ERASE_ALL = 0x0, -/* Command Extentions */ +/* Command Extensions */ FM93C56A_WEN_EXT = 0x3, FM93C56A_WRITE_ALL_EXT = 0x1, FM93C56A_WDS_EXT = 0x0, diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 49bfa5813068..5bb311945436 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -660,7 +660,7 @@ static void ql_disable_interrupts(struct ql_adapter *qdev) /* If we're running with multiple MSI-X vectors then we enable on the fly. * Otherwise, we may have multiple outstanding workers and don't want to * enable until the last one finishes. In this case, the irq_cnt gets - * incremented everytime we queue a worker and decremented everytime + * incremented every time we queue a worker and decremented every time * a worker finishes. Once it hits zero we enable the interrupt. */ u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr) @@ -3299,7 +3299,7 @@ msi: * will service it. An example would be if there are * 2 vectors (so 2 RSS rings) and 8 TX completion rings. * This would mean that vector 0 would service RSS ring 0 - * and TX competion rings 0,1,2 and 3. Vector 1 would + * and TX completion rings 0,1,2 and 3. Vector 1 would * service RSS ring 1 and TX completion rings 4,5,6 and 7. */ static void ql_set_tx_vect(struct ql_adapter *qdev) @@ -4152,7 +4152,7 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev) int i, status; u32 lbq_buf_len; - /* Wait for an oustanding reset to complete. */ + /* Wait for an outstanding reset to complete. */ if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) { int i = 3; while (i-- && !test_bit(QL_ADAPTER_UP, &qdev->flags)) { @@ -4281,7 +4281,7 @@ static void qlge_set_multicast_list(struct net_device *ndev) if (ql_set_routing_reg (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 1)) { netif_err(qdev, hw, qdev->ndev, - "Failed to set promiscous mode.\n"); + "Failed to set promiscuous mode.\n"); } else { set_bit(QL_PROMISCUOUS, &qdev->flags); } @@ -4291,7 +4291,7 @@ static void qlge_set_multicast_list(struct net_device *ndev) if (ql_set_routing_reg (qdev, RT_IDX_PROMISCUOUS_SLOT, RT_IDX_VALID, 0)) { netif_err(qdev, hw, qdev->ndev, - "Failed to clear promiscous mode.\n"); + "Failed to clear promiscuous mode.\n"); } else { clear_bit(QL_PROMISCUOUS, &qdev->flags); } diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index e3ebd90ae651..200a363c3bf5 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -535,7 +535,7 @@ static int r6040_rx(struct net_device *dev, int limit) /* RX dribble */ if (err & DSC_RX_ERR_DRI) dev->stats.rx_frame_errors++; - /* Buffer lenght exceeded */ + /* Buffer length exceeded */ if (err & DSC_RX_ERR_BUF) dev->stats.rx_length_errors++; /* Packet too long */ diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 356e74d20b80..337bdcd5abc9 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2353,7 +2353,7 @@ static int start_nic(struct s2io_nic *nic) if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { /* - * Dont see link state interrupts initally on some switches, + * Dont see link state interrupts initially on some switches, * so directly scheduling the link state task here. */ schedule_work(&nic->set_link_task); @@ -3563,7 +3563,7 @@ static void s2io_reset(struct s2io_nic *sp) } /* - * Clear spurious ECC interrupts that would have occured on + * Clear spurious ECC interrupts that would have occurred on * XFRAME II cards after reset. */ if (sp->device_type == XFRAME_II_DEVICE) { @@ -4065,7 +4065,7 @@ static int s2io_close(struct net_device *dev) * Description : * This function is the Tx entry point of the driver. S2IO NIC supports * certain protocol assist features on Tx side, namely CSO, S/G, LSO. - * NOTE: when device cant queue the pkt,just the trans_start variable will + * NOTE: when device can't queue the pkt,just the trans_start variable will * not be upadted. * Return value: * 0 on success & 1 on failure. diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 7d160306b651..2d144979f6f8 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -376,7 +376,7 @@ static const u16 fifo_selector[MAX_TX_FIFOS] = {0, 1, 3, 3, 7, 7, 7, 7}; /* Maintains Per FIFO related information. */ struct tx_fifo_config { #define MAX_AVAILABLE_TXDS 8192 - u32 fifo_len; /* specifies len of FIFO upto 8192, ie no of TxDLs */ + u32 fifo_len; /* specifies len of FIFO up to 8192, ie no of TxDLs */ /* Priority definition */ #define TX_FIFO_PRI_0 0 /*Highest */ #define TX_FIFO_PRI_1 1 diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 734fcfb52e85..d96b23769bd1 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -692,7 +692,7 @@ static int falcon_gmii_wait(struct efx_nic *efx) efx_oword_t md_stat; int count; - /* wait upto 50ms - taken max from datasheet */ + /* wait up to 50ms - taken max from datasheet */ for (count = 0; count < 5000; count++) { efx_reado(efx, &md_stat, FR_AB_MD_STAT); if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) { @@ -1221,7 +1221,7 @@ static int falcon_reset_sram(struct efx_nic *efx) return 0; } - } while (++count < 20); /* wait upto 0.4 sec */ + } while (++count < 20); /* wait up to 0.4 sec */ netif_err(efx, hw, efx->net_dev, "timed out waiting for SRAM reset\n"); return -ETIMEDOUT; diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index 5e118f0d2479..d98479030ef2 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -453,7 +453,7 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc) * * There's a race here with efx_mcdi_rpc(), because we might receive * a REBOOT event *before* the request has been copied out. In polled - * mode (during startup) this is irrelevent, because efx_mcdi_complete() + * mode (during startup) this is irrelevant, because efx_mcdi_complete() * is ignored. In event mode, this condition is just an edge-case of * receiving a REBOOT event after posting the MCDI request. Did the mc * reboot before or after the copyout? The best we can do always is diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h index b86a15f221ad..41fe06fa0600 100644 --- a/drivers/net/sfc/mcdi_pcol.h +++ b/drivers/net/sfc/mcdi_pcol.h @@ -103,7 +103,7 @@ * * If Code==CMDDONE, then the fields are further interpreted as: * - * - LEVEL==INFO Command succeded + * - LEVEL==INFO Command succeeded * - LEVEL==ERR Command failed * * 0 8 16 24 32 @@ -572,7 +572,7 @@ (4*(_numwords)) /* MC_CMD_SET_RAND_SEED: - * Set the 16byte seed for the MC psuedo-random generator + * Set the 16byte seed for the MC pseudo-random generator */ #define MC_CMD_SET_RAND_SEED 0x1a #define MC_CMD_SET_RAND_SEED_IN_LEN 16 @@ -1162,7 +1162,7 @@ #define MC_CMD_MAC_STATS_CMD_CLEAR_WIDTH 1 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_LBN 2 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_WIDTH 1 -/* Remaining PERIOD* fields only relevent when PERIODIC_CHANGE is set */ +/* Remaining PERIOD* fields only relevant when PERIODIC_CHANGE is set */ #define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_LBN 3 #define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_WIDTH 1 #define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_LBN 4 diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c index ec3f740f5465..7e3c65b0c99f 100644 --- a/drivers/net/sfc/mcdi_phy.c +++ b/drivers/net/sfc/mcdi_phy.c @@ -449,7 +449,7 @@ void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa) struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; u32 rmtadv; - /* The link partner capabilities are only relevent if the + /* The link partner capabilities are only relevant if the * link supports flow control autonegotiation */ if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) return; diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 215d5c51bfa0..9ffa9a6b55a0 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -670,7 +670,7 @@ struct efx_filter_state; * @irq_zero_count: Number of legacy IRQs seen with queue flags == 0 * @fatal_irq_level: IRQ level (bit number) used for serious errors * @mtd_list: List of MTDs attached to the NIC - * @nic_data: Hardware dependant state + * @nic_data: Hardware dependent state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, * @port_inhibited, efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 3a0cc63428ee..dd03bf619988 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -33,7 +33,7 @@ static char *sgiseeqstr = "SGI Seeq8003"; * with that in mind, I've decided to make this driver look completely like a * stupid Lance from a driver architecture perspective. Only difference is that * here our "ring buffer" looks and acts like a real Lance one does but is - * layed out like how the HPC DMA and the Seeq want it to. You'd be surprised + * laid out like how the HPC DMA and the Seeq want it to. You'd be surprised * how a stupid idea like this can pay off in performance, not to mention * making this driver 2,000 times easier to write. ;-) */ @@ -77,7 +77,7 @@ struct sgiseeq_tx_desc { }; /* - * Warning: This structure is layed out in a certain way because HPC dma + * Warning: This structure is laid out in a certain way because HPC dma * descriptors must be 8-byte aligned. So don't touch this without * some care. */ diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index e9e7a530552c..8a72a979ee71 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -1875,7 +1875,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) if (ret) goto out_unregister; - /* print device infomation */ + /* print device information */ pr_info("Base address at 0x%x, %pM, IRQ %d.\n", (u32)ndev->base_addr, ndev->dev_addr, ndev->irq); diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 3406ed870917..b436e007eea0 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -93,7 +93,7 @@ enum sis190_registers { IntrStatus = 0x20, IntrMask = 0x24, IntrControl = 0x28, - IntrTimer = 0x2c, // unused (Interupt Timer) + IntrTimer = 0x2c, // unused (Interrupt Timer) PMControl = 0x30, // unused (Power Mgmt Control/Status) rsv2 = 0x34, // reserved ROMControl = 0x38, @@ -234,7 +234,7 @@ enum _DescStatusBit { RxSizeMask = 0x0000ffff /* * The asic could apparently do vlan, TSO, jumbo (sis191 only) and - * provide two (unused with Linux) Tx queues. No publically + * provide two (unused with Linux) Tx queues. No publicly * available documentation alas. */ }; diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 84d4167eee9a..cb317cd069ff 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1180,7 +1180,7 @@ sis900_init_rx_ring(struct net_device *net_dev) * * 630E equalizer workaround rule(Cyrus Huang 08/15) * PHY register 14h(Test) - * Bit 14: 0 -- Automatically dectect (default) + * Bit 14: 0 -- Automatically detect (default) * 1 -- Manually set Equalizer filter * Bit 13: 0 -- (Default) * 1 -- Speed up convergence of equalizer setting @@ -1192,7 +1192,7 @@ sis900_init_rx_ring(struct net_device *net_dev) * Then set equalizer value, and set Bit 14 to 1, Bit 9 to 0 * Link Off:Set Bit 13 to 1, Bit 14 to 0 * Calculate Equalizer value: - * When Link is ON and Bit 14 is 0, SIS900PHY will auto-dectect proper equalizer value. + * When Link is ON and Bit 14 is 0, SIS900PHY will auto-detect proper equalizer value. * When the equalizer is stable, this value is not a fixed value. It will be within * a small range(eg. 7~9). Then we get a minimum and a maximum value(eg. min=7, max=9) * 0 <= max <= 4 --> set equalizer to max @@ -1723,7 +1723,7 @@ static int sis900_rx(struct net_device *net_dev) rx_size = data_size - CRC_SIZE; #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) - /* ``TOOLONG'' flag means jumbo packet recived. */ + /* ``TOOLONG'' flag means jumbo packet received. */ if ((rx_status & TOOLONG) && data_size <= MAX_FRAME_SIZE) rx_status &= (~ ((unsigned int)TOOLONG)); #endif diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c index 8639a0884f5c..2fc5987b41dc 100644 --- a/drivers/net/skfp/ess.c +++ b/drivers/net/skfp/ess.c @@ -241,7 +241,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm, != SMT_RDF_SUCCESS) || (sm->smt_tid != smc->ess.alloc_trans_id)) { - DB_ESS("ESS: Allocation Responce not accepted\n",0,0) ; + DB_ESS("ESS: Allocation Response not accepted\n",0,0) ; return fs; } @@ -393,7 +393,7 @@ static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhe * | T-NEG | * - - * - * T-NEG is discribed by the equation: + * T-NEG is described by the equation: * * (-) fddiMACT-NEG * T-NEG = ------------------- @@ -479,7 +479,7 @@ static void ess_send_response(struct s_smc *smc, struct smt_header *sm, void *p ; /* - * get and initialize the responce frame + * get and initialize the response frame */ if (sba_cmd == CHANGE_ALLOCATION) { if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, @@ -578,7 +578,7 @@ static void ess_send_alc_req(struct s_smc *smc) } /* - * get and initialize the responce frame + * get and initialize the response frame */ if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST, sizeof(struct smt_sba_alc_req)))) diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c index ca4e7bb6a5a8..a20ed1a98099 100644 --- a/drivers/net/skfp/fplustm.c +++ b/drivers/net/skfp/fplustm.c @@ -340,7 +340,7 @@ static void mac_counter_init(struct s_smc *smc) outpw(FM_A(FM_LCNTR),0) ; outpw(FM_A(FM_ECNTR),0) ; /* - * clear internal error counter stucture + * clear internal error counter structure */ ec = (u_long *)&smc->hw.fp.err_stats ; for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--) @@ -1262,8 +1262,8 @@ Function DOWNCALL/INTERN (SMT, fplustm.c) Para mode = 1 RX_ENABLE_ALLMULTI enable all multicasts 2 RX_DISABLE_ALLMULTI disable "enable all multicasts" - 3 RX_ENABLE_PROMISC enable promiscous - 4 RX_DISABLE_PROMISC disable promiscous + 3 RX_ENABLE_PROMISC enable promiscuous + 4 RX_DISABLE_PROMISC disable promiscuous 5 RX_ENABLE_NSA enable reception of NSA frames 6 RX_DISABLE_NSA disable reception of NSA frames diff --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/skfp/h/cmtdef.h index f2f771d8be76..5a6c6122ccb0 100644 --- a/drivers/net/skfp/h/cmtdef.h +++ b/drivers/net/skfp/h/cmtdef.h @@ -19,7 +19,7 @@ /* * implementation specific constants - * MODIIFY THE FOLLWOING THREE DEFINES + * MODIIFY THE FOLLOWING THREE DEFINES */ #define AMDPLC /* if Amd PLC chip used */ #ifdef CONC @@ -456,7 +456,7 @@ struct s_plc { u_long soft_err ; /* error counter */ u_long parity_err ; /* error counter */ u_long ebuf_err ; /* error counter */ - u_long ebuf_cont ; /* continous error counter */ + u_long ebuf_cont ; /* continuous error counter */ u_long phyinv ; /* error counter */ u_long vsym_ctr ; /* error counter */ u_long mini_ctr ; /* error counter */ diff --git a/drivers/net/skfp/h/fplustm.h b/drivers/net/skfp/h/fplustm.h index 6d738e1e2393..d43191ed938b 100644 --- a/drivers/net/skfp/h/fplustm.h +++ b/drivers/net/skfp/h/fplustm.h @@ -237,8 +237,8 @@ struct s_smt_fp { */ #define RX_ENABLE_ALLMULTI 1 /* enable all multicasts */ #define RX_DISABLE_ALLMULTI 2 /* disable "enable all multicasts" */ -#define RX_ENABLE_PROMISC 3 /* enable promiscous */ -#define RX_DISABLE_PROMISC 4 /* disable promiscous */ +#define RX_ENABLE_PROMISC 3 /* enable promiscuous */ +#define RX_DISABLE_PROMISC 4 /* disable promiscuous */ #define RX_ENABLE_NSA 5 /* enable reception of NSA frames */ #define RX_DISABLE_NSA 6 /* disable reception of NSA frames */ diff --git a/drivers/net/skfp/h/smc.h b/drivers/net/skfp/h/smc.h index 026a83b9f743..c774a95902f5 100644 --- a/drivers/net/skfp/h/smc.h +++ b/drivers/net/skfp/h/smc.h @@ -388,7 +388,7 @@ struct smt_config { u_long rmt_t_poll ; /* RMT : claim/beacon poller */ u_long rmt_dup_mac_behavior ; /* Flag for the beavior of SMT if * a Duplicate MAC Address was detected. - * FALSE: SMT will leave finaly the ring + * FALSE: SMT will leave finally the ring * TRUE: SMT will reinstert into the ring */ u_long mac_d_max ; /* MAC : D_Max timer value */ diff --git a/drivers/net/skfp/h/smt.h b/drivers/net/skfp/h/smt.h index 2976757a36fb..2030f9cbb24b 100644 --- a/drivers/net/skfp/h/smt.h +++ b/drivers/net/skfp/h/smt.h @@ -793,7 +793,7 @@ struct smt_rdf { } ; /* - * SBA Request Allocation Responce Frame + * SBA Request Allocation Response Frame */ struct smt_sba_alc_res { struct smt_header smt ; /* generic header */ diff --git a/drivers/net/skfp/h/supern_2.h b/drivers/net/skfp/h/supern_2.h index 5ba0b8306753..0b73690280f6 100644 --- a/drivers/net/skfp/h/supern_2.h +++ b/drivers/net/skfp/h/supern_2.h @@ -14,7 +14,7 @@ /* defines for AMD Supernet II chip set - the chips are refered to as + the chips are referred to as FPLUS Formac Plus PLC Physical Layer @@ -386,7 +386,7 @@ struct tx_queue { #define FM_MDISRCV (4<<8) /* disable receive function */ #define FM_MRES0 (5<<8) /* reserve */ #define FM_MLIMPROM (6<<8) /* limited-promiscuous mode */ -#define FM_MPROMISCOUS (7<<8) /* address detection : promiscous */ +#define FM_MPROMISCOUS (7<<8) /* address detection : promiscuous */ #define FM_SELSA 0x0800 /* select-short-address bit */ diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c index af5a755e269d..e26398b5a7dc 100644 --- a/drivers/net/skfp/hwmtm.c +++ b/drivers/net/skfp/hwmtm.c @@ -691,7 +691,7 @@ static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue) * interrupt service routine, handles the interrupt requests * generated by the FDDI adapter. * - * NOTE: The operating system dependent module must garantee that the + * NOTE: The operating system dependent module must guarantee that the * interrupts of the adapter are disabled when it calls fddi_isr. * * About the USE_BREAK_ISR mechanismn: diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c index 112d35b1bf0e..88d02d0a42c4 100644 --- a/drivers/net/skfp/pcmplc.c +++ b/drivers/net/skfp/pcmplc.c @@ -1680,7 +1680,7 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd) * Prevent counter from being wrapped after * hanging years in that interrupt. */ - plc->ebuf_cont++ ; /* Ebuf continous error */ + plc->ebuf_cont++ ; /* Ebuf continuous error */ } #ifdef SUPERNET_3 @@ -1717,8 +1717,8 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd) } #endif /* SUPERNET_3 */ } else { - /* Reset the continous error variable */ - plc->ebuf_cont = 0 ; /* reset Ebuf continous error */ + /* Reset the continuous error variable */ + plc->ebuf_cont = 0 ; /* reset Ebuf continuous error */ } if (cmd & PL_PHYINV) { /* physical layer invalid signal */ plc->phyinv++ ; diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index 1e1bd0c201c8..08d94329c12f 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -219,7 +219,7 @@ void smt_emulate_token_ct(struct s_smc *smc, int mac_index) /* * Only when ring is up we will have a token count. The - * flag is unfortunatly a single instance value. This + * flag is unfortunately a single instance value. This * doesn't matter now, because we currently have only * one MAC instance. */ diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 507addcaffa3..51c0214ac25c 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -1038,7 +1038,7 @@ enum { PHY_ST_PRE_SUP = 1<<6, /* Bit 6: Preamble Suppression */ PHY_ST_AN_OVER = 1<<5, /* Bit 5: Auto-Negotiation Over */ - PHY_ST_REM_FLT = 1<<4, /* Bit 4: Remote Fault Condition Occured */ + PHY_ST_REM_FLT = 1<<4, /* Bit 4: Remote Fault Condition Occurred */ PHY_ST_AN_CAP = 1<<3, /* Bit 3: Auto-Negotiation Capability */ PHY_ST_LSYNC = 1<<2, /* Bit 2: Link Synchronized */ PHY_ST_JAB_DET = 1<<1, /* Bit 1: Jabber Detected */ @@ -1721,8 +1721,8 @@ enum { GM_GPSR_LINK_UP = 1<<12, /* Bit 12: Link Up Status */ GM_GPSR_PAUSE = 1<<11, /* Bit 11: Pause State */ GM_GPSR_TX_ACTIVE = 1<<10, /* Bit 10: Tx in Progress */ - GM_GPSR_EXC_COL = 1<<9, /* Bit 9: Excessive Collisions Occured */ - GM_GPSR_LAT_COL = 1<<8, /* Bit 8: Late Collisions Occured */ + GM_GPSR_EXC_COL = 1<<9, /* Bit 9: Excessive Collisions Occurred */ + GM_GPSR_LAT_COL = 1<<8, /* Bit 8: Late Collisions Occurred */ GM_GPSR_PHY_ST_CH = 1<<5, /* Bit 5: PHY Status Change */ GM_GPSR_GIG_SPEED = 1<<4, /* Bit 4: Gigabit Speed (1 = 1000 Mbps) */ @@ -2227,7 +2227,7 @@ enum { XM_ST_BC = 1<<7, /* Bit 7: Broadcast packet */ XM_ST_MC = 1<<6, /* Bit 6: Multicast packet */ XM_ST_UC = 1<<5, /* Bit 5: Unicast packet */ - XM_ST_TX_UR = 1<<4, /* Bit 4: FIFO Underrun occured */ + XM_ST_TX_UR = 1<<4, /* Bit 4: FIFO Underrun occurred */ XM_ST_CS_ERR = 1<<3, /* Bit 3: Carrier Sense Error */ XM_ST_LAT_COL = 1<<2, /* Bit 2: Late Collision Error */ XM_ST_MUL_COL = 1<<1, /* Bit 1: Multiple Collisions */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2a91868788f7..ff8d262dc276 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -932,7 +932,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); - /* On chips without ram buffer, pause is controled by MAC level */ + /* On chips without ram buffer, pause is controlled by MAC level */ if (!(hw->flags & SKY2_HW_RAM_BUFFER)) { /* Pause threshold is scaled by 8 in bytes */ if (hw->chip_id == CHIP_ID_YUKON_FE_P && @@ -3255,7 +3255,7 @@ static void sky2_reset(struct sky2_hw *hw) /* Take device down (offline). * Equivalent to doing dev_stop() but this does not - * inform upper layers of the transistion. + * inform upper layers of the transition. */ static void sky2_detach(struct net_device *dev) { diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 6861b0e8db9a..0c6d10c5f053 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1194,7 +1194,7 @@ enum { PHY_ST_PRE_SUP = 1<<6, /* Bit 6: Preamble Suppression */ PHY_ST_AN_OVER = 1<<5, /* Bit 5: Auto-Negotiation Over */ - PHY_ST_REM_FLT = 1<<4, /* Bit 4: Remote Fault Condition Occured */ + PHY_ST_REM_FLT = 1<<4, /* Bit 4: Remote Fault Condition Occurred */ PHY_ST_AN_CAP = 1<<3, /* Bit 3: Auto-Negotiation Capability */ PHY_ST_LSYNC = 1<<2, /* Bit 2: Link Synchronized */ PHY_ST_JAB_DET = 1<<1, /* Bit 1: Jabber Detected */ @@ -1725,8 +1725,8 @@ enum { GM_GPSR_LINK_UP = 1<<12, /* Bit 12: Link Up Status */ GM_GPSR_PAUSE = 1<<11, /* Bit 11: Pause State */ GM_GPSR_TX_ACTIVE = 1<<10, /* Bit 10: Tx in Progress */ - GM_GPSR_EXC_COL = 1<<9, /* Bit 9: Excessive Collisions Occured */ - GM_GPSR_LAT_COL = 1<<8, /* Bit 8: Late Collisions Occured */ + GM_GPSR_EXC_COL = 1<<9, /* Bit 9: Excessive Collisions Occurred */ + GM_GPSR_LAT_COL = 1<<8, /* Bit 8: Late Collisions Occurred */ GM_GPSR_PHY_ST_CH = 1<<5, /* Bit 5: PHY Status Change */ GM_GPSR_GIG_SPEED = 1<<4, /* Bit 4: Gigabit Speed (1 = 1000 Mbps) */ diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 68d48ab6eacf..5f53fbbf67be 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -921,7 +921,7 @@ static const char * chip_ids[ 16 ] = { * Hack Alert: Some setups just can't write 8 or 16 bits reliably when not * aligned to a 32 bit boundary. I tell you that does exist! * Fortunately the affected register accesses can be easily worked around - * since we can write zeroes to the preceeding 16 bits without adverse + * since we can write zeroes to the preceding 16 bits without adverse * effects and use a 32-bit access. * * Enforce it on any 32-bit capable setup for now. diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 1566259c1f27..c498b720b532 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1669,7 +1669,7 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) } if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - SMSC_TRACE(DRV, "Error occured during eeprom operation"); + SMSC_TRACE(DRV, "Error occurred during eeprom operation"); return -EINVAL; } diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index b09ee1c319e8..4c92ad8be765 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -364,7 +364,7 @@ static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op) } if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - smsc_info(HW, "Error occured during eeprom operation"); + smsc_info(HW, "Error occurred during eeprom operation"); return -EINVAL; } diff --git a/drivers/net/stmmac/norm_desc.c b/drivers/net/stmmac/norm_desc.c index cd0cc76f7a1c..029c2a2cf524 100644 --- a/drivers/net/stmmac/norm_desc.c +++ b/drivers/net/stmmac/norm_desc.c @@ -67,7 +67,7 @@ static int ndesc_get_tx_len(struct dma_desc *p) /* This function verifies if each incoming frame has some errors * and, if required, updates the multicast statistics. - * In case of success, it returns csum_none becasue the device + * In case of success, it returns csum_none because the device * is not able to compute the csum in HW. */ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, struct dma_desc *p) diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h index 8db88945b889..4943e975a731 100644 --- a/drivers/net/sunbmac.h +++ b/drivers/net/sunbmac.h @@ -185,7 +185,7 @@ #define BIGMAC_RXCFG_ENABLE 0x00000001 /* Enable the receiver */ #define BIGMAC_RXCFG_FIFO 0x0000000e /* Default rx fthresh... */ #define BIGMAC_RXCFG_PSTRIP 0x00000020 /* Pad byte strip enable */ -#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */ +#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscuous mode */ #define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */ #define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */ #define BIGMAC_RXCFG_ME 0x00000200 /* Receive packets addressed to me */ diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index c1a344829b54..d3be735c4719 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -1150,7 +1150,7 @@ static void gem_pcs_reinit_adv(struct gem *gp) val &= ~(PCS_CFG_ENABLE | PCS_CFG_TO); writel(val, gp->regs + PCS_CFG); - /* Advertise all capabilities except assymetric + /* Advertise all capabilities except asymmetric * pause. */ val = readl(gp->regs + PCS_MIIADV); diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index 756b5bf3aa89..64f278360d89 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -223,7 +223,7 @@ /* BigMac receive config register. */ #define BIGMAC_RXCFG_ENABLE 0x00000001 /* Enable the receiver */ #define BIGMAC_RXCFG_PSTRIP 0x00000020 /* Pad byte strip enable */ -#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */ +#define BIGMAC_RXCFG_PMISC 0x00000040 /* Enable promiscuous mode */ #define BIGMAC_RXCFG_DERR 0x00000080 /* Disable error checking */ #define BIGMAC_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */ #define BIGMAC_RXCFG_REJME 0x00000200 /* Reject packets addressed to me */ diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index b6eec8cea209..7ca51cebcddd 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -119,13 +119,13 @@ struct tc35815_regs { /* * Bit assignments */ -/* DMA_Ctl bit asign ------------------------------------------------------- */ +/* DMA_Ctl bit assign ------------------------------------------------------- */ #define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */ #define DMA_RxAlign_1 0x00400000 #define DMA_RxAlign_2 0x00800000 #define DMA_RxAlign_3 0x00c00000 #define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */ -#define DMA_IntMask 0x00040000 /* 1:Interupt mask */ +#define DMA_IntMask 0x00040000 /* 1:Interrupt mask */ #define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ #define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ #define DMA_RxBigE 0x00008000 /* 1:Receive Big Endian */ @@ -134,11 +134,11 @@ struct tc35815_regs { #define DMA_PowrMgmnt 0x00001000 /* 1:Power Management */ #define DMA_DmBurst_Mask 0x000001fc /* DMA Burst size */ -/* RxFragSize bit asign ---------------------------------------------------- */ +/* RxFragSize bit assign ---------------------------------------------------- */ #define RxFrag_EnPack 0x00008000 /* 1:Enable Packing */ #define RxFrag_MinFragMask 0x00000ffc /* Minimum Fragment */ -/* MAC_Ctl bit asign ------------------------------------------------------- */ +/* MAC_Ctl bit assign ------------------------------------------------------- */ #define MAC_Link10 0x00008000 /* 1:Link Status 10Mbits */ #define MAC_EnMissRoll 0x00002000 /* 1:Enable Missed Roll */ #define MAC_MissRoll 0x00000400 /* 1:Missed Roll */ @@ -152,7 +152,7 @@ struct tc35815_regs { #define MAC_HaltImm 0x00000002 /* 1:Halt Immediate */ #define MAC_HaltReq 0x00000001 /* 1:Halt request */ -/* PROM_Ctl bit asign ------------------------------------------------------ */ +/* PROM_Ctl bit assign ------------------------------------------------------ */ #define PROM_Busy 0x00008000 /* 1:Busy (Start Operation) */ #define PROM_Read 0x00004000 /*10:Read operation */ #define PROM_Write 0x00002000 /*01:Write operation */ @@ -162,7 +162,7 @@ struct tc35815_regs { #define PROM_Addr_Ena 0x00000030 /*11xxxx:PROM Write enable */ /*00xxxx: disable */ -/* CAM_Ctl bit asign ------------------------------------------------------- */ +/* CAM_Ctl bit assign ------------------------------------------------------- */ #define CAM_CompEn 0x00000010 /* 1:CAM Compare Enable */ #define CAM_NegCAM 0x00000008 /* 1:Reject packets CAM recognizes,*/ /* accept other */ @@ -170,7 +170,7 @@ struct tc35815_regs { #define CAM_GroupAcc 0x00000002 /* 1:Multicast assept */ #define CAM_StationAcc 0x00000001 /* 1:unicast accept */ -/* CAM_Ena bit asign ------------------------------------------------------- */ +/* CAM_Ena bit assign ------------------------------------------------------- */ #define CAM_ENTRY_MAX 21 /* CAM Data entry max count */ #define CAM_Ena_Mask ((1<ifr_data, sizeof(data)); if (error) { - pr_err("cant copy from user\n"); + pr_err("can't copy from user\n"); RET(-EFAULT); } DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); @@ -999,7 +999,7 @@ static inline void bdx_rxdb_free_elem(struct rxdb *db, int n) * * RxD fifo is smaller than RxF fifo by design. Upon high load, RxD will be * filled and packets will be dropped by nic without getting into host or - * cousing interrupt. Anyway, in that condition, host has no chance to proccess + * cousing interrupt. Anyway, in that condition, host has no chance to process * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles */ @@ -1200,8 +1200,8 @@ static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd) RET(); } -/* bdx_rx_receive - recieves full packets from RXD fifo and pass them to OS - * NOTE: a special treatment is given to non-continous descriptors +/* bdx_rx_receive - receives full packets from RXD fifo and pass them to OS + * NOTE: a special treatment is given to non-continuous descriptors * that start near the end, wraps around and continue at the beginning. a second * part is copied right after the first, and then descriptor is interpreted as * normal. fifo has an extra space to allow such operations @@ -1584,9 +1584,9 @@ err_mem: } /* - * bdx_tx_space - calculates avalable space in TX fifo + * bdx_tx_space - calculates available space in TX fifo * @priv - NIC private structure - * Returns avaliable space in TX fifo in bytes + * Returns available space in TX fifo in bytes */ static inline int bdx_tx_space(struct bdx_priv *priv) { diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h index b6ba8601e2b5..c5642fefc9e7 100644 --- a/drivers/net/tehuti.h +++ b/drivers/net/tehuti.h @@ -502,7 +502,7 @@ struct txd_desc { #define GMAC_RX_FILTER_ACRC 0x0010 /* accept crc error */ #define GMAC_RX_FILTER_AM 0x0008 /* accept multicast */ #define GMAC_RX_FILTER_AB 0x0004 /* accept broadcast */ -#define GMAC_RX_FILTER_PRM 0x0001 /* [0:1] promiscous mode */ +#define GMAC_RX_FILTER_PRM 0x0001 /* [0:1] promiscuous mode */ #define MAX_FRAME_AB_VAL 0x3fff /* 13:0 */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 73c942d85f07..b8c5f35577e4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9712,7 +9712,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, eeprom->len += b_count; } - /* read bytes upto the last 4 byte boundary */ + /* read bytes up to the last 4 byte boundary */ pd = &data[eeprom->len]; for (i = 0; i < (len - (len & 3)); i += 4) { ret = tg3_nvram_read_be32(tp, offset + i, &val); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 73884b69b749..5e96706ad108 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2130,7 +2130,7 @@ #define MII_TG3_DSP_EXP96 0x0f96 #define MII_TG3_DSP_EXP97 0x0f97 -#define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */ +#define MII_TG3_AUX_CTRL 0x18 /* auxiliary control register */ #define MII_TG3_AUXCTL_PCTL_100TX_LPWR 0x0010 #define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE 0x0020 @@ -2146,7 +2146,7 @@ #define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400 #define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000 -#define MII_TG3_AUX_STAT 0x19 /* auxilliary status register */ +#define MII_TG3_AUX_STAT 0x19 /* auxiliary status register */ #define MII_TG3_AUX_STAT_LPASS 0x0004 #define MII_TG3_AUX_STAT_SPDMASK 0x0700 #define MII_TG3_AUX_STAT_10HALF 0x0100 diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 10800f16a231..8a3b191b195b 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -208,7 +208,7 @@ static void print_rx_state(struct net_device *dev) * passing/getting the next value from the nic. As with all requests * on this nic it has to be done in two stages, a) tell the nic which * memory address you want to access and b) pass/get the value from the nic. - * With the EEProm, you have to wait before and inbetween access a) and b). + * With the EEProm, you have to wait before and between access a) and b). * As this is only read at initialization time and the wait period is very * small we shouldn't have to worry about scheduling issues. */ diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 785ad1a2157b..2bedc0ace812 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -73,7 +73,7 @@ static void madgemc_setint(struct net_device *dev, int val); static irqreturn_t madgemc_interrupt(int irq, void *dev_id); /* - * These work around paging, however they don't guarentee you're on the + * These work around paging, however they don't guarantee you're on the * right page. */ #define SIFREADB(reg) (inb(dev->base_addr + ((reg<0x8)?reg:reg-0x8))) @@ -387,7 +387,7 @@ getout: * both with their own disadvantages... * * 1) Read in the SIFSTS register from the TMS controller. This - * is guarenteed to be accurate, however, there's a fairly + * is guaranteed to be accurate, however, there's a fairly * large performance penalty for doing so: the Madge chips * must request the register from the Eagle, the Eagle must * read them from its internal bus, and then take the route @@ -454,7 +454,7 @@ static irqreturn_t madgemc_interrupt(int irq, void *dev_id) } /* - * Set the card to the prefered ring speed. + * Set the card to the preferred ring speed. * * Unlike newer cards, the MC16/32 have their speed selection * circuit connected to the Madge ASICs and not to the TMS380 diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 63db5a6762ae..d9044aba7afa 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -393,7 +393,7 @@ static int smctr_alloc_shared_memory(struct net_device *dev) tp->rx_bdb_end[NON_MAC_QUEUE] = (BDBlock *)smctr_malloc(dev, 0); /* Allocate MAC transmit buffers. - * MAC Tx Buffers doen't have to be on an ODD Boundry. + * MAC Tx Buffers doen't have to be on an ODD Boundary. */ tp->tx_buff_head[MAC_QUEUE] = (__u16 *)smctr_malloc(dev, tp->tx_buff_size[MAC_QUEUE]); @@ -415,7 +415,7 @@ static int smctr_alloc_shared_memory(struct net_device *dev) /* Allocate Non-MAC transmit buffers. * ?? For maximum Netware performance, put Tx Buffers on - * ODD Boundry and then restore malloc to Even Boundrys. + * ODD Boundary and then restore malloc to Even Boundrys. */ smctr_malloc(dev, 1L); tp->tx_buff_head[NON_MAC_QUEUE] @@ -1311,7 +1311,7 @@ static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev) mem_used += sizeof(BDBlock) * tp->num_rx_bdbs[MAC_QUEUE]; /* Allocate MAC transmit buffers. - * MAC transmit buffers don't have to be on an ODD Boundry. + * MAC transmit buffers don't have to be on an ODD Boundary. */ mem_used += tp->tx_buff_size[MAC_QUEUE]; @@ -1325,7 +1325,7 @@ static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev) /* Allocate Non-MAC transmit buffers. * For maximum Netware performance, put Tx Buffers on - * ODD Boundry,and then restore malloc to Even Boundrys. + * ODD Boundary,and then restore malloc to Even Boundrys. */ mem_used += 1L; mem_used += tp->tx_buff_size[NON_MAC_QUEUE]; @@ -3069,8 +3069,8 @@ static int smctr_load_node_addr(struct net_device *dev) * disabled.!? * * NOTE 2: If the monitor_state is MS_BEACON_TEST_STATE and the receive_mask - * has any multi-cast or promiscous bits set, the receive_mask needs to - * be changed to clear the multi-cast or promiscous mode bits, the lobe_test + * has any multi-cast or promiscuous bits set, the receive_mask needs to + * be changed to clear the multi-cast or promiscuous mode bits, the lobe_test * run, and then the receive mask set back to its original value if the test * is successful. */ diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index 60b30ee38dcb..e5a617c586c2 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -442,7 +442,7 @@ typedef struct { #define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer * of each received frame; FrameSize * of RPLs must contain internal - * BUFFER_SIZE bits for promiscous mode. + * BUFFER_SIZE bits for promiscuous mode. */ #define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex diff --git a/drivers/net/tsi108_eth.h b/drivers/net/tsi108_eth.h index 5a77ae6c5f36..5fee7d78dc6d 100644 --- a/drivers/net/tsi108_eth.h +++ b/drivers/net/tsi108_eth.h @@ -305,9 +305,9 @@ #define TSI108_TX_CRC (1 << 5) /* Generate CRC for this packet */ #define TSI108_TX_INT (1 << 14) /* Generate an IRQ after frag. processed */ #define TSI108_TX_RETRY (0xf << 16) /* 4 bit field indicating num. of retries */ -#define TSI108_TX_COL (1 << 20) /* Set if a collision occured */ -#define TSI108_TX_LCOL (1 << 24) /* Set if a late collision occured */ -#define TSI108_TX_UNDER (1 << 25) /* Set if a FIFO underrun occured */ +#define TSI108_TX_COL (1 << 20) /* Set if a collision occurred */ +#define TSI108_TX_LCOL (1 << 24) /* Set if a late collision occurred */ +#define TSI108_TX_UNDER (1 << 25) /* Set if a FIFO underrun occurred */ #define TSI108_TX_RLIM (1 << 26) /* Set if the retry limit was reached */ #define TSI108_TX_OK (1 << 30) /* Set if the frame TX was successful */ #define TSI108_TX_OWN (1 << 31) /* Set if the device owns the descriptor */ @@ -332,7 +332,7 @@ typedef struct { #define TSI108_RX_RUNT (1 << 4)/* Packet is less than minimum size */ #define TSI108_RX_HASH (1 << 7)/* Hash table match */ #define TSI108_RX_BAD (1 << 8) /* Bad frame */ -#define TSI108_RX_OVER (1 << 9) /* FIFO overrun occured */ +#define TSI108_RX_OVER (1 << 9) /* FIFO overrun occurred */ #define TSI108_RX_TRUNC (1 << 11) /* Packet truncated due to excess length */ #define TSI108_RX_CRC (1 << 12) /* Packet had a CRC error */ #define TSI108_RX_INT (1 << 13) /* Generate an IRQ after frag. processed */ diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 4dbd493b996b..efaa1d69b720 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -79,7 +79,7 @@ every usable DECchip board, I pinched Donald's 'next_module' field to link my modules together. - Upto 15 EISA cards can be supported under this driver, limited primarily + Up to 15 EISA cards can be supported under this driver, limited primarily by the available IRQ lines. I have checked different configurations of multiple depca, EtherWORKS 3 cards and de4x5 cards and have not found a problem yet (provided you have at least depca.c v0.38) ... @@ -517,7 +517,7 @@ struct mii_phy { u_int mci; /* 21142 MII Connector Interrupt info */ }; -#define DE4X5_MAX_PHY 8 /* Allow upto 8 attached PHY devices per board */ +#define DE4X5_MAX_PHY 8 /* Allow up to 8 attached PHY devices per board */ struct sia_phy { u_char mc; /* Media Code */ @@ -1436,7 +1436,7 @@ de4x5_sw_reset(struct net_device *dev) /* Poll for setup frame completion (adapter interrupts are disabled now) */ - for (j=0, i=0;(i<500) && (j==0);i++) { /* Upto 500ms delay */ + for (j=0, i=0;(i<500) && (j==0);i++) { /* Up to 500ms delay */ mdelay(1); if ((s32)le32_to_cpu(lp->tx_ring[lp->tx_new].status) >= 0) j=1; } diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 7064e035757a..fb07f48910ae 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -1224,7 +1224,7 @@ static void dmfe_timer(unsigned long data) /* If chip reports that link is failed it could be because external - PHY link status pin is not conected correctly to chip + PHY link status pin is not connected correctly to chip To be sure ask PHY too. */ diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 3031ed9c4a1a..296486bf0956 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -115,7 +115,7 @@ static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp) 0x02, /* phy reset sequence length */ 0x01, 0x00, /* phy reset sequence */ 0x00, 0x78, /* media capabilities */ - 0x00, 0xe0, /* nway advertisment */ + 0x00, 0xe0, /* nway advertisement */ 0x00, 0x05, /* fdx bit map */ 0x00, 0x06 /* ttm bit map */ }; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 7fa5ec2de942..82653cb07857 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -846,7 +846,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) if(typhoon_num_free_tx(txRing) < (numDesc + 2)) { netif_stop_queue(dev); - /* A Tx complete IRQ could have gotten inbetween, making + /* A Tx complete IRQ could have gotten between, making * the ring free again. Only need to recheck here, since * Tx is serialized. */ diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index 055b87ab4f07..d12fcad145e9 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -80,7 +80,7 @@ struct ucc_geth { frames) received that were between 128 (Including FCS length==4) and 255 octets */ u32 txok; /* Total number of octets residing in frames - that where involved in successfull + that where involved in successful transmission */ u16 txcf; /* Total number of PAUSE control frames transmitted by this MAC */ @@ -759,7 +759,7 @@ struct ucc_geth_hardware_statistics { frames) received that were between 128 (Including FCS length==4) and 255 octets */ u32 txok; /* Total number of octets residing in frames - that where involved in successfull + that where involved in successful transmission */ u16 txcf; /* Total number of PAUSE control frames transmitted by this MAC */ diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 5f3b97668e63..555284761313 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -190,7 +190,7 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb) /* * EEM packet header format: - * b0..14: EEM type dependant (Data or Command) + * b0..14: EEM type dependent (Data or Command) * b15: bmType */ header = get_unaligned_le16(skb->data); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 7dc84971f26f..ad0298f9b5f9 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -1221,7 +1221,7 @@ static void kaweth_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (!kaweth) { - dev_warn(&intf->dev, "unregistering non-existant device\n"); + dev_warn(&intf->dev, "unregistering non-existent device\n"); return; } netdev = kaweth->net; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 5e7f069eab53..eb5d75df5d5d 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1861,7 +1861,7 @@ static void rhine_restart_tx(struct net_device *dev) { u32 intr_status; /* - * If new errors occured, we need to sort them out before doing Tx. + * If new errors occurred, we need to sort them out before doing Tx. * In that case the ISR will be back here RSN anyway. */ intr_status = get_intr_status(dev); @@ -1887,7 +1887,7 @@ static void rhine_restart_tx(struct net_device *dev) { /* This should never happen */ if (debug > 1) printk(KERN_WARNING "%s: rhine_restart_tx() " - "Another error occured %8.8x.\n", + "Another error occurred %8.8x.\n", dev->name, intr_status); } diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 0d6fec6b7d93..4fe051753842 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -292,7 +292,7 @@ VELOCITY_PARAM(DMA_length, "DMA length"); /* IP_byte_align[] is used for IP header DWORD byte aligned 0: indicate the IP header won't be DWORD byte aligned.(Default) . 1: indicate the IP header will be DWORD byte aligned. - In some enviroment, the IP header should be DWORD byte aligned, + In some environment, the IP header should be DWORD byte aligned, or the packet will be droped when we receive it. (eg: IPVS) */ VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned"); @@ -1994,7 +1994,7 @@ static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb) * @dev: network device * * Replace the current skb that is scheduled for Rx processing by a - * shorter, immediatly allocated skb, if the received packet is small + * shorter, immediately allocated skb, if the received packet is small * enough. This function returns a negative value if the received * packet is too big or if memory is exhausted. */ diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index cc14b4a75048..0d47c3a05307 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -892,7 +892,7 @@ vmxnet3_prepare_tso(struct sk_buff *skb, * Transmits a pkt thru a given tq * Returns: * NETDEV_TX_OK: descriptors are setup successfully - * NETDEV_TX_OK: error occured, the pkt is dropped + * NETDEV_TX_OK: error occurred, the pkt is dropped * NETDEV_TX_BUSY: tx ring is full, queue is stopped * * Side-effects: @@ -2685,7 +2685,7 @@ vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac) * Enable MSIx vectors. * Returns : * 0 on successful enabling of required vectors, - * VMXNET3_LINUX_MIN_MSIX_VECT when only minumum number of vectors required + * VMXNET3_LINUX_MIN_MSIX_VECT when only minimum number of vectors required * could be enabled. * number of vectors which can be enabled otherwise (this number is smaller * than VMXNET3_LINUX_MIN_MSIX_VECT) diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index e74e4b42592d..401bebf59502 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c @@ -187,7 +187,7 @@ vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action, VXGE_HW_DEF_DEVICE_POLL_MILLIS); /* The __vxge_hw_device_register_poll can udelay for a significant - * amount of time, blocking other proccess from the CPU. If it delays + * amount of time, blocking other process from the CPU. If it delays * for ~5secs, a NMI error can occur. A way around this is to give up * the processor via msleep, but this is not allowed is under lock. * So, only allow it to sleep for ~4secs if open. Otherwise, delay for diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 395423aeec00..aff68c1118d4 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -2282,7 +2282,7 @@ vxge_alarm_msix_handle(int irq, void *dev_id) VXGE_HW_VPATH_MSIX_ACTIVE) + VXGE_ALARM_MSIX_ID; for (i = 0; i < vdev->no_of_vpath; i++) { - /* Reduce the chance of loosing alarm interrupts by masking + /* Reduce the chance of losing alarm interrupts by masking * the vector. A pending bit will be set if an alarm is * generated and on unmask the interrupt will be fired. */ @@ -2788,7 +2788,7 @@ static int vxge_open(struct net_device *dev) } /* Enable vpath to sniff all unicast/multicast traffic that not - * addressed to them. We allow promiscous mode for PF only + * addressed to them. We allow promiscuous mode for PF only */ val64 = 0; @@ -2890,7 +2890,7 @@ out0: return ret; } -/* Loop throught the mac address list and delete all the entries */ +/* Loop through the mac address list and delete all the entries */ static void vxge_free_mac_add_list(struct vxge_vpath *vpath) { @@ -2957,7 +2957,7 @@ static int do_vxge_close(struct net_device *dev, int do_io) val64); } - /* Remove the function 0 from promiscous mode */ + /* Remove the function 0 from promiscuous mode */ vxge_hw_mgmt_reg_write(vdev->devh, vxge_hw_mgmt_reg_type_mrpcim, 0, diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 8674f331311c..2638b8d97b8f 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -1111,7 +1111,7 @@ void vxge_hw_channel_dtr_free(struct __vxge_hw_channel *channel, void *dtrh) * vxge_hw_channel_dtr_count * @channel: Channel handle. Obtained via vxge_hw_channel_open(). * - * Retreive number of DTRs available. This function can not be called + * Retrieve number of DTRs available. This function can not be called * from data path. ring_initial_replenishi() is the only user. */ int vxge_hw_channel_dtr_count(struct __vxge_hw_channel *channel) @@ -2060,7 +2060,7 @@ enum vxge_hw_status vxge_hw_vpath_promisc_enable( vpath = vp->vpath; - /* Enable promiscous mode for function 0 only */ + /* Enable promiscuous mode for function 0 only */ if (!(vpath->hldev->access_rights & VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) return VXGE_HW_OK; diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 9d9dfda4c7ab..6c2fc0b72af5 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h @@ -681,7 +681,7 @@ struct vxge_hw_xmac_aggr_stats { * @rx_red_discard: Count of received frames that are discarded because of RED * (Random Early Discard). * @rx_xgmii_ctrl_err_cnt: Maintains a count of unexpected or misplaced control - * characters occuring between times of normal data transmission + * characters occurring between times of normal data transmission * (i.e. not included in RX_XGMII_DATA_ERR_CNT). This counter is * incremented when either - * 1) The Reconciliation Sublayer (RS) is expecting one control diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 10bafd59f9c3..6fb6f8e667d0 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -329,7 +329,7 @@ static int startmicrocode(struct cosa_data *cosa, int address); static int readmem(struct cosa_data *cosa, char __user *data, int addr, int len); static int cosa_reset_and_read_id(struct cosa_data *cosa, char *id); -/* Auxilliary functions */ +/* Auxiliary functions */ static int get_wait_data(struct cosa_data *cosa); static int put_wait_data(struct cosa_data *cosa, int data); static int puthexnumber(struct cosa_data *cosa, int number); diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 4578e5b4b411..acb9ea830628 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -56,7 +56,7 @@ * IV. Notes * The current error (XDU, RFO) recovery code is untested. * So far, RDO takes his RX channel down and the right sequence to enable it - * again is still a mistery. If RDO happens, plan a reboot. More details + * again is still a mystery. If RDO happens, plan a reboot. More details * in the code (NB: as this happens, TX still works). * Don't mess the cables during operation, especially on DTE ports. I don't * suggest it for DCE either but at least one can get some messages instead @@ -1065,7 +1065,7 @@ static int dscc4_open(struct net_device *dev) /* * Due to various bugs, there is no way to reliably reset a - * specific port (manufacturer's dependant special PCI #RST wiring + * specific port (manufacturer's dependent special PCI #RST wiring * apart: it affects all ports). Thus the device goes in the best * silent mode possible at dscc4_close() time and simply claims to * be up if it's opened again. It still isn't possible to change @@ -1230,9 +1230,9 @@ static inline int dscc4_check_clock_ability(int port) * scaling. Of course some rounding may take place. * - no high speed mode (40Mb/s). May be trivial to do but I don't have an * appropriate external clocking device for testing. - * - no time-slot/clock mode 5: shameless lazyness. + * - no time-slot/clock mode 5: shameless laziness. * - * The clock signals wiring can be (is ?) manufacturer dependant. Good luck. + * The clock signals wiring can be (is ?) manufacturer dependent. Good luck. * * BIG FAT WARNING: if the device isn't provided enough clocking signal, it * won't pass the init sequence. For example, straight back-to-back DTE without diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 48edc5f4dac8..e817583e6ec5 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -15,7 +15,7 @@ * The hardware does the bus handling to avoid the need for delays between * touching control registers. * - * Port B isnt wired (why - beats me) + * Port B isn't wired (why - beats me) * * Generic HDLC port Copyright (C) 2008 Krzysztof Halasa */ diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 6c571e198835..f1e1643dc3eb 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -178,7 +178,7 @@ * * The resulting average clock frequency (assuming 33.333 MHz oscillator) is: * freq = 66.666 MHz / (A + (B + 1) / (C + 1)) - * minumum freq = 66.666 MHz / (A + 1) + * minimum freq = 66.666 MHz / (A + 1) * maximum freq = 66.666 MHz / A * * Example: A = 2, B = 2, C = 7, CLOCK_CR register = 2 << 22 | 2 << 12 | 7 @@ -230,7 +230,7 @@ #define PKT_PIPE_MODE_WRITE 0x57 /* HDLC packet status values - desc->status */ -#define ERR_SHUTDOWN 1 /* stop or shutdown occurrance */ +#define ERR_SHUTDOWN 1 /* stop or shutdown occurrence */ #define ERR_HDLC_ALIGN 2 /* HDLC alignment error */ #define ERR_HDLC_FCS 3 /* HDLC Frame Check Sum error */ #define ERR_RXFREE_Q_EMPTY 4 /* RX-free queue became empty while receiving diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 70feb84df670..b7f2358d23be 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -24,7 +24,7 @@ * * Linux driver notes: * Linux uses the device struct lmc_private to pass private information - * arround. + * around. * * The initialization portion of this driver (the lmc_reset() and the * lmc_dec_reset() functions, as well as the led controls and the diff --git a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h index 65d01978e784..01ad45218d19 100644 --- a/drivers/net/wan/lmc/lmc_var.h +++ b/drivers/net/wan/lmc/lmc_var.h @@ -180,7 +180,7 @@ struct lmc___ctl { /* - * Carefull, look at the data sheet, there's more to this + * Careful, look at the data sheet, there's more to this * structure than meets the eye. It should probably be: * * struct tulip_desc_t { @@ -380,7 +380,7 @@ struct lmc___softc { /* CSR6 settings */ #define OPERATION_MODE 0x00000200 /* Full Duplex */ #define PROMISC_MODE 0x00000040 /* Promiscuous Mode */ -#define RECIEVE_ALL 0x40000000 /* Recieve All */ +#define RECIEVE_ALL 0x40000000 /* Receive All */ #define PASS_BAD_FRAMES 0x00000008 /* Pass Bad Frames */ /* Dec control registers CSR6 as well */ @@ -398,7 +398,7 @@ struct lmc___softc { #define TULIP_CMD_RECEIVEALL 0x40000000L /* (RW) Receivel all frames? */ #define TULIP_CMD_MUSTBEONE 0x02000000L /* (RW) Must Be One (21140) */ #define TULIP_CMD_TXTHRSHLDCTL 0x00400000L /* (RW) Transmit Threshold Mode (21140) */ -#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Foward (21140) */ +#define TULIP_CMD_STOREFWD 0x00200000L /* (RW) Store and Forward (21140) */ #define TULIP_CMD_NOHEARTBEAT 0x00080000L /* (RW) No Heartbeat (21140) */ #define TULIP_CMD_PORTSELECT 0x00040000L /* (RW) Post Select (100Mb) (21140) */ #define TULIP_CMD_FULLDUPLEX 0x00000200L /* (RW) Full Duplex Mode */ diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 93956861ea21..0806232e0f8f 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -542,7 +542,7 @@ static void z8530_dma_tx(struct z8530_channel *chan) z8530_tx(chan); return; } - /* This shouldnt occur in DMA mode */ + /* This shouldn't occur in DMA mode */ printk(KERN_ERR "DMA tx - bogus event!\n"); z8530_tx(chan); } @@ -1219,7 +1219,7 @@ static const char *z8530_type_name[]={ * @io: the port value in question * * Describe a Z8530 in a standard format. We must pass the I/O as - * the port offset isnt predictable. The main reason for this function + * the port offset isn't predictable. The main reason for this function * is to try and get a common format of report. */ @@ -1588,7 +1588,7 @@ static void z8530_rx_done(struct z8530_channel *c) unsigned long flags; /* - * Complete this DMA. Neccessary to find the length + * Complete this DMA. Necessary to find the length */ flags=claim_dma_lock(); @@ -1657,7 +1657,7 @@ static void z8530_rx_done(struct z8530_channel *c) * fifo length for this. Thus we want to flip to the new * buffer and then mess around copying and allocating * things. For the current case it doesn't matter but - * if you build a system where the sync irq isnt blocked + * if you build a system where the sync irq isn't blocked * by the kernel IRQ disable then you need only block the * sync IRQ for the RT_LOCK area. * diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c index 12b84ed0e38a..727d728649b7 100644 --- a/drivers/net/wimax/i2400m/control.c +++ b/drivers/net/wimax/i2400m/control.c @@ -378,7 +378,7 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m, * the device's state as sometimes we need to do a link-renew (the BS * wants us to renew a DHCP lease, for example). * - * In fact, doc says that everytime we get a link-up, we should do a + * In fact, doc says that every time we get a link-up, we should do a * DHCP negotiation... */ static @@ -675,7 +675,7 @@ void i2400m_msg_to_dev_cancel_wait(struct i2400m *i2400m, int code) * - the ack message wasn't formatted correctly * * The returned skb has been allocated with wimax_msg_to_user_alloc(), - * it contains the reponse in a netlink attribute and is ready to be + * it contains the response in a netlink attribute and is ready to be * passed up to user space with wimax_msg_to_user_send(). To access * the payload and its length, use wimax_msg_{data,len}() on the skb. * diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 65bc334ed57b..47cae7150bc1 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -654,7 +654,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) if (result == -EUCLEAN) { /* * We come here because the reset during operational mode - * wasn't successully done and need to proceed to a bus + * wasn't successfully done and need to proceed to a bus * reset. For the dev_reset_handle() to be able to handle * the reset event later properly, we restore boot_mode back * to the state before previous reset. ie: just like we are @@ -755,7 +755,7 @@ EXPORT_SYMBOL_GPL(i2400m_error_recovery); * Alloc the command and ack buffers for boot mode * * Get the buffers needed to deal with boot mode messages. These - * buffers need to be allocated before the sdio recieve irq is setup. + * buffers need to be allocated before the sdio receive irq is setup. */ static int i2400m_bm_buf_alloc(struct i2400m *i2400m) diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 8b55a5b14152..85dadd5bf4be 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -54,7 +54,7 @@ * endpoint and read from it in the notification endpoint. In SDIO we * talk to it via the write address and read from the read address. * - * Upon entrance to boot mode, the device sends (preceeded with a few + * Upon entrance to boot mode, the device sends (preceded with a few * zero length packets (ZLPs) on the notification endpoint in USB) a * reboot barker (4 le32 words with the same value). We ack it by * sending the same barker to the device. The device acks with a @@ -1589,7 +1589,7 @@ int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags) i2400m->fw_name = fw_name; ret = i2400m_fw_bootstrap(i2400m, fw, flags); release_firmware(fw); - if (ret >= 0) /* firmware loaded succesfully */ + if (ret >= 0) /* firmware loaded successfully */ break; i2400m->fw_name = NULL; } diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h index eb80243e22df..6650fde99e1d 100644 --- a/drivers/net/wimax/i2400m/i2400m-usb.h +++ b/drivers/net/wimax/i2400m/i2400m-usb.h @@ -105,14 +105,14 @@ static inline void edc_init(struct edc *edc) * * @edc: pointer to error density counter. * @max_err: maximum number of errors we can accept over the timeframe - * @timeframe: lenght of the timeframe (in jiffies). + * @timeframe: length of the timeframe (in jiffies). * * Returns: !0 1 if maximum acceptable errors per timeframe has been * exceeded. 0 otherwise. * * This is way to determine if the number of acceptable errors per time * period has been exceeded. It is not accurate as there are cases in which - * this scheme will not work, for example if there are periodic occurences + * this scheme will not work, for example if there are periodic occurrences * of errors that straddle updates to the start time. This scheme is * sufficient for our usage. * @@ -204,7 +204,7 @@ enum { * usb_autopm_get/put_interface() barriers when executing * commands. See doc in i2400mu_suspend() for more information. * - * @rx_size_auto_shrink: if true, the rx_size is shrinked + * @rx_size_auto_shrink: if true, the rx_size is shrunk * automatically based on the average size of the received * transactions. This allows the receive code to allocate smaller * chunks of memory and thus reduce pressure on the memory diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index 030cbfd31704..5eacc653a94d 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -526,7 +526,7 @@ struct i2400m_barker_db; * * @barker: barker type that the device uses; this is initialized by * i2400m_is_boot_barker() the first time it is called. Then it - * won't change during the life cycle of the device and everytime + * won't change during the life cycle of the device and every time * a boot barker is received, it is just verified for it being the * same. * @@ -928,7 +928,7 @@ extern void i2400m_report_tlv_rf_switches_status( struct i2400m *, const struct i2400m_tlv_rf_switches_status *); /* - * Helpers for firmware backwards compability + * Helpers for firmware backwards compatibility * * As we aim to support at least the firmware version that was * released with the previous kernel/driver release, some code will be diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c index 94742e1eafe0..2edd8fe1c1f3 100644 --- a/drivers/net/wimax/i2400m/netdev.c +++ b/drivers/net/wimax/i2400m/netdev.c @@ -166,7 +166,7 @@ void i2400m_wake_tx_work(struct work_struct *ws) d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb); result = -EINVAL; if (skb == NULL) { - dev_err(dev, "WAKE&TX: skb dissapeared!\n"); + dev_err(dev, "WAKE&TX: skb disappeared!\n"); goto out_put; } /* If we have, somehow, lost the connection after this was diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c index 9e02b90b0080..b0dba35a8ad2 100644 --- a/drivers/net/wimax/i2400m/op-rfkill.c +++ b/drivers/net/wimax/i2400m/op-rfkill.c @@ -27,7 +27,7 @@ * - report changes in the HW RF Kill switch [with * wimax_rfkill_{sw,hw}_report(), which happens when we detect those * indications coming through hardware reports]. We also do it on - * initialization to let the stack know the intial HW state. + * initialization to let the stack know the initial HW state. * * - implement indications from the stack to change the SW RF Kill * switch (coming from sysfs, the wimax stack or user space). @@ -73,7 +73,7 @@ int i2400m_radio_is(struct i2400m *i2400m, enum wimax_rf_state state) * Generic Netlink will call this function when a message is sent from * userspace to change the software RF-Kill switch status. * - * This function will set the device's sofware RF-Kill switch state to + * This function will set the device's software RF-Kill switch state to * match what is requested. * * NOTE: the i2400m has a strict state machine; we can only set the diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c index 844133b44af0..2f94a872101f 100644 --- a/drivers/net/wimax/i2400m/rx.c +++ b/drivers/net/wimax/i2400m/rx.c @@ -349,7 +349,7 @@ error_no_waiter: * * For reports: We can't clone the original skb where the data is * because we need to send this up via netlink; netlink has to add - * headers and we can't overwrite what's preceeding the payload...as + * headers and we can't overwrite what's preceding the payload...as * it is another message. So we just dup them. */ static @@ -425,7 +425,7 @@ error_check: * * As in i2400m_rx_ctl(), we can't clone the original skb where the * data is because we need to send this up via netlink; netlink has to - * add headers and we can't overwrite what's preceeding the + * add headers and we can't overwrite what's preceding the * payload...as it is another message. So we just dup them. */ static diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c index 3f819efc06b5..4b30ed11d785 100644 --- a/drivers/net/wimax/i2400m/tx.c +++ b/drivers/net/wimax/i2400m/tx.c @@ -149,7 +149,7 @@ * (with a moved message header to make sure it is size-aligned to * 16), TAIL room that was unusable (and thus is marked with a message * header that says 'skip this') and at the head of the buffer, an - * imcomplete message with a couple of payloads. + * incomplete message with a couple of payloads. * * N ___________________________________________________ * | | @@ -819,7 +819,7 @@ EXPORT_SYMBOL_GPL(i2400m_tx); * the FIF that is ready for transmission. * * It sets the state in @i2400m to indicate the bus-specific driver is - * transfering that message (i2400m->tx_msg_size). + * transferring that message (i2400m->tx_msg_size). * * Once the transfer is completed, call i2400m_tx_msg_sent(). * diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c index b58ec56b86f8..1fda46c55eb3 100644 --- a/drivers/net/wimax/i2400m/usb-fw.c +++ b/drivers/net/wimax/i2400m/usb-fw.c @@ -169,7 +169,7 @@ retry: * * Command can be a raw command, which requires no preparation (and * which might not even be following the command format). Checks that - * the right amount of data was transfered. + * the right amount of data was transferred. * * To satisfy USB requirements (no onstack, vmalloc or in data segment * buffers), we copy the command to i2400m->bm_cmd_buf and send it from diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c index a26483a812a5..e3257681e360 100644 --- a/drivers/net/wimax/i2400m/usb-rx.c +++ b/drivers/net/wimax/i2400m/usb-rx.c @@ -58,7 +58,7 @@ * a zillion reads; by serializing, we are throttling. * * - RX data processing can get heavy enough so that it is not - * appropiate for doing it in the USB callback; thus we run it in a + * appropriate for doing it in the USB callback; thus we run it in a * process context. * * We provide a read buffer of an arbitrary size (short of a page); if diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c index c65b9979f87e..ac357acfb3e9 100644 --- a/drivers/net/wimax/i2400m/usb-tx.c +++ b/drivers/net/wimax/i2400m/usb-tx.c @@ -168,7 +168,7 @@ retry: /* * Get the next TX message in the TX FIFO and send it to the device * - * Note we exit the loop if i2400mu_tx() fails; that funtion only + * Note we exit the loop if i2400mu_tx() fails; that function only * fails on hard error (failing to tx a buffer not being one of them, * see its doc). * diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 57a79b0475f6..4e5c7a11f04a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1884,7 +1884,7 @@ static int airo_open(struct net_device *dev) { /* Make sure the card is configured. * Wireless Extensions may postpone config changes until the card * is open (to pipeline changes and speed-up card setup). If - * those changes are not yet commited, do it now - Jean II */ + * those changes are not yet committed, do it now - Jean II */ if (test_bit(FLAG_COMMIT, &ai->flags)) { disable_MAC(ai, 1); writeConfigRid(ai, 1); @@ -1992,7 +1992,7 @@ static int mpi_send_packet (struct net_device *dev) /* * Magic, the cards firmware needs a length count (2 bytes) in the host buffer * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen - * is immediatly after it. ------------------------------------------------ + * is immediately after it. ------------------------------------------------ * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| * ------------------------------------------------ */ @@ -2006,7 +2006,7 @@ static int mpi_send_packet (struct net_device *dev) sizeof(wifictlhdr8023) + 2 ; /* - * Firmware automaticly puts 802 header on so + * Firmware automatically puts 802 header on so * we don't need to account for it in the length */ if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && @@ -2531,7 +2531,7 @@ static int mpi_init_descriptors (struct airo_info *ai) /* * We are setting up three things here: * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid. - * 2) Map PCI memory for issueing commands. + * 2) Map PCI memory for issuing commands. * 3) Allocate memory (shared) to send and receive ethernet frames. */ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) @@ -3947,7 +3947,7 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { if ( max_tries == -1 ) { airo_print_err(ai->dev->name, - "Max tries exceeded when issueing command"); + "Max tries exceeded when issuing command"); if (IN4500(ai, COMMAND) & COMMAND_BUSY) OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); return ERROR; @@ -4173,7 +4173,7 @@ done: } /* Note, that we are using BAP1 which is also used by transmit, so - * make sure this isnt called when a transmit is happening */ + * make sure this isn't called when a transmit is happening */ static int PC4500_writerid(struct airo_info *ai, u16 rid, const void *pBuf, int len, int lock) { @@ -4776,7 +4776,7 @@ static int proc_stats_rid_open( struct inode *inode, if (!statsLabels[i]) continue; if (j+strlen(statsLabels[i])+16>4096) { airo_print_warn(apriv->dev->name, - "Potentially disasterous buffer overflow averted!"); + "Potentially disastrous buffer overflow averted!"); break; } j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c index b761fec0d721..ccc2edaaeda0 100644 --- a/drivers/net/wireless/ath/ar9170/main.c +++ b/drivers/net/wireless/ath/ar9170/main.c @@ -974,7 +974,7 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb) if (ar->rx_failover_missing <= 0) { /* * nested ar9170_rx call! - * termination is guranteed, even when the + * termination is guaranteed, even when the * combined frame also have a element with * a bad tag. */ diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c index 0dbfcf79ac96..aa8d06ba1ee4 100644 --- a/drivers/net/wireless/ath/ar9170/phy.c +++ b/drivers/net/wireless/ath/ar9170/phy.c @@ -424,7 +424,7 @@ static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz) /* * initialize some phy regs from eeprom values in modal_header[] - * acc. to band and bandwith + * acc. to band and bandwidth */ static int ar9170_init_phy_from_eeprom(struct ar9170 *ar, bool is_2ghz, bool is_40mhz) diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index d0a664039c87..034015397093 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -27,7 +27,7 @@ #define ATH5K_ANI_RSSI_THR_HIGH 40 #define ATH5K_ANI_RSSI_THR_LOW 7 -/* maximum availabe levels */ +/* maximum available levels */ #define ATH5K_ANI_MAX_FIRSTEP_LVL 2 #define ATH5K_ANI_MAX_NOISE_IMM_LVL 1 diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 4d7f21ee111c..349a5963931b 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1953,7 +1953,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) #define FUDGE AR5K_TUNE_SW_BEACON_RESP + 3 /* We use FUDGE to make sure the next TBTT is ahead of the current TU. - * Since we later substract AR5K_TUNE_SW_BEACON_RESP (10) in the timer + * Since we later subtract AR5K_TUNE_SW_BEACON_RESP (10) in the timer * configuration we need to make sure it is bigger than that. */ if (bc_tsf == -1) { @@ -1971,7 +1971,7 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) intval |= AR5K_BEACON_RESET_TSF; } else if (bc_tsf > hw_tsf) { /* - * beacon received, SW merge happend but HW TSF not yet updated. + * beacon received, SW merge happened but HW TSF not yet updated. * not possible to reconfigure timers yet, but next time we * receive a beacon with the same BSSID, the hardware will * automatically update the TSF and then we need to reconfigure @@ -2651,7 +2651,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan, synchronize_irq(sc->irq); stop_tasklets(sc); - /* Save ani mode and disable ANI durring + /* Save ani mode and disable ANI during * reset. If we don't we might get false * PHY error interrupts. */ ani_mode = ah->ah_sc->ani_state.ani_mode; diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 16b44ff7dd3e..a8fcc94269f7 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -51,7 +51,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* * Validate input * - Zero retries don't make sense. - * - A zero rate will put the HW into a mode where it continously sends + * - A zero rate will put the HW into a mode where it continuously sends * noise on the channel, so it is important to avoid this. */ if (unlikely(tx_tries0 == 0)) { @@ -190,7 +190,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* * Validate input * - Zero retries don't make sense. - * - A zero rate will put the HW into a mode where it continously sends + * - A zero rate will put the HW into a mode where it continuously sends * noise on the channel, so it is important to avoid this. */ if (unlikely(tx_tries0 == 0)) { @@ -300,7 +300,7 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* * Rates can be 0 as long as the retry count is 0 too. * A zero rate and nonzero retry count will put the HW into a mode where - * it continously sends noise on the channel, so it is important to + * it continuously sends noise on the channel, so it is important to * avoid this. */ if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || @@ -342,7 +342,7 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, \***********************/ /* - * Proccess the tx status descriptor on 5210/5211 + * Process the tx status descriptor on 5210/5211 */ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, struct ath5k_tx_status *ts) @@ -394,7 +394,7 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, } /* - * Proccess a tx status descriptor on 5212 + * Process a tx status descriptor on 5212 */ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, struct ath5k_tx_status *ts) @@ -519,7 +519,7 @@ int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, } /* - * Proccess the rx status descriptor on 5210/5211 + * Process the rx status descriptor on 5210/5211 */ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, struct ath5k_rx_status *rs) @@ -602,7 +602,7 @@ static int ath5k_hw_proc_5210_rx_status(struct ath5k_hw *ah, } /* - * Proccess the rx status descriptor on 5212 + * Process the rx status descriptor on 5212 */ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah, struct ath5k_desc *desc, diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index b6561f785c6e..efb672cb31e4 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -1080,7 +1080,7 @@ ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) * * To recreate the curves we read here the points and interpolate * later. Note that in most cases only 2 (higher and lower) curves are - * used (like RF5112) but vendors have the oportunity to include all + * used (like RF5112) but vendors have the opportunity to include all * 4 curves on eeprom. The final curve (higher power) has an extra * point for better accuracy like RF5112. */ @@ -1302,7 +1302,7 @@ ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) /* * Pd gain 0 is not the last pd gain * so it only has 2 pd points. - * Continue wih pd gain 1. + * Continue with pd gain 1. */ pcinfo->pwr_i[1] = (val >> 10) & 0x1f; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index 66598a0d1df0..3c44689a700b 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -57,7 +57,7 @@ static void ath5k_pci_read_cachesize(struct ath_common *common, int *csz) *csz = (int)u8tmp; /* - * This check was put in to avoid "unplesant" consequences if + * This check was put in to avoid "unpleasant" consequences if * the bootrom has not fully initialized all PCI devices. * Sometimes the cache line size register is not set */ diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index a702817daf72..d9b3f828455a 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -472,7 +472,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) } /* - * The AR5210 uses promiscous mode to detect radar activity + * The AR5210 uses promiscuous mode to detect radar activity */ if (ah->ah_version == AR5K_AR5210 && (filter & AR5K_RX_FILTER_RADARERR)) { @@ -706,8 +706,8 @@ ath5k_check_timer_win(int a, int b, int window, int intval) * The need for this function arises from the fact that we have 4 separate * HW timer registers (TIMER0 - TIMER3), which are closely related to the * next beacon target time (NBTT), and that the HW updates these timers - * seperately based on the current TSF value. The hardware increments each - * timer by the beacon interval, when the local TSF coverted to TU is equal + * separately based on the current TSF value. The hardware increments each + * timer by the beacon interval, when the local TSF converted to TU is equal * to the value stored in the timer. * * The reception of a beacon with the same BSSID can update the local HW TSF diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 62ce2f4e8605..55441913344d 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -335,11 +335,11 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, * http://madwifi-project.org/ticket/1659 * with various measurements and diagrams * - * TODO: Deal with power drops due to probes by setting an apropriate + * TODO: Deal with power drops due to probes by setting an appropriate * tx power on the probe packets ! Make this part of the calibration process. */ -/* Initialize ah_gain durring attach */ +/* Initialize ah_gain during attach */ int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah) { /* Initialize the gain optimization values */ @@ -1049,7 +1049,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, \**************************/ /* - * Convertion needed for RF5110 + * Conversion needed for RF5110 */ static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) { @@ -1088,7 +1088,7 @@ static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, } /* - * Convertion needed for 5111 + * Conversion needed for 5111 */ static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, struct ath5k_athchan_2ghz *athchan) @@ -2201,7 +2201,7 @@ ath5k_create_power_curve(s16 pmin, s16 pmax, /* * Get the surrounding per-channel power calibration piers * for a given frequency so that we can interpolate between - * them and come up with an apropriate dataset for our current + * them and come up with an appropriate dataset for our current * channel. */ static void @@ -2618,7 +2618,7 @@ ath5k_write_pcdac_table(struct ath5k_hw *ah) /* * Set the gain boundaries and create final Power to PDADC table * - * We can have up to 4 pd curves, we need to do a simmilar process + * We can have up to 4 pd curves, we need to do a similar process * as we do for RF5112. This time we don't have an edge_flag but we * set the gain boundaries on a separate register. */ @@ -2826,13 +2826,13 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah, u32 target = channel->center_freq; int pdg, i; - /* Get surounding freq piers for this channel */ + /* Get surrounding freq piers for this channel */ ath5k_get_chan_pcal_surrounding_piers(ah, channel, &pcinfo_L, &pcinfo_R); /* Loop over pd gain curves on - * surounding freq piers by index */ + * surrounding freq piers by index */ for (pdg = 0; pdg < ee->ee_pd_gains[ee_mode]; pdg++) { /* Fill curves in reverse order @@ -2923,7 +2923,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah, } /* Interpolate between curves - * of surounding freq piers to + * of surrounding freq piers to * get the final curve for this * pd gain. Re-use tmpL for interpolation * output */ @@ -2947,7 +2947,7 @@ ath5k_setup_channel_powertable(struct ath5k_hw *ah, /* Fill min and max power levels for this * channel by interpolating the values on - * surounding channels to complete the dataset */ + * surrounding channels to complete the dataset */ ah->ah_txpower.txp_min_pwr = ath5k_get_interpolated_value(target, (s16) pcinfo_L->freq, (s16) pcinfo_R->freq, @@ -3179,7 +3179,7 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, /* FIXME: TPC scale reduction */ - /* Get surounding channels for per-rate power table + /* Get surrounding channels for per-rate power table * calibration */ ath5k_get_rate_pcal_data(ah, channel, &rate_info); diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index e1c9abd8c879..d12b827033c1 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -132,8 +132,8 @@ * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR). - * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i - * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what + * So SNAPPEDBCRVALID should also stand for "snapped BCR -values- valid", so i + * renamed it to SNAPSHOTSVALID to make more sense. I really have no idea what * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR. */ #define AR5K_BSR 0x002c /* Register Address */ @@ -283,7 +283,7 @@ */ #define AR5K_ISR 0x001c /* Register Address [5210] */ #define AR5K_PISR 0x0080 /* Register Address [5211+] */ -#define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly recieved */ +#define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly received */ #define AR5K_ISR_RXDESC 0x00000002 /* RX descriptor request */ #define AR5K_ISR_RXERR 0x00000004 /* Receive error */ #define AR5K_ISR_RXNOFRM 0x00000008 /* No frame received (receive timeout) */ @@ -372,12 +372,12 @@ /* * Interrupt Mask Registers * - * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary + * As with ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match. */ #define AR5K_IMR 0x0020 /* Register Address [5210] */ #define AR5K_PIMR 0x00a0 /* Register Address [5211+] */ -#define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly recieved*/ +#define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly received*/ #define AR5K_IMR_RXDESC 0x00000002 /* RX descriptor request*/ #define AR5K_IMR_RXERR 0x00000004 /* Receive error*/ #define AR5K_IMR_RXNOFRM 0x00000008 /* No frame received (receive timeout)*/ @@ -895,7 +895,7 @@ #define AR5K_PCICFG_SL_INTEN 0x00000800 /* Enable interrupts when asleep */ #define AR5K_PCICFG_LED_BCTL 0x00001000 /* Led blink (?) [5210] */ #define AR5K_PCICFG_RETRY_FIX 0x00001000 /* Enable pci core retry fix */ -#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even whith pending interrupts*/ +#define AR5K_PCICFG_SL_INPEN 0x00002000 /* Sleep even with pending interrupts*/ #define AR5K_PCICFG_SPWR_DN 0x00010000 /* Mask for power status */ #define AR5K_PCICFG_LEDMODE 0x000e0000 /* Ledmode [5211+] */ #define AR5K_PCICFG_LEDMODE_PROP 0x00000000 /* Blink on standard traffic [5211+] */ diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index ffcf44a4058b..106c0b06cf55 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -142,7 +142,7 @@ static void ar5008_hw_force_bias(struct ath_hw *ah, u16 synth_freq) /** * ar5008_hw_set_channel - tune to a channel on the external AR2133/AR5133 radios - * @ah: atheros hardware stucture + * @ah: atheros hardware structure * @chan: * * For the external AR2133/AR5133 radios, takes the MHz channel value and set diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 4a9271802991..6eadf975ae48 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3240,7 +3240,7 @@ static int ar9300_compress_decision(struct ath_hw *ah, eep = ar9003_eeprom_struct_find_by_id(reference); if (eep == NULL) { ath_dbg(common, ATH_DBG_EEPROM, - "cant find reference eeprom struct %d\n", + "can't find reference eeprom struct %d\n", reference); return -1; } diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index c41ab8c30161..62e139a30a74 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c @@ -360,7 +360,7 @@ ret: * HTC Messages are handled directly here and the obtained SKB * is freed. * - * Sevice messages (Data, WMI) passed to the corresponding + * Service messages (Data, WMI) passed to the corresponding * endpoint RX handlers, which have to free the SKB. */ void ath9k_htc_rx_msg(struct htc_target *htc_handle, diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index e83128c50f7b..9c65459be100 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -44,7 +44,7 @@ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) *csz = (int)u8tmp; /* - * This check was put in to avoid "unplesant" consequences if + * This check was put in to avoid "unpleasant" consequences if * the bootrom has not fully initialized all PCI devices. * Sometimes the cache line size register is not set */ diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index a3241cd089b1..4c0d36a6980f 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -792,7 +792,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { - /* Set the choosen rate. No RTS for first series entry. */ + /* Set the chosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, &rates[i++], txrc, try_per_rate, rix, 0); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 26734e53b37f..88fa7fdffd05 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -628,8 +628,8 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, (u32)ATH_AMPDU_LIMIT_MAX); /* - * h/w can accept aggregates upto 16 bit lengths (65535). - * The IE, however can hold upto 65536, which shows up here + * h/w can accept aggregates up to 16 bit lengths (65535). + * The IE, however can hold up to 65536, which shows up here * as zero. Ignore 65536 since we are constrained by hw. */ if (tid->an->maxampdu) diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index c6a5fae634a0..c01c43d8e61b 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -161,7 +161,7 @@ struct carl9170_sta_tid { * Naturally: The higher the limit, the faster the device CAN send. * However, even a slight over-commitment at the wrong time and the * hardware is doomed to send all already-queued frames at suboptimal - * rates. This in turn leads to an enourmous amount of unsuccessful + * rates. This in turn leads to an enormous amount of unsuccessful * retries => Latency goes up, whereas the throughput goes down. CRASH! */ #define CARL9170_NUM_TX_LIMIT_HARD ((AR9170_TXQ_DEPTH * 3) / 2) diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index b6b0de600506..b6ae0e179c8d 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -427,7 +427,7 @@ static u32 carl9170_def_val(u32 reg, bool is_2ghz, bool is_40mhz) /* * initialize some phy regs from eeprom values in modal_header[] - * acc. to band and bandwith + * acc. to band and bandwidth */ static int carl9170_init_phy_from_eeprom(struct ar9170 *ar, bool is_2ghz, bool is_40mhz) diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 84866a4b8350..ec21ea9fd8d5 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -849,7 +849,7 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len) /* * nested carl9170_rx_stream call! * - * termination is guranteed, even when the + * termination is guaranteed, even when the * combined frame also have an element with * a bad tag. */ diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c index f82c400be288..2fb53d067512 100644 --- a/drivers/net/wireless/ath/carl9170/usb.c +++ b/drivers/net/wireless/ath/carl9170/usb.c @@ -430,7 +430,7 @@ static void carl9170_usb_rx_complete(struct urb *urb) * The system is too slow to cope with * the enormous workload. We have simply * run out of active rx urbs and this - * unfortunatly leads to an unpredictable + * unfortunately leads to an unpredictable * device. */ diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c index 183c28281385..cc11d66f15bc 100644 --- a/drivers/net/wireless/ath/hw.c +++ b/drivers/net/wireless/ath/hw.c @@ -86,7 +86,7 @@ * IFRAME-01: 0110 * * An easy eye-inspeciton of this already should tell you that this frame - * will not pass our check. This is beacuse the bssid_mask tells the + * will not pass our check. This is because the bssid_mask tells the * hardware to only look at the second least significant bit and the * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB * as 1, which does not match 0. diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index f828f294ba89..0e1b8793c864 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -268,7 +268,7 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, } /* - * If a country IE has been recieved check its rule for this + * If a country IE has been received check its rule for this * channel first before enabling active scan. The passive scan * would have been enforced by the initial processing of our * custom regulatory domain. @@ -476,7 +476,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; } else { /* - * This gets applied in the case of the absense of CRDA, + * This gets applied in the case of the absence of CRDA, * it's our own custom world regulatory domain, similar to * cfg80211's but we enable passive scanning. */ diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 46e382ed46aa..39a11e8af4fa 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -439,7 +439,7 @@ static u8 mac_reader[] = { }; struct atmel_private { - void *card; /* Bus dependent stucture varies for PCcard */ + void *card; /* Bus dependent structure varies for PCcard */ int (*present_callback)(void *); /* And callback which uses it */ char firmware_id[32]; AtmelFWType firmware_type; @@ -3895,7 +3895,7 @@ static int reset_atmel_card(struct net_device *dev) This routine is also responsible for initialising some hardware-specific fields in the atmel_private structure, - including a copy of the firmware's hostinfo stucture + including a copy of the firmware's hostinfo structure which is the route into the rest of the firmware datastructures. */ struct atmel_private *priv = netdev_priv(dev); diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index c96e19da2949..05263516c113 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -99,7 +99,7 @@ static void atmel_detach(struct pcmcia_device *link) } /* Call-back function to interrogate PCMCIA-specific information - about the current existance of the card */ + about the current existence of the card */ static int card_present(void *arg) { struct pcmcia_device *link = (struct pcmcia_device *)arg; diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index bd4cb75b6ca3..229f4388f790 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -648,7 +648,7 @@ struct b43_request_fw_context { char errors[B43_NR_FWTYPES][128]; /* Temporary buffer for storing the firmware name. */ char fwname[64]; - /* A fatal error occured while requesting. Firmware reqest + /* A fatal error occurred while requesting. Firmware reqest * can not continue, as any other reqest will also fail. */ int fatal_failure; }; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 57eb5b649730..d59b0168c14a 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4010,7 +4010,7 @@ static int b43_wireless_core_start(struct b43_wldev *dev) b43_mac_enable(dev); b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask); - /* Start maintainance work */ + /* Start maintenance work */ b43_periodic_tasks_setup(dev); b43_leds_init(dev); diff --git a/drivers/net/wireless/b43/phy_g.h b/drivers/net/wireless/b43/phy_g.h index 8569fdd4c6be..5413c906a3e7 100644 --- a/drivers/net/wireless/b43/phy_g.h +++ b/drivers/net/wireless/b43/phy_g.h @@ -164,7 +164,7 @@ struct b43_phy_g { /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code. - * Each value in the stack is layed out as follows: + * Each value in the stack is laid out as follows: * bit 0-11: offset * bit 12-15: register ID * bit 16-32: value diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index 001e841f118c..e789a89f1047 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -703,7 +703,7 @@ #define B43_NPHY_CHAN_ESTHANG B43_PHY_N(0x21D) /* Channel estimate hang */ #define B43_NPHY_FINERX2_CGC B43_PHY_N(0x221) /* Fine RX 2 clock gate control */ #define B43_NPHY_FINERX2_CGC_DECGC 0x0008 /* Decode gated clocks */ -#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ +#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power control init */ #define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ #define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 #define B43_NPHY_PAPD_EN0 B43_PHY_N(0x297) /* PAPD Enable0 TBD */ diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index c81b2f53b0c5..23583be1ee0b 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -488,7 +488,7 @@ struct b43legacy_phy { /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code. - * Each value in the stack is layed out as follows: + * Each value in the stack is laid out as follows: * bit 0-11: offset * bit 12-15: register ID * bit 16-32: value diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 18d63f57777d..3d05dc15c6b8 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -2359,7 +2359,7 @@ int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], } -/* Translate our list of Access Points & Stations to a card independant +/* Translate our list of Access Points & Stations to a card independent * format that the Wireless Tools will understand - Jean II */ int prism2_ap_translate_scan(struct net_device *dev, struct iw_request_info *info, char *buffer) diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 655ceeba9612..334e2d0b8e11 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -114,7 +114,7 @@ struct sta_info { * has passed since last received frame from the station, a nullfunc data * frame is sent to the station. If this frame is not acknowledged and no other * frames have been received, the station will be disassociated after - * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after + * AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with * max inactivity timer. */ #define AP_MAX_INACTIVITY_SEC (5 * 60) diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 6038633ef361..12de46407c71 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -1945,7 +1945,7 @@ static char * __prism2_translate_scan(local_info_t *local, } -/* Translate scan data returned from the card to a card independant +/* Translate scan data returned from the card to a card independent * format that the Wireless Tools will understand - Jean II */ static inline int prism2_translate_scan(local_info_t *local, struct iw_request_info *info, @@ -2043,7 +2043,7 @@ static inline int prism2_ioctl_giwscan_sta(struct net_device *dev, * until results are ready for various reasons. * First, managing wait queues is complex and racy * (there may be multiple simultaneous callers). - * Second, we grab some rtnetlink lock before comming + * Second, we grab some rtnetlink lock before coming * here (in dev_ioctl()). * Third, the caller can wait on the Wireless Event * - Jean II */ diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 1c66b3c1030d..88dc6a52bdf1 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -853,7 +853,7 @@ struct local_info { struct work_struct comms_qual_update; /* RSSI to dBm adjustment (for RX descriptor fields) */ - int rssi_to_dBm; /* substract from RSSI to get approximate dBm value */ + int rssi_to_dBm; /* subtract from RSSI to get approximate dBm value */ /* BSS list / protected by local->lock */ struct list_head bss_list; diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 4b97f918daff..44307753587d 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -63,7 +63,7 @@ When data is sent to the firmware, the first TBD is used to indicate to the firmware if a Command or Data is being sent. If it is Command, all of the command information is contained within the physical address referred to by the TBD. If it is Data, the first TBD indicates the type of data packet, number -of fragments, etc. The next TBD then referrs to the actual packet location. +of fragments, etc. The next TBD then refers to the actual packet location. The Tx flow cycle is as follows: diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 160881f234cc..42c3fe37af64 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -1181,7 +1181,7 @@ static void ipw_led_shutdown(struct ipw_priv *priv) /* * The following adds a new attribute to the sysfs representation * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/) - * used for controling the debug level. + * used for controlling the debug level. * * See the level definitions in ipw for details. */ @@ -3763,7 +3763,7 @@ static int ipw_queue_tx_init(struct ipw_priv *priv, q->txb = kmalloc(sizeof(q->txb[0]) * count, GFP_KERNEL); if (!q->txb) { - IPW_ERROR("vmalloc for auxilary BD structures failed\n"); + IPW_ERROR("vmalloc for auxiliary BD structures failed\n"); return -ENOMEM; } @@ -5581,7 +5581,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, return 0; } - /* Verify privacy compatability */ + /* Verify privacy compatibility */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " @@ -5808,7 +5808,7 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } - /* Verify privacy compatability */ + /* Verify privacy compatibility */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " @@ -8184,7 +8184,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, static int is_network_packet(struct ipw_priv *priv, struct libipw_hdr_4addr *header) { - /* Filter incoming packets to determine if they are targetted toward + /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ @@ -8340,9 +8340,9 @@ static void ipw_handle_mgmt_packet(struct ipw_priv *priv, } /* - * Main entry function for recieving a packet with 80211 headers. This + * Main entry function for receiving a packet with 80211 headers. This * should be called when ever the FW has notified us that there is a new - * skb in the recieve queue. + * skb in the receive queue. */ static void ipw_rx(struct ipw_priv *priv) { @@ -8683,7 +8683,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) * functions defined in ipw_main to provide the HW interaction. * * The exception to this is the use of the ipw_get_ordinal() - * function used to poll the hardware vs. making unecessary calls. + * function used to poll the hardware vs. making unnecessary calls. * */ @@ -10419,7 +10419,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, memset(&dummystats, 0, sizeof(dummystats)); - /* Filtering of fragment chains is done agains the first fragment */ + /* Filtering of fragment chains is done against the first fragment */ hdr = (void *)txb->fragments[0]->data; if (libipw_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c index 0de1b1893220..e5ad76cd77da 100644 --- a/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -925,7 +925,7 @@ drop_free: static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; /* -* Make ther structure we read from the beacon packet has +* Make the structure we read from the beacon packet to have * the right values */ static int libipw_verify_qos_info(struct libipw_qos_information_element diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index d418b647be80..1c3a8cb186bf 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -1030,7 +1030,7 @@ int iwl_legacy_apm_init(struct iwl_priv *priv) /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s - * NOTE: This is no-op for 3945 (non-existant bit) + * NOTE: This is no-op for 3945 (non-existent bit) */ iwl_legacy_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); diff --git a/drivers/net/wireless/iwlegacy/iwl-fh.h b/drivers/net/wireless/iwlegacy/iwl-fh.h index 4e20c7e5c883..6e6091816e36 100644 --- a/drivers/net/wireless/iwlegacy/iwl-fh.h +++ b/drivers/net/wireless/iwlegacy/iwl-fh.h @@ -436,7 +436,7 @@ * @finished_rb_num [0:11] - Indicates the index of the current RB * in which the last frame was written to * @finished_fr_num [0:11] - Indicates the index of the RX Frame - * which was transfered + * which was transferred */ struct iwl_rb_status { __le16 closed_rb_num; diff --git a/drivers/net/wireless/iwlegacy/iwl-scan.c b/drivers/net/wireless/iwlegacy/iwl-scan.c index 60f597f796ca..353234a02c6d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-scan.c +++ b/drivers/net/wireless/iwlegacy/iwl-scan.c @@ -143,7 +143,7 @@ static void iwl_legacy_do_scan_abort(struct iwl_priv *priv) IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret); iwl_legacy_force_scan_end(priv); } else - IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n"); + IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n"); } /** diff --git a/drivers/net/wireless/iwlegacy/iwl-sta.c b/drivers/net/wireless/iwlegacy/iwl-sta.c index 47c9da3834ea..66f0fb2bbe00 100644 --- a/drivers/net/wireless/iwlegacy/iwl-sta.c +++ b/drivers/net/wireless/iwlegacy/iwl-sta.c @@ -110,7 +110,7 @@ static int iwl_legacy_process_add_sta_resp(struct iwl_priv *priv, /* * XXX: The MAC address in the command buffer is often changed from * the original sent to the device. That is, the MAC address - * written to the command buffer often is not the same MAC adress + * written to the command buffer often is not the same MAC address * read from the command buffer when the command returns. This * issue has not yet been resolved and this debugging is left to * observe the problem. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c index b5cb3be0eb4b..ed0148d714de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c @@ -69,7 +69,7 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv) if (!priv->_agn.ict_tbl_vir) return -ENOMEM; - /* align table to PAGE_SIZE boundry */ + /* align table to PAGE_SIZE boundary */ priv->_agn.aligned_ict_tbl_dma = ALIGN(priv->_agn.ict_tbl_dma, PAGE_SIZE); IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 6c30fa652e27..bafbe57c9602 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1040,7 +1040,7 @@ int iwl_apm_init(struct iwl_priv *priv) /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s - * NOTE: This is no-op for 3945 (non-existant bit) + * NOTE: This is no-op for 3945 (non-existent bit) */ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 55b8370bc6d4..474009a244d4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -436,7 +436,7 @@ * @finished_rb_num [0:11] - Indicates the index of the current RB * in which the last frame was written to * @finished_fr_num [0:11] - Indicates the index of the RX Frame - * which was transfered + * which was transferred */ struct iwl_rb_status { __le16 closed_rb_num; diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 3a4d9e6b0421..914c77e44588 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -143,7 +143,7 @@ static void iwl_do_scan_abort(struct iwl_priv *priv) IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret); iwl_force_scan_end(priv); } else - IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n"); + IWL_DEBUG_SCAN(priv, "Successfully send scan abort\n"); } /** diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c index 907ac890997c..1cabcb39643f 100644 --- a/drivers/net/wireless/iwmc3200wifi/hal.c +++ b/drivers/net/wireless/iwmc3200wifi/hal.c @@ -57,7 +57,7 @@ * This is due to the fact the host talks exclusively * to the UMAC and so there needs to be a special UMAC * command for talking to the LMAC. - * This is how a wifi command is layed out: + * This is how a wifi command is laid out: * ------------------------ * | iwm_udma_out_wifi_hdr | * ------------------------ @@ -72,7 +72,7 @@ * Those commands are handled by the device's bootrom, * and are typically sent when the UMAC and the LMAC * are not yet available. - * * This is how a non-wifi command is layed out: + * * This is how a non-wifi command is laid out: * --------------------------- * | iwm_udma_out_nonwifi_hdr | * --------------------------- diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c index 3216621fc55a..be98074c0608 100644 --- a/drivers/net/wireless/iwmc3200wifi/tx.c +++ b/drivers/net/wireless/iwmc3200wifi/tx.c @@ -197,7 +197,7 @@ int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb) spin_lock(&iwm->tx_credit.lock); if (!iwm_tx_credit_ok(iwm, id, nb)) { - IWM_DBG_TX(iwm, DBG, "No credit avaliable for pool[%d]\n", id); + IWM_DBG_TX(iwm, DBG, "No credit available for pool[%d]\n", id); ret = -ENOSPC; goto out; } diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README index 60fd1afe89ac..1453eec82a99 100644 --- a/drivers/net/wireless/libertas/README +++ b/drivers/net/wireless/libertas/README @@ -70,7 +70,7 @@ rdrf These commands are used to read the MAC, BBP and RF registers from the card. These commands take one parameter that specifies the offset location that is to be read. This parameter must be specified in - hexadecimal (its possible to preceed preceding the number with a "0x"). + hexadecimal (its possible to precede preceding the number with a "0x"). Path: /sys/kernel/debug/libertas_wireless/ethX/registers/ @@ -84,7 +84,7 @@ wrrf These commands are used to write the MAC, BBP and RF registers in the card. These commands take two parameters that specify the offset location and the value that is to be written. This parameters must - be specified in hexadecimal (its possible to preceed the number + be specified in hexadecimal (its possible to precede the number with a "0x"). Usage: diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 30ef0351bfc4..5caa2ac14d61 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -1350,7 +1350,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, * we remove all keys like in the WPA/WPA2 setup, * we just don't set RSN. * - * Therefore: fall-throught + * Therefore: fall-through */ case WLAN_CIPHER_SUITE_TKIP: case WLAN_CIPHER_SUITE_CCMP: diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index fc8121190d38..8712cb213f2f 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -913,7 +913,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out3; } - /* Clear any interrupt cause that happend while sending + /* Clear any interrupt cause that happened while sending * firmware/initializing card */ if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK); if_cs_enable_ints(card); diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h index 8b1417d3b71b..d2ac1dcd7e2e 100644 --- a/drivers/net/wireless/libertas/if_spi.h +++ b/drivers/net/wireless/libertas/if_spi.h @@ -66,7 +66,7 @@ #define IF_SPI_HOST_INT_CTRL_REG 0x40 /* Host interrupt controller reg */ #define IF_SPI_CARD_INT_CAUSE_REG 0x44 /* Card interrupt cause reg */ -#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interupt status reg */ +#define IF_SPI_CARD_INT_STATUS_REG 0x48 /* Card interrupt status reg */ #define IF_SPI_CARD_INT_EVENT_MASK_REG 0x4C /* Card interrupt event mask */ #define IF_SPI_CARD_INT_STATUS_MASK_REG 0x50 /* Card interrupt status mask */ diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 56f439d58013..f4f4257a9d67 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -62,7 +62,7 @@ MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler"); * an intersection to occur but each device will still use their * respective regulatory requested domains. Subsequent radios will * use the resulting intersection. - * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We acomplish + * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We accomplish * this by using a custom beacon-capable regulatory domain for the first * radio. All other device world roam. * @HWSIM_REGTEST_CUSTOM_WORLD: Used for testing the custom world regulatory diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c index b4772c1c6135..3c7877a7c31c 100644 --- a/drivers/net/wireless/orinoco/hw.c +++ b/drivers/net/wireless/orinoco/hw.c @@ -1031,7 +1031,7 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx, else buf.tsc[4] = 0x10; - /* Wait upto 100ms for tx queue to empty */ + /* Wait up to 100ms for tx queue to empty */ for (k = 100; k > 0; k--) { udelay(1000); ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY, diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 356e6bb443a6..a946991989c6 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -465,7 +465,7 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, if (slot < 0) { /* - * The device supports the choosen algorithm, but the + * The device supports the chosen algorithm, but the * firmware does not provide enough key slots to store * all of them. * But encryption offload for outgoing frames is always diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 7ecc0bda57b3..6d9204fef90b 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -287,7 +287,7 @@ static void p54spi_power_on(struct p54s_priv *priv) enable_irq(gpio_to_irq(p54spi_gpio_irq)); /* - * need to wait a while before device can be accessed, the lenght + * need to wait a while before device can be accessed, the length * is just a guess */ msleep(10); diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index d44f8e20cce0..266d45bf86f5 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -113,7 +113,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes * and add WDS address information */ if (likely(((long) skb->data & 0x03) | init_wds)) { - /* get the number of bytes to add and re-allign */ + /* get the number of bytes to add and re-align */ offset = (4 - (long) skb->data) & 0x03; offset += init_wds ? 6 : 0; @@ -342,7 +342,7 @@ islpci_eth_receive(islpci_private *priv) priv->pci_map_rx_address[index], MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); - /* update the skb structure and allign the buffer */ + /* update the skb structure and align the buffer */ skb_put(skb, size); if (offset) { /* shift the buffer allocation offset bytes to get the right frame */ diff --git a/drivers/net/wireless/rayctl.h b/drivers/net/wireless/rayctl.h index 49d9b267bc0f..d7646f299bd3 100644 --- a/drivers/net/wireless/rayctl.h +++ b/drivers/net/wireless/rayctl.h @@ -578,7 +578,7 @@ struct tx_msg { UCHAR var[1]; }; -/****** ECF Receive Control Stucture (RCS) Area at Shared RAM offset 0x0800 */ +/****** ECF Receive Control Structure (RCS) Area at Shared RAM offset 0x0800 */ /* Structures for command specific parameters (rcs.var) */ struct rx_packet_cmd { UCHAR rx_data_ptr[2]; diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 70b9abbdeb9e..8fbc5fa965e0 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -616,7 +616,7 @@ * READ_CONTROL: 0 write BBP, 1 read BBP * BUSY: ASIC is busy executing BBP commands * BBP_PAR_DUR: 0 4 MAC clocks, 1 8 MAC clocks - * BBP_RW_MODE: 0 serial, 1 paralell + * BBP_RW_MODE: 0 serial, 1 parallel */ #define BBP_CSR_CFG 0x101c #define BBP_CSR_CFG_VALUE FIELD32(0x000000ff) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 2ee6cebb9b25..dbf74d07d947 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1518,7 +1518,7 @@ static void rt2800_config_channel_rf2xxx(struct rt2x00_dev *rt2x00dev, if (rf->channel > 14) { /* * When TX power is below 0, we should increase it by 7 to - * make it a positive value (Minumum value is -7). + * make it a positive value (Minimum value is -7). * However this means that values between 0 and 7 have * double meaning, and we should set a 7DBm boost flag. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index a3940d7300a4..7f10239f56a8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -484,13 +484,13 @@ struct rt2x00intf_conf { enum nl80211_iftype type; /* - * TSF sync value, this is dependant on the operation type. + * TSF sync value, this is dependent on the operation type. */ enum tsf_sync sync; /* - * The MAC and BSSID addressess are simple array of bytes, - * these arrays are little endian, so when sending the addressess + * The MAC and BSSID addresses are simple array of bytes, + * these arrays are little endian, so when sending the addresses * to the drivers, copy the it into a endian-signed variable. * * Note that all devices (except rt2500usb) have 32 bits @@ -1131,7 +1131,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue); * @drop: True to drop all pending frames. * * This function will flush the queue. After this call - * the queue is guarenteed to be empty. + * the queue is guaranteed to be empty. */ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index e7f67d5eda52..9416e36de29e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -60,7 +60,7 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, * Note that when NULL is passed as address we will send * 00:00:00:00:00 to the device to clear the address. * This will prevent the device being confused when it wants - * to ACK frames or consideres itself associated. + * to ACK frames or considers itself associated. */ memset(conf.mac, 0, sizeof(conf.mac)); if (mac) diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 5e9074bf2b8e..3f5688fbf3f7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -237,7 +237,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, } /* - * NOTE: Always count the payload as transfered, + * NOTE: Always count the payload as transferred, * even when alignment was set to zero. This is required * for determining the correct offset for the ICV data. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h index 5d6e0b83151f..063ebcce97f8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dump.h +++ b/drivers/net/wireless/rt2x00/rt2x00dump.h @@ -51,7 +51,7 @@ * [rt2x00dump header][hardware descriptor][ieee802.11 frame] * * rt2x00dump header: The description of the dumped frame, as well as - * additional information usefull for debugging. See &rt2x00dump_hdr. + * additional information useful for debugging. See &rt2x00dump_hdr. * hardware descriptor: Descriptor that was used to receive or transmit * the frame. * ieee802.11 frame: The actual frame that was received or transmitted. diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c index c975b0a12e95..29abfdeb0b65 100644 --- a/drivers/net/wireless/rt2x00/rt2x00link.c +++ b/drivers/net/wireless/rt2x00/rt2x00link.c @@ -283,7 +283,7 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev) /** * While scanning, link tuning is disabled. By default * the most sensitive settings will be used to make sure - * that all beacons and probe responses will be recieved + * that all beacons and probe responses will be received * during the scan. */ if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 4b3c70eeef1f..4358051bfe1a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -546,7 +546,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, } /* - * When DMA allocation is required we should guarentee to the + * When DMA allocation is required we should guarantee to the * driver that the DMA is aligned to a 4-byte boundary. * However some drivers require L2 padding to pad the payload * rather then the header. This could be a requirement for @@ -689,7 +689,7 @@ void rt2x00queue_for_each_entry(struct data_queue *queue, spin_unlock_irqrestore(&queue->index_lock, irqflags); /* - * Start from the TX done pointer, this guarentees that we will + * Start from the TX done pointer, this guarantees that we will * send out all frames in the correct order. */ if (index_start < index_end) { @@ -883,7 +883,7 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop) } /* - * Check if driver supports flushing, we can only guarentee + * Check if driver supports flushing, we can only guarantee * full support for flushing if the driver is able * to cancel all pending frames (drop = true). */ diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 0c8b0c699679..217861f8d95f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -344,8 +344,8 @@ struct txentry_desc { * only be touched after the device has signaled it is done with it. * @ENTRY_DATA_PENDING: This entry contains a valid frame and is waiting * for the signal to start sending. - * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occured - * while transfering the data to the hardware. No TX status report will + * @ENTRY_DATA_IO_FAILED: Hardware indicated that an IO error occurred + * while transferring the data to the hardware. No TX status report will * be expected from the hardware. * @ENTRY_DATA_STATUS_PENDING: The entry has been send to the device and * returned. It is now waiting for the status reporting before the @@ -365,7 +365,7 @@ enum queue_entry_flags { * @flags: Entry flags, see &enum queue_entry_flags. * @queue: The data queue (&struct data_queue) to which this entry belongs. * @skb: The buffer which is currently being transmitted (for TX queue), - * or used to directly recieve data in (for RX queue). + * or used to directly receive data in (for RX queue). * @entry_idx: The entry index number. * @priv_data: Private data belonging to this queue entry. The pointer * points to data specific to a particular driver and queue type. @@ -388,7 +388,7 @@ struct queue_entry { * @Q_INDEX: Index pointer to the current entry in the queue, if this entry is * owned by the hardware then the queue is considered to be full. * @Q_INDEX_DMA_DONE: Index pointer for the next entry which will have been - * transfered to the hardware. + * transferred to the hardware. * @Q_INDEX_DONE: Index pointer to the next entry which will be completed by * the hardware and for which we need to run the txdone handler. If this * entry is not owned by the hardware the queue is considered to be empty. @@ -627,7 +627,7 @@ static inline int rt2x00queue_threshold(struct data_queue *queue) } /** - * rt2x00queue_status_timeout - Check if a timeout occured for STATUS reports + * rt2x00queue_status_timeout - Check if a timeout occurred for STATUS reports * @queue: Queue to check. */ static inline int rt2x00queue_status_timeout(struct data_queue *queue) @@ -637,7 +637,7 @@ static inline int rt2x00queue_status_timeout(struct data_queue *queue) } /** - * rt2x00queue_timeout - Check if a timeout occured for DMA transfers + * rt2x00queue_timeout - Check if a timeout occurred for DMA transfers * @queue: Queue to check. */ static inline int rt2x00queue_dma_timeout(struct data_queue *queue) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index fbe735f5b352..36f388f97d65 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -173,7 +173,7 @@ static void rt2x00usb_work_txdone_entry(struct queue_entry *entry) /* * If the transfer to hardware succeeded, it does not mean the * frame was send out correctly. It only means the frame - * was succesfully pushed to the hardware, we have no + * was successfully pushed to the hardware, we have no * way to determine the transmission status right now. * (Only indirectly by looking at the failed TX counters * in the register). diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 6aaf51fc7ad8..e11c759ac9ed 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -400,7 +400,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue); * @rt2x00dev: Pointer to &struct rt2x00_dev * * Check the health of the USB communication and determine - * if timeouts have occured. If this is the case, this function + * if timeouts have occurred. If this is the case, this function * will reset all communication to restore functionality again. */ void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index bb0c781f4a1b..0d7d93e1d398 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -520,7 +520,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *because hw will nerver use hw_rate *when tcb_desc->use_driver_rate = false *so we never set highest N rate here, - *and N rate will all be controled by FW + *and N rate will all be controlled by FW *when tcb_desc->use_driver_rate = false */ if (rtlmac->ht_enable) { diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 9cd7703c2a30..5938f6ee21e4 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -395,7 +395,7 @@ static void rtl_pci_init_aspm(struct ieee80211_hw *hw) * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, * 2 - Enable ASPM with Clock Req, - * 3 - Alwyas Enable ASPM with Clock Req, + * 3 - Always Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. * set defult to RTL8192CE:3 RTL8192E:2 * */ diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c index 3336ca999dfd..d26f957981ad 100644 --- a/drivers/net/wireless/rtlwifi/regd.c +++ b/drivers/net/wireless/rtlwifi/regd.c @@ -179,7 +179,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, } /* - *If a country IE has been recieved check its rule for this + *If a country IE has been received check its rule for this *channel first before enabling active scan. The passive scan *would have been enforced by the initial processing of our *custom regulatory domain. diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index 01226f8e70f9..07db95ff9bc5 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1555,7 +1555,7 @@ struct rtl_priv { /*************************************** - Bluetooth Co-existance Related + Bluetooth Co-existence Related ****************************************/ enum bt_ant_num { diff --git a/drivers/net/wireless/wl1251/cmd.c b/drivers/net/wireless/wl1251/cmd.c index 0ade4bd617c0..81f164bc4888 100644 --- a/drivers/net/wireless/wl1251/cmd.c +++ b/drivers/net/wireless/wl1251/cmd.c @@ -104,7 +104,7 @@ int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) * @wl: wl struct * @id: acx id * @buf: buffer for the response, including all headers, must work with dma - * @len: lenght of buf + * @len: length of buf */ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len) { diff --git a/drivers/net/wireless/wl1251/rx.c b/drivers/net/wireless/wl1251/rx.c index c1b3b3f03da2..6af35265c900 100644 --- a/drivers/net/wireless/wl1251/rx.c +++ b/drivers/net/wireless/wl1251/rx.c @@ -179,7 +179,7 @@ static void wl1251_rx_body(struct wl1251 *wl, rx_buffer = skb_put(skb, length); wl1251_mem_read(wl, rx_packet_ring_addr, rx_buffer, length); - /* The actual lenght doesn't include the target's alignment */ + /* The actual length doesn't include the target's alignment */ skb->len = desc->length - PLCP_HEADER_LENGTH; fc = (u16 *)skb->data; diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index f0aa7ab97bf7..96324336f936 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -359,7 +359,7 @@ int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) * @wl: wl struct * @id: acx id * @buf: buffer for the response, including all headers, must work with dma - * @len: lenght of buf + * @len: length of buf */ int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) { diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 856a8a2fff4f..8a8323896eec 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -497,7 +497,7 @@ struct conf_rx_settings { #define CONF_TX_RATE_RETRY_LIMIT 10 /* - * Rates supported for data packets when operating as AP. Note the absense + * Rates supported for data packets when operating as AP. Note the absence * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop * one. The rate dropped is not mandatory under any operating mode. */ @@ -572,7 +572,7 @@ enum conf_tx_ac { CONF_TX_AC_BK = 1, /* background */ CONF_TX_AC_VI = 2, /* video */ CONF_TX_AC_VO = 3, /* voice */ - CONF_TX_AC_CTS2SELF = 4, /* fictious AC, follows AC_VO */ + CONF_TX_AC_CTS2SELF = 4, /* fictitious AC, follows AC_VO */ CONF_TX_AC_ANY_TID = 0x1f }; @@ -1169,7 +1169,7 @@ struct conf_memory_settings { /* * Minimum required free tx memory blocks in order to assure optimum - * performence + * performance * * Range: 0-120 */ @@ -1177,7 +1177,7 @@ struct conf_memory_settings { /* * Minimum required free rx memory blocks in order to assure optimum - * performence + * performance * * Range: 0-120 */ diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index c1aac8292089..00c771ea70bf 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -94,7 +94,7 @@ static inline int wl1271_translate_addr(struct wl1271 *wl, int addr) * translated region. * * The translated regions occur next to each other in physical device - * memory, so just add the sizes of the preceeding address regions to + * memory, so just add the sizes of the preceding address regions to * get the offset to the new region. * * Currently, only the two first regions are addressed, and the diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 3e5befe4d03b..fc08f36fe1f5 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -290,7 +290,7 @@ static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest, * \ \- IEEE 802.11 -/ \-------------- len --------------/ * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/ * - * Return = Postion in Card + * Return = Position in Card */ static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len) { @@ -1932,7 +1932,7 @@ static int wl3501_config(struct pcmcia_device *link) this->base_addr = dev->base_addr; if (!wl3501_get_flash_mac_addr(this)) { - printk(KERN_WARNING "%s: Cant read MAC addr in flash ROM?\n", + printk(KERN_WARNING "%s: Can't read MAC addr in flash ROM?\n", dev->name); unregister_netdev(dev); goto failed; diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index 0597d862fbd2..e36117486c91 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -169,7 +169,7 @@ static int rf2959_init_hw(struct zd_rf *rf) { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A }, { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 }, /* { CR91, 0x18 }, */ - /* should solve continous CTS frame problems */ + /* should solve continuous CTS frame problems */ { CR91, 0x00 }, { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 }, diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index 9e74eb1b67d5..ba0a0ccb1fa0 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -353,7 +353,7 @@ static int uw2453_init_hw(struct zd_rf *rf) }; static const u32 rv[] = { - UW2453_REGWRITE(4, 0x2b), /* configure reciever gain */ + UW2453_REGWRITE(4, 0x2b), /* configure receiver gain */ UW2453_REGWRITE(5, 0x19e4f), /* configure transmitter gain */ UW2453_REGWRITE(6, 0xf81ad), /* enable RX/TX filter tuning */ UW2453_REGWRITE(7, 0x3fffe), /* disable TX gain in test mode */ diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 2642af4ee491..372572c0adc6 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -786,7 +786,7 @@ static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg) * @reg: register number to write to * @val: value to write to the register number specified by reg * - * This fucntion waits till the device is ready to accept a new MDIO + * This function waits till the device is ready to accept a new MDIO * request and then writes the val to the MDIO Write Data register. */ static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg, diff --git a/drivers/net/znet.c b/drivers/net/znet.c index ae07b3dfbcc1..ec2800ff8d42 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -652,7 +652,7 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id) dev->stats.tx_errors++; /* Transceiver may be stuck if cable - * was removed while emiting a + * was removed while emitting a * packet. Flip it off, then on to * reset it. This is very empirical, * but it seems to work. */ diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index c9db49c10f45..8b63a691a9ed 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -676,7 +676,7 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, early_init_dt_check_for_initrd(node); - /* Retreive command line */ + /* Retrieve command line */ p = of_get_flat_dt_prop(node, "bootargs", &l); if (p != NULL && l > 0) strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index dcd7857784f2..d35e300b0ad1 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -136,7 +136,7 @@ EXPORT_SYMBOL(of_phy_find_device); * @hndlr: Link state callback for the network device * @iface: PHY data interface type * - * Returns a pointer to the phy_device if successfull. NULL otherwise + * Returns a pointer to the phy_device if successful. NULL otherwise */ struct phy_device *of_phy_connect(struct net_device *dev, struct device_node *phy_np, diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 1062b8ffe244..246a92f677e4 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -141,7 +141,7 @@ struct pdcspath_attribute paths_attr_##_name = { \ * @entry: A pointer to an allocated pdcspath_entry. * * The general idea is that you don't read from the Stable Storage every time - * you access the files provided by the facilites. We store a copy of the + * you access the files provided by the facilities. We store a copy of the * content of the stable storage WRT various paths in these structs. We read * these structs when reading the files, and we will write to these structs when * writing to the files, and only then write them back to the Stable Storage. @@ -213,7 +213,7 @@ pdcspath_store(struct pdcspath_entry *entry) /* addr, devpath and count must be word aligned */ if (pdc_stable_write(entry->addr, devpath, sizeof(*devpath)) != PDC_OK) { - printk(KERN_ERR "%s: an error occured when writing to PDC.\n" + printk(KERN_ERR "%s: an error occurred when writing to PDC.\n" "It is likely that the Stable Storage data has been corrupted.\n" "Please check it carefully upon next reboot.\n", __func__); WARN_ON(1); diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 855f389eea40..d92185a5523b 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -142,7 +142,7 @@ config PARPORT_AX88796 the AX88796 network controller chip. This code is also available as a module (say M), called parport_ax88796. - The driver is not dependant on the AX88796 network driver, and + The driver is not dependent on the AX88796 network driver, and should not interfere with the networking functions of the chip. config PARPORT_1284 diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 8901ecf6e037..f9fd4b33a546 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -355,7 +355,7 @@ int parport_negotiate (struct parport *port, int mode) return 0; } - /* Go to compability forward idle mode */ + /* Go to compatibility forward idle mode */ if (port->ieee1284.mode != IEEE1284_MODE_COMPAT) parport_ieee1284_terminate (port); diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 8d62fb76cd41..a3755ffc03d4 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -1488,7 +1488,7 @@ static void __devinit winbond_check(int io, int key) outb(key, io); outb(key, io); /* Write Magic Sequence to EFER, extended - funtion enable register */ + function enable register */ outb(0x20, io); /* Write EFIR, extended function index register */ devid = inb(io + 1); /* Read EFDR, extended function data register */ outb(0x21, io); @@ -1527,7 +1527,7 @@ static void __devinit winbond_check2(int io, int key) x_oldid = inb(io + 2); outb(key, io); /* Write Magic Byte to EFER, extended - funtion enable register */ + function enable register */ outb(0x20, io + 2); /* Write EFIR, extended function index register */ devid = inb(io + 2); /* Read EFDR, extended function data register */ outb(0x21, io + 1); @@ -1569,7 +1569,7 @@ static void __devinit smsc_check(int io, int key) outb(key, io); outb(key, io); /* Write Magic Sequence to EFER, extended - funtion enable register */ + function enable register */ outb(0x0d, io); /* Write EFIR, extended function index register */ oldid = inb(io + 1); /* Read EFDR, extended function data register */ outb(0x0e, io); diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 3bc72d18b121..8f3faf343f75 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -351,7 +351,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags) * To handle different BIOS behavior, we look for _OSC on a root * bridge preferentially (according to PCI fw spec). Later for * OSHP within the scope of the hotplug controller and its parents, - * upto the host bridge under which this controller exists. + * up to the host bridge under which this controller exists. */ handle = acpi_find_root_bridge_handle(pdev); if (handle) { diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e610cfe4f07b..2f67e9bc2f96 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -585,7 +585,7 @@ static void remove_bridge(acpi_handle handle) /* * On root bridges with hotplug slots directly underneath (ie, - * no p2p bridge inbetween), we call cleanup_bridge(). + * no p2p bridge between), we call cleanup_bridge(). * * The else clause cleans up root bridges that either had no * hotplug slots at all, or had a p2p bridge underneath. diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c index ef7411c660b9..758adb5f47fd 100644 --- a/drivers/pci/hotplug/rpaphp_core.c +++ b/drivers/pci/hotplug/rpaphp_core.c @@ -290,7 +290,7 @@ static int is_php_dn(struct device_node *dn, const int **indexes, * @dn: device node of slot * * This subroutine will register a hotplugable slot with the - * PCI hotplug infrastructure. This routine is typicaly called + * PCI hotplug infrastructure. This routine is typically called * during boot time, if the hotplug slots are present at boot time, * or is called later, by the dlpar add code, if the slot is * being dynamically added during runtime. diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 7da3bef60d87..505c1c7075f0 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -2265,7 +2265,7 @@ int __init init_dmars(void) /* * TBD: * we could share the same root & context tables - * amoung all IOMMU's. Need to Split it later. + * among all IOMMU's. Need to Split it later. */ ret = iommu_alloc_root_entry(iommu); if (ret) { diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index a22557b20283..3607faf28a4d 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -289,7 +289,7 @@ int free_irte(int irq) * source validation type */ #define SVT_NO_VERIFY 0x0 /* no verification is required */ -#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fiels */ +#define SVT_VERIFY_SID_SQ 0x1 /* verify using SID and SQ fields */ #define SVT_VERIFY_BUS 0x2 /* verify bus of request-id */ /* diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c index 7914951ef29a..9606e599a475 100644 --- a/drivers/pci/iova.c +++ b/drivers/pci/iova.c @@ -391,7 +391,7 @@ reserve_iova(struct iova_domain *iovad, break; } - /* We are here either becasue this is the first reserver node + /* We are here either because this is the first reserver node * or need to insert remaining non overlap addr range */ iova = __insert_new_range(iovad, pfn_lo, pfn_hi); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index a8a277a2e0d0..f8deb3e380a2 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -645,7 +645,7 @@ pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) * a per-bus basis. This routine creates the files and ties them into * their associated read, write and mmap files from pci-sysfs.c * - * On error unwind, but don't propogate the error to the caller + * On error unwind, but don't propagate the error to the caller * as it is ok to set up the PCI bus without these files. */ void pci_create_legacy_files(struct pci_bus *b) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index bd80f6378463..5129ed6d8fa7 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -263,7 +263,7 @@ static void quirk_vialatency(struct pci_dev *dev) * This happens to include the IDE controllers.... * * VIA only apply this fix when an SB Live! is present but under - * both Linux and Windows this isnt enough, and we have seen + * both Linux and Windows this isn't enough, and we have seen * corruption without SB Live! but with things like 3 UDMA IDE * controllers. So we ignore that bit of the VIA recommendation.. */ @@ -2680,7 +2680,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HINT, 0x0020, quirk_hotplug_bridge); * This is a quirk for the Ricoh MMC controller found as a part of * some mulifunction chips. - * This is very similiar and based on the ricoh_mmc driver written by + * This is very similar and based on the ricoh_mmc driver written by * Philip Langdale. Thank you for these magic sequences. * * These chips implement the four main memory card controllers (SD, MMC, MS, xD) diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index fc7906eaf228..3e447d0387b7 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -54,7 +54,7 @@ static struct pccard_operations i82092aa_operations = { .set_mem_map = i82092aa_set_mem_map, }; -/* The card can do upto 4 sockets, allocate a structure for each of them */ +/* The card can do up to 4 sockets, allocate a structure for each of them */ struct socket_info { int number; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 42fbf1a75576..fe77e8223841 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -173,7 +173,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev, c = p_dev->function_config; if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&p_dev->dev, "Configuration isnt't locked\n"); + dev_dbg(&p_dev->dev, "Configuration isn't't locked\n"); mutex_unlock(&s->ops_mutex); return -EACCES; } diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c index 25afe637c657..c21888eebb58 100644 --- a/drivers/pcmcia/pxa2xx_lubbock.c +++ b/drivers/pcmcia/pxa2xx_lubbock.c @@ -187,7 +187,7 @@ lubbock_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, * We need to hack around the const qualifier as * well to keep this ugly workaround localized and * not force it to the rest of the code. Barf bags - * avaliable in the seat pocket in front of you! + * available in the seat pocket in front of you! */ ((socket_state_t *)state)->Vcc = 50; ((socket_state_t *)state)->Vpp = 50; diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index 9ffa97d0b16c..a71789486cdf 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -691,7 +691,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) /* * those are either single or dual slot CB with additional functions * like 1394, smartcard reader, etc. check the TIEALL flag for them - * the TIEALL flag binds the IRQ of all functions toghether. + * the TIEALL flag binds the IRQ of all functions together. * we catch the single slot variants later. */ sysctl = config_readl(socket, TI113X_SYSTEM_CONTROL); diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 6c12db503161..c2f4bd8013b5 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -202,7 +202,7 @@ static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) if (ret) return ret; - /* Shift bits to accomodate the lower two data bits */ + /* Shift bits to accommodate the lower two data bits */ adc_val = (data << 2); addr++; diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index 4a651f69e17c..bc00693d0c79 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -320,7 +320,7 @@ void pnp_remove_card_device(struct pnp_dev *dev) * pnp_request_card_device - Searches for a PnP device under the specified card * @clink: pointer to the card link, cannot be NULL * @id: pointer to a PnP ID structure that explains the rules for finding the device - * @from: Starting place to search from. If NULL it will start from the begining. + * @from: Starting place to search from. If NULL it will start from the beginning. */ struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink, const char *id, struct pnp_dev *from) @@ -369,7 +369,7 @@ err_out: /** * pnp_release_card_device - call this when the driver no longer needs the device - * @dev: pointer to the PnP device stucture + * @dev: pointer to the PnP device structure */ void pnp_release_card_device(struct pnp_dev *dev) { diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 8591f6ab1b35..b859d16cf78c 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -219,7 +219,7 @@ void pnpbios_print_status(const char *module, u16 status) module); break; case PNP_HARDWARE_ERROR: - printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", + printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occurred\n", module); break; default: diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig index f0d3376b58ba..258ca596e1bc 100644 --- a/drivers/pps/Kconfig +++ b/drivers/pps/Kconfig @@ -35,7 +35,7 @@ config NTP_PPS depends on PPS && !NO_HZ help This option adds support for direct in-kernel time - syncronization using an external PPS signal. + synchronization using an external PPS signal. It doesn't work on tickless systems at the moment. diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c index 8000985d0e8c..643697f71390 100644 --- a/drivers/ps3/ps3-lpm.c +++ b/drivers/ps3/ps3-lpm.c @@ -919,7 +919,7 @@ EXPORT_SYMBOL_GPL(ps3_disable_pm); * @offset: Offset in bytes from the start of the trace buffer. * @buf: Copy destination. * @count: Maximum count of bytes to copy. - * @bytes_copied: Pointer to a variable that will recieve the number of + * @bytes_copied: Pointer to a variable that will receive the number of * bytes copied to @buf. * * On error @buf will contain any successfully copied trace buffer data @@ -974,7 +974,7 @@ EXPORT_SYMBOL_GPL(ps3_lpm_copy_tb); * @offset: Offset in bytes from the start of the trace buffer. * @buf: A __user copy destination. * @count: Maximum count of bytes to copy. - * @bytes_copied: Pointer to a variable that will recieve the number of + * @bytes_copied: Pointer to a variable that will receive the number of * bytes copied to @buf. * * On error @buf will contain any successfully copied trace buffer data @@ -1074,7 +1074,7 @@ EXPORT_SYMBOL_GPL(ps3_disable_pm_interrupts); /** * ps3_lpm_open - Open the logical performance monitor device. - * @tb_type: Specifies the type of trace buffer lv1 sould use for this lpm + * @tb_type: Specifies the type of trace buffer lv1 should use for this lpm * instance, specified by one of enum ps3_lpm_tb_type. * @tb_cache: Optional user supplied buffer to use as the trace buffer cache. * If NULL, the driver will allocate and manage an internal buffer. diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index d37c445f0eda..1b98367110c4 100644 --- a/drivers/ps3/ps3-sys-manager.c +++ b/drivers/ps3/ps3-sys-manager.c @@ -80,7 +80,7 @@ static void __maybe_unused _dump_sm_header( * * Currently all messages received from the system manager are either * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header - * + 16 bytes payload = 32 bytes). This knowlege is used to simplify + * + 16 bytes payload = 32 bytes). This knowledge is used to simplify * the logic. */ diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 3a59d5f018d3..ee893581d4b7 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -295,7 +295,7 @@ static int __devinit rio_add_device(struct rio_dev *rdev) } /** - * rio_enable_rx_tx_port - enable input reciever and output transmitter of + * rio_enable_rx_tx_port - enable input receiver and output transmitter of * given port * @port: Master port associated with the RIO network * @local: local=1 select local port otherwise a far device is reached diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 3ffc6979d164..0fae51c4845a 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1313,7 +1313,7 @@ static int _regulator_enable(struct regulator_dev *rdev) return -EINVAL; /* Query before enabling in case configuration - * dependant. */ + * dependent. */ ret = _regulator_get_enable_time(rdev); if (ret >= 0) { delay = ret; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index a8f4ecfb0843..daff7fd0e95c 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -262,7 +262,7 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, if (err) { dev_warn(max8952->dev, "VID0/1 gpio invalid: " - "DVS not avilable.\n"); + "DVS not available.\n"); max8952->vid0 = 0; max8952->vid1 = 0; /* Mark invalid */ diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8ec6b069a7f5..23719f0acbf6 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -454,7 +454,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); * @rtc: pointer to the rtc device * * This function is called when an AIE, UIE or PIE mode interrupt - * has occured (or been emulated). + * has occurred (or been emulated). * * Triggers the registered irq_task function callback. */ diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 518a76ec71ca..e39b77a4609a 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -60,7 +60,7 @@ static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg, /* * The Calendar Alarm register does not have a field for * the year - so these will return an invalid value. When an - * alarm is set, at91_alarm_year wille store the current year. + * alarm is set, at91_alarm_year will store the current year. */ tm->tm_year = bcd2bin(date & AT91_RTC_CENT) * 100; /* century */ tm->tm_year += bcd2bin((date & AT91_RTC_YEAR) >> 8); /* year */ diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index ca9cff85ab8a..a0fc4cf42abf 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -20,9 +20,9 @@ * write would be discarded and things quickly fall apart. * * To keep this delay from significantly degrading performance (we, in theory, - * would have to sleep for up to 1 second everytime we wanted to write a + * would have to sleep for up to 1 second every time we wanted to write a * register), we only check the write pending status before we start to issue - * a new write. We bank on the idea that it doesnt matter when the sync + * a new write. We bank on the idea that it doesn't matter when the sync * happens so long as we don't attempt another write before it does. The only * time userspace would take this penalty is when they try and do multiple * operations right after another ... but in this case, they need to take the diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index ec8701ce99f9..ae16250c762f 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -240,7 +240,7 @@ static int __devinit lpc32xx_rtc_probe(struct platform_device *pdev) spin_lock_init(&rtc->lock); /* - * The RTC is on a seperate power domain and can keep it's state + * The RTC is on a separate power domain and can keep it's state * across a chip power cycle. If the RTC has never been previously * setup, then set it up now for the first time. */ diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 9aae49139a0a..b00aad2620d4 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -573,7 +573,7 @@ static int x1205_probe(struct i2c_client *client, i2c_set_clientdata(client, rtc); - /* Check for power failures and eventualy enable the osc */ + /* Check for power failures and eventually enable the osc */ if ((err = x1205_get_status(client, &sr)) == 0) { if (sr & X1205_SR_RTCF) { dev_err(&client->dev, diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 1654a24817be..87a0cf160fe5 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2207,7 +2207,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) * DASD_3990_ERP_CONTROL_CHECK * * DESCRIPTION - * Does a generic inspection if a control check occured and sets up + * Does a generic inspection if a control check occurred and sets up * the related error recovery procedure * * PARAMETER @@ -2250,7 +2250,7 @@ dasd_3990_erp_inspect(struct dasd_ccw_req *erp) struct dasd_ccw_req *erp_new = NULL; char *sense; - /* if this problem occured on an alias retry on base */ + /* if this problem occurred on an alias retry on base */ erp_new = dasd_3990_erp_inspect_alias(erp); if (erp_new) return erp_new; @@ -2282,7 +2282,7 @@ dasd_3990_erp_inspect(struct dasd_ccw_req *erp) * DASD_3990_ERP_ADD_ERP * * DESCRIPTION - * This funtion adds an additional request block (ERP) to the head of + * This function adds an additional request block (ERP) to the head of * the given cqr (or erp). * For a command mode cqr the erp is initialized as an default erp * (retry TIC). diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index cb6a67bc89ff..42e1bf35f689 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -302,7 +302,7 @@ dasd_parse_keyword( char *parsestring ) { /* * Try to interprete the first element on the comma separated parse string * as a device number or a range of devices. If the interpretation is - * successfull, create the matching dasd_devmap entries and return a pointer + * successful, create the matching dasd_devmap entries and return a pointer * to the residual string. * If interpretation fails or in case of an error, return an error code. */ diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 459f2cbe80fc..db8005d9f2fd 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2858,7 +2858,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, /* * struct PFX_eckd_data has up to 2 byte as extended parameter * this is needed for write full track and has to be mentioned - * seperately + * separately * add 8 instead of 2 to keep 8 byte boundary */ pfx_datasize = sizeof(struct PFX_eckd_data) + 8; diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 4c023761946f..e21a5c39ef20 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -604,7 +604,7 @@ __raw3270_size_device(struct raw3270 *rp) /* * To determine the size of the 3270 device we need to do: * 1) send a 'read partition' data stream to the device - * 2) wait for the attn interrupt that preceeds the query reply + * 2) wait for the attn interrupt that precedes the query reply * 3) do a read modified to get the query reply * To make things worse we have to cope with intervention * required (3270 device switched to 'stand-by') and command diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index e090a307fdee..87cd0ab242de 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -139,7 +139,7 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) /* * If the tape isn't terminated yet, do it now. And since we then * are at the end of the tape there wouldn't be anything to read - * anyways. So we return immediatly. + * anyways. So we return immediately. */ if(device->required_tapemarks) { return tape_std_terminate_write(device); diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index d33554df2b06..2db1482b406e 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -328,7 +328,7 @@ tty3270_write_callback(struct raw3270_request *rq, void *data) tp = (struct tty3270 *) rq->view; if (rq->rc != 0) { - /* Write wasn't successfull. Refresh all. */ + /* Write wasn't successful. Refresh all. */ tp->update_flags = TTY_UPDATE_ALL; tty3270_set_timer(tp, 1); } diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index a845695ac314..6084103672b5 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -318,7 +318,7 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err) /** * ccw_device_notify() - inform the device's driver about an event - * @cdev: device for which an event occured + * @cdev: device for which an event occurred * @event: event that occurred * * Returns: @@ -688,7 +688,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { /* * No final status yet or final status not yet delivered - * to the device driver. Can't do path verfication now, + * to the device driver. Can't do path verification now, * delay until final status was delivered. */ cdev->private->flags.doverify = 1; diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 88ebd114735b..9688f3985b07 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -76,7 +76,7 @@ struct ica_z90_status { /** * Large random numbers are pulled in 4096 byte chunks from the crypto cards - * and stored in a page. Be carefull when increasing this buffer due to size + * and stored in a page. Be careful when increasing this buffer due to size * limitations for AP requests. */ #define ZCRYPT_RNG_BUFFER_SIZE 4096 diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 9feb62febb3d..da8aa75bb20b 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -779,7 +779,7 @@ claw_irq_handler(struct ccw_device *cdev, case CLAW_START_WRITE: if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { dev_info(&cdev->dev, - "%s: Unit Check Occured in " + "%s: Unit Check Occurred in " "write channel\n", dev->name); clear_bit(0, (void *)&p_ch->IO_active); if (p_ch->irb->ecw[0] & 0x80) { diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index 8c921fc3511a..2d602207541b 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -184,7 +184,7 @@ static void ctcmpc_chx_resend(fsm_instance *, int, void *); static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg); /** - * Check return code of a preceeding ccw_device call, halt_IO etc... + * Check return code of a preceding ccw_device call, halt_IO etc... * * ch : The channel, the error belongs to. * Returns the error code (!= 0) to inspect. diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 7fbc4adbb6d5..49d1cfc3217e 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1123,7 +1123,7 @@ list_modified: list_for_each_entry_safe(ipm, tmp, &card->ipm_list, list){ switch (ipm->ipm_state) { case LCS_IPM_STATE_SET_REQUIRED: - /* del from ipm_list so noone else can tamper with + /* del from ipm_list so no one else can tamper with * this entry */ list_del_init(&ipm->list); spin_unlock_irqrestore(&card->ipm_lock, flags); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 10a3a3b4dd3e..85cc53117ea6 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1107,7 +1107,7 @@ static int qeth_setup_card(struct qeth_card *card) INIT_LIST_HEAD(card->ip_tbd_list); INIT_LIST_HEAD(&card->cmd_waiter_list); init_waitqueue_head(&card->wait_q); - /* intial options */ + /* initial options */ qeth_set_intial_options(card); /* IP address takeover */ INIT_LIST_HEAD(&card->ipato.entries); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index a0e05ef65924..8512b5c0ef82 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1083,7 +1083,7 @@ static void zfcp_fsf_send_els_handler(struct zfcp_fsf_req *req) } break; case FSF_SBAL_MISMATCH: - /* should never occure, avoided in zfcp_fsf_send_els */ + /* should never occur, avoided in zfcp_fsf_send_els */ /* fall through */ default: req->status |= ZFCP_STATUS_FSFREQ_ERROR; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 8da5ed644c2b..98e97d90835b 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -391,7 +391,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) if (do_QDIO(cdev, QDIO_FLAG_SYNC_INPUT, 0, 0, QDIO_MAX_BUFFERS_PER_Q)) goto failed_qdio; - /* set index of first avalable SBALS / number of available SBALS */ + /* set index of first available SBALS / number of available SBALS */ qdio->req_q_idx = 0; atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index e8566224fe4b..6b4678a7900a 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -13,7 +13,7 @@ * TODO: Erase/program both banks of a 8MB SIMM. * * It is anticipated that programming an OS Flash will be a routine - * procedure. In the same time it is exeedingly dangerous because + * procedure. In the same time it is exceedingly dangerous because * a user can program its OBP flash with OS image and effectively * kill the machine. * diff --git a/drivers/sbus/char/max1617.h b/drivers/sbus/char/max1617.h index 0bb09c286cb4..cd30819a0a30 100644 --- a/drivers/sbus/char/max1617.h +++ b/drivers/sbus/char/max1617.h @@ -6,7 +6,7 @@ #define MAX1617_CPU_TEMP 0x01 /* Processor die temp in C */ #define MAX1617_STATUS 0x02 /* Chip status bits */ -/* Read-only versions of changable registers. */ +/* Read-only versions of changeable registers. */ #define MAX1617_RD_CFG_BYTE 0x03 /* Config register */ #define MAX1617_RD_CVRATE_BYTE 0x04 /* Temp conversion rate */ #define MAX1617_RD_AMB_HIGHLIM 0x05 /* Ambient high limit */ diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h index 3343824855d0..040f7214e5b7 100644 --- a/drivers/scsi/3w-9xxx.h +++ b/drivers/scsi/3w-9xxx.h @@ -61,7 +61,7 @@ static twa_message_type twa_aen_table[] = { {0x0000, "AEN queue empty"}, {0x0001, "Controller reset occurred"}, {0x0002, "Degraded unit detected"}, - {0x0003, "Controller error occured"}, + {0x0003, "Controller error occurred"}, {0x0004, "Background rebuild failed"}, {0x0005, "Background rebuild done"}, {0x0006, "Incomplete unit detected"}, diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 8b9f9d17e7fe..49dcf03c631a 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -8,7 +8,7 @@ Copyright (C) 1999-2010 3ware Inc. - Kernel compatiblity By: Andre Hedrick + Kernel compatibility By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick This program is free software; you can redistribute it and/or modify diff --git a/drivers/scsi/53c700.scr b/drivers/scsi/53c700.scr index a064a092c604..ec822e3b7a27 100644 --- a/drivers/scsi/53c700.scr +++ b/drivers/scsi/53c700.scr @@ -31,7 +31,7 @@ ABSOLUTE StatusAddress = 0 ; Addr to receive status return ABSOLUTE ReceiveMsgAddress = 0 ; Addr to receive msg ; ; This is the magic component for handling scatter-gather. Each of the -; SG components is preceeded by a script fragment which moves the +; SG components is preceded by a script fragment which moves the ; necessary amount of data and jumps to the next SG segment. The final ; SG segment jumps back to . However, this address is the first SG script ; segment. diff --git a/drivers/scsi/53c700_d.h_shipped b/drivers/scsi/53c700_d.h_shipped index 0b42a51257f2..aa623da333c8 100644 --- a/drivers/scsi/53c700_d.h_shipped +++ b/drivers/scsi/53c700_d.h_shipped @@ -34,7 +34,7 @@ ABSOLUTE StatusAddress = 0 ; Addr to receive status return ABSOLUTE ReceiveMsgAddress = 0 ; Addr to receive msg ; ; This is the magic component for handling scatter-gather. Each of the -; SG components is preceeded by a script fragment which moves the +; SG components is preceded by a script fragment which moves the ; necessary amount of data and jumps to the next SG segment. The final ; SG segment jumps back to . However, this address is the first SG script ; segment. diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index e40cdfb7541f..dcd716d68600 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -2509,7 +2509,7 @@ static void FPT_ssel(unsigned long port, unsigned char p_card) WR_HARPOON(port + hp_autostart_3, (SELECT + SELCHK_STRT)); - /* Setup our STATE so we know what happend when + /* Setup our STATE so we know what happened when the wheels fall off. */ currSCCB->Sccb_scsistat = SELECT_ST; @@ -2900,7 +2900,7 @@ static void FPT_SendMsg(unsigned long port, unsigned char message) * * Function: FPT_sdecm * - * Description: Determine the proper responce to the message from the + * Description: Determine the proper response to the message from the * target device. * *---------------------------------------------------------------------*/ diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index e7cd2fcbe036..165e4dd865d9 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -1198,12 +1198,12 @@ static irqreturn_t NCR5380_intr(int dummy, void *dev_id) */ if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) { - int transfered; + int transferred; if (!hostdata->connected) panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno); - transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); + transferred = (hostdata->dmalen - NCR5380_dma_residual(instance)); hostdata->connected->SCp.this_residual -= transferred; hostdata->connected->SCp.ptr += transferred; hostdata->dmalen = 0; @@ -1563,7 +1563,7 @@ failed: * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transfered or exit + * maximum number of bytes, 0 if all bytes or transferred or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. @@ -1800,7 +1800,7 @@ static int do_abort(struct Scsi_Host *host) { * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transfered or exit + * maximum number of bytes, 0 if all bytes or transferred or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 118ce83a737c..061995741444 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -747,8 +747,8 @@ char * get_container_type(unsigned tindex) * Arguments: [1] pointer to void [1] int * * Purpose: Sets SCSI inquiry data strings for vendor, product - * and revision level. Allows strings to be set in platform dependant - * files instead of in OS dependant driver source. + * and revision level. Allows strings to be set in platform dependent + * files instead of in OS dependent driver source. */ static void setinqstr(struct aac_dev *dev, void *data, int tindex) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 29ab00016b78..ffb587817efc 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1259,7 +1259,7 @@ struct aac_dev #define CACHE_UNSTABLE 2 /* - * Lets the client know at which level the data was commited on + * Lets the client know at which level the data was committed on * a write request */ diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index dd7ad3ba2dad..e7d0d47b9185 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -421,7 +421,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned))) return -EBUSY; /* - * There are 5 cases with the wait and reponse requested flags. + * There are 5 cases with the wait and response requested flags. * The only invalid cases are if the caller requests to wait and * does not request a response and if the caller does not want a * response and the Fib is not allocated from pool. If a response diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 081c6de92bc5..bfd618a69499 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -4544,7 +4544,7 @@ AscMemWordCopyPtrToLram(PortAddr iop_base, ushort s_addr, * Copy 4 bytes to LRAM. * * The source data is assumed to be in little-endian order in memory - * and is maintained in little-endian order when writen to LRAM. + * and is maintained in little-endian order when written to LRAM. */ static void AscMemDWordCopyPtrToLram(PortAddr iop_base, diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index d058f1ab82b5..1c10b796c1a2 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -461,7 +461,7 @@ static int aha1740_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *) /* The Adaptec Spec says the card is so fast that the loops will only be executed once in the code below. Even if this was true with the fastest processors when the spec was - written, it doesn't seem to be true with todays fast + written, it doesn't seem to be true with today's fast processors. We print a warning if the code is executed more often than LOOPCNT_WARN. If this happens, it should be investigated. If the count reaches LOOPCNT_MAX, we assume diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index 95ee50385188..9b059422aacb 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -473,7 +473,7 @@ struct hardware_scb { * o A residual has occurred if SG_FULL_RESID is set in sgptr, * or residual_sgptr does not have SG_LIST_NULL set. * - * o We are transfering the last segment if residual_datacnt has + * o We are transferring the last segment if residual_datacnt has * the SG_LAST_SEG flag set. * * Host: @@ -516,7 +516,7 @@ struct hardware_scb { */ /* - * Definition of a scatter/gather element as transfered to the controller. + * Definition of a scatter/gather element as transferred to the controller. * The aic7xxx chips only support a 24bit length. We use the top byte of * the length to store additional address bits and a flag to indicate * that a given segment terminates the transfer. This gives us an diff --git a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg index 0666c22ab55b..7e12c31ccfda 100644 --- a/drivers/scsi/aic7xxx/aic79xx.reg +++ b/drivers/scsi/aic7xxx/aic79xx.reg @@ -305,7 +305,7 @@ register HS_MAILBOX { } /* - * Sequencer Interupt Status + * Sequencer Interrupt Status */ register SEQINTSTAT { address 0x00C @@ -685,7 +685,7 @@ register DCHRXMSG0 { } /* - * CMC Recieve Message 0 + * CMC Receive Message 0 */ register CMCRXMSG0 { address 0x090 @@ -696,7 +696,7 @@ register CMCRXMSG0 { } /* - * Overlay Recieve Message 0 + * Overlay Receive Message 0 */ register OVLYRXMSG0 { address 0x090 @@ -732,7 +732,7 @@ register DCHRXMSG1 { } /* - * CMC Recieve Message 1 + * CMC Receive Message 1 */ register CMCRXMSG1 { address 0x091 @@ -742,7 +742,7 @@ register CMCRXMSG1 { } /* - * Overlay Recieve Message 1 + * Overlay Receive Message 1 */ register OVLYRXMSG1 { address 0x091 @@ -777,7 +777,7 @@ register DCHRXMSG2 { } /* - * CMC Recieve Message 2 + * CMC Receive Message 2 */ register CMCRXMSG2 { address 0x092 @@ -787,7 +787,7 @@ register CMCRXMSG2 { } /* - * Overlay Recieve Message 2 + * Overlay Receive Message 2 */ register OVLYRXMSG2 { address 0x092 @@ -816,7 +816,7 @@ register DCHRXMSG3 { } /* - * CMC Recieve Message 3 + * CMC Receive Message 3 */ register CMCRXMSG3 { address 0x093 @@ -826,7 +826,7 @@ register CMCRXMSG3 { } /* - * Overlay Recieve Message 3 + * Overlay Receive Message 3 */ register OVLYRXMSG3 { address 0x093 @@ -1249,7 +1249,7 @@ register TARGPCISTAT { /* * LQ Packet In - * The last LQ Packet recieved + * The last LQ Packet received */ register LQIN { address 0x020 @@ -2573,7 +2573,7 @@ register IOPDNCTL { } /* - * Shaddow Host Address. + * Shadow Host Address. */ register SHADDR { address 0x060 @@ -3983,7 +3983,7 @@ scratch_ram { /* * The maximum amount of time to wait, when interrupt coalescing - * is enabled, before issueing a CMDCMPLT interrupt for a completed + * is enabled, before issuing a CMDCMPLT interrupt for a completed * command. */ INT_COALESCING_TIMER { diff --git a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq index 2fb78e35a9e5..3a36d9362a10 100644 --- a/drivers/scsi/aic7xxx/aic79xx.seq +++ b/drivers/scsi/aic7xxx/aic79xx.seq @@ -567,7 +567,7 @@ BEGIN_CRITICAL; shr SELOID, 4, SCB_SCSIID; /* * If we want to send a message to the device, ensure - * we are selecting with atn irregardless of our packetized + * we are selecting with atn regardless of our packetized * agreement. Since SPI4 only allows target reset or PPR * messages if this is a packetized connection, the change * to our negotiation table entry for this selection will @@ -960,7 +960,7 @@ p_status_okay: * This is done to allow the host to send messages outside of an identify * sequence while protecting the seqencer from testing the MK_MESSAGE bit * on an SCB that might not be for the current nexus. (For example, a - * BDR message in responce to a bad reselection would leave us pointed to + * BDR message in response to a bad reselection would leave us pointed to * an SCB that doesn't have anything to do with the current target). * * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, @@ -1507,7 +1507,7 @@ service_fifo: * If the other FIFO needs loading, then it * must not have claimed the S/G cache yet * (SG_CACHE_AVAIL would have been cleared in - * the orginal FIFO mode and we test this above). + * the original FIFO mode and we test this above). * Return to the idle loop so we can process the * FIFO not currently on the bus first. */ @@ -1521,7 +1521,7 @@ idle_sgfetch_okay: idle_sgfetch_start: /* * We fetch a "cacheline aligned" and sized amount of data - * so we don't end up referencing a non-existant page. + * so we don't end up referencing a non-existent page. * Cacheline aligned is in quotes because the kernel will * set the prefetch amount to a reasonable level if the * cacheline size is unknown. @@ -1551,7 +1551,7 @@ idle_sg_avail: test DFSTATUS, PRELOAD_AVAIL jz return; /* * On the A, preloading a segment before HDMAENACK - * comes true can clobber the shaddow address of the + * comes true can clobber the shadow address of the * first segment in the S/G FIFO. Wait until it is * safe to proceed. */ @@ -2004,10 +2004,10 @@ pkt_handle_xfer: * Defer handling of this NONPACKREQ until we * can be sure it pertains to this FIFO. SAVEPTRS * will not be asserted if the NONPACKREQ is for us, - * so we must simulate it if shaddow is valid. If - * shaddow is not valid, keep running this FIFO until we + * so we must simulate it if shadow is valid. If + * shadow is not valid, keep running this FIFO until we * have satisfied the transfer by loading segments and - * waiting for either shaddow valid or last_seg_done. + * waiting for either shadow valid or last_seg_done. */ test MDFFSTAT, SHVALID jnz pkt_saveptrs; pkt_service_fifo: @@ -2171,7 +2171,7 @@ pkt_status_check_nonpackreq: /* * The unexpected nonpkt phase handler assumes that any * data channel use will have a FIFO reference count. It - * turns out that the status handler doesn't need a refernce + * turns out that the status handler doesn't need a references * count since the status received flag, and thus completion * processing, cannot be set until the handler is finished. * We increment the count here to make the nonpkt handler diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 3233bf564435..5f8617dd43bb 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -562,7 +562,7 @@ ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) } #endif -/*********************** Miscelaneous Support Functions ***********************/ +/*********************** Miscellaneous Support Functions ***********************/ /* * Return pointers to the transfer negotiation information * for the specified our_id/remote_id pair. @@ -599,7 +599,7 @@ void ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) { /* - * Write low byte first to accomodate registers + * Write low byte first to accommodate registers * such as PRGMCNT where the order maters. */ ahd_outb(ahd, port, value & 0xFF); @@ -2067,7 +2067,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) * that requires host assistance for completion. * While handling the message phase(s), we will be * notified by the sequencer after each byte is - * transfered so we can track bus phase changes. + * transferred so we can track bus phase changes. * * If this is the first time we've seen a HOST_MSG_LOOP * interrupt, initialize the state of the host message @@ -2487,7 +2487,7 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) /* * Although the driver does not care about the * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a successfull + * LED does. SELINGO is only cleared by a successful * selection, so we must manually clear it to insure * the LED turns off just incase no future successful * selections occur (e.g. no devices on the bus). @@ -3548,7 +3548,7 @@ ahd_clear_critical_section(struct ahd_softc *ahd) ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP); ahd_outb(ahd, SIMODE1, simode1); /* - * SCSIINT seems to glitch occassionally when + * SCSIINT seems to glitch occasionally when * the interrupt masks are restored. Clear SCSIINT * one more time so that only persistent errors * are seen as a real interrupt. @@ -3838,7 +3838,7 @@ ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, /* * Update the bitmask of targets for which the controller should - * negotiate with at the next convenient oportunity. This currently + * negotiate with at the next convenient opportunity. This currently * means the next time we send the initial identify messages for * a new transaction. */ @@ -4200,7 +4200,7 @@ ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, /* * During packetized transfers, the target will - * give us the oportunity to send command packets + * give us the opportunity to send command packets * without us asserting attention. */ if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) == 0) @@ -5651,7 +5651,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) /* * Requeue all tagged commands for this target - * currently in our posession so they can be + * currently in our possession so they can be * converted to untagged commands. */ ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), @@ -6245,7 +6245,7 @@ ahd_shutdown(void *arg) /* * Reset the controller and record some information about it * that is only available just after a reset. If "reinit" is - * non-zero, this reset occured after initial configuration + * non-zero, this reset occurred after initial configuration * and the caller requests that the chip be fully reinitialized * to a runable state. Chip interrupts are *not* enabled after * a reinitialization. The caller must enable interrupts via @@ -6495,7 +6495,7 @@ ahd_init_scbdata(struct ahd_softc *ahd) } /* - * Note that we were successfull + * Note that we were successful */ return (0); @@ -7079,7 +7079,7 @@ ahd_init(struct ahd_softc *ahd) return (ENOMEM); /* - * Verify that the compiler hasn't over-agressively + * Verify that the compiler hasn't over-aggressively * padded important structures. */ if (sizeof(struct hardware_scb) != 64) @@ -10087,7 +10087,7 @@ ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, return (error); /* - * Write the data. If we don't get throught the loop at + * Write the data. If we don't get through the loop at * least once, the arguments were invalid. */ retval = EINVAL; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 25d066624476..7d48700257a7 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1441,7 +1441,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, usertags = ahd_linux_user_tagdepth(ahd, devinfo); if (!was_queuing) { /* - * Start out agressively and allow our + * Start out aggressively and allow our * dynamic queue depth algorithm to take * care of the rest. */ diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 17444bc18bca..f695774645c1 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -440,7 +440,7 @@ struct hardware_scb { * o A residual has occurred if SG_FULL_RESID is set in sgptr, * or residual_sgptr does not have SG_LIST_NULL set. * - * o We are transfering the last segment if residual_datacnt has + * o We are transferring the last segment if residual_datacnt has * the SG_LAST_SEG flag set. * * Host: @@ -494,7 +494,7 @@ struct hardware_scb { */ /* - * Definition of a scatter/gather element as transfered to the controller. + * Definition of a scatter/gather element as transferred to the controller. * The aic7xxx chips only support a 24bit length. We use the top byte of * the length to store additional address bits and a flag to indicate * that a given segment terminates the transfer. This gives us an diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg index 9a96e55da39a..ba0b411d03e2 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.reg +++ b/drivers/scsi/aic7xxx/aic7xxx.reg @@ -351,7 +351,7 @@ register SSTAT2 { address 0x00d access_mode RO field OVERRUN 0x80 - field SHVALID 0x40 /* Shaddow Layer non-zero */ + field SHVALID 0x40 /* Shadow Layer non-zero */ field EXP_ACTIVE 0x10 /* SCSI Expander Active */ field CRCVALERR 0x08 /* CRC doesn't match (U3 only) */ field CRCENDERR 0x04 /* No terminal CRC packet (U3 only) */ diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq index 5a4cfc954a9f..e60041e8f2d1 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.seq +++ b/drivers/scsi/aic7xxx/aic7xxx.seq @@ -57,10 +57,10 @@ PREFIX = "ahc_" * a later time. This problem cannot be resolved by holding a single entry * in scratch ram since a reconnecting target can request sense and this will * create yet another SCB waiting for selection. The solution used here is to - * use byte 27 of the SCB as a psuedo-next pointer and to thread a list + * use byte 27 of the SCB as a pseudo-next pointer and to thread a list * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to - * this list everytime a request sense occurs or after completing a non-tagged + * this list every time a request sense occurs or after completing a non-tagged * command for which a second SCB has been queued. The sequencer will * automatically consume the entries. */ @@ -752,7 +752,7 @@ idle_loop: /* * We fetch a "cacheline aligned" and sized amount of data - * so we don't end up referencing a non-existant page. + * so we don't end up referencing a non-existent page. * Cacheline aligned is in quotes because the kernel will * set the prefetch amount to a reasonable level if the * cacheline size is unknown. @@ -1485,7 +1485,7 @@ p_status_okay: * This is done to allow the host to send messages outside of an identify * sequence while protecting the seqencer from testing the MK_MESSAGE bit * on an SCB that might not be for the current nexus. (For example, a - * BDR message in responce to a bad reselection would leave us pointed to + * BDR message in response to a bad reselection would leave us pointed to * an SCB that doesn't have anything to do with the current target). * * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, @@ -1999,7 +1999,7 @@ if ((ahc->flags & AHC_TARGETROLE) != 0) { * from out to in, wait an additional data release delay before continuing. */ change_phase: - /* Wait for preceeding I/O session to complete. */ + /* Wait for preceding I/O session to complete. */ test SCSISIGI, ACKI jnz .; /* Change the phase */ diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index e021b4812d58..dc28b0a91b22 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -427,7 +427,7 @@ ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index) } #endif -/*********************** Miscelaneous Support Functions ***********************/ +/*********************** Miscellaneous Support Functions ***********************/ /* * Determine whether the sequencer reported a residual * for this SCB/transaction. @@ -1243,7 +1243,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * that requires host assistance for completion. * While handling the message phase(s), we will be * notified by the sequencer after each byte is - * transfered so we can track bus phase changes. + * transferred so we can track bus phase changes. * * If this is the first time we've seen a HOST_MSG_LOOP * interrupt, initialize the state of the host message @@ -1487,7 +1487,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) scbptr, ahc_inb(ahc, ARG_1), ahc->scb_data->hscbs[scbptr].tag); ahc_dump_card_state(ahc); - panic("for saftey"); + panic("for safety"); break; } case OUT_OF_RANGE: @@ -1733,7 +1733,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) /* * Although the driver does not care about the * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a successfull + * LED does. SELINGO is only cleared by a successful * selection, so we must manually clear it to insure * the LED turns off just incase no future successful * selections occur (e.g. no devices on the bus). @@ -1943,7 +1943,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) if (lastphase != P_BUSFREE) { /* * Renegotiate with this device at the - * next oportunity just in case this busfree + * next opportunity just in case this busfree * is due to a negotiation mismatch with the * device. */ @@ -2442,7 +2442,7 @@ ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, /* * Update the bitmask of targets for which the controller should - * negotiate with at the next convenient oportunity. This currently + * negotiate with at the next convenient opportunity. This currently * means the next time we send the initial identify messages for * a new transaction. */ @@ -4131,7 +4131,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) /* * Requeue all tagged commands for this target - * currently in our posession so they can be + * currently in our possession so they can be * converted to untagged commands. */ ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), @@ -4581,7 +4581,7 @@ ahc_shutdown(void *arg) /* * Reset the controller and record some information about it * that is only available just after a reset. If "reinit" is - * non-zero, this reset occured after initial configuration + * non-zero, this reset occurred after initial configuration * and the caller requests that the chip be fully reinitialized * to a runable state. Chip interrupts are *not* enabled after * a reinitialization. The caller must enable interrupts via @@ -4899,7 +4899,7 @@ ahc_init_scbdata(struct ahc_softc *ahc) ahc->next_queued_scb = ahc_get_scb(ahc); /* - * Note that we were successfull + * Note that we were successful */ return (0); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 4a359bb307c6..c6251bb4f438 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -294,7 +294,7 @@ static uint32_t aic7xxx_extended; * dubious at best. To my knowledge, this option has never actually * solved a PCI parity problem, but on certain machines with broken PCI * chipset configurations where stray PCI transactions with bad parity are - * the norm rather than the exception, the error messages can be overwelming. + * the norm rather than the exception, the error messages can be overwhelming. * It's included in the driver for completeness. * 0 = Shut off PCI parity check * non-0 = reverse polarity pci parity checking @@ -1318,7 +1318,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, usertags = ahc_linux_user_tagdepth(ahc, devinfo); if (!was_queuing) { /* - * Start out agressively and allow our + * Start out aggressively and allow our * dynamic queue depth algorithm to take * care of the rest. */ diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index 2b11a4272364..6917b4f5ac9e 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -789,7 +789,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) ahc->bus_intr = ahc_pci_intr; ahc->bus_chip_init = ahc_pci_chip_init; - /* Remeber how the card was setup in case there is no SEEPROM */ + /* Remember how the card was setup in case there is no SEEPROM */ if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { ahc_pause(ahc); if ((ahc->features & AHC_ULTRA2) != 0) @@ -860,7 +860,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) } /* - * We cannot perform ULTRA speeds without the presense + * We cannot perform ULTRA speeds without the presence * of the external precision resistor. */ if ((ahc->features & AHC_ULTRA) != 0) { @@ -969,7 +969,7 @@ ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) } /* - * Test for the presense of external sram in an + * Test for the presence of external sram in an * "unshared" configuration. */ static int diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y index e4064433842e..f1586a437906 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y @@ -803,7 +803,7 @@ macro_arglist: | macro_arglist ',' T_ARG { if ($1 == 0) { - stop("Comma without preceeding argument in arg list", + stop("Comma without preceding argument in arg list", EX_DATAERR); /* NOTREACHED */ } @@ -1319,8 +1319,8 @@ code: ; /* - * This grammer differs from the one in the aic7xxx - * reference manual since the grammer listed there is + * This grammar differs from the one in the aic7xxx + * reference manual since the grammar listed there is * ambiguous and causes a shift/reduce conflict. * It also seems more logical as the "immediate" * argument is listed as the second arg like the @@ -1799,7 +1799,7 @@ format_3_instr(int opcode, symbol_ref_t *src, instr = seq_alloc(); f3_instr = &instr->format.format3; if (address->symbol == NULL) { - /* 'dot' referrence. Use the current instruction pointer */ + /* 'dot' reference. Use the current instruction pointer */ addr = instruction_ptr + address->offset; } else if (address->symbol->type == UNINITIALIZED) { /* forward reference */ diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y index ff46aa6801bf..708326df0766 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y @@ -115,7 +115,7 @@ macro_arglist: | macro_arglist ',' T_ARG { if ($1 == 0) { - stop("Comma without preceeding argument in arg list", + stop("Comma without preceding argument in arg list", EX_DATAERR); /* NOTREACHED */ } diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 4ff60a08df0f..5b212f0df898 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -905,7 +905,7 @@ struct aic_dev_data { * problems with architectures I can't test on (because I don't have one, * such as the Alpha based systems) which happen to give faults for * non-aligned memory accesses, care was taken to align this structure - * in a way that gauranteed all accesses larger than 8 bits were aligned + * in a way that guaranteed all accesses larger than 8 bits were aligned * on the appropriate boundary. It's also organized to try and be more * cache line efficient. Be careful when changing this lest you might hurt * overall performance and bring down the wrath of the masses. @@ -1180,7 +1180,7 @@ static int aic7xxx_pci_parity = 0; * the card's registers in a hex dump format tailored to each model of * controller. * - * NOTE: THE CONTROLLER IS LEFT IN AN UNUSEABLE STATE BY THIS OPTION. + * NOTE: THE CONTROLLER IS LEFT IN AN UNUSABLE STATE BY THIS OPTION. * YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES * ONLY */ @@ -3467,7 +3467,7 @@ aic7xxx_reset_current_bus(struct aic7xxx_host *p) /* Turn off the bus' current operations, after all, we shouldn't have any * valid commands left to cause a RSELI and SELO once we've tossed the * bus away with this reset, so we might as well shut down the sequencer - * until the bus is restarted as oppossed to saving the current settings + * until the bus is restarted as opposed to saving the current settings * and restoring them (which makes no sense to me). */ /* Turn on the bus reset. */ @@ -4070,7 +4070,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) aic_dev->max_q_depth = aic_dev->temp_q_depth = 1; /* * We set this command up as a bus device reset. However, we have - * to clear the tag type as it's causing us problems. We shouldnt + * to clear the tag type as it's causing us problems. We shouldn't * have to worry about any other commands being active, since if * the device is refusing tagged commands, this should be the * first tagged command sent to the device, however, we do have @@ -9748,7 +9748,7 @@ skip_pci_controller: } /* - * We are commited now, everything has been checked and this card + * We are committed now, everything has been checked and this card * has been found, now we just set it up */ @@ -9906,7 +9906,7 @@ skip_pci_controller: * 2: All PCI controllers with BIOS_ENABLED next, according to BIOS * address, going from lowest to highest. * 3: Remaining VLB/EISA controllers going in slot order. - * 4: Remaining PCI controllers, going in PCI device order (reversable) + * 4: Remaining PCI controllers, going in PCI device order (reversible) */ { diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.seq b/drivers/scsi/aic7xxx_old/aic7xxx.seq index 1565be9ebd49..823ff2873229 100644 --- a/drivers/scsi/aic7xxx_old/aic7xxx.seq +++ b/drivers/scsi/aic7xxx_old/aic7xxx.seq @@ -51,7 +51,7 @@ * use byte 27 of the SCB as a pseudo-next pointer and to thread a list * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to - * this list everytime a request sense occurs or after completing a non-tagged + * this list every time a request sense occurs or after completing a non-tagged * command for which a second SCB has been queued. The sequencer will * automatically consume the entries. */ @@ -696,7 +696,7 @@ p_status: * This is done to allow the hsot to send messages outside of an identify * sequence while protecting the seqencer from testing the MK_MESSAGE bit * on an SCB that might not be for the current nexus. (For example, a - * BDR message in responce to a bad reselection would leave us pointed to + * BDR message in response to a bad reselection would leave us pointed to * an SCB that doesn't have anything to do with the current target). * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, * bus device reset). @@ -716,8 +716,8 @@ p_mesgout_identify: } else { and SINDEX,0x7,SCB_TCL; /* lun */ } - and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */ - or SINDEX,A; /* or in disconnect privledge */ + and A,DISCENB,SCB_CONTROL; /* mask off disconnect privilege */ + or SINDEX,A; /* or in disconnect privilege */ or SINDEX,MSG_IDENTIFYFLAG; p_mesgout_mk_message: test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag; diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h index 40273a747d29..dd6cc8008b16 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h @@ -2134,7 +2134,7 @@ * The host accesses this scratch in a different manner from the * link sequencer. The sequencer has to use LSEQ registers * LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat -* mapping of the scratch memory is avaliable for software +* mapping of the scratch memory is available for software * convenience and to prevent corruption while the sequencer is * running. This memory is mapped onto addresses 800h - 9FFh. * diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index ec166726b314..c454e44cf51c 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -100,7 +100,7 @@ */ #define TIMEOUT_TIME 10 /* - * Define this if you want to have verbose explaination of SCSI + * Define this if you want to have verbose explanation of SCSI * status/messages. */ #undef CONFIG_ACORNSCSI_CONSTANTS @@ -1561,7 +1561,7 @@ void acornscsi_message(AS_Host *host) /* * If we were negociating sync transfer, we don't yet know if * this REJECT is for the sync transfer or for the tagged queue/wide - * transfer. Re-initiate sync transfer negociation now, and if + * transfer. Re-initiate sync transfer negotiation now, and if * we got a REJECT in response to SDTR, then it'll be set to DONE. */ if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h index 8d2172a0b351..01bc715a3aec 100644 --- a/drivers/scsi/arm/acornscsi.h +++ b/drivers/scsi/arm/acornscsi.h @@ -223,8 +223,8 @@ typedef enum { * Synchronous transfer state */ typedef enum { /* Synchronous transfer state */ - SYNC_ASYNCHRONOUS, /* don't negociate synchronous transfers*/ - SYNC_NEGOCIATE, /* start negociation */ + SYNC_ASYNCHRONOUS, /* don't negotiate synchronous transfers*/ + SYNC_NEGOCIATE, /* start negotiation */ SYNC_SENT_REQUEST, /* sent SDTR message */ SYNC_COMPLETED, /* received SDTR reply */ } syncxfer_t; @@ -322,7 +322,7 @@ typedef struct acornscsi_hostdata { /* per-device info */ struct { unsigned char sync_xfer; /* synchronous transfer (SBIC value) */ - syncxfer_t sync_state; /* sync xfer negociation state */ + syncxfer_t sync_state; /* sync xfer negotiation state */ unsigned char disconnect_ok:1; /* device can disconnect */ } device[8]; unsigned long busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy */ diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c index 2836fe248df9..a750aa72b8ef 100644 --- a/drivers/scsi/arm/arxescsi.c +++ b/drivers/scsi/arm/arxescsi.c @@ -228,7 +228,7 @@ static const char *arxescsi_info(struct Scsi_Host *host) * Params : buffer - a buffer to write information to * start - a pointer into this buffer set by this routine to the start * of the required information. - * offset - offset into information that we have read upto. + * offset - offset into information that we have read up to. * length - length of buffer * host_no - host number to return information for * inout - 0 for reading, 1 for writing. diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index c9902b5c1f2b..547987b86384 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -344,7 +344,7 @@ cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length) * Params : buffer - a buffer to write information to * start - a pointer into this buffer set by this routine to the start * of the required information. - * offset - offset into information that we have read upto. + * offset - offset into information that we have read up to. * length - length of buffer * host_no - host number to return information for * inout - 0 for reading, 1 for writing. diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index d8435132f461..edfd12b48c28 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -429,7 +429,7 @@ eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) * Params : buffer - a buffer to write information to * start - a pointer into this buffer set by this routine to the start * of the required information. - * offset - offset into information that we have read upto. + * offset - offset into information that we have read up to. * length - length of buffer * host_no - host number to return information for * inout - 0 for reading, 1 for writing. diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 2b2ce21e227e..e85c40b6e19b 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2119,7 +2119,7 @@ request_sense: * executed, unless a target connects to us. */ if (info->reqSCpnt) - printk(KERN_WARNING "scsi%d.%c: loosing request command\n", + printk(KERN_WARNING "scsi%d.%c: losing request command\n", info->host->host_no, '0' + SCpnt->device->id); info->reqSCpnt = SCpnt; } @@ -2294,7 +2294,7 @@ static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt, * If we don't have an IRQ, then we must poll the card for * it's interrupt, and use that to call this driver's * interrupt routine. That way, we keep the command - * progressing. Maybe we can add some inteligence here + * progressing. Maybe we can add some intelligence here * and go to sleep if we know that the device is going * to be some time (eg, disconnected). */ diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index f30f8d659dc4..84b7127c0121 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -203,11 +203,11 @@ typedef enum { } fasdmatype_t; typedef enum { - neg_wait, /* Negociate with device */ - neg_inprogress, /* Negociation sent */ - neg_complete, /* Negociation complete */ - neg_targcomplete, /* Target completed negociation */ - neg_invalid /* Negociation not supported */ + neg_wait, /* Negotiate with device */ + neg_inprogress, /* Negotiation sent */ + neg_complete, /* Negotiation complete */ + neg_targcomplete, /* Target completed negotiation */ + neg_invalid /* Negotiation not supported */ } neg_t; #define MAGIC 0x441296bdUL diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index e2297b4c1b9e..9274c0677b9c 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -232,7 +232,7 @@ powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) * Params : buffer - a buffer to write information to * start - a pointer into this buffer set by this routine to the start * of the required information. - * offset - offset into information that we have read upto. + * offset - offset into information that we have read up to. * length - length of buffer * inout - 0 for reading, 1 for writing. * Returns : length of data written to buffer. diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 88b2928b4d3b..ea439f93ed81 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -464,7 +464,7 @@ static void free_all_tags(void) * * Parameters: Scsi_Cmnd *cmd * The command to work on. The first scatter buffer's data are - * assumed to be already transfered into ptr/this_residual. + * assumed to be already transferred into ptr/this_residual. */ static void merge_contiguous_buffers(Scsi_Cmnd *cmd) @@ -1720,7 +1720,7 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes are transfered or exit + * maximum number of bytes, 0 if all bytes are transferred or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. @@ -1911,7 +1911,7 @@ static int do_abort(struct Scsi_Host *host) * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transfered or exit + * maximum number of bytes, 0 if all bytes or transferred or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 76029d570beb..7e6eca4a125e 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1228,7 +1228,7 @@ TCM_5: /* isolation complete.. */ printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */ i = 15; j = mbuf[0]; - if ((j & 0x20) != 0) { /* bit5=1:ID upto 7 */ + if ((j & 0x20) != 0) { /* bit5=1:ID up to 7 */ i = 7; } if ((j & 0x06) == 0) { /* IDvalid? */ diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index 5218de4ab35a..fbd1dc2c15f7 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -877,7 +877,7 @@ struct be_all_if_id { */ #define CXN_KILLED_PDU_SIZE_EXCEEDS_DSL 3 /* Connection got invalidated * internally - * due to a recieved PDU + * due to a received PDU * size > DSL */ #define CXN_KILLED_BURST_LEN_MISMATCH 4 /* Connection got invalidated @@ -886,7 +886,7 @@ struct be_all_if_id { * FBL/MBL. */ #define CXN_KILLED_AHS_RCVD 5 /* Connection got invalidated - * internally due to a recieved + * internally due to a received * PDU Hdr that has * AHS */ #define CXN_KILLED_HDR_DIGEST_ERR 6 /* Connection got invalidated @@ -899,12 +899,12 @@ struct be_all_if_id { * pdu hdr */ #define CXN_KILLED_STALE_ITT_TTT_RCVD 8 /* Connection got invalidated - * internally due to a recieved + * internally due to a received * ITT/TTT that does not belong * to this Connection */ #define CXN_KILLED_INVALID_ITT_TTT_RCVD 9 /* Connection got invalidated - * internally due to recieved + * internally due to received * ITT/TTT value > Max * Supported ITTs/TTTs */ @@ -936,21 +936,21 @@ struct be_all_if_id { * index. */ #define CXN_KILLED_OVER_RUN_RESIDUAL 16 /* Command got invalidated - * internally due to recived + * internally due to received * command has residual * over run bytes. */ #define CXN_KILLED_UNDER_RUN_RESIDUAL 17 /* Command got invalidated - * internally due to recived + * internally due to received * command has residual under * run bytes. */ #define CMD_KILLED_INVALID_STATSN_RCVD 18 /* Command got invalidated - * internally due to a recieved + * internally due to a received * PDU has an invalid StatusSN */ #define CMD_KILLED_INVALID_R2T_RCVD 19 /* Command got invalidated - * internally due to a recieved + * internally due to a received * an R2T with some invalid * fields in it */ @@ -973,7 +973,7 @@ struct be_all_if_id { */ #define CMD_CXN_KILLED_INVALID_DATASN_RCVD 24 /* Command got invalidated * internally due to a - * recieved PDU has an invalid + * received PDU has an invalid * DataSN */ #define CXN_INVALIDATE_NOTIFY 25 /* Connection invalidation diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c index 1cd5c8b0618d..91838c51fb76 100644 --- a/drivers/scsi/bfa/bfa_core.c +++ b/drivers/scsi/bfa/bfa_core.c @@ -355,7 +355,7 @@ bfa_msix_lpu_err(struct bfa_s *bfa, int vec) /* * ERR_PSS bit needs to be cleared as well in case * interrups are shared so driver's interrupt handler is - * still called eventhough it is already masked out. + * still called even though it is already masked out. */ curr_value = readl( bfa->ioc.ioc_regs.pss_err_status_reg); diff --git a/drivers/scsi/bfa/bfa_defs_svc.h b/drivers/scsi/bfa/bfa_defs_svc.h index 648c84176722..207f598877c7 100644 --- a/drivers/scsi/bfa/bfa_defs_svc.h +++ b/drivers/scsi/bfa/bfa_defs_svc.h @@ -145,7 +145,7 @@ struct bfa_fw_io_stats_s { u32 ioh_data_oor_event; /* Data out of range */ u32 ioh_ro_ooo_event; /* Relative offset out of range */ u32 ioh_cpu_owned_event; /* IOH hit -iost owned by f/w */ - u32 ioh_unexp_frame_event; /* unexpected frame recieved + u32 ioh_unexp_frame_event; /* unexpected frame received * count */ u32 ioh_err_int; /* IOH error int during data-phase * for scsi write @@ -566,8 +566,8 @@ struct bfa_itnim_iostats_s { u32 input_reqs; /* Data in-bound requests */ u32 output_reqs; /* Data out-bound requests */ u32 io_comps; /* Total IO Completions */ - u32 wr_throughput; /* Write data transfered in bytes */ - u32 rd_throughput; /* Read data transfered in bytes */ + u32 wr_throughput; /* Write data transferred in bytes */ + u32 rd_throughput; /* Read data transferred in bytes */ u32 iocomp_ok; /* Slowpath IO completions */ u32 iocomp_underrun; /* IO underrun */ diff --git a/drivers/scsi/bfa/bfa_fc.h b/drivers/scsi/bfa/bfa_fc.h index 8e764fae8dc9..bf0067e0fd0d 100644 --- a/drivers/scsi/bfa/bfa_fc.h +++ b/drivers/scsi/bfa/bfa_fc.h @@ -315,7 +315,7 @@ struct fc_plogi_csp_s { query_dbc:1, hg_supp:1; #endif - __be16 rxsz; /* recieve data_field size */ + __be16 rxsz; /* receive data_field size */ __be16 conseq; __be16 ro_bitmap; __be32 e_d_tov; diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c index f674f9318629..9b43ca4b6778 100644 --- a/drivers/scsi/bfa/bfa_fcs.c +++ b/drivers/scsi/bfa/bfa_fcs.c @@ -1033,7 +1033,7 @@ bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, /* - * Lookup for a vport withing a fabric given its pwwn + * Lookup for a vport within a fabric given its pwwn */ struct bfa_fcs_vport_s * bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn) diff --git a/drivers/scsi/bfa/bfa_fcs.h b/drivers/scsi/bfa/bfa_fcs.h index 0fd63168573f..61cdce4bd913 100644 --- a/drivers/scsi/bfa/bfa_fcs.h +++ b/drivers/scsi/bfa/bfa_fcs.h @@ -705,7 +705,7 @@ enum rport_event { RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */ RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */ RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ - RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continously */ + RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continuously */ }; /* diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c index 43fa986bb586..1d6be8c14473 100644 --- a/drivers/scsi/bfa/bfa_fcs_lport.c +++ b/drivers/scsi/bfa/bfa_fcs_lport.c @@ -1149,7 +1149,7 @@ bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi, } else { /* * For a base port, we should first register the HBA - * atribute. The HBA attribute also contains the base + * attribute. The HBA attribute also contains the base * port registration. */ bfa_sm_set_state(fdmi, diff --git a/drivers/scsi/bfa/bfa_svc.c b/drivers/scsi/bfa/bfa_svc.c index 1d34921f88bf..16d9a5f61c18 100644 --- a/drivers/scsi/bfa/bfa_svc.c +++ b/drivers/scsi/bfa/bfa_svc.c @@ -1035,7 +1035,7 @@ bfa_fcxp_free(struct bfa_fcxp_s *fcxp) * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports * @param[in] vf_id virtual Fabric ID * @param[in] lp_tag lport tag - * @param[in] cts use Continous sequence + * @param[in] cts use Continuous sequence * @param[in] cos fc Class of Service * @param[in] reqlen request length, does not include FCHS length * @param[in] fchs fc Header Pointer. The header content will be copied @@ -5022,7 +5022,7 @@ bfa_uf_start(struct bfa_s *bfa) } /* - * Register handler for all unsolicted recieve frames. + * Register handler for all unsolicted receive frames. * * @param[in] bfa BFA instance * @param[in] ufrecv receive handler function diff --git a/drivers/scsi/bfa/bfa_svc.h b/drivers/scsi/bfa/bfa_svc.h index 331ad992a581..5902a45c080f 100644 --- a/drivers/scsi/bfa/bfa_svc.h +++ b/drivers/scsi/bfa/bfa_svc.h @@ -127,7 +127,7 @@ struct bfa_fcxp_req_info_s { * rport nexus is established */ struct fchs_s fchs; /* request FC header structure */ - u8 cts; /* continous sequence */ + u8 cts; /* continuous sequence */ u8 class; /* FC class for the request/response */ u16 max_frmsz; /* max send frame size */ u16 vf_id; /* vsan tag if applicable */ diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 44524cf55d33..0fd510a01561 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1278,7 +1278,7 @@ bfad_setup_intr(struct bfad_s *bfad) * interrupts into one vector, so even if we * can try to request less vectors, we don't * know how to associate interrupt events to - * vectors. Linux doesn't dupicate vectors + * vectors. Linux doesn't duplicate vectors * in the MSIX table for this case. */ diff --git a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h index 69d031d98469..97a61b4d81b7 100644 --- a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h +++ b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h @@ -898,7 +898,7 @@ struct fcoe_confqe { /* - * FCoE conection data base + * FCoE connection data base */ struct fcoe_conn_db { #if defined(__BIG_ENDIAN) diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index 7a11a255157f..52c358427ce2 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -397,7 +397,7 @@ void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, &els_req->req_flags)) { BNX2FC_ELS_DBG("Timer context finished processing this " "els - 0x%x\n", els_req->xid); - /* This IO doesnt receive cleanup completion */ + /* This IO doesn't receive cleanup completion */ kref_put(&els_req->refcount, bnx2fc_cmd_release); return; } diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index d3fc302c241a..1decefbf32e3 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1273,7 +1273,7 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) bnx2fc_cmd_release); /* timer hold */ rc = bnx2fc_initiate_abts(cmd); - /* abts shouldnt fail in this context */ + /* abts shouldn't fail in this context */ WARN_ON(rc != SUCCESS); } else printk(KERN_ERR PFX "lun_rst: abts already in" @@ -1308,7 +1308,7 @@ static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req) kref_put(&io_req->refcount, bnx2fc_cmd_release); /* timer hold */ rc = bnx2fc_initiate_abts(cmd); - /* abts shouldnt fail in this context */ + /* abts shouldn't fail in this context */ WARN_ON(rc != SUCCESS); } else diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index 7cc05e4e82d5..a2e3830bd268 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -395,7 +395,7 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport, rp = rport->dd_data; if (rport->port_id == FC_FID_DIR_SERV) { /* - * bnx2fc_rport structure doesnt exist for + * bnx2fc_rport structure doesn't exist for * directory server. * We should not come here, as lport will * take care of fabric login diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index 1da34c019b8a..f0b89513faed 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -173,7 +173,7 @@ void bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) /** * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer - * @conn: iscsi connection on which RQ event occured + * @conn: iscsi connection on which RQ event occurred * @ptr: driver buffer to which RQ buffer contents is to * be copied * @len: length of valid data inside RQ buf diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 0a20fd5f7102..9267844519c9 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -262,9 +262,9 @@ struct cxgbi_skb_tx_cb { enum cxgbi_skcb_flags { SKCBF_TX_NEED_HDR, /* packet needs a header */ SKCBF_RX_COALESCED, /* received whole pdu */ - SKCBF_RX_HDR, /* recieved pdu header */ - SKCBF_RX_DATA, /* recieved pdu payload */ - SKCBF_RX_STATUS, /* recieved ddp status */ + SKCBF_RX_HDR, /* received pdu header */ + SKCBF_RX_DATA, /* received pdu payload */ + SKCBF_RX_STATUS, /* received ddp status */ SKCBF_RX_DATA_DDPD, /* pdu payload ddp'd */ SKCBF_RX_HCRC_ERR, /* header digest error */ SKCBF_RX_DCRC_ERR, /* data digest error */ diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index b0f8523e665f..b10b3841535c 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -235,7 +235,7 @@ struct ScsiReqBlk { u8 sg_count; /* No of HW sg entries for this request */ u8 sg_index; /* Index of HW sg entry for this request */ - size_t total_xfer_length; /* Total number of bytes remaining to be transfered */ + size_t total_xfer_length; /* Total number of bytes remaining to be transferred */ size_t request_length; /* Total number of bytes in this request */ /* * The sense buffer handling function, request_sense, uses @@ -1774,7 +1774,7 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, dc395x_statev(acb, srb, &scsi_status); /* - * if there were any exception occured scsi_status + * if there were any exception occurred scsi_status * will be modify to bus free phase new scsi_status * transfer out from ... previous dc395x_statev */ @@ -1954,11 +1954,11 @@ static void sg_verify_length(struct ScsiReqBlk *srb) static void sg_update_list(struct ScsiReqBlk *srb, u32 left) { u8 idx; - u32 xferred = srb->total_xfer_length - left; /* bytes transfered */ + u32 xferred = srb->total_xfer_length - left; /* bytes transferred */ struct SGentry *psge = srb->segment_x + srb->sg_index; dprintkdbg(DBG_0, - "sg_update_list: Transfered %i of %i bytes, %i remain\n", + "sg_update_list: Transferred %i of %i bytes, %i remain\n", xferred, srb->total_xfer_length, left); if (xferred == 0) { /* nothing to update since we did not transfer any data */ @@ -1990,7 +1990,7 @@ static void sg_update_list(struct ScsiReqBlk *srb, u32 left) /* - * We have transfered a single byte (PIO mode?) and need to update + * We have transferred a single byte (PIO mode?) and need to update * the count of bytes remaining (total_xfer_length) and update the sg * entry to either point to next byte in the current sg entry, or of * already at the end to point to the start of the next sg entry @@ -2029,7 +2029,7 @@ static void cleanup_after_transfer(struct AdapterCtlBlk *acb, /* - * Those no of bytes will be transfered w/ PIO through the SCSI FIFO + * Those no of bytes will be transferred w/ PIO through the SCSI FIFO * Seems to be needed for unknown reasons; could be a hardware bug :-( */ #define DC395x_LASTPIO 4 @@ -2256,7 +2256,7 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, DC395x_read32(acb, TRM_S1040_DMA_CXCNT), srb->total_xfer_length, d_left_counter); #if DC395x_LASTPIO - /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */ + /* KG: Less than or equal to 4 bytes can not be transferred via DMA, it seems. */ if (d_left_counter && srb->total_xfer_length <= DC395x_LASTPIO) { size_t left_io = srb->total_xfer_length; diff --git a/drivers/scsi/dc395x.h b/drivers/scsi/dc395x.h index b38360e5fe4f..fbf35e37701e 100644 --- a/drivers/scsi/dc395x.h +++ b/drivers/scsi/dc395x.h @@ -617,7 +617,7 @@ struct ScsiInqData #define NTC_DO_SEND_START 0x08 /* Send start command SPINUP */ #define NTC_DO_DISCONNECT 0x04 /* Enable SCSI disconnect */ #define NTC_DO_SYNC_NEGO 0x02 /* Sync negotiation */ -#define NTC_DO_PARITY_CHK 0x01 /* (it sould define at NAC) */ +#define NTC_DO_PARITY_CHK 0x01 /* (it should define at NAC) */ /* Parity check enable */ /************************************************************************/ diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 7cae0bc85390..42fe52902add 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -541,7 +541,7 @@ static int alua_check_sense(struct scsi_device *sdev, * * Evaluate the Target Port Group State. * Returns SCSI_DH_DEV_OFFLINED if the path is - * found to be unuseable. + * found to be unusable. */ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) { @@ -620,7 +620,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) break; case TPGS_STATE_OFFLINE: case TPGS_STATE_UNAVAILABLE: - /* Path unuseable for unavailable/offline */ + /* Path unusable for unavailable/offline */ err = SCSI_DH_DEV_OFFLINED; break; default: diff --git a/drivers/scsi/dpt/sys_info.h b/drivers/scsi/dpt/sys_info.h index a90c4cb8ea8b..a4aa1c31ff72 100644 --- a/drivers/scsi/dpt/sys_info.h +++ b/drivers/scsi/dpt/sys_info.h @@ -79,9 +79,9 @@ typedef struct { #endif - uSHORT cylinders; /* Upto 1024 */ - uCHAR heads; /* Upto 255 */ - uCHAR sectors; /* Upto 63 */ + uSHORT cylinders; /* Up to 1024 */ + uCHAR heads; /* Up to 255 */ + uCHAR sectors; /* Up to 63 */ #ifdef __cplusplus diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 53925ac178fd..0eb4fe6a4c8a 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -63,7 +63,7 @@ * ep:[y|n] eisa_probe=[1|0] CONFIG_EISA defined * pp:[y|n] pci_probe=[1|0] CONFIG_PCI defined * - * The default action is to perform probing if the corrisponding + * The default action is to perform probing if the corresponding * bus is configured and to skip probing otherwise. * * + If pci_probe is in effect and a list of I/O ports is specified diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index c93f007e702f..9d38be2a41f9 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -656,7 +656,7 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, * If non-FIP, we may have gotten an SID by accepting an FLOGI * from a point-to-point connection. Switch to using * the source mac based on the SID. The destination - * MAC in this case would have been set by receving the + * MAC in this case would have been set by receiving the * FLOGI. */ if (fip->state == FIP_ST_NON_FIP) { @@ -1876,7 +1876,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, * fcoe_ctlr_vn_rport_callback - Event handler for rport events. * @lport: The lport which is receiving the event * @rdata: remote port private data - * @event: The event that occured + * @event: The event that occurred * * Locking Note: The rport lock must not be held when calling this function. */ diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 69b7aa54f43f..643f6d500fe7 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -174,7 +174,7 @@ Future Domain sold DOS BIOS source for $250 and the UN*X driver source was $750, but these required a non-disclosure agreement, so even if I could have afforded them, they would *not* have been useful for writing this - publically distributable driver. Future Domain technical support has + publicly distributable driver. Future Domain technical support has provided some information on the phone and have sent a few useful FAXs. They have been much more helpful since they started to recognize that the word "Linux" refers to an operating system :-). diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 2b48d79bad94..3c53c3478ee7 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -411,7 +411,7 @@ int fnic_rq_cmpl_handler(struct fnic *fnic, int rq_work_to_do) err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); if (err) shost_printk(KERN_ERR, fnic->lport->host, - "fnic_alloc_rq_frame cant alloc" + "fnic_alloc_rq_frame can't alloc" " frame\n"); } tot_rq_work_done += cur_work_done; diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 22d02404d15f..538b31c2cf58 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1123,7 +1123,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) fc_lun.scsi_lun, io_req)) { /* * Revert the cmd state back to old state, if - * it hasnt changed in between. This cmd will get + * it hasn't changed in between. This cmd will get * aborted later by scsi_eh, or cleaned up during * lun reset */ @@ -1208,7 +1208,7 @@ void fnic_terminate_rport_io(struct fc_rport *rport) fc_lun.scsi_lun, io_req)) { /* * Revert the cmd state back to old state, if - * it hasnt changed in between. This cmd will get + * it hasn't changed in between. This cmd will get * aborted later by scsi_eh, or cleaned up during * lun reset */ diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 427a56d3117e..81182badfeb1 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -566,7 +566,7 @@ generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev, * @dst: buffer to read into * @len: buffer length * - * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * Perform a pseudo DMA mode read from an NCR53C400 or equivalent * controller */ @@ -650,7 +650,7 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, * @dst: buffer to read into * @len: buffer length * - * Perform a psuedo DMA mode read from an NCR53C400 or equivalent + * Perform a pseudo DMA mode read from an NCR53C400 or equivalent * controller */ diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 120a0625a7b5..d969855ac64a 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -895,7 +895,7 @@ typedef struct { u8 ldr_no; /* log. drive no. */ u8 rw_attribs; /* r/w attributes */ u8 cluster_type; /* cluster properties */ - u8 media_changed; /* Flag:MOUNT/UNMOUNT occured */ + u8 media_changed; /* Flag:MOUNT/UNMOUNT occurred */ u32 start_sec; /* start sector */ } hdr[MAX_LDRIVES]; /* host drives */ struct { diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 2ce26eb7a1ec..50bb54150a78 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -300,7 +300,7 @@ static int __devinit gvp11_probe(struct zorro_dev *z, /* * Rumors state that some GVP ram boards use the same product * code as the SCSI controllers. Therefore if the board-size - * is not 64KB we asume it is a ram board and bail out. + * is not 64KB we assume it is a ram board and bail out. */ if (zorro_resource_len(z) != 0x10000) return -ENODEV; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 99aa0e5699bc..26cd9d1d7571 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -3,7 +3,7 @@ * * (The IMM is the embedded controller in the ZIP Plus drive.) * - * My unoffical company acronym list is 21 pages long: + * My unofficial company acronym list is 21 pages long: * FLA: Four letter acronym with built in facility for * future expansion to five letters. */ diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 9627d062e16b..dd741bcd6ccd 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -242,7 +242,7 @@ static u8 i91udftNvRam[64] = static u8 initio_rate_tbl[8] = /* fast 20 */ { - /* nanosecond devide by 4 */ + /* nanosecond divide by 4 */ 12, /* 50ns, 20M */ 18, /* 75ns, 13.3M */ 25, /* 100ns, 10M */ @@ -1917,7 +1917,7 @@ static int int_initio_scsi_rst(struct initio_host * host) } /** - * int_initio_scsi_resel - Reselection occured + * int_initio_scsi_resel - Reselection occurred * @host: InitIO host adapter * * A SCSI reselection event has been signalled and the interrupt diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h index e58af9e95506..219b901bdc25 100644 --- a/drivers/scsi/initio.h +++ b/drivers/scsi/initio.h @@ -116,7 +116,7 @@ typedef struct { #define TUL_SBusId 0x89 /* 09 R SCSI BUS ID */ #define TUL_STimeOut 0x8A /* 0A W Sel/Resel Time Out Register */ #define TUL_SIdent 0x8A /* 0A R Identify Message Register */ -#define TUL_SAvail 0x8A /* 0A R Availiable Counter Register */ +#define TUL_SAvail 0x8A /* 0A R Available Counter Register */ #define TUL_SData 0x8B /* 0B R/W SCSI data in/out */ #define TUL_SFifo 0x8C /* 0C R/W FIFO */ #define TUL_SSignal 0x90 /* 10 R/W SCSI signal in/out */ @@ -389,7 +389,7 @@ struct scsi_ctrl_blk { /* Bit Definition for status */ #define SCB_RENT 0x01 #define SCB_PEND 0x02 -#define SCB_CONTIG 0x04 /* Contigent Allegiance */ +#define SCB_CONTIG 0x04 /* Contingent Allegiance */ #define SCB_SELECT 0x08 #define SCB_BUSY 0x10 #define SCB_DONE 0x20 diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index b2511acd39bd..218f71a8726e 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -137,7 +137,7 @@ /* - Fix path/name for scsi_hosts.h include for 2.6 kernels */ /* - Fix sort order of 7k */ /* - Remove 3 unused "inline" functions */ -/* 7.12.xx - Use STATIC functions whereever possible */ +/* 7.12.xx - Use STATIC functions wherever possible */ /* - Clean up deprecated MODULE_PARM calls */ /* 7.12.05 - Remove Version Matching per IBM request */ /*****************************************************************************/ @@ -1665,7 +1665,7 @@ ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) int datasize; /* Trombone is the only copperhead that can do packet flash, but only - * for firmware. No one said it had to make sence. */ + * for firmware. No one said it had to make sense. */ if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) { if (ips_usrcmd(ha, pt, scb)) return IPS_SUCCESS; diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 4e49fbcfe8af..f2df0593332b 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -1193,7 +1193,7 @@ typedef struct { #define IPS_VER_SEBRING "7.12.02" #define IPS_VER_KEYWEST "7.12.02" -/* Compatability IDs for various adapters */ +/* Compatibility IDs for various adapters */ #define IPS_COMPAT_UNKNOWN "" #define IPS_COMPAT_CURRENT "KW710" #define IPS_COMPAT_SERVERAID1 "2.25.01" diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index a860452a8f71..3df985305f69 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -295,7 +295,7 @@ static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn) rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment); /* * We may not have been able to send data because the conn - * is getting stopped. libiscsi will know so propogate err + * is getting stopped. libiscsi will know so propagate err * for it to do the right thing. */ if (rc == -EAGAIN) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 28231badd9e6..77035a746f60 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -1042,7 +1042,7 @@ static void fc_exch_set_addr(struct fc_exch *ep, } /** - * fc_seq_els_rsp_send() - Send an ELS response using infomation from + * fc_seq_els_rsp_send() - Send an ELS response using information from * the existing sequence/exchange. * @fp: The received frame * @els_cmd: The ELS command to be sent @@ -1153,7 +1153,7 @@ static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) * fc_exch_send_ba_rjt() - Send BLS Reject * @rx_fp: The frame being rejected * @reason: The reason the frame is being rejected - * @explan: The explaination for the rejection + * @explan: The explanation for the rejection * * This is for rejecting BA_ABTS only. */ diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index b1b03af158bf..5b799a37ad09 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -870,7 +870,7 @@ static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) fsp->scsi_resid = ntohl(rp_ex->fr_resid); /* * The cmnd->underflow is the minimum number of - * bytes that must be transfered for this + * bytes that must be transferred for this * command. Provided a sense condition is not * present, make sure the actual amount * transferred is at least the underflow value @@ -1306,7 +1306,7 @@ static int fc_lun_reset(struct fc_lport *lport, struct fc_fcp_pkt *fsp, } /** - * fc_tm_done() - Task Managment response handler + * fc_tm_done() - Task Management response handler * @seq: The sequence that the response is on * @fp: The response frame * @arg: The FCP packet the response is for diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 8c08b210001d..906bbcad0e2d 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -52,7 +52,7 @@ * while making the callback. To ensure that the rport is not free'd while * processing the callback the rport callbacks are serialized through a * single-threaded workqueue. An rport would never be free'd while in a - * callback handler becuase no other rport work in this queue can be executed + * callback handler because no other rport work in this queue can be executed * at the same time. * * When discovery succeeds or fails a callback is made to the lport as @@ -163,7 +163,7 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) * fc_lport_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event * @rdata: private remote port data - * @event: The event that occured + * @event: The event that occurred * * Locking Note: The rport lock should not be held when calling * this function. @@ -379,7 +379,7 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) /** * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. - * @lport: Fibre Channel local port recieving the RLIR + * @lport: Fibre Channel local port receiving the RLIR * @fp: The RLIR request frame * * Locking Note: The lport lock is expected to be held before calling @@ -396,7 +396,7 @@ static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp) /** * fc_lport_recv_echo_req() - Handle received ECHO request - * @lport: The local port recieving the ECHO + * @lport: The local port receiving the ECHO * @fp: ECHO request frame * * Locking Note: The lport lock is expected to be held before calling @@ -432,7 +432,7 @@ static void fc_lport_recv_echo_req(struct fc_lport *lport, /** * fc_lport_recv_rnid_req() - Handle received Request Node ID data request - * @lport: The local port recieving the RNID + * @lport: The local port receiving the RNID * @fp: The RNID request frame * * Locking Note: The lport lock is expected to be held before calling @@ -491,7 +491,7 @@ static void fc_lport_recv_rnid_req(struct fc_lport *lport, /** * fc_lport_recv_logo_req() - Handle received fabric LOGO request - * @lport: The local port recieving the LOGO + * @lport: The local port receiving the LOGO * @fp: The LOGO request frame * * Locking Note: The lport lock is exected to be held before calling @@ -771,7 +771,7 @@ EXPORT_SYMBOL(fc_lport_set_local_id); /** * fc_lport_recv_flogi_req() - Receive a FLOGI request - * @lport: The local port that recieved the request + * @lport: The local port that received the request * @rx_fp: The FLOGI frame * * A received FLOGI request indicates a point-to-point connection. @@ -858,7 +858,7 @@ out: * if an rport should handle the request. * * Locking Note: This function should not be called with the lport - * lock held becuase it will grab the lock. + * lock held because it will grab the lock. */ static void fc_lport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) @@ -925,7 +925,7 @@ struct fc4_prov fc_lport_els_prov = { * @fp: The frame the request is in * * Locking Note: This function should not be called with the lport - * lock held becuase it may grab the lock. + * lock held because it may grab the lock. */ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index f3f693b772ac..874e29d9533f 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -240,7 +240,7 @@ static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, disc_resp, DISCOVER_RESP_SIZE); if (res) return res; - /* This is detecting a failure to transmit inital + /* This is detecting a failure to transmit initial * dev to host FIS as described in section G.5 of * sas-2 r 04b */ dr = &((struct smp_resp *)disc_resp)->disc; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 4e0faa00b96f..17d789325f40 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -4515,7 +4515,7 @@ static FC_RPORT_ATTR(field, S_IRUGO, lpfc_show_rport_##field, NULL) * Description: * This function is called by the transport after the @fc_vport's symbolic name * has been changed. This function re-registers the symbolic name with the - * switch to propogate the change into the fabric if the vport is active. + * switch to propagate the change into the fabric if the vport is active. **/ static void lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport) diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 793b9f1131fb..77b2871d96b7 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1939,7 +1939,7 @@ out: * @rxxri: Receive exchange id * @len: Number of data bytes * - * This function allocates and posts a data buffer of sufficient size to recieve + * This function allocates and posts a data buffer of sufficient size to receive * an unsolicted CT command. **/ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index a753581509d6..3d967741c708 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -908,7 +908,7 @@ lpfc_debugfs_dumpData_open(struct inode *inode, struct file *file) if (!debug) goto out; - /* Round to page boundry */ + /* Round to page boundary */ printk(KERN_ERR "9059 BLKGRD: %s: _dump_buf_data=0x%p\n", __func__, _dump_buf_data); debug->buffer = _dump_buf_data; @@ -938,7 +938,7 @@ lpfc_debugfs_dumpDif_open(struct inode *inode, struct file *file) if (!debug) goto out; - /* Round to page boundry */ + /* Round to page boundary */ printk(KERN_ERR "9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%s\n", __func__, _dump_buf_dif, file->f_dentry->d_name.name); debug->buffer = _dump_buf_dif; @@ -2158,7 +2158,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_dir(name, phba->hba_debugfs_root); if (!vport->vport_debugfs_root) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0417 Cant create debugfs\n"); + "0417 Can't create debugfs\n"); goto debug_failed; } atomic_inc(&phba->debugfs_vport_count); @@ -2211,7 +2211,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) vport, &lpfc_debugfs_op_nodelist); if (!vport->debug_nodelist) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0409 Cant create debugfs nodelist\n"); + "0409 Can't create debugfs nodelist\n"); goto debug_failed; } diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 735028fedda5..d34b69f9cdb1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -102,7 +102,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) phba->pport->port_state); /* CLEAR_LA should re-enable link attention events and - * we should then imediately take a LATT event. The + * we should then immediately take a LATT event. The * LATT processing should call lpfc_linkdown() which * will cleanup any left over in-progress discovery * events. @@ -1599,7 +1599,7 @@ out: * This routine is the completion callback function for issuing the Port * Login (PLOGI) command. For PLOGI completion, there must be an active * ndlp on the vport node list that matches the remote node ID from the - * PLOGI reponse IOCB. If such ndlp does not exist, the PLOGI is simply + * PLOGI response IOCB. If such ndlp does not exist, the PLOGI is simply * ignored and command IOCB released. The PLOGI response IOCB status is * checked for error conditons. If there is error status reported, PLOGI * retry shall be attempted by invoking the lpfc_els_retry() routine. diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 154c715fb3af..301498301a8f 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -739,7 +739,7 @@ lpfc_do_work(void *p) /* * This is only called to handle FC worker events. Since this a rare - * occurance, we allocate a struct lpfc_work_evt structure here instead of + * occurrence, we allocate a struct lpfc_work_evt structure here instead of * embedding it in the IOCB. */ int @@ -1348,7 +1348,7 @@ lpfc_register_fcf(struct lpfc_hba *phba) int rc; spin_lock_irq(&phba->hbalock); - /* If the FCF is not availabe do nothing. */ + /* If the FCF is not available do nothing. */ if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) { phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); spin_unlock_irq(&phba->hbalock); @@ -1538,7 +1538,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, /* * If user did not specify any addressing mode, or if the - * prefered addressing mode specified by user is not supported + * preferred addressing mode specified by user is not supported * by FCF, allow fabric to pick the addressing mode. */ *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, @@ -1553,7 +1553,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, FCFCNCT_AM_SPMA) ? LPFC_FCF_SPMA : LPFC_FCF_FPMA; /* - * If the user specified a prefered address mode, use the + * If the user specified a preferred address mode, use the * addr mode only if FCF support the addr_mode. */ else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && @@ -3117,7 +3117,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * back at reg login state so this * mbox needs to be ignored becase * there is another reg login in - * proccess. + * process. */ spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; @@ -4477,7 +4477,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) if ((vport->fc_flag & FC_RSCN_MODE) && !(vport->fc_flag & FC_NDISC_ACTIVE)) { if (lpfc_rscn_payload_check(vport, did)) { - /* If we've already recieved a PLOGI from this NPort + /* If we've already received a PLOGI from this NPort * we don't need to try to discover it again. */ if (ndlp->nlp_flag & NLP_RCV_PLOGI) @@ -4493,7 +4493,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) } else ndlp = NULL; } else { - /* If we've already recieved a PLOGI from this NPort, + /* If we've already received a PLOGI from this NPort, * or we are already in the process of discovery on it, * we don't need to try to discover it again. */ @@ -5756,7 +5756,7 @@ lpfc_read_fcoe_param(struct lpfc_hba *phba, * @size: Size of the data buffer. * @rec_type: Record type to be searched. * - * This function searches config region data to find the begining + * This function searches config region data to find the beginning * of the record specified by record_type. If record found, this * function return pointer to the record else return NULL. */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e6ebe516cfbb..505f88443b5c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -4466,7 +4466,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) } /** - * lpfc_init_api_table_setup - Set up init api fucntion jump table + * lpfc_init_api_table_setup - Set up init api function jump table * @phba: The hba struct for which this call is being executed. * @dev_grp: The HBA PCI-Device group number. * @@ -4850,7 +4850,7 @@ out_free_mem: * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ int @@ -5730,7 +5730,7 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ static int @@ -5835,7 +5835,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ static int @@ -5894,7 +5894,7 @@ lpfc_setup_endian_order(struct lpfc_hba *phba) * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ static int @@ -6189,7 +6189,7 @@ out_error: * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ static void @@ -6253,7 +6253,7 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ int @@ -6498,7 +6498,7 @@ out_error: * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ void @@ -6543,7 +6543,7 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory **/ static int lpfc_sli4_cq_event_pool_create(struct lpfc_hba *phba) @@ -6704,7 +6704,7 @@ lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) * * Return codes * 0 - successful - * -ENOMEM - No availble memory + * -ENOMEM - No available memory * -EIO - The mailbox failed to complete successfully. **/ int diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index dba32dfdb59b..fbab9734e9b4 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1834,7 +1834,7 @@ lpfc_sli4_mbox_opcode_get(struct lpfc_hba *phba, struct lpfcMboxq *mbox) * @fcf_index: index to fcf table. * * This routine routine allocates and constructs non-embedded mailbox command - * for reading a FCF table entry refered by @fcf_index. + * for reading a FCF table entry referred by @fcf_index. * * Return: pointer to the mailbox command constructed if successful, otherwise * NULL. diff --git a/drivers/scsi/lpfc/lpfc_nl.h b/drivers/scsi/lpfc/lpfc_nl.h index f3cfbe2ce986..f2b1bbcb196f 100644 --- a/drivers/scsi/lpfc/lpfc_nl.h +++ b/drivers/scsi/lpfc/lpfc_nl.h @@ -50,7 +50,7 @@ * and subcategory. The event type must come first. * The subcategory further defines the data that follows in the rest * of the payload. Each category will have its own unique header plus - * any addtional data unique to the subcategory. + * any additional data unique to the subcategory. * The payload sent via the fc transport is one-way driver->application. */ diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 52b35159fc35..0d92d4205ea6 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -658,7 +658,7 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) return 0; } /** - * lpfc_release_rpi - Release a RPI by issueing unreg_login mailbox cmd. + * lpfc_release_rpi - Release a RPI by issuing unreg_login mailbox cmd. * @phba : Pointer to lpfc_hba structure. * @vport: Pointer to lpfc_vport structure. * @rpi : rpi to be release. diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 2b962b020cfb..fe7cc84e773b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -577,7 +577,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) iocb->un.fcpi64.bdl.addrHigh = 0; iocb->ulpBdeCount = 0; iocb->ulpLe = 0; - /* fill in responce BDE */ + /* fill in response BDE */ iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize = @@ -1217,10 +1217,10 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) (2 * sizeof(struct ulp_bde64))); data_bde->addrHigh = putPaddrHigh(physaddr); data_bde->addrLow = putPaddrLow(physaddr); - /* ebde count includes the responce bde and data bpl */ + /* ebde count includes the response bde and data bpl */ iocb_cmd->unsli3.fcp_ext.ebde_count = 2; } else { - /* ebde count includes the responce bde and data bdes */ + /* ebde count includes the response bde and data bdes */ iocb_cmd->unsli3.fcp_ext.ebde_count = (num_bde + 1); } } else { @@ -2380,7 +2380,7 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, } /* * The cmnd->underflow is the minimum number of bytes that must - * be transfered for this command. Provided a sense condition + * be transferred for this command. Provided a sense condition * is not present, make sure the actual amount transferred is at * least the underflow value or fail. */ @@ -2873,7 +2873,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, } /** - * lpfc_scsi_api_table_setup - Set up scsi api fucntion jump table + * lpfc_scsi_api_table_setup - Set up scsi api function jump table * @phba: The hba struct for which this call is being executed. * @dev_grp: The HBA PCI-Device group number. * diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 5932273870a5..ce645b20a6ad 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -130,7 +130,7 @@ struct lpfc_scsi_buf { dma_addr_t nonsg_phys; /* Non scatter-gather physical address. */ /* - * data and dma_handle are the kernel virutal and bus address of the + * data and dma_handle are the kernel virtual and bus address of the * dma-able buffer containing the fcp_cmd, fcp_rsp and a scatter * gather bde list that supports the sg_tablesize value. */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4746dcd756dd..dacabbe0a586 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2817,7 +2817,7 @@ void lpfc_poll_eratt(unsigned long ptr) * This function is called from the interrupt context when there is a ring * event for the fcp ring. The caller does not hold any lock. * The function processes each response iocb in the response ring until it - * finds an iocb with LE bit set and chains all the iocbs upto the iocb with + * finds an iocb with LE bit set and chains all the iocbs up to the iocb with * LE bit set. The function will call the completion handler of the command iocb * if the response iocb indicates a completion for a command iocb or it is * an abort completion. The function will call lpfc_sli_process_unsol_iocb @@ -5117,7 +5117,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) /* Setting state unknown so lpfc_sli_abort_iocb_ring * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing - * it to fail all oustanding SCSI IO. + * it to fail all outstanding SCSI IO. */ spin_lock_irq(&phba->pport->work_port_lock); phba->pport->work_port_events &= ~WORKER_MBOX_TMO; @@ -6031,7 +6031,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) } /** - * lpfc_mbox_api_table_setup - Set up mbox api fucntion jump table + * lpfc_mbox_api_table_setup - Set up mbox api function jump table * @phba: The hba struct for which this call is being executed. * @dev_grp: The HBA PCI-Device group number. * @@ -6847,7 +6847,7 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, } /** - * lpfc_sli_api_table_setup - Set up sli api fucntion jump table + * lpfc_sli_api_table_setup - Set up sli api function jump table * @phba: The hba struct for which this call is being executed. * @dev_grp: The HBA PCI-Device group number. * @@ -7521,7 +7521,7 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_dmabuf *mp, *next_mp; struct list_head *slp = &pring->postbufq; - /* Search postbufq, from the begining, looking for a match on tag */ + /* Search postbufq, from the beginning, looking for a match on tag */ spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { if (mp->buffer_tag == tag) { @@ -7565,7 +7565,7 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_dmabuf *mp, *next_mp; struct list_head *slp = &pring->postbufq; - /* Search postbufq, from the begining, looking for a match on phys */ + /* Search postbufq, from the beginning, looking for a match on phys */ spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { if (mp->phys == phys) { @@ -8438,7 +8438,7 @@ lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba) * for possible error attention events. The caller must hold the hostlock * with spin_lock_irq(). * - * This fucntion returns 1 when there is Error Attention in the Host Attention + * This function returns 1 when there is Error Attention in the Host Attention * Register and returns 0 otherwise. **/ static int @@ -8491,7 +8491,7 @@ unplug_err: * for possible error attention events. The caller must hold the hostlock * with spin_lock_irq(). * - * This fucntion returns 1 when there is Error Attention in the Host Attention + * This function returns 1 when there is Error Attention in the Host Attention * Register and returns 0 otherwise. **/ static int @@ -8581,7 +8581,7 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba) * This function is called from timer soft interrupt context to check HBA's * error attention register bit for error attention events. * - * This fucntion returns 1 when there is Error Attention in the Host Attention + * This function returns 1 when there is Error Attention in the Host Attention * Register and returns 0 otherwise. **/ int @@ -9684,7 +9684,7 @@ out: * @cq: Pointer to the completion queue. * @wcqe: Pointer to a completion queue entry. * - * This routine process a slow-path work-queue or recieve queue completion queue + * This routine process a slow-path work-queue or receive queue completion queue * entry. * * Return: true if work posted to worker thread, otherwise false. @@ -12971,7 +12971,7 @@ lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba, * record and processing it one at a time starting from the @fcf_index * for initial FCF discovery or fast FCF failover rediscovery. * - * Return 0 if the mailbox command is submitted sucessfully, none 0 + * Return 0 if the mailbox command is submitted successfully, none 0 * otherwise. **/ int @@ -13032,7 +13032,7 @@ fail_fcf_scan: * This routine is invoked to read an FCF record indicated by @fcf_index * and to use it for FLOGI roundrobin FCF failover. * - * Return 0 if the mailbox command is submitted sucessfully, none 0 + * Return 0 if the mailbox command is submitted successfully, none 0 * otherwise. **/ int @@ -13078,7 +13078,7 @@ fail_fcf_read: * This routine is invoked to read an FCF record indicated by @fcf_index to * determine whether it's eligible for FLOGI roundrobin failover list. * - * Return 0 if the mailbox command is submitted sucessfully, none 0 + * Return 0 if the mailbox command is submitted successfully, none 0 * otherwise. **/ int diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index c212694a9714..f2684dd09ed0 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -284,7 +284,7 @@ mega_query_adapter(adapter_t *adapter) adapter->host->max_id = 16; /* max targets per channel */ - adapter->host->max_lun = 7; /* Upto 7 luns for non disk devices */ + adapter->host->max_lun = 7; /* Up to 7 luns for non disk devices */ adapter->host->cmd_per_lun = max_cmd_per_lun; @@ -3734,7 +3734,7 @@ mega_m_to_n(void __user *arg, nitioctl_t *uioc) * check is the application conforms to NIT. We do not have to do much * in that case. * We exploit the fact that the signature is stored in the very - * begining of the structure. + * beginning of the structure. */ if( copy_from_user(signature, arg, 7) ) diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index 853411911b2e..9a7897f8ca43 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -532,9 +532,9 @@ struct uioctl_t { /* * struct mcontroller is used to pass information about the controllers in the - * system. Its upto the application how to use the information. We are passing + * system. Its up to the application how to use the information. We are passing * as much info about the cards as possible and useful. Before issuing the - * call to find information about the cards, the applicaiton needs to issue a + * call to find information about the cards, the application needs to issue a * ioctl first to find out the number of controllers in the system. */ #define MAX_CONTROLLERS 32 @@ -804,7 +804,7 @@ typedef struct { unsigned long base; void __iomem *mmio_base; - /* mbox64 with mbox not aligned on 16-byte boundry */ + /* mbox64 with mbox not aligned on 16-byte boundary */ mbox64_t *una_mbox64; dma_addr_t una_mbox64_dma; diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h index ce2487a888ed..e01c6f7c2cac 100644 --- a/drivers/scsi/megaraid/mbox_defs.h +++ b/drivers/scsi/megaraid/mbox_defs.h @@ -660,7 +660,7 @@ typedef struct { * @lparam : logical drives parameters * @span : span * - * 8-LD logical drive with upto 8 spans + * 8-LD logical drive with up to 8 spans */ typedef struct { logdrv_param_t lparam; @@ -673,7 +673,7 @@ typedef struct { * @lparam : logical drives parameters * @span : span * - * 8-LD logical drive with upto 4 spans + * 8-LD logical drive with up to 4 spans */ typedef struct { logdrv_param_t lparam; @@ -720,7 +720,7 @@ typedef struct { * @ldrv : logical drives information * @pdrv : physical drives information * - * Disk array for 8LD logical drives with upto 8 spans + * Disk array for 8LD logical drives with up to 8 spans */ typedef struct { uint8_t numldrv; @@ -737,7 +737,7 @@ typedef struct { * @ldrv : logical drives information * @pdrv : physical drives information * - * Disk array for 8LD logical drives with upto 4 spans + * Disk array for 8LD logical drives with up to 4 spans */ typedef struct { uint8_t numldrv; diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 5708cb27d078..1dba32870b4c 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -2689,7 +2689,7 @@ megaraid_reset_handler(struct scsi_cmnd *scp) (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i)); } - // bailout if no recovery happended in reset time + // bailout if no recovery happened in reset time if (adapter->outstanding_cmds == 0) { break; } @@ -3452,7 +3452,7 @@ megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb) * megaraid_mbox_setup_device_map - manage device ids * @adapter : Driver's soft state * - * Manange the device ids to have an appropraite mapping between the kernel + * Manange the device ids to have an appropriate mapping between the kernel * scsi addresses and megaraid scsi and logical drive addresses. We export * scsi devices on their actual addresses, whereas the logical drives are * exported on a virtual scsi channel. @@ -3973,7 +3973,7 @@ megaraid_sysfs_get_ldmap_timeout(unsigned long data) * NOTE: The commands issuance functionality is not generalized and * implemented in context of "get ld map" command only. If required, the * command issuance logical can be trivially pulled out and implemented as a - * standalone libary. For now, this should suffice since there is no other + * standalone library. For now, this should suffice since there is no other * user of this interface. * * Return 0 on success. diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 635b228c3ead..046dcc672ec1 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1347,7 +1347,7 @@ struct megasas_instance { struct timer_list io_completion_timer; struct list_head internal_reset_pending_q; - /* Ptr to hba specfic information */ + /* Ptr to hba specific information */ void *ctrl_context; u8 msi_flag; struct msix_entry msixentry; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index bbd10c81fd9c..66d4cea4df98 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1698,7 +1698,7 @@ void megasas_do_ocr(struct megasas_instance *instance) * megasas_wait_for_outstanding - Wait for all outstanding cmds * @instance: Adapter soft state * - * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to + * This function waits for up to MEGASAS_RESET_WAIT_TIME seconds for FW to * complete all its outstanding commands. Returns error if one or more IOs * are pending after this time period. It also marks the controller dead. */ diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h index 20e6b8869341..165454d52591 100644 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h @@ -21,7 +21,7 @@ * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO * Control field Task Attribute flags. - * Moved LUN field defines to mpi2.h becasue they are + * Moved LUN field defines to mpi2.h because they are * common to many structures. * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to * Query Asynchronous Event. diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 5e001ffd4c13..3346357031e9 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -925,7 +925,7 @@ _base_interrupt(int irq, void *bus_id) } /** - * mpt2sas_base_release_callback_handler - clear interupt callback handler + * mpt2sas_base_release_callback_handler - clear interrupt callback handler * @cb_idx: callback index * * Return nothing. @@ -1113,7 +1113,7 @@ _base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc) * @ioc: per adapter object * * Check to see if card is capable of MSIX, and set number - * of avaliable msix vectors + * of available msix vectors */ static int _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) @@ -1595,7 +1595,7 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle) /** - * mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware + * mpt2sas_base_put_smid_hi_priority - send Task Management request to firmware * @ioc: per adapter object * @smid: system request message index * @@ -2599,7 +2599,7 @@ _base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout, int_status = readl(&ioc->chip->HostInterruptStatus); if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successfull count(%d), timeout(%d)\n", ioc->name, + "successful count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; } @@ -2640,7 +2640,7 @@ _base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout, int_status = readl(&ioc->chip->HostInterruptStatus); if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successfull count(%d), timeout(%d)\n", ioc->name, + "successful count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { @@ -2688,7 +2688,7 @@ _base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout, doorbell_reg = readl(&ioc->chip->Doorbell); if (!(doorbell_reg & MPI2_DOORBELL_USED)) { dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successfull count(%d), timeout(%d)\n", ioc->name, + "successful count(%d), timeout(%d)\n", ioc->name, __func__, count, timeout)); return 0; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c index 6afd67b324fe..6861244249a3 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ b/drivers/scsi/mpt2sas/mpt2sas_config.c @@ -93,7 +93,7 @@ struct config_request{ * @mpi_reply: reply message frame * Context: none. * - * Function for displaying debug info helpfull when debugging issues + * Function for displaying debug info helpful when debugging issues * in this module. */ static void diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index e92b77af5484..1c6d2b405eef 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -116,7 +116,7 @@ _ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) * @mpi_reply: reply message frame * Context: none. * - * Function for displaying debug info helpfull when debugging issues + * Function for displaying debug info helpful when debugging issues * in this module. */ static void diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 6ceb7759bfe5..d2064a0533ae 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -397,7 +397,7 @@ _scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle, * @is_raid: [flag] 1 = raid object, 0 = sas object * * Determines whether this device should be first reported device to - * to scsi-ml or sas transport, this purpose is for persistant boot device. + * to scsi-ml or sas transport, this purpose is for persistent boot device. * There are primary, alternate, and current entries in bios page 2. The order * priority is primary, alternate, then current. This routine saves * the corresponding device object and is_raid flag in the ioc object. @@ -2671,10 +2671,10 @@ _scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, * @handle: device handle * Context: interrupt time. * - * This code is to initiate the device removal handshake protocal + * This code is to initiate the device removal handshake protocol * with controller firmware. This function will issue target reset * using high priority request queue. It will send a sas iounit - * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. + * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. * * This is designed to send muliple task management request at the same * time to the fifo. If the fifo is full, we will append the request, @@ -2749,9 +2749,9 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) * @reply: reply message frame(lower 32bit addr) * Context: interrupt time. * - * This is the sas iounit controll completion routine. + * This is the sas iounit control completion routine. * This code is part of the code to initiate the device removal - * handshake protocal with controller firmware. + * handshake protocol with controller firmware. * * Return 1 meaning mf should be freed from _base_interrupt * 0 means the mf is freed from this function. @@ -2878,8 +2878,8 @@ _scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, * * This is the target reset completion routine. * This code is part of the code to initiate the device removal - * handshake protocal with controller firmware. - * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE) + * handshake protocol with controller firmware. + * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE) * * Return 1 meaning mf should be freed from _base_interrupt * 0 means the mf is freed from this function. @@ -2984,7 +2984,7 @@ _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid) * * This routine added to better handle cable breaker. * - * This handles the case where driver recieves multiple expander + * This handles the case where driver receives multiple expander * add and delete events in a single shot. When there is a delete event * the routine will void any pending add events waiting in the event queue. * @@ -3511,7 +3511,7 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data) #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** - * _scsih_scsi_ioc_info - translated non-successfull SCSI_IO request + * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request * @ioc: per adapter object * @scmd: pointer to scsi command object * @mpi_reply: reply mf payload returned from firmware @@ -5138,7 +5138,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, unsigned long flags; int r; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: " + dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primitive: " "phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum, event_data->PortWidth)); dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 46cc3825638d..835d8d66e696 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -2679,7 +2679,7 @@ static struct script script0 __initdata = { }/*-------------------------< RESEL_TAG >-------------------*/,{ /* ** Read IDENTIFY + SIMPLE + TAG using a single MOVE. - ** Agressive optimization, is'nt it? + ** Aggressive optimization, is'nt it? ** No need to test the SIMPLE TAG message, since the ** driver only supports conformant devices for tags. ;-) */ diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 6b8b021400f8..f6a50c98c36f 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -1288,7 +1288,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id) nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", nsp32_read4(base, SAVED_SACK_CNT)); - scsi_set_resid(SCpnt, 0); /* all data transfered! */ + scsi_set_resid(SCpnt, 0); /* all data transferred! */ } /* @@ -1630,7 +1630,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph) /* * If SAVEDSACKCNT == 0, it means SavedDataPointer is - * come after data transfering. + * come after data transferring. */ if (s_sacklen > 0) { /* @@ -1785,7 +1785,7 @@ static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen the head element of the sg. restlen is correctly calculated. */ } - /* calculate the rest length for transfering */ + /* calculate the rest length for transferring */ restlen = sentlen - s_sacklen; /* update adjusting current SG table entry */ diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h index 9565acf1aa72..c0221829069c 100644 --- a/drivers/scsi/nsp32.h +++ b/drivers/scsi/nsp32.h @@ -507,7 +507,7 @@ typedef struct _nsp32_lunt { /* * SCSI TARGET/LUN definition */ -#define NSP32_HOST_SCSIID 7 /* SCSI initiator is everytime defined as 7 */ +#define NSP32_HOST_SCSIID 7 /* SCSI initiator is every time defined as 7 */ #define MAX_TARGET 8 #define MAX_LUN 8 /* XXX: In SPI3, max number of LUN is 64. */ diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 521e2182d45b..58f5be4740e9 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -1366,7 +1366,7 @@ error: /* The values below are based on the OnStream frame payload size of 32K == 2**15, * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions - * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. + * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. */ #define OSST_FRAME_SHIFT 6 #define OSST_SECTOR_SHIFT 9 @@ -3131,7 +3131,7 @@ static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** } #if DEBUG if (debugging) - printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n", + printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n", name, offset, transfer, blks); #endif @@ -3811,7 +3811,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo if (transfer == 0) { printk(KERN_WARNING - "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n", + "%s:W: Nothing can be transferred, requested %Zd, tape block size (%d%c).\n", name, count, STp->block_size < 1024? STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h index 11d26c57f3f8..b4fea98ba276 100644 --- a/drivers/scsi/osst.h +++ b/drivers/scsi/osst.h @@ -413,7 +413,7 @@ typedef struct os_dat_s { * AUX */ typedef struct os_aux_s { - __be32 format_id; /* hardware compability AUX is based on */ + __be32 format_id; /* hardware compatibility AUX is based on */ char application_sig[4]; /* driver used to write this media */ __be32 hdwr; /* reserved */ __be32 update_frame_cntr; /* for configuration frame */ diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index be3f33d31a99..54bdf6d85c6d 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -742,7 +742,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt) res = nsp_fifo_count(SCpnt) - ocount; //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); - if (res == 0) { /* if some data avilable ? */ + if (res == 0) { /* if some data available ? */ if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual); continue; diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 18b6c55cd08c..8b7db1e53c10 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -339,7 +339,7 @@ update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number) /** * bar4_shift - function is called to shift BAR base address - * @pm8001_ha : our hba card infomation + * @pm8001_ha : our hba card information * @shiftValue : shifting value in memory bar. */ static int bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue) diff --git a/drivers/scsi/pm8001/pm8001_hwi.h b/drivers/scsi/pm8001/pm8001_hwi.h index 833a5201eda4..909132041c07 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.h +++ b/drivers/scsi/pm8001/pm8001_hwi.h @@ -209,7 +209,7 @@ struct pio_setup_fis { /* * brief the data structure of SATA Completion Response - * use to discribe the sata task response (64 bytes) + * use to describe the sata task response (64 bytes) */ struct sata_completion_resp { __le32 tag; @@ -951,7 +951,7 @@ struct set_dev_state_resp { #define PCIE_EVENT_INTERRUPT 0x003044 #define PCIE_ERROR_INTERRUPT_ENABLE 0x003048 #define PCIE_ERROR_INTERRUPT 0x00304C -/* signature defintion for host scratch pad0 register */ +/* signature definition for host scratch pad0 register */ #define SPC_SOFT_RESET_SIGNATURE 0x252acbcd /* Signature for Soft Reset */ diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index bdb6b27dedd6..aa05e661d113 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -445,7 +445,7 @@ struct fw_control_info { struct fw_control_ex { struct fw_control_info *fw_control; void *buffer;/* keep buffer pointer to be - freed when the responce comes*/ + freed when the response comes*/ void *virtAddr;/* keep virtual address of the data */ void *usrAddr;/* keep virtual address of the user data */ diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index bcf858e88c64..96d5ad0c1e42 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -213,7 +213,7 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) * pmcraid_slave_configure - Configures a SCSI device * @scsi_dev: scsi device struct * - * This fucntion is executed by SCSI mid layer just after a device is first + * This function is executed by SCSI mid layer just after a device is first * scanned (i.e. it has responded to an INQUIRY). For VSET resources, the * timeout value (default 30s) will be over-written to a higher value (60s) * and max_sectors value will be over-written to 512. It also sets queue depth @@ -2122,7 +2122,7 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) * * This function executes most of the steps required for IOA reset. This gets * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's - * 'eh_' thread. Access to variables used for controling the reset sequence is + * 'eh_' thread. Access to variables used for controlling the reset sequence is * synchronized using host lock. Various functions called during reset process * would make use of a single command block, pointer to which is also stored in * adapter instance structure. @@ -2994,7 +2994,7 @@ static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) /* If the abort task is not timed out we will get a Good completion * as sense_key, otherwise we may get one the following responses - * due to subsquent bus reset or device reset. In case IOASC is + * due to subsequent bus reset or device reset. In case IOASC is * NR_SYNC_REQUIRED, set sync_reqd flag for the corresponding resource */ if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || @@ -3933,7 +3933,7 @@ static long pmcraid_ioctl_passthrough( /* if abort task couldn't find the command i.e it got * completed prior to aborting, return good completion. - * if command got aborted succesfully or there was IOA + * if command got aborted successfully or there was IOA * reset due to abort task itself getting timedout then * return -ETIMEDOUT */ @@ -5932,7 +5932,7 @@ static int __devinit pmcraid_probe( * However, firmware supports 64-bit streaming DMA buffers, whereas * coherent buffers are to be 32-bit. Since pci_alloc_consistent always * returns memory within 4GB (if not, change this logic), coherent - * buffers are within firmware acceptible address ranges. + * buffers are within firmware acceptable address ranges. */ if ((sizeof(dma_addr_t) == 4) || pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h index 4db210d93947..34e4c915002e 100644 --- a/drivers/scsi/pmcraid.h +++ b/drivers/scsi/pmcraid.h @@ -1024,7 +1024,7 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = { /* - * pmcraid_ioctl_header - definition of header structure that preceeds all the + * pmcraid_ioctl_header - definition of header structure that precedes all the * buffers given as ioctl arguments. * * .signature : always ASCII string, "PMCRAID" diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 5dec684bf010..8ba5744c267e 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -78,7 +78,7 @@ - Clean up vchan handling Rev 3.23.33 July 3, 2003, Jes Sorensen - Don't define register access macros before define determining MMIO. - This just happend to work out on ia64 but not elsewhere. + This just happened to work out on ia64 but not elsewhere. - Don't try and read from the card while it is in reset as it won't respond and causes an MCA Rev 3.23.32 June 23, 2003, Jes Sorensen diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 6c51c0a35b9e..ee20353c8550 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2086,7 +2086,7 @@ struct ct_sns_pkt { }; /* - * SNS command structures -- for 2200 compatability. + * SNS command structures -- for 2200 compatibility. */ #define RFT_ID_SNS_SCMD_LEN 22 #define RFT_ID_SNS_CMD_SIZE 60 diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 631fefc8482d..f5ba09c8a663 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -539,7 +539,7 @@ struct sts_entry_24xx { * If DIF Error is set in comp_status, these additional fields are * defined: * &data[10] : uint8_t report_runt_bg[2]; - computed guard - * &data[12] : uint8_t actual_dif[8]; - DIF Data recieved + * &data[12] : uint8_t actual_dif[8]; - DIF Data received * &data[20] : uint8_t expected_dif[8]; - DIF Data computed */ }; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d17ed9a94a0c..712518d05128 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -414,7 +414,7 @@ skip_rio: "marked OFFLINE!\n"); vha->flags.online = 0; } else { - /* Check to see if MPI timeout occured */ + /* Check to see if MPI timeout occurred */ if ((mbx & MBX_3) && (ha->flags.port0)) set_bit(MPI_RESET_NEEDED, &vha->dpc_flags); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 7a7c0ecfe7dd..34893397ac84 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -303,7 +303,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { qla_printk(KERN_WARNING, ha, - "Mailbox command timeout occured. " + "Mailbox command timeout occurred. " "Scheduling ISP " "abort. eeh_busy: 0x%x\n", ha->flags.eeh_busy); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); @@ -321,7 +321,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { qla_printk(KERN_WARNING, ha, - "Mailbox command timeout occured. " + "Mailbox command timeout occurred. " "Issuing ISP abort.\n"); set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); @@ -3789,7 +3789,7 @@ qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, mcp->mb[20] = LSW(MSD(mreq->send_dma)); mcp->mb[21] = MSW(MSD(mreq->send_dma)); - /* recieve data address */ + /* receive data address */ mcp->mb[16] = LSW(mreq->rcv_dma); mcp->mb[17] = MSW(mreq->rcv_dma); mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 76ec876e6b21..455fe134d31d 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2598,7 +2598,7 @@ qla82xx_calc_dsd_lists(uint16_t dsds) * qla82xx_start_scsi() - Send a SCSI command to the ISP * @sp: command to send to the ISP * - * Returns non-zero if a failure occured, else zero. + * Returns non-zero if a failure occurred, else zero. */ int qla82xx_start_scsi(srb_t *sp) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 75a966c94860..aa7747529165 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1046,7 +1046,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) eh_bus_reset_done: qla_printk(KERN_INFO, vha->hw, "%s: reset %s\n", __func__, - (ret == FAILED) ? "failed" : "succeded"); + (ret == FAILED) ? "failed" : "succeeded"); return ret; } @@ -1136,7 +1136,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) eh_host_reset_lock: qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__, - (ret == FAILED) ? "failed" : "succeded"); + (ret == FAILED) ? "failed" : "succeeded"); return ret; } @@ -3902,7 +3902,7 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha) continue; if (atomic_read(&other_pdev->enable_cnt)) { DEBUG17(qla_printk(KERN_INFO, ha, - "Found PCI func availabe and enabled at 0x%x\n", + "Found PCI func available and enabled at 0x%x\n", fn)); pci_dev_put(other_pdev); break; diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index c1f8d1b150f7..4757878d59dd 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -182,7 +182,7 @@ struct srb { uint16_t flags; /* (1) Status flags. */ #define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */ -#define SRB_GOT_SENSE BIT_4 /* sense data recieved. */ +#define SRB_GOT_SENSE BIT_4 /* sense data received. */ uint8_t state; /* (1) Status flags. */ #define SRB_NO_QUEUE_STATE 0 /* Request is in between states */ diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index bbb2e903d38a..48e2241ddaf4 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -1338,7 +1338,7 @@ exit_init_hba: } DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no, - status == QLA_ERROR ? "FAILED" : "SUCCEDED")); + status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); return status; } diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h index b3831bd29479..945cc328f57f 100644 --- a/drivers/scsi/qla4xxx/ql4_nvram.h +++ b/drivers/scsi/qla4xxx/ql4_nvram.h @@ -28,7 +28,7 @@ #define FM93C56A_ERASE 0x3 #define FM93C56A_ERASE_ALL 0x0 -/* Command Extentions */ +/* Command Extensions */ #define FM93C56A_WEN_EXT 0x3 #define FM93C56A_WRITE_ALL_EXT 0x1 #define FM93C56A_WDS_EXT 0x0 diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index a4acb0dd7beb..230ba097d28c 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -1213,7 +1213,7 @@ recover_ha_init_adapter: clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, - status == QLA_ERROR ? "FAILED" : "SUCCEDED")); + status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); return status; } @@ -2110,7 +2110,7 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d: Abort command - %s\n", - ha->host_no, id, lun, (ret == SUCCESS) ? "succeded" : "failed"); + ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed"); return ret; } @@ -2278,7 +2278,7 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) return_status = SUCCESS; ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", - return_status == FAILED ? "FAILED" : "SUCCEDED"); + return_status == FAILED ? "FAILED" : "SUCCEEDED"); return return_status; } @@ -2492,7 +2492,7 @@ qla4xxx_pci_slot_reset(struct pci_dev *pdev) /* Initialize device or resume if in suspended state */ rc = pci_enable_device(pdev); if (rc) { - ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Cant re-enable " + ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable " "device after reset\n", ha->host_no, __func__); goto exit_slot_reset; } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index fa5758cbdedb..6888b2ca5bfc 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2454,7 +2454,7 @@ static void scsi_debug_slave_destroy(struct scsi_device *sdp) printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (devip) { - /* make this slot avaliable for re-use */ + /* make this slot available for re-use */ devip->used = 0; sdp->hostdata = NULL; } diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index a2ed201885ae..26a8a45584ef 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -499,7 +499,7 @@ scsi_netlink_init(void) SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL, THIS_MODULE); if (!scsi_nl_sock) { - printk(KERN_ERR "%s: register of recieve handler failed\n", + printk(KERN_ERR "%s: register of receive handler failed\n", __func__); netlink_unregister_notifier(&scsi_netlink_notifier); return; diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index f67282058ba1..8bca8c25ba69 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -93,7 +93,7 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, /* * The blk helpers are used to the READ/WRITE requests - * transfering data from a initiator point of view. Since + * transferring data from a initiator point of view. Since * we are in target mode we want the opposite. */ rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 2941d2d92c94..fdf3fa639056 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -2378,7 +2378,7 @@ fc_flush_devloss(struct Scsi_Host *shost) * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host. * @shost: Which &Scsi_Host * - * This routine is expected to be called immediately preceeding the + * This routine is expected to be called immediately preceding the * a driver's call to scsi_remove_host(). * * WARNING: A driver utilizing the fc_transport, which fails to call @@ -2458,7 +2458,7 @@ static void fc_terminate_rport_io(struct fc_rport *rport) } /** - * fc_starget_delete - called to delete the scsi decendents of an rport + * fc_starget_delete - called to delete the scsi descendants of an rport * @work: remote port to be operated on. * * Deletes target and all sdevs. diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index b61ebec6bca7..bd0806e64e85 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1055,7 +1055,7 @@ static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) * @arg: this is third argument given to ioctl(2) system call. * Often contains a pointer. * - * Returns 0 if successful (some ioctls return postive numbers on + * Returns 0 if successful (some ioctls return positive numbers on * success as well). Returns a negated errno value in case of error. * * Note: most ioctls are forward onto the block subsystem or further diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index aefadc6a1607..95019c747cc1 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -567,7 +567,7 @@ static const struct block_device_operations sr_bdops = .revalidate_disk = sr_block_revalidate_disk, /* * No compat_ioctl for now because sr_block_ioctl never - * seems to pass arbitary ioctls down to host drivers. + * seems to pass arbitrary ioctls down to host drivers. */ }; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 4f0e5485ffde..07eaef1c722b 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -467,7 +467,7 @@ static void free_all_tags( void ) * * Parameters: struct scsi_cmnd *cmd * The command to work on. The first scatter buffer's data are - * assumed to be already transfered into ptr/this_residual. + * assumed to be already transferred into ptr/this_residual. */ static void merge_contiguous_buffers(struct scsi_cmnd *cmd) @@ -1717,7 +1717,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd, * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes are transfered or exit + * maximum number of bytes, 0 if all bytes are transferred or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. @@ -1904,7 +1904,7 @@ static int do_abort (struct Scsi_Host *host) * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transfered or exit + * maximum number of bytes, 0 if all bytes or transferred or exit * is in same phase. * * Also, *phase, *count, *data are modified in place. diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 190107ae120b..012c86edd59f 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -774,7 +774,7 @@ static int sym53c416_host_reset(Scsi_Cmnd *SCpnt) /* printk("sym53c416_reset\n"); */ base = SCpnt->device->host->io_port; - /* search scsi_id - fixme, we shouldnt need to iterate for this! */ + /* search scsi_id - fixme, we shouldn't need to iterate for this! */ for(i = 0; i < host_index && scsi_id == -1; i++) if(hosts[i].base == base) scsi_id = hosts[i].scsi_id; diff --git a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h index 7b08d6caaa99..63952ee300b5 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw1.h +++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h @@ -1449,7 +1449,7 @@ static struct SYM_FWB_SCR SYM_FWB_SCR = { PADDR_B (msg_weird_seen), /* * We donnot handle extended messages from SCRIPTS. - * Read the amount of data correponding to the + * Read the amount of data corresponding to the * message length and call the C code. */ SCR_COPY (1), diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h index ae1fb179b88e..c87d72443a16 100644 --- a/drivers/scsi/sym53c8xx_2/sym_fw2.h +++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h @@ -1326,7 +1326,7 @@ static struct SYM_FWB_SCR SYM_FWB_SCR = { PADDR_B (msg_weird_seen), /* * We donnot handle extended messages from SCRIPTS. - * Read the amount of data correponding to the + * Read the amount of data corresponding to the * message length and call the C code. */ SCR_STORE_REL (scratcha, 1), diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index 2c3e89ddf069..d92fe4037e94 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -2457,7 +2457,7 @@ static void sym_int_ma (struct sym_hcb *np) } /* - * The data in the dma fifo has not been transfered to + * The data in the dma fifo has not been transferred to * the target -> add the amount to the rest * and clear the data. * Check the sstat2 register in case of wide transfer. @@ -5094,7 +5094,7 @@ fail: } /* - * Lun control block deallocation. Returns the number of valid remaing LCBs + * Lun control block deallocation. Returns the number of valid remaining LCBs * for the target. */ int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln) diff --git a/drivers/scsi/sym53c8xx_2/sym_malloc.c b/drivers/scsi/sym53c8xx_2/sym_malloc.c index 883cac10daf9..6f9af0de7ec3 100644 --- a/drivers/scsi/sym53c8xx_2/sym_malloc.c +++ b/drivers/scsi/sym53c8xx_2/sym_malloc.c @@ -50,7 +50,7 @@ * from the SCRIPTS code. In addition, cache line alignment * is guaranteed for power of 2 cache line size. * - * This allocator has been developped for the Linux sym53c8xx + * This allocator has been developed for the Linux sym53c8xx * driver, since this O/S does not provide naturally aligned * allocations. * It has the advantage of allowing the driver to use private diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 5f697e0bd009..4468ae3610f7 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -1843,7 +1843,7 @@ check_setup_args(char *key, int *flags, int *val, char *buf) * * The original driver used to rely on a fixed sx_table, containing periods * for (only) the lower limits of the respective input-clock-frequency ranges - * (8-10/12-15/16-20 MHz). Although it seems, that no problems ocurred with + * (8-10/12-15/16-20 MHz). Although it seems, that no problems occurred with * this setting so far, it might be desirable to adjust the transfer periods * closer to the really attached, possibly 25% higher, input-clock, since * - the wd33c93 may really use a significant shorter period, than it has diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index db451ae0a368..9ee0afef2d16 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -837,7 +837,7 @@ static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed) } } - /* Take the lock, then check we didnt get beaten, if so try again */ + /* Take the lock, then check we didn't get beaten, if so try again */ spin_lock_irqsave(&scbpool_lock, flags); if (freescbs < needed) { spin_unlock_irqrestore(&scbpool_lock, flags); diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c index 04113e5304a0..1e824fb1649b 100644 --- a/drivers/sfi/sfi_core.c +++ b/drivers/sfi/sfi_core.c @@ -515,7 +515,7 @@ void __init sfi_init_late(void) } /* - * The reason we put it here becasue we need wait till the /sys/firmware + * The reason we put it here because we need wait till the /sys/firmware * is setup, then our interface can be registered in /sys/firmware/sfi */ core_initcall(sfi_sysfs_init); diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 5a4e0afb9ad6..5825370bad25 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -661,7 +661,7 @@ static void readwriter(struct pl022 *pl022) { /* - * The FIFO depth is different inbetween primecell variants. + * The FIFO depth is different between primecell variants. * I believe filling in too much in the FIFO might cause * errons in 8bit wide transfers on ARM variants (just 8 words * FIFO, means only 8x8 = 64 bits in FIFO) at least. @@ -722,7 +722,7 @@ static void readwriter(struct pl022 *pl022) * This inner reader takes care of things appearing in the RX * FIFO as we're transmitting. This will happen a lot since the * clock starts running when you put things into the TX FIFO, - * and then things are continously clocked into the RX FIFO. + * and then things are continuously clocked into the RX FIFO. */ while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) && (pl022->rx < pl022->rx_end)) { @@ -842,7 +842,7 @@ static void dma_callback(void *data) unmap_free_dma_scatter(pl022); - /* Update total bytes transfered */ + /* Update total bytes transferred */ msg->actual_length += pl022->cur_transfer->len; if (pl022->cur_transfer->cs_change) pl022->cur_chip-> @@ -1224,7 +1224,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) "number of bytes on a 16bit bus?)\n", (u32) (pl022->rx - pl022->rx_end)); } - /* Update total bytes transfered */ + /* Update total bytes transferred */ msg->actual_length += pl022->cur_transfer->len; if (pl022->cur_transfer->cs_change) pl022->cur_chip-> @@ -1415,11 +1415,11 @@ static void do_polling_transfer(struct pl022 *pl022) SSP_CR1(pl022->virtbase)); dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n"); - /* FIXME: insert a timeout so we don't hang here indefinately */ + /* FIXME: insert a timeout so we don't hang here indefinitely */ while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) readwriter(pl022); - /* Update total byte transfered */ + /* Update total byte transferred */ message->actual_length += pl022->cur_transfer->len; if (pl022->cur_transfer->cs_change) pl022->cur_chip->cs_control(SSP_CHIP_DESELECT); @@ -2129,7 +2129,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) "probe - problem registering spi master\n"); goto err_spi_register; } - dev_dbg(dev, "probe succeded\n"); + dev_dbg(dev, "probe succeeded\n"); /* * Disable the silicon block pclk and any voltage domain and just * power it up and clock it when it's needed @@ -2184,7 +2184,7 @@ pl022_remove(struct amba_device *adev) spi_unregister_master(pl022->master); spi_master_put(pl022->master); amba_set_drvdata(adev, NULL); - dev_dbg(&adev->dev, "remove succeded\n"); + dev_dbg(&adev->dev, "remove succeeded\n"); return 0; } diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c index 3c9ade69643f..b50563d320e1 100644 --- a/drivers/spi/au1550_spi.c +++ b/drivers/spi/au1550_spi.c @@ -480,7 +480,7 @@ static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw) au1xxx_dbdma_stop(hw->dma_rx_ch); au1xxx_dbdma_stop(hw->dma_tx_ch); - /* get number of transfered bytes */ + /* get number of transferred bytes */ hw->rx_count = hw->len - au1xxx_get_dma_residue(hw->dma_rx_ch); hw->tx_count = hw->len - au1xxx_get_dma_residue(hw->dma_tx_ch); diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 9a6196461b27..b1a4b9f503ae 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -345,7 +345,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg) void dw_spi_xfer_done(struct dw_spi *dws) { - /* Update total byte transfered return count actual bytes read */ + /* Update total byte transferred return count actual bytes read */ dws->cur_msg->actual_length += dws->len; /* Move to next transfer */ diff --git a/drivers/spi/dw_spi.h b/drivers/spi/dw_spi.h index fb0bce564844..b23e452adaf7 100644 --- a/drivers/spi/dw_spi.h +++ b/drivers/spi/dw_spi.h @@ -46,7 +46,7 @@ #define SPI_INT_RXFI (1 << 4) #define SPI_INT_MSTI (1 << 5) -/* TX RX interrupt level threshhold, max can be 256 */ +/* TX RX interrupt level threshold, max can be 256 */ #define SPI_INT_THRESHOLD 32 enum dw_ssi_type { diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c index 0ba35df9a6df..d3570071e98f 100644 --- a/drivers/spi/ep93xx_spi.c +++ b/drivers/spi/ep93xx_spi.c @@ -512,7 +512,7 @@ static int ep93xx_spi_read_write(struct ep93xx_spi *espi) * * This function processes one SPI transfer given in @t. Function waits until * transfer is complete (may sleep) and updates @msg->status based on whether - * transfer was succesfully processed or not. + * transfer was successfully processed or not. */ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, struct spi_message *msg, diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index a429b01d0285..9c74aad6be93 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -700,7 +700,7 @@ static void int_transfer_complete(struct driver_data *drv_data) if (!pxa25x_ssp_comp(drv_data)) write_SSTO(0, reg); - /* Update total byte transfered return count actual bytes read */ + /* Update total byte transferred return count actual bytes read */ drv_data->cur_msg->actual_length += drv_data->len - (drv_data->rx_end - drv_data->rx); @@ -759,7 +759,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) /* * PXA25x_SSP has no timeout, set up rx threshould for the - * remaing RX bytes. + * remaining RX bytes. */ if (pxa25x_ssp_comp(drv_data)) { diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 34bb17f03019..82b9a428c323 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -957,7 +957,7 @@ EXPORT_SYMBOL_GPL(spi_sync); * drivers may DMA directly into and out of the message buffers. * * This call should be used by drivers that require exclusive access to the - * SPI bus. It has to be preceeded by a spi_bus_lock call. The SPI bus must + * SPI bus. It has to be preceded by a spi_bus_lock call. The SPI bus must * be released by a spi_bus_unlock call when the exclusive access is over. * * It returns zero on success, else a negative error code. diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index a28462486df8..bdb7289a1d22 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -905,7 +905,7 @@ static void bfin_spi_pump_transfers(unsigned long data) "IO write error!\n"); message->state = ERROR_STATE; } else { - /* Update total byte transfered */ + /* Update total byte transferred */ message->actual_length += drv_data->len_in_bytes; /* Move to next transfer of this msg */ message->state = bfin_spi_next_transfer(drv_data); diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c index 900e921ab80e..496f895a0024 100644 --- a/drivers/spi/spi_fsl_espi.c +++ b/drivers/spi/spi_fsl_espi.c @@ -474,7 +474,7 @@ static int fsl_espi_setup(struct spi_device *spi) mpc8xxx_spi = spi_master_get_devdata(spi->master); reg_base = mpc8xxx_spi->reg_base; - hw_mode = cs->hw_mode; /* Save orginal settings */ + hw_mode = cs->hw_mode; /* Save original settings */ cs->hw_mode = mpc8xxx_spi_read_reg( ®_base->csmode[spi->chip_select]); /* mask out bits we are going to set */ diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index a467b20baac8..6f34963b3c64 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -670,7 +670,7 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, ssb_printk(KERN_ERR PFX "No SPROM available!\n"); return -ENODEV; } - if (bus->chipco.dev) { /* can be unavailible! */ + if (bus->chipco.dev) { /* can be unavailable! */ /* * get SPROM offset: SSB_SPROM_BASE1 except for * chipcommon rev >= 31 or chip ID is 0x4312 and diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c index 4f7cc8d13277..5f34d7a3e3a5 100644 --- a/drivers/ssb/sprom.c +++ b/drivers/ssb/sprom.c @@ -185,7 +185,7 @@ bool ssb_is_sprom_available(struct ssb_bus *bus) /* this routine differs from specs as we do not access SPROM directly on PCMCIA */ if (bus->bustype == SSB_BUSTYPE_PCI && - bus->chipco.dev && /* can be unavailible! */ + bus->chipco.dev && /* can be unavailable! */ bus->chipco.dev->id.revision >= 31) return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM; diff --git a/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c b/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c index c6488e0d1305..41223f953589 100644 --- a/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c +++ b/drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c @@ -237,7 +237,7 @@ static int CreditsAvailableCallback(void *pContext, int Credits, bool CreditIRQE pProt->CreditsCurrentSeek)); if (pProt->CreditsAvailable >= pProt->CreditsCurrentSeek) { - /* we have enough credits to fullfill at least 1 packet waiting in the queue */ + /* we have enough credits to fulfill at least 1 packet waiting in the queue */ pProt->CreditsCurrentSeek = 0; pProt->SendStateFlags &= ~HCI_SEND_WAIT_CREDITS; doPendingSends = true; @@ -285,7 +285,7 @@ static void FailureCallback(void *pContext, int Status) { struct gmbox_proto_hci_uart *pProt = (struct gmbox_proto_hci_uart *)pContext; - /* target assertion occured */ + /* target assertion occurred */ NotifyTransportFailure(pProt, Status); } @@ -507,7 +507,7 @@ static int HCIUartMessagePending(void *pContext, u8 LookAheadBytes[], int ValidB } while (false); - /* check if we need to disable the reciever */ + /* check if we need to disable the receiver */ if (status || blockRecv) { DevGMboxIRQAction(pProt->pDev, GMBOX_RECV_IRQ_DISABLE, PROC_IO_SYNC); } diff --git a/drivers/staging/ath6kl/include/aggr_recv_api.h b/drivers/staging/ath6kl/include/aggr_recv_api.h index 67a058492c4d..5ead58d5febd 100644 --- a/drivers/staging/ath6kl/include/aggr_recv_api.h +++ b/drivers/staging/ath6kl/include/aggr_recv_api.h @@ -72,7 +72,7 @@ aggr_process_bar(void *cntxt, u8 tid, u16 seq_no); * This event is to initiate/modify the receive side window. * Target will send WMI_ADDBA_REQ_EVENTID event to host - to setup * recv re-ordering queues. Target will negotiate ADDBA with peer, - * and indicate via this event after succesfully completing the + * and indicate via this event after successfully completing the * negotiation. This happens in two situations: * 1. Initial setup of aggregation * 2. Renegotiation of current recv window. diff --git a/drivers/staging/ath6kl/include/common/a_hci.h b/drivers/staging/ath6kl/include/common/a_hci.h index 08cb013090be..379d65224e3a 100644 --- a/drivers/staging/ath6kl/include/common/a_hci.h +++ b/drivers/staging/ath6kl/include/common/a_hci.h @@ -124,7 +124,7 @@ #define PAL_NUM_COMPL_DATA_BLOCK_EVENT 0x48 #define PAL_SHORT_RANGE_MODE_CHANGE_COMPL_EVENT 0x4C #define PAL_AMP_STATUS_CHANGE_EVENT 0x4D -/*======== End of PAL events definiton =================*/ +/*======== End of PAL events definition =================*/ /*======== Timeouts (not part of HCI cmd, but input to PAL engine) =========*/ @@ -430,7 +430,7 @@ typedef struct hci_event_hw_err_t { u8 hw_err_code; } POSTPACK HCI_EVENT_HW_ERR; -/* Flush occured event */ +/* Flush occurred event */ /* Qos Violation event */ typedef struct hci_event_handle_t { u8 event_code; diff --git a/drivers/staging/ath6kl/include/common/dbglog.h b/drivers/staging/ath6kl/include/common/dbglog.h index 3a3d00da0b81..b7a123086ccf 100644 --- a/drivers/staging/ath6kl/include/common/dbglog.h +++ b/drivers/staging/ath6kl/include/common/dbglog.h @@ -44,7 +44,7 @@ extern "C" { #define DBGLOG_MODULEID_NUM_MAX 16 /* Upper limit is width of mask */ /* - * Please ensure that the definition of any new module intrduced is captured + * Please ensure that the definition of any new module introduced is captured * between the DBGLOG_MODULEID_START and DBGLOG_MODULEID_END defines. The * structure is required for the parser to correctly pick up the values for * different modules. diff --git a/drivers/staging/ath6kl/include/common/epping_test.h b/drivers/staging/ath6kl/include/common/epping_test.h index 5c40d8a2229d..7027fac8f37e 100644 --- a/drivers/staging/ath6kl/include/common/epping_test.h +++ b/drivers/staging/ath6kl/include/common/epping_test.h @@ -92,7 +92,7 @@ typedef PREPACK struct { #define EPPING_CMD_RESET_RECV_CNT 2 /* reset recv count */ #define EPPING_CMD_CAPTURE_RECV_CNT 3 /* fetch recv count, 4-byte count returned in CmdBuffer_t */ #define EPPING_CMD_NO_ECHO 4 /* non-echo packet test (tx-only) */ -#define EPPING_CMD_CONT_RX_START 5 /* continous RX packets, parameters are in CmdBuffer_h */ +#define EPPING_CMD_CONT_RX_START 5 /* continuous RX packets, parameters are in CmdBuffer_h */ #define EPPING_CMD_CONT_RX_STOP 6 /* stop continuous RX packet transmission */ /* test command parameters may be no more than 8 bytes */ diff --git a/drivers/staging/ath6kl/include/common/ini_dset.h b/drivers/staging/ath6kl/include/common/ini_dset.h index 8bfc75940c8f..a9e05fa0f659 100644 --- a/drivers/staging/ath6kl/include/common/ini_dset.h +++ b/drivers/staging/ath6kl/include/common/ini_dset.h @@ -31,7 +31,7 @@ */ typedef enum { #if defined(AR6002_REV4) || defined(AR6003) -/* Add these definitions for compatability */ +/* Add these definitions for compatibility */ #define WHAL_INI_DATA_ID_BB_RFGAIN_LNA1 WHAL_INI_DATA_ID_BB_RFGAIN #define WHAL_INI_DATA_ID_BB_RFGAIN_LNA2 WHAL_INI_DATA_ID_BB_RFGAIN WHAL_INI_DATA_ID_NULL =0, diff --git a/drivers/staging/ath6kl/include/common/testcmd.h b/drivers/staging/ath6kl/include/common/testcmd.h index 9ca1f2ac2cbf..7d94aee508b3 100644 --- a/drivers/staging/ath6kl/include/common/testcmd.h +++ b/drivers/staging/ath6kl/include/common/testcmd.h @@ -43,8 +43,8 @@ typedef enum { PN15_PATTERN }TX_DATA_PATTERN; -/* Continous tx - mode : TCMD_CONT_TX_OFF - Disabling continous tx +/* Continuous tx + mode : TCMD_CONT_TX_OFF - Disabling continuous tx TCMD_CONT_TX_SINE - Enable continuous unmodulated tx TCMD_CONT_TX_FRAME- Enable continuous modulated tx freq : Channel freq in Mhz. (e.g 2412 for channel 1 in 11 g) diff --git a/drivers/staging/ath6kl/include/common/wmi.h b/drivers/staging/ath6kl/include/common/wmi.h index c645af373442..4e6343485362 100644 --- a/drivers/staging/ath6kl/include/common/wmi.h +++ b/drivers/staging/ath6kl/include/common/wmi.h @@ -1568,8 +1568,8 @@ typedef PREPACK struct { switch to ps-poll mode default = 3 */ - u32 scoContStompMax; /* max number of continous stomp allowed in opt mode. - if excedded switch to pspoll mode + u32 scoContStompMax; /* max number of continuous stomp allowed in opt mode. + if exceeded switch to pspoll mode default = 3 */ u32 scoMinlowRateMbps; /* Low rate threshold */ @@ -2084,7 +2084,7 @@ typedef PREPACK struct { /* * BSS INFO HDR version 2.0 * With 6 bytes HTC header and 6 bytes of WMI header - * WMI_BSS_INFO_HDR cannot be accomodated in the removed 802.11 management + * WMI_BSS_INFO_HDR cannot be accommodated in the removed 802.11 management * header space. * - Reduce the ieMask to 2 bytes as only two bit flags are used * - Remove rssi and compute it on the host. rssi = snr - 95 @@ -2911,7 +2911,7 @@ typedef PREPACK struct { u8 pktID; /* packet ID to identify parent packet */ u8 rateIdx; /* rate index on successful transmission */ u8 ackFailures; /* number of ACK failures in tx attempt */ -#if 0 /* optional params currently ommitted. */ +#if 0 /* optional params currently omitted. */ u32 queueDelay; // usec delay measured Tx Start time - host delivery time u32 mediaDelay; // usec delay measured ACK rx time - host delivery time #endif diff --git a/drivers/staging/ath6kl/include/common/wmix.h b/drivers/staging/ath6kl/include/common/wmix.h index 5ebb8285d135..36acba66d49f 100644 --- a/drivers/staging/ath6kl/include/common/wmix.h +++ b/drivers/staging/ath6kl/include/common/wmix.h @@ -191,7 +191,7 @@ typedef PREPACK struct { } POSTPACK WMIX_GPIO_INTR_ACK_CMD; /* - * Target informs Host of GPIO interrupts that have ocurred since the + * Target informs Host of GPIO interrupts that have occurred since the * last WMIX_GIPO_INTR_ACK_CMD was received. Additional information -- * the current GPIO input values is provided -- in order to support * use of a GPIO interrupt as a Data Valid signal for other GPIO pins. diff --git a/drivers/staging/ath6kl/include/htc_api.h b/drivers/staging/ath6kl/include/htc_api.h index 1bc2488788ab..4fb767559f82 100644 --- a/drivers/staging/ath6kl/include/htc_api.h +++ b/drivers/staging/ath6kl/include/htc_api.h @@ -209,7 +209,7 @@ struct htc_endpoint_credit_dist { typedef enum _HTC_CREDIT_DIST_REASON { HTC_CREDIT_DIST_SEND_COMPLETE = 0, /* credits available as a result of completed send operations (MANDATORY) resulting in credit reports */ - HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occured (OPTIONAL) */ + HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occurred (OPTIONAL) */ HTC_CREDIT_DIST_SEEK_CREDITS, /* an endpoint needs to "seek" credits (OPTIONAL) */ HTC_DUMP_CREDIT_STATE /* for debugging, dump any state information that is kept by the distribution function */ @@ -253,7 +253,7 @@ struct htc_endpoint_stats { u32 RxPacketsBundled; /* count of recv packets received in a bundle */ u32 RxBundleLookAheads; /* count of number of bundled lookaheads */ u32 RxBundleIndFromHdr; /* count of the number of bundle indications from the HTC header */ - u32 RxAllocThreshHit; /* count of the number of times the recv allocation threshhold was hit */ + u32 RxAllocThreshHit; /* count of the number of times the recv allocation threshold was hit */ u32 RxAllocThreshBytes; /* total number of bytes */ }; @@ -391,7 +391,7 @@ int HTCSendPkt(HTC_HANDLE HTCHandle, struct htc_packet *pPacket); +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ void HTCStop(HTC_HANDLE HTCHandle); /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - @desc: Destory HTC service + @desc: Destroy HTC service @function name: HTCDestroy @input: HTCHandle @output: diff --git a/drivers/staging/ath6kl/miscdrv/credit_dist.c b/drivers/staging/ath6kl/miscdrv/credit_dist.c index ae54e1f48e50..33fa0209026d 100644 --- a/drivers/staging/ath6kl/miscdrv/credit_dist.c +++ b/drivers/staging/ath6kl/miscdrv/credit_dist.c @@ -341,7 +341,7 @@ static void SeekCredits(struct common_credit_state_info *pCredInfo, credits = min(pCredInfo->CurrentFreeCredits,pEPDist->TxCreditsSeek); if (credits >= pEPDist->TxCreditsSeek) { - /* we found some to fullfill the seek request */ + /* we found some to fulfill the seek request */ break; } @@ -364,8 +364,8 @@ static void SeekCredits(struct common_credit_state_info *pCredInfo, if ((pCurEpDist->TxCreditsAssigned - need) >= pCurEpDist->TxCreditsMin) { /* the current one has been allocated more than it's minimum and it - * has enough credits assigned above it's minimum to fullfill our need - * try to take away just enough to fullfill our need */ + * has enough credits assigned above it's minimum to fulfill our need + * try to take away just enough to fulfill our need */ ReduceCredits(pCredInfo, pCurEpDist, pCurEpDist->TxCreditsAssigned - need); diff --git a/drivers/staging/ath6kl/os/linux/ar6000_android.c b/drivers/staging/ath6kl/os/linux/ar6000_android.c index c96f6e9c99c6..4aa75ee2cb13 100644 --- a/drivers/staging/ath6kl/os/linux/ar6000_android.c +++ b/drivers/staging/ath6kl/os/linux/ar6000_android.c @@ -372,7 +372,7 @@ void android_ar6k_check_wow_status(struct ar6_softc *ar, struct sk_buff *skb, bo } } if (needWake) { - /* keep host wake up if there is any event and packate comming in*/ + /* keep host wake up if there is any event and packate coming in*/ if (wowledon) { char buf[32]; int len = sprintf(buf, "on"); diff --git a/drivers/staging/ath6kl/os/linux/ar6000_drv.c b/drivers/staging/ath6kl/os/linux/ar6000_drv.c index 27cb02dfad3c..97d6ce63b5c0 100644 --- a/drivers/staging/ath6kl/os/linux/ar6000_drv.c +++ b/drivers/staging/ath6kl/os/linux/ar6000_drv.c @@ -520,7 +520,7 @@ dbglog_parse_debug_logs(s8 *datap, u32 len) int ar6000_dbglog_get_debug_logs(struct ar6_softc *ar) { - u32 data[8]; /* Should be able to accomodate struct dbglog_buf_s */ + u32 data[8]; /* Should be able to accommodate struct dbglog_buf_s */ u32 address; u32 length; u32 dropped; @@ -2063,7 +2063,7 @@ ar6000_stop_endpoint(struct net_device *dev, bool keepprofile, bool getdbglogs) * - In case of surprise removal, the hcd already frees up the pending * for the device and hence there is no need to unregister the function * driver inorder to get these requests. For planned removal, the function - * driver has to explictly unregister itself to have the hcd return all the + * driver has to explicitly unregister itself to have the hcd return all the * pending requests before the data structures for the devices are freed up. * Note that as per the current implementation, the function driver will * end up releasing all the devices since there is no API to selectively @@ -2982,7 +2982,7 @@ ar6000_data_tx(struct sk_buff *skb, struct net_device *dev) /* If target is not associated */ if( (!ar->arConnected && !bypasswmi) #ifdef CONFIG_HOST_TCMD_SUPPORT - /* TCMD doesnt support any data, free the buf and return */ + /* TCMD doesn't support any data, free the buf and return */ || (ar->arTargetMode == AR6000_TCMD_MODE) #endif ) { @@ -6393,7 +6393,7 @@ static void DoHTCSendPktsTest(struct ar6_softc *ar, int MapNo, HTC_ENDPOINT_ID e /* * Add support for adding and removing a virtual adapter for soft AP. * Some OS requires different adapters names for station and soft AP mode. - * To support these requirement, create and destory a netdevice instance + * To support these requirement, create and destroy a netdevice instance * when the AP mode is operational. A full fledged support for virual device * is not implemented. Rather a virtual interface is created and is linked * with the existing physical device instance during the operation of the diff --git a/drivers/staging/ath6kl/wmi/wmi.c b/drivers/staging/ath6kl/wmi/wmi.c index 0ddaee21f9d7..a00bf0a59871 100644 --- a/drivers/staging/ath6kl/wmi/wmi.c +++ b/drivers/staging/ath6kl/wmi/wmi.c @@ -4867,7 +4867,7 @@ wmi_set_country(struct wmi_t *wmip, u8 *countryCode) #ifdef CONFIG_HOST_TCMD_SUPPORT /* WMI layer doesn't need to know the data type of the test cmd. This would be beneficial for customers like Qualcomm, who might - have different test command requirements from differnt manufacturers + have different test command requirements from different manufacturers */ int wmi_test_cmd(struct wmi_t *wmip, u8 *buf, u32 len) diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h index 32909e2938d5..20cca24ff5f0 100644 --- a/drivers/staging/bcm/Adapter.h +++ b/drivers/staging/bcm/Adapter.h @@ -412,7 +412,7 @@ struct _MINI_ADAPTER // this to keep track of the Tx and Rx MailBox Registers. atomic_t CurrNumFreeTxDesc; - // to keep track the no of byte recieved + // to keep track the no of byte received USHORT PrevNumRecvDescs; USHORT CurrNumRecvDescs; UINT u32TotalDSD; @@ -527,7 +527,7 @@ struct _MINI_ADAPTER BOOLEAN bStatusWrite; UINT uiNVMDSDSize; UINT uiVendorExtnFlag; - //it will always represent choosed DSD at any point of time. + //it will always represent chosen DSD at any point of time. // Generally it is Active DSD but in case of NVM RD/WR it might be different. UINT ulFlashCalStart; ULONG ulFlashControlSectionStart; @@ -546,10 +546,10 @@ struct _MINI_ADAPTER PFLASH_CS_INFO psFlashCSInfo ; PFLASH2X_VENDORSPECIFIC_INFO psFlash2xVendorInfo; UINT uiFlashBaseAdd; //Flash start address - UINT uiActiveISOOffset; //Active ISO offset choosen before f/w download + UINT uiActiveISOOffset; //Active ISO offset chosen before f/w download FLASH2X_SECTION_VAL eActiveISO; //Active ISO section val - FLASH2X_SECTION_VAL eActiveDSD; //Active DSD val choosen before f/w download - UINT uiActiveDSDOffsetAtFwDld; //For accessing Active DSD choosen before f/w download + FLASH2X_SECTION_VAL eActiveDSD; //Active DSD val chosen before f/w download + UINT uiActiveDSDOffsetAtFwDld; //For accessing Active DSD chosen before f/w download UINT uiFlashLayoutMajorVersion ; UINT uiFlashLayoutMinorVersion; BOOLEAN bAllDSDWriteAllow ; diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index 9be184f143e5..c0ee95a71343 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -384,7 +384,7 @@ static inline VOID CopyClassifierRuleToSF(PMINI_ADAPTER Adapter,stConvergenceSLT } if(psfCSType->cCPacketClassificationRule.u8Protocol == 0) { - //we didnt get protocol field filled in by the BS + //we didn't get protocol field filled in by the BS pstClassifierEntry->ucProtocolLength=0; } else @@ -879,7 +879,7 @@ static VOID CopyToAdapter( register PMINI_ADAPTER Adapter, /**sfAuthorizedSet.u8TrafficIndicationPreference); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Recieved : 0x%X",pstAddIndication->sfAuthorizedSet.u8TotalClassifiers); + BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received : 0x%X",pstAddIndication->sfAuthorizedSet.u8TotalClassifiers); nCurClassifierCnt = pstAddIndication->sfAuthorizedSet.u8TotalClassifiers; @@ -1305,7 +1305,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficIndicationPreference : 0x%02X", pstAddIndication->sfAdmittedSet.u8TrafficIndicationPreference); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Recieved : 0x%X",pstAddIndication->sfAdmittedSet.u8TotalClassifiers); + BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received : 0x%X",pstAddIndication->sfAdmittedSet.u8TotalClassifiers); nCurClassifierCnt = pstAddIndication->sfAdmittedSet.u8TotalClassifiers; @@ -1502,7 +1502,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8TrafficIndicationPreference : 0x%X", pstAddIndication->sfActiveSet.u8TrafficIndicationPreference); - BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Recieved : 0x%X",pstAddIndication->sfActiveSet.u8TotalClassifiers); + BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received : 0x%X",pstAddIndication->sfActiveSet.u8TotalClassifiers); nCurClassifierCnt = pstAddIndication->sfActiveSet.u8TotalClassifiers; @@ -1696,7 +1696,7 @@ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *p //No Special handling send the message as it is return 1; } - // For DSA_REQ, only upto "psfAuthorizedSet" parameter should be accessed by driver! + // For DSA_REQ, only up to "psfAuthorizedSet" parameter should be accessed by driver! pstAddIndication=kmalloc(sizeof(*pstAddIndication), GFP_KERNEL); if(NULL==pstAddIndication) @@ -1788,7 +1788,7 @@ static inline stLocalSFAddIndicationAlt BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Inside RestoreCmControlResponseMessage "); /* //Need to Allocate memory to contain the SUPER Large structures - //Our driver cant create these structures on Stack :( + //Our driver can't create these structures on Stack :( */ pstAddIndicationDest=kmalloc(sizeof(stLocalSFAddIndicationAlt), GFP_KERNEL); @@ -1957,7 +1957,7 @@ INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter) { /* //Need to Allocate memory to contain the SUPER Large structures - //Our driver cant create these structures on Stack + //Our driver can't create these structures on Stack */ Adapter->caDsxReqResp=kmalloc(sizeof(stLocalSFAddIndicationAlt)+LEADER_SIZE, GFP_KERNEL); if(!Adapter->caDsxReqResp) diff --git a/drivers/staging/bcm/HostMIBSInterface.h b/drivers/staging/bcm/HostMIBSInterface.h index f17a4f13474c..e34531b638e8 100644 --- a/drivers/staging/bcm/HostMIBSInterface.h +++ b/drivers/staging/bcm/HostMIBSInterface.h @@ -62,7 +62,7 @@ typedef struct _S_MIBS_HOST_INFO ULONG NumDesUsed; ULONG CurrNumFreeDesc; ULONG PrevNumFreeDesc; - // to keep track the no of byte recieved + // to keep track the no of byte received ULONG PrevNumRcevBytes; ULONG CurrNumRcevBytes; diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c index 91b6fbe33c91..5b4fd372ec36 100644 --- a/drivers/staging/bcm/IPv6Protocol.c +++ b/drivers/staging/bcm/IPv6Protocol.c @@ -287,7 +287,7 @@ static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Head for(uiLoopIndex=0;uiLoopIndexstSrcIpAddress.ulIpv6Mask[uiLoopIndex]); @@ -340,7 +340,7 @@ static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Hea for(uiLoopIndex=0;uiLoopIndexstDestIpAddress.ulIpv6Mask[uiLoopIndex]); diff --git a/drivers/staging/bcm/InterfaceIdleMode.c b/drivers/staging/bcm/InterfaceIdleMode.c index bf5c0ad86610..96fa4ead7930 100644 --- a/drivers/staging/bcm/InterfaceIdleMode.c +++ b/drivers/staging/bcm/InterfaceIdleMode.c @@ -11,7 +11,7 @@ Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context Return: BCM_STATUS_SUCCESS - If Wakeup of the HW Interface was successful. - Other - If an error occured. + Other - If an error occurred. */ @@ -26,7 +26,7 @@ Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context Return: BCM_STATUS_SUCCESS - If Idle mode response related HW configuration was successful. - Other - If an error occured. + Other - If an error occurred. */ /* diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c index 220ff922bdcf..67719d57256d 100644 --- a/drivers/staging/bcm/InterfaceIsr.c +++ b/drivers/staging/bcm/InterfaceIsr.c @@ -80,8 +80,8 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/) } case -EINPROGRESS: { - //This situation may happend when URBunlink is used. for detail check usb_unlink_urb documentation. - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Impossibe condition has occured... something very bad is going on"); + //This situation may happened when URBunlink is used. for detail check usb_unlink_urb documentation. + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Impossibe condition has occurred... something very bad is going on"); break ; //return; } diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c index 533f8ebe0f84..806ef5d18522 100644 --- a/drivers/staging/bcm/InterfaceRx.c +++ b/drivers/staging/bcm/InterfaceRx.c @@ -34,7 +34,7 @@ GetBulkInRcb(PS_INTERFACE_ADAPTER psIntfAdapter) return pRcb; } -/*this is receive call back - when pkt avilable for receive (BULK IN- end point)*/ +/*this is receive call back - when pkt available for receive (BULK IN- end point)*/ static void read_bulk_callback(struct urb *urb) { struct sk_buff *skb = NULL; @@ -123,7 +123,7 @@ static void read_bulk_callback(struct urb *urb) if((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) || (!(pLeader->Status >= 0x20 && pLeader->Status <= 0x3F))) { - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Recived control pkt..."); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Received control pkt..."); *(PUSHORT)skb->data = pLeader->Status; memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer + (sizeof(LEADER)), pLeader->PLength); @@ -142,7 +142,7 @@ static void read_bulk_callback(struct urb *urb) * Data Packet, Format a proper Ethernet Header * and give it to the stack */ - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt..."); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt..."); skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES); memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(LEADER), pLeader->PLength); skb->dev = Adapter->dev; @@ -151,7 +151,7 @@ static void read_bulk_callback(struct urb *urb) skb_put (skb, pLeader->PLength + ETH_HLEN); Adapter->PackInfo[QueueIndex].uiTotalRxBytes+=pLeader->PLength; Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes+= pLeader->PLength; - BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt of len :0x%X", pLeader->PLength); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt of len :0x%X", pLeader->PLength); if(netif_running(Adapter->dev)) { @@ -237,7 +237,7 @@ Input parameters: IN PMINI_ADAPTER Adapter - Miniport Adapter Context Return: TRUE - If Rx was successful. - Other - If an error occured. + Other - If an error occurred. */ BOOLEAN InterfaceRx (PS_INTERFACE_ADAPTER psIntfAdapter) diff --git a/drivers/staging/bcm/Ioctl.h b/drivers/staging/bcm/Ioctl.h index e4f8eb70be1e..f859cf1c47b0 100644 --- a/drivers/staging/bcm/Ioctl.h +++ b/drivers/staging/bcm/Ioctl.h @@ -241,7 +241,7 @@ typedef struct bulkwrmbuffer typedef enum _FLASH2X_SECTION_VAL { - NO_SECTION_VAL = 0, //no section is choosen when absolute offset is given for RD/WR + NO_SECTION_VAL = 0, //no section is chosen when absolute offset is given for RD/WR ISO_IMAGE1, ISO_IMAGE2, DSD0, diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c index f4cf41c0e46b..a55d4228e8e0 100644 --- a/drivers/staging/bcm/LeakyBucket.c +++ b/drivers/staging/bcm/LeakyBucket.c @@ -213,7 +213,7 @@ static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF) BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo); BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n", psSF->uiCurrentTokenCount, iPacketLen); - //this part indicates that becuase of non-availability of the tokens + //this part indicates that because of non-availability of the tokens //pkt has not been send out hence setting the pending flag indicating the host to send it out //first next iteration . psSF->uiPendedLast = TRUE; diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index d624f35d0551..c5003b62234c 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -602,7 +602,7 @@ VOID LinkControlResponseMessage(PMINI_ADAPTER Adapter,PUCHAR pucBuffer) Adapter->LinkStatus=LINKUP_DONE; Adapter->bPHSEnabled = *(pucBuffer+3); Adapter->bETHCSEnabled = *(pucBuffer+4) & ETH_CS_MASK; - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "PHS Support Status Recieved In LinkUp Ack : %x \n",Adapter->bPHSEnabled); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "PHS Support Status Received In LinkUp Ack : %x \n",Adapter->bPHSEnabled); if((FALSE == Adapter->bShutStatus)&& (FALSE == Adapter->IdleMode)) { @@ -1153,7 +1153,7 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) /* * 1. If the LED Settings fails, do not stop and do the Firmware download. - * 2. This init would happend only if the cfg file is present, else + * 2. This init would happened only if the cfg file is present, else * call from the ioctl context. */ @@ -1185,7 +1185,7 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter) status = PropagateCalParamsFromFlashToMemory(ps_adapter); if(status) { - BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL," Propogation of Cal param failed .." ); + BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL," Propagation of Cal param failed .." ); goto OUT; } } diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index feade9451b2e..c97020f0fb6a 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -727,7 +727,7 @@ static BOOLEAN EthCSMatchVLANRules(S_CLASSIFIER_RULE *pstClassifierRule,struct s BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS UserPrio:%x CLS VLANID:%x\n",__FUNCTION__,ntohs(*((USHORT *)pstClassifierRule->usUserPriority)),pstClassifierRule->usVLANID); - /* In case FW didn't recieve the TLV, the priority field should be ignored */ + /* In case FW didn't receive the TLV, the priority field should be ignored */ if(pstClassifierRule->usValidityBitMap & (1<eNwpktEthFrameType!=eEth802QVLANFrame) diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h index 890778450a86..ab131806e2c9 100644 --- a/drivers/staging/bcm/cntrl_SignalingInterface.h +++ b/drivers/staging/bcm/cntrl_SignalingInterface.h @@ -21,7 +21,7 @@ #define VENDOR_PHS_PARAM_LENGTH 10 #define MAX_NUM_ACTIVE_BS 10 #define AUTH_TOKEN_LENGTH 10 -#define NUM_HARQ_CHANNELS 16 //Changed from 10 to 16 to accomodate all HARQ channels +#define NUM_HARQ_CHANNELS 16 //Changed from 10 to 16 to accommodate all HARQ channels #define VENDOR_CLASSIFIER_PARAM_LENGTH 1 //Changed the size to 1 byte since we dnt use it #define VENDOR_SPECIF_QOS_PARAM 1 #define VENDOR_PHS_PARAM_LENGTH 10 @@ -109,13 +109,13 @@ typedef struct _stPhsRuleSI { B_UINT8 u8PHSI; /** PHSF Length Of The Service Flow*/ B_UINT8 u8PHSFLength; - /** String of bytes containing header information to be supressed by the sending CS and reconstructed by the receiving CS*/ + /** String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS*/ B_UINT8 u8PHSF[MAX_PHS_LENGTHS]; /** PHSM Length Of The Service Flow*/ B_UINT8 u8PHSMLength; /** PHS Mask for the SF*/ B_UINT8 u8PHSM[MAX_PHS_LENGTHS]; - /** 8bit Total number of bytes to be supressed for the Service Flow*/ + /** 8bit Total number of bytes to be suppressed for the Service Flow*/ B_UINT8 u8PHSS; /** 8bit Indicates whether or not Packet Header contents need to be verified prior to supression */ B_UINT8 u8PHSV; diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c index c7292373a65f..4da5b7b54a1a 100644 --- a/drivers/staging/bcm/nvm.c +++ b/drivers/staging/bcm/nvm.c @@ -313,7 +313,7 @@ INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter) // uiNumBytes - Number of bytes to be read from the EEPROM. // // Returns: -// OSAL_STATUS_SUCCESS - if EEPROM read is successfull. +// OSAL_STATUS_SUCCESS - if EEPROM read is successful. // - if failed. //----------------------------------------------------------------------------- @@ -431,7 +431,7 @@ INT BeceemEEPROMBulkRead( // uiNumBytes - Number of bytes to be read from the FLASH. // // Returns: -// OSAL_STATUS_SUCCESS - if FLASH read is successfull. +// OSAL_STATUS_SUCCESS - if FLASH read is successful. // - if failed. //----------------------------------------------------------------------------- @@ -1174,7 +1174,7 @@ static INT BeceemFlashBulkWrite( if(NULL == pTempBuff) goto BeceemFlashBulkWrite_EXIT; // -// check if the data to be written is overlapped accross sectors +// check if the data to be written is overlapped across sectors // if(uiOffset+uiNumBytes < uiSectBoundary) { @@ -1390,7 +1390,7 @@ static INT BeceemFlashBulkWriteStatus( goto BeceemFlashBulkWriteStatus_EXIT; // -// check if the data to be written is overlapped accross sectors +// check if the data to be written is overlapped across sectors // if(uiOffset+uiNumBytes < uiSectBoundary) { @@ -2020,7 +2020,7 @@ INT BeceemEEPROMBulkWrite( // uiNumBytes - Number of bytes to be read from the NVM. // // Returns: -// OSAL_STATUS_SUCCESS - if NVM read is successfull. +// OSAL_STATUS_SUCCESS - if NVM read is successful. // - if failed. //----------------------------------------------------------------------------- @@ -2083,7 +2083,7 @@ INT BeceemNVMRead( // uiNumBytes - Number of bytes to be written.. // // Returns: -// OSAL_STATUS_SUCCESS - if NVM write is successfull. +// OSAL_STATUS_SUCCESS - if NVM write is successful. // - if failed. //----------------------------------------------------------------------------- @@ -2218,7 +2218,7 @@ INT BeceemNVMWrite( // uiSectorSize - sector size // // Returns: -// OSAL_STATUS_SUCCESS - if NVM write is successfull. +// OSAL_STATUS_SUCCESS - if NVM write is successful. // - if failed. //----------------------------------------------------------------------------- @@ -2430,7 +2430,7 @@ INT BcmInitNVM(PMINI_ADAPTER ps_adapter) *Input Parameter: * Adapter data structure *Return Value : -* 0. means sucess; +* 0. means success; */ /***************************************************************************/ @@ -2998,7 +2998,7 @@ INT BcmGetSectionValStartOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlas /* * Considering all the section for which end offset can be calculated or directly given * in CS Structure. if matching case does not exist, return STATUS_FAILURE indicating section - * endoffset can't be calculated or given in CS Stucture. + * endoffset can't be calculated or given in CS Structure. */ INT SectStartOffset = 0 ; @@ -3173,7 +3173,7 @@ INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2 * @uiNumBytes : Number of Bytes for Read * * Return value:- -* return true on sucess and STATUS_FAILURE on fail. +* return true on success and STATUS_FAILURE on fail. */ INT BcmFlash2xBulkRead( @@ -3241,7 +3241,7 @@ INT BcmFlash2xBulkRead( * @uiNumBytes : Number of Bytes for Write * * Return value:- -* return true on sucess and STATUS_FAILURE on fail. +* return true on success and STATUS_FAILURE on fail. * */ @@ -3308,7 +3308,7 @@ INT BcmFlash2xBulkWrite( * @Adapter :-Drivers private Data Structure * * Return Value:- -* Return STATUS_SUCESS if get sucess in setting the right DSD else negaive error code +* Return STATUS_SUCESS if get success in setting the right DSD else negaive error code * **/ static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter) @@ -3384,7 +3384,7 @@ static INT BcmGetActiveISO(PMINI_ADAPTER Adapter) * @uiOffset : Offset provided in the Flash * * Return Value:- -* Sucess:-TRUE , offset is writable +* Success:-TRUE , offset is writable * Failure:-FALSE, offset is RO * **/ @@ -3441,7 +3441,7 @@ static INT BcmDumpFlash2xSectionBitMap(PFLASH2X_BITMAP psFlash2xBitMap) @Adapter:-Driver private Data Structure * * Return value:- -* Sucess:- STATUS_SUCESS +* Success:- STATUS_SUCESS * Failure:- negative error code **/ @@ -3783,7 +3783,7 @@ INT BcmSetActiveSection(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectV // This is a SPECIAL Case which will only happen if the current highest priority ISO has priority value = 0x7FFFFFFF. // We will write 1 to the current Highest priority ISO And then shall increase the priority of the requested ISO // by user - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happend, eFlash2xSectVal: 0x%x\n",eFlash2xSectVal); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n",eFlash2xSectVal); SectImagePriority = htonl(0x1); Status = BcmFlash2xBulkWrite(Adapter, &SectImagePriority, @@ -3853,7 +3853,7 @@ INT BcmSetActiveSection(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectV // This is a SPECIAL Case which will only happen if the current highest priority DSD has priority value = 0x7FFFFFFF. // We will write 1 to the current Highest priority DSD And then shall increase the priority of the requested DSD // by user - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happend, eFlash2xSectVal: 0x%x\n",eFlash2xSectVal); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n",eFlash2xSectVal); SectImagePriority = htonl(0x1); Status = BcmFlash2xBulkWrite(Adapter, @@ -4119,7 +4119,7 @@ INT BcmCopyISO(PMINI_ADAPTER Adapter, FLASH2X_COPY_SECTION sCopySectStrut) MAX_RW_SIZE); IsThisHeaderSector = FALSE ; } - //substracting the written Data + //subtracting the written Data uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize ; } @@ -4250,7 +4250,7 @@ INT BcmCopyISO(PMINI_ADAPTER Adapter, FLASH2X_COPY_SECTION sCopySectStrut) IsThisHeaderSector = FALSE ; } - //substracting the written Data + //subtracting the written Data uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize ; } @@ -4268,7 +4268,7 @@ BcmFlash2xCorruptSig : this API is used to corrupt the written sig in Bcm Header @eFlash2xSectionVal :- Flash section val which has header Return Value :- - Sucess :- If Section is present and writable, corrupt the sig and return STATUS_SUCCESS + Success :- If Section is present and writable, corrupt the sig and return STATUS_SUCCESS Failure :-Return negative error code @@ -4301,7 +4301,7 @@ BcmFlash2xWriteSig :-this API is used to Write the sig if requested Section has @eFlashSectionVal :- Flash section val which has header Return Value :- - Sucess :- If Section is present and writable write the sig and return STATUS_SUCCESS + Success :- If Section is present and writable write the sig and return STATUS_SUCCESS Failure :-Return negative error code **/ @@ -4504,7 +4504,7 @@ BcmCopySection :- This API is used to copy the One section in another. Both sect in case of numofBytes equal zero complete section will be copied. Return Values- - Sucess : Return STATUS_SUCCESS + Success : Return STATUS_SUCCESS Faillure :- return negative error code **/ @@ -4621,7 +4621,7 @@ SaveHeaderIfPresent :- This API is use to Protect the Header in case of Header S @uiOffset :- Flash offset that has to be written. Return value :- - Sucess :- On sucess return STATUS_SUCCESS + Success :- On success return STATUS_SUCCESS Faillure :- Return negative error code **/ @@ -4634,7 +4634,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset) UINT uiSectAlignAddr = 0; UINT sig = 0; - //making the offset sector alligned + //making the offset sector aligned uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1); @@ -4643,7 +4643,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset) (uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter,DSD0)- Adapter->uiSectorSize)) { - //offset from the sector boundry having the header map + //offset from the sector boundary having the header map offsetToProtect = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader % Adapter->uiSectorSize; HeaderSizeToProtect = sizeof(DSD_HEADER); bHasHeader = TRUE ; @@ -4697,7 +4697,7 @@ BcmDoChipSelect : This will selcet the appropriate chip for writing. @Adapater :- Bcm Driver Private Data Structure OutPut:- - Select the Appropriate chip and retrn status Sucess + Select the Appropriate chip and retrn status Success **/ static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset) { @@ -5086,7 +5086,7 @@ static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSect { if(IsSectionWritable(Adapter,eFlash2xSectionVal) != TRUE) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section is not Writable...Hence cant Corrupt signature"); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section is not Writable...Hence can't Corrupt signature"); return SECTOR_IS_NOT_WRITABLE; } } @@ -5155,7 +5155,7 @@ static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSect if(IsSectionWritable(Adapter,eFlash2xSectionVal) != TRUE) { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section is not Writable...Hence cant Corrupt signature"); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Section is not Writable...Hence can't Corrupt signature"); return SECTOR_IS_NOT_WRITABLE; } diff --git a/drivers/staging/brcm80211/README b/drivers/staging/brcm80211/README index 99e67669f26b..f8facb0786ec 100644 --- a/drivers/staging/brcm80211/README +++ b/drivers/staging/brcm80211/README @@ -71,7 +71,7 @@ the driver. The devices use a single worldwide regulatory domain, with channels passive operation. Transmission on those channels is suppressed until appropriate other traffic is observed on those channels. -Within the driver, we use the ficticious country code "X2" to represent this +Within the driver, we use the fictitious country code "X2" to represent this worldwide regulatory domain. There is currently no interface to configure a different domain. diff --git a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 65313fa0cf4a..71c3571ee143 100644 --- a/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -264,7 +264,7 @@ extern SDIOH_API_RC sdioh_disable_func_intr(void) } #endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */ -/* Configure callback to client when we recieve client interrupt */ +/* Configure callback to client when we receive client interrupt */ extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh) { diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c index cbfa1c1b7059..1cf6c5dc2bb7 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c @@ -46,7 +46,7 @@ extern int sdioh_mmc_irq(int irq); #include #endif -/* Customer specific Host GPIO defintion */ +/* Customer specific Host GPIO definition */ static int dhd_oob_gpio_num = -1; /* GG 19 */ module_param(dhd_oob_gpio_num, int, 0644); diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c index 02c6d446934c..dd0375793875 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_linux.c @@ -478,7 +478,7 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) dhd_set_packet_filter(1, dhd); /* if dtim skip setup as default force it - * to wake each thrid dtim + * to wake each third dtim * for better power saving. * Note that side effect is chance to miss BC/MC * packet diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c index 106627040db0..464f52af1315 100644 --- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c @@ -3659,7 +3659,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) * control pkt receives. * Later we use buffer-poll for data as well * as control packets. - * This is required becuase dhd receives full + * This is required because dhd receives full * frame in gSPI unlike SDIO. * After the frame is received we have to * distinguish whether it is data @@ -3744,7 +3744,7 @@ static uint dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) bus->dhd->rx_errors++; dhd_os_sdunlock_rxq(bus->dhd); /* Force retry w/normal header read. - * Don't attemp NAK for + * Don't attempt NAK for * gSPI */ dhdsdio_rxfail(bus, true, diff --git a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c index 774b4e916b29..c1b07ae31674 100644 --- a/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c +++ b/drivers/staging/brcm80211/brcmsmac/wl_mac80211.c @@ -1079,7 +1079,7 @@ static int ieee_hw_init(struct ieee80211_hw *hw) */ hw->max_rates = 2; /* Primary rate and 1 fallback rate */ - hw->channel_change_time = 7 * 1000; /* channel change time is dependant on chip and band */ + hw->channel_change_time = 7 * 1000; /* channel change time is dependent on chip and band */ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); hw->rate_control_algorithm = "minstrel_ht"; diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c b/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c index c6cdcd940956..f00865957881 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c @@ -89,7 +89,7 @@ u32 wl_ampdu_dbg = /* structure to hold tx fifo information and pre-loading state * counters specific to tx underflows of ampdus * some counters might be redundant with the ones in wlc or ampdu structures. - * This allows to maintain a specific state independantly of + * This allows to maintain a specific state independently of * how often and/or when the wlc counters are updated. */ typedef struct wlc_fifo_info { @@ -265,7 +265,7 @@ static void scb_ampdu_update_config(struct ampdu_info *ampdu, struct scb *scb) scb_ampdu->max_pdu = (u8) ampdu->wlc->pub->tunables->ampdunummpdu; - /* go back to legacy size if some preloading is occuring */ + /* go back to legacy size if some preloading is occurring */ for (i = 0; i < NUM_FFPLD_FIFO; i++) { if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR) scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY; @@ -406,7 +406,7 @@ static int wlc_ffpld_check_txfunfl(struct wlc_info *wlc, int fid) /* compute a new dma xfer rate for max_mpdu @ max mcs. This is the minimum dma rate that - can acheive no unferflow condition for the current mpdu size. + can achieve no unferflow condition for the current mpdu size. */ /* note : we divide/multiply by 100 to avoid integer overflows */ fifo->dmaxferrate = diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c b/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c index 5a96dc3cdb36..4b6e181c7dc9 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_bmac.c @@ -1915,7 +1915,7 @@ void wlc_bmac_phy_reset(struct wlc_hw_info *wlc_hw) phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi); - /* Specfic reset sequence required for NPHY rev 3 and 4 */ + /* Specific reset sequence required for NPHY rev 3 and 4 */ if (WLCISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) && NREV_LE(wlc_hw->band->phyrev, 4)) { /* Set the PHY bandwidth */ diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_main.c b/drivers/staging/brcm80211/brcmsmac/wlc_main.c index 639b5d7c9603..717fced45801 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_main.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_main.c @@ -8295,7 +8295,7 @@ wlc_txflowcontrol_prio_isset(struct wlc_info *wlc, struct wlc_txq_info *q, return (q->stopped & prio_mask) == prio_mask; } -/* propogate the flow control to all interfaces using the given tx queue */ +/* propagate the flow control to all interfaces using the given tx queue */ void wlc_txflowcontrol(struct wlc_info *wlc, struct wlc_txq_info *qi, bool on, int prio) { @@ -8462,7 +8462,7 @@ static void wlc_txq_free(struct wlc_info *wlc, struct wlc_txq_info *qi) } /* - * Flag 'scan in progress' to withold dynamic phy calibration + * Flag 'scan in progress' to withhold dynamic phy calibration */ void wlc_scan_start(struct wlc_info *wlc) { diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_rate.c b/drivers/staging/brcm80211/brcmsmac/wlc_rate.c index 0cfa36023cf1..d284f1ac49cc 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_rate.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_rate.c @@ -332,7 +332,7 @@ wlc_rate_hwrs_filter_sort_validate(wlc_rateset_t *rs, return false; } -/* caluclate the rate of a rx'd frame and return it as a ratespec */ +/* calculate the rate of a rx'd frame and return it as a ratespec */ ratespec_t BCMFASTPATH wlc_compute_rspec(d11rxhdr_t *rxh, u8 *plcp) { int phy_type; diff --git a/drivers/staging/brcm80211/include/bcmsrom_fmt.h b/drivers/staging/brcm80211/include/bcmsrom_fmt.h index ae2bff828607..4768968f910a 100644 --- a/drivers/staging/brcm80211/include/bcmsrom_fmt.h +++ b/drivers/staging/brcm80211/include/bcmsrom_fmt.h @@ -103,7 +103,7 @@ #define SROM_CRCREV 63 -/* SROM Rev 4: Reallocate the software part of the srom to accomodate +/* SROM Rev 4: Reallocate the software part of the srom to accommodate * MIMO features. It assumes up to two PCIE functions and 440 bytes * of useable srom i.e. the useable storage in chips with OTP that * implements hardware redundancy. diff --git a/drivers/staging/brcm80211/include/hndsoc.h b/drivers/staging/brcm80211/include/hndsoc.h index 9747cc46ca96..6435686b329f 100644 --- a/drivers/staging/brcm80211/include/hndsoc.h +++ b/drivers/staging/brcm80211/include/hndsoc.h @@ -181,7 +181,7 @@ * conventions for the use the flash space: */ -/* Minumum amount of flash we support */ +/* Minimum amount of flash we support */ #define FLASH_MIN 0x00020000 /* Minimum flash size */ /* A boot/binary may have an embedded block that describes its size */ diff --git a/drivers/staging/brcm80211/util/bcmotp.c b/drivers/staging/brcm80211/util/bcmotp.c index ba71c108b366..17991212a22d 100644 --- a/drivers/staging/brcm80211/util/bcmotp.c +++ b/drivers/staging/brcm80211/util/bcmotp.c @@ -213,7 +213,7 @@ static u16 ipxotp_read_bit(void *oh, chipcregs_t *cc, uint off) return (int)st; } -/* Calculate max HW/SW region byte size by substracting fuse region and checksum size, +/* Calculate max HW/SW region byte size by subtracting fuse region and checksum size, * osizew is oi->wsize (OTP size - GU size) in words */ static int ipxotp_max_rgnsz(si_t *sih, int osizew) @@ -229,7 +229,7 @@ static int ipxotp_max_rgnsz(si_t *sih, int osizew) ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; break; default: - ASSERT(0); /* Don't konw about this chip */ + ASSERT(0); /* Don't know about this chip */ } return ret; diff --git a/drivers/staging/brcm80211/util/bcmsrom.c b/drivers/staging/brcm80211/util/bcmsrom.c index eca35b94e96c..850bfa6593e0 100644 --- a/drivers/staging/brcm80211/util/bcmsrom.c +++ b/drivers/staging/brcm80211/util/bcmsrom.c @@ -1859,7 +1859,7 @@ static int initvars_srom_pci(si_t *sih, void *curmap, char **vars, uint *count) /* * Apply CRC over SROM content regardless SROM is present or not, - * and use variable sromrev's existance in flash to decide + * and use variable sromrev's existence in flash to decide * if we should return an error when CRC fails or read SROM variables * from flash. */ diff --git a/drivers/staging/brcm80211/util/hnddma.c b/drivers/staging/brcm80211/util/hnddma.c index 8a81eb997f99..be339feae77d 100644 --- a/drivers/staging/brcm80211/util/hnddma.c +++ b/drivers/staging/brcm80211/util/hnddma.c @@ -1179,7 +1179,7 @@ static void BCMFASTPATH dma64_txreclaim(dma_info_t *di, txd_range_t range) (range == HNDDMA_RANGE_ALL) ? "all" : ((range == HNDDMA_RANGE_TRANSMITTED) ? "transmitted" : - "transfered"))); + "transferred"))); if (di->txin == di->txout) return; @@ -1549,7 +1549,7 @@ static int BCMFASTPATH dma64_txfast(dma_info_t *di, struct sk_buff *p0, * If range is HNDDMA_RANGE_TRANSMITTED, reclaim descriptors that have be * transmitted as noted by the hardware "CurrDescr" pointer. * If range is HNDDMA_RANGE_TRANSFERED, reclaim descriptors that have be - * transfered by the DMA as noted by the hardware "ActiveDescr" pointer. + * transferred by the DMA as noted by the hardware "ActiveDescr" pointer. * If range is HNDDMA_RANGE_ALL, reclaim all txd(s) posted to the ring and * return associated packet regardless of the value of hardware pointers. */ @@ -1563,7 +1563,7 @@ static void *BCMFASTPATH dma64_getnexttxp(dma_info_t *di, txd_range_t range) (range == HNDDMA_RANGE_ALL) ? "all" : ((range == HNDDMA_RANGE_TRANSMITTED) ? "transmitted" : - "transfered"))); + "transferred"))); if (di->ntxd == 0) return NULL; diff --git a/drivers/staging/brcm80211/util/sbpcmcia.h b/drivers/staging/brcm80211/util/sbpcmcia.h index 6b9923f551a9..d4c156586e81 100644 --- a/drivers/staging/brcm80211/util/sbpcmcia.h +++ b/drivers/staging/brcm80211/util/sbpcmcia.h @@ -109,7 +109,7 @@ #define CISTPL_CFTABLE 0x1b /* Config table entry */ #define CISTPL_END 0xff /* End of the CIS tuple chain */ -/* Function identifier provides context for the function extentions tuple */ +/* Function identifier provides context for the function extensions tuple */ #define CISTPL_FID_SDIO 0x0c /* Extensions defined by SDIO spec */ /* Function extensions for LANs (assumed for extensions other than SDIO) */ diff --git a/drivers/staging/brcm80211/util/siutils.c b/drivers/staging/brcm80211/util/siutils.c index ed168ceba5f0..6ebd7f58af81 100644 --- a/drivers/staging/brcm80211/util/siutils.c +++ b/drivers/staging/brcm80211/util/siutils.c @@ -1319,7 +1319,7 @@ int si_clkctl_xtal(si_t *sih, uint what, bool on) } /* - * clock control policy function throught chipcommon + * clock control policy function through chipcommon * * set dynamic clk control mode (forceslow, forcefast, dynamic) * returns true if we are forcing fast clock diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index a4ceb29c358e..e7e72b8d8cde 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2064,7 +2064,7 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) COMEDI_CB_OVERFLOW)) { runflags_mask |= SRF_RUNNING; } - /* remember if an error event has occured, so an error + /* remember if an error event has occurred, so an error * can be returned the next time the user does a read() */ if (s->async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) { runflags_mask |= SRF_ERROR; diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c index 644bda44556e..482a412aa652 100644 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c +++ b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c @@ -124,9 +124,9 @@ You should also find the complete GPL in the COPYING file accompanying this sour | -5: The selected PCI input clock is wrong | | -6: Timing unity selection is wrong | | -7: Base timing selection is wrong | -| -8: You can not used the 40MHz clock selection wich | +| -8: You can not used the 40MHz clock selection with | | this board | -| -9: You can not used the 40MHz clock selection wich | +| -9: You can not used the 40MHz clock selection with | | this CHRONOS version | +----------------------------------------------------------------------------+ */ @@ -721,10 +721,10 @@ int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, struct comedi_sub } } else { /**************************************************************/ - /* You can not used the 40MHz clock selection wich this board */ + /* You can not use the 40MHz clock selection with this board */ /**************************************************************/ - DPRINTK("You can not used the 40MHz clock selection wich this board\n"); + DPRINTK("You can not used the 40MHz clock selection with this board\n"); i_ReturnValue = -8; } diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c index 90e71e12784a..b973095146f9 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c @@ -59,7 +59,7 @@ You should also find the complete GPL in the COPYING file accompanying this sour /*+----------------------------------------------------------------------------+*/ /*| Input Parameters : int i_NbOfWordsToRead : Nbr. of word to read |*/ /*| unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/ -/*| unsigned short w_EepromStartAddress : Eeprom strat address |*/ +/*| unsigned short w_EepromStartAddress : Eeprom start address |*/ /*+----------------------------------------------------------------------------+*/ /*| Output Parameters : unsigned short * pw_DataRead : Read data |*/ /*+----------------------------------------------------------------------------+*/ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c index 9dd857df93c8..002297dfe33f 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c @@ -498,7 +498,7 @@ void v_APCI2032_Interrupt(int irq, void *d) struct comedi_device *dev = d; unsigned int ui_DO; - ui_DO = inl(devpriv->iobase + APCI2032_DIGITAL_OP_IRQ) & 0x1; /* Check if VCC OR CC interrupt has occured. */ + ui_DO = inl(devpriv->iobase + APCI2032_DIGITAL_OP_IRQ) & 0x1; /* Check if VCC OR CC interrupt has occurred. */ if (ui_DO == 0) { printk("\nInterrupt from unKnown source\n"); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index a813fdbbd96e..fc61214151b7 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -148,7 +148,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd unsigned short us_ConvertTiming, us_TmpValue, i; unsigned char b_Tmp; - /* fix convertion time to 10 us */ + /* fix conversion time to 10 us */ if (!devpriv->ui_EocEosConversionTime) { printk("No timer0 Value using 10 us\n"); us_ConvertTiming = 10; @@ -251,7 +251,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - /* Set the convertion time */ + /* Set the conversion time */ outw(us_ConvertTiming, devpriv->iobase + APCI3120_TIMER_VALUE); @@ -311,7 +311,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, devpriv->iobase + APCI3120_TIMER_CRT0); - /* Set the convertion time */ + /* Set the conversion time */ outw(us_ConvertTiming, devpriv->iobase + APCI3120_TIMER_VALUE); @@ -354,9 +354,9 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd /* Start conversion */ outw(0, devpriv->iobase + APCI3120_START_CONVERSION); - /* Waiting of end of convertion if interrupt is not installed */ + /* Waiting of end of conversion if interrupt is not installed */ if (devpriv->b_EocEosInterrupt == APCI3120_DISABLE) { - /* Waiting the end of convertion */ + /* Waiting the end of conversion */ do { us_TmpValue = inw(devpriv->iobase + @@ -854,7 +854,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - /* Set the convertion time */ + /* Set the conversion time */ outw(((unsigned short) ui_TimerValue0), dev->iobase + APCI3120_TIMER_VALUE); break; @@ -872,7 +872,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, b_DigitalOutputRegister) & 0xF0) | APCI3120_SELECT_TIMER_1_WORD; outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - /* Set the convertion time */ + /* Set the conversion time */ outw(((unsigned short) ui_TimerValue1), dev->iobase + APCI3120_TIMER_VALUE); @@ -889,7 +889,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, APCI3120_SELECT_TIMER_0_WORD; outb(b_Tmp, dev->iobase + APCI3120_TIMER_CRT0); - /* Set the convertion time */ + /* Set the conversion time */ outw(((unsigned short) ui_TimerValue0), dev->iobase + APCI3120_TIMER_VALUE); break; @@ -1104,7 +1104,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, /* * 4 - * amount of bytes to be transfered set transfer count used ADDON + * amount of bytes to be transferred set transfer count used ADDON * MWTC register commented testing * outl(devpriv->ui_DmaBufferUsesize[0], * devpriv->i_IobaseAddon+AMCC_OP_REG_AMWTC); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h index b3c81979f14d..50eb0a0a0a05 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h @@ -169,7 +169,7 @@ struct str_AnalogReadInformation { unsigned char b_Type; /* EOC or EOS */ unsigned char b_InterruptFlag; /* Interrupt use or not */ - unsigned int ui_ConvertTiming; /* Selection of the convertion time */ + unsigned int ui_ConvertTiming; /* Selection of the conversion time */ unsigned char b_NbrOfChannel; /* Number of channel to read */ unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS]; /* Number of the channel to be read */ unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS]; /* Gain of each channel */ diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index a93e2349ad3a..c75a1a1fd775 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -103,7 +103,7 @@ struct str_BoardInfos s_BoardInfos[100]; /* 100 will be the max number of board /*+----------------------------------------------------------------------------+*/ /*| Input Parameters : int i_NbOfWordsToRead : Nbr. of word to read |*/ /*| unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/ -/*| unsigned short w_EepromStartAddress : Eeprom strat address |*/ +/*| unsigned short w_EepromStartAddress : Eeprom start address |*/ /*+----------------------------------------------------------------------------+*/ /*| Output Parameters : unsigned short * pw_DataRead : Read data |*/ /*+----------------------------------------------------------------------------+*/ @@ -849,7 +849,7 @@ int i_APCI3200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdev | 0:Single Read | 1:Read more channel 2:Single scan - | 3:Continous Scan + | 3:Continuous Scan data[13] :Number of channels to read | data[14] :RTD connection type :0:RTD not used diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 766103c882ad..632d5d0721cd 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -23,7 +23,7 @@ For AI: - If cmd->scan_begin_src=TRIG_EXT then trigger input is TGIN (pin 46). - If cmd->convert_src=TRIG_EXT then trigger input is EXTTRG (pin 44). - If cmd->start_src/stop_src=TRIG_EXT then trigger input is TGIN (pin 46). -- It is not neccessary to have cmd.scan_end_arg=cmd.chanlist_len but +- It is not necessary to have cmd.scan_end_arg=cmd.chanlist_len but cmd.scan_end_arg modulo cmd.chanlist_len must by 0. - If return value of cmdtest is 5 then you've bad channel list (it isn't possible mixture S.E. and DIFF inputs or bipolar and unipolar @@ -823,7 +823,7 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, move_block_from_dma(dev, s, devpriv->dmabuf_virt[devpriv->dma_actbuf], samplesinbuf); - m = m - sampls; /* m= how many samples was transfered */ + m = m - sampls; /* m= how many samples was transferred */ } /* DPRINTK("YYY\n"); */ @@ -1297,7 +1297,7 @@ static int Compute_and_setup_dma(struct comedi_device *dev) DPRINTK("3 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); /* transfer without TRIG_WAKE_EOS */ if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) { - /* if it's possible then allign DMA buffers to length of scan */ + /* if it's possible then align DMA buffers to length of scan */ i = dmalen0; dmalen0 = (dmalen0 / (devpriv->ai_n_realscanlen << 1)) * diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 4b470000b69c..5361f318b010 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -65,7 +65,7 @@ If you do not specify any options, they will default to written by jeremy theler instituto balseiro - comision nacional de energia atomica + commission nacional de energia atomica universidad nacional de cuyo argentina @@ -342,7 +342,7 @@ static int adq12b_ai_rinsn(struct comedi_device *dev, /* convert n samples */ for (n = 0; n < insn->n; n++) { - /* wait for end of convertion */ + /* wait for end of conversion */ i = 0; do { /* udelay(1); */ diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 466e69f94ef2..da2b75b15d4e 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -98,7 +98,7 @@ Configuration options: #define Status_FE 0x0100 /* 1=FIFO is empty */ #define Status_FH 0x0200 /* 1=FIFO is half full */ #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */ -#define Status_IRQ 0x0800 /* 1=IRQ occured */ +#define Status_IRQ 0x0800 /* 1=IRQ occurred */ /* bits from control register (PCI171x_CONTROL) */ #define Control_CNT0 0x0040 /* 1=CNT0 have external source, * 0=have internal 100kHz source */ @@ -1161,7 +1161,7 @@ static int check_channel_list(struct comedi_device *dev, } if (n_chan > 1) { - chansegment[0] = chanlist[0]; /* first channel is everytime ok */ + chansegment[0] = chanlist[0]; /* first channel is every time ok */ for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */ /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ if (chanlist[0] == chanlist[i]) @@ -1176,9 +1176,9 @@ static int check_channel_list(struct comedi_device *dev, (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) nowmustbechan = (nowmustbechan + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */ + if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ printk - ("channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", + ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", i, CR_CHAN(chanlist[i]), nowmustbechan, CR_CHAN(chanlist[0])); return 0; diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 0941643b3869..61968a505f24 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -115,7 +115,7 @@ analog triggering on 1602 series #define INT_MASK 0x3 /* mask of interrupt select bits */ #define INTE 0x4 /* interrupt enable */ #define DAHFIE 0x8 /* dac half full interrupt enable */ -#define EOAIE 0x10 /* end of aquisition interrupt enable */ +#define EOAIE 0x10 /* end of acquisition interrupt enable */ #define DAHFI 0x20 /* dac half full read status / write interrupt clear */ #define EOAI 0x40 /* read end of acq. interrupt status / write clear */ #define INT 0x80 /* read interrupt status / write clear */ @@ -440,7 +440,7 @@ struct cb_pcidas_private { unsigned int divisor1; unsigned int divisor2; volatile unsigned int count; /* number of analog input samples remaining */ - volatile unsigned int adc_fifo_bits; /* bits to write to interupt/adcfifo register */ + volatile unsigned int adc_fifo_bits; /* bits to write to interrupt/adcfifo register */ volatile unsigned int s5933_intcsr_bits; /* bits to write to amcc s5933 interrupt control/status register */ volatile unsigned int ao_control_bits; /* bits to write to ao control and status register */ short ai_buffer[AI_BUFFER_SIZE]; @@ -1653,7 +1653,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) spin_unlock_irqrestore(&dev->spinlock, flags); } else if (status & EOAI) { comedi_error(dev, - "bug! encountered end of aquisition interrupt?"); + "bug! encountered end of acquisition interrupt?"); /* clear EOA interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | EOAI, diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 2583e16cd02a..1e324198996c 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -104,7 +104,7 @@ TODO: #endif #define TIMER_BASE 25 /* 40MHz master clock */ -#define PRESCALED_TIMER_BASE 10000 /* 100kHz 'prescaled' clock for slow aquisition, maybe I'll support this someday */ +#define PRESCALED_TIMER_BASE 10000 /* 100kHz 'prescaled' clock for slow acquisition, maybe I'll support this someday */ #define DMA_BUFFER_SIZE 0x1000 #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307 @@ -136,7 +136,7 @@ enum write_only_registers { ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, /* upper 8 bits of delay interval counter */ ADC_COUNT_LOWER_REG = 0x1e, /* lower 16 bits of hardware conversion/scan counter */ ADC_COUNT_UPPER_REG = 0x20, /* upper 8 bits of hardware conversion/scan counter */ - ADC_START_REG = 0x22, /* software trigger to start aquisition */ + ADC_START_REG = 0x22, /* software trigger to start acquisition */ ADC_CONVERT_REG = 0x24, /* initiates single conversion */ ADC_QUEUE_CLEAR_REG = 0x26, /* clears adc queue */ ADC_QUEUE_LOAD_REG = 0x28, /* loads adc queue */ @@ -199,7 +199,7 @@ enum intr_enable_contents { ADC_INTR_EOSCAN_BITS = 0x2, /* interrupt end of scan */ ADC_INTR_EOSEQ_BITS = 0x3, /* interrupt end of sequence (probably wont use this it's pretty fancy) */ EN_ADC_INTR_SRC_BIT = 0x4, /* enable adc interrupt source */ - EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc aquisition done interrupt */ + EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc acquisition done interrupt */ DAC_INTR_SRC_MASK = 0x30, DAC_INTR_QEMPTY_BITS = 0x0, DAC_INTR_HIGH_CHAN_BITS = 0x10, @@ -2867,7 +2867,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) spin_unlock_irqrestore(&dev->spinlock, flags); - /* start aquisition */ + /* start acquisition */ if (cmd->start_src == TRIG_NOW) { writew(0, priv(dev)->main_iobase + ADC_START_REG); DEBUG_PRINT("soft trig\n"); @@ -2942,7 +2942,7 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev) /* Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of pointers. * The pci-4020 hardware only supports * dma transfers (it only supports the use of pio for draining the last remaining - * points from the fifo when a data aquisition operation has completed). + * points from the fifo when a data acquisition operation has completed). */ static void pio_drain_ai_fifo_32(struct comedi_device *dev) { @@ -3046,7 +3046,7 @@ static void handle_ai_interrupt(struct comedi_device *dev, comedi_error(dev, "fifo overrun"); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - /* spin lock makes sure noone else changes plx dma control reg */ + /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */ @@ -3170,7 +3170,7 @@ static void handle_ao_interrupt(struct comedi_device *dev, async = s->async; cmd = &async->cmd; - /* spin lock makes sure noone else changes plx dma control reg */ + /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index b220b3055412..a804742b8022 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -81,7 +81,7 @@ static const struct waveform_board waveform_boards[] = { /* Data unique to this driver */ struct waveform_private { struct timer_list timer; - struct timeval last; /* time at which last timer interrupt occured */ + struct timeval last; /* time at which last timer interrupt occurred */ unsigned int uvolt_amplitude; /* waveform amplitude in microvolts */ unsigned long usec_period; /* waveform period in microseconds */ unsigned long usec_current; /* current time (modulo waveform period) */ diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 6ea93f9c0b48..60c2b12d6ffb 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -1087,7 +1087,7 @@ static void das1800_flush_dma_channel(struct comedi_device *dev, return; } -/* flushes remaining data from board when external trigger has stopped aquisition +/* flushes remaining data from board when external trigger has stopped acquisition * and we are using dma transfers */ static void das1800_flush_dma(struct comedi_device *dev, struct comedi_subdevice *s) diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index aecaedc5027e..96d41ad76956 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -391,7 +391,7 @@ static irqreturn_t das800_interrupt(int irq, void *d) spin_lock_irqsave(&dev->spinlock, irq_flags); outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */ status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN; - /* don't release spinlock yet since we want to make sure noone else disables hardware conversions */ + /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */ if (status == 0) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); return IRQ_HANDLED; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 693728e14bdb..2b4e6e6eb825 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -532,7 +532,7 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev, msb = dmm_inb(dev, DMM32AT_AIMSB); /* invert sign bit to make range unsigned, this is an - idiosyncracy of the diamond board, it return + idiosyncrasy of the diamond board, it return conversions as a signed value, i.e. -32768 to 32767, flipping the bit and interpreting it as signed gives you a range of 0 to 65535 which is diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index a1664caa1d96..0131d5225b52 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -560,7 +560,7 @@ int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) switch (dev->i_admode) { case COMEDI_MDEMAND: dev->ntrig = adtrig->n - 1; - /* not neccessary */ + /* not necessary */ /*printk("dt2811: AD soft trigger\n"); */ /*outb(DT2811_CLRERROR|DT2811_INTENB, dev->iobase+DT2811_ADCSR); */ diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 06059850dae2..32d9c42e9659 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -773,7 +773,7 @@ static int dt9812_probe(struct usb_interface *interface, retval = dt9812_read_info(dev, 1, &fw, sizeof(fw)); if (retval == 0) { dev_info(&interface->dev, - "usb_reset_configuration succeded " + "usb_reset_configuration succeeded " "after %d iterations\n", i); break; } diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 1661b57ca2ad..bc020dea141b 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -1031,7 +1031,7 @@ static irqreturn_t handle_interrupt(int irq, void *d) writel(hpdi_intr_status, priv(dev)->hpdi_iobase + INTERRUPT_STATUS_REG); } - /* spin lock makes sure noone else changes plx dma control reg */ + /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ @@ -1045,7 +1045,7 @@ static irqreturn_t handle_interrupt(int irq, void *d) } spin_unlock_irqrestore(&dev->spinlock, flags); - /* spin lock makes sure noone else changes plx dma control reg */ + /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 0bab39b3409b..126550f3c02b 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -715,7 +715,7 @@ Description: is built correctly Parameters: - struct comedi_device *dev Pointer to current sevice structure + struct comedi_device *dev Pointer to current service structure struct comedi_subdevice *s Pointer to current subdevice structure unsigned int *chanlist Pointer to packed channel list unsigned int n_chan Number of channels to scan @@ -772,7 +772,7 @@ Description: Status register. Parameters: - struct comedi_device *dev Pointer to current sevice structure + struct comedi_device *dev Pointer to current service structure struct comedi_subdevice *s Pointer to current subdevice structure unsigned int *chanlist Pointer to packed channel list unsigned int n_chan Number of channels to scan @@ -848,7 +848,7 @@ Description: This function resets the icp multi device to a 'safe' state Parameters: - struct comedi_device *dev Pointer to current sevice structure + struct comedi_device *dev Pointer to current service structure Returns:int 0 = success diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 75511bae0191..b692fea0d2b0 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -1810,7 +1810,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_AI_HF) { ISR_PDEBUG - ("me4000_ai_isr(): Fifo half full interrupt occured\n"); + ("me4000_ai_isr(): Fifo half full interrupt occurred\n"); /* Read status register to find out what happened */ tmp = me4000_inl(dev, ai_context->ctrl_reg); @@ -1903,7 +1903,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) if (me4000_inl(dev, ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) { ISR_PDEBUG - ("me4000_ai_isr(): Sample counter interrupt occured\n"); + ("me4000_ai_isr(): Sample counter interrupt occurred\n"); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA; diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index a89eebd23f65..dd09a6d46e5c 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -39,8 +39,8 @@ Status: working Configuration Options: [0] - I/O base address - [1] - convertion rate - Convertion rate RMS noise Effective Number Of Bits + [1] - conversion rate + Conversion rate RMS noise Effective Number Of Bits 0 3.52kHz 23uV 17 1 1.76kHz 3.5uV 20 2 880Hz 2uV 21.3 @@ -93,8 +93,8 @@ Configuration Options: #define MPC624_DMY_BIT (1<<30) #define MPC624_SGN_BIT (1<<29) -/* Convertion speeds */ -/* OSR4 OSR3 OSR2 OSR1 OSR0 Convertion rate RMS noise ENOB^ +/* Conversion speeds */ +/* OSR4 OSR3 OSR2 OSR1 OSR0 Conversion rate RMS noise ENOB^ * X 0 0 0 1 3.52kHz 23uV 17 * X 0 0 1 0 1.76kHz 3.5uV 20 * X 0 0 1 1 880Hz 2uV 21.3 @@ -227,7 +227,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) break; default: printk - (KERN_ERR "illegal convertion rate setting!" + (KERN_ERR "illegal conversion rate setting!" " Valid numbers are 0..9. Using 9 => 6.875 Hz, "); devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; } @@ -296,7 +296,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, } for (n = 0; n < insn->n; n++) { - /* Trigger the convertion */ + /* Trigger the conversion */ outb(MPC624_ADSCK, dev->iobase + MPC624_ADC); udelay(1); outb(MPC624_ADCS | MPC624_ADSCK, dev->iobase + MPC624_ADC); @@ -304,7 +304,7 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, outb(0, dev->iobase + MPC624_ADC); udelay(1); - /* Wait for the convertion to end */ + /* Wait for the conversion to end */ for (i = 0; i < TIMEOUT; i++) { ucPort = inb(dev->iobase + MPC624_ADC); if (ucPort & MPC624_ADBUSY) diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index 4d0053ea2465..c192b71ec04f 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -104,10 +104,10 @@ TRIG_WAKE_EOS #define STATUS_REG 0x12 /* read only */ #define FNE_BIT 0x1 /* fifo not empty */ #define OVFL_BIT 0x8 /* fifo overflow */ -#define EDAQ_BIT 0x10 /* end of aquisition interrupt */ +#define EDAQ_BIT 0x10 /* end of acquisition interrupt */ #define DCAL_BIT 0x20 /* offset calibration in progress */ -#define INTR_BIT 0x40 /* interrupt has occured */ -#define DMA_TC_BIT 0x80 /* dma terminal count interrupt has occured */ +#define INTR_BIT 0x40 /* interrupt has occurred */ +#define DMA_TC_BIT 0x80 /* dma terminal count interrupt has occurred */ #define ID_BITS(x) (((x) >> 8) & 0x3) #define IRQ_DMA_CNTRL_REG 0x12 /* write only */ #define DMA_CHAN_BITS(x) ((x) & 0x7) /* sets dma channel */ @@ -434,7 +434,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->cancel = a2150_cancel; /* need to do this for software counting of completed conversions, to - * prevent hardware count from stopping aquisition */ + * prevent hardware count from stopping acquisition */ outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG); /* set card's irq and dma levels */ @@ -729,7 +729,7 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* send trigger config bits */ outw(trigger_bits, dev->iobase + TRIGGER_REG); - /* start aquisition for soft trigger */ + /* start acquisition for soft trigger */ if (cmd->start_src == TRIG_NOW) { outw(0, dev->iobase + FIFO_START_REG); } @@ -768,7 +768,7 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* setup start triggering */ outw(0, dev->iobase + TRIGGER_REG); - /* start aquisition for soft trigger */ + /* start acquisition for soft trigger */ outw(0, dev->iobase + FIFO_START_REG); /* there is a 35.6 sample delay for data to get through the antialias filter */ diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index 241fe525abf0..ab8f37022a3c 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -183,11 +183,11 @@ NI manuals: #define OVERRUN_BIT 0x2 /* fifo overflow */ #define OVERFLOW_BIT 0x4 -/* timer interrupt has occured */ +/* timer interrupt has occurred */ #define TIMER_BIT 0x8 -/* dma terminal count has occured */ +/* dma terminal count has occurred */ #define DMATC_BIT 0x10 -/* external trigger has occured */ +/* external trigger has occurred */ #define EXT_TRIG_BIT 0x40 /* 1200 boards only */ #define STATUS2_REG 0x1d @@ -1149,7 +1149,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) range = CR_RANGE(cmd->chanlist[0]); aref = CR_AREF(cmd->chanlist[0]); - /* make sure board is disabled before setting up aquisition */ + /* make sure board is disabled before setting up acquisition */ spin_lock_irqsave(&dev->spinlock, flags); devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); @@ -1349,7 +1349,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT; devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - /* startup aquisition */ + /* startup acquisition */ /* command2 reg */ /* use 2 cascaded counters for pacing */ @@ -1571,8 +1571,8 @@ static void handle_isa_dma(struct comedi_device *dev) devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG); } -/* makes sure all data acquired by board is transfered to comedi (used - * when aquisition is terminated by stop_src == TRIG_EXT). */ +/* makes sure all data acquired by board is transferred to comedi (used + * when acquisition is terminated by stop_src == TRIG_EXT). */ static void labpc_drain_dregs(struct comedi_device *dev) { if (devpriv->current_transfer == isa_dma_transfer) diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 005d2fe86ee4..8dd3a01d48dd 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -821,7 +821,7 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, cmd->scan_begin_arg = MAX_SPEED; err++; } - /* no minumum speed */ + /* no minimum speed */ } else { /* TRIG_EXT */ /* should be level/edge, hi/lo specification here */ diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index c6dce4a1425e..09ff4723b225 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -34,7 +34,7 @@ * and I cann't test all features.) * * This driver supports insn and cmd interfaces. Some boards support only insn - * becouse their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813). + * because their hardware don't allow more (PCL-813/B, ACL-8113, ISO-813). * Data transfer over DMA is supported only when you measure only one * channel, this is too hardware limitation of these boards. * diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index ef3cc4f3be6e..8f3fc6ee088b 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -954,7 +954,7 @@ check_channel_list(struct comedi_device *dev, } if (chanlen > 1) { - /* first channel is everytime ok */ + /* first channel is every time ok */ chansegment[0] = chanlist[0]; for (i = 1, seglen = 1; i < chanlen; i++, seglen++) { /* build part of chanlist */ @@ -968,10 +968,10 @@ check_channel_list(struct comedi_device *dev, nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % chanlen; if (nowmustbechan != CR_CHAN(chanlist[i])) { - /* channel list isn't continous :-( */ + /* channel list isn't continuous :-( */ printk(KERN_WARNING "comedi%d: pcl816: channel list must " - "be continous! chanlist[%i]=%d but " + "be continuous! chanlist[%i]=%d but " "must be %d or %d!\n", dev->minor, i, CR_CHAN(chanlist[i]), nowmustbechan, CR_CHAN(chanlist[0])); diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index f58d75be7295..e3eea09ae1fb 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -1231,7 +1231,7 @@ static int check_channel_list(struct comedi_device *dev, } if (n_chan > 1) { - /* first channel is everytime ok */ + /* first channel is every time ok */ chansegment[0] = chanlist[0]; /* build part of chanlist */ for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { @@ -1245,9 +1245,9 @@ static int check_channel_list(struct comedi_device *dev, break; nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continous :-( */ + if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ printk - ("comedi%d: pcl818: channel list must be continous! chanlist[%i]=%d but must be %d or %d!\n", + ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", dev->minor, i, CR_CHAN(chanlist[i]), nowmustbechan, CR_CHAN(chanlist[0])); return 0; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 5c832d7ed45d..f2e88e57d558 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -733,7 +733,7 @@ static int pcmmio_dio_insn_config(struct comedi_device *dev, break; case INSN_CONFIG_DIO_QUERY: - /* retreive from shadow register */ + /* retrieve from shadow register */ data[1] = (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; return insn->n; @@ -1279,7 +1279,7 @@ static int wait_dac_ready(unsigned long iobase) "no busy waiting" policy. The fact is that the hardware is normally so fast that we usually only need one time through the loop anyway. The longer timeout is for rare occasions and for detecting - non-existant hardware. */ + non-existent hardware. */ while (retry--) { if (inb(iobase + 3) & 0x80) diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index 7a9287433b2e..b2c2c8971a32 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -605,7 +605,7 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev, break; case INSN_CONFIG_DIO_QUERY: - /* retreive from shadow register */ + /* retrieve from shadow register */ data[1] = (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; return insn->n; diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index ebba9bb47777..82942e5728a5 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -390,7 +390,7 @@ static int daqp_ai_insn_read(struct comedi_device *dev, outb(v, dev->iobase + DAQP_CONTROL); - /* Reset any pending interrupts (my card has a tendancy to require + /* Reset any pending interrupts (my card has a tendency to require * require multiple reads on the status register to achieve this) */ @@ -752,7 +752,7 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outb(v, dev->iobase + DAQP_CONTROL); - /* Reset any pending interrupts (my card has a tendancy to require + /* Reset any pending interrupts (my card has a tendency to require * require multiple reads on the status register to achieve this) */ counter = 100; diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 357858d27441..7f09ed755fe6 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -75,7 +75,7 @@ Configuration options: das1800, since they have the best documented code. Driver cb_pcidas64.c uses the same DMA controller. - As far as I can tell, the About interrupt doesnt work if Sample is + As far as I can tell, the About interrupt doesn't work if Sample is also enabled. It turns out that About really isn't needed, since we always count down samples read. @@ -370,7 +370,7 @@ struct rtdPrivate { /* timer gate (when enabled) */ u8 utcGate[4]; /* 1 extra allows simple range check */ - /* shadow registers affect other registers, but cant be read back */ + /* shadow registers affect other registers, but can't be read back */ /* The macros below update these on writes */ u16 intMask; /* interrupt mask */ u16 intClearMask; /* interrupt clear mask */ @@ -485,7 +485,7 @@ struct rtdPrivate { #define RtdAdcFifoGet(dev) \ readw(devpriv->las1+LAS1_ADC_FIFO) -/* Read two ADC data values (DOESNT WORK) */ +/* Read two ADC data values (DOESN'T WORK) */ #define RtdAdcFifoGet2(dev) \ readl(devpriv->las1+LAS1_ADC_FIFO) @@ -857,7 +857,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) DPRINTK("rtd520: PCI latency = %d\n", pci_latency); } - /* Undocumented EPLD version (doesnt match RTD driver results) */ + /* Undocumented EPLD version (doesn't match RTD driver results) */ /*DPRINTK ("rtd520: Reading epld from %p\n", devpriv->las0+0); epld_version = readl (devpriv->las0+0); @@ -1291,7 +1291,7 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev) /* "instructions" read/write data in "one-shot" or "software-triggered" mode (simplest case). - This doesnt use interrupts. + This doesn't use interrupts. Note, we don't do any settling delays. Use a instruction list to select, delay, then read. @@ -2120,7 +2120,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* - Stop a running data aquisition. + Stop a running data acquisition. */ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index d5ba3ab357a3..23fc64b9988e 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -139,7 +139,7 @@ struct s626_private { int got_regions; short allocatedBuf; uint8_t ai_cmd_running; /* ai_cmd is running */ - uint8_t ai_continous; /* continous aquisition */ + uint8_t ai_continous; /* continous acquisition */ int ai_sample_count; /* number of samples to acquire */ unsigned int ai_sample_timer; /* time between samples in units of the timer */ @@ -1048,7 +1048,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d) uint8_t group; uint16_t irqbit; - DEBUG("s626_irq_handler: interrupt request recieved!!!\n"); + DEBUG("s626_irq_handler: interrupt request received!!!\n"); if (dev->attached == 0) return IRQ_NONE; @@ -1165,14 +1165,14 @@ static irqreturn_t s626_irq_handler(int irq, void *d) (16 * group))) == 1 && cmd->start_src == TRIG_EXT) { DEBUG - ("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", + ("s626_irq_handler: Edge capture interrupt received from channel %d\n", cmd->start_arg); /* Start executing the RPS program. */ MC_ENABLE(P_MC1, MC1_ERPS1); DEBUG - ("s626_irq_handler: aquisition start triggered!!!\n"); + ("s626_irq_handler: acquisition start triggered!!!\n"); if (cmd->scan_begin_src == TRIG_EXT) { @@ -1194,7 +1194,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d) && cmd->scan_begin_src == TRIG_EXT) { DEBUG - ("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", + ("s626_irq_handler: Edge capture interrupt received from channel %d\n", cmd->scan_begin_arg); /* Trigger ADC scan loop start by setting RPS Signal 0. */ @@ -1236,7 +1236,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d) == 1 && cmd->convert_src == TRIG_EXT) { DEBUG - ("s626_irq_handler: Edge capture interrupt recieved from channel %d\n", + ("s626_irq_handler: Edge capture interrupt received from channel %d\n", cmd->convert_arg); /* Trigger ADC scan loop start by setting RPS Signal 0. */ @@ -1805,7 +1805,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) DEBUG("s626_ai_cmd: NULL command\n"); return -EINVAL; } else { - DEBUG("s626_ai_cmd: command recieved!!!\n"); + DEBUG("s626_ai_cmd: command received!!!\n"); } if (dev->irq == 0) { @@ -1880,7 +1880,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_continous = 0; break; case TRIG_NONE: - /* continous aquisition */ + /* continous acquisition */ devpriv->ai_continous = 1; devpriv->ai_sample_count = 0; break; @@ -2570,7 +2570,7 @@ static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val) while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY) ; - /* Return non-zero if I2C error occured. */ + /* Return non-zero if I2C error occurred. */ return RR7146(P_I2CCTRL) & I2C_ERR; } diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index be93c30e4b15..e543e6c2b1bb 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -285,7 +285,7 @@ struct usbduxsub { short int ao_cmd_running; /* pwm is running */ short int pwm_cmd_running; - /* continous aquisition */ + /* continous acquisition */ short int ai_continous; short int ao_continous; /* number of samples to acquire */ @@ -500,7 +500,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) /* test, if we transmit only a fixed number of samples */ if (!(this_usbduxsub->ai_continous)) { - /* not continous, fixed number of samples */ + /* not continuous, fixed number of samples */ this_usbduxsub->ai_sample_count--; /* all samples received? */ if (this_usbduxsub->ai_sample_count < 0) { @@ -653,7 +653,7 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb) /* timer zero */ this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; - /* handle non continous aquisition */ + /* handle non continous acquisition */ if (!(this_usbduxsub->ao_continous)) { /* fixed number of samples */ this_usbduxsub->ao_sample_count--; @@ -957,7 +957,7 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; - /* scanning is continous */ + /* scanning is continuous */ tmp = cmd->convert_src; cmd->convert_src &= TRIG_NOW; if (!cmd->convert_src || tmp != cmd->convert_src) @@ -1222,7 +1222,7 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) up(&this_usbduxsub->sem); return -EBUSY; } - /* set current channel of the running aquisition to zero */ + /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; this_usbduxsub->dux_commands[1] = cmd->chanlist_len; @@ -1284,7 +1284,7 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) this_usbduxsub->ai_sample_count = cmd->stop_arg; this_usbduxsub->ai_continous = 0; } else { - /* continous aquisition */ + /* continous acquisition */ this_usbduxsub->ai_continous = 1; this_usbduxsub->ai_sample_count = 0; } @@ -1515,7 +1515,7 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, /* just now we scan also in the high speed mode every frame */ /* this is due to ehci driver limitations */ if (0) { /* (this_usbduxsub->high_speed) */ - /* start immidiately a new scan */ + /* start immediately a new scan */ /* the sampling rate is set by the coversion rate */ cmd->scan_begin_src &= TRIG_FOLLOW; } else { @@ -1525,7 +1525,7 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) err++; - /* scanning is continous */ + /* scanning is continuous */ tmp = cmd->convert_src; /* we always output at 1kHz just now all channels at once */ if (0) { /* (this_usbduxsub->high_speed) */ @@ -1645,7 +1645,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n", dev->minor, __func__); - /* set current channel of the running aquisition to zero */ + /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; for (i = 0; i < cmd->chanlist_len; ++i) { chan = CR_CHAN(cmd->chanlist[i]); @@ -1694,7 +1694,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; if (cmd->stop_src == TRIG_COUNT) { - /* not continous */ + /* not continuous */ /* counter */ /* high speed also scans everything at once */ if (0) { /* (this_usbduxsub->high_speed) */ @@ -1708,7 +1708,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } this_usbduxsub->ao_continous = 0; } else { - /* continous aquisition */ + /* continous acquisition */ this_usbduxsub->ao_continous = 1; this_usbduxsub->ao_sample_count = 0; } diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 5b15e6df54e6..2a8e725b7859 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -180,7 +180,7 @@ struct usbduxfastsub_s { /* comedi device for the interrupt context */ struct comedi_device *comedidev; short int ai_cmd_running; /* asynchronous command is running */ - short int ai_continous; /* continous aquisition */ + short int ai_continous; /* continous acquisition */ long int ai_sample_count; /* number of samples to acquire */ uint8_t *dux_commands; /* commands */ int ignore; /* counter which ignores the first @@ -392,7 +392,7 @@ static void usbduxfastsub_ai_Irq(struct urb *urb) p = urb->transfer_buffer; if (!udfs->ignore) { if (!udfs->ai_continous) { - /* not continous, fixed number of samples */ + /* not continuous, fixed number of samples */ n = urb->actual_length / sizeof(uint16_t); if (unlikely(udfs->ai_sample_count < n)) { /* @@ -775,7 +775,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, up(&udfs->sem); return -EBUSY; } - /* set current channel of the running aquisition to zero */ + /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; /* @@ -1182,7 +1182,7 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, } udfs->ai_continous = 0; } else { - /* continous aquisition */ + /* continous acquisition */ udfs->ai_continous = 1; udfs->ai_sample_count = 0; } diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c index 76e4b782d2fb..0fe713e72e9d 100644 --- a/drivers/staging/cptm1217/clearpad_tm1217.c +++ b/drivers/staging/cptm1217/clearpad_tm1217.c @@ -52,7 +52,7 @@ #define TMA1217_DEV_STATUS 0x13 /* Device Status */ #define TMA1217_INT_STATUS 0x14 /* Interrupt Status */ -/* Controller can detect upto 2 possible finger touches. +/* Controller can detect up to 2 possible finger touches. * Each finger touch provides 12 bit X Y co-ordinates, the values are split * across 2 registers, and an 8 bit Z value */ #define TMA1217_FINGER_STATE 0x18 /* Finger State */ diff --git a/drivers/staging/crystalhd/crystalhd_cmds.c b/drivers/staging/crystalhd/crystalhd_cmds.c index 1429608544d6..3735ed3da4c6 100644 --- a/drivers/staging/crystalhd/crystalhd_cmds.c +++ b/drivers/staging/crystalhd/crystalhd_cmds.c @@ -914,7 +914,7 @@ enum BC_STATUS crystalhd_user_open(struct crystalhd_cmd *ctx, * Return: * status * - * Closer aplication handle and release app specific + * Closer application handle and release app specific * resources. */ enum BC_STATUS crystalhd_user_close(struct crystalhd_cmd *ctx, struct crystalhd_user *uc) diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c index 13a514dd0f79..5acf39e7cdef 100644 --- a/drivers/staging/crystalhd/crystalhd_hw.c +++ b/drivers/staging/crystalhd/crystalhd_hw.c @@ -302,7 +302,7 @@ static bool crystalhd_start_device(struct crystalhd_adp *adp) crystalhd_enable_interrupts(adp); /* Enable the option for getting the total no. of DWORDS - * that have been transfered by the RXDMA engine + * that have been transferred by the RXDMA engine */ dbg_options = crystalhd_reg_rd(adp, MISC1_DMA_DEBUG_OPTIONS_REG); dbg_options |= 0x10; @@ -1776,7 +1776,7 @@ enum BC_STATUS crystalhd_do_fw_cmd(struct crystalhd_hw *hw, return sts; } - /*Get the Responce Address*/ + /*Get the Response Address*/ cmd_res_addr = bc_dec_reg_rd(hw->adp, Cpu2HstMbx1); /*Read the Response*/ @@ -2367,7 +2367,7 @@ enum BC_STATUS crystalhd_hw_set_core_clock(struct crystalhd_hw *hw) BCMLOG(BCMLOG_INFO, "clock is moving to %d with n %d with vco_mg %d\n", hw->core_clock_mhz, n, vco_mg); - /* Change the DRAM refresh rate to accomodate the new frequency */ + /* Change the DRAM refresh rate to accommodate the new frequency */ /* refresh reg = ((refresh_rate * clock_rate)/16) - 1; rounding up*/ refresh_reg = (7 * hw->core_clock_mhz / 16); bc_dec_reg_wr(hw->adp, SDRAM_REF_PARAM, ((1 << 12) | refresh_reg)); diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c index f274c77fb3fc..5cc3423a6646 100644 --- a/drivers/staging/cxt1e1/musycc.c +++ b/drivers/staging/cxt1e1/musycc.c @@ -1455,7 +1455,7 @@ musycc_intr_bh_tasklet (ci_t * ci) /* * If the descriptor has not recovered, then leaving the EMPTY * entry set will not signal to the MUSYCC that this descriptor - * has been serviced. The Interrupt Queue can then start loosing + * has been serviced. The Interrupt Queue can then start losing * available descriptors and MUSYCC eventually encounters and * reports the INTFULL condition. Per manual, changing any bit * marks descriptor as available, thus the use of different diff --git a/drivers/staging/cxt1e1/musycc.h b/drivers/staging/cxt1e1/musycc.h index d2c91ef686d1..68f3660f4477 100644 --- a/drivers/staging/cxt1e1/musycc.h +++ b/drivers/staging/cxt1e1/musycc.h @@ -74,7 +74,7 @@ extern "C" #define INT_QUEUE_SIZE MUSYCC_NIQD -/* RAM image of MUSYCC registers layed out as a C structure */ +/* RAM image of MUSYCC registers laid out as a C structure */ struct musycc_groupr { VINT32 thp[32]; /* Transmit Head Pointer [5-29] */ @@ -96,7 +96,7 @@ extern "C" VINT32 pcd; /* Port Configuration Descriptor [5-19] */ }; -/* hardware MUSYCC registers layed out as a C structure */ +/* hardware MUSYCC registers laid out as a C structure */ struct musycc_globalr { VINT32 gbp; /* Group Base Pointer */ diff --git a/drivers/staging/cxt1e1/pmcc4_defs.h b/drivers/staging/cxt1e1/pmcc4_defs.h index 186347b8d565..a39505f45c29 100644 --- a/drivers/staging/cxt1e1/pmcc4_defs.h +++ b/drivers/staging/cxt1e1/pmcc4_defs.h @@ -54,8 +54,8 @@ #define MUSYCC_MTU 2048 /* default */ #define MUSYCC_TXDESC_MIN 10 /* HDLC mode default */ #define MUSYCC_RXDESC_MIN 18 /* HDLC mode default */ -#define MUSYCC_TXDESC_TRANS 4 /* Transparent mode minumum # of TX descriptors */ -#define MUSYCC_RXDESC_TRANS 12 /* Transparent mode minumum # of RX descriptors */ +#define MUSYCC_TXDESC_TRANS 4 /* Transparent mode minimum # of TX descriptors */ +#define MUSYCC_RXDESC_TRANS 12 /* Transparent mode minimum # of RX descriptors */ #define MAX_DEFAULT_IFQLEN 32 /* network qlen */ diff --git a/drivers/staging/cxt1e1/sbecrc.c b/drivers/staging/cxt1e1/sbecrc.c index 51232948091f..3f3cd60ac367 100644 --- a/drivers/staging/cxt1e1/sbecrc.c +++ b/drivers/staging/cxt1e1/sbecrc.c @@ -95,7 +95,7 @@ sbeCrc (u_int8_t *buffer, /* data buffer to crc */ /* * if table not yet created, do so. Don't care about "extra" time - * checking this everytime sbeCrc() is called, since CRC calculations are + * checking this every time sbeCrc() is called, since CRC calculations are * already time consuming */ if (!crcTableInit) diff --git a/drivers/staging/cxt1e1/sbeproc.c b/drivers/staging/cxt1e1/sbeproc.c index 70b9b33f3522..f42531c3d8da 100644 --- a/drivers/staging/cxt1e1/sbeproc.c +++ b/drivers/staging/cxt1e1/sbeproc.c @@ -239,7 +239,7 @@ sbecom_proc_get_sbe_info (char *buffer, char **start, off_t offset, */ #if 1 - /* #4 - intepretation of above = set EOF, return len */ + /* #4 - interpretation of above = set EOF, return len */ *eof = 1; #endif diff --git a/drivers/staging/et131x/et1310_address_map.h b/drivers/staging/et131x/et1310_address_map.h index e6c8cb3828e9..425e9274f28a 100644 --- a/drivers/staging/et131x/et1310_address_map.h +++ b/drivers/staging/et131x/et1310_address_map.h @@ -856,7 +856,7 @@ typedef union _RXMAC_UNI_PF_ADDR3_t { */ /* - * structure for space availiable reg in rxmac address map. + * structure for space available reg in rxmac address map. * located at address 0x4094 * * 31-17: reserved @@ -1031,7 +1031,7 @@ typedef struct _RXMAC_t { /* Location: */ * 31: reset MII mgmt * 30-6: unused * 5: scan auto increment - * 4: preamble supress + * 4: preamble suppress * 3: undefined * 2-0: mgmt clock reset */ diff --git a/drivers/staging/et131x/et1310_phy.h b/drivers/staging/et131x/et1310_phy.h index 78349adc7d8e..946c0c547404 100644 --- a/drivers/staging/et131x/et1310_phy.h +++ b/drivers/staging/et131x/et1310_phy.h @@ -468,7 +468,7 @@ typedef union _MI_ANAR_t { #define TRUEPHY_ANEG_COMPLETE 1 #define TRUEPHY_ANEG_DISABLED 2 -/* Define duplex advertisment flags */ +/* Define duplex advertisement flags */ #define TRUEPHY_ADV_DUPLEX_NONE 0x00 #define TRUEPHY_ADV_DUPLEX_FULL 0x01 #define TRUEPHY_ADV_DUPLEX_HALF 0x02 diff --git a/drivers/staging/et131x/et1310_rx.c b/drivers/staging/et131x/et1310_rx.c index 339136f64be1..fc6bd438366d 100644 --- a/drivers/staging/et131x/et1310_rx.c +++ b/drivers/staging/et131x/et1310_rx.c @@ -122,7 +122,7 @@ int et131x_rx_dma_memory_alloc(struct et131x_adapter *adapter) * number of entries in FBR1. * * FBR1 holds "large" frames, FBR0 holds "small" frames. If FBR1 - * entries are huge in order to accomodate a "jumbo" frame, then it + * entries are huge in order to accommodate a "jumbo" frame, then it * will have less entries. Conversely, FBR1 will now be relied upon * to carry more "normal" frames, thus it's entry size also increases * and the number of entries goes up too (since it now carries diff --git a/drivers/staging/et131x/et131x_isr.c b/drivers/staging/et131x/et131x_isr.c index ce4d93042679..f716e408712b 100644 --- a/drivers/staging/et131x/et131x_isr.c +++ b/drivers/staging/et131x/et131x_isr.c @@ -466,7 +466,7 @@ void et131x_isr_handler(struct work_struct *work) /* Handle SLV Timeout Interrupt */ if (status & ET_INTR_SLV_TIMEOUT) { /* - * This means a timeout has occured on a read or + * This means a timeout has occurred on a read or * write request to one of the JAGCore registers. The * Global Resources block has terminated the request * and on a read request, returned a "fake" value. diff --git a/drivers/staging/et131x/et131x_netdev.c b/drivers/staging/et131x/et131x_netdev.c index 0c298cae90d9..b25bae29042e 100644 --- a/drivers/staging/et131x/et131x_netdev.c +++ b/drivers/staging/et131x/et131x_netdev.c @@ -415,7 +415,7 @@ void et131x_multicast(struct net_device *netdev) */ PacketFilter = adapter->PacketFilter; - /* Clear the 'multicast' flag locally; becuase we only have a single + /* Clear the 'multicast' flag locally; because we only have a single * flag to check multicast, and multiple multicast addresses can be * set, this is the easiest way to determine if more than one * multicast address is being set. diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dev.h b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dev.h index 4a89bd1bbf74..0b63f051f27c 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dev.h +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dev.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------- // // Function: ft1000_read_reg -// Descripton: This function will read the value of a given ASIC register. +// Description: This function will read the value of a given ASIC register. // Input: // dev - device structure // offset - ASIC register offset @@ -49,7 +49,7 @@ static inline u16 ft1000_read_reg (struct net_device *dev, u16 offset) { //--------------------------------------------------------------------------- // // Function: ft1000_write_reg -// Descripton: This function will set the value for a given ASIC register. +// Description: This function will set the value for a given ASIC register. // Input: // dev - device structure // offset - ASIC register offset diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c index ff691d9b984e..eeb7dd43f9a8 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c @@ -90,7 +90,7 @@ MODULE_SUPPORTED_DEVICE("FT1000"); //--------------------------------------------------------------------------- // // Function: ft1000_asic_read -// Descripton: This function will retrieve the value of a specific ASIC +// Description: This function will retrieve the value of a specific ASIC // register. // Input: // dev - network device structure @@ -107,7 +107,7 @@ inline u16 ft1000_asic_read(struct net_device *dev, u16 offset) //--------------------------------------------------------------------------- // // Function: ft1000_asic_write -// Descripton: This function will set the value of a specific ASIC +// Description: This function will set the value of a specific ASIC // register. // Input: // dev - network device structure @@ -124,7 +124,7 @@ inline void ft1000_asic_write(struct net_device *dev, u16 offset, u16 value) //--------------------------------------------------------------------------- // // Function: ft1000_read_fifo_len -// Descripton: This function will read the ASIC Uplink FIFO status register +// Description: This function will read the ASIC Uplink FIFO status register // which will return the number of bytes remaining in the Uplink FIFO. // Sixteen bytes are subtracted to make sure that the ASIC does not // reach its threshold. @@ -148,7 +148,7 @@ static inline u16 ft1000_read_fifo_len(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_read_dpram -// Descripton: This function will read the specific area of dpram +// Description: This function will read the specific area of dpram // (Electrabuzz ASIC only) // Input: // dev - device structure @@ -175,7 +175,7 @@ u16 ft1000_read_dpram(struct net_device * dev, int offset) //--------------------------------------------------------------------------- // // Function: ft1000_write_dpram -// Descripton: This function will write to a specific area of dpram +// Description: This function will write to a specific area of dpram // (Electrabuzz ASIC only) // Input: // dev - device structure @@ -201,7 +201,7 @@ static inline void ft1000_write_dpram(struct net_device *dev, //--------------------------------------------------------------------------- // // Function: ft1000_read_dpram_mag_16 -// Descripton: This function will read the specific area of dpram +// Description: This function will read the specific area of dpram // (Magnemite ASIC only) // Input: // dev - device structure @@ -233,7 +233,7 @@ u16 ft1000_read_dpram_mag_16(struct net_device *dev, int offset, int Index) //--------------------------------------------------------------------------- // // Function: ft1000_write_dpram_mag_16 -// Descripton: This function will write to a specific area of dpram +// Description: This function will write to a specific area of dpram // (Magnemite ASIC only) // Input: // dev - device structure @@ -263,7 +263,7 @@ static inline void ft1000_write_dpram_mag_16(struct net_device *dev, //--------------------------------------------------------------------------- // // Function: ft1000_read_dpram_mag_32 -// Descripton: This function will read the specific area of dpram +// Description: This function will read the specific area of dpram // (Magnemite ASIC only) // Input: // dev - device structure @@ -290,7 +290,7 @@ u32 ft1000_read_dpram_mag_32(struct net_device *dev, int offset) //--------------------------------------------------------------------------- // // Function: ft1000_write_dpram_mag_32 -// Descripton: This function will write to a specific area of dpram +// Description: This function will write to a specific area of dpram // (Magnemite ASIC only) // Input: // dev - device structure @@ -315,7 +315,7 @@ void ft1000_write_dpram_mag_32(struct net_device *dev, int offset, u32 value) //--------------------------------------------------------------------------- // // Function: ft1000_enable_interrupts -// Descripton: This function will enable interrupts base on the current interrupt mask. +// Description: This function will enable interrupts base on the current interrupt mask. // Input: // dev - device structure // Output: @@ -340,7 +340,7 @@ static void ft1000_enable_interrupts(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_disable_interrupts -// Descripton: This function will disable all interrupts. +// Description: This function will disable all interrupts. // Input: // dev - device structure // Output: @@ -364,7 +364,7 @@ static void ft1000_disable_interrupts(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_reset_asic -// Descripton: This function will call the Card Service function to reset the +// Description: This function will call the Card Service function to reset the // ASIC. // Input: // dev - device structure @@ -408,7 +408,7 @@ static void ft1000_reset_asic(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_reset_card -// Descripton: This function will reset the card +// Description: This function will reset the card // Input: // dev - device structure // Output: @@ -571,7 +571,7 @@ static int ft1000_reset_card(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_chkcard -// Descripton: This function will check if the device is presently available on +// Description: This function will check if the device is presently available on // the system. // Input: // dev - device structure @@ -607,7 +607,7 @@ static int ft1000_chkcard(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_hbchk -// Descripton: This function will perform the heart beat check of the DSP as +// Description: This function will perform the heart beat check of the DSP as // well as the ASIC. // Input: // dev - device structure @@ -828,7 +828,7 @@ static void ft1000_hbchk(u_long data) //--------------------------------------------------------------------------- // // Function: ft1000_send_cmd -// Descripton: +// Description: // Input: // Output: // @@ -908,7 +908,7 @@ void ft1000_send_cmd (struct net_device *dev, u16 *ptempbuffer, int size, u16 qt //--------------------------------------------------------------------------- // // Function: ft1000_receive_cmd -// Descripton: This function will read a message from the dpram area. +// Description: This function will read a message from the dpram area. // Input: // dev - network device structure // pbuffer - caller supply address to buffer @@ -1003,7 +1003,7 @@ BOOLEAN ft1000_receive_cmd(struct net_device *dev, u16 * pbuffer, int maxsz, u16 //--------------------------------------------------------------------------- // // Function: ft1000_proc_drvmsg -// Descripton: This function will process the various driver messages. +// Description: This function will process the various driver messages. // Input: // dev - device structure // pnxtph - pointer to next pseudo header @@ -1285,7 +1285,7 @@ void ft1000_proc_drvmsg(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_parse_dpram_msg -// Descripton: This function will parse the message received from the DSP +// Description: This function will parse the message received from the DSP // via the DPRAM interface. // Input: // dev - device structure @@ -1442,7 +1442,7 @@ int ft1000_parse_dpram_msg(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_flush_fifo -// Descripton: This function will flush one packet from the downlink +// Description: This function will flush one packet from the downlink // FIFO. // Input: // dev - device structure @@ -1587,7 +1587,7 @@ static void ft1000_flush_fifo(struct net_device *dev, u16 DrvErrNum) //--------------------------------------------------------------------------- // // Function: ft1000_copy_up_pkt -// Descripton: This function will pull Flarion packets out of the Downlink +// Description: This function will pull Flarion packets out of the Downlink // FIFO and convert it to an ethernet packet. The ethernet packet will // then be deliver to the TCP/IP stack. // Input: @@ -1773,7 +1773,7 @@ int ft1000_copy_up_pkt(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_copy_down_pkt -// Descripton: This function will take an ethernet packet and convert it to +// Description: This function will take an ethernet packet and convert it to // a Flarion packet prior to sending it to the ASIC Downlink // FIFO. // Input: diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c index 8e622425aa13..1972b72450d4 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_download.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_download.c @@ -488,7 +488,7 @@ static int check_buffers(u16 *buff_w, u16 *buff_r, int len, int offset) // Parameters: struct ft1000_device - device structure // u16 **pUsFile - DSP image file pointer in u16 // u8 **pUcFile - DSP image file pointer in u8 -// long word_length - lenght of the buffer to be written +// long word_length - length of the buffer to be written // to DPRAM // // Returns: STATUS_SUCCESS - success @@ -628,7 +628,7 @@ static void usb_dnld_complete (struct urb *urb) // Parameters: struct ft1000_device - device structure // u16 **pUsFile - DSP image file pointer in u16 // u8 **pUcFile - DSP image file pointer in u8 -// long word_length - lenght of the buffer to be written +// long word_length - length of the buffer to be written // to DPRAM // // Returns: STATUS_SUCCESS - success @@ -817,7 +817,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, * Error, beyond boot code range. */ DEBUG - ("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundry.\n", + ("FT1000:download:Download error: Requested len=%d exceeds BOOT code boundary.\n", (int)word_length); status = STATUS_FAILURE; break; @@ -950,7 +950,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, * Error, beyond boot code range. */ DEBUG - ("FT1000:download:Download error: Requested len=%d exceeds DSP code boundry.\n", + ("FT1000:download:Download error: Requested len=%d exceeds DSP code boundary.\n", (int)word_length); status = STATUS_FAILURE; break; diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 78dcd49bb985..684e69eacb71 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -585,7 +585,7 @@ int dsp_reload(struct ft1000_device *ft1000dev) //--------------------------------------------------------------------------- // // Function: ft1000_reset_asic -// Descripton: This function will call the Card Service function to reset the +// Description: This function will call the Card Service function to reset the // ASIC. // Input: // dev - device structure @@ -626,7 +626,7 @@ static void ft1000_reset_asic(struct net_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_reset_card -// Descripton: This function will reset the card +// Description: This function will reset the card // Input: // dev - device structure // Output: @@ -917,7 +917,7 @@ static void ft1000_usb_transmit_complete(struct urb *urb) //--------------------------------------------------------------------------- // // Function: ft1000_copy_down_pkt -// Descripton: This function will take an ethernet packet and convert it to +// Description: This function will take an ethernet packet and convert it to // a Flarion packet prior to sending it to the ASIC Downlink // FIFO. // Input: @@ -1075,10 +1075,10 @@ err: //--------------------------------------------------------------------------- // // Function: ft1000_copy_up_pkt -// Descripton: This function will take a packet from the FIFO up link and +// Description: This function will take a packet from the FIFO up link and // convert it into an ethernet packet and deliver it to the IP stack // Input: -// urb - the receving usb urb +// urb - the receiving usb urb // // Output: // status - FAILURE @@ -1182,7 +1182,7 @@ static int ft1000_copy_up_pkt(struct urb *urb) //--------------------------------------------------------------------------- // // Function: ft1000_submit_rx_urb -// Descripton: the receiving function of the network driver +// Description: the receiving function of the network driver // // Input: // info - a private structure contains the device information @@ -1316,7 +1316,7 @@ Jim //--------------------------------------------------------------------------- // // Function: ft1000_chkcard -// Descripton: This function will check if the device is presently available on +// Description: This function will check if the device is presently available on // the system. // Input: // dev - device structure @@ -1363,7 +1363,7 @@ static int ft1000_chkcard(struct ft1000_device *dev) //--------------------------------------------------------------------------- // // Function: ft1000_receive_cmd -// Descripton: This function will read a message from the dpram area. +// Description: This function will read a message from the dpram area. // Input: // dev - network device structure // pbuffer - caller supply address to buffer diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h index 3f72d5bb3f92..6a8a1969f9e1 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_ioctl.h @@ -55,7 +55,7 @@ struct pseudo_hdr { unsigned char seq_num; //sequence number unsigned char rsvd2; //reserved unsigned short qos_class; //Quality of Service class (Not applicable on Mobile) - unsigned short checksum; //Psuedo header checksum + unsigned short checksum; //Pseudo header checksum } __attribute__ ((packed)); typedef struct _IOCTL_GET_VER diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index e047c03fbf3a..f2ecb3eae9cd 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -364,7 +364,7 @@ struct prov_record { #define ISR_EMPTY (u8)0x00 // no bits set in ISR -#define ISR_DOORBELL_ACK (u8)0x01 // the doorbell i sent has been recieved. +#define ISR_DOORBELL_ACK (u8)0x01 // the doorbell i sent has been received. #define ISR_DOORBELL_PEND (u8)0x02 // doorbell for me diff --git a/drivers/staging/generic_serial/generic_serial.c b/drivers/staging/generic_serial/generic_serial.c index 466988dbc37d..f29dda4e9f20 100644 --- a/drivers/staging/generic_serial/generic_serial.c +++ b/drivers/staging/generic_serial/generic_serial.c @@ -113,7 +113,7 @@ int gs_write(struct tty_struct * tty, c = count; - /* This is safe because we "OWN" the "head". Noone else can + /* This is safe because we "OWN" the "head". No one else can change the "head": we own the port_write_mutex. */ /* Don't overrun the end of the buffer */ t = SERIAL_XMIT_SIZE - port->xmit_head; diff --git a/drivers/staging/generic_serial/rio/map.h b/drivers/staging/generic_serial/rio/map.h index 8366978578c1..28a66129293e 100644 --- a/drivers/staging/generic_serial/rio/map.h +++ b/drivers/staging/generic_serial/rio/map.h @@ -87,7 +87,7 @@ struct Map { ** The Topology array contains the ID of the unit connected to each of the ** four links on this unit. The entry will be 0xFFFF if NOTHING is connected ** to the link, or will be 0xFF00 if an UNKNOWN unit is connected to the link. -** The Name field is a null-terminated string, upto 31 characters, containing +** The Name field is a null-terminated string, up to 31 characters, containing ** the 'cute' name that the sysadmin/users know the RTA by. It is permissible ** for this string to contain any character in the range \040 to \176 inclusive. ** In particular, ctrl sequences and DEL (0x7F, \177) are not allowed. The diff --git a/drivers/staging/generic_serial/rio/rioboot.c b/drivers/staging/generic_serial/rio/rioboot.c index d956dd316005..ffa01c590216 100644 --- a/drivers/staging/generic_serial/rio/rioboot.c +++ b/drivers/staging/generic_serial/rio/rioboot.c @@ -109,7 +109,7 @@ int RIOBootCodeRTA(struct rio_info *p, struct DownLoad * rbp) rio_dprintk(RIO_DEBUG_BOOT, "Data at user address %p\n", rbp->DataP); /* - ** Check that we have set asside enough memory for this + ** Check that we have set aside enough memory for this */ if (rbp->Count > SIXTY_FOUR_K) { rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n"); @@ -293,7 +293,7 @@ int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp) /* ** S T O P ! ** - ** Upto this point the code has been fairly rational, and possibly + ** Up to this point the code has been fairly rational, and possibly ** even straight forward. What follows is a pile of crud that will ** magically turn into six bytes of transputer assembler. Normally ** you would expect an array or something, but, being me, I have @@ -419,7 +419,7 @@ int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp) rio_dprintk(RIO_DEBUG_BOOT, "Set control port\n"); /* - ** Now, wait for upto five seconds for the Tp to setup the parmmap + ** Now, wait for up to five seconds for the Tp to setup the parmmap ** pointer: */ for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && (readw(&HostP->__ParmMapR) == OldParmMap); wait_count++) { @@ -475,7 +475,7 @@ int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp) /* ** now wait for the card to set all the parmmap->XXX stuff - ** this is a wait of upto two seconds.... + ** this is a wait of up to two seconds.... */ rio_dprintk(RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n", p->RIOConf.StartupTime); HostP->timeout_id = 0; diff --git a/drivers/staging/generic_serial/rio/riocmd.c b/drivers/staging/generic_serial/rio/riocmd.c index f121357e5af0..61efd538e850 100644 --- a/drivers/staging/generic_serial/rio/riocmd.c +++ b/drivers/staging/generic_serial/rio/riocmd.c @@ -863,7 +863,7 @@ int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP) ** being transferred from the write queue into the transmit packets ** (add_transmit) and no furthur transmit interrupt will be sent for that ** data. The next interrupt will occur up to 500ms later (RIOIntr is called - ** twice a second as a saftey measure). This was the case when kermit was + ** twice a second as a safety measure). This was the case when kermit was ** used to send data into a RIO port. After each packet was sent, TCFLSH ** was called to flush the read queue preemptively. PortP->InUse was ** incremented, thereby blocking the 6 byte acknowledgement packet diff --git a/drivers/staging/generic_serial/rio/rioroute.c b/drivers/staging/generic_serial/rio/rioroute.c index f9b936ac3394..8757378e8320 100644 --- a/drivers/staging/generic_serial/rio/rioroute.c +++ b/drivers/staging/generic_serial/rio/rioroute.c @@ -450,7 +450,7 @@ int RIORouteRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct ** we reset the unit, because we didn't boot it. ** However, if the table is full, it could be that we did boot ** this unit, and so we won't reboot it, because it isn't really - ** all that disasterous to keep the old bins in most cases. This + ** all that disastrous to keep the old bins in most cases. This ** is a rather tacky feature, but we are on the edge of reallity ** here, because the implication is that someone has connected ** 16+MAX_EXTRA_UNITS onto one host. @@ -678,7 +678,7 @@ static int RIOCheck(struct Host *HostP, unsigned int UnitId) HostP->Mapping[UnitId].Flags &= ~BEEN_HERE; - /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESNT KNOW THE HOST!\n", UnitId)); */ + /* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESN'T KNOW THE HOST!\n", UnitId)); */ return 0; } diff --git a/drivers/staging/generic_serial/rio/riotty.c b/drivers/staging/generic_serial/rio/riotty.c index 8a90393faf3c..e7e9911d7a72 100644 --- a/drivers/staging/generic_serial/rio/riotty.c +++ b/drivers/staging/generic_serial/rio/riotty.c @@ -124,7 +124,7 @@ int riotopen(struct tty_struct *tty, struct file *filp) } /* - ** Grab pointer to the port stucture + ** Grab pointer to the port structure */ PortP = p->RIOPortp[SysPort]; /* Get control struc */ rio_dprintk(RIO_DEBUG_TTY, "PortP: %p\n", PortP); @@ -161,7 +161,7 @@ int riotopen(struct tty_struct *tty, struct file *filp) } /* - ** If the RTA has not booted yet and the user has choosen to block + ** If the RTA has not booted yet and the user has chosen to block ** until the RTA is present then we must spin here waiting for ** the RTA to boot. */ diff --git a/drivers/staging/generic_serial/sx.c b/drivers/staging/generic_serial/sx.c index 1291462bcddb..4f94aaffbe83 100644 --- a/drivers/staging/generic_serial/sx.c +++ b/drivers/staging/generic_serial/sx.c @@ -158,13 +158,13 @@ * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS). * * Revision 0.12 1999/03/28 09:20:10 wolff - * Fixed problem in 0.11, continueing cleanup. + * Fixed problem in 0.11, continuing cleanup. * * Revision 0.11 1999/03/28 08:46:44 wolff * cleanup. Not good. * * Revision 0.10 1999/03/28 08:09:43 wolff - * Fixed loosing characters on close. + * Fixed losing characters on close. * * Revision 0.9 1999/03/21 22:52:01 wolff * Ported back to 2.2.... (minor things) @@ -1588,7 +1588,7 @@ static void sx_close(void *ptr) #define R0 if (read_sx_byte(board, i) != 0x55) return 1 #define R1 if (read_sx_byte(board, i) != 0xaa) return 1 -/* This memtest takes a human-noticable time. You normally only do it +/* This memtest takes a human-noticeable time. You normally only do it once a boot, so I guess that it is worth it. */ static int do_memtest(struct sx_board *board, int min, int max) { @@ -1645,7 +1645,7 @@ static int do_memtest(struct sx_board *board, int min, int max) #define R1 if (read_sx_word(board, i) != 0xaa55) return 1 #if 0 -/* This memtest takes a human-noticable time. You normally only do it +/* This memtest takes a human-noticeable time. You normally only do it once a boot, so I guess that it is worth it. */ static int do_memtest_w(struct sx_board *board, int min, int max) { diff --git a/drivers/staging/gma500/psb_drm.h b/drivers/staging/gma500/psb_drm.h index fb9b4245bada..a339406052ef 100644 --- a/drivers/staging/gma500/psb_drm.h +++ b/drivers/staging/gma500/psb_drm.h @@ -131,7 +131,7 @@ struct drm_psb_reloc { u32 pre_add; /* Destination format: */ u32 background; /* Destination add */ u32 dst_buffer; /* Destination buffer. Index into buffer_list */ - u32 arg0; /* Reloc-op dependant */ + u32 arg0; /* Reloc-op dependent */ u32 arg1; }; diff --git a/drivers/staging/gma500/psb_drv.c b/drivers/staging/gma500/psb_drv.c index 44cd095d2862..d01d45e7a14d 100644 --- a/drivers/staging/gma500/psb_drv.c +++ b/drivers/staging/gma500/psb_drv.c @@ -561,7 +561,7 @@ static int psb_driver_unload(struct drm_device *dev) kfree(dev_priv); dev->dev_private = NULL; - /*destory VBT data*/ + /*destroy VBT data*/ psb_intel_destroy_bios(dev); } diff --git a/drivers/staging/gma500/psb_intel_bios.c b/drivers/staging/gma500/psb_intel_bios.c index f5bcd119b87d..48ac8ba7f40b 100644 --- a/drivers/staging/gma500/psb_intel_bios.c +++ b/drivers/staging/gma500/psb_intel_bios.c @@ -271,7 +271,7 @@ bool psb_intel_init_bios(struct drm_device *dev) } /** - * Destory and free VBT data + * Destroy and free VBT data */ void psb_intel_destroy_bios(struct drm_device *dev) { diff --git a/drivers/staging/gma500/psb_intel_sdvo.c b/drivers/staging/gma500/psb_intel_sdvo.c index 731a5a2261d3..1d2bb021c0a5 100644 --- a/drivers/staging/gma500/psb_intel_sdvo.c +++ b/drivers/staging/gma500/psb_intel_sdvo.c @@ -573,7 +573,7 @@ static bool psb_sdvo_set_current_inoutmap(struct psb_intel_output *output, /* Make all fields of the args/ret to zero */ memset(byArgs, 0, sizeof(byArgs)); - /* Fill up the arguement values; */ + /* Fill up the argument values; */ byArgs[0] = (u8) (in0outputmask & 0xFF); byArgs[1] = (u8) ((in0outputmask >> 8) & 0xFF); byArgs[2] = (u8) (in1outputmask & 0xFF); diff --git a/drivers/staging/gma500/psb_intel_sdvo_regs.h b/drivers/staging/gma500/psb_intel_sdvo_regs.h index a1d1475a9315..c7107a37e33d 100644 --- a/drivers/staging/gma500/psb_intel_sdvo_regs.h +++ b/drivers/staging/gma500/psb_intel_sdvo_regs.h @@ -217,7 +217,7 @@ struct psb_intel_sdvo_set_target_input_args { } __attribute__ ((packed)); /** - * Takes a struct psb_intel_sdvo_output_flags of which outputs are targetted by + * Takes a struct psb_intel_sdvo_output_flags of which outputs are targeted by * future output commands. * * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12], diff --git a/drivers/staging/gma500/psb_ttm_fence_user.h b/drivers/staging/gma500/psb_ttm_fence_user.h index fc13f89c6e12..762a05728632 100644 --- a/drivers/staging/gma500/psb_ttm_fence_user.h +++ b/drivers/staging/gma500/psb_ttm_fence_user.h @@ -130,7 +130,7 @@ struct ttm_fence_unref_arg { }; /* - * Ioctl offsets frome extenstion start. + * Ioctl offsets from extenstion start. */ #define TTM_FENCE_SIGNALED 0x01 diff --git a/drivers/staging/go7007/go7007.txt b/drivers/staging/go7007/go7007.txt index 06a76da32128..9db1f3952fd2 100644 --- a/drivers/staging/go7007/go7007.txt +++ b/drivers/staging/go7007/go7007.txt @@ -2,7 +2,7 @@ This is a driver for the WIS GO7007SB multi-format video encoder. Pete Eberlein -The driver was orignally released under the GPL and is currently hosted at: +The driver was originally released under the GPL and is currently hosted at: http://nikosapi.org/wiki/index.php/WIS_Go7007_Linux_driver The go7007 firmware can be acquired from the package on the site above. diff --git a/drivers/staging/hv/blkvsc_drv.c b/drivers/staging/hv/blkvsc_drv.c index af789937be4e..68ad17d67098 100644 --- a/drivers/staging/hv/blkvsc_drv.c +++ b/drivers/staging/hv/blkvsc_drv.c @@ -894,7 +894,7 @@ static int blkvsc_submit_request(struct blkvsc_request *blkvsc_req, /* * We break the request into 1 or more blkvsc_requests and submit - * them. If we cant submit them all, we put them on the + * them. If we can't submit them all, we put them on the * pending_list. The blkvsc_request() will work on the pending_list. */ static int blkvsc_do_request(struct block_device_context *blkdev, diff --git a/drivers/staging/hv/channel_mgmt.c b/drivers/staging/hv/channel_mgmt.c index bc0393a41d29..06b573227e8d 100644 --- a/drivers/staging/hv/channel_mgmt.c +++ b/drivers/staging/hv/channel_mgmt.c @@ -166,7 +166,7 @@ EXPORT_SYMBOL(prep_negotiate_resp); * from Hyper-V. This stub responds to the default negotiate messages * that come in for every non IDE/SCSI/Network request. * This behavior is normally overwritten in the hv_utils driver. That - * driver handles requests like gracefull shutdown, heartbeats etc. + * driver handles requests like graceful shutdown, heartbeats etc. * * Mainly used by Hyper-V drivers. */ diff --git a/drivers/staging/hv/hv.c b/drivers/staging/hv/hv.c index 2d492adb95bb..0b06f4fe5838 100644 --- a/drivers/staging/hv/hv.c +++ b/drivers/staging/hv/hv.c @@ -37,7 +37,7 @@ struct hv_context hv_context = { /* * query_hypervisor_presence - * - Query the cpuid for presense of windows hypervisor + * - Query the cpuid for presence of windows hypervisor */ static int query_hypervisor_presence(void) { diff --git a/drivers/staging/hv/hv_api.h b/drivers/staging/hv/hv_api.h index 7114fceab21e..43a722888dc4 100644 --- a/drivers/staging/hv/hv_api.h +++ b/drivers/staging/hv/hv_api.h @@ -53,14 +53,14 @@ struct hv_guid { /* * HV_STATUS_INVALID_ALIGNMENT - * The hypervisor could not perform the operation beacuse a parameter has an + * The hypervisor could not perform the operation because a parameter has an * invalid alignment. */ #define HV_STATUS_INVALID_ALIGNMENT ((u16)0x0004) /* * HV_STATUS_INVALID_PARAMETER - * The hypervisor could not perform the operation beacuse an invalid parameter + * The hypervisor could not perform the operation because an invalid parameter * was specified. */ #define HV_STATUS_INVALID_PARAMETER ((u16)0x0005) diff --git a/drivers/staging/hv/hv_kvp.h b/drivers/staging/hv/hv_kvp.h index e069f59b5135..8c402f357d37 100644 --- a/drivers/staging/hv/hv_kvp.h +++ b/drivers/staging/hv/hv_kvp.h @@ -36,7 +36,7 @@ * registry. * * Note: This value is used in defining the KVP exchange message - this value - * cannot be modified without affecting the message size and compatability. + * cannot be modified without affecting the message size and compatibility. */ /* diff --git a/drivers/staging/hv/hv_util.c b/drivers/staging/hv/hv_util.c index 4792f2c402b2..2df15683f8fa 100644 --- a/drivers/staging/hv/hv_util.c +++ b/drivers/staging/hv/hv_util.c @@ -80,7 +80,7 @@ static void shutdown_onchannelcallback(void *context) execute_shutdown = true; DPRINT_INFO(VMBUS, "Shutdown request received -" - " gracefull shutdown initiated"); + " graceful shutdown initiated"); break; default: icmsghdrp->status = HV_E_FAIL; diff --git a/drivers/staging/hv/rndis_filter.c b/drivers/staging/hv/rndis_filter.c index e7189cd324ca..048376b2b676 100644 --- a/drivers/staging/hv/rndis_filter.c +++ b/drivers/staging/hv/rndis_filter.c @@ -585,7 +585,7 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev, ret = -1; DPRINT_ERR(NETVSC, "timeout before we got a set response..."); /* - * We cant deallocate the request since we may still receive a + * We can't deallocate the request since we may still receive a * send completion for it. */ goto Exit; diff --git a/drivers/staging/hv/tools/hv_kvp_daemon.c b/drivers/staging/hv/tools/hv_kvp_daemon.c index f5a2dd694611..aa77a971aace 100644 --- a/drivers/staging/hv/tools/hv_kvp_daemon.c +++ b/drivers/staging/hv/tools/hv_kvp_daemon.c @@ -202,7 +202,7 @@ kvp_get_ip_address(int family, char *buffer, int length) /* * We only support AF_INET and AF_INET6 - * and the list of addresses is seperated by a ";". + * and the list of addresses is separated by a ";". */ struct sockaddr_in6 *addr = (struct sockaddr_in6 *) curp->ifa_addr; diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index 8095727b3966..fd78e4ff99ae 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -556,7 +556,7 @@ int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) if (strcmp(temp, val) != 0) { printf("Possible failure in string write of %s " "Should be %s " - "writen to %s\%s\n", + "written to %s\%s\n", temp, val, basedir, diff --git a/drivers/staging/iio/accel/adis16201.h b/drivers/staging/iio/accel/adis16201.h index c9bf22c13428..23fe54d09d12 100644 --- a/drivers/staging/iio/accel/adis16201.h +++ b/drivers/staging/iio/accel/adis16201.h @@ -70,7 +70,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16201_state { diff --git a/drivers/staging/iio/accel/adis16203.h b/drivers/staging/iio/accel/adis16203.h index b39323eac9e3..b88688128d61 100644 --- a/drivers/staging/iio/accel/adis16203.h +++ b/drivers/staging/iio/accel/adis16203.h @@ -65,7 +65,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16203_state { diff --git a/drivers/staging/iio/accel/adis16204.h b/drivers/staging/iio/accel/adis16204.h index e9ed7cb048cf..e61844684f99 100644 --- a/drivers/staging/iio/accel/adis16204.h +++ b/drivers/staging/iio/accel/adis16204.h @@ -73,7 +73,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16204_state { diff --git a/drivers/staging/iio/accel/adis16209.h b/drivers/staging/iio/accel/adis16209.h index 4e97596620ef..8b0da1349555 100644 --- a/drivers/staging/iio/accel/adis16209.h +++ b/drivers/staging/iio/accel/adis16209.h @@ -109,7 +109,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16209_state { diff --git a/drivers/staging/iio/accel/adis16220.h b/drivers/staging/iio/accel/adis16220.h index 7013314a9d77..4d5758c2c047 100644 --- a/drivers/staging/iio/accel/adis16220.h +++ b/drivers/staging/iio/accel/adis16220.h @@ -132,7 +132,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16220_state { diff --git a/drivers/staging/iio/accel/adis16240.h b/drivers/staging/iio/accel/adis16240.h index 51a807dde27c..76a45797b9dd 100644 --- a/drivers/staging/iio/accel/adis16240.h +++ b/drivers/staging/iio/accel/adis16240.h @@ -132,7 +132,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16240_state { diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h index 579b3a26e5d7..11402187f9ae 100644 --- a/drivers/staging/iio/accel/lis3l02dq.h +++ b/drivers/staging/iio/accel/lis3l02dq.h @@ -57,7 +57,7 @@ /* Reboot memory content */ #define LIS3L02DQ_REG_CTRL_2_REBOOT_MEMORY 0x10 -/* Interupt Enable - applies data ready to the RDY pad */ +/* Interrupt Enable - applies data ready to the RDY pad */ #define LIS3L02DQ_REG_CTRL_2_ENABLE_INTERRUPT 0x08 /* Enable Data Ready Generation - relationship with previous unclear in docs */ @@ -70,34 +70,34 @@ * - option for 16 bit left justified */ #define LIS3L02DQ_REG_CTRL_2_DATA_ALIGNMENT_16_BIT_LEFT_JUSTIFIED 0x01 -/* Interupt related stuff */ +/* Interrupt related stuff */ #define LIS3L02DQ_REG_WAKE_UP_CFG_ADDR 0x23 /* Switch from or combination fo conditions to and */ #define LIS3L02DQ_REG_WAKE_UP_CFG_BOOLEAN_AND 0x80 -/* Latch interupt request, +/* Latch interrupt request, * if on ack must be given by reading the ack register */ #define LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC 0x40 -/* Z Interupt on High (above threshold)*/ +/* Z Interrupt on High (above threshold)*/ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_HIGH 0x20 -/* Z Interupt on Low */ +/* Z Interrupt on Low */ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_LOW 0x10 -/* Y Interupt on High */ +/* Y Interrupt on High */ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_HIGH 0x08 -/* Y Interupt on Low */ +/* Y Interrupt on Low */ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Y_LOW 0x04 -/* X Interupt on High */ +/* X Interrupt on High */ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_HIGH 0x02 -/* X Interupt on Low */ +/* X Interrupt on Low */ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_X_LOW 0x01 -/* Register that gives description of what caused interupt +/* Register that gives description of what caused interrupt * - latched if set in CFG_ADDRES */ #define LIS3L02DQ_REG_WAKE_UP_SRC_ADDR 0x24 /* top bit ignored */ -/* Interupt Active */ +/* Interrupt Active */ #define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_ACTIVATED 0x40 /* Interupts that have been triggered */ #define LIS3L02DQ_REG_WAKE_UP_SRC_INTERRUPT_Z_HIGH 0x20 @@ -123,7 +123,7 @@ #define LIS3L02DQ_REG_STATUS_X_NEW_DATA 0x01 /* The accelerometer readings - low and high bytes. -Form of high byte dependant on justification set in ctrl reg */ +Form of high byte dependent on justification set in ctrl reg */ #define LIS3L02DQ_REG_OUT_X_L_ADDR 0x28 #define LIS3L02DQ_REG_OUT_X_H_ADDR 0x29 #define LIS3L02DQ_REG_OUT_Y_L_ADDR 0x2A @@ -155,7 +155,7 @@ Form of high byte dependant on justification set in ctrl reg */ * @inter: used to check if new interrupt has been triggered * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct lis3l02dq_state { diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index c4b4ab7e6423..3067f9662d20 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -77,7 +77,7 @@ int lis3l02dq_spi_read_reg_8(struct device *dev, u8 reg_address, u8 *val) /** * lis3l02dq_spi_write_reg_8() - write single byte to a register * @dev: device associated with child of actual device (iio_dev or iio_trig) - * @reg_address: the address of the register to be writen + * @reg_address: the address of the register to be written * @val: the value to write **/ int lis3l02dq_spi_write_reg_8(struct device *dev, diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 2c461a31f129..529a3cc6d0c7 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -217,7 +217,7 @@ static const u8 read_all_tx_array[] = { /** * lis3l02dq_read_all() Reads all channels currently selected * @st: device specific state - * @rx_array: (dma capable) recieve array, must be at least + * @rx_array: (dma capable) receive array, must be at least * 4*number of channels **/ static int lis3l02dq_read_all(struct lis3l02dq_state *st, u8 *rx_array) @@ -409,7 +409,7 @@ static const struct attribute_group lis3l02dq_trigger_attr_group = { * * As the trigger may occur on any data element being updated it is * really rather likely to occur during the read from the previous - * trigger event. The only way to discover if this has occured on + * trigger event. The only way to discover if this has occurred on * boards not supporting level interrupts is to take a look at the line. * If it is indicating another interrupt and we don't seem to have a * handler looking at it, then we need to notify the core that we need diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h index 23892848f5ae..db710334b99b 100644 --- a/drivers/staging/iio/accel/sca3000.h +++ b/drivers/staging/iio/accel/sca3000.h @@ -185,7 +185,7 @@ struct sca3000_state { }; /** - * struct sca3000_chip_info - model dependant parameters + * struct sca3000_chip_info - model dependent parameters * @name: model identification * @scale: string containing floating point scale factor * @temp_output: some devices have temperature sensors. @@ -213,7 +213,7 @@ struct sca3000_chip_info { * sca3000_read_data() read a series of values from the device * @dev: device * @reg_address_high: start address (decremented read) - * @rx: pointer where recieved data is placed. Callee + * @rx: pointer where received data is placed. Callee * responsible for freeing this. * @len: number of bytes to read * diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index c872fddfb2bf..a730a7638de1 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -43,7 +43,7 @@ * leading byte used in bus comms. * * Currently does not provide timestamps. As the hardware doesn't add them they - * can only be inferred aproximately from ring buffer events such as 50% full + * can only be inferred approximately from ring buffer events such as 50% full * and knowledge of when buffer was last emptied. This is left to userspace. **/ static int sca3000_rip_hw_rb(struct iio_ring_buffer *r, diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c index 19d1aced1e6c..9068d7f54d15 100644 --- a/drivers/staging/iio/adc/ad7298_ring.c +++ b/drivers/staging/iio/adc/ad7298_ring.c @@ -157,7 +157,7 @@ static int ad7298_ring_preenable(struct iio_dev *indio_dev) /** * ad7298_poll_func_th() th of trigger launched polling to ring buffer * - * As sampling only occurs on spi comms occuring, leave timestamping until + * As sampling only occurs on spi comms occurring, leave timestamping until * then. Some triggers will generate their own time stamp. Currently * there is no way of notifying them when no one cares. **/ diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c index 1d654c86099d..92d93787d5b8 100644 --- a/drivers/staging/iio/adc/ad7476_ring.c +++ b/drivers/staging/iio/adc/ad7476_ring.c @@ -112,7 +112,7 @@ static int ad7476_ring_preenable(struct iio_dev *indio_dev) /** * ad7476_poll_func_th() th of trigger launched polling to ring buffer * - * As sampling only occurs on i2c comms occuring, leave timestamping until + * As sampling only occurs on i2c comms occurring, leave timestamping until * then. Some triggers will generate their own time stamp. Currently * there is no way of notifying them when no one cares. **/ diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c index 2d7fe65049dd..da77f266c16b 100644 --- a/drivers/staging/iio/adc/ad7887_ring.c +++ b/drivers/staging/iio/adc/ad7887_ring.c @@ -165,7 +165,7 @@ static int ad7887_ring_postdisable(struct iio_dev *indio_dev) /** * ad7887_poll_func_th() th of trigger launched polling to ring buffer * - * As sampling only occurs on spi comms occuring, leave timestamping until + * As sampling only occurs on spi comms occurring, leave timestamping until * then. Some triggers will generate their own time stamp. Currently * there is no way of notifying them when no one cares. **/ diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index e50841b3ac69..f04e642e7272 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -184,7 +184,7 @@ static ssize_t ad799x_read_single_channel(struct device *dev, mutex_lock(&dev_info->mlock); mask = 1 << this_attr->address; - /* If ring buffer capture is occuring, query the buffer */ + /* If ring buffer capture is occurring, query the buffer */ if (iio_ring_enabled(dev_info)) { data = ret = ad799x_single_channel_from_ring(st, mask); if (ret < 0) diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c index 56abc395f177..0875a7ef67a5 100644 --- a/drivers/staging/iio/adc/ad799x_ring.c +++ b/drivers/staging/iio/adc/ad799x_ring.c @@ -101,7 +101,7 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev) /** * ad799x_poll_func_th() th of trigger launched polling to ring buffer * - * As sampling only occurs on i2c comms occuring, leave timestamping until + * As sampling only occurs on i2c comms occurring, leave timestamping until * then. Some triggers will generate their own time stamp. Currently * there is no way of notifying them when no one cares. **/ diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index dde097afb430..de83c3b37a2d 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -255,7 +255,7 @@ static ssize_t max1363_read_single_channel(struct device *dev, goto error_ret; } - /* If ring buffer capture is occuring, query the buffer */ + /* If ring buffer capture is occurring, query the buffer */ if (iio_ring_enabled(dev_info)) { mask = max1363_mode_table[this_attr->address].modemask; data = max1363_single_channel_from_ring(mask, st); @@ -1425,7 +1425,7 @@ error_ret: } /* - * To keep this managable we always use one of 3 scan modes. + * To keep this manageable we always use one of 3 scan modes. * Scan 0...3, 0-1,2-3 and 1-0,3-2 */ static inline int __max1363_check_event_mask(int thismask, int checkmask) diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c index 5532f3e466bc..d36fcc62e976 100644 --- a/drivers/staging/iio/adc/max1363_ring.c +++ b/drivers/staging/iio/adc/max1363_ring.c @@ -108,7 +108,7 @@ static int max1363_ring_preenable(struct iio_dev *indio_dev) /** * max1363_poll_func_th() - th of trigger launched polling to ring buffer * - * As sampling only occurs on i2c comms occuring, leave timestamping until + * As sampling only occurs on i2c comms occurring, leave timestamping until * then. Some triggers will generate their own time stamp. Currently * there is no way of notifying them when no one cares. **/ diff --git a/drivers/staging/iio/chrdev.h b/drivers/staging/iio/chrdev.h index 98d1a2c12df2..4fcb99c816f9 100644 --- a/drivers/staging/iio/chrdev.h +++ b/drivers/staging/iio/chrdev.h @@ -33,7 +33,7 @@ struct iio_handler { /** * struct iio_event_data - The actual event being pushed to userspace * @id: event identifier - * @timestamp: best estimate of time of event occurance (often from + * @timestamp: best estimate of time of event occurrence (often from * the interrupt handler) */ struct iio_event_data { @@ -42,7 +42,7 @@ struct iio_event_data { }; /** - * struct iio_detected_event_list - list element for events that have occured + * struct iio_detected_event_list - list element for events that have occurred * @list: linked list header * @ev: the event itself * @shared_pointer: used when the event is shared - i.e. can be escallated @@ -98,7 +98,7 @@ struct iio_event_interface { * @list: list header * @refcount: as the handler may be shared between multiple device * side events, reference counting ensures clean removal - * @exist_lock: prevents race conditions related to refcount useage. + * @exist_lock: prevents race conditions related to refcount usage. * @handler: event handler function - called on event if this * event_handler is enabled. * diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c index 700eb3980f9e..ae53e71d1c2f 100644 --- a/drivers/staging/iio/gyro/adis16060_core.c +++ b/drivers/staging/iio/gyro/adis16060_core.c @@ -30,7 +30,7 @@ * @us_w: actual spi_device to write config * @us_r: actual spi_device to read back data * @indio_dev: industrial I/O device structure - * @buf: transmit or recieve buffer + * @buf: transmit or receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16060_state { diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index fb4336c7d2a6..ef9e304a226d 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -35,7 +35,7 @@ * struct adis16080_state - device instance specific data * @us: actual spi_device to write data * @indio_dev: industrial I/O device structure - * @buf: transmit or recieve buffer + * @buf: transmit or receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16080_state { diff --git a/drivers/staging/iio/gyro/adis16260.h b/drivers/staging/iio/gyro/adis16260.h index c1fd4364287f..1369501b4096 100644 --- a/drivers/staging/iio/gyro/adis16260.h +++ b/drivers/staging/iio/gyro/adis16260.h @@ -91,7 +91,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx * @negate: negate the scale parameter **/ diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h index 248bdd2846fd..7127f26f8d26 100644 --- a/drivers/staging/iio/iio.h +++ b/drivers/staging/iio/iio.h @@ -92,7 +92,7 @@ void iio_remove_event_from_list(struct iio_event_handler_list *el, * changes * @available_scan_masks: [DRIVER] optional array of allowed bitmasks * @trig: [INTERN] current device trigger (ring buffer modes) - * @pollfunc: [DRIVER] function run on trigger being recieved + * @pollfunc: [DRIVER] function run on trigger being received **/ struct iio_dev { int id; diff --git a/drivers/staging/iio/imu/adis16300.h b/drivers/staging/iio/imu/adis16300.h index 1f25d68064a0..c0957591aed7 100644 --- a/drivers/staging/iio/imu/adis16300.h +++ b/drivers/staging/iio/imu/adis16300.h @@ -99,7 +99,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16300_state { diff --git a/drivers/staging/iio/imu/adis16350.h b/drivers/staging/iio/imu/adis16350.h index b00001e3edd0..b1ad48662a2c 100644 --- a/drivers/staging/iio/imu/adis16350.h +++ b/drivers/staging/iio/imu/adis16350.h @@ -105,7 +105,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16350_state { diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index 6ff33e1ad8c1..7a127029e099 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -131,7 +131,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct adis16400_state { diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index f3bf111f354f..1795ee1e8207 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -258,7 +258,7 @@ static ssize_t iio_event_chrdev_read(struct file *filep, ->det_events.list)); if (ret) goto error_ret; - /* Single access device so noone else can get the data */ + /* Single access device so no one else can get the data */ mutex_lock(&ev_int->event_list_lock); } diff --git a/drivers/staging/iio/meter/ade7753.h b/drivers/staging/iio/meter/ade7753.h index 70dabae6efe9..3b9c7f6a50e7 100644 --- a/drivers/staging/iio/meter/ade7753.h +++ b/drivers/staging/iio/meter/ade7753.h @@ -62,7 +62,7 @@ * @us: actual spi_device * @indio_dev: industrial I/O device structure * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct ade7753_state { diff --git a/drivers/staging/iio/meter/ade7754.h b/drivers/staging/iio/meter/ade7754.h index 8faa9b3b48b6..0aa0522a33a3 100644 --- a/drivers/staging/iio/meter/ade7754.h +++ b/drivers/staging/iio/meter/ade7754.h @@ -80,7 +80,7 @@ * @us: actual spi_device * @indio_dev: industrial I/O device structure * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct ade7754_state { diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h index df5bb7ba5a0f..c6fd94f3b3ee 100644 --- a/drivers/staging/iio/meter/ade7758.h +++ b/drivers/staging/iio/meter/ade7758.h @@ -98,7 +98,7 @@ * @indio_dev: industrial I/O device structure * @trig: data ready trigger registered with iio * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct ade7758_state { diff --git a/drivers/staging/iio/meter/ade7759.h b/drivers/staging/iio/meter/ade7759.h index e9d1c43336fe..cc76c2c4c039 100644 --- a/drivers/staging/iio/meter/ade7759.h +++ b/drivers/staging/iio/meter/ade7759.h @@ -43,7 +43,7 @@ * @us: actual spi_device * @indio_dev: industrial I/O device structure * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct ade7759_state { diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h index 4ad84a3bb462..79a21109f4e2 100644 --- a/drivers/staging/iio/meter/ade7854.h +++ b/drivers/staging/iio/meter/ade7854.h @@ -149,7 +149,7 @@ * @spi: actual spi_device * @indio_dev: industrial I/O device structure * @tx: transmit buffer - * @rx: recieve buffer + * @rx: receive buffer * @buf_lock: mutex to protect tx and rx **/ struct ade7854_state { diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h index f21ac09373cf..32948e55dc81 100644 --- a/drivers/staging/iio/ring_generic.h +++ b/drivers/staging/iio/ring_generic.h @@ -30,7 +30,7 @@ int iio_push_ring_event(struct iio_ring_buffer *ring_buf, * @event_code: event indentification code * @timestamp: time of event * - * Typical usecase is to escalate a 50% ring full to 75% full if noone has yet + * Typical usecase is to escalate a 50% ring full to 75% full if no one has yet * read the first event. Clearly the 50% full is no longer of interest in * typical use case. **/ diff --git a/drivers/staging/intel_sst/TODO b/drivers/staging/intel_sst/TODO index a24e5ed5689c..c733d7011091 100644 --- a/drivers/staging/intel_sst/TODO +++ b/drivers/staging/intel_sst/TODO @@ -1,7 +1,7 @@ TODO ---- -Get the memrar driver cleaned up and upstream (dependancy blocking SST) +Get the memrar driver cleaned up and upstream (dependency blocking SST) Replace long/short press with two virtual buttons Review the printks and kill off any left over ST_ERR: messages Review the misc device ioctls for 32/64bit safety and sanity diff --git a/drivers/staging/intel_sst/intel_sst.c b/drivers/staging/intel_sst/intel_sst.c index ce4a9f79ccd2..81c24d19eb9e 100644 --- a/drivers/staging/intel_sst/intel_sst.c +++ b/drivers/staging/intel_sst/intel_sst.c @@ -263,7 +263,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci, /* Init the device */ ret = pci_enable_device(pci); if (ret) { - pr_err("device cant be enabled\n"); + pr_err("device can't be enabled\n"); goto do_free_mem; } sst_drv_ctx->pci = pci_dev_get(pci); @@ -453,7 +453,7 @@ int intel_sst_resume(struct pci_dev *pci) pci_restore_state(pci); ret = pci_enable_device(pci); if (ret) - pr_err("device cant be enabled\n"); + pr_err("device can't be enabled\n"); mutex_lock(&sst_drv_ctx->sst_lock); sst_drv_ctx->sst_state = SST_UN_INIT; diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index a367991d5600..1d0621260ea8 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c @@ -236,7 +236,7 @@ int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma) if (!sst_drv_ctx->mmap_mem) return -EIO; - /* round it up to the page bondary */ + /* round it up to the page boundary */ /*mem_area = (void *)((((unsigned long)sst_drv_ctx->mmap_mem) + PAGE_SIZE - 1) & PAGE_MASK);*/ mem_area = (void *) PAGE_ALIGN((unsigned int) sst_drv_ctx->mmap_mem); @@ -871,7 +871,7 @@ int sst_send_algo_ipc(struct ipc_post **msg) } /** - * intel_sst_ioctl_dsp - recieves the device ioctl's + * intel_sst_ioctl_dsp - receives the device ioctl's * * @cmd:Ioctl cmd * @arg:data @@ -1067,7 +1067,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - pr_debug("SET_VOLUME recieved for %d!\n", + pr_debug("SET_VOLUME received for %d!\n", set_vol.stream_id); if (minor == STREAM_MODULE && set_vol.stream_id == 0) { pr_debug("invalid operation!\n"); @@ -1085,7 +1085,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - pr_debug("IOCTL_GET_VOLUME recieved for stream = %d!\n", + pr_debug("IOCTL_GET_VOLUME received for stream = %d!\n", get_vol.stream_id); if (minor == STREAM_MODULE && get_vol.stream_id == 0) { pr_debug("invalid operation!\n"); @@ -1117,7 +1117,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - pr_debug("SNDRV_SST_SET_VOLUME recieved for %d!\n", + pr_debug("SNDRV_SST_SET_VOLUME received for %d!\n", set_mute.stream_id); if (minor == STREAM_MODULE && set_mute.stream_id == 0) { retval = -EPERM; @@ -1153,7 +1153,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): { struct snd_sst_mmap_buffs mmap_buf; - pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n"); + pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE received!\n"); if (minor != STREAM_MODULE) { retval = -EBADRQC; break; @@ -1239,7 +1239,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): { struct snd_sst_target_device target_device; - pr_debug("SET_TARGET_DEVICE recieved!\n"); + pr_debug("SET_TARGET_DEVICE received!\n"); if (copy_from_user(&target_device, (void __user *)arg, sizeof(target_device))) { retval = -EFAULT; @@ -1256,7 +1256,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) case _IOC_NR(SNDRV_SST_DRIVER_INFO): { struct snd_sst_driver_info info; - pr_debug("SNDRV_SST_DRIVER_INFO recived\n"); + pr_debug("SNDRV_SST_DRIVER_INFO received\n"); info.version = SST_VERSION_NUM; /* hard coding, shud get sumhow later */ info.active_pcm_streams = sst_drv_ctx->stream_cnt - diff --git a/drivers/staging/intel_sst/intel_sst_drv_interface.c b/drivers/staging/intel_sst/intel_sst_drv_interface.c index ea8e251b5099..e9c182108243 100644 --- a/drivers/staging/intel_sst/intel_sst_drv_interface.c +++ b/drivers/staging/intel_sst/intel_sst_drv_interface.c @@ -315,7 +315,7 @@ int sst_open_pcm_stream(struct snd_sst_params *str_param) pm_runtime_get_sync(&sst_drv_ctx->pci->dev); if (sst_drv_ctx->sst_state == SST_SUSPENDED) { - /* LPE is suspended, resume it before proceding*/ + /* LPE is suspended, resume it before proceeding*/ pr_debug("Resuming from Suspended state\n"); retval = intel_sst_resume(sst_drv_ctx->pci); if (retval) { diff --git a/drivers/staging/intel_sst/intel_sst_dsp.c b/drivers/staging/intel_sst/intel_sst_dsp.c index 6e5c9152da9f..bffe4c6e2928 100644 --- a/drivers/staging/intel_sst/intel_sst_dsp.c +++ b/drivers/staging/intel_sst/intel_sst_dsp.c @@ -350,7 +350,7 @@ static int sst_download_library(const struct firmware *fw_lib, } -/* This function is called befoer downloading the codec/postprocessing +/* This function is called before downloading the codec/postprocessing library is set for download to SST DSP*/ static int sst_validate_library(const struct firmware *fw_lib, struct lib_slot_info *slot, @@ -405,7 +405,7 @@ exit: } -/* This function is called when FW requests for a particular libary download +/* This function is called when FW requests for a particular library download This function prepares the library to download*/ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops) { diff --git a/drivers/staging/intel_sst/intel_sst_fw_ipc.h b/drivers/staging/intel_sst/intel_sst_fw_ipc.h index 8df313d10d2a..0f0c5bbc5f4b 100644 --- a/drivers/staging/intel_sst/intel_sst_fw_ipc.h +++ b/drivers/staging/intel_sst/intel_sst_fw_ipc.h @@ -111,7 +111,7 @@ #define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */ #define IPC_IA_TARGET_DEV_CHNGD 0x98 /* error in processing a stream */ -#define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occured */ +#define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occurred */ /* L2S messages */ #define IPC_SC_DDR_LINK_UP 0xC0 #define IPC_SC_DDR_LINK_DOWN 0xC1 diff --git a/drivers/staging/intel_sst/intel_sst_stream.c b/drivers/staging/intel_sst/intel_sst_stream.c index 795e42ab7360..dd58be5b1975 100644 --- a/drivers/staging/intel_sst/intel_sst_stream.c +++ b/drivers/staging/intel_sst/intel_sst_stream.c @@ -98,7 +98,7 @@ static unsigned int get_mrst_stream_id(void) if (sst_drv_ctx->streams[i].status == STREAM_UN_INIT) return i; } - pr_debug("Didnt find empty stream for mrst\n"); + pr_debug("Didn't find empty stream for mrst\n"); return -EBUSY; } diff --git a/drivers/staging/intel_sst/intel_sst_stream_encoded.c b/drivers/staging/intel_sst/intel_sst_stream_encoded.c index 29753c7519a7..d5f07b878828 100644 --- a/drivers/staging/intel_sst/intel_sst_stream_encoded.c +++ b/drivers/staging/intel_sst/intel_sst_stream_encoded.c @@ -914,7 +914,7 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info, (void *) ((unsigned long) rar_buffers.bus_address); pr_debug("RAR buf addr in DnR (input buffer function)0x%lu", (unsigned long) str_info->decode_ibuf); - pr_debug("rar in DnR decode funtion/output b_add rar =0x%lu", + pr_debug("rar in DnR decode function/output b_add rar =0x%lu", (unsigned long) rar_buffers.bus_address); *input_index = i + 1; str_info->decode_isize = dbufs->ibufs->buff_entry[i].size; diff --git a/drivers/staging/intel_sst/intelmid.c b/drivers/staging/intel_sst/intelmid.c index fb2292186703..d207636a7b6d 100644 --- a/drivers/staging/intel_sst/intelmid.c +++ b/drivers/staging/intel_sst/intelmid.c @@ -773,7 +773,7 @@ static int __devinit snd_intelmad_sst_register( if (ret_val) return ret_val; sst_card_vendor_id = (vendor_addr.value & (MASK2|MASK1|MASK0)); - pr_debug("orginal n extrated vendor id = 0x%x %d\n", + pr_debug("original n extrated vendor id = 0x%x %d\n", vendor_addr.value, sst_card_vendor_id); if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) { pr_err("vendor card not supported!!\n"); diff --git a/drivers/staging/intel_sst/intelmid.h b/drivers/staging/intel_sst/intelmid.h index ca881b790cb2..e77da87e1df0 100644 --- a/drivers/staging/intel_sst/intelmid.h +++ b/drivers/staging/intel_sst/intelmid.h @@ -90,7 +90,7 @@ struct mad_jack_msg_wq { * @card_index: sound card index * @card_id: sound card id detected * @sstdrv_ops: ptr to sst driver ops - * @pdev: ptr to platfrom device + * @pdev: ptr to platform device * @irq: interrupt number detected * @pmic_status: Device status of sound card * @int_base: ptr to MMIO interrupt region diff --git a/drivers/staging/keucr/init.c b/drivers/staging/keucr/init.c index 5c01f28f0734..8af7c84daee2 100644 --- a/drivers/staging/keucr/init.c +++ b/drivers/staging/keucr/init.c @@ -90,7 +90,7 @@ int ENE_MSInit(struct us_data *us) result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0); if (result != USB_STOR_XFER_GOOD) { - printk(KERN_ERR "Exection MS Init Code Fail !!\n"); + printk(KERN_ERR "Execution MS Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -145,7 +145,7 @@ int ENE_SMInit(struct us_data *us) result = ENE_SendScsiCmd(us, FDIR_READ, &buf, 0); if (result != USB_STOR_XFER_GOOD) { printk(KERN_ERR - "Exection SM Init Code Fail !! result = %x\n", result); + "Execution SM Init Code Fail !! result = %x\n", result); return USB_STOR_TRANSPORT_ERROR; } diff --git a/drivers/staging/keucr/smilmain.c b/drivers/staging/keucr/smilmain.c index 2cbe9f897eef..95c688a5c95a 100644 --- a/drivers/staging/keucr/smilmain.c +++ b/drivers/staging/keucr/smilmain.c @@ -64,7 +64,7 @@ extern struct SSFDCTYPE Ssfdc; extern struct ADDRESS Media; extern struct CIS_AREA CisArea; -//BIT Controll Macro +//BIT Control Macro BYTE BitData[] = { 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 } ; #define Set_D_Bit(a,b) (a[(BYTE)((b)/8)]|= BitData[(b)%8]) #define Clr_D_Bit(a,b) (a[(BYTE)((b)/8)]&=~BitData[(b)%8]) @@ -76,7 +76,7 @@ extern BYTE IsXDCompliance; // -////Power Controll & Media Exist Check Function +////Power Control & Media Exist Check Function ////----- Init_D_SmartMedia() -------------------------------------------- //int Init_D_SmartMedia(void) //{ @@ -575,7 +575,7 @@ int Media_D_OneSectWriteFlush(PFDO_DEVICE_EXTENSION fdoExt) // return(SUCCESS); //} // -////Power Controll & Media Exist Check Subroutine +////Power Control & Media Exist Check Subroutine ////----- Initialize_D_Media() ------------------------------------------- //void Initialize_D_Media(void) //{ @@ -738,7 +738,7 @@ int Check_D_MediaFmt(struct us_data *us) // return(SUCCESS); //} */ -//SmartMedia Physical Address Controll Subroutine +//SmartMedia Physical Address Control Subroutine //----- Conv_D_MediaAddr() --------------------------------------------- int Conv_D_MediaAddr(struct us_data *us, DWORD addr) { diff --git a/drivers/staging/keucr/smilsub.c b/drivers/staging/keucr/smilsub.c index 80da61c37bff..4fe47422eb79 100644 --- a/drivers/staging/keucr/smilsub.c +++ b/drivers/staging/keucr/smilsub.c @@ -57,7 +57,7 @@ extern WORD WriteBlock; #define ODD 1 // Odd Page for 256byte/page -//SmartMedia Redundant buffer data Controll Subroutine +//SmartMedia Redundant buffer data Control Subroutine //----- Check_D_DataBlank() -------------------------------------------- int Check_D_DataBlank(BYTE *redundant) { @@ -1367,7 +1367,7 @@ BYTE _Check_D_DevCode(BYTE dcode) } } /* -////SmartMedia Power Controll Subroutine +////SmartMedia Power Control Subroutine ////----- Cnt_D_Reset() ---------------------------------------------- //void Cnt_D_Reset(void) //{ @@ -1478,7 +1478,7 @@ BYTE _Check_D_DevCode(BYTE dcode) //} // */ -//SmartMedia ECC Controll Subroutine +//SmartMedia ECC Control Subroutine //----- Check_D_ReadError() ---------------------------------------------- int Check_D_ReadError(BYTE *redundant) { diff --git a/drivers/staging/lirc/lirc_ene0100.h b/drivers/staging/lirc/lirc_ene0100.h index 776b693bb307..06bebd6acc46 100644 --- a/drivers/staging/lirc/lirc_ene0100.h +++ b/drivers/staging/lirc/lirc_ene0100.h @@ -81,7 +81,7 @@ /* CIR block settings */ #define ENE_CIR_CONF1 0xFEC0 -#define ENE_CIR_CONF1_ADC_ON 0x7 /* reciever on gpio40 enabled */ +#define ENE_CIR_CONF1_ADC_ON 0x7 /* receiver on gpio40 enabled */ #define ENE_CIR_CONF1_LEARN1 (1 << 3) /* enabled on learning mode */ #define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */ #define ENE_CIR_CONF1_TX_CARR (1 << 7) /* send TX carrier or not */ @@ -96,7 +96,7 @@ /* transmitter - not implemented yet */ /* KB3926C and higher */ -/* transmission is very similiar to recieving, a byte is written to */ +/* transmission is very similar to receiving, a byte is written to */ /* ENE_TX_INPUT, in same manner as it is read from sample buffer */ /* sample period is fixed*/ diff --git a/drivers/staging/memrar/memrar_handler.c b/drivers/staging/memrar/memrar_handler.c index cfcaa8e5b8e6..1d9399d6f10f 100644 --- a/drivers/staging/memrar/memrar_handler.c +++ b/drivers/staging/memrar/memrar_handler.c @@ -690,7 +690,7 @@ static int memrar_mmap(struct file *filp, struct vm_area_struct *vma) * @inode: inode to open * @filp: file handle * - * As we support multiple arbitary opens there is no work to be done + * As we support multiple arbitrary opens there is no work to be done * really. */ diff --git a/drivers/staging/msm/mdp4_overlay.c b/drivers/staging/msm/mdp4_overlay.c index de284c28faa1..b9acf5299297 100644 --- a/drivers/staging/msm/mdp4_overlay.c +++ b/drivers/staging/msm/mdp4_overlay.c @@ -696,7 +696,7 @@ void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe) stage = pipe->mixer_stage; mixer = pipe->mixer_num; - if (pipe != ctrl->stage[mixer][stage]) /* not runing */ + if (pipe != ctrl->stage[mixer][stage]) /* not running */ return; /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ diff --git a/drivers/staging/msm/mdp_ppp_dq.c b/drivers/staging/msm/mdp_ppp_dq.c index 3dc1c0cc61f9..3a687c7a5695 100644 --- a/drivers/staging/msm/mdp_ppp_dq.c +++ b/drivers/staging/msm/mdp_ppp_dq.c @@ -200,7 +200,7 @@ static void mdp_ppp_flush_dirty_djobs(void *cond) msm_fb_ensure_mem_coherency_after_dma(job->info, &job->req, 1); /* Schedule jobs for cleanup - * A seperate worker thread does this */ + * A separate worker thread does this */ queue_delayed_work(mdp_ppp_djob_clnr, &job->cleaner, mdp_timer_duration); } diff --git a/drivers/staging/msm/msm_fb.c b/drivers/staging/msm/msm_fb.c index a2f29d464051..e7ef836eb8de 100644 --- a/drivers/staging/msm/msm_fb.c +++ b/drivers/staging/msm/msm_fb.c @@ -859,7 +859,7 @@ static int msm_fb_register(struct msm_fb_data_type *mfd) break; default: - MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n", + MSM_FB_ERR("msm_fb_init: fb %d unknown image type!\n", mfd->index); return ret; } @@ -1793,9 +1793,9 @@ static int msmfb_async_blit(struct fb_info *info, void __user *p) /* * NOTE: The userspace issues blit operations in a sequence, the sequence * start with a operation marked START and ends in an operation marked - * END. It is guranteed by the userspace that all the blit operations + * END. It is guaranteed by the userspace that all the blit operations * between START and END are only within the regions of areas designated - * by the START and END operations and that the userspace doesnt modify + * by the START and END operations and that the userspace doesn't modify * those areas. Hence it would be enough to perform barrier/cache operations * only on the START and END operations. */ diff --git a/drivers/staging/octeon/cvmx-cmd-queue.h b/drivers/staging/octeon/cvmx-cmd-queue.h index 59d221422293..614653b686a0 100644 --- a/drivers/staging/octeon/cvmx-cmd-queue.h +++ b/drivers/staging/octeon/cvmx-cmd-queue.h @@ -214,7 +214,7 @@ static inline int __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id) /* * Warning: This code currently only works with devices that * have 256 queues or less. Devices with more than 16 queues - * are layed out in memory to allow cores quick access to + * are laid out in memory to allow cores quick access to * every 16th queue. This reduces cache thrashing when you are * running 16 queues per port to support lockless operation. */ diff --git a/drivers/staging/octeon/cvmx-fpa.h b/drivers/staging/octeon/cvmx-fpa.h index 50a8c91778fa..1f04f9658736 100644 --- a/drivers/staging/octeon/cvmx-fpa.h +++ b/drivers/staging/octeon/cvmx-fpa.h @@ -195,7 +195,7 @@ static inline void cvmx_fpa_async_alloc(uint64_t scr_addr, uint64_t pool) cvmx_fpa_iobdma_data_t data; /* - * Hardware only uses 64 bit alligned locations, so convert + * Hardware only uses 64 bit aligned locations, so convert * from byte address to 64-bit index */ data.s.scraddr = scr_addr >> 3; diff --git a/drivers/staging/octeon/cvmx-helper-board.h b/drivers/staging/octeon/cvmx-helper-board.h index 611a8e03c216..b465bec43553 100644 --- a/drivers/staging/octeon/cvmx-helper-board.h +++ b/drivers/staging/octeon/cvmx-helper-board.h @@ -81,7 +81,7 @@ extern int cvmx_helper_board_get_mii_address(int ipd_port); * @phy_addr: The address of the PHY to program * @link_flags: * Flags to control autonegotiation. Bit 0 is autonegotiation - * enable/disable to maintain backware compatability. + * enable/disable to maintain backware compatibility. * @link_info: Link speed to program. If the speed is zero and autonegotiation * is enabled, all possible negotiation speeds are advertised. * diff --git a/drivers/staging/octeon/cvmx-helper-util.c b/drivers/staging/octeon/cvmx-helper-util.c index 41ef8a40bb03..131182bf5abb 100644 --- a/drivers/staging/octeon/cvmx-helper-util.c +++ b/drivers/staging/octeon/cvmx-helper-util.c @@ -362,7 +362,7 @@ int __cvmx_helper_setup_gmx(int interface, int num_ports) } /** - * Returns the IPD/PKO port number for a port on teh given + * Returns the IPD/PKO port number for a port on the given * interface. * * @interface: Interface to use diff --git a/drivers/staging/octeon/cvmx-helper.c b/drivers/staging/octeon/cvmx-helper.c index 591506643d02..e9c5c836ceff 100644 --- a/drivers/staging/octeon/cvmx-helper.c +++ b/drivers/staging/octeon/cvmx-helper.c @@ -691,7 +691,7 @@ int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) if (!retry_cnt) cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT " - "get_work() timeout occured.\n"); + "get_work() timeout occurred.\n"); /* Free packet */ if (work) diff --git a/drivers/staging/octeon/cvmx-mdio.h b/drivers/staging/octeon/cvmx-mdio.h index f45dc49512f2..d88ab8d8e37d 100644 --- a/drivers/staging/octeon/cvmx-mdio.h +++ b/drivers/staging/octeon/cvmx-mdio.h @@ -254,7 +254,7 @@ typedef union { #define MDIO_CLAUSE_45_READ_INC 2 #define MDIO_CLAUSE_45_READ 3 -/* MMD identifiers, mostly for accessing devices withing XENPAK modules. */ +/* MMD identifiers, mostly for accessing devices within XENPAK modules. */ #define CVMX_MMD_DEVICE_PMA_PMD 1 #define CVMX_MMD_DEVICE_WIS 2 #define CVMX_MMD_DEVICE_PCS 3 diff --git a/drivers/staging/octeon/cvmx-pko.h b/drivers/staging/octeon/cvmx-pko.h index f068c1982497..de3412aada5d 100644 --- a/drivers/staging/octeon/cvmx-pko.h +++ b/drivers/staging/octeon/cvmx-pko.h @@ -98,7 +98,7 @@ typedef enum { /* * PKO doesn't do any locking. It is the responsibility of the * application to make sure that no other core is accessing - * the same queue at the smae time + * the same queue at the same time */ CVMX_PKO_LOCK_NONE = 0, /* @@ -324,7 +324,7 @@ static inline void cvmx_pko_doorbell(uint64_t port, uint64_t queue, * - CVMX_PKO_LOCK_NONE * - PKO doesn't do any locking. It is the responsibility * of the application to make sure that no other core - * is accessing the same queue at the smae time. + * is accessing the same queue at the same time. * - CVMX_PKO_LOCK_ATOMIC_TAG * - PKO performs an atomic tagswitch to insure exclusive * access to the output queue. This will maintain diff --git a/drivers/staging/octeon/cvmx-pow.h b/drivers/staging/octeon/cvmx-pow.h index bf9e069a898c..999aefe3274c 100644 --- a/drivers/staging/octeon/cvmx-pow.h +++ b/drivers/staging/octeon/cvmx-pow.h @@ -1492,8 +1492,8 @@ static inline void cvmx_pow_tag_sw_full(cvmx_wqe_t *wqp, uint32_t tag, /** * Switch to a NULL tag, which ends any ordering or * synchronization provided by the POW for the current - * work queue entry. This operation completes immediatly, - * so completetion should not be waited for. + * work queue entry. This operation completes immediately, + * so completion should not be waited for. * This function does NOT wait for previous tag switches to complete, * so the caller must ensure that any previous tag switches have completed. */ @@ -1532,8 +1532,8 @@ static inline void cvmx_pow_tag_sw_null_nocheck(void) /** * Switch to a NULL tag, which ends any ordering or * synchronization provided by the POW for the current - * work queue entry. This operation completes immediatly, - * so completetion should not be waited for. + * work queue entry. This operation completes immediately, + * so completion should not be waited for. * This function waits for any pending tag switches to complete * before requesting the switch to NULL. */ @@ -1672,7 +1672,7 @@ static inline void cvmx_pow_set_priority(uint64_t core_num, /** * Performs a tag switch and then an immediate deschedule. This completes - * immediatly, so completion must not be waited for. This function does NOT + * immediately, so completion must not be waited for. This function does NOT * update the wqe in DRAM to match arguments. * * This function does NOT wait for any prior tag switches to complete, so the @@ -1758,7 +1758,7 @@ static inline void cvmx_pow_tag_sw_desched_nocheck( /** * Performs a tag switch and then an immediate deschedule. This completes - * immediatly, so completion must not be waited for. This function does NOT + * immediately, so completion must not be waited for. This function does NOT * update the wqe in DRAM to match arguments. * * This function waits for any prior tag switches to complete, so the diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h index 23467563fe57..c745a72a0594 100644 --- a/drivers/staging/octeon/ethernet-util.h +++ b/drivers/staging/octeon/ethernet-util.h @@ -55,7 +55,7 @@ static inline int INTERFACE(int ipd_port) return 2; else if (ipd_port < 40) /* Interface 3 for loopback */ return 3; - else if (ipd_port == 40) /* Non existant interface for POW0 */ + else if (ipd_port == 40) /* Non existent interface for POW0 */ return 4; else panic("Illegal ipd_port %d passed to INTERFACE\n", ipd_port); diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index b154be7a2fe6..b5d21f6497f9 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -80,7 +80,7 @@ static int dcon_init_xo_1(struct dcon_priv *dcon) lob &= ~(1 << DCON_IRQ); outb(lob, 0x4d0); - /* Register the interupt handler */ + /* Register the interrupt handler */ if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", dcon)) { printk(KERN_ERR "olpc-dcon: failed to request DCON's irq\n"); goto err_req_irq; diff --git a/drivers/staging/pohmelfs/crypto.c b/drivers/staging/pohmelfs/crypto.c index 6540864216c8..5cca24fcf6ca 100644 --- a/drivers/staging/pohmelfs/crypto.c +++ b/drivers/staging/pohmelfs/crypto.c @@ -745,7 +745,7 @@ static int pohmelfs_crypto_init_handshake(struct pohmelfs_sb *psb) /* * At this point NETFS_CAPABILITIES response command - * should setup superblock in a way, which is acceptible + * should setup superblock in a way, which is acceptable * for both client and server, so if server refuses connection, * it will send error in transaction response. */ diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c index c45b09ed0d35..ca098cabc2bc 100644 --- a/drivers/staging/quatech_usb2/quatech_usb2.c +++ b/drivers/staging/quatech_usb2/quatech_usb2.c @@ -148,7 +148,7 @@ static struct usb_driver quausb2_usb_driver = { * value of the line status flags from the port * @shadowMSR: Last received state of the modem status register, holds * the value of the modem status received from the port - * @rcv_flush: Flag indicating that a receive flush has occured on + * @rcv_flush: Flag indicating that a receive flush has occurred on * the hardware. * @xmit_flush: Flag indicating that a transmit flush has been processed by * the hardware. @@ -156,7 +156,7 @@ static struct usb_driver quausb2_usb_driver = { * includes the size (excluding header) of URBs that have been submitted but * have not yet been sent to to the device, and bytes that have been sent out * of the port but not yet reported sent by the "xmit_empty" messages (which - * indicate the number of bytes sent each time they are recieved, despite the + * indicate the number of bytes sent each time they are received, despite the * misleading name). * - Starts at zero when port is initialised. * - is incremented by the size of the data to be written (no headers) @@ -649,7 +649,7 @@ static void qt2_close(struct usb_serial_port *port) /* although the USB side is now empty, the UART itself may * still be pushing characters out over the line, so we have to * wait testing the actual line status until the lines change - * indicating that the data is done transfering. */ + * indicating that the data is done transferring. */ /* FIXME: slow this polling down so it doesn't run the USB bus flat out * if it actually has to spend any time in this loop (which it normally * doesn't because the buffer is nearly empty) */ @@ -726,7 +726,7 @@ static int qt2_write(struct tty_struct *tty, struct usb_serial_port *port, return 0; } else if (port_extra->tx_pending_bytes >= QT2_FIFO_DEPTH) { /* buffer is full (==). > should not occur, but would indicate - * that an overflow had occured */ + * that an overflow had occurred */ dbg("%s(): port transmit buffer is full!", __func__); /* schedule_work(&port->work); commented in vendor driver */ return 0; @@ -823,7 +823,7 @@ static int qt2_write_room(struct tty_struct *tty) * reduce the free space count by the size of the dispatched write. * When a "transmit empty" message comes back up the USB read stream, * we decrement the count by the number of bytes reported sent, thus - * keeping track of the difference between sent and recieved bytes. + * keeping track of the difference between sent and received bytes. */ room = (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes); @@ -1795,7 +1795,7 @@ static void qt2_process_rx_char(struct usb_serial_port *port, } } -/** @brief Retreive the value of a register from the device +/** @brief Retrieve the value of a register from the device * * Issues a GET_REGISTER vendor-spcific request over the USB control * pipe to obtain a value back from a specific register on a specific diff --git a/drivers/staging/rt2860/chip/rtmp_phy.h b/drivers/staging/rt2860/chip/rtmp_phy.h index 98454df30a22..a52221f1294e 100644 --- a/drivers/staging/rt2860/chip/rtmp_phy.h +++ b/drivers/staging/rt2860/chip/rtmp_phy.h @@ -467,7 +467,7 @@ DBGPRINT_ERR("BBP write R%d=0x%x fail. BusyCnt= %d.bPCIclkOff = %d. \n", _I, BbpCsr.word, BusyCnt, (_A)->bPCIclkOff); \ } \ } else { \ - DBGPRINT_ERR("****** BBP_Write_Latch Buffer exceeds max boundry ****** \n"); \ + DBGPRINT_ERR("****** BBP_Write_Latch Buffer exceeds max boundary ****** \n"); \ } \ } #endif /* RTMP_MAC_PCI // */ diff --git a/drivers/staging/rt2860/common/ba_action.c b/drivers/staging/rt2860/common/ba_action.c index 62f6f6be4acb..133bc1b87d2c 100644 --- a/drivers/staging/rt2860/common/ba_action.c +++ b/drivers/staging/rt2860/common/ba_action.c @@ -28,7 +28,7 @@ #include "../rt_config.h" #include -#define BA_ORI_INIT_SEQ (pEntry->TxSeq[TID]) /*1 // inital sequence number of BA session */ +#define BA_ORI_INIT_SEQ (pEntry->TxSeq[TID]) /*1 // initial sequence number of BA session */ #define ORI_SESSION_MAX_RETRY 8 #define ORI_BA_SESSION_TIMEOUT (2000) /* ms */ @@ -1487,7 +1487,7 @@ static void ba_enqueue_reordering_packet(struct rt_rtmp_adapter *pAd, /* * flush all pending reordering mpdus - * and receving mpdu to upper layer + * and receiving mpdu to upper layer * make tcp/ip to take care reordering mechanism */ /*ba_refresh_reordering_mpdus(pAd, pBAEntry); */ diff --git a/drivers/staging/rt2860/common/cmm_aes.c b/drivers/staging/rt2860/common/cmm_aes.c index a99879bada42..d70d229a6e53 100644 --- a/drivers/staging/rt2860/common/cmm_aes.c +++ b/drivers/staging/rt2860/common/cmm_aes.c @@ -858,7 +858,7 @@ static uint32 KT1[256]; static uint32 KT2[256]; static uint32 KT3[256]; -/* platform-independant 32-bit integer manipulation macros */ +/* platform-independent 32-bit integer manipulation macros */ #define GET_UINT32(n,b,i) \ { \ diff --git a/drivers/staging/rt2860/common/cmm_cfg.c b/drivers/staging/rt2860/common/cmm_cfg.c index 24f439378439..727f79929258 100644 --- a/drivers/staging/rt2860/common/cmm_cfg.c +++ b/drivers/staging/rt2860/common/cmm_cfg.c @@ -223,7 +223,7 @@ int RT_CfgSetWepKey(struct rt_rtmp_adapter *pAd, pAdapter Pointer to our adapter keyString WPA pre-shared key string pHashStr String used for password hash function - hashStrLen Lenght of the hash string + hashStrLen Length of the hash string pPMKBuf Output buffer of WPAPSK key Return: diff --git a/drivers/staging/rt2860/common/cmm_data.c b/drivers/staging/rt2860/common/cmm_data.c index f6c193cb84ee..33799e1449ae 100644 --- a/drivers/staging/rt2860/common/cmm_data.c +++ b/drivers/staging/rt2860/common/cmm_data.c @@ -337,7 +337,7 @@ int MlmeHardTransmitMgmtRing(struct rt_rtmp_adapter *pAd, /* */ /* In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame */ - /* Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD */ + /* Data-Null packets also pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD */ /* if ((pHeader_802_11->FC.Type != BTYPE_DATA) && (pHeader_802_11->FC.Type != BTYPE_CNTL)) */ { if ((pHeader_802_11->FC.SubType == SUBTYPE_ACTION) || @@ -1933,7 +1933,7 @@ BOOLEAN RTMPCheckEtherType(struct rt_rtmp_adapter *pAd, void *pPacket) if (TypeLen <= 1500) { /* 802.3, 802.3 LLC */ /* - DestMAC(6) + SrcMAC(6) + Lenght(2) + + DestMAC(6) + SrcMAC(6) + Length(2) + DSAP(1) + SSAP(1) + Control(1) + if the DSAP = 0xAA, SSAP=0xAA, Contorl = 0x03, it has a 5-bytes SNAP header. => + SNAP (5, OriginationID(3) + etherType(2)) diff --git a/drivers/staging/rt2860/common/cmm_data_pci.c b/drivers/staging/rt2860/common/cmm_data_pci.c index 7af59ff9e220..bef0bbd8cef7 100644 --- a/drivers/staging/rt2860/common/cmm_data_pci.c +++ b/drivers/staging/rt2860/common/cmm_data_pci.c @@ -438,13 +438,13 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, /* Add Rx size to channel load counter, we should ignore error counts */ pAd->StaCfg.CLBusyBytes += (pRxD->SDL0 + 14); - /* Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics */ + /* Drop ToDs promiscuous frame, it is opened due to CCX 2 channel load statistics */ if (pHeader != NULL) { if (pHeader->FC.ToDs) { return (NDIS_STATUS_FAILURE); } } - /* Drop not U2M frames, cant's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ @@ -939,7 +939,7 @@ int MlmeHardTransmitTxRing(struct rt_rtmp_adapter *pAd, /* */ /* */ /* In WMM-UAPSD, mlme frame should be set psm as power saving but probe request frame */ - /* Data-Null packets alse pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD */ + /* Data-Null packets also pass through MMRequest in RT2860, however, we hope control the psm bit to pass APSD */ if (pHeader_802_11->FC.Type != BTYPE_DATA) { if ((pHeader_802_11->FC.SubType == SUBTYPE_PROBE_REQ) || !(pAd->CommonCfg.bAPSDCapable diff --git a/drivers/staging/rt2860/common/cmm_data_usb.c b/drivers/staging/rt2860/common/cmm_data_usb.c index 7c56c2f51987..5637857ae9eb 100644 --- a/drivers/staging/rt2860/common/cmm_data_usb.c +++ b/drivers/staging/rt2860/common/cmm_data_usb.c @@ -702,7 +702,7 @@ Arguments: *pRxPending pending received packet flag Return Value: - the recieved packet + the received packet Note: ======================================================================== @@ -850,7 +850,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, /* Add Rx size to channel load counter, we should ignore error counts */ pAd->StaCfg.CLBusyBytes += (pRxWI->MPDUtotalByteCount + 14); - /* Drop ToDs promiscous frame, it is opened due to CCX 2 channel load statistics */ + /* Drop ToDs promiscuous frame, it is opened due to CCX 2 channel load statistics */ if (pHeader->FC.ToDs) { DBGPRINT_RAW(RT_DEBUG_ERROR, ("Err;FC.ToDs\n")); return NDIS_STATUS_FAILURE; @@ -860,7 +860,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); return NDIS_STATUS_FAILURE; } - /* Drop not U2M frames, cant's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/rt2860/common/cmm_mac_pci.c b/drivers/staging/rt2860/common/cmm_mac_pci.c index 21eed2507e1c..d06f0a6dc379 100644 --- a/drivers/staging/rt2860/common/cmm_mac_pci.c +++ b/drivers/staging/rt2860/common/cmm_mac_pci.c @@ -1446,7 +1446,7 @@ BOOLEAN RT28xxPciAsicRadioOff(struct rt_rtmp_adapter *pAd, pAd->CheckDmaBusyCount = 0; } */ -/*KH Debug:My original codes have the follwoing codes, but currecnt codes do not have it. */ +/*KH Debug:My original codes have the following codes, but currecnt codes do not have it. */ /* Disable for stability. If PCIE Link Control is modified for advance power save, re-covery this code segment. */ RTMP_IO_WRITE32(pAd, PBF_SYS_CTRL, 0x1280); /*OPSTATUS_SET_FLAG(pAd, fOP_STATUS_CLKSELECT_40MHZ); */ diff --git a/drivers/staging/rt2860/common/cmm_sanity.c b/drivers/staging/rt2860/common/cmm_sanity.c index 6b003c903444..3bfb4ad00c1a 100644 --- a/drivers/staging/rt2860/common/cmm_sanity.c +++ b/drivers/staging/rt2860/common/cmm_sanity.c @@ -67,7 +67,7 @@ BOOLEAN MlmeAddBAReqSanity(struct rt_rtmp_adapter *pAd, if ((MsgLen != sizeof(struct rt_mlme_addba_req))) { DBGPRINT(RT_DEBUG_TRACE, - ("MlmeAddBAReqSanity fail - message lenght not correct.\n")); + ("MlmeAddBAReqSanity fail - message length not correct.\n")); return FALSE; } @@ -104,7 +104,7 @@ BOOLEAN MlmeDelBAReqSanity(struct rt_rtmp_adapter *pAd, void * Msg, unsigned lon if ((MsgLen != sizeof(struct rt_mlme_delba_req))) { DBGPRINT(RT_DEBUG_ERROR, - ("MlmeDelBAReqSanity fail - message lenght not correct.\n")); + ("MlmeDelBAReqSanity fail - message length not correct.\n")); return FALSE; } diff --git a/drivers/staging/rt2860/common/cmm_sync.c b/drivers/staging/rt2860/common/cmm_sync.c index f84194da47bc..aefe1b774650 100644 --- a/drivers/staging/rt2860/common/cmm_sync.c +++ b/drivers/staging/rt2860/common/cmm_sync.c @@ -694,7 +694,7 @@ void ScanNextChannel(struct rt_rtmp_adapter *pAd) MiniportMMRequest(pAd, 0, pOutBuffer, FrameLen); MlmeFreeMemory(pAd, pOutBuffer); } - /* For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe reponse */ + /* For SCAN_CISCO_PASSIVE, do nothing and silently wait for beacon or other probe response */ pAd->Mlme.SyncMachine.CurrState = SCAN_LISTEN; } diff --git a/drivers/staging/rt2860/common/cmm_wpa.c b/drivers/staging/rt2860/common/cmm_wpa.c index 0040f45b629b..616ebec50c61 100644 --- a/drivers/staging/rt2860/common/cmm_wpa.c +++ b/drivers/staging/rt2860/common/cmm_wpa.c @@ -1222,7 +1222,7 @@ void PeerGroupMsg2Action(struct rt_rtmp_adapter *pAd, Note: All these constants are defined in wpa.h - For supplicant, there is only EAPOL Key message avaliable + For supplicant, there is only EAPOL Key message available ======================================================================== */ @@ -1267,7 +1267,7 @@ BOOLEAN WpaMsgTypeSubst(u8 EAPType, int * MsgType) int prefix_len - the length of the label u8 *data - a specific data with variable length int data_len - the length of a specific data - int len - the output lenght + int len - the output length Return Value: u8 *output - the calculated result diff --git a/drivers/staging/rt2860/common/mlme.c b/drivers/staging/rt2860/common/mlme.c index d9c3fd5c2166..e48eac0f3a29 100644 --- a/drivers/staging/rt2860/common/mlme.c +++ b/drivers/staging/rt2860/common/mlme.c @@ -632,7 +632,7 @@ void MlmeHalt(struct rt_rtmp_adapter *pAd) pChipOps->AsicHaltAction(pAd); } - RTMPusecDelay(5000); /* 5 msec to gurantee Ant Diversity timer canceled */ + RTMPusecDelay(5000); /* 5 msec to guarantee Ant Diversity timer canceled */ MlmeQueueDestroy(&pAd->Mlme.Queue); NdisFreeSpinLock(&pAd->Mlme.TaskLock); @@ -1107,14 +1107,14 @@ void MlmeSelectTxRateTable(struct rt_rtmp_adapter *pAd, *pInitTxRateIdx = RateSwitchTable11N1S[1]; DBGPRINT_RAW(RT_DEBUG_ERROR, - ("DRS: unkown mode,default use 11N 1S AP \n")); + ("DRS: unknown mode,default use 11N 1S AP \n")); } else { *ppTable = RateSwitchTable11N2S; *pTableSize = RateSwitchTable11N2S[0]; *pInitTxRateIdx = RateSwitchTable11N2S[1]; DBGPRINT_RAW(RT_DEBUG_ERROR, - ("DRS: unkown mode,default use 11N 2S AP \n")); + ("DRS: unknown mode,default use 11N 2S AP \n")); } } else { if (pAd->CommonCfg.TxStream == 1) { @@ -1123,7 +1123,7 @@ void MlmeSelectTxRateTable(struct rt_rtmp_adapter *pAd, *pInitTxRateIdx = RateSwitchTable11N1S[1]; DBGPRINT_RAW(RT_DEBUG_ERROR, - ("DRS: unkown mode,default use 11N 1S AP \n")); + ("DRS: unknown mode,default use 11N 1S AP \n")); } else { *ppTable = RateSwitchTable11N2SForABand; *pTableSize = @@ -1131,11 +1131,11 @@ void MlmeSelectTxRateTable(struct rt_rtmp_adapter *pAd, *pInitTxRateIdx = RateSwitchTable11N2SForABand[1]; DBGPRINT_RAW(RT_DEBUG_ERROR, - ("DRS: unkown mode,default use 11N 2S AP \n")); + ("DRS: unknown mode,default use 11N 2S AP \n")); } } DBGPRINT_RAW(RT_DEBUG_ERROR, - ("DRS: unkown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", + ("DRS: unknown mode (SupRateLen=%d, ExtRateLen=%d, MCSSet[0]=0x%x, MCSSet[1]=0x%x)\n", pAd->StaActive.SupRateLen, pAd->StaActive.ExtRateLen, pAd->StaActive.SupportedPhyInfo.MCSSet[0], @@ -1368,7 +1368,7 @@ void STAMlmePeriodicExec(struct rt_rtmp_adapter *pAd) if ((pAd->StaCfg.LastScanTime + 10 * OS_HZ) < pAd->Mlme.Now32) { DBGPRINT(RT_DEBUG_TRACE, - ("MMCHK - Roaming, No eligable entry, try new scan!\n")); + ("MMCHK - Roaming, No eligible entry, try new scan!\n")); pAd->StaCfg.ScanCnt = 2; pAd->StaCfg.LastScanTime = pAd->Mlme.Now32; @@ -2828,7 +2828,7 @@ void UpdateBasicRateBitmap(struct rt_rtmp_adapter *pAdapter) /* IRQL = PASSIVE_LEVEL */ /* IRQL = DISPATCH_LEVEL */ -/* bLinkUp is to identify the inital link speed. */ +/* bLinkUp is to identify the initial link speed. */ /* TRUE indicates the rate update at linkup, we should not try to set the rate at 54Mbps. */ void MlmeUpdateTxRates(struct rt_rtmp_adapter *pAd, IN BOOLEAN bLinkUp, u8 apidx) { diff --git a/drivers/staging/rt2860/common/rtmp_init.c b/drivers/staging/rt2860/common/rtmp_init.c index d359a14f5d4d..5fa193eac0d3 100644 --- a/drivers/staging/rt2860/common/rtmp_init.c +++ b/drivers/staging/rt2860/common/rtmp_init.c @@ -2037,7 +2037,7 @@ void NICUpdateFifoStaCounters(struct rt_rtmp_adapter *pAd) pEntry->FIFOCount = 0; pEntry->OneSecTxNoRetryOkCount++; - /* update NoDataIdleCount when sucessful send packet to STA. */ + /* update NoDataIdleCount when successful send packet to STA. */ pEntry->NoDataIdleCount = 0; pEntry->ContinueTxFailCnt = 0; } @@ -2516,7 +2516,7 @@ void UserCfgInit(struct rt_rtmp_adapter *pAd) /*pAd->TurnAggrBulkInCount = 0; */ pAd->bUsbTxBulkAggre = 0; - /* init as unsed value to ensure driver will set to MCU once. */ + /* init as unused value to ensure driver will set to MCU once. */ pAd->LedIndicatorStrength = 0xFF; pAd->CommonCfg.MaxPktOneTxBulk = 2; @@ -3076,11 +3076,11 @@ void RTMPSetLED(struct rt_rtmp_adapter *pAd, u8 Status) ======================================================================== Routine Description: - Set LED Signal Stregth + Set LED Signal Strength Arguments: pAd Pointer to our adapter - Dbm Signal Stregth + Dbm Signal Strength Return Value: None @@ -3090,7 +3090,7 @@ void RTMPSetLED(struct rt_rtmp_adapter *pAd, u8 Status) Note: Can be run on any IRQL level. - According to Microsoft Zero Config Wireless Signal Stregth definition as belows. + According to Microsoft Zero Config Wireless Signal Strength definition as belows. <= -90 No Signal <= -81 Very Low <= -71 Low @@ -3118,7 +3118,7 @@ void RTMPSetSignalLED(struct rt_rtmp_adapter *pAd, IN NDIS_802_11_RSSI Dbm) nLed = 31; /* */ - /* Update Signal Stregth to firmware if changed. */ + /* Update Signal Strength to firmware if changed. */ /* */ if (pAd->LedIndicatorStrength != nLed) { AsicSendCommandToMcu(pAd, 0x51, 0xff, nLed, @@ -3166,7 +3166,7 @@ void RTMPEnableRxTx(struct rt_rtmp_adapter *pAd) if (pAd->CommonCfg.PSPXlink) rx_filter_flag = PSPXLINK; else - rx_filter_flag = STANORMAL; /* Staion not drop control frame will fail WiFi Certification. */ + rx_filter_flag = STANORMAL; /* Station not drop control frame will fail WiFi Certification. */ RTMP_IO_WRITE32(pAd, RX_FILTR_CFG, rx_filter_flag); } diff --git a/drivers/staging/rt2860/common/spectrum.c b/drivers/staging/rt2860/common/spectrum.c index c0d2f428069c..ceb622df12d7 100644 --- a/drivers/staging/rt2860/common/spectrum.c +++ b/drivers/staging/rt2860/common/spectrum.c @@ -1058,8 +1058,8 @@ static void InsertMeasureReqIE(struct rt_rtmp_adapter *pAd, 3. Measure Token. 4. Measure Request Mode. 5. Measure Request Type. - 6. Length of Report Infomation - 7. Pointer of Report Infomation Buffer. + 6. Length of Report Information + 7. Pointer of Report Information Buffer. Return : None. ========================================================================== @@ -1400,7 +1400,7 @@ static void StartDFSProcedure(struct rt_rtmp_adapter *pAd, Parametrs: 1. MLME message containing the received frame 2. message length. - 3. Channel switch announcement infomation buffer. + 3. Channel switch announcement information buffer. Return : None. ========================================================================== @@ -1465,7 +1465,7 @@ static BOOLEAN PeerChSwAnnSanity(struct rt_rtmp_adapter *pAd, Parametrs: 1. MLME message containing the received frame 2. message length. - 3. Measurement request infomation buffer. + 3. Measurement request information buffer. Return : None. ========================================================================== @@ -1538,8 +1538,8 @@ static BOOLEAN PeerMeasureReqSanity(struct rt_rtmp_adapter *pAd, Parametrs: 1. MLME message containing the received frame 2. message length. - 3. Measurement report infomation buffer. - 4. basic report infomation buffer. + 3. Measurement report information buffer. + 4. basic report information buffer. Return : None. ========================================================================== diff --git a/drivers/staging/rt2860/mlme.h b/drivers/staging/rt2860/mlme.h index cd1ee3d7a91d..a285851692ee 100644 --- a/drivers/staging/rt2860/mlme.h +++ b/drivers/staging/rt2860/mlme.h @@ -374,7 +374,7 @@ struct PACKED rt_sec_cha_offset_ie { struct rt_ht_phy_info { BOOLEAN bHtEnable; /* If we should use ht rate. */ BOOLEAN bPreNHt; /* If we should use ht rate. */ - /*Substract from HT Capability IE */ + /*Subtract from HT Capability IE */ u8 MCSSet[16]; }; @@ -392,7 +392,7 @@ struct rt_ht_capability { u16 AmsduSize:1; /* Max receiving A-MSDU size */ u16 rsv:5; - /*Substract from Addiont HT INFO IE */ + /*Subtract from Addiont HT INFO IE */ u8 MaxRAmpduFactor:2; u8 MpduDensity:3; u8 ExtChanOffset:2; /* Please note the difference with following u8 NewExtChannelOffset; from 802.11n */ @@ -410,7 +410,7 @@ struct rt_ht_capability { u8 BSSCoexist2040; }; -/* field in Addtional HT Information IE . */ +/* field in Additional HT Information IE . */ struct PACKED rt_add_htinfo { u8 ExtChanOffset:2; u8 RecomWidth:1; @@ -857,7 +857,7 @@ struct rt_state_machine { }; /* MLME AUX data structure that holds temporarliy settings during a connection attempt. */ -/* Once this attemp succeeds, all settings will be copy to pAd->StaActive. */ +/* Once this attempt succeeds, all settings will be copy to pAd->StaActive. */ /* A connection attempt (user set OID, roaming, CCX fast roaming,..) consists of */ /* several steps (JOIN, AUTH, ASSOC or REASSOC) and may fail at any step. We purposely */ /* separate this under-trial settings away from pAd->StaActive so that once */ diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c index e5b042712430..1583347fcd52 100644 --- a/drivers/staging/rt2860/rt_linux.c +++ b/drivers/staging/rt2860/rt_linux.c @@ -283,7 +283,7 @@ BOOLEAN OS_Need_Clone_Packet(void) Arguments: pAd Pointer to our adapter pInsAMSDUHdr EWC A-MSDU format has extra 14-bytes header. if TRUE, insert this 14-byte hdr in front of MSDU. - *pSrcTotalLen return total packet length. This lenght is calculated with 802.3 format packet. + *pSrcTotalLen return total packet length. This length is calculated with 802.3 format packet. Return Value: NDIS_STATUS_SUCCESS diff --git a/drivers/staging/rt2860/rt_pci_rbus.c b/drivers/staging/rt2860/rt_pci_rbus.c index e5fb67cd9a68..f80ab4e6a0ac 100644 --- a/drivers/staging/rt2860/rt_pci_rbus.c +++ b/drivers/staging/rt2860/rt_pci_rbus.c @@ -619,7 +619,7 @@ IRQ_HANDLE_TYPE rt2860_interrupt(int irq, void *dev_instance) Or kernel will panic after ifconfig ra0 down sometimes */ /* */ - /* Inital the Interrupt source. */ + /* Initial the Interrupt source. */ /* */ IntSource.word = 0x00000000L; /* McuIntSource.word = 0x00000000L; */ diff --git a/drivers/staging/rt2860/rtmp.h b/drivers/staging/rt2860/rtmp.h index d16b06a6e2ac..3c31340c946a 100644 --- a/drivers/staging/rt2860/rtmp.h +++ b/drivers/staging/rt2860/rtmp.h @@ -756,7 +756,7 @@ struct rt_tkip_key_info { /* */ struct rt_private { u32 SystemResetCnt; /* System reset counter */ - u32 TxRingFullCnt; /* Tx ring full occurrance number */ + u32 TxRingFullCnt; /* Tx ring full occurrence number */ u32 PhyRxErrCnt; /* PHY Rx error count, for debug purpose, might move to global counter */ /* Variables for WEP encryption / decryption in rtmp_wep.c */ u32 FCSCRC32; @@ -925,7 +925,7 @@ struct rt_mlme { **************************************************************************/ struct reordering_mpdu { struct reordering_mpdu *next; - void *pPacket; /* coverted to 802.3 frame */ + void *pPacket; /* converted to 802.3 frame */ int Sequence; /* sequence number of MPDU */ BOOLEAN bAMSDU; }; diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c index 5717e12a9544..49b1013e7a03 100644 --- a/drivers/staging/rt2860/sta_ioctl.c +++ b/drivers/staging/rt2860/sta_ioctl.c @@ -2460,7 +2460,7 @@ int rt28xx_sta_ioctl(IN struct net_device *net_dev, } } - { /* determine this ioctl command is comming from which interface. */ + { /* determine this ioctl command is coming from which interface. */ pObj->ioctl_if_type = INT_MAIN; pObj->ioctl_if = MAIN_MBSSID; } diff --git a/drivers/staging/rt2870/common/rtusb_bulk.c b/drivers/staging/rt2870/common/rtusb_bulk.c index d2746f8732e6..679b802d2169 100644 --- a/drivers/staging/rt2870/common/rtusb_bulk.c +++ b/drivers/staging/rt2870/common/rtusb_bulk.c @@ -298,7 +298,7 @@ void RTUSBBulkOutDataPacket(struct rt_rtmp_adapter *pAd, /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) */ ) { /* For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. */ - /* For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. */ + /* For performance in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. */ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; break; @@ -311,7 +311,7 @@ void RTUSBBulkOutDataPacket(struct rt_rtmp_adapter *pAd, TmpBulkEndPos; break; } else if (((pAd->BulkOutMaxPacketSize < 512) && ((ThisBulkSize & 0xfffff800) != 0)) /*|| ( (ThisBulkSize != 0) && (pTxWI->AMPDU == 0)) */) { /* For USB 1.1 or peer which didn't support AMPDU, limit the BulkOut size. */ - /* For performence in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. */ + /* For performance in b/g mode, now just check for USB 1.1 and didn't care about the APMDU or not! 2008/06/04. */ pHTTXContext->ENextBulkOutPosition = TmpBulkEndPos; break; @@ -1016,7 +1016,7 @@ void RTUSBKickBulkOut(struct rt_rtmp_adapter *pAd) RTUSBBulkOutNullFrame(pAd); } } - /* 8. No data avaliable */ + /* 8. No data available */ else ; } diff --git a/drivers/staging/rt2870/common/rtusb_data.c b/drivers/staging/rt2870/common/rtusb_data.c index 69368862217c..5b72bcdaa78f 100644 --- a/drivers/staging/rt2870/common/rtusb_data.c +++ b/drivers/staging/rt2870/common/rtusb_data.c @@ -71,7 +71,7 @@ void REPORT_AMSDU_FRAMES_TO_LLC(struct rt_rtmp_adapter *pAd, Routine Description: This subroutine will scan through releative ring descriptor to find - out avaliable free ring descriptor and compare with request size. + out available free ring descriptor and compare with request size. Arguments: pAd Pointer to our adapter diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index dc608c70deb1..16aa6a8952fd 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -1099,7 +1099,7 @@ struct ieee80211_device { * not set. As some cards may have different HW queues that * one might want to use for data and management frames * the option to have two callbacks might be useful. - * This fucntion can't sleep. + * This function can't sleep. */ int (*softmac_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev); @@ -1138,9 +1138,9 @@ struct ieee80211_device { * it is called in a work_queue when swithcing to ad-hoc mode * or in behalf of iwlist scan when the card is associated * and root user ask for a scan. - * the fucntion stop_scan should stop both the syncro and + * the function stop_scan should stop both the syncro and * background scanning and can sleep. - * The fucntion start_scan should initiate the background + * The function start_scan should initiate the background * scanning and can't sleep. */ void (*scan_syncro)(struct net_device *dev); diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index 771e0196842e..736a1404f287 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -1954,7 +1954,7 @@ associate_complete: -/* following are for a simplier TX queue management. +/* following are for a simpler TX queue management. * Instead of using netif_[stop/wake]_queue the driver * will uses these two function (plus a reset one), that * will internally uses the kernel netif_* and takes diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 70ab0084e5f5..2155a771c339 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -1591,7 +1591,7 @@ void rtl8180_rx(struct net_device *dev) priv->RSSI = RSSI; /* SQ translation formula is provided by SD3 DZ. 2006.06.27 */ if (quality >= 127) - quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk aroud now; */ + quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk around now; */ else if (quality < 27) quality = 100; else @@ -3883,7 +3883,7 @@ void rtl8180_tx_isr(struct net_device *dev, int pri, short error) * If the packet previous of the nic pointer has been * processed this doesn't matter: it will be checked * here at the next round. Anyway if no more packet are - * TXed no memory leak occour at all. + * TXed no memory leak occur at all. */ switch (pri) { diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c index fc4907839c58..261085d4b74a 100644 --- a/drivers/staging/rtl8187se/r8180_dm.c +++ b/drivers/staging/rtl8187se/r8180_dm.c @@ -123,7 +123,7 @@ DoTxHighPower( // // Description: // Callback function of UpdateTxPowerWorkItem. -// Because of some event happend, e.g. CCX TPC, High Power Mechanism, +// Because of some event happened, e.g. CCX TPC, High Power Mechanism, // We update Tx power of current channel again. // void rtl8180_tx_pw_wq (struct work_struct *work) @@ -984,7 +984,7 @@ StaRateAdaptive87SE( { priv->TryupingCount = 0; // - // When transfering from CCK to OFDM, DIG is an important issue. + // When transferring from CCK to OFDM, DIG is an important issue. // if(priv->CurrentOperaRate == 22) bUpdateInitialGain = true; diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c index 2a2afd51cf42..3f09f76080af 100644 --- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c +++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c @@ -378,7 +378,7 @@ static u32 read_rtl8225(struct net_device *dev, u8 adr) mask = (low2high) ? 0x01 : (((u32)0x01) << (12-1)); /* - * We must set data pin to HW controled, otherwise RF can't driver it + * We must set data pin to HW controlled, otherwise RF can't driver it * and value RF register won't be able to read back properly. */ write_nic_word(dev, RFPinsEnable, (oval2 & (~0x01))); diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c index 3bdf9b31cc4e..4b0b830f9ab6 100644 --- a/drivers/staging/rtl8187se/r8185b_init.c +++ b/drivers/staging/rtl8187se/r8185b_init.c @@ -1273,7 +1273,7 @@ MgntDisconnectIBSS( /* Stop Beacon. - Vista add a Adhoc profile, HW radio off untill OID_DOT11_RESET_REQUEST + Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck. Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send. diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211.h b/drivers/staging/rtl8192e/ieee80211/ieee80211.h index 3ca388152616..dbe21ab0dbf7 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211.h @@ -1967,7 +1967,7 @@ struct ieee80211_device { u16 prev_seq_ctl; /* used to drop duplicate frames */ /* map of allowed channels. 0 is dummy */ - // FIXME: remeber to default to a basic channel plan depending of the PHY type + // FIXME: remember to default to a basic channel plan depending of the PHY type #ifdef ENABLE_DOT11D void* pDot11dInfo; bool bGlobalDomain; @@ -2121,7 +2121,7 @@ struct ieee80211_device { * not set. As some cards may have different HW queues that * one might want to use for data and management frames * the option to have two callbacks might be useful. - * This fucntion can't sleep. + * This function can't sleep. */ int (*softmac_hard_start_xmit)(struct sk_buff *skb, struct ieee80211_device *ieee80211); @@ -2160,9 +2160,9 @@ struct ieee80211_device { * it is called in a work_queue when swithcing to ad-hoc mode * or in behalf of iwlist scan when the card is associated * and root user ask for a scan. - * the fucntion stop_scan should stop both the syncro and + * the function stop_scan should stop both the syncro and * background scanning and can sleep. - * The fucntion start_scan should initiate the background + * The function start_scan should initiate the background * scanning and can't sleep. */ void (*scan_syncro)(struct ieee80211_device *ieee80211); diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c index add015ebba1c..ed5a38023094 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c @@ -1426,7 +1426,7 @@ int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; /* -* Make ther structure we read from the beacon packet has +* Make the structure we read from the beacon packet to have * the right values */ static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c index f6922d40a88a..7d4cba3a7c12 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c @@ -2023,7 +2023,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, return 1; } else - { //filling the PeerHTCap. //maybe not neccesary as we can get its info from current_network. + { //filling the PeerHTCap. //maybe not necessary as we can get its info from current_network. memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen); memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen); } @@ -2163,7 +2163,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, return 0; } -/* following are for a simplier TX queue management. +/* following are for a simpler TX queue management. * Instead of using netif_[stop/wake]_queue the driver * will uses these two function (plus a reset one), that * will internally uses the kernel netif_* and takes diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h index f968817d073c..56a120cf6291 100644 --- a/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h +++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_HT.h @@ -64,7 +64,7 @@ typedef enum _HT_CHANNEL_WIDTH{ }HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; // -// Represent Extention Channel Offset in HT Capabilities +// Represent Extension Channel Offset in HT Capabilities // This is available only in 40Mhz mode. // typedef enum _HT_EXTCHNL_OFFSET{ diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c index a2a4fe9dd9da..f7a9da3ec829 100644 --- a/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_HTProc.c @@ -459,7 +459,7 @@ u8 HTIOTActIsForcedCTS2Self(struct ieee80211_device *ieee, struct ieee80211_netw /** * Function: HTIOTActIsDisableMCS15 * -* Overview: Check whether driver should declare capability of receving MCS15 +* Overview: Check whether driver should declare capability of receiving MCS15 * * Input: * PADAPTER Adapter, @@ -496,7 +496,7 @@ bool HTIOTActIsDisableMCS15(struct ieee80211_device* ieee) /** * Function: HTIOTActIsDisableMCSTwoSpatialStream * -* Overview: Check whether driver should declare capability of receving All 2 ss packets +* Overview: Check whether driver should declare capability of receiving All 2 ss packets * * Input: * PADAPTER Adapter, @@ -1681,7 +1681,7 @@ void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidt //if in half N mode, set to 20M bandwidth please 09.08.2008 WB. if (Bandwidth==HT_CHANNEL_WIDTH_20_40 && (!ieee->GetHalfNmodeSupportByAPsHandler(ieee))) { - // Handle Illegal extention channel offset!! + // Handle Illegal extension channel offset!! if(ieee->current_network.channel<2 && Offset==HT_EXTCHNL_OFFSET_LOWER) Offset = HT_EXTCHNL_OFFSET_NO_EXT; if(Offset==HT_EXTCHNL_OFFSET_UPPER || Offset==HT_EXTCHNL_OFFSET_LOWER) { @@ -1698,7 +1698,7 @@ void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidt pHTInfo->bSwBwInProgress = true; - // TODO: 2007.7.13 by Emily Wait 2000ms in order to garantee that switching + // TODO: 2007.7.13 by Emily Wait 2000ms in order to guarantee that switching // bandwidth is executed after scan is finished. It is a temporal solution // because software should ganrantee the last operation of switching bandwidth // is executed properlly. diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h b/drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h index baaac2149de1..e7e26fd96395 100644 --- a/drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h +++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_TS.h @@ -44,7 +44,7 @@ typedef struct _RX_TS_RECORD { u16 RxTimeoutIndicateSeq; struct list_head RxPendingPktList; struct timer_list RxPktPendingTimer; - BA_RECORD RxAdmittedBARecord; // For BA Recepient + BA_RECORD RxAdmittedBARecord; // For BA Recipient u16 RxLastSeqNum; u8 RxLastFragNum; u8 num; diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c index 29eecf0ab769..ad6872dcf1c2 100644 --- a/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_TSProc.c @@ -135,7 +135,7 @@ void ResetRxTsEntry(PRX_TS_RECORD pTS) ResetTsCommonInfo(&pTS->TsCommonInfo); pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!! pTS->RxTimeoutIndicateSeq = 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!! - ResetBaEntry(&pTS->RxAdmittedBARecord); // For BA Recepient + ResetBaEntry(&pTS->RxAdmittedBARecord); // For BA Recipient } void TSInitialize(struct ieee80211_device *ieee) diff --git a/drivers/staging/rtl8192e/r819xE_phy.c b/drivers/staging/rtl8192e/r819xE_phy.c index dfa4e112ef46..9e7828ef1cbe 100644 --- a/drivers/staging/rtl8192e/r819xE_phy.c +++ b/drivers/staging/rtl8192e/r819xE_phy.c @@ -2032,13 +2032,13 @@ void rtl8192_SetBWModeWorkItem(struct r8192_priv *priv) { case HT_CHANNEL_WIDTH_20: regBwOpMode |= BW_OPMODE_20MHZ; - // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + // 2007/02/07 Mark by Emily because we have not verify whether this register works write_nic_byte(priv, BW_OPMODE, regBwOpMode); break; case HT_CHANNEL_WIDTH_20_40: regBwOpMode &= ~BW_OPMODE_20MHZ; - // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + // 2007/02/07 Mark by Emily because we have not verify whether this register works write_nic_byte(priv, BW_OPMODE, regBwOpMode); break; @@ -2116,7 +2116,7 @@ void rtl8192_SetBWModeWorkItem(struct r8192_priv *priv) } /****************************************************************************** - *function: This function schedules bandwith switch work. + *function: This function schedules bandwidth switch work. * input: struct net_device *dev * HT_CHANNEL_WIDTH Bandwidth //20M or 40M * HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h index c0b844d75c0d..e716f7b1144f 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h @@ -1965,7 +1965,7 @@ struct ieee80211_device { u16 prev_seq_ctl; /* used to drop duplicate frames */ /* map of allowed channels. 0 is dummy */ - // FIXME: remeber to default to a basic channel plan depending of the PHY type + // FIXME: remember to default to a basic channel plan depending of the PHY type void* pDot11dInfo; bool bGlobalDomain; int rate; /* current rate */ @@ -2119,7 +2119,7 @@ struct ieee80211_device { * not set. As some cards may have different HW queues that * one might want to use for data and management frames * the option to have two callbacks might be useful. - * This fucntion can't sleep. + * This function can't sleep. */ int (*softmac_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev); @@ -2158,9 +2158,9 @@ struct ieee80211_device { * it is called in a work_queue when swithcing to ad-hoc mode * or in behalf of iwlist scan when the card is associated * and root user ask for a scan. - * the fucntion stop_scan should stop both the syncro and + * the function stop_scan should stop both the syncro and * background scanning and can sleep. - * The fucntion start_scan should initiate the background + * The function start_scan should initiate the background * scanning and can't sleep. */ void (*scan_syncro)(struct net_device *dev); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index 498b520efcf4..a414303aef54 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -1399,7 +1399,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; /* -* Make ther structure we read from the beacon packet has +* Make the structure we read from the beacon packet to have * the right values */ static int ieee80211_verify_qos_info(struct ieee80211_qos_information_element diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index 4992d630f984..4ec0a6520ddc 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -1973,7 +1973,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, return 1; } else - { //filling the PeerHTCap. //maybe not neccesary as we can get its info from current_network. + { //filling the PeerHTCap. //maybe not necessary as we can get its info from current_network. memcpy(ieee->pHTInfo->PeerHTCapBuf, network->bssht.bdHTCapBuf, network->bssht.bdHTCapLen); memcpy(ieee->pHTInfo->PeerHTInfoBuf, network->bssht.bdHTInfoBuf, network->bssht.bdHTInfoLen); } @@ -2113,7 +2113,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, return 0; } -/* following are for a simplier TX queue management. +/* following are for a simpler TX queue management. * Instead of using netif_[stop/wake]_queue the driver * will uses these two function (plus a reset one), that * will internally uses the kernel netif_* and takes diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h index cde603f67f43..0b1a1fc09391 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h @@ -64,7 +64,7 @@ typedef enum _HT_CHANNEL_WIDTH{ }HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; // -// Represent Extention Channel Offset in HT Capabilities +// Represent Extension Channel Offset in HT Capabilities // This is available only in 40Mhz mode. // typedef enum _HT_EXTCHNL_OFFSET{ diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c index 50f4f5943e75..e88a839b2a91 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c @@ -423,7 +423,7 @@ u8 HTIOTActIsDisableMCS14(struct ieee80211_device* ieee, u8* PeerMacAddr) /** * Function: HTIOTActIsDisableMCS15 * -* Overview: Check whether driver should declare capability of receving MCS15 +* Overview: Check whether driver should declare capability of receiving MCS15 * * Input: * PADAPTER Adapter, @@ -460,7 +460,7 @@ bool HTIOTActIsDisableMCS15(struct ieee80211_device* ieee) /** * Function: HTIOTActIsDisableMCSTwoSpatialStream * -* Overview: Check whether driver should declare capability of receving All 2 ss packets +* Overview: Check whether driver should declare capability of receiving All 2 ss packets * * Input: * PADAPTER Adapter, @@ -1409,7 +1409,7 @@ void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidt //if in half N mode, set to 20M bandwidth please 09.08.2008 WB. if(Bandwidth==HT_CHANNEL_WIDTH_20_40 && (!ieee->GetHalfNmodeSupportByAPsHandler(ieee->dev))) { - // Handle Illegal extention channel offset!! + // Handle Illegal extension channel offset!! if(ieee->current_network.channel<2 && Offset==HT_EXTCHNL_OFFSET_LOWER) Offset = HT_EXTCHNL_OFFSET_NO_EXT; if(Offset==HT_EXTCHNL_OFFSET_UPPER || Offset==HT_EXTCHNL_OFFSET_LOWER) { @@ -1426,7 +1426,7 @@ void HTSetConnectBwMode(struct ieee80211_device* ieee, HT_CHANNEL_WIDTH Bandwidt pHTInfo->bSwBwInProgress = true; - // TODO: 2007.7.13 by Emily Wait 2000ms in order to garantee that switching + // TODO: 2007.7.13 by Emily Wait 2000ms in order to guarantee that switching // bandwidth is executed after scan is finished. It is a temporal solution // because software should ganrantee the last operation of switching bandwidth // is executed properlly. diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h index baaac2149de1..e7e26fd96395 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TS.h @@ -44,7 +44,7 @@ typedef struct _RX_TS_RECORD { u16 RxTimeoutIndicateSeq; struct list_head RxPendingPktList; struct timer_list RxPktPendingTimer; - BA_RECORD RxAdmittedBARecord; // For BA Recepient + BA_RECORD RxAdmittedBARecord; // For BA Recipient u16 RxLastSeqNum; u8 RxLastFragNum; u8 num; diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c index c3fcaae0750d..957ce4ef48b5 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c @@ -135,7 +135,7 @@ void ResetRxTsEntry(PRX_TS_RECORD pTS) ResetTsCommonInfo(&pTS->TsCommonInfo); pTS->RxIndicateSeq = 0xffff; // This indicate the RxIndicateSeq is not used now!! pTS->RxTimeoutIndicateSeq = 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!! - ResetBaEntry(&pTS->RxAdmittedBARecord); // For BA Recepient + ResetBaEntry(&pTS->RxAdmittedBARecord); // For BA Recipient } void TSInitialize(struct ieee80211_device *ieee) diff --git a/drivers/staging/rtl8192u/ieee80211/scatterwalk.c b/drivers/staging/rtl8192u/ieee80211/scatterwalk.c index 49f401fbce88..3543a6145046 100644 --- a/drivers/staging/rtl8192u/ieee80211/scatterwalk.c +++ b/drivers/staging/rtl8192u/ieee80211/scatterwalk.c @@ -71,7 +71,7 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out, unsigned int more) { /* walk->data may be pointing the first byte of the next page; - however, we know we transfered at least one byte. So, + however, we know we transferred at least one byte. So, walk->data - 1 will be a virtual address in the mapped page. */ if (out) diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index da612e6d994e..e81b8ab6aa9d 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -460,7 +460,7 @@ u32 read_nic_dword(struct net_device *dev, int indx) /* u8 read_phy_cck(struct net_device *dev, u8 adr); */ /* u8 read_phy_ofdm(struct net_device *dev, u8 adr); */ /* this might still called in what was the PHY rtl8185/rtl8192 common code - * plans are to possibilty turn it again in one common code... + * plans are to possibility turn it again in one common code... */ inline void force_pci_posting(struct net_device *dev) { @@ -1378,7 +1378,7 @@ struct sk_buff *DrvAggr_Aggregation(struct net_device *dev, struct ieee80211_drv //tx_agg_desc->LINIP = 0; //tx_agg_desc->CmdInit = 1; tx_agg_desc->Offset = sizeof(tx_fwinfo_819x_usb) + 8; - /* already raw data, need not to substract header length */ + /* already raw data, need not to subtract header length */ tx_agg_desc->PktSize = skb->len & 0xffff; /*DWORD 1*/ @@ -2888,7 +2888,7 @@ static void rtl8192_get_eeprom_size(struct net_device* dev) RT_TRACE(COMP_EPROM, "<===========%s(), epromtype:%d\n", __FUNCTION__, priv->epromtype); } -//used to swap endian. as ntohl & htonl are not neccessary to swap endian, so use this instead. +//used to swap endian. as ntohl & htonl are not necessary to swap endian, so use this instead. static inline u16 endian_swap(u16* data) { u16 tmp = *data; diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h index 01f58b902028..2ac421626e7c 100644 --- a/drivers/staging/rtl8192u/r819xU_HTType.h +++ b/drivers/staging/rtl8192u/r819xU_HTType.h @@ -65,7 +65,7 @@ typedef enum _HT_CHANNEL_WIDTH{ }HT_CHANNEL_WIDTH, *PHT_CHANNEL_WIDTH; // -// Represent Extention Channel Offset in HT Capabilities +// Represent Extension Channel Offset in HT Capabilities // This is available only in 40Mhz mode. // typedef enum _HT_EXTCHNL_OFFSET{ diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c index 41684e8fcf4c..c4586b0817d1 100644 --- a/drivers/staging/rtl8192u/r819xU_phy.c +++ b/drivers/staging/rtl8192u/r819xU_phy.c @@ -1531,13 +1531,13 @@ void rtl8192_SetBWModeWorkItem(struct net_device *dev) { case HT_CHANNEL_WIDTH_20: regBwOpMode |= BW_OPMODE_20MHZ; - // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + // 2007/02/07 Mark by Emily because we have not verify whether this register works write_nic_byte(dev, BW_OPMODE, regBwOpMode); break; case HT_CHANNEL_WIDTH_20_40: regBwOpMode &= ~BW_OPMODE_20MHZ; - // 2007/02/07 Mark by Emily becasue we have not verify whether this register works + // 2007/02/07 Mark by Emily because we have not verify whether this register works write_nic_byte(dev, BW_OPMODE, regBwOpMode); break; @@ -1647,7 +1647,7 @@ void rtl8192_SetBWModeWorkItem(struct net_device *dev) } /****************************************************************************** - *function: This function schedules bandwith switch work. + *function: This function schedules bandwidth switch work. * input: struct net_device *dev * HT_CHANNEL_WIDTH Bandwidth //20M or 40M * HT_EXTCHNL_OFFSET Offset //Upper, Lower, or Don't care diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h index 3a945b5f0e01..2dc78476b7d3 100644 --- a/drivers/staging/rtl8712/rtl871x_cmd.h +++ b/drivers/staging/rtl8712/rtl871x_cmd.h @@ -656,7 +656,7 @@ struct PT_param { /* * Result: * 0x00: success - * 0x01: sucess, and check Response. + * 0x01: success, and check Response. * 0x02: cmd ignored due to duplicated sequcne number * 0x03: cmd dropped due to invalid cmd code * 0x04: reserved. diff --git a/drivers/staging/rtl8712/rtl871x_led.h b/drivers/staging/rtl8712/rtl871x_led.h index 994ef82141ab..8085e5eb82b1 100644 --- a/drivers/staging/rtl8712/rtl871x_led.h +++ b/drivers/staging/rtl8712/rtl871x_led.h @@ -78,14 +78,14 @@ struct LED_871x { }; struct led_priv { - /* add for led controll */ + /* add for led control */ struct LED_871x SwLed0; struct LED_871x SwLed1; enum LED_STRATEGY_871x LedStrategy; u8 bRegUseLed; void (*LedControlHandler)(struct _adapter *padapter, enum LED_CTL_MODE LedAction); - /* add for led controll */ + /* add for led control */ }; /*=========================================================================== diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index 98ba7602e250..866554d48d86 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -1663,7 +1663,7 @@ void r8712_update_registrypriv_dev_network(struct _adapter *adapter) (struct ndis_wlan_bssid_ex *)pdev_network); } -/*the fucntion is at passive_level*/ +/*the function is at passive_level*/ void r8712_joinbss_reset(struct _adapter *padapter) { int i; @@ -1726,7 +1726,7 @@ unsigned int r8712_restructure_ht_ie(struct _adapter *padapter, u8 *in_ie, return phtpriv->ht_option; } -/* the fucntion is > passive_level (in critical_section) */ +/* the function is > passive_level (in critical_section) */ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len) { u8 *p, max_ampdu_sz; @@ -1803,7 +1803,7 @@ void r8712_issue_addbareq_cmd(struct _adapter *padapter, int priority) } } -/*the fucntion is >= passive_level*/ +/*the function is >= passive_level*/ unsigned int r8712_add_ht_addt_info(struct _adapter *padapter, u8 *in_ie, u8 *out_ie, uint in_len, uint *pout_len) diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h index 2b35b740ab89..2794804d0822 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.h +++ b/drivers/staging/rtl8712/rtl871x_mlme.h @@ -29,7 +29,7 @@ * single-tone*/ #define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in cont, tx * background due to out of skb*/ -#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continous tx*/ +#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continuous tx*/ #define WIFI_MP_CTX_CCK_CS 0x00200000 /* in cont, tx with carrier * suppression*/ #define WIFI_MP_LPBK_STATE 0x00400000 diff --git a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h index e386fb0aac3e..23532a793859 100644 --- a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h +++ b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h @@ -38,7 +38,7 @@ * 2. 0x800/0x900/0xA00/0xC00/0xD00/0xE00 * 3. RF register 0x00-2E * 4. Bit Mask for BB/RF register - * 5. Other defintion for BB/RF R/W + * 5. Other definition for BB/RF R/W * * 1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF * 1. Page1(0x100) diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c index 0e9483bbabe1..46287c17a417 100644 --- a/drivers/staging/rtl8712/usb_halinit.c +++ b/drivers/staging/rtl8712/usb_halinit.c @@ -112,7 +112,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter) /* Initialization for power on sequence, */ r8712_write8(padapter, SPS0_CTRL + 1, 0x53); r8712_write8(padapter, SPS0_CTRL, 0x57); - /* Enable AFE Macro Block's Bandgap adn Enable AFE Macro + /* Enable AFE Macro Block's Bandgap and Enable AFE Macro * Block's Mbias */ val8 = r8712_read8(padapter, AFE_MISC); diff --git a/drivers/staging/rts_pstor/rtsx_chip.h b/drivers/staging/rts_pstor/rtsx_chip.h index 713c5eaadacd..9f7cd82a1541 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.h +++ b/drivers/staging/rts_pstor/rtsx_chip.h @@ -180,8 +180,8 @@ #define CUR_ERR 0x70 /* current error */ #define DEF_ERR 0x71 /* specific command error */ -/*---- sense key Infomation ----*/ -#define SNSKEYINFO_LEN 3 /* length of sense key infomation */ +/*---- sense key Information ----*/ +#define SNSKEYINFO_LEN 3 /* length of sense key information */ #define SKSV 0x80 #define CDB_ILLEGAL 0x40 @@ -235,13 +235,13 @@ struct sense_data_t { unsigned char seg_no; /* segment No. */ unsigned char sense_key; /* byte5 : ILI */ /* bit3-0 : sense key */ - unsigned char info[4]; /* infomation */ + unsigned char info[4]; /* information */ unsigned char ad_sense_len; /* additional sense data length */ - unsigned char cmd_info[4]; /* command specific infomation */ + unsigned char cmd_info[4]; /* command specific information */ unsigned char asc; /* ASC */ unsigned char ascq; /* ASCQ */ unsigned char rfu; /* FRU */ - unsigned char sns_key_info[3]; /* sense key specific infomation */ + unsigned char sns_key_info[3]; /* sense key specific information */ }; /* PCI Operation Register Address */ diff --git a/drivers/staging/rts_pstor/rtsx_scsi.h b/drivers/staging/rts_pstor/rtsx_scsi.h index fac122c1eabd..64b84992fdb3 100644 --- a/drivers/staging/rts_pstor/rtsx_scsi.h +++ b/drivers/staging/rts_pstor/rtsx_scsi.h @@ -85,7 +85,7 @@ #define CHIP_NORMALMODE 0x00 #define CHIP_DEBUGMODE 0x01 -/* SD Pass Through Command Extention */ +/* SD Pass Through Command Extension */ #define SD_PASS_THRU_MODE 0xD0 #define SD_EXECUTE_NO_DATA 0xD1 #define SD_EXECUTE_READ 0xD2 diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c index 21bfa5755bec..8d066bd428c4 100644 --- a/drivers/staging/rts_pstor/sd.c +++ b/drivers/staging/rts_pstor/sd.c @@ -1719,7 +1719,7 @@ static u8 sd_search_final_phase(struct rtsx_chip *chip, u32 phase_map, u8 tune_d } Search_Finish: - RTSX_DEBUGP("Final choosen phase: %d\n", final_phase); + RTSX_DEBUGP("Final chosen phase: %d\n", final_phase); return final_phase; } diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 71a5fbc041e4..c2f2664b61ae 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -586,7 +586,7 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait) dev_dbg(&sep->pdev->dev, "poll: send_ct is %lx reply ct is %lx\n", sep->send_ct, sep->reply_ct); - /* Check if error occured during poll */ + /* Check if error occurred during poll */ retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR); if (retval2 != 0x0) { dev_warn(&sep->pdev->dev, "poll; poll error %x\n", retval2); @@ -1106,7 +1106,7 @@ static int sep_lock_user_pages(struct sep_device *sep, lli_array[count].block_size); } - /* Set output params acording to the in_out flag */ + /* Set output params according to the in_out flag */ if (in_out_flag == SEP_DRIVER_IN_FLAG) { *lli_array_ptr = lli_array; sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages = num_pages; @@ -1577,7 +1577,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep, /* * If this is not the last table - - * then allign it to the block size + * then align it to the block size */ if (!last_table_flag) table_data_size = @@ -1974,7 +1974,7 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP is %x\n", SEP_DRIVER_ENTRIES_PER_TABLE_IN_SEP); - /* Call the fucntion that creates table from the lli arrays */ + /* Call the function that creates table from the lli arrays */ error = sep_construct_dma_tables_from_lli(sep, lli_in_array, sep->dma_res_arr[sep->nr_dcb_creat].in_num_pages, lli_out_array, @@ -2416,7 +2416,7 @@ end_function: * @cmd: command * @arg: pointer to argument structure * - * Implement the ioctl methods availble on the SEP device. + * Implement the ioctl methods available on the SEP device. */ static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h index d3b9220f3963..1033425c9c30 100644 --- a/drivers/staging/sep/sep_driver_config.h +++ b/drivers/staging/sep/sep_driver_config.h @@ -65,11 +65,11 @@ #define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE 16 /* flag that signifies tah the lock is -currently held by the proccess (struct file) */ +currently held by the process (struct file) */ #define SEP_DRIVER_OWN_LOCK_FLAG 1 /* flag that signifies tah the lock is currently NOT -held by the proccess (struct file) */ +held by the process (struct file) */ #define SEP_DRIVER_DISOWN_LOCK_FLAG 0 /* indicates whether driver has mapped/unmapped shared area */ diff --git a/drivers/staging/slicoss/README b/drivers/staging/slicoss/README index 70f49099c065..b83bba19b7f0 100644 --- a/drivers/staging/slicoss/README +++ b/drivers/staging/slicoss/README @@ -33,7 +33,7 @@ TODO: - NAPI? - wasted overhead of extra stats - state variables for things that are - easily availble and shouldn't be kept in card structure, cardnum, ... + easily available and shouldn't be kept in card structure, cardnum, ... slotnumber, events, ... - get rid of slic_spinlock wrapper - volatile == bad design => bad code diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c index d007e4a12c14..78a16a768509 100644 --- a/drivers/staging/sm7xx/smtcfb.c +++ b/drivers/staging/sm7xx/smtcfb.c @@ -965,7 +965,7 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, goto failed; smtcfb_setmode(sfb); - /* Primary display starting from 0 postion */ + /* Primary display starting from 0 position */ hw.BaseAddressInVRAM = 0; sfb->fb.par = &hw; @@ -1055,7 +1055,7 @@ static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg) pdev->dev.power.power_state = msg; - /* additionaly turn off all function blocks including internal PLLs */ + /* additionally turn off all function blocks including internal PLLs */ smtc_seqw(0x21, 0xff); return 0; diff --git a/drivers/staging/speakup/keyhelp.c b/drivers/staging/speakup/keyhelp.c index 23cf7f44f450..170f38815ffd 100644 --- a/drivers/staging/speakup/keyhelp.c +++ b/drivers/staging/speakup/keyhelp.c @@ -69,7 +69,7 @@ static void build_key_data(void) memset(key_offsets, 0, sizeof(key_offsets)); kp = state_tbl + nstates + 1; while (*kp++) { - /* count occurrances of each function */ + /* count occurrences of each function */ for (i = 0; i < nstates; i++, kp++) { if (!*kp) continue; diff --git a/drivers/staging/speakup/spkguide.txt b/drivers/staging/speakup/spkguide.txt index 24362eb7b8f1..f3210571e396 100644 --- a/drivers/staging/speakup/spkguide.txt +++ b/drivers/staging/speakup/spkguide.txt @@ -1091,7 +1091,7 @@ screen that is constantly changing, such as a clock or status line. There is no way to save these window settings, and you can only have one window defined for each virtual console. There is also no way to have -windows automaticly defined for specific applications. +windows automatically defined for specific applications. In order to define a window, use the review keys to move your reading cursor to the beginning of the area you want to define. Then press diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 007b24b54e25..20dae73d3b78 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -38,7 +38,7 @@ * Outputs: Number of Used Bits * 0, if the argument is 0 * Description: Calculate the number of bits used by a given power of 2 number -* Number can be upto 32 bit +* Number can be up to 32 bit *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ int GLOB_Calc_Used_Bits(u32 n) { @@ -653,7 +653,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) } dev->queue->queuedata = dev; - /* As Linux block layer doens't support >4KB hardware sector, */ + /* As Linux block layer does't support >4KB hardware sector, */ /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); diff --git a/drivers/staging/spectra/flash.c b/drivers/staging/spectra/flash.c index a2f820025ae4..aead358e5c2a 100644 --- a/drivers/staging/spectra/flash.c +++ b/drivers/staging/spectra/flash.c @@ -965,7 +965,7 @@ static void process_cmd_fail_abort(int *first_failed_cmd, if (0 == *first_failed_cmd) *first_failed_cmd = PendingCMD[idx].SBDCmdIndex; - nand_dbg_print(NAND_DBG_DEBUG, "Uncorrectable error has occured " + nand_dbg_print(NAND_DBG_DEBUG, "Uncorrectable error has occurred " "while executing %u Command %u accesing Block %u\n", (unsigned int)p_BTableChangesDelta->ftl_cmd_cnt, PendingCMD[idx].CMD, @@ -1879,7 +1879,7 @@ static int write_back_to_l2_cache(u8 *buf, u64 logical_addr) } /* - * Seach in the Level2 Cache table to find the cache item. + * Search in the Level2 Cache table to find the cache item. * If find, read the data from the NAND page of L2 Cache, * Otherwise, return FAIL. */ @@ -3989,7 +3989,7 @@ int GLOB_FTL_Block_Erase(u64 blk_addr) * Inputs: index to block that was just incremented and is at the max * Outputs: PASS=0 / FAIL=1 * Description: If any erase counts at MAX, adjusts erase count of every -* block by substracting least worn +* block by subtracting least worn * counter from counter value of every entry in wear table *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*/ static int FTL_Adjust_Relative_Erase_Count(u32 Index_of_MAX) diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c index d55a8e40318b..3e68d58fdffd 100644 --- a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c +++ b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c @@ -71,7 +71,7 @@ #define SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM (0x01) /** - * struct synaptics_rmi4_fn_desc - contains the funtion descriptor information + * struct synaptics_rmi4_fn_desc - contains the function descriptor information * @query_base_addr: base address for query * @cmd_base_addr: base address for command * @ctrl_base_addr: base address for control @@ -92,7 +92,7 @@ struct synaptics_rmi4_fn_desc { }; /** - * struct synaptics_rmi4_fn - contains the funtion information + * struct synaptics_rmi4_fn - contains the function information * @fn_number: function number * @num_of_data_sources: number of data sources * @num_of_data_points: number of fingers touched @@ -151,7 +151,7 @@ struct synaptics_rmi4_device_info { * @input_dev: pointer for input device * @i2c_client: pointer for i2c client * @board: constant pointer for touch platform data - * @fn_list_mutex: mutex for funtion list + * @fn_list_mutex: mutex for function list * @rmi4_page_mutex: mutex for rmi4 page * @current_page: variable for integer * @number_of_interrupt_register: interrupt registers count @@ -278,7 +278,7 @@ static int synaptics_rmi4_i2c_byte_write(struct synaptics_rmi4_data *pdata, txbuf[0] = address & MASK_8BIT; txbuf[1] = data; retval = i2c_master_send(pdata->i2c_client, txbuf, 2); - /* Add in retry on writes only in certian error return values */ + /* Add in retry on writes only in certain error return values */ if (retval != 2) { dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval); retval = -EIO; @@ -561,7 +561,7 @@ static int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata, } /* * 2D data sources have only 3 bits for the number of fingers - * supported - so the encoding is a bit wierd. + * supported - so the encoding is a bit weird. */ if ((queries[1] & MASK_3BIT) <= 4) /* add 1 since zero based */ @@ -1027,7 +1027,7 @@ err_input: * synaptics_rmi4_remove() - Removes the i2c-client touchscreen driver * @client: i2c client structure pointer * - * This funtion uses to remove the i2c-client + * This function uses to remove the i2c-client * touchscreen driver and returns integer. */ static int __devexit synaptics_rmi4_remove(struct i2c_client *client) @@ -1053,7 +1053,7 @@ static int __devexit synaptics_rmi4_remove(struct i2c_client *client) * synaptics_rmi4_suspend() - suspend the touch screen controller * @dev: pointer to device structure * - * This funtion is used to suspend the + * This function is used to suspend the * touch panel controller and returns integer */ static int synaptics_rmi4_suspend(struct device *dev) @@ -1089,7 +1089,7 @@ static int synaptics_rmi4_suspend(struct device *dev) * synaptics_rmi4_resume() - resume the touch screen controller * @dev: pointer to device structure * - * This funtion is used to resume the touch panel + * This function is used to resume the touch panel * controller and returns integer. */ static int synaptics_rmi4_resume(struct device *dev) @@ -1148,7 +1148,7 @@ static struct i2c_driver synaptics_rmi4_driver = { /** * synaptics_rmi4_init() - Initialize the touchscreen driver * - * This funtion uses to initializes the synaptics + * This function uses to initializes the synaptics * touchscreen driver and returns integer. */ static int __init synaptics_rmi4_init(void) @@ -1158,7 +1158,7 @@ static int __init synaptics_rmi4_init(void) /** * synaptics_rmi4_exit() - De-initialize the touchscreen driver * - * This funtion uses to de-initialize the synaptics + * This function uses to de-initialize the synaptics * touchscreen driver and returns none. */ static void __exit synaptics_rmi4_exit(void) diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h index 1e0273e50d2b..7cb587103975 100644 --- a/drivers/staging/tidspbridge/core/_tiomap.h +++ b/drivers/staging/tidspbridge/core/_tiomap.h @@ -366,7 +366,7 @@ extern s32 dsp_debug; * ======== sm_interrupt_dsp ======== * Purpose: * Set interrupt value & send an interrupt to the DSP processor(s). - * This is typicaly used when mailbox interrupt mechanisms allow data + * This is typically used when mailbox interrupt mechanisms allow data * to be associated with interrupt such as for OMAP's CMD/DATA regs. * Parameters: * dev_context: Handle to Bridge driver defined device info. diff --git a/drivers/staging/tidspbridge/core/chnl_sm.c b/drivers/staging/tidspbridge/core/chnl_sm.c index 8381130e1460..6d66e7d0fba8 100644 --- a/drivers/staging/tidspbridge/core/chnl_sm.c +++ b/drivers/staging/tidspbridge/core/chnl_sm.c @@ -578,7 +578,7 @@ int bridge_chnl_get_ioc(struct chnl_object *chnl_obj, u32 timeout, } else if (stat_sync == -EPERM) { /* This can occur when the user mode thread is * aborted (^C), or when _VWIN32_WaitSingleObject() - * fails due to unkown causes. */ + * fails due to unknown causes. */ /* Even though Wait failed, there may be something in * the Q: */ if (list_empty(&pchnl->io_completions)) { diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c index 390040984e03..5cecd237e3f6 100644 --- a/drivers/staging/tidspbridge/dynload/cload.c +++ b/drivers/staging/tidspbridge/dynload/cload.c @@ -718,7 +718,7 @@ static void dload_symbols(struct dload_state *dlthis) * as a temporary for .dllview record construction. * Allocate storage for the whole table. Add 1 to the section count * in case a trampoline section is auto-generated as well as the - * size of the trampoline section name so DLLView doens't get lost. + * size of the trampoline section name so DLLView does't get lost. */ siz = sym_count * sizeof(struct local_symbol); diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.c b/drivers/staging/tidspbridge/hw/hw_mmu.c index 014f5d5293ae..c214df9b205e 100644 --- a/drivers/staging/tidspbridge/hw/hw_mmu.c +++ b/drivers/staging/tidspbridge/hw/hw_mmu.c @@ -59,7 +59,7 @@ enum hw_mmu_page_size_t { * RETURNS: * * Type : hw_status - * Description : 0 -- No errors occured + * Description : 0 -- No errors occurred * RET_BAD_NULL_PARAM -- A Pointer * Paramater was set to NULL * @@ -102,7 +102,7 @@ static hw_status mmu_flush_entry(const void __iomem *base_address); * RETURNS: * * Type : hw_status - * Description : 0 -- No errors occured + * Description : 0 -- No errors occurred * RET_BAD_NULL_PARAM -- A Pointer Paramater * was set to NULL * RET_PARAM_OUT_OF_RANGE -- Input Parameter out @@ -147,7 +147,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address, * RETURNS: * * Type : hw_status - * Description : 0 -- No errors occured + * Description : 0 -- No errors occurred * RET_BAD_NULL_PARAM -- A Pointer Paramater * was set to NULL * RET_PARAM_OUT_OF_RANGE -- Input Parameter diff --git a/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h b/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h index d60e25258020..6e7ab4fd8c39 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h +++ b/drivers/staging/tidspbridge/include/dspbridge/_chnl_sm.h @@ -144,7 +144,7 @@ struct chnl_object { s8 chnl_mode; /* Chnl mode and attributes */ /* Chnl I/O completion event (user mode) */ void *user_event; - /* Abstract syncronization object */ + /* Abstract synchronization object */ struct sync_object *sync_event; u32 process; /* Process which created this channel */ u32 cb_arg; /* Argument to use with callback */ @@ -156,7 +156,7 @@ struct chnl_object { struct list_head io_completions; struct list_head free_packets_list; /* List of free Irps */ struct ntfy_object *ntfy_obj; - u32 bytes_moved; /* Total number of bytes transfered */ + u32 bytes_moved; /* Total number of bytes transferred */ /* For DSP-DMA */ diff --git a/drivers/staging/tidspbridge/include/dspbridge/clk.h b/drivers/staging/tidspbridge/include/dspbridge/clk.h index b23950323421..685341c50693 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/clk.h +++ b/drivers/staging/tidspbridge/include/dspbridge/clk.h @@ -55,7 +55,7 @@ extern void dsp_clk_exit(void); * Initializes private state of CLK module. * Parameters: * Returns: - * TRUE if initialized; FALSE if error occured. + * TRUE if initialized; FALSE if error occurred. * Requires: * Ensures: * CLK initialized. @@ -71,7 +71,7 @@ void dsp_gpt_wait_overflow(short int clk_id, unsigned int load); * Parameters: * Returns: * 0: Success. - * -EPERM: Error occured while enabling the clock. + * -EPERM: Error occurred while enabling the clock. * Requires: * Ensures: */ @@ -86,7 +86,7 @@ u32 dsp_clock_enable_all(u32 dsp_per_clocks); * Parameters: * Returns: * 0: Success. - * -EPERM: Error occured while disabling the clock. + * -EPERM: Error occurred while disabling the clock. * Requires: * Ensures: */ diff --git a/drivers/staging/tidspbridge/include/dspbridge/cmm.h b/drivers/staging/tidspbridge/include/dspbridge/cmm.h index 27a21b5f3ff0..aff22051cf57 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/cmm.h +++ b/drivers/staging/tidspbridge/include/dspbridge/cmm.h @@ -190,7 +190,7 @@ extern int cmm_get_info(struct cmm_object *hcmm_mgr, * Initializes private state of CMM module. * Parameters: * Returns: - * TRUE if initialized; FALSE if error occured. + * TRUE if initialized; FALSE if error occurred. * Requires: * Ensures: * CMM initialized. diff --git a/drivers/staging/tidspbridge/include/dspbridge/cod.h b/drivers/staging/tidspbridge/include/dspbridge/cod.h index 53bd4bb8b0bb..cb684c11b302 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/cod.h +++ b/drivers/staging/tidspbridge/include/dspbridge/cod.h @@ -249,7 +249,7 @@ extern int cod_get_sym_value(struct cod_manager *cod_mgr_obj, * Parameters: * None. * Returns: - * TRUE if initialized; FALSE if error occured. + * TRUE if initialized; FALSE if error occurred. * Requires: * Ensures: * A requirement for each of the other public COD functions. diff --git a/drivers/staging/tidspbridge/include/dspbridge/dev.h b/drivers/staging/tidspbridge/include/dspbridge/dev.h index f41e4783157f..f92b4be0b413 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/dev.h +++ b/drivers/staging/tidspbridge/include/dspbridge/dev.h @@ -497,7 +497,7 @@ extern void dev_exit(void); * Initialize DEV's private state, keeping a reference count on each call. * Parameters: * Returns: - * TRUE if initialized; FALSE if error occured. + * TRUE if initialized; FALSE if error occurred. * Requires: * Ensures: * TRUE: A requirement for the other public DEV functions. diff --git a/drivers/staging/tidspbridge/include/dspbridge/drv.h b/drivers/staging/tidspbridge/include/dspbridge/drv.h index 25ef1a2c58eb..9cdbd955dce9 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/drv.h +++ b/drivers/staging/tidspbridge/include/dspbridge/drv.h @@ -154,7 +154,7 @@ struct process_context { * Parameters: * drv_obj: Location to store created DRV Object handle. * Returns: - * 0: Sucess + * 0: Success * -ENOMEM: Failed in Memory allocation * -EPERM: General Failure * Requires: @@ -170,7 +170,7 @@ struct process_context { * There is one Driver Object for the Driver representing * the driver itself. It contains the list of device * Objects and the list of Device Extensions in the system. - * Also it can hold other neccessary + * Also it can hold other necessary * information in its storage area. */ extern int drv_create(struct drv_object **drv_obj); @@ -180,7 +180,7 @@ extern int drv_create(struct drv_object **drv_obj); * Purpose: * destroys the Dev Object list, DrvExt list * and destroy the DRV object - * Called upon driver unLoading.or unsuccesful loading of the driver. + * Called upon driver unLoading.or unsuccessful loading of the driver. * Parameters: * driver_obj: Handle to Driver object . * Returns: diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h index c2ba26c09308..ed32bf383132 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h +++ b/drivers/staging/tidspbridge/include/dspbridge/dspdefs.h @@ -52,7 +52,7 @@ struct bridge_dev_context; * dev_ctxt: Handle to Bridge driver defined device context. * Returns: * 0: Success. - * -ETIMEDOUT: Timeout occured waiting for a response from hardware. + * -ETIMEDOUT: Timeout occurred waiting for a response from hardware. * -EPERM: Other, unspecified error. * Requires: * dev_ctxt != NULL @@ -91,7 +91,7 @@ typedef int(*fxn_brd_setstate) (struct bridge_dev_context * dsp_addr: DSP address at which to start execution. * Returns: * 0: Success. - * -ETIMEDOUT: Timeout occured waiting for a response from hardware. + * -ETIMEDOUT: Timeout occurred waiting for a response from hardware. * -EPERM: Other, unspecified error. * Requires: * dev_ctxt != NULL @@ -142,7 +142,7 @@ typedef int(*fxn_brd_memcopy) (struct bridge_dev_context * mem_type: Memory space on DSP to which to transfer. * Returns: * 0: Success. - * -ETIMEDOUT: Timeout occured waiting for a response from hardware. + * -ETIMEDOUT: Timeout occurred waiting for a response from hardware. * -EPERM: Other, unspecified error. * Requires: * dev_ctxt != NULL; @@ -205,7 +205,7 @@ typedef int(*fxn_brd_memunmap) (struct bridge_dev_context * dev_ctxt: Handle to Bridge driver defined device context. * Returns: * 0: Success. - * -ETIMEDOUT: Timeout occured waiting for a response from hardware. + * -ETIMEDOUT: Timeout occurred waiting for a response from hardware. * -EPERM: Other, unspecified error. * Requires: * dev_ctxt != NULL @@ -248,7 +248,7 @@ typedef int(*fxn_brd_status) (struct bridge_dev_context *dev_ctxt, * mem_type: Memory space on DSP from which to transfer. * Returns: * 0: Success. - * -ETIMEDOUT: Timeout occured waiting for a response from hardware. + * -ETIMEDOUT: Timeout occurred waiting for a response from hardware. * -EPERM: Other, unspecified error. * Requires: * dev_ctxt != NULL; @@ -274,7 +274,7 @@ typedef int(*fxn_brd_read) (struct bridge_dev_context *dev_ctxt, * mem_type: Memory space on DSP to which to transfer. * Returns: * 0: Success. - * -ETIMEDOUT: Timeout occured waiting for a response from hardware. + * -ETIMEDOUT: Timeout occurred waiting for a response from hardware. * -EPERM: Other, unspecified error. * Requires: * dev_ctxt != NULL; @@ -601,7 +601,7 @@ typedef int(*fxn_chnl_getmgrinfo) (struct chnl_mgr * Returns: * 0: Success; * -EFAULT: Invalid chnl_obj. - * -ETIMEDOUT: Timeout occured before channel could be idled. + * -ETIMEDOUT: Timeout occurred before channel could be idled. * Requires: * Ensures: */ diff --git a/drivers/staging/tidspbridge/include/dspbridge/mgr.h b/drivers/staging/tidspbridge/include/dspbridge/mgr.h index e506c4d49472..47b0318430e1 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/mgr.h +++ b/drivers/staging/tidspbridge/include/dspbridge/mgr.h @@ -176,7 +176,7 @@ extern void mgr_exit(void); * mgr_handle: Handle to the Manager Object * dcd_handle: Ptr to receive the DCD Handle. * Returns: - * 0: Sucess + * 0: Success * -EPERM: Failure to get the Handle * Requires: * MGR is initialized. @@ -195,7 +195,7 @@ extern int mgr_get_dcd_handle(struct mgr_object * call. Initializes the DCD. * Parameters: * Returns: - * TRUE if initialized; FALSE if error occured. + * TRUE if initialized; FALSE if error occurred. * Requires: * Ensures: * TRUE: A requirement for the other public MGR functions. diff --git a/drivers/staging/tidspbridge/include/dspbridge/node.h b/drivers/staging/tidspbridge/include/dspbridge/node.h index 53da0ef483c8..16371d818e3d 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/node.h +++ b/drivers/staging/tidspbridge/include/dspbridge/node.h @@ -44,7 +44,7 @@ * -ESPIPE: iAlg functions not found for a DAIS node. * -EDOM: attr_in != NULL and attr_in->prio out of * range. - * -EPERM: A failure occured, unable to allocate node. + * -EPERM: A failure occurred, unable to allocate node. * -EBADR: Proccessor is not in the running state. * Requires: * node_init(void) called. diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h index 5e09fd165d9d..f00dffd51989 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/proc.h +++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h @@ -89,7 +89,7 @@ extern int proc_auto_start(struct cfg_devnode *dev_node_obj, * Returns: * 0 : SUCCESS * -EFAULT : Invalid processor handle. - * -ETIME: A Timeout Occured before the Control information + * -ETIME: A Timeout Occurred before the Control information * could be sent. * -EPERM : General Failure. * Requires: @@ -169,7 +169,7 @@ extern int proc_enum_nodes(void *hprocessor, * 0 : Success. * -EFAULT : Invalid processor handle. * -EBADR: The processor is not in the PROC_RUNNING state. - * -ETIME: A timeout occured before the DSP responded to the + * -ETIME: A timeout occurred before the DSP responded to the * querry. * -EPERM : Unable to get Resource Information * Requires: @@ -229,7 +229,7 @@ extern int proc_get_dev_object(void *hprocessor, * call. * Parameters: * Returns: - * TRUE if initialized; FALSE if error occured. + * TRUE if initialized; FALSE if error occurred. * Requires: * Ensures: * TRUE: A requirement for the other public PROC functions. diff --git a/drivers/staging/tidspbridge/include/dspbridge/pwr.h b/drivers/staging/tidspbridge/include/dspbridge/pwr.h index 5e3ab2123aaa..0fb066488da9 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/pwr.h +++ b/drivers/staging/tidspbridge/include/dspbridge/pwr.h @@ -46,7 +46,7 @@ * 0: Success. * 0: Success, but the DSP was already asleep. * -EINVAL: The specified sleep_code is not supported. - * -ETIME: A timeout occured while waiting for DSP sleep + * -ETIME: A timeout occurred while waiting for DSP sleep * confirmation. * -EPERM: General failure, unable to send sleep command to * the DSP. @@ -67,7 +67,7 @@ extern int pwr_sleep_dsp(const u32 sleep_code, const u32 timeout); * Returns: * 0: Success. * 0: Success, but the DSP was already awake. - * -ETIME: A timeout occured while waiting for wake + * -ETIME: A timeout occurred while waiting for wake * confirmation. * -EPERM: General failure, unable to send wake command to * the DSP. @@ -85,7 +85,7 @@ extern int pwr_wake_dsp(const u32 timeout); * Returns: * 0: Success. * 0: Success, but the DSP was already awake. - * -ETIME: A timeout occured while waiting for wake + * -ETIME: A timeout occurred while waiting for wake * confirmation. * -EPERM: General failure, unable to send wake command to * the DSP. @@ -103,7 +103,7 @@ extern int pwr_pm_pre_scale(u16 voltage_domain, u32 level); * Returns: * 0: Success. * 0: Success, but the DSP was already awake. - * -ETIME: A timeout occured while waiting for wake + * -ETIME: A timeout occurred while waiting for wake * confirmation. * -EPERM: General failure, unable to send wake command to * the DSP. diff --git a/drivers/staging/tidspbridge/pmgr/dev.c b/drivers/staging/tidspbridge/pmgr/dev.c index 9a38d86a84a0..522810bc7427 100644 --- a/drivers/staging/tidspbridge/pmgr/dev.c +++ b/drivers/staging/tidspbridge/pmgr/dev.c @@ -787,7 +787,7 @@ int dev_notify_clients(struct dev_object *dev_obj, u32 ret) /* * FIXME: this code needs struct proc_object to have a list_head - * at the begining. If not, this can go horribly wrong. + * at the beginning. If not, this can go horribly wrong. */ list_for_each(curr, &dev_obj->proc_list) proc_notify_clients((void *)curr, ret); @@ -810,7 +810,7 @@ int dev_remove_device(struct cfg_devnode *dev_node_obj) if (!dev_node_obj) status = -EFAULT; - /* Retrieve the device object handle originaly stored with + /* Retrieve the device object handle originally stored with * the dev_node: */ if (!status) { /* check the device string and then store dev object */ @@ -986,7 +986,7 @@ int dev_insert_proc_object(struct dev_object *hdev_obj, /* Add DevObject to tail. */ /* * FIXME: this code needs struct proc_object to have a list_head - * at the begining. If not, this can go horribly wrong. + * at the beginning. If not, this can go horribly wrong. */ list_add_tail((struct list_head *)proc_obj, &dev_obj->proc_list); diff --git a/drivers/staging/tidspbridge/rmgr/drv.c b/drivers/staging/tidspbridge/rmgr/drv.c index 8c88583364eb..db8215f540d8 100644 --- a/drivers/staging/tidspbridge/rmgr/drv.c +++ b/drivers/staging/tidspbridge/rmgr/drv.c @@ -609,7 +609,7 @@ int drv_request_resources(u32 dw_context, u32 *dev_node_strg) DBC_REQUIRE(dev_node_strg != NULL); /* - * Allocate memory to hold the string. This will live untill + * Allocate memory to hold the string. This will live until * it is freed in the Release resources. Update the driver object * list. */ diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c index fb5c2ba01d47..0e70cba15ebc 100644 --- a/drivers/staging/tidspbridge/rmgr/nldr.c +++ b/drivers/staging/tidspbridge/rmgr/nldr.c @@ -57,9 +57,9 @@ * uuuuuuuu|fueeeeee|fudddddd|fucccccc| * where * u = unused - * cccccc = prefered/required dynamic mem segid for create phase data/code - * dddddd = prefered/required dynamic mem segid for delete phase data/code - * eeeeee = prefered/req. dynamic mem segid for execute phase data/code + * cccccc = preferred/required dynamic mem segid for create phase data/code + * dddddd = preferred/required dynamic mem segid for delete phase data/code + * eeeeee = preferred/req. dynamic mem segid for execute phase data/code * f = flag indicating if memory is preferred or required: * f = 1 if required, f = 0 if preferred. * diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c index c4e5c4e0d71c..242dd1399996 100644 --- a/drivers/staging/tidspbridge/rmgr/proc.c +++ b/drivers/staging/tidspbridge/rmgr/proc.c @@ -1670,7 +1670,7 @@ int proc_stop(void *hprocessor) if (!status) { dev_dbg(bridge, "%s: processor in standby mode\n", __func__); p_proc_object->proc_state = PROC_STOPPED; - /* Destory the Node Manager, msg_ctrl Manager */ + /* Destroy the Node Manager, msg_ctrl Manager */ if (!(dev_destroy2(p_proc_object->dev_obj))) { /* Destroy the msg_ctrl by calling msg_delete */ dev_get_msg_mgr(p_proc_object->dev_obj, &hmsg_mgr); @@ -1827,7 +1827,7 @@ static int proc_monitor(struct proc_object *proc_obj) /* This is needed only when Device is loaded when it is * already 'ACTIVE' */ - /* Destory the Node Manager, msg_ctrl Manager */ + /* Destroy the Node Manager, msg_ctrl Manager */ if (!dev_destroy2(proc_obj->dev_obj)) { /* Destroy the msg_ctrl by calling msg_delete */ dev_get_msg_mgr(proc_obj->dev_obj, &hmsg_mgr); diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c index c80a316d9d8f..17db6684abbe 100644 --- a/drivers/staging/tm6000/tm6000-video.c +++ b/drivers/staging/tm6000/tm6000-video.c @@ -182,7 +182,7 @@ static inline void get_next_buf(struct tm6000_dmaqueue *dma_q, if (!buf) return; - /* Cleans up buffer - Usefull for testing for frame/URB loss */ + /* Cleans up buffer - Useful for testing for frame/URB loss */ outp = videobuf_to_vmalloc(&(*buf)->vb); return; diff --git a/drivers/staging/tty/cd1865.h b/drivers/staging/tty/cd1865.h index 9940966e7a1d..8c2ad654b79d 100644 --- a/drivers/staging/tty/cd1865.h +++ b/drivers/staging/tty/cd1865.h @@ -9,7 +9,7 @@ * Please DO contact io8-linux@specialix.co.uk if you require * support. * - * This driver was developped in the BitWizard linux device + * This driver was developed in the BitWizard linux device * driver service. If you require a linux device driver for your * product, please contact devices@BitWizard.nl for a quote. * diff --git a/drivers/staging/tty/epca.c b/drivers/staging/tty/epca.c index 7ad3638967ae..7f1369e5b418 100644 --- a/drivers/staging/tty/epca.c +++ b/drivers/staging/tty/epca.c @@ -7,7 +7,7 @@ ** This driver is no longer supported by Digi ** Much of this design and code came from epca.c which was - copyright (C) 1994, 1995 Troy De Jongh, and subsquently + copyright (C) 1994, 1995 Troy De Jongh, and subsequently modified by David Nugent, Christoph Lameter, Mike McLagan. This program is free software; you can redistribute it and/or modify @@ -471,7 +471,7 @@ static void shutdown(struct channel *ch, struct tty_struct *tty) memoff(ch); /* - * The channel has officialy been closed. The next time it is opened it + * The channel has officially been closed. The next time it is opened it * will have to reinitialized. Set a flag to indicate this. */ /* Prevent future Digi programmed interrupts from coming active */ @@ -975,7 +975,7 @@ static int __init pc_init(void) /* * Note : If lilo was used to configure the driver and the ignore - * epcaconfig option was choosen (digiepca=2) then nbdevs and num_cards + * epcaconfig option was chosen (digiepca=2) then nbdevs and num_cards * will equal 0 at this point. This is okay; PCI cards will still be * picked up if detected. */ @@ -1230,14 +1230,14 @@ static void post_fep_init(unsigned int crd) memaddr = bd->re_map_membase; /* - * The below assignment will set bc to point at the BEGINING of the + * The below assignment will set bc to point at the BEGINNING of the * cards channel structures. For 1 card there will be between 8 and 64 * of these structures. */ bc = memaddr + CHANSTRUCT; /* - * The below assignment will set gd to point at the BEGINING of global + * The below assignment will set gd to point at the BEGINNING of global * memory address 0xc00. The first data in that global memory actually * starts at address 0xc1a. The command in pointer begins at 0xd10. */ @@ -1492,7 +1492,7 @@ static void doevent(int crd) /* * The two assignments below get the current modem status * (mstat) and the previous modem status (lstat). These are - * useful becuase an event could signal a change in modem + * useful because an event could signal a change in modem * signals itself. */ mstat = readb(eventbuf + 2); @@ -1897,7 +1897,7 @@ static void receive_data(struct channel *ch, struct tty_struct *tty) /* * Even if head has wrapped around only report the amount of * data to be equal to the size - tail. Remember memcpy can't - * automaticly wrap around the receive buffer. + * automatically wrap around the receive buffer. */ dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable; @@ -2543,7 +2543,7 @@ static void __init epca_setup(char *str, int *ints) break; /* * If the index incremented above refers to a - * legitamate board type set it here. + * legitimate board type set it here. */ if (index < EPCA_NUM_TYPES) board.type = loop; diff --git a/drivers/staging/tty/ip2/i2hw.h b/drivers/staging/tty/ip2/i2hw.h index c0ba6c05f0cd..8df2f487217a 100644 --- a/drivers/staging/tty/ip2/i2hw.h +++ b/drivers/staging/tty/ip2/i2hw.h @@ -335,7 +335,7 @@ be off by a factor of five. The important point is that the first command reset in fact generates a reset pulse on the board. This pulse is guaranteed to last less than 10 milliseconds. The additional delay ensures the 1400 has had the chance to respond sufficiently to the first reset. Why not a longer delay? Much -more than 50 milliseconds gets to be noticable, but the board would still work. +more than 50 milliseconds gets to be noticeable, but the board would still work. Once all 16 bytes of the Power-on Reset Message have been read, the bootstrap firmware is ready to receive loadware. @@ -399,7 +399,7 @@ typedef union _porStr // "por" stands for Power On Reset // expandable products must report a MAP of available channels. Since // each UART supports four ports, we represent each UART found by a // single bit. Using two bytes to supply the mapping information we - // report the presense or absense of up to 16 UARTS, or 64 ports in + // report the presence or absence of up to 16 UARTS, or 64 ports in // steps of 4 ports. For -IIEX products, the ports are numbered // starting at the box closest to the controller in the "chain". diff --git a/drivers/staging/tty/ip2/i2lib.c b/drivers/staging/tty/ip2/i2lib.c index 0d10b89218ed..13a3caba85f2 100644 --- a/drivers/staging/tty/ip2/i2lib.c +++ b/drivers/staging/tty/ip2/i2lib.c @@ -821,7 +821,7 @@ i2GetStatus(i2ChanStrPtr pCh, int resetBits) // // Description: // Strips data from the input buffer and writes it to pDest. If there is a -// collosal blunder, (invalid structure pointers or the like), returns -1. +// colossal blunder, (invalid structure pointers or the like), returns -1. // Otherwise, returns the number of bytes read. //****************************************************************************** static int @@ -909,7 +909,7 @@ i2Input_exit: // Returns: Number of bytes stripped, or -1 for error // // Description: -// Strips any data from the input buffer. If there is a collosal blunder, +// Strips any data from the input buffer. If there is a colossal blunder, // (invalid structure pointers or the like), returns -1. Otherwise, returns the // number of bytes stripped. //****************************************************************************** @@ -963,7 +963,7 @@ i2InputFlush(i2ChanStrPtr pCh) // Returns: Number of bytes available, or -1 for error // // Description: -// If there is a collosal blunder, (invalid structure pointers or the like), +// If there is a colossal blunder, (invalid structure pointers or the like), // returns -1. Otherwise, returns the number of bytes stripped. Otherwise, // returns the number of bytes available in the buffer. //****************************************************************************** @@ -1001,7 +1001,7 @@ i2InputAvailable(i2ChanStrPtr pCh) // // Description: // Queues the data at pSource to be sent as data packets to the board. If there -// is a collosal blunder, (invalid structure pointers or the like), returns -1. +// is a colossal blunder, (invalid structure pointers or the like), returns -1. // Otherwise, returns the number of bytes written. What if there is not enough // room for all the data? If pCh->channelOptions & CO_NBLOCK_WRITE is set, then // we transfer as many characters as we can now, then return. If this bit is diff --git a/drivers/staging/tty/ip2/ip2main.c b/drivers/staging/tty/ip2/ip2main.c index ea7a8fb08283..ba074fbb4ce2 100644 --- a/drivers/staging/tty/ip2/ip2main.c +++ b/drivers/staging/tty/ip2/ip2main.c @@ -1824,7 +1824,7 @@ ip2_flush_chars( PTTY tty ) // ip2trace (CHANN, ITRC_PUTC, 10, 1, strip ); // - // We may need to restart i2Output if it does not fullfill this request + // We may need to restart i2Output if it does not fulfill this request // strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff); if ( strip != pCh->Pbuf_stuff ) { diff --git a/drivers/staging/tty/specialix.c b/drivers/staging/tty/specialix.c index 17a1be536a46..cb24c6d999db 100644 --- a/drivers/staging/tty/specialix.c +++ b/drivers/staging/tty/specialix.c @@ -9,7 +9,7 @@ * support. But please read the documentation (specialix.txt) * first. * - * This driver was developped in the BitWizard linux device + * This driver was developed in the BitWizard linux device * driver service. If you require a linux device driver for your * product, please contact devices@BitWizard.nl for a quote. * @@ -978,7 +978,7 @@ static void sx_change_speed(struct specialix_board *bp, spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); - /* The Specialix board doens't implement the RTS lines. + /* The Specialix board does't implement the RTS lines. They are used to set the IRQ level. Don't touch them. */ if (sx_crtscts(tty)) port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS); diff --git a/drivers/staging/tty/specialix_io8.h b/drivers/staging/tty/specialix_io8.h index c63005274d9b..1215d7e2cb37 100644 --- a/drivers/staging/tty/specialix_io8.h +++ b/drivers/staging/tty/specialix_io8.h @@ -10,7 +10,7 @@ * Please DO contact io8-linux@specialix.co.uk if you require * support. * - * This driver was developped in the BitWizard linux device + * This driver was developed in the BitWizard linux device * driver service. If you require a linux device driver for your * product, please contact devices@BitWizard.nl for a quote. * @@ -79,7 +79,7 @@ more than a few PCI versions of the card. */ #define SPECIALIX_MAGIC 0x0907 -#define SX_CCR_TIMEOUT 10000 /* CCR timeout. You may need to wait upto +#define SX_CCR_TIMEOUT 10000 /* CCR timeout. You may need to wait up to 10 milliseconds before the internal processor is available again after you give it a command */ diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index e23484998598..0f02a4b12ae4 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -194,7 +194,7 @@ void rh_port_disconnect(int rhport) * * So, the maximum number of ports is 31 ( port 0 to port 30) ? * - * The return value is the actual transfered length in byte. If nothing has + * The return value is the actual transferred length in byte. If nothing has * been changed, return 0. In the case that the number of ports is less than or * equal to 6 (VHCI_NPORTS==7), return 1. * diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index d4a48c4e59c2..a4007287ef47 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -621,7 +621,7 @@ static int ca91cx42_master_set(struct vme_master_resource *image, int enabled, /* * Let's allocate the resource here rather than further up the stack as - * it avoids pushing loads of bus dependant stuff up the stack + * it avoids pushing loads of bus dependent stuff up the stack */ retval = ca91cx42_alloc_resource(image, size); if (retval) { @@ -1052,7 +1052,7 @@ static int ca91cx42_dma_list_add(struct vme_dma_list *list, pci_attr = dest->private; } - /* Check we can do fullfill required attributes */ + /* Check we can do fulfill required attributes */ if ((vme_attr->aspace & ~(VME_A16 | VME_A24 | VME_A32 | VME_USER1 | VME_USER2)) != 0) { @@ -1069,7 +1069,7 @@ static int ca91cx42_dma_list_add(struct vme_dma_list *list, goto err_cycle; } - /* Check to see if we can fullfill source and destination */ + /* Check to see if we can fulfill source and destination */ if (!(((src->type == VME_DMA_PCI) && (dest->type == VME_DMA_VME)) || ((src->type == VME_DMA_VME) && (dest->type == VME_DMA_PCI)))) { diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index b00a53e793e7..106aa9daff48 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -928,7 +928,7 @@ static int tsi148_master_set(struct vme_master_resource *image, int enabled, spin_lock(&image->lock); /* Let's allocate the resource here rather than further up the stack as - * it avoids pushing loads of bus dependant stuff up the stack. If size + * it avoids pushing loads of bus dependent stuff up the stack. If size * is zero, any existing resource will be freed. */ retval = tsi148_alloc_resource(image, size); @@ -1320,7 +1320,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, /* * Writes are posted. We need to do a read on the VME bus to flush out - * all of the writes before we check for errors. We can't guarentee + * all of the writes before we check for errors. We can't guarantee * that reading the data we have just written is safe. It is believed * that there isn't any read, write re-ordering, so we can read any * location in VME space, so lets read the Device ID from the tsi148's diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/staging/vme/bridges/vme_tsi148.h index 9f97fa8084e8..a3ac2fe98816 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.h +++ b/drivers/staging/vme/bridges/vme_tsi148.h @@ -212,7 +212,7 @@ static const int TSI148_LCSR_OT[8] = { TSI148_LCSR_OT0, TSI148_LCSR_OT1, #define TSI148_LCSR_OFFSET_OTAT 0x1C /* - * VMEbus interupt ack + * VMEbus interrupt ack * offset 200 */ #define TSI148_LCSR_VIACK1 0x204 @@ -613,7 +613,7 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, /* * PCI-X Status Register (CRG +$054) */ -#define TSI148_PCFS_PCIXSTAT_RSCEM (1<<29) /* Recieved Split Comp Error */ +#define TSI148_PCFS_PCIXSTAT_RSCEM (1<<29) /* Received Split Comp Error */ #define TSI148_PCFS_PCIXSTAT_DMCRS_M (7<<26) /* max Cumulative Read Size */ #define TSI148_PCFS_PCIXSTAT_DMOST_M (7<<23) /* max outstanding Split Trans */ @@ -982,8 +982,8 @@ static const int TSI148_GCSR_MBOX[4] = { TSI148_GCSR_MBOX0, #define TSI148_LCSR_VICR_CNTS_IRQ1 (2<<22) /* IRQ1 to Cntr */ #define TSI148_LCSR_VICR_CNTS_IRQ2 (3<<22) /* IRQ2 to Cntr */ -#define TSI148_LCSR_VICR_EDGIS_M (3<<20) /* Edge interupt MASK */ -#define TSI148_LCSR_VICR_EDGIS_DIS (1<<20) /* Edge interupt Disable */ +#define TSI148_LCSR_VICR_EDGIS_M (3<<20) /* Edge interrupt MASK */ +#define TSI148_LCSR_VICR_EDGIS_DIS (1<<20) /* Edge interrupt Disable */ #define TSI148_LCSR_VICR_EDGIS_IRQ1 (2<<20) /* IRQ1 to Edge */ #define TSI148_LCSR_VICR_EDGIS_IRQ2 (3<<20) /* IRQ2 to Edge */ diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt index a910a0c4388b..4910e92c52af 100644 --- a/drivers/staging/vme/vme_api.txt +++ b/drivers/staging/vme/vme_api.txt @@ -6,7 +6,7 @@ Driver registration As with other subsystems within the Linux kernel, VME device drivers register with the VME subsystem, typically called from the devices init routine. This is -achieved via a call to the follwoing function: +achieved via a call to the following function: int vme_register_driver (struct vme_driver *driver); @@ -108,7 +108,7 @@ Master windows ============== Master windows provide access from the local processor[s] out onto the VME bus. -The number of windows available and the available access modes is dependant on +The number of windows available and the available access modes is dependent on the underlying chipset. A window must be configured before it can be used. @@ -163,7 +163,7 @@ Slave windows Slave windows provide devices on the VME bus access into mapped portions of the local memory. The number of windows available and the access modes that can be -used is dependant on the underlying chipset. A window must be configured before +used is dependent on the underlying chipset. A window must be configured before it can be used. diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 951a3a8ddcb2..2721e0798496 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -1186,7 +1186,7 @@ CARDbStartMeasure ( wDuration += 1; // 1 TU for channel switching if ((LODWORD(qwStartTSF) == 0) && (HIDWORD(qwStartTSF) == 0)) { - // start imediately by setting start TSF == current TSF + 2 TU + // start immediately by setting start TSF == current TSF + 2 TU LODWORD(qwStartTSF) = LODWORD(qwCurrTSF) + 2048; HIDWORD(qwStartTSF) = HIDWORD(qwCurrTSF); if (LODWORD(qwCurrTSF) > LODWORD(qwStartTSF)) { diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index efaf19bc07b7..ad39c8727e9b 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -137,7 +137,7 @@ DEVICE_PARAM(TxDescriptors1,"Number of transmit descriptors1"); /* IP_byte_align[] is used for IP header unsigned long byte aligned 0: indicate the IP header won't be unsigned long byte aligned.(Default) . 1: indicate the IP header will be unsigned long byte aligned. - In some enviroment, the IP header should be unsigned long byte aligned, + In some environment, the IP header should be unsigned long byte aligned, or the packet will be droped when we receive it. (eg: IPVS) */ DEVICE_PARAM(IP_byte_align,"Enable IP header dword aligned"); diff --git a/drivers/staging/vt6655/wcmd.c b/drivers/staging/vt6655/wcmd.c index abd6745bc3fe..c30170a2bc44 100644 --- a/drivers/staging/vt6655/wcmd.c +++ b/drivers/staging/vt6655/wcmd.c @@ -587,7 +587,7 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED)) { // Call mgr to begin the deauthentication - // reason = (3) beacuse sta has left ESS + // reason = (3) because sta has left ESS if (pMgmt->eCurrState>= WMAC_STATE_AUTH) { vMgrDeAuthenBeginSta((void *)pDevice, pMgmt, pMgmt->abyCurrBSSID, (3), &Status); } diff --git a/drivers/staging/vt6655/wmgr.h b/drivers/staging/vt6655/wmgr.h index 141e80b843af..e3ae562f521a 100644 --- a/drivers/staging/vt6655/wmgr.h +++ b/drivers/staging/vt6655/wmgr.h @@ -220,7 +220,7 @@ typedef enum tagWMAC_POWER_MODE { */ -// Tx Managment Packet descriptor +// Tx Management Packet descriptor typedef struct tagSTxMgmtPacket { PUWLAN_80211HDR p80211Header; @@ -230,7 +230,7 @@ typedef struct tagSTxMgmtPacket { } STxMgmtPacket, *PSTxMgmtPacket; -// Rx Managment Packet descriptor +// Rx Management Packet descriptor typedef struct tagSRxMgmtPacket { PUWLAN_80211HDR p80211Header; diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 8f18578a5903..5185d61564d7 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -1938,7 +1938,7 @@ s_vGenerateMACHeader ( * Out: * none * - * Return Value: CMD_STATUS_PENDING if MAC Tx resource avaliable; otherwise FALSE + * Return Value: CMD_STATUS_PENDING if MAC Tx resource available; otherwise FALSE * -*/ diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c index b83b660b1f0f..019fb52de366 100644 --- a/drivers/staging/vt6656/wcmd.c +++ b/drivers/staging/vt6656/wcmd.c @@ -421,7 +421,7 @@ void vRunCommand(void *hDeviceContext) pMgmt->eScanState = WMAC_IS_SCANNING; pDevice->byScanBBType = pDevice->byBBType; //lucas pDevice->bStopDataPkt = TRUE; - // Turn off RCR_BSSID filter everytime + // Turn off RCR_BSSID filter every time MACvRegBitsOff(pDevice, MAC_REG_RCR, RCR_BSSID); pDevice->byRxMode &= ~RCR_BSSID; @@ -604,7 +604,7 @@ void vRunCommand(void *hDeviceContext) // if Infra mode if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED)) { // Call mgr to begin the deauthentication - // reason = (3) beacuse sta has left ESS + // reason = (3) because sta has left ESS if (pMgmt->eCurrState >= WMAC_STATE_AUTH) { vMgrDeAuthenBeginSta((void *)pDevice, pMgmt, diff --git a/drivers/staging/vt6656/wmgr.h b/drivers/staging/vt6656/wmgr.h index 594f3a89d8a7..13dfb3bf8328 100644 --- a/drivers/staging/vt6656/wmgr.h +++ b/drivers/staging/vt6656/wmgr.h @@ -218,7 +218,7 @@ typedef enum tagWMAC_POWER_MODE { -// Tx Managment Packet descriptor +// Tx Management Packet descriptor typedef struct tagSTxMgmtPacket { PUWLAN_80211HDR p80211Header; @@ -228,7 +228,7 @@ typedef struct tagSTxMgmtPacket { } STxMgmtPacket, *PSTxMgmtPacket; -// Rx Managment Packet descriptor +// Rx Management Packet descriptor typedef struct tagSRxMgmtPacket { PUWLAN_80211HDR p80211Header; diff --git a/drivers/staging/westbridge/astoria/api/src/cyasdma.c b/drivers/staging/westbridge/astoria/api/src/cyasdma.c index 16b8ec124510..c461d4f60bfb 100644 --- a/drivers/staging/westbridge/astoria/api/src/cyasdma.c +++ b/drivers/staging/westbridge/astoria/api/src/cyasdma.c @@ -1082,7 +1082,7 @@ cy_as_dma_received_data(cy_as_device *dev_p, /* * if the data received exceeds the size of the DMA buffer, * clip the data to the size of the buffer. this can lead - * to loosing some data, but is not different than doing + * to losing some data, but is not different than doing * non-packet reads on the other endpoints. */ if (dsize > dma_p->size - dma_p->offset) diff --git a/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c b/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c index 60b6f3525332..76821e51b817 100644 --- a/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c +++ b/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c @@ -126,7 +126,7 @@ find_endpoint_directions(cy_as_device *dev_p, cy_as_physical_endpoint_state desired; /* - * note, there is no error checking here becuase + * note, there is no error checking here because * ISO error checking happens when the API is called. */ for (i = 0; i < 10; i++) { diff --git a/drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c b/drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c index d43dd858de58..96a86d088305 100644 --- a/drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c +++ b/drivers/staging/westbridge/astoria/api/src/cyaslowlevel.c @@ -432,7 +432,7 @@ cy_as_mail_box_queued_data_handler(cy_as_device *dev_p) * is received. When a complete request is received, the callback * associated with requests on that context is called. When a complete * response is recevied, the callback associated with the request that -* generated the reponse is called. +* generated the response is called. */ void cy_as_mail_box_interrupt_handler(cy_as_device *dev_p) diff --git a/drivers/staging/westbridge/astoria/api/src/cyasmisc.c b/drivers/staging/westbridge/astoria/api/src/cyasmisc.c index 7852410b0a4c..4564fc11df22 100644 --- a/drivers/staging/westbridge/astoria/api/src/cyasmisc.c +++ b/drivers/staging/westbridge/astoria/api/src/cyasmisc.c @@ -428,7 +428,7 @@ my_misc_callback(cy_as_device *dev_p, uint8_t context, if (v & CY_AS_MEM_P0_VM_SET_CFGMODE) cy_as_hal_print_message( "initialization message " - "recieved, but config bit " + "received, but config bit " "still set\n"); v = cy_as_hal_read_register(dev_p->tag, @@ -436,7 +436,7 @@ my_misc_callback(cy_as_device *dev_p, uint8_t context, if ((v & CY_AS_MEM_RST_RSTCMPT) == 0) cy_as_hal_print_message( "initialization message " - "recieved, but reset complete " + "received, but reset complete " "bit still not set\n"); } break; @@ -2381,7 +2381,7 @@ try_wakeup_again: /* * release the west bridge micro-_controller from reset, * so that firmware initialization can complete. the attempt - * to release antioch reset is made upto 8 times. + * to release antioch reset is made up to 8 times. */ v = 0x03; count = 0x08; diff --git a/drivers/staging/westbridge/astoria/api/src/cyasmtp.c b/drivers/staging/westbridge/astoria/api/src/cyasmtp.c index 368984633874..8598364f7ab7 100644 --- a/drivers/staging/westbridge/astoria/api/src/cyasmtp.c +++ b/drivers/staging/westbridge/astoria/api/src/cyasmtp.c @@ -346,7 +346,7 @@ cy_as_mtp_start(cy_as_device_handle handle, dev_p->mtp_event_cb = event_c_b; /* - * we register here becuase the start request may cause + * we register here because the start request may cause * events to occur before the response to the start request. */ cy_as_ll_register_request_callback(dev_p, @@ -424,7 +424,7 @@ my_handle_response_mtp_stop(cy_as_device *dev_p, goto destroy; /* - * we sucessfully shutdown the stack, so decrement + * we successfully shutdown the stack, so decrement * to make the count zero. */ dev_p->mtp_count--; diff --git a/drivers/staging/westbridge/astoria/api/src/cyasstorage.c b/drivers/staging/westbridge/astoria/api/src/cyasstorage.c index 2451404b88d4..7abd6a35e828 100644 --- a/drivers/staging/westbridge/astoria/api/src/cyasstorage.c +++ b/drivers/staging/westbridge/astoria/api/src/cyasstorage.c @@ -1773,7 +1773,7 @@ cy_as_storage_async_oper(cy_as_device *dev_p, cy_as_end_point_number_t ep, if (unit > 255) return CY_AS_ERROR_NO_SUCH_UNIT; - /* We are supposed to return sucess if the number of + /* We are supposed to return success if the number of * blocks is zero */ if (num_blocks == 0) { @@ -1969,7 +1969,7 @@ cy_as_storage_sync_oper(cy_as_device *dev_p, if (cy_as_device_is_usb_async_pending(dev_p, 6)) return CY_AS_ERROR_ASYNC_PENDING; - /* We are supposed to return sucess if the number of + /* We are supposed to return success if the number of * blocks is zero */ if (num_blocks == 0) @@ -3285,7 +3285,7 @@ cy_as_sdio_extended_i_o_async( if (callback == 0) return CY_AS_ERROR_NULL_CALLBACK; - /* We are supposed to return sucess if the number of + /* We are supposed to return success if the number of * blocks is zero */ if (((misc_buf&CY_SDIO_BLOCKMODE) != 0) && (argument == 0)) { diff --git a/drivers/staging/westbridge/astoria/api/src/cyasusb.c b/drivers/staging/westbridge/astoria/api/src/cyasusb.c index 92ea42503bf3..1b55e611191e 100644 --- a/drivers/staging/westbridge/astoria/api/src/cyasusb.c +++ b/drivers/staging/westbridge/astoria/api/src/cyasusb.c @@ -739,7 +739,7 @@ cy_as_usb_start(cy_as_device_handle handle, cy_as_usb_reset_e_p0_state(dev_p); /* - * we register here becuase the start request may cause + * we register here because the start request may cause * events to occur before the response to the start request. */ cy_as_ll_register_request_callback(dev_p, @@ -867,7 +867,7 @@ my_handle_response_usb_stop(cy_as_device *dev_p, goto destroy; /* - * we sucessfully shutdown the stack, so + * we successfully shutdown the stack, so * decrement to make the count zero. */ cy_as_usb_cleanup(dev_p); diff --git a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c index 21cdb0637beb..3bcedce13f4a 100644 --- a/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c +++ b/drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c @@ -87,7 +87,7 @@ /* - * For performance reasons, we handle storage endpoint transfers upto 4 KB + * For performance reasons, we handle storage endpoint transfers up to 4 KB * within the HAL itself. */ #define CYASSTORAGE_WRITE_EP_NUM (4) @@ -108,12 +108,12 @@ ((ep) == 6) || ((ep) == 8)) /* - * persistant, stores current GPMC interface cfg mode + * persistent, stores current GPMC interface cfg mode */ static uint8_t pnand_16bit; /* - * keep processing new WB DRQ in ISR untill all handled (performance feature) + * keep processing new WB DRQ in ISR until all handled (performance feature) */ #define PROCESS_MULTIPLE_DRQ_IN_ISR (1) @@ -157,7 +157,7 @@ typedef struct cy_as_hal_endpoint_dma { * dma_xfer_sz - size of the next dma xfer on P port * seg_xfer_cnt - counts xfered bytes for in current sg_list * memory segment - * req_xfer_cnt - total number of bytes transfered so far in + * req_xfer_cnt - total number of bytes transferred so far in * current request * req_length - total request length */ @@ -2160,7 +2160,7 @@ void cy_as_hal_mem_set(void *ptr, uint8_t value, uint32_t cnt) /* * This function is expected to create a sleep channel. * The data structure that represents the sleep channel object - * sleep channel (which is Linux "wait_queue_head_t wq" for this paticular HAL) + * sleep channel (which is Linux "wait_queue_head_t wq" for this particular HAL) * passed as a pointer, and allpocated by the caller * (typically as a local var on the stack) "Create" word should read as * "SleepOn", this func doesn't actually create anything @@ -2364,7 +2364,7 @@ int start_o_m_a_p_kernel(const char *pgm, */ cy_as_hal_gpmc_enable_16bit_bus(cy_true); #else - /* Astoria and GPMC are already in 8 bit mode, jsut initialize PNAND_CFG */ + /* Astoria and GPMC are already in 8 bit mode, just initialize PNAND_CFG */ ast_p_nand_casdi_write(CY_AS_MEM_PNAND_CFG, 0x0000); #endif diff --git a/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyashalomap_kernel.h b/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyashalomap_kernel.h index 80dd530bc4fd..6426ea61f3d4 100644 --- a/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyashalomap_kernel.h +++ b/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyashalomap_kernel.h @@ -20,7 +20,7 @@ */ /* - * This file contains the defintion of the hardware abstraction + * This file contains the definition of the hardware abstraction * layer on OMAP3430 talking to the West Bridge Astoria device */ diff --git a/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyasmemmap.h b/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyasmemmap.h index 3eee192ffe89..46f06ee29357 100644 --- a/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyasmemmap.h +++ b/drivers/staging/westbridge/astoria/arch/arm/plat-omap/include/mach/westbridge/westbridge-omap3-pnand-hal/cyasmemmap.h @@ -51,7 +51,7 @@ * GPMC_ADDR * [A8:A1]->upD[7:0] * INT# -GPMC_nWP_GPIO_62 - * DACK -N/C not conected + * DACK -N/C not connected * WAKEUP-GPIO_167 * RESET-GPIO_126 * R/B -GPMC_WAIT2_GPIO_64 @@ -108,7 +108,7 @@ * will be monitored * PF_EN_ENGINE - 1- ENABLES ENGINE, but it needs to be started after * that C ctrl reg bit 0 - * PF_FIFO_THRESHOLD - FIFO threshhold in number of BUS(8 or 16) words + * PF_FIFO_THRESHOLD - FIFO threshold in number of BUS(8 or 16) words * PF_WEIGHTED_PRIO - NUM of cycles granted to PFE if RND_ROBIN * prioritization is enabled * PF_ROUND_ROBIN - if enabled, gives priority to other CS, but diff --git a/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c b/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c index 0bbb8a3e191d..d1996a27515e 100644 --- a/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c +++ b/drivers/staging/westbridge/astoria/block/cyasblkdev_queue.c @@ -222,7 +222,7 @@ static int cyasblkdev_queue_thread(void *d) continue; } - /* new req recieved, issue it to the driver */ + /* new req received, issue it to the driver */ set_current_state(TASK_RUNNING); #ifndef WESTBRIDGE_NDEBUG diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdevice.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdevice.h index 0c0726b678ad..6452a9070091 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdevice.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdevice.h @@ -119,7 +119,7 @@ #define CY_AS_REQUEST_LIST_STATE_QUEUED (0x00) /* The request is sent, waiting for response */ #define CY_AS_REQUEST_LIST_STATE_WAITING (0x01) -/* The response has been received, processing reponse */ +/* The response has been received, processing response */ #define CY_AS_REQUEST_LIST_STATE_RECEIVED (0x02) /* The request/response is being canceled */ #define CY_AS_REQUEST_LIST_STATE_CANCELING (0x03) @@ -517,7 +517,7 @@ typedef struct cy_as_context { cy_as_ll_request_list_node *request_queue_p; /* The list node in the request queue */ cy_as_ll_request_list_node *last_node_p; - /* Index upto which data is stored. */ + /* Index up to which data is stored. */ uint16_t queue_index; /* Index to the next request in the queue. */ uint16_t rqt_index; @@ -768,7 +768,7 @@ struct cy_as_device { uint32_t mtp_count; /* The MTP event callback supplied by the client */ cy_as_mtp_event_callback mtp_event_cb; - /* The current block table to be transfered */ + /* The current block table to be transferred */ cy_as_mtp_block_table *tp_blk_tbl; cy_as_c_b_queue *func_cbs_mtp; diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdma.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdma.h index 8dab5e900149..16dc9f96018c 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdma.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasdma.h @@ -108,7 +108,7 @@ typedef enum cy_as_dma_direction { completes a requested DMA operation. Returns - CY_AS_ERROR_SUCCESS - the module initialized sucessfully + CY_AS_ERROR_SUCCESS - the module initialized successfully CY_AS_ERROR_OUT_OF_MEMORY - memory allocation failed during initialization CY_AS_ERROR_ALREADY_RUNNING - the DMA module was already running @@ -131,7 +131,7 @@ cy_as_dma_start( then freeing the resources associated with each DMA endpoint. Returns - CY_AS_ERROR_SUCCESS - the module shutdown sucessfully + CY_AS_ERROR_SUCCESS - the module shutdown successfully CY_AS_ERROR_NOT_RUNNING - the DMA module was not running See Also @@ -161,7 +161,7 @@ cy_as_dma_stop( Returns CY_AS_ERROR_SUCCESS - the traffic on the endpoint is canceled - sucessfully + successfully See Also */ @@ -266,7 +266,7 @@ cy_as_dma_queue_request( will have to maintain a list of sleep channels to wake. Returns - * CY_AS_ERROR_SUCCESS - the queue has drained sucessfully + * CY_AS_ERROR_SUCCESS - the queue has drained successfully * CY_AS_ERROR_INVALID_ENDPOINT - the endpoint given is not valid * CY_AS_ERROR_NESTED_SLEEP - CyAsDmaQueueRequest() was requested * on an endpoint where CyAsDmaQueueRequest was already called @@ -295,7 +295,7 @@ cy_as_dma_drain_queue( CyAsHalDmaSetupRead() functoins. Returns - * CY_AS_ERROR_SUCCESS - the value was set sucessfully + * CY_AS_ERROR_SUCCESS - the value was set successfully * CY_AS_ERROR_INVALID_SIZE - the size value was not valid */ extern cy_as_return_status_t diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyaserr.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyaserr.h index f78d60270d45..2cd0af1ed781 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyaserr.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyaserr.h @@ -29,7 +29,7 @@ */ /* Summary - The function completed sucessfully + The function completed successfully */ #define CY_AS_ERROR_SUCCESS (0) @@ -796,7 +796,7 @@ Description This error is returned when an operation is attempted that cannot be completed while the USB stack is connected to a USB host. In order - to sucessfully complete the desired operation, CyAsUsbDisconnect() + to successfully complete the desired operation, CyAsUsbDisconnect() must be called to disconnect from the host. */ #define CY_AS_ERROR_USB_CONNECTED (53) diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyashaldoc.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyashaldoc.h index 28136ad75115..5bcbe9bf2f5d 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyashaldoc.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyashaldoc.h @@ -597,7 +597,7 @@ cy_as_mem_set( CyAsHalSleepChannel. Returns - CyTrue is the initialization was sucessful, and CyFalse otherwise + CyTrue is the initialization was successful, and CyFalse otherwise See Also * CyAsHalSleepChannel diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasintr.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasintr.h index 3d7063ea3093..60a6fffb5d53 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasintr.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasintr.h @@ -69,7 +69,7 @@ cy_as_intr_start( Returns * CY_AS_ERROR_SUCCESS - the interrupt module was stopped - * sucessfully + * successfully * CY_AS_ERROR_NOT_RUNNING - the interrupt module was not * running diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasmisc.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasmisc.h index 2f0701850561..df7c2b66cf27 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasmisc.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasmisc.h @@ -620,7 +620,7 @@ cy_as_misc_in_standby( * Nestable: YES Returns - * CY_AS_ERROR_SUCCESS - the firmware was sucessfully downloaded + * CY_AS_ERROR_SUCCESS - the firmware was successfully downloaded * CY_AS_ERROR_INVALID_HANDLE * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device * was not configured @@ -836,7 +836,7 @@ cy_as_misc_reset( ownership. Returns - * CY_AS_ERROR_SUCCESS - the p port sucessfully acquired the + * CY_AS_ERROR_SUCCESS - the p port successfully acquired the * resource of interest * CY_AS_ERROR_INVALID_HANDLE * CY_AS_ERROR_NOT_CONFIGURED @@ -879,7 +879,7 @@ cy_as_misc_acquire_resource( * Valid In Asynchronous Callback: NO Returns - * CY_AS_ERROR_SUCCESS - the p port sucessfully released + * CY_AS_ERROR_SUCCESS - the p port successfully released * the resource of interest * CY_AS_ERROR_INVALID_HANDLE * CY_AS_ERROR_NOT_CONFIGURED @@ -929,7 +929,7 @@ cy_as_misc_release_resource( Returns * CY_AS_ERROR_SUCCESS - the trace configuration has been - * sucessfully changed + * successfully changed * CY_AS_ERROR_NO_SUCH_BUS - the bus specified does not exist * CY_AS_ERROR_NO_SUCH_DEVICE - the specified media/device * pair does not exist diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasprotocol.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasprotocol.h index 317805fc4ff4..773b645ea7eb 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasprotocol.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasprotocol.h @@ -756,7 +756,7 @@ * 1 : Debug mode Description - This reponse is sent to return the firmware version + This response is sent to return the firmware version number to the requestor. */ #define CY_RESP_FIRMWARE_VERSION (16) @@ -3655,7 +3655,7 @@ This request is sent to the West Bridge when the P port needs to send data to the Host in a Turbo Endpoint. Upon receiving this event, Firmware will make the end point - avilable for the P port. If the length is zero, then + available for the P port. If the length is zero, then firmware will send a zero length packet. Direction diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasstorage.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasstorage.h index 64f078cf202c..52b93c3e4813 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasstorage.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasstorage.h @@ -832,7 +832,7 @@ typedef struct cy_as_sdio_func { * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been * loaded into West Bridge * CY_AS_ERROR_INVALID_HANDLE - an invalid handle was passed in - * CY_AS_ERROR_SUCCESS - the module started sucessfully + * CY_AS_ERROR_SUCCESS - the module started successfully * CY_AS_ERROR_TIMEOUT - a timeout occurred communicating * with the West Bridge device * CY_AS_ERROR_OUT_OF_MEMORY @@ -882,7 +882,7 @@ cy_as_storage_start( * CY_AS_ERROR_INVALID_HANDLE - an invalid handle was * passed in * CY_AS_ERROR_SUCCESS - this module was shut - * down sucessfully + * down successfully * CY_AS_ERROR_TIMEOUT - a timeout occurred * communicating with the West Bridge device * CY_AS_ERROR_NOT_RUNNING @@ -934,7 +934,7 @@ cy_as_storage_stop( * CY_AS_ERROR_INVALID_HANDLE - an invalid handle * was passed in * CY_AS_ERROR_SUCCESS - the function was registered - * sucessfully + * successfully * CY_AS_ERROR_NOT_RUNNING - the stack is not running See Also @@ -981,7 +981,7 @@ cy_as_storage_register_callback( * been started * CY_AS_ERROR_INVALID_HANDLE - an invalid handle was * passed in - * CY_AS_ERROR_SUCCESS - this request was sucessfully + * CY_AS_ERROR_SUCCESS - this request was successfully * transmitted to the West Bridge device * CY_AS_ERROR_TIMEOUT - a timeout occurred communicating * with the West Bridge device @@ -1034,7 +1034,7 @@ cy_as_storage_claim( * been started * CY_AS_ERROR_INVALID_HANDLE - an invalid handle * was passed in - * CY_AS_ERROR_SUCCESS - the media was sucessfully + * CY_AS_ERROR_SUCCESS - the media was successfully * released * CY_AS_ERROR_MEDIA_NOT_CLAIMED - the media was not * claimed by the P port @@ -1905,7 +1905,7 @@ cy_as_storage_get_transfer_amount( differ between SD cards. A large erase can take a while to complete depending on the SD - card. In such a case it is reccomended that an async call is made. + card. In such a case it is recommended that an async call is made. Returns * CY_AS_ERROR_SUCCESS - API call completed successfully @@ -1926,7 +1926,7 @@ cy_as_storage_get_transfer_amount( * required before erase is allowed * CY_AS_ERROR_NO_SUCH_BUS * CY_AS_ERROR_NO_SUCH_DEVICE - * CY_AS_ERROR_NOT_SUPPORTED - Erase is currenly only supported + * CY_AS_ERROR_NOT_SUPPORTED - Erase is currently only supported * on SD and using SD only firmware * CY_AS_ERROR_OUT_OF_MEMORY @@ -1985,7 +1985,7 @@ cy_as_storage_erase( * type was made * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available * CY_AS_ERROR_INVALID_RESPONSE - an error message was - * recieved from the firmware + * received from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error in * reading from the media * CY_AS_ERROR_INVALID_FUNCTION - An IO attempt was made to @@ -2047,7 +2047,7 @@ cy_as_sdio_get_c_i_s_info( * pair does not exist * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available * CY_AS_ERROR_INVALID_RESPONSE - an error message was - * recieved from the firmware + * received from the firmware */ cy_as_return_status_t @@ -2095,7 +2095,7 @@ cy_as_sdio_query_card( * pair does not exist * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available * CY_AS_ERROR_INVALID_RESPONSE - an error message was - * recieved from the firmware + * received from the firmware */ cy_as_return_status_t cy_as_sdio_reset_card( @@ -2139,7 +2139,7 @@ cy_as_sdio_reset_card( * CY_AS_ERROR_NO_SUCH_DEVICE - the specified media/device pair * does not exist * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available - * CY_AS_ERROR_INVALID_RESPONSE - an error message was recieved + * CY_AS_ERROR_INVALID_RESPONSE - an error message was received * from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error in reading * from the media @@ -2198,7 +2198,7 @@ cy_as_sdio_direct_read( * CY_AS_ERROR_NO_SUCH_DEVICE - the specified media/device * pair does not exist * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available - * CY_AS_ERROR_INVALID_RESPONSE - an error message was recieved + * CY_AS_ERROR_INVALID_RESPONSE - an error message was received * from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error in * reading from the media @@ -2262,7 +2262,7 @@ cy_as_sdio_direct_write( * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory * available * CY_AS_ERROR_INVALID_RESPONSE - an error message was - * recieved from the firmware + * received from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error in * reading from the media * CY_AS_ERROR_INVALID_FUNCTION - An IO attempt was made @@ -2319,7 +2319,7 @@ cy_as_sdio_set_blocksize( * pair does not exist * CY_AS_ERROR_ASYNC_PENDING - an async operation is pending * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available - * CY_AS_ERROR_INVALID_RESPONSE - an error message was recieved + * CY_AS_ERROR_INVALID_RESPONSE - an error message was received * from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error in * reading from the media @@ -2396,7 +2396,7 @@ cy_as_sdio_extended_read( * CY_AS_ERROR_ASYNC_PENDING - an async operation is pending * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available * CY_AS_ERROR_INVALID_RESPONSE - an error message was - * recieved from the firmware + * received from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error in * reading from the media * CY_AS_ERROR_INVALID_FUNCTION - An IO attempt was made @@ -2471,7 +2471,7 @@ cy_as_sdio_extended_write( * pair does not exist * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory available * CY_AS_ERROR_INVALID_RESPONSE - an error message was - * recieved from the firmware + * received from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error in * reading from the media * CY_AS_ERROR_INVALID_FUNCTION - An IO attempt was made @@ -2714,7 +2714,7 @@ cy_as_sdio_suspend( * CY_AS_ERROR_OUT_OF_MEMORY - insufficient memory * available * CY_AS_ERROR_INVALID_RESPONSE - an error message was - * recieved from the firmware + * received from the firmware * CY_AS_ERROR_MEDIA_ACCESS_FAILURE - there was error * in reading from the media * CY_AS_ERROR_INVALID_FUNCTION - An IO attempt was diff --git a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasusb.h b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasusb.h index 4a549e146812..e3ba9ca4c75f 100644 --- a/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasusb.h +++ b/drivers/staging/westbridge/astoria/include/linux/westbridge/cyasusb.h @@ -464,7 +464,7 @@ typedef struct cy_as_usb_end_point_config { be selected on a partitioned storage device. Description - West Bridge firmware supports creating upto two + West Bridge firmware supports creating up to two partitions on mass storage devices connected to West Bridge. When there are two partitions on a device, the user can choose which of these partitions should be @@ -698,7 +698,7 @@ cy_as_usb_start( * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded * into West Bridge - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_TIMEOUT - a timeout occurred communicating with * the West Bridge device @@ -752,7 +752,7 @@ cy_as_usb_register_callback( * Nestable: YES Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -791,7 +791,7 @@ cy_as_usb_connect( * Nestable: YES Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -825,7 +825,7 @@ cy_as_usb_disconnect( * Valid In Asynchronous Callback: Yes (if cb supplied) Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -855,13 +855,13 @@ cy_as_usb_set_enum_config( the USB stack Description - This function sends a request to West Bridge to retreive + This function sends a request to West Bridge to retrieve the current configuration * Valid In Asynchronous Callback: Yes (if cb supplied) Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -906,7 +906,7 @@ cy_as_usb_get_enum_config( Chapter 9. Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -993,7 +993,7 @@ cy_as_usb_clear_descriptors( Description This data structure the buffer to hold the descriptor data, and an in/out parameter ti indicate the - lenght of the buffer and descriptor data in bytes. + length of the buffer and descriptor data in bytes. See Also * CyAsUsbGetDescriptor @@ -1027,7 +1027,7 @@ typedef struct cy_as_get_descriptor_data { Chapter 9. Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -1106,7 +1106,7 @@ cy_as_usb_get_descriptor( * Valid In Asynchronous Callback: NO Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -1140,7 +1140,7 @@ cy_as_usb_set_physical_configuration( Add documentation about endpoint configuration limitations Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -1181,7 +1181,7 @@ cy_as_usb_set_end_point_config( * Valid In Asynchronous Callback: NO Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_NOT_CONFIGURED - the West Bridge device has not * been configured * CY_AS_ERROR_NO_FIRMWARE - the firmware has not been loaded @@ -1219,7 +1219,7 @@ cy_as_usb_get_end_point_config( functions store away the configuration information and this CyAsUsbCommitConfig() actually finds the best hardware configuration based on the requested endpoint - configuration and sends thsi optimal + configuration and sends this optimal confiuration down to the West Bridge device. * Valid In Asynchronous Callback: YES (if cb supplied) @@ -1268,7 +1268,7 @@ cy_as_usb_commit_config( * Valid In Asynchronous Callback: NO Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_TIMEOUT - a timeout occurred communicating with * the West Bridge device * CY_AS_ERROR_NOT_RUNNING - the USB stack is not running @@ -1311,7 +1311,7 @@ cy_as_usb_read_data( * Valid In Asynchronous Callback: YES Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_TIMEOUT - a timeout occurred communicating with * the West Bridge device * CY_AS_ERROR_NOT_RUNNING - the USB stack is not running @@ -1355,7 +1355,7 @@ cy_as_usb_read_data_async( a zero length packet transmitted to the USB host. Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_TIMEOUT - a timeout occurred communicating with * the West Bridge device * CY_AS_ERROR_NOT_RUNNING - the USB stack is not running @@ -1395,7 +1395,7 @@ cy_as_usb_write_data( in a zero length packet transmitted to the USB host. Returns - * CY_AS_ERROR_SUCCESS - this module was shut down sucessfully + * CY_AS_ERROR_SUCCESS - this module was shut down successfully * CY_AS_ERROR_TIMEOUT - a timeout occurred communicating with * the West Bridge device * CY_AS_ERROR_NOT_RUNNING - the USB stack is not running @@ -1435,7 +1435,7 @@ cy_as_usb_write_data_async( Returns * CY_AS_ERROR_SUCCESS - this module was shut down - * sucessfully + * successfully * CY_AS_ERROR_NOT_RUNNING - the USB stack is not * running * CY_AS_ERROR_ASYNC_NOT_PENDING - no asynchronous USB @@ -1791,7 +1791,7 @@ cy_as_usb_set_m_s_report_threshold( device should be made visible to USB. Description - West Bridge firmware supports the creation of upto two + West Bridge firmware supports the creation of up to two partitions on mass storage devices connected to the West Bridge device. When there are two partitions on a device, the user can choose which of these partitions should be made visible to the diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index 9cfea94bcea5..c9f0e8f856a0 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -492,7 +492,7 @@ Mds_Tx(struct wbsoft_priv *adapter) TxDesIndex = pMds->TxDesIndex; /* Get the current ID */ pTxDes->Descriptor_ID = TxDesIndex; - pMds->TxDesFrom[TxDesIndex] = 2; /* Storing the information of source comming from */ + pMds->TxDesFrom[TxDesIndex] = 2; /* Storing the information of source coming from */ pMds->TxDesIndex++; pMds->TxDesIndex %= MAX_USB_TX_DESCRIPTOR; diff --git a/drivers/staging/wlags49_h2/README.ubuntu b/drivers/staging/wlags49_h2/README.ubuntu index 47beaec86e4a..edee8b9385be 100644 --- a/drivers/staging/wlags49_h2/README.ubuntu +++ b/drivers/staging/wlags49_h2/README.ubuntu @@ -116,7 +116,7 @@ LICENSE The Agere Systems license applies. This is why I include the original README.wlags49. The instructions in that file are bogus now. I also -include the man page. Eventhough setting parameters on the module +include the man page. Even though setting parameters on the module does not work anymore but it provides some information about all the settings. diff --git a/drivers/staging/wlags49_h2/TODO b/drivers/staging/wlags49_h2/TODO index 14aa415b1a82..94032b6ac2b5 100644 --- a/drivers/staging/wlags49_h2/TODO +++ b/drivers/staging/wlags49_h2/TODO @@ -1,7 +1,7 @@ First of all, the best thing would be that this driver becomes obsolte by adding support for Hermes II and Hermes II.5 cards to the existing orinoco driver. The orinoco driver currently only supports Hermes I based cards. -Since this will not happen by magic and has not happend until now this +Since this will not happen by magic and has not happened until now this driver provides a stop-gap solution for these type of cards. Having said that, the following wishlist comes to mind to make the driver @@ -18,7 +18,7 @@ TODO: - the driver is split into a Hermes II and a Hermes II.5 part, it would be nice to handle both with one module instead of two - review by the wireless developer community - - verify the code against the coding standards for a propper linux + - verify the code against the coding standards for a proper linux driver - resolve license issues (?) diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c index d4bdd3ee8be1..a73317ef9350 100644 --- a/drivers/staging/wlags49_h2/hcf.c +++ b/drivers/staging/wlags49_h2/hcf.c @@ -540,7 +540,7 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = { * *.CONDITIONS * Except for hcf_action with HCF_ACT_INT_FORCE_ON or HCF_ACT_INT_OFF as parameter or hcf_connect with an I/O -* address (i.e. not HCF_DISCONNECT), all hcf-function calls MUST be preceeded by a call of hcf_action with +* address (i.e. not HCF_DISCONNECT), all hcf-function calls MUST be preceded by a call of hcf_action with * HCF_ACT_INT_OFF as parameter. * Note that hcf_connect defaults to NIC interrupt disabled mode, i.e. as if hcf_action( HCF_ACT_INT_OFF ) * was called. @@ -843,7 +843,7 @@ hcf_16 i; *.MODULE int hcf_cntl( IFBP ifbp, hcf_16 cmd ) *.PURPOSE Connect or disconnect a specific port to a specific network. *!! ;???????????????? continue needs more explanation -* recovers by means of "continue" when the connect proces in CCX mode fails +* recovers by means of "continue" when the connect process in CCX mode fails * Enables or disables data transmission and reception for the NIC. * Activates static NIC configuration for a specific port at connect. * Activates static configuration for all ports at enable. @@ -1170,12 +1170,12 @@ LTV_STRCT x; io_addr = io_base; } -#if 0 //;? if a subsequent hcf_connect is preceeded by an hcf_disconnect the wakeup is not needed !! +#if 0 //;? if a subsequent hcf_connect is preceded by an hcf_disconnect the wakeup is not needed !! #if HCF_SLEEP OUT_PORT_WORD( .....+HREG_IO, HREG_IO_WAKEUP_ASYNC ); //OPW not yet useable MSF_WAIT(800); // MSF-defined function to wait n microseconds. note that MSF_WAIT uses not yet defined!!!! IFB_IOBase and IFB_TickIni (via PROT_CNT_INI) - so be carefull if this code is restored + so be careful if this code is restored #endif // HCF_SLEEP #endif // 0 @@ -1563,7 +1563,7 @@ DESC_STRCT *p = descp->next_desc_addr; //pointer to 2nd descriptor of frame * This function is called by the MSF to supply the HCF with new/more buffers for receive purposes. * The HCF can be used in 2 fashions: with and without encapsulation for data transfer. * This is controlled at compile time by the HCF_ENC bit of the HCF_ENCAP system constant. -* As a consequence, some additional constaints apply to the number of descriptor and the buffers associated +* As a consequence, some additional constraints apply to the number of descriptor and the buffers associated * with the first 2 descriptors. Independent of the encapsulation feature, the COUNT fields are ignored. * A special case is the supplying of the DELWA descriptor, which must be supplied as the first descriptor. * @@ -1735,7 +1735,7 @@ DESC_STRCT *descp; // pointer to start of FrameList * - in case encapsulation by the HCF is selected: * - The FrameList does not consists of at least 2 Descriptors. * - The first databuffer does not contain exactly the (space for) the 802.11 header (== 28 words) -* - The first databuffer does not have a size to additionally accomodate the 802.3 header and the +* - The first databuffer does not have a size to additionally accommodate the 802.3 header and the * SNAP header of the frame after encapsulation (== 39 words). * - The second databuffer does not contain at least DA, SA and 'type/length' (==14 bytes or 7 words) *!! The 2nd part of the list of asserts should be kept in sync with put_frame_lst, in order to get @@ -1762,14 +1762,14 @@ DESC_STRCT *descp; // pointer to start of FrameList * - Copy DA/SA fields from the 2nd buffer * - Calculate total length of the message (snap-header + type-field + the length of all buffer fragments * associated with the 802.3 frame (i.e all descriptors except the first), but not the DestinationAddress, -* SourceAddress and lenght-field) +* SourceAddress and length-field) * Assert the message length * Write length. Note that the message is in BE format, hence on LE platforms the length must be converted * ;? THIS IS NOT WHAT CURRENTLY IS IMPLEMENTED * - Write snap header. Note that the last byte of the snap header is NOT copied, that byte is already in * place as result of the call to hcf_encap. * Note that there are many ways to skin a cat. To express the offsets in the 1st buffer while writing -* the snap header, HFS_TYPE is choosen as a reference point to make it easier to grasp that the snap header +* the snap header, HFS_TYPE is chosen as a reference point to make it easier to grasp that the snap header * and encapsualtion type are at least relative in the right. *8: modify 1st descriptor to reflect moved part of the 802.3 header + Snap-header * modify 2nd descriptor to skip the moved part of the 802.3 header (DA/SA @@ -1933,7 +1933,7 @@ hcf_16 t = (hcf_16)(*type<<8) + *(type+1); /* 2 */ * HCF_SUCCESS Success *!! via cmd_exe ( type >= CFG_RID_FW_MIN ) * HCF_ERR_NO_NIC NIC removed during retrieval -* HCF_ERR_TIME_OUT Expected Hermes event did not occure in expected time +* HCF_ERR_TIME_OUT Expected Hermes event did not occur in expected time *!! via cmd_exe and setup_bap (type >= CFG_RID_FW_MIN ) * HCF_ERR_DEFUNCT_... HCF is in defunct mode (bits 0x7F reflect cause) * @@ -2958,7 +2958,7 @@ or * hcf_service_nic is also skipped in those cases. * To prevent that hcf_service_nic reports bogus information to the MSF with all - possibly difficult to * debug - undesirable side effects, it is paramount to check the NIC presence. In former days the presence -* test was based on the Hermes register HREG_SW_0. Since in HCF_ACT_INT_OFF is choosen for strategy based on +* test was based on the Hermes register HREG_SW_0. Since in HCF_ACT_INT_OFF is chosen for strategy based on * HREG_EV_STAT, this is now also used in hcf_service_nic. The motivation to change strategy is partly * due to inconsistent F/W implementations with respect to HREG_SW_0 manipulation around reset and download. * Note that in polled environments Card Removal is not detected by INT_OFF which makes the check in @@ -4048,7 +4048,7 @@ hcf_32 FAR *p4; //prevent side effects from macro HCFASSERT( word_len == 0 || word_len == 2 || word_len == 4, word_len ) HCFASSERT( word_len == 0 || ((hcf_32)bufp & 1 ) == 0, (hcf_32)bufp ) HCFASSERT( word_len <= len, MERGE2( word_len, len ) ) - //see put_frag for an alternative implementation, but be carefull about what are int's and what are + //see put_frag for an alternative implementation, but be careful about what are int's and what are //hcf_16's if ( word_len ) { //. if there is anything to convert hcf_8 c; @@ -4712,7 +4712,7 @@ int rc = HCF_SUCCESS; * Note that len is unsigned, so even MSF I/F violation works out O.K. * The '2' in the expression "len+2" is used because 1 word is needed for L itself and 1 word is needed * for the zero-sentinel -*8: update MailBox Info length report to MSF with "oldest" MB Info Block size. Be carefull here, if you get +*8: update MailBox Info length report to MSF with "oldest" MB Info Block size. Be careful here, if you get * here before the MailBox is registered, you can't read from the buffer addressed by IFB_MBp (it is the * Null buffer) so don't move this code till the end of this routine but keep it where there is garuanteed * a buffer. diff --git a/drivers/staging/wlags49_h2/hcfdef.h b/drivers/staging/wlags49_h2/hcfdef.h index 4e20171b7829..cb1966d8473f 100644 --- a/drivers/staging/wlags49_h2/hcfdef.h +++ b/drivers/staging/wlags49_h2/hcfdef.h @@ -315,7 +315,7 @@ err: these values should match; #if HCF_DMA //************************* DMA (bus mastering) - // Be carefull to use these registers only at a genuine 32 bits NIC + // Be careful to use these registers only at a genuine 32 bits NIC // On 16 bits NICs, these addresses are mapped into the range 0x00 through 0x3F with all consequences // thereof, e.g. HREG_DMA_CTRL register maps to HREG_CMD. #define HREG_DMA_CTRL 0x0040 diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c index 9e5da0815371..522a31090c58 100644 --- a/drivers/staging/wlags49_h2/wl_wext.c +++ b/drivers/staging/wlags49_h2/wl_wext.c @@ -2575,7 +2575,7 @@ static int wireless_set_scan(struct net_device *dev, struct iw_request_info *inf * This looks like a nice place to test if the HCF is still * communicating with the card. It seems that sometimes BAP_1 * gets corrupted. By looking at the comments in HCF the - * cause is still a mistery. Okay, the communication to the + * cause is still a mystery. Okay, the communication to the * card is dead, reset the card to revive. */ if((lp->hcfCtx.IFB_CardStat & CARD_STAT_DEFUNCT) != 0) @@ -3924,7 +3924,7 @@ void wl_wext_event_mic_failed( struct net_device *dev ) memset( msg, 0, sizeof( msg )); - /* Becuase MIC failures are not part of the Wireless Extensions yet, they + /* Because MIC failures are not part of the Wireless Extensions yet, they must be passed as a string using an IWEVCUSTOM event. In order for the event to be effective, the string format must be known by both the driver and the supplicant. The following is the string format used by the @@ -3999,7 +3999,7 @@ void wl_wext_event_assoc_ie( struct net_device *dev ) memcpy( &data.rawData, &( lp->ltvRecord.u.u8[1] ), 88 ); wpa_ie = wl_parse_wpa_ie( &data, &length ); - /* Becuase this event (Association WPA-IE) is not part of the Wireless + /* Because this event (Association WPA-IE) is not part of the Wireless Extensions yet, it must be passed as a string using an IWEVCUSTOM event. In order for the event to be effective, the string format must be known by both the driver and the supplicant. The following is the string format diff --git a/drivers/staging/wlags49_h25/TODO b/drivers/staging/wlags49_h25/TODO index 14aa415b1a82..94032b6ac2b5 100644 --- a/drivers/staging/wlags49_h25/TODO +++ b/drivers/staging/wlags49_h25/TODO @@ -1,7 +1,7 @@ First of all, the best thing would be that this driver becomes obsolte by adding support for Hermes II and Hermes II.5 cards to the existing orinoco driver. The orinoco driver currently only supports Hermes I based cards. -Since this will not happen by magic and has not happend until now this +Since this will not happen by magic and has not happened until now this driver provides a stop-gap solution for these type of cards. Having said that, the following wishlist comes to mind to make the driver @@ -18,7 +18,7 @@ TODO: - the driver is split into a Hermes II and a Hermes II.5 part, it would be nice to handle both with one module instead of two - review by the wireless developer community - - verify the code against the coding standards for a propper linux + - verify the code against the coding standards for a proper linux driver - resolve license issues (?) diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c index ed751f418db9..21f25a21c291 100644 --- a/drivers/staging/wlan-ng/prism2sta.c +++ b/drivers/staging/wlan-ng/prism2sta.c @@ -1976,7 +1976,7 @@ static wlandevice_t *create_wlan(void) wlandev->nsdcaps = P80211_NSDCAP_HWFRAGMENT | P80211_NSDCAP_AUTOJOIN; - /* Initialize the device private data stucture. */ + /* Initialize the device private data structure. */ hw->dot11_desired_bss_type = 1; return wlandev; diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c index 8762a5327693..9669c22cc82c 100644 --- a/drivers/staging/xgifb/vb_setmode.c +++ b/drivers/staging/xgifb/vb_setmode.c @@ -7834,7 +7834,7 @@ unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE, == 600)) { index++; } - /* Alan 10/19/2007; do the similiar adjustment like XGISearchCRT1Rate() */ + /* Alan 10/19/2007; do the similar adjustment like XGISearchCRT1Rate() */ if ((pVBInfo->RefIndex[RefreshRateTableIndex].XRes == 1024) && (pVBInfo->RefIndex[RefreshRateTableIndex].YRes == 768)) { diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h index 4b87951f4322..d613e84aab62 100644 --- a/drivers/staging/xgifb/vgatypes.h +++ b/drivers/staging/xgifb/vgatypes.h @@ -85,7 +85,7 @@ struct xgi_hw_device_info unsigned long *); }; -/* Addtional IOCTL for communication xgifb <> X driver */ +/* Additional IOCTL for communication xgifb <> X driver */ /* If changing this, xgifb.h must also be changed (for xgifb) */ diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 2c5fcfed5934..30cbb743d9ba 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -496,8 +496,8 @@ static int core_alua_state_check( nonop_delay_msecs = tg_pt_gp->tg_pt_gp_nonop_delay_msecs; spin_unlock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); /* - * Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a seperate conditional - * statement so the complier knows explictly to check this case first. + * Process ALUA_ACCESS_STATE_ACTIVE_OPTMIZED in a separate conditional + * statement so the compiler knows explicitly to check this case first. * For the Optimized ALUA access state case, we want to process the * incoming fabric cmd ASAP.. */ @@ -1157,7 +1157,7 @@ void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp) spin_unlock(&lu_gp->lu_gp_lock); /* * - * lu_gp_mem is assoicated with a single + * lu_gp_mem is associated with a single * struct se_device->dev_alua_lu_gp_mem, and is released when * struct se_device is released via core_alua_free_lu_gp_mem(). * @@ -1429,7 +1429,7 @@ void core_alua_free_tg_pt_gp( } spin_unlock(&tg_pt_gp->tg_pt_gp_lock); /* - * tg_pt_gp_mem is assoicated with a single + * tg_pt_gp_mem is associated with a single * se_port->sep_alua_tg_pt_gp_mem, and is released via * core_alua_free_tg_pt_gp_mem(). * @@ -1963,7 +1963,7 @@ int core_setup_alua(struct se_device *dev, int force_pt) printk(KERN_INFO "%s: Enabling ALUA Emulation for SPC-3" " device\n", TRANSPORT(dev)->name); /* - * Assoicate this struct se_device with the default ALUA + * Associate this struct se_device with the default ALUA * LUN Group. */ lu_gp_mem = core_alua_allocate_lu_gp_mem(dev); diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 3fb8e32506ed..d25e20829012 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -371,7 +371,7 @@ int core_update_device_list_for_node( if (!(enable)) { /* * deve->se_lun_acl will be NULL for demo-mode created LUNs - * that have not been explictly concerted to MappedLUNs -> + * that have not been explicitly concerted to MappedLUNs -> * struct se_lun_acl, but we remove deve->alua_port_list from * port->sep_alua_list. This also means that active UAs and * NodeACL context specific PR metadata for demo-mode diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index d57ad672677f..1e193f324895 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -433,7 +433,7 @@ char *iscsi_parse_pr_out_transport_id( /* * Go ahead and do the lower case conversion of the received * 12 ASCII characters representing the ISID in the TransportID - * for comparision against the running iSCSI session's ISID from + * for comparison against the running iSCSI session's ISID from * iscsi_target.c:lio_sess_get_initiator_sid() */ for (i = 0; i < 12; i++) { diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 02f553aef43d..150c4305f385 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -159,7 +159,7 @@ static struct se_device *fd_create_virtdevice( #endif /* flags |= O_DIRECT; */ /* - * If fd_buffered_io=1 has not been set explictly (the default), + * If fd_buffered_io=1 has not been set explicitly (the default), * use O_SYNC to force FILEIO writes to disk. */ if (!(fd_dev->fbd_flags & FDBD_USE_BUFFERED_IO)) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 2521f75362c3..a79f518ca6e2 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -478,7 +478,7 @@ static int core_scsi3_pr_seq_non_holder( break; } /* - * Case where the CDB is explictly allowed in the above switch + * Case where the CDB is explicitly allowed in the above switch * statement. */ if (!(ret) && !(other_cdb)) { @@ -3735,7 +3735,7 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) return PYX_TRANSPORT_LU_COMM_FAILURE; if (cmd->data_length < 24) { - printk(KERN_WARNING "SPC-PR: Recieved PR OUT parameter list" + printk(KERN_WARNING "SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); return PYX_TRANSPORT_INVALID_PARAMETER_LIST; } @@ -3778,7 +3778,7 @@ static int core_scsi3_emulate_pr_out(struct se_cmd *cmd, unsigned char *cdb) */ if (!(spec_i_pt) && ((cdb[1] & 0x1f) != PRO_REGISTER_AND_MOVE) && (cmd->data_length != 24)) { - printk(KERN_WARNING "SPC-PR: Recieved PR OUT illegal parameter" + printk(KERN_WARNING "SPC-PR: Received PR OUT illegal parameter" " list length: %u\n", cmd->data_length); return PYX_TRANSPORT_INVALID_PARAMETER_LIST; } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index bf6aa8a9f1d8..9583b23c9c84 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -719,7 +719,7 @@ static int transport_cmd_check_stop( cmd->se_lun = NULL; /* * Some fabric modules like tcm_loop can release - * their internally allocated I/O refrence now and + * their internally allocated I/O reference now and * struct se_cmd now. */ if (CMD_TFO(cmd)->check_stop_free != NULL) { @@ -2029,7 +2029,7 @@ int transport_generic_handle_data( * If the received CDB has aleady been ABORTED by the generic * target engine, we now call transport_check_aborted_status() * to queue any delated TASK_ABORTED status for the received CDB to the - * fabric module as we are expecting no futher incoming DATA OUT + * fabric module as we are expecting no further incoming DATA OUT * sequences at this point. */ if (transport_check_aborted_status(cmd, 1) != 0) @@ -2501,7 +2501,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd) if (SE_DEV(cmd)->dev_task_attr_type != SAM_TASK_ATTR_EMULATED) return 1; /* - * Check for the existance of HEAD_OF_QUEUE, and if true return 1 + * Check for the existence of HEAD_OF_QUEUE, and if true return 1 * to allow the passed struct se_cmd list of tasks to the front of the list. */ if (cmd->sam_task_attr == TASK_ATTR_HOQ) { @@ -2547,7 +2547,7 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd) if (atomic_read(&SE_DEV(cmd)->dev_ordered_sync) != 0) { /* * Otherwise, add cmd w/ tasks to delayed cmd queue that - * will be drained upon competion of HEAD_OF_QUEUE task. + * will be drained upon completion of HEAD_OF_QUEUE task. */ spin_lock(&SE_DEV(cmd)->delayed_cmd_lock); cmd->se_cmd_flags |= SCF_DELAYED_CMD_FROM_SAM_ATTR; @@ -2589,7 +2589,7 @@ static int transport_execute_tasks(struct se_cmd *cmd) } /* * Call transport_cmd_check_stop() to see if a fabric exception - * has occured that prevents execution. + * has occurred that prevents execution. */ if (!(transport_cmd_check_stop(cmd, 0, TRANSPORT_PROCESSING))) { /* @@ -3109,7 +3109,7 @@ static int transport_generic_cmd_sequencer( if (ret != 0) { cmd->transport_wait_for_tasks = &transport_nop_wait_for_tasks; /* - * Set SCSI additional sense code (ASC) to 'LUN Not Accessable'; + * Set SCSI additional sense code (ASC) to 'LUN Not Accessible'; * The ALUA additional sense code qualifier (ASCQ) is determined * by the ALUA primary or secondary access state.. */ @@ -3867,7 +3867,7 @@ static void transport_generic_complete_ok(struct se_cmd *cmd) } } /* - * Check for a callback, used by amoungst other things + * Check for a callback, used by amongst other things * XDWRITE_READ_10 emulation. */ if (cmd->transport_complete_callback) diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index a2ef346087e8..df355176a377 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c @@ -247,7 +247,7 @@ void core_scsi3_ua_for_check_condition( } /* * Otherwise for the default 00b, release the UNIT ATTENTION - * condition. Return the ASC/ASCQ of the higest priority UA + * condition. Return the ASC/ASCQ of the highest priority UA * (head of the list) in the outgoing CHECK_CONDITION + sense. */ if (head) { @@ -304,7 +304,7 @@ int core_scsi3_ua_clear_for_request_sense( * matching struct se_lun. * * Once the returning ASC/ASCQ values are set, we go ahead and - * release all of the Unit Attention conditions for the assoicated + * release all of the Unit Attention conditions for the associated * struct se_lun. */ spin_lock(&deve->ua_lock); diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index b00101972f20..d5f923bcdffe 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -169,7 +169,7 @@ * Added support for Linux 2.4.x kernels. * * Revision 3.77 2001/01/09 04:00:52 eokerson - * Linetest will now test the line, even if it has previously succeded. + * Linetest will now test the line, even if it has previously succeeded. * * Revision 3.76 2001/01/08 19:27:00 eokerson * Fixed problem with standard cable on Internet PhoneCARD. @@ -352,7 +352,7 @@ static void ixj_fsk_alloc(IXJ *j) } else { j->fsksize = 8000; if(ixjdebug & 0x0200) { - printk("IXJ phone%d - allocate succeded\n", j->board); + printk("IXJ phone%d - allocate succeeded\n", j->board); } } } @@ -487,7 +487,7 @@ DSPbase + 8-9 Hardware Status Register Read Only A-B Hardware Control Register Read Write C-D Host Transmit (Write) Data Buffer Access Port (buffer input)Write Only -E-F Host Recieve (Read) Data Buffer Access Port (buffer input) Read Only +E-F Host Receive (Read) Data Buffer Access Port (buffer input) Read Only ************************************************************************/ static inline void ixj_read_HSR(IXJ *j) @@ -4195,7 +4195,7 @@ static void ixj_aec_start(IXJ *j, int level) ixj_WriteDSPCommand(0xE338, j); /* Set Echo Suppresser Attenuation to 0dB */ /* Now we can set the AGC initial parameters and turn it on */ - ixj_WriteDSPCommand(0xCF90, j); /* Set AGC Minumum gain */ + ixj_WriteDSPCommand(0xCF90, j); /* Set AGC Minimum gain */ ixj_WriteDSPCommand(0x0020, j); /* to 0.125 (-18dB) */ ixj_WriteDSPCommand(0xCF91, j); /* Set AGC Maximum gain */ diff --git a/drivers/telephony/ixj.h b/drivers/telephony/ixj.h index 4c32a43b7914..2c841134f61c 100644 --- a/drivers/telephony/ixj.h +++ b/drivers/telephony/ixj.h @@ -1149,7 +1149,7 @@ typedef struct { unsigned int firstring:1; /* First ring cadence is complete */ unsigned int pstncheck:1; /* Currently checking the PSTN Line */ unsigned int pstn_rmr:1; - unsigned int x:3; /* unsed bits */ + unsigned int x:3; /* unused bits */ } IXJ_FLAGS; diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index c3425bb3a1f6..b6f7d52f7c35 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -255,7 +255,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv, default: written = -EIO; } - /* remove buffer if an error has occured or received data + /* remove buffer if an error has occurred or received data * is not correct */ if (rc || (rb->mbuf->version != MSG_VERSION) || (rb->msg.length != MSG_SIZE(rb->mbuf->datalen))) @@ -620,7 +620,7 @@ static void hvc_iucv_hangup(struct hvc_iucv_private *priv) * the index of an struct hvc_iucv_private instance. * * This routine notifies the HVC back-end that a tty hangup (carrier loss, - * virtual or otherwise) has occured. + * virtual or otherwise) has occurred. * The z/VM IUCV HVC device driver ignores virtual hangups (vhangup()) * to keep an existing IUCV communication path established. * (Background: vhangup() is called from user space (by getty or login) to diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 5e2f52b33327..e6eea1485244 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -1,7 +1,7 @@ /* * vio driver interface to hvc_console.c * - * This code was moved here to allow the remaing code to be reused as a + * This code was moved here to allow the remaining code to be reused as a * generic polling mode with semi-reliable transport driver core to the * console and tty subsystems. * diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index bef238f9ffd7..4c8b66546930 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -118,7 +118,7 @@ * arch/powerepc/include/asm/hvcserver.h * * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to - * prevent possible lockup with realtime scheduling as similarily pointed out by + * prevent possible lockup with realtime scheduling as similarly pointed out by * akpm in hvc_console. Changed resulted in the removal of hvcs_final_close() * to reorder cleanup operations and prevent discarding of pending data during * an hvcs_close(). Removed spinlock protection of hvcs_struct data members in @@ -581,7 +581,7 @@ static void hvcs_try_write(struct hvcs_struct *hvcsd) /* * We are still obligated to deliver the data to the * hypervisor even if the tty has been closed because - * we commited to delivering it. But don't try to wake + * we committed to delivering it. But don't try to wake * a non-existent tty. */ if (tty) { @@ -1349,7 +1349,7 @@ static int hvcs_write(struct tty_struct *tty, spin_lock_irqsave(&hvcsd->lock, flags); /* - * Somehow an open succedded but the device was removed or the + * Somehow an open succeeded but the device was removed or the * connection terminated between the vty-server and partner vty during * the middle of a write operation? This is a crummy place to do this * but we want to keep it all in the spinlock. @@ -1420,7 +1420,7 @@ static int hvcs_write(struct tty_struct *tty, } /* - * This is really asking how much can we guarentee that we can send or that we + * This is really asking how much can we guarantee that we can send or that we * absolutely WILL BUFFER if we can't send it. This driver MUST honor the * return value, hence the reason for hvcs_struct buffering. */ diff --git a/drivers/tty/mxser.h b/drivers/tty/mxser.h index 41878a69203d..0bf794313ffd 100644 --- a/drivers/tty/mxser.h +++ b/drivers/tty/mxser.h @@ -113,7 +113,7 @@ #define MOXA_MUST_IIR_RTO 0x0C #define MOXA_MUST_IIR_LSR 0x06 -/* recieved Xon/Xoff or specical interrupt pending */ +/* received Xon/Xoff or specical interrupt pending */ #define MOXA_MUST_IIR_XSC 0x10 /* RTS/CTS change state interrupt pending */ diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 176f63256b37..47f8cdb207f1 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -74,7 +74,7 @@ module_param(debug, int, 0600); #endif /* - * Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte + * Semi-arbitrary buffer size limits. 0710 is normally run with 32-64 byte * limits so this is plenty */ #define MAX_MRU 512 @@ -82,7 +82,7 @@ module_param(debug, int, 0600); /* * Each block of data we have queued to go out is in the form of - * a gsm_msg which holds everything we need in a link layer independant + * a gsm_msg which holds everything we need in a link layer independent * format */ @@ -1193,8 +1193,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, break; /* Optional unsupported commands */ case CMD_PN: /* Parameter negotiation */ - case CMD_RPN: /* Remote port negotation */ - case CMD_SNC: /* Service negotation command */ + case CMD_RPN: /* Remote port negotiation */ + case CMD_SNC: /* Service negotiation command */ default: /* Reply to bad commands with an NSC */ buf[0] = command; @@ -2026,7 +2026,7 @@ EXPORT_SYMBOL_GPL(gsm_activate_mux); * @mux: mux to free * * Dispose of allocated resources for a dead mux. No refcounting - * at present so the mux must be truely dead. + * at present so the mux must be truly dead. */ void gsm_free_mux(struct gsm_mux *gsm) { diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index f4f11164efe5..fd0a98524d51 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1673,7 +1673,7 @@ static void ntty_hangup(struct tty_struct *tty) /* * called when the userspace process writes to the tty (/dev/noz*). - * Data is inserted into a fifo, which is then read and transfered to the modem. + * Data is inserted into a fifo, which is then read and transferred to the modem. */ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, int count) diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 3780da8ad12d..036feeb5e3f6 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -2060,7 +2060,7 @@ static __init int register_PCI(int i, struct pci_dev *dev) sClockPrescale = 0x19; rp_baud_base[i] = 230400; } else { - /* mod 4 (devide by 5) prescale */ + /* mod 4 (divide by 5) prescale */ sClockPrescale = 0x14; rp_baud_base[i] = 460800; } @@ -2183,7 +2183,7 @@ static int __init init_ISA(int i) sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ rp_baud_base[i] = 230400; } else { - sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */ + sClockPrescale = 0x14; /* mod 4 (divide by 5) prescale */ rp_baud_base[i] = 460800; } diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index b3b881bc4712..6611535f4440 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c @@ -1629,7 +1629,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) up->port.iotype == UPIO_DWAPB32) && (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { /* The DesignWare APB UART has an Busy Detect (0x07) - * interrupt meaning an LCR write attempt occured while the + * interrupt meaning an LCR write attempt occurred while the * UART was busy. The interrupt must be cleared by reading * the UART status register (USR) and the LCR re-written. */ unsigned int status; diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c index 8b8930f700b5..738cec9807d3 100644 --- a/drivers/tty/serial/8250_pci.c +++ b/drivers/tty/serial/8250_pci.c @@ -433,7 +433,7 @@ static void __devexit sbs_exit(struct pci_dev *dev) /* * SIIG serial cards have an PCI interface chip which also controls * the UART clocking frequency. Each UART can be clocked independently - * (except cards equiped with 4 UARTs) and initial clocking settings + * (except cards equipped with 4 UARTs) and initial clocking settings * are stored in the EEPROM chip. It can cause problems because this * version of serial driver doesn't support differently clocked UART's * on single PCI card. To prevent this, initialization functions set diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 57731e870085..6deee4e546be 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -520,7 +520,7 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) /* * We don't have a TX buffer queued, so try to queue one. - * If we succesfully queued a buffer, mask the TX IRQ. + * If we successfully queued a buffer, mask the TX IRQ. */ if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index 53a468227056..8a869e58f6d7 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -1248,7 +1248,7 @@ static void icom_set_termios(struct uart_port *port, } } - /* Enable Transmitter and Reciever */ + /* Enable Transmitter and Receiver */ offset = (unsigned long) &ICOM_PORT->statStg->rcv[0] - (unsigned long) ICOM_PORT->statStg; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index dfcf4b1878aa..cb36b0d4ef3c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -78,7 +78,7 @@ #define URXD_FRMERR (1<<12) #define URXD_BRK (1<<11) #define URXD_PRERR (1<<10) -#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */ +#define UCR1_ADEN (1<<15) /* Auto detect interrupt */ #define UCR1_ADBR (1<<14) /* Auto detect baud rate */ #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ #define UCR1_IDEN (1<<12) /* Idle condition interrupt */ diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c index ebff4a1d4bcc..7b1cda59ebb5 100644 --- a/drivers/tty/serial/ip22zilog.c +++ b/drivers/tty/serial/ip22zilog.c @@ -375,7 +375,7 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up, * be nice to transmit console writes just like we normally would for * a TTY line. (ie. buffered and TX interrupt driven). That is not * easy because console writes cannot sleep. One solution might be - * to poll on enough port->xmit space becomming free. -DaveM + * to poll on enough port->xmit space becoming free. -DaveM */ if (!(status & Tx_BUF_EMP)) return; diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index 38a509c684cd..b704c8ce0d71 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -273,7 +273,7 @@ struct neo_uart_struct { u8 fctr; /* WR FCTR - Feature Control Reg */ u8 efr; /* WR EFR - Enhanced Function Reg */ u8 tfifo; /* WR TXCNT/TXTRG - Transmit FIFO Reg */ - u8 rfifo; /* WR RXCNT/RXTRG - Recieve FIFO Reg */ + u8 rfifo; /* WR RXCNT/RXTRG - Receive FIFO Reg */ u8 xoffchar1; /* WR XOFF 1 - XOff Character 1 Reg */ u8 xoffchar2; /* WR XOFF 2 - XOff Character 2 Reg */ u8 xonchar1; /* WR XON 1 - Xon Character 1 Reg */ diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 7960d9633c15..4538c3e3646e 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -381,7 +381,7 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch) /* Copy data from uart to the queue */ memcpy_fromio(ch->ch_rqueue + head, &ch->ch_neo_uart->txrxburst, n); /* - * Since RX_FIFO_DATA_ERROR was 0, we are guarenteed + * Since RX_FIFO_DATA_ERROR was 0, we are guaranteed * that all the data currently in the FIFO is free of * breaks and parity/frame/orun errors. */ @@ -1210,7 +1210,7 @@ static irqreturn_t neo_intr(int irq, void *voidbrd) * Why would I check EVERY possibility of type of * interrupt, when we know its TXRDY??? * Becuz for some reason, even tho we got triggered for TXRDY, - * it seems to be occassionally wrong. Instead of TX, which + * it seems to be occasionally wrong. Instead of TX, which * it should be, I was getting things like RXDY too. Weird. */ neo_parse_isr(brd, port); diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h index 7ab632392502..8415fc723b96 100644 --- a/drivers/tty/serial/max3107.h +++ b/drivers/tty/serial/max3107.h @@ -369,7 +369,7 @@ struct max3107_port { struct spi_device *spi; #if defined(CONFIG_GPIOLIB) - /* GPIO chip stucture */ + /* GPIO chip structure */ struct gpio_chip chip; #endif diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index 37e13c3d91d9..2f548af4e98a 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -23,7 +23,7 @@ * 1 word. If SPI master controller doesn't support sclk frequency change, * then the char need be sent out one by one with some delay * - * 2. Currently only RX availabe interrrupt is used, no need for waiting TXE + * 2. Currently only RX available interrrupt is used, no need for waiting TXE * interrupt for a low speed UART device */ diff --git a/drivers/tty/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h index d1ef43af397c..c37ea48c825a 100644 --- a/drivers/tty/serial/mrst_max3110.h +++ b/drivers/tty/serial/mrst_max3110.h @@ -21,7 +21,7 @@ #define WC_IRQ_MASK (0xF << 8) #define WC_TXE_IRQ_ENABLE (1 << 11) /* TX empty irq */ -#define WC_RXA_IRQ_ENABLE (1 << 10) /* RX availabe irq */ +#define WC_RXA_IRQ_ENABLE (1 << 10) /* RX available irq */ #define WC_PAR_HIGH_IRQ_ENABLE (1 << 9) #define WC_REC_ACT_IRQ_ENABLE (1 << 8) diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c index b906f11f7c1a..624701f8138a 100644 --- a/drivers/tty/serial/msm_serial_hs.c +++ b/drivers/tty/serial/msm_serial_hs.c @@ -495,7 +495,7 @@ static void msm_hs_pm(struct uart_port *uport, unsigned int state, * * Interrupts should be disabled before we are called, as * we modify Set Baud rate - * Set receive stale interrupt level, dependant on Bit Rate + * Set receive stale interrupt level, dependent on Bit Rate * Goal is to have around 8 ms before indicate stale. * roundup (((Bit Rate * .008) / 10) + 1 */ @@ -1350,7 +1350,7 @@ static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev) spin_lock_irqsave(&uport->lock, flags); if (msm_uport->clk_state == MSM_HS_CLK_OFF) { - /* ignore the first irq - it is a pending irq that occured + /* ignore the first irq - it is a pending irq that occurred * before enable_irq() */ if (msm_uport->rx_wakeup.ignore) msm_uport->rx_wakeup.ignore = 0; diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 763537943a53..47cadf474149 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -13,7 +13,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * Note: This driver is made seperate from 8250 driver as we cannot + * Note: This driver is made separate from 8250 driver as we cannot * over load 8250 driver with omap platform specific configuration for * features like DMA, it makes easier to implement features like DMA and * hardware flow control and software flow control configuration with diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 5b9cde79e4ea..e1c8d4f1ce58 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -330,7 +330,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap) * When that happens, I disable the receive side of the driver. * Note that what I've been experiencing is a real irq loop where * I'm getting flooded regardless of the actual port speed. - * Something stange is going on with the HW + * Something strange is going on with the HW */ if ((++loops) > 1000) goto flood; @@ -396,7 +396,7 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap) * be nice to transmit console writes just like we normally would for * a TTY line. (ie. buffered and TX interrupt driven). That is not * easy because console writes cannot sleep. One solution might be - * to poll on enough port->xmit space becomming free. -DaveM + * to poll on enough port->xmit space becoming free. -DaveM */ if (!(status & Tx_BUF_EMP)) return; @@ -809,7 +809,7 @@ static int pmz_set_scc_power(struct uart_pmac_port *uap, int state) #endif /* !CONFIG_PPC_PMAC */ /* - * FixZeroBug....Works around a bug in the SCC receving channel. + * FixZeroBug....Works around a bug in the SCC receiving channel. * Inspired from Darwin code, 15 Sept. 2000 -DanM * * The following sequence prevents a problem that is seen with O'Hare ASICs diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 2335edafe903..9e2fa8d784e2 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -64,7 +64,7 @@ #define tx_enabled(port) ((port)->unused[0]) #define rx_enabled(port) ((port)->unused[1]) -/* flag to ignore all characters comming in */ +/* flag to ignore all characters coming in */ #define RXSTAT_DUMMY_READ (0x10000000) static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port) @@ -291,7 +291,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) goto out; } - /* if there isnt anything more to transmit, or the uart is now + /* if there isn't anything more to transmit, or the uart is now * stopped, disable the uart and exit */ diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index eb7958c675a8..a7b083f4ea78 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -812,7 +812,7 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) } /* - * Here we define a transistion notifier so that we can update all of our + * Here we define a transition notifier so that we can update all of our * ports' baud rate when the peripheral clock changes. */ static int sci_notifier(struct notifier_block *self, diff --git a/drivers/tty/serial/sn_console.c b/drivers/tty/serial/sn_console.c index cff9a306660f..377ae74e7154 100644 --- a/drivers/tty/serial/sn_console.c +++ b/drivers/tty/serial/sn_console.c @@ -146,7 +146,7 @@ static struct sn_sal_ops intr_ops = { }; /* the console does output in two distinctly different ways: - * synchronous (raw) and asynchronous (buffered). initally, early_printk + * synchronous (raw) and asynchronous (buffered). initially, early_printk * does synchronous output. any data written goes directly to the SAL * to be output (incidentally, it is internally buffered by the SAL) * after interrupts and timers are initialized and available for use, @@ -481,7 +481,7 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags) while (port->sc_ops->sal_input_pending()) { ch = port->sc_ops->sal_getc(); if (ch < 0) { - printk(KERN_ERR "sn_console: An error occured while " + printk(KERN_ERR "sn_console: An error occurred while " "obtaining data from the console (0x%0x)\n", ch); break; } diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c index 99ff9abf57ce..8e916e76b7b5 100644 --- a/drivers/tty/serial/sunzilog.c +++ b/drivers/tty/serial/sunzilog.c @@ -474,7 +474,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up, * be nice to transmit console writes just like we normally would for * a TTY line. (ie. buffered and TX interrupt driven). That is not * easy because console writes cannot sleep. One solution might be - * to poll on enough port->xmit space becomming free. -DaveM + * to poll on enough port->xmit space becoming free. -DaveM */ if (!(status & Tx_BUF_EMP)) return; diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 18888d005a0a..27da23d98e3f 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -4072,7 +4072,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) if ( request_irq(info->irq_level,mgsl_interrupt,info->irq_flags, info->device_name, info ) < 0 ) { - printk( "%s(%d):Cant request interrupt on device %s IRQ=%d\n", + printk( "%s(%d):Can't request interrupt on device %s IRQ=%d\n", __FILE__,__LINE__,info->device_name, info->irq_level ); goto errout; } @@ -4095,7 +4095,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) info->memory_base = ioremap_nocache(info->phys_memory_base, 0x40000); if (!info->memory_base) { - printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n", + printk( "%s(%d):Can't map shared memory on device %s MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); goto errout; } @@ -4109,7 +4109,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) info->lcr_base = ioremap_nocache(info->phys_lcr_base, PAGE_SIZE); if (!info->lcr_base) { - printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n", + printk( "%s(%d):Can't map LCR memory on device %s MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); goto errout; } @@ -4119,7 +4119,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) /* claim DMA channel */ if (request_dma(info->dma_level,info->device_name) < 0){ - printk( "%s(%d):Cant request DMA channel on device %s DMA=%d\n", + printk( "%s(%d):Can't request DMA channel on device %s DMA=%d\n", __FILE__,__LINE__,info->device_name, info->dma_level ); mgsl_release_resources( info ); return -ENODEV; @@ -4132,7 +4132,7 @@ static int mgsl_claim_resources(struct mgsl_struct *info) } if ( mgsl_allocate_dma_buffers(info) < 0 ) { - printk( "%s(%d):Cant allocate DMA buffers on device %s DMA=%d\n", + printk( "%s(%d):Can't allocate DMA buffers on device %s DMA=%d\n", __FILE__,__LINE__,info->device_name, info->dma_level ); goto errout; } diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index a35dd549a008..18b48cd3b41d 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3491,7 +3491,7 @@ static int claim_resources(struct slgt_info *info) info->reg_addr = ioremap_nocache(info->phys_reg_addr, SLGT_REG_SIZE); if (!info->reg_addr) { - DBGERR(("%s cant map device registers, addr=%08X\n", + DBGERR(("%s can't map device registers, addr=%08X\n", info->device_name, info->phys_reg_addr)); info->init_error = DiagStatus_CantAssignPciResources; goto errout; diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 327343694473..c77831c7675a 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -3595,7 +3595,7 @@ static int claim_resources(SLMP_INFO *info) info->memory_base = ioremap_nocache(info->phys_memory_base, SCA_MEM_SIZE); if (!info->memory_base) { - printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", + printk( "%s(%d):%s Can't map shared memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); info->init_error = DiagStatus_CantAssignPciResources; goto errout; @@ -3603,7 +3603,7 @@ static int claim_resources(SLMP_INFO *info) info->lcr_base = ioremap_nocache(info->phys_lcr_base, PAGE_SIZE); if (!info->lcr_base) { - printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", + printk( "%s(%d):%s Can't map LCR memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); info->init_error = DiagStatus_CantAssignPciResources; goto errout; @@ -3612,7 +3612,7 @@ static int claim_resources(SLMP_INFO *info) info->sca_base = ioremap_nocache(info->phys_sca_base, PAGE_SIZE); if (!info->sca_base) { - printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", + printk( "%s(%d):%s Can't map SCA memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base ); info->init_error = DiagStatus_CantAssignPciResources; goto errout; @@ -3622,7 +3622,7 @@ static int claim_resources(SLMP_INFO *info) info->statctrl_base = ioremap_nocache(info->phys_statctrl_base, PAGE_SIZE); if (!info->statctrl_base) { - printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", + printk( "%s(%d):%s Can't map SCA Status/Control memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); info->init_error = DiagStatus_CantAssignPciResources; goto errout; @@ -3869,7 +3869,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev) port_array[0]->irq_flags, port_array[0]->device_name, port_array[0]) < 0 ) { - printk( "%s(%d):%s Cant request interrupt, IRQ=%d\n", + printk( "%s(%d):%s Can't request interrupt, IRQ=%d\n", __FILE__,__LINE__, port_array[0]->device_name, port_array[0]->irq_level ); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 936a4ead6c21..d7d50b48287e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2134,7 +2134,7 @@ done: * actually has driver level meaning and triggers a VC resize. * * Locking: - * Driver dependant. The default do_resize method takes the + * Driver dependent. The default do_resize method takes the * tty termios mutex and ctrl_lock. The console takes its own lock * then calls into the default method. */ @@ -2155,7 +2155,7 @@ static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) * tioccons - allow admin to move logical console * @file: the file to become console * - * Allow the adminstrator to move the redirected console device + * Allow the administrator to move the redirected console device * * Locking: uses redirect_lock to guard the redirect information */ @@ -2290,7 +2290,7 @@ EXPORT_SYMBOL_GPL(tty_get_pgrp); /** * tiocgpgrp - get process group * @tty: tty passed by user - * @real_tty: tty side of the tty pased by the user if a pty else the tty + * @real_tty: tty side of the tty passed by the user if a pty else the tty * @p: returned pid * * Obtain the process group of the tty. If there is no process group @@ -2367,7 +2367,7 @@ out_unlock: /** * tiocgsid - get session id * @tty: tty passed by user - * @real_tty: tty side of the tty pased by the user if a pty else the tty + * @real_tty: tty side of the tty passed by the user if a pty else the tty * @p: pointer to returned session id * * Obtain the session id of the tty. If there is no session diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 1a1135d580a2..21574cb32343 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -247,7 +247,7 @@ speed_t tty_termios_baud_rate(struct ktermios *termios) cbaud = termios->c_cflag & CBAUD; #ifdef BOTHER - /* Magic token for arbitary speed via c_ispeed/c_ospeed */ + /* Magic token for arbitrary speed via c_ispeed/c_ospeed */ if (cbaud == BOTHER) return termios->c_ospeed; #endif @@ -283,7 +283,7 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios) if (cbaud == B0) return tty_termios_baud_rate(termios); - /* Magic token for arbitary speed via c_ispeed*/ + /* Magic token for arbitrary speed via c_ispeed*/ if (cbaud == BOTHER) return termios->c_ispeed; @@ -449,7 +449,7 @@ EXPORT_SYMBOL(tty_get_baud_rate); * @new: New termios * @old: Old termios * - * Propogate the hardware specific terminal setting bits from + * Propagate the hardware specific terminal setting bits from * the old termios structure to the new one. This is used in cases * where the hardware does not support reconfiguration or as a helper * in some cases where only minimal reconfiguration is supported diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index c83cdfb56fcc..4bea1efaec98 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3963,7 +3963,7 @@ void reset_palette(struct vc_data *vc) * of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, * depending on width) reserved for each character which is kinda wasty, but * this is done in order to maintain compatibility with the EGA/VGA fonts. It - * is upto the actual low-level console-driver convert data into its favorite + * is up to the actual low-level console-driver convert data into its favorite * format (maybe we should add a `fontoffset' field to the `display' * structure so we won't have to convert the fontdata all the time. * /Jes diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index daf6e77de2b1..e67b566e7aa3 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -39,7 +39,7 @@ module_param(extram_pool_sz, int, 0); MODULE_PARM_DESC(extram_pool_sz, "external ram pool size to allocate"); /* - * Host event IRQ numbers from PRUSS - PRUSS can generate upto 8 interrupt + * Host event IRQ numbers from PRUSS - PRUSS can generate up to 8 interrupt * events to AINTC of ARM host processor - which can be used for IPC b/w PRUSS * firmware and user space application, async notification from PRU firmware * to user space application diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index b268e9fccb47..e71521ce3010 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -1283,7 +1283,7 @@ static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate) /* in bulk mode the modem have problem with high rate * changing internal timing could improve things, but the - * value is misterious. + * value is mysterious. * ADI930 don't support it (-EPIPE error). */ @@ -1743,7 +1743,7 @@ static int uea_send_cmvs_e1(struct uea_softc *sc) goto out; } } else { - /* This realy should not happen */ + /* This really should not happen */ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); goto out; } @@ -1798,7 +1798,7 @@ static int uea_send_cmvs_e4(struct uea_softc *sc) goto out; } } else { - /* This realy should not happen */ + /* This really should not happen */ uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver); goto out; } @@ -1829,7 +1829,7 @@ static int uea_start_reset(struct uea_softc *sc) /* mask interrupt */ sc->booting = 1; - /* We need to set this here because, a ack timeout could have occured, + /* We need to set this here because, a ack timeout could have occurred, * but before we start the reboot, the ack occurs and set this to 1. * So we will failed to wait Ready CMV. */ diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c index b6d49234e521..62050f7a4f97 100644 --- a/drivers/usb/c67x00/c67x00-drv.c +++ b/drivers/usb/c67x00/c67x00-drv.c @@ -27,7 +27,7 @@ * the link between the common hardware parts and the subdrivers (e.g. * interrupt handling). * - * The c67x00 has 2 SIE's (serial interface engine) wich can be configured + * The c67x00 has 2 SIE's (serial interface engine) which can be configured * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG). * * Depending on the platform configuration, the SIE's are created and diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h index 74e44621e313..e3d493d4d61a 100644 --- a/drivers/usb/c67x00/c67x00-hcd.h +++ b/drivers/usb/c67x00/c67x00-hcd.h @@ -34,7 +34,7 @@ /* * The following parameters depend on the CPU speed, bus speed, ... * These can be tuned for specific use cases, e.g. if isochronous transfers - * are very important, bandwith can be sacrificed to guarantee that the + * are very important, bandwidth can be sacrificed to guarantee that the * 1ms deadline will be met. * If bulk transfers are important, the MAX_FRAME_BW can be increased, * but some (or many) isochronous deadlines might not be met. diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c index f6b3c253f3fa..a03fbc15fa9c 100644 --- a/drivers/usb/c67x00/c67x00-sched.c +++ b/drivers/usb/c67x00/c67x00-sched.c @@ -907,7 +907,7 @@ static inline int c67x00_end_of_data(struct c67x00_td *td) /* Remove all td's from the list which come * after last_td and are meant for the same pipe. - * This is used when a short packet has occured */ + * This is used when a short packet has occurred */ static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00, struct c67x00_td *last_td) { diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 5eeb570b9a61..b4ea54dbf323 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -52,7 +52,7 @@ */ /* - * The only reason to have several buffers is to accomodate assumptions + * The only reason to have several buffers is to accommodate assumptions * in line disciplines. They ask for empty space amount, receive our URB size, * and proceed to issue several 1-character writes, assuming they will fit. * The very first write takes a complete URB. Fortunately, this only happens diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 6a54634ab823..385acb895ab3 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -483,7 +483,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, } done += n_characters; - /* Terminate if end-of-message bit recieved from device */ + /* Terminate if end-of-message bit received from device */ if ((buffer[8] & 0x01) && (actual >= n_characters + 12)) remaining = 0; else diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 02b4dbfa488a..8eed05d23838 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -700,7 +700,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd) /* The USB 2.0 spec says 256 ms. This is close enough and won't * exceed that limit if HZ is 100. The math is more clunky than * maybe expected, this is to make sure that all timers for USB devices - * fire at the same time to give the CPU a break inbetween */ + * fire at the same time to give the CPU a break in between */ if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) : (length == 0 && hcd->status_urb != NULL)) mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 564eaa5525d7..8fb754916c67 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1649,7 +1649,7 @@ void usb_disconnect(struct usb_device **pdev) /* mark the device as inactive, so any further urb submissions for * this device (and any of its children) will fail immediately. - * this quiesces everyting except pending urbs. + * this quiesces everything except pending urbs. */ usb_set_device_state(udev, USB_STATE_NOTATTACHED); dev_info(&udev->dev, "USB disconnect, device number %d\n", diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 0bc06e2bcfcb..a6a350f5827b 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -648,7 +648,7 @@ static int ehci_reset_port(int port) if (!(portsc & PORT_CONNECT)) return -ENOTCONN; - /* bomb out completely if something weird happend */ + /* bomb out completely if something weird happened */ if ((portsc & PORT_CSC)) return -EINVAL; diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index f8dd7269d79c..6e42aab75806 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -278,7 +278,7 @@ static int udc_enable_dev_setup_interrupts(struct udc *dev) return 0; } -/* Calculates fifo start of endpoint based on preceeding endpoints */ +/* Calculates fifo start of endpoint based on preceding endpoints */ static int udc_set_txfifo_addr(struct udc_ep *ep) { struct udc *dev; @@ -2137,7 +2137,7 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix) if (use_dma) { /* BNA event ? */ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) { - DBG(dev, "BNA ep%dout occured - DESPTR = %x \n", + DBG(dev, "BNA ep%dout occurred - DESPTR = %x \n", ep->num, readl(&ep->regs->desptr)); /* clear BNA */ writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts); @@ -2151,7 +2151,7 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix) } /* HE event ? */ if (tmp & AMD_BIT(UDC_EPSTS_HE)) { - dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num); + dev_err(&dev->pdev->dev, "HE ep%dout occurred\n", ep->num); /* clear HE */ writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts); @@ -2354,7 +2354,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) /* BNA ? */ if (epsts & AMD_BIT(UDC_EPSTS_BNA)) { dev_err(&dev->pdev->dev, - "BNA ep%din occured - DESPTR = %08lx \n", + "BNA ep%din occurred - DESPTR = %08lx \n", ep->num, (unsigned long) readl(&ep->regs->desptr)); @@ -2367,7 +2367,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) /* HE event ? */ if (epsts & AMD_BIT(UDC_EPSTS_HE)) { dev_err(&dev->pdev->dev, - "HE ep%dn occured - DESPTR = %08lx \n", + "HE ep%dn occurred - DESPTR = %08lx \n", ep->num, (unsigned long) readl(&ep->regs->desptr)); /* clear HE */ @@ -2384,7 +2384,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) req = list_entry(ep->queue.next, struct udc_request, queue); /* - * length bytes transfered + * length bytes transferred * check dma done of last desc. in PPBDU mode */ if (use_dma_ppb_du) { @@ -2784,7 +2784,7 @@ static irqreturn_t udc_control_in_isr(struct udc *dev) /* write fifo */ udc_txfifo_write(ep, &req->req); - /* lengh bytes transfered */ + /* lengh bytes transferred */ len = req->req.length - req->req.actual; if (len > ep->ep.maxpacket) len = ep->ep.maxpacket; diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h index 4bbabbbfc93f..1d1c7543468e 100644 --- a/drivers/usb/gadget/amd5536udc.h +++ b/drivers/usb/gadget/amd5536udc.h @@ -584,7 +584,7 @@ union udc_setup_data { * SET and GET bitfields in u32 values * via constants for mask/offset: * is the text between - * UDC_ and _MASK|_OFS of appropiate + * UDC_ and _MASK|_OFS of appropriate * constant * * set bitfield value in u32 u32Val diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index bb8ddf0469f9..9b7cdb16f26b 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -826,7 +826,7 @@ done: return status; } -/* reinit == restore inital software state */ +/* reinit == restore initial software state */ static void udc_reinit(struct at91_udc *udc) { u32 i; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index c2251c40a205..82314ed22506 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -42,7 +42,7 @@ static struct usb_composite_driver *composite; static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); -/* Some systems will need runtime overrides for the product identifers +/* Some systems will need runtime overrides for the product identifiers * published in the device descriptor, either numbers or strings or both. * String parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ @@ -205,14 +205,14 @@ int usb_function_activate(struct usb_function *function) * usb_interface_id() is called from usb_function.bind() callbacks to * allocate new interface IDs. The function driver will then store that * ID in interface, association, CDC union, and other descriptors. It - * will also handle any control requests targetted at that interface, + * will also handle any control requests targeted at that interface, * particularly changing its altsetting via set_alt(). There may * also be class-specific or vendor-specific requests to handle. * * All interface identifier should be allocated using this routine, to * ensure that for example different functions don't wrongly assign * different meanings to the same identifier. Note that since interface - * identifers are configuration-specific, functions used in more than + * identifiers are configuration-specific, functions used in more than * one configuration (or more than once in a given configuration) need * multiple versions of the relevant descriptors. * diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 00975ed903d1..9abecfddb27d 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -742,7 +742,7 @@ int __init control_selector_init(struct f_audio *audio) } /** - * audio_bind_config - add USB audio fucntion to a configuration + * audio_bind_config - add USB audio function to a configuration * @c: the configuration to supcard the USB audio function * Context: single threaded during gadget setup * diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 130eee678c8b..86902a60bcdb 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -111,7 +111,7 @@ static inline unsigned ncm_bitrate(struct usb_gadget *g) #define NTB_OUT_SIZE 16384 /* - * skbs of size less than that will not be alligned + * skbs of size less than that will not be aligned * to NCM's dwNtbInMaxSize to save bus bandwidth */ diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/fsl_qe_udc.h index bea5b827bebe..e35e24fd64bb 100644 --- a/drivers/usb/gadget/fsl_qe_udc.h +++ b/drivers/usb/gadget/fsl_qe_udc.h @@ -208,14 +208,14 @@ struct qe_frame{ /* Frame status field */ /* Receive side */ #define FRAME_OK 0x00000000 /* Frame tranmitted or received OK */ -#define FRAME_ERROR 0x80000000 /* Error occured on frame */ +#define FRAME_ERROR 0x80000000 /* Error occurred on frame */ #define START_FRAME_LOST 0x40000000 /* START_FRAME_LOST */ #define END_FRAME_LOST 0x20000000 /* END_FRAME_LOST */ #define RX_ER_NONOCT 0x10000000 /* Rx Non Octet Aligned Packet */ #define RX_ER_BITSTUFF 0x08000000 /* Frame Aborted --Received packet with bit stuff error */ #define RX_ER_CRC 0x04000000 /* Received packet with CRC error */ -#define RX_ER_OVERUN 0x02000000 /* Over-run occured on reception */ +#define RX_ER_OVERUN 0x02000000 /* Over-run occurred on reception */ #define RX_ER_PID 0x01000000 /* Wrong PID received */ /* Tranmit side */ #define TX_ER_NAK 0x00800000 /* Received NAK handshake */ @@ -379,7 +379,7 @@ struct qe_udc { #define T_LSP 0x01000000 /* Low-speed transaction */ #define T_PID 0x00c00000 /* packet id */ #define T_NAK 0x00100000 /* No ack. */ -#define T_STAL 0x00080000 /* Stall recieved */ +#define T_STAL 0x00080000 /* Stall received */ #define T_TO 0x00040000 /* time out */ #define T_UN 0x00020000 /* underrun */ diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 912cb8e63fe3..07499c1cdcc4 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -464,7 +464,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, max = le16_to_cpu(desc->wMaxPacketSize); - /* Disable automatic zlp generation. Driver is reponsible to indicate + /* Disable automatic zlp generation. Driver is responsible to indicate * explicitly through req->req.zero. This is needed to enable multi-td * request. */ zlt = 1; @@ -648,7 +648,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) | EP_QUEUE_HEAD_STATUS_HALT)); dQH->size_ioc_int_sts &= temp; - /* Ensure that updates to the QH will occure before priming. */ + /* Ensure that updates to the QH will occur before priming. */ wmb(); /* Prime endpoint by writing 1 to ENDPTPRIME */ @@ -1459,7 +1459,7 @@ static int process_ep_req(struct fsl_udc *udc, int pipe, status = -EILSEQ; break; } else - ERR("Unknown error has occured (0x%x)!\n", + ERR("Unknown error has occurred (0x%x)!\n", errors); } else if (le32_to_cpu(curr_td->size_ioc_sts) diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 20aeceed48c7..e88cce5c2c0d 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -15,7 +15,7 @@ struct usb_dr_device { u8 res1[256]; u16 caplength; /* Capability Register Length */ u16 hciversion; /* Host Controller Interface Version */ - u32 hcsparams; /* Host Controller Structual Parameters */ + u32 hcsparams; /* Host Controller Structural Parameters */ u32 hccparams; /* Host Controller Capability Parameters */ u8 res2[20]; u32 dciversion; /* Device Controller Interface Version */ @@ -52,7 +52,7 @@ struct usb_dr_host { u8 res1[256]; u16 caplength; /* Capability Register Length */ u16 hciversion; /* Host Controller Interface Version */ - u32 hcsparams; /* Host Controller Structual Parameters */ + u32 hcsparams; /* Host Controller Structural Parameters */ u32 hccparams; /* Host Controller Capability Parameters */ u8 res2[20]; u32 dciversion; /* Device Controller Interface Version */ diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 0ab7e141d494..47b86b99d449 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -67,7 +67,7 @@ MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter."); module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter."); -/* Some systems will want different product identifers published in the +/* Some systems will want different product identifiers published in the * device descriptor, either numbers or strings or both. These string * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c index 1eca8b47ce3c..9cee88a43a73 100644 --- a/drivers/usb/gadget/langwell_udc.c +++ b/drivers/usb/gadget/langwell_udc.c @@ -642,7 +642,7 @@ static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) dqh->dtd_status &= dtd_status; dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status); - /* ensure that updates to the dQH will occure before priming */ + /* ensure that updates to the dQH will occur before priming */ wmb(); /* write 1 to endptprime register to PRIME endpoint */ diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index d5468a7f38e0..b62b2640deb0 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -325,7 +325,7 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req) /* * Ensure that updates to the QH will - * occure before priming. + * occur before priming. */ wmb(); @@ -338,7 +338,7 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req) & EP_QUEUE_HEAD_NEXT_POINTER_MASK;; dqh->size_ioc_int_sts = 0; - /* Ensure that updates to the QH will occure before priming. */ + /* Ensure that updates to the QH will occur before priming. */ wmb(); /* Prime the Endpoint */ @@ -1845,7 +1845,7 @@ static irqreturn_t mv_udc_irq(int irq, void *dev) return IRQ_NONE; } - /* Clear all the interrupts occured */ + /* Clear all the interrupts occurred */ writel(status, &udc->op_regs->usbsts); if (status & USBSTS_ERR) diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d09155b25d73..24696f7fa6a9 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -117,7 +117,7 @@ module_param (fifo_mode, ushort, 0644); /* enable_suspend -- When enabled, the driver will respond to * USB suspend requests by powering down the NET2280. Otherwise, - * USB suspend requests will be ignored. This is acceptible for + * USB suspend requests will be ignored. This is acceptable for * self-powered devices */ static int enable_suspend = 0; diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index b5364f9d7cd2..55ca63ad3506 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -203,7 +203,7 @@ static int __init nokia_bind(struct usb_composite_dev *cdev) goto err_usb; } - /* finaly register the configuration */ + /* finally register the configuration */ status = usb_add_config(cdev, &nokia_config_500ma_driver, nokia_bind_config); if (status < 0) diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 12ff6cffedc9..c3f2bd42bd5a 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -126,7 +126,7 @@ static struct printer_dev usb_printer_gadget; #define PRINTER_VENDOR_NUM 0x0525 /* NetChip */ #define PRINTER_PRODUCT_NUM 0xa4a8 /* Linux-USB Printer Gadget */ -/* Some systems will want different product identifers published in the +/* Some systems will want different product identifiers published in the * device descriptor, either numbers or strings or both. These string * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 2efd6732d130..78a39a41547d 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -602,7 +602,7 @@ static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in) /** * inc_ep_stats_bytes - Update ep stats counts * @ep: physical endpoint - * @count: bytes transfered on endpoint + * @count: bytes transferred on endpoint * @is_in: ep direction (USB_DIR_IN or 0) */ static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in) @@ -877,7 +877,7 @@ static void nuke(struct pxa_ep *ep, int status) * If there is less space in request than bytes received in OUT endpoint, * bytes are left in the OUT endpoint. * - * Returns how many bytes were actually transfered + * Returns how many bytes were actually transferred */ static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req) { @@ -914,7 +914,7 @@ static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req) * endpoint. If there are no bytes to transfer, doesn't write anything * to physical endpoint. * - * Returns how many bytes were actually transfered. + * Returns how many bytes were actually transferred. */ static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req, unsigned int max) @@ -991,7 +991,7 @@ static int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req) * caller guarantees at least one packet buffer is ready (or a zlp). * Doesn't complete the request, that's the caller's job * - * Returns 1 if request fully transfered, 0 if partial transfer + * Returns 1 if request fully transferred, 0 if partial transfer */ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req) { @@ -1094,7 +1094,7 @@ static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req) * Sends a request (or a part of the request) to the control endpoint (ep0 in). * If the request doesn't fit, the remaining part will be sent from irq. * The request is considered fully written only if either : - * - last write transfered all remaining bytes, but fifo was not fully filled + * - last write transferred all remaining bytes, but fifo was not fully filled * - last write was a 0 length write * * Returns 1 if request fully written, 0 if request only partially sent @@ -1548,7 +1548,7 @@ static int pxa_udc_get_frame(struct usb_gadget *_gadget) * pxa_udc_wakeup - Force udc device out of suspend * @_gadget: usb gadget * - * Returns 0 if successfull, error code otherwise + * Returns 0 if successful, error code otherwise */ static int pxa_udc_wakeup(struct usb_gadget *_gadget) { diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index ef825c3baed9..0912679de99a 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -41,8 +41,8 @@ /* EP0_MPS_LIMIT * * Unfortunately there seems to be a limit of the amount of data that can - * be transfered by IN transactions on EP0. This is either 127 bytes or 3 - * packets (which practially means 1 packet and 63 bytes of data) when the + * be transferred by IN transactions on EP0. This is either 127 bytes or 3 + * packets (which practically means 1 packet and 63 bytes of data) when the * MPS is set to 64. * * This means if we are wanting to move >127 bytes of data, we need to @@ -783,7 +783,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, hsotg->regs + S3C_DIEPINT(index)); /* Note, trying to clear the NAK here causes problems with transmit - * on the S3C6400 ending up with the TXFIFO becomming full. */ + * on the S3C6400 ending up with the TXFIFO becoming full. */ /* check ep is enabled */ if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna)) @@ -1176,10 +1176,10 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, writel(ctrl, hsotg->regs + reg); dev_dbg(hsotg->dev, - "writen DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", + "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", ctrl, reg, readl(hsotg->regs + reg)); - /* don't belive we need to anything more to get the EP + /* don't believe we need to anything more to get the EP * to reply with a STALL packet */ } } @@ -1416,7 +1416,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) * transaction. * * Note, since we don't write any data to the TxFIFO, then it is - * currently belived that we do not need to wait for any space in + * currently believed that we do not need to wait for any space in * the TxFIFO. */ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, @@ -1540,7 +1540,7 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) * that requires processing, so find out what is in there and do the * appropriate read. * - * The RXFIFO is a true FIFO, the packets comming out are still in packet + * The RXFIFO is a true FIFO, the packets coming out are still in packet * chunks, so if you have x packets received on an endpoint you'll get x * FIFO events delivered, each with a packet's worth of data in it. * @@ -2188,7 +2188,7 @@ irq_retry: /* these next two seem to crop-up occasionally causing the core * to shutdown the USB transfer, so try clearing them and logging - * the occurence. */ + * the occurrence. */ if (gintsts & S3C_GINTSTS_GOUTNakEff) { dev_info(hsotg->dev, "GOUTNakEff triggered\n"); @@ -2469,7 +2469,7 @@ static struct usb_ep_ops s3c_hsotg_ep_ops = { .queue = s3c_hsotg_ep_queue, .dequeue = s3c_hsotg_ep_dequeue, .set_halt = s3c_hsotg_ep_sethalt, - /* note, don't belive we have any call for the fifo routines */ + /* note, don't believe we have any call for the fifo routines */ }; /** diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 9483acdf2e9e..e0e0787b724b 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -402,7 +402,7 @@ config FHCI_DEBUG depends on USB_FHCI_HCD && DEBUG_FS help Say "y" to see some FHCI debug information and statistics - throught debugfs. + through debugfs. config USB_U132_HCD tristate "Elan U132 Adapter Host Controller" diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index f86d3fa20214..333ddc156919 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -644,7 +644,7 @@ static inline void ehci_writel(const struct ehci_hcd *ehci, /* * On certain ppc-44x SoC there is a HW issue, that could only worked around with * explicit suspend/operate of OHCI. This function hereby makes sense only on that arch. - * Other common bits are dependant on has_amcc_usb23 quirk flag. + * Other common bits are dependent on has_amcc_usb23 quirk flag. */ #ifdef CONFIG_44x static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational) diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index b84ff7e51896..19223c7449e1 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -401,7 +401,7 @@ static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, /* 1 td fro setup,1 for ack */ size = 2; case PIPE_BULK: - /* one td for every 4096 bytes(can be upto 8k) */ + /* one td for every 4096 bytes(can be up to 8k) */ size += urb->transfer_buffer_length / 4096; /* ...add for any remaining bytes... */ if ((urb->transfer_buffer_length % 4096) != 0) diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c index 38fe058fbe61..0ea577bfca2a 100644 --- a/drivers/usb/host/fhci-tds.c +++ b/drivers/usb/host/fhci-tds.c @@ -40,7 +40,7 @@ #define TD_RXER 0x0020 /* Rx error or not */ #define TD_NAK 0x0010 /* No ack. */ -#define TD_STAL 0x0008 /* Stall recieved */ +#define TD_STAL 0x0008 /* Stall received */ #define TD_TO 0x0004 /* time out */ #define TD_UN 0x0002 /* underrun */ #define TD_NO 0x0010 /* Rx Non Octet Aligned Packet */ @@ -274,7 +274,7 @@ void fhci_init_ep_registers(struct fhci_usb *usb, struct endpoint *ep, * It is also preparing the TDs for new frames. If the Tx interrupts * are disabled, the application should call that routine to get * confirmation about the submitted frames. Otherwise, the routine is - * called frome the interrupt service routine during the Tx interrupt. + * called from the interrupt service routine during the Tx interrupt. * In that case the application is informed by calling the application * specific 'fhci_transaction_confirm' routine */ @@ -337,7 +337,7 @@ static void fhci_td_transaction_confirm(struct fhci_usb *usb) pkt->status = USB_TD_RX_ER_NONOCT; else fhci_err(usb->fhci, "illegal error " - "occured\n"); + "occurred\n"); } else if (td_status & TD_NAK) pkt->status = USB_TD_TX_ER_NAK; else if (td_status & TD_TO) @@ -347,7 +347,7 @@ static void fhci_td_transaction_confirm(struct fhci_usb *usb) else if (td_status & TD_STAL) pkt->status = USB_TD_TX_ER_STALL; else - fhci_err(usb->fhci, "illegal error occured\n"); + fhci_err(usb->fhci, "illegal error occurred\n"); } else if ((extra_data & TD_TOK_IN) && pkt->len > td_length - CRC_SIZE) { pkt->status = USB_TD_RX_DATA_UNDERUN; diff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h index 71c3caaea4c1..dc6939a44a1a 100644 --- a/drivers/usb/host/fhci.h +++ b/drivers/usb/host/fhci.h @@ -82,7 +82,7 @@ #define USB_TD_RX_ER_NONOCT 0x40000000 /* Tx Non Octet Aligned Packet */ #define USB_TD_RX_ER_BITSTUFF 0x20000000 /* Frame Aborted-Received pkt */ #define USB_TD_RX_ER_CRC 0x10000000 /* CRC error */ -#define USB_TD_RX_ER_OVERUN 0x08000000 /* Over - run occured */ +#define USB_TD_RX_ER_OVERUN 0x08000000 /* Over - run occurred */ #define USB_TD_RX_ER_PID 0x04000000 /* wrong PID received */ #define USB_TD_RX_DATA_UNDERUN 0x02000000 /* shorter than expected */ #define USB_TD_RX_DATA_OVERUN 0x01000000 /* longer than expected */ @@ -363,7 +363,7 @@ struct ed { struct td { void *data; /* a pointer to the data buffer */ unsigned int len; /* length of the data to be submitted */ - unsigned int actual_len; /* actual bytes transfered on this td */ + unsigned int actual_len; /* actual bytes transferred on this td */ enum fhci_ta_type type; /* transaction type */ u8 toggle; /* toggle for next trans. within this TD */ u16 iso_index; /* ISO transaction index */ diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 2562e92e3178..af05718bdc73 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1323,7 +1323,7 @@ static void process_etds(struct usb_hcd *hcd, struct imx21 *imx21, int sof) * (and hence no interrupt occurs). * This causes the transfer in question to hang. * The kludge below checks for this condition at each SOF and processes any - * blocked ETDs (after an arbitary 10 frame wait) + * blocked ETDs (after an arbitrary 10 frame wait) * * With a single active transfer the usbtest test suite will run for days * without the kludge. diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index 12db961acdfb..9a2c400e6090 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h @@ -13,7 +13,7 @@ /* Full speed: max # of bytes to transfer for a single urb at a time must be < 1024 && must be multiple of 64. - 832 allows transfering 4kiB within 5 frames. */ + 832 allows transferring 4kiB within 5 frames. */ #define MAX_TRANSFER_SIZE_FULLSPEED 832 /* Low speed: there is no reason to schedule in very big diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 662cd002adfc..f97570a847ca 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -546,7 +546,7 @@ static void postproc_ep(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep) if (usb_pipecontrol(urb->pipe)) { ep->nextpid = USB_PID_ACK; /* save the data underrun error code for later and - * procede with the status stage + * proceed with the status stage */ urb->actual_length += PTD_GET_COUNT(ptd); BUG_ON(urb->actual_length > urb->transfer_buffer_length); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index e7288639edb0..d55723514860 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -162,7 +162,7 @@ static int ohci_urb_enqueue ( // case PIPE_INTERRUPT: // case PIPE_BULK: default: - /* one TD for every 4096 Bytes (can be upto 8K) */ + /* one TD for every 4096 Bytes (can be up to 8K) */ size += urb->transfer_buffer_length / 4096; /* ... and for any remaining bytes ... */ if ((urb->transfer_buffer_length % 4096) != 0) diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 44e4deb362e1..4a771f6cc822 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2879,7 +2879,7 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, /* Ok, we have more job to do! :) */ for (i = 0; i < num - 1; i++) { - /* Get free micro URB poll till a free urb is recieved */ + /* Get free micro URB poll till a free urb is received */ do { murb = (struct urb *) oxu_murb_alloc(oxu); @@ -2911,7 +2911,7 @@ static int oxu_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, /* Last urb requires special handling */ - /* Get free micro URB poll till a free urb is recieved */ + /* Get free micro URB poll till a free urb is received */ do { murb = (struct urb *) oxu_murb_alloc(oxu); if (!murb) diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index dc0ab8382f5d..d6e175428618 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -739,7 +739,7 @@ static int get_urb_status_from_qtd(struct urb *urb, u32 status) * process_inactive_qtd - process an inactive (but not halted) qTD. * * Update the urb with the transfer bytes from the qTD, if the urb is - * completely transfered or (in the case of an IN only) the LPF is + * completely transferred or (in the case of an IN only) the LPF is * set, then the transfer is complete and the urb should be returned * to the system. */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9a3645fd759b..196e0181b2ed 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -741,7 +741,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) int retval; /* Wait a bit if either of the roothubs need to settle from the - * transistion into bus suspend. + * transition into bus suspend. */ if (time_before(jiffies, xhci->bus_state[0].next_statechange) || time_before(jiffies, @@ -2072,7 +2072,7 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, return -EINVAL; } vdev = xhci->devs[udev->slot_id]; - /* Mark each endpoint as being in transistion, so + /* Mark each endpoint as being in transition, so * xhci_urb_enqueue() will reject all URBs. */ for (i = 0; i < num_eps; i++) { diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 711de253bc0f..07e263063e37 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -873,7 +873,7 @@ struct xhci_transfer_event { #define COMP_CMD_ABORT 25 /* Stopped - transfer was terminated by a stop endpoint command */ #define COMP_STOP 26 -/* Same as COMP_EP_STOPPED, but the transfered length in the event is invalid */ +/* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */ #define COMP_STOP_INVAL 27 /* Control Abort Error - Debug Capability - control pipe aborted */ #define COMP_DBG_ABORT 28 diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index c90c89dc0003..a0037961e5bd 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -69,7 +69,7 @@ * 20000513 added IDs for all products supported by Windows driver (john) * 20000514 Rewrote mts_scsi_queuecommand to use URBs (john) * 20000514 Version 0.0.8j - * 20000514 Fix reporting of non-existant devices to SCSI layer (john) + * 20000514 Fix reporting of non-existent devices to SCSI layer (john) * 20000514 Added MTS_DEBUG_INT (john) * 20000514 Changed "usb-microtek" to "microtek" for consistency (john) * 20000514 Stupid bug fixes (john) @@ -557,14 +557,14 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc) if ( !memcmp( srb->cmnd, mts_read_image_sig, mts_read_image_sig_len ) ) { pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_image); - MTS_DEBUG( "transfering from desc->ep_image == %d\n", + MTS_DEBUG( "transferring from desc->ep_image == %d\n", (int)desc->ep_image ); } else if ( MTS_DIRECTION_IS_IN(srb->cmnd[0]) ) { pipe = usb_rcvbulkpipe(desc->usb_dev,desc->ep_response); - MTS_DEBUG( "transfering from desc->ep_response == %d\n", + MTS_DEBUG( "transferring from desc->ep_response == %d\n", (int)desc->ep_response); } else { - MTS_DEBUG("transfering to desc->ep_out == %d\n", + MTS_DEBUG("transferring to desc->ep_out == %d\n", (int)desc->ep_out); pipe = usb_sndbulkpipe(desc->usb_dev,desc->ep_out); } diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index e573e4704015..a2190b983f52 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -40,7 +40,7 @@ #ifdef CONFIG_USB_DYNAMIC_MINORS #define IOWARRIOR_MINOR_BASE 0 #else -#define IOWARRIOR_MINOR_BASE 208 // SKELETON_MINOR_BASE 192 + 16, not offical yet +#define IOWARRIOR_MINOR_BASE 208 // SKELETON_MINOR_BASE 192 + 16, not official yet #endif /* interrupt input queue size */ diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c index 8c6fdef61d1c..e25700f44b6f 100644 --- a/drivers/usb/otg/isp1301_omap.c +++ b/drivers/usb/otg/isp1301_omap.c @@ -1531,7 +1531,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id) i2c_set_clientdata(i2c, isp); isp->client = i2c; - /* verify the chip (shouldn't be necesary) */ + /* verify the chip (shouldn't be necessary) */ status = isp1301_get_u16(isp, ISP1301_VENDOR_ID); if (status != I2C_VENDOR_ID_PHILIPS) { dev_dbg(&i2c->dev, "not philips id: %d\n", status); diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c index 7f9b8cd4514b..e973ff19c55a 100644 --- a/drivers/usb/otg/langwell_otg.c +++ b/drivers/usb/otg/langwell_otg.c @@ -580,7 +580,7 @@ static void langwell_otg_add_ktimer(enum langwell_otg_timer_type timers) time = TB_BUS_SUSPEND; break; default: - dev_dbg(lnw->dev, "unkown timer, cannot enable it\n"); + dev_dbg(lnw->dev, "unknown timer, cannot enable it\n"); return; } @@ -1381,7 +1381,7 @@ static void langwell_otg_work(struct work_struct *work) } else if (!iotg->hsm.a_bus_req && iotg->otg.host && iotg->otg.host->b_hnp_enable) { /* It is not safe enough to do a fast - * transistion from A_WAIT_BCON to + * transition from A_WAIT_BCON to * A_SUSPEND */ msleep(10000); if (iotg->hsm.a_bus_req) diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 0db6ace16f7b..aba201cb872c 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -16,7 +16,7 @@ * When reading the process is almost equal except that the header starts with * 0x00 0x20. * - * The device simply need some stuff to understand data comming from the usb + * The device simply need some stuff to understand data coming from the usb * buffer: The First and Second byte is used for a Header, the Third and Fourth * tells the device the amount of information the package holds. * Packages are 60 bytes long Header Stuff. @@ -30,7 +30,7 @@ * one. * * The driver registers himself with the USB-serial core and the USB Core. I had - * to implement a probe function agains USB-serial, because other way, the + * to implement a probe function against USB-serial, because other way, the * driver was attaching himself to both interfaces. I have tryed with different * configurations of usb_serial_driver with out exit, only the probe function * could handle this correctly. diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 4df3e0cecbae..0f11afdda134 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -101,7 +101,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */ { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ - { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */ + { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesys ETRX2USB */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 987e9bf7bd02..d9906eb9d16a 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -35,7 +35,7 @@ * * Lonnie Mendez * 04-10-2004 - * Driver modified to support dynamic line settings. Various improvments + * Driver modified to support dynamic line settings. Various improvements * and features. * * Neil Whelchel diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 65967b36365f..a973c7a29d6e 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -17,7 +17,7 @@ * See Documentation/usb/usb-serial.txt for more information on using this * driver * - * See http://ftdi-usb-sio.sourceforge.net for upto date testing info + * See http://ftdi-usb-sio.sourceforge.net for up to date testing info * and extra documentation * * Change entries from 2004 and earlier can be found in versions of this diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index f1aedfa7c420..abf095be5753 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -1981,7 +1981,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial, if (code == IOSP_STATUS_OPEN_RSP) { edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3); edge_port->maxTxCredits = edge_port->txCredits; - dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __func__, edge_serial->rxPort, byte2, edge_port->txCredits); + dbg("%s - Port %u Open Response Initial MSR = %02x TxBufferSize = %d", __func__, edge_serial->rxPort, byte2, edge_port->txCredits); handle_new_msr(edge_port, byte2); /* send the current line settings to the port so we are diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h index dced7ec65470..ad9c1d47a619 100644 --- a/drivers/usb/serial/io_edgeport.h +++ b/drivers/usb/serial/io_edgeport.h @@ -68,7 +68,7 @@ struct comMapper { #define PROC_SET_COM_ENTRY 2 -/* The following sturcture is passed to the write */ +/* The following structure is passed to the write */ struct procWrite { int Command; union { diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index d8434910fa7b..0aac00afb5c8 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -433,7 +433,7 @@ static int write_i2c_mem(struct edgeport_serial *serial, /* We can only send a maximum of 1 aligned byte page at a time */ - /* calulate the number of bytes left in the first page */ + /* calculate the number of bytes left in the first page */ write_length = EPROM_PAGE_SIZE - (start_address & (EPROM_PAGE_SIZE - 1)); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 201f6096844b..a6f63cc8c130 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -116,7 +116,7 @@ static void opticon_read_bulk_callback(struct urb *urb) } else { if ((data[0] == 0x00) && (data[1] == 0x01)) { spin_lock_irqsave(&priv->lock, flags); - /* CTS status infomation package */ + /* CTS status information package */ if (data[2] == 0x00) priv->cts = false; else diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 08e03745e251..0e5aafda4537 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -562,7 +562,7 @@ static int ene_sd_init(struct us_data *us) result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Exection SD Init Code Fail !!\n"); + US_DEBUGP("Execution SD Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } @@ -581,7 +581,7 @@ static int ene_sd_init(struct us_data *us) result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Exection SD Init Code Fail !!\n"); + US_DEBUGP("Execution SD Init Code Fail !!\n"); return USB_STOR_TRANSPORT_ERROR; } diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 6b9982cd5423..09e52ba47ddf 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1510,7 +1510,7 @@ static int isd200_Initialization(struct us_data *us) * Protocol and Transport for the ISD200 ASIC * * This protocol and transport are for ATA devices connected to an ISD200 - * ASIC. An ATAPI device that is conected as a slave device will be + * ASIC. An ATAPI device that is connected as a slave device will be * detected in the driver initialization function and the protocol will * be changed to an ATAPI protocol (Transparent SCSI). * diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 689ee1fb702a..13b8bcdf3dba 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -123,7 +123,7 @@ static int slave_configure(struct scsi_device *sdev) { struct us_data *us = host_to_us(sdev->host); - /* Many devices have trouble transfering more than 32KB at a time, + /* Many devices have trouble transferring more than 32KB at a time, * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). */ diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index bd3f415893d8..0b00091d2ae9 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -340,7 +340,7 @@ static int usbat_check_status(struct us_data *us) } /* - * Stores critical information in internal registers in prepartion for the execution + * Stores critical information in internal registers in preparation for the execution * of a conditional usbat_read_blocks or usbat_write_blocks call. */ static int usbat_set_shuttle_features(struct us_data *us, diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 827c87f10cc5..7e4bf95f8f7b 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -180,7 +180,7 @@ static void bytewise_xor(void *_bo, const void *_bi1, const void *_bi2, * using the 14 bytes of @a to fill up * b1.{mac_header,e0,security_reserved,padding}. * - * NOTE: The definiton of l(a) in WUSB1.0[6.5] vs the definition of + * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of * l(m) is orthogonal, they bear no relationship, so it is not * in conflict with the parameter's relation that * WUSB1.0[6.4.2]) defines. @@ -272,7 +272,7 @@ static int wusb_ccm_mac(struct crypto_blkcipher *tfm_cbc, /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5] * The procedure is to AES crypt the A0 block and XOR the MIC - * Tag agains it; we only do the first 8 bytes and place it + * Tag against it; we only do the first 8 bytes and place it * directly in the destination buffer. * * POS Crypto API: size is assumed to be AES's block size. diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c index 4ed97360c046..6f4fafdc2401 100644 --- a/drivers/usb/wusbcore/reservation.c +++ b/drivers/usb/wusbcore/reservation.c @@ -71,7 +71,7 @@ static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv) /** * wusbhc_rsv_establish - establish a reservation for the cluster - * @wusbhc: the WUSB HC requesting a bandwith reservation + * @wusbhc: the WUSB HC requesting a bandwidth reservation */ int wusbhc_rsv_establish(struct wusbhc *wusbhc) { diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c index c175b7300c73..39de3900ad20 100644 --- a/drivers/usb/wusbcore/rh.c +++ b/drivers/usb/wusbcore/rh.c @@ -133,7 +133,7 @@ static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx) * big of a problem [and we can't make it an spinlock * because other parts need to take it and sleep] . * - * @usb_hcd is refcounted, so it won't dissapear under us + * @usb_hcd is refcounted, so it won't disappear under us * and before killing a host, the polling of the root hub * would be stopped anyway. */ diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index 8cb9d80207fa..ca80171f42c6 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -24,7 +24,7 @@ * * RPIPE * - * Targetted at different downstream endpoints + * Targeted at different downstream endpoints * * Descriptor: use to config the remote pipe. * diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 84b744c428a4..6ccd93a9b909 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -61,7 +61,7 @@ * * Two methods it could be done: * - * (a) set up a timer everytime an rpipe's use count drops to 1 + * (a) set up a timer every time an rpipe's use count drops to 1 * (which means unused) or when a transfer ends. Reset the * timer when a xfer is queued. If the timer expires, release * the rpipe [see rpipe_ep_disable()]. @@ -140,7 +140,7 @@ struct wa_xfer { struct wahc *wa; /* Wire adapter we are plugged to */ struct usb_host_endpoint *ep; - struct urb *urb; /* URB we are transfering for */ + struct urb *urb; /* URB we are transferring for */ struct wa_seg **seg; /* transfer segments */ u8 segs, segs_submitted, segs_done; unsigned is_inbound:1; @@ -161,7 +161,7 @@ static inline void wa_xfer_init(struct wa_xfer *xfer) } /* - * Destory a transfer structure + * Destroy a transfer structure * * Note that the xfer->seg[index] thingies follow the URB life cycle, * so we need to put them, not free them. @@ -494,7 +494,7 @@ static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer, * function does almost the same thing and they work closely * together. * - * If the seg request has failed but this DTO phase has suceeded, + * If the seg request has failed but this DTO phase has succeeded, * wa_seg_cb() has already failed the segment and moved the * status to WA_SEG_ERROR, so this will go through 'case 0' and * effectively do nothing. diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h index 6bd426b7ec07..3a2d09162e70 100644 --- a/drivers/usb/wusbcore/wusbhc.h +++ b/drivers/usb/wusbcore/wusbhc.h @@ -231,7 +231,7 @@ struct wusb_port { * * Most of the times when you need to use it, it will be non-NULL, * so there is no real need to check for it (wusb_dev will - * dissapear before usb_dev). + * disappear before usb_dev). * * - The following fields need to be filled out before calling * wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}. diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c index 08bd6dbfd4a6..3e5454aba5d4 100644 --- a/drivers/uwb/driver.c +++ b/drivers/uwb/driver.c @@ -61,7 +61,7 @@ /** - * If a beacon dissapears for longer than this, then we consider the + * If a beacon disappears for longer than this, then we consider the * device who was represented by that beacon to be gone. * * ECMA-368[17.2.3, last para] establishes that a device must not diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c index a8d83e25e3b6..3fbcf789dfaa 100644 --- a/drivers/uwb/drp.c +++ b/drivers/uwb/drp.c @@ -27,7 +27,7 @@ /* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */ enum uwb_drp_conflict_action { - /* Reservation is mantained, no action needed */ + /* Reservation is maintained, no action needed */ UWB_DRP_CONFLICT_MANTAIN = 0, /* the device shall not transmit frames in conflicting MASs in @@ -741,12 +741,12 @@ void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, * DRP notifications can occur for three different reasons: * * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as - * the target or source have been recieved. + * the target or source have been received. * * These DRP IEs could be new or for an existing reservation. * * If the DRP IE for an existing reservation ceases to be to - * recieved for at least mMaxLostBeacons, the reservation should be + * received for at least mMaxLostBeacons, the reservation should be * considered to be terminated. Note that the TERMINATE reason (see * below) may not always be signalled (e.g., the remote device has * two or more reservations established with the RC). diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c index b0091c771b9a..b4395f41a007 100644 --- a/drivers/uwb/lc-rc.c +++ b/drivers/uwb/lc-rc.c @@ -168,7 +168,7 @@ int uwb_rc_mac_addr_setup(struct uwb_rc *rc) } if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) { - addr.data[0] = 0x02; /* locally adminstered and unicast */ + addr.data[0] = 0x02; /* locally administered and unicast */ get_random_bytes(&addr.data[1], sizeof(addr.data)-1); result = uwb_rc_mac_addr_set(rc, &addr); diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c index 27849292b552..3de630b0f691 100644 --- a/drivers/uwb/reset.c +++ b/drivers/uwb/reset.c @@ -52,7 +52,7 @@ const char *__strerror[] = { "cancelled", "invalid state", "invalid size", - "ack not recieved", + "ack not received", "no more asie notification", }; diff --git a/drivers/uwb/umc-dev.c b/drivers/uwb/umc-dev.c index ccd2184e05d2..b2948ec57878 100644 --- a/drivers/uwb/umc-dev.c +++ b/drivers/uwb/umc-dev.c @@ -78,7 +78,7 @@ EXPORT_SYMBOL_GPL(umc_device_register); * First we unregister the device, make sure the driver can do it's * resource release thing and then we try to release any left over * resources. We take a ref to the device, to make sure it doesn't - * dissapear under our feet. + * disappear under our feet. */ void umc_device_unregister(struct umc_dev *umc) { diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index ccecf9974587..4484c721f0f9 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -637,7 +637,7 @@ static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitf * magnitude which needs to be scaled in this function for the hardware. * Things to take into consideration are how many color registers, if * any, are supported with the current color visual. With truecolor mode - * no color palettes are supported. Here a psuedo palette is created + * no color palettes are supported. Here a pseudo palette is created * which we store the value in pseudo_palette in struct fb_info. For * pseudocolor mode we have a limited color palette. To deal with this * we can program what color is displayed for a particular pixel value. diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index d437b3daf1f5..ebb893c49e90 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -3124,12 +3124,12 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, M = pll_regs[2]; /* - * PLL Feedback Divider N (Dependant on CLOCK_CNTL): + * PLL Feedback Divider N (Dependent on CLOCK_CNTL): */ N = pll_regs[7 + (clock_cntl & 3)]; /* - * PLL Post Divider P (Dependant on CLOCK_CNTL): + * PLL Post Divider P (Dependent on CLOCK_CNTL): */ P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1)); diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c index 2ba8b3c421a1..46f72ed53510 100644 --- a/drivers/video/aty/mach64_cursor.c +++ b/drivers/video/aty/mach64_cursor.c @@ -51,7 +51,7 @@ * to a larger number and saturate CUR_HORZ_POSN to zero. * * if Y becomes negative, CUR_VERT_OFFSET must be adjusted to a larger number, - * CUR_OFFSET must be adjusted to a point to the appropraite line in the cursor + * CUR_OFFSET must be adjusted to a point to the appropriate line in the cursor * definitation and CUR_VERT_POSN must be saturated to zero. */ diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 4ea187d93768..5dff32ac8044 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -1572,7 +1572,7 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) /* Copy monitor specs from panel data */ /* fixme: we're setting up LCD controller windows, so these dont give a damn as to what the monitor specs are (the panel itself does, but that - isnt done here...so maybe need a generic catchall monitor setting??? */ + isn't done here...so maybe need a generic catchall monitor setting??? */ memcpy(&fbi->monspecs, &panel->monspecs, sizeof(struct fb_monspecs)); /* We first try the user mode passed in argument. If that failed, diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index af6098396fe6..c6533bad26f8 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -109,7 +109,7 @@ static unsigned long corgibl_flags; #define CORGIBL_BATTLOW 0x02 /* - * This is only a psuedo I2C interface. We can't use the standard kernel + * This is only a pseudo I2C interface. We can't use the standard kernel * routines as the interface is write only. We just assume the data is acked... */ static void lcdtg_ssp_i2c_send(struct corgi_lcd *lcd, uint8_t data) diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index bbca3127071e..be20b5cbe26c 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -6,7 +6,7 @@ * GPL v2 * * This driver assumes single CPU. That's okay, because collie is - * slightly old hardware, and noone is going to retrofit second CPU to + * slightly old hardware, and no one is going to retrofit second CPU to * old PDA. */ diff --git a/drivers/video/bfin_adv7393fb.h b/drivers/video/bfin_adv7393fb.h index 8c7f9e4fc6eb..cd591b5152a5 100644 --- a/drivers/video/bfin_adv7393fb.h +++ b/drivers/video/bfin_adv7393fb.h @@ -87,12 +87,12 @@ static const u8 init_NTSC_TESTPATTERN[] = { static const u8 init_NTSC[] = { 0x00, 0x1E, /* Power up all DACs and PLL */ - 0xC3, 0x26, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xC5, 0x12, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xC2, 0x4A, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xC6, 0x5E, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xBD, 0x19, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xBF, 0x42, /* Program RGB->YCrCb Color Space convertion matrix */ + 0xC3, 0x26, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xC5, 0x12, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xC2, 0x4A, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xC6, 0x5E, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xBD, 0x19, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xBF, 0x42, /* Program RGB->YCrCb Color Space conversion matrix */ 0x8C, 0x1F, /* NTSC Subcarrier Frequency */ 0x8D, 0x7C, /* NTSC Subcarrier Frequency */ 0x8E, 0xF0, /* NTSC Subcarrier Frequency */ @@ -109,12 +109,12 @@ static const u8 init_NTSC[] = { static const u8 init_PAL[] = { 0x00, 0x1E, /* Power up all DACs and PLL */ - 0xC3, 0x26, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xC5, 0x12, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xC2, 0x4A, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xC6, 0x5E, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xBD, 0x19, /* Program RGB->YCrCb Color Space convertion matrix */ - 0xBF, 0x42, /* Program RGB->YCrCb Color Space convertion matrix */ + 0xC3, 0x26, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xC5, 0x12, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xC2, 0x4A, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xC6, 0x5E, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xBD, 0x19, /* Program RGB->YCrCb Color Space conversion matrix */ + 0xBF, 0x42, /* Program RGB->YCrCb Color Space conversion matrix */ 0x8C, 0xCB, /* PAL Subcarrier Frequency */ 0x8D, 0x8A, /* PAL Subcarrier Frequency */ 0x8E, 0x09, /* PAL Subcarrier Frequency */ diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c index a19a7f33133e..fa6e698e63c4 100644 --- a/drivers/video/console/font_mini_4x6.c +++ b/drivers/video/console/font_mini_4x6.c @@ -1,5 +1,5 @@ -/* Hand composed "Miniscule" 4x6 font, with binary data generated using +/* Hand composed "Minuscule" 4x6 font, with binary data generated using * Perl stub. * * Use 'perl -x mini_4x6.c < mini_4x6.c > new_version.c' to regenerate diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 8d61ef96eedd..8b7d47386f39 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -763,7 +763,7 @@ static int fb_wait_for_vsync(struct fb_info *info) /* * Set flag to 0 and wait for isr to set to 1. It would seem there is a - * race condition here where the ISR could have occured just before or + * race condition here where the ISR could have occurred just before or * just after this set. But since we are just coarsely waiting for * a frame to complete then that's OK. i.e. if the frame completed * just before this code executed then we have to wait another full diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c index f6a09ab0dac6..0c647d7af0ee 100644 --- a/drivers/video/display/display-sysfs.c +++ b/drivers/video/display/display-sysfs.c @@ -182,7 +182,7 @@ void display_device_unregister(struct display_device *ddev) mutex_lock(&ddev->lock); device_unregister(ddev->dev); mutex_unlock(&ddev->lock); - // Mark device index as avaliable + // Mark device index as available mutex_lock(&allocated_dsp_lock); idr_remove(&allocated_dsp, ddev->idx); mutex_unlock(&allocated_dsp_lock); diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c index b358d045f130..cbdb1bd77c21 100644 --- a/drivers/video/ep93xx-fb.c +++ b/drivers/video/ep93xx-fb.c @@ -456,7 +456,7 @@ static int __init ep93xxfb_alloc_videomem(struct fb_info *info) * There is a bug in the ep93xx framebuffer which causes problems * if bit 27 of the physical address is set. * See: http://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2 - * There does not seem to be any offical errata for this, but I + * There does not seem to be any official errata for this, but I * have confirmed the problem exists on my hardware (ep9315) at * least. */ diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index f4a32779168b..04251ce89184 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -33,7 +33,7 @@ * for driver private data (info->par). info->par (if any) will be * aligned to sizeof(long). * - * Returns the new structure, or NULL if an error occured. + * Returns the new structure, or NULL if an error occurred. * */ struct fb_info *framebuffer_alloc(size_t size, struct device *dev) diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c index 1b0feb8e7244..d0533b7aad79 100644 --- a/drivers/video/fm2fb.c +++ b/drivers/video/fm2fb.c @@ -45,7 +45,7 @@ * buffer needs an amount of memory of 1.769.472 bytes which * is near to 2 MByte (the allocated address space of Zorro2). * The memory is channel interleaved. That means every channel - * owns four VRAMs. Unfortunatly most FrameMasters II are + * owns four VRAMs. Unfortunately most FrameMasters II are * not assembled with memory for the alpha channel. In this * case it could be possible to add the frame buffer into the * normal memory pool. diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 9048f87fa8c1..bedf5be27f05 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -882,7 +882,7 @@ static inline __u32 CNVT_TOHW(__u32 val, __u32 width) * which needs to be scaled in this function for the hardware. Things to take * into consideration are how many color registers, if any, are supported with * the current color visual. With truecolor mode no color palettes are - * supported. Here a psuedo palette is created which we store the value in + * supported. Here a pseudo palette is created which we store the value in * pseudo_palette in struct fb_info. For pseudocolor mode we have a limited * color palette. */ diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c index 933899dca33a..7e7b7a9ba274 100644 --- a/drivers/video/gbefb.c +++ b/drivers/video/gbefb.c @@ -721,7 +721,7 @@ static int gbefb_set_par(struct fb_info *info) Tiles have the advantage that they can be allocated individually in memory. However, this mapping is not linear at all, which is not - really convienient. In order to support linear addressing, the GBE + really convenient. In order to support linear addressing, the GBE DMA hardware is fooled into thinking the screen is only one tile large and but has a greater height, so that the DMA transfer covers the same region. diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h index be8ccb47ebe0..cfcd8090f313 100644 --- a/drivers/video/geode/lxfb.h +++ b/drivers/video/geode/lxfb.h @@ -117,7 +117,7 @@ enum gp_registers { }; #define GP_BLT_STATUS_CE (1 << 4) /* cmd buf empty */ -#define GP_BLT_STATUS_PB (1 << 0) /* primative busy */ +#define GP_BLT_STATUS_PB (1 << 0) /* primitive busy */ /* Display Controller registers (table 6-47 from the data book) */ diff --git a/drivers/video/i810/i810_accel.c b/drivers/video/i810/i810_accel.c index f5bedee4310a..7672d2ea9b35 100644 --- a/drivers/video/i810/i810_accel.c +++ b/drivers/video/i810/i810_accel.c @@ -112,7 +112,7 @@ static inline int wait_for_engine_idle(struct fb_info *info) * @par: pointer to i810fb_par structure * * DESCRIPTION: - * Checks/waits for sufficent space in ringbuffer of size + * Checks/waits for sufficient space in ringbuffer of size * space. Returns the tail of the buffer */ static inline u32 begin_iring(struct fb_info *info, u32 space) diff --git a/drivers/video/kyro/STG4000OverlayDevice.c b/drivers/video/kyro/STG4000OverlayDevice.c index a8c9713413e6..0aeeaa10708b 100644 --- a/drivers/video/kyro/STG4000OverlayDevice.c +++ b/drivers/video/kyro/STG4000OverlayDevice.c @@ -417,7 +417,7 @@ int SetOverlayViewPort(volatile STG4000REG __iomem *pSTGReg, /***************** Horizontal decimation/scaling ***************************/ /* - * Now we handle the horizontal case, this is a simplified verison of + * Now we handle the horizontal case, this is a simplified version of * the vertical case in that we decimate by factors of 2. as we are * working in words we should always be able to decimate by these * factors. as we always have to have a buffer which is aligned to a diff --git a/drivers/video/kyro/STG4000Reg.h b/drivers/video/kyro/STG4000Reg.h index 244549e61368..5d6269882589 100644 --- a/drivers/video/kyro/STG4000Reg.h +++ b/drivers/video/kyro/STG4000Reg.h @@ -16,7 +16,7 @@ /* * Macros that access memory mapped card registers in PCI space - * Add an appropraite section for your OS or processor architecture. + * Add an appropriate section for your OS or processor architecture. */ #if defined(__KERNEL__) #include diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h index c6ed7801efe2..1e6e45b57b78 100644 --- a/drivers/video/matrox/matroxfb_DAC1064.h +++ b/drivers/video/matrox/matroxfb_DAC1064.h @@ -46,7 +46,7 @@ void DAC1064_global_restore(struct matrox_fb_info *minfo); #define M1064_XDVICLKCTRL_DVILOOPCTL 0x30 /* CRTC2 pixel clock allowed to(0)/blocked from(1) driving CRTC2 */ #define M1064_XDVICLKCTRL_C2DVICLKEN 0x40 - /* P1PLL loop filter bandwith selection */ + /* P1PLL loop filter bandwidth selection */ #define M1064_XDVICLKCTRL_P1LOOPBWDTCTL 0x80 #define M1064_XCURCOL0RED 0x08 #define M1064_XCURCOL0GREEN 0x09 diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c index 835aaaae6b96..9a44cec394b5 100644 --- a/drivers/video/matrox/matroxfb_Ti3026.c +++ b/drivers/video/matrox/matroxfb_Ti3026.c @@ -387,7 +387,7 @@ static int Ti3026_init(struct matrox_fb_info *minfo, struct my_timming *m) hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_8BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; break; case 16: - /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */ + /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used every time) */ hw->DACreg[POS3026_XTRUECOLORCTRL] = (minfo->fbcon.var.green.length == 5) ? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565); hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT; hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2; @@ -399,7 +399,7 @@ static int Ti3026_init(struct matrox_fb_info *minfo, struct my_timming *m) hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV4; break; case 32: - /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used everytime) */ + /* XLATCHCTRL should be _2_1 / _1_1... Why is not? (_2_1 is used every time) */ hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_32BIT; break; default: diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 5ce6fa6e59f0..44bf8d4a216b 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -621,7 +621,7 @@ static int matroxfb_decode_var(const struct matrox_fb_info *minfo, var->yoffset = var->yres_virtual - var->yres; if (bpp == 16 && var->green.length == 5) { - bpp--; /* an artifical value - 15 */ + bpp--; /* an artificial value - 15 */ } for (rgbt = table; rgbt->bpp < bpp; rgbt++); diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h index f96a471cb1a8..11ed57bb704e 100644 --- a/drivers/video/matrox/matroxfb_base.h +++ b/drivers/video/matrox/matroxfb_base.h @@ -12,7 +12,7 @@ #undef MATROXFB_DEBUG /* heavy debugging: */ -/* -- logs putc[s], so everytime a char is displayed, it's logged */ +/* -- logs putc[s], so every time a char is displayed, it's logged */ #undef MATROXFB_DEBUG_HEAVY /* This one _could_ cause infinite loops */ diff --git a/drivers/video/nuc900fb.h b/drivers/video/nuc900fb.h index 6c23aa3d3b89..bc7c9300f276 100644 --- a/drivers/video/nuc900fb.h +++ b/drivers/video/nuc900fb.h @@ -8,7 +8,7 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * Auther: + * Author: * Wang Qiang(rurality.linux@gmail.com) 2009/12/16 */ diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig index 15e7f1912af9..196fa2e7f438 100644 --- a/drivers/video/omap/Kconfig +++ b/drivers/video/omap/Kconfig @@ -64,7 +64,7 @@ config FB_OMAP_MANUAL_UPDATE depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL help Say Y here, if your user-space applications are capable of - notifying the frame buffer driver when a change has occured in + notifying the frame buffer driver when a change has occurred in the frame buffer content and thus a reload of the image data to the external frame buffer is required. If unsure, say N. diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 0d44f070ef36..a981def8099a 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -587,7 +587,7 @@ static void get_edid_timing_data(u8 *edid) struct hdmi_cm cm; struct omap_video_timings edid_timings; - /* seach block 0, there are 4 DTDs arranged in priority order */ + /* search block 0, there are 4 DTDs arranged in priority order */ for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) { current_descriptor_addrs = EDID_DESCRIPTOR_BLOCK0_ADDRESS + diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index cf4beb9dc9bb..0283c7021090 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -25,7 +25,7 @@ /* * WARNING: This controller is attached to System Bus 2 of the PXA which - * needs its arbiter to be enabled explictly (CKENB & 1<<9). + * needs its arbiter to be enabled explicitly (CKENB & 1<<9). * There is currently no way to do this from Linux, so you need to teach * your bootloader for now. */ diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index e4c3f214eb8e..4e9490c19d7d 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h @@ -153,7 +153,7 @@ struct savage_reg { unsigned char CRTC[25]; /* Crtc Controller */ unsigned char Sequencer[5]; /* Video Sequencer */ unsigned char Graphics[9]; /* Video Graphics */ - unsigned char Attribute[21]; /* Video Atribute */ + unsigned char Attribute[21]; /* Video Attribute */ unsigned int mode, refresh; unsigned char SR08, SR0E, SR0F; diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 487911e2926c..a2dc1a7ec758 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -385,7 +385,7 @@ SavageSetup2DEngine(struct savagefb_par *par) BCI_SEND(GlobalBitmapDescriptor); /* - * I don't know why, sending this twice fixes the intial black screen, + * I don't know why, sending this twice fixes the initial black screen, * prevents X from crashing at least in Toshiba laptops with SavageIX. * --Tony */ @@ -2211,7 +2211,7 @@ static int __devinit savagefb_probe(struct pci_dev* dev, goto failed_mmio; video_len = savage_init_hw(par); - /* FIXME: cant be negative */ + /* FIXME: can't be negative */ if (video_len < 0) { err = video_len; goto failed_mmio; diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 46d1a64fe80d..56ef6b3a9851 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -265,7 +265,7 @@ static unsigned long sm501fb_ps_to_hz(unsigned long psvalue) return (unsigned long)numerator; } -/* sm501fb_hz_to_ps is identical to the oposite transform */ +/* sm501fb_hz_to_ps is identical to the opposite transform */ #define sm501fb_hz_to_ps(x) sm501fb_ps_to_hz(x) @@ -1719,7 +1719,7 @@ static int sm501fb_init_fb(struct fb_info *fb, (head == HEAD_CRT) ? &sm501fb_ops_crt : &sm501fb_ops_pnl, sizeof(struct fb_ops)); - /* update ops dependant on what we've been passed */ + /* update ops dependent on what we've been passed */ if ((pd->flags & SM501FB_FLAG_USE_HWCURSOR) == 0) par->ops.fb_cursor = NULL; diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c index 2ab704118c44..2301c275d63a 100644 --- a/drivers/video/sstfb.c +++ b/drivers/video/sstfb.c @@ -221,7 +221,7 @@ static int __sst_wait_idle(u8 __iomem *vbase) while(1) { if (__sst_read(vbase, STATUS) & STATUS_FBI_BUSY) { f_dddprintk("status: busy\n"); -/* FIXME basicaly, this is a busy wait. maybe not that good. oh well; +/* FIXME basically, this is a busy wait. maybe not that good. oh well; * this is a small loop after all. * Or maybe we should use mdelay() or udelay() here instead ? */ count = 0; @@ -501,7 +501,7 @@ static int sstfb_set_par(struct fb_info *info) } if (IS_VOODOO2(par)) { - /* voodoo2 has 32 pixel wide tiles , BUT stange things + /* voodoo2 has 32 pixel wide tiles , BUT strange things happen with odd number of tiles */ par->tiles_in_X = (info->var.xres + 63 ) / 64 * 2; } else { @@ -920,11 +920,11 @@ static int __devinit sst_detect_ti(struct fb_info *info) * we get the 1st byte (M value) of preset f1,f7 and fB * why those 3 ? mmmh... for now, i'll do it the glide way... * and ask questions later. anyway, it seems that all the freq registers are - * realy at their default state (cf specs) so i ask again, why those 3 regs ? + * really at their default state (cf specs) so i ask again, why those 3 regs ? * mmmmh.. it seems that's much more ugly than i thought. we use f0 and fA for * pll programming, so in fact, we *hope* that the f1, f7 & fB won't be * touched... - * is it realy safe ? how can i reset this ramdac ? geee... + * is it really safe ? how can i reset this ramdac ? geee... */ static int __devinit sst_detect_ics(struct fb_info *info) { diff --git a/drivers/video/sticore.h b/drivers/video/sticore.h index 7fe5be4bc70e..addf7b615ef8 100644 --- a/drivers/video/sticore.h +++ b/drivers/video/sticore.h @@ -79,7 +79,7 @@ struct sti_glob_cfg_ext { u8 curr_mon; /* current monitor configured */ u8 friendly_boot; /* in friendly boot mode */ s16 power; /* power calculation (in Watts) */ - s32 freq_ref; /* frequency refrence */ + s32 freq_ref; /* frequency reference */ u32 sti_mem_addr; /* pointer to global sti memory (size=sti_mem_request) */ u32 future_ptr; /* pointer to future data */ }; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 3ee5e63cfa4f..a99b994c9b6b 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -877,12 +877,12 @@ static void tdfxfb_fillrect(struct fb_info *info, else tdfx_rop = TDFX_ROP_XOR; - /* asume always rect->height < 4096 */ + /* assume always rect->height < 4096 */ if (dy + rect->height > 4095) { dstbase = stride * dy; dy = 0; } - /* asume always rect->width < 4096 */ + /* assume always rect->width < 4096 */ if (dx + rect->width > 4095) { dstbase += dx * bpp >> 3; dx = 0; @@ -915,22 +915,22 @@ static void tdfxfb_copyarea(struct fb_info *info, u32 dstbase = 0; u32 srcbase = 0; - /* asume always area->height < 4096 */ + /* assume always area->height < 4096 */ if (sy + area->height > 4095) { srcbase = stride * sy; sy = 0; } - /* asume always area->width < 4096 */ + /* assume always area->width < 4096 */ if (sx + area->width > 4095) { srcbase += sx * bpp >> 3; sx = 0; } - /* asume always area->height < 4096 */ + /* assume always area->height < 4096 */ if (dy + area->height > 4095) { dstbase = stride * dy; dy = 0; } - /* asume always area->width < 4096 */ + /* assume always area->width < 4096 */ if (dx + area->width > 4095) { dstbase += dx * bpp >> 3; dx = 0; @@ -1003,12 +1003,12 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) #else srcfmt = 0x400000; #endif - /* asume always image->height < 4096 */ + /* assume always image->height < 4096 */ if (dy + image->height > 4095) { dstbase = stride * dy; dy = 0; } - /* asume always image->width < 4096 */ + /* assume always image->width < 4096 */ if (dx + image->width > 4095) { dstbase += dx * bpp >> 3; dx = 0; @@ -1124,7 +1124,7 @@ static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor) * lower half (least significant 64 bits) of a 128 bit word * and pattern 1 the upper half. If you examine the data of * the cursor image the graphics card uses then from the - * begining you see line one of pattern 0, line one of + * beginning you see line one of pattern 0, line one of * pattern 1, line two of pattern 0, line two of pattern 1, * etc etc. The linear stride for the cursor is always 16 bytes * (128 bits) which is the maximum cursor width times two for diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index 9710bf8caeae..0c341d739604 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c @@ -359,7 +359,7 @@ tmiofb_acc_wait(struct fb_info *info, unsigned int ccs) { struct tmiofb_par *par = info->par; /* - * This code can be called whith interrupts disabled. + * This code can be called with interrupts disabled. * So instead of relaying on irq to trigger the event, * poll the state till the necessary command is executed. */ diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 2c8364e9b632..68041d9dc260 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -769,7 +769,7 @@ static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd, /* * If we have a damage-aware client, turn fb_defio "off" - * To avoid perf imact of unecessary page fault handling. + * To avoid perf imact of unnecessary page fault handling. * Done by resetting the delay for this fb_info to a very * long period. Pages will become writable and stay that way. * Reset to normal value when all clients have closed this fb. diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 28ccab44a391..53b2c5aae067 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -152,7 +152,7 @@ static inline int setop(int op) } /* Set the Enable Set/Reset Register and return its old value. - The code here always uses value 0xf for thsi register. */ + The code here always uses value 0xf for this register. */ static inline int setsr(int sr) { int oldsr; diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c index d05ccb62b55f..35458a5eadc8 100644 --- a/drivers/video/via/via_utility.c +++ b/drivers/video/via/via_utility.c @@ -174,7 +174,7 @@ void viafb_set_gamma_table(int bpp, unsigned int *gamma_table) } /* If adjust Gamma value in SAMM, fill IGA1, - IGA2 Gamma table simultanous. */ + IGA2 Gamma table simultaneous. */ /* Switch to IGA2 Gamma Table */ if ((active_device_amount > 1) && !((viaparinfo->chip_info->gfx_chip_name == diff --git a/drivers/video/via/via_utility.h b/drivers/video/via/via_utility.h index 1670ba82143f..f23be1708c14 100644 --- a/drivers/video/via/via_utility.h +++ b/drivers/video/via/via_utility.h @@ -21,7 +21,7 @@ #ifndef __VIAUTILITY_H__ #define __VIAUTILITY_H__ -/* These functions are used to get infomation about device's state */ +/* These functions are used to get information about device's state */ void viafb_get_device_support_state(u32 *support_state); void viafb_get_device_connect_state(u32 *connect_state); bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index f555b891cc72..b64818953aa7 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -2019,7 +2019,7 @@ int __init viafb_init(void) return -EINVAL; printk(KERN_INFO - "VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n", + "VIA Graphics Integration Chipset framebuffer %d.%d initializing\n", VERSION_MAJOR, VERSION_MINOR); return 0; } diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index d8b12c32e3ef..c8be8af0cc6d 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c @@ -1306,7 +1306,7 @@ static void w100_init_lcd(struct w100fb_par *par) union graphic_v_disp_u graphic_v_disp; union crtc_total_u crtc_total; - /* w3200 doesnt like undefined bits being set so zero register values first */ + /* w3200 doesn't like undefined bits being set so zero register values first */ active_h_disp.val = 0; active_h_disp.f.active_h_start=mode->left_margin; diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 38e96ab90945..5ef385bfed18 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -545,7 +545,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) return; } - /* Second write, data transfered. Release the module */ + /* Second write, data transferred. Release the module */ if (hdq_data->init_trans > 1) { omap_hdq_put(hdq_data); ret = mutex_lock_interruptible(&hdq_data->hdq_mutex); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b69d71482554..1b0f98bc51b5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -933,7 +933,7 @@ config PNX833X_WDT depends on SOC_PNX8335 help Hardware driver for the PNX833x's watchdog. This is a - watchdog timer that will reboot the machine after a programable + watchdog timer that will reboot the machine after a programmable timer has expired and no process has written to /dev/watchdog during that time. diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index d520bf9c3355..3f8608b922a7 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -4,7 +4,7 @@ # Only one watchdog can succeed. We probe the ISA/PCI/USB based # watchdog-cards first, then the architecture specific watchdog -# drivers and then the architecture independant "softdog" driver. +# drivers and then the architecture independent "softdog" driver. # This means that if your ISA/PCI/USB card isn't detected that # you can fall back to an architecture specific driver and if # that also fails then you can fall back to the software watchdog @@ -153,7 +153,7 @@ obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o # Xen obj-$(CONFIG_XEN_WDT) += xen_wdt.o -# Architecture Independant +# Architecture Independent obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c index 2ffce4d75443..b6a2b58cbe64 100644 --- a/drivers/watchdog/acquirewdt.c +++ b/drivers/watchdog/acquirewdt.c @@ -26,7 +26,7 @@ * Theory of Operation: * The Watch-Dog Timer is provided to ensure that standalone * Systems can always recover from catastrophic conditions that - * caused the CPU to crash. This condition may have occured by + * caused the CPU to crash. This condition may have occurred by * external EMI or a software bug. When the CPU stops working * correctly, hardware on the board will either perform a hardware * reset (cold boot) or a non-maskable interrupt (NMI) to bring the diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c index 139d773300c6..b7c139051575 100644 --- a/drivers/watchdog/pc87413_wdt.c +++ b/drivers/watchdog/pc87413_wdt.c @@ -49,7 +49,7 @@ #define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1) #define SWC_LDN 0x04 #define SIOCFG2 0x22 /* Serial IO register */ -#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */ +#define WDCTL 0x10 /* Watchdog-Timer-Control-Register */ #define WDTO 0x11 /* Watchdog timeout register */ #define WDCFG 0x12 /* Watchdog config register */ diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c index 67ddeb1c830a..ff11504c376e 100644 --- a/drivers/watchdog/sbc7240_wdt.c +++ b/drivers/watchdog/sbc7240_wdt.c @@ -273,7 +273,7 @@ static int __init sbc7240_wdt_init(void) /* The IO port 0x043 used to disable the watchdog * is already claimed by the system timer, so we - * cant request_region() it ...*/ + * can't request_region() it ...*/ if (timeout < 1 || timeout > SBC7240_MAX_TIMEOUT) { timeout = SBC7240_TIMEOUT; diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c index b61ab1c54293..c7cf4b01f58d 100644 --- a/drivers/watchdog/sch311x_wdt.c +++ b/drivers/watchdog/sch311x_wdt.c @@ -201,7 +201,7 @@ static void sch311x_wdt_get_status(int *status) spin_lock(&sch311x_wdt_data.io_lock); /* -- Watchdog timer control -- - * Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured + * Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occurred * Bit 1 Reserved * Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) * Bit 3 P20 Force Timeout enabled: diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 4e3e7eb5919c..db84f2322d1a 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c @@ -50,7 +50,7 @@ * necssary. * * As a result of this timing problem, the only modes that are particularly - * feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms + * feasible are the 4096 and the 2048 divisors, which yield 5.25 and 2.62ms * overflow periods respectively. * * Also, since we can't really expect userspace to be responsive enough diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c index df88cfa05f35..e97b0499bd0d 100644 --- a/drivers/watchdog/smsc37b787_wdt.c +++ b/drivers/watchdog/smsc37b787_wdt.c @@ -191,7 +191,7 @@ static inline void wdt_timer_conf(unsigned char conf) static inline void wdt_timer_ctrl(unsigned char reg) { /* -- Watchdog timer control -- - * Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured + * Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occurred * Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz * Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning) * Bit 3 P20 Force Timeout enabled: diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 0a0efe713bc8..0d80e08b6439 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -90,7 +90,7 @@ static void wdt_setload(unsigned int timeout) /* * sp805 runs counter with given value twice, after the end of first * counter it gives an interrupt and then starts counter again. If - * interrupt already occured then it resets the system. This is why + * interrupt already occurred then it resets the system. This is why * load is half of what should be required. */ load = div_u64(rate, 2) * timeout - 1; diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 036343ba204e..42d6c930cc87 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -5,7 +5,7 @@ * domain gets 1024 event channels, but NR_IRQ is not that large, we * must dynamically map irqs<->event channels. The event channels * interface with the rest of the kernel by defining a xen interrupt - * chip. When an event is recieved, it is mapped to an irq and sent + * chip. When an event is received, it is mapped to an irq and sent * through the normal interrupt processing path. * * There are four kinds of events which can be mapped to an event @@ -416,7 +416,7 @@ static int __must_check xen_allocate_irq_dynamic(void) #ifdef CONFIG_X86_IO_APIC /* * For an HVM guest or domain 0 which see "real" (emulated or - * actual repectively) GSIs we allocate dynamic IRQs + * actual respectively) GSIs we allocate dynamic IRQs * e.g. those corresponding to event channels or MSIs * etc. from the range above those "real" GSIs to avoid * collisions. -- cgit v1.2.2 From ba43861277f1858472de4adfc0b28a047484da83 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Thu, 24 Mar 2011 18:17:14 -0500 Subject: gpio/ml_ioh_gpio: Fix output value of ioh_gpio_direction_output() The ioh_gpio_direction_output() function was missing a write to set the desired output value. The function would properly set the GPIO direction, but not the output value. The value would have to manually be set with a follow up call to ioh_gpio_set(). Add the missing write so that ioh_gpio_direction_output() sets both the GPIO direction and value. Signed-off-by: Peter Tyser Tested-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/gpio/ml_ioh_gpio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c index 7f6f01a4b145..0a775f7987c2 100644 --- a/drivers/gpio/ml_ioh_gpio.c +++ b/drivers/gpio/ml_ioh_gpio.c @@ -116,6 +116,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, reg_val |= (1 << nr); else reg_val &= ~(1 << nr); + iowrite32(reg_val, &chip->reg->regs[chip->ch].po); mutex_unlock(&chip->lock); -- cgit v1.2.2 From 88aab9341a315d81118be6b41c45e4fe32b94bc1 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Fri, 25 Mar 2011 10:04:00 -0500 Subject: gpio/pch_gpio: Fix output value of pch_gpio_direction_output() The pch_gpio_direction_output() function was missing a write to set the desired output value. The function would properly set the GPIO direction, but not the output value. The value would have to manually be set with a follow up call to pch_gpio_set(). Add the missing write so that pch_gpio_direction_output() sets both the GPIO direction and value. Signed-off-by: Peter Tyser Tested-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/gpio/pch_gpio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpio/pch_gpio.c b/drivers/gpio/pch_gpio.c index 2c6af8705103..f970a5f3585e 100644 --- a/drivers/gpio/pch_gpio.c +++ b/drivers/gpio/pch_gpio.c @@ -105,6 +105,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, reg_val |= (1 << nr); else reg_val &= ~(1 << nr); + iowrite32(reg_val, &chip->reg->po); mutex_unlock(&chip->lock); -- cgit v1.2.2 From 92ce52695ccf2b6c4ef7eb02e1bee1bcbf5fde89 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 28 Mar 2011 12:23:05 -0300 Subject: [media] staging: altera-jtag needs delay.h altera-jtag.c needs to include to fix a build error: drivers/staging/altera-stapl/altera-jtag.c:398: error: implicit declaration of function 'udelay' Signed-off-by: Randy Dunlap Cc: Igor M. Liplianin Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/altera-stapl/altera-jtag.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/altera-stapl/altera-jtag.c b/drivers/staging/altera-stapl/altera-jtag.c index 6b633b179a7e..876308858b82 100644 --- a/drivers/staging/altera-stapl/altera-jtag.c +++ b/drivers/staging/altera-stapl/altera-jtag.c @@ -23,6 +23,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include -- cgit v1.2.2 From 6705a9cc52733cb5cbdbee72be66ab462d8fb46f Mon Sep 17 00:00:00 2001 From: Manjunatha Halli Date: Wed, 23 Mar 2011 07:44:30 -0300 Subject: [media] radio: wl128x: Update registration process with ST As underlying ST driver registration API's have changed with latest 2.6.38-rc8 kernel this patch will update the FM driver accordingly. Signed-off-by: Manjunatha Halli Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 64454d39c0ca..ecfd9fb167d8 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -1494,12 +1494,17 @@ u32 fmc_prepare(struct fmdev *fmdev) } memset(&fm_st_proto, 0, sizeof(fm_st_proto)); - fm_st_proto.type = ST_FM; fm_st_proto.recv = fm_st_receive; fm_st_proto.match_packet = NULL; fm_st_proto.reg_complete_cb = fm_st_reg_comp_cb; fm_st_proto.write = NULL; /* TI ST driver will fill write pointer */ fm_st_proto.priv_data = fmdev; + fm_st_proto.chnl_id = 0x08; + fm_st_proto.max_frame_size = 0xff; + fm_st_proto.hdr_len = 1; + fm_st_proto.offset_len_in_hdr = 0; + fm_st_proto.len_size = 1; + fm_st_proto.reserve = 1; ret = st_register(&fm_st_proto); if (ret == -EINPROGRESS) { @@ -1532,7 +1537,7 @@ u32 fmc_prepare(struct fmdev *fmdev) g_st_write = fm_st_proto.write; } else { fmerr("Failed to get ST write func pointer\n"); - ret = st_unregister(ST_FM); + ret = st_unregister(&fm_st_proto); if (ret < 0) fmerr("st_unregister failed %d\n", ret); return -EAGAIN; @@ -1586,6 +1591,7 @@ u32 fmc_prepare(struct fmdev *fmdev) */ u32 fmc_release(struct fmdev *fmdev) { + static struct st_proto_s fm_st_proto; u32 ret; if (!test_bit(FM_CORE_READY, &fmdev->flag)) { @@ -1604,7 +1610,11 @@ u32 fmc_release(struct fmdev *fmdev) fmdev->resp_comp = NULL; fmdev->rx.freq = 0; - ret = st_unregister(ST_FM); + memset(&fm_st_proto, 0, sizeof(fm_st_proto)); + fm_st_proto.chnl_id = 0x08; + + ret = st_unregister(&fm_st_proto); + if (ret < 0) fmerr("Failed to de-register FM from ST %d\n", ret); else -- cgit v1.2.2 From 97ea530f6fac1f9632b0c4792a2a56411454adbe Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Thu, 24 Mar 2011 23:28:31 +0000 Subject: drm/radeon/kms: add some sanity checks to obj info record parsingi (v2) Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=35502 agd5f: also add sanity check to connector records. v2: fix one more case. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 02d5c415f499..99768d9d91da 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -675,7 +675,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) ATOM_ENCODER_CAP_RECORD *cap_record; u16 caps = 0; - while (record->ucRecordType > 0 && + while (record->ucRecordSize > 0 && + record->ucRecordType > 0 && record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { switch (record->ucRecordType) { case ATOM_ENCODER_CAP_RECORD_TYPE: @@ -720,7 +721,8 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) break; } - while (record->ucRecordType > 0 && + while (record->ucRecordSize > 0 && + record->ucRecordType > 0 && record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { switch (record->ucRecordType) { case ATOM_I2C_RECORD_TYPE: @@ -782,10 +784,9 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev) ATOM_HPD_INT_RECORD *hpd_record; ATOM_I2C_ID_CONFIG_ACCESS *i2c_config; - while (record->ucRecordType > 0 - && record-> - ucRecordType <= - ATOM_MAX_OBJECT_RECORD_NUMBER) { + while (record->ucRecordSize > 0 && + record->ucRecordType > 0 && + record->ucRecordType <= ATOM_MAX_OBJECT_RECORD_NUMBER) { switch (record->ucRecordType) { case ATOM_I2C_RECORD_TYPE: i2c_record = -- cgit v1.2.2 From eccaca28e29861a63ebc067bfff59c7efa427371 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 30 Mar 2011 05:03:47 +0000 Subject: drm: export drm_find_cea_extension to drivers Nouveau needs access to this structure to build an ELD block for use by the HDA audio codec. Signed-off-by: Ben Skeggs Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_edid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9c595e3b9c20..adc9358c9bec 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1297,7 +1297,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, /** * Search EDID for CEA extension block. */ -static u8 *drm_find_cea_extension(struct edid *edid) +u8 *drm_find_cea_extension(struct edid *edid) { u8 *edid_ext = NULL; int i; @@ -1318,6 +1318,7 @@ static u8 *drm_find_cea_extension(struct edid *edid) return edid_ext; } +EXPORT_SYMBOL(drm_find_cea_extension); /** * drm_detect_hdmi_monitor - detect whether monitor is hdmi. -- cgit v1.2.2 From 65e646ac509ff45e9f35e7fc1fea0d2b6723679f Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 7 Mar 2011 17:02:49 +1100 Subject: powerpc/pmac: Rename cpu_state in therm_pm72 to avoid collision This collides with the cpu_state in our SMP code, use processor_state instead. Signed-off-by: Benjamin Herrenschmidt --- drivers/macintosh/therm_pm72.c | 60 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index bca2af2e3760..c987033714f6 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -153,7 +153,7 @@ static struct i2c_adapter * u3_0; static struct i2c_adapter * u3_1; static struct i2c_adapter * k2; static struct i2c_client * fcu; -static struct cpu_pid_state cpu_state[2]; +static struct cpu_pid_state processor_state[2]; static struct basckside_pid_params backside_params; static struct backside_pid_state backside_state; static struct drives_pid_state drives_state; @@ -664,8 +664,8 @@ static int read_eeprom(int cpu, struct mpu_data *out) static void fetch_cpu_pumps_minmax(void) { - struct cpu_pid_state *state0 = &cpu_state[0]; - struct cpu_pid_state *state1 = &cpu_state[1]; + struct cpu_pid_state *state0 = &processor_state[0]; + struct cpu_pid_state *state1 = &processor_state[1]; u16 pump_min = 0, pump_max = 0xffff; u16 tmp[4]; @@ -717,17 +717,17 @@ static ssize_t show_##name(struct device *dev, struct device_attribute *attr, ch return sprintf(buf, "%d", data); \ } -BUILD_SHOW_FUNC_FIX(cpu0_temperature, cpu_state[0].last_temp) -BUILD_SHOW_FUNC_FIX(cpu0_voltage, cpu_state[0].voltage) -BUILD_SHOW_FUNC_FIX(cpu0_current, cpu_state[0].current_a) -BUILD_SHOW_FUNC_INT(cpu0_exhaust_fan_rpm, cpu_state[0].rpm) -BUILD_SHOW_FUNC_INT(cpu0_intake_fan_rpm, cpu_state[0].intake_rpm) +BUILD_SHOW_FUNC_FIX(cpu0_temperature, processor_state[0].last_temp) +BUILD_SHOW_FUNC_FIX(cpu0_voltage, processor_state[0].voltage) +BUILD_SHOW_FUNC_FIX(cpu0_current, processor_state[0].current_a) +BUILD_SHOW_FUNC_INT(cpu0_exhaust_fan_rpm, processor_state[0].rpm) +BUILD_SHOW_FUNC_INT(cpu0_intake_fan_rpm, processor_state[0].intake_rpm) -BUILD_SHOW_FUNC_FIX(cpu1_temperature, cpu_state[1].last_temp) -BUILD_SHOW_FUNC_FIX(cpu1_voltage, cpu_state[1].voltage) -BUILD_SHOW_FUNC_FIX(cpu1_current, cpu_state[1].current_a) -BUILD_SHOW_FUNC_INT(cpu1_exhaust_fan_rpm, cpu_state[1].rpm) -BUILD_SHOW_FUNC_INT(cpu1_intake_fan_rpm, cpu_state[1].intake_rpm) +BUILD_SHOW_FUNC_FIX(cpu1_temperature, processor_state[1].last_temp) +BUILD_SHOW_FUNC_FIX(cpu1_voltage, processor_state[1].voltage) +BUILD_SHOW_FUNC_FIX(cpu1_current, processor_state[1].current_a) +BUILD_SHOW_FUNC_INT(cpu1_exhaust_fan_rpm, processor_state[1].rpm) +BUILD_SHOW_FUNC_INT(cpu1_intake_fan_rpm, processor_state[1].intake_rpm) BUILD_SHOW_FUNC_FIX(backside_temperature, backside_state.last_temp) BUILD_SHOW_FUNC_INT(backside_fan_pwm, backside_state.pwm) @@ -919,8 +919,8 @@ static void do_cpu_pid(struct cpu_pid_state *state, s32 temp, s32 power) static void do_monitor_cpu_combined(void) { - struct cpu_pid_state *state0 = &cpu_state[0]; - struct cpu_pid_state *state1 = &cpu_state[1]; + struct cpu_pid_state *state0 = &processor_state[0]; + struct cpu_pid_state *state1 = &processor_state[1]; s32 temp0, power0, temp1, power1; s32 temp_combi, power_combi; int rc, intake, pump; @@ -1150,7 +1150,7 @@ static void do_monitor_cpu_rack(struct cpu_pid_state *state) /* * Initialize the state structure for one CPU control loop */ -static int init_cpu_state(struct cpu_pid_state *state, int index) +static int init_processor_state(struct cpu_pid_state *state, int index) { int err; @@ -1205,7 +1205,7 @@ static int init_cpu_state(struct cpu_pid_state *state, int index) /* * Dispose of the state data for one CPU control loop */ -static void dispose_cpu_state(struct cpu_pid_state *state) +static void dispose_processor_state(struct cpu_pid_state *state) { if (state->monitor == NULL) return; @@ -1804,9 +1804,9 @@ static int main_control_loop(void *x) set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM); /* Initialize ADCs */ - initialize_adc(&cpu_state[0]); - if (cpu_state[1].monitor != NULL) - initialize_adc(&cpu_state[1]); + initialize_adc(&processor_state[0]); + if (processor_state[1].monitor != NULL) + initialize_adc(&processor_state[1]); fcu_tickle_ticks = FCU_TICKLE_TICKS; @@ -1833,14 +1833,14 @@ static int main_control_loop(void *x) if (cpu_pid_type == CPU_PID_TYPE_COMBINED) do_monitor_cpu_combined(); else if (cpu_pid_type == CPU_PID_TYPE_RACKMAC) { - do_monitor_cpu_rack(&cpu_state[0]); - if (cpu_state[1].monitor != NULL) - do_monitor_cpu_rack(&cpu_state[1]); + do_monitor_cpu_rack(&processor_state[0]); + if (processor_state[1].monitor != NULL) + do_monitor_cpu_rack(&processor_state[1]); // better deal with UP } else { - do_monitor_cpu_split(&cpu_state[0]); - if (cpu_state[1].monitor != NULL) - do_monitor_cpu_split(&cpu_state[1]); + do_monitor_cpu_split(&processor_state[0]); + if (processor_state[1].monitor != NULL) + do_monitor_cpu_split(&processor_state[1]); // better deal with UP } /* Then, the rest */ @@ -1885,8 +1885,8 @@ static int main_control_loop(void *x) */ static void dispose_control_loops(void) { - dispose_cpu_state(&cpu_state[0]); - dispose_cpu_state(&cpu_state[1]); + dispose_processor_state(&processor_state[0]); + dispose_processor_state(&processor_state[1]); dispose_backside_state(&backside_state); dispose_drives_state(&drives_state); dispose_slots_state(&slots_state); @@ -1928,12 +1928,12 @@ static int create_control_loops(void) /* Create control loops for everything. If any fail, everything * fails */ - if (init_cpu_state(&cpu_state[0], 0)) + if (init_processor_state(&processor_state[0], 0)) goto fail; if (cpu_pid_type == CPU_PID_TYPE_COMBINED) fetch_cpu_pumps_minmax(); - if (cpu_count > 1 && init_cpu_state(&cpu_state[1], 1)) + if (cpu_count > 1 && init_processor_state(&processor_state[1], 1)) goto fail; if (init_backside_state(&backside_state)) goto fail; -- cgit v1.2.2 From 26fcd2a7618db6c16be6aa3e56c0f3c25381e5a3 Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Thu, 31 Mar 2011 22:39:43 -0700 Subject: Input: wacom - add support for Lenovo tablet ID (0xE6) Signed-off-by: Manoj Iyer Acked-by: Ping Cheng Signed-off-by: Dmitry Torokhov --- drivers/input/tablet/wacom_wac.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index c87d94ff6ae4..08ba5ad9c9be 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1439,6 +1439,9 @@ static const struct wacom_features wacom_features_0xE2 = static const struct wacom_features wacom_features_0xE3 = { "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0xE6 = + { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, + 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1561,6 +1564,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x9F) }, { USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE3) }, + { USB_DEVICE_WACOM(0xE6) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_LENOVO(0x6004) }, { } -- cgit v1.2.2 From 2130ad32a03f8d2d772cbbd94eff5358d8ab9e33 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 29 Mar 2011 12:35:23 -0700 Subject: mtd: mtdswap: fix printk format warning The number is actually a sizeof(), so using %zu for it builds cleanly on 32-bit or 64-bit. drivers/mtd/mtdswap.c:1456: warning: format '%lu' expects type 'long unsigned int', but argument 4 has type 'unsigned int' Signed-off-by: Randy Dunlap Signed-off-by: Artem Bityutskiy --- drivers/mtd/mtdswap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index 237913c5c92c..fed215c4cfa1 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -1452,7 +1452,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) oinfo = mtd->ecclayout; if (!mtd->oobsize || !oinfo || oinfo->oobavail < MTDSWAP_OOBSIZE) { printk(KERN_ERR "%s: Not enough free bytes in OOB, " - "%d available, %lu needed.\n", + "%d available, %zu needed.\n", MTDSWAP_PREFIX, oinfo->oobavail, MTDSWAP_OOBSIZE); return; } -- cgit v1.2.2 From 042bc9c0c434b61241ceda1d332e3076e2571859 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 30 Mar 2011 16:26:40 +0800 Subject: mtd: atmel_nand: trivial: change DMA usage information trace Signed-off-by: Nicolas Ferre Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 6fae04b3fc6d..7e88a801669c 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -611,7 +611,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev) } } if (use_dma) - dev_info(host->dev, "Using DMA for NAND access.\n"); + dev_info(host->dev, "Using %s for DMA transfers.\n", + dma_chan_name(host->dma_chan)); else dev_info(host->dev, "No DMA support for NAND access.\n"); -- cgit v1.2.2 From cb457a4ddd4eeac9c81792a1e6a5d59b1b44abe1 Mon Sep 17 00:00:00 2001 From: Hong Xu Date: Wed, 30 Mar 2011 16:26:41 +0800 Subject: mtd: atmel_nand: fix support for CPUs that do not support DMA access use_dma was always "1" even if the CPU does not support DMA Tested on AT91SAM9261EK by Jean-Christophe PLAGNIOL-VILLARD Reported-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Hong Xu Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 7e88a801669c..f254fa636afc 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -599,7 +599,10 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->options |= NAND_USE_FLASH_BBT; } - if (cpu_has_dma() && use_dma) { + if (!cpu_has_dma()) + use_dma = 0; + + if (use_dma) { dma_cap_mask_t mask; dma_cap_zero(mask); -- cgit v1.2.2 From 9d51567e47a0d84f6b6e7751a4ea4f710cdcbbdf Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 1 Apr 2011 16:40:44 +0200 Subject: mtd: atmel_nand: modify test case for using DMA operations We have better performances not using DMA for oob operations. Modify size test so that it is using DMA for size greater than oobsize. Signed-off-by: Nicolas Ferre Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index f254fa636afc..e9fdbe46b247 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -280,7 +280,8 @@ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) struct nand_chip *chip = mtd->priv; struct atmel_nand_host *host = chip->priv; - if (use_dma && len >= mtd->oobsize) + if (use_dma && len > mtd->oobsize) + /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) return; @@ -295,7 +296,8 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) struct nand_chip *chip = mtd->priv; struct atmel_nand_host *host = chip->priv; - if (use_dma && len >= mtd->oobsize) + if (use_dma && len > mtd->oobsize) + /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) return; -- cgit v1.2.2 From 1478d82df822f5d895d810f2b11ec9d373b63bc0 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Fri, 1 Apr 2011 13:56:00 +0200 Subject: HID: add FF support for Logitech G25/G27 Small patch to add support for the G25/G27 by adding USB ID's as suggested by Peter. Boots but otherwise untested as I don't have hardware, .debs for kernel (2.6.38) here if want to test/run Ubuntu/Debian: http://www.mungewell.org/Logitech_Wii_Wheel/ Reported-by: Peter Gundermann Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-lgff.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 90d0ef2c92be..f099079ca6b9 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -73,6 +73,8 @@ static const struct dev_type devices[] = { { 0x046d, 0xc293, ff_joystick }, { 0x046d, 0xc294, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, + { 0x046d, 0xc298, ff_wheel }, + { 0x046d, 0xc299, ff_wheel }, { 0x046d, 0xca03, ff_wheel }, }; -- cgit v1.2.2 From 80b4f81a49809774f1b123c456fb179e472dbd0e Mon Sep 17 00:00:00 2001 From: Hong Xu Date: Thu, 31 Mar 2011 18:33:15 +0800 Subject: mtd: atmel_nand: use CPU I/O when buffer is in vmalloc(ed) region The previous way of dealing with vmalloc(ed) region by walking though the pages can not work well actually. We just fall back to CPU I/O when the buffer address is higher than `high_memory'. Signed-off-by: Nicolas Ferre Signed-off-by: Hong Xu Signed-off-by: Artem Bityutskiy --- drivers/mtd/nand/atmel_nand.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e9fdbe46b247..950646aa4c4b 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -209,22 +209,8 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len, int err = -EIO; enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - if (buf >= high_memory) { - struct page *pg; - - if (((size_t)buf & PAGE_MASK) != - ((size_t)(buf + len - 1) & PAGE_MASK)) { - dev_warn(host->dev, "Buffer not fit in one page\n"); - goto err_buf; - } - - pg = vmalloc_to_page(buf); - if (pg == 0) { - dev_err(host->dev, "Failed to vmalloc_to_page\n"); - goto err_buf; - } - p = page_address(pg) + ((size_t)buf & ~PAGE_MASK); - } + if (buf >= high_memory) + goto err_buf; dma_dev = host->dma_chan->device; -- cgit v1.2.2 From 58a9f397ac9288403d600b22b8472c0d164ee8cb Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 30 Mar 2011 16:32:32 +0200 Subject: asus-wmi: swap input name and phys Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index efc776cb0c66..832a3fd7c1c8 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -201,8 +201,8 @@ static int asus_wmi_input_init(struct asus_wmi *asus) if (!asus->inputdev) return -ENOMEM; - asus->inputdev->name = asus->driver->input_phys; - asus->inputdev->phys = asus->driver->input_name; + asus->inputdev->name = asus->driver->input_name; + asus->inputdev->phys = asus->driver->input_phys; asus->inputdev->id.bustype = BUS_HOST; asus->inputdev->dev.parent = &asus->platform_device->dev; -- cgit v1.2.2 From 9481472559b3ecd366390786628c2fb211d1477b Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Wed, 30 Mar 2011 16:32:33 +0200 Subject: eeepc-wmi: add keys found on EeePC 1215T Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-wmi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index 0ddc434fb93b..649dcadd8ea3 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -67,9 +67,11 @@ static const struct key_entry eeepc_wmi_keymap[] = { { KE_KEY, 0x82, { KEY_CAMERA } }, { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, { KE_KEY, 0x88, { KEY_WLAN } }, + { KE_KEY, 0xbd, { KEY_CAMERA } }, { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ + { KE_KEY, 0xe8, { KEY_SCREENLOCK } }, { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, { KE_KEY, 0xec, { KEY_CAMERA_UP } }, -- cgit v1.2.2 From a0bcaee99df69b6d4d4dfd30bd40ac24b5ad3e22 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 30 Mar 2011 15:20:22 -0700 Subject: msi-laptop: fix config-dependent build error The msi-laptop driver uses input_*() and sparse_keymap_*() interfaces. It should depend on the INPUT subsystem being present and select INPUT_SPARSEKMAP so that those interfaces are present. ERROR: "input_free_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "input_register_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "sparse_keymap_setup" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "input_allocate_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "sparse_keymap_report_event" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "input_unregister_device" [drivers/platform/x86/msi-laptop.ko] undefined! ERROR: "sparse_keymap_free" [drivers/platform/x86/msi-laptop.ko] undefined! Signed-off-by: Randy Dunlap Cc: Matthew Garrett Cc: "Lee, Chun-Yi" Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2ee442c2a5db..0485e394712a 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -187,7 +187,8 @@ config MSI_LAPTOP depends on ACPI depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL - depends on SERIO_I8042 + depends on INPUT && SERIO_I8042 + select INPUT_SPARSEKMAP ---help--- This is a driver for laptops built by MSI (MICRO-STAR INTERNATIONAL): -- cgit v1.2.2 From 1591cb60838603c8cc2c540192c8244962436539 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 1 Apr 2011 05:27:51 +0000 Subject: starfire: clean up dma_addr_t size test Now we have CONFIG_ARCH_DMA_ADDR_T_64BIT. We can fix the hacky dma_addr_t size test cleanly. Signed-off-by: FUJITA Tomonori Signed-off-by: David S. Miller --- drivers/net/starfire.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index a4f2bd52e546..36045f3b0327 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -144,11 +144,7 @@ static int full_duplex[MAX_UNITS] = {0, }; /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2 * HZ) -/* - * 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(CONFIG_MIPS) && ((defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR)) || defined(CONFIG_64BIT))) || (defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)) +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT /* 64-bit dma_addr_t */ #define ADDR_64BITS /* This chip uses 64 bit addresses. */ #define netdrv_addr_t __le64 -- cgit v1.2.2 From c261344d3ce3edac781f9d3c7eabe2e96d8e8fe8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 1 Apr 2011 20:12:02 -0700 Subject: usbnet: use eth%d name for known ethernet devices The documentation for the USB ethernet devices suggests that only some devices are supposed to use usb0 as the network interface name instead of eth0. The logic used there, and documented in Kconfig for CDC is that eth0 will be used when the mac address is a globally assigned one, but usb0 is used for the locally managed range that is typically used on point-to-point links. Unfortunately, this has caused a lot of pain on the smsc95xx device that is used on the popular pandaboard without an EEPROM to store the MAC address, which causes the driver to call random_ether_address(). Obviously, there should be a proper MAC addressed assigned to the device, and discussions are ongoing about how to solve this, but this patch at least makes sure that the default interface naming gets a little saner and matches what the user can expect based on the documentation, including for new devices. The approach taken here is to flag whether a device might be a point-to-point link with the new FLAG_POINTTOPOINT setting in the usbnet driver_info. A driver can set both FLAG_POINTTOPOINT and FLAG_ETHER if it is not sure (e.g. cdc_ether), or just one of the two. The usbnet framework only looks at the MAC address for device naming if both flags are set, otherwise it trusts the flag. Signed-off-by: Arnd Bergmann Tested-by: Andy Green Signed-off-by: David S. Miller --- drivers/net/usb/cdc_eem.c | 2 +- drivers/net/usb/cdc_ether.c | 2 +- drivers/net/usb/cdc_ncm.c | 2 +- drivers/net/usb/cdc_subset.c | 8 ++++++++ drivers/net/usb/gl620a.c | 2 +- drivers/net/usb/net1080.c | 2 +- drivers/net/usb/plusb.c | 2 +- drivers/net/usb/rndis_host.c | 2 +- drivers/net/usb/usbnet.c | 3 ++- drivers/net/usb/zaurus.c | 8 ++++---- 10 files changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 5f3b97668e63..8f128541656d 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -340,7 +340,7 @@ next: static const struct driver_info eem_info = { .description = "CDC EEM Device", - .flags = FLAG_ETHER, + .flags = FLAG_ETHER | FLAG_POINTTOPOINT, .bind = eem_bind, .rx_fixup = eem_rx_fixup, .tx_fixup = eem_tx_fixup, diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 51c259b69278..341f7056a800 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -452,7 +452,7 @@ static int cdc_manage_power(struct usbnet *dev, int on) static const struct driver_info cdc_info = { .description = "CDC Ethernet Device", - .flags = FLAG_ETHER, + .flags = FLAG_ETHER | FLAG_POINTTOPOINT, // .check_connect = cdc_check_connect, .bind = usbnet_cdc_bind, .unbind = usbnet_cdc_unbind, diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 7113168473cf..967371f04454 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1237,7 +1237,7 @@ static int cdc_ncm_manage_power(struct usbnet *dev, int status) static const struct driver_info cdc_ncm_info = { .description = "CDC NCM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET, + .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET, .bind = cdc_ncm_bind, .unbind = cdc_ncm_unbind, .check_connect = cdc_ncm_check_connect, diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index ca39ace0b0eb..fc5f13d47ad9 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -89,6 +89,7 @@ static int always_connected (struct usbnet *dev) static const struct driver_info ali_m5632_info = { .description = "ALi M5632", + .flags = FLAG_POINTTOPOINT, }; #endif @@ -110,6 +111,7 @@ static const struct driver_info ali_m5632_info = { static const struct driver_info an2720_info = { .description = "AnchorChips/Cypress 2720", + .flags = FLAG_POINTTOPOINT, // no reset available! // no check_connect available! @@ -132,6 +134,7 @@ static const struct driver_info an2720_info = { static const struct driver_info belkin_info = { .description = "Belkin, eTEK, or compatible", + .flags = FLAG_POINTTOPOINT, }; #endif /* CONFIG_USB_BELKIN */ @@ -157,6 +160,7 @@ static const struct driver_info belkin_info = { static const struct driver_info epson2888_info = { .description = "Epson USB Device", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, .in = 4, .out = 3, }; @@ -173,6 +177,7 @@ static const struct driver_info epson2888_info = { #define HAVE_HARDWARE static const struct driver_info kc2190_info = { .description = "KC Technology KC-190", + .flags = FLAG_POINTTOPOINT, }; #endif /* CONFIG_USB_KC2190 */ @@ -200,16 +205,19 @@ static const struct driver_info kc2190_info = { static const struct driver_info linuxdev_info = { .description = "Linux Device", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, }; static const struct driver_info yopy_info = { .description = "Yopy", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, }; static const struct driver_info blob_info = { .description = "Boot Loader OBject", .check_connect = always_connected, + .flags = FLAG_POINTTOPOINT, }; #endif /* CONFIG_USB_ARMLINUX */ diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index dcd57c37ef73..c4cfd1dea881 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -193,7 +193,7 @@ static int genelink_bind(struct usbnet *dev, struct usb_interface *intf) static const struct driver_info genelink_info = { .description = "Genesys GeneLink", - .flags = FLAG_FRAMING_GL | FLAG_NO_SETINT, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_GL | FLAG_NO_SETINT, .bind = genelink_bind, .rx_fixup = genelink_rx_fixup, .tx_fixup = genelink_tx_fixup, diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index ba72a7281cb0..01db4602a39e 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -560,7 +560,7 @@ static int net1080_bind(struct usbnet *dev, struct usb_interface *intf) static const struct driver_info net1080_info = { .description = "NetChip TurboCONNECT", - .flags = FLAG_FRAMING_NC, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_NC, .bind = net1080_bind, .reset = net1080_reset, .check_connect = net1080_check_connect, diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 08ad269f6b4e..823c53751307 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -96,7 +96,7 @@ static int pl_reset(struct usbnet *dev) static const struct driver_info prolific_info = { .description = "Prolific PL-2301/PL-2302", - .flags = FLAG_NO_SETINT, + .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT, /* some PL-2302 versions seem to fail usb_set_interface() */ .reset = pl_reset, }; diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index dd8a4adf48ca..5994a25c56ac 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -573,7 +573,7 @@ EXPORT_SYMBOL_GPL(rndis_tx_fixup); static const struct driver_info rndis_info = { .description = "RNDIS device", - .flags = FLAG_ETHER | FLAG_FRAMING_RN | FLAG_NO_SETINT, + .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT, .bind = rndis_bind, .unbind = rndis_unbind, .status = rndis_status, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index cf58b7682565..069c1cf0fdf7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1380,7 +1380,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) // else "eth%d" when there's reasonable doubt. userspace // can rename the link if it knows better. if ((dev->driver_info->flags & FLAG_ETHER) != 0 && - (net->dev_addr [0] & 0x02) == 0) + ((dev->driver_info->flags & FLAG_POINTTOPOINT) == 0 || + (net->dev_addr [0] & 0x02) == 0)) strcpy (net->name, "eth%d"); /* WLAN devices should always be named "wlan%d" */ if ((dev->driver_info->flags & FLAG_WLAN) != 0) diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 3eb0b167b5b4..241756e0e86f 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -102,7 +102,7 @@ static int always_connected (struct usbnet *dev) static const struct driver_info zaurus_sl5x00_info = { .description = "Sharp Zaurus SL-5x00", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .bind = zaurus_bind, .unbind = usbnet_cdc_unbind, @@ -112,7 +112,7 @@ static const struct driver_info zaurus_sl5x00_info = { static const struct driver_info zaurus_pxa_info = { .description = "Sharp Zaurus, PXA-2xx based", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .bind = zaurus_bind, .unbind = usbnet_cdc_unbind, @@ -122,7 +122,7 @@ static const struct driver_info zaurus_pxa_info = { static const struct driver_info olympus_mxl_info = { .description = "Olympus R1000", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .bind = zaurus_bind, .unbind = usbnet_cdc_unbind, @@ -258,7 +258,7 @@ bad_desc: static const struct driver_info bogus_mdlm_info = { .description = "pseudo-MDLM (BLAN) device", - .flags = FLAG_FRAMING_Z, + .flags = FLAG_POINTTOPOINT | FLAG_FRAMING_Z, .check_connect = always_connected, .tx_fixup = zaurus_tx_fixup, .bind = blan_mdlm_bind, -- cgit v1.2.2 From 6b794743b2c5e21825d35b5d5dd57d6fcc388198 Mon Sep 17 00:00:00 2001 From: Guan Xuetao Date: Fri, 1 Apr 2011 16:38:59 +0800 Subject: unicore32 framebuffer fix: get videomemory by __get_free_pages() and make it floatable 1. get videomemory by __get_free_pages() in fb-puv3.c 2. remove resource reservation for old fixed UNIGFX_MMAP & UVC_MMAP space 3. remove unused macros: PKUNTIY_UNIGFX_MMAP_BASE, PKUNITY_UNIGFX_MMAP_SIZE, PKUNITY_UVC_MMAP_BASE, PKUNITY_UVC_MMAP_SIZE and KUSER_UNIGFX_BASE 4. remove unused header linux/vmalloc.h in fb-puv3.h Signed-off-by: Guan Xuetao Acked-by: Arnd Bergmann --- drivers/video/fb-puv3.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c index dbd2dc4745d1..27f2c57e06e9 100644 --- a/drivers/video/fb-puv3.c +++ b/drivers/video/fb-puv3.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -531,7 +530,7 @@ static int unifb_set_par(struct fb_info *info) return -EINVAL; } - writel(PKUNITY_UNIGFX_MMAP_BASE, UDE_FSA); + writel(info->fix.smem_start, UDE_FSA); writel(info->var.yres, UDE_LS); writel(get_line_length(info->var.xres, info->var.bits_per_pixel) >> 3, UDE_PS); @@ -680,13 +679,27 @@ static int unifb_probe(struct platform_device *dev) struct fb_info *info; u32 unifb_regs[UNIFB_REGS_NUM]; int retval = -ENOMEM; - struct resource *iomem, *mapmem; + struct resource *iomem; + void *videomemory; + + videomemory = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP, + get_order(UNIFB_MEMSIZE)); + if (!videomemory) + goto err; + + memset(videomemory, 0, UNIFB_MEMSIZE); + + unifb_fix.smem_start = virt_to_phys(videomemory); + unifb_fix.smem_len = UNIFB_MEMSIZE; + + iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); + unifb_fix.mmio_start = iomem->start; info = framebuffer_alloc(sizeof(u32)*256, &dev->dev); if (!info) goto err; - info->screen_base = (char __iomem *)KUSER_UNIGFX_BASE; + info->screen_base = (char __iomem *)videomemory; info->fbops = &unifb_ops; retval = fb_find_mode(&info->var, info, NULL, @@ -695,13 +708,6 @@ static int unifb_probe(struct platform_device *dev) if (!retval || (retval == 4)) info->var = unifb_default; - iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); - unifb_fix.mmio_start = iomem->start; - - mapmem = platform_get_resource(dev, IORESOURCE_MEM, 1); - unifb_fix.smem_start = mapmem->start; - unifb_fix.smem_len = UNIFB_MEMSIZE; - info->fix = unifb_fix; info->pseudo_palette = info->par; info->par = NULL; -- cgit v1.2.2 From e28e1d93e9591d21e440f5210a9b4317c59445df Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 2 Apr 2011 21:20:24 -0700 Subject: Input: rpckbd - fix a leak of the IRQ during init failure In rpckbd_open prror path, free_irq() was using NULL rather than the driver data as the data pointer so free_irq() wouldn't have matched. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/serio/rpckbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index 9da6fbcaaa7e..7ec3c97dc1b9 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -90,7 +90,7 @@ static int rpckbd_open(struct serio *port) if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) { printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n"); - free_irq(IRQ_KEYBOARDRX, NULL); + free_irq(IRQ_KEYBOARDRX, port); return -EBUSY; } -- cgit v1.2.2 From beb47274116b36e17cf52869a2004e7d12a4ef1d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 2 Apr 2011 09:09:08 -0400 Subject: drm/radeon/kms: Add support for tv-out dongle on G5 9600 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_combios.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index cf602e2d0718..8caf546c8e92 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2079,6 +2079,19 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev) DRM_MODE_CONNECTOR_DVII, &ddc_i2c, CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I, &hpd); + /* TV - TV DAC */ + ddc_i2c.valid = false; + hpd.hpd = RADEON_HPD_NONE; + radeon_add_legacy_encoder(dev, + radeon_get_encoder_enum(dev, + ATOM_DEVICE_TV1_SUPPORT, + 2), + ATOM_DEVICE_TV1_SUPPORT); + radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT, + DRM_MODE_CONNECTOR_SVIDEO, + &ddc_i2c, + CONNECTOR_OBJECT_ID_SVIDEO, + &hpd); break; default: DRM_INFO("Connector table: %d (invalid)\n", -- cgit v1.2.2 From fb9674bd2cd3c18f6c756ee123967e43be501263 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sat, 2 Apr 2011 09:15:50 -0400 Subject: drm/radeon/kms: pageflipping cleanup for avivo+ Avoid touching the flip setup regs while acceleration is running. Set them at modeset rather than during pageflip. Touching these regs while acceleration is active caused hangs on pre-avivo chips. These chips do not seem to be affected, but better safe than sorry, plus it avoids repeatedly reprogramming the regs every flip. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 20 ++++++++++++++++++++ drivers/gpu/drm/radeon/evergreen.c | 11 ----------- drivers/gpu/drm/radeon/rs600.c | 11 ----------- 3 files changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 10e41af6b026..b41ec59c7100 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1009,6 +1009,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, uint64_t fb_location; uint32_t fb_format, fb_pitch_pixels, tiling_flags; u32 fb_swap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); + u32 tmp; int r; /* no fb bound */ @@ -1137,6 +1138,15 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, WREG32(EVERGREEN_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); + /* pageflip setup */ + /* make sure flip is at vb rather than hb */ + tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; + WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); + + /* set pageflip to happen anywhere in vblank interval */ + WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); + if (!atomic && fb && fb != crtc->fb) { radeon_fb = to_radeon_framebuffer(fb); rbo = gem_to_radeon_bo(radeon_fb->obj); @@ -1167,6 +1177,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, uint64_t fb_location; uint32_t fb_format, fb_pitch_pixels, tiling_flags; u32 fb_swap = R600_D1GRPH_SWAP_ENDIAN_NONE; + u32 tmp; int r; /* no fb bound */ @@ -1294,6 +1305,15 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay); + /* pageflip setup */ + /* make sure flip is at vb rather than hb */ + tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); + tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; + WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); + + /* set pageflip to happen anywhere in vblank interval */ + WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); + if (!atomic && fb && fb != crtc->fb) { radeon_fb = to_radeon_framebuffer(fb); rbo = gem_to_radeon_bo(radeon_fb->obj); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 941080a77940..0b0cc74c08c0 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -43,17 +43,6 @@ static void evergreen_pcie_gen2_enable(struct radeon_device *rdev); void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) { - struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; - u32 tmp; - - /* make sure flip is at vb rather than hb */ - tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); - tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; - WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); - - /* set pageflip to happen anywhere in vblank interval */ - WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); - /* enable the pflip int */ radeon_irq_kms_pflip_irq_get(rdev, crtc); } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 19763f5df5e1..876cebc4b8ba 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -48,17 +48,6 @@ int rs600_mc_wait_for_idle(struct radeon_device *rdev); void rs600_pre_page_flip(struct radeon_device *rdev, int crtc) { - struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; - u32 tmp; - - /* make sure flip is at vb rather than hb */ - tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); - tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; - WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); - - /* set pageflip to happen anywhere in vblank interval */ - WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); - /* enable the pflip int */ radeon_irq_kms_pflip_irq_get(rdev, crtc); } -- cgit v1.2.2 From a14b289d4614bb3b25d0455d68f72f3c7b4cc8e8 Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Sun, 3 Apr 2011 22:04:01 -0700 Subject: mlx4: fix kfree on error path in new_steering_entry() On error path kfree() should get pointer to memory allocated by kmalloc() not the address of variable holding it (which is on stack). Signed-off-by: Mariusz Kozlowski Signed-off-by: David S. Miller --- drivers/net/mlx4/mcg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 37150b2f6425..c6d336aed2d9 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -111,7 +111,7 @@ static int new_steering_entry(struct mlx4_dev *dev, u8 vep_num, u8 port, u32 members_count; struct mlx4_steer_index *new_entry; struct mlx4_promisc_qp *pqp; - struct mlx4_promisc_qp *dqp; + struct mlx4_promisc_qp *dqp = NULL; u32 prot; int err; u8 pf_num; @@ -184,7 +184,7 @@ out_mailbox: out_alloc: if (dqp) { list_del(&dqp->list); - kfree(&dqp); + kfree(dqp); } list_del(&new_entry->list); kfree(new_entry); -- cgit v1.2.2 From aa5c8df398266a141fb5ff0e77cbc7904a3e0648 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Mon, 4 Apr 2011 09:43:31 +0200 Subject: [S390] qdio: fix init sequence Reorder the initialization sequence of the qdio module to avoid writing to an uninitialized debug feature entry. Also reorder the exit function to restore a consistent cleanup path. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 479c665e9e7c..c532ba929ccd 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1649,26 +1649,26 @@ static int __init init_QDIO(void) { int rc; - rc = qdio_setup_init(); + rc = qdio_debug_init(); if (rc) return rc; + rc = qdio_setup_init(); + if (rc) + goto out_debug; rc = tiqdio_allocate_memory(); if (rc) goto out_cache; - rc = qdio_debug_init(); - if (rc) - goto out_ti; rc = tiqdio_register_thinints(); if (rc) - goto out_debug; + goto out_ti; return 0; -out_debug: - qdio_debug_exit(); out_ti: tiqdio_free_memory(); out_cache: qdio_setup_exit(); +out_debug: + qdio_debug_exit(); return rc; } @@ -1676,8 +1676,8 @@ static void __exit exit_QDIO(void) { tiqdio_unregister_thinints(); tiqdio_free_memory(); - qdio_debug_exit(); qdio_setup_exit(); + qdio_debug_exit(); } module_init(init_QDIO); -- cgit v1.2.2 From a2fc8485f838ccd2ce5db690f81ac086489a9e7e Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 4 Apr 2011 09:43:32 +0200 Subject: [S390] cio: prevent purging of CCW devices in the online state The cio_ignore purge function is intended to only remove CCW devices which are in the offline state. There is a time frame after the purge function finished where a CCW device is scheduled for removal but still accessible. When the device is set online during this time frame, it may first appear online before it is then removed. Fix this by preventing that CCW devices can be set online while there is work (such as removal triggered by the purge function) for it pending. Also ensure that the purge function does not schedule devices for removal which are in the process of being set online. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index df14c51f6532..8e04c00cf0ad 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -541,15 +541,24 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, int force, ret; unsigned long i; - if (!dev_fsm_final_state(cdev) && - cdev->private->state != DEV_STATE_DISCONNECTED) - return -EAGAIN; + /* Prevent conflict between multiple on-/offline processing requests. */ if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) return -EAGAIN; + /* Prevent conflict between internal I/Os and on-/offline processing. */ + if (!dev_fsm_final_state(cdev) && + cdev->private->state != DEV_STATE_DISCONNECTED) { + ret = -EAGAIN; + goto out_onoff; + } + /* Prevent conflict between pending work and on-/offline processing.*/ + if (work_pending(&cdev->private->todo_work)) { + ret = -EAGAIN; + goto out_onoff; + } if (cdev->drv && !try_module_get(cdev->drv->driver.owner)) { - atomic_set(&cdev->private->onoff, 0); - return -EINVAL; + ret = -EINVAL; + goto out_onoff; } if (!strncmp(buf, "force\n", count)) { force = 1; @@ -574,6 +583,7 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, out: if (cdev->drv) module_put(cdev->drv->driver.owner); +out_onoff: atomic_set(&cdev->private->onoff, 0); return (ret < 0) ? ret : count; } @@ -1311,10 +1321,12 @@ static int purge_fn(struct device *dev, void *data) spin_lock_irq(cdev->ccwlock); if (is_blacklisted(id->ssid, id->devno) && - (cdev->private->state == DEV_STATE_OFFLINE)) { + (cdev->private->state == DEV_STATE_OFFLINE) && + (atomic_cmpxchg(&cdev->private->onoff, 0, 1) == 0)) { CIO_MSG_EVENT(3, "ccw: purging 0.%x.%04x\n", id->ssid, id->devno); ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); + atomic_set(&cdev->private->onoff, 0); } spin_unlock_irq(cdev->ccwlock); /* Abort loop in case of pending signal. */ -- cgit v1.2.2 From a94d7b35067ab403485a1ea06b7a3d0172d1a1ba Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Thu, 31 Mar 2011 17:11:39 -0500 Subject: edac/mpc85xx: Limit setting/clearing of HID1[RFXE] to e500v1/v2 cores Only the e500v1/v2 cores have HID1[RXFE] so we should attempt to set or clear this register bit on them. Otherwise we get crashes like: NIP: c0579f84 LR: c006d550 CTR: c0579f84 REGS: ef857ec0 TRAP: 0700 Not tainted (2.6.38.2-00072-gf15ba3c) MSR: 00021002 CR: 22044022 XER: 00000000 TASK = ef8559c0[1] 'swapper' THREAD: ef856000 CPU: 0 GPR00: c006d538 ef857f70 ef8559c0 00000000 00000004 00000000 00000000 00000000 GPR08: c0590000 c30170a8 00000000 c30170a8 00000001 0fffe000 00000000 00000000 GPR16: 00000000 7ffa0e60 00000000 00000000 7ffb0bd8 7ff3b844 c05be000 00000000 GPR24: 00000000 00000000 c05c28b0 c0579fac 00000000 00029002 00000000 c0579f84 NIP [c0579f84] mpc85xx_mc_clear_rfxe+0x0/0x28 LR [c006d550] on_each_cpu+0x34/0x50 Call Trace: [ef857f70] [c006d538] on_each_cpu+0x1c/0x50 (unreliable) [ef857f90] [c057a070] mpc85xx_mc_init+0xc4/0xdc [ef857fa0] [c0001cd4] do_one_initcall+0x34/0x1a8 [ef857fd0] [c055d9d8] kernel_init+0x17c/0x218 [ef857ff0] [c000cda4] kernel_thread+0x4c/0x68 Instruction dump: 40be0018 3c60c052 3863c70c 4be9baad 3be0ffed 4bd7c99d 80010014 7fe3fb78 83e1000c 38210010 7c0803a6 4e800020 <7c11faa6> 54290024 81290008 3d60c06e Oops: Exception in kernel mode, sig: 4 [#2] ---[ end trace 49ff3b8f93efde1a ]--- Also use the HID1_RFXE define rather than a magic number. Signed-off-by: Kumar Gala --- drivers/edac/mpc85xx_edac.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index ffb5ad080bee..38ab8e2cd7f4 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -1147,13 +1147,14 @@ static struct platform_driver mpc85xx_mc_err_driver = { static void __init mpc85xx_mc_clear_rfxe(void *data) { orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1); - mtspr(SPRN_HID1, (orig_hid1[smp_processor_id()] & ~0x20000)); + mtspr(SPRN_HID1, (orig_hid1[smp_processor_id()] & ~HID1_RFXE)); } #endif static int __init mpc85xx_mc_init(void) { int res = 0; + u32 pvr = 0; printk(KERN_INFO "Freescale(R) MPC85xx EDAC driver, " "(C) 2006 Montavista Software\n"); @@ -1183,12 +1184,17 @@ static int __init mpc85xx_mc_init(void) #endif #ifdef CONFIG_FSL_SOC_BOOKE - /* - * need to clear HID1[RFXE] to disable machine check int - * so we can catch it - */ - if (edac_op_state == EDAC_OPSTATE_INT) - on_each_cpu(mpc85xx_mc_clear_rfxe, NULL, 0); + pvr = mfspr(SPRN_PVR); + + if ((PVR_VER(pvr) == PVR_VER_E500V1) || + (PVR_VER(pvr) == PVR_VER_E500V2)) { + /* + * need to clear HID1[RFXE] to disable machine check int + * so we can catch it + */ + if (edac_op_state == EDAC_OPSTATE_INT) + on_each_cpu(mpc85xx_mc_clear_rfxe, NULL, 0); + } #endif return 0; @@ -1206,7 +1212,12 @@ static void __exit mpc85xx_mc_restore_hid1(void *data) static void __exit mpc85xx_mc_exit(void) { #ifdef CONFIG_FSL_SOC_BOOKE - on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); + u32 pvr = mfspr(SPRN_PVR); + + if ((PVR_VER(pvr) == PVR_VER_E500V1) || + (PVR_VER(pvr) == PVR_VER_E500V2)) { + on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0); + } #endif #ifdef CONFIG_PCI platform_driver_unregister(&mpc85xx_pci_err_driver); -- cgit v1.2.2 From b3b896c73b4b04b506816a09994192e3a54f0fef Mon Sep 17 00:00:00 2001 From: Major Lee Date: Mon, 4 Apr 2011 11:32:12 +0100 Subject: rtc-mrst: Fix section types Fix the following section mismatch warning. WARNING: drivers/rtc/built-in.o(.data+0xa0): Section mismatch in reference from the variable vrtc_mrst_platform_driver to the function .init.text:vrtc_mrst_platform_probe() The variable vrtc_mrst_platform_driver references the function __init vrtc_mrst_platform_probe() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console, Signed-off-by: Major Lee Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mrst.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index b86bc328463b..332a2c4a891c 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -319,7 +319,7 @@ static irqreturn_t mrst_rtc_irq(int irq, void *p) return IRQ_NONE; } -static int __init +static int __devinit vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) { int retval = 0; @@ -391,7 +391,7 @@ static void rtc_mrst_do_shutdown(void) spin_unlock_irq(&rtc_lock); } -static void __exit rtc_mrst_do_remove(struct device *dev) +static void __devexit rtc_mrst_do_remove(struct device *dev) { struct mrst_rtc *mrst = dev_get_drvdata(dev); struct resource *iomem; @@ -500,14 +500,14 @@ static inline int mrst_poweroff(struct device *dev) #endif -static int __init vrtc_mrst_platform_probe(struct platform_device *pdev) +static int __devinit vrtc_mrst_platform_probe(struct platform_device *pdev) { return vrtc_mrst_do_probe(&pdev->dev, platform_get_resource(pdev, IORESOURCE_MEM, 0), platform_get_irq(pdev, 0)); } -static int __exit vrtc_mrst_platform_remove(struct platform_device *pdev) +static int __devexit vrtc_mrst_platform_remove(struct platform_device *pdev) { rtc_mrst_do_remove(&pdev->dev); return 0; @@ -525,7 +525,7 @@ MODULE_ALIAS("platform:vrtc_mrst"); static struct platform_driver vrtc_mrst_platform_driver = { .probe = vrtc_mrst_platform_probe, - .remove = __exit_p(vrtc_mrst_platform_remove), + .remove = __devexit_p(vrtc_mrst_platform_remove), .shutdown = vrtc_mrst_platform_shutdown, .driver = { .name = (char *) driver_name, -- cgit v1.2.2 From 4acfaf829dacb8f8170b439d30065e8d2cfdaac9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 3 Apr 2011 11:42:00 -0700 Subject: usb/serial: fix function args warnings, dropping *filp Fix build warnings caused by removal of *filp arg in struct usb_serial_driver. These changes were missed somehow in commits 00a0d0d65b61 ("tty: remove filp from the USB tty ioctls") and 60b33c133ca0b ("tiocmget: kill off the passing of the struct file") drivers/usb/serial/mct_u232.c:159: warning: initialization from incompatible pointer type drivers/usb/serial/opticon.c:627: warning: initialization from incompatible pointer type Signed-off-by: Randy Dunlap Cc: Alan Cox Signed-off-by: Linus Torvalds --- drivers/usb/serial/mct_u232.c | 4 ++-- drivers/usb/serial/opticon.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index d2c019637e45..ba0d28727ccb 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -106,7 +106,7 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state); static int mct_u232_tiocmget(struct tty_struct *tty); static int mct_u232_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int mct_u232_ioctl(struct tty_struct *tty, struct file *file, +static int mct_u232_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static int mct_u232_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount); @@ -874,7 +874,7 @@ static void mct_u232_unthrottle(struct tty_struct *tty) } } -static int mct_u232_ioctl(struct tty_struct *tty, struct file *file, +static int mct_u232_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { DEFINE_WAIT(wait); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 201f6096844b..a1dd4d4fa192 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -413,7 +413,7 @@ static int opticon_tiocmget(struct tty_struct *tty) return result; } -static int opticon_tiocmset(struct tty_struct *tty, struct file *file, +static int opticon_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; -- cgit v1.2.2 From fef34861381eefe266c822fc28bdedc897a8265f Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Sat, 2 Apr 2011 19:00:44 +0900 Subject: sony-laptop: fix early NULL pointer dereference The SNC acpi driver could get early notifications before it fully initializes and that could lead to dereferencing the sony_nc_handles structure pointer that is still NULL at that stage. Make sure we return early from the handle lookup function in these cases. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index e642f5f29504..33c3b8c066ee 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -808,6 +808,11 @@ static int sony_nc_handles_cleanup(struct platform_device *pd) static int sony_find_snc_handle(int handle) { int i; + + /* not initialized yet, return early */ + if (!handles) + return -1; + for (i = 0; i < 0x10; i++) { if (handles->cap[i] == handle) { dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", -- cgit v1.2.2 From 65d7ac038e34702feedad91d0bf597b1f0a4174a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sat, 2 Apr 2011 21:23:36 +0200 Subject: platform-drivers: x86: pmic: Restore the dropped buslock/unlock When I added the buslock/unlock mechanism to the pmic code in order to get rid of the horrible work queue stuff, stupid me missed to add the new callbacks to the irq_chip. In consequence Andrew removed the unused functions, but I missed that. Add them back and hook them up proper. Signed-off-by: Thomas Gleixner Cc: Matthew Garrett Cc: Andrew Morton Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_pmic_gpio.c | 43 ++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index d653104b59cb..7bbb5388e564 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -74,6 +74,19 @@ struct pmic_gpio { u32 trigger_type; }; +static void pmic_program_irqtype(int gpio, int type) +{ + if (type & IRQ_TYPE_EDGE_RISING) + intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20); + else + intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20); + + if (type & IRQ_TYPE_EDGE_FALLING) + intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10); + else + intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); +}; + static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { if (offset > 8) { @@ -166,16 +179,38 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return pg->irq_base + offset; } +static void pmic_bus_lock(struct irq_data *data) +{ + struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); + + mutex_lock(&pg->buslock); +} + +static void pmic_bus_sync_unlock(struct irq_data *data) +{ + struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); + + if (pg->update_type) { + unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE; + + pmic_program_irqtype(gpio, pg->trigger_type); + pg->update_type = 0; + } + mutex_unlock(&pg->buslock); +} + /* the gpiointr register is read-clear, so just do nothing. */ static void pmic_irq_unmask(struct irq_data *data) { } static void pmic_irq_mask(struct irq_data *data) { } static struct irq_chip pmic_irqchip = { - .name = "PMIC-GPIO", - .irq_mask = pmic_irq_mask, - .irq_unmask = pmic_irq_unmask, - .irq_set_type = pmic_irq_type, + .name = "PMIC-GPIO", + .irq_mask = pmic_irq_mask, + .irq_unmask = pmic_irq_unmask, + .irq_set_type = pmic_irq_type, + .irq_bus_lock = pmic_irq_buslock, + .irq_bus_sync_unlock = pmic_bus_sync_unlock, }; static irqreturn_t pmic_irq_handler(int irq, void *data) -- cgit v1.2.2 From 7f4d527f0bf3ddc8c257b21fb9bbada5e49f0ef0 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:28:08 -0300 Subject: [media] DIB0700: fix typo in dib0700_devices.c Fix typo introduced in b4d6046e841955be9cc49164b03b91c9524f9c2e. Spotted by Dr. David Alan Gilbert. Thanks for that. Signed-off-by: Patrick Boettcher Cc: Dr. David Alan Gilbert Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 97af266d7f1d..72e2370c99fe 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -2162,7 +2162,7 @@ struct dibx000_agc_config dib7090_agc_config[2] = { .agc1_pt3 = 98, .agc1_slope1 = 0, .agc1_slope2 = 167, - .agc1_pt1 = 98, + .agc2_pt1 = 98, .agc2_pt2 = 255, .agc2_slope1 = 104, .agc2_slope2 = 0, -- cgit v1.2.2 From b934c20de1398d4a82d2ecfeb588a214a910f13f Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:40:24 -0300 Subject: [media] FLEXCOP-PCI: fix __xlate_proc_name-warning for flexcop-pci This patch fixes the warning about bad names for sys-fs and other kernel-things. The flexcop-pci driver was using '/'-characters in it, which is not good. This has been fixed in several attempts by several people, but obviously never made it into the kernel. Signed-off-by: Patrick Boettcher Cc: Steffen Barszus Cc: Boris Cuber Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/b2c2/flexcop-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 227c0200b70a..4f3e3ceaa7c9 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -38,7 +38,7 @@ MODULE_PARM_DESC(debug, DEBSTATUS); #define DRIVER_VERSION "0.1" -#define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver" +#define DRIVER_NAME "flexcop-pci" #define DRIVER_AUTHOR "Patrick Boettcher " struct flexcop_pci { -- cgit v1.2.2 From 71682520b33abef3f6c3fb618cb530826f472476 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:44:25 -0300 Subject: [media] dib0700: fix possible NULL pointer dereference Seems like 'adap->fe' test for NULL was meant to be before we dereference that pointer. Signed-off-by: Mariusz Kozlowski Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_devices.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 72e2370c99fe..65214af5cd74 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -2440,11 +2440,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) dib0700_set_i2c_speed(adap->dev, 340); adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - dib7090_slave_reset(adap->fe); - if (adap->fe == NULL) return -ENODEV; + dib7090_slave_reset(adap->fe); + return 0; } -- cgit v1.2.2 From 974ceab8fd76d795cb6d77b7573a383d2e733ee6 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Sun, 3 Apr 2011 12:46:02 -0300 Subject: [media] Fix dependencies for Technisat USB2.0 DVB-S/S2 Device is based on STV0903 demod and STV6110x tuner Signed-off-by: Oleg Roitburd Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index fe4f894183ff..ccbd39a38c46 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -362,7 +362,7 @@ config DVB_USB_LME2510 config DVB_USB_TECHNISAT_USB2 tristate "Technisat DVB-S/S2 USB2.0 support" depends on DVB_USB - select DVB_STB0899 if !DVB_FE_CUSTOMISE - select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV090x if !DVB_FE_CUSTOMISE + select DVB_STV6110x if !DVB_FE_CUSTOMISE help Say Y here to support the Technisat USB2 DVB-S/S2 device -- cgit v1.2.2 From c85ce65ecac078ab1a1835c87c4a6319cf74660a Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Wed, 30 Mar 2011 14:02:46 -0400 Subject: b43: allocate receive buffers big enough for max frame len + offset Otherwise, skb_put inside of dma_rx can fail... https://bugzilla.kernel.org/show_bug.cgi?id=32042 Signed-off-by: John W. Linville Acked-by: Larry Finger Cc: stable@kernel.org --- drivers/net/wireless/b43/dma.c | 2 +- drivers/net/wireless/b43/dma.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 3d5566e7af0a..ff0f5ba14b2c 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1536,7 +1536,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot) dmaaddr = meta->dmaaddr; goto drop_recycle_buffer; } - if (unlikely(len > ring->rx_buffersize)) { + if (unlikely(len + ring->frameoffset > ring->rx_buffersize)) { /* The data did not fit into one descriptor buffer * and is split over multiple buffers. * This should never happen, as we try to allocate buffers diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index a01c2100f166..e8a80a1251bf 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -163,7 +163,7 @@ struct b43_dmadesc_generic { /* DMA engine tuning knobs */ #define B43_TXRING_SLOTS 256 #define B43_RXRING_SLOTS 64 -#define B43_DMA0_RX_BUFFERSIZE IEEE80211_MAX_FRAME_LEN +#define B43_DMA0_RX_BUFFERSIZE (B43_DMA0_RX_FRAMEOFFSET + IEEE80211_MAX_FRAME_LEN) /* Pointer poison */ #define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM)) -- cgit v1.2.2 From 5245e3a9f77a8dd4ea92d7bdab2e96629f1feda4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Wed, 30 Mar 2011 21:31:39 +0300 Subject: wl12xx: fix module author's email address in the spi and sdio modules The MODULE_AUTHOR() macro in the main module (wl12xx) has been updated to reflect one of the author's new email address, but the wl12xx_spi and wl12xx_sdio modules haven't been updated. This patches updates them. Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/sdio.c | 2 +- drivers/net/wireless/wl12xx/spi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index 5b9dbeafec06..b1c7d031c391 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -340,7 +340,7 @@ module_init(wl1271_init); module_exit(wl1271_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL1271_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 18cf01719ae0..ffc745b17f4d 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -487,7 +487,7 @@ module_init(wl1271_init); module_exit(wl1271_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Luciano Coelho "); +MODULE_AUTHOR("Luciano Coelho "); MODULE_AUTHOR("Juuso Oikarinen "); MODULE_FIRMWARE(WL1271_FW_NAME); MODULE_FIRMWARE(WL1271_AP_FW_NAME); -- cgit v1.2.2 From 8f06ca2c83689f4d352a34ef1c484f40c25b41ed Mon Sep 17 00:00:00 2001 From: Senthil Balasubramanian Date: Fri, 1 Apr 2011 17:16:33 +0530 Subject: ath9k: Fix phy info print message with AR9485 chipset. The phy information print during driver init time doesn't show the numeric part of the chip name properly for AR9485. This patch addresses this issue by adding the string to the respective array. Signed-off-by: Senthil Balasubramanian Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 338b07502f1a..1ec9bcd6b281 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -2546,6 +2546,7 @@ static struct { { AR_SREV_VERSION_9287, "9287" }, { AR_SREV_VERSION_9271, "9271" }, { AR_SREV_VERSION_9300, "9300" }, + { AR_SREV_VERSION_9485, "9485" }, }; /* For devices with external radios */ -- cgit v1.2.2 From 2fc713b20469b2779fa89f582d2a9696b10031e7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 1 Apr 2011 19:34:08 +0300 Subject: zd1211rw: remove URB_SHORT_NOT_OK flag in zd_usb_iowrite16v_async() Patch removes the bogus flag introduced by upstream commit eefdbec1ea8b7093d2c09d1825f68438701723cf. Old code had buffer length check that new code tried to handle with URB_SHORT_NOT_OK flag. With USB debugging enabled bogus flag caused usb_submit_urb fail. Remove URB_SHORT_NOT_OK flag and add buffer length check to urb completion handler. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=32092 Reported-by: Jonathan Callen Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 58236e6d0921..9b1a26a4435b 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1671,6 +1671,10 @@ static void iowrite16v_urb_complete(struct urb *urb) if (urb->status && !usb->cmd_error) usb->cmd_error = urb->status; + + if (!usb->cmd_error && + urb->actual_length != urb->transfer_buffer_length) + usb->cmd_error = -EIO; } static int zd_submit_waiting_urb(struct zd_usb *usb, bool last) @@ -1805,7 +1809,7 @@ int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT), req, req_len, iowrite16v_urb_complete, usb, ep->desc.bInterval); - urb->transfer_flags |= URB_FREE_BUFFER | URB_SHORT_NOT_OK; + urb->transfer_flags |= URB_FREE_BUFFER; /* Submit previous URB */ r = zd_submit_waiting_urb(usb, false); -- cgit v1.2.2 From 023535732f4db01af4921f20f058bc4561d9add7 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Fri, 1 Apr 2011 19:34:16 +0300 Subject: zd1211rw: reset rx idle timer from tasklet 2.6.38 added WARN_ON(in_irq) in del_timer_sync that triggers on zd1211rw when reseting rx idle timer in urb completion handler. Move timer reseting to tasklet. Signed-off-by: Jussi Kivilinna Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_usb.c | 14 +++++++++++++- drivers/net/wireless/zd1211rw/zd_usb.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index 9b1a26a4435b..ab607bbd6291 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -643,7 +643,7 @@ static void rx_urb_complete(struct urb *urb) usb = urb->context; rx = &usb->rx; - zd_usb_reset_rx_idle_timer(usb); + tasklet_schedule(&rx->reset_timer_tasklet); if (length%rx->usb_packet_size > rx->usb_packet_size-4) { /* If there is an old first fragment, we don't care. */ @@ -812,6 +812,7 @@ void zd_usb_disable_rx(struct zd_usb *usb) __zd_usb_disable_rx(usb); mutex_unlock(&rx->setup_mutex); + tasklet_kill(&rx->reset_timer_tasklet); cancel_delayed_work_sync(&rx->idle_work); } @@ -1106,6 +1107,13 @@ static void zd_rx_idle_timer_handler(struct work_struct *work) zd_usb_reset_rx(usb); } +static void zd_usb_reset_rx_idle_timer_tasklet(unsigned long param) +{ + struct zd_usb *usb = (struct zd_usb *)param; + + zd_usb_reset_rx_idle_timer(usb); +} + void zd_usb_reset_rx_idle_timer(struct zd_usb *usb) { struct zd_usb_rx *rx = &usb->rx; @@ -1127,6 +1135,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb) static inline void init_usb_rx(struct zd_usb *usb) { struct zd_usb_rx *rx = &usb->rx; + spin_lock_init(&rx->lock); mutex_init(&rx->setup_mutex); if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) { @@ -1136,11 +1145,14 @@ static inline void init_usb_rx(struct zd_usb *usb) } ZD_ASSERT(rx->fragment_length == 0); INIT_DELAYED_WORK(&rx->idle_work, zd_rx_idle_timer_handler); + rx->reset_timer_tasklet.func = zd_usb_reset_rx_idle_timer_tasklet; + rx->reset_timer_tasklet.data = (unsigned long)usb; } static inline void init_usb_tx(struct zd_usb *usb) { struct zd_usb_tx *tx = &usb->tx; + spin_lock_init(&tx->lock); atomic_set(&tx->enabled, 0); tx->stopped = 0; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index b3df2c8116cc..325d0f989257 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -183,6 +183,7 @@ struct zd_usb_rx { spinlock_t lock; struct mutex setup_mutex; struct delayed_work idle_work; + struct tasklet_struct reset_timer_tasklet; u8 fragment[2 * USB_MAX_RX_SIZE]; unsigned int fragment_length; unsigned int usb_packet_size; -- cgit v1.2.2 From 09b661b33268698d3b453dceb78cda129ad899b4 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Fri, 1 Apr 2011 19:42:02 +0300 Subject: wl12xx: fix potential buffer overflow in testmode nvs push We were allocating the size of the NVS file struct and not checking whether the length of the buffer passed was correct before copying it into the allocated memory. This is a security hole because buffer overflows can occur if the userspace passes a bigger file than what is expected. With this patch, we check if the size of the data passed from userspace matches the size required. This bug was introduced in 2.6.36. Cc: stable@kernel.org Reported-by: Ido Yariv Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/wl12xx/testmode.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c index e64403b6896d..6ec06a4a4c6d 100644 --- a/drivers/net/wireless/wl12xx/testmode.c +++ b/drivers/net/wireless/wl12xx/testmode.c @@ -204,7 +204,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[]) kfree(wl->nvs); - wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL); + if (len != sizeof(struct wl1271_nvs_file)) + return -EINVAL; + + wl->nvs = kzalloc(len, GFP_KERNEL); if (!wl->nvs) { wl1271_error("could not allocate memory for the nvs file"); ret = -ENOMEM; -- cgit v1.2.2 From 220107610c7c2c9703e09eb363e8ab31025b9315 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Sat, 2 Apr 2011 11:31:29 +0200 Subject: p54usb: IDs for two new devices Cc: Reported-by: Mark Davis [via p54/devices wiki] Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/p54/p54usb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 9b344a921e74..e18358725b69 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -56,6 +56,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x0846, 0x4210)}, /* Netgear WG121 the second ? */ {USB_DEVICE(0x0846, 0x4220)}, /* Netgear WG111 */ {USB_DEVICE(0x09aa, 0x1000)}, /* Spinnaker Proto board */ + {USB_DEVICE(0x0bf8, 0x1007)}, /* Fujitsu E-5400 USB */ {USB_DEVICE(0x0cde, 0x0006)}, /* Medion 40900, Roper Europe */ {USB_DEVICE(0x0db0, 0x6826)}, /* MSI UB54G (MS-6826) */ {USB_DEVICE(0x107b, 0x55f2)}, /* Gateway WGU-210 (Gemtek) */ @@ -68,6 +69,7 @@ static struct usb_device_id p54u_table[] __devinitdata = { {USB_DEVICE(0x1915, 0x2235)}, /* Linksys WUSB54G Portable OEM */ {USB_DEVICE(0x2001, 0x3701)}, /* DLink DWL-G120 Spinnaker */ {USB_DEVICE(0x2001, 0x3703)}, /* DLink DWL-G122 */ + {USB_DEVICE(0x2001, 0x3762)}, /* Conceptronic C54U */ {USB_DEVICE(0x5041, 0x2234)}, /* Linksys WUSB54G */ {USB_DEVICE(0x5041, 0x2235)}, /* Linksys WUSB54G Portable */ -- cgit v1.2.2 From 2e3e66e3bbcd5f999dc66d843a3efc2314e40e7b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 2 Apr 2011 18:10:22 -0500 Subject: rtlwifi: Fix some warnings/bugs Some compiler/architecture combinations generate some warnings that are not seen on my main system. Two of the "warnings" about unitialized variables are really bugs. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/rtlwifi/efuse.c | 2 +- drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c | 2 +- drivers/net/wireless/rtlwifi/usb.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c index f74a8701c67d..590f14f45a89 100644 --- a/drivers/net/wireless/rtlwifi/efuse.c +++ b/drivers/net/wireless/rtlwifi/efuse.c @@ -685,7 +685,7 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data) u8 efuse_data, word_cnts = 0; u16 efuse_addr = 0; - u8 hworden; + u8 hworden = 0; u8 tmpdata[8]; if (data == NULL) diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c index 5ef91374b230..28a6ce3bc239 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c +++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c @@ -303,7 +303,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw, u16 box_reg, box_extreg; u8 u1b_tmp; bool isfw_read = false; - u8 buf_index; + u8 buf_index = 0; bool bwrite_sucess = false; u8 wait_h2c_limmit = 100; u8 wait_writeh2c_limmit = 100; diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index a4b2613d6a8c..f5d85735d642 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -246,7 +246,7 @@ static void _rtl_usb_io_handler_init(struct device *dev, static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) { - struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_priv __maybe_unused *rtlpriv = rtl_priv(hw); mutex_destroy(&rtlpriv->io.bb_mutex); } -- cgit v1.2.2 From 37f4ee0b6b39640828dac5937a482c20e8ac794f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Mon, 4 Apr 2011 13:50:32 +0200 Subject: rt2x00: fix cancelling uninitialized work {rx,tx}done_work's are only initialized for usb devices. Signed-off-by: Stanislaw Gruszka Cc: stable@kernel.org Acked-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 9de9dbe94399..84eb6ad36377 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -1062,8 +1062,10 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Stop all work. */ cancel_work_sync(&rt2x00dev->intf_work); - cancel_work_sync(&rt2x00dev->rxdone_work); - cancel_work_sync(&rt2x00dev->txdone_work); + if (rt2x00_is_usb(rt2x00dev)) { + cancel_work_sync(&rt2x00dev->rxdone_work); + cancel_work_sync(&rt2x00dev->txdone_work); + } destroy_workqueue(rt2x00dev->workqueue); /* -- cgit v1.2.2 From 3d7dc7e8c1566acb0fc55df228b2ed91f5638e9d Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 4 Apr 2011 13:18:44 -0400 Subject: iwlwifi: accept EEPROM version 0x423 for iwl6000 A number of these devices have appeared "in the wild", and apparently the Windows driver is perfectly happy to support this EEPROM version. Signed-off-by: John W. Linville Cc: stable@kernel.org Acked-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-eeprom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index 98aa8af01192..20b66469d68f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -241,7 +241,7 @@ struct iwl_eeprom_enhanced_txpwr { /* 6x00 Specific */ #define EEPROM_6000_TX_POWER_VERSION (4) -#define EEPROM_6000_EEPROM_VERSION (0x434) +#define EEPROM_6000_EEPROM_VERSION (0x423) /* 6x50 Specific */ #define EEPROM_6050_TX_POWER_VERSION (4) -- cgit v1.2.2 From a5660b41af6a28f8004e70eb261e1202ad55c5e3 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 4 Apr 2011 14:26:54 -0700 Subject: tty: fix endless work loop when the buffer fills up Commit f23eb2b2b285 ('tty: stop using "delayed_work" in the tty layer') ended up causing hung machines on UP with no preemption, because the work routine to flip the buffer data to the ldisc would endlessly re-arm itself if the destination buffer had filled up. With the delayed work, that only caused a timer-driving polling of the tty state every timer tick, but without the delay we just ended up with basically a busy loop instead. Stop the insane polling, and instead make the code that opens up the receive room re-schedule the buffer flip work. That's what we should have been doing anyway. This same "poll for tty room" issue is almost certainly also the cause of excessive kworker activity when idle reported by Dave Jones, who also reported "flush_to_ldisc executing 2500 times a second" back in Nov 2010: http://lkml.org/lkml/2010/11/30/592 which is that silly flushing done every timer tick. Wasting both power and CPU for no good reason. Reported-and-tested-by: Alexander Beregalov Reported-and-tested-by: Sitsofe Wheeler Cc: Greg KH Cc: Alan Cox Cc: Dave Jones Signed-off-by: Linus Torvalds --- drivers/tty/n_tty.c | 6 ++++++ drivers/tty/tty_buffer.c | 4 +--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 428f4fe0b5f7..0ad32888091c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -95,6 +95,7 @@ static void n_tty_set_room(struct tty_struct *tty) { /* tty->read_cnt is not read locked ? */ int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + int old_left; /* * If we are doing input canonicalization, and there are no @@ -104,7 +105,12 @@ static void n_tty_set_room(struct tty_struct *tty) */ if (left <= 0) left = tty->icanon && !tty->canon_data; + old_left = tty->receive_room; tty->receive_room = left; + + /* Did this open up the receive buffer? We may need to flip */ + if (left && !old_left) + schedule_work(&tty->buf.work); } static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index b9451219528b..f1a7918d71aa 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -442,10 +442,8 @@ static void flush_to_ldisc(struct work_struct *work) line discipline as we want to empty the queue */ if (test_bit(TTY_FLUSHPENDING, &tty->flags)) break; - if (!tty->receive_room || seen_tail) { - schedule_work(&tty->buf.work); + if (!tty->receive_room || seen_tail) break; - } if (count > tty->receive_room) count = tty->receive_room; char_buf = head->char_buf_ptr + head->read; -- cgit v1.2.2 From 5df23979bc628934febe02e80f9644ec67603ee8 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 4 Apr 2011 01:25:18 +0200 Subject: drm: fix "persistant" typo Signed-off-by: Jan Engelhardt Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- drivers/gpu/drm/ttm/ttm_bo.c | 10 +++++----- drivers/gpu/drm/ttm/ttm_tt.c | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index e8b04f4aed7e..b52e46018245 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -97,7 +97,7 @@ nouveau_gem_new(struct drm_device *dev, struct nouveau_channel *chan, return -ENOMEM; } - nvbo->bo.persistant_swap_storage = nvbo->gem->filp; + nvbo->bo.persistent_swap_storage = nvbo->gem->filp; nvbo->gem->driver_private = nvbo; return 0; } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 0b6a55ac2f87..2e618b5ac465 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1168,7 +1168,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, uint32_t page_alignment, unsigned long buffer_start, bool interruptible, - struct file *persistant_swap_storage, + struct file *persistent_swap_storage, size_t acc_size, void (*destroy) (struct ttm_buffer_object *)) { @@ -1211,7 +1211,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev, bo->priv_flags = 0; bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED); bo->seq_valid = false; - bo->persistant_swap_storage = persistant_swap_storage; + bo->persistent_swap_storage = persistent_swap_storage; bo->acc_size = acc_size; atomic_inc(&bo->glob->bo_count); @@ -1260,7 +1260,7 @@ int ttm_bo_create(struct ttm_bo_device *bdev, uint32_t page_alignment, unsigned long buffer_start, bool interruptible, - struct file *persistant_swap_storage, + struct file *persistent_swap_storage, struct ttm_buffer_object **p_bo) { struct ttm_buffer_object *bo; @@ -1282,7 +1282,7 @@ int ttm_bo_create(struct ttm_bo_device *bdev, ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment, buffer_start, interruptible, - persistant_swap_storage, acc_size, NULL); + persistent_swap_storage, acc_size, NULL); if (likely(ret == 0)) *p_bo = bo; @@ -1863,7 +1863,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) if (bo->bdev->driver->swap_notify) bo->bdev->driver->swap_notify(bo); - ret = ttm_tt_swapout(bo->ttm, bo->persistant_swap_storage); + ret = ttm_tt_swapout(bo->ttm, bo->persistent_swap_storage); out: /** diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index 86d5b1745a45..90e23e0bfadb 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -332,7 +332,7 @@ void ttm_tt_destroy(struct ttm_tt *ttm) ttm_tt_free_page_directory(ttm); } - if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTANT_SWAP) && + if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP) && ttm->swap_storage) fput(ttm->swap_storage); @@ -503,7 +503,7 @@ static int ttm_tt_swapin(struct ttm_tt *ttm) page_cache_release(from_page); } - if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTANT_SWAP)) + if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP)) fput(swap_storage); ttm->swap_storage = NULL; ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED; @@ -514,7 +514,7 @@ out_err: return ret; } -int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) +int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage) { struct address_space *swap_space; struct file *swap_storage; @@ -540,7 +540,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) return 0; } - if (!persistant_swap_storage) { + if (!persistent_swap_storage) { swap_storage = shmem_file_setup("ttm swap", ttm->num_pages << PAGE_SHIFT, 0); @@ -549,7 +549,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) return PTR_ERR(swap_storage); } } else - swap_storage = persistant_swap_storage; + swap_storage = persistent_swap_storage; swap_space = swap_storage->f_path.dentry->d_inode->i_mapping; @@ -577,12 +577,12 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage) ttm_tt_free_alloced_pages(ttm); ttm->swap_storage = swap_storage; ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED; - if (persistant_swap_storage) - ttm->page_flags |= TTM_PAGE_FLAG_PERSISTANT_SWAP; + if (persistent_swap_storage) + ttm->page_flags |= TTM_PAGE_FLAG_PERSISTENT_SWAP; return 0; out_err: - if (!persistant_swap_storage) + if (!persistent_swap_storage) fput(swap_storage); return ret; -- cgit v1.2.2 From ac5c15fa585a89bcebca92dfdbb862dd507534fc Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Wed, 9 Feb 2011 14:56:42 +0100 Subject: drm/nouveau: correct memtiming table parsing for nv4x In line with envytools, verified on 4 or 5 BIOS'es. Signed-off-by: Ben Skeggs Signed-off-by: Roy Spliet --- drivers/gpu/drm/nouveau/nouveau_mem.c | 76 ++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 2683377f4131..78f467fe30be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -552,6 +552,7 @@ nouveau_mem_timing_init(struct drm_device *dev) u8 tRC; /* Byte 9 */ u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; + u8 magic_number = 0; /* Yeah... sorry*/ u8 *mem = NULL, *entry; int i, recordlen, entries; @@ -596,6 +597,12 @@ nouveau_mem_timing_init(struct drm_device *dev) if (!memtimings->timing) return; + /* Get "some number" from the timing reg for NV_40 + * Used in calculations later */ + if(dev_priv->card_type == NV_40) { + magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24; + } + entry = mem + mem[1]; for (i = 0; i < entries; i++, entry += recordlen) { struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; @@ -635,36 +642,51 @@ nouveau_mem_timing_init(struct drm_device *dev) /* XXX: I don't trust the -1's and +1's... they must come * from somewhere! */ - timing->reg_100224 = ((tUNK_0 + tUNK_19 + 1) << 24 | + timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | tUNK_18 << 16 | - (tUNK_1 + tUNK_19 + 1) << 8 | - (tUNK_2 - 1)); + (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; + if(dev_priv->chipset == 0xa8) { + timing->reg_100224 |= (tUNK_2 - 1); + } else { + timing->reg_100224 |= (tUNK_2 + 2 - magic_number); + } timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); - if(recordlen > 19) { - timing->reg_100228 += (tUNK_19 - 1) << 24; - }/* I cannot back-up this else-statement right now - else { - timing->reg_100228 += tUNK_12 << 24; - }*/ - - /* XXX: reg_10022c */ - timing->reg_10022c = tUNK_2 - 1; - - timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | - tUNK_13 << 8 | tUNK_13); - - /* XXX: +6? */ - timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC); - timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; - - /* XXX; reg_100238, reg_10023c - * reg: 0x00?????? - * reg_10023c: - * 0 for pre-NV50 cards - * 0x????0202 for NV50+ cards (empirical evidence) */ - if(dev_priv->card_type >= NV_50) { + if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) { + timing->reg_100228 |= (tUNK_19 - 1) << 24; + } + + if(dev_priv->card_type == NV_40) { + /* NV40: don't know what the rest of the regs are.. + * And don't need to know either */ + timing->reg_100228 |= 0x20200000 | magic_number << 24; + } else if(dev_priv->card_type >= NV_50) { + /* XXX: reg_10022c */ + timing->reg_10022c = tUNK_2 - 1; + + timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | + tUNK_13 << 8 | tUNK_13); + + timing->reg_100234 = (tRAS << 24 | tRC); + timing->reg_100234 += max(tUNK_10,tUNK_11) << 16; + + if(dev_priv->chipset < 0xa3) { + timing->reg_100234 |= (tUNK_2 + 2) << 8; + } else { + /* XXX: +6? */ + timing->reg_100234 |= (tUNK_19 + 6) << 8; + } + + /* XXX; reg_100238, reg_10023c + * reg_100238: 0x00?????? + * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */ timing->reg_10023c = 0x202; + if(dev_priv->chipset < 0xa3) { + timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; + } else { + /* currently unknown + * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ + } } NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, @@ -675,7 +697,7 @@ nouveau_mem_timing_init(struct drm_device *dev) timing->reg_100238, timing->reg_10023c); } - memtimings->nr_timing = entries; + memtimings->nr_timing = entries; memtimings->supported = true; } -- cgit v1.2.2 From b251d1a488b8a742b621f4cd28f7e57a7bacc434 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 18 Mar 2011 20:19:53 +0000 Subject: nv30: Fix parsing of perf table Perf tables v 1.2 and 1.3 (seen on Geforce FX/ 5) are not long enough to store the voltage label/id v2 - Remove comment from the code Signed-off-by: Emil Velikov Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_perf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index ac62a1b8c4fc..670e3cb697ec 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c @@ -134,7 +134,7 @@ nouveau_perf_init(struct drm_device *dev) case 0x13: case 0x15: perflvl->fanspeed = entry[55]; - perflvl->voltage = entry[56]; + perflvl->voltage = (recordlen > 56) ? entry[56] : 0; perflvl->core = ROM32(entry[1]) * 10; perflvl->memory = ROM32(entry[5]) * 20; break; -- cgit v1.2.2 From fb522ee1aa57f2bb57ebd1111524601076d9ad0a Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Thu, 10 Mar 2011 22:43:25 +0100 Subject: drm/nouveau: fix oops on unload with disabled LVDS panel Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=35135 BUG: unable to handle kernel NULL pointer dereference at 000002d8 IP: [] nv04_dfp_restore+0x7f/0xd0 [nouveau] (...) Call Trace: [] nv04_display_destroy+0xa8/0x140 [nouveau] [] nouveau_unload+0x2a/0x160 [nouveau] [] drm_put_dev+0xbb/0x1b0 [drm] [] nouveau_pci_remove+0x15/0x20 [nouveau] [] pci_device_remove+0x44/0xf0 [] __device_release_driver+0x51/0xb0 [] driver_detach+0x8f/0xa0 [] bus_remove_driver+0x63/0xa0 [] driver_unregister+0x49/0x80 [] ? sysfs_remove_file+0x14/0x20 [] pci_unregister_driver+0x32/0x90 [] ? __stop_machine+0x5a/0x70 [] drm_exit+0x83/0x90 [drm] [] nouveau_exit+0x1b/0x8be [nouveau] [] sys_delete_module+0x13b/0x1f0 [] ? do_munmap+0x1fe/0x280 [] ? arch_unmap_area_topdown+0x0/0x20 [] syscall_call+0x7/0xb Reported-by: Francesco Marella Tested-by: Francesco Marella Signed-off-by: Marcin Slusarz [ currojerez@riseup.net: No need to spam the logs in that case, an unbound LVDS encoder is not an error. ] Signed-off-by: Francisco Jerez Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv04_dfp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index c82db37d9f41..12098bf839c4 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -581,12 +581,13 @@ static void nv04_dfp_restore(struct drm_encoder *encoder) int head = nv_encoder->restore.head; if (nv_encoder->dcb->type == OUTPUT_LVDS) { - struct drm_display_mode *native_mode = nouveau_encoder_connector_get(nv_encoder)->native_mode; - if (native_mode) - call_lvds_script(dev, nv_encoder->dcb, head, LVDS_PANEL_ON, - native_mode->clock); - else - NV_ERROR(dev, "Not restoring LVDS without native mode\n"); + struct nouveau_connector *connector = + nouveau_encoder_connector_get(nv_encoder); + + if (connector && connector->native_mode) + call_lvds_script(dev, nv_encoder->dcb, head, + LVDS_PANEL_ON, + connector->native_mode->clock); } else if (nv_encoder->dcb->type == OUTPUT_TMDS) { int clock = nouveau_hw_pllvals_to_clk -- cgit v1.2.2 From ec64a40868469d308ad1e040c6ead2373af334dd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 21 Mar 2011 21:31:21 +1000 Subject: drm/nouveau: implement init table opcode 0x5c Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 8314a49b6b9a..eca191accb6a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -269,7 +269,7 @@ struct init_tbl_entry { int (*handler)(struct nvbios *, uint16_t, struct init_exec *); }; -static int parse_init_table(struct nvbios *, unsigned int, struct init_exec *); +static int parse_init_table(struct nvbios *, uint16_t, struct init_exec *); #define MACRO_INDEX_SIZE 2 #define MACRO_SIZE 8 @@ -2010,6 +2010,27 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) return 3; } +static int +init_jump(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) +{ + /* + * INIT_JUMP opcode: 0x5C ('\') + * + * offset (8 bit): opcode + * offset + 1 (16 bit): offset (in bios) + * + * Continue execution of init table from 'offset' + */ + + uint16_t jmp_offset = ROM16(bios->data[offset + 1]); + + if (!iexec->execute) + return 3; + + BIOSLOG(bios, "0x%04X: Jump to 0x%04X\n", offset, jmp_offset); + return jmp_offset - offset; +} + static int init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { @@ -3659,6 +3680,7 @@ static struct init_tbl_entry itbl_entry[] = { { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, + { "INIT_JUMP" , 0x5C, init_jump }, { "INIT_I2C_IF" , 0x5E, init_i2c_if }, { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg }, { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io }, @@ -3700,8 +3722,7 @@ static struct init_tbl_entry itbl_entry[] = { #define MAX_TABLE_OPS 1000 static int -parse_init_table(struct nvbios *bios, unsigned int offset, - struct init_exec *iexec) +parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { /* * Parses all commands in an init table. -- cgit v1.2.2 From 59197c026257ab730c7fc8819a0e2b26e125a534 Mon Sep 17 00:00:00 2001 From: David Dillow Date: Mon, 21 Mar 2011 21:41:47 +1000 Subject: drm/nv50-nvc0: work around an evo channel hang that some people see Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_evo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c index a2cfaa691e9b..c8e83c1a4de8 100644 --- a/drivers/gpu/drm/nouveau/nv50_evo.c +++ b/drivers/gpu/drm/nouveau/nv50_evo.c @@ -186,6 +186,7 @@ nv50_evo_channel_init(struct nouveau_channel *evo) nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id); evo->dma.max = (4096/4) - 2; + evo->dma.max &= ~7; evo->dma.put = 0; evo->dma.cur = evo->dma.put; evo->dma.free = evo->dma.max - evo->dma.cur; -- cgit v1.2.2 From c0929b499f834210561fe5e8c48bcad4f2130d25 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 21 Mar 2011 11:42:51 +1000 Subject: drm/nouveau: quirk for XFX GT-240X-YA Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index eca191accb6a..90aef64b76f2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6354,6 +6354,32 @@ apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) } } + /* XFX GT-240X-YA + * + * So many things wrong here, replace the entire encoder table.. + */ + if (nv_match_device(dev, 0x0ca3, 0x1682, 0x3003)) { + if (idx == 0) { + *conn = 0x02001300; /* VGA, connector 1 */ + *conf = 0x00000028; + } else + if (idx == 1) { + *conn = 0x01010312; /* DVI, connector 0 */ + *conf = 0x00020030; + } else + if (idx == 2) { + *conn = 0x01010310; /* VGA, connector 0 */ + *conf = 0x00000028; + } else + if (idx == 3) { + *conn = 0x02022362; /* HDMI, connector 2 */ + *conf = 0x00020010; + } else { + *conn = 0x0000000e; /* EOL */ + *conf = 0x00000000; + } + } + return true; } -- cgit v1.2.2 From 2b4cebe4e165b0ef30a138e4cf602538dea15583 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 29 Mar 2011 09:56:14 +1000 Subject: drm/nv50: use "nv86" tlb flush method on everything except 0x50/0xac It has been reported that this greatly improves (and possibly fixes completely) the stability of NVA3+ chipsets. In traces of my NVA8, NVIDIA now appear to be doing this too. The most recent traces of 0x50 and 0xac I could find don't show NVIDIA checking PGRAPH status on these flushes, so for now, we won't either. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 +- drivers/gpu/drm/nouveau/nouveau_state.c | 12 ++++-------- drivers/gpu/drm/nouveau/nv50_graph.c | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index fff180a99867..59ed5be403ef 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1190,7 +1190,7 @@ extern int nv50_graph_load_context(struct nouveau_channel *); extern int nv50_graph_unload_context(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); extern void nv50_graph_tlb_flush(struct drm_device *dev); -extern void nv86_graph_tlb_flush(struct drm_device *dev); +extern void nv84_graph_tlb_flush(struct drm_device *dev); extern struct nouveau_enum nv50_data_error_names[]; /* nvc0_graph.c */ diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 4fcbd091a117..1e7e006c75e4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -376,15 +376,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->graph.destroy_context = nv50_graph_destroy_context; engine->graph.load_context = nv50_graph_load_context; engine->graph.unload_context = nv50_graph_unload_context; - if (dev_priv->chipset != 0x86) + if (dev_priv->chipset == 0x50 || + dev_priv->chipset == 0xac) engine->graph.tlb_flush = nv50_graph_tlb_flush; - else { - /* from what i can see nvidia do this on every - * pre-NVA3 board except NVAC, but, we've only - * ever seen problems on NV86 - */ - engine->graph.tlb_flush = nv86_graph_tlb_flush; - } + else + engine->graph.tlb_flush = nv84_graph_tlb_flush; engine->fifo.channels = 128; engine->fifo.init = nv50_fifo_init; engine->fifo.takedown = nv50_fifo_takedown; diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 8675b00caf18..b02a5b1e7d37 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -503,7 +503,7 @@ nv50_graph_tlb_flush(struct drm_device *dev) } void -nv86_graph_tlb_flush(struct drm_device *dev) +nv84_graph_tlb_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; -- cgit v1.2.2 From e61e51f134a3299c2c37051f69638cc9e9fd88c1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 30 Mar 2011 11:56:16 +1000 Subject: drm/nv50-nvc0: remove some code that doesn't belong here Not sure how this snuck in... Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_crtc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index 2b9984027f41..a19ccaa025b3 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -469,9 +469,6 @@ nv50_crtc_wait_complete(struct drm_crtc *crtc) start = ptimer->read(dev); do { - nv_wr32(dev, 0x61002c, 0x370); - nv_wr32(dev, 0x000140, 1); - if (nv_ro32(disp->ntfy, 0x000)) return 0; } while (ptimer->read(dev) - start < 2000000000ULL); -- cgit v1.2.2 From a719726f4ceaf14842c80fd7e58dec40cb7022a2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 30 Mar 2011 13:57:44 +1000 Subject: drm/nvc0: improve vm flush function Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvc0_vm.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c index 69af0ba7edd3..a0a2a0277f73 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vm.c +++ b/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -104,20 +104,26 @@ nvc0_vm_flush(struct nouveau_vm *vm) struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; struct drm_device *dev = vm->dev; struct nouveau_vm_pgd *vpgd; - u32 r100c80, engine; + u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5; pinstmem->flush(vm->dev); - if (vm == dev_priv->chan_vm) - engine = 1; - else - engine = 5; - + spin_lock(&dev_priv->ramin_lock); list_for_each_entry(vpgd, &vm->pgd_list, head) { - r100c80 = nv_rd32(dev, 0x100c80); + /* looks like maybe a "free flush slots" counter, the + * faster you write to 0x100cbc to more it decreases + */ + if (!nv_wait_ne(dev, 0x100c80, 0x00ff0000, 0x00000000)) { + NV_ERROR(dev, "vm timeout 0: 0x%08x %d\n", + nv_rd32(dev, 0x100c80), engine); + } nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8); nv_wr32(dev, 0x100cbc, 0x80000000 | engine); - if (!nv_wait(dev, 0x100c80, 0xffffffff, r100c80)) - NV_ERROR(dev, "vm flush timeout eng %d\n", engine); + /* wait for flush to be queued? */ + if (!nv_wait(dev, 0x100c80, 0x00008000, 0x00008000)) { + NV_ERROR(dev, "vm timeout 1: 0x%08x %d\n", + nv_rd32(dev, 0x100c80), engine); + } } + spin_unlock(&dev_priv->ramin_lock); } -- cgit v1.2.2 From 75e4fb221babbe329c1aba8c34092d29034f1545 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 16 Mar 2011 21:40:59 -0400 Subject: staging: hv: fix reversed memset arguments in hv_mouse size is 3rd arg, not the 2nd. Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/hv_mouse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c index 50147f84741c..cbe568616850 100644 --- a/drivers/staging/hv/hv_mouse.c +++ b/drivers/staging/hv/hv_mouse.c @@ -374,7 +374,7 @@ static void MousevscOnReceiveDeviceInfo(struct mousevsc_dev *InputDevice, struct desc->desc[0].wDescriptorLength); /* Send the ack */ - memset(&ack, sizeof(struct mousevsc_prt_msg), 0); + memset(&ack, 0, sizeof(struct mousevsc_prt_msg)); ack.type = PipeMessageData; ack.size = sizeof(struct synthhid_device_info_ack); @@ -595,7 +595,7 @@ static int MousevscConnectToVsp(struct hv_device *Device) /* * Now, initiate the vsc/vsp initialization protocol on the open channel */ - memset(request, sizeof(struct mousevsc_prt_msg), 0); + memset(request, 0, sizeof(struct mousevsc_prt_msg)); request->type = PipeMessageData; request->size = sizeof(struct synthhid_protocol_request); -- cgit v1.2.2 From 22356585712d1ff08fbfed152edd8b386873b238 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 21 Mar 2011 14:41:37 +0100 Subject: staging: hv: use sync_bitops when interacting with the hypervisor Locking is required when tweaking bits located in a shared page, use the sync_ version of bitops. Without this change vmbus_on_event() will miss events and as a result, vmbus_isr() will not schedule the receive tasklet. Signed-off-by: Olaf Hering Cc: stable Acked-by: Haiyang Zhang Acked-by: Hank Janssen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/channel.c | 8 ++++---- drivers/staging/hv/connection.c | 4 ++-- drivers/staging/hv/vmbus_drv.c | 2 +- drivers/staging/hv/vmbus_private.h | 1 + 4 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/channel.c b/drivers/staging/hv/channel.c index 775a52a91222..f7ce7d2494b3 100644 --- a/drivers/staging/hv/channel.c +++ b/drivers/staging/hv/channel.c @@ -81,14 +81,14 @@ static void vmbus_setevent(struct vmbus_channel *channel) if (channel->offermsg.monitor_allocated) { /* Each u32 represents 32 channels */ - set_bit(channel->offermsg.child_relid & 31, + sync_set_bit(channel->offermsg.child_relid & 31, (unsigned long *) vmbus_connection.send_int_page + (channel->offermsg.child_relid >> 5)); monitorpage = vmbus_connection.monitor_pages; monitorpage++; /* Get the child to parent monitor page */ - set_bit(channel->monitor_bit, + sync_set_bit(channel->monitor_bit, (unsigned long *)&monitorpage->trigger_group [channel->monitor_grp].pending); @@ -104,7 +104,7 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel) if (Channel->offermsg.monitor_allocated) { /* Each u32 represents 32 channels */ - clear_bit(Channel->offermsg.child_relid & 31, + sync_clear_bit(Channel->offermsg.child_relid & 31, (unsigned long *)vmbus_connection.send_int_page + (Channel->offermsg.child_relid >> 5)); @@ -112,7 +112,7 @@ static void VmbusChannelClearEvent(struct vmbus_channel *channel) vmbus_connection.monitor_pages; monitorPage++; /* Get the child to parent monitor page */ - clear_bit(Channel->monitor_bit, + sync_clear_bit(Channel->monitor_bit, (unsigned long *)&monitorPage->trigger_group [Channel->monitor_grp].Pending); } diff --git a/drivers/staging/hv/connection.c b/drivers/staging/hv/connection.c index 44b203b95a22..afc8116e7aa4 100644 --- a/drivers/staging/hv/connection.c +++ b/drivers/staging/hv/connection.c @@ -296,7 +296,7 @@ void vmbus_on_event(unsigned long data) for (dword = 0; dword < maxdword; dword++) { if (recv_int_page[dword]) { for (bit = 0; bit < 32; bit++) { - if (test_and_clear_bit(bit, + if (sync_test_and_clear_bit(bit, (unsigned long *) &recv_int_page[dword])) { relid = (dword << 5) + bit; @@ -338,7 +338,7 @@ int vmbus_post_msg(void *buffer, size_t buflen) int vmbus_set_event(u32 child_relid) { /* Each u32 represents 32 channels */ - set_bit(child_relid & 31, + sync_set_bit(child_relid & 31, (unsigned long *)vmbus_connection.send_int_page + (child_relid >> 5)); diff --git a/drivers/staging/hv/vmbus_drv.c b/drivers/staging/hv/vmbus_drv.c index b473f468dd83..79089f85d903 100644 --- a/drivers/staging/hv/vmbus_drv.c +++ b/drivers/staging/hv/vmbus_drv.c @@ -254,7 +254,7 @@ static int vmbus_on_isr(void) event = (union hv_synic_event_flags *)page_addr + VMBUS_MESSAGE_SINT; /* Since we are a child, we only need to check bit 0 */ - if (test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) { + if (sync_test_and_clear_bit(0, (unsigned long *) &event->flags32[0])) { DPRINT_DBG(VMBUS, "received event %d", event->flags32[0]); ret |= 0x2; } diff --git a/drivers/staging/hv/vmbus_private.h b/drivers/staging/hv/vmbus_private.h index ca050a499b99..6f0d8df5e178 100644 --- a/drivers/staging/hv/vmbus_private.h +++ b/drivers/staging/hv/vmbus_private.h @@ -31,6 +31,7 @@ #include "channel_mgmt.h" #include "ring_buffer.h" #include +#include /* -- cgit v1.2.2 From 7989f7d5ea65b10d2d4c8249aca75690d4d71e17 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 22 Mar 2011 10:02:17 +0100 Subject: staging: hv: update dist release parsing in hv_kvp_daemon The current code to parse the distribution file handles only files with at least 3 lines. openSuSE has 2 lines and Redhat only one (according to google). Update the parser to handle up to three lines properly. Also make the buffer allocation dynamic and remove a few casts to avoid compiler warnings. Signed-off-by: Olaf Hering Acked-by: KY Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/tools/hv_kvp_daemon.c | 90 ++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/hv/tools/hv_kvp_daemon.c b/drivers/staging/hv/tools/hv_kvp_daemon.c index f5a2dd694611..f51264031376 100644 --- a/drivers/staging/hv/tools/hv_kvp_daemon.c +++ b/drivers/staging/hv/tools/hv_kvp_daemon.c @@ -102,22 +102,22 @@ static char kvp_send_buffer[4096]; static char kvp_recv_buffer[4096]; static struct sockaddr_nl addr; -static char os_name[100]; -static char os_major[50]; -static char os_minor[50]; -static char processor_arch[50]; -static char os_build[100]; +static char *os_name = ""; +static char *os_major = ""; +static char *os_minor = ""; +static char *processor_arch; +static char *os_build; static char *lic_version; +static struct utsname uts_buf; void kvp_get_os_info(void) { FILE *file; - char *eol; - struct utsname buf; + char *p, buf[512]; - uname(&buf); - strcpy(os_build, buf.release); - strcpy(processor_arch, buf.machine); + uname(&uts_buf); + os_build = uts_buf.release; + processor_arch= uts_buf.machine; file = fopen("/etc/SuSE-release", "r"); if (file != NULL) @@ -132,21 +132,46 @@ void kvp_get_os_info(void) /* * We don't have information about the os. */ - strcpy(os_name, "Linux"); - strcpy(os_major, "0"); - strcpy(os_minor, "0"); + os_name = uts_buf.sysname; return; kvp_osinfo_found: - fgets(os_name, 99, file); - eol = index(os_name, '\n'); - *eol = '\0'; - fgets(os_major, 49, file); - eol = index(os_major, '\n'); - *eol = '\0'; - fgets(os_minor, 49, file); - eol = index(os_minor, '\n'); - *eol = '\0'; + /* up to three lines */ + p = fgets(buf, sizeof(buf), file); + if (p) { + p = strchr(buf, '\n'); + if (p) + *p = '\0'; + p = strdup(buf); + if (!p) + goto done; + os_name = p; + + /* second line */ + p = fgets(buf, sizeof(buf), file); + if (p) { + p = strchr(buf, '\n'); + if (p) + *p = '\0'; + p = strdup(buf); + if (!p) + goto done; + os_major = p; + + /* third line */ + p = fgets(buf, sizeof(buf), file); + if (p) { + p = strchr(buf, '\n'); + if (p) + *p = '\0'; + p = strdup(buf); + if (p) + os_minor = p; + } + } + } + +done: fclose(file); return; } @@ -293,7 +318,7 @@ netlink_send(int fd, struct cn_msg *msg) return sendmsg(fd, &message, 0); } -main(void) +int main(void) { int fd, len, sock_opt; int error; @@ -301,9 +326,10 @@ main(void) struct pollfd pfd; struct nlmsghdr *incoming_msg; struct cn_msg *incoming_cn_msg; + struct hv_ku_msg *hv_msg; + char *p; char *key_value; char *key_name; - int key_index; daemon(1, 0); openlog("KVP", 0, LOG_USER); @@ -373,9 +399,10 @@ main(void) * Driver is registering with us; stash away the version * information. */ - lic_version = malloc(strlen(incoming_cn_msg->data) + 1); + p = (char *)incoming_cn_msg->data; + lic_version = malloc(strlen(p) + 1); if (lic_version) { - strcpy(lic_version, incoming_cn_msg->data); + strcpy(lic_version, p); syslog(LOG_INFO, "KVP LIC Version: %s", lic_version); } else { @@ -389,14 +416,11 @@ main(void) continue; } - key_index = - ((struct hv_ku_msg *)incoming_cn_msg->data)->kvp_index; - key_name = - ((struct hv_ku_msg *)incoming_cn_msg->data)->kvp_key; - key_value = - ((struct hv_ku_msg *)incoming_cn_msg->data)->kvp_value; + hv_msg = (struct hv_ku_msg *)incoming_cn_msg->data; + key_name = (char *)hv_msg->kvp_key; + key_value = (char *)hv_msg->kvp_value; - switch (key_index) { + switch (hv_msg->kvp_index) { case FullyQualifiedDomainName: kvp_get_domain_name(key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); -- cgit v1.2.2 From 07e195fde6dd553f30fb287fc169d64895425f5e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 17 Mar 2011 08:19:18 -0700 Subject: Staging: vt665?: prevent modules from being built into the kernel. It causes lots of linking errors when both of these modules are built into the kernel directly due to their global symbol mess. Reported-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/Kconfig | 2 +- drivers/staging/vt6656/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vt6655/Kconfig b/drivers/staging/vt6655/Kconfig index 061e730df2d0..c3ba693a8cad 100644 --- a/drivers/staging/vt6655/Kconfig +++ b/drivers/staging/vt6655/Kconfig @@ -1,6 +1,6 @@ config VT6655 tristate "VIA Technologies VT6655 support" - depends on PCI && WLAN + depends on PCI && WLAN && m select WIRELESS_EXT select WEXT_PRIV ---help--- diff --git a/drivers/staging/vt6656/Kconfig b/drivers/staging/vt6656/Kconfig index a441ba513c40..f89ab205c8e0 100644 --- a/drivers/staging/vt6656/Kconfig +++ b/drivers/staging/vt6656/Kconfig @@ -1,6 +1,6 @@ config VT6656 tristate "VIA Technologies VT6656 support" - depends on USB && WLAN + depends on USB && WLAN && m select WIRELESS_EXT select WEXT_PRIV select FW_LOADER -- cgit v1.2.2 From e0007c0c87f02b357a4f97f792c96f1264d09ea9 Mon Sep 17 00:00:00 2001 From: wwang Date: Tue, 15 Mar 2011 16:22:06 +0800 Subject: staging: rts_pstor: modify initial card clock Modify initial card clock to avoid over spec Signed-off-by: wwang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts_pstor/rtsx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rts_pstor/rtsx.c b/drivers/staging/rts_pstor/rtsx.c index 4514419a5fb8..02525d57ba83 100644 --- a/drivers/staging/rts_pstor/rtsx.c +++ b/drivers/staging/rts_pstor/rtsx.c @@ -824,13 +824,13 @@ static void rtsx_init_options(struct rtsx_chip *chip) chip->fpga_ms_hg_clk = CLK_80; chip->fpga_ms_4bit_clk = CLK_80; chip->fpga_ms_1bit_clk = CLK_40; - chip->asic_sd_sdr104_clk = 207; - chip->asic_sd_sdr50_clk = 99; - chip->asic_sd_ddr50_clk = 99; - chip->asic_sd_hs_clk = 99; - chip->asic_mmc_52m_clk = 99; - chip->asic_ms_hg_clk = 119; - chip->asic_ms_4bit_clk = 79; + chip->asic_sd_sdr104_clk = 203; + chip->asic_sd_sdr50_clk = 98; + chip->asic_sd_ddr50_clk = 98; + chip->asic_sd_hs_clk = 98; + chip->asic_mmc_52m_clk = 98; + chip->asic_ms_hg_clk = 117; + chip->asic_ms_4bit_clk = 78; chip->asic_ms_1bit_clk = 39; chip->ssc_depth_sd_sdr104 = SSC_DEPTH_2M; chip->ssc_depth_sd_sdr50 = SSC_DEPTH_2M; -- cgit v1.2.2 From ea4fca42b9ba61c68f77a783fcae13368a71b6bc Mon Sep 17 00:00:00 2001 From: wwang Date: Tue, 15 Mar 2011 16:22:16 +0800 Subject: staging: rts_pstor: set lun_mode in a different place In sony notebook, card reader will be configured as two-lun mode through EFUSE. In this situation, MS card can't be recognized properly because driver does only support single-lun mode in default. In this patch, lun_mode is set in a different place, so driver can detect the EFUSE configuation automatically. Signed-off-by: wwang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts_pstor/rtsx_chip.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c index f443d97a56f8..d2f1c715a684 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.c +++ b/drivers/staging/rts_pstor/rtsx_chip.c @@ -684,6 +684,11 @@ static int rts5209_init(struct rtsx_chip *chip) RTSX_DEBUGP("dw in 0x724: 0x%x\n", lval); val = (u8)lval; if (!(val & 0x80)) { + if (val & 0x08) + chip->lun_mode = DEFAULT_SINGLE; + else + chip->lun_mode = SD_MS_2LUN; + if (val & 0x04) { SET_SDIO_EXIST(chip); } else { @@ -705,12 +710,6 @@ static int rts5209_init(struct rtsx_chip *chip) chip->aspm_l0s_l1_en = (val >> 5) & 0x03; - if (val & 0x08) { - chip->lun_mode = DEFAULT_SINGLE; - } else { - chip->lun_mode = SD_MS_2LUN; - } - val = (u8)(lval >> 8); clk = (val >> 5) & 0x07; -- cgit v1.2.2 From 14e5d8ef5beedf47005b1433096c0e30815da9b3 Mon Sep 17 00:00:00 2001 From: pixo Date: Wed, 23 Mar 2011 08:08:08 +0100 Subject: staging: ft1000-pcmcia: Fix ft1000_dnld() to work also on 64bit architectures. Firmware file needs to be read by 4bytes also on 64 bit architectures. Change long type to u32 and also extend checking. Tested on 32 and also 64 bit architectures. Signed-off-by: Stano Lanci Signed-off-by: Marek Belisko Tested-by: Stano Lanci Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c | 78 +++++++++++----------- 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c index b0729fc3c89a..fb375ea26dd2 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c @@ -95,47 +95,47 @@ void put_request_value(struct net_device *dev, long lvalue); USHORT hdr_checksum(PPSEUDO_HDR pHdr); typedef struct _DSP_FILE_HDR { - long build_date; - long dsp_coff_date; - long loader_code_address; - long loader_code_size; - long loader_code_end; - long dsp_code_address; - long dsp_code_size; - long dsp_code_end; - long reserved[8]; + u32 build_date; + u32 dsp_coff_date; + u32 loader_code_address; + u32 loader_code_size; + u32 loader_code_end; + u32 dsp_code_address; + u32 dsp_code_size; + u32 dsp_code_end; + u32 reserved[8]; } __attribute__ ((packed)) DSP_FILE_HDR, *PDSP_FILE_HDR; typedef struct _DSP_FILE_HDR_5 { - long version_id; // Version ID of this image format. - long package_id; // Package ID of code release. - long build_date; // Date/time stamp when file was built. - long commands_offset; // Offset to attached commands in Pseudo Hdr format. - long loader_offset; // Offset to bootloader code. - long loader_code_address; // Start address of bootloader. - long loader_code_end; // Where bootloader code ends. - long loader_code_size; - long version_data_offset; // Offset were scrambled version data begins. - long version_data_size; // Size, in words, of scrambled version data. - long nDspImages; // Number of DSP images in file. + u32 version_id; // Version ID of this image format. + u32 package_id; // Package ID of code release. + u32 build_date; // Date/time stamp when file was built. + u32 commands_offset; // Offset to attached commands in Pseudo Hdr format. + u32 loader_offset; // Offset to bootloader code. + u32 loader_code_address; // Start address of bootloader. + u32 loader_code_end; // Where bootloader code ends. + u32 loader_code_size; + u32 version_data_offset; // Offset were scrambled version data begins. + u32 version_data_size; // Size, in words, of scrambled version data. + u32 nDspImages; // Number of DSP images in file. } __attribute__ ((packed)) DSP_FILE_HDR_5, *PDSP_FILE_HDR_5; typedef struct _DSP_IMAGE_INFO { - long coff_date; // Date/time when DSP Coff image was built. - long begin_offset; // Offset in file where image begins. - long end_offset; // Offset in file where image begins. - long run_address; // On chip Start address of DSP code. - long image_size; // Size of image. - long version; // Embedded version # of DSP code. + u32 coff_date; // Date/time when DSP Coff image was built. + u32 begin_offset; // Offset in file where image begins. + u32 end_offset; // Offset in file where image begins. + u32 run_address; // On chip Start address of DSP code. + u32 image_size; // Size of image. + u32 version; // Embedded version # of DSP code. } __attribute__ ((packed)) DSP_IMAGE_INFO, *PDSP_IMAGE_INFO; typedef struct _DSP_IMAGE_INFO_V6 { - long coff_date; // Date/time when DSP Coff image was built. - long begin_offset; // Offset in file where image begins. - long end_offset; // Offset in file where image begins. - long run_address; // On chip Start address of DSP code. - long image_size; // Size of image. - long version; // Embedded version # of DSP code. + u32 coff_date; // Date/time when DSP Coff image was built. + u32 begin_offset; // Offset in file where image begins. + u32 end_offset; // Offset in file where image begins. + u32 run_address; // On chip Start address of DSP code. + u32 image_size; // Size of image. + u32 version; // Embedded version # of DSP code. unsigned short checksum; // Dsp File checksum unsigned short pad1; } __attribute__ ((packed)) DSP_IMAGE_INFO_V6, *PDSP_IMAGE_INFO_V6; @@ -846,8 +846,8 @@ int card_download(struct net_device *dev, const u8 *pFileStart, UINT FileLength) break; case STATE_DONE_DWNLD: - if (((UINT) (pUcFile) - (UINT) pFileStart) >= - (UINT) FileLength) { + if (((unsigned long) (pUcFile) - (unsigned long) pFileStart) >= + (unsigned long) FileLength) { uiState = STATE_DONE_FILE; break; } @@ -901,11 +901,11 @@ int card_download(struct net_device *dev, const u8 *pFileStart, UINT FileLength) &info->prov_list); // Move to next entry if available pUcFile = - (UCHAR *) ((UINT) pUcFile + - (UINT) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(PSEUDO_HDR)); - if ((UINT) (pUcFile) - - (UINT) (pFileStart) >= - (UINT) FileLength) { + (UCHAR *) ((unsigned long) pUcFile + + (unsigned long) ((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(PSEUDO_HDR)); + if ((unsigned long) (pUcFile) - + (unsigned long) (pFileStart) >= + (unsigned long) FileLength) { uiState = STATE_DONE_FILE; } -- cgit v1.2.2 From 9c94b7a668ea7422ad75e97c3bfd6274b37495c6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 20 Mar 2011 14:11:31 +0300 Subject: Staging: westbridge/astoria: unlock on error path There is an unlock missing on this error path. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/westbridge/astoria/gadget/cyasgadget.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c b/drivers/staging/westbridge/astoria/gadget/cyasgadget.c index defa05cd5e50..be851ca54cec 100644 --- a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c +++ b/drivers/staging/westbridge/astoria/gadget/cyasgadget.c @@ -587,6 +587,7 @@ static int cyasgadget_enable( "cy_as_usb_end_point_config EP %s mismatch " "on enabled\n", an_ep->usb_ep_inst.name); #endif + spin_unlock_irqrestore(&an_dev->lock, flags); return -EINVAL; } -- cgit v1.2.2 From 392a002a0066812480e1b55639bbced5936d26aa Mon Sep 17 00:00:00 2001 From: "Javier M. Mellid" Date: Wed, 30 Mar 2011 16:24:10 +0200 Subject: staging: sm7xx: fixed defines Deleted redundant __KERNEL__ define PM methods (suspend and resume) enabled under CONFIG_PM only Signed-off-by: Javier M. Mellid Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm7xx/smtcfb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c index d007e4a12c14..0d65971457fc 100644 --- a/drivers/staging/sm7xx/smtcfb.c +++ b/drivers/staging/sm7xx/smtcfb.c @@ -26,10 +26,6 @@ * Boyod.yang */ -#ifndef __KERNEL__ -#define __KERNEL__ -#endif - #include #include #include @@ -1019,6 +1015,7 @@ static void __devexit smtcfb_pci_remove(struct pci_dev *pdev) smtc_free_fb_info(sfb); } +#ifdef CONFIG_PM /* Jason (08/14/2009) * suspend function, called when the suspend event is triggered */ @@ -1111,6 +1108,7 @@ static int __maybe_unused smtcfb_resume(struct pci_dev *pdev) return 0; } +#endif /* Jason (08/13/2009) * pci_driver struct used to wrap the original driver -- cgit v1.2.2 From bed4ab7781e8600a7ebf4378a1b3f26d31517f57 Mon Sep 17 00:00:00 2001 From: Sascha Silbe Date: Sun, 3 Apr 2011 12:05:36 +0200 Subject: staging: fix olpc_dcon build errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c: In function ‘dcon_wiggle_xo_1_5’: drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c:155: error: implicit declaration of function ‘udelay’ drivers/built-in.o: In function `dcon_read_status_xo_1': olpc_dcon_xo_1.c:(.text+0x13472e): undefined reference to `cs5535_gpio_set' Signed-off-by: Sascha Silbe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/olpc_dcon/Kconfig | 2 +- drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig index f1082f50fdce..b05306766870 100644 --- a/drivers/staging/olpc_dcon/Kconfig +++ b/drivers/staging/olpc_dcon/Kconfig @@ -9,7 +9,7 @@ config FB_OLPC_DCON config FB_OLPC_DCON_1 bool "OLPC XO-1 DCON support" - depends on FB_OLPC_DCON + depends on FB_OLPC_DCON && GPIO_CS5535 default y ---help--- Enable support for the DCON in XO-1 model laptops. The kernel diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c index e213b63f8116..7aa9b1a45bd6 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include -- cgit v1.2.2 From a58c616a9525a7094e950a64ec9232905a2858b5 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 1 Apr 2011 09:50:54 -0700 Subject: staging: fix hv_mouse build, needs delay.h Fix hv_mouse.c build, it needs delay.h: drivers/staging/hv/hv_mouse.c:293: error: implicit declaration of function 'udelay' Signed-off-by: Randy Dunlap Cc: Hank Janssen Cc: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/hv_mouse.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c index cbe568616850..05b86cc09dba 100644 --- a/drivers/staging/hv/hv_mouse.c +++ b/drivers/staging/hv/hv_mouse.c @@ -14,6 +14,7 @@ */ #include #include +#include #include #include #include -- cgit v1.2.2 From 00838d4f507ae73f2b5a260c826f6275bd2d4ba7 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 30 Mar 2011 23:43:16 +0100 Subject: staging: sep: remove last memrar remnants So we can drop the memrar staging driver Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sep/sep_driver.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c index 71a5fbc041e4..7009fd8b79f2 100644 --- a/drivers/staging/sep/sep_driver.c +++ b/drivers/staging/sep/sep_driver.c @@ -55,8 +55,6 @@ #include #include -#include "../memrar/memrar.h" - #include "sep_driver_hw_defs.h" #include "sep_driver_config.h" #include "sep_driver_api.h" @@ -2372,7 +2370,6 @@ static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, int error = 0; /* Command args */ struct rar_hndl_to_bus_struct command_args; - struct RAR_buffer rar_buf; /* Bus address */ dma_addr_t rar_bus = 0; /* Holds the RAR address in the system memory offset */ @@ -2386,16 +2383,8 @@ static int sep_rar_prepare_output_msg_handler(struct sep_device *sep, } /* Call to translation function only if user handle is not NULL */ - if (command_args.rar_handle) { - memset(&rar_buf, 0, sizeof(rar_buf)); - rar_buf.info.handle = (u32)command_args.rar_handle; - - if (rar_handle_to_bus(&rar_buf, 1) != 1) { - error = -EFAULT; - goto end_function; - } - rar_bus = rar_buf.bus_address; - } + if (command_args.rar_handle) + return -EOPNOTSUPP; dev_dbg(&sep->pdev->dev, "rar msg; rar_addr_bus = %x\n", (u32)rar_bus); /* Set value in the SYSTEM MEMORY offset */ -- cgit v1.2.2 From 4dd2b32f3c48112da2ffe55279aedc10c3784f90 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 4 Apr 2011 21:41:20 -0700 Subject: staging: memrar: remove driver from tree It's no longer needed at all. Cc: Ossama Othman Cc: Eugene Epshteyn Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/memrar/Kconfig | 15 - drivers/staging/memrar/Makefile | 2 - drivers/staging/memrar/TODO | 43 -- drivers/staging/memrar/memrar-abi | 89 --- drivers/staging/memrar/memrar.h | 174 ----- drivers/staging/memrar/memrar_allocator.c | 432 ------------- drivers/staging/memrar/memrar_allocator.h | 149 ----- drivers/staging/memrar/memrar_handler.c | 1007 ----------------------------- 10 files changed, 1914 deletions(-) delete mode 100644 drivers/staging/memrar/Kconfig delete mode 100644 drivers/staging/memrar/Makefile delete mode 100644 drivers/staging/memrar/TODO delete mode 100644 drivers/staging/memrar/memrar-abi delete mode 100644 drivers/staging/memrar/memrar.h delete mode 100644 drivers/staging/memrar/memrar_allocator.c delete mode 100644 drivers/staging/memrar/memrar_allocator.h delete mode 100644 drivers/staging/memrar/memrar_handler.c (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 18b43fcb4171..dca4a0bb6ca9 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -117,8 +117,6 @@ source "drivers/staging/hv/Kconfig" source "drivers/staging/vme/Kconfig" -source "drivers/staging/memrar/Kconfig" - source "drivers/staging/sep/Kconfig" source "drivers/staging/iio/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index cfd13cd55efb..eb93012b6f59 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_VT6655) += vt6655/ obj-$(CONFIG_VT6656) += vt6656/ obj-$(CONFIG_HYPERV) += hv/ obj-$(CONFIG_VME_BUS) += vme/ -obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio/ diff --git a/drivers/staging/memrar/Kconfig b/drivers/staging/memrar/Kconfig deleted file mode 100644 index cbeebc550904..000000000000 --- a/drivers/staging/memrar/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config MRST_RAR_HANDLER - tristate "RAR handler driver for Intel Moorestown platform" - depends on RAR_REGISTER - ---help--- - This driver provides a memory management interface to - restricted access regions (RAR) available on the Intel - Moorestown platform. - - Once locked down, restricted access regions are only - accessible by specific hardware on the platform. The x86 - CPU is typically not one of those platforms. As such this - driver does not access RAR, and only provides a buffer - allocation/bookkeeping mechanism. - - If unsure, say N. diff --git a/drivers/staging/memrar/Makefile b/drivers/staging/memrar/Makefile deleted file mode 100644 index a3336c00cc5f..000000000000 --- a/drivers/staging/memrar/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_MRST_RAR_HANDLER) += memrar.o -memrar-y := memrar_allocator.o memrar_handler.o diff --git a/drivers/staging/memrar/TODO b/drivers/staging/memrar/TODO deleted file mode 100644 index 435e09ba44c5..000000000000 --- a/drivers/staging/memrar/TODO +++ /dev/null @@ -1,43 +0,0 @@ -RAR Handler (memrar) Driver TODO Items -====================================== - -Maintainer: Eugene Epshteyn - -memrar.h --------- -1. This header exposes the driver's user space and kernel space - interfaces. It should be moved to , or - something along those lines, when this memrar driver is moved out - of `staging'. - a. It would be ideal if staging/rar_register/rar_register.h was - moved to the same directory. - -memrar_allocator.[ch] ---------------------- -1. Address potential fragmentation issues with the memrar_allocator. - -2. Hide struct memrar_allocator details/fields. They need not be - exposed to the user. - a. Forward declare struct memrar_allocator. - b. Move all three struct definitions to `memrar_allocator.c' - source file. - c. Add a memrar_allocator_largest_free_area() function, or - something like that to get access to the value of the struct - memrar_allocator "largest_free_area" field. This allows the - struct memrar_allocator fields to be completely hidden from - the user. The memrar_handler code really only needs this for - statistic gathering on-demand. - d. Do the same for the "capacity" field as the - "largest_free_area" field. - -3. Move memrar_allocator.* to kernel `lib' directory since it is HW - neutral. - a. Alternatively, use lib/genalloc.c instead. - b. A kernel port of Doug Lea's malloc() implementation may also - be an option. - -memrar_handler.c ----------------- -1. Split user space interface (ioctl code) from core/kernel code, - e.g.: - memrar_handler.c -> memrar_core.c, memrar_user.c diff --git a/drivers/staging/memrar/memrar-abi b/drivers/staging/memrar/memrar-abi deleted file mode 100644 index c23fc996a435..000000000000 --- a/drivers/staging/memrar/memrar-abi +++ /dev/null @@ -1,89 +0,0 @@ -What: /dev/memrar -Date: March 2010 -KernelVersion: 2.6.34 -Contact: Eugene Epshteyn -Description: The Intel Moorestown Restricted Access Region (RAR) - Handler driver exposes an ioctl() based interface that - allows a user to reserve and release blocks of RAR - memory. - - Note: A sysfs based one was not appropriate for the - RAR handler's usage model. - - ========================================================= - ioctl() Requests - ========================================================= - RAR_HANDLER_RESERVE - ------------------- - Description: Reserve RAR block. - Type: struct RAR_block_info - Direction: in/out - Errors: EINVAL (invalid RAR type or size) - ENOMEM (not enough RAR memory) - - RAR_HANDLER_STAT - ---------------- - Description: Get RAR statistics. - Type: struct RAR_stat - Direction: in/out - Errors: EINVAL (invalid RAR type) - - RAR_HANDLER_RELEASE - ------------------- - Description: Release previously reserved RAR block. - Type: 32 bit unsigned integer - (e.g. uint32_t), i.e the RAR "handle". - Direction: in - Errors: EINVAL (invalid RAR handle) - - - ========================================================= - ioctl() Request Parameter Types - ========================================================= - The structures referred to above are defined as - follows: - - /** - * struct RAR_block_info - user space struct that - * describes RAR buffer - * @type: Type of RAR memory (e.g., - * RAR_TYPE_VIDEO or RAR_TYPE_AUDIO) [in] - * @size: Requested size of a block in bytes to - * be reserved in RAR. [in] - * @handle: Handle that can be used to refer to - * reserved block. [out] - * - * This is the basic structure exposed to the user - * space that describes a given RAR buffer. It used - * as the parameter for the RAR_HANDLER_RESERVE ioctl. - * The buffer's underlying bus address is not exposed - * to the user. User space code refers to the buffer - * entirely by "handle". - */ - struct RAR_block_info { - __u32 type; - __u32 size; - __u32 handle; - }; - - /** - * struct RAR_stat - RAR statistics structure - * @type: Type of RAR memory (e.g., - * RAR_TYPE_VIDEO or - * RAR_TYPE_AUDIO) [in] - * @capacity: Total size of RAR memory - * region. [out] - * @largest_block_size: Size of the largest reservable - * block. [out] - * - * This structure is used for RAR_HANDLER_STAT ioctl. - */ - struct RAR_stat { - __u32 type; - __u32 capacity; - __u32 largest_block_size; - }; - - Lastly, the RAR_HANDLER_RELEASE ioctl expects a - "handle" to the RAR block of memory. It is a 32 bit - unsigned integer. diff --git a/drivers/staging/memrar/memrar.h b/drivers/staging/memrar/memrar.h deleted file mode 100644 index 0feb73b94c91..000000000000 --- a/drivers/staging/memrar/memrar.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * RAR Handler (/dev/memrar) internal driver API. - * Copyright (C) 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General - * Public License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * The full GNU General Public License is included in this - * distribution in the file called COPYING. - */ - - -#ifndef _MEMRAR_H -#define _MEMRAR_H - -#include -#include - - -/** - * struct RAR_stat - RAR statistics structure - * @type: Type of RAR memory (e.g., audio vs. video) - * @capacity: Total size of RAR memory region. - * @largest_block_size: Size of the largest reservable block. - * - * This structure is used for RAR_HANDLER_STAT ioctl and for the - * RAR_get_stat() user space wrapper function. - */ -struct RAR_stat { - __u32 type; - __u32 capacity; - __u32 largest_block_size; -}; - - -/** - * struct RAR_block_info - user space struct that describes RAR buffer - * @type: Type of RAR memory (e.g., audio vs. video) - * @size: Requested size of a block to be reserved in RAR. - * @handle: Handle that can be used to refer to reserved block. - * - * This is the basic structure exposed to the user space that - * describes a given RAR buffer. The buffer's underlying bus address - * is not exposed to the user. User space code refers to the buffer - * entirely by "handle". - */ -struct RAR_block_info { - __u32 type; - __u32 size; - __u32 handle; -}; - - -#define RAR_IOCTL_BASE 0xE0 - -/* Reserve RAR block. */ -#define RAR_HANDLER_RESERVE _IOWR(RAR_IOCTL_BASE, 0x00, struct RAR_block_info) - -/* Release previously reserved RAR block. */ -#define RAR_HANDLER_RELEASE _IOW(RAR_IOCTL_BASE, 0x01, __u32) - -/* Get RAR stats. */ -#define RAR_HANDLER_STAT _IOWR(RAR_IOCTL_BASE, 0x02, struct RAR_stat) - - -#ifdef __KERNEL__ - -/* -------------------------------------------------------------- */ -/* Kernel Side RAR Handler Interface */ -/* -------------------------------------------------------------- */ - -/** - * struct RAR_buffer - kernel space struct that describes RAR buffer - * @info: structure containing base RAR buffer information - * @bus_address: buffer bus address - * - * Structure that contains all information related to a given block of - * memory in RAR. It is generally only used when retrieving RAR - * related bus addresses. - * - * Note: This structure is used only by RAR-enabled drivers, and is - * not intended to be exposed to the user space. - */ -struct RAR_buffer { - struct RAR_block_info info; - dma_addr_t bus_address; -}; - -#if defined(CONFIG_MRST_RAR_HANDLER) -/** - * rar_reserve() - reserve RAR buffers - * @buffers: array of RAR_buffers where type and size of buffers to - * reserve are passed in, handle and bus address are - * passed out - * @count: number of RAR_buffers in the "buffers" array - * - * This function will reserve buffers in the restricted access regions - * of given types. - * - * It returns the number of successfully reserved buffers. Successful - * buffer reservations will have the corresponding bus_address field - * set to a non-zero value in the given buffers vector. - */ -extern size_t rar_reserve(struct RAR_buffer *buffers, - size_t count); - -/** - * rar_release() - release RAR buffers - * @buffers: array of RAR_buffers where handles to buffers to be - * released are passed in - * @count: number of RAR_buffers in the "buffers" array - * - * This function will release RAR buffers that were retrieved through - * a call to rar_reserve() or rar_handle_to_bus() by decrementing the - * reference count. The RAR buffer will be reclaimed when the - * reference count drops to zero. - * - * It returns the number of successfully released buffers. Successful - * releases will have their handle field set to zero in the given - * buffers vector. - */ -extern size_t rar_release(struct RAR_buffer *buffers, - size_t count); - -/** - * rar_handle_to_bus() - convert a vector of RAR handles to bus addresses - * @buffers: array of RAR_buffers containing handles to be - * converted to bus_addresses - * @count: number of RAR_buffers in the "buffers" array - - * This function will retrieve the RAR buffer bus addresses, type and - * size corresponding to the RAR handles provided in the buffers - * vector. - * - * It returns the number of successfully converted buffers. The bus - * address will be set to 0 for unrecognized handles. - * - * The reference count for each corresponding buffer in RAR will be - * incremented. Call rar_release() when done with the buffers. - */ -extern size_t rar_handle_to_bus(struct RAR_buffer *buffers, - size_t count); - -#else - -extern inline size_t rar_reserve(struct RAR_buffer *buffers, size_t count) -{ - return 0; -} - -extern inline size_t rar_release(struct RAR_buffer *buffers, size_t count) -{ - return 0; -} - -extern inline size_t rar_handle_to_bus(struct RAR_buffer *buffers, - size_t count) -{ - return 0; -} - -#endif /* MRST_RAR_HANDLER */ -#endif /* __KERNEL__ */ - -#endif /* _MEMRAR_H */ diff --git a/drivers/staging/memrar/memrar_allocator.c b/drivers/staging/memrar/memrar_allocator.c deleted file mode 100644 index a4f8c5846a00..000000000000 --- a/drivers/staging/memrar/memrar_allocator.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * memrar_allocator 1.0: An allocator for Intel RAR. - * - * Copyright (C) 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General - * Public License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * The full GNU General Public License is included in this - * distribution in the file called COPYING. - * - * - * ------------------------------------------------------------------ - * - * This simple allocator implementation provides a - * malloc()/free()-like interface for reserving space within a - * previously reserved block of memory. It is not specific to - * any hardware, nor is it coupled with the lower level paging - * mechanism. - * - * The primary goal of this implementation is to provide a means - * to partition an arbitrary block of memory without actually - * accessing the memory or incurring any hardware side-effects - * (e.g. paging). It is, in effect, a bookkeeping mechanism for - * buffers. - */ - - -#include "memrar_allocator.h" -#include -#include -#include - - -struct memrar_allocator *memrar_create_allocator(unsigned long base, - size_t capacity, - size_t block_size) -{ - struct memrar_allocator *allocator = NULL; - struct memrar_address_ranges *first_node = NULL; - - /* - * Make sure the base address is aligned on a block_size - * boundary. - * - * @todo Is this necessary? - */ - /* base = ALIGN(base, block_size); */ - - /* Validate parameters. - * - * Make sure we can allocate the entire memory space. Zero - * capacity or block size are obviously invalid. - */ - if (base == 0 - || capacity == 0 - || block_size == 0 - || ULONG_MAX - capacity < base - || capacity < block_size) - return allocator; - - /* - * There isn't much point in creating a memory allocator that - * is only capable of holding one block but we'll allow it, - * and issue a diagnostic. - */ - WARN(capacity < block_size * 2, - "memrar: Only one block available to allocator.\n"); - - allocator = kmalloc(sizeof(*allocator), GFP_KERNEL); - - if (allocator == NULL) - return allocator; - - mutex_init(&allocator->lock); - allocator->base = base; - - /* Round the capacity down to a multiple of block_size. */ - allocator->capacity = (capacity / block_size) * block_size; - - allocator->block_size = block_size; - - allocator->largest_free_area = allocator->capacity; - - /* Initialize the handle and free lists. */ - INIT_LIST_HEAD(&allocator->allocated_list.list); - INIT_LIST_HEAD(&allocator->free_list.list); - - first_node = kmalloc(sizeof(*first_node), GFP_KERNEL); - if (first_node == NULL) { - kfree(allocator); - allocator = NULL; - } else { - /* Full range of blocks is available. */ - first_node->range.begin = base; - first_node->range.end = base + allocator->capacity; - list_add(&first_node->list, - &allocator->free_list.list); - } - - return allocator; -} - -void memrar_destroy_allocator(struct memrar_allocator *allocator) -{ - /* - * Assume that the memory allocator lock isn't held at this - * point in time. Caller must ensure that. - */ - - struct memrar_address_ranges *pos = NULL; - struct memrar_address_ranges *n = NULL; - - if (allocator == NULL) - return; - - mutex_lock(&allocator->lock); - - /* Reclaim free list resources. */ - list_for_each_entry_safe(pos, - n, - &allocator->free_list.list, - list) { - list_del(&pos->list); - kfree(pos); - } - - mutex_unlock(&allocator->lock); - - kfree(allocator); -} - -unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator, - size_t size) -{ - struct memrar_address_ranges *pos = NULL; - - size_t num_blocks; - unsigned long reserved_bytes; - - /* - * Address of allocated buffer. We assume that zero is not a - * valid address. - */ - unsigned long addr = 0; - - if (allocator == NULL || size == 0) - return addr; - - /* Reserve enough blocks to hold the amount of bytes requested. */ - num_blocks = DIV_ROUND_UP(size, allocator->block_size); - - reserved_bytes = num_blocks * allocator->block_size; - - mutex_lock(&allocator->lock); - - if (reserved_bytes > allocator->largest_free_area) { - mutex_unlock(&allocator->lock); - return addr; - } - - /* - * Iterate through the free list to find a suitably sized - * range of free contiguous memory blocks. - * - * We also take the opportunity to reset the size of the - * largest free area size statistic. - */ - list_for_each_entry(pos, &allocator->free_list.list, list) { - struct memrar_address_range * const fr = &pos->range; - size_t const curr_size = fr->end - fr->begin; - - if (curr_size >= reserved_bytes && addr == 0) { - struct memrar_address_range *range = NULL; - struct memrar_address_ranges * const new_node = - kmalloc(sizeof(*new_node), GFP_KERNEL); - - if (new_node == NULL) - break; - - list_add(&new_node->list, - &allocator->allocated_list.list); - - /* - * Carve out area of memory from end of free - * range. - */ - range = &new_node->range; - range->end = fr->end; - fr->end -= reserved_bytes; - range->begin = fr->end; - addr = range->begin; - - /* - * Check if largest area has decreased in - * size. We'll need to continue scanning for - * the next largest area if it has. - */ - if (curr_size == allocator->largest_free_area) - allocator->largest_free_area -= - reserved_bytes; - else - break; - } - - /* - * Reset largest free area size statistic as needed, - * but only if we've actually allocated memory. - */ - if (addr != 0 - && curr_size > allocator->largest_free_area) { - allocator->largest_free_area = curr_size; - break; - } - } - - mutex_unlock(&allocator->lock); - - return addr; -} - -long memrar_allocator_free(struct memrar_allocator *allocator, - unsigned long addr) -{ - struct list_head *pos = NULL; - struct list_head *tmp = NULL; - struct list_head *dst = NULL; - - struct memrar_address_ranges *allocated = NULL; - struct memrar_address_range const *handle = NULL; - - unsigned long old_end = 0; - unsigned long new_chunk_size = 0; - - if (allocator == NULL) - return -EINVAL; - - if (addr == 0) - return 0; /* Ignore "free(0)". */ - - mutex_lock(&allocator->lock); - - /* Find the corresponding handle. */ - list_for_each_entry(allocated, - &allocator->allocated_list.list, - list) { - if (allocated->range.begin == addr) { - handle = &allocated->range; - break; - } - } - - /* No such buffer created by this allocator. */ - if (handle == NULL) { - mutex_unlock(&allocator->lock); - return -EFAULT; - } - - /* - * Coalesce adjacent chunks of memory if possible. - * - * @note This isn't full blown coalescing since we're only - * coalescing at most three chunks of memory. - */ - list_for_each_safe(pos, tmp, &allocator->free_list.list) { - /* @todo O(n) performance. Optimize. */ - - struct memrar_address_range * const chunk = - &list_entry(pos, - struct memrar_address_ranges, - list)->range; - - /* Extend size of existing free adjacent chunk. */ - if (chunk->end == handle->begin) { - /* - * Chunk "less than" than the one we're - * freeing is adjacent. - * - * Before: - * - * +-----+------+ - * |chunk|handle| - * +-----+------+ - * - * After: - * - * +------------+ - * | chunk | - * +------------+ - */ - - struct memrar_address_ranges const * const next = - list_entry(pos->next, - struct memrar_address_ranges, - list); - - chunk->end = handle->end; - - /* - * Now check if next free chunk is adjacent to - * the current extended free chunk. - * - * Before: - * - * +------------+----+ - * | chunk |next| - * +------------+----+ - * - * After: - * - * +-----------------+ - * | chunk | - * +-----------------+ - */ - if (!list_is_singular(pos) - && chunk->end == next->range.begin) { - chunk->end = next->range.end; - list_del(pos->next); - kfree(next); - } - - list_del(&allocated->list); - - new_chunk_size = chunk->end - chunk->begin; - - goto exit_memrar_free; - - } else if (handle->end == chunk->begin) { - /* - * Chunk "greater than" than the one we're - * freeing is adjacent. - * - * +------+-----+ - * |handle|chunk| - * +------+-----+ - * - * After: - * - * +------------+ - * | chunk | - * +------------+ - */ - - struct memrar_address_ranges const * const prev = - list_entry(pos->prev, - struct memrar_address_ranges, - list); - - chunk->begin = handle->begin; - - /* - * Now check if previous free chunk is - * adjacent to the current extended free - * chunk. - * - * - * Before: - * - * +----+------------+ - * |prev| chunk | - * +----+------------+ - * - * After: - * - * +-----------------+ - * | chunk | - * +-----------------+ - */ - if (!list_is_singular(pos) - && prev->range.end == chunk->begin) { - chunk->begin = prev->range.begin; - list_del(pos->prev); - kfree(prev); - } - - list_del(&allocated->list); - - new_chunk_size = chunk->end - chunk->begin; - - goto exit_memrar_free; - - } else if (chunk->end < handle->begin - && chunk->end > old_end) { - /* Keep track of where the entry could be - * potentially moved from the "allocated" list - * to the "free" list if coalescing doesn't - * occur, making sure the "free" list remains - * sorted. - */ - old_end = chunk->end; - dst = pos; - } - } - - /* - * Nothing to coalesce. - * - * Move the entry from the "allocated" list to the "free" - * list. - */ - list_move(&allocated->list, dst); - new_chunk_size = handle->end - handle->begin; - allocated = NULL; - -exit_memrar_free: - - if (new_chunk_size > allocator->largest_free_area) - allocator->largest_free_area = new_chunk_size; - - mutex_unlock(&allocator->lock); - - kfree(allocated); - - return 0; -} - - - -/* - Local Variables: - c-file-style: "linux" - End: -*/ diff --git a/drivers/staging/memrar/memrar_allocator.h b/drivers/staging/memrar/memrar_allocator.h deleted file mode 100644 index 0b80dead710f..000000000000 --- a/drivers/staging/memrar/memrar_allocator.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General - * Public License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * The full GNU General Public License is included in this - * distribution in the file called COPYING. - */ - -#ifndef MEMRAR_ALLOCATOR_H -#define MEMRAR_ALLOCATOR_H - - -#include -#include -#include -#include - - -/** - * struct memrar_address_range - struct that describes a memory range - * @begin: Beginning of available address range. - * @end: End of available address range, one past the end, - * i.e. [begin, end). - */ -struct memrar_address_range { -/* private: internal use only */ - unsigned long begin; - unsigned long end; -}; - -/** - * struct memrar_address_ranges - list of areas of memory. - * @list: Linked list of address ranges. - * @range: Memory address range corresponding to given list node. - */ -struct memrar_address_ranges { -/* private: internal use only */ - struct list_head list; - struct memrar_address_range range; -}; - -/** - * struct memrar_allocator - encapsulation of the memory allocator state - * @lock: Lock used to synchronize access to the memory - * allocator state. - * @base: Base (start) address of the allocator memory - * space. - * @capacity: Size of the allocator memory space in bytes. - * @block_size: The size in bytes of individual blocks within - * the allocator memory space. - * @largest_free_area: Largest free area of memory in the allocator - * in bytes. - * @allocated_list: List of allocated memory block address - * ranges. - * @free_list: List of free address ranges. - * - * This structure contains all memory allocator state, including the - * base address, capacity, free list, lock, etc. - */ -struct memrar_allocator { -/* private: internal use only */ - struct mutex lock; - unsigned long base; - size_t capacity; - size_t block_size; - size_t largest_free_area; - struct memrar_address_ranges allocated_list; - struct memrar_address_ranges free_list; -}; - -/** - * memrar_create_allocator() - create a memory allocator - * @base: Address at which the memory allocator begins. - * @capacity: Desired size of the memory allocator. This value must - * be larger than the block_size, ideally more than twice - * as large since there wouldn't be much point in using a - * memory allocator otherwise. - * @block_size: The size of individual blocks within the memory - * allocator. This value must smaller than the - * capacity. - * - * Create a memory allocator with the given capacity and block size. - * The capacity will be reduced to be a multiple of the block size, if - * necessary. - * - * Returns an instance of the memory allocator, if creation succeeds, - * otherwise zero if creation fails. Failure may occur if not enough - * kernel memory exists to create the memrar_allocator instance - * itself, or if the capacity and block_size arguments are not - * compatible or make sense. - */ -struct memrar_allocator *memrar_create_allocator(unsigned long base, - size_t capacity, - size_t block_size); - -/** - * memrar_destroy_allocator() - destroy allocator - * @allocator: The allocator being destroyed. - * - * Reclaim resources held by the memory allocator. The caller must - * explicitly free all memory reserved by memrar_allocator_alloc() - * prior to calling this function. Otherwise leaks will occur. - */ -void memrar_destroy_allocator(struct memrar_allocator *allocator); - -/** - * memrar_allocator_alloc() - reserve an area of memory of given size - * @allocator: The allocator instance being used to reserve buffer. - * @size: The size in bytes of the buffer to allocate. - * - * This functions reserves an area of memory managed by the given - * allocator. It returns zero if allocation was not possible. - * Failure may occur if the allocator no longer has space available. - */ -unsigned long memrar_allocator_alloc(struct memrar_allocator *allocator, - size_t size); - -/** - * memrar_allocator_free() - release buffer starting at given address - * @allocator: The allocator instance being used to release the buffer. - * @address: The address of the buffer being released. - * - * Release an area of memory starting at the given address. Failure - * could occur if the given address is not in the address space - * managed by the allocator. Returns zero on success or an errno - * (negative value) on failure. - */ -long memrar_allocator_free(struct memrar_allocator *allocator, - unsigned long address); - -#endif /* MEMRAR_ALLOCATOR_H */ - - -/* - Local Variables: - c-file-style: "linux" - End: -*/ diff --git a/drivers/staging/memrar/memrar_handler.c b/drivers/staging/memrar/memrar_handler.c deleted file mode 100644 index cfcaa8e5b8e6..000000000000 --- a/drivers/staging/memrar/memrar_handler.c +++ /dev/null @@ -1,1007 +0,0 @@ -/* - * memrar_handler 1.0: An Intel restricted access region handler device - * - * Copyright (C) 2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General - * Public License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * The full GNU General Public License is included in this - * distribution in the file called COPYING. - * - * ------------------------------------------------------------------- - * - * Moorestown restricted access regions (RAR) provide isolated - * areas of main memory that are only acceessible by authorized - * devices. - * - * The Intel Moorestown RAR handler module exposes a kernel space - * RAR memory management mechanism. It is essentially a - * RAR-specific allocator. - * - * Besides providing RAR buffer management, the RAR handler also - * behaves in many ways like an OS virtual memory manager. For - * example, the RAR "handles" created by the RAR handler are - * analogous to user space virtual addresses. - * - * RAR memory itself is never accessed directly by the RAR - * handler. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "memrar.h" -#include "memrar_allocator.h" - - -#define MEMRAR_VER "1.0" - -/* - * Moorestown supports three restricted access regions. - * - * We only care about the first two, video and audio. The third, - * reserved for Chaabi and the P-unit, will be handled by their - * respective drivers. - */ -#define MRST_NUM_RAR 2 - -/* ---------------- -------------------- ------------------- */ - -/** - * struct memrar_buffer_info - struct that keeps track of all RAR buffers - * @list: Linked list of memrar_buffer_info objects. - * @buffer: Core RAR buffer information. - * @refcount: Reference count. - * @owner: File handle corresponding to process that reserved the - * block of memory in RAR. This will be zero for buffers - * allocated by other drivers instead of by a user space - * process. - * - * This structure encapsulates a link list of RAR buffers, as well as - * other characteristics specific to a given list node, such as the - * reference count on the corresponding RAR buffer. - */ -struct memrar_buffer_info { - struct list_head list; - struct RAR_buffer buffer; - struct kref refcount; - struct file *owner; -}; - -/** - * struct memrar_rar_info - characteristics of a given RAR - * @base: Base bus address of the RAR. - * @length: Length of the RAR. - * @iobase: Virtual address of RAR mapped into kernel. - * @allocator: Allocator associated with the RAR. Note the allocator - * "capacity" may be smaller than the RAR length if the - * length is not a multiple of the configured allocator - * block size. - * @buffers: Table that keeps track of all reserved RAR buffers. - * @lock: Lock used to synchronize access to RAR-specific data - * structures. - * - * Each RAR has an associated memrar_rar_info structure that describes - * where in memory the RAR is located, how large it is, and a list of - * reserved RAR buffers inside that RAR. Each RAR also has a mutex - * associated with it to reduce lock contention when operations on - * multiple RARs are performed in parallel. - */ -struct memrar_rar_info { - dma_addr_t base; - unsigned long length; - void __iomem *iobase; - struct memrar_allocator *allocator; - struct memrar_buffer_info buffers; - struct mutex lock; - int allocated; /* True if we own this RAR */ -}; - -/* - * Array of RAR characteristics. - */ -static struct memrar_rar_info memrars[MRST_NUM_RAR]; - -/* ---------------- -------------------- ------------------- */ - -/* Validate RAR type. */ -static inline int memrar_is_valid_rar_type(u32 type) -{ - return type == RAR_TYPE_VIDEO || type == RAR_TYPE_AUDIO; -} - -/* Check if an address/handle falls with the given RAR memory range. */ -static inline int memrar_handle_in_range(struct memrar_rar_info *rar, - u32 vaddr) -{ - unsigned long const iobase = (unsigned long) (rar->iobase); - return (vaddr >= iobase && vaddr < iobase + rar->length); -} - -/* Retrieve RAR information associated with the given handle. */ -static struct memrar_rar_info *memrar_get_rar_info(u32 vaddr) -{ - int i; - for (i = 0; i < MRST_NUM_RAR; ++i) { - struct memrar_rar_info * const rar = &memrars[i]; - if (memrar_handle_in_range(rar, vaddr)) - return rar; - } - - return NULL; -} - -/** - * memrar_get_bus address - handle to bus address - * - * Retrieve bus address from given handle. - * - * Returns address corresponding to given handle. Zero if handle is - * invalid. - */ -static dma_addr_t memrar_get_bus_address( - struct memrar_rar_info *rar, - u32 vaddr) -{ - unsigned long const iobase = (unsigned long) (rar->iobase); - - if (!memrar_handle_in_range(rar, vaddr)) - return 0; - - /* - * An assumption is made that the virtual address offset is - * the same as the bus address offset, at least based on the - * way this driver is implemented. For example, vaddr + 2 == - * baddr + 2. - * - * @todo Is that a valid assumption? - */ - return rar->base + (vaddr - iobase); -} - -/** - * memrar_get_physical_address - handle to physical address - * - * Retrieve physical address from given handle. - * - * Returns address corresponding to given handle. Zero if handle is - * invalid. - */ -static dma_addr_t memrar_get_physical_address( - struct memrar_rar_info *rar, - u32 vaddr) -{ - /* - * @todo This assumes that the bus address and physical - * address are the same. That is true for Moorestown - * but not necessarily on other platforms. This - * deficiency should be addressed at some point. - */ - return memrar_get_bus_address(rar, vaddr); -} - -/** - * memrar_release_block - release a block to the pool - * @kref: kref of block - * - * Core block release code. A node has hit zero references so can - * be released and the lists must be updated. - * - * Note: This code removes the node from a list. Make sure any list - * iteration is performed using list_for_each_safe(). - */ -static void memrar_release_block_i(struct kref *ref) -{ - /* - * Last reference is being released. Remove from the table, - * and reclaim resources. - */ - - struct memrar_buffer_info * const node = - container_of(ref, struct memrar_buffer_info, refcount); - - struct RAR_block_info * const user_info = - &node->buffer.info; - - struct memrar_allocator * const allocator = - memrars[user_info->type].allocator; - - list_del(&node->list); - - memrar_allocator_free(allocator, user_info->handle); - - kfree(node); -} - -/** - * memrar_init_rar_resources - configure a RAR - * @rarnum: rar that has been allocated - * @devname: name of our device - * - * Initialize RAR parameters, such as bus addresses, etc and make - * the resource accessible. - */ -static int memrar_init_rar_resources(int rarnum, char const *devname) -{ - /* ---- Sanity Checks ---- - * 1. RAR bus addresses in both Lincroft and Langwell RAR - * registers should be the same. - * a. There's no way we can do this through IA. - * - * 2. Secure device ID in Langwell RAR registers should be set - * appropriately, e.g. only LPE DMA for the audio RAR, and - * security for the other Langwell based RAR registers. - * a. There's no way we can do this through IA. - * - * 3. Audio and video RAR registers and RAR access should be - * locked down. If not, enable RAR access control. Except - * for debugging purposes, there is no reason for them to - * be unlocked. - * a. We can only do this for the Lincroft (IA) side. - * - * @todo Should the RAR handler driver even be aware of audio - * and video RAR settings? - */ - - /* - * RAR buffer block size. - * - * We choose it to be the size of a page to simplify the - * /dev/memrar mmap() implementation and usage. Otherwise - * paging is not involved once an RAR is locked down. - */ - static size_t const RAR_BLOCK_SIZE = PAGE_SIZE; - - dma_addr_t low, high; - struct memrar_rar_info * const rar = &memrars[rarnum]; - - BUG_ON(MRST_NUM_RAR != ARRAY_SIZE(memrars)); - BUG_ON(!memrar_is_valid_rar_type(rarnum)); - BUG_ON(rar->allocated); - - if (rar_get_address(rarnum, &low, &high) != 0) - /* No RAR is available. */ - return -ENODEV; - - if (low == 0 || high == 0) { - rar->base = 0; - rar->length = 0; - rar->iobase = NULL; - rar->allocator = NULL; - return -ENOSPC; - } - - /* - * @todo Verify that LNC and LNW RAR register contents - * addresses, security, etc are compatible and - * consistent). - */ - - rar->length = high - low + 1; - - /* Claim RAR memory as our own. */ - if (request_mem_region(low, rar->length, devname) == NULL) { - rar->length = 0; - pr_err("%s: Unable to claim RAR[%d] memory.\n", - devname, rarnum); - pr_err("%s: RAR[%d] disabled.\n", devname, rarnum); - return -EBUSY; - } - - rar->base = low; - - /* - * Now map it into the kernel address space. - * - * Note that the RAR memory may only be accessed by IA - * when debugging. Otherwise attempts to access the - * RAR memory when it is locked down will result in - * behavior similar to writing to /dev/null and - * reading from /dev/zero. This behavior is enforced - * by the hardware. Even if we don't access the - * memory, mapping it into the kernel provides us with - * a convenient RAR handle to bus address mapping. - */ - rar->iobase = ioremap_nocache(rar->base, rar->length); - if (rar->iobase == NULL) { - pr_err("%s: Unable to map RAR memory.\n", devname); - release_mem_region(low, rar->length); - return -ENOMEM; - } - - /* Initialize corresponding memory allocator. */ - rar->allocator = memrar_create_allocator((unsigned long) rar->iobase, - rar->length, RAR_BLOCK_SIZE); - if (rar->allocator == NULL) { - iounmap(rar->iobase); - release_mem_region(low, rar->length); - return -ENOMEM; - } - - pr_info("%s: BRAR[%d] bus address range = [0x%lx, 0x%lx]\n", - devname, rarnum, (unsigned long) low, (unsigned long) high); - - pr_info("%s: BRAR[%d] size = %zu KiB\n", - devname, rarnum, rar->allocator->capacity / 1024); - - rar->allocated = 1; - return 0; -} - -/** - * memrar_fini_rar_resources - free up RAR resources - * - * Finalize RAR resources. Free up the resource tables, hand the memory - * back to the kernel, unmap the device and release the address space. - */ -static void memrar_fini_rar_resources(void) -{ - int z; - struct memrar_buffer_info *pos; - struct memrar_buffer_info *tmp; - - /* - * @todo Do we need to hold a lock at this point in time? - * (module initialization failure or exit?) - */ - - for (z = MRST_NUM_RAR; z-- != 0; ) { - struct memrar_rar_info * const rar = &memrars[z]; - - if (!rar->allocated) - continue; - - /* Clean up remaining resources. */ - - list_for_each_entry_safe(pos, - tmp, - &rar->buffers.list, - list) { - kref_put(&pos->refcount, memrar_release_block_i); - } - - memrar_destroy_allocator(rar->allocator); - rar->allocator = NULL; - - iounmap(rar->iobase); - release_mem_region(rar->base, rar->length); - - rar->iobase = NULL; - rar->base = 0; - rar->length = 0; - - unregister_rar(z); - } -} - -/** - * memrar_reserve_block - handle an allocation request - * @request: block being requested - * @filp: owner it is tied to - * - * Allocate a block of the requested RAR. If successful return the - * request object filled in and zero, if not report an error code - */ - -static long memrar_reserve_block(struct RAR_buffer *request, - struct file *filp) -{ - struct RAR_block_info * const rinfo = &request->info; - struct RAR_buffer *buffer; - struct memrar_buffer_info *buffer_info; - u32 handle; - struct memrar_rar_info *rar = NULL; - - /* Prevent array overflow. */ - if (!memrar_is_valid_rar_type(rinfo->type)) - return -EINVAL; - - rar = &memrars[rinfo->type]; - if (!rar->allocated) - return -ENODEV; - - /* Reserve memory in RAR. */ - handle = memrar_allocator_alloc(rar->allocator, rinfo->size); - if (handle == 0) - return -ENOMEM; - - buffer_info = kmalloc(sizeof(*buffer_info), GFP_KERNEL); - - if (buffer_info == NULL) { - memrar_allocator_free(rar->allocator, handle); - return -ENOMEM; - } - - buffer = &buffer_info->buffer; - buffer->info.type = rinfo->type; - buffer->info.size = rinfo->size; - - /* Memory handle corresponding to the bus address. */ - buffer->info.handle = handle; - buffer->bus_address = memrar_get_bus_address(rar, handle); - - /* - * Keep track of owner so that we can later cleanup if - * necessary. - */ - buffer_info->owner = filp; - - kref_init(&buffer_info->refcount); - - mutex_lock(&rar->lock); - list_add(&buffer_info->list, &rar->buffers.list); - mutex_unlock(&rar->lock); - - rinfo->handle = buffer->info.handle; - request->bus_address = buffer->bus_address; - - return 0; -} - -/** - * memrar_release_block - release a RAR block - * @addr: address in RAR space - * - * Release a previously allocated block. Releases act on complete - * blocks, partially freeing a block is not supported - */ - -static long memrar_release_block(u32 addr) -{ - struct memrar_buffer_info *pos; - struct memrar_buffer_info *tmp; - struct memrar_rar_info * const rar = memrar_get_rar_info(addr); - long result = -EINVAL; - - if (rar == NULL) - return -ENOENT; - - mutex_lock(&rar->lock); - - /* - * Iterate through the buffer list to find the corresponding - * buffer to be released. - */ - list_for_each_entry_safe(pos, - tmp, - &rar->buffers.list, - list) { - struct RAR_block_info * const info = - &pos->buffer.info; - - /* - * Take into account handle offsets that may have been - * added to the base handle, such as in the following - * scenario: - * - * u32 handle = base + offset; - * rar_handle_to_bus(handle); - * rar_release(handle); - */ - if (addr >= info->handle - && addr < (info->handle + info->size) - && memrar_is_valid_rar_type(info->type)) { - kref_put(&pos->refcount, memrar_release_block_i); - result = 0; - break; - } - } - - mutex_unlock(&rar->lock); - - return result; -} - -/** - * memrar_get_stats - read statistics for a RAR - * @r: statistics to be filled in - * - * Returns the statistics data for the RAR, or an error code if - * the request cannot be completed - */ -static long memrar_get_stat(struct RAR_stat *r) -{ - struct memrar_allocator *allocator; - - if (!memrar_is_valid_rar_type(r->type)) - return -EINVAL; - - if (!memrars[r->type].allocated) - return -ENODEV; - - allocator = memrars[r->type].allocator; - - BUG_ON(allocator == NULL); - - /* - * Allocator capacity doesn't change over time. No - * need to synchronize. - */ - r->capacity = allocator->capacity; - - mutex_lock(&allocator->lock); - r->largest_block_size = allocator->largest_free_area; - mutex_unlock(&allocator->lock); - return 0; -} - -/** - * memrar_ioctl - ioctl callback - * @filp: file issuing the request - * @cmd: command - * @arg: pointer to control information - * - * Perform one of the ioctls supported by the memrar device - */ - -static long memrar_ioctl(struct file *filp, - unsigned int cmd, - unsigned long arg) -{ - void __user *argp = (void __user *)arg; - long result = 0; - - struct RAR_buffer buffer; - struct RAR_block_info * const request = &buffer.info; - struct RAR_stat rar_info; - u32 rar_handle; - - switch (cmd) { - case RAR_HANDLER_RESERVE: - if (copy_from_user(request, - argp, - sizeof(*request))) - return -EFAULT; - - result = memrar_reserve_block(&buffer, filp); - if (result != 0) - return result; - - return copy_to_user(argp, request, sizeof(*request)); - - case RAR_HANDLER_RELEASE: - if (copy_from_user(&rar_handle, - argp, - sizeof(rar_handle))) - return -EFAULT; - - return memrar_release_block(rar_handle); - - case RAR_HANDLER_STAT: - if (copy_from_user(&rar_info, - argp, - sizeof(rar_info))) - return -EFAULT; - - /* - * Populate the RAR_stat structure based on the RAR - * type given by the user - */ - if (memrar_get_stat(&rar_info) != 0) - return -EINVAL; - - /* - * @todo Do we need to verify destination pointer - * "argp" is non-zero? Is that already done by - * copy_to_user()? - */ - return copy_to_user(argp, - &rar_info, - sizeof(rar_info)) ? -EFAULT : 0; - - default: - return -ENOTTY; - } - - return 0; -} - -/** - * memrar_mmap - mmap helper for deubgging - * @filp: handle doing the mapping - * @vma: memory area - * - * Support the mmap operation on the RAR space for debugging systems - * when the memory is not locked down. - */ - -static int memrar_mmap(struct file *filp, struct vm_area_struct *vma) -{ - /* - * This mmap() implementation is predominantly useful for - * debugging since the CPU will be prevented from accessing - * RAR memory by the hardware when RAR is properly locked - * down. - * - * In order for this implementation to be useful RAR memory - * must be not be locked down. However, we only want to do - * that when debugging. DO NOT leave RAR memory unlocked in a - * deployed device that utilizes RAR. - */ - - size_t const size = vma->vm_end - vma->vm_start; - - /* Users pass the RAR handle as the mmap() offset parameter. */ - unsigned long const handle = vma->vm_pgoff << PAGE_SHIFT; - - struct memrar_rar_info * const rar = memrar_get_rar_info(handle); - unsigned long pfn; - - /* Only allow priviledged apps to go poking around this way */ - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* Invalid RAR handle or size passed to mmap(). */ - if (rar == NULL - || handle == 0 - || size > (handle - (unsigned long) rar->iobase)) - return -EINVAL; - - /* - * Retrieve physical address corresponding to the RAR handle, - * and convert it to a page frame. - */ - pfn = memrar_get_physical_address(rar, handle) >> PAGE_SHIFT; - - - pr_debug("memrar: mapping RAR range [0x%lx, 0x%lx) into user space.\n", - handle, - handle + size); - - /* - * Map RAR memory into user space. This is really only useful - * for debugging purposes since the memory won't be - * accessible, i.e. reads return zero and writes are ignored, - * when RAR access control is enabled. - */ - if (remap_pfn_range(vma, - vma->vm_start, - pfn, - size, - vma->vm_page_prot)) - return -EAGAIN; - - /* vma->vm_ops = &memrar_mem_ops; */ - - return 0; -} - -/** - * memrar_open - device open method - * @inode: inode to open - * @filp: file handle - * - * As we support multiple arbitary opens there is no work to be done - * really. - */ - -static int memrar_open(struct inode *inode, struct file *filp) -{ - nonseekable_open(inode, filp); - return 0; -} - -/** - * memrar_release - close method for miscev - * @inode: inode of device - * @filp: handle that is going away - * - * Free up all the regions that belong to this file handle. We use - * the handle as a natural Linux style 'lifetime' indicator and to - * ensure resources are not leaked when their owner explodes in an - * unplanned fashion. - */ - -static int memrar_release(struct inode *inode, struct file *filp) -{ - /* Free all regions associated with the given file handle. */ - - struct memrar_buffer_info *pos; - struct memrar_buffer_info *tmp; - int z; - - for (z = 0; z != MRST_NUM_RAR; ++z) { - struct memrar_rar_info * const rar = &memrars[z]; - - mutex_lock(&rar->lock); - - list_for_each_entry_safe(pos, - tmp, - &rar->buffers.list, - list) { - if (filp == pos->owner) - kref_put(&pos->refcount, - memrar_release_block_i); - } - - mutex_unlock(&rar->lock); - } - - return 0; -} - -/** - * rar_reserve - reserve RAR memory - * @buffers: buffers to reserve - * @count: number wanted - * - * Reserve a series of buffers in the RAR space. Returns the number of - * buffers successfully allocated - */ - -size_t rar_reserve(struct RAR_buffer *buffers, size_t count) -{ - struct RAR_buffer * const end = - (buffers == NULL ? buffers : buffers + count); - struct RAR_buffer *i; - - size_t reserve_count = 0; - - for (i = buffers; i != end; ++i) { - if (memrar_reserve_block(i, NULL) == 0) - ++reserve_count; - else - i->bus_address = 0; - } - - return reserve_count; -} -EXPORT_SYMBOL(rar_reserve); - -/** - * rar_release - return RAR buffers - * @buffers: buffers to release - * @size: size of released block - * - * Return a set of buffers to the RAR pool - */ - -size_t rar_release(struct RAR_buffer *buffers, size_t count) -{ - struct RAR_buffer * const end = - (buffers == NULL ? buffers : buffers + count); - struct RAR_buffer *i; - - size_t release_count = 0; - - for (i = buffers; i != end; ++i) { - u32 * const handle = &i->info.handle; - if (memrar_release_block(*handle) == 0) { - /* - * @todo We assume we should do this each time - * the ref count is decremented. Should - * we instead only do this when the ref - * count has dropped to zero, and the - * buffer has been completely - * released/unmapped? - */ - *handle = 0; - ++release_count; - } - } - - return release_count; -} -EXPORT_SYMBOL(rar_release); - -/** - * rar_handle_to_bus - RAR to bus address - * @buffers: RAR buffer structure - * @count: number of buffers to convert - * - * Turn a list of RAR handle mappings into actual bus addresses. Note - * that when the device is locked down the bus addresses in question - * are not CPU accessible. - */ - -size_t rar_handle_to_bus(struct RAR_buffer *buffers, size_t count) -{ - struct RAR_buffer * const end = - (buffers == NULL ? buffers : buffers + count); - struct RAR_buffer *i; - struct memrar_buffer_info *pos; - - size_t conversion_count = 0; - - /* - * Find all bus addresses corresponding to the given handles. - * - * @todo Not liking this nested loop. Optimize. - */ - for (i = buffers; i != end; ++i) { - struct memrar_rar_info * const rar = - memrar_get_rar_info(i->info.handle); - - /* - * Check if we have a bogus handle, and then continue - * with remaining buffers. - */ - if (rar == NULL) { - i->bus_address = 0; - continue; - } - - mutex_lock(&rar->lock); - - list_for_each_entry(pos, &rar->buffers.list, list) { - struct RAR_block_info * const user_info = - &pos->buffer.info; - - /* - * Take into account handle offsets that may - * have been added to the base handle, such as - * in the following scenario: - * - * u32 handle = base + offset; - * rar_handle_to_bus(handle); - */ - - if (i->info.handle >= user_info->handle - && i->info.handle < (user_info->handle - + user_info->size)) { - u32 const offset = - i->info.handle - user_info->handle; - - i->info.type = user_info->type; - i->info.size = user_info->size - offset; - i->bus_address = - pos->buffer.bus_address - + offset; - - /* Increment the reference count. */ - kref_get(&pos->refcount); - - ++conversion_count; - break; - } else { - i->bus_address = 0; - } - } - - mutex_unlock(&rar->lock); - } - - return conversion_count; -} -EXPORT_SYMBOL(rar_handle_to_bus); - -static const struct file_operations memrar_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = memrar_ioctl, - .mmap = memrar_mmap, - .open = memrar_open, - .release = memrar_release, - .llseek = no_llseek, -}; - -static struct miscdevice memrar_miscdev = { - .minor = MISC_DYNAMIC_MINOR, /* dynamic allocation */ - .name = "memrar", /* /dev/memrar */ - .fops = &memrar_fops -}; - -static char const banner[] __initdata = - KERN_INFO - "Intel RAR Handler: " MEMRAR_VER " initialized.\n"; - -/** - * memrar_registration_callback - RAR obtained - * @rar: RAR number - * - * We have been granted ownership of the RAR. Add it to our memory - * management tables - */ - -static int memrar_registration_callback(unsigned long rar) -{ - /* - * We initialize the RAR parameters early on so that we can - * discontinue memrar device initialization and registration - * if suitably configured RARs are not available. - */ - return memrar_init_rar_resources(rar, memrar_miscdev.name); -} - -/** - * memrar_init - initialise RAR support - * - * Initialise support for RAR handlers. This may get loaded before - * the RAR support is activated, but the callbacks on the registration - * will handle that situation for us anyway. - */ - -static int __init memrar_init(void) -{ - int err; - int i; - - printk(banner); - - /* - * Some delayed initialization is performed in this driver. - * Make sure resources that are used during driver clean-up - * (e.g. during driver's release() function) are fully - * initialized before first use. This is particularly - * important for the case when the delayed initialization - * isn't completed, leaving behind a partially initialized - * driver. - * - * Such a scenario can occur when RAR is not available on the - * platform, and the driver is release()d. - */ - for (i = 0; i != ARRAY_SIZE(memrars); ++i) { - struct memrar_rar_info * const rar = &memrars[i]; - mutex_init(&rar->lock); - INIT_LIST_HEAD(&rar->buffers.list); - } - - err = misc_register(&memrar_miscdev); - if (err) - return err; - - /* Now claim the two RARs we want */ - err = register_rar(0, memrar_registration_callback, 0); - if (err) - goto fail; - - err = register_rar(1, memrar_registration_callback, 1); - if (err == 0) - return 0; - - /* It is possible rar 0 registered and allocated resources then rar 1 - failed so do a full resource free */ - memrar_fini_rar_resources(); -fail: - misc_deregister(&memrar_miscdev); - return err; -} - -/** - * memrar_exit - unregister and unload - * - * Unregister the device and then unload any mappings and release - * the RAR resources - */ - -static void __exit memrar_exit(void) -{ - misc_deregister(&memrar_miscdev); - memrar_fini_rar_resources(); -} - - -module_init(memrar_init); -module_exit(memrar_exit); - - -MODULE_AUTHOR("Ossama Othman "); -MODULE_DESCRIPTION("Intel Restricted Access Region Handler"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MEMRAR_VER); - - - -/* - Local Variables: - c-file-style: "linux" - End: -*/ -- cgit v1.2.2 From 02ee6d56b791ca004b141c3fc4939f020b8782dc Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Fri, 25 Mar 2011 10:23:08 +0100 Subject: staging: brcm80211: fix for 'AC_BE txop..' logs spammed problem Larry Finger reported this issue. The driver, under certain conditions, spews log messages like this: wl0: wlc_d11hdrs_mac80211: AC_BE txop exceeded phylen 159/256 dur 1778/1504 These log messages turned out to be false alarms. Root cause was that the AC was derived from the sk_buff::priority field. Fix was to derive the AC from the sk_buff using skb_get_queue_mapping() Signed-off-by: Roland Vossen Tested-by: Larry Finger Acked-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmsmac/wlc_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_main.c b/drivers/staging/brcm80211/brcmsmac/wlc_main.c index 639b5d7c9603..181a626d1984 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_main.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_main.c @@ -6283,7 +6283,7 @@ wlc_d11hdrs_mac80211(struct wlc_info *wlc, struct ieee80211_hw *hw, ((preamble_type[1] == WLC_MM_PREAMBLE) == (txh->MModeFbrLen != 0))); - ac = wme_fifo2ac[queue]; + ac = skb_get_queue_mapping(p); if (SCB_WME(scb) && qos && wlc->edcf_txop[ac]) { uint frag_dur, dur, dur_fallback; -- cgit v1.2.2 From e5b9584518e278aa1632f8eafaf26e80e59addb8 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Wed, 30 Mar 2011 10:27:10 +0200 Subject: staging: brcm80211: fix for 'Short CCK' log spam Larry Finger reported this issue. Under certain conditions the log file would be spammed with 'Short CCK' messages. Since this does not indicate an error condition, the log message was simply deleted. Also, the RX_FLAG_SHORTPRE flag in rx_status->flag, on CCK reception, is now only set on short preamble reception (it used to be set both CCK short and long preambles). Signed-off-by: Roland Vossen Acked-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmsmac/wlc_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_main.c b/drivers/staging/brcm80211/brcmsmac/wlc_main.c index 181a626d1984..fe4dcce1c6fa 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_main.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_main.c @@ -6919,8 +6919,7 @@ prep_mac80211_status(struct wlc_info *wlc, d11rxhdr_t *rxh, struct sk_buff *p, preamble = 0; if (IS_CCK(rspec)) { if (rxh->PhyRxStatus_0 & PRXS0_SHORTH) - WL_ERROR("Short CCK\n"); - rx_status->flag |= RX_FLAG_SHORTPRE; + rx_status->flag |= RX_FLAG_SHORTPRE; } else if (IS_OFDM(rspec)) { rx_status->flag |= RX_FLAG_SHORTPRE; } else { -- cgit v1.2.2 From d571a566203e9dd6587b4db26e057817f2598318 Mon Sep 17 00:00:00 2001 From: Roland Vossen Date: Wed, 30 Mar 2011 10:16:29 +0200 Subject: staging: brcm80211: removed 'is_amsdu causing toss' log spam Issue reported by Larry Finger. Log message was removed. Signed-off-by: Roland Vossen Acked-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/brcm80211/brcmsmac/wlc_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_main.c b/drivers/staging/brcm80211/brcmsmac/wlc_main.c index fe4dcce1c6fa..bcccad2de354 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_main.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_main.c @@ -7078,10 +7078,8 @@ void BCMFASTPATH wlc_recv(struct wlc_info *wlc, struct sk_buff *p) if (ieee80211_is_probe_req(h->frame_control)) goto toss; - if (is_amsdu) { - WL_ERROR("%s: is_amsdu causing toss\n", __func__); + if (is_amsdu) goto toss; - } wlc_recvctl(wlc, rxh, p); return; -- cgit v1.2.2 From 84ba253b07a3d8e58160690320e9cfbe199bb88e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 21 Mar 2011 08:51:43 -0700 Subject: staging/rtl81*: build as loadable modules only These 3 drivers contain much duplicated (triplicated) code, so building them as built-in results in many errors like: (.text+0x1b160): multiple definition of `ieee80211_sta_ps_sleep' Prevent this configuration by making them all buildable only as loadable modules (similar to the vt665[56] patch last week). Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8187se/Kconfig | 1 + drivers/staging/rtl8192e/Kconfig | 1 + drivers/staging/rtl8192u/Kconfig | 1 + 3 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig index 1b3103fbf29c..3162aabbeb07 100644 --- a/drivers/staging/rtl8187se/Kconfig +++ b/drivers/staging/rtl8187se/Kconfig @@ -1,6 +1,7 @@ config R8187SE tristate "RealTek RTL8187SE Wireless LAN NIC driver" depends on PCI && WLAN + depends on m select WIRELESS_EXT select WEXT_PRIV select EEPROM_93CX6 diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig index 2e64b239e241..750c347bfbe1 100644 --- a/drivers/staging/rtl8192e/Kconfig +++ b/drivers/staging/rtl8192e/Kconfig @@ -1,6 +1,7 @@ config RTL8192E tristate "RealTek RTL8192E Wireless LAN NIC driver" depends on PCI && WLAN + depends on m select WIRELESS_EXT select WEXT_PRIV select CRYPTO diff --git a/drivers/staging/rtl8192u/Kconfig b/drivers/staging/rtl8192u/Kconfig index 28969198e7e2..3f055091b35f 100644 --- a/drivers/staging/rtl8192u/Kconfig +++ b/drivers/staging/rtl8192u/Kconfig @@ -1,6 +1,7 @@ config RTL8192U tristate "RealTek RTL8192U Wireless LAN NIC driver" depends on PCI && WLAN && USB + depends on m select WIRELESS_EXT select WEXT_PRIV select CRYPTO -- cgit v1.2.2 From 3efe509070e3d27e6d5dbc4bf8588e9453e9b949 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 18 Mar 2011 18:11:42 +0200 Subject: UBI: check if we are in RO mode in the erase routine 'do_sync_erase()' has to check whether we are in R/O mode before erasing the PEB. This patch adds the check and while on it, adds an assertion which validates the 'pnum' argument, as well as removes a check which is always true because it has already been done few lines before. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/io.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index eededf94f5a6..e347cc4388ed 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -344,6 +344,12 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum) wait_queue_head_t wq; dbg_io("erase PEB %d", pnum); + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + + if (ubi->ro_mode) { + ubi_err("read-only mode"); + return -EROFS; + } retry: init_waitqueue_head(&wq); @@ -390,7 +396,7 @@ retry: if (err) return err; - if (ubi_dbg_is_erase_failure() && !err) { + if (ubi_dbg_is_erase_failure()) { dbg_err("cannot erase PEB %d (emulated)", pnum); return -EIO; } -- cgit v1.2.2 From 6e5133cc757912e7ba2bfbbfb384667707f45ec3 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Fri, 25 Mar 2011 18:48:59 +0200 Subject: UBI: do not compare array with NULL Coverity spotted that UBI debugging code tries to compare an array and NULL, which obviously makes little sense. Kill this check. Signed-off-by: Artem Bityutskiy --- drivers/mtd/ubi/vmt.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index b79e0dea3632..366eb70219a6 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -790,11 +790,6 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id) goto fail; } - if (!vol->name) { - ubi_err("NULL volume name"); - goto fail; - } - n = strnlen(vol->name, vol->name_len + 1); if (n != vol->name_len) { ubi_err("bad name_len %lld", n); -- cgit v1.2.2 From 6bef0b67474d71e0d6484cbabcc87657a1176d8d Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 30 Mar 2011 11:27:08 +0300 Subject: UBI: do not select KALLSYMS_ALL All UBI needs is to make sure we stacktraces when UBI debugging is enabled. It is enough to select KALLSYMS for this, KALLSYMS_ALL is not necessary. And the current Kconfig line we have: select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL is just too complex to be sane and right. But this "if" part there is needed to prevent "unmet direct dependency" warnings, because KALLSYMS_ALL depends on KALLSYMS and DEBUG_KERNEL, so we cannot just select KALLSYMS_ALL. Anyway, this feels messy, and we do not seem to really need KALLSYMS_ALL, so select KALLSYMS instead. Signed-off-by: Artem Bityutskiy Acked-by: Randy Dunlap --- drivers/mtd/ubi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index 6abeb4f13403..4dcc752a0c0b 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -56,7 +56,7 @@ config MTD_UBI_DEBUG bool "UBI debugging" depends on SYSFS select DEBUG_FS - select KALLSYMS_ALL if KALLSYMS && DEBUG_KERNEL + select KALLSYMS help This option enables UBI debugging. -- cgit v1.2.2 From 0de009c900e7ebd21097797f723a40813e953879 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 5 Apr 2011 16:04:39 +0100 Subject: drm/i915/crt: Remove 0xa0 probe for VGA This is a moral revert of 6ec3d0c0e9c0c605696e91048eebaca7b0c36695. Following the fix to reset the GMBUS controller after a NAK, we finally utilize the 0xa0 probe for a CRT connection. And discover that the code is broken. Shock. There are a number of issues, but following a key insight from Dave Airlie, that 0xA0 is an invalid address on a 7-bit bus (though not if we were to enable 10-bit addressing), and would look like the EDID port 0x50, it is possible to see where the confusion starts. In short, a write to 0xA0 is accepted by the GMBUS controller which we interpreted as meaning the existence of a connection (a slave on the other end of the wire ACKing the write). That was false. During testing with a broken GMBUS implementation, which never reset an earlier NAK, this test always reported a NAK and so we proceeded on to the next test. Reported-and-tested-by: Sitsofe Wheeler Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35904 Reported-and-tested-by: Riccardo Magliocchetti Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=32612 Signed-off-by: Chris Wilson Acked-by: Dave Airlie Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_crt.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 8342259f3160..d03fc05b39c0 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -269,21 +269,6 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) return ret; } -static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus) -{ - u8 buf; - struct i2c_msg msgs[] = { - { - .addr = 0xA0, - .flags = 0, - .len = 1, - .buf = &buf, - }, - }; - /* DDC monitor detect: Does it ACK a write to 0xA0? */ - return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1; -} - static bool intel_crt_detect_ddc(struct drm_connector *connector) { struct intel_crt *crt = intel_attached_crt(connector); @@ -293,11 +278,6 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) if (crt->base.type != INTEL_OUTPUT_ANALOG) return false; - if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) { - DRM_DEBUG_KMS("CRT detected via DDC:0xa0\n"); - return true; - } - if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) { struct edid *edid; bool is_digital = false; -- cgit v1.2.2 From a6737ad15b4acf88bbf7753e929faf215adeaa3a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 5 Apr 2011 16:04:40 +0100 Subject: drm/i915/lvds: Remove 0xa0 DDC probe for LVDS This is a revert of 428d2e828c0a68206e5158a42451487601dc9194. This is broken in the same manner as for VGA: trying to write to an invalid address on the (currently 7-bit) i2c bus. One notable failure appears to be for MacBooks. The scary part was that it gave the appearance of working (i.e. reporting the absence of the panel) on various all-in-one machines with ghost LVDS panels and not failing for laptops. Signed-off-by: Chris Wilson Acked-by: Dave Airlie Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_lvds.c | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 86cd30bcb619..a562bd2648c7 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -829,25 +829,6 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev, return false; } -static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u8 buf = 0; - struct i2c_msg msgs[] = { - { - .addr = 0xA0, - .flags = 0, - .len = 1, - .buf = &buf, - }, - }; - struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter; - /* XXX this only appears to work when using GMBUS */ - if (intel_gmbus_is_forced_bit(i2c)) - return true; - return i2c_transfer(i2c, msgs, 1) == 1; -} - /** * intel_lvds_init - setup LVDS connectors on this device * @dev: drm device @@ -888,11 +869,6 @@ bool intel_lvds_init(struct drm_device *dev) } } - if (!intel_lvds_ddc_probe(dev, pin)) { - DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n"); - return false; - } - intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL); if (!intel_lvds) { return false; -- cgit v1.2.2 From fc5b85b0ad1f9da948e4d683710081a9bda357cb Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Mar 2011 16:44:35 +0100 Subject: staging: IIO: IMU: ADIS16400: Fix up SPI messages cs_change behavior cs_change must not be set in the last transfer of a spi message Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron CC: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/imu/adis16400_core.c | 2 -- drivers/staging/iio/imu/adis16400_ring.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index cfb108a1545b..1007e3ded92f 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -93,7 +93,6 @@ static int adis16400_spi_write_reg_16(struct device *dev, .tx_buf = st->tx + 2, .bits_per_word = 8, .len = 2, - .cs_change = 1, }, }; @@ -137,7 +136,6 @@ static int adis16400_spi_read_reg_16(struct device *dev, .rx_buf = st->rx, .bits_per_word = 8, .len = 2, - .cs_change = 1, }, }; diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index 33293fba9bcc..ac381ca126fc 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -122,12 +122,10 @@ static int adis16400_spi_read_burst(struct device *dev, u8 *rx) .tx_buf = st->tx, .bits_per_word = 8, .len = 2, - .cs_change = 0, }, { .rx_buf = rx, .bits_per_word = 8, .len = 24, - .cs_change = 1, }, }; -- cgit v1.2.2 From c59c95ce6ace6d256401fc3a3648a95375ef4e63 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Mar 2011 16:44:36 +0100 Subject: staging: IIO: IMU: ADIS16400: Add delay after self test Add delay after self test to satisfy timing requirements. Increase start-up delay. Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron CC: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/imu/adis16400.h | 3 ++- drivers/staging/iio/imu/adis16400_core.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index 6ff33e1ad8c1..90e90f0e65e8 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -17,7 +17,8 @@ #ifndef SPI_ADIS16400_H_ #define SPI_ADIS16400_H_ -#define ADIS16400_STARTUP_DELAY 220 /* ms */ +#define ADIS16400_STARTUP_DELAY 290 /* ms */ +#define ADIS16400_MTEST_DELAY 90 /* ms */ #define ADIS16400_READ_REG(a) a #define ADIS16400_WRITE_REG(a) ((a) | 0x80) diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 1007e3ded92f..633b3a4e4289 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -373,7 +373,7 @@ static int adis16400_self_test(struct device *dev) dev_err(dev, "problem starting self test"); goto err_ret; } - + msleep(ADIS16400_MTEST_DELAY); adis16400_check_status(dev); err_ret: -- cgit v1.2.2 From b181119723d62b19904e1f12e467e996631c5a29 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Mar 2011 16:44:37 +0100 Subject: staging: IIO: IMU: ADIS16400: Fix addresses of GYRO and ACCEL calibration offset Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron CC: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/imu/adis16400_core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 633b3a4e4289..2107edb3ebce 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -495,12 +495,12 @@ err_ret: _reg) static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_X, ADIS16400_XGYRO_OFF); -static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_Y, ADIS16400_XGYRO_OFF); -static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_Z, ADIS16400_XGYRO_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_Y, ADIS16400_YGYRO_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(GYRO_Z, ADIS16400_ZGYRO_OFF); static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_X, ADIS16400_XACCL_OFF); -static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_Y, ADIS16400_XACCL_OFF); -static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_Z, ADIS16400_XACCL_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_Y, ADIS16400_YACCL_OFF); +static ADIS16400_DEV_ATTR_CALIBBIAS(ACCEL_Z, ADIS16400_ZACCL_OFF); static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16400_read_14bit_signed, -- cgit v1.2.2 From 0fea4d6192cb82789e28905240d3c1dac6529c7c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Mar 2011 16:44:38 +0100 Subject: staging: IIO: IMU: ADIS16400: Make sure only enabled scan_elements are pushed into the ring Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron CC: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/imu/adis16400_ring.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index ac381ca126fc..da28cb4288af 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -160,9 +160,10 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s) work_trigger_to_ring); struct iio_ring_buffer *ring = st->indio_dev->ring; - int i = 0; + int i = 0, j; s16 *data; size_t datasize = ring->access.get_bytes_per_datum(ring); + unsigned long mask = ring->scan_mask; data = kmalloc(datasize , GFP_KERNEL); if (data == NULL) { @@ -172,9 +173,12 @@ static void adis16400_trigger_bh_to_ring(struct work_struct *work_s) if (ring->scan_count) if (adis16400_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0) - for (; i < ring->scan_count; i++) + for (; i < ring->scan_count; i++) { + j = __ffs(mask); + mask &= ~(1 << j); data[i] = be16_to_cpup( - (__be16 *)&(st->rx[i*2])); + (__be16 *)&(st->rx[j*2])); + } /* Guaranteed to be aligned with 8 byte boundary */ if (ring->scan_timestamp) -- cgit v1.2.2 From 4d1ea4a67ef4d8ba9462c1c8df84ab7c9176006b Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Mar 2011 16:44:39 +0100 Subject: staging: IIO: IMU: ADIS16400: Fix product ID check, skip embedded revision number Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/imu/adis16400_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 2107edb3ebce..0d8df6282b21 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -469,7 +469,7 @@ static int adis16400_initial_setup(struct adis16400_state *st) if (ret) goto err_ret; - if (prod_id != ADIS16400_PRODUCT_ID_DEFAULT) + if ((prod_id & 0xF000) != ADIS16400_PRODUCT_ID_DEFAULT) dev_warn(dev, "unknown product id"); printk(KERN_INFO DRIVER_NAME ": prod_id 0x%04x at CS%d (irq %d)\n", -- cgit v1.2.2 From 6a6ec6233403ecdad0c042276e4479ca23716b1c Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Mon, 21 Mar 2011 16:44:40 +0100 Subject: staging: IIO: IMU: ADIS16400: Avoid using printk facility directly Signed-off-by: Michael Hennerich Acked-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/staging/iio/imu/adis16400_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index 0d8df6282b21..540bde69cc3b 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -6,6 +6,7 @@ * * Copyright (c) 2009 Manuel Stahl * Copyright (c) 2007 Jonathan Cameron + * Copyright (c) 2011 Analog Devices Inc. * * 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 @@ -472,7 +473,8 @@ static int adis16400_initial_setup(struct adis16400_state *st) if ((prod_id & 0xF000) != ADIS16400_PRODUCT_ID_DEFAULT) dev_warn(dev, "unknown product id"); - printk(KERN_INFO DRIVER_NAME ": prod_id 0x%04x at CS%d (irq %d)\n", + + dev_info(dev, ": prod_id 0x%04x at CS%d (irq %d)\n", prod_id, st->us->chip_select, st->us->irq); /* use high spi speed if possible */ @@ -645,7 +647,7 @@ static int __devinit adis16400_probe(struct spi_device *spi) ret = iio_ring_buffer_register(st->indio_dev->ring, 0); if (ret) { - printk(KERN_ERR "failed to initialize the ring\n"); + dev_err(&spi->dev, "failed to initialize the ring\n"); goto error_unreg_ring_funcs; } -- cgit v1.2.2 From 929e27252e8ca69363f81f26af5eaba62cb4c572 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Wed, 30 Mar 2011 12:22:23 +0200 Subject: ide: ide_requeue_and_plug() reinstate "always plug" behaviour We see stalls if we don't always ensure that the queue gets run again. Even if rq == NULL, we could have other pending requests in the queue. Signed-off-by: Jens Axboe --- drivers/ide/ide-io.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 0e406d73b2c8..ca27d3090aeb 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -570,8 +570,7 @@ void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) spin_unlock_irqrestore(q->queue_lock, flags); /* Use 3ms as that was the old plug delay */ - if (rq) - blk_delay_queue(q, 3); + blk_delay_queue(q, 3); } static int drive_is_ready(ide_drive_t *drive) -- cgit v1.2.2 From a63a5cf84dac7a23a57c800eea5734701e7d3c04 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Fri, 1 Apr 2011 21:02:31 +0200 Subject: dm: improve block integrity support The current block integrity (DIF/DIX) support in DM is verifying that all devices' integrity profiles match during DM device resume (which is past the point of no return). To some degree that is unavoidable (stacked DM devices force this late checking). But for most DM devices (which aren't stacking on other DM devices) the ideal time to verify all integrity profiles match is during table load. Introduce the notion of an "initialized" integrity profile: a profile that was blk_integrity_register()'d with a non-NULL 'blk_integrity' template. Add blk_integrity_is_initialized() to allow checking if a profile was initialized. Update DM integrity support to: - check all devices with _initialized_ integrity profiles match during table load; uninitialized profiles (e.g. for underlying DM device(s) of a stacked DM device) are ignored. - disallow a table load that would result in an integrity profile that conflicts with a DM device's existing (in-use) integrity profile - avoid clearing an existing integrity profile - validate all integrity profiles match during resume; but if they don't all we can do is report the mismatch (during resume we're past the point of no return) Signed-off-by: Mike Snitzer Cc: Martin K. Petersen Signed-off-by: Jens Axboe --- drivers/md/dm-table.c | 114 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 416d4e258df6..cb8380c9767f 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -926,21 +926,81 @@ static int dm_table_build_index(struct dm_table *t) return r; } +/* + * Get a disk whose integrity profile reflects the table's profile. + * If %match_all is true, all devices' profiles must match. + * If %match_all is false, all devices must at least have an + * allocated integrity profile; but uninitialized is ok. + * Returns NULL if integrity support was inconsistent or unavailable. + */ +static struct gendisk * dm_table_get_integrity_disk(struct dm_table *t, + bool match_all) +{ + struct list_head *devices = dm_table_get_devices(t); + struct dm_dev_internal *dd = NULL; + struct gendisk *prev_disk = NULL, *template_disk = NULL; + + list_for_each_entry(dd, devices, list) { + template_disk = dd->dm_dev.bdev->bd_disk; + if (!blk_get_integrity(template_disk)) + goto no_integrity; + if (!match_all && !blk_integrity_is_initialized(template_disk)) + continue; /* skip uninitialized profiles */ + else if (prev_disk && + blk_integrity_compare(prev_disk, template_disk) < 0) + goto no_integrity; + prev_disk = template_disk; + } + + return template_disk; + +no_integrity: + if (prev_disk) + DMWARN("%s: integrity not set: %s and %s profile mismatch", + dm_device_name(t->md), + prev_disk->disk_name, + template_disk->disk_name); + return NULL; +} + /* * Register the mapped device for blk_integrity support if - * the underlying devices support it. + * the underlying devices have an integrity profile. But all devices + * may not have matching profiles (checking all devices isn't reliable + * during table load because this table may use other DM device(s) which + * must be resumed before they will have an initialized integity profile). + * Stacked DM devices force a 2 stage integrity profile validation: + * 1 - during load, validate all initialized integrity profiles match + * 2 - during resume, validate all integrity profiles match */ static int dm_table_prealloc_integrity(struct dm_table *t, struct mapped_device *md) { - struct list_head *devices = dm_table_get_devices(t); - struct dm_dev_internal *dd; + struct gendisk *template_disk = NULL; - list_for_each_entry(dd, devices, list) - if (bdev_get_integrity(dd->dm_dev.bdev)) { - t->integrity_supported = 1; - return blk_integrity_register(dm_disk(md), NULL); - } + template_disk = dm_table_get_integrity_disk(t, false); + if (!template_disk) + return 0; + if (!blk_integrity_is_initialized(dm_disk(md))) { + t->integrity_supported = 1; + return blk_integrity_register(dm_disk(md), NULL); + } + + /* + * If DM device already has an initalized integrity + * profile the new profile should not conflict. + */ + if (blk_integrity_is_initialized(template_disk) && + blk_integrity_compare(dm_disk(md), template_disk) < 0) { + DMWARN("%s: conflict with existing integrity profile: " + "%s profile mismatch", + dm_device_name(t->md), + template_disk->disk_name); + return 1; + } + + /* Preserve existing initialized integrity profile */ + t->integrity_supported = 1; return 0; } @@ -1094,41 +1154,27 @@ combine_limits: /* * Set the integrity profile for this device if all devices used have - * matching profiles. + * matching profiles. We're quite deep in the resume path but still + * don't know if all devices (particularly DM devices this device + * may be stacked on) have matching profiles. Even if the profiles + * don't match we have no way to fail (to resume) at this point. */ static void dm_table_set_integrity(struct dm_table *t) { - struct list_head *devices = dm_table_get_devices(t); - struct dm_dev_internal *prev = NULL, *dd = NULL; + struct gendisk *template_disk = NULL; if (!blk_get_integrity(dm_disk(t->md))) return; - list_for_each_entry(dd, devices, list) { - if (prev && - blk_integrity_compare(prev->dm_dev.bdev->bd_disk, - dd->dm_dev.bdev->bd_disk) < 0) { - DMWARN("%s: integrity not set: %s and %s mismatch", - dm_device_name(t->md), - prev->dm_dev.bdev->bd_disk->disk_name, - dd->dm_dev.bdev->bd_disk->disk_name); - goto no_integrity; - } - prev = dd; + template_disk = dm_table_get_integrity_disk(t, true); + if (!template_disk && + blk_integrity_is_initialized(dm_disk(t->md))) { + DMWARN("%s: device no longer has a valid integrity profile", + dm_device_name(t->md)); + return; } - - if (!prev || !bdev_get_integrity(prev->dm_dev.bdev)) - goto no_integrity; - blk_integrity_register(dm_disk(t->md), - bdev_get_integrity(prev->dm_dev.bdev)); - - return; - -no_integrity: - blk_integrity_register(dm_disk(t->md), NULL); - - return; + blk_get_integrity(template_disk)); } void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, -- cgit v1.2.2 From 782b86e2656762382ae1c2686d8d5c91f7d5eacf Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 5 Apr 2011 03:29:57 +0200 Subject: ide: always ensure that blk_delay_queue() is called if we have pending IO Just because we are not requeuing a request does not mean that some aren't pending. So always issue a blk_delay_queue() if either we are requeueing OR there's pending IO. This fixes a boot problem for some IDE boxes. Signed-off-by: Jens Axboe --- drivers/ide/ide-io.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index ca27d3090aeb..177db6d5b2f5 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -430,6 +430,26 @@ static inline void ide_unlock_host(struct ide_host *host) } } +static void __ide_requeue_and_plug(struct request_queue *q, struct request *rq) +{ + if (rq) + blk_requeue_request(q, rq); + if (rq || blk_peek_request(q)) { + /* Use 3ms as that was the old plug delay */ + blk_delay_queue(q, 3); + } +} + +void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) +{ + struct request_queue *q = drive->queue; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + __ide_requeue_and_plug(q, rq); + spin_unlock_irqrestore(q->queue_lock, flags); +} + /* * Issue a new request to a device. */ @@ -550,27 +570,7 @@ plug_device: ide_unlock_host(host); plug_device_2: spin_lock_irq(q->queue_lock); - - if (rq) { - blk_requeue_request(q, rq); - blk_delay_queue(q, queue_run_ms); - } -} - -void ide_requeue_and_plug(ide_drive_t *drive, struct request *rq) -{ - struct request_queue *q = drive->queue; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - - if (rq) - blk_requeue_request(q, rq); - - spin_unlock_irqrestore(q->queue_lock, flags); - - /* Use 3ms as that was the old plug delay */ - blk_delay_queue(q, 3); + __ide_requeue_and_plug(q, rq); } static int drive_is_ready(ide_drive_t *drive) -- cgit v1.2.2 From cc5e0f08ca2a66fc4c6984ccff74fd529e969fac Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Fri, 1 Apr 2011 17:03:39 -0400 Subject: HID: hid-magicmouse: Increase evdev buffer size The evdev buffer isn't big enough when you get many fingers on the device. Bump up the buffer to a reasonable size, matching what other multitouch devices use. Without this change, events may be discarded in the evdev buffer before they are read. Reported-by: Simon Budig Cc: Henrik Rydberg Cc: Jiri Kosina Cc: stable@kernel.org Signed-off-by: Chase Douglas Acked-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 318cc40df92d..418c399d3ef7 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -418,6 +418,8 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h input_set_abs_params(input, ABS_MT_POSITION_Y, -2456, 2565, 4, 0); } + + input_set_events_per_packet(input, 60); } if (report_undeciphered) { -- cgit v1.2.2 From da60325d83867849543b48a317bf2f8d4faebfb4 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 6 Apr 2011 07:12:32 -0700 Subject: HID: Add support for CH Pro Throttle CH Pro Throttle needs NOGET the same way as other products from the same vendor require. Reported-by: Unavowed Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 56e8e4ab65d0..609fa799b916 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -147,6 +147,7 @@ #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01 #define USB_VENDOR_ID_CH 0x068e +#define USB_DEVICE_ID_CH_PRO_THROTTLE 0x00f1 #define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2 #define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4 #define USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE 0x0051 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 9a94b643ccde..a8426f15e9ab 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -59,6 +59,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, -- cgit v1.2.2 From b73a21fc66fee35b41db755abebfacba48b2fc76 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 1 Apr 2011 07:17:27 +0000 Subject: video: s3c-fb: fix checkpatch errors and warning This patch fixes the checkpatch errors listed below: ERROR: space required before the open parenthesis '(' ERROR: need consistent spacing around '+' (ctx:WxV) ERROR: space prohibited before that close parenthesis ')' Also, following warning is fixed by adding 'platid' variable which can reduce number of lines exceeding 80 characters. WARNING: line over 80 characters Signed-off-by: Jingoo Han Signed-off-by: Paul Mundt --- drivers/video/s3c-fb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 6817d187d46e..3b6cdcac8f1a 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -48,7 +48,7 @@ #undef writel #define writel(v, r) do { \ printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \ - __raw_writel(v, r); } while(0) + __raw_writel(v, r); } while (0) #endif /* FB_S3C_DEBUG_REGWRITE */ /* irq_flags bits */ @@ -518,7 +518,7 @@ static int s3c_fb_set_par(struct fb_info *info) data = VIDTCON2_LINEVAL(var->yres - 1) | VIDTCON2_HOZVAL(var->xres - 1); - writel(data, regs +sfb->variant.vidtcon + 8 ); + writel(data, regs + sfb->variant.vidtcon + 8); } /* write the buffer address */ @@ -1304,6 +1304,7 @@ static void s3c_fb_clear_win(struct s3c_fb *sfb, int win) static int __devinit s3c_fb_probe(struct platform_device *pdev) { + const struct platform_device_id *platid; struct s3c_fb_driverdata *fbdrv; struct device *dev = &pdev->dev; struct s3c_fb_platdata *pd; @@ -1312,7 +1313,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) int win; int ret = 0; - fbdrv = (struct s3c_fb_driverdata *)platform_get_device_id(pdev)->driver_data; + platid = platform_get_device_id(pdev); + fbdrv = (struct s3c_fb_driverdata *)platid->driver_data; if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) { dev_err(dev, "too many windows, cannot attach\n"); -- cgit v1.2.2 From a8c908d353e52336b864025dbd8253134c3f5411 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 1 Apr 2011 14:23:47 +0000 Subject: drivers/video/bfin-lq035q1-fb.c: introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Acked-by: Mike Frysinger Signed-off-by: Paul Mundt --- drivers/video/bfin-lq035q1-fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c index c8e1f04941bd..23b6c4b62c78 100644 --- a/drivers/video/bfin-lq035q1-fb.c +++ b/drivers/video/bfin-lq035q1-fb.c @@ -154,8 +154,10 @@ static int __devinit lq035q1_spidev_probe(struct spi_device *spi) ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); - if (ret) + if (ret) { + kfree(ctl); return ret; + } spi_set_drvdata(spi, ctl); -- cgit v1.2.2 From a564d301e93f96a23c808b4cf234ac08b073c96d Mon Sep 17 00:00:00 2001 From: Tormod Volden Date: Sun, 3 Apr 2011 12:54:04 +0000 Subject: savagefb: Replace magic register address with define MM_SERIAL1 was already defined, but not used. Signed-off-by: Tormod Volden Signed-off-by: Paul Mundt --- drivers/video/savage/savagefb-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index b16e6138fdd4..58c8a3ce33c5 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -191,7 +191,7 @@ void savagefb_create_i2c_busses(struct fb_info *info) par->chan.algo.getscl = prosavage_gpio_getscl; break; case FB_ACCEL_SAVAGE2000: - par->chan.reg = 0xff20; + par->chan.reg = MM_SERIAL1; par->chan.ioaddr = par->mmio.vbase; par->chan.algo.setsda = savage4_gpio_setsda; par->chan.algo.setscl = savage4_gpio_setscl; -- cgit v1.2.2 From 21cd72e7cb424f1686855602ec0fdc6e5830f249 Mon Sep 17 00:00:00 2001 From: Tormod Volden Date: Sun, 3 Apr 2011 12:54:05 +0000 Subject: savagefb: Set up I2C based on chip family instead of card id In practice this means enabling I2C (for DDC2) on all prosavage cards, like the xorg ddx does. The savage4 and savage2000 families have only one member each, so there is no change for those. Tested on TwisterK. Signed-off-by: Tormod Volden Signed-off-by: Paul Mundt --- drivers/video/savage/savagefb-i2c.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 58c8a3ce33c5..5e7acda2ba90 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -170,9 +170,8 @@ void savagefb_create_i2c_busses(struct fb_info *info) struct savagefb_par *par = info->par; par->chan.par = par; - switch(info->fix.accel) { - case FB_ACCEL_PROSAVAGE_DDRK: - case FB_ACCEL_PROSAVAGE_PM: + switch (par->chip) { + case S3_PROSAVAGE: par->chan.reg = CR_SERIAL2; par->chan.ioaddr = par->mmio.vbase; par->chan.algo.setsda = prosavage_gpio_setsda; @@ -180,7 +179,7 @@ void savagefb_create_i2c_busses(struct fb_info *info) par->chan.algo.getsda = prosavage_gpio_getsda; par->chan.algo.getscl = prosavage_gpio_getscl; break; - case FB_ACCEL_SAVAGE4: + case S3_SAVAGE4: par->chan.reg = CR_SERIAL1; if (par->pcidev->revision > 1 && !(VGArCR(0xa6, par) & 0x40)) par->chan.reg = CR_SERIAL2; @@ -190,7 +189,7 @@ void savagefb_create_i2c_busses(struct fb_info *info) par->chan.algo.getsda = prosavage_gpio_getsda; par->chan.algo.getscl = prosavage_gpio_getscl; break; - case FB_ACCEL_SAVAGE2000: + case S3_SAVAGE2000: par->chan.reg = MM_SERIAL1; par->chan.ioaddr = par->mmio.vbase; par->chan.algo.setsda = savage4_gpio_setsda; -- cgit v1.2.2 From 787dffa5c790fdae40a0706e0b3847e31282eb3b Mon Sep 17 00:00:00 2001 From: Tormod Volden Date: Sun, 3 Apr 2011 12:54:06 +0000 Subject: savagefb: Remove obsolete else clause in savage_setup_i2c_bus The else clause was not needed after the cleanup in commit b8901b091db260b0f0101d6395ce5c6016835a47 Signed-off-by: Tormod Volden Signed-off-by: Paul Mundt --- drivers/video/savage/savagefb-i2c.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 5e7acda2ba90..bb71fea07284 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -159,8 +159,7 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan, else dev_warn(&chan->par->pcidev->dev, "Failed to register I2C bus %s.\n", name); - } else - chan->par = NULL; + } return rc; } -- cgit v1.2.2 From 47c87d930f3db4fc3a30505075e07f5597e2e953 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 4 Apr 2011 21:39:54 +0000 Subject: fb: Reduce priority of resource conflict message It's expected that efifb will conflict with a native driver, so the handover message should be informational rather than an error. Signed-off-by: Matthew Garrett Acked-by: Dave Airlie Signed-off-by: Paul Mundt --- drivers/video/fbmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e2bf95370e40..e0c2284924b6 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1507,7 +1507,7 @@ void remove_conflicting_framebuffers(struct apertures_struct *a, (primary && gen_aper && gen_aper->count && gen_aper->ranges[0].base == VGA_FB_PHYS)) { - printk(KERN_ERR "fb: conflicting fb hw usage " + printk(KERN_INFO "fb: conflicting fb hw usage " "%s vs %s - removing generic driver\n", name, registered_fb[i]->fix.id); unregister_framebuffer(registered_fb[i]); -- cgit v1.2.2 From 47dfe51f8f0b9540cbe15072cd352d9f3857d47f Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Wed, 6 Apr 2011 17:34:58 +0000 Subject: efifb: Support overriding fields FW tells us with the DMI data. Some machines apparently give us bogus linelength/stride/pitch data, so we need to support letting the DMI table override the supplied data. I bet you can't guess whose machines I'm talking about. Signed-off-by: Peter Jones Signed-off-by: Paul Mundt --- drivers/video/efifb.c | 149 +++++++++++++++++++++++++++++--------------------- 1 file changed, 88 insertions(+), 61 deletions(-) (limited to 'drivers') diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index a9645b86a623..2359b6403a16 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -68,41 +68,48 @@ enum { M_UNKNOWN /* placeholder */ }; +#define OVERRIDE_NONE 0x0 +#define OVERRIDE_BASE 0x1 +#define OVERRIDE_STRIDE 0x2 +#define OVERRIDE_HEIGHT 0x4 +#define OVERRIDE_WIDTH 0x8 + static struct efifb_dmi_info { char *optname; unsigned long base; int stride; int width; int height; + int flags; } dmi_list[] __initdata = { - [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 }, - [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */ - [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 }, - [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */ - [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200 }, - [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080 }, - [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440 }, - [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 }, - [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768 }, - [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200 }, - [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 }, - [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800 }, - [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800 }, - [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800 }, - [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 }, - [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 }, - [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */ - [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900 }, - [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 }, - [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 }, - [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900 }, - [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200 }, - [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900 }, - [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200 }, - [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050 }, - [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800 }, - [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900 }, - [M_UNKNOWN] = { NULL, 0, 0, 0, 0 } + [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, + [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, /* guess */ + [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050, OVERRIDE_NONE }, + [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, /* guess */ + [M_I24_8_1] = { "imac8", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, + [M_I24_10_1] = { "imac10", 0xc0010000, 2048 * 4, 1920, 1080, OVERRIDE_NONE }, + [M_I27_11_1] = { "imac11", 0xc0010000, 2560 * 4, 2560, 1440, OVERRIDE_NONE }, + [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768, OVERRIDE_NONE }, + [M_MINI_3_1] = { "mini31", 0x40010000, 1024 * 4, 1024, 768, OVERRIDE_NONE }, + [M_MINI_4_1] = { "mini41", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, + [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, + [M_MB_5_1] = { "macbook51", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, + [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, + [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, + [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, + [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, + [M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */ + [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, + [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, + [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, + [M_MBP_5_1] = { "mbp51", 0xc0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, + [M_MBP_5_2] = { "mbp52", 0xc0010000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, + [M_MBP_5_3] = { "mbp53", 0xd0010000, 2048 * 4, 1440, 900, OVERRIDE_NONE }, + [M_MBP_6_1] = { "mbp61", 0x90030000, 2048 * 4, 1920, 1200, OVERRIDE_NONE }, + [M_MBP_6_2] = { "mbp62", 0x90030000, 2048 * 4, 1680, 1050, OVERRIDE_NONE }, + [M_MBP_7_1] = { "mbp71", 0xc0010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, + [M_MBP_8_2] = { "mbp82", 0x90010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, + [M_UNKNOWN] = { NULL, 0, 0, 0, 0, OVERRIDE_NONE } }; static int set_system(const struct dmi_system_id *id); @@ -157,16 +164,22 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { {}, }; +#define choose_value(dmivalue, fwvalue, field, flags) ({ \ + typeof(fwvalue) _ret_ = fwvalue; \ + if ((flags) & (field)) \ + _ret_ = dmivalue; \ + else if ((fwvalue) == 0) \ + _ret_ = dmivalue; \ + _ret_; \ + }) + static int set_system(const struct dmi_system_id *id) { struct efifb_dmi_info *info = id->driver_data; - if (info->base == 0) - return 0; - printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " - "(%dx%d, stride %d)\n", id->ident, - (void *)info->base, info->width, info->height, - info->stride); + if (info->base == 0 && info->height == 0 && info->width == 0 + && info->stride == 0) + return 0; /* Trust the bootloader over the DMI tables */ if (screen_info.lfb_base == 0) { @@ -174,40 +187,47 @@ static int set_system(const struct dmi_system_id *id) struct pci_dev *dev = NULL; int found_bar = 0; #endif - screen_info.lfb_base = info->base; + if (info->base) { + screen_info.lfb_base = choose_value(info->base, + screen_info.lfb_base, OVERRIDE_BASE, + info->flags); #if defined(CONFIG_PCI) - /* make sure that the address in the table is actually on a - * VGA device's PCI BAR */ - - for_each_pci_dev(dev) { - int i; - if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) - continue; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - resource_size_t start, end; - - start = pci_resource_start(dev, i); - if (start == 0) - break; - end = pci_resource_end(dev, i); - if (screen_info.lfb_base >= start && - screen_info.lfb_base < end) { - found_bar = 1; + /* make sure that the address in the table is actually + * on a VGA device's PCI BAR */ + + for_each_pci_dev(dev) { + int i; + if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + continue; + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + resource_size_t start, end; + + start = pci_resource_start(dev, i); + if (start == 0) + break; + end = pci_resource_end(dev, i); + if (screen_info.lfb_base >= start && + screen_info.lfb_base < end) { + found_bar = 1; + } } } - } - if (!found_bar) - screen_info.lfb_base = 0; + if (!found_bar) + screen_info.lfb_base = 0; #endif + } } if (screen_info.lfb_base) { - if (screen_info.lfb_linelength == 0) - screen_info.lfb_linelength = info->stride; - if (screen_info.lfb_width == 0) - screen_info.lfb_width = info->width; - if (screen_info.lfb_height == 0) - screen_info.lfb_height = info->height; + screen_info.lfb_linelength = choose_value(info->stride, + screen_info.lfb_linelength, OVERRIDE_STRIDE, + info->flags); + screen_info.lfb_width = choose_value(info->width, + screen_info.lfb_width, OVERRIDE_WIDTH, + info->flags); + screen_info.lfb_height = choose_value(info->height, + screen_info.lfb_height, OVERRIDE_HEIGHT, + info->flags); if (screen_info.orig_video_isVGA == 0) screen_info.orig_video_isVGA = VIDEO_TYPE_EFI; } else { @@ -217,6 +237,13 @@ static int set_system(const struct dmi_system_id *id) screen_info.orig_video_isVGA = 0; return 0; } + + printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p " + "(%dx%d, stride %d)\n", id->ident, + (void *)screen_info.lfb_base, screen_info.lfb_width, + screen_info.lfb_height, screen_info.lfb_linelength); + + return 1; } -- cgit v1.2.2 From 97fb85076c2d3adcc559dee577e0a3bf7215d48e Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 6 Apr 2011 17:34:59 +0000 Subject: efifb: Add override for 11" Macbook Air 3,1 The 11" Macbook Air appears to claim that its stride is 1366, when it's actually 2048. Override it. Signed-off-by: Matthew Garrett Signed-off-by: Peter Jones Signed-off-by: Paul Mundt --- drivers/video/efifb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c index 2359b6403a16..4eb38db36e4b 100644 --- a/drivers/video/efifb.c +++ b/drivers/video/efifb.c @@ -53,6 +53,7 @@ enum { M_MB_7_1, /* MacBook, 7th rev. */ M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */ M_MBA, /* MacBook Air */ + M_MBA_3, /* Macbook Air, 3rd rev */ M_MBP, /* MacBook Pro */ M_MBP_2, /* MacBook Pro 2nd gen */ M_MBP_2_2, /* MacBook Pro 2,2nd gen */ @@ -97,6 +98,8 @@ static struct efifb_dmi_info { [M_MB_6_1] = { "macbook61", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, [M_MB_7_1] = { "macbook71", 0x80010000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800, OVERRIDE_NONE }, + /* 11" Macbook Air 3,1 passes the wrong stride */ + [M_MBA_3] = { "mba3", 0, 2048 * 4, 0, 0, OVERRIDE_STRIDE }, [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, [M_MBP_2] = { "mbp2", 0, 0, 0, 0, OVERRIDE_NONE }, /* placeholder */ [M_MBP_2_2] = { "mbp22", 0x80010000, 1472 * 4, 1440, 900, OVERRIDE_NONE }, @@ -147,6 +150,7 @@ static const struct dmi_system_id dmi_system_table[] __initconst = { EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook6,1", M_MB_6_1), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook7,1", M_MB_7_1), EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA), + EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir3,1", M_MBA_3), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2), EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,2", M_MBP_2_2), -- cgit v1.2.2 From 35a67edf3570e9b44c34965dd52a6b7f845fb40f Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 5 Apr 2011 06:52:49 +0000 Subject: smsc911x: fix mac_lock acquision before calling smsc911x_mac_read When SMSC911X_SAVE_MAC_ADDRESS flag is enabled the driver calls smsc911x_mac_read and smsc911x_mac_read function without acquiring mac_lock spinlock This patch fixes following warning smsc911x: Driver version 2008-10-21. ------------[ cut here ]------------ WARNING: at drivers/net/smsc911x.c:261 smsc911x_mac_read+0x24/0x220() Modules linked in: [] (unwind_backtrace+0x0/0xe0) from [] (warn_slowpath_common+0x4c/0x64) [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_null+0x18/0x1c) [] (warn_slowpath_null+0x18/0x1c) from [] (smsc911x_mac_read+0x24/0x220) [] (smsc911x_mac_read+0x24/0x220) from [] (smsc911x_read_mac_address+0x18/0x6c) [] (smsc911x_read_mac_address+0x18/0x6c) from [] (smsc911x_drv_probe+0x498/0x1788) [] (smsc911x_drv_probe+0x498/0x1788) from [] (platform_drv_probe+0x14/0x18) [] (platform_drv_probe+0x14/0x18) from [] (driver_probe_device+0xc8/0x184) [] (driver_probe_device+0xc8/0x184) from [] (__driver_attach+0x68/0x8c) [] (__driver_attach+0x68/0x8c) from [] (bus_for_each_dev+0x48/0x74) [] (bus_for_each_dev+0x48/0x74) from [] (bus_add_driver+0x9c/0x228) [] (bus_add_driver+0x9c/0x228) from [] (driver_register+0xa0/0x124) [] (driver_register+0xa0/0x124) from [] (do_one_initcall+0x94/0x168) [] (do_one_initcall+0x94/0x168) from [] (kernel_init+0xa0/0x154) [] (kernel_init+0xa0/0x154) from [] (kernel_thread_exit+0x0/0x8) ---[ end trace 2c931a35b7885770 ]--- Signed-off-by: Enric Balletbo i Serra Signed-off-by: David S. Miller --- drivers/net/smsc911x.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 1566259c1f27..4747846eb4f2 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1818,6 +1818,7 @@ static int __devinit smsc911x_init(struct net_device *dev) SMSC_TRACE(PROBE, "PHY will be autodetected."); spin_lock_init(&pdata->dev_lock); + spin_lock_init(&pdata->mac_lock); if (pdata->ioaddr == 0) { SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); @@ -1895,8 +1896,11 @@ static int __devinit smsc911x_init(struct net_device *dev) /* workaround for platforms without an eeprom, where the mac address * is stored elsewhere and set by the bootloader. This saves the * mac address before resetting the device */ - if (pdata->config.flags & SMSC911X_SAVE_MAC_ADDRESS) + if (pdata->config.flags & SMSC911X_SAVE_MAC_ADDRESS) { + spin_lock_irq(&pdata->mac_lock); smsc911x_read_mac_address(dev); + spin_unlock_irq(&pdata->mac_lock); + } /* Reset the LAN911x */ if (smsc911x_soft_reset(pdata)) @@ -2059,8 +2063,6 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name); } - spin_lock_init(&pdata->mac_lock); - retval = smsc911x_mii_init(pdev, dev); if (retval) { SMSC_WARNING(PROBE, -- cgit v1.2.2 From 34206f267120c839a479d0237db907fa062e7b0f Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 5 Apr 2011 07:08:41 +0000 Subject: can: mcp251x: Allow pass IRQ flags through platform data. When an interrupt occurs, the INT pin is driven low by the MCP251x controller (falling edge) but in some cases the INT pin can be connected to the MPU through a transistor or level translator which inverts this signal. In this case interrupt should be configured in rising edge. This patch adds support to pass the IRQ flags via mcp251x_platform_data. Signed-off-by: Enric Balletbo i Serra Acked-by: Wolfgang Grandegger Acked-by: Marc Kleine-Budde Signed-off-by: David S. Miller --- drivers/net/can/mcp251x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index 7513c4523ac4..330140ee266d 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -931,7 +931,8 @@ static int mcp251x_open(struct net_device *net) priv->tx_len = 0; ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist, - IRQF_TRIGGER_FALLING, DEVICE_NAME, priv); + pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING, + DEVICE_NAME, priv); if (ret) { dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq); if (pdata->transceiver_enable) -- cgit v1.2.2 From 1e58148670908e9fd180761c0eed3839b6778f01 Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Mon, 4 Apr 2011 08:29:59 +0000 Subject: bna: Fix for handling firmware heartbeat failure This patch contains a fix for gracefully handling firmware heartbeat failure instead of forcing panic. Signed-off-by: Debashis Dutt Signed-off-by: Rasesh Mody Signed-off-by: David S. Miller --- drivers/net/bna/bfa_ioc.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index 34933cb9569f..e3de0b8625cd 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -2219,13 +2219,9 @@ bfa_nw_ioc_get_mac(struct bfa_ioc *ioc) static void bfa_ioc_recover(struct bfa_ioc *ioc) { - u16 bdf; - - bdf = (ioc->pcidev.pci_slot << 8 | ioc->pcidev.pci_func << 3 | - ioc->pcidev.device_id); - - pr_crit("Firmware heartbeat failure at %d", bdf); - BUG_ON(1); + pr_crit("Heart Beat of IOC has failed\n"); + bfa_ioc_stats(ioc, ioc_hbfails); + bfa_fsm_send_event(ioc, IOC_E_HBFAIL); } static void -- cgit v1.2.2 From 2d5d4154650459b61a8e7097d186a89d89dab8ed Mon Sep 17 00:00:00 2001 From: Ajit Khaparde Date: Wed, 6 Apr 2011 05:53:13 +0000 Subject: be2net: Fix a potential crash during shutdown. adapter could remain uninitialized if probe fails for some reason. A null pointer access could cause a crash if be_shutdown is called after that. Signed-off-by: Ajit Khaparde Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a71163f1e34b..6e8e211d8afe 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -3141,12 +3141,14 @@ static int be_resume(struct pci_dev *pdev) static void be_shutdown(struct pci_dev *pdev) { struct be_adapter *adapter = pci_get_drvdata(pdev); - struct net_device *netdev = adapter->netdev; - if (netif_running(netdev)) + if (!adapter) + return; + + if (netif_running(adapter->netdev)) cancel_delayed_work_sync(&adapter->work); - netif_device_detach(netdev); + netif_device_detach(adapter->netdev); be_cmd_reset_function(adapter); -- cgit v1.2.2 From ae07b0b221b6ab2edf9e3abd518aec6cd3f1ba66 Mon Sep 17 00:00:00 2001 From: Ulrich Weber Date: Wed, 6 Apr 2011 14:04:49 -0700 Subject: pppoe: drop PPPOX_ZOMBIEs in pppoe_flush_dev otherwise we loop forever if a PPPoE socket was set to PPPOX_ZOMBIE state by a PADT message when the ethernet device is going down afterwards. Signed-off-by: Ulrich Weber Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 78c0e3c9b2b5..71b1d8fbc301 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -317,7 +317,7 @@ static void pppoe_flush_dev(struct net_device *dev) lock_sock(sk); if (po->pppoe_dev == dev && - sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) { pppox_unbind_sock(sk); sk->sk_state = PPPOX_ZOMBIE; sk->sk_state_change(sk); -- cgit v1.2.2 From ecd6210765f93bd2c578d370d45bb49c710f3e89 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Sun, 3 Apr 2011 01:54:11 +0000 Subject: be2net: Rename some struct members for clarity Renamed msix_vec_idx to eq_idx in be_eq_obj struct. Renamed msix_vec_next_idx to eq_next_idx in be_adapter structure. These members are used in INTX mode also. Signed-off-by: Sarveswara Rao Mygapula Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 4 ++-- drivers/net/benet/be_main.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index f803c58b941d..66823eded7a3 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -154,7 +154,7 @@ struct be_eq_obj { u16 min_eqd; /* in usecs */ u16 max_eqd; /* in usecs */ u16 cur_eqd; /* in usecs */ - u8 msix_vec_idx; + u8 eq_idx; struct napi_struct napi; }; @@ -291,7 +291,7 @@ struct be_adapter { u32 num_rx_qs; u32 big_page_size; /* Compounded page size shared by rx wrbs */ - u8 msix_vec_next_idx; + u8 eq_next_idx; struct be_drv_stats drv_stats; struct vlan_group *vlan_grp; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 6e8e211d8afe..1a4808c6311f 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1497,7 +1497,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) goto tx_eq_free; - adapter->tx_eq.msix_vec_idx = adapter->msix_vec_next_idx++; + adapter->tx_eq.eq_idx = adapter->eq_next_idx++; /* Alloc TX eth compl queue */ @@ -1590,7 +1590,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) if (rc) goto err; - rxo->rx_eq.msix_vec_idx = adapter->msix_vec_next_idx++; + rxo->rx_eq.eq_idx = adapter->eq_next_idx++; /* CQ */ cq = &rxo->cq; @@ -1666,11 +1666,11 @@ static irqreturn_t be_intx(int irq, void *dev) if (!isr) return IRQ_NONE; - if ((1 << adapter->tx_eq.msix_vec_idx & isr)) + if ((1 << adapter->tx_eq.eq_idx & isr)) event_handle(adapter, &adapter->tx_eq); for_all_rx_queues(adapter, rxo, i) { - if ((1 << rxo->rx_eq.msix_vec_idx & isr)) + if ((1 << rxo->rx_eq.eq_idx & isr)) event_handle(adapter, &rxo->rx_eq); } } @@ -1951,7 +1951,7 @@ static void be_sriov_disable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, struct be_eq_obj *eq_obj) { - return adapter->msix_entries[eq_obj->msix_vec_idx].vector; + return adapter->msix_entries[eq_obj->eq_idx].vector; } static int be_request_irq(struct be_adapter *adapter, -- cgit v1.2.2 From 1f5db833758a9650ad002058e40760aaa11d732e Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Sun, 3 Apr 2011 01:54:39 +0000 Subject: be2net: Fix suspend/resume operation eq_next_idx is not getting reset to zero during suspend. This causes resume to fail. Added the fix. Signed-off-by: Sarveswara Rao Mygapula Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 1a4808c6311f..88d4c8038be4 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -2345,6 +2345,7 @@ static int be_clear(struct be_adapter *adapter) be_mcc_queues_destroy(adapter); be_rx_queues_destroy(adapter); be_tx_queues_destroy(adapter); + adapter->eq_next_idx = 0; if (be_physfn(adapter) && adapter->sriov_enabled) for (vf = 0; vf < num_vfs; vf++) -- cgit v1.2.2 From 8f74c0661c42104b3e3d2c032bc61efde15360ad Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Wed, 6 Apr 2011 15:31:22 -0700 Subject: Input: twl4030_keypad - avoid potential NULL-pointer dereference Signed-off-by: Shubhrajyoti D Acked-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/twl4030_keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 09bef79d9da1..cc06c4b2f920 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -338,7 +338,7 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) u8 reg; int error; - if (!pdata || !pdata->rows || !pdata->cols || + if (!pdata || !pdata->rows || !pdata->cols || !pdata->keymap_data || pdata->rows > TWL4030_MAX_ROWS || pdata->cols > TWL4030_MAX_COLS) { dev_err(&pdev->dev, "Invalid platform_data\n"); return -EINVAL; -- cgit v1.2.2 From 908433833cac977563e9bef8b206990d846876b4 Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Wed, 6 Apr 2011 15:33:16 -0700 Subject: Input: h3600_ts - fix error handling at connect In case of an error in h3600ts_connect(), deconstruct in correct order and with the right calls. Signed-off-by: Christoph Fritz Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/h3600_ts_input.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index efa06882de00..45f93d0f5592 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -399,31 +399,34 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv) IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n"); err = -EBUSY; - goto fail2; + goto fail1; } if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler, IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) { printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n"); err = -EBUSY; - goto fail3; + goto fail2; } serio_set_drvdata(serio, ts); err = serio_open(serio, drv); if (err) - return err; + goto fail3; //h3600_flite_control(1, 25); /* default brightness */ - input_register_device(ts->dev); + err = input_register_device(ts->dev); + if (err) + goto fail4; return 0; -fail3: free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); +fail4: serio_close(serio); +fail3: serio_set_drvdata(serio, NULL); + free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev); fail2: free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev); -fail1: serio_set_drvdata(serio, NULL); - input_free_device(input_dev); +fail1: input_free_device(input_dev); kfree(ts); return err; } -- cgit v1.2.2 From c996edcf1c451b81740abbcca5257ed7e353fcc6 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Wed, 6 Apr 2011 15:18:00 -0700 Subject: staging: hv: Fix GARP not sent after Quick Migration After Quick Migration, the network is not immediately operational in the current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, I added another netif_notify_peers() into a scheduled work, otherwise GARP packet will not be sent after quick migration, and cause network disconnection. Thanks to Mike Surcouf for reporting the bug and testing the patch. Reported-by: Mike Surcouf Tested-by: Mike Surcouf Signed-off-by: Haiyang Zhang Signed-off-by: Hank Janssen Signed-off-by: Abhishek Kane Signed-off-by: K. Y. Srinivasan Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/netvsc_drv.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/hv/netvsc_drv.c b/drivers/staging/hv/netvsc_drv.c index 2d40f5f86b24..33973568214f 100644 --- a/drivers/staging/hv/netvsc_drv.c +++ b/drivers/staging/hv/netvsc_drv.c @@ -46,6 +46,7 @@ struct net_device_context { /* point back to our device context */ struct hv_device *device_ctx; unsigned long avail; + struct work_struct work; }; @@ -219,6 +220,7 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj, unsigned int status) { struct net_device *net = dev_get_drvdata(&device_obj->device); + struct net_device_context *ndev_ctx; if (!net) { DPRINT_ERR(NETVSC_DRV, "got link status but net device " @@ -230,6 +232,8 @@ static void netvsc_linkstatus_callback(struct hv_device *device_obj, netif_carrier_on(net); netif_wake_queue(net); netif_notify_peers(net); + ndev_ctx = netdev_priv(net); + schedule_work(&ndev_ctx->work); } else { netif_carrier_off(net); netif_stop_queue(net); @@ -328,6 +332,25 @@ static const struct net_device_ops device_ops = { .ndo_set_mac_address = eth_mac_addr, }; +/* + * Send GARP packet to network peers after migrations. + * After Quick Migration, the network is not immediately operational in the + * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add + * another netif_notify_peers() into a scheduled work, otherwise GARP packet + * will not be sent after quick migration, and cause network disconnection. + */ +static void netvsc_send_garp(struct work_struct *w) +{ + struct net_device_context *ndev_ctx; + struct net_device *net; + + msleep(20); + ndev_ctx = container_of(w, struct net_device_context, work); + net = dev_get_drvdata(&ndev_ctx->device_ctx->device); + netif_notify_peers(net); +} + + static int netvsc_probe(struct device *device) { struct hv_driver *drv = @@ -353,6 +376,7 @@ static int netvsc_probe(struct device *device) net_device_ctx->device_ctx = device_obj; net_device_ctx->avail = ring_size; dev_set_drvdata(device, net); + INIT_WORK(&net_device_ctx->work, netvsc_send_garp); /* Notify the netvsc driver of the new device */ ret = net_drv_obj->base.dev_add(device_obj, &device_info); -- cgit v1.2.2 From 2f8c4c5494c2589e6cb9a62f399e61a1c4c2378d Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Tue, 5 Apr 2011 20:24:56 +0200 Subject: staging: usbip: fix shutdown problems. When shuting down the tcp_rx and tcp_tx threads first check if they are not closed already (maybe because an error caused them to return). Signed-off-by: Arjan Mels Cc: Takahiro Hirofuchi Cc: Max Vozeler Cc: Arnd Bergmann Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/stub_dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 8214c353d9f5..bce7d039346c 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -220,8 +220,10 @@ static void stub_shutdown_connection(struct usbip_device *ud) } /* 1. stop threads */ - kthread_stop(ud->tcp_rx); - kthread_stop(ud->tcp_tx); + if (ud->tcp_rx && !task_is_dead(ud->tcp_rx)) + kthread_stop(ud->tcp_rx); + if (ud->tcp_tx && !task_is_dead(ud->tcp_tx)) + kthread_stop(ud->tcp_tx); /* 2. close the socket */ /* -- cgit v1.2.2 From d2dd0b07c3e725d386d20294ec906f7ddef207fa Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Tue, 5 Apr 2011 20:26:11 +0200 Subject: staging: usbip: bugfixes related to kthread conversion When doing a usb port reset do a queued reset instead to prevent a deadlock: the reset will cause the driver to unbind, causing the usb_driver_lock_for_reset to stall. Signed-off-by: Arjan Mels Cc: Takahiro Hirofuchi Cc: Max Vozeler Cc: Arnd Bergmann Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/stub_rx.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index 6445f12cb4fd..51fbd0986475 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -171,33 +171,23 @@ static int tweak_set_configuration_cmd(struct urb *urb) static int tweak_reset_device_cmd(struct urb *urb) { - struct usb_ctrlrequest *req; - __u16 value; - __u16 index; - int ret; - - req = (struct usb_ctrlrequest *) urb->setup_packet; - value = le16_to_cpu(req->wValue); - index = le16_to_cpu(req->wIndex); - - usbip_uinfo("reset_device (port %d) to %s\n", index, - dev_name(&urb->dev->dev)); + struct stub_priv *priv = (struct stub_priv *) urb->context; + struct stub_device *sdev = priv->sdev; - /* all interfaces should be owned by usbip driver, so just reset it. */ - ret = usb_lock_device_for_reset(urb->dev, NULL); - if (ret < 0) { - dev_err(&urb->dev->dev, "lock for reset\n"); - return ret; - } - - /* try to reset the device */ - ret = usb_reset_device(urb->dev); - if (ret < 0) - dev_err(&urb->dev->dev, "device reset\n"); + usbip_uinfo("reset_device %s\n", dev_name(&urb->dev->dev)); - usb_unlock_device(urb->dev); - - return ret; + /* + * usb_lock_device_for_reset caused a deadlock: it causes the driver + * to unbind. In the shutdown the rx thread is signalled to shut down + * but this thread is pending in the usb_lock_device_for_reset. + * + * Instead queue the reset. + * + * Unfortunatly an existing usbip connection will be dropped due to + * driver unbinding. + */ + usb_queue_reset_device(sdev->interface); + return 0; } /* -- cgit v1.2.2 From 1325f85fa49f57df034869de430f7c302ae23109 Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Tue, 5 Apr 2011 20:26:38 +0200 Subject: staging: usbip: bugfix add number of packets for isochronous frames The number_of_packets was not transmitted for RET_SUBMIT packets. The linux client used the stored number_of_packet from the submitted request. The windows userland client does not do this however and needs to know the number_of_packets to determine the size of the transmission. Signed-off-by: Arjan Mels Cc: Takahiro Hirofuchi Cc: Max Vozeler Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/usbip_common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 337abc48f714..85622153ea7c 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -333,10 +333,11 @@ void usbip_dump_header(struct usbip_header *pdu) usbip_udbg("CMD_UNLINK: seq %u\n", pdu->u.cmd_unlink.seqnum); break; case USBIP_RET_SUBMIT: - usbip_udbg("RET_SUBMIT: st %d al %u sf %d ec %d\n", + usbip_udbg("RET_SUBMIT: st %d al %u sf %d #p %d ec %d\n", pdu->u.ret_submit.status, pdu->u.ret_submit.actual_length, pdu->u.ret_submit.start_frame, + pdu->u.ret_submit.number_of_packets, pdu->u.ret_submit.error_count); case USBIP_RET_UNLINK: usbip_udbg("RET_UNLINK: status %d\n", pdu->u.ret_unlink.status); @@ -520,6 +521,7 @@ static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb, rpdu->status = urb->status; rpdu->actual_length = urb->actual_length; rpdu->start_frame = urb->start_frame; + rpdu->number_of_packets = urb->number_of_packets; rpdu->error_count = urb->error_count; } else { /* vhci_rx.c */ @@ -527,6 +529,7 @@ static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb, urb->status = rpdu->status; urb->actual_length = rpdu->actual_length; urb->start_frame = rpdu->start_frame; + urb->number_of_packets = rpdu->number_of_packets; urb->error_count = rpdu->error_count; } } @@ -595,11 +598,13 @@ static void correct_endian_ret_submit(struct usbip_header_ret_submit *pdu, cpu_to_be32s(&pdu->status); cpu_to_be32s(&pdu->actual_length); cpu_to_be32s(&pdu->start_frame); + cpu_to_be32s(&pdu->number_of_packets); cpu_to_be32s(&pdu->error_count); } else { be32_to_cpus(&pdu->status); be32_to_cpus(&pdu->actual_length); be32_to_cpus(&pdu->start_frame); + cpu_to_be32s(&pdu->number_of_packets); be32_to_cpus(&pdu->error_count); } } -- cgit v1.2.2 From 28276a28d8b3cd19f4449991faad4945fe557656 Mon Sep 17 00:00:00 2001 From: Arjan Mels Date: Tue, 5 Apr 2011 20:26:59 +0200 Subject: staging: usbip: bugfix for isochronous packets and optimization For isochronous packets the actual_length is the sum of the actual length of each of the packets, however between the packets might be padding, so it is not sufficient to just send the first actual_length bytes of the buffer. To fix this and simultanesouly optimize the bandwidth the content of the isochronous packets are send without the padding, the padding is restored on the receiving end. Signed-off-by: Arjan Mels Cc: Takahiro Hirofuchi Cc: Max Vozeler Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/stub_tx.c | 74 +++++++++++++++++++++++++++++------- drivers/staging/usbip/usbip_common.c | 57 +++++++++++++++++++++++++++ drivers/staging/usbip/usbip_common.h | 2 + drivers/staging/usbip/vhci_rx.c | 3 ++ 4 files changed, 122 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c index 5523f25998e6..64a52b26dcf6 100644 --- a/drivers/staging/usbip/stub_tx.c +++ b/drivers/staging/usbip/stub_tx.c @@ -170,7 +170,6 @@ static int stub_send_ret_submit(struct stub_device *sdev) struct stub_priv *priv, *tmp; struct msghdr msg; - struct kvec iov[3]; size_t txsize; size_t total_size = 0; @@ -180,28 +179,73 @@ static int stub_send_ret_submit(struct stub_device *sdev) struct urb *urb = priv->urb; struct usbip_header pdu_header; void *iso_buffer = NULL; + struct kvec *iov = NULL; + int iovnum = 0; txsize = 0; memset(&pdu_header, 0, sizeof(pdu_header)); memset(&msg, 0, sizeof(msg)); - memset(&iov, 0, sizeof(iov)); - usbip_dbg_stub_tx("setup txdata urb %p\n", urb); + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + iovnum = 2 + urb->number_of_packets; + else + iovnum = 2; + + iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL); + if (!iov) { + usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC); + return -1; + } + + iovnum = 0; /* 1. setup usbip_header */ setup_ret_submit_pdu(&pdu_header, urb); + usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", + pdu_header.base.seqnum, urb); + /*usbip_dump_header(pdu_header);*/ usbip_header_correct_endian(&pdu_header, 1); - iov[0].iov_base = &pdu_header; - iov[0].iov_len = sizeof(pdu_header); + iov[iovnum].iov_base = &pdu_header; + iov[iovnum].iov_len = sizeof(pdu_header); + iovnum++; txsize += sizeof(pdu_header); /* 2. setup transfer buffer */ - if (usb_pipein(urb->pipe) && urb->actual_length > 0) { - iov[1].iov_base = urb->transfer_buffer; - iov[1].iov_len = urb->actual_length; + if (usb_pipein(urb->pipe) && + usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS && + urb->actual_length > 0) { + iov[iovnum].iov_base = urb->transfer_buffer; + iov[iovnum].iov_len = urb->actual_length; + iovnum++; txsize += urb->actual_length; + } else if (usb_pipein(urb->pipe) && + usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + /* + * For isochronous packets: actual length is the sum of + * the actual length of the individual, packets, but as + * the packet offsets are not changed there will be + * padding between the packets. To optimally use the + * bandwidth the padding is not transmitted. + */ + + int i; + for (i = 0; i < urb->number_of_packets; i++) { + iov[iovnum].iov_base = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + iov[iovnum].iov_len = urb->iso_frame_desc[i].actual_length; + iovnum++; + txsize += urb->iso_frame_desc[i].actual_length; + } + + if (txsize != sizeof(pdu_header) + urb->actual_length) { + dev_err(&sdev->interface->dev, + "actual length of urb (%d) does not match iso packet sizes (%d)\n", + urb->actual_length, txsize-sizeof(pdu_header)); + kfree(iov); + usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); + return -1; + } } /* 3. setup iso_packet_descriptor */ @@ -212,32 +256,34 @@ static int stub_send_ret_submit(struct stub_device *sdev) if (!iso_buffer) { usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC); + kfree(iov); return -1; } - iov[2].iov_base = iso_buffer; - iov[2].iov_len = len; + iov[iovnum].iov_base = iso_buffer; + iov[iovnum].iov_len = len; txsize += len; + iovnum++; } - ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, - 3, txsize); + ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, + iov, iovnum, txsize); if (ret != txsize) { dev_err(&sdev->interface->dev, "sendmsg failed!, retval %d for %zd\n", ret, txsize); + kfree(iov); kfree(iso_buffer); usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); return -1; } + kfree(iov); kfree(iso_buffer); - usbip_dbg_stub_tx("send txdata\n"); total_size += txsize; } - spin_lock_irqsave(&sdev->priv_lock, flags); list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 85622153ea7c..7b1fe45bf7dd 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -730,6 +730,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) int size = np * sizeof(*iso); int i; int ret; + int total_length = 0; if (!usb_pipeisoc(urb->pipe)) return 0; @@ -759,19 +760,75 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) return -EPIPE; } + for (i = 0; i < np; i++) { iso = buff + (i * sizeof(*iso)); usbip_iso_pakcet_correct_endian(iso, 0); usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0); + total_length += urb->iso_frame_desc[i].actual_length; } kfree(buff); + if (total_length != urb->actual_length) { + dev_err(&urb->dev->dev, + "total length of iso packets (%d) not equal to actual length of buffer (%d)\n", + total_length, urb->actual_length); + + if (ud->side == USBIP_STUB) + usbip_event_add(ud, SDEV_EVENT_ERROR_TCP); + else + usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); + + return -EPIPE; + } + return ret; } EXPORT_SYMBOL_GPL(usbip_recv_iso); +/* + * This functions restores the padding which was removed for optimizing + * the bandwidth during transfer over tcp/ip + * + * buffer and iso packets need to be stored and be in propeper endian in urb + * before calling this function + */ +int usbip_pad_iso(struct usbip_device *ud, struct urb *urb) +{ + int np = urb->number_of_packets; + int i; + int ret; + int actualoffset = urb->actual_length; + + if (!usb_pipeisoc(urb->pipe)) + return 0; + + /* if no packets or length of data is 0, then nothing to unpack */ + if (np == 0 || urb->actual_length == 0) + return 0; + + /* + * if actual_length is transfer_buffer_length then no padding is + * present. + */ + if (urb->actual_length == urb->transfer_buffer_length) + return 0; + + /* + * loop over all packets from last to first (to prevent overwritting + * memory when padding) and move them into the proper place + */ + for (i = np-1; i > 0; i--) { + actualoffset -= urb->iso_frame_desc[i].actual_length; + memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->transfer_buffer + actualoffset, + urb->iso_frame_desc[i].actual_length); + } + return ret; +} +EXPORT_SYMBOL_GPL(usbip_pad_iso); /* some members of urb must be substituted before. */ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h index 9f809c315d92..c767f52be5fb 100644 --- a/drivers/staging/usbip/usbip_common.h +++ b/drivers/staging/usbip/usbip_common.h @@ -379,6 +379,8 @@ void usbip_header_correct_endian(struct usbip_header *pdu, int send); int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb); /* some members of urb must be substituted before. */ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb); +/* some members of urb must be substituted before. */ +int usbip_pad_iso(struct usbip_device *ud, struct urb *urb); void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen); diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index 09bf2355934b..2ffc96a4c0d4 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c @@ -100,6 +100,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, if (usbip_recv_iso(ud, urb) < 0) return; + /* restore the padding in iso packets */ + if (usbip_pad_iso(ud, urb) < 0) + return; if (usbip_dbg_flag_vhci_rx) usbip_dump_urb(urb); -- cgit v1.2.2 From 67c1b8c6aa354aad14aad85d36508fd73d1c6361 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 7 Apr 2011 09:39:44 +0800 Subject: RTC: rtc-mrst: follow on to the change of rtc_device_register() commit f44f7f96a20 (RTC: Initialize kernel state from RTC) will call rtc_read_alarm() inside rtc_device_register(), so rtc-mrst driver need to call dev_set_drvdata() before rtc_device_register() get called. Cc: Alessandro Zummo Cc: John Stultz Cc: Thomas Gleixner Signed-off-by: Feng Tang Signed-off-by: John Stultz --- drivers/rtc/rtc-mrst.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index b86bc328463b..d2c397c369fc 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -342,6 +342,8 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) mrst_rtc.irq = rtc_irq; mrst_rtc.iomem = iomem; + mrst_rtc.dev = dev; + dev_set_drvdata(dev, &mrst_rtc); mrst_rtc.rtc = rtc_device_register(driver_name, dev, &mrst_rtc_ops, THIS_MODULE); @@ -350,8 +352,6 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) goto cleanup0; } - mrst_rtc.dev = dev; - dev_set_drvdata(dev, &mrst_rtc); rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); @@ -376,9 +376,10 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) return 0; cleanup1: - mrst_rtc.dev = NULL; rtc_device_unregister(mrst_rtc.rtc); cleanup0: + dev_set_drvdata(dev, NULL); + mrst_rtc.dev = NULL; release_region(iomem->start, iomem->end + 1 - iomem->start); dev_err(dev, "rtc-mrst: unable to initialise\n"); return retval; -- cgit v1.2.2 From de97a21a23dda34f1754a748560dede139e6bfc2 Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 7 Apr 2011 09:39:44 +0800 Subject: rtc, x86/mrst/vrtc: Fix boot crash in rtc_read_alarm() Commit f44f7f96a20 ("RTC: Initialize kernel state from RTC") caused a boot regression on the MRST platform. The reason is that rtc_device_register() calls rtc_read_alarm() after that change, which function does not have all driver data set up yet. The rtc-mrst driver needs to call dev_set_drvdata() before rtc_device_register() gets called. Signed-off-by: Feng Tang Signed-off-by: Alan Cox Acked-by: John Stultz Cc: Alessandro Zummo Cc: Linus Torvalds Link: http://lkml.kernel.org/r/1302140384-27571-1-git-send-email-feng.tang@intel.com Signed-off-by: Ingo Molnar --- drivers/rtc/rtc-mrst.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index 332a2c4a891c..b2f096871a97 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -342,6 +342,8 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) mrst_rtc.irq = rtc_irq; mrst_rtc.iomem = iomem; + mrst_rtc.dev = dev; + dev_set_drvdata(dev, &mrst_rtc); mrst_rtc.rtc = rtc_device_register(driver_name, dev, &mrst_rtc_ops, THIS_MODULE); @@ -350,8 +352,6 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) goto cleanup0; } - mrst_rtc.dev = dev; - dev_set_drvdata(dev, &mrst_rtc); rename_region(iomem, dev_name(&mrst_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); @@ -376,9 +376,10 @@ vrtc_mrst_do_probe(struct device *dev, struct resource *iomem, int rtc_irq) return 0; cleanup1: - mrst_rtc.dev = NULL; rtc_device_unregister(mrst_rtc.rtc); cleanup0: + dev_set_drvdata(dev, NULL); + mrst_rtc.dev = NULL; release_region(iomem->start, iomem->end + 1 - iomem->start); dev_err(dev, "rtc-mrst: unable to initialise\n"); return retval; -- cgit v1.2.2 From 7e3bf1d3308934bc1b8ca492f473e0e22a95da7e Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Wed, 6 Apr 2011 14:35:12 +0800 Subject: fix build fail for hv_mouse indefine udelay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix build failure issue for hv_mouse When build 2.6.39-rc1 kernel, it will be blocked at build hv_mouse. drivers/staging/hv/hv_mouse.c: In function ‘ReleaseInputDevice’: drivers/staging/hv/hv_mouse.c:293: error: implicit declaration of function ‘udelay’ Signed-off-by: Youquan Song Signed-off-by: Linus Torvalds --- drivers/staging/hv/hv_mouse.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/hv/hv_mouse.c b/drivers/staging/hv/hv_mouse.c index 50147f84741c..9c6d4d24f889 100644 --- a/drivers/staging/hv/hv_mouse.c +++ b/drivers/staging/hv/hv_mouse.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "hv_api.h" #include "logging.h" -- cgit v1.2.2 From 850a28ecd8044ef36b2c7699d2e3736a410b4d0a Mon Sep 17 00:00:00 2001 From: Vasily Khoruzhick Date: Wed, 6 Apr 2011 17:49:15 +0300 Subject: spi: Fix race condition in stop_queue() There's a race condition in stop_queue() in some drivers - if drv_data->queue is empty, but drv_data->busy is still set (or opposite situation) stop_queue will return -EBUSY. So fix loop condition to check that both drv_data->queue is empty and drv_data->busy is not set. This patch affects following drivers: pxa2xx_spi spi_bfin5xx amba-pl022 dw_spi Signed-off-by: Vasily Khoruzhick Acked-by: Eric Miao Acked-by: Mike Frysinger Signed-off-by: Grant Likely --- drivers/spi/amba-pl022.c | 2 +- drivers/spi/dw_spi.c | 2 +- drivers/spi/pxa2xx_spi.c | 2 +- drivers/spi/spi_bfin5xx.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c index 5a4e0afb9ad6..4b8357b728cb 100644 --- a/drivers/spi/amba-pl022.c +++ b/drivers/spi/amba-pl022.c @@ -1555,7 +1555,7 @@ static int stop_queue(struct pl022 *pl022) * A wait_queue on the pl022->busy could be used, but then the common * execution path (pump_messages) would be required to call wake_up or * friends on every SPI message. Do this instead */ - while (!list_empty(&pl022->queue) && pl022->busy && limit--) { + while ((!list_empty(&pl022->queue) || pl022->busy) && limit--) { spin_unlock_irqrestore(&pl022->queue_lock, flags); msleep(10); spin_lock_irqsave(&pl022->queue_lock, flags); diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 9a6196461b27..d040debc07c2 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -821,7 +821,7 @@ static int stop_queue(struct dw_spi *dws) spin_lock_irqsave(&dws->lock, flags); dws->run = QUEUE_STOPPED; - while (!list_empty(&dws->queue) && dws->busy && limit--) { + while ((!list_empty(&dws->queue) || dws->busy) && limit--) { spin_unlock_irqrestore(&dws->lock, flags); msleep(10); spin_lock_irqsave(&dws->lock, flags); diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index a429b01d0285..3aa782067b68 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1493,7 +1493,7 @@ static int stop_queue(struct driver_data *drv_data) * execution path (pump_messages) would be required to call wake_up or * friends on every SPI message. Do this instead */ drv_data->run = QUEUE_STOPPED; - while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { spin_unlock_irqrestore(&drv_data->lock, flags); msleep(10); spin_lock_irqsave(&drv_data->lock, flags); diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index a28462486df8..f3a1c52c0fb0 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1284,7 +1284,7 @@ static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data) * friends on every SPI message. Do this instead */ drv_data->running = false; - while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) { + while ((!list_empty(&drv_data->queue) || drv_data->busy) && limit--) { spin_unlock_irqrestore(&drv_data->lock, flags); msleep(10); spin_lock_irqsave(&drv_data->lock, flags); -- cgit v1.2.2 From 2845fd858c55c8a05674a071384a12a19cc17dbf Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 5 Apr 2011 08:55:05 -0700 Subject: iwlagn: override 5300 EEPROM # of chains At least EEPROM version 0x11A has the wrong number of chains programmed into it for some reason, so we need to override in the driver. Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-5000.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 3ea31b659d1a..22e045b5bcee 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -530,6 +530,9 @@ static struct iwl_ht_params iwl5000_ht_params = { struct iwl_cfg iwl5300_agn_cfg = { .name = "Intel(R) Ultimate N WiFi Link 5300 AGN", IWL_DEVICE_5000, + /* at least EEPROM 0x11A has wrong info */ + .valid_tx_ant = ANT_ABC, /* .cfg overwrite */ + .valid_rx_ant = ANT_ABC, /* .cfg overwrite */ .ht_params = &iwl5000_ht_params, }; -- cgit v1.2.2 From bf3ca7f752d8f5009c9a83db56035566f3e313de Mon Sep 17 00:00:00 2001 From: Brian Cavagnolo Date: Wed, 6 Apr 2011 14:18:46 +0530 Subject: mwl8k: do not free unrequested irq When the mwl8k driver attempts and fails to switch from sta to ap firmware (or vice-versa) in the mwl8k_add_interface routine, the mwl8k_stop routine will be called. This routine must not attempt to free the irq if it was not requested. Signed-off-by: Brian Cavagnolo Signed-off-by: Nishant Sarmukadam Signed-off-by: John W. Linville --- drivers/net/wireless/mwl8k.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 36952274950e..c1ceb4b23971 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -137,6 +137,7 @@ struct mwl8k_tx_queue { struct mwl8k_priv { struct ieee80211_hw *hw; struct pci_dev *pdev; + int irq; struct mwl8k_device_info *device_info; @@ -3761,9 +3762,11 @@ static int mwl8k_start(struct ieee80211_hw *hw) rc = request_irq(priv->pdev->irq, mwl8k_interrupt, IRQF_SHARED, MWL8K_NAME, hw); if (rc) { + priv->irq = -1; wiphy_err(hw->wiphy, "failed to register IRQ handler\n"); return -EIO; } + priv->irq = priv->pdev->irq; /* Enable TX reclaim and RX tasklets. */ tasklet_enable(&priv->poll_tx_task); @@ -3800,6 +3803,7 @@ static int mwl8k_start(struct ieee80211_hw *hw) if (rc) { iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); free_irq(priv->pdev->irq, hw); + priv->irq = -1; tasklet_disable(&priv->poll_tx_task); tasklet_disable(&priv->poll_rx_task); } @@ -3818,7 +3822,10 @@ static void mwl8k_stop(struct ieee80211_hw *hw) /* Disable interrupts */ iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK); - free_irq(priv->pdev->irq, hw); + if (priv->irq != -1) { + free_irq(priv->pdev->irq, hw); + priv->irq = -1; + } /* Stop finalize join worker */ cancel_work_sync(&priv->finalize_join_worker); -- cgit v1.2.2 From bd39a274fb7b43374c797bafdb7f506598f36f77 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 6 Apr 2011 20:40:31 +0200 Subject: ath: add missing regdomain pair 0x5c mapping Joe Culler reported a problem with his AR9170 device: > ath: EEPROM regdomain: 0x5c > ath: EEPROM indicates we should expect a direct regpair map > ath: invalid regulatory domain/country code 0x5c > ath: Invalid EEPROM contents It turned out that the regdomain 'APL7_FCCA' was not mapped yet. According to Luis R. Rodriguez [Atheros' engineer] APL7 maps to FCC_CTL and FCCA maps to FCC_CTL as well, so the attached patch should be correct. Cc: Reported-by: Joe Culler Acked-by: Luis R. Rodriguez Signed-off-by: Christian Lamparter Signed-off-by: John W. Linville --- drivers/net/wireless/ath/regd_common.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 248c670fdfbe..5c2cfe694152 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -195,6 +195,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = { {APL9_WORLD, CTL_ETSI, CTL_ETSI}, {APL3_FCCA, CTL_FCC, CTL_FCC}, + {APL7_FCCA, CTL_FCC, CTL_FCC}, {APL1_ETSIC, CTL_FCC, CTL_ETSI}, {APL2_ETSIC, CTL_FCC, CTL_ETSI}, {APL2_APLD, CTL_FCC, NO_CTL}, -- cgit v1.2.2 From d856b418464024dba4c7e901bab74dfb9a030d2e Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 30 Mar 2011 15:48:22 +0200 Subject: watchdog: mpc8xxx_wdt: fix build Since 1c48a5c93da6313 (dt: Eliminate of_platform_{,un}register_driver) mpc8xxx_wdt no longer builds as it tries to refer to a 'match' variable rather than ofdev->dev.of_match that it checks just before. Signed-off-by: Peter Korsgaard Acked-by: Grant Likely Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 6709d723e017..528bceb220fd 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -195,7 +195,7 @@ static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev) if (!ofdev->dev.of_match) return -EINVAL; - wdt_type = match->data; + wdt_type = ofdev->dev.of_match->data; if (!freq || freq == -1) return -EINVAL; -- cgit v1.2.2 From ab6dc30da55d262c54ae12e47e4a2e4372e39fbf Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 6 Apr 2011 23:24:42 +0000 Subject: mlx4: Sensing link type at device initialization When bringing the port up, performing a SENSE_PORT command To try and check to which physical link type (IB or Ethernet) the physical port is connected. In case there is no valid link partner, the port will come up as its supported default. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/main.c | 5 +++++ drivers/net/mlx4/mlx4.h | 2 ++ drivers/net/mlx4/sense.c | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 62fa7eec5f0c..3814fc9b1145 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -944,6 +944,10 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) } for (port = 1; port <= dev->caps.num_ports; port++) { + enum mlx4_port_type port_type = 0; + mlx4_SENSE_PORT(dev, port, &port_type); + if (port_type) + dev->caps.port_type[port] = port_type; ib_port_default_caps = 0; err = mlx4_get_port_ib_caps(dev, port, &ib_port_default_caps); if (err) @@ -958,6 +962,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) goto err_mcg_table_free; } } + mlx4_set_port_mask(dev); return 0; diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index c1e0e5f1bcdb..dd7d745fbab4 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -431,6 +431,8 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); void mlx4_handle_catas_err(struct mlx4_dev *dev); +int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, + enum mlx4_port_type *type); void mlx4_do_sense_ports(struct mlx4_dev *dev, enum mlx4_port_type *stype, enum mlx4_port_type *defaults); diff --git a/drivers/net/mlx4/sense.c b/drivers/net/mlx4/sense.c index 015fbe785c13..e2337a7411d9 100644 --- a/drivers/net/mlx4/sense.c +++ b/drivers/net/mlx4/sense.c @@ -38,8 +38,8 @@ #include "mlx4.h" -static int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, - enum mlx4_port_type *type) +int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, + enum mlx4_port_type *type) { u64 out_param; int err = 0; -- cgit v1.2.2 From 60b1809f7e2ea2620aa548e1c866066756bdd1d2 Mon Sep 17 00:00:00 2001 From: Yevgeny Petrilin Date: Wed, 6 Apr 2011 23:25:45 +0000 Subject: mlx4_en: Restoring RX buffer pointer in case of failure If not done, second attempt to open the RX ring would cause memory corruption. Signed-off-by: Yevgeny Petrilin Signed-off-by: David S. Miller --- drivers/net/mlx4/en_rx.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 05998ee297c9..98d4ce04f86f 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -345,6 +345,8 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) err = mlx4_en_init_allocator(priv, ring); if (err) { en_err(priv, "Failed initializing ring allocator\n"); + if (ring->stride <= TXBB_SIZE) + ring->buf -= TXBB_SIZE; ring_ind--; goto err_allocator; } @@ -369,6 +371,8 @@ err_buffers: ring_ind = priv->rx_ring_num - 1; err_allocator: while (ring_ind >= 0) { + if (priv->rx_ring[ring_ind].stride <= TXBB_SIZE) + priv->rx_ring[ring_ind].buf -= TXBB_SIZE; mlx4_en_destroy_allocator(priv, &priv->rx_ring[ring_ind]); ring_ind--; } -- cgit v1.2.2 From 96f372c95d32f76fa2b0e035e0a6269234bfda09 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 7 Apr 2011 19:07:17 +0200 Subject: ath9k: fix missing ath9k_ps_wakeup/ath9k_ps_restore calls These missing chip wakeups mainly cause crashes on AR5416 cards in MIPS boards, but have also been reported to cause radio stability issues on AR9285. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index dddb85de622d..17d04ff8d678 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1376,7 +1376,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_calculate_iter_data(hw, vif, &iter_data); - ath9k_ps_wakeup(sc); /* Set BSSID mask. */ memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); @@ -1411,7 +1410,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, } ath9k_hw_set_interrupts(ah, ah->imask); - ath9k_ps_restore(sc); /* Set up ANI */ if ((iter_data.naps + iter_data.nadhocs) > 0) { @@ -1457,6 +1455,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, struct ath_vif *avp = (void *)vif->drv_priv; int ret = 0; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); switch (vif->type) { @@ -1503,6 +1502,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, ath9k_do_vif_add_setup(hw, vif); out: mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return ret; } @@ -1517,6 +1517,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Change Interface\n"); mutex_lock(&sc->mutex); + ath9k_ps_wakeup(sc); /* See if new interface type is valid. */ if ((new_type == NL80211_IFTYPE_ADHOC) && @@ -1546,6 +1547,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, ath9k_do_vif_add_setup(hw, vif); out: + ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); return ret; } @@ -1558,6 +1560,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath_dbg(common, ATH_DBG_CONFIG, "Detach Interface\n"); + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); sc->nvifs--; @@ -1569,6 +1572,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, ath9k_calculate_summary_state(hw, NULL); mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); } static void ath9k_enable_ps(struct ath_softc *sc) @@ -1809,6 +1813,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, txq = sc->tx.txq_map[queue]; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); memset(&qi, 0, sizeof(struct ath9k_tx_queue_info)); @@ -1832,6 +1837,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, ath_beaconq_config(sc); mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return ret; } @@ -1894,6 +1900,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, int slottime; int error; + ath9k_ps_wakeup(sc); mutex_lock(&sc->mutex); if (changed & BSS_CHANGED_BSSID) { @@ -1994,6 +2001,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); } static u64 ath9k_get_tsf(struct ieee80211_hw *hw) -- cgit v1.2.2 From a6756da9eace8b4af73e9dea43f1fc2889224c94 Mon Sep 17 00:00:00 2001 From: Jason Conti Date: Thu, 7 Apr 2011 21:09:57 +0200 Subject: p54: Initialize extra_len in p54_tx_80211 This patch fixes a very serious off-by-one bug in the driver, which could leave the device in an unresponsive state. The problem was that the extra_len variable [used to reserve extra scratch buffer space for the firmware] was left uninitialized. Because p54_assign_address later needs the value to reserve additional space, the resulting frame could be to big for the small device's memory window and everything would immediately come to a grinding halt. Reference: https://bugs.launchpad.net/bugs/722185 Cc: Acked-by: Christian Lamparter Signed-off-by: Jason Conti Signed-off-by: John W. Linville --- drivers/net/wireless/p54/txrx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 7834c26c2954..042842e704de 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -703,7 +703,7 @@ void p54_tx_80211(struct ieee80211_hw *dev, struct sk_buff *skb) struct p54_tx_info *p54info; struct p54_hdr *hdr; struct p54_tx_data *txhdr; - unsigned int padding, len, extra_len; + unsigned int padding, len, extra_len = 0; int i, j, ridx; u16 hdr_flags = 0, aid = 0; u8 rate, queue = 0, crypt_offset = 0; -- cgit v1.2.2 From 0a0883c8433c743dad0a4d9ebe2717558f2c209e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 5 Apr 2011 17:57:23 +1000 Subject: i915: restore only the mode of this driver on lastclose This has always used a big hammer, but that hammer is probably too big, I'm also not sure its necessary but at least this should be safe. Should fix: https://bugzilla.kernel.org/show_bug.cgi?id=23592 Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fb.c | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 72730377a01b..12876f2795d2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_fb_helper_restore(); + intel_fb_restore_mode(dev); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f5b0d8306d83..1d20712d527f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,4 +338,5 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); +extern void intel_fb_restore_mode(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 512782728e51..96a45c4e9a16 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -264,3 +264,19 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } + +void intel_fb_restore_mode(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + int ret, i; + + if (!dev_priv->fbdev) + return; + + for (i = 0; i < dev_priv->fbdev->helper.crtc_count; i++) { + struct drm_mode_set *mode_set = &dev_priv->fbdev->helper.crtc_info[i].mode_set; + ret = drm_crtc_helper_set_config(mode_set); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); + } +} -- cgit v1.2.2 From dc66b325f161bb651493c7d96ad44876b629cf6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 7 Apr 2011 16:17:47 +0200 Subject: radeon: Fix KMS CP writeback on big endian machines. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is necessary even with PCI(e) GART, and it makes writeback work even with AGP on my PowerBook. Might still be unreliable with older revisions of UniNorth and other AGP bridges though. Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_fence.c | 2 +- drivers/gpu/drm/radeon/radeon_ring.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 9e59868d354e..bbcd1dd7bac0 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -79,7 +79,7 @@ static bool radeon_fence_poll_locked(struct radeon_device *rdev) scratch_index = R600_WB_EVENT_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; else scratch_index = RADEON_WB_SCRATCH_OFFSET + rdev->fence_drv.scratch_reg - rdev->scratch.reg_base; - seq = rdev->wb.wb[scratch_index/4]; + seq = le32_to_cpu(rdev->wb.wb[scratch_index/4]); } else seq = RREG32(rdev->fence_drv.scratch_reg); if (seq != rdev->fence_drv.last_seq) { diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index bbc9cd823334..c6776e48fdde 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -248,7 +248,7 @@ void radeon_ib_pool_fini(struct radeon_device *rdev) void radeon_ring_free_size(struct radeon_device *rdev) { if (rdev->wb.enabled) - rdev->cp.rptr = rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4]; + rdev->cp.rptr = le32_to_cpu(rdev->wb.wb[RADEON_WB_CP_RPTR_OFFSET/4]); else { if (rdev->family >= CHIP_R600) rdev->cp.rptr = RREG32(R600_CP_RB_RPTR); -- cgit v1.2.2 From 88a2b75cceba1fdbc1fdb70c7c8cd2b40da3d95d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 7 Apr 2011 16:20:49 +0200 Subject: drm/radeon: Fix KMS legacy backlight support if CONFIG_BACKLIGHT_CLASS_DEVICE=m. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michel Dänzer Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_legacy_encoders.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 5b54268ed6b2..2f46e0c8df53 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -269,7 +269,7 @@ static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = { .disable = radeon_legacy_encoder_disable, }; -#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) #define MAX_RADEON_LEVEL 0xFF -- cgit v1.2.2 From 9bb09fa1b5b07459279301ac6220d575f307597b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 7 Apr 2011 10:31:25 -0400 Subject: drm/radeon/kms: pll tweaks for rv6xx Prefer minm over maxp. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=35994 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index b41ec59c7100..9d516a8c4dfa 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -531,6 +531,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, pll->flags |= RADEON_PLL_PREFER_HIGH_FB_DIV; else pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; + + if ((rdev->family == CHIP_R600) || + (rdev->family == CHIP_RV610) || + (rdev->family == CHIP_RV630) || + (rdev->family == CHIP_RV670)) + pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; } else { pll->flags |= RADEON_PLL_LEGACY; -- cgit v1.2.2 From d4864d604a8d29a0d6a13a8d882be6e21c498c22 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 6 Apr 2011 13:44:10 -0400 Subject: drm/radeon/kms: make radeon i2c put/get bytes less noisy Switch some errors to debug output. These are generally harmless and tend to confuse users. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index ded2a45bc95c..ccbabf734a61 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1062,7 +1062,7 @@ void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus, *val = in_buf[0]; DRM_DEBUG("val = 0x%02x\n", *val); } else { - DRM_ERROR("i2c 0x%02x 0x%02x read failed\n", + DRM_DEBUG("i2c 0x%02x 0x%02x read failed\n", addr, *val); } } @@ -1084,7 +1084,7 @@ void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c_bus, out_buf[1] = val; if (i2c_transfer(&i2c_bus->adapter, &msg, 1) != 1) - DRM_ERROR("i2c 0x%02x 0x%02x write failed\n", + DRM_DEBUG("i2c 0x%02x 0x%02x write failed\n", addr, val); } -- cgit v1.2.2 From 88edaa415966af965bb7eb7056d8b58145462c8e Mon Sep 17 00:00:00 2001 From: Steve Glendinning Date: Sun, 10 Apr 2011 18:59:27 -0700 Subject: net: Add support for SMSC LAN9530, LAN9730 and LAN89530 This patch adds support for SMSC's LAN9530, LAN9730 and LAN89530 USB ethernet controllers to the existing smsc95xx driver by adding their new USB VID/PID pairs. Signed-off-by: Steve Glendinning Signed-off-by: David S. Miller --- drivers/net/usb/smsc95xx.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 727874d9deb6..47a6c870b51f 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1313,6 +1313,21 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0424, 0x9909), .driver_info = (unsigned long) &smsc95xx_info, }, + { + /* SMSC LAN9530 USB Ethernet Device */ + USB_DEVICE(0x0424, 0x9530), + .driver_info = (unsigned long) &smsc95xx_info, + }, + { + /* SMSC LAN9730 USB Ethernet Device */ + USB_DEVICE(0x0424, 0x9730), + .driver_info = (unsigned long) &smsc95xx_info, + }, + { + /* SMSC LAN89530 USB Ethernet Device */ + USB_DEVICE(0x0424, 0x9E08), + .driver_info = (unsigned long) &smsc95xx_info, + }, { }, /* END */ }; MODULE_DEVICE_TABLE(usb, products); -- cgit v1.2.2 From 8faa7cf828bca1745a4ed599876567f5afc47544 Mon Sep 17 00:00:00 2001 From: "Ira W. Snyder" Date: Thu, 7 Apr 2011 10:33:03 -0700 Subject: dt/fsldma: fix build warning caused by of_platform_device changes Commit 000061245a6797d542854106463b6b20fbdcb12e, "dt/powerpc: Eliminate users of of_platform_{,un}register_driver" forgot to convert the type of structure passed into platform_device_register() when it was converted from of_platform_device_register. Fix it. Signed-off-by: Ira W. Snyder Signed-off-by: Grant Likely --- drivers/dma/fsldma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 6b396759e7f5..8a781540590c 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1448,7 +1448,7 @@ static const struct of_device_id fsldma_of_ids[] = { {} }; -static struct of_platform_driver fsldma_of_driver = { +static struct platform_driver fsldma_of_driver = { .driver = { .name = "fsl-elo-dma", .owner = THIS_MODULE, -- cgit v1.2.2 From b42282e5a05018ecdc0d63a4ad530b0999785912 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 11 Apr 2011 10:53:11 -0700 Subject: pci: fix PCI bus allocation alignment handling In commit 13583b16592a ("PCI: refactor io size calculation code") Ram had a thinko in the refactorization of the code: the end result used the variable 'align' for the bus alignment, but the original code used 'min_align'. Since then, another use of that 'align' variable got introduced by commit c8adf9a3e873 ("PCI: pre-allocate additional resources to devices only after successful allocation of essential resources.") Fix both of those uses to use 'min_align' as they should. Daniel Hellstrom Acked-by: Ram Pai Acked-by: Jesse Barnes Signed-off-by: Linus Torvalds --- drivers/pci/setup-bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 89d0a6a88df7..ebf51ad1b714 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -676,10 +676,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, min_align = align1 >> 1; align += aligns[order]; } - size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), align); + size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); size1 = !add_size ? size : calculate_memsize(size, min_size+add_size, 0, - resource_size(b_res), align); + resource_size(b_res), min_align); if (!size0 && !size1) { if (b_res->start || b_res->end) dev_info(&bus->self->dev, "disabling bridge window " -- cgit v1.2.2 From 4a39e781682828c1b81a839e7d343fd91945a8d5 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 11 Apr 2011 13:02:06 -0400 Subject: iwlegacy: make iwl3945 and iwl4965 select IWLWIFI_LEGACY Otherwise, IWLWIFI_LEGACY has to be selected independently before the drivers are made available. Reported-by: Dave Airlie Signed-off-by: John W. Linville Cc: Stanislaw Gruszka Cc: Wey-Yi Guy --- drivers/net/wireless/iwlegacy/Kconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/Kconfig b/drivers/net/wireless/iwlegacy/Kconfig index 2a45dd44cc12..aef65cd47661 100644 --- a/drivers/net/wireless/iwlegacy/Kconfig +++ b/drivers/net/wireless/iwlegacy/Kconfig @@ -1,6 +1,5 @@ config IWLWIFI_LEGACY - tristate "Intel Wireless Wifi legacy devices" - depends on PCI && MAC80211 + tristate select FW_LOADER select NEW_LEDS select LEDS_CLASS @@ -65,7 +64,8 @@ endmenu config IWL4965 tristate "Intel Wireless WiFi 4965AGN (iwl4965)" - depends on IWLWIFI_LEGACY + depends on PCI && MAC80211 + select IWLWIFI_LEGACY ---help--- This option enables support for @@ -92,7 +92,8 @@ config IWL4965 config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" - depends on IWLWIFI_LEGACY + depends on PCI && MAC80211 + select IWLWIFI_LEGACY ---help--- Select to build the driver supporting the: -- cgit v1.2.2 From bded18c2dd09eee870f4446652dbce493a6dece1 Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Sun, 10 Apr 2011 23:16:44 +0000 Subject: stmmac: fixed dma lib build when turn-on the debug option This patch fixes a compilation error when build the dwmac_lib with the DEBUG option enabled. Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/dwmac_lib.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/stmmac/dwmac_lib.c b/drivers/net/stmmac/dwmac_lib.c index d65fab1ba790..e25093510b0c 100644 --- a/drivers/net/stmmac/dwmac_lib.c +++ b/drivers/net/stmmac/dwmac_lib.c @@ -26,9 +26,9 @@ #undef DWMAC_DMA_DEBUG #ifdef DWMAC_DMA_DEBUG -#define DBG(fmt, args...) printk(fmt, ## args) +#define DWMAC_LIB_DBG(fmt, args...) printk(fmt, ## args) #else -#define DBG(fmt, args...) do { } while (0) +#define DWMAC_LIB_DBG(fmt, args...) do { } while (0) #endif /* CSR1 enables the transmit DMA to check for new descriptor */ @@ -152,7 +152,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, /* read the status register (CSR5) */ u32 intr_status = readl(ioaddr + DMA_STATUS); - DBG(INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status); + DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status); #ifdef DWMAC_DMA_DEBUG /* It displays the DMA process states (CSR5 register) */ show_tx_process_state(intr_status); @@ -160,43 +160,43 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, #endif /* ABNORMAL interrupts */ if (unlikely(intr_status & DMA_STATUS_AIS)) { - DBG(INFO, "CSR5[15] DMA ABNORMAL IRQ: "); + DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: "); if (unlikely(intr_status & DMA_STATUS_UNF)) { - DBG(INFO, "transmit underflow\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n"); ret = tx_hard_error_bump_tc; x->tx_undeflow_irq++; } if (unlikely(intr_status & DMA_STATUS_TJT)) { - DBG(INFO, "transmit jabber\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n"); x->tx_jabber_irq++; } if (unlikely(intr_status & DMA_STATUS_OVF)) { - DBG(INFO, "recv overflow\n"); + DWMAC_LIB_DBG(KERN_INFO "recv overflow\n"); x->rx_overflow_irq++; } if (unlikely(intr_status & DMA_STATUS_RU)) { - DBG(INFO, "receive buffer unavailable\n"); + DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n"); x->rx_buf_unav_irq++; } if (unlikely(intr_status & DMA_STATUS_RPS)) { - DBG(INFO, "receive process stopped\n"); + DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n"); x->rx_process_stopped_irq++; } if (unlikely(intr_status & DMA_STATUS_RWT)) { - DBG(INFO, "receive watchdog\n"); + DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n"); x->rx_watchdog_irq++; } if (unlikely(intr_status & DMA_STATUS_ETI)) { - DBG(INFO, "transmit early interrupt\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n"); x->tx_early_irq++; } if (unlikely(intr_status & DMA_STATUS_TPS)) { - DBG(INFO, "transmit process stopped\n"); + DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n"); x->tx_process_stopped_irq++; ret = tx_hard_error; } if (unlikely(intr_status & DMA_STATUS_FBI)) { - DBG(INFO, "fatal bus error\n"); + DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n"); x->fatal_bus_error_irq++; ret = tx_hard_error; } @@ -215,7 +215,7 @@ int dwmac_dma_interrupt(void __iomem *ioaddr, /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); - DBG(INFO, "\n\n"); + DWMAC_LIB_DBG(KERN_INFO "\n\n"); return ret; } -- cgit v1.2.2 From f66ffe285939559d2a6f630a36f676d7c056b99d Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Sun, 10 Apr 2011 23:16:45 +0000 Subject: stmmac: fix open funct when exit on error This patch reviews the open function and fixes some errors when exit with an error state. It also moves the request_irq after core is initialized when interrupts are properly masked. Signed-off-by: Shiraz Hashim Hacked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac_main.c | 48 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 0e5f03135b50..38f7b619c44c 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -781,21 +781,6 @@ static int stmmac_open(struct net_device *dev) stmmac_verify_args(); - ret = stmmac_init_phy(dev); - if (unlikely(ret)) { - pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); - return ret; - } - - /* Request the IRQ lines */ - ret = request_irq(dev->irq, stmmac_interrupt, - IRQF_SHARED, dev->name, dev); - if (unlikely(ret < 0)) { - pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", - __func__, dev->irq, ret); - return ret; - } - #ifdef CONFIG_STMMAC_TIMER priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL); if (unlikely(priv->tm == NULL)) { @@ -814,6 +799,11 @@ static int stmmac_open(struct net_device *dev) } else priv->tm->enable = 1; #endif + ret = stmmac_init_phy(dev); + if (unlikely(ret)) { + pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret); + goto open_error; + } /* Create and initialize the TX/RX descriptors chains. */ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); @@ -822,12 +812,11 @@ static int stmmac_open(struct net_device *dev) init_dma_desc_rings(dev); /* DMA initialization and SW reset */ - if (unlikely(priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, - priv->dma_tx_phy, - priv->dma_rx_phy) < 0)) { - + ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl, + priv->dma_tx_phy, priv->dma_rx_phy); + if (ret < 0) { pr_err("%s: DMA initialization failed\n", __func__); - return -1; + goto open_error; } /* Copy the MAC addr into the HW */ @@ -848,6 +837,15 @@ static int stmmac_open(struct net_device *dev) writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK); writel(0xffffffff, priv->ioaddr + MMC_LOW_INTR_MASK); + /* Request the IRQ lines */ + ret = request_irq(dev->irq, stmmac_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(ret < 0)) { + pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n", + __func__, dev->irq, ret); + goto open_error; + } + /* Enable the MAC Rx/Tx */ stmmac_enable_mac(priv->ioaddr); @@ -878,7 +876,17 @@ static int stmmac_open(struct net_device *dev) napi_enable(&priv->napi); skb_queue_head_init(&priv->rx_recycle); netif_start_queue(dev); + return 0; + +open_error: +#ifdef CONFIG_STMMAC_TIMER + kfree(priv->tm); +#endif + if (priv->phydev) + phy_disconnect(priv->phydev); + + return ret; } /** -- cgit v1.2.2 From a08070acd43a76069ab20000cd02474369506add Mon Sep 17 00:00:00 2001 From: Giuseppe CAVALLARO Date: Sun, 10 Apr 2011 23:16:46 +0000 Subject: stmmac: fix Transmit Underflow error On some old MAC chips without COE sometime the Transmit Underflow error is issued. The driver aborted all the transmission process and initialized it from scratch. This breaks the network activity as raised by Nachiketa on a SPEAr board. The patch is to fix this rare underflow event. The driver will only clear the interrupt and the Tx DMA will go out the Suspend state as soon as the descriptor is fetched again. The driver will continue to bump-up the DMA FIFO threshold that, indeed, helped somebody to prevent this kind of error in the past as well. Reported-by: Nachiketa Prachanda Signed-off-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/stmmac/stmmac_main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index 38f7b619c44c..cc973fc38405 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -750,7 +750,6 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv) priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE); priv->xstats.threshold = tc; } - stmmac_tx_err(priv); } else if (unlikely(status == tx_hard_error)) stmmac_tx_err(priv); } -- cgit v1.2.2 From 38dbaf0afb518e462de7afca552acad048237a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Fri, 8 Apr 2011 03:40:19 +0000 Subject: bonding:set save_load to 0 when initializing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is unnecessary to set save_load to 1 here, as the tx_hashtbl is just kzalloced. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 9bc5de3e04a8..ab69e5afa3b2 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -176,7 +176,7 @@ static int tlb_initialize(struct bonding *bond) bond_info->tx_hashtbl = new_hashtbl; for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { - tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); + tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0); } _unlock_tx_hashtbl(bond); -- cgit v1.2.2 From 3b647568454acedb8f09f72931bfe92b73f812c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Sun, 10 Apr 2011 22:17:24 +0000 Subject: bonding:delete unused alb_timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now bonding-alb uses delayed_work instead of timer_list. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 86861f08b24d..f2a1d0a3aa8f 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -122,7 +122,6 @@ struct tlb_slave_info { }; struct alb_bond_info { - struct timer_list alb_timer; struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */ spinlock_t tx_hashtbl_lock; u32 unbalanced_load; -- cgit v1.2.2 From 26f007b85a1bb73e1974ebd371cf5cd1e80c0a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Sun, 10 Apr 2011 22:17:25 +0000 Subject: bonding:delete unused rlb_interval_counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now, alb_bond_info uses rx_ntt,rlb_update_delay_counter and rlb_update_retry_counter to decide when to call rlb_update_rx_clients(). Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index f2a1d0a3aa8f..01ed1fb2940d 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -139,7 +139,6 @@ struct alb_bond_info { struct slave *next_rx_slave;/* next slave to be assigned * to a new rx client for */ - u32 rlb_interval_counter; u8 primary_is_promisc; /* boolean */ u32 rlb_promisc_timeout_counter;/* counts primary * promiscuity time -- cgit v1.2.2 From 9814290ad0314fa0ce7991eae34ac44956e40b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Mon, 11 Apr 2011 00:15:57 +0000 Subject: net: fix tranmitted/tranmitting typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace tranmitted with transmitted. replace tranmitting with transmitting. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.h | 2 +- drivers/net/tokenring/3c359.c | 4 ++-- drivers/net/tokenring/lanstreamer.c | 2 +- drivers/net/tokenring/olympic.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h index 01ed1fb2940d..8ca7158b2dda 100644 --- a/drivers/net/bonding/bond_alb.h +++ b/drivers/net/bonding/bond_alb.h @@ -75,7 +75,7 @@ struct tlb_client_info { * gave this entry index. */ u32 tx_bytes; /* Each Client accumulates the BytesTx that - * were tranmitted to it, and after each + * were transmitted to it, and after each * CallBack the LoadHistory is divided * by the balance interval */ diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index 8a3b191b195b..ff32befd8443 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -1251,7 +1251,7 @@ static netdev_tx_t xl_xmit(struct sk_buff *skb, struct net_device *dev) /* * The NIC has told us that a packet has been downloaded onto the card, we must * find out which packet it has done, clear the skb and information for the packet - * then advance around the ring for all tranmitted packets + * then advance around the ring for all transmitted packets */ static void xl_dn_comp(struct net_device *dev) @@ -1568,7 +1568,7 @@ static void xl_arb_cmd(struct net_device *dev) if (lan_status_diff & LSC_SOFT_ERR) printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name); if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name); if (lan_status_diff & LSC_SS) printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); if (lan_status_diff & LSC_RING_REC) diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 5bd140704533..9354ca9da576 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -1675,7 +1675,7 @@ drop_frame: if (lan_status_diff & LSC_SOFT_ERR) printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n", dev->name); if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n", dev->name); + printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n", dev->name); if (lan_status_diff & LSC_SS) printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); if (lan_status_diff & LSC_RING_REC) diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 3d2fbe60b46e..2684003b8ab6 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -1500,7 +1500,7 @@ drop_frame: if (lan_status_diff & LSC_SOFT_ERR) printk(KERN_WARNING "%s: Adapter transmitted Soft Error Report Mac Frame\n",dev->name); if (lan_status_diff & LSC_TRAN_BCN) - printk(KERN_INFO "%s: We are tranmitting the beacon, aaah\n",dev->name); + printk(KERN_INFO "%s: We are transmitting the beacon, aaah\n",dev->name); if (lan_status_diff & LSC_SS) printk(KERN_INFO "%s: Single Station on the ring\n", dev->name); if (lan_status_diff & LSC_RING_REC) -- cgit v1.2.2 From 77c8e2c01542649f7a02fef8eb3b3d0e7fed6bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Pan=28=E6=BD=98=E5=8D=AB=E5=B9=B3=29?= Date: Mon, 11 Apr 2011 00:16:32 +0000 Subject: bonding:fix two typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace relpy with reply. replace premanent with permanent. Signed-off-by: Weiping Pan(潘å«å¹³) Signed-off-by: David S. Miller --- drivers/net/bonding/bond_alb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index ab69e5afa3b2..ba715826e2a8 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -701,7 +701,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) */ rlb_choose_channel(skb, bond); - /* The ARP relpy packets must be delayed so that + /* The ARP reply packets must be delayed so that * they can cancel out the influence of the ARP request. */ bond->alb_info.rlb_update_delay_counter = RLB_UPDATE_DELAY; @@ -1042,7 +1042,7 @@ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *sla * * If the permanent hw address of @slave is @bond's hw address, we need to * find a different hw address to give @slave, that isn't in use by any other - * slave in the bond. This address must be, of course, one of the premanent + * slave in the bond. This address must be, of course, one of the permanent * addresses of the other slaves. * * We go over the slave list, and for each slave there we compare its -- cgit v1.2.2 From c968bdf6912cad6d0fc63d7037cc1c870604a808 Mon Sep 17 00:00:00 2001 From: amit salecha Date: Mon, 11 Apr 2011 02:10:22 +0000 Subject: netxen: limit skb frags for non tso packet Machines are getting deadlock in four node cluster environment. All nodes are accessing (find /gfs2 -depth -print|cpio -ocv > /dev/null) 200 GB storage on a GFS2 filesystem. This result in memory fragmentation and driver receives 18 frags for 1448 byte packets. For non tso packet, fw drops the tx request, if it has >14 frags. Fixing it by pulling extra frags. Cc: stable@kernel.org Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/netxen/netxen_nic.h | 4 ++-- drivers/net/netxen/netxen_nic_main.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index d7299f1a4940..679dc8519c5b 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -174,7 +174,7 @@ #define MAX_NUM_CARDS 4 -#define MAX_BUFFERS_PER_CMD 32 +#define NETXEN_MAX_FRAGS_PER_TX 14 #define MAX_TSO_HEADER_DESC 2 #define MGMT_CMD_DESC_RESV 4 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \ @@ -558,7 +558,7 @@ struct netxen_recv_crb { */ struct netxen_cmd_buffer { struct sk_buff *skb; - struct netxen_skb_frag frag_array[MAX_BUFFERS_PER_CMD + 1]; + struct netxen_skb_frag frag_array[MAX_SKB_FRAGS + 1]; u32 frag_count; }; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 83348dc4b184..e8a4b6655999 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -1844,6 +1844,8 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; int i, k; + int delta = 0; + struct skb_frag_struct *frag; u32 producer; int frag_count, no_of_desc; @@ -1851,6 +1853,21 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) frag_count = skb_shinfo(skb)->nr_frags + 1; + /* 14 frags supported for normal packet and + * 32 frags supported for TSO packet + */ + if (!skb_is_gso(skb) && frag_count > NETXEN_MAX_FRAGS_PER_TX) { + + for (i = 0; i < (frag_count - NETXEN_MAX_FRAGS_PER_TX); i++) { + frag = &skb_shinfo(skb)->frags[i]; + delta += frag->size; + } + + if (!__pskb_pull_tail(skb, delta)) + goto drop_packet; + + frag_count = 1 + skb_shinfo(skb)->nr_frags; + } /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; -- cgit v1.2.2 From 1f112cee07b314e244ee9e71d9c1e6950dc13327 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 11 Apr 2011 22:54:42 +0200 Subject: PM / Hibernate: Introduce CONFIG_HIBERNATE_CALLBACKS Xen save/restore is going to use hibernate device callbacks for quiescing devices and putting them back to normal operations and it would need to select CONFIG_HIBERNATION for this purpose. However, that also would cause the hibernate interfaces for user space to be enabled, which might confuse user space, because the Xen kernels don't support hibernation. Moreover, it would be wasteful, as it would make the Xen kernels include a substantial amount of code that they would never use. To address this issue introduce new power management Kconfig option CONFIG_HIBERNATE_CALLBACKS, such that it will only select the code that is necessary for the hibernate device callbacks to work and make CONFIG_HIBERNATION select it. Then, Xen save/restore will be able to select CONFIG_HIBERNATE_CALLBACKS without dragging the entire hibernate code along with it. Signed-off-by: Rafael J. Wysocki Tested-by: Shriram Rajagopalan --- drivers/amba/bus.c | 6 +++--- drivers/base/platform.c | 6 +++--- drivers/base/power/main.c | 8 ++++---- drivers/pci/pci-driver.c | 6 +++--- drivers/xen/manage.c | 6 +++--- 5 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 821040503154..7025593a58c8 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -214,7 +214,7 @@ static int amba_pm_resume_noirq(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int amba_pm_freeze(struct device *dev) { @@ -352,7 +352,7 @@ static int amba_pm_restore_noirq(struct device *dev) return ret; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define amba_pm_freeze NULL #define amba_pm_thaw NULL @@ -363,7 +363,7 @@ static int amba_pm_restore_noirq(struct device *dev) #define amba_pm_poweroff_noirq NULL #define amba_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f051cfff18af..92792313d24a 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -771,7 +771,7 @@ int __weak platform_pm_resume_noirq(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int platform_pm_freeze(struct device *dev) { @@ -909,7 +909,7 @@ static int platform_pm_restore_noirq(struct device *dev) return ret; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define platform_pm_freeze NULL #define platform_pm_thaw NULL @@ -920,7 +920,7 @@ static int platform_pm_restore_noirq(struct device *dev) #define platform_pm_poweroff_noirq NULL #define platform_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 052dc53eef38..fbc5b6e7c591 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -233,7 +233,7 @@ static int pm_op(struct device *dev, } break; #endif /* CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS case PM_EVENT_FREEZE: case PM_EVENT_QUIESCE: if (ops->freeze) { @@ -260,7 +260,7 @@ static int pm_op(struct device *dev, suspend_report_result(ops->restore, error); } break; -#endif /* CONFIG_HIBERNATION */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ default: error = -EINVAL; } @@ -308,7 +308,7 @@ static int pm_noirq_op(struct device *dev, } break; #endif /* CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS case PM_EVENT_FREEZE: case PM_EVENT_QUIESCE: if (ops->freeze_noirq) { @@ -335,7 +335,7 @@ static int pm_noirq_op(struct device *dev, suspend_report_result(ops->restore_noirq, error); } break; -#endif /* CONFIG_HIBERNATION */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ default: error = -EINVAL; } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d86ea8b01137..135df164a4c1 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -781,7 +781,7 @@ static int pci_pm_resume(struct device *dev) #endif /* !CONFIG_SUSPEND */ -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int pci_pm_freeze(struct device *dev) { @@ -970,7 +970,7 @@ static int pci_pm_restore(struct device *dev) return error; } -#else /* !CONFIG_HIBERNATION */ +#else /* !CONFIG_HIBERNATE_CALLBACKS */ #define pci_pm_freeze NULL #define pci_pm_freeze_noirq NULL @@ -981,7 +981,7 @@ static int pci_pm_restore(struct device *dev) #define pci_pm_restore NULL #define pci_pm_restore_noirq NULL -#endif /* !CONFIG_HIBERNATION */ +#endif /* !CONFIG_HIBERNATE_CALLBACKS */ #ifdef CONFIG_PM_RUNTIME diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 95143dd6904d..1ac94125bf93 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -61,7 +61,7 @@ static void xen_post_suspend(int cancelled) xen_mm_unpin_all(); } -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS static int xen_suspend(void *data) { struct suspend_info *si = data; @@ -173,7 +173,7 @@ out: #endif shutting_down = SHUTDOWN_INVALID; } -#endif /* CONFIG_HIBERNATION */ +#endif /* CONFIG_HIBERNATE_CALLBACKS */ struct shutdown_handler { const char *command; @@ -202,7 +202,7 @@ static void shutdown_handler(struct xenbus_watch *watch, { "poweroff", do_poweroff }, { "halt", do_poweroff }, { "reboot", do_reboot }, -#ifdef CONFIG_HIBERNATION +#ifdef CONFIG_HIBERNATE_CALLBACKS { "suspend", do_suspend }, #endif {NULL, NULL}, -- cgit v1.2.2 From c68b2081250a87ba9b9a173faa5a600cc684602e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 11 Apr 2011 23:50:02 -0700 Subject: Input: twl4030_keypad - fix potential NULL dereference in twl4030_kp_probe() We should first check whether platform data is NULL or not, before dereferencing it to get the keymap. Signed-off-by: Axel Lin Reviewed-by: Felipe Balbi Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/twl4030_keypad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index cc06c4b2f920..a26922cf0e84 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -332,7 +332,7 @@ static int __devinit twl4030_kp_program(struct twl4030_keypad *kp) static int __devinit twl4030_kp_probe(struct platform_device *pdev) { struct twl4030_keypad_data *pdata = pdev->dev.platform_data; - const struct matrix_keymap_data *keymap_data = pdata->keymap_data; + const struct matrix_keymap_data *keymap_data; struct twl4030_keypad *kp; struct input_dev *input; u8 reg; @@ -344,6 +344,8 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev) return -EINVAL; } + keymap_data = pdata->keymap_data; + kp = kzalloc(sizeof(*kp), GFP_KERNEL); input = input_allocate_device(); if (!kp || !input) { -- cgit v1.2.2 From e710d7d5a9cab1041b7a3cf9e655b75d92786857 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 8 Apr 2011 00:43:01 +0200 Subject: mfd: Fetch cell pointer from platform_device->mfd_cell In order for MFD drivers to fetch their cell pointer but also their platform data one, an mfd cell pointer is added to the platform_device structure. That allows all MFD sub devices drivers to be MFD agnostic, unless they really need to access their MFD cell data. Most of them don't, especially the ones for IPs used by both MFD and non MFD SoCs. Cc: Grant Likely Acked-by: Greg KH Signed-off-by: Samuel Ortiz --- drivers/base/platform.c | 1 + drivers/mfd/mfd-core.c | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index f051cfff18af..6c3a2bdc527a 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -149,6 +149,7 @@ static void platform_device_release(struct device *dev) of_device_node_put(&pa->pdev.dev); kfree(pa->pdev.dev.platform_data); + kfree(pa->pdev.mfd_cell); kfree(pa->pdev.resource); kfree(pa); } diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index d01574d98870..f4c8c844b913 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -55,6 +55,19 @@ int mfd_cell_disable(struct platform_device *pdev) } EXPORT_SYMBOL(mfd_cell_disable); +static int mfd_platform_add_cell(struct platform_device *pdev, + const struct mfd_cell *cell) +{ + if (!cell) + return 0; + + pdev->mfd_cell = kmemdup(cell, sizeof(*cell), GFP_KERNEL); + if (!pdev->mfd_cell) + return -ENOMEM; + + return 0; +} + static int mfd_add_device(struct device *parent, int id, const struct mfd_cell *cell, struct resource *mem_base, @@ -75,7 +88,7 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; - ret = platform_device_add_data(pdev, cell, sizeof(*cell)); + ret = mfd_platform_add_cell(pdev, cell); if (ret) goto fail_res; @@ -123,7 +136,6 @@ static int mfd_add_device(struct device *parent, int id, return 0; -/* platform_device_del(pdev); */ fail_res: kfree(res); fail_device: -- cgit v1.2.2 From a6d710fefd1b2c209353a452d0f4c831b3af0da0 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 22 Mar 2011 13:09:50 +0100 Subject: ARM: pxafb: Fix access to nonexistent member of pxafb_info In case CONFIG_FB_PXA_OVERLAY is not defined, the pxafb_freq_transition() function tests nonexistent member of pxafb_info (since the member is not part of the structure). Fix this by wraping the test in ifdef, even if I don't really like how the code looks now. The check doesn't have to happen if overlays are disabled at all as the check is always true then. Signed-off-by: Marek Vasut Acked-by: Vasily Khoruzhick Signed-off-by: Eric Miao --- drivers/video/pxafb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index a2e5b5100ab4..0f4e8c942f9e 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -1648,7 +1648,9 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) switch (val) { case CPUFREQ_PRECHANGE: - if (!fbi->overlay[0].usage && !fbi->overlay[1].usage) +#ifdef CONFIG_FB_PXA_OVERLAY + if (!(fbi->overlay[0].usage || fbi->overlay[1].usage)) +#endif set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); break; -- cgit v1.2.2 From af21cbb1ef6aa366fcb629ea4d4330300ba22de7 Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 1 Apr 2011 13:28:45 +0400 Subject: pcmcia: limit pxa2xx_balloon3 subdriver to balloon3 platform pxa2xx_balloon3 tries to register pxa2xx-pcmcia device not checking whether machine is really balloon3, thus messing multi-machine kernels. Fix it up. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Eric Miao --- drivers/pcmcia/pxa2xx_balloon3.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c index 453c54c97612..4c3e94c0ae85 100644 --- a/drivers/pcmcia/pxa2xx_balloon3.c +++ b/drivers/pcmcia/pxa2xx_balloon3.c @@ -25,6 +25,8 @@ #include +#include + #include "soc_common.h" /* @@ -127,6 +129,9 @@ static int __init balloon3_pcmcia_init(void) { int ret; + if (!machine_is_balloon3()) + return -ENODEV; + balloon3_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); if (!balloon3_pcmcia_device) return -ENOMEM; -- cgit v1.2.2 From 735443fede138fbbad062ec258e4d49648a0a56d Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Fri, 1 Apr 2011 13:28:46 +0400 Subject: pcmcia: limit pxa2xx_trizeps4 subdriver to trizeps4 platform pxa2xx_trizeps4 tries to register pxa2xx-pcmcia device not checking whether machine is really trizeps4, thus messing multi-machine kernels. Fix it up. Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: Eric Miao --- drivers/pcmcia/pxa2xx_trizeps4.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c index b7e596620db1..5bb4e1a94d25 100644 --- a/drivers/pcmcia/pxa2xx_trizeps4.c +++ b/drivers/pcmcia/pxa2xx_trizeps4.c @@ -226,6 +226,9 @@ static int __init trizeps_pcmcia_init(void) { int ret; + if (!machine_is_trizeps4() && !machine_is_trizeps4wl()) + return -ENODEV; + trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); if (!trizeps_pcmcia_device) return -ENOMEM; -- cgit v1.2.2 From 101650726e4a5c0eca3e2716aefeb3296bb177b9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 8 Apr 2011 17:02:04 +0200 Subject: samsung-laptop: add support for N230 model Signed-off-by: Greg Kroah-Hartman [mmarek: cherry-picked from staging commit 0789b003] Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index de434c6dc2d6..11a3fe29cf0e 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -591,12 +591,12 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { .callback = dmi_check_cb, }, { - .ident = "N150/N210/N220", + .ident = "N150/N210/N220/N230", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"), + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"), }, .callback = dmi_check_cb, }, -- cgit v1.2.2 From 3d536ed415a8f5d3f683597521df071af9f2866c Mon Sep 17 00:00:00 2001 From: Alberto Mardegan Date: Fri, 8 Apr 2011 17:02:03 +0200 Subject: samsung-laptop: Samsung R410P backlight driver Here's a trivial patch which adds support to the backlight device found in Samsung R410 Plus laptops. Signed-off-by: Alberto Mardegan Signed-off-by: Greg Kroah-Hartman [mmarek: cherry-picked from staging commit d542f180] Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 11a3fe29cf0e..39f30ff090ab 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -570,6 +570,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .callback = dmi_check_cb, }, + { + .ident = "R410 Plus", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, + "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), + DMI_MATCH(DMI_BOARD_NAME, "R460"), + }, + .callback = dmi_check_cb, + }, { .ident = "R518", .matches = { -- cgit v1.2.2 From 9d1aea62e45d447e7fc05d4e7f4e90f633e3abfc Mon Sep 17 00:00:00 2001 From: Neil Turton Date: Mon, 4 Apr 2011 13:46:23 +0100 Subject: sfc: Stop the TX queues during loopback self-tests If the TX queues are running during loopback self tests, host traffic gets looped back which causes the test to fail. Avoid restarting the TX queues after the port reset so that any packets sent by the host get held back until after the tests have completed. [bwh: Also wake all TX queues at the end of self-tests.] Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 2 +- drivers/net/sfc/selftest.c | 2 ++ drivers/net/sfc/tx.c | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index d890679e4c4d..0dc800b5a4ea 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1436,7 +1436,7 @@ static void efx_start_all(struct efx_nic *efx) * restart the transmit interface early so the watchdog timer stops */ efx_start_port(efx); - if (efx_dev_registered(efx)) + if (efx_dev_registered(efx) && !efx->port_inhibited) netif_tx_wake_all_queues(efx->net_dev); efx_for_each_channel(channel, efx) diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index a0f49b348d62..845808408924 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -770,6 +770,8 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); + netif_tx_wake_all_queues(efx->net_dev); + return rc_test; } diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index 139801908217..d2c85dfdf3bf 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -435,7 +435,8 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index) * queue state. */ smp_mb(); if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) && - likely(efx->port_enabled)) { + likely(efx->port_enabled) && + likely(!efx->port_inhibited)) { fill_level = tx_queue->insert_count - tx_queue->read_count; if (fill_level < EFX_TXQ_THRESHOLD(efx)) { EFX_BUG_ON_PARANOID(!efx_dev_registered(efx)); -- cgit v1.2.2 From 993819c563695efc2782d312f55bec634c2d2da5 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 8 Apr 2011 17:02:06 +0200 Subject: staging: samsung-laptop has moved to platform/x86 Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/samsung-laptop/Kconfig | 10 - drivers/staging/samsung-laptop/Makefile | 1 - drivers/staging/samsung-laptop/TODO | 5 - drivers/staging/samsung-laptop/samsung-laptop.c | 843 ------------------------ 6 files changed, 862 deletions(-) delete mode 100644 drivers/staging/samsung-laptop/Kconfig delete mode 100644 drivers/staging/samsung-laptop/Makefile delete mode 100644 drivers/staging/samsung-laptop/TODO delete mode 100644 drivers/staging/samsung-laptop/samsung-laptop.c (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 18b43fcb4171..9d5a033e59bb 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -133,8 +133,6 @@ source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h25/Kconfig" -source "drivers/staging/samsung-laptop/Kconfig" - source "drivers/staging/sm7xx/Kconfig" source "drivers/staging/dt3155v4l/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index cfd13cd55efb..adebf8e14089 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -49,7 +49,6 @@ obj-$(CONFIG_XVMALLOC) += zram/ obj-$(CONFIG_ZCACHE) += zcache/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ -obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop/ obj-$(CONFIG_FB_SM7XX) += sm7xx/ obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ diff --git a/drivers/staging/samsung-laptop/Kconfig b/drivers/staging/samsung-laptop/Kconfig deleted file mode 100644 index f27c60864c26..000000000000 --- a/drivers/staging/samsung-laptop/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config SAMSUNG_LAPTOP - tristate "Samsung Laptop driver" - default n - depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 - help - This module implements a driver for the N128 Samsung Laptop - providing control over the Wireless LED and the LCD backlight - - To compile this driver as a module, choose - M here: the module will be called samsung-laptop. diff --git a/drivers/staging/samsung-laptop/Makefile b/drivers/staging/samsung-laptop/Makefile deleted file mode 100644 index 3c6f42045211..000000000000 --- a/drivers/staging/samsung-laptop/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o diff --git a/drivers/staging/samsung-laptop/TODO b/drivers/staging/samsung-laptop/TODO deleted file mode 100644 index f7a6d589916e..000000000000 --- a/drivers/staging/samsung-laptop/TODO +++ /dev/null @@ -1,5 +0,0 @@ -TODO: - - review from other developers - - figure out ACPI video issues - -Please send patches to Greg Kroah-Hartman diff --git a/drivers/staging/samsung-laptop/samsung-laptop.c b/drivers/staging/samsung-laptop/samsung-laptop.c deleted file mode 100644 index 25294462b8b6..000000000000 --- a/drivers/staging/samsung-laptop/samsung-laptop.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Samsung Laptop driver - * - * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) - * Copyright (C) 2009,2011 Novell Inc. - * - * 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. - * - */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This driver is needed because a number of Samsung laptops do not hook - * their control settings through ACPI. So we have to poke around in the - * BIOS to do things like brightness values, and "special" key controls. - */ - -/* - * We have 0 - 8 as valid brightness levels. The specs say that level 0 should - * be reserved by the BIOS (which really doesn't make much sense), we tell - * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8 - */ -#define MAX_BRIGHT 0x07 - - -#define SABI_IFACE_MAIN 0x00 -#define SABI_IFACE_SUB 0x02 -#define SABI_IFACE_COMPLETE 0x04 -#define SABI_IFACE_DATA 0x05 - -/* Structure to get data back to the calling function */ -struct sabi_retval { - u8 retval[20]; -}; - -struct sabi_header_offsets { - u8 port; - u8 re_mem; - u8 iface_func; - u8 en_mem; - u8 data_offset; - u8 data_segment; -}; - -struct sabi_commands { - /* - * Brightness is 0 - 8, as described above. - * Value 0 is for the BIOS to use - */ - u8 get_brightness; - u8 set_brightness; - - /* - * first byte: - * 0x00 - wireless is off - * 0x01 - wireless is on - * second byte: - * 0x02 - 3G is off - * 0x03 - 3G is on - * TODO, verify 3G is correct, that doesn't seem right... - */ - u8 get_wireless_button; - u8 set_wireless_button; - - /* 0 is off, 1 is on */ - u8 get_backlight; - u8 set_backlight; - - /* - * 0x80 or 0x00 - no action - * 0x81 - recovery key pressed - */ - u8 get_recovery_mode; - u8 set_recovery_mode; - - /* - * on seclinux: 0 is low, 1 is high, - * on swsmi: 0 is normal, 1 is silent, 2 is turbo - */ - u8 get_performance_level; - u8 set_performance_level; - - /* - * Tell the BIOS that Linux is running on this machine. - * 81 is on, 80 is off - */ - u8 set_linux; -}; - -struct sabi_performance_level { - const char *name; - u8 value; -}; - -struct sabi_config { - const char *test_string; - u16 main_function; - const struct sabi_header_offsets header_offsets; - const struct sabi_commands commands; - const struct sabi_performance_level performance_levels[4]; - u8 min_brightness; - u8 max_brightness; -}; - -static const struct sabi_config sabi_configs[] = { - { - .test_string = "SECLINUX", - - .main_function = 0x4c49, - - .header_offsets = { - .port = 0x00, - .re_mem = 0x02, - .iface_func = 0x03, - .en_mem = 0x04, - .data_offset = 0x05, - .data_segment = 0x07, - }, - - .commands = { - .get_brightness = 0x00, - .set_brightness = 0x01, - - .get_wireless_button = 0x02, - .set_wireless_button = 0x03, - - .get_backlight = 0x04, - .set_backlight = 0x05, - - .get_recovery_mode = 0x06, - .set_recovery_mode = 0x07, - - .get_performance_level = 0x08, - .set_performance_level = 0x09, - - .set_linux = 0x0a, - }, - - .performance_levels = { - { - .name = "silent", - .value = 0, - }, - { - .name = "normal", - .value = 1, - }, - { }, - }, - .min_brightness = 1, - .max_brightness = 8, - }, - { - .test_string = "SwSmi@", - - .main_function = 0x5843, - - .header_offsets = { - .port = 0x00, - .re_mem = 0x04, - .iface_func = 0x02, - .en_mem = 0x03, - .data_offset = 0x05, - .data_segment = 0x07, - }, - - .commands = { - .get_brightness = 0x10, - .set_brightness = 0x11, - - .get_wireless_button = 0x12, - .set_wireless_button = 0x13, - - .get_backlight = 0x2d, - .set_backlight = 0x2e, - - .get_recovery_mode = 0xff, - .set_recovery_mode = 0xff, - - .get_performance_level = 0x31, - .set_performance_level = 0x32, - - .set_linux = 0xff, - }, - - .performance_levels = { - { - .name = "normal", - .value = 0, - }, - { - .name = "silent", - .value = 1, - }, - { - .name = "overclock", - .value = 2, - }, - { }, - }, - .min_brightness = 0, - .max_brightness = 8, - }, - { }, -}; - -static const struct sabi_config *sabi_config; - -static void __iomem *sabi; -static void __iomem *sabi_iface; -static void __iomem *f0000_segment; -static struct backlight_device *backlight_device; -static struct mutex sabi_mutex; -static struct platform_device *sdev; -static struct rfkill *rfk; - -static int force; -module_param(force, bool, 0); -MODULE_PARM_DESC(force, - "Disable the DMI check and forces the driver to be loaded"); - -static int debug; -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug enabled or not"); - -static int sabi_get_command(u8 command, struct sabi_retval *sretval) -{ - int retval = 0; - u16 port = readw(sabi + sabi_config->header_offsets.port); - u8 complete, iface_data; - - mutex_lock(&sabi_mutex); - - /* enable memory to be able to write to it */ - outb(readb(sabi + sabi_config->header_offsets.en_mem), port); - - /* write out the command */ - writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); - writew(command, sabi_iface + SABI_IFACE_SUB); - writeb(0, sabi_iface + SABI_IFACE_COMPLETE); - outb(readb(sabi + sabi_config->header_offsets.iface_func), port); - - /* write protect memory to make it safe */ - outb(readb(sabi + sabi_config->header_offsets.re_mem), port); - - /* see if the command actually succeeded */ - complete = readb(sabi_iface + SABI_IFACE_COMPLETE); - iface_data = readb(sabi_iface + SABI_IFACE_DATA); - if (complete != 0xaa || iface_data == 0xff) { - pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", - command, complete, iface_data); - retval = -EINVAL; - goto exit; - } - /* - * Save off the data into a structure so the caller use it. - * Right now we only want the first 4 bytes, - * There are commands that need more, but not for the ones we - * currently care about. - */ - sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA); - sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1); - sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2); - sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3); - -exit: - mutex_unlock(&sabi_mutex); - return retval; - -} - -static int sabi_set_command(u8 command, u8 data) -{ - int retval = 0; - u16 port = readw(sabi + sabi_config->header_offsets.port); - u8 complete, iface_data; - - mutex_lock(&sabi_mutex); - - /* enable memory to be able to write to it */ - outb(readb(sabi + sabi_config->header_offsets.en_mem), port); - - /* write out the command */ - writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); - writew(command, sabi_iface + SABI_IFACE_SUB); - writeb(0, sabi_iface + SABI_IFACE_COMPLETE); - writeb(data, sabi_iface + SABI_IFACE_DATA); - outb(readb(sabi + sabi_config->header_offsets.iface_func), port); - - /* write protect memory to make it safe */ - outb(readb(sabi + sabi_config->header_offsets.re_mem), port); - - /* see if the command actually succeeded */ - complete = readb(sabi_iface + SABI_IFACE_COMPLETE); - iface_data = readb(sabi_iface + SABI_IFACE_DATA); - if (complete != 0xaa || iface_data == 0xff) { - pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", - command, complete, iface_data); - retval = -EINVAL; - } - - mutex_unlock(&sabi_mutex); - return retval; -} - -static void test_backlight(void) -{ - struct sabi_retval sretval; - - sabi_get_command(sabi_config->commands.get_backlight, &sretval); - printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); - - sabi_set_command(sabi_config->commands.set_backlight, 0); - printk(KERN_DEBUG "backlight should be off\n"); - - sabi_get_command(sabi_config->commands.get_backlight, &sretval); - printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); - - msleep(1000); - - sabi_set_command(sabi_config->commands.set_backlight, 1); - printk(KERN_DEBUG "backlight should be on\n"); - - sabi_get_command(sabi_config->commands.get_backlight, &sretval); - printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); -} - -static void test_wireless(void) -{ - struct sabi_retval sretval; - - sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); - printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); - - sabi_set_command(sabi_config->commands.set_wireless_button, 0); - printk(KERN_DEBUG "wireless led should be off\n"); - - sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); - printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); - - msleep(1000); - - sabi_set_command(sabi_config->commands.set_wireless_button, 1); - printk(KERN_DEBUG "wireless led should be on\n"); - - sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); - printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); -} - -static u8 read_brightness(void) -{ - struct sabi_retval sretval; - int user_brightness = 0; - int retval; - - retval = sabi_get_command(sabi_config->commands.get_brightness, - &sretval); - if (!retval) { - user_brightness = sretval.retval[0]; - if (user_brightness != 0) - user_brightness -= sabi_config->min_brightness; - } - return user_brightness; -} - -static void set_brightness(u8 user_brightness) -{ - u8 user_level = user_brightness - sabi_config->min_brightness; - - sabi_set_command(sabi_config->commands.set_brightness, user_level); -} - -static int get_brightness(struct backlight_device *bd) -{ - return (int)read_brightness(); -} - -static int update_status(struct backlight_device *bd) -{ - set_brightness(bd->props.brightness); - - if (bd->props.power == FB_BLANK_UNBLANK) - sabi_set_command(sabi_config->commands.set_backlight, 1); - else - sabi_set_command(sabi_config->commands.set_backlight, 0); - return 0; -} - -static const struct backlight_ops backlight_ops = { - .get_brightness = get_brightness, - .update_status = update_status, -}; - -static int rfkill_set(void *data, bool blocked) -{ - /* Do something with blocked...*/ - /* - * blocked == false is on - * blocked == true is off - */ - if (blocked) - sabi_set_command(sabi_config->commands.set_wireless_button, 0); - else - sabi_set_command(sabi_config->commands.set_wireless_button, 1); - - return 0; -} - -static struct rfkill_ops rfkill_ops = { - .set_block = rfkill_set, -}; - -static int init_wireless(struct platform_device *sdev) -{ - int retval; - - rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, - &rfkill_ops, NULL); - if (!rfk) - return -ENOMEM; - - retval = rfkill_register(rfk); - if (retval) { - rfkill_destroy(rfk); - return -ENODEV; - } - - return 0; -} - -static void destroy_wireless(void) -{ - rfkill_unregister(rfk); - rfkill_destroy(rfk); -} - -static ssize_t get_performance_level(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sabi_retval sretval; - int retval; - int i; - - /* Read the state */ - retval = sabi_get_command(sabi_config->commands.get_performance_level, - &sretval); - if (retval) - return retval; - - /* The logic is backwards, yeah, lots of fun... */ - for (i = 0; sabi_config->performance_levels[i].name; ++i) { - if (sretval.retval[0] == sabi_config->performance_levels[i].value) - return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); - } - return sprintf(buf, "%s\n", "unknown"); -} - -static ssize_t set_performance_level(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - if (count >= 1) { - int i; - for (i = 0; sabi_config->performance_levels[i].name; ++i) { - const struct sabi_performance_level *level = - &sabi_config->performance_levels[i]; - if (!strncasecmp(level->name, buf, strlen(level->name))) { - sabi_set_command(sabi_config->commands.set_performance_level, - level->value); - break; - } - } - if (!sabi_config->performance_levels[i].name) - return -EINVAL; - } - return count; -} -static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, - get_performance_level, set_performance_level); - - -static int __init dmi_check_cb(const struct dmi_system_id *id) -{ - pr_info("found laptop model '%s'\n", - id->ident); - return 0; -} - -static struct dmi_system_id __initdata samsung_dmi_table[] = { - { - .ident = "N128", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N128"), - DMI_MATCH(DMI_BOARD_NAME, "N128"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N130", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N130"), - DMI_MATCH(DMI_BOARD_NAME, "N130"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X125", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X125"), - DMI_MATCH(DMI_BOARD_NAME, "X125"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X120/X170", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), - DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NC10", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), - DMI_MATCH(DMI_BOARD_NAME, "NC10"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NP-Q45", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), - DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "X360", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "X360"), - DMI_MATCH(DMI_BOARD_NAME, "X360"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R410 Plus", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), - DMI_MATCH(DMI_BOARD_NAME, "R460"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R518", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R518"), - DMI_MATCH(DMI_BOARD_NAME, "R518"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R519/R719", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), - DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N150/N210/N220/N230", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"), - DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N150P/N210P/N220P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), - DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R530/R730", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), - DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "NF110/NF210/NF310", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), - DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "N145P/N250P/N260P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), - DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "R70/R71", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), - DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), - }, - .callback = dmi_check_cb, - }, - { - .ident = "P460", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "P460"), - DMI_MATCH(DMI_BOARD_NAME, "P460"), - }, - .callback = dmi_check_cb, - }, - { }, -}; -MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); - -static int find_signature(void __iomem *memcheck, const char *testStr) -{ - int i = 0; - int loca; - - for (loca = 0; loca < 0xffff; loca++) { - char temp = readb(memcheck + loca); - - if (temp == testStr[i]) { - if (i == strlen(testStr)-1) - break; - ++i; - } else { - i = 0; - } - } - return loca; -} - -static int __init samsung_init(void) -{ - struct backlight_properties props; - struct sabi_retval sretval; - unsigned int ifaceP; - int i; - int loca; - int retval; - - mutex_init(&sabi_mutex); - - if (!force && !dmi_check_system(samsung_dmi_table)) - return -ENODEV; - - f0000_segment = ioremap_nocache(0xf0000, 0xffff); - if (!f0000_segment) { - pr_err("Can't map the segment at 0xf0000\n"); - return -EINVAL; - } - - /* Try to find one of the signatures in memory to find the header */ - for (i = 0; sabi_configs[i].test_string != 0; ++i) { - sabi_config = &sabi_configs[i]; - loca = find_signature(f0000_segment, sabi_config->test_string); - if (loca != 0xffff) - break; - } - - if (loca == 0xffff) { - pr_err("This computer does not support SABI\n"); - goto error_no_signature; - } - - /* point to the SMI port Number */ - loca += 1; - sabi = (f0000_segment + loca); - - if (debug) { - printk(KERN_DEBUG "This computer supports SABI==%x\n", - loca + 0xf0000 - 6); - printk(KERN_DEBUG "SABI header:\n"); - printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", - readw(sabi + sabi_config->header_offsets.port)); - printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", - readb(sabi + sabi_config->header_offsets.iface_func)); - printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", - readb(sabi + sabi_config->header_offsets.en_mem)); - printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", - readb(sabi + sabi_config->header_offsets.re_mem)); - printk(KERN_DEBUG " SABI data offset = 0x%04x\n", - readw(sabi + sabi_config->header_offsets.data_offset)); - printk(KERN_DEBUG " SABI data segment = 0x%04x\n", - readw(sabi + sabi_config->header_offsets.data_segment)); - } - - /* Get a pointer to the SABI Interface */ - ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; - ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; - sabi_iface = ioremap_nocache(ifaceP, 16); - if (!sabi_iface) { - pr_err("Can't remap %x\n", ifaceP); - goto exit; - } - if (debug) { - printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); - printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); - - test_backlight(); - test_wireless(); - - retval = sabi_get_command(sabi_config->commands.get_brightness, - &sretval); - printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); - } - - /* Turn on "Linux" mode in the BIOS */ - if (sabi_config->commands.set_linux != 0xff) { - retval = sabi_set_command(sabi_config->commands.set_linux, - 0x81); - if (retval) { - pr_warn("Linux mode was not set!\n"); - goto error_no_platform; - } - } - - /* knock up a platform device to hang stuff off of */ - sdev = platform_device_register_simple("samsung", -1, NULL, 0); - if (IS_ERR(sdev)) - goto error_no_platform; - - /* create a backlight device to talk to this one */ - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = sabi_config->max_brightness; - backlight_device = backlight_device_register("samsung", &sdev->dev, - NULL, &backlight_ops, - &props); - if (IS_ERR(backlight_device)) - goto error_no_backlight; - - backlight_device->props.brightness = read_brightness(); - backlight_device->props.power = FB_BLANK_UNBLANK; - backlight_update_status(backlight_device); - - retval = init_wireless(sdev); - if (retval) - goto error_no_rfk; - - retval = device_create_file(&sdev->dev, &dev_attr_performance_level); - if (retval) - goto error_file_create; - -exit: - return 0; - -error_file_create: - destroy_wireless(); - -error_no_rfk: - backlight_device_unregister(backlight_device); - -error_no_backlight: - platform_device_unregister(sdev); - -error_no_platform: - iounmap(sabi_iface); - -error_no_signature: - iounmap(f0000_segment); - return -EINVAL; -} - -static void __exit samsung_exit(void) -{ - /* Turn off "Linux" mode in the BIOS */ - if (sabi_config->commands.set_linux != 0xff) - sabi_set_command(sabi_config->commands.set_linux, 0x80); - - device_remove_file(&sdev->dev, &dev_attr_performance_level); - backlight_device_unregister(backlight_device); - destroy_wireless(); - iounmap(sabi_iface); - iounmap(f0000_segment); - platform_device_unregister(sdev); -} - -module_init(samsung_init); -module_exit(samsung_exit); - -MODULE_AUTHOR("Greg Kroah-Hartman "); -MODULE_DESCRIPTION("Samsung Backlight driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 8713b04ab8da256493410bd4f25170d2e0836534 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Fri, 8 Apr 2011 17:02:05 +0200 Subject: samsung-laptop: set backlight type Cherry-picked from drivers/staging/samsung-laptop/samsung-laptop.c Signed-off-by: Michal Marek Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 39f30ff090ab..d347116d150e 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -781,6 +781,7 @@ static int __init samsung_init(void) /* create a backlight device to talk to this one */ memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; props.max_brightness = sabi_config->max_brightness; backlight_device = backlight_device_register("samsung", &sdev->dev, NULL, &backlight_ops, -- cgit v1.2.2 From 855b8bc9953fdf40095fdec9d91d49736ca7b17c Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Tue, 5 Apr 2011 23:38:35 +0900 Subject: sony-laptop: only show the handles sysfs file in debug mode It makes no sense to expose this type of information to userspace unless the driver was explicitly loaded with the debug option. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 33c3b8c066ee..33d9555470c3 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -771,11 +771,6 @@ static int sony_nc_handles_setup(struct platform_device *pd) if (!handles) return -ENOMEM; - sysfs_attr_init(&handles->devattr.attr); - handles->devattr.attr.name = "handles"; - handles->devattr.attr.mode = S_IRUGO; - handles->devattr.show = sony_nc_handles_show; - for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { if (!acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i + 0x20, &result)) { @@ -785,11 +780,18 @@ static int sony_nc_handles_setup(struct platform_device *pd) } } - /* allow reading capabilities via sysfs */ - if (device_create_file(&pd->dev, &handles->devattr)) { - kfree(handles); - handles = NULL; - return -1; + if (debug) { + sysfs_attr_init(&handles->devattr.attr); + handles->devattr.attr.name = "handles"; + handles->devattr.attr.mode = S_IRUGO; + handles->devattr.show = sony_nc_handles_show; + + /* allow reading capabilities via sysfs */ + if (device_create_file(&pd->dev, &handles->devattr)) { + kfree(handles); + handles = NULL; + return -1; + } } return 0; @@ -798,7 +800,8 @@ static int sony_nc_handles_setup(struct platform_device *pd) static int sony_nc_handles_cleanup(struct platform_device *pd) { if (handles) { - device_remove_file(&pd->dev, &handles->devattr); + if (debug) + device_remove_file(&pd->dev, &handles->devattr); kfree(handles); handles = NULL; } -- cgit v1.2.2 From df410d522410e676602a14eb5957c4b3e1fa3902 Mon Sep 17 00:00:00 2001 From: Marco Chiappero Date: Tue, 5 Apr 2011 23:38:34 +0900 Subject: sony-laptop: keyboard backlight fixes Restore the original state on module removal, set the latest values on resume. When setting the keyboard backlight mode try to turn on/off backlight immediately. [malattia@linux.it: patch taken from a largely modified sony-laptop.c, ported and slightly modified to use defines already available.] Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 33d9555470c3..8f709aec4da0 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -138,6 +138,8 @@ MODULE_PARM_DESC(kbd_backlight_timeout, "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " "(default: 0)"); +static void sony_nc_kbd_backlight_resume(void); + enum sony_nc_rfkill { SONY_WIFI, SONY_BLUETOOTH, @@ -1176,6 +1178,9 @@ static int sony_nc_resume(struct acpi_device *device) /* re-read rfkill state */ sony_nc_rfkill_update(); + /* restore kbd backlight states */ + sony_nc_kbd_backlight_resume(); + return 0; } @@ -1363,6 +1368,7 @@ out_no_enum: #define KBDBL_HANDLER 0x137 #define KBDBL_PRESENT 0xB00 #define SET_MODE 0xC00 +#define SET_STATE 0xD00 #define SET_TIMEOUT 0xE00 struct kbd_backlight { @@ -1385,6 +1391,10 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) (value << 0x10) | SET_MODE, &result)) return -EIO; + /* Try to turn the light on/off immediately */ + sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE, + &result); + kbdbl_handle->mode = value; return 0; @@ -1466,7 +1476,7 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd) { int result; - if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) + if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) return 0; if (!(result & 0x02)) return 0; @@ -1509,13 +1519,36 @@ outkzalloc: static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) { if (kbdbl_handle) { + int result; + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); + + /* restore the default hw behaviour */ + sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result); + sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result); + kfree(kbdbl_handle); } return 0; } +static void sony_nc_kbd_backlight_resume(void) +{ + int ignore = 0; + + if (!kbdbl_handle) + return; + + if (kbdbl_handle->mode == 0) + sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore); + + if (kbdbl_handle->timeout != 0) + sony_call_snc_handle(KBDBL_HANDLER, + (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT, + &ignore); +} + static void sony_nc_backlight_setup(void) { acpi_handle unused; -- cgit v1.2.2 From 08a0799d5736f1494ef35d386570d177447acbfb Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Wed, 6 Apr 2011 17:40:06 +0800 Subject: acer-wmi: Fix capitalisation of GUID in module alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3 needs to be wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3 in module alias for acer-wmi is automatically loaded. Cc: Pali Rohár Cc: Carlos Corbacho Cc: Matthew Garrett Signed-off-by: Lee, Chun-Yi Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 5ea6c3477d17..ac4e7f83ce6c 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -89,7 +89,7 @@ MODULE_LICENSE("GPL"); #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); -MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); +MODULE_ALIAS("wmi:6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"); MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); enum acer_wmi_event_ids { -- cgit v1.2.2 From b569ab3911aca64841bd819720d2b241aa09d713 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 31 Mar 2011 15:22:33 -0700 Subject: thinkpad-acpi fails to load with newer Thinkpad X201s BIOS The new BIOS has a slightly different EC version string. From a1541710300b083a1a9acff2890d721d15ede62b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 13 Mar 2011 23:46:22 -0700 Subject: [PATCH] thinkpad-acpi: Some BIOS versions don't end in WW, remove check My X201s BIOS version string is 6QET46V1 (1.16 ). The EC version string is 6QHT28WW-1.09. The driver was requiring that both of these have 'WW' in positions 6 and 7. I don't know what the significance of having 'V1' there instead is, but removing the test makes the driver load on my machine. Signed-off-by: Keith Packard Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a08561f5349e..efb3b6b9bcdb 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -8618,8 +8618,7 @@ static bool __pure __init tpacpi_is_valid_fw_id(const char* const s, tpacpi_is_fw_digit(s[1]) && s[2] == t && s[3] == 'T' && tpacpi_is_fw_digit(s[4]) && - tpacpi_is_fw_digit(s[5]) && - s[6] == 'W' && s[7] == 'W'; + tpacpi_is_fw_digit(s[5]); } /* returns 0 - probe ok, or < 0 - probe error. -- cgit v1.2.2 From d4fabcc8e8ecac21262b1a5b9684fe415b128bd2 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 4 Apr 2011 14:22:11 +0100 Subject: sfc: Do not use efx_process_channel_now() in online self-test During self-tests we use efx_process_channel_now() to handle completion and other events synchronously. This disables interrupts and NAPI processing for the channel in question, but it may still be interrupted by another channel. A single socket may receive packets from multiple net devices or even multiple channels of the same net device, so this can result in deadlock on a socket lock. Receiving packets in process context will also result in incorrect classification by the network cgroup classifier. Therefore, we must only use efx_process_channel_now() in the offline loopback tests (which never deliver packets up the stack) and not for the online interrupt and event tests. For the interrupt test, there is no reason to process events. We only care that an interrupt is raised. For the event test, we want to know whether events have been received, and there may be many events ahead of the one we inject. Therefore remove efx_channel::magic_count and instead test whether efx_channel::eventq_read_ptr advances. This is currently an event queue index and might wrap around to exactly the same value, resulting in a false negative. Therefore move the masking to efx_event() and efx_nic_eventq_read_ack() so that it cannot wrap within the time of the test. The event test also tries to diagnose failures by checking whether an event was delivered without causing an interrupt. Add and use a helper function that only does this. Signed-off-by: Ben Hutchings --- drivers/net/sfc/efx.c | 4 +++- drivers/net/sfc/net_driver.h | 2 -- drivers/net/sfc/nic.c | 22 +++++++++++++++------- drivers/net/sfc/nic.h | 1 + drivers/net/sfc/selftest.c | 23 ++++------------------- 5 files changed, 23 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 0dc800b5a4ea..a3c2aab53de8 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -328,7 +328,8 @@ static int efx_poll(struct napi_struct *napi, int budget) * processing to finish, then directly poll (and ack ) the eventq. * Finally reenable NAPI and interrupts. * - * Since we are touching interrupts the caller should hold the suspend lock + * This is for use only during a loopback self-test. It must not + * deliver any packets up the stack as this can result in deadlock. */ void efx_process_channel_now(struct efx_channel *channel) { @@ -336,6 +337,7 @@ void efx_process_channel_now(struct efx_channel *channel) BUG_ON(channel->channel >= efx->n_channels); BUG_ON(!channel->enabled); + BUG_ON(!efx->loopback_selftest); /* Disable interrupts and wait for ISRs to complete */ efx_nic_disable_interrupts(efx); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index 9ffa9a6b55a0..191a311da2dc 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -330,7 +330,6 @@ enum efx_rx_alloc_method { * @eventq_mask: Event queue pointer mask * @eventq_read_ptr: Event queue read pointer * @last_eventq_read_ptr: Last event queue read pointer value. - * @magic_count: Event queue test event count * @irq_count: Number of IRQs since last adaptive moderation decision * @irq_mod_score: IRQ moderation score * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors @@ -360,7 +359,6 @@ struct efx_channel { unsigned int eventq_mask; unsigned int eventq_read_ptr; unsigned int last_eventq_read_ptr; - unsigned int magic_count; unsigned int irq_count; unsigned int irq_mod_score; diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index e8396614daf3..10f1cb79c147 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -84,7 +84,8 @@ static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, static inline efx_qword_t *efx_event(struct efx_channel *channel, unsigned int index) { - return ((efx_qword_t *) (channel->eventq.addr)) + index; + return ((efx_qword_t *) (channel->eventq.addr)) + + (index & channel->eventq_mask); } /* See if an event is present @@ -673,7 +674,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel) efx_dword_t reg; struct efx_nic *efx = channel->efx; - EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); + EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, + channel->eventq_read_ptr & channel->eventq_mask); efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, channel->channel); } @@ -908,7 +910,7 @@ efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event) code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC); if (code == EFX_CHANNEL_MAGIC_TEST(channel)) - ++channel->magic_count; + ; /* ignore */ else if (code == EFX_CHANNEL_MAGIC_FILL(channel)) /* The queue must be empty, so we won't receive any rx * events, so efx_process_channel() won't refill the @@ -1015,8 +1017,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget) /* Clear this event by marking it all ones */ EFX_SET_QWORD(*p_event); - /* Increment read pointer */ - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); @@ -1060,6 +1061,13 @@ out: return spent; } +/* Check whether an event is present in the eventq at the current + * read pointer. Only useful for self-test. + */ +bool efx_nic_event_present(struct efx_channel *channel) +{ + return efx_event_present(efx_event(channel, channel->eventq_read_ptr)); +} /* Allocate buffer table entries for event queue */ int efx_nic_probe_eventq(struct efx_channel *channel) @@ -1165,7 +1173,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; unsigned int read_ptr = channel->eventq_read_ptr; - unsigned int end_ptr = (read_ptr - 1) & channel->eventq_mask; + unsigned int end_ptr = read_ptr + channel->eventq_mask - 1; do { efx_qword_t *event = efx_event(channel, read_ptr); @@ -1205,7 +1213,7 @@ static void efx_poll_flush_events(struct efx_nic *efx) * it's ok to throw away every non-flush event */ EFX_SET_QWORD(*event); - read_ptr = (read_ptr + 1) & channel->eventq_mask; + ++read_ptr; } while (read_ptr != end_ptr); channel->eventq_read_ptr = read_ptr; diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index d9de1b647d41..a42db6e35be3 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -184,6 +184,7 @@ extern void efx_nic_fini_eventq(struct efx_channel *channel); extern void efx_nic_remove_eventq(struct efx_channel *channel); extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); extern void efx_nic_eventq_read_ack(struct efx_channel *channel); +extern bool efx_nic_event_present(struct efx_channel *channel); /* MAC/PHY */ extern void falcon_drain_tx_fifo(struct efx_nic *efx); diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 845808408924..50ad3bcaf68a 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -131,8 +131,6 @@ static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) static int efx_test_interrupts(struct efx_nic *efx, struct efx_self_tests *tests) { - struct efx_channel *channel; - netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); tests->interrupt = -1; @@ -140,15 +138,6 @@ static int efx_test_interrupts(struct efx_nic *efx, efx->last_irq_cpu = -1; smp_wmb(); - /* ACK each interrupting event queue. Receiving an interrupt due to - * traffic before a test event is raised is considered a pass */ - efx_for_each_channel(channel, efx) { - if (channel->work_pending) - efx_process_channel_now(channel); - if (efx->last_irq_cpu >= 0) - goto success; - } - efx_nic_generate_interrupt(efx); /* Wait for arrival of test interrupt. */ @@ -173,13 +162,13 @@ static int efx_test_eventq_irq(struct efx_channel *channel, struct efx_self_tests *tests) { struct efx_nic *efx = channel->efx; - unsigned int magic_count, count; + unsigned int read_ptr, count; tests->eventq_dma[channel->channel] = -1; tests->eventq_int[channel->channel] = -1; tests->eventq_poll[channel->channel] = -1; - magic_count = channel->magic_count; + read_ptr = channel->eventq_read_ptr; channel->efx->last_irq_cpu = -1; smp_wmb(); @@ -190,10 +179,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, do { schedule_timeout_uninterruptible(HZ / 100); - if (channel->work_pending) - efx_process_channel_now(channel); - - if (channel->magic_count != magic_count) + if (ACCESS_ONCE(channel->eventq_read_ptr) != read_ptr) goto eventq_ok; } while (++count < 2); @@ -211,8 +197,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, } /* Check to see if event was received even if interrupt wasn't */ - efx_process_channel_now(channel); - if (channel->magic_count != magic_count) { + if (efx_nic_event_present(channel)) { netif_err(efx, drv, efx->net_dev, "channel %d event was generated, but " "failed to trigger an interrupt\n", channel->channel); -- cgit v1.2.2 From 8a226e00eeed8db843d4a580013a49ae3559bcd7 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 29 Mar 2011 09:45:57 -0700 Subject: PCI: pci-label: Fix build failure when CONFIG_NLS is set to 'm' by allmodconfig Create a kconfig option symbol for PCI_LABEL and enable it when DMI || ACPI are enabled. Signed-off-by: Randy Dunlap Signed-off-by: Jesse Barnes --- drivers/pci/Kconfig | 4 +++- drivers/pci/Makefile | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index c8ff646c0b05..0fa466a91bf4 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -88,4 +88,6 @@ config PCI_IOAPIC depends on HOTPLUG default y -select NLS if (DMI || ACPI) +config PCI_LABEL + def_bool y if (DMI || ACPI) + select NLS diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98d61c8e984b..c85f744270a5 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,10 +56,10 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o # ACPI Related PCI FW Functions # ACPI _DSM provided firmware instance and string name # -obj-$(CONFIG_ACPI) += pci-acpi.o pci-label.o +obj-$(CONFIG_ACPI) += pci-acpi.o # SMBIOS provided firmware instance and labels -obj-$(CONFIG_DMI) += pci-label.o +obj-$(CONFIG_PCI_LABEL) += pci-label.o # Cardbus & CompactPCI use setup-bus obj-$(CONFIG_HOTPLUG) += setup-bus.o -- cgit v1.2.2 From d5627663f2088fa4be447fdcfd52bcb233448d85 Mon Sep 17 00:00:00 2001 From: Mathew McKernan Date: Tue, 12 Apr 2011 06:51:37 +0100 Subject: drm/i915/tv: Remember the detected TV type During detect() we would probe the connection bits to determine if there was a TV attached, and what video input type (Component, S-Video, Composite, etc) to use. However, we promptly discarded this vital bit of information and never propagated it to where it was used to determine the correct modes and setup the control registers. Fix it! This fixes a regression from 7b334fcb45b757ffb093696ca3de1b0c8b4a33f1. Reported-and-tested-by: Mathew McKernan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35977 Signed-off-by: Mathew McKernan Signed-off-by: Chris Wilson Cc: stable@kernel.org Acked-by: Paul Menzel Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_tv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 4256b8ef3947..0be2265d1f39 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1378,7 +1378,9 @@ intel_tv_detect(struct drm_connector *connector, bool force) if (type < 0) return connector_status_disconnected; + intel_tv->type = type; intel_tv_find_better_format(connector); + return connector_status_connected; } -- cgit v1.2.2 From 89ea42d716e1ee94f643ecdc516d90a4111ec135 Mon Sep 17 00:00:00 2001 From: Mathew McKernan Date: Tue, 12 Apr 2011 06:51:38 +0100 Subject: drm/i915/tv: Only poll for TV connections As a probe for a TV connection modifies the TV_CTL register, it causes a loss of sync and a regular glitch on the output. This is highly undesirable when using the TV, so only poll for TV connections and wait for an explicit query for detecting the disconnection event. Reported-by: Mathew McKernan Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35977 Signed-off-by: Mathew McKernan Signed-off-by: Chris Wilson Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_tv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 0be2265d1f39..f5848cb91562 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1672,8 +1672,7 @@ intel_tv_init(struct drm_device *dev) * * More recent chipsets favour HDMI rather than integrated S-Video. */ - connector->polled = - DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + connector->polled = DRM_CONNECTOR_POLL_CONNECT; drm_connector_init(dev, connector, &intel_tv_connector_funcs, DRM_MODE_CONNECTOR_SVIDEO); -- cgit v1.2.2 From ccacfec6cc22157971bd970486fd3fd4972b8e2e Mon Sep 17 00:00:00 2001 From: Sitsofe Wheeler Date: Tue, 12 Apr 2011 06:51:39 +0100 Subject: drm/i915/tv: Fix modeset flickering introduced in 7f58aabc3 The tidy ups in 7f58aabc369014fda3a4a33604ba0a1b63b941ac ("drm/i915: cleanup per-pipe reg usage") changed intel_crtc->plane to intel_crtc->pipe in intel_tv_mode_set(). This caused the screen to quickly turn off before returning whenever modesetting/mode probing took place on my 915GM EeePC 900 creating a flickering effect. This patch changes intel_crtc->pipe back to intel_crtc->plane which solves the problem for me. References: https://bugs.freedesktop.org/show_bug.cgi?id=35903 Signed-off-by: Sitsofe Wheeler Cc: Jesse Barnes Signed-off-by: Chris Wilson Humbly-acked-by: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_tv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index f5848cb91562..6b22c1dcc015 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1151,10 +1151,10 @@ intel_tv_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, (video_levels->blank << TV_BLANK_LEVEL_SHIFT))); { int pipeconf_reg = PIPECONF(pipe); - int dspcntr_reg = DSPCNTR(pipe); + int dspcntr_reg = DSPCNTR(intel_crtc->plane); int pipeconf = I915_READ(pipeconf_reg); int dspcntr = I915_READ(dspcntr_reg); - int dspbase_reg = DSPADDR(pipe); + int dspbase_reg = DSPADDR(intel_crtc->plane); int xpos = 0x0, ypos = 0x0; unsigned int xsize, ysize; /* Pipe must be off here */ -- cgit v1.2.2 From f6e5b1603b8bb7131b6778d0d4e2e5dda120a379 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 12 Apr 2011 18:06:51 +0100 Subject: drm/i915: Sanitize the output registers after resume Similar to booting, we need to inspect the state left by the BIOS and remove any conflicting bits before we take over. The example reported by Seth Forshee is very similar to the bug we encountered with the state left by grub2, that the crtc pipe<->planning mapping was reversed from our expectations and so we failed to turn off the outputs when booting or, in this case, resuming. This may be in fact the same bug, but triggered at resume time. This patch rearranges the code we already have to clear up the conflicting state upon init and calls it from reset (which is called after we have lost control of the hardware, i.e. along both the boot and resume paths) instead. Reported-and-tested-by: Seth Forshee Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=35796 Signed-off-by: Chris Wilson Cc: stable@kernel.org Reviewed-by: Keith Packard Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 68 +++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 432fc04c6bff..4fc21e047a2d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6215,36 +6215,6 @@ cleanup_work: return ret; } -static void intel_crtc_reset(struct drm_crtc *crtc) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* Reset flags back to the 'unknown' status so that they - * will be correctly set on the initial modeset. - */ - intel_crtc->dpms_mode = -1; -} - -static struct drm_crtc_helper_funcs intel_helper_funcs = { - .dpms = intel_crtc_dpms, - .mode_fixup = intel_crtc_mode_fixup, - .mode_set = intel_crtc_mode_set, - .mode_set_base = intel_pipe_set_base, - .mode_set_base_atomic = intel_pipe_set_base_atomic, - .load_lut = intel_crtc_load_lut, - .disable = intel_crtc_disable, -}; - -static const struct drm_crtc_funcs intel_crtc_funcs = { - .reset = intel_crtc_reset, - .cursor_set = intel_crtc_cursor_set, - .cursor_move = intel_crtc_cursor_move, - .gamma_set = intel_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, - .destroy = intel_crtc_destroy, - .page_flip = intel_crtc_page_flip, -}; - static void intel_sanitize_modesetting(struct drm_device *dev, int pipe, int plane) { @@ -6281,6 +6251,42 @@ static void intel_sanitize_modesetting(struct drm_device *dev, intel_disable_pipe(dev_priv, pipe); } +static void intel_crtc_reset(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* Reset flags back to the 'unknown' status so that they + * will be correctly set on the initial modeset. + */ + intel_crtc->dpms_mode = -1; + + /* We need to fix up any BIOS configuration that conflicts with + * our expectations. + */ + intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); +} + +static struct drm_crtc_helper_funcs intel_helper_funcs = { + .dpms = intel_crtc_dpms, + .mode_fixup = intel_crtc_mode_fixup, + .mode_set = intel_crtc_mode_set, + .mode_set_base = intel_pipe_set_base, + .mode_set_base_atomic = intel_pipe_set_base_atomic, + .load_lut = intel_crtc_load_lut, + .disable = intel_crtc_disable, +}; + +static const struct drm_crtc_funcs intel_crtc_funcs = { + .reset = intel_crtc_reset, + .cursor_set = intel_crtc_cursor_set, + .cursor_move = intel_crtc_cursor_move, + .gamma_set = intel_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = intel_crtc_destroy, + .page_flip = intel_crtc_page_flip, +}; + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -6330,8 +6336,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer, (unsigned long)intel_crtc); - - intel_sanitize_modesetting(dev, intel_crtc->pipe, intel_crtc->plane); } int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, -- cgit v1.2.2 From 5882da02e9d9089b7e8c739f3e774aaeeff8b7ba Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 8 Apr 2011 20:13:18 +0200 Subject: ath9k_hw: fix stopping rx DMA during resets During PHY errors, the MAC can sometimes fail to enter an idle state on older hardware (before AR9380) after an rx stop has been requested. This typically shows up in the kernel log with messages like these: ath: Could not stop RX, we could be confusing the DMA engine when we start RX up ------------[ cut here ]------------ WARNING: at drivers/net/wireless/ath/ath9k/recv.c:504 ath_stoprecv+0xcc/0xf0 [ath9k]() Call Trace: [<8023f0e8>] dump_stack+0x8/0x34 [<80075050>] warn_slowpath_common+0x78/0xa4 [<80075094>] warn_slowpath_null+0x18/0x24 [<80d66d60>] ath_stoprecv+0xcc/0xf0 [ath9k] [<80d642cc>] ath_set_channel+0xbc/0x270 [ath9k] [<80d65254>] ath_radio_disable+0x4a4/0x7fc [ath9k] When this happens, the state that the MAC enters is easy to identify and does not result in bogus DMA traffic, however to ensure a working state after a channel change, the hardware should still be reset. This patch adds detection for this specific MAC state, after which the above warnings completely disappear in my tests. Signed-off-by: Felix Fietkau Cc: stable@kernel.org Cc: Kyungwan Nam Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hw.c | 9 --------- drivers/net/wireless/ath/ath9k/mac.c | 25 ++++++++++++++++++++++--- drivers/net/wireless/ath/ath9k/mac.h | 2 +- drivers/net/wireless/ath/ath9k/recv.c | 6 +++--- 4 files changed, 26 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 1ec9bcd6b281..c95bc5cc1a1f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1254,15 +1254,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ah->txchainmask = common->tx_chainmask; ah->rxchainmask = common->rx_chainmask; - if ((common->bus_ops->ath_bus_type != ATH_USB) && !ah->chip_fullsleep) { - ath9k_hw_abortpcurecv(ah); - if (!ath9k_hw_stopdmarecv(ah)) { - ath_dbg(common, ATH_DBG_XMIT, - "Failed to stop receive dma\n"); - bChannelChange = false; - } - } - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 562257ac52cf..edc1cbbfecaf 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -751,28 +751,47 @@ void ath9k_hw_abortpcurecv(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_abortpcurecv); -bool ath9k_hw_stopdmarecv(struct ath_hw *ah) +bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset) { #define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */ #define AH_RX_TIME_QUANTUM 100 /* usec */ struct ath_common *common = ath9k_hw_common(ah); + u32 mac_status, last_mac_status = 0; int i; + /* Enable access to the DMA observation bus */ + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Wait for rx enable bit to go low */ for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) { if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0) break; + + if (!AR_SREV_9300_20_OR_LATER(ah)) { + mac_status = REG_READ(ah, AR_DMADBG_7) & 0x7f0; + if (mac_status == 0x1c0 && mac_status == last_mac_status) { + *reset = true; + break; + } + + last_mac_status = mac_status; + } + udelay(AH_TIME_QUANTUM); } if (i == 0) { ath_err(common, - "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + "DMA failed to stop in %d ms AR_CR=0x%08x AR_DIAG_SW=0x%08x DMADBG_7=0x%08x\n", AH_RX_STOP_DMA_TIMEOUT / 1000, REG_READ(ah, AR_CR), - REG_READ(ah, AR_DIAG_SW)); + REG_READ(ah, AR_DIAG_SW), + REG_READ(ah, AR_DMADBG_7)); return false; } else { return true; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index b2b2ff852c32..c2a59386fb9c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -695,7 +695,7 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp); void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning); void ath9k_hw_abortpcurecv(struct ath_hw *ah); -bool ath9k_hw_stopdmarecv(struct ath_hw *ah); +bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset); int ath9k_hw_beaconq_setup(struct ath_hw *ah); /* Interrupt Handling */ diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index a9c3f4672aa0..dcd19bc337d1 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -486,12 +486,12 @@ start_recv: bool ath_stoprecv(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - bool stopped; + bool stopped, reset = false; spin_lock_bh(&sc->rx.rxbuflock); ath9k_hw_abortpcurecv(ah); ath9k_hw_setrxfilter(ah, 0); - stopped = ath9k_hw_stopdmarecv(ah); + stopped = ath9k_hw_stopdmarecv(ah, &reset); if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_edma_stop_recv(sc); @@ -506,7 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc) "confusing the DMA engine when we start RX up\n"); ATH_DBG_WARN_ON_ONCE(!stopped); } - return stopped; + return stopped || reset; } void ath_flushrecv(struct ath_softc *sc) -- cgit v1.2.2 From 50f6871218802be528961e24487f00c203a5c3c7 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Mon, 11 Apr 2011 22:56:55 +0530 Subject: ath9k_htc: Fix ethtool reporting Pass the correct module name and device interface so that ethtool can display the proper values. The firmware version will be fixed later on when the FW can actually report a version. :) Reported-by: Richard Farina Signed-off-by: Sujith Manoharan Tested-by: Richard Farina Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/hif_usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index f1b8af64569c..2d10239ce829 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1040,7 +1040,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface, } ret = ath9k_htc_hw_init(hif_dev->htc_handle, - &hif_dev->udev->dev, hif_dev->device_id, + &interface->dev, hif_dev->device_id, hif_dev->udev->product, id->driver_info); if (ret) { ret = -EINVAL; @@ -1158,7 +1158,7 @@ fail_resume: #endif static struct usb_driver ath9k_hif_usb_driver = { - .name = "ath9k_hif_usb", + .name = KBUILD_MODNAME, .probe = ath9k_hif_usb_probe, .disconnect = ath9k_hif_usb_disconnect, #ifdef CONFIG_PM -- cgit v1.2.2 From 0e08785845093ef4ed220463a739bc8d0db95de7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 12 Apr 2011 05:39:51 +0000 Subject: connector: fix skb double free in cn_rx_skb() When a skb is delivered to a registered callback, cn_call_callback() incorrectly returns -ENODEV after freeing the skb, causing cn_rx_skb() to free the skb a second time. Reported-by: Eric B Munson Signed-off-by: Patrick McHardy Tested-by: Eric B Munson Signed-off-by: David S. Miller --- drivers/connector/connector.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index d77005849af8..219d88a0eeae 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -142,6 +142,7 @@ static int cn_call_callback(struct sk_buff *skb) cbq->callback(msg, nsp); kfree_skb(skb); cn_queue_release_callback(cbq); + err = 0; } return err; -- cgit v1.2.2 From efa2ad8918afc2f5e4ea533110758b26991f1937 Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Tue, 12 Apr 2011 05:30:40 +0000 Subject: net/sis900: store MAC into perm_addr for SiS 900, 630E, 635 and 96x variants Signed-off-by: Otavio Salvador Signed-off-by: David S. Miller --- drivers/net/sis900.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index cb317cd069ff..484f795a779d 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -240,7 +240,8 @@ static const struct ethtool_ops sis900_ethtool_ops; * @net_dev: the net device to get address for * * Older SiS900 and friends, use EEPROM to store MAC address. - * MAC address is read from read_eeprom() into @net_dev->dev_addr. + * MAC address is read from read_eeprom() into @net_dev->dev_addr and + * @net_dev->perm_addr. */ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) @@ -261,6 +262,9 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + return 1; } @@ -271,7 +275,8 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de * * SiS630E model, use APC CMOS RAM to store MAC address. * APC CMOS RAM is accessed through ISA bridge. - * MAC address is read into @net_dev->dev_addr. + * MAC address is read into @net_dev->dev_addr and + * @net_dev->perm_addr. */ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, @@ -296,6 +301,10 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, outb(0x09 + i, 0x70); ((u8 *)(net_dev->dev_addr))[i] = inb(0x71); } + + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40); pci_dev_put(isa_bridge); @@ -310,7 +319,7 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, * * SiS635 model, set MAC Reload Bit to load Mac address from APC * to rfdr. rfdr is accessed through rfcr. MAC address is read into - * @net_dev->dev_addr. + * @net_dev->dev_addr and @net_dev->perm_addr. */ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, @@ -334,6 +343,9 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, *( ((u16 *)net_dev->dev_addr) + i) = inw(ioaddr + rfdr); } + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + /* enable packet filtering */ outl(rfcrSave | RFEN, rfcr + ioaddr); @@ -353,7 +365,7 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev, * EEDONE signal to refuse EEPROM access by LAN. * The EEPROM map of SiS962 or SiS963 is different to SiS900. * The signature field in SiS962 or SiS963 spec is meaningless. - * MAC address is read into @net_dev->dev_addr. + * MAC address is read into @net_dev->dev_addr and @net_dev->perm_addr. */ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, @@ -372,6 +384,9 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, for (i = 0; i < 3; i++) ((u16 *)(net_dev->dev_addr))[i] = read_eeprom(ioaddr, i+EEPROMMACAddr); + /* Store MAC Address in perm_addr */ + memcpy(net_dev->perm_addr, net_dev->dev_addr, ETH_ALEN); + outl(EEDONE, ee_addr); return 1; } else { -- cgit v1.2.2 From 3d894a9c1959acaa6981283619b465f75f7e535e Mon Sep 17 00:00:00 2001 From: Otavio Salvador Date: Tue, 12 Apr 2011 05:30:41 +0000 Subject: net/natsami: store MAC into perm_addr Signed-off-by: Otavio Salvador Signed-off-by: David S. Miller --- drivers/net/natsemi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index aa2813e06d00..1074231f0a0d 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -860,6 +860,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, prev_eedata = eedata; } + /* Store MAC Address in perm_addr */ + memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); + dev->base_addr = (unsigned long __force) ioaddr; dev->irq = irq; -- cgit v1.2.2 From fcfa060468a4edcf776f0c1211d826d5de1668c1 Mon Sep 17 00:00:00 2001 From: Neil Turton Date: Mon, 11 Apr 2011 11:42:43 +0100 Subject: sfc: Use rmb() to ensure reads occur in order Enabling write-combining may also enable read reordering. The BIU is only guaranteed to read from a 128-bit CSR or 64-bit SRAM word when the host reads from its lowest address; otherwise the BIU may use the latched value. Therefore we need to reinstate the read memory barriers after the first read operation for each CSR or SRAM word. Signed-off-by; Ben Hutchings --- drivers/net/sfc/io.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/sfc/io.h b/drivers/net/sfc/io.h index d9d8c2ef1074..cc978803d484 100644 --- a/drivers/net/sfc/io.h +++ b/drivers/net/sfc/io.h @@ -152,6 +152,7 @@ static inline void efx_reado(struct efx_nic *efx, efx_oword_t *value, spin_lock_irqsave(&efx->biu_lock, flags); value->u32[0] = _efx_readd(efx, reg + 0); + rmb(); value->u32[1] = _efx_readd(efx, reg + 4); value->u32[2] = _efx_readd(efx, reg + 8); value->u32[3] = _efx_readd(efx, reg + 12); @@ -174,6 +175,7 @@ static inline void efx_sram_readq(struct efx_nic *efx, void __iomem *membase, value->u64[0] = (__force __le64)__raw_readq(membase + addr); #else value->u32[0] = (__force __le32)__raw_readl(membase + addr); + rmb(); value->u32[1] = (__force __le32)__raw_readl(membase + addr + 4); #endif spin_unlock_irqrestore(&efx->biu_lock, flags); -- cgit v1.2.2 From 92656d707e961c88b6f931038c7dc41790a52e1e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 13:32:13 -0400 Subject: drm/radeon/kms: clean up gart dummy page handling As per Konrad's original patch, the dummy page used by the gart code and allocated in radeon_gart_init() was not freed properly in radeon_gart_fini(). At the same time r6xx and newer allocated and freed the dummy page on their own. So to do Konrad's patch one better, just remove the allocation and freeing of the dummy page in the r6xx, 7xx, evergreen, and ni code and allocate and free in the gart_init/fini() functions for all asics. Cc: Jerome Glisse Signed-off-by: Alex Deucher Acked-by: Konrad Rzeszutek Wilk Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 4 ---- drivers/gpu/drm/radeon/r600.c | 4 ---- drivers/gpu/drm/radeon/radeon_gart.c | 2 ++ drivers/gpu/drm/radeon/rv770.c | 4 ---- 4 files changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 0b0cc74c08c0..cff7144a4ccc 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3036,9 +3036,6 @@ int evergreen_init(struct radeon_device *rdev) { int r; - r = radeon_dummy_page_init(rdev); - if (r) - return r; /* This don't do much */ r = radeon_gem_init(rdev); if (r) @@ -3150,7 +3147,6 @@ void evergreen_fini(struct radeon_device *rdev) radeon_atombios_fini(rdev); kfree(rdev->bios); rdev->bios = NULL; - radeon_dummy_page_fini(rdev); } static void evergreen_pcie_gen2_enable(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index be271c42de4d..304fc76b5fab 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -2509,9 +2509,6 @@ int r600_init(struct radeon_device *rdev) { int r; - r = radeon_dummy_page_init(rdev); - if (r) - return r; if (r600_debugfs_mc_info_init(rdev)) { DRM_ERROR("Failed to register debugfs file for mc !\n"); } @@ -2625,7 +2622,6 @@ void r600_fini(struct radeon_device *rdev) radeon_atombios_fini(rdev); kfree(rdev->bios); rdev->bios = NULL; - radeon_dummy_page_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index f0534ef2f331..8a955bbdb608 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -285,4 +285,6 @@ void radeon_gart_fini(struct radeon_device *rdev) rdev->gart.pages = NULL; rdev->gart.pages_addr = NULL; rdev->gart.ttm_alloced = NULL; + + radeon_dummy_page_fini(rdev); } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index b974ac7df8df..4faa2e56bef2 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1255,9 +1255,6 @@ int rv770_init(struct radeon_device *rdev) { int r; - r = radeon_dummy_page_init(rdev); - if (r) - return r; /* This don't do much */ r = radeon_gem_init(rdev); if (r) @@ -1372,7 +1369,6 @@ void rv770_fini(struct radeon_device *rdev) radeon_atombios_fini(rdev); kfree(rdev->bios); rdev->bios = NULL; - radeon_dummy_page_fini(rdev); } static void rv770_pcie_gen2_enable(struct radeon_device *rdev) -- cgit v1.2.2 From 71e16bfbd2b1c63d4d97cc5059694c9346aee340 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 13:33:27 -0400 Subject: drm/radeon/kms: fix suspend on rv530 asics Apparently only rv515 asics need the workaround added in f24d86f1a49505cdea56728b853a5d0a3f8e3d11 (drm/radeon/kms: fix resume regression for some r5xx laptops). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=34709 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 258fa5e7a2d9..d71d375149f8 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -32,6 +32,7 @@ #include "atom.h" #include "atom-names.h" #include "atom-bits.h" +#include "radeon.h" #define ATOM_COND_ABOVE 0 #define ATOM_COND_ABOVEOREQUAL 1 @@ -101,7 +102,9 @@ static void debug_print_spaces(int n) static uint32_t atom_iio_execute(struct atom_context *ctx, int base, uint32_t index, uint32_t data) { + struct radeon_device *rdev = ctx->card->dev->dev_private; uint32_t temp = 0xCDCDCDCD; + while (1) switch (CU8(base)) { case ATOM_IIO_NOP: @@ -112,7 +115,8 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, base += 3; break; case ATOM_IIO_WRITE: - (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); + if (rdev->family == CHIP_RV515) + (void)ctx->card->ioreg_read(ctx->card, CU16(base + 1)); ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); base += 3; break; -- cgit v1.2.2 From b4df8be1048eb6c8c5a8bd1646f5989fd34b549e Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 13:40:18 -0400 Subject: drm/radeon/kms: fix pcie_p callbacks on btc and cayman btc and cayman asics use the same callback for pcie port registers. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_asic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index eb888ee5f674..ca576191d058 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -94,7 +94,7 @@ static void radeon_register_accessor_init(struct radeon_device *rdev) rdev->mc_rreg = &rs600_mc_rreg; rdev->mc_wreg = &rs600_mc_wreg; } - if ((rdev->family >= CHIP_R600) && (rdev->family <= CHIP_HEMLOCK)) { + if (rdev->family >= CHIP_R600) { rdev->pciep_rreg = &r600_pciep_rreg; rdev->pciep_wreg = &r600_pciep_wreg; } -- cgit v1.2.2 From 8a83ec5ee824a6bd431b49bdb2428c8bf88f03eb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 14:49:23 -0400 Subject: drm/radeon/kms: add voltage type to atom set voltage function This is needed for setting voltages other than vddc. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- drivers/gpu/drm/radeon/radeon.h | 2 +- drivers/gpu/drm/radeon/radeon_atombios.c | 10 +++++----- drivers/gpu/drm/radeon/radeon_pm.c | 7 +++++-- drivers/gpu/drm/radeon/rs600.c | 2 +- drivers/gpu/drm/radeon/rv770.c | 2 +- 7 files changed, 15 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index cff7144a4ccc..f2448170086e 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -122,7 +122,7 @@ void evergreen_pm_misc(struct radeon_device *rdev) if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { - radeon_atom_set_voltage(rdev, voltage->voltage); + radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG("Setting: v: %d\n", voltage->voltage); } diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 304fc76b5fab..15d58292677a 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -587,7 +587,7 @@ void r600_pm_misc(struct radeon_device *rdev) if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { - radeon_atom_set_voltage(rdev, voltage->voltage); + radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG_DRIVER("Setting: v: %d\n", voltage->voltage); } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 93f536594c73..99557407cdce 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -177,7 +177,7 @@ void radeon_pm_suspend(struct radeon_device *rdev); void radeon_pm_resume(struct radeon_device *rdev); void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); -void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type); void rs690_pm_info(struct radeon_device *rdev); extern int rv6xx_get_temp(struct radeon_device *rdev); extern int rv770_get_temp(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 99768d9d91da..330a5b56602b 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2577,25 +2577,25 @@ union set_voltage { struct _SET_VOLTAGE_PARAMETERS_V2 v2; }; -void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level) +void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type) { union set_voltage args; int index = GetIndexIntoMasterTable(COMMAND, SetVoltage); - u8 frev, crev, volt_index = level; + u8 frev, crev, volt_index = voltage_level; if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) return; switch (crev) { case 1: - args.v1.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v1.ucVoltageType = voltage_type; args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE; args.v1.ucVoltageIndex = volt_index; break; case 2: - args.v2.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC; + args.v2.ucVoltageType = voltage_type; args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE; - args.v2.usVoltageLevel = cpu_to_le16(level); + args.v2.usVoltageLevel = cpu_to_le16(voltage_level); break; default: DRM_ERROR("Unknown table version %d, %d\n", frev, crev); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 08de669e025a..4010571def3a 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -23,6 +23,7 @@ #include "drmP.h" #include "radeon.h" #include "avivod.h" +#include "atom.h" #ifdef CONFIG_ACPI #include #endif @@ -535,7 +536,8 @@ void radeon_pm_resume(struct radeon_device *rdev) /* set up the default clocks if the MC ucode is loaded */ if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { if (rdev->pm.default_vddc) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddc); + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, + SET_VOLTAGE_TYPE_ASIC_VDDC); if (rdev->pm.default_sclk) radeon_set_engine_clock(rdev, rdev->pm.default_sclk); if (rdev->pm.default_mclk) @@ -585,7 +587,8 @@ int radeon_pm_init(struct radeon_device *rdev) /* set up the default clocks if the MC ucode is loaded */ if (ASIC_IS_DCE5(rdev) && rdev->mc_fw) { if (rdev->pm.default_vddc) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddc); + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, + SET_VOLTAGE_TYPE_ASIC_VDDC); if (rdev->pm.default_sclk) radeon_set_engine_clock(rdev, rdev->pm.default_sclk); if (rdev->pm.default_mclk) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 876cebc4b8ba..6e3b11e5abbe 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -114,7 +114,7 @@ void rs600_pm_misc(struct radeon_device *rdev) udelay(voltage->delay); } } else if (voltage->type == VOLTAGE_VDDC) - radeon_atom_set_voltage(rdev, voltage->vddc_id); + radeon_atom_set_voltage(rdev, voltage->vddc_id, SET_VOLTAGE_TYPE_ASIC_VDDC); dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH); dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4faa2e56bef2..ef8a5babe9f7 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -106,7 +106,7 @@ void rv770_pm_misc(struct radeon_device *rdev) if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { if (voltage->voltage != rdev->pm.current_vddc) { - radeon_atom_set_voltage(rdev, voltage->voltage); + radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; DRM_DEBUG("Setting: v: %d\n", voltage->voltage); } -- cgit v1.2.2 From 2feea49ae34a2fcea1035136b85f5eaca56f5cd0 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 12 Apr 2011 14:49:24 -0400 Subject: drm/radeon/kms: properly program vddci on evergreen+ Change vddci as well as vddc when changing power modes on evergreen/ni. Also, properly set vddci on boot up for ni cards. The vbios only sets the limited clocks and voltages on boot until the mc ucode is loaded. This should fix stability problems on some btc cards. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 11 ++++++++--- drivers/gpu/drm/radeon/radeon.h | 10 +++++++--- drivers/gpu/drm/radeon/radeon_atombios.c | 20 ++++++++++++++------ drivers/gpu/drm/radeon/radeon_pm.c | 4 ++++ 4 files changed, 33 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f2448170086e..3453910ee0f3 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -120,11 +120,16 @@ void evergreen_pm_misc(struct radeon_device *rdev) struct radeon_power_state *ps = &rdev->pm.power_state[req_ps_idx]; struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage; - if ((voltage->type == VOLTAGE_SW) && voltage->voltage) { - if (voltage->voltage != rdev->pm.current_vddc) { + if (voltage->type == VOLTAGE_SW) { + if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) { radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC); rdev->pm.current_vddc = voltage->voltage; - DRM_DEBUG("Setting: v: %d\n", voltage->voltage); + DRM_DEBUG("Setting: vddc: %d\n", voltage->voltage); + } + if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) { + radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI); + rdev->pm.current_vddci = voltage->vddci; + DRM_DEBUG("Setting: vddci: %d\n", voltage->vddci); } } } diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 99557407cdce..ba643b576054 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -767,7 +767,9 @@ struct radeon_voltage { u8 vddci_id; /* index into vddci voltage table */ bool vddci_enabled; /* r6xx+ sw */ - u32 voltage; + u16 voltage; + /* evergreen+ vddci */ + u16 vddci; }; /* clock mode flags */ @@ -835,10 +837,12 @@ struct radeon_pm { int default_power_state_index; u32 current_sclk; u32 current_mclk; - u32 current_vddc; + u16 current_vddc; + u16 current_vddci; u32 default_sclk; u32 default_mclk; - u32 default_vddc; + u16 default_vddc; + u16 default_vddci; struct radeon_i2c_chan *i2c_bus; /* selected pm method */ enum radeon_pm_method pm_method; diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 330a5b56602b..f5d12fb103fa 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2176,24 +2176,27 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r } } -static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev) +static void radeon_atombios_get_default_voltages(struct radeon_device *rdev, + u16 *vddc, u16 *vddci) { struct radeon_mode_info *mode_info = &rdev->mode_info; int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); u8 frev, crev; u16 data_offset; union firmware_info *firmware_info; - u16 vddc = 0; + + *vddc = 0; + *vddci = 0; if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { firmware_info = (union firmware_info *)(mode_info->atom_context->bios + data_offset); - vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); + *vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage); + if ((frev == 2) && (crev >= 2)) + *vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage); } - - return vddc; } static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, @@ -2203,7 +2206,9 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde int j; u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); u32 misc2 = le16_to_cpu(non_clock_info->usClassification); - u16 vddc = radeon_atombios_get_default_vddc(rdev); + u16 vddc, vddci; + + radeon_atombios_get_default_voltages(rdev, &vddc, &vddci); rdev->pm.power_state[state_index].misc = misc; rdev->pm.power_state[state_index].misc2 = misc2; @@ -2244,6 +2249,7 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk; rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk; rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage; + rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci; } else { /* patch the table values with the default slck/mclk from firmware info */ for (j = 0; j < mode_index; j++) { @@ -2286,6 +2292,8 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, VOLTAGE_SW; rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = le16_to_cpu(clock_info->evergreen.usVDDC); + rdev->pm.power_state[state_index].clock_info[mode_index].voltage.vddci = + le16_to_cpu(clock_info->evergreen.usVDDCI); } else { sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); sclk |= clock_info->r600.ucEngineClockHigh << 16; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 4010571def3a..86eda1ea94df 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -538,6 +538,9 @@ void radeon_pm_resume(struct radeon_device *rdev) if (rdev->pm.default_vddc) radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, SET_VOLTAGE_TYPE_ASIC_VDDC); + if (rdev->pm.default_vddci) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, + SET_VOLTAGE_TYPE_ASIC_VDDCI); if (rdev->pm.default_sclk) radeon_set_engine_clock(rdev, rdev->pm.default_sclk); if (rdev->pm.default_mclk) @@ -550,6 +553,7 @@ void radeon_pm_resume(struct radeon_device *rdev) rdev->pm.current_sclk = rdev->pm.default_sclk; rdev->pm.current_mclk = rdev->pm.default_mclk; rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; -- cgit v1.2.2 From cbf15bdbbdaec3b2e3b4f476803a6149707d1a1f Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 12 Apr 2011 14:27:47 +0400 Subject: i915: select VIDEO_OUTPUT_CONTROL for ACPI_VIDEO fix Kconfig warning: (DRM_I915 && STUB_POULSBO) selects ACPI_VIDEO which has unmet direct dependencies (ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT) Signed-off-by: Konstantin Khlebnikov Signed-off-by: Dave Airlie --- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/stub/Kconfig | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index a6feb78c404c..c58f691ec3ce 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -96,6 +96,7 @@ config DRM_I915 # i915 depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick select BACKLIGHT_CLASS_DEVICE if ACPI + select VIDEO_OUTPUT_CONTROL if ACPI select INPUT if ACPI select ACPI_VIDEO if ACPI select ACPI_BUTTON if ACPI diff --git a/drivers/gpu/stub/Kconfig b/drivers/gpu/stub/Kconfig index 70e60a4bb678..419917955bf6 100644 --- a/drivers/gpu/stub/Kconfig +++ b/drivers/gpu/stub/Kconfig @@ -5,6 +5,7 @@ config STUB_POULSBO # Poulsbo stub depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick select BACKLIGHT_CLASS_DEVICE if ACPI + select VIDEO_OUTPUT_CONTROL if ACPI select INPUT if ACPI select ACPI_VIDEO if ACPI select THERMAL if ACPI -- cgit v1.2.2 From d87dfdbfc91c5e37288e7e8f7afdd992ba61a60d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Apr 2011 09:15:09 +1000 Subject: Revert "ttm: Utilize the DMA API for pages that have TTM_PAGE_FLAG_DMA32 set." This reverts commit 69a07f0b117a40fcc1a479358d8e1f41793617f2. We've tracked a number of problems back to this, and Thomas thinks we should redesign this for .40/41 anyways so I'm happy to revert it. Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index 737a2a2e46a5..9d9d92945f8c 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -683,22 +683,14 @@ int ttm_get_pages(struct list_head *pages, int flags, gfp_flags |= GFP_HIGHUSER; for (r = 0; r < count; ++r) { - if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) { - void *addr; - addr = dma_alloc_coherent(NULL, PAGE_SIZE, - &dma_address[r], - gfp_flags); - if (addr == NULL) - return -ENOMEM; - p = virt_to_page(addr); - } else - p = alloc_page(gfp_flags); + p = alloc_page(gfp_flags); if (!p) { printk(KERN_ERR TTM_PFX "Unable to allocate page."); return -ENOMEM; } + list_add(&p->lru, pages); } return 0; @@ -746,24 +738,12 @@ void ttm_put_pages(struct list_head *pages, unsigned page_count, int flags, unsigned long irq_flags; struct ttm_page_pool *pool = ttm_get_pool(flags, cstate); struct page *p, *tmp; - unsigned r; if (pool == NULL) { /* No pool for this memory type so free the pages */ - r = page_count-1; list_for_each_entry_safe(p, tmp, pages, lru) { - if ((flags & TTM_PAGE_FLAG_DMA32) && dma_address) { - void *addr = page_address(p); - WARN_ON(!addr || !dma_address[r]); - if (addr) - dma_free_coherent(NULL, PAGE_SIZE, - addr, - dma_address[r]); - dma_address[r] = 0; - } else - __free_page(p); - r--; + __free_page(p); } /* Make the pages list empty */ INIT_LIST_HEAD(pages); -- cgit v1.2.2 From 2582b6efceb43dce63b4a1090d289934067a972d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 13 Apr 2011 09:20:24 +1000 Subject: Revert "i915: restore only the mode of this driver on lastclose" This reverts commit 0a0883c8433c743dad0a4d9ebe2717558f2c209e. this was in my tree by accident, I meant to rebase it out and didn't realise in time. Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_fb.c | 16 ---------------- 3 files changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 12876f2795d2..72730377a01b 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { - intel_fb_restore_mode(dev); + drm_fb_helper_restore(); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 1d20712d527f..f5b0d8306d83 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,5 +338,4 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); -extern void intel_fb_restore_mode(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 96a45c4e9a16..512782728e51 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -264,19 +264,3 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } - -void intel_fb_restore_mode(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - int ret, i; - - if (!dev_priv->fbdev) - return; - - for (i = 0; i < dev_priv->fbdev->helper.crtc_count; i++) { - struct drm_mode_set *mode_set = &dev_priv->fbdev->helper.crtc_info[i].mode_set; - ret = drm_crtc_helper_set_config(mode_set); - if (ret) - DRM_DEBUG("failed to restore crtc mode\n"); - } -} -- cgit v1.2.2 From 7db6a7fa09884b34d2a5d4e6e4ed58664a5f0cf8 Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Tue, 12 Apr 2011 18:39:39 +0800 Subject: ARM: pxa: convert incorrect IRQ_TO_IRQ() to irq_to_gpio() This fixes the failure to register the IRQ_RTCAlrm alarm as a wakeup event. It is misinterpreted as a gpio irq not a PWER bitmask. Fixed this by converting the incorrect IRQ_TO_IRQ() to a correct version of irq_to_gpio(). Reported-by: Nick Bane Signed-off-by: Eric Miao --- drivers/pcmcia/pxa2xx_trizeps4.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c index 5bb4e1a94d25..b829e655457b 100644 --- a/drivers/pcmcia/pxa2xx_trizeps4.c +++ b/drivers/pcmcia/pxa2xx_trizeps4.c @@ -69,15 +69,15 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) for (i = 0; i < ARRAY_SIZE(irqs); i++) { if (irqs[i].sock != skt->nr) continue; - if (gpio_request(IRQ_TO_GPIO(irqs[i].irq), irqs[i].str) < 0) { + if (gpio_request(irq_to_gpio(irqs[i].irq), irqs[i].str) < 0) { pr_err("%s: sock %d unable to request gpio %d\n", - __func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq)); + __func__, skt->nr, irq_to_gpio(irqs[i].irq)); ret = -EBUSY; goto error; } - if (gpio_direction_input(IRQ_TO_GPIO(irqs[i].irq)) < 0) { + if (gpio_direction_input(irq_to_gpio(irqs[i].irq)) < 0) { pr_err("%s: sock %d unable to set input gpio %d\n", - __func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq)); + __func__, skt->nr, irq_to_gpio(irqs[i].irq)); ret = -EINVAL; goto error; } @@ -86,7 +86,7 @@ static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) error: for (; i >= 0; i--) { - gpio_free(IRQ_TO_GPIO(irqs[i].irq)); + gpio_free(irq_to_gpio(irqs[i].irq)); } return (ret); } @@ -97,7 +97,7 @@ static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) /* free allocated gpio's */ gpio_free(GPIO_PRDY); for (i = 0; i < ARRAY_SIZE(irqs); i++) - gpio_free(IRQ_TO_GPIO(irqs[i].irq)); + gpio_free(irq_to_gpio(irqs[i].irq)); } static unsigned long trizeps_pcmcia_status[2]; -- cgit v1.2.2 From 9fb0f14e31b6101a0cc69a333b43541044f9b0a6 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 12 Apr 2011 23:29:38 -0700 Subject: Input: evdev - indicate buffer overrun with SYN_DROPPED Add a new EV_SYN code, SYN_DROPPED, to inform the client when input events have been dropped from the evdev input buffer due to a buffer overrun. The client should use this event as a hint to reset its state or ignore all following events until the next packet begins. Signed-off-by: Jeff Brown [dtor@mail.ru: Implement Henrik's suggestion and drop old events in case of overflow.] Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7f42d3a454d2..88d8e4cb419a 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -39,13 +39,13 @@ struct evdev { }; struct evdev_client { - int head; - int tail; + unsigned int head; + unsigned int tail; spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; - int bufsize; + unsigned int bufsize; struct input_event buffer[]; }; @@ -55,16 +55,25 @@ static DEFINE_MUTEX(evdev_table_mutex); static void evdev_pass_event(struct evdev_client *client, struct input_event *event) { - /* - * Interrupts are disabled, just acquire the lock. - * Make sure we don't leave with the client buffer - * "empty" by having client->head == client->tail. - */ + /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); - do { - client->buffer[client->head++] = *event; - client->head &= client->bufsize - 1; - } while (client->head == client->tail); + + client->buffer[client->head++] = *event; + client->head &= client->bufsize - 1; + + if (unlikely(client->head == client->tail)) { + /* + * This effectively "drops" all unconsumed events, leaving + * EV_SYN/SYN_DROPPED plus the newest event in the queue. + */ + client->tail = (client->head - 2) & (client->bufsize - 1); + + client->buffer[client->tail].time = event->time; + client->buffer[client->tail].type = EV_SYN; + client->buffer[client->tail].code = SYN_DROPPED; + client->buffer[client->tail].value = 0; + } + spin_unlock(&client->buffer_lock); if (event->type == EV_SYN) -- cgit v1.2.2 From 100d4a9d20015315bf4215d11c2cf4b1f30c33b8 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Tue, 15 Mar 2011 16:24:24 +0100 Subject: usb: musb: clear AUTOSET while clearing DMAENAB On the completion of tx dma, dma is disabled by clearing MUSB_TXCSR_DMAENAB in TXCSR. If MUSB_TXCSR_AUTOSET was set in txstate() it will remain set although it is not needed in PIO mode. Clear it as soon as it is not needed. Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 98519c5d8b5c..9ecb057902ef 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -535,7 +535,7 @@ void musb_g_tx(struct musb *musb, u8 epnum) is_dma = 1; csr |= MUSB_TXCSR_P_WZC_BITS; csr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_P_UNDERRUN | - MUSB_TXCSR_TXPKTRDY); + MUSB_TXCSR_TXPKTRDY | MUSB_TXCSR_AUTOSET); musb_writew(epio, MUSB_TXCSR, csr); /* Ensure writebuffer is empty. */ csr = musb_readw(epio, MUSB_TXCSR); -- cgit v1.2.2 From 8726606424738ca0341e1bb93ebac956d80f6d29 Mon Sep 17 00:00:00 2001 From: Mian Yousaf Kaukab Date: Tue, 15 Mar 2011 16:24:29 +0100 Subject: usb: musb: ux500: copy dma mask from platform device to musb device musb code checks dma mask before calling dma hooks. Signed-off-by: Mian Yousaf Kaukab Signed-off-by: Felipe Balbi --- drivers/usb/musb/ux500.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index d6384e4aeef9..f7e04bf34a13 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -93,6 +93,8 @@ static int __init ux500_probe(struct platform_device *pdev) } musb->dev.parent = &pdev->dev; + musb->dev.dma_mask = pdev->dev.dma_mask; + musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; glue->dev = &pdev->dev; glue->musb = musb; -- cgit v1.2.2 From ec63bf6c06b01ceeb6048a2b9fa9e73060259307 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 20 Mar 2011 14:14:36 +0300 Subject: USB: musb: add missing unlock in cppi_interrupt() We should unlock before returning here. Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi --- drivers/usb/musb/cppi_dma.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index de55a3c3259a..6385eeb44a07 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -1167,8 +1167,11 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG); rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG); - if (!tx && !rx) + if (!tx && !rx) { + if (cppi->irq) + spin_unlock_irqrestore(&musb->lock, flags); return IRQ_NONE; + } DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx); -- cgit v1.2.2 From aca7f353219abfb7b8a1530fbba1b1acf0e30da4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 20 Mar 2011 14:15:24 +0300 Subject: USB: musb: using 0 instead of NULL Sparse complains (and rightly so): drivers/usb/musb/cppi_dma.c:1458:33: warning: Using plain integer as NULL pointer Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi --- drivers/usb/musb/cppi_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 6385eeb44a07..0db0f5e7d3a4 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -1455,7 +1455,7 @@ static int cppi_channel_abort(struct dma_channel *channel) * compare mode by writing 1 to the tx_complete register. */ cppi_reset_tx(tx_ram, 1); - cppi_ch->head = 0; + cppi_ch->head = NULL; musb_writel(&tx_ram->tx_complete, 0, 1); cppi_dump_tx(5, cppi_ch, " (done teardown)"); -- cgit v1.2.2 From 2fbcf3fa43af809ebf4e4ad33c2f0a17e903385c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 20 Mar 2011 14:16:17 +0300 Subject: USB: musb: silence printk format warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gcc gives the following warnings: drivers/usb/musb/cppi_dma.c: In function ‘cppi_next_tx_segment’: drivers/usb/musb/cppi_dma.c:600: warning: format ‘%x’ expects type ‘unsigned int’, but argument 8 has type ‘dma_addr_t’ drivers/usb/musb/cppi_dma.c: In function ‘cppi_next_rx_segment’: drivers/usb/musb/cppi_dma.c:822: warning: format ‘%x’ expects type ‘unsigned int’, but argument 9 has type ‘dma_addr_t’ drivers/usb/musb/cppi_dma.c: In function ‘cppi_rx_scan’: drivers/usb/musb/cppi_dma.c:1042: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 4 has type ‘dma_addr_t’ drivers/usb/musb/cppi_dma.c:1114: warning: format ‘%08x’ expects type ‘unsigned int’, but argument 7 has type ‘dma_addr_t’ dma_addr_t is sometimes 32 bit and sometimes 64. We normally cast them to unsigned long long for printk(). Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi --- drivers/usb/musb/cppi_dma.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 0db0f5e7d3a4..eb9161ae57a4 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -597,12 +597,12 @@ cppi_next_tx_segment(struct musb *musb, struct cppi_channel *tx) length = min(n_bds * maxpacket, length); } - DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%x len %u\n", + DBG(4, "TX DMA%d, pktSz %d %s bds %d dma 0x%llx len %u\n", tx->index, maxpacket, rndis ? "rndis" : "transparent", n_bds, - addr, length); + (unsigned long long)addr, length); cppi_rndis_update(tx, 0, musb->ctrl_base, rndis); @@ -820,7 +820,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) length = min(n_bds * maxpacket, length); DBG(4, "RX DMA%d seg, maxp %d %s bds %d (cnt %d) " - "dma 0x%x len %u %u/%u\n", + "dma 0x%llx len %u %u/%u\n", rx->index, maxpacket, onepacket ? (is_rndis ? "rndis" : "onepacket") @@ -829,7 +829,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) musb_readl(tibase, DAVINCI_RXCPPI_BUFCNT0_REG + (rx->index * 4)) & 0xffff, - addr, length, rx->channel.actual_len, rx->buf_len); + (unsigned long long)addr, length, + rx->channel.actual_len, rx->buf_len); /* only queue one segment at a time, since the hardware prevents * correct queue shutdown after unexpected short packets @@ -1039,9 +1040,9 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) if (!completed && (bd->hw_options & CPPI_OWN_SET)) break; - DBG(5, "C/RXBD %08x: nxt %08x buf %08x " + DBG(5, "C/RXBD %llx: nxt %08x buf %08x " "off.len %08x opt.len %08x (%d)\n", - bd->dma, bd->hw_next, bd->hw_bufp, + (unsigned long long)bd->dma, bd->hw_next, bd->hw_bufp, bd->hw_off_len, bd->hw_options, rx->channel.actual_len); @@ -1111,11 +1112,12 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) musb_ep_select(cppi->mregs, rx->index + 1); csr = musb_readw(regs, MUSB_RXCSR); if (csr & MUSB_RXCSR_DMAENAB) { - DBG(4, "list%d %p/%p, last %08x%s, csr %04x\n", + DBG(4, "list%d %p/%p, last %llx%s, csr %04x\n", rx->index, rx->head, rx->tail, rx->last_processed - ? rx->last_processed->dma + ? (unsigned long long) + rx->last_processed->dma : 0, completed ? ", completed" : "", csr); -- cgit v1.2.2 From 2e10f5e70f670d981f789075e3ebc394f5bb51e3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 20 Mar 2011 14:18:26 +0300 Subject: USB: musb: dereferencing an iomem pointer "tx_ram" points to io memory. We can't dereference it directly. Sparse complains about this: "drivers/usb/musb/cppi_dma.c:1205:25: warning: dereference of noderef expression" Signed-off-by: Dan Carpenter Signed-off-by: Felipe Balbi --- drivers/usb/musb/cppi_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index eb9161ae57a4..ab434fbd8c35 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -1204,7 +1204,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id) */ if (NULL == bd) { DBG(1, "null BD\n"); - tx_ram->tx_complete = 0; + musb_writel(&tx_ram->tx_complete, 0, 0); continue; } -- cgit v1.2.2 From 7a180e70cfc56e131bfe4796773df2acfc7d4180 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 22 Mar 2011 11:31:37 +0200 Subject: usb: musb: temporarily make it bool Due to the recent changes to musb's glue layers, we can't compile musb-hdrc as a module - compilation will break due to undefined symbol musb_debug. In order to fix that, we need a big re-work of the debug support on the MUSB driver. Because that would mean a lot of new code coming into the -rc series, it's best to defer that to next merge window and for now just disable module support for MUSB. Once we get the refactor of the debugging support done, we can simply revert this patch and things will go back to normal again. Cc: stable@kernel.org # v2.6.38 Signed-off-by: Felipe Balbi --- drivers/usb/musb/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 4cbb7e4b368d..74073b363c30 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -14,7 +14,7 @@ config USB_MUSB_HDRC select TWL4030_USB if MACH_OMAP_3430SDP select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA select USB_OTG_UTILS - tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' + bool 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' help Say Y here if your system has a dual role high speed USB controller based on the Mentor Graphics silicon IP. Then @@ -30,8 +30,8 @@ config USB_MUSB_HDRC If you do not know what this is, please say N. - To compile this driver as a module, choose M here; the - module will be called "musb-hdrc". +# To compile this driver as a module, choose M here; the +# module will be called "musb-hdrc". choice prompt "Platform Glue Layer" -- cgit v1.2.2 From 3d5ad13eac320292f64071ea7ded1b661edd9430 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 22 Mar 2011 11:38:49 +0200 Subject: usb: musb: gadget: check the correct list_head We are now using our own list_head, so we should be checking against that, not the gadget driver's list_head. Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9ecb057902ef..6dfbf9ffd7a6 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1296,7 +1296,7 @@ static int musb_gadget_dequeue(struct usb_ep *ep, struct usb_request *request) } /* if the hardware doesn't have the request, easy ... */ - if (musb_ep->req_list.next != &request->list || musb_ep->busy) + if (musb_ep->req_list.next != &req->list || musb_ep->busy) musb_g_giveback(musb_ep, request, -ECONNRESET); /* ... else abort the dma transfer ... */ -- cgit v1.2.2 From 4f9edd2d7e8dd170d10780532cb76eb5890468b4 Mon Sep 17 00:00:00 2001 From: Hema HK Date: Tue, 22 Mar 2011 16:02:12 +0530 Subject: usb: musb: Fix the crash issue during reboot Below crash observed with commit 7acc6197b76edd0b932a7cbcc6cfad0a8a87f026 (usb: musb: Idle path retention and offmode support for OMAP3) during board reboot. The musb clock was disabled when musb_shutdown() was called by platform_drv_shutdown in which there are register accesses. call pm_runtime_get_sync() and pm_runtime_put_sync() in the musb_shutdown function. / # [ 172.368774] Unhandled fault: imprecise external abort (0x1406) at 0x400f0000 [ 172.376190] Internal error: : 1406 [#1] SMP [ 172.380554] last sysfs file: /sys/devices/platform/omap/omap_i2c.4/i2c-4/i2c-dev/i2c-4/dev [ 172.389221] Modules linked in: [ 172.392456] CPU: 0 Tainted: G W (2.6.38-06671-geddecbb #33) [ 172.399475] PC is at do_raw_spin_unlock+0x50/0xc0 [ 172.404418] LR is at _raw_spin_unlock_irqrestore+0x24/0x44 [ 172.410186] pc : [] lr : [] psr: 60000093 [ 172.410186] sp : ee993e40 ip : c0d00240 fp : bea9cf14 [ 172.422241] r10: 00000000 r9 : ee992000 r8 : c04b2fa8 [ 172.427703] r7 : 00000000 r6 : c0fa46c0 r5 : ef966124 r4 : ef966124 [ 172.434539] r3 : ef92cbc0 r2 : ef92cbc0 r1 : 00000000 r0 : ef966124 [ 172.441406] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user [ 172.448974] Control: 10c5387d Table: ae8d804a DAC: 00000015 [ 172.454986] Process init (pid: 1094, stack limit = 0xee9922f8) [ 172.461120] Stack: (0xee993e40 to 0xee994000) [ 172.465667] 3e40: a0000013 c085a7f8 ef966124 a0000013 c0fa46c0 c0761ab4 c0761a70 ef95c008 [ 172.474273] 3e60: ef95c014 c06e2fd0 c06e2fbc c06dea90 00000000 01234567 28121969 c04fccb4 [ 172.482849] 3e80: 00000000 c04fcd04 c0a302bc c04fce44 c0a02600 00000001 00000000 c085cd04 [ 172.491424] 3ea0: 00000000 00000002 c09ea000 c085afc0 ee993f24 00000000 00040001 00000445 [ 172.499999] 3ec0: a8eb9d34 00000027 00000000 00000000 00000000 c0a56a4c 00000000 00000000 [ 172.508575] 3ee0: 00000002 60000093 00000000 c0519aac 00000002 00000080 00000000 c0550420 [ 172.517150] 3f00: 00000000 00000002 ee970000 c0a56a3c c0a56a20 00000002 c0a56a3c 00000000 [ 172.525726] 3f20: c0a56a3c 0000000a c1580e00 c0a56a20 00000002 c0a56a3c c1580e00 c0a56a20 [ 172.534301] 3f40: ef92cbc0 c05173a0 00000001 ef92cbc0 c0576190 c04e3174 20000013 c0517324 [ 172.542877] 3f60: ef815c00 ee90b720 c04e3174 c0576190 00000001 ef92cbc0 c04b2f00 ffffffff [ 172.551483] 3f80: 00000058 c0517324 00000000 00000000 ffffffff 00000000 00000000 ffffffff [ 172.560058] 3fa0: 00000058 c04b2de0 00000000 00000000 fee1dead 28121969 01234567 00000000 [ 172.568634] 3fc0: 00000000 00000000 ffffffff 00000058 00000000 00000001 400aa000 bea9cf14 [ 172.577209] 3fe0: 000ea148 bea9c958 000aa750 40225728 60000010 fee1dead 00000000 00000000 [ 172.585784] [] (do_raw_spin_unlock+0x50/0xc0) from [] (_raw_spin_unlock_irqrestore+0x24/0x44) [ 172.596588] [] (_raw_spin_unlock_irqrestore+0x24/0x44) from [] (musb_shutdown+0x44/0x88) [ 172.606933] [] (musb_shutdown+0x44/0x88) from [] (platform_drv_shutdown+0x14/0x18) [ 172.616699] [] (platform_drv_shutdown+0x14/0x18) from [] (device_shutdown+0x74/0xb4) [ 172.626647] [] (device_shutdown+0x74/0xb4) from [] (kernel_restart_prepare+0x24/0x38) [ 172.636688] [] (kernel_restart_prepare+0x24/0x38) from [] (kernel_restart+0xc/0x48) [ 172.646545] [] (kernel_restart+0xc/0x48) from [] (sys_reboot+0xfc/0x1d8) [ 172.655426] [] (sys_reboot+0xfc/0x1d8) from [] (ret_fast_syscall+0x0/0x3c) [ 172.664459] Code: e3c3303f e594200c e593300c e1520003 (0a000002) [ 172.670867] ------------[ cut here ]------------ Signed-off-by: Hema HK Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 630ae7f3cd4c..f10ff00ca09e 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1030,6 +1030,7 @@ static void musb_shutdown(struct platform_device *pdev) struct musb *musb = dev_to_musb(&pdev->dev); unsigned long flags; + pm_runtime_get_sync(musb->controller); spin_lock_irqsave(&musb->lock, flags); musb_platform_disable(musb); musb_generic_disable(musb); @@ -1040,6 +1041,7 @@ static void musb_shutdown(struct platform_device *pdev) musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_platform_exit(musb); + pm_runtime_put(musb->controller); /* FIXME power down */ } -- cgit v1.2.2 From 132543074af3cf1e94e3608abf162880edbdcbb3 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 30 Mar 2011 22:48:54 -0400 Subject: USB: musb: blackfin: work around anomaly 05000450 DMA mode 1 data corruption anomaly on Blackfin systems. This issue is specific to the Blackfin silicon as the bug appears to be related to the connection of the musb ip to the bus/dma fabric. Data corruption when using USB DMA mode 1. (Issue manager 17-01-0105) DMA mode 1 allows large size transfers to generate a single interrupt at the end of the entire transfer. The transfer is split up in packets of length specified in the Maximum Packet Size field for that endpoint. If the transfer size is not an integer multiple of the Maximum Packet Size, a short packet will be present at the end of the transfer. Under certain conditions this packet may be corrupted in the USB FIFO. Workaround: Use DMA mode 1 to transfer (n* Maximum Packet Size) and schedule DMA mode 0 to transfer the short packet. As an example if your transfer size is 33168 bytes and Maximum Packet Size equals 512, schedule [33168 - (33168 mod 512)] in DMA mode 1 and the remainder (33168 mod 512) in DMA mode 0. Signed-off-by: Mike Frysinger Signed-off-by: Felipe Balbi --- drivers/usb/musb/blackfin.c | 24 ++++++++++++++++++++++++ drivers/usb/musb/musb_core.h | 5 +++++ drivers/usb/musb/musbhsdma.c | 8 ++++++++ 3 files changed, 37 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 52312e8af213..8e2a1ff8a35a 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -21,6 +21,7 @@ #include #include "musb_core.h" +#include "musbhsdma.h" #include "blackfin.h" struct bfin_glue { @@ -332,6 +333,27 @@ static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode) return -EIO; } +static int bfin_musb_adjust_channel_params(struct dma_channel *channel, + u16 packet_sz, u8 *mode, + dma_addr_t *dma_addr, u32 *len) +{ + struct musb_dma_channel *musb_channel = channel->private_data; + + /* + * Anomaly 05000450 might cause data corruption when using DMA + * MODE 1 transmits with short packet. So to work around this, + * we truncate all MODE 1 transfers down to a multiple of the + * max packet size, and then do the last short packet transfer + * (if there is any) using MODE 0. + */ + if (ANOMALY_05000450) { + if (musb_channel->transmit && *mode == 1) + *len = *len - (*len % packet_sz); + } + + return 0; +} + static void bfin_musb_reg_init(struct musb *musb) { if (ANOMALY_05000346) { @@ -430,6 +452,8 @@ static const struct musb_platform_ops bfin_ops = { .vbus_status = bfin_musb_vbus_status, .set_vbus = bfin_musb_set_vbus, + + .adjust_channel_params = bfin_musb_adjust_channel_params, }; static u64 bfin_dmamask = DMA_BIT_MASK(32); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 4bd9e2145ee4..0e053b587960 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -261,6 +261,7 @@ enum musb_g_ep0_state { * @try_ilde: tries to idle the IP * @vbus_status: returns vbus status if possible * @set_vbus: forces vbus status + * @channel_program: pre check for standard dma channel_program func */ struct musb_platform_ops { int (*init)(struct musb *musb); @@ -274,6 +275,10 @@ struct musb_platform_ops { int (*vbus_status)(struct musb *musb); void (*set_vbus)(struct musb *musb, int on); + + int (*adjust_channel_params)(struct dma_channel *channel, + u16 packet_sz, u8 *mode, + dma_addr_t *dma_addr, u32 *len); }; /* diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index 0144a2d481fd..d281792db05c 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -169,6 +169,14 @@ static int dma_channel_program(struct dma_channel *channel, BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || channel->status == MUSB_DMA_STATUS_BUSY); + /* Let targets check/tweak the arguments */ + if (musb->ops->adjust_channel_params) { + int ret = musb->ops->adjust_channel_params(channel, + packet_sz, &mode, &dma_addr, &len); + if (ret) + return ret; + } + /* * The DMA engine in RTL1.8 and above cannot handle * DMA addresses that are not aligned to a 4 byte boundary. -- cgit v1.2.2 From 0f890ab1b51a5e59f078f046229825076d1e3c77 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 27 Mar 2011 20:19:15 -0300 Subject: [media] cx18: Fix list BUG for IDX stream, triggerable in cx18_probe() error clean up, If allocating stream buffers for one of the primary streams (e.g. YUV) failed during card probe, the error path clean up would try to manipulate the yet unitialized IDX stream structures. This caused a BUG due to unitialized list heads. Detect that case and ignore the uninitialized IDX stream. Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx18/cx18-streams.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index c6e2ca3b1149..6fbc356113c1 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -350,9 +350,17 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) /* No struct video_device, but can have buffers allocated */ if (type == CX18_ENC_STREAM_TYPE_IDX) { + /* If the module params didn't inhibit IDX ... */ if (cx->stream_buffers[type] != 0) { cx->stream_buffers[type] = 0; - cx18_stream_free(&cx->streams[type]); + /* + * Before calling cx18_stream_free(), + * check if the IDX stream was actually set up. + * Needed, since the cx18_probe() error path + * exits through here as well as normal clean up + */ + if (cx->streams[type].buffers != 0) + cx18_stream_free(&cx->streams[type]); } continue; } -- cgit v1.2.2 From 62a79436a54e5f33920bf95a3fae677540c7ef2c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 22 Mar 2011 09:24:58 -0300 Subject: [media] videobuf2: fix core to correctly identify allocation failures The videobuf2-dma-contig allocator returns an ERR_PTR() on failure, not a NULL like all other allocators. Fix videobuf2-core to also correctly recognise those failures. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 6698c77e0f64..71734a4da135 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -51,7 +51,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb, for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, plane, alloc, q->alloc_ctx[plane], plane_sizes[plane]); - if (!mem_priv) + if (IS_ERR_OR_NULL(mem_priv)) goto free; /* Associate allocator private data with this plane */ -- cgit v1.2.2 From 99a41771bfbd4fb350b0021d3298b0cb49dd747b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 22 Mar 2011 09:29:32 -0300 Subject: [media] videobuf2: fix an error message buf->size is not yet initialised in videobuf2-dma-contig at the time of the error message, use "size." Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-dma-contig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c index 58205d596138..a790a5f8c06f 100644 --- a/drivers/media/video/videobuf2-dma-contig.c +++ b/drivers/media/video/videobuf2-dma-contig.c @@ -46,7 +46,7 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) GFP_KERNEL); if (!buf->vaddr) { dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", - buf->size); + size); kfree(buf); return ERR_PTR(-ENOMEM); } -- cgit v1.2.2 From 24105ebc0567f2864999a8176be681c62fe31350 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:41:28 -0300 Subject: [media] soc-camera: fix a recent multi-camera breakage on sh-mobile With the introduction of CSI2 support on sh-mobile, the host driver switched to using v4l2_device_call_until_err() with grp_id == 0 to call subdev operations on the sensor and the CSI2 subdev. However, this has broken multi-client set ups like the one on migor, because that way all operations get called on both clients. To fix this add a grp_id and set it to the client private context. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_ceu_camera.c | 10 +++++----- drivers/media/video/sh_mobile_csi2.c | 1 + drivers/media/video/soc_camera.c | 4 +++- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index 3fe54bf41142..134e86bf6d97 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -922,7 +922,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int /* Try 2560x1920, 1280x960, 640x480, 320x240 */ mf.width = 2560 >> shift; mf.height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1224,7 +1224,7 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_cropcap cap; int ret; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); if (ret < 0) return ret; @@ -1254,7 +1254,7 @@ static int client_s_fmt(struct soc_camera_device *icd, tmp_h = min(2 * tmp_h, max_height); mf->width = tmp_w; mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, s_mbus_fmt, mf); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); @@ -1658,7 +1658,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, mf.code = xlate->code; mf.colorspace = pix->colorspace; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1682,7 +1682,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, */ mf.width = 2560; mf.height = 1920; - ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); if (ret < 0) { /* Shouldn't actually happen... */ diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index dd1b81b1442b..9e7c1a7c46c2 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -208,6 +208,7 @@ static int sh_csi2_notify(struct notifier_block *nb, case BUS_NOTIFY_BOUND_DRIVER: snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s", dev_name(v4l2_dev->dev), ".mipi-csi"); + priv->subdev.grp_id = (long)icd; ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev); dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret); if (ret < 0) diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 46284489e4eb..921993060d2f 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -1071,6 +1071,9 @@ static int soc_camera_probe(struct device *dev) } } + sd = soc_camera_to_subdev(icd); + sd->grp_id = (long)icd; + /* At this point client .probe() should have run already */ ret = soc_camera_init_user_formats(icd); if (ret < 0) @@ -1092,7 +1095,6 @@ static int soc_camera_probe(struct device *dev) goto evidstart; /* Try to improve our guess of a reasonable window format */ - sd = soc_camera_to_subdev(icd); if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { icd->user_width = mf.width; icd->user_height = mf.height; -- cgit v1.2.2 From 3e31f2b9456d0777a41d9d26429d6f2ad6894014 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:24:42 -0300 Subject: [media] imx074: return a meaningful error code instead of -1 Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/imx074.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c index 1a1169115716..0382ea752e6f 100644 --- a/drivers/media/video/imx074.c +++ b/drivers/media/video/imx074.c @@ -298,7 +298,7 @@ static unsigned long imx074_query_bus_param(struct soc_camera_device *icd) static int imx074_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { - return -1; + return -EINVAL; } static struct soc_camera_ops imx074_ops = { -- cgit v1.2.2 From c8dd707805af100965c93cdca7d61e61165e9c07 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:26:11 -0300 Subject: [media] soc-camera: don't dereference I2C client after it has been removed i2c_unregister_device() frees the I2C client, so, dereferencing it afterwards is a bug, that leads to Oopses. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/soc_camera.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 921993060d2f..3973f9a94753 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -996,10 +996,11 @@ static void soc_camera_free_i2c(struct soc_camera_device *icd) { struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct i2c_adapter *adap = client->adapter; dev_set_drvdata(&icd->dev, NULL); v4l2_device_unregister_subdev(i2c_get_clientdata(client)); i2c_unregister_device(client); - i2c_put_adapter(client->adapter); + i2c_put_adapter(adap); } #else #define soc_camera_init_i2c(icd, icl) (-ENODEV) -- cgit v1.2.2 From cb743930eb91e5b608c4491ce1b930dfeca43943 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 23 Mar 2011 05:43:51 -0300 Subject: [media] sh_mobile_csi2: fix module reloading If the camera host driver (sh_mobile_ceu_camera.c) is unloaded and then reloaded, probe will fail, because camera client .set_bus_param() and .query_bus_param() methods have been set to NULL. Fix this by caching the original pointers and restoring them on driver-unbind. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/sh_mobile_csi2.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index 9e7c1a7c46c2..98b87481fa94 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -38,6 +38,8 @@ struct sh_csi2 { void __iomem *base; struct platform_device *pdev; struct sh_csi2_client_config *client; + unsigned long (*query_bus_param)(struct soc_camera_device *); + int (*set_bus_param)(struct soc_camera_device *, unsigned long); }; static int sh_csi2_try_fmt(struct v4l2_subdev *sd, @@ -216,6 +218,8 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = pdata->clients + i; + priv->set_bus_param = icd->ops->set_bus_param; + priv->query_bus_param = icd->ops->query_bus_param; icd->ops->set_bus_param = sh_csi2_set_bus_param; icd->ops->query_bus_param = sh_csi2_query_bus_param; @@ -227,8 +231,10 @@ static int sh_csi2_notify(struct notifier_block *nb, priv->client = NULL; /* Driver is about to be unbound */ - icd->ops->set_bus_param = NULL; - icd->ops->query_bus_param = NULL; + icd->ops->set_bus_param = priv->set_bus_param; + icd->ops->query_bus_param = priv->query_bus_param; + priv->set_bus_param = NULL; + priv->query_bus_param = NULL; v4l2_device_unregister_subdev(&priv->subdev); -- cgit v1.2.2 From 122af366015abc2787a06b1564d62962b08b2042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 7 Apr 2011 05:50:43 -0300 Subject: [media] V4L: mx3_camera: select VIDEOBUF2_DMA_CONTIG instead of VIDEOBUF_DMA_CONTIG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 379fa5d ([media] V4L: mx3_camera: convert to videobuf2) mx3_camera uses videobuf2, but that commit didn't upgrade the select resulting in the following build failure: drivers/built-in.o: In function `mx3_camera_init_videobuf': clkdev.c:(.text+0x86580): undefined reference to `vb2_dma_contig_memops' drivers/built-in.o: In function `mx3_camera_probe': clkdev.c:(.devinit.text+0x3548): undefined reference to `vb2_dma_contig_init_ctx' clkdev.c:(.devinit.text+0x3578): undefined reference to `vb2_dma_contig_cleanup_ctx' drivers/built-in.o: In function `mx3_camera_remove': clkdev.c:(.devexit.text+0x674): undefined reference to `vb2_dma_contig_cleanup_ctx' make[2]: *** [.tmp_vmlinux1] Error 1 make[1]: *** [sub-make] Error 2 make: *** [all] Error 2 Signed-off-by: Uwe Kleine-König Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 4498b944dec8..00f51dd121f3 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -875,7 +875,7 @@ config MX3_VIDEO config VIDEO_MX3 tristate "i.MX3x Camera Sensor Interface driver" depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG select MX3_VIDEO ---help--- This is a v4l2 driver for the i.MX3x Camera Sensor Interface -- cgit v1.2.2 From 8eca7a004ef9fec2fdca8a2b4b65410ff1515b80 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 18 Feb 2011 09:41:49 -0300 Subject: [media] omap3isp: resizer: Center the crop rectangle When the crop rectangle needs to be modified to match hardware requirements, center the resulting rectangle on the requested rectangle instead of removing pixels from the right and bottom sides only. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispresizer.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 75d39b115d42..829d7bfd422d 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -775,6 +775,8 @@ static void resizer_calc_ratios(struct isp_res_device *res, unsigned int max_width; unsigned int max_height; unsigned int width_alignment; + unsigned int width; + unsigned int height; /* * Clamp the output height based on the hardware capabilities and @@ -794,11 +796,11 @@ static void resizer_calc_ratios(struct isp_res_device *res, if (ratio->vert <= MID_RESIZE_VALUE) { upscaled_height = (output->height - 1) * ratio->vert + 32 * spv + 16; - input->height = (upscaled_height >> 8) + 4; + height = (upscaled_height >> 8) + 4; } else { upscaled_height = (output->height - 1) * ratio->vert + 64 * spv + 32; - input->height = (upscaled_height >> 8) + 7; + height = (upscaled_height >> 8) + 7; } /* @@ -862,12 +864,18 @@ static void resizer_calc_ratios(struct isp_res_device *res, if (ratio->horz <= MID_RESIZE_VALUE) { upscaled_width = (output->width - 1) * ratio->horz + 32 * sph + 16; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } else { upscaled_width = (output->width - 1) * ratio->horz + 64 * sph + 32; - input->width = (upscaled_width >> 8) + 7; + width = (upscaled_width >> 8) + 7; } + + /* Center the new crop rectangle. */ + input->left += (input->width - width) / 2; + input->top += (input->height - height) / 2; + input->width = width; + input->height = height; } /* -- cgit v1.2.2 From 21a8d026e0721f90ae03084e96a215632c80fc13 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Wed, 13 Apr 2011 11:52:16 -0400 Subject: x86 platform drivers: Build fix for intel_pmic_gpio Fix an incorrect function name so the driver builds. Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_pmic_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 7bbb5388e564..464bb3fc4d88 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -209,7 +209,7 @@ static struct irq_chip pmic_irqchip = { .irq_mask = pmic_irq_mask, .irq_unmask = pmic_irq_unmask, .irq_set_type = pmic_irq_type, - .irq_bus_lock = pmic_irq_buslock, + .irq_bus_lock = pmic_bus_lock, .irq_bus_sync_unlock = pmic_bus_sync_unlock, }; -- cgit v1.2.2 From 5c72d064f7ead1126bed6faab0c2bfb7418036e2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 13 Apr 2011 09:28:23 +0100 Subject: drm/i915: Initialise g4x watermarks for disabled pipes We were using uninitialised watermarks values for disabled pipes which were combined into a single WM register and so corrupting the values for the enabled pipe and upsetting the display hardware. Reported-by: Riccardo Magliocchetti Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=32612 Signed-off-by: Chris Wilson Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4fc21e047a2d..e522c702b04e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3771,8 +3771,11 @@ static bool g4x_compute_wm0(struct drm_device *dev, int entries, tlb_miss; crtc = intel_get_crtc_for_plane(dev, plane); - if (crtc->fb == NULL || !crtc->enabled) + if (crtc->fb == NULL || !crtc->enabled) { + *cursor_wm = cursor->guard_size; + *plane_wm = display->guard_size; return false; + } htotal = crtc->mode.htotal; hdisplay = crtc->mode.hdisplay; -- cgit v1.2.2 From 7c9f6472d46d07000c197e1d24fa2a332606968e Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Tue, 12 Apr 2011 23:49:28 +0000 Subject: net: can: mscan: fix build breakage in mpc5xxx_can Commit 74888760d40b3ac9054f9c5fa07b566c0676ba2d "dt/net: Eliminate users of of_platform_{,un}register_driver" broke building mscan driver. Fix it. Signed-off-by: Anatolij Gustschin Cc: Grant Likely Acked-by: Wolfgang Grandegger Acked-by: Marc Kleine-Budde Signed-off-by: David S. Miller --- drivers/net/can/mscan/mpc5xxx_can.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c index c0a1bc5b1435..bd1d811c204f 100644 --- a/drivers/net/can/mscan/mpc5xxx_can.c +++ b/drivers/net/can/mscan/mpc5xxx_can.c @@ -260,7 +260,7 @@ static int __devinit mpc5xxx_can_probe(struct platform_device *ofdev) if (!ofdev->dev.of_match) return -EINVAL; - data = (struct mpc5xxx_can_data *)of_dev->dev.of_match->data; + data = (struct mpc5xxx_can_data *)ofdev->dev.of_match->data; base = of_iomap(np, 0); if (!base) { -- cgit v1.2.2 From 91a403caf0f26c71ce4407fd235b2d6fb225fba9 Mon Sep 17 00:00:00 2001 From: Amit Kumar Salecha Date: Tue, 12 Apr 2011 17:05:55 +0000 Subject: qlcnic: limit skb frags for non tso packet Machines are getting deadlock in four node cluster environment. All nodes are accessing (find /gfs2 -depth -print|cpio -ocv > /dev/null) 200 GB storage on a GFS2 filesystem. This result in memory fragmentation and driver receives 18 frags for 1448 byte packets. For non tso packet, fw drops the tx request, if it has >14 frags. Fixing it by pulling extra frags. Cc: stable@kernel.org Signed-off-by: Amit Kumar Salecha Signed-off-by: David S. Miller --- drivers/net/qlcnic/qlcnic.h | 1 + drivers/net/qlcnic/qlcnic_main.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index dc44564ef6f9..b0dead00b2d1 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h @@ -99,6 +99,7 @@ #define TX_UDPV6_PKT 0x0c /* Tx defines */ +#define QLCNIC_MAX_FRAGS_PER_TX 14 #define MAX_TSO_HEADER_DESC 2 #define MGMT_CMD_DESC_RESV 4 #define TX_STOP_THRESH ((MAX_SKB_FRAGS >> 2) + MAX_TSO_HEADER_DESC \ diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index cd88c7e1bfa9..cb1a1ef36c0a 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c @@ -2099,6 +2099,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) struct cmd_desc_type0 *hwdesc, *first_desc; struct pci_dev *pdev; struct ethhdr *phdr; + int delta = 0; int i, k; u32 producer; @@ -2118,6 +2119,19 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } frag_count = skb_shinfo(skb)->nr_frags + 1; + /* 14 frags supported for normal packet and + * 32 frags supported for TSO packet + */ + if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) { + + for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++) + delta += skb_shinfo(skb)->frags[i].size; + + if (!__pskb_pull_tail(skb, delta)) + goto drop_packet; + + frag_count = 1 + skb_shinfo(skb)->nr_frags; + } /* 4 fragments per cmd des */ no_of_desc = (frag_count + 3) >> 2; -- cgit v1.2.2 From 332704a51498a7e29aa92c19dc03f11f80b71bfe Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 13 Apr 2011 10:56:51 +0200 Subject: iwlegacy: fix tx_power initialization priv->tx_power_next is not initialized to max supported power, but instead default value is used, what cause errors like [ 58.597834] iwl3945 0000:03:00.0: Requested user TXPOWER 15 above upper limit 14. [ 58.597839] iwl3945 0000:03:00.0: Error setting Tx power (-22). if maximum tx power read from the eeprom is smaller than default. In consequence card is unable to initialize properly. Fix the problem and cleanup tx power initialization. Reported-and-tested-by: Robin Dong Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-3945-hw.h | 2 -- drivers/net/wireless/iwlegacy/iwl-4965-hw.h | 3 --- drivers/net/wireless/iwlegacy/iwl-core.c | 17 +++++++++++------ drivers/net/wireless/iwlegacy/iwl-eeprom.c | 7 ------- drivers/net/wireless/iwlegacy/iwl3945-base.c | 4 ---- drivers/net/wireless/iwlegacy/iwl4965-base.c | 6 ------ 6 files changed, 11 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-hw.h b/drivers/net/wireless/iwlegacy/iwl-3945-hw.h index 779d3cb86e2c..5c3a68d3af12 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlegacy/iwl-3945-hw.h @@ -74,8 +74,6 @@ /* RSSI to dBm */ #define IWL39_RSSI_OFFSET 95 -#define IWL_DEFAULT_TX_POWER 0x0F - /* * EEPROM related constants, enums, and structures. */ diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-hw.h b/drivers/net/wireless/iwlegacy/iwl-4965-hw.h index 08b189c8472d..fc6fa2886d9c 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlegacy/iwl-4965-hw.h @@ -804,9 +804,6 @@ struct iwl4965_scd_bc_tbl { #define IWL4965_DEFAULT_TX_RETRY 15 -/* Limit range of txpower output target to be between these values */ -#define IWL4965_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm: 1 milliwatt */ - /* EEPROM */ #define IWL4965_FIRST_AMPDU_QUEUE 10 diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index a209a0e76bf0..2b08efb3b658 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -160,6 +160,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; + s8 max_tx_power = 0; if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { @@ -235,8 +236,8 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) geo_ch->flags |= ch->ht40_extension_channel; - if (ch->max_power_avg > priv->tx_power_device_lmt) - priv->tx_power_device_lmt = ch->max_power_avg; + if (ch->max_power_avg > max_tx_power) + max_tx_power = ch->max_power_avg; } else { geo_ch->flags |= IEEE80211_CHAN_DISABLED; } @@ -249,6 +250,10 @@ int iwl_legacy_init_geos(struct iwl_priv *priv) geo_ch->flags); } + priv->tx_power_device_lmt = max_tx_power; + priv->tx_power_user_lmt = max_tx_power; + priv->tx_power_next = max_tx_power; + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->cfg->sku & IWL_SKU_A) { IWL_INFO(priv, "Incorrectly detected BG card as ABG. " @@ -1124,11 +1129,11 @@ int iwl_legacy_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) if (!priv->cfg->ops->lib->send_tx_power) return -EOPNOTSUPP; - if (tx_power < IWL4965_TX_POWER_TARGET_POWER_MIN) { + /* 0 dBm mean 1 milliwatt */ + if (tx_power < 0) { IWL_WARN(priv, - "Requested user TXPOWER %d below lower limit %d.\n", - tx_power, - IWL4965_TX_POWER_TARGET_POWER_MIN); + "Requested user TXPOWER %d below 1 mW.\n", + tx_power); return -EINVAL; } diff --git a/drivers/net/wireless/iwlegacy/iwl-eeprom.c b/drivers/net/wireless/iwlegacy/iwl-eeprom.c index 04c5648027df..cb346d1a9ffa 100644 --- a/drivers/net/wireless/iwlegacy/iwl-eeprom.c +++ b/drivers/net/wireless/iwlegacy/iwl-eeprom.c @@ -471,13 +471,6 @@ int iwl_legacy_init_channel_map(struct iwl_priv *priv) flags & EEPROM_CHANNEL_RADAR)) ? "" : "not "); - /* Set the tx_power_user_lmt to the highest power - * supported by any channel */ - if (eeprom_ch_info[ch].max_power_avg > - priv->tx_power_user_lmt) - priv->tx_power_user_lmt = - eeprom_ch_info[ch].max_power_avg; - ch_info++; } } diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 28eb3d885ba1..cc7ebcee60e5 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -3825,10 +3825,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv) priv->force_reset[IWL_FW_RESET].reset_duration = IWL_DELAY_NEXT_FORCE_FW_RELOAD; - - priv->tx_power_user_lmt = IWL_DEFAULT_TX_POWER; - priv->tx_power_next = IWL_DEFAULT_TX_POWER; - if (eeprom->version < EEPROM_3945_EEPROM_VERSION) { IWL_WARN(priv, "Unsupported EEPROM version: 0x%04X\n", eeprom->version); diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index 91b3d8b9d7a5..d484c3678163 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -3140,12 +3140,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv) iwl_legacy_init_scan_params(priv); - /* Set the tx_power_user_lmt to the lowest power level - * this value will get overwritten by channel max power avg - * from eeprom */ - priv->tx_power_user_lmt = IWL4965_TX_POWER_TARGET_POWER_MIN; - priv->tx_power_next = IWL4965_TX_POWER_TARGET_POWER_MIN; - ret = iwl_legacy_init_channel_map(priv); if (ret) { IWL_ERR(priv, "initializing regulatory failed: %d\n", ret); -- cgit v1.2.2 From d06847fec256f4f902075ce5986e10f7c55fa250 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 15 Mar 2011 17:09:10 -0700 Subject: usb: fix ips1760-hcd printk format warning Fix printk format build warning and grammar typo on same line. drivers/usb/host/isp1760-hcd.c:300: warning: format '%lu' expects type 'long unsigned int', but argument 4 has type 'size_t' Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index f50e84ac570a..795345ad45e6 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -295,7 +295,7 @@ static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd) } dev_err(hcd->self.controller, - "%s: Can not allocate %lu bytes of memory\n" + "%s: Cannot allocate %zu bytes of memory\n" "Current memory map:\n", __func__, qtd->length); for (i = 0; i < BLOCKS; i++) { -- cgit v1.2.2 From 00cc7a5faf25b3ba5cf30fcffc62249bdd152006 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Wed, 16 Mar 2011 21:54:05 +0200 Subject: USB: usb-gadget: unlock data->lock mutex on error path in ep_read() ep_read() acquires data->lock mutex in get_ready_ep() and releases it on all paths except for one: when usb_endpoint_xfer_isoc() failed. The patch adds mutex_unlock(&data->lock) at that path. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/inode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 3ed73f49cf18..a01383f71f38 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -386,8 +386,10 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* halt any endpoint by doing a "wrong direction" i/o call */ if (usb_endpoint_dir_in(&data->desc)) { - if (usb_endpoint_xfer_isoc(&data->desc)) + if (usb_endpoint_xfer_isoc(&data->desc)) { + mutex_unlock(&data->lock); return -EINVAL; + } DBG (data->dev, "%s halt\n", data->name); spin_lock_irq (&data->dev->lock); if (likely (data->ep != NULL)) -- cgit v1.2.2 From 0291303d37585ab9056bae9fac1d1e13ae1ce913 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 4 Apr 2011 11:35:05 +0200 Subject: usb: Fix Kconfig unmet dependencies for Microblaze EHCI Disable USB_ARCH_HAS_EHCI in arch Kconfig and enable it in usb Kconfig Warning log: warning: (MICROBLAZE) selects USB_ARCH_HAS_EHCI which has unmet direct dependencies (USB_SUPPORT) Signed-off-by: Michal Simek Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 41b6e51188e4..006489d82dc3 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -66,6 +66,7 @@ config USB_ARCH_HAS_EHCI default y if ARCH_VT8500 default y if PLAT_SPEAR default y if ARCH_MSM + default y if MICROBLAZE default PCI # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. -- cgit v1.2.2 From 2c2da1799ba776c4bd8d51ee46d9f00cb4cc6120 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 4 Apr 2011 13:09:22 +0900 Subject: usb: r8a66597-udc: fix spinlock usage Because the disconnect function in the composite driver will call spin_lock, this driver has to call spin_unlock before calling driver->disconnet(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/r8a66597-udc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 015118535f77..6dcc1f68fa60 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1083,7 +1083,9 @@ static void irq_device_state(struct r8a66597 *r8a66597) if (dvsq == DS_DFLT) { /* bus reset */ + spin_unlock(&r8a66597->lock); r8a66597->driver->disconnect(&r8a66597->gadget); + spin_lock(&r8a66597->lock); r8a66597_update_usb_speed(r8a66597); } if (r8a66597->old_dvsq == DS_CNFG && dvsq != DS_CNFG) -- cgit v1.2.2 From 5a9443f08c83c294c5c806a689c1184b27cb26b3 Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Mon, 28 Mar 2011 21:54:47 +0200 Subject: USB: ftdi_sio: Added IDs for CTI USB Serial Devices I added new ProdutIds for two devices from CTI GmbH Leipzig. Signed-off-by: Christian Simon Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 9 +++++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a973c7a29d6e..8a02407bc41f 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -151,6 +151,8 @@ static struct ftdi_sio_quirk ftdi_stmclite_quirk = { * /sys/bus/usb/ftdi_sio/new_id, then send patch/report! */ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index c543e55bafba..770b5dd7114d 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1141,3 +1141,12 @@ #define QIHARDWARE_VID 0x20B7 #define MILKYMISTONE_JTAGSERIAL_PID 0x0713 +/* + * CTI GmbH RS485 Converter http://www.cti-lean.com/ + */ +/* USB-485-Mini*/ +#define FTDI_CTI_MINI_PID 0xF608 +/* USB-Nano-485*/ +#define FTDI_CTI_NANO_PID 0xF60B + + -- cgit v1.2.2 From 505d1f69ec4f8697a74711fb3a01ed151fda3834 Mon Sep 17 00:00:00 2001 From: Yauheni Kaliuta Date: Tue, 5 Apr 2011 16:55:25 +0300 Subject: usb: gadget: eem: fix echo command processing During processing of bunch of eem frames if "echo" command is found skb is cloned and the cloned version should be used to send reply. Unfortunately, the data of the original skb were actually used and the cloned skb is never freed. Using the cloned skb and freeing the skb in the completion callback for usb request. Signed-off-by: Yauheni Kaliuta Reviewed-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_eem.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index 95dd4662d6a8..b3c304290150 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -314,6 +314,9 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f) static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req) { + struct sk_buff *skb = (struct sk_buff *)req->context; + + dev_kfree_skb_any(skb); } /* @@ -428,10 +431,11 @@ static int eem_unwrap(struct gether *port, skb_trim(skb2, len); put_unaligned_le16(BIT(15) | BIT(11) | len, skb_push(skb2, 2)); - skb_copy_bits(skb, 0, req->buf, skb->len); - req->length = skb->len; + skb_copy_bits(skb2, 0, req->buf, skb2->len); + req->length = skb2->len; req->complete = eem_cmd_complete; req->zero = 1; + req->context = skb2; if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC)) DBG(cdev, "echo response queue fail\n"); break; -- cgit v1.2.2 From 94ae4976e253757e9b03a44d27d41b20f1829d80 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 5 Apr 2011 13:36:15 -0400 Subject: USB: EHCI: unlink unused QHs when the controller is stopped This patch (as1458) fixes a problem affecting ultra-reliable systems: When hardware failover of an EHCI controller occurs, the data structures do not get released correctly. This is because the routine responsible for removing unused QHs from the async schedule assumes the controller is running properly (the frame counter is used in determining how long the QH has been idle) -- but when a failover causes the controller to be electronically disconnected from the PCI bus, obviously it stops running. The solution is simple: Allow scan_async() to remove a QH from the async schedule if it has been idle for long enough _or_ if the controller is stopped. Signed-off-by: Alan Stern Reported-and-Tested-by: Dan Duval CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 98ded66e8d3f..42abd0f603bf 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1247,24 +1247,27 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) static void scan_async (struct ehci_hcd *ehci) { + bool stopped; struct ehci_qh *qh; enum ehci_timer_action action = TIMER_IO_WATCHDOG; ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index); timer_action_done (ehci, TIMER_ASYNC_SHRINK); rescan: + stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state); qh = ehci->async->qh_next.qh; if (likely (qh != NULL)) { do { /* clean any finished work for this qh */ - if (!list_empty (&qh->qtd_list) - && qh->stamp != ehci->stamp) { + if (!list_empty(&qh->qtd_list) && (stopped || + qh->stamp != ehci->stamp)) { int temp; /* unlinks could happen here; completion * reporting drops the lock. rescan using * the latest schedule, but don't rescan - * qhs we already finished (no looping). + * qhs we already finished (no looping) + * unless the controller is stopped. */ qh = qh_get (qh); qh->stamp = ehci->stamp; @@ -1285,9 +1288,9 @@ rescan: */ if (list_empty(&qh->qtd_list) && qh->qh_state == QH_STATE_LINKED) { - if (!ehci->reclaim - && ((ehci->stamp - qh->stamp) & 0x1fff) - >= (EHCI_SHRINK_FRAMES * 8)) + if (!ehci->reclaim && (stopped || + ((ehci->stamp - qh->stamp) & 0x1fff) + >= EHCI_SHRINK_FRAMES * 8)) start_unlink_async(ehci, qh); else action = TIMER_ASYNC_SHRINK; -- cgit v1.2.2 From 36a52c009a39049893c9a3a4091f8f8f48585f47 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 Apr 2011 19:50:34 +0200 Subject: usb: musb: omap2430: fix build failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix build failure introduced by commit 7acc6197b76edd0b932a7cbcc6cfad0a8a87f026 (usb: musb: Idle path retention and offmode support for OMAP3) when building without gadget support. CC drivers/usb/musb/omap2430.o drivers/usb/musb/omap2430.c: In function ‘musb_otg_notifications’: drivers/usb/musb/omap2430.c:262: error: ‘struct musb’ has no member named ‘gadget_driver’ Signed-off-by: Johan Hovold Cc: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/omap2430.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 25cb8b0003b1..57a27fa954b4 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -259,9 +259,10 @@ static int musb_otg_notifications(struct notifier_block *nb, case USB_EVENT_VBUS: DBG(4, "VBUS Connect\n"); +#ifdef CONFIG_USB_GADGET_MUSB_HDRC if (musb->gadget_driver) pm_runtime_get_sync(musb->controller); - +#endif otg_init(musb->xceiv); break; -- cgit v1.2.2 From 11a31d84129dc3133417d626643d714c9df5317e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 8 Apr 2011 17:38:22 +0200 Subject: USB: ftdi_sio: add PID for OCT DK201 docking station Add PID 0x0103 for serial port of the OCT DK201 docking station. Reported-by: Jan Hoogenraad Signed-off-by: Johan Hovold Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 8a02407bc41f..51b780134f59 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -527,6 +527,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) }, { USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) }, { USB_DEVICE(OCT_VID, OCT_US101_PID) }, + { USB_DEVICE(OCT_VID, OCT_DK201_PID) }, { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID), .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk }, { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID), diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 770b5dd7114d..0bdba7a96293 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -572,6 +572,7 @@ /* Note: OCT US101 is also rebadged as Dick Smith Electronics (NZ) XH6381 */ /* Also rebadged as Dick Smith Electronics (Aus) XH6451 */ /* Also rebadged as SIIG Inc. model US2308 hardware version 1 */ +#define OCT_DK201_PID 0x0103 /* OCT DK201 USB docking station */ #define OCT_US101_PID 0x0421 /* OCT US101 USB to RS-232 */ /* -- cgit v1.2.2 From 0fdf65c3394358a3634ad1064ea4984a03a6aa07 Mon Sep 17 00:00:00 2001 From: Yoichi Yuasa Date: Mon, 11 Apr 2011 21:56:39 +0900 Subject: USB: ohci-au1xxx: fix warning "__BIG_ENDIAN" is not defined In file included from drivers/usb/host/ohci-hcd.c:1028:0: drivers/usb/host/ohci-au1xxx.c:36:7: warning: "__BIG_ENDIAN" is not defined Signed-off-by: Yoichi Yuasa Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-au1xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 17a6043c1fa0..958d985f2951 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -33,7 +33,7 @@ #ifdef __LITTLE_ENDIAN #define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C) -#elif __BIG_ENDIAN +#elif defined(__BIG_ENDIAN) #define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | \ USBH_ENABLE_BE) #else -- cgit v1.2.2 From 16a2f970f3b4beb8d21009b2c45b9b5ab56bb621 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Mon, 11 Apr 2011 20:44:30 +0200 Subject: usb/gadget: don't leak hs_descriptors We should free both descriptors. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_audio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 9abecfddb27d..0111f8a9cf7f 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -706,6 +706,7 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f) struct f_audio *audio = func_to_audio(f); usb_free_descriptors(f->descriptors); + usb_free_descriptors(f->hs_descriptors); kfree(audio); } -- cgit v1.2.2 From 9ab7927bb845cf2549110b19c212fe44a2bfbacb Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Wed, 13 Apr 2011 08:38:16 +0200 Subject: USB host: Fix lockdep warning in AMD PLL quirk Booting latest kernel on my test machine produces a lockdep warning from the usb_amd_find_chipset_info() function: WARNING: at /data/lemmy/linux.trees.git/kernel/lockdep.c:2465 lockdep_trace_alloc+0x95/0xc2() Hardware name: Snook Modules linked in: Pid: 959, comm: work_for_cpu Not tainted 2.6.39-rc2+ #22 Call Trace: [] warn_slowpath_common+0x80/0x98 [] ? T.492+0x24/0x26 [] warn_slowpath_null+0x15/0x17 [] lockdep_trace_alloc+0x95/0xc2 [] slab_pre_alloc_hook+0x18/0x3b [] kmem_cache_alloc_trace+0x25/0xba [] T.492+0x24/0x26 [] pci_get_subsys+0x2e/0x73 [] pci_get_device+0x11/0x13 [] usb_amd_find_chipset_info+0x3f/0x18a ... It turns out that this function calls pci_get_device under a spin_lock with irqs disabled, but the pci_get_device function is only allowed in preemptible context. This patch fixes the warning by making all data-structure modifications on temporal storage and commiting this back into the visible structure at the end. While at it, this patch also moves the pci_dev_put calls out of the spinlocks because this function might sleep too. Signed-off-by: Joerg Roedel Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 117 ++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 1d586d4f7b56..9b166d70ae91 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -84,65 +84,92 @@ int usb_amd_find_chipset_info(void) { u8 rev = 0; unsigned long flags; + struct amd_chipset_info info; + int ret; spin_lock_irqsave(&amd_lock, flags); - amd_chipset.probe_count++; /* probe only once */ - if (amd_chipset.probe_count > 1) { + if (amd_chipset.probe_count > 0) { + amd_chipset.probe_count++; spin_unlock_irqrestore(&amd_lock, flags); return amd_chipset.probe_result; } + memset(&info, 0, sizeof(info)); + spin_unlock_irqrestore(&amd_lock, flags); - amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); - if (amd_chipset.smbus_dev) { - rev = amd_chipset.smbus_dev->revision; + info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); + if (info.smbus_dev) { + rev = info.smbus_dev->revision; if (rev >= 0x40) - amd_chipset.sb_type = 1; + info.sb_type = 1; else if (rev >= 0x30 && rev <= 0x3b) - amd_chipset.sb_type = 3; + info.sb_type = 3; } else { - amd_chipset.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, - 0x780b, NULL); - if (!amd_chipset.smbus_dev) { - spin_unlock_irqrestore(&amd_lock, flags); - return 0; + info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, + 0x780b, NULL); + if (!info.smbus_dev) { + ret = 0; + goto commit; } - rev = amd_chipset.smbus_dev->revision; + + rev = info.smbus_dev->revision; if (rev >= 0x11 && rev <= 0x18) - amd_chipset.sb_type = 2; + info.sb_type = 2; } - if (amd_chipset.sb_type == 0) { - if (amd_chipset.smbus_dev) { - pci_dev_put(amd_chipset.smbus_dev); - amd_chipset.smbus_dev = NULL; + if (info.sb_type == 0) { + if (info.smbus_dev) { + pci_dev_put(info.smbus_dev); + info.smbus_dev = NULL; } - spin_unlock_irqrestore(&amd_lock, flags); - return 0; + ret = 0; + goto commit; } - amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL); - if (amd_chipset.nb_dev) { - amd_chipset.nb_type = 1; + info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x9601, NULL); + if (info.nb_dev) { + info.nb_type = 1; } else { - amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, - 0x1510, NULL); - if (amd_chipset.nb_dev) { - amd_chipset.nb_type = 2; - } else { - amd_chipset.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, - 0x9600, NULL); - if (amd_chipset.nb_dev) - amd_chipset.nb_type = 3; + info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1510, NULL); + if (info.nb_dev) { + info.nb_type = 2; + } else { + info.nb_dev = pci_get_device(PCI_VENDOR_ID_AMD, + 0x9600, NULL); + if (info.nb_dev) + info.nb_type = 3; } } - amd_chipset.probe_result = 1; + ret = info.probe_result = 1; printk(KERN_DEBUG "QUIRK: Enable AMD PLL fix\n"); - spin_unlock_irqrestore(&amd_lock, flags); - return amd_chipset.probe_result; +commit: + + spin_lock_irqsave(&amd_lock, flags); + if (amd_chipset.probe_count > 0) { + /* race - someone else was faster - drop devices */ + + /* Mark that we where here */ + amd_chipset.probe_count++; + ret = amd_chipset.probe_result; + + spin_unlock_irqrestore(&amd_lock, flags); + + if (info.nb_dev) + pci_dev_put(info.nb_dev); + if (info.smbus_dev) + pci_dev_put(info.smbus_dev); + + } else { + /* no race - commit the result */ + info.probe_count++; + amd_chipset = info; + spin_unlock_irqrestore(&amd_lock, flags); + } + + return ret; } EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info); @@ -284,6 +311,7 @@ EXPORT_SYMBOL_GPL(usb_amd_quirk_pll_enable); void usb_amd_dev_put(void) { + struct pci_dev *nb, *smbus; unsigned long flags; spin_lock_irqsave(&amd_lock, flags); @@ -294,20 +322,23 @@ void usb_amd_dev_put(void) return; } - if (amd_chipset.nb_dev) { - pci_dev_put(amd_chipset.nb_dev); - amd_chipset.nb_dev = NULL; - } - if (amd_chipset.smbus_dev) { - pci_dev_put(amd_chipset.smbus_dev); - amd_chipset.smbus_dev = NULL; - } + /* save them to pci_dev_put outside of spinlock */ + nb = amd_chipset.nb_dev; + smbus = amd_chipset.smbus_dev; + + amd_chipset.nb_dev = NULL; + amd_chipset.smbus_dev = NULL; amd_chipset.nb_type = 0; amd_chipset.sb_type = 0; amd_chipset.isoc_reqs = 0; amd_chipset.probe_result = 0; spin_unlock_irqrestore(&amd_lock, flags); + + if (nb) + pci_dev_put(nb); + if (smbus) + pci_dev_put(smbus); } EXPORT_SYMBOL_GPL(usb_amd_dev_put); -- cgit v1.2.2 From 485707116b3949ab41e1aba8d74f45a7551e3a65 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 20 Mar 2011 14:09:50 +0300 Subject: usb: pch_udc: unlock on allocation failure There was an unlock missing on the error path. Also I did a small cleanup by changing ep->dev->lock for just dev->lock. They're the same lock, but dev->lock is shorter and that's how it is used for the spin_unlock_irqrestore() call. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/pch_udc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 3e4b35e50c24..68dbcc3e4cc2 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -1608,7 +1608,7 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, return -EINVAL; if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; - spin_lock_irqsave(&ep->dev->lock, iflags); + spin_lock_irqsave(&dev->lock, iflags); /* map the buffer for dma */ if (usbreq->length && ((usbreq->dma == DMA_ADDR_INVALID) || !usbreq->dma)) { @@ -1625,8 +1625,10 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, DMA_FROM_DEVICE); } else { req->buf = kzalloc(usbreq->length, GFP_ATOMIC); - if (!req->buf) - return -ENOMEM; + if (!req->buf) { + retval = -ENOMEM; + goto probe_end; + } if (ep->in) { memcpy(req->buf, usbreq->buf, usbreq->length); req->dma = dma_map_single(&dev->pdev->dev, -- cgit v1.2.2 From 80f9df3e0093ad9f1eeefd2ff7fd27daaa518d25 Mon Sep 17 00:00:00 2001 From: "Marius B. Kotsbak" Date: Tue, 22 Mar 2011 00:01:53 +0100 Subject: USB: option: Added support for Samsung GT-B3730/GT-B3710 LTE USB modem. Bind only modem AT command endpoint to option. Signed-off-by: Marius B. Kotsbak Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 75c7f456eed5..d77ff0435896 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -407,6 +407,10 @@ static void option_instat_callback(struct urb *urb); /* ONDA MT825UP HSDPA 14.2 modem */ #define ONDA_MT825UP 0x000b +/* Samsung products */ +#define SAMSUNG_VENDOR_ID 0x04e8 +#define SAMSUNG_PRODUCT_GT_B3730 0x6889 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -968,6 +972,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, { USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */ { USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */ + { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730/GT-B3710 LTE USB modem.*/ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); -- cgit v1.2.2 From c53c2fab40cf16e13af66f40bfd27200cda98d2f Mon Sep 17 00:00:00 2001 From: Paul Friedrich Date: Fri, 18 Mar 2011 11:13:55 +0100 Subject: USB: ftdi_sio: add ids for Hameg HO720 and HO730 usb serial: ftdi_sio: add two missing USB ID's for Hameg interfaces HO720 and HO730 Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 51b780134f59..4de6ef0ae52a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -790,6 +790,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, + { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) }, { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) }, { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 0bdba7a96293..efffc23723bd 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -300,6 +300,8 @@ * Hameg HO820 and HO870 interface (using VID 0x0403) */ #define HAMEG_HO820_PID 0xed74 +#define HAMEG_HO730_PID 0xed73 +#define HAMEG_HO720_PID 0xed72 #define HAMEG_HO870_PID 0xed71 /* -- cgit v1.2.2 From 10c9ab15d6aee153968d150c05b3ee3df89673de Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Mon, 4 Apr 2011 17:57:37 +0100 Subject: usb: Fix qcserial memory leak on rmmod qcprobe function allocates serial->private but this is never freed, this patch adds a new function qc_release() which frees serial->private, after calling usb_wwan_release Signed-off-by: Steven Hardy Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 8858201eb1d3..6e3b933457f4 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -205,6 +205,18 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) return retval; } +static void qc_release(struct usb_serial *serial) +{ + struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); + + dbg("%s", __func__); + + /* Call usb_wwan release & free the private data allocated in qcprobe */ + usb_wwan_release(serial); + usb_set_serial_data(serial, NULL); + kfree(priv); +} + static struct usb_serial_driver qcdevice = { .driver = { .owner = THIS_MODULE, @@ -222,7 +234,7 @@ static struct usb_serial_driver qcdevice = { .chars_in_buffer = usb_wwan_chars_in_buffer, .attach = usb_wwan_startup, .disconnect = usb_wwan_disconnect, - .release = usb_wwan_release, + .release = qc_release, #ifdef CONFIG_PM .suspend = usb_wwan_suspend, .resume = usb_wwan_resume, -- cgit v1.2.2 From 99ab3f9e4eaec35fd2d7159c31b71f17f7e613e3 Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Mon, 4 Apr 2011 17:59:55 +0100 Subject: usb: qcserial avoid pointing to freed memory Rework the qcprobe logic such that serial->private is not set when qcprobe exits with -ENODEV, otherwise serial->private will point to freed memory on -ENODEV Signed-off-by: Steven Hardy Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 6e3b933457f4..cd638648479a 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -111,7 +111,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) ifnum = intf->desc.bInterfaceNumber; dbg("This Interface = %d", ifnum); - data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), + data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); if (!data) return -ENOMEM; @@ -134,8 +134,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { dbg("QDL port found"); - if (serial->interface->num_altsetting == 1) - return 0; + if (serial->interface->num_altsetting == 1) { + retval = 0; /* Success */ + break; + } retval = usb_set_interface(serial->dev, ifnum, 1); if (retval < 0) { @@ -145,7 +147,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) retval = -ENODEV; kfree(data); } - return retval; } break; @@ -177,7 +178,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) retval = -ENODEV; kfree(data); } - return retval; } else if (ifnum==3) { /* * NMEA (serial line 9600 8N1) @@ -199,9 +199,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) dev_err(&serial->dev->dev, "unknown number of interfaces: %d\n", nintf); kfree(data); - return -ENODEV; + retval = -ENODEV; } + /* Set serial->private if not returning -ENODEV */ + if (retval != -ENODEV) + usb_set_serial_data(serial, data); return retval; } -- cgit v1.2.2 From cb62d65f966146a39fdde548cb474dacf1d00fa5 Mon Sep 17 00:00:00 2001 From: Steven Hardy Date: Mon, 4 Apr 2011 18:02:25 +0100 Subject: usb: qcserial add missing errorpath kfrees There are two -ENODEV error paths in qcprobe where the allocated private data is not freed, this patch adds the two missing kfrees to avoid leaking memory on the error path Signed-off-by: Steven Hardy Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index cd638648479a..54a9dab1f33b 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -167,6 +167,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) "Could not set interface, error %d\n", retval); retval = -ENODEV; + kfree(data); } } else if (ifnum == 2) { dbg("Modem port found"); @@ -191,6 +192,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) "Could not set interface, error %d\n", retval); retval = -ENODEV; + kfree(data); } } break; -- cgit v1.2.2 From d834508e159fe8936f9e7fd941b1e2fe9a209d4b Mon Sep 17 00:00:00 2001 From: Valentin Longchamp Date: Wed, 23 Mar 2011 17:47:00 +0100 Subject: USB: fsl_qe_udc: send ZLP when zero flag and length % maxpacket == 0 The driver did not take the zero flag in the USB request. If the request length is the same as the endpoint's maxpacket, an additional ZLP with no data has to be transmitted. The method used here is inspired to what is done in fsl_udc_core.c (and pxa27x_udc.c and at91_udc.c) where this is supported. There already was a discussion about this topic with people from Keymile, and I propose here a better implementation: http://thread.gmane.org/gmane.linux.usb.general/38951 Signed-off-by: Valentin Longchamp Acked-by: Li Yang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/fsl_qe_udc.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index aee7e3c53c38..36613b37c504 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -1148,6 +1148,12 @@ static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame) static int txcomplete(struct qe_ep *ep, unsigned char restart) { if (ep->tx_req != NULL) { + struct qe_req *req = ep->tx_req; + unsigned zlp = 0, last_len = 0; + + last_len = min_t(unsigned, req->req.length - ep->sent, + ep->ep.maxpacket); + if (!restart) { int asent = ep->last; ep->sent += asent; @@ -1156,9 +1162,18 @@ static int txcomplete(struct qe_ep *ep, unsigned char restart) ep->last = 0; } + /* zlp needed when req->re.zero is set */ + if (req->req.zero) { + if (last_len == 0 || + (req->req.length % ep->ep.maxpacket) != 0) + zlp = 0; + else + zlp = 1; + } else + zlp = 0; + /* a request already were transmitted completely */ - if ((ep->tx_req->req.length - ep->sent) <= 0) { - ep->tx_req->req.actual = (unsigned int)ep->sent; + if (((ep->tx_req->req.length - ep->sent) <= 0) && !zlp) { done(ep, ep->tx_req, 0); ep->tx_req = NULL; ep->last = 0; @@ -1191,6 +1206,7 @@ static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame) buf = (u8 *)ep->tx_req->req.buf + ep->sent; if (buf && size) { ep->last = size; + ep->tx_req->req.actual += size; frame_set_data(frame, buf); frame_set_length(frame, size); frame_set_status(frame, FRAME_OK); -- cgit v1.2.2 From 5808544690300071f09eef9ab83a0fb1f60cf1cd Mon Sep 17 00:00:00 2001 From: Richard Retanubun Date: Thu, 17 Mar 2011 17:39:28 -0400 Subject: USB: isp1760-hcd: move imask clear after pending work is done This patch moves the HcInterrupt register write to clear the pending interrupt to after the isr work is done, doing this removes glitches in the irq line. Signed-off-by: Richard Retanubun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 795345ad45e6..564b03337e7e 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1676,13 +1676,15 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd) if (unlikely(!imask)) goto leave; - reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); if (imask & (HC_ATL_INT | HC_SOT_INT)) do_atl_int(hcd); if (imask & HC_INTL_INT) do_intl_int(hcd); + /* Clear interrupt mask on device after the work is done */ + reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); + irqret = IRQ_HANDLED; leave: spin_unlock(&priv->lock); -- cgit v1.2.2 From 2868a2b1ba8f9c7f6c4170519ebb6c62934df70e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 18 Mar 2011 21:29:01 -0700 Subject: USB: fix formatting of SuperSpeed endpoints in /proc/bus/usb/devices Isochronous and interrupt SuperSpeed endpoints use the same mechanisms for decoding bInterval values as HighSpeed ones so adjust the code accordingly. Also bandwidth reservation for SuperSpeed matches highspeed, not low/full speed. Signed-off-by: Dmitry Torokhov Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devices.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index a3d2e2399655..96fdfb815f89 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -221,7 +221,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, break; case USB_ENDPOINT_XFER_INT: type = "Int."; - if (speed == USB_SPEED_HIGH) + if (speed == USB_SPEED_HIGH || speed == USB_SPEED_SUPER) interval = 1 << (desc->bInterval - 1); else interval = desc->bInterval; @@ -229,7 +229,8 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end, default: /* "can't happen" */ return start; } - interval *= (speed == USB_SPEED_HIGH) ? 125 : 1000; + interval *= (speed == USB_SPEED_HIGH || + speed == USB_SPEED_SUPER) ? 125 : 1000; if (interval % 1000) unit = 'u'; else { @@ -542,8 +543,9 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, if (level == 0) { int max; - /* high speed reserves 80%, full/low reserves 90% */ - if (usbdev->speed == USB_SPEED_HIGH) + /* super/high speed reserves 80%, full/low reserves 90% */ + if (usbdev->speed == USB_SPEED_HIGH || + usbdev->speed == USB_SPEED_SUPER) max = 800; else max = FRAME_TIME_MAX_USECS_ALLOC; -- cgit v1.2.2 From 5a6c2f3ff039154872ce597952f8b8900ea0d732 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 20 Mar 2011 02:15:17 -0700 Subject: USB: xhci - fix unsafe macro definitions Macro arguments used in expressions need to be enclosed in parenthesis to avoid unpleasant surprises. This should be queued for kernels back to 2.6.31 Signed-off-by: Dmitry Torokhov Signed-off-by: Sarah Sharp Cc: stable@kernel.org --- drivers/usb/host/xhci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 07e263063e37..91b1a237c11e 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -232,7 +232,7 @@ struct xhci_op_regs { * notification type that matches a bit set in this bit field. */ #define DEV_NOTE_MASK (0xffff) -#define ENABLE_DEV_NOTE(x) (1 << x) +#define ENABLE_DEV_NOTE(x) (1 << (x)) /* Most of the device notification types should only be used for debug. * SW does need to pay attention to function wake notifications. */ @@ -601,11 +601,11 @@ struct xhci_ep_ctx { #define EP_STATE_STOPPED 3 #define EP_STATE_ERROR 4 /* Mult - Max number of burtst within an interval, in EP companion desc. */ -#define EP_MULT(p) ((p & 0x3) << 8) +#define EP_MULT(p) (((p) & 0x3) << 8) /* bits 10:14 are Max Primary Streams */ /* bit 15 is Linear Stream Array */ /* Interval - period between requests to an endpoint - 125u increments. */ -#define EP_INTERVAL(p) ((p & 0xff) << 16) +#define EP_INTERVAL(p) (((p) & 0xff) << 16) #define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff)) #define EP_MAXPSTREAMS_MASK (0x1f << 10) #define EP_MAXPSTREAMS(p) (((p) << 10) & EP_MAXPSTREAMS_MASK) -- cgit v1.2.2 From 22e0487047567252d5677ff35766cd884375efc2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 17 Mar 2011 22:39:49 +0300 Subject: USB: xhci: unsigned char never equals -1 There were some places that compared port_speed == -1 where port_speed is a u8. This doesn't work unless we cast the -1 to u8. Some places did it correctly. Instead of using -1 directly, I've created a DUPLICATE_ENTRY define which does the cast and is more descriptive as well. Signed-off-by: Dan Carpenter Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-mem.c | 8 ++++---- drivers/usb/host/xhci-ring.c | 4 ++-- drivers/usb/host/xhci.h | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index a003e79aacdc..ab7fc2b71a8c 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -846,7 +846,7 @@ static u32 xhci_find_real_port_number(struct xhci_hcd *xhci, * Skip ports that don't have known speeds, or have duplicate * Extended Capabilities port speed entries. */ - if (port_speed == 0 || port_speed == -1) + if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) continue; /* @@ -1727,12 +1727,12 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, * found a similar duplicate. */ if (xhci->port_array[i] != major_revision && - xhci->port_array[i] != (u8) -1) { + xhci->port_array[i] != DUPLICATE_ENTRY) { if (xhci->port_array[i] == 0x03) xhci->num_usb3_ports--; else xhci->num_usb2_ports--; - xhci->port_array[i] = (u8) -1; + xhci->port_array[i] = DUPLICATE_ENTRY; } /* FIXME: Should we disable the port? */ continue; @@ -1831,7 +1831,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) for (i = 0; i < num_ports; i++) { if (xhci->port_array[i] == 0x03 || xhci->port_array[i] == 0 || - xhci->port_array[i] == -1) + xhci->port_array[i] == DUPLICATE_ENTRY) continue; xhci->usb2_ports[port_index] = diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cfc1ad92473f..c6d1462aa1c3 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1209,7 +1209,7 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd, * Skip ports that don't have known speeds, or have duplicate * Extended Capabilities port speed entries. */ - if (port_speed == 0 || port_speed == -1) + if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) continue; /* @@ -1260,7 +1260,7 @@ static void handle_port_status(struct xhci_hcd *xhci, port_id); goto cleanup; } - if (major_revision == (u8) -1) { + if (major_revision == DUPLICATE_ENTRY) { xhci_warn(xhci, "Event for port %u duplicated in" "Extended Capabilities, ignoring.\n", port_id); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 91b1a237c11e..bdb78f51735e 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -348,6 +348,9 @@ struct xhci_op_regs { /* Initiate a warm port reset - complete when PORT_WRC is '1' */ #define PORT_WR (1 << 31) +/* We mark duplicate entries with -1 */ +#define DUPLICATE_ENTRY ((u8)(-1)) + /* Port Power Management Status and Control - port_power_base bitmasks */ /* Inactivity timer value for transitions into U1, in microseconds. * Timeout can be up to 127us. 0xFF means an infinite timeout. -- cgit v1.2.2 From 575688e1e5f462c44ddd608ce3ec9f38b64c3c0d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 20 Mar 2011 02:15:16 -0700 Subject: USB: xhci - remove excessive 'inline' markings Remove 'inline' markings from file-local functions and let compiler do its job and inline what makes sense for given architecture. Signed-off-by: Dmitry Torokhov Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-mem.c | 8 ++++---- drivers/usb/host/xhci-ring.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index ab7fc2b71a8c..7f56c9b80692 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -982,7 +982,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval * is set to 0. */ -static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, +static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, struct usb_host_endpoint *ep) { unsigned int interval = 0; @@ -1041,7 +1041,7 @@ static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev, * transaction opportunities per microframe", but that goes in the Max Burst * endpoint context field. */ -static inline u32 xhci_get_endpoint_mult(struct usb_device *udev, +static u32 xhci_get_endpoint_mult(struct usb_device *udev, struct usb_host_endpoint *ep) { if (udev->speed != USB_SPEED_SUPER || @@ -1050,7 +1050,7 @@ static inline u32 xhci_get_endpoint_mult(struct usb_device *udev, return ep->ss_ep_comp.bmAttributes; } -static inline u32 xhci_get_endpoint_type(struct usb_device *udev, +static u32 xhci_get_endpoint_type(struct usb_device *udev, struct usb_host_endpoint *ep) { int in; @@ -1084,7 +1084,7 @@ static inline u32 xhci_get_endpoint_type(struct usb_device *udev, * Basically, this is the maxpacket size, multiplied by the burst size * and mult size. */ -static inline u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, +static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci, struct usb_device *udev, struct usb_host_endpoint *ep) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c6d1462aa1c3..0161eb053225 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -93,7 +93,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, /* Does this link TRB point to the first segment in a ring, * or was the previous TRB the last TRB on the last segment in the ERST? */ -static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring, +static bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring, struct xhci_segment *seg, union xhci_trb *trb) { if (ring == xhci->event_ring) @@ -107,7 +107,7 @@ static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring * segment? I.e. would the updated event TRB pointer step off the end of the * event seg? */ -static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, +static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, struct xhci_segment *seg, union xhci_trb *trb) { if (ring == xhci->event_ring) @@ -116,7 +116,7 @@ static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK); } -static inline int enqueue_is_link_trb(struct xhci_ring *ring) +static int enqueue_is_link_trb(struct xhci_ring *ring) { struct xhci_link_trb *link = &ring->enqueue->link; return ((link->control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)); @@ -592,7 +592,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, ep->ep_state |= SET_DEQ_PENDING; } -static inline void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, +static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) { ep->ep_state &= ~EP_HALT_PENDING; -- cgit v1.2.2 From 926008c9386dde09b015753b6681c502177baa30 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 23 Mar 2011 20:47:05 -0700 Subject: USB: xhci: simplify logic of skipping missed isoc TDs The logic of the handling Missed Service Error Events was pretty confusing as we were checking the same condition several times. In addition, it caused compiler warning since the compiler could not figure out that event_trb is actually unused in case we are skipping current TD. Fix that by rearranging "skip" condition checks, and factor out skip_isoc_td() so that it is called explicitly. Signed-off-by: Dmitry Torokhov Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 172 +++++++++++++++++++++++-------------------- 1 file changed, 94 insertions(+), 78 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 0161eb053225..b69a0a136e66 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1675,71 +1675,52 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, struct urb_priv *urb_priv; int idx; int len = 0; - int skip_td = 0; union xhci_trb *cur_trb; struct xhci_segment *cur_seg; + struct usb_iso_packet_descriptor *frame; u32 trb_comp_code; + bool skip_td = false; ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer); trb_comp_code = GET_COMP_CODE(event->transfer_len); urb_priv = td->urb->hcpriv; idx = urb_priv->td_cnt; + frame = &td->urb->iso_frame_desc[idx]; - if (ep->skip) { - /* The transfer is partly done */ - *status = -EXDEV; - td->urb->iso_frame_desc[idx].status = -EXDEV; - } else { - /* handle completion code */ - switch (trb_comp_code) { - case COMP_SUCCESS: - td->urb->iso_frame_desc[idx].status = 0; - xhci_dbg(xhci, "Successful isoc transfer!\n"); - break; - case COMP_SHORT_TX: - if (td->urb->transfer_flags & URB_SHORT_NOT_OK) - td->urb->iso_frame_desc[idx].status = - -EREMOTEIO; - else - td->urb->iso_frame_desc[idx].status = 0; - break; - case COMP_BW_OVER: - td->urb->iso_frame_desc[idx].status = -ECOMM; - skip_td = 1; - break; - case COMP_BUFF_OVER: - case COMP_BABBLE: - td->urb->iso_frame_desc[idx].status = -EOVERFLOW; - skip_td = 1; - break; - case COMP_STALL: - td->urb->iso_frame_desc[idx].status = -EPROTO; - skip_td = 1; - break; - case COMP_STOP: - case COMP_STOP_INVAL: - break; - default: - td->urb->iso_frame_desc[idx].status = -1; - break; - } - } - - /* calc actual length */ - if (ep->skip) { - td->urb->iso_frame_desc[idx].actual_length = 0; - /* Update ring dequeue pointer */ - while (ep_ring->dequeue != td->last_trb) - inc_deq(xhci, ep_ring, false); - inc_deq(xhci, ep_ring, false); - return finish_td(xhci, td, event_trb, event, ep, status, true); + /* handle completion code */ + switch (trb_comp_code) { + case COMP_SUCCESS: + frame->status = 0; + xhci_dbg(xhci, "Successful isoc transfer!\n"); + break; + case COMP_SHORT_TX: + frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? + -EREMOTEIO : 0; + break; + case COMP_BW_OVER: + frame->status = -ECOMM; + skip_td = true; + break; + case COMP_BUFF_OVER: + case COMP_BABBLE: + frame->status = -EOVERFLOW; + skip_td = true; + break; + case COMP_STALL: + frame->status = -EPROTO; + skip_td = true; + break; + case COMP_STOP: + case COMP_STOP_INVAL: + break; + default: + frame->status = -1; + break; } - if (trb_comp_code == COMP_SUCCESS || skip_td == 1) { - td->urb->iso_frame_desc[idx].actual_length = - td->urb->iso_frame_desc[idx].length; - td->urb->actual_length += - td->urb->iso_frame_desc[idx].length; + if (trb_comp_code == COMP_SUCCESS || skip_td) { + frame->actual_length = frame->length; + td->urb->actual_length += frame->length; } else { for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg; cur_trb != event_trb; @@ -1755,7 +1736,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, TRB_LEN(event->transfer_len); if (trb_comp_code != COMP_STOP_INVAL) { - td->urb->iso_frame_desc[idx].actual_length = len; + frame->actual_length = len; td->urb->actual_length += len; } } @@ -1766,6 +1747,35 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, return finish_td(xhci, td, event_trb, event, ep, status, false); } +static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_transfer_event *event, + struct xhci_virt_ep *ep, int *status) +{ + struct xhci_ring *ep_ring; + struct urb_priv *urb_priv; + struct usb_iso_packet_descriptor *frame; + int idx; + + ep_ring = xhci_dma_to_transfer_ring(ep, event->buffer); + urb_priv = td->urb->hcpriv; + idx = urb_priv->td_cnt; + frame = &td->urb->iso_frame_desc[idx]; + + /* The transfer is partly done */ + *status = -EXDEV; + frame->status = -EXDEV; + + /* calc actual length */ + frame->actual_length = 0; + + /* Update ring dequeue pointer */ + while (ep_ring->dequeue != td->last_trb) + inc_deq(xhci, ep_ring, false); + inc_deq(xhci, ep_ring, false); + + return finish_td(xhci, td, NULL, event, ep, status, true); +} + /* * Process bulk and interrupt tds, update urb status and actual_length. */ @@ -2024,36 +2034,42 @@ static int handle_tx_event(struct xhci_hcd *xhci, } td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); + /* Is this a TRB in the currently executing TD? */ event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, td->last_trb, event_dma); - if (event_seg && ep->skip) { + if (!event_seg) { + if (!ep->skip || + !usb_endpoint_xfer_isoc(&td->urb->ep->desc)) { + /* HC is busted, give up! */ + xhci_err(xhci, + "ERROR Transfer event TRB DMA ptr not " + "part of current TD\n"); + return -ESHUTDOWN; + } + + ret = skip_isoc_td(xhci, td, event, ep, &status); + goto cleanup; + } + + if (ep->skip) { xhci_dbg(xhci, "Found td. Clear skip flag.\n"); ep->skip = false; } - if (!event_seg && - (!ep->skip || !usb_endpoint_xfer_isoc(&td->urb->ep->desc))) { - /* HC is busted, give up! */ - xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not " - "part of current TD\n"); - return -ESHUTDOWN; - } - if (event_seg) { - event_trb = &event_seg->trbs[(event_dma - - event_seg->dma) / sizeof(*event_trb)]; - /* - * No-op TRB should not trigger interrupts. - * If event_trb is a no-op TRB, it means the - * corresponding TD has been cancelled. Just ignore - * the TD. - */ - if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK) - == TRB_TYPE(TRB_TR_NOOP)) { - xhci_dbg(xhci, "event_trb is a no-op TRB. " - "Skip it\n"); - goto cleanup; - } + event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / + sizeof(*event_trb)]; + /* + * No-op TRB should not trigger interrupts. + * If event_trb is a no-op TRB, it means the + * corresponding TD has been cancelled. Just ignore + * the TD. + */ + if ((event_trb->generic.field[3] & TRB_TYPE_BITMASK) + == TRB_TYPE(TRB_TR_NOOP)) { + xhci_dbg(xhci, + "event_trb is a no-op TRB. Skip it\n"); + goto cleanup; } /* Now update the urb's actual_length and give back to -- cgit v1.2.2 From dfa49c4ad120a784ef1ff0717168aa79f55a483a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 23 Mar 2011 22:41:23 -0700 Subject: USB: xhci - fix math in xhci_get_endpoint_interval() When parsing exponent-expressed intervals we subtract 1 from the value and then expect it to match with original + 1, which is highly unlikely, and we end with frequent spew: usb 3-4: ep 0x83 - rounding interval to 512 microframes Also, parsing interval for fullspeed isochronous endpoints was incorrect - according to USB spec they use exponent-based intervals (but xHCI spec claims frame-based intervals). I trust USB spec more, especially since USB core agrees with it. This should be queued for stable kernels back to 2.6.31. Reviewed-by: Micah Elizabeth Scott Signed-off-by: Dmitry Torokhov Signed-off-by: Sarah Sharp Cc: stable@kernel.org --- drivers/usb/host/xhci-mem.c | 90 +++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 7f56c9b80692..627f3438028c 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -974,6 +974,47 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud return 0; } +/* + * Convert interval expressed as 2^(bInterval - 1) == interval into + * straight exponent value 2^n == interval. + * + */ +static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + unsigned int interval; + + interval = clamp_val(ep->desc.bInterval, 1, 16) - 1; + if (interval != ep->desc.bInterval - 1) + dev_warn(&udev->dev, + "ep %#x - rounding interval to %d microframes\n", + ep->desc.bEndpointAddress, + 1 << interval); + + return interval; +} + +/* + * Convert bInterval expressed in frames (in 1-255 range) to exponent of + * microframes, rounded down to nearest power of 2. + */ +static unsigned int xhci_parse_frame_interval(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + unsigned int interval; + + interval = fls(8 * ep->desc.bInterval) - 1; + interval = clamp_val(interval, 3, 10); + if ((1 << interval) != 8 * ep->desc.bInterval) + dev_warn(&udev->dev, + "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n", + ep->desc.bEndpointAddress, + 1 << interval, + 8 * ep->desc.bInterval); + + return interval; +} + /* Return the polling or NAK interval. * * The polling interval is expressed in "microframes". If xHCI's Interval field @@ -991,45 +1032,38 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, case USB_SPEED_HIGH: /* Max NAK rate */ if (usb_endpoint_xfer_control(&ep->desc) || - usb_endpoint_xfer_bulk(&ep->desc)) + usb_endpoint_xfer_bulk(&ep->desc)) { interval = ep->desc.bInterval; + break; + } /* Fall through - SS and HS isoc/int have same decoding */ + case USB_SPEED_SUPER: if (usb_endpoint_xfer_int(&ep->desc) || - usb_endpoint_xfer_isoc(&ep->desc)) { - if (ep->desc.bInterval == 0) - interval = 0; - else - interval = ep->desc.bInterval - 1; - if (interval > 15) - interval = 15; - if (interval != ep->desc.bInterval + 1) - dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n", - ep->desc.bEndpointAddress, 1 << interval); + usb_endpoint_xfer_isoc(&ep->desc)) { + interval = xhci_parse_exponent_interval(udev, ep); } break; - /* Convert bInterval (in 1-255 frames) to microframes and round down to - * nearest power of 2. - */ + case USB_SPEED_FULL: + if (usb_endpoint_xfer_int(&ep->desc)) { + interval = xhci_parse_exponent_interval(udev, ep); + break; + } + /* + * Fall through for isochronous endpoint interval decoding + * since it uses the same rules as low speed interrupt + * endpoints. + */ + case USB_SPEED_LOW: if (usb_endpoint_xfer_int(&ep->desc) || - usb_endpoint_xfer_isoc(&ep->desc)) { - interval = fls(8*ep->desc.bInterval) - 1; - if (interval > 10) - interval = 10; - if (interval < 3) - interval = 3; - if ((1 << interval) != 8*ep->desc.bInterval) - dev_warn(&udev->dev, - "ep %#x - rounding interval" - " to %d microframes, " - "ep desc says %d microframes\n", - ep->desc.bEndpointAddress, - 1 << interval, - 8*ep->desc.bInterval); + usb_endpoint_xfer_isoc(&ep->desc)) { + + interval = xhci_parse_frame_interval(udev, ep); } break; + default: BUG(); } -- cgit v1.2.2 From 386139d7c8f22d4983ca89de35d339cc41bb0996 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 24 Mar 2011 08:02:58 -0700 Subject: xhci: Fix NULL pointer deref in handle_port_status() When we get a port status change event, we need to figure out what type of port it came from: a USB 3.0 port, or a USB 2.0/1.1 port. We can't know which usb_hcd to use until that point, so hcd will be NULL for part of the function. Unfortunately, if any of the sanity checks fail, we'll jump to the cleanup label before hcd is set to a valid pointer, and then we'll attempt to tell the USB core to kick the hcd, which is NULL. Skip kicking the roothub if the sanity checks fail. Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-ring.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b69a0a136e66..b0b4cc3b8584 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1235,6 +1235,7 @@ static void handle_port_status(struct xhci_hcd *xhci, u8 major_revision; struct xhci_bus_state *bus_state; u32 __iomem **port_array; + bool bogus_port_status = false; /* Port status change events always have a successful completion code */ if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) { @@ -1247,6 +1248,7 @@ static void handle_port_status(struct xhci_hcd *xhci, max_ports = HCS_MAX_PORTS(xhci->hcs_params1); if ((port_id <= 0) || (port_id > max_ports)) { xhci_warn(xhci, "Invalid port id %d\n", port_id); + bogus_port_status = true; goto cleanup; } @@ -1258,12 +1260,14 @@ static void handle_port_status(struct xhci_hcd *xhci, xhci_warn(xhci, "Event for port %u not in " "Extended Capabilities, ignoring.\n", port_id); + bogus_port_status = true; goto cleanup; } if (major_revision == DUPLICATE_ENTRY) { xhci_warn(xhci, "Event for port %u duplicated in" "Extended Capabilities, ignoring.\n", port_id); + bogus_port_status = true; goto cleanup; } @@ -1335,6 +1339,13 @@ cleanup: /* Update event ring dequeue pointer before dropping the lock */ inc_deq(xhci, xhci->event_ring, true); + /* Don't make the USB core poll the roothub if we got a bad port status + * change event. Besides, at that point we can't tell which roothub + * (USB 2.0 or USB 3.0) to kick. + */ + if (bogus_port_status) + return; + spin_unlock(&xhci->lock); /* Pass this up to the core */ usb_hcd_poll_rh_status(hcd); -- cgit v1.2.2 From 2dea75d96ade3c7cd2bfe73f99c7b3291dc3d03a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 12 Apr 2011 23:06:28 -0700 Subject: USB: xhci - also free streams when resetting devices Currently, when resetting a device, xHCI driver disables all but one endpoints and frees their rings, but leaves alone any streams that might have been allocated. Later, when users try to free allocated streams, we oops in xhci_setup_no_streams_ep_input_ctx() because ep->ring is NULL. Let's free not only rings but also stream data as well, so that calling free_streams() on a device that was reset will be safe. This should be queued for stable trees back to 2.6.35. Reviewed-by: Micah Elizabeth Scott Signed-off-by: Dmitry Torokhov Signed-off-by: Sarah Sharp Cc: stable@kernel.org --- drivers/usb/host/xhci.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 196e0181b2ed..48706c0d6577 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2386,10 +2386,18 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Everything but endpoint 0 is disabled, so free or cache the rings. */ last_freed_endpoint = 1; for (i = 1; i < 31; ++i) { - if (!virt_dev->eps[i].ring) - continue; - xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); - last_freed_endpoint = i; + struct xhci_virt_ep *ep = &virt_dev->eps[i]; + + if (ep->ep_state & EP_HAS_STREAMS) { + xhci_free_stream_info(xhci, ep->stream_info); + ep->stream_info = NULL; + ep->ep_state &= ~EP_HAS_STREAMS; + } + + if (ep->ring) { + xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); + last_freed_endpoint = i; + } } xhci_dbg(xhci, "Output context after successful reset device cmd:\n"); xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint); -- cgit v1.2.2 From b214f191d95ba4b5a35aebd69cd129cf7e3b1884 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 28 Sep 2010 00:57:32 -0400 Subject: USB: Fix unplug of device with active streams If I unplug a device while the UAS driver is loaded, I get an oops in usb_free_streams(). This is because usb_unbind_interface() calls usb_disable_interface() which calls usb_disable_endpoint() which sets ep_out and ep_in to NULL. Then the UAS driver calls usb_pipe_endpoint() which returns a NULL pointer and passes an array of NULL pointers to usb_free_streams(). I think the correct fix for this is to check for the NULL pointer in usb_free_streams() rather than making the driver check for this situation. My original patch for this checked for dev->state == USB_STATE_NOTATTACHED, but the call to usb_disable_interface() is conditional, so not all drivers would want this check. Note from Sarah Sharp: This patch does avoid a potential dereference, but the real fix (which will be implemented later) is to set the .soft_unbind flag in the usb_driver structure for the UAS driver, and all drivers that allocate streams. The driver should free any streams when it is unbound from the interface. This avoids leaking stream rings in the xHCI driver when usb_disable_interface() is called. This should be queued for stable trees back to 2.6.35. Signed-off-by: Matthew Wilcox Signed-off-by: Sarah Sharp Cc: stable@kernel.org --- drivers/usb/core/hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 8eed05d23838..77a7faec8d78 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1908,7 +1908,7 @@ void usb_free_streams(struct usb_interface *interface, /* Streams only apply to bulk endpoints. */ for (i = 0; i < num_eps; i++) - if (!usb_endpoint_xfer_bulk(&eps[i]->desc)) + if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc)) return; hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); -- cgit v1.2.2 From a8f08d86dbf1b7bb5869cf1807d2fd40ec9d6d0a Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Thu, 31 Mar 2011 14:56:50 +0800 Subject: usbcore: Bug fix: system can't suspend with USB3.0 device connected to USB3.0 hub This patch clear PORT_POWER when suspend a USB3.0 device behind a USB3.0 external hub, so the system can suspend and resume. Note USB3.0 device may not work after system resume and this is a temporary workaround. The correct fix will be in future patches. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/core/hub.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8fb754916c67..93720bdc9efd 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2285,7 +2285,17 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) } /* see 7.1.7.6 */ - status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND); + /* Clear PORT_POWER if it's a USB3.0 device connected to USB 3.0 + * external hub. + * FIXME: this is a temporary workaround to make the system able + * to suspend/resume. + */ + if ((hub->hdev->parent != NULL) && hub_is_superspeed(hub->hdev)) + status = clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_POWER); + else + status = set_port_feature(hub->hdev, port1, + USB_PORT_FEAT_SUSPEND); if (status) { dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", port1, status); -- cgit v1.2.2 From fedd383e33f9ba9b91626f72c593ea327403bf59 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 12 Apr 2011 17:43:19 -0700 Subject: xhci: Tell USB core both roothubs lost power. On a resume, when the power is lost during hibernate, the USB core will call hub_reset_resume for the xHCI USB 2.0 roothub, but not for the USB 3.0 roothub: [ 164.748310] usb usb1: root hub lost power or was reset [ 164.748353] usb usb2: root hub lost power or was reset [ 164.748487] usb usb3: root hub lost power or was reset [ 164.748488] xhci_hcd 0000:01:00.0: Stop HCD ... [ 164.870039] hub 4-0:1.0: hub_resume ... [ 164.870054] hub 3-0:1.0: hub_reset_resume This causes issues later, because the USB core assumes the USB 3.0 hub attached to the USB 3.0 roothub is still active. It attempts to queue a control URB for the external hub, which fails because all the device slot contexts were released when the USB 3.0 roothub lost power: [ 164.980044] hub 4-1:1.0: hub_resume [ 164.980047] xhci_hcd 0000:01:00.0: Get port status returned 0x10101 [ 164.980049] xHCI xhci_urb_enqueue called with unaddressed device [ 164.980053] hub 3-0:1.0: port 1: status 0101 change 0001 [ 164.980056] hub 4-1:1.0: hub_port_status failed (err = -22) [ 164.980060] xhci_hcd 0000:01:00.0: `MEM_WRITE_DWORD(3'b000, 32'hffffc90008948440, 32'h202e1, 4'hf); [ 164.980062] xHCI xhci_urb_enqueue called with unaddressed device [ 164.980066] xhci_hcd 0000:01:00.0: clear port connect change, actual port 0 status = 0x2e1 [ 164.980069] hub 4-1:1.0: hub_port_status failed (err = -22) [ 164.980072] xhci_hcd 0000:01:00.0: get port status, actual port 1 status = 0x2a0 [ 164.980074] xHCI xhci_urb_enqueue called with unaddressed device [ 164.980077] xhci_hcd 0000:01:00.0: Get port status returned 0x100 [ 164.980079] hub 4-1:1.0: hub_port_status failed (err = -22) [ 164.980082] xHCI xhci_urb_enqueue called with unaddressed device [ 164.980085] hub 4-1:1.0: hub_port_status failed (err = -22) [ 164.980088] hub 4-1:1.0: port 4: status 0000 change 0000 [ 164.980091] xHCI xhci_urb_enqueue called with unaddressed device [ 164.980094] hub 4-1:1.0: activate --> -22 [ 164.980113] xHCI xhci_urb_enqueue called with unaddressed device [ 164.980117] hub 4-1:1.0: hub_port_status failed (err = -22) [ 164.980119] xHCI xhci_urb_enqueue called with unaddressed device [ 164.980123] hub 4-1:1.0: can't resume port 4, status -22 [ 164.980126] hub 4-1:1.0: port 4 status ffff.ffff after resume, -22 [ 164.980129] usb 4-1.4: can't resume, status -22 [ 164.980131] hub 4-1:1.0: logical disconnect on port 4 This causes issues when a USB 3.0 hard drive is attached to the external USB 3.0 hub when the system is hibernated: [ 6249.849653] sd 8:0:0:0: [sdb] Unhandled error code [ 6249.849659] sd 8:0:0:0: [sdb] Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK [ 6249.849663] sd 8:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 2a 08 00 00 02 00 [ 6249.849671] end_request: I/O error, dev sdb, sector 10760 Make sure to inform the USB core that *both* xHCI roothubs lost power. Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 48706c0d6577..c41358e4b8cc 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -771,7 +771,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) /* If restore operation fails, re-initialize the HC during resume */ if ((temp & STS_SRE) || hibernated) { - usb_root_hub_lost_power(hcd->self.root_hub); + /* Let the USB core know _both_ roothubs lost power. */ + usb_root_hub_lost_power(xhci->main_hcd->self.root_hub); + usb_root_hub_lost_power(xhci->shared_hcd->self.root_hub); xhci_dbg(xhci, "Stop HCD\n"); xhci_halt(xhci); -- cgit v1.2.2 From c41136b05d3fb213a192f76a5688ff83687c1136 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Tue, 22 Mar 2011 17:08:14 +0800 Subject: xHCI: Implement AMD PLL quirk This patch disable the optional PM feature inside the Hudson3 platform under the following conditions: 1. If an isochronous device is connected to xHCI port and is active; 2. Optional PM feature that powers down the internal Bus PLL when the link is in low power state is enabled. The PM feature needs to be disabled to eliminate PLL startup delays when the link comes out of low power state. The performance of DMA data transfer could be impacted if system delay were encountered and in addition to the PLL start up delays. Disabling the PM would leave room for unpredictable system delays in order to guarantee uninterrupted data transfer to isochronous audio or video stream devices that require time sensitive information. If data in an audio/video stream was interrupted then erratic audio or video performance may be encountered. AMD PLL quirk is already implemented in OHCI/EHCI driver. After moving the quirk code to pci-quirks.c and export them, xHCI driver can call it directly without having the quirk implementation in itself. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-pci.c | 4 ++++ drivers/usb/host/xhci-ring.c | 24 +++++++++++++++++++++++- drivers/usb/host/xhci.c | 3 +++ drivers/usb/host/xhci.h | 2 ++ 4 files changed, 32 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index ceea9f33491c..a10494c2f3c7 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -114,6 +114,10 @@ static int xhci_pci_setup(struct usb_hcd *hcd) if (pdev->vendor == PCI_VENDOR_ID_NEC) xhci->quirks |= XHCI_NEC_HOST; + /* AMD PLL quirk */ + if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) + xhci->quirks |= XHCI_AMD_PLL_FIX; + /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b0b4cc3b8584..7437386a9a50 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -619,6 +619,13 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, /* Only giveback urb when this is the last td in urb */ if (urb_priv->td_cnt == urb_priv->length) { + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--; + if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { + if (xhci->quirks & XHCI_AMD_PLL_FIX) + usb_amd_quirk_pll_enable(); + } + } usb_hcd_unlink_urb_from_ep(hcd, urb); xhci_dbg(xhci, "Giveback %s URB %p\n", adjective, urb); @@ -1565,8 +1572,17 @@ td_cleanup: urb_priv->td_cnt++; /* Giveback the urb when all the tds are completed */ - if (urb_priv->td_cnt == urb_priv->length) + if (urb_priv->td_cnt == urb_priv->length) { ret = 1; + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { + xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs--; + if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs + == 0) { + if (xhci->quirks & XHCI_AMD_PLL_FIX) + usb_amd_quirk_pll_enable(); + } + } + } } return ret; @@ -3153,6 +3169,12 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } } + if (xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs == 0) { + if (xhci->quirks & XHCI_AMD_PLL_FIX) + usb_amd_quirk_pll_disable(); + } + xhci_to_hcd(xhci)->self.bandwidth_isoc_reqs++; + giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_cycle, start_trb); return 0; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index c41358e4b8cc..81b976e45880 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -550,6 +550,9 @@ void xhci_stop(struct usb_hcd *hcd) del_timer_sync(&xhci->event_ring_timer); #endif + if (xhci->quirks & XHCI_AMD_PLL_FIX) + usb_amd_dev_put(); + xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = xhci_readl(xhci, &xhci->op_regs->status); xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index bdb78f51735e..ba1be6b7cc6d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -30,6 +30,7 @@ /* Code sharing between pci-quirks and xhci hcd */ #include "xhci-ext-caps.h" +#include "pci-quirks.h" /* xHCI PCI Configuration Registers */ #define XHCI_SBRN_OFFSET (0x60) @@ -1279,6 +1280,7 @@ struct xhci_hcd { #define XHCI_LINK_TRB_QUIRK (1 << 0) #define XHCI_RESET_EP_QUIRK (1 << 1) #define XHCI_NEC_HOST (1 << 2) +#define XHCI_AMD_PLL_FIX (1 << 3) /* There are two roothubs to keep track of bus suspend info for */ struct xhci_bus_state bus_state[2]; /* Is each xHCI roothub port a USB 3.0, USB 2.0, or USB 1.1 port? */ -- cgit v1.2.2 From 753d8534cc190ed144caebc2ea49ab7a43dca662 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 14 Apr 2011 13:37:07 -0700 Subject: Revert "USB: isp1760-hcd: move imask clear after pending work is done" This reverts commit 5808544690300071f09eef9ab83a0fb1f60cf1cd. To quote Richard: I don't think this should be mainlined. It was a misunderstanding on my part. If you see all the other hdc drivers in the same location, they all do the same thing (i.e. clear the interrupt status first, then do the work) that "glitch" I think I saw was actually two back-to-back interrupts. Sebastian (the original author of isp1760) explained it to me a few days after my submission. sorry for the confusion Cc: Richard Retanubun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 564b03337e7e..795345ad45e6 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1676,15 +1676,13 @@ static irqreturn_t isp1760_irq(struct usb_hcd *hcd) if (unlikely(!imask)) goto leave; + reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); if (imask & (HC_ATL_INT | HC_SOT_INT)) do_atl_int(hcd); if (imask & HC_INTL_INT) do_intl_int(hcd); - /* Clear interrupt mask on device after the work is done */ - reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); - irqret = IRQ_HANDLED; leave: spin_unlock(&priv->lock); -- cgit v1.2.2 From 79ea6c8966b861f80e77a14b2acf581563f3c83e Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Thu, 14 Apr 2011 08:05:18 +0000 Subject: bna: fix for clean fw re-initialization During a kernel crash, bna control path state machine and firmware do not get a notification and hence are not cleanly shutdown. The registers holding driver/IOC state information are not reset back to valid disabled/parking values. This causes subsequent driver initialization to hang during kdump kernel boot. This patch, during the initialization of first PCI function, resets corresponding register when unclean shutown is detect by reading chip registers. This will make sure that ioc/fw gets clean re-initialization. Signed-off-by: Debashis Dutt Signed-off-by: Rasesh Mody Signed-off-by: David S. Miller --- drivers/net/bna/bfa_ioc.c | 31 ++++++++++++++++++------------- drivers/net/bna/bfa_ioc.h | 1 + drivers/net/bna/bfa_ioc_ct.c | 28 ++++++++++++++++++++++++++++ drivers/net/bna/bfi.h | 6 ++++-- 4 files changed, 51 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c index e3de0b8625cd..7581518ecfa2 100644 --- a/drivers/net/bna/bfa_ioc.c +++ b/drivers/net/bna/bfa_ioc.c @@ -38,6 +38,8 @@ #define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc)) #define bfa_ioc_notify_fail(__ioc) \ ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc)) +#define bfa_ioc_sync_start(__ioc) \ + ((__ioc)->ioc_hwif->ioc_sync_start(__ioc)) #define bfa_ioc_sync_join(__ioc) \ ((__ioc)->ioc_hwif->ioc_sync_join(__ioc)) #define bfa_ioc_sync_leave(__ioc) \ @@ -602,7 +604,7 @@ bfa_iocpf_sm_fwcheck(struct bfa_iocpf *iocpf, enum iocpf_event event) switch (event) { case IOCPF_E_SEMLOCKED: if (bfa_ioc_firmware_lock(ioc)) { - if (bfa_ioc_sync_complete(ioc)) { + if (bfa_ioc_sync_start(ioc)) { iocpf->retry_count = 0; bfa_ioc_sync_join(ioc); bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); @@ -1314,7 +1316,7 @@ bfa_nw_ioc_fwver_cmp(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr) * execution context (driver/bios) must match. */ static bool -bfa_ioc_fwver_valid(struct bfa_ioc *ioc) +bfa_ioc_fwver_valid(struct bfa_ioc *ioc, u32 boot_env) { struct bfi_ioc_image_hdr fwhdr, *drv_fwhdr; @@ -1325,7 +1327,7 @@ bfa_ioc_fwver_valid(struct bfa_ioc *ioc) if (fwhdr.signature != drv_fwhdr->signature) return false; - if (fwhdr.exec != drv_fwhdr->exec) + if (swab32(fwhdr.param) != boot_env) return false; return bfa_nw_ioc_fwver_cmp(ioc, &fwhdr); @@ -1352,9 +1354,12 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) { enum bfi_ioc_state ioc_fwstate; bool fwvalid; + u32 boot_env; ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate); + boot_env = BFI_BOOT_LOADER_OS; + if (force) ioc_fwstate = BFI_IOC_UNINIT; @@ -1362,10 +1367,10 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) * check if firmware is valid */ fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ? - false : bfa_ioc_fwver_valid(ioc); + false : bfa_ioc_fwver_valid(ioc, boot_env); if (!fwvalid) { - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env); return; } @@ -1396,7 +1401,7 @@ bfa_ioc_hwinit(struct bfa_ioc *ioc, bool force) /** * Initialize the h/w for any other states. */ - bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id); + bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, boot_env); } void @@ -1506,7 +1511,7 @@ bfa_ioc_hb_stop(struct bfa_ioc *ioc) */ static void bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, - u32 boot_param) + u32 boot_env) { u32 *fwimg; u32 pgnum, pgoff; @@ -1558,10 +1563,10 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type, /* * Set boot type and boot param at the end. */ - writel((swab32(swab32(boot_type))), ((ioc->ioc_regs.smem_page_start) + writel(boot_type, ((ioc->ioc_regs.smem_page_start) + (BFI_BOOT_TYPE_OFF))); - writel((swab32(swab32(boot_param))), ((ioc->ioc_regs.smem_page_start) - + (BFI_BOOT_PARAM_OFF))); + writel(boot_env, ((ioc->ioc_regs.smem_page_start) + + (BFI_BOOT_LOADER_OFF))); } static void @@ -1721,7 +1726,7 @@ bfa_ioc_pll_init(struct bfa_ioc *ioc) * as the entry vector. */ static void -bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) +bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_env) { void __iomem *rb; @@ -1734,7 +1739,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) * Initialize IOC state of all functions on a chip reset. */ rb = ioc->pcidev.pci_bar_kva; - if (boot_param == BFI_BOOT_TYPE_MEMTEST) { + if (boot_type == BFI_BOOT_TYPE_MEMTEST) { writel(BFI_IOC_MEMTEST, (rb + BFA_IOC0_STATE_REG)); writel(BFI_IOC_MEMTEST, (rb + BFA_IOC1_STATE_REG)); } else { @@ -1743,7 +1748,7 @@ bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type, u32 boot_param) } bfa_ioc_msgflush(ioc); - bfa_ioc_download_fw(ioc, boot_type, boot_param); + bfa_ioc_download_fw(ioc, boot_type, boot_env); /** * Enable interrupts just before starting LPU diff --git a/drivers/net/bna/bfa_ioc.h b/drivers/net/bna/bfa_ioc.h index e4974bc24ef6..bd48abee781f 100644 --- a/drivers/net/bna/bfa_ioc.h +++ b/drivers/net/bna/bfa_ioc.h @@ -194,6 +194,7 @@ struct bfa_ioc_hwif { bool msix); void (*ioc_notify_fail) (struct bfa_ioc *ioc); void (*ioc_ownership_reset) (struct bfa_ioc *ioc); + bool (*ioc_sync_start) (struct bfa_ioc *ioc); void (*ioc_sync_join) (struct bfa_ioc *ioc); void (*ioc_sync_leave) (struct bfa_ioc *ioc); void (*ioc_sync_ack) (struct bfa_ioc *ioc); diff --git a/drivers/net/bna/bfa_ioc_ct.c b/drivers/net/bna/bfa_ioc_ct.c index 469997c4ffd1..87aecdf22cf9 100644 --- a/drivers/net/bna/bfa_ioc_ct.c +++ b/drivers/net/bna/bfa_ioc_ct.c @@ -41,6 +41,7 @@ static void bfa_ioc_ct_map_port(struct bfa_ioc *ioc); static void bfa_ioc_ct_isr_mode_set(struct bfa_ioc *ioc, bool msix); static void bfa_ioc_ct_notify_fail(struct bfa_ioc *ioc); static void bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc); +static bool bfa_ioc_ct_sync_start(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_join(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_leave(struct bfa_ioc *ioc); static void bfa_ioc_ct_sync_ack(struct bfa_ioc *ioc); @@ -63,6 +64,7 @@ bfa_nw_ioc_set_ct_hwif(struct bfa_ioc *ioc) nw_hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; nw_hwif_ct.ioc_notify_fail = bfa_ioc_ct_notify_fail; nw_hwif_ct.ioc_ownership_reset = bfa_ioc_ct_ownership_reset; + nw_hwif_ct.ioc_sync_start = bfa_ioc_ct_sync_start; nw_hwif_ct.ioc_sync_join = bfa_ioc_ct_sync_join; nw_hwif_ct.ioc_sync_leave = bfa_ioc_ct_sync_leave; nw_hwif_ct.ioc_sync_ack = bfa_ioc_ct_sync_ack; @@ -342,6 +344,32 @@ bfa_ioc_ct_ownership_reset(struct bfa_ioc *ioc) bfa_nw_ioc_hw_sem_release(ioc); } +/** + * Synchronized IOC failure processing routines + */ +static bool +bfa_ioc_ct_sync_start(struct bfa_ioc *ioc) +{ + u32 r32 = readl(ioc->ioc_regs.ioc_fail_sync); + u32 sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); + + /* + * Driver load time. If the sync required bit for this PCI fn + * is set, it is due to an unclean exit by the driver for this + * PCI fn in the previous incarnation. Whoever comes here first + * should clean it up, no matter which PCI fn. + */ + + if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) { + writel(0, ioc->ioc_regs.ioc_fail_sync); + writel(1, ioc->ioc_regs.ioc_usage_reg); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); + writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate); + return true; + } + + return bfa_ioc_ct_sync_complete(ioc); +} /** * Synchronized IOC failure processing routines */ diff --git a/drivers/net/bna/bfi.h b/drivers/net/bna/bfi.h index a97396811050..6050379526f7 100644 --- a/drivers/net/bna/bfi.h +++ b/drivers/net/bna/bfi.h @@ -184,12 +184,14 @@ enum bfi_mclass { #define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ #define BFI_BOOT_TYPE_OFF 8 -#define BFI_BOOT_PARAM_OFF 12 +#define BFI_BOOT_LOADER_OFF 12 -#define BFI_BOOT_TYPE_NORMAL 0 /* param is device id */ +#define BFI_BOOT_TYPE_NORMAL 0 #define BFI_BOOT_TYPE_FLASH 1 #define BFI_BOOT_TYPE_MEMTEST 2 +#define BFI_BOOT_LOADER_OS 0 + #define BFI_BOOT_MEMTEST_RES_ADDR 0x900 #define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3 -- cgit v1.2.2 From 49b4947aae404c8c5758ffd1007d0d78c48b3643 Mon Sep 17 00:00:00 2001 From: Rasesh Mody Date: Thu, 14 Apr 2011 08:05:19 +0000 Subject: bna: fix memory leak during RX path cleanup The memory leak was caused by unintentional assignment of the Rx path destroy callback function pointer to NULL just after correct initialization. Signed-off-by: Debashis Dutt Signed-off-by: Rasesh Mody Signed-off-by: David S. Miller --- drivers/net/bna/bnad.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c index 9f356d5d0f33..8e6ceab9f4d8 100644 --- a/drivers/net/bna/bnad.c +++ b/drivers/net/bna/bnad.c @@ -1837,7 +1837,6 @@ bnad_setup_rx(struct bnad *bnad, uint rx_id) /* Initialize the Rx event handlers */ rx_cbfn.rcb_setup_cbfn = bnad_cb_rcb_setup; rx_cbfn.rcb_destroy_cbfn = bnad_cb_rcb_destroy; - rx_cbfn.rcb_destroy_cbfn = NULL; rx_cbfn.ccb_setup_cbfn = bnad_cb_ccb_setup; rx_cbfn.ccb_destroy_cbfn = bnad_cb_ccb_destroy; rx_cbfn.rx_cleanup_cbfn = bnad_cb_rx_cleanup; -- cgit v1.2.2 From 8e461123f28e6b17456225e70eb834b3b30d28bb Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Apr 2011 11:19:50 -0400 Subject: drm/radeon/kms: fix bad shift in atom iio table parser Noticed by Patrick Lowry. Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index d71d375149f8..7bd745689097 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -135,7 +135,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_INDEX: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((index >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + @@ -145,7 +145,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_DATA: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((data >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base + @@ -155,7 +155,7 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, case ATOM_IIO_MOVE_ATTR: temp &= ~((0xFFFFFFFF >> (32 - CU8(base + 1))) << - CU8(base + 2)); + CU8(base + 3)); temp |= ((ctx-> io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 - -- cgit v1.2.2 From a70882aa3137fff9532b51ed5d6a92922e1c4c9c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Apr 2011 17:24:07 -0400 Subject: drm/radeon/kms: add connectors even if i2c fails Sometimes the i2c test in i2c_bit_add_bus fails if this happens we fail to register the i2c adapter and eventually fail to add the connector. If i2c fails, add the connector to the user can at least force it on. Note that some distros set i2c-algo-bit.bit_test to 1 by default which sometimes fails preventing the ddc i2c adapter from being added. The i2c adapter works even if the bit test fails, probably due to pre/post_xfer not getting called in the test_bit function. I have another patch to follow up on that. See: https://bugs.freedesktop.org/show_bug.cgi?id=36221 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_connectors.c | 29 ++++++++++++----------------- drivers/gpu/drm/radeon/radeon_i2c.c | 6 ++++++ 2 files changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 2ef6d5135064..5f45fa12bb8b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1199,7 +1199,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (router->ddc_valid || router->cd_valid) { radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); if (!radeon_connector->router_bus) - goto failed; + DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n"); } switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: @@ -1208,7 +1208,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1226,7 +1226,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1249,7 +1249,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; drm_connector_attach_property(&radeon_connector->base, @@ -1290,7 +1290,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.coherent_mode_property, @@ -1329,10 +1329,10 @@ radeon_add_atom_connector(struct drm_device *dev, else radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); if (!radeon_dig_connector->dp_i2c_bus) - goto failed; + DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; drm_connector_attach_property(&radeon_connector->base, @@ -1381,7 +1381,7 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, dev->mode_config.scaling_mode_property, @@ -1457,7 +1457,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1475,7 +1475,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1493,7 +1493,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; @@ -1538,7 +1538,7 @@ radeon_add_legacy_connector(struct drm_device *dev, if (i2c_bus->valid) { radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) - goto failed; + DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_connector_attach_property(&radeon_connector->base, dev->mode_config.scaling_mode_property, @@ -1567,9 +1567,4 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_legacy_backlight_init(radeon_encoder, connector); } } - return; - -failed: - drm_connector_cleanup(connector); - kfree(connector); } diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index ccbabf734a61..983cbac75af0 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1096,6 +1096,9 @@ void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector) if (!radeon_connector->router.ddc_valid) return; + if (!radeon_connector->router_bus) + return; + radeon_i2c_get_byte(radeon_connector->router_bus, radeon_connector->router.i2c_addr, 0x3, &val); @@ -1121,6 +1124,9 @@ void radeon_router_select_cd_port(struct radeon_connector *radeon_connector) if (!radeon_connector->router.cd_valid) return; + if (!radeon_connector->router_bus) + return; + radeon_i2c_get_byte(radeon_connector->router_bus, radeon_connector->router.i2c_addr, 0x3, &val); -- cgit v1.2.2 From c344180c9e77145a9e7eab0050169c68afae04b2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 14 Apr 2011 15:21:55 -0700 Subject: drivers/rtc/rtc-mc13xxx.c: fix unterminated platform_device_id table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The platform_device_id table is supposed to be zero-terminated. Signed-off-by: Axel Lin Acked-by: Uwe Kleine-König Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-mc13xxx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index c42006469559..c5ac03793e79 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -401,6 +401,7 @@ const struct platform_device_id mc13xxx_rtc_idtable[] = { }, { .name = "mc13892-rtc", }, + { } }; static struct platform_driver mc13xxx_rtc_driver = { -- cgit v1.2.2 From 592ce316395abc6b4e96c1ac198e5f347bb5d578 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Thu, 14 Apr 2011 15:21:59 -0700 Subject: leds/leds-regulator.c: fix handling of already enabled regulators Make the driver aware of the initial status of the regulator. The leds-regulator driver was ignoring the initial status of the regulator; this resulted in rdev->use_count being incremented to 2 after calling regulator_led_set_value() in the .probe method when a regulator was already enabled at insmod time, which made it impossible to ever disable the regulator. Signed-off-by: Antonio Ospite Cc: Richard Purdie Cc: Antonio Ospite Acked-by: Mark Brown Cc: Liam Girdwood Cc: Daniel Ribeiro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/leds/leds-regulator.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c index 3790816643be..8497f56f8e46 100644 --- a/drivers/leds/leds-regulator.c +++ b/drivers/leds/leds-regulator.c @@ -178,6 +178,10 @@ static int __devinit regulator_led_probe(struct platform_device *pdev) led->cdev.flags |= LED_CORE_SUSPENDRESUME; led->vcc = vcc; + /* to handle correctly an already enabled regulator */ + if (regulator_is_enabled(led->vcc)) + led->enabled = 1; + mutex_init(&led->mutex); INIT_WORK(&led->work, led_work); -- cgit v1.2.2 From 5de1743e2434fcb24e3d944a20130029b8fe867a Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Thu, 14 Apr 2011 15:22:08 -0700 Subject: drivers/misc/sgi-gru/grufile.c: fix the wrong members of gru_chip Fix the wrong members and the wrong function's definition, since the irq_chip had changed. Signed-off-by: Wanlong Gao Cc: Jack Steiner Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/misc/sgi-gru/grufile.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index 20e4e9395b61..ecafa4ba238b 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c @@ -348,15 +348,15 @@ static unsigned long gru_chiplet_cpu_to_mmr(int chiplet, int cpu, int *corep) static int gru_irq_count[GRU_CHIPLETS_PER_BLADE]; -static void gru_noop(unsigned int irq) +static void gru_noop(struct irq_data *d) { } static struct irq_chip gru_chip[GRU_CHIPLETS_PER_BLADE] = { [0 ... GRU_CHIPLETS_PER_BLADE - 1] { - .mask = gru_noop, - .unmask = gru_noop, - .ack = gru_noop + .irq_mask = gru_noop, + .irq_unmask = gru_noop, + .irq_ack = gru_noop } }; -- cgit v1.2.2 From 13209c2a52afa691ca19e7e6ebd22d4034bdfeed Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Thu, 14 Apr 2011 15:22:14 -0700 Subject: RapidIO: add IDT CPS-1432 switch definitions Signed-off-by: Alexandre Bounine Cc: Matt Porter Cc: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/switches/idt_gen2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c index 095016a9dec1..ac2701b22e71 100644 --- a/drivers/rapidio/switches/idt_gen2.c +++ b/drivers/rapidio/switches/idt_gen2.c @@ -418,3 +418,4 @@ DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init); DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init); DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init); DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init); +DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1432, idtg2_switch_init); -- cgit v1.2.2 From 59f9996555542f901f2d01ccab5c0612c8c5c480 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Thu, 14 Apr 2011 15:22:14 -0700 Subject: RapidIO/mpc85xx: fix possible mport registration problems Fix a possible problem with mport registration left non-cleared after fsl_rio_setup() exits on link error. Abort mport initialization if registration failed. This patch is applicable to 2.6.39-rc1 only. The problem does not exist for earlier versions. Signed-off-by: Alexandre Bounine Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Cc: Thomas Moll Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rapidio/rio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index c29719cacbca..86c9a091a2ff 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1171,16 +1171,17 @@ static int rio_hdid_setup(char *str) __setup("riohdid=", rio_hdid_setup); -void rio_register_mport(struct rio_mport *port) +int rio_register_mport(struct rio_mport *port) { if (next_portid >= RIO_MAX_MPORTS) { pr_err("RIO: reached specified max number of mports\n"); - return; + return 1; } port->id = next_portid++; port->host_deviceid = rio_get_hdid(port->id); list_add_tail(&port->node, &rio_mports); + return 0; } EXPORT_SYMBOL_GPL(rio_local_get_device_id); -- cgit v1.2.2 From 12dfc843f43efe14d0cfc7a52753d971a0cc759d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 14 Apr 2011 19:07:34 -0400 Subject: drm/radeon/kms: adjust evergreen display watermark setup This patch fixes two issues: - A disabled crtc does not use any lb, so return 0 for lb size. This makes the display priority calculation more exact. - Only use 1/2 and whole lb partitions. Using smaller partitions can cause underflow to one of the displays if you have multiple large displays on the same lb. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=34534 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 89 +++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 3453910ee0f3..43fd01674489 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -353,7 +353,7 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev, struct drm_display_mode *mode, struct drm_display_mode *other_mode) { - u32 tmp = 0; + u32 tmp; /* * Line Buffer Setup * There are 3 line buffers, each one shared by 2 display controllers. @@ -363,64 +363,63 @@ static u32 evergreen_line_buffer_adjust(struct radeon_device *rdev, * first display controller * 0 - first half of lb (3840 * 2) * 1 - first 3/4 of lb (5760 * 2) - * 2 - whole lb (7680 * 2) + * 2 - whole lb (7680 * 2), other crtc must be disabled * 3 - first 1/4 of lb (1920 * 2) * second display controller * 4 - second half of lb (3840 * 2) * 5 - second 3/4 of lb (5760 * 2) - * 6 - whole lb (7680 * 2) + * 6 - whole lb (7680 * 2), other crtc must be disabled * 7 - last 1/4 of lb (1920 * 2) */ - if (mode && other_mode) { - if (mode->hdisplay > other_mode->hdisplay) { - if (mode->hdisplay > 2560) - tmp = 1; /* 3/4 */ - else - tmp = 0; /* 1/2 */ - } else if (other_mode->hdisplay > mode->hdisplay) { - if (other_mode->hdisplay > 2560) - tmp = 3; /* 1/4 */ - else - tmp = 0; /* 1/2 */ - } else + /* this can get tricky if we have two large displays on a paired group + * of crtcs. Ideally for multiple large displays we'd assign them to + * non-linked crtcs for maximum line buffer allocation. + */ + if (radeon_crtc->base.enabled && mode) { + if (other_mode) tmp = 0; /* 1/2 */ - } else if (mode) - tmp = 2; /* whole */ - else if (other_mode) - tmp = 3; /* 1/4 */ + else + tmp = 2; /* whole */ + } else + tmp = 0; /* second controller of the pair uses second half of the lb */ if (radeon_crtc->crtc_id % 2) tmp += 4; WREG32(DC_LB_MEMORY_SPLIT + radeon_crtc->crtc_offset, tmp); - switch (tmp) { - case 0: - case 4: - default: - if (ASIC_IS_DCE5(rdev)) - return 4096 * 2; - else - return 3840 * 2; - case 1: - case 5: - if (ASIC_IS_DCE5(rdev)) - return 6144 * 2; - else - return 5760 * 2; - case 2: - case 6: - if (ASIC_IS_DCE5(rdev)) - return 8192 * 2; - else - return 7680 * 2; - case 3: - case 7: - if (ASIC_IS_DCE5(rdev)) - return 2048 * 2; - else - return 1920 * 2; + if (radeon_crtc->base.enabled && mode) { + switch (tmp) { + case 0: + case 4: + default: + if (ASIC_IS_DCE5(rdev)) + return 4096 * 2; + else + return 3840 * 2; + case 1: + case 5: + if (ASIC_IS_DCE5(rdev)) + return 6144 * 2; + else + return 5760 * 2; + case 2: + case 6: + if (ASIC_IS_DCE5(rdev)) + return 8192 * 2; + else + return 7680 * 2; + case 3: + case 7: + if (ASIC_IS_DCE5(rdev)) + return 2048 * 2; + else + return 1920 * 2; + } } + + /* controller not enabled, so no lb used */ + return 0; } static u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev) -- cgit v1.2.2 From a920ff41cb3d2b03da095c4fa1a11b71417ae2a4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 17 Apr 2011 10:20:19 +0200 Subject: i2c: Improve deprecation warnings When warning on the use of deprecated i2c_driver methods attach_adapter and detach_adapter, mention the name of the driver which needs to be updated. Signed-off-by: Jean Delvare Cc: Benjamin Herrenschmidt --- drivers/i2c/i2c-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 70c30e6bce0b..9a58994ff7ea 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -797,7 +797,8 @@ static int i2c_do_add_adapter(struct i2c_driver *driver, /* Let legacy drivers scan this bus for matching devices */ if (driver->attach_adapter) { - dev_warn(&adap->dev, "attach_adapter method is deprecated\n"); + dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n", + driver->driver.name); dev_warn(&adap->dev, "Please use another way to instantiate " "your i2c_client\n"); /* We ignore the return code; if it fails, too bad */ @@ -984,7 +985,8 @@ static int i2c_do_del_adapter(struct i2c_driver *driver, if (!driver->detach_adapter) return 0; - dev_warn(&adapter->dev, "detach_adapter method is deprecated\n"); + dev_warn(&adapter->dev, "%s: detach_adapter method is deprecated\n", + driver->driver.name); res = driver->detach_adapter(adapter); if (res) dev_err(&adapter->dev, "detach_adapter failed (%d) " -- cgit v1.2.2 From d3b3e15da14ded61c9654db05863b04a2435f4cc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 17 Apr 2011 10:20:19 +0200 Subject: i2c-algo-bit: Call pre/post_xfer for bit_test Apparently some distros set i2c-algo-bit.bit_test to 1 by default. In some cases this causes i2c_bit_add_bus to fail and prevents the i2c bus from being added. In the radeon case, we fail to add the ddc i2c buses which prevents the driver from being able to detect attached monitors. The i2c bus works fine even if bit_test fails. This is likely due to gpio switching that is required and handled in the pre/post_xfer hooks, so call the pre/post_xfer hooks in the bit test as well. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=36221 Signed-off-by: Alex Deucher Signed-off-by: Jean Delvare Cc: stable@kernel.org [.38 down to .34] --- drivers/i2c/algos/i2c-algo-bit.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 38319a69bd0a..d6d58684712b 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -232,9 +232,17 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) * Sanity check for the adapter hardware - check the reaction of * the bus lines only if it seems to be idle. */ -static int test_bus(struct i2c_algo_bit_data *adap, char *name) +static int test_bus(struct i2c_adapter *i2c_adap) { - int scl, sda; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + const char *name = i2c_adap->name; + int scl, sda, ret; + + if (adap->pre_xfer) { + ret = adap->pre_xfer(i2c_adap); + if (ret < 0) + return -ENODEV; + } if (adap->getscl == NULL) pr_info("%s: Testing SDA only, SCL is not readable\n", name); @@ -297,11 +305,19 @@ static int test_bus(struct i2c_algo_bit_data *adap, char *name) "while pulling SCL high!\n", name); goto bailout; } + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + pr_info("%s: Test OK\n", name); return 0; bailout: sdahi(adap); sclhi(adap); + + if (adap->post_xfer) + adap->post_xfer(i2c_adap); + return -ENODEV; } @@ -607,7 +623,7 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, int ret; if (bit_test) { - ret = test_bus(bit_adap, adap->name); + ret = test_bus(adap); if (ret < 0) return -ENODEV; } -- cgit v1.2.2 From f792e4f6ac12d45b0eca12f505295c48182a8fd2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 18 Feb 2011 09:41:50 -0300 Subject: [media] omap3isp: resizer: Use 4-tap mode equations when the ratio is <= 512 As the number of phases/taps, used to select the correct equations to compute the ratio, depends on the ratio, start with the 7-tap mode equations to compute an approximation of the ratio, and switch to the 4-tap mode equations if the approximation is lower than or equal to 512. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispresizer.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 829d7bfd422d..40b2db873a13 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -724,9 +724,20 @@ static void resizer_print_status(struct isp_res_device *res) * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) * * The ratios are integer values, and must be rounded down to ensure that the - * cropped input size is not bigger than the uncropped input size. As the ratio - * in 7-tap mode is always smaller than the ratio in 4-tap mode, we can use the - * 7-tap mode equations to compute a ratio approximation. + * cropped input size is not bigger than the uncropped input size. + * + * As the number of phases/taps, used to select the correct equations to compute + * the ratio, depends on the ratio, we start with the 4-tap mode equations to + * compute an approximation of the ratio, and switch to the 7-tap mode equations + * if the approximation is higher than the ratio threshold. + * + * As the 7-tap mode equations will return a ratio smaller than or equal to the + * 4-tap mode equations, the resulting ratio could become lower than or equal to + * the ratio threshold. This 'equations loop' isn't an issue as long as the + * correct equations are used to compute the final input size. Starting with the + * 4-tap mode equations ensure that, in case of values resulting in a 'ratio + * loop', the smallest of the ratio values will be used, never exceeding the + * requested input size. * * We first clamp the output size according to the hardware capabilitie to avoid * auto-cropping the input more than required to satisfy the TRM equations. The @@ -788,8 +799,11 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); output->height = clamp(output->height, min_height, max_height); - ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + ratio->vert = ((input->height - 4) * 256 - 16 - 32 * spv) / (output->height - 1); + if (ratio->vert > MID_RESIZE_VALUE) + ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + / (output->height - 1); ratio->vert = clamp_t(unsigned int, ratio->vert, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); @@ -856,8 +870,11 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_width & ~(width_alignment - 1)); output->width = ALIGN(output->width, width_alignment); - ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + ratio->horz = ((input->width - 7) * 256 - 16 - 32 * sph) / (output->width - 1); + if (ratio->horz > MID_RESIZE_VALUE) + ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + / (output->width - 1); ratio->horz = clamp_t(unsigned int, ratio->horz, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); -- cgit v1.2.2 From 8dc1e75e9dc2fa3f5fa2e98be670118366beac92 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 18 Feb 2011 09:41:51 -0300 Subject: [media] omap3isp: resizer: Improved resizer rsz factor formula Round properly the rsz factor so that we get highest rsz so that the input width (or height) is highest possible smaller or equal to what the user asks. Signed-off-by: Sakari Ailus Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispresizer.c | 40 +++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c index 40b2db873a13..70897ce5dced 100644 --- a/drivers/media/video/omap3isp/ispresizer.c +++ b/drivers/media/video/omap3isp/ispresizer.c @@ -714,16 +714,36 @@ static void resizer_print_status(struct isp_res_device *res) * iw and ih are the input width and height after cropping. Those equations need * to be satisfied exactly for the resizer to work correctly. * - * Reverting the equations, we can compute the resizing ratios with + * The equations can't be easily reverted, as the >> 8 operation is not linear. + * In addition, not all input sizes can be achieved for a given output size. To + * get the highest input size lower than or equal to the requested input size, + * we need to compute the highest resizing ratio that satisfies the following + * inequality (taking the 4-tap mode width equation as an example) + * + * iw >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 - 7 + * + * (where iw is the requested input width) which can be rewritten as + * + * iw - 7 >= (32 * sph + (ow - 1) * hrsz + 16) >> 8 + * (iw - 7) << 8 >= 32 * sph + (ow - 1) * hrsz + 16 - b + * ((iw - 7) << 8) + b >= 32 * sph + (ow - 1) * hrsz + 16 + * + * where b is the value of the 8 least significant bits of the right hand side + * expression of the last inequality. The highest resizing ratio value will be + * achieved when b is equal to its maximum value of 255. That resizing ratio + * value will still satisfy the original inequality, as b will disappear when + * the expression will be shifted right by 8. + * + * The reverted the equations thus become * * - 8-phase, 4-tap mode - * hrsz = ((iw - 7) * 256 - 16 - 32 * sph) / (ow - 1) - * vrsz = ((ih - 4) * 256 - 16 - 32 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1) + * vrsz = ((ih - 4) * 256 + 255 - 16 - 32 * spv) / (oh - 1) * - 4-phase, 7-tap mode - * hrsz = ((iw - 7) * 256 - 32 - 64 * sph) / (ow - 1) - * vrsz = ((ih - 7) * 256 - 32 - 64 * spv) / (oh - 1) + * hrsz = ((iw - 7) * 256 + 255 - 32 - 64 * sph) / (ow - 1) + * vrsz = ((ih - 7) * 256 + 255 - 32 - 64 * spv) / (oh - 1) * - * The ratios are integer values, and must be rounded down to ensure that the + * The ratios are integer values, and are rounded down to ensure that the * cropped input size is not bigger than the uncropped input size. * * As the number of phases/taps, used to select the correct equations to compute @@ -799,10 +819,10 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_height = min_t(unsigned int, max_height, MAX_OUT_HEIGHT); output->height = clamp(output->height, min_height, max_height); - ratio->vert = ((input->height - 4) * 256 - 16 - 32 * spv) + ratio->vert = ((input->height - 4) * 256 + 255 - 16 - 32 * spv) / (output->height - 1); if (ratio->vert > MID_RESIZE_VALUE) - ratio->vert = ((input->height - 7) * 256 - 32 - 64 * spv) + ratio->vert = ((input->height - 7) * 256 + 255 - 32 - 64 * spv) / (output->height - 1); ratio->vert = clamp_t(unsigned int, ratio->vert, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); @@ -870,10 +890,10 @@ static void resizer_calc_ratios(struct isp_res_device *res, max_width & ~(width_alignment - 1)); output->width = ALIGN(output->width, width_alignment); - ratio->horz = ((input->width - 7) * 256 - 16 - 32 * sph) + ratio->horz = ((input->width - 7) * 256 + 255 - 16 - 32 * sph) / (output->width - 1); if (ratio->horz > MID_RESIZE_VALUE) - ratio->horz = ((input->width - 7) * 256 - 32 - 64 * sph) + ratio->horz = ((input->width - 7) * 256 + 255 - 32 - 64 * sph) / (output->width - 1); ratio->horz = clamp_t(unsigned int, ratio->horz, MIN_RESIZE_VALUE, MAX_RESIZE_VALUE); -- cgit v1.2.2 From 2d4e9d1db22117ebcd4f3353cb45292a8704d511 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Mon, 28 Feb 2011 08:29:03 -0300 Subject: [media] omap3isp: Fix trivial typos It doesn't get more trivial than these. Signed-off-by: Michael Jones Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 4 ++-- drivers/media/video/omap3isp/ispccdc.c | 4 ++-- drivers/media/video/omap3isp/isppreview.c | 2 +- drivers/media/video/omap3isp/ispqueue.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 1a9963bd6d40..7d68b109d32f 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -715,7 +715,7 @@ static int isp_pipeline_link_notify(struct media_pad *source, * Walk the entities chain starting at the pipeline output video node and start * all modules in the chain in the given mode. * - * Return 0 if successfull, or the return value of the failed video::s_stream + * Return 0 if successful, or the return value of the failed video::s_stream * operation otherwise. */ static int isp_pipeline_enable(struct isp_pipeline *pipe, @@ -883,7 +883,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) * Set the pipeline to the given stream state. Pipelines can be started in * single-shot or continuous mode. * - * Return 0 if successfull, or the return value of the failed video::s_stream + * Return 0 if successful, or the return value of the failed video::s_stream * operation otherwise. */ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 5ff9d14ce710..fd811eab26f8 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1338,7 +1338,7 @@ static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc, * @ccdc: Pointer to ISP CCDC device. * @event: Pointing which event trigger handler * - * Return 1 when the event and stopping request combination is satisfyied, + * Return 1 when the event and stopping request combination is satisfied, * zero otherwise. */ static int __ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event) @@ -1618,7 +1618,7 @@ static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer) ccdc_set_outaddr(ccdc, buffer->isp_addr); - /* We now have a buffer queued on the output, restart the pipeline in + /* We now have a buffer queued on the output, restart the pipeline * on the next CCDC interrupt if running in continuous mode (or when * starting the stream). */ diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c index baf9374201dc..6af0f231702d 100644 --- a/drivers/media/video/omap3isp/isppreview.c +++ b/drivers/media/video/omap3isp/isppreview.c @@ -755,7 +755,7 @@ static struct preview_update update_attrs[] = { * @configs - pointer to update config structure. * @config - return pointer to appropriate structure field. * @bit - for which feature to return pointers. - * Return size of coresponding prev_params member + * Return size of corresponding prev_params member */ static u32 __preview_get_ptrs(struct prev_params *params, void **param, diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index 8fddc5806b0d..c91e56a5791e 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -408,8 +408,8 @@ done: * isp_video_buffer_prepare_vm_flags - Get VMA flags for a userspace address * * This function locates the VMAs for the buffer's userspace address and checks - * that their flags match. The onlflag that we need to care for at the moment is - * VM_PFNMAP. + * that their flags match. The only flag that we need to care for at the moment + * is VM_PFNMAP. * * The buffer vm_flags field is set to the first VMA flags. * -- cgit v1.2.2 From 7a6f0b22706e2314dbba91f53d20502050aec1d2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 11 Mar 2011 11:34:35 -0300 Subject: [media] media: Properly handle link flags in link setup, link notify callback The link flags were not properly handled in __media_entity_setup_link which could lead to link_notify callback to be called when the flags are not modified. Fix this. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-entity.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 23640ed44d85..056138f63c7d 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -378,7 +378,6 @@ EXPORT_SYMBOL_GPL(media_entity_create_link); static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) { - const u32 mask = MEDIA_LNK_FL_ENABLED; int ret; /* Notify both entities. */ @@ -395,7 +394,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) return ret; } - link->flags = (link->flags & ~mask) | (flags & mask); + link->flags = flags; link->reverse->flags = link->flags; return 0; @@ -417,6 +416,7 @@ static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) */ int __media_entity_setup_link(struct media_link *link, u32 flags) { + const u32 mask = MEDIA_LNK_FL_ENABLED; struct media_device *mdev; struct media_entity *source, *sink; int ret = -EBUSY; @@ -424,6 +424,10 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) if (link == NULL) return -EINVAL; + /* The non-modifiable link flags must not be modified. */ + if ((link->flags & ~mask) != (flags & ~mask)) + return -EINVAL; + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) return link->flags == flags ? 0 : -EINVAL; -- cgit v1.2.2 From b5feda91c1c3510f54720dd8f086653af230a0e1 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Tue, 1 Mar 2011 12:17:40 -0300 Subject: [media] omap3isp: stat: update struct ispstat_generic_config's comments struct ispstat_generic_config's comments refers to isph3a_aewb_config, isph3a_af_config and isphist_config. But those structs have had their names prefixed with 'omap3'. So, let's update the comments. Signed-off-by: David Cohen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispstat.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispstat.h b/drivers/media/video/omap3isp/ispstat.h index 820950c9ef46..d86da94fa50d 100644 --- a/drivers/media/video/omap3isp/ispstat.h +++ b/drivers/media/video/omap3isp/ispstat.h @@ -131,9 +131,9 @@ struct ispstat { struct ispstat_generic_config { /* * Fields must be in the same order as in: - * - isph3a_aewb_config - * - isph3a_af_config - * - isphist_config + * - omap3isp_h3a_aewb_config + * - omap3isp_h3a_af_config + * - omap3isp_hist_config */ u32 buf_size; u16 config_counter; -- cgit v1.2.2 From 994d5375a246c6585d2a6751d568cc86e89aef34 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 1 Mar 2011 13:43:07 -0300 Subject: [media] omap3isp: isp: Reset the ISP when the pipeline can't be stopped When a failure to stop a module in the pipeline is detected, the only way to recover is to reset the ISP. However, as other users can be using a different pipeline with other modules, the ISP can't be reset synchronously with the error detection. Mark the ISP as needing a reset when a failure to stop a pipeline is detected, and reset the ISP when the last user releases the last reference to the ISP. Modify the omap3isp_pipeline_set_stream() function to record the new ISP pipeline state only when no error occurs, except when stopping the pipeline in which case the pipeline is still marked as stopped. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 14 ++++++++++++-- drivers/media/video/omap3isp/isp.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 7d68b109d32f..f380f09b119c 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -872,6 +872,9 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) } } + if (failure < 0) + isp->needs_reset = true; + return failure; } @@ -884,7 +887,8 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe) * single-shot or continuous mode. * * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. + * operation otherwise. The pipeline state is not updated when the operation + * fails, except when stopping the pipeline. */ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state) @@ -895,7 +899,9 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, ret = isp_pipeline_disable(pipe); else ret = isp_pipeline_enable(pipe, state); - pipe->stream_state = state; + + if (ret == 0 || state == ISP_PIPELINE_STREAM_STOPPED) + pipe->stream_state = state; return ret; } @@ -1481,6 +1487,10 @@ void omap3isp_put(struct isp_device *isp) if (--isp->ref_count == 0) { isp_disable_interrupts(isp); isp_save_ctx(isp); + if (isp->needs_reset) { + isp_reset(isp); + isp->needs_reset = false; + } isp_disable_clocks(isp); } mutex_unlock(&isp->isp_mutex); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index cf5214e95a92..5f87645565b8 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -262,6 +262,7 @@ struct isp_device { /* ISP Obj */ spinlock_t stat_lock; /* common lock for statistic drivers */ struct mutex isp_mutex; /* For handling ref_count field */ + bool needs_reset; int has_context; int ref_count; unsigned int autoidle; -- cgit v1.2.2 From 7c2c8f42a389d3b8acdcee19c4ecc4e9c1354d78 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Mon, 21 Mar 2011 12:22:44 -0300 Subject: [media] omap3isp: Use isp xclk defines Use isp defines for isp xclk selection in isp_set_xclk(). Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 11 ++++++----- drivers/media/video/omap3isp/isp.h | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index f380f09b119c..e4fe836ee6d2 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -215,20 +215,21 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } switch (xclksel) { - case 0: + case ISP_XCLK_A: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVA_MASK, divisor << ISPTCTRL_CTRL_DIVA_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclka set to %d Hz\n", currentxclk); break; - case 1: + case ISP_XCLK_B: isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL, ISPTCTRL_CTRL_DIVB_MASK, divisor << ISPTCTRL_CTRL_DIVB_SHIFT); dev_dbg(isp->dev, "isp_set_xclk(): cam_xclkb set to %d Hz\n", currentxclk); break; + case ISP_XCLK_NONE: default: omap3isp_put(isp); dev_dbg(isp->dev, "ISP_ERR: isp_set_xclk(): Invalid requested " @@ -237,13 +238,13 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel) } /* Do we go from stable whatever to clock? */ - if (divisor >= 2 && isp->xclk_divisor[xclksel] < 2) + if (divisor >= 2 && isp->xclk_divisor[xclksel - 1] < 2) omap3isp_get(isp); /* Stopping the clock. */ - else if (divisor < 2 && isp->xclk_divisor[xclksel] >= 2) + else if (divisor < 2 && isp->xclk_divisor[xclksel - 1] >= 2) omap3isp_put(isp); - isp->xclk_divisor[xclksel] = divisor; + isp->xclk_divisor[xclksel - 1] = divisor; omap3isp_put(isp); diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index 5f87645565b8..00075c621e6b 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -314,9 +314,9 @@ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, const struct isp_parallel_platform_data *pdata); -#define ISP_XCLK_NONE -1 -#define ISP_XCLK_A 0 -#define ISP_XCLK_B 1 +#define ISP_XCLK_NONE 0 +#define ISP_XCLK_A 1 +#define ISP_XCLK_B 2 struct isp_device *omap3isp_get(struct isp_device *isp); void omap3isp_put(struct isp_device *isp); -- cgit v1.2.2 From 5a3ddcde35ecadd92d3390552d153f906b120175 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 17 Apr 2011 08:07:57 -0300 Subject: cx23885: Fix stv0367 Kconfig dependency Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 3b6e7f28568e..caab1bfb79e2 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -22,6 +22,7 @@ config VIDEO_CX23885 select DVB_CX24116 if !DVB_FE_CUSTOMISE select DVB_STV0900 if !DVB_FE_CUSTOMISE select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STV0367 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE -- cgit v1.2.2 From 70dda99c41fc8a153e09bdba9adb7805ba2a4bb3 Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Sun, 17 Apr 2011 17:50:01 -0700 Subject: bnx2x: Fix port identification problem This patch fixes port identification on optic devices when there's no link on the port. Signed-off-by: Yaniv Rosner Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_ethtool.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index f5050155c6b5..89cb977898cb 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -2114,19 +2114,18 @@ static int bnx2x_phys_id(struct net_device *dev, u32 data) for (i = 0; i < (data * 2); i++) { if ((i % 2) == 0) bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OPER, SPEED_1000); + LED_MODE_ON, SPEED_1000); else bnx2x_set_led(&bp->link_params, &bp->link_vars, - LED_MODE_OFF, 0); + LED_MODE_FRONT_PANEL_OFF, 0); msleep_interruptible(500); if (signal_pending(current)) break; } - if (bp->link_vars.link_up) - bnx2x_set_led(&bp->link_params, &bp->link_vars, LED_MODE_OPER, - bp->link_vars.line_speed); + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OPER, bp->link_vars.line_speed); return 0; } -- cgit v1.2.2 From 0553c891fabd287726b41076cfd03fe7e5ab596f Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Thu, 14 Apr 2011 06:07:04 +0000 Subject: ip6_pol_route panic: Do not allow VLAN on loopback Several tests in the ipv6 routing code check IFF_LOOPBACK, and allowing stacking such as VLAN'ing on top of loopback results in a netdevice which reports IFF_LOOPBACK but really isn't the loopback device. Instead of spamming the ipv6 routing code with even more special tests, simply disallow VLAN over loopback. The result of this patch is: # modprobe 8021q # vconfig add lo 43 ERROR: trying to add VLAN #43 to IF -:lo:- error: Operation not supported Signed-off-by: Krishna Kumar Signed-off-by: David S. Miller --- drivers/net/loopback.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index ea0dc451da9c..d70fb76edb77 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -173,7 +173,8 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX - | NETIF_F_NETNS_LOCAL; + | NETIF_F_NETNS_LOCAL + | NETIF_F_VLAN_CHALLENGED; dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; dev->netdev_ops = &loopback_ops; -- cgit v1.2.2 From e1dfa0a29737142c32f00a3bac0f609dc85b4a82 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:41 +1000 Subject: md: use new plugging interface for RAID IO. md/raid submits a lot of IO from the various raid threads. So adding start/finish plug calls to those so that some plugging happens. Signed-off-by: NeilBrown --- drivers/md/raid1.c | 5 ++++- drivers/md/raid10.c | 3 +++ drivers/md/raid5.c | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index c2a21ae56d97..5449cd5e3141 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1516,9 +1516,11 @@ static void raid1d(mddev_t *mddev) conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; mdk_rdev_t *rdev; + struct blk_plug plug; md_check_recovery(mddev); - + + blk_start_plug(&plug); for (;;) { char b[BDEVNAME_SIZE]; @@ -1593,6 +1595,7 @@ static void raid1d(mddev_t *mddev) } cond_resched(); } + blk_finish_plug(&plug); } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 2da83d566592..c8e5dac5d695 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1640,9 +1640,11 @@ static void raid10d(mddev_t *mddev) conf_t *conf = mddev->private; struct list_head *head = &conf->retry_list; mdk_rdev_t *rdev; + struct blk_plug plug; md_check_recovery(mddev); + blk_start_plug(&plug); for (;;) { char b[BDEVNAME_SIZE]; @@ -1716,6 +1718,7 @@ static void raid10d(mddev_t *mddev) } cond_resched(); } + blk_finish_plug(&plug); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e867ee42b152..ce6960b1c682 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4478,11 +4478,13 @@ static void raid5d(mddev_t *mddev) struct stripe_head *sh; raid5_conf_t *conf = mddev->private; int handled; + struct blk_plug plug; pr_debug("+++ raid5d active\n"); md_check_recovery(mddev); + blk_start_plug(&plug); handled = 0; spin_lock_irq(&conf->device_lock); while (1) { @@ -4525,6 +4527,7 @@ static void raid5d(mddev_t *mddev) spin_unlock_irq(&conf->device_lock); async_tx_issue_pending_all(); + blk_finish_plug(&plug); pr_debug("--- raid5d inactive\n"); } -- cgit v1.2.2 From af1db72d8b340f97ad12b60175afdef43e6f0e60 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:41 +1000 Subject: md/dm - remove remains of plug_fn callback. Now that unplugging is done differently, the unplug_fn callback is never called, so it can be completely discarded. Signed-off-by: NeilBrown --- drivers/md/dm-raid.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 5ef136cdba91..e5d8904fc8f6 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -390,13 +390,6 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits) return md_raid5_congested(&rs->md, bits); } -static void raid_unplug(struct dm_target_callbacks *cb) -{ - struct raid_set *rs = container_of(cb, struct raid_set, callbacks); - - md_raid5_kick_device(rs->md.private); -} - /* * Construct a RAID4/5/6 mapping: * Args: @@ -487,7 +480,6 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv) } rs->callbacks.congested_fn = raid_is_congested; - rs->callbacks.unplug_fn = raid_unplug; dm_table_add_target_callbacks(ti->table, &rs->callbacks); return 0; -- cgit v1.2.2 From 482c083492ddaa32ef5864bae3d143dc8bcdf7d1 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:42 +1000 Subject: md - remove old plugging code. md has some plugging infrastructure for RAID5 to use because the normal plugging infrastructure required a 'request_queue', and when called from dm, RAID5 doesn't have one of those available. This relied on the ->unplug_fn callback which doesn't exist any more. So remove all of that code, both in md and raid5. Subsequent patches with restore the plugging functionality. Signed-off-by: NeilBrown --- drivers/md/md.c | 51 --------------------------------------------------- drivers/md/md.h | 22 ---------------------- drivers/md/raid5.c | 37 ++++++++----------------------------- drivers/md/raid5.h | 2 -- 4 files changed, 8 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index b12b3776c0c0..fb11170c717e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -445,50 +445,6 @@ void md_flush_request(mddev_t *mddev, struct bio *bio) } EXPORT_SYMBOL(md_flush_request); -/* Support for plugging. - * This mirrors the plugging support in request_queue, but does not - * require having a whole queue - */ -static void plugger_work(struct work_struct *work) -{ - struct plug_handle *plug = - container_of(work, struct plug_handle, unplug_work); - plug->unplug_fn(plug); -} -static void plugger_timeout(unsigned long data) -{ - struct plug_handle *plug = (void *)data; - kblockd_schedule_work(NULL, &plug->unplug_work); -} -void plugger_init(struct plug_handle *plug, - void (*unplug_fn)(struct plug_handle *)) -{ - plug->unplug_flag = 0; - plug->unplug_fn = unplug_fn; - init_timer(&plug->unplug_timer); - plug->unplug_timer.function = plugger_timeout; - plug->unplug_timer.data = (unsigned long)plug; - INIT_WORK(&plug->unplug_work, plugger_work); -} -EXPORT_SYMBOL_GPL(plugger_init); - -void plugger_set_plug(struct plug_handle *plug) -{ - if (!test_and_set_bit(PLUGGED_FLAG, &plug->unplug_flag)) - mod_timer(&plug->unplug_timer, jiffies + msecs_to_jiffies(3)+1); -} -EXPORT_SYMBOL_GPL(plugger_set_plug); - -int plugger_remove_plug(struct plug_handle *plug) -{ - if (test_and_clear_bit(PLUGGED_FLAG, &plug->unplug_flag)) { - del_timer(&plug->unplug_timer); - return 1; - } else - return 0; -} -EXPORT_SYMBOL_GPL(plugger_remove_plug); - static inline mddev_t *mddev_get(mddev_t *mddev) { @@ -4723,7 +4679,6 @@ static void md_clean(mddev_t *mddev) mddev->bitmap_info.chunksize = 0; mddev->bitmap_info.daemon_sleep = 0; mddev->bitmap_info.max_write_behind = 0; - mddev->plug = NULL; } static void __md_stop_writes(mddev_t *mddev) @@ -6688,12 +6643,6 @@ int md_allow_write(mddev_t *mddev) } EXPORT_SYMBOL_GPL(md_allow_write); -void md_unplug(mddev_t *mddev) -{ - if (mddev->plug) - mddev->plug->unplug_fn(mddev->plug); -} - #define SYNC_MARKS 10 #define SYNC_MARK_STEP (3*HZ) void md_do_sync(mddev_t *mddev) diff --git a/drivers/md/md.h b/drivers/md/md.h index 52b407369e13..fad90228672f 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -29,26 +29,6 @@ typedef struct mddev_s mddev_t; typedef struct mdk_rdev_s mdk_rdev_t; -/* generic plugging support - like that provided with request_queue, - * but does not require a request_queue - */ -struct plug_handle { - void (*unplug_fn)(struct plug_handle *); - struct timer_list unplug_timer; - struct work_struct unplug_work; - unsigned long unplug_flag; -}; -#define PLUGGED_FLAG 1 -void plugger_init(struct plug_handle *plug, - void (*unplug_fn)(struct plug_handle *)); -void plugger_set_plug(struct plug_handle *plug); -int plugger_remove_plug(struct plug_handle *plug); -static inline void plugger_flush(struct plug_handle *plug) -{ - del_timer_sync(&plug->unplug_timer); - cancel_work_sync(&plug->unplug_work); -} - /* * MD's 'extended' device */ @@ -336,7 +316,6 @@ struct mddev_s struct list_head all_mddevs; struct attribute_group *to_remove; - struct plug_handle *plug; /* if used by personality */ struct bio_set *bio_set; @@ -516,7 +495,6 @@ extern int md_integrity_register(mddev_t *mddev); extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); extern void restore_bitmap_write_access(struct file *file); -extern void md_unplug(mddev_t *mddev); extern void mddev_init(mddev_t *mddev); extern int md_run(mddev_t *mddev); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index ce6960b1c682..a1755a6a3e5f 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -199,14 +199,12 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh) BUG_ON(!list_empty(&sh->lru)); BUG_ON(atomic_read(&conf->active_stripes)==0); if (test_bit(STRIPE_HANDLE, &sh->state)) { - if (test_bit(STRIPE_DELAYED, &sh->state)) { + if (test_bit(STRIPE_DELAYED, &sh->state)) list_add_tail(&sh->lru, &conf->delayed_list); - plugger_set_plug(&conf->plug); - } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && - sh->bm_seq - conf->seq_write > 0) { + else if (test_bit(STRIPE_BIT_DELAY, &sh->state) && + sh->bm_seq - conf->seq_write > 0) list_add_tail(&sh->lru, &conf->bitmap_list); - plugger_set_plug(&conf->plug); - } else { + else { clear_bit(STRIPE_BIT_DELAY, &sh->state); list_add_tail(&sh->lru, &conf->handle_list); } @@ -461,7 +459,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector, < (conf->max_nr_stripes *3/4) || !conf->inactive_blocked), conf->device_lock, - md_raid5_kick_device(conf)); + md_wakeup_thread(conf->mddev->thread)); conf->inactive_blocked = 0; } else init_stripe(sh, sector, previous); @@ -1470,7 +1468,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize) wait_event_lock_irq(conf->wait_for_stripe, !list_empty(&conf->inactive_list), conf->device_lock, - blk_flush_plug(current)); + ); osh = get_free_stripe(conf); spin_unlock_irq(&conf->device_lock); atomic_set(&nsh->count, 1); @@ -3623,8 +3621,7 @@ static void raid5_activate_delayed(raid5_conf_t *conf) atomic_inc(&conf->preread_active_stripes); list_add_tail(&sh->lru, &conf->hold_list); } - } else - plugger_set_plug(&conf->plug); + } } static void activate_bit_delay(raid5_conf_t *conf) @@ -3641,21 +3638,6 @@ static void activate_bit_delay(raid5_conf_t *conf) } } -void md_raid5_kick_device(raid5_conf_t *conf) -{ - blk_flush_plug(current); - raid5_activate_delayed(conf); - md_wakeup_thread(conf->mddev->thread); -} -EXPORT_SYMBOL_GPL(md_raid5_kick_device); - -static void raid5_unplug(struct plug_handle *plug) -{ - raid5_conf_t *conf = container_of(plug, raid5_conf_t, plug); - - md_raid5_kick_device(conf); -} - int md_raid5_congested(mddev_t *mddev, int bits) { raid5_conf_t *conf = mddev->private; @@ -4057,7 +4039,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) * add failed due to overlap. Flush everything * and wait a while */ - md_raid5_kick_device(conf); + md_wakeup_thread(mddev->thread); release_stripe(sh); schedule(); goto retry; @@ -5144,8 +5126,6 @@ static int run(mddev_t *mddev) mdname(mddev)); md_set_array_sectors(mddev, raid5_size(mddev, 0, 0)); - plugger_init(&conf->plug, raid5_unplug); - mddev->plug = &conf->plug; if (mddev->queue) { int chunk_size; /* read-ahead size must cover two whole stripes, which @@ -5195,7 +5175,6 @@ static int stop(mddev_t *mddev) mddev->thread = NULL; if (mddev->queue) mddev->queue->backing_dev_info.congested_fn = NULL; - plugger_flush(&conf->plug); /* the unplug fn references 'conf'*/ free_conf(conf); mddev->private = NULL; mddev->to_remove = &raid5_attrs_group; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 8d563a4f022a..3ca77a2613ba 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -400,8 +400,6 @@ struct raid5_private_data { * Cleared when a sync completes. */ - struct plug_handle plug; - /* per cpu variables */ struct raid5_percpu { struct page *spare_page; /* Used when checking P/Q in raid6 */ -- cgit v1.2.2 From 97658cdd3af7d01461874c93b89afa4a2465e7c6 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:42 +1000 Subject: md: provide generic support for handling unplug callbacks. When an md device adds a request to a queue, it can call mddev_check_plugged. If this succeeds then we know that the md thread will be woken up shortly, and ->plug_cnt will be non-zero until then, so some processing can be delayed. If it fails, then no unplug callback is expected and the make_request function needs to do whatever is required to make the request happen. Signed-off-by: NeilBrown --- drivers/md/md.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/md/md.h | 4 ++++ 2 files changed, 60 insertions(+) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index fb11170c717e..6e853c61d87e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -445,6 +445,61 @@ void md_flush_request(mddev_t *mddev, struct bio *bio) } EXPORT_SYMBOL(md_flush_request); +/* Support for plugging. + * This mirrors the plugging support in request_queue, but does not + * require having a whole queue or request structures. + * We allocate an md_plug_cb for each md device and each thread it gets + * plugged on. This links tot the private plug_handle structure in the + * personality data where we keep a count of the number of outstanding + * plugs so other code can see if a plug is active. + */ +struct md_plug_cb { + struct blk_plug_cb cb; + mddev_t *mddev; +}; + +static void plugger_unplug(struct blk_plug_cb *cb) +{ + struct md_plug_cb *mdcb = container_of(cb, struct md_plug_cb, cb); + if (atomic_dec_and_test(&mdcb->mddev->plug_cnt)) + md_wakeup_thread(mdcb->mddev->thread); + kfree(mdcb); +} + +/* Check that an unplug wakeup will come shortly. + * If not, wakeup the md thread immediately + */ +int mddev_check_plugged(mddev_t *mddev) +{ + struct blk_plug *plug = current->plug; + struct md_plug_cb *mdcb; + + if (!plug) + return 0; + + list_for_each_entry(mdcb, &plug->cb_list, cb.list) { + if (mdcb->cb.callback == plugger_unplug && + mdcb->mddev == mddev) { + /* Already on the list, move to top */ + if (mdcb != list_first_entry(&plug->cb_list, + struct md_plug_cb, + cb.list)) + list_move(&mdcb->cb.list, &plug->cb_list); + return 1; + } + } + /* Not currently on the callback list */ + mdcb = kmalloc(sizeof(*mdcb), GFP_ATOMIC); + if (!mdcb) + return 0; + + mdcb->mddev = mddev; + mdcb->cb.callback = plugger_unplug; + atomic_inc(&mddev->plug_cnt); + list_add(&mdcb->cb.list, &plug->cb_list); + return 1; +} +EXPORT_SYMBOL_GPL(mddev_check_plugged); static inline mddev_t *mddev_get(mddev_t *mddev) { @@ -494,6 +549,7 @@ void mddev_init(mddev_t *mddev) atomic_set(&mddev->active, 1); atomic_set(&mddev->openers, 0); atomic_set(&mddev->active_io, 0); + atomic_set(&mddev->plug_cnt, 0); spin_lock_init(&mddev->write_lock); atomic_set(&mddev->flush_pending, 0); init_waitqueue_head(&mddev->sb_wait); diff --git a/drivers/md/md.h b/drivers/md/md.h index fad90228672f..0b1fd3f1d85b 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -179,6 +179,9 @@ struct mddev_s int delta_disks, new_level, new_layout; int new_chunk_sectors; + atomic_t plug_cnt; /* If device is expecting + * more bios soon. + */ struct mdk_thread_s *thread; /* management thread */ struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ sector_t curr_resync; /* last block scheduled */ @@ -508,4 +511,5 @@ extern struct bio *bio_clone_mddev(struct bio *bio, gfp_t gfp_mask, mddev_t *mddev); extern struct bio *bio_alloc_mddev(gfp_t gfp_mask, int nr_iovecs, mddev_t *mddev); +extern int mddev_check_plugged(mddev_t *mddev); #endif /* _MD_MD_H */ -- cgit v1.2.2 From 7c13edc87510f665da3094174e1fd633e06649f4 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:43 +1000 Subject: md: incorporate new plugging into raid5. In raid5 plugging is used for 2 things: 1/ collecting writes that require a bitmap update 2/ collecting writes in the hope that we can create full stripes - or at least more-full. We now release these different sets of stripes when plug_cnt is zero. Also in make_request, we call mddev_check_plug to hopefully increase plug_cnt, and wake up the thread at the end if plugging wasn't achieved for some reason. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a1755a6a3e5f..f301e6ae220c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -27,12 +27,12 @@ * * We group bitmap updates into batches. Each batch has a number. * We may write out several batches at once, but that isn't very important. - * conf->bm_write is the number of the last batch successfully written. - * conf->bm_flush is the number of the last batch that was closed to + * conf->seq_write is the number of the last batch successfully written. + * conf->seq_flush is the number of the last batch that was closed to * new additions. * When we discover that we will need to write to any block in a stripe * (in add_stripe_bio) we update the in-memory bitmap and record in sh->bm_seq - * the number of the batch it will be in. This is bm_flush+1. + * the number of the batch it will be in. This is seq_flush+1. * When we are ready to do a write, if that batch hasn't been written yet, * we plug the array and queue the stripe for later. * When an unplug happens, we increment bm_flush, thus closing the current @@ -459,7 +459,7 @@ get_active_stripe(raid5_conf_t *conf, sector_t sector, < (conf->max_nr_stripes *3/4) || !conf->inactive_blocked), conf->device_lock, - md_wakeup_thread(conf->mddev->thread)); + ); conf->inactive_blocked = 0; } else init_stripe(sh, sector, previous); @@ -3927,6 +3927,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) struct stripe_head *sh; const int rw = bio_data_dir(bi); int remaining; + int plugged; if (unlikely(bi->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bi); @@ -3945,6 +3946,7 @@ static int make_request(mddev_t *mddev, struct bio * bi) bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ + plugged = mddev_check_plugged(mddev); for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) { DEFINE_WAIT(w); int disks, data_disks; @@ -4059,6 +4061,9 @@ static int make_request(mddev_t *mddev, struct bio * bi) } } + if (!plugged) + md_wakeup_thread(mddev->thread); + spin_lock_irq(&conf->device_lock); remaining = raid5_dec_bi_phys_segments(bi); spin_unlock_irq(&conf->device_lock); @@ -4472,14 +4477,18 @@ static void raid5d(mddev_t *mddev) while (1) { struct bio *bio; - if (conf->seq_flush != conf->seq_write) { - int seq = conf->seq_flush; + if (atomic_read(&mddev->plug_cnt) == 0 && + !list_empty(&conf->bitmap_list)) { + /* Now is a good time to flush some bitmap updates */ + conf->seq_flush++; spin_unlock_irq(&conf->device_lock); bitmap_unplug(mddev->bitmap); spin_lock_irq(&conf->device_lock); - conf->seq_write = seq; + conf->seq_write = conf->seq_flush; activate_bit_delay(conf); } + if (atomic_read(&mddev->plug_cnt) == 0) + raid5_activate_delayed(conf); while ((bio = remove_bio_from_retry(conf))) { int ok; -- cgit v1.2.2 From c3b328ac846bcf6b9a62c5563380a81ab723006d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 18 Apr 2011 18:25:43 +1000 Subject: md: fix up raid1/raid10 unplugging. We just need to make sure that an unplug event wakes up the md thread, which is exactly what mddev_check_plugged does. Also remove some plug-related code that is no longer needed. Signed-off-by: NeilBrown --- drivers/md/raid1.c | 24 ++++++++++-------------- drivers/md/raid10.c | 24 ++++++++++-------------- 2 files changed, 20 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 5449cd5e3141..2b7a7ff401dc 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -565,12 +565,6 @@ static void flush_pending_writes(conf_t *conf) spin_unlock_irq(&conf->device_lock); } -static void md_kick_device(mddev_t *mddev) -{ - blk_flush_plug(current); - md_wakeup_thread(mddev->thread); -} - /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -600,7 +594,7 @@ static void raise_barrier(conf_t *conf) /* Wait until no block IO is waiting */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_waiting, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); /* block any new IO from starting */ conf->barrier++; @@ -608,7 +602,7 @@ static void raise_barrier(conf_t *conf) /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); spin_unlock_irq(&conf->resync_lock); } @@ -630,7 +624,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - md_kick_device(conf->mddev)); + ); conf->nr_waiting--; } conf->nr_pending++; @@ -666,8 +660,7 @@ static void freeze_array(conf_t *conf) wait_event_lock_irq(conf->wait_barrier, conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - ({ flush_pending_writes(conf); - md_kick_device(conf->mddev); })); + flush_pending_writes(conf)); spin_unlock_irq(&conf->resync_lock); } static void unfreeze_array(conf_t *conf) @@ -729,6 +722,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA)); mdk_rdev_t *blocked_rdev; + int plugged; /* * Register the new request and wait if the reconstruction @@ -820,6 +814,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ + plugged = mddev_check_plugged(mddev); + disks = conf->raid_disks; retry_write: blocked_rdev = NULL; @@ -925,7 +921,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid1d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync || !bitmap) + if (do_sync || !bitmap || !plugged) md_wakeup_thread(mddev->thread); return 0; @@ -1524,7 +1520,8 @@ static void raid1d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; - flush_pending_writes(conf); + if (atomic_read(&mddev->plug_cnt) == 0) + flush_pending_writes(conf); spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) { @@ -2042,7 +2039,6 @@ static int stop(mddev_t *mddev) md_unregister_thread(mddev->thread); mddev->thread = NULL; - blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); kfree(conf->mirrors); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c8e5dac5d695..8e9462626ec5 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -634,12 +634,6 @@ static void flush_pending_writes(conf_t *conf) spin_unlock_irq(&conf->device_lock); } -static void md_kick_device(mddev_t *mddev) -{ - blk_flush_plug(current); - md_wakeup_thread(mddev->thread); -} - /* Barriers.... * Sometimes we need to suspend IO while we do something else, * either some resync/recovery, or reconfigure the array. @@ -669,15 +663,15 @@ static void raise_barrier(conf_t *conf, int force) /* Wait until no block IO is waiting (unless 'force') */ wait_event_lock_irq(conf->wait_barrier, force || !conf->nr_waiting, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); /* block any new IO from starting */ conf->barrier++; - /* No wait for all pending IO to complete */ + /* Now wait for all pending IO to complete */ wait_event_lock_irq(conf->wait_barrier, !conf->nr_pending && conf->barrier < RESYNC_DEPTH, - conf->resync_lock, md_kick_device(conf->mddev)); + conf->resync_lock, ); spin_unlock_irq(&conf->resync_lock); } @@ -698,7 +692,7 @@ static void wait_barrier(conf_t *conf) conf->nr_waiting++; wait_event_lock_irq(conf->wait_barrier, !conf->barrier, conf->resync_lock, - md_kick_device(conf->mddev)); + ); conf->nr_waiting--; } conf->nr_pending++; @@ -734,8 +728,8 @@ static void freeze_array(conf_t *conf) wait_event_lock_irq(conf->wait_barrier, conf->nr_pending == conf->nr_queued+1, conf->resync_lock, - ({ flush_pending_writes(conf); - md_kick_device(conf->mddev); })); + flush_pending_writes(conf)); + spin_unlock_irq(&conf->resync_lock); } @@ -762,6 +756,7 @@ static int make_request(mddev_t *mddev, struct bio * bio) const unsigned long do_fua = (bio->bi_rw & REQ_FUA); unsigned long flags; mdk_rdev_t *blocked_rdev; + int plugged; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); @@ -870,6 +865,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) * inc refcount on their rdev. Record them by setting * bios[x] to bio */ + plugged = mddev_check_plugged(mddev); + raid10_find_phys(conf, r10_bio); retry_write: blocked_rdev = NULL; @@ -946,9 +943,8 @@ static int make_request(mddev_t *mddev, struct bio * bio) /* In case raid10d snuck in to freeze_array */ wake_up(&conf->wait_barrier); - if (do_sync || !mddev->bitmap) + if (do_sync || !mddev->bitmap || !plugged) md_wakeup_thread(mddev->thread); - return 0; } -- cgit v1.2.2 From 2dd93c4f47d506c586b827d75646a4257aafa43e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 17 Apr 2011 10:02:58 +0800 Subject: RTC: rtc-omap: Fix a leak of the IRQ during init failure In omap_rtc_probe error path, free_irq() was using NULL rather than the driver data as the data pointer so free_irq() wouldn't have matched. Signed-off-by: Axel Lin Cc: "George G. Davis" Cc: Alessandro Zummo Cc: rtc-linux@googlegroups.com Link: http://lkml.kernel.org/r/%3C1303005778.2889.2.camel%40phoenix%3E Signed-off-by: Thomas Gleixner --- drivers/rtc/rtc-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index de0dd7b1f146..bcae8dd41496 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -394,7 +394,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev) return 0; fail2: - free_irq(omap_rtc_timer, NULL); + free_irq(omap_rtc_timer, rtc); fail1: rtc_device_unregister(rtc); fail0: -- cgit v1.2.2 From 24ecfbe27f65563909b14492afda2f1c21f7c044 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 18 Apr 2011 11:41:33 +0200 Subject: block: add blk_run_queue_async Instead of overloading __blk_run_queue to force an offload to kblockd add a new blk_run_queue_async helper to do it explicitly. I've kept the blk_queue_stopped check for now, but I suspect it's not needed as the check we do when the workqueue items runs should be enough. Signed-off-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/scsi/scsi_lib.c | 2 +- drivers/scsi/scsi_transport_fc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 6d5c7ff43f5b..ab55c2fa7ce2 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -443,7 +443,7 @@ static void scsi_run_queue(struct request_queue *q) &sdev->request_queue->queue_flags); if (flagset) queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); - __blk_run_queue(sdev->request_queue, false); + __blk_run_queue(sdev->request_queue); if (flagset) queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); spin_unlock(sdev->request_queue->queue_lock); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index fdf3fa639056..28c33506e4ad 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3829,7 +3829,7 @@ fc_bsg_goose_queue(struct fc_rport *rport) !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); if (flagset) queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); - __blk_run_queue(rport->rqst_q, false); + __blk_run_queue(rport->rqst_q); if (flagset) queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); -- cgit v1.2.2 From 7caa2316bf0434f1150f58cb576542987a0466d7 Mon Sep 17 00:00:00 2001 From: Daniel Halperin Date: Wed, 6 Apr 2011 12:47:25 -0700 Subject: iwlwifi: fix frame injection for HT channels For some reason, sending QoS configuration causes transmission to stop after a single frame on HT channels when not associated. Removing the extra QoS configuration has no effect on station mode, and fixes injection mode. Signed-off-by: Daniel Halperin Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index dfdbea6e8f99..fbbde0712fa5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -335,7 +335,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_channel *channel = conf->channel; const struct iwl_channel_info *ch_info; int ret = 0; - bool ht_changed[NUM_IWL_RXON_CTX] = {}; IWL_DEBUG_MAC80211(priv, "changed %#x", changed); @@ -383,10 +382,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) for_each_context(priv, ctx) { /* Configure HT40 channels */ - if (ctx->ht.enabled != conf_is_ht(conf)) { + if (ctx->ht.enabled != conf_is_ht(conf)) ctx->ht.enabled = conf_is_ht(conf); - ht_changed[ctx->ctxid] = true; - } if (ctx->ht.enabled) { if (conf_is_ht40_minus(conf)) { @@ -455,8 +452,6 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (!memcmp(&ctx->staging, &ctx->active, sizeof(ctx->staging))) continue; iwlagn_commit_rxon(priv, ctx); - if (ht_changed[ctx->ctxid]) - iwlagn_update_qos(priv, ctx); } out: mutex_unlock(&priv->mutex); -- cgit v1.2.2 From 80b4895aa4578e9372d76cd4063f82d0c3994d77 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Mon, 18 Apr 2011 10:08:02 -0700 Subject: Input: estimate number of events per packet Calculate a default based on the number of ABS axes, REL axes, and MT slots for the device during input device registration. Signed-off-by: Jeff Brown Reviewed-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/input/input.c b/drivers/input/input.c index d6e8bd8a851c..ebbceedc92f4 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1746,6 +1746,42 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int } EXPORT_SYMBOL(input_set_capability); +static unsigned int input_estimate_events_per_packet(struct input_dev *dev) +{ + int mt_slots; + int i; + unsigned int events; + + if (dev->mtsize) { + mt_slots = dev->mtsize; + } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { + mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - + dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, + clamp(mt_slots, 2, 32); + } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { + mt_slots = 2; + } else { + mt_slots = 0; + } + + events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */ + + for (i = 0; i < ABS_CNT; i++) { + if (test_bit(i, dev->absbit)) { + if (input_is_mt_axis(i)) + events += mt_slots; + else + events++; + } + } + + for (i = 0; i < REL_CNT; i++) + if (test_bit(i, dev->relbit)) + events++; + + return events; +} + #define INPUT_CLEANSE_BITMASK(dev, type, bits) \ do { \ if (!test_bit(EV_##type, dev->evbit)) \ @@ -1793,6 +1829,10 @@ int input_register_device(struct input_dev *dev) /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); + if (!dev->hint_events_per_packet) + dev->hint_events_per_packet = + input_estimate_events_per_packet(dev); + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. -- cgit v1.2.2 From c36b58e8a9112017c2bcc322cc98e71241814303 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Mon, 18 Apr 2011 10:17:17 -0700 Subject: Input: xen-kbdfront - fix mouse getting stuck after save/restore Mouse gets "stuck" after restore of PV guest but buttons are in working condition. If driver has been configured for ABS coordinates at start it will get XENKBD_TYPE_POS events and then suddenly after restore it'll start getting XENKBD_TYPE_MOTION events, that will be dropped later and they won't get into user-space. Regression was introduced by hunk 5 and 6 of 5ea5254aa0ad269cfbd2875c973ef25ab5b5e9db ("Input: xen-kbdfront - advertise either absolute or relative coordinates"). Driver on restore should ask xen for request-abs-pointer again if it is available. So restore parts that did it before 5ea5254. Acked-by: Olaf Hering Signed-off-by: Igor Mammedov [v1: Expanded the commit description] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Dmitry Torokhov --- drivers/input/misc/xen-kbdfront.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 7077f9bf5ead..62bae99424e6 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -303,7 +303,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int val; + int ret, val; switch (backend_state) { case XenbusStateInitialising: @@ -316,6 +316,17 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, case XenbusStateInitWait: InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + pr_warning("xenkbd: can't request abs-pointer"); + } + xenbus_switch_state(dev, XenbusStateConnected); break; -- cgit v1.2.2 From c21e6beba8835d09bb80e34961430b13e60381c5 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Apr 2011 13:32:46 +0200 Subject: block: get rid of QUEUE_FLAG_REENTER We are currently using this flag to check whether it's safe to call into ->request_fn(). If it is set, we punt to kblockd. But we get a lot of false positives and excessive punts to kblockd, which hurts performance. The only real abuser of this infrastructure is SCSI. So export the async queue run and convert SCSI over to use that. There's room for improvement in that SCSI need not always use the async call, but this fixes our performance issue and they can fix that up in due time. Signed-off-by: Jens Axboe --- drivers/scsi/scsi_lib.c | 17 +---------------- drivers/scsi/scsi_transport_fc.c | 19 ++++--------------- 2 files changed, 5 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ab55c2fa7ce2..e9901b8f8443 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -411,8 +411,6 @@ static void scsi_run_queue(struct request_queue *q) list_splice_init(&shost->starved_list, &starved_list); while (!list_empty(&starved_list)) { - int flagset; - /* * As long as shost is accepting commands and we have * starved queues, call blk_run_queue. scsi_request_fn @@ -435,20 +433,7 @@ static void scsi_run_queue(struct request_queue *q) continue; } - spin_unlock(shost->host_lock); - - spin_lock(sdev->request_queue->queue_lock); - flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && - !test_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags); - if (flagset) - queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); - __blk_run_queue(sdev->request_queue); - if (flagset) - queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); - spin_unlock(sdev->request_queue->queue_lock); - - spin_lock(shost->host_lock); + blk_run_queue_async(sdev->request_queue); } /* put any unprocessed entries back */ list_splice(&starved_list, &shost->starved_list); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 28c33506e4ad..815069d13f9b 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3816,28 +3816,17 @@ fail_host_msg: static void fc_bsg_goose_queue(struct fc_rport *rport) { - int flagset; - unsigned long flags; - if (!rport->rqst_q) return; + /* + * This get/put dance makes no sense + */ get_device(&rport->dev); - - spin_lock_irqsave(rport->rqst_q->queue_lock, flags); - flagset = test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags) && - !test_bit(QUEUE_FLAG_REENTER, &rport->rqst_q->queue_flags); - if (flagset) - queue_flag_set(QUEUE_FLAG_REENTER, rport->rqst_q); - __blk_run_queue(rport->rqst_q); - if (flagset) - queue_flag_clear(QUEUE_FLAG_REENTER, rport->rqst_q); - spin_unlock_irqrestore(rport->rqst_q->queue_lock, flags); - + blk_run_queue_async(rport->rqst_q); put_device(&rport->dev); } - /** * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD * @q: rport request queue -- cgit v1.2.2 From 5782f97b55a0cf8ef66dff045f1beafcdaf40dda Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 29 Mar 2011 05:19:08 -0300 Subject: [media] omap3isp: ccdc: support Y10/12, 8-bit bayer fmts Add support for 8-bit bayer and 10- and 12-bit grey formats at the CCDC input. Y12 is truncated to Y10 at the CCDC output. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispccdc.c | 6 ++++++ drivers/media/video/omap3isp/ispvideo.c | 12 ++++++++++++ 2 files changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index fd811eab26f8..68941ed47194 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -43,6 +43,12 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh, static const unsigned int ccdc_fmts[] = { V4L2_MBUS_FMT_Y8_1X8, + V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, + V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index a0bb5db9cb8a..9ade7359ebca 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -48,6 +48,18 @@ static struct isp_format_info formats[] = { { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, + { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10, 10, }, + { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, + V4L2_MBUS_FMT_Y12_1X12, V4L2_PIX_FMT_Y12, 12, }, + { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 8, }, + { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 8, }, + { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 8, }, + { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 8, }, { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, -- cgit v1.2.2 From c09af044db91bf0f8ca5073f5863c7280de39cc1 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 29 Mar 2011 05:19:09 -0300 Subject: [media] omap3isp: lane shifter support To use the lane shifter, set different pixel formats at each end of the link at the CCDC input. Signed-off-by: Michael Jones Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 7 ++- drivers/media/video/omap3isp/isp.h | 5 +- drivers/media/video/omap3isp/ispccdc.c | 27 ++++++-- drivers/media/video/omap3isp/ispvideo.c | 108 ++++++++++++++++++++++++++------ drivers/media/video/omap3isp/ispvideo.h | 3 + 5 files changed, 120 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index e4fe836ee6d2..5d8e1ce64508 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -286,7 +286,8 @@ static void isp_power_settings(struct isp_device *isp, int idle) */ void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata) + const struct isp_parallel_platform_data *pdata, + unsigned int shift) { u32 ispctrl_val; @@ -299,9 +300,9 @@ void omap3isp_configure_bridge(struct isp_device *isp, switch (input) { case CCDC_INPUT_PARALLEL: ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL; - ispctrl_val |= pdata->data_lane_shift << ISPCTRL_SHIFT_SHIFT; ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT; ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT; + shift += pdata->data_lane_shift * 2; break; case CCDC_INPUT_CSI2A: @@ -320,6 +321,8 @@ void omap3isp_configure_bridge(struct isp_device *isp, return; } + ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK; + ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK; ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE; diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h index 00075c621e6b..2620c405f5e4 100644 --- a/drivers/media/video/omap3isp/isp.h +++ b/drivers/media/video/omap3isp/isp.h @@ -132,7 +132,6 @@ struct isp_reg { /** * struct isp_parallel_platform_data - Parallel interface platform data - * @width: Parallel bus width in bits (8, 10, 11 or 12) * @data_lane_shift: Data lane shifter * 0 - CAMEXT[13:0] -> CAM[13:0] * 1 - CAMEXT[13:2] -> CAM[11:0] @@ -146,7 +145,6 @@ struct isp_reg { * ISPCTRL_PAR_BRIDGE_BENDIAN - Big endian */ struct isp_parallel_platform_data { - unsigned int width; unsigned int data_lane_shift:2; unsigned int clk_pol:1; unsigned int bridge:4; @@ -312,7 +310,8 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe, enum isp_pipeline_stream_state state); void omap3isp_configure_bridge(struct isp_device *isp, enum ccdc_input_entity input, - const struct isp_parallel_platform_data *pdata); + const struct isp_parallel_platform_data *pdata, + unsigned int shift); #define ISP_XCLK_NONE 0 #define ISP_XCLK_A 1 diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index 68941ed47194..39d501bda636 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1116,21 +1116,38 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc) struct isp_parallel_platform_data *pdata = NULL; struct v4l2_subdev *sensor; struct v4l2_mbus_framefmt *format; + const struct isp_format_info *fmt_info; + struct v4l2_subdev_format fmt_src; + unsigned int depth_out; + unsigned int depth_in = 0; struct media_pad *pad; unsigned long flags; + unsigned int shift; u32 syn_mode; u32 ccdc_pattern; - if (ccdc->input == CCDC_INPUT_PARALLEL) { - pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); - sensor = media_entity_to_v4l2_subdev(pad->entity); + pad = media_entity_remote_source(&ccdc->pads[CCDC_PAD_SINK]); + sensor = media_entity_to_v4l2_subdev(pad->entity); + if (ccdc->input == CCDC_INPUT_PARALLEL) pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv) ->bus.parallel; + + /* Compute shift value for lane shifter to configure the bridge. */ + fmt_src.pad = pad->index; + fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; + if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) { + fmt_info = omap3isp_video_format_info(fmt_src.format.code); + depth_in = fmt_info->bpp; } - omap3isp_configure_bridge(isp, ccdc->input, pdata); + fmt_info = omap3isp_video_format_info + (isp->isp_ccdc.formats[CCDC_PAD_SINK].code); + depth_out = fmt_info->bpp; + + shift = depth_in - depth_out; + omap3isp_configure_bridge(isp, ccdc->input, pdata, shift); - ccdc->syncif.datsz = pdata ? pdata->width : 10; + ccdc->syncif.datsz = depth_out; ccdc_config_sync_if(ccdc, &ccdc->syncif); /* CCDC_PAD_SINK */ diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index 9ade7359ebca..6e18cee274c7 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -47,41 +47,59 @@ static struct isp_format_info formats[] = { { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, - V4L2_MBUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 8, }, + V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_GREY, 8, }, { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10, 10, }, + V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y10, 10, }, { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10, - V4L2_MBUS_FMT_Y12_1X12, V4L2_PIX_FMT_Y12, 12, }, + V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8, + V4L2_PIX_FMT_Y12, 12, }, { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, - V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 8, }, + V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR8, 8, }, { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, - V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 8, }, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG8, 8, }, { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, - V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 8, }, + V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG8, 8, }, { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, - V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 8, }, + V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB8, 8, }, { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, + V4L2_MBUS_FMT_SGRBG10_1X10, 0, + V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10, 10, }, + V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR10, 10, }, { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10, 10, }, + V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG10, 10, }, { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10, 10, }, + V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG10, 10, }, { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10, 10, }, + V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB10, 10, }, { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10, - V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12, 12, }, + V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_PIX_FMT_SBGGR12, 12, }, { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10, - V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12, 12, }, + V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8, + V4L2_PIX_FMT_SGBRG12, 12, }, { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10, - V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12, 12, }, + V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_PIX_FMT_SGRBG12, 12, }, { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10, - V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12, 12, }, + V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_PIX_FMT_SRGGB12, 12, }, { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16, - V4L2_MBUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 16, }, + V4L2_MBUS_FMT_UYVY8_1X16, 0, + V4L2_PIX_FMT_UYVY, 16, }, { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16, - V4L2_MBUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 16, }, + V4L2_MBUS_FMT_YUYV8_1X16, 0, + V4L2_PIX_FMT_YUYV, 16, }, }; const struct isp_format_info * @@ -97,6 +115,37 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code) return NULL; } +/* + * Decide whether desired output pixel code can be obtained with + * the lane shifter by shifting the input pixel code. + * @in: input pixelcode to shifter + * @out: output pixelcode from shifter + * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0] + * + * return true if the combination is possible + * return false otherwise + */ +static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in, + enum v4l2_mbus_pixelcode out, + unsigned int additional_shift) +{ + const struct isp_format_info *in_info, *out_info; + + if (in == out) + return true; + + in_info = omap3isp_video_format_info(in); + out_info = omap3isp_video_format_info(out); + + if ((in_info->flavor == 0) || (out_info->flavor == 0)) + return false; + + if (in_info->flavor != out_info->flavor) + return false; + + return in_info->bpp - out_info->bpp + additional_shift <= 6; +} + /* * isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format * @video: ISP video instance @@ -247,6 +296,7 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; while (1) { + unsigned int shifter_link; /* Retrieve the sink format */ pad = &subdev->entity.pads[0]; if (!(pad->flags & MEDIA_PAD_FL_SINK)) @@ -275,6 +325,10 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -ENOSPC; } + /* If sink pad is on CCDC, the link has the lane shifter + * in the middle of it. */ + shifter_link = subdev == &isp->isp_ccdc.subdev; + /* Retrieve the source format */ pad = media_entity_remote_source(pad); if (pad == NULL || @@ -290,10 +344,24 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe) return -EPIPE; /* Check if the two ends match */ - if (fmt_source.format.code != fmt_sink.format.code || - fmt_source.format.width != fmt_sink.format.width || + if (fmt_source.format.width != fmt_sink.format.width || fmt_source.format.height != fmt_sink.format.height) return -EPIPE; + + if (shifter_link) { + unsigned int parallel_shift = 0; + if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) { + struct isp_parallel_platform_data *pdata = + &((struct isp_v4l2_subdevs_group *) + subdev->host_priv)->bus.parallel; + parallel_shift = pdata->data_lane_shift * 2; + } + if (!isp_video_is_shiftable(fmt_source.format.code, + fmt_sink.format.code, + parallel_shift)) + return -EPIPE; + } else if (fmt_source.format.code != fmt_sink.format.code) + return -EPIPE; } return 0; diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h index 524a1acd0906..911bea64e78a 100644 --- a/drivers/media/video/omap3isp/ispvideo.h +++ b/drivers/media/video/omap3isp/ispvideo.h @@ -49,6 +49,8 @@ struct v4l2_pix_format; * bits. Identical to @code if the format is 10 bits wide or less. * @uncompressed: V4L2 media bus format code for the corresponding uncompressed * format. Identical to @code if the format is not DPCM compressed. + * @flavor: V4L2 media bus format code for the same pixel layout but + * shifted to be 8 bits per pixel. =0 if format is not shiftable. * @pixelformat: V4L2 pixel format FCC identifier * @bpp: Bits per pixel */ @@ -56,6 +58,7 @@ struct isp_format_info { enum v4l2_mbus_pixelcode code; enum v4l2_mbus_pixelcode truncated; enum v4l2_mbus_pixelcode uncompressed; + enum v4l2_mbus_pixelcode flavor; u32 pixelformat; unsigned int bpp; }; -- cgit v1.2.2 From e2241531a5d015b55cdddd488f6f3477c785f34e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 1 Apr 2011 09:12:54 -0300 Subject: [media] omap3isp: Don't increment node entity use count when poweron fails When open a device node, all entities part of the same pipeline are powered on. If one of the entities fails to be powered on, the open operations fails. In that case the device node entity use count must not be incremented. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/isp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c index 5d8e1ce64508..de2dec506663 100644 --- a/drivers/media/video/omap3isp/isp.c +++ b/drivers/media/video/omap3isp/isp.c @@ -662,6 +662,8 @@ int omap3isp_pipeline_pm_use(struct media_entity *entity, int use) /* Apply power change to connected non-nodes. */ ret = isp_pipeline_pm_power(entity, change); + if (ret < 0) + entity->use_count -= change; mutex_unlock(&entity->parent->graph_mutex); -- cgit v1.2.2 From c4f0b78ad5d0e76caaeb5c2349c2613728c816bc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 8 Apr 2011 09:04:06 -0300 Subject: [media] v4l: Don't register media entities for subdev device nodes Subdevs already have their own entity, don't register as second one when registering the subdev device node. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-dev.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 498e6742579e..6dc7196296b3 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -389,7 +389,8 @@ static int v4l2_open(struct inode *inode, struct file *filp) video_get(vdev); mutex_unlock(&videodev_lock); #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { entity = media_entity_get(&vdev->entity); if (!entity) { ret = -EBUSY; @@ -415,7 +416,8 @@ err: /* decrease the refcount in case of an error */ if (ret) { #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(entity); #endif video_put(vdev); @@ -437,7 +439,8 @@ static int v4l2_release(struct inode *inode, struct file *filp) mutex_unlock(vdev->lock); } #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_entity_put(&vdev->entity); #endif /* decrease the refcount unconditionally since the release() @@ -686,7 +689,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr, #if defined(CONFIG_MEDIA_CONTROLLER) /* Part 5: Register the entity. */ - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) { + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) { vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L; vdev->entity.name = vdev->name; vdev->entity.v4l.major = VIDEO_MAJOR; @@ -733,7 +737,8 @@ void video_unregister_device(struct video_device *vdev) return; #if defined(CONFIG_MEDIA_CONTROLLER) - if (vdev->v4l2_dev && vdev->v4l2_dev->mdev) + if (vdev->v4l2_dev && vdev->v4l2_dev->mdev && + vdev->vfl_type != VFL_TYPE_SUBDEV) media_device_unregister_entity(&vdev->entity); #endif -- cgit v1.2.2 From 2578dfb7f767076baf04eaf5fbf35a75afb9a1a7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 7 Apr 2011 13:30:14 -0300 Subject: [media] omap3isp: queue: Don't corrupt buf->npages when get_user_pages() fails get_user_pages() can return a negative error code when it fails. Set buf->npages to 0 in that case, to prevent isp_video_buffer_cleanup() from releasing invalid pages. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/omap3isp/ispqueue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/omap3isp/ispqueue.c b/drivers/media/video/omap3isp/ispqueue.c index c91e56a5791e..9c317148205f 100644 --- a/drivers/media/video/omap3isp/ispqueue.c +++ b/drivers/media/video/omap3isp/ispqueue.c @@ -339,7 +339,7 @@ static int isp_video_buffer_prepare_user(struct isp_video_buffer *buf) up_read(¤t->mm->mmap_sem); if (ret != buf->npages) { - buf->npages = ret; + buf->npages = ret < 0 ? 0 : ret; isp_video_buffer_cleanup(buf); return -EFAULT; } -- cgit v1.2.2 From f78028b68f01925b826979627a2498111ea11bed Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: fix calculation bug in tda18271_rf_tracking_filters_init Misplaced parenthesis cause a calculation bug in tda18271_rf_tracking_filters_init Thanks to Stefan Sibiga for pointing this out. Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda18271-fe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 9ad4454a148d..42105d1c8613 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -616,15 +616,15 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) map[i].rf1 = rf_freq[RF1] / 1000; break; case RF2: - dividend = (s32)(prog_cal[RF2] - prog_tab[RF2]) - - (s32)(prog_cal[RF1] + prog_tab[RF1]); + dividend = (s32)(prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; map[i].rf_a1 = (dividend / divisor); map[i].rf2 = rf_freq[RF2] / 1000; break; case RF3: - dividend = (s32)(prog_cal[RF3] - prog_tab[RF3]) - - (s32)(prog_cal[RF2] + prog_tab[RF2]); + dividend = (s32)(prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; map[i].rf_a2 = (dividend / divisor); map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]); -- cgit v1.2.2 From 381ad0ea146465406a0740f437e9971ceb6465a9 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: prog_cal and prog_tab variables should be s32, not u8 Fix type of prog_cal and prog_tab variables to avoid any possible calculation errors. Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda18271-fe.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index 42105d1c8613..d884f5eee73c 100644 --- a/drivers/media/common/tuners/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c @@ -579,8 +579,8 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) #define RF3 2 u32 rf_default[3]; u32 rf_freq[3]; - u8 prog_cal[3]; - u8 prog_tab[3]; + s32 prog_cal[3]; + s32 prog_tab[3]; i = tda18271_lookup_rf_band(fe, &freq, NULL); @@ -602,32 +602,33 @@ static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) return bcal; tda18271_calc_rf_cal(fe, &rf_freq[rf]); - prog_tab[rf] = regs[R_EB14]; + prog_tab[rf] = (s32)regs[R_EB14]; if (1 == bcal) - prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); + prog_cal[rf] = + (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); else prog_cal[rf] = prog_tab[rf]; switch (rf) { case RF1: map[i].rf_a1 = 0; - map[i].rf_b1 = (s32)(prog_cal[RF1] - prog_tab[RF1]); + map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); map[i].rf1 = rf_freq[RF1] / 1000; break; case RF2: - dividend = (s32)(prog_cal[RF2] - prog_tab[RF2] - - prog_cal[RF1] + prog_tab[RF1]); + dividend = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]); divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; map[i].rf_a1 = (dividend / divisor); map[i].rf2 = rf_freq[RF2] / 1000; break; case RF3: - dividend = (s32)(prog_cal[RF3] - prog_tab[RF3] - - prog_cal[RF2] + prog_tab[RF2]); + dividend = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]); divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; map[i].rf_a2 = (dividend / divisor); - map[i].rf_b2 = (s32)(prog_cal[RF2] - prog_tab[RF2]); + map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); map[i].rf3 = rf_freq[RF3] / 1000; break; default: -- cgit v1.2.2 From 3f688e8c62fb69ff65bc9325831b5b3d3f5ef8ed Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: fix bad calculation of main post divider byte R_MPD bit 3 does not depend on analog vs. digital. Just use (0x7f & pd) directly from the values in the main pll table. Thanks to Stefan Sibiga for pointing this out. Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda18271-common.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index 5466d47db899..aae40e52af5b 100644 --- a/drivers/media/common/tuners/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c @@ -533,16 +533,7 @@ int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) if (tda_fail(ret)) goto fail; - regs[R_MPD] = (0x77 & pd); - - switch (priv->mode) { - case TDA18271_ANALOG: - regs[R_MPD] &= ~0x08; - break; - case TDA18271_DIGITAL: - regs[R_MPD] |= 0x08; - break; - } + regs[R_MPD] = (0x7f & pd); div = ((d * (freq / 1000)) << 7) / 125; -- cgit v1.2.2 From 786e86ae5efff8552f5ae07977324c226e0fcfe7 Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: update tda18271_rf_band as per NXP's rev.04 datasheet Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda18271-maps.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index e7f84c705da8..2fef12691116 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -229,8 +229,7 @@ static struct tda18271_map tda18271c2_km[] = { static struct tda18271_map tda18271_rf_band[] = { { .rfmax = 47900, .val = 0x00 }, { .rfmax = 61100, .val = 0x01 }, -/* { .rfmax = 152600, .val = 0x02 }, */ - { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 152600, .val = 0x02 }, { .rfmax = 164700, .val = 0x03 }, { .rfmax = 203500, .val = 0x04 }, { .rfmax = 457800, .val = 0x05 }, -- cgit v1.2.2 From 5b9a81d14fcf0bf166f73bc3b31463efbdb2660a Mon Sep 17 00:00:00 2001 From: Michael Krufky Date: Sat, 16 Apr 2011 13:22:10 -0300 Subject: [media] tda18271: update tda18271c2_rf_cal as per NXP's rev.04 datasheet Cc: Stefan Sibiga Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda18271-maps.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tuners/tda18271-maps.c b/drivers/media/common/tuners/tda18271-maps.c index 2fef12691116..3d5b6ab7e332 100644 --- a/drivers/media/common/tuners/tda18271-maps.c +++ b/drivers/media/common/tuners/tda18271-maps.c @@ -447,7 +447,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 150000, .val = 0xb0 }, { .rfmax = 151000, .val = 0xb1 }, { .rfmax = 152000, .val = 0xb7 }, - { .rfmax = 153000, .val = 0xbd }, + { .rfmax = 152600, .val = 0xbd }, { .rfmax = 154000, .val = 0x20 }, { .rfmax = 155000, .val = 0x22 }, { .rfmax = 156000, .val = 0x24 }, @@ -458,7 +458,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 161000, .val = 0x2d }, { .rfmax = 163000, .val = 0x2e }, { .rfmax = 164000, .val = 0x2f }, - { .rfmax = 165000, .val = 0x30 }, + { .rfmax = 164700, .val = 0x30 }, { .rfmax = 166000, .val = 0x11 }, { .rfmax = 167000, .val = 0x12 }, { .rfmax = 168000, .val = 0x13 }, @@ -509,7 +509,8 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 236000, .val = 0x1b }, { .rfmax = 237000, .val = 0x1c }, { .rfmax = 240000, .val = 0x1d }, - { .rfmax = 242000, .val = 0x1f }, + { .rfmax = 242000, .val = 0x1e }, + { .rfmax = 244000, .val = 0x1f }, { .rfmax = 247000, .val = 0x20 }, { .rfmax = 249000, .val = 0x21 }, { .rfmax = 252000, .val = 0x22 }, @@ -623,7 +624,7 @@ static struct tda18271_map tda18271c2_rf_cal[] = { { .rfmax = 453000, .val = 0x93 }, { .rfmax = 454000, .val = 0x94 }, { .rfmax = 456000, .val = 0x96 }, - { .rfmax = 457000, .val = 0x98 }, + { .rfmax = 457800, .val = 0x98 }, { .rfmax = 461000, .val = 0x11 }, { .rfmax = 468000, .val = 0x12 }, { .rfmax = 472000, .val = 0x13 }, -- cgit v1.2.2 From 3b17857dfbcb698c2dd0b4c38775ab04cf643d1a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 14 Mar 2011 17:54:25 -0700 Subject: hwmon: (pmbus) Removed unused variable from struct pmbus_data struct pmbus_data included an unused variable named status_bits. Remove it. Signed-off-by: Guenter Roeck Reviewed-by: Tom Grennan --- drivers/hwmon/pmbus_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c index edfb92e41735..196ffafafd88 100644 --- a/drivers/hwmon/pmbus_core.c +++ b/drivers/hwmon/pmbus_core.c @@ -139,7 +139,6 @@ struct pmbus_data { * A single status register covers multiple attributes, * so we keep them all together. */ - u8 status_bits; u8 status[PB_NUM_STATUS_REG]; u8 currpage; -- cgit v1.2.2 From 71460af58f8565110160283849db4d6bf7e1efa1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 19 Apr 2011 10:54:44 -0700 Subject: Revert "[media] V4L: videobuf, don't use dma addr as physical" This reverts commit 35d9f510b67b10338161aba6229d4f55b4000f5b. Quoth Jiri Slaby: "It fixes mmap when IOMMU is used on x86 only, but breaks architectures like ARM or PPC where virt_to_phys(dma_alloc_coherent) doesn't work. We need there dma_mmap_coherent or similar (the trickery what snd_pcm_default_mmap does but in some saner way). But this cannot be done at this phase." Requested-by: Jiri Slaby Cc: Russell King - ARM Linux Cc: Janusz Krzysztofik Acked-by: Mauro Carvalho Chehab Signed-off-by: Linus Torvalds --- drivers/media/video/videobuf-dma-contig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index c4742fc15529..c9691115f2d2 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -300,7 +300,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); retval = remap_pfn_range(vma, vma->vm_start, - PFN_DOWN(virt_to_phys(mem->vaddr)), + mem->dma_handle >> PAGE_SHIFT, size, vma->vm_page_prot); if (retval) { dev_err(q->dev, "mmap: remap failed with error %d. ", retval); -- cgit v1.2.2 From 25b9875fb4880efabb79d6a35c92cc7287fcaccd Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Apr 2011 09:08:52 -0300 Subject: [media] s5p-fimc: Fix FIMC3 pixel limits on Exynos4 Correct pixel limits for the fourth FIMC entity on Exynos4 SoCs. FIMC3 only supports the writeback input from the LCD mixer. Also rename s5pv310 variant to exynos4 which is needed after renaming s5pv310 series to Exynos4. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-core.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 6c919b38a3d8..d54e6d851f52 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -1750,7 +1750,7 @@ static int __devexit fimc_remove(struct platform_device *pdev) } /* Image pixel limits, similar across several FIMC HW revisions. */ -static struct fimc_pix_limit s5p_pix_limit[3] = { +static struct fimc_pix_limit s5p_pix_limit[4] = { [0] = { .scaler_en_w = 3264, .scaler_dis_w = 8192, @@ -1775,6 +1775,14 @@ static struct fimc_pix_limit s5p_pix_limit[3] = { .out_rot_en_w = 1280, .out_rot_dis_w = 1920, }, + [3] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .in_rot_en_h = 1366, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1366, + .out_rot_dis_w = 1920, + }, }; static struct samsung_fimc_variant fimc0_variant_s5p = { @@ -1827,7 +1835,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = { .pix_limit = &s5p_pix_limit[2], }; -static struct samsung_fimc_variant fimc0_variant_s5pv310 = { +static struct samsung_fimc_variant fimc0_variant_exynos4 = { .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, @@ -1840,7 +1848,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv310 = { .pix_limit = &s5p_pix_limit[1], }; -static struct samsung_fimc_variant fimc2_variant_s5pv310 = { +static struct samsung_fimc_variant fimc2_variant_exynos4 = { .pix_hoff = 1, .has_cistatus2 = 1, .has_mainscaler_ext = 1, @@ -1848,7 +1856,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv310 = { .min_out_pixsize = 16, .hor_offs_align = 1, .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[2], + .pix_limit = &s5p_pix_limit[3], }; /* S5PC100 */ @@ -1874,12 +1882,12 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = { }; /* S5PV310, S5PC210 */ -static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = { +static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = { .variant = { - [0] = &fimc0_variant_s5pv310, - [1] = &fimc0_variant_s5pv310, - [2] = &fimc0_variant_s5pv310, - [3] = &fimc2_variant_s5pv310, + [0] = &fimc0_variant_exynos4, + [1] = &fimc0_variant_exynos4, + [2] = &fimc0_variant_exynos4, + [3] = &fimc2_variant_exynos4, }, .num_entities = 4, .lclk_frequency = 166000000UL, @@ -1893,8 +1901,8 @@ static struct platform_device_id fimc_driver_ids[] = { .name = "s5pv210-fimc", .driver_data = (unsigned long)&fimc_drvdata_s5pv210, }, { - .name = "s5pv310-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv310, + .name = "exynos4-fimc", + .driver_data = (unsigned long)&fimc_drvdata_exynos4, }, {}, }; -- cgit v1.2.2 From c4a627333f0d952c5e10c02609493fa63b5c7b28 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 15 Mar 2011 14:50:52 -0300 Subject: [media] s5p-fimc: Do not allow changing format after REQBUFS Protecting the color format with vb2_is_streaming() is not sufficient as this prevents changing the format only after VIDIOC_STREAMON. To prevent the color format reconfiguration as soon as buffers are allocated use vb2_is_busy() instead. Also make the videobuf queue ops structure static. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 2 +- drivers/media/video/s5p-fimc/fimc-core.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 95f8b4e11e46..00c561ca3870 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -527,7 +527,7 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, if (ret) return ret; - if (vb2_is_streaming(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) + if (vb2_is_busy(&fimc->vid_cap.vbq) || fimc_capture_active(fimc)) return -EBUSY; frame = &ctx->d_frame; diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index d54e6d851f52..115a1e0d8c29 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -758,7 +758,7 @@ static void fimc_unlock(struct vb2_queue *vq) mutex_unlock(&ctx->fimc_dev->lock); } -struct vb2_ops fimc_qops = { +static struct vb2_ops fimc_qops = { .queue_setup = fimc_queue_setup, .buf_prepare = fimc_buf_prepare, .buf_queue = fimc_buf_queue, @@ -965,7 +965,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (vb2_is_streaming(vq)) { + if (vb2_is_busy(vq)) { v4l2_err(&fimc->m2m.v4l2_dev, "queue (%d) busy\n", f->type); return -EBUSY; } -- cgit v1.2.2 From 045030fa16648449b416d4fc8dcc54bfefd6f4aa Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Apr 2011 09:11:43 -0300 Subject: [media] s5p-fimc: Fix bytesperline and plane payload setup Make sure the sizeimage for 3-planar color formats is width * height * 3/2 and the bytesperline is same for each plane in case of a multi-planar format. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-capture.c | 6 ++++-- drivers/media/video/s5p-fimc/fimc-core.c | 30 +++++++++++++++-------------- 2 files changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index 00c561ca3870..d142b40ea64e 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -539,8 +539,10 @@ static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, return -EINVAL; } - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) >> 3; + } /* Output DMA frame pixel size and offsets. */ frame->f_width = pix->plane_fmt[0].bytesperline * 8 diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 115a1e0d8c29..ef4e3f66eac0 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -927,23 +927,23 @@ int fimc_vidioc_try_fmt_mplane(struct file *file, void *priv, pix->num_planes = fmt->memplanes; pix->colorspace = V4L2_COLORSPACE_JPEG; - for (i = 0; i < pix->num_planes; ++i) { - int bpl = pix->plane_fmt[i].bytesperline; - dbg("[%d] bpl: %d, depth: %d, w: %d, h: %d", - i, bpl, fmt->depth[i], pix->width, pix->height); + for (i = 0; i < pix->num_planes; ++i) { + u32 bpl = pix->plane_fmt[i].bytesperline; + u32 *sizeimage = &pix->plane_fmt[i].sizeimage; - if (!bpl || (bpl * 8 / fmt->depth[i]) > pix->width) - bpl = (pix->width * fmt->depth[0]) >> 3; + if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) + bpl = pix->width; /* Planar */ - if (!pix->plane_fmt[i].sizeimage) - pix->plane_fmt[i].sizeimage = pix->height * bpl; + if (fmt->colplanes == 1 && /* Packed */ + (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) + bpl = (pix->width * fmt->depth[0]) / 8; - pix->plane_fmt[i].bytesperline = bpl; + if (i == 0) /* Same bytesperline for each plane. */ + mod_x = bpl; - dbg("[%d]: bpl: %d, sizeimage: %d", - i, pix->plane_fmt[i].bytesperline, - pix->plane_fmt[i].sizeimage); + pix->plane_fmt[i].bytesperline = mod_x; + *sizeimage = (pix->width * pix->height * fmt->depth[i]) / 8; } return 0; @@ -985,8 +985,10 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *priv, if (!frame->fmt) return -EINVAL; - for (i = 0; i < frame->fmt->colplanes; i++) - frame->payload[i] = pix->plane_fmt[i].bytesperline * pix->height; + for (i = 0; i < frame->fmt->colplanes; i++) { + frame->payload[i] = + (pix->width * pix->height * frame->fmt->depth[i]) / 8; + } frame->f_width = pix->plane_fmt[0].bytesperline * 8 / frame->fmt->depth[0]; -- cgit v1.2.2 From 89582654ee3d1d76e153212c88daa6aa6c024fec Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 11 Mar 2011 12:33:44 -0300 Subject: [media] s5p-fimc: Add support for the buffer timestamps and sequence Add support for buffer timestamps and the sequence number in the video capture driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/s5p-fimc/fimc-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index ef4e3f66eac0..dc91a8511af6 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -361,10 +361,20 @@ static void fimc_capture_irq_handler(struct fimc_dev *fimc) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *v_buf; + struct timeval *tv; + struct timespec ts; if (!list_empty(&cap->active_buf_q) && test_bit(ST_CAPT_RUN, &fimc->state)) { + ktime_get_real_ts(&ts); + v_buf = active_queue_pop(cap); + + tv = &v_buf->vb.v4l2_buf.timestamp; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + v_buf->vb.v4l2_buf.sequence = cap->frame_count++; + vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); } -- cgit v1.2.2 From ea42c8ecb2ff998b8f71e0a5f9d2748a65cb8f04 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 12 Apr 2011 10:14:13 -0300 Subject: [media] media: vb2: fix incorrect v4l2_buffer->flags handling Videobuf2 core assumes that driver doesn't set any buffer flags. This is correct for buffer state flags that videobuf2 manages, but the other flags like V4L2_BUF_FLAG_{KEY,P,B}FRAME, V4L2_BUF_FLAG_TIMECODE and V4L2_BUF_FLAG_INPUT should be passed from or to the driver. Reported-by: Jonghun Han Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 71734a4da135..09d792d2edfd 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -37,6 +37,9 @@ module_param(debug, int, 0644); #define call_qop(q, op, args...) \ (((q)->ops->op) ? ((q)->ops->op(args)) : 0) +#define V4L2_BUFFER_STATE_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \ + V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR) + /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer */ @@ -284,7 +287,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) struct vb2_queue *q = vb->vb2_queue; int ret = 0; - /* Copy back data such as timestamp, input, etc. */ + /* Copy back data such as timestamp, flags, input, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); b->input = vb->v4l2_buf.input; b->reserved = vb->v4l2_buf.reserved; @@ -313,7 +316,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->m.userptr = vb->v4l2_planes[0].m.userptr; } - b->flags = 0; + /* + * Clear any buffer state related flags. + */ + b->flags &= ~V4L2_BUFFER_STATE_FLAGS; switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -715,6 +721,8 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; + vb->v4l2_buf.input = b->input; + vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; return 0; } -- cgit v1.2.2 From 13b140953ab4fd86e2065adfef892fe833986ffa Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 14 Apr 2011 07:17:44 -0300 Subject: [media] media: vb2: correct queue initialization order q->memory entry is initialized to late, so if allocation of memory buffers fails, the buffers might not be freed correctly (q->memory is tested in __vb2_free_mem, which can be called before setting q->memory). Reported-by: Kamil Debski Signed-off-by: Marek Szyprowski Signed-off-by: Kyungmin Park CC: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/videobuf2-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 09d792d2edfd..6ba1461d51ef 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -525,6 +525,7 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME); memset(plane_sizes, 0, sizeof(plane_sizes)); memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx)); + q->memory = req->memory; /* * Ask the driver how many buffers and planes per buffer it requires. @@ -566,8 +567,6 @@ int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req) ret = num_buffers; } - q->memory = req->memory; - /* * Return the number of successfully allocated buffers * to the userspace. -- cgit v1.2.2 From 2232d31bf18ba02f5cd632bbfc3466aeca394c75 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Apr 2011 00:41:43 +0200 Subject: ath9k: fix the return value of ath_stoprecv The patch 'ath9k_hw: fix stopping rx DMA during resets' added code to detect a condition where rx DMA was stopped, but the MAC failed to enter the idle state. This condition requires a hardware reset, however the return value of ath_stoprecv was 'true' in that case, which allowed it to skip the reset when issuing a fast channel change. Signed-off-by: Felix Fietkau Reported-by: Paul Stewart Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index dcd19bc337d1..b29c80def35e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -506,7 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc) "confusing the DMA engine when we start RX up\n"); ATH_DBG_WARN_ON_ONCE(!stopped); } - return stopped || reset; + return stopped && !reset; } void ath_flushrecv(struct ath_softc *sc) -- cgit v1.2.2 From 19234c0819da0e043a02710488dfd9b242b42eba Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 20 Apr 2011 00:36:11 +0200 Subject: PM: Add missing syscore_suspend() and syscore_resume() calls Device suspend/resume infrastructure is used not only by the suspend and hibernate code in kernel/power, but also by APM, Xen and the kexec jump feature. However, commit 40dc166cb5dddbd36aa4ad11c03915ea (PM / Core: Introduce struct syscore_ops for core subsystems PM) failed to add syscore_suspend() and syscore_resume() calls to that code, which generally leads to breakage when the features in question are used. To fix this problem, add the missing syscore_suspend() and syscore_resume() calls to arch/x86/kernel/apm_32.c, kernel/kexec.c and drivers/xen/manage.c. Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Acked-by: Ian Campbell --- drivers/base/syscore.c | 2 ++ drivers/xen/manage.c | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/syscore.c b/drivers/base/syscore.c index 90af2943f9e4..c126db3cb7d1 100644 --- a/drivers/base/syscore.c +++ b/drivers/base/syscore.c @@ -73,6 +73,7 @@ int syscore_suspend(void) return ret; } +EXPORT_SYMBOL_GPL(syscore_suspend); /** * syscore_resume - Execute all the registered system core resume callbacks. @@ -95,6 +96,7 @@ void syscore_resume(void) "Interrupts enabled after %pF\n", ops->resume); } } +EXPORT_SYMBOL_GPL(syscore_resume); #endif /* CONFIG_PM_SLEEP */ /** diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 1ac94125bf93..a2eee574784e 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -70,8 +71,13 @@ static int xen_suspend(void *data) BUG_ON(!irqs_disabled()); err = sysdev_suspend(PMSG_FREEZE); + if (!err) { + err = syscore_suspend(); + if (err) + sysdev_resume(); + } if (err) { - printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", + printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n", err); return err; } @@ -95,6 +101,7 @@ static int xen_suspend(void *data) xen_timer_resume(); } + syscore_resume(); sysdev_resume(); return 0; -- cgit v1.2.2 From 04eb34a43ce5168e05e2748bd46a62a09289cdde Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 6 Apr 2011 13:28:35 +1000 Subject: drm/nouveau: split ramin_lock into two locks, one hardirq safe Fixes a possible lock ordering reversal between context_switch_lock and ramin_lock. Signed-off-by: Ben Skeggs Reviewed-by: Francisco Jerez --- drivers/gpu/drm/nouveau/nouveau_drv.h | 3 +++ drivers/gpu/drm/nouveau/nouveau_object.c | 10 ++++++---- drivers/gpu/drm/nouveau/nouveau_state.c | 1 + drivers/gpu/drm/nouveau/nv50_instmem.c | 10 ++++++---- drivers/gpu/drm/nouveau/nv50_vm.c | 5 +++-- drivers/gpu/drm/nouveau/nvc0_vm.c | 5 +++-- 6 files changed, 22 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 856d56a98d1e..a76514a209b3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -682,6 +682,9 @@ struct drm_nouveau_private { /* For PFIFO and PGRAPH. */ spinlock_t context_switch_lock; + /* VM/PRAMIN flush, legacy PRAMIN aperture */ + spinlock_t vm_lock; + /* RAMIN configuration, RAMFC, RAMHT and RAMRO offsets */ struct nouveau_ramht *ramht; struct nouveau_gpuobj *ramfc; diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 4f00c87ed86e..67a16e01ffa6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -1039,19 +1039,20 @@ nv_ro32(struct nouveau_gpuobj *gpuobj, u32 offset) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct drm_device *dev = gpuobj->dev; + unsigned long flags; if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { u64 ptr = gpuobj->vinst + offset; u32 base = ptr >> 16; u32 val; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); if (dev_priv->ramin_base != base) { dev_priv->ramin_base = base; nv_wr32(dev, 0x001700, dev_priv->ramin_base); } val = nv_rd32(dev, 0x700000 + (ptr & 0xffff)); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); return val; } @@ -1063,18 +1064,19 @@ nv_wo32(struct nouveau_gpuobj *gpuobj, u32 offset, u32 val) { struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; struct drm_device *dev = gpuobj->dev; + unsigned long flags; if (gpuobj->pinst == ~0 || !dev_priv->ramin_available) { u64 ptr = gpuobj->vinst + offset; u32 base = ptr >> 16; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); if (dev_priv->ramin_base != base) { dev_priv->ramin_base = base; nv_wr32(dev, 0x001700, dev_priv->ramin_base); } nv_wr32(dev, 0x700000 + (ptr & 0xffff), val); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 6e2b1a6caa2d..a30adec5beaa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -608,6 +608,7 @@ nouveau_card_init(struct drm_device *dev) spin_lock_init(&dev_priv->channels.lock); spin_lock_init(&dev_priv->tile.lock); spin_lock_init(&dev_priv->context_switch_lock); + spin_lock_init(&dev_priv->vm_lock); /* Make the CRTCs and I2C buses accessible */ ret = engine->display.early_init(dev); diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index a6f8aa651fc6..4f95a1e5822e 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -404,23 +404,25 @@ void nv50_instmem_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x00330c, 0x00000001); if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000)) NV_ERROR(dev, "PRAMIN flush timeout\n"); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } void nv84_instmem_flush(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x070000, 0x00000001); if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) NV_ERROR(dev, "PRAMIN flush timeout\n"); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c index 4fd3432b5b8d..6c2694490741 100644 --- a/drivers/gpu/drm/nouveau/nv50_vm.c +++ b/drivers/gpu/drm/nouveau/nv50_vm.c @@ -174,10 +174,11 @@ void nv50_vm_flush_engine(struct drm_device *dev, int engine) { struct drm_nouveau_private *dev_priv = dev->dev_private; + unsigned long flags; - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); nv_wr32(dev, 0x100c80, (engine << 16) | 1); if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nvc0_vm.c b/drivers/gpu/drm/nouveau/nvc0_vm.c index a0a2a0277f73..a179e6c55afb 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vm.c +++ b/drivers/gpu/drm/nouveau/nvc0_vm.c @@ -104,11 +104,12 @@ nvc0_vm_flush(struct nouveau_vm *vm) struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; struct drm_device *dev = vm->dev; struct nouveau_vm_pgd *vpgd; + unsigned long flags; u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5; pinstmem->flush(vm->dev); - spin_lock(&dev_priv->ramin_lock); + spin_lock_irqsave(&dev_priv->vm_lock, flags); list_for_each_entry(vpgd, &vm->pgd_list, head) { /* looks like maybe a "free flush slots" counter, the * faster you write to 0x100cbc to more it decreases @@ -125,5 +126,5 @@ nvc0_vm_flush(struct nouveau_vm *vm) nv_rd32(dev, 0x100c80), engine); } } - spin_unlock(&dev_priv->ramin_lock); + spin_unlock_irqrestore(&dev_priv->vm_lock, flags); } -- cgit v1.2.2 From 01d153326ecd81ed77395f1699a30af416cf77ab Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 8 Apr 2011 10:07:34 +1000 Subject: drm/nouveau: fix nv30 pcie boards Wasn't aware they even existed, apparently they do! They're actually AGP chips with a bridge as far as I can tell, which puts them in the same boat as nv40/nv45. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 78f467fe30be..5045f8b921d6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -398,7 +398,7 @@ nouveau_mem_vram_init(struct drm_device *dev) dma_bits = 40; } else if (drm_pci_device_is_pcie(dev) && - dev_priv->chipset != 0x40 && + dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) { if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39))) dma_bits = 39; diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index a33fe4019286..fc292443039e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -427,7 +427,7 @@ nouveau_sgdma_init(struct drm_device *dev) u32 aper_size, align; int ret; - if (dev_priv->card_type >= NV_50 || drm_pci_device_is_pcie(dev)) + if (dev_priv->card_type >= NV_40 && drm_pci_device_is_pcie(dev)) aper_size = 512 * 1024 * 1024; else aper_size = 64 * 1024 * 1024; @@ -457,7 +457,7 @@ nouveau_sgdma_init(struct drm_device *dev) dev_priv->gart_info.func = &nv50_sgdma_backend; } else if (drm_pci_device_is_pcie(dev) && - dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { + dev_priv->chipset > 0x40 && dev_priv->chipset != 0x45) { if (nv44_graph_class(dev)) { dev_priv->gart_info.func = &nv44_sgdma_backend; align = 512 * 1024; -- cgit v1.2.2 From 8706398bf8841868d4e56fc924a5edcd3f156243 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 11 Apr 2011 16:37:44 +1000 Subject: drm/nouveau: populate ttm_alloced with false, when it's not Caught with kmemcheck on unrelated business. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index fc292443039e..4bce801bc588 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -55,6 +55,7 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, be->func->clear(be); return -EFAULT; } + nvbe->ttm_alloced[nvbe->nr_pages] = false; } nvbe->nr_pages++; -- cgit v1.2.2 From 11dea1a2144f24216551fbeddacbde0980ae8a55 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 18 Apr 2011 09:12:25 +1000 Subject: drm/nouveau: fix pinning of notifier block Problem introduced with commit 6ba9a68317781537d6184d3fdb2d0f20c97da3a4 Reported-by: Bob Gleitsmann Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_notifier.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 7ba3fc0b30c1..5b39718ae1f8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -35,19 +35,22 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct nouveau_bo *ntfy = NULL; - uint32_t flags; + uint32_t flags, ttmpl; int ret; - if (nouveau_vram_notify) + if (nouveau_vram_notify) { flags = NOUVEAU_GEM_DOMAIN_VRAM; - else + ttmpl = TTM_PL_FLAG_VRAM; + } else { flags = NOUVEAU_GEM_DOMAIN_GART; + ttmpl = TTM_PL_FLAG_TT; + } ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy); if (ret) return ret; - ret = nouveau_bo_pin(ntfy, flags); + ret = nouveau_bo_pin(ntfy, ttmpl); if (ret) goto out_err; -- cgit v1.2.2 From a18d89ca026140eb8ac4459bf70a01c571dd9a32 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Tue, 19 Apr 2011 23:50:48 +0200 Subject: drm/nouveau: fix notifier memory corruption bug nouveau_bo_wr32 expects offset to be in words, but we pass value in bytes, so after commit 73412c3854c877e5f37ad944ee8977addde4d35a ("drm/nouveau: allocate kernel's notifier object at end of block") we started to overwrite some memory after notifier buffer object (previously m2mf_ntfy was always 0, so it didn't matter it was a value in bytes). Reported-by: Dominik Brodowski Reported-by: Nigel Cunningham Signed-off-by: Marcin Slusarz Cc: Ben Skeggs Cc: Pekka Paalanen Cc: stable@kernel.org [2.6.38] Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_fbcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 889c4454682e..39aee6d4daf8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -181,13 +181,13 @@ nouveau_fbcon_sync(struct fb_info *info) OUT_RING (chan, 0); } - nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); + nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3, 0xffffffff); FIRE_RING(chan); mutex_unlock(&chan->mutex); ret = -EBUSY; for (i = 0; i < 100000; i++) { - if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy + 3)) { + if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3)) { ret = 0; break; } -- cgit v1.2.2 From e4ac93bf3c05bbe9fed1498a1461a8cdaf4b944d Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Tue, 19 Apr 2011 23:52:42 +0200 Subject: drm/nouveau: fix allocation of notifier object Commit 73412c3854c877e5f37ad944ee8977addde4d35a ("drm/nouveau: allocate kernel's notifier object at end of block") intended to align end of notifier block to page boundary, but start of block was miscalculated to be off by -16 bytes. Fix it. Signed-off-by: Marcin Slusarz Cc: Ben Skeggs Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index ce38e97b9428..568caedd7216 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -83,7 +83,7 @@ nouveau_dma_init(struct nouveau_channel *chan) return ret; /* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */ - ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfd0, 0x1000, + ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000, &chan->m2mf_ntfy); if (ret) return ret; -- cgit v1.2.2 From 0f6db2172ffa478409b5facd06bcd38a03b504f7 Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Mon, 18 Apr 2011 15:26:03 +0100 Subject: parport_pc.c: correctly release the requested region for the IT887x Replace release_resource() by release_region() and also fix the inconsistency in the size of the requested/released region. The size of the resource should be 32, not 0x8 like it was corrected in commit e7c310c36e5fdf1b83a459e5db167bfbd86137db already. CC: linux-serial@vger.kernel.org Reported-by: Julia Lawall Signed-off-by: Niels de Vos Signed-off-by: Greg Kroah-Hartman --- drivers/parport/parport_pc.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index a3755ffc03d4..bc8ce48f0778 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2550,7 +2550,6 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, const struct parport_pc_via_data *via) { short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 }; - struct resource *base_res; u32 ite8872set; u32 ite8872_lpt, ite8872_lpthi; u8 ite8872_irq, type; @@ -2561,8 +2560,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, /* make sure which one chip */ for (i = 0; i < 5; i++) { - base_res = request_region(inta_addr[i], 32, "it887x"); - if (base_res) { + if (request_region(inta_addr[i], 32, "it887x")) { int test; pci_write_config_dword(pdev, 0x60, 0xe5000000 | inta_addr[i]); @@ -2571,7 +2569,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, test = inb(inta_addr[i]); if (test != 0xff) break; - release_region(inta_addr[i], 0x8); + release_region(inta_addr[i], 32); } } if (i >= 5) { @@ -2635,7 +2633,7 @@ static int __devinit sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, /* * Release the resource so that parport_pc_probe_port can get it. */ - release_resource(base_res); + release_region(inta_addr[i], 32); if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi, irq, PARPORT_DMA_NONE, &pdev->dev, 0)) { printk(KERN_INFO -- cgit v1.2.2 From 5680e94148a86e8c31fdc5cb0ea0d5c6810c05b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 11 Apr 2011 10:59:09 +0200 Subject: serial/imx: read cts state only after acking cts change irq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If cts changes between reading the level at the cts input (USR1_RTSS) and acking the irq (USR1_RTSD) the last edge doesn't generate an irq and uart_handle_cts_change is called with a outdated value for cts. The race was introduced by commit ceca629 ([ARM] 2971/1: i.MX uart handle rts irq) Reported-by: Arwed Springer Tested-by: Arwed Springer Cc: stable@kernel.org # 2.6.14+ Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index cb36b0d4ef3c..62df72d9f0aa 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -382,12 +382,13 @@ static void imx_start_tx(struct uart_port *port) static irqreturn_t imx_rtsint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; + unsigned int val; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); writel(USR1_RTSD, sport->port.membase + USR1); + val = readl(sport->port.membase + USR1) & USR1_RTSS; uart_handle_cts_change(&sport->port, !!val); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); -- cgit v1.2.2 From 9db4e4381a8e881ff65a5d3400bfa471f84217e7 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Sun, 27 Mar 2011 04:05:00 +0400 Subject: tty/n_gsm: fix bug in CRC calculation for gsm1 mode Problem description: gsm_queue() calculate a CRC for arrived frames. As a last step of CRC calculation it call gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); This work perfectly for the case of GSM0 mode as gsm->received_fcs contain the last piece of data required to generate final CRC. gsm->received_fcs is not used for GSM1 mode. Thus we put an additional byte to CRC calculation. As result we get a wrong CRC and reject incoming frame. Signed-off-by: Mikhail Kshevetskiy Acked-by: Alan Cox Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 47f8cdb207f1..74273e638c0d 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1658,8 +1658,12 @@ static void gsm_queue(struct gsm_mux *gsm) if ((gsm->control & ~PF) == UI) gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len); - /* generate final CRC with received FCS */ - gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); + if (gsm->encoding == 0){ + /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only. + In this case it contain the last piece of data + required to generate final CRC */ + gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs); + } if (gsm->fcs != GOOD_FCS) { gsm->bad_fcs++; if (debug & 4) -- cgit v1.2.2 From 5785e53ffa73f77fb19e378c899027afc07272bc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 19 Apr 2011 15:24:59 -0400 Subject: drm/radeon/kms: pll tweaks for r7xx Prefer min m to max p only on pre-r7xx asics. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=36197 Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/atombios_crtc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9d516a8c4dfa..529a3a704731 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -532,10 +532,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, else pll->flags |= RADEON_PLL_PREFER_LOW_REF_DIV; - if ((rdev->family == CHIP_R600) || - (rdev->family == CHIP_RV610) || - (rdev->family == CHIP_RV630) || - (rdev->family == CHIP_RV670)) + if (rdev->family < CHIP_RV770) pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; } else { pll->flags |= RADEON_PLL_LEGACY; @@ -565,7 +562,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { if (ss_enabled) { if (ss->refdiv) { - pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; pll->flags |= RADEON_PLL_USE_REF_DIV; pll->reference_div = ss->refdiv; if (ASIC_IS_AVIVO(rdev)) -- cgit v1.2.2 From 204ae24dc71f794aaad4df48a0083dfedc711afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Cano?= Date: Tue, 19 Apr 2011 11:07:13 -0400 Subject: drm/radeon/kms: fix IH writeback on r6xx+ on big endian machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit agd5f: fix commit message. Signed-off-by: Cedric Cano Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 2 +- drivers/gpu/drm/radeon/r600.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 43fd01674489..e9bc135d9189 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -2580,7 +2580,7 @@ static inline u32 evergreen_get_ih_wptr(struct radeon_device *rdev) u32 wptr, tmp; if (rdev->wb.enabled) - wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]; + wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]); else wptr = RREG32(IH_RB_WPTR); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 15d58292677a..6f27593901c7 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3231,7 +3231,7 @@ static inline u32 r600_get_ih_wptr(struct radeon_device *rdev) u32 wptr, tmp; if (rdev->wb.enabled) - wptr = rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]; + wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]); else wptr = RREG32(IH_RB_WPTR); -- cgit v1.2.2 From 2b7da309ffe602d222558cee4d7e407b96e34b3a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 20 Apr 2011 15:38:07 +1000 Subject: md/raid5: remove setting of ->queue_lock We previously needed to set ->queue_lock to match the raid5 device_lock so we could safely use queue_flag_* operations (e.g. for plugging). which test the ->queue_lock is in fact locked. However that need has completely gone away and is unlikely to come back to remove this now-pointless setting. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f301e6ae220c..179bdfc4d03a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5151,7 +5151,6 @@ static int run(mddev_t *mddev) mddev->queue->backing_dev_info.congested_data = mddev; mddev->queue->backing_dev_info.congested_fn = raid5_congested; - mddev->queue->queue_lock = &conf->device_lock; chunk_size = mddev->chunk_sectors << 9; blk_queue_io_min(mddev->queue, chunk_size); -- cgit v1.2.2 From 3b71bd9337b404baab5c894e066be6b6bf51b1c3 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 20 Apr 2011 15:38:18 +1000 Subject: md: Fix dev_sectors on takeover from raid0 to raid4/5 A raid0 array doesn't set 'dev_sectors' as each device might contribute a different number of sectors. So when converting to a RAID4 or RAID5 we need to set dev_sectors as they need the number. We have already verified that in fact all devices do contribute the same number of sectors, so use that number. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 179bdfc4d03a..fd500112f13e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5678,6 +5678,7 @@ static void raid5_quiesce(mddev_t *mddev, int state) static void *raid45_takeover_raid0(mddev_t *mddev, int level) { struct raid0_private_data *raid0_priv = mddev->private; + unsigned long long sectors; /* for raid0 takeover only one zone is supported */ if (raid0_priv->nr_strip_zones > 1) { @@ -5686,6 +5687,9 @@ static void *raid45_takeover_raid0(mddev_t *mddev, int level) return ERR_PTR(-EINVAL); } + sectors = raid0_priv->strip_zone[0].zone_end; + sector_div(sectors, raid0_priv->strip_zone[0].nb_dev); + mddev->dev_sectors = sectors; mddev->new_level = level; mddev->new_layout = ALGORITHM_PARITY_N; mddev->new_chunk_sectors = mddev->chunk_sectors; -- cgit v1.2.2 From fee68723cf6ae00082f70f3eff17fceab2a4f7d7 Mon Sep 17 00:00:00 2001 From: Krzysztof Wojcik Date: Wed, 20 Apr 2011 15:39:53 +1000 Subject: md: Cleanup after raid45->raid0 takeover Problem: After raid4->raid0 takeover operation, another takeover operation (e.g raid0->raid10) results "kernel oops". Root cause: Variables 'degraded' in mddev structure is not cleared on raid45->raid0 takeover. This patch reset this variable. Signed-off-by: Krzysztof Wojcik Signed-off-by: NeilBrown --- drivers/md/md.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/md/md.c b/drivers/md/md.c index 6e853c61d87e..7d6f7f18a920 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3170,6 +3170,7 @@ level_store(mddev_t *mddev, const char *buf, size_t len) mddev->layout = mddev->new_layout; mddev->chunk_sectors = mddev->new_chunk_sectors; mddev->delta_disks = 0; + mddev->degraded = 0; if (mddev->pers->sync_request == NULL) { /* this is now an array without redundancy, so * it must always be in_sync -- cgit v1.2.2 From 65f8da475995f667af5298c644707dbd9d646ca6 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 20 Apr 2011 10:15:30 +0200 Subject: [S390] dasd: fix race between open and offline The dasd_open function uses the private_data pointer of the gendisk to find the dasd_block structure that matches the gendisk. When a DASD device is set offline, we set the private_data pointer of the gendisk to NULL and later remove the dasd_block structure, but there is still a small race window, in which dasd_open could first read a pointer from the private_data field and then try to use it, after the structure has already been freed. To close this race window, we will store a pointer to the dasd_devmap structure of the base device in the private_data field. The devmap entries are not deleted, and we already have proper locking and reference counting in place, so that we can safely get from a devmap pointer to the dasd_device and dasd_block structures of the device. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 40 ++++++------ drivers/s390/block/dasd_devmap.c | 30 +++++++++ drivers/s390/block/dasd_genhd.c | 2 +- drivers/s390/block/dasd_int.h | 3 + drivers/s390/block/dasd_ioctl.c | 128 ++++++++++++++++++++++++++------------- 5 files changed, 143 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4d2df2f76ea0..475e603fc584 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2314,15 +2314,14 @@ static void dasd_flush_request_queue(struct dasd_block *block) static int dasd_open(struct block_device *bdev, fmode_t mode) { - struct dasd_block *block = bdev->bd_disk->private_data; struct dasd_device *base; int rc; - if (!block) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) return -ENODEV; - base = block->base; - atomic_inc(&block->open_count); + atomic_inc(&base->block->open_count); if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { rc = -ENODEV; goto unlock; @@ -2355,21 +2354,28 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) goto out; } + dasd_put_device(base); return 0; out: module_put(base->discipline->owner); unlock: - atomic_dec(&block->open_count); + atomic_dec(&base->block->open_count); + dasd_put_device(base); return rc; } static int dasd_release(struct gendisk *disk, fmode_t mode) { - struct dasd_block *block = disk->private_data; + struct dasd_device *base; - atomic_dec(&block->open_count); - module_put(block->base->discipline->owner); + base = dasd_device_from_gendisk(disk); + if (!base) + return -ENODEV; + + atomic_dec(&base->block->open_count); + module_put(base->discipline->owner); + dasd_put_device(base); return 0; } @@ -2378,20 +2384,20 @@ static int dasd_release(struct gendisk *disk, fmode_t mode) */ static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct dasd_block *block; struct dasd_device *base; - block = bdev->bd_disk->private_data; - if (!block) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) return -ENODEV; - base = block->base; if (!base->discipline || - !base->discipline->fill_geometry) + !base->discipline->fill_geometry) { + dasd_put_device(base); return -EINVAL; - - base->discipline->fill_geometry(block, geo); - geo->start = get_start_sect(bdev) >> block->s2b_shift; + } + base->discipline->fill_geometry(base->block, geo); + geo->start = get_start_sect(bdev) >> base->block->s2b_shift; + dasd_put_device(base); return 0; } @@ -2528,7 +2534,6 @@ void dasd_generic_remove(struct ccw_device *cdev) dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ block = device->block; - device->block = NULL; dasd_delete_device(device); /* * life cycle of block is bound to device, so delete it after @@ -2650,7 +2655,6 @@ int dasd_generic_set_offline(struct ccw_device *cdev) dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ block = device->block; - device->block = NULL; dasd_delete_device(device); /* * life cycle of block is bound to device, so delete it after diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 42e1bf35f689..d71511c7850a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -674,6 +674,36 @@ dasd_device_from_cdev(struct ccw_device *cdev) return device; } +void dasd_add_link_to_gendisk(struct gendisk *gdp, struct dasd_device *device) +{ + struct dasd_devmap *devmap; + + devmap = dasd_find_busid(dev_name(&device->cdev->dev)); + if (IS_ERR(devmap)) + return; + spin_lock(&dasd_devmap_lock); + gdp->private_data = devmap; + spin_unlock(&dasd_devmap_lock); +} + +struct dasd_device *dasd_device_from_gendisk(struct gendisk *gdp) +{ + struct dasd_device *device; + struct dasd_devmap *devmap; + + if (!gdp->private_data) + return NULL; + device = NULL; + spin_lock(&dasd_devmap_lock); + devmap = gdp->private_data; + if (devmap && devmap->device) { + device = devmap->device; + dasd_get_device(device); + } + spin_unlock(&dasd_devmap_lock); + return device; +} + /* * SECTION: files in sysfs */ diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 5505bc07e1e7..19a1ff03d65e 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -73,7 +73,7 @@ int dasd_gendisk_alloc(struct dasd_block *block) if (base->features & DASD_FEATURE_READONLY || test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) set_disk_ro(gdp, 1); - gdp->private_data = block; + dasd_add_link_to_gendisk(gdp, base); gdp->queue = block->request_queue; block->gdp = gdp; set_capacity(block->gdp, 0); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index df9f6999411d..d1e4f2c1264c 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -686,6 +686,9 @@ struct dasd_device *dasd_device_from_cdev(struct ccw_device *); struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *); struct dasd_device *dasd_device_from_devindex(int); +void dasd_add_link_to_gendisk(struct gendisk *, struct dasd_device *); +struct dasd_device *dasd_device_from_gendisk(struct gendisk *); + int dasd_parse(void); int dasd_busid_known(const char *); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 26075e95b1ba..72261e4c516d 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -42,16 +42,22 @@ dasd_ioctl_api_version(void __user *argp) static int dasd_ioctl_enable(struct block_device *bdev) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - dasd_enable_device(block->base); + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + + dasd_enable_device(base); /* Formatting the dasd device can change the capacity. */ mutex_lock(&bdev->bd_mutex); - i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9); + i_size_write(bdev->bd_inode, + (loff_t)get_capacity(base->block->gdp) << 9); mutex_unlock(&bdev->bd_mutex); + dasd_put_device(base); return 0; } @@ -62,11 +68,14 @@ dasd_ioctl_enable(struct block_device *bdev) static int dasd_ioctl_disable(struct block_device *bdev) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; /* * Man this is sick. We don't do a real disable but only downgrade * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses @@ -75,7 +84,7 @@ dasd_ioctl_disable(struct block_device *bdev) * using the BIODASDFMT ioctl. Therefore the correct state for the * device is DASD_STATE_BASIC that allows to do basic i/o. */ - dasd_set_target_state(block->base, DASD_STATE_BASIC); + dasd_set_target_state(base, DASD_STATE_BASIC); /* * Set i_size to zero, since read, write, etc. check against this * value. @@ -83,6 +92,7 @@ dasd_ioctl_disable(struct block_device *bdev) mutex_lock(&bdev->bd_mutex); i_size_write(bdev->bd_inode, 0); mutex_unlock(&bdev->bd_mutex); + dasd_put_device(base); return 0; } @@ -191,26 +201,36 @@ static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) static int dasd_ioctl_format(struct block_device *bdev, void __user *argp) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_device *base; struct format_data_t fdata; + int rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (!argp) return -EINVAL; - - if (block->base->features & DASD_FEATURE_READONLY || - test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + if (base->features & DASD_FEATURE_READONLY || + test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { + dasd_put_device(base); return -EROFS; - if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) + } + if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) { + dasd_put_device(base); return -EFAULT; + } if (bdev != bdev->bd_contains) { pr_warning("%s: The specified DASD is a partition and cannot " "be formatted\n", - dev_name(&block->base->cdev->dev)); + dev_name(&base->cdev->dev)); + dasd_put_device(base); return -EINVAL; } - return dasd_format(block, &fdata); + rc = dasd_format(base->block, &fdata); + dasd_put_device(base); + return rc; } #ifdef CONFIG_DASD_PROFILE @@ -340,8 +360,8 @@ static int dasd_ioctl_information(struct dasd_block *block, static int dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) { - struct dasd_block *block = bdev->bd_disk->private_data; - int intval; + struct dasd_device *base; + int intval, rc; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -350,10 +370,17 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) return -EINVAL; if (get_user(intval, (int __user *)argp)) return -EFAULT; - if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &block->base->flags)) + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + if (!intval && test_bit(DASD_FLAG_DEVICE_RO, &base->flags)) { + dasd_put_device(base); return -EROFS; + } set_disk_ro(bdev->bd_disk, intval); - return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); + rc = dasd_set_feature(base->cdev, DASD_FEATURE_READONLY, intval); + dasd_put_device(base); + return rc; } static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, @@ -372,59 +399,78 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, int dasd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct dasd_block *block = bdev->bd_disk->private_data; + struct dasd_block *block; + struct dasd_device *base; void __user *argp; + int rc; if (is_compat_task()) argp = compat_ptr(arg); else argp = (void __user *)arg; - if (!block) - return -ENODEV; - if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { PRINT_DEBUG("empty data ptr"); return -EINVAL; } + base = dasd_device_from_gendisk(bdev->bd_disk); + if (!base) + return -ENODEV; + block = base->block; + rc = 0; switch (cmd) { case BIODASDDISABLE: - return dasd_ioctl_disable(bdev); + rc = dasd_ioctl_disable(bdev); + break; case BIODASDENABLE: - return dasd_ioctl_enable(bdev); + rc = dasd_ioctl_enable(bdev); + break; case BIODASDQUIESCE: - return dasd_ioctl_quiesce(block); + rc = dasd_ioctl_quiesce(block); + break; case BIODASDRESUME: - return dasd_ioctl_resume(block); + rc = dasd_ioctl_resume(block); + break; case BIODASDFMT: - return dasd_ioctl_format(bdev, argp); + rc = dasd_ioctl_format(bdev, argp); + break; case BIODASDINFO: - return dasd_ioctl_information(block, cmd, argp); + rc = dasd_ioctl_information(block, cmd, argp); + break; case BIODASDINFO2: - return dasd_ioctl_information(block, cmd, argp); + rc = dasd_ioctl_information(block, cmd, argp); + break; case BIODASDPRRD: - return dasd_ioctl_read_profile(block, argp); + rc = dasd_ioctl_read_profile(block, argp); + break; case BIODASDPRRST: - return dasd_ioctl_reset_profile(block); + rc = dasd_ioctl_reset_profile(block); + break; case BLKROSET: - return dasd_ioctl_set_ro(bdev, argp); + rc = dasd_ioctl_set_ro(bdev, argp); + break; case DASDAPIVER: - return dasd_ioctl_api_version(argp); + rc = dasd_ioctl_api_version(argp); + break; case BIODASDCMFENABLE: - return enable_cmf(block->base->cdev); + rc = enable_cmf(base->cdev); + break; case BIODASDCMFDISABLE: - return disable_cmf(block->base->cdev); + rc = disable_cmf(base->cdev); + break; case BIODASDREADALLCMB: - return dasd_ioctl_readall_cmb(block, cmd, argp); + rc = dasd_ioctl_readall_cmb(block, cmd, argp); + break; default: /* if the discipline has an ioctl method try it. */ - if (block->base->discipline->ioctl) { - int rval = block->base->discipline->ioctl(block, cmd, argp); - if (rval != -ENOIOCTLCMD) - return rval; - } - - return -EINVAL; + if (base->discipline->ioctl) { + rc = base->discipline->ioctl(block, cmd, argp); + if (rc == -ENOIOCTLCMD) + rc = -EINVAL; + } else + rc = -EINVAL; } + dasd_put_device(base); + return rc; } -- cgit v1.2.2 From bffbbd2df4196a73ffdc16709866dd96eb66aad8 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Wed, 20 Apr 2011 10:15:33 +0200 Subject: [S390] qdio: reset error states immediately The qdio hardware may surpress further interrupts as long as a SBAL is in the error state. That can lead to unnotified data in the SBALs following the error state. To prevent this behaviour change the SBAL[s] in error state immediately to another program owned state so interrupts are again received for further traffic on the device. Signed-off-by: Jan Glauber Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/qdio_main.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index c532ba929ccd..e8f267eb8887 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -407,8 +407,11 @@ static inline void account_sbals(struct qdio_q *q, int count) q->q_stats.nr_sbals[pos]++; } -static void announce_buffer_error(struct qdio_q *q, int count) +static void process_buffer_error(struct qdio_q *q, int count) { + unsigned char state = (q->is_input_q) ? SLSB_P_INPUT_NOT_INIT : + SLSB_P_OUTPUT_NOT_INIT; + q->qdio_error |= QDIO_ERROR_SLSB_STATE; /* special handling for no target buffer empty */ @@ -426,6 +429,12 @@ static void announce_buffer_error(struct qdio_q *q, int count) DBF_ERROR("F14:%2x F15:%2x", q->sbal[q->first_to_check]->element[14].flags & 0xff, q->sbal[q->first_to_check]->element[15].flags & 0xff); + + /* + * Interrupts may be avoided as long as the error is present + * so change the buffer state immediately to avoid starvation. + */ + set_buf_states(q, q->first_to_check, state, count); } static inline void inbound_primed(struct qdio_q *q, int count) @@ -506,8 +515,7 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) account_sbals(q, count); break; case SLSB_P_INPUT_ERROR: - announce_buffer_error(q, count); - /* process the buffer, the upper layer will take care of it */ + process_buffer_error(q, count); q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); if (q->irq_ptr->perf_stat_enabled) @@ -677,8 +685,7 @@ static int get_outbound_buffer_frontier(struct qdio_q *q) account_sbals(q, count); break; case SLSB_P_OUTPUT_ERROR: - announce_buffer_error(q, count); - /* process the buffer, the upper layer will take care of it */ + process_buffer_error(q, count); q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); if (q->irq_ptr->perf_stat_enabled) -- cgit v1.2.2 From c7a29e56f0a3526b71e9694b403b8e2cbe9c31e5 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Wed, 20 Apr 2011 10:15:35 +0200 Subject: [S390] dasd: check sense type in device change handler When evaluating sense data in dasd_eckd_check_for_device_change, we must always check for the type of sense data in byte 27, bit 0, to make sure that the rest of the sense data is interpreted correctly. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index db8005d9f2fd..3ebdf5f92f8f 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2037,7 +2037,7 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, return; /* summary unit check */ - if ((sense[7] == 0x0D) && + if ((sense[27] & DASD_SENSE_BIT_0) && (sense[7] == 0x0D) && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK)) { dasd_alias_handle_summary_unit_check(device, irb); return; @@ -2053,7 +2053,8 @@ static void dasd_eckd_check_for_device_change(struct dasd_device *device, /* loss of device reservation is handled via base devices only * as alias devices may be used with several bases */ - if (device->block && (sense[7] == 0x3F) && + if (device->block && (sense[27] & DASD_SENSE_BIT_0) && + (sense[7] == 0x3F) && (scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) && test_bit(DASD_FLAG_IS_RESERVED, &device->flags)) { if (device->features & DASD_FEATURE_FAILONSLCK) -- cgit v1.2.2 From 6f4d6dc167a001267eeff18bdea0ce3e9108c662 Mon Sep 17 00:00:00 2001 From: Breno Leitao Date: Tue, 19 Apr 2011 09:39:22 +0000 Subject: ehea: Fix a DLPAR bug on ehea_rereg_mrs(). We are currently continuing if ehea_restart_qps() fails, when we do a memory DLPAR (remove or add more memory to the system). This patch just let the NAPI disabled if the ehea_restart_qps() fails. Signed-off-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index f75d3144b8a5..53c0f04b1b23 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3040,11 +3040,14 @@ static void ehea_rereg_mrs(void) if (dev->flags & IFF_UP) { mutex_lock(&port->port_lock); - port_napi_enable(port); ret = ehea_restart_qps(dev); - check_sqs(port); - if (!ret) + if (!ret) { + check_sqs(port); + port_napi_enable(port); netif_wake_queue(dev); + } else { + netdev_err(dev, "Unable to restart QPS\n"); + } mutex_unlock(&port->port_lock); } } -- cgit v1.2.2 From 2430af8b7fa37ac0be102c77f9dc6ee669d24ba9 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Tue, 19 Apr 2011 02:09:55 +0000 Subject: bonding: 802.3ad - fix agg_device_up The slave member of struct aggregator does not necessarily point to a slave which is part of the aggregator. It points to the slave structure containing the aggregator structure, while completely different slaves (or no slaves at all) may be part of the aggregator. The agg_device_up() function wrongly uses agg->slave to find the state of the aggregator. Use agg->lag_ports->slave instead. The bug has been introduced by commit 4cd6fe1c6483cde93e2ec91f58b7af9c9eea51ad ("bonding: fix link down handling in 802.3ad mode"). Signed-off-by: Jiri Bohac Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 494bf960442d..31912f17653f 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1482,8 +1482,11 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, static int agg_device_up(const struct aggregator *agg) { - return (netif_running(agg->slave->dev) && - netif_carrier_ok(agg->slave->dev)); + struct port *port = agg->lag_ports; + if (!port) + return 0; + return (netif_running(port->slave->dev) && + netif_carrier_ok(port->slave->dev)); } /** -- cgit v1.2.2 From 9cf3b5fa6f7b246784d62a2a7637a871290c9ab9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 17 Apr 2011 20:32:19 +0200 Subject: rtc: fix coh901331 startup crash The rtc_device_register() call has changed semantics so that it will immediately call out to rtc_read_alarm() and since the callbacks require the drvdata to be set, we need to set it before the registration call to avoid NULL dereference. Signed-off-by: Linus Walleij --- drivers/rtc/rtc-coh901331.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 316f484999b5..80f9c88214c5 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -220,6 +220,7 @@ static int __init coh901331_probe(struct platform_device *pdev) } clk_disable(rtap->clk); + platform_set_drvdata(pdev, rtap); rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops, THIS_MODULE); if (IS_ERR(rtap->rtc)) { @@ -227,11 +228,10 @@ static int __init coh901331_probe(struct platform_device *pdev) goto out_no_rtc; } - platform_set_drvdata(pdev, rtap); - return 0; out_no_rtc: + platform_set_drvdata(pdev, NULL); out_no_clk_enable: clk_put(rtap->clk); out_no_clk: -- cgit v1.2.2 From b25026981aecde3685dd0e45ad980fff9f528daa Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 20 Apr 2011 15:57:14 +0200 Subject: iwlwifi: fix skb usage after free Since commit a120e912eb51e347f36c71b60a1d13af74d30e83 Author: Stanislaw Gruszka Date: Fri Feb 19 15:47:33 2010 -0800 iwlwifi: sanity check before counting number of tfds can be free we use skb->data after calling ieee80211_tx_status_irqsafe(), which could free skb instantly. On current kernels I do not observe practical problems related with bug, but on 2.6.35.y it cause random system hangs when stressing wireless link. Cc: stable@kernel.org # 2.6.32+ Signed-off-by: Stanislaw Gruszka Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index a709d05c5868..2dd7d54a796f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -1224,12 +1224,16 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwlagn_tx_status(priv, tx_info, - txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwlagn_tx_status(priv, tx_info, + txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) -- cgit v1.2.2 From 069f40fc07f6df3da325e7ea1698a0d6247983d5 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 20 Apr 2011 16:01:46 +0200 Subject: iwl4965: fix skb usage after free Since commit a120e912eb51e347f36c71b60a1d13af74d30e83 Author: Stanislaw Gruszka Date: Fri Feb 19 15:47:33 2010 -0800 iwlwifi: sanity check before counting number of tfds can be free we use skb->data after calling ieee80211_tx_status_irqsafe(), which could free skb instantly. On current kernels I do not observe practical problems related with bug, but on 2.6.35.y it cause random system hangs when stressing wireless link, making bisection of other problems impossible. Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-4965-tx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index 5c40502f869a..fbec88d48f1b 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -1127,12 +1127,16 @@ int iwl4965_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd)) { tx_info = &txq->txb[txq->q.read_ptr]; - iwl4965_tx_status(priv, tx_info, - txq_id >= IWL4965_FIRST_AMPDU_QUEUE); + + if (WARN_ON_ONCE(tx_info->skb == NULL)) + continue; hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (hdr && ieee80211_is_data_qos(hdr->frame_control)) + if (ieee80211_is_data_qos(hdr->frame_control)) nfreed++; + + iwl4965_tx_status(priv, tx_info, + txq_id >= IWL4965_FIRST_AMPDU_QUEUE); tx_info->skb = NULL; priv->cfg->ops->lib->txq_free_tfd(priv, txq); -- cgit v1.2.2 From b522f02184b413955f3bc952e3776ce41edc6355 Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Thu, 14 Apr 2011 20:55:19 +0400 Subject: agp: fix OOM and buffer overflow page_count is copied from userspace. agp_allocate_memory() tries to check whether this number is too big, but doesn't take into account the wrap case. Also agp_create_user_memory() doesn't check whether alloc_size is calculated from num_agp_pages variable without overflow. This may lead to allocation of too small buffer with following buffer overflow. Another problem in agp code is not addressed in the patch - kernel memory exhaustion (AGPIOC_RESERVE and AGPIOC_ALLOCATE ioctls). It is not checked whether requested pid is a pid of the caller (no check in agpioc_reserve_wrap()). Each allocation is limited to 16KB, though, there is no per-process limit. This might lead to OOM situation, which is not even solved in case of the caller death by OOM killer - the memory is allocated for another (faked) process. Signed-off-by: Vasiliy Kulikov Signed-off-by: Dave Airlie --- drivers/char/agp/generic.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 012cba0d6d96..850a643ad694 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -115,6 +115,9 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) struct agp_memory *new; unsigned long alloc_size = num_agp_pages*sizeof(struct page *); + if (INT_MAX/sizeof(struct page *) < num_agp_pages) + return NULL; + new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); if (new == NULL) return NULL; @@ -234,11 +237,14 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, int scratch_pages; struct agp_memory *new; size_t i; + int cur_memory; if (!bridge) return NULL; - if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp) + cur_memory = atomic_read(&bridge->current_memory_agp); + if ((cur_memory + page_count > bridge->max_memory_agp) || + (cur_memory + page_count < page_count)) return NULL; if (type >= AGP_USER_TYPES) { -- cgit v1.2.2 From 194b3da873fd334ef183806db751473512af29ce Mon Sep 17 00:00:00 2001 From: Vasiliy Kulikov Date: Thu, 14 Apr 2011 20:55:16 +0400 Subject: agp: fix arbitrary kernel memory writes pg_start is copied from userspace on AGPIOC_BIND and AGPIOC_UNBIND ioctl cmds of agp_ioctl() and passed to agpioc_bind_wrap(). As said in the comment, (pg_start + mem->page_count) may wrap in case of AGPIOC_BIND, and it is not checked at all in case of AGPIOC_UNBIND. As a result, user with sufficient privileges (usually "video" group) may generate either local DoS or privilege escalation. Signed-off-by: Vasiliy Kulikov Signed-off-by: Dave Airlie --- drivers/char/agp/generic.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 850a643ad694..b072648dc3f6 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1095,8 +1095,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) return -EINVAL; } - /* AK: could wrap */ - if ((pg_start + mem->page_count) > num_entries) + if (((pg_start + mem->page_count) > num_entries) || + ((pg_start + mem->page_count) < pg_start)) return -EINVAL; j = pg_start; @@ -1130,7 +1130,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { size_t i; struct agp_bridge_data *bridge; - int mask_type; + int mask_type, num_entries; bridge = mem->bridge; if (!bridge) @@ -1142,6 +1142,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) if (type != mem->type) return -EINVAL; + num_entries = agp_num_entries(); + if (((pg_start + mem->page_count) > num_entries) || + ((pg_start + mem->page_count) < pg_start)) + return -EINVAL; + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); if (mask_type != 0) { /* The generic routines know nothing of memory types */ -- cgit v1.2.2 From 4949603a6fabf3a54cbd7be6df1681789abfca7d Mon Sep 17 00:00:00 2001 From: Markus Trippelsdorf Date: Wed, 20 Apr 2011 14:28:45 -0400 Subject: EDAC: Remove debugging output in scrub rate handling This patch removes superfluous debugging output in the sysfs scrub rate handler. It also consolidates the error handling in the scrub rate accessors. Signed-off-by: Markus Trippelsdorf Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 2 -- drivers/edac/edac_mc_sysfs.c | 11 +++++------ 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 31e71c4fc831..4b4071ee2f5c 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -211,8 +211,6 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci) scrubval = scrubval & 0x001F; - amd64_debug("pci-read, sdram scrub control value: %d\n", scrubval); - for (i = 0; i < ARRAY_SIZE(scrubrates); i++) { if (scrubrates[i].scrubval == scrubval) { retval = scrubrates[i].bandwidth; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 26343fd46596..29ffa350bfbe 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -458,13 +458,13 @@ static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci, return -EINVAL; new_bw = mci->set_sdram_scrub_rate(mci, bandwidth); - if (new_bw >= 0) { - edac_printk(KERN_DEBUG, EDAC_MC, "Scrub rate set to %d\n", new_bw); - return count; + if (new_bw < 0) { + edac_printk(KERN_WARNING, EDAC_MC, + "Error setting scrub rate to: %lu\n", bandwidth); + return -EINVAL; } - edac_printk(KERN_DEBUG, EDAC_MC, "Error setting scrub rate to: %lu\n", bandwidth); - return -EINVAL; + return count; } /* @@ -483,7 +483,6 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data) return bandwidth; } - edac_printk(KERN_DEBUG, EDAC_MC, "Read scrub rate: %d\n", bandwidth); return sprintf(data, "%d\n", bandwidth); } -- cgit v1.2.2 From 51a63e67da6056c13b5b597dcc9e1b3bd7ceaa55 Mon Sep 17 00:00:00 2001 From: Joseph Cihula Date: Mon, 21 Mar 2011 11:04:24 -0700 Subject: intel_iommu: disable all VT-d PMRs when TXT launched Intel VT-d Protected Memory Regions (PMRs) are supposed to be disabled, on each VT-d engine, after DMA remapping is enabled on the engines. This is because the behavior of having both enabled is not deterministic and because, if TXT has been used to launch the kernel, the PMRs may be programmed to cover memory regions that will be used for DMA. Under some circumstances (certain quirks detected, lack of multiple devices, etc.), the current code does not set up DMA remapping on some VT-d engines. In such cases it also skips disabling the PMRs. This causes failures when the kernel is launched with TXT (most often this occurs on the graphics engine and results in colored vertical bars on the display). This patch detects when the kernel has been launched with TXT and then disables the PMRs on all VT-d engines. In some cases where the reason that remapping is not being enabled is due to possible ACPI DMAR table errors, the VT-d engine addresses may not be correct and thus not able to be safely programmed even to disable PMRs. Because part of the TXT launch process is the verification of these addresses, it will always be safe to disable PMRs if the TXT launch has succeeded and hence only doing this in such cases. Signed-off-by: Joseph Cihula Signed-off-by: David Woodhouse --- drivers/pci/intel-iommu.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 5dc5d3e3508e..cdded1e2e660 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1299,7 +1299,7 @@ static void iommu_detach_domain(struct dmar_domain *domain, static struct iova_domain reserved_iova_list; static struct lock_class_key reserved_rbtree_key; -static void dmar_init_reserved_ranges(void) +static int dmar_init_reserved_ranges(void) { struct pci_dev *pdev = NULL; struct iova *iova; @@ -1313,8 +1313,10 @@ static void dmar_init_reserved_ranges(void) /* IOAPIC ranges shouldn't be accessed by DMA */ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), IOVA_PFN(IOAPIC_RANGE_END)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve IOAPIC range failed\n"); + return -ENODEV; + } /* Reserve all PCI MMIO to avoid peer-to-peer access */ for_each_pci_dev(pdev) { @@ -1327,11 +1329,13 @@ static void dmar_init_reserved_ranges(void) iova = reserve_iova(&reserved_iova_list, IOVA_PFN(r->start), IOVA_PFN(r->end)); - if (!iova) + if (!iova) { printk(KERN_ERR "Reserve iova failed\n"); + return -ENODEV; + } } } - + return 0; } static void domain_reserve_special_ranges(struct dmar_domain *domain) @@ -2213,7 +2217,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw) return 0; } -int __init init_dmars(void) +static int __init init_dmars(int force_on) { struct dmar_drhd_unit *drhd; struct dmar_rmrr_unit *rmrr; @@ -2393,8 +2397,15 @@ int __init init_dmars(void) * enable translation */ for_each_drhd_unit(drhd) { - if (drhd->ignored) + if (drhd->ignored) { + /* + * we always have to disable PMRs or DMA may fail on + * this device + */ + if (force_on) + iommu_disable_protect_mem_regions(drhd->iommu); continue; + } iommu = drhd->iommu; iommu_flush_write_buffer(iommu); @@ -3303,12 +3314,21 @@ int __init intel_iommu_init(void) if (no_iommu || dmar_disabled) return -ENODEV; - iommu_init_mempool(); - dmar_init_reserved_ranges(); + if (iommu_init_mempool()) { + if (force_on) + panic("tboot: Failed to initialize iommu memory\n"); + return -ENODEV; + } + + if (dmar_init_reserved_ranges()) { + if (force_on) + panic("tboot: Failed to reserve iommu ranges\n"); + return -ENODEV; + } init_no_remapping_devices(); - ret = init_dmars(); + ret = init_dmars(force_on); if (ret) { if (force_on) panic("tboot: Failed to initialize DMARs\n"); -- cgit v1.2.2 From b3258ff1d6086bd2b9eeb556844a868ad7d49bc8 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Wed, 16 Mar 2011 19:12:10 +0530 Subject: virtio: Decrement avail idx on buffer detach When detaching a buffer from a vq, the avail.idx value should be decremented as well. This was noticed by hot-unplugging a virtio console port and then plugging in a new one on the same number (re-using the vqs which were just 'disowned'). qemu reported 'Guest moved used index from 0 to 256' when any IO was attempted on the new port. CC: stable@kernel.org Reported-by: juzhang Signed-off-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/virtio/virtio_ring.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index cc2f73e03475..b0043fb26a4d 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -371,6 +371,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq) /* detach_buf clears data, so grab it now. */ buf = vq->data[i]; detach_buf(vq, i); + vq->vring.avail->idx--; END_USE(vq); return buf; } -- cgit v1.2.2 From 31a3ddda166cda86d2b5111e09ba4bda5239fae6 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 14 Mar 2011 17:45:02 +0530 Subject: virtio_pci: Prevent double-free of pci regions after device hot-unplug In the case where a virtio-console port is in use (opened by a program) and a virtio-console device is removed, the port is kept around but all the virtio-related state is assumed to be gone. When the port is finally released (close() called), we call device_destroy() on the port's device. This results in the parent device's structures to be freed as well. This includes the PCI regions for the virtio-console PCI device. Once this is done, however, virtio_pci_release_dev() kicks in, as the last ref to the virtio device is now gone, and attempts to do pci_iounmap(pci_dev, vp_dev->ioaddr); pci_release_regions(pci_dev); pci_disable_device(pci_dev); which results in a double-free warning. Move the code that releases regions, etc., to the virtio_pci_remove() function, and all that's now left in release_dev is the final freeing of the vp_dev. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/virtio/virtio_pci.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 4fb5b2bf2348..4bcc8b82640b 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -590,15 +590,10 @@ static struct virtio_config_ops virtio_pci_config_ops = { static void virtio_pci_release_dev(struct device *_d) { - struct virtio_device *dev = container_of(_d, struct virtio_device, dev); + struct virtio_device *dev = container_of(_d, struct virtio_device, + dev); struct virtio_pci_device *vp_dev = to_vp_device(dev); - struct pci_dev *pci_dev = vp_dev->pci_dev; - vp_del_vqs(dev); - pci_set_drvdata(pci_dev, NULL); - pci_iounmap(pci_dev, vp_dev->ioaddr); - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); kfree(vp_dev); } @@ -681,6 +676,12 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); unregister_virtio_device(&vp_dev->vdev); + + vp_del_vqs(&vp_dev->vdev); + pci_set_drvdata(pci_dev, NULL); + pci_iounmap(pci_dev, vp_dev->ioaddr); + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); } #ifdef CONFIG_PM -- cgit v1.2.2 From afa2689e19073cd2e762d0f2c1358fab1ab9f18c Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 14 Mar 2011 17:45:48 +0530 Subject: virtio: console: Enable call to hvc_remove() on console port remove This call was disabled as hot-unplugging one virtconsole port led to another virtconsole port freezing. Upon testing it again, this now works, so enable it. In addition, a bug was found in qemu wherein removing a port of one type caused the guest output from another port to stop working. I doubt it was just this bug that caused it (since disabling the hvc_remove() call did allow other ports to continue working), but since it's all solved now, we're fine with hot-unplugging of virtconsole ports. Signed-off-by: Amit Shah Signed-off-by: Rusty Russell --- drivers/char/virtio_console.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 84b164d1eb2b..838568a7dbf5 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1280,18 +1280,7 @@ static void unplug_port(struct port *port) spin_lock_irq(&pdrvdata_lock); list_del(&port->cons.list); spin_unlock_irq(&pdrvdata_lock); -#if 0 - /* - * hvc_remove() not called as removing one hvc port - * results in other hvc ports getting frozen. - * - * Once this is resolved in hvc, this functionality - * will be enabled. Till that is done, the -EPIPE - * return from get_chars() above will help - * hvc_console.c to clean up on ports we remove here. - */ hvc_remove(port->cons.hvc); -#endif } /* Remove unused data this port might have received. */ -- cgit v1.2.2 From d76c8420c3cf8e468901b0bd58306637335c98ea Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 21 Apr 2011 09:07:26 -0700 Subject: raid5: fix build error, sector_t usage Change from unsigned long long to sector_t. This matches its source field. ERROR: "__udivdi3" [drivers/md/raid456.ko] undefined! Signed-off-by: Randy Dunlap Signed-off-by: Linus Torvalds --- drivers/md/raid5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index fd500112f13e..49bf5f891435 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5678,7 +5678,7 @@ static void raid5_quiesce(mddev_t *mddev, int state) static void *raid45_takeover_raid0(mddev_t *mddev, int level) { struct raid0_private_data *raid0_priv = mddev->private; - unsigned long long sectors; + sector_t sectors; /* for raid0 takeover only one zone is supported */ if (raid0_priv->nr_strip_zones > 1) { -- cgit v1.2.2 From 7eec77a1816a7042591a6cbdb4820e9e7ebffe0e Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 21 Apr 2011 19:43:59 +0200 Subject: ide: unexport DISK_EVENT_MEDIA_CHANGE for ide-gd and ide-cd check_events() implementations in both ide-gd and ide-cd are inadequate for in-kernel event polling. Both generate media change events continuously when certain conditions are met causing infinite event loop between the driver and userland event handler. As disk event now supports suppression of unlisted events, simply de-listing DISK_EVENT_MEDIA_CHANGE from disk->events resolves the problem. Internal handling around media revalidation will behave the same while userland will fall back to userland event polling after detecting the device doesn't support disk events. Signed-off-by: Tejun Heo Reported-by: Jens Axboe Acked-by: "David S. Miller" Signed-off-by: Jens Axboe --- drivers/ide/ide-cd.c | 1 - drivers/ide/ide-cd_ioctl.c | 6 ++++++ drivers/ide/ide-gd.c | 7 ++++++- 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index fd1e11799137..a5ec5a7cb381 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1782,7 +1782,6 @@ static int ide_cd_probe(ide_drive_t *drive) ide_cd_read_toc(drive, &sense); g->fops = &idecd_ops; g->flags |= GENHD_FL_REMOVABLE; - g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c index 2a6bc50e8a41..02caa7dd51c8 100644 --- a/drivers/ide/ide-cd_ioctl.c +++ b/drivers/ide/ide-cd_ioctl.c @@ -79,6 +79,12 @@ int ide_cdrom_drive_status(struct cdrom_device_info *cdi, int slot_nr) return CDS_DRIVE_NOT_READY; } +/* + * ide-cd always generates media changed event if media is missing, which + * makes it impossible to use for proper event reporting, so disk->events + * is cleared to 0 and the following function is used only to trigger + * revalidation and never propagated to userland. + */ unsigned int ide_cdrom_check_events_real(struct cdrom_device_info *cdi, unsigned int clearing, int slot_nr) { diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c index c4ffd4888939..70ea8763567d 100644 --- a/drivers/ide/ide-gd.c +++ b/drivers/ide/ide-gd.c @@ -298,6 +298,12 @@ static unsigned int ide_gd_check_events(struct gendisk *disk, return 0; } + /* + * The following is used to force revalidation on the first open on + * removeable devices, and never gets reported to userland as + * genhd->events is 0. This is intended as removeable ide disk + * can't really detect MEDIA_CHANGE events. + */ ret = drive->dev_flags & IDE_DFLAG_MEDIA_CHANGED; drive->dev_flags &= ~IDE_DFLAG_MEDIA_CHANGED; @@ -413,7 +419,6 @@ static int ide_gd_probe(ide_drive_t *drive) if (drive->dev_flags & IDE_DFLAG_REMOVABLE) g->flags = GENHD_FL_REMOVABLE; g->fops = &ide_gd_ops; - g->events = DISK_EVENT_MEDIA_CHANGE; add_disk(g); return 0; -- cgit v1.2.2 From e2a85aecebc03d165bc2dcd233deadd5dd97ea9f Mon Sep 17 00:00:00 2001 From: Andrea Galbusera Date: Thu, 21 Apr 2011 02:21:21 +0000 Subject: powerpc: Fix multicast problem in fs_enet driver mac-fec.c was setting individual UDP address registers instead of multicast group address registers when joining a multicast group. This prevented from correctly receiving UDP multicast packets. According to datasheet, replaced hash_table_high and hash_table_low with grp_hash_table_high and grp_hash_table_low respectively. Also renamed hash_table_* with grp_hash_table_* in struct fec declaration for 8xx: these registers are used only for multicast there. Tested on a MPC5121 based board. Build tested also against mpc866_ads_defconfig. Signed-off-by: Andrea Galbusera Signed-off-by: David S. Miller --- drivers/net/fs_enet/mac-fec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 61035fc5599b..b9fbc83d64a7 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -226,8 +226,8 @@ static void set_multicast_finish(struct net_device *dev) } FC(fecp, r_cntrl, FEC_RCNTRL_PROM); - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); } static void set_multicast_list(struct net_device *dev) @@ -273,8 +273,8 @@ static void restart(struct net_device *dev) /* * Reset all multicast. */ - FW(fecp, hash_table_high, fep->fec.hthi); - FW(fecp, hash_table_low, fep->fec.htlo); + FW(fecp, grp_hash_table_high, fep->fec.hthi); + FW(fecp, grp_hash_table_low, fep->fec.htlo); /* * Set maximum receive buffer size. -- cgit v1.2.2 From e74fbd030223e29d269f4be17e3dce6de38f4c28 Mon Sep 17 00:00:00 2001 From: Ivan Vecera Date: Thu, 21 Apr 2011 00:20:04 +0000 Subject: be2net: increment work_counter in be_worker The commit 609ff3b ("be2net: add code to display temperature of ASIC") adds support to display temperature of ASIC but there is missing increment of work_counter in be_worker. Because of this 1) the function be_cmd_get_die_temperature is called every 1 second instead of every 32 seconds 2) be_cmd_get_die_temperature is called, although it is not supported. This patch fixes this bug. Signed-off-by: Ivan Vecera Signed-off-by: David S. Miller --- drivers/net/benet/be_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 7cb5a114c733..02a0443d1821 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1873,6 +1873,7 @@ static void be_worker(struct work_struct *work) be_detect_dump_ue(adapter); reschedule: + adapter->work_counter++; schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000)); } -- cgit v1.2.2 From cb771838715b1c470bc5735bdae709b33b18e0ad Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Wed, 20 Apr 2011 09:00:49 +0000 Subject: atl1c: Fix work event interrupt/task races The mechanism used to initiate work events from the interrupt handler has a classic read/modify/write race between the interrupt handler that sets the condition, and the worker task that reads and clears the condition. Close these races by using atomic bit fields. Cc: stable@kernel.org Cc: Jie Yang Signed-off-by: Tim Gardner Signed-off-by: David S. Miller --- drivers/net/atl1c/atl1c.h | 6 +++--- drivers/net/atl1c/atl1c_main.c | 14 +++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h index 7cb375e0e29c..925929d764ca 100644 --- a/drivers/net/atl1c/atl1c.h +++ b/drivers/net/atl1c/atl1c.h @@ -566,9 +566,9 @@ struct atl1c_adapter { #define __AT_TESTING 0x0001 #define __AT_RESETTING 0x0002 #define __AT_DOWN 0x0003 - u8 work_event; -#define ATL1C_WORK_EVENT_RESET 0x01 -#define ATL1C_WORK_EVENT_LINK_CHANGE 0x02 + unsigned long work_event; +#define ATL1C_WORK_EVENT_RESET 0 +#define ATL1C_WORK_EVENT_LINK_CHANGE 1 u32 msg_enable; bool have_msi; diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index 7d9d5067a65c..a6e1c36e48e6 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -325,7 +325,7 @@ static void atl1c_link_chg_event(struct atl1c_adapter *adapter) } } - adapter->work_event |= ATL1C_WORK_EVENT_LINK_CHANGE; + set_bit(ATL1C_WORK_EVENT_LINK_CHANGE, &adapter->work_event); schedule_work(&adapter->common_task); } @@ -337,20 +337,16 @@ static void atl1c_common_task(struct work_struct *work) adapter = container_of(work, struct atl1c_adapter, common_task); netdev = adapter->netdev; - if (adapter->work_event & ATL1C_WORK_EVENT_RESET) { - adapter->work_event &= ~ATL1C_WORK_EVENT_RESET; + if (test_and_clear_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event)) { netif_device_detach(netdev); atl1c_down(adapter); atl1c_up(adapter); netif_device_attach(netdev); - return; } - if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) { - adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE; + if (test_and_clear_bit(ATL1C_WORK_EVENT_LINK_CHANGE, + &adapter->work_event)) atl1c_check_link_status(adapter); - } - return; } @@ -369,7 +365,7 @@ static void atl1c_tx_timeout(struct net_device *netdev) struct atl1c_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ - adapter->work_event |= ATL1C_WORK_EVENT_RESET; + set_bit(ATL1C_WORK_EVENT_RESET, &adapter->work_event); schedule_work(&adapter->common_task); } -- cgit v1.2.2 From 2955caed8b9865c1f04fcde6bd7103d5d5ec9415 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 21 Apr 2011 14:15:59 +0200 Subject: HID: hid-multitouch: refactor last_field_index the current implementation requires the devices to report HID_DG_CONTACTCOUNT to set the last_field_index value. However, devices reporting in serial mode (DWAV and PenMount) do not send this field. Other devices (3M) add other fields in the reports descriptor that are not multitouch related at the end, thus the need to add a special case in the default case when handling events. A first work around has been set up but with PenMount devices, we have reached the limit. The idea is to calculate the last_field_index by relying only on multitouch fields the device send. This allows us to remove the handling of non-multitouch events in hid-multitouch, and guarantee that the function mt_emit_event is always called. Signed-off-by: Benjamin Tissoires Reviewed-and-tested-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 0175f8583095..6005e7888b14 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -210,6 +210,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, /* touchscreen emulation */ set_abs(hi->input, ABS_X, field, cls->sn_move); td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_GD_Y: if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) @@ -221,6 +222,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, /* touchscreen emulation */ set_abs(hi->input, ABS_Y, field, cls->sn_move); td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; } return 0; @@ -229,18 +231,22 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, switch (usage->hid) { case HID_DG_INRANGE: td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_DG_CONFIDENCE: td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_DG_TIPSWITCH: hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH); td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_DG_CONTACTID: input_mt_init_slots(hi->input, td->maxcontacts); td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, @@ -248,6 +254,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, @@ -257,6 +264,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_DG_TIPPRESSURE: if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) @@ -269,13 +277,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, set_abs(hi->input, ABS_PRESSURE, field, cls->sn_pressure); td->last_slot_field = usage->hid; + td->last_field_index = field->index; return 1; case HID_DG_CONTACTCOUNT: - td->last_field_index = field->report->maxfield - 1; + td->last_field_index = field->index; return 1; case HID_DG_CONTACTMAX: /* we don't set td->last_slot_field as contactcount and * contact max are global to the report */ + td->last_field_index = field->index; return -1; } /* let hid-input decide for the others */ @@ -424,23 +434,12 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, break; default: - if (td->last_field_index - && field->index == td->last_field_index) - /* we reach here when the last field in the - * report is not related to multitouch. - * This is not good. As a temporary solution, - * we trigger our mt event completion and - * ignore the field. - */ - break; /* fallback to the generic hidinput handling */ return 0; } if (usage->hid == td->last_slot_field) { mt_complete_slot(td); - if (!td->last_field_index) - mt_emit_event(td, field->hidinput->input); } if (field->index == td->last_field_index -- cgit v1.2.2 From 6ab3a9a63fc16b04f7de48eb0190d516dd7574df Mon Sep 17 00:00:00 2001 From: John Sung Date: Thu, 21 Apr 2011 16:21:52 +0200 Subject: HID: hid-multitouch: add support for PenMount dual-touch panel This patch adds PenMount support to hid-multitouch. A new class MT_CLS_CONFIDENCE is defined for PenMount, since it uses HID_DG_CONFIDENCE as the valid flag. Signed-off-by: John Sung [benjamin.tissoires@enac.fr: rebased on top of last_index_field changes] Signed-off-by: Benjamin Tissoires Acked-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 8 ++++++++ 4 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 996ae3ac3244..8058cf1ba83c 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -313,6 +313,7 @@ config HID_MULTITOUCH - Cypress TrueTouch panels - Hanvon dual touch panels - IrTouch Infrared USB panels + - PenMount dual touch panels - Pixcir dual touch panels - 'Sensing Win7-TwoFinger' panel by GeneralTouch - eGalax dual-touch panels, including the diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d66269ed7d..6e31b9f93329 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1438,6 +1438,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) }, { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) }, { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d485894ff4db..252aebae5701 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -484,6 +484,9 @@ #define USB_VENDOR_ID_PANTHERLORD 0x0810 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 +#define USB_VENDOR_ID_PENMOUNT 0x14e1 +#define USB_DEVICE_ID_PENMOUNT_PCI 0x3500 + #define USB_VENDOR_ID_PETALYNX 0x18b1 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6005e7888b14..51b5d272458f 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -89,6 +89,7 @@ struct mt_class { #define MT_CLS_EGALAX 5 #define MT_CLS_STANTUM 6 #define MT_CLS_3M 7 +#define MT_CLS_CONFIDENCE 8 #define MT_DEFAULT_MAXCONTACT 10 @@ -156,6 +157,8 @@ struct mt_class mt_classes[] = { .sn_move = 2048, .sn_width = 128, .sn_height = 128 }, + { .name = MT_CLS_CONFIDENCE, + .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, { } }; @@ -584,6 +587,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, + /* PenMount panels */ + { .driver_data = MT_CLS_CONFIDENCE, + HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, + USB_DEVICE_ID_PENMOUNT_PCI) }, + /* PixCir-based panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, HID_USB_DEVICE(USB_VENDOR_ID_HANVON, -- cgit v1.2.2 From 4a6ee685fbcba4a440cf86f41557752ba81e2ccf Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 22 Apr 2011 11:51:48 +0200 Subject: HID: hid-multitouch: merge hid-mosart into hid-multitouch This patch include MosArt devices into hid-multitouch. MosArt devices now support mt-protocol B. We also need to introduce a new quirk for mosart devices to support their contactID. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 7 +- drivers/hid/Makefile | 1 - drivers/hid/hid-mosart.c | 296 ------------------------------------------- drivers/hid/hid-multitouch.c | 20 ++- 4 files changed, 20 insertions(+), 304 deletions(-) delete mode 100644 drivers/hid/hid-mosart.c (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 8058cf1ba83c..d2d4e5f1911e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -288,12 +288,6 @@ config HID_MICROSOFT ---help--- Support for Microsoft devices that are not fully compliant with HID standard. -config HID_MOSART - tristate "MosArt dual-touch panels" - depends on USB_HID - ---help--- - Support for MosArt dual-touch panels. - config HID_MONTEREY tristate "Monterey Genius KB29E keyboard" if EXPERT depends on USB_HID @@ -313,6 +307,7 @@ config HID_MULTITOUCH - Cypress TrueTouch panels - Hanvon dual touch panels - IrTouch Infrared USB panels + - MosArt dual-touch panels - PenMount dual touch panels - Pixcir dual touch panels - 'Sensing Win7-TwoFinger' panel by GeneralTouch diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 11c9f0b127e1..f8cc4ea7335a 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -45,7 +45,6 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o -obj-$(CONFIG_HID_MOSART) += hid-mosart.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c deleted file mode 100644 index aed7ffe36283..000000000000 --- a/drivers/hid/hid-mosart.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * HID driver for the multitouch panel on the ASUS EeePC T91MT - * - * Copyright (c) 2009-2010 Stephane Chatty - * Copyright (c) 2010 Teemu Tuominen - * - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include -#include -#include -#include -#include -#include "usbhid/usbhid.h" - -MODULE_AUTHOR("Stephane Chatty "); -MODULE_DESCRIPTION("MosArt dual-touch panel"); -MODULE_LICENSE("GPL"); - -#include "hid-ids.h" - -struct mosart_data { - __u16 x, y; - __u8 id; - bool valid; /* valid finger data, or just placeholder? */ - bool first; /* is this the first finger in this frame? */ - bool activity_now; /* at least one active finger in this frame? */ - bool activity; /* at least one active finger previously? */ -}; - -static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_GENDESK: - switch (usage->hid) { - case HID_GD_X: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_X); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_X, - field->logical_minimum, - field->logical_maximum, 0, 0); - return 1; - case HID_GD_Y: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_POSITION_Y); - /* touchscreen emulation */ - input_set_abs_params(hi->input, ABS_Y, - field->logical_minimum, - field->logical_maximum, 0, 0); - return 1; - } - return 0; - - case HID_UP_DIGITIZER: - switch (usage->hid) { - case HID_DG_CONFIDENCE: - case HID_DG_TIPSWITCH: - case HID_DG_INPUTMODE: - case HID_DG_DEVICEINDEX: - case HID_DG_CONTACTCOUNT: - case HID_DG_CONTACTMAX: - case HID_DG_TIPPRESSURE: - case HID_DG_WIDTH: - case HID_DG_HEIGHT: - return -1; - case HID_DG_INRANGE: - /* touchscreen emulation */ - hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); - return 1; - - case HID_DG_CONTACTID: - hid_map_usage(hi, usage, bit, max, - EV_ABS, ABS_MT_TRACKING_ID); - return 1; - - } - return 0; - - case 0xff000000: - /* ignore HID features */ - return -1; - - case HID_UP_BUTTON: - /* ignore buttons */ - return -1; - } - - return 0; -} - -static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - if (usage->type == EV_KEY || usage->type == EV_ABS) - clear_bit(usage->code, *bit); - - return 0; -} - -/* - * this function is called when a whole finger has been parsed, - * so that it can decide what to send to the input layer. - */ -static void mosart_filter_event(struct mosart_data *td, struct input_dev *input) -{ - td->first = !td->first; /* touchscreen emulation */ - - if (!td->valid) { - /* - * touchscreen emulation: if no finger in this frame is valid - * and there previously was finger activity, this is a release - */ - if (!td->first && !td->activity_now && td->activity) { - input_event(input, EV_KEY, BTN_TOUCH, 0); - td->activity = false; - } - return; - } - - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id); - input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x); - input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y); - - input_mt_sync(input); - td->valid = false; - - /* touchscreen emulation: if first active finger in this frame... */ - if (!td->activity_now) { - /* if there was no previous activity, emit touch event */ - if (!td->activity) { - input_event(input, EV_KEY, BTN_TOUCH, 1); - td->activity = true; - } - td->activity_now = true; - /* and in any case this is our preferred finger */ - input_event(input, EV_ABS, ABS_X, td->x); - input_event(input, EV_ABS, ABS_Y, td->y); - } -} - - -static int mosart_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - struct mosart_data *td = hid_get_drvdata(hid); - - if (hid->claimed & HID_CLAIMED_INPUT) { - struct input_dev *input = field->hidinput->input; - switch (usage->hid) { - case HID_DG_INRANGE: - td->valid = !!value; - break; - case HID_GD_X: - td->x = value; - break; - case HID_GD_Y: - td->y = value; - mosart_filter_event(td, input); - break; - case HID_DG_CONTACTID: - td->id = value; - break; - case HID_DG_CONTACTCOUNT: - /* touch emulation: this is the last field in a frame */ - td->first = false; - td->activity_now = false; - break; - case HID_DG_CONFIDENCE: - case HID_DG_TIPSWITCH: - /* avoid interference from generic hidinput handling */ - break; - - default: - /* fallback to the generic hidinput handling */ - return 0; - } - } - - /* we have handled the hidinput part, now remains hiddev */ - if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event) - hid->hiddev_hid_event(hid, field, usage, value); - - return 1; -} - -static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - int ret; - struct mosart_data *td; - - - td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL); - if (!td) { - hid_err(hdev, "cannot allocate MosArt data\n"); - return -ENOMEM; - } - td->valid = false; - td->activity = false; - td->activity_now = false; - td->first = false; - hid_set_drvdata(hdev, td); - - /* currently, it's better to have one evdev device only */ -#if 0 - hdev->quirks |= HID_QUIRK_MULTI_INPUT; -#endif - - ret = hid_parse(hdev); - if (ret == 0) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - - if (ret == 0) { - struct hid_report_enum *re = hdev->report_enum - + HID_FEATURE_REPORT; - struct hid_report *r = re->report_id_hash[7]; - - r->field[0]->value[0] = 0x02; - usbhid_submit_report(hdev, r, USB_DIR_OUT); - } else - kfree(td); - - return ret; -} - -#ifdef CONFIG_PM -static int mosart_reset_resume(struct hid_device *hdev) -{ - struct hid_report_enum *re = hdev->report_enum - + HID_FEATURE_REPORT; - struct hid_report *r = re->report_id_hash[7]; - - r->field[0]->value[0] = 0x02; - usbhid_submit_report(hdev, r, USB_DIR_OUT); - return 0; -} -#endif - -static void mosart_remove(struct hid_device *hdev) -{ - hid_hw_stop(hdev); - kfree(hid_get_drvdata(hdev)); - hid_set_drvdata(hdev, NULL); -} - -static const struct hid_device_id mosart_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, - { } -}; -MODULE_DEVICE_TABLE(hid, mosart_devices); - -static const struct hid_usage_id mosart_grabbed_usages[] = { - { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, - { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} -}; - -static struct hid_driver mosart_driver = { - .name = "mosart", - .id_table = mosart_devices, - .probe = mosart_probe, - .remove = mosart_remove, - .input_mapping = mosart_input_mapping, - .input_mapped = mosart_input_mapped, - .usage_table = mosart_grabbed_usages, - .event = mosart_event, -#ifdef CONFIG_PM - .reset_resume = mosart_reset_resume, -#endif -}; - -static int __init mosart_init(void) -{ - return hid_register_driver(&mosart_driver); -} - -static void __exit mosart_exit(void) -{ - hid_unregister_driver(&mosart_driver); -} - -module_init(mosart_init); -module_exit(mosart_exit); - diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 51b5d272458f..bf46804670c7 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -50,6 +50,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_VALID_IS_INRANGE (1 << 4) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) #define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6) +#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 7) struct mt_slot { __s32 x, y, p, w, h; @@ -90,6 +91,7 @@ struct mt_class { #define MT_CLS_STANTUM 6 #define MT_CLS_3M 7 #define MT_CLS_CONFIDENCE 8 +#define MT_CLS_CONFIDENCE_MINUS_ONE 9 #define MT_DEFAULT_MAXCONTACT 10 @@ -140,7 +142,9 @@ struct mt_class mt_classes[] = { .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | MT_QUIRK_CYPRESS, .maxcontacts = 10 }, - + { .name = MT_CLS_CONFIDENCE_MINUS_ONE, + .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | + MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, { .name = MT_CLS_EGALAX, .quirks = MT_QUIRK_SLOT_IS_CONTACTID | MT_QUIRK_VALID_IS_INRANGE | @@ -325,6 +329,9 @@ static int mt_compute_slot(struct mt_device *td) if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER) return td->num_received; + if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) + return td->curdata.contactid - 1; + return find_slot_from_contactid(td); } @@ -587,6 +594,17 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, + /* MosArt panels */ + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + HID_USB_DEVICE(USB_VENDOR_ID_ASUS, + USB_DEVICE_ID_ASUS_T91MT)}, + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + HID_USB_DEVICE(USB_VENDOR_ID_ASUS, + USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) }, + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, + USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, + /* PenMount panels */ { .driver_data = MT_CLS_CONFIDENCE, HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, -- cgit v1.2.2 From 13f172ff26563995049abe73f6eeba828de3c09d Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 22 Apr 2011 08:10:59 +0000 Subject: netconsole: fix deadlock when removing net driver that netconsole is using (v2) A deadlock was reported to me recently that occured when netconsole was being used in a virtual guest. If the virtio_net driver was removed while netconsole was setup to use an interface that was driven by that driver, the guest deadlocked. No backtrace was provided because netconsole was the only console configured, but it became clear pretty quickly what the problem was. In netconsole_netdev_event, if we get an unregister event, we call __netpoll_cleanup with the target_list_lock held and irqs disabled. __netpoll_cleanup can, if pending netpoll packets are waiting call cancel_delayed_work_sync, which is a sleeping path. the might_sleep call in that path gets triggered, causing a console warning to be issued. The netconsole write handler of course tries to take the target_list_lock again, which we already hold, causing deadlock. The fix is pretty striaghtforward. Simply drop the target_list_lock and re-enable irqs prior to calling __netpoll_cleanup, the re-acquire the lock, and restart the loop. Confirmed by myself to fix the problem reported. Signed-off-by: Neil Horman CC: "David S. Miller" Signed-off-by: David S. Miller --- drivers/net/netconsole.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index dfb67eb2a94b..eb41e44921e6 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -671,6 +671,7 @@ static int netconsole_netdev_event(struct notifier_block *this, goto done; spin_lock_irqsave(&target_list_lock, flags); +restart: list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->np.dev == dev) { @@ -683,9 +684,16 @@ static int netconsole_netdev_event(struct notifier_block *this, * rtnl_lock already held */ if (nt->np.dev) { + spin_unlock_irqrestore( + &target_list_lock, + flags); __netpoll_cleanup(&nt->np); + spin_lock_irqsave(&target_list_lock, + flags); dev_put(nt->np.dev); nt->np.dev = NULL; + netconsole_target_put(nt); + goto restart; } /* Fall through */ case NETDEV_GOING_DOWN: -- cgit v1.2.2 From e39aece7d41119c3d63f390420e00ab4d2a526a9 Mon Sep 17 00:00:00 2001 From: Vladislav Zolotarov Date: Sat, 23 Apr 2011 07:44:46 +0000 Subject: bnx2x: fix UDP csum offload Fixed packets parameters for FW in UDP checksum offload flow. Do not dereference TCP headers on non TCP frames. Reported-by: Eric Dumazet Signed-off-by: Dmitry Kravkov Signed-off-by: Eilon Greenstein Signed-off-by: David S. Miller --- drivers/net/bnx2x/bnx2x_cmn.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index e83ac6dd6fc0..16581df5ee4e 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -2019,15 +2019,23 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, u32 *parsing_data, u32 xmit_type) { - *parsing_data |= ((tcp_hdrlen(skb)/4) << - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; + *parsing_data |= + ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) << + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; - *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) << - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & - ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; + if (xmit_type & XMIT_CSUM_TCP) { + *parsing_data |= ((tcp_hdrlen(skb) / 4) << + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; - return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + } else + /* We support checksum offload for TCP and UDP only. + * No need to pass the UDP header length - it's a constant. + */ + return skb_transport_header(skb) + + sizeof(struct udphdr) - skb->data; } /** @@ -2043,7 +2051,7 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, struct eth_tx_parse_bd_e1x *pbd, u32 xmit_type) { - u8 hlen = (skb_network_header(skb) - skb->data) / 2; + u8 hlen = (skb_network_header(skb) - skb->data) >> 1; /* for now NS flag is not used in Linux */ pbd->global_data = @@ -2051,9 +2059,15 @@ static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT)); pbd->ip_hlen_w = (skb_transport_header(skb) - - skb_network_header(skb)) / 2; + skb_network_header(skb)) >> 1; - hlen += pbd->ip_hlen_w + tcp_hdrlen(skb) / 2; + hlen += pbd->ip_hlen_w; + + /* We support checksum offload for TCP and UDP only */ + if (xmit_type & XMIT_CSUM_TCP) + hlen += tcp_hdrlen(skb) / 2; + else + hlen += sizeof(struct udphdr) / 2; pbd->total_hlen_w = cpu_to_le16(hlen); hlen = hlen*2; -- cgit v1.2.2 From 6e5fe5b12cfcd9ed4303c9a4f4a22a694104d28f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 4 Mar 2011 09:54:52 +0100 Subject: ahci: EM supported message type sysfs attribute This patch adds an sysfs attribute 'em_message_supported' to the ahci host device which prints out the supported enclosure management message types. Signed-off-by: Hannes Reinecke Signed-off-by: Jeff Garzik --- drivers/ata/ahci.h | 4 ++++ drivers/ata/libahci.c | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 39865009c251..12c5282e7fca 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -229,6 +229,10 @@ enum { EM_CTL_ALHD = (1 << 26), /* Activity LED */ EM_CTL_XMT = (1 << 25), /* Transmit Only */ EM_CTL_SMB = (1 << 24), /* Single Message Buffer */ + EM_CTL_SGPIO = (1 << 19), /* SGPIO messages supported */ + EM_CTL_SES = (1 << 18), /* SES-2 messages supported */ + EM_CTL_SAFTE = (1 << 17), /* SAF-TE messages supported */ + EM_CTL_LED = (1 << 16), /* LED messages supported */ /* em message type */ EM_MSG_TYPE_LED = (1 << 0), /* LED */ diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 26d452339e98..633159b5152a 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -109,6 +109,8 @@ static ssize_t ahci_read_em_buffer(struct device *dev, static ssize_t ahci_store_em_buffer(struct device *dev, struct device_attribute *attr, const char *buf, size_t size); +static ssize_t ahci_show_em_supported(struct device *dev, + struct device_attribute *attr, char *buf); static DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL); static DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL); @@ -116,6 +118,7 @@ static DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL); static DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL); static DEVICE_ATTR(em_buffer, S_IWUSR | S_IRUGO, ahci_read_em_buffer, ahci_store_em_buffer); +static DEVICE_ATTR(em_message_supported, S_IRUGO, ahci_show_em_supported, NULL); struct device_attribute *ahci_shost_attrs[] = { &dev_attr_link_power_management_policy, @@ -126,6 +129,7 @@ struct device_attribute *ahci_shost_attrs[] = { &dev_attr_ahci_host_version, &dev_attr_ahci_port_cmd, &dev_attr_em_buffer, + &dev_attr_em_message_supported, NULL }; EXPORT_SYMBOL_GPL(ahci_shost_attrs); @@ -343,6 +347,24 @@ static ssize_t ahci_store_em_buffer(struct device *dev, return size; } +static ssize_t ahci_show_em_supported(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct ata_port *ap = ata_shost_to_port(shost); + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *mmio = hpriv->mmio; + u32 em_ctl; + + em_ctl = readl(mmio + HOST_EM_CTL); + + return sprintf(buf, "%s%s%s%s\n", + em_ctl & EM_CTL_LED ? "led " : "", + em_ctl & EM_CTL_SAFTE ? "saf-te " : "", + em_ctl & EM_CTL_SES ? "ses-2 " : "", + em_ctl & EM_CTL_SGPIO ? "sgpio " : ""); +} + /** * ahci_save_initial_config - Save and fixup initial config values * @dev: target AHCI device -- cgit v1.2.2 From ae01b2493c3bf03c504c32ac4ebb01d528508db3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 16 Mar 2011 11:14:55 +0100 Subject: libata: Implement ATA_FLAG_NO_DIPM and apply it to mcp65 NVIDIA mcp65 familiy of controllers cause command timeouts when DIPM is used. Implement ATA_FLAG_NO_DIPM and apply it. This problem was reported by Stefan Bader in the following thread. http://thread.gmane.org/gmane.linux.ide/48841 stable: applicable to 2.6.37 and 38. Signed-off-by: Tejun Heo Reported-by: Stefan Bader Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 2 +- drivers/ata/libata-eh.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 39d829cd82dd..cbd38e130f05 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -150,7 +150,7 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ), - .flags = AHCI_FLAG_COMMON, + .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM, .pio_mask = ATA_PIO4, .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 88cd22fa65cd..f26f2fe3480a 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3316,6 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, 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; + bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM; unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; unsigned int err_mask; int rc; @@ -3332,7 +3333,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, */ ata_for_each_dev(dev, link, ENABLED) { bool hipm = ata_id_has_hipm(dev->id); - bool dipm = ata_id_has_dipm(dev->id); + bool dipm = ata_id_has_dipm(dev->id) && !no_dipm; /* find the first enabled and LPM enabled devices */ if (!link_dev) @@ -3389,7 +3390,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_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)) { + if (policy == ATA_LPM_MIN_POWER && !no_dipm && + ata_id_has_dipm(dev->id)) { err_mask = ata_dev_set_feature(dev, SETFEATURES_SATA_ENABLE, SATA_DIPM); if (err_mask && err_mask != AC_ERR_DEV) { -- cgit v1.2.2 From 7b3a24c57d2eeda8dba9c205342b12689c4679f9 Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Wed, 16 Mar 2011 14:58:32 +0100 Subject: ahci: don't enable port irq before handler is registered The ahci_pmp_attach() & ahci_pmp_detach() unmask port irqs, but they are also called during port initialization, before ahci host irq handler is registered. On ce4100 platform, this sometimes triggers "irq 4: nobody cared" message when loading driver. Fixed this by not touching the register if the port is in frozen state, and mark all uninitialized port as frozen. Signed-off-by: Maxime Bizon Acked-by: Tejun Heo Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/libahci.c | 17 +++++++++++++++-- drivers/ata/libata-core.c | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 633159b5152a..d38c40fe4ddb 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1919,7 +1919,17 @@ static void ahci_pmp_attach(struct ata_port *ap) ahci_enable_fbs(ap); pp->intr_mask |= PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + + /* + * We must not change the port interrupt mask register if the + * port is marked frozen, the value in pp->intr_mask will be + * restored later when the port is thawed. + * + * Note that during initialization, the port is marked as + * frozen since the irq handler is not yet registered. + */ + if (!(ap->pflags & ATA_PFLAG_FROZEN)) + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } static void ahci_pmp_detach(struct ata_port *ap) @@ -1935,7 +1945,10 @@ static void ahci_pmp_detach(struct ata_port *ap) writel(cmd, port_mmio + PORT_CMD); pp->intr_mask &= ~PORT_IRQ_BAD_PMP; - writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); + + /* see comment above in ahci_pmp_attach() */ + if (!(ap->pflags & ATA_PFLAG_FROZEN)) + writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK); } int ahci_port_resume(struct ata_port *ap) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 423c0a6952b2..5096b2a24a17 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5480,7 +5480,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) if (!ap) return NULL; - ap->pflags |= ATA_PFLAG_INITIALIZING; + ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN; ap->lock = &host->lock; ap->print_id = -1; ap->host = host; -- cgit v1.2.2 From d69cf28cd2f85c3086fac5ea39aa1d5ba65546b1 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 19 Apr 2011 11:13:32 -0400 Subject: libata: Pioneer DVR-216D can't do SETXFER Commit 4a5610a04d415ed94af75bb1159d2621d62c8328 fixed an issue with the Pioneer DVR-212D not handling SETXFER correctly. An openSUSE user reported a similar issue with his DVR-216D that the NOSETXFER horkage worked around for him as well. This patch adds the DVR-216D (1.08) to the horkage list for NOSETXFER. The issue was reported at: https://bugzilla.novell.com/show_bug.cgi?id=679143 Reported-by: Volodymyr Kyrychenko Signed-off-by: Jeff Mahoney Signed-off-by: Jeff Garzik --- drivers/ata/libata-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 5096b2a24a17..76c3c15cb1e6 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4139,6 +4139,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { */ { "PIONEER DVD-RW DVRTD08", "1.00", ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-212D", "1.28", ATA_HORKAGE_NOSETXFER }, + { "PIONEER DVD-RW DVR-216D", "1.08", ATA_HORKAGE_NOSETXFER }, /* End Marker */ { } -- cgit v1.2.2 From 4a836c701a0f68e5a028113c176413e9b72c4c7c Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 20 Apr 2011 08:43:37 -0700 Subject: ata_piix: IDE-mode SATA patch for Intel Panther Point DeviceIDs The previously submitted patch was word-wrapped. This patch adds the IDE-mode SATA DeviceIDs for the Intel Panther Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik --- drivers/ata/ata_piix.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 0bc3fd6c3fdb..6f6e7718b05c 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -309,6 +309,14 @@ static const struct pci_device_id piix_pci_tbl[] = { { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (PBG) */ { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, + /* SATA Controller IDE (Panther Point) */ + { 0x8086, 0x1e09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { } /* terminate list */ }; -- cgit v1.2.2 From 181e3ceaba761d35d96d791d5031b1e51abec46c Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 20 Apr 2011 08:45:20 -0700 Subject: ahci: AHCI-mode SATA patch for Intel Panther Point DeviceIDs The previously submitted patch was word-wrapped. This patch adds the AHCI-mode SATA DeviceIDs for the Intel Panther Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index cbd38e130f05..71afe0371311 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -261,6 +261,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x1d06), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* PBG RAID */ { PCI_VDEVICE(INTEL, 0x2323), board_ahci }, /* DH89xxCC AHCI */ + { PCI_VDEVICE(INTEL, 0x1e02), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e03), board_ahci }, /* Panther Point AHCI */ + { PCI_VDEVICE(INTEL, 0x1e04), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e05), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e06), board_ahci }, /* Panther Point RAID */ + { PCI_VDEVICE(INTEL, 0x1e07), board_ahci }, /* Panther Point RAID */ /* JMicron 360/1/3/5/6, match class to avoid IDE function */ { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, -- cgit v1.2.2 From 9719b8f5bc35664a23de1ddfbc85217398af0df8 Mon Sep 17 00:00:00 2001 From: Igor Plyatov Date: Mon, 28 Mar 2011 16:56:15 +0400 Subject: ata: pata_at91.c bugfix for high master clock The AT91SAM9 microcontrollers with master clock higher then 105 MHz and PIO0, have overflow of the NCS_RD_PULSE value in the MSB. This lead to "NCS_RD_PULSE" pulse longer then "NRD_CYCLE" pulse and driver does not detect ATA device. Signed-off-by: Igor Plyatov Signed-off-by: Jeff Garzik --- drivers/ata/pata_at91.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index 0da0dcc7dd08..a9a066a18ccf 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -33,11 +33,12 @@ #define DRV_NAME "pata_at91" -#define DRV_VERSION "0.1" +#define DRV_VERSION "0.2" #define CF_IDE_OFFSET 0x00c00000 #define CF_ALT_IDE_OFFSET 0x00e00000 #define CF_IDE_RES_SIZE 0x08 +#define NCS_RD_PULSE_LIMIT 0x3f /* maximal value for pulse bitfields */ struct at91_ide_info { unsigned long mode; @@ -109,6 +110,11 @@ static void set_smc_timing(struct device *dev, /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */ ncs_read_setup = 1; ncs_read_pulse = read_cycle - 2; + if (ncs_read_pulse > NCS_RD_PULSE_LIMIT) { + ncs_read_pulse = NCS_RD_PULSE_LIMIT; + dev_warn(dev, "ncs_read_pulse limited to maximal value %lu\n", + ncs_read_pulse); + } /* Write timings same as read timings */ write_cycle = read_cycle; -- cgit v1.2.2 From 792d37af35386466cf5dda51d6b710fa1dd9aad1 Mon Sep 17 00:00:00 2001 From: Igor Plyatov Date: Mon, 28 Mar 2011 16:56:14 +0400 Subject: ata: pata_at91.c bugfix for initial_timing initialisation The "struct ata_timing" must contain 10 members, but ".dmack_hold" member was forgotten for "initial_timing" initialisation. This patch fixes such a problem. Signed-off-by: Igor Plyatov Signed-off-by: Jeff Garzik --- drivers/ata/pata_at91.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index a9a066a18ccf..a5fdbdcb0faf 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -50,8 +50,18 @@ struct at91_ide_info { void __iomem *alt_addr; }; -static const struct ata_timing initial_timing = - {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; +static const struct ata_timing initial_timing = { + .mode = XFER_PIO_0, + .setup = 70, + .act8b = 290, + .rec8b = 240, + .cyc8b = 600, + .active = 165, + .recover = 150, + .dmack_hold = 0, + .cycle = 600, + .udma = 0 +}; static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz) { -- cgit v1.2.2 From 270dac35c26433d06a89150c51e75ca0181ca7e4 Mon Sep 17 00:00:00 2001 From: Jian Peng Date: Fri, 22 Apr 2011 23:58:10 -0700 Subject: libata: ahci_start_engine compliant to AHCI spec At the end of section 10.1 of AHCI spec (rev 1.3), it states Software shall not set PxCMD.ST to 1 until it is determined that a functoinal device is present on the port as determined by PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h Even though most AHCI host controller works without this check, specific controller will fail under this condition. Signed-off-by: Jian Peng Signed-off-by: Jeff Garzik --- drivers/ata/libahci.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index d38c40fe4ddb..ff9d832a163d 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -561,6 +561,27 @@ void ahci_start_engine(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; + u8 status; + + status = readl(port_mmio + PORT_TFDATA) & 0xFF; + + /* + * At end of section 10.1 of AHCI spec (rev 1.3), it states + * Software shall not set PxCMD.ST to 1 until it is determined + * that a functoinal device is present on the port as determined by + * PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h + * + * Even though most AHCI host controllers work without this check, + * specific controller will fail under this condition + */ + if (status & (ATA_BUSY | ATA_DRQ)) + return; + else { + ahci_scr_read(&ap->link, SCR_STATUS, &tmp); + + if ((tmp & 0xf) != 0x3) + return; + } /* start DMA */ tmp = readl(port_mmio + PORT_CMD); -- cgit v1.2.2 From 953a12cc2889d1be92e80a2d0bab5ffef4942300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Romieu?= Date: Sun, 24 Apr 2011 17:38:48 +0200 Subject: r8169: don't request firmware when there's no userspace. The firmware is cached during the first successfull call to open() and released once the network device is unregistered. The driver uses the cached firmware between open() and unregister_netdev(). So far the firmware is optional : a failure to load the firmware does not prevent open() to success. It is thus necessary to 1) unregister all 816x / 810[23] devices and 2) force a driver probe to issue a new firmware load. Signed-off-by: Francois Romieu Fixed-by: Ciprian Docan Cc: Realtek linux nic maintainers --- drivers/net/r8169.c | 99 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 493b0de3848b..397c36810a15 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -170,6 +170,16 @@ static const struct { }; #undef _R +static const struct rtl_firmware_info { + int mac_version; + const char *fw_name; +} rtl_firmware_infos[] = { + { .mac_version = RTL_GIGA_MAC_VER_25, .fw_name = FIRMWARE_8168D_1 }, + { .mac_version = RTL_GIGA_MAC_VER_26, .fw_name = FIRMWARE_8168D_2 }, + { .mac_version = RTL_GIGA_MAC_VER_29, .fw_name = FIRMWARE_8105E_1 }, + { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 } +}; + enum cfg_version { RTL_CFG_0 = 0x00, RTL_CFG_1, @@ -565,6 +575,7 @@ struct rtl8169_private { u32 saved_wolopts; const struct firmware *fw; +#define RTL_FIRMWARE_UNKNOWN ERR_PTR(-EAGAIN); }; MODULE_AUTHOR("Realtek and the Linux r8169 crew "); @@ -1789,25 +1800,26 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw) static void rtl_release_firmware(struct rtl8169_private *tp) { - release_firmware(tp->fw); - tp->fw = NULL; + if (!IS_ERR_OR_NULL(tp->fw)) + release_firmware(tp->fw); + tp->fw = RTL_FIRMWARE_UNKNOWN; } -static int rtl_apply_firmware(struct rtl8169_private *tp, const char *fw_name) +static void rtl_apply_firmware(struct rtl8169_private *tp) { - const struct firmware **fw = &tp->fw; - int rc = !*fw; - - if (rc) { - rc = request_firmware(fw, fw_name, &tp->pci_dev->dev); - if (rc < 0) - goto out; - } + const struct firmware *fw = tp->fw; /* TODO: release firmware once rtl_phy_write_fw signals failures. */ - rtl_phy_write_fw(tp, *fw); -out: - return rc; + if (!IS_ERR_OR_NULL(fw)) + rtl_phy_write_fw(tp, fw); +} + +static void rtl_apply_firmware_cond(struct rtl8169_private *tp, u8 reg, u16 val) +{ + if (rtl_readphy(tp, reg) != val) + netif_warn(tp, hw, tp->dev, "chipset not ready for firmware\n"); + else + rtl_apply_firmware(tp); } static void rtl8169s_hw_phy_config(struct rtl8169_private *tp) @@ -2246,10 +2258,8 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xbf00) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_1) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xbf00); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2351,10 +2361,8 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x1f, 0x0005); rtl_writephy(tp, 0x05, 0x001b); - if ((rtl_readphy(tp, 0x06) != 0xb300) || - (rtl_apply_firmware(tp, FIRMWARE_8168D_2) < 0)) { - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); - } + + rtl_apply_firmware_cond(tp, MII_EXPANSION, 0xb300); rtl_writephy(tp, 0x1f, 0x0000); } @@ -2474,8 +2482,7 @@ static void rtl8105e_hw_phy_config(struct rtl8169_private *tp) rtl_writephy(tp, 0x18, 0x0310); msleep(100); - if (rtl_apply_firmware(tp, FIRMWARE_8105E_1) < 0) - netif_warn(tp, probe, tp->dev, "unable to apply firmware patch\n"); + rtl_apply_firmware(tp); rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init)); } @@ -3237,6 +3244,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->timer.data = (unsigned long) dev; tp->timer.function = rtl8169_phy_timer; + tp->fw = RTL_FIRMWARE_UNKNOWN; + rc = register_netdev(dev); if (rc < 0) goto err_out_msi_4; @@ -3288,10 +3297,10 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&tp->task); - rtl_release_firmware(tp); - unregister_netdev(dev); + rtl_release_firmware(tp); + if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); @@ -3303,6 +3312,37 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +static void rtl_request_firmware(struct rtl8169_private *tp) +{ + int i; + + /* Return early if the firmware is already loaded / cached. */ + if (!IS_ERR(tp->fw)) + goto out; + + for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) { + const struct rtl_firmware_info *info = rtl_firmware_infos + i; + + if (info->mac_version == tp->mac_version) { + const char *name = info->fw_name; + int rc; + + rc = request_firmware(&tp->fw, name, &tp->pci_dev->dev); + if (rc < 0) { + netif_warn(tp, ifup, tp->dev, "unable to load " + "firmware patch %s (%d)\n", name, rc); + goto out_disable_request_firmware; + } + goto out; + } + } + +out_disable_request_firmware: + tp->fw = NULL; +out: + return; +} + static int rtl8169_open(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -3334,11 +3374,13 @@ static int rtl8169_open(struct net_device *dev) smp_mb(); + rtl_request_firmware(tp); + retval = request_irq(dev->irq, rtl8169_interrupt, (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED, dev->name, dev); if (retval < 0) - goto err_release_ring_2; + goto err_release_fw_2; napi_enable(&tp->napi); @@ -3359,7 +3401,8 @@ static int rtl8169_open(struct net_device *dev) out: return retval; -err_release_ring_2: +err_release_fw_2: + rtl_release_firmware(tp); rtl8169_rx_clear(tp); err_free_rx_1: dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray, -- cgit v1.2.2 From a1f74ae82d133ebb2aabb19d181944b4e83e9960 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Tue, 5 Apr 2011 12:45:59 -0400 Subject: [SCSI] mpt2sas: prevent heap overflows and unchecked reads At two points in handling device ioctls via /dev/mpt2ctl, user-supplied length values are used to copy data from userspace into heap buffers without bounds checking, allowing controllable heap corruption and subsequently privilege escalation. Additionally, user-supplied values are used to determine the size of a copy_to_user() as well as the offset into the buffer to be read, with no bounds checking, allowing users to read arbitrary kernel memory. Signed-off-by: Dan Rosenberg Cc: stable@kernel.org Acked-by: Eric Moore Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 1c6d2b405eef..d72f1f2b1392 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -688,6 +688,13 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, goto out; } + /* Check for overflow and wraparound */ + if (karg.data_sge_offset * 4 > ioc->request_sz || + karg.data_sge_offset > (UINT_MAX / 4)) { + ret = -EINVAL; + goto out; + } + /* copy in request message frame from user */ if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, @@ -1963,7 +1970,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) Mpi2DiagBufferPostReply_t *mpi_reply; int rc, i; u8 buffer_type; - unsigned long timeleft; + unsigned long timeleft, request_size, copy_size; u16 smid; u16 ioc_status; u8 issue_reset = 0; @@ -1999,6 +2006,8 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -ENOMEM; } + request_size = ioc->diag_buffer_sz[buffer_type]; + if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " "or bytes_to_read are not 4 byte aligned\n", ioc->name, @@ -2006,13 +2015,23 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state) return -EINVAL; } + if (karg.starting_offset > request_size) + return -EINVAL; + diag_data = (void *)(request_data + karg.starting_offset); dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " "offset(%d), sz(%d)\n", ioc->name, __func__, diag_data, karg.starting_offset, karg.bytes_to_read)); + /* Truncate data on requests that are too large */ + if ((diag_data + karg.bytes_to_read < diag_data) || + (diag_data + karg.bytes_to_read > request_data + request_size)) + copy_size = request_size - karg.starting_offset; + else + copy_size = karg.bytes_to_read; + if (copy_to_user((void __user *)uarg->diagnostic_data, - diag_data, karg.bytes_to_read)) { + diag_data, copy_size)) { printk(MPT2SAS_ERR_FMT "%s: Unable to write " "mpt_diag_read_buffer_t data @ %p\n", ioc->name, __func__, diag_data); -- cgit v1.2.2 From 0b8393578c70bc1f09790eeae7d918f38da2e010 Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Fri, 8 Apr 2011 15:05:36 -0400 Subject: [SCSI] scsi_dh: fix reference counting in scsi_dh_activate error path Commit db422318cbca55168cf965f655471dbf8be82433 ([SCSI] scsi_dh: propagate SCSI device deletion) introduced a regression where the device reference is not dropped prior to scsi_dh_activate's early return from the error path. Signed-off-by: Mike Snitzer Cc: stable@kernel.org # 2.6.38 Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 564e6ecd17c2..0119b8147797 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -394,12 +394,14 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) unsigned long flags; struct scsi_device *sdev; struct scsi_device_handler *scsi_dh = NULL; + struct device *dev = NULL; spin_lock_irqsave(q->queue_lock, flags); sdev = q->queuedata; if (sdev && sdev->scsi_dh_data) scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (!scsi_dh || !get_device(&sdev->sdev_gendev) || + dev = get_device(&sdev->sdev_gendev); + if (!scsi_dh || !dev || sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) err = SCSI_DH_NOSYS; @@ -410,12 +412,13 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) if (err) { if (fn) fn(data, err); - return err; + goto out; } if (scsi_dh->activate) err = scsi_dh->activate(sdev, fn, data); - put_device(&sdev->sdev_gendev); +out: + put_device(dev); return err; } EXPORT_SYMBOL_GPL(scsi_dh_activate); -- cgit v1.2.2 From 86cbfb5607d4b81b1a993ff689bbd2addd5d3a9b Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 22 Apr 2011 10:39:59 -0500 Subject: [SCSI] put stricter guards on queue dead checks SCSI uses request_queue->queuedata == NULL as a signal that the queue is dying. We set this state in the sdev release function. However, this allows a small window where we release the last reference but haven't quite got to this stage yet and so something will try to take a reference in scsi_request_fn and oops. It's very rare, but we had a report here, so we're pushing this as a bug fix The actual fix is to set request_queue->queuedata to NULL in scsi_remove_device() before we drop the reference. This causes correct automatic rejects from scsi_request_fn as people who hold additional references try to submit work and prevents anything from getting a new reference to the sdev that way. Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/scsi_sysfs.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index e44ff64233fd..e63912510fb9 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -322,14 +322,8 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) kfree(evt); } - if (sdev->request_queue) { - sdev->request_queue->queuedata = NULL; - /* user context needed to free queue */ - scsi_free_queue(sdev->request_queue); - /* temporary expedient, try to catch use of queue lock - * after free of sdev */ - sdev->request_queue = NULL; - } + /* NULL queue means the device can't be used */ + sdev->request_queue = NULL; scsi_target_reap(scsi_target(sdev)); @@ -937,6 +931,12 @@ void __scsi_remove_device(struct scsi_device *sdev) if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(dev); + + /* cause the request function to reject all I/O requests */ + sdev->request_queue->queuedata = NULL; + + /* Freeing the queue signals to block that we're done */ + scsi_free_queue(sdev->request_queue); put_device(dev); } -- cgit v1.2.2 From 5f6279da3760ce48f478f2856aacebe0c59a39f3 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Tue, 5 Apr 2011 13:27:31 -0400 Subject: [SCSI] pmcraid: reject negative request size There's a code path in pmcraid that can be reached via device ioctl that causes all sorts of ugliness, including heap corruption or triggering the OOM killer due to consecutive allocation of large numbers of pages. Not especially relevant from a security perspective, since users must have CAP_SYS_ADMIN to open the character device. First, the user can call pmcraid_chr_ioctl() with a type PMCRAID_PASSTHROUGH_IOCTL. A pmcraid_passthrough_ioctl_buffer is copied in, and the request_size variable is set to buffer->ioarcb.data_transfer_length, which is an arbitrary 32-bit signed value provided by the user. If a negative value is provided here, bad things can happen. For example, pmcraid_build_passthrough_ioadls() is called with this request_size, which immediately calls pmcraid_alloc_sglist() with a negative size. The resulting math on allocating a scatter list can result in an overflow in the kzalloc() call (if num_elem is 0, the sglist will be smaller than expected), or if num_elem is unexpectedly large the subsequent loop will call alloc_pages() repeatedly, a high number of pages will be allocated and the OOM killer might be invoked. Prevent this value from being negative in pmcraid_ioctl_passthrough(). Signed-off-by: Dan Rosenberg Cc: stable@kernel.org Cc: Anil Ravindranath Signed-off-by: James Bottomley --- drivers/scsi/pmcraid.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 96d5ad0c1e42..7f636b118287 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3814,6 +3814,9 @@ static long pmcraid_ioctl_passthrough( rc = -EFAULT; goto out_free_buffer; } + } else if (request_size < 0) { + rc = -EINVAL; + goto out_free_buffer; } /* check if we have any additional command parameters */ -- cgit v1.2.2 From 8c61d9d611cb5b290f1b4ac57c4631acfd6e3b5a Mon Sep 17 00:00:00 2001 From: Hans Petter Selasky Date: Sun, 24 Apr 2011 22:35:19 -0700 Subject: cdc_ncm: fix short packet issue on some devices The default maximum transmit length for NCM USB frames should be so that a short packet happens at the end if the device supports a length greater than the defined maximum. This is achieved by adding 4 bytes to the maximum length so that the existing logic can fit a short packet there. Signed-off-by: Hans Petter Selasky Signed-off-by: Greg Kroah-Hartman Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ncm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index 967371f04454..1033ef6476a4 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -54,13 +54,13 @@ #include #include -#define DRIVER_VERSION "7-Feb-2011" +#define DRIVER_VERSION "23-Apr-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 /* Maximum NTB length */ -#define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */ +#define CDC_NCM_NTB_MAX_SIZE_TX (16384 + 4) /* bytes, must be short terminated */ #define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */ /* Minimum value for MaxDatagramSize, ch. 6.2.9 */ -- cgit v1.2.2 From 97232fd666f27d1a1cc560adaac446b0bb57f578 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 14:55:11 -0400 Subject: staging: olpc: Add The olpc dcon xo1 driver uses udelay() without including . This patch adds it. Signed-off-by: Jeff Mahoney Signed-off-by: Randy Dunlap Cc: Andres Salomon Signed-off-by: Greg Kroah-Hartman --- drivers/staging/olpc_dcon/olpc_dcon_xo_1.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index b5d21f6497f9..22c04eabed41 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -12,6 +12,7 @@ */ #include #include +#include #include #include "olpc_dcon.h" -- cgit v1.2.2 From 4f80494daa1f9705c3717a02e7d713ea2f874bd0 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 15:32:36 -0400 Subject: staging: gma500: Depend on X86 The gma500 driver calls set_pages_uc, which is an x86 pageattr call. Since this driver is only used with Intel x86 motherboard chipsets, make the driver depend on X86. Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gma500/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/gma500/Kconfig b/drivers/staging/gma500/Kconfig index 5501eb9b3355..ce8bedaeaac2 100644 --- a/drivers/staging/gma500/Kconfig +++ b/drivers/staging/gma500/Kconfig @@ -1,6 +1,6 @@ config DRM_PSB tristate "Intel GMA500 KMS Framebuffer" - depends on DRM && PCI + depends on DRM && PCI && X86 select FB_CFB_COPYAREA select FB_CFB_FILLRECT select FB_CFB_IMAGEBLIT -- cgit v1.2.2 From c6cdaded146875e2e47e946f6592c1775eaee849 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 21:05:07 -0400 Subject: staging: rts_pstor: Add There are a few files in the rts_pstor driver that use vmalloc/vfree without including the header for it. This patch adds to those files. Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts_pstor/ms.c | 1 + drivers/staging/rts_pstor/rtsx_chip.c | 1 + drivers/staging/rts_pstor/rtsx_scsi.c | 1 + drivers/staging/rts_pstor/xd.c | 1 + 4 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c index 810e170894f5..d89795c6a3ac 100644 --- a/drivers/staging/rts_pstor/ms.c +++ b/drivers/staging/rts_pstor/ms.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c index d2f1c715a684..755be436489a 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.c +++ b/drivers/staging/rts_pstor/rtsx_chip.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/rtsx_scsi.c b/drivers/staging/rts_pstor/rtsx_scsi.c index 20c2464a20f9..7de1fae443fc 100644 --- a/drivers/staging/rts_pstor/rtsx_scsi.c +++ b/drivers/staging/rts_pstor/rtsx_scsi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" diff --git a/drivers/staging/rts_pstor/xd.c b/drivers/staging/rts_pstor/xd.c index 7bcd468b8f2c..9f3add1e8f59 100644 --- a/drivers/staging/rts_pstor/xd.c +++ b/drivers/staging/rts_pstor/xd.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "rtsx.h" #include "rtsx_transport.h" -- cgit v1.2.2 From 1035117d2a47583f9539c28bf6ce5f677946e172 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 21:05:33 -0400 Subject: staging: rts_pstor: use #ifdef instead of #if This patch fixes a number of the following warnings: warning: "CONFIG_RTS_PSTOR_DEBUG" is not defined The code uses '#if CONFIG_RTS_PSTOR_DEBUG' when it should be using '#ifdef' Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts_pstor/debug.h | 2 +- drivers/staging/rts_pstor/rtsx_chip.c | 4 ++-- drivers/staging/rts_pstor/sd.c | 4 ++-- drivers/staging/rts_pstor/trace.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rts_pstor/debug.h b/drivers/staging/rts_pstor/debug.h index e1408b0e7ae4..ab305be96fb5 100644 --- a/drivers/staging/rts_pstor/debug.h +++ b/drivers/staging/rts_pstor/debug.h @@ -28,7 +28,7 @@ #define RTSX_STOR "rts_pstor: " -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG #define RTSX_DEBUGP(x...) printk(KERN_DEBUG RTSX_STOR x) #define RTSX_DEBUGPN(x...) printk(KERN_DEBUG x) #define RTSX_DEBUGPX(x...) printk(x) diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c index 755be436489a..4e60780ea804 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.c +++ b/drivers/staging/rts_pstor/rtsx_chip.c @@ -1312,11 +1312,11 @@ void rtsx_polling_func(struct rtsx_chip *chip) #ifdef SUPPORT_OCP if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - #if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER)) { RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n", chip->ocp_stat); } - #endif +#endif if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) { if (chip->card_exist & SD_CARD) { diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c index 8d066bd428c4..b1277a6c7a8b 100644 --- a/drivers/staging/rts_pstor/sd.c +++ b/drivers/staging/rts_pstor/sd.c @@ -909,7 +909,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) RTSX_WRITE_REG(chip, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); RTSX_WRITE_REG(chip, CLK_CTL, CHANGE_CLK, 0); } else { -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG rtsx_read_register(chip, SD_VP_CTL, &val); RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val); rtsx_read_register(chip, SD_DCMPS_CTL, &val); @@ -958,7 +958,7 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) return STATUS_SUCCESS; Fail: -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG rtsx_read_register(chip, SD_VP_CTL, &val); RTSX_DEBUGP("SD_VP_CTL: 0x%x\n", val); rtsx_read_register(chip, SD_DCMPS_CTL, &val); diff --git a/drivers/staging/rts_pstor/trace.h b/drivers/staging/rts_pstor/trace.h index 2c668bae6ff4..bc83b49a4eb4 100644 --- a/drivers/staging/rts_pstor/trace.h +++ b/drivers/staging/rts_pstor/trace.h @@ -82,7 +82,7 @@ do { \ #define TRACE_GOTO(chip, label) goto label #endif -#if CONFIG_RTS_PSTOR_DEBUG +#ifdef CONFIG_RTS_PSTOR_DEBUG static inline void rtsx_dump(u8 *buf, int buf_len) { int i; -- cgit v1.2.2 From 9f908a9eaa94f07265811c59b740a4608d3dfc96 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Tue, 12 Apr 2011 22:57:57 -0400 Subject: staging: ft1000: Remove unnecessary EXPORT_SYMBOLs ft1000-pcmcia uses EXPORT_SYMBOL unnecessarily for sharing symbols inside the same module. For some reason, this is causing section conflicts on ia64 as well, even though neither are static. error: __ksymtab_stop_ft1000_card causes a section type conflict error: __ksymtab_init_ft1000_card causes a section type conflict Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c | 4 ---- drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c | 3 --- 2 files changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c index eeb7dd43f9a8..830822f86e41 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c @@ -2288,7 +2288,3 @@ err_dev: free_netdev(dev); return NULL; } - -EXPORT_SYMBOL(init_ft1000_card); -EXPORT_SYMBOL(stop_ft1000_card); -EXPORT_SYMBOL(flarion_ft1000_cnt); diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c index 935608e72007..bdfb1aec58df 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c @@ -214,6 +214,3 @@ void ft1000CleanupProc(struct net_device *dev) remove_proc_entry(FT1000_PROC, init_net.proc_net); unregister_netdevice_notifier(&ft1000_netdev_notifier); } - -EXPORT_SYMBOL(ft1000InitProc); -EXPORT_SYMBOL(ft1000CleanupProc); -- cgit v1.2.2 From d1b2e95ab016a0c5b01748986f6ce42e9d11cab2 Mon Sep 17 00:00:00 2001 From: Max Vozeler Date: Mon, 18 Apr 2011 21:44:10 +0200 Subject: staging: usbip: vhci: fix oops on subsequent attach vhci_rx/vhci_tx threads are created once but stopped each time the vdev is shut down. On subsequent attach wake_up_process() oopses trying to access the stopped threads. This patch does as before the kthread conversion which is to create the threads each time a device is attached and stop the threads when the device is shut down. Signed-off-by: Max Vozeler Cc: Arnd Bergmann Cc: Takahiro Hirofuchi Cc: Arjan Mels Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/vhci_hcd.c | 9 ++++----- drivers/staging/usbip/vhci_sysfs.c | 7 ++++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 0f02a4b12ae4..14caae279f7e 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -876,8 +876,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud) } /* kill threads related to this sdev, if v.c. exists */ - kthread_stop(vdev->ud.tcp_rx); - kthread_stop(vdev->ud.tcp_tx); + if (vdev->ud.tcp_rx) + kthread_stop(vdev->ud.tcp_rx); + if (vdev->ud.tcp_tx) + kthread_stop(vdev->ud.tcp_tx); usbip_uinfo("stop threads\n"); @@ -949,9 +951,6 @@ static void vhci_device_init(struct vhci_device *vdev) { memset(vdev, 0, sizeof(*vdev)); - vdev->ud.tcp_rx = kthread_create(vhci_rx_loop, &vdev->ud, "vhci_rx"); - vdev->ud.tcp_tx = kthread_create(vhci_tx_loop, &vdev->ud, "vhci_tx"); - vdev->ud.side = USBIP_VHCI; vdev->ud.status = VDEV_ST_NULL; /* vdev->ud.lock = SPIN_LOCK_UNLOCKED; */ diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c index 3f2459f30415..e2dadbd5ef1e 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -21,6 +21,7 @@ #include "vhci.h" #include +#include /* TODO: refine locking ?*/ @@ -220,13 +221,13 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, vdev->ud.tcp_socket = socket; vdev->ud.status = VDEV_ST_NOTASSIGNED; - wake_up_process(vdev->ud.tcp_rx); - wake_up_process(vdev->ud.tcp_tx); - spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); /* end the lock */ + vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); + vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); + rh_port_connect(rhport, speed); return count; -- cgit v1.2.2 From 95c2b71b7b7422749950e3d497a894957d724b16 Mon Sep 17 00:00:00 2001 From: Peter Foley Date: Sun, 24 Apr 2011 17:15:09 -0400 Subject: staging: solo6x10: add select SND_PCM to fix build error This patch fixes a build error when SND_PCM is not set by adding a select statment. Signed-off-by: Peter Foley Acked-By: Ben Collins Signed-off-by: Greg Kroah-Hartman --- drivers/staging/solo6x10/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/solo6x10/Kconfig b/drivers/staging/solo6x10/Kconfig index 2cf77c940860..03dcac4ea4d0 100644 --- a/drivers/staging/solo6x10/Kconfig +++ b/drivers/staging/solo6x10/Kconfig @@ -2,6 +2,7 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" depends on PCI && VIDEO_DEV && SND && I2C select VIDEOBUF_DMA_SG + select SND_PCM ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec codec cards. -- cgit v1.2.2 From b27b8ea853c4c1c1d5d95448cf69b3f10a9558d4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 19 Apr 2011 11:26:35 -0700 Subject: staging: intel_sst: intelmid needs delay.h intel_sst drivers need to #include so that they build cleanly: drivers/staging/intel_sst/intelmid_v1_control.c:188: error: implicit declaration of function 'msleep' drivers/staging/intel_sst/intelmid_v2_control.c:172: error: implicit declaration of function 'msleep' Signed-off-by: Randy Dunlap Cc: Vinod Koul Cc: Harsha Priya Cc: KP Jeeja Cc: Dharageswari R Signed-off-by: Greg Kroah-Hartman --- drivers/staging/intel_sst/intelmid_v1_control.c | 1 + drivers/staging/intel_sst/intelmid_v2_control.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/intel_sst/intelmid_v1_control.c b/drivers/staging/intel_sst/intelmid_v1_control.c index 9cc15c1c18d4..1ea814218059 100644 --- a/drivers/staging/intel_sst/intelmid_v1_control.c +++ b/drivers/staging/intel_sst/intelmid_v1_control.c @@ -28,6 +28,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include diff --git a/drivers/staging/intel_sst/intelmid_v2_control.c b/drivers/staging/intel_sst/intelmid_v2_control.c index 26d815a67eb8..3c6b3abff3c3 100644 --- a/drivers/staging/intel_sst/intelmid_v2_control.c +++ b/drivers/staging/intel_sst/intelmid_v2_control.c @@ -29,6 +29,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include "intel_sst.h" #include "intelmid_snd_control.h" -- cgit v1.2.2 From 4b5730fafb6287bdeed6af914fe90ed9e114d9a6 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 26 Apr 2011 10:51:28 +0200 Subject: HID: add support for barcode scanners from Symbol Technologies Barcode handheld scanners produced by Symbol Technologies (0x05e0/0x0800 and 0x05e0/0x1300) need HID_QUIRK_NOGET, otherwise their firmware exposes trouble during enumeration/initialization. Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 4 ++++ drivers/hid/usbhid/hid-quirks.c | 2 ++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d485894ff4db..be5cf24401bf 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -544,6 +544,10 @@ #define USB_VENDOR_ID_SUNPLUS 0x04fc #define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 +#define USB_VENDOR_ID_SYMBOL 0x05e0 +#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800 +#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300 + #define USB_VENDOR_ID_THRUSTMASTER 0x044f #define USB_VENDOR_ID_TOPSEED 0x0766 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 9a94b643ccde..c09fa0c297c7 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -67,6 +67,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT }, -- cgit v1.2.2 From 22110faf8c8e980013790e6a5214de32b3303730 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 11:33:09 +0200 Subject: PM / Wakeup: Fix initialization of wakeup-related device sysfs files It turns out that some PCI devices are only found to be wakeup-capable during registration, in which case, when device_set_wakeup_capable() is called, device_is_registered() already returns 'true' for the given device, but dpm_sysfs_add() hasn't been called for it yet. This leads to situations in which the device's power.can_wakeup flag is not set as requested because of failing wakeup_sysfs_add() and its wakeup-related sysfs files are not created, although they should be present. This is a post-2.6.38 regression introduced by commit cb8f51bdadb7969139c2e39c2defd4cde98c1 (PM: Do not create wakeup sysfs files for devices that cannot wake up). To work around this problem initialize the device's power.entry field to an empty list head and make device_set_wakeup_capable() check if it is still empty before attempting to add the devices wakeup-related sysfs files with wakeup_sysfs_add(). Namely, if power.entry is still empty at this point, device_pm_add() hasn't been called yet for the device and its wakeup-related files will be created later, so device_set_wakeup_capable() doesn't have to create them. Reported-and-tested-by: Tino Keitel Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman --- drivers/base/power/main.c | 1 + drivers/base/power/wakeup.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index fbc5b6e7c591..abe3ab709e87 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -63,6 +63,7 @@ void device_pm_init(struct device *dev) dev->power.wakeup = NULL; spin_lock_init(&dev->power.lock); pm_runtime_init(dev); + INIT_LIST_HEAD(&dev->power.entry); } /** diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c index 4573c83df6dd..abbbd33e8d8a 100644 --- a/drivers/base/power/wakeup.c +++ b/drivers/base/power/wakeup.c @@ -258,7 +258,7 @@ void device_set_wakeup_capable(struct device *dev, bool capable) if (!!dev->power.can_wakeup == !!capable) return; - if (device_is_registered(dev)) { + if (device_is_registered(dev) && !list_empty(&dev->power.entry)) { if (capable) { if (wakeup_sysfs_add(dev)) return; -- cgit v1.2.2 From 7bed50c5edf5cba8dd515a31191cbfb6065ddc85 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 26 Apr 2011 11:33:18 +0200 Subject: ACPI / PM: Avoid infinite recurrence while registering power resources There is at least one BIOS with a DSDT containing a power resource object with a _PR0 entry pointing back to that power resource. In consequence, while registering that power resource acpi_bus_get_power_flags() sees that it depends on itself and tries to register it again, which leads to an infinitely deep recurrence. This problem was introduced by commit bf325f9538d8c89312be305b9779e (ACPI / PM: Register power resource devices as soon as they are needed). To fix this problem use the observation that power resources cannot be power manageable and prevent acpi_bus_get_power_flags() from being called for power resource objects. References: https://bugzilla.kernel.org/show_bug.cgi?id=31872 Reported-and-tested-by: Pascal Dormeau Signed-off-by: Rafael J. Wysocki Acked-by: Len Brown Cc: stable@kernel.org --- drivers/acpi/scan.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b136c9c1e531..449c556274c0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -943,6 +943,10 @@ static int acpi_bus_get_flags(struct acpi_device *device) if (ACPI_SUCCESS(status)) device->flags.lockable = 1; + /* Power resources cannot be power manageable. */ + if (device->device_type == ACPI_BUS_TYPE_POWER) + return 0; + /* Presence of _PS0|_PR0 indicates 'power manageable' */ status = acpi_get_handle(device->handle, "_PS0", &temp); if (ACPI_FAILURE(status)) -- cgit v1.2.2 From aa1f465225384b276e150238472a5452c4f92a84 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 20 Apr 2011 10:56:20 -0700 Subject: watchdog: iTCO_wdt: TCO Watchdog patch for Intel Panther Point PCH This patch adds the TCO Watchdog DeviceIDs for the Intel Panther Point PCH. Signed-off-by: Seth Heasley Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/iTCO_wdt.c | 97 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) (limited to 'drivers') diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 35a0d12dad73..5fd020da7c55 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -35,6 +35,7 @@ * document number 324645-001, 324646-001: Cougar Point (CPT) * document number TBD : Patsburg (PBG) * document number TBD : DH89xxCC + * document number TBD : Panther Point */ /* @@ -153,6 +154,38 @@ enum iTCO_chipsets { TCO_PBG1, /* Patsburg */ TCO_PBG2, /* Patsburg */ TCO_DH89XXCC, /* DH89xxCC */ + TCO_PPT0, /* Panther Point */ + TCO_PPT1, /* Panther Point */ + TCO_PPT2, /* Panther Point */ + TCO_PPT3, /* Panther Point */ + TCO_PPT4, /* Panther Point */ + TCO_PPT5, /* Panther Point */ + TCO_PPT6, /* Panther Point */ + TCO_PPT7, /* Panther Point */ + TCO_PPT8, /* Panther Point */ + TCO_PPT9, /* Panther Point */ + TCO_PPT10, /* Panther Point */ + TCO_PPT11, /* Panther Point */ + TCO_PPT12, /* Panther Point */ + TCO_PPT13, /* Panther Point */ + TCO_PPT14, /* Panther Point */ + TCO_PPT15, /* Panther Point */ + TCO_PPT16, /* Panther Point */ + TCO_PPT17, /* Panther Point */ + TCO_PPT18, /* Panther Point */ + TCO_PPT19, /* Panther Point */ + TCO_PPT20, /* Panther Point */ + TCO_PPT21, /* Panther Point */ + TCO_PPT22, /* Panther Point */ + TCO_PPT23, /* Panther Point */ + TCO_PPT24, /* Panther Point */ + TCO_PPT25, /* Panther Point */ + TCO_PPT26, /* Panther Point */ + TCO_PPT27, /* Panther Point */ + TCO_PPT28, /* Panther Point */ + TCO_PPT29, /* Panther Point */ + TCO_PPT30, /* Panther Point */ + TCO_PPT31, /* Panther Point */ }; static struct { @@ -244,6 +277,38 @@ static struct { {"Patsburg", 2}, {"Patsburg", 2}, {"DH89xxCC", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, + {"Panther Point", 2}, {NULL, 0} }; @@ -363,6 +428,38 @@ static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = { { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)}, + { ITCO_PCI_DEVICE(0x1e40, TCO_PPT0)}, + { ITCO_PCI_DEVICE(0x1e41, TCO_PPT1)}, + { ITCO_PCI_DEVICE(0x1e42, TCO_PPT2)}, + { ITCO_PCI_DEVICE(0x1e43, TCO_PPT3)}, + { ITCO_PCI_DEVICE(0x1e44, TCO_PPT4)}, + { ITCO_PCI_DEVICE(0x1e45, TCO_PPT5)}, + { ITCO_PCI_DEVICE(0x1e46, TCO_PPT6)}, + { ITCO_PCI_DEVICE(0x1e47, TCO_PPT7)}, + { ITCO_PCI_DEVICE(0x1e48, TCO_PPT8)}, + { ITCO_PCI_DEVICE(0x1e49, TCO_PPT9)}, + { ITCO_PCI_DEVICE(0x1e4a, TCO_PPT10)}, + { ITCO_PCI_DEVICE(0x1e4b, TCO_PPT11)}, + { ITCO_PCI_DEVICE(0x1e4c, TCO_PPT12)}, + { ITCO_PCI_DEVICE(0x1e4d, TCO_PPT13)}, + { ITCO_PCI_DEVICE(0x1e4e, TCO_PPT14)}, + { ITCO_PCI_DEVICE(0x1e4f, TCO_PPT15)}, + { ITCO_PCI_DEVICE(0x1e50, TCO_PPT16)}, + { ITCO_PCI_DEVICE(0x1e51, TCO_PPT17)}, + { ITCO_PCI_DEVICE(0x1e52, TCO_PPT18)}, + { ITCO_PCI_DEVICE(0x1e53, TCO_PPT19)}, + { ITCO_PCI_DEVICE(0x1e54, TCO_PPT20)}, + { ITCO_PCI_DEVICE(0x1e55, TCO_PPT21)}, + { ITCO_PCI_DEVICE(0x1e56, TCO_PPT22)}, + { ITCO_PCI_DEVICE(0x1e57, TCO_PPT23)}, + { ITCO_PCI_DEVICE(0x1e58, TCO_PPT24)}, + { ITCO_PCI_DEVICE(0x1e59, TCO_PPT25)}, + { ITCO_PCI_DEVICE(0x1e5a, TCO_PPT26)}, + { ITCO_PCI_DEVICE(0x1e5b, TCO_PPT27)}, + { ITCO_PCI_DEVICE(0x1e5c, TCO_PPT28)}, + { ITCO_PCI_DEVICE(0x1e5d, TCO_PPT29)}, + { ITCO_PCI_DEVICE(0x1e5e, TCO_PPT30)}, + { ITCO_PCI_DEVICE(0x1e5f, TCO_PPT31)}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); -- cgit v1.2.2 From f030ddfb3752df36bb73285353374fc04feabb80 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 8 Apr 2011 15:05:21 +0200 Subject: amd64_edac: Remove node interleave warning This warning was wrongfully added for a normal condition - intlvsel actually selects the destination node when node interleaving is enabled and it is not a mismatch. For a detailed example, see section 2.8.10.2 "Node Interleaving" in F10h BKDG. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 4b4071ee2f5c..601142a0738a 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -1401,12 +1401,8 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range, return -EINVAL; } - if (intlv_en && - (intlv_sel != ((sys_addr >> 12) & intlv_en))) { - amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n", - intlv_en, intlv_sel); + if (intlv_en && (intlv_sel != ((sys_addr >> 12) & intlv_en))) return -EINVAL; - } sys_addr = f1x_swap_interleaved_region(pvt, sys_addr); -- cgit v1.2.2 From f08e457cecece7fbbdad3add9defac3373a59b5a Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Mon, 21 Mar 2011 20:45:06 +0100 Subject: amd64_edac: Factor in CC6 save area F15h and later use a portion of DRAM as a CC6 storage area. BIOS programs D18F1x[17C:140,7C:40] DRAM Base/Limit accordingly by subtracting the storage area from the DRAM limit setting. However, in order for edac to consider that part of DRAM too, we need to include it into the per-node range. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 28 +++++++++++++++++++++++++++- drivers/edac/amd64_edac.h | 2 ++ 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 601142a0738a..e17de90ba6c6 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -944,12 +944,13 @@ static u64 get_error_address(struct mce *m) static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) { + struct cpuinfo_x86 *c = &boot_cpu_data; int off = range << 3; amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo); amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo); - if (boot_cpu_data.x86 == 0xf) + if (c->x86 == 0xf) return; if (!dram_rw(pvt, range)) @@ -957,6 +958,31 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi); amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi); + + /* Factor in CC6 save area by reading dst node's limit reg */ + if (c->x86 == 0x15) { + struct pci_dev *f1 = NULL; + u8 nid = dram_dst_node(pvt, range); + u32 llim; + + f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1)); + if (WARN_ON(!f1)) + return; + + amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim); + + pvt->ranges[range].lim.lo &= GENMASK(0, 15); + + /* {[39:27],111b} */ + pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16; + + pvt->ranges[range].lim.hi &= GENMASK(0, 7); + + /* [47:40] */ + pvt->ranges[range].lim.hi |= llim >> 13; + + pci_dev_put(f1); + } } static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 11be36a311eb..0110930c82ed 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -196,6 +196,8 @@ #define DCT_CFG_SEL 0x10C +#define DRAM_LOCAL_NODE_LIM 0x124 + #define DRAM_BASE_HI 0x140 #define DRAM_LIMIT_HI 0x144 -- cgit v1.2.2 From c1ae68309b0c1ea67b72e9e94e26b4e819022fc7 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Wed, 30 Mar 2011 15:42:10 +0200 Subject: amd64_edac: Erratum #637 workaround F15h CPUs may report a non-DRAM address when reporting an error address belonging to a CC6 state save area. Add a workaround to detect this condition and compute the actual DRAM address of the error as documented in the Revision Guide for AMD Family 15h Models 00h-0Fh Processors. Signed-off-by: Borislav Petkov --- drivers/edac/amd64_edac.c | 52 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/edac/amd64_edac.h | 1 + 2 files changed, 51 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index e17de90ba6c6..9a8bebcf6b17 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -931,15 +931,63 @@ static int k8_early_channel_count(struct amd64_pvt *pvt) /* On F10h and later ErrAddr is MC4_ADDR[47:1] */ static u64 get_error_address(struct mce *m) { + struct cpuinfo_x86 *c = &boot_cpu_data; + u64 addr; u8 start_bit = 1; u8 end_bit = 47; - if (boot_cpu_data.x86 == 0xf) { + if (c->x86 == 0xf) { start_bit = 3; end_bit = 39; } - return m->addr & GENMASK(start_bit, end_bit); + addr = m->addr & GENMASK(start_bit, end_bit); + + /* + * Erratum 637 workaround + */ + if (c->x86 == 0x15) { + struct amd64_pvt *pvt; + u64 cc6_base, tmp_addr; + u32 tmp; + u8 mce_nid, intlv_en; + + if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7) + return addr; + + mce_nid = amd_get_nb_id(m->extcpu); + pvt = mcis[mce_nid]->pvt_info; + + amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_LIM, &tmp); + intlv_en = tmp >> 21 & 0x7; + + /* add [47:27] + 3 trailing bits */ + cc6_base = (tmp & GENMASK(0, 20)) << 3; + + /* reverse and add DramIntlvEn */ + cc6_base |= intlv_en ^ 0x7; + + /* pin at [47:24] */ + cc6_base <<= 24; + + if (!intlv_en) + return cc6_base | (addr & GENMASK(0, 23)); + + amd64_read_pci_cfg(pvt->F1, DRAM_LOCAL_NODE_BASE, &tmp); + + /* faster log2 */ + tmp_addr = (addr & GENMASK(12, 23)) << __fls(intlv_en + 1); + + /* OR DramIntlvSel into bits [14:12] */ + tmp_addr |= (tmp & GENMASK(21, 23)) >> 9; + + /* add remaining [11:0] bits from original MC4_ADDR */ + tmp_addr |= addr & GENMASK(0, 11); + + return cc6_base | tmp_addr; + } + + return addr; } static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 0110930c82ed..9a666cb985b2 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -196,6 +196,7 @@ #define DCT_CFG_SEL 0x10C +#define DRAM_LOCAL_NODE_BASE 0x120 #define DRAM_LOCAL_NODE_LIM 0x124 #define DRAM_BASE_HI 0x140 -- cgit v1.2.2 From e9c549998dc24209847007e1f209f3b6c88d21ba Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 26 Apr 2011 23:28:26 -0700 Subject: Revert wrong fixes for common misspellings These changes were incorrectly fixed by codespell. They were now manually corrected. Signed-off-by: Lucas De Marchi --- drivers/infiniband/hw/qib/qib_iba6120.c | 2 +- drivers/infiniband/hw/qib/qib_iba7220.c | 2 +- drivers/infiniband/hw/qib/qib_iba7322.c | 2 +- drivers/media/radio/radio-sf16fmr2.c | 2 +- drivers/mtd/nand/diskonchip.c | 2 +- drivers/pcmcia/pcmcia_resource.c | 2 +- drivers/staging/rt2860/common/cmm_data_pci.c | 2 +- drivers/staging/rt2860/common/cmm_data_usb.c | 2 +- drivers/staging/spectra/ffsport.c | 2 +- drivers/staging/tidspbridge/dynload/cload.c | 2 +- drivers/staging/tty/specialix.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index 7de4b7ebffc5..d8ca0a0b970d 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1799,7 +1799,7 @@ static int qib_6120_setup_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 74fe0360bec7..c765a2eb04cf 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2111,7 +2111,7 @@ static int qib_setup_7220_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT); dd->int_counter = 0; /* so we check interrupts work again */ diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 55de3cf3441c..6bab3eaea70f 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3299,7 +3299,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd) /* * Keep chip from being accessed until we are ready. Use * writeq() directly, to allow the write even though QIB_PRESENT - * isn't' set. + * isn't set. */ dd->flags &= ~(QIB_INITTED | QIB_PRESENT | QIB_BADINTR); dd->flags |= QIB_DOING_RESET; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index dc3f04c52d5e..87bad7678d92 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -170,7 +170,7 @@ static int fmr2_setfreq(struct fmr2 *dev) return 0; } -/* !!! not tested, in my card this does't work !!! */ +/* !!! not tested, in my card this doesn't work !!! */ static int fmr2_setvolume(struct fmr2 *dev) { int vol[16] = { 0x021, 0x084, 0x090, 0x104, diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 96c0b34ba8db..657b9f4b6f9b 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -400,7 +400,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) doc200x_hwcontrol(mtd, 0, NAND_CTRL_ALE | NAND_CTRL_CHANGE); doc200x_hwcontrol(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - /* We can't' use dev_ready here, but at least we wait for the + /* We can't use dev_ready here, but at least we wait for the * command to complete */ udelay(50); diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index fe77e8223841..e8c19def1b0f 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -173,7 +173,7 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev, c = p_dev->function_config; if (!(c->state & CONFIG_LOCKED)) { - dev_dbg(&p_dev->dev, "Configuration isn't't locked\n"); + dev_dbg(&p_dev->dev, "Configuration isn't locked\n"); mutex_unlock(&s->ops_mutex); return -EACCES; } diff --git a/drivers/staging/rt2860/common/cmm_data_pci.c b/drivers/staging/rt2860/common/cmm_data_pci.c index bef0bbd8cef7..f01a51c381f1 100644 --- a/drivers/staging/rt2860/common/cmm_data_pci.c +++ b/drivers/staging/rt2860/common/cmm_data_pci.c @@ -444,7 +444,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, return (NDIS_STATUS_FAILURE); } } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/rt2860/common/cmm_data_usb.c b/drivers/staging/rt2860/common/cmm_data_usb.c index 5637857ae9eb..83a62faa7e57 100644 --- a/drivers/staging/rt2860/common/cmm_data_usb.c +++ b/drivers/staging/rt2860/common/cmm_data_usb.c @@ -860,7 +860,7 @@ int RTMPCheckRxError(struct rt_rtmp_adapter *pAd, DBGPRINT_RAW(RT_DEBUG_ERROR, ("received packet too long\n")); return NDIS_STATUS_FAILURE; } - /* Drop not U2M frames, can't's drop here because we will drop beacon in this case */ + /* Drop not U2M frames, can't drop here because we will drop beacon in this case */ /* I am kind of doubting the U2M bit operation */ /* if (pRxD->U2M == 0) */ /* return(NDIS_STATUS_FAILURE); */ diff --git a/drivers/staging/spectra/ffsport.c b/drivers/staging/spectra/ffsport.c index 20dae73d3b78..506547b603e1 100644 --- a/drivers/staging/spectra/ffsport.c +++ b/drivers/staging/spectra/ffsport.c @@ -653,7 +653,7 @@ static int SBD_setup_device(struct spectra_nand_dev *dev, int which) } dev->queue->queuedata = dev; - /* As Linux block layer does't support >4KB hardware sector, */ + /* As Linux block layer doesn't support >4KB hardware sector, */ /* Here we force report 512 byte hardware sector size to Kernel */ blk_queue_logical_block_size(dev->queue, 512); diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c index 5cecd237e3f6..fe1ef0addb09 100644 --- a/drivers/staging/tidspbridge/dynload/cload.c +++ b/drivers/staging/tidspbridge/dynload/cload.c @@ -718,7 +718,7 @@ static void dload_symbols(struct dload_state *dlthis) * as a temporary for .dllview record construction. * Allocate storage for the whole table. Add 1 to the section count * in case a trampoline section is auto-generated as well as the - * size of the trampoline section name so DLLView does't get lost. + * size of the trampoline section name so DLLView doesn't get lost. */ siz = sym_count * sizeof(struct local_symbol); diff --git a/drivers/staging/tty/specialix.c b/drivers/staging/tty/specialix.c index cb24c6d999db..5c3598ec7456 100644 --- a/drivers/staging/tty/specialix.c +++ b/drivers/staging/tty/specialix.c @@ -978,7 +978,7 @@ static void sx_change_speed(struct specialix_board *bp, spin_lock_irqsave(&bp->lock, flags); sx_out(bp, CD186x_CAR, port_No(port)); - /* The Specialix board does't implement the RTS lines. + /* The Specialix board doesn't implement the RTS lines. They are used to set the IRQ level. Don't touch them. */ if (sx_crtscts(tty)) port->MSVR = MSVR_DTR | (sx_in(bp, CD186x_MSVR) & MSVR_RTS); -- cgit v1.2.2 From bf5192edcbc1f0a7f9c054649dbf1a0b3210d9b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 22 Apr 2011 07:51:33 +1000 Subject: drm: select FRAMEBUFFER_CONSOLE_PRIMARY if we have FRAMEBUFFER_CONSOLE Multi-gpu/switcheroo relies on this option to get the console on the correct GPU at bootup, some distros enable it but it seems some get it wrong. cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index c58f691ec3ce..b493663c7ba7 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -24,6 +24,7 @@ config DRM_KMS_HELPER depends on DRM select FB select FRAMEBUFFER_CONSOLE if !EXPERT + select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE help FB and CRTC helpers for KMS drivers. -- cgit v1.2.2 From 834f0c353ae430c1a6ce023c9b77bbd3ff9241a7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 26 Apr 2011 13:10:20 -0400 Subject: drm/radeon/kms: add missing safe regs for 6xx/7xx needed for HiS in mesa. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/reg_srcs/r600 | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/reg_srcs/r600 b/drivers/gpu/drm/radeon/reg_srcs/r600 index af0da4ae3f55..92f1900dc7ca 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r600 +++ b/drivers/gpu/drm/radeon/reg_srcs/r600 @@ -708,6 +708,7 @@ r600 0x9400 0x00028D0C DB_RENDER_CONTROL 0x00028D10 DB_RENDER_OVERRIDE 0x0002880C DB_SHADER_CONTROL +0x00028D28 DB_SRESULTS_COMPARE_STATE0 0x00028D2C DB_SRESULTS_COMPARE_STATE1 0x00028430 DB_STENCILREFMASK 0x00028434 DB_STENCILREFMASK_BF -- cgit v1.2.2 From 6565945b60922211c299968ba66a66617af32c9f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 26 Apr 2011 13:27:43 -0400 Subject: drm/radeon/kms: add info query for tile pipes needed by mesa for htile setup. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_kms.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index bf7d4c061451..871df0376b1c 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -221,6 +221,19 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return -EINVAL; } break; + case RADEON_INFO_NUM_TILE_PIPES: + if (rdev->family >= CHIP_CAYMAN) + value = rdev->config.cayman.max_tile_pipes; + else if (rdev->family >= CHIP_CEDAR) + value = rdev->config.evergreen.max_tile_pipes; + else if (rdev->family >= CHIP_RV770) + value = rdev->config.rv770.max_tile_pipes; + else if (rdev->family >= CHIP_R600) + value = rdev->config.r600.max_tile_pipes; + else { + return -EINVAL; + } + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; -- cgit v1.2.2 From e8e7a2b8ccfdae0d4cb6bd25824bbedcd42da316 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 21 Apr 2011 22:18:32 +0100 Subject: drm/i915: restore only the mode of this driver on lastclose (v2) i915 calls the panic handler function on last close to reset the modes, however this is a really bad idea for multi-gpu machines, esp shareable gpus machines. So add a new entry point for the driver to just restore its own fbcon mode. v2: move code into fb helper, fix panic code to block mode change on powered off GPUs. [airlied: this hits drm core and I wrote it and it was reviewed on intel-gfx so really I signed it off twice ;-).] Signed-off-by: Chris Wilson Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 27 ++++++++++++++++++++------- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fb.c | 10 ++++++++++ 4 files changed, 32 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 950720473967..11d7a72c22d9 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -342,9 +342,22 @@ int drm_fb_helper_debug_leave(struct fb_info *info) } EXPORT_SYMBOL(drm_fb_helper_debug_leave); +bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) +{ + bool error = false; + int i, ret; + for (i = 0; i < fb_helper->crtc_count; i++) { + struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; + ret = drm_crtc_helper_set_config(mode_set); + if (ret) + error = true; + } + return error; +} +EXPORT_SYMBOL(drm_fb_helper_restore_fbdev_mode); + bool drm_fb_helper_force_kernel_mode(void) { - int i = 0; bool ret, error = false; struct drm_fb_helper *helper; @@ -352,12 +365,12 @@ bool drm_fb_helper_force_kernel_mode(void) return false; list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { - for (i = 0; i < helper->crtc_count; i++) { - struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; - ret = drm_crtc_helper_set_config(mode_set); - if (ret) - error = true; - } + if (helper->dev->switch_power_state == DRM_SWITCH_POWER_OFF) + continue; + + ret = drm_fb_helper_restore_fbdev_mode(helper); + if (ret) + error = true; } return error; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 72730377a01b..12876f2795d2 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2207,7 +2207,7 @@ void i915_driver_lastclose(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_fb_helper_restore(); + intel_fb_restore_mode(dev); vga_switcheroo_process_delayed_switch(); return; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f5b0d8306d83..1d20712d527f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,4 +338,5 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data, struct drm_file *file_priv); extern void intel_fb_output_poll_changed(struct drm_device *dev); +extern void intel_fb_restore_mode(struct drm_device *dev); #endif /* __INTEL_DRV_H__ */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 512782728e51..ec49bae73382 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -264,3 +264,13 @@ void intel_fb_output_poll_changed(struct drm_device *dev) drm_i915_private_t *dev_priv = dev->dev_private; drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); } + +void intel_fb_restore_mode(struct drm_device *dev) +{ + int ret; + drm_i915_private_t *dev_priv = dev->dev_private; + + ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper); + if (ret) + DRM_DEBUG("failed to restore crtc mode\n"); +} -- cgit v1.2.2 From 9fdcdbb0d84922e7ccda2f717a04ea62629f7e18 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Tue, 29 Mar 2011 00:46:12 -0400 Subject: mmc: sdhci-pci: Fix error case in sdhci_pci_probe_slot() If pci_ioremap_bar() fails during probe, we "goto release;" and free the host, but then we return 0 -- which tells sdhci_pci_probe() that the probe succeeded. Since we think the probe succeeded, when we unload sdhci we'll go to sdhci_pci_remove_slot() and it will try to dereference slot->host, which is now NULL because we freed it in the error path earlier. The patch simply sets ret appropriately, so that sdhci_pci_probe() will detect the failure immediately and bail out. Signed-off-by: Chris Ball Cc: --- drivers/mmc/host/sdhci-pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index a136be706347..f8b5f37007b2 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -957,6 +957,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( host->ioaddr = pci_ioremap_bar(pdev, bar); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); + ret = -ENOMEM; goto release; } -- cgit v1.2.2 From 9bc21848b1d6cb8389d927196b16c9950b5e21e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miros=C5=82aw?= Date: Sat, 9 Apr 2011 08:16:47 +0200 Subject: mmc: core: mmc_add_card(): fix missing break in switch statement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a cosmetic bug that affects printk() for SD-combo cards. Reported-by: Prashanth Bhat Signed-off-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: Chris Ball --- drivers/mmc/core/bus.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 63667a8f140c..d6d62fd07ee9 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -284,6 +284,7 @@ int mmc_add_card(struct mmc_card *card) type = "SD-combo"; if (mmc_card_blockaddr(card)) type = "SDHC-combo"; + break; default: type = "?"; break; -- cgit v1.2.2 From f69475142136c8ad9b9c717aea2ff907aed9f863 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 11 Apr 2011 17:00:44 -0400 Subject: mmc: omap: Fix possible NULL pointer deref Either OMAP_MMC_STAT_CARD_ERR or OMAP_MMC_STAT_END_OF_CMD might fire if there is no host->cmd pointer. Check for a valid host->cmd pointer before calling mmc_omap_cmd_done(). Signed-off-by: Michael Buesch Acked-by: Tony Lindgren Signed-off-by: Chris Ball --- drivers/mmc/host/omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 2e032f0e8cf4..a6c329040140 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -832,7 +832,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) return IRQ_HANDLED; } - if (end_command) + if (end_command && host->cmd) mmc_omap_cmd_done(host, host->cmd); if (host->data != NULL) { if (transfer_error) -- cgit v1.2.2 From 26fc8775b51484d8c0a671198639c6d5ae60533e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 15 Apr 2011 20:08:19 +0200 Subject: mmc: fix a race between card-detect rescan and clock-gate work instances Currently there is a race in the MMC core between a card-detect rescan work and the clock-gating work, scheduled from a command completion. Fix it by removing the dedicated clock-gating mutex and using the MMC standard locking mechanism instead. Signed-off-by: Guennadi Liakhovetski Cc: Simon Horman Cc: Magnus Damm Acked-by: Linus Walleij Cc: Signed-off-by: Chris Ball --- drivers/mmc/core/host.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 461e6a17fb90..2b200c1cfbba 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -94,7 +94,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) spin_unlock_irqrestore(&host->clk_lock, flags); return; } - mutex_lock(&host->clk_gate_mutex); + mmc_claim_host(host); spin_lock_irqsave(&host->clk_lock, flags); if (!host->clk_requests) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -104,7 +104,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); } spin_unlock_irqrestore(&host->clk_lock, flags); - mutex_unlock(&host->clk_gate_mutex); + mmc_release_host(host); } /* @@ -130,7 +130,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) { unsigned long flags; - mutex_lock(&host->clk_gate_mutex); + mmc_claim_host(host); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -140,7 +140,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) } host->clk_requests++; spin_unlock_irqrestore(&host->clk_lock, flags); - mutex_unlock(&host->clk_gate_mutex); + mmc_release_host(host); } /** @@ -215,7 +215,6 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_gated = false; INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); - mutex_init(&host->clk_gate_mutex); } /** -- cgit v1.2.2 From c919c2a073c5d2e076e52a56b44281d922721b61 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 21 Apr 2011 09:09:59 +0200 Subject: mmc: tmio: fix .set_ios(MMC_POWER_UP) handling The aggressive clock gating for TMIO MMC patch has broken switching interface power on, using MFD or platform callbacks. Restore the ios->power_mode == MMC_POWER_UP && ios->clock == 0 case handling. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/tmio_mmc_pio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 62d37de6de76..710339a85c84 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -728,15 +728,15 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmio_mmc_set_clock(host, ios->clock); /* Power sequence - OFF -> UP -> ON */ - if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { + if (ios->power_mode == MMC_POWER_UP) { + /* power up SD bus */ + if (host->set_pwr) + host->set_pwr(host->pdev, 1); + } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { /* power down SD bus */ if (ios->power_mode == MMC_POWER_OFF && host->set_pwr) host->set_pwr(host->pdev, 0); tmio_mmc_clk_stop(host); - } else if (ios->power_mode == MMC_POWER_UP) { - /* power up SD bus */ - if (host->set_pwr) - host->set_pwr(host->pdev, 1); } else { /* start bus clock */ tmio_mmc_clk_start(host); -- cgit v1.2.2 From b7b4d3426d2b5ecab21578eb20d8e456a1aace8f Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 27 Apr 2011 14:24:19 +0100 Subject: mmc: sdhci: Check mrq->cmd in sdhci_tasklet_finish It seems that under certain circumstances that the sdhci_tasklet_finish() call can be entered with mrq->cmd set to NULL, causing the system to crash with a NULL pointer de-reference. Unable to handle kernel NULL pointer dereference at virtual address 00000000 PC is at sdhci_tasklet_finish+0x34/0xe8 LR is at sdhci_tasklet_finish+0x24/0xe8 Seen on S3C6410 system. Signed-off-by: Ben Dooks Signed-off-by: Mark Brown Cc: Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9e15f41f87be..fd8f488df5fa 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1345,7 +1345,7 @@ static void sdhci_tasklet_finish(unsigned long param) * upon error conditions. */ if (!(host->flags & SDHCI_DEVICE_DEAD) && - (mrq->cmd->error || + ((mrq->cmd && mrq->cmd->error) || (mrq->data && (mrq->data->error || (mrq->data->stop && mrq->data->stop->error))) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { -- cgit v1.2.2 From 0c9c99a765321104cc5f9c97f949382a9ba4927e Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Wed, 27 Apr 2011 17:35:31 -0400 Subject: mmc: sdhci: Check mrq != NULL in sdhci_tasklet_finish It seems that under certain circumstances the sdhci_tasklet_finish() call can be entered with mrq set to NULL, causing the system to crash with a NULL pointer de-reference. Seen on S3C6410 system. Based on a patch by Dimitris Papastamos. Reported-by: Dimitris Papastamos Cc: Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index fd8f488df5fa..5d20661bc357 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1334,6 +1334,13 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; + /* + * If this tasklet gets rescheduled while running, it will + * be run again afterwards but without any active request. + */ + if (!host->mrq) + return; + spin_lock_irqsave(&host->lock, flags); del_timer(&host->timer); -- cgit v1.2.2 From f5346668150c37094b42cc2d07ec5fd1451eb980 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:08:34 -0700 Subject: Input: wm831x-ts - fix races with IRQ management If the WM831x pen down and data IRQs run in parallel it is possible for the data and pen down IRQs to deadlock themselves as one is part way through disabling its operation while the other is part way through enabling. Fix this by always disabling the pen down interrupt while data is active and vice versa. When a changeover is required we disable the IRQ that is to be stopped then schedule work that will enable the new IRQ. We need to handle the data flow in the data IRQ as the readback from the device needs to be ordered correctly with the IRQ for robust operation. This also fixes an issue when using the built in IRQs due to enable_irq() not being valid from interrupt context on an interrupt controller with bus operations like the built in IRQ controller - this issue may also have affected other interrupt controllers. We can't rely on having the data and pen down IRQs available via GPIOs on the CPU on every system. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 54 +++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 6ae054f8e0aa..b9373012b3e6 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -68,8 +68,23 @@ struct wm831x_ts { unsigned int pd_irq; bool pressure; bool pen_down; + struct work_struct pd_data_work; }; +static void wm831x_pd_data_work(struct work_struct *work) +{ + struct wm831x_ts *wm831x_ts = + container_of(work, struct wm831x_ts, pd_data_work); + + if (wm831x_ts->pen_down) { + enable_irq(wm831x_ts->data_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ PD->DATA done\n"); + } else { + enable_irq(wm831x_ts->pd_irq); + dev_dbg(wm831x_ts->wm831x->dev, "IRQ DATA->PD done\n"); + } +} + static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) { struct wm831x_ts *wm831x_ts = irq_data; @@ -110,6 +125,9 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) } if (!wm831x_ts->pen_down) { + /* Switch from data to pen down */ + dev_dbg(wm831x->dev, "IRQ DATA->PD\n"); + disable_irq_nosync(wm831x_ts->data_irq); /* Don't need data any more */ @@ -128,6 +146,8 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) ABS_PRESSURE, 0); input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); + + schedule_work(&wm831x_ts->pd_data_work); } input_sync(wm831x_ts->input_dev); @@ -141,6 +161,11 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) struct wm831x *wm831x = wm831x_ts->wm831x; int ena = 0; + if (wm831x_ts->pen_down) + return IRQ_HANDLED; + + disable_irq_nosync(wm831x_ts->pd_irq); + /* Start collecting data */ if (wm831x_ts->pressure) ena |= WM831X_TCH_Z_ENA; @@ -156,7 +181,10 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); wm831x_ts->pen_down = true; - enable_irq(wm831x_ts->data_irq); + + /* Switch from pen down to data */ + dev_dbg(wm831x->dev, "IRQ PD->DATA\n"); + schedule_work(&wm831x_ts->pd_data_work); return IRQ_HANDLED; } @@ -182,13 +210,28 @@ static void wm831x_ts_input_close(struct input_dev *idev) struct wm831x_ts *wm831x_ts = input_get_drvdata(idev); struct wm831x *wm831x = wm831x_ts->wm831x; + /* Shut the controller down, disabling all other functionality too */ wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, - WM831X_TCH_ENA | WM831X_TCH_CVT_ENA | - WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | - WM831X_TCH_Z_ENA, 0); + WM831X_TCH_ENA | WM831X_TCH_X_ENA | + WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, 0); - if (wm831x_ts->pen_down) + /* Make sure any pending IRQs are done, the above will prevent + * new ones firing. + */ + synchronize_irq(wm831x_ts->data_irq); + synchronize_irq(wm831x_ts->pd_irq); + + /* Make sure the IRQ completion work is quiesced */ + flush_work_sync(&wm831x_ts->pd_data_work); + + /* If we ended up with the pen down then make sure we revert back + * to pen detection state for the next time we start up. + */ + if (wm831x_ts->pen_down) { disable_irq(wm831x_ts->data_irq); + enable_irq(wm831x_ts->pd_irq); + wm831x_ts->pen_down = false; + } } static __devinit int wm831x_ts_probe(struct platform_device *pdev) @@ -212,6 +255,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_ts->wm831x = wm831x; wm831x_ts->input_dev = input_dev; + INIT_WORK(&wm831x_ts->pd_data_work, wm831x_pd_data_work); /* * If we have a direct IRQ use it, otherwise use the interrupt -- cgit v1.2.2 From acad9853b95df6a3887f52e0ec88e4a77119ee28 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:08:51 -0700 Subject: Input: wm831x-ts - allow IRQ flags to be specified This allows maximum flexibility for configuring the direct GPIO based interrupts. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index b9373012b3e6..78e8705df20d 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -241,7 +241,7 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) struct wm831x_pdata *core_pdata = dev_get_platdata(pdev->dev.parent); struct wm831x_touch_pdata *pdata = NULL; struct input_dev *input_dev; - int error; + int error, irqf; if (core_pdata) pdata = core_pdata->touch; @@ -314,9 +314,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) wm831x_set_bits(wm831x, WM831X_TOUCH_CONTROL_1, WM831X_TCH_RATE_MASK, 6); + if (pdata && pdata->data_irqf) + irqf = pdata->data_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->data_irq, NULL, wm831x_ts_data_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen data", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request data IRQ %d: %d\n", @@ -325,9 +330,14 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev) } disable_irq(wm831x_ts->data_irq); + if (pdata && pdata->pd_irqf) + irqf = pdata->pd_irqf; + else + irqf = IRQF_TRIGGER_HIGH; + error = request_threaded_irq(wm831x_ts->pd_irq, NULL, wm831x_ts_pen_down_irq, - IRQF_ONESHOT, + irqf | IRQF_ONESHOT, "Touchscreen pen down", wm831x_ts); if (error) { dev_err(&pdev->dev, "Failed to request pen down IRQ %d: %d\n", -- cgit v1.2.2 From bf283707d5fb174ec09215ae19860ad04ba7b67a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 27 Apr 2011 23:09:26 -0700 Subject: Input: wm831x-ts - move BTN_TOUCH reporting to data transfer Don't report BTN_TOUCH until we've got data as some less robust applications can be confused by getting a touch event by itself and it doesn't seem unreasonable for them to expect coordinates along with a touch. Signed-off-by: Mark Brown Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wm831x-ts.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c index 78e8705df20d..9175d49d2546 100644 --- a/drivers/input/touchscreen/wm831x-ts.c +++ b/drivers/input/touchscreen/wm831x-ts.c @@ -148,6 +148,8 @@ static irqreturn_t wm831x_ts_data_irq(int irq, void *irq_data) input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 0); schedule_work(&wm831x_ts->pd_data_work); + } else { + input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); } input_sync(wm831x_ts->input_dev); @@ -174,9 +176,6 @@ static irqreturn_t wm831x_ts_pen_down_irq(int irq, void *irq_data) WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | WM831X_TCH_Z_ENA, WM831X_TCH_X_ENA | WM831X_TCH_Y_ENA | ena); - input_report_key(wm831x_ts->input_dev, BTN_TOUCH, 1); - input_sync(wm831x_ts->input_dev); - wm831x_set_bits(wm831x, WM831X_INTERRUPT_STATUS_1, WM831X_TCHPD_EINT, WM831X_TCHPD_EINT); -- cgit v1.2.2 From f945a3d9600633de589ce698233b34ff6ad57e55 Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Wed, 27 Apr 2011 11:44:29 -0700 Subject: rtc: max8925: Call dev_set_drvdata before rtc_device_register We call rtc_read_alarm from rtc_device_register, so it is important that the rtc device is fully initialized prior to registration. rtc-max8925 sets drvdata after register, so the rtc_read_alarm code dereferences a NULL pointer. Call dev_set_drvdata before rtc_device_register. [ jstultz/tglx: Massaged commit message ] Signed-off-by: Zhangfei Gao Cc: Alessandro Zummo Link: http://lkml.kernel.org/r/%3C1303929869-25249-1-git-send-email-john.stultz%40linaro.org%3E Signed-off-by: John Stultz Signed-off-by: Thomas Gleixner --- drivers/rtc/rtc-max8925.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 174036dda786..20494b5edc3c 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -257,6 +257,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_irq; } + dev_set_drvdata(&pdev->dev, info); + info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev, &max8925_rtc_ops, THIS_MODULE); ret = PTR_ERR(info->rtc_dev); @@ -265,7 +267,6 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev) goto out_rtc; } - dev_set_drvdata(&pdev->dev, info); platform_set_drvdata(pdev, info); return 0; -- cgit v1.2.2 From 35dca5b4a67a93bbb75c2753d6dc432dc8f82e5d Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 28 Apr 2011 15:43:13 +0200 Subject: HID: add support for Sony Navigation Controller Sony Navigation Controller needs a special report to be sent to it before it is able to operate, the same way as other Sony controllers do. Tested-by: Jacek Lukas Wotka Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-sony.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d66269ed7d..b1986b954ac5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1449,6 +1449,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index be5cf24401bf..087a5a436598 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -524,6 +524,7 @@ #define USB_VENDOR_ID_SONY 0x054c #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 +#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 #define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 93819a08121a..936c911fdca6 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -178,6 +178,8 @@ static void sony_remove(struct hid_device *hdev) static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), + .driver_data = SIXAXIS_CONTROLLER_USB }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), -- cgit v1.2.2 From f61583941667c96d61fc6991b9f23307f9bfa87e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 19 Apr 2011 22:49:29 +0200 Subject: b43: trivial: update module info about ucode16_mimo firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: RafaÅ‚ MiÅ‚ecki Signed-off-by: John W. Linville --- drivers/net/wireless/b43/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 57eb5b649730..7841b95f3935 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -72,6 +72,7 @@ MODULE_FIRMWARE("b43/ucode11.fw"); MODULE_FIRMWARE("b43/ucode13.fw"); MODULE_FIRMWARE("b43/ucode14.fw"); MODULE_FIRMWARE("b43/ucode15.fw"); +MODULE_FIRMWARE("b43/ucode16_mimo.fw"); MODULE_FIRMWARE("b43/ucode5.fw"); MODULE_FIRMWARE("b43/ucode9.fw"); -- cgit v1.2.2 From 1501b6764f0c363a9f1d72f9d422841f81f1bd8c Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Mon, 25 Apr 2011 11:12:57 -0700 Subject: iwlegacy: led stay solid on when no traffic commit 5ed540aecc2aae92d5c97b9a9306a5bf88ad5574 change the led behavior for iwlwifi driver; the side effect cause led blink all the time. Modify the led blink table to fix this problem Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-led.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c index 15eb8b707157..bda0d61b2c0d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-led.c @@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); +/* Throughput OFF time(ms) ON time (ms) + * >300 25 25 + * >200 to 300 40 40 + * >100 to 200 55 55 + * >70 to 100 65 65 + * >50 to 70 75 75 + * >20 to 50 85 85 + * >10 to 20 95 95 + * >5 to 10 110 110 + * >1 to 5 130 130 + * >0 to 1 167 167 + * <=0 SOLID ON + */ static const struct ieee80211_tpt_blink iwl_blink[] = { - { .throughput = 0 * 1024 - 1, .blink_time = 334 }, + { .throughput = 0, .blink_time = 334 }, { .throughput = 1 * 1024 - 1, .blink_time = 260 }, { .throughput = 5 * 1024 - 1, .blink_time = 220 }, { .throughput = 10 * 1024 - 1, .blink_time = 190 }, @@ -101,6 +114,11 @@ static int iwl_legacy_led_cmd(struct iwl_priv *priv, if (priv->blink_on == on && priv->blink_off == off) return 0; + if (off == 0) { + /* led is SOLID_ON */ + on = IWL_LED_SOLID; + } + IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n", priv->cfg->base_params->led_compensation); led_cmd.on = iwl_legacy_blink_compensation(priv, on, -- cgit v1.2.2 From f325757ab2812b42da4d690cf8da73c0e678368c Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 28 Apr 2011 11:36:54 +0200 Subject: iwl4965: fix "TX Power requested while scanning" Fix the following: WARNING: at drivers/net/wireless/iwlegacy/iwl-4965.c:1128 \ iwl4965_send_tx_power+0x61/0x102 [iwl4965]() Hardware name: [...] TX Power requested while scanning! Pid: 5723, comm: kworker/u:28 Not tainted 2.6.39-0.rc4.4.fc14.x86_64 #1 Call Trace: [] warn_slowpath_common+0x85/0x9d [] ? iwl4965_show_temperature+0x49/0x49 [iwl4965] [] warn_slowpath_fmt+0x46/0x48 [] iwl4965_send_tx_power+0x61/0x102 [iwl4965] [] ? mutex_lock+0x36/0x50 [] iwl4965_bg_txpower_work+0x57/0x73 [iwl4965] [] process_one_work+0x18d/0x286 [] worker_thread+0xfd/0x181 [] ? manage_workers.clone.16+0x172/0x172 [] kthread+0x82/0x8a [] kernel_thread_helper+0x4/0x10 [] ? kthread_worker_fn+0x14b/0x14b [] ? gs_change+0x13/0x13 Reported-and-tested-by: Paul Bolle Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl4965-base.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index d484c3678163..a62fe24ee594 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -2984,15 +2984,15 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, txpower_work); + mutex_lock(&priv->mutex); + /* If a scan happened to start before we got here * then just return; the statistics notification will * kick off another scheduled work to compensate for * any temperature delta we missed here. */ if (test_bit(STATUS_EXIT_PENDING, &priv->status) || test_bit(STATUS_SCANNING, &priv->status)) - return; - - mutex_lock(&priv->mutex); + goto out; /* Regardless of if we are associated, we must reconfigure the * TX power since frames can be sent on non-radar channels while @@ -3002,7 +3002,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* Update last_temperature to keep is_calib_needed from running * when it isn't needed... */ priv->last_temperature = priv->temperature; - +out: mutex_unlock(&priv->mutex); } -- cgit v1.2.2 From 68972efa657040f891c7eda07c7da8c8dd576788 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Thu, 28 Apr 2011 05:43:37 +0000 Subject: usbnet: Resubmit interrupt URB if device is open Resubmit interrupt URB if device is open. Use a flag set in usbnet_open() to determine this state. Also kill and free interrupt URB in usbnet_disconnect(). [Rebased off git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git] Signed-off-by: Paul Stewart Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 069c1cf0fdf7..009bba3d753e 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -736,6 +736,7 @@ int usbnet_open (struct net_device *net) } } + set_bit(EVENT_DEV_OPEN, &dev->flags); netif_start_queue (net); netif_info(dev, ifup, dev->net, "open: enable queueing (rx %d, tx %d) mtu %d %s framing\n", @@ -1259,6 +1260,9 @@ void usbnet_disconnect (struct usb_interface *intf) if (dev->driver_info->unbind) dev->driver_info->unbind (dev, intf); + usb_kill_urb(dev->interrupt); + usb_free_urb(dev->interrupt); + free_netdev(net); usb_put_dev (xdev); } @@ -1498,6 +1502,10 @@ int usbnet_resume (struct usb_interface *intf) int retval; if (!--dev->suspend_count) { + /* resume interrupt URBs */ + if (dev->interrupt && test_bit(EVENT_DEV_OPEN, &dev->flags)) + usb_submit_urb(dev->interrupt, GFP_NOIO); + spin_lock_irq(&dev->txq.lock); while ((res = usb_get_from_anchor(&dev->deferred))) { -- cgit v1.2.2 From a9851832857dc1e4efefca1713f5cff3e168a25c Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Fri, 29 Apr 2011 10:42:19 +0200 Subject: [S390] irqstats: fix counting of pfault, dasd diag and virtio irqs pfault, dasd diag and virtio all use the same external interrupt number. The respective interrupt handlers decide by the subcode if they are meant to handle the interrupt. Counting is currently done before looking at the subcode which means each handler counts an interrupt even if it is not handling it. Fix this by moving the kstat code after the code which looks at the subcode. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_diag.c | 2 +- drivers/s390/kvm/kvm_virtio.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 29143eda9dd9..85dddb1e4126 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -239,7 +239,6 @@ static void dasd_ext_handler(unsigned int ext_int_code, addr_t ip; int rc; - kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; switch (ext_int_code >> 24) { case DASD_DIAG_CODE_31BIT: ip = (addr_t) param32; @@ -250,6 +249,7 @@ static void dasd_ext_handler(unsigned int ext_int_code, default: return; } + kstat_cpu(smp_processor_id()).irqs[EXTINT_DSD]++; if (!ip) { /* no intparm: unsolicited interrupt */ DBF_EVENT(DBF_NOTICE, "%s", "caught unsolicited " "interrupt"); diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index 414427d64a8f..607998f0b7d8 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -381,10 +381,10 @@ static void kvm_extint_handler(unsigned int ext_int_code, u16 subcode; u32 param; - kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; subcode = ext_int_code >> 16; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) return; + kstat_cpu(smp_processor_id()).irqs[EXTINT_VRT]++; /* The LSB might be overloaded, we have to mask it */ vq = (struct virtqueue *)(param64 & ~1UL); -- cgit v1.2.2 From 06268b2a384ece73618c1ad7649d19905ab79806 Mon Sep 17 00:00:00 2001 From: Peter Waechtler Date: Thu, 28 Apr 2011 20:53:58 +0200 Subject: HID: hiddev: fix error path in hiddev_read when interrupted hiddev_read: in case mutex_lock_interruptible will be interrupted remove the task from the wait queue. Signed-off-by: Peter Waechtler Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index af0a7c1002af..891ff531cf34 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -367,8 +367,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun /* let O_NONBLOCK tasks run */ mutex_unlock(&list->thread_lock); schedule(); - if (mutex_lock_interruptible(&list->thread_lock)) + if (mutex_lock_interruptible(&list->thread_lock)) { + finish_wait(&list->hiddev->wait, &wait); return -EINTR; + } set_current_state(TASK_INTERRUPTIBLE); } finish_wait(&list->hiddev->wait, &wait); -- cgit v1.2.2 From e296e1276ca389156d7f06eed668dac30141c37d Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 25 Apr 2011 14:48:18 -0300 Subject: [media] mceusb: add Dell transceiver ID Add device ID for a Dell-branded, Philips device ID transceiver reported by an OpenELEC user on their forums. http://openelec.tv/forum/27-hardware-support/5622-adding-support-for-an-ir-receiver--dell-branded--#5622 Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 044fb7a382d6..0c273ec465c9 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -220,6 +220,8 @@ static struct usb_device_id mceusb_dev_table[] = { { USB_DEVICE(VENDOR_PHILIPS, 0x206c) }, /* Philips/Spinel plus IR transceiver for ASUS */ { USB_DEVICE(VENDOR_PHILIPS, 0x2088) }, + /* Philips IR transceiver (Dell branded) */ + { USB_DEVICE(VENDOR_PHILIPS, 0x2093) }, /* Realtek MCE IR Receiver and card reader */ { USB_DEVICE(VENDOR_REALTEK, 0x0161), .driver_info = MULTIFUNCTION }, -- cgit v1.2.2 From d7516c7cf37a5fcb84b8f229947e3f52c62e19ae Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Mon, 25 Apr 2011 14:50:50 -0300 Subject: [media] ite-cir: modular build on ppc requires delay.h include Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ite-cir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index ac0e42b47b2a..9485dac35986 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.2 From b30039333ae2a1cdd19ebd856a69e96918a46637 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 26 Apr 2011 12:25:02 -0300 Subject: [media] rc: show RC_TYPE_OTHER in sysfs Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 5ac1baf45c8e..9f0a2d9f3d1e 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -733,6 +733,7 @@ static struct { { RC_TYPE_SONY, "sony" }, { RC_TYPE_RC5_SZ, "rc-5-sz" }, { RC_TYPE_LIRC, "lirc" }, + { RC_TYPE_OTHER, "other" }, }; #define PROTO_NONE "none" -- cgit v1.2.2 From 23ef710e1a6c4d6b9ef1c2fa19410f7f1479401e Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Wed, 27 Apr 2011 19:01:44 -0300 Subject: [media] imon: add conditional locking in change_protocol The imon_ir_change_protocol function gets called two different ways, one way is from rc_register_device, for initial protocol selection/setup, and the other is via a userspace-initiated protocol change request, either by direct sysfs prodding or by something like ir-keytable. In the rc_register_device case, the imon context lock is already held, but when initiated from userspace, it is not, so we must acquire it, prior to calling send_packet, which requires that the lock is held. Without this change, there's an easily reproduceable deadlock when another function calls send_packet (such as either of the display write fops) after a userspace-initiated change_protocol. With a lock-debugging-enabled kernel, I was getting this: [ 15.014153] ===================================== [ 15.015048] [ BUG: bad unlock balance detected! ] [ 15.015048] ------------------------------------- [ 15.015048] ir-keytable/773 is trying to release lock (&ictx->lock) at: [ 15.015048] [] mutex_unlock+0xe/0x10 [ 15.015048] but there are no more locks to release! [ 15.015048] [ 15.015048] other info that might help us debug this: [ 15.015048] 2 locks held by ir-keytable/773: [ 15.015048] #0: (&buffer->mutex){+.+.+.}, at: [] sysfs_write_file+0x3c/0x144 [ 15.015048] #1: (s_active#87){.+.+.+}, at: [] sysfs_write_file+0xe7/0x144 [ 15.015048] [ 15.015048] stack backtrace: [ 15.015048] Pid: 773, comm: ir-keytable Not tainted 2.6.38.4-20.fc15.x86_64.debug #1 [ 15.015048] Call Trace: [ 15.015048] [] ? print_unlock_inbalance_bug+0xca/0xd5 [ 15.015048] [] ? lock_release_non_nested+0xc1/0x263 [ 15.015048] [] ? mutex_unlock+0xe/0x10 [ 15.015048] [] ? mutex_unlock+0xe/0x10 [ 15.015048] [] ? lock_release+0x17d/0x1a4 [ 15.015048] [] ? __mutex_unlock_slowpath+0xc5/0x125 [ 15.015048] [] ? mutex_unlock+0xe/0x10 [ 15.015048] [] ? send_packet+0x1c9/0x264 [imon] [ 15.015048] [] ? lock_release_non_nested+0xdb/0x263 [ 15.015048] [] ? imon_ir_change_protocol+0x126/0x15e [imon] [ 15.015048] [] ? store_protocols+0x1c3/0x286 [rc_core] [ 15.015048] [] ? dev_attr_store+0x20/0x22 [ 15.015048] [] ? sysfs_write_file+0x108/0x144 ... The original report that led to the investigation was the following: [ 1679.457305] INFO: task LCDd:8460 blocked for more than 120 seconds. [ 1679.457307] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 1679.457309] LCDd D ffff88010fcd89c8 0 8460 1 0x00000000 [ 1679.457312] ffff8800d5a03b48 0000000000000082 0000000000000000 ffff8800d5a03fd8 [ 1679.457314] 00000000012dcd30 fffffffffffffffd ffff8800d5a03fd8 ffff88010fcd86f0 [ 1679.457316] ffff8800d5a03fd8 ffff8800d5a03fd8 ffff88010fcd89d0 ffff8800d5a03fd8 [ 1679.457319] Call Trace: [ 1679.457324] [] ? zone_statistics+0x75/0x90 [ 1679.457327] [] ? get_page_from_freelist+0x3c7/0x820 [ 1679.457330] [] __mutex_lock_slowpath+0x139/0x320 [ 1679.457335] [] mutex_lock+0x11/0x30 [ 1679.457338] [] display_open+0x66/0x130 [imon] [ 1679.457345] [] usb_open+0x180/0x310 [usbcore] [ 1679.457349] [] chrdev_open+0x1bb/0x2d0 [ 1679.457350] [] __dentry_open+0x10d/0x370 [ 1679.457352] [] ? chrdev_open+0x0/0x2d0 ... Bump the driver version here so its easier to tell if people have this locking fix or not, and also make locking during probe easier to follow. CC: stable@kernel.org Reported-by: Benjamin Hodgetts Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index f714e1a22c92..3ca86594feb8 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -46,7 +46,7 @@ #define MOD_AUTHOR "Jarod Wilson " #define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display" #define MOD_NAME "imon" -#define MOD_VERSION "0.9.2" +#define MOD_VERSION "0.9.3" #define DISPLAY_MINOR_BASE 144 #define DEVICE_NAME "lcd%d" @@ -460,8 +460,9 @@ static int display_close(struct inode *inode, struct file *file) } /** - * Sends a packet to the device -- this function must be called - * with ictx->lock held. + * Sends a packet to the device -- this function must be called with + * ictx->lock held, or its unlock/lock sequence while waiting for tx + * to complete can/will lead to a deadlock. */ static int send_packet(struct imon_context *ictx) { @@ -991,12 +992,21 @@ static void imon_touch_display_timeout(unsigned long data) * the iMON remotes, and those used by the Windows MCE remotes (which is * really just RC-6), but only one or the other at a time, as the signals * are decoded onboard the receiver. + * + * This function gets called two different ways, one way is from + * rc_register_device, for initial protocol selection/setup, and the other is + * via a userspace-initiated protocol change request, either by direct sysfs + * prodding or by something like ir-keytable. In the rc_register_device case, + * the imon context lock is already held, but when initiated from userspace, + * it is not, so we must acquire it prior to calling send_packet, which + * requires that the lock is held. */ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) { int retval; struct imon_context *ictx = rc->priv; struct device *dev = ictx->dev; + bool unlock = false; unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; @@ -1029,6 +1039,11 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); + if (!mutex_is_locked(&ictx->lock)) { + unlock = true; + mutex_lock(&ictx->lock); + } + retval = send_packet(ictx); if (retval) goto out; @@ -1037,6 +1052,9 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) ictx->pad_mouse = false; out: + if (unlock) + mutex_unlock(&ictx->lock); + return retval; } @@ -2134,6 +2152,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) goto rdev_setup_failed; } + mutex_unlock(&ictx->lock); return ictx; rdev_setup_failed: @@ -2205,6 +2224,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, goto urb_submit_failed; } + mutex_unlock(&ictx->lock); return ictx; urb_submit_failed: @@ -2299,6 +2319,8 @@ static int __devinit imon_probe(struct usb_interface *interface, usb_set_intfdata(interface, ictx); if (ifnum == 0) { + mutex_lock(&ictx->lock); + if (product == 0xffdc && ictx->rf_device) { sysfs_err = sysfs_create_group(&interface->dev.kobj, &imon_rf_attr_group); @@ -2309,13 +2331,14 @@ static int __devinit imon_probe(struct usb_interface *interface, if (ictx->display_supported) imon_init_display(ictx, interface); + + mutex_unlock(&ictx->lock); } dev_info(dev, "iMON device (%04x:%04x, intf%d) on " "usb<%d:%d> initialized\n", vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum); - mutex_unlock(&ictx->lock); mutex_unlock(&driver_lock); return 0; -- cgit v1.2.2 From 5a4e5e6a701bea7d3cbeed19fa9ea45802e8fabb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 29 Apr 2011 16:33:35 +0200 Subject: hwmon: (lm90) Add support for ADT7461A and NCT1008 This patch adds support for ADT7461A and NCT1008 to the lm90 driver. Both chips have identical functionality and report the same manufacturing ID and device ID values. Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 8 ++++---- drivers/hwmon/lm90.c | 22 +++++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 060ef6327876..92d02512bcde 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -618,10 +618,10 @@ config SENSORS_LM90 depends on I2C help If you say yes here you get support for National Semiconductor LM90, - LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, Maxim - MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, - MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, and Winbond/Nuvoton - W83L771W/G/AWG/ASG sensor chips. + LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, + Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, + MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, + and Winbond/Nuvoton W83L771W/G/AWG/ASG sensor chips. This driver can also be built as a module. If so, the module will be called lm90. diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index c43b4e9f96a9..2f94f9504804 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -49,10 +49,10 @@ * chips, but support three temperature sensors instead of two. MAX6695 * and MAX6696 only differ in the pinout so they can be treated identically. * - * This driver also supports the ADT7461 chip from Analog Devices. - * It's supported in both compatibility and extended mode. It is mostly - * compatible with LM90 except for a data format difference for the - * temperature value registers. + * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as + * NCT1008 from ON Semiconductor. The chips are supported in both compatibility + * and extended mode. They are mostly compatible with LM90 except for a data + * format difference for the temperature value registers. * * Since the LM90 was the first chipset supported by this driver, most * comments will refer to this chipset, but are actually general and @@ -88,9 +88,10 @@ * Addresses to scan * Address is fully defined internally and cannot be changed except for * MAX6659, MAX6680 and MAX6681. - * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6649, MAX6657, - * MAX6658 and W83L771 have address 0x4c. - * ADM1032-2, ADT7461-2, LM89-1, LM99-1 and MAX6646 have address 0x4d. + * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649, + * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c. + * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D + * have address 0x4d. * MAX6647 has address 0x4e. * MAX6659 can have address 0x4c, 0x4d or 0x4e. * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, @@ -174,6 +175,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680, static const struct i2c_device_id lm90_id[] = { { "adm1032", adm1032 }, { "adt7461", adt7461 }, + { "adt7461a", adt7461 }, { "lm90", lm90 }, { "lm86", lm86 }, { "lm89", lm86 }, @@ -188,6 +190,7 @@ static const struct i2c_device_id lm90_id[] = { { "max6681", max6680 }, { "max6695", max6696 }, { "max6696", max6696 }, + { "nct1008", adt7461 }, { "w83l771", w83l771 }, { } }; @@ -1153,6 +1156,11 @@ static int lm90_detect(struct i2c_client *new_client, && (reg_config1 & 0x1B) == 0x00 && reg_convrate <= 0x0A) { name = "adt7461"; + } else + if (chip_id == 0x57 /* ADT7461A, NCT1008 */ + && (reg_config1 & 0x1B) == 0x00 + && reg_convrate <= 0x0A) { + name = "adt7461a"; } } else if (man_id == 0x4D) { /* Maxim */ -- cgit v1.2.2 From d7ce0335b5ddbe4cc1c519750074b5176a4124ab Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 29 Apr 2011 16:33:36 +0200 Subject: hwmon: (adm1021) Clarify documentation regarding Xeon processors Recent Xeon processor thermal sensors are supported by the coretemp driver and not the adm1021 driver. Only one old generation of Xeon processors (the first Netburst ones) are supported by the adm1021 driver. Reported-by: Darren Hart Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 92d02512bcde..50e40dbd8bb6 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -110,8 +110,7 @@ config SENSORS_ADM1021 help If you say yes here you get support for Analog Devices ADM1021 and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10, - and the XEON processor built-in sensor. + Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10. This driver can also be built as a module. If so, the module will be called adm1021. -- cgit v1.2.2 From 5f441e2256506a5878d276399e0a22a13942fe4b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 29 Apr 2011 16:33:36 +0200 Subject: hwmon: (lm85) Add missing list terminators Fixes kernel bug #34072: https://bugzilla.kernel.org/show_bug.cgi?id=34072 Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/lm85.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 250d099ca398..b5a6bc48597e 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1094,6 +1094,7 @@ static struct attribute *lm85_attributes_minctl[] = { &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr, &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_minctl = { @@ -1104,6 +1105,7 @@ static struct attribute *lm85_attributes_temp_off[] = { &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr, &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr, + NULL }; static const struct attribute_group lm85_group_temp_off = { -- cgit v1.2.2 From bc4d45f1901042a295b10949f51d24cce223e65d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 29 Apr 2011 16:33:36 +0200 Subject: hwmon: (lm85) Fix error paths in probe function We must remove all files we created, even in error cases. Fixes second part of kernel bug #34072: https://bugzilla.kernel.org/show_bug.cgi?id=34072 Signed-off-by: Jean Delvare Acked-by: Guenter Roeck --- drivers/hwmon/lm85.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index b5a6bc48597e..da72dc12068c 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -1331,11 +1331,11 @@ static int lm85_probe(struct i2c_client *client, if (data->type != emc6d103s) { err = sysfs_create_group(&client->dev.kobj, &lm85_group_minctl); if (err) - goto err_kfree; + goto err_remove_files; err = sysfs_create_group(&client->dev.kobj, &lm85_group_temp_off); if (err) - goto err_kfree; + goto err_remove_files; } /* The ADT7463/68 have an optional VRM 10 mode where pin 21 is used -- cgit v1.2.2 From 88fda5619e6cd7988dc1d9a52f2da9ee8fd0e64d Mon Sep 17 00:00:00 2001 From: Hussam Al-Tayeb Date: Mon, 21 Feb 2011 15:20:26 -0300 Subject: [media] rc_core: avoid kernel oops when rmmod saa7134 The following is a patch to avoid a kernel oops when running rmmod saa7134 on kernel 2.6.27.1. The change is as suggested by mchehab on irc.freenode.org Signed-off-by: Hussam Al-Tayeb Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 9f0a2d9f3d1e..33afd98938da 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -707,7 +707,8 @@ static void ir_close(struct input_dev *idev) { struct rc_dev *rdev = input_get_drvdata(idev); - rdev->close(rdev); + if (rdev) + rdev->close(rdev); } /* class for /sys/class/rc */ -- cgit v1.2.2 From 2b5cb549f8a31b44575fe25ccd043ddb7e901cf8 Mon Sep 17 00:00:00 2001 From: Malcolm Priestley Date: Tue, 22 Feb 2011 03:14:34 -0300 Subject: [media] Missing frontend config for LME DM04/QQBOX Forgot to add the DVB_STV0299/DVB_PLL to config Signed-off-by: Malcolm Priestley Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index ccbd39a38c46..c545039287ad 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -356,6 +356,8 @@ config DVB_USB_LME2510 select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_STV0288 if !DVB_FE_CUSTOMISE select DVB_IX2505V if !DVB_FE_CUSTOMISE + select DVB_STV0299 if !DVB_FE_CUSTOMISE + select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 . -- cgit v1.2.2 From 80845a33165278f3236812009e9c568ba8c29938 Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Fri, 1 Apr 2011 14:12:02 -0300 Subject: [media] v4l: make sure drivers supply a zeroed struct v4l2_subdev Some v4l drivers currently don't initialize their struct v4l2_subdev with zeros, and this is a problem since some of the v4l2 code expects this. One example is the addition of internal_ops in commit 45f6f84, after that we are at risk of random oopses with these drivers when code in v4l2_device_register_subdev tries to dereference sd->internal_ops->*, as can be shown by the report at http://bugs.launchpad.net/bugs/745213 and analysis of its crash at https://lkml.org/lkml/2011/4/1/168 Use kzalloc within problematic drivers to ensure we have a zeroed struct v4l2_subdev. BugLink: http://bugs.launchpad.net/bugs/745213 Cc: Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/saa7706h.c | 2 +- drivers/media/radio/tef6862.c | 2 +- drivers/media/video/m52790.c | 2 +- drivers/media/video/tda9840.c | 2 +- drivers/media/video/tea6415c.c | 2 +- drivers/media/video/tea6420.c | 2 +- drivers/media/video/upd64031a.c | 2 +- drivers/media/video/upd64083.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index 585680ffbfb6..b1193dfc5087 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c @@ -376,7 +376,7 @@ static int __devinit saa7706h_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct saa7706h_state), GFP_KERNEL); + state = kzalloc(sizeof(struct saa7706h_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 7c0d77751f6e..0991e1973678 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -176,7 +176,7 @@ static int __devinit tef6862_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct tef6862_state), GFP_KERNEL); + state = kzalloc(sizeof(struct tef6862_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; state->freq = TEF6862_LO_FREQ; diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index 5e1c9a81984c..303ffa7df4ac 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -174,7 +174,7 @@ static int m52790_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); + state = kzalloc(sizeof(struct m52790_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index 5d4cf3b3d435..22fa8202d5ca 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -171,7 +171,7 @@ static int tda9840_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tda9840_ops); diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index 19621ed523ec..827425c5b866 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -152,7 +152,7 @@ static int tea6415c_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tea6415c_ops); diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index 5ea840401f21..f350b6c24500 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -125,7 +125,7 @@ static int tea6420_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = kmalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); if (sd == NULL) return -ENOMEM; v4l2_i2c_subdev_init(sd, client, &tea6420_ops); diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index f8138c75be8b..1aab96a88203 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -230,7 +230,7 @@ static int upd64031a_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); + state = kzalloc(sizeof(struct upd64031a_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 28e0e6b6ca84..9bbe61700fd5 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -202,7 +202,7 @@ static int upd64083_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); + state = kzalloc(sizeof(struct upd64083_state), GFP_KERNEL); if (state == NULL) return -ENOMEM; sd = &state->sd; -- cgit v1.2.2 From b730011061e2805a46b7291e708b6caaf2be6869 Mon Sep 17 00:00:00 2001 From: Oliver Endriss Date: Tue, 29 Mar 2011 17:35:24 -0300 Subject: [media] ngene: Fix CI data transfer regression Fix CI data transfer regression introduced by previous cleanup. Signed-off-by: Oliver Endriss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/ngene/ngene-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 175a0f6c2a4c..96307056589d 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c @@ -1520,6 +1520,7 @@ static int init_channel(struct ngene_channel *chan) if (dev->ci.en && (io & NGENE_IO_TSOUT)) { dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); set_transfer(chan, 1); + chan->dev->channel[2].DataFormatFlags = DF_SWAP32; set_transfer(&chan->dev->channel[2], 1); dvb_register_device(adapter, &chan->ci_dev, &ngene_dvbdev_ci, (void *) chan, -- cgit v1.2.2 From bfd36103ec26599557c2bd3225a1f1c9267f8fcb Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 29 Apr 2011 17:51:06 +0200 Subject: iwlagn: fix "Received BA when not expected" Need to use broadcast sta_id for management frames, otherwise we broke BA session in the firmware and get messages like that: "Received BA when not expected" or (on older kernels): "BA scd_flow 0 does not match txq_id 10" This fix regression introduced in 2.6.35 during station management code rewrite by: commit 2a87c26bbe9587baeb9e56d3ce0b4971bd777643 Author: Johannes Berg Date: Fri Apr 30 11:30:45 2010 -0700 iwlwifi: use iwl_find_station less Patch partially resolve: https://bugzilla.kernel.org/show_bug.cgi?id=16691 However, there are still 11n performance problems on 4965 and 5xxx devices that need to be investigated. Cc: stable@kernel.org # 2.6.35+ Signed-off-by: Stanislaw Gruszka Acked-by: Johannes Berg Acked-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 2dd7d54a796f..0712b67283a4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -568,12 +568,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_sta_id_or_broadcast(priv, ctx, info->control.sta); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); -- cgit v1.2.2 From 16b345d89686ca0482a9ca741a1167def1abdd7f Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 29 Apr 2011 17:51:56 +0200 Subject: iwl4965: fix "Received BA when not expected" Need to use broadcast sta_id for management frames, otherwise we broke BA session in the firmware and get messages like that: "Received BA when not expected" or (on older kernels): "BA scd_flow 0 does not match txq_id 10" This fix regression introduced in 2.6.35 during station management code rewrite by: commit 2a87c26bbe9587baeb9e56d3ce0b4971bd777643 Author: Johannes Berg Date: Fri Apr 30 11:30:45 2010 -0700 iwlwifi: use iwl_find_station less Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-4965-tx.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index fbec88d48f1b..79ac081832fb 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -316,12 +316,18 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) hdr_len = ieee80211_hdrlen(fc); - /* Find index into station table for destination station */ - sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", - hdr->addr1); - goto drop_unlock; + /* For management frames use broadcast id to do not break aggregation */ + if (!ieee80211_is_data(fc)) + sta_id = ctx->bcast_sta_id; + else { + /* Find index into station table for destination station */ + sta_id = iwl_legacy_sta_id_or_broadcast(priv, ctx, info->control.sta); + + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", + hdr->addr1); + goto drop_unlock; + } } IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); -- cgit v1.2.2 From 8333a46ad3877485e4d67ef499c6dda36bfd1f9a Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 26 Apr 2011 10:30:11 +0000 Subject: bnx2: cancel timer on device removal This oops was recently reported to me: invalid opcode: 0000 [#1] SMP last sysfs file: /sys/devices/pci0000:00/0000:00:01.0/0000:01:0d.0/0000:02:05.0/device CPU 1 Modules linked in: bnx2(+) sunrpc ipv6 dm_mirror dm_region_hash dm_log sg microcode serio_raw amd64_edac_mod edac_core edac_mce_amd k8temp i2c_piix4 shpchp ext4 mbcache jbd2 sd_mod crc_t10dif mptsas mptscsih mptbase scsi_transport_sas radeon ttm drm_kms_helper drm hwmon i2c_algo_bit i2c_core dm_mod [last unloaded: bnx2] Modules linked in: bnx2(+) sunrpc ipv6 dm_mirror dm_region_hash dm_log sg microcode serio_raw amd64_edac_mod edac_core edac_mce_amd k8temp i2c_piix4 shpchp ext4 mbcache jbd2 sd_mod crc_t10dif mptsas mptscsih mptbase scsi_transport_sas radeon ttm drm_kms_helper drm hwmon i2c_algo_bit i2c_core dm_mod [last unloaded: bnx2] Pid: 23900, comm: pidof Not tainted 2.6.32-130.el6.x86_64 #1 BladeCenter LS21 -[797251Z]- RIP: 0010:[] [] 0xffffffffa058b270 RSP: 0018:ffff880002083e48 EFLAGS: 00010246 RAX: ffff880002083e90 RBX: ffff88007ccd4000 RCX: 0000000000000000 RDX: 0000000000000100 RSI: dead000000200200 RDI: ffff8800007b8700 RBP: ffff880002083ed0 R08: ffff88000208db40 R09: 0000022d191d27c8 R10: 0000000000000000 R11: 0000000000000000 R12: ffff8800007b9bc8 R13: ffff880002083e90 R14: ffff8800007b8700 R15: ffffffffa058b270 FS: 00007fbb3bcf7700(0000) GS:ffff880002080000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000001664a98 CR3: 0000000060395000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process pidof (pid: 23900, threadinfo ffff8800007e8000, task ffff8800091c0040) Stack: ffffffff81079f77 ffffffff8109e010 ffff88007ccd5c20 ffff88007ccd5820 <0> ffff88007ccd5420 ffff8800007e9fd8 ffff8800007e9fd8 0000010000000000 <0> ffff88007ccd5020 ffff880002083e90 ffff880002083e90 ffffffff8102a00d Call Trace: [] ? run_timer_softirq+0x197/0x340 [] ? tick_sched_timer+0x0/0xc0 [] ? lapic_next_event+0x1d/0x30 [] __do_softirq+0xb7/0x1e0 [] ? hrtimer_interrupt+0x140/0x250 [] ? filldir+0x0/0xe0 [] call_softirq+0x1c/0x30 [] do_softirq+0x65/0xa0 [] irq_exit+0x85/0x90 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] ? selinux_file_permission+0x45/0x150 [] ? _atomic_dec_and_lock+0x55/0x80 [] security_file_permission+0x16/0x20 [] vfs_readdir+0x71/0xe0 [] sys_getdents+0x89/0xf0 [] system_call_fastpath+0x16/0x1b It occured during some stress testing, in which the reporter was repeatedly removing and modprobing the bnx2 module while doing various other random operations on the bnx2 registered net device. Noting that this error occured on a serdes based device, we noted that there were a few ethtool operations (most notably self_test and set_phys_id) that have execution paths that lead into bnx2_setup_serdes_phy. This function is notable because it executes a mod_timer call, which starts the bp->timer running. Currently bnx2 is setup to assume that this timer only nees to be stopped when bnx2_close or bnx2_suspend is called. Since the above ethtool operations are not gated on the net device having been opened however, that assumption is incorrect, and can lead to the timer still running after the module has been removed, leading to the oops above (as well as other simmilar oopses). Fix the problem by ensuring that the timer is stopped when pci_device_unregister is called. Signed-off-by: Neil Horman Reported-by: Hushan Jia CC: Michael Chan CC: "David S. Miller" Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8e6d618b5305..d8383a9af9ad 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -8413,6 +8413,8 @@ bnx2_remove_one(struct pci_dev *pdev) unregister_netdev(dev); + del_timer_sync(&bp->timer); + if (bp->mips_firmware) release_firmware(bp->mips_firmware); if (bp->rv2p_firmware) -- cgit v1.2.2 From b3c914aa84f4e4bbb3efc8f41c359d96e5e932d2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 27 Apr 2011 09:54:28 +0000 Subject: usbnet: add support for some Huawei modems with cdc-ether ports Some newer Huawei devices (T-Mobile Rocket, others) have cdc-ether compatible ports, so recognize and expose them. Signed-off-by: Dan Williams Acked-by: Oliver Neukum Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 341f7056a800..a301479ecc60 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -460,7 +460,7 @@ static const struct driver_info cdc_info = { .manage_power = cdc_manage_power, }; -static const struct driver_info mbm_info = { +static const struct driver_info wwan_info = { .description = "Mobile Broadband Network Device", .flags = FLAG_WWAN, .bind = usbnet_cdc_bind, @@ -471,6 +471,7 @@ static const struct driver_info mbm_info = { /*-------------------------------------------------------------------------*/ +#define HUAWEI_VENDOR_ID 0x12D1 static const struct usb_device_id products [] = { /* @@ -587,8 +588,17 @@ static const struct usb_device_id products [] = { }, { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&mbm_info, + .driver_info = (unsigned long)&wwan_info, +}, { + /* Various Huawei modems with a network port like the UMG1831 */ + .match_flags = USB_DEVICE_ID_MATCH_VENDOR + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = HUAWEI_VENDOR_ID, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, + .bInterfaceProtocol = 255, + .driver_info = (unsigned long)&wwan_info, }, { }, // END }; -- cgit v1.2.2 From eee9700c5dd8fbac517c8c1e85c60b688bc311a9 Mon Sep 17 00:00:00 2001 From: Adam Jaremko Date: Thu, 28 Apr 2011 07:41:18 +0000 Subject: net: ftmac100: fix scheduling while atomic during PHY link status change Signed-off-by: Adam Jaremko Acked-by: Po-Yu Chuang Signed-off-by: David S. Miller --- drivers/net/ftmac100.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ftmac100.c b/drivers/net/ftmac100.c index a31661948c42..9bd7746cbfcf 100644 --- a/drivers/net/ftmac100.c +++ b/drivers/net/ftmac100.c @@ -139,11 +139,11 @@ static int ftmac100_reset(struct ftmac100 *priv) * that hardware reset completed (what the f*ck). * We still need to wait for a while. */ - usleep_range(500, 1000); + udelay(500); return 0; } - usleep_range(1000, 10000); + udelay(1000); } netdev_err(netdev, "software reset failed\n"); @@ -772,7 +772,7 @@ static int ftmac100_mdio_read(struct net_device *netdev, int phy_id, int reg) if ((phycr & FTMAC100_PHYCR_MIIRD) == 0) return phycr & FTMAC100_PHYCR_MIIRDATA; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio read timed out\n"); @@ -801,7 +801,7 @@ static void ftmac100_mdio_write(struct net_device *netdev, int phy_id, int reg, if ((phycr & FTMAC100_PHYCR_MIIWR) == 0) return; - usleep_range(100, 1000); + udelay(100); } netdev_err(netdev, "mdio write timed out\n"); -- cgit v1.2.2 From 2b5a4ace664cfe05c17bee60c4da66263a05fccf Mon Sep 17 00:00:00 2001 From: artpol Date: Wed, 27 Apr 2011 17:49:14 +0000 Subject: mii: add support of pause frames in mii_get_an Add support of pause frames advertise in mii_get_an. This provides all drivers that use mii_ethtool_gset to represent their own and Link partner flow control abilities in ethtool. Signed-off-by: Artem Polyakov Signed-off-by: David S. Miller --- drivers/net/mii.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 0a6c6a2e7550..d4fc00b1ff93 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c @@ -49,6 +49,10 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr) result |= ADVERTISED_100baseT_Half; if (advert & ADVERTISE_100FULL) result |= ADVERTISED_100baseT_Full; + if (advert & ADVERTISE_PAUSE_CAP) + result |= ADVERTISED_Pause; + if (advert & ADVERTISE_PAUSE_ASYM) + result |= ADVERTISED_Asym_Pause; return result; } -- cgit v1.2.2 From e8bf8df9c296b782c32236c6a5893aec301320c7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 30 Apr 2011 10:14:08 +0100 Subject: CLKDEV: Fix clkdev return value for NULL clk case clkdev may incorrectly cause a clkdev entry with a NULL clk to return -ENOENT. This is not the intention of this code; -ENOENT should only be returned if the clock entry can not be found in the table. Fix this. Reported-by: Stephen Boyd Signed-off-by: Russell King --- drivers/clk/clkdev.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 0fc0a79852de..6db161f64ae0 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -32,10 +32,9 @@ static DEFINE_MUTEX(clocks_mutex); * 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) +static struct clk_lookup *clk_find(const char *dev_id, const char *con_id) { - struct clk_lookup *p; - struct clk *clk = NULL; + struct clk_lookup *p, *cl = NULL; int match, best = 0; list_for_each_entry(p, &clocks, node) { @@ -52,27 +51,27 @@ static struct clk *clk_find(const char *dev_id, const char *con_id) } if (match > best) { - clk = p->clk; + cl = p; if (match != 3) best = match; else break; } } - return clk; + return cl; } struct clk *clk_get_sys(const char *dev_id, const char *con_id) { - struct clk *clk; + struct clk_lookup *cl; mutex_lock(&clocks_mutex); - clk = clk_find(dev_id, con_id); - if (clk && !__clk_get(clk)) - clk = NULL; + cl = clk_find(dev_id, con_id); + if (cl && !__clk_get(cl->clk)) + cl = NULL; mutex_unlock(&clocks_mutex); - return clk ? clk : ERR_PTR(-ENOENT); + return cl ? cl->clk : ERR_PTR(-ENOENT); } EXPORT_SYMBOL(clk_get_sys); -- cgit v1.2.2 From c30aa39c233ca1df8397eb9e9c8b40a397ce72bb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 1 May 2011 11:34:55 -0400 Subject: hwmon: (twl4030-madc-hwmon) Return proper error if hwmon_device_register fails The driver did not return an error if the call to hwmon_device_register failed. Fix by returning the error reported from hwmon_device_register. Signed-off-by: Axel Lin Signed-off-by: Guenter Roeck --- drivers/hwmon/twl4030-madc-hwmon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index de5819199e2e..57240740b161 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -98,7 +98,6 @@ static const struct attribute_group twl4030_madc_group = { static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) { int ret; - int status; struct device *hwmon; ret = sysfs_create_group(&pdev->dev.kobj, &twl4030_madc_group); @@ -107,7 +106,7 @@ static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) hwmon = hwmon_device_register(&pdev->dev); if (IS_ERR(hwmon)) { dev_err(&pdev->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(hwmon); + ret = PTR_ERR(hwmon); goto err_reg; } -- cgit v1.2.2 From a6e5e2be44616c8400f9ec2f635b10f8e579217c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 1 May 2011 18:18:49 +0200 Subject: i2c-i801: Move device ID definitions to driver Move the SMBus device ID definitions of recent devices from pci_ids.h to the i2c-i801.c driver file. They don't have to be shared, as they are clearly identified and only used in this driver. In the future, such IDs will go to i2c-i801 directly. This will make adding support for new devices much faster and easier, as it will avoid cross- subsystem patch sets and merge conflicts. Signed-off-by: Jean Delvare Cc: Seth Heasley Acked-by: Jesse Barnes --- drivers/i2c/busses/i2c-i801.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 72c0415f6f94..455e909bc768 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -134,10 +134,15 @@ SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \ SMBHSTSTS_INTR) +/* Older devices have their ID defined in */ +#define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72 +#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 +#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 struct i801_priv { struct i2c_adapter adapter; -- cgit v1.2.2 From 56acc7a39ac4ac7638cdc32cd3d0832ebbc834e4 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 1 May 2011 18:18:49 +0200 Subject: i2c-parport: Fix adapter list handling Use a standard list with proper locking to handle the list of adapters. Thankfully it only matters on systems with more than one parallel port, which are very rare. Thanks to Lukasz Kapiec for reporting the problem to me. Signed-off-by: Jean Delvare Cc: stable@kernel.org --- drivers/i2c/busses/i2c-parport.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0eb1515541e7..2dbba163b102 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2010 Jean Delvare + Copyright (C) 2003-2011 Jean Delvare Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "i2c-parport.h" /* ----- Device list ------------------------------------------------------ */ @@ -43,10 +45,11 @@ struct i2c_par { struct i2c_algo_bit_data algo_data; struct i2c_smbus_alert_setup alert_data; struct i2c_client *ara; - struct i2c_par *next; + struct list_head node; }; -static struct i2c_par *adapter_list; +static LIST_HEAD(adapter_list); +static DEFINE_MUTEX(adapter_list_lock); /* ----- Low-level parallel port access ----------------------------------- */ @@ -228,8 +231,9 @@ static void i2c_parport_attach (struct parport *port) } /* Add the new adapter to the list */ - adapter->next = adapter_list; - adapter_list = adapter; + mutex_lock(&adapter_list_lock); + list_add_tail(&adapter->node, &adapter_list); + mutex_unlock(&adapter_list_lock); return; ERROR1: @@ -241,11 +245,11 @@ ERROR0: static void i2c_parport_detach (struct parport *port) { - struct i2c_par *adapter, *prev; + struct i2c_par *adapter, *_n; /* Walk the list */ - for (prev = NULL, adapter = adapter_list; adapter; - prev = adapter, adapter = adapter->next) { + mutex_lock(&adapter_list_lock); + list_for_each_entry_safe(adapter, _n, &adapter_list, node) { if (adapter->pdev->port == port) { if (adapter->ara) { parport_disable_irq(port); @@ -259,14 +263,11 @@ static void i2c_parport_detach (struct parport *port) parport_release(adapter->pdev); parport_unregister_device(adapter->pdev); - if (prev) - prev->next = adapter->next; - else - adapter_list = adapter->next; + list_del(&adapter->node); kfree(adapter); - return; } } + mutex_unlock(&adapter_list_lock); } static struct parport_driver i2c_parport_driver = { -- cgit v1.2.2 From 383cf4e8d47f902600263191f8f167379c376985 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Wed, 27 Apr 2011 17:02:37 +0300 Subject: usb: musb: omap2430: Fix retention idle on musb peripheral only boards Recent runtime pm and hwmod conversions for 2.6.39 broke the musb peripheral mode OMAP retention idle on boards where the board mode in struct musb_hdrc_platform_data is set to MUSB_PERIPHERAL. These conversions changed the way how the OTG_SYSCONFIG register is configured and used in runtime. Before 2.6.39 smart standby/idle modes were activated statically in OTG_SYSCONFIG. Those modes allow that the musb is able to idle when peripheral device is not connected to host. In 2.6.39 the OTG_SYSCONFIG is updated runtime depending on VBUS status. No standby/idle modes are used when device is connected and force standby/idle when disconnected. Unfortunately VBUS disconnect event that handles the disconnect case lets the peripheral musb to idle only when board mode is MUSB_OTG. Fix this by checking the peripheral mode also. Signed-off-by: Jarkko Nikula Signed-off-by: Felipe Balbi --- drivers/usb/musb/omap2430.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 57a27fa954b4..e9e60b6e0583 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -270,7 +270,7 @@ static int musb_otg_notifications(struct notifier_block *nb, DBG(4, "VBUS Disconnect\n"); #ifdef CONFIG_USB_GADGET_MUSB_HDRC - if (is_otg_enabled(musb)) + if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) if (musb->gadget_driver) #endif { -- cgit v1.2.2 From cdefce169594742ace29a2016dfa381755428ab5 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 29 Apr 2011 16:17:35 +0300 Subject: usb: musb: gadget: Fix out-of-sync runtime pm calls If cable is not connected to peripheral only board when initializing the gadget driver, then runtime pm calls are out-of-sync and the musb cannot idle with omap2430.c. This was noted on Nokia N900 where musb prevented the CPU to be able to enter deeper retention idle state. This was working in 2.6.38 before runtime pm conversions but there musb smart standby/idle modes were configured statically where they are now updated runtime depending on use and cable status. Reason for out-of-sync is that runtime pm is activated in function musb_gadget.c: usb_gadget_probe_driver but suspended only in OTG mode if cable is not connected when initializing. In peripheral only mode this leads to out-of-sync runtime pm since runtime pm remain active and is activated another time in omap2430.c: musb_otg_notifications for VBUS Connect event and thus cannot suspend for VBUS Disconnect event since the use count remains active. Fix this by moving cable status check and pm_runtime_put call in usb_gadget_probe_driver out of is_otg_enabled block. Signed-off-by: Jarkko Nikula Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_gadget.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 6dfbf9ffd7a6..f47c20197c61 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1887,11 +1887,9 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, otg_set_vbus(musb->xceiv, 1); hcd->self.uses_pio_for_control = 1; - - if (musb->xceiv->last_event == USB_EVENT_NONE) - pm_runtime_put(musb->controller); - } + if (musb->xceiv->last_event == USB_EVENT_NONE) + pm_runtime_put(musb->controller); return 0; -- cgit v1.2.2 From d11536e4e0e99c26d33c849b44cd279cdd67b032 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 21 Apr 2011 19:52:41 +0530 Subject: mfd: Fix usbhs_enable error handling In the case of missing platform_data we do not hold a spin_lock, thus we should not call spin_unlock_irqrestore in the error path. Also simplify the error handling by separating the successful path from error path. I think this change improves readability. Signed-off-by: Axel Lin Tested-by: Steve Calfee Signed-off-by: Felipe Balbi --- drivers/mfd/omap-usb-host.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 53450f433f10..b3bb3ac5b045 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -700,8 +700,7 @@ static int usbhs_enable(struct device *dev) dev_dbg(dev, "starting TI HSUSB Controller\n"); if (!pdata) { dev_dbg(dev, "missing platform_data\n"); - ret = -ENODEV; - goto end_enable; + return -ENODEV; } spin_lock_irqsave(&omap->lock, flags); @@ -915,7 +914,8 @@ static int usbhs_enable(struct device *dev) end_count: omap->count++; - goto end_enable; + spin_unlock_irqrestore(&omap->lock, flags); + return 0; err_tll: if (pdata->ehci_data->phy_reset) { @@ -931,8 +931,6 @@ err_tll: clk_disable(omap->usbhost_fs_fck); clk_disable(omap->usbhost_hs_fck); clk_disable(omap->usbhost_ick); - -end_enable: spin_unlock_irqrestore(&omap->lock, flags); return ret; } -- cgit v1.2.2 From 6e3d4bec6b1e0829ed8b23be750762255f225019 Mon Sep 17 00:00:00 2001 From: Keshava Munegowda Date: Thu, 21 Apr 2011 19:52:43 +0530 Subject: omap:usb: add regulator support for EHCI in case of ehci phy mode; regulator of phy should be enabled before initializing the usbhs core driver. Signed-off-by: Keshava Munegowda Tested-by: Steve Calfee Signed-off-by: Felipe Balbi --- drivers/mfd/omap-usb-host.c | 1 - drivers/usb/host/ehci-omap.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index b3bb3ac5b045..2e165117457b 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #define USBHS_DRIVER_NAME "usbhs-omap" diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 7e41a95c5ceb..627f3a678759 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -40,6 +40,7 @@ #include #include #include +#include /* EHCI Register Set */ #define EHCI_INSNREG04 (0xA0) @@ -118,6 +119,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) struct ehci_hcd *omap_ehci; int ret = -ENODEV; int irq; + int i; + char supply[7]; if (usb_disabled()) return -ENODEV; @@ -158,6 +161,23 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) hcd->rsrc_len = resource_size(res); hcd->regs = regs; + /* get ehci regulator and enable */ + for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { + if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { + pdata->regulator[i] = NULL; + continue; + } + snprintf(supply, sizeof(supply), "hsusb%d", i); + pdata->regulator[i] = regulator_get(dev, supply); + if (IS_ERR(pdata->regulator[i])) { + pdata->regulator[i] = NULL; + dev_dbg(dev, + "failed to get ehci port%d regulator\n", i); + } else { + regulator_enable(pdata->regulator[i]); + } + } + ret = omap_usbhs_enable(dev); if (ret) { dev_err(dev, "failed to start usbhs with err %d\n", ret); -- cgit v1.2.2 From 2e053a27d9d5ad5e0831e002cbf8043836fb2060 Mon Sep 17 00:00:00 2001 From: "B.J. Buchalter" Date: Mon, 2 May 2011 13:33:42 -0400 Subject: firewire: Fix for broken configrom updates in quick succession Current implementation of ohci_set_config_rom() uses a deferred bus reset via fw_schedule_bus_reset(). If clients add multiple unit descriptors to the config_rom in quick succession, the deferred bus reset may not have fired before succeeding update requests have come in. This can lead to an incorrect partial update of the config_rom for both addition and removal of config_rom descriptors, as the ohci_set_config_rom() routine will return -EBUSY if a previous pending update has not been completed yet; the requested update just gets dropped on the floor. This patch recognizes that the "in-flight" update can be modified until it has been processed by the bus-reset, and the locking in the bus_reset_tasklet ensures that the update is done atomically with respect to modifications made by ohci_set_config_rom(). The -EBUSY error case is simply removed. [Stefan R: The bug always existed at least theoretically. But it became easy to trigger since 2.6.36 commit 02d37bed188c "firewire: core: integrate software-forced bus resets with bus management" which introduced long mandatory delays between janitorial bus resets.] Signed-off-by: Benjamin Buchalter Signed-off-by: Stefan Richter (trivial style changes) Cc: # 2.6.36.y and newer --- drivers/firewire/ohci.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f903d7b6f34a..23d1468ad253 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -2199,7 +2199,6 @@ static int ohci_set_config_rom(struct fw_card *card, { struct fw_ohci *ohci; unsigned long flags; - int ret = -EBUSY; __be32 *next_config_rom; dma_addr_t uninitialized_var(next_config_rom_bus); @@ -2240,22 +2239,37 @@ static int ohci_set_config_rom(struct fw_card *card, spin_lock_irqsave(&ohci->lock, flags); + /* + * If there is not an already pending config_rom update, + * push our new allocation into the ohci->next_config_rom + * and then mark the local variable as null so that we + * won't deallocate the new buffer. + * + * OTOH, if there is a pending config_rom update, just + * use that buffer with the new config_rom data, and + * let this routine free the unused DMA allocation. + */ + if (ohci->next_config_rom == NULL) { ohci->next_config_rom = next_config_rom; ohci->next_config_rom_bus = next_config_rom_bus; + next_config_rom = NULL; + } - copy_config_rom(ohci->next_config_rom, config_rom, length); + copy_config_rom(ohci->next_config_rom, config_rom, length); - ohci->next_header = config_rom[0]; - ohci->next_config_rom[0] = 0; + ohci->next_header = config_rom[0]; + ohci->next_config_rom[0] = 0; - reg_write(ohci, OHCI1394_ConfigROMmap, - ohci->next_config_rom_bus); - ret = 0; - } + reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus); spin_unlock_irqrestore(&ohci->lock, flags); + /* If we didn't use the DMA allocation, delete it. */ + if (next_config_rom != NULL) + dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, + next_config_rom, next_config_rom_bus); + /* * Now initiate a bus reset to have the changes take * effect. We clean up the old config rom memory and DMA @@ -2263,13 +2277,10 @@ static int ohci_set_config_rom(struct fw_card *card, * controller could need to access it before the bus reset * takes effect. */ - if (ret == 0) - fw_schedule_bus_reset(&ohci->card, true, true); - else - dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, - next_config_rom, next_config_rom_bus); - return ret; + fw_schedule_bus_reset(&ohci->card, true, true); + + return 0; } static void ohci_send_request(struct fw_card *card, struct fw_packet *packet) -- cgit v1.2.2 From 983960b159a75621855283030d92a80bea92e071 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 2 May 2011 09:59:29 +0000 Subject: amd8111e: trivial typo spelling: Negotitate -> Negotiate Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/amd8111e.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 88495c48a81d..241b185e6569 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -106,7 +106,7 @@ MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version "M MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl); module_param_array(speed_duplex, int, NULL, 0); -MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); +MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotiate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); module_param_array(coalesce, bool, NULL, 0); MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable"); module_param_array(dynamic_ipg, bool, NULL, 0); -- cgit v1.2.2 From 6fdbab9d93e04bfe71f2b3fde485d092e2ffe3ec Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Apr 2011 11:02:15 +0000 Subject: tg3: Fix failure to enable WoL by default when possible tg3 is supposed to enable WoL by default on adapters which support that, but it fails to do so unless the adapter's /sys/devices/.../power/wakeup file contains 'enabled' during the initialization of the adapter. Fix that by making tg3 use device_set_wakeup_enable() to enable wakeup automatically whenever WoL should be enabled by default. Signed-off-by: Rafael J. Wysocki Signed-off-by: David S. Miller --- drivers/net/tg3.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b8c5f35577e4..7a5daefb6f33 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -12327,8 +12327,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; if ((val & VCPU_CFGSHDW_WOL_ENABLE) && - (val & VCPU_CFGSHDW_WOL_MAGPKT)) + (val & VCPU_CFGSHDW_WOL_MAGPKT)) { tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + device_set_wakeup_enable(&tp->pdev->dev, true); + } goto done; } @@ -12461,8 +12463,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) + (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) { tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; + device_set_wakeup_enable(&tp->pdev->dev, true); + } if (cfg2 & (1 << 17)) tp->phy_flags |= TG3_PHYFLG_CAPACITIVE_COUPLING; -- cgit v1.2.2 From d946092000698fd204d82a9d239103c656fb63bf Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 30 Apr 2011 08:29:27 +0000 Subject: smsc95xx: fix reset check The reset loop check should check the MII_BMCR register value for BMCR_RESET rather than for MII_BMCR (the register address, which also happens to be zero). Signed-off-by: Rabin Vincent Signed-off-by: David S. Miller --- drivers/net/usb/smsc95xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 47a6c870b51f..48d4efdb4959 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -730,7 +730,7 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) msleep(10); bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); timeout++; - } while ((bmcr & MII_BMCR) && (timeout < 100)); + } while ((bmcr & BMCR_RESET) && (timeout < 100)); if (timeout >= 100) { netdev_warn(dev->net, "timeout on PHY Reset"); -- cgit v1.2.2 From 6c8c44462ac8ac3f95929328f0c56e9e8b6dd524 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 30 Apr 2011 01:28:17 +0000 Subject: Revert: veth: remove unneeded ifname code from veth_newlink() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 84c49d8c3e4abefb0a41a77b25aa37ebe8d6b743 ("veth: remove unneeded ifname code from veth_newlink()") caused regression on veth creation. This patch reverts the original one. Reported-by: MichaÅ‚ MirosÅ‚aw Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/veth.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2de9b90c5f8f..3b99f64104fd 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -403,6 +403,17 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (tb[IFLA_ADDRESS] == NULL) random_ether_addr(dev->dev_addr); + if (tb[IFLA_IFNAME]) + nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); + else + snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); + + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto err_alloc_name; + } + err = register_netdevice(dev); if (err < 0) goto err_register_dev; @@ -422,6 +433,7 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, err_register_dev: /* nothing to do */ +err_alloc_name: err_configure_peer: unregister_netdevice(peer); return err; -- cgit v1.2.2 From d93da492d9a8840a0bdda88e74df8d0f593f1977 Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Tue, 26 Apr 2011 21:46:47 +0200 Subject: usb/isp1760: Report correct urb status after unlink This fixes a bug in my previous (2.6.38) patch series which caused urb->status value to be wrong after unlink (broke usbtest 11, 12). Signed-off-by: Arvid Brodin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 795345ad45e6..7b2e69aa2e98 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1633,6 +1633,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) ints[i].qh = NULL; ints[i].qtd = NULL; + urb->status = status; isp1760_urb_done(hcd, urb); if (qtd) pe(hcd, qh, qtd); -- cgit v1.2.2 From cee6a262550f53a13acfefbc1e3e5ff35c96182c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 2 May 2011 14:21:44 -0400 Subject: USB: fix regression in usbip by setting has_tt flag This patch (as1460) fixes a regression in the usbip driver caused by the new check for Transaction Translators in USB-2 hubs. The root hub registered by vhci_hcd needs to have the has_tt flag set, because it can connect to low- and full-speed devices as well as high-speed devices. Signed-off-by: Alan Stern Reported-and-tested-by: Nikola Ciprich CC: Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/vhci_hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 0f02a4b12ae4..5d0caa8648e2 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -1139,7 +1139,7 @@ static int vhci_hcd_probe(struct platform_device *pdev) usbip_uerr("create hcd failed\n"); return -ENOMEM; } - + hcd->has_tt = 1; /* this is private data for vhci_hcd */ the_controller = hcd_to_vhci(hcd); -- cgit v1.2.2 From fdc6807fcd09416c5537f479e1dcd624118e234c Mon Sep 17 00:00:00 2001 From: Peter Gundermann Date: Tue, 3 May 2011 10:15:03 +0200 Subject: HID: add support for Logitech G27 wheel Gere's a small patch to add support for the Logitech G27 wheel, since the prior patch only added FF support for the Driving Force Pro and G25. The patch contains the changes from the G25 and DFP, too. I tested the changes with wine/LFS and got full support for all axes and buttons. Signed-off: Peter Gundermann Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-lg.c | 2 ++ drivers/hid/hid-lgff.c | 3 +++ 4 files changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b1986b954ac5..852989fc5757 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1405,6 +1405,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 087a5a436598..e41d32a43962 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -394,6 +394,7 @@ #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 #define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298 #define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 +#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b #define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c #define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a #define USB_DEVICE_ID_S510_RECEIVER 0xc50c diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 3da90402ee81..21f205f09250 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -377,6 +377,8 @@ static const struct hid_device_id lg_devices[] = { .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL), .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL), + .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL), .driver_data = LG_FF }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c index 90d0ef2c92be..f901349c30b5 100644 --- a/drivers/hid/hid-lgff.c +++ b/drivers/hid/hid-lgff.c @@ -72,6 +72,9 @@ static const struct dev_type devices[] = { { 0x046d, 0xc287, ff_joystick_ac }, { 0x046d, 0xc293, ff_joystick }, { 0x046d, 0xc294, ff_wheel }, + { 0x046d, 0xc298, ff_wheel }, + { 0x046d, 0xc299, ff_wheel }, + { 0x046d, 0xc29b, ff_wheel }, { 0x046d, 0xc295, ff_joystick }, { 0x046d, 0xca03, ff_wheel }, }; -- cgit v1.2.2 From 4ad12621e442b7a072e81270808f617cb65c5672 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 3 May 2011 09:23:36 -0700 Subject: libceph: fix ceph_osdc_alloc_request error checks ceph_osdc_alloc_request returns NULL on failure. Signed-off-by: Sage Weil --- drivers/block/rbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 16dc3645291c..3e904717c1c0 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -777,9 +777,9 @@ static int rbd_do_request(struct request *rq, ops, false, GFP_NOIO, pages, bio); - if (IS_ERR(req)) { + if (!req) { up_read(&header->snap_rwsem); - ret = PTR_ERR(req); + ret = -ENOMEM; goto done_pages; } -- cgit v1.2.2 From 4f0871a6c7811a433513c3788a7cce27033bb8b8 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Tue, 19 Apr 2011 17:17:39 +0800 Subject: xHCI: Clear PLC in xhci_bus_resume() This patch clears PORT_PLC if xhci_bus_resume() resumes a previous suspended port, because if a port transition from U3 to U0 state, it will report a port link state change, and software should clear the corresponding PLC bit. It also uses hcd->speed to check if a port is a USB2 protocol port. The patch fixes the issue that USB keyboard can not wakeup system from hibernation. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp --- drivers/usb/host/xhci-hub.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index a78f2ebd11b7..73f75d26436c 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -777,7 +777,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) if (t1 != t2) xhci_writel(xhci, t2, port_array[port_index]); - if (DEV_HIGHSPEED(t1)) { + if (hcd->speed != HCD_USB3) { /* enable remote wake up for USB 2.0 */ u32 __iomem *addr; u32 tmp; @@ -866,6 +866,21 @@ int xhci_bus_resume(struct usb_hcd *hcd) temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[port_index]); } + /* wait for the port to enter U0 and report port link + * state change. + */ + spin_unlock_irqrestore(&xhci->lock, flags); + msleep(20); + spin_lock_irqsave(&xhci->lock, flags); + + /* Clear PLC */ + temp = xhci_readl(xhci, port_array[port_index]); + if (temp & PORT_PLC) { + temp = xhci_port_state_to_neutral(temp); + temp |= PORT_PLC; + xhci_writel(xhci, temp, port_array[port_index]); + } + slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); if (slot_id) @@ -873,7 +888,7 @@ int xhci_bus_resume(struct usb_hcd *hcd) } else xhci_writel(xhci, temp, port_array[port_index]); - if (DEV_HIGHSPEED(temp)) { + if (hcd->speed != HCD_USB3) { /* disable remote wake up for USB 2.0 */ u32 __iomem *addr; u32 tmp; -- cgit v1.2.2 From 9005fcd89c24f2a0fa6f87588b9208aae6d4d6cd Mon Sep 17 00:00:00 2001 From: Harry Wei Date: Thu, 28 Apr 2011 09:30:01 +0800 Subject: staging: Remove a warning for drivers/staging/wlan-ng/cfg80211.c Hi us, When i was compiling kernel, a warning happened to me. The warning said like following. drivers/staging/wlan-ng/cfg80211.c:709: warning: initialization from incompatible pointer type. See http://s1202.photobucket.com/albums/bb364/harrywei/?action=view¤t=patched2.png for more details. So i patch like following. Signed-off-by: Harry Wei Acked-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 6a71f52c59b1..76378397b763 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -273,7 +273,7 @@ exit: } int prism2_set_default_key(struct wiphy *wiphy, struct net_device *dev, - u8 key_index) + u8 key_index, bool unicast, bool multicast) { wlandevice_t *wlandev = dev->ml_priv; -- cgit v1.2.2 From c055f5b2614b4f758ae6cc86733f31fa4c2c5844 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 1 May 2011 09:42:07 -0500 Subject: [SCSI] fix oops in scsi_run_queue() The recent commit closing the race window in device teardown: commit 86cbfb5607d4b81b1a993ff689bbd2addd5d3a9b Author: James Bottomley Date: Fri Apr 22 10:39:59 2011 -0500 [SCSI] put stricter guards on queue dead checks is causing a potential NULL deref in scsi_run_queue() because the q->queuedata may already be NULL by the time this function is called. Since we shouldn't be running a queue that is being torn down, simply add a NULL check in scsi_run_queue() to forestall this. Tested-by: Jim Schutt Cc: stable@kernel.org Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index e9901b8f8443..0bac91e72370 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -400,10 +400,15 @@ static inline int scsi_host_is_busy(struct Scsi_Host *shost) static void scsi_run_queue(struct request_queue *q) { struct scsi_device *sdev = q->queuedata; - struct Scsi_Host *shost = sdev->host; + struct Scsi_Host *shost; LIST_HEAD(starved_list); unsigned long flags; + /* if the device is dead, sdev will be NULL, so no queue to run */ + if (!sdev) + return; + + shost = sdev->host; if (scsi_target(sdev)->single_lun) scsi_single_lun_run(sdev); -- cgit v1.2.2 From eaa4f5e1d0b816291a59a47917e569c0384f2b6f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sun, 1 May 2011 20:16:30 +1000 Subject: drm/radeon: fix regression on atom cards with hardcoded EDID record. Since fafcf94e2b5732d1e13b440291c53115d2b172e9 introduced an edid size, it seems to have broken this path. This manifest as oops on T500 Lenovo laptops with dual graphics primarily. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33812 cc: stable@kernel.org Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f5d12fb103fa..f116516bfef7 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1599,9 +1599,10 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0], fake_edid_record->ucFakeEDIDLength); - if (drm_edid_is_valid(edid)) + if (drm_edid_is_valid(edid)) { rdev->mode_info.bios_hardcoded_edid = edid; - else + rdev->mode_info.bios_hardcoded_edid_size = edid_size; + } else kfree(edid); } } -- cgit v1.2.2 From 498548ec69c6897fe4376b2ca90758762fa0b817 Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Wed, 27 Apr 2011 16:10:57 +1000 Subject: drm: Send pending vblank events before disabling vblank. This is the least-bad behaviour. It means that we signal the vblank event before it actually happens, but since we're disabling vblanks there's no guarantee that it will *ever* happen otherwise. This prevents GL applications which use WaitMSC from hanging indefinitely. Signed-off-by: Christopher James Halse Rogers Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_irq.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 741457bd1c46..a1f12cb043de 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -932,11 +932,34 @@ EXPORT_SYMBOL(drm_vblank_put); void drm_vblank_off(struct drm_device *dev, int crtc) { + struct drm_pending_vblank_event *e, *t; + struct timeval now; unsigned long irqflags; + unsigned int seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); vblank_disable_and_save(dev, crtc); DRM_WAKEUP(&dev->vbl_queue[crtc]); + + /* Send any queued vblank events, lest the natives grow disquiet */ + seq = drm_vblank_count_and_time(dev, crtc, &now); + list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { + if (e->pipe != crtc) + continue; + DRM_DEBUG("Sending premature vblank event on disable: \ + wanted %d, current %d\n", + e->event.sequence, seq); + + e->event.sequence = seq; + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + drm_vblank_put(dev, e->pipe); + list_move_tail(&e->base.link, &e->base.file_priv->event_list); + wake_up_interruptible(&e->base.file_priv->event_wait); + trace_drm_vblank_event_delivered(e->base.pid, e->pipe, + e->event.sequence); + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } EXPORT_SYMBOL(drm_vblank_off); -- cgit v1.2.2 From 8aeb96f80232e9a701b5c4715504f4c9173978bd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 May 2011 19:28:02 -0400 Subject: drm/radeon/kms: fix gart setup on fusion parts (v2) Out of the entire GART/VM subsystem, the hw designers changed the location of 3 regs. v2: airlied: add parameter for userspace to work from. Signed-off-by: Alex Deucher Signed-off-by: Jerome Glisse Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 17 +++++++++-------- drivers/gpu/drm/radeon/evergreend.h | 5 +++++ drivers/gpu/drm/radeon/radeon_kms.c | 3 +++ 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index e9bc135d9189..c20eac3379e6 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -862,9 +862,15 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) SYSTEM_ACCESS_MODE_NOT_IN_SYS | SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU | EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5); - WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); - WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + if (rdev->flags & RADEON_IS_IGP) { + WREG32(FUS_MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(FUS_MC_VM_MD_L1_TLB2_CNTL, tmp); + } else { + WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp); + WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp); + } WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); @@ -2923,11 +2929,6 @@ static int evergreen_startup(struct radeon_device *rdev) rdev->asic->copy = NULL; dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r); } - /* XXX: ontario has problems blitting to gart at the moment */ - if (rdev->family == CHIP_PALM) { - rdev->asic->copy = NULL; - radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size); - } /* allocate wb buffer */ r = radeon_wb_init(rdev); diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 9aaa3f0c9372..94533849927e 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -221,6 +221,11 @@ #define MC_VM_MD_L1_TLB0_CNTL 0x2654 #define MC_VM_MD_L1_TLB1_CNTL 0x2658 #define MC_VM_MD_L1_TLB2_CNTL 0x265C + +#define FUS_MC_VM_MD_L1_TLB0_CNTL 0x265C +#define FUS_MC_VM_MD_L1_TLB1_CNTL 0x2660 +#define FUS_MC_VM_MD_L1_TLB2_CNTL 0x2664 + #define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C #define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038 #define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034 diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 871df0376b1c..bd58af658581 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -234,6 +234,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return -EINVAL; } break; + case RADEON_INFO_FUSION_GART_WORKING: + value = 1; + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; -- cgit v1.2.2 From 2dd251f0a294300a1cf8f4b63768145fa6153c4d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 16 Apr 2011 10:23:51 +0100 Subject: drm/i915: Release object along create user fb error path Reported-by: Alan Cox Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e522c702b04e..aab06cfaf70f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6579,8 +6579,10 @@ intel_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOENT); intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) + if (!intel_fb) { + drm_gem_object_unreference_unlocked(&obj->base); return ERR_PTR(-ENOMEM); + } ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); if (ret) { -- cgit v1.2.2 From 31acbcc408f412d1ba73765b846c38642be553c3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sun, 17 Apr 2011 06:38:35 +0100 Subject: drm/i915/dp: Be paranoid in case we disable a DP before it is attached Given that the hardware may be left in a random condition by the BIOS, it is conceivable that we then attempt to clear the DP_PIPEB_SELECT bit without us ever enabling/attaching the DP encoder to a pipe. Thus causing a NULL deference when we attempt to wait for a vblank on that crtc. Reported-and-tested-by: Bryan Christ Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36314 Signed-off-by: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=36456 Reported-and-tested-by: Bo Wang Cc: stable@kernel.org Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_dp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index cb8578b7e443..a4d80314e7f8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1470,7 +1470,8 @@ intel_dp_link_down(struct intel_dp *intel_dp) if (!HAS_PCH_CPT(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { - struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); + struct drm_crtc *crtc = intel_dp->base.base.crtc; + /* Hardware workaround: leaving our transcoder select * set to transcoder B while it's off will prevent the * corresponding HDMI output on transcoder A. @@ -1485,7 +1486,19 @@ intel_dp_link_down(struct intel_dp *intel_dp) /* Changes to enable or select take place the vblank * after being written. */ - intel_wait_for_vblank(dev, intel_crtc->pipe); + if (crtc == NULL) { + /* We can arrive here never having been attached + * to a CRTC, for instance, due to inheriting + * random state from the BIOS. + * + * If the pipe is not running, play safe and + * wait for the clocks to stabilise before + * continuing. + */ + POSTING_READ(intel_dp->output_reg); + msleep(50); + } else + intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); } I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); -- cgit v1.2.2 From 8c4e708d01424f88afde64a96ffd05146c9978b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Wed, 4 May 2011 21:08:42 +0200 Subject: HID: picolcd: Avoid compile warning/error triggered by copy_from_user() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y compilation of PicoLCD driver fails on copy_from_user(), without it a warning is generated: CC [M] drivers/hid/hid-picolcd.o In file included from /usr/src/linux-2.6/arch/x86/include/asm/uaccess.h:571, from /usr/src/linux-2.6/arch/x86/include/asm/sections.h:5, from /usr/src/linux-2.6/arch/x86/include/asm/hw_irq.h:26, from /usr/src/linux-2.6/include/linux/irq.h:359, from /usr/src/linux-2.6/arch/x86/include/asm/hardirq.h:5, from /usr/src/linux-2.6/include/linux/hardirq.h:7, from /usr/src/linux-2.6/include/linux/interrupt.h:12, from /usr/src/linux-2.6/include/linux/usb.h:15, from /usr/src/linux-2.6/drivers/hid/hid-picolcd.c:25: In function 'copy_from_user', inlined from 'picolcd_debug_eeprom_write' at drivers/hid/hid-picolcd.c:1592: arch/x86/include/asm/uaccess_32.h:212: error: call to 'copy_from_user_overflow' declared with attribute error: copy_from_user() buffer size is not provably correct gcc-4.4.5 is not able to track size calculation when it is stored into a variable, thus tell copy_from_user() maximum size via min(*max-size*, *effective-size*) explicitly and inline how much to copy at most. Signed-off-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index de9cf21b3494..6f0642ea1009 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -1584,11 +1584,11 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u, memset(raw_data, 0, sizeof(raw_data)); raw_data[0] = *off & 0xff; raw_data[1] = (*off >> 8) & 0xff; - raw_data[2] = s < 20 ? s : 20; + raw_data[2] = min((size_t)20, s); if (*off + raw_data[2] > 0xff) raw_data[2] = 0x100 - *off; - if (copy_from_user(raw_data+3, u, raw_data[2])) + if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2]))) return -EFAULT; resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data, sizeof(raw_data)); -- cgit v1.2.2 From 1dbe7dada2d03d1313183d439068f1f951a91244 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 5 May 2011 08:40:14 -0700 Subject: Input: ads7846 - make transfer buffers DMA safe req.sample needs its own cacheline otherwise accessing req.msg fetches it in again. Note: This effect doesn't occur if the underlying SPI driver doesn't use DMA at all. Signed-off-by: Alexander Stein Acked-by: Jonathan Cameron Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c24946f51256..ab51a8dbdb5a 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -281,17 +281,25 @@ struct ser_req { u8 command; u8 ref_off; u16 scratch; - __be16 sample; struct spi_message msg; struct spi_transfer xfer[6]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + __be16 sample ____cacheline_aligned; }; struct ads7845_ser_req { u8 command[3]; u8 pwrdown[3]; - u8 sample[3]; struct spi_message msg; struct spi_transfer xfer[2]; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + u8 sample[3] ____cacheline_aligned; }; static int ads7846_read12_ser(struct device *dev, unsigned command) -- cgit v1.2.2 From 28350e330cfab46b60a1dbf763b678d859f9f3d9 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 5 May 2011 08:40:46 -0700 Subject: Input: ads7846 - remove unused variable from struct ads7845_ser_req Signed-off-by: Alexander Stein Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ab51a8dbdb5a..1de1c19dad30 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -292,7 +292,6 @@ struct ser_req { struct ads7845_ser_req { u8 command[3]; - u8 pwrdown[3]; struct spi_message msg; struct spi_transfer xfer[2]; /* -- cgit v1.2.2 From 75bd0cbdc21d80859c80bdd5dd00125c1a3ccbca Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 28 Apr 2011 22:37:09 +0000 Subject: usbnet: runtime pm: fix out of memory This patch makes use of the EVENT_DEV_OPEN flag introduced recently to fix one out of memory issue, which can be reproduced on omap3/4 based pandaboard/beagle XM easily with steps below: - enable runtime pm echo auto > /sys/devices/platform/usbhs-omap.0/ehci-omap.0/usb1/1-1/1-1.1/power/control - ifconfig eth0 up - then out of memroy happened, see [1] for kernel message. Follows my analysis: - 'ifconfig eth0 up' brings eth0 out of suspend, and usbnet_resume is called to schedule dev->bh, then rx urbs are submited to prepare for recieving data; - some usbnet devices will produce garbage rx packets flood if info->reset is not called in usbnet_open. - so there is no enough chances for usbnet_bh to handle and release recieved skb buffers since many rx interrupts consumes cpu, so out of memory for atomic allocation in rx_submit happened. This patch fixes the issue by simply not allowing schedule of usbnet_bh until device is opened. [1], dmesg [ 234.712005] smsc95xx 1-1.1:1.0: rpm_resume flags 0x4 [ 234.712066] usb 1-1.1: rpm_resume flags 0x0 [ 234.712066] usb 1-1: rpm_resume flags 0x0 [ 234.712097] usb usb1: rpm_resume flags 0x0 [ 234.712127] usb usb1: usb auto-resume [ 234.712158] ehci-omap ehci-omap.0: resume root hub [ 234.754028] hub 1-0:1.0: hub_resume [ 234.754821] hub 1-0:1.0: port 1: status 0507 change 0000 [ 234.756011] hub 1-0:1.0: state 7 ports 3 chg 0000 evt 0000 [ 234.756042] hub 1-0:1.0: rpm_resume flags 0x4 [ 234.756072] usb usb1: rpm_resume flags 0x0 [ 234.756164] usb usb1: rpm_resume returns 1 [ 234.756195] hub 1-0:1.0: rpm_resume returns 0 [ 234.756195] hub 1-0:1.0: rpm_suspend flags 0x4 [ 234.756225] hub 1-0:1.0: rpm_suspend returns 0 [ 234.756256] usb usb1: rpm_resume returns 0 [ 234.757141] usb 1-1: usb auto-resume [ 234.793151] ehci-omap ehci-omap.0: GetStatus port:1 status 001005 0 ACK POWER sig=se0 PE CONNECT [ 234.816558] usb 1-1: finish resume [ 234.817871] hub 1-1:1.0: hub_resume [ 234.818420] hub 1-1:1.0: port 1: status 0507 change 0000 [ 234.820495] ehci-omap ehci-omap.0: reused qh eec50220 schedule [ 234.820495] usb 1-1: link qh256-0001/eec50220 start 1 [1/0 us] [ 234.820587] usb 1-1: rpm_resume returns 0 [ 234.820800] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0000 [ 234.820800] hub 1-1:1.0: rpm_resume flags 0x4 [ 234.820831] hub 1-1:1.0: rpm_resume returns 0 [ 234.820861] hub 1-1:1.0: rpm_suspend flags 0x4 [ 234.820861] hub 1-1:1.0: rpm_suspend returns 0 [ 234.821777] usb 1-1.1: usb auto-resume [ 234.868591] hub 1-1:1.0: state 7 ports 5 chg 0000 evt 0002 [ 234.868591] hub 1-1:1.0: rpm_resume flags 0x4 [ 234.868621] hub 1-1:1.0: rpm_resume returns 0 [ 234.868652] hub 1-1:1.0: rpm_suspend flags 0x4 [ 234.868652] hub 1-1:1.0: rpm_suspend returns 0 [ 234.879486] usb 1-1.1: finish resume [ 234.880279] usb 1-1.1: rpm_resume returns 0 [ 234.880310] smsc95xx 1-1.1:1.0: rpm_resume returns 0 [ 238.880187] ksoftirqd/0: page allocation failure. order:0, mode:0x20 [ 238.880218] Backtrace: [ 238.880249] [] (dump_backtrace+0x0/0xf8) from [] (dump_stack+0x18/0x1c) [ 238.880249] r6:00000000 r5:00000000 r4:00000020 r3:00000002 [ 238.880310] [] (dump_stack+0x0/0x1c) from [] (__alloc_pages_nodemask+0x620/0x724) [ 238.880340] [] (__alloc_pages_nodemask+0x0/0x724) from [] (kmem_getpages.clone.34+0x34/0xc8) [ 238.880371] [] (kmem_getpages.clone.34+0x0/0xc8) from [] (cache_grow.clone.42+0x84/0x154) [ 238.880371] r6:ef871aa4 r5:ef871a80 r4:ef81fd40 r3:00000020 [ 238.880401] [] (cache_grow.clone.42+0x0/0x154) from [] (cache_alloc_refill+0x19c/0x1f0) [ 238.880432] [] (cache_alloc_refill+0x0/0x1f0) from [] (kmem_cache_alloc+0x90/0x190) [ 238.880462] [] (kmem_cache_alloc+0x0/0x190) from [] (__alloc_skb+0x34/0xe8) [ 238.880493] [] (__alloc_skb+0x0/0xe8) from [] (rx_submit+0x2c/0x1d4 [usbnet]) [ 238.880523] [] (rx_submit+0x0/0x1d4 [usbnet]) from [] (rx_complete+0x19c/0x1b0 [usbnet]) [ 238.880737] [] (rx_complete+0x0/0x1b0 [usbnet]) from [] (usb_hcd_giveback_urb+0xa8/0xf4 [usbcore]) [ 238.880737] r8:eeeced34 r7:eeecec00 r6:eeecec00 r5:00000000 r4:eec2dd20 [ 238.880767] r3:bf050b9c [ 238.880859] [] (usb_hcd_giveback_urb+0x0/0xf4 [usbcore]) from [] (ehci_urb_done+0xb0/0xbc [ehci_hcd]) [ 238.880859] r6:00000000 r5:eec2dd20 r4:eeeced44 r3:eec2dd34 [ 238.880920] [] (ehci_urb_done+0x0/0xbc [ehci_hcd]) from [] (qh_completions+0x308/0x3bc [ehci_hcd]) [ 238.880920] r7:00000000 r6:eeda21a0 r5:ffdfe3c0 r4:eeda21ac [ 238.880981] [] (qh_completions+0x0/0x3bc [ehci_hcd]) from [] (scan_async+0xb0/0x16c [ehci_hcd]) [ 238.881011] [] (scan_async+0x0/0x16c [ehci_hcd]) from [] (ehci_work+0x38/0x90 [ehci_hcd]) [ 238.881042] [] (ehci_work+0x0/0x90 [ehci_hcd]) from [] (ehci_irq+0x300/0x34c [ehci_hcd]) [ 238.881072] r4:eeeced34 r3:00000001 [ 238.881134] [] (ehci_irq+0x0/0x34c [ehci_hcd]) from [] (usb_hcd_irq+0x40/0xac [usbcore]) [ 238.881195] [] (usb_hcd_irq+0x0/0xac [usbcore]) from [] (handle_irq_event_percpu+0xb8/0x240) [ 238.881225] r6:eec504e0 r5:0000006d r4:eec504e0 r3:bf0067e8 [ 238.881256] [] (handle_irq_event_percpu+0x0/0x240) from [] (handle_irq_event+0x44/0x64) [ 238.881256] [] (handle_irq_event+0x0/0x64) from [] (handle_level_irq+0xe0/0x114) [ 238.881286] r6:0000006d r5:c080c14c r4:c080c100 r3:00020000 [ 238.881317] [] (handle_level_irq+0x0/0x114) from [] (asm_do_IRQ+0x90/0xd0) [ 238.881317] r5:00000000 r4:0000006d [ 238.881347] [] (asm_do_IRQ+0x0/0xd0) from [] (__irq_svc+0x50/0x134) [ 238.881378] Exception stack(0xef837e20 to 0xef837e68) [ 238.881378] 7e20: 00000001 00185610 016cc000 c00490c0 eb380000 ef800540 00000020 00004ae0 [ 238.881408] 7e40: 00000020 bf0509f4 60000013 ef837e9c ef837e40 ef837e68 c0226f0c c0298ca0 [ 238.881408] 7e60: 20000013 ffffffff [ 238.881408] r5:fa240100 r4:ffffffff [ 238.881439] [] (__kmalloc_track_caller+0x0/0x1d0) from [] (__alloc_skb+0x58/0xe8) [ 238.881469] [] (__alloc_skb+0x0/0xe8) from [] (rx_submit+0x2c/0x1d4 [usbnet]) [ 238.881500] [] (rx_submit+0x0/0x1d4 [usbnet]) from [] (usbnet_bh+0x1b4/0x250 [usbnet]) [ 238.881530] [] (usbnet_bh+0x0/0x250 [usbnet]) from [] (tasklet_action+0xb0/0x1f8) [ 238.881530] r6:00000000 r5:ef9757f0 r4:ef9757ec r3:bf051224 [ 238.881561] [] (tasklet_action+0x0/0x1f8) from [] (__do_softirq+0x140/0x290) [ 238.881561] r8:00000006 r7:00000101 r6:00000000 r5:c0806098 r4:00000001 [ 238.881591] r3:c01f907c [ 238.881622] [] (__do_softirq+0x0/0x290) from [] (run_ksoftirqd+0xd0/0x1f4) [ 238.881622] [] (run_ksoftirqd+0x0/0x1f4) from [] (kthread+0x90/0x98) [ 238.881652] r7:00000013 r6:c01f98fc r5:00000000 r4:ef831efc [ 238.881683] [] (kthread+0x0/0x98) from [] (do_exit+0x0/0x374) [ 238.881713] r6:c01f62f4 r5:c0211320 r4:ef831efc [ 238.881713] Mem-info: [ 238.881744] Normal per-cpu: [ 238.881744] CPU 0: hi: 186, btch: 31 usd: 38 [ 238.881744] CPU 1: hi: 186, btch: 31 usd: 169 [ 238.881774] HighMem per-cpu: [ 238.881774] CPU 0: hi: 90, btch: 15 usd: 66 [ 238.881774] CPU 1: hi: 90, btch: 15 usd: 86 [ 238.881805] active_anon:544 inactive_anon:71 isolated_anon:0 [ 238.881805] active_file:926 inactive_file:2538 isolated_file:0 [ 238.881805] unevictable:0 dirty:10 writeback:0 unstable:0 [ 238.881805] free:57782 slab_reclaimable:864 slab_unreclaimable:186898 [ 238.881805] mapped:632 shmem:144 pagetables:50 bounce:0 [ 238.881835] Normal free:1328kB min:3532kB low:4412kB high:5296kB active_anon:0kB inactive_anon:0kB active_file:880kB inactive_file:848kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:780288kB mlocked:0kB dirty:36kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:3456kB slab_unreclaimable:747592kB kernel_stack:392kB pagetables:200kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no [ 238.881866] lowmem_reserve[]: 0 1904 1904 [ 238.881896] HighMem free:229800kB min:236kB low:508kB high:784kB active_anon:2176kB inactive_anon:284kB active_file:2824kB inactive_file:9304kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:243712kB mlocked:0kB dirty:4kB writeback:0kB mapped:2528kB shmem:576kB slab_reclaimable:0kB slab_unreclaimable:0kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? no [ 238.881927] lowmem_reserve[]: 0 0 0 [ 238.881958] Normal: 0*4kB 4*8kB 6*16kB 0*32kB 1*64kB 1*128kB 0*256kB 2*512kB 0*1024kB 0*2048kB 0*4096kB = 1344kB [ 238.882019] HighMem: 6*4kB 2*8kB 4*16kB 4*32kB 1*64kB 1*128kB 0*256kB 2*512kB 3*1024kB 0*2048kB 55*4096kB = 229800kB [ 238.882080] 3610 total pagecache pages [ 238.882080] 0 pages in swap cache [ 238.882080] Swap cache stats: add 0, delete 0, find 0/0 [ 238.882110] Free swap = 0kB [ 238.882110] Total swap = 0kB [ 238.933776] 262144 pages of RAM [ 238.933776] 58240 free pages [ 238.933776] 10503 reserved pages [ 238.933776] 187773 slab pages [ 238.933807] 2475 pages shared [ 238.933807] 0 pages swap cached Signed-off-by: Ming Lei Acked-by: Oliver Neukum Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 009bba3d753e..9ab439d144ed 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -645,6 +645,7 @@ int usbnet_stop (struct net_device *net) struct driver_info *info = dev->driver_info; int retval; + clear_bit(EVENT_DEV_OPEN, &dev->flags); netif_stop_queue (net); netif_info(dev, ifdown, dev->net, @@ -1524,9 +1525,12 @@ int usbnet_resume (struct usb_interface *intf) smp_mb(); clear_bit(EVENT_DEV_ASLEEP, &dev->flags); spin_unlock_irq(&dev->txq.lock); - if (!(dev->txq.qlen >= TX_QLEN(dev))) - netif_start_queue(dev->net); - tasklet_schedule (&dev->bh); + + if (test_bit(EVENT_DEV_OPEN, &dev->flags)) { + if (!(dev->txq.qlen >= TX_QLEN(dev))) + netif_start_queue(dev->net); + tasklet_schedule (&dev->bh); + } } return 0; } -- cgit v1.2.2 From 87e9af6cc67d842cd92b52b81f3f14e665e7ab05 Mon Sep 17 00:00:00 2001 From: Kurt Van Dijck Date: Mon, 2 May 2011 04:50:48 +0000 Subject: can: fix SJA1000 dlc for RTR packets RTR frames do have a valid data length code on CAN. The driver for SJA1000 did not handle that situation properly. Signed-off-by: Kurt Van Dijck Acked-by: Marc Kleine-Budde Signed-off-by: David S. Miller --- drivers/net/can/sja1000/sja1000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index a358ea9445a2..f501bba1fc6f 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -346,10 +346,10 @@ static void sja1000_rx(struct net_device *dev) | (priv->read_reg(priv, REG_ID2) >> 5); } + cf->can_dlc = get_can_dlc(fi & 0x0F); if (fi & FI_RTR) { id |= CAN_RTR_FLAG; } else { - cf->can_dlc = get_can_dlc(fi & 0x0F); for (i = 0; i < cf->can_dlc; i++) cf->data[i] = priv->read_reg(priv, dreg++); } -- cgit v1.2.2 From 56f3aeb2c14b9d000dfc77f352250bc3b67af5c0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 6 May 2011 08:14:57 +0100 Subject: ARM: RiscPC: etherh: fix section mismatches WARNING: drivers/net/arm/built-in.o(.data+0x0): Section mismatch in reference from the variable etherh_driver to the function .init.text:etherh_probe() The variable etherh_driver references the function __init etherh_probe() If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console Signed-off-by: Russell King --- drivers/net/arm/etherh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 4af235d41fda..fbfb5b47c506 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -527,7 +527,7 @@ static void __init etherh_banner(void) * Read the ethernet address string from the on board rom. * This is an ascii string... */ -static int __init etherh_addr(char *addr, struct expansion_card *ec) +static int __devinit etherh_addr(char *addr, struct expansion_card *ec) { struct in_chunk_dir cd; char *s; @@ -655,7 +655,7 @@ static const struct net_device_ops etherh_netdev_ops = { static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16]; -static int __init +static int __devinit etherh_probe(struct expansion_card *ec, const struct ecard_id *id) { const struct etherh_data *data = id->data; -- cgit v1.2.2 From 52fe116376129b29572f55acc9c73ebd485052c9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 6 May 2011 08:16:51 +0100 Subject: ARM: RiscPC: acornfb: fix section mismatches WARNING: drivers/video/built-in.o(.devinit.text+0x38): Section mismatch in reference from the function acornfb_probe() to the function .init.text:acornfb_setup() The function __devinit acornfb_probe() references a function __init acornfb_setup(). If acornfb_setup is only used by acornfb_probe then annotate acornfb_setup with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x3c): Section mismatch in reference from the function acornfb_probe() to the function .init.text:acornfb_init_fbinfo() The function __devinit acornfb_probe() references a function __init acornfb_init_fbinfo(). If acornfb_init_fbinfo is only used by acornfb_probe then annotate acornfb_init_fbinfo with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x4c0): Section mismatch in reference from the function acornfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit acornfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by acornfb_probe then annotate (unknown) with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x4c8): Section mismatch in reference from the function acornfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit acornfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by acornfb_probe then annotate (unknown) with a matching annotation. WARNING: drivers/video/built-in.o(.devinit.text+0x4cc): Section mismatch in reference from the function acornfb_probe() to the (unknown reference) .init.data:(unknown) The function __devinit acornfb_probe() references a (unknown reference) __initdata (unknown). If (unknown) is only used by acornfb_probe then annotate (unknown) with a matching annotation. Signed-off-by: Russell King --- drivers/video/acornfb.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 82acb8dc4aa1..6183a57eb69d 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -66,7 +66,7 @@ * have. Allow 1% either way on the nominal for TVs. */ #define NR_MONTYPES 6 -static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = { +static struct fb_monspecs monspecs[NR_MONTYPES] __devinitdata = { { /* TV */ .hfmin = 15469, .hfmax = 15781, @@ -873,7 +873,7 @@ static struct fb_ops acornfb_ops = { /* * Everything after here is initialisation!!! */ -static struct fb_videomode modedb[] __initdata = { +static struct fb_videomode modedb[] __devinitdata = { { /* 320x256 @ 50Hz */ NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, FB_SYNC_COMP_HIGH_ACT, @@ -925,8 +925,7 @@ static struct fb_videomode modedb[] __initdata = { } }; -static struct fb_videomode __initdata -acornfb_default_mode = { +static struct fb_videomode acornfb_default_mode __devinitdata = { .name = NULL, .refresh = 60, .xres = 640, @@ -942,7 +941,7 @@ acornfb_default_mode = { .vmode = FB_VMODE_NONINTERLACED }; -static void __init acornfb_init_fbinfo(void) +static void __devinit acornfb_init_fbinfo(void) { static int first = 1; @@ -1018,8 +1017,7 @@ static void __init acornfb_init_fbinfo(void) * size can optionally be followed by 'M' or 'K' for * MB or KB respectively. */ -static void __init -acornfb_parse_mon(char *opt) +static void __devinit acornfb_parse_mon(char *opt) { char *p = opt; @@ -1066,8 +1064,7 @@ bad: current_par.montype = -1; } -static void __init -acornfb_parse_montype(char *opt) +static void __devinit acornfb_parse_montype(char *opt) { current_par.montype = -2; @@ -1108,8 +1105,7 @@ acornfb_parse_montype(char *opt) } } -static void __init -acornfb_parse_dram(char *opt) +static void __devinit acornfb_parse_dram(char *opt) { unsigned int size; @@ -1134,15 +1130,14 @@ acornfb_parse_dram(char *opt) static struct options { char *name; void (*parse)(char *opt); -} opt_table[] __initdata = { +} opt_table[] __devinitdata = { { "mon", acornfb_parse_mon }, { "montype", acornfb_parse_montype }, { "dram", acornfb_parse_dram }, { NULL, NULL } }; -int __init -acornfb_setup(char *options) +static int __devinit acornfb_setup(char *options) { struct options *optp; char *opt; @@ -1179,8 +1174,7 @@ acornfb_setup(char *options) * Detect type of monitor connected * For now, we just assume SVGA */ -static int __init -acornfb_detect_monitortype(void) +static int __devinit acornfb_detect_monitortype(void) { return 4; } -- cgit v1.2.2 From e328d410826d52e9ee348aff9064c4a207f2adb1 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Fri, 6 May 2011 08:32:53 +0000 Subject: vmxnet3: Consistently disable irqs when taking adapter->cmd_lock Using the vmxnet3 driver produces a lockdep warning because vmxnet3_set_mc(), which is called with mc->mca_lock held, takes adapter->cmd_lock. However, there are a couple of places where adapter->cmd_lock is taken with softirqs enabled, lockdep warns that a softirq that tries to take mc->mca_lock could happen while adapter->cmd_lock is held, leading to an AB-BA deadlock. I'm not sure if this is a real potential deadlock or not, but the simplest and best fix seems to be simply to make sure we take cmd_lock with spin_lock_irqsave() everywhere -- the places with plain spin_lock just look like oversights. The full enormous lockdep warning is: ========================================================= [ INFO: possible irq lock inversion dependency detected ] 2.6.39-rc6+ #1 --------------------------------------------------------- ifconfig/567 just changed the state of lock: (&(&mc->mca_lock)->rlock){+.-...}, at: [] mld_ifc_timer_expire+0xff/0x280 but this lock took another, SOFTIRQ-unsafe lock in the past: (&(&adapter->cmd_lock)->rlock){+.+...} and interrupts could create inverse lock ordering between them. other info that might help us debug this: 4 locks held by ifconfig/567: #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0x17/0x20 #1: ((inetaddr_chain).rwsem){.+.+.+}, at: [] __blocking_notifier_call_chain+0x5f/0xb0 #2: (&idev->mc_ifc_timer){+.-...}, at: [] run_timer_softirq+0xeb/0x3f0 #3: (&ndev->lock){++.-..}, at: [] mld_ifc_timer_expire+0x32/0x280 the shortest dependencies between 2nd lock and 1st lock: -> (&(&adapter->cmd_lock)->rlock){+.+...} ops: 11 { HARDIRQ-ON-W at: [] __lock_acquire+0x7f6/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock+0x36/0x70 [] vmxnet3_alloc_intr_resources+0x22/0x230 [vmxnet3] [] vmxnet3_probe_device+0x5f6/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b SOFTIRQ-ON-W at: [] __lock_acquire+0x827/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock+0x36/0x70 [] vmxnet3_alloc_intr_resources+0x22/0x230 [vmxnet3] [] vmxnet3_probe_device+0x5f6/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b INITIAL USE at: [] __lock_acquire+0x459/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock+0x36/0x70 [] vmxnet3_alloc_intr_resources+0x22/0x230 [vmxnet3] [] vmxnet3_probe_device+0x5f6/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b } ... key at: [] __key.42516+0x0/0xffffffffffffda70 [vmxnet3] ... acquired at: [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_irqsave+0x55/0xa0 [] vmxnet3_set_mc+0x97/0x1a0 [vmxnet3] [] __dev_set_rx_mode+0x40/0xb0 [] dev_set_rx_mode+0x30/0x50 [] __dev_open+0xc7/0x100 [] __dev_change_flags+0xa1/0x180 [] dev_change_flags+0x28/0x70 [] devinet_ioctl+0x730/0x800 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] do_vfs_ioctl+0x98/0x570 [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b -> (_xmit_ETHER){+.....} ops: 6 { HARDIRQ-ON-W at: [] __lock_acquire+0x7f6/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] __dev_mc_add+0x38/0x90 [] dev_mc_add+0x10/0x20 [] igmp6_group_added+0x10e/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_notify+0x2f7/0xb10 [] notifier_call_chain+0x8c/0xc0 [] raw_notifier_call_chain+0x16/0x20 [] call_netdevice_notifiers+0x37/0x70 [] register_netdevice+0x244/0x2d0 [] register_netdev+0x3f/0x60 [] vmxnet3_probe_device+0x760/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b INITIAL USE at: [] __lock_acquire+0x459/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] __dev_mc_add+0x38/0x90 [] dev_mc_add+0x10/0x20 [] igmp6_group_added+0x10e/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_notify+0x2f7/0xb10 [] notifier_call_chain+0x8c/0xc0 [] raw_notifier_call_chain+0x16/0x20 [] call_netdevice_notifiers+0x37/0x70 [] register_netdevice+0x244/0x2d0 [] register_netdev+0x3f/0x60 [] vmxnet3_probe_device+0x760/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b } ... key at: [] netdev_addr_lock_key+0x8/0x1e0 ... acquired at: [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] __dev_mc_add+0x38/0x90 [] dev_mc_add+0x10/0x20 [] igmp6_group_added+0x10e/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_notify+0x2f7/0xb10 [] notifier_call_chain+0x8c/0xc0 [] raw_notifier_call_chain+0x16/0x20 [] call_netdevice_notifiers+0x37/0x70 [] register_netdevice+0x244/0x2d0 [] register_netdev+0x3f/0x60 [] vmxnet3_probe_device+0x760/0x15c5 [vmxnet3] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] driver_probe_device+0x96/0x1c0 [] __driver_attach+0xab/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xc8/0x290 [] driver_register+0x76/0x140 [] __pci_register_driver+0x66/0xe0 [] serio_raw_poll+0x3a/0x60 [serio_raw] [] do_one_initcall+0x45/0x190 [] sys_init_module+0xfb/0x250 [] system_call_fastpath+0x16/0x1b -> (&(&mc->mca_lock)->rlock){+.-...} ops: 6 { HARDIRQ-ON-W at: [] __lock_acquire+0x7f6/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] igmp6_group_added+0x45/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_init+0x4e/0x183 [] inet6_init+0x191/0x2a6 [] do_one_initcall+0x45/0x190 [] kernel_init+0xe3/0x168 [] kernel_thread_helper+0x4/0x10 IN-SOFTIRQ-W at: [] __lock_acquire+0x7ce/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] mld_ifc_timer_expire+0xff/0x280 [] run_timer_softirq+0x179/0x3f0 [] __do_softirq+0xc0/0x210 [] call_softirq+0x1c/0x30 [] do_softirq+0xad/0xe0 [] irq_exit+0x9e/0xb0 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] rt_do_flush+0x87/0x2a0 [] rt_cache_flush+0x46/0x60 [] fib_disable_ip+0x40/0x60 [] fib_inetaddr_event+0xd7/0xe0 [] notifier_call_chain+0x8c/0xc0 [] __blocking_notifier_call_chain+0x78/0xb0 [] blocking_notifier_call_chain+0x16/0x20 [] __inet_del_ifa+0xf1/0x2e0 [] inet_del_ifa+0x13/0x20 [] devinet_ioctl+0x501/0x800 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] do_vfs_ioctl+0x98/0x570 [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b INITIAL USE at: [] __lock_acquire+0x459/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] igmp6_group_added+0x45/0x1b0 [] ipv6_dev_mc_inc+0x2cd/0x430 [] ipv6_add_dev+0x357/0x450 [] addrconf_init+0x4e/0x183 [] inet6_init+0x191/0x2a6 [] do_one_initcall+0x45/0x190 [] kernel_init+0xe3/0x168 [] kernel_thread_helper+0x4/0x10 } ... key at: [] __key.40877+0x0/0x8 ... acquired at: [] check_usage_forwards+0x9c/0x110 [] mark_lock+0x19c/0x400 [] __lock_acquire+0x7ce/0x1e10 [] lock_acquire+0x9d/0x130 [] _raw_spin_lock_bh+0x3b/0x70 [] mld_ifc_timer_expire+0xff/0x280 [] run_timer_softirq+0x179/0x3f0 [] __do_softirq+0xc0/0x210 [] call_softirq+0x1c/0x30 [] do_softirq+0xad/0xe0 [] irq_exit+0x9e/0xb0 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] rt_do_flush+0x87/0x2a0 [] rt_cache_flush+0x46/0x60 [] fib_disable_ip+0x40/0x60 [] fib_inetaddr_event+0xd7/0xe0 [] notifier_call_chain+0x8c/0xc0 [] __blocking_notifier_call_chain+0x78/0xb0 [] blocking_notifier_call_chain+0x16/0x20 [] __inet_del_ifa+0xf1/0x2e0 [] inet_del_ifa+0x13/0x20 [] devinet_ioctl+0x501/0x800 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] do_vfs_ioctl+0x98/0x570 [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b stack backtrace: Pid: 567, comm: ifconfig Not tainted 2.6.39-rc6+ #1 Call Trace: [] print_irq_inversion_bug+0x146/0x170 [] ? print_irq_inversion_bug+0x170/0x170 [] check_usage_forwards+0x9c/0x110 [] mark_lock+0x19c/0x400 [] __lock_acquire+0x7ce/0x1e10 [] ? mark_lock+0x1f3/0x400 [] ? __lock_acquire+0xf07/0x1e10 [] ? native_sched_clock+0x15/0x70 [] lock_acquire+0x9d/0x130 [] ? mld_ifc_timer_expire+0xff/0x280 [] ? lock_release_holdtime+0x3d/0x1a0 [] _raw_spin_lock_bh+0x3b/0x70 [] ? mld_ifc_timer_expire+0xff/0x280 [] ? _raw_spin_unlock+0x2b/0x40 [] mld_ifc_timer_expire+0xff/0x280 [] run_timer_softirq+0x179/0x3f0 [] ? run_timer_softirq+0xeb/0x3f0 [] ? sched_clock+0x9/0x10 [] ? mld_gq_timer_expire+0x30/0x30 [] __do_softirq+0xc0/0x210 [] ? tick_program_event+0x1f/0x30 [] call_softirq+0x1c/0x30 [] do_softirq+0xad/0xe0 [] irq_exit+0x9e/0xb0 [] smp_apic_timer_interrupt+0x70/0x9b [] apic_timer_interrupt+0x13/0x20 [] ? retint_restore_args+0x13/0x13 [] ? lock_is_held+0x17/0xd0 [] rt_do_flush+0x87/0x2a0 [] rt_cache_flush+0x46/0x60 [] fib_disable_ip+0x40/0x60 [] fib_inetaddr_event+0xd7/0xe0 [] notifier_call_chain+0x8c/0xc0 [] __blocking_notifier_call_chain+0x78/0xb0 [] blocking_notifier_call_chain+0x16/0x20 [] __inet_del_ifa+0xf1/0x2e0 [] inet_del_ifa+0x13/0x20 [] devinet_ioctl+0x501/0x800 [] ? local_clock+0x6f/0x80 [] ? do_page_fault+0x268/0x560 [] inet_ioctl+0x88/0xa0 [] sock_do_ioctl+0x30/0x70 [] sock_ioctl+0x79/0x2f0 [] ? __call_rcu+0xa7/0x190 [] do_vfs_ioctl+0x98/0x570 [] ? fget_light+0x33e/0x430 [] ? retint_swapgs+0x13/0x1b [] sys_ioctl+0x91/0xa0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Roland Dreier Signed-off-by: Shreyas N Bhatewara Signed-off-by: Scott J. Goldman Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_drv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 0d47c3a05307..c16ed961153a 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -178,6 +178,7 @@ static void vmxnet3_process_events(struct vmxnet3_adapter *adapter) { int i; + unsigned long flags; u32 events = le32_to_cpu(adapter->shared->ecr); if (!events) return; @@ -190,10 +191,10 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter) /* Check if there is an error on xmit/recv queues */ if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) { - spin_lock(&adapter->cmd_lock); + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_QUEUE_STATUS); - spin_unlock(&adapter->cmd_lock); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); for (i = 0; i < adapter->num_tx_queues; i++) if (adapter->tqd_start[i].status.stopped) @@ -2733,13 +2734,14 @@ static void vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter) { u32 cfg; + unsigned long flags; /* intr settings */ - spin_lock(&adapter->cmd_lock); + spin_lock_irqsave(&adapter->cmd_lock, flags); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_CONF_INTR); cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD); - spin_unlock(&adapter->cmd_lock); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); adapter->intr.type = cfg & 0x3; adapter->intr.mask_mode = (cfg >> 2) & 0x3; -- cgit v1.2.2 From 7a7b94ad8ce3e24d4dd97b45583911e0f03aecd6 Mon Sep 17 00:00:00 2001 From: Jimmy Rentz Date: Sun, 17 Apr 2011 16:15:09 -0400 Subject: drm/nouveau: Fix a crash at card takedown for NV40 and older cards NV40 and older cards (pre NV50) reserve a vram bo for the vga memory at card init. This bo is then freed at card shutdown. The problem is that the ttm bo vram manager was already freed. So a crash occurs when the vga bo is freed. The fix is to free the vga bo prior to freeing the ttm bo vram manager. There might be other solutions but this seemed the simplest to me. Signed-off-by: Jimmy Rentz Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_mem.c | 2 -- drivers/gpu/drm/nouveau/nouveau_state.c | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 5045f8b921d6..c3e953b08992 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -152,8 +152,6 @@ nouveau_mem_vram_fini(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - nouveau_bo_ref(NULL, &dev_priv->vga_ram); - ttm_bo_device_release(&dev_priv->ttm.bdev); nouveau_ttm_global_release(dev_priv); diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index a30adec5beaa..915fbce89595 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -768,6 +768,11 @@ static void nouveau_card_takedown(struct drm_device *dev) engine->mc.takedown(dev); engine->display.late_takedown(dev); + if (dev_priv->vga_ram) { + nouveau_bo_unpin(dev_priv->vga_ram); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + } + mutex_lock(&dev->struct_mutex); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); -- cgit v1.2.2 From 9c412942a0bb19ba18f7bd939d42eff1e132a901 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 3 May 2011 07:49:25 +0000 Subject: ipheth: Properly distinguish length and alignment in URBs and skbs The USB protocol this driver implements appears to require 2 bytes of padding in front of each received packet. This used to be equal to the value of NET_IP_ALIGN on x86, so the driver abused that constant and mostly worked, but this is no longer the case. The driver also mixed up the URB and packet lengths, resulting in 2 bytes of junk at the end of the skb. Introduce a private constant for the 2 bytes of padding; fix this confusion and check for the under-length case. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/usb/ipheth.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 7d42f9a2c068..81126ff85e05 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -65,6 +65,7 @@ #define IPHETH_USBINTF_PROTO 1 #define IPHETH_BUF_SIZE 1516 +#define IPHETH_IP_ALIGN 2 /* padding at front of URB */ #define IPHETH_TX_TIMEOUT (5 * HZ) #define IPHETH_INTFNUM 2 @@ -202,18 +203,21 @@ static void ipheth_rcvbulk_callback(struct urb *urb) return; } - len = urb->actual_length; - buf = urb->transfer_buffer; + if (urb->actual_length <= IPHETH_IP_ALIGN) { + dev->net->stats.rx_length_errors++; + return; + } + len = urb->actual_length - IPHETH_IP_ALIGN; + buf = urb->transfer_buffer + IPHETH_IP_ALIGN; - skb = dev_alloc_skb(NET_IP_ALIGN + len); + skb = dev_alloc_skb(len); if (!skb) { err("%s: dev_alloc_skb: -ENOMEM", __func__); dev->net->stats.rx_dropped++; return; } - skb_reserve(skb, NET_IP_ALIGN); - memcpy(skb_put(skb, len), buf + NET_IP_ALIGN, len - NET_IP_ALIGN); + memcpy(skb_put(skb, len), buf, len); skb->dev = dev->net; skb->protocol = eth_type_trans(skb, dev->net); -- cgit v1.2.2 From 58e73811c85d0c0e74b8d300547bbc9abaf40a38 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 6 May 2011 01:42:49 -0400 Subject: drm/radeon/kms: ATPX switcheroo fixes When we switch the display mux, also switch the i2c mux. Also use the start and finish methods to let the sbios know that the switch is happening. Should fix: https://bugs.freedesktop.org/show_bug.cgi?id=35398 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atpx_handler.c | 29 ++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index ed5dfe58f29c..9d95792bea3e 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -15,6 +15,9 @@ #define ATPX_VERSION 0 #define ATPX_GPU_PWR 2 #define ATPX_MUX_SELECT 3 +#define ATPX_I2C_MUX_SELECT 4 +#define ATPX_SWITCH_START 5 +#define ATPX_SWITCH_END 6 #define ATPX_INTEGRATED 0 #define ATPX_DISCRETE 1 @@ -149,13 +152,35 @@ static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id) return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id); } +static int radeon_atpx_switch_i2c_mux(acpi_handle handle, int mux_id) +{ + return radeon_atpx_execute(handle, ATPX_I2C_MUX_SELECT, mux_id); +} + +static int radeon_atpx_switch_start(acpi_handle handle, int gpu_id) +{ + return radeon_atpx_execute(handle, ATPX_SWITCH_START, gpu_id); +} + +static int radeon_atpx_switch_end(acpi_handle handle, int gpu_id) +{ + return radeon_atpx_execute(handle, ATPX_SWITCH_END, gpu_id); +} static int radeon_atpx_switchto(enum vga_switcheroo_client_id id) { + int gpu_id; + if (id == VGA_SWITCHEROO_IGD) - radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0); + gpu_id = ATPX_INTEGRATED; else - radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1); + gpu_id = ATPX_DISCRETE; + + radeon_atpx_switch_start(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_i2c_mux(radeon_atpx_priv.atpx_handle, gpu_id); + radeon_atpx_switch_end(radeon_atpx_priv.atpx_handle, gpu_id); + return 0; } -- cgit v1.2.2 From 2bbd4492552867053b5a618a2474297e2b1c355d Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 6 May 2011 23:47:53 +0200 Subject: drm: mm: fix debug output The looping helper didn't do anything due to a superficial semicolon. Furthermore one of the two dump functions suffered from copy&paste fail. While staring at the code I've also noticed that the replace helper (currently unused) is a bit broken. Signed-off-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_mm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 5d00b0fc0d91..959186cbf328 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -431,7 +431,7 @@ EXPORT_SYMBOL(drm_mm_search_free_in_range); void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new) { list_replace(&old->node_list, &new->node_list); - list_replace(&old->node_list, &new->hole_stack); + list_replace(&old->hole_stack, &new->hole_stack); new->hole_follows = old->hole_follows; new->mm = old->mm; new->start = old->start; @@ -699,8 +699,8 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) entry->size); total_used += entry->size; if (entry->hole_follows) { - hole_start = drm_mm_hole_node_start(&mm->head_node); - hole_end = drm_mm_hole_node_end(&mm->head_node); + hole_start = drm_mm_hole_node_start(entry); + hole_end = drm_mm_hole_node_end(entry); hole_size = hole_end - hole_start; seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: free\n", hole_start, hole_end, hole_size); -- cgit v1.2.2 From 45e5f6a2ee6aac20e393d44f8a6762104426c81b Mon Sep 17 00:00:00 2001 From: Ilija Hadzic Date: Wed, 4 May 2011 20:15:03 -0400 Subject: drm/radeon: fix order of doing things in radeon_crtc_cursor_set if object pin or object lookup in radeon_cursor_set fail, the function could leave inconsistent mouse width and hight values in radeon_crtc fixed by moving cursor width and height assignments after all checks have passed Signed-off-by: Ilija Hadzic Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_cursor.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index bdf2fa1189ae..3189a7efb2e9 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -167,9 +167,6 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; } - radeon_crtc->cursor_width = width; - radeon_crtc->cursor_height = height; - obj = drm_gem_object_lookup(crtc->dev, file_priv, handle); if (!obj) { DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id); @@ -180,6 +177,9 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc, if (ret) goto fail; + radeon_crtc->cursor_width = width; + radeon_crtc->cursor_height = height; + radeon_lock_cursor(crtc, true); /* XXX only 27 bit offset for legacy cursor */ radeon_set_cursor(crtc, obj, gpu_addr); -- cgit v1.2.2 From 4f87af46107499415afd238be104587b5a9d7ac3 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 4 May 2011 11:41:47 -0400 Subject: drm/radeon/kms: add pci id to acer travelmate quirk for 5730 Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=34082 Reported by: Sampo Laaksonen Signed-off-by: Alex Deucher Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index f116516bfef7..dd881d035f09 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -431,7 +431,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, } } - /* Acer laptop (Acer TravelMate 5730G) has an HDMI port + /* Acer laptop (Acer TravelMate 5730/5730G) has an HDMI port * on the laptop and a DVI port on the docking station and * both share the same encoder, hpd pin, and ddc line. * So while the bios table is technically correct, @@ -440,7 +440,7 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev, * with different crtcs which isn't possible on the hardware * side and leaves no crtcs for LVDS or VGA. */ - if ((dev->pdev->device == 0x95c4) && + if (((dev->pdev->device == 0x95c4) || (dev->pdev->device == 0x9591)) && (dev->pdev->subsystem_vendor == 0x1025) && (dev->pdev->subsystem_device == 0x013c)) { if ((*connector_type == DRM_MODE_CONNECTOR_DVII) && -- cgit v1.2.2 From 9fbdaeb4f4dd14a0caa9fc35c496d5440c251a3a Mon Sep 17 00:00:00 2001 From: Manoj Iyer Date: Sun, 8 May 2011 18:04:29 -0400 Subject: thinkpad-acpi: module autoloading for newer Lenovo ThinkPads. The newer Lenovo ThinkPads have HKEY HID of LEN0068 instead of IBM0068. Added new HID so that thinkpad_acpi module will auto load on these newer Lenovo ThinkPads. Acked-by: Henrique de Moraes Holschuh Cc: stable@kernel.org Signed-off-by: Manoj Iyer Signed-off-by: Andy Lutomirski Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index efb3b6b9bcdb..562fcf0dd2b5 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -128,7 +128,8 @@ enum { }; /* ACPI HIDs */ -#define TPACPI_ACPI_HKEY_HID "IBM0068" +#define TPACPI_ACPI_IBM_HKEY_HID "IBM0068" +#define TPACPI_ACPI_LENOVO_HKEY_HID "LEN0068" #define TPACPI_ACPI_EC_HID "PNP0C09" /* Input IDs */ @@ -3879,7 +3880,8 @@ errexit: } static const struct acpi_device_id ibm_htk_device_ids[] = { - {TPACPI_ACPI_HKEY_HID, 0}, + {TPACPI_ACPI_IBM_HKEY_HID, 0}, + {TPACPI_ACPI_LENOVO_HKEY_HID, 0}, {"", 0}, }; -- cgit v1.2.2 From 6192fa7109fb33591fa1078c8c1981e39da02d2d Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Tue, 5 Apr 2011 23:38:36 +0900 Subject: sony-laptop: report failures on setting LCD brightness Check if we were successful in setting the requested brightness and report failure in that case. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 8f709aec4da0..9d80ae4e6be6 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -966,9 +966,10 @@ static int sony_nc_update_status_ng(struct backlight_device *bd) int *handle = (int *)bl_get_data(bd); value = bd->props.brightness; - sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result); + if (sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result)) + return -EIO; - return sony_nc_get_brightness_ng(bd); + return value; } static const struct backlight_ops sony_backlight_ops = { -- cgit v1.2.2 From 62d2f23e8bce3e7da4db53928e810fc8a474ce70 Mon Sep 17 00:00:00 2001 From: Mattia Dongili Date: Mon, 9 May 2011 10:20:29 -0400 Subject: [PATCH] sony-laptop: limit brightness range to DSDT provided ones The new style brightness control provides an operating range of 9 values (seems consistent over a large number of models sharing the same brightness control methods). Read and use the minimum and maximum values to limit the backlight interface between those boundaries. Signed-off-by: Mattia Dongili Signed-off-by: Matthew Garrett --- drivers/platform/x86/sony-laptop.c | 127 ++++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 9d80ae4e6be6..6fe8cd6e23b5 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -934,6 +934,14 @@ static ssize_t sony_nc_sysfs_store(struct device *dev, /* * Backlight device */ +struct sony_backlight_props { + struct backlight_device *dev; + int handle; + u8 offset; + u8 maxlvl; +}; +struct sony_backlight_props sony_bl_props; + static int sony_backlight_update_status(struct backlight_device *bd) { return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", @@ -954,19 +962,23 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd) { int result; int *handle = (int *)bl_get_data(bd); + struct sony_backlight_props *sdev = + (struct sony_backlight_props *)bl_get_data(bd); - sony_call_snc_handle(*handle, 0x0200, &result); + sony_call_snc_handle(sdev->handle, 0x0200, &result); - return result & 0xff; + return (result & 0xff) - sdev->offset; } static int sony_nc_update_status_ng(struct backlight_device *bd) { int value, result; int *handle = (int *)bl_get_data(bd); + struct sony_backlight_props *sdev = + (struct sony_backlight_props *)bl_get_data(bd); - value = bd->props.brightness; - if (sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result)) + value = bd->props.brightness + sdev->offset; + if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result)) return -EIO; return value; @@ -982,8 +994,6 @@ static const struct backlight_ops sony_backlight_ng_ops = { .update_status = sony_nc_update_status_ng, .get_brightness = sony_nc_get_brightness_ng, }; -static int backlight_ng_handle; -static struct backlight_device *sony_backlight_device; /* * New SNC-only Vaios event mapping to driver known keys @@ -1550,6 +1560,75 @@ static void sony_nc_kbd_backlight_resume(void) &ignore); } +static void sony_nc_backlight_ng_read_limits(int handle, + struct sony_backlight_props *props) +{ + int offset; + acpi_status status; + u8 brlvl, i; + u8 min = 0xff, max = 0x00; + struct acpi_object_list params; + union acpi_object in_obj; + union acpi_object *lvl_enum; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + + props->handle = handle; + props->offset = 0; + props->maxlvl = 0xff; + + offset = sony_find_snc_handle(handle); + if (offset < 0) + return; + + /* try to read the boundaries from ACPI tables, if we fail the above + * defaults should be reasonable + */ + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = offset; + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms, + &buffer); + if (ACPI_FAILURE(status)) + return; + + lvl_enum = (union acpi_object *) buffer.pointer; + if (!lvl_enum) { + pr_err("No SN06 return object."); + return; + } + if (lvl_enum->type != ACPI_TYPE_BUFFER) { + pr_err("Invalid SN06 return object 0x%.2x\n", + lvl_enum->type); + goto out_invalid; + } + + /* the buffer lists brightness levels available, brightness levels are + * from 0 to 8 in the array, other values are used by ALS control. + */ + for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { + + brlvl = *(lvl_enum->buffer.pointer + i); + dprintk("Brightness level: %d\n", brlvl); + + if (!brlvl) + break; + + if (brlvl > max) + max = brlvl; + if (brlvl < min) + min = brlvl; + } + props->offset = min; + props->maxlvl = max; + dprintk("Brightness levels: min=%d max=%d\n", props->offset, + props->maxlvl); + +out_invalid: + kfree(buffer.pointer); + return; +} + static void sony_nc_backlight_setup(void) { acpi_handle unused; @@ -1558,14 +1637,14 @@ static void sony_nc_backlight_setup(void) struct backlight_properties props; if (sony_find_snc_handle(0x12f) != -1) { - backlight_ng_handle = 0x12f; ops = &sony_backlight_ng_ops; - max_brightness = 0xff; + sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; } else if (sony_find_snc_handle(0x137) != -1) { - backlight_ng_handle = 0x137; ops = &sony_backlight_ng_ops; - max_brightness = 0xff; + sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props); + max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset; } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &unused))) { @@ -1578,22 +1657,22 @@ static void sony_nc_backlight_setup(void) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; props.max_brightness = max_brightness; - sony_backlight_device = backlight_device_register("sony", NULL, - &backlight_ng_handle, - ops, &props); + sony_bl_props.dev = backlight_device_register("sony", NULL, + &sony_bl_props, + ops, &props); - if (IS_ERR(sony_backlight_device)) { - pr_warning(DRV_PFX "unable to register backlight device\n"); - sony_backlight_device = NULL; + if (IS_ERR(sony_bl_props.dev)) { + pr_warn(DRV_PFX "unable to register backlight device\n"); + sony_bl_props.dev = NULL; } else - sony_backlight_device->props.brightness = - ops->get_brightness(sony_backlight_device); + sony_bl_props.dev->props.brightness = + ops->get_brightness(sony_bl_props.dev); } static void sony_nc_backlight_cleanup(void) { - if (sony_backlight_device) - backlight_device_unregister(sony_backlight_device); + if (sony_bl_props.dev) + backlight_device_unregister(sony_bl_props.dev); } static int sony_nc_add(struct acpi_device *device) @@ -2591,7 +2670,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, mutex_lock(&spic_dev.lock); switch (cmd) { case SONYPI_IOCGBRT: - if (sony_backlight_device == NULL) { + if (sony_bl_props.dev == NULL) { ret = -EIO; break; } @@ -2604,7 +2683,7 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, ret = -EFAULT; break; case SONYPI_IOCSBRT: - if (sony_backlight_device == NULL) { + if (sony_bl_props.dev == NULL) { ret = -EIO; break; } @@ -2618,8 +2697,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd, break; } /* sync the backlight device status */ - sony_backlight_device->props.brightness = - sony_backlight_get_brightness(sony_backlight_device); + sony_bl_props.dev->props.brightness = + sony_backlight_get_brightness(sony_bl_props.dev); break; case SONYPI_IOCGBAT1CAP: if (ec_read16(SONYPI_BAT1_FULL, &val16)) { -- cgit v1.2.2 From 14fdb152416c0fab80ecddf492c129d7da1bb8ef Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Mon, 9 May 2011 10:44:01 -0400 Subject: eeepc-laptop: Use ACPI handle to identify rfkill port The ACPI notification we get from rfkill events on these machines gives us all the information we need to identify the port that's changed. Do so rather than assuming that it's always bus 1. Signed-off-by: Matthew Garrett --- drivers/platform/x86/eeepc-laptop.c | 57 ++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 5f2dd386152b..2c1abf63957f 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -585,8 +585,9 @@ static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc) return true; } -static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) +static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle) { + struct pci_dev *port; struct pci_dev *dev; struct pci_bus *bus; bool blocked = eeepc_wlan_rfkill_blocked(eeepc); @@ -599,9 +600,16 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) mutex_lock(&eeepc->hotplug_lock); if (eeepc->hotplug_slot) { - bus = pci_find_bus(0, 1); + port = acpi_get_pci_dev(handle); + if (!port) { + pr_warning("Unable to find port\n"); + goto out_unlock; + } + + bus = port->subordinate; + if (!bus) { - pr_warning("Unable to find PCI bus 1?\n"); + pr_warning("Unable to find PCI bus?\n"); goto out_unlock; } @@ -609,6 +617,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) pr_err("Unable to read PCI config space?\n"); goto out_unlock; } + absent = (l == 0xffffffff); if (blocked != absent) { @@ -647,6 +656,17 @@ out_unlock: mutex_unlock(&eeepc->hotplug_lock); } +static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node) +{ + acpi_status status = AE_OK; + acpi_handle handle; + + status = acpi_get_handle(NULL, node, &handle); + + if (ACPI_SUCCESS(status)) + eeepc_rfkill_hotplug(eeepc, handle); +} + static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) { struct eeepc_laptop *eeepc = data; @@ -654,7 +674,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) if (event != ACPI_NOTIFY_BUS_CHECK) return; - eeepc_rfkill_hotplug(eeepc); + eeepc_rfkill_hotplug(eeepc, handle); } static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, @@ -672,6 +692,11 @@ static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, eeepc); if (ACPI_FAILURE(status)) pr_warning("Failed to register notify on %s\n", node); + /* + * Refresh pci hotplug in case the rfkill state was + * changed during setup. + */ + eeepc_rfkill_hotplug(eeepc, handle); } else return -ENODEV; @@ -693,6 +718,12 @@ static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc, if (ACPI_FAILURE(status)) pr_err("Error removing rfkill notify handler %s\n", node); + /* + * Refresh pci hotplug in case the rfkill + * state was changed after + * eeepc_unregister_rfkill_notifier() + */ + eeepc_rfkill_hotplug(eeepc, handle); } } @@ -816,11 +847,7 @@ static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) rfkill_destroy(eeepc->wlan_rfkill); eeepc->wlan_rfkill = NULL; } - /* - * Refresh pci hotplug in case the rfkill state was changed after - * eeepc_unregister_rfkill_notifier() - */ - eeepc_rfkill_hotplug(eeepc); + if (eeepc->hotplug_slot) pci_hp_deregister(eeepc->hotplug_slot); @@ -889,11 +916,6 @@ static int eeepc_rfkill_init(struct eeepc_laptop *eeepc) eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); - /* - * Refresh pci hotplug in case the rfkill state was changed during - * setup. - */ - eeepc_rfkill_hotplug(eeepc); exit: if (result && result != -ENODEV) @@ -928,8 +950,11 @@ static int eeepc_hotk_restore(struct device *device) struct eeepc_laptop *eeepc = dev_get_drvdata(device); /* Refresh both wlan rfkill state and pci hotplug */ - if (eeepc->wlan_rfkill) - eeepc_rfkill_hotplug(eeepc); + if (eeepc->wlan_rfkill) { + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P5"); + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P6"); + eeepc_rfkill_hotplug_update(eeepc, "\\_SB.PCI0.P0P7"); + } if (eeepc->bluetooth_rfkill) rfkill_set_sw_state(eeepc->bluetooth_rfkill, -- cgit v1.2.2 From 4e61f0d75aa86c9e59451f6bcffcdceb355b4fc4 Mon Sep 17 00:00:00 2001 From: Austin Zhang Date: Mon, 9 May 2011 23:54:14 +0800 Subject: HID: hid-multitouch: add support for Ilitek dual-touch panel Added ILITEK hid dual touch panel support into hid-multitouch. Signed-off-by: Austin Zhang Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d2d4e5f1911e..d9635d6a907a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -306,6 +306,7 @@ config HID_MULTITOUCH - Cando dual touch panel - Cypress TrueTouch panels - Hanvon dual touch panels + - Ilitek dual touch panel - IrTouch Infrared USB panels - MosArt dual-touch panels - PenMount dual touch panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6e31b9f93329..c0ea857ed429 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1377,6 +1377,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 252aebae5701..0f29b3facca1 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -330,6 +330,9 @@ #define USB_DEVICE_ID_UGCI_FLYING 0x0020 #define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 +#define USB_VENDOR_ID_ILITEK 0x222a +#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 + #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index bf46804670c7..b21251b43a35 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -589,6 +589,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, + /* Ilitek dual touch panel */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, + USB_DEVICE_ID_ILITEK_MULTITOUCH) }, + /* IRTOUCH panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, -- cgit v1.2.2 From 49183b2818de6899383bb82bc032f9344d6791ff Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 19 Apr 2011 21:14:14 +0100 Subject: drm/i915: Only enable the plane after setting the fb base (pre-ILK) When enabling the plane, it is helpful to have already pointed that plane to valid memory or else we may incur the wrath of a PGTBL_ER. This code preserved the behaviour from the bad old days for unknown reasons... Found by assert_fb_bound_for_plane(). References: https://bugs.freedesktop.org/show_bug.cgi?id=36246 Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aab06cfaf70f..967451e90dee 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5154,8 +5154,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); - if (!HAS_PCH_SPLIT(dev)) - intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); -- cgit v1.2.2 From 39adb7a542db08998b4ae88f1698c4300dc39b55 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 22 Apr 2011 22:17:21 +0100 Subject: drm/i915: fix intel_crtc_clock_get pipe reads after "cleanup cleanup" Despite the fixes in 548f245ba6a31 (drm/i915: fix per-pipe reads after "cleanup"), we missed one neighbouring read that was mistakenly replaced with the reg value in 9db4a9c (drm/i915: cleanup per-pipe reg usage). This was preventing us from correctly determining the mode the BIOS left the panel in for machines that neither have an OpRegion nor access to the VBT, (e.g. the EeePC 700). Signed-off-by: Chris Wilson Cc: Jesse Barnes Cc: stable@kernel.org Reviewed-by: Jesse Barnes Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 967451e90dee..373c2a005ec1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5603,9 +5603,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc) intel_clock_t clock; if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) - fp = FP0(pipe); + fp = I915_READ(FP0(pipe)); else - fp = FP1(pipe); + fp = I915_READ(FP1(pipe)); clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; if (IS_PINEVIEW(dev)) { -- cgit v1.2.2 From 2fb4e61d9471867677c97bf11dba8f1e9dfa7f7c Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 21 Apr 2011 16:08:14 -0600 Subject: drm/i915/lvds: Only act on lid notify when the device is on If we're using vga switcheroo, the device may be turned off and poking it can return random state. This provokes an OOPS fixed separately by 8ff887c847 (drm/i915/dp: Be paranoid in case we disable a DP before it is attached). Trying to use and respond to events on a device that has been turned off by the user is in principle a silly thing to do. Signed-off-by: Alex Williamson Signed-off-by: Chris Wilson Cc: stable@kernel.org Signed-off-by: Keith Packard --- drivers/gpu/drm/i915/intel_lvds.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a562bd2648c7..67cb076d271b 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -539,6 +539,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, struct drm_device *dev = dev_priv->dev; struct drm_connector *connector = dev_priv->int_lvds_connector; + if (dev->switch_power_state != DRM_SWITCH_POWER_ON) + return NOTIFY_OK; + /* * check and update the status of LVDS connector after receiving * the LID nofication event. -- cgit v1.2.2 From dcbe14b91a920657ff3a9ba0efb7c5b5562f956a Mon Sep 17 00:00:00 2001 From: Kleber Sacilotto de Souza Date: Wed, 4 May 2011 13:05:11 +0000 Subject: ehea: fix wrongly reported speed and port Currently EHEA reports to ethtool as supporting 10M, 100M, 1G and 10G and connected to FIBRE independent of the hardware configuration. However, when connected to FIBRE the only supported speed is 10G full-duplex, and the other speeds and modes are only supported when connected to twisted pair. Signed-off-by: Kleber Sacilotto de Souza Acked-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_ethtool.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 3e2e734fecb7..f3bbdcef338c 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c @@ -55,15 +55,20 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->duplex = -1; } - cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full - | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half - | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half - | SUPPORTED_Autoneg | SUPPORTED_FIBRE); - - cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg - | ADVERTISED_FIBRE); + if (cmd->speed == SPEED_10000) { + cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); + cmd->port = PORT_FIBRE; + } else { + cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_10baseT_Half | SUPPORTED_Autoneg + | SUPPORTED_TP); + cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg + | ADVERTISED_TP); + cmd->port = PORT_TP; + } - cmd->port = PORT_FIBRE; cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE; return 0; -- cgit v1.2.2 From 6709d9521df05c105343473ab8b147e2ef1e13d8 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Wed, 4 May 2011 22:40:46 +0000 Subject: be2net: Fixed bugs related to PVID. Fixed bug to make sure 'pvid' retrieval will work on big endian hosts. Fixed incorrect comparison between the Rx Completion's 16-bit VLAN TCI and the PVID. Now comparing only the relevant 12 bits corresponding to the VID. Renamed 'vid' field under Rx Completion to 'vlan_tag' to reflect accurate description. Signed-off-by: Somnath Kotur Signed-off-by: David S. Miller --- drivers/net/benet/be.h | 2 +- drivers/net/benet/be_cmds.c | 2 +- drivers/net/benet/be_main.c | 18 ++++++++++++------ 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 66823eded7a3..2353eca32593 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -213,7 +213,7 @@ struct be_rx_stats { struct be_rx_compl_info { u32 rss_hash; - u16 vid; + u16 vlan_tag; u16 pkt_size; u16 rxq_idx; u16 mac_id; diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 1e2d825bb94a..9dc9394fd4ca 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -132,7 +132,7 @@ static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, struct be_async_event_grp5_pvid_state *evt) { if (evt->enabled) - adapter->pvid = evt->tag; + adapter->pvid = le16_to_cpu(evt->tag); else adapter->pvid = 0; } diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 02a0443d1821..9187fb4e08f1 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -1018,7 +1018,8 @@ static void be_rx_compl_process(struct be_adapter *adapter, kfree_skb(skb); return; } - vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rxcp->vid); + vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, + rxcp->vlan_tag); } else { netif_receive_skb(skb); } @@ -1076,7 +1077,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter, if (likely(!rxcp->vlanf)) napi_gro_frags(&eq_obj->napi); else - vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, rxcp->vid); + vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, + rxcp->vlan_tag); } static void be_parse_rx_compl_v1(struct be_adapter *adapter, @@ -1102,7 +1104,8 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter, rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl); rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); + rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, + compl); } static void be_parse_rx_compl_v0(struct be_adapter *adapter, @@ -1128,7 +1131,8 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter, rxcp->pkt_type = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl); rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl); - rxcp->vid = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); + rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, + compl); } static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) @@ -1155,9 +1159,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) rxcp->vlanf = 0; if (!lancer_chip(adapter)) - rxcp->vid = swab16(rxcp->vid); + rxcp->vlan_tag = swab16(rxcp->vlan_tag); - if ((adapter->pvid == rxcp->vid) && !adapter->vlan_tag[rxcp->vid]) + if (((adapter->pvid & VLAN_VID_MASK) == + (rxcp->vlan_tag & VLAN_VID_MASK)) && + !adapter->vlan_tag[rxcp->vlan_tag]) rxcp->vlanf = 0; /* As the compl has been parsed, reset it; we wont touch it again */ -- cgit v1.2.2 From 057bef938896e6266ae24ec4266d24792d27c29a Mon Sep 17 00:00:00 2001 From: Matvejchikov Ilya Date: Fri, 6 May 2011 06:23:09 +0000 Subject: NET: slip, fix ldisc->open retval TTY layer expects 0 if the ldisc->open operation succeeded. Signed-off-by : Matvejchikov Ilya Acked-by: Oliver Hartkopp Acked-by: Alan Cox Signed-off-by: David S. Miller --- drivers/net/slip.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 86cbb9ea2f26..8ec1a9a0bb9a 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -853,7 +853,9 @@ static int slip_open(struct tty_struct *tty) /* Done. We have linked the TTY line to a channel. */ rtnl_unlock(); tty->receive_room = 65536; /* We don't flow control */ - return sl->dev->base_addr; + + /* TTY layer expects 0 on success */ + return 0; err_free_bufs: sl_free_bufs(sl); -- cgit v1.2.2 From ce3dad0f74e6b240f0b1dedbd8ea268a3f298d82 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Fri, 6 May 2011 02:53:51 +0000 Subject: PCH_GbE : Fixed the issue of collision detection The collision detection setting was invalid. When collision occurred, because data was not resent, there was an issue to which a transmitting throughput falls. This patch enables the collision detection. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller --- drivers/net/pch_gbe/pch_gbe_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 2ef2f9cdefa6..4ebd1d4ad3ed 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -43,8 +43,7 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_MAC_RGMII_CTRL_SETTING ( \ PCH_GBE_CHIP_TYPE_INTERNAL | \ - PCH_GBE_RGMII_MODE_RGMII | \ - PCH_GBE_CRS_SEL \ + PCH_GBE_RGMII_MODE_RGMII \ ) /* Ethertype field values */ -- cgit v1.2.2 From 5d05a04d283061b586e8dc819cfa6f4b8cfd5948 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Fri, 6 May 2011 02:53:56 +0000 Subject: PCH_GbE : Fixed the issue of checksum judgment The checksum judgment was mistaken. Judgment result 0:Correct 1:Wrong This patch fixes the issue. Signed-off-by: Toshiharu Okada Signed-off-by: David S. Miller --- drivers/net/pch_gbe/pch_gbe_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 4ebd1d4ad3ed..9f6c4025c6ea 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -1493,12 +1493,11 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, /* Write meta date of skb */ skb_put(skb, length); skb->protocol = eth_type_trans(skb, netdev); - if ((tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) == - PCH_GBE_RXD_ACC_STAT_TCPIPOK) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else { + if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK) skb->ip_summed = CHECKSUM_NONE; - } + else + skb->ip_summed = CHECKSUM_UNNECESSARY; + napi_gro_receive(&adapter->napi, skb); (*work_done)++; pr_debug("Receive skb->ip_summed: %d length: %d\n", -- cgit v1.2.2 From b0e6baf5619a6fa3eaf43b55fdb4daa362c3c916 Mon Sep 17 00:00:00 2001 From: Tomoya Date: Mon, 9 May 2011 01:19:37 +0000 Subject: pch_gbe: support ML7223 IOH Support new device OKI SEMICONDUCTOR ML7223 IOH(Input/Output Hub). The ML7223 IOH is for MP(Media Phone) use. The ML7223 is companion chip for Intel Atom E6xx series. The ML7223 is completely compatible for Intel EG20T PCH. Signed-off-by: Tomoya MORINAGA Signed-off-by: David S. Miller --- drivers/net/Kconfig | 8 +++++++- drivers/net/pch_gbe/pch_gbe_main.c | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index dc280bc8eba2..6c884ef1b069 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2536,7 +2536,7 @@ config S6GMAC source "drivers/net/stmmac/Kconfig" config PCH_GBE - tristate "PCH Gigabit Ethernet" + tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GbE" depends on PCI select MII ---help--- @@ -2548,6 +2548,12 @@ config PCH_GBE to Gigabit Ethernet. This driver enables Gigabit Ethernet function. + This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ + Output Hub), ML7223. + ML7223 IOH is for MP(Media Phone) use. + ML7223 is companion chip for Intel Atom E6xx series. + ML7223 is completely compatible for Intel EG20T PCH. + endif # NETDEV_1000 # diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c index 9f6c4025c6ea..56d049a472da 100644 --- a/drivers/net/pch_gbe/pch_gbe_main.c +++ b/drivers/net/pch_gbe/pch_gbe_main.c @@ -34,6 +34,10 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_COPYBREAK_DEFAULT 256 #define PCH_GBE_PCI_BAR 1 +/* Macros for ML7223 */ +#define PCI_VENDOR_ID_ROHM 0x10db +#define PCI_DEVICE_ID_ROHM_ML7223_GBE 0x8013 + #define PCH_GBE_TX_WEIGHT 64 #define PCH_GBE_RX_WEIGHT 64 #define PCH_GBE_RX_BUFFER_WRITE 16 @@ -2418,6 +2422,13 @@ static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = { .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = (0xFFFF00) }, + {.vendor = PCI_VENDOR_ID_ROHM, + .device = PCI_DEVICE_ID_ROHM_ML7223_GBE, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_NETWORK_ETHERNET << 8), + .class_mask = (0xFFFF00) + }, /* required last entry */ {0} }; -- cgit v1.2.2 From fdb1bb157525907163e2a0c96fe8bb19fbe867a8 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 10 May 2011 17:13:37 +0200 Subject: [S390] sclp/memory hotplug: fix initial usecount of increments Fix initial usecount of attached and assigned storage increments so they can be set offline. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_cmd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 4b60ede07f0e..be55fb2b1b1c 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -518,6 +518,8 @@ static void __init insert_increment(u16 rn, int standby, int assigned) return; new_incr->rn = rn; new_incr->standby = standby; + if (!standby) + new_incr->usecount = 1; last_rn = 0; prev = &sclp_mem_list; list_for_each_entry(incr, &sclp_mem_list, list) { -- cgit v1.2.2 From aade6c0dfb46ff7ce7df0ed7a2ef15d2d3c47f05 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Tue, 10 May 2011 17:13:38 +0200 Subject: [S390] dasd: prevent IO error during reserve/release loop The termination of running CQR caused by reserve/release operations may lead to an IO error if reserve/release is done in a tight loop. Prevent this by increasing the retry counter after termination. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 475e603fc584..86b6f1cc1b10 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1742,11 +1742,20 @@ int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) static inline int _dasd_term_running_cqr(struct dasd_device *device) { struct dasd_ccw_req *cqr; + int rc; if (list_empty(&device->ccw_queue)) return 0; cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); - return device->discipline->term_IO(cqr); + rc = device->discipline->term_IO(cqr); + if (!rc) + /* + * CQR terminated because a more important request is pending. + * Undo decreasing of retry counter because this is + * not an error case. + */ + cqr->retries++; + return rc; } int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) -- cgit v1.2.2 From 99aa55b66e3553e6f7212ec1104e0fac06cc558e Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 6 May 2011 20:43:11 +0530 Subject: ath9k: Fix a warning due to a queued work during S3 state during suspend/S3 state drv_flush is called from mac80211 irrespective of interface count. In ath9k we queue a work in ath9k_flush which we expect to be cancelled in the drv_stop call back. during suspend process mac80211 calls drv_stop only when the interface count(local->count) is non-zero. unfortunately when the network manager is enabled, drv_flush is called while drv_stop is not called as local->count reaches '0'. So fix this by simply checking for the device presence in the drv_flush call back in the driver before queueing work or anything else. this patch fixes the following WARNING Call Trace: [] warn_slowpath_common+0x72/0xa0 [] ? ieee80211_can_queue_work+0x39/0x50 [mac80211] [] ? ieee80211_can_queue_work+0x39/0x50 [mac80211] [] warn_slowpath_fmt+0x2b/0x30 [] ieee80211_can_queue_work+0x39/0x50 [mac80211] [] ieee80211_queue_delayed_work+0x21/0x50 [mac80211] [] ath_tx_complete_poll_work+0xb2/0x100 [ath9k] [] run_workqueue+0x8e/0x150 [] ? ath_tx_complete_poll_work+0x0/0x100 [ath9k] [] worker_thread+0x84/0xe0 [] ? autoremove_wake_function+0x0/0x50 [] ? worker_thread+0x0/0xe0 [] kthread+0x74/0x80 [] ? kthread+0x0/0x80 [] kernel_thread_helper+0x7/0x10 ---[ end trace 2aff81010df9215b ]--- Signed-off-by: Rajkumar Manoharan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 17d04ff8d678..1482fa650833 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -2141,6 +2141,8 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) static void ath9k_flush(struct ieee80211_hw *hw, bool drop) { struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); int timeout = 200; /* ms */ int i, j; @@ -2149,6 +2151,12 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) cancel_delayed_work_sync(&sc->tx_complete_work); + if (sc->sc_flags & SC_OP_INVALID) { + ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); + mutex_unlock(&sc->mutex); + return; + } + if (drop) timeout = 1; -- cgit v1.2.2 From eb85de3f84868ca85703a23617b4079ce79a801e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Sat, 7 May 2011 17:46:21 +0200 Subject: iwlegacy: fix IBSS mode crashes We should not switch to non-IBSS channels when working in IBSS mode, otherwise there are microcode errors, and after some time system crashes. This bug is only observable when software scan is used in IBSS mode, so should be considered as regression after: commit 0263aa45293838b514b8af674a03faf040991a90 Author: Stanislaw Gruszka Date: Tue Mar 29 11:24:21 2011 +0200 iwl3945: disable hw scan by default However IBSS mode check, which this patch add again, was removed by commit b2f30e8bdd8ef5f3b5a7ef9146509585a15347d3 Author: Johannes Berg Date: Thu Jan 21 07:32:20 2010 -0800 iwlwifi: remove IBSS channel sanity check That commit claim that mac80211 will not use non-IBSS channel in IBSS mode, what definitely is not true. Bug probably should be fixed in mac80211, but that will require more work, so better to apply that patch temporally, and provide proper mac80211 fix latter. Resolves: https://bugzilla.kernel.org/show_bug.cgi?id=34452 Reported-and-tested-by: Mikko Rapeli Cc: stable@kernel.org # 2.6.38.5+ Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville --- drivers/net/wireless/iwlegacy/iwl-core.c | 7 +++++++ drivers/net/wireless/iwlegacy/iwl-dev.h | 6 ++++++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index 2b08efb3b658..dcbb2ef27f22 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -2155,6 +2155,13 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed) goto set_ch_out; } + if (priv->iw_mode == NL80211_IFTYPE_ADHOC && + !iwl_legacy_is_channel_ibss(ch_info)) { + IWL_DEBUG_MAC80211(priv, "leave - not IBSS channel\n"); + ret = -EINVAL; + goto set_ch_out; + } + spin_lock_irqsave(&priv->lock, flags); for_each_context(priv, ctx) { diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index 9ee849d669f3..f43ac1eb9014 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -1411,6 +1411,12 @@ iwl_legacy_is_channel_passive(const struct iwl_channel_info *ch) return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; } +static inline int +iwl_legacy_is_channel_ibss(const struct iwl_channel_info *ch) +{ + return (ch->flags & EEPROM_CHANNEL_IBSS) ? 1 : 0; +} + static inline void __iwl_legacy_free_pages(struct iwl_priv *priv, struct page *page) { -- cgit v1.2.2 From 2ae1b8b35faba31a59b153cbad07f9c15de99740 Mon Sep 17 00:00:00 2001 From: Paul Fox Date: Mon, 9 May 2011 10:40:42 +0100 Subject: libertas: fix cmdpendingq locking We occasionally see list corruption using libertas. While we haven't been able to diagnose this precisely, we have spotted a possible cause: cmdpendingq is generally modified with driver_lock held. However, there are a couple of points where this is not the case. Fix up those operations to execute under the lock, it seems like the correct thing to do and will hopefully improve the situation. Signed-off-by: Paul Fox Signed-off-by: Daniel Drake Acked-by: Dan Williams Cc: stable@kernel.org Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 7e8a658b7670..f3ac62431a30 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1339,8 +1339,8 @@ int lbs_execute_next_command(struct lbs_private *priv) cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n"); - list_del(&cmdnode->list); spin_lock_irqsave(&priv->driver_lock, flags); + list_del(&cmdnode->list); lbs_complete_command(priv, cmdnode, 0); spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -1352,8 +1352,8 @@ int lbs_execute_next_command(struct lbs_private *priv) (priv->psstate == PS_STATE_PRE_SLEEP)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n"); - list_del(&cmdnode->list); spin_lock_irqsave(&priv->driver_lock, flags); + list_del(&cmdnode->list); lbs_complete_command(priv, cmdnode, 0); spin_unlock_irqrestore(&priv->driver_lock, flags); priv->needtowakeup = 1; @@ -1366,7 +1366,9 @@ int lbs_execute_next_command(struct lbs_private *priv) "EXEC_NEXT_CMD: sending EXIT_PS\n"); } } + spin_lock_irqsave(&priv->driver_lock, flags); list_del(&cmdnode->list); + spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n", le16_to_cpu(cmd->command)); lbs_submit_command(priv, cmdnode); -- cgit v1.2.2 From aae1e743fee2b5523fb31ee050295f062cb26a31 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 9 May 2011 07:43:20 +0000 Subject: net/usb: mark LG VL600 LTE modem ethernet interface as WWAN Like other mobile broadband device ethernet interfaces, mark the LG VL600 with the 'wwan' devtype so userspace knows it needs additional configuration via the AT port before the interface can be used. Signed-off-by: Dan Williams Signed-off-by: David S. Miller --- drivers/net/usb/cdc_ether.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index a301479ecc60..c924ea2bce07 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -567,7 +567,7 @@ static const struct usb_device_id products [] = { { USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = 0, + .driver_info = (unsigned long)&wwan_info, }, /* -- cgit v1.2.2 From 0d4420a90b51abdea71585f571bad6d789ff8eb7 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Tue, 10 May 2011 13:12:30 -0700 Subject: slcan: fix ldisc->open retval TTY layer expects 0 if the ldisc->open operation succeeded. Reported-by: Matvejchikov Ilya Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller --- drivers/net/can/slcan.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index b423965a78d1..1b49df6b2470 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -583,7 +583,9 @@ static int slcan_open(struct tty_struct *tty) /* Done. We have linked the TTY line to a channel. */ rtnl_unlock(); tty->receive_room = 65536; /* We don't flow control */ - return sl->dev->base_addr; + + /* TTY layer expects 0 on success */ + return 0; err_free_chan: sl->tty = NULL; -- cgit v1.2.2 From 285e042dcd9fe9a9b7fbfdc215e4d076791ded8e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 9 May 2011 14:54:33 +1000 Subject: drm/radeon: fix cayman struct accessors. We are accessing totally the wrong struct in this case, and putting uninitialised values into the GPU, which it doesn't like unsurprisingly. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/ni.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 7aade20f63a8..e9e45eac6a03 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -871,7 +871,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) smx_dc_ctl0 = RREG32(SMX_DC_CTL0); smx_dc_ctl0 &= ~NUMBER_OF_SETS(0x1ff); - smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.evergreen.sx_num_of_sets); + smx_dc_ctl0 |= NUMBER_OF_SETS(rdev->config.cayman.sx_num_of_sets); WREG32(SMX_DC_CTL0, smx_dc_ctl0); WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4) | CRC_SIMD_ID_WADDR_DISABLE); @@ -887,20 +887,20 @@ static void cayman_gpu_init(struct radeon_device *rdev) WREG32(TA_CNTL_AUX, DISABLE_CUBE_ANISO); - WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_size / 4) - 1) | - POSITION_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_pos_size / 4) - 1) | - SMX_BUFFER_SIZE((rdev->config.evergreen.sx_max_export_smx_size / 4) - 1))); + WREG32(SX_EXPORT_BUFFER_SIZES, (COLOR_BUFFER_SIZE((rdev->config.cayman.sx_max_export_size / 4) - 1) | + POSITION_BUFFER_SIZE((rdev->config.cayman.sx_max_export_pos_size / 4) - 1) | + SMX_BUFFER_SIZE((rdev->config.cayman.sx_max_export_smx_size / 4) - 1))); - WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.evergreen.sc_prim_fifo_size) | - SC_HIZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_hiz_tile_fifo_size) | - SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.evergreen.sc_earlyz_tile_fifo_size))); + WREG32(PA_SC_FIFO_SIZE, (SC_PRIM_FIFO_SIZE(rdev->config.cayman.sc_prim_fifo_size) | + SC_HIZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_hiz_tile_fifo_size) | + SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.cayman.sc_earlyz_tile_fifo_size))); WREG32(VGT_NUM_INSTANCES, 1); WREG32(CP_PERFMON_CNTL, 0); - WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.evergreen.sq_num_cf_insts) | + WREG32(SQ_MS_FIFO_SIZES, (CACHE_FIFO_SIZE(16 * rdev->config.cayman.sq_num_cf_insts) | FETCH_FIFO_HIWATER(0x4) | DONE_FIFO_HIWATER(0xe0) | ALU_UPDATE_FIFO_HIWATER(0x8))); -- cgit v1.2.2 From 1f03128251b77bfc68d1578a4f11316eb3806238 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 10 May 2011 02:14:52 +0000 Subject: drm/radeon/kms: fix cayman acceleration The TCC disable setup was incorrect. This prevents the GPU from hanging when draw commands are issued. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/ni.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index e9e45eac6a03..3d8a7634bbe9 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -674,7 +674,7 @@ static void cayman_gpu_init(struct radeon_device *rdev) cc_rb_backend_disable = RREG32(CC_RB_BACKEND_DISABLE); cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG); - cgts_tcc_disable = RREG32(CGTS_TCC_DISABLE); + cgts_tcc_disable = 0xff000000; gc_user_rb_backend_disable = RREG32(GC_USER_RB_BACKEND_DISABLE); gc_user_shader_pipe_config = RREG32(GC_USER_SHADER_PIPE_CONFIG); cgts_user_tcc_disable = RREG32(CGTS_USER_TCC_DISABLE); -- cgit v1.2.2 From 03a80665341bbb9a57064c2ddeca13b554d56893 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 9 May 2011 02:24:04 +0000 Subject: drm/radeon/nouveau: fix build regression on alpha due to Xen changes. The Xen changes were using DMA_ERROR_CODE which isn't defined on a few platforms, however we reverted the Xen patch that caused use to try and use this code path earlier in 2.6.39 cycle, so for now lets just force the code to never take this path and allow it to build again on alpha. The proper long term answer is probably to store if the dma_addr has been assigned to alongside the dma_addr in the higher level code, though I think Thomas wanted to rewrite most of this anyways properly. Acked-by: Konrad Rzeszutek Wilk Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_sgdma.c | 3 ++- drivers/gpu/drm/radeon/radeon_gart.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 4bce801bc588..c77111eca6ac 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -42,7 +42,8 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, nvbe->nr_pages = 0; while (num_pages--) { - if (dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE) { + /* this code path isn't called and is incorrect anyways */ + if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/ nvbe->pages[nvbe->nr_pages] = dma_addrs[nvbe->nr_pages]; nvbe->ttm_alloced[nvbe->nr_pages] = true; diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index 8a955bbdb608..a533f52fd163 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -181,9 +181,9 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); for (i = 0; i < pages; i++, p++) { - /* On TTM path, we only use the DMA API if TTM_PAGE_FLAG_DMA32 - * is requested. */ - if (dma_addr[i] != DMA_ERROR_CODE) { + /* we reverted the patch using dma_addr in TTM for now but this + * code stops building on alpha so just comment it out for now */ + if (0) { /*dma_addr[i] != DMA_ERROR_CODE) */ rdev->gart.ttm_alloced[p] = true; rdev->gart.pages_addr[p] = dma_addr[i]; } else { -- cgit v1.2.2 From 557f447f21621de9c5447c8702c33b53279822ce Mon Sep 17 00:00:00 2001 From: Juergen Kilb Date: Thu, 14 Apr 2011 09:31:43 +0200 Subject: mfd: Fixed gpio polarity of omap-usb gpio USB-phy reset With commit 19403165 a main part of ehci-omap.c moved to drivers/mfd/omap-usb-host.c created by commit 17cdd29d. Due to this reorganisation the polarity used to reset the external USB phy changed and USB host doesn't recognize any devices. Signed-off-by: Juergen Kilb Acked-by: Felipe Balbi Tested-by: Steve Sakoman Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 2e165117457b..3ab9ffa00aad 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -717,14 +717,14 @@ static int usbhs_enable(struct device *dev) gpio_request(pdata->ehci_data->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output - (pdata->ehci_data->reset_gpio_port[0], 1); + (pdata->ehci_data->reset_gpio_port[0], 0); } if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { gpio_request(pdata->ehci_data->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output - (pdata->ehci_data->reset_gpio_port[1], 1); + (pdata->ehci_data->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ @@ -904,11 +904,11 @@ static int usbhs_enable(struct device *dev) if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_set_value - (pdata->ehci_data->reset_gpio_port[0], 0); + (pdata->ehci_data->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_set_value - (pdata->ehci_data->reset_gpio_port[1], 0); + (pdata->ehci_data->reset_gpio_port[1], 1); } end_count: -- cgit v1.2.2 From a09aee8b636a3b2b7b10ad57d60d91e9272e771d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 14 Apr 2011 22:43:47 +0800 Subject: mfd: Fix asic3 build error Fix below compile error: CC drivers/mfd/asic3.o drivers/mfd/asic3.c: In function 'asic3_irq_demux': drivers/mfd/asic3.c:147: error: 'irq_data' undeclared (first use in this function) drivers/mfd/asic3.c:147: error: (Each undeclared identifier is reported only once drivers/mfd/asic3.c:147: error: for each function it appears in.) Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index d4a851c6b5bf..0b4d5b23bec9 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -144,7 +144,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) int iter, i; unsigned long flags; - data->chip->irq_ack(irq_data); + data->chip->irq_ack(data); for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { u32 status; -- cgit v1.2.2 From c62dd365e248222903e6e3e3a8f5d8587e7e3345 Mon Sep 17 00:00:00 2001 From: Lesly A M Date: Thu, 14 Apr 2011 17:57:49 +0530 Subject: mfd: Fix for the TWL4030 PM sleep/wakeup sequence Only configure sleep script when the flag is TWL4030_SLEEP_SCRIPT. Adding the missing brackets for fixing the issue. Signed-off-by: Lesly A M Cc: Nishanth Menon Cc: David Derrick Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-power.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 16422de0823a..2c0d4d16491a 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -447,12 +447,13 @@ static int __init load_twl4030_script(struct twl4030_script *tscript, if (err) goto out; } - if (tscript->flags & TWL4030_SLEEP_SCRIPT) + if (tscript->flags & TWL4030_SLEEP_SCRIPT) { if (order) pr_warning("TWL4030: Bad order of scripts (sleep "\ "script before wakeup) Leads to boot"\ "failure on some boards\n"); err = twl4030_config_sleep_sequence(address); + } out: return err; } -- cgit v1.2.2 From 52cd4e5c620af9e21b5298bf01844b98573505a7 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 11 May 2011 15:13:28 -0700 Subject: drivers/rtc/rtc-s3c.c: fixup wake support for rtc The driver is not balancing set_irq and disable_irq_wake() calls, so ensure that it keeps track of whether the wake is enabled. The fixes the following error on S3C6410 devices: WARNING: at kernel/irq/manage.c:382 set_irq_wake+0x84/0xec() Unbalanced IRQ 92 wake disable Signed-off-by: Ben Dooks Signed-off-by: Mark Brown Cc: Alessandro Zummo Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-s3c.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index b3466c491cd3..16512ecae31a 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -46,6 +46,7 @@ static struct clk *rtc_clk; static void __iomem *s3c_rtc_base; static int s3c_rtc_alarmno = NO_IRQ; static int s3c_rtc_tickno = NO_IRQ; +static bool wake_en; static enum s3c_cpu_type s3c_rtc_cpu_type; static DEFINE_SPINLOCK(s3c_rtc_pie_lock); @@ -562,8 +563,12 @@ static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state) } s3c_rtc_enable(pdev, 0); - if (device_may_wakeup(&pdev->dev)) - enable_irq_wake(s3c_rtc_alarmno); + if (device_may_wakeup(&pdev->dev) && !wake_en) { + if (enable_irq_wake(s3c_rtc_alarmno) == 0) + wake_en = true; + else + dev_err(&pdev->dev, "enable_irq_wake failed\n"); + } return 0; } @@ -579,8 +584,10 @@ static int s3c_rtc_resume(struct platform_device *pdev) writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); } - if (device_may_wakeup(&pdev->dev)) + if (device_may_wakeup(&pdev->dev) && wake_en) { disable_irq_wake(s3c_rtc_alarmno); + wake_en = false; + } return 0; } -- cgit v1.2.2 From 21ccc7936dac5ca9b3e2838bbc112a60f34e18b3 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 10 May 2011 16:17:10 +0000 Subject: ehea: Fix memory hotplug oops The ehea driver oopses during memory hotplug if the ports are not up. A simple testcase: # ifconfig ethX down # echo offline > /sys/devices/system/memory/memory32/state Oops: Kernel access of bad area, sig: 11 [#1] last sysfs file: /sys/devices/system/memory/memory32/state REGS: c000000709393110 TRAP: 0300 Not tainted (2.6.39-rc2-01385-g7ef73bc-dirty) DAR: 0000000000000000, DSISR: 40000000 ... NIP [c000000000067c98] .__wake_up_common+0x48/0xf0 LR [c00000000006d034] .__wake_up+0x54/0x90 Call Trace: [c00000000006d034] .__wake_up+0x54/0x90 [d000000006bb6270] .ehea_rereg_mrs+0x140/0x730 [ehea] [d000000006bb69c4] .ehea_mem_notifier+0x164/0x170 [ehea] [c0000000006fc8a8] .notifier_call_chain+0x78/0xf0 [c0000000000b3d70] .__blocking_notifier_call_chain+0x70/0xb0 [c000000000458d78] .memory_notify+0x28/0x40 [c0000000001871d8] .remove_memory+0x208/0x6d0 [c000000000458264] .memory_section_action+0x94/0x140 [c0000000004583ec] .memory_block_change_state+0xdc/0x1d0 [c0000000004585cc] .store_mem_state+0xec/0x160 [c00000000044768c] .sysdev_store+0x3c/0x50 [c00000000020b48c] .sysfs_write_file+0xec/0x1f0 [c00000000018f86c] .vfs_write+0xec/0x1e0 [c00000000018fa88] .SyS_write+0x58/0xd0 To fix this, initialise the waitqueues during port probe instead of port open. Signed-off-by: Anton Blanchard Cc: stable@kernel.org Acked-by: Breno Leitao Signed-off-by: David S. Miller --- drivers/net/ehea/ehea_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 53c0f04b1b23..cf79cf759e13 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2688,9 +2688,6 @@ static int ehea_open(struct net_device *dev) netif_start_queue(dev); } - init_waitqueue_head(&port->swqe_avail_wq); - init_waitqueue_head(&port->restart_wq); - mutex_unlock(&port->port_lock); return ret; @@ -3276,6 +3273,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, INIT_WORK(&port->reset_task, ehea_reset_port); + init_waitqueue_head(&port->swqe_avail_wq); + init_waitqueue_head(&port->restart_wq); + ret = register_netdev(dev); if (ret) { pr_err("register_netdev failed. ret=%d\n", ret); -- cgit v1.2.2 From 747df2258b1b9a2e25929ef496262c339c380009 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 11 May 2011 17:41:18 +0100 Subject: sfc: Always map MCDI shared memory as uncacheable We enabled write-combining for memory-mapped registers in commit 65f0b417dee94f779ce9b77102b7d73c93723b39, but inhibited it for the MCDI shared memory where this is not supported. However, write-combining mappings also allow read-reordering, which may also be a problem. I found that when an SFC9000-family controller is connected to an Intel 3000 chipset, and write-combining is enabled, the controller stops responding to PCIe read requests during driver initialisation while the driver is polling for completion of an MCDI command. This results in an NMI and system hang. Adding read memory barriers between all reads to the shared memory area appears to reduce but not eliminate the probability of this. We have not yet established whether this is a bug in our BIU or in the PCIe bridge. For now, work around by mapping the shared memory area separately. Signed-off-by: Ben Hutchings --- drivers/net/sfc/mcdi.c | 49 ++++++++++++++++++++++++++++++------------------- drivers/net/sfc/nic.h | 2 ++ drivers/net/sfc/siena.c | 25 +++++++++++++++++++++---- 3 files changed, 53 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c index d98479030ef2..3dd45ed61f0a 100644 --- a/drivers/net/sfc/mcdi.c +++ b/drivers/net/sfc/mcdi.c @@ -50,6 +50,20 @@ static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) return &nic_data->mcdi; } +static inline void +efx_mcdi_readd(struct efx_nic *efx, efx_dword_t *value, unsigned reg) +{ + struct siena_nic_data *nic_data = efx->nic_data; + value->u32[0] = (__force __le32)__raw_readl(nic_data->mcdi_smem + reg); +} + +static inline void +efx_mcdi_writed(struct efx_nic *efx, const efx_dword_t *value, unsigned reg) +{ + struct siena_nic_data *nic_data = efx->nic_data; + __raw_writel((__force u32)value->u32[0], nic_data->mcdi_smem + reg); +} + void efx_mcdi_init(struct efx_nic *efx) { struct efx_mcdi_iface *mcdi; @@ -70,8 +84,8 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, size_t inlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); - unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); + unsigned pdu = MCDI_PDU(efx); + unsigned doorbell = MCDI_DOORBELL(efx); unsigned int i; efx_dword_t hdr; u32 xflags, seqno; @@ -92,30 +106,28 @@ static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, MCDI_HEADER_SEQ, seqno, MCDI_HEADER_XFLAGS, xflags); - efx_writed(efx, &hdr, pdu); + efx_mcdi_writed(efx, &hdr, pdu); - for (i = 0; i < inlen; i += 4) { - _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); - /* use wmb() within loop to inhibit write combining */ - wmb(); - } + for (i = 0; i < inlen; i += 4) + efx_mcdi_writed(efx, (const efx_dword_t *)(inbuf + i), + pdu + 4 + i); /* ring the doorbell with a distinctive value */ - _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); - wmb(); + EFX_POPULATE_DWORD_1(hdr, EFX_DWORD_0, 0x45789abc); + efx_mcdi_writed(efx, &hdr, doorbell); } static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) { struct efx_mcdi_iface *mcdi = efx_mcdi(efx); - unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int pdu = MCDI_PDU(efx); int i; BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); BUG_ON(outlen & 3 || outlen >= 0x100); for (i = 0; i < outlen; i += 4) - *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); + efx_mcdi_readd(efx, (efx_dword_t *)(outbuf + i), pdu + 4 + i); } static int efx_mcdi_poll(struct efx_nic *efx) @@ -123,7 +135,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) struct efx_mcdi_iface *mcdi = efx_mcdi(efx); unsigned int time, finish; unsigned int respseq, respcmd, error; - unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int pdu = MCDI_PDU(efx); unsigned int rc, spins; efx_dword_t reg; @@ -149,8 +161,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) time = get_seconds(); - rmb(); - efx_readd(efx, ®, pdu); + efx_mcdi_readd(efx, ®, pdu); /* All 1's indicates that shared memory is in reset (and is * not a valid header). Wait for it to come out reset before @@ -177,7 +188,7 @@ static int efx_mcdi_poll(struct efx_nic *efx) respseq, mcdi->seqno); rc = EIO; } else if (error) { - efx_readd(efx, ®, pdu + 4); + efx_mcdi_readd(efx, ®, pdu + 4); switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { #define TRANSLATE_ERROR(name) \ case MC_CMD_ERR_ ## name: \ @@ -211,21 +222,21 @@ out: /* Test and clear MC-rebooted flag for this port/function */ int efx_mcdi_poll_reboot(struct efx_nic *efx) { - unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); + unsigned int addr = MCDI_REBOOT_FLAG(efx); efx_dword_t reg; uint32_t value; if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) return false; - efx_readd(efx, ®, addr); + efx_mcdi_readd(efx, ®, addr); value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); if (value == 0) return 0; EFX_ZERO_DWORD(reg); - efx_writed(efx, ®, addr); + efx_mcdi_writed(efx, ®, addr); if (value == MC_STATUS_DWORD_ASSERT) return -EINTR; diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index a42db6e35be3..d91701abd331 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -143,10 +143,12 @@ static inline struct falcon_board *falcon_board(struct efx_nic *efx) /** * struct siena_nic_data - Siena NIC state * @mcdi: Management-Controller-to-Driver Interface + * @mcdi_smem: MCDI shared memory mapping. The mapping is always uncacheable. * @wol_filter_id: Wake-on-LAN packet filter id */ struct siena_nic_data { struct efx_mcdi_iface mcdi; + void __iomem *mcdi_smem; int wol_filter_id; }; diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index e4dd8986b1fe..837869b71db9 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -220,12 +220,26 @@ static int siena_probe_nic(struct efx_nic *efx) efx_reado(efx, ®, FR_AZ_CS_DEBUG); efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; + /* Initialise MCDI */ + nic_data->mcdi_smem = ioremap_nocache(efx->membase_phys + + FR_CZ_MC_TREG_SMEM, + FR_CZ_MC_TREG_SMEM_STEP * + FR_CZ_MC_TREG_SMEM_ROWS); + if (!nic_data->mcdi_smem) { + netif_err(efx, probe, efx->net_dev, + "could not map MCDI at %llx+%x\n", + (unsigned long long)efx->membase_phys + + FR_CZ_MC_TREG_SMEM, + FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS); + rc = -ENOMEM; + goto fail1; + } efx_mcdi_init(efx); /* Recover from a failed assertion before probing */ rc = efx_mcdi_handle_assertion(efx); if (rc) - goto fail1; + goto fail2; /* Let the BMC know that the driver is now in charge of link and * filter settings. We must do this before we reset the NIC */ @@ -280,6 +294,7 @@ fail4: fail3: efx_mcdi_drv_attach(efx, false, NULL); fail2: + iounmap(nic_data->mcdi_smem); fail1: kfree(efx->nic_data); return rc; @@ -359,6 +374,8 @@ static int siena_init_nic(struct efx_nic *efx) static void siena_remove_nic(struct efx_nic *efx) { + struct siena_nic_data *nic_data = efx->nic_data; + efx_nic_free_buffer(efx, &efx->irq_status); siena_reset_hw(efx, RESET_TYPE_ALL); @@ -368,7 +385,8 @@ static void siena_remove_nic(struct efx_nic *efx) efx_mcdi_drv_attach(efx, false, NULL); /* Tear down the private nic state */ - kfree(efx->nic_data); + iounmap(nic_data->mcdi_smem); + kfree(nic_data); efx->nic_data = NULL; } @@ -606,8 +624,7 @@ struct efx_nic_type siena_a0_nic_type = { .default_mac_ops = &efx_mcdi_mac_operations, .revision = EFX_REV_SIENA_A0, - .mem_map_size = (FR_CZ_MC_TREG_SMEM + - FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS), + .mem_map_size = FR_CZ_MC_TREG_SMEM, /* MC_TREG_SMEM mapped separately */ .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, .buf_tbl_base = FR_BZ_BUF_FULL_TBL, -- cgit v1.2.2 From 698b368275c3fa98261159253cfc79653f9dffc6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 11 May 2011 14:49:36 -0700 Subject: fbcon: add lifetime refcount to opened frame buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This just adds the refcount and the new registration lock logic. It does not (for example) actually change the read/write/ioctl routines to actually use the frame buffer that was opened: those function still end up alway susing whatever the current frame buffer is at the time of the call. Without this, if something holds the frame buffer open over a framebuffer switch, the close() operation after the switch will access a fb_info that has been free'd by the unregistering of the old frame buffer. (The read/write/ioctl operations will normally not cause problems, because they will - illogically - pick up the new fbcon instead. But a switch that happens just as one of those is going on might see problems too, the window is just much smaller: one individual op rather than the whole open-close sequence.) This use-after-free is apparently fairly easily triggered by the Ubuntu 11.04 boot sequence. Acked-by: Tim Gardner Tested-by: Daniel J Blueman Tested-by: Anca Emanuel Cc: Bruno Prémont Cc: Alan Cox Cc: Paul Mundt Cc: Dave Airlie Cc: Andy Whitcroft Signed-off-by: Linus Torvalds --- drivers/video/fbmem.c | 56 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e0c2284924b6..eec14d2ca1c7 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -42,9 +42,34 @@ #define FBPIXMAPSIZE (1024 * 8) +static DEFINE_MUTEX(registration_lock); struct fb_info *registered_fb[FB_MAX] __read_mostly; int num_registered_fb __read_mostly; +static struct fb_info *get_fb_info(unsigned int idx) +{ + struct fb_info *fb_info; + + if (idx >= FB_MAX) + return ERR_PTR(-ENODEV); + + mutex_lock(®istration_lock); + fb_info = registered_fb[idx]; + if (fb_info) + atomic_inc(&fb_info->count); + mutex_unlock(®istration_lock); + + return fb_info; +} + +static void put_fb_info(struct fb_info *fb_info) +{ + if (!atomic_dec_and_test(&fb_info->count)) + return; + if (fb_info->fbops->fb_destroy) + fb_info->fbops->fb_destroy(fb_info); +} + int lock_fb_info(struct fb_info *info) { mutex_lock(&info->lock); @@ -647,6 +672,7 @@ int fb_show_logo(struct fb_info *info, int rotate) { return 0; } static void *fb_seq_start(struct seq_file *m, loff_t *pos) { + mutex_lock(®istration_lock); return (*pos < FB_MAX) ? pos : NULL; } @@ -658,6 +684,7 @@ static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) static void fb_seq_stop(struct seq_file *m, void *v) { + mutex_unlock(®istration_lock); } static int fb_seq_show(struct seq_file *m, void *v) @@ -1361,14 +1388,16 @@ __releases(&info->lock) struct fb_info *info; int res = 0; - if (fbidx >= FB_MAX) - return -ENODEV; - info = registered_fb[fbidx]; - if (!info) + info = get_fb_info(fbidx); + if (!info) { request_module("fb%d", fbidx); - info = registered_fb[fbidx]; - if (!info) - return -ENODEV; + info = get_fb_info(fbidx); + if (!info) + return -ENODEV; + } + if (IS_ERR(info)) + return PTR_ERR(info); + mutex_lock(&info->lock); if (!try_module_get(info->fbops->owner)) { res = -ENODEV; @@ -1386,6 +1415,8 @@ __releases(&info->lock) #endif out: mutex_unlock(&info->lock); + if (res) + put_fb_info(info); return res; } @@ -1401,6 +1432,7 @@ __releases(&info->lock) info->fbops->fb_release(info,1); module_put(info->fbops->owner); mutex_unlock(&info->lock); + put_fb_info(info); return 0; } @@ -1542,11 +1574,13 @@ register_framebuffer(struct fb_info *fb_info) remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info)); + mutex_lock(®istration_lock); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) break; fb_info->node = i; + atomic_set(&fb_info->count, 1); mutex_init(&fb_info->lock); mutex_init(&fb_info->mm_lock); @@ -1583,6 +1617,7 @@ register_framebuffer(struct fb_info *fb_info) fb_var_to_videomode(&mode, &fb_info->var); fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; + mutex_unlock(®istration_lock); event.info = fb_info; if (!lock_fb_info(fb_info)) @@ -1616,6 +1651,7 @@ unregister_framebuffer(struct fb_info *fb_info) struct fb_event event; int i, ret = 0; + mutex_lock(®istration_lock); i = fb_info->node; if (!registered_fb[i]) { ret = -EINVAL; @@ -1638,7 +1674,7 @@ unregister_framebuffer(struct fb_info *fb_info) (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); fb_destroy_modelist(&fb_info->modelist); - registered_fb[i]=NULL; + registered_fb[i] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); device_destroy(fb_class, MKDEV(FB_MAJOR, i)); @@ -1646,9 +1682,9 @@ unregister_framebuffer(struct fb_info *fb_info) fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); /* this may free fb info */ - if (fb_info->fbops->fb_destroy) - fb_info->fbops->fb_destroy(fb_info); + put_fb_info(fb_info); done: + mutex_unlock(®istration_lock); return ret; } -- cgit v1.2.2 From c47747fde931c02455683bd00ea43eaa62f35b0e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 11 May 2011 14:58:34 -0700 Subject: fbmem: make read/write/ioctl use the frame buffer at open time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit read/write/ioctl on a fbcon file descriptor has traditionally used the fbcon not when it was opened, but as it was at the time of the call. That makes no sense, but the lack of sense is much more obvious now that we properly ref-count the usage - it means that the ref-counting doesn't actually protect operations we do on the frame buffer. This changes it to look at the fb_info that we got at open time, but in order to avoid using a frame buffer long after it has been unregistered, we do verify that it is still current, and return -ENODEV if not. Acked-by: Tim Gardner Tested-by: Daniel J Blueman Tested-by: Anca Emanuel Cc: Bruno Prémont Cc: Alan Cox Cc: Paul Mundt Cc: Dave Airlie Cc: Andy Whitcroft Signed-off-by: Linus Torvalds --- drivers/video/fbmem.c | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index eec14d2ca1c7..ea16e654a9b6 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -717,13 +717,30 @@ static const struct file_operations fb_proc_fops = { .release = seq_release, }; -static ssize_t -fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +/* + * We hold a reference to the fb_info in file->private_data, + * but if the current registered fb has changed, we don't + * actually want to use it. + * + * So look up the fb_info using the inode minor number, + * and just verify it against the reference we have. + */ +static struct fb_info *file_fb_info(struct file *file) { - unsigned long p = *ppos; struct inode *inode = file->f_path.dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; + + if (info != file->private_data) + info = NULL; + return info; +} + +static ssize_t +fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct fb_info *info = file_fb_info(file); u8 *buffer, *dst; u8 __iomem *src; int c, cnt = 0, err = 0; @@ -788,9 +805,7 @@ static ssize_t fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info = file_fb_info(file); u8 *buffer, *src; u8 __iomem *dst; int c, cnt = 0, err = 0; @@ -1168,10 +1183,10 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info = file_fb_info(file); + if (!info) + return -ENODEV; return do_fb_ioctl(info, cmd, arg); } @@ -1292,12 +1307,13 @@ static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, static long fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int fbidx = iminor(inode); - struct fb_info *info = registered_fb[fbidx]; - struct fb_ops *fb = info->fbops; + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; long ret = -ENOIOCTLCMD; + if (!info) + return -ENODEV; + fb = info->fbops; switch(cmd) { case FBIOGET_VSCREENINFO: case FBIOPUT_VSCREENINFO: @@ -1330,16 +1346,18 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, static int fb_mmap(struct file *file, struct vm_area_struct * vma) { - int fbidx = iminor(file->f_path.dentry->d_inode); - struct fb_info *info = registered_fb[fbidx]; - struct fb_ops *fb = info->fbops; + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; unsigned long off; unsigned long start; u32 len; + if (!info) + return -ENODEV; if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; + fb = info->fbops; if (!fb) return -ENODEV; mutex_lock(&info->mm_lock); -- cgit v1.2.2 From 982b2035d9d7033f63db187bac55e9d8998b0266 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 12 May 2011 12:19:43 -0700 Subject: Revert "drm/i915: Only enable the plane after setting the fb base (pre-ILK)" This reverts commit 49183b2818de6899383bb82bc032f9344d6791ff. Quoth Franz Melchior: "This patch introduces a bug on my infamous "Acer Travelmate 5735Z-452G32Mnss": when KMS takes over, the frame buffer contents get completely garbled up on screen, with colored stripes and unreadable text (photo on request). Only when X11 is started, the screen gets restored again. Closing and re-opening the lid partly cures the mess, too: it makes the font readable, though horizontally stretched." Acked-by: Keith Packard Cc: Chris Wilson Cc: Daniel Vetter Cc: Jesse Barnes Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 373c2a005ec1..2166ee071ddb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5154,6 +5154,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, I915_WRITE(DSPCNTR(plane), dspcntr); POSTING_READ(DSPCNTR(plane)); + if (!HAS_PCH_SPLIT(dev)) + intel_enable_plane(dev_priv, plane, pipe); ret = intel_pipe_set_base(crtc, x, y, old_fb); -- cgit v1.2.2 From cf7e032fc87d59c475df26c4d40bf45d401b2adb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 May 2011 09:11:38 +0000 Subject: zorro8390: Fix regression caused during net_device_ops conversion Changeset b6114794a1c394534659f4a17420e48cf23aa922 ("zorro8390: convert to net_device_ops") broke zorro8390 by adding 8390.o to the link. That meant that lib8390.c was included twice, once in zorro8390.c and once in 8390.c, subject to different macros. This patch reverts that by avoiding the wrappers in 8390.c. Fix based on commits 217cbfa856dc1cbc2890781626c4032d9e3ec59f ("mac8390: fix regression caused during net_device_ops conversion") and 4e0168fa4842e27795a75b205a510f25b62181d9 ("mac8390: fix build with NET_POLL_CONTROLLER"). Reported-by: Christian T. Steigies Suggested-by: Finn Thain Signed-off-by: Geert Uytterhoeven Tested-by: Christian T. Steigies Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/Makefile | 2 +- drivers/net/zorro8390.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 01b604ad155e..c64675f6c977 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -219,7 +219,7 @@ obj-$(CONFIG_SC92031) += sc92031.o obj-$(CONFIG_LP486E) += lp486e.o obj-$(CONFIG_ETH16I) += eth16i.o -obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o +obj-$(CONFIG_ZORRO8390) += zorro8390.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index b78a38d9172a..8c7c522a056a 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -126,7 +126,7 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, board = z->resource.start; ioaddr = board+cards[i].offset; - dev = alloc_ei_netdev(); + dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) { @@ -146,15 +146,15 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, static const struct net_device_ops zorro8390_netdev_ops = { .ndo_open = zorro8390_open, .ndo_stop = zorro8390_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; -- cgit v1.2.2 From 0b25e0157dfa236a0629c16c8ad6f222f633f682 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 May 2011 09:11:39 +0000 Subject: hydra: Fix regression caused during net_device_ops conversion Changeset 5618f0d1193d6b051da9b59b0e32ad24397f06a4 ("hydra: convert to net_device_ops") broke hydra by adding 8390.o to the link. That meant that lib8390.c was included twice, once in hydra.c and once in 8390.c, subject to different macros. This patch reverts that by avoiding the wrappers in 8390.c. Fix based on commits 217cbfa856dc1cbc2890781626c4032d9e3ec59f ("mac8390: fix regression caused during net_device_ops conversion") and 4e0168fa4842e27795a75b205a510f25b62181d9 ("mac8390: fix build with NET_POLL_CONTROLLER"). Signed-off-by: Geert Uytterhoeven Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/Makefile | 2 +- drivers/net/hydra.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c64675f6c977..4d2f09460d60 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -231,7 +231,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o obj-$(CONFIG_A2065) += a2065.o -obj-$(CONFIG_HYDRA) += hydra.o 8390.o +obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_MACSONIC) += macsonic.o diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index c5ef62ceb840..1cd481c04202 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -98,15 +98,15 @@ static const struct net_device_ops hydra_netdev_ops = { .ndo_open = hydra_open, .ndo_stop = hydra_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; @@ -125,7 +125,7 @@ static int __devinit hydra_init(struct zorro_dev *z) 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = alloc_ei_netdev(); + dev = ____alloc_ei_netdev(0); if (!dev) return -ENOMEM; -- cgit v1.2.2 From 2592a7354092afd304a8c067319b15ab1e441e35 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 May 2011 09:11:40 +0000 Subject: ne-h8300: Fix regression caused during net_device_ops conversion Changeset dcd39c90290297f6e6ed8a04bb20da7ac2b043c5 ("ne-h8300: convert to net_device_ops") broke ne-h8300 by adding 8390.o to the link. That meant that lib8390.c was included twice, once in ne-h8300.c and once in 8390.c, subject to different macros. This patch reverts that by avoiding the wrappers in 8390.c. Fix based on commits 217cbfa856dc1cbc2890781626c4032d9e3ec59f ("mac8390: fix regression caused during net_device_ops conversion") and 4e0168fa4842e27795a75b205a510f25b62181d9 ("mac8390: fix build with NET_POLL_CONTROLLER"). Signed-off-by: Geert Uytterhoeven Cc: stable@kernel.org Signed-off-by: David S. Miller --- drivers/net/Makefile | 2 +- drivers/net/ne-h8300.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 4d2f09460d60..e5a7375685ad 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -144,7 +144,7 @@ obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o -obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o +obj-$(CONFIG_NE_H8300) += ne-h8300.o obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o obj-$(CONFIG_FTMAC100) += ftmac100.o diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 30be8c634ebd..7298a34bc795 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -167,7 +167,7 @@ static void cleanup_card(struct net_device *dev) #ifndef MODULE struct net_device * __init ne_probe(int unit) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = ____alloc_ei_netdev(0); int err; if (!dev) @@ -197,15 +197,15 @@ static const struct net_device_ops ne_netdev_ops = { .ndo_open = ne_open, .ndo_stop = ne_close, - .ndo_start_xmit = ei_start_xmit, - .ndo_tx_timeout = ei_tx_timeout, - .ndo_get_stats = ei_get_stats, - .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_start_xmit = __ei_start_xmit, + .ndo_tx_timeout = __ei_tx_timeout, + .ndo_get_stats = __ei_get_stats, + .ndo_set_multicast_list = __ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = ei_poll, + .ndo_poll_controller = __ei_poll, #endif }; @@ -637,7 +637,7 @@ int init_module(void) int err; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = alloc_ei_netdev(); + struct net_device *dev = ____alloc_ei_netdev(0); if (!dev) break; if (io[this_dev]) { -- cgit v1.2.2 From 9ddabb055d73c63037878bb9346e52c7f2e07e96 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 29 Apr 2011 15:30:02 +0200 Subject: i2c: pnx: Fix crash due to wrong init of timer->data alg_data is already a pointer which must be passed directly. Reported-by: Dieter Ripp Signed-off-by: Wolfram Sang Cc: Russell King Cc: Ben Dooks Signed-off-by: Ben Dooks --- drivers/i2c/busses/i2c-pnx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index a97e3fec8148..04be9f82e14b 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -65,7 +65,7 @@ static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) jiffies, expires); timer->expires = jiffies + expires; - timer->data = (unsigned long)&alg_data; + timer->data = (unsigned long)alg_data; add_timer(timer); } -- cgit v1.2.2 From 11f770027b5c0de16544f3ec82b5c6f9f8d5a644 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Thu, 12 May 2011 16:13:54 -0700 Subject: rbd: fix leak of ops struct The ops vector must be freed by the rbd_do_request caller. Signed-off-by: Sage Weil --- drivers/block/rbd.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 3e904717c1c0..2146cab1c61b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -996,6 +996,8 @@ static int rbd_do_op(struct request *rq, ops, num_reply, rbd_req_cb, 0, NULL); + + rbd_destroy_ops(ops); done: kfree(seg_name); return ret; @@ -1063,7 +1065,9 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, { struct ceph_osd_req_op *ops; struct page **pages = NULL; - int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0); + int ret; + + ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_NOTIFY_ACK, 0); if (ret < 0) return ret; -- cgit v1.2.2 From d9282fca8a763be574a2fc20b2edcc6e132cbf90 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 11 May 2011 03:15:24 -0400 Subject: drm/radeon/kms: fix tiling reg on fusion The location of MC_ARB_RAMCFG changed on fusion. I've diffed all the other regs in evergreend.h and this is the only other reg that changed. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen.c | 5 ++++- drivers/gpu/drm/radeon/evergreend.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index c20eac3379e6..9073e3bfb08c 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1780,7 +1780,10 @@ static void evergreen_gpu_init(struct radeon_device *rdev) mc_shared_chmap = RREG32(MC_SHARED_CHMAP); - mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); + if (rdev->flags & RADEON_IS_IGP) + mc_arb_ramcfg = RREG32(FUS_MC_ARB_RAMCFG); + else + mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG); switch (rdev->config.evergreen.max_tile_pipes) { case 1: diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 94533849927e..fc40e0cc3451 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -200,6 +200,7 @@ #define BURSTLENGTH_SHIFT 9 #define BURSTLENGTH_MASK 0x00000200 #define CHANSIZE_OVERRIDE (1 << 11) +#define FUS_MC_ARB_RAMCFG 0x2768 #define MC_VM_AGP_TOP 0x2028 #define MC_VM_AGP_BOT 0x202C #define MC_VM_AGP_BASE 0x2030 -- cgit v1.2.2 From 05fa7ea7d23980de0014417a0e0af2048a0f9fc1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 11 May 2011 14:02:07 -0400 Subject: drm/radeon/kms: fix extended lvds info parsing On rev <= 1.1 tables, the offset is absolute, on newer tables, it's relative. Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=700326 Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Cc: stable@kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_atombios.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index dd881d035f09..90dfb2b8cf03 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -1574,9 +1574,17 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; bool bad_record = false; - u8 *record = (u8 *)(mode_info->atom_context->bios + - data_offset + - le16_to_cpu(lvds_info->info.usModePatchTableOffset)); + u8 *record; + + if ((frev == 1) && (crev < 2)) + /* absolute */ + record = (u8 *)(mode_info->atom_context->bios + + le16_to_cpu(lvds_info->info.usModePatchTableOffset)); + else + /* relative */ + record = (u8 *)(mode_info->atom_context->bios + + data_offset + + le16_to_cpu(lvds_info->info.usModePatchTableOffset)); while (*record != ATOM_RECORD_END_TYPE) { switch (*record) { case LCD_MODE_PATCH_RECORD_MODE_TYPE: -- cgit v1.2.2 From 3a8ab79eae4500e6ac618a92a90cee63d6e804a8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 May 2011 21:15:15 -0400 Subject: drm/radeon/kms: add some evergreen/ni safe regs need to programmed from the userspace drivers. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/reg_srcs/cayman | 1 + drivers/gpu/drm/radeon/reg_srcs/evergreen | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/reg_srcs/cayman b/drivers/gpu/drm/radeon/reg_srcs/cayman index 6334f8ac1209..0aa8e85a9457 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/cayman +++ b/drivers/gpu/drm/radeon/reg_srcs/cayman @@ -33,6 +33,7 @@ cayman 0x9400 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS 0x00009100 SPI_CONFIG_CNTL 0x0000913C SPI_CONFIG_CNTL_1 +0x00009508 TA_CNTL_AUX 0x00009830 DB_DEBUG 0x00009834 DB_DEBUG2 0x00009838 DB_DEBUG3 diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen index 7e1637176e08..0e28cae7ea43 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/evergreen +++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen @@ -46,6 +46,7 @@ evergreen 0x9400 0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS 0x00009100 SPI_CONFIG_CNTL 0x0000913C SPI_CONFIG_CNTL_1 +0x00009508 TA_CNTL_AUX 0x00009700 VC_CNTL 0x00009714 VC_ENHANCE 0x00009830 DB_DEBUG -- cgit v1.2.2 From a10e14667635dde504ed9e7ee851494c2cf2ae8e Mon Sep 17 00:00:00 2001 From: Vitalii Demianets Date: Thu, 12 May 2011 23:04:29 +0000 Subject: bonding,llc: Fix structure sizeof incompatibility for some PDUs With some combinations of arch/compiler (e.g. arm-linux-gcc) the sizeof operator on structure returns value greater than expected. In cases when the structure is used for mapping PDU fields it may lead to unexpected results (such as holes and alignment problems in skb data). __packed prevents this undesired behavior. Signed-off-by: Vitalii Demianets Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index b28baff70864..01b8a6af275b 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -39,7 +39,7 @@ typedef struct mac_addr { u8 mac_addr_value[ETH_ALEN]; -} mac_addr_t; +} __packed mac_addr_t; enum { BOND_AD_STABLE = 0, @@ -134,12 +134,12 @@ typedef struct lacpdu { u8 tlv_type_terminator; // = terminator u8 terminator_length; // = 0 u8 reserved_50[50]; // = 0 -} lacpdu_t; +} __packed lacpdu_t; typedef struct lacpdu_header { struct ethhdr hdr; struct lacpdu lacpdu; -} lacpdu_header_t; +} __packed lacpdu_header_t; // Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) typedef struct bond_marker { @@ -155,12 +155,12 @@ typedef struct bond_marker { u8 tlv_type_terminator; // = 0x00 u8 terminator_length; // = 0x00 u8 reserved_90[90]; // = 0 -} bond_marker_t; +} __packed bond_marker_t; typedef struct bond_marker_header { struct ethhdr hdr; struct bond_marker marker; -} bond_marker_header_t; +} __packed bond_marker_header_t; #pragma pack() -- cgit v1.2.2 From 087fbc9962e10a65fb0b542ecfc116ebf6cf1735 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 13 May 2011 12:14:54 -0400 Subject: drm/i915: Revert i915.semaphore=1 default from i915 merge My Q67 / i7-2600 box has rev09 Sandy Bridge graphics. It hangs instantly when GNOME loads and it hangs so hard the reset button doesn't work. Setting i915.semaphore=0 fixes it. Semaphores were disabled in a1656b9090f7 ("drm/i915: Disable GPU semaphores by default") in 2.6.38 but were then re-enabled (by mistake?) by the merge 47ae63e0c2e5 ("Merge branch 'drm-intel-fixes' into drm-intel-next"). (It's worth noting that the offending change is i915_drv.c, which was not marked as a conflict - although a 'git show --cc' on the merge does show that neither parent had it set to 1) Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds --- drivers/gpu/drm/i915/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c34a8dd31d02..32d1b3e829c8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,7 +49,7 @@ module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); -unsigned int i915_semaphores = 1; +unsigned int i915_semaphores = 0; module_param_named(semaphores, i915_semaphores, int, 0600); unsigned int i915_enable_rc6 = 0; -- cgit v1.2.2 From 1fec70932d867416ffe620dd17005f168cc84eb5 Mon Sep 17 00:00:00 2001 From: Yehuda Sadeh Date: Fri, 13 May 2011 13:52:56 -0700 Subject: rbd: fix split bio handling The rbd driver currently splits bios when they span an object boundary. However, the blk_end_request expects the completions to roll up the results in block device order, and the split rbd/ceph ops can complete in any order. This patch adds a struct rbd_req_coll to track completion of split requests and ensures that the results are passed back up to the block layer in order. This fixes errors where the file system gets completion of a read operation that spans an object boundary before the data has actually arrived. The bug is easily reproduced with iozone with a working set larger than available RAM. Reported-by: Fyodor Ustinov Signed-off-by: Yehuda Sadeh Signed-off-by: Sage Weil --- drivers/block/rbd.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 151 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 2146cab1c61b..9712fad82bc6 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -92,6 +92,8 @@ struct rbd_client { struct list_head node; }; +struct rbd_req_coll; + /* * a single io request */ @@ -100,6 +102,24 @@ struct rbd_request { struct bio *bio; /* cloned bio */ struct page **pages; /* list of used pages */ u64 len; + int coll_index; + struct rbd_req_coll *coll; +}; + +struct rbd_req_status { + int done; + int rc; + u64 bytes; +}; + +/* + * a collection of requests + */ +struct rbd_req_coll { + int total; + int num_done; + struct kref kref; + struct rbd_req_status status[0]; }; struct rbd_snap { @@ -416,6 +436,17 @@ static void rbd_put_client(struct rbd_device *rbd_dev) rbd_dev->client = NULL; } +/* + * Destroy requests collection + */ +static void rbd_coll_release(struct kref *kref) +{ + struct rbd_req_coll *coll = + container_of(kref, struct rbd_req_coll, kref); + + dout("rbd_coll_release %p\n", coll); + kfree(coll); +} /* * Create a new header structure, translate header format from the on-disk @@ -590,6 +621,14 @@ static u64 rbd_get_segment(struct rbd_image_header *header, return len; } +static int rbd_get_num_segments(struct rbd_image_header *header, + u64 ofs, u64 len) +{ + u64 start_seg = ofs >> header->obj_order; + u64 end_seg = (ofs + len - 1) >> header->obj_order; + return end_seg - start_seg + 1; +} + /* * bio helpers */ @@ -735,6 +774,50 @@ static void rbd_destroy_ops(struct ceph_osd_req_op *ops) kfree(ops); } +static void rbd_coll_end_req_index(struct request *rq, + struct rbd_req_coll *coll, + int index, + int ret, u64 len) +{ + struct request_queue *q; + int min, max, i; + + dout("rbd_coll_end_req_index %p index %d ret %d len %lld\n", + coll, index, ret, len); + + if (!rq) + return; + + if (!coll) { + blk_end_request(rq, ret, len); + return; + } + + q = rq->q; + + spin_lock_irq(q->queue_lock); + coll->status[index].done = 1; + coll->status[index].rc = ret; + coll->status[index].bytes = len; + max = min = coll->num_done; + while (max < coll->total && coll->status[max].done) + max++; + + for (i = min; istatus[i].rc, + coll->status[i].bytes); + coll->num_done++; + kref_put(&coll->kref, rbd_coll_release); + } + spin_unlock_irq(q->queue_lock); +} + +static void rbd_coll_end_req(struct rbd_request *req, + int ret, u64 len) +{ + rbd_coll_end_req_index(req->rq, req->coll, req->coll_index, ret, len); +} + /* * Send ceph osd request */ @@ -749,6 +832,8 @@ static int rbd_do_request(struct request *rq, int flags, struct ceph_osd_req_op *ops, int num_reply, + struct rbd_req_coll *coll, + int coll_index, void (*rbd_cb)(struct ceph_osd_request *req, struct ceph_msg *msg), struct ceph_osd_request **linger_req, @@ -763,12 +848,20 @@ static int rbd_do_request(struct request *rq, struct ceph_osd_request_head *reqhead; struct rbd_image_header *header = &dev->header; - ret = -ENOMEM; req_data = kzalloc(sizeof(*req_data), GFP_NOIO); - if (!req_data) - goto done; + if (!req_data) { + if (coll) + rbd_coll_end_req_index(rq, coll, coll_index, + -ENOMEM, len); + return -ENOMEM; + } + + if (coll) { + req_data->coll = coll; + req_data->coll_index = coll_index; + } - dout("rbd_do_request len=%lld ofs=%lld\n", len, ofs); + dout("rbd_do_request obj=%s ofs=%lld len=%lld\n", obj, len, ofs); down_read(&header->snap_rwsem); @@ -828,7 +921,8 @@ static int rbd_do_request(struct request *rq, ret = ceph_osdc_wait_request(&dev->client->osdc, req); if (ver) *ver = le64_to_cpu(req->r_reassert_version.version); - dout("reassert_ver=%lld\n", le64_to_cpu(req->r_reassert_version.version)); + dout("reassert_ver=%lld\n", + le64_to_cpu(req->r_reassert_version.version)); ceph_osdc_put_request(req); } return ret; @@ -837,10 +931,8 @@ done_err: bio_chain_put(req_data->bio); ceph_osdc_put_request(req); done_pages: + rbd_coll_end_req(req_data, ret, len); kfree(req_data); -done: - if (rq) - blk_end_request(rq, ret, len); return ret; } @@ -874,7 +966,7 @@ static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg) bytes = req_data->len; } - blk_end_request(req_data->rq, rc, bytes); + rbd_coll_end_req(req_data, rc, bytes); if (req_data->bio) bio_chain_put(req_data->bio); @@ -934,6 +1026,7 @@ static int rbd_req_sync_op(struct rbd_device *dev, flags, ops, 2, + NULL, 0, NULL, linger_req, ver); if (ret < 0) @@ -959,7 +1052,9 @@ static int rbd_do_op(struct request *rq, u64 snapid, int opcode, int flags, int num_reply, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { char *seg_name; u64 seg_ofs; @@ -995,6 +1090,7 @@ static int rbd_do_op(struct request *rq, flags, ops, num_reply, + coll, coll_index, rbd_req_cb, 0, NULL); rbd_destroy_ops(ops); @@ -1010,13 +1106,15 @@ static int rbd_req_write(struct request *rq, struct rbd_device *rbd_dev, struct ceph_snap_context *snapc, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP, CEPH_OSD_OP_WRITE, CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, 2, - ofs, len, bio); + ofs, len, bio, coll, coll_index); } /* @@ -1026,14 +1124,16 @@ static int rbd_req_read(struct request *rq, struct rbd_device *rbd_dev, u64 snapid, u64 ofs, u64 len, - struct bio *bio) + struct bio *bio, + struct rbd_req_coll *coll, + int coll_index) { return rbd_do_op(rq, rbd_dev, NULL, (snapid ? snapid : CEPH_NOSNAP), CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, 2, - ofs, len, bio); + ofs, len, bio, coll, coll_index); } /* @@ -1081,6 +1181,7 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev, CEPH_OSD_FLAG_READ, ops, 1, + NULL, 0, rbd_simple_req_cb, 0, NULL); rbd_destroy_ops(ops); @@ -1278,6 +1379,20 @@ static int rbd_req_sync_exec(struct rbd_device *dev, return ret; } +static struct rbd_req_coll *rbd_alloc_coll(int num_reqs) +{ + struct rbd_req_coll *coll = + kzalloc(sizeof(struct rbd_req_coll) + + sizeof(struct rbd_req_status) * num_reqs, + GFP_ATOMIC); + + if (!coll) + return NULL; + coll->total = num_reqs; + kref_init(&coll->kref); + return coll; +} + /* * block device queue callback */ @@ -1295,6 +1410,8 @@ static void rbd_rq_fn(struct request_queue *q) bool do_write; int size, op_size = 0; u64 ofs; + int num_segs, cur_seg = 0; + struct rbd_req_coll *coll; /* peek at request from block layer */ if (!rq) @@ -1325,6 +1442,14 @@ static void rbd_rq_fn(struct request_queue *q) do_write ? "write" : "read", size, blk_rq_pos(rq) * 512ULL); + num_segs = rbd_get_num_segments(&rbd_dev->header, ofs, size); + coll = rbd_alloc_coll(num_segs); + if (!coll) { + spin_lock_irq(q->queue_lock); + __blk_end_request_all(rq, -ENOMEM); + goto next; + } + do { /* a bio clone to be passed down to OSD req */ dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt); @@ -1332,35 +1457,41 @@ static void rbd_rq_fn(struct request_queue *q) rbd_dev->header.block_name, ofs, size, NULL, NULL); + kref_get(&coll->kref); bio = bio_chain_clone(&rq_bio, &next_bio, &bp, op_size, GFP_ATOMIC); if (!bio) { - spin_lock_irq(q->queue_lock); - __blk_end_request_all(rq, -ENOMEM); - goto next; + rbd_coll_end_req_index(rq, coll, cur_seg, + -ENOMEM, op_size); + goto next_seg; } + /* init OSD command: write or read */ if (do_write) rbd_req_write(rq, rbd_dev, rbd_dev->header.snapc, ofs, - op_size, bio); + op_size, bio, + coll, cur_seg); else rbd_req_read(rq, rbd_dev, cur_snap_id(rbd_dev), ofs, - op_size, bio); + op_size, bio, + coll, cur_seg); +next_seg: size -= op_size; ofs += op_size; + cur_seg++; rq_bio = next_bio; } while (size > 0); + kref_put(&coll->kref, rbd_coll_release); if (bp) bio_pair_release(bp); - spin_lock_irq(q->queue_lock); next: rq = blk_fetch_request(q); -- cgit v1.2.2 From 712f3147aee0fbbbbed2da20b21b272c5505125e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 13 May 2011 16:16:41 -0700 Subject: fbmem: fix remove_conflicting_framebuffers races MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a register_framebuffer() call results in us removing old conflicting framebuffers, the new registration_lock doesn't protect that situation. And we can't just add the same locking to the function, because these functions call each other: register_framebuffer() calls remove_conflicting_framebuffers, which in turn calls unregister_framebuffer for any conflicting entry. In order to fix it, this just creates wrapper functions around all three functions and makes the versions that actually do the work be called "do_xxx()", leaving just the wrapper that gets the lock and calls the worker function. So the rule becomes simply that "do_xxxx()" has to be called with the lock held, and now do_register_framebuffer() can just call do_remove_conflicting_framebuffers(), and that in turn can call _do_unregister_framebuffer(), and there is no deadlock, and we can hold the registration lock over the whole sequence, fixing the races. It also makes error cases simpler, and fixes one situation where we would return from unregister_framebuffer() without releasing the lock, pointed out by Bruno Prémont. Tested-by: Bruno Prémont Tested-by: Anca Emanuel Signed-off-by: Linus Torvalds --- drivers/video/fbmem.c | 117 +++++++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ea16e654a9b6..46ee5e5a08c6 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1537,8 +1537,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, return false; } +static int do_unregister_framebuffer(struct fb_info *fb_info); + #define VGA_FB_PHYS 0xA0000 -void remove_conflicting_framebuffers(struct apertures_struct *a, +static void do_remove_conflicting_framebuffers(struct apertures_struct *a, const char *name, bool primary) { int i; @@ -1560,24 +1562,12 @@ void remove_conflicting_framebuffers(struct apertures_struct *a, printk(KERN_INFO "fb: conflicting fb hw usage " "%s vs %s - removing generic driver\n", name, registered_fb[i]->fix.id); - unregister_framebuffer(registered_fb[i]); + do_unregister_framebuffer(registered_fb[i]); } } } -EXPORT_SYMBOL(remove_conflicting_framebuffers); - -/** - * register_framebuffer - registers a frame buffer device - * @fb_info: frame buffer info structure - * - * Registers a frame buffer device @fb_info. - * - * Returns negative errno on error, or zero for success. - * - */ -int -register_framebuffer(struct fb_info *fb_info) +static int do_register_framebuffer(struct fb_info *fb_info) { int i; struct fb_event event; @@ -1589,10 +1579,9 @@ register_framebuffer(struct fb_info *fb_info) if (fb_check_foreignness(fb_info)) return -ENOSYS; - remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, + do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info)); - mutex_lock(®istration_lock); num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1635,7 +1624,6 @@ register_framebuffer(struct fb_info *fb_info) fb_var_to_videomode(&mode, &fb_info->var); fb_add_videomode(&mode, &fb_info->modelist); registered_fb[i] = fb_info; - mutex_unlock(®istration_lock); event.info = fb_info; if (!lock_fb_info(fb_info)) @@ -1645,37 +1633,14 @@ register_framebuffer(struct fb_info *fb_info) return 0; } - -/** - * unregister_framebuffer - releases a frame buffer device - * @fb_info: frame buffer info structure - * - * Unregisters a frame buffer device @fb_info. - * - * Returns negative errno on error, or zero for success. - * - * This function will also notify the framebuffer console - * to release the driver. - * - * This is meant to be called within a driver's module_exit() - * function. If this is called outside module_exit(), ensure - * that the driver implements fb_open() and fb_release() to - * check that no processes are using the device. - */ - -int -unregister_framebuffer(struct fb_info *fb_info) +static int do_unregister_framebuffer(struct fb_info *fb_info) { struct fb_event event; int i, ret = 0; - mutex_lock(®istration_lock); i = fb_info->node; - if (!registered_fb[i]) { - ret = -EINVAL; - goto done; - } - + if (!registered_fb[i]) + return -EINVAL; if (!lock_fb_info(fb_info)) return -ENODEV; @@ -1683,10 +1648,8 @@ unregister_framebuffer(struct fb_info *fb_info) ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); unlock_fb_info(fb_info); - if (ret) { - ret = -EINVAL; - goto done; - } + if (ret) + return -EINVAL; if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) @@ -1701,8 +1664,64 @@ unregister_framebuffer(struct fb_info *fb_info) /* this may free fb info */ put_fb_info(fb_info); -done: + return 0; +} + +void remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) +{ + mutex_lock(®istration_lock); + do_remove_conflicting_framebuffers(a, name, primary); mutex_unlock(®istration_lock); +} +EXPORT_SYMBOL(remove_conflicting_framebuffers); + +/** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure + * + * Registers a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ +int +register_framebuffer(struct fb_info *fb_info) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_register_framebuffer(fb_info); + mutex_unlock(®istration_lock); + + return ret; +} + +/** + * unregister_framebuffer - releases a frame buffer device + * @fb_info: frame buffer info structure + * + * Unregisters a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + * This function will also notify the framebuffer console + * to release the driver. + * + * This is meant to be called within a driver's module_exit() + * function. If this is called outside module_exit(), ensure + * that the driver implements fb_open() and fb_release() to + * check that no processes are using the device. + */ +int +unregister_framebuffer(struct fb_info *fb_info) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_unregister_framebuffer(fb_info); + mutex_unlock(®istration_lock); + return ret; } -- cgit v1.2.2 From c590cece75728a85ea06801df3ebad2d7ad8612c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Sat, 14 May 2011 12:24:15 +0200 Subject: Further fbcon sanity checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves the if (num_registered_fb == FB_MAX) return -ENXIO; check _AFTER_ the call to do_remove_conflicting_framebuffers() as this would (now in a safe way) allow a native driver to replace the conflicting one even if all slots in registered_fb[] are taken. This also prevents unregistering a framebuffer that is no longer registered (vga16f will unregister at module unload time even if the frame buffer had been unregistered earlier due to being found conflicting). Signed-off-by: Bruno Prémont Signed-off-by: Linus Torvalds --- drivers/video/fbmem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 46ee5e5a08c6..5aac00eb1830 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1573,15 +1573,15 @@ static int do_register_framebuffer(struct fb_info *fb_info) struct fb_event event; struct fb_videomode mode; - if (num_registered_fb == FB_MAX) - return -ENXIO; - if (fb_check_foreignness(fb_info)) return -ENOSYS; do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, fb_is_primary_device(fb_info)); + if (num_registered_fb == FB_MAX) + return -ENXIO; + num_registered_fb++; for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) @@ -1639,7 +1639,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) int i, ret = 0; i = fb_info->node; - if (!registered_fb[i]) + if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) return -EINVAL; if (!lock_fb_info(fb_info)) -- cgit v1.2.2 From 22fe9446e82f1fe4b59900db4599061384efb0ad Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 14 May 2011 12:28:04 +0200 Subject: Revert "libata: ahci_start_engine compliant to AHCI spec" This reverts commit 270dac35c26433d06a89150c51e75ca0181ca7e4. The commits causes command timeouts on AC plug/unplug. It isn't yet clear why. As the commit was for a single rather obscure controller, revert the change for now. The problem was reported and bisected by Gu Rui in bug#34692. https://bugzilla.kernel.org/show_bug.cgi?id=34692 Also, reported by Rafael and Michael in the following thread. http://thread.gmane.org/gmane.linux.kernel/1138771 Signed-off-by: Tejun Heo Reported-by: Gu Rui Reported-by: Rafael J. Wysocki Reported-by: Michael Leun Cc: Jian Peng Cc: Jeff Garzik Signed-off-by: Linus Torvalds --- drivers/ata/libahci.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index ff9d832a163d..d38c40fe4ddb 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -561,27 +561,6 @@ void ahci_start_engine(struct ata_port *ap) { void __iomem *port_mmio = ahci_port_base(ap); u32 tmp; - u8 status; - - status = readl(port_mmio + PORT_TFDATA) & 0xFF; - - /* - * At end of section 10.1 of AHCI spec (rev 1.3), it states - * Software shall not set PxCMD.ST to 1 until it is determined - * that a functoinal device is present on the port as determined by - * PxTFD.STS.BSY=0, PxTFD.STS.DRQ=0 and PxSSTS.DET=3h - * - * Even though most AHCI host controllers work without this check, - * specific controller will fail under this condition - */ - if (status & (ATA_BUSY | ATA_DRQ)) - return; - else { - ahci_scr_read(&ap->link, SCR_STATUS, &tmp); - - if ((tmp & 0xf) != 0x3) - return; - } /* start DMA */ tmp = readl(port_mmio + PORT_CMD); -- cgit v1.2.2 From 5f6f12ccf3aa42cfc0c5bde9228df0c843dd63f7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 9 May 2011 16:04:11 +0200 Subject: libata: fix oops when LPM is used with PMP ae01b2493c (libata: Implement ATA_FLAG_NO_DIPM and apply it to mcp65) added ATA_FLAG_NO_DIPM and made ata_eh_set_lpm() check the flag. However, @ap is NULL if @link points to a PMP link and thus the unconditional @ap->flags dereference leads to the following oops. BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 IP: [] ata_eh_recover+0x9a1/0x1510 ... Pid: 295, comm: scsi_eh_4 Tainted: P 2.6.38.5-core2 #1 System76, Inc. Serval Professional/Serval Professional RIP: 0010:[] [] ata_eh_recover+0x9a1/0x1510 RSP: 0018:ffff880132defbf0 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff880132f40000 RCX: 0000000000000000 RDX: ffff88013377c000 RSI: ffff880132f40000 RDI: 0000000000000000 RBP: ffff880132defce0 R08: ffff88013377dc58 R09: ffff880132defd98 R10: 0000000000000000 R11: 00000000ffffffff R12: 0000000000000000 R13: 0000000000000000 R14: ffff88013377c000 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff8800bf700000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000018 CR3: 0000000001a03000 CR4: 00000000000406e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process scsi_eh_4 (pid: 295, threadinfo ffff880132dee000, task ffff880133b416c0) Stack: 0000000000000000 ffff880132defcc0 0000000000000000 ffff880132f42738 ffffffff813ee8f0 ffffffff813eefe0 ffff880132defd98 ffff88013377f190 ffffffffa00b3e30 ffffffff813ef030 0000000032defc60 ffff880100000000 Call Trace: [] sata_pmp_error_handler+0x607/0xc30 [] ahci_error_handler+0x1f/0x70 [libahci] [] ata_scsi_error+0x5be/0x900 [] scsi_error_handler+0x124/0x650 [] kthread+0x96/0xa0 [] kernel_thread_helper+0x4/0x10 Code: 8b 95 70 ff ff ff b8 00 00 00 00 48 3b 9a 10 2e 00 00 48 0f 44 c2 48 89 85 70 ff ff ff 48 8b 8d 70 ff ff ff f6 83 69 02 00 00 01 <48> 8b 41 18 0f 85 48 01 00 00 48 85 c9 74 12 48 8b 51 08 48 83 RIP [] ata_eh_recover+0x9a1/0x1510 RSP CR2: 0000000000000018 Fix it by testing @link->ap->flags instead. stable: ATA_FLAG_NO_DIPM was added during 2.6.39 cycle but was backported to 2.6.37 and 38. This is a fix for that and thus also applicable to 2.6.37 and 38. Signed-off-by: Tejun Heo Reported-by: "Nathan A. Mourey II" LKML-Reference: <1304555277.2059.2.camel@localhost.localdomain> Cc: Connor H Cc: stable@kernel.org Signed-off-by: Jeff Garzik --- drivers/ata/libata-eh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f26f2fe3480a..dad9fd660f37 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3316,7 +3316,7 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, 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; - bool no_dipm = ap->flags & ATA_FLAG_NO_DIPM; + bool no_dipm = link->ap->flags & ATA_FLAG_NO_DIPM; unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM; unsigned int err_mask; int rc; -- cgit v1.2.2 From a67b8887ced9d54cab7759bdb19deafed37481eb Mon Sep 17 00:00:00 2001 From: Florian Mickler Date: Sun, 15 May 2011 16:32:50 +0200 Subject: vga_switcheroo: don't toggle-switch devices If the requested device is already active, ignore the request. This restores the original behaviour of the interface. The change was probably an unintended side effect of commit 66b37c6777c4 vga_switcheroo: split switching into two stages which did not take into account to duplicate the !active check in the split-off stage2. Fix this by factoring that check out of stage1 into the debugfs_write routine. References: https://bugzilla.kernel.org/show_bug.cgi?id=34252 Reported-by: Igor Murzov Tested-by: Igor Murzov Signed-off-by: Florian Mickler Signed-off-by: Dave Airlie --- drivers/gpu/vga/vga_switcheroo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index e01cacba685f..498b284e5ef9 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -219,9 +219,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client) int i; struct vga_switcheroo_client *active = NULL; - if (new_client->active == true) - return 0; - for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { if (vgasr_priv.clients[i].active == true) { active = &vgasr_priv.clients[i]; @@ -372,6 +369,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf, goto out; } + if (client->active == true) + goto out; + /* okay we want a switch - test if devices are willing to switch */ can_switch = true; for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) { -- cgit v1.2.2 From 8eea1be174a1ea4b86323167bbadc8a6abdca613 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 13 May 2011 12:14:54 -0400 Subject: drm/i915: Revert i915.semaphore=1 default from 47ae63e0 My Q67 / i7-2600 box has rev09 Sandy Bridge graphics. It hangs instantly when GNOME loads and it hangs so hard the reset button doesn't work. Setting i915.semaphore=0 fixes it. Semaphores were disabled in a1656b9090f7008d2941c314f5a64724bea2ae37 in 2.6.38 and were re-enabled by commit 47ae63e0c2e5fdb582d471dc906eb29be94c732f Merge: c59a333 467cffb Author: Chris Wilson Date: Mon Mar 7 12:32:44 2011 +0000 Merge branch 'drm-intel-fixes' into drm-intel-next Apply the trivial conflicting regression fixes, but keep GPU semaphores enabled. Conflicts: drivers/gpu/drm/i915/i915_drv.h drivers/gpu/drm/i915/i915_gem_execbuffer.c (It's worth noting that the offending change is i915_drv.c, which is not a conflict.) Signed-off-by: Andy Lutomirski Acked-by: Keith Packard Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c34a8dd31d02..32d1b3e829c8 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -49,7 +49,7 @@ module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600); unsigned int i915_powersave = 1; module_param_named(powersave, i915_powersave, int, 0600); -unsigned int i915_semaphores = 1; +unsigned int i915_semaphores = 0; module_param_named(semaphores, i915_semaphores, int, 0600); unsigned int i915_enable_rc6 = 0; -- cgit v1.2.2 From 752d2635ebb12b6122ba05775f7d1ccfef14b275 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 22 Apr 2011 11:03:57 +0100 Subject: drm: Take lock around probes for drm_fb_helper_hotplug_event We need to hold the dev->mode_config.mutex whilst detecting the output status. But we also need to drop it for the call into drm_fb_helper_single_fb_probe(), which indirectly acquires the lock when attaching the fbcon. Failure to do so exposes a race with normal output probing. Detected by adding some warnings that the mutex is held to the backend detect routines: [ 17.772456] WARNING: at drivers/gpu/drm/i915/intel_crt.c:471 intel_crt_detect+0x3e/0x373 [i915]() [ 17.772458] Hardware name: Latitude E6400 [ 17.772460] Modules linked in: .... [ 17.772582] Pid: 11, comm: kworker/0:1 Tainted: G W 2.6.38.4-custom.2 #8 [ 17.772584] Call Trace: [ 17.772591] [] ? warn_slowpath_common+0x78/0x8c [ 17.772603] [] ? intel_crt_detect+0x3e/0x373 [i915] [ 17.772612] [] ? drm_helper_probe_single_connector_modes+0xbf/0x2af [drm_kms_helper] [ 17.772619] [] ? drm_fb_helper_probe_connector_modes+0x39/0x4d [drm_kms_helper] [ 17.772625] [] ? drm_fb_helper_hotplug_event+0xa5/0xc3 [drm_kms_helper] [ 17.772633] [] ? output_poll_execute+0x146/0x17c [drm_kms_helper] [ 17.772638] [] ? cfq_init_queue+0x247/0x345 [ 17.772644] [] ? output_poll_execute+0x0/0x17c [drm_kms_helper] [ 17.772648] [] ? process_one_work+0x193/0x28e [ 17.772652] [] ? worker_thread+0xef/0x172 [ 17.772655] [] ? worker_thread+0x0/0x172 [ 17.772658] [] ? worker_thread+0x0/0x172 [ 17.772663] [] ? kthread+0x7a/0x82 [ 17.772668] [] ? kernel_thread_helper+0x4/0x10 [ 17.772671] [] ? kthread+0x0/0x82 [ 17.772674] [] ? kernel_thread_helper+0x0/0x10 Reported-by: Frederik Himpe References: https://bugs.freedesktop.org/show_bug.cgi?id=36394 Signed-off-by: Chris Wilson Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_fb_helper.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 11d7a72c22d9..140b9525b48a 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -1516,17 +1516,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) } EXPORT_SYMBOL(drm_fb_helper_initial_config); -bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) +/** + * drm_fb_helper_hotplug_event - respond to a hotplug notification by + * probing all the outputs attached to the fb. + * @fb_helper: the drm_fb_helper + * + * LOCKING: + * Called at runtime, must take mode config lock. + * + * Scan the connectors attached to the fb_helper and try to put together a + * setup after *notification of a change in output configuration. + * + * RETURNS: + * 0 on success and a non-zero error code otherwise. + */ +int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { + struct drm_device *dev = fb_helper->dev; int count = 0; u32 max_width, max_height, bpp_sel; bool bound = false, crtcs_bound = false; struct drm_crtc *crtc; if (!fb_helper->fb) - return false; + return 0; - list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb) crtcs_bound = true; if (crtc->fb == fb_helper->fb) @@ -1535,7 +1551,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) if (!bound && crtcs_bound) { fb_helper->delayed_hotplug = true; - return false; + mutex_unlock(&dev->mode_config.mutex); + return 0; } DRM_DEBUG_KMS("\n"); @@ -1546,6 +1563,7 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, max_height); drm_setup_crtcs(fb_helper); + mutex_unlock(&dev->mode_config.mutex); return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } -- cgit v1.2.2 From 86f315bbb2374f1f077500ad131dd9b71856e697 Mon Sep 17 00:00:00 2001 From: Chris Ball Date: Mon, 16 May 2011 11:32:26 -0400 Subject: Revert "mmc: fix a race between card-detect rescan and clock-gate work instances" This reverts commit 26fc8775b51484d8c0a671198639c6d5ae60533e, which has been reported to cause boot/resume-time crashes for some users: https://bbs.archlinux.org/viewtopic.php?id=118751. Signed-off-by: Chris Ball Cc: --- drivers/mmc/core/host.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 2b200c1cfbba..461e6a17fb90 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -94,7 +94,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) spin_unlock_irqrestore(&host->clk_lock, flags); return; } - mmc_claim_host(host); + mutex_lock(&host->clk_gate_mutex); spin_lock_irqsave(&host->clk_lock, flags); if (!host->clk_requests) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -104,7 +104,7 @@ static void mmc_host_clk_gate_delayed(struct mmc_host *host) pr_debug("%s: gated MCI clock\n", mmc_hostname(host)); } spin_unlock_irqrestore(&host->clk_lock, flags); - mmc_release_host(host); + mutex_unlock(&host->clk_gate_mutex); } /* @@ -130,7 +130,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) { unsigned long flags; - mmc_claim_host(host); + mutex_lock(&host->clk_gate_mutex); spin_lock_irqsave(&host->clk_lock, flags); if (host->clk_gated) { spin_unlock_irqrestore(&host->clk_lock, flags); @@ -140,7 +140,7 @@ void mmc_host_clk_ungate(struct mmc_host *host) } host->clk_requests++; spin_unlock_irqrestore(&host->clk_lock, flags); - mmc_release_host(host); + mutex_unlock(&host->clk_gate_mutex); } /** @@ -215,6 +215,7 @@ static inline void mmc_host_clk_init(struct mmc_host *host) host->clk_gated = false; INIT_WORK(&host->clk_gate_work, mmc_host_clk_gate_work); spin_lock_init(&host->clk_lock); + mutex_init(&host->clk_gate_mutex); } /** -- cgit v1.2.2 From 867955f5682f7157fdafe8670804b9f8ea077bc7 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 16 May 2011 06:13:49 +0000 Subject: sfc: Fix oops in register dump after mapping change Commit 747df2258b1b9a2e25929ef496262c339c380009 ('sfc: Always map MCDI shared memory as uncacheable') introduced a separate mapping for the MCDI shared memory (MC_TREG_SMEM). This means we can no longer easily include it in the register dump. Since it is not particularly useful in debugging, substitute a recognisable dummy value. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- drivers/net/sfc/nic.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 10f1cb79c147..9b29a8d7c449 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1937,6 +1937,13 @@ void efx_nic_get_regs(struct efx_nic *efx, void *buf) size = min_t(size_t, table->step, 16); + if (table->offset >= efx->type->mem_map_size) { + /* No longer mapped; return dummy data */ + memcpy(buf, "\xde\xc0\xad\xde", 4); + buf += table->rows * size; + continue; + } + for (i = 0; i < table->rows; i++) { switch (table->step) { case 4: /* 32-bit register or SRAM */ -- cgit v1.2.2 From ebde6f8acba92abfc203585198a54f47e83e2cd0 Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Mon, 16 May 2011 06:28:15 +0000 Subject: vmxnet3: Fix inconsistent LRO state after initialization During initialization of vmxnet3, the state of LRO gets out of sync with netdev->features. This leads to very poor TCP performance in a IP forwarding setup and is hitting many VMware users. Simplified call sequence: 1. vmxnet3_declare_features() initializes "adapter->lro" to true. 2. The kernel automatically disables LRO if IP forwarding is enabled, so vmxnet3_set_flags() gets called. This also updates netdev->features. 3. Now vmxnet3_setup_driver_shared() is called. "adapter->lro" is still set to true and LRO gets enabled again, even though netdev->features shows it's disabled. Fix it by updating "adapter->lro", too. The private vmxnet3 adapter flags are scheduled for removal in net-next, see commit a0d2730c9571aeba793cb5d3009094ee1d8fda35 "net: vmxnet3: convert to hw_features". Patch applies to 2.6.37 / 2.6.38 and 2.6.39-rc6. Please CC: comments. Signed-off-by: Thomas Jarosch Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/vmxnet3/vmxnet3_ethtool.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 51f2ef142a5b..976467253d20 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -311,6 +311,9 @@ vmxnet3_set_flags(struct net_device *netdev, u32 data) /* toggle the LRO feature*/ netdev->features ^= NETIF_F_LRO; + /* Update private LRO flag */ + adapter->lro = lro_requested; + /* update harware LRO capability accordingly */ if (lro_requested) adapter->shared->devRead.misc.uptFeatures |= -- cgit v1.2.2 From 93d2175d3d31f11ba04fcfa0e9a496a1b4bc8b34 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 13 May 2011 18:06:17 -0700 Subject: PCI: Clear bridge resource flags if requested size is 0 During pci remove/rescan testing found: pci 0000:c0:03.0: PCI bridge to [bus c4-c9] pci 0000:c0:03.0: bridge window [io 0x1000-0x0fff] pci 0000:c0:03.0: bridge window [mem 0xf0000000-0xf00fffff] pci 0000:c0:03.0: bridge window [mem 0xfc180000000-0xfc197ffffff 64bit pref] pci 0000:c0:03.0: device not available (can't reserve [io 0x1000-0x0fff]) pci 0000:c0:03.0: Error enabling bridge (-22), continuing pci 0000:c0:03.0: enabling bus mastering pci 0000:c0:03.0: setting latency timer to 64 pcieport 0000:c0:03.0: device not available (can't reserve [io 0x1000-0x0fff]) pcieport: probe of 0000:c0:03.0 failed with error -22 This bug was caused by commit c8adf9a3e873 ("PCI: pre-allocate additional resources to devices only after successful allocation of essential resources.") After that commit, pci_hotplug_io_size is changed to additional_io_size from minium size. So it will not go through resource_size(res) != 0 path, and will not be reset. The root cause is: pci_bridge_check_ranges will set RESOURCE_IO flag for pci bridge, and later if children do not need IO resource. those bridge resources will not need to be allocated. but flags is still there. that will confuse the the pci_enable_bridges later. related code: static void assign_requested_resources_sorted(struct resource_list *head, struct resource_list_x *fail_head) { struct resource *res; struct resource_list *list; int idx; for (list = head->next; list; list = list->next) { res = list->res; idx = res - &list->dev->resource[0]; if (resource_size(res) && pci_assign_resource(list->dev, idx)) { ... reset_resource(res); } } } At last, We have to clear the flags in pbus_size_mem/io when requested size == 0 and !add_head. becasue this case it will not go through adjust_resources_sorted(). Just make size1 = size0 when !add_head. it will make flags get cleared. At the same time when requested size == 0, add_size != 0, will still have in head and add_list. because we do not clear the flags for it. After this, we will get right result: pci 0000:c0:03.0: PCI bridge to [bus c4-c9] pci 0000:c0:03.0: bridge window [io disabled] pci 0000:c0:03.0: bridge window [mem 0xf0000000-0xf00fffff] pci 0000:c0:03.0: bridge window [mem 0xfc180000000-0xfc197ffffff 64bit pref] pci 0000:c0:03.0: enabling bus mastering pci 0000:c0:03.0: setting latency timer to 64 pcieport 0000:c0:03.0: setting latency timer to 64 pcieport 0000:c0:03.0: irq 160 for MSI/MSI-X pcieport 0000:c0:03.0: Signaling PME through PCIe PME interrupt pci 0000:c4:00.0: Signaling PME through PCIe PME interrupt pcie_pme 0000:c0:03.0:pcie01: service driver pcie_pme loaded aer 0000:c0:03.0:pcie02: service driver aer loaded pciehp 0000:c0:03.0:pcie04: Hotplug Controller: v3: more simple fix. also fix one typo in pbus_size_mem Signed-off-by: Yinghai Lu Reviewed-by: Ram Pai Cc: Jesse Barnes Cc: Bjorn Helgaas Signed-off-by: Linus Torvalds --- drivers/pci/setup-bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index ebf51ad1b714..a806cb321d2e 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -579,7 +579,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, } size0 = calculate_iosize(size, min_size, size1, resource_size(b_res), 4096); - size1 = !add_size? size0: + size1 = (!add_head || (add_head && !add_size)) ? size0 : calculate_iosize(size, min_size+add_size, size1, resource_size(b_res), 4096); if (!size0 && !size1) { @@ -677,7 +677,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, align += aligns[order]; } size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); - size1 = !add_size ? size : + size1 = (!add_head || (add_head && !add_size)) ? size0 : calculate_memsize(size, min_size+add_size, 0, resource_size(b_res), min_align); if (!size0 && !size1) { -- cgit v1.2.2 From dd2ed487fdd78b50549b2ca8418875c0d9f4a30e Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Sun, 15 May 2011 18:07:42 +0200 Subject: HID: 'name' and 'phys' in 'struct hid_device' can never be NULL As they are static members of fix size, there is no need to NULL-check them. Signed-off-by: Daniel Mack Cc: Dmitry Torokhov Cc: Jiri Kosina Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 14 ++------------ drivers/hid/usbhid/hiddev.c | 18 ++---------------- 2 files changed, 4 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 93c72e593701..c79578b5a788 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -395,12 +395,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, } if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) { - int len; - if (!hid->name) { - ret = 0; - break; - } - len = strlen(hid->name) + 1; + int len = strlen(hid->name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); ret = copy_to_user(user_arg, hid->name, len) ? @@ -409,12 +404,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, } if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) { - int len; - if (!hid->phys) { - ret = 0; - break; - } - len = strlen(hid->phys) + 1; + int len = strlen(hid->phys) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); ret = copy_to_user(user_arg, hid->phys, len) ? diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 527003188bfe..2baa71e6cc29 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -801,14 +801,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) { - int len; - - if (!hid->name) { - r = 0; - break; - } - - len = strlen(hid->name) + 1; + int len = strlen(hid->name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); r = copy_to_user(user_arg, hid->name, len) ? @@ -817,14 +810,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) { - int len; - - if (!hid->phys) { - r = 0; - break; - } - - len = strlen(hid->phys) + 1; + int len = strlen(hid->phys) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); r = copy_to_user(user_arg, hid->phys, len) ? -- cgit v1.2.2 From df167c4a0d68a9dbde044a39a77f255ac666f93e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 18 May 2011 15:27:24 +0200 Subject: HID: hid-multitouch: Add support for Lumio panels This patch enables support for Lumio optical devices. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d9635d6a907a..5a54b1312abf 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -308,6 +308,7 @@ config HID_MULTITOUCH - Hanvon dual touch panels - Ilitek dual touch panel - IrTouch Infrared USB panels + - Lumio CrystalTouch panels - MosArt dual-touch panels - PenMount dual touch panels - Pixcir dual touch panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c0ea857ed429..3dad069e142a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1410,6 +1410,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 0f29b3facca1..bfbc0d258851 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -410,6 +410,9 @@ #define USB_DEVICE_ID_DINOVO_MINI 0xc71f #define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03 +#define USB_VENDOR_ID_LUMIO 0x202e +#define USB_DEVICE_ID_CRYSTALTOUCH 0x0006 + #define USB_VENDOR_ID_MCC 0x09db #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index b21251b43a35..ef33e2d5af87 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -599,6 +599,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, + /* Lumio panels */ + { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, + HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, + USB_DEVICE_ID_CRYSTALTOUCH) }, + /* MosArt panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, HID_USB_DEVICE(USB_VENDOR_ID_ASUS, -- cgit v1.2.2 From b50f315cbb865079a16a12fd9ae6083f98fd592c Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 13 Apr 2011 17:17:52 +0200 Subject: HID: roccat: fix actual/startup profile sysfs attribute in koneplus startup_profile and actual_profile didn't work as expected. Also as the actual profile is persistent, the distinction between the two was ambiguous, so both use the same code now and startup_profile has been deprecated. Also the event is now propagated through chardev. The userland tool has been updated to support this change. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-koneplus.c | 82 +++++++++++++++++++++------------------ drivers/hid/hid-roccat-koneplus.h | 11 +++--- 2 files changed, 49 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c index 33eec74e0615..5b640a7a15a7 100644 --- a/drivers/hid/hid-roccat-koneplus.c +++ b/drivers/hid/hid-roccat-koneplus.c @@ -167,28 +167,28 @@ static int koneplus_set_profile_buttons(struct usb_device *usb_dev, } /* retval is 0-4 on success, < 0 on error */ -static int koneplus_get_startup_profile(struct usb_device *usb_dev) +static int koneplus_get_actual_profile(struct usb_device *usb_dev) { - struct koneplus_startup_profile buf; + struct koneplus_actual_profile buf; int retval; - retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE, - &buf, sizeof(struct koneplus_startup_profile)); + retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE, + &buf, sizeof(struct koneplus_actual_profile)); - return retval ? retval : buf.startup_profile; + return retval ? retval : buf.actual_profile; } -static int koneplus_set_startup_profile(struct usb_device *usb_dev, - int startup_profile) +static int koneplus_set_actual_profile(struct usb_device *usb_dev, + int new_profile) { - struct koneplus_startup_profile buf; + struct koneplus_actual_profile buf; - buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE; - buf.size = sizeof(struct koneplus_startup_profile); - buf.startup_profile = startup_profile; + buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE; + buf.size = sizeof(struct koneplus_actual_profile); + buf.actual_profile = new_profile; - return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE, - &buf, sizeof(struct koneplus_profile_buttons)); + return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE, + &buf, sizeof(struct koneplus_actual_profile)); } static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj, @@ -398,21 +398,22 @@ static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp, return sizeof(struct koneplus_profile_buttons); } -static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev, +static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev, struct device_attribute *attr, char *buf) { struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile); + return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile); } -static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev, +static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, struct device_attribute *attr, char const *buf, size_t size) { struct koneplus_device *koneplus; struct usb_device *usb_dev; unsigned long profile; int retval; + struct koneplus_roccat_report roccat_report; dev = dev->parent->parent; koneplus = hid_get_drvdata(dev_get_drvdata(dev)); @@ -423,20 +424,25 @@ static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev, return retval; mutex_lock(&koneplus->koneplus_lock); - retval = koneplus_set_startup_profile(usb_dev, profile); - mutex_unlock(&koneplus->koneplus_lock); - if (retval) + + retval = koneplus_set_actual_profile(usb_dev, profile); + if (retval) { + mutex_unlock(&koneplus->koneplus_lock); return retval; + } - return size; -} + koneplus->actual_profile = profile; -static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct koneplus_device *koneplus = - hid_get_drvdata(dev_get_drvdata(dev->parent->parent)); - return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile); + roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE; + roccat_report.data1 = profile + 1; + roccat_report.data2 = 0; + roccat_report.profile = profile + 1; + roccat_report_event(koneplus->chrdev_minor, + (uint8_t const *)&roccat_report); + + mutex_unlock(&koneplus->koneplus_lock); + + return size; } static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev, @@ -448,11 +454,12 @@ static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev, } static struct device_attribute koneplus_attributes[] = { + __ATTR(actual_profile, 0660, + koneplus_sysfs_show_actual_profile, + koneplus_sysfs_set_actual_profile), __ATTR(startup_profile, 0660, - koneplus_sysfs_show_startup_profile, - koneplus_sysfs_set_startup_profile), - __ATTR(actual_profile, 0440, - koneplus_sysfs_show_actual_profile, NULL), + koneplus_sysfs_show_actual_profile, + koneplus_sysfs_set_actual_profile), __ATTR(firmware_version, 0440, koneplus_sysfs_show_firmware_version, NULL), __ATTR_NULL @@ -557,15 +564,10 @@ static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev, struct koneplus_device *koneplus) { int retval, i; - static uint wait = 100; /* device will freeze with just 60 */ + static uint wait = 200; mutex_init(&koneplus->koneplus_lock); - koneplus->startup_profile = koneplus_get_startup_profile(usb_dev); - if (koneplus->startup_profile < 0) - return koneplus->startup_profile; - - msleep(wait); retval = koneplus_get_info(usb_dev, &koneplus->info); if (retval) return retval; @@ -584,7 +586,11 @@ static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev, return retval; } - koneplus_profile_activated(koneplus, koneplus->startup_profile); + msleep(wait); + retval = koneplus_get_actual_profile(usb_dev); + if (retval < 0) + return retval; + koneplus_profile_activated(koneplus, retval); return 0; } diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h index 57a5c1ab7b05..c57a376ab8ae 100644 --- a/drivers/hid/hid-roccat-koneplus.h +++ b/drivers/hid/hid-roccat-koneplus.h @@ -40,10 +40,10 @@ enum koneplus_control_values { KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3, }; -struct koneplus_startup_profile { - uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */ +struct koneplus_actual_profile { + uint8_t command; /* KONEPLUS_COMMAND_ACTUAL_PROFILE */ uint8_t size; /* always 3 */ - uint8_t startup_profile; /* Range 0-4! */ + uint8_t actual_profile; /* Range 0-4! */ } __attribute__ ((__packed__)); struct koneplus_profile_settings { @@ -132,7 +132,7 @@ struct koneplus_tcu_image { enum koneplus_commands { KONEPLUS_COMMAND_CONTROL = 0x4, - KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5, + KONEPLUS_COMMAND_ACTUAL_PROFILE = 0x5, KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6, KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7, KONEPLUS_COMMAND_MACRO = 0x8, @@ -145,7 +145,7 @@ enum koneplus_commands { enum koneplus_usb_commands { KONEPLUS_USB_COMMAND_CONTROL = 0x304, - KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305, + KONEPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307, KONEPLUS_USB_COMMAND_MACRO = 0x308, @@ -215,7 +215,6 @@ struct koneplus_device { struct mutex koneplus_lock; - int startup_profile; struct koneplus_info info; struct koneplus_profile_settings profile_settings[5]; struct koneplus_profile_buttons profile_buttons[5]; -- cgit v1.2.2 From 437f3b199c437e2a9ac01b9ab733c78e5fc7c720 Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Tue, 19 Apr 2011 15:28:30 -0400 Subject: HID: assorted usage updates from hut 1.12 I've got a Tivo Slide bluetooth remote/dongle, which uses a fair number of hid usages that aren't currently mapped in hid-input.c. I'd initially written additions to hid-input.c with just this device in mind, including some bits that were specific to the device. This go around, I'm looking at adding/correcting as many generic HID usages from the HID Usage Tables, version 1.12, as I can -- which also serves to enable all but four of the buttons on the Tivo Slide remote[*]. Outside of fixing the obviously incorrect mapping of 0xc 0x45 from KEY_RADIO to KEY_RIGHT, and making use of the new KEY_IMAGES (just added in 2.6.39-rc4) for AL Image Browser instead of KEY_MEDIA, these are purely additions, and thus should have no negative impact on any already functional HID devices. Most of the added mappings seemed to be perfectly logical to me, but there were a few that were mapped on more of an "I think this makes the most sense" basis. [*] I'll handle the last four tivo buttons via an hid-tivo.c follow-up. CC: Dmitry Torokhov CC: Jiri Kosina Signed-off-by: Jarod Wilson Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 60 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 33dde8724e02..6559e2e3364e 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -44,11 +44,11 @@ static const unsigned char hid_keyboard[256] = { 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, - 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, + unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk, 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk }; @@ -357,6 +357,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x1: map_key_clear(KEY_POWER); break; case 0x2: map_key_clear(KEY_SLEEP); break; case 0x3: map_key_clear(KEY_WAKEUP); break; + case 0x4: map_key_clear(KEY_CONTEXT_MENU); break; + case 0x5: map_key_clear(KEY_MENU); break; + case 0x6: map_key_clear(KEY_PROG1); break; + case 0x7: map_key_clear(KEY_HELP); break; + case 0x8: map_key_clear(KEY_EXIT); break; + case 0x9: map_key_clear(KEY_SELECT); break; + case 0xa: map_key_clear(KEY_RIGHT); break; + case 0xb: map_key_clear(KEY_LEFT); break; + case 0xc: map_key_clear(KEY_UP); break; + case 0xd: map_key_clear(KEY_DOWN); break; + case 0xe: map_key_clear(KEY_POWER2); break; + case 0xf: map_key_clear(KEY_RESTART); break; default: goto unknown; } break; @@ -466,16 +478,39 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } break; - case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ + case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */ switch (usage->hid & HID_USAGE) { case 0x000: goto ignore; + case 0x030: map_key_clear(KEY_POWER); break; + case 0x031: map_key_clear(KEY_RESTART); break; + case 0x032: map_key_clear(KEY_SLEEP); break; case 0x034: map_key_clear(KEY_SLEEP); break; + case 0x035: map_key_clear(KEY_KBDILLUMTOGGLE); break; case 0x036: map_key_clear(BTN_MISC); break; - case 0x040: map_key_clear(KEY_MENU); break; - case 0x045: map_key_clear(KEY_RADIO); break; - + case 0x040: map_key_clear(KEY_MENU); break; /* Menu */ + case 0x041: map_key_clear(KEY_SELECT); break; /* Menu Pick */ + case 0x042: map_key_clear(KEY_UP); break; /* Menu Up */ + case 0x043: map_key_clear(KEY_DOWN); break; /* Menu Down */ + case 0x044: map_key_clear(KEY_LEFT); break; /* Menu Left */ + case 0x045: map_key_clear(KEY_RIGHT); break; /* Menu Right */ + case 0x046: map_key_clear(KEY_ESC); break; /* Menu Escape */ + case 0x047: map_key_clear(KEY_KPPLUS); break; /* Menu Value Increase */ + case 0x048: map_key_clear(KEY_KPMINUS); break; /* Menu Value Decrease */ + + case 0x060: map_key_clear(KEY_INFO); break; /* Data On Screen */ + case 0x061: map_key_clear(KEY_SUBTITLE); break; /* Closed Caption */ + case 0x063: map_key_clear(KEY_VCR); break; /* VCR/TV */ + case 0x065: map_key_clear(KEY_CAMERA); break; /* Snapshot */ + case 0x069: map_key_clear(KEY_RED); break; + case 0x06a: map_key_clear(KEY_GREEN); break; + case 0x06b: map_key_clear(KEY_BLUE); break; + case 0x06c: map_key_clear(KEY_YELLOW); break; + case 0x06d: map_key_clear(KEY_ZOOM); break; + + case 0x082: map_key_clear(KEY_VIDEO_NEXT); break; case 0x083: map_key_clear(KEY_LAST); break; + case 0x084: map_key_clear(KEY_ENTER); break; case 0x088: map_key_clear(KEY_PC); break; case 0x089: map_key_clear(KEY_TV); break; case 0x08a: map_key_clear(KEY_WWW); break; @@ -509,6 +544,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0b7: map_key_clear(KEY_STOPCD); break; case 0x0b8: map_key_clear(KEY_EJECTCD); break; case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT); break; + case 0x0b9: map_key_clear(KEY_SHUFFLE); break; + case 0x0bf: map_key_clear(KEY_SLOW); break; case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; case 0x0e0: map_abs_clear(ABS_VOLUME); break; @@ -516,6 +553,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0e5: map_key_clear(KEY_BASSBOOST); break; case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; + case 0x0f5: map_key_clear(KEY_SLOW); break; case 0x182: map_key_clear(KEY_BOOKMARKS); break; case 0x183: map_key_clear(KEY_CONFIG); break; @@ -532,6 +570,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x18e: map_key_clear(KEY_CALENDAR); break; case 0x191: map_key_clear(KEY_FINANCE); break; case 0x192: map_key_clear(KEY_CALC); break; + case 0x193: map_key_clear(KEY_PLAYER); break; case 0x194: map_key_clear(KEY_FILE); break; case 0x196: map_key_clear(KEY_WWW); break; case 0x199: map_key_clear(KEY_CHAT); break; @@ -540,8 +579,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; - case 0x1b6: map_key_clear(KEY_MEDIA); break; - case 0x1b7: map_key_clear(KEY_SOUND); break; + case 0x1ae: map_key_clear(KEY_KEYBOARD); break; + case 0x1b6: map_key_clear(KEY_IMAGES); break; + case 0x1b7: map_key_clear(KEY_AUDIO); break; + case 0x1b8: map_key_clear(KEY_VIDEO); break; case 0x1bc: map_key_clear(KEY_MESSENGER); break; case 0x1bd: map_key_clear(KEY_INFO); break; case 0x201: map_key_clear(KEY_NEW); break; @@ -570,7 +611,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x233: map_key_clear(KEY_SCROLLUP); break; case 0x234: map_key_clear(KEY_SCROLLDOWN); break; case 0x238: map_rel(REL_HWHEEL); break; + case 0x23d: map_key_clear(KEY_EDIT); break; case 0x25f: map_key_clear(KEY_CANCEL); break; + case 0x269: map_key_clear(KEY_INSERT); break; + case 0x26a: map_key_clear(KEY_DELETE); break; case 0x279: map_key_clear(KEY_REDO); break; case 0x289: map_key_clear(KEY_REPLY); break; -- cgit v1.2.2 From c04abeeff9d76a703cac1e6d312853b0fc8136f5 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 19 May 2011 11:37:29 +0200 Subject: HID: hid-multitouch: add support for Elo TouchSystems 2515 IntelliTouch Plus This patch adds support for Elo TouchSystems 2515 IntelliTouch Plus that can be found in Lenovo A700 all-in-one. Signed-off-by: Benjamin Tissoires Tested-by: Bastien Nocera Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 10 ++++++++++ 4 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 5a54b1312abf..1572ff13f348 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -305,6 +305,7 @@ config HID_MULTITOUCH - 3M PCT touch screens - Cando dual touch panel - Cypress TrueTouch panels + - Elo TouchSystems IntelliTouch Plus panels - Hanvon dual touch panels - Ilitek dual touch panel - IrTouch Infrared USB panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3dad069e142a..053fc08a270d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1366,6 +1366,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index bfbc0d258851..6c19d1a66cf2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -216,6 +216,7 @@ #define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 #define USB_VENDOR_ID_ELO 0x04E7 +#define USB_DEVICE_ID_ELO_TS2515 0x0022 #define USB_DEVICE_ID_ELO_TS2700 0x0020 #define USB_VENDOR_ID_EMS 0x2006 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index ef33e2d5af87..3bc8de6074f7 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -92,6 +92,7 @@ struct mt_class { #define MT_CLS_3M 7 #define MT_CLS_CONFIDENCE 8 #define MT_CLS_CONFIDENCE_MINUS_ONE 9 +#define MT_CLS_DUAL_NSMU_CONTACTID 10 #define MT_DEFAULT_MAXCONTACT 10 @@ -163,6 +164,10 @@ struct mt_class mt_classes[] = { .sn_height = 128 }, { .name = MT_CLS_CONFIDENCE, .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, + { .name = MT_CLS_DUAL_NSMU_CONTACTID, + .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | + MT_QUIRK_SLOT_IS_CONTACTID, + .maxcontacts = 2 }, { } }; @@ -584,6 +589,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, + /* Elo TouchSystems IntelliTouch Plus panel */ + { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, + HID_USB_DEVICE(USB_VENDOR_ID_ELO, + USB_DEVICE_ID_ELO_TS2515) }, + /* GeneralTouch panel */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, -- cgit v1.2.2 From 966922f26c7fb5eddbe3c506b66bb5659f57b76f Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Thu, 19 May 2011 21:41:22 +0200 Subject: HID: fix a crash in hid_report_raw_event() function. I'm using a Data Modul EasyTouch USB multitouch controller, which is issuing a hid report with a size equals to 0. The rsize value gets set to 536870912 and Linux is crashing in the memset because the value is too big. Signed-off-by: Armando Visconti Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 852989fc5757..84df80e3efc1 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1045,6 +1045,9 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, rsize = ((report->size - 1) >> 3) + 1; + if (rsize > HID_MAX_BUFFER_SIZE) + rsize = HID_MAX_BUFFER_SIZE; + if (csize < rsize) { dbg_hid("report %d is too short, (%d < %d)\n", report->id, csize, rsize); -- cgit v1.2.2 From 23746a66d7d9e73402c68ef00d708796b97ebd72 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Thu, 19 May 2011 17:58:07 +0200 Subject: HID: magicmouse: ignore 'ivalid report id' while switching modes The device reponds with 'invalid report id' when feature report switching it into multitouch mode is sent to it. This has been silently ignored before 0825411ade ("HID: bt: Wait for ACK on Sent Reports"), but since this commit, it propagates -EIO from the _raw callback . So let the driver ignore -EIO as response to 0xd7,0x01 report, as that's how the device reacts in normal mode. Sad, but following reality. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=35022 Tested-by: Chase Douglas Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 318cc40df92d..82f0c3d741f2 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -499,9 +499,17 @@ static int magicmouse_probe(struct hid_device *hdev, } report->size = 6; + /* + * The device reponds with 'invalid report id' when feature + * report switching it into multitouch mode is sent to it. + * + * This results in -EIO from the _raw low-level transport callback, + * but there seems to be no other way of switching the mode. + * Thus the super-ugly hacky success check below. + */ ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), HID_FEATURE_REPORT); - if (ret != sizeof(feature)) { + if (ret != -EIO) { hid_err(hdev, "unable to request touch data (%d)\n", ret); goto err_stop_hw; } -- cgit v1.2.2 From 6cb4b040795c555c7ab4b1ba29b0dba2b5a42beb Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 20 May 2011 10:50:13 +0200 Subject: HID: hiddev: fix race between hiddev_disconnect and hiddev_release When hiddev_disconnect() runs with chardev open, it will proceed with usbhid_close(). When userspace in parallel runs the hiddev_release(), it sees !hiddev->exists (as it has been already set so by hiddev_disconnect()) and kfrees hiddev while hiddev_disconnect() hasn't finished yet. Serialize the access to hiddev->exists and hiddev->open by existancelock. Reported-by: mike-@cinci.rr.com Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 2baa71e6cc29..f4c67a5021c7 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -242,6 +242,7 @@ static int hiddev_release(struct inode * inode, struct file * file) list_del(&list->node); spin_unlock_irqrestore(&list->hiddev->list_lock, flags); + mutex_lock(&list->hiddev->existancelock); if (!--list->hiddev->open) { if (list->hiddev->exist) { usbhid_close(list->hiddev->hid); @@ -252,6 +253,7 @@ static int hiddev_release(struct inode * inode, struct file * file) } kfree(list); + mutex_unlock(&list->hiddev->existancelock); return 0; } @@ -300,17 +302,21 @@ static int hiddev_open(struct inode *inode, struct file *file) list_add_tail(&list->node, &hiddev->list); spin_unlock_irq(&list->hiddev->list_lock); + mutex_lock(&hiddev->existancelock); if (!list->hiddev->open++) if (list->hiddev->exist) { struct hid_device *hid = hiddev->hid; res = usbhid_get_power(hid); if (res < 0) { res = -EIO; - goto bail; + goto bail_unlock; } usbhid_open(hid); } + mutex_unlock(&hiddev->existancelock); return 0; +bail_unlock: + mutex_unlock(&hiddev->existancelock); bail: file->private_data = NULL; kfree(list); @@ -911,7 +917,6 @@ void hiddev_disconnect(struct hid_device *hid) mutex_lock(&hiddev->existancelock); hiddev->exist = 0; - mutex_unlock(&hiddev->existancelock); usb_deregister_dev(usbhid->intf, &hiddev_class); @@ -921,4 +926,5 @@ void hiddev_disconnect(struct hid_device *hid) } else { kfree(hiddev); } + mutex_unlock(&hiddev->existancelock); } -- cgit v1.2.2 From e6aac3427ef03f61e7478514d0648b58359d05d1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 19 May 2011 14:18:13 +0200 Subject: HID: hid-multitouch: add support for ActionStar panels This patch introduce support for ActionStar panels. This device has not been optimized in term of kernel processing operations (default class), but it will work. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 1572ff13f348..605b69b2a52a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -303,6 +303,7 @@ config HID_MULTITOUCH Say Y here if you have one of the following devices: - 3M PCT touch screens + - ActionStar dual touch panels - Cando dual touch panel - Cypress TrueTouch panels - Elo TouchSystems IntelliTouch Plus panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 053fc08a270d..c2382b6ad2d5 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1290,6 +1290,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) }, { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6c19d1a66cf2..0ebb7fa4cbf6 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -37,6 +37,9 @@ #define USB_VENDOR_ID_ACRUX 0x1a34 +#define USB_VENDOR_ID_ACTIONSTAR 0x2101 +#define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011 + #define USB_VENDOR_ID_ADS_TECH 0x06e1 #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3bc8de6074f7..10a8c760568f 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -570,6 +570,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, + /* ActionStar panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, + USB_DEVICE_ID_ACTIONSTAR_1011) }, + /* Cando panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, HID_USB_DEVICE(USB_VENDOR_ID_CANDO, -- cgit v1.2.2 From 79603dc9a8223856cf3194dcabad32b9828c7be9 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 19 May 2011 14:18:14 +0200 Subject: HID: hid-multitouch: add support for CVTouch panels This patch introduce support for CVTouch panels. This device has not been optimized in term of kernel processing operations (default class), but it will work. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 605b69b2a52a..3e14815eba36 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -305,6 +305,7 @@ config HID_MULTITOUCH - 3M PCT touch screens - ActionStar dual touch panels - Cando dual touch panel + - CVTouch panels - Cypress TrueTouch panels - Elo TouchSystems IntelliTouch Plus panels - Hanvon dual touch panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c2382b6ad2d5..cc52faa9d87a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1354,6 +1354,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 0ebb7fa4cbf6..e9b8004e99b9 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -181,6 +181,9 @@ #define USB_VENDOR_ID_CREATIVELABS 0x041e #define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 +#define USB_VENDOR_ID_CVTOUCH 0x1ff7 +#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013 + #define USB_VENDOR_ID_CYGNAL 0x10c4 #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 10a8c760568f..af8789a8138d 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -589,6 +589,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, + /* CVTouch panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, + USB_DEVICE_ID_CVTOUCH_SCREEN) }, + /* Cypress panel */ { .driver_data = MT_CLS_CYPRESS, HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, -- cgit v1.2.2 From ee0fbd149182d91e3b9df7b306eb03cd1f1dd4a1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 19 May 2011 14:18:15 +0200 Subject: HID: hid-multitouch: add support for GoodTouch panels This patch introduce support for GoodTouch panels. This device has not been optimized in term of kernel processing operations (default class), but it will work. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 3e14815eba36..9a8ecc03416e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -308,6 +308,7 @@ config HID_MULTITOUCH - CVTouch panels - Cypress TrueTouch panels - Elo TouchSystems IntelliTouch Plus panels + - GoodTouch panels - Hanvon dual touch panels - Ilitek dual touch panel - IrTouch Infrared USB panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index cc52faa9d87a..5ba23fbfc5a7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1374,6 +1374,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) }, { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e9b8004e99b9..5ad823528e24 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -258,6 +258,9 @@ #define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053 #define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058 +#define USB_VENDOR_ID_GOODTOUCH 0x1aad +#define USB_DEVICE_ID_GOODTOUCH_000f 0x000f + #define USB_VENDOR_ID_GOTOP 0x08f2 #define USB_DEVICE_ID_SUPER_Q2 0x007f #define USB_DEVICE_ID_GOGOPEN 0x00ce diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index af8789a8138d..76ef60db15cc 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -609,6 +609,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, + /* GoodTouch panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, + USB_DEVICE_ID_GOODTOUCH_000f) }, + /* Ilitek dual touch panel */ { .driver_data = MT_CLS_DEFAULT, HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, -- cgit v1.2.2 From 5e74e56da03f581482c104628951eeb1455848ea Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 19 May 2011 14:18:16 +0200 Subject: HID: hid-multitouch: add support for Touch International panels This patch introduce support for Touch International panels. This device has not been optimized in term of kernel processing operations (default class), but it will work. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 4 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 9a8ecc03416e..34ba931a268b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -320,6 +320,7 @@ config HID_MULTITOUCH - eGalax dual-touch panels, including the Joojoo and Wetab tablets - Stantum multitouch panels + - Touch International Panels If unsure, say N. diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5ba23fbfc5a7..697ee3fe798e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1472,6 +1472,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5ad823528e24..84871ebbe937 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -574,6 +574,9 @@ #define USB_VENDOR_ID_TOPMAX 0x0663 #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 +#define USB_VENDOR_ID_TOUCH_INTL 0x1e5e +#define USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH 0x0313 + #define USB_VENDOR_ID_TOUCHPACK 0x1bfd #define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 76ef60db15cc..bc5761591a60 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -683,6 +683,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP_SITRONIX)}, + /* Touch International panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, + USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, + { } }; MODULE_DEVICE_TABLE(hid, mt_devices); -- cgit v1.2.2 From 617b64f97708be26a061e6c8178ad46b4c49d031 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 19 May 2011 14:18:17 +0200 Subject: HID: hid-multitouch: add support for Unitec panels This patch introduce support for Unitec panels. This device has not been optimized in term of kernel processing operations (default class), but it will work. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 2 ++ drivers/hid/hid-ids.h | 4 ++++ drivers/hid/hid-multitouch.c | 8 ++++++++ 4 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 34ba931a268b..88e6b2b9a42e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -321,6 +321,7 @@ config HID_MULTITOUCH Joojoo and Wetab tablets - Stantum multitouch panels - Touch International Panels + - Unitec Panels If unsure, say N. diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 697ee3fe798e..9f15c9238fb2 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1479,6 +1479,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 84871ebbe937..b8299ef0f01c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -594,6 +594,10 @@ #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 +#define USB_VENDOR_ID_UNITEC 0x227d +#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 +#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 0x0a19 + #define USB_VENDOR_ID_VERNIER 0x08f7 #define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 #define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index bc5761591a60..feeb0b7b6db2 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -688,6 +688,14 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) }, + /* Unitec panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, + USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, + USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, + { } }; MODULE_DEVICE_TABLE(hid, mt_devices); -- cgit v1.2.2 From bf5af9b5bba2453ff46f241e8f2e139ca79302e7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 19 May 2011 14:18:18 +0200 Subject: HID: hid-multitouch: class MT_CLS_STANTUM is redundant with MT_CLS_CONFIDENCE Stantum devices used to work with MT_CLS_STANTUM but MT_CLS_CONFIDENCE is exactly the same. This patch switches them to this generic class, and remove the unused MT_CLS_STANTUM. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index feeb0b7b6db2..65b92d2bf759 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -88,7 +88,6 @@ struct mt_class { #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3 #define MT_CLS_CYPRESS 4 #define MT_CLS_EGALAX 5 -#define MT_CLS_STANTUM 6 #define MT_CLS_3M 7 #define MT_CLS_CONFIDENCE 8 #define MT_CLS_CONFIDENCE_MINUS_ONE 9 @@ -154,8 +153,6 @@ struct mt_class mt_classes[] = { .sn_move = 4096, .sn_pressure = 32, }, - { .name = MT_CLS_STANTUM, - .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, { .name = MT_CLS_3M, .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | MT_QUIRK_SLOT_IS_CONTACTID, @@ -673,13 +670,13 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, /* Stantum panels */ - { .driver_data = MT_CLS_STANTUM, + { .driver_data = MT_CLS_CONFIDENCE, HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP)}, - { .driver_data = MT_CLS_STANTUM, + { .driver_data = MT_CLS_CONFIDENCE, HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP_STM)}, - { .driver_data = MT_CLS_STANTUM, + { .driver_data = MT_CLS_CONFIDENCE, HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP_SITRONIX)}, -- cgit v1.2.2 From 22408283bca57780bdd53da5a6e4474b71b94430 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 20 May 2011 15:59:34 +0200 Subject: HID: hid-multitouch: cosmetic changes, sort classes and devices This patch sorts the defs for the MT_CLS. I choose to split generic classes and device specific ones to be able to add more generic classes in the future. It also put eGalax devices at their right place (alphabetically) in mt_devices. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 9 ++--- drivers/hid/hid-multitouch.c | 93 ++++++++++++++++++++++++-------------------- 2 files changed, 54 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 88e6b2b9a42e..d588a5e28d0e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -304,21 +304,20 @@ config HID_MULTITOUCH Say Y here if you have one of the following devices: - 3M PCT touch screens - ActionStar dual touch panels - - Cando dual touch panel + - Cando dual touch panels - CVTouch panels - Cypress TrueTouch panels - Elo TouchSystems IntelliTouch Plus panels + - GeneralTouch 'Sensing Win7-TwoFinger' panels - GoodTouch panels - Hanvon dual touch panels - - Ilitek dual touch panel + - Ilitek dual touch panels - IrTouch Infrared USB panels - Lumio CrystalTouch panels - MosArt dual-touch panels - PenMount dual touch panels - Pixcir dual touch panels - - 'Sensing Win7-TwoFinger' panel by GeneralTouch - - eGalax dual-touch panels, including the - Joojoo and Wetab tablets + - eGalax dual-touch panels, including the Joojoo and Wetab tablets - Stantum multitouch panels - Touch International Panels - Unitec Panels diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 65b92d2bf759..ecd4d2db9e80 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -83,15 +83,18 @@ struct mt_class { }; /* classes of device behavior */ -#define MT_CLS_DEFAULT 1 -#define MT_CLS_DUAL_INRANGE_CONTACTID 2 -#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3 -#define MT_CLS_CYPRESS 4 -#define MT_CLS_EGALAX 5 -#define MT_CLS_3M 7 -#define MT_CLS_CONFIDENCE 8 -#define MT_CLS_CONFIDENCE_MINUS_ONE 9 -#define MT_CLS_DUAL_NSMU_CONTACTID 10 +#define MT_CLS_DEFAULT 0x0001 + +#define MT_CLS_CONFIDENCE 0x0002 +#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0003 +#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0004 +#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0005 +#define MT_CLS_DUAL_NSMU_CONTACTID 0x0006 + +/* vendor specific classes */ +#define MT_CLS_3M 0x0101 +#define MT_CLS_CYPRESS 0x0102 +#define MT_CLS_EGALAX 0x0103 #define MT_DEFAULT_MAXCONTACT 10 @@ -130,6 +133,11 @@ static int find_slot_from_contactid(struct mt_device *td) struct mt_class mt_classes[] = { { .name = MT_CLS_DEFAULT, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, + { .name = MT_CLS_CONFIDENCE, + .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, + { .name = MT_CLS_CONFIDENCE_MINUS_ONE, + .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | + MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, { .name = MT_CLS_DUAL_INRANGE_CONTACTID, .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTID, @@ -138,13 +146,24 @@ struct mt_class mt_classes[] = { .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTNUMBER, .maxcontacts = 2 }, + { .name = MT_CLS_DUAL_NSMU_CONTACTID, + .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | + MT_QUIRK_SLOT_IS_CONTACTID, + .maxcontacts = 2 }, + + /* + * vendor specific classes + */ + { .name = MT_CLS_3M, + .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | + MT_QUIRK_SLOT_IS_CONTACTID, + .sn_move = 2048, + .sn_width = 128, + .sn_height = 128 }, { .name = MT_CLS_CYPRESS, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | MT_QUIRK_CYPRESS, .maxcontacts = 10 }, - { .name = MT_CLS_CONFIDENCE_MINUS_ONE, - .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | - MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE }, { .name = MT_CLS_EGALAX, .quirks = MT_QUIRK_SLOT_IS_CONTACTID | MT_QUIRK_VALID_IS_INRANGE | @@ -153,18 +172,6 @@ struct mt_class mt_classes[] = { .sn_move = 4096, .sn_pressure = 32, }, - { .name = MT_CLS_3M, - .quirks = MT_QUIRK_VALID_IS_CONFIDENCE | - MT_QUIRK_SLOT_IS_CONTACTID, - .sn_move = 2048, - .sn_width = 128, - .sn_height = 128 }, - { .name = MT_CLS_CONFIDENCE, - .quirks = MT_QUIRK_VALID_IS_CONFIDENCE }, - { .name = MT_CLS_DUAL_NSMU_CONTACTID, - .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | - MT_QUIRK_SLOT_IS_CONTACTID, - .maxcontacts = 2 }, { } }; @@ -596,6 +603,25 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, + /* eGalax devices (resistive) */ + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, + + /* eGalax devices (capacitive) */ + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, + /* Elo TouchSystems IntelliTouch Plus panel */ { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, HID_USB_DEVICE(USB_VENDOR_ID_ELO, @@ -650,25 +676,6 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, - /* Resistive eGalax devices */ - { .driver_data = MT_CLS_EGALAX, - HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, - { .driver_data = MT_CLS_EGALAX, - HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, - - /* Capacitive eGalax devices */ - { .driver_data = MT_CLS_EGALAX, - HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, - { .driver_data = MT_CLS_EGALAX, - HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, - { .driver_data = MT_CLS_EGALAX, - HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, - /* Stantum panels */ { .driver_data = MT_CLS_CONFIDENCE, HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, -- cgit v1.2.2